]> Sergey Matveev's repositories - btrtrc.git/blob - iplist/iplist.go
9fe9871efe88e2e85bce725fc4cd78a0b2dd6e7e
[btrtrc.git] / iplist / iplist.go
1 package iplist
2
3 import (
4         "bytes"
5         "fmt"
6         "net"
7         "sort"
8         "strings"
9 )
10
11 type IPList struct {
12         ranges []Range
13 }
14
15 type Range struct {
16         First, Last net.IP
17         Description string
18 }
19
20 func (r *Range) String() string {
21         return fmt.Sprintf("%s-%s (%s)", r.First, r.Last, r.Description)
22 }
23
24 // Create a new IP list. The given range must already sorted by the lower IP
25 // in the range. Behaviour is undefined for lists of overlapping ranges.
26 func New(initSorted []Range) *IPList {
27         return &IPList{
28                 ranges: initSorted,
29         }
30 }
31
32 // Return the range the given IP is in. Returns nil if no range is found.
33 func (me *IPList) Lookup(ip net.IP) (r *Range) {
34         // Find the index of the first range for which the following range exceeds
35         // it.
36         i := sort.Search(len(me.ranges), func(i int) bool {
37                 if i+1 >= len(me.ranges) {
38                         return true
39                 }
40                 return bytes.Compare(ip, me.ranges[i+1].First) < 0
41         })
42         if i == len(me.ranges) {
43                 return
44         }
45         r = &me.ranges[i]
46         if bytes.Compare(ip, r.First) < 0 || bytes.Compare(ip, r.Last) > 0 {
47                 r = nil
48         }
49         return
50 }
51
52 // Parse a line of the PeerGuardian Text Lists (P2P) Format. Returns !ok but
53 // no error if a line doesn't contain a range but isn't erroneous, such as
54 // comment and blank lines.
55 func ParseBlocklistP2PLine(l string) (r Range, ok bool, err error) {
56         l = strings.TrimSpace(l)
57         if len(l) == 0 || strings.HasPrefix(l, "#") {
58                 return
59         }
60         colon := strings.IndexByte(l, ':')
61         hyphen := strings.IndexByte(l[colon+1:], '-') + colon + 1
62         r.Description = l[:colon]
63         r.First = net.ParseIP(l[colon+1 : hyphen])
64         r.Last = net.ParseIP(l[hyphen+1:])
65         if r.First == nil || r.Last == nil {
66                 return
67         }
68         ok = true
69         return
70 }