Sfoglia il codice sorgente

Merge pull request #481 from slingamn/cloaks.5

implement ip cloaking
tags/v1.1.0-rc1
Shivaram Lingamneni 5 anni fa
parent
commit
13dda00989
Nessun account collegato all'indirizzo email del committer
10 ha cambiato i file con 264 aggiunte e 4 eliminazioni
  1. 1
    0
      Makefile
  2. 11
    0
      docs/MANUAL.md
  3. 11
    1
      irc/client.go
  4. 106
    0
      irc/cloaks/cloak_test.go
  5. 70
    0
      irc/cloaks/cloaks.go
  6. 9
    0
      irc/config.go
  7. 2
    0
      irc/gateways.go
  8. 10
    2
      irc/utils/crypto.go
  9. 6
    1
      oragono.go
  10. 38
    0
      oragono.yaml

+ 1
- 0
Makefile Vedi File

20
 	python3 ./gencapdefs.py | diff - ${capdef_file}
20
 	python3 ./gencapdefs.py | diff - ${capdef_file}
21
 	cd irc && go test . && go vet .
21
 	cd irc && go test . && go vet .
22
 	cd irc/caps && go test . && go vet .
22
 	cd irc/caps && go test . && go vet .
23
+	cd irc/cloaks && go test . && go vet .
23
 	cd irc/connection_limits && go test . && go vet .
24
 	cd irc/connection_limits && go test . && go vet .
24
 	cd irc/history && go test . && go vet .
25
 	cd irc/history && go test . && go vet .
25
 	cd irc/isupport && go test . && go vet .
26
 	cd irc/isupport && go test . && go vet .

+ 11
- 0
docs/MANUAL.md Vedi File

26
         - Nickname reservation
26
         - Nickname reservation
27
     - Channel Registration
27
     - Channel Registration
28
     - Language
28
     - Language
29
+    - IP cloaking
29
 - Frequently Asked Questions
30
 - Frequently Asked Questions
30
 - Modes
31
 - Modes
31
     - User Modes
32
     - User Modes
242
 Our language and translation functionality is very early, so feel free to let us know if there are any troubles with it! If you know another language and you'd like to contribute, we've got a CrowdIn project here: [https://crowdin.com/project/oragono](https://crowdin.com/project/oragono)
243
 Our language and translation functionality is very early, so feel free to let us know if there are any troubles with it! If you know another language and you'd like to contribute, we've got a CrowdIn project here: [https://crowdin.com/project/oragono](https://crowdin.com/project/oragono)
243
 
244
 
244
 
245
 
246
+## IP cloaking
247
+
248
+Unlike many other chat and web platforms, IRC traditionally exposes the user's IP and hostname information to other users. This is in part because channel owners and operators (who have privileges over a single channel, but not over the server as a whole) need to be able to ban spammers and abusers from their channels, including via hostnames in cases where the abuser tries to evade the ban.
249
+
250
+IP cloaking is a way of balancing these concerns about abuse with concerns about user privacy. With cloaking, the user's IP address is deterministically "scrambled", typically via a cryptographic [MAC](https://en.wikipedia.org/wiki/Message_authentication_code), to form a "cloaked" hostname that replaces the usual reverse-DNS-based hostname. Users cannot reverse the scrambling to learn each other's IPs, but can ban a scrambled address the same way they would ban a regular hostname.
251
+
252
+Oragono supports cloaking, which can be enabled via the `server.ip-cloaking` section of the config. However, Oragono's cloaking behavior differs from other IRC software. Rather than scrambling each of the 4 bytes of the IPv4 address (or each 2-byte pair of the 8 such pairs of the IPv6 address) separately, the server administrator configures a CIDR length (essentially, a fixed number of most-significant-bits of the address). The CIDR (i.e., only the most significant portion of the address) is then scrambled atomically to produce the cloaked hostname. This errs on the side of user privacy, since knowing the cloaked hostname for one CIDR tells you nothing about the cloaked hostnames of other CIDRs --- the scheme reveals only whether two users are coming from the same CIDR. We suggest using 32-bit CIDRs for IPv4 (i.e., the whole address) and 64-bit CIDRs for IPv6, since these are the typical assignments made by ISPs to individual customers.
253
+
254
+Setting `server.ip-cloaking.num-bits` to 0 gives users cloaks that don't depend on their IP address information at all, which is an option for deployments where privacy is a more pressing concern than abuse. Holders of registered accounts can also use the vhost system (for details, `/msg HostServ HELP`.)
255
+
245
 -------------------------------------------------------------------------------------------
256
 -------------------------------------------------------------------------------------------
246
 
257
 
247
 
258
 

+ 11
- 1
irc/client.go Vedi File

70
 	preregNick         string
70
 	preregNick         string
71
 	proxiedIP          net.IP // actual remote IP if using the PROXY protocol
71
 	proxiedIP          net.IP // actual remote IP if using the PROXY protocol
72
 	rawHostname        string
72
 	rawHostname        string
73
+	cloakedHostname    string
73
 	realname           string
74
 	realname           string
74
 	realIP             net.IP
75
 	realIP             net.IP
75
 	registered         bool
76
 	registered         bool
215
 		session.realIP = utils.AddrToIP(remoteAddr)
216
 		session.realIP = utils.AddrToIP(remoteAddr)
216
 		// set the hostname for this client (may be overridden later by PROXY or WEBIRC)
217
 		// set the hostname for this client (may be overridden later by PROXY or WEBIRC)
217
 		session.rawHostname = utils.LookupHostname(session.realIP.String())
218
 		session.rawHostname = utils.LookupHostname(session.realIP.String())
219
+		client.cloakedHostname = config.Server.Cloaks.ComputeCloak(session.realIP)
218
 		if utils.AddrIsLocal(remoteAddr) {
220
 		if utils.AddrIsLocal(remoteAddr) {
219
 			// treat local connections as secure (may be overridden later by WEBIRC)
221
 			// treat local connections as secure (may be overridden later by WEBIRC)
220
 			client.SetMode(modes.TLS, true)
222
 			client.SetMode(modes.TLS, true)
812
 func (client *Client) updateNickMaskNoMutex() {
814
 func (client *Client) updateNickMaskNoMutex() {
813
 	client.hostname = client.getVHostNoMutex()
815
 	client.hostname = client.getVHostNoMutex()
814
 	if client.hostname == "" {
816
 	if client.hostname == "" {
815
-		client.hostname = client.rawHostname
817
+		client.hostname = client.cloakedHostname
818
+		if client.hostname == "" {
819
+			client.hostname = client.rawHostname
820
+		}
816
 	}
821
 	}
817
 
822
 
818
 	cfhostname, err := Casefold(client.hostname)
823
 	cfhostname, err := Casefold(client.hostname)
831
 	nick := client.nickCasefolded
836
 	nick := client.nickCasefolded
832
 	username := client.username
837
 	username := client.username
833
 	rawHostname := client.rawHostname
838
 	rawHostname := client.rawHostname
839
+	cloakedHostname := client.cloakedHostname
834
 	vhost := client.getVHostNoMutex()
840
 	vhost := client.getVHostNoMutex()
835
 	client.stateMutex.RUnlock()
841
 	client.stateMutex.RUnlock()
836
 	username = strings.ToLower(username)
842
 	username = strings.ToLower(username)
849
 		masks = append(masks, rawhostmask)
855
 		masks = append(masks, rawhostmask)
850
 	}
856
 	}
851
 
857
 
858
+	if cloakedHostname != "" {
859
+		masks = append(masks, fmt.Sprintf("%s!%s@%s", nick, username, cloakedHostname))
860
+	}
861
+
852
 	ipmask := fmt.Sprintf("%s!%s@%s", nick, username, client.IPString())
862
 	ipmask := fmt.Sprintf("%s!%s@%s", nick, username, client.IPString())
853
 	if ipmask != rawhostmask {
863
 	if ipmask != rawhostmask {
854
 		masks = append(masks, ipmask)
864
 		masks = append(masks, ipmask)

+ 106
- 0
irc/cloaks/cloak_test.go Vedi File

1
+// Copyright (c) 2019 Shivaram Lingamneni
2
+// released under the MIT license
3
+
4
+package cloaks
5
+
6
+import (
7
+	"net"
8
+	"reflect"
9
+	"testing"
10
+)
11
+
12
+func assertEqual(supplied, expected interface{}, t *testing.T) {
13
+	if !reflect.DeepEqual(supplied, expected) {
14
+		t.Errorf("expected %v but got %v", expected, supplied)
15
+	}
16
+}
17
+
18
+func easyParseIP(ipstr string) (result net.IP) {
19
+	result = net.ParseIP(ipstr)
20
+	if result == nil {
21
+		panic(ipstr)
22
+	}
23
+	return
24
+}
25
+
26
+func cloakConfForTesting() CloakConfig {
27
+	config := CloakConfig{
28
+		Enabled:     true,
29
+		Netname:     "oragono",
30
+		Secret:      "_BdVPWB5sray7McbFmeuJL996yaLgG4l9tEyficGXKg",
31
+		CidrLenIPv4: 32,
32
+		CidrLenIPv6: 64,
33
+		NumBits:     80,
34
+	}
35
+	config.Initialize()
36
+	return config
37
+}
38
+
39
+func TestCloakDeterminism(t *testing.T) {
40
+	config := cloakConfForTesting()
41
+
42
+	v4ip := easyParseIP("8.8.8.8").To4()
43
+	assertEqual(config.ComputeCloak(v4ip), "d2z5guriqhzwazyr.oragono", t)
44
+	// use of the 4-in-6 mapping should not affect the cloak
45
+	v6mappedIP := v4ip.To16()
46
+	assertEqual(config.ComputeCloak(v6mappedIP), "d2z5guriqhzwazyr.oragono", t)
47
+
48
+	v6ip := easyParseIP("2001:0db8::1")
49
+	assertEqual(config.ComputeCloak(v6ip), "w7ren6nxii6f3i3d.oragono", t)
50
+	// same CIDR, so same cloak:
51
+	v6ipsamecidr := easyParseIP("2001:0db8::2")
52
+	assertEqual(config.ComputeCloak(v6ipsamecidr), "w7ren6nxii6f3i3d.oragono", t)
53
+	v6ipdifferentcidr := easyParseIP("2001:0db9::1")
54
+	// different CIDR, different cloak:
55
+	assertEqual(config.ComputeCloak(v6ipdifferentcidr), "ccmptyrjwsxv4f4d.oragono", t)
56
+
57
+	// cloak values must be sensitive to changes in the secret key
58
+	config.Secret = "HJcXK4lLawxBE4-9SIdPji_21YiL3N5r5f5-SPNrGVY"
59
+	assertEqual(config.ComputeCloak(v4ip), "4khy3usk8mfu42pe.oragono", t)
60
+	assertEqual(config.ComputeCloak(v6mappedIP), "4khy3usk8mfu42pe.oragono", t)
61
+	assertEqual(config.ComputeCloak(v6ip), "mxpk3c83vdxkek9j.oragono", t)
62
+	assertEqual(config.ComputeCloak(v6ipsamecidr), "mxpk3c83vdxkek9j.oragono", t)
63
+}
64
+
65
+func TestCloakShortv4Cidr(t *testing.T) {
66
+	config := CloakConfig{
67
+		Enabled:     true,
68
+		Netname:     "oragono",
69
+		Secret:      "_BdVPWB5sray7McbFmeuJL996yaLgG4l9tEyficGXKg",
70
+		CidrLenIPv4: 24,
71
+		CidrLenIPv6: 64,
72
+		NumBits:     60,
73
+	}
74
+	config.Initialize()
75
+
76
+	v4ip := easyParseIP("8.8.8.8")
77
+	assertEqual(config.ComputeCloak(v4ip), "3cay3zc72tnui.oragono", t)
78
+	v4ipsamecidr := easyParseIP("8.8.8.9")
79
+	assertEqual(config.ComputeCloak(v4ipsamecidr), "3cay3zc72tnui.oragono", t)
80
+}
81
+
82
+func TestCloakZeroBits(t *testing.T) {
83
+	config := cloakConfForTesting()
84
+	config.NumBits = 0
85
+	config.Netname = "example.com"
86
+	config.Initialize()
87
+
88
+	v4ip := easyParseIP("8.8.8.8").To4()
89
+	assertEqual(config.ComputeCloak(v4ip), "example.com", t)
90
+}
91
+
92
+func TestCloakDisabled(t *testing.T) {
93
+	config := cloakConfForTesting()
94
+	config.Enabled = false
95
+	v4ip := easyParseIP("8.8.8.8").To4()
96
+	assertEqual(config.ComputeCloak(v4ip), "", t)
97
+}
98
+
99
+func BenchmarkCloaks(b *testing.B) {
100
+	config := cloakConfForTesting()
101
+	v6ip := easyParseIP("2001:0db8::1")
102
+	b.ResetTimer()
103
+	for i := 0; i < b.N; i++ {
104
+		config.ComputeCloak(v6ip)
105
+	}
106
+}

+ 70
- 0
irc/cloaks/cloaks.go Vedi File

1
+// Copyright (c) 2019 Shivaram Lingamneni
2
+
3
+package cloaks
4
+
5
+import (
6
+	"fmt"
7
+	"net"
8
+
9
+	"golang.org/x/crypto/sha3"
10
+
11
+	"github.com/oragono/oragono/irc/utils"
12
+)
13
+
14
+type CloakConfig struct {
15
+	Enabled     bool
16
+	Netname     string
17
+	Secret      string
18
+	CidrLenIPv4 int `yaml:"cidr-len-ipv4"`
19
+	CidrLenIPv6 int `yaml:"cidr-len-ipv6"`
20
+	NumBits     int `yaml:"num-bits"`
21
+
22
+	numBytes int
23
+	ipv4Mask net.IPMask
24
+	ipv6Mask net.IPMask
25
+}
26
+
27
+func (cloakConfig *CloakConfig) Initialize() {
28
+	// sanity checks:
29
+	numBits := cloakConfig.NumBits
30
+	if 0 == numBits {
31
+		numBits = 80
32
+	} else if 256 < numBits {
33
+		numBits = 256
34
+	}
35
+
36
+	// derived values:
37
+	cloakConfig.numBytes = numBits / 8
38
+	// round up to the nearest byte
39
+	if numBits%8 != 0 {
40
+		cloakConfig.numBytes += 1
41
+	}
42
+	cloakConfig.ipv4Mask = net.CIDRMask(cloakConfig.CidrLenIPv4, 32)
43
+	cloakConfig.ipv6Mask = net.CIDRMask(cloakConfig.CidrLenIPv6, 128)
44
+}
45
+
46
+// simple cloaking algorithm: normalize the IP to its CIDR,
47
+// then hash the resulting bytes with a secret key,
48
+// then truncate to the desired length, b32encode, and append the fake TLD.
49
+func (config *CloakConfig) ComputeCloak(ip net.IP) string {
50
+	if !config.Enabled {
51
+		return ""
52
+	} else if config.NumBits == 0 {
53
+		return config.Netname
54
+	}
55
+	var masked net.IP
56
+	v4ip := ip.To4()
57
+	if v4ip != nil {
58
+		masked = v4ip.Mask(config.ipv4Mask)
59
+	} else {
60
+		masked = ip.Mask(config.ipv6Mask)
61
+	}
62
+	// SHA3(K || M):
63
+	// https://crypto.stackexchange.com/questions/17735/is-hmac-needed-for-a-sha-3-based-mac
64
+	input := make([]byte, len(config.Secret)+len(masked))
65
+	copy(input, config.Secret[:])
66
+	copy(input[len(config.Secret):], masked)
67
+	digest := sha3.Sum512(input)
68
+	b32digest := utils.B32Encoder.EncodeToString(digest[:config.numBytes])
69
+	return fmt.Sprintf("%s.%s", b32digest, config.Netname)
70
+}

+ 9
- 0
irc/config.go Vedi File

18
 	"time"
18
 	"time"
19
 
19
 
20
 	"code.cloudfoundry.org/bytefmt"
20
 	"code.cloudfoundry.org/bytefmt"
21
+	"github.com/oragono/oragono/irc/cloaks"
21
 	"github.com/oragono/oragono/irc/connection_limits"
22
 	"github.com/oragono/oragono/irc/connection_limits"
22
 	"github.com/oragono/oragono/irc/custime"
23
 	"github.com/oragono/oragono/irc/custime"
23
 	"github.com/oragono/oragono/irc/isupport"
24
 	"github.com/oragono/oragono/irc/isupport"
297
 		isupport            isupport.List
298
 		isupport            isupport.List
298
 		ConnectionLimiter   connection_limits.LimiterConfig   `yaml:"connection-limits"`
299
 		ConnectionLimiter   connection_limits.LimiterConfig   `yaml:"connection-limits"`
299
 		ConnectionThrottler connection_limits.ThrottlerConfig `yaml:"connection-throttling"`
300
 		ConnectionThrottler connection_limits.ThrottlerConfig `yaml:"connection-throttling"`
301
+		Cloaks              cloaks.CloakConfig                `yaml:"ip-cloaking"`
300
 	}
302
 	}
301
 
303
 
302
 	Languages struct {
304
 	Languages struct {
728
 		config.History.ClientLength = 0
730
 		config.History.ClientLength = 0
729
 	}
731
 	}
730
 
732
 
733
+	config.Server.Cloaks.Initialize()
734
+	if config.Server.Cloaks.Enabled {
735
+		if config.Server.Cloaks.Secret == "" || config.Server.Cloaks.Secret == "siaELnk6Kaeo65K3RCrwJjlWaZ-Bt3WuZ2L8MXLbNb4" {
736
+			return nil, fmt.Errorf("You must generate a new value of server.ip-cloaking.secret to enable cloaking")
737
+		}
738
+	}
739
+
731
 	for _, listenAddress := range config.Server.TorListeners.Listeners {
740
 	for _, listenAddress := range config.Server.TorListeners.Listeners {
732
 		found := false
741
 		found := false
733
 		for _, configuredListener := range config.Server.Listen {
742
 		for _, configuredListener := range config.Server.Listen {

+ 2
- 0
irc/gateways.go Vedi File

70
 	ipstring := parsedProxiedIP.String()
70
 	ipstring := parsedProxiedIP.String()
71
 	client.server.logger.Info("localconnect-ip", "Accepted proxy IP for client", ipstring)
71
 	client.server.logger.Info("localconnect-ip", "Accepted proxy IP for client", ipstring)
72
 	rawHostname := utils.LookupHostname(ipstring)
72
 	rawHostname := utils.LookupHostname(ipstring)
73
+	cloakedHostname := client.server.Config().Server.Cloaks.ComputeCloak(parsedProxiedIP)
73
 
74
 
74
 	client.stateMutex.Lock()
75
 	client.stateMutex.Lock()
75
 	defer client.stateMutex.Unlock()
76
 	defer client.stateMutex.Unlock()
77
 	client.proxiedIP = parsedProxiedIP
78
 	client.proxiedIP = parsedProxiedIP
78
 	session.rawHostname = rawHostname
79
 	session.rawHostname = rawHostname
79
 	client.rawHostname = rawHostname
80
 	client.rawHostname = rawHostname
81
+	client.cloakedHostname = cloakedHostname
80
 	// nickmask will be updated when the client completes registration
82
 	// nickmask will be updated when the client completes registration
81
 	// set tls info
83
 	// set tls info
82
 	client.certfp = ""
84
 	client.certfp = ""

+ 10
- 2
irc/utils/crypto.go Vedi File

7
 	"crypto/rand"
7
 	"crypto/rand"
8
 	"crypto/subtle"
8
 	"crypto/subtle"
9
 	"encoding/base32"
9
 	"encoding/base32"
10
+	"encoding/base64"
10
 )
11
 )
11
 
12
 
12
 var (
13
 var (
13
 	// slingamn's own private b32 alphabet, removing 1, l, o, and 0
14
 	// slingamn's own private b32 alphabet, removing 1, l, o, and 0
14
-	b32encoder = base32.NewEncoding("abcdefghijkmnpqrstuvwxyz23456789").WithPadding(base32.NoPadding)
15
+	B32Encoder = base32.NewEncoding("abcdefghijkmnpqrstuvwxyz23456789").WithPadding(base32.NoPadding)
15
 )
16
 )
16
 
17
 
17
 const (
18
 const (
24
 	var buf [16]byte
25
 	var buf [16]byte
25
 	rand.Read(buf[:])
26
 	rand.Read(buf[:])
26
 	// 26 ASCII characters, should be fine for most purposes
27
 	// 26 ASCII characters, should be fine for most purposes
27
-	return b32encoder.EncodeToString(buf[:])
28
+	return B32Encoder.EncodeToString(buf[:])
28
 }
29
 }
29
 
30
 
30
 // securely check if a supplied token matches a stored token
31
 // securely check if a supplied token matches a stored token
37
 
38
 
38
 	return subtle.ConstantTimeCompare([]byte(storedToken), []byte(suppliedToken)) == 1
39
 	return subtle.ConstantTimeCompare([]byte(storedToken), []byte(suppliedToken)) == 1
39
 }
40
 }
41
+
42
+// generate a 256-bit secret key that can be written into a config file
43
+func GenerateSecretKey() string {
44
+	var buf [32]byte
45
+	rand.Read(buf[:])
46
+	return base64.RawURLEncoding.EncodeToString(buf[:])
47
+}

+ 6
- 1
oragono.go Vedi File

17
 	"github.com/oragono/oragono/irc"
17
 	"github.com/oragono/oragono/irc"
18
 	"github.com/oragono/oragono/irc/logger"
18
 	"github.com/oragono/oragono/irc/logger"
19
 	"github.com/oragono/oragono/irc/mkcerts"
19
 	"github.com/oragono/oragono/irc/mkcerts"
20
+	"github.com/oragono/oragono/irc/utils"
20
 	"golang.org/x/crypto/bcrypt"
21
 	"golang.org/x/crypto/bcrypt"
21
 	"golang.org/x/crypto/ssh/terminal"
22
 	"golang.org/x/crypto/ssh/terminal"
22
 )
23
 )
46
 	oragono upgradedb [--conf <filename>] [--quiet]
47
 	oragono upgradedb [--conf <filename>] [--quiet]
47
 	oragono genpasswd [--conf <filename>] [--quiet]
48
 	oragono genpasswd [--conf <filename>] [--quiet]
48
 	oragono mkcerts [--conf <filename>] [--quiet]
49
 	oragono mkcerts [--conf <filename>] [--quiet]
50
+	oragono mksecret [--conf <filename>] [--quiet]
49
 	oragono run [--conf <filename>] [--quiet]
51
 	oragono run [--conf <filename>] [--quiet]
50
 	oragono -h | --help
52
 	oragono -h | --help
51
 	oragono --version
53
 	oragono --version
57
 
59
 
58
 	arguments, _ := docopt.ParseArgs(usage, nil, version)
60
 	arguments, _ := docopt.ParseArgs(usage, nil, version)
59
 
61
 
60
-	// don't require a config file for genpasswd
62
+	// don't require a config file for genpasswd or mksecret
61
 	if arguments["genpasswd"].(bool) {
63
 	if arguments["genpasswd"].(bool) {
62
 		var password string
64
 		var password string
63
 		fd := int(os.Stdin.Fd())
65
 		fd := int(os.Stdin.Fd())
83
 			fmt.Println()
85
 			fmt.Println()
84
 		}
86
 		}
85
 		return
87
 		return
88
+	} else if arguments["mksecret"].(bool) {
89
+		fmt.Println(utils.GenerateSecretKey())
90
+		return
86
 	}
91
 	}
87
 
92
 
88
 	configfile := arguments["--conf"].(string)
93
 	configfile := arguments["--conf"].(string)

+ 38
- 0
oragono.yaml Vedi File

188
             # - "192.168.1.1"
188
             # - "192.168.1.1"
189
             # - "2001:0db8::/32"
189
             # - "2001:0db8::/32"
190
 
190
 
191
+    # IP cloaking hides users' IP addresses from other users and from channel admins
192
+    # (but not from server admins), while still allowing channel admins to ban
193
+    # offending IP addresses or networks. In place of hostnames derived from reverse
194
+    # DNS, users see fake domain names like pwbs2ui4377257x8.oragono. These names are
195
+    # generated deterministically from the underlying IP address, but if the underlying
196
+    # IP is not already known, it is infeasible to recover it from the cloaked name.
197
+    ip-cloaking:
198
+        # whether to enable IP cloaking
199
+        enabled: false
200
+
201
+        # fake TLD at the end of the hostname, e.g., pwbs2ui4377257x8.oragono
202
+        netname: "oragono"
203
+
204
+        # secret key to prevent dictionary attacks against cloaked IPs
205
+        # any high-entropy secret is valid for this purpose:
206
+        # you MUST generate a new one for your installation.
207
+        # suggestion: use the output of `oragono mksecret`
208
+        # note that rotating this key will invalidate all existing ban masks.
209
+        secret: "siaELnk6Kaeo65K3RCrwJjlWaZ-Bt3WuZ2L8MXLbNb4"
210
+
211
+        # the cloaked hostname is derived only from the CIDR (most significant bits
212
+        # of the IP address), up to a configurable number of bits. this is the
213
+        # granularity at which bans will take effect for ipv4 (a /32 is a fully
214
+        # specified IP address). note that changing this value will invalidate
215
+        # any stored bans.
216
+        cidr-len-ipv4: 32
217
+
218
+        # analogous value for ipv6 (an ipv6 /64 is the typical prefix assigned
219
+        # by an ISP to an individual customer for their LAN)
220
+        cidr-len-ipv6: 64
221
+
222
+        # number of bits of hash output to include in the cloaked hostname.
223
+        # more bits means less likelihood of distinct IPs colliding,
224
+        # at the cost of a longer cloaked hostname. if this value is set to 0,
225
+        # all users will receive simply `netname` as their cloaked hostname.
226
+        num-bits: 80
227
+
228
+
191
 # account options
229
 # account options
192
 accounts:
230
 accounts:
193
     # account registration
231
     # account registration

Loading…
Annulla
Salva