You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298
  1. // Copyright (c) 2020 Shivaram Lingamneni <slingamn@cs.stanford.edu>
  2. // released under the MIT license
  3. package utils
  4. import (
  5. "crypto/tls"
  6. "encoding/binary"
  7. "io"
  8. "net"
  9. "strings"
  10. "sync/atomic"
  11. "time"
  12. )
  13. const (
  14. // https://www.haproxy.org/download/1.8/doc/proxy-protocol.txt
  15. // "a 108-byte buffer is always enough to store all the line and a trailing zero
  16. // for string processing."
  17. maxProxyLineLenV1 = 107
  18. )
  19. // XXX implement net.Error with a Temporary() method that returns true;
  20. // otherwise, ErrBadProxyLine will cause (*http.Server).Serve() to exit
  21. type proxyLineError struct{}
  22. func (p *proxyLineError) Error() string {
  23. return "invalid PROXY line"
  24. }
  25. func (p *proxyLineError) Timeout() bool {
  26. return false
  27. }
  28. func (p *proxyLineError) Temporary() bool {
  29. return true
  30. }
  31. var (
  32. ErrBadProxyLine error = &proxyLineError{}
  33. )
  34. // ListenerConfig is all the information about how to process
  35. // incoming IRC connections on a listener.
  36. type ListenerConfig struct {
  37. TLSConfig *tls.Config
  38. ProxyDeadline time.Duration
  39. RequireProxy bool
  40. // these are just metadata for easier tracking,
  41. // they are not used by ReloadableListener:
  42. Tor bool
  43. STSOnly bool
  44. WebSocket bool
  45. HideSTS bool
  46. }
  47. // read a PROXY header (either v1 or v2), ensuring we don't read anything beyond
  48. // the header into a buffer (this would break the TLS handshake)
  49. func readRawProxyLine(conn net.Conn, deadline time.Duration) (result []byte, err error) {
  50. // normally this is covered by ping timeouts, but we're doing this outside
  51. // of the normal client goroutine:
  52. conn.SetDeadline(time.Now().Add(deadline))
  53. defer conn.SetDeadline(time.Time{})
  54. // read the first 16 bytes of the proxy header
  55. buf := make([]byte, 16, maxProxyLineLenV1)
  56. _, err = io.ReadFull(conn, buf)
  57. if err != nil {
  58. return
  59. }
  60. switch buf[0] {
  61. case 'P':
  62. // PROXY v1: starts with "PROXY"
  63. return readRawProxyLineV1(conn, buf)
  64. case '\r':
  65. // PROXY v2: starts with "\r\n\r\n"
  66. return readRawProxyLineV2(conn, buf)
  67. default:
  68. return nil, ErrBadProxyLine
  69. }
  70. }
  71. func readRawProxyLineV1(conn net.Conn, buf []byte) (result []byte, err error) {
  72. for {
  73. i := len(buf)
  74. if i >= maxProxyLineLenV1 {
  75. return nil, ErrBadProxyLine // did not find \r\n, fail
  76. }
  77. // prepare a single byte of free space, then read into it
  78. buf = buf[0 : i+1]
  79. _, err = io.ReadFull(conn, buf[i:])
  80. if err != nil {
  81. return nil, err
  82. }
  83. if buf[i] == '\n' {
  84. return buf, nil
  85. }
  86. }
  87. }
  88. func readRawProxyLineV2(conn net.Conn, buf []byte) (result []byte, err error) {
  89. // "The 15th and 16th bytes is the address length in bytes in network endian order."
  90. addrLen := int(binary.BigEndian.Uint16(buf[14:16]))
  91. if addrLen == 0 {
  92. return buf[0:16], nil
  93. } else if addrLen <= cap(buf)-16 {
  94. buf = buf[0 : 16+addrLen]
  95. } else {
  96. // proxy source is unix domain, we don't really handle this
  97. buf2 := make([]byte, 16+addrLen)
  98. copy(buf2[0:16], buf[0:16])
  99. buf = buf2
  100. }
  101. _, err = io.ReadFull(conn, buf[16:16+addrLen])
  102. if err != nil {
  103. return
  104. }
  105. return buf[0 : 16+addrLen], nil
  106. }
  107. // ParseProxyLine parses a PROXY protocol (v1 or v2) line and returns the remote IP.
  108. func ParseProxyLine(line []byte) (ip net.IP, err error) {
  109. if len(line) == 0 {
  110. return nil, ErrBadProxyLine
  111. }
  112. switch line[0] {
  113. case 'P':
  114. return ParseProxyLineV1(string(line))
  115. case '\r':
  116. return parseProxyLineV2(line)
  117. default:
  118. return nil, ErrBadProxyLine
  119. }
  120. }
  121. // ParseProxyLineV1 parses a PROXY protocol (v1) line and returns the remote IP.
  122. func ParseProxyLineV1(line string) (ip net.IP, err error) {
  123. params := strings.Fields(line)
  124. if len(params) != 6 || params[0] != "PROXY" {
  125. return nil, ErrBadProxyLine
  126. }
  127. ip = net.ParseIP(params[2])
  128. if ip == nil {
  129. return nil, ErrBadProxyLine
  130. }
  131. return ip.To16(), nil
  132. }
  133. func parseProxyLineV2(line []byte) (ip net.IP, err error) {
  134. if len(line) < 16 {
  135. return nil, ErrBadProxyLine
  136. }
  137. // this doesn't allocate
  138. if string(line[:12]) != "\x0d\x0a\x0d\x0a\x00\x0d\x0a\x51\x55\x49\x54\x0a" {
  139. return nil, ErrBadProxyLine
  140. }
  141. // "The next byte (the 13th one) is the protocol version and command."
  142. versionCmd := line[12]
  143. // "The highest four bits contains the version [....] it must always be sent as \x2"
  144. if (versionCmd >> 4) != 2 {
  145. return nil, ErrBadProxyLine
  146. }
  147. // "The lowest four bits represents the command"
  148. switch versionCmd & 0x0f {
  149. case 0:
  150. return nil, nil // LOCAL command
  151. case 1:
  152. // PROXY command, continue below
  153. default:
  154. // "Receivers must drop connections presenting unexpected values here"
  155. return nil, ErrBadProxyLine
  156. }
  157. var addrLen int
  158. // "The 14th byte contains the transport protocol and address family."
  159. protoAddr := line[13]
  160. // "The highest 4 bits contain the address family"
  161. switch protoAddr >> 4 {
  162. case 1:
  163. addrLen = 4 // AF_INET
  164. case 2:
  165. addrLen = 16 // AF_INET6
  166. default:
  167. return nil, nil // AF_UNSPEC or AF_UNIX, either way there's no IP address
  168. }
  169. // header, source and destination address, two 16-bit port numbers:
  170. expectedLen := 16 + 2*addrLen + 4
  171. if len(line) < expectedLen {
  172. return nil, ErrBadProxyLine
  173. }
  174. // "Starting from the 17th byte, addresses are presented in network byte order.
  175. // The address order is always the same :
  176. // - source layer 3 address in network byte order [...]"
  177. if addrLen == 4 {
  178. ip = net.IP(line[16 : 16+addrLen]).To16()
  179. } else {
  180. ip = make(net.IP, addrLen)
  181. copy(ip, line[16:16+addrLen])
  182. }
  183. return ip, nil
  184. }
  185. // / WrappedConn is a net.Conn with some additional data stapled to it;
  186. // the proxied IP, if one was read via the PROXY protocol, and the listener
  187. // configuration.
  188. type WrappedConn struct {
  189. net.Conn
  190. ProxiedIP net.IP
  191. TLS bool
  192. Tor bool
  193. STSOnly bool
  194. WebSocket bool
  195. HideSTS bool
  196. // Secure indicates whether we believe the connection between us and the client
  197. // was secure against interception and modification (including all proxies):
  198. Secure bool
  199. }
  200. // ReloadableListener is a wrapper for net.Listener that allows reloading
  201. // of config data for postprocessing connections (TLS, PROXY protocol, etc.)
  202. type ReloadableListener struct {
  203. realListener net.Listener
  204. // nil means the listener is closed:
  205. config atomic.Pointer[ListenerConfig]
  206. }
  207. func NewReloadableListener(realListener net.Listener, config ListenerConfig) *ReloadableListener {
  208. result := &ReloadableListener{
  209. realListener: realListener,
  210. }
  211. result.config.Store(&config) // heap escape
  212. return result
  213. }
  214. func (rl *ReloadableListener) Reload(config ListenerConfig) {
  215. rl.config.Store(&config)
  216. }
  217. func (rl *ReloadableListener) Accept() (conn net.Conn, err error) {
  218. conn, err = rl.realListener.Accept()
  219. config := rl.config.Load()
  220. if config == nil {
  221. // Close() was called
  222. if err == nil {
  223. conn.Close()
  224. }
  225. err = net.ErrClosed
  226. }
  227. if err != nil {
  228. return nil, err
  229. }
  230. var proxiedIP net.IP
  231. if config.RequireProxy {
  232. // this will occur synchronously on the goroutine calling Accept(),
  233. // but that's OK because this listener *requires* a PROXY line,
  234. // therefore it must be used with proxies that always send the line
  235. // and we won't get slowloris'ed waiting for the client response
  236. proxyLine, err := readRawProxyLine(conn, config.ProxyDeadline)
  237. if err == nil {
  238. proxiedIP, err = ParseProxyLine(proxyLine)
  239. }
  240. if err != nil {
  241. conn.Close()
  242. return nil, err
  243. }
  244. }
  245. if config.TLSConfig != nil {
  246. conn = tls.Server(conn, config.TLSConfig)
  247. }
  248. return &WrappedConn{
  249. Conn: conn,
  250. ProxiedIP: proxiedIP,
  251. TLS: config.TLSConfig != nil,
  252. Tor: config.Tor,
  253. STSOnly: config.STSOnly,
  254. WebSocket: config.WebSocket,
  255. HideSTS: config.HideSTS,
  256. // Secure will be set later by client code
  257. }, nil
  258. }
  259. func (rl *ReloadableListener) Close() error {
  260. rl.config.Store(nil)
  261. return rl.realListener.Close()
  262. }
  263. func (rl *ReloadableListener) Addr() net.Addr {
  264. return rl.realListener.Addr()
  265. }