1%{
2/*
3 * (C) 2006-2009 by Pablo Neira Ayuso <pablo@netfilter.org>
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
18 *
19 * Description: configuration file abstract grammar
20 */
21
22#include <stdio.h>
23#include <stdlib.h>
24#include <string.h>
25#include <netdb.h>
26#include <errno.h>
27#include <stdarg.h>
28#include "conntrackd.h"
29#include "bitops.h"
30#include "cidr.h"
31#include "helper.h"
32#include "stack.h"
33#include <syslog.h>
34#include <sched.h>
35#include <dlfcn.h>
36#include <libnetfilter_conntrack/libnetfilter_conntrack.h>
37#include <libnetfilter_conntrack/libnetfilter_conntrack_tcp.h>
38
39extern char *yytext;
40extern int   yylineno;
41
42struct ct_conf conf;
43
44enum {
45	CTD_CFG_ERROR = 0,
46	CTD_CFG_WARN,
47};
48
49static void print_err(int err, const char *msg, ...);
50
51static void __kernel_filter_start(void);
52static void __kernel_filter_add_state(int value);
53static void __max_dedicated_links_reached(void);
54
55struct stack symbol_stack;
56
57enum {
58	SYMBOL_HELPER_QUEUE_NUM,
59	SYMBOL_HELPER_QUEUE_LEN,
60	SYMBOL_HELPER_POLICY_EXPECT_ROOT,
61	SYMBOL_HELPER_EXPECT_POLICY_LEAF,
62};
63
64%}
65
66%union {
67	int		val;
68	char		*string;
69}
70
71%token T_IPV4_ADDR T_IPV4_IFACE T_PORT T_HASHSIZE T_HASHLIMIT T_MULTICAST
72%token T_PATH T_UNIX T_REFRESH T_IPV6_ADDR T_IPV6_IFACE
73%token T_IGNORE_UDP T_IGNORE_ICMP T_IGNORE_TRAFFIC T_BACKLOG T_GROUP
74%token T_LOG T_UDP T_ICMP T_IGMP T_VRRP T_TCP T_IGNORE_PROTOCOL
75%token T_LOCK T_STRIP_NAT T_BUFFER_SIZE_MAX_GROWN T_EXPIRE T_TIMEOUT
76%token T_GENERAL T_SYNC T_STATS T_RELAX_TRANSITIONS T_BUFFER_SIZE T_DELAY
77%token T_SYNC_MODE T_LISTEN_TO T_FAMILY T_RESEND_BUFFER_SIZE
78%token T_ALARM T_FTFW T_CHECKSUM T_WINDOWSIZE T_ON T_OFF
79%token T_REPLICATE T_FOR T_IFACE T_PURGE T_RESEND_QUEUE_SIZE
80%token T_ESTABLISHED T_SYN_SENT T_SYN_RECV T_FIN_WAIT
81%token T_CLOSE_WAIT T_LAST_ACK T_TIME_WAIT T_CLOSE T_LISTEN
82%token T_SYSLOG T_WRITE_THROUGH T_STAT_BUFFER_SIZE T_DESTROY_TIMEOUT
83%token T_RCVBUFF T_SNDBUFF T_NOTRACK T_POLL_SECS
84%token T_FILTER T_ADDRESS T_PROTOCOL T_STATE T_ACCEPT T_IGNORE
85%token T_FROM T_USERSPACE T_KERNELSPACE T_EVENT_ITER_LIMIT T_DEFAULT
86%token T_NETLINK_OVERRUN_RESYNC T_NICE T_IPV4_DEST_ADDR T_IPV6_DEST_ADDR
87%token T_SCHEDULER T_TYPE T_PRIO T_NETLINK_EVENTS_RELIABLE
88%token T_DISABLE_INTERNAL_CACHE T_DISABLE_EXTERNAL_CACHE T_ERROR_QUEUE_LENGTH
89%token T_OPTIONS T_TCP_WINDOW_TRACKING T_EXPECT_SYNC
90%token T_HELPER T_HELPER_QUEUE_NUM T_HELPER_QUEUE_LEN T_HELPER_POLICY
91%token T_HELPER_EXPECT_TIMEOUT T_HELPER_EXPECT_MAX
92
93%token <string> T_IP T_PATH_VAL
94%token <val> T_NUMBER
95%token <val> T_SIGNED_NUMBER
96%token <string> T_STRING
97
98%%
99
100configfile :
101	   | lines
102	   ;
103
104lines : line
105      | lines line
106      ;
107
108line : ignore_protocol
109     | ignore_traffic
110     | strip_nat
111     | general
112     | sync
113     | stats
114     | helper
115     ;
116
117logfile_bool : T_LOG T_ON
118{
119	strncpy(conf.logfile, DEFAULT_LOGFILE, FILENAME_MAXLEN);
120};
121
122logfile_bool : T_LOG T_OFF
123{
124};
125
126logfile_path : T_LOG T_PATH_VAL
127{
128	strncpy(conf.logfile, $2, FILENAME_MAXLEN);
129};
130
131syslog_bool : T_SYSLOG T_ON
132{
133	conf.syslog_facility = DEFAULT_SYSLOG_FACILITY;
134};
135
136syslog_bool : T_SYSLOG T_OFF
137{
138	conf.syslog_facility = -1;
139}
140
141syslog_facility : T_SYSLOG T_STRING
142{
143	if (!strcmp($2, "daemon"))
144		conf.syslog_facility = LOG_DAEMON;
145	else if (!strcmp($2, "local0"))
146		conf.syslog_facility = LOG_LOCAL0;
147	else if (!strcmp($2, "local1"))
148		conf.syslog_facility = LOG_LOCAL1;
149	else if (!strcmp($2, "local2"))
150		conf.syslog_facility = LOG_LOCAL2;
151	else if (!strcmp($2, "local3"))
152		conf.syslog_facility = LOG_LOCAL3;
153	else if (!strcmp($2, "local4"))
154		conf.syslog_facility = LOG_LOCAL4;
155	else if (!strcmp($2, "local5"))
156		conf.syslog_facility = LOG_LOCAL5;
157	else if (!strcmp($2, "local6"))
158		conf.syslog_facility = LOG_LOCAL6;
159	else if (!strcmp($2, "local7"))
160		conf.syslog_facility = LOG_LOCAL7;
161	else {
162		print_err(CTD_CFG_WARN, "'%s' is not a known syslog facility, "
163					"ignoring", $2);
164		break;
165	}
166
167	if (conf.stats.syslog_facility != -1 &&
168	    conf.syslog_facility != conf.stats.syslog_facility)
169	    	print_err(CTD_CFG_WARN, "conflicting Syslog facility "
170					"values, defaulting to General");
171};
172
173lock : T_LOCK T_PATH_VAL
174{
175	strncpy(conf.lockfile, $2, FILENAME_MAXLEN);
176};
177
178strip_nat: T_STRIP_NAT
179{
180	print_err(CTD_CFG_WARN, "`StripNAT' clause is obsolete, ignoring");
181};
182
183refreshtime : T_REFRESH T_NUMBER
184{
185	conf.refresh = $2;
186};
187
188expiretime: T_EXPIRE T_NUMBER
189{
190	conf.cache_timeout = $2;
191};
192
193timeout: T_TIMEOUT T_NUMBER
194{
195	conf.commit_timeout = $2;
196};
197
198purge: T_PURGE T_NUMBER
199{
200	conf.purge_timeout = $2;
201};
202
203checksum: T_CHECKSUM T_ON
204{
205	print_err(CTD_CFG_WARN, "the use of `Checksum' outside the "
206				"`Multicast' clause is ambiguous");
207	/*
208	 * XXX: The use of Checksum outside of the Multicast clause is broken
209	 *	if we have more than one dedicated links.
210	 */
211	conf.channel[0].u.mcast.checksum = 0;
212};
213
214checksum: T_CHECKSUM T_OFF
215{
216	print_err(CTD_CFG_WARN, "the use of `Checksum' outside the "
217				"`Multicast' clause is ambiguous");
218	/*
219	 * XXX: The use of Checksum outside of the Multicast clause is broken
220	 *	if we have more than one dedicated links.
221	 */
222	conf.channel[0].u.mcast.checksum = 1;
223};
224
225ignore_traffic : T_IGNORE_TRAFFIC '{' ignore_traffic_options '}'
226{
227	ct_filter_set_logic(STATE(us_filter),
228			    CT_FILTER_ADDRESS,
229			    CT_FILTER_NEGATIVE);
230
231	print_err(CTD_CFG_WARN, "the clause `IgnoreTrafficFor' is obsolete. "
232				"Use `Filter' instead");
233};
234
235ignore_traffic_options :
236		       | ignore_traffic_options ignore_traffic_option;
237
238ignore_traffic_option : T_IPV4_ADDR T_IP
239{
240	union inet_address ip;
241
242	memset(&ip, 0, sizeof(union inet_address));
243
244	if (!inet_aton($2, &ip.ipv4)) {
245		print_err(CTD_CFG_WARN, "%s is not a valid IPv4, "
246					"ignoring", $2);
247		break;
248	}
249
250	if (!ct_filter_add_ip(STATE(us_filter), &ip, AF_INET)) {
251		if (errno == EEXIST)
252			print_err(CTD_CFG_WARN, "IP %s is repeated "
253						"in the ignore pool", $2);
254		if (errno == ENOSPC)
255			print_err(CTD_CFG_WARN, "too many IP in the "
256						"ignore pool!");
257	}
258};
259
260ignore_traffic_option : T_IPV6_ADDR T_IP
261{
262	union inet_address ip;
263
264	memset(&ip, 0, sizeof(union inet_address));
265
266#ifdef HAVE_INET_PTON_IPV6
267	if (inet_pton(AF_INET6, $2, &ip.ipv6) <= 0) {
268		print_err(CTD_CFG_WARN, "%s is not a valid IPv6, ignoring", $2);
269		break;
270	}
271#else
272	print_err(CTD_CFG_WARN, "cannot find inet_pton(), IPv6 unsupported!");
273#endif
274
275	if (!ct_filter_add_ip(STATE(us_filter), &ip, AF_INET6)) {
276		if (errno == EEXIST)
277			print_err(CTD_CFG_WARN, "IP %s is repeated "
278						"in the ignore pool", $2);
279		if (errno == ENOSPC)
280			print_err(CTD_CFG_WARN, "too many IP in the "
281						"ignore pool!");
282	}
283
284};
285
286multicast_line : T_MULTICAST '{' multicast_options '}'
287{
288	if (conf.channel_type_global != CHANNEL_NONE &&
289	    conf.channel_type_global != CHANNEL_MCAST) {
290		print_err(CTD_CFG_ERROR, "cannot use `Multicast' with other "
291					 "dedicated link protocols!");
292		exit(EXIT_FAILURE);
293	}
294	conf.channel_type_global = CHANNEL_MCAST;
295	conf.channel[conf.channel_num].channel_type = CHANNEL_MCAST;
296	conf.channel[conf.channel_num].channel_flags = CHANNEL_F_BUFFERED;
297	conf.channel_num++;
298};
299
300multicast_line : T_MULTICAST T_DEFAULT '{' multicast_options '}'
301{
302	if (conf.channel_type_global != CHANNEL_NONE &&
303	    conf.channel_type_global != CHANNEL_MCAST) {
304		print_err(CTD_CFG_ERROR, "cannot use `Multicast' with other "
305					 "dedicated link protocols!");
306		exit(EXIT_FAILURE);
307	}
308	conf.channel_type_global = CHANNEL_MCAST;
309	conf.channel[conf.channel_num].channel_type = CHANNEL_MCAST;
310	conf.channel[conf.channel_num].channel_flags = CHANNEL_F_DEFAULT |
311						       CHANNEL_F_BUFFERED;
312	conf.channel_default = conf.channel_num;
313	conf.channel_num++;
314};
315
316multicast_options :
317		  | multicast_options multicast_option;
318
319multicast_option : T_IPV4_ADDR T_IP
320{
321	__max_dedicated_links_reached();
322
323	if (!inet_aton($2, &conf.channel[conf.channel_num].u.mcast.in)) {
324		print_err(CTD_CFG_WARN, "%s is not a valid IPv4 address", $2);
325		break;
326	}
327
328        if (conf.channel[conf.channel_num].u.mcast.ipproto == AF_INET6) {
329		print_err(CTD_CFG_WARN, "your multicast address is IPv4 but "
330					"is binded to an IPv6 interface? "
331					"Surely, this is not what you want");
332		break;
333	}
334
335	conf.channel[conf.channel_num].u.mcast.ipproto = AF_INET;
336};
337
338multicast_option : T_IPV6_ADDR T_IP
339{
340	__max_dedicated_links_reached();
341
342#ifdef HAVE_INET_PTON_IPV6
343	if (inet_pton(AF_INET6, $2,
344		      &conf.channel[conf.channel_num].u.mcast.in) <= 0) {
345		print_err(CTD_CFG_WARN, "%s is not a valid IPv6 address", $2);
346		break;
347	}
348#else
349	print_err(CTD_CFG_WARN, "cannot find inet_pton(), IPv6 unsupported!");
350	break;
351#endif
352
353	if (conf.channel[conf.channel_num].u.mcast.ipproto == AF_INET) {
354		print_err(CTD_CFG_WARN, "your multicast address is IPv6 but "
355					"is binded to an IPv4 interface? "
356					"Surely this is not what you want");
357		break;
358	}
359
360	conf.channel[conf.channel_num].u.mcast.ipproto = AF_INET6;
361
362	if (conf.channel[conf.channel_num].channel_ifname[0] &&
363	    !conf.channel[conf.channel_num].u.mcast.ifa.interface_index6) {
364		unsigned int idx;
365
366		idx = if_nametoindex($2);
367		if (!idx) {
368			print_err(CTD_CFG_WARN,
369				  "%s is an invalid interface", $2);
370			break;
371		}
372
373		conf.channel[conf.channel_num].u.mcast.ifa.interface_index6 = idx;
374		conf.channel[conf.channel_num].u.mcast.ipproto = AF_INET6;
375	}
376};
377
378multicast_option : T_IPV4_IFACE T_IP
379{
380	__max_dedicated_links_reached();
381
382	if (!inet_aton($2, &conf.channel[conf.channel_num].u.mcast.ifa)) {
383		print_err(CTD_CFG_WARN, "%s is not a valid IPv4 address", $2);
384		break;
385	}
386
387        if (conf.channel[conf.channel_num].u.mcast.ipproto == AF_INET6) {
388		print_err(CTD_CFG_WARN, "your multicast interface is IPv4 but "
389					"is binded to an IPv6 interface? "
390					"Surely, this is not what you want");
391		break;
392	}
393
394	conf.channel[conf.channel_num].u.mcast.ipproto = AF_INET;
395};
396
397multicast_option : T_IPV6_IFACE T_IP
398{
399	print_err(CTD_CFG_WARN, "`IPv6_interface' not required, ignoring");
400}
401
402multicast_option : T_IFACE T_STRING
403{
404	unsigned int idx;
405
406	__max_dedicated_links_reached();
407
408	strncpy(conf.channel[conf.channel_num].channel_ifname, $2, IFNAMSIZ);
409
410	idx = if_nametoindex($2);
411	if (!idx) {
412		print_err(CTD_CFG_WARN, "%s is an invalid interface", $2);
413		break;
414	}
415
416	if (conf.channel[conf.channel_num].u.mcast.ipproto == AF_INET6) {
417		conf.channel[conf.channel_num].u.mcast.ifa.interface_index6 = idx;
418		conf.channel[conf.channel_num].u.mcast.ipproto = AF_INET6;
419	}
420};
421
422multicast_option : T_BACKLOG T_NUMBER
423{
424	print_err(CTD_CFG_WARN, "`Backlog' option inside Multicast clause is "
425				"obsolete. Please, remove it from "
426				"conntrackd.conf");
427};
428
429multicast_option : T_GROUP T_NUMBER
430{
431	__max_dedicated_links_reached();
432	conf.channel[conf.channel_num].u.mcast.port = $2;
433};
434
435multicast_option: T_SNDBUFF T_NUMBER
436{
437	__max_dedicated_links_reached();
438	conf.channel[conf.channel_num].u.mcast.sndbuf = $2;
439};
440
441multicast_option: T_RCVBUFF T_NUMBER
442{
443	__max_dedicated_links_reached();
444	conf.channel[conf.channel_num].u.mcast.rcvbuf = $2;
445};
446
447multicast_option: T_CHECKSUM T_ON
448{
449	__max_dedicated_links_reached();
450	conf.channel[conf.channel_num].u.mcast.checksum = 0;
451};
452
453multicast_option: T_CHECKSUM T_OFF
454{
455	__max_dedicated_links_reached();
456	conf.channel[conf.channel_num].u.mcast.checksum = 1;
457};
458
459udp_line : T_UDP '{' udp_options '}'
460{
461	if (conf.channel_type_global != CHANNEL_NONE &&
462	    conf.channel_type_global != CHANNEL_UDP) {
463		print_err(CTD_CFG_ERROR, "cannot use `UDP' with other "
464					 "dedicated link protocols!");
465		exit(EXIT_FAILURE);
466	}
467	conf.channel_type_global = CHANNEL_UDP;
468	conf.channel[conf.channel_num].channel_type = CHANNEL_UDP;
469	conf.channel[conf.channel_num].channel_flags = CHANNEL_F_BUFFERED;
470	conf.channel_num++;
471};
472
473udp_line : T_UDP T_DEFAULT '{' udp_options '}'
474{
475	if (conf.channel_type_global != CHANNEL_NONE &&
476	    conf.channel_type_global != CHANNEL_UDP) {
477		print_err(CTD_CFG_ERROR, "cannot use `UDP' with other "
478					 "dedicated link protocols!");
479		exit(EXIT_FAILURE);
480	}
481	conf.channel_type_global = CHANNEL_UDP;
482	conf.channel[conf.channel_num].channel_type = CHANNEL_UDP;
483	conf.channel[conf.channel_num].channel_flags = CHANNEL_F_DEFAULT |
484						       CHANNEL_F_BUFFERED;
485	conf.channel_default = conf.channel_num;
486	conf.channel_num++;
487};
488
489udp_options :
490	    | udp_options udp_option;
491
492udp_option : T_IPV4_ADDR T_IP
493{
494	__max_dedicated_links_reached();
495
496	if (!inet_aton($2, &conf.channel[conf.channel_num].u.udp.server.ipv4)) {
497		print_err(CTD_CFG_WARN, "%s is not a valid IPv4 address", $2);
498		break;
499	}
500	conf.channel[conf.channel_num].u.udp.ipproto = AF_INET;
501};
502
503udp_option : T_IPV6_ADDR T_IP
504{
505	__max_dedicated_links_reached();
506
507#ifdef HAVE_INET_PTON_IPV6
508	if (inet_pton(AF_INET6, $2,
509		      &conf.channel[conf.channel_num].u.udp.server.ipv6) <= 0) {
510		print_err(CTD_CFG_WARN, "%s is not a valid IPv6 address", $2);
511		break;
512	}
513#else
514	print_err(CTD_CFG_WARN, "cannot find inet_pton(), IPv6 unsupported!");
515	break;
516#endif
517	conf.channel[conf.channel_num].u.udp.ipproto = AF_INET6;
518};
519
520udp_option : T_IPV4_DEST_ADDR T_IP
521{
522	__max_dedicated_links_reached();
523
524	if (!inet_aton($2, &conf.channel[conf.channel_num].u.udp.client)) {
525		print_err(CTD_CFG_WARN, "%s is not a valid IPv4 address", $2);
526		break;
527	}
528	conf.channel[conf.channel_num].u.udp.ipproto = AF_INET;
529};
530
531udp_option : T_IPV6_DEST_ADDR T_IP
532{
533	__max_dedicated_links_reached();
534
535#ifdef HAVE_INET_PTON_IPV6
536	if (inet_pton(AF_INET6, $2,
537		      &conf.channel[conf.channel_num].u.udp.client) <= 0) {
538		print_err(CTD_CFG_WARN, "%s is not a valid IPv6 address", $2);
539		break;
540	}
541#else
542	print_err(CTD_CFG_WARN, "cannot find inet_pton(), IPv6 unsupported!");
543	break;
544#endif
545	conf.channel[conf.channel_num].u.udp.ipproto = AF_INET6;
546};
547
548udp_option : T_IFACE T_STRING
549{
550	int idx;
551
552	__max_dedicated_links_reached();
553	strncpy(conf.channel[conf.channel_num].channel_ifname, $2, IFNAMSIZ);
554
555	idx = if_nametoindex($2);
556	if (!idx) {
557		print_err(CTD_CFG_WARN, "%s is an invalid interface", $2);
558		break;
559	}
560	conf.channel[conf.channel_num].u.udp.server.ipv6.scope_id = idx;
561};
562
563udp_option : T_PORT T_NUMBER
564{
565	__max_dedicated_links_reached();
566	conf.channel[conf.channel_num].u.udp.port = $2;
567};
568
569udp_option: T_SNDBUFF T_NUMBER
570{
571	__max_dedicated_links_reached();
572	conf.channel[conf.channel_num].u.udp.sndbuf = $2;
573};
574
575udp_option: T_RCVBUFF T_NUMBER
576{
577	__max_dedicated_links_reached();
578	conf.channel[conf.channel_num].u.udp.rcvbuf = $2;
579};
580
581udp_option: T_CHECKSUM T_ON
582{
583	__max_dedicated_links_reached();
584	conf.channel[conf.channel_num].u.udp.checksum = 0;
585};
586
587udp_option: T_CHECKSUM T_OFF
588{
589	__max_dedicated_links_reached();
590	conf.channel[conf.channel_num].u.udp.checksum = 1;
591};
592
593tcp_line : T_TCP '{' tcp_options '}'
594{
595	if (conf.channel_type_global != CHANNEL_NONE &&
596	    conf.channel_type_global != CHANNEL_TCP) {
597		print_err(CTD_CFG_ERROR, "cannot use `TCP' with other "
598					 "dedicated link protocols!");
599		exit(EXIT_FAILURE);
600	}
601	conf.channel_type_global = CHANNEL_TCP;
602	conf.channel[conf.channel_num].channel_type = CHANNEL_TCP;
603	conf.channel[conf.channel_num].channel_flags = CHANNEL_F_BUFFERED |
604						       CHANNEL_F_STREAM |
605						       CHANNEL_F_ERRORS;
606	conf.channel_num++;
607};
608
609tcp_line : T_TCP T_DEFAULT '{' tcp_options '}'
610{
611	if (conf.channel_type_global != CHANNEL_NONE &&
612	    conf.channel_type_global != CHANNEL_TCP) {
613		print_err(CTD_CFG_ERROR, "cannot use `TCP' with other "
614					 "dedicated link protocols!");
615		exit(EXIT_FAILURE);
616	}
617	conf.channel_type_global = CHANNEL_TCP;
618	conf.channel[conf.channel_num].channel_type = CHANNEL_TCP;
619	conf.channel[conf.channel_num].channel_flags = CHANNEL_F_DEFAULT |
620						       CHANNEL_F_BUFFERED |
621						       CHANNEL_F_STREAM |
622						       CHANNEL_F_ERRORS;
623	conf.channel_default = conf.channel_num;
624	conf.channel_num++;
625};
626
627tcp_options :
628	    | tcp_options tcp_option;
629
630tcp_option : T_IPV4_ADDR T_IP
631{
632	__max_dedicated_links_reached();
633
634	if (!inet_aton($2, &conf.channel[conf.channel_num].u.tcp.server.ipv4)) {
635		print_err(CTD_CFG_WARN, "%s is not a valid IPv4 address", $2);
636		break;
637	}
638	conf.channel[conf.channel_num].u.tcp.ipproto = AF_INET;
639};
640
641tcp_option : T_IPV6_ADDR T_IP
642{
643	__max_dedicated_links_reached();
644
645#ifdef HAVE_INET_PTON_IPV6
646	if (inet_pton(AF_INET6, $2,
647		      &conf.channel[conf.channel_num].u.tcp.server.ipv6) <= 0) {
648		print_err(CTD_CFG_WARN, "%s is not a valid IPv6 address", $2);
649		break;
650	}
651#else
652	print_err(CTD_CFG_WARN, "cannot find inet_pton(), IPv6 unsupported!");
653	break;
654#endif
655	conf.channel[conf.channel_num].u.tcp.ipproto = AF_INET6;
656};
657
658tcp_option : T_IPV4_DEST_ADDR T_IP
659{
660	__max_dedicated_links_reached();
661
662	if (!inet_aton($2, &conf.channel[conf.channel_num].u.tcp.client)) {
663		print_err(CTD_CFG_WARN, "%s is not a valid IPv4 address", $2);
664		break;
665	}
666	conf.channel[conf.channel_num].u.tcp.ipproto = AF_INET;
667};
668
669tcp_option : T_IPV6_DEST_ADDR T_IP
670{
671	__max_dedicated_links_reached();
672
673#ifdef HAVE_INET_PTON_IPV6
674	if (inet_pton(AF_INET6, $2,
675		      &conf.channel[conf.channel_num].u.tcp.client) <= 0) {
676		print_err(CTD_CFG_WARN, "%s is not a valid IPv6 address", $2);
677		break;
678	}
679#else
680	print_err(CTD_CFG_WARN, "cannot find inet_pton(), IPv6 unsupported!");
681	break;
682#endif
683	conf.channel[conf.channel_num].u.tcp.ipproto = AF_INET6;
684};
685
686tcp_option : T_IFACE T_STRING
687{
688	int idx;
689
690	__max_dedicated_links_reached();
691	strncpy(conf.channel[conf.channel_num].channel_ifname, $2, IFNAMSIZ);
692
693	idx = if_nametoindex($2);
694	if (!idx) {
695		print_err(CTD_CFG_WARN, "%s is an invalid interface", $2);
696		break;
697	}
698	conf.channel[conf.channel_num].u.tcp.server.ipv6.scope_id = idx;
699};
700
701tcp_option : T_PORT T_NUMBER
702{
703	__max_dedicated_links_reached();
704	conf.channel[conf.channel_num].u.tcp.port = $2;
705};
706
707tcp_option: T_SNDBUFF T_NUMBER
708{
709	__max_dedicated_links_reached();
710	conf.channel[conf.channel_num].u.tcp.sndbuf = $2;
711};
712
713tcp_option: T_RCVBUFF T_NUMBER
714{
715	__max_dedicated_links_reached();
716	conf.channel[conf.channel_num].u.tcp.rcvbuf = $2;
717};
718
719tcp_option: T_CHECKSUM T_ON
720{
721	__max_dedicated_links_reached();
722	conf.channel[conf.channel_num].u.tcp.checksum = 0;
723};
724
725tcp_option: T_CHECKSUM T_OFF
726{
727	__max_dedicated_links_reached();
728	conf.channel[conf.channel_num].u.tcp.checksum = 1;
729};
730
731tcp_option: T_ERROR_QUEUE_LENGTH T_NUMBER
732{
733	__max_dedicated_links_reached();
734	CONFIG(channelc).error_queue_length = $2;
735};
736
737hashsize : T_HASHSIZE T_NUMBER
738{
739	conf.hashsize = $2;
740};
741
742hashlimit: T_HASHLIMIT T_NUMBER
743{
744	conf.limit = $2;
745};
746
747unix_line: T_UNIX '{' unix_options '}';
748
749unix_options:
750	    | unix_options unix_option
751	    ;
752
753unix_option : T_PATH T_PATH_VAL
754{
755	strcpy(conf.local.path, $2);
756};
757
758unix_option : T_BACKLOG T_NUMBER
759{
760	conf.local.backlog = $2;
761};
762
763ignore_protocol: T_IGNORE_PROTOCOL '{' ignore_proto_list '}'
764{
765	ct_filter_set_logic(STATE(us_filter),
766			    CT_FILTER_L4PROTO,
767			    CT_FILTER_NEGATIVE);
768
769	print_err(CTD_CFG_WARN, "the clause `IgnoreProtocol' is "
770				"obsolete. Use `Filter' instead");
771};
772
773ignore_proto_list:
774		 | ignore_proto_list ignore_proto
775		 ;
776
777ignore_proto: T_NUMBER
778{
779	if ($1 < IPPROTO_MAX)
780		ct_filter_add_proto(STATE(us_filter), $1);
781	else
782		print_err(CTD_CFG_WARN, "protocol number `%d' is freak", $1);
783};
784
785ignore_proto: T_STRING
786{
787	struct protoent *pent;
788
789	pent = getprotobyname($1);
790	if (pent == NULL) {
791		print_err(CTD_CFG_WARN, "getprotobyname() cannot find "
792					"protocol `%s' in /etc/protocols", $1);
793		break;
794	}
795	ct_filter_add_proto(STATE(us_filter), pent->p_proto);
796};
797
798sync: T_SYNC '{' sync_list '}'
799{
800	if (conf.flags & CTD_STATS_MODE) {
801		print_err(CTD_CFG_ERROR, "cannot use both `Stats' and `Sync' "
802					 "clauses in conntrackd.conf");
803		exit(EXIT_FAILURE);
804	}
805	conf.flags |= CTD_SYNC_MODE;
806};
807
808sync_list:
809	 | sync_list sync_line;
810
811sync_line: refreshtime
812	 | expiretime
813	 | timeout
814	 | purge
815	 | checksum
816	 | multicast_line
817	 | udp_line
818	 | tcp_line
819	 | relax_transitions
820	 | delay_destroy_msgs
821	 | sync_mode_alarm
822	 | sync_mode_ftfw
823	 | sync_mode_notrack
824	 | listen_to
825	 | state_replication
826	 | cache_writethrough
827	 | destroy_timeout
828	 | option_line
829	 ;
830
831option_line: T_OPTIONS '{' options '}';
832
833options:
834       | options option
835       ;
836
837option: T_TCP_WINDOW_TRACKING T_ON
838{
839	CONFIG(sync).tcp_window_tracking = 1;
840};
841
842option: T_TCP_WINDOW_TRACKING T_OFF
843{
844	CONFIG(sync).tcp_window_tracking = 0;
845};
846
847option: T_EXPECT_SYNC T_ON
848{
849	CONFIG(flags) |= CTD_EXPECT;
850	CONFIG(netlink).subsys_id = NFNL_SUBSYS_NONE;
851	CONFIG(netlink).groups = NF_NETLINK_CONNTRACK_NEW |
852				 NF_NETLINK_CONNTRACK_UPDATE |
853				 NF_NETLINK_CONNTRACK_DESTROY |
854				 NF_NETLINK_CONNTRACK_EXP_NEW |
855				 NF_NETLINK_CONNTRACK_EXP_UPDATE |
856				 NF_NETLINK_CONNTRACK_EXP_DESTROY;
857};
858
859option: T_EXPECT_SYNC T_OFF
860{
861	CONFIG(netlink).subsys_id = NFNL_SUBSYS_CTNETLINK;
862	CONFIG(netlink).groups = NF_NETLINK_CONNTRACK_NEW |
863				 NF_NETLINK_CONNTRACK_UPDATE |
864				 NF_NETLINK_CONNTRACK_DESTROY;
865};
866
867option: T_EXPECT_SYNC '{' expect_list '}'
868{
869	CONFIG(flags) |= CTD_EXPECT;
870	CONFIG(netlink).subsys_id = NFNL_SUBSYS_NONE;
871	CONFIG(netlink).groups = NF_NETLINK_CONNTRACK_NEW |
872				 NF_NETLINK_CONNTRACK_UPDATE |
873				 NF_NETLINK_CONNTRACK_DESTROY |
874				 NF_NETLINK_CONNTRACK_EXP_NEW |
875				 NF_NETLINK_CONNTRACK_EXP_UPDATE |
876				 NF_NETLINK_CONNTRACK_EXP_DESTROY;
877};
878
879expect_list:
880            | expect_list expect_item ;
881
882expect_item: T_STRING
883{
884	exp_filter_add(STATE(exp_filter), $1);
885}
886
887sync_mode_alarm: T_SYNC_MODE T_ALARM '{' sync_mode_alarm_list '}'
888{
889	conf.flags |= CTD_SYNC_ALARM;
890};
891
892sync_mode_ftfw: T_SYNC_MODE T_FTFW '{' sync_mode_ftfw_list '}'
893{
894	conf.flags |= CTD_SYNC_FTFW;
895};
896
897sync_mode_notrack: T_SYNC_MODE T_NOTRACK '{' sync_mode_notrack_list '}'
898{
899	conf.flags |= CTD_SYNC_NOTRACK;
900};
901
902sync_mode_alarm_list:
903	      | sync_mode_alarm_list sync_mode_alarm_line;
904
905sync_mode_alarm_line: refreshtime
906              		 | expiretime
907	     		 | timeout
908			 | purge
909			 | relax_transitions
910			 | delay_destroy_msgs
911			 ;
912
913sync_mode_ftfw_list:
914	      | sync_mode_ftfw_list sync_mode_ftfw_line;
915
916sync_mode_ftfw_line: resend_queue_size
917		   | resend_buffer_size
918		   | timeout
919		   | purge
920		   | window_size
921		   | disable_external_cache
922		   ;
923
924sync_mode_notrack_list:
925	      | sync_mode_notrack_list sync_mode_notrack_line;
926
927sync_mode_notrack_line: timeout
928		      | purge
929		      | disable_internal_cache
930		      | disable_external_cache
931		      ;
932
933disable_internal_cache: T_DISABLE_INTERNAL_CACHE T_ON
934{
935	conf.sync.internal_cache_disable = 1;
936};
937
938disable_internal_cache: T_DISABLE_INTERNAL_CACHE T_OFF
939{
940	conf.sync.internal_cache_disable = 0;
941};
942
943disable_external_cache: T_DISABLE_EXTERNAL_CACHE T_ON
944{
945	conf.sync.external_cache_disable = 1;
946};
947
948disable_external_cache: T_DISABLE_EXTERNAL_CACHE T_OFF
949{
950	conf.sync.external_cache_disable = 0;
951};
952
953resend_buffer_size: T_RESEND_BUFFER_SIZE T_NUMBER
954{
955	print_err(CTD_CFG_WARN, "`ResendBufferSize' is deprecated. "
956				"Use `ResendQueueSize' instead");
957};
958
959resend_queue_size: T_RESEND_QUEUE_SIZE T_NUMBER
960{
961	conf.resend_queue_size = $2;
962};
963
964window_size: T_WINDOWSIZE T_NUMBER
965{
966	conf.window_size = $2;
967};
968
969destroy_timeout: T_DESTROY_TIMEOUT T_NUMBER
970{
971	print_err(CTD_CFG_WARN, "`DestroyTimeout' is deprecated. Remove it");
972};
973
974relax_transitions: T_RELAX_TRANSITIONS
975{
976	print_err(CTD_CFG_WARN, "`RelaxTransitions' clause is obsolete. "
977				"Please, remove it from conntrackd.conf");
978};
979
980delay_destroy_msgs: T_DELAY
981{
982	print_err(CTD_CFG_WARN, "`DelayDestroyMessages' clause is obsolete. "
983				"Please, remove it from conntrackd.conf");
984};
985
986listen_to: T_LISTEN_TO T_IP
987{
988	print_err(CTD_CFG_WARN, "the clause `ListenTo' is obsolete, ignoring");
989};
990
991state_replication: T_REPLICATE states T_FOR state_proto
992{
993	ct_filter_set_logic(STATE(us_filter),
994			    CT_FILTER_STATE,
995			    CT_FILTER_POSITIVE);
996
997	print_err(CTD_CFG_WARN, "the clause `Replicate' is obsolete. "
998				"Use `Filter' instead");
999};
1000
1001states:
1002      | states state;
1003
1004state_proto: T_STRING
1005{
1006	if (strncmp($1, "TCP", strlen("TCP")) != 0) {
1007		print_err(CTD_CFG_WARN, "unsupported protocol `%s' in line %d",
1008					$1, yylineno);
1009	}
1010};
1011state: tcp_state;
1012
1013tcp_states:
1014	  | tcp_states tcp_state;
1015
1016tcp_state: T_SYN_SENT
1017{
1018	ct_filter_add_state(STATE(us_filter),
1019			    IPPROTO_TCP,
1020			    TCP_CONNTRACK_SYN_SENT);
1021
1022	__kernel_filter_add_state(TCP_CONNTRACK_SYN_SENT);
1023};
1024tcp_state: T_SYN_RECV
1025{
1026	ct_filter_add_state(STATE(us_filter),
1027			    IPPROTO_TCP,
1028			    TCP_CONNTRACK_SYN_RECV);
1029
1030	__kernel_filter_add_state(TCP_CONNTRACK_SYN_RECV);
1031};
1032tcp_state: T_ESTABLISHED
1033{
1034	ct_filter_add_state(STATE(us_filter),
1035			    IPPROTO_TCP,
1036			    TCP_CONNTRACK_ESTABLISHED);
1037
1038	__kernel_filter_add_state(TCP_CONNTRACK_ESTABLISHED);
1039};
1040tcp_state: T_FIN_WAIT
1041{
1042	ct_filter_add_state(STATE(us_filter),
1043			    IPPROTO_TCP,
1044			    TCP_CONNTRACK_FIN_WAIT);
1045
1046	__kernel_filter_add_state(TCP_CONNTRACK_FIN_WAIT);
1047};
1048tcp_state: T_CLOSE_WAIT
1049{
1050	ct_filter_add_state(STATE(us_filter),
1051			    IPPROTO_TCP,
1052			    TCP_CONNTRACK_CLOSE_WAIT);
1053
1054	__kernel_filter_add_state(TCP_CONNTRACK_CLOSE_WAIT);
1055};
1056tcp_state: T_LAST_ACK
1057{
1058	ct_filter_add_state(STATE(us_filter),
1059			    IPPROTO_TCP,
1060			    TCP_CONNTRACK_LAST_ACK);
1061
1062	__kernel_filter_add_state(TCP_CONNTRACK_LAST_ACK);
1063};
1064tcp_state: T_TIME_WAIT
1065{
1066	ct_filter_add_state(STATE(us_filter),
1067			    IPPROTO_TCP,
1068			    TCP_CONNTRACK_TIME_WAIT);
1069
1070	__kernel_filter_add_state(TCP_CONNTRACK_TIME_WAIT);
1071};
1072tcp_state: T_CLOSE
1073{
1074	ct_filter_add_state(STATE(us_filter),
1075			    IPPROTO_TCP,
1076			    TCP_CONNTRACK_CLOSE);
1077
1078	__kernel_filter_add_state(TCP_CONNTRACK_CLOSE);
1079};
1080tcp_state: T_LISTEN
1081{
1082	ct_filter_add_state(STATE(us_filter),
1083			    IPPROTO_TCP,
1084			    TCP_CONNTRACK_LISTEN);
1085
1086	__kernel_filter_add_state(TCP_CONNTRACK_LISTEN);
1087};
1088
1089cache_writethrough: T_WRITE_THROUGH T_ON
1090{
1091	print_err(CTD_CFG_WARN, "`CacheWriteThrough' clause is obsolete, "
1092				"ignoring");
1093};
1094
1095cache_writethrough: T_WRITE_THROUGH T_OFF
1096{
1097	print_err(CTD_CFG_WARN, "`CacheWriteThrough' clause is obsolete, "
1098				"ignoring");
1099};
1100
1101general: T_GENERAL '{' general_list '}';
1102
1103general_list:
1104	    | general_list general_line
1105	    ;
1106
1107general_line: hashsize
1108	    | hashlimit
1109	    | logfile_bool
1110	    | logfile_path
1111	    | syslog_facility
1112	    | syslog_bool
1113	    | lock
1114	    | unix_line
1115	    | netlink_buffer_size
1116	    | netlink_buffer_size_max_grown
1117	    | family
1118	    | event_iterations_limit
1119	    | poll_secs
1120	    | filter
1121	    | netlink_overrun_resync
1122	    | netlink_events_reliable
1123	    | nice
1124	    | scheduler
1125	    ;
1126
1127netlink_buffer_size: T_BUFFER_SIZE T_NUMBER
1128{
1129	conf.netlink_buffer_size = $2;
1130};
1131
1132netlink_buffer_size_max_grown : T_BUFFER_SIZE_MAX_GROWN T_NUMBER
1133{
1134	conf.netlink_buffer_size_max_grown = $2;
1135};
1136
1137netlink_overrun_resync : T_NETLINK_OVERRUN_RESYNC T_ON
1138{
1139	conf.nl_overrun_resync = 30;
1140};
1141
1142netlink_overrun_resync : T_NETLINK_OVERRUN_RESYNC T_OFF
1143{
1144	conf.nl_overrun_resync = -1;
1145};
1146
1147netlink_overrun_resync : T_NETLINK_OVERRUN_RESYNC T_NUMBER
1148{
1149	conf.nl_overrun_resync = $2;
1150};
1151
1152netlink_events_reliable : T_NETLINK_EVENTS_RELIABLE T_ON
1153{
1154	conf.netlink.events_reliable = 1;
1155};
1156
1157netlink_events_reliable : T_NETLINK_EVENTS_RELIABLE T_OFF
1158{
1159	conf.netlink.events_reliable = 0;
1160};
1161
1162nice : T_NICE T_SIGNED_NUMBER
1163{
1164	conf.nice = $2;
1165};
1166
1167scheduler : T_SCHEDULER '{' scheduler_options '}';
1168
1169scheduler_options :
1170		  | scheduler_options scheduler_line
1171		  ;
1172
1173scheduler_line : T_TYPE T_STRING
1174{
1175	if (strcasecmp($2, "rr") == 0) {
1176		conf.sched.type = SCHED_RR;
1177	} else if (strcasecmp($2, "fifo") == 0) {
1178		conf.sched.type = SCHED_FIFO;
1179	} else {
1180		print_err(CTD_CFG_ERROR, "unknown scheduler `%s'", $2);
1181		exit(EXIT_FAILURE);
1182	}
1183};
1184
1185scheduler_line : T_PRIO T_NUMBER
1186{
1187	conf.sched.prio = $2;
1188	if (conf.sched.prio < 0 || conf.sched.prio > 99) {
1189		print_err(CTD_CFG_ERROR, "`Priority' must be [0, 99]\n", $2);
1190		exit(EXIT_FAILURE);
1191	}
1192};
1193
1194family : T_FAMILY T_STRING
1195{
1196	if (strncmp($2, "IPv6", strlen("IPv6")) == 0)
1197		conf.family = AF_INET6;
1198	else
1199		conf.family = AF_INET;
1200};
1201
1202event_iterations_limit : T_EVENT_ITER_LIMIT T_NUMBER
1203{
1204	CONFIG(event_iterations_limit) = $2;
1205};
1206
1207poll_secs: T_POLL_SECS T_NUMBER
1208{
1209	conf.flags |= CTD_POLL;
1210	conf.poll_kernel_secs = $2;
1211	if (conf.poll_kernel_secs == 0) {
1212		print_err(CTD_CFG_ERROR, "`PollSecs' clause must be > 0");
1213		exit(EXIT_FAILURE);
1214	}
1215};
1216
1217filter : T_FILTER '{' filter_list '}'
1218{
1219	CONFIG(filter_from_kernelspace) = 0;
1220};
1221
1222filter : T_FILTER T_FROM T_USERSPACE '{' filter_list '}'
1223{
1224	CONFIG(filter_from_kernelspace) = 0;
1225};
1226
1227filter : T_FILTER T_FROM T_KERNELSPACE '{' filter_list '}'
1228{
1229	CONFIG(filter_from_kernelspace) = 1;
1230};
1231
1232filter_list :
1233	    | filter_list filter_item;
1234
1235filter_item : T_PROTOCOL T_ACCEPT '{' filter_protocol_list '}'
1236{
1237	ct_filter_set_logic(STATE(us_filter),
1238			    CT_FILTER_L4PROTO,
1239			    CT_FILTER_POSITIVE);
1240
1241	__kernel_filter_start();
1242};
1243
1244filter_item : T_PROTOCOL T_IGNORE '{' filter_protocol_list '}'
1245{
1246	ct_filter_set_logic(STATE(us_filter),
1247			    CT_FILTER_L4PROTO,
1248			    CT_FILTER_NEGATIVE);
1249
1250	__kernel_filter_start();
1251
1252	nfct_filter_set_logic(STATE(filter),
1253			      NFCT_FILTER_L4PROTO,
1254			      NFCT_FILTER_LOGIC_NEGATIVE);
1255};
1256
1257filter_protocol_list :
1258		     | filter_protocol_list filter_protocol_item;
1259
1260filter_protocol_item : T_STRING
1261{
1262	struct protoent *pent;
1263
1264	pent = getprotobyname($1);
1265	if (pent == NULL) {
1266		print_err(CTD_CFG_WARN, "getprotobyname() cannot find "
1267					"protocol `%s' in /etc/protocols", $1);
1268		break;
1269	}
1270	ct_filter_add_proto(STATE(us_filter), pent->p_proto);
1271
1272	__kernel_filter_start();
1273
1274	nfct_filter_add_attr_u32(STATE(filter),
1275				 NFCT_FILTER_L4PROTO,
1276				 pent->p_proto);
1277};
1278
1279filter_protocol_item : T_TCP
1280{
1281	struct protoent *pent;
1282
1283	pent = getprotobyname("tcp");
1284	if (pent == NULL) {
1285		print_err(CTD_CFG_WARN, "getprotobyname() cannot find "
1286					"protocol `tcp' in /etc/protocols");
1287		break;
1288	}
1289	ct_filter_add_proto(STATE(us_filter), pent->p_proto);
1290
1291	__kernel_filter_start();
1292
1293	nfct_filter_add_attr_u32(STATE(filter),
1294				 NFCT_FILTER_L4PROTO,
1295				 pent->p_proto);
1296};
1297
1298filter_protocol_item : T_UDP
1299{
1300	struct protoent *pent;
1301
1302	pent = getprotobyname("udp");
1303	if (pent == NULL) {
1304		print_err(CTD_CFG_WARN, "getprotobyname() cannot find "
1305					"protocol `udp' in /etc/protocols");
1306		break;
1307	}
1308	ct_filter_add_proto(STATE(us_filter), pent->p_proto);
1309
1310	__kernel_filter_start();
1311
1312	nfct_filter_add_attr_u32(STATE(filter),
1313				 NFCT_FILTER_L4PROTO,
1314				 pent->p_proto);
1315};
1316
1317filter_item : T_ADDRESS T_ACCEPT '{' filter_address_list '}'
1318{
1319	ct_filter_set_logic(STATE(us_filter),
1320			    CT_FILTER_ADDRESS,
1321			    CT_FILTER_POSITIVE);
1322
1323	__kernel_filter_start();
1324};
1325
1326filter_item : T_ADDRESS T_IGNORE '{' filter_address_list '}'
1327{
1328	ct_filter_set_logic(STATE(us_filter),
1329			    CT_FILTER_ADDRESS,
1330			    CT_FILTER_NEGATIVE);
1331
1332	__kernel_filter_start();
1333
1334	nfct_filter_set_logic(STATE(filter),
1335			      NFCT_FILTER_SRC_IPV4,
1336			      NFCT_FILTER_LOGIC_NEGATIVE);
1337	nfct_filter_set_logic(STATE(filter),
1338			      NFCT_FILTER_DST_IPV4,
1339			      NFCT_FILTER_LOGIC_NEGATIVE);
1340	nfct_filter_set_logic(STATE(filter),
1341			      NFCT_FILTER_SRC_IPV6,
1342			      NFCT_FILTER_LOGIC_NEGATIVE);
1343	nfct_filter_set_logic(STATE(filter),
1344			      NFCT_FILTER_DST_IPV6,
1345			      NFCT_FILTER_LOGIC_NEGATIVE);
1346};
1347
1348filter_address_list :
1349		    | filter_address_list filter_address_item;
1350
1351filter_address_item : T_IPV4_ADDR T_IP
1352{
1353	union inet_address ip;
1354	char *slash;
1355	unsigned int cidr = 32;
1356
1357	memset(&ip, 0, sizeof(union inet_address));
1358
1359	slash = strchr($2, '/');
1360	if (slash) {
1361		*slash = '\0';
1362		cidr = atoi(slash+1);
1363		if (cidr > 32) {
1364			print_err(CTD_CFG_WARN, "%s/%d is not a valid network, "
1365						"ignoring", $2, cidr);
1366			break;
1367		}
1368	}
1369
1370	if (!inet_aton($2, &ip.ipv4)) {
1371		print_err(CTD_CFG_WARN, "%s is not a valid IPv4, ignoring", $2);
1372		break;
1373	}
1374
1375	if (slash && cidr < 32) {
1376		/* network byte order */
1377		struct ct_filter_netmask_ipv4 tmp = {
1378			.ip = ip.ipv4,
1379			.mask = ipv4_cidr2mask_net(cidr)
1380		};
1381
1382		if (!ct_filter_add_netmask(STATE(us_filter), &tmp, AF_INET)) {
1383			if (errno == EEXIST)
1384				print_err(CTD_CFG_WARN, "netmask %s is "
1385							"repeated in the "
1386							"ignore pool", $2);
1387		}
1388	} else {
1389		if (!ct_filter_add_ip(STATE(us_filter), &ip, AF_INET)) {
1390			if (errno == EEXIST)
1391				print_err(CTD_CFG_WARN, "IP %s is repeated in "
1392							"the ignore pool", $2);
1393			if (errno == ENOSPC)
1394				print_err(CTD_CFG_WARN, "too many IP in the "
1395							"ignore pool!");
1396		}
1397	}
1398	__kernel_filter_start();
1399
1400	/* host byte order */
1401	struct nfct_filter_ipv4 filter_ipv4 = {
1402		.addr = ntohl(ip.ipv4),
1403		.mask = ipv4_cidr2mask_host(cidr),
1404	};
1405
1406	nfct_filter_add_attr(STATE(filter), NFCT_FILTER_SRC_IPV4, &filter_ipv4);
1407	nfct_filter_add_attr(STATE(filter), NFCT_FILTER_DST_IPV4, &filter_ipv4);
1408};
1409
1410filter_address_item : T_IPV6_ADDR T_IP
1411{
1412	union inet_address ip;
1413	char *slash;
1414	int cidr = 128;
1415	struct nfct_filter_ipv6 filter_ipv6;
1416
1417	memset(&ip, 0, sizeof(union inet_address));
1418
1419	slash = strchr($2, '/');
1420	if (slash) {
1421		*slash = '\0';
1422		cidr = atoi(slash+1);
1423		if (cidr > 128) {
1424			print_err(CTD_CFG_WARN, "%s/%d is not a valid network, "
1425						"ignoring", $2, cidr);
1426			break;
1427		}
1428	}
1429
1430#ifdef HAVE_INET_PTON_IPV6
1431	if (inet_pton(AF_INET6, $2, &ip.ipv6) <= 0) {
1432		print_err(CTD_CFG_WARN, "%s is not a valid IPv6, ignoring", $2);
1433		break;
1434	}
1435#else
1436	print_err(CTD_CFG_WARN, "cannot find inet_pton(), IPv6 unsupported!");
1437	break;
1438#endif
1439	if (slash && cidr < 128) {
1440		struct ct_filter_netmask_ipv6 tmp;
1441
1442		memcpy(tmp.ip, ip.ipv6, sizeof(uint32_t)*4);
1443		ipv6_cidr2mask_net(cidr, tmp.mask);
1444		if (!ct_filter_add_netmask(STATE(us_filter), &tmp, AF_INET6)) {
1445			if (errno == EEXIST)
1446				print_err(CTD_CFG_WARN, "netmask %s is "
1447							"repeated in the "
1448							"ignore pool", $2);
1449		}
1450	} else {
1451		if (!ct_filter_add_ip(STATE(us_filter), &ip, AF_INET6)) {
1452			if (errno == EEXIST)
1453				print_err(CTD_CFG_WARN, "IP %s is repeated in "
1454							"the ignore pool", $2);
1455			if (errno == ENOSPC)
1456				print_err(CTD_CFG_WARN, "too many IP in the "
1457							"ignore pool!");
1458		}
1459	}
1460	__kernel_filter_start();
1461
1462	/* host byte order */
1463	ipv6_addr2addr_host(ip.ipv6, filter_ipv6.addr);
1464	ipv6_cidr2mask_host(cidr, filter_ipv6.mask);
1465
1466	nfct_filter_add_attr(STATE(filter), NFCT_FILTER_SRC_IPV6, &filter_ipv6);
1467	nfct_filter_add_attr(STATE(filter), NFCT_FILTER_DST_IPV6, &filter_ipv6);
1468};
1469
1470filter_item : T_STATE T_ACCEPT '{' filter_state_list '}'
1471{
1472	ct_filter_set_logic(STATE(us_filter),
1473			    CT_FILTER_STATE,
1474			    CT_FILTER_POSITIVE);
1475
1476	__kernel_filter_start();
1477};
1478
1479filter_item : T_STATE T_IGNORE '{' filter_state_list '}'
1480{
1481	ct_filter_set_logic(STATE(us_filter),
1482			    CT_FILTER_STATE,
1483			    CT_FILTER_NEGATIVE);
1484
1485
1486	__kernel_filter_start();
1487
1488	nfct_filter_set_logic(STATE(filter),
1489			      NFCT_FILTER_L4PROTO_STATE,
1490			      NFCT_FILTER_LOGIC_NEGATIVE);
1491};
1492
1493filter_state_list :
1494		  | filter_state_list filter_state_item;
1495
1496filter_state_item : tcp_states T_FOR T_TCP;
1497
1498stats: T_STATS '{' stats_list '}'
1499{
1500	if (conf.flags & CTD_SYNC_MODE) {
1501		print_err(CTD_CFG_ERROR, "cannot use both `Stats' and `Sync' "
1502					 "clauses in conntrackd.conf");
1503		exit(EXIT_FAILURE);
1504	}
1505	conf.flags |= CTD_STATS_MODE;
1506};
1507
1508stats_list:
1509	 | stats_list stat_line
1510	 ;
1511
1512stat_line: stat_logfile_bool
1513	 | stat_logfile_path
1514	 | stat_syslog_bool
1515	 | stat_syslog_facility
1516	 | buffer_size
1517	 ;
1518
1519stat_logfile_bool : T_LOG T_ON
1520{
1521	strncpy(conf.stats.logfile, DEFAULT_STATS_LOGFILE, FILENAME_MAXLEN);
1522};
1523
1524stat_logfile_bool : T_LOG T_OFF
1525{
1526};
1527
1528stat_logfile_path : T_LOG T_PATH_VAL
1529{
1530	strncpy(conf.stats.logfile, $2, FILENAME_MAXLEN);
1531};
1532
1533stat_syslog_bool : T_SYSLOG T_ON
1534{
1535	conf.stats.syslog_facility = DEFAULT_SYSLOG_FACILITY;
1536};
1537
1538stat_syslog_bool : T_SYSLOG T_OFF
1539{
1540	conf.stats.syslog_facility = -1;
1541}
1542
1543stat_syslog_facility : T_SYSLOG T_STRING
1544{
1545	if (!strcmp($2, "daemon"))
1546		conf.stats.syslog_facility = LOG_DAEMON;
1547	else if (!strcmp($2, "local0"))
1548		conf.stats.syslog_facility = LOG_LOCAL0;
1549	else if (!strcmp($2, "local1"))
1550		conf.stats.syslog_facility = LOG_LOCAL1;
1551	else if (!strcmp($2, "local2"))
1552		conf.stats.syslog_facility = LOG_LOCAL2;
1553	else if (!strcmp($2, "local3"))
1554		conf.stats.syslog_facility = LOG_LOCAL3;
1555	else if (!strcmp($2, "local4"))
1556		conf.stats.syslog_facility = LOG_LOCAL4;
1557	else if (!strcmp($2, "local5"))
1558		conf.stats.syslog_facility = LOG_LOCAL5;
1559	else if (!strcmp($2, "local6"))
1560		conf.stats.syslog_facility = LOG_LOCAL6;
1561	else if (!strcmp($2, "local7"))
1562		conf.stats.syslog_facility = LOG_LOCAL7;
1563	else {
1564		print_err(CTD_CFG_WARN, "'%s' is not a known syslog facility, "
1565					"ignoring.", $2);
1566		break;
1567	}
1568
1569	if (conf.syslog_facility != -1 &&
1570	    conf.stats.syslog_facility != conf.syslog_facility)
1571		print_err(CTD_CFG_WARN, "conflicting Syslog facility "
1572					"values, defaulting to General");
1573};
1574
1575buffer_size: T_STAT_BUFFER_SIZE T_NUMBER
1576{
1577	print_err(CTD_CFG_WARN, "`LogFileBufferSize' is deprecated");
1578};
1579
1580helper: T_HELPER '{' helper_list '}'
1581{
1582	conf.flags |= CTD_HELPER;
1583};
1584
1585helper_list:
1586	    | helper_list helper_line
1587	    ;
1588
1589helper_line: helper_type
1590	    ;
1591
1592helper_type: T_TYPE T_STRING T_STRING T_STRING '{' helper_type_list  '}'
1593{
1594	struct ctd_helper_instance *helper_inst;
1595	struct ctd_helper *helper;
1596	struct stack_item *e;
1597	uint16_t l3proto;
1598	uint8_t l4proto;
1599
1600	if (strcmp($3, "inet") == 0)
1601		l3proto = AF_INET;
1602	else if (strcmp($3, "inet6") == 0)
1603		l3proto = AF_INET6;
1604	else {
1605		print_err(CTD_CFG_ERROR, "unknown layer 3 protocol");
1606		exit(EXIT_FAILURE);
1607	}
1608
1609	if (strcmp($4, "tcp") == 0)
1610		l4proto = IPPROTO_TCP;
1611	else if (strcmp($4, "udp") == 0)
1612		l4proto = IPPROTO_UDP;
1613	else {
1614		print_err(CTD_CFG_ERROR, "unknown layer 4 protocol");
1615		exit(EXIT_FAILURE);
1616	}
1617
1618	/* XXX use configure.ac definitions. */
1619	helper = helper_find("/usr/lib/conntrack-tools", $2, l4proto, RTLD_NOW);
1620	if (helper == NULL) {
1621		print_err(CTD_CFG_ERROR, "Unknown `%s' helper", $2);
1622		exit(EXIT_FAILURE);
1623	}
1624
1625	helper_inst = calloc(1, sizeof(struct ctd_helper_instance));
1626	if (helper_inst == NULL)
1627		break;
1628
1629	helper_inst->l3proto = l3proto;
1630	helper_inst->l4proto = l4proto;
1631	helper_inst->helper = helper;
1632
1633	while ((e = stack_item_pop(&symbol_stack, -1)) != NULL) {
1634
1635		switch(e->type) {
1636		case SYMBOL_HELPER_QUEUE_NUM: {
1637			int *qnum = (int *) &e->data;
1638
1639			helper_inst->queue_num = *qnum;
1640			stack_item_free(e);
1641			break;
1642		}
1643		case SYMBOL_HELPER_QUEUE_LEN: {
1644			int *qlen = (int *) &e->data;
1645
1646			helper_inst->queue_len = *qlen;
1647			stack_item_free(e);
1648			break;
1649		}
1650		case SYMBOL_HELPER_POLICY_EXPECT_ROOT: {
1651			struct ctd_helper_policy *pol =
1652				(struct ctd_helper_policy *) &e->data;
1653			struct ctd_helper_policy *matching = NULL;
1654			int i;
1655
1656			for (i=0; i<CTD_HELPER_POLICY_MAX; i++) {
1657				if (strcmp(helper->policy[i].name,
1658					   pol->name) != 0)
1659					continue;
1660
1661				matching = pol;
1662				break;
1663			}
1664			if (matching == NULL) {
1665				print_err(CTD_CFG_ERROR,
1666					  "Unknown policy `%s' in helper "
1667					  "configuration", pol->name);
1668				exit(EXIT_FAILURE);
1669			}
1670			/* FIXME: First set default policy, then change only
1671			 * tuned fields, not everything.
1672			 */
1673			memcpy(&helper->policy[i], pol,
1674				sizeof(struct ctd_helper_policy));
1675
1676			stack_item_free(e);
1677			break;
1678		}
1679		default:
1680			print_err(CTD_CFG_ERROR,
1681				  "Unexpected symbol parsing helper policy");
1682				exit(EXIT_FAILURE);
1683			break;
1684		}
1685	}
1686	list_add(&helper_inst->head, &CONFIG(cthelper).list);
1687};
1688
1689helper_type_list:
1690		| helper_type_list helper_type_line
1691		;
1692
1693helper_type_line: helper_type
1694		;
1695
1696helper_type: T_HELPER_QUEUE_NUM T_NUMBER
1697{
1698	int *qnum;
1699	struct stack_item *e;
1700
1701	e = stack_item_alloc(SYMBOL_HELPER_QUEUE_NUM, sizeof(int));
1702	qnum = (int *) e->data;
1703	*qnum = $2;
1704	stack_item_push(&symbol_stack, e);
1705};
1706
1707helper_type: T_HELPER_QUEUE_LEN T_NUMBER
1708{
1709	int *qlen;
1710	struct stack_item *e;
1711
1712	e = stack_item_alloc(SYMBOL_HELPER_QUEUE_LEN, sizeof(int));
1713	qlen = (int *) e->data;
1714	*qlen = $2;
1715	stack_item_push(&symbol_stack, e);
1716};
1717
1718helper_type: T_HELPER_POLICY T_STRING '{' helper_policy_list '}'
1719{
1720	struct stack_item *e;
1721	struct ctd_helper_policy *policy;
1722
1723	e = stack_item_pop(&symbol_stack, SYMBOL_HELPER_EXPECT_POLICY_LEAF);
1724	if (e == NULL) {
1725		print_err(CTD_CFG_ERROR,
1726			  "Helper policy configuration empty, fix your "
1727			  "configuration file, please");
1728		exit(EXIT_FAILURE);
1729		break;
1730	}
1731
1732	policy = (struct ctd_helper_policy *) &e->data;
1733	strncpy(policy->name, $2, CTD_HELPER_NAME_LEN);
1734	policy->name[CTD_HELPER_NAME_LEN-1] = '\0';
1735	/* Now object is complete. */
1736	e->type = SYMBOL_HELPER_POLICY_EXPECT_ROOT;
1737	stack_item_push(&symbol_stack, e);
1738};
1739
1740helper_policy_list:
1741		  | helper_policy_list helper_policy_line
1742		  ;
1743
1744helper_policy_line: helper_policy_expect_max
1745		  | helper_policy_expect_timeout
1746		  ;
1747
1748helper_policy_expect_max: T_HELPER_EXPECT_MAX T_NUMBER
1749{
1750	struct stack_item *e;
1751	struct ctd_helper_policy *policy;
1752
1753	e = stack_item_pop(&symbol_stack, SYMBOL_HELPER_EXPECT_POLICY_LEAF);
1754	if (e == NULL) {
1755		e = stack_item_alloc(SYMBOL_HELPER_EXPECT_POLICY_LEAF,
1756				     sizeof(struct ctd_helper_policy));
1757	}
1758	policy = (struct ctd_helper_policy *) &e->data;
1759	policy->expect_max = $2;
1760	stack_item_push(&symbol_stack, e);
1761};
1762
1763helper_policy_expect_timeout: T_HELPER_EXPECT_TIMEOUT T_NUMBER
1764{
1765	struct stack_item *e;
1766	struct ctd_helper_policy *policy;
1767
1768	e = stack_item_pop(&symbol_stack, SYMBOL_HELPER_EXPECT_POLICY_LEAF);
1769	if (e == NULL) {
1770		e = stack_item_alloc(SYMBOL_HELPER_EXPECT_POLICY_LEAF,
1771				     sizeof(struct ctd_helper_policy));
1772	}
1773	policy = (struct ctd_helper_policy *) &e->data;
1774	policy->expect_timeout = $2;
1775	stack_item_push(&symbol_stack, e);
1776};
1777
1778%%
1779
1780int __attribute__((noreturn))
1781yyerror(char *msg)
1782{
1783	print_err(CTD_CFG_ERROR, "parsing config file in "
1784				 "line (%d), symbol '%s': %s",
1785				 yylineno, yytext, msg);
1786	exit(EXIT_FAILURE);
1787}
1788
1789static void print_err(int type, const char *msg, ...)
1790{
1791	va_list args;
1792
1793	va_start(args, msg);
1794	switch(type) {
1795	case CTD_CFG_ERROR:
1796		fprintf(stderr, "ERROR: ");
1797		break;
1798	case CTD_CFG_WARN:
1799		fprintf(stderr, "WARNING: ");
1800		break;
1801	default:
1802		fprintf(stderr, "?: ");
1803	}
1804	vfprintf(stderr, msg, args);
1805	va_end(args);
1806	fprintf(stderr,"\n");
1807}
1808
1809static void __kernel_filter_start(void)
1810{
1811	if (!STATE(filter)) {
1812		STATE(filter) = nfct_filter_create();
1813		if (!STATE(filter)) {
1814			print_err(CTD_CFG_ERROR, "cannot create ignore pool!");
1815			exit(EXIT_FAILURE);
1816		}
1817	}
1818}
1819
1820static void __kernel_filter_add_state(int value)
1821{
1822	__kernel_filter_start();
1823
1824	struct nfct_filter_proto filter_proto = {
1825		.proto = IPPROTO_TCP,
1826		.state = value
1827	};
1828	nfct_filter_add_attr(STATE(filter),
1829			     NFCT_FILTER_L4PROTO_STATE,
1830			     &filter_proto);
1831}
1832
1833static void __max_dedicated_links_reached(void)
1834{
1835	if (conf.channel_num >= MULTICHANNEL_MAX) {
1836		print_err(CTD_CFG_ERROR, "too many dedicated links in "
1837					 "the configuration file "
1838					 "(Maximum: %d)", MULTICHANNEL_MAX);
1839		exit(EXIT_FAILURE);
1840	}
1841}
1842
1843int
1844init_config(char *filename)
1845{
1846	FILE *fp;
1847
1848	fp = fopen(filename, "r");
1849	if (!fp)
1850		return -1;
1851
1852	/* Zero may be a valid facility */
1853	CONFIG(syslog_facility) = -1;
1854	CONFIG(stats).syslog_facility = -1;
1855	CONFIG(netlink).subsys_id = -1;
1856
1857	/* Initialize list of user-space helpers */
1858	INIT_LIST_HEAD(&CONFIG(cthelper).list);
1859
1860	stack_init(&symbol_stack);
1861
1862	yyrestart(fp);
1863	yyparse();
1864	fclose(fp);
1865
1866	/* default to IPv4 */
1867	if (CONFIG(family) == 0)
1868		CONFIG(family) = AF_INET;
1869
1870	/* set to default is not specified */
1871	if (strcmp(CONFIG(lockfile), "") == 0)
1872		strncpy(CONFIG(lockfile), DEFAULT_LOCKFILE, FILENAME_MAXLEN);
1873
1874	/* default to 180 seconds of expiration time: cache entries */
1875	if (CONFIG(cache_timeout) == 0)
1876		CONFIG(cache_timeout) = 180;
1877
1878	/* default to 60 seconds: purge kernel entries */
1879	if (CONFIG(purge_timeout) == 0)
1880		CONFIG(purge_timeout) = 60;
1881
1882	/* default to 60 seconds of refresh time */
1883	if (CONFIG(refresh) == 0)
1884		CONFIG(refresh) = 60;
1885
1886	if (CONFIG(resend_queue_size) == 0)
1887		CONFIG(resend_queue_size) = 131072;
1888
1889	/* default to a window size of 300 packets */
1890	if (CONFIG(window_size) == 0)
1891		CONFIG(window_size) = 300;
1892
1893	if (CONFIG(event_iterations_limit) == 0)
1894		CONFIG(event_iterations_limit) = 100;
1895
1896	/* default number of bucket of the hashtable that are committed in
1897	   one run loop. XXX: no option available to tune this value yet. */
1898	if (CONFIG(general).commit_steps == 0)
1899		CONFIG(general).commit_steps = 8192;
1900
1901	/* if overrun, automatically resync with kernel after 30 seconds */
1902	if (CONFIG(nl_overrun_resync) == 0)
1903		CONFIG(nl_overrun_resync) = 30;
1904
1905	/* default to 128 elements in the channel error queue */
1906	if (CONFIG(channelc).error_queue_length == 0)
1907		CONFIG(channelc).error_queue_length = 128;
1908
1909	if (CONFIG(netlink).subsys_id == -1) {
1910		CONFIG(netlink).subsys_id = NFNL_SUBSYS_CTNETLINK;
1911		CONFIG(netlink).groups = NF_NETLINK_CONNTRACK_NEW |
1912					 NF_NETLINK_CONNTRACK_UPDATE |
1913					 NF_NETLINK_CONNTRACK_DESTROY;
1914	}
1915
1916	return 0;
1917}
1918