Try to read a proxy protocol header (V1 or V2). Returns 1 on success or 0 on failure. */
| 158 | |
| 159 | /* Try to read a proxy protocol header (V1 or V2). Returns 1 on success or 0 on failure. */ |
| 160 | int read_proxy_protocol_header(int fd) |
| 161 | { |
| 162 | union { |
| 163 | struct { |
| 164 | char line[108]; |
| 165 | } v1; |
| 166 | struct { |
| 167 | char sig[PROXY_V2_SIG_SIZE]; |
| 168 | char ver_cmd; |
| 169 | char fam; |
| 170 | unsigned char len[2]; |
| 171 | union { |
| 172 | struct { |
| 173 | char src_addr[4]; |
| 174 | char dst_addr[4]; |
| 175 | char src_port[2]; |
| 176 | char dst_port[2]; |
| 177 | } ip4; |
| 178 | struct { |
| 179 | char src_addr[16]; |
| 180 | char dst_addr[16]; |
| 181 | char src_port[2]; |
| 182 | char dst_port[2]; |
| 183 | } ip6; |
| 184 | struct { |
| 185 | char src_addr[108]; |
| 186 | char dst_addr[108]; |
| 187 | } unx; |
| 188 | } addr; |
| 189 | } v2; |
| 190 | } hdr; |
| 191 | |
| 192 | read_buf(fd, (char*)&hdr, PROXY_V2_SIG_SIZE); |
| 193 | |
| 194 | if (memcmp(hdr.v2.sig, proxyv2sig, PROXY_V2_SIG_SIZE) == 0) { /* Proxy V2 */ |
| 195 | int ver, cmd, size; |
| 196 | |
| 197 | read_buf(fd, (char*)&hdr + PROXY_V2_SIG_SIZE, PROXY_V2_HEADER_SIZE - PROXY_V2_SIG_SIZE); |
| 198 | |
| 199 | ver = (hdr.v2.ver_cmd & 0xf0) >> 4; |
| 200 | cmd = (hdr.v2.ver_cmd & 0x0f); |
| 201 | size = (hdr.v2.len[0] << 8) + hdr.v2.len[1]; |
| 202 | |
| 203 | if (ver != 2 || size + PROXY_V2_HEADER_SIZE > (int)sizeof hdr) |
| 204 | return 0; |
| 205 | |
| 206 | /* Grab all the remaining data in the binary request. */ |
| 207 | read_buf(fd, (char*)&hdr + PROXY_V2_HEADER_SIZE, size); |
| 208 | |
| 209 | switch (cmd) { |
| 210 | case CMD_PROXY: |
| 211 | switch (hdr.v2.fam) { |
| 212 | case PROXY_FAM_TCPv4: |
| 213 | if (size != sizeof hdr.v2.addr.ip4) |
| 214 | return 0; |
| 215 | inet_ntop(AF_INET, hdr.v2.addr.ip4.src_addr, ipaddr_buf, sizeof ipaddr_buf); |
| 216 | return valid_ipaddr(ipaddr_buf, False); |
| 217 | #ifdef INET6 |
no test coverage detected