blob: 9e710c3f948acb7f0b4025d1d40f629acd06a644 [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 }
Amaury Denoyelle60378872021-10-28 16:36:11 +020064 else if (conn_install_mux_be(conn, conn->ctx, sess, NULL) < 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
Amaury Denoyelle92621012021-10-18 14:32:36 +020091/* Set the ALPN of connection <conn> to <alpn>. If force is false, <alpn> must
92 * be a subset or identical to the registered protos for the parent SSL_CTX.
93 * In this case <alpn> must be a single protocol value, not a list.
94 *
95 * Returns 0 if ALPN is updated else -1.
96 */
97int conn_update_alpn(struct connection *conn, const struct ist alpn, int force)
98{
99#ifdef TLSEXT_TYPE_application_layer_protocol_negotiation
100 size_t alpn_len = istlen(alpn);
101 char *ctx_alpn_str = NULL;
102 int ctx_alpn_len = 0, found = 0;
103
104 /* if not force, first search if alpn is a subset or identical to the
105 * parent SSL_CTX.
106 */
107 if (!force) {
108 /* retrieve the SSL_CTX according to the connection side. */
109 if (conn_is_back(conn)) {
110 if (obj_type(conn->target) == OBJ_TYPE_SERVER) {
111 struct server *srv = __objt_server(conn->target);
112 ctx_alpn_str = srv->ssl_ctx.alpn_str;
113 ctx_alpn_len = srv->ssl_ctx.alpn_len;
114 }
115 }
116 else {
117 struct session *sess = conn->owner;
118 struct listener *li = sess->listener;
119
120 if (li->bind_conf && li->bind_conf->is_ssl) {
121 ctx_alpn_str = li->bind_conf->ssl_conf.alpn_str;
122 ctx_alpn_len = li->bind_conf->ssl_conf.alpn_len;
123 }
124 }
125
126 if (ctx_alpn_str) {
127 /* search if ALPN is present in SSL_CTX ALPN before
128 * using it.
129 */
130 while (ctx_alpn_len) {
131 /* skip ALPN whose size is not 8 */
132 if (*ctx_alpn_str != alpn_len - 1) {
133 ctx_alpn_len -= *ctx_alpn_str + 1;
134 }
135 else {
136 if (isteqi(ist2(ctx_alpn_str, alpn_len), alpn)) {
137 found = 1;
138 break;
139 }
140 }
141 ctx_alpn_str += *ctx_alpn_str + 1;
142
143 /* This indicates an invalid ALPN formatted
144 * string and should never happen. */
145 BUG_ON(ctx_alpn_len < 0);
146 }
147 }
148 }
149
150 if (found || force) {
151 ssl_sock_set_alpn(conn, (const uchar *)istptr(alpn), istlen(alpn));
152 return 0;
153 }
154
155#endif
156 return -1;
157}
158
Willy Tarreauff3e6482015-03-12 23:56:52 +0100159/* Send a message over an established connection. It makes use of send() and
160 * returns the same return code and errno. If the socket layer is not ready yet
161 * then -1 is returned and ENOTSOCK is set into errno. If the fd is not marked
162 * as ready, or if EAGAIN or ENOTCONN is returned, then we return 0. It returns
163 * EMSGSIZE if called with a zero length message. The purpose is to simplify
164 * some rare attempts to directly write on the socket from above the connection
165 * (typically send_proxy). In case of EAGAIN, the fd is marked as "cant_send".
166 * It automatically retries on EINTR. Other errors cause the connection to be
167 * marked as in error state. It takes similar arguments as send() except the
Willy Tarreau827fee72020-12-11 15:26:55 +0100168 * first one which is the connection instead of the file descriptor. <flags>
169 * only support CO_SFL_MSG_MORE.
Willy Tarreauff3e6482015-03-12 23:56:52 +0100170 */
Willy Tarreau827fee72020-12-11 15:26:55 +0100171int conn_ctrl_send(struct connection *conn, const void *buf, int len, int flags)
Willy Tarreauff3e6482015-03-12 23:56:52 +0100172{
Willy Tarreau827fee72020-12-11 15:26:55 +0100173 const struct buffer buffer = b_make((char*)buf, len, 0, len);
174 const struct xprt_ops *xprt = xprt_get(XPRT_RAW);
Willy Tarreauff3e6482015-03-12 23:56:52 +0100175 int ret;
176
177 ret = -1;
178 errno = ENOTSOCK;
179
180 if (conn->flags & CO_FL_SOCK_WR_SH)
181 goto fail;
182
183 if (!conn_ctrl_ready(conn))
184 goto fail;
185
186 errno = EMSGSIZE;
187 if (!len)
188 goto fail;
189
Willy Tarreau827fee72020-12-11 15:26:55 +0100190 /* snd_buf() already takes care of updating conn->flags and handling
191 * the FD polling status.
192 */
193 ret = xprt->snd_buf(conn, NULL, &buffer, buffer.data, flags);
194 if (conn->flags & CO_FL_ERROR)
195 ret = -1;
196 return ret;
Willy Tarreauff3e6482015-03-12 23:56:52 +0100197 fail:
198 conn->flags |= CO_FL_SOCK_RD_SH | CO_FL_SOCK_WR_SH | CO_FL_ERROR;
199 return ret;
200}
201
Willy Tarreau746b0512020-12-11 17:06:11 +0100202/* Called from the upper layer, to unsubscribe <es> from events <event_type>.
203 * The event subscriber <es> is not allowed to change from a previous call as
204 * long as at least one event is still subscribed. The <event_type> must only
205 * be a combination of SUB_RETRY_RECV and SUB_RETRY_SEND. It always returns 0.
Willy Tarreauee1a6fc2020-01-17 07:52:13 +0100206 */
207int conn_unsubscribe(struct connection *conn, void *xprt_ctx, int event_type, struct wait_event *es)
Olivier Houchard83a0cd82018-09-28 17:57:58 +0200208{
Willy Tarreau7872d1f2020-01-10 07:06:05 +0100209 BUG_ON(event_type & ~(SUB_RETRY_SEND|SUB_RETRY_RECV));
Willy Tarreauee1a6fc2020-01-17 07:52:13 +0100210 BUG_ON(conn->subs && conn->subs != es);
Willy Tarreau7872d1f2020-01-10 07:06:05 +0100211
Willy Tarreauee1a6fc2020-01-17 07:52:13 +0100212 es->events &= ~event_type;
213 if (!es->events)
Willy Tarreau7872d1f2020-01-10 07:06:05 +0100214 conn->subs = NULL;
215
Willy Tarreau746b0512020-12-11 17:06:11 +0100216 if (conn_ctrl_ready(conn) && conn->ctrl->ignore_events)
217 conn->ctrl->ignore_events(conn, event_type);
Willy Tarreau7872d1f2020-01-10 07:06:05 +0100218
Olivier Houchard83a0cd82018-09-28 17:57:58 +0200219 return 0;
220}
221
Willy Tarreau7e59c0a2020-02-28 14:24:49 +0100222/* Called from the upper layer, to subscribe <es> to events <event_type>.
223 * The <es> struct is not allowed to differ from the one passed during a
Willy Tarreau746b0512020-12-11 17:06:11 +0100224 * previous call to subscribe(). If the connection's ctrl layer is ready,
225 * the wait_event is immediately woken up and the subcription is cancelled.
226 * It always returns zero.
Willy Tarreauee1a6fc2020-01-17 07:52:13 +0100227 */
228int conn_subscribe(struct connection *conn, void *xprt_ctx, int event_type, struct wait_event *es)
Olivier Houchard6ff20392018-07-17 18:46:31 +0200229{
Willy Tarreau746b0512020-12-11 17:06:11 +0100230 int ret = 0;
231
Willy Tarreau7872d1f2020-01-10 07:06:05 +0100232 BUG_ON(event_type & ~(SUB_RETRY_SEND|SUB_RETRY_RECV));
Willy Tarreauee1a6fc2020-01-17 07:52:13 +0100233 BUG_ON(conn->subs && conn->subs != es);
Willy Tarreau7872d1f2020-01-10 07:06:05 +0100234
Willy Tarreau7e59c0a2020-02-28 14:24:49 +0100235 if (conn->subs && (conn->subs->events & event_type) == event_type)
236 return 0;
237
Willy Tarreau746b0512020-12-11 17:06:11 +0100238 if (conn_ctrl_ready(conn) && conn->ctrl->check_events) {
239 ret = conn->ctrl->check_events(conn, event_type);
240 if (ret)
241 tasklet_wakeup(es->tasklet);
Willy Tarreaud1d14c32020-02-21 10:34:19 +0100242 }
Willy Tarreau746b0512020-12-11 17:06:11 +0100243
244 es->events = (es->events | event_type) & ~ret;
245 conn->subs = es->events ? es : NULL;
Olivier Houchard83a0cd82018-09-28 17:57:58 +0200246 return 0;
Olivier Houchard6ff20392018-07-17 18:46:31 +0200247}
248
Willy Tarreau2ded48d2020-12-11 16:20:34 +0100249/* Drains possibly pending incoming data on the connection and update the flags
250 * accordingly. This is used to know whether we need to disable lingering on
251 * close. Returns non-zero if it is safe to close without disabling lingering,
252 * otherwise zero. The CO_FL_SOCK_RD_SH flag may also be updated if the incoming
253 * shutdown was reported by the ->drain() function.
Willy Tarreaud85c4852015-03-13 00:40:28 +0100254 */
Willy Tarreau2ded48d2020-12-11 16:20:34 +0100255int conn_ctrl_drain(struct connection *conn)
Willy Tarreaud85c4852015-03-13 00:40:28 +0100256{
Willy Tarreau2ded48d2020-12-11 16:20:34 +0100257 int ret = 0;
Willy Tarreaue215bba2018-08-24 14:31:53 +0200258
Willy Tarreau2ded48d2020-12-11 16:20:34 +0100259 if (!conn_ctrl_ready(conn) || conn->flags & (CO_FL_ERROR | CO_FL_SOCK_RD_SH))
260 ret = 1;
261 else if (conn->ctrl->drain) {
262 ret = conn->ctrl->drain(conn);
263 if (ret)
264 conn->flags |= CO_FL_SOCK_RD_SH;
Willy Tarreaud85c4852015-03-13 00:40:28 +0100265 }
Willy Tarreau2ded48d2020-12-11 16:20:34 +0100266 return ret;
Willy Tarreaud85c4852015-03-13 00:40:28 +0100267}
268
KOVACS Krisztianb3e54fe2014-11-17 15:11:45 +0100269/*
270 * Get data length from tlv
271 */
Tim Duesterhusba837ec2020-03-05 23:11:02 +0100272static inline size_t get_tlv_length(const struct tlv *src)
KOVACS Krisztianb3e54fe2014-11-17 15:11:45 +0100273{
274 return (src->length_hi << 8) | src->length_lo;
275}
276
Willy Tarreaue1e4a612012-10-05 00:10:55 +0200277/* This handshake handler waits a PROXY protocol header at the beginning of the
278 * raw data stream. The header looks like this :
279 *
280 * "PROXY" <SP> PROTO <SP> SRC3 <SP> DST3 <SP> SRC4 <SP> <DST4> "\r\n"
281 *
282 * There must be exactly one space between each field. Fields are :
283 * - PROTO : layer 4 protocol, which must be "TCP4" or "TCP6".
284 * - SRC3 : layer 3 (eg: IP) source address in standard text form
285 * - DST3 : layer 3 (eg: IP) destination address in standard text form
286 * - SRC4 : layer 4 (eg: TCP port) source address in standard text form
287 * - DST4 : layer 4 (eg: TCP port) destination address in standard text form
288 *
289 * This line MUST be at the beginning of the buffer and MUST NOT wrap.
290 *
291 * The header line is small and in all cases smaller than the smallest normal
292 * TCP MSS. So it MUST always be delivered as one segment, which ensures we
293 * can safely use MSG_PEEK and avoid buffering.
294 *
295 * Once the data is fetched, the values are set in the connection's address
296 * fields, and data are removed from the socket's buffer. The function returns
297 * zero if it needs to wait for more data or if it fails, or 1 if it completed
298 * and removed itself.
299 */
300int conn_recv_proxy(struct connection *conn, int flag)
301{
302 char *line, *end;
Willy Tarreau77992672014-06-14 11:06:17 +0200303 struct proxy_hdr_v2 *hdr_v2;
304 const char v2sig[] = PP2_SIGNATURE;
Tim Duesterhus488ee7f2020-03-05 22:55:20 +0100305 size_t total_v2_len;
Tim Duesterhusba837ec2020-03-05 23:11:02 +0100306 size_t tlv_offset = 0;
Willy Tarreaub406b872018-08-22 05:20:32 +0200307 int ret;
Willy Tarreaue1e4a612012-10-05 00:10:55 +0200308
Willy Tarreau3c728722014-01-23 13:50:42 +0100309 if (!conn_ctrl_ready(conn))
Willy Tarreauf79c8172013-10-21 16:30:56 +0200310 goto fail;
311
Willy Tarreau9b7587a2020-10-15 07:32:10 +0200312 if (!sockaddr_alloc(&conn->src, NULL, 0) || !sockaddr_alloc(&conn->dst, NULL, 0))
Willy Tarreauca79f592019-07-17 19:04:47 +0200313 goto fail;
314
Willy Tarreau585744b2017-08-24 14:31:19 +0200315 if (!fd_recv_ready(conn->handle.fd))
Willy Tarreau6499b9d2019-06-03 08:17:30 +0200316 goto not_ready;
Willy Tarreaufd803bb2014-01-20 15:13:07 +0100317
Willy Tarreau157788c2020-02-11 10:08:05 +0100318 while (1) {
Willy Tarreaub406b872018-08-22 05:20:32 +0200319 ret = recv(conn->handle.fd, trash.area, trash.size, MSG_PEEK);
320 if (ret < 0) {
Willy Tarreaue1e4a612012-10-05 00:10:55 +0200321 if (errno == EINTR)
322 continue;
323 if (errno == EAGAIN) {
Willy Tarreau585744b2017-08-24 14:31:19 +0200324 fd_cant_recv(conn->handle.fd);
Willy Tarreau6499b9d2019-06-03 08:17:30 +0200325 goto not_ready;
Willy Tarreaue1e4a612012-10-05 00:10:55 +0200326 }
Willy Tarreau8e3bf692012-12-03 15:41:18 +0100327 goto recv_abort;
Willy Tarreaue1e4a612012-10-05 00:10:55 +0200328 }
Willy Tarreaub406b872018-08-22 05:20:32 +0200329 trash.data = ret;
Willy Tarreau157788c2020-02-11 10:08:05 +0100330 break;
331 }
Willy Tarreaue1e4a612012-10-05 00:10:55 +0200332
Willy Tarreau843b7cb2018-07-13 10:54:26 +0200333 if (!trash.data) {
Willy Tarreau8e3bf692012-12-03 15:41:18 +0100334 /* client shutdown */
335 conn->err_code = CO_ER_PRX_EMPTY;
336 goto fail;
337 }
338
Willy Tarreauc192b0a2020-01-23 09:11:58 +0100339 conn->flags &= ~CO_FL_WAIT_L4_CONN;
340
Willy Tarreau843b7cb2018-07-13 10:54:26 +0200341 if (trash.data < 6)
Willy Tarreaue1e4a612012-10-05 00:10:55 +0200342 goto missing;
343
Willy Tarreau843b7cb2018-07-13 10:54:26 +0200344 line = trash.area;
345 end = trash.area + trash.data;
Willy Tarreaue1e4a612012-10-05 00:10:55 +0200346
347 /* Decode a possible proxy request, fail early if it does not match */
Willy Tarreau77992672014-06-14 11:06:17 +0200348 if (strncmp(line, "PROXY ", 6) != 0)
349 goto not_v1;
Willy Tarreaue1e4a612012-10-05 00:10:55 +0200350
351 line += 6;
Willy Tarreau843b7cb2018-07-13 10:54:26 +0200352 if (trash.data < 9) /* shortest possible line */
Willy Tarreaue1e4a612012-10-05 00:10:55 +0200353 goto missing;
354
David CARLIER42ff05e2016-03-24 09:22:36 +0000355 if (memcmp(line, "TCP4 ", 5) == 0) {
Willy Tarreaue1e4a612012-10-05 00:10:55 +0200356 u32 src3, dst3, sport, dport;
357
358 line += 5;
359
360 src3 = inetaddr_host_lim_ret(line, end, &line);
361 if (line == end)
362 goto missing;
363 if (*line++ != ' ')
Willy Tarreau8e3bf692012-12-03 15:41:18 +0100364 goto bad_header;
Willy Tarreaue1e4a612012-10-05 00:10:55 +0200365
366 dst3 = inetaddr_host_lim_ret(line, end, &line);
367 if (line == end)
368 goto missing;
369 if (*line++ != ' ')
Willy Tarreau8e3bf692012-12-03 15:41:18 +0100370 goto bad_header;
Willy Tarreaue1e4a612012-10-05 00:10:55 +0200371
372 sport = read_uint((const char **)&line, end);
373 if (line == end)
374 goto missing;
375 if (*line++ != ' ')
Willy Tarreau8e3bf692012-12-03 15:41:18 +0100376 goto bad_header;
Willy Tarreaue1e4a612012-10-05 00:10:55 +0200377
378 dport = read_uint((const char **)&line, end);
379 if (line > end - 2)
380 goto missing;
381 if (*line++ != '\r')
Willy Tarreau8e3bf692012-12-03 15:41:18 +0100382 goto bad_header;
Willy Tarreaue1e4a612012-10-05 00:10:55 +0200383 if (*line++ != '\n')
Willy Tarreau8e3bf692012-12-03 15:41:18 +0100384 goto bad_header;
Willy Tarreaue1e4a612012-10-05 00:10:55 +0200385
386 /* update the session's addresses and mark them set */
Willy Tarreau226572f2019-07-17 14:46:00 +0200387 ((struct sockaddr_in *)conn->src)->sin_family = AF_INET;
388 ((struct sockaddr_in *)conn->src)->sin_addr.s_addr = htonl(src3);
389 ((struct sockaddr_in *)conn->src)->sin_port = htons(sport);
Willy Tarreaue1e4a612012-10-05 00:10:55 +0200390
Willy Tarreau226572f2019-07-17 14:46:00 +0200391 ((struct sockaddr_in *)conn->dst)->sin_family = AF_INET;
392 ((struct sockaddr_in *)conn->dst)->sin_addr.s_addr = htonl(dst3);
393 ((struct sockaddr_in *)conn->dst)->sin_port = htons(dport);
Willy Tarreaue1e4a612012-10-05 00:10:55 +0200394 conn->flags |= CO_FL_ADDR_FROM_SET | CO_FL_ADDR_TO_SET;
395 }
David CARLIER42ff05e2016-03-24 09:22:36 +0000396 else if (memcmp(line, "TCP6 ", 5) == 0) {
Willy Tarreaue1e4a612012-10-05 00:10:55 +0200397 u32 sport, dport;
398 char *src_s;
399 char *dst_s, *sport_s, *dport_s;
400 struct in6_addr src3, dst3;
401
402 line += 5;
403
404 src_s = line;
405 dst_s = sport_s = dport_s = NULL;
406 while (1) {
407 if (line > end - 2) {
408 goto missing;
409 }
410 else if (*line == '\r') {
411 *line = 0;
412 line++;
413 if (*line++ != '\n')
Willy Tarreau8e3bf692012-12-03 15:41:18 +0100414 goto bad_header;
Willy Tarreaue1e4a612012-10-05 00:10:55 +0200415 break;
416 }
417
418 if (*line == ' ') {
419 *line = 0;
420 if (!dst_s)
421 dst_s = line + 1;
422 else if (!sport_s)
423 sport_s = line + 1;
424 else if (!dport_s)
425 dport_s = line + 1;
426 }
427 line++;
428 }
429
430 if (!dst_s || !sport_s || !dport_s)
Willy Tarreau8e3bf692012-12-03 15:41:18 +0100431 goto bad_header;
Willy Tarreaue1e4a612012-10-05 00:10:55 +0200432
433 sport = read_uint((const char **)&sport_s,dport_s - 1);
434 if (*sport_s != 0)
Willy Tarreau8e3bf692012-12-03 15:41:18 +0100435 goto bad_header;
Willy Tarreaue1e4a612012-10-05 00:10:55 +0200436
437 dport = read_uint((const char **)&dport_s,line - 2);
438 if (*dport_s != 0)
Willy Tarreau8e3bf692012-12-03 15:41:18 +0100439 goto bad_header;
Willy Tarreaue1e4a612012-10-05 00:10:55 +0200440
441 if (inet_pton(AF_INET6, src_s, (void *)&src3) != 1)
Willy Tarreau8e3bf692012-12-03 15:41:18 +0100442 goto bad_header;
Willy Tarreaue1e4a612012-10-05 00:10:55 +0200443
444 if (inet_pton(AF_INET6, dst_s, (void *)&dst3) != 1)
Willy Tarreau8e3bf692012-12-03 15:41:18 +0100445 goto bad_header;
Willy Tarreaue1e4a612012-10-05 00:10:55 +0200446
447 /* update the session's addresses and mark them set */
Willy Tarreau226572f2019-07-17 14:46:00 +0200448 ((struct sockaddr_in6 *)conn->src)->sin6_family = AF_INET6;
449 memcpy(&((struct sockaddr_in6 *)conn->src)->sin6_addr, &src3, sizeof(struct in6_addr));
450 ((struct sockaddr_in6 *)conn->src)->sin6_port = htons(sport);
Willy Tarreaue1e4a612012-10-05 00:10:55 +0200451
Willy Tarreau226572f2019-07-17 14:46:00 +0200452 ((struct sockaddr_in6 *)conn->dst)->sin6_family = AF_INET6;
453 memcpy(&((struct sockaddr_in6 *)conn->dst)->sin6_addr, &dst3, sizeof(struct in6_addr));
454 ((struct sockaddr_in6 *)conn->dst)->sin6_port = htons(dport);
Willy Tarreaue1e4a612012-10-05 00:10:55 +0200455 conn->flags |= CO_FL_ADDR_FROM_SET | CO_FL_ADDR_TO_SET;
456 }
Willy Tarreau4c20d292014-06-14 11:41:36 +0200457 else if (memcmp(line, "UNKNOWN\r\n", 9) == 0) {
458 /* This can be a UNIX socket forwarded by an haproxy upstream */
459 line += 9;
460 }
Willy Tarreaue1e4a612012-10-05 00:10:55 +0200461 else {
Willy Tarreau4c20d292014-06-14 11:41:36 +0200462 /* The protocol does not match something known (TCP4/TCP6/UNKNOWN) */
Willy Tarreau8e3bf692012-12-03 15:41:18 +0100463 conn->err_code = CO_ER_PRX_BAD_PROTO;
Willy Tarreaue1e4a612012-10-05 00:10:55 +0200464 goto fail;
465 }
466
Willy Tarreau843b7cb2018-07-13 10:54:26 +0200467 trash.data = line - trash.area;
Willy Tarreau77992672014-06-14 11:06:17 +0200468 goto eat_header;
469
470 not_v1:
471 /* try PPv2 */
Willy Tarreau843b7cb2018-07-13 10:54:26 +0200472 if (trash.data < PP2_HEADER_LEN)
Willy Tarreau77992672014-06-14 11:06:17 +0200473 goto missing;
474
Willy Tarreau843b7cb2018-07-13 10:54:26 +0200475 hdr_v2 = (struct proxy_hdr_v2 *) trash.area;
Willy Tarreau77992672014-06-14 11:06:17 +0200476
477 if (memcmp(hdr_v2->sig, v2sig, PP2_SIGNATURE_LEN) != 0 ||
478 (hdr_v2->ver_cmd & PP2_VERSION_MASK) != PP2_VERSION) {
479 conn->err_code = CO_ER_PRX_NOT_HDR;
480 goto fail;
481 }
482
Tim Duesterhus488ee7f2020-03-05 22:55:20 +0100483 total_v2_len = PP2_HEADER_LEN + ntohs(hdr_v2->len);
484 if (trash.data < total_v2_len)
Willy Tarreau77992672014-06-14 11:06:17 +0200485 goto missing;
486
487 switch (hdr_v2->ver_cmd & PP2_CMD_MASK) {
488 case 0x01: /* PROXY command */
489 switch (hdr_v2->fam) {
490 case 0x11: /* TCPv4 */
KOVACS Krisztianefd3aa92014-11-19 10:53:20 +0100491 if (ntohs(hdr_v2->len) < PP2_ADDR_LEN_INET)
492 goto bad_header;
493
Willy Tarreau226572f2019-07-17 14:46:00 +0200494 ((struct sockaddr_in *)conn->src)->sin_family = AF_INET;
495 ((struct sockaddr_in *)conn->src)->sin_addr.s_addr = hdr_v2->addr.ip4.src_addr;
496 ((struct sockaddr_in *)conn->src)->sin_port = hdr_v2->addr.ip4.src_port;
497 ((struct sockaddr_in *)conn->dst)->sin_family = AF_INET;
498 ((struct sockaddr_in *)conn->dst)->sin_addr.s_addr = hdr_v2->addr.ip4.dst_addr;
499 ((struct sockaddr_in *)conn->dst)->sin_port = hdr_v2->addr.ip4.dst_port;
Willy Tarreau77992672014-06-14 11:06:17 +0200500 conn->flags |= CO_FL_ADDR_FROM_SET | CO_FL_ADDR_TO_SET;
KOVACS Krisztian7209c202015-07-03 14:09:10 +0200501 tlv_offset = PP2_HEADER_LEN + PP2_ADDR_LEN_INET;
Willy Tarreau77992672014-06-14 11:06:17 +0200502 break;
503 case 0x21: /* TCPv6 */
KOVACS Krisztianefd3aa92014-11-19 10:53:20 +0100504 if (ntohs(hdr_v2->len) < PP2_ADDR_LEN_INET6)
505 goto bad_header;
506
Willy Tarreau226572f2019-07-17 14:46:00 +0200507 ((struct sockaddr_in6 *)conn->src)->sin6_family = AF_INET6;
508 memcpy(&((struct sockaddr_in6 *)conn->src)->sin6_addr, hdr_v2->addr.ip6.src_addr, 16);
509 ((struct sockaddr_in6 *)conn->src)->sin6_port = hdr_v2->addr.ip6.src_port;
510 ((struct sockaddr_in6 *)conn->dst)->sin6_family = AF_INET6;
511 memcpy(&((struct sockaddr_in6 *)conn->dst)->sin6_addr, hdr_v2->addr.ip6.dst_addr, 16);
512 ((struct sockaddr_in6 *)conn->dst)->sin6_port = hdr_v2->addr.ip6.dst_port;
Willy Tarreau77992672014-06-14 11:06:17 +0200513 conn->flags |= CO_FL_ADDR_FROM_SET | CO_FL_ADDR_TO_SET;
KOVACS Krisztian7209c202015-07-03 14:09:10 +0200514 tlv_offset = PP2_HEADER_LEN + PP2_ADDR_LEN_INET6;
Willy Tarreau77992672014-06-14 11:06:17 +0200515 break;
516 }
KOVACS Krisztianb3e54fe2014-11-17 15:11:45 +0100517
518 /* TLV parsing */
Tim Duesterhus488ee7f2020-03-05 22:55:20 +0100519 while (tlv_offset < total_v2_len) {
520 struct tlv *tlv_packet;
Tim Duesterhus56c176a2021-03-06 20:06:51 +0100521 struct ist tlv;
KOVACS Krisztianb3e54fe2014-11-17 15:11:45 +0100522
Tim Duesterhus488ee7f2020-03-05 22:55:20 +0100523 /* Verify that we have at least TLV_HEADER_SIZE bytes left */
524 if (tlv_offset + TLV_HEADER_SIZE > total_v2_len)
525 goto bad_header;
526
527 tlv_packet = (struct tlv *) &trash.area[tlv_offset];
Tim Duesterhus56c176a2021-03-06 20:06:51 +0100528 tlv = ist2((const char *)tlv_packet->value, get_tlv_length(tlv_packet));
529 tlv_offset += istlen(tlv) + TLV_HEADER_SIZE;
Tim Duesterhus488ee7f2020-03-05 22:55:20 +0100530
531 /* Verify that the TLV length does not exceed the total PROXYv2 length */
532 if (tlv_offset > total_v2_len)
533 goto bad_header;
534
535 switch (tlv_packet->type) {
536 case PP2_TYPE_CRC32C: {
537 uint32_t n_crc32c;
538
539 /* Verify that this TLV is exactly 4 bytes long */
Tim Duesterhus56c176a2021-03-06 20:06:51 +0100540 if (istlen(tlv) != 4)
Tim Duesterhus488ee7f2020-03-05 22:55:20 +0100541 goto bad_header;
542
Tim Duesterhus56c176a2021-03-06 20:06:51 +0100543 n_crc32c = read_n32(istptr(tlv));
544 write_n32(istptr(tlv), 0); // compute with CRC==0
Tim Duesterhus488ee7f2020-03-05 22:55:20 +0100545
546 if (hash_crc32c(trash.area, total_v2_len) != n_crc32c)
547 goto bad_header;
548 break;
549 }
Willy Tarreaue5733232019-05-22 19:24:06 +0200550#ifdef USE_NS
Tim Duesterhus488ee7f2020-03-05 22:55:20 +0100551 case PP2_TYPE_NETNS: {
552 const struct netns_entry *ns;
553
Tim Duesterhus56c176a2021-03-06 20:06:51 +0100554 ns = netns_store_lookup(istptr(tlv), istlen(tlv));
Tim Duesterhus488ee7f2020-03-05 22:55:20 +0100555 if (ns)
556 conn->proxy_netns = ns;
557 break;
558 }
KOVACS Krisztianb3e54fe2014-11-17 15:11:45 +0100559#endif
Tim Duesterhus488ee7f2020-03-05 22:55:20 +0100560 case PP2_TYPE_AUTHORITY: {
Tim Duesterhus615f81e2021-03-06 20:06:50 +0100561 if (istlen(tlv) > PP2_AUTHORITY_MAX)
Tim Duesterhus488ee7f2020-03-05 22:55:20 +0100562 goto bad_header;
Tim Duesterhus615f81e2021-03-06 20:06:50 +0100563 conn->proxy_authority = ist2(pool_alloc(pool_head_authority), 0);
564 if (!isttest(conn->proxy_authority))
Tim Duesterhus488ee7f2020-03-05 22:55:20 +0100565 goto fail;
Tim Duesterhus615f81e2021-03-06 20:06:50 +0100566 if (istcpy(&conn->proxy_authority, tlv, PP2_AUTHORITY_MAX) < 0) {
567 /* This is technically unreachable, because we verified above
568 * that the TLV value fits.
569 */
570 goto fail;
571 }
Tim Duesterhus488ee7f2020-03-05 22:55:20 +0100572 break;
573 }
Tim Duesterhusd1b15b62020-03-13 12:34:23 +0100574 case PP2_TYPE_UNIQUE_ID: {
Tim Duesterhus002bd772021-03-06 20:06:49 +0100575 if (istlen(tlv) > UNIQUEID_LEN)
Tim Duesterhusd1b15b62020-03-13 12:34:23 +0100576 goto bad_header;
Tim Duesterhus2b7f6c22020-03-14 13:07:05 +0100577 conn->proxy_unique_id = ist2(pool_alloc(pool_head_uniqueid), 0);
Tim Duesterhusd1b15b62020-03-13 12:34:23 +0100578 if (!isttest(conn->proxy_unique_id))
579 goto fail;
580 if (istcpy(&conn->proxy_unique_id, tlv, UNIQUEID_LEN) < 0) {
581 /* This is technically unreachable, because we verified above
582 * that the TLV value fits.
583 */
584 goto fail;
585 }
586 break;
587 }
Tim Duesterhus488ee7f2020-03-05 22:55:20 +0100588 default:
589 break;
KOVACS Krisztianb3e54fe2014-11-17 15:11:45 +0100590 }
591 }
592
Tim Duesterhus488ee7f2020-03-05 22:55:20 +0100593 /* Verify that the PROXYv2 header ends at a TLV boundary.
594 * This is technically unreachable, because the TLV parsing already
595 * verifies that a TLV does not exceed the total length and also
596 * that there is space for a TLV header.
597 */
598 if (tlv_offset != total_v2_len)
599 goto bad_header;
600
Willy Tarreau77992672014-06-14 11:06:17 +0200601 /* unsupported protocol, keep local connection address */
602 break;
603 case 0x00: /* LOCAL command */
604 /* keep local connection address for LOCAL */
605 break;
606 default:
607 goto bad_header; /* not a supported command */
608 }
609
Tim Duesterhus488ee7f2020-03-05 22:55:20 +0100610 trash.data = total_v2_len;
Willy Tarreau77992672014-06-14 11:06:17 +0200611 goto eat_header;
612
613 eat_header:
Willy Tarreaue1e4a612012-10-05 00:10:55 +0200614 /* remove the PROXY line from the request. For this we re-read the
615 * exact line at once. If we don't get the exact same result, we
616 * fail.
617 */
Willy Tarreau157788c2020-02-11 10:08:05 +0100618 while (1) {
Tim Duesterhusa8692f32020-03-13 12:34:25 +0100619 ssize_t len2 = recv(conn->handle.fd, trash.area, trash.data, 0);
620
Willy Tarreaue1e4a612012-10-05 00:10:55 +0200621 if (len2 < 0 && errno == EINTR)
622 continue;
Willy Tarreau843b7cb2018-07-13 10:54:26 +0200623 if (len2 != trash.data)
Willy Tarreau8e3bf692012-12-03 15:41:18 +0100624 goto recv_abort;
Willy Tarreau157788c2020-02-11 10:08:05 +0100625 break;
626 }
Willy Tarreaue1e4a612012-10-05 00:10:55 +0200627
628 conn->flags &= ~flag;
Emeric Brun4f603012017-01-05 15:11:44 +0100629 conn->flags |= CO_FL_RCVD_PROXY;
Willy Tarreaue1e4a612012-10-05 00:10:55 +0200630 return 1;
631
Willy Tarreau6499b9d2019-06-03 08:17:30 +0200632 not_ready:
Willy Tarreau6499b9d2019-06-03 08:17:30 +0200633 return 0;
634
Willy Tarreaue1e4a612012-10-05 00:10:55 +0200635 missing:
636 /* Missing data. Since we're using MSG_PEEK, we can only poll again if
637 * we have not read anything. Otherwise we need to fail because we won't
638 * be able to poll anymore.
639 */
Willy Tarreau8e3bf692012-12-03 15:41:18 +0100640 conn->err_code = CO_ER_PRX_TRUNCATED;
641 goto fail;
642
643 bad_header:
644 /* This is not a valid proxy protocol header */
645 conn->err_code = CO_ER_PRX_BAD_HDR;
646 goto fail;
647
648 recv_abort:
649 conn->err_code = CO_ER_PRX_ABORT;
Willy Tarreau26f4a042013-12-04 23:44:10 +0100650 conn->flags |= CO_FL_SOCK_RD_SH | CO_FL_SOCK_WR_SH;
Willy Tarreau8e3bf692012-12-03 15:41:18 +0100651 goto fail;
652
Willy Tarreaue1e4a612012-10-05 00:10:55 +0200653 fail:
Willy Tarreaue1e4a612012-10-05 00:10:55 +0200654 conn->flags |= CO_FL_ERROR;
Willy Tarreaue1e4a612012-10-05 00:10:55 +0200655 return 0;
656}
657
Bertrand Jacquin93b227d2016-06-04 15:11:10 +0100658/* This handshake handler waits a NetScaler Client IP insertion header
Bertrand Jacquin72fa1ec2017-12-12 01:17:23 +0000659 * at the beginning of the raw data stream. The header format is
660 * described in doc/netscaler-client-ip-insertion-protocol.txt
Bertrand Jacquin93b227d2016-06-04 15:11:10 +0100661 *
662 * This line MUST be at the beginning of the buffer and MUST NOT be
663 * fragmented.
664 *
665 * The header line is small and in all cases smaller than the smallest normal
666 * TCP MSS. So it MUST always be delivered as one segment, which ensures we
667 * can safely use MSG_PEEK and avoid buffering.
668 *
669 * Once the data is fetched, the values are set in the connection's address
670 * fields, and data are removed from the socket's buffer. The function returns
671 * zero if it needs to wait for more data or if it fails, or 1 if it completed
672 * and removed itself.
673 */
674int conn_recv_netscaler_cip(struct connection *conn, int flag)
675{
676 char *line;
Bertrand Jacquin7d668f92017-12-13 01:23:39 +0000677 uint32_t hdr_len;
Willy Tarreau0ca24aa2019-03-29 17:35:32 +0100678 uint8_t ip_ver;
Willy Tarreaub406b872018-08-22 05:20:32 +0200679 int ret;
Bertrand Jacquin93b227d2016-06-04 15:11:10 +0100680
Bertrand Jacquin93b227d2016-06-04 15:11:10 +0100681 if (!conn_ctrl_ready(conn))
682 goto fail;
683
Willy Tarreau9b7587a2020-10-15 07:32:10 +0200684 if (!sockaddr_alloc(&conn->src, NULL, 0) || !sockaddr_alloc(&conn->dst, NULL, 0))
Olivier Houchard1a9dbe52020-01-22 15:31:09 +0100685 goto fail;
686
Willy Tarreau585744b2017-08-24 14:31:19 +0200687 if (!fd_recv_ready(conn->handle.fd))
Willy Tarreau6499b9d2019-06-03 08:17:30 +0200688 goto not_ready;
Bertrand Jacquin93b227d2016-06-04 15:11:10 +0100689
Willy Tarreau157788c2020-02-11 10:08:05 +0100690 while (1) {
Willy Tarreaub406b872018-08-22 05:20:32 +0200691 ret = recv(conn->handle.fd, trash.area, trash.size, MSG_PEEK);
692 if (ret < 0) {
Bertrand Jacquin93b227d2016-06-04 15:11:10 +0100693 if (errno == EINTR)
694 continue;
695 if (errno == EAGAIN) {
Willy Tarreau585744b2017-08-24 14:31:19 +0200696 fd_cant_recv(conn->handle.fd);
Willy Tarreau6499b9d2019-06-03 08:17:30 +0200697 goto not_ready;
Bertrand Jacquin93b227d2016-06-04 15:11:10 +0100698 }
699 goto recv_abort;
700 }
Willy Tarreaub406b872018-08-22 05:20:32 +0200701 trash.data = ret;
Willy Tarreau157788c2020-02-11 10:08:05 +0100702 break;
703 }
Bertrand Jacquin93b227d2016-06-04 15:11:10 +0100704
Willy Tarreauc192b0a2020-01-23 09:11:58 +0100705 conn->flags &= ~CO_FL_WAIT_L4_CONN;
706
Willy Tarreau843b7cb2018-07-13 10:54:26 +0200707 if (!trash.data) {
Bertrand Jacquin93b227d2016-06-04 15:11:10 +0100708 /* client shutdown */
709 conn->err_code = CO_ER_CIP_EMPTY;
710 goto fail;
711 }
712
713 /* Fail if buffer length is not large enough to contain
Bertrand Jacquin72fa1ec2017-12-12 01:17:23 +0000714 * CIP magic, header length or
715 * CIP magic, CIP length, CIP type, header length */
Willy Tarreau843b7cb2018-07-13 10:54:26 +0200716 if (trash.data < 12)
Bertrand Jacquin93b227d2016-06-04 15:11:10 +0100717 goto missing;
718
Willy Tarreau843b7cb2018-07-13 10:54:26 +0200719 line = trash.area;
Bertrand Jacquin93b227d2016-06-04 15:11:10 +0100720
721 /* Decode a possible NetScaler Client IP request, fail early if
722 * it does not match */
Willy Tarreau1ac83af2020-02-25 10:06:49 +0100723 if (ntohl(read_u32(line)) != __objt_listener(conn->target)->bind_conf->ns_cip_magic)
Bertrand Jacquin93b227d2016-06-04 15:11:10 +0100724 goto bad_magic;
725
Bertrand Jacquin72fa1ec2017-12-12 01:17:23 +0000726 /* Legacy CIP protocol */
Willy Tarreau843b7cb2018-07-13 10:54:26 +0200727 if ((trash.area[8] & 0xD0) == 0x40) {
Willy Tarreau1ac83af2020-02-25 10:06:49 +0100728 hdr_len = ntohl(read_u32((line+4)));
Bertrand Jacquin72fa1ec2017-12-12 01:17:23 +0000729 line += 8;
730 }
731 /* Standard CIP protocol */
Willy Tarreau843b7cb2018-07-13 10:54:26 +0200732 else if (trash.area[8] == 0x00) {
Willy Tarreau1ac83af2020-02-25 10:06:49 +0100733 hdr_len = ntohs(read_u32((line+10)));
Bertrand Jacquin72fa1ec2017-12-12 01:17:23 +0000734 line += 12;
735 }
736 /* Unknown CIP protocol */
737 else {
738 conn->err_code = CO_ER_CIP_BAD_PROTO;
739 goto fail;
740 }
741
Bertrand Jacquin93b227d2016-06-04 15:11:10 +0100742 /* Fail if buffer length is not large enough to contain
Bertrand Jacquin72fa1ec2017-12-12 01:17:23 +0000743 * a minimal IP header */
Willy Tarreau843b7cb2018-07-13 10:54:26 +0200744 if (trash.data < 20)
Bertrand Jacquin93b227d2016-06-04 15:11:10 +0100745 goto missing;
746
Bertrand Jacquin93b227d2016-06-04 15:11:10 +0100747 /* Get IP version from the first four bits */
Willy Tarreau0ca24aa2019-03-29 17:35:32 +0100748 ip_ver = (*line & 0xf0) >> 4;
Bertrand Jacquin93b227d2016-06-04 15:11:10 +0100749
Willy Tarreau0ca24aa2019-03-29 17:35:32 +0100750 if (ip_ver == 4) {
Bertrand Jacquin93b227d2016-06-04 15:11:10 +0100751 struct ip *hdr_ip4;
David Carlier3015a2e2016-07-04 22:51:33 +0100752 struct my_tcphdr *hdr_tcp;
Bertrand Jacquin93b227d2016-06-04 15:11:10 +0100753
754 hdr_ip4 = (struct ip *)line;
755
Willy Tarreau843b7cb2018-07-13 10:54:26 +0200756 if (trash.data < 40 || trash.data < hdr_len) {
Bertrand Jacquin93b227d2016-06-04 15:11:10 +0100757 /* Fail if buffer length is not large enough to contain
Bertrand Jacquin67de5a22017-12-13 01:15:05 +0000758 * IPv4 header, TCP header */
Bertrand Jacquin93b227d2016-06-04 15:11:10 +0100759 goto missing;
Bertrand Jacquinb3875912017-12-13 00:58:51 +0000760 }
761 else if (hdr_ip4->ip_p != IPPROTO_TCP) {
Bertrand Jacquin93b227d2016-06-04 15:11:10 +0100762 /* The protocol does not include a TCP header */
763 conn->err_code = CO_ER_CIP_BAD_PROTO;
764 goto fail;
Bertrand Jacquinb3875912017-12-13 00:58:51 +0000765 }
Bertrand Jacquin93b227d2016-06-04 15:11:10 +0100766
David Carlier3015a2e2016-07-04 22:51:33 +0100767 hdr_tcp = (struct my_tcphdr *)(line + (hdr_ip4->ip_hl * 4));
Bertrand Jacquin93b227d2016-06-04 15:11:10 +0100768
769 /* update the session's addresses and mark them set */
Willy Tarreau226572f2019-07-17 14:46:00 +0200770 ((struct sockaddr_in *)conn->src)->sin_family = AF_INET;
771 ((struct sockaddr_in *)conn->src)->sin_addr.s_addr = hdr_ip4->ip_src.s_addr;
772 ((struct sockaddr_in *)conn->src)->sin_port = hdr_tcp->source;
Bertrand Jacquin93b227d2016-06-04 15:11:10 +0100773
Willy Tarreau226572f2019-07-17 14:46:00 +0200774 ((struct sockaddr_in *)conn->dst)->sin_family = AF_INET;
775 ((struct sockaddr_in *)conn->dst)->sin_addr.s_addr = hdr_ip4->ip_dst.s_addr;
776 ((struct sockaddr_in *)conn->dst)->sin_port = hdr_tcp->dest;
Bertrand Jacquin93b227d2016-06-04 15:11:10 +0100777
778 conn->flags |= CO_FL_ADDR_FROM_SET | CO_FL_ADDR_TO_SET;
779 }
Willy Tarreau0ca24aa2019-03-29 17:35:32 +0100780 else if (ip_ver == 6) {
Bertrand Jacquin93b227d2016-06-04 15:11:10 +0100781 struct ip6_hdr *hdr_ip6;
David Carlier3015a2e2016-07-04 22:51:33 +0100782 struct my_tcphdr *hdr_tcp;
Bertrand Jacquin93b227d2016-06-04 15:11:10 +0100783
784 hdr_ip6 = (struct ip6_hdr *)line;
785
Willy Tarreau843b7cb2018-07-13 10:54:26 +0200786 if (trash.data < 60 || trash.data < hdr_len) {
Bertrand Jacquin93b227d2016-06-04 15:11:10 +0100787 /* Fail if buffer length is not large enough to contain
Bertrand Jacquin67de5a22017-12-13 01:15:05 +0000788 * IPv6 header, TCP header */
Bertrand Jacquin93b227d2016-06-04 15:11:10 +0100789 goto missing;
Bertrand Jacquinb3875912017-12-13 00:58:51 +0000790 }
791 else if (hdr_ip6->ip6_nxt != IPPROTO_TCP) {
Bertrand Jacquin93b227d2016-06-04 15:11:10 +0100792 /* The protocol does not include a TCP header */
793 conn->err_code = CO_ER_CIP_BAD_PROTO;
794 goto fail;
Bertrand Jacquinb3875912017-12-13 00:58:51 +0000795 }
Bertrand Jacquin93b227d2016-06-04 15:11:10 +0100796
David Carlier3015a2e2016-07-04 22:51:33 +0100797 hdr_tcp = (struct my_tcphdr *)(line + sizeof(struct ip6_hdr));
Bertrand Jacquin93b227d2016-06-04 15:11:10 +0100798
799 /* update the session's addresses and mark them set */
Willy Tarreau226572f2019-07-17 14:46:00 +0200800 ((struct sockaddr_in6 *)conn->src)->sin6_family = AF_INET6;
801 ((struct sockaddr_in6 *)conn->src)->sin6_addr = hdr_ip6->ip6_src;
802 ((struct sockaddr_in6 *)conn->src)->sin6_port = hdr_tcp->source;
Bertrand Jacquin93b227d2016-06-04 15:11:10 +0100803
Willy Tarreau226572f2019-07-17 14:46:00 +0200804 ((struct sockaddr_in6 *)conn->dst)->sin6_family = AF_INET6;
805 ((struct sockaddr_in6 *)conn->dst)->sin6_addr = hdr_ip6->ip6_dst;
806 ((struct sockaddr_in6 *)conn->dst)->sin6_port = hdr_tcp->dest;
Bertrand Jacquin93b227d2016-06-04 15:11:10 +0100807
808 conn->flags |= CO_FL_ADDR_FROM_SET | CO_FL_ADDR_TO_SET;
809 }
810 else {
811 /* The protocol does not match something known (IPv4/IPv6) */
812 conn->err_code = CO_ER_CIP_BAD_PROTO;
813 goto fail;
814 }
815
Bertrand Jacquin7d668f92017-12-13 01:23:39 +0000816 line += hdr_len;
Willy Tarreau843b7cb2018-07-13 10:54:26 +0200817 trash.data = line - trash.area;
Bertrand Jacquin93b227d2016-06-04 15:11:10 +0100818
819 /* remove the NetScaler Client IP header from the request. For this
820 * we re-read the exact line at once. If we don't get the exact same
821 * result, we fail.
822 */
Willy Tarreau157788c2020-02-11 10:08:05 +0100823 while (1) {
Willy Tarreau843b7cb2018-07-13 10:54:26 +0200824 int len2 = recv(conn->handle.fd, trash.area, trash.data, 0);
Bertrand Jacquin93b227d2016-06-04 15:11:10 +0100825 if (len2 < 0 && errno == EINTR)
826 continue;
Willy Tarreau843b7cb2018-07-13 10:54:26 +0200827 if (len2 != trash.data)
Bertrand Jacquin93b227d2016-06-04 15:11:10 +0100828 goto recv_abort;
Willy Tarreau157788c2020-02-11 10:08:05 +0100829 break;
830 }
Bertrand Jacquin93b227d2016-06-04 15:11:10 +0100831
832 conn->flags &= ~flag;
833 return 1;
834
Willy Tarreau6499b9d2019-06-03 08:17:30 +0200835 not_ready:
Willy Tarreau6499b9d2019-06-03 08:17:30 +0200836 return 0;
837
Bertrand Jacquin93b227d2016-06-04 15:11:10 +0100838 missing:
839 /* Missing data. Since we're using MSG_PEEK, we can only poll again if
840 * we have not read anything. Otherwise we need to fail because we won't
841 * be able to poll anymore.
842 */
843 conn->err_code = CO_ER_CIP_TRUNCATED;
844 goto fail;
845
846 bad_magic:
847 conn->err_code = CO_ER_CIP_BAD_MAGIC;
848 goto fail;
849
850 recv_abort:
851 conn->err_code = CO_ER_CIP_ABORT;
852 conn->flags |= CO_FL_SOCK_RD_SH | CO_FL_SOCK_WR_SH;
853 goto fail;
854
855 fail:
Bertrand Jacquin93b227d2016-06-04 15:11:10 +0100856 conn->flags |= CO_FL_ERROR;
857 return 0;
858}
859
Alexander Liu2a54bb72019-05-22 19:44:48 +0800860
861int conn_send_socks4_proxy_request(struct connection *conn)
862{
863 struct socks4_request req_line;
864
Alexander Liu2a54bb72019-05-22 19:44:48 +0800865 if (!conn_ctrl_ready(conn))
866 goto out_error;
867
Willy Tarreau226572f2019-07-17 14:46:00 +0200868 if (!conn_get_dst(conn))
869 goto out_error;
870
Alexander Liu2a54bb72019-05-22 19:44:48 +0800871 req_line.version = 0x04;
872 req_line.command = 0x01;
Willy Tarreau226572f2019-07-17 14:46:00 +0200873 req_line.port = get_net_port(conn->dst);
874 req_line.ip = is_inet_addr(conn->dst);
Alexander Liu2a54bb72019-05-22 19:44:48 +0800875 memcpy(req_line.user_id, "HAProxy\0", 8);
876
877 if (conn->send_proxy_ofs > 0) {
878 /*
879 * This is the first call to send the request
880 */
881 conn->send_proxy_ofs = -(int)sizeof(req_line);
882 }
883
884 if (conn->send_proxy_ofs < 0) {
885 int ret = 0;
886
887 /* we are sending the socks4_req_line here. If the data layer
888 * has a pending write, we'll also set MSG_MORE.
889 */
Willy Tarreau827fee72020-12-11 15:26:55 +0100890 ret = conn_ctrl_send(
Alexander Liu2a54bb72019-05-22 19:44:48 +0800891 conn,
892 ((char *)(&req_line)) + (sizeof(req_line)+conn->send_proxy_ofs),
893 -conn->send_proxy_ofs,
Willy Tarreau827fee72020-12-11 15:26:55 +0100894 (conn->subs && conn->subs->events & SUB_RETRY_SEND) ? CO_SFL_MSG_MORE : 0);
Alexander Liu2a54bb72019-05-22 19:44:48 +0800895
896 DPRINTF(stderr, "SOCKS PROXY HS FD[%04X]: Before send remain is [%d], sent [%d]\n",
897 conn->handle.fd, -conn->send_proxy_ofs, ret);
898
899 if (ret < 0) {
900 goto out_error;
901 }
902
903 conn->send_proxy_ofs += ret; /* becomes zero once complete */
904 if (conn->send_proxy_ofs != 0) {
905 goto out_wait;
906 }
907 }
908
909 /* OK we've the whole request sent */
910 conn->flags &= ~CO_FL_SOCKS4_SEND;
Alexander Liu2a54bb72019-05-22 19:44:48 +0800911
912 /* The connection is ready now, simply return and let the connection
913 * handler notify upper layers if needed.
914 */
Willy Tarreauc192b0a2020-01-23 09:11:58 +0100915 conn->flags &= ~CO_FL_WAIT_L4_CONN;
Alexander Liu2a54bb72019-05-22 19:44:48 +0800916
917 if (conn->flags & CO_FL_SEND_PROXY) {
918 /*
919 * Get the send_proxy_ofs ready for the send_proxy due to we are
920 * reusing the "send_proxy_ofs", and SOCKS4 handshake should be done
921 * before sending PROXY Protocol.
922 */
923 conn->send_proxy_ofs = 1;
924 }
925 return 1;
926
927 out_error:
928 /* Write error on the file descriptor */
929 conn->flags |= CO_FL_ERROR;
930 if (conn->err_code == CO_ER_NONE) {
931 conn->err_code = CO_ER_SOCKS4_SEND;
932 }
933 return 0;
934
935 out_wait:
Alexander Liu2a54bb72019-05-22 19:44:48 +0800936 return 0;
937}
938
939int conn_recv_socks4_proxy_response(struct connection *conn)
940{
941 char line[SOCKS4_HS_RSP_LEN];
942 int ret;
943
Alexander Liu2a54bb72019-05-22 19:44:48 +0800944 if (!conn_ctrl_ready(conn))
945 goto fail;
946
947 if (!fd_recv_ready(conn->handle.fd))
Willy Tarreau6499b9d2019-06-03 08:17:30 +0200948 goto not_ready;
Alexander Liu2a54bb72019-05-22 19:44:48 +0800949
Willy Tarreau157788c2020-02-11 10:08:05 +0100950 while (1) {
Alexander Liu2a54bb72019-05-22 19:44:48 +0800951 /* SOCKS4 Proxy will response with 8 bytes, 0x00 | 0x5A | 0x00 0x00 | 0x00 0x00 0x00 0x00
952 * Try to peek into it, before all 8 bytes ready.
953 */
954 ret = recv(conn->handle.fd, line, SOCKS4_HS_RSP_LEN, MSG_PEEK);
955
956 if (ret == 0) {
957 /* the socket has been closed or shutdown for send */
958 DPRINTF(stderr, "SOCKS PROXY HS FD[%04X]: Received ret[%d], errno[%d], looks like the socket has been closed or shutdown for send\n",
959 conn->handle.fd, ret, errno);
960 if (conn->err_code == CO_ER_NONE) {
961 conn->err_code = CO_ER_SOCKS4_RECV;
962 }
963 goto fail;
964 }
965
966 if (ret > 0) {
967 if (ret == SOCKS4_HS_RSP_LEN) {
968 DPRINTF(stderr, "SOCKS PROXY HS FD[%04X]: Received 8 bytes, the response is [%02X|%02X|%02X %02X|%02X %02X %02X %02X]\n",
969 conn->handle.fd, line[0], line[1], line[2], line[3], line[4], line[5], line[6], line[7]);
970 }else{
971 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]);
972 }
973 } else {
974 DPRINTF(stderr, "SOCKS PROXY HS FD[%04X]: Received ret[%d], errno[%d]\n", conn->handle.fd, ret, errno);
975 }
976
977 if (ret < 0) {
978 if (errno == EINTR) {
979 continue;
980 }
981 if (errno == EAGAIN) {
982 fd_cant_recv(conn->handle.fd);
Willy Tarreau6499b9d2019-06-03 08:17:30 +0200983 goto not_ready;
Alexander Liu2a54bb72019-05-22 19:44:48 +0800984 }
985 goto recv_abort;
986 }
Willy Tarreau157788c2020-02-11 10:08:05 +0100987 break;
988 }
Alexander Liu2a54bb72019-05-22 19:44:48 +0800989
Willy Tarreauc192b0a2020-01-23 09:11:58 +0100990 conn->flags &= ~CO_FL_WAIT_L4_CONN;
991
Alexander Liu2a54bb72019-05-22 19:44:48 +0800992 if (ret < SOCKS4_HS_RSP_LEN) {
993 /* Missing data. Since we're using MSG_PEEK, we can only poll again if
994 * we are not able to read enough data.
995 */
Willy Tarreau6499b9d2019-06-03 08:17:30 +0200996 goto not_ready;
Alexander Liu2a54bb72019-05-22 19:44:48 +0800997 }
998
999 /*
1000 * Base on the SOCSK4 protocol:
1001 *
1002 * +----+----+----+----+----+----+----+----+
1003 * | VN | CD | DSTPORT | DSTIP |
1004 * +----+----+----+----+----+----+----+----+
1005 * # of bytes: 1 1 2 4
1006 * VN is the version of the reply code and should be 0. CD is the result
1007 * code with one of the following values:
1008 * 90: request granted
1009 * 91: request rejected or failed
Ilya Shipitsince7b00f2020-03-23 22:28:40 +05001010 * 92: request rejected because SOCKS server cannot connect to identd on the client
Alexander Liu2a54bb72019-05-22 19:44:48 +08001011 * 93: request rejected because the client program and identd report different user-ids
1012 * The remaining fields are ignored.
1013 */
1014 if (line[1] != 90) {
1015 conn->flags &= ~CO_FL_SOCKS4_RECV;
1016
1017 DPRINTF(stderr, "SOCKS PROXY HS FD[%04X]: FAIL, the response is [%02X|%02X|%02X %02X|%02X %02X %02X %02X]\n",
1018 conn->handle.fd, line[0], line[1], line[2], line[3], line[4], line[5], line[6], line[7]);
1019 if (conn->err_code == CO_ER_NONE) {
1020 conn->err_code = CO_ER_SOCKS4_DENY;
1021 }
1022 goto fail;
1023 }
1024
1025 /* remove the 8 bytes response from the stream */
Willy Tarreau157788c2020-02-11 10:08:05 +01001026 while (1) {
Alexander Liu2a54bb72019-05-22 19:44:48 +08001027 ret = recv(conn->handle.fd, line, SOCKS4_HS_RSP_LEN, 0);
1028 if (ret < 0 && errno == EINTR) {
1029 continue;
1030 }
1031 if (ret != SOCKS4_HS_RSP_LEN) {
1032 if (conn->err_code == CO_ER_NONE) {
1033 conn->err_code = CO_ER_SOCKS4_RECV;
1034 }
1035 goto fail;
1036 }
Willy Tarreau157788c2020-02-11 10:08:05 +01001037 break;
1038 }
Alexander Liu2a54bb72019-05-22 19:44:48 +08001039
1040 conn->flags &= ~CO_FL_SOCKS4_RECV;
1041 return 1;
1042
Willy Tarreau6499b9d2019-06-03 08:17:30 +02001043 not_ready:
Willy Tarreau6499b9d2019-06-03 08:17:30 +02001044 return 0;
1045
Alexander Liu2a54bb72019-05-22 19:44:48 +08001046 recv_abort:
1047 if (conn->err_code == CO_ER_NONE) {
1048 conn->err_code = CO_ER_SOCKS4_ABORT;
1049 }
1050 conn->flags |= (CO_FL_SOCK_RD_SH | CO_FL_SOCK_WR_SH);
1051 goto fail;
1052
1053 fail:
Alexander Liu2a54bb72019-05-22 19:44:48 +08001054 conn->flags |= CO_FL_ERROR;
1055 return 0;
1056}
1057
Willy Tarreaue59b5162021-05-08 14:06:09 +02001058/* Lists the known proto mux on <out> */
1059void list_mux_proto(FILE *out)
1060{
1061 struct mux_proto_list *item;
1062 struct buffer *chk = get_trash_chunk();
1063 struct ist proto;
1064 char *mode, *side;
1065
1066 fprintf(out, "Available multiplexer protocols :\n"
1067 "(protocols marked as <default> cannot be specified using 'proto' keyword)\n");
1068 list_for_each_entry(item, &mux_proto_list.list, list) {
1069 proto = item->token;
1070
1071 if (item->mode == PROTO_MODE_ANY)
1072 mode = "TCP|HTTP";
1073 else if (item->mode == PROTO_MODE_TCP)
1074 mode = "TCP";
1075 else if (item->mode == PROTO_MODE_HTTP)
1076 mode = "HTTP";
1077 else
1078 mode = "NONE";
1079
1080 if (item->side == PROTO_SIDE_BOTH)
1081 side = "FE|BE";
1082 else if (item->side == PROTO_SIDE_FE)
1083 side = "FE";
1084 else if (item->side == PROTO_SIDE_BE)
1085 side = "BE";
1086 else
1087 side = "NONE";
1088
1089 chunk_reset(chk);
1090 if (item->mux->flags & MX_FL_HTX)
1091 chunk_strcpy(chk, "HTX");
1092 if (item->mux->flags & MX_FL_CLEAN_ABRT)
1093 chunk_appendf(chk, "%sCLEAN_ABRT", (b_data(chk) ? "|": ""));
1094 if (item->mux->flags & MX_FL_HOL_RISK)
1095 chunk_appendf(chk, "%sHOL_RISK", (b_data(chk) ? "|": ""));
1096 if (item->mux->flags & MX_FL_NO_UPG)
1097 chunk_appendf(chk, "%sNO_UPG", (b_data(chk) ? "|": ""));
1098
1099 fprintf(out, " %15s : mode=%-10s side=%-8s mux=%-8s flags=%.*s\n",
1100 (proto.len ? proto.ptr : "<default>"), mode, side, item->mux->name,
1101 (int)b_data(chk), b_orig(chk));
1102 }
1103}
1104
Ilya Shipitsinca56fce2018-09-15 00:50:05 +05001105/* Note: <remote> is explicitly allowed to be NULL */
Tim Duesterhuscf6e0c82020-03-13 12:34:24 +01001106int make_proxy_line(char *buf, int buf_len, struct server *srv, struct connection *remote, struct stream *strm)
David Safb76832014-05-08 23:42:08 -04001107{
1108 int ret = 0;
1109
1110 if (srv && (srv->pp_opts & SRV_PP_V2)) {
Tim Duesterhuscf6e0c82020-03-13 12:34:24 +01001111 ret = make_proxy_line_v2(buf, buf_len, srv, remote, strm);
David Safb76832014-05-08 23:42:08 -04001112 }
1113 else {
Willy Tarreau226572f2019-07-17 14:46:00 +02001114 if (remote && conn_get_src(remote) && conn_get_dst(remote))
1115 ret = make_proxy_line_v1(buf, buf_len, remote->src, remote->dst);
David Safb76832014-05-08 23:42:08 -04001116 else
1117 ret = make_proxy_line_v1(buf, buf_len, NULL, NULL);
1118 }
1119
1120 return ret;
1121}
1122
Willy Tarreaue1e4a612012-10-05 00:10:55 +02001123/* Makes a PROXY protocol line from the two addresses. The output is sent to
1124 * buffer <buf> for a maximum size of <buf_len> (including the trailing zero).
1125 * It returns the number of bytes composing this line (including the trailing
1126 * LF), or zero in case of failure (eg: not enough space). It supports TCP4,
Willy Tarreau2e1401a2013-10-01 11:41:55 +02001127 * TCP6 and "UNKNOWN" formats. If any of <src> or <dst> is null, UNKNOWN is
1128 * emitted as well.
Willy Tarreaue1e4a612012-10-05 00:10:55 +02001129 */
David Safb76832014-05-08 23:42:08 -04001130int make_proxy_line_v1(char *buf, int buf_len, struct sockaddr_storage *src, struct sockaddr_storage *dst)
Willy Tarreaue1e4a612012-10-05 00:10:55 +02001131{
1132 int ret = 0;
Tim Duesterhus7fec0212018-07-27 18:46:13 +02001133 char * protocol;
1134 char src_str[MAX(INET_ADDRSTRLEN, INET6_ADDRSTRLEN)];
1135 char dst_str[MAX(INET_ADDRSTRLEN, INET6_ADDRSTRLEN)];
1136 in_port_t src_port;
1137 in_port_t dst_port;
Willy Tarreaue1e4a612012-10-05 00:10:55 +02001138
Tim Duesterhus7fec0212018-07-27 18:46:13 +02001139 if ( !src
1140 || !dst
1141 || (src->ss_family != AF_INET && src->ss_family != AF_INET6)
1142 || (dst->ss_family != AF_INET && dst->ss_family != AF_INET6)) {
1143 /* unknown family combination */
1144 ret = snprintf(buf, buf_len, "PROXY UNKNOWN\r\n");
Willy Tarreaue1e4a612012-10-05 00:10:55 +02001145 if (ret >= buf_len)
1146 return 0;
1147
Tim Duesterhus7fec0212018-07-27 18:46:13 +02001148 return ret;
1149 }
Willy Tarreaue1e4a612012-10-05 00:10:55 +02001150
Tim Duesterhus7fec0212018-07-27 18:46:13 +02001151 /* IPv4 for both src and dst */
1152 if (src->ss_family == AF_INET && dst->ss_family == AF_INET) {
1153 protocol = "TCP4";
1154 if (!inet_ntop(AF_INET, &((struct sockaddr_in *)src)->sin_addr, src_str, sizeof(src_str)))
Willy Tarreaue1e4a612012-10-05 00:10:55 +02001155 return 0;
Tim Duesterhus7fec0212018-07-27 18:46:13 +02001156 src_port = ((struct sockaddr_in *)src)->sin_port;
1157 if (!inet_ntop(AF_INET, &((struct sockaddr_in *)dst)->sin_addr, dst_str, sizeof(dst_str)))
Willy Tarreaue1e4a612012-10-05 00:10:55 +02001158 return 0;
Tim Duesterhus7fec0212018-07-27 18:46:13 +02001159 dst_port = ((struct sockaddr_in *)dst)->sin_port;
Willy Tarreaue1e4a612012-10-05 00:10:55 +02001160 }
Tim Duesterhus7fec0212018-07-27 18:46:13 +02001161 /* IPv6 for at least one of src and dst */
1162 else {
1163 struct in6_addr tmp;
Willy Tarreaue1e4a612012-10-05 00:10:55 +02001164
Tim Duesterhus7fec0212018-07-27 18:46:13 +02001165 protocol = "TCP6";
Willy Tarreaue1e4a612012-10-05 00:10:55 +02001166
Tim Duesterhus7fec0212018-07-27 18:46:13 +02001167 if (src->ss_family == AF_INET) {
1168 /* Convert src to IPv6 */
1169 v4tov6(&tmp, &((struct sockaddr_in *)src)->sin_addr);
1170 src_port = ((struct sockaddr_in *)src)->sin_port;
1171 }
1172 else {
1173 tmp = ((struct sockaddr_in6 *)src)->sin6_addr;
1174 src_port = ((struct sockaddr_in6 *)src)->sin6_port;
1175 }
Willy Tarreaue1e4a612012-10-05 00:10:55 +02001176
Tim Duesterhus7fec0212018-07-27 18:46:13 +02001177 if (!inet_ntop(AF_INET6, &tmp, src_str, sizeof(src_str)))
Willy Tarreaue1e4a612012-10-05 00:10:55 +02001178 return 0;
1179
Tim Duesterhus7fec0212018-07-27 18:46:13 +02001180 if (dst->ss_family == AF_INET) {
1181 /* Convert dst to IPv6 */
1182 v4tov6(&tmp, &((struct sockaddr_in *)dst)->sin_addr);
1183 dst_port = ((struct sockaddr_in *)dst)->sin_port;
1184 }
1185 else {
1186 tmp = ((struct sockaddr_in6 *)dst)->sin6_addr;
1187 dst_port = ((struct sockaddr_in6 *)dst)->sin6_port;
1188 }
Willy Tarreaue1e4a612012-10-05 00:10:55 +02001189
Tim Duesterhus7fec0212018-07-27 18:46:13 +02001190 if (!inet_ntop(AF_INET6, &tmp, dst_str, sizeof(dst_str)))
Willy Tarreaue1e4a612012-10-05 00:10:55 +02001191 return 0;
1192 }
Tim Duesterhus7fec0212018-07-27 18:46:13 +02001193
1194 ret = snprintf(buf, buf_len, "PROXY %s %s %s %u %u\r\n", protocol, src_str, dst_str, ntohs(src_port), ntohs(dst_port));
1195 if (ret >= buf_len)
1196 return 0;
1197
Willy Tarreaue1e4a612012-10-05 00:10:55 +02001198 return ret;
1199}
David Safb76832014-05-08 23:42:08 -04001200
KOVACS Krisztianb3e54fe2014-11-17 15:11:45 +01001201static int make_tlv(char *dest, int dest_len, char type, uint16_t length, const char *value)
David Safb76832014-05-08 23:42:08 -04001202{
1203 struct tlv *tlv;
1204
1205 if (!dest || (length + sizeof(*tlv) > dest_len))
1206 return 0;
1207
1208 tlv = (struct tlv *)dest;
1209
1210 tlv->type = type;
1211 tlv->length_hi = length >> 8;
1212 tlv->length_lo = length & 0x00ff;
1213 memcpy(tlv->value, value, length);
1214 return length + sizeof(*tlv);
1215}
David Safb76832014-05-08 23:42:08 -04001216
Ilya Shipitsinca56fce2018-09-15 00:50:05 +05001217/* Note: <remote> is explicitly allowed to be NULL */
Tim Duesterhuscf6e0c82020-03-13 12:34:24 +01001218int 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 -04001219{
Willy Tarreau8fccfa22014-06-14 08:28:06 +02001220 const char pp2_signature[] = PP2_SIGNATURE;
Emmanuel Hocdet4399c752018-02-05 15:26:43 +01001221 void *tlv_crc32c_p = NULL;
David Safb76832014-05-08 23:42:08 -04001222 int ret = 0;
Willy Tarreau8fccfa22014-06-14 08:28:06 +02001223 struct proxy_hdr_v2 *hdr = (struct proxy_hdr_v2 *)buf;
Vincent Bernat6e615892016-05-18 16:17:44 +02001224 struct sockaddr_storage null_addr = { .ss_family = 0 };
David Safb76832014-05-08 23:42:08 -04001225 struct sockaddr_storage *src = &null_addr;
1226 struct sockaddr_storage *dst = &null_addr;
Emmanuel Hocdet404d9782017-10-24 10:55:14 +02001227 const char *value;
1228 int value_len;
David Safb76832014-05-08 23:42:08 -04001229
1230 if (buf_len < PP2_HEADER_LEN)
1231 return 0;
Willy Tarreau8fccfa22014-06-14 08:28:06 +02001232 memcpy(hdr->sig, pp2_signature, PP2_SIGNATURE_LEN);
David Safb76832014-05-08 23:42:08 -04001233
Willy Tarreau226572f2019-07-17 14:46:00 +02001234 if (remote && conn_get_src(remote) && conn_get_dst(remote)) {
1235 src = remote->src;
1236 dst = remote->dst;
David Safb76832014-05-08 23:42:08 -04001237 }
KOVACS Krisztianb3e54fe2014-11-17 15:11:45 +01001238
Tim Duesterhus7fec0212018-07-27 18:46:13 +02001239 /* At least one of src or dst is not of AF_INET or AF_INET6 */
1240 if ( !src
1241 || !dst
Willy Tarreau119e50e2020-05-22 13:53:29 +02001242 || (!pp2_never_send_local && conn_is_back(remote)) // locally initiated connection
Tim Duesterhus7fec0212018-07-27 18:46:13 +02001243 || (src->ss_family != AF_INET && src->ss_family != AF_INET6)
1244 || (dst->ss_family != AF_INET && dst->ss_family != AF_INET6)) {
David Safb76832014-05-08 23:42:08 -04001245 if (buf_len < PP2_HDR_LEN_UNSPEC)
1246 return 0;
Willy Tarreau8fccfa22014-06-14 08:28:06 +02001247 hdr->ver_cmd = PP2_VERSION | PP2_CMD_LOCAL;
1248 hdr->fam = PP2_FAM_UNSPEC | PP2_TRANS_UNSPEC;
David Safb76832014-05-08 23:42:08 -04001249 ret = PP2_HDR_LEN_UNSPEC;
1250 }
Tim Duesterhus7fec0212018-07-27 18:46:13 +02001251 else {
Willy Tarreau02c88032020-04-14 12:54:10 +02001252 hdr->ver_cmd = PP2_VERSION | PP2_CMD_PROXY;
Tim Duesterhus7fec0212018-07-27 18:46:13 +02001253 /* IPv4 for both src and dst */
1254 if (src->ss_family == AF_INET && dst->ss_family == AF_INET) {
1255 if (buf_len < PP2_HDR_LEN_INET)
1256 return 0;
Tim Duesterhus7fec0212018-07-27 18:46:13 +02001257 hdr->fam = PP2_FAM_INET | PP2_TRANS_STREAM;
1258 hdr->addr.ip4.src_addr = ((struct sockaddr_in *)src)->sin_addr.s_addr;
1259 hdr->addr.ip4.src_port = ((struct sockaddr_in *)src)->sin_port;
1260 hdr->addr.ip4.dst_addr = ((struct sockaddr_in *)dst)->sin_addr.s_addr;
1261 hdr->addr.ip4.dst_port = ((struct sockaddr_in *)dst)->sin_port;
1262 ret = PP2_HDR_LEN_INET;
1263 }
1264 /* IPv6 for at least one of src and dst */
1265 else {
1266 struct in6_addr tmp;
1267
1268 if (buf_len < PP2_HDR_LEN_INET6)
1269 return 0;
Tim Duesterhus7fec0212018-07-27 18:46:13 +02001270 hdr->fam = PP2_FAM_INET6 | PP2_TRANS_STREAM;
1271 if (src->ss_family == AF_INET) {
1272 v4tov6(&tmp, &((struct sockaddr_in *)src)->sin_addr);
1273 memcpy(hdr->addr.ip6.src_addr, &tmp, 16);
1274 hdr->addr.ip6.src_port = ((struct sockaddr_in *)src)->sin_port;
1275 }
1276 else {
1277 memcpy(hdr->addr.ip6.src_addr, &((struct sockaddr_in6 *)src)->sin6_addr, 16);
1278 hdr->addr.ip6.src_port = ((struct sockaddr_in6 *)src)->sin6_port;
1279 }
1280 if (dst->ss_family == AF_INET) {
1281 v4tov6(&tmp, &((struct sockaddr_in *)dst)->sin_addr);
1282 memcpy(hdr->addr.ip6.dst_addr, &tmp, 16);
William Dauchybd8bf672020-01-26 19:06:39 +01001283 hdr->addr.ip6.dst_port = ((struct sockaddr_in *)dst)->sin_port;
Tim Duesterhus7fec0212018-07-27 18:46:13 +02001284 }
1285 else {
1286 memcpy(hdr->addr.ip6.dst_addr, &((struct sockaddr_in6 *)dst)->sin6_addr, 16);
1287 hdr->addr.ip6.dst_port = ((struct sockaddr_in6 *)dst)->sin6_port;
1288 }
1289
1290 ret = PP2_HDR_LEN_INET6;
1291 }
1292 }
David Safb76832014-05-08 23:42:08 -04001293
Emmanuel Hocdet4399c752018-02-05 15:26:43 +01001294 if (srv->pp_opts & SRV_PP_V2_CRC32C) {
1295 uint32_t zero_crc32c = 0;
Tim Duesterhusa8692f32020-03-13 12:34:25 +01001296
Emmanuel Hocdet4399c752018-02-05 15:26:43 +01001297 if ((buf_len - ret) < sizeof(struct tlv))
1298 return 0;
1299 tlv_crc32c_p = (void *)((struct tlv *)&buf[ret])->value;
1300 ret += make_tlv(&buf[ret], (buf_len - ret), PP2_TYPE_CRC32C, sizeof(zero_crc32c), (const char *)&zero_crc32c);
1301 }
1302
Ilya Shipitsinca56fce2018-09-15 00:50:05 +05001303 if (remote && conn_get_alpn(remote, &value, &value_len)) {
Emmanuel Hocdet404d9782017-10-24 10:55:14 +02001304 if ((buf_len - ret) < sizeof(struct tlv))
1305 return 0;
Emmanuel Hocdet571c7ac2017-10-31 18:24:05 +01001306 ret += make_tlv(&buf[ret], (buf_len - ret), PP2_TYPE_ALPN, value_len, value);
Emmanuel Hocdet404d9782017-10-24 10:55:14 +02001307 }
1308
Emmanuel Hocdet253c3b72018-02-01 18:29:59 +01001309 if (srv->pp_opts & SRV_PP_V2_AUTHORITY) {
Emmanuel Hocdet8a4ffa02019-08-29 11:54:51 +02001310 value = NULL;
Tim Duesterhus615f81e2021-03-06 20:06:50 +01001311 if (remote && isttest(remote->proxy_authority)) {
1312 value = istptr(remote->proxy_authority);
1313 value_len = istlen(remote->proxy_authority);
Emmanuel Hocdet8a4ffa02019-08-29 11:54:51 +02001314 }
1315#ifdef USE_OPENSSL
1316 else {
Jerome Magnin78891c72019-09-02 09:53:41 +02001317 if ((value = ssl_sock_get_sni(remote)))
Emmanuel Hocdet8a4ffa02019-08-29 11:54:51 +02001318 value_len = strlen(value);
1319 }
1320#endif
Emmanuel Hocdet253c3b72018-02-01 18:29:59 +01001321 if (value) {
1322 if ((buf_len - ret) < sizeof(struct tlv))
1323 return 0;
Emmanuel Hocdet8a4ffa02019-08-29 11:54:51 +02001324 ret += make_tlv(&buf[ret], (buf_len - ret), PP2_TYPE_AUTHORITY, value_len, value);
Emmanuel Hocdet253c3b72018-02-01 18:29:59 +01001325 }
1326 }
1327
Christopher Faulet3ab504f2020-05-26 15:16:01 +02001328 if (strm && (srv->pp_opts & SRV_PP_V2_UNIQUE_ID)) {
Tim Duesterhuscf6e0c82020-03-13 12:34:24 +01001329 struct session* sess = strm_sess(strm);
1330 struct ist unique_id = stream_generate_unique_id(strm, &sess->fe->format_unique_id);
1331
1332 value = unique_id.ptr;
1333 value_len = unique_id.len;
1334
1335 if (value_len >= 0) {
1336 if ((buf_len - ret) < sizeof(struct tlv))
1337 return 0;
1338 ret += make_tlv(&buf[ret], (buf_len - ret), PP2_TYPE_UNIQUE_ID, value_len, value);
1339 }
1340 }
1341
Emmanuel Hocdet8a4ffa02019-08-29 11:54:51 +02001342#ifdef USE_OPENSSL
David Safb76832014-05-08 23:42:08 -04001343 if (srv->pp_opts & SRV_PP_V2_SSL) {
Emmanuel Hocdet404d9782017-10-24 10:55:14 +02001344 struct tlv_ssl *tlv;
1345 int ssl_tlv_len = 0;
Tim Duesterhusa8692f32020-03-13 12:34:25 +01001346
David Safb76832014-05-08 23:42:08 -04001347 if ((buf_len - ret) < sizeof(struct tlv_ssl))
1348 return 0;
1349 tlv = (struct tlv_ssl *)&buf[ret];
1350 memset(tlv, 0, sizeof(struct tlv_ssl));
1351 ssl_tlv_len += sizeof(struct tlv_ssl);
1352 tlv->tlv.type = PP2_TYPE_SSL;
1353 if (ssl_sock_is_ssl(remote)) {
1354 tlv->client |= PP2_CLIENT_SSL;
Emmanuel Hocdet01da5712017-10-13 16:59:49 +02001355 value = ssl_sock_get_proto_version(remote);
David Safb76832014-05-08 23:42:08 -04001356 if (value) {
Emmanuel Hocdet8c0c34b2018-02-28 12:02:14 +01001357 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 -04001358 }
Dave McCowan328fb582014-07-30 10:39:13 -04001359 if (ssl_sock_get_cert_used_sess(remote)) {
1360 tlv->client |= PP2_CLIENT_CERT_SESS;
David Safb76832014-05-08 23:42:08 -04001361 tlv->verify = htonl(ssl_sock_get_verify_result(remote));
Dave McCowan328fb582014-07-30 10:39:13 -04001362 if (ssl_sock_get_cert_used_conn(remote))
1363 tlv->client |= PP2_CLIENT_CERT_CONN;
David Safb76832014-05-08 23:42:08 -04001364 }
1365 if (srv->pp_opts & SRV_PP_V2_SSL_CN) {
Willy Tarreau83061a82018-07-13 11:56:34 +02001366 struct buffer *cn_trash = get_trash_chunk();
Willy Tarreau3b9a0c92014-07-19 06:37:33 +02001367 if (ssl_sock_get_remote_common_name(remote, cn_trash) > 0) {
Willy Tarreau843b7cb2018-07-13 10:54:26 +02001368 ssl_tlv_len += make_tlv(&buf[ret+ssl_tlv_len], (buf_len - ret - ssl_tlv_len), PP2_SUBTYPE_SSL_CN,
1369 cn_trash->data,
1370 cn_trash->area);
David Safb76832014-05-08 23:42:08 -04001371 }
1372 }
Emmanuel Hocdetfa8d0f12018-02-01 15:53:52 +01001373 if (srv->pp_opts & SRV_PP_V2_SSL_KEY_ALG) {
Willy Tarreau83061a82018-07-13 11:56:34 +02001374 struct buffer *pkey_trash = get_trash_chunk();
Emmanuel Hocdetfa8d0f12018-02-01 15:53:52 +01001375 if (ssl_sock_get_pkey_algo(remote, pkey_trash) > 0) {
Willy Tarreau843b7cb2018-07-13 10:54:26 +02001376 ssl_tlv_len += make_tlv(&buf[ret+ssl_tlv_len], (buf_len - ret - ssl_tlv_len), PP2_SUBTYPE_SSL_KEY_ALG,
1377 pkey_trash->data,
1378 pkey_trash->area);
Emmanuel Hocdetfa8d0f12018-02-01 15:53:52 +01001379 }
1380 }
1381 if (srv->pp_opts & SRV_PP_V2_SSL_SIG_ALG) {
1382 value = ssl_sock_get_cert_sig(remote);
1383 if (value) {
1384 ssl_tlv_len += make_tlv(&buf[ret+ssl_tlv_len], (buf_len - ret - ssl_tlv_len), PP2_SUBTYPE_SSL_SIG_ALG, strlen(value), value);
1385 }
1386 }
1387 if (srv->pp_opts & SRV_PP_V2_SSL_CIPHER) {
1388 value = ssl_sock_get_cipher_name(remote);
1389 if (value) {
1390 ssl_tlv_len += make_tlv(&buf[ret+ssl_tlv_len], (buf_len - ret - ssl_tlv_len), PP2_SUBTYPE_SSL_CIPHER, strlen(value), value);
1391 }
1392 }
David Safb76832014-05-08 23:42:08 -04001393 }
1394 tlv->tlv.length_hi = (uint16_t)(ssl_tlv_len - sizeof(struct tlv)) >> 8;
1395 tlv->tlv.length_lo = (uint16_t)(ssl_tlv_len - sizeof(struct tlv)) & 0x00ff;
1396 ret += ssl_tlv_len;
1397 }
1398#endif
1399
Willy Tarreaue5733232019-05-22 19:24:06 +02001400#ifdef USE_NS
KOVACS Krisztianb3e54fe2014-11-17 15:11:45 +01001401 if (remote && (remote->proxy_netns)) {
1402 if ((buf_len - ret) < sizeof(struct tlv))
1403 return 0;
Emmanuel Hocdet571c7ac2017-10-31 18:24:05 +01001404 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 +01001405 }
1406#endif
1407
Willy Tarreau8fccfa22014-06-14 08:28:06 +02001408 hdr->len = htons((uint16_t)(ret - PP2_HEADER_LEN));
David Safb76832014-05-08 23:42:08 -04001409
Emmanuel Hocdet4399c752018-02-05 15:26:43 +01001410 if (tlv_crc32c_p) {
1411 write_u32(tlv_crc32c_p, htonl(hash_crc32c(buf, ret)));
1412 }
1413
David Safb76832014-05-08 23:42:08 -04001414 return ret;
1415}
Emeric Brun4f603012017-01-05 15:11:44 +01001416
Willy Tarreau119e50e2020-05-22 13:53:29 +02001417/* returns 0 on success */
1418static int cfg_parse_pp2_never_send_local(char **args, int section_type, struct proxy *curpx,
Willy Tarreau01825162021-03-09 09:53:46 +01001419 const struct proxy *defpx, const char *file, int line,
Willy Tarreau119e50e2020-05-22 13:53:29 +02001420 char **err)
1421{
1422 if (too_many_args(0, args, err, NULL))
1423 return -1;
1424 pp2_never_send_local = 1;
1425 return 0;
1426}
1427
Willy Tarreaua7d14552021-06-16 17:35:20 +02001428/* extracts some info from the connection and appends them to buffer <buf>. The
1429 * connection's pointer, its direction, target (fe/be/srv), xprt/ctrl, source
1430 * when set, destination when set, are printed in a compact human-readable format
1431 * fitting on a single line. This is handy to complete traces or debug output.
1432 * It is permitted to pass a NULL conn pointer. The number of characters emitted
1433 * is returned. A prefix <pfx> might be prepended before the first field if not
1434 * NULL.
1435 */
1436int conn_append_debug_info(struct buffer *buf, const struct connection *conn, const char *pfx)
1437{
1438 const struct listener *li;
1439 const struct server *sv;
1440 const struct proxy *px;
1441 char addr[40];
1442 int old_len = buf->data;
1443
1444 if (!conn)
1445 return 0;
1446
1447 chunk_appendf(buf, "%sconn=%p(%s)", pfx ? pfx : "", conn, conn_is_back(conn) ? "OUT" : "IN");
1448
1449 if ((li = objt_listener(conn->target)))
1450 chunk_appendf(buf, " fe=%s", li->bind_conf->frontend->id);
1451 else if ((sv = objt_server(conn->target)))
1452 chunk_appendf(buf, " sv=%s/%s", sv->proxy->id, sv->id);
1453 else if ((px = objt_proxy(conn->target)))
1454 chunk_appendf(buf, " be=%s", px->id);
1455
1456 chunk_appendf(buf, " %s/%s", conn_get_xprt_name(conn), conn_get_ctrl_name(conn));
1457
1458 if (conn->flags & CO_FL_ADDR_FROM_SET && addr_to_str(conn->src, addr, sizeof(addr)))
1459 chunk_appendf(buf, " src=%s:%d", addr, get_host_port(conn->src));
1460
1461 if (conn->flags & CO_FL_ADDR_TO_SET && addr_to_str(conn->dst, addr, sizeof(addr)))
1462 chunk_appendf(buf, " dst=%s:%d", addr, get_host_port(conn->dst));
1463
1464 return buf->data - old_len;
1465}
1466
Willy Tarreau60ca10a2017-08-18 15:26:54 +02001467/* return the major HTTP version as 1 or 2 depending on how the request arrived
1468 * before being processed.
Christopher Fauletf4dd9ae2021-04-14 15:40:30 +02001469 *
1470 * WARNING: Should be updated if a new major HTTP version is added.
Willy Tarreau60ca10a2017-08-18 15:26:54 +02001471 */
1472static int
1473smp_fetch_fc_http_major(const struct arg *args, struct sample *smp, const char *kw, void *private)
1474{
Christopher Faulet242f8ce2021-04-14 15:46:49 +02001475 struct connection *conn = NULL;
1476
1477 if (obj_type(smp->sess->origin) == OBJ_TYPE_CHECK)
1478 conn = (kw[0] == 'b') ? cs_conn(__objt_check(smp->sess->origin)->cs) : NULL;
1479 else
1480 conn = (kw[0] != 'b') ? objt_conn(smp->sess->origin) :
1481 smp->strm ? cs_conn(objt_cs(smp->strm->si[1].end)) : NULL;
Willy Tarreau60ca10a2017-08-18 15:26:54 +02001482
Christopher Fauletf4dd9ae2021-04-14 15:40:30 +02001483 /* No connection or a connection with a RAW muxx */
1484 if (!conn || (conn->mux && !(conn->mux->flags & MX_FL_HTX)))
1485 return 0;
1486
1487 /* No mux install, this may change */
1488 if (!conn->mux) {
1489 smp->flags |= SMP_F_MAY_CHANGE;
1490 return 0;
1491 }
1492
Willy Tarreau60ca10a2017-08-18 15:26:54 +02001493 smp->data.type = SMP_T_SINT;
Christopher Fauletf4dd9ae2021-04-14 15:40:30 +02001494 smp->data.u.sint = (strcmp(conn_get_mux_name(conn), "H2") == 0) ? 2 : 1;
Willy Tarreau60ca10a2017-08-18 15:26:54 +02001495 return 1;
1496}
1497
Emeric Brun4f603012017-01-05 15:11:44 +01001498/* fetch if the received connection used a PROXY protocol header */
1499int smp_fetch_fc_rcvd_proxy(const struct arg *args, struct sample *smp, const char *kw, void *private)
1500{
1501 struct connection *conn;
1502
1503 conn = objt_conn(smp->sess->origin);
1504 if (!conn)
1505 return 0;
1506
Willy Tarreau911db9b2020-01-23 16:27:54 +01001507 if (conn->flags & CO_FL_WAIT_XPRT) {
Emeric Brun4f603012017-01-05 15:11:44 +01001508 smp->flags |= SMP_F_MAY_CHANGE;
1509 return 0;
1510 }
1511
1512 smp->flags = 0;
1513 smp->data.type = SMP_T_BOOL;
1514 smp->data.u.sint = (conn->flags & CO_FL_RCVD_PROXY) ? 1 : 0;
1515
1516 return 1;
1517}
1518
Geoff Simmons7185b782019-08-27 18:31:16 +02001519/* fetch the authority TLV from a PROXY protocol header */
1520int smp_fetch_fc_pp_authority(const struct arg *args, struct sample *smp, const char *kw, void *private)
1521{
1522 struct connection *conn;
1523
1524 conn = objt_conn(smp->sess->origin);
1525 if (!conn)
1526 return 0;
1527
Willy Tarreau911db9b2020-01-23 16:27:54 +01001528 if (conn->flags & CO_FL_WAIT_XPRT) {
Geoff Simmons7185b782019-08-27 18:31:16 +02001529 smp->flags |= SMP_F_MAY_CHANGE;
1530 return 0;
1531 }
1532
Tim Duesterhus615f81e2021-03-06 20:06:50 +01001533 if (!isttest(conn->proxy_authority))
Geoff Simmons7185b782019-08-27 18:31:16 +02001534 return 0;
1535
1536 smp->flags = 0;
1537 smp->data.type = SMP_T_STR;
Tim Duesterhus615f81e2021-03-06 20:06:50 +01001538 smp->data.u.str.area = istptr(conn->proxy_authority);
1539 smp->data.u.str.data = istlen(conn->proxy_authority);
Geoff Simmons7185b782019-08-27 18:31:16 +02001540
1541 return 1;
1542}
1543
Tim Duesterhusd1b15b62020-03-13 12:34:23 +01001544/* fetch the unique ID TLV from a PROXY protocol header */
1545int smp_fetch_fc_pp_unique_id(const struct arg *args, struct sample *smp, const char *kw, void *private)
1546{
1547 struct connection *conn;
1548
1549 conn = objt_conn(smp->sess->origin);
1550 if (!conn)
1551 return 0;
1552
1553 if (conn->flags & CO_FL_WAIT_XPRT) {
1554 smp->flags |= SMP_F_MAY_CHANGE;
1555 return 0;
1556 }
1557
1558 if (!isttest(conn->proxy_unique_id))
1559 return 0;
1560
1561 smp->flags = 0;
1562 smp->data.type = SMP_T_STR;
Tim Duesterhus002bd772021-03-06 20:06:49 +01001563 smp->data.u.str.area = istptr(conn->proxy_unique_id);
1564 smp->data.u.str.data = istlen(conn->proxy_unique_id);
Tim Duesterhusd1b15b62020-03-13 12:34:23 +01001565
1566 return 1;
1567}
1568
Emeric Brun4f603012017-01-05 15:11:44 +01001569/* Note: must not be declared <const> as its list will be overwritten.
1570 * Note: fetches that may return multiple types must be declared as the lowest
1571 * common denominator, the type that can be casted into all other ones. For
1572 * instance v4/v6 must be declared v4.
1573 */
1574static struct sample_fetch_kw_list sample_fetch_keywords = {ILH, {
Willy Tarreau60ca10a2017-08-18 15:26:54 +02001575 { "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 +01001576 { "bc_http_major", smp_fetch_fc_http_major, 0, NULL, SMP_T_SINT, SMP_USE_L4SRV },
Emeric Brun4f603012017-01-05 15:11:44 +01001577 { "fc_rcvd_proxy", smp_fetch_fc_rcvd_proxy, 0, NULL, SMP_T_BOOL, SMP_USE_L4CLI },
Geoff Simmons7185b782019-08-27 18:31:16 +02001578 { "fc_pp_authority", smp_fetch_fc_pp_authority, 0, NULL, SMP_T_STR, SMP_USE_L4CLI },
Tim Duesterhusd1b15b62020-03-13 12:34:23 +01001579 { "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 +01001580 { /* END */ },
1581}};
1582
Willy Tarreau0108d902018-11-25 19:14:37 +01001583INITCALL1(STG_REGISTER, sample_register_fetches, &sample_fetch_keywords);
Willy Tarreau119e50e2020-05-22 13:53:29 +02001584
1585static struct cfg_kw_list cfg_kws = {ILH, {
1586 { CFG_GLOBAL, "pp2-never-send-local", cfg_parse_pp2_never_send_local },
1587 { /* END */ },
1588}};
1589
1590INITCALL1(STG_REGISTER, cfg_register_keywords, &cfg_kws);
Amaury Denoyelle81c6f762021-01-18 14:57:50 +01001591
Amaury Denoyelle01a287f2021-02-11 16:46:53 +01001592/* private function to handle sockaddr as input for connection hash */
1593static void conn_calculate_hash_sockaddr(const struct sockaddr_storage *ss,
1594 char *buf, size_t *idx,
1595 enum conn_hash_params_t *hash_flags,
1596 enum conn_hash_params_t param_type_addr,
1597 enum conn_hash_params_t param_type_port)
1598{
1599 struct sockaddr_in *addr;
1600 struct sockaddr_in6 *addr6;
1601
1602 switch (ss->ss_family) {
1603 case AF_INET:
1604 addr = (struct sockaddr_in *)ss;
1605
1606 conn_hash_update(buf, idx,
1607 &addr->sin_addr, sizeof(addr->sin_addr),
1608 hash_flags, param_type_addr);
1609
1610 if (addr->sin_port) {
1611 conn_hash_update(buf, idx,
1612 &addr->sin_port, sizeof(addr->sin_port),
1613 hash_flags, param_type_port);
1614 }
1615
1616 break;
1617
1618 case AF_INET6:
1619 addr6 = (struct sockaddr_in6 *)ss;
1620
1621 conn_hash_update(buf, idx,
1622 &addr6->sin6_addr, sizeof(addr6->sin6_addr),
1623 hash_flags, param_type_addr);
1624
1625 if (addr6->sin6_port) {
1626 conn_hash_update(buf, idx,
1627 &addr6->sin6_port, sizeof(addr6->sin6_port),
1628 hash_flags, param_type_port);
1629 }
1630
1631 break;
1632 }
1633}
1634
Amaury Denoyelle81c6f762021-01-18 14:57:50 +01001635XXH64_hash_t conn_calculate_hash(const struct conn_hash_params *params)
1636{
1637 char *buf;
1638 size_t idx = 0;
1639 XXH64_hash_t hash = 0;
1640 enum conn_hash_params_t hash_flags = 0;
1641
1642 buf = trash.area;
1643
Amaury Denoyelle8ede3db2021-03-02 14:38:53 +01001644 conn_hash_update(buf, &idx, &params->target, sizeof(params->target), &hash_flags, 0);
Amaury Denoyelle1a58aca2021-01-22 16:47:46 +01001645
Amaury Denoyelle9b626e32021-01-06 17:03:27 +01001646 if (params->sni_prehash) {
1647 conn_hash_update(buf, &idx,
Amaury Denoyelle36441f42021-02-17 16:25:31 +01001648 &params->sni_prehash, sizeof(params->sni_prehash),
Amaury Denoyelle9b626e32021-01-06 17:03:27 +01001649 &hash_flags, CONN_HASH_PARAMS_TYPE_SNI);
1650 }
1651
Amaury Denoyelle01a287f2021-02-11 16:46:53 +01001652 if (params->dst_addr) {
1653 conn_calculate_hash_sockaddr(params->dst_addr,
1654 buf, &idx, &hash_flags,
1655 CONN_HASH_PARAMS_TYPE_DST_ADDR,
1656 CONN_HASH_PARAMS_TYPE_DST_PORT);
1657 }
1658
Amaury Denoyelled10a2002021-02-11 19:45:19 +01001659 if (params->src_addr) {
1660 conn_calculate_hash_sockaddr(params->src_addr,
1661 buf, &idx, &hash_flags,
1662 CONN_HASH_PARAMS_TYPE_SRC_ADDR,
1663 CONN_HASH_PARAMS_TYPE_SRC_PORT);
1664 }
1665
Amaury Denoyelle1921d202021-01-14 10:15:29 +01001666 if (params->proxy_prehash) {
1667 conn_hash_update(buf, &idx,
Amaury Denoyelle36441f42021-02-17 16:25:31 +01001668 &params->proxy_prehash, sizeof(params->proxy_prehash),
Amaury Denoyelle1921d202021-01-14 10:15:29 +01001669 &hash_flags, CONN_HASH_PARAMS_TYPE_PROXY);
1670 }
Amaury Denoyelle01a287f2021-02-11 16:46:53 +01001671
Amaury Denoyelle1921d202021-01-14 10:15:29 +01001672 hash = conn_hash_digest(buf, idx, hash_flags);
Amaury Denoyelle81c6f762021-01-18 14:57:50 +01001673 return hash;
1674}
Amaury Denoyelle1e572682021-09-16 12:15:12 +02001675
1676/* Handler of the task of mux_stopping_data.
1677 * Called on soft-stop.
1678 */
1679static struct task *mux_stopping_process(struct task *t, void *ctx, unsigned int state)
1680{
1681 struct connection *conn, *back;
1682
1683 list_for_each_entry_safe(conn, back, &mux_stopping_data[tid].list, stopping_list) {
1684 if (conn->mux && conn->mux->wake)
1685 conn->mux->wake(conn);
1686 }
1687
1688 return t;
1689}
1690
1691static int allocate_mux_cleanup(void)
1692{
1693 /* allocates the thread bound mux_stopping_data task */
1694 mux_stopping_data[tid].task = task_new(tid_bit);
1695 if (!mux_stopping_data[tid].task) {
1696 ha_alert("Failed to allocate the task for connection cleanup on thread %d.\n", tid);
1697 return 0;
1698 }
1699
1700 mux_stopping_data[tid].task->process = mux_stopping_process;
1701 LIST_INIT(&mux_stopping_data[tid].list);
1702
1703 return 1;
1704}
1705REGISTER_PER_THREAD_ALLOC(allocate_mux_cleanup);
1706
1707static int deallocate_mux_cleanup(void)
1708{
1709 task_destroy(mux_stopping_data[tid].task);
1710 return 1;
1711}
1712REGISTER_PER_THREAD_FREE(deallocate_mux_cleanup);