blob: 2d79e22d26135dc993e8af8db3a4216531151f6b [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/*
Willy Tarreauac825402011-03-04 22:04:29 +0100184 * This function initiates a connection to the target assigned to this session
185 * (si->{target,addr.s.to}). A source address may be pointed to by si->addr.s.from
186 * in case of transparent proxying. Normal source bind addresses are still
187 * determined locally (due to the possible need of a source port).
188 * si->target may point either to a valid server or to a backend, depending
189 * on si->target.type. Only TARG_TYPE_PROXY and TARG_TYPE_SERVER are supported.
Willy Tarreaub1d67742010-03-29 19:36:59 +0200190 *
Willy Tarreau9650f372009-08-16 14:02:45 +0200191 * It can return one of :
192 * - SN_ERR_NONE if everything's OK
193 * - SN_ERR_SRVTO if there are no more servers
194 * - SN_ERR_SRVCL if the connection was refused by the server
195 * - SN_ERR_PRXCOND if the connection has been limited by the proxy (maxconn)
196 * - SN_ERR_RESOURCE if a system resource is lacking (eg: fd limits, ports, ...)
197 * - SN_ERR_INTERNAL for any other purely internal errors
198 * Additionnally, in the case of SN_ERR_RESOURCE, an emergency log will be emitted.
199 */
Willy Tarreauf1536862011-03-03 18:27:32 +0100200
Willy Tarreauac825402011-03-04 22:04:29 +0100201int tcpv4_connect_server(struct stream_interface *si)
Willy Tarreau9650f372009-08-16 14:02:45 +0200202{
203 int fd;
Willy Tarreauac825402011-03-04 22:04:29 +0100204 struct server *srv;
205 struct proxy *be;
206
207 switch (si->target.type) {
208 case TARG_TYPE_PROXY:
209 be = si->target.ptr.p;
210 srv = NULL;
211 break;
212 case TARG_TYPE_SERVER:
213 srv = si->target.ptr.s;
214 be = srv->proxy;
215 break;
216 default:
217 return SN_ERR_INTERNAL;
218 }
Willy Tarreau9650f372009-08-16 14:02:45 +0200219
220 if ((fd = si->fd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)) == -1) {
221 qfprintf(stderr, "Cannot get a server socket.\n");
222
223 if (errno == ENFILE)
224 send_log(be, LOG_EMERG,
225 "Proxy %s reached system FD limit at %d. Please check system tunables.\n",
226 be->id, maxfd);
227 else if (errno == EMFILE)
228 send_log(be, LOG_EMERG,
229 "Proxy %s reached process FD limit at %d. Please check 'ulimit-n' and restart.\n",
230 be->id, maxfd);
231 else if (errno == ENOBUFS || errno == ENOMEM)
232 send_log(be, LOG_EMERG,
233 "Proxy %s reached system memory limit at %d sockets. Please check system tunables.\n",
234 be->id, maxfd);
235 /* this is a resource error */
236 return SN_ERR_RESOURCE;
237 }
238
239 if (fd >= global.maxsock) {
240 /* do not log anything there, it's a normal condition when this option
241 * is used to serialize connections to a server !
242 */
243 Alert("socket(): not enough free sockets. Raise -n argument. Giving up.\n");
244 close(fd);
245 return SN_ERR_PRXCOND; /* it is a configuration limit */
246 }
247
248 if ((fcntl(fd, F_SETFL, O_NONBLOCK)==-1) ||
249 (setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, (char *) &one, sizeof(one)) == -1)) {
250 qfprintf(stderr,"Cannot set client socket to non blocking mode.\n");
251 close(fd);
252 return SN_ERR_INTERNAL;
253 }
254
255 if (be->options & PR_O_TCP_SRV_KA)
256 setsockopt(fd, SOL_SOCKET, SO_KEEPALIVE, (char *) &one, sizeof(one));
257
258 if (be->options & PR_O_TCP_NOLING)
259 setsockopt(fd, SOL_SOCKET, SO_LINGER, (struct linger *) &nolinger, sizeof(struct linger));
260
261 /* allow specific binding :
262 * - server-specific at first
263 * - proxy-specific next
264 */
265 if (srv != NULL && srv->state & SRV_BIND_SRC) {
Willy Tarreau9650f372009-08-16 14:02:45 +0200266 int ret, flags = 0;
267
Willy Tarreau9650f372009-08-16 14:02:45 +0200268 switch (srv->state & SRV_TPROXY_MASK) {
269 case SRV_TPROXY_ADDR:
Willy Tarreau9650f372009-08-16 14:02:45 +0200270 case SRV_TPROXY_CLI:
Willy Tarreaub1d67742010-03-29 19:36:59 +0200271 flags = 3;
272 break;
Willy Tarreau9650f372009-08-16 14:02:45 +0200273 case SRV_TPROXY_CIP:
Willy Tarreau090466c2009-09-07 11:51:47 +0200274 case SRV_TPROXY_DYN:
Willy Tarreaub1d67742010-03-29 19:36:59 +0200275 flags = 1;
Willy Tarreau9650f372009-08-16 14:02:45 +0200276 break;
277 }
Willy Tarreaub1d67742010-03-29 19:36:59 +0200278
Willy Tarreau9650f372009-08-16 14:02:45 +0200279#ifdef SO_BINDTODEVICE
280 /* Note: this might fail if not CAP_NET_RAW */
281 if (srv->iface_name)
282 setsockopt(fd, SOL_SOCKET, SO_BINDTODEVICE, srv->iface_name, srv->iface_len + 1);
283#endif
284
285 if (srv->sport_range) {
286 int attempts = 10; /* should be more than enough to find a spare port */
287 struct sockaddr_in src;
288
289 ret = 1;
290 src = srv->source_addr;
291
292 do {
293 /* note: in case of retry, we may have to release a previously
294 * allocated port, hence this loop's construct.
295 */
Willy Tarreau8d5d77e2009-10-18 07:25:52 +0200296 port_range_release_port(fdinfo[fd].port_range, fdinfo[fd].local_port);
297 fdinfo[fd].port_range = NULL;
Willy Tarreau9650f372009-08-16 14:02:45 +0200298
299 if (!attempts)
300 break;
301 attempts--;
302
Willy Tarreau8d5d77e2009-10-18 07:25:52 +0200303 fdinfo[fd].local_port = port_range_alloc_port(srv->sport_range);
304 if (!fdinfo[fd].local_port)
Willy Tarreau9650f372009-08-16 14:02:45 +0200305 break;
306
Willy Tarreau8d5d77e2009-10-18 07:25:52 +0200307 fdinfo[fd].port_range = srv->sport_range;
308 src.sin_port = htons(fdinfo[fd].local_port);
Willy Tarreau9650f372009-08-16 14:02:45 +0200309
Willy Tarreauf1536862011-03-03 18:27:32 +0100310 ret = tcpv4_bind_socket(fd, flags, &src, (struct sockaddr_in *)&si->addr.s.from);
Willy Tarreau9650f372009-08-16 14:02:45 +0200311 } while (ret != 0); /* binding NOK */
312 }
313 else {
Willy Tarreauf1536862011-03-03 18:27:32 +0100314 ret = tcpv4_bind_socket(fd, flags, &srv->source_addr, (struct sockaddr_in *)&si->addr.s.from);
Willy Tarreau9650f372009-08-16 14:02:45 +0200315 }
316
317 if (ret) {
Willy Tarreau8d5d77e2009-10-18 07:25:52 +0200318 port_range_release_port(fdinfo[fd].port_range, fdinfo[fd].local_port);
319 fdinfo[fd].port_range = NULL;
Willy Tarreau9650f372009-08-16 14:02:45 +0200320 close(fd);
321
322 if (ret == 1) {
323 Alert("Cannot bind to source address before connect() for server %s/%s. Aborting.\n",
324 be->id, srv->id);
325 send_log(be, LOG_EMERG,
326 "Cannot bind to source address before connect() for server %s/%s.\n",
327 be->id, srv->id);
328 } else {
329 Alert("Cannot bind to tproxy source address before connect() for server %s/%s. Aborting.\n",
330 be->id, srv->id);
331 send_log(be, LOG_EMERG,
332 "Cannot bind to tproxy source address before connect() for server %s/%s.\n",
333 be->id, srv->id);
334 }
335 return SN_ERR_RESOURCE;
336 }
337 }
338 else if (be->options & PR_O_BIND_SRC) {
Willy Tarreau9650f372009-08-16 14:02:45 +0200339 int ret, flags = 0;
340
Willy Tarreau9650f372009-08-16 14:02:45 +0200341 switch (be->options & PR_O_TPXY_MASK) {
342 case PR_O_TPXY_ADDR:
Willy Tarreau9650f372009-08-16 14:02:45 +0200343 case PR_O_TPXY_CLI:
Willy Tarreaub1d67742010-03-29 19:36:59 +0200344 flags = 3;
345 break;
Willy Tarreau9650f372009-08-16 14:02:45 +0200346 case PR_O_TPXY_CIP:
Willy Tarreau090466c2009-09-07 11:51:47 +0200347 case PR_O_TPXY_DYN:
Willy Tarreaub1d67742010-03-29 19:36:59 +0200348 flags = 1;
Willy Tarreau9650f372009-08-16 14:02:45 +0200349 break;
350 }
Willy Tarreaub1d67742010-03-29 19:36:59 +0200351
Willy Tarreau9650f372009-08-16 14:02:45 +0200352#ifdef SO_BINDTODEVICE
353 /* Note: this might fail if not CAP_NET_RAW */
354 if (be->iface_name)
355 setsockopt(fd, SOL_SOCKET, SO_BINDTODEVICE, be->iface_name, be->iface_len + 1);
356#endif
Willy Tarreauf1536862011-03-03 18:27:32 +0100357 ret = tcpv4_bind_socket(fd, flags, &be->source_addr, (struct sockaddr_in *)&si->addr.s.from);
Willy Tarreau9650f372009-08-16 14:02:45 +0200358 if (ret) {
359 close(fd);
360 if (ret == 1) {
361 Alert("Cannot bind to source address before connect() for proxy %s. Aborting.\n",
362 be->id);
363 send_log(be, LOG_EMERG,
364 "Cannot bind to source address before connect() for proxy %s.\n",
365 be->id);
366 } else {
367 Alert("Cannot bind to tproxy source address before connect() for proxy %s. Aborting.\n",
368 be->id);
369 send_log(be, LOG_EMERG,
370 "Cannot bind to tproxy source address before connect() for proxy %s.\n",
371 be->id);
372 }
373 return SN_ERR_RESOURCE;
374 }
375 }
376
Dmitry Sivachenkocaf58982009-08-24 15:11:06 +0400377#if defined(TCP_QUICKACK)
Willy Tarreau9650f372009-08-16 14:02:45 +0200378 /* disabling tcp quick ack now allows the first request to leave the
379 * machine with the first ACK. We only do this if there are pending
380 * data in the buffer.
381 */
382 if ((be->options2 & PR_O2_SMARTCON) && si->ob->send_max)
Dmitry Sivachenkocaf58982009-08-24 15:11:06 +0400383 setsockopt(fd, IPPROTO_TCP, TCP_QUICKACK, (char *) &zero, sizeof(zero));
Willy Tarreau9650f372009-08-16 14:02:45 +0200384#endif
385
Willy Tarreaue803de22010-01-21 17:43:04 +0100386 if (global.tune.server_sndbuf)
387 setsockopt(fd, SOL_SOCKET, SO_SNDBUF, &global.tune.server_sndbuf, sizeof(global.tune.server_sndbuf));
388
389 if (global.tune.server_rcvbuf)
390 setsockopt(fd, SOL_SOCKET, SO_RCVBUF, &global.tune.server_rcvbuf, sizeof(global.tune.server_rcvbuf));
391
Willy Tarreauf1536862011-03-03 18:27:32 +0100392 if ((connect(fd, (struct sockaddr *)&si->addr.s.to, sizeof(struct sockaddr_in)) == -1) &&
Willy Tarreau9650f372009-08-16 14:02:45 +0200393 (errno != EINPROGRESS) && (errno != EALREADY) && (errno != EISCONN)) {
394
395 if (errno == EAGAIN || errno == EADDRINUSE) {
396 char *msg;
397 if (errno == EAGAIN) /* no free ports left, try again later */
398 msg = "no free ports";
399 else
400 msg = "local address already in use";
401
402 qfprintf(stderr,"Cannot connect: %s.\n",msg);
Willy Tarreau8d5d77e2009-10-18 07:25:52 +0200403 port_range_release_port(fdinfo[fd].port_range, fdinfo[fd].local_port);
404 fdinfo[fd].port_range = NULL;
Willy Tarreau9650f372009-08-16 14:02:45 +0200405 close(fd);
406 send_log(be, LOG_EMERG,
407 "Connect() failed for server %s/%s: %s.\n",
408 be->id, srv->id, msg);
409 return SN_ERR_RESOURCE;
410 } else if (errno == ETIMEDOUT) {
411 //qfprintf(stderr,"Connect(): ETIMEDOUT");
Willy Tarreau8d5d77e2009-10-18 07:25:52 +0200412 port_range_release_port(fdinfo[fd].port_range, fdinfo[fd].local_port);
413 fdinfo[fd].port_range = NULL;
Willy Tarreau9650f372009-08-16 14:02:45 +0200414 close(fd);
415 return SN_ERR_SRVTO;
416 } else {
417 // (errno == ECONNREFUSED || errno == ENETUNREACH || errno == EACCES || errno == EPERM)
418 //qfprintf(stderr,"Connect(): %d", errno);
Willy Tarreau8d5d77e2009-10-18 07:25:52 +0200419 port_range_release_port(fdinfo[fd].port_range, fdinfo[fd].local_port);
420 fdinfo[fd].port_range = NULL;
Willy Tarreau9650f372009-08-16 14:02:45 +0200421 close(fd);
422 return SN_ERR_SRVCL;
423 }
424 }
425
426 fdtab[fd].owner = si;
427 fdtab[fd].state = FD_STCONN; /* connection in progress */
428 fdtab[fd].flags = FD_FL_TCP | FD_FL_TCP_NODELAY;
429 fdtab[fd].cb[DIR_RD].f = &stream_sock_read;
430 fdtab[fd].cb[DIR_RD].b = si->ib;
431 fdtab[fd].cb[DIR_WR].f = &stream_sock_write;
432 fdtab[fd].cb[DIR_WR].b = si->ob;
433
Willy Tarreauf1536862011-03-03 18:27:32 +0100434 fdinfo[fd].peeraddr = (struct sockaddr *)&si->addr.s.to;
Willy Tarreau8d5d77e2009-10-18 07:25:52 +0200435 fdinfo[fd].peerlen = sizeof(struct sockaddr_in);
Willy Tarreau9650f372009-08-16 14:02:45 +0200436
437 fd_insert(fd);
438 EV_FD_SET(fd, DIR_WR); /* for connect status */
439
440 si->state = SI_ST_CON;
441 si->flags |= SI_FL_CAP_SPLTCP; /* TCP supports splicing */
442 si->exp = tick_add_ifset(now_ms, be->timeout.connect);
443
444 return SN_ERR_NONE; /* connection is OK */
445}
446
447
Willy Tarreaue6b98942007-10-29 01:09:36 +0100448/* This function tries to bind a TCPv4/v6 listener. It may return a warning or
449 * an error message in <err> if the message is at most <errlen> bytes long
450 * (including '\0'). The return value is composed from ERR_ABORT, ERR_WARN,
451 * ERR_ALERT, ERR_RETRYABLE and ERR_FATAL. ERR_NONE indicates that everything
452 * was alright and that no message was returned. ERR_RETRYABLE means that an
453 * error occurred but that it may vanish after a retry (eg: port in use), and
454 * ERR_FATAL indicates a non-fixable error.ERR_WARN and ERR_ALERT do not alter
455 * the meaning of the error, but just indicate that a message is present which
456 * should be displayed with the respective level. Last, ERR_ABORT indicates
457 * that it's pointless to try to start other listeners. No error message is
458 * returned if errlen is NULL.
459 */
460int tcp_bind_listener(struct listener *listener, char *errmsg, int errlen)
461{
462 __label__ tcp_return, tcp_close_return;
463 int fd, err;
464 const char *msg = NULL;
465
466 /* ensure we never return garbage */
467 if (errmsg && errlen)
468 *errmsg = 0;
469
470 if (listener->state != LI_ASSIGNED)
471 return ERR_NONE; /* already bound */
472
473 err = ERR_NONE;
474
475 if ((fd = socket(listener->addr.ss_family, SOCK_STREAM, IPPROTO_TCP)) == -1) {
476 err |= ERR_RETRYABLE | ERR_ALERT;
477 msg = "cannot create listening socket";
478 goto tcp_return;
479 }
Willy Tarreauedcf6682008-11-30 23:15:34 +0100480
Willy Tarreaue6b98942007-10-29 01:09:36 +0100481 if (fd >= global.maxsock) {
482 err |= ERR_FATAL | ERR_ABORT | ERR_ALERT;
483 msg = "not enough free sockets (raise '-n' parameter)";
484 goto tcp_close_return;
485 }
486
Willy Tarreaufb14edc2009-06-14 15:24:37 +0200487 if (fcntl(fd, F_SETFL, O_NONBLOCK) == -1) {
Willy Tarreaue6b98942007-10-29 01:09:36 +0100488 err |= ERR_FATAL | ERR_ALERT;
489 msg = "cannot make socket non-blocking";
490 goto tcp_close_return;
491 }
492
493 if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (char *) &one, sizeof(one)) == -1) {
494 /* not fatal but should be reported */
495 msg = "cannot do so_reuseaddr";
496 err |= ERR_ALERT;
497 }
498
499 if (listener->options & LI_O_NOLINGER)
500 setsockopt(fd, SOL_SOCKET, SO_LINGER, (struct linger *) &nolinger, sizeof(struct linger));
Willy Tarreauedcf6682008-11-30 23:15:34 +0100501
Willy Tarreaue6b98942007-10-29 01:09:36 +0100502#ifdef SO_REUSEPORT
503 /* OpenBSD supports this. As it's present in old libc versions of Linux,
504 * it might return an error that we will silently ignore.
505 */
506 setsockopt(fd, SOL_SOCKET, SO_REUSEPORT, (char *) &one, sizeof(one));
507#endif
Willy Tarreaub1e52e82008-01-13 14:49:51 +0100508#ifdef CONFIG_HAP_LINUX_TPROXY
Willy Tarreauedcf6682008-11-30 23:15:34 +0100509 if ((listener->options & LI_O_FOREIGN)
Willy Tarreau0a459892008-01-13 17:37:16 +0100510 && (setsockopt(fd, SOL_IP, IP_TRANSPARENT, (char *) &one, sizeof(one)) == -1)
511 && (setsockopt(fd, SOL_IP, IP_FREEBIND, (char *) &one, sizeof(one)) == -1)) {
Willy Tarreaub1e52e82008-01-13 14:49:51 +0100512 msg = "cannot make listening socket transparent";
513 err |= ERR_ALERT;
514 }
515#endif
Willy Tarreau5e6e2042009-02-04 17:19:29 +0100516#ifdef SO_BINDTODEVICE
517 /* Note: this might fail if not CAP_NET_RAW */
518 if (listener->interface) {
519 if (setsockopt(fd, SOL_SOCKET, SO_BINDTODEVICE,
Willy Tarreau604e8302009-03-06 00:48:23 +0100520 listener->interface, strlen(listener->interface) + 1) == -1) {
Willy Tarreau5e6e2042009-02-04 17:19:29 +0100521 msg = "cannot bind listener to device";
522 err |= ERR_WARN;
523 }
524 }
525#endif
Dmitry Sivachenkocaf58982009-08-24 15:11:06 +0400526#if defined(TCP_MAXSEG)
Willy Tarreau48a7e722010-12-24 15:26:39 +0100527 if (listener->maxseg > 0) {
Dmitry Sivachenkocaf58982009-08-24 15:11:06 +0400528 if (setsockopt(fd, IPPROTO_TCP, TCP_MAXSEG,
Willy Tarreaube1b9182009-06-14 18:48:19 +0200529 &listener->maxseg, sizeof(listener->maxseg)) == -1) {
530 msg = "cannot set MSS";
531 err |= ERR_WARN;
532 }
533 }
534#endif
Willy Tarreaucb6cd432009-10-13 07:34:14 +0200535#if defined(TCP_DEFER_ACCEPT)
536 if (listener->options & LI_O_DEF_ACCEPT) {
537 /* defer accept by up to one second */
538 int accept_delay = 1;
539 if (setsockopt(fd, IPPROTO_TCP, TCP_DEFER_ACCEPT, &accept_delay, sizeof(accept_delay)) == -1) {
540 msg = "cannot enable DEFER_ACCEPT";
541 err |= ERR_WARN;
542 }
543 }
544#endif
Willy Tarreaue6b98942007-10-29 01:09:36 +0100545 if (bind(fd, (struct sockaddr *)&listener->addr, listener->proto->sock_addrlen) == -1) {
546 err |= ERR_RETRYABLE | ERR_ALERT;
547 msg = "cannot bind socket";
548 goto tcp_close_return;
549 }
Willy Tarreauedcf6682008-11-30 23:15:34 +0100550
Willy Tarreauc73ce2b2008-01-06 10:55:10 +0100551 if (listen(fd, listener->backlog ? listener->backlog : listener->maxconn) == -1) {
Willy Tarreaue6b98942007-10-29 01:09:36 +0100552 err |= ERR_RETRYABLE | ERR_ALERT;
553 msg = "cannot listen to socket";
554 goto tcp_close_return;
555 }
Willy Tarreauedcf6682008-11-30 23:15:34 +0100556
Dmitry Sivachenkocaf58982009-08-24 15:11:06 +0400557#if defined(TCP_QUICKACK)
Willy Tarreau9ea05a72009-06-14 12:07:01 +0200558 if (listener->options & LI_O_NOQUICKACK)
Dmitry Sivachenkocaf58982009-08-24 15:11:06 +0400559 setsockopt(fd, IPPROTO_TCP, TCP_QUICKACK, (char *) &zero, sizeof(zero));
Willy Tarreau9ea05a72009-06-14 12:07:01 +0200560#endif
561
Willy Tarreaue6b98942007-10-29 01:09:36 +0100562 /* the socket is ready */
563 listener->fd = fd;
564 listener->state = LI_LISTEN;
565
Willy Tarreaueabf3132008-08-29 23:36:51 +0200566 fdtab[fd].owner = listener; /* reference the listener instead of a task */
Willy Tarreaue6b98942007-10-29 01:09:36 +0100567 fdtab[fd].state = FD_STLISTEN;
Willy Tarreaueb472682010-05-28 18:46:57 +0200568 fdtab[fd].flags = FD_FL_TCP | ((listener->options & LI_O_NOLINGER) ? FD_FL_TCP_NOLING : 0);
569 fdtab[fd].cb[DIR_RD].f = listener->proto->accept;
570 fdtab[fd].cb[DIR_WR].f = NULL; /* never called */
571 fdtab[fd].cb[DIR_RD].b = fdtab[fd].cb[DIR_WR].b = NULL;
Willy Tarreau5d707e12009-06-28 11:09:07 +0200572
Willy Tarreau8d5d77e2009-10-18 07:25:52 +0200573 fdinfo[fd].peeraddr = NULL;
574 fdinfo[fd].peerlen = 0;
Willy Tarreaueb472682010-05-28 18:46:57 +0200575 fd_insert(fd);
576
Willy Tarreaue6b98942007-10-29 01:09:36 +0100577 tcp_return:
Cyril Bonté43ba1b32010-11-01 19:26:01 +0100578 if (msg && errlen) {
579 char pn[INET6_ADDRSTRLEN];
580
581 if (listener->addr.ss_family == AF_INET) {
582 inet_ntop(AF_INET,
583 (const void *)&((struct sockaddr_in *)&listener->addr)->sin_addr,
584 pn, sizeof(pn));
585 snprintf(errmsg, errlen, "%s [%s:%d]", msg, pn, ntohs(((struct sockaddr_in *)&listener->addr)->sin_port));
586 }
587 else {
588 inet_ntop(AF_INET6,
589 (const void *)&((struct sockaddr_in6 *)(&listener->addr))->sin6_addr,
590 pn, sizeof(pn));
591 snprintf(errmsg, errlen, "%s [%s:%d]", msg, pn, ntohs(((struct sockaddr_in6 *)&listener->addr)->sin6_port));
592 }
593 }
Willy Tarreaue6b98942007-10-29 01:09:36 +0100594 return err;
595
596 tcp_close_return:
597 close(fd);
598 goto tcp_return;
599}
600
601/* This function creates all TCP sockets bound to the protocol entry <proto>.
602 * It is intended to be used as the protocol's bind_all() function.
603 * The sockets will be registered but not added to any fd_set, in order not to
604 * loose them across the fork(). A call to enable_all_listeners() is needed
605 * to complete initialization. The return value is composed from ERR_*.
606 */
Emeric Bruncf20bf12010-10-22 16:06:11 +0200607static int tcp_bind_listeners(struct protocol *proto, char *errmsg, int errlen)
Willy Tarreaue6b98942007-10-29 01:09:36 +0100608{
609 struct listener *listener;
610 int err = ERR_NONE;
611
612 list_for_each_entry(listener, &proto->listeners, proto_list) {
Emeric Bruncf20bf12010-10-22 16:06:11 +0200613 err |= tcp_bind_listener(listener, errmsg, errlen);
614 if (err & ERR_ABORT)
Willy Tarreaue6b98942007-10-29 01:09:36 +0100615 break;
616 }
617
618 return err;
619}
620
621/* Add listener to the list of tcpv4 listeners. The listener's state
622 * is automatically updated from LI_INIT to LI_ASSIGNED. The number of
623 * listeners is updated. This is the function to use to add a new listener.
624 */
625void tcpv4_add_listener(struct listener *listener)
626{
627 if (listener->state != LI_INIT)
628 return;
629 listener->state = LI_ASSIGNED;
630 listener->proto = &proto_tcpv4;
631 LIST_ADDQ(&proto_tcpv4.listeners, &listener->proto_list);
632 proto_tcpv4.nb_listeners++;
633}
634
635/* Add listener to the list of tcpv4 listeners. The listener's state
636 * is automatically updated from LI_INIT to LI_ASSIGNED. The number of
637 * listeners is updated. This is the function to use to add a new listener.
638 */
639void tcpv6_add_listener(struct listener *listener)
640{
641 if (listener->state != LI_INIT)
642 return;
643 listener->state = LI_ASSIGNED;
644 listener->proto = &proto_tcpv6;
645 LIST_ADDQ(&proto_tcpv6.listeners, &listener->proto_list);
646 proto_tcpv6.nb_listeners++;
647}
648
Willy Tarreauedcf6682008-11-30 23:15:34 +0100649/* This function performs the TCP request analysis on the current request. It
650 * returns 1 if the processing can continue on next analysers, or zero if it
651 * needs more data, encounters an error, or wants to immediately abort the
Willy Tarreaufb356202010-08-03 14:02:05 +0200652 * request. It relies on buffers flags, and updates s->req->analysers. The
653 * function may be called for frontend rules and backend rules. It only relies
654 * on the backend pointer so this works for both cases.
Willy Tarreauedcf6682008-11-30 23:15:34 +0100655 */
Willy Tarreau3a816292009-07-07 10:55:49 +0200656int tcp_inspect_request(struct session *s, struct buffer *req, int an_bit)
Willy Tarreauedcf6682008-11-30 23:15:34 +0100657{
658 struct tcp_rule *rule;
Willy Tarreaud1f96522010-08-03 19:34:32 +0200659 struct stksess *ts;
660 struct stktable *t;
Willy Tarreauedcf6682008-11-30 23:15:34 +0100661 int partial;
662
663 DPRINTF(stderr,"[%u] %s: session=%p b=%p, exp(r,w)=%u,%u bf=%08x bl=%d analysers=%02x\n",
664 now_ms, __FUNCTION__,
665 s,
666 req,
667 req->rex, req->wex,
668 req->flags,
669 req->l,
670 req->analysers);
671
Willy Tarreauedcf6682008-11-30 23:15:34 +0100672 /* We don't know whether we have enough data, so must proceed
673 * this way :
674 * - iterate through all rules in their declaration order
675 * - if one rule returns MISS, it means the inspect delay is
676 * not over yet, then return immediately, otherwise consider
677 * it as a non-match.
678 * - if one rule returns OK, then return OK
679 * - if one rule returns KO, then return KO
680 */
681
Willy Tarreaub824b002010-09-29 16:36:16 +0200682 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 +0100683 partial = 0;
684 else
685 partial = ACL_PARTIAL;
686
Willy Tarreaufb356202010-08-03 14:02:05 +0200687 list_for_each_entry(rule, &s->be->tcp_req.inspect_rules, list) {
Willy Tarreauedcf6682008-11-30 23:15:34 +0100688 int ret = ACL_PAT_PASS;
689
690 if (rule->cond) {
Willy Tarreaufb356202010-08-03 14:02:05 +0200691 ret = acl_exec_cond(rule->cond, s->be, s, &s->txn, ACL_DIR_REQ | partial);
Willy Tarreauedcf6682008-11-30 23:15:34 +0100692 if (ret == ACL_PAT_MISS) {
Willy Tarreau520d95e2009-09-19 21:04:57 +0200693 buffer_dont_connect(req);
Willy Tarreauedcf6682008-11-30 23:15:34 +0100694 /* just set the request timeout once at the beginning of the request */
Willy Tarreaufb356202010-08-03 14:02:05 +0200695 if (!tick_isset(req->analyse_exp) && s->be->tcp_req.inspect_delay)
696 req->analyse_exp = tick_add_ifset(now_ms, s->be->tcp_req.inspect_delay);
Willy Tarreauedcf6682008-11-30 23:15:34 +0100697 return 0;
698 }
699
700 ret = acl_pass(ret);
701 if (rule->cond->pol == ACL_COND_UNLESS)
702 ret = !ret;
703 }
704
705 if (ret) {
706 /* we have a matching rule. */
707 if (rule->action == TCP_ACT_REJECT) {
708 buffer_abort(req);
709 buffer_abort(s->rep);
710 req->analysers = 0;
Krzysztof Piotr Oledzkiaeebf9b2009-10-04 15:43:17 +0200711
Willy Tarreaufb356202010-08-03 14:02:05 +0200712 s->be->counters.denied_req++;
Krzysztof Piotr Oledzkiaeebf9b2009-10-04 15:43:17 +0200713 if (s->listener->counters)
Willy Tarreau23968d82010-05-23 23:50:44 +0200714 s->listener->counters->denied_req++;
Krzysztof Piotr Oledzkiaeebf9b2009-10-04 15:43:17 +0200715
Willy Tarreauedcf6682008-11-30 23:15:34 +0100716 if (!(s->flags & SN_ERR_MASK))
717 s->flags |= SN_ERR_PRXCOND;
718 if (!(s->flags & SN_FINST_MASK))
719 s->flags |= SN_FINST_R;
720 return 0;
721 }
Willy Tarreau56123282010-08-06 19:06:56 +0200722 else if (rule->action == TCP_ACT_TRK_SC1) {
723 if (!s->stkctr1_entry) {
724 /* only the first valid track-sc1 directive applies.
Willy Tarreaud1f96522010-08-03 19:34:32 +0200725 * Also, note that right now we can only track SRC so we
726 * don't check how to get the key, but later we may need
727 * to consider rule->act_prm->trk_ctr.type.
728 */
729 t = rule->act_prm.trk_ctr.table.t;
730 ts = stktable_get_entry(t, tcpv4_src_to_stktable_key(s));
Willy Tarreau0a4838c2010-08-06 20:11:05 +0200731 if (ts) {
Willy Tarreau56123282010-08-06 19:06:56 +0200732 session_track_stkctr1(s, t, ts);
Willy Tarreau0a4838c2010-08-06 20:11:05 +0200733 if (s->fe != s->be)
734 s->flags |= SN_BE_TRACK_SC1;
735 }
Willy Tarreaud1f96522010-08-03 19:34:32 +0200736 }
737 }
Willy Tarreau56123282010-08-06 19:06:56 +0200738 else if (rule->action == TCP_ACT_TRK_SC2) {
739 if (!s->stkctr2_entry) {
740 /* only the first valid track-sc2 directive applies.
Willy Tarreaud1f96522010-08-03 19:34:32 +0200741 * Also, note that right now we can only track SRC so we
742 * don't check how to get the key, but later we may need
743 * to consider rule->act_prm->trk_ctr.type.
744 */
745 t = rule->act_prm.trk_ctr.table.t;
746 ts = stktable_get_entry(t, tcpv4_src_to_stktable_key(s));
Willy Tarreau0a4838c2010-08-06 20:11:05 +0200747 if (ts) {
Willy Tarreau56123282010-08-06 19:06:56 +0200748 session_track_stkctr2(s, t, ts);
Willy Tarreau0a4838c2010-08-06 20:11:05 +0200749 if (s->fe != s->be)
750 s->flags |= SN_BE_TRACK_SC2;
751 }
Willy Tarreaud1f96522010-08-03 19:34:32 +0200752 }
753 }
754 else {
Willy Tarreauedcf6682008-11-30 23:15:34 +0100755 /* otherwise accept */
Willy Tarreaud1f96522010-08-03 19:34:32 +0200756 break;
757 }
Willy Tarreauedcf6682008-11-30 23:15:34 +0100758 }
759 }
760
761 /* if we get there, it means we have no rule which matches, or
762 * we have an explicit accept, so we apply the default accept.
763 */
Willy Tarreau3a816292009-07-07 10:55:49 +0200764 req->analysers &= ~an_bit;
Willy Tarreauedcf6682008-11-30 23:15:34 +0100765 req->analyse_exp = TICK_ETERNITY;
766 return 1;
767}
768
Emeric Brun97679e72010-09-23 17:56:44 +0200769/* This function performs the TCP response analysis on the current response. It
770 * returns 1 if the processing can continue on next analysers, or zero if it
771 * needs more data, encounters an error, or wants to immediately abort the
772 * response. It relies on buffers flags, and updates s->rep->analysers. The
773 * function may be called for backend rules.
774 */
775int tcp_inspect_response(struct session *s, struct buffer *rep, int an_bit)
776{
777 struct tcp_rule *rule;
778 int partial;
779
780 DPRINTF(stderr,"[%u] %s: session=%p b=%p, exp(r,w)=%u,%u bf=%08x bl=%d analysers=%02x\n",
781 now_ms, __FUNCTION__,
782 s,
783 rep,
784 rep->rex, rep->wex,
785 rep->flags,
786 rep->l,
787 rep->analysers);
788
789 /* We don't know whether we have enough data, so must proceed
790 * this way :
791 * - iterate through all rules in their declaration order
792 * - if one rule returns MISS, it means the inspect delay is
793 * not over yet, then return immediately, otherwise consider
794 * it as a non-match.
795 * - if one rule returns OK, then return OK
796 * - if one rule returns KO, then return KO
797 */
798
799 if (rep->flags & BF_SHUTR || tick_is_expired(rep->analyse_exp, now_ms))
800 partial = 0;
801 else
802 partial = ACL_PARTIAL;
803
804 list_for_each_entry(rule, &s->be->tcp_rep.inspect_rules, list) {
805 int ret = ACL_PAT_PASS;
806
807 if (rule->cond) {
808 ret = acl_exec_cond(rule->cond, s->be, s, &s->txn, ACL_DIR_RTR | partial);
809 if (ret == ACL_PAT_MISS) {
810 /* just set the analyser timeout once at the beginning of the response */
811 if (!tick_isset(rep->analyse_exp) && s->be->tcp_rep.inspect_delay)
812 rep->analyse_exp = tick_add_ifset(now_ms, s->be->tcp_rep.inspect_delay);
813 return 0;
814 }
815
816 ret = acl_pass(ret);
817 if (rule->cond->pol == ACL_COND_UNLESS)
818 ret = !ret;
819 }
820
821 if (ret) {
822 /* we have a matching rule. */
823 if (rule->action == TCP_ACT_REJECT) {
824 buffer_abort(rep);
825 buffer_abort(s->req);
826 rep->analysers = 0;
827
828 s->be->counters.denied_resp++;
829 if (s->listener->counters)
830 s->listener->counters->denied_resp++;
831
832 if (!(s->flags & SN_ERR_MASK))
833 s->flags |= SN_ERR_PRXCOND;
834 if (!(s->flags & SN_FINST_MASK))
835 s->flags |= SN_FINST_D;
836 return 0;
837 }
838 else {
839 /* otherwise accept */
840 break;
841 }
842 }
843 }
844
845 /* if we get there, it means we have no rule which matches, or
846 * we have an explicit accept, so we apply the default accept.
847 */
848 rep->analysers &= ~an_bit;
849 rep->analyse_exp = TICK_ETERNITY;
850 return 1;
851}
852
853
Willy Tarreaua5c0ab22010-05-31 10:30:33 +0200854/* This function performs the TCP layer4 analysis on the current request. It
855 * returns 0 if a reject rule matches, otherwise 1 if either an accept rule
856 * matches or if no more rule matches. It can only use rules which don't need
857 * any data.
858 */
859int tcp_exec_req_rules(struct session *s)
860{
861 struct tcp_rule *rule;
Willy Tarreauf059a0f2010-08-03 16:29:52 +0200862 struct stksess *ts;
Willy Tarreau9ba2dcc2010-06-14 21:04:55 +0200863 struct stktable *t = NULL;
864 int result = 1;
Willy Tarreaua5c0ab22010-05-31 10:30:33 +0200865 int ret;
866
867 list_for_each_entry(rule, &s->fe->tcp_req.l4_rules, list) {
868 ret = ACL_PAT_PASS;
869
870 if (rule->cond) {
871 ret = acl_exec_cond(rule->cond, s->fe, s, NULL, ACL_DIR_REQ);
872 ret = acl_pass(ret);
873 if (rule->cond->pol == ACL_COND_UNLESS)
874 ret = !ret;
875 }
876
877 if (ret) {
878 /* we have a matching rule. */
879 if (rule->action == TCP_ACT_REJECT) {
Willy Tarreau2799e982010-06-05 15:43:21 +0200880 s->fe->counters.denied_conn++;
Willy Tarreaua5c0ab22010-05-31 10:30:33 +0200881 if (s->listener->counters)
Willy Tarreau2799e982010-06-05 15:43:21 +0200882 s->listener->counters->denied_conn++;
Willy Tarreaua5c0ab22010-05-31 10:30:33 +0200883
884 if (!(s->flags & SN_ERR_MASK))
885 s->flags |= SN_ERR_PRXCOND;
886 if (!(s->flags & SN_FINST_MASK))
887 s->flags |= SN_FINST_R;
Willy Tarreau9ba2dcc2010-06-14 21:04:55 +0200888 result = 0;
889 break;
Willy Tarreaua5c0ab22010-05-31 10:30:33 +0200890 }
Willy Tarreau56123282010-08-06 19:06:56 +0200891 else if (rule->action == TCP_ACT_TRK_SC1) {
892 if (!s->stkctr1_entry) {
893 /* only the first valid track-sc1 directive applies.
Willy Tarreau9ba2dcc2010-06-14 21:04:55 +0200894 * Also, note that right now we can only track SRC so we
895 * don't check how to get the key, but later we may need
896 * to consider rule->act_prm->trk_ctr.type.
897 */
898 t = rule->act_prm.trk_ctr.table.t;
899 ts = stktable_get_entry(t, tcpv4_src_to_stktable_key(s));
900 if (ts)
Willy Tarreau56123282010-08-06 19:06:56 +0200901 session_track_stkctr1(s, t, ts);
Willy Tarreau9ba2dcc2010-06-14 21:04:55 +0200902 }
903 }
Willy Tarreau56123282010-08-06 19:06:56 +0200904 else if (rule->action == TCP_ACT_TRK_SC2) {
905 if (!s->stkctr2_entry) {
906 /* only the first valid track-sc2 directive applies.
Willy Tarreauf059a0f2010-08-03 16:29:52 +0200907 * Also, note that right now we can only track SRC so we
908 * don't check how to get the key, but later we may need
909 * to consider rule->act_prm->trk_ctr.type.
910 */
911 t = rule->act_prm.trk_ctr.table.t;
912 ts = stktable_get_entry(t, tcpv4_src_to_stktable_key(s));
913 if (ts)
Willy Tarreau56123282010-08-06 19:06:56 +0200914 session_track_stkctr2(s, t, ts);
Willy Tarreauf059a0f2010-08-03 16:29:52 +0200915 }
916 }
Willy Tarreau9ba2dcc2010-06-14 21:04:55 +0200917 else {
918 /* otherwise it's an accept */
919 break;
920 }
Willy Tarreaua5c0ab22010-05-31 10:30:33 +0200921 }
922 }
Willy Tarreau9ba2dcc2010-06-14 21:04:55 +0200923 return result;
Willy Tarreaua5c0ab22010-05-31 10:30:33 +0200924}
925
Emeric Brun97679e72010-09-23 17:56:44 +0200926/* Parse a tcp-response rule. Return a negative value in case of failure */
927static int tcp_parse_response_rule(char **args, int arg, int section_type,
928 struct proxy *curpx, struct proxy *defpx,
929 struct tcp_rule *rule, char *err, int errlen)
930{
931 if (curpx == defpx || !(curpx->cap & PR_CAP_BE)) {
932 snprintf(err, errlen, "%s %s is only allowed in 'backend' sections",
933 args[0], args[1]);
934 return -1;
935 }
936
937 if (strcmp(args[arg], "accept") == 0) {
938 arg++;
939 rule->action = TCP_ACT_ACCEPT;
940 }
941 else if (strcmp(args[arg], "reject") == 0) {
942 arg++;
943 rule->action = TCP_ACT_REJECT;
944 }
945 else {
946 snprintf(err, errlen,
947 "'%s %s' expects 'accept' or 'reject' in %s '%s' (was '%s')",
948 args[0], args[1], proxy_type_str(curpx), curpx->id, args[arg]);
949 return -1;
950 }
951
952 if (strcmp(args[arg], "if") == 0 || strcmp(args[arg], "unless") == 0) {
953 if ((rule->cond = build_acl_cond(NULL, 0, curpx, (const char **)args+arg)) == NULL) {
954 snprintf(err, errlen,
955 "error detected in %s '%s' while parsing '%s' condition",
956 proxy_type_str(curpx), curpx->id, args[arg]);
957 return -1;
958 }
959 }
960 else if (*args[arg]) {
961 snprintf(err, errlen,
962 "'%s %s %s' only accepts 'if' or 'unless', in %s '%s' (was '%s')",
963 args[0], args[1], args[2], proxy_type_str(curpx), curpx->id, args[arg]);
964 return -1;
965 }
966 return 0;
967}
968
969
970
Willy Tarreau68c03ab2010-08-06 15:08:45 +0200971/* Parse a tcp-request rule. Return a negative value in case of failure */
972static int tcp_parse_request_rule(char **args, int arg, int section_type,
973 struct proxy *curpx, struct proxy *defpx,
974 struct tcp_rule *rule, char *err, int errlen)
975{
976 if (curpx == defpx) {
977 snprintf(err, errlen, "%s %s is not allowed in 'defaults' sections",
978 args[0], args[1]);
979 return -1;
980 }
981
982 if (!strcmp(args[arg], "accept")) {
983 arg++;
984 rule->action = TCP_ACT_ACCEPT;
985 }
986 else if (!strcmp(args[arg], "reject")) {
987 arg++;
988 rule->action = TCP_ACT_REJECT;
989 }
Willy Tarreau56123282010-08-06 19:06:56 +0200990 else if (strcmp(args[arg], "track-sc1") == 0) {
Willy Tarreau68c03ab2010-08-06 15:08:45 +0200991 int ret;
992
993 arg++;
994 ret = parse_track_counters(args, &arg, section_type, curpx,
995 &rule->act_prm.trk_ctr, defpx, err, errlen);
996
997 if (ret < 0) /* nb: warnings are not handled yet */
998 return -1;
999
Willy Tarreau56123282010-08-06 19:06:56 +02001000 rule->action = TCP_ACT_TRK_SC1;
Willy Tarreau68c03ab2010-08-06 15:08:45 +02001001 }
Willy Tarreau56123282010-08-06 19:06:56 +02001002 else if (strcmp(args[arg], "track-sc2") == 0) {
Willy Tarreau68c03ab2010-08-06 15:08:45 +02001003 int ret;
1004
1005 arg++;
1006 ret = parse_track_counters(args, &arg, section_type, curpx,
1007 &rule->act_prm.trk_ctr, defpx, err, errlen);
1008
1009 if (ret < 0) /* nb: warnings are not handled yet */
1010 return -1;
1011
Willy Tarreau56123282010-08-06 19:06:56 +02001012 rule->action = TCP_ACT_TRK_SC2;
Willy Tarreau68c03ab2010-08-06 15:08:45 +02001013 }
1014 else {
1015 snprintf(err, errlen,
Willy Tarreau56123282010-08-06 19:06:56 +02001016 "'%s %s' expects 'accept', 'reject', 'track-sc1' "
1017 "or 'track-sc2' in %s '%s' (was '%s')",
Willy Tarreau68c03ab2010-08-06 15:08:45 +02001018 args[0], args[1], proxy_type_str(curpx), curpx->id, args[arg]);
1019 return -1;
1020 }
1021
1022 if (strcmp(args[arg], "if") == 0 || strcmp(args[arg], "unless") == 0) {
1023 if ((rule->cond = build_acl_cond(NULL, 0, curpx, (const char **)args+arg)) == NULL) {
1024 snprintf(err, errlen,
1025 "error detected in %s '%s' while parsing '%s' condition",
1026 proxy_type_str(curpx), curpx->id, args[arg]);
1027 return -1;
1028 }
1029 }
1030 else if (*args[arg]) {
1031 snprintf(err, errlen,
1032 "'%s %s %s' only accepts 'if' or 'unless', in %s '%s' (was '%s')",
1033 args[0], args[1], args[2], proxy_type_str(curpx), curpx->id, args[arg]);
1034 return -1;
1035 }
1036 return 0;
1037}
1038
Emeric Brun97679e72010-09-23 17:56:44 +02001039/* This function should be called to parse a line starting with the "tcp-response"
1040 * keyword.
1041 */
1042static int tcp_parse_tcp_rep(char **args, int section_type, struct proxy *curpx,
1043 struct proxy *defpx, char *err, int errlen)
1044{
1045 const char *ptr = NULL;
1046 unsigned int val;
1047 int retlen;
1048 int warn = 0;
1049 int arg;
1050 struct tcp_rule *rule;
1051
1052 if (!*args[1]) {
1053 snprintf(err, errlen, "missing argument for '%s' in %s '%s'",
1054 args[0], proxy_type_str(curpx), curpx->id);
1055 return -1;
1056 }
1057
1058 if (strcmp(args[1], "inspect-delay") == 0) {
1059 if (curpx == defpx || !(curpx->cap & PR_CAP_BE)) {
1060 snprintf(err, errlen, "%s %s is only allowed in 'backend' sections",
1061 args[0], args[1]);
1062 return -1;
1063 }
1064
1065 if (!*args[2] || (ptr = parse_time_err(args[2], &val, TIME_UNIT_MS))) {
1066 retlen = snprintf(err, errlen,
1067 "'%s %s' expects a positive delay in milliseconds, in %s '%s'",
1068 args[0], args[1], proxy_type_str(curpx), curpx->id);
1069 if (ptr && retlen < errlen)
1070 retlen += snprintf(err + retlen, errlen - retlen,
1071 " (unexpected character '%c')", *ptr);
1072 return -1;
1073 }
1074
1075 if (curpx->tcp_rep.inspect_delay) {
1076 snprintf(err, errlen, "ignoring %s %s (was already defined) in %s '%s'",
1077 args[0], args[1], proxy_type_str(curpx), curpx->id);
1078 return 1;
1079 }
1080 curpx->tcp_rep.inspect_delay = val;
1081 return 0;
1082 }
1083
1084 rule = (struct tcp_rule *)calloc(1, sizeof(*rule));
1085 LIST_INIT(&rule->list);
1086 arg = 1;
1087
1088 if (strcmp(args[1], "content") == 0) {
1089 arg++;
1090 if (tcp_parse_response_rule(args, arg, section_type, curpx, defpx, rule, err, errlen) < 0)
1091 goto error;
1092
1093 if (rule->cond && (rule->cond->requires & ACL_USE_L6REQ_VOLATILE)) {
1094 struct acl *acl;
1095 const char *name;
1096
1097 acl = cond_find_require(rule->cond, ACL_USE_L6REQ_VOLATILE);
1098 name = acl ? acl->name : "(unknown)";
1099
1100 retlen = snprintf(err, errlen,
1101 "acl '%s' involves some request-only criteria which will be ignored.",
1102 name);
1103 warn++;
1104 }
1105
1106 LIST_ADDQ(&curpx->tcp_rep.inspect_rules, &rule->list);
1107 }
1108 else {
1109 retlen = snprintf(err, errlen,
1110 "'%s' expects 'inspect-delay' or 'content' in %s '%s' (was '%s')",
1111 args[0], proxy_type_str(curpx), curpx->id, args[1]);
1112 goto error;
1113 }
1114
1115 return warn;
1116 error:
1117 free(rule);
1118 return -1;
1119}
1120
1121
Willy Tarreaub6866442008-07-14 23:54:42 +02001122/* This function should be called to parse a line starting with the "tcp-request"
1123 * keyword.
1124 */
1125static int tcp_parse_tcp_req(char **args, int section_type, struct proxy *curpx,
1126 struct proxy *defpx, char *err, int errlen)
1127{
1128 const char *ptr = NULL;
Willy Tarreauc7e961e2008-08-17 17:13:47 +02001129 unsigned int val;
Willy Tarreaub6866442008-07-14 23:54:42 +02001130 int retlen;
Willy Tarreau1a687942010-05-23 22:40:30 +02001131 int warn = 0;
Willy Tarreau6a984fa2010-06-14 16:44:27 +02001132 int arg;
Willy Tarreau1a687942010-05-23 22:40:30 +02001133 struct tcp_rule *rule;
Willy Tarreaub6866442008-07-14 23:54:42 +02001134
1135 if (!*args[1]) {
1136 snprintf(err, errlen, "missing argument for '%s' in %s '%s'",
Willy Tarreauf5356832010-06-14 18:40:26 +02001137 args[0], proxy_type_str(curpx), curpx->id);
Willy Tarreaub6866442008-07-14 23:54:42 +02001138 return -1;
1139 }
1140
1141 if (!strcmp(args[1], "inspect-delay")) {
1142 if (curpx == defpx) {
1143 snprintf(err, errlen, "%s %s is not allowed in 'defaults' sections",
1144 args[0], args[1]);
1145 return -1;
1146 }
1147
Willy Tarreaub6866442008-07-14 23:54:42 +02001148 if (!*args[2] || (ptr = parse_time_err(args[2], &val, TIME_UNIT_MS))) {
1149 retlen = snprintf(err, errlen,
1150 "'%s %s' expects a positive delay in milliseconds, in %s '%s'",
Willy Tarreauf5356832010-06-14 18:40:26 +02001151 args[0], args[1], proxy_type_str(curpx), curpx->id);
Willy Tarreaub6866442008-07-14 23:54:42 +02001152 if (ptr && retlen < errlen)
1153 retlen += snprintf(err+retlen, errlen - retlen,
1154 " (unexpected character '%c')", *ptr);
1155 return -1;
1156 }
1157
1158 if (curpx->tcp_req.inspect_delay) {
1159 snprintf(err, errlen, "ignoring %s %s (was already defined) in %s '%s'",
Willy Tarreauf5356832010-06-14 18:40:26 +02001160 args[0], args[1], proxy_type_str(curpx), curpx->id);
Willy Tarreaub6866442008-07-14 23:54:42 +02001161 return 1;
1162 }
1163 curpx->tcp_req.inspect_delay = val;
1164 return 0;
1165 }
1166
Willy Tarreau6a984fa2010-06-14 16:44:27 +02001167 rule = (struct tcp_rule *)calloc(1, sizeof(*rule));
Willy Tarreaufb024dc2010-08-20 13:35:41 +02001168 LIST_INIT(&rule->list);
Willy Tarreau6a984fa2010-06-14 16:44:27 +02001169 arg = 1;
1170
Willy Tarreau68c03ab2010-08-06 15:08:45 +02001171 if (strcmp(args[1], "content") == 0) {
Willy Tarreaud1f96522010-08-03 19:34:32 +02001172 arg++;
Willy Tarreau68c03ab2010-08-06 15:08:45 +02001173 if (tcp_parse_request_rule(args, arg, section_type, curpx, defpx, rule, err, errlen) < 0)
Willy Tarreau6a984fa2010-06-14 16:44:27 +02001174 goto error;
Willy Tarreaub6866442008-07-14 23:54:42 +02001175
Willy Tarreau6a984fa2010-06-14 16:44:27 +02001176 if (rule->cond && (rule->cond->requires & ACL_USE_RTR_ANY)) {
Willy Tarreaudd64f8d2008-07-27 22:02:32 +02001177 struct acl *acl;
1178 const char *name;
1179
Willy Tarreau6a984fa2010-06-14 16:44:27 +02001180 acl = cond_find_require(rule->cond, ACL_USE_RTR_ANY);
Willy Tarreaudd64f8d2008-07-27 22:02:32 +02001181 name = acl ? acl->name : "(unknown)";
1182
1183 retlen = snprintf(err, errlen,
Willy Tarreau1a211942009-07-14 13:53:17 +02001184 "acl '%s' involves some response-only criteria which will be ignored.",
1185 name);
Willy Tarreaudd64f8d2008-07-27 22:02:32 +02001186 warn++;
1187 }
Willy Tarreaufb024dc2010-08-20 13:35:41 +02001188 LIST_ADDQ(&curpx->tcp_req.inspect_rules, &rule->list);
Willy Tarreau9ba2dcc2010-06-14 21:04:55 +02001189 }
Willy Tarreau68c03ab2010-08-06 15:08:45 +02001190 else if (strcmp(args[1], "connection") == 0) {
Willy Tarreau9ba2dcc2010-06-14 21:04:55 +02001191 arg++;
Willy Tarreau9ba2dcc2010-06-14 21:04:55 +02001192
Willy Tarreau68c03ab2010-08-06 15:08:45 +02001193 if (!(curpx->cap & PR_CAP_FE)) {
1194 snprintf(err, errlen, "%s %s is not allowed because %s %s is not a frontend",
1195 args[0], args[1], proxy_type_str(curpx), curpx->id);
1196 return -1;
1197 }
Willy Tarreau9ba2dcc2010-06-14 21:04:55 +02001198
Willy Tarreau68c03ab2010-08-06 15:08:45 +02001199 if (tcp_parse_request_rule(args, arg, section_type, curpx, defpx, rule, err, errlen) < 0)
Willy Tarreau9ba2dcc2010-06-14 21:04:55 +02001200 goto error;
1201
Willy Tarreau68c03ab2010-08-06 15:08:45 +02001202 if (rule->cond && (rule->cond->requires & (ACL_USE_RTR_ANY|ACL_USE_L6_ANY|ACL_USE_L7_ANY))) {
1203 struct acl *acl;
1204 const char *name;
Willy Tarreauf059a0f2010-08-03 16:29:52 +02001205
Willy Tarreau68c03ab2010-08-06 15:08:45 +02001206 acl = cond_find_require(rule->cond, ACL_USE_RTR_ANY|ACL_USE_L6_ANY|ACL_USE_L7_ANY);
1207 name = acl ? acl->name : "(unknown)";
Willy Tarreauf059a0f2010-08-03 16:29:52 +02001208
Willy Tarreau68c03ab2010-08-06 15:08:45 +02001209 if (acl->requires & (ACL_USE_L6_ANY|ACL_USE_L7_ANY)) {
1210 retlen = snprintf(err, errlen,
1211 "'%s %s' may not reference acl '%s' which makes use of "
1212 "payload in %s '%s'. Please use '%s content' for this.",
1213 args[0], args[1], name, proxy_type_str(curpx), curpx->id, args[0]);
1214 goto error;
1215 }
1216 if (acl->requires & ACL_USE_RTR_ANY)
1217 retlen = snprintf(err, errlen,
1218 "acl '%s' involves some response-only criteria which will be ignored.",
1219 name);
1220 warn++;
1221 }
Willy Tarreaufb024dc2010-08-20 13:35:41 +02001222 LIST_ADDQ(&curpx->tcp_req.l4_rules, &rule->list);
Willy Tarreau9ba2dcc2010-06-14 21:04:55 +02001223 }
Willy Tarreau1a687942010-05-23 22:40:30 +02001224 else {
1225 retlen = snprintf(err, errlen,
Willy Tarreau68c03ab2010-08-06 15:08:45 +02001226 "'%s' expects 'inspect-delay', 'connection', or 'content' in %s '%s' (was '%s')",
Willy Tarreau1a687942010-05-23 22:40:30 +02001227 args[0], proxy_type_str(curpx), curpx->id, args[1]);
Willy Tarreau6a984fa2010-06-14 16:44:27 +02001228 goto error;
Willy Tarreau1a687942010-05-23 22:40:30 +02001229 }
1230
Willy Tarreau1a687942010-05-23 22:40:30 +02001231 return warn;
Willy Tarreau6a984fa2010-06-14 16:44:27 +02001232 error:
1233 free(rule);
1234 return -1;
Willy Tarreaub6866442008-07-14 23:54:42 +02001235}
1236
Willy Tarreau645513a2010-05-24 20:55:15 +02001237
1238/************************************************************************/
1239/* All supported ACL keywords must be declared here. */
1240/************************************************************************/
1241
1242/* set test->ptr to point to the source IPv4/IPv6 address and test->i to the family */
1243static int
1244acl_fetch_src(struct proxy *px, struct session *l4, void *l7, int dir,
1245 struct acl_expr *expr, struct acl_test *test)
1246{
Willy Tarreau957c0a52011-03-03 17:42:23 +01001247 test->i = l4->si[0].addr.c.from.ss_family;
Willy Tarreau645513a2010-05-24 20:55:15 +02001248 if (test->i == AF_INET)
Willy Tarreau957c0a52011-03-03 17:42:23 +01001249 test->ptr = (void *)&((struct sockaddr_in *)&l4->si[0].addr.c.from)->sin_addr;
Emeric Brunf769f512010-10-22 17:14:01 +02001250 else if (test->i == AF_INET6)
Willy Tarreau957c0a52011-03-03 17:42:23 +01001251 test->ptr = (void *)&((struct sockaddr_in6 *)(&l4->si[0].addr.c.from))->sin6_addr;
Emeric Brunf769f512010-10-22 17:14:01 +02001252 else
1253 return 0;
1254
Willy Tarreau645513a2010-05-24 20:55:15 +02001255 test->flags = ACL_TEST_F_READ_ONLY;
1256 return 1;
1257}
1258
1259/* extract the connection's source address */
1260static int
1261pattern_fetch_src(struct proxy *px, struct session *l4, void *l7, int dir,
Emeric Brun485479d2010-09-23 18:02:19 +02001262 const struct pattern_arg *arg_p, int arg_i, union pattern_data *data)
Willy Tarreau645513a2010-05-24 20:55:15 +02001263{
Willy Tarreau957c0a52011-03-03 17:42:23 +01001264 if (l4->si[0].addr.c.from.ss_family != AF_INET )
Emeric Brunf769f512010-10-22 17:14:01 +02001265 return 0;
1266
Willy Tarreau957c0a52011-03-03 17:42:23 +01001267 data->ip.s_addr = ((struct sockaddr_in *)&l4->si[0].addr.c.from)->sin_addr.s_addr;
Willy Tarreau645513a2010-05-24 20:55:15 +02001268 return 1;
1269}
1270
1271
1272/* set test->i to the connection's source port */
1273static int
1274acl_fetch_sport(struct proxy *px, struct session *l4, void *l7, int dir,
1275 struct acl_expr *expr, struct acl_test *test)
1276{
Willy Tarreau957c0a52011-03-03 17:42:23 +01001277 if (l4->si[0].addr.c.from.ss_family == AF_INET)
1278 test->i = ntohs(((struct sockaddr_in *)&l4->si[0].addr.c.from)->sin_port);
1279 else if (l4->si[0].addr.c.from.ss_family == AF_INET6)
1280 test->i = ntohs(((struct sockaddr_in6 *)(&l4->si[0].addr.c.from))->sin6_port);
Emeric Brunf769f512010-10-22 17:14:01 +02001281 else
1282 return 0;
1283
Willy Tarreau645513a2010-05-24 20:55:15 +02001284 test->flags = 0;
1285 return 1;
1286}
1287
1288
1289/* set test->ptr to point to the frontend's IPv4/IPv6 address and test->i to the family */
1290static int
1291acl_fetch_dst(struct proxy *px, struct session *l4, void *l7, int dir,
1292 struct acl_expr *expr, struct acl_test *test)
1293{
1294 if (!(l4->flags & SN_FRT_ADDR_SET))
1295 get_frt_addr(l4);
1296
Willy Tarreau957c0a52011-03-03 17:42:23 +01001297 test->i = l4->si[0].addr.c.to.ss_family;
Willy Tarreau645513a2010-05-24 20:55:15 +02001298 if (test->i == AF_INET)
Willy Tarreau957c0a52011-03-03 17:42:23 +01001299 test->ptr = (void *)&((struct sockaddr_in *)&l4->si[0].addr.c.to)->sin_addr;
Emeric Brunf769f512010-10-22 17:14:01 +02001300 else if (test->i == AF_INET6)
Willy Tarreau957c0a52011-03-03 17:42:23 +01001301 test->ptr = (void *)&((struct sockaddr_in6 *)(&l4->si[0].addr.c.to))->sin6_addr;
Emeric Brunf769f512010-10-22 17:14:01 +02001302 else
1303 return 0;
1304
Willy Tarreau645513a2010-05-24 20:55:15 +02001305 test->flags = ACL_TEST_F_READ_ONLY;
1306 return 1;
1307}
1308
1309
1310/* extract the connection's destination address */
1311static int
1312pattern_fetch_dst(struct proxy *px, struct session *l4, void *l7, int dir,
Emeric Brun485479d2010-09-23 18:02:19 +02001313 const struct pattern_arg *arg_p, int arg_i, union pattern_data *data)
Willy Tarreau645513a2010-05-24 20:55:15 +02001314{
emeric8aa6b372010-10-22 17:06:26 +02001315 if (!(l4->flags & SN_FRT_ADDR_SET))
1316 get_frt_addr(l4);
1317
Willy Tarreau957c0a52011-03-03 17:42:23 +01001318 if (l4->si[0].addr.c.to.ss_family != AF_INET)
Emeric Brunf769f512010-10-22 17:14:01 +02001319 return 0;
1320
Willy Tarreau957c0a52011-03-03 17:42:23 +01001321 data->ip.s_addr = ((struct sockaddr_in *)&l4->si[0].addr.c.to)->sin_addr.s_addr;
Willy Tarreau645513a2010-05-24 20:55:15 +02001322 return 1;
1323}
1324
1325/* set test->i to the frontend connexion's destination port */
1326static int
1327acl_fetch_dport(struct proxy *px, struct session *l4, void *l7, int dir,
1328 struct acl_expr *expr, struct acl_test *test)
1329{
1330 if (!(l4->flags & SN_FRT_ADDR_SET))
1331 get_frt_addr(l4);
1332
Willy Tarreau957c0a52011-03-03 17:42:23 +01001333 if (l4->si[0].addr.c.to.ss_family == AF_INET)
1334 test->i = ntohs(((struct sockaddr_in *)&l4->si[0].addr.c.to)->sin_port);
1335 else if (l4->si[0].addr.c.to.ss_family == AF_INET6)
1336 test->i = ntohs(((struct sockaddr_in6 *)(&l4->si[0].addr.c.to))->sin6_port);
Emeric Brunf769f512010-10-22 17:14:01 +02001337 else
1338 return 0;
1339
Willy Tarreau645513a2010-05-24 20:55:15 +02001340 test->flags = 0;
1341 return 1;
1342}
1343
1344static int
1345pattern_fetch_dport(struct proxy *px, struct session *l4, void *l7, int dir,
Emeric Brun485479d2010-09-23 18:02:19 +02001346 const struct pattern_arg *arg, int i, union pattern_data *data)
Willy Tarreau645513a2010-05-24 20:55:15 +02001347{
emeric8aa6b372010-10-22 17:06:26 +02001348 if (!(l4->flags & SN_FRT_ADDR_SET))
1349 get_frt_addr(l4);
1350
Willy Tarreau957c0a52011-03-03 17:42:23 +01001351 if (l4->si[0].addr.c.to.ss_family != AF_INET)
Emeric Brunf769f512010-10-22 17:14:01 +02001352 return 0;
1353
Willy Tarreau957c0a52011-03-03 17:42:23 +01001354 data->integer = ntohs(((struct sockaddr_in *)&l4->si[0].addr.c.to)->sin_port);
Willy Tarreau645513a2010-05-24 20:55:15 +02001355 return 1;
1356}
1357
Emericf2d7cae2010-11-05 18:13:50 +01001358static int
1359pattern_arg_fetch_payloadlv(const char *arg, struct pattern_arg **arg_p, int *arg_i)
1360{
1361 int member = 0;
1362 int len_offset = 0;
1363 int len_size = 0;
1364 int buf_offset = 0;
1365 int relative = 0;
1366 int arg_len = strlen(arg);
1367 int i;
1368
1369 for (i = 0; i < arg_len; i++) {
1370 if (arg[i] == ',') {
1371 member++;
1372 } else if (member == 0) {
1373 if (arg[i] < '0' || arg[i] > '9')
1374 return 0;
1375
1376 len_offset = 10 * len_offset + arg[i] - '0';
1377 } else if (member == 1) {
1378 if (arg[i] < '0' || arg[i] > '9')
1379 return 0;
1380
1381 len_size = 10 * len_size + arg[i] - '0';
1382 } else if (member == 2) {
1383 if (!relative && !buf_offset && arg[i] == '+') {
1384 relative = 1;
1385 continue;
1386 } else if (!relative && !buf_offset && arg[i] == '-') {
1387 relative = 2;
1388 continue;
1389 } else if (arg[i] < '0' || arg[i] > '9')
1390 return 0;
1391
1392 buf_offset = 10 * buf_offset + arg[i] - '0';
1393 }
1394 }
1395
1396 if (member < 1)
1397 return 0;
1398
1399 if (!len_size)
1400 return 0;
1401
1402 if (member == 1) {
1403 buf_offset = len_offset + len_size;
1404 }
1405 else if (relative == 1) {
1406 buf_offset = len_offset + len_size + buf_offset;
1407 }
1408 else if (relative == 2) {
1409 if (len_offset + len_size < buf_offset)
1410 return 0;
1411
1412 buf_offset = len_offset + len_size - buf_offset;
1413 }
1414
1415 *arg_i = 3;
1416 *arg_p = calloc(1, *arg_i*sizeof(struct pattern_arg));
1417 (*arg_p)[0].type = PATTERN_ARG_TYPE_INTEGER;
1418 (*arg_p)[0].data.integer = len_offset;
1419 (*arg_p)[1].type = PATTERN_ARG_TYPE_INTEGER;
1420 (*arg_p)[1].data.integer = len_size;
1421 (*arg_p)[2].type = PATTERN_ARG_TYPE_INTEGER;
1422 (*arg_p)[2].data.integer = buf_offset;
1423
1424 return 1;
1425}
1426
1427static int
1428pattern_fetch_payloadlv(struct proxy *px, struct session *l4, void *l7, int dir,
1429 const struct pattern_arg *arg_p, int arg_i, union pattern_data *data)
1430{
1431 int len_offset = arg_p[0].data.integer;
1432 int len_size = arg_p[1].data.integer;
1433 int buf_offset = arg_p[2].data.integer;
1434 int buf_size = 0;
1435 struct buffer *b;
1436 int i;
1437
1438 /* Format is (len offset, len size, buf offset) or (len offset, len size) */
1439 /* by default buf offset == len offset + len size */
1440 /* buf offset could be absolute or relative to len offset + len size if prefixed by + or - */
1441
1442 if (!l4)
1443 return 0;
1444
1445 b = (dir & PATTERN_FETCH_RTR) ? l4->rep : l4->req;
1446
1447 if (!b || !b->l)
1448 return 0;
1449
1450 if (len_offset + len_size > b->l)
1451 return 0;
1452
1453 for (i = 0; i < len_size; i++) {
1454 buf_size = (buf_size << 8) + ((unsigned char *)b->w)[i + len_offset];
1455 }
1456
1457 if (!buf_size)
1458 return 0;
1459
1460 if (buf_offset + buf_size > b->l)
1461 return 0;
1462
1463 /* init chunk as read only */
1464 chunk_initlen(&data->str, (char *)(b->w + buf_offset), 0, buf_size);
1465
1466 return 1;
1467}
1468
1469static int
1470pattern_arg_fetch_payload (const char *arg, struct pattern_arg **arg_p, int *arg_i)
1471{
1472 int member = 0;
1473 int buf_offset = 0;
1474 int buf_size = 0;
1475 int arg_len = strlen(arg);
1476 int i;
1477
1478 for (i = 0 ; i < arg_len ; i++) {
1479 if (arg[i] == ',') {
1480 member++;
1481 } else if (member == 0) {
1482 if (arg[i] < '0' || arg[i] > '9')
1483 return 0;
1484
1485 buf_offset = 10 * buf_offset + arg[i] - '0';
1486 } else if (member == 1) {
1487 if (arg[i] < '0' || arg[i] > '9')
1488 return 0;
1489
1490 buf_size = 10 * buf_size + arg[i] - '0';
1491 }
1492 }
1493
1494 if (!buf_size)
1495 return 0;
1496
1497 *arg_i = 2;
1498 *arg_p = calloc(1, *arg_i*sizeof(struct pattern_arg));
1499 (*arg_p)[0].type = PATTERN_ARG_TYPE_INTEGER;
1500 (*arg_p)[0].data.integer = buf_offset;
1501 (*arg_p)[1].type = PATTERN_ARG_TYPE_INTEGER;
1502 (*arg_p)[1].data.integer = buf_size;
1503
1504 return 1;
1505}
1506
1507static int
1508pattern_fetch_payload(struct proxy *px, struct session *l4, void *l7, int dir,
1509 const struct pattern_arg *arg_p, int arg_i, union pattern_data *data)
1510{
1511 int buf_offset = arg_p[0].data.integer;
1512 int buf_size = arg_p[1].data.integer;
1513 struct buffer *b;
1514
1515 if (!l4)
1516 return 0;
1517
1518 b = (dir & PATTERN_FETCH_RTR) ? l4->rep : l4->req;
1519
1520 if (!b || !b->l)
1521 return 0;
1522
1523 if (buf_offset + buf_size > b->l)
1524 return 0;
1525
1526 /* init chunk as read only */
1527 chunk_initlen(&data->str, (char *)(b->w + buf_offset), 0, buf_size);
1528
1529 return 1;
1530}
1531
Willy Tarreaub6866442008-07-14 23:54:42 +02001532static struct cfg_kw_list cfg_kws = {{ },{
1533 { CFG_LISTEN, "tcp-request", tcp_parse_tcp_req },
Emeric Brun97679e72010-09-23 17:56:44 +02001534 { CFG_LISTEN, "tcp-response", tcp_parse_tcp_rep },
Willy Tarreaub6866442008-07-14 23:54:42 +02001535 { 0, NULL, NULL },
1536}};
1537
Willy Tarreau645513a2010-05-24 20:55:15 +02001538/* Note: must not be declared <const> as its list will be overwritten */
Willy Tarreaub6866442008-07-14 23:54:42 +02001539static struct acl_kw_list acl_kws = {{ },{
Willy Tarreau645513a2010-05-24 20:55:15 +02001540 { "src_port", acl_parse_int, acl_fetch_sport, acl_match_int, ACL_USE_TCP_PERMANENT },
1541 { "src", acl_parse_ip, acl_fetch_src, acl_match_ip, ACL_USE_TCP4_PERMANENT|ACL_MAY_LOOKUP },
1542 { "dst", acl_parse_ip, acl_fetch_dst, acl_match_ip, ACL_USE_TCP4_PERMANENT|ACL_MAY_LOOKUP },
1543 { "dst_port", acl_parse_int, acl_fetch_dport, acl_match_int, ACL_USE_TCP_PERMANENT },
Willy Tarreaub6866442008-07-14 23:54:42 +02001544 { NULL, NULL, NULL, NULL },
1545}};
1546
Willy Tarreau645513a2010-05-24 20:55:15 +02001547/* Note: must not be declared <const> as its list will be overwritten */
1548static struct pattern_fetch_kw_list pattern_fetch_keywords = {{ },{
Emericf2d7cae2010-11-05 18:13:50 +01001549 { "src", pattern_fetch_src, NULL, PATTERN_TYPE_IP, PATTERN_FETCH_REQ },
1550 { "dst", pattern_fetch_dst, NULL, PATTERN_TYPE_IP, PATTERN_FETCH_REQ },
1551 { "dst_port", pattern_fetch_dport, NULL, PATTERN_TYPE_INTEGER, PATTERN_FETCH_REQ },
1552 { "payload", pattern_fetch_payload, pattern_arg_fetch_payload, PATTERN_TYPE_CONSTDATA, PATTERN_FETCH_REQ|PATTERN_FETCH_RTR },
1553 { "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 +02001554 { NULL, NULL, NULL, 0, 0 },
Willy Tarreau645513a2010-05-24 20:55:15 +02001555}};
1556
Willy Tarreaue6b98942007-10-29 01:09:36 +01001557__attribute__((constructor))
1558static void __tcp_protocol_init(void)
1559{
1560 protocol_register(&proto_tcpv4);
1561 protocol_register(&proto_tcpv6);
Willy Tarreau645513a2010-05-24 20:55:15 +02001562 pattern_register_fetches(&pattern_fetch_keywords);
Willy Tarreaub6866442008-07-14 23:54:42 +02001563 cfg_register_keywords(&cfg_kws);
1564 acl_register_keywords(&acl_kws);
Willy Tarreaue6b98942007-10-29 01:09:36 +01001565}
1566
1567
1568/*
1569 * Local variables:
1570 * c-indent-level: 8
1571 * c-basic-offset: 8
1572 * End:
1573 */