blob: 50ab08170f29f46f6c0e8daa66950d8f789dca69 [file] [log] [blame]
Willy Tarreaue6b98942007-10-29 01:09:36 +01001/*
2 * AF_INET/AF_INET6 SOCK_STREAM protocol layer (tcp)
3 *
Willy Tarreaue8c66af2008-01-13 18:40:14 +01004 * Copyright 2000-2008 Willy Tarreau <w@1wt.eu>
Willy Tarreaue6b98942007-10-29 01:09:36 +01005 *
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
13#include <ctype.h>
14#include <errno.h>
15#include <fcntl.h>
16#include <stdio.h>
17#include <stdlib.h>
18#include <string.h>
19#include <time.h>
20
21#include <sys/param.h>
22#include <sys/socket.h>
23#include <sys/stat.h>
24#include <sys/types.h>
25#include <sys/un.h>
26
Dmitry Sivachenkocaf58982009-08-24 15:11:06 +040027#include <netinet/tcp.h>
28
Willy Tarreaub6866442008-07-14 23:54:42 +020029#include <common/cfgparse.h>
Willy Tarreaue6b98942007-10-29 01:09:36 +010030#include <common/compat.h>
31#include <common/config.h>
32#include <common/debug.h>
33#include <common/errors.h>
34#include <common/memory.h>
35#include <common/mini-clist.h>
36#include <common/standard.h>
37#include <common/time.h>
38#include <common/version.h>
39
Willy Tarreaue6b98942007-10-29 01:09:36 +010040#include <types/global.h>
Willy Tarreau9650f372009-08-16 14:02:45 +020041#include <types/server.h>
Willy Tarreaue6b98942007-10-29 01:09:36 +010042
43#include <proto/acl.h>
44#include <proto/backend.h>
45#include <proto/buffers.h>
Krzysztof Piotr Oledzki97f07b82009-12-15 22:31:24 +010046#include <proto/checks.h>
Willy Tarreaue6b98942007-10-29 01:09:36 +010047#include <proto/fd.h>
Willy Tarreau9650f372009-08-16 14:02:45 +020048#include <proto/log.h>
49#include <proto/port_range.h>
Willy Tarreaue6b98942007-10-29 01:09:36 +010050#include <proto/protocols.h>
51#include <proto/proto_tcp.h>
Willy Tarreaub6866442008-07-14 23:54:42 +020052#include <proto/proxy.h>
Willy Tarreaue6b98942007-10-29 01:09:36 +010053#include <proto/queue.h>
Willy Tarreaue6b98942007-10-29 01:09:36 +010054#include <proto/session.h>
55#include <proto/stream_sock.h>
56#include <proto/task.h>
57
Willy Tarreaue8c66af2008-01-13 18:40:14 +010058#ifdef CONFIG_HAP_CTTPROXY
59#include <import/ip_tproxy.h>
60#endif
61
Willy Tarreaue6b98942007-10-29 01:09:36 +010062static int tcp_bind_listeners(struct protocol *proto);
63
64/* Note: must not be declared <const> as its list will be overwritten */
65static struct protocol proto_tcpv4 = {
66 .name = "tcpv4",
67 .sock_domain = AF_INET,
68 .sock_type = SOCK_STREAM,
69 .sock_prot = IPPROTO_TCP,
70 .sock_family = AF_INET,
71 .sock_addrlen = sizeof(struct sockaddr_in),
72 .l3_addrlen = 32/8,
73 .read = &stream_sock_read,
74 .write = &stream_sock_write,
75 .bind_all = tcp_bind_listeners,
76 .unbind_all = unbind_all_listeners,
77 .enable_all = enable_all_listeners,
78 .listeners = LIST_HEAD_INIT(proto_tcpv4.listeners),
79 .nb_listeners = 0,
80};
81
82/* Note: must not be declared <const> as its list will be overwritten */
83static struct protocol proto_tcpv6 = {
84 .name = "tcpv6",
85 .sock_domain = AF_INET6,
86 .sock_type = SOCK_STREAM,
87 .sock_prot = IPPROTO_TCP,
88 .sock_family = AF_INET6,
89 .sock_addrlen = sizeof(struct sockaddr_in6),
90 .l3_addrlen = 128/8,
91 .read = &stream_sock_read,
92 .write = &stream_sock_write,
93 .bind_all = tcp_bind_listeners,
94 .unbind_all = unbind_all_listeners,
95 .enable_all = enable_all_listeners,
96 .listeners = LIST_HEAD_INIT(proto_tcpv6.listeners),
97 .nb_listeners = 0,
98};
99
Willy Tarreaue8c66af2008-01-13 18:40:14 +0100100
101/* Binds ipv4 address <local> to socket <fd>, unless <flags> is set, in which
102 * case we try to bind <remote>. <flags> is a 2-bit field consisting of :
103 * - 0 : ignore remote address (may even be a NULL pointer)
104 * - 1 : use provided address
105 * - 2 : use provided port
106 * - 3 : use both
107 *
108 * The function supports multiple foreign binding methods :
109 * - linux_tproxy: we directly bind to the foreign address
110 * - cttproxy: we bind to a local address then nat.
111 * The second one can be used as a fallback for the first one.
112 * This function returns 0 when everything's OK, 1 if it could not bind, to the
113 * local address, 2 if it could not bind to the foreign address.
114 */
115int tcpv4_bind_socket(int fd, int flags, struct sockaddr_in *local, struct sockaddr_in *remote)
116{
117 struct sockaddr_in bind_addr;
118 int foreign_ok = 0;
119 int ret;
120
121#ifdef CONFIG_HAP_LINUX_TPROXY
122 static int ip_transp_working = 1;
123 if (flags && ip_transp_working) {
124 if (setsockopt(fd, SOL_IP, IP_TRANSPARENT, (char *) &one, sizeof(one)) == 0
125 || setsockopt(fd, SOL_IP, IP_FREEBIND, (char *) &one, sizeof(one)) == 0)
126 foreign_ok = 1;
127 else
128 ip_transp_working = 0;
129 }
130#endif
131 if (flags) {
132 memset(&bind_addr, 0, sizeof(bind_addr));
133 if (flags & 1)
134 bind_addr.sin_addr = remote->sin_addr;
135 if (flags & 2)
136 bind_addr.sin_port = remote->sin_port;
137 }
138
139 setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (char *) &one, sizeof(one));
140 if (foreign_ok) {
141 ret = bind(fd, (struct sockaddr *)&bind_addr, sizeof(bind_addr));
142 if (ret < 0)
143 return 2;
144 }
145 else {
146 ret = bind(fd, (struct sockaddr *)local, sizeof(*local));
147 if (ret < 0)
148 return 1;
149 }
150
151 if (!flags)
152 return 0;
153
154#ifdef CONFIG_HAP_CTTPROXY
155 if (!foreign_ok) {
156 struct in_tproxy itp1, itp2;
157 memset(&itp1, 0, sizeof(itp1));
158
159 itp1.op = TPROXY_ASSIGN;
160 itp1.v.addr.faddr = bind_addr.sin_addr;
161 itp1.v.addr.fport = bind_addr.sin_port;
162
163 /* set connect flag on socket */
164 itp2.op = TPROXY_FLAGS;
165 itp2.v.flags = ITP_CONNECT | ITP_ONCE;
166
167 if (setsockopt(fd, SOL_IP, IP_TPROXY, &itp1, sizeof(itp1)) != -1 &&
168 setsockopt(fd, SOL_IP, IP_TPROXY, &itp2, sizeof(itp2)) != -1) {
169 foreign_ok = 1;
170 }
171 }
172#endif
173 if (!foreign_ok)
174 /* we could not bind to a foreign address */
175 return 2;
176
177 return 0;
178}
Willy Tarreaue6b98942007-10-29 01:09:36 +0100179
Willy Tarreau9650f372009-08-16 14:02:45 +0200180
181/*
182 * This function initiates a connection to the server assigned to this session
Willy Tarreaub1d67742010-03-29 19:36:59 +0200183 * (s->srv, s->srv_addr). It will assign a server if none is assigned yet. A
184 * source address may be pointed to by <from_addr>. Note that this is only used
185 * in case of transparent proxying. Normal source bind addresses are still
186 * determined locally (due to the possible need of a source port).
187 *
Willy Tarreau9650f372009-08-16 14:02:45 +0200188 * It can return one of :
189 * - SN_ERR_NONE if everything's OK
190 * - SN_ERR_SRVTO if there are no more servers
191 * - SN_ERR_SRVCL if the connection was refused by the server
192 * - SN_ERR_PRXCOND if the connection has been limited by the proxy (maxconn)
193 * - SN_ERR_RESOURCE if a system resource is lacking (eg: fd limits, ports, ...)
194 * - SN_ERR_INTERNAL for any other purely internal errors
195 * Additionnally, in the case of SN_ERR_RESOURCE, an emergency log will be emitted.
196 */
197int tcpv4_connect_server(struct stream_interface *si,
198 struct proxy *be, struct server *srv,
Willy Tarreaub1d67742010-03-29 19:36:59 +0200199 struct sockaddr *srv_addr, struct sockaddr *from_addr)
Willy Tarreau9650f372009-08-16 14:02:45 +0200200{
201 int fd;
202
203 if ((fd = si->fd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)) == -1) {
204 qfprintf(stderr, "Cannot get a server socket.\n");
205
206 if (errno == ENFILE)
207 send_log(be, LOG_EMERG,
208 "Proxy %s reached system FD limit at %d. Please check system tunables.\n",
209 be->id, maxfd);
210 else if (errno == EMFILE)
211 send_log(be, LOG_EMERG,
212 "Proxy %s reached process FD limit at %d. Please check 'ulimit-n' and restart.\n",
213 be->id, maxfd);
214 else if (errno == ENOBUFS || errno == ENOMEM)
215 send_log(be, LOG_EMERG,
216 "Proxy %s reached system memory limit at %d sockets. Please check system tunables.\n",
217 be->id, maxfd);
218 /* this is a resource error */
219 return SN_ERR_RESOURCE;
220 }
221
222 if (fd >= global.maxsock) {
223 /* do not log anything there, it's a normal condition when this option
224 * is used to serialize connections to a server !
225 */
226 Alert("socket(): not enough free sockets. Raise -n argument. Giving up.\n");
227 close(fd);
228 return SN_ERR_PRXCOND; /* it is a configuration limit */
229 }
230
231 if ((fcntl(fd, F_SETFL, O_NONBLOCK)==-1) ||
232 (setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, (char *) &one, sizeof(one)) == -1)) {
233 qfprintf(stderr,"Cannot set client socket to non blocking mode.\n");
234 close(fd);
235 return SN_ERR_INTERNAL;
236 }
237
238 if (be->options & PR_O_TCP_SRV_KA)
239 setsockopt(fd, SOL_SOCKET, SO_KEEPALIVE, (char *) &one, sizeof(one));
240
241 if (be->options & PR_O_TCP_NOLING)
242 setsockopt(fd, SOL_SOCKET, SO_LINGER, (struct linger *) &nolinger, sizeof(struct linger));
243
244 /* allow specific binding :
245 * - server-specific at first
246 * - proxy-specific next
247 */
248 if (srv != NULL && srv->state & SRV_BIND_SRC) {
Willy Tarreau9650f372009-08-16 14:02:45 +0200249 int ret, flags = 0;
250
Willy Tarreau9650f372009-08-16 14:02:45 +0200251 switch (srv->state & SRV_TPROXY_MASK) {
252 case SRV_TPROXY_ADDR:
Willy Tarreau9650f372009-08-16 14:02:45 +0200253 case SRV_TPROXY_CLI:
Willy Tarreaub1d67742010-03-29 19:36:59 +0200254 flags = 3;
255 break;
Willy Tarreau9650f372009-08-16 14:02:45 +0200256 case SRV_TPROXY_CIP:
Willy Tarreaub1d67742010-03-29 19:36:59 +0200257 flags = 1;
Willy Tarreau9650f372009-08-16 14:02:45 +0200258 break;
259 }
Willy Tarreaub1d67742010-03-29 19:36:59 +0200260
Willy Tarreau9650f372009-08-16 14:02:45 +0200261#ifdef SO_BINDTODEVICE
262 /* Note: this might fail if not CAP_NET_RAW */
263 if (srv->iface_name)
264 setsockopt(fd, SOL_SOCKET, SO_BINDTODEVICE, srv->iface_name, srv->iface_len + 1);
265#endif
266
267 if (srv->sport_range) {
268 int attempts = 10; /* should be more than enough to find a spare port */
269 struct sockaddr_in src;
270
271 ret = 1;
272 src = srv->source_addr;
273
274 do {
275 /* note: in case of retry, we may have to release a previously
276 * allocated port, hence this loop's construct.
277 */
Willy Tarreau8d5d77e2009-10-18 07:25:52 +0200278 port_range_release_port(fdinfo[fd].port_range, fdinfo[fd].local_port);
279 fdinfo[fd].port_range = NULL;
Willy Tarreau9650f372009-08-16 14:02:45 +0200280
281 if (!attempts)
282 break;
283 attempts--;
284
Willy Tarreau8d5d77e2009-10-18 07:25:52 +0200285 fdinfo[fd].local_port = port_range_alloc_port(srv->sport_range);
286 if (!fdinfo[fd].local_port)
Willy Tarreau9650f372009-08-16 14:02:45 +0200287 break;
288
Willy Tarreau8d5d77e2009-10-18 07:25:52 +0200289 fdinfo[fd].port_range = srv->sport_range;
290 src.sin_port = htons(fdinfo[fd].local_port);
Willy Tarreau9650f372009-08-16 14:02:45 +0200291
Willy Tarreaub1d67742010-03-29 19:36:59 +0200292 ret = tcpv4_bind_socket(fd, flags, &src, (struct sockaddr_in *)from_addr);
Willy Tarreau9650f372009-08-16 14:02:45 +0200293 } while (ret != 0); /* binding NOK */
294 }
295 else {
Willy Tarreaub1d67742010-03-29 19:36:59 +0200296 ret = tcpv4_bind_socket(fd, flags, &srv->source_addr, (struct sockaddr_in *)from_addr);
Willy Tarreau9650f372009-08-16 14:02:45 +0200297 }
298
299 if (ret) {
Willy Tarreau8d5d77e2009-10-18 07:25:52 +0200300 port_range_release_port(fdinfo[fd].port_range, fdinfo[fd].local_port);
301 fdinfo[fd].port_range = NULL;
Willy Tarreau9650f372009-08-16 14:02:45 +0200302 close(fd);
303
304 if (ret == 1) {
305 Alert("Cannot bind to source address before connect() for server %s/%s. Aborting.\n",
306 be->id, srv->id);
307 send_log(be, LOG_EMERG,
308 "Cannot bind to source address before connect() for server %s/%s.\n",
309 be->id, srv->id);
310 } else {
311 Alert("Cannot bind to tproxy source address before connect() for server %s/%s. Aborting.\n",
312 be->id, srv->id);
313 send_log(be, LOG_EMERG,
314 "Cannot bind to tproxy source address before connect() for server %s/%s.\n",
315 be->id, srv->id);
316 }
317 return SN_ERR_RESOURCE;
318 }
319 }
320 else if (be->options & PR_O_BIND_SRC) {
Willy Tarreau9650f372009-08-16 14:02:45 +0200321 int ret, flags = 0;
322
Willy Tarreau9650f372009-08-16 14:02:45 +0200323 switch (be->options & PR_O_TPXY_MASK) {
324 case PR_O_TPXY_ADDR:
Willy Tarreau9650f372009-08-16 14:02:45 +0200325 case PR_O_TPXY_CLI:
Willy Tarreaub1d67742010-03-29 19:36:59 +0200326 flags = 3;
327 break;
Willy Tarreau9650f372009-08-16 14:02:45 +0200328 case PR_O_TPXY_CIP:
Willy Tarreaub1d67742010-03-29 19:36:59 +0200329 flags = 1;
Willy Tarreau9650f372009-08-16 14:02:45 +0200330 break;
331 }
Willy Tarreaub1d67742010-03-29 19:36:59 +0200332
Willy Tarreau9650f372009-08-16 14:02:45 +0200333#ifdef SO_BINDTODEVICE
334 /* Note: this might fail if not CAP_NET_RAW */
335 if (be->iface_name)
336 setsockopt(fd, SOL_SOCKET, SO_BINDTODEVICE, be->iface_name, be->iface_len + 1);
337#endif
Willy Tarreaub1d67742010-03-29 19:36:59 +0200338 ret = tcpv4_bind_socket(fd, flags, &be->source_addr, (struct sockaddr_in *)from_addr);
Willy Tarreau9650f372009-08-16 14:02:45 +0200339 if (ret) {
340 close(fd);
341 if (ret == 1) {
342 Alert("Cannot bind to source address before connect() for proxy %s. Aborting.\n",
343 be->id);
344 send_log(be, LOG_EMERG,
345 "Cannot bind to source address before connect() for proxy %s.\n",
346 be->id);
347 } else {
348 Alert("Cannot bind to tproxy source address before connect() for proxy %s. Aborting.\n",
349 be->id);
350 send_log(be, LOG_EMERG,
351 "Cannot bind to tproxy source address before connect() for proxy %s.\n",
352 be->id);
353 }
354 return SN_ERR_RESOURCE;
355 }
356 }
357
Dmitry Sivachenkocaf58982009-08-24 15:11:06 +0400358#if defined(TCP_QUICKACK)
Willy Tarreau9650f372009-08-16 14:02:45 +0200359 /* disabling tcp quick ack now allows the first request to leave the
360 * machine with the first ACK. We only do this if there are pending
361 * data in the buffer.
362 */
363 if ((be->options2 & PR_O2_SMARTCON) && si->ob->send_max)
Dmitry Sivachenkocaf58982009-08-24 15:11:06 +0400364 setsockopt(fd, IPPROTO_TCP, TCP_QUICKACK, (char *) &zero, sizeof(zero));
Willy Tarreau9650f372009-08-16 14:02:45 +0200365#endif
366
Willy Tarreaue803de22010-01-21 17:43:04 +0100367 if (global.tune.server_sndbuf)
368 setsockopt(fd, SOL_SOCKET, SO_SNDBUF, &global.tune.server_sndbuf, sizeof(global.tune.server_sndbuf));
369
370 if (global.tune.server_rcvbuf)
371 setsockopt(fd, SOL_SOCKET, SO_RCVBUF, &global.tune.server_rcvbuf, sizeof(global.tune.server_rcvbuf));
372
Willy Tarreau9650f372009-08-16 14:02:45 +0200373 if ((connect(fd, (struct sockaddr *)srv_addr, sizeof(struct sockaddr_in)) == -1) &&
374 (errno != EINPROGRESS) && (errno != EALREADY) && (errno != EISCONN)) {
375
376 if (errno == EAGAIN || errno == EADDRINUSE) {
377 char *msg;
378 if (errno == EAGAIN) /* no free ports left, try again later */
379 msg = "no free ports";
380 else
381 msg = "local address already in use";
382
383 qfprintf(stderr,"Cannot connect: %s.\n",msg);
Willy Tarreau8d5d77e2009-10-18 07:25:52 +0200384 port_range_release_port(fdinfo[fd].port_range, fdinfo[fd].local_port);
385 fdinfo[fd].port_range = NULL;
Willy Tarreau9650f372009-08-16 14:02:45 +0200386 close(fd);
387 send_log(be, LOG_EMERG,
388 "Connect() failed for server %s/%s: %s.\n",
389 be->id, srv->id, msg);
390 return SN_ERR_RESOURCE;
391 } else if (errno == ETIMEDOUT) {
392 //qfprintf(stderr,"Connect(): ETIMEDOUT");
Willy Tarreau8d5d77e2009-10-18 07:25:52 +0200393 port_range_release_port(fdinfo[fd].port_range, fdinfo[fd].local_port);
394 fdinfo[fd].port_range = NULL;
Willy Tarreau9650f372009-08-16 14:02:45 +0200395 close(fd);
396 return SN_ERR_SRVTO;
397 } else {
398 // (errno == ECONNREFUSED || errno == ENETUNREACH || errno == EACCES || errno == EPERM)
399 //qfprintf(stderr,"Connect(): %d", errno);
Willy Tarreau8d5d77e2009-10-18 07:25:52 +0200400 port_range_release_port(fdinfo[fd].port_range, fdinfo[fd].local_port);
401 fdinfo[fd].port_range = NULL;
Willy Tarreau9650f372009-08-16 14:02:45 +0200402 close(fd);
403 return SN_ERR_SRVCL;
404 }
405 }
406
407 fdtab[fd].owner = si;
408 fdtab[fd].state = FD_STCONN; /* connection in progress */
409 fdtab[fd].flags = FD_FL_TCP | FD_FL_TCP_NODELAY;
410 fdtab[fd].cb[DIR_RD].f = &stream_sock_read;
411 fdtab[fd].cb[DIR_RD].b = si->ib;
412 fdtab[fd].cb[DIR_WR].f = &stream_sock_write;
413 fdtab[fd].cb[DIR_WR].b = si->ob;
414
Willy Tarreau8d5d77e2009-10-18 07:25:52 +0200415 fdinfo[fd].peeraddr = (struct sockaddr *)srv_addr;
416 fdinfo[fd].peerlen = sizeof(struct sockaddr_in);
Willy Tarreau9650f372009-08-16 14:02:45 +0200417
418 fd_insert(fd);
419 EV_FD_SET(fd, DIR_WR); /* for connect status */
420
421 si->state = SI_ST_CON;
422 si->flags |= SI_FL_CAP_SPLTCP; /* TCP supports splicing */
423 si->exp = tick_add_ifset(now_ms, be->timeout.connect);
424
425 return SN_ERR_NONE; /* connection is OK */
426}
427
428
Willy Tarreaue6b98942007-10-29 01:09:36 +0100429/* This function tries to bind a TCPv4/v6 listener. It may return a warning or
430 * an error message in <err> if the message is at most <errlen> bytes long
431 * (including '\0'). The return value is composed from ERR_ABORT, ERR_WARN,
432 * ERR_ALERT, ERR_RETRYABLE and ERR_FATAL. ERR_NONE indicates that everything
433 * was alright and that no message was returned. ERR_RETRYABLE means that an
434 * error occurred but that it may vanish after a retry (eg: port in use), and
435 * ERR_FATAL indicates a non-fixable error.ERR_WARN and ERR_ALERT do not alter
436 * the meaning of the error, but just indicate that a message is present which
437 * should be displayed with the respective level. Last, ERR_ABORT indicates
438 * that it's pointless to try to start other listeners. No error message is
439 * returned if errlen is NULL.
440 */
441int tcp_bind_listener(struct listener *listener, char *errmsg, int errlen)
442{
443 __label__ tcp_return, tcp_close_return;
444 int fd, err;
445 const char *msg = NULL;
446
447 /* ensure we never return garbage */
448 if (errmsg && errlen)
449 *errmsg = 0;
450
451 if (listener->state != LI_ASSIGNED)
452 return ERR_NONE; /* already bound */
453
454 err = ERR_NONE;
455
456 if ((fd = socket(listener->addr.ss_family, SOCK_STREAM, IPPROTO_TCP)) == -1) {
457 err |= ERR_RETRYABLE | ERR_ALERT;
458 msg = "cannot create listening socket";
459 goto tcp_return;
460 }
Willy Tarreauedcf6682008-11-30 23:15:34 +0100461
Willy Tarreaue6b98942007-10-29 01:09:36 +0100462 if (fd >= global.maxsock) {
463 err |= ERR_FATAL | ERR_ABORT | ERR_ALERT;
464 msg = "not enough free sockets (raise '-n' parameter)";
465 goto tcp_close_return;
466 }
467
Willy Tarreaufb14edc2009-06-14 15:24:37 +0200468 if (fcntl(fd, F_SETFL, O_NONBLOCK) == -1) {
Willy Tarreaue6b98942007-10-29 01:09:36 +0100469 err |= ERR_FATAL | ERR_ALERT;
470 msg = "cannot make socket non-blocking";
471 goto tcp_close_return;
472 }
473
474 if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (char *) &one, sizeof(one)) == -1) {
475 /* not fatal but should be reported */
476 msg = "cannot do so_reuseaddr";
477 err |= ERR_ALERT;
478 }
479
480 if (listener->options & LI_O_NOLINGER)
481 setsockopt(fd, SOL_SOCKET, SO_LINGER, (struct linger *) &nolinger, sizeof(struct linger));
Willy Tarreauedcf6682008-11-30 23:15:34 +0100482
Willy Tarreaue6b98942007-10-29 01:09:36 +0100483#ifdef SO_REUSEPORT
484 /* OpenBSD supports this. As it's present in old libc versions of Linux,
485 * it might return an error that we will silently ignore.
486 */
487 setsockopt(fd, SOL_SOCKET, SO_REUSEPORT, (char *) &one, sizeof(one));
488#endif
Willy Tarreaub1e52e82008-01-13 14:49:51 +0100489#ifdef CONFIG_HAP_LINUX_TPROXY
Willy Tarreauedcf6682008-11-30 23:15:34 +0100490 if ((listener->options & LI_O_FOREIGN)
Willy Tarreau0a459892008-01-13 17:37:16 +0100491 && (setsockopt(fd, SOL_IP, IP_TRANSPARENT, (char *) &one, sizeof(one)) == -1)
492 && (setsockopt(fd, SOL_IP, IP_FREEBIND, (char *) &one, sizeof(one)) == -1)) {
Willy Tarreaub1e52e82008-01-13 14:49:51 +0100493 msg = "cannot make listening socket transparent";
494 err |= ERR_ALERT;
495 }
496#endif
Willy Tarreau5e6e2042009-02-04 17:19:29 +0100497#ifdef SO_BINDTODEVICE
498 /* Note: this might fail if not CAP_NET_RAW */
499 if (listener->interface) {
500 if (setsockopt(fd, SOL_SOCKET, SO_BINDTODEVICE,
Willy Tarreau604e8302009-03-06 00:48:23 +0100501 listener->interface, strlen(listener->interface) + 1) == -1) {
Willy Tarreau5e6e2042009-02-04 17:19:29 +0100502 msg = "cannot bind listener to device";
503 err |= ERR_WARN;
504 }
505 }
506#endif
Dmitry Sivachenkocaf58982009-08-24 15:11:06 +0400507#if defined(TCP_MAXSEG)
Willy Tarreaube1b9182009-06-14 18:48:19 +0200508 if (listener->maxseg) {
Dmitry Sivachenkocaf58982009-08-24 15:11:06 +0400509 if (setsockopt(fd, IPPROTO_TCP, TCP_MAXSEG,
Willy Tarreaube1b9182009-06-14 18:48:19 +0200510 &listener->maxseg, sizeof(listener->maxseg)) == -1) {
511 msg = "cannot set MSS";
512 err |= ERR_WARN;
513 }
514 }
515#endif
Willy Tarreaucb6cd432009-10-13 07:34:14 +0200516#if defined(TCP_DEFER_ACCEPT)
517 if (listener->options & LI_O_DEF_ACCEPT) {
518 /* defer accept by up to one second */
519 int accept_delay = 1;
520 if (setsockopt(fd, IPPROTO_TCP, TCP_DEFER_ACCEPT, &accept_delay, sizeof(accept_delay)) == -1) {
521 msg = "cannot enable DEFER_ACCEPT";
522 err |= ERR_WARN;
523 }
524 }
525#endif
Willy Tarreaue6b98942007-10-29 01:09:36 +0100526 if (bind(fd, (struct sockaddr *)&listener->addr, listener->proto->sock_addrlen) == -1) {
527 err |= ERR_RETRYABLE | ERR_ALERT;
528 msg = "cannot bind socket";
529 goto tcp_close_return;
530 }
Willy Tarreauedcf6682008-11-30 23:15:34 +0100531
Willy Tarreauc73ce2b2008-01-06 10:55:10 +0100532 if (listen(fd, listener->backlog ? listener->backlog : listener->maxconn) == -1) {
Willy Tarreaue6b98942007-10-29 01:09:36 +0100533 err |= ERR_RETRYABLE | ERR_ALERT;
534 msg = "cannot listen to socket";
535 goto tcp_close_return;
536 }
Willy Tarreauedcf6682008-11-30 23:15:34 +0100537
Dmitry Sivachenkocaf58982009-08-24 15:11:06 +0400538#if defined(TCP_QUICKACK)
Willy Tarreau9ea05a72009-06-14 12:07:01 +0200539 if (listener->options & LI_O_NOQUICKACK)
Dmitry Sivachenkocaf58982009-08-24 15:11:06 +0400540 setsockopt(fd, IPPROTO_TCP, TCP_QUICKACK, (char *) &zero, sizeof(zero));
Willy Tarreau9ea05a72009-06-14 12:07:01 +0200541#endif
542
Willy Tarreaue6b98942007-10-29 01:09:36 +0100543 /* the socket is ready */
544 listener->fd = fd;
545 listener->state = LI_LISTEN;
546
547 /* the function for the accept() event */
548 fd_insert(fd);
549 fdtab[fd].cb[DIR_RD].f = listener->accept;
550 fdtab[fd].cb[DIR_WR].f = NULL; /* never called */
551 fdtab[fd].cb[DIR_RD].b = fdtab[fd].cb[DIR_WR].b = NULL;
Willy Tarreaueabf3132008-08-29 23:36:51 +0200552 fdtab[fd].owner = listener; /* reference the listener instead of a task */
Willy Tarreaue6b98942007-10-29 01:09:36 +0100553 fdtab[fd].state = FD_STLISTEN;
Willy Tarreaufb14edc2009-06-14 15:24:37 +0200554 fdtab[fd].flags = FD_FL_TCP;
Willy Tarreau5d707e12009-06-28 11:09:07 +0200555 if (listener->options & LI_O_NOLINGER)
556 fdtab[fd].flags |= FD_FL_TCP_NOLING;
557
Willy Tarreau8d5d77e2009-10-18 07:25:52 +0200558 fdinfo[fd].peeraddr = NULL;
559 fdinfo[fd].peerlen = 0;
Willy Tarreaue6b98942007-10-29 01:09:36 +0100560 tcp_return:
561 if (msg && errlen)
562 strlcpy2(errmsg, msg, errlen);
563 return err;
564
565 tcp_close_return:
566 close(fd);
567 goto tcp_return;
568}
569
570/* This function creates all TCP sockets bound to the protocol entry <proto>.
571 * It is intended to be used as the protocol's bind_all() function.
572 * The sockets will be registered but not added to any fd_set, in order not to
573 * loose them across the fork(). A call to enable_all_listeners() is needed
574 * to complete initialization. The return value is composed from ERR_*.
575 */
576static int tcp_bind_listeners(struct protocol *proto)
577{
578 struct listener *listener;
579 int err = ERR_NONE;
580
581 list_for_each_entry(listener, &proto->listeners, proto_list) {
582 err |= tcp_bind_listener(listener, NULL, 0);
583 if ((err & ERR_CODE) == ERR_ABORT)
584 break;
585 }
586
587 return err;
588}
589
590/* Add listener to the list of tcpv4 listeners. The listener's state
591 * is automatically updated from LI_INIT to LI_ASSIGNED. The number of
592 * listeners is updated. This is the function to use to add a new listener.
593 */
594void tcpv4_add_listener(struct listener *listener)
595{
596 if (listener->state != LI_INIT)
597 return;
598 listener->state = LI_ASSIGNED;
599 listener->proto = &proto_tcpv4;
600 LIST_ADDQ(&proto_tcpv4.listeners, &listener->proto_list);
601 proto_tcpv4.nb_listeners++;
602}
603
604/* Add listener to the list of tcpv4 listeners. The listener's state
605 * is automatically updated from LI_INIT to LI_ASSIGNED. The number of
606 * listeners is updated. This is the function to use to add a new listener.
607 */
608void tcpv6_add_listener(struct listener *listener)
609{
610 if (listener->state != LI_INIT)
611 return;
612 listener->state = LI_ASSIGNED;
613 listener->proto = &proto_tcpv6;
614 LIST_ADDQ(&proto_tcpv6.listeners, &listener->proto_list);
615 proto_tcpv6.nb_listeners++;
616}
617
Willy Tarreauedcf6682008-11-30 23:15:34 +0100618/* This function performs the TCP request analysis on the current request. It
619 * returns 1 if the processing can continue on next analysers, or zero if it
620 * needs more data, encounters an error, or wants to immediately abort the
621 * request. It relies on buffers flags, and updates s->req->analysers. Its
622 * behaviour is rather simple:
Willy Tarreau86ef7dc2009-03-15 22:55:47 +0100623 * - the analyser should check for errors and timeouts, and react as expected.
624 * It does not have to close anything upon error, the caller will. Note that
625 * the caller also knows how to report errors and timeouts.
626 * - if the analyser does not have enough data, it must return 0 without calling
Willy Tarreauedcf6682008-11-30 23:15:34 +0100627 * other ones. It should also probably do a buffer_write_dis() to ensure
628 * that unprocessed data will not be forwarded. But that probably depends on
629 * the protocol.
630 * - if an analyser has enough data, it just has to pass on to the next
631 * analyser without using buffer_write_dis() (enabled by default).
632 * - if an analyser thinks it has no added value anymore staying here, it must
633 * reset its bit from the analysers flags in order not to be called anymore.
634 *
635 * In the future, analysers should be able to indicate that they want to be
636 * called after XXX bytes have been received (or transfered), and the min of
637 * all's wishes will be used to ring back (unless a special condition occurs).
638 */
Willy Tarreau3a816292009-07-07 10:55:49 +0200639int tcp_inspect_request(struct session *s, struct buffer *req, int an_bit)
Willy Tarreauedcf6682008-11-30 23:15:34 +0100640{
641 struct tcp_rule *rule;
642 int partial;
643
644 DPRINTF(stderr,"[%u] %s: session=%p b=%p, exp(r,w)=%u,%u bf=%08x bl=%d analysers=%02x\n",
645 now_ms, __FUNCTION__,
646 s,
647 req,
648 req->rex, req->wex,
649 req->flags,
650 req->l,
651 req->analysers);
652
Willy Tarreauedcf6682008-11-30 23:15:34 +0100653 /* We don't know whether we have enough data, so must proceed
654 * this way :
655 * - iterate through all rules in their declaration order
656 * - if one rule returns MISS, it means the inspect delay is
657 * not over yet, then return immediately, otherwise consider
658 * it as a non-match.
659 * - if one rule returns OK, then return OK
660 * - if one rule returns KO, then return KO
661 */
662
Willy Tarreaud869b242009-03-15 14:43:58 +0100663 if (req->flags & BF_SHUTR || !s->fe->tcp_req.inspect_delay || tick_is_expired(req->analyse_exp, now_ms))
Willy Tarreauedcf6682008-11-30 23:15:34 +0100664 partial = 0;
665 else
666 partial = ACL_PARTIAL;
667
668 list_for_each_entry(rule, &s->fe->tcp_req.inspect_rules, list) {
669 int ret = ACL_PAT_PASS;
670
671 if (rule->cond) {
Willy Tarreau51d5dad2009-07-12 10:10:05 +0200672 ret = acl_exec_cond(rule->cond, s->fe, s, &s->txn, ACL_DIR_REQ | partial);
Willy Tarreauedcf6682008-11-30 23:15:34 +0100673 if (ret == ACL_PAT_MISS) {
Willy Tarreau520d95e2009-09-19 21:04:57 +0200674 buffer_dont_connect(req);
Willy Tarreauedcf6682008-11-30 23:15:34 +0100675 /* just set the request timeout once at the beginning of the request */
Willy Tarreaud869b242009-03-15 14:43:58 +0100676 if (!tick_isset(req->analyse_exp) && s->fe->tcp_req.inspect_delay)
Willy Tarreauedcf6682008-11-30 23:15:34 +0100677 req->analyse_exp = tick_add_ifset(now_ms, s->fe->tcp_req.inspect_delay);
678 return 0;
679 }
680
681 ret = acl_pass(ret);
682 if (rule->cond->pol == ACL_COND_UNLESS)
683 ret = !ret;
684 }
685
686 if (ret) {
687 /* we have a matching rule. */
688 if (rule->action == TCP_ACT_REJECT) {
689 buffer_abort(req);
690 buffer_abort(s->rep);
691 req->analysers = 0;
Krzysztof Piotr Oledzkiaeebf9b2009-10-04 15:43:17 +0200692
Krzysztof Piotr Oledzki052d4fd2009-10-04 14:52:57 +0200693 s->fe->counters.failed_req++;
Krzysztof Piotr Oledzkiaeebf9b2009-10-04 15:43:17 +0200694 if (s->listener->counters)
695 s->listener->counters->failed_req++;
696
Willy Tarreauedcf6682008-11-30 23:15:34 +0100697 if (!(s->flags & SN_ERR_MASK))
698 s->flags |= SN_ERR_PRXCOND;
699 if (!(s->flags & SN_FINST_MASK))
700 s->flags |= SN_FINST_R;
701 return 0;
702 }
703 /* otherwise accept */
704 break;
705 }
706 }
707
708 /* if we get there, it means we have no rule which matches, or
709 * we have an explicit accept, so we apply the default accept.
710 */
Willy Tarreau3a816292009-07-07 10:55:49 +0200711 req->analysers &= ~an_bit;
Willy Tarreauedcf6682008-11-30 23:15:34 +0100712 req->analyse_exp = TICK_ETERNITY;
713 return 1;
714}
715
Emeric Brun647caf12009-06-30 17:57:00 +0200716/* Apply RDP cookie persistence to the current session. For this, the function
717 * tries to extract an RDP cookie from the request buffer, and look for the
718 * matching server in the list. If the server is found, it is assigned to the
719 * session. This always returns 1, and the analyser removes itself from the
720 * list. Nothing is performed if a server was already assigned.
721 */
722int tcp_persist_rdp_cookie(struct session *s, struct buffer *req, int an_bit)
723{
724 struct proxy *px = s->be;
725 int ret;
726 struct acl_expr expr;
727 struct acl_test test;
728 struct server *srv = px->srv;
729 struct sockaddr_in addr;
730 char *p;
731
732 DPRINTF(stderr,"[%u] %s: session=%p b=%p, exp(r,w)=%u,%u bf=%08x bl=%d analysers=%02x\n",
733 now_ms, __FUNCTION__,
734 s,
735 req,
736 req->rex, req->wex,
737 req->flags,
738 req->l,
739 req->analysers);
740
741 if (s->flags & SN_ASSIGNED)
742 goto no_cookie;
743
744 memset(&expr, 0, sizeof(expr));
745 memset(&test, 0, sizeof(test));
746
747 expr.arg.str = s->be->rdp_cookie_name;
748 expr.arg_len = s->be->rdp_cookie_len;
749
750 ret = acl_fetch_rdp_cookie(px, s, NULL, ACL_DIR_REQ, &expr, &test);
751 if (ret == 0 || (test.flags & ACL_TEST_F_MAY_CHANGE) || test.len == 0)
752 goto no_cookie;
753
754 memset(&addr, 0, sizeof(addr));
755 addr.sin_family = AF_INET;
756
757 /* Considering an rdp cookie detected using acl, test.ptr ended with <cr><lf> and should return */
758 addr.sin_addr.s_addr = strtoul(test.ptr, &p, 10);
759 if (*p != '.')
760 goto no_cookie;
761 p++;
762 addr.sin_port = (unsigned short)strtoul(p, &p, 10);
763 if (*p != '.')
764 goto no_cookie;
765
766 while (srv) {
767 if (memcmp(&addr, &(srv->addr), sizeof(addr)) == 0) {
768 if ((srv->state & SRV_RUNNING) || (px->options & PR_O_PERSIST)) {
769 /* we found the server and it is usable */
770 s->flags |= SN_DIRECT | SN_ASSIGNED;
771 s->srv = srv;
772 break;
773 }
774 }
775 srv = srv->next;
776 }
777
778no_cookie:
779 req->analysers &= ~an_bit;
780 req->analyse_exp = TICK_ETERNITY;
781 return 1;
782}
783
Willy Tarreauedcf6682008-11-30 23:15:34 +0100784
Willy Tarreaub6866442008-07-14 23:54:42 +0200785/* This function should be called to parse a line starting with the "tcp-request"
786 * keyword.
787 */
788static int tcp_parse_tcp_req(char **args, int section_type, struct proxy *curpx,
789 struct proxy *defpx, char *err, int errlen)
790{
791 const char *ptr = NULL;
Willy Tarreauc7e961e2008-08-17 17:13:47 +0200792 unsigned int val;
Willy Tarreaub6866442008-07-14 23:54:42 +0200793 int retlen;
794
795 if (!*args[1]) {
796 snprintf(err, errlen, "missing argument for '%s' in %s '%s'",
797 args[0], proxy_type_str(proxy), curpx->id);
798 return -1;
799 }
800
801 if (!strcmp(args[1], "inspect-delay")) {
802 if (curpx == defpx) {
803 snprintf(err, errlen, "%s %s is not allowed in 'defaults' sections",
804 args[0], args[1]);
805 return -1;
806 }
807
808 if (!(curpx->cap & PR_CAP_FE)) {
809 snprintf(err, errlen, "%s %s will be ignored because %s '%s' has no %s capability",
810 args[0], args[1], proxy_type_str(proxy), curpx->id,
811 "frontend");
812 return 1;
813 }
814
815 if (!*args[2] || (ptr = parse_time_err(args[2], &val, TIME_UNIT_MS))) {
816 retlen = snprintf(err, errlen,
817 "'%s %s' expects a positive delay in milliseconds, in %s '%s'",
818 args[0], args[1], proxy_type_str(proxy), curpx->id);
819 if (ptr && retlen < errlen)
820 retlen += snprintf(err+retlen, errlen - retlen,
821 " (unexpected character '%c')", *ptr);
822 return -1;
823 }
824
825 if (curpx->tcp_req.inspect_delay) {
826 snprintf(err, errlen, "ignoring %s %s (was already defined) in %s '%s'",
827 args[0], args[1], proxy_type_str(proxy), curpx->id);
828 return 1;
829 }
830 curpx->tcp_req.inspect_delay = val;
831 return 0;
832 }
833
834 if (!strcmp(args[1], "content")) {
835 int action;
Willy Tarreaudd64f8d2008-07-27 22:02:32 +0200836 int warn = 0;
Willy Tarreaub6866442008-07-14 23:54:42 +0200837 int pol = ACL_COND_NONE;
838 struct acl_cond *cond;
839 struct tcp_rule *rule;
840
841 if (curpx == defpx) {
842 snprintf(err, errlen, "%s %s is not allowed in 'defaults' sections",
843 args[0], args[1]);
844 return -1;
845 }
846
847 if (!strcmp(args[2], "accept"))
848 action = TCP_ACT_ACCEPT;
849 else if (!strcmp(args[2], "reject"))
850 action = TCP_ACT_REJECT;
851 else {
852 retlen = snprintf(err, errlen,
853 "'%s %s' expects 'accept' or 'reject', in %s '%s' (was '%s')",
854 args[0], args[1], proxy_type_str(curpx), curpx->id, args[2]);
855 return -1;
856 }
857
858 pol = ACL_COND_NONE;
859 cond = NULL;
860
Willy Tarreauef6494c2010-01-28 17:12:36 +0100861 if (strcmp(args[3], "if") == 0 || strcmp(args[3], "unless") == 0) {
862 if ((cond = build_acl_cond(NULL, 0, curpx, (const char **)args+3)) == NULL) {
863 retlen = snprintf(err, errlen,
864 "error detected in %s '%s' while parsing '%s' condition",
865 proxy_type_str(curpx), curpx->id, args[3]);
866 return -1;
867 }
868 }
869 else if (*args[3]) {
Willy Tarreau606ad732009-07-14 21:17:05 +0200870 retlen = snprintf(err, errlen,
871 "'%s %s %s' only accepts 'if' or 'unless', in %s '%s' (was '%s')",
872 args[0], args[1], args[2], proxy_type_str(curpx), curpx->id, args[3]);
873 return -1;
874 }
Willy Tarreaub6866442008-07-14 23:54:42 +0200875
Willy Tarreau1a211942009-07-14 13:53:17 +0200876 if (cond && (cond->requires & ACL_USE_RTR_ANY)) {
Willy Tarreaudd64f8d2008-07-27 22:02:32 +0200877 struct acl *acl;
878 const char *name;
879
Willy Tarreau1a211942009-07-14 13:53:17 +0200880 acl = cond_find_require(cond, ACL_USE_RTR_ANY);
Willy Tarreaudd64f8d2008-07-27 22:02:32 +0200881 name = acl ? acl->name : "(unknown)";
882
883 retlen = snprintf(err, errlen,
Willy Tarreau1a211942009-07-14 13:53:17 +0200884 "acl '%s' involves some response-only criteria which will be ignored.",
885 name);
Willy Tarreaudd64f8d2008-07-27 22:02:32 +0200886 warn++;
887 }
Willy Tarreaub6866442008-07-14 23:54:42 +0200888 rule = (struct tcp_rule *)calloc(1, sizeof(*rule));
889 rule->cond = cond;
890 rule->action = action;
891 LIST_INIT(&rule->list);
892 LIST_ADDQ(&curpx->tcp_req.inspect_rules, &rule->list);
Willy Tarreaudd64f8d2008-07-27 22:02:32 +0200893 return warn;
Willy Tarreaub6866442008-07-14 23:54:42 +0200894 }
895
896 snprintf(err, errlen, "unknown argument '%s' after '%s' in %s '%s'",
897 args[1], args[0], proxy_type_str(proxy), curpx->id);
898 return -1;
899}
900
901/* return the number of bytes in the request buffer */
902static int
903acl_fetch_req_len(struct proxy *px, struct session *l4, void *l7, int dir,
904 struct acl_expr *expr, struct acl_test *test)
905{
906 if (!l4 || !l4->req)
907 return 0;
908
909 test->i = l4->req->l;
910 test->flags = ACL_TEST_F_VOLATILE | ACL_TEST_F_MAY_CHANGE;
911 return 1;
912}
913
Willy Tarreau655e26a2008-07-15 18:58:05 +0200914/* Return the version of the SSL protocol in the request. It supports both
915 * SSLv3 (TLSv1) header format for any message, and SSLv2 header format for
916 * the hello message. The SSLv3 format is described in RFC 2246 p49, and the
917 * SSLv2 format is described here, and completed p67 of RFC 2246 :
918 * http://wp.netscape.com/eng/security/SSL_2.html
919 *
920 * Note: this decoder only works with non-wrapping data.
921 */
922static int
923acl_fetch_req_ssl_ver(struct proxy *px, struct session *l4, void *l7, int dir,
924 struct acl_expr *expr, struct acl_test *test)
925{
926 int version, bleft, msg_len;
927 const unsigned char *data;
928
929 if (!l4 || !l4->req)
930 return 0;
931
932 msg_len = 0;
933 bleft = l4->req->l;
934 if (!bleft)
935 goto too_short;
936
Willy Tarreauc7e961e2008-08-17 17:13:47 +0200937 data = (const unsigned char *)l4->req->w;
Willy Tarreau655e26a2008-07-15 18:58:05 +0200938 if ((*data >= 0x14 && *data <= 0x17) || (*data == 0xFF)) {
939 /* SSLv3 header format */
940 if (bleft < 5)
941 goto too_short;
942
943 version = (data[1] << 16) + data[2]; /* version: major, minor */
944 msg_len = (data[3] << 8) + data[4]; /* record length */
945
946 /* format introduced with SSLv3 */
947 if (version < 0x00030000)
948 goto not_ssl;
949
950 /* message length between 1 and 2^14 + 2048 */
951 if (msg_len < 1 || msg_len > ((1<<14) + 2048))
952 goto not_ssl;
953
954 bleft -= 5; data += 5;
955 } else {
956 /* SSLv2 header format, only supported for hello (msg type 1) */
957 int rlen, plen, cilen, silen, chlen;
958
959 if (*data & 0x80) {
960 if (bleft < 3)
961 goto too_short;
962 /* short header format : 15 bits for length */
963 rlen = ((data[0] & 0x7F) << 8) | data[1];
964 plen = 0;
965 bleft -= 2; data += 2;
966 } else {
967 if (bleft < 4)
968 goto too_short;
969 /* long header format : 14 bits for length + pad length */
970 rlen = ((data[0] & 0x3F) << 8) | data[1];
971 plen = data[2];
972 bleft -= 3; data += 2;
973 }
974
975 if (*data != 0x01)
976 goto not_ssl;
977 bleft--; data++;
978
979 if (bleft < 8)
980 goto too_short;
981 version = (data[0] << 16) + data[1]; /* version: major, minor */
982 cilen = (data[2] << 8) + data[3]; /* cipher len, multiple of 3 */
983 silen = (data[4] << 8) + data[5]; /* session_id_len: 0 or 16 */
984 chlen = (data[6] << 8) + data[7]; /* 16<=challenge length<=32 */
985
986 bleft -= 8; data += 8;
987 if (cilen % 3 != 0)
988 goto not_ssl;
989 if (silen && silen != 16)
990 goto not_ssl;
991 if (chlen < 16 || chlen > 32)
992 goto not_ssl;
993 if (rlen != 9 + cilen + silen + chlen)
994 goto not_ssl;
995
996 /* focus on the remaining data length */
997 msg_len = cilen + silen + chlen + plen;
998 }
999 /* We could recursively check that the buffer ends exactly on an SSL
1000 * fragment boundary and that a possible next segment is still SSL,
1001 * but that's a bit pointless. However, we could still check that
1002 * all the part of the request which fits in a buffer is already
1003 * there.
1004 */
Willy Tarreau7c3c5412009-12-13 15:53:05 +01001005 if (msg_len > buffer_max_len(l4->req) + l4->req->data - l4->req->w)
1006 msg_len = buffer_max_len(l4->req) + l4->req->data - l4->req->w;
Willy Tarreau655e26a2008-07-15 18:58:05 +02001007
1008 if (bleft < msg_len)
1009 goto too_short;
1010
1011 /* OK that's enough. We have at least the whole message, and we have
1012 * the protocol version.
1013 */
1014 test->i = version;
1015 test->flags = ACL_TEST_F_VOLATILE;
1016 return 1;
1017
1018 too_short:
1019 test->flags = ACL_TEST_F_MAY_CHANGE;
1020 not_ssl:
1021 return 0;
1022}
1023
Emeric Brunbede3d02009-06-30 17:54:00 +02001024int
1025acl_fetch_rdp_cookie(struct proxy *px, struct session *l4, void *l7, int dir,
1026 struct acl_expr *expr, struct acl_test *test)
1027{
1028 int bleft;
1029 const unsigned char *data;
1030
1031 if (!l4 || !l4->req)
1032 return 0;
1033
1034 test->flags = 0;
1035
1036 bleft = l4->req->l;
1037 if (bleft <= 11)
1038 goto too_short;
1039
1040 data = (const unsigned char *)l4->req->w + 11;
1041 bleft -= 11;
1042
1043 if (bleft <= 7)
1044 goto too_short;
1045
1046 if (strncasecmp((const char *)data, "Cookie:", 7) != 0)
1047 goto not_cookie;
1048
1049 data += 7;
1050 bleft -= 7;
1051
1052 while (bleft > 0 && *data == ' ') {
1053 data++;
1054 bleft--;
1055 }
1056
1057 if (expr->arg_len) {
1058
1059 if (bleft <= expr->arg_len)
1060 goto too_short;
1061
1062 if ((data[expr->arg_len] != '=') ||
1063 strncasecmp(expr->arg.str, (const char *)data, expr->arg_len) != 0)
1064 goto not_cookie;
1065
1066 data += expr->arg_len + 1;
1067 bleft -= expr->arg_len + 1;
1068 } else {
1069 while (bleft > 0 && *data != '=') {
1070 if (*data == '\r' || *data == '\n')
1071 goto not_cookie;
1072 data++;
1073 bleft--;
1074 }
1075
1076 if (bleft < 1)
1077 goto too_short;
1078
1079 if (*data != '=')
1080 goto not_cookie;
1081
1082 data++;
1083 bleft--;
1084 }
1085
1086 /* data points to cookie value */
1087 test->ptr = (char *)data;
1088 test->len = 0;
1089
1090 while (bleft > 0 && *data != '\r') {
1091 data++;
1092 bleft--;
1093 }
1094
1095 if (bleft < 2)
1096 goto too_short;
1097
1098 if (data[0] != '\r' || data[1] != '\n')
1099 goto not_cookie;
1100
1101 test->len = (char *)data - test->ptr;
1102 test->flags = ACL_TEST_F_VOLATILE;
1103 return 1;
1104
1105 too_short:
1106 test->flags = ACL_TEST_F_MAY_CHANGE;
1107 not_cookie:
1108 return 0;
1109}
1110
1111static int
1112acl_fetch_rdp_cookie_cnt(struct proxy *px, struct session *l4, void *l7, int dir,
1113 struct acl_expr *expr, struct acl_test *test)
1114{
1115 int ret;
1116
1117 ret = acl_fetch_rdp_cookie(px, l4, l7, dir, expr, test);
1118
1119 test->ptr = NULL;
1120 test->len = 0;
1121
1122 if (test->flags & ACL_TEST_F_MAY_CHANGE)
1123 return 0;
1124
1125 test->flags = ACL_TEST_F_VOLATILE;
1126 test->i = ret;
1127
1128 return 1;
1129}
Willy Tarreaub6866442008-07-14 23:54:42 +02001130
1131static struct cfg_kw_list cfg_kws = {{ },{
1132 { CFG_LISTEN, "tcp-request", tcp_parse_tcp_req },
1133 { 0, NULL, NULL },
1134}};
1135
1136static struct acl_kw_list acl_kws = {{ },{
Willy Tarreau0ceba5a2008-07-25 19:31:03 +02001137 { "req_len", acl_parse_int, acl_fetch_req_len, acl_match_int, ACL_USE_L4REQ_VOLATILE },
1138 { "req_ssl_ver", acl_parse_dotted_ver, acl_fetch_req_ssl_ver, acl_match_int, ACL_USE_L4REQ_VOLATILE },
Emeric Brunbede3d02009-06-30 17:54:00 +02001139 { "req_rdp_cookie", acl_parse_str, acl_fetch_rdp_cookie, acl_match_str, ACL_USE_L4REQ_VOLATILE },
1140 { "req_rdp_cookie_cnt", acl_parse_int, acl_fetch_rdp_cookie_cnt, acl_match_int, ACL_USE_L4REQ_VOLATILE },
Willy Tarreaub6866442008-07-14 23:54:42 +02001141 { NULL, NULL, NULL, NULL },
1142}};
1143
Willy Tarreaue6b98942007-10-29 01:09:36 +01001144__attribute__((constructor))
1145static void __tcp_protocol_init(void)
1146{
1147 protocol_register(&proto_tcpv4);
1148 protocol_register(&proto_tcpv6);
Willy Tarreaub6866442008-07-14 23:54:42 +02001149 cfg_register_keywords(&cfg_kws);
1150 acl_register_keywords(&acl_kws);
Willy Tarreaue6b98942007-10-29 01:09:36 +01001151}
1152
1153
1154/*
1155 * Local variables:
1156 * c-indent-level: 8
1157 * c-basic-offset: 8
1158 * End:
1159 */