Move mjpg-streamer.pot to the right directory
[project/luci.git] / contrib / fwd / src / fwd_xtables.c
1 /*
2  * fwd - OpenWrt firewall daemon - libiptc/libxtables interface
3  *
4  *   Copyright (C) 2009 Jo-Philipp Wich <xm@subsignal.org>
5  *
6  * The fwd program is free software: you can redistribute it and/or
7  * modify it under the terms of the GNU General Public License version 2
8  * as published by the Free Software Foundation.
9  *
10  * The fwd 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.
13  * See the GNU General Public License for more details.
14  *
15  * You should have received a copy of the GNU General Public License along
16  * with the fwd program. If not, see http://www.gnu.org/licenses/.
17  */
18
19
20 #include "fwd.h"
21 #include "fwd_xtables.h"
22 #include "fwd_utils.h"
23
24
25 /* Required by certain extensions like SNAT and DNAT */
26 int kernel_version;
27
28 extern void
29 get_kernel_version(void) {
30         static struct utsname uts;
31         int x = 0, y = 0, z = 0;
32
33         if (uname(&uts) == -1) {
34                 fprintf(stderr, "Unable to retrieve kernel version.\n");
35                 xtables_free_opts(1);
36                 exit(1);
37         }
38
39         sscanf(uts.release, "%d.%d.%d", &x, &y, &z);
40         kernel_version = LINUX_VERSION(x, y, z);
41 }
42
43
44 static void xt_exit_error(enum xtables_exittype status, const char *msg, ...)
45 {
46         va_list ap;
47         va_start(ap, msg);
48         vprintf(msg, ap);
49         va_end(ap);     
50         exit(1);
51 }
52
53 void fwd_xt_init(void)
54 {
55         struct xtables_globals xt_globals = {
56                 .option_offset = 0,
57                 .program_version = IPTABLES_VERSION,
58                 .opts = 0,
59                 .orig_opts = 0,
60                 .exit_err = (void *)&xt_exit_error,
61         };
62
63         xtables_init();
64         xtables_set_nfproto(NFPROTO_IPV4);
65         xtables_set_params(&xt_globals);
66 }
67
68
69 struct fwd_xt_rule * fwd_xt_init_rule(struct iptc_handle *h)
70 {
71         struct fwd_xt_rule *r;
72
73         if( (r = fwd_alloc_ptr(struct fwd_xt_rule)) != NULL )
74         {
75                 if( (r->entry = fwd_alloc_ptr(struct ipt_entry)) != NULL )
76                 {
77                         r->iptc = h;
78                         return r;
79                 }
80         }
81
82         fwd_free_ptr(r);
83         return NULL;
84 }
85
86 void fwd_xt_parse_frag(
87         struct fwd_xt_rule *r, int frag, int inv
88 ) {
89         if( frag )
90         {
91                 r->entry->ip.flags |= IPT_F_FRAG;
92
93                 if( inv )
94                         r->entry->ip.invflags |= IPT_INV_FRAG;
95         }
96 }
97
98 void fwd_xt_parse_proto(
99         struct fwd_xt_rule *r, struct fwd_proto *p, int inv
100 ) {
101         if( p != NULL )
102         {
103                 switch(p->type)
104                 {
105                         case FWD_PR_TCP:
106                                 r->entry->ip.proto = 6;
107                                 break;
108
109                         case FWD_PR_UDP:
110                                 r->entry->ip.proto = 17;
111                                 break;
112
113                         case FWD_PR_ICMP:
114                                 r->entry->ip.proto = 1;
115                                 break;
116
117                         case FWD_PR_CUSTOM:
118                                 r->entry->ip.proto = p->proto;
119                                 break;
120
121                         case FWD_PR_ALL:
122                         case FWD_PR_TCPUDP:
123                                 r->entry->ip.proto = 0;
124                                 break;
125                 }
126
127                 if( inv )
128                         r->entry->ip.invflags |= IPT_INV_PROTO;
129         }
130 }
131
132 void fwd_xt_parse_in(
133         struct fwd_xt_rule *r, struct fwd_network *n, int inv
134 ) {
135         if( n != NULL )
136         {
137                 strncpy(r->entry->ip.iniface, n->ifname, IFNAMSIZ);
138
139                 if( inv )
140                         r->entry->ip.invflags |= IPT_INV_VIA_IN;
141         }
142 }
143
144 void fwd_xt_parse_out(
145         struct fwd_xt_rule *r, struct fwd_network *n, int inv
146 ) {
147         if( n != NULL )
148         {
149                 strncpy(r->entry->ip.outiface, n->ifname, IFNAMSIZ);
150
151                 if( inv )
152                         r->entry->ip.invflags |= IPT_INV_VIA_OUT;
153         }
154 }
155
156 void fwd_xt_parse_src(
157         struct fwd_xt_rule *r, struct fwd_cidr *c, int inv
158 ) {
159         if( c != NULL )
160         {
161                 r->entry->ip.src.s_addr  = c->addr.s_addr;
162                 r->entry->ip.smsk.s_addr = htonl(~((1 << (32 - c->prefix)) - 1));
163
164                 if( inv )
165                         r->entry->ip.invflags |= IPT_INV_SRCIP;
166         }
167 }
168
169 void fwd_xt_parse_dest(
170         struct fwd_xt_rule *r, struct fwd_cidr *c, int inv
171 ) {
172         if( c != NULL )
173         {
174                 r->entry->ip.dst.s_addr  = c->addr.s_addr;
175                 r->entry->ip.dmsk.s_addr = htonl(~((1 << (32 - c->prefix)) - 1));
176
177                 if( inv )
178                         r->entry->ip.invflags |= IPT_INV_DSTIP;
179         }
180 }
181
182
183 struct xtables_match * fwd_xt_get_match(
184         struct fwd_xt_rule *r, const char *name
185 ) {
186         struct xtables_match *m = xtables_find_match(name, XTF_TRY_LOAD, &r->matches);
187         size_t s;
188
189         if( m != NULL )
190         {
191                 s = IPT_ALIGN(sizeof(struct ipt_entry_match)) + m->size;
192
193                 if(     (m->m = malloc(s)) != NULL )
194                 {
195                         memset(m->m, 0, s);
196                         strcpy(m->m->u.user.name, m->name);
197                         m->m->u.match_size = s;
198
199                         if( m->init )
200                                 m->init(m->m);
201
202                         return m;
203                 }
204         }
205
206         return NULL;
207 }
208
209 void __fwd_xt_parse_match(
210         struct fwd_xt_rule *r, struct xtables_match *m, ...
211 ) {
212         char optc;
213         char *s, **opts;
214         size_t len = 1;
215         int inv = 0;
216
217         va_list ap;
218         va_start(ap, m);
219
220         opts = malloc(len * sizeof(*opts));
221         opts[0] = "x";
222
223         while( (s = (char *)va_arg(ap, char *)) != NULL )
224         {
225                 opts = realloc(opts, ++len * sizeof(*opts));
226                 opts[len-1] = s;
227         }
228
229         va_end(ap);
230
231         if( len > 1 )
232         {
233                 optind = 0;
234
235                 while( (optc = getopt_long(len, opts, "", m->extra_opts, NULL)) > -1 )
236                 {
237                         if( (optc == '?') && (optarg[0] == '!') && (optarg[1] == '\0') )
238                         {
239                                 inv = 1;
240                                 continue;
241                         }
242
243                         m->parse(optc, opts, inv, &m->mflags, r->entry, &m->m);
244                         inv = 0;
245                 }
246         }
247
248         free(opts);
249 }
250
251
252 struct xtables_target * fwd_xt_get_target(
253         struct fwd_xt_rule *r, const char *name
254 ) {
255         struct xtables_target *t = xtables_find_target(name, XTF_TRY_LOAD);
256         size_t s;
257
258         if( !t )
259                 t = xtables_find_target(IPT_STANDARD_TARGET, XTF_LOAD_MUST_SUCCEED);
260
261         if( t != NULL )
262         {
263                 s = IPT_ALIGN(sizeof(struct ipt_entry_target)) + t->size;
264
265                 if(     (t->t = malloc(s)) != NULL )
266                 {
267                         memset(t->t, 0, s);
268                         strcpy(t->t->u.user.name, name);
269                         t->t->u.target_size = s;
270                         xtables_set_revision(t->t->u.user.name, t->revision);
271
272                         if( t->init )
273                                 t->init(t->t);
274
275                         r->target = t;
276
277                         return t;
278                 }
279         }
280
281         return NULL;
282 }
283
284 void __fwd_xt_parse_target(
285         struct fwd_xt_rule *r, struct xtables_target *t, ...
286 ) {
287         char optc;
288         char *s, **opts;
289         size_t len = 1;
290         int inv = 0;
291
292         va_list ap;
293         va_start(ap, t);
294
295         opts = malloc(len * sizeof(*opts));
296         opts[0] = "x";
297
298         while( (s = (char *)va_arg(ap, char *)) != NULL )
299         {
300                 opts = realloc(opts, ++len * sizeof(*opts));
301                 opts[len-1] = s;
302         }
303
304         va_end(ap);
305
306         if( len > 1 )
307         {
308                 optind = 0;
309
310                 while( (optc = getopt_long(len, opts, "", t->extra_opts, NULL)) > -1 )
311                 {
312                         if( (optc == '?') && (optarg[0] == '!') && (optarg[1] == '\0') )
313                         {
314                                 inv = 1;
315                                 continue;
316                         }
317
318                         t->parse(optc, opts, inv, &t->tflags, r->entry, &t->t);
319                         inv = 0;
320                 }
321         }
322
323         free(opts);
324 }
325
326
327 static int fwd_xt_exec_rule(struct fwd_xt_rule *r, const char *chain, int pos)
328 {
329         size_t s;
330         struct xtables_rule_match *m, *next;
331         struct xtables_match *em;
332         struct xtables_target *et;
333         struct ipt_entry *e;
334         int rv = 0;
335
336         s = IPT_ALIGN(sizeof(struct ipt_entry));
337
338         for( m = r->matches; m; m = m->next )
339                 s += m->match->m->u.match_size;
340
341         if( (e = malloc(s + r->target->t->u.target_size)) != NULL )
342         {
343                 memset(e, 0, s + r->target->t->u.target_size);
344                 memcpy(e, r->entry, sizeof(struct ipt_entry));
345
346                 e->target_offset = s;
347                 e->next_offset = s + r->target->t->u.target_size;
348
349                 s = 0;
350
351                 for( m = r->matches; m; m = m->next )
352                 {
353                         memcpy(e->elems + s, m->match->m, m->match->m->u.match_size);
354                         s += m->match->m->u.match_size;
355                 }
356
357                 memcpy(e->elems + s, r->target->t, r->target->t->u.target_size);
358
359                 rv = (pos > -1)
360                         ? iptc_insert_entry(chain, e, (unsigned int) pos, r->iptc)
361                         : iptc_append_entry(chain, e, r->iptc)
362                 ;
363         }
364         else
365         {
366                 errno = ENOMEM;
367         }
368
369
370         fwd_free_ptr(e);
371         fwd_free_ptr(r->entry);
372         fwd_free_ptr(r->target->t);
373
374         for( m = r->matches; m; )
375         {
376                 next = m->next;
377                 fwd_free_ptr(m->match->m);
378
379                 if( m->match == m->match->next )
380                         fwd_free_ptr(m->match);
381
382                 fwd_free_ptr(m);
383                 m = next;
384         }
385
386         fwd_free_ptr(r);
387
388         /* reset all targets and matches */
389         for (em = xtables_matches; em; em = em->next)
390                 em->mflags = 0;
391
392         for (et = xtables_targets; et; et = et->next)
393         {
394                 et->tflags = 0;
395                 et->used = 0;
396         }
397
398         return rv;
399 }
400
401 int fwd_xt_insert_rule(
402         struct fwd_xt_rule *r, const char *chain, unsigned int pos
403 ) {
404         return fwd_xt_exec_rule(r, chain, pos);
405 }
406
407 int fwd_xt_append_rule(
408         struct fwd_xt_rule *r, const char *chain
409 ) {
410         return fwd_xt_exec_rule(r, chain, -1);
411 }
412