From 2451737f8768ce93a05b8c6a1e62560c27204130 Mon Sep 17 00:00:00 2001 From: Shivaram Lingamneni Date: Sun, 12 May 2019 04:01:47 -0400 Subject: [PATCH] give cloaks their own package --- Makefile | 1 + irc/{ => cloaks}/cloak_test.go | 15 ++++++-- irc/cloaks/cloaks.go | 70 ++++++++++++++++++++++++++++++++++ irc/config.go | 37 ++---------------- irc/server.go | 28 -------------- 5 files changed, 85 insertions(+), 66 deletions(-) rename irc/{ => cloaks}/cloak_test.go (91%) create mode 100644 irc/cloaks/cloaks.go diff --git a/Makefile b/Makefile index 8b35ab9d..a355b42c 100644 --- a/Makefile +++ b/Makefile @@ -20,6 +20,7 @@ test: python3 ./gencapdefs.py | diff - ${capdef_file} cd irc && go test . && go vet . cd irc/caps && go test . && go vet . + cd irc/cloaks && go test . && go vet . cd irc/connection_limits && go test . && go vet . cd irc/history && go test . && go vet . cd irc/isupport && go test . && go vet . diff --git a/irc/cloak_test.go b/irc/cloaks/cloak_test.go similarity index 91% rename from irc/cloak_test.go rename to irc/cloaks/cloak_test.go index 49271fdd..f6cf1965 100644 --- a/irc/cloak_test.go +++ b/irc/cloaks/cloak_test.go @@ -1,13 +1,20 @@ // Copyright (c) 2019 Shivaram Lingamneni // released under the MIT license -package irc +package cloaks import ( "net" + "reflect" "testing" ) +func assertEqual(supplied, expected interface{}, t *testing.T) { + if !reflect.DeepEqual(supplied, expected) { + t.Errorf("expected %v but got %v", expected, supplied) + } +} + func easyParseIP(ipstr string) (result net.IP) { result = net.ParseIP(ipstr) if result == nil { @@ -25,7 +32,7 @@ func cloakConfForTesting() CloakConfig { CidrLenIPv6: 64, NumBits: 80, } - config.postprocess() + config.Initialize() return config } @@ -64,7 +71,7 @@ func TestCloakShortv4Cidr(t *testing.T) { CidrLenIPv6: 64, NumBits: 60, } - config.postprocess() + config.Initialize() v4ip := easyParseIP("8.8.8.8") assertEqual(config.ComputeCloak(v4ip), "3cay3zc72tnui.oragono", t) @@ -76,7 +83,7 @@ func TestCloakZeroBits(t *testing.T) { config := cloakConfForTesting() config.NumBits = 0 config.Netname = "example.com" - config.postprocess() + config.Initialize() v4ip := easyParseIP("8.8.8.8").To4() assertEqual(config.ComputeCloak(v4ip), "example.com", t) diff --git a/irc/cloaks/cloaks.go b/irc/cloaks/cloaks.go new file mode 100644 index 00000000..4557a85a --- /dev/null +++ b/irc/cloaks/cloaks.go @@ -0,0 +1,70 @@ +// Copyright (c) 2019 Shivaram Lingamneni + +package cloaks + +import ( + "fmt" + "net" + + "golang.org/x/crypto/sha3" + + "github.com/oragono/oragono/irc/utils" +) + +type CloakConfig struct { + Enabled bool + Netname string + Secret string + CidrLenIPv4 int `yaml:"cidr-len-ipv4"` + CidrLenIPv6 int `yaml:"cidr-len-ipv6"` + NumBits int `yaml:"num-bits"` + + numBytes int + ipv4Mask net.IPMask + ipv6Mask net.IPMask +} + +func (cloakConfig *CloakConfig) Initialize() { + // sanity checks: + numBits := cloakConfig.NumBits + if 0 == numBits { + numBits = 80 + } else if 256 < numBits { + numBits = 256 + } + + // derived values: + cloakConfig.numBytes = numBits / 8 + // round up to the nearest byte + if numBits%8 != 0 { + cloakConfig.numBytes += 1 + } + cloakConfig.ipv4Mask = net.CIDRMask(cloakConfig.CidrLenIPv4, 32) + cloakConfig.ipv6Mask = net.CIDRMask(cloakConfig.CidrLenIPv6, 128) +} + +// simple cloaking algorithm: normalize the IP to its CIDR, +// then hash the resulting bytes with a secret key, +// then truncate to the desired length, b32encode, and append the fake TLD. +func (config *CloakConfig) ComputeCloak(ip net.IP) string { + if !config.Enabled { + return "" + } else if config.NumBits == 0 { + return config.Netname + } + var masked net.IP + v4ip := ip.To4() + if v4ip != nil { + masked = v4ip.Mask(config.ipv4Mask) + } else { + masked = ip.Mask(config.ipv6Mask) + } + // SHA3(K || M): + // https://crypto.stackexchange.com/questions/17735/is-hmac-needed-for-a-sha-3-based-mac + input := make([]byte, len(config.Secret)+len(masked)) + copy(input, config.Secret[:]) + copy(input[len(config.Secret):], masked) + digest := sha3.Sum512(input) + b32digest := utils.B32Encoder.EncodeToString(digest[:config.numBytes]) + return fmt.Sprintf("%s.%s", b32digest, config.Netname) +} diff --git a/irc/config.go b/irc/config.go index 639dc7a4..11121495 100644 --- a/irc/config.go +++ b/irc/config.go @@ -18,6 +18,7 @@ import ( "time" "code.cloudfoundry.org/bytefmt" + "github.com/oragono/oragono/irc/cloaks" "github.com/oragono/oragono/irc/connection_limits" "github.com/oragono/oragono/irc/custime" "github.com/oragono/oragono/irc/isupport" @@ -263,38 +264,6 @@ type TorListenersConfig struct { MaxConnectionsPerDuration int `yaml:"max-connections-per-duration"` } -type CloakConfig struct { - Enabled bool - Netname string - Secret string - CidrLenIPv4 int `yaml:"cidr-len-ipv4"` - CidrLenIPv6 int `yaml:"cidr-len-ipv6"` - NumBits int `yaml:"num-bits"` - - numBytes int - ipv4Mask net.IPMask - ipv6Mask net.IPMask -} - -func (cloakConfig *CloakConfig) postprocess() { - // sanity checks: - numBits := cloakConfig.NumBits - if 0 == numBits { - numBits = 80 - } else if 256 < numBits { - numBits = 256 - } - - // derived values: - cloakConfig.numBytes = numBits / 8 - // round up to the nearest byte - if numBits%8 != 0 { - cloakConfig.numBytes += 1 - } - cloakConfig.ipv4Mask = net.CIDRMask(cloakConfig.CidrLenIPv4, 32) - cloakConfig.ipv6Mask = net.CIDRMask(cloakConfig.CidrLenIPv6, 128) -} - // Config defines the overall configuration. type Config struct { Network struct { @@ -329,7 +298,7 @@ type Config struct { isupport isupport.List ConnectionLimiter connection_limits.LimiterConfig `yaml:"connection-limits"` ConnectionThrottler connection_limits.ThrottlerConfig `yaml:"connection-throttling"` - Cloaks CloakConfig `yaml:"ip-cloaking"` + Cloaks cloaks.CloakConfig `yaml:"ip-cloaking"` } Languages struct { @@ -761,7 +730,7 @@ func LoadConfig(filename string) (config *Config, err error) { config.History.ClientLength = 0 } - config.Server.Cloaks.postprocess() + config.Server.Cloaks.Initialize() for _, listenAddress := range config.Server.TorListeners.Listeners { found := false diff --git a/irc/server.go b/irc/server.go index ced8cb7c..87ced2b0 100644 --- a/irc/server.go +++ b/irc/server.go @@ -21,8 +21,6 @@ import ( "time" "unsafe" - "golang.org/x/crypto/sha3" - "github.com/goshuirc/irc-go/ircfmt" "github.com/oragono/oragono/irc/caps" "github.com/oragono/oragono/irc/connection_limits" @@ -285,32 +283,6 @@ func (server *Server) checkTorLimits() (banned bool, message string) { } } -// simple cloaking algorithm: normalize the IP to its CIDR, -// then hash the resulting bytes with a secret key, -// then truncate to the desired length, b32encode, and append the fake TLD. -func (config *CloakConfig) ComputeCloak(ip net.IP) string { - if !config.Enabled { - return "" - } else if config.NumBits == 0 { - return config.Netname - } - var masked net.IP - v4ip := ip.To4() - if v4ip != nil { - masked = v4ip.Mask(config.ipv4Mask) - } else { - masked = ip.Mask(config.ipv6Mask) - } - // SHA3(K || M): - // https://crypto.stackexchange.com/questions/17735/is-hmac-needed-for-a-sha-3-based-mac - input := make([]byte, len(config.Secret)+len(masked)) - copy(input, config.Secret[:]) - copy(input[len(config.Secret):], masked) - digest := sha3.Sum512(input) - b32digest := utils.B32Encoder.EncodeToString(digest[:config.numBytes]) - return fmt.Sprintf("%s.%s", b32digest, config.Netname) -} - // // IRC protocol listeners //