blob: 6886768070f3fc445bba4fa88e66809b65c489a4 [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 Tarreau119e50e2020-05-22 13:53:29 +020015#include <common/cfgparse.h>
Willy Tarreau59f98392012-07-06 14:13:49 +020016#include <common/compat.h>
17#include <common/config.h>
Willy Tarreau0108d902018-11-25 19:14:37 +010018#include <common/initcall.h>
KOVACS Krisztianb3e54fe2014-11-17 15:11:45 +010019#include <common/namespace.h>
Emmanuel Hocdet4399c752018-02-05 15:26:43 +010020#include <common/hash.h>
21#include <common/net_helper.h>
Willy Tarreau59f98392012-07-06 14:13:49 +020022
Willy Tarreauc5788912012-08-24 18:12:41 +020023#include <proto/connection.h>
Willy Tarreaudd2f85e2012-09-02 22:34:23 +020024#include <proto/fd.h>
Willy Tarreau5f1504f2012-10-04 23:55:57 +020025#include <proto/frontend.h>
Willy Tarreau2da156f2012-07-23 15:07:23 +020026#include <proto/proto_tcp.h>
Willy Tarreau2c6be842012-07-06 17:12:34 +020027#include <proto/stream_interface.h>
Emeric Brun4f603012017-01-05 15:11:44 +010028#include <proto/sample.h>
Emeric Brun46591952012-05-18 15:47:34 +020029#include <proto/ssl_sock.h>
Emeric Brun46591952012-05-18 15:47:34 +020030
Alexander Liu2a54bb72019-05-22 19:44:48 +080031#include <common/debug.h>
32
Willy Tarreau8ceae722018-11-26 11:58:30 +010033DECLARE_POOL(pool_head_connection, "connection", sizeof(struct connection));
34DECLARE_POOL(pool_head_connstream, "conn_stream", sizeof(struct conn_stream));
Willy Tarreauff5d57b2019-07-17 18:37:02 +020035DECLARE_POOL(pool_head_sockaddr, "sockaddr", sizeof(struct sockaddr_storage));
Geoff Simmons7185b782019-08-27 18:31:16 +020036DECLARE_POOL(pool_head_authority, "authority", PP2_AUTHORITY_MAX);
Willy Tarreau8ceae722018-11-26 11:58:30 +010037
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
Willy Tarreau119e50e2020-05-22 13:53:29 +020045/* disables sending of proxy-protocol-v2's LOCAL command */
46static int pp2_never_send_local;
47
Olivier Houchard477902b2020-01-22 18:08:48 +010048int conn_create_mux(struct connection *conn)
49{
Olivier Houchard477902b2020-01-22 18:08:48 +010050 if (conn_is_back(conn)) {
51 struct server *srv;
52 struct conn_stream *cs = conn->ctx;
Christopher Faulet14cd3162020-04-16 14:50:06 +020053 struct session *sess = conn->owner;
Olivier Houchard477902b2020-01-22 18:08:48 +010054
55 if (conn->flags & CO_FL_ERROR)
56 goto fail;
Olivier Houcharda8a415d2020-01-23 13:15:14 +010057
Christopher Faulet14cd3162020-04-16 14:50:06 +020058 if (sess && obj_type(sess->origin) == OBJ_TYPE_CHECK) {
59 if (conn_install_mux_chk(conn, conn->ctx, conn->owner) < 0)
60 goto fail;
61 }
62 else if (conn_install_mux_be(conn, conn->ctx, conn->owner) < 0)
Olivier Houchard477902b2020-01-22 18:08:48 +010063 goto fail;
64 srv = objt_server(conn->target);
65 if (srv && ((srv->proxy->options & PR_O_REUSE_MASK) != PR_O_REUSE_NEVR) &&
66 conn->mux->avail_streams(conn) > 0)
Olivier Houchardf0d4dff2020-03-06 18:12:03 +010067 LIST_ADDQ(&srv->available_conns[tid], mt_list_to_list(&conn->list));
Olivier Houchard477902b2020-01-22 18:08:48 +010068 return 0;
69fail:
70 /* let the upper layer know the connection failed */
71 cs->data_cb->wake(cs);
72 return -1;
73 } else
74 return conn_complete_session(conn);
75
76}
77
Willy Tarreau59f98392012-07-06 14:13:49 +020078/* I/O callback for fd-based connections. It calls the read/write handlers
Willy Tarreau7a798e52016-04-14 11:13:20 +020079 * provided by the connection's sock_ops, which must be valid.
Willy Tarreau59f98392012-07-06 14:13:49 +020080 */
Willy Tarreau7a798e52016-04-14 11:13:20 +020081void conn_fd_handler(int fd)
Willy Tarreau59f98392012-07-06 14:13:49 +020082{
Willy Tarreau80184712012-07-06 14:54:49 +020083 struct connection *conn = fdtab[fd].owner;
Willy Tarreau9e272bf2012-10-03 21:04:48 +020084 unsigned int flags;
Willy Tarreau8de5c4f2020-03-04 17:45:21 +010085 int need_wake = 0;
Willy Tarreau59f98392012-07-06 14:13:49 +020086
Willy Tarreaud80cb4e2018-01-20 19:30:13 +010087 if (unlikely(!conn)) {
88 activity[tid].conn_dead++;
Willy Tarreau7a798e52016-04-14 11:13:20 +020089 return;
Willy Tarreaud80cb4e2018-01-20 19:30:13 +010090 }
Willy Tarreau59f98392012-07-06 14:13:49 +020091
Willy Tarreau7d281492012-12-16 19:19:13 +010092 flags = conn->flags & ~CO_FL_ERROR; /* ensure to call the wake handler upon error */
Willy Tarreaud29a0662012-12-10 16:33:38 +010093
Willy Tarreaub2a7ab02019-12-27 10:54:22 +010094 if (unlikely(conn->flags & CO_FL_WAIT_L4_CONN) &&
95 ((fd_send_ready(fd) && fd_send_active(fd)) ||
96 (fd_recv_ready(fd) && fd_recv_active(fd)))) {
97 /* Still waiting for a connection to establish and nothing was
98 * attempted yet to probe the connection. this will clear the
99 * CO_FL_WAIT_L4_CONN flag on success.
100 */
101 if (!conn_fd_check(conn))
102 goto leave;
Willy Tarreau8de5c4f2020-03-04 17:45:21 +0100103 need_wake = 1;
Willy Tarreaub2a7ab02019-12-27 10:54:22 +0100104 }
105
Willy Tarreau8081abe2019-11-28 18:08:49 +0100106 if (fd_send_ready(fd) && fd_send_active(fd)) {
Willy Tarreau3c0cc492017-03-19 07:54:28 +0100107 /* force reporting of activity by clearing the previous flags :
108 * we'll have at least ERROR or CONNECTED at the end of an I/O,
109 * both of which will be detected below.
Willy Tarreau9e272bf2012-10-03 21:04:48 +0200110 */
Willy Tarreau3c0cc492017-03-19 07:54:28 +0100111 flags = 0;
Willy Tarreau7872d1f2020-01-10 07:06:05 +0100112 if (conn->subs && conn->subs->events & SUB_RETRY_SEND) {
Willy Tarreau8de5c4f2020-03-04 17:45:21 +0100113 need_wake = 0; // wake will be called after this I/O
Willy Tarreau7872d1f2020-01-10 07:06:05 +0100114 tasklet_wakeup(conn->subs->tasklet);
115 conn->subs->events &= ~SUB_RETRY_SEND;
116 if (!conn->subs->events)
117 conn->subs = NULL;
Willy Tarreau8de5c4f2020-03-04 17:45:21 +0100118 }
Willy Tarreau667fefd2020-03-04 17:22:10 +0100119 fd_stop_send(fd);
Willy Tarreau9e272bf2012-10-03 21:04:48 +0200120 }
Willy Tarreau59f98392012-07-06 14:13:49 +0200121
Willy Tarreau57ec32f2017-04-11 19:59:33 +0200122 /* The data transfer starts here and stops on error and handshakes. Note
123 * that we must absolutely test conn->xprt at each step in case it suddenly
124 * changes due to a quick unexpected close().
125 */
Willy Tarreau8081abe2019-11-28 18:08:49 +0100126 if (fd_recv_ready(fd) && fd_recv_active(fd)) {
Willy Tarreau3c0cc492017-03-19 07:54:28 +0100127 /* force reporting of activity by clearing the previous flags :
128 * we'll have at least ERROR or CONNECTED at the end of an I/O,
129 * both of which will be detected below.
Willy Tarreau9e272bf2012-10-03 21:04:48 +0200130 */
Willy Tarreau3c0cc492017-03-19 07:54:28 +0100131 flags = 0;
Willy Tarreau7872d1f2020-01-10 07:06:05 +0100132 if (conn->subs && conn->subs->events & SUB_RETRY_RECV) {
Willy Tarreau8de5c4f2020-03-04 17:45:21 +0100133 need_wake = 0; // wake will be called after this I/O
Willy Tarreau7872d1f2020-01-10 07:06:05 +0100134 tasklet_wakeup(conn->subs->tasklet);
135 conn->subs->events &= ~SUB_RETRY_RECV;
136 if (!conn->subs->events)
137 conn->subs = NULL;
Willy Tarreau8de5c4f2020-03-04 17:45:21 +0100138 }
Willy Tarreau6f95f6e2020-03-04 18:33:19 +0100139 else if (tasks_run_queue_cur >= 16*global.tune.runqueue_depth) {
140 /* In order to save syscalls especially with epoll, we
141 * prefer *not* to disable receiving and instead let
142 * the handler do its job. But if the run queue becomes
143 * high, the excess of events may cause extra wakeups
144 * and in this case we'd rather flow-control ourselves.
145 */
146 fd_stop_recv(fd);
147 }
Willy Tarreau9e272bf2012-10-03 21:04:48 +0200148 }
Willy Tarreau2da156f2012-07-23 15:07:23 +0200149
Willy Tarreau2c6be842012-07-06 17:12:34 +0200150 leave:
Olivier Houchard477902b2020-01-22 18:08:48 +0100151 /* If we don't yet have a mux, that means we were waiting for
Ilya Shipitsince7b00f2020-03-23 22:28:40 +0500152 * information to create one, typically from the ALPN. If we're
Olivier Houchard477902b2020-01-22 18:08:48 +0100153 * done with the handshake, attempt to create one.
Willy Tarreau8e3c6ce2017-08-28 15:46:01 +0200154 */
Willy Tarreau911db9b2020-01-23 16:27:54 +0100155 if (unlikely(!conn->mux) && !(conn->flags & CO_FL_WAIT_XPRT))
Olivier Houchard477902b2020-01-22 18:08:48 +0100156 if (conn_create_mux(conn) < 0)
157 return;
Willy Tarreau8e3c6ce2017-08-28 15:46:01 +0200158
Willy Tarreau3c0cc492017-03-19 07:54:28 +0100159 /* The wake callback is normally used to notify the data layer about
160 * data layer activity (successful send/recv), connection establishment,
161 * shutdown and fatal errors. We need to consider the following
162 * situations to wake up the data layer :
Willy Tarreau0fbc3182019-12-27 14:57:45 +0100163 * - change among the CO_FL_NOTIFY_DONE flags :
164 * SOCK_{RD,WR}_SH, ERROR,
Willy Tarreau3c0cc492017-03-19 07:54:28 +0100165 * - absence of any of {L4,L6}_CONN and CONNECTED, indicating the
166 * end of handshake and transition to CONNECTED
167 * - raise of CONNECTED with HANDSHAKE down
168 * - end of HANDSHAKE with CONNECTED set
169 * - regular data layer activity
170 *
171 * Note that the wake callback is allowed to release the connection and
172 * the fd (and return < 0 in this case).
Willy Tarreau2396c1c2012-10-03 21:12:16 +0200173 */
Willy Tarreau8de5c4f2020-03-04 17:45:21 +0100174 if ((need_wake || ((conn->flags ^ flags) & CO_FL_NOTIFY_DONE) ||
Willy Tarreau911db9b2020-01-23 16:27:54 +0100175 ((flags & CO_FL_WAIT_XPRT) && !(conn->flags & CO_FL_WAIT_XPRT))) &&
Olivier Houchardfe50bfb2019-05-27 12:09:19 +0200176 conn->mux && conn->mux->wake && conn->mux->wake(conn) < 0)
Willy Tarreau7a798e52016-04-14 11:13:20 +0200177 return;
Willy Tarreaufd31e532012-07-23 18:24:25 +0200178
Willy Tarreauf9dabec2012-08-17 17:33:53 +0200179 /* commit polling changes */
180 conn_cond_update_polling(conn);
Willy Tarreau7a798e52016-04-14 11:13:20 +0200181 return;
Willy Tarreau59f98392012-07-06 14:13:49 +0200182}
Willy Tarreaub5e2cbd2012-08-17 11:55:04 +0200183
Willy Tarreau4970e5a2019-12-27 10:40:21 +0100184/* This is the callback which is set when a connection establishment is pending
185 * and we have nothing to send. It may update the FD polling status to indicate
186 * !READY. It returns 0 if it fails in a fatal way or needs to poll to go
187 * further, otherwise it returns non-zero and removes the CO_FL_WAIT_L4_CONN
188 * flag from the connection's flags. In case of error, it sets CO_FL_ERROR and
189 * leaves the error code in errno.
190 */
191int conn_fd_check(struct connection *conn)
192{
193 struct sockaddr_storage *addr;
194 int fd = conn->handle.fd;
195
196 if (conn->flags & CO_FL_ERROR)
197 return 0;
198
199 if (!conn_ctrl_ready(conn))
200 return 0;
201
202 if (!(conn->flags & CO_FL_WAIT_L4_CONN))
203 return 1; /* strange we were called while ready */
204
205 if (!fd_send_ready(fd))
206 return 0;
207
208 /* Here we have 2 cases :
209 * - modern pollers, able to report ERR/HUP. If these ones return any
210 * of these flags then it's likely a failure, otherwise it possibly
211 * is a success (i.e. there may have been data received just before
212 * the error was reported).
213 * - select, which doesn't report these and with which it's always
214 * necessary either to try connect() again or to check for SO_ERROR.
215 * In order to simplify everything, we double-check using connect() as
216 * soon as we meet either of these delicate situations. Note that
217 * SO_ERROR would clear the error after reporting it!
218 */
219 if (cur_poller.flags & HAP_POLL_F_ERRHUP) {
220 /* modern poller, able to report ERR/HUP */
221 if ((fdtab[fd].ev & (FD_POLL_IN|FD_POLL_ERR|FD_POLL_HUP)) == FD_POLL_IN)
222 goto done;
223 if ((fdtab[fd].ev & (FD_POLL_OUT|FD_POLL_ERR|FD_POLL_HUP)) == FD_POLL_OUT)
224 goto done;
225 if (!(fdtab[fd].ev & (FD_POLL_ERR|FD_POLL_HUP)))
226 goto wait;
227 /* error present, fall through common error check path */
228 }
229
230 /* Use connect() to check the state of the socket. This has the double
231 * advantage of *not* clearing the error (so that health checks can
232 * still use getsockopt(SO_ERROR)) and giving us the following info :
233 * - error
234 * - connecting (EALREADY, EINPROGRESS)
235 * - connected (EISCONN, 0)
236 */
237 addr = conn->dst;
238 if ((conn->flags & CO_FL_SOCKS4) && obj_type(conn->target) == OBJ_TYPE_SERVER)
239 addr = &objt_server(conn->target)->socks4_addr;
240
241 if (connect(fd, (const struct sockaddr *)addr, get_addr_len(addr)) == -1) {
242 if (errno == EALREADY || errno == EINPROGRESS)
243 goto wait;
244
245 if (errno && errno != EISCONN)
246 goto out_error;
247 }
248
249 done:
250 /* The FD is ready now, we'll mark the connection as complete and
251 * forward the event to the transport layer which will notify the
252 * data layer.
253 */
254 conn->flags &= ~CO_FL_WAIT_L4_CONN;
255 fd_may_send(fd);
256 fd_cond_recv(fd);
257 errno = 0; // make health checks happy
258 return 1;
259
260 out_error:
261 /* Write error on the file descriptor. Report it to the connection
262 * and disable polling on this FD.
263 */
264 fdtab[fd].linger_risk = 0;
265 conn->flags |= CO_FL_ERROR | CO_FL_SOCK_RD_SH | CO_FL_SOCK_WR_SH;
Willy Tarreau5d4d1802020-02-21 09:58:29 +0100266 conn_stop_polling(conn);
Willy Tarreau4970e5a2019-12-27 10:40:21 +0100267 return 0;
268
269 wait:
Willy Tarreau4970e5a2019-12-27 10:40:21 +0100270 fd_cant_send(fd);
Willy Tarreaud1d14c32020-02-21 10:34:19 +0100271 fd_want_send(fd);
Willy Tarreau4970e5a2019-12-27 10:40:21 +0100272 return 0;
273}
274
Willy Tarreauff3e6482015-03-12 23:56:52 +0100275/* Send a message over an established connection. It makes use of send() and
276 * returns the same return code and errno. If the socket layer is not ready yet
277 * then -1 is returned and ENOTSOCK is set into errno. If the fd is not marked
278 * as ready, or if EAGAIN or ENOTCONN is returned, then we return 0. It returns
279 * EMSGSIZE if called with a zero length message. The purpose is to simplify
280 * some rare attempts to directly write on the socket from above the connection
281 * (typically send_proxy). In case of EAGAIN, the fd is marked as "cant_send".
282 * It automatically retries on EINTR. Other errors cause the connection to be
283 * marked as in error state. It takes similar arguments as send() except the
284 * first one which is the connection instead of the file descriptor. Note,
285 * MSG_DONTWAIT and MSG_NOSIGNAL are forced on the flags.
286 */
287int conn_sock_send(struct connection *conn, const void *buf, int len, int flags)
288{
289 int ret;
290
291 ret = -1;
292 errno = ENOTSOCK;
293
294 if (conn->flags & CO_FL_SOCK_WR_SH)
295 goto fail;
296
297 if (!conn_ctrl_ready(conn))
298 goto fail;
299
300 errno = EMSGSIZE;
301 if (!len)
302 goto fail;
303
Willy Tarreau585744b2017-08-24 14:31:19 +0200304 if (!fd_send_ready(conn->handle.fd))
Willy Tarreauff3e6482015-03-12 23:56:52 +0100305 goto wait;
306
307 do {
Willy Tarreau585744b2017-08-24 14:31:19 +0200308 ret = send(conn->handle.fd, buf, len, flags | MSG_DONTWAIT | MSG_NOSIGNAL);
Willy Tarreauff3e6482015-03-12 23:56:52 +0100309 } while (ret < 0 && errno == EINTR);
310
311
Willy Tarreauccf3f6d2019-09-05 17:05:05 +0200312 if (ret > 0) {
313 if (conn->flags & CO_FL_WAIT_L4_CONN) {
314 conn->flags &= ~CO_FL_WAIT_L4_CONN;
315 fd_may_send(conn->handle.fd);
316 fd_cond_recv(conn->handle.fd);
317 }
Willy Tarreauff3e6482015-03-12 23:56:52 +0100318 return ret;
Willy Tarreauccf3f6d2019-09-05 17:05:05 +0200319 }
Willy Tarreauff3e6482015-03-12 23:56:52 +0100320
321 if (ret == 0 || errno == EAGAIN || errno == ENOTCONN) {
322 wait:
Willy Tarreau585744b2017-08-24 14:31:19 +0200323 fd_cant_send(conn->handle.fd);
Willy Tarreauff3e6482015-03-12 23:56:52 +0100324 return 0;
325 }
326 fail:
327 conn->flags |= CO_FL_SOCK_RD_SH | CO_FL_SOCK_WR_SH | CO_FL_ERROR;
328 return ret;
329}
330
Willy Tarreauee1a6fc2020-01-17 07:52:13 +0100331/* Called from the upper layer, to subscribe <es> to events <event_type>. The
332 * event subscriber <es> is not allowed to change from a previous call as long
333 * as at least one event is still subscribed. The <event_type> must only be a
334 * combination of SUB_RETRY_RECV and SUB_RETRY_SEND. It always returns 0.
335 */
336int conn_unsubscribe(struct connection *conn, void *xprt_ctx, int event_type, struct wait_event *es)
Olivier Houchard83a0cd82018-09-28 17:57:58 +0200337{
Willy Tarreau7872d1f2020-01-10 07:06:05 +0100338 BUG_ON(event_type & ~(SUB_RETRY_SEND|SUB_RETRY_RECV));
Willy Tarreauee1a6fc2020-01-17 07:52:13 +0100339 BUG_ON(conn->subs && conn->subs != es);
Willy Tarreau7872d1f2020-01-10 07:06:05 +0100340
Willy Tarreauee1a6fc2020-01-17 07:52:13 +0100341 es->events &= ~event_type;
342 if (!es->events)
Willy Tarreau7872d1f2020-01-10 07:06:05 +0100343 conn->subs = NULL;
344
Willy Tarreaud1d14c32020-02-21 10:34:19 +0100345 if (conn_ctrl_ready(conn)) {
346 if (event_type & SUB_RETRY_RECV)
347 fd_stop_recv(conn->handle.fd);
Willy Tarreau7872d1f2020-01-10 07:06:05 +0100348
Willy Tarreaud1d14c32020-02-21 10:34:19 +0100349 if (event_type & SUB_RETRY_SEND)
350 fd_stop_send(conn->handle.fd);
351 }
Olivier Houchard83a0cd82018-09-28 17:57:58 +0200352 return 0;
353}
354
Willy Tarreau7e59c0a2020-02-28 14:24:49 +0100355/* Called from the upper layer, to subscribe <es> to events <event_type>.
356 * The <es> struct is not allowed to differ from the one passed during a
357 * previous call to subscribe(). If the FD is ready, the wait_event is
358 * immediately woken up and the subcription is cancelled. It always
359 * returns zero.
Willy Tarreauee1a6fc2020-01-17 07:52:13 +0100360 */
361int conn_subscribe(struct connection *conn, void *xprt_ctx, int event_type, struct wait_event *es)
Olivier Houchard6ff20392018-07-17 18:46:31 +0200362{
Willy Tarreau7872d1f2020-01-10 07:06:05 +0100363 BUG_ON(event_type & ~(SUB_RETRY_SEND|SUB_RETRY_RECV));
Willy Tarreauee1a6fc2020-01-17 07:52:13 +0100364 BUG_ON(conn->subs && conn->subs != es);
Willy Tarreau7872d1f2020-01-10 07:06:05 +0100365
Willy Tarreau7e59c0a2020-02-28 14:24:49 +0100366 if (conn->subs && (conn->subs->events & event_type) == event_type)
367 return 0;
368
Willy Tarreauee1a6fc2020-01-17 07:52:13 +0100369 conn->subs = es;
370 es->events |= event_type;
Willy Tarreau7872d1f2020-01-10 07:06:05 +0100371
Willy Tarreaud1d14c32020-02-21 10:34:19 +0100372 if (conn_ctrl_ready(conn)) {
Willy Tarreau7e59c0a2020-02-28 14:24:49 +0100373 if (event_type & SUB_RETRY_RECV) {
374 if (fd_recv_ready(conn->handle.fd)) {
375 tasklet_wakeup(es->tasklet);
376 es->events &= ~SUB_RETRY_RECV;
377 if (!es->events)
378 conn->subs = NULL;
379 }
380 else
381 fd_want_recv(conn->handle.fd);
382 }
Willy Tarreau7872d1f2020-01-10 07:06:05 +0100383
Willy Tarreau7e59c0a2020-02-28 14:24:49 +0100384 if (event_type & SUB_RETRY_SEND) {
385 if (fd_send_ready(conn->handle.fd)) {
386 tasklet_wakeup(es->tasklet);
387 es->events &= ~SUB_RETRY_SEND;
388 if (!es->events)
389 conn->subs = NULL;
390 }
391 else
392 fd_want_send(conn->handle.fd);
393 }
Willy Tarreaud1d14c32020-02-21 10:34:19 +0100394 }
Olivier Houchard83a0cd82018-09-28 17:57:58 +0200395 return 0;
Olivier Houchard6ff20392018-07-17 18:46:31 +0200396}
397
Willy Tarreaud85c4852015-03-13 00:40:28 +0100398/* Drains possibly pending incoming data on the file descriptor attached to the
399 * connection and update the connection's flags accordingly. This is used to
400 * know whether we need to disable lingering on close. Returns non-zero if it
401 * is safe to close without disabling lingering, otherwise zero. The SOCK_RD_SH
402 * flag may also be updated if the incoming shutdown was reported by the drain()
403 * function.
404 */
405int conn_sock_drain(struct connection *conn)
406{
Willy Tarreaue215bba2018-08-24 14:31:53 +0200407 int turns = 2;
408 int len;
409
Willy Tarreaud85c4852015-03-13 00:40:28 +0100410 if (!conn_ctrl_ready(conn))
411 return 1;
412
413 if (conn->flags & (CO_FL_ERROR | CO_FL_SOCK_RD_SH))
414 return 1;
415
Willy Tarreaue215bba2018-08-24 14:31:53 +0200416 if (fdtab[conn->handle.fd].ev & (FD_POLL_ERR|FD_POLL_HUP))
417 goto shut;
Willy Tarreaud85c4852015-03-13 00:40:28 +0100418
Willy Tarreaue215bba2018-08-24 14:31:53 +0200419 if (!fd_recv_ready(conn->handle.fd))
420 return 0;
Willy Tarreaud85c4852015-03-13 00:40:28 +0100421
Willy Tarreaue215bba2018-08-24 14:31:53 +0200422 if (conn->ctrl->drain) {
Willy Tarreau585744b2017-08-24 14:31:19 +0200423 if (conn->ctrl->drain(conn->handle.fd) <= 0)
Willy Tarreaud85c4852015-03-13 00:40:28 +0100424 return 0;
Willy Tarreaue215bba2018-08-24 14:31:53 +0200425 goto shut;
426 }
427
428 /* no drain function defined, use the generic one */
429
430 while (turns) {
431#ifdef MSG_TRUNC_CLEARS_INPUT
432 len = recv(conn->handle.fd, NULL, INT_MAX, MSG_DONTWAIT | MSG_NOSIGNAL | MSG_TRUNC);
433 if (len == -1 && errno == EFAULT)
434#endif
435 len = recv(conn->handle.fd, trash.area, trash.size,
436 MSG_DONTWAIT | MSG_NOSIGNAL);
437
438 if (len == 0)
439 goto shut;
440
441 if (len < 0) {
442 if (errno == EAGAIN) {
443 /* connection not closed yet */
444 fd_cant_recv(conn->handle.fd);
445 break;
446 }
447 if (errno == EINTR) /* oops, try again */
448 continue;
449 /* other errors indicate a dead connection, fine. */
450 goto shut;
451 }
452 /* OK we read some data, let's try again once */
453 turns--;
Willy Tarreaud85c4852015-03-13 00:40:28 +0100454 }
455
Willy Tarreaue215bba2018-08-24 14:31:53 +0200456 /* some data are still present, give up */
457 return 0;
458
459 shut:
460 /* we're certain the connection was shut down */
461 fdtab[conn->handle.fd].linger_risk = 0;
Willy Tarreaud85c4852015-03-13 00:40:28 +0100462 conn->flags |= CO_FL_SOCK_RD_SH;
463 return 1;
464}
465
KOVACS Krisztianb3e54fe2014-11-17 15:11:45 +0100466/*
467 * Get data length from tlv
468 */
Tim Duesterhusba837ec2020-03-05 23:11:02 +0100469static inline size_t get_tlv_length(const struct tlv *src)
KOVACS Krisztianb3e54fe2014-11-17 15:11:45 +0100470{
471 return (src->length_hi << 8) | src->length_lo;
472}
473
Willy Tarreaue1e4a612012-10-05 00:10:55 +0200474/* This handshake handler waits a PROXY protocol header at the beginning of the
475 * raw data stream. The header looks like this :
476 *
477 * "PROXY" <SP> PROTO <SP> SRC3 <SP> DST3 <SP> SRC4 <SP> <DST4> "\r\n"
478 *
479 * There must be exactly one space between each field. Fields are :
480 * - PROTO : layer 4 protocol, which must be "TCP4" or "TCP6".
481 * - SRC3 : layer 3 (eg: IP) source address in standard text form
482 * - DST3 : layer 3 (eg: IP) destination address in standard text form
483 * - SRC4 : layer 4 (eg: TCP port) source address in standard text form
484 * - DST4 : layer 4 (eg: TCP port) destination address in standard text form
485 *
486 * This line MUST be at the beginning of the buffer and MUST NOT wrap.
487 *
488 * The header line is small and in all cases smaller than the smallest normal
489 * TCP MSS. So it MUST always be delivered as one segment, which ensures we
490 * can safely use MSG_PEEK and avoid buffering.
491 *
492 * Once the data is fetched, the values are set in the connection's address
493 * fields, and data are removed from the socket's buffer. The function returns
494 * zero if it needs to wait for more data or if it fails, or 1 if it completed
495 * and removed itself.
496 */
497int conn_recv_proxy(struct connection *conn, int flag)
498{
499 char *line, *end;
Willy Tarreau77992672014-06-14 11:06:17 +0200500 struct proxy_hdr_v2 *hdr_v2;
501 const char v2sig[] = PP2_SIGNATURE;
Tim Duesterhus488ee7f2020-03-05 22:55:20 +0100502 size_t total_v2_len;
Tim Duesterhusba837ec2020-03-05 23:11:02 +0100503 size_t tlv_offset = 0;
Willy Tarreaub406b872018-08-22 05:20:32 +0200504 int ret;
Willy Tarreaue1e4a612012-10-05 00:10:55 +0200505
Willy Tarreau3c728722014-01-23 13:50:42 +0100506 if (!conn_ctrl_ready(conn))
Willy Tarreauf79c8172013-10-21 16:30:56 +0200507 goto fail;
508
Willy Tarreauca79f592019-07-17 19:04:47 +0200509 if (!sockaddr_alloc(&conn->src) || !sockaddr_alloc(&conn->dst))
510 goto fail;
511
Willy Tarreau585744b2017-08-24 14:31:19 +0200512 if (!fd_recv_ready(conn->handle.fd))
Willy Tarreau6499b9d2019-06-03 08:17:30 +0200513 goto not_ready;
Willy Tarreaufd803bb2014-01-20 15:13:07 +0100514
Willy Tarreau157788c2020-02-11 10:08:05 +0100515 while (1) {
Willy Tarreaub406b872018-08-22 05:20:32 +0200516 ret = recv(conn->handle.fd, trash.area, trash.size, MSG_PEEK);
517 if (ret < 0) {
Willy Tarreaue1e4a612012-10-05 00:10:55 +0200518 if (errno == EINTR)
519 continue;
520 if (errno == EAGAIN) {
Willy Tarreau585744b2017-08-24 14:31:19 +0200521 fd_cant_recv(conn->handle.fd);
Willy Tarreau6499b9d2019-06-03 08:17:30 +0200522 goto not_ready;
Willy Tarreaue1e4a612012-10-05 00:10:55 +0200523 }
Willy Tarreau8e3bf692012-12-03 15:41:18 +0100524 goto recv_abort;
Willy Tarreaue1e4a612012-10-05 00:10:55 +0200525 }
Willy Tarreaub406b872018-08-22 05:20:32 +0200526 trash.data = ret;
Willy Tarreau157788c2020-02-11 10:08:05 +0100527 break;
528 }
Willy Tarreaue1e4a612012-10-05 00:10:55 +0200529
Willy Tarreau843b7cb2018-07-13 10:54:26 +0200530 if (!trash.data) {
Willy Tarreau8e3bf692012-12-03 15:41:18 +0100531 /* client shutdown */
532 conn->err_code = CO_ER_PRX_EMPTY;
533 goto fail;
534 }
535
Willy Tarreauc192b0a2020-01-23 09:11:58 +0100536 conn->flags &= ~CO_FL_WAIT_L4_CONN;
537
Willy Tarreau843b7cb2018-07-13 10:54:26 +0200538 if (trash.data < 6)
Willy Tarreaue1e4a612012-10-05 00:10:55 +0200539 goto missing;
540
Willy Tarreau843b7cb2018-07-13 10:54:26 +0200541 line = trash.area;
542 end = trash.area + trash.data;
Willy Tarreaue1e4a612012-10-05 00:10:55 +0200543
544 /* Decode a possible proxy request, fail early if it does not match */
Willy Tarreau77992672014-06-14 11:06:17 +0200545 if (strncmp(line, "PROXY ", 6) != 0)
546 goto not_v1;
Willy Tarreaue1e4a612012-10-05 00:10:55 +0200547
548 line += 6;
Willy Tarreau843b7cb2018-07-13 10:54:26 +0200549 if (trash.data < 9) /* shortest possible line */
Willy Tarreaue1e4a612012-10-05 00:10:55 +0200550 goto missing;
551
David CARLIER42ff05e2016-03-24 09:22:36 +0000552 if (memcmp(line, "TCP4 ", 5) == 0) {
Willy Tarreaue1e4a612012-10-05 00:10:55 +0200553 u32 src3, dst3, sport, dport;
554
555 line += 5;
556
557 src3 = inetaddr_host_lim_ret(line, end, &line);
558 if (line == end)
559 goto missing;
560 if (*line++ != ' ')
Willy Tarreau8e3bf692012-12-03 15:41:18 +0100561 goto bad_header;
Willy Tarreaue1e4a612012-10-05 00:10:55 +0200562
563 dst3 = inetaddr_host_lim_ret(line, end, &line);
564 if (line == end)
565 goto missing;
566 if (*line++ != ' ')
Willy Tarreau8e3bf692012-12-03 15:41:18 +0100567 goto bad_header;
Willy Tarreaue1e4a612012-10-05 00:10:55 +0200568
569 sport = read_uint((const char **)&line, end);
570 if (line == end)
571 goto missing;
572 if (*line++ != ' ')
Willy Tarreau8e3bf692012-12-03 15:41:18 +0100573 goto bad_header;
Willy Tarreaue1e4a612012-10-05 00:10:55 +0200574
575 dport = read_uint((const char **)&line, end);
576 if (line > end - 2)
577 goto missing;
578 if (*line++ != '\r')
Willy Tarreau8e3bf692012-12-03 15:41:18 +0100579 goto bad_header;
Willy Tarreaue1e4a612012-10-05 00:10:55 +0200580 if (*line++ != '\n')
Willy Tarreau8e3bf692012-12-03 15:41:18 +0100581 goto bad_header;
Willy Tarreaue1e4a612012-10-05 00:10:55 +0200582
583 /* update the session's addresses and mark them set */
Willy Tarreau226572f2019-07-17 14:46:00 +0200584 ((struct sockaddr_in *)conn->src)->sin_family = AF_INET;
585 ((struct sockaddr_in *)conn->src)->sin_addr.s_addr = htonl(src3);
586 ((struct sockaddr_in *)conn->src)->sin_port = htons(sport);
Willy Tarreaue1e4a612012-10-05 00:10:55 +0200587
Willy Tarreau226572f2019-07-17 14:46:00 +0200588 ((struct sockaddr_in *)conn->dst)->sin_family = AF_INET;
589 ((struct sockaddr_in *)conn->dst)->sin_addr.s_addr = htonl(dst3);
590 ((struct sockaddr_in *)conn->dst)->sin_port = htons(dport);
Willy Tarreaue1e4a612012-10-05 00:10:55 +0200591 conn->flags |= CO_FL_ADDR_FROM_SET | CO_FL_ADDR_TO_SET;
592 }
David CARLIER42ff05e2016-03-24 09:22:36 +0000593 else if (memcmp(line, "TCP6 ", 5) == 0) {
Willy Tarreaue1e4a612012-10-05 00:10:55 +0200594 u32 sport, dport;
595 char *src_s;
596 char *dst_s, *sport_s, *dport_s;
597 struct in6_addr src3, dst3;
598
599 line += 5;
600
601 src_s = line;
602 dst_s = sport_s = dport_s = NULL;
603 while (1) {
604 if (line > end - 2) {
605 goto missing;
606 }
607 else if (*line == '\r') {
608 *line = 0;
609 line++;
610 if (*line++ != '\n')
Willy Tarreau8e3bf692012-12-03 15:41:18 +0100611 goto bad_header;
Willy Tarreaue1e4a612012-10-05 00:10:55 +0200612 break;
613 }
614
615 if (*line == ' ') {
616 *line = 0;
617 if (!dst_s)
618 dst_s = line + 1;
619 else if (!sport_s)
620 sport_s = line + 1;
621 else if (!dport_s)
622 dport_s = line + 1;
623 }
624 line++;
625 }
626
627 if (!dst_s || !sport_s || !dport_s)
Willy Tarreau8e3bf692012-12-03 15:41:18 +0100628 goto bad_header;
Willy Tarreaue1e4a612012-10-05 00:10:55 +0200629
630 sport = read_uint((const char **)&sport_s,dport_s - 1);
631 if (*sport_s != 0)
Willy Tarreau8e3bf692012-12-03 15:41:18 +0100632 goto bad_header;
Willy Tarreaue1e4a612012-10-05 00:10:55 +0200633
634 dport = read_uint((const char **)&dport_s,line - 2);
635 if (*dport_s != 0)
Willy Tarreau8e3bf692012-12-03 15:41:18 +0100636 goto bad_header;
Willy Tarreaue1e4a612012-10-05 00:10:55 +0200637
638 if (inet_pton(AF_INET6, src_s, (void *)&src3) != 1)
Willy Tarreau8e3bf692012-12-03 15:41:18 +0100639 goto bad_header;
Willy Tarreaue1e4a612012-10-05 00:10:55 +0200640
641 if (inet_pton(AF_INET6, dst_s, (void *)&dst3) != 1)
Willy Tarreau8e3bf692012-12-03 15:41:18 +0100642 goto bad_header;
Willy Tarreaue1e4a612012-10-05 00:10:55 +0200643
644 /* update the session's addresses and mark them set */
Willy Tarreau226572f2019-07-17 14:46:00 +0200645 ((struct sockaddr_in6 *)conn->src)->sin6_family = AF_INET6;
646 memcpy(&((struct sockaddr_in6 *)conn->src)->sin6_addr, &src3, sizeof(struct in6_addr));
647 ((struct sockaddr_in6 *)conn->src)->sin6_port = htons(sport);
Willy Tarreaue1e4a612012-10-05 00:10:55 +0200648
Willy Tarreau226572f2019-07-17 14:46:00 +0200649 ((struct sockaddr_in6 *)conn->dst)->sin6_family = AF_INET6;
650 memcpy(&((struct sockaddr_in6 *)conn->dst)->sin6_addr, &dst3, sizeof(struct in6_addr));
651 ((struct sockaddr_in6 *)conn->dst)->sin6_port = htons(dport);
Willy Tarreaue1e4a612012-10-05 00:10:55 +0200652 conn->flags |= CO_FL_ADDR_FROM_SET | CO_FL_ADDR_TO_SET;
653 }
Willy Tarreau4c20d292014-06-14 11:41:36 +0200654 else if (memcmp(line, "UNKNOWN\r\n", 9) == 0) {
655 /* This can be a UNIX socket forwarded by an haproxy upstream */
656 line += 9;
657 }
Willy Tarreaue1e4a612012-10-05 00:10:55 +0200658 else {
Willy Tarreau4c20d292014-06-14 11:41:36 +0200659 /* The protocol does not match something known (TCP4/TCP6/UNKNOWN) */
Willy Tarreau8e3bf692012-12-03 15:41:18 +0100660 conn->err_code = CO_ER_PRX_BAD_PROTO;
Willy Tarreaue1e4a612012-10-05 00:10:55 +0200661 goto fail;
662 }
663
Willy Tarreau843b7cb2018-07-13 10:54:26 +0200664 trash.data = line - trash.area;
Willy Tarreau77992672014-06-14 11:06:17 +0200665 goto eat_header;
666
667 not_v1:
668 /* try PPv2 */
Willy Tarreau843b7cb2018-07-13 10:54:26 +0200669 if (trash.data < PP2_HEADER_LEN)
Willy Tarreau77992672014-06-14 11:06:17 +0200670 goto missing;
671
Willy Tarreau843b7cb2018-07-13 10:54:26 +0200672 hdr_v2 = (struct proxy_hdr_v2 *) trash.area;
Willy Tarreau77992672014-06-14 11:06:17 +0200673
674 if (memcmp(hdr_v2->sig, v2sig, PP2_SIGNATURE_LEN) != 0 ||
675 (hdr_v2->ver_cmd & PP2_VERSION_MASK) != PP2_VERSION) {
676 conn->err_code = CO_ER_PRX_NOT_HDR;
677 goto fail;
678 }
679
Tim Duesterhus488ee7f2020-03-05 22:55:20 +0100680 total_v2_len = PP2_HEADER_LEN + ntohs(hdr_v2->len);
681 if (trash.data < total_v2_len)
Willy Tarreau77992672014-06-14 11:06:17 +0200682 goto missing;
683
684 switch (hdr_v2->ver_cmd & PP2_CMD_MASK) {
685 case 0x01: /* PROXY command */
686 switch (hdr_v2->fam) {
687 case 0x11: /* TCPv4 */
KOVACS Krisztianefd3aa92014-11-19 10:53:20 +0100688 if (ntohs(hdr_v2->len) < PP2_ADDR_LEN_INET)
689 goto bad_header;
690
Willy Tarreau226572f2019-07-17 14:46:00 +0200691 ((struct sockaddr_in *)conn->src)->sin_family = AF_INET;
692 ((struct sockaddr_in *)conn->src)->sin_addr.s_addr = hdr_v2->addr.ip4.src_addr;
693 ((struct sockaddr_in *)conn->src)->sin_port = hdr_v2->addr.ip4.src_port;
694 ((struct sockaddr_in *)conn->dst)->sin_family = AF_INET;
695 ((struct sockaddr_in *)conn->dst)->sin_addr.s_addr = hdr_v2->addr.ip4.dst_addr;
696 ((struct sockaddr_in *)conn->dst)->sin_port = hdr_v2->addr.ip4.dst_port;
Willy Tarreau77992672014-06-14 11:06:17 +0200697 conn->flags |= CO_FL_ADDR_FROM_SET | CO_FL_ADDR_TO_SET;
KOVACS Krisztian7209c202015-07-03 14:09:10 +0200698 tlv_offset = PP2_HEADER_LEN + PP2_ADDR_LEN_INET;
Willy Tarreau77992672014-06-14 11:06:17 +0200699 break;
700 case 0x21: /* TCPv6 */
KOVACS Krisztianefd3aa92014-11-19 10:53:20 +0100701 if (ntohs(hdr_v2->len) < PP2_ADDR_LEN_INET6)
702 goto bad_header;
703
Willy Tarreau226572f2019-07-17 14:46:00 +0200704 ((struct sockaddr_in6 *)conn->src)->sin6_family = AF_INET6;
705 memcpy(&((struct sockaddr_in6 *)conn->src)->sin6_addr, hdr_v2->addr.ip6.src_addr, 16);
706 ((struct sockaddr_in6 *)conn->src)->sin6_port = hdr_v2->addr.ip6.src_port;
707 ((struct sockaddr_in6 *)conn->dst)->sin6_family = AF_INET6;
708 memcpy(&((struct sockaddr_in6 *)conn->dst)->sin6_addr, hdr_v2->addr.ip6.dst_addr, 16);
709 ((struct sockaddr_in6 *)conn->dst)->sin6_port = hdr_v2->addr.ip6.dst_port;
Willy Tarreau77992672014-06-14 11:06:17 +0200710 conn->flags |= CO_FL_ADDR_FROM_SET | CO_FL_ADDR_TO_SET;
KOVACS Krisztian7209c202015-07-03 14:09:10 +0200711 tlv_offset = PP2_HEADER_LEN + PP2_ADDR_LEN_INET6;
Willy Tarreau77992672014-06-14 11:06:17 +0200712 break;
713 }
KOVACS Krisztianb3e54fe2014-11-17 15:11:45 +0100714
715 /* TLV parsing */
Tim Duesterhus488ee7f2020-03-05 22:55:20 +0100716 while (tlv_offset < total_v2_len) {
717 struct tlv *tlv_packet;
Tim Duesterhusba837ec2020-03-05 23:11:02 +0100718 size_t tlv_len;
KOVACS Krisztianb3e54fe2014-11-17 15:11:45 +0100719
Tim Duesterhus488ee7f2020-03-05 22:55:20 +0100720 /* Verify that we have at least TLV_HEADER_SIZE bytes left */
721 if (tlv_offset + TLV_HEADER_SIZE > total_v2_len)
722 goto bad_header;
723
724 tlv_packet = (struct tlv *) &trash.area[tlv_offset];
725 tlv_len = get_tlv_length(tlv_packet);
726 tlv_offset += tlv_len + TLV_HEADER_SIZE;
727
728 /* Verify that the TLV length does not exceed the total PROXYv2 length */
729 if (tlv_offset > total_v2_len)
730 goto bad_header;
731
732 switch (tlv_packet->type) {
733 case PP2_TYPE_CRC32C: {
734 uint32_t n_crc32c;
735
736 /* Verify that this TLV is exactly 4 bytes long */
737 if (tlv_len != 4)
738 goto bad_header;
739
740 n_crc32c = read_n32(tlv_packet->value);
741 write_n32(tlv_packet->value, 0); // compute with CRC==0
742
743 if (hash_crc32c(trash.area, total_v2_len) != n_crc32c)
744 goto bad_header;
745 break;
746 }
Willy Tarreaue5733232019-05-22 19:24:06 +0200747#ifdef USE_NS
Tim Duesterhus488ee7f2020-03-05 22:55:20 +0100748 case PP2_TYPE_NETNS: {
749 const struct netns_entry *ns;
750
751 ns = netns_store_lookup((char*)tlv_packet->value, tlv_len);
752 if (ns)
753 conn->proxy_netns = ns;
754 break;
755 }
KOVACS Krisztianb3e54fe2014-11-17 15:11:45 +0100756#endif
Tim Duesterhus488ee7f2020-03-05 22:55:20 +0100757 case PP2_TYPE_AUTHORITY: {
758 if (tlv_len > PP2_AUTHORITY_MAX)
759 goto bad_header;
760 conn->proxy_authority = pool_alloc(pool_head_authority);
761 if (conn->proxy_authority == NULL)
762 goto fail;
763 memcpy(conn->proxy_authority, (const char *)tlv_packet->value, tlv_len);
764 conn->proxy_authority_len = tlv_len;
765 break;
766 }
Tim Duesterhusd1b15b62020-03-13 12:34:23 +0100767 case PP2_TYPE_UNIQUE_ID: {
768 const struct ist tlv = ist2((const char *)tlv_packet->value, tlv_len);
769
770 if (tlv.len > UNIQUEID_LEN)
771 goto bad_header;
Tim Duesterhus2b7f6c22020-03-14 13:07:05 +0100772 conn->proxy_unique_id = ist2(pool_alloc(pool_head_uniqueid), 0);
Tim Duesterhusd1b15b62020-03-13 12:34:23 +0100773 if (!isttest(conn->proxy_unique_id))
774 goto fail;
775 if (istcpy(&conn->proxy_unique_id, tlv, UNIQUEID_LEN) < 0) {
776 /* This is technically unreachable, because we verified above
777 * that the TLV value fits.
778 */
779 goto fail;
780 }
781 break;
782 }
Tim Duesterhus488ee7f2020-03-05 22:55:20 +0100783 default:
784 break;
KOVACS Krisztianb3e54fe2014-11-17 15:11:45 +0100785 }
786 }
787
Tim Duesterhus488ee7f2020-03-05 22:55:20 +0100788 /* Verify that the PROXYv2 header ends at a TLV boundary.
789 * This is technically unreachable, because the TLV parsing already
790 * verifies that a TLV does not exceed the total length and also
791 * that there is space for a TLV header.
792 */
793 if (tlv_offset != total_v2_len)
794 goto bad_header;
795
Willy Tarreau77992672014-06-14 11:06:17 +0200796 /* unsupported protocol, keep local connection address */
797 break;
798 case 0x00: /* LOCAL command */
799 /* keep local connection address for LOCAL */
800 break;
801 default:
802 goto bad_header; /* not a supported command */
803 }
804
Tim Duesterhus488ee7f2020-03-05 22:55:20 +0100805 trash.data = total_v2_len;
Willy Tarreau77992672014-06-14 11:06:17 +0200806 goto eat_header;
807
808 eat_header:
Willy Tarreaue1e4a612012-10-05 00:10:55 +0200809 /* remove the PROXY line from the request. For this we re-read the
810 * exact line at once. If we don't get the exact same result, we
811 * fail.
812 */
Willy Tarreau157788c2020-02-11 10:08:05 +0100813 while (1) {
Tim Duesterhusa8692f32020-03-13 12:34:25 +0100814 ssize_t len2 = recv(conn->handle.fd, trash.area, trash.data, 0);
815
Willy Tarreaue1e4a612012-10-05 00:10:55 +0200816 if (len2 < 0 && errno == EINTR)
817 continue;
Willy Tarreau843b7cb2018-07-13 10:54:26 +0200818 if (len2 != trash.data)
Willy Tarreau8e3bf692012-12-03 15:41:18 +0100819 goto recv_abort;
Willy Tarreau157788c2020-02-11 10:08:05 +0100820 break;
821 }
Willy Tarreaue1e4a612012-10-05 00:10:55 +0200822
823 conn->flags &= ~flag;
Emeric Brun4f603012017-01-05 15:11:44 +0100824 conn->flags |= CO_FL_RCVD_PROXY;
Willy Tarreaue1e4a612012-10-05 00:10:55 +0200825 return 1;
826
Willy Tarreau6499b9d2019-06-03 08:17:30 +0200827 not_ready:
Willy Tarreau6499b9d2019-06-03 08:17:30 +0200828 return 0;
829
Willy Tarreaue1e4a612012-10-05 00:10:55 +0200830 missing:
831 /* Missing data. Since we're using MSG_PEEK, we can only poll again if
832 * we have not read anything. Otherwise we need to fail because we won't
833 * be able to poll anymore.
834 */
Willy Tarreau8e3bf692012-12-03 15:41:18 +0100835 conn->err_code = CO_ER_PRX_TRUNCATED;
836 goto fail;
837
838 bad_header:
839 /* This is not a valid proxy protocol header */
840 conn->err_code = CO_ER_PRX_BAD_HDR;
841 goto fail;
842
843 recv_abort:
844 conn->err_code = CO_ER_PRX_ABORT;
Willy Tarreau26f4a042013-12-04 23:44:10 +0100845 conn->flags |= CO_FL_SOCK_RD_SH | CO_FL_SOCK_WR_SH;
Willy Tarreau8e3bf692012-12-03 15:41:18 +0100846 goto fail;
847
Willy Tarreaue1e4a612012-10-05 00:10:55 +0200848 fail:
Willy Tarreaue1e4a612012-10-05 00:10:55 +0200849 conn->flags |= CO_FL_ERROR;
Willy Tarreaue1e4a612012-10-05 00:10:55 +0200850 return 0;
851}
852
Bertrand Jacquin93b227d2016-06-04 15:11:10 +0100853/* This handshake handler waits a NetScaler Client IP insertion header
Bertrand Jacquin72fa1ec2017-12-12 01:17:23 +0000854 * at the beginning of the raw data stream. The header format is
855 * described in doc/netscaler-client-ip-insertion-protocol.txt
Bertrand Jacquin93b227d2016-06-04 15:11:10 +0100856 *
857 * This line MUST be at the beginning of the buffer and MUST NOT be
858 * fragmented.
859 *
860 * The header line is small and in all cases smaller than the smallest normal
861 * TCP MSS. So it MUST always be delivered as one segment, which ensures we
862 * can safely use MSG_PEEK and avoid buffering.
863 *
864 * Once the data is fetched, the values are set in the connection's address
865 * fields, and data are removed from the socket's buffer. The function returns
866 * zero if it needs to wait for more data or if it fails, or 1 if it completed
867 * and removed itself.
868 */
869int conn_recv_netscaler_cip(struct connection *conn, int flag)
870{
871 char *line;
Bertrand Jacquin7d668f92017-12-13 01:23:39 +0000872 uint32_t hdr_len;
Willy Tarreau0ca24aa2019-03-29 17:35:32 +0100873 uint8_t ip_ver;
Willy Tarreaub406b872018-08-22 05:20:32 +0200874 int ret;
Bertrand Jacquin93b227d2016-06-04 15:11:10 +0100875
Bertrand Jacquin93b227d2016-06-04 15:11:10 +0100876 if (!conn_ctrl_ready(conn))
877 goto fail;
878
Olivier Houchard1a9dbe52020-01-22 15:31:09 +0100879 if (!sockaddr_alloc(&conn->src) || !sockaddr_alloc(&conn->dst))
880 goto fail;
881
Willy Tarreau585744b2017-08-24 14:31:19 +0200882 if (!fd_recv_ready(conn->handle.fd))
Willy Tarreau6499b9d2019-06-03 08:17:30 +0200883 goto not_ready;
Bertrand Jacquin93b227d2016-06-04 15:11:10 +0100884
Willy Tarreau157788c2020-02-11 10:08:05 +0100885 while (1) {
Willy Tarreaub406b872018-08-22 05:20:32 +0200886 ret = recv(conn->handle.fd, trash.area, trash.size, MSG_PEEK);
887 if (ret < 0) {
Bertrand Jacquin93b227d2016-06-04 15:11:10 +0100888 if (errno == EINTR)
889 continue;
890 if (errno == EAGAIN) {
Willy Tarreau585744b2017-08-24 14:31:19 +0200891 fd_cant_recv(conn->handle.fd);
Willy Tarreau6499b9d2019-06-03 08:17:30 +0200892 goto not_ready;
Bertrand Jacquin93b227d2016-06-04 15:11:10 +0100893 }
894 goto recv_abort;
895 }
Willy Tarreaub406b872018-08-22 05:20:32 +0200896 trash.data = ret;
Willy Tarreau157788c2020-02-11 10:08:05 +0100897 break;
898 }
Bertrand Jacquin93b227d2016-06-04 15:11:10 +0100899
Willy Tarreauc192b0a2020-01-23 09:11:58 +0100900 conn->flags &= ~CO_FL_WAIT_L4_CONN;
901
Willy Tarreau843b7cb2018-07-13 10:54:26 +0200902 if (!trash.data) {
Bertrand Jacquin93b227d2016-06-04 15:11:10 +0100903 /* client shutdown */
904 conn->err_code = CO_ER_CIP_EMPTY;
905 goto fail;
906 }
907
908 /* Fail if buffer length is not large enough to contain
Bertrand Jacquin72fa1ec2017-12-12 01:17:23 +0000909 * CIP magic, header length or
910 * CIP magic, CIP length, CIP type, header length */
Willy Tarreau843b7cb2018-07-13 10:54:26 +0200911 if (trash.data < 12)
Bertrand Jacquin93b227d2016-06-04 15:11:10 +0100912 goto missing;
913
Willy Tarreau843b7cb2018-07-13 10:54:26 +0200914 line = trash.area;
Bertrand Jacquin93b227d2016-06-04 15:11:10 +0100915
916 /* Decode a possible NetScaler Client IP request, fail early if
917 * it does not match */
Willy Tarreau1ac83af2020-02-25 10:06:49 +0100918 if (ntohl(read_u32(line)) != __objt_listener(conn->target)->bind_conf->ns_cip_magic)
Bertrand Jacquin93b227d2016-06-04 15:11:10 +0100919 goto bad_magic;
920
Bertrand Jacquin72fa1ec2017-12-12 01:17:23 +0000921 /* Legacy CIP protocol */
Willy Tarreau843b7cb2018-07-13 10:54:26 +0200922 if ((trash.area[8] & 0xD0) == 0x40) {
Willy Tarreau1ac83af2020-02-25 10:06:49 +0100923 hdr_len = ntohl(read_u32((line+4)));
Bertrand Jacquin72fa1ec2017-12-12 01:17:23 +0000924 line += 8;
925 }
926 /* Standard CIP protocol */
Willy Tarreau843b7cb2018-07-13 10:54:26 +0200927 else if (trash.area[8] == 0x00) {
Willy Tarreau1ac83af2020-02-25 10:06:49 +0100928 hdr_len = ntohs(read_u32((line+10)));
Bertrand Jacquin72fa1ec2017-12-12 01:17:23 +0000929 line += 12;
930 }
931 /* Unknown CIP protocol */
932 else {
933 conn->err_code = CO_ER_CIP_BAD_PROTO;
934 goto fail;
935 }
936
Bertrand Jacquin93b227d2016-06-04 15:11:10 +0100937 /* Fail if buffer length is not large enough to contain
Bertrand Jacquin72fa1ec2017-12-12 01:17:23 +0000938 * a minimal IP header */
Willy Tarreau843b7cb2018-07-13 10:54:26 +0200939 if (trash.data < 20)
Bertrand Jacquin93b227d2016-06-04 15:11:10 +0100940 goto missing;
941
Bertrand Jacquin93b227d2016-06-04 15:11:10 +0100942 /* Get IP version from the first four bits */
Willy Tarreau0ca24aa2019-03-29 17:35:32 +0100943 ip_ver = (*line & 0xf0) >> 4;
Bertrand Jacquin93b227d2016-06-04 15:11:10 +0100944
Willy Tarreau0ca24aa2019-03-29 17:35:32 +0100945 if (ip_ver == 4) {
Bertrand Jacquin93b227d2016-06-04 15:11:10 +0100946 struct ip *hdr_ip4;
David Carlier3015a2e2016-07-04 22:51:33 +0100947 struct my_tcphdr *hdr_tcp;
Bertrand Jacquin93b227d2016-06-04 15:11:10 +0100948
949 hdr_ip4 = (struct ip *)line;
950
Willy Tarreau843b7cb2018-07-13 10:54:26 +0200951 if (trash.data < 40 || trash.data < hdr_len) {
Bertrand Jacquin93b227d2016-06-04 15:11:10 +0100952 /* Fail if buffer length is not large enough to contain
Bertrand Jacquin67de5a22017-12-13 01:15:05 +0000953 * IPv4 header, TCP header */
Bertrand Jacquin93b227d2016-06-04 15:11:10 +0100954 goto missing;
Bertrand Jacquinb3875912017-12-13 00:58:51 +0000955 }
956 else if (hdr_ip4->ip_p != IPPROTO_TCP) {
Bertrand Jacquin93b227d2016-06-04 15:11:10 +0100957 /* The protocol does not include a TCP header */
958 conn->err_code = CO_ER_CIP_BAD_PROTO;
959 goto fail;
Bertrand Jacquinb3875912017-12-13 00:58:51 +0000960 }
Bertrand Jacquin93b227d2016-06-04 15:11:10 +0100961
David Carlier3015a2e2016-07-04 22:51:33 +0100962 hdr_tcp = (struct my_tcphdr *)(line + (hdr_ip4->ip_hl * 4));
Bertrand Jacquin93b227d2016-06-04 15:11:10 +0100963
964 /* update the session's addresses and mark them set */
Willy Tarreau226572f2019-07-17 14:46:00 +0200965 ((struct sockaddr_in *)conn->src)->sin_family = AF_INET;
966 ((struct sockaddr_in *)conn->src)->sin_addr.s_addr = hdr_ip4->ip_src.s_addr;
967 ((struct sockaddr_in *)conn->src)->sin_port = hdr_tcp->source;
Bertrand Jacquin93b227d2016-06-04 15:11:10 +0100968
Willy Tarreau226572f2019-07-17 14:46:00 +0200969 ((struct sockaddr_in *)conn->dst)->sin_family = AF_INET;
970 ((struct sockaddr_in *)conn->dst)->sin_addr.s_addr = hdr_ip4->ip_dst.s_addr;
971 ((struct sockaddr_in *)conn->dst)->sin_port = hdr_tcp->dest;
Bertrand Jacquin93b227d2016-06-04 15:11:10 +0100972
973 conn->flags |= CO_FL_ADDR_FROM_SET | CO_FL_ADDR_TO_SET;
974 }
Willy Tarreau0ca24aa2019-03-29 17:35:32 +0100975 else if (ip_ver == 6) {
Bertrand Jacquin93b227d2016-06-04 15:11:10 +0100976 struct ip6_hdr *hdr_ip6;
David Carlier3015a2e2016-07-04 22:51:33 +0100977 struct my_tcphdr *hdr_tcp;
Bertrand Jacquin93b227d2016-06-04 15:11:10 +0100978
979 hdr_ip6 = (struct ip6_hdr *)line;
980
Willy Tarreau843b7cb2018-07-13 10:54:26 +0200981 if (trash.data < 60 || trash.data < hdr_len) {
Bertrand Jacquin93b227d2016-06-04 15:11:10 +0100982 /* Fail if buffer length is not large enough to contain
Bertrand Jacquin67de5a22017-12-13 01:15:05 +0000983 * IPv6 header, TCP header */
Bertrand Jacquin93b227d2016-06-04 15:11:10 +0100984 goto missing;
Bertrand Jacquinb3875912017-12-13 00:58:51 +0000985 }
986 else if (hdr_ip6->ip6_nxt != IPPROTO_TCP) {
Bertrand Jacquin93b227d2016-06-04 15:11:10 +0100987 /* The protocol does not include a TCP header */
988 conn->err_code = CO_ER_CIP_BAD_PROTO;
989 goto fail;
Bertrand Jacquinb3875912017-12-13 00:58:51 +0000990 }
Bertrand Jacquin93b227d2016-06-04 15:11:10 +0100991
David Carlier3015a2e2016-07-04 22:51:33 +0100992 hdr_tcp = (struct my_tcphdr *)(line + sizeof(struct ip6_hdr));
Bertrand Jacquin93b227d2016-06-04 15:11:10 +0100993
994 /* update the session's addresses and mark them set */
Willy Tarreau226572f2019-07-17 14:46:00 +0200995 ((struct sockaddr_in6 *)conn->src)->sin6_family = AF_INET6;
996 ((struct sockaddr_in6 *)conn->src)->sin6_addr = hdr_ip6->ip6_src;
997 ((struct sockaddr_in6 *)conn->src)->sin6_port = hdr_tcp->source;
Bertrand Jacquin93b227d2016-06-04 15:11:10 +0100998
Willy Tarreau226572f2019-07-17 14:46:00 +0200999 ((struct sockaddr_in6 *)conn->dst)->sin6_family = AF_INET6;
1000 ((struct sockaddr_in6 *)conn->dst)->sin6_addr = hdr_ip6->ip6_dst;
1001 ((struct sockaddr_in6 *)conn->dst)->sin6_port = hdr_tcp->dest;
Bertrand Jacquin93b227d2016-06-04 15:11:10 +01001002
1003 conn->flags |= CO_FL_ADDR_FROM_SET | CO_FL_ADDR_TO_SET;
1004 }
1005 else {
1006 /* The protocol does not match something known (IPv4/IPv6) */
1007 conn->err_code = CO_ER_CIP_BAD_PROTO;
1008 goto fail;
1009 }
1010
Bertrand Jacquin7d668f92017-12-13 01:23:39 +00001011 line += hdr_len;
Willy Tarreau843b7cb2018-07-13 10:54:26 +02001012 trash.data = line - trash.area;
Bertrand Jacquin93b227d2016-06-04 15:11:10 +01001013
1014 /* remove the NetScaler Client IP header from the request. For this
1015 * we re-read the exact line at once. If we don't get the exact same
1016 * result, we fail.
1017 */
Willy Tarreau157788c2020-02-11 10:08:05 +01001018 while (1) {
Willy Tarreau843b7cb2018-07-13 10:54:26 +02001019 int len2 = recv(conn->handle.fd, trash.area, trash.data, 0);
Bertrand Jacquin93b227d2016-06-04 15:11:10 +01001020 if (len2 < 0 && errno == EINTR)
1021 continue;
Willy Tarreau843b7cb2018-07-13 10:54:26 +02001022 if (len2 != trash.data)
Bertrand Jacquin93b227d2016-06-04 15:11:10 +01001023 goto recv_abort;
Willy Tarreau157788c2020-02-11 10:08:05 +01001024 break;
1025 }
Bertrand Jacquin93b227d2016-06-04 15:11:10 +01001026
1027 conn->flags &= ~flag;
1028 return 1;
1029
Willy Tarreau6499b9d2019-06-03 08:17:30 +02001030 not_ready:
Willy Tarreau6499b9d2019-06-03 08:17:30 +02001031 return 0;
1032
Bertrand Jacquin93b227d2016-06-04 15:11:10 +01001033 missing:
1034 /* Missing data. Since we're using MSG_PEEK, we can only poll again if
1035 * we have not read anything. Otherwise we need to fail because we won't
1036 * be able to poll anymore.
1037 */
1038 conn->err_code = CO_ER_CIP_TRUNCATED;
1039 goto fail;
1040
1041 bad_magic:
1042 conn->err_code = CO_ER_CIP_BAD_MAGIC;
1043 goto fail;
1044
1045 recv_abort:
1046 conn->err_code = CO_ER_CIP_ABORT;
1047 conn->flags |= CO_FL_SOCK_RD_SH | CO_FL_SOCK_WR_SH;
1048 goto fail;
1049
1050 fail:
Bertrand Jacquin93b227d2016-06-04 15:11:10 +01001051 conn->flags |= CO_FL_ERROR;
1052 return 0;
1053}
1054
Alexander Liu2a54bb72019-05-22 19:44:48 +08001055
1056int conn_send_socks4_proxy_request(struct connection *conn)
1057{
1058 struct socks4_request req_line;
1059
Alexander Liu2a54bb72019-05-22 19:44:48 +08001060 if (!conn_ctrl_ready(conn))
1061 goto out_error;
1062
Willy Tarreau226572f2019-07-17 14:46:00 +02001063 if (!conn_get_dst(conn))
1064 goto out_error;
1065
Alexander Liu2a54bb72019-05-22 19:44:48 +08001066 req_line.version = 0x04;
1067 req_line.command = 0x01;
Willy Tarreau226572f2019-07-17 14:46:00 +02001068 req_line.port = get_net_port(conn->dst);
1069 req_line.ip = is_inet_addr(conn->dst);
Alexander Liu2a54bb72019-05-22 19:44:48 +08001070 memcpy(req_line.user_id, "HAProxy\0", 8);
1071
1072 if (conn->send_proxy_ofs > 0) {
1073 /*
1074 * This is the first call to send the request
1075 */
1076 conn->send_proxy_ofs = -(int)sizeof(req_line);
1077 }
1078
1079 if (conn->send_proxy_ofs < 0) {
1080 int ret = 0;
1081
1082 /* we are sending the socks4_req_line here. If the data layer
1083 * has a pending write, we'll also set MSG_MORE.
1084 */
1085 ret = conn_sock_send(
1086 conn,
1087 ((char *)(&req_line)) + (sizeof(req_line)+conn->send_proxy_ofs),
1088 -conn->send_proxy_ofs,
Willy Tarreau19bc2012020-02-21 08:46:19 +01001089 (conn->subs && conn->subs->events & SUB_RETRY_SEND) ? MSG_MORE : 0);
Alexander Liu2a54bb72019-05-22 19:44:48 +08001090
1091 DPRINTF(stderr, "SOCKS PROXY HS FD[%04X]: Before send remain is [%d], sent [%d]\n",
1092 conn->handle.fd, -conn->send_proxy_ofs, ret);
1093
1094 if (ret < 0) {
1095 goto out_error;
1096 }
1097
1098 conn->send_proxy_ofs += ret; /* becomes zero once complete */
1099 if (conn->send_proxy_ofs != 0) {
1100 goto out_wait;
1101 }
1102 }
1103
1104 /* OK we've the whole request sent */
1105 conn->flags &= ~CO_FL_SOCKS4_SEND;
Alexander Liu2a54bb72019-05-22 19:44:48 +08001106
1107 /* The connection is ready now, simply return and let the connection
1108 * handler notify upper layers if needed.
1109 */
Willy Tarreauc192b0a2020-01-23 09:11:58 +01001110 conn->flags &= ~CO_FL_WAIT_L4_CONN;
Alexander Liu2a54bb72019-05-22 19:44:48 +08001111
1112 if (conn->flags & CO_FL_SEND_PROXY) {
1113 /*
1114 * Get the send_proxy_ofs ready for the send_proxy due to we are
1115 * reusing the "send_proxy_ofs", and SOCKS4 handshake should be done
1116 * before sending PROXY Protocol.
1117 */
1118 conn->send_proxy_ofs = 1;
1119 }
1120 return 1;
1121
1122 out_error:
1123 /* Write error on the file descriptor */
1124 conn->flags |= CO_FL_ERROR;
1125 if (conn->err_code == CO_ER_NONE) {
1126 conn->err_code = CO_ER_SOCKS4_SEND;
1127 }
1128 return 0;
1129
1130 out_wait:
Alexander Liu2a54bb72019-05-22 19:44:48 +08001131 return 0;
1132}
1133
1134int conn_recv_socks4_proxy_response(struct connection *conn)
1135{
1136 char line[SOCKS4_HS_RSP_LEN];
1137 int ret;
1138
Alexander Liu2a54bb72019-05-22 19:44:48 +08001139 if (!conn_ctrl_ready(conn))
1140 goto fail;
1141
1142 if (!fd_recv_ready(conn->handle.fd))
Willy Tarreau6499b9d2019-06-03 08:17:30 +02001143 goto not_ready;
Alexander Liu2a54bb72019-05-22 19:44:48 +08001144
Willy Tarreau157788c2020-02-11 10:08:05 +01001145 while (1) {
Alexander Liu2a54bb72019-05-22 19:44:48 +08001146 /* SOCKS4 Proxy will response with 8 bytes, 0x00 | 0x5A | 0x00 0x00 | 0x00 0x00 0x00 0x00
1147 * Try to peek into it, before all 8 bytes ready.
1148 */
1149 ret = recv(conn->handle.fd, line, SOCKS4_HS_RSP_LEN, MSG_PEEK);
1150
1151 if (ret == 0) {
1152 /* the socket has been closed or shutdown for send */
1153 DPRINTF(stderr, "SOCKS PROXY HS FD[%04X]: Received ret[%d], errno[%d], looks like the socket has been closed or shutdown for send\n",
1154 conn->handle.fd, ret, errno);
1155 if (conn->err_code == CO_ER_NONE) {
1156 conn->err_code = CO_ER_SOCKS4_RECV;
1157 }
1158 goto fail;
1159 }
1160
1161 if (ret > 0) {
1162 if (ret == SOCKS4_HS_RSP_LEN) {
1163 DPRINTF(stderr, "SOCKS PROXY HS FD[%04X]: Received 8 bytes, the response is [%02X|%02X|%02X %02X|%02X %02X %02X %02X]\n",
1164 conn->handle.fd, line[0], line[1], line[2], line[3], line[4], line[5], line[6], line[7]);
1165 }else{
1166 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]);
1167 }
1168 } else {
1169 DPRINTF(stderr, "SOCKS PROXY HS FD[%04X]: Received ret[%d], errno[%d]\n", conn->handle.fd, ret, errno);
1170 }
1171
1172 if (ret < 0) {
1173 if (errno == EINTR) {
1174 continue;
1175 }
1176 if (errno == EAGAIN) {
1177 fd_cant_recv(conn->handle.fd);
Willy Tarreau6499b9d2019-06-03 08:17:30 +02001178 goto not_ready;
Alexander Liu2a54bb72019-05-22 19:44:48 +08001179 }
1180 goto recv_abort;
1181 }
Willy Tarreau157788c2020-02-11 10:08:05 +01001182 break;
1183 }
Alexander Liu2a54bb72019-05-22 19:44:48 +08001184
Willy Tarreauc192b0a2020-01-23 09:11:58 +01001185 conn->flags &= ~CO_FL_WAIT_L4_CONN;
1186
Alexander Liu2a54bb72019-05-22 19:44:48 +08001187 if (ret < SOCKS4_HS_RSP_LEN) {
1188 /* Missing data. Since we're using MSG_PEEK, we can only poll again if
1189 * we are not able to read enough data.
1190 */
Willy Tarreau6499b9d2019-06-03 08:17:30 +02001191 goto not_ready;
Alexander Liu2a54bb72019-05-22 19:44:48 +08001192 }
1193
1194 /*
1195 * Base on the SOCSK4 protocol:
1196 *
1197 * +----+----+----+----+----+----+----+----+
1198 * | VN | CD | DSTPORT | DSTIP |
1199 * +----+----+----+----+----+----+----+----+
1200 * # of bytes: 1 1 2 4
1201 * VN is the version of the reply code and should be 0. CD is the result
1202 * code with one of the following values:
1203 * 90: request granted
1204 * 91: request rejected or failed
Ilya Shipitsince7b00f2020-03-23 22:28:40 +05001205 * 92: request rejected because SOCKS server cannot connect to identd on the client
Alexander Liu2a54bb72019-05-22 19:44:48 +08001206 * 93: request rejected because the client program and identd report different user-ids
1207 * The remaining fields are ignored.
1208 */
1209 if (line[1] != 90) {
1210 conn->flags &= ~CO_FL_SOCKS4_RECV;
1211
1212 DPRINTF(stderr, "SOCKS PROXY HS FD[%04X]: FAIL, the response is [%02X|%02X|%02X %02X|%02X %02X %02X %02X]\n",
1213 conn->handle.fd, line[0], line[1], line[2], line[3], line[4], line[5], line[6], line[7]);
1214 if (conn->err_code == CO_ER_NONE) {
1215 conn->err_code = CO_ER_SOCKS4_DENY;
1216 }
1217 goto fail;
1218 }
1219
1220 /* remove the 8 bytes response from the stream */
Willy Tarreau157788c2020-02-11 10:08:05 +01001221 while (1) {
Alexander Liu2a54bb72019-05-22 19:44:48 +08001222 ret = recv(conn->handle.fd, line, SOCKS4_HS_RSP_LEN, 0);
1223 if (ret < 0 && errno == EINTR) {
1224 continue;
1225 }
1226 if (ret != SOCKS4_HS_RSP_LEN) {
1227 if (conn->err_code == CO_ER_NONE) {
1228 conn->err_code = CO_ER_SOCKS4_RECV;
1229 }
1230 goto fail;
1231 }
Willy Tarreau157788c2020-02-11 10:08:05 +01001232 break;
1233 }
Alexander Liu2a54bb72019-05-22 19:44:48 +08001234
1235 conn->flags &= ~CO_FL_SOCKS4_RECV;
1236 return 1;
1237
Willy Tarreau6499b9d2019-06-03 08:17:30 +02001238 not_ready:
Willy Tarreau6499b9d2019-06-03 08:17:30 +02001239 return 0;
1240
Alexander Liu2a54bb72019-05-22 19:44:48 +08001241 recv_abort:
1242 if (conn->err_code == CO_ER_NONE) {
1243 conn->err_code = CO_ER_SOCKS4_ABORT;
1244 }
1245 conn->flags |= (CO_FL_SOCK_RD_SH | CO_FL_SOCK_WR_SH);
1246 goto fail;
1247
1248 fail:
Alexander Liu2a54bb72019-05-22 19:44:48 +08001249 conn->flags |= CO_FL_ERROR;
1250 return 0;
1251}
1252
Ilya Shipitsinca56fce2018-09-15 00:50:05 +05001253/* Note: <remote> is explicitly allowed to be NULL */
Tim Duesterhuscf6e0c82020-03-13 12:34:24 +01001254int make_proxy_line(char *buf, int buf_len, struct server *srv, struct connection *remote, struct stream *strm)
David Safb76832014-05-08 23:42:08 -04001255{
1256 int ret = 0;
1257
1258 if (srv && (srv->pp_opts & SRV_PP_V2)) {
Tim Duesterhuscf6e0c82020-03-13 12:34:24 +01001259 ret = make_proxy_line_v2(buf, buf_len, srv, remote, strm);
David Safb76832014-05-08 23:42:08 -04001260 }
1261 else {
Willy Tarreau226572f2019-07-17 14:46:00 +02001262 if (remote && conn_get_src(remote) && conn_get_dst(remote))
1263 ret = make_proxy_line_v1(buf, buf_len, remote->src, remote->dst);
David Safb76832014-05-08 23:42:08 -04001264 else
1265 ret = make_proxy_line_v1(buf, buf_len, NULL, NULL);
1266 }
1267
1268 return ret;
1269}
1270
Willy Tarreaue1e4a612012-10-05 00:10:55 +02001271/* Makes a PROXY protocol line from the two addresses. The output is sent to
1272 * buffer <buf> for a maximum size of <buf_len> (including the trailing zero).
1273 * It returns the number of bytes composing this line (including the trailing
1274 * LF), or zero in case of failure (eg: not enough space). It supports TCP4,
Willy Tarreau2e1401a2013-10-01 11:41:55 +02001275 * TCP6 and "UNKNOWN" formats. If any of <src> or <dst> is null, UNKNOWN is
1276 * emitted as well.
Willy Tarreaue1e4a612012-10-05 00:10:55 +02001277 */
David Safb76832014-05-08 23:42:08 -04001278int make_proxy_line_v1(char *buf, int buf_len, struct sockaddr_storage *src, struct sockaddr_storage *dst)
Willy Tarreaue1e4a612012-10-05 00:10:55 +02001279{
1280 int ret = 0;
Tim Duesterhus7fec0212018-07-27 18:46:13 +02001281 char * protocol;
1282 char src_str[MAX(INET_ADDRSTRLEN, INET6_ADDRSTRLEN)];
1283 char dst_str[MAX(INET_ADDRSTRLEN, INET6_ADDRSTRLEN)];
1284 in_port_t src_port;
1285 in_port_t dst_port;
Willy Tarreaue1e4a612012-10-05 00:10:55 +02001286
Tim Duesterhus7fec0212018-07-27 18:46:13 +02001287 if ( !src
1288 || !dst
1289 || (src->ss_family != AF_INET && src->ss_family != AF_INET6)
1290 || (dst->ss_family != AF_INET && dst->ss_family != AF_INET6)) {
1291 /* unknown family combination */
1292 ret = snprintf(buf, buf_len, "PROXY UNKNOWN\r\n");
Willy Tarreaue1e4a612012-10-05 00:10:55 +02001293 if (ret >= buf_len)
1294 return 0;
1295
Tim Duesterhus7fec0212018-07-27 18:46:13 +02001296 return ret;
1297 }
Willy Tarreaue1e4a612012-10-05 00:10:55 +02001298
Tim Duesterhus7fec0212018-07-27 18:46:13 +02001299 /* IPv4 for both src and dst */
1300 if (src->ss_family == AF_INET && dst->ss_family == AF_INET) {
1301 protocol = "TCP4";
1302 if (!inet_ntop(AF_INET, &((struct sockaddr_in *)src)->sin_addr, src_str, sizeof(src_str)))
Willy Tarreaue1e4a612012-10-05 00:10:55 +02001303 return 0;
Tim Duesterhus7fec0212018-07-27 18:46:13 +02001304 src_port = ((struct sockaddr_in *)src)->sin_port;
1305 if (!inet_ntop(AF_INET, &((struct sockaddr_in *)dst)->sin_addr, dst_str, sizeof(dst_str)))
Willy Tarreaue1e4a612012-10-05 00:10:55 +02001306 return 0;
Tim Duesterhus7fec0212018-07-27 18:46:13 +02001307 dst_port = ((struct sockaddr_in *)dst)->sin_port;
Willy Tarreaue1e4a612012-10-05 00:10:55 +02001308 }
Tim Duesterhus7fec0212018-07-27 18:46:13 +02001309 /* IPv6 for at least one of src and dst */
1310 else {
1311 struct in6_addr tmp;
Willy Tarreaue1e4a612012-10-05 00:10:55 +02001312
Tim Duesterhus7fec0212018-07-27 18:46:13 +02001313 protocol = "TCP6";
Willy Tarreaue1e4a612012-10-05 00:10:55 +02001314
Tim Duesterhus7fec0212018-07-27 18:46:13 +02001315 if (src->ss_family == AF_INET) {
1316 /* Convert src to IPv6 */
1317 v4tov6(&tmp, &((struct sockaddr_in *)src)->sin_addr);
1318 src_port = ((struct sockaddr_in *)src)->sin_port;
1319 }
1320 else {
1321 tmp = ((struct sockaddr_in6 *)src)->sin6_addr;
1322 src_port = ((struct sockaddr_in6 *)src)->sin6_port;
1323 }
Willy Tarreaue1e4a612012-10-05 00:10:55 +02001324
Tim Duesterhus7fec0212018-07-27 18:46:13 +02001325 if (!inet_ntop(AF_INET6, &tmp, src_str, sizeof(src_str)))
Willy Tarreaue1e4a612012-10-05 00:10:55 +02001326 return 0;
1327
Tim Duesterhus7fec0212018-07-27 18:46:13 +02001328 if (dst->ss_family == AF_INET) {
1329 /* Convert dst to IPv6 */
1330 v4tov6(&tmp, &((struct sockaddr_in *)dst)->sin_addr);
1331 dst_port = ((struct sockaddr_in *)dst)->sin_port;
1332 }
1333 else {
1334 tmp = ((struct sockaddr_in6 *)dst)->sin6_addr;
1335 dst_port = ((struct sockaddr_in6 *)dst)->sin6_port;
1336 }
Willy Tarreaue1e4a612012-10-05 00:10:55 +02001337
Tim Duesterhus7fec0212018-07-27 18:46:13 +02001338 if (!inet_ntop(AF_INET6, &tmp, dst_str, sizeof(dst_str)))
Willy Tarreaue1e4a612012-10-05 00:10:55 +02001339 return 0;
1340 }
Tim Duesterhus7fec0212018-07-27 18:46:13 +02001341
1342 ret = snprintf(buf, buf_len, "PROXY %s %s %s %u %u\r\n", protocol, src_str, dst_str, ntohs(src_port), ntohs(dst_port));
1343 if (ret >= buf_len)
1344 return 0;
1345
Willy Tarreaue1e4a612012-10-05 00:10:55 +02001346 return ret;
1347}
David Safb76832014-05-08 23:42:08 -04001348
KOVACS Krisztianb3e54fe2014-11-17 15:11:45 +01001349static int make_tlv(char *dest, int dest_len, char type, uint16_t length, const char *value)
David Safb76832014-05-08 23:42:08 -04001350{
1351 struct tlv *tlv;
1352
1353 if (!dest || (length + sizeof(*tlv) > dest_len))
1354 return 0;
1355
1356 tlv = (struct tlv *)dest;
1357
1358 tlv->type = type;
1359 tlv->length_hi = length >> 8;
1360 tlv->length_lo = length & 0x00ff;
1361 memcpy(tlv->value, value, length);
1362 return length + sizeof(*tlv);
1363}
David Safb76832014-05-08 23:42:08 -04001364
Ilya Shipitsinca56fce2018-09-15 00:50:05 +05001365/* Note: <remote> is explicitly allowed to be NULL */
Tim Duesterhuscf6e0c82020-03-13 12:34:24 +01001366int 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 -04001367{
Willy Tarreau8fccfa22014-06-14 08:28:06 +02001368 const char pp2_signature[] = PP2_SIGNATURE;
Emmanuel Hocdet4399c752018-02-05 15:26:43 +01001369 void *tlv_crc32c_p = NULL;
David Safb76832014-05-08 23:42:08 -04001370 int ret = 0;
Willy Tarreau8fccfa22014-06-14 08:28:06 +02001371 struct proxy_hdr_v2 *hdr = (struct proxy_hdr_v2 *)buf;
Vincent Bernat6e615892016-05-18 16:17:44 +02001372 struct sockaddr_storage null_addr = { .ss_family = 0 };
David Safb76832014-05-08 23:42:08 -04001373 struct sockaddr_storage *src = &null_addr;
1374 struct sockaddr_storage *dst = &null_addr;
Emmanuel Hocdet404d9782017-10-24 10:55:14 +02001375 const char *value;
1376 int value_len;
David Safb76832014-05-08 23:42:08 -04001377
1378 if (buf_len < PP2_HEADER_LEN)
1379 return 0;
Willy Tarreau8fccfa22014-06-14 08:28:06 +02001380 memcpy(hdr->sig, pp2_signature, PP2_SIGNATURE_LEN);
David Safb76832014-05-08 23:42:08 -04001381
Willy Tarreau226572f2019-07-17 14:46:00 +02001382 if (remote && conn_get_src(remote) && conn_get_dst(remote)) {
1383 src = remote->src;
1384 dst = remote->dst;
David Safb76832014-05-08 23:42:08 -04001385 }
KOVACS Krisztianb3e54fe2014-11-17 15:11:45 +01001386
Tim Duesterhus7fec0212018-07-27 18:46:13 +02001387 /* At least one of src or dst is not of AF_INET or AF_INET6 */
1388 if ( !src
1389 || !dst
Willy Tarreau119e50e2020-05-22 13:53:29 +02001390 || (!pp2_never_send_local && conn_is_back(remote)) // locally initiated connection
Tim Duesterhus7fec0212018-07-27 18:46:13 +02001391 || (src->ss_family != AF_INET && src->ss_family != AF_INET6)
1392 || (dst->ss_family != AF_INET && dst->ss_family != AF_INET6)) {
David Safb76832014-05-08 23:42:08 -04001393 if (buf_len < PP2_HDR_LEN_UNSPEC)
1394 return 0;
Willy Tarreau8fccfa22014-06-14 08:28:06 +02001395 hdr->ver_cmd = PP2_VERSION | PP2_CMD_LOCAL;
1396 hdr->fam = PP2_FAM_UNSPEC | PP2_TRANS_UNSPEC;
David Safb76832014-05-08 23:42:08 -04001397 ret = PP2_HDR_LEN_UNSPEC;
1398 }
Tim Duesterhus7fec0212018-07-27 18:46:13 +02001399 else {
Willy Tarreau02c88032020-04-14 12:54:10 +02001400 hdr->ver_cmd = PP2_VERSION | PP2_CMD_PROXY;
Tim Duesterhus7fec0212018-07-27 18:46:13 +02001401 /* IPv4 for both src and dst */
1402 if (src->ss_family == AF_INET && dst->ss_family == AF_INET) {
1403 if (buf_len < PP2_HDR_LEN_INET)
1404 return 0;
Tim Duesterhus7fec0212018-07-27 18:46:13 +02001405 hdr->fam = PP2_FAM_INET | PP2_TRANS_STREAM;
1406 hdr->addr.ip4.src_addr = ((struct sockaddr_in *)src)->sin_addr.s_addr;
1407 hdr->addr.ip4.src_port = ((struct sockaddr_in *)src)->sin_port;
1408 hdr->addr.ip4.dst_addr = ((struct sockaddr_in *)dst)->sin_addr.s_addr;
1409 hdr->addr.ip4.dst_port = ((struct sockaddr_in *)dst)->sin_port;
1410 ret = PP2_HDR_LEN_INET;
1411 }
1412 /* IPv6 for at least one of src and dst */
1413 else {
1414 struct in6_addr tmp;
1415
1416 if (buf_len < PP2_HDR_LEN_INET6)
1417 return 0;
Tim Duesterhus7fec0212018-07-27 18:46:13 +02001418 hdr->fam = PP2_FAM_INET6 | PP2_TRANS_STREAM;
1419 if (src->ss_family == AF_INET) {
1420 v4tov6(&tmp, &((struct sockaddr_in *)src)->sin_addr);
1421 memcpy(hdr->addr.ip6.src_addr, &tmp, 16);
1422 hdr->addr.ip6.src_port = ((struct sockaddr_in *)src)->sin_port;
1423 }
1424 else {
1425 memcpy(hdr->addr.ip6.src_addr, &((struct sockaddr_in6 *)src)->sin6_addr, 16);
1426 hdr->addr.ip6.src_port = ((struct sockaddr_in6 *)src)->sin6_port;
1427 }
1428 if (dst->ss_family == AF_INET) {
1429 v4tov6(&tmp, &((struct sockaddr_in *)dst)->sin_addr);
1430 memcpy(hdr->addr.ip6.dst_addr, &tmp, 16);
William Dauchybd8bf672020-01-26 19:06:39 +01001431 hdr->addr.ip6.dst_port = ((struct sockaddr_in *)dst)->sin_port;
Tim Duesterhus7fec0212018-07-27 18:46:13 +02001432 }
1433 else {
1434 memcpy(hdr->addr.ip6.dst_addr, &((struct sockaddr_in6 *)dst)->sin6_addr, 16);
1435 hdr->addr.ip6.dst_port = ((struct sockaddr_in6 *)dst)->sin6_port;
1436 }
1437
1438 ret = PP2_HDR_LEN_INET6;
1439 }
1440 }
David Safb76832014-05-08 23:42:08 -04001441
Emmanuel Hocdet4399c752018-02-05 15:26:43 +01001442 if (srv->pp_opts & SRV_PP_V2_CRC32C) {
1443 uint32_t zero_crc32c = 0;
Tim Duesterhusa8692f32020-03-13 12:34:25 +01001444
Emmanuel Hocdet4399c752018-02-05 15:26:43 +01001445 if ((buf_len - ret) < sizeof(struct tlv))
1446 return 0;
1447 tlv_crc32c_p = (void *)((struct tlv *)&buf[ret])->value;
1448 ret += make_tlv(&buf[ret], (buf_len - ret), PP2_TYPE_CRC32C, sizeof(zero_crc32c), (const char *)&zero_crc32c);
1449 }
1450
Ilya Shipitsinca56fce2018-09-15 00:50:05 +05001451 if (remote && conn_get_alpn(remote, &value, &value_len)) {
Emmanuel Hocdet404d9782017-10-24 10:55:14 +02001452 if ((buf_len - ret) < sizeof(struct tlv))
1453 return 0;
Emmanuel Hocdet571c7ac2017-10-31 18:24:05 +01001454 ret += make_tlv(&buf[ret], (buf_len - ret), PP2_TYPE_ALPN, value_len, value);
Emmanuel Hocdet404d9782017-10-24 10:55:14 +02001455 }
1456
Emmanuel Hocdet253c3b72018-02-01 18:29:59 +01001457 if (srv->pp_opts & SRV_PP_V2_AUTHORITY) {
Emmanuel Hocdet8a4ffa02019-08-29 11:54:51 +02001458 value = NULL;
1459 if (remote && remote->proxy_authority) {
1460 value = remote->proxy_authority;
1461 value_len = remote->proxy_authority_len;
1462 }
1463#ifdef USE_OPENSSL
1464 else {
Jerome Magnin78891c72019-09-02 09:53:41 +02001465 if ((value = ssl_sock_get_sni(remote)))
Emmanuel Hocdet8a4ffa02019-08-29 11:54:51 +02001466 value_len = strlen(value);
1467 }
1468#endif
Emmanuel Hocdet253c3b72018-02-01 18:29:59 +01001469 if (value) {
1470 if ((buf_len - ret) < sizeof(struct tlv))
1471 return 0;
Emmanuel Hocdet8a4ffa02019-08-29 11:54:51 +02001472 ret += make_tlv(&buf[ret], (buf_len - ret), PP2_TYPE_AUTHORITY, value_len, value);
Emmanuel Hocdet253c3b72018-02-01 18:29:59 +01001473 }
1474 }
1475
Christopher Faulet3ab504f2020-05-26 15:16:01 +02001476 if (strm && (srv->pp_opts & SRV_PP_V2_UNIQUE_ID)) {
Tim Duesterhuscf6e0c82020-03-13 12:34:24 +01001477 struct session* sess = strm_sess(strm);
1478 struct ist unique_id = stream_generate_unique_id(strm, &sess->fe->format_unique_id);
1479
1480 value = unique_id.ptr;
1481 value_len = unique_id.len;
1482
1483 if (value_len >= 0) {
1484 if ((buf_len - ret) < sizeof(struct tlv))
1485 return 0;
1486 ret += make_tlv(&buf[ret], (buf_len - ret), PP2_TYPE_UNIQUE_ID, value_len, value);
1487 }
1488 }
1489
Emmanuel Hocdet8a4ffa02019-08-29 11:54:51 +02001490#ifdef USE_OPENSSL
David Safb76832014-05-08 23:42:08 -04001491 if (srv->pp_opts & SRV_PP_V2_SSL) {
Emmanuel Hocdet404d9782017-10-24 10:55:14 +02001492 struct tlv_ssl *tlv;
1493 int ssl_tlv_len = 0;
Tim Duesterhusa8692f32020-03-13 12:34:25 +01001494
David Safb76832014-05-08 23:42:08 -04001495 if ((buf_len - ret) < sizeof(struct tlv_ssl))
1496 return 0;
1497 tlv = (struct tlv_ssl *)&buf[ret];
1498 memset(tlv, 0, sizeof(struct tlv_ssl));
1499 ssl_tlv_len += sizeof(struct tlv_ssl);
1500 tlv->tlv.type = PP2_TYPE_SSL;
1501 if (ssl_sock_is_ssl(remote)) {
1502 tlv->client |= PP2_CLIENT_SSL;
Emmanuel Hocdet01da5712017-10-13 16:59:49 +02001503 value = ssl_sock_get_proto_version(remote);
David Safb76832014-05-08 23:42:08 -04001504 if (value) {
Emmanuel Hocdet8c0c34b2018-02-28 12:02:14 +01001505 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 -04001506 }
Dave McCowan328fb582014-07-30 10:39:13 -04001507 if (ssl_sock_get_cert_used_sess(remote)) {
1508 tlv->client |= PP2_CLIENT_CERT_SESS;
David Safb76832014-05-08 23:42:08 -04001509 tlv->verify = htonl(ssl_sock_get_verify_result(remote));
Dave McCowan328fb582014-07-30 10:39:13 -04001510 if (ssl_sock_get_cert_used_conn(remote))
1511 tlv->client |= PP2_CLIENT_CERT_CONN;
David Safb76832014-05-08 23:42:08 -04001512 }
1513 if (srv->pp_opts & SRV_PP_V2_SSL_CN) {
Willy Tarreau83061a82018-07-13 11:56:34 +02001514 struct buffer *cn_trash = get_trash_chunk();
Willy Tarreau3b9a0c92014-07-19 06:37:33 +02001515 if (ssl_sock_get_remote_common_name(remote, cn_trash) > 0) {
Willy Tarreau843b7cb2018-07-13 10:54:26 +02001516 ssl_tlv_len += make_tlv(&buf[ret+ssl_tlv_len], (buf_len - ret - ssl_tlv_len), PP2_SUBTYPE_SSL_CN,
1517 cn_trash->data,
1518 cn_trash->area);
David Safb76832014-05-08 23:42:08 -04001519 }
1520 }
Emmanuel Hocdetfa8d0f12018-02-01 15:53:52 +01001521 if (srv->pp_opts & SRV_PP_V2_SSL_KEY_ALG) {
Willy Tarreau83061a82018-07-13 11:56:34 +02001522 struct buffer *pkey_trash = get_trash_chunk();
Emmanuel Hocdetfa8d0f12018-02-01 15:53:52 +01001523 if (ssl_sock_get_pkey_algo(remote, pkey_trash) > 0) {
Willy Tarreau843b7cb2018-07-13 10:54:26 +02001524 ssl_tlv_len += make_tlv(&buf[ret+ssl_tlv_len], (buf_len - ret - ssl_tlv_len), PP2_SUBTYPE_SSL_KEY_ALG,
1525 pkey_trash->data,
1526 pkey_trash->area);
Emmanuel Hocdetfa8d0f12018-02-01 15:53:52 +01001527 }
1528 }
1529 if (srv->pp_opts & SRV_PP_V2_SSL_SIG_ALG) {
1530 value = ssl_sock_get_cert_sig(remote);
1531 if (value) {
1532 ssl_tlv_len += make_tlv(&buf[ret+ssl_tlv_len], (buf_len - ret - ssl_tlv_len), PP2_SUBTYPE_SSL_SIG_ALG, strlen(value), value);
1533 }
1534 }
1535 if (srv->pp_opts & SRV_PP_V2_SSL_CIPHER) {
1536 value = ssl_sock_get_cipher_name(remote);
1537 if (value) {
1538 ssl_tlv_len += make_tlv(&buf[ret+ssl_tlv_len], (buf_len - ret - ssl_tlv_len), PP2_SUBTYPE_SSL_CIPHER, strlen(value), value);
1539 }
1540 }
David Safb76832014-05-08 23:42:08 -04001541 }
1542 tlv->tlv.length_hi = (uint16_t)(ssl_tlv_len - sizeof(struct tlv)) >> 8;
1543 tlv->tlv.length_lo = (uint16_t)(ssl_tlv_len - sizeof(struct tlv)) & 0x00ff;
1544 ret += ssl_tlv_len;
1545 }
1546#endif
1547
Willy Tarreaue5733232019-05-22 19:24:06 +02001548#ifdef USE_NS
KOVACS Krisztianb3e54fe2014-11-17 15:11:45 +01001549 if (remote && (remote->proxy_netns)) {
1550 if ((buf_len - ret) < sizeof(struct tlv))
1551 return 0;
Emmanuel Hocdet571c7ac2017-10-31 18:24:05 +01001552 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 +01001553 }
1554#endif
1555
Willy Tarreau8fccfa22014-06-14 08:28:06 +02001556 hdr->len = htons((uint16_t)(ret - PP2_HEADER_LEN));
David Safb76832014-05-08 23:42:08 -04001557
Emmanuel Hocdet4399c752018-02-05 15:26:43 +01001558 if (tlv_crc32c_p) {
1559 write_u32(tlv_crc32c_p, htonl(hash_crc32c(buf, ret)));
1560 }
1561
David Safb76832014-05-08 23:42:08 -04001562 return ret;
1563}
Emeric Brun4f603012017-01-05 15:11:44 +01001564
Willy Tarreau119e50e2020-05-22 13:53:29 +02001565/* returns 0 on success */
1566static int cfg_parse_pp2_never_send_local(char **args, int section_type, struct proxy *curpx,
1567 struct proxy *defpx, const char *file, int line,
1568 char **err)
1569{
1570 if (too_many_args(0, args, err, NULL))
1571 return -1;
1572 pp2_never_send_local = 1;
1573 return 0;
1574}
1575
Willy Tarreau60ca10a2017-08-18 15:26:54 +02001576/* return the major HTTP version as 1 or 2 depending on how the request arrived
1577 * before being processed.
1578 */
1579static int
1580smp_fetch_fc_http_major(const struct arg *args, struct sample *smp, const char *kw, void *private)
1581{
Jérôme Magnin86577422018-12-07 09:03:11 +01001582 struct connection *conn = (kw[0] != 'b') ? objt_conn(smp->sess->origin) :
1583 smp->strm ? cs_conn(objt_cs(smp->strm->si[1].end)) : NULL;
Willy Tarreau60ca10a2017-08-18 15:26:54 +02001584
1585 smp->data.type = SMP_T_SINT;
1586 smp->data.u.sint = (conn && strcmp(conn_get_mux_name(conn), "H2") == 0) ? 2 : 1;
1587 return 1;
1588}
1589
Emeric Brun4f603012017-01-05 15:11:44 +01001590/* fetch if the received connection used a PROXY protocol header */
1591int smp_fetch_fc_rcvd_proxy(const struct arg *args, struct sample *smp, const char *kw, void *private)
1592{
1593 struct connection *conn;
1594
1595 conn = objt_conn(smp->sess->origin);
1596 if (!conn)
1597 return 0;
1598
Willy Tarreau911db9b2020-01-23 16:27:54 +01001599 if (conn->flags & CO_FL_WAIT_XPRT) {
Emeric Brun4f603012017-01-05 15:11:44 +01001600 smp->flags |= SMP_F_MAY_CHANGE;
1601 return 0;
1602 }
1603
1604 smp->flags = 0;
1605 smp->data.type = SMP_T_BOOL;
1606 smp->data.u.sint = (conn->flags & CO_FL_RCVD_PROXY) ? 1 : 0;
1607
1608 return 1;
1609}
1610
Geoff Simmons7185b782019-08-27 18:31:16 +02001611/* fetch the authority TLV from a PROXY protocol header */
1612int smp_fetch_fc_pp_authority(const struct arg *args, struct sample *smp, const char *kw, void *private)
1613{
1614 struct connection *conn;
1615
1616 conn = objt_conn(smp->sess->origin);
1617 if (!conn)
1618 return 0;
1619
Willy Tarreau911db9b2020-01-23 16:27:54 +01001620 if (conn->flags & CO_FL_WAIT_XPRT) {
Geoff Simmons7185b782019-08-27 18:31:16 +02001621 smp->flags |= SMP_F_MAY_CHANGE;
1622 return 0;
1623 }
1624
1625 if (conn->proxy_authority == NULL)
1626 return 0;
1627
1628 smp->flags = 0;
1629 smp->data.type = SMP_T_STR;
1630 smp->data.u.str.area = conn->proxy_authority;
1631 smp->data.u.str.data = conn->proxy_authority_len;
1632
1633 return 1;
1634}
1635
Tim Duesterhusd1b15b62020-03-13 12:34:23 +01001636/* fetch the unique ID TLV from a PROXY protocol header */
1637int smp_fetch_fc_pp_unique_id(const struct arg *args, struct sample *smp, const char *kw, void *private)
1638{
1639 struct connection *conn;
1640
1641 conn = objt_conn(smp->sess->origin);
1642 if (!conn)
1643 return 0;
1644
1645 if (conn->flags & CO_FL_WAIT_XPRT) {
1646 smp->flags |= SMP_F_MAY_CHANGE;
1647 return 0;
1648 }
1649
1650 if (!isttest(conn->proxy_unique_id))
1651 return 0;
1652
1653 smp->flags = 0;
1654 smp->data.type = SMP_T_STR;
1655 smp->data.u.str.area = conn->proxy_unique_id.ptr;
1656 smp->data.u.str.data = conn->proxy_unique_id.len;
1657
1658 return 1;
1659}
1660
Emeric Brun4f603012017-01-05 15:11:44 +01001661/* Note: must not be declared <const> as its list will be overwritten.
1662 * Note: fetches that may return multiple types must be declared as the lowest
1663 * common denominator, the type that can be casted into all other ones. For
1664 * instance v4/v6 must be declared v4.
1665 */
1666static struct sample_fetch_kw_list sample_fetch_keywords = {ILH, {
Willy Tarreau60ca10a2017-08-18 15:26:54 +02001667 { "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 +01001668 { "bc_http_major", smp_fetch_fc_http_major, 0, NULL, SMP_T_SINT, SMP_USE_L4SRV },
Emeric Brun4f603012017-01-05 15:11:44 +01001669 { "fc_rcvd_proxy", smp_fetch_fc_rcvd_proxy, 0, NULL, SMP_T_BOOL, SMP_USE_L4CLI },
Geoff Simmons7185b782019-08-27 18:31:16 +02001670 { "fc_pp_authority", smp_fetch_fc_pp_authority, 0, NULL, SMP_T_STR, SMP_USE_L4CLI },
Tim Duesterhusd1b15b62020-03-13 12:34:23 +01001671 { "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 +01001672 { /* END */ },
1673}};
1674
Willy Tarreau0108d902018-11-25 19:14:37 +01001675INITCALL1(STG_REGISTER, sample_register_fetches, &sample_fetch_keywords);
Willy Tarreau119e50e2020-05-22 13:53:29 +02001676
1677static struct cfg_kw_list cfg_kws = {ILH, {
1678 { CFG_GLOBAL, "pp2-never-send-local", cfg_parse_pp2_never_send_local },
1679 { /* END */ },
1680}};
1681
1682INITCALL1(STG_REGISTER, cfg_register_keywords, &cfg_kws);