blob: 174d661db8f5c08c6e00eb38bc90b6705e617e44 [file] [log] [blame]
Willy Tarreaue6b98942007-10-29 01:09:36 +01001/*
2 * AF_INET/AF_INET6 SOCK_STREAM protocol layer (tcp)
3 *
Willy Tarreau1a687942010-05-23 22:40:30 +02004 * Copyright 2000-2010 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>
Willy Tarreaue6b98942007-10-29 01:09:36 +010034#include <common/mini-clist.h>
35#include <common/standard.h>
Willy Tarreaue6b98942007-10-29 01:09:36 +010036
Willy Tarreaue6b98942007-10-29 01:09:36 +010037#include <types/global.h>
Willy Tarreau9650f372009-08-16 14:02:45 +020038#include <types/server.h>
Willy Tarreaue6b98942007-10-29 01:09:36 +010039
40#include <proto/acl.h>
Willy Tarreaue6b98942007-10-29 01:09:36 +010041#include <proto/buffers.h>
Willy Tarreau03fa5df2010-05-24 21:02:37 +020042#include <proto/frontend.h>
Willy Tarreau9650f372009-08-16 14:02:45 +020043#include <proto/log.h>
Willy Tarreau645513a2010-05-24 20:55:15 +020044#include <proto/pattern.h>
Willy Tarreau9650f372009-08-16 14:02:45 +020045#include <proto/port_range.h>
Willy Tarreaue6b98942007-10-29 01:09:36 +010046#include <proto/protocols.h>
47#include <proto/proto_tcp.h>
Willy Tarreaub6866442008-07-14 23:54:42 +020048#include <proto/proxy.h>
Willy Tarreau9ba2dcc2010-06-14 21:04:55 +020049#include <proto/session.h>
Willy Tarreaua975b8f2010-06-05 19:13:27 +020050#include <proto/stick_table.h>
Willy Tarreaue6b98942007-10-29 01:09:36 +010051#include <proto/stream_sock.h>
Willy Tarreaua975b8f2010-06-05 19:13:27 +020052#include <proto/task.h>
Emeric Brun97679e72010-09-23 17:56:44 +020053#include <proto/buffers.h>
Willy Tarreaue6b98942007-10-29 01:09:36 +010054
Willy Tarreaue8c66af2008-01-13 18:40:14 +010055#ifdef CONFIG_HAP_CTTPROXY
56#include <import/ip_tproxy.h>
57#endif
58
Emeric Bruncf20bf12010-10-22 16:06:11 +020059static int tcp_bind_listeners(struct protocol *proto, char *errmsg, int errlen);
60static int tcp_bind_listener(struct listener *listener, char *errmsg, int errlen);
Willy Tarreaue6b98942007-10-29 01:09:36 +010061
62/* Note: must not be declared <const> as its list will be overwritten */
63static struct protocol proto_tcpv4 = {
64 .name = "tcpv4",
65 .sock_domain = AF_INET,
66 .sock_type = SOCK_STREAM,
67 .sock_prot = IPPROTO_TCP,
68 .sock_family = AF_INET,
69 .sock_addrlen = sizeof(struct sockaddr_in),
70 .l3_addrlen = 32/8,
Willy Tarreaueb472682010-05-28 18:46:57 +020071 .accept = &stream_sock_accept,
Willy Tarreaue6b98942007-10-29 01:09:36 +010072 .read = &stream_sock_read,
73 .write = &stream_sock_write,
Emeric Bruncf20bf12010-10-22 16:06:11 +020074 .bind = tcp_bind_listener,
Willy Tarreaue6b98942007-10-29 01:09:36 +010075 .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,
Willy Tarreaueb472682010-05-28 18:46:57 +020091 .accept = &stream_sock_accept,
Willy Tarreaue6b98942007-10-29 01:09:36 +010092 .read = &stream_sock_read,
93 .write = &stream_sock_write,
Emeric Bruncf20bf12010-10-22 16:06:11 +020094 .bind = tcp_bind_listener,
Willy Tarreaue6b98942007-10-29 01:09:36 +010095 .bind_all = tcp_bind_listeners,
96 .unbind_all = unbind_all_listeners,
97 .enable_all = enable_all_listeners,
98 .listeners = LIST_HEAD_INIT(proto_tcpv6.listeners),
99 .nb_listeners = 0,
100};
101
Willy Tarreaue8c66af2008-01-13 18:40:14 +0100102
103/* Binds ipv4 address <local> to socket <fd>, unless <flags> is set, in which
104 * case we try to bind <remote>. <flags> is a 2-bit field consisting of :
105 * - 0 : ignore remote address (may even be a NULL pointer)
106 * - 1 : use provided address
107 * - 2 : use provided port
108 * - 3 : use both
109 *
110 * The function supports multiple foreign binding methods :
111 * - linux_tproxy: we directly bind to the foreign address
112 * - cttproxy: we bind to a local address then nat.
113 * The second one can be used as a fallback for the first one.
114 * This function returns 0 when everything's OK, 1 if it could not bind, to the
115 * local address, 2 if it could not bind to the foreign address.
116 */
117int tcpv4_bind_socket(int fd, int flags, struct sockaddr_in *local, struct sockaddr_in *remote)
118{
119 struct sockaddr_in bind_addr;
120 int foreign_ok = 0;
121 int ret;
122
123#ifdef CONFIG_HAP_LINUX_TPROXY
124 static int ip_transp_working = 1;
125 if (flags && ip_transp_working) {
126 if (setsockopt(fd, SOL_IP, IP_TRANSPARENT, (char *) &one, sizeof(one)) == 0
127 || setsockopt(fd, SOL_IP, IP_FREEBIND, (char *) &one, sizeof(one)) == 0)
128 foreign_ok = 1;
129 else
130 ip_transp_working = 0;
131 }
132#endif
133 if (flags) {
134 memset(&bind_addr, 0, sizeof(bind_addr));
135 if (flags & 1)
136 bind_addr.sin_addr = remote->sin_addr;
137 if (flags & 2)
138 bind_addr.sin_port = remote->sin_port;
139 }
140
141 setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (char *) &one, sizeof(one));
142 if (foreign_ok) {
143 ret = bind(fd, (struct sockaddr *)&bind_addr, sizeof(bind_addr));
144 if (ret < 0)
145 return 2;
146 }
147 else {
148 ret = bind(fd, (struct sockaddr *)local, sizeof(*local));
149 if (ret < 0)
150 return 1;
151 }
152
153 if (!flags)
154 return 0;
155
156#ifdef CONFIG_HAP_CTTPROXY
157 if (!foreign_ok) {
158 struct in_tproxy itp1, itp2;
159 memset(&itp1, 0, sizeof(itp1));
160
161 itp1.op = TPROXY_ASSIGN;
162 itp1.v.addr.faddr = bind_addr.sin_addr;
163 itp1.v.addr.fport = bind_addr.sin_port;
164
165 /* set connect flag on socket */
166 itp2.op = TPROXY_FLAGS;
167 itp2.v.flags = ITP_CONNECT | ITP_ONCE;
168
169 if (setsockopt(fd, SOL_IP, IP_TPROXY, &itp1, sizeof(itp1)) != -1 &&
170 setsockopt(fd, SOL_IP, IP_TPROXY, &itp2, sizeof(itp2)) != -1) {
171 foreign_ok = 1;
172 }
173 }
174#endif
175 if (!foreign_ok)
176 /* we could not bind to a foreign address */
177 return 2;
178
179 return 0;
180}
Willy Tarreaue6b98942007-10-29 01:09:36 +0100181
Willy Tarreau9650f372009-08-16 14:02:45 +0200182
183/*
184 * This function initiates a connection to the server assigned to this session
Willy Tarreauf1536862011-03-03 18:27:32 +0100185 * (s->srv, si->addr.s.to). A source address may be pointed to by si->addr.s.from.
186 * Note that this is only used in case of transparent proxying. Normal source bind
187 * addresses are still determined locally (due to the possible need of a source port).
Willy Tarreaub1d67742010-03-29 19:36:59 +0200188 *
Willy Tarreau9650f372009-08-16 14:02:45 +0200189 * It can return one of :
190 * - SN_ERR_NONE if everything's OK
191 * - SN_ERR_SRVTO if there are no more servers
192 * - SN_ERR_SRVCL if the connection was refused by the server
193 * - SN_ERR_PRXCOND if the connection has been limited by the proxy (maxconn)
194 * - SN_ERR_RESOURCE if a system resource is lacking (eg: fd limits, ports, ...)
195 * - SN_ERR_INTERNAL for any other purely internal errors
196 * Additionnally, in the case of SN_ERR_RESOURCE, an emergency log will be emitted.
197 */
Willy Tarreauf1536862011-03-03 18:27:32 +0100198
199int tcpv4_connect_server(struct stream_interface *si, struct proxy *be, struct server *srv)
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 Tarreau090466c2009-09-07 11:51:47 +0200257 case SRV_TPROXY_DYN:
Willy Tarreaub1d67742010-03-29 19:36:59 +0200258 flags = 1;
Willy Tarreau9650f372009-08-16 14:02:45 +0200259 break;
260 }
Willy Tarreaub1d67742010-03-29 19:36:59 +0200261
Willy Tarreau9650f372009-08-16 14:02:45 +0200262#ifdef SO_BINDTODEVICE
263 /* Note: this might fail if not CAP_NET_RAW */
264 if (srv->iface_name)
265 setsockopt(fd, SOL_SOCKET, SO_BINDTODEVICE, srv->iface_name, srv->iface_len + 1);
266#endif
267
268 if (srv->sport_range) {
269 int attempts = 10; /* should be more than enough to find a spare port */
270 struct sockaddr_in src;
271
272 ret = 1;
273 src = srv->source_addr;
274
275 do {
276 /* note: in case of retry, we may have to release a previously
277 * allocated port, hence this loop's construct.
278 */
Willy Tarreau8d5d77e2009-10-18 07:25:52 +0200279 port_range_release_port(fdinfo[fd].port_range, fdinfo[fd].local_port);
280 fdinfo[fd].port_range = NULL;
Willy Tarreau9650f372009-08-16 14:02:45 +0200281
282 if (!attempts)
283 break;
284 attempts--;
285
Willy Tarreau8d5d77e2009-10-18 07:25:52 +0200286 fdinfo[fd].local_port = port_range_alloc_port(srv->sport_range);
287 if (!fdinfo[fd].local_port)
Willy Tarreau9650f372009-08-16 14:02:45 +0200288 break;
289
Willy Tarreau8d5d77e2009-10-18 07:25:52 +0200290 fdinfo[fd].port_range = srv->sport_range;
291 src.sin_port = htons(fdinfo[fd].local_port);
Willy Tarreau9650f372009-08-16 14:02:45 +0200292
Willy Tarreauf1536862011-03-03 18:27:32 +0100293 ret = tcpv4_bind_socket(fd, flags, &src, (struct sockaddr_in *)&si->addr.s.from);
Willy Tarreau9650f372009-08-16 14:02:45 +0200294 } while (ret != 0); /* binding NOK */
295 }
296 else {
Willy Tarreauf1536862011-03-03 18:27:32 +0100297 ret = tcpv4_bind_socket(fd, flags, &srv->source_addr, (struct sockaddr_in *)&si->addr.s.from);
Willy Tarreau9650f372009-08-16 14:02:45 +0200298 }
299
300 if (ret) {
Willy Tarreau8d5d77e2009-10-18 07:25:52 +0200301 port_range_release_port(fdinfo[fd].port_range, fdinfo[fd].local_port);
302 fdinfo[fd].port_range = NULL;
Willy Tarreau9650f372009-08-16 14:02:45 +0200303 close(fd);
304
305 if (ret == 1) {
306 Alert("Cannot bind to source address before connect() for server %s/%s. Aborting.\n",
307 be->id, srv->id);
308 send_log(be, LOG_EMERG,
309 "Cannot bind to source address before connect() for server %s/%s.\n",
310 be->id, srv->id);
311 } else {
312 Alert("Cannot bind to tproxy source address before connect() for server %s/%s. Aborting.\n",
313 be->id, srv->id);
314 send_log(be, LOG_EMERG,
315 "Cannot bind to tproxy source address before connect() for server %s/%s.\n",
316 be->id, srv->id);
317 }
318 return SN_ERR_RESOURCE;
319 }
320 }
321 else if (be->options & PR_O_BIND_SRC) {
Willy Tarreau9650f372009-08-16 14:02:45 +0200322 int ret, flags = 0;
323
Willy Tarreau9650f372009-08-16 14:02:45 +0200324 switch (be->options & PR_O_TPXY_MASK) {
325 case PR_O_TPXY_ADDR:
Willy Tarreau9650f372009-08-16 14:02:45 +0200326 case PR_O_TPXY_CLI:
Willy Tarreaub1d67742010-03-29 19:36:59 +0200327 flags = 3;
328 break;
Willy Tarreau9650f372009-08-16 14:02:45 +0200329 case PR_O_TPXY_CIP:
Willy Tarreau090466c2009-09-07 11:51:47 +0200330 case PR_O_TPXY_DYN:
Willy Tarreaub1d67742010-03-29 19:36:59 +0200331 flags = 1;
Willy Tarreau9650f372009-08-16 14:02:45 +0200332 break;
333 }
Willy Tarreaub1d67742010-03-29 19:36:59 +0200334
Willy Tarreau9650f372009-08-16 14:02:45 +0200335#ifdef SO_BINDTODEVICE
336 /* Note: this might fail if not CAP_NET_RAW */
337 if (be->iface_name)
338 setsockopt(fd, SOL_SOCKET, SO_BINDTODEVICE, be->iface_name, be->iface_len + 1);
339#endif
Willy Tarreauf1536862011-03-03 18:27:32 +0100340 ret = tcpv4_bind_socket(fd, flags, &be->source_addr, (struct sockaddr_in *)&si->addr.s.from);
Willy Tarreau9650f372009-08-16 14:02:45 +0200341 if (ret) {
342 close(fd);
343 if (ret == 1) {
344 Alert("Cannot bind to source address before connect() for proxy %s. Aborting.\n",
345 be->id);
346 send_log(be, LOG_EMERG,
347 "Cannot bind to source address before connect() for proxy %s.\n",
348 be->id);
349 } else {
350 Alert("Cannot bind to tproxy source address before connect() for proxy %s. Aborting.\n",
351 be->id);
352 send_log(be, LOG_EMERG,
353 "Cannot bind to tproxy source address before connect() for proxy %s.\n",
354 be->id);
355 }
356 return SN_ERR_RESOURCE;
357 }
358 }
359
Dmitry Sivachenkocaf58982009-08-24 15:11:06 +0400360#if defined(TCP_QUICKACK)
Willy Tarreau9650f372009-08-16 14:02:45 +0200361 /* disabling tcp quick ack now allows the first request to leave the
362 * machine with the first ACK. We only do this if there are pending
363 * data in the buffer.
364 */
365 if ((be->options2 & PR_O2_SMARTCON) && si->ob->send_max)
Dmitry Sivachenkocaf58982009-08-24 15:11:06 +0400366 setsockopt(fd, IPPROTO_TCP, TCP_QUICKACK, (char *) &zero, sizeof(zero));
Willy Tarreau9650f372009-08-16 14:02:45 +0200367#endif
368
Willy Tarreaue803de22010-01-21 17:43:04 +0100369 if (global.tune.server_sndbuf)
370 setsockopt(fd, SOL_SOCKET, SO_SNDBUF, &global.tune.server_sndbuf, sizeof(global.tune.server_sndbuf));
371
372 if (global.tune.server_rcvbuf)
373 setsockopt(fd, SOL_SOCKET, SO_RCVBUF, &global.tune.server_rcvbuf, sizeof(global.tune.server_rcvbuf));
374
Willy Tarreauf1536862011-03-03 18:27:32 +0100375 if ((connect(fd, (struct sockaddr *)&si->addr.s.to, sizeof(struct sockaddr_in)) == -1) &&
Willy Tarreau9650f372009-08-16 14:02:45 +0200376 (errno != EINPROGRESS) && (errno != EALREADY) && (errno != EISCONN)) {
377
378 if (errno == EAGAIN || errno == EADDRINUSE) {
379 char *msg;
380 if (errno == EAGAIN) /* no free ports left, try again later */
381 msg = "no free ports";
382 else
383 msg = "local address already in use";
384
385 qfprintf(stderr,"Cannot connect: %s.\n",msg);
Willy Tarreau8d5d77e2009-10-18 07:25:52 +0200386 port_range_release_port(fdinfo[fd].port_range, fdinfo[fd].local_port);
387 fdinfo[fd].port_range = NULL;
Willy Tarreau9650f372009-08-16 14:02:45 +0200388 close(fd);
389 send_log(be, LOG_EMERG,
390 "Connect() failed for server %s/%s: %s.\n",
391 be->id, srv->id, msg);
392 return SN_ERR_RESOURCE;
393 } else if (errno == ETIMEDOUT) {
394 //qfprintf(stderr,"Connect(): ETIMEDOUT");
Willy Tarreau8d5d77e2009-10-18 07:25:52 +0200395 port_range_release_port(fdinfo[fd].port_range, fdinfo[fd].local_port);
396 fdinfo[fd].port_range = NULL;
Willy Tarreau9650f372009-08-16 14:02:45 +0200397 close(fd);
398 return SN_ERR_SRVTO;
399 } else {
400 // (errno == ECONNREFUSED || errno == ENETUNREACH || errno == EACCES || errno == EPERM)
401 //qfprintf(stderr,"Connect(): %d", errno);
Willy Tarreau8d5d77e2009-10-18 07:25:52 +0200402 port_range_release_port(fdinfo[fd].port_range, fdinfo[fd].local_port);
403 fdinfo[fd].port_range = NULL;
Willy Tarreau9650f372009-08-16 14:02:45 +0200404 close(fd);
405 return SN_ERR_SRVCL;
406 }
407 }
408
409 fdtab[fd].owner = si;
410 fdtab[fd].state = FD_STCONN; /* connection in progress */
411 fdtab[fd].flags = FD_FL_TCP | FD_FL_TCP_NODELAY;
412 fdtab[fd].cb[DIR_RD].f = &stream_sock_read;
413 fdtab[fd].cb[DIR_RD].b = si->ib;
414 fdtab[fd].cb[DIR_WR].f = &stream_sock_write;
415 fdtab[fd].cb[DIR_WR].b = si->ob;
416
Willy Tarreauf1536862011-03-03 18:27:32 +0100417 fdinfo[fd].peeraddr = (struct sockaddr *)&si->addr.s.to;
Willy Tarreau8d5d77e2009-10-18 07:25:52 +0200418 fdinfo[fd].peerlen = sizeof(struct sockaddr_in);
Willy Tarreau9650f372009-08-16 14:02:45 +0200419
420 fd_insert(fd);
421 EV_FD_SET(fd, DIR_WR); /* for connect status */
422
423 si->state = SI_ST_CON;
424 si->flags |= SI_FL_CAP_SPLTCP; /* TCP supports splicing */
425 si->exp = tick_add_ifset(now_ms, be->timeout.connect);
426
427 return SN_ERR_NONE; /* connection is OK */
428}
429
430
Willy Tarreaue6b98942007-10-29 01:09:36 +0100431/* This function tries to bind a TCPv4/v6 listener. It may return a warning or
432 * an error message in <err> if the message is at most <errlen> bytes long
433 * (including '\0'). The return value is composed from ERR_ABORT, ERR_WARN,
434 * ERR_ALERT, ERR_RETRYABLE and ERR_FATAL. ERR_NONE indicates that everything
435 * was alright and that no message was returned. ERR_RETRYABLE means that an
436 * error occurred but that it may vanish after a retry (eg: port in use), and
437 * ERR_FATAL indicates a non-fixable error.ERR_WARN and ERR_ALERT do not alter
438 * the meaning of the error, but just indicate that a message is present which
439 * should be displayed with the respective level. Last, ERR_ABORT indicates
440 * that it's pointless to try to start other listeners. No error message is
441 * returned if errlen is NULL.
442 */
443int tcp_bind_listener(struct listener *listener, char *errmsg, int errlen)
444{
445 __label__ tcp_return, tcp_close_return;
446 int fd, err;
447 const char *msg = NULL;
448
449 /* ensure we never return garbage */
450 if (errmsg && errlen)
451 *errmsg = 0;
452
453 if (listener->state != LI_ASSIGNED)
454 return ERR_NONE; /* already bound */
455
456 err = ERR_NONE;
457
458 if ((fd = socket(listener->addr.ss_family, SOCK_STREAM, IPPROTO_TCP)) == -1) {
459 err |= ERR_RETRYABLE | ERR_ALERT;
460 msg = "cannot create listening socket";
461 goto tcp_return;
462 }
Willy Tarreauedcf6682008-11-30 23:15:34 +0100463
Willy Tarreaue6b98942007-10-29 01:09:36 +0100464 if (fd >= global.maxsock) {
465 err |= ERR_FATAL | ERR_ABORT | ERR_ALERT;
466 msg = "not enough free sockets (raise '-n' parameter)";
467 goto tcp_close_return;
468 }
469
Willy Tarreaufb14edc2009-06-14 15:24:37 +0200470 if (fcntl(fd, F_SETFL, O_NONBLOCK) == -1) {
Willy Tarreaue6b98942007-10-29 01:09:36 +0100471 err |= ERR_FATAL | ERR_ALERT;
472 msg = "cannot make socket non-blocking";
473 goto tcp_close_return;
474 }
475
476 if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (char *) &one, sizeof(one)) == -1) {
477 /* not fatal but should be reported */
478 msg = "cannot do so_reuseaddr";
479 err |= ERR_ALERT;
480 }
481
482 if (listener->options & LI_O_NOLINGER)
483 setsockopt(fd, SOL_SOCKET, SO_LINGER, (struct linger *) &nolinger, sizeof(struct linger));
Willy Tarreauedcf6682008-11-30 23:15:34 +0100484
Willy Tarreaue6b98942007-10-29 01:09:36 +0100485#ifdef SO_REUSEPORT
486 /* OpenBSD supports this. As it's present in old libc versions of Linux,
487 * it might return an error that we will silently ignore.
488 */
489 setsockopt(fd, SOL_SOCKET, SO_REUSEPORT, (char *) &one, sizeof(one));
490#endif
Willy Tarreaub1e52e82008-01-13 14:49:51 +0100491#ifdef CONFIG_HAP_LINUX_TPROXY
Willy Tarreauedcf6682008-11-30 23:15:34 +0100492 if ((listener->options & LI_O_FOREIGN)
Willy Tarreau0a459892008-01-13 17:37:16 +0100493 && (setsockopt(fd, SOL_IP, IP_TRANSPARENT, (char *) &one, sizeof(one)) == -1)
494 && (setsockopt(fd, SOL_IP, IP_FREEBIND, (char *) &one, sizeof(one)) == -1)) {
Willy Tarreaub1e52e82008-01-13 14:49:51 +0100495 msg = "cannot make listening socket transparent";
496 err |= ERR_ALERT;
497 }
498#endif
Willy Tarreau5e6e2042009-02-04 17:19:29 +0100499#ifdef SO_BINDTODEVICE
500 /* Note: this might fail if not CAP_NET_RAW */
501 if (listener->interface) {
502 if (setsockopt(fd, SOL_SOCKET, SO_BINDTODEVICE,
Willy Tarreau604e8302009-03-06 00:48:23 +0100503 listener->interface, strlen(listener->interface) + 1) == -1) {
Willy Tarreau5e6e2042009-02-04 17:19:29 +0100504 msg = "cannot bind listener to device";
505 err |= ERR_WARN;
506 }
507 }
508#endif
Dmitry Sivachenkocaf58982009-08-24 15:11:06 +0400509#if defined(TCP_MAXSEG)
Willy Tarreau48a7e722010-12-24 15:26:39 +0100510 if (listener->maxseg > 0) {
Dmitry Sivachenkocaf58982009-08-24 15:11:06 +0400511 if (setsockopt(fd, IPPROTO_TCP, TCP_MAXSEG,
Willy Tarreaube1b9182009-06-14 18:48:19 +0200512 &listener->maxseg, sizeof(listener->maxseg)) == -1) {
513 msg = "cannot set MSS";
514 err |= ERR_WARN;
515 }
516 }
517#endif
Willy Tarreaucb6cd432009-10-13 07:34:14 +0200518#if defined(TCP_DEFER_ACCEPT)
519 if (listener->options & LI_O_DEF_ACCEPT) {
520 /* defer accept by up to one second */
521 int accept_delay = 1;
522 if (setsockopt(fd, IPPROTO_TCP, TCP_DEFER_ACCEPT, &accept_delay, sizeof(accept_delay)) == -1) {
523 msg = "cannot enable DEFER_ACCEPT";
524 err |= ERR_WARN;
525 }
526 }
527#endif
Willy Tarreaue6b98942007-10-29 01:09:36 +0100528 if (bind(fd, (struct sockaddr *)&listener->addr, listener->proto->sock_addrlen) == -1) {
529 err |= ERR_RETRYABLE | ERR_ALERT;
530 msg = "cannot bind socket";
531 goto tcp_close_return;
532 }
Willy Tarreauedcf6682008-11-30 23:15:34 +0100533
Willy Tarreauc73ce2b2008-01-06 10:55:10 +0100534 if (listen(fd, listener->backlog ? listener->backlog : listener->maxconn) == -1) {
Willy Tarreaue6b98942007-10-29 01:09:36 +0100535 err |= ERR_RETRYABLE | ERR_ALERT;
536 msg = "cannot listen to socket";
537 goto tcp_close_return;
538 }
Willy Tarreauedcf6682008-11-30 23:15:34 +0100539
Dmitry Sivachenkocaf58982009-08-24 15:11:06 +0400540#if defined(TCP_QUICKACK)
Willy Tarreau9ea05a72009-06-14 12:07:01 +0200541 if (listener->options & LI_O_NOQUICKACK)
Dmitry Sivachenkocaf58982009-08-24 15:11:06 +0400542 setsockopt(fd, IPPROTO_TCP, TCP_QUICKACK, (char *) &zero, sizeof(zero));
Willy Tarreau9ea05a72009-06-14 12:07:01 +0200543#endif
544
Willy Tarreaue6b98942007-10-29 01:09:36 +0100545 /* the socket is ready */
546 listener->fd = fd;
547 listener->state = LI_LISTEN;
548
Willy Tarreaueabf3132008-08-29 23:36:51 +0200549 fdtab[fd].owner = listener; /* reference the listener instead of a task */
Willy Tarreaue6b98942007-10-29 01:09:36 +0100550 fdtab[fd].state = FD_STLISTEN;
Willy Tarreaueb472682010-05-28 18:46:57 +0200551 fdtab[fd].flags = FD_FL_TCP | ((listener->options & LI_O_NOLINGER) ? FD_FL_TCP_NOLING : 0);
552 fdtab[fd].cb[DIR_RD].f = listener->proto->accept;
553 fdtab[fd].cb[DIR_WR].f = NULL; /* never called */
554 fdtab[fd].cb[DIR_RD].b = fdtab[fd].cb[DIR_WR].b = NULL;
Willy Tarreau5d707e12009-06-28 11:09:07 +0200555
Willy Tarreau8d5d77e2009-10-18 07:25:52 +0200556 fdinfo[fd].peeraddr = NULL;
557 fdinfo[fd].peerlen = 0;
Willy Tarreaueb472682010-05-28 18:46:57 +0200558 fd_insert(fd);
559
Willy Tarreaue6b98942007-10-29 01:09:36 +0100560 tcp_return:
Cyril Bonté43ba1b32010-11-01 19:26:01 +0100561 if (msg && errlen) {
562 char pn[INET6_ADDRSTRLEN];
563
564 if (listener->addr.ss_family == AF_INET) {
565 inet_ntop(AF_INET,
566 (const void *)&((struct sockaddr_in *)&listener->addr)->sin_addr,
567 pn, sizeof(pn));
568 snprintf(errmsg, errlen, "%s [%s:%d]", msg, pn, ntohs(((struct sockaddr_in *)&listener->addr)->sin_port));
569 }
570 else {
571 inet_ntop(AF_INET6,
572 (const void *)&((struct sockaddr_in6 *)(&listener->addr))->sin6_addr,
573 pn, sizeof(pn));
574 snprintf(errmsg, errlen, "%s [%s:%d]", msg, pn, ntohs(((struct sockaddr_in6 *)&listener->addr)->sin6_port));
575 }
576 }
Willy Tarreaue6b98942007-10-29 01:09:36 +0100577 return err;
578
579 tcp_close_return:
580 close(fd);
581 goto tcp_return;
582}
583
584/* This function creates all TCP sockets bound to the protocol entry <proto>.
585 * It is intended to be used as the protocol's bind_all() function.
586 * The sockets will be registered but not added to any fd_set, in order not to
587 * loose them across the fork(). A call to enable_all_listeners() is needed
588 * to complete initialization. The return value is composed from ERR_*.
589 */
Emeric Bruncf20bf12010-10-22 16:06:11 +0200590static int tcp_bind_listeners(struct protocol *proto, char *errmsg, int errlen)
Willy Tarreaue6b98942007-10-29 01:09:36 +0100591{
592 struct listener *listener;
593 int err = ERR_NONE;
594
595 list_for_each_entry(listener, &proto->listeners, proto_list) {
Emeric Bruncf20bf12010-10-22 16:06:11 +0200596 err |= tcp_bind_listener(listener, errmsg, errlen);
597 if (err & ERR_ABORT)
Willy Tarreaue6b98942007-10-29 01:09:36 +0100598 break;
599 }
600
601 return err;
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 tcpv4_add_listener(struct listener *listener)
609{
610 if (listener->state != LI_INIT)
611 return;
612 listener->state = LI_ASSIGNED;
613 listener->proto = &proto_tcpv4;
614 LIST_ADDQ(&proto_tcpv4.listeners, &listener->proto_list);
615 proto_tcpv4.nb_listeners++;
616}
617
618/* Add listener to the list of tcpv4 listeners. The listener's state
619 * is automatically updated from LI_INIT to LI_ASSIGNED. The number of
620 * listeners is updated. This is the function to use to add a new listener.
621 */
622void tcpv6_add_listener(struct listener *listener)
623{
624 if (listener->state != LI_INIT)
625 return;
626 listener->state = LI_ASSIGNED;
627 listener->proto = &proto_tcpv6;
628 LIST_ADDQ(&proto_tcpv6.listeners, &listener->proto_list);
629 proto_tcpv6.nb_listeners++;
630}
631
Willy Tarreauedcf6682008-11-30 23:15:34 +0100632/* This function performs the TCP request analysis on the current request. It
633 * returns 1 if the processing can continue on next analysers, or zero if it
634 * needs more data, encounters an error, or wants to immediately abort the
Willy Tarreaufb356202010-08-03 14:02:05 +0200635 * request. It relies on buffers flags, and updates s->req->analysers. The
636 * function may be called for frontend rules and backend rules. It only relies
637 * on the backend pointer so this works for both cases.
Willy Tarreauedcf6682008-11-30 23:15:34 +0100638 */
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;
Willy Tarreaud1f96522010-08-03 19:34:32 +0200642 struct stksess *ts;
643 struct stktable *t;
Willy Tarreauedcf6682008-11-30 23:15:34 +0100644 int partial;
645
646 DPRINTF(stderr,"[%u] %s: session=%p b=%p, exp(r,w)=%u,%u bf=%08x bl=%d analysers=%02x\n",
647 now_ms, __FUNCTION__,
648 s,
649 req,
650 req->rex, req->wex,
651 req->flags,
652 req->l,
653 req->analysers);
654
Willy Tarreauedcf6682008-11-30 23:15:34 +0100655 /* We don't know whether we have enough data, so must proceed
656 * this way :
657 * - iterate through all rules in their declaration order
658 * - if one rule returns MISS, it means the inspect delay is
659 * not over yet, then return immediately, otherwise consider
660 * it as a non-match.
661 * - if one rule returns OK, then return OK
662 * - if one rule returns KO, then return KO
663 */
664
Willy Tarreaub824b002010-09-29 16:36:16 +0200665 if (req->flags & (BF_SHUTR|BF_FULL) || !s->be->tcp_req.inspect_delay || tick_is_expired(req->analyse_exp, now_ms))
Willy Tarreauedcf6682008-11-30 23:15:34 +0100666 partial = 0;
667 else
668 partial = ACL_PARTIAL;
669
Willy Tarreaufb356202010-08-03 14:02:05 +0200670 list_for_each_entry(rule, &s->be->tcp_req.inspect_rules, list) {
Willy Tarreauedcf6682008-11-30 23:15:34 +0100671 int ret = ACL_PAT_PASS;
672
673 if (rule->cond) {
Willy Tarreaufb356202010-08-03 14:02:05 +0200674 ret = acl_exec_cond(rule->cond, s->be, s, &s->txn, ACL_DIR_REQ | partial);
Willy Tarreauedcf6682008-11-30 23:15:34 +0100675 if (ret == ACL_PAT_MISS) {
Willy Tarreau520d95e2009-09-19 21:04:57 +0200676 buffer_dont_connect(req);
Willy Tarreauedcf6682008-11-30 23:15:34 +0100677 /* just set the request timeout once at the beginning of the request */
Willy Tarreaufb356202010-08-03 14:02:05 +0200678 if (!tick_isset(req->analyse_exp) && s->be->tcp_req.inspect_delay)
679 req->analyse_exp = tick_add_ifset(now_ms, s->be->tcp_req.inspect_delay);
Willy Tarreauedcf6682008-11-30 23:15:34 +0100680 return 0;
681 }
682
683 ret = acl_pass(ret);
684 if (rule->cond->pol == ACL_COND_UNLESS)
685 ret = !ret;
686 }
687
688 if (ret) {
689 /* we have a matching rule. */
690 if (rule->action == TCP_ACT_REJECT) {
691 buffer_abort(req);
692 buffer_abort(s->rep);
693 req->analysers = 0;
Krzysztof Piotr Oledzkiaeebf9b2009-10-04 15:43:17 +0200694
Willy Tarreaufb356202010-08-03 14:02:05 +0200695 s->be->counters.denied_req++;
Krzysztof Piotr Oledzkiaeebf9b2009-10-04 15:43:17 +0200696 if (s->listener->counters)
Willy Tarreau23968d82010-05-23 23:50:44 +0200697 s->listener->counters->denied_req++;
Krzysztof Piotr Oledzkiaeebf9b2009-10-04 15:43:17 +0200698
Willy Tarreauedcf6682008-11-30 23:15:34 +0100699 if (!(s->flags & SN_ERR_MASK))
700 s->flags |= SN_ERR_PRXCOND;
701 if (!(s->flags & SN_FINST_MASK))
702 s->flags |= SN_FINST_R;
703 return 0;
704 }
Willy Tarreau56123282010-08-06 19:06:56 +0200705 else if (rule->action == TCP_ACT_TRK_SC1) {
706 if (!s->stkctr1_entry) {
707 /* only the first valid track-sc1 directive applies.
Willy Tarreaud1f96522010-08-03 19:34:32 +0200708 * Also, note that right now we can only track SRC so we
709 * don't check how to get the key, but later we may need
710 * to consider rule->act_prm->trk_ctr.type.
711 */
712 t = rule->act_prm.trk_ctr.table.t;
713 ts = stktable_get_entry(t, tcpv4_src_to_stktable_key(s));
Willy Tarreau0a4838c2010-08-06 20:11:05 +0200714 if (ts) {
Willy Tarreau56123282010-08-06 19:06:56 +0200715 session_track_stkctr1(s, t, ts);
Willy Tarreau0a4838c2010-08-06 20:11:05 +0200716 if (s->fe != s->be)
717 s->flags |= SN_BE_TRACK_SC1;
718 }
Willy Tarreaud1f96522010-08-03 19:34:32 +0200719 }
720 }
Willy Tarreau56123282010-08-06 19:06:56 +0200721 else if (rule->action == TCP_ACT_TRK_SC2) {
722 if (!s->stkctr2_entry) {
723 /* only the first valid track-sc2 directive applies.
Willy Tarreaud1f96522010-08-03 19:34:32 +0200724 * Also, note that right now we can only track SRC so we
725 * don't check how to get the key, but later we may need
726 * to consider rule->act_prm->trk_ctr.type.
727 */
728 t = rule->act_prm.trk_ctr.table.t;
729 ts = stktable_get_entry(t, tcpv4_src_to_stktable_key(s));
Willy Tarreau0a4838c2010-08-06 20:11:05 +0200730 if (ts) {
Willy Tarreau56123282010-08-06 19:06:56 +0200731 session_track_stkctr2(s, t, ts);
Willy Tarreau0a4838c2010-08-06 20:11:05 +0200732 if (s->fe != s->be)
733 s->flags |= SN_BE_TRACK_SC2;
734 }
Willy Tarreaud1f96522010-08-03 19:34:32 +0200735 }
736 }
737 else {
Willy Tarreauedcf6682008-11-30 23:15:34 +0100738 /* otherwise accept */
Willy Tarreaud1f96522010-08-03 19:34:32 +0200739 break;
740 }
Willy Tarreauedcf6682008-11-30 23:15:34 +0100741 }
742 }
743
744 /* if we get there, it means we have no rule which matches, or
745 * we have an explicit accept, so we apply the default accept.
746 */
Willy Tarreau3a816292009-07-07 10:55:49 +0200747 req->analysers &= ~an_bit;
Willy Tarreauedcf6682008-11-30 23:15:34 +0100748 req->analyse_exp = TICK_ETERNITY;
749 return 1;
750}
751
Emeric Brun97679e72010-09-23 17:56:44 +0200752/* This function performs the TCP response analysis on the current response. It
753 * returns 1 if the processing can continue on next analysers, or zero if it
754 * needs more data, encounters an error, or wants to immediately abort the
755 * response. It relies on buffers flags, and updates s->rep->analysers. The
756 * function may be called for backend rules.
757 */
758int tcp_inspect_response(struct session *s, struct buffer *rep, int an_bit)
759{
760 struct tcp_rule *rule;
761 int partial;
762
763 DPRINTF(stderr,"[%u] %s: session=%p b=%p, exp(r,w)=%u,%u bf=%08x bl=%d analysers=%02x\n",
764 now_ms, __FUNCTION__,
765 s,
766 rep,
767 rep->rex, rep->wex,
768 rep->flags,
769 rep->l,
770 rep->analysers);
771
772 /* We don't know whether we have enough data, so must proceed
773 * this way :
774 * - iterate through all rules in their declaration order
775 * - if one rule returns MISS, it means the inspect delay is
776 * not over yet, then return immediately, otherwise consider
777 * it as a non-match.
778 * - if one rule returns OK, then return OK
779 * - if one rule returns KO, then return KO
780 */
781
782 if (rep->flags & BF_SHUTR || tick_is_expired(rep->analyse_exp, now_ms))
783 partial = 0;
784 else
785 partial = ACL_PARTIAL;
786
787 list_for_each_entry(rule, &s->be->tcp_rep.inspect_rules, list) {
788 int ret = ACL_PAT_PASS;
789
790 if (rule->cond) {
791 ret = acl_exec_cond(rule->cond, s->be, s, &s->txn, ACL_DIR_RTR | partial);
792 if (ret == ACL_PAT_MISS) {
793 /* just set the analyser timeout once at the beginning of the response */
794 if (!tick_isset(rep->analyse_exp) && s->be->tcp_rep.inspect_delay)
795 rep->analyse_exp = tick_add_ifset(now_ms, s->be->tcp_rep.inspect_delay);
796 return 0;
797 }
798
799 ret = acl_pass(ret);
800 if (rule->cond->pol == ACL_COND_UNLESS)
801 ret = !ret;
802 }
803
804 if (ret) {
805 /* we have a matching rule. */
806 if (rule->action == TCP_ACT_REJECT) {
807 buffer_abort(rep);
808 buffer_abort(s->req);
809 rep->analysers = 0;
810
811 s->be->counters.denied_resp++;
812 if (s->listener->counters)
813 s->listener->counters->denied_resp++;
814
815 if (!(s->flags & SN_ERR_MASK))
816 s->flags |= SN_ERR_PRXCOND;
817 if (!(s->flags & SN_FINST_MASK))
818 s->flags |= SN_FINST_D;
819 return 0;
820 }
821 else {
822 /* otherwise accept */
823 break;
824 }
825 }
826 }
827
828 /* if we get there, it means we have no rule which matches, or
829 * we have an explicit accept, so we apply the default accept.
830 */
831 rep->analysers &= ~an_bit;
832 rep->analyse_exp = TICK_ETERNITY;
833 return 1;
834}
835
836
Willy Tarreaua5c0ab22010-05-31 10:30:33 +0200837/* This function performs the TCP layer4 analysis on the current request. It
838 * returns 0 if a reject rule matches, otherwise 1 if either an accept rule
839 * matches or if no more rule matches. It can only use rules which don't need
840 * any data.
841 */
842int tcp_exec_req_rules(struct session *s)
843{
844 struct tcp_rule *rule;
Willy Tarreauf059a0f2010-08-03 16:29:52 +0200845 struct stksess *ts;
Willy Tarreau9ba2dcc2010-06-14 21:04:55 +0200846 struct stktable *t = NULL;
847 int result = 1;
Willy Tarreaua5c0ab22010-05-31 10:30:33 +0200848 int ret;
849
850 list_for_each_entry(rule, &s->fe->tcp_req.l4_rules, list) {
851 ret = ACL_PAT_PASS;
852
853 if (rule->cond) {
854 ret = acl_exec_cond(rule->cond, s->fe, s, NULL, ACL_DIR_REQ);
855 ret = acl_pass(ret);
856 if (rule->cond->pol == ACL_COND_UNLESS)
857 ret = !ret;
858 }
859
860 if (ret) {
861 /* we have a matching rule. */
862 if (rule->action == TCP_ACT_REJECT) {
Willy Tarreau2799e982010-06-05 15:43:21 +0200863 s->fe->counters.denied_conn++;
Willy Tarreaua5c0ab22010-05-31 10:30:33 +0200864 if (s->listener->counters)
Willy Tarreau2799e982010-06-05 15:43:21 +0200865 s->listener->counters->denied_conn++;
Willy Tarreaua5c0ab22010-05-31 10:30:33 +0200866
867 if (!(s->flags & SN_ERR_MASK))
868 s->flags |= SN_ERR_PRXCOND;
869 if (!(s->flags & SN_FINST_MASK))
870 s->flags |= SN_FINST_R;
Willy Tarreau9ba2dcc2010-06-14 21:04:55 +0200871 result = 0;
872 break;
Willy Tarreaua5c0ab22010-05-31 10:30:33 +0200873 }
Willy Tarreau56123282010-08-06 19:06:56 +0200874 else if (rule->action == TCP_ACT_TRK_SC1) {
875 if (!s->stkctr1_entry) {
876 /* only the first valid track-sc1 directive applies.
Willy Tarreau9ba2dcc2010-06-14 21:04:55 +0200877 * Also, note that right now we can only track SRC so we
878 * don't check how to get the key, but later we may need
879 * to consider rule->act_prm->trk_ctr.type.
880 */
881 t = rule->act_prm.trk_ctr.table.t;
882 ts = stktable_get_entry(t, tcpv4_src_to_stktable_key(s));
883 if (ts)
Willy Tarreau56123282010-08-06 19:06:56 +0200884 session_track_stkctr1(s, t, ts);
Willy Tarreau9ba2dcc2010-06-14 21:04:55 +0200885 }
886 }
Willy Tarreau56123282010-08-06 19:06:56 +0200887 else if (rule->action == TCP_ACT_TRK_SC2) {
888 if (!s->stkctr2_entry) {
889 /* only the first valid track-sc2 directive applies.
Willy Tarreauf059a0f2010-08-03 16:29:52 +0200890 * Also, note that right now we can only track SRC so we
891 * don't check how to get the key, but later we may need
892 * to consider rule->act_prm->trk_ctr.type.
893 */
894 t = rule->act_prm.trk_ctr.table.t;
895 ts = stktable_get_entry(t, tcpv4_src_to_stktable_key(s));
896 if (ts)
Willy Tarreau56123282010-08-06 19:06:56 +0200897 session_track_stkctr2(s, t, ts);
Willy Tarreauf059a0f2010-08-03 16:29:52 +0200898 }
899 }
Willy Tarreau9ba2dcc2010-06-14 21:04:55 +0200900 else {
901 /* otherwise it's an accept */
902 break;
903 }
Willy Tarreaua5c0ab22010-05-31 10:30:33 +0200904 }
905 }
Willy Tarreau9ba2dcc2010-06-14 21:04:55 +0200906 return result;
Willy Tarreaua5c0ab22010-05-31 10:30:33 +0200907}
908
Emeric Brun97679e72010-09-23 17:56:44 +0200909/* Parse a tcp-response rule. Return a negative value in case of failure */
910static int tcp_parse_response_rule(char **args, int arg, int section_type,
911 struct proxy *curpx, struct proxy *defpx,
912 struct tcp_rule *rule, char *err, int errlen)
913{
914 if (curpx == defpx || !(curpx->cap & PR_CAP_BE)) {
915 snprintf(err, errlen, "%s %s is only allowed in 'backend' sections",
916 args[0], args[1]);
917 return -1;
918 }
919
920 if (strcmp(args[arg], "accept") == 0) {
921 arg++;
922 rule->action = TCP_ACT_ACCEPT;
923 }
924 else if (strcmp(args[arg], "reject") == 0) {
925 arg++;
926 rule->action = TCP_ACT_REJECT;
927 }
928 else {
929 snprintf(err, errlen,
930 "'%s %s' expects 'accept' or 'reject' in %s '%s' (was '%s')",
931 args[0], args[1], proxy_type_str(curpx), curpx->id, args[arg]);
932 return -1;
933 }
934
935 if (strcmp(args[arg], "if") == 0 || strcmp(args[arg], "unless") == 0) {
936 if ((rule->cond = build_acl_cond(NULL, 0, curpx, (const char **)args+arg)) == NULL) {
937 snprintf(err, errlen,
938 "error detected in %s '%s' while parsing '%s' condition",
939 proxy_type_str(curpx), curpx->id, args[arg]);
940 return -1;
941 }
942 }
943 else if (*args[arg]) {
944 snprintf(err, errlen,
945 "'%s %s %s' only accepts 'if' or 'unless', in %s '%s' (was '%s')",
946 args[0], args[1], args[2], proxy_type_str(curpx), curpx->id, args[arg]);
947 return -1;
948 }
949 return 0;
950}
951
952
953
Willy Tarreau68c03ab2010-08-06 15:08:45 +0200954/* Parse a tcp-request rule. Return a negative value in case of failure */
955static int tcp_parse_request_rule(char **args, int arg, int section_type,
956 struct proxy *curpx, struct proxy *defpx,
957 struct tcp_rule *rule, char *err, int errlen)
958{
959 if (curpx == defpx) {
960 snprintf(err, errlen, "%s %s is not allowed in 'defaults' sections",
961 args[0], args[1]);
962 return -1;
963 }
964
965 if (!strcmp(args[arg], "accept")) {
966 arg++;
967 rule->action = TCP_ACT_ACCEPT;
968 }
969 else if (!strcmp(args[arg], "reject")) {
970 arg++;
971 rule->action = TCP_ACT_REJECT;
972 }
Willy Tarreau56123282010-08-06 19:06:56 +0200973 else if (strcmp(args[arg], "track-sc1") == 0) {
Willy Tarreau68c03ab2010-08-06 15:08:45 +0200974 int ret;
975
976 arg++;
977 ret = parse_track_counters(args, &arg, section_type, curpx,
978 &rule->act_prm.trk_ctr, defpx, err, errlen);
979
980 if (ret < 0) /* nb: warnings are not handled yet */
981 return -1;
982
Willy Tarreau56123282010-08-06 19:06:56 +0200983 rule->action = TCP_ACT_TRK_SC1;
Willy Tarreau68c03ab2010-08-06 15:08:45 +0200984 }
Willy Tarreau56123282010-08-06 19:06:56 +0200985 else if (strcmp(args[arg], "track-sc2") == 0) {
Willy Tarreau68c03ab2010-08-06 15:08:45 +0200986 int ret;
987
988 arg++;
989 ret = parse_track_counters(args, &arg, section_type, curpx,
990 &rule->act_prm.trk_ctr, defpx, err, errlen);
991
992 if (ret < 0) /* nb: warnings are not handled yet */
993 return -1;
994
Willy Tarreau56123282010-08-06 19:06:56 +0200995 rule->action = TCP_ACT_TRK_SC2;
Willy Tarreau68c03ab2010-08-06 15:08:45 +0200996 }
997 else {
998 snprintf(err, errlen,
Willy Tarreau56123282010-08-06 19:06:56 +0200999 "'%s %s' expects 'accept', 'reject', 'track-sc1' "
1000 "or 'track-sc2' in %s '%s' (was '%s')",
Willy Tarreau68c03ab2010-08-06 15:08:45 +02001001 args[0], args[1], proxy_type_str(curpx), curpx->id, args[arg]);
1002 return -1;
1003 }
1004
1005 if (strcmp(args[arg], "if") == 0 || strcmp(args[arg], "unless") == 0) {
1006 if ((rule->cond = build_acl_cond(NULL, 0, curpx, (const char **)args+arg)) == NULL) {
1007 snprintf(err, errlen,
1008 "error detected in %s '%s' while parsing '%s' condition",
1009 proxy_type_str(curpx), curpx->id, args[arg]);
1010 return -1;
1011 }
1012 }
1013 else if (*args[arg]) {
1014 snprintf(err, errlen,
1015 "'%s %s %s' only accepts 'if' or 'unless', in %s '%s' (was '%s')",
1016 args[0], args[1], args[2], proxy_type_str(curpx), curpx->id, args[arg]);
1017 return -1;
1018 }
1019 return 0;
1020}
1021
Emeric Brun97679e72010-09-23 17:56:44 +02001022/* This function should be called to parse a line starting with the "tcp-response"
1023 * keyword.
1024 */
1025static int tcp_parse_tcp_rep(char **args, int section_type, struct proxy *curpx,
1026 struct proxy *defpx, char *err, int errlen)
1027{
1028 const char *ptr = NULL;
1029 unsigned int val;
1030 int retlen;
1031 int warn = 0;
1032 int arg;
1033 struct tcp_rule *rule;
1034
1035 if (!*args[1]) {
1036 snprintf(err, errlen, "missing argument for '%s' in %s '%s'",
1037 args[0], proxy_type_str(curpx), curpx->id);
1038 return -1;
1039 }
1040
1041 if (strcmp(args[1], "inspect-delay") == 0) {
1042 if (curpx == defpx || !(curpx->cap & PR_CAP_BE)) {
1043 snprintf(err, errlen, "%s %s is only allowed in 'backend' sections",
1044 args[0], args[1]);
1045 return -1;
1046 }
1047
1048 if (!*args[2] || (ptr = parse_time_err(args[2], &val, TIME_UNIT_MS))) {
1049 retlen = snprintf(err, errlen,
1050 "'%s %s' expects a positive delay in milliseconds, in %s '%s'",
1051 args[0], args[1], proxy_type_str(curpx), curpx->id);
1052 if (ptr && retlen < errlen)
1053 retlen += snprintf(err + retlen, errlen - retlen,
1054 " (unexpected character '%c')", *ptr);
1055 return -1;
1056 }
1057
1058 if (curpx->tcp_rep.inspect_delay) {
1059 snprintf(err, errlen, "ignoring %s %s (was already defined) in %s '%s'",
1060 args[0], args[1], proxy_type_str(curpx), curpx->id);
1061 return 1;
1062 }
1063 curpx->tcp_rep.inspect_delay = val;
1064 return 0;
1065 }
1066
1067 rule = (struct tcp_rule *)calloc(1, sizeof(*rule));
1068 LIST_INIT(&rule->list);
1069 arg = 1;
1070
1071 if (strcmp(args[1], "content") == 0) {
1072 arg++;
1073 if (tcp_parse_response_rule(args, arg, section_type, curpx, defpx, rule, err, errlen) < 0)
1074 goto error;
1075
1076 if (rule->cond && (rule->cond->requires & ACL_USE_L6REQ_VOLATILE)) {
1077 struct acl *acl;
1078 const char *name;
1079
1080 acl = cond_find_require(rule->cond, ACL_USE_L6REQ_VOLATILE);
1081 name = acl ? acl->name : "(unknown)";
1082
1083 retlen = snprintf(err, errlen,
1084 "acl '%s' involves some request-only criteria which will be ignored.",
1085 name);
1086 warn++;
1087 }
1088
1089 LIST_ADDQ(&curpx->tcp_rep.inspect_rules, &rule->list);
1090 }
1091 else {
1092 retlen = snprintf(err, errlen,
1093 "'%s' expects 'inspect-delay' or 'content' in %s '%s' (was '%s')",
1094 args[0], proxy_type_str(curpx), curpx->id, args[1]);
1095 goto error;
1096 }
1097
1098 return warn;
1099 error:
1100 free(rule);
1101 return -1;
1102}
1103
1104
Willy Tarreaub6866442008-07-14 23:54:42 +02001105/* This function should be called to parse a line starting with the "tcp-request"
1106 * keyword.
1107 */
1108static int tcp_parse_tcp_req(char **args, int section_type, struct proxy *curpx,
1109 struct proxy *defpx, char *err, int errlen)
1110{
1111 const char *ptr = NULL;
Willy Tarreauc7e961e2008-08-17 17:13:47 +02001112 unsigned int val;
Willy Tarreaub6866442008-07-14 23:54:42 +02001113 int retlen;
Willy Tarreau1a687942010-05-23 22:40:30 +02001114 int warn = 0;
Willy Tarreau6a984fa2010-06-14 16:44:27 +02001115 int arg;
Willy Tarreau1a687942010-05-23 22:40:30 +02001116 struct tcp_rule *rule;
Willy Tarreaub6866442008-07-14 23:54:42 +02001117
1118 if (!*args[1]) {
1119 snprintf(err, errlen, "missing argument for '%s' in %s '%s'",
Willy Tarreauf5356832010-06-14 18:40:26 +02001120 args[0], proxy_type_str(curpx), curpx->id);
Willy Tarreaub6866442008-07-14 23:54:42 +02001121 return -1;
1122 }
1123
1124 if (!strcmp(args[1], "inspect-delay")) {
1125 if (curpx == defpx) {
1126 snprintf(err, errlen, "%s %s is not allowed in 'defaults' sections",
1127 args[0], args[1]);
1128 return -1;
1129 }
1130
Willy Tarreaub6866442008-07-14 23:54:42 +02001131 if (!*args[2] || (ptr = parse_time_err(args[2], &val, TIME_UNIT_MS))) {
1132 retlen = snprintf(err, errlen,
1133 "'%s %s' expects a positive delay in milliseconds, in %s '%s'",
Willy Tarreauf5356832010-06-14 18:40:26 +02001134 args[0], args[1], proxy_type_str(curpx), curpx->id);
Willy Tarreaub6866442008-07-14 23:54:42 +02001135 if (ptr && retlen < errlen)
1136 retlen += snprintf(err+retlen, errlen - retlen,
1137 " (unexpected character '%c')", *ptr);
1138 return -1;
1139 }
1140
1141 if (curpx->tcp_req.inspect_delay) {
1142 snprintf(err, errlen, "ignoring %s %s (was already defined) in %s '%s'",
Willy Tarreauf5356832010-06-14 18:40:26 +02001143 args[0], args[1], proxy_type_str(curpx), curpx->id);
Willy Tarreaub6866442008-07-14 23:54:42 +02001144 return 1;
1145 }
1146 curpx->tcp_req.inspect_delay = val;
1147 return 0;
1148 }
1149
Willy Tarreau6a984fa2010-06-14 16:44:27 +02001150 rule = (struct tcp_rule *)calloc(1, sizeof(*rule));
Willy Tarreaufb024dc2010-08-20 13:35:41 +02001151 LIST_INIT(&rule->list);
Willy Tarreau6a984fa2010-06-14 16:44:27 +02001152 arg = 1;
1153
Willy Tarreau68c03ab2010-08-06 15:08:45 +02001154 if (strcmp(args[1], "content") == 0) {
Willy Tarreaud1f96522010-08-03 19:34:32 +02001155 arg++;
Willy Tarreau68c03ab2010-08-06 15:08:45 +02001156 if (tcp_parse_request_rule(args, arg, section_type, curpx, defpx, rule, err, errlen) < 0)
Willy Tarreau6a984fa2010-06-14 16:44:27 +02001157 goto error;
Willy Tarreaub6866442008-07-14 23:54:42 +02001158
Willy Tarreau6a984fa2010-06-14 16:44:27 +02001159 if (rule->cond && (rule->cond->requires & ACL_USE_RTR_ANY)) {
Willy Tarreaudd64f8d2008-07-27 22:02:32 +02001160 struct acl *acl;
1161 const char *name;
1162
Willy Tarreau6a984fa2010-06-14 16:44:27 +02001163 acl = cond_find_require(rule->cond, ACL_USE_RTR_ANY);
Willy Tarreaudd64f8d2008-07-27 22:02:32 +02001164 name = acl ? acl->name : "(unknown)";
1165
1166 retlen = snprintf(err, errlen,
Willy Tarreau1a211942009-07-14 13:53:17 +02001167 "acl '%s' involves some response-only criteria which will be ignored.",
1168 name);
Willy Tarreaudd64f8d2008-07-27 22:02:32 +02001169 warn++;
1170 }
Willy Tarreaufb024dc2010-08-20 13:35:41 +02001171 LIST_ADDQ(&curpx->tcp_req.inspect_rules, &rule->list);
Willy Tarreau9ba2dcc2010-06-14 21:04:55 +02001172 }
Willy Tarreau68c03ab2010-08-06 15:08:45 +02001173 else if (strcmp(args[1], "connection") == 0) {
Willy Tarreau9ba2dcc2010-06-14 21:04:55 +02001174 arg++;
Willy Tarreau9ba2dcc2010-06-14 21:04:55 +02001175
Willy Tarreau68c03ab2010-08-06 15:08:45 +02001176 if (!(curpx->cap & PR_CAP_FE)) {
1177 snprintf(err, errlen, "%s %s is not allowed because %s %s is not a frontend",
1178 args[0], args[1], proxy_type_str(curpx), curpx->id);
1179 return -1;
1180 }
Willy Tarreau9ba2dcc2010-06-14 21:04:55 +02001181
Willy Tarreau68c03ab2010-08-06 15:08:45 +02001182 if (tcp_parse_request_rule(args, arg, section_type, curpx, defpx, rule, err, errlen) < 0)
Willy Tarreau9ba2dcc2010-06-14 21:04:55 +02001183 goto error;
1184
Willy Tarreau68c03ab2010-08-06 15:08:45 +02001185 if (rule->cond && (rule->cond->requires & (ACL_USE_RTR_ANY|ACL_USE_L6_ANY|ACL_USE_L7_ANY))) {
1186 struct acl *acl;
1187 const char *name;
Willy Tarreauf059a0f2010-08-03 16:29:52 +02001188
Willy Tarreau68c03ab2010-08-06 15:08:45 +02001189 acl = cond_find_require(rule->cond, ACL_USE_RTR_ANY|ACL_USE_L6_ANY|ACL_USE_L7_ANY);
1190 name = acl ? acl->name : "(unknown)";
Willy Tarreauf059a0f2010-08-03 16:29:52 +02001191
Willy Tarreau68c03ab2010-08-06 15:08:45 +02001192 if (acl->requires & (ACL_USE_L6_ANY|ACL_USE_L7_ANY)) {
1193 retlen = snprintf(err, errlen,
1194 "'%s %s' may not reference acl '%s' which makes use of "
1195 "payload in %s '%s'. Please use '%s content' for this.",
1196 args[0], args[1], name, proxy_type_str(curpx), curpx->id, args[0]);
1197 goto error;
1198 }
1199 if (acl->requires & ACL_USE_RTR_ANY)
1200 retlen = snprintf(err, errlen,
1201 "acl '%s' involves some response-only criteria which will be ignored.",
1202 name);
1203 warn++;
1204 }
Willy Tarreaufb024dc2010-08-20 13:35:41 +02001205 LIST_ADDQ(&curpx->tcp_req.l4_rules, &rule->list);
Willy Tarreau9ba2dcc2010-06-14 21:04:55 +02001206 }
Willy Tarreau1a687942010-05-23 22:40:30 +02001207 else {
1208 retlen = snprintf(err, errlen,
Willy Tarreau68c03ab2010-08-06 15:08:45 +02001209 "'%s' expects 'inspect-delay', 'connection', or 'content' in %s '%s' (was '%s')",
Willy Tarreau1a687942010-05-23 22:40:30 +02001210 args[0], proxy_type_str(curpx), curpx->id, args[1]);
Willy Tarreau6a984fa2010-06-14 16:44:27 +02001211 goto error;
Willy Tarreau1a687942010-05-23 22:40:30 +02001212 }
1213
Willy Tarreau1a687942010-05-23 22:40:30 +02001214 return warn;
Willy Tarreau6a984fa2010-06-14 16:44:27 +02001215 error:
1216 free(rule);
1217 return -1;
Willy Tarreaub6866442008-07-14 23:54:42 +02001218}
1219
Willy Tarreau645513a2010-05-24 20:55:15 +02001220
1221/************************************************************************/
1222/* All supported ACL keywords must be declared here. */
1223/************************************************************************/
1224
1225/* set test->ptr to point to the source IPv4/IPv6 address and test->i to the family */
1226static int
1227acl_fetch_src(struct proxy *px, struct session *l4, void *l7, int dir,
1228 struct acl_expr *expr, struct acl_test *test)
1229{
Willy Tarreau957c0a52011-03-03 17:42:23 +01001230 test->i = l4->si[0].addr.c.from.ss_family;
Willy Tarreau645513a2010-05-24 20:55:15 +02001231 if (test->i == AF_INET)
Willy Tarreau957c0a52011-03-03 17:42:23 +01001232 test->ptr = (void *)&((struct sockaddr_in *)&l4->si[0].addr.c.from)->sin_addr;
Emeric Brunf769f512010-10-22 17:14:01 +02001233 else if (test->i == AF_INET6)
Willy Tarreau957c0a52011-03-03 17:42:23 +01001234 test->ptr = (void *)&((struct sockaddr_in6 *)(&l4->si[0].addr.c.from))->sin6_addr;
Emeric Brunf769f512010-10-22 17:14:01 +02001235 else
1236 return 0;
1237
Willy Tarreau645513a2010-05-24 20:55:15 +02001238 test->flags = ACL_TEST_F_READ_ONLY;
1239 return 1;
1240}
1241
1242/* extract the connection's source address */
1243static int
1244pattern_fetch_src(struct proxy *px, struct session *l4, void *l7, int dir,
Emeric Brun485479d2010-09-23 18:02:19 +02001245 const struct pattern_arg *arg_p, int arg_i, union pattern_data *data)
Willy Tarreau645513a2010-05-24 20:55:15 +02001246{
Willy Tarreau957c0a52011-03-03 17:42:23 +01001247 if (l4->si[0].addr.c.from.ss_family != AF_INET )
Emeric Brunf769f512010-10-22 17:14:01 +02001248 return 0;
1249
Willy Tarreau957c0a52011-03-03 17:42:23 +01001250 data->ip.s_addr = ((struct sockaddr_in *)&l4->si[0].addr.c.from)->sin_addr.s_addr;
Willy Tarreau645513a2010-05-24 20:55:15 +02001251 return 1;
1252}
1253
1254
1255/* set test->i to the connection's source port */
1256static int
1257acl_fetch_sport(struct proxy *px, struct session *l4, void *l7, int dir,
1258 struct acl_expr *expr, struct acl_test *test)
1259{
Willy Tarreau957c0a52011-03-03 17:42:23 +01001260 if (l4->si[0].addr.c.from.ss_family == AF_INET)
1261 test->i = ntohs(((struct sockaddr_in *)&l4->si[0].addr.c.from)->sin_port);
1262 else if (l4->si[0].addr.c.from.ss_family == AF_INET6)
1263 test->i = ntohs(((struct sockaddr_in6 *)(&l4->si[0].addr.c.from))->sin6_port);
Emeric Brunf769f512010-10-22 17:14:01 +02001264 else
1265 return 0;
1266
Willy Tarreau645513a2010-05-24 20:55:15 +02001267 test->flags = 0;
1268 return 1;
1269}
1270
1271
1272/* set test->ptr to point to the frontend's IPv4/IPv6 address and test->i to the family */
1273static int
1274acl_fetch_dst(struct proxy *px, struct session *l4, void *l7, int dir,
1275 struct acl_expr *expr, struct acl_test *test)
1276{
1277 if (!(l4->flags & SN_FRT_ADDR_SET))
1278 get_frt_addr(l4);
1279
Willy Tarreau957c0a52011-03-03 17:42:23 +01001280 test->i = l4->si[0].addr.c.to.ss_family;
Willy Tarreau645513a2010-05-24 20:55:15 +02001281 if (test->i == AF_INET)
Willy Tarreau957c0a52011-03-03 17:42:23 +01001282 test->ptr = (void *)&((struct sockaddr_in *)&l4->si[0].addr.c.to)->sin_addr;
Emeric Brunf769f512010-10-22 17:14:01 +02001283 else if (test->i == AF_INET6)
Willy Tarreau957c0a52011-03-03 17:42:23 +01001284 test->ptr = (void *)&((struct sockaddr_in6 *)(&l4->si[0].addr.c.to))->sin6_addr;
Emeric Brunf769f512010-10-22 17:14:01 +02001285 else
1286 return 0;
1287
Willy Tarreau645513a2010-05-24 20:55:15 +02001288 test->flags = ACL_TEST_F_READ_ONLY;
1289 return 1;
1290}
1291
1292
1293/* extract the connection's destination address */
1294static int
1295pattern_fetch_dst(struct proxy *px, struct session *l4, void *l7, int dir,
Emeric Brun485479d2010-09-23 18:02:19 +02001296 const struct pattern_arg *arg_p, int arg_i, union pattern_data *data)
Willy Tarreau645513a2010-05-24 20:55:15 +02001297{
emeric8aa6b372010-10-22 17:06:26 +02001298 if (!(l4->flags & SN_FRT_ADDR_SET))
1299 get_frt_addr(l4);
1300
Willy Tarreau957c0a52011-03-03 17:42:23 +01001301 if (l4->si[0].addr.c.to.ss_family != AF_INET)
Emeric Brunf769f512010-10-22 17:14:01 +02001302 return 0;
1303
Willy Tarreau957c0a52011-03-03 17:42:23 +01001304 data->ip.s_addr = ((struct sockaddr_in *)&l4->si[0].addr.c.to)->sin_addr.s_addr;
Willy Tarreau645513a2010-05-24 20:55:15 +02001305 return 1;
1306}
1307
1308/* set test->i to the frontend connexion's destination port */
1309static int
1310acl_fetch_dport(struct proxy *px, struct session *l4, void *l7, int dir,
1311 struct acl_expr *expr, struct acl_test *test)
1312{
1313 if (!(l4->flags & SN_FRT_ADDR_SET))
1314 get_frt_addr(l4);
1315
Willy Tarreau957c0a52011-03-03 17:42:23 +01001316 if (l4->si[0].addr.c.to.ss_family == AF_INET)
1317 test->i = ntohs(((struct sockaddr_in *)&l4->si[0].addr.c.to)->sin_port);
1318 else if (l4->si[0].addr.c.to.ss_family == AF_INET6)
1319 test->i = ntohs(((struct sockaddr_in6 *)(&l4->si[0].addr.c.to))->sin6_port);
Emeric Brunf769f512010-10-22 17:14:01 +02001320 else
1321 return 0;
1322
Willy Tarreau645513a2010-05-24 20:55:15 +02001323 test->flags = 0;
1324 return 1;
1325}
1326
1327static int
1328pattern_fetch_dport(struct proxy *px, struct session *l4, void *l7, int dir,
Emeric Brun485479d2010-09-23 18:02:19 +02001329 const struct pattern_arg *arg, int i, union pattern_data *data)
Willy Tarreau645513a2010-05-24 20:55:15 +02001330{
emeric8aa6b372010-10-22 17:06:26 +02001331 if (!(l4->flags & SN_FRT_ADDR_SET))
1332 get_frt_addr(l4);
1333
Willy Tarreau957c0a52011-03-03 17:42:23 +01001334 if (l4->si[0].addr.c.to.ss_family != AF_INET)
Emeric Brunf769f512010-10-22 17:14:01 +02001335 return 0;
1336
Willy Tarreau957c0a52011-03-03 17:42:23 +01001337 data->integer = ntohs(((struct sockaddr_in *)&l4->si[0].addr.c.to)->sin_port);
Willy Tarreau645513a2010-05-24 20:55:15 +02001338 return 1;
1339}
1340
Emericf2d7cae2010-11-05 18:13:50 +01001341static int
1342pattern_arg_fetch_payloadlv(const char *arg, struct pattern_arg **arg_p, int *arg_i)
1343{
1344 int member = 0;
1345 int len_offset = 0;
1346 int len_size = 0;
1347 int buf_offset = 0;
1348 int relative = 0;
1349 int arg_len = strlen(arg);
1350 int i;
1351
1352 for (i = 0; i < arg_len; i++) {
1353 if (arg[i] == ',') {
1354 member++;
1355 } else if (member == 0) {
1356 if (arg[i] < '0' || arg[i] > '9')
1357 return 0;
1358
1359 len_offset = 10 * len_offset + arg[i] - '0';
1360 } else if (member == 1) {
1361 if (arg[i] < '0' || arg[i] > '9')
1362 return 0;
1363
1364 len_size = 10 * len_size + arg[i] - '0';
1365 } else if (member == 2) {
1366 if (!relative && !buf_offset && arg[i] == '+') {
1367 relative = 1;
1368 continue;
1369 } else if (!relative && !buf_offset && arg[i] == '-') {
1370 relative = 2;
1371 continue;
1372 } else if (arg[i] < '0' || arg[i] > '9')
1373 return 0;
1374
1375 buf_offset = 10 * buf_offset + arg[i] - '0';
1376 }
1377 }
1378
1379 if (member < 1)
1380 return 0;
1381
1382 if (!len_size)
1383 return 0;
1384
1385 if (member == 1) {
1386 buf_offset = len_offset + len_size;
1387 }
1388 else if (relative == 1) {
1389 buf_offset = len_offset + len_size + buf_offset;
1390 }
1391 else if (relative == 2) {
1392 if (len_offset + len_size < buf_offset)
1393 return 0;
1394
1395 buf_offset = len_offset + len_size - buf_offset;
1396 }
1397
1398 *arg_i = 3;
1399 *arg_p = calloc(1, *arg_i*sizeof(struct pattern_arg));
1400 (*arg_p)[0].type = PATTERN_ARG_TYPE_INTEGER;
1401 (*arg_p)[0].data.integer = len_offset;
1402 (*arg_p)[1].type = PATTERN_ARG_TYPE_INTEGER;
1403 (*arg_p)[1].data.integer = len_size;
1404 (*arg_p)[2].type = PATTERN_ARG_TYPE_INTEGER;
1405 (*arg_p)[2].data.integer = buf_offset;
1406
1407 return 1;
1408}
1409
1410static int
1411pattern_fetch_payloadlv(struct proxy *px, struct session *l4, void *l7, int dir,
1412 const struct pattern_arg *arg_p, int arg_i, union pattern_data *data)
1413{
1414 int len_offset = arg_p[0].data.integer;
1415 int len_size = arg_p[1].data.integer;
1416 int buf_offset = arg_p[2].data.integer;
1417 int buf_size = 0;
1418 struct buffer *b;
1419 int i;
1420
1421 /* Format is (len offset, len size, buf offset) or (len offset, len size) */
1422 /* by default buf offset == len offset + len size */
1423 /* buf offset could be absolute or relative to len offset + len size if prefixed by + or - */
1424
1425 if (!l4)
1426 return 0;
1427
1428 b = (dir & PATTERN_FETCH_RTR) ? l4->rep : l4->req;
1429
1430 if (!b || !b->l)
1431 return 0;
1432
1433 if (len_offset + len_size > b->l)
1434 return 0;
1435
1436 for (i = 0; i < len_size; i++) {
1437 buf_size = (buf_size << 8) + ((unsigned char *)b->w)[i + len_offset];
1438 }
1439
1440 if (!buf_size)
1441 return 0;
1442
1443 if (buf_offset + buf_size > b->l)
1444 return 0;
1445
1446 /* init chunk as read only */
1447 chunk_initlen(&data->str, (char *)(b->w + buf_offset), 0, buf_size);
1448
1449 return 1;
1450}
1451
1452static int
1453pattern_arg_fetch_payload (const char *arg, struct pattern_arg **arg_p, int *arg_i)
1454{
1455 int member = 0;
1456 int buf_offset = 0;
1457 int buf_size = 0;
1458 int arg_len = strlen(arg);
1459 int i;
1460
1461 for (i = 0 ; i < arg_len ; i++) {
1462 if (arg[i] == ',') {
1463 member++;
1464 } else if (member == 0) {
1465 if (arg[i] < '0' || arg[i] > '9')
1466 return 0;
1467
1468 buf_offset = 10 * buf_offset + arg[i] - '0';
1469 } else if (member == 1) {
1470 if (arg[i] < '0' || arg[i] > '9')
1471 return 0;
1472
1473 buf_size = 10 * buf_size + arg[i] - '0';
1474 }
1475 }
1476
1477 if (!buf_size)
1478 return 0;
1479
1480 *arg_i = 2;
1481 *arg_p = calloc(1, *arg_i*sizeof(struct pattern_arg));
1482 (*arg_p)[0].type = PATTERN_ARG_TYPE_INTEGER;
1483 (*arg_p)[0].data.integer = buf_offset;
1484 (*arg_p)[1].type = PATTERN_ARG_TYPE_INTEGER;
1485 (*arg_p)[1].data.integer = buf_size;
1486
1487 return 1;
1488}
1489
1490static int
1491pattern_fetch_payload(struct proxy *px, struct session *l4, void *l7, int dir,
1492 const struct pattern_arg *arg_p, int arg_i, union pattern_data *data)
1493{
1494 int buf_offset = arg_p[0].data.integer;
1495 int buf_size = arg_p[1].data.integer;
1496 struct buffer *b;
1497
1498 if (!l4)
1499 return 0;
1500
1501 b = (dir & PATTERN_FETCH_RTR) ? l4->rep : l4->req;
1502
1503 if (!b || !b->l)
1504 return 0;
1505
1506 if (buf_offset + buf_size > b->l)
1507 return 0;
1508
1509 /* init chunk as read only */
1510 chunk_initlen(&data->str, (char *)(b->w + buf_offset), 0, buf_size);
1511
1512 return 1;
1513}
1514
Willy Tarreaub6866442008-07-14 23:54:42 +02001515static struct cfg_kw_list cfg_kws = {{ },{
1516 { CFG_LISTEN, "tcp-request", tcp_parse_tcp_req },
Emeric Brun97679e72010-09-23 17:56:44 +02001517 { CFG_LISTEN, "tcp-response", tcp_parse_tcp_rep },
Willy Tarreaub6866442008-07-14 23:54:42 +02001518 { 0, NULL, NULL },
1519}};
1520
Willy Tarreau645513a2010-05-24 20:55:15 +02001521/* Note: must not be declared <const> as its list will be overwritten */
Willy Tarreaub6866442008-07-14 23:54:42 +02001522static struct acl_kw_list acl_kws = {{ },{
Willy Tarreau645513a2010-05-24 20:55:15 +02001523 { "src_port", acl_parse_int, acl_fetch_sport, acl_match_int, ACL_USE_TCP_PERMANENT },
1524 { "src", acl_parse_ip, acl_fetch_src, acl_match_ip, ACL_USE_TCP4_PERMANENT|ACL_MAY_LOOKUP },
1525 { "dst", acl_parse_ip, acl_fetch_dst, acl_match_ip, ACL_USE_TCP4_PERMANENT|ACL_MAY_LOOKUP },
1526 { "dst_port", acl_parse_int, acl_fetch_dport, acl_match_int, ACL_USE_TCP_PERMANENT },
Willy Tarreaub6866442008-07-14 23:54:42 +02001527 { NULL, NULL, NULL, NULL },
1528}};
1529
Willy Tarreau645513a2010-05-24 20:55:15 +02001530/* Note: must not be declared <const> as its list will be overwritten */
1531static struct pattern_fetch_kw_list pattern_fetch_keywords = {{ },{
Emericf2d7cae2010-11-05 18:13:50 +01001532 { "src", pattern_fetch_src, NULL, PATTERN_TYPE_IP, PATTERN_FETCH_REQ },
1533 { "dst", pattern_fetch_dst, NULL, PATTERN_TYPE_IP, PATTERN_FETCH_REQ },
1534 { "dst_port", pattern_fetch_dport, NULL, PATTERN_TYPE_INTEGER, PATTERN_FETCH_REQ },
1535 { "payload", pattern_fetch_payload, pattern_arg_fetch_payload, PATTERN_TYPE_CONSTDATA, PATTERN_FETCH_REQ|PATTERN_FETCH_RTR },
1536 { "payload_lv", pattern_fetch_payloadlv, pattern_arg_fetch_payloadlv, PATTERN_TYPE_CONSTDATA, PATTERN_FETCH_REQ|PATTERN_FETCH_RTR },
Emeric Brun485479d2010-09-23 18:02:19 +02001537 { NULL, NULL, NULL, 0, 0 },
Willy Tarreau645513a2010-05-24 20:55:15 +02001538}};
1539
Willy Tarreaue6b98942007-10-29 01:09:36 +01001540__attribute__((constructor))
1541static void __tcp_protocol_init(void)
1542{
1543 protocol_register(&proto_tcpv4);
1544 protocol_register(&proto_tcpv6);
Willy Tarreau645513a2010-05-24 20:55:15 +02001545 pattern_register_fetches(&pattern_fetch_keywords);
Willy Tarreaub6866442008-07-14 23:54:42 +02001546 cfg_register_keywords(&cfg_kws);
1547 acl_register_keywords(&acl_kws);
Willy Tarreaue6b98942007-10-29 01:09:36 +01001548}
1549
1550
1551/*
1552 * Local variables:
1553 * c-indent-level: 8
1554 * c-basic-offset: 8
1555 * End:
1556 */