Home | History | Annotate | Download | only in iptables
      1 %{
      2 /*
      3  * (C) 2012 by Pablo Neira Ayuso <pablo (at) 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 
     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 
     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 
     65 static inline void stack_put_i32(void *data, int value)
     66 {
     67 	memcpy(data, &value, sizeof(int));
     68 }
     69 
     70 static inline void stack_put_str(void *data, const char *str)
     71 {
     72 	memcpy(data, str, strlen(str));
     73 }
     74 
     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 
    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 
    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 
    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