mirror of
https://github.com/ergochat/ergo.git
synced 2024-11-29 23:49:25 +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
|
# whether to enable IP cloaking
|
||||||
enabled: false
|
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
|
# fake TLD at the end of the hostname, e.g., pwbs2ui4377257x8.irc
|
||||||
# you may want to use your network name here
|
# you may want to use your network name here
|
||||||
netname: "irc"
|
netname: "irc"
|
||||||
|
@ -297,6 +297,12 @@ server:
|
|||||||
# whether to enable IP cloaking
|
# whether to enable IP cloaking
|
||||||
enabled: true
|
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
|
# fake TLD at the end of the hostname, e.g., pwbs2ui4377257x8.irc
|
||||||
# you may want to use your network name here
|
# you may want to use your network name here
|
||||||
netname: "irc"
|
netname: "irc"
|
||||||
|
@ -411,6 +411,11 @@ func (server *Server) AddAlwaysOnClient(account ClientAccount, chnames []string,
|
|||||||
lastSeen = map[string]time.Time{"": now}
|
lastSeen = map[string]time.Time{"": now}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
hostname := server.name
|
||||||
|
if config.Server.Cloaks.EnabledForAlwaysOn {
|
||||||
|
hostname = config.Server.Cloaks.ComputeAccountCloak(account.Name)
|
||||||
|
}
|
||||||
|
|
||||||
client := &Client{
|
client := &Client{
|
||||||
lastSeen: lastSeen,
|
lastSeen: lastSeen,
|
||||||
lastActive: now,
|
lastActive: now,
|
||||||
@ -419,9 +424,8 @@ func (server *Server) AddAlwaysOnClient(account ClientAccount, chnames []string,
|
|||||||
languages: server.Languages().Default(),
|
languages: server.Languages().Default(),
|
||||||
server: server,
|
server: server,
|
||||||
|
|
||||||
// TODO figure out how to set these on reattach?
|
|
||||||
username: "~user",
|
username: "~user",
|
||||||
rawHostname: server.name,
|
rawHostname: hostname,
|
||||||
realIP: utils.IPv4LoopbackAddress,
|
realIP: utils.IPv4LoopbackAddress,
|
||||||
|
|
||||||
alwaysOn: true,
|
alwaysOn: true,
|
||||||
|
@ -104,3 +104,25 @@ func BenchmarkCloaks(b *testing.B) {
|
|||||||
config.ComputeCloak(v6ip)
|
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 {
|
type CloakConfig struct {
|
||||||
Enabled bool
|
Enabled bool
|
||||||
|
EnabledForAlwaysOn bool `yaml:"enabled-for-always-on"`
|
||||||
Netname string
|
Netname string
|
||||||
CidrLenIPv4 int `yaml:"cidr-len-ipv4"`
|
CidrLenIPv4 int `yaml:"cidr-len-ipv4"`
|
||||||
CidrLenIPv6 int `yaml:"cidr-len-ipv6"`
|
CidrLenIPv6 int `yaml:"cidr-len-ipv6"`
|
||||||
@ -26,14 +27,10 @@ type CloakConfig struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (cloakConfig *CloakConfig) Initialize() {
|
func (cloakConfig *CloakConfig) Initialize() {
|
||||||
if !cloakConfig.Enabled {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
// sanity checks:
|
// sanity checks:
|
||||||
numBits := cloakConfig.NumBits
|
numBits := cloakConfig.NumBits
|
||||||
if 0 == numBits {
|
if 0 == numBits {
|
||||||
numBits = 80
|
numBits = 64
|
||||||
} else if 256 < numBits {
|
} else if 256 < numBits {
|
||||||
numBits = 256
|
numBits = 256
|
||||||
}
|
}
|
||||||
@ -69,12 +66,30 @@ func (config *CloakConfig) ComputeCloak(ip net.IP) string {
|
|||||||
} else {
|
} else {
|
||||||
masked = ip.Mask(config.ipv6Mask)
|
masked = ip.Mask(config.ipv6Mask)
|
||||||
}
|
}
|
||||||
|
return config.macAndCompose(masked)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (config *CloakConfig) macAndCompose(b []byte) string {
|
||||||
// SHA3(K || M):
|
// SHA3(K || M):
|
||||||
// https://crypto.stackexchange.com/questions/17735/is-hmac-needed-for-a-sha-3-based-mac
|
// 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, config.secret[:])
|
||||||
copy(input[len(config.secret):], masked)
|
copy(input[len(config.secret):], b)
|
||||||
digest := sha3.Sum512(input)
|
digest := sha3.Sum512(input)
|
||||||
b32digest := utils.B32Encoder.EncodeToString(digest[:config.numBytes])
|
b32digest := utils.B32Encoder.EncodeToString(digest[:config.numBytes])
|
||||||
return fmt.Sprintf("%s.%s", b32digest, config.Netname)
|
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
|
// 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,
|
// XXX this modifies config after the initial load, which is naughty,
|
||||||
// but there's no data race because we haven't done SetConfig yet
|
// 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))
|
config.Server.Cloaks.SetSecret(LoadCloakSecret(server.store))
|
||||||
}
|
|
||||||
|
|
||||||
// activate the new config
|
// activate the new config
|
||||||
server.SetConfig(config)
|
server.SetConfig(config)
|
||||||
|
Loading…
Reference in New Issue
Block a user