mirror of
https://github.com/ergochat/ergo.git
synced 2024-11-29 15:40:02 +01:00
Merge pull request #1313 from slingamn/issue1312_unique_hostnames.1
fix #1312
This commit is contained in:
commit
3cd0e40146
@ -269,6 +269,12 @@ server:
|
||||
# whether to enable IP cloaking
|
||||
enabled: false
|
||||
|
||||
# whether to use these cloak settings (specifically, `netname` and `num-bits`)
|
||||
# to produce unique hostnames for always-on clients. you can enable this even if
|
||||
# you disabled IP cloaking for normal clients above. if this is disabled,
|
||||
# always-on clients will all have an identical hostname (the server name).
|
||||
enabled-for-always-on: true
|
||||
|
||||
# fake TLD at the end of the hostname, e.g., pwbs2ui4377257x8.irc
|
||||
# you may want to use your network name here
|
||||
netname: "irc"
|
||||
|
@ -297,6 +297,12 @@ server:
|
||||
# whether to enable IP cloaking
|
||||
enabled: true
|
||||
|
||||
# whether to use these cloak settings (specifically, `netname` and `num-bits`)
|
||||
# to produce unique hostnames for always-on clients. you can enable this even if
|
||||
# you disabled IP cloaking for normal clients above. if this is disabled,
|
||||
# always-on clients will all have an identical hostname (the server name).
|
||||
enabled-for-always-on: true
|
||||
|
||||
# fake TLD at the end of the hostname, e.g., pwbs2ui4377257x8.irc
|
||||
# you may want to use your network name here
|
||||
netname: "irc"
|
||||
|
@ -411,6 +411,11 @@ func (server *Server) AddAlwaysOnClient(account ClientAccount, chnames []string,
|
||||
lastSeen = map[string]time.Time{"": now}
|
||||
}
|
||||
|
||||
hostname := server.name
|
||||
if config.Server.Cloaks.EnabledForAlwaysOn {
|
||||
hostname = config.Server.Cloaks.ComputeAccountCloak(account.Name)
|
||||
}
|
||||
|
||||
client := &Client{
|
||||
lastSeen: lastSeen,
|
||||
lastActive: now,
|
||||
@ -419,9 +424,8 @@ func (server *Server) AddAlwaysOnClient(account ClientAccount, chnames []string,
|
||||
languages: server.Languages().Default(),
|
||||
server: server,
|
||||
|
||||
// TODO figure out how to set these on reattach?
|
||||
username: "~user",
|
||||
rawHostname: server.name,
|
||||
rawHostname: hostname,
|
||||
realIP: utils.IPv4LoopbackAddress,
|
||||
|
||||
alwaysOn: true,
|
||||
|
@ -104,3 +104,25 @@ func BenchmarkCloaks(b *testing.B) {
|
||||
config.ComputeCloak(v6ip)
|
||||
}
|
||||
}
|
||||
|
||||
func TestAccountCloak(t *testing.T) {
|
||||
config := cloakConfForTesting()
|
||||
|
||||
// just assert that we get all distinct values
|
||||
assertEqual(config.ComputeAccountCloak("shivaram"), "8yu8kunudb45ztxm.oragono", t)
|
||||
assertEqual(config.ComputeAccountCloak("dolph🐬n"), "hhgeqsvzeagv3wjw.oragono", t)
|
||||
assertEqual(config.ComputeAccountCloak("SHIVARAM"), "bgx32x4r7qzih4uh.oragono", t)
|
||||
assertEqual(config.ComputeAccountCloak("ed"), "j5autmgxtdjdyzf4.oragono", t)
|
||||
}
|
||||
|
||||
func TestAccountCloakCollisions(t *testing.T) {
|
||||
config := cloakConfForTesting()
|
||||
|
||||
v4ip := easyParseIP("97.97.97.97")
|
||||
v4cloak := config.ComputeCloak(v4ip)
|
||||
// "aaaa" is the same bytestring as 97.97.97.97
|
||||
aaaacloak := config.ComputeAccountCloak("aaaa")
|
||||
if v4cloak == aaaacloak {
|
||||
t.Errorf("cloak collision between 97.97.97.97 and aaaa: %s", v4cloak)
|
||||
}
|
||||
}
|
||||
|
@ -13,6 +13,7 @@ import (
|
||||
|
||||
type CloakConfig struct {
|
||||
Enabled bool
|
||||
EnabledForAlwaysOn bool `yaml:"enabled-for-always-on"`
|
||||
Netname string
|
||||
CidrLenIPv4 int `yaml:"cidr-len-ipv4"`
|
||||
CidrLenIPv6 int `yaml:"cidr-len-ipv6"`
|
||||
@ -26,14 +27,10 @@ type CloakConfig struct {
|
||||
}
|
||||
|
||||
func (cloakConfig *CloakConfig) Initialize() {
|
||||
if !cloakConfig.Enabled {
|
||||
return
|
||||
}
|
||||
|
||||
// sanity checks:
|
||||
numBits := cloakConfig.NumBits
|
||||
if 0 == numBits {
|
||||
numBits = 80
|
||||
numBits = 64
|
||||
} else if 256 < numBits {
|
||||
numBits = 256
|
||||
}
|
||||
@ -69,12 +66,30 @@ func (config *CloakConfig) ComputeCloak(ip net.IP) string {
|
||||
} else {
|
||||
masked = ip.Mask(config.ipv6Mask)
|
||||
}
|
||||
return config.macAndCompose(masked)
|
||||
}
|
||||
|
||||
func (config *CloakConfig) macAndCompose(b []byte) string {
|
||||
// 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))
|
||||
input := make([]byte, len(config.secret)+len(b))
|
||||
copy(input, config.secret[:])
|
||||
copy(input[len(config.secret):], masked)
|
||||
copy(input[len(config.secret):], b)
|
||||
digest := sha3.Sum512(input)
|
||||
b32digest := utils.B32Encoder.EncodeToString(digest[:config.numBytes])
|
||||
return fmt.Sprintf("%s.%s", b32digest, config.Netname)
|
||||
}
|
||||
|
||||
func (config *CloakConfig) ComputeAccountCloak(accountName string) string {
|
||||
// XXX don't bother checking EnabledForAlwaysOn, since if it's disabled,
|
||||
// we need to use the server name which we don't have
|
||||
if config.NumBits == 0 || config.secret == "" {
|
||||
return config.Netname
|
||||
}
|
||||
|
||||
// pad with 16 initial bytes of zeroes, avoiding any possibility of collision
|
||||
// with a masked IP that could be an input to ComputeCloak:
|
||||
paddedAccountName := make([]byte, 16+len(accountName))
|
||||
copy(paddedAccountName[16:], accountName[:])
|
||||
return config.macAndCompose(paddedAccountName)
|
||||
}
|
||||
|
@ -599,9 +599,7 @@ func (server *Server) applyConfig(config *Config) (err error) {
|
||||
// now that the datastore is initialized, we can load the cloak secret from it
|
||||
// XXX this modifies config after the initial load, which is naughty,
|
||||
// but there's no data race because we haven't done SetConfig yet
|
||||
if config.Server.Cloaks.Enabled {
|
||||
config.Server.Cloaks.SetSecret(LoadCloakSecret(server.store))
|
||||
}
|
||||
|
||||
// activate the new config
|
||||
server.SetConfig(config)
|
||||
|
Loading…
Reference in New Issue
Block a user