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  }