11package csnet
22
33import (
4- "github.com/crowdsecurity/crowdsec/pkg/types"
4+ "encoding/binary"
5+ "errors"
6+ "math"
7+ "net/netip"
8+ "strings"
59)
610
711type IPAddrSize int
@@ -11,37 +15,98 @@ const (
1115 IPv6Size IPAddrSize = 16
1216)
1317
14- type IP struct {
18+ type IntIP struct {
1519 size IPAddrSize
1620 Addr int64
1721 Sfx int64
1822}
1923
2024type Range struct {
21- Start IP
22- End IP
25+ Start IntIP
26+ End IntIP
2327}
2428
2529func (r Range ) Size () int {
2630 return int (r .Start .size )
2731}
2832
33+ // NewIP converts a netip.Addr into an IntIP for storage and comparison.
34+ func NewIP (addr netip.Addr ) IntIP {
35+ if addr .Is4 () {
36+ ipBytes := addr .As4 ()
37+
38+ return IntIP {
39+ size : IPv4Size ,
40+ Addr : uint2int (uint64 (binary .BigEndian .Uint32 (ipBytes [:]))),
41+ Sfx : 0 ,
42+ }
43+ }
44+
45+ ipBytes := addr .As16 ()
46+
47+ return IntIP {
48+ size : IPv6Size ,
49+ Addr : uint2int (binary .BigEndian .Uint64 (ipBytes [0 :8 ])),
50+ Sfx : uint2int (binary .BigEndian .Uint64 (ipBytes [8 :16 ])),
51+ }
52+ }
53+
54+ // NewRange parses an IP or CIDR string into a Range of IntIP addresses.
55+ // If the input is a single IP (e.g. "1.2.3.4"), the start and end of the range are equal.
56+ // If the input is a prefix (e.g. "1.2.3.0/24"), the function computes the first and last
57+ // addresses covered by the prefix.
2958func NewRange (anyIP string ) (Range , error ) {
30- size , start_ip , start_sfx , end_ip , end_sfx , err := types .Addr2Ints (anyIP )
59+ if ! strings .Contains (anyIP , "/" ) {
60+ addr , err := netip .ParseAddr (anyIP )
61+ if err != nil {
62+ return Range {}, err
63+ }
64+
65+ ip := NewIP (addr )
66+
67+ return Range {Start : ip , End : ip }, nil
68+ }
69+
70+ prefix , err := netip .ParsePrefix (anyIP )
3171 if err != nil {
3272 return Range {}, err
3373 }
3474
35- return Range {
36- Start : IP {
37- size : IPAddrSize (size ),
38- Addr : start_ip ,
39- Sfx : start_sfx ,
40- },
41- End : IP {
42- size : IPAddrSize (size ),
43- Addr : end_ip ,
44- Sfx : end_sfx ,
45- },
46- }, nil
75+ start := prefix .Masked ().Addr ()
76+ bits := prefix .Bits ()
77+
78+ if start .Is4In6 () && bits < 96 {
79+ return Range {}, errors .New ("prefix with 4in6 address must have mask >= 96" )
80+ }
81+
82+ a16 := start .As16 ()
83+
84+ if start .Is4 () {
85+ bits += 96
86+ }
87+
88+ // Fill host bits with 1s
89+ for b := bits ; b < 128 ; b ++ {
90+ a16 [b / 8 ] |= 1 << (7 - (b % 8 ))
91+ }
92+
93+ end := netip .AddrFrom16 (a16 )
94+ if start .Is4 () {
95+ end = end .Unmap ()
96+ }
97+
98+ return Range {Start : NewIP (start ), End : NewIP (end )}, nil
99+ }
100+
101+ func uint2int (u uint64 ) int64 {
102+ switch {
103+ case u == math .MaxInt64 :
104+ return 0
105+ case u == math .MaxUint64 :
106+ return math .MaxInt64
107+ case u > math .MaxInt64 :
108+ return int64 (u - math .MaxInt64 )
109+ default :
110+ return int64 (u ) - math .MaxInt64
111+ }
47112}
0 commit comments