-
Notifications
You must be signed in to change notification settings - Fork 0
/
proxyprotocol.go
154 lines (134 loc) · 4.71 KB
/
proxyprotocol.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
// Copyright 2019 Path Network, Inc. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package main
import (
"bytes"
"encoding/binary"
"fmt"
"net"
"strings"
)
type PROXYProtocolInfo struct {
SourceAddr net.Addr
DestinationAddr net.Addr
}
func readRemoteAddrPROXYv2(ctrlBuf []byte, protocol Protocol) (net.Addr, net.Addr, []byte, error) {
if (ctrlBuf[12] >> 4) != 2 {
return nil, nil, nil, fmt.Errorf("unknown protocol version %d", ctrlBuf[12]>>4)
}
if ctrlBuf[12]&0xF > 1 {
return nil, nil, nil, fmt.Errorf("unknown command %d", ctrlBuf[12]&0xF)
}
if ctrlBuf[12]&0xF == 1 && ((protocol == TCP && ctrlBuf[13] != 0x11 && ctrlBuf[13] != 0x21) ||
(protocol == UDP && ctrlBuf[13] != 0x12 && ctrlBuf[13] != 0x22)) {
return nil, nil, nil, fmt.Errorf("invalid family/protocol %d/%d", ctrlBuf[13]>>4, ctrlBuf[13]&0xF)
}
var dataLen uint16
reader := bytes.NewReader(ctrlBuf[14:16])
if err := binary.Read(reader, binary.BigEndian, &dataLen); err != nil {
return nil, nil, nil, fmt.Errorf("failed to decode address data length: %s", err.Error())
}
if len(ctrlBuf) < 16+int(dataLen) {
return nil, nil, nil, fmt.Errorf("incomplete PROXY header")
}
if ctrlBuf[12]&0xF == 0 { // LOCAL
return nil, nil, ctrlBuf[16+dataLen:], nil
}
var sport, dport uint16
if ctrlBuf[13]>>4 == 0x1 { // IPv4
reader = bytes.NewReader(ctrlBuf[24:])
} else {
reader = bytes.NewReader(ctrlBuf[48:])
}
if err := binary.Read(reader, binary.BigEndian, &sport); err != nil {
return nil, nil, nil, fmt.Errorf("failed to decode source port: %s", err.Error())
}
if err := binary.Read(reader, binary.BigEndian, &dport); err != nil {
return nil, nil, nil, fmt.Errorf("failed to decode destination port: %s", err.Error())
}
var srcIP, dstIP net.IP
if ctrlBuf[13]>>4 == 0x1 { // IPv4
srcIP = net.IPv4(ctrlBuf[16], ctrlBuf[17], ctrlBuf[18], ctrlBuf[19])
dstIP = net.IPv4(ctrlBuf[20], ctrlBuf[21], ctrlBuf[22], ctrlBuf[23])
} else {
srcIP = ctrlBuf[16:32]
dstIP = ctrlBuf[32:48]
}
if ctrlBuf[13]&0xF == 0x1 { // TCP
return &net.TCPAddr{IP: srcIP, Port: int(sport)},
&net.TCPAddr{IP: dstIP, Port: int(dport)},
ctrlBuf[16+dataLen:], nil
}
return &net.UDPAddr{IP: srcIP, Port: int(sport)},
&net.UDPAddr{IP: dstIP, Port: int(dport)},
ctrlBuf[16+dataLen:], nil
}
func readRemoteAddrPROXYv1(ctrlBuf []byte) (net.Addr, net.Addr, []byte, error) {
str := string(ctrlBuf)
if idx := strings.Index(str, "\r\n"); idx >= 0 {
var headerProtocol, src, dst string
var sport, dport int
n, err := fmt.Sscanf(str, "PROXY %s", &headerProtocol)
if err != nil {
return nil, nil, nil, err
}
if n != 1 {
return nil, nil, nil, fmt.Errorf("failed to decode elements")
}
if headerProtocol == "UNKNOWN" {
return nil, nil, ctrlBuf[idx+2:], nil
}
if headerProtocol != "TCP4" && headerProtocol != "TCP6" {
return nil, nil, nil, fmt.Errorf("unknown protocol %s", headerProtocol)
}
n, err = fmt.Sscanf(str, "PROXY %s %s %s %d %d", &headerProtocol, &src, &dst, &sport, &dport)
if err != nil {
return nil, nil, nil, err
}
if n != 5 {
return nil, nil, nil, fmt.Errorf("failed to decode elements")
}
srcIP := net.ParseIP(src)
if srcIP == nil {
return nil, nil, nil, fmt.Errorf("failed to parse source IP address %s", src)
}
dstIP := net.ParseIP(dst)
if dstIP == nil {
return nil, nil, nil, fmt.Errorf("failed to parse destination IP address %s", dst)
}
return &net.TCPAddr{IP: srcIP, Port: sport},
&net.TCPAddr{IP: dstIP, Port: dport},
ctrlBuf[idx+2:], nil
}
return nil, nil, nil, fmt.Errorf("did not find \\r\\n in first data segment")
}
func PROXYReadRemoteAddr(buf []byte, protocol Protocol) (net.Addr, net.Addr, []byte, error) {
if len(buf) >= 16 && bytes.Equal(buf[:12],
[]byte{0x0D, 0x0A, 0x0D, 0x0A, 0x00, 0x0D, 0x0A, 0x51, 0x55, 0x49, 0x54, 0x0A}) {
saddr, daddr, rest, err := readRemoteAddrPROXYv2(buf, protocol)
if err != nil {
return nil, nil, nil, fmt.Errorf("failed to parse PROXY v2 header: %s", err.Error())
}
return saddr, daddr, rest, err
}
// PROXYv1 only works with TCP
if protocol == TCP && len(buf) >= 8 && bytes.Equal(buf[:5], []byte("PROXY")) {
saddr, daddr, rest, err := readRemoteAddrPROXYv1(buf)
if err != nil {
return nil, nil, nil, fmt.Errorf("failed to parse PROXY v1 header: %s", err.Error())
}
return saddr, daddr, rest, err
}
return nil, nil, nil, fmt.Errorf("PROXY header missing")
}
func TryReadPROXYProtocol(buf []byte, protocol Protocol) (*PROXYProtocolInfo, []byte, error) {
saddr, daddr, restBytes, err := PROXYReadRemoteAddr(buf, protocol)
if err == nil {
return &PROXYProtocolInfo{
SourceAddr: saddr,
DestinationAddr: daddr,
}, restBytes, err
}
return nil, buf, err
}