give cloaks their own package

This commit is contained in:
Shivaram Lingamneni 2019-05-12 04:01:47 -04:00
parent c28e6d13f9
commit 2451737f87
5 changed files with 85 additions and 66 deletions

View File

@ -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 .

View File

@ -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)

70
irc/cloaks/cloaks.go Normal file
View File

@ -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)
}

View File

@ -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

View File

@ -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
//