Bladeren bron

support unix domain sockets

tags/v0.11.0-beta
Shivaram Lingamneni 6 jaren geleden
bovenliggende
commit
2a7f055ef3
5 gewijzigde bestanden met toevoegingen van 91 en 40 verwijderingen
  1. 11
    11
      irc/client.go
  2. 31
    11
      irc/gateways.go
  3. 26
    14
      irc/server.go
  4. 18
    3
      irc/utils/net.go
  5. 5
    1
      oragono.yaml

+ 11
- 11
irc/client.go Bestand weergeven

@@ -33,6 +33,7 @@ const (
33 33
 var (
34 34
 	// ErrNickAlreadySet is a weird error that's sent when the server's consistency has been compromised.
35 35
 	ErrNickAlreadySet = errors.New("Nickname is already set")
36
+	LoopbackIP        = net.ParseIP("127.0.0.1")
36 37
 )
37 38
 
38 39
 // Client is an IRC client.
@@ -64,7 +65,7 @@ type Client struct {
64 65
 	nickMaskCasefolded string
65 66
 	nickMaskString     string // cache for nickmask string since it's used with lots of replies
66 67
 	operName           string
67
-	proxiedIP          string // actual remote IP if using the PROXY protocol
68
+	proxiedIP          net.IP // actual remote IP if using the PROXY protocol
68 69
 	quitMessage        string
69 70
 	rawHostname        string
70 71
 	realname           string
@@ -111,7 +112,7 @@ func NewClient(server *Server, conn net.Conn, isTLS bool) *Client {
111 112
 		// error is not useful to us here anyways so we can ignore it
112 113
 		client.certfp, _ = client.socket.CertFP()
113 114
 	}
114
-	if server.checkIdent {
115
+	if server.checkIdent && !utils.AddrIsUnix(conn.RemoteAddr()) {
115 116
 		_, serverPortString, err := net.SplitHostPort(conn.LocalAddr().String())
116 117
 		serverPort, _ := strconv.Atoi(serverPortString)
117 118
 		if err != nil {
@@ -146,19 +147,18 @@ func NewClient(server *Server, conn net.Conn, isTLS bool) *Client {
146 147
 
147 148
 // IP returns the IP address of this client.
148 149
 func (client *Client) IP() net.IP {
149
-	if client.proxiedIP != "" {
150
-		return net.ParseIP(client.proxiedIP)
150
+	if client.proxiedIP != nil {
151
+		return client.proxiedIP
151 152
 	}
152
-
153
-	return net.ParseIP(utils.IPString(client.socket.conn.RemoteAddr()))
153
+	if ip := utils.AddrToIP(client.socket.conn.RemoteAddr()); ip != nil {
154
+		return ip
155
+	}
156
+	// unix domain socket that hasn't issued PROXY/WEBIRC yet. YOLO
157
+	return LoopbackIP
154 158
 }
155 159
 
156 160
 // IPString returns the IP address of this client as a string.
157 161
 func (client *Client) IPString() string {
158
-	if client.proxiedIP != "" {
159
-		return client.proxiedIP
160
-	}
161
-
162 162
 	ip := client.IP().String()
163 163
 	if 0 < len(ip) && ip[0] == ':' {
164 164
 		ip = "0" + ip
@@ -581,7 +581,7 @@ func (client *Client) AllNickmasks() []string {
581 581
 		masks = append(masks, mask)
582 582
 	}
583 583
 
584
-	mask2, err := Casefold(fmt.Sprintf("%s!%s@%s", client.nick, client.username, utils.IPString(client.socket.conn.RemoteAddr())))
584
+	mask2, err := Casefold(fmt.Sprintf("%s!%s@%s", client.nick, client.username, client.IPString()))
585 585
 	if err == nil && mask2 != mask {
586 586
 		masks = append(masks, mask2)
587 587
 	}

+ 31
- 11
irc/gateways.go Bestand weergeven

@@ -38,10 +38,34 @@ func (wc *webircConfig) Populate() (err error) {
38 38
 	return err
39 39
 }
40 40
 
41
+func isGatewayAllowed(addr net.Addr, gatewaySpec string) bool {
42
+	// "localhost" includes any loopback IP or unix domain socket
43
+	if gatewaySpec == "localhost" {
44
+		return utils.AddrIsLocal(addr)
45
+	}
46
+
47
+	ip := utils.AddrToIP(addr)
48
+	if ip == nil {
49
+		return false
50
+	}
51
+
52
+	// exact IP match
53
+	if ip.String() == gatewaySpec {
54
+		return true
55
+	}
56
+
57
+	// CIDR match
58
+	_, gatewayNet, err := net.ParseCIDR(gatewaySpec)
59
+	if err != nil {
60
+		return false
61
+	}
62
+	return gatewayNet.Contains(ip)
63
+}
64
+
41 65
 // WEBIRC <password> <gateway> <hostname> <ip> [:flag1 flag2=x flag3]
42 66
 func webircHandler(server *Server, client *Client, msg ircmsg.IrcMessage) bool {
43 67
 	// only allow unregistered clients to use this command
44
-	if client.registered || client.proxiedIP != "" {
68
+	if client.registered || client.proxiedIP != nil {
45 69
 		return false
46 70
 	}
47 71
 
@@ -68,11 +92,9 @@ func webircHandler(server *Server, client *Client, msg ircmsg.IrcMessage) bool {
68 92
 		}
69 93
 	}
70 94
 
71
-	clientAddress := utils.IPString(client.socket.conn.RemoteAddr())
72
-	clientHostname := client.hostname
73 95
 	for _, info := range server.WebIRCConfig() {
74
-		for _, address := range info.Hosts {
75
-			if clientHostname == address || clientAddress == address {
96
+		for _, gateway := range info.Hosts {
97
+			if isGatewayAllowed(client.socket.conn.RemoteAddr(), gateway) {
76 98
 				// confirm password and/or fingerprint
77 99
 				givenPassword := msg.Params[0]
78 100
 				if 0 < len(info.Password) && passwd.ComparePasswordString(info.Password, givenPassword) != nil {
@@ -96,14 +118,12 @@ func webircHandler(server *Server, client *Client, msg ircmsg.IrcMessage) bool {
96 118
 // http://www.haproxy.org/download/1.8/doc/proxy-protocol.txt
97 119
 func proxyHandler(server *Server, client *Client, msg ircmsg.IrcMessage) bool {
98 120
 	// only allow unregistered clients to use this command
99
-	if client.registered || client.proxiedIP != "" {
121
+	if client.registered || client.proxiedIP != nil {
100 122
 		return false
101 123
 	}
102 124
 
103
-	clientAddress := utils.IPString(client.socket.conn.RemoteAddr())
104
-	clientHostname := client.hostname
105
-	for _, address := range server.ProxyAllowedFrom() {
106
-		if clientHostname == address || clientAddress == address {
125
+	for _, gateway := range server.ProxyAllowedFrom() {
126
+		if isGatewayAllowed(client.socket.conn.RemoteAddr(), gateway) {
107 127
 			proxiedIP := msg.Params[1]
108 128
 
109 129
 			// assume PROXY connections are always secure
@@ -130,7 +150,7 @@ func (client *Client) ApplyProxiedIP(proxiedIP string, tls bool) (exiting bool)
130 150
 	}
131 151
 
132 152
 	// given IP is sane! override the client's current IP
133
-	client.proxiedIP = proxiedIP
153
+	client.proxiedIP = parsedProxiedIP
134 154
 	client.rawHostname = utils.LookupHostname(proxiedIP)
135 155
 	client.hostname = client.rawHostname
136 156
 

+ 26
- 14
irc/server.go Bestand weergeven

@@ -267,19 +267,15 @@ func (server *Server) Run() {
267 267
 
268 268
 func (server *Server) acceptClient(conn clientConn) {
269 269
 	// check IP address
270
-	ipaddr := net.ParseIP(utils.IPString(conn.Conn.RemoteAddr()))
271
-	if ipaddr == nil {
272
-		conn.Conn.Write([]byte(couldNotParseIPMsg))
273
-		conn.Conn.Close()
274
-		return
275
-	}
276
-
277
-	isBanned, banMsg := server.checkBans(ipaddr)
278
-	if isBanned {
279
-		// this might not show up properly on some clients, but our objective here is just to close the connection out before it has a load impact on us
280
-		conn.Conn.Write([]byte(fmt.Sprintf(errorMsg, banMsg)))
281
-		conn.Conn.Close()
282
-		return
270
+	ipaddr := utils.AddrToIP(conn.Conn.RemoteAddr())
271
+	if ipaddr != nil {
272
+		isBanned, banMsg := server.checkBans(ipaddr)
273
+		if isBanned {
274
+			// this might not show up properly on some clients, but our objective here is just to close the connection out before it has a load impact on us
275
+			conn.Conn.Write([]byte(fmt.Sprintf(errorMsg, banMsg)))
276
+			conn.Conn.Close()
277
+			return
278
+		}
283 279
 	}
284 280
 
285 281
 	server.logger.Debug("localconnect-ip", fmt.Sprintf("Client connecting from %v", ipaddr))
@@ -336,7 +332,23 @@ func (server *Server) checkBans(ipaddr net.IP) (banned bool, message string) {
336 332
 // createListener starts the given listeners.
337 333
 func (server *Server) createListener(addr string, tlsConfig *tls.Config) *ListenerWrapper {
338 334
 	// make listener
339
-	listener, err := net.Listen("tcp", addr)
335
+	var listener net.Listener
336
+	var err error
337
+	optional_unix_prefix := "unix:"
338
+	optional_prefix_len := len(optional_unix_prefix)
339
+	if len(addr) >= optional_prefix_len && strings.ToLower(addr[0:optional_prefix_len]) == optional_unix_prefix {
340
+		addr = addr[optional_prefix_len:]
341
+		if len(addr) == 0 || addr[0] != '/' {
342
+			log.Fatal("Bad unix socket address", addr)
343
+		}
344
+	}
345
+	if len(addr) > 0 && addr[0] == '/' {
346
+		// https://stackoverflow.com/a/34881585
347
+		os.Remove(addr)
348
+		listener, err = net.Listen("unix", addr)
349
+	} else {
350
+		listener, err = net.Listen("tcp", addr)
351
+	}
340 352
 	if err != nil {
341 353
 		log.Fatal(server, "listen error: ", err)
342 354
 	}

+ 18
- 3
irc/utils/net.go Bestand weergeven

@@ -22,6 +22,9 @@ func IPString(addr net.Addr) string {
22 22
 
23 23
 // AddrLookupHostname returns the hostname (if possible) or address for the given `net.Addr`.
24 24
 func AddrLookupHostname(addr net.Addr) string {
25
+	if AddrIsUnix(addr) {
26
+		return "localhost"
27
+	}
25 28
 	return LookupHostname(IPString(addr))
26 29
 }
27 30
 
@@ -30,10 +33,22 @@ func AddrIsLocal(addr net.Addr) bool {
30 33
 	if tcpaddr, ok := addr.(*net.TCPAddr); ok {
31 34
 		return tcpaddr.IP.IsLoopback()
32 35
 	}
33
-	if _, ok := addr.(*net.UnixAddr); ok {
34
-		return true
36
+	_, ok := addr.(*net.UnixAddr)
37
+	return ok
38
+}
39
+
40
+// AddrToIP returns the IP address for a net.Addr, or nil if it's a unix domain socket.
41
+func AddrToIP(addr net.Addr) net.IP {
42
+	if tcpaddr, ok := addr.(*net.TCPAddr); ok {
43
+		return tcpaddr.IP
35 44
 	}
36
-	return false
45
+	return nil
46
+}
47
+
48
+// AddrIsUnix returns whether the address is a unix domain socket.
49
+func AddrIsUnix(addr net.Addr) bool {
50
+	_, ok := addr.(*net.UnixAddr)
51
+	return ok
37 52
 }
38 53
 
39 54
 // LookupHostname returns the hostname for `addr` if it has one. Otherwise, just returns `addr`.

+ 5
- 1
oragono.yaml Bestand weergeven

@@ -16,6 +16,8 @@ server:
16 16
         - "127.0.0.1:6668"
17 17
         - "[::1]:6668"
18 18
         - ":6697" # ssl port
19
+        # unix domain socket for proxying:
20
+        # - "/tmp/oragono_sock"
19 21
 
20 22
     # tls listeners
21 23
     tls-listeners:
@@ -59,11 +61,12 @@ server:
59 61
     #motd-formatting: true
60 62
 
61 63
     # addresses/hostnames the PROXY command can be used from
62
-    # this should be restricted to 127.0.0.1 and localhost at most
64
+    # this should be restricted to 127.0.0.1/8 and localhost at most
63 65
     # you should also add these addresses to the connection limits and throttling exemption lists
64 66
     proxy-allowed-from:
65 67
         # - localhost
66 68
         # - "127.0.0.1"
69
+        # - "127.0.0.1/8"
67 70
 
68 71
     # controls the use of the WEBIRC command (by IRC<->web interfaces, bouncers and similar)
69 72
     webirc:
@@ -79,6 +82,7 @@ server:
79 82
             hosts:
80 83
                 # - localhost
81 84
                 # - "127.0.0.1"
85
+                # - "127.0.0.1/8"
82 86
                 # - "0::1"
83 87
 
84 88
     # maximum length of clients' sendQ in bytes

Laden…
Annuleren
Opslaan