From bb56ad81cdad8d91fbb2b6cad61f3ebc48911ac2 Mon Sep 17 00:00:00 2001 From: Daniel Oaks Date: Fri, 23 Jun 2017 07:21:45 +1000 Subject: [PATCH 1/3] cloak: Start cloaking, add IPv4 IP cloaking --- irc/cloaking/cloak.go | 117 ++++++++++++++++++++++++++++++++++++++++++ irc/config.go | 11 +++- oragono.go | 23 +++++++++ 3 files changed, 150 insertions(+), 1 deletion(-) create mode 100644 irc/cloaking/cloak.go diff --git a/irc/cloaking/cloak.go b/irc/cloaking/cloak.go new file mode 100644 index 00000000..0bded17e --- /dev/null +++ b/irc/cloaking/cloak.go @@ -0,0 +1,117 @@ +// Copyright (c) 2017 Daniel Oaks +// released under the MIT license + +// Package cloak implements IP address cloaking for IRC. +package cloak + +import ( + "errors" + "fmt" + "net" + "strings" + + "crypto/sha512" + "encoding/base64" +) + +const ( + // MinKeyLength determines how many characters our cloak keys should be, minimum. + // This MUST NOT be higher in future releases, or else it will break existing, + // working cloaking for everyone using key lengths this long. + MinKeyLength = 50 +) + +var ( + errNotIPv4 = errors.New("The given address is not an IPv4 address") + errConfigDisabled = errors.New("Config has disabled IP cloaking") + errKeysTooShort = fmt.Errorf("Cloaking keys too short (min: %d)", MinKeyLength) + errKeysNotRandomEnough = errors.New("Cloaking keys aren't random enough") +) + +// Config controls whether we cloak, and if we do what values are used to do so. +type Config struct { + // Enabled controls whether cloaking is performed. + Enabled bool + // IPv4KeyA is used to cloak the `a` part of the IP address. + IPv4KeyA string `yaml:"ipv4-key-a"` + // IPv4KeyB is used to cloak the `b` part of the IP address. + IPv4KeyB string `yaml:"ipv4-key-b"` + // IPv4KeyC is used to cloak the `c` part of the IP address. + IPv4KeyC string `yaml:"ipv4-key-c"` + // IPv4KeyD is used to cloak the `d` part of the IP address. + IPv4KeyD string `yaml:"ipv4-key-d"` +} + +// IsRandomEnough makes sure people are using keys that are random enough. +func IsRandomEnough(key string) bool { + return true +} + +// toByteSlice is used for converting sha512 output from [64]byte to []byte. +func toByteSlice(orig [64]byte) []byte { + var new []byte + for _, val := range orig { + new = append(new, val) + } + return new +} + +// IPv4 returns a cloaked IPv4 address +// +// IPv4 addresses can be represented as a.b.c.d, where `a` is the least unique +// part of the address and `d` is the most unique part. +// +// `a` is unique for a given a.*.*.*, and `d` is unique for a given, specific +// a.b.c.d address. That is, if you have 1.2.3.4 and 2.3.4.4, the `d` part of +// both addresses should differ to prevent discoverability. In the same way, +// if you have 4.5.6.7 and 4.3.2.1 then the `a` part of those addresses will +// be the same value. This ensures chanops can properly ban dodgy people as +// they need to do so. +func IPv4(address net.IP, config Config, netName string) (string, error) { + if !config.Enabled { + return "", errConfigDisabled + } + + // make sure the IP address is an IPv4 address. + // from this point on we can assume `address` is a 4-byte slice + if address.To4() == nil { + return "", errNotIPv4 + } + + // check randomness of cloak keys + if len(config.IPv4KeyA) < MinKeyLength || len(config.IPv4KeyB) < MinKeyLength || len(config.IPv4KeyC) < MinKeyLength || len(config.IPv4KeyD) < MinKeyLength { + return "", errKeysTooShort + } + if !IsRandomEnough(config.IPv4KeyA) || !IsRandomEnough(config.IPv4KeyB) || !IsRandomEnough(config.IPv4KeyC) || !IsRandomEnough(config.IPv4KeyD) { + return "", errKeysNotRandomEnough + } + + // get IP parts + address = address.To4() + partA := address[0] + partB := address[1] + partC := address[2] + partD := address[3] + + // cloak `a` part of IP address. + fullKey := fmt.Sprintf("%d%s", partA, config.IPv4KeyA) + cryptoHashedKey := toByteSlice(sha512.Sum512([]byte(fullKey))) + partAHashed := strings.Trim(strings.Replace(base64.URLEncoding.EncodeToString(cryptoHashedKey), "_", "-", -1)[:16], "-") + + // cloak `b` part of IP address. + fullKey = fmt.Sprintf("%d%d%s", partB, partA, config.IPv4KeyB) + cryptoHashedKey = toByteSlice(sha512.Sum512([]byte(fullKey))) + partBHashed := strings.Trim(strings.Replace(base64.URLEncoding.EncodeToString(cryptoHashedKey), "_", "-", -1)[:16], "-") + + // cloak `c` part of IP address. + fullKey = fmt.Sprintf("%d%d%d%s", partC, partB, partA, config.IPv4KeyC) + cryptoHashedKey = toByteSlice(sha512.Sum512([]byte(fullKey))) + partCHashed := strings.Trim(strings.Replace(base64.URLEncoding.EncodeToString(cryptoHashedKey), "_", "-", -1)[:16], "-") + + // cloak `d` part of IP address. + fullKey = fmt.Sprintf("%d%d%d%d%s", partD, partC, partB, partA, config.IPv4KeyD) + cryptoHashedKey = toByteSlice(sha512.Sum512([]byte(fullKey))) + partDHashed := strings.Trim(strings.Replace(base64.URLEncoding.EncodeToString(cryptoHashedKey), "_", "-", -1)[:16], "-") + + return fmt.Sprintf("%s.%s.%s.%s.cloaked-%s", partAHashed, partBHashed, partCHashed, partDHashed, netName), nil +} diff --git a/irc/config.go b/irc/config.go index ac840f7e..fe7b91fb 100644 --- a/irc/config.go +++ b/irc/config.go @@ -11,9 +11,11 @@ import ( "fmt" "io/ioutil" "log" + "net" "strings" "time" + cloak "github.com/oragono/oragono/irc/cloaking" "github.com/oragono/oragono/irc/custime" "github.com/oragono/oragono/irc/logger" @@ -187,7 +189,8 @@ type StackImpactConfig struct { // Config defines the overall configuration. type Config struct { Network struct { - Name string + Name string + IPCloaking cloak.Config `yaml:"ip-cloaking"` } Server struct { @@ -418,6 +421,12 @@ func LoadConfig(filename string) (config *Config, err error) { return nil, fmt.Errorf("STS port is incorrect, should be 0 if disabled: %d", config.Server.STS.Port) } } + if config.Network.IPCloaking.Enabled { + _, err := cloak.IPv4(net.ParseIP("8.8.8.8"), config.Network.IPCloaking, "Config") + if err != nil { + return nil, fmt.Errorf("IPv4 cloaking config is incorrect: %s", err.Error()) + } + } if config.Server.ConnectionThrottle.Enabled { config.Server.ConnectionThrottle.Duration, err = time.ParseDuration(config.Server.ConnectionThrottle.DurationString) if err != nil { diff --git a/oragono.go b/oragono.go index 40ceb7c7..9ba919ac 100644 --- a/oragono.go +++ b/oragono.go @@ -13,8 +13,11 @@ import ( "syscall" "time" + "net" + "github.com/docopt/docopt-go" "github.com/oragono/oragono/irc" + cloak "github.com/oragono/oragono/irc/cloaking" "github.com/oragono/oragono/irc/logger" "github.com/oragono/oragono/mkcerts" stackimpact "github.com/stackimpact/stackimpact-go" @@ -38,6 +41,26 @@ Options: -h --help Show this screen. --version Show version.` + conf := cloak.Config{ + Enabled: true, + IPv4KeyA: "n6by5q4wn5ebw534g4e6rtnr6y5t^Nbnrt35NHrghn3rhrhrnr", + IPv4KeyB: "n6by5q4wn5ebw534g4e6rtnr6y5t^Nbnrt35NHrghn3rhrhrnr", + IPv4KeyC: "n6by5q4wn5ebw534g4e6rtnr6y5t^Nbnrt35NHrghn3rhrhrnr", + IPv4KeyD: "n6by5q4wn5ebw534g4e6rtnr6y5t^Nbnrt35NHrghn3rhrhrnr", + } + ip := net.ParseIP("8.8.8.8") + key, err := cloak.IPv4(ip, conf, "Tst") + fmt.Println(ip, key, err) + ip = net.ParseIP("9.4.8.8") + key, err = cloak.IPv4(ip, conf, "Tst") + fmt.Println(ip, key, err) + ip = net.ParseIP("8.4.2.8") + key, err = cloak.IPv4(ip, conf, "Tst") + fmt.Println(ip, key, err) + ip = net.ParseIP("8.4.2.1") + key, err = cloak.IPv4(ip, conf, "Tst") + fmt.Println(ip, key, err) + arguments, _ := docopt.Parse(usage, nil, true, version, false) configfile := arguments["--conf"].(string) From ceb4860312f409ffe10728d3b237adf063657d73 Mon Sep 17 00:00:00 2001 From: Daniel Oaks Date: Sat, 24 Jun 2017 05:26:48 +1000 Subject: [PATCH 2/3] cloaking: Use hmac+base32 to cloak instead --- irc/cloaking/cloak.go | 71 +++++++++++++++++++++++++++---------------- irc/config.go | 2 +- oragono.go | 24 ++++++++++----- 3 files changed, 61 insertions(+), 36 deletions(-) diff --git a/irc/cloaking/cloak.go b/irc/cloaking/cloak.go index 0bded17e..9247884f 100644 --- a/irc/cloaking/cloak.go +++ b/irc/cloaking/cloak.go @@ -5,23 +5,27 @@ package cloak import ( + "crypto/hmac" + "crypto/sha256" "errors" "fmt" "net" "strings" - "crypto/sha512" - "encoding/base64" + "encoding/base32" ) const ( - // MinKeyLength determines how many characters our cloak keys should be, minimum. + // MinKeyLength determines how many bytes our cloak keys should be, minimum. // This MUST NOT be higher in future releases, or else it will break existing, // working cloaking for everyone using key lengths this long. - MinKeyLength = 50 + MinKeyLength = 32 + // partLength is how long each octet is after being base32'd. + partLength = 10 ) var ( + errNetName = errors.New("NetName is not the right size (must be 1-10 characters long)") errNotIPv4 = errors.New("The given address is not an IPv4 address") errConfigDisabled = errors.New("Config has disabled IP cloaking") errKeysTooShort = fmt.Errorf("Cloaking keys too short (min: %d)", MinKeyLength) @@ -32,18 +36,24 @@ var ( type Config struct { // Enabled controls whether cloaking is performed. Enabled bool - // IPv4KeyA is used to cloak the `a` part of the IP address. - IPv4KeyA string `yaml:"ipv4-key-a"` - // IPv4KeyB is used to cloak the `b` part of the IP address. - IPv4KeyB string `yaml:"ipv4-key-b"` - // IPv4KeyC is used to cloak the `c` part of the IP address. - IPv4KeyC string `yaml:"ipv4-key-c"` - // IPv4KeyD is used to cloak the `d` part of the IP address. - IPv4KeyD string `yaml:"ipv4-key-d"` + // NetName is the name used for the network in cloaked addresses. + NetName string + // IPv4KeyAString is used to cloak the `a` part of the IP address. + IPv4KeyAString string `yaml:"ipv4-key-a"` + IPv4KeyA []byte + // IPv4KeyBString is used to cloak the `b` part of the IP address. + IPv4KeyBString string `yaml:"ipv4-key-b"` + IPv4KeyB []byte + // IPv4KeyCString is used to cloak the `c` part of the IP address. + IPv4KeyCString string `yaml:"ipv4-key-c"` + IPv4KeyC []byte + // IPv4KeyDString is used to cloak the `d` part of the IP address. + IPv4KeyDString string `yaml:"ipv4-key-d"` + IPv4KeyD []byte } // IsRandomEnough makes sure people are using keys that are random enough. -func IsRandomEnough(key string) bool { +func IsRandomEnough(key []byte) bool { return true } @@ -56,6 +66,14 @@ func toByteSlice(orig [64]byte) []byte { return new } +// hashOctet does the heavy lifting in terms of hashing and returned an appropriate hashed octet +func hashOctet(key []byte, data string) string { + sig := hmac.New(sha256.New, key) + sig.Write([]byte(data)) + raw := sig.Sum(nil) + return strings.ToLower(base32.StdEncoding.EncodeToString(raw)) +} + // IPv4 returns a cloaked IPv4 address // // IPv4 addresses can be represented as a.b.c.d, where `a` is the least unique @@ -67,10 +85,13 @@ func toByteSlice(orig [64]byte) []byte { // if you have 4.5.6.7 and 4.3.2.1 then the `a` part of those addresses will // be the same value. This ensures chanops can properly ban dodgy people as // they need to do so. -func IPv4(address net.IP, config Config, netName string) (string, error) { +func IPv4(address net.IP, config Config) (string, error) { if !config.Enabled { return "", errConfigDisabled } + if len(config.NetName) < 1 || 10 < len(config.NetName) { + return "", errNetName + } // make sure the IP address is an IPv4 address. // from this point on we can assume `address` is a 4-byte slice @@ -94,24 +115,20 @@ func IPv4(address net.IP, config Config, netName string) (string, error) { partD := address[3] // cloak `a` part of IP address. - fullKey := fmt.Sprintf("%d%s", partA, config.IPv4KeyA) - cryptoHashedKey := toByteSlice(sha512.Sum512([]byte(fullKey))) - partAHashed := strings.Trim(strings.Replace(base64.URLEncoding.EncodeToString(cryptoHashedKey), "_", "-", -1)[:16], "-") + data := fmt.Sprintf("%d", partA) + partAHashed := hashOctet(config.IPv4KeyA, data)[:partLength] // cloak `b` part of IP address. - fullKey = fmt.Sprintf("%d%d%s", partB, partA, config.IPv4KeyB) - cryptoHashedKey = toByteSlice(sha512.Sum512([]byte(fullKey))) - partBHashed := strings.Trim(strings.Replace(base64.URLEncoding.EncodeToString(cryptoHashedKey), "_", "-", -1)[:16], "-") + data = fmt.Sprintf("%d%d", partB, partA) + partBHashed := hashOctet(config.IPv4KeyB, data)[:partLength] // cloak `c` part of IP address. - fullKey = fmt.Sprintf("%d%d%d%s", partC, partB, partA, config.IPv4KeyC) - cryptoHashedKey = toByteSlice(sha512.Sum512([]byte(fullKey))) - partCHashed := strings.Trim(strings.Replace(base64.URLEncoding.EncodeToString(cryptoHashedKey), "_", "-", -1)[:16], "-") + data = fmt.Sprintf("%d%d%d", partC, partB, partA) + partCHashed := hashOctet(config.IPv4KeyC, data)[:partLength] // cloak `d` part of IP address. - fullKey = fmt.Sprintf("%d%d%d%d%s", partD, partC, partB, partA, config.IPv4KeyD) - cryptoHashedKey = toByteSlice(sha512.Sum512([]byte(fullKey))) - partDHashed := strings.Trim(strings.Replace(base64.URLEncoding.EncodeToString(cryptoHashedKey), "_", "-", -1)[:16], "-") + data = fmt.Sprintf("%d%d%d%d", partD, partC, partB, partA) + partDHashed := hashOctet(config.IPv4KeyD, data)[:partLength] - return fmt.Sprintf("%s.%s.%s.%s.cloaked-%s", partAHashed, partBHashed, partCHashed, partDHashed, netName), nil + return fmt.Sprintf("%s.%s.%s.%s.%s-cloaked", partAHashed, partBHashed, partCHashed, partDHashed, strings.ToLower(config.NetName)), nil } diff --git a/irc/config.go b/irc/config.go index fe7b91fb..89a85fca 100644 --- a/irc/config.go +++ b/irc/config.go @@ -422,7 +422,7 @@ func LoadConfig(filename string) (config *Config, err error) { } } if config.Network.IPCloaking.Enabled { - _, err := cloak.IPv4(net.ParseIP("8.8.8.8"), config.Network.IPCloaking, "Config") + _, err := cloak.IPv4(net.ParseIP("8.8.8.8"), config.Network.IPCloaking) if err != nil { return nil, fmt.Errorf("IPv4 cloaking config is incorrect: %s", err.Error()) } diff --git a/oragono.go b/oragono.go index 9ba919ac..172decaf 100644 --- a/oragono.go +++ b/oragono.go @@ -15,6 +15,8 @@ import ( "net" + "encoding/base64" + "github.com/docopt/docopt-go" "github.com/oragono/oragono/irc" cloak "github.com/oragono/oragono/irc/cloaking" @@ -41,24 +43,30 @@ Options: -h --help Show this screen. --version Show version.` + keyA, _ := base64.StdEncoding.DecodeString("idXACDbEhqRZsExn0jOTi4rtC6MrKBOcN4edxdSzTAA=") + keyB, _ := base64.StdEncoding.DecodeString("qODtg8WEJ0YA6JRnryDDUEoSdJyrGgPFI6hPNnGHyIw=") + keyC, _ := base64.StdEncoding.DecodeString("Oxqc6uDsyEO5vZcxHmtZ1zOLL8wwATeYA4KqJmkTJQo=") + keyD, _ := base64.StdEncoding.DecodeString("vd2eimWWh3L9fukFwxZThJ9pKTf/I5UZ/k7o/3JHkMc=") + conf := cloak.Config{ Enabled: true, - IPv4KeyA: "n6by5q4wn5ebw534g4e6rtnr6y5t^Nbnrt35NHrghn3rhrhrnr", - IPv4KeyB: "n6by5q4wn5ebw534g4e6rtnr6y5t^Nbnrt35NHrghn3rhrhrnr", - IPv4KeyC: "n6by5q4wn5ebw534g4e6rtnr6y5t^Nbnrt35NHrghn3rhrhrnr", - IPv4KeyD: "n6by5q4wn5ebw534g4e6rtnr6y5t^Nbnrt35NHrghn3rhrhrnr", + NetName: "Test", + IPv4KeyA: keyA, + IPv4KeyB: keyB, + IPv4KeyC: keyC, + IPv4KeyD: keyD, } ip := net.ParseIP("8.8.8.8") - key, err := cloak.IPv4(ip, conf, "Tst") + key, err := cloak.IPv4(ip, conf) fmt.Println(ip, key, err) ip = net.ParseIP("9.4.8.8") - key, err = cloak.IPv4(ip, conf, "Tst") + key, err = cloak.IPv4(ip, conf) fmt.Println(ip, key, err) ip = net.ParseIP("8.4.2.8") - key, err = cloak.IPv4(ip, conf, "Tst") + key, err = cloak.IPv4(ip, conf) fmt.Println(ip, key, err) ip = net.ParseIP("8.4.2.1") - key, err = cloak.IPv4(ip, conf, "Tst") + key, err = cloak.IPv4(ip, conf) fmt.Println(ip, key, err) arguments, _ := docopt.Parse(usage, nil, true, version, false) From 21a061c1377f5292eb3d297e38e6651abe9a35b8 Mon Sep 17 00:00:00 2001 From: Daniel Oaks Date: Wed, 6 Sep 2017 15:51:55 +1000 Subject: [PATCH 3/3] cloaking: Generate and check for cloak keys appropriately --- irc/cloaking/cloak.go | 63 ++++++++++++++--- irc/config.go | 9 +-- oragono.go | 152 ++++++++++++++++++++++++++---------------- oragono.yaml | 20 ++++++ 4 files changed, 170 insertions(+), 74 deletions(-) diff --git a/irc/cloaking/cloak.go b/irc/cloaking/cloak.go index 9247884f..9de8e967 100644 --- a/irc/cloaking/cloak.go +++ b/irc/cloaking/cloak.go @@ -6,7 +6,9 @@ package cloak import ( "crypto/hmac" + "crypto/rand" "crypto/sha256" + "encoding/base64" "errors" "fmt" "net" @@ -28,7 +30,7 @@ var ( errNetName = errors.New("NetName is not the right size (must be 1-10 characters long)") errNotIPv4 = errors.New("The given address is not an IPv4 address") errConfigDisabled = errors.New("Config has disabled IP cloaking") - errKeysTooShort = fmt.Errorf("Cloaking keys too short (min: %d)", MinKeyLength) + errKeysTooShort = errors.New("Cloaking keys too short") errKeysNotRandomEnough = errors.New("Cloaking keys aren't random enough") ) @@ -38,22 +40,63 @@ type Config struct { Enabled bool // NetName is the name used for the network in cloaked addresses. NetName string - // IPv4KeyAString is used to cloak the `a` part of the IP address. - IPv4KeyAString string `yaml:"ipv4-key-a"` + // IPv4KeyString is used to cloak the `a`, `b`, `c` and `d` parts of the IP address. + // it is split up into the separate A/B/C/D keys below. + IPv4KeysString []string `yaml:"ipv4-keys"` IPv4KeyA []byte - // IPv4KeyBString is used to cloak the `b` part of the IP address. - IPv4KeyBString string `yaml:"ipv4-key-b"` IPv4KeyB []byte - // IPv4KeyCString is used to cloak the `c` part of the IP address. - IPv4KeyCString string `yaml:"ipv4-key-c"` IPv4KeyC []byte - // IPv4KeyDString is used to cloak the `d` part of the IP address. - IPv4KeyDString string `yaml:"ipv4-key-d"` IPv4KeyD []byte } +// CheckConfig checks whether we're configured correctly. +func (config *Config) CheckConfig() error { + if config.Enabled { + // IPv4 cloak keys + if len(config.IPv4KeysString) < 4 { + return errKeysTooShort + } + + keyA, errA := base64.StdEncoding.DecodeString(config.IPv4KeysString[0]) + keyB, errB := base64.StdEncoding.DecodeString(config.IPv4KeysString[1]) + keyC, errC := base64.StdEncoding.DecodeString(config.IPv4KeysString[2]) + keyD, errD := base64.StdEncoding.DecodeString(config.IPv4KeysString[3]) + + if errA != nil || errB != nil || errC != nil || errD != nil { + return fmt.Errorf("Could not decode IPv4 cloak keys") + } + if len(keyA) < MinKeyLength || len(keyB) < MinKeyLength || len(keyC) < MinKeyLength || len(keyD) < MinKeyLength { + return errKeysTooShort + } + + config.IPv4KeyA = keyA + config.IPv4KeyB = keyB + config.IPv4KeyC = keyC + config.IPv4KeyD = keyD + + // try cloaking IPs to confirm everything works properly + _, err := IPv4(net.ParseIP("8.8.8.8"), config) + if err != nil { + return err + } + } + return nil +} + +// GenerateCloakKey generates one cloak key. +func GenerateCloakKey() (string, error) { + keyBytes := make([]byte, MinKeyLength) + _, err := rand.Read(keyBytes) + if err != nil { + return "", fmt.Errorf("Could not generate random bytes for cloak key: %s", err.Error()) + } + + return base64.StdEncoding.EncodeToString(keyBytes), nil +} + // IsRandomEnough makes sure people are using keys that are random enough. func IsRandomEnough(key []byte) bool { + //TODO(dan): actually find out how to calc this return true } @@ -85,7 +128,7 @@ func hashOctet(key []byte, data string) string { // if you have 4.5.6.7 and 4.3.2.1 then the `a` part of those addresses will // be the same value. This ensures chanops can properly ban dodgy people as // they need to do so. -func IPv4(address net.IP, config Config) (string, error) { +func IPv4(address net.IP, config *Config) (string, error) { if !config.Enabled { return "", errConfigDisabled } diff --git a/irc/config.go b/irc/config.go index 89a85fca..8f297606 100644 --- a/irc/config.go +++ b/irc/config.go @@ -11,7 +11,6 @@ import ( "fmt" "io/ioutil" "log" - "net" "strings" "time" @@ -421,11 +420,9 @@ func LoadConfig(filename string) (config *Config, err error) { return nil, fmt.Errorf("STS port is incorrect, should be 0 if disabled: %d", config.Server.STS.Port) } } - if config.Network.IPCloaking.Enabled { - _, err := cloak.IPv4(net.ParseIP("8.8.8.8"), config.Network.IPCloaking) - if err != nil { - return nil, fmt.Errorf("IPv4 cloaking config is incorrect: %s", err.Error()) - } + err = config.Network.IPCloaking.CheckConfig() + if err != nil { + return nil, fmt.Errorf("Could not parse IP cloaking: %s", err.Error()) } if config.Server.ConnectionThrottle.Enabled { config.Server.ConnectionThrottle.Duration, err = time.ParseDuration(config.Server.ConnectionThrottle.DurationString) diff --git a/oragono.go b/oragono.go index 172decaf..4c0839af 100644 --- a/oragono.go +++ b/oragono.go @@ -13,10 +13,6 @@ import ( "syscall" "time" - "net" - - "encoding/base64" - "github.com/docopt/docopt-go" "github.com/oragono/oragono/irc" cloak "github.com/oragono/oragono/irc/cloaking" @@ -33,6 +29,7 @@ Usage: oragono initdb [--conf ] [--quiet] oragono upgradedb [--conf ] [--quiet] oragono genpasswd [--conf ] [--quiet] + oragono genkeys oragono mkcerts [--conf ] [--quiet] oragono run [--conf ] [--quiet] oragono -h | --help @@ -43,57 +40,37 @@ Options: -h --help Show this screen. --version Show version.` - keyA, _ := base64.StdEncoding.DecodeString("idXACDbEhqRZsExn0jOTi4rtC6MrKBOcN4edxdSzTAA=") - keyB, _ := base64.StdEncoding.DecodeString("qODtg8WEJ0YA6JRnryDDUEoSdJyrGgPFI6hPNnGHyIw=") - keyC, _ := base64.StdEncoding.DecodeString("Oxqc6uDsyEO5vZcxHmtZ1zOLL8wwATeYA4KqJmkTJQo=") - keyD, _ := base64.StdEncoding.DecodeString("vd2eimWWh3L9fukFwxZThJ9pKTf/I5UZ/k7o/3JHkMc=") - - conf := cloak.Config{ - Enabled: true, - NetName: "Test", - IPv4KeyA: keyA, - IPv4KeyB: keyB, - IPv4KeyC: keyC, - IPv4KeyD: keyD, - } - ip := net.ParseIP("8.8.8.8") - key, err := cloak.IPv4(ip, conf) - fmt.Println(ip, key, err) - ip = net.ParseIP("9.4.8.8") - key, err = cloak.IPv4(ip, conf) - fmt.Println(ip, key, err) - ip = net.ParseIP("8.4.2.8") - key, err = cloak.IPv4(ip, conf) - fmt.Println(ip, key, err) - ip = net.ParseIP("8.4.2.1") - key, err = cloak.IPv4(ip, conf) - fmt.Println(ip, key, err) - arguments, _ := docopt.Parse(usage, nil, true, version, false) + // load config and logger for everything but genkeys + var err error configfile := arguments["--conf"].(string) - config, err := irc.LoadConfig(configfile) - if err != nil { - log.Fatal("Config file did not load successfully:", err.Error()) - } + var config *irc.Config + var logman *logger.Manager + if !arguments["genkeys"].(bool) { + config, err = irc.LoadConfig(configfile) + if err != nil { + log.Fatal("Config file did not load successfully:", err.Error()) + } - // assemble separate log configs - var logConfigs []logger.Config - for _, lConfig := range config.Logging { - logConfigs = append(logConfigs, logger.Config{ - MethodStdout: lConfig.MethodStdout, - MethodStderr: lConfig.MethodStderr, - MethodFile: lConfig.MethodFile, - Filename: lConfig.Filename, - Level: lConfig.Level, - Types: lConfig.Types, - ExcludedTypes: lConfig.ExcludedTypes, - }) - } + // assemble separate log configs + var logConfigs []logger.Config + for _, lConfig := range config.Logging { + logConfigs = append(logConfigs, logger.Config{ + MethodStdout: lConfig.MethodStdout, + MethodStderr: lConfig.MethodStderr, + MethodFile: lConfig.MethodFile, + Filename: lConfig.Filename, + Level: lConfig.Level, + Types: lConfig.Types, + ExcludedTypes: lConfig.ExcludedTypes, + }) + } - logger, err := logger.NewManager(logConfigs...) - if err != nil { - log.Fatal("Logger did not load successfully:", err.Error()) + logman, err = logger.NewManager(logConfigs...) + if err != nil { + log.Fatal("Logger did not load successfully:", err.Error()) + } } if arguments["genpasswd"].(bool) { @@ -109,6 +86,65 @@ Options: } fmt.Print("\n") fmt.Println(encoded) + } else if arguments["genkeys"].(bool) { + fmt.Println("Here are your cloak keys:") + + // generate IPv4 keys + keyA, err := cloak.GenerateCloakKey() + if err != nil { + log.Fatal("Error generating cloak keys:", err) + } + keyB, err := cloak.GenerateCloakKey() + if err != nil { + log.Fatal("Error generating cloak keys:", err) + } + keyC, err := cloak.GenerateCloakKey() + if err != nil { + log.Fatal("Error generating cloak keys:", err) + } + keyD, err := cloak.GenerateCloakKey() + if err != nil { + log.Fatal("Error generating cloak keys:", err) + } + + fmt.Println(fmt.Sprintf(`ipv4-keys: ["%s", "%s", "%s", "%s"]`, keyA, keyB, keyC, keyD)) + + // generate IPv6 keys + keyA, err = cloak.GenerateCloakKey() + if err != nil { + log.Fatal("Error generating cloak keys:", err) + } + keyB, err = cloak.GenerateCloakKey() + if err != nil { + log.Fatal("Error generating cloak keys:", err) + } + keyC, err = cloak.GenerateCloakKey() + if err != nil { + log.Fatal("Error generating cloak keys:", err) + } + keyD, err = cloak.GenerateCloakKey() + if err != nil { + log.Fatal("Error generating cloak keys:", err) + } + keyE, err := cloak.GenerateCloakKey() + if err != nil { + log.Fatal("Error generating cloak keys:", err) + } + keyF, err := cloak.GenerateCloakKey() + if err != nil { + log.Fatal("Error generating cloak keys:", err) + } + keyG, err := cloak.GenerateCloakKey() + if err != nil { + log.Fatal("Error generating cloak keys:", err) + } + keyH, err := cloak.GenerateCloakKey() + if err != nil { + log.Fatal("Error generating cloak keys:", err) + } + + fmt.Println(fmt.Sprintf(`ipv6-keys: ["%s", "%s", "%s", "%s", "%s", "%s", "%s", "%s"]`, keyA, keyB, keyC, keyD, keyE, keyF, keyG, keyH)) + } else if arguments["initdb"].(bool) { irc.InitDB(config.Datastore.Path) if !arguments["--quiet"].(bool) { @@ -139,13 +175,13 @@ Options: } else if arguments["run"].(bool) { rand.Seed(time.Now().UTC().UnixNano()) if !arguments["--quiet"].(bool) { - logger.Info("startup", fmt.Sprintf("Oragono v%s starting", irc.SemVer)) + logman.Info("startup", fmt.Sprintf("Oragono v%s starting", irc.SemVer)) } // profiling if config.Debug.StackImpact.Enabled { if config.Debug.StackImpact.AgentKey == "" || config.Debug.StackImpact.AppName == "" { - logger.Error("startup", "Could not start StackImpact - agent-key or app-name are undefined") + logman.Error("startup", "Could not start StackImpact - agent-key or app-name are undefined") return } @@ -153,22 +189,22 @@ Options: agent.Start(stackimpact.Options{AgentKey: config.Debug.StackImpact.AgentKey, AppName: config.Debug.StackImpact.AppName}) defer agent.RecordPanic() - logger.Info("startup", fmt.Sprintf("StackImpact profiling started as %s", config.Debug.StackImpact.AppName)) + logman.Info("startup", fmt.Sprintf("StackImpact profiling started as %s", config.Debug.StackImpact.AppName)) } // warning if running a non-final version if strings.Contains(irc.SemVer, "unreleased") { - logger.Warning("startup", "You are currently running an unreleased beta version of Oragono that may be unstable and could corrupt your database.\nIf you are running a production network, please download the latest build from https://oragono.io/downloads.html and run that instead.") + logman.Warning("startup", "You are currently running an unreleased beta version of Oragono that may be unstable and could corrupt your database.\nIf you are running a production network, please download the latest build from https://oragono.io/downloads.html and run that instead.") } - server, err := irc.NewServer(configfile, config, logger) + server, err := irc.NewServer(configfile, config, logman) if err != nil { - logger.Error("startup", fmt.Sprintf("Could not load server: %s", err.Error())) + logman.Error("startup", fmt.Sprintf("Could not load server: %s", err.Error())) return } if !arguments["--quiet"].(bool) { - logger.Info("startup", "Server running") - defer logger.Info("shutdown", fmt.Sprintf("Oragono v%s exiting", irc.SemVer)) + logman.Info("startup", "Server running") + defer logman.Info("shutdown", fmt.Sprintf("Oragono v%s exiting", irc.SemVer)) } server.Run() } diff --git a/oragono.yaml b/oragono.yaml index bfb961a8..af026ae4 100644 --- a/oragono.yaml +++ b/oragono.yaml @@ -5,6 +5,26 @@ network: # name of the network name: OragonoTest + # cloaking IP addresses and hostnames + ip-cloaking: + # enable the cloaking + enabled: false + + # short name to use in cloaked hostnames + netname: "testnet" + + # ipv4 cloak keys + # to generate these keys, run "oragono genkeys" + ipv4-keys: ["keyhere", "keyhere", "keyhere", "keyhere"] + + # ipv6 cloak keys + # to generate these keys, run "oragono genkeys" + ipv6-keys: ["keyhere", "keyhere", "keyhere", "keyhere", "keyhere", "keyhere", "keyhere", "keyhere"] + + # hostname cloaking keys + # to generate these keys, run "oragono genkeys" + hostname-keys: ["keyhere", "keyhere", "keyhere", "keyhere"] + # server configuration server: # server name