header.go 4.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116
  1. // Package proxyproto implements Proxy Protocol (v1 and v2) parser and writer, as per specification:
  2. // http://www.haproxy.org/download/1.5/doc/proxy-protocol.txt
  3. package proxyproto
  4. import (
  5. "bufio"
  6. "bytes"
  7. "errors"
  8. "io"
  9. "net"
  10. "time"
  11. )
  12. var (
  13. // Protocol
  14. SIGV1 = []byte{'\x50', '\x52', '\x4F', '\x58', '\x59'}
  15. SIGV2 = []byte{'\x0D', '\x0A', '\x0D', '\x0A', '\x00', '\x0D', '\x0A', '\x51', '\x55', '\x49', '\x54', '\x0A'}
  16. ErrCantReadProtocolVersionAndCommand = errors.New("Can't read proxy protocol version and command")
  17. ErrCantReadAddressFamilyAndProtocol = errors.New("Can't read address family or protocol")
  18. ErrCantReadLength = errors.New("Can't read length")
  19. ErrCantResolveSourceUnixAddress = errors.New("Can't resolve source Unix address")
  20. ErrCantResolveDestinationUnixAddress = errors.New("Can't resolve destination Unix address")
  21. ErrNoProxyProtocol = errors.New("Proxy protocol signature not present")
  22. ErrUnknownProxyProtocolVersion = errors.New("Unknown proxy protocol version")
  23. ErrUnsupportedProtocolVersionAndCommand = errors.New("Unsupported proxy protocol version and command")
  24. ErrUnsupportedAddressFamilyAndProtocol = errors.New("Unsupported address family and protocol")
  25. ErrInvalidLength = errors.New("Invalid length")
  26. ErrInvalidAddress = errors.New("Invalid address")
  27. ErrInvalidPortNumber = errors.New("Invalid port number")
  28. )
  29. // Header is the placeholder for proxy protocol header.
  30. type Header struct {
  31. Version byte
  32. Command ProtocolVersionAndCommand
  33. TransportProtocol AddressFamilyAndProtocol
  34. SourceAddress net.IP
  35. DestinationAddress net.IP
  36. SourcePort uint16
  37. DestinationPort uint16
  38. }
  39. // EqualTo returns true if headers are equivalent, false otherwise.
  40. func (header *Header) EqualTo(q *Header) bool {
  41. if header == nil || q == nil {
  42. return false
  43. }
  44. if header.Command.IsLocal() {
  45. return true
  46. }
  47. return header.TransportProtocol == q.TransportProtocol &&
  48. header.SourceAddress.String() == q.SourceAddress.String() &&
  49. header.DestinationAddress.String() == q.DestinationAddress.String() &&
  50. header.SourcePort == q.SourcePort &&
  51. header.DestinationPort == q.DestinationPort
  52. }
  53. // WriteTo renders a proxy protocol header in a format to write over the wire.
  54. func (header *Header) WriteTo(w io.Writer) (int64, error) {
  55. switch header.Version {
  56. case 1:
  57. return header.writeVersion1(w)
  58. case 2:
  59. return header.writeVersion2(w)
  60. default:
  61. return 0, ErrUnknownProxyProtocolVersion
  62. }
  63. }
  64. // Read identifies the proxy protocol version and reads the remaining of
  65. // the header, accordingly.
  66. //
  67. // If proxy protocol header signature is not present, the reader buffer remains untouched
  68. // and is safe for reading outside of this code.
  69. //
  70. // If proxy protocol header signature is present but an error is raised while processing
  71. // the remaining header, assume the reader buffer to be in a corrupt state.
  72. // Also, this operation will block until enough bytes are available for peeking.
  73. func Read(reader *bufio.Reader) (*Header, error) {
  74. // In order to improve speed for small non-PROXYed packets, take a peek at the first byte alone.
  75. if b1, err := reader.Peek(1); err == nil && (bytes.Equal(b1[:1], SIGV1[:1]) || bytes.Equal(b1[:1], SIGV2[:1])) {
  76. if signature, err := reader.Peek(5); err == nil && bytes.Equal(signature[:5], SIGV1) {
  77. return parseVersion1(reader)
  78. } else if signature, err := reader.Peek(12); err == nil && bytes.Equal(signature[:12], SIGV2) {
  79. return parseVersion2(reader)
  80. }
  81. }
  82. return nil, ErrNoProxyProtocol
  83. }
  84. // ReadTimeout acts as Read but takes a timeout. If that timeout is reached, it's assumed
  85. // there's no proxy protocol header.
  86. func ReadTimeout(reader *bufio.Reader, timeout time.Duration) (*Header, error) {
  87. type header struct {
  88. h *Header
  89. e error
  90. }
  91. read := make(chan *header, 1)
  92. go func() {
  93. h := &header{}
  94. h.h, h.e = Read(reader)
  95. read <- h
  96. }()
  97. timer := time.NewTimer(timeout)
  98. select {
  99. case result := <-read:
  100. timer.Stop()
  101. return result.h, result.e
  102. case <-timer.C:
  103. return nil, ErrNoProxyProtocol
  104. }
  105. }