From 71141fb486e7fb5634137471328b46f4d9d52ea1 Mon Sep 17 00:00:00 2001 From: 0x90-n Date: Sat, 9 Nov 2024 11:31:08 -0700 Subject: [PATCH 01/14] testing registration v4 phantom overrides --- cmd/registration-server/main.go | 46 ++++-- pkg/regserver/regprocessor/regprocessor.go | 178 ++++++++++++++++++--- 2 files changed, 186 insertions(+), 38 deletions(-) diff --git a/cmd/registration-server/main.go b/cmd/registration-server/main.go index dfe59731..112d24cf 100644 --- a/cmd/registration-server/main.go +++ b/cmd/registration-server/main.go @@ -4,6 +4,7 @@ import ( "crypto/ed25519" "flag" "fmt" + "net" "os" "os/signal" "strconv" @@ -33,20 +34,33 @@ type regServer interface { // config defines the variables and options from the toml config file type config struct { - DNSListenAddr string `toml:"dns_listen_addr"` - Domain string `toml:"domain"` - DNSPrivkeyPath string `toml:"dns_private_key_path"` - APIPort uint16 `toml:"api_port"` - ZMQAuthVerbose bool `toml:"zmq_auth_verbose"` - ZMQAuthType string `toml:"zmq_auth_type"` - ZMQPort uint16 `toml:"zmq_port"` - ZMQBindAddr string `toml:"zmq_bind_addr"` - ZMQPrivateKeyPath string `toml:"zmq_privkey_path"` - StationPublicKeys []string `toml:"station_pubkeys"` - ClientConfPath string `toml:"clientconf_path"` - latestClientConf *pb.ClientConf - LogLevel string `toml:"log_level"` - LogMetricsInterval uint16 `toml:"log_metrics_interval"` + DNSListenAddr string `toml:"dns_listen_addr"` + Domain string `toml:"domain"` + DNSPrivkeyPath string `toml:"dns_private_key_path"` + APIPort uint16 `toml:"api_port"` + ZMQAuthVerbose bool `toml:"zmq_auth_verbose"` + ZMQAuthType string `toml:"zmq_auth_type"` + ZMQPort uint16 `toml:"zmq_port"` + ZMQBindAddr string `toml:"zmq_bind_addr"` + ZMQPrivateKeyPath string `toml:"zmq_privkey_path"` + StationPublicKeys []string `toml:"station_pubkeys"` + ClientConfPath string `toml:"clientconf_path"` + latestClientConf *pb.ClientConf + LogLevel string `toml:"log_level"` + LogMetricsInterval uint16 `toml:"log_metrics_interval"` + EnforceSubnetOverrides bool `toml:"enforce_subnet_overrides"` + OverrideSubnets []regprocessor.Subnet `toml:"override_subnets"` + ExclusionsFromOverride []regprocessor.Subnet `toml:"excluded_subnets_from_overrides"` +} + +// UnmarshalText makes CIDR compatible with TOML decoding +func (n *regprocessor.ipnet) UnmarshalText(text []byte) error { + _, cidr, err := net.ParseCIDR(string(text)) + if err != nil { + return err + } + n.IPNet = cidr + return nil } var defaultTransports = map[pb.TransportType]lib.Transport{ @@ -192,9 +206,9 @@ func main() { switch conf.ZMQAuthType { case "CURVE": - processor, err = regprocessor.NewRegProcessor(conf.ZMQBindAddr, conf.ZMQPort, zmqPrivkey, conf.ZMQAuthVerbose, conf.StationPublicKeys, metrics) + processor, err = regprocessor.NewRegProcessor(conf.ZMQBindAddr, conf.ZMQPort, zmqPrivkey, conf.ZMQAuthVerbose, conf.StationPublicKeys, metrics, conf.EnforceSubnetOverrides, conf.OverrideSubnets, conf.ExclusionsFromOverride) case "NULL": - processor, err = regprocessor.NewRegProcessorNoAuth(conf.ZMQBindAddr, conf.ZMQPort, metrics) + processor, err = regprocessor.NewRegProcessorNoAuth(conf.ZMQBindAddr, conf.ZMQPort, metrics, conf.EnforceSubnetOverrides, conf.OverrideSubnets, conf.ExclusionsFromOverride) default: log.Fatalf("Unknown ZMQ auth type: %s", conf.ZMQAuthType) } diff --git a/pkg/regserver/regprocessor/regprocessor.go b/pkg/regserver/regprocessor/regprocessor.go index d3cbcee7..9eeff123 100644 --- a/pkg/regserver/regprocessor/regprocessor.go +++ b/pkg/regserver/regprocessor/regprocessor.go @@ -11,6 +11,8 @@ import ( "encoding/binary" "errors" "fmt" + "math/big" + "net" "sync" zmq "github.com/pebbe/zmq4" @@ -20,8 +22,11 @@ import ( "github.com/refraction-networking/conjure/pkg/phantoms" "github.com/refraction-networking/conjure/pkg/regserver/overrides" "github.com/refraction-networking/conjure/pkg/station/lib" + "github.com/refraction-networking/conjure/pkg/transports/wrapping/prefix" + pb "github.com/refraction-networking/conjure/proto" "google.golang.org/protobuf/proto" + "google.golang.org/protobuf/types/known/anypb" ) var ( @@ -74,10 +79,26 @@ type RegProcessor struct { regOverrides interfaces.Overrides transports map[pb.TransportType]lib.Transport + + enforceSubnetOverrides bool + overrideSubnets []Subnet + exclusionsFromOverride []Subnet +} + +type Subnet struct { + CIDR ipnet `toml:"cidr"` + Weight float64 `toml:"weight"` + Port int `toml:"port"` + Transport string `toml:"transport"` +} + +// Custom type to handle CIDR notation in TOML +type ipnet struct { + *net.IPNet } // NewRegProcessor initialize a new RegProcessor -func NewRegProcessor(zmqBindAddr string, zmqPort uint16, privkey []byte, authVerbose bool, stationPublicKeys []string, metrics *metrics.Metrics) (*RegProcessor, error) { +func NewRegProcessor(zmqBindAddr string, zmqPort uint16, privkey []byte, authVerbose bool, stationPublicKeys []string, metrics *metrics.Metrics, enforceSubnetOverrides bool, overrideSubnets []Subnet, exclusionsFromOverride []Subnet) (*RegProcessor, error) { if len(privkey) != ed25519.PrivateKeySize { // We require the 64 byte [private_key][public_key] format to Sign using crypto/ed25519 @@ -89,7 +110,7 @@ func NewRegProcessor(zmqBindAddr string, zmqPort uint16, privkey []byte, authVer return nil, err } - regProcessor, err := newRegProcessor(zmqBindAddr, zmqPort, privkey, authVerbose, stationPublicKeys) + regProcessor, err := newRegProcessor(zmqBindAddr, zmqPort, privkey, authVerbose, stationPublicKeys, enforceSubnetOverrides, overrideSubnets, exclusionsFromOverride) if err != nil { return nil, err } @@ -101,7 +122,7 @@ func NewRegProcessor(zmqBindAddr string, zmqPort uint16, privkey []byte, authVer // initializes the registration processor without the phantom selector which can be added by a // wrapping function before it is returned. This function is required for testing. -func newRegProcessor(zmqBindAddr string, zmqPort uint16, privkey []byte, authVerbose bool, stationPublicKeys []string) (*RegProcessor, error) { +func newRegProcessor(zmqBindAddr string, zmqPort uint16, privkey []byte, authVerbose bool, stationPublicKeys []string, enforceSubnetOverrides bool, overrideSubnets []Subnet, exclusionsFromOverride []Subnet) (*RegProcessor, error) { sock, err := zmq.NewSocket(zmq.PUB) if err != nil { return nil, fmt.Errorf("%w: %v", ErrZmqSocket, err) @@ -137,19 +158,25 @@ func newRegProcessor(zmqBindAddr string, zmqPort uint16, privkey []byte, authVer regOverrides = interfaces.Overrides([]interfaces.RegOverride{overrides.NewRandPrefixOverride()}) } - return &RegProcessor{ - zmqMutex: sync.Mutex{}, - selectorMutex: sync.RWMutex{}, - sock: sock, - transports: make(map[pb.TransportType]lib.Transport), - authenticated: true, - privkey: privkey, - regOverrides: regOverrides, - }, nil + rp := &RegProcessor{ + zmqMutex: sync.Mutex{}, + selectorMutex: sync.RWMutex{}, + sock: sock, + transports: make(map[pb.TransportType]lib.Transport), + authenticated: true, + privkey: privkey, + regOverrides: regOverrides, + enforceSubnetOverrides: enforceSubnetOverrides, + overrideSubnets: make([]Subnet, len(overrideSubnets)), + exclusionsFromOverride: make([]Subnet, len(exclusionsFromOverride)), + } + copy(rp.overrideSubnets, overrideSubnets) + + return rp, nil } // NewRegProcessorNoAuth creates a regprocessor without authentication to zmq address -func NewRegProcessorNoAuth(zmqBindAddr string, zmqPort uint16, metrics *metrics.Metrics) (*RegProcessor, error) { +func NewRegProcessorNoAuth(zmqBindAddr string, zmqPort uint16, metrics *metrics.Metrics, enforceSubnetOverrides bool, overrideSubnets []Subnet, exclusionsFromOverride []Subnet) (*RegProcessor, error) { sock, err := zmq.NewSocket(zmq.PUB) if err != nil { return nil, ErrZmqSocket @@ -165,15 +192,21 @@ func NewRegProcessorNoAuth(zmqBindAddr string, zmqPort uint16, metrics *metrics. return nil, err } - return &RegProcessor{ - zmqMutex: sync.Mutex{}, - selectorMutex: sync.RWMutex{}, - ipSelector: phantomSelector, - sock: sock, - metrics: metrics, - transports: make(map[pb.TransportType]lib.Transport), - authenticated: false, - }, nil + rp := &RegProcessor{ + zmqMutex: sync.Mutex{}, + selectorMutex: sync.RWMutex{}, + ipSelector: phantomSelector, + sock: sock, + metrics: metrics, + transports: make(map[pb.TransportType]lib.Transport), + authenticated: false, + enforceSubnetOverrides: enforceSubnetOverrides, + overrideSubnets: make([]Subnet, len(overrideSubnets)), + exclusionsFromOverride: make([]Subnet, len(exclusionsFromOverride)), + } + copy(rp.overrideSubnets, overrideSubnets) + + return rp, nil } // Close cleans up the (ZMQ) servers running in the background supporting registration. @@ -356,9 +389,110 @@ func (p *RegProcessor) processBdReq(c2sPayload *pb.C2SWrapper) (*pb.Registration regResp.DstPort = proto.Uint32(443) } + if p.enforceSubnetOverrides { + // ignore prior choices and begin experimental overrides for Min and Prefix transports only + if transportType == pb.TransportType_Min { + + // TODO: process subnet overrides and pick one according to assigned weights + + ipv4FromRegResponse := uint32ToIPv4(regResp.Ipv4Addr) + for _, subnet := range p.exclusionsFromOverride { + if subnet.CIDR.IPNet.Contains(ipv4FromRegResponse) && subnet.Transport == "Min_Transport" { + // the IPv4 originally chosen by the client exists in a subnet we exluded from overrides + // so do not apply overrides + return regResp, nil + } + } + + // TODO: pick the first override subnet for testing purposes + ipNet := p.overrideSubnets[0].CIDR.IPNet + + ipUint32, err := ipv4ToUint32(ipNet.IP) + if err != nil { + // failed to convert IPv4 to uint32. So do not apply overrides + // and return the original regResp + return regResp, nil + } + + mask := ipNet.Mask + ones, bits := mask.Size() + hosts := uint32(1 << uint(bits-ones)) + + randIpUintFromRange, err := randomInt(ipUint32, ipUint32+hosts) + if err != nil { + // failed to get random IPv4 as uint32 from the given range. + // do not apply override and return the original regResp. + return regResp, nil + } + regResp.Ipv4Addr = proto.Uint32(randIpUintFromRange) + } + } + return regResp, nil } +// Helper function to convert IPv4 to uint32 +func ipv4ToUint32(ip net.IP) (uint32, error) { + err := errors.New("Provided IP is not IPv4") + if ip == nil { + return 0, err + } + + ip = ip.To4() + if ip == nil { + return 0, err + } + + return binary.BigEndian.Uint32(ip), nil +} + +// Helper function to cenvert uint32 to IPv4 +func uint32ToIPv4(ip *uint32) net.IP { + if ip == nil { + return nil + } + + ipInt := *ip + return net.IPv4( + byte(ipInt>>24), + byte(ipInt>>16), + byte(ipInt>>8), + byte(ipInt), + ) +} + +// Helper function to get random integers within a range +func randomInt(x, y uint32) (uint32, error) { + rangeSize := y - x + 1 + // Generate a random number in the range [0, rangeSize) + randomNum, err := rand.Int(rand.Reader, big.NewInt(int64(rangeSize))) + if err != nil { + return 0, err + } + // Return the random number in the range [x, y] + return x + uint32(randomNum.Int64()), nil +} + +// Helper function to override the prefix in the registration response +func overridePrefix(newRegResp *pb.RegistrationResponse, prefixId prefix.PrefixID, dstPort uint32) error { + // Override Phantom dstPort + newRegResp.DstPort = proto.Uint32(dstPort) + // Override Prefix choice and PrefixParam + newPrefix, err := prefix.TryFromID(prefixId) + var fp = newPrefix.FlushPolicy() + var i int32 = int32(newPrefix.ID()) + newparams := &pb.PrefixTransportParams{} + newparams.PrefixId = &i + newparams.CustomFlushPolicy = &fp + newparams.Prefix = newPrefix.Bytes() + anypbParams, err := anypb.New(newparams) + if err != nil { + return err + } + newRegResp.TransportParams = anypbParams + return nil +} + // processC2SWrapper adds missing variables to the input c2s and returns the payload in format ready to be published to zmq func (p *RegProcessor) processC2SWrapper(c2sPayload *pb.C2SWrapper, clientAddr []byte, regMethod pb.RegistrationSource) ([]byte, error) { if c2sPayload == nil { From afed1470531029b6bd76597d5356d8fdda3b4e08 Mon Sep 17 00:00:00 2001 From: 0x90-n Date: Sat, 9 Nov 2024 15:17:03 -0700 Subject: [PATCH 02/14] fixes --- cmd/registration-server/main.go | 5 ++++- pkg/regserver/regprocessor/regprocessor.go | 4 ++-- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/cmd/registration-server/main.go b/cmd/registration-server/main.go index 112d24cf..05c041a7 100644 --- a/cmd/registration-server/main.go +++ b/cmd/registration-server/main.go @@ -53,8 +53,11 @@ type config struct { ExclusionsFromOverride []regprocessor.Subnet `toml:"excluded_subnets_from_overrides"` } +// backing non-local type with local definition +type ipnet regprocessor.Ipnet + // UnmarshalText makes CIDR compatible with TOML decoding -func (n *regprocessor.ipnet) UnmarshalText(text []byte) error { +func (n *ipnet) UnmarshalText(text []byte) error { _, cidr, err := net.ParseCIDR(string(text)) if err != nil { return err diff --git a/pkg/regserver/regprocessor/regprocessor.go b/pkg/regserver/regprocessor/regprocessor.go index 9eeff123..d313b1ca 100644 --- a/pkg/regserver/regprocessor/regprocessor.go +++ b/pkg/regserver/regprocessor/regprocessor.go @@ -86,14 +86,14 @@ type RegProcessor struct { } type Subnet struct { - CIDR ipnet `toml:"cidr"` + CIDR Ipnet `toml:"cidr"` Weight float64 `toml:"weight"` Port int `toml:"port"` Transport string `toml:"transport"` } // Custom type to handle CIDR notation in TOML -type ipnet struct { +type Ipnet struct { *net.IPNet } From 8e81ecf47cb756ef652f82a87bbca31cd536bb20 Mon Sep 17 00:00:00 2001 From: 0x90-n Date: Sat, 9 Nov 2024 17:23:20 -0700 Subject: [PATCH 03/14] more fixes --- cmd/registration-server/main.go | 14 -------------- pkg/regserver/regprocessor/regprocessor.go | 16 +++++++++++++--- 2 files changed, 13 insertions(+), 17 deletions(-) diff --git a/cmd/registration-server/main.go b/cmd/registration-server/main.go index 05c041a7..be828e5d 100644 --- a/cmd/registration-server/main.go +++ b/cmd/registration-server/main.go @@ -4,7 +4,6 @@ import ( "crypto/ed25519" "flag" "fmt" - "net" "os" "os/signal" "strconv" @@ -53,19 +52,6 @@ type config struct { ExclusionsFromOverride []regprocessor.Subnet `toml:"excluded_subnets_from_overrides"` } -// backing non-local type with local definition -type ipnet regprocessor.Ipnet - -// UnmarshalText makes CIDR compatible with TOML decoding -func (n *ipnet) UnmarshalText(text []byte) error { - _, cidr, err := net.ParseCIDR(string(text)) - if err != nil { - return err - } - n.IPNet = cidr - return nil -} - var defaultTransports = map[pb.TransportType]lib.Transport{ pb.TransportType_Min: min.Transport{}, pb.TransportType_Obfs4: obfs4.Transport{}, diff --git a/pkg/regserver/regprocessor/regprocessor.go b/pkg/regserver/regprocessor/regprocessor.go index d313b1ca..ad4045fa 100644 --- a/pkg/regserver/regprocessor/regprocessor.go +++ b/pkg/regserver/regprocessor/regprocessor.go @@ -85,6 +85,16 @@ type RegProcessor struct { exclusionsFromOverride []Subnet } +// UnmarshalText makes CIDR compatible with TOML decoding +func (n *Ipnet) UnmarshalText(text []byte) error { + _, cidr, err := net.ParseCIDR(string(text)) + if err != nil { + return err + } + n.IPNet = cidr + return nil +} + type Subnet struct { CIDR Ipnet `toml:"cidr"` Weight float64 `toml:"weight"` @@ -92,7 +102,6 @@ type Subnet struct { Transport string `toml:"transport"` } -// Custom type to handle CIDR notation in TOML type Ipnet struct { *net.IPNet } @@ -171,6 +180,7 @@ func newRegProcessor(zmqBindAddr string, zmqPort uint16, privkey []byte, authVer exclusionsFromOverride: make([]Subnet, len(exclusionsFromOverride)), } copy(rp.overrideSubnets, overrideSubnets) + copy(rp.exclusionsFromOverride, exclusionsFromOverride) return rp, nil } @@ -205,6 +215,7 @@ func NewRegProcessorNoAuth(zmqBindAddr string, zmqPort uint16, metrics *metrics. exclusionsFromOverride: make([]Subnet, len(exclusionsFromOverride)), } copy(rp.overrideSubnets, overrideSubnets) + copy(rp.exclusionsFromOverride, exclusionsFromOverride) return rp, nil } @@ -388,7 +399,6 @@ func (p *RegProcessor) processBdReq(c2sPayload *pb.C2SWrapper) (*pb.Registration } else { regResp.DstPort = proto.Uint32(443) } - if p.enforceSubnetOverrides { // ignore prior choices and begin experimental overrides for Min and Prefix transports only if transportType == pb.TransportType_Min { @@ -397,7 +407,7 @@ func (p *RegProcessor) processBdReq(c2sPayload *pb.C2SWrapper) (*pb.Registration ipv4FromRegResponse := uint32ToIPv4(regResp.Ipv4Addr) for _, subnet := range p.exclusionsFromOverride { - if subnet.CIDR.IPNet.Contains(ipv4FromRegResponse) && subnet.Transport == "Min_Transport" { + if subnet.CIDR.IPNet.Contains(ipv4FromRegResponse) { // the IPv4 originally chosen by the client exists in a subnet we exluded from overrides // so do not apply overrides return regResp, nil From 46d8b1423db42cc234265b3ded80fa6f68564527 Mon Sep 17 00:00:00 2001 From: 0x90-n Date: Sat, 9 Nov 2024 17:32:46 -0700 Subject: [PATCH 04/14] code reorganization --- pkg/regserver/regprocessor/regprocessor.go | 138 ++++++++++----------- 1 file changed, 69 insertions(+), 69 deletions(-) diff --git a/pkg/regserver/regprocessor/regprocessor.go b/pkg/regserver/regprocessor/regprocessor.go index ad4045fa..da1dfd7e 100644 --- a/pkg/regserver/regprocessor/regprocessor.go +++ b/pkg/regserver/regprocessor/regprocessor.go @@ -85,6 +85,17 @@ type RegProcessor struct { exclusionsFromOverride []Subnet } +type Subnet struct { + CIDR Ipnet `toml:"cidr"` + Weight float64 `toml:"weight"` + Port int `toml:"port"` + Transport string `toml:"transport"` +} + +type Ipnet struct { + *net.IPNet +} + // UnmarshalText makes CIDR compatible with TOML decoding func (n *Ipnet) UnmarshalText(text []byte) error { _, cidr, err := net.ParseCIDR(string(text)) @@ -95,15 +106,66 @@ func (n *Ipnet) UnmarshalText(text []byte) error { return nil } -type Subnet struct { - CIDR Ipnet `toml:"cidr"` - Weight float64 `toml:"weight"` - Port int `toml:"port"` - Transport string `toml:"transport"` +// Helper function to convert IPv4 to uint32 +func ipv4ToUint32(ip net.IP) (uint32, error) { + err := errors.New("Provided IP is not IPv4") + if ip == nil { + return 0, err + } + + ip = ip.To4() + if ip == nil { + return 0, err + } + + return binary.BigEndian.Uint32(ip), nil } -type Ipnet struct { - *net.IPNet +// Helper function to cenvert uint32 to IPv4 +func uint32ToIPv4(ip *uint32) net.IP { + if ip == nil { + return nil + } + + ipInt := *ip + return net.IPv4( + byte(ipInt>>24), + byte(ipInt>>16), + byte(ipInt>>8), + byte(ipInt), + ) +} + +// Helper function to get random integers within a range +func randomInt(x, y uint32) (uint32, error) { + rangeSize := y - x + 1 + // Generate a random number in the range [0, rangeSize) + randomNum, err := rand.Int(rand.Reader, big.NewInt(int64(rangeSize))) + if err != nil { + return 0, err + } + // Return the random number in the range [x, y] + return x + uint32(randomNum.Int64()), nil +} + +// Helper function to override the prefix in the registration response +func overridePrefix(newRegResp *pb.RegistrationResponse, prefixId prefix.PrefixID, dstPort uint32) error { + // Override Phantom dstPort + newRegResp.DstPort = proto.Uint32(dstPort) + // Override Prefix choice and PrefixParam + newPrefix, err := prefix.TryFromID(prefixId) + var fp = newPrefix.FlushPolicy() + var i int32 = int32(newPrefix.ID()) + newparams := &pb.PrefixTransportParams{} + newparams.PrefixId = &i + newparams.CustomFlushPolicy = &fp + newparams.Prefix = newPrefix.Bytes() + anypbParams, err := anypb.New(newparams) + if err != nil { + return err + } + newRegResp.TransportParams = anypbParams + return nil } // NewRegProcessor initialize a new RegProcessor @@ -441,68 +503,6 @@ func (p *RegProcessor) processBdReq(c2sPayload *pb.C2SWrapper) (*pb.Registration return regResp, nil } -// Helper function to convert IPv4 to uint32 -func ipv4ToUint32(ip net.IP) (uint32, error) { - err := errors.New("Provided IP is not IPv4") - if ip == nil { - return 0, err - } - - ip = ip.To4() - if ip == nil { - return 0, err - } - - return binary.BigEndian.Uint32(ip), nil -} - -// Helper function to cenvert uint32 to IPv4 -func uint32ToIPv4(ip *uint32) net.IP { - if ip == nil { - return nil - } - - ipInt := *ip - return net.IPv4( - byte(ipInt>>24), - byte(ipInt>>16), - byte(ipInt>>8), - byte(ipInt), - ) -} - -// Helper function to get random integers within a range -func randomInt(x, y uint32) (uint32, error) { - rangeSize := y - x + 1 - // Generate a random number in the range [0, rangeSize) - randomNum, err := rand.Int(rand.Reader, big.NewInt(int64(rangeSize))) - if err != nil { - return 0, err - } - // Return the random number in the range [x, y] - return x + uint32(randomNum.Int64()), nil -} - -// Helper function to override the prefix in the registration response -func overridePrefix(newRegResp *pb.RegistrationResponse, prefixId prefix.PrefixID, dstPort uint32) error { - // Override Phantom dstPort - newRegResp.DstPort = proto.Uint32(dstPort) - // Override Prefix choice and PrefixParam - newPrefix, err := prefix.TryFromID(prefixId) - var fp = newPrefix.FlushPolicy() - var i int32 = int32(newPrefix.ID()) - newparams := &pb.PrefixTransportParams{} - newparams.PrefixId = &i - newparams.CustomFlushPolicy = &fp - newparams.Prefix = newPrefix.Bytes() - anypbParams, err := anypb.New(newparams) - if err != nil { - return err - } - newRegResp.TransportParams = anypbParams - return nil -} - // processC2SWrapper adds missing variables to the input c2s and returns the payload in format ready to be published to zmq func (p *RegProcessor) processC2SWrapper(c2sPayload *pb.C2SWrapper, clientAddr []byte, regMethod pb.RegistrationSource) ([]byte, error) { if c2sPayload == nil { From ba939f3fd15c6bce3f962ae29ddc7caffbcb6fd6 Mon Sep 17 00:00:00 2001 From: 0x90-n Date: Sat, 9 Nov 2024 18:46:57 -0700 Subject: [PATCH 05/14] splitting overrides by transport --- pkg/regserver/regprocessor/regprocessor.go | 36 +++++++++++++++++----- 1 file changed, 29 insertions(+), 7 deletions(-) diff --git a/pkg/regserver/regprocessor/regprocessor.go b/pkg/regserver/regprocessor/regprocessor.go index da1dfd7e..e59c46c3 100644 --- a/pkg/regserver/regprocessor/regprocessor.go +++ b/pkg/regserver/regprocessor/regprocessor.go @@ -81,7 +81,8 @@ type RegProcessor struct { transports map[pb.TransportType]lib.Transport enforceSubnetOverrides bool - overrideSubnets []Subnet + minOverrideSubnets []Subnet + prefixOverrideSubnets []Subnet exclusionsFromOverride []Subnet } @@ -191,6 +192,22 @@ func NewRegProcessor(zmqBindAddr string, zmqPort uint16, privkey []byte, authVer return regProcessor, nil } +// shallow-copy the override subnets into different slices based on transport type. +// could be improved to handle different transports +func splitOverrideSubnets(overrideSubnets []Subnet) ([]Subnet, []Subnet) { + + var minOverrideSubnets []Subnet + var prefixOverrideSubnets []Subnet + for _, subnet := range overrideSubnets { + if subnet.Transport == "Min_Transport" { + minOverrideSubnets = append(minOverrideSubnets, subnet) + } else if subnet.Transport == "Prefix_Transport" { + prefixOverrideSubnets = append(prefixOverrideSubnets, subnet) + } + } + return minOverrideSubnets, prefixOverrideSubnets +} + // initializes the registration processor without the phantom selector which can be added by a // wrapping function before it is returned. This function is required for testing. func newRegProcessor(zmqBindAddr string, zmqPort uint16, privkey []byte, authVerbose bool, stationPublicKeys []string, enforceSubnetOverrides bool, overrideSubnets []Subnet, exclusionsFromOverride []Subnet) (*RegProcessor, error) { @@ -229,6 +246,8 @@ func newRegProcessor(zmqBindAddr string, zmqPort uint16, privkey []byte, authVer regOverrides = interfaces.Overrides([]interfaces.RegOverride{overrides.NewRandPrefixOverride()}) } + minOverrideSubnets, prefixOverrideSubnets := splitOverrideSubnets(overrideSubnets) + rp := &RegProcessor{ zmqMutex: sync.Mutex{}, selectorMutex: sync.RWMutex{}, @@ -238,10 +257,10 @@ func newRegProcessor(zmqBindAddr string, zmqPort uint16, privkey []byte, authVer privkey: privkey, regOverrides: regOverrides, enforceSubnetOverrides: enforceSubnetOverrides, - overrideSubnets: make([]Subnet, len(overrideSubnets)), + minOverrideSubnets: minOverrideSubnets, + prefixOverrideSubnets: prefixOverrideSubnets, exclusionsFromOverride: make([]Subnet, len(exclusionsFromOverride)), } - copy(rp.overrideSubnets, overrideSubnets) copy(rp.exclusionsFromOverride, exclusionsFromOverride) return rp, nil @@ -264,6 +283,8 @@ func NewRegProcessorNoAuth(zmqBindAddr string, zmqPort uint16, metrics *metrics. return nil, err } + minOverrideSubnets, prefixOverrideSubnets := splitOverrideSubnets(overrideSubnets) + rp := &RegProcessor{ zmqMutex: sync.Mutex{}, selectorMutex: sync.RWMutex{}, @@ -273,10 +294,10 @@ func NewRegProcessorNoAuth(zmqBindAddr string, zmqPort uint16, metrics *metrics. transports: make(map[pb.TransportType]lib.Transport), authenticated: false, enforceSubnetOverrides: enforceSubnetOverrides, - overrideSubnets: make([]Subnet, len(overrideSubnets)), + minOverrideSubnets: minOverrideSubnets, + prefixOverrideSubnets: prefixOverrideSubnets, exclusionsFromOverride: make([]Subnet, len(exclusionsFromOverride)), } - copy(rp.overrideSubnets, overrideSubnets) copy(rp.exclusionsFromOverride, exclusionsFromOverride) return rp, nil @@ -462,6 +483,7 @@ func (p *RegProcessor) processBdReq(c2sPayload *pb.C2SWrapper) (*pb.Registration regResp.DstPort = proto.Uint32(443) } if p.enforceSubnetOverrides { + // ignore prior choices and begin experimental overrides for Min and Prefix transports only if transportType == pb.TransportType_Min { @@ -477,7 +499,7 @@ func (p *RegProcessor) processBdReq(c2sPayload *pb.C2SWrapper) (*pb.Registration } // TODO: pick the first override subnet for testing purposes - ipNet := p.overrideSubnets[0].CIDR.IPNet + ipNet := p.minOverrideSubnets[0].CIDR.IPNet ipUint32, err := ipv4ToUint32(ipNet.IP) if err != nil { @@ -488,7 +510,7 @@ func (p *RegProcessor) processBdReq(c2sPayload *pb.C2SWrapper) (*pb.Registration mask := ipNet.Mask ones, bits := mask.Size() - hosts := uint32(1 << uint(bits-ones)) + hosts := uint32(1 << uint32(bits-ones)) randIpUintFromRange, err := randomInt(ipUint32, ipUint32+hosts) if err != nil { From ddb6eb52d7699f76a9aab03929d8fa51e9c99502 Mon Sep 17 00:00:00 2001 From: 0x90-n Date: Sat, 9 Nov 2024 18:54:10 -0700 Subject: [PATCH 06/14] error handling --- pkg/regserver/regprocessor/regprocessor.go | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/pkg/regserver/regprocessor/regprocessor.go b/pkg/regserver/regprocessor/regprocessor.go index e59c46c3..200a6691 100644 --- a/pkg/regserver/regprocessor/regprocessor.go +++ b/pkg/regserver/regprocessor/regprocessor.go @@ -487,6 +487,10 @@ func (p *RegProcessor) processBdReq(c2sPayload *pb.C2SWrapper) (*pb.Registration // ignore prior choices and begin experimental overrides for Min and Prefix transports only if transportType == pb.TransportType_Min { + if p.minOverrideSubnets == nil { + // reg_conf.toml does not contain subnet overrides for Min transport + return regResp, nil + } // TODO: process subnet overrides and pick one according to assigned weights ipv4FromRegResponse := uint32ToIPv4(regResp.Ipv4Addr) From 579e06cf3f43e95237b59b1c0b263f3d90b692cd Mon Sep 17 00:00:00 2001 From: 0x90-n Date: Sat, 9 Nov 2024 19:36:53 -0700 Subject: [PATCH 07/14] choosing an override subnet based on weight --- pkg/regserver/regprocessor/regprocessor.go | 140 ++++++++++++++------- 1 file changed, 95 insertions(+), 45 deletions(-) diff --git a/pkg/regserver/regprocessor/regprocessor.go b/pkg/regserver/regprocessor/regprocessor.go index 200a6691..6d7b2bb0 100644 --- a/pkg/regserver/regprocessor/regprocessor.go +++ b/pkg/regserver/regprocessor/regprocessor.go @@ -12,8 +12,10 @@ import ( "errors" "fmt" "math/big" + mrand "math/rand" "net" "sync" + "time" zmq "github.com/pebbe/zmq4" "github.com/refraction-networking/conjure/pkg/core" @@ -80,10 +82,14 @@ type RegProcessor struct { transports map[pb.TransportType]lib.Transport - enforceSubnetOverrides bool - minOverrideSubnets []Subnet - prefixOverrideSubnets []Subnet - exclusionsFromOverride []Subnet + enforceSubnetOverrides bool + minOverrideSubnets []Subnet + minOverrideSubnetsTotalWeight float64 + minOverrideSubnetsCumulativeWeights []float64 + prefixOverrideSubnetsTotalWeight float64 + prefixOverrideSubnetsCumulativeWeights []float64 + prefixOverrideSubnets []Subnet + exclusionsFromOverride []Subnet } type Subnet struct { @@ -169,6 +175,45 @@ func overridePrefix(newRegResp *pb.RegistrationResponse, prefixId prefix.PrefixI return nil } +// shallow-copy the override subnets into different slices based on transport type. +// could be improved to handle different transports +func splitOverrideSubnets(overrideSubnets []Subnet) ([]Subnet, []Subnet) { + + var minOverrideSubnets []Subnet + var prefixOverrideSubnets []Subnet + for _, subnet := range overrideSubnets { + if subnet.Transport == "Min_Transport" { + minOverrideSubnets = append(minOverrideSubnets, subnet) + } else if subnet.Transport == "Prefix_Transport" { + prefixOverrideSubnets = append(prefixOverrideSubnets, subnet) + } + } + return minOverrideSubnets, prefixOverrideSubnets +} + +// calculate cumulative weights for a given subnets slice +func processOverrideSubnetsWeights(subnets []Subnet) []float64 { + + if len(subnets) == 0 { + return nil + } + + var totalWeight float64 + for _, subnet := range subnets { + totalWeight += subnet.Weight + } + + cumulativeWeights := make([]float64, len(subnets)) + for i, subnet := range subnets { + if i == 0 { + cumulativeWeights[i] = subnet.Weight / totalWeight + } else { + cumulativeWeights[i] = cumulativeWeights[i-1] + (subnet.Weight / totalWeight) + } + } + return cumulativeWeights +} + // NewRegProcessor initialize a new RegProcessor func NewRegProcessor(zmqBindAddr string, zmqPort uint16, privkey []byte, authVerbose bool, stationPublicKeys []string, metrics *metrics.Metrics, enforceSubnetOverrides bool, overrideSubnets []Subnet, exclusionsFromOverride []Subnet) (*RegProcessor, error) { @@ -192,22 +237,6 @@ func NewRegProcessor(zmqBindAddr string, zmqPort uint16, privkey []byte, authVer return regProcessor, nil } -// shallow-copy the override subnets into different slices based on transport type. -// could be improved to handle different transports -func splitOverrideSubnets(overrideSubnets []Subnet) ([]Subnet, []Subnet) { - - var minOverrideSubnets []Subnet - var prefixOverrideSubnets []Subnet - for _, subnet := range overrideSubnets { - if subnet.Transport == "Min_Transport" { - minOverrideSubnets = append(minOverrideSubnets, subnet) - } else if subnet.Transport == "Prefix_Transport" { - prefixOverrideSubnets = append(prefixOverrideSubnets, subnet) - } - } - return minOverrideSubnets, prefixOverrideSubnets -} - // initializes the registration processor without the phantom selector which can be added by a // wrapping function before it is returned. This function is required for testing. func newRegProcessor(zmqBindAddr string, zmqPort uint16, privkey []byte, authVerbose bool, stationPublicKeys []string, enforceSubnetOverrides bool, overrideSubnets []Subnet, exclusionsFromOverride []Subnet) (*RegProcessor, error) { @@ -248,18 +277,23 @@ func newRegProcessor(zmqBindAddr string, zmqPort uint16, privkey []byte, authVer minOverrideSubnets, prefixOverrideSubnets := splitOverrideSubnets(overrideSubnets) + minOverrideSubnetsCumulativeWeights := processOverrideSubnetsWeights(minOverrideSubnets) + prefixOverrideSubnetsCumulativeWeights := processOverrideSubnetsWeights(minOverrideSubnets) + rp := &RegProcessor{ - zmqMutex: sync.Mutex{}, - selectorMutex: sync.RWMutex{}, - sock: sock, - transports: make(map[pb.TransportType]lib.Transport), - authenticated: true, - privkey: privkey, - regOverrides: regOverrides, - enforceSubnetOverrides: enforceSubnetOverrides, - minOverrideSubnets: minOverrideSubnets, - prefixOverrideSubnets: prefixOverrideSubnets, - exclusionsFromOverride: make([]Subnet, len(exclusionsFromOverride)), + zmqMutex: sync.Mutex{}, + selectorMutex: sync.RWMutex{}, + sock: sock, + transports: make(map[pb.TransportType]lib.Transport), + authenticated: true, + privkey: privkey, + regOverrides: regOverrides, + enforceSubnetOverrides: enforceSubnetOverrides, + minOverrideSubnets: minOverrideSubnets, + prefixOverrideSubnets: prefixOverrideSubnets, + minOverrideSubnetsCumulativeWeights: minOverrideSubnetsCumulativeWeights, + prefixOverrideSubnetsCumulativeWeights: prefixOverrideSubnetsCumulativeWeights, + exclusionsFromOverride: make([]Subnet, len(exclusionsFromOverride)), } copy(rp.exclusionsFromOverride, exclusionsFromOverride) @@ -285,18 +319,23 @@ func NewRegProcessorNoAuth(zmqBindAddr string, zmqPort uint16, metrics *metrics. minOverrideSubnets, prefixOverrideSubnets := splitOverrideSubnets(overrideSubnets) + minOverrideSubnetsCumulativeWeights := processOverrideSubnetsWeights(minOverrideSubnets) + prefixOverrideSubnetsCumulativeWeights := processOverrideSubnetsWeights(minOverrideSubnets) + rp := &RegProcessor{ - zmqMutex: sync.Mutex{}, - selectorMutex: sync.RWMutex{}, - ipSelector: phantomSelector, - sock: sock, - metrics: metrics, - transports: make(map[pb.TransportType]lib.Transport), - authenticated: false, - enforceSubnetOverrides: enforceSubnetOverrides, - minOverrideSubnets: minOverrideSubnets, - prefixOverrideSubnets: prefixOverrideSubnets, - exclusionsFromOverride: make([]Subnet, len(exclusionsFromOverride)), + zmqMutex: sync.Mutex{}, + selectorMutex: sync.RWMutex{}, + ipSelector: phantomSelector, + sock: sock, + metrics: metrics, + transports: make(map[pb.TransportType]lib.Transport), + authenticated: false, + enforceSubnetOverrides: enforceSubnetOverrides, + minOverrideSubnets: minOverrideSubnets, + prefixOverrideSubnets: prefixOverrideSubnets, + minOverrideSubnetsCumulativeWeights: minOverrideSubnetsCumulativeWeights, + prefixOverrideSubnetsCumulativeWeights: prefixOverrideSubnetsCumulativeWeights, + exclusionsFromOverride: make([]Subnet, len(exclusionsFromOverride)), } copy(rp.exclusionsFromOverride, exclusionsFromOverride) @@ -491,7 +530,6 @@ func (p *RegProcessor) processBdReq(c2sPayload *pb.C2SWrapper) (*pb.Registration // reg_conf.toml does not contain subnet overrides for Min transport return regResp, nil } - // TODO: process subnet overrides and pick one according to assigned weights ipv4FromRegResponse := uint32ToIPv4(regResp.Ipv4Addr) for _, subnet := range p.exclusionsFromOverride { @@ -502,8 +540,20 @@ func (p *RegProcessor) processBdReq(c2sPayload *pb.C2SWrapper) (*pb.Registration } } - // TODO: pick the first override subnet for testing purposes - ipNet := p.minOverrideSubnets[0].CIDR.IPNet + var ipNet *net.IPNet + mrand.Seed(time.Now().UnixNano()) + randVal := mrand.Float64() + + for i, cumulativeWeight := range p.minOverrideSubnetsCumulativeWeights { + if randVal < cumulativeWeight { + ipNet = p.minOverrideSubnets[i].CIDR.IPNet + } + } + if ipNet == nil { + // problem in choosing a weighted override subnet + // so do not apply overrides + return regResp, nil + } ipUint32, err := ipv4ToUint32(ipNet.IP) if err != nil { From 23a6835cf3a81c972d678761b9e6e10fe182597a Mon Sep 17 00:00:00 2001 From: 0x90-n Date: Mon, 11 Nov 2024 10:50:10 -0700 Subject: [PATCH 08/14] supporting v4 phantom overrides for min and prefix transports --- cmd/registration-server/main.go | 40 ++--- pkg/regserver/regprocessor/regprocessor.go | 177 +++++++++++++++------ 2 files changed, 151 insertions(+), 66 deletions(-) diff --git a/cmd/registration-server/main.go b/cmd/registration-server/main.go index be828e5d..6a0234b8 100644 --- a/cmd/registration-server/main.go +++ b/cmd/registration-server/main.go @@ -33,23 +33,25 @@ type regServer interface { // config defines the variables and options from the toml config file type config struct { - DNSListenAddr string `toml:"dns_listen_addr"` - Domain string `toml:"domain"` - DNSPrivkeyPath string `toml:"dns_private_key_path"` - APIPort uint16 `toml:"api_port"` - ZMQAuthVerbose bool `toml:"zmq_auth_verbose"` - ZMQAuthType string `toml:"zmq_auth_type"` - ZMQPort uint16 `toml:"zmq_port"` - ZMQBindAddr string `toml:"zmq_bind_addr"` - ZMQPrivateKeyPath string `toml:"zmq_privkey_path"` - StationPublicKeys []string `toml:"station_pubkeys"` - ClientConfPath string `toml:"clientconf_path"` - latestClientConf *pb.ClientConf - LogLevel string `toml:"log_level"` - LogMetricsInterval uint16 `toml:"log_metrics_interval"` - EnforceSubnetOverrides bool `toml:"enforce_subnet_overrides"` - OverrideSubnets []regprocessor.Subnet `toml:"override_subnets"` - ExclusionsFromOverride []regprocessor.Subnet `toml:"excluded_subnets_from_overrides"` + DNSListenAddr string `toml:"dns_listen_addr"` + Domain string `toml:"domain"` + DNSPrivkeyPath string `toml:"dns_private_key_path"` + APIPort uint16 `toml:"api_port"` + ZMQAuthVerbose bool `toml:"zmq_auth_verbose"` + ZMQAuthType string `toml:"zmq_auth_type"` + ZMQPort uint16 `toml:"zmq_port"` + ZMQBindAddr string `toml:"zmq_bind_addr"` + ZMQPrivateKeyPath string `toml:"zmq_privkey_path"` + StationPublicKeys []string `toml:"station_pubkeys"` + ClientConfPath string `toml:"clientconf_path"` + latestClientConf *pb.ClientConf + LogLevel string `toml:"log_level"` + LogMetricsInterval uint16 `toml:"log_metrics_interval"` + EnforceSubnetOverrides bool `toml:"enforce_subnet_overrides"` + PrcntMinConnsToOverride float64 `toml:"prcnt_min_conns_to_override"` + PrcntPrefixConnsToOverride float64 `toml:"prcnt_prefix_conns_to_override"` + OverrideSubnets []regprocessor.Subnet `toml:"override_subnets"` + ExclusionsFromOverride []regprocessor.Subnet `toml:"excluded_subnets_from_overrides"` } var defaultTransports = map[pb.TransportType]lib.Transport{ @@ -195,9 +197,9 @@ func main() { switch conf.ZMQAuthType { case "CURVE": - processor, err = regprocessor.NewRegProcessor(conf.ZMQBindAddr, conf.ZMQPort, zmqPrivkey, conf.ZMQAuthVerbose, conf.StationPublicKeys, metrics, conf.EnforceSubnetOverrides, conf.OverrideSubnets, conf.ExclusionsFromOverride) + processor, err = regprocessor.NewRegProcessor(conf.ZMQBindAddr, conf.ZMQPort, zmqPrivkey, conf.ZMQAuthVerbose, conf.StationPublicKeys, metrics, conf.EnforceSubnetOverrides, conf.OverrideSubnets, conf.ExclusionsFromOverride, conf.PrcntMinConnsToOverride, conf.PrcntPrefixConnsToOverride) case "NULL": - processor, err = regprocessor.NewRegProcessorNoAuth(conf.ZMQBindAddr, conf.ZMQPort, metrics, conf.EnforceSubnetOverrides, conf.OverrideSubnets, conf.ExclusionsFromOverride) + processor, err = regprocessor.NewRegProcessorNoAuth(conf.ZMQBindAddr, conf.ZMQPort, metrics, conf.EnforceSubnetOverrides, conf.OverrideSubnets, conf.ExclusionsFromOverride, conf.PrcntMinConnsToOverride, conf.PrcntPrefixConnsToOverride) default: log.Fatalf("Unknown ZMQ auth type: %s", conf.ZMQAuthType) } diff --git a/pkg/regserver/regprocessor/regprocessor.go b/pkg/regserver/regprocessor/regprocessor.go index 6d7b2bb0..45a5edda 100644 --- a/pkg/regserver/regprocessor/regprocessor.go +++ b/pkg/regserver/regprocessor/regprocessor.go @@ -11,6 +11,7 @@ import ( "encoding/binary" "errors" "fmt" + "math" "math/big" mrand "math/rand" "net" @@ -84,19 +85,20 @@ type RegProcessor struct { enforceSubnetOverrides bool minOverrideSubnets []Subnet - minOverrideSubnetsTotalWeight float64 minOverrideSubnetsCumulativeWeights []float64 - prefixOverrideSubnetsTotalWeight float64 prefixOverrideSubnetsCumulativeWeights []float64 prefixOverrideSubnets []Subnet exclusionsFromOverride []Subnet + prcntMinConnsToOverride float64 + prcntPrefixConnsToOverride float64 } type Subnet struct { CIDR Ipnet `toml:"cidr"` Weight float64 `toml:"weight"` - Port int `toml:"port"` + Port uint32 `toml:"port"` Transport string `toml:"transport"` + PrefixxID int `toml:"prefix_id"` } type Ipnet struct { @@ -143,6 +145,24 @@ func uint32ToIPv4(ip *uint32) net.IP { ) } +// Helper function that wraps randomInt() +func getRandUint32IPv4(ipNet *net.IPNet) (uint32, error) { + ipUint32, err := ipv4ToUint32(ipNet.IP) + if err != nil { + return 0, errors.New("Failed to convert IPv4 to uint32") + } + + mask := ipNet.Mask + ones, bits := mask.Size() + hosts := uint32(1 << uint32(bits-ones)) + + ip, err := randomInt(ipUint32, ipUint32+hosts) + if err != nil { + return 0, errors.New("Failed to get random IPv4 as uint32 from the given range") + } + return ip, nil +} + // Helper function to get random integers within a range func randomInt(x, y uint32) (uint32, error) { rangeSize := y - x + 1 @@ -215,7 +235,7 @@ func processOverrideSubnetsWeights(subnets []Subnet) []float64 { } // NewRegProcessor initialize a new RegProcessor -func NewRegProcessor(zmqBindAddr string, zmqPort uint16, privkey []byte, authVerbose bool, stationPublicKeys []string, metrics *metrics.Metrics, enforceSubnetOverrides bool, overrideSubnets []Subnet, exclusionsFromOverride []Subnet) (*RegProcessor, error) { +func NewRegProcessor(zmqBindAddr string, zmqPort uint16, privkey []byte, authVerbose bool, stationPublicKeys []string, metrics *metrics.Metrics, enforceSubnetOverrides bool, overrideSubnets []Subnet, exclusionsFromOverride []Subnet, prcntMinConnsToOverride float64, prcntPrefixConnsToOverride float64) (*RegProcessor, error) { if len(privkey) != ed25519.PrivateKeySize { // We require the 64 byte [private_key][public_key] format to Sign using crypto/ed25519 @@ -227,7 +247,7 @@ func NewRegProcessor(zmqBindAddr string, zmqPort uint16, privkey []byte, authVer return nil, err } - regProcessor, err := newRegProcessor(zmqBindAddr, zmqPort, privkey, authVerbose, stationPublicKeys, enforceSubnetOverrides, overrideSubnets, exclusionsFromOverride) + regProcessor, err := newRegProcessor(zmqBindAddr, zmqPort, privkey, authVerbose, stationPublicKeys, enforceSubnetOverrides, overrideSubnets, exclusionsFromOverride, prcntMinConnsToOverride, prcntPrefixConnsToOverride) if err != nil { return nil, err } @@ -239,7 +259,7 @@ func NewRegProcessor(zmqBindAddr string, zmqPort uint16, privkey []byte, authVer // initializes the registration processor without the phantom selector which can be added by a // wrapping function before it is returned. This function is required for testing. -func newRegProcessor(zmqBindAddr string, zmqPort uint16, privkey []byte, authVerbose bool, stationPublicKeys []string, enforceSubnetOverrides bool, overrideSubnets []Subnet, exclusionsFromOverride []Subnet) (*RegProcessor, error) { +func newRegProcessor(zmqBindAddr string, zmqPort uint16, privkey []byte, authVerbose bool, stationPublicKeys []string, enforceSubnetOverrides bool, overrideSubnets []Subnet, exclusionsFromOverride []Subnet, prcntMinConnsToOverride float64, prcntPrefixConnsToOverride float64) (*RegProcessor, error) { sock, err := zmq.NewSocket(zmq.PUB) if err != nil { return nil, fmt.Errorf("%w: %v", ErrZmqSocket, err) @@ -275,6 +295,19 @@ func newRegProcessor(zmqBindAddr string, zmqPort uint16, privkey []byte, authVer regOverrides = interfaces.Overrides([]interfaces.RegOverride{overrides.NewRandPrefixOverride()}) } + if prcntMinConnsToOverride > 100.0 || prcntMinConnsToOverride < 0.0 { + fmt.Println("prcnt_min_conns_to_override value in reg_config.toml is out of range [0,100]. Resetting to 50%") + prcntMinConnsToOverride = 50 * 10 + } else { + prcntMinConnsToOverride = math.Round(prcntMinConnsToOverride*100) / 10 + } + if prcntPrefixConnsToOverride > 100.0 || prcntPrefixConnsToOverride < 0.0 { + fmt.Println("prcnt_prefix_conns_to_override value in reg_config.toml is out of range [0,100]. Resetting to 50%") + prcntPrefixConnsToOverride = 50 * 10 + } else { + prcntPrefixConnsToOverride = math.Round(prcntPrefixConnsToOverride*100) / 10 + } + minOverrideSubnets, prefixOverrideSubnets := splitOverrideSubnets(overrideSubnets) minOverrideSubnetsCumulativeWeights := processOverrideSubnetsWeights(minOverrideSubnets) @@ -294,6 +327,8 @@ func newRegProcessor(zmqBindAddr string, zmqPort uint16, privkey []byte, authVer minOverrideSubnetsCumulativeWeights: minOverrideSubnetsCumulativeWeights, prefixOverrideSubnetsCumulativeWeights: prefixOverrideSubnetsCumulativeWeights, exclusionsFromOverride: make([]Subnet, len(exclusionsFromOverride)), + prcntMinConnsToOverride: prcntMinConnsToOverride, + prcntPrefixConnsToOverride: prcntPrefixConnsToOverride, } copy(rp.exclusionsFromOverride, exclusionsFromOverride) @@ -301,7 +336,7 @@ func newRegProcessor(zmqBindAddr string, zmqPort uint16, privkey []byte, authVer } // NewRegProcessorNoAuth creates a regprocessor without authentication to zmq address -func NewRegProcessorNoAuth(zmqBindAddr string, zmqPort uint16, metrics *metrics.Metrics, enforceSubnetOverrides bool, overrideSubnets []Subnet, exclusionsFromOverride []Subnet) (*RegProcessor, error) { +func NewRegProcessorNoAuth(zmqBindAddr string, zmqPort uint16, metrics *metrics.Metrics, enforceSubnetOverrides bool, overrideSubnets []Subnet, exclusionsFromOverride []Subnet, prcntMinConnsToOverride float64, prcntPrefixConnsToOverride float64) (*RegProcessor, error) { sock, err := zmq.NewSocket(zmq.PUB) if err != nil { return nil, ErrZmqSocket @@ -336,6 +371,8 @@ func NewRegProcessorNoAuth(zmqBindAddr string, zmqPort uint16, metrics *metrics. minOverrideSubnetsCumulativeWeights: minOverrideSubnetsCumulativeWeights, prefixOverrideSubnetsCumulativeWeights: prefixOverrideSubnetsCumulativeWeights, exclusionsFromOverride: make([]Subnet, len(exclusionsFromOverride)), + prcntMinConnsToOverride: prcntMinConnsToOverride, + prcntPrefixConnsToOverride: prcntPrefixConnsToOverride, } copy(rp.exclusionsFromOverride, exclusionsFromOverride) @@ -522,60 +559,106 @@ func (p *RegProcessor) processBdReq(c2sPayload *pb.C2SWrapper) (*pb.Registration regResp.DstPort = proto.Uint32(443) } if p.enforceSubnetOverrides { + ipv4FromRegResponse := uint32ToIPv4(regResp.Ipv4Addr) + for _, subnet := range p.exclusionsFromOverride { + // TODO: apply exclusions based on both transport and subnet + if subnet.CIDR.IPNet.Contains(ipv4FromRegResponse) { + // the IPv4 originally chosen by the client exists in a subnet we excluded from overrides + // so do not apply overrides + return regResp, nil + } + } + + num, err := randomInt(0, 10000) + if err != nil { + // In case of an error, return the original regResp and + // do not apply overrides + return regResp, nil + } + randNumFloat := float64(num) / 10.0 + + var ipNet *net.IPNet + var dstPortOverride uint32 + mrand.Seed(time.Now().UnixNano()) + randVal := mrand.Float64() // ignore prior choices and begin experimental overrides for Min and Prefix transports only if transportType == pb.TransportType_Min { + if randNumFloat < p.prcntMinConnsToOverride { + if p.minOverrideSubnets == nil { + // reg_conf.toml does not contain subnet overrides for Min transport + return regResp, nil + } - if p.minOverrideSubnets == nil { - // reg_conf.toml does not contain subnet overrides for Min transport - return regResp, nil - } + for i, cumulativeWeight := range p.minOverrideSubnetsCumulativeWeights { + if randVal < cumulativeWeight { + ipNet = p.minOverrideSubnets[i].CIDR.IPNet + //dstPortOverride = p.minOverrideSubnets[i].Port + } + } - ipv4FromRegResponse := uint32ToIPv4(regResp.Ipv4Addr) - for _, subnet := range p.exclusionsFromOverride { - if subnet.CIDR.IPNet.Contains(ipv4FromRegResponse) { - // the IPv4 originally chosen by the client exists in a subnet we exluded from overrides + if ipNet == nil { + // problem in choosing a weighted override subnet // so do not apply overrides return regResp, nil } - } - - var ipNet *net.IPNet - mrand.Seed(time.Now().UnixNano()) - randVal := mrand.Float64() - for i, cumulativeWeight := range p.minOverrideSubnetsCumulativeWeights { - if randVal < cumulativeWeight { - ipNet = p.minOverrideSubnets[i].CIDR.IPNet + ip, err := getRandUint32IPv4(ipNet) + if err != nil { + // failed to get random IPv4 as uint32 from the given range. + // do not apply override and return the original regResp. + return regResp, nil } + regResp.Ipv4Addr = proto.Uint32(ip) } - if ipNet == nil { - // problem in choosing a weighted override subnet - // so do not apply overrides - return regResp, nil - } - - ipUint32, err := ipv4ToUint32(ipNet.IP) - if err != nil { - // failed to convert IPv4 to uint32. So do not apply overrides - // and return the original regResp - return regResp, nil - } - - mask := ipNet.Mask - ones, bits := mask.Size() - hosts := uint32(1 << uint32(bits-ones)) - - randIpUintFromRange, err := randomInt(ipUint32, ipUint32+hosts) - if err != nil { - // failed to get random IPv4 as uint32 from the given range. - // do not apply override and return the original regResp. - return regResp, nil + } else if transportType == pb.TransportType_Prefix { + + // Override the Phantom IPv4 for clients with the Prefix transport + // and override the transport type only if c2s.GetDisableRegistrarOverrides() is false + if !c2s.GetDisableRegistrarOverrides() { + if randNumFloat < p.prcntPrefixConnsToOverride { + if p.prefixOverrideSubnets == nil { + // reg_conf.toml does not contain subnet overrides for Prefix transport + return regResp, nil + } + + //newRegResp := &pb.RegistrationResponse{} + var prefixid int + for i, cumulativeWeight := range p.prefixOverrideSubnetsCumulativeWeights { + if randVal < cumulativeWeight { + ipNet = p.prefixOverrideSubnets[i].CIDR.IPNet + dstPortOverride = p.prefixOverrideSubnets[i].Port + prefixid = p.prefixOverrideSubnets[i].PrefixxID + } + } + + if ipNet == nil { + // problem in choosing a weighted override subnet + // so do not apply overrides + return regResp, nil + } + + ip, err := getRandUint32IPv4(ipNet) + if err != nil { + // failed to get random IPv4 as uint32 from the given range. + // do not apply override and return the original regResp. + return regResp, nil + } + + newRegResp := proto.Clone(regResp).(*pb.RegistrationResponse) + + err = overridePrefix(newRegResp, prefixid, dstPortOverride) + if err != nil { + return regResp, nil + } + newRegResp.Ipv4Addr = proto.Uint32(ip) + + regResp = newRegResp + c2sPayload.RegistrationResponse = regResp + } } - regResp.Ipv4Addr = proto.Uint32(randIpUintFromRange) } } - return regResp, nil } From 656fe1fe2361ca7abb739159051608c2d4345554 Mon Sep 17 00:00:00 2001 From: 0x90-n Date: Mon, 11 Nov 2024 10:59:38 -0700 Subject: [PATCH 09/14] fixes --- pkg/regserver/regprocessor/regprocessor.go | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/pkg/regserver/regprocessor/regprocessor.go b/pkg/regserver/regprocessor/regprocessor.go index 45a5edda..1d0b769d 100644 --- a/pkg/regserver/regprocessor/regprocessor.go +++ b/pkg/regserver/regprocessor/regprocessor.go @@ -94,11 +94,11 @@ type RegProcessor struct { } type Subnet struct { - CIDR Ipnet `toml:"cidr"` - Weight float64 `toml:"weight"` - Port uint32 `toml:"port"` - Transport string `toml:"transport"` - PrefixxID int `toml:"prefix_id"` + CIDR Ipnet `toml:"cidr"` + Weight float64 `toml:"weight"` + Port uint32 `toml:"port"` + Transport string `toml:"transport"` + PrefixId prefix.PrefixID `toml:"prefix_id"` } type Ipnet struct { @@ -623,12 +623,12 @@ func (p *RegProcessor) processBdReq(c2sPayload *pb.C2SWrapper) (*pb.Registration } //newRegResp := &pb.RegistrationResponse{} - var prefixid int + var prefixid prefix.PrefixID for i, cumulativeWeight := range p.prefixOverrideSubnetsCumulativeWeights { if randVal < cumulativeWeight { ipNet = p.prefixOverrideSubnets[i].CIDR.IPNet dstPortOverride = p.prefixOverrideSubnets[i].Port - prefixid = p.prefixOverrideSubnets[i].PrefixxID + prefixid = p.prefixOverrideSubnets[i].PrefixId } } From fc6f1714147cd86ac5784617adc57318df697455 Mon Sep 17 00:00:00 2001 From: 0x90-n Date: Mon, 11 Nov 2024 11:17:28 -0700 Subject: [PATCH 10/14] more fixes --- pkg/regserver/regprocessor/regprocessor.go | 46 +++++++++++++--------- 1 file changed, 27 insertions(+), 19 deletions(-) diff --git a/pkg/regserver/regprocessor/regprocessor.go b/pkg/regserver/regprocessor/regprocessor.go index 1d0b769d..d202e1a8 100644 --- a/pkg/regserver/regprocessor/regprocessor.go +++ b/pkg/regserver/regprocessor/regprocessor.go @@ -115,7 +115,7 @@ func (n *Ipnet) UnmarshalText(text []byte) error { return nil } -// Helper function to convert IPv4 to uint32 +// helper function to convert IPv4 to uint32 func ipv4ToUint32(ip net.IP) (uint32, error) { err := errors.New("Provided IP is not IPv4") if ip == nil { @@ -130,7 +130,7 @@ func ipv4ToUint32(ip net.IP) (uint32, error) { return binary.BigEndian.Uint32(ip), nil } -// Helper function to cenvert uint32 to IPv4 +// helper function to cenvert uint32 to IPv4 func uint32ToIPv4(ip *uint32) net.IP { if ip == nil { return nil @@ -145,7 +145,7 @@ func uint32ToIPv4(ip *uint32) net.IP { ) } -// Helper function that wraps randomInt() +// helper function that wraps randomInt() func getRandUint32IPv4(ipNet *net.IPNet) (uint32, error) { ipUint32, err := ipv4ToUint32(ipNet.IP) if err != nil { @@ -163,7 +163,7 @@ func getRandUint32IPv4(ipNet *net.IPNet) (uint32, error) { return ip, nil } -// Helper function to get random integers within a range +// helper function to get random integers within a range func randomInt(x, y uint32) (uint32, error) { rangeSize := y - x + 1 // Generate a random number in the range [0, rangeSize) @@ -175,7 +175,7 @@ func randomInt(x, y uint32) (uint32, error) { return x + uint32(randomNum.Int64()), nil } -// Helper function to override the prefix in the registration response +// helper function to override the prefix in the registration response func overridePrefix(newRegResp *pb.RegistrationResponse, prefixId prefix.PrefixID, dstPort uint32) error { // Override Phantom dstPort newRegResp.DstPort = proto.Uint32(dstPort) @@ -195,6 +195,23 @@ func overridePrefix(newRegResp *pb.RegistrationResponse, prefixId prefix.PrefixI return nil } +// helper function to validate override percentages for the Min and Prefix transports set by reg_config.toml +func validateOverridePercentages(prcntMinConnsToOverride float64, prcntPrefixConnsToOverride float64) (float64, float64) { + if prcntMinConnsToOverride > 100.0 || prcntMinConnsToOverride < 0.0 { + fmt.Println("prcnt_min_conns_to_override value in reg_config.toml is out of range [0,100]. Resetting to 50%") + prcntMinConnsToOverride = 50 * 10 + } else { + prcntMinConnsToOverride = math.Round(prcntMinConnsToOverride*100) / 10 + } + if prcntPrefixConnsToOverride > 100.0 || prcntPrefixConnsToOverride < 0.0 { + fmt.Println("prcnt_prefix_conns_to_override value in reg_config.toml is out of range [0,100]. Resetting to 50%") + prcntPrefixConnsToOverride = 50 * 10 + } else { + prcntPrefixConnsToOverride = math.Round(prcntPrefixConnsToOverride*100) / 10 + } + return prcntMinConnsToOverride, prcntPrefixConnsToOverride +} + // shallow-copy the override subnets into different slices based on transport type. // could be improved to handle different transports func splitOverrideSubnets(overrideSubnets []Subnet) ([]Subnet, []Subnet) { @@ -295,23 +312,12 @@ func newRegProcessor(zmqBindAddr string, zmqPort uint16, privkey []byte, authVer regOverrides = interfaces.Overrides([]interfaces.RegOverride{overrides.NewRandPrefixOverride()}) } - if prcntMinConnsToOverride > 100.0 || prcntMinConnsToOverride < 0.0 { - fmt.Println("prcnt_min_conns_to_override value in reg_config.toml is out of range [0,100]. Resetting to 50%") - prcntMinConnsToOverride = 50 * 10 - } else { - prcntMinConnsToOverride = math.Round(prcntMinConnsToOverride*100) / 10 - } - if prcntPrefixConnsToOverride > 100.0 || prcntPrefixConnsToOverride < 0.0 { - fmt.Println("prcnt_prefix_conns_to_override value in reg_config.toml is out of range [0,100]. Resetting to 50%") - prcntPrefixConnsToOverride = 50 * 10 - } else { - prcntPrefixConnsToOverride = math.Round(prcntPrefixConnsToOverride*100) / 10 - } + prcntMinConnsToOverride, prcntPrefixConnsToOverride = validateOverridePercentages(prcntMinConnsToOverride, prcntPrefixConnsToOverride) minOverrideSubnets, prefixOverrideSubnets := splitOverrideSubnets(overrideSubnets) minOverrideSubnetsCumulativeWeights := processOverrideSubnetsWeights(minOverrideSubnets) - prefixOverrideSubnetsCumulativeWeights := processOverrideSubnetsWeights(minOverrideSubnets) + prefixOverrideSubnetsCumulativeWeights := processOverrideSubnetsWeights(prefixOverrideSubnets) rp := &RegProcessor{ zmqMutex: sync.Mutex{}, @@ -352,10 +358,12 @@ func NewRegProcessorNoAuth(zmqBindAddr string, zmqPort uint16, metrics *metrics. return nil, err } + prcntMinConnsToOverride, prcntPrefixConnsToOverride = validateOverridePercentages(prcntMinConnsToOverride, prcntPrefixConnsToOverride) + minOverrideSubnets, prefixOverrideSubnets := splitOverrideSubnets(overrideSubnets) minOverrideSubnetsCumulativeWeights := processOverrideSubnetsWeights(minOverrideSubnets) - prefixOverrideSubnetsCumulativeWeights := processOverrideSubnetsWeights(minOverrideSubnets) + prefixOverrideSubnetsCumulativeWeights := processOverrideSubnetsWeights(prefixOverrideSubnets) rp := &RegProcessor{ zmqMutex: sync.Mutex{}, From db1ebfd5a614d7e0dba78da5678816cf93c77a25 Mon Sep 17 00:00:00 2001 From: 0x90-n Date: Mon, 11 Nov 2024 12:12:40 -0700 Subject: [PATCH 11/14] fix off-by-one --- pkg/regserver/regprocessor/regprocessor.go | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/pkg/regserver/regprocessor/regprocessor.go b/pkg/regserver/regprocessor/regprocessor.go index d202e1a8..170224d3 100644 --- a/pkg/regserver/regprocessor/regprocessor.go +++ b/pkg/regserver/regprocessor/regprocessor.go @@ -165,7 +165,7 @@ func getRandUint32IPv4(ipNet *net.IPNet) (uint32, error) { // helper function to get random integers within a range func randomInt(x, y uint32) (uint32, error) { - rangeSize := y - x + 1 + rangeSize := y - x // Generate a random number in the range [0, rangeSize) randomNum, err := rand.Int(rand.Reader, big.NewInt(int64(rangeSize))) if err != nil { @@ -583,10 +583,14 @@ func (p *RegProcessor) processBdReq(c2sPayload *pb.C2SWrapper) (*pb.Registration // do not apply overrides return regResp, nil } + + // random float64 between 0 and 999 randNumFloat := float64(num) / 10.0 var ipNet *net.IPNet var dstPortOverride uint32 + + // random float64 between 0 and 1 mrand.Seed(time.Now().UnixNano()) randVal := mrand.Float64() From 0d09b51702008715b85827340a6479b1691b10f3 Mon Sep 17 00:00:00 2001 From: 0x90-n Date: Mon, 11 Nov 2024 12:36:58 -0700 Subject: [PATCH 12/14] err handling --- pkg/regserver/regprocessor/regprocessor.go | 3 +++ 1 file changed, 3 insertions(+) diff --git a/pkg/regserver/regprocessor/regprocessor.go b/pkg/regserver/regprocessor/regprocessor.go index 170224d3..15e0b5a4 100644 --- a/pkg/regserver/regprocessor/regprocessor.go +++ b/pkg/regserver/regprocessor/regprocessor.go @@ -181,6 +181,9 @@ func overridePrefix(newRegResp *pb.RegistrationResponse, prefixId prefix.PrefixI newRegResp.DstPort = proto.Uint32(dstPort) // Override Prefix choice and PrefixParam newPrefix, err := prefix.TryFromID(prefixId) + if err != nil { + return err + } var fp = newPrefix.FlushPolicy() var i int32 = int32(newPrefix.ID()) newparams := &pb.PrefixTransportParams{} From c4db5a4c921c748c54c79fe4fd17892fcce32c6b Mon Sep 17 00:00:00 2001 From: 0x90-n Date: Mon, 11 Nov 2024 13:11:06 -0700 Subject: [PATCH 13/14] adding a reg_config.toml with template for subnet overrides --- cmd/registration-server/main.go | 42 +++++++++++----------- cmd/registration-server/reg_config.toml | 29 +++++++++++++++ pkg/regserver/regprocessor/regprocessor.go | 28 +++++++-------- 3 files changed, 64 insertions(+), 35 deletions(-) diff --git a/cmd/registration-server/main.go b/cmd/registration-server/main.go index 6a0234b8..eee17120 100644 --- a/cmd/registration-server/main.go +++ b/cmd/registration-server/main.go @@ -33,25 +33,25 @@ type regServer interface { // config defines the variables and options from the toml config file type config struct { - DNSListenAddr string `toml:"dns_listen_addr"` - Domain string `toml:"domain"` - DNSPrivkeyPath string `toml:"dns_private_key_path"` - APIPort uint16 `toml:"api_port"` - ZMQAuthVerbose bool `toml:"zmq_auth_verbose"` - ZMQAuthType string `toml:"zmq_auth_type"` - ZMQPort uint16 `toml:"zmq_port"` - ZMQBindAddr string `toml:"zmq_bind_addr"` - ZMQPrivateKeyPath string `toml:"zmq_privkey_path"` - StationPublicKeys []string `toml:"station_pubkeys"` - ClientConfPath string `toml:"clientconf_path"` - latestClientConf *pb.ClientConf - LogLevel string `toml:"log_level"` - LogMetricsInterval uint16 `toml:"log_metrics_interval"` - EnforceSubnetOverrides bool `toml:"enforce_subnet_overrides"` - PrcntMinConnsToOverride float64 `toml:"prcnt_min_conns_to_override"` - PrcntPrefixConnsToOverride float64 `toml:"prcnt_prefix_conns_to_override"` - OverrideSubnets []regprocessor.Subnet `toml:"override_subnets"` - ExclusionsFromOverride []regprocessor.Subnet `toml:"excluded_subnets_from_overrides"` + DNSListenAddr string `toml:"dns_listen_addr"` + Domain string `toml:"domain"` + DNSPrivkeyPath string `toml:"dns_private_key_path"` + APIPort uint16 `toml:"api_port"` + ZMQAuthVerbose bool `toml:"zmq_auth_verbose"` + ZMQAuthType string `toml:"zmq_auth_type"` + ZMQPort uint16 `toml:"zmq_port"` + ZMQBindAddr string `toml:"zmq_bind_addr"` + ZMQPrivateKeyPath string `toml:"zmq_privkey_path"` + StationPublicKeys []string `toml:"station_pubkeys"` + ClientConfPath string `toml:"clientconf_path"` + latestClientConf *pb.ClientConf + LogLevel string `toml:"log_level"` + LogMetricsInterval uint16 `toml:"log_metrics_interval"` + EnforceSubnetOverrides bool `toml:"enforce_subnet_overrides"` + PrcntMinRegsToOverride float64 `toml:"prcnt_min_regs_to_override"` + PrcntPrefixRegsToOverride float64 `toml:"prcnt_prefix_regs_to_override"` + OverrideSubnets []regprocessor.Subnet `toml:"override_subnet"` + ExclusionsFromOverride []regprocessor.Subnet `toml:"excluded_subnet_from_overrides"` } var defaultTransports = map[pb.TransportType]lib.Transport{ @@ -197,9 +197,9 @@ func main() { switch conf.ZMQAuthType { case "CURVE": - processor, err = regprocessor.NewRegProcessor(conf.ZMQBindAddr, conf.ZMQPort, zmqPrivkey, conf.ZMQAuthVerbose, conf.StationPublicKeys, metrics, conf.EnforceSubnetOverrides, conf.OverrideSubnets, conf.ExclusionsFromOverride, conf.PrcntMinConnsToOverride, conf.PrcntPrefixConnsToOverride) + processor, err = regprocessor.NewRegProcessor(conf.ZMQBindAddr, conf.ZMQPort, zmqPrivkey, conf.ZMQAuthVerbose, conf.StationPublicKeys, metrics, conf.EnforceSubnetOverrides, conf.OverrideSubnets, conf.ExclusionsFromOverride, conf.PrcntMinRegsToOverride, conf.PrcntPrefixRegsToOverride) case "NULL": - processor, err = regprocessor.NewRegProcessorNoAuth(conf.ZMQBindAddr, conf.ZMQPort, metrics, conf.EnforceSubnetOverrides, conf.OverrideSubnets, conf.ExclusionsFromOverride, conf.PrcntMinConnsToOverride, conf.PrcntPrefixConnsToOverride) + processor, err = regprocessor.NewRegProcessorNoAuth(conf.ZMQBindAddr, conf.ZMQPort, metrics, conf.EnforceSubnetOverrides, conf.OverrideSubnets, conf.ExclusionsFromOverride, conf.PrcntMinRegsToOverride, conf.PrcntPrefixRegsToOverride) default: log.Fatalf("Unknown ZMQ auth type: %s", conf.ZMQAuthType) } diff --git a/cmd/registration-server/reg_config.toml b/cmd/registration-server/reg_config.toml index bc470647..867bb82b 100644 --- a/cmd/registration-server/reg_config.toml +++ b/cmd/registration-server/reg_config.toml @@ -45,3 +45,32 @@ bidirectional_api_generation = 957 # Path on disk to the latest ClientConfig file that the station should use clientconf_path = "/var/lib/conjure/ClientConf" + +# Whether to apply the below subnet overrides to clients bidirectional api registrations +enforce_subnet_overrides = true + +# Percentage of bidirectional api registrations to override per transport +prcnt_min_regs_to_override = 100 +prcnt_prefix_regs_to_override = 100 + +# Subnets to use when overriding clients bidirectional api registrations +[[override_subnet]] +cidr = "X.X.X.X/32" +weight = 10.7 +port = 443 +transport = "Min_Transport" + +[[override_subnet]] +cidr = "X.X.X.X/24" +weight = 10 +port = 80 +transport = "Prefix_Transport" +prefix_id = 1 + +# Subnets to refrain from overriding when clients bidirectional api registrations pick a v4 phantom inside them +[[excluded_subnet_from_overrides]] +cidr = "X.X.X.X/25" +# For future features that can exclude subnets according to weight, port, or transport +weight = 28.7 +port = 80 +transport = "Min_Transport" diff --git a/pkg/regserver/regprocessor/regprocessor.go b/pkg/regserver/regprocessor/regprocessor.go index 15e0b5a4..080d77ed 100644 --- a/pkg/regserver/regprocessor/regprocessor.go +++ b/pkg/regserver/regprocessor/regprocessor.go @@ -89,8 +89,8 @@ type RegProcessor struct { prefixOverrideSubnetsCumulativeWeights []float64 prefixOverrideSubnets []Subnet exclusionsFromOverride []Subnet - prcntMinConnsToOverride float64 - prcntPrefixConnsToOverride float64 + prcntMinRegsToOverride float64 + prcntPrefixRegsToOverride float64 } type Subnet struct { @@ -255,7 +255,7 @@ func processOverrideSubnetsWeights(subnets []Subnet) []float64 { } // NewRegProcessor initialize a new RegProcessor -func NewRegProcessor(zmqBindAddr string, zmqPort uint16, privkey []byte, authVerbose bool, stationPublicKeys []string, metrics *metrics.Metrics, enforceSubnetOverrides bool, overrideSubnets []Subnet, exclusionsFromOverride []Subnet, prcntMinConnsToOverride float64, prcntPrefixConnsToOverride float64) (*RegProcessor, error) { +func NewRegProcessor(zmqBindAddr string, zmqPort uint16, privkey []byte, authVerbose bool, stationPublicKeys []string, metrics *metrics.Metrics, enforceSubnetOverrides bool, overrideSubnets []Subnet, exclusionsFromOverride []Subnet, prcntMinRegsToOverride float64, prcntPrefixRegsToOverride float64) (*RegProcessor, error) { if len(privkey) != ed25519.PrivateKeySize { // We require the 64 byte [private_key][public_key] format to Sign using crypto/ed25519 @@ -267,7 +267,7 @@ func NewRegProcessor(zmqBindAddr string, zmqPort uint16, privkey []byte, authVer return nil, err } - regProcessor, err := newRegProcessor(zmqBindAddr, zmqPort, privkey, authVerbose, stationPublicKeys, enforceSubnetOverrides, overrideSubnets, exclusionsFromOverride, prcntMinConnsToOverride, prcntPrefixConnsToOverride) + regProcessor, err := newRegProcessor(zmqBindAddr, zmqPort, privkey, authVerbose, stationPublicKeys, enforceSubnetOverrides, overrideSubnets, exclusionsFromOverride, prcntMinRegsToOverride, prcntPrefixRegsToOverride) if err != nil { return nil, err } @@ -279,7 +279,7 @@ func NewRegProcessor(zmqBindAddr string, zmqPort uint16, privkey []byte, authVer // initializes the registration processor without the phantom selector which can be added by a // wrapping function before it is returned. This function is required for testing. -func newRegProcessor(zmqBindAddr string, zmqPort uint16, privkey []byte, authVerbose bool, stationPublicKeys []string, enforceSubnetOverrides bool, overrideSubnets []Subnet, exclusionsFromOverride []Subnet, prcntMinConnsToOverride float64, prcntPrefixConnsToOverride float64) (*RegProcessor, error) { +func newRegProcessor(zmqBindAddr string, zmqPort uint16, privkey []byte, authVerbose bool, stationPublicKeys []string, enforceSubnetOverrides bool, overrideSubnets []Subnet, exclusionsFromOverride []Subnet, prcntMinRegsToOverride float64, prcntPrefixRegsToOverride float64) (*RegProcessor, error) { sock, err := zmq.NewSocket(zmq.PUB) if err != nil { return nil, fmt.Errorf("%w: %v", ErrZmqSocket, err) @@ -315,7 +315,7 @@ func newRegProcessor(zmqBindAddr string, zmqPort uint16, privkey []byte, authVer regOverrides = interfaces.Overrides([]interfaces.RegOverride{overrides.NewRandPrefixOverride()}) } - prcntMinConnsToOverride, prcntPrefixConnsToOverride = validateOverridePercentages(prcntMinConnsToOverride, prcntPrefixConnsToOverride) + prcntMinRegsToOverride, prcntPrefixRegsToOverride = validateOverridePercentages(prcntMinRegsToOverride, prcntPrefixRegsToOverride) minOverrideSubnets, prefixOverrideSubnets := splitOverrideSubnets(overrideSubnets) @@ -336,8 +336,8 @@ func newRegProcessor(zmqBindAddr string, zmqPort uint16, privkey []byte, authVer minOverrideSubnetsCumulativeWeights: minOverrideSubnetsCumulativeWeights, prefixOverrideSubnetsCumulativeWeights: prefixOverrideSubnetsCumulativeWeights, exclusionsFromOverride: make([]Subnet, len(exclusionsFromOverride)), - prcntMinConnsToOverride: prcntMinConnsToOverride, - prcntPrefixConnsToOverride: prcntPrefixConnsToOverride, + prcntMinRegsToOverride: prcntMinRegsToOverride, + prcntPrefixRegsToOverride: prcntPrefixRegsToOverride, } copy(rp.exclusionsFromOverride, exclusionsFromOverride) @@ -345,7 +345,7 @@ func newRegProcessor(zmqBindAddr string, zmqPort uint16, privkey []byte, authVer } // NewRegProcessorNoAuth creates a regprocessor without authentication to zmq address -func NewRegProcessorNoAuth(zmqBindAddr string, zmqPort uint16, metrics *metrics.Metrics, enforceSubnetOverrides bool, overrideSubnets []Subnet, exclusionsFromOverride []Subnet, prcntMinConnsToOverride float64, prcntPrefixConnsToOverride float64) (*RegProcessor, error) { +func NewRegProcessorNoAuth(zmqBindAddr string, zmqPort uint16, metrics *metrics.Metrics, enforceSubnetOverrides bool, overrideSubnets []Subnet, exclusionsFromOverride []Subnet, prcntMinRegsToOverride float64, prcntPrefixRegsToOverride float64) (*RegProcessor, error) { sock, err := zmq.NewSocket(zmq.PUB) if err != nil { return nil, ErrZmqSocket @@ -361,7 +361,7 @@ func NewRegProcessorNoAuth(zmqBindAddr string, zmqPort uint16, metrics *metrics. return nil, err } - prcntMinConnsToOverride, prcntPrefixConnsToOverride = validateOverridePercentages(prcntMinConnsToOverride, prcntPrefixConnsToOverride) + prcntMinRegsToOverride, prcntPrefixRegsToOverride = validateOverridePercentages(prcntMinRegsToOverride, prcntPrefixRegsToOverride) minOverrideSubnets, prefixOverrideSubnets := splitOverrideSubnets(overrideSubnets) @@ -382,8 +382,8 @@ func NewRegProcessorNoAuth(zmqBindAddr string, zmqPort uint16, metrics *metrics. minOverrideSubnetsCumulativeWeights: minOverrideSubnetsCumulativeWeights, prefixOverrideSubnetsCumulativeWeights: prefixOverrideSubnetsCumulativeWeights, exclusionsFromOverride: make([]Subnet, len(exclusionsFromOverride)), - prcntMinConnsToOverride: prcntMinConnsToOverride, - prcntPrefixConnsToOverride: prcntPrefixConnsToOverride, + prcntMinRegsToOverride: prcntMinRegsToOverride, + prcntPrefixRegsToOverride: prcntPrefixRegsToOverride, } copy(rp.exclusionsFromOverride, exclusionsFromOverride) @@ -599,7 +599,7 @@ func (p *RegProcessor) processBdReq(c2sPayload *pb.C2SWrapper) (*pb.Registration // ignore prior choices and begin experimental overrides for Min and Prefix transports only if transportType == pb.TransportType_Min { - if randNumFloat < p.prcntMinConnsToOverride { + if randNumFloat < p.prcntMinRegsToOverride { if p.minOverrideSubnets == nil { // reg_conf.toml does not contain subnet overrides for Min transport return regResp, nil @@ -631,7 +631,7 @@ func (p *RegProcessor) processBdReq(c2sPayload *pb.C2SWrapper) (*pb.Registration // Override the Phantom IPv4 for clients with the Prefix transport // and override the transport type only if c2s.GetDisableRegistrarOverrides() is false if !c2s.GetDisableRegistrarOverrides() { - if randNumFloat < p.prcntPrefixConnsToOverride { + if randNumFloat < p.prcntPrefixRegsToOverride { if p.prefixOverrideSubnets == nil { // reg_conf.toml does not contain subnet overrides for Prefix transport return regResp, nil From ac11bd2e29aa08f6acf74a7a9d4fc7e513f7d0e6 Mon Sep 17 00:00:00 2001 From: 0x90-n Date: Mon, 11 Nov 2024 17:43:57 -0700 Subject: [PATCH 14/14] update tests --- pkg/regserver/regprocessor/auth_test.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pkg/regserver/regprocessor/auth_test.go b/pkg/regserver/regprocessor/auth_test.go index 49ccf7c3..49e605da 100644 --- a/pkg/regserver/regprocessor/auth_test.go +++ b/pkg/regserver/regprocessor/auth_test.go @@ -134,7 +134,7 @@ func TestZMQAuth(t *testing.T) { // messages that we expect the station to hear. in production this will be new registrations, // here we don't care about the message contents. go func() { - regProcessor, err := newRegProcessor(zmqBindAddr, zmqPort, []byte(zmq.Z85decode(serverPrivkeyZ85)), true, stationPublicKeys) + regProcessor, err := newRegProcessor(zmqBindAddr, zmqPort, []byte(zmq.Z85decode(serverPrivkeyZ85)), true, stationPublicKeys, false, nil, nil, 0.0, 0.0) require.Nil(t, err) defer regProcessor.Close() errStation := regProcessor.AddTransport(pb.TransportType_Min, min.Transport{})