github.com/database64128/shadowsocks-go@v1.10.2-0.20240315062903-143a773533f1/prefixset/prefixset.go (about) 1 package prefixset 2 3 import ( 4 "fmt" 5 "net/netip" 6 7 "github.com/database64128/shadowsocks-go/bytestrings" 8 "github.com/database64128/shadowsocks-go/mmap" 9 "go4.org/netipx" 10 ) 11 12 // Config is the configuration for a prefix set. 13 type Config struct { 14 Name string `json:"name"` 15 Path string `json:"path"` 16 } 17 18 // IPSet creates a prefix set from the configuration. 19 func (psc Config) IPSet() (*netipx.IPSet, error) { 20 data, err := mmap.ReadFile[string](psc.Path) 21 if err != nil { 22 return nil, fmt.Errorf("failed to load prefix set %s: %w", psc.Name, err) 23 } 24 defer mmap.Unmap(data) 25 26 return IPSetFromText(data) 27 } 28 29 // IPSetFromText parses prefixes from the text and builds a prefix set. 30 func IPSetFromText(text string) (*netipx.IPSet, error) { 31 var ( 32 line string 33 sb netipx.IPSetBuilder 34 ) 35 36 for { 37 line, text = bytestrings.NextNonEmptyLine(text) 38 if len(line) == 0 { 39 break 40 } 41 42 if line[0] == '#' { 43 continue 44 } 45 46 prefix, err := netip.ParsePrefix(line) 47 if err != nil { 48 return nil, err 49 } 50 51 sb.AddPrefix(prefix) 52 } 53 54 return sb.IPSet() 55 } 56 57 // IPSetToText returns the text representation of the prefix set. 58 func IPSetToText(s *netipx.IPSet) []byte { 59 prefixes := s.Prefixes() 60 b := make([]byte, 0, 20*len(prefixes)) 61 for _, prefix := range prefixes { 62 b = prefix.AppendTo(b) 63 b = append(b, '\n') 64 } 65 return b 66 }