• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 %{
2 /*
3  * (C) 2012 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 software has been sponsored by Sophos Astaro <http://www.sophos.com>
11  */
12 
13 #include <stdio.h>
14 #include <stdlib.h>
15 #include <stdint.h>
16 #include <string.h>
17 #include <errno.h>
18 #include <stdarg.h>
19 #include <libiptc/linux_list.h>
20 #include <libnftnl/table.h>
21 #include <libnftnl/chain.h>
22 
23 #include <netinet/in.h>
24 #include <linux/netfilter.h>
25 
26 extern char *yytext;
27 extern int yylineno;
28 
29 static LIST_HEAD(xtables_stack);
30 
31 struct stack_elem {
32 	struct list_head	head;
33 	int			token;
34 	size_t			size;
35 	char			data[];
36 };
37 
stack_push(int token,size_t size)38 static void *stack_push(int token, size_t size)
39 {
40 	struct stack_elem *e;
41 
42 	e = calloc(1, sizeof(struct stack_elem) + size);
43 
44 	e->token = token;
45 	e->size = size;
46 
47 	list_add(&e->head, &xtables_stack);
48 
49 	return e->data;
50 }
51 
stack_pop(void)52 static struct stack_elem *stack_pop(void)
53 {
54 	struct stack_elem *e;
55 
56 	e = list_entry(xtables_stack.next, struct stack_elem, head);
57 
58 	if (&e->head == &xtables_stack)
59 		return NULL;
60 
61 	list_del(&e->head);
62 	return e;
63 }
64 
stack_put_i32(void * data,int value)65 static inline void stack_put_i32(void *data, int value)
66 {
67 	memcpy(data, &value, sizeof(int));
68 }
69 
stack_put_str(void * data,const char * str)70 static inline void stack_put_str(void *data, const char *str)
71 {
72 	memcpy(data, str, strlen(str));
73 }
74 
stack_free(struct stack_elem * e)75 static void stack_free(struct stack_elem *e)
76 {
77 	free(e);
78 }
79 
80 %}
81 
82 %union {
83 	int	val;
84 	char	*string;
85 }
86 
87 %token T_FAMILY
88 %token T_TABLE
89 %token T_CHAIN
90 %token T_HOOK
91 %token T_PRIO
92 
93 %token <string> T_STRING
94 %token <val>	T_INTEGER
95 
96 %%
97 
98 configfile	:
99 		| lines
100 		;
101 
102 lines		: line
103 		| lines line
104 		;
105 
106 line		: family
107 		;
108 
109 family		: T_FAMILY T_STRING '{' tables '}'
110 		{
111 			void *data = stack_push(T_FAMILY, strlen($2)+1);
112 			stack_put_str(data, $2);
113 		}
114 		;
115 
116 tables		: table
117 		| tables table
118 		;
119 
120 table		: T_TABLE T_STRING '{' chains '}'
121 		{
122 			/* added in reverse order to pop it in order */
123 			void *data = stack_push(T_TABLE, strlen($2)+1);
124 			stack_put_str(data, $2);
125 		}
126 		;
127 
128 chains		: chain
129 		| chains chain
130 		;
131 
132 chain		: T_CHAIN T_STRING T_HOOK T_STRING T_PRIO T_INTEGER
133 		{
134 			/* added in reverse order to pop it in order */
135 			void *data = stack_push(T_PRIO, sizeof(int32_t));
136 			stack_put_i32(data, $6);
137 			data = stack_push(T_HOOK, strlen($4)+1);
138 			stack_put_str(data, $4);
139 			data = stack_push(T_CHAIN, strlen($2)+1);
140 			stack_put_str(data, $2);
141 		}
142 		;
143 
144 %%
145 
146 int __attribute__((noreturn))
147 yyerror(char *msg)
148 {
149 	fprintf(stderr, "parsing config file in line (%d), symbol '%s': %s\n",
150 			 yylineno, yytext, msg);
151 	exit(EXIT_FAILURE);
152 }
153 
hooknametonum(const char * hookname)154 static int hooknametonum(const char *hookname)
155 {
156 	if (strcmp(hookname, "NF_INET_LOCAL_IN") == 0)
157 		return NF_INET_LOCAL_IN;
158 	else if (strcmp(hookname, "NF_INET_FORWARD") == 0)
159 		return NF_INET_FORWARD;
160 	else if (strcmp(hookname, "NF_INET_LOCAL_OUT") == 0)
161 		return NF_INET_LOCAL_OUT;
162 	else if (strcmp(hookname, "NF_INET_PRE_ROUTING") == 0)
163 		return NF_INET_PRE_ROUTING;
164 	else if (strcmp(hookname, "NF_INET_POST_ROUTING") == 0)
165 		return NF_INET_POST_ROUTING;
166 
167 	return -1;
168 }
169 
familytonumber(const char * family)170 static int32_t familytonumber(const char *family)
171 {
172 	if (strcmp(family, "ipv4") == 0)
173 		return AF_INET;
174 	else if (strcmp(family, "ipv6") == 0)
175 		return AF_INET6;
176 
177 	return -1;
178 }
179 
xtables_config_parse(char * filename,struct nftnl_table_list * table_list,struct nftnl_chain_list * chain_list)180 int xtables_config_parse(char *filename, struct nftnl_table_list *table_list,
181 			 struct nftnl_chain_list *chain_list)
182 {
183 	FILE *fp;
184 	struct stack_elem *e;
185 	struct nftnl_table *table = NULL;
186 	struct nftnl_chain *chain = NULL;
187 	int prio = 0;
188 	int32_t family = 0;
189 
190 	fp = fopen(filename, "r");
191 	if (!fp)
192 		return -1;
193 
194 	yyrestart(fp);
195 	yyparse();
196 	fclose(fp);
197 
198 	for (e = stack_pop(); e != NULL; e = stack_pop()) {
199 		switch(e->token) {
200 		case T_FAMILY:
201 			family = familytonumber(e->data);
202 			if (family == -1)
203 				return -1;
204 			break;
205 		case T_TABLE:
206 			table = nftnl_table_alloc();
207 			if (table == NULL)
208 				return -1;
209 
210 			nftnl_table_set_u32(table, NFTNL_TABLE_FAMILY, family);
211 			nftnl_table_set(table, NFTNL_TABLE_NAME, e->data);
212 			/* This is intentionally prepending, instead of
213 			 * appending, since the elements in the stack are in
214 			 * the reverse order that chains appear in the
215 			 * configuration file.
216 			 */
217 			nftnl_table_list_add(table, table_list);
218 			break;
219 		case T_PRIO:
220 			memcpy(&prio, e->data, sizeof(int32_t));
221 			break;
222 		case T_CHAIN:
223 			chain = nftnl_chain_alloc();
224 			if (chain == NULL)
225 				return -1;
226 
227 			nftnl_chain_set(chain, NFTNL_CHAIN_TABLE,
228 				(char *)nftnl_table_get(table, NFTNL_TABLE_NAME));
229 			nftnl_chain_set_u32(chain, NFTNL_CHAIN_FAMILY,
230 				nftnl_table_get_u32(table, NFTNL_TABLE_FAMILY));
231 			nftnl_chain_set_s32(chain, NFTNL_CHAIN_PRIO, prio);
232 			nftnl_chain_set(chain, NFTNL_CHAIN_NAME, e->data);
233 			/* Intentionally prepending, instead of appending */
234 			nftnl_chain_list_add(chain, chain_list);
235 			break;
236 		case T_HOOK:
237 			nftnl_chain_set_u32(chain, NFTNL_CHAIN_HOOKNUM,
238 						hooknametonum(e->data));
239 			break;
240 		default:
241 			printf("unknown token type %d\n", e->token);
242 			break;
243 		}
244 		stack_free(e);
245 	}
246 
247 	return 0;
248 }
249