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