11#if DETWS_ENABLE_PROXY_PROTOCOL
16static const uint8_t kV2Sig[PROXY_V2_SIG_LEN] = {0x0D, 0x0A, 0x0D, 0x0A, 0x00, 0x0D,
17 0x0A, 0x51, 0x55, 0x49, 0x54, 0x0A};
19static uint16_t rd16(
const uint8_t *p)
21 return (uint16_t)(((uint16_t)p[0] << 8) | p[1]);
24static uint32_t rd32(
const uint8_t *p)
26 return ((uint32_t)p[0] << 24) | ((uint32_t)p[1] << 16) | ((uint32_t)p[2] << 8) | p[3];
30static bool parse_ipv4(
const char *s,
size_t n, uint32_t *out)
37 if (i >= n || s[i] <
'0' || s[i] >
'9')
41 while (i < n && s[i] >=
'0' && s[i] <=
'9')
43 o = o * 10 + (uint32_t)(s[i] -
'0');
45 if (++digits > 3 || o > 255)
52 if (i >= n || s[i] !=
'.')
63static bool parse_u16(
const char *s,
size_t n, uint16_t *out)
68 for (
size_t i = 0; i < n; i++)
70 if (s[i] <
'0' || s[i] >
'9')
72 v = v * 10 + (uint32_t)(s[i] -
'0');
81static bool parse_v1(
const uint8_t *buf,
size_t len, ProxyInfo *out,
size_t *consumed)
85 size_t scan = len < 108 ? len : 108;
86 for (
size_t i = 0; i + 1 < scan; i++)
87 if (buf[i] ==
'\r' && buf[i + 1] ==
'\n')
95 const char *s = (
const char *)buf;
101 while (i < crlf && ntok < 6)
103 while (i < crlf && s[i] ==
' ')
108 while (i < crlf && s[i] !=
' ')
110 tok[ntok] = s + start;
111 tlen[ntok] = i - start;
115 out->has_addr =
false;
116 out->src_addr = out->dst_addr = 0;
117 out->src_port = out->dst_port = 0;
118 *consumed = crlf + 2;
120 if (ntok == 6 && tlen[1] == 4 && memcmp(tok[1],
"TCP4", 4) == 0)
122 if (parse_ipv4(tok[2], tlen[2], &out->src_addr) && parse_ipv4(tok[3], tlen[3], &out->dst_addr) &&
123 parse_u16(tok[4], tlen[4], &out->src_port) && parse_u16(tok[5], tlen[5], &out->dst_port))
124 out->has_addr =
true;
129bool proxy_parse(
const uint8_t *buf,
size_t len, ProxyInfo *out,
size_t *consumed)
131 if (!buf || !out || !consumed)
135 if (len >= PROXY_V2_SIG_LEN && memcmp(buf, kV2Sig, PROXY_V2_SIG_LEN) == 0)
139 uint8_t ver_cmd = buf[12];
140 uint8_t fam = buf[13];
141 uint16_t addr_len = rd16(buf + 14);
142 size_t total = 16 + (size_t)addr_len;
145 if ((ver_cmd & 0xF0) != 0x20)
148 out->has_addr =
false;
149 out->src_addr = out->dst_addr = 0;
150 out->src_port = out->dst_port = 0;
151 if (ver_cmd == PROXY_V2_VER_CMD_PROXY && fam == PROXY_V2_FAM_TCP4 && addr_len >= 12)
153 out->src_addr = rd32(buf + 16);
154 out->dst_addr = rd32(buf + 20);
155 out->src_port = rd16(buf + 24);
156 out->dst_port = rd16(buf + 26);
157 out->has_addr =
true;
164 if (len >= 6 && memcmp(buf,
"PROXY ", 6) == 0)
165 return parse_v1(buf, len, out, consumed);
170size_t proxy_v1_build(
char *buf,
size_t cap, uint32_t src_addr, uint32_t dst_addr, uint16_t src_port, uint16_t dst_port)
174 int n = snprintf(buf, cap,
"PROXY TCP4 %u.%u.%u.%u %u.%u.%u.%u %u %u\r\n", (
unsigned)((src_addr >> 24) & 0xFF),
175 (
unsigned)((src_addr >> 16) & 0xFF), (
unsigned)((src_addr >> 8) & 0xFF),
176 (
unsigned)(src_addr & 0xFF), (
unsigned)((dst_addr >> 24) & 0xFF),
177 (
unsigned)((dst_addr >> 16) & 0xFF), (
unsigned)((dst_addr >> 8) & 0xFF),
178 (
unsigned)(dst_addr & 0xFF), (
unsigned)src_port, (
unsigned)dst_port);
179 if (n < 0 || (
size_t)n >= cap)
184size_t proxy_v2_build(uint8_t *buf,
size_t cap, uint32_t src_addr, uint32_t dst_addr, uint16_t src_port,
187 const size_t total = 16 + 12;
188 if (!buf || cap < total)
190 memcpy(buf, kV2Sig, PROXY_V2_SIG_LEN);
191 buf[12] = PROXY_V2_VER_CMD_PROXY;
192 buf[13] = PROXY_V2_FAM_TCP4;
195 buf[16] = (uint8_t)(src_addr >> 24);
196 buf[17] = (uint8_t)(src_addr >> 16);
197 buf[18] = (uint8_t)(src_addr >> 8);
198 buf[19] = (uint8_t)(src_addr);
199 buf[20] = (uint8_t)(dst_addr >> 24);
200 buf[21] = (uint8_t)(dst_addr >> 16);
201 buf[22] = (uint8_t)(dst_addr >> 8);
202 buf[23] = (uint8_t)(dst_addr);
203 buf[24] = (uint8_t)(src_port >> 8);
204 buf[25] = (uint8_t)(src_port);
205 buf[26] = (uint8_t)(dst_port >> 8);
206 buf[27] = (uint8_t)(dst_port);
HAProxy PROXY protocol codec (DETWS_ENABLE_PROXY_PROTOCOL) - zero-heap parser + builder for the v1 (t...