blob: 0ba29ed662f16edf6f8bfe7638998bda3d318dbe [file] [log] [blame]
Willy Tarreau59f98392012-07-06 14:13:49 +02001/*
2 * Connection management functions
3 *
4 * Copyright 2000-2012 Willy Tarreau <w@1wt.eu>
5 *
6 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU General Public License
8 * as published by the Free Software Foundation; either version
9 * 2 of the License, or (at your option) any later version.
10 *
11 */
12
Willy Tarreaue1e4a612012-10-05 00:10:55 +020013#include <errno.h>
14
Willy Tarreau4c7e4b72020-05-27 12:58:42 +020015#include <haproxy/api.h>
Willy Tarreau6be78492020-06-05 00:00:29 +020016#include <haproxy/cfgparse.h>
Willy Tarreau7ea393d2020-06-04 18:02:10 +020017#include <haproxy/connection.h>
Willy Tarreaub2551052020-06-09 09:07:15 +020018#include <haproxy/fd.h>
Willy Tarreau762d7a52020-06-04 11:23:07 +020019#include <haproxy/frontend.h>
Willy Tarreaub2551052020-06-09 09:07:15 +020020#include <haproxy/hash.h>
Willy Tarreau36979d92020-06-05 17:27:29 +020021#include <haproxy/log-t.h>
Willy Tarreau7a00efb2020-06-02 17:02:59 +020022#include <haproxy/namespace.h>
Willy Tarreau6131d6a2020-06-02 16:48:09 +020023#include <haproxy/net_helper.h>
Willy Tarreaufc774542020-06-04 17:31:04 +020024#include <haproxy/proto_tcp.h>
Willy Tarreaue6ce10b2020-06-04 15:33:47 +020025#include <haproxy/sample.h>
Willy Tarreau209108d2020-06-04 20:30:20 +020026#include <haproxy/ssl_sock.h>
Willy Tarreau5e539c92020-06-04 20:45:39 +020027#include <haproxy/stream_interface.h>
Willy Tarreau908908e2021-05-08 13:07:31 +020028#include <haproxy/tools.h>
Emeric Brun46591952012-05-18 15:47:34 +020029
Alexander Liu2a54bb72019-05-22 19:44:48 +080030
Amaury Denoyelle8990b012021-02-19 15:29:16 +010031DECLARE_POOL(pool_head_connection, "connection", sizeof(struct connection));
32DECLARE_POOL(pool_head_connstream, "conn_stream", sizeof(struct conn_stream));
33DECLARE_POOL(pool_head_conn_hash_node, "conn_hash_node", sizeof(struct conn_hash_node));
34DECLARE_POOL(pool_head_sockaddr, "sockaddr", sizeof(struct sockaddr_storage));
35DECLARE_POOL(pool_head_authority, "authority", PP2_AUTHORITY_MAX);
Willy Tarreau8ceae722018-11-26 11:58:30 +010036
Willy Tarreau4d82bf52020-06-28 00:19:17 +020037struct idle_conns idle_conns[MAX_THREADS] = { };
Willy Tarreau13e14102016-12-22 20:25:26 +010038struct xprt_ops *registered_xprt[XPRT_ENTRIES] = { NULL, };
Willy Tarreauf2943dc2012-10-26 20:10:28 +020039
Christopher Faulet32f61c02018-04-10 14:33:41 +020040/* List head of all known muxes for PROTO */
41struct mux_proto_list mux_proto_list = {
42 .list = LIST_HEAD_INIT(mux_proto_list.list)
Willy Tarreau2386be62017-09-21 19:40:52 +020043};
44
Amaury Denoyelled3a88c12021-05-03 10:47:51 +020045struct mux_stopping_data mux_stopping_data[MAX_THREADS];
46
Willy Tarreau119e50e2020-05-22 13:53:29 +020047/* disables sending of proxy-protocol-v2's LOCAL command */
48static int pp2_never_send_local;
49
Olivier Houchard477902b2020-01-22 18:08:48 +010050int conn_create_mux(struct connection *conn)
51{
Olivier Houchard477902b2020-01-22 18:08:48 +010052 if (conn_is_back(conn)) {
53 struct server *srv;
54 struct conn_stream *cs = conn->ctx;
Christopher Faulet14cd3162020-04-16 14:50:06 +020055 struct session *sess = conn->owner;
Olivier Houchard477902b2020-01-22 18:08:48 +010056
57 if (conn->flags & CO_FL_ERROR)
58 goto fail;
Olivier Houcharda8a415d2020-01-23 13:15:14 +010059
Christopher Faulet14cd3162020-04-16 14:50:06 +020060 if (sess && obj_type(sess->origin) == OBJ_TYPE_CHECK) {
Willy Tarreau38b4d2e2020-11-20 17:08:15 +010061 if (conn_install_mux_chk(conn, conn->ctx, sess) < 0)
Christopher Faulet14cd3162020-04-16 14:50:06 +020062 goto fail;
63 }
Willy Tarreau38b4d2e2020-11-20 17:08:15 +010064 else if (conn_install_mux_be(conn, conn->ctx, sess) < 0)
Olivier Houchard477902b2020-01-22 18:08:48 +010065 goto fail;
66 srv = objt_server(conn->target);
Christopher Faulet08016ab2020-07-01 16:10:06 +020067
68 /* If we're doing http-reuse always, and the connection is not
69 * private with available streams (an http2 connection), add it
70 * to the available list, so that others can use it right
71 * away. If the connection is private, add it in the session
72 * server list.
73 */
Christopher Faulet2883fcf2020-07-01 14:59:43 +020074 if (srv && ((srv->proxy->options & PR_O_REUSE_MASK) == PR_O_REUSE_ALWS) &&
Christopher Fauletaa278532020-06-30 14:47:46 +020075 !(conn->flags & CO_FL_PRIVATE) && conn->mux->avail_streams(conn) > 0)
Willy Tarreau430bf4a2021-03-04 09:45:32 +010076 ebmb_insert(&srv->per_thr[tid].avail_conns, &conn->hash_node->node, sizeof(conn->hash_node->hash));
Christopher Faulet08016ab2020-07-01 16:10:06 +020077 else if (conn->flags & CO_FL_PRIVATE) {
Ilya Shipitsin6b79f382020-07-23 00:32:55 +050078 /* If it fail now, the same will be done in mux->detach() callback */
Willy Tarreau38b4d2e2020-11-20 17:08:15 +010079 session_add_conn(sess, conn, conn->target);
Christopher Faulet08016ab2020-07-01 16:10:06 +020080 }
Olivier Houchard477902b2020-01-22 18:08:48 +010081 return 0;
82fail:
83 /* let the upper layer know the connection failed */
84 cs->data_cb->wake(cs);
85 return -1;
86 } else
87 return conn_complete_session(conn);
88
89}
90
Willy Tarreauff3e6482015-03-12 23:56:52 +010091/* Send a message over an established connection. It makes use of send() and
92 * returns the same return code and errno. If the socket layer is not ready yet
93 * then -1 is returned and ENOTSOCK is set into errno. If the fd is not marked
94 * as ready, or if EAGAIN or ENOTCONN is returned, then we return 0. It returns
95 * EMSGSIZE if called with a zero length message. The purpose is to simplify
96 * some rare attempts to directly write on the socket from above the connection
97 * (typically send_proxy). In case of EAGAIN, the fd is marked as "cant_send".
98 * It automatically retries on EINTR. Other errors cause the connection to be
99 * marked as in error state. It takes similar arguments as send() except the
Willy Tarreau827fee72020-12-11 15:26:55 +0100100 * first one which is the connection instead of the file descriptor. <flags>
101 * only support CO_SFL_MSG_MORE.
Willy Tarreauff3e6482015-03-12 23:56:52 +0100102 */
Willy Tarreau827fee72020-12-11 15:26:55 +0100103int conn_ctrl_send(struct connection *conn, const void *buf, int len, int flags)
Willy Tarreauff3e6482015-03-12 23:56:52 +0100104{
Willy Tarreau827fee72020-12-11 15:26:55 +0100105 const struct buffer buffer = b_make((char*)buf, len, 0, len);
106 const struct xprt_ops *xprt = xprt_get(XPRT_RAW);
Willy Tarreauff3e6482015-03-12 23:56:52 +0100107 int ret;
108
109 ret = -1;
110 errno = ENOTSOCK;
111
112 if (conn->flags & CO_FL_SOCK_WR_SH)
113 goto fail;
114
115 if (!conn_ctrl_ready(conn))
116 goto fail;
117
118 errno = EMSGSIZE;
119 if (!len)
120 goto fail;
121
Willy Tarreau827fee72020-12-11 15:26:55 +0100122 /* snd_buf() already takes care of updating conn->flags and handling
123 * the FD polling status.
124 */
125 ret = xprt->snd_buf(conn, NULL, &buffer, buffer.data, flags);
126 if (conn->flags & CO_FL_ERROR)
127 ret = -1;
128 return ret;
Willy Tarreauff3e6482015-03-12 23:56:52 +0100129 fail:
130 conn->flags |= CO_FL_SOCK_RD_SH | CO_FL_SOCK_WR_SH | CO_FL_ERROR;
131 return ret;
132}
133
Willy Tarreau746b0512020-12-11 17:06:11 +0100134/* Called from the upper layer, to unsubscribe <es> from events <event_type>.
135 * The event subscriber <es> is not allowed to change from a previous call as
136 * long as at least one event is still subscribed. The <event_type> must only
137 * be a combination of SUB_RETRY_RECV and SUB_RETRY_SEND. It always returns 0.
Willy Tarreauee1a6fc2020-01-17 07:52:13 +0100138 */
139int conn_unsubscribe(struct connection *conn, void *xprt_ctx, int event_type, struct wait_event *es)
Olivier Houchard83a0cd82018-09-28 17:57:58 +0200140{
Willy Tarreau7872d1f2020-01-10 07:06:05 +0100141 BUG_ON(event_type & ~(SUB_RETRY_SEND|SUB_RETRY_RECV));
Willy Tarreauee1a6fc2020-01-17 07:52:13 +0100142 BUG_ON(conn->subs && conn->subs != es);
Willy Tarreau7872d1f2020-01-10 07:06:05 +0100143
Willy Tarreauee1a6fc2020-01-17 07:52:13 +0100144 es->events &= ~event_type;
145 if (!es->events)
Willy Tarreau7872d1f2020-01-10 07:06:05 +0100146 conn->subs = NULL;
147
Willy Tarreau746b0512020-12-11 17:06:11 +0100148 if (conn_ctrl_ready(conn) && conn->ctrl->ignore_events)
149 conn->ctrl->ignore_events(conn, event_type);
Willy Tarreau7872d1f2020-01-10 07:06:05 +0100150
Olivier Houchard83a0cd82018-09-28 17:57:58 +0200151 return 0;
152}
153
Willy Tarreau7e59c0a2020-02-28 14:24:49 +0100154/* Called from the upper layer, to subscribe <es> to events <event_type>.
155 * The <es> struct is not allowed to differ from the one passed during a
Willy Tarreau746b0512020-12-11 17:06:11 +0100156 * previous call to subscribe(). If the connection's ctrl layer is ready,
157 * the wait_event is immediately woken up and the subcription is cancelled.
158 * It always returns zero.
Willy Tarreauee1a6fc2020-01-17 07:52:13 +0100159 */
160int conn_subscribe(struct connection *conn, void *xprt_ctx, int event_type, struct wait_event *es)
Olivier Houchard6ff20392018-07-17 18:46:31 +0200161{
Willy Tarreau746b0512020-12-11 17:06:11 +0100162 int ret = 0;
163
Willy Tarreau7872d1f2020-01-10 07:06:05 +0100164 BUG_ON(event_type & ~(SUB_RETRY_SEND|SUB_RETRY_RECV));
Willy Tarreauee1a6fc2020-01-17 07:52:13 +0100165 BUG_ON(conn->subs && conn->subs != es);
Willy Tarreau7872d1f2020-01-10 07:06:05 +0100166
Willy Tarreau7e59c0a2020-02-28 14:24:49 +0100167 if (conn->subs && (conn->subs->events & event_type) == event_type)
168 return 0;
169
Willy Tarreau746b0512020-12-11 17:06:11 +0100170 if (conn_ctrl_ready(conn) && conn->ctrl->check_events) {
171 ret = conn->ctrl->check_events(conn, event_type);
172 if (ret)
173 tasklet_wakeup(es->tasklet);
Willy Tarreaud1d14c32020-02-21 10:34:19 +0100174 }
Willy Tarreau746b0512020-12-11 17:06:11 +0100175
176 es->events = (es->events | event_type) & ~ret;
177 conn->subs = es->events ? es : NULL;
Olivier Houchard83a0cd82018-09-28 17:57:58 +0200178 return 0;
Olivier Houchard6ff20392018-07-17 18:46:31 +0200179}
180
Willy Tarreau2ded48d2020-12-11 16:20:34 +0100181/* Drains possibly pending incoming data on the connection and update the flags
182 * accordingly. This is used to know whether we need to disable lingering on
183 * close. Returns non-zero if it is safe to close without disabling lingering,
184 * otherwise zero. The CO_FL_SOCK_RD_SH flag may also be updated if the incoming
185 * shutdown was reported by the ->drain() function.
Willy Tarreaud85c4852015-03-13 00:40:28 +0100186 */
Willy Tarreau2ded48d2020-12-11 16:20:34 +0100187int conn_ctrl_drain(struct connection *conn)
Willy Tarreaud85c4852015-03-13 00:40:28 +0100188{
Willy Tarreau2ded48d2020-12-11 16:20:34 +0100189 int ret = 0;
Willy Tarreaue215bba2018-08-24 14:31:53 +0200190
Willy Tarreau2ded48d2020-12-11 16:20:34 +0100191 if (!conn_ctrl_ready(conn) || conn->flags & (CO_FL_ERROR | CO_FL_SOCK_RD_SH))
192 ret = 1;
193 else if (conn->ctrl->drain) {
194 ret = conn->ctrl->drain(conn);
195 if (ret)
196 conn->flags |= CO_FL_SOCK_RD_SH;
Willy Tarreaud85c4852015-03-13 00:40:28 +0100197 }
Willy Tarreau2ded48d2020-12-11 16:20:34 +0100198 return ret;
Willy Tarreaud85c4852015-03-13 00:40:28 +0100199}
200
KOVACS Krisztianb3e54fe2014-11-17 15:11:45 +0100201/*
202 * Get data length from tlv
203 */
Tim Duesterhusba837ec2020-03-05 23:11:02 +0100204static inline size_t get_tlv_length(const struct tlv *src)
KOVACS Krisztianb3e54fe2014-11-17 15:11:45 +0100205{
206 return (src->length_hi << 8) | src->length_lo;
207}
208
Willy Tarreaue1e4a612012-10-05 00:10:55 +0200209/* This handshake handler waits a PROXY protocol header at the beginning of the
210 * raw data stream. The header looks like this :
211 *
212 * "PROXY" <SP> PROTO <SP> SRC3 <SP> DST3 <SP> SRC4 <SP> <DST4> "\r\n"
213 *
214 * There must be exactly one space between each field. Fields are :
215 * - PROTO : layer 4 protocol, which must be "TCP4" or "TCP6".
216 * - SRC3 : layer 3 (eg: IP) source address in standard text form
217 * - DST3 : layer 3 (eg: IP) destination address in standard text form
218 * - SRC4 : layer 4 (eg: TCP port) source address in standard text form
219 * - DST4 : layer 4 (eg: TCP port) destination address in standard text form
220 *
221 * This line MUST be at the beginning of the buffer and MUST NOT wrap.
222 *
223 * The header line is small and in all cases smaller than the smallest normal
224 * TCP MSS. So it MUST always be delivered as one segment, which ensures we
225 * can safely use MSG_PEEK and avoid buffering.
226 *
227 * Once the data is fetched, the values are set in the connection's address
228 * fields, and data are removed from the socket's buffer. The function returns
229 * zero if it needs to wait for more data or if it fails, or 1 if it completed
230 * and removed itself.
231 */
232int conn_recv_proxy(struct connection *conn, int flag)
233{
234 char *line, *end;
Willy Tarreau77992672014-06-14 11:06:17 +0200235 struct proxy_hdr_v2 *hdr_v2;
236 const char v2sig[] = PP2_SIGNATURE;
Tim Duesterhus488ee7f2020-03-05 22:55:20 +0100237 size_t total_v2_len;
Tim Duesterhusba837ec2020-03-05 23:11:02 +0100238 size_t tlv_offset = 0;
Willy Tarreaub406b872018-08-22 05:20:32 +0200239 int ret;
Willy Tarreaue1e4a612012-10-05 00:10:55 +0200240
Willy Tarreau3c728722014-01-23 13:50:42 +0100241 if (!conn_ctrl_ready(conn))
Willy Tarreauf79c8172013-10-21 16:30:56 +0200242 goto fail;
243
Willy Tarreau9b7587a2020-10-15 07:32:10 +0200244 if (!sockaddr_alloc(&conn->src, NULL, 0) || !sockaddr_alloc(&conn->dst, NULL, 0))
Willy Tarreauca79f592019-07-17 19:04:47 +0200245 goto fail;
246
Willy Tarreau585744b2017-08-24 14:31:19 +0200247 if (!fd_recv_ready(conn->handle.fd))
Willy Tarreau6499b9d2019-06-03 08:17:30 +0200248 goto not_ready;
Willy Tarreaufd803bb2014-01-20 15:13:07 +0100249
Willy Tarreau157788c2020-02-11 10:08:05 +0100250 while (1) {
Willy Tarreaub406b872018-08-22 05:20:32 +0200251 ret = recv(conn->handle.fd, trash.area, trash.size, MSG_PEEK);
252 if (ret < 0) {
Willy Tarreaue1e4a612012-10-05 00:10:55 +0200253 if (errno == EINTR)
254 continue;
255 if (errno == EAGAIN) {
Willy Tarreau585744b2017-08-24 14:31:19 +0200256 fd_cant_recv(conn->handle.fd);
Willy Tarreau6499b9d2019-06-03 08:17:30 +0200257 goto not_ready;
Willy Tarreaue1e4a612012-10-05 00:10:55 +0200258 }
Willy Tarreau8e3bf692012-12-03 15:41:18 +0100259 goto recv_abort;
Willy Tarreaue1e4a612012-10-05 00:10:55 +0200260 }
Willy Tarreaub406b872018-08-22 05:20:32 +0200261 trash.data = ret;
Willy Tarreau157788c2020-02-11 10:08:05 +0100262 break;
263 }
Willy Tarreaue1e4a612012-10-05 00:10:55 +0200264
Willy Tarreau843b7cb2018-07-13 10:54:26 +0200265 if (!trash.data) {
Willy Tarreau8e3bf692012-12-03 15:41:18 +0100266 /* client shutdown */
267 conn->err_code = CO_ER_PRX_EMPTY;
268 goto fail;
269 }
270
Willy Tarreauc192b0a2020-01-23 09:11:58 +0100271 conn->flags &= ~CO_FL_WAIT_L4_CONN;
272
Willy Tarreau843b7cb2018-07-13 10:54:26 +0200273 if (trash.data < 6)
Willy Tarreaue1e4a612012-10-05 00:10:55 +0200274 goto missing;
275
Willy Tarreau843b7cb2018-07-13 10:54:26 +0200276 line = trash.area;
277 end = trash.area + trash.data;
Willy Tarreaue1e4a612012-10-05 00:10:55 +0200278
279 /* Decode a possible proxy request, fail early if it does not match */
Willy Tarreau77992672014-06-14 11:06:17 +0200280 if (strncmp(line, "PROXY ", 6) != 0)
281 goto not_v1;
Willy Tarreaue1e4a612012-10-05 00:10:55 +0200282
283 line += 6;
Willy Tarreau843b7cb2018-07-13 10:54:26 +0200284 if (trash.data < 9) /* shortest possible line */
Willy Tarreaue1e4a612012-10-05 00:10:55 +0200285 goto missing;
286
David CARLIER42ff05e2016-03-24 09:22:36 +0000287 if (memcmp(line, "TCP4 ", 5) == 0) {
Willy Tarreaue1e4a612012-10-05 00:10:55 +0200288 u32 src3, dst3, sport, dport;
289
290 line += 5;
291
292 src3 = inetaddr_host_lim_ret(line, end, &line);
293 if (line == end)
294 goto missing;
295 if (*line++ != ' ')
Willy Tarreau8e3bf692012-12-03 15:41:18 +0100296 goto bad_header;
Willy Tarreaue1e4a612012-10-05 00:10:55 +0200297
298 dst3 = inetaddr_host_lim_ret(line, end, &line);
299 if (line == end)
300 goto missing;
301 if (*line++ != ' ')
Willy Tarreau8e3bf692012-12-03 15:41:18 +0100302 goto bad_header;
Willy Tarreaue1e4a612012-10-05 00:10:55 +0200303
304 sport = read_uint((const char **)&line, end);
305 if (line == end)
306 goto missing;
307 if (*line++ != ' ')
Willy Tarreau8e3bf692012-12-03 15:41:18 +0100308 goto bad_header;
Willy Tarreaue1e4a612012-10-05 00:10:55 +0200309
310 dport = read_uint((const char **)&line, end);
311 if (line > end - 2)
312 goto missing;
313 if (*line++ != '\r')
Willy Tarreau8e3bf692012-12-03 15:41:18 +0100314 goto bad_header;
Willy Tarreaue1e4a612012-10-05 00:10:55 +0200315 if (*line++ != '\n')
Willy Tarreau8e3bf692012-12-03 15:41:18 +0100316 goto bad_header;
Willy Tarreaue1e4a612012-10-05 00:10:55 +0200317
318 /* update the session's addresses and mark them set */
Willy Tarreau226572f2019-07-17 14:46:00 +0200319 ((struct sockaddr_in *)conn->src)->sin_family = AF_INET;
320 ((struct sockaddr_in *)conn->src)->sin_addr.s_addr = htonl(src3);
321 ((struct sockaddr_in *)conn->src)->sin_port = htons(sport);
Willy Tarreaue1e4a612012-10-05 00:10:55 +0200322
Willy Tarreau226572f2019-07-17 14:46:00 +0200323 ((struct sockaddr_in *)conn->dst)->sin_family = AF_INET;
324 ((struct sockaddr_in *)conn->dst)->sin_addr.s_addr = htonl(dst3);
325 ((struct sockaddr_in *)conn->dst)->sin_port = htons(dport);
Willy Tarreaue1e4a612012-10-05 00:10:55 +0200326 conn->flags |= CO_FL_ADDR_FROM_SET | CO_FL_ADDR_TO_SET;
327 }
David CARLIER42ff05e2016-03-24 09:22:36 +0000328 else if (memcmp(line, "TCP6 ", 5) == 0) {
Willy Tarreaue1e4a612012-10-05 00:10:55 +0200329 u32 sport, dport;
330 char *src_s;
331 char *dst_s, *sport_s, *dport_s;
332 struct in6_addr src3, dst3;
333
334 line += 5;
335
336 src_s = line;
337 dst_s = sport_s = dport_s = NULL;
338 while (1) {
339 if (line > end - 2) {
340 goto missing;
341 }
342 else if (*line == '\r') {
343 *line = 0;
344 line++;
345 if (*line++ != '\n')
Willy Tarreau8e3bf692012-12-03 15:41:18 +0100346 goto bad_header;
Willy Tarreaue1e4a612012-10-05 00:10:55 +0200347 break;
348 }
349
350 if (*line == ' ') {
351 *line = 0;
352 if (!dst_s)
353 dst_s = line + 1;
354 else if (!sport_s)
355 sport_s = line + 1;
356 else if (!dport_s)
357 dport_s = line + 1;
358 }
359 line++;
360 }
361
362 if (!dst_s || !sport_s || !dport_s)
Willy Tarreau8e3bf692012-12-03 15:41:18 +0100363 goto bad_header;
Willy Tarreaue1e4a612012-10-05 00:10:55 +0200364
365 sport = read_uint((const char **)&sport_s,dport_s - 1);
366 if (*sport_s != 0)
Willy Tarreau8e3bf692012-12-03 15:41:18 +0100367 goto bad_header;
Willy Tarreaue1e4a612012-10-05 00:10:55 +0200368
369 dport = read_uint((const char **)&dport_s,line - 2);
370 if (*dport_s != 0)
Willy Tarreau8e3bf692012-12-03 15:41:18 +0100371 goto bad_header;
Willy Tarreaue1e4a612012-10-05 00:10:55 +0200372
373 if (inet_pton(AF_INET6, src_s, (void *)&src3) != 1)
Willy Tarreau8e3bf692012-12-03 15:41:18 +0100374 goto bad_header;
Willy Tarreaue1e4a612012-10-05 00:10:55 +0200375
376 if (inet_pton(AF_INET6, dst_s, (void *)&dst3) != 1)
Willy Tarreau8e3bf692012-12-03 15:41:18 +0100377 goto bad_header;
Willy Tarreaue1e4a612012-10-05 00:10:55 +0200378
379 /* update the session's addresses and mark them set */
Willy Tarreau226572f2019-07-17 14:46:00 +0200380 ((struct sockaddr_in6 *)conn->src)->sin6_family = AF_INET6;
381 memcpy(&((struct sockaddr_in6 *)conn->src)->sin6_addr, &src3, sizeof(struct in6_addr));
382 ((struct sockaddr_in6 *)conn->src)->sin6_port = htons(sport);
Willy Tarreaue1e4a612012-10-05 00:10:55 +0200383
Willy Tarreau226572f2019-07-17 14:46:00 +0200384 ((struct sockaddr_in6 *)conn->dst)->sin6_family = AF_INET6;
385 memcpy(&((struct sockaddr_in6 *)conn->dst)->sin6_addr, &dst3, sizeof(struct in6_addr));
386 ((struct sockaddr_in6 *)conn->dst)->sin6_port = htons(dport);
Willy Tarreaue1e4a612012-10-05 00:10:55 +0200387 conn->flags |= CO_FL_ADDR_FROM_SET | CO_FL_ADDR_TO_SET;
388 }
Willy Tarreau4c20d292014-06-14 11:41:36 +0200389 else if (memcmp(line, "UNKNOWN\r\n", 9) == 0) {
390 /* This can be a UNIX socket forwarded by an haproxy upstream */
391 line += 9;
392 }
Willy Tarreaue1e4a612012-10-05 00:10:55 +0200393 else {
Willy Tarreau4c20d292014-06-14 11:41:36 +0200394 /* The protocol does not match something known (TCP4/TCP6/UNKNOWN) */
Willy Tarreau8e3bf692012-12-03 15:41:18 +0100395 conn->err_code = CO_ER_PRX_BAD_PROTO;
Willy Tarreaue1e4a612012-10-05 00:10:55 +0200396 goto fail;
397 }
398
Willy Tarreau843b7cb2018-07-13 10:54:26 +0200399 trash.data = line - trash.area;
Willy Tarreau77992672014-06-14 11:06:17 +0200400 goto eat_header;
401
402 not_v1:
403 /* try PPv2 */
Willy Tarreau843b7cb2018-07-13 10:54:26 +0200404 if (trash.data < PP2_HEADER_LEN)
Willy Tarreau77992672014-06-14 11:06:17 +0200405 goto missing;
406
Willy Tarreau843b7cb2018-07-13 10:54:26 +0200407 hdr_v2 = (struct proxy_hdr_v2 *) trash.area;
Willy Tarreau77992672014-06-14 11:06:17 +0200408
409 if (memcmp(hdr_v2->sig, v2sig, PP2_SIGNATURE_LEN) != 0 ||
410 (hdr_v2->ver_cmd & PP2_VERSION_MASK) != PP2_VERSION) {
411 conn->err_code = CO_ER_PRX_NOT_HDR;
412 goto fail;
413 }
414
Tim Duesterhus488ee7f2020-03-05 22:55:20 +0100415 total_v2_len = PP2_HEADER_LEN + ntohs(hdr_v2->len);
416 if (trash.data < total_v2_len)
Willy Tarreau77992672014-06-14 11:06:17 +0200417 goto missing;
418
419 switch (hdr_v2->ver_cmd & PP2_CMD_MASK) {
420 case 0x01: /* PROXY command */
421 switch (hdr_v2->fam) {
422 case 0x11: /* TCPv4 */
KOVACS Krisztianefd3aa92014-11-19 10:53:20 +0100423 if (ntohs(hdr_v2->len) < PP2_ADDR_LEN_INET)
424 goto bad_header;
425
Willy Tarreau226572f2019-07-17 14:46:00 +0200426 ((struct sockaddr_in *)conn->src)->sin_family = AF_INET;
427 ((struct sockaddr_in *)conn->src)->sin_addr.s_addr = hdr_v2->addr.ip4.src_addr;
428 ((struct sockaddr_in *)conn->src)->sin_port = hdr_v2->addr.ip4.src_port;
429 ((struct sockaddr_in *)conn->dst)->sin_family = AF_INET;
430 ((struct sockaddr_in *)conn->dst)->sin_addr.s_addr = hdr_v2->addr.ip4.dst_addr;
431 ((struct sockaddr_in *)conn->dst)->sin_port = hdr_v2->addr.ip4.dst_port;
Willy Tarreau77992672014-06-14 11:06:17 +0200432 conn->flags |= CO_FL_ADDR_FROM_SET | CO_FL_ADDR_TO_SET;
KOVACS Krisztian7209c202015-07-03 14:09:10 +0200433 tlv_offset = PP2_HEADER_LEN + PP2_ADDR_LEN_INET;
Willy Tarreau77992672014-06-14 11:06:17 +0200434 break;
435 case 0x21: /* TCPv6 */
KOVACS Krisztianefd3aa92014-11-19 10:53:20 +0100436 if (ntohs(hdr_v2->len) < PP2_ADDR_LEN_INET6)
437 goto bad_header;
438
Willy Tarreau226572f2019-07-17 14:46:00 +0200439 ((struct sockaddr_in6 *)conn->src)->sin6_family = AF_INET6;
440 memcpy(&((struct sockaddr_in6 *)conn->src)->sin6_addr, hdr_v2->addr.ip6.src_addr, 16);
441 ((struct sockaddr_in6 *)conn->src)->sin6_port = hdr_v2->addr.ip6.src_port;
442 ((struct sockaddr_in6 *)conn->dst)->sin6_family = AF_INET6;
443 memcpy(&((struct sockaddr_in6 *)conn->dst)->sin6_addr, hdr_v2->addr.ip6.dst_addr, 16);
444 ((struct sockaddr_in6 *)conn->dst)->sin6_port = hdr_v2->addr.ip6.dst_port;
Willy Tarreau77992672014-06-14 11:06:17 +0200445 conn->flags |= CO_FL_ADDR_FROM_SET | CO_FL_ADDR_TO_SET;
KOVACS Krisztian7209c202015-07-03 14:09:10 +0200446 tlv_offset = PP2_HEADER_LEN + PP2_ADDR_LEN_INET6;
Willy Tarreau77992672014-06-14 11:06:17 +0200447 break;
448 }
KOVACS Krisztianb3e54fe2014-11-17 15:11:45 +0100449
450 /* TLV parsing */
Tim Duesterhus488ee7f2020-03-05 22:55:20 +0100451 while (tlv_offset < total_v2_len) {
452 struct tlv *tlv_packet;
Tim Duesterhus56c176a2021-03-06 20:06:51 +0100453 struct ist tlv;
KOVACS Krisztianb3e54fe2014-11-17 15:11:45 +0100454
Tim Duesterhus488ee7f2020-03-05 22:55:20 +0100455 /* Verify that we have at least TLV_HEADER_SIZE bytes left */
456 if (tlv_offset + TLV_HEADER_SIZE > total_v2_len)
457 goto bad_header;
458
459 tlv_packet = (struct tlv *) &trash.area[tlv_offset];
Tim Duesterhus56c176a2021-03-06 20:06:51 +0100460 tlv = ist2((const char *)tlv_packet->value, get_tlv_length(tlv_packet));
461 tlv_offset += istlen(tlv) + TLV_HEADER_SIZE;
Tim Duesterhus488ee7f2020-03-05 22:55:20 +0100462
463 /* Verify that the TLV length does not exceed the total PROXYv2 length */
464 if (tlv_offset > total_v2_len)
465 goto bad_header;
466
467 switch (tlv_packet->type) {
468 case PP2_TYPE_CRC32C: {
469 uint32_t n_crc32c;
470
471 /* Verify that this TLV is exactly 4 bytes long */
Tim Duesterhus56c176a2021-03-06 20:06:51 +0100472 if (istlen(tlv) != 4)
Tim Duesterhus488ee7f2020-03-05 22:55:20 +0100473 goto bad_header;
474
Tim Duesterhus56c176a2021-03-06 20:06:51 +0100475 n_crc32c = read_n32(istptr(tlv));
476 write_n32(istptr(tlv), 0); // compute with CRC==0
Tim Duesterhus488ee7f2020-03-05 22:55:20 +0100477
478 if (hash_crc32c(trash.area, total_v2_len) != n_crc32c)
479 goto bad_header;
480 break;
481 }
Willy Tarreaue5733232019-05-22 19:24:06 +0200482#ifdef USE_NS
Tim Duesterhus488ee7f2020-03-05 22:55:20 +0100483 case PP2_TYPE_NETNS: {
484 const struct netns_entry *ns;
485
Tim Duesterhus56c176a2021-03-06 20:06:51 +0100486 ns = netns_store_lookup(istptr(tlv), istlen(tlv));
Tim Duesterhus488ee7f2020-03-05 22:55:20 +0100487 if (ns)
488 conn->proxy_netns = ns;
489 break;
490 }
KOVACS Krisztianb3e54fe2014-11-17 15:11:45 +0100491#endif
Tim Duesterhus488ee7f2020-03-05 22:55:20 +0100492 case PP2_TYPE_AUTHORITY: {
Tim Duesterhus615f81e2021-03-06 20:06:50 +0100493 if (istlen(tlv) > PP2_AUTHORITY_MAX)
Tim Duesterhus488ee7f2020-03-05 22:55:20 +0100494 goto bad_header;
Tim Duesterhus615f81e2021-03-06 20:06:50 +0100495 conn->proxy_authority = ist2(pool_alloc(pool_head_authority), 0);
496 if (!isttest(conn->proxy_authority))
Tim Duesterhus488ee7f2020-03-05 22:55:20 +0100497 goto fail;
Tim Duesterhus615f81e2021-03-06 20:06:50 +0100498 if (istcpy(&conn->proxy_authority, tlv, PP2_AUTHORITY_MAX) < 0) {
499 /* This is technically unreachable, because we verified above
500 * that the TLV value fits.
501 */
502 goto fail;
503 }
Tim Duesterhus488ee7f2020-03-05 22:55:20 +0100504 break;
505 }
Tim Duesterhusd1b15b62020-03-13 12:34:23 +0100506 case PP2_TYPE_UNIQUE_ID: {
Tim Duesterhus002bd772021-03-06 20:06:49 +0100507 if (istlen(tlv) > UNIQUEID_LEN)
Tim Duesterhusd1b15b62020-03-13 12:34:23 +0100508 goto bad_header;
Tim Duesterhus2b7f6c22020-03-14 13:07:05 +0100509 conn->proxy_unique_id = ist2(pool_alloc(pool_head_uniqueid), 0);
Tim Duesterhusd1b15b62020-03-13 12:34:23 +0100510 if (!isttest(conn->proxy_unique_id))
511 goto fail;
512 if (istcpy(&conn->proxy_unique_id, tlv, UNIQUEID_LEN) < 0) {
513 /* This is technically unreachable, because we verified above
514 * that the TLV value fits.
515 */
516 goto fail;
517 }
518 break;
519 }
Tim Duesterhus488ee7f2020-03-05 22:55:20 +0100520 default:
521 break;
KOVACS Krisztianb3e54fe2014-11-17 15:11:45 +0100522 }
523 }
524
Tim Duesterhus488ee7f2020-03-05 22:55:20 +0100525 /* Verify that the PROXYv2 header ends at a TLV boundary.
526 * This is technically unreachable, because the TLV parsing already
527 * verifies that a TLV does not exceed the total length and also
528 * that there is space for a TLV header.
529 */
530 if (tlv_offset != total_v2_len)
531 goto bad_header;
532
Willy Tarreau77992672014-06-14 11:06:17 +0200533 /* unsupported protocol, keep local connection address */
534 break;
535 case 0x00: /* LOCAL command */
536 /* keep local connection address for LOCAL */
537 break;
538 default:
539 goto bad_header; /* not a supported command */
540 }
541
Tim Duesterhus488ee7f2020-03-05 22:55:20 +0100542 trash.data = total_v2_len;
Willy Tarreau77992672014-06-14 11:06:17 +0200543 goto eat_header;
544
545 eat_header:
Willy Tarreaue1e4a612012-10-05 00:10:55 +0200546 /* remove the PROXY line from the request. For this we re-read the
547 * exact line at once. If we don't get the exact same result, we
548 * fail.
549 */
Willy Tarreau157788c2020-02-11 10:08:05 +0100550 while (1) {
Tim Duesterhusa8692f32020-03-13 12:34:25 +0100551 ssize_t len2 = recv(conn->handle.fd, trash.area, trash.data, 0);
552
Willy Tarreaue1e4a612012-10-05 00:10:55 +0200553 if (len2 < 0 && errno == EINTR)
554 continue;
Willy Tarreau843b7cb2018-07-13 10:54:26 +0200555 if (len2 != trash.data)
Willy Tarreau8e3bf692012-12-03 15:41:18 +0100556 goto recv_abort;
Willy Tarreau157788c2020-02-11 10:08:05 +0100557 break;
558 }
Willy Tarreaue1e4a612012-10-05 00:10:55 +0200559
560 conn->flags &= ~flag;
Emeric Brun4f603012017-01-05 15:11:44 +0100561 conn->flags |= CO_FL_RCVD_PROXY;
Willy Tarreaue1e4a612012-10-05 00:10:55 +0200562 return 1;
563
Willy Tarreau6499b9d2019-06-03 08:17:30 +0200564 not_ready:
Willy Tarreau6499b9d2019-06-03 08:17:30 +0200565 return 0;
566
Willy Tarreaue1e4a612012-10-05 00:10:55 +0200567 missing:
568 /* Missing data. Since we're using MSG_PEEK, we can only poll again if
569 * we have not read anything. Otherwise we need to fail because we won't
570 * be able to poll anymore.
571 */
Willy Tarreau8e3bf692012-12-03 15:41:18 +0100572 conn->err_code = CO_ER_PRX_TRUNCATED;
573 goto fail;
574
575 bad_header:
576 /* This is not a valid proxy protocol header */
577 conn->err_code = CO_ER_PRX_BAD_HDR;
578 goto fail;
579
580 recv_abort:
581 conn->err_code = CO_ER_PRX_ABORT;
Willy Tarreau26f4a042013-12-04 23:44:10 +0100582 conn->flags |= CO_FL_SOCK_RD_SH | CO_FL_SOCK_WR_SH;
Willy Tarreau8e3bf692012-12-03 15:41:18 +0100583 goto fail;
584
Willy Tarreaue1e4a612012-10-05 00:10:55 +0200585 fail:
Willy Tarreaue1e4a612012-10-05 00:10:55 +0200586 conn->flags |= CO_FL_ERROR;
Willy Tarreaue1e4a612012-10-05 00:10:55 +0200587 return 0;
588}
589
Bertrand Jacquin93b227d2016-06-04 15:11:10 +0100590/* This handshake handler waits a NetScaler Client IP insertion header
Bertrand Jacquin72fa1ec2017-12-12 01:17:23 +0000591 * at the beginning of the raw data stream. The header format is
592 * described in doc/netscaler-client-ip-insertion-protocol.txt
Bertrand Jacquin93b227d2016-06-04 15:11:10 +0100593 *
594 * This line MUST be at the beginning of the buffer and MUST NOT be
595 * fragmented.
596 *
597 * The header line is small and in all cases smaller than the smallest normal
598 * TCP MSS. So it MUST always be delivered as one segment, which ensures we
599 * can safely use MSG_PEEK and avoid buffering.
600 *
601 * Once the data is fetched, the values are set in the connection's address
602 * fields, and data are removed from the socket's buffer. The function returns
603 * zero if it needs to wait for more data or if it fails, or 1 if it completed
604 * and removed itself.
605 */
606int conn_recv_netscaler_cip(struct connection *conn, int flag)
607{
608 char *line;
Bertrand Jacquin7d668f92017-12-13 01:23:39 +0000609 uint32_t hdr_len;
Willy Tarreau0ca24aa2019-03-29 17:35:32 +0100610 uint8_t ip_ver;
Willy Tarreaub406b872018-08-22 05:20:32 +0200611 int ret;
Bertrand Jacquin93b227d2016-06-04 15:11:10 +0100612
Bertrand Jacquin93b227d2016-06-04 15:11:10 +0100613 if (!conn_ctrl_ready(conn))
614 goto fail;
615
Willy Tarreau9b7587a2020-10-15 07:32:10 +0200616 if (!sockaddr_alloc(&conn->src, NULL, 0) || !sockaddr_alloc(&conn->dst, NULL, 0))
Olivier Houchard1a9dbe52020-01-22 15:31:09 +0100617 goto fail;
618
Willy Tarreau585744b2017-08-24 14:31:19 +0200619 if (!fd_recv_ready(conn->handle.fd))
Willy Tarreau6499b9d2019-06-03 08:17:30 +0200620 goto not_ready;
Bertrand Jacquin93b227d2016-06-04 15:11:10 +0100621
Willy Tarreau157788c2020-02-11 10:08:05 +0100622 while (1) {
Willy Tarreaub406b872018-08-22 05:20:32 +0200623 ret = recv(conn->handle.fd, trash.area, trash.size, MSG_PEEK);
624 if (ret < 0) {
Bertrand Jacquin93b227d2016-06-04 15:11:10 +0100625 if (errno == EINTR)
626 continue;
627 if (errno == EAGAIN) {
Willy Tarreau585744b2017-08-24 14:31:19 +0200628 fd_cant_recv(conn->handle.fd);
Willy Tarreau6499b9d2019-06-03 08:17:30 +0200629 goto not_ready;
Bertrand Jacquin93b227d2016-06-04 15:11:10 +0100630 }
631 goto recv_abort;
632 }
Willy Tarreaub406b872018-08-22 05:20:32 +0200633 trash.data = ret;
Willy Tarreau157788c2020-02-11 10:08:05 +0100634 break;
635 }
Bertrand Jacquin93b227d2016-06-04 15:11:10 +0100636
Willy Tarreauc192b0a2020-01-23 09:11:58 +0100637 conn->flags &= ~CO_FL_WAIT_L4_CONN;
638
Willy Tarreau843b7cb2018-07-13 10:54:26 +0200639 if (!trash.data) {
Bertrand Jacquin93b227d2016-06-04 15:11:10 +0100640 /* client shutdown */
641 conn->err_code = CO_ER_CIP_EMPTY;
642 goto fail;
643 }
644
645 /* Fail if buffer length is not large enough to contain
Bertrand Jacquin72fa1ec2017-12-12 01:17:23 +0000646 * CIP magic, header length or
647 * CIP magic, CIP length, CIP type, header length */
Willy Tarreau843b7cb2018-07-13 10:54:26 +0200648 if (trash.data < 12)
Bertrand Jacquin93b227d2016-06-04 15:11:10 +0100649 goto missing;
650
Willy Tarreau843b7cb2018-07-13 10:54:26 +0200651 line = trash.area;
Bertrand Jacquin93b227d2016-06-04 15:11:10 +0100652
653 /* Decode a possible NetScaler Client IP request, fail early if
654 * it does not match */
Willy Tarreau1ac83af2020-02-25 10:06:49 +0100655 if (ntohl(read_u32(line)) != __objt_listener(conn->target)->bind_conf->ns_cip_magic)
Bertrand Jacquin93b227d2016-06-04 15:11:10 +0100656 goto bad_magic;
657
Bertrand Jacquin72fa1ec2017-12-12 01:17:23 +0000658 /* Legacy CIP protocol */
Willy Tarreau843b7cb2018-07-13 10:54:26 +0200659 if ((trash.area[8] & 0xD0) == 0x40) {
Willy Tarreau1ac83af2020-02-25 10:06:49 +0100660 hdr_len = ntohl(read_u32((line+4)));
Bertrand Jacquin72fa1ec2017-12-12 01:17:23 +0000661 line += 8;
662 }
663 /* Standard CIP protocol */
Willy Tarreau843b7cb2018-07-13 10:54:26 +0200664 else if (trash.area[8] == 0x00) {
Willy Tarreau1ac83af2020-02-25 10:06:49 +0100665 hdr_len = ntohs(read_u32((line+10)));
Bertrand Jacquin72fa1ec2017-12-12 01:17:23 +0000666 line += 12;
667 }
668 /* Unknown CIP protocol */
669 else {
670 conn->err_code = CO_ER_CIP_BAD_PROTO;
671 goto fail;
672 }
673
Bertrand Jacquin93b227d2016-06-04 15:11:10 +0100674 /* Fail if buffer length is not large enough to contain
Bertrand Jacquin72fa1ec2017-12-12 01:17:23 +0000675 * a minimal IP header */
Willy Tarreau843b7cb2018-07-13 10:54:26 +0200676 if (trash.data < 20)
Bertrand Jacquin93b227d2016-06-04 15:11:10 +0100677 goto missing;
678
Bertrand Jacquin93b227d2016-06-04 15:11:10 +0100679 /* Get IP version from the first four bits */
Willy Tarreau0ca24aa2019-03-29 17:35:32 +0100680 ip_ver = (*line & 0xf0) >> 4;
Bertrand Jacquin93b227d2016-06-04 15:11:10 +0100681
Willy Tarreau0ca24aa2019-03-29 17:35:32 +0100682 if (ip_ver == 4) {
Bertrand Jacquin93b227d2016-06-04 15:11:10 +0100683 struct ip *hdr_ip4;
David Carlier3015a2e2016-07-04 22:51:33 +0100684 struct my_tcphdr *hdr_tcp;
Bertrand Jacquin93b227d2016-06-04 15:11:10 +0100685
686 hdr_ip4 = (struct ip *)line;
687
Willy Tarreau843b7cb2018-07-13 10:54:26 +0200688 if (trash.data < 40 || trash.data < hdr_len) {
Bertrand Jacquin93b227d2016-06-04 15:11:10 +0100689 /* Fail if buffer length is not large enough to contain
Bertrand Jacquin67de5a22017-12-13 01:15:05 +0000690 * IPv4 header, TCP header */
Bertrand Jacquin93b227d2016-06-04 15:11:10 +0100691 goto missing;
Bertrand Jacquinb3875912017-12-13 00:58:51 +0000692 }
693 else if (hdr_ip4->ip_p != IPPROTO_TCP) {
Bertrand Jacquin93b227d2016-06-04 15:11:10 +0100694 /* The protocol does not include a TCP header */
695 conn->err_code = CO_ER_CIP_BAD_PROTO;
696 goto fail;
Bertrand Jacquinb3875912017-12-13 00:58:51 +0000697 }
Bertrand Jacquin93b227d2016-06-04 15:11:10 +0100698
David Carlier3015a2e2016-07-04 22:51:33 +0100699 hdr_tcp = (struct my_tcphdr *)(line + (hdr_ip4->ip_hl * 4));
Bertrand Jacquin93b227d2016-06-04 15:11:10 +0100700
701 /* update the session's addresses and mark them set */
Willy Tarreau226572f2019-07-17 14:46:00 +0200702 ((struct sockaddr_in *)conn->src)->sin_family = AF_INET;
703 ((struct sockaddr_in *)conn->src)->sin_addr.s_addr = hdr_ip4->ip_src.s_addr;
704 ((struct sockaddr_in *)conn->src)->sin_port = hdr_tcp->source;
Bertrand Jacquin93b227d2016-06-04 15:11:10 +0100705
Willy Tarreau226572f2019-07-17 14:46:00 +0200706 ((struct sockaddr_in *)conn->dst)->sin_family = AF_INET;
707 ((struct sockaddr_in *)conn->dst)->sin_addr.s_addr = hdr_ip4->ip_dst.s_addr;
708 ((struct sockaddr_in *)conn->dst)->sin_port = hdr_tcp->dest;
Bertrand Jacquin93b227d2016-06-04 15:11:10 +0100709
710 conn->flags |= CO_FL_ADDR_FROM_SET | CO_FL_ADDR_TO_SET;
711 }
Willy Tarreau0ca24aa2019-03-29 17:35:32 +0100712 else if (ip_ver == 6) {
Bertrand Jacquin93b227d2016-06-04 15:11:10 +0100713 struct ip6_hdr *hdr_ip6;
David Carlier3015a2e2016-07-04 22:51:33 +0100714 struct my_tcphdr *hdr_tcp;
Bertrand Jacquin93b227d2016-06-04 15:11:10 +0100715
716 hdr_ip6 = (struct ip6_hdr *)line;
717
Willy Tarreau843b7cb2018-07-13 10:54:26 +0200718 if (trash.data < 60 || trash.data < hdr_len) {
Bertrand Jacquin93b227d2016-06-04 15:11:10 +0100719 /* Fail if buffer length is not large enough to contain
Bertrand Jacquin67de5a22017-12-13 01:15:05 +0000720 * IPv6 header, TCP header */
Bertrand Jacquin93b227d2016-06-04 15:11:10 +0100721 goto missing;
Bertrand Jacquinb3875912017-12-13 00:58:51 +0000722 }
723 else if (hdr_ip6->ip6_nxt != IPPROTO_TCP) {
Bertrand Jacquin93b227d2016-06-04 15:11:10 +0100724 /* The protocol does not include a TCP header */
725 conn->err_code = CO_ER_CIP_BAD_PROTO;
726 goto fail;
Bertrand Jacquinb3875912017-12-13 00:58:51 +0000727 }
Bertrand Jacquin93b227d2016-06-04 15:11:10 +0100728
David Carlier3015a2e2016-07-04 22:51:33 +0100729 hdr_tcp = (struct my_tcphdr *)(line + sizeof(struct ip6_hdr));
Bertrand Jacquin93b227d2016-06-04 15:11:10 +0100730
731 /* update the session's addresses and mark them set */
Willy Tarreau226572f2019-07-17 14:46:00 +0200732 ((struct sockaddr_in6 *)conn->src)->sin6_family = AF_INET6;
733 ((struct sockaddr_in6 *)conn->src)->sin6_addr = hdr_ip6->ip6_src;
734 ((struct sockaddr_in6 *)conn->src)->sin6_port = hdr_tcp->source;
Bertrand Jacquin93b227d2016-06-04 15:11:10 +0100735
Willy Tarreau226572f2019-07-17 14:46:00 +0200736 ((struct sockaddr_in6 *)conn->dst)->sin6_family = AF_INET6;
737 ((struct sockaddr_in6 *)conn->dst)->sin6_addr = hdr_ip6->ip6_dst;
738 ((struct sockaddr_in6 *)conn->dst)->sin6_port = hdr_tcp->dest;
Bertrand Jacquin93b227d2016-06-04 15:11:10 +0100739
740 conn->flags |= CO_FL_ADDR_FROM_SET | CO_FL_ADDR_TO_SET;
741 }
742 else {
743 /* The protocol does not match something known (IPv4/IPv6) */
744 conn->err_code = CO_ER_CIP_BAD_PROTO;
745 goto fail;
746 }
747
Bertrand Jacquin7d668f92017-12-13 01:23:39 +0000748 line += hdr_len;
Willy Tarreau843b7cb2018-07-13 10:54:26 +0200749 trash.data = line - trash.area;
Bertrand Jacquin93b227d2016-06-04 15:11:10 +0100750
751 /* remove the NetScaler Client IP header from the request. For this
752 * we re-read the exact line at once. If we don't get the exact same
753 * result, we fail.
754 */
Willy Tarreau157788c2020-02-11 10:08:05 +0100755 while (1) {
Willy Tarreau843b7cb2018-07-13 10:54:26 +0200756 int len2 = recv(conn->handle.fd, trash.area, trash.data, 0);
Bertrand Jacquin93b227d2016-06-04 15:11:10 +0100757 if (len2 < 0 && errno == EINTR)
758 continue;
Willy Tarreau843b7cb2018-07-13 10:54:26 +0200759 if (len2 != trash.data)
Bertrand Jacquin93b227d2016-06-04 15:11:10 +0100760 goto recv_abort;
Willy Tarreau157788c2020-02-11 10:08:05 +0100761 break;
762 }
Bertrand Jacquin93b227d2016-06-04 15:11:10 +0100763
764 conn->flags &= ~flag;
765 return 1;
766
Willy Tarreau6499b9d2019-06-03 08:17:30 +0200767 not_ready:
Willy Tarreau6499b9d2019-06-03 08:17:30 +0200768 return 0;
769
Bertrand Jacquin93b227d2016-06-04 15:11:10 +0100770 missing:
771 /* Missing data. Since we're using MSG_PEEK, we can only poll again if
772 * we have not read anything. Otherwise we need to fail because we won't
773 * be able to poll anymore.
774 */
775 conn->err_code = CO_ER_CIP_TRUNCATED;
776 goto fail;
777
778 bad_magic:
779 conn->err_code = CO_ER_CIP_BAD_MAGIC;
780 goto fail;
781
782 recv_abort:
783 conn->err_code = CO_ER_CIP_ABORT;
784 conn->flags |= CO_FL_SOCK_RD_SH | CO_FL_SOCK_WR_SH;
785 goto fail;
786
787 fail:
Bertrand Jacquin93b227d2016-06-04 15:11:10 +0100788 conn->flags |= CO_FL_ERROR;
789 return 0;
790}
791
Alexander Liu2a54bb72019-05-22 19:44:48 +0800792
793int conn_send_socks4_proxy_request(struct connection *conn)
794{
795 struct socks4_request req_line;
796
Alexander Liu2a54bb72019-05-22 19:44:48 +0800797 if (!conn_ctrl_ready(conn))
798 goto out_error;
799
Willy Tarreau226572f2019-07-17 14:46:00 +0200800 if (!conn_get_dst(conn))
801 goto out_error;
802
Alexander Liu2a54bb72019-05-22 19:44:48 +0800803 req_line.version = 0x04;
804 req_line.command = 0x01;
Willy Tarreau226572f2019-07-17 14:46:00 +0200805 req_line.port = get_net_port(conn->dst);
806 req_line.ip = is_inet_addr(conn->dst);
Alexander Liu2a54bb72019-05-22 19:44:48 +0800807 memcpy(req_line.user_id, "HAProxy\0", 8);
808
809 if (conn->send_proxy_ofs > 0) {
810 /*
811 * This is the first call to send the request
812 */
813 conn->send_proxy_ofs = -(int)sizeof(req_line);
814 }
815
816 if (conn->send_proxy_ofs < 0) {
817 int ret = 0;
818
819 /* we are sending the socks4_req_line here. If the data layer
820 * has a pending write, we'll also set MSG_MORE.
821 */
Willy Tarreau827fee72020-12-11 15:26:55 +0100822 ret = conn_ctrl_send(
Alexander Liu2a54bb72019-05-22 19:44:48 +0800823 conn,
824 ((char *)(&req_line)) + (sizeof(req_line)+conn->send_proxy_ofs),
825 -conn->send_proxy_ofs,
Willy Tarreau827fee72020-12-11 15:26:55 +0100826 (conn->subs && conn->subs->events & SUB_RETRY_SEND) ? CO_SFL_MSG_MORE : 0);
Alexander Liu2a54bb72019-05-22 19:44:48 +0800827
828 DPRINTF(stderr, "SOCKS PROXY HS FD[%04X]: Before send remain is [%d], sent [%d]\n",
829 conn->handle.fd, -conn->send_proxy_ofs, ret);
830
831 if (ret < 0) {
832 goto out_error;
833 }
834
835 conn->send_proxy_ofs += ret; /* becomes zero once complete */
836 if (conn->send_proxy_ofs != 0) {
837 goto out_wait;
838 }
839 }
840
841 /* OK we've the whole request sent */
842 conn->flags &= ~CO_FL_SOCKS4_SEND;
Alexander Liu2a54bb72019-05-22 19:44:48 +0800843
844 /* The connection is ready now, simply return and let the connection
845 * handler notify upper layers if needed.
846 */
Willy Tarreauc192b0a2020-01-23 09:11:58 +0100847 conn->flags &= ~CO_FL_WAIT_L4_CONN;
Alexander Liu2a54bb72019-05-22 19:44:48 +0800848
849 if (conn->flags & CO_FL_SEND_PROXY) {
850 /*
851 * Get the send_proxy_ofs ready for the send_proxy due to we are
852 * reusing the "send_proxy_ofs", and SOCKS4 handshake should be done
853 * before sending PROXY Protocol.
854 */
855 conn->send_proxy_ofs = 1;
856 }
857 return 1;
858
859 out_error:
860 /* Write error on the file descriptor */
861 conn->flags |= CO_FL_ERROR;
862 if (conn->err_code == CO_ER_NONE) {
863 conn->err_code = CO_ER_SOCKS4_SEND;
864 }
865 return 0;
866
867 out_wait:
Alexander Liu2a54bb72019-05-22 19:44:48 +0800868 return 0;
869}
870
871int conn_recv_socks4_proxy_response(struct connection *conn)
872{
873 char line[SOCKS4_HS_RSP_LEN];
874 int ret;
875
Alexander Liu2a54bb72019-05-22 19:44:48 +0800876 if (!conn_ctrl_ready(conn))
877 goto fail;
878
879 if (!fd_recv_ready(conn->handle.fd))
Willy Tarreau6499b9d2019-06-03 08:17:30 +0200880 goto not_ready;
Alexander Liu2a54bb72019-05-22 19:44:48 +0800881
Willy Tarreau157788c2020-02-11 10:08:05 +0100882 while (1) {
Alexander Liu2a54bb72019-05-22 19:44:48 +0800883 /* SOCKS4 Proxy will response with 8 bytes, 0x00 | 0x5A | 0x00 0x00 | 0x00 0x00 0x00 0x00
884 * Try to peek into it, before all 8 bytes ready.
885 */
886 ret = recv(conn->handle.fd, line, SOCKS4_HS_RSP_LEN, MSG_PEEK);
887
888 if (ret == 0) {
889 /* the socket has been closed or shutdown for send */
890 DPRINTF(stderr, "SOCKS PROXY HS FD[%04X]: Received ret[%d], errno[%d], looks like the socket has been closed or shutdown for send\n",
891 conn->handle.fd, ret, errno);
892 if (conn->err_code == CO_ER_NONE) {
893 conn->err_code = CO_ER_SOCKS4_RECV;
894 }
895 goto fail;
896 }
897
898 if (ret > 0) {
899 if (ret == SOCKS4_HS_RSP_LEN) {
900 DPRINTF(stderr, "SOCKS PROXY HS FD[%04X]: Received 8 bytes, the response is [%02X|%02X|%02X %02X|%02X %02X %02X %02X]\n",
901 conn->handle.fd, line[0], line[1], line[2], line[3], line[4], line[5], line[6], line[7]);
902 }else{
903 DPRINTF(stderr, "SOCKS PROXY HS FD[%04X]: Received ret[%d], first byte is [%02X], last bye is [%02X]\n", conn->handle.fd, ret, line[0], line[ret-1]);
904 }
905 } else {
906 DPRINTF(stderr, "SOCKS PROXY HS FD[%04X]: Received ret[%d], errno[%d]\n", conn->handle.fd, ret, errno);
907 }
908
909 if (ret < 0) {
910 if (errno == EINTR) {
911 continue;
912 }
913 if (errno == EAGAIN) {
914 fd_cant_recv(conn->handle.fd);
Willy Tarreau6499b9d2019-06-03 08:17:30 +0200915 goto not_ready;
Alexander Liu2a54bb72019-05-22 19:44:48 +0800916 }
917 goto recv_abort;
918 }
Willy Tarreau157788c2020-02-11 10:08:05 +0100919 break;
920 }
Alexander Liu2a54bb72019-05-22 19:44:48 +0800921
Willy Tarreauc192b0a2020-01-23 09:11:58 +0100922 conn->flags &= ~CO_FL_WAIT_L4_CONN;
923
Alexander Liu2a54bb72019-05-22 19:44:48 +0800924 if (ret < SOCKS4_HS_RSP_LEN) {
925 /* Missing data. Since we're using MSG_PEEK, we can only poll again if
926 * we are not able to read enough data.
927 */
Willy Tarreau6499b9d2019-06-03 08:17:30 +0200928 goto not_ready;
Alexander Liu2a54bb72019-05-22 19:44:48 +0800929 }
930
931 /*
932 * Base on the SOCSK4 protocol:
933 *
934 * +----+----+----+----+----+----+----+----+
935 * | VN | CD | DSTPORT | DSTIP |
936 * +----+----+----+----+----+----+----+----+
937 * # of bytes: 1 1 2 4
938 * VN is the version of the reply code and should be 0. CD is the result
939 * code with one of the following values:
940 * 90: request granted
941 * 91: request rejected or failed
Ilya Shipitsince7b00f2020-03-23 22:28:40 +0500942 * 92: request rejected because SOCKS server cannot connect to identd on the client
Alexander Liu2a54bb72019-05-22 19:44:48 +0800943 * 93: request rejected because the client program and identd report different user-ids
944 * The remaining fields are ignored.
945 */
946 if (line[1] != 90) {
947 conn->flags &= ~CO_FL_SOCKS4_RECV;
948
949 DPRINTF(stderr, "SOCKS PROXY HS FD[%04X]: FAIL, the response is [%02X|%02X|%02X %02X|%02X %02X %02X %02X]\n",
950 conn->handle.fd, line[0], line[1], line[2], line[3], line[4], line[5], line[6], line[7]);
951 if (conn->err_code == CO_ER_NONE) {
952 conn->err_code = CO_ER_SOCKS4_DENY;
953 }
954 goto fail;
955 }
956
957 /* remove the 8 bytes response from the stream */
Willy Tarreau157788c2020-02-11 10:08:05 +0100958 while (1) {
Alexander Liu2a54bb72019-05-22 19:44:48 +0800959 ret = recv(conn->handle.fd, line, SOCKS4_HS_RSP_LEN, 0);
960 if (ret < 0 && errno == EINTR) {
961 continue;
962 }
963 if (ret != SOCKS4_HS_RSP_LEN) {
964 if (conn->err_code == CO_ER_NONE) {
965 conn->err_code = CO_ER_SOCKS4_RECV;
966 }
967 goto fail;
968 }
Willy Tarreau157788c2020-02-11 10:08:05 +0100969 break;
970 }
Alexander Liu2a54bb72019-05-22 19:44:48 +0800971
972 conn->flags &= ~CO_FL_SOCKS4_RECV;
973 return 1;
974
Willy Tarreau6499b9d2019-06-03 08:17:30 +0200975 not_ready:
Willy Tarreau6499b9d2019-06-03 08:17:30 +0200976 return 0;
977
Alexander Liu2a54bb72019-05-22 19:44:48 +0800978 recv_abort:
979 if (conn->err_code == CO_ER_NONE) {
980 conn->err_code = CO_ER_SOCKS4_ABORT;
981 }
982 conn->flags |= (CO_FL_SOCK_RD_SH | CO_FL_SOCK_WR_SH);
983 goto fail;
984
985 fail:
Alexander Liu2a54bb72019-05-22 19:44:48 +0800986 conn->flags |= CO_FL_ERROR;
987 return 0;
988}
989
Willy Tarreaue59b5162021-05-08 14:06:09 +0200990/* Lists the known proto mux on <out> */
991void list_mux_proto(FILE *out)
992{
993 struct mux_proto_list *item;
994 struct buffer *chk = get_trash_chunk();
995 struct ist proto;
996 char *mode, *side;
997
998 fprintf(out, "Available multiplexer protocols :\n"
999 "(protocols marked as <default> cannot be specified using 'proto' keyword)\n");
1000 list_for_each_entry(item, &mux_proto_list.list, list) {
1001 proto = item->token;
1002
1003 if (item->mode == PROTO_MODE_ANY)
1004 mode = "TCP|HTTP";
1005 else if (item->mode == PROTO_MODE_TCP)
1006 mode = "TCP";
1007 else if (item->mode == PROTO_MODE_HTTP)
1008 mode = "HTTP";
1009 else
1010 mode = "NONE";
1011
1012 if (item->side == PROTO_SIDE_BOTH)
1013 side = "FE|BE";
1014 else if (item->side == PROTO_SIDE_FE)
1015 side = "FE";
1016 else if (item->side == PROTO_SIDE_BE)
1017 side = "BE";
1018 else
1019 side = "NONE";
1020
1021 chunk_reset(chk);
1022 if (item->mux->flags & MX_FL_HTX)
1023 chunk_strcpy(chk, "HTX");
1024 if (item->mux->flags & MX_FL_CLEAN_ABRT)
1025 chunk_appendf(chk, "%sCLEAN_ABRT", (b_data(chk) ? "|": ""));
1026 if (item->mux->flags & MX_FL_HOL_RISK)
1027 chunk_appendf(chk, "%sHOL_RISK", (b_data(chk) ? "|": ""));
1028 if (item->mux->flags & MX_FL_NO_UPG)
1029 chunk_appendf(chk, "%sNO_UPG", (b_data(chk) ? "|": ""));
1030
1031 fprintf(out, " %15s : mode=%-10s side=%-8s mux=%-8s flags=%.*s\n",
1032 (proto.len ? proto.ptr : "<default>"), mode, side, item->mux->name,
1033 (int)b_data(chk), b_orig(chk));
1034 }
1035}
1036
Ilya Shipitsinca56fce2018-09-15 00:50:05 +05001037/* Note: <remote> is explicitly allowed to be NULL */
Tim Duesterhuscf6e0c82020-03-13 12:34:24 +01001038int make_proxy_line(char *buf, int buf_len, struct server *srv, struct connection *remote, struct stream *strm)
David Safb76832014-05-08 23:42:08 -04001039{
1040 int ret = 0;
1041
1042 if (srv && (srv->pp_opts & SRV_PP_V2)) {
Tim Duesterhuscf6e0c82020-03-13 12:34:24 +01001043 ret = make_proxy_line_v2(buf, buf_len, srv, remote, strm);
David Safb76832014-05-08 23:42:08 -04001044 }
1045 else {
Willy Tarreau226572f2019-07-17 14:46:00 +02001046 if (remote && conn_get_src(remote) && conn_get_dst(remote))
1047 ret = make_proxy_line_v1(buf, buf_len, remote->src, remote->dst);
David Safb76832014-05-08 23:42:08 -04001048 else
1049 ret = make_proxy_line_v1(buf, buf_len, NULL, NULL);
1050 }
1051
1052 return ret;
1053}
1054
Willy Tarreaue1e4a612012-10-05 00:10:55 +02001055/* Makes a PROXY protocol line from the two addresses. The output is sent to
1056 * buffer <buf> for a maximum size of <buf_len> (including the trailing zero).
1057 * It returns the number of bytes composing this line (including the trailing
1058 * LF), or zero in case of failure (eg: not enough space). It supports TCP4,
Willy Tarreau2e1401a2013-10-01 11:41:55 +02001059 * TCP6 and "UNKNOWN" formats. If any of <src> or <dst> is null, UNKNOWN is
1060 * emitted as well.
Willy Tarreaue1e4a612012-10-05 00:10:55 +02001061 */
David Safb76832014-05-08 23:42:08 -04001062int make_proxy_line_v1(char *buf, int buf_len, struct sockaddr_storage *src, struct sockaddr_storage *dst)
Willy Tarreaue1e4a612012-10-05 00:10:55 +02001063{
1064 int ret = 0;
Tim Duesterhus7fec0212018-07-27 18:46:13 +02001065 char * protocol;
1066 char src_str[MAX(INET_ADDRSTRLEN, INET6_ADDRSTRLEN)];
1067 char dst_str[MAX(INET_ADDRSTRLEN, INET6_ADDRSTRLEN)];
1068 in_port_t src_port;
1069 in_port_t dst_port;
Willy Tarreaue1e4a612012-10-05 00:10:55 +02001070
Tim Duesterhus7fec0212018-07-27 18:46:13 +02001071 if ( !src
1072 || !dst
1073 || (src->ss_family != AF_INET && src->ss_family != AF_INET6)
1074 || (dst->ss_family != AF_INET && dst->ss_family != AF_INET6)) {
1075 /* unknown family combination */
1076 ret = snprintf(buf, buf_len, "PROXY UNKNOWN\r\n");
Willy Tarreaue1e4a612012-10-05 00:10:55 +02001077 if (ret >= buf_len)
1078 return 0;
1079
Tim Duesterhus7fec0212018-07-27 18:46:13 +02001080 return ret;
1081 }
Willy Tarreaue1e4a612012-10-05 00:10:55 +02001082
Tim Duesterhus7fec0212018-07-27 18:46:13 +02001083 /* IPv4 for both src and dst */
1084 if (src->ss_family == AF_INET && dst->ss_family == AF_INET) {
1085 protocol = "TCP4";
1086 if (!inet_ntop(AF_INET, &((struct sockaddr_in *)src)->sin_addr, src_str, sizeof(src_str)))
Willy Tarreaue1e4a612012-10-05 00:10:55 +02001087 return 0;
Tim Duesterhus7fec0212018-07-27 18:46:13 +02001088 src_port = ((struct sockaddr_in *)src)->sin_port;
1089 if (!inet_ntop(AF_INET, &((struct sockaddr_in *)dst)->sin_addr, dst_str, sizeof(dst_str)))
Willy Tarreaue1e4a612012-10-05 00:10:55 +02001090 return 0;
Tim Duesterhus7fec0212018-07-27 18:46:13 +02001091 dst_port = ((struct sockaddr_in *)dst)->sin_port;
Willy Tarreaue1e4a612012-10-05 00:10:55 +02001092 }
Tim Duesterhus7fec0212018-07-27 18:46:13 +02001093 /* IPv6 for at least one of src and dst */
1094 else {
1095 struct in6_addr tmp;
Willy Tarreaue1e4a612012-10-05 00:10:55 +02001096
Tim Duesterhus7fec0212018-07-27 18:46:13 +02001097 protocol = "TCP6";
Willy Tarreaue1e4a612012-10-05 00:10:55 +02001098
Tim Duesterhus7fec0212018-07-27 18:46:13 +02001099 if (src->ss_family == AF_INET) {
1100 /* Convert src to IPv6 */
1101 v4tov6(&tmp, &((struct sockaddr_in *)src)->sin_addr);
1102 src_port = ((struct sockaddr_in *)src)->sin_port;
1103 }
1104 else {
1105 tmp = ((struct sockaddr_in6 *)src)->sin6_addr;
1106 src_port = ((struct sockaddr_in6 *)src)->sin6_port;
1107 }
Willy Tarreaue1e4a612012-10-05 00:10:55 +02001108
Tim Duesterhus7fec0212018-07-27 18:46:13 +02001109 if (!inet_ntop(AF_INET6, &tmp, src_str, sizeof(src_str)))
Willy Tarreaue1e4a612012-10-05 00:10:55 +02001110 return 0;
1111
Tim Duesterhus7fec0212018-07-27 18:46:13 +02001112 if (dst->ss_family == AF_INET) {
1113 /* Convert dst to IPv6 */
1114 v4tov6(&tmp, &((struct sockaddr_in *)dst)->sin_addr);
1115 dst_port = ((struct sockaddr_in *)dst)->sin_port;
1116 }
1117 else {
1118 tmp = ((struct sockaddr_in6 *)dst)->sin6_addr;
1119 dst_port = ((struct sockaddr_in6 *)dst)->sin6_port;
1120 }
Willy Tarreaue1e4a612012-10-05 00:10:55 +02001121
Tim Duesterhus7fec0212018-07-27 18:46:13 +02001122 if (!inet_ntop(AF_INET6, &tmp, dst_str, sizeof(dst_str)))
Willy Tarreaue1e4a612012-10-05 00:10:55 +02001123 return 0;
1124 }
Tim Duesterhus7fec0212018-07-27 18:46:13 +02001125
1126 ret = snprintf(buf, buf_len, "PROXY %s %s %s %u %u\r\n", protocol, src_str, dst_str, ntohs(src_port), ntohs(dst_port));
1127 if (ret >= buf_len)
1128 return 0;
1129
Willy Tarreaue1e4a612012-10-05 00:10:55 +02001130 return ret;
1131}
David Safb76832014-05-08 23:42:08 -04001132
KOVACS Krisztianb3e54fe2014-11-17 15:11:45 +01001133static int make_tlv(char *dest, int dest_len, char type, uint16_t length, const char *value)
David Safb76832014-05-08 23:42:08 -04001134{
1135 struct tlv *tlv;
1136
1137 if (!dest || (length + sizeof(*tlv) > dest_len))
1138 return 0;
1139
1140 tlv = (struct tlv *)dest;
1141
1142 tlv->type = type;
1143 tlv->length_hi = length >> 8;
1144 tlv->length_lo = length & 0x00ff;
1145 memcpy(tlv->value, value, length);
1146 return length + sizeof(*tlv);
1147}
David Safb76832014-05-08 23:42:08 -04001148
Ilya Shipitsinca56fce2018-09-15 00:50:05 +05001149/* Note: <remote> is explicitly allowed to be NULL */
Tim Duesterhuscf6e0c82020-03-13 12:34:24 +01001150int make_proxy_line_v2(char *buf, int buf_len, struct server *srv, struct connection *remote, struct stream *strm)
David Safb76832014-05-08 23:42:08 -04001151{
Willy Tarreau8fccfa22014-06-14 08:28:06 +02001152 const char pp2_signature[] = PP2_SIGNATURE;
Emmanuel Hocdet4399c752018-02-05 15:26:43 +01001153 void *tlv_crc32c_p = NULL;
David Safb76832014-05-08 23:42:08 -04001154 int ret = 0;
Willy Tarreau8fccfa22014-06-14 08:28:06 +02001155 struct proxy_hdr_v2 *hdr = (struct proxy_hdr_v2 *)buf;
Vincent Bernat6e615892016-05-18 16:17:44 +02001156 struct sockaddr_storage null_addr = { .ss_family = 0 };
David Safb76832014-05-08 23:42:08 -04001157 struct sockaddr_storage *src = &null_addr;
1158 struct sockaddr_storage *dst = &null_addr;
Emmanuel Hocdet404d9782017-10-24 10:55:14 +02001159 const char *value;
1160 int value_len;
David Safb76832014-05-08 23:42:08 -04001161
1162 if (buf_len < PP2_HEADER_LEN)
1163 return 0;
Willy Tarreau8fccfa22014-06-14 08:28:06 +02001164 memcpy(hdr->sig, pp2_signature, PP2_SIGNATURE_LEN);
David Safb76832014-05-08 23:42:08 -04001165
Willy Tarreau226572f2019-07-17 14:46:00 +02001166 if (remote && conn_get_src(remote) && conn_get_dst(remote)) {
1167 src = remote->src;
1168 dst = remote->dst;
David Safb76832014-05-08 23:42:08 -04001169 }
KOVACS Krisztianb3e54fe2014-11-17 15:11:45 +01001170
Tim Duesterhus7fec0212018-07-27 18:46:13 +02001171 /* At least one of src or dst is not of AF_INET or AF_INET6 */
1172 if ( !src
1173 || !dst
Willy Tarreau119e50e2020-05-22 13:53:29 +02001174 || (!pp2_never_send_local && conn_is_back(remote)) // locally initiated connection
Tim Duesterhus7fec0212018-07-27 18:46:13 +02001175 || (src->ss_family != AF_INET && src->ss_family != AF_INET6)
1176 || (dst->ss_family != AF_INET && dst->ss_family != AF_INET6)) {
David Safb76832014-05-08 23:42:08 -04001177 if (buf_len < PP2_HDR_LEN_UNSPEC)
1178 return 0;
Willy Tarreau8fccfa22014-06-14 08:28:06 +02001179 hdr->ver_cmd = PP2_VERSION | PP2_CMD_LOCAL;
1180 hdr->fam = PP2_FAM_UNSPEC | PP2_TRANS_UNSPEC;
David Safb76832014-05-08 23:42:08 -04001181 ret = PP2_HDR_LEN_UNSPEC;
1182 }
Tim Duesterhus7fec0212018-07-27 18:46:13 +02001183 else {
Willy Tarreau02c88032020-04-14 12:54:10 +02001184 hdr->ver_cmd = PP2_VERSION | PP2_CMD_PROXY;
Tim Duesterhus7fec0212018-07-27 18:46:13 +02001185 /* IPv4 for both src and dst */
1186 if (src->ss_family == AF_INET && dst->ss_family == AF_INET) {
1187 if (buf_len < PP2_HDR_LEN_INET)
1188 return 0;
Tim Duesterhus7fec0212018-07-27 18:46:13 +02001189 hdr->fam = PP2_FAM_INET | PP2_TRANS_STREAM;
1190 hdr->addr.ip4.src_addr = ((struct sockaddr_in *)src)->sin_addr.s_addr;
1191 hdr->addr.ip4.src_port = ((struct sockaddr_in *)src)->sin_port;
1192 hdr->addr.ip4.dst_addr = ((struct sockaddr_in *)dst)->sin_addr.s_addr;
1193 hdr->addr.ip4.dst_port = ((struct sockaddr_in *)dst)->sin_port;
1194 ret = PP2_HDR_LEN_INET;
1195 }
1196 /* IPv6 for at least one of src and dst */
1197 else {
1198 struct in6_addr tmp;
1199
1200 if (buf_len < PP2_HDR_LEN_INET6)
1201 return 0;
Tim Duesterhus7fec0212018-07-27 18:46:13 +02001202 hdr->fam = PP2_FAM_INET6 | PP2_TRANS_STREAM;
1203 if (src->ss_family == AF_INET) {
1204 v4tov6(&tmp, &((struct sockaddr_in *)src)->sin_addr);
1205 memcpy(hdr->addr.ip6.src_addr, &tmp, 16);
1206 hdr->addr.ip6.src_port = ((struct sockaddr_in *)src)->sin_port;
1207 }
1208 else {
1209 memcpy(hdr->addr.ip6.src_addr, &((struct sockaddr_in6 *)src)->sin6_addr, 16);
1210 hdr->addr.ip6.src_port = ((struct sockaddr_in6 *)src)->sin6_port;
1211 }
1212 if (dst->ss_family == AF_INET) {
1213 v4tov6(&tmp, &((struct sockaddr_in *)dst)->sin_addr);
1214 memcpy(hdr->addr.ip6.dst_addr, &tmp, 16);
William Dauchybd8bf672020-01-26 19:06:39 +01001215 hdr->addr.ip6.dst_port = ((struct sockaddr_in *)dst)->sin_port;
Tim Duesterhus7fec0212018-07-27 18:46:13 +02001216 }
1217 else {
1218 memcpy(hdr->addr.ip6.dst_addr, &((struct sockaddr_in6 *)dst)->sin6_addr, 16);
1219 hdr->addr.ip6.dst_port = ((struct sockaddr_in6 *)dst)->sin6_port;
1220 }
1221
1222 ret = PP2_HDR_LEN_INET6;
1223 }
1224 }
David Safb76832014-05-08 23:42:08 -04001225
Emmanuel Hocdet4399c752018-02-05 15:26:43 +01001226 if (srv->pp_opts & SRV_PP_V2_CRC32C) {
1227 uint32_t zero_crc32c = 0;
Tim Duesterhusa8692f32020-03-13 12:34:25 +01001228
Emmanuel Hocdet4399c752018-02-05 15:26:43 +01001229 if ((buf_len - ret) < sizeof(struct tlv))
1230 return 0;
1231 tlv_crc32c_p = (void *)((struct tlv *)&buf[ret])->value;
1232 ret += make_tlv(&buf[ret], (buf_len - ret), PP2_TYPE_CRC32C, sizeof(zero_crc32c), (const char *)&zero_crc32c);
1233 }
1234
Ilya Shipitsinca56fce2018-09-15 00:50:05 +05001235 if (remote && conn_get_alpn(remote, &value, &value_len)) {
Emmanuel Hocdet404d9782017-10-24 10:55:14 +02001236 if ((buf_len - ret) < sizeof(struct tlv))
1237 return 0;
Emmanuel Hocdet571c7ac2017-10-31 18:24:05 +01001238 ret += make_tlv(&buf[ret], (buf_len - ret), PP2_TYPE_ALPN, value_len, value);
Emmanuel Hocdet404d9782017-10-24 10:55:14 +02001239 }
1240
Emmanuel Hocdet253c3b72018-02-01 18:29:59 +01001241 if (srv->pp_opts & SRV_PP_V2_AUTHORITY) {
Emmanuel Hocdet8a4ffa02019-08-29 11:54:51 +02001242 value = NULL;
Tim Duesterhus615f81e2021-03-06 20:06:50 +01001243 if (remote && isttest(remote->proxy_authority)) {
1244 value = istptr(remote->proxy_authority);
1245 value_len = istlen(remote->proxy_authority);
Emmanuel Hocdet8a4ffa02019-08-29 11:54:51 +02001246 }
1247#ifdef USE_OPENSSL
1248 else {
Jerome Magnin78891c72019-09-02 09:53:41 +02001249 if ((value = ssl_sock_get_sni(remote)))
Emmanuel Hocdet8a4ffa02019-08-29 11:54:51 +02001250 value_len = strlen(value);
1251 }
1252#endif
Emmanuel Hocdet253c3b72018-02-01 18:29:59 +01001253 if (value) {
1254 if ((buf_len - ret) < sizeof(struct tlv))
1255 return 0;
Emmanuel Hocdet8a4ffa02019-08-29 11:54:51 +02001256 ret += make_tlv(&buf[ret], (buf_len - ret), PP2_TYPE_AUTHORITY, value_len, value);
Emmanuel Hocdet253c3b72018-02-01 18:29:59 +01001257 }
1258 }
1259
Christopher Faulet3ab504f2020-05-26 15:16:01 +02001260 if (strm && (srv->pp_opts & SRV_PP_V2_UNIQUE_ID)) {
Tim Duesterhuscf6e0c82020-03-13 12:34:24 +01001261 struct session* sess = strm_sess(strm);
1262 struct ist unique_id = stream_generate_unique_id(strm, &sess->fe->format_unique_id);
1263
1264 value = unique_id.ptr;
1265 value_len = unique_id.len;
1266
1267 if (value_len >= 0) {
1268 if ((buf_len - ret) < sizeof(struct tlv))
1269 return 0;
1270 ret += make_tlv(&buf[ret], (buf_len - ret), PP2_TYPE_UNIQUE_ID, value_len, value);
1271 }
1272 }
1273
Emmanuel Hocdet8a4ffa02019-08-29 11:54:51 +02001274#ifdef USE_OPENSSL
David Safb76832014-05-08 23:42:08 -04001275 if (srv->pp_opts & SRV_PP_V2_SSL) {
Emmanuel Hocdet404d9782017-10-24 10:55:14 +02001276 struct tlv_ssl *tlv;
1277 int ssl_tlv_len = 0;
Tim Duesterhusa8692f32020-03-13 12:34:25 +01001278
David Safb76832014-05-08 23:42:08 -04001279 if ((buf_len - ret) < sizeof(struct tlv_ssl))
1280 return 0;
1281 tlv = (struct tlv_ssl *)&buf[ret];
1282 memset(tlv, 0, sizeof(struct tlv_ssl));
1283 ssl_tlv_len += sizeof(struct tlv_ssl);
1284 tlv->tlv.type = PP2_TYPE_SSL;
1285 if (ssl_sock_is_ssl(remote)) {
1286 tlv->client |= PP2_CLIENT_SSL;
Emmanuel Hocdet01da5712017-10-13 16:59:49 +02001287 value = ssl_sock_get_proto_version(remote);
David Safb76832014-05-08 23:42:08 -04001288 if (value) {
Emmanuel Hocdet8c0c34b2018-02-28 12:02:14 +01001289 ssl_tlv_len += make_tlv(&buf[ret+ssl_tlv_len], (buf_len-ret-ssl_tlv_len), PP2_SUBTYPE_SSL_VERSION, strlen(value), value);
David Safb76832014-05-08 23:42:08 -04001290 }
Dave McCowan328fb582014-07-30 10:39:13 -04001291 if (ssl_sock_get_cert_used_sess(remote)) {
1292 tlv->client |= PP2_CLIENT_CERT_SESS;
David Safb76832014-05-08 23:42:08 -04001293 tlv->verify = htonl(ssl_sock_get_verify_result(remote));
Dave McCowan328fb582014-07-30 10:39:13 -04001294 if (ssl_sock_get_cert_used_conn(remote))
1295 tlv->client |= PP2_CLIENT_CERT_CONN;
David Safb76832014-05-08 23:42:08 -04001296 }
1297 if (srv->pp_opts & SRV_PP_V2_SSL_CN) {
Willy Tarreau83061a82018-07-13 11:56:34 +02001298 struct buffer *cn_trash = get_trash_chunk();
Willy Tarreau3b9a0c92014-07-19 06:37:33 +02001299 if (ssl_sock_get_remote_common_name(remote, cn_trash) > 0) {
Willy Tarreau843b7cb2018-07-13 10:54:26 +02001300 ssl_tlv_len += make_tlv(&buf[ret+ssl_tlv_len], (buf_len - ret - ssl_tlv_len), PP2_SUBTYPE_SSL_CN,
1301 cn_trash->data,
1302 cn_trash->area);
David Safb76832014-05-08 23:42:08 -04001303 }
1304 }
Emmanuel Hocdetfa8d0f12018-02-01 15:53:52 +01001305 if (srv->pp_opts & SRV_PP_V2_SSL_KEY_ALG) {
Willy Tarreau83061a82018-07-13 11:56:34 +02001306 struct buffer *pkey_trash = get_trash_chunk();
Emmanuel Hocdetfa8d0f12018-02-01 15:53:52 +01001307 if (ssl_sock_get_pkey_algo(remote, pkey_trash) > 0) {
Willy Tarreau843b7cb2018-07-13 10:54:26 +02001308 ssl_tlv_len += make_tlv(&buf[ret+ssl_tlv_len], (buf_len - ret - ssl_tlv_len), PP2_SUBTYPE_SSL_KEY_ALG,
1309 pkey_trash->data,
1310 pkey_trash->area);
Emmanuel Hocdetfa8d0f12018-02-01 15:53:52 +01001311 }
1312 }
1313 if (srv->pp_opts & SRV_PP_V2_SSL_SIG_ALG) {
1314 value = ssl_sock_get_cert_sig(remote);
1315 if (value) {
1316 ssl_tlv_len += make_tlv(&buf[ret+ssl_tlv_len], (buf_len - ret - ssl_tlv_len), PP2_SUBTYPE_SSL_SIG_ALG, strlen(value), value);
1317 }
1318 }
1319 if (srv->pp_opts & SRV_PP_V2_SSL_CIPHER) {
1320 value = ssl_sock_get_cipher_name(remote);
1321 if (value) {
1322 ssl_tlv_len += make_tlv(&buf[ret+ssl_tlv_len], (buf_len - ret - ssl_tlv_len), PP2_SUBTYPE_SSL_CIPHER, strlen(value), value);
1323 }
1324 }
David Safb76832014-05-08 23:42:08 -04001325 }
1326 tlv->tlv.length_hi = (uint16_t)(ssl_tlv_len - sizeof(struct tlv)) >> 8;
1327 tlv->tlv.length_lo = (uint16_t)(ssl_tlv_len - sizeof(struct tlv)) & 0x00ff;
1328 ret += ssl_tlv_len;
1329 }
1330#endif
1331
Willy Tarreaue5733232019-05-22 19:24:06 +02001332#ifdef USE_NS
KOVACS Krisztianb3e54fe2014-11-17 15:11:45 +01001333 if (remote && (remote->proxy_netns)) {
1334 if ((buf_len - ret) < sizeof(struct tlv))
1335 return 0;
Emmanuel Hocdet571c7ac2017-10-31 18:24:05 +01001336 ret += make_tlv(&buf[ret], (buf_len - ret), PP2_TYPE_NETNS, remote->proxy_netns->name_len, remote->proxy_netns->node.key);
KOVACS Krisztianb3e54fe2014-11-17 15:11:45 +01001337 }
1338#endif
1339
Willy Tarreau8fccfa22014-06-14 08:28:06 +02001340 hdr->len = htons((uint16_t)(ret - PP2_HEADER_LEN));
David Safb76832014-05-08 23:42:08 -04001341
Emmanuel Hocdet4399c752018-02-05 15:26:43 +01001342 if (tlv_crc32c_p) {
1343 write_u32(tlv_crc32c_p, htonl(hash_crc32c(buf, ret)));
1344 }
1345
David Safb76832014-05-08 23:42:08 -04001346 return ret;
1347}
Emeric Brun4f603012017-01-05 15:11:44 +01001348
Willy Tarreau119e50e2020-05-22 13:53:29 +02001349/* returns 0 on success */
1350static int cfg_parse_pp2_never_send_local(char **args, int section_type, struct proxy *curpx,
Willy Tarreau01825162021-03-09 09:53:46 +01001351 const struct proxy *defpx, const char *file, int line,
Willy Tarreau119e50e2020-05-22 13:53:29 +02001352 char **err)
1353{
1354 if (too_many_args(0, args, err, NULL))
1355 return -1;
1356 pp2_never_send_local = 1;
1357 return 0;
1358}
1359
Willy Tarreaua7d14552021-06-16 17:35:20 +02001360/* extracts some info from the connection and appends them to buffer <buf>. The
1361 * connection's pointer, its direction, target (fe/be/srv), xprt/ctrl, source
1362 * when set, destination when set, are printed in a compact human-readable format
1363 * fitting on a single line. This is handy to complete traces or debug output.
1364 * It is permitted to pass a NULL conn pointer. The number of characters emitted
1365 * is returned. A prefix <pfx> might be prepended before the first field if not
1366 * NULL.
1367 */
1368int conn_append_debug_info(struct buffer *buf, const struct connection *conn, const char *pfx)
1369{
1370 const struct listener *li;
1371 const struct server *sv;
1372 const struct proxy *px;
1373 char addr[40];
1374 int old_len = buf->data;
1375
1376 if (!conn)
1377 return 0;
1378
1379 chunk_appendf(buf, "%sconn=%p(%s)", pfx ? pfx : "", conn, conn_is_back(conn) ? "OUT" : "IN");
1380
1381 if ((li = objt_listener(conn->target)))
1382 chunk_appendf(buf, " fe=%s", li->bind_conf->frontend->id);
1383 else if ((sv = objt_server(conn->target)))
1384 chunk_appendf(buf, " sv=%s/%s", sv->proxy->id, sv->id);
1385 else if ((px = objt_proxy(conn->target)))
1386 chunk_appendf(buf, " be=%s", px->id);
1387
1388 chunk_appendf(buf, " %s/%s", conn_get_xprt_name(conn), conn_get_ctrl_name(conn));
1389
1390 if (conn->flags & CO_FL_ADDR_FROM_SET && addr_to_str(conn->src, addr, sizeof(addr)))
1391 chunk_appendf(buf, " src=%s:%d", addr, get_host_port(conn->src));
1392
1393 if (conn->flags & CO_FL_ADDR_TO_SET && addr_to_str(conn->dst, addr, sizeof(addr)))
1394 chunk_appendf(buf, " dst=%s:%d", addr, get_host_port(conn->dst));
1395
1396 return buf->data - old_len;
1397}
1398
Willy Tarreau60ca10a2017-08-18 15:26:54 +02001399/* return the major HTTP version as 1 or 2 depending on how the request arrived
1400 * before being processed.
Christopher Fauletf4dd9ae2021-04-14 15:40:30 +02001401 *
1402 * WARNING: Should be updated if a new major HTTP version is added.
Willy Tarreau60ca10a2017-08-18 15:26:54 +02001403 */
1404static int
1405smp_fetch_fc_http_major(const struct arg *args, struct sample *smp, const char *kw, void *private)
1406{
Christopher Faulet242f8ce2021-04-14 15:46:49 +02001407 struct connection *conn = NULL;
1408
1409 if (obj_type(smp->sess->origin) == OBJ_TYPE_CHECK)
1410 conn = (kw[0] == 'b') ? cs_conn(__objt_check(smp->sess->origin)->cs) : NULL;
1411 else
1412 conn = (kw[0] != 'b') ? objt_conn(smp->sess->origin) :
1413 smp->strm ? cs_conn(objt_cs(smp->strm->si[1].end)) : NULL;
Willy Tarreau60ca10a2017-08-18 15:26:54 +02001414
Christopher Fauletf4dd9ae2021-04-14 15:40:30 +02001415 /* No connection or a connection with a RAW muxx */
1416 if (!conn || (conn->mux && !(conn->mux->flags & MX_FL_HTX)))
1417 return 0;
1418
1419 /* No mux install, this may change */
1420 if (!conn->mux) {
1421 smp->flags |= SMP_F_MAY_CHANGE;
1422 return 0;
1423 }
1424
Willy Tarreau60ca10a2017-08-18 15:26:54 +02001425 smp->data.type = SMP_T_SINT;
Christopher Fauletf4dd9ae2021-04-14 15:40:30 +02001426 smp->data.u.sint = (strcmp(conn_get_mux_name(conn), "H2") == 0) ? 2 : 1;
Willy Tarreau60ca10a2017-08-18 15:26:54 +02001427 return 1;
1428}
1429
Emeric Brun4f603012017-01-05 15:11:44 +01001430/* fetch if the received connection used a PROXY protocol header */
1431int smp_fetch_fc_rcvd_proxy(const struct arg *args, struct sample *smp, const char *kw, void *private)
1432{
1433 struct connection *conn;
1434
1435 conn = objt_conn(smp->sess->origin);
1436 if (!conn)
1437 return 0;
1438
Willy Tarreau911db9b2020-01-23 16:27:54 +01001439 if (conn->flags & CO_FL_WAIT_XPRT) {
Emeric Brun4f603012017-01-05 15:11:44 +01001440 smp->flags |= SMP_F_MAY_CHANGE;
1441 return 0;
1442 }
1443
1444 smp->flags = 0;
1445 smp->data.type = SMP_T_BOOL;
1446 smp->data.u.sint = (conn->flags & CO_FL_RCVD_PROXY) ? 1 : 0;
1447
1448 return 1;
1449}
1450
Geoff Simmons7185b782019-08-27 18:31:16 +02001451/* fetch the authority TLV from a PROXY protocol header */
1452int smp_fetch_fc_pp_authority(const struct arg *args, struct sample *smp, const char *kw, void *private)
1453{
1454 struct connection *conn;
1455
1456 conn = objt_conn(smp->sess->origin);
1457 if (!conn)
1458 return 0;
1459
Willy Tarreau911db9b2020-01-23 16:27:54 +01001460 if (conn->flags & CO_FL_WAIT_XPRT) {
Geoff Simmons7185b782019-08-27 18:31:16 +02001461 smp->flags |= SMP_F_MAY_CHANGE;
1462 return 0;
1463 }
1464
Tim Duesterhus615f81e2021-03-06 20:06:50 +01001465 if (!isttest(conn->proxy_authority))
Geoff Simmons7185b782019-08-27 18:31:16 +02001466 return 0;
1467
1468 smp->flags = 0;
1469 smp->data.type = SMP_T_STR;
Tim Duesterhus615f81e2021-03-06 20:06:50 +01001470 smp->data.u.str.area = istptr(conn->proxy_authority);
1471 smp->data.u.str.data = istlen(conn->proxy_authority);
Geoff Simmons7185b782019-08-27 18:31:16 +02001472
1473 return 1;
1474}
1475
Tim Duesterhusd1b15b62020-03-13 12:34:23 +01001476/* fetch the unique ID TLV from a PROXY protocol header */
1477int smp_fetch_fc_pp_unique_id(const struct arg *args, struct sample *smp, const char *kw, void *private)
1478{
1479 struct connection *conn;
1480
1481 conn = objt_conn(smp->sess->origin);
1482 if (!conn)
1483 return 0;
1484
1485 if (conn->flags & CO_FL_WAIT_XPRT) {
1486 smp->flags |= SMP_F_MAY_CHANGE;
1487 return 0;
1488 }
1489
1490 if (!isttest(conn->proxy_unique_id))
1491 return 0;
1492
1493 smp->flags = 0;
1494 smp->data.type = SMP_T_STR;
Tim Duesterhus002bd772021-03-06 20:06:49 +01001495 smp->data.u.str.area = istptr(conn->proxy_unique_id);
1496 smp->data.u.str.data = istlen(conn->proxy_unique_id);
Tim Duesterhusd1b15b62020-03-13 12:34:23 +01001497
1498 return 1;
1499}
1500
Emeric Brun4f603012017-01-05 15:11:44 +01001501/* Note: must not be declared <const> as its list will be overwritten.
1502 * Note: fetches that may return multiple types must be declared as the lowest
1503 * common denominator, the type that can be casted into all other ones. For
1504 * instance v4/v6 must be declared v4.
1505 */
1506static struct sample_fetch_kw_list sample_fetch_keywords = {ILH, {
Willy Tarreau60ca10a2017-08-18 15:26:54 +02001507 { "fc_http_major", smp_fetch_fc_http_major, 0, NULL, SMP_T_SINT, SMP_USE_L4CLI },
Jérôme Magnin86577422018-12-07 09:03:11 +01001508 { "bc_http_major", smp_fetch_fc_http_major, 0, NULL, SMP_T_SINT, SMP_USE_L4SRV },
Emeric Brun4f603012017-01-05 15:11:44 +01001509 { "fc_rcvd_proxy", smp_fetch_fc_rcvd_proxy, 0, NULL, SMP_T_BOOL, SMP_USE_L4CLI },
Geoff Simmons7185b782019-08-27 18:31:16 +02001510 { "fc_pp_authority", smp_fetch_fc_pp_authority, 0, NULL, SMP_T_STR, SMP_USE_L4CLI },
Tim Duesterhusd1b15b62020-03-13 12:34:23 +01001511 { "fc_pp_unique_id", smp_fetch_fc_pp_unique_id, 0, NULL, SMP_T_STR, SMP_USE_L4CLI },
Emeric Brun4f603012017-01-05 15:11:44 +01001512 { /* END */ },
1513}};
1514
Willy Tarreau0108d902018-11-25 19:14:37 +01001515INITCALL1(STG_REGISTER, sample_register_fetches, &sample_fetch_keywords);
Willy Tarreau119e50e2020-05-22 13:53:29 +02001516
1517static struct cfg_kw_list cfg_kws = {ILH, {
1518 { CFG_GLOBAL, "pp2-never-send-local", cfg_parse_pp2_never_send_local },
1519 { /* END */ },
1520}};
1521
1522INITCALL1(STG_REGISTER, cfg_register_keywords, &cfg_kws);
Amaury Denoyelle81c6f762021-01-18 14:57:50 +01001523
Amaury Denoyelle01a287f2021-02-11 16:46:53 +01001524/* private function to handle sockaddr as input for connection hash */
1525static void conn_calculate_hash_sockaddr(const struct sockaddr_storage *ss,
1526 char *buf, size_t *idx,
1527 enum conn_hash_params_t *hash_flags,
1528 enum conn_hash_params_t param_type_addr,
1529 enum conn_hash_params_t param_type_port)
1530{
1531 struct sockaddr_in *addr;
1532 struct sockaddr_in6 *addr6;
1533
1534 switch (ss->ss_family) {
1535 case AF_INET:
1536 addr = (struct sockaddr_in *)ss;
1537
1538 conn_hash_update(buf, idx,
1539 &addr->sin_addr, sizeof(addr->sin_addr),
1540 hash_flags, param_type_addr);
1541
1542 if (addr->sin_port) {
1543 conn_hash_update(buf, idx,
1544 &addr->sin_port, sizeof(addr->sin_port),
1545 hash_flags, param_type_port);
1546 }
1547
1548 break;
1549
1550 case AF_INET6:
1551 addr6 = (struct sockaddr_in6 *)ss;
1552
1553 conn_hash_update(buf, idx,
1554 &addr6->sin6_addr, sizeof(addr6->sin6_addr),
1555 hash_flags, param_type_addr);
1556
1557 if (addr6->sin6_port) {
1558 conn_hash_update(buf, idx,
1559 &addr6->sin6_port, sizeof(addr6->sin6_port),
1560 hash_flags, param_type_port);
1561 }
1562
1563 break;
1564 }
1565}
1566
Amaury Denoyelle81c6f762021-01-18 14:57:50 +01001567XXH64_hash_t conn_calculate_hash(const struct conn_hash_params *params)
1568{
1569 char *buf;
1570 size_t idx = 0;
1571 XXH64_hash_t hash = 0;
1572 enum conn_hash_params_t hash_flags = 0;
1573
1574 buf = trash.area;
1575
Amaury Denoyelle8ede3db2021-03-02 14:38:53 +01001576 conn_hash_update(buf, &idx, &params->target, sizeof(params->target), &hash_flags, 0);
Amaury Denoyelle1a58aca2021-01-22 16:47:46 +01001577
Amaury Denoyelle9b626e32021-01-06 17:03:27 +01001578 if (params->sni_prehash) {
1579 conn_hash_update(buf, &idx,
Amaury Denoyelle36441f42021-02-17 16:25:31 +01001580 &params->sni_prehash, sizeof(params->sni_prehash),
Amaury Denoyelle9b626e32021-01-06 17:03:27 +01001581 &hash_flags, CONN_HASH_PARAMS_TYPE_SNI);
1582 }
1583
Amaury Denoyelle01a287f2021-02-11 16:46:53 +01001584 if (params->dst_addr) {
1585 conn_calculate_hash_sockaddr(params->dst_addr,
1586 buf, &idx, &hash_flags,
1587 CONN_HASH_PARAMS_TYPE_DST_ADDR,
1588 CONN_HASH_PARAMS_TYPE_DST_PORT);
1589 }
1590
Amaury Denoyelled10a2002021-02-11 19:45:19 +01001591 if (params->src_addr) {
1592 conn_calculate_hash_sockaddr(params->src_addr,
1593 buf, &idx, &hash_flags,
1594 CONN_HASH_PARAMS_TYPE_SRC_ADDR,
1595 CONN_HASH_PARAMS_TYPE_SRC_PORT);
1596 }
1597
Amaury Denoyelle1921d202021-01-14 10:15:29 +01001598 if (params->proxy_prehash) {
1599 conn_hash_update(buf, &idx,
Amaury Denoyelle36441f42021-02-17 16:25:31 +01001600 &params->proxy_prehash, sizeof(params->proxy_prehash),
Amaury Denoyelle1921d202021-01-14 10:15:29 +01001601 &hash_flags, CONN_HASH_PARAMS_TYPE_PROXY);
1602 }
Amaury Denoyelle01a287f2021-02-11 16:46:53 +01001603
Amaury Denoyelle1921d202021-01-14 10:15:29 +01001604 hash = conn_hash_digest(buf, idx, hash_flags);
Amaury Denoyelle81c6f762021-01-18 14:57:50 +01001605 return hash;
1606}