瀏覽代碼

fix #561, take 2

tags/v2.0.0-rc1
Shivaram Lingamneni 4 年之前
父節點
當前提交
50783d5276
共有 5 個檔案被更改,包括 85 行新增18 行删除
  1. 14
    9
      irc/client.go
  2. 13
    5
      irc/config.go
  3. 43
    2
      irc/gateways.go
  4. 11
    2
      irc/server.go
  5. 4
    0
      oragono.yaml

+ 14
- 9
irc/client.go 查看文件

@@ -190,7 +190,7 @@ type ClientDetails struct {
190 190
 }
191 191
 
192 192
 // RunClient sets up a new client and runs its goroutine.
193
-func (server *Server) RunClient(conn clientConn) {
193
+func (server *Server) RunClient(conn clientConn, proxyLine string) {
194 194
 	var isBanned bool
195 195
 	var banMsg string
196 196
 	var realIP net.IP
@@ -278,7 +278,7 @@ func (server *Server) RunClient(conn clientConn) {
278 278
 	client.proxiedIP = session.proxiedIP
279 279
 
280 280
 	server.stats.Add()
281
-	client.run(session)
281
+	client.run(session, proxyLine)
282 282
 }
283 283
 
284 284
 func (client *Client) doIdentLookup(conn net.Conn) {
@@ -371,11 +371,9 @@ func (client *Client) t(originalString string) string {
371 371
 	return languageManager.Translate(client.Languages(), originalString)
372 372
 }
373 373
 
374
-//
375
-// command goroutine
376
-//
377
-
378
-func (client *Client) run(session *Session) {
374
+// main client goroutine: read lines and execute the corresponding commands
375
+// `proxyLine` is the PROXY-before-TLS line, if there was one
376
+func (client *Client) run(session *Session, proxyLine string) {
379 377
 
380 378
 	defer func() {
381 379
 		if r := recover(); r != nil {
@@ -414,7 +412,14 @@ func (client *Client) run(session *Session) {
414 412
 	for {
415 413
 		maxlenRest := session.MaxlenRest()
416 414
 
417
-		line, err := session.socket.Read()
415
+		var line string
416
+		var err error
417
+		if proxyLine == "" {
418
+			line, err = session.socket.Read()
419
+		} else {
420
+			line = proxyLine // pretend we're just now receiving the proxy-before-TLS line
421
+			proxyLine = ""
422
+		}
418 423
 		if err != nil {
419 424
 			quitMessage := "connection closed"
420 425
 			if err == errReadQ {
@@ -483,7 +488,7 @@ func (client *Client) run(session *Session) {
483 488
 			break
484 489
 		} else if session.client != client {
485 490
 			// bouncer reattach
486
-			go session.client.run(session)
491
+			go session.client.run(session, "")
487 492
 			break
488 493
 		}
489 494
 	}

+ 13
- 5
irc/config.go 查看文件

@@ -39,8 +39,9 @@ import (
39 39
 
40 40
 // TLSListenConfig defines configuration options for listening on TLS.
41 41
 type TLSListenConfig struct {
42
-	Cert string
43
-	Key  string
42
+	Cert  string
43
+	Key   string
44
+	Proxy bool
44 45
 }
45 46
 
46 47
 // This is the YAML-deserializable type of the value of the `Server.Listeners` map
@@ -53,9 +54,10 @@ type listenerConfigBlock struct {
53 54
 // listenerConfig is the config governing a particular listener (bound address),
54 55
 // in particular whether it has TLS or Tor (or both) enabled.
55 56
 type listenerConfig struct {
56
-	TLSConfig *tls.Config
57
-	IsTor     bool
58
-	IsSTSOnly bool
57
+	TLSConfig  *tls.Config
58
+	IsTor      bool
59
+	IsSTSOnly  bool
60
+	IsTLSProxy bool
59 61
 }
60 62
 
61 63
 type AccountConfig struct {
@@ -529,6 +531,7 @@ func (conf *Config) prepareListeners() (err error) {
529 531
 					return err
530 532
 				}
531 533
 				lconf.TLSConfig = tlsConfig
534
+				lconf.IsTLSProxy = block.TLS.Proxy
532 535
 			}
533 536
 			listeners[addr] = lconf
534 537
 		}
@@ -848,5 +851,10 @@ func LoadConfig(filename string) (config *Config, err error) {
848 851
 		return nil, err
849 852
 	}
850 853
 
854
+	err = config.prepareListeners()
855
+	if err != nil {
856
+		return nil, fmt.Errorf("failed to prepare listeners: %v", err)
857
+	}
858
+
851 859
 	return config, nil
852 860
 }

+ 43
- 2
irc/gateways.go 查看文件

@@ -10,6 +10,7 @@ import (
10 10
 	"fmt"
11 11
 	"net"
12 12
 	"strings"
13
+	"time"
13 14
 
14 15
 	"github.com/oragono/oragono/irc/modes"
15 16
 	"github.com/oragono/oragono/irc/utils"
@@ -20,6 +21,13 @@ var (
20 21
 	errBadProxyLine      = errors.New("Invalid PROXY/WEBIRC command")
21 22
 )
22 23
 
24
+const (
25
+	// https://www.haproxy.org/download/1.8/doc/proxy-protocol.txt
26
+	// "a 108-byte buffer is always enough to store all the line and a trailing zero
27
+	// for string processing."
28
+	maxProxyLineLen = 107
29
+)
30
+
23 31
 type webircConfig struct {
24 32
 	PasswordString string `yaml:"password"`
25 33
 	Password       []byte `yaml:"password-bytes"`
@@ -75,10 +83,10 @@ func (client *Client) ApplyProxiedIP(session *Session, proxiedIP string, tls boo
75 83
 
76 84
 	client.stateMutex.Lock()
77 85
 	defer client.stateMutex.Unlock()
78
-	session.proxiedIP = parsedProxiedIP
79 86
 	client.proxiedIP = parsedProxiedIP
80
-	session.rawHostname = rawHostname
81 87
 	client.rawHostname = rawHostname
88
+	session.proxiedIP = parsedProxiedIP
89
+	session.rawHostname = rawHostname
82 90
 	client.cloakedHostname = cloakedHostname
83 91
 	// nickmask will be updated when the client completes registration
84 92
 	// set tls info
@@ -118,3 +126,36 @@ func handleProxyCommand(server *Server, client *Client, session *Session, line s
118 126
 		return errBadGatewayAddress
119 127
 	}
120 128
 }
129
+
130
+// read a PROXY line one byte at a time, to ensure we don't read anything beyond
131
+// that into a buffer, which would break the TLS handshake
132
+func readRawProxyLine(conn net.Conn) (result string) {
133
+	// normally this is covered by ping timeouts, but we're doing this outside
134
+	// of the normal client goroutine:
135
+	conn.SetDeadline(time.Now().Add(time.Minute))
136
+	defer conn.SetDeadline(time.Time{})
137
+
138
+	var buf [maxProxyLineLen]byte
139
+	oneByte := make([]byte, 1)
140
+	i := 0
141
+	for i < maxProxyLineLen {
142
+		n, err := conn.Read(oneByte)
143
+		if err != nil {
144
+			return
145
+		} else if n == 1 {
146
+			buf[i] = oneByte[0]
147
+			if buf[i] == '\n' {
148
+				candidate := string(buf[0 : i+1])
149
+				if strings.HasPrefix(candidate, "PROXY") {
150
+					return candidate
151
+				} else {
152
+					return
153
+				}
154
+			}
155
+			i += 1
156
+		}
157
+	}
158
+
159
+	// no \r\n, fail out
160
+	return
161
+}

+ 11
- 2
irc/server.go 查看文件

@@ -307,6 +307,15 @@ func (server *Server) createListener(addr string, conf listenerConfig, bindMode
307 307
 				listener.Close()
308 308
 				return
309 309
 			} else if err == nil {
310
+				var proxyLine string
311
+				if conf.IsTLSProxy {
312
+					proxyLine = readRawProxyLine(conn)
313
+					if proxyLine == "" {
314
+						server.logger.Error("internal", "bad TLS-proxy line from", addr)
315
+						conn.Close()
316
+						continue
317
+					}
318
+				}
310 319
 				if conf.TLSConfig != nil {
311 320
 					conn = tls.Server(conn, conf.TLSConfig)
312 321
 				}
@@ -315,7 +324,7 @@ func (server *Server) createListener(addr string, conf listenerConfig, bindMode
315 324
 					Config: conf,
316 325
 				}
317 326
 				// hand off the connection
318
-				go server.RunClient(newConn)
327
+				go server.RunClient(newConn, proxyLine)
319 328
 			} else {
320 329
 				server.logger.Error("internal", "accept error", addr, err.Error())
321 330
 			}
@@ -868,7 +877,7 @@ func (server *Server) loadDatastore(config *Config) error {
868 877
 func (server *Server) setupListeners(config *Config) (err error) {
869 878
 	logListener := func(addr string, config listenerConfig) {
870 879
 		server.logger.Info("listeners",
871
-			fmt.Sprintf("now listening on %s, tls=%t, tor=%t.", addr, (config.TLSConfig != nil), config.IsTor),
880
+			fmt.Sprintf("now listening on %s, tls=%t, tlsproxy=%t, tor=%t.", addr, (config.TLSConfig != nil), config.IsTLSProxy, config.IsTor),
872 881
 		)
873 882
 	}
874 883
 

+ 4
- 0
oragono.yaml 查看文件

@@ -30,6 +30,10 @@ server:
30 30
             tls:
31 31
                 key: tls.key
32 32
                 cert: tls.crt
33
+                # 'proxy' should typically be false. It's only for Kubernetes-style load
34
+                # balancing that does not terminate TLS, but sends an initial PROXY line
35
+                # in plaintext.
36
+                proxy: false
33 37
 
34 38
         # Example of a Unix domain socket for proxying:
35 39
         # "/tmp/oragono_sock":

Loading…
取消
儲存