66c186580428405da587eb8c2dd01c4b49e5e7a3
[project/firewall3.git] / utils.c
1 /*
2  * firewall3 - 3rd OpenWrt UCI firewall implementation
3  *
4  *   Copyright (C) 2013 Jo-Philipp Wich <jow@openwrt.org>
5  *
6  * Permission to use, copy, modify, and/or distribute this software for any
7  * purpose with or without fee is hereby granted, provided that the above
8  * copyright notice and this permission notice appear in all copies.
9  *
10  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17  */
18
19 #include "utils.h"
20 #include "options.h"
21
22 #include "zones.h"
23 #include "ipsets.h"
24
25
26 static int lock_fd = -1;
27 static pid_t pipe_pid = -1;
28 static FILE *pipe_fd = NULL;
29
30 bool fw3_pr_debug = false;
31
32
33 static void
34 warn_elem_section_name(struct uci_section *s, bool find_name)
35 {
36         int i = 0;
37         struct uci_option *o;
38         struct uci_element *tmp;
39
40         if (s->anonymous)
41         {
42                 uci_foreach_element(&s->package->sections, tmp)
43                 {
44                         if (strcmp(uci_to_section(tmp)->type, s->type))
45                                 continue;
46
47                         if (&s->e == tmp)
48                                 break;
49
50                         i++;
51                 }
52
53                 fprintf(stderr, "@%s[%d]", s->type, i);
54
55                 if (find_name)
56                 {
57                         uci_foreach_element(&s->options, tmp)
58                         {
59                                 o = uci_to_option(tmp);
60
61                                 if (!strcmp(tmp->name, "name") && (o->type == UCI_TYPE_STRING))
62                                 {
63                                         fprintf(stderr, " (%s)", o->v.string);
64                                         break;
65                                 }
66                         }
67                 }
68         }
69         else
70         {
71                 fprintf(stderr, "'%s'", s->e.name);
72         }
73
74         if (find_name)
75                 fprintf(stderr, " ");
76 }
77
78 void
79 warn_elem(struct uci_element *e, const char *format, ...)
80 {
81         if (e->type == UCI_TYPE_SECTION)
82         {
83                 fprintf(stderr, "Warning: Section ");
84                 warn_elem_section_name(uci_to_section(e), true);
85         }
86         else if (e->type == UCI_TYPE_OPTION)
87         {
88                 fprintf(stderr, "Warning: Option ");
89                 warn_elem_section_name(uci_to_option(e)->section, false);
90                 fprintf(stderr, ".%s ", e->name);
91         }
92
93     va_list argptr;
94     va_start(argptr, format);
95     vfprintf(stderr, format, argptr);
96     va_end(argptr);
97
98         fprintf(stderr, "\n");
99 }
100
101 void
102 warn(const char* format, ...)
103 {
104         fprintf(stderr, "Warning: ");
105     va_list argptr;
106     va_start(argptr, format);
107     vfprintf(stderr, format, argptr);
108     va_end(argptr);
109         fprintf(stderr, "\n");
110 }
111
112 void
113 error(const char* format, ...)
114 {
115         fprintf(stderr, "Error: ");
116     va_list argptr;
117     va_start(argptr, format);
118     vfprintf(stderr, format, argptr);
119     va_end(argptr);
120         fprintf(stderr, "\n");
121
122         exit(1);
123 }
124
125 void
126 info(const char* format, ...)
127 {
128         va_list argptr;
129     va_start(argptr, format);
130     vfprintf(stderr, format, argptr);
131     va_end(argptr);
132         fprintf(stderr, "\n");
133 }
134
135 void *
136 fw3_alloc(size_t size)
137 {
138         void *mem;
139
140         mem = calloc(1, size);
141
142         if (!mem)
143                 error("Out of memory while allocating %d bytes", size);
144
145         return mem;
146 }
147
148 char *
149 fw3_strdup(const char *s)
150 {
151         char *ns;
152
153         ns = strdup(s);
154
155         if (!ns)
156                 error("Out of memory while duplicating string '%s'", s);
157
158         return ns;
159 }
160
161 const char *
162 fw3_find_command(const char *cmd)
163 {
164         struct stat s;
165         int plen = 0, clen = strlen(cmd) + 1;
166         char *search, *p;
167         static char path[PATH_MAX];
168
169         if (!stat(cmd, &s) && S_ISREG(s.st_mode))
170                 return cmd;
171
172         search = getenv("PATH");
173
174         if (!search)
175                 search = "/bin:/usr/bin:/sbin:/usr/sbin";
176
177         p = search;
178
179         do
180         {
181                 if (*p != ':' && *p != '\0')
182                         continue;
183
184                 plen = p - search;
185
186                 if ((plen + clen) >= sizeof(path))
187                         continue;
188
189                 strncpy(path, search, plen);
190                 sprintf(path + plen, "/%s", cmd);
191
192                 if (!stat(path, &s) && S_ISREG(s.st_mode))
193                         return path;
194
195                 search = p + 1;
196         }
197         while (*p++);
198
199         return NULL;
200 }
201
202 bool
203 fw3_stdout_pipe(void)
204 {
205         pipe_fd = stdout;
206         return true;
207 }
208
209 bool
210 __fw3_command_pipe(bool silent, const char *command, ...)
211 {
212         pid_t pid;
213         va_list argp;
214         int pfds[2];
215         int argn;
216         char *arg, **args, **tmp;
217
218         command = fw3_find_command(command);
219
220         if (!command)
221                 return false;
222
223         if (pipe(pfds))
224                 return false;
225
226         argn = 2;
227         args = malloc(argn * sizeof(arg));
228
229         if (!args)
230                 return false;
231
232         args[0] = (char *)command;
233         args[1] = NULL;
234
235         va_start(argp, command);
236
237         while ((arg = va_arg(argp, char *)) != NULL)
238         {
239                 tmp = realloc(args, ++argn * sizeof(arg));
240
241                 if (!tmp)
242                         break;
243
244                 args = tmp;
245                 args[argn-2] = arg;
246                 args[argn-1] = NULL;
247         }
248
249         va_end(argp);
250
251         switch ((pid = fork()))
252         {
253         case -1:
254                 return false;
255
256         case 0:
257                 dup2(pfds[0], 0);
258
259                 close(pfds[0]);
260                 close(pfds[1]);
261
262                 close(1);
263
264                 if (silent)
265                         close(2);
266
267                 execv(command, args);
268
269         default:
270                 signal(SIGPIPE, SIG_IGN);
271                 pipe_pid = pid;
272                 close(pfds[0]);
273                 fcntl(pfds[1], F_SETFD, fcntl(pfds[1], F_GETFD) | FD_CLOEXEC);
274         }
275
276         pipe_fd = fdopen(pfds[1], "w");
277         return true;
278 }
279
280 void
281 fw3_pr(const char *fmt, ...)
282 {
283         va_list args;
284
285         if (fw3_pr_debug && pipe_fd != stdout)
286         {
287                 va_start(args, fmt);
288                 vfprintf(stderr, fmt, args);
289                 va_end(args);
290         }
291
292         va_start(args, fmt);
293         vfprintf(pipe_fd, fmt, args);
294         va_end(args);
295 }
296
297 void
298 fw3_command_close(void)
299 {
300         if (pipe_fd && pipe_fd != stdout)
301                 fclose(pipe_fd);
302
303         if (pipe_pid > -1)
304                 waitpid(pipe_pid, NULL, 0);
305
306         signal(SIGPIPE, SIG_DFL);
307
308         pipe_fd = NULL;
309         pipe_pid = -1;
310 }
311
312 bool
313 fw3_has_table(bool ipv6, const char *table)
314 {
315         FILE *f;
316
317         char line[12];
318         bool seen = false;
319
320         const char *path = ipv6
321                 ? "/proc/net/ip6_tables_names" : "/proc/net/ip_tables_names";
322
323         if (!(f = fopen(path, "r")))
324                 return false;
325
326         while (fgets(line, sizeof(line), f))
327         {
328                 if (!strncmp(line, table, strlen(table)))
329                 {
330                         seen = true;
331                         break;
332                 }
333         }
334
335         fclose(f);
336
337         return seen;
338 }
339
340
341 bool
342 fw3_lock(void)
343 {
344         lock_fd = open(FW3_LOCKFILE, O_CREAT|O_WRONLY, S_IRUSR|S_IWUSR);
345
346         if (lock_fd < 0)
347         {
348                 warn("Cannot create lock file %s: %s", FW3_LOCKFILE, strerror(errno));
349                 return false;
350         }
351
352         if (flock(lock_fd, LOCK_EX))
353         {
354                 warn("Cannot acquire exclusive lock: %s", strerror(errno));
355                 return false;
356         }
357
358         return true;
359 }
360
361 void
362 fw3_unlock(void)
363 {
364         if (lock_fd < 0)
365                 return;
366
367         if (flock(lock_fd, LOCK_UN))
368                 warn("Cannot release exclusive lock: %s", strerror(errno));
369
370         close(lock_fd);
371         unlink(FW3_LOCKFILE);
372
373         lock_fd = -1;
374 }
375
376
377 static void
378 write_defaults_uci(struct uci_context *ctx, struct fw3_defaults *d,
379                    struct uci_package *dest)
380 {
381         char buf[sizeof("0xffffffff\0")];
382         struct uci_ptr ptr = { .p = dest };
383
384         uci_add_section(ctx, dest, "defaults", &ptr.s);
385
386         ptr.o      = NULL;
387         ptr.option = "input";
388         ptr.value  = fw3_flag_names[d->policy_input];
389         uci_set(ctx, &ptr);
390
391         ptr.o      = NULL;
392         ptr.option = "output";
393         ptr.value  = fw3_flag_names[d->policy_output];
394         uci_set(ctx, &ptr);
395
396         ptr.o      = NULL;
397         ptr.option = "forward";
398         ptr.value  = fw3_flag_names[d->policy_forward];
399         uci_set(ctx, &ptr);
400
401         sprintf(buf, "0x%x", d->flags[0]);
402         ptr.o      = NULL;
403         ptr.option = "__flags_v4";
404         ptr.value  = buf;
405         uci_set(ctx, &ptr);
406
407         sprintf(buf, "0x%x", d->flags[1]);
408         ptr.o      = NULL;
409         ptr.option = "__flags_v6";
410         ptr.value  = buf;
411         uci_set(ctx, &ptr);
412 }
413
414 static void
415 write_zone_uci(struct uci_context *ctx, struct fw3_zone *z,
416                struct uci_package *dest)
417 {
418         struct fw3_device *dev;
419         struct fw3_address *sub;
420         enum fw3_family fam = FW3_FAMILY_ANY;
421
422         char *p, buf[34];
423
424         struct uci_ptr ptr = { .p = dest };
425
426         if (!z->enabled)
427                 return;
428
429         if (fw3_no_table(z->flags[0]) && !fw3_no_table(z->flags[1]))
430                 fam = FW3_FAMILY_V6;
431         else if (!fw3_no_table(z->flags[0]) && fw3_no_table(z->flags[1]))
432                 fam = FW3_FAMILY_V4;
433         else if (fw3_no_table(z->flags[0]) && fw3_no_table(z->flags[1]))
434                 return;
435
436         uci_add_section(ctx, dest, "zone", &ptr.s);
437
438         ptr.o      = NULL;
439         ptr.option = "name";
440         ptr.value  = z->name;
441         uci_set(ctx, &ptr);
442
443         ptr.o      = NULL;
444         ptr.option = "input";
445         ptr.value  = fw3_flag_names[z->policy_input];
446         uci_set(ctx, &ptr);
447
448         ptr.o      = NULL;
449         ptr.option = "output";
450         ptr.value  = fw3_flag_names[z->policy_output];
451         uci_set(ctx, &ptr);
452
453         ptr.o      = NULL;
454         ptr.option = "forward";
455         ptr.value  = fw3_flag_names[z->policy_forward];
456         uci_set(ctx, &ptr);
457
458         ptr.o      = NULL;
459         ptr.option = "masq";
460         ptr.value  = z->masq ? "1" : "0";
461         uci_set(ctx, &ptr);
462
463         ptr.o      = NULL;
464         ptr.option = "conntrack";
465         ptr.value  = z->conntrack ? "1" : "0";
466         uci_set(ctx, &ptr);
467
468         ptr.o      = NULL;
469         ptr.option = "mtu_fix";
470         ptr.value  = z->mtu_fix ? "1" : "0";
471         uci_set(ctx, &ptr);
472
473         ptr.o      = NULL;
474         ptr.option = "custom_chains";
475         ptr.value  = z->custom_chains ? "1" : "0";
476         uci_set(ctx, &ptr);
477
478         if (fam != FW3_FAMILY_ANY)
479         {
480                 ptr.o      = NULL;
481                 ptr.option = "family";
482                 ptr.value  = fw3_flag_names[fam];
483                 uci_set(ctx, &ptr);
484         }
485
486         ptr.o      = NULL;
487         ptr.option = "device";
488
489         fw3_foreach(dev, &z->devices)
490         {
491                 if (!dev)
492                         continue;
493
494                 p = buf;
495
496                 if (dev->invert)
497                         p += sprintf(p, "!");
498
499                 if (*dev->network)
500                         p += sprintf(p, "%s@%s", dev->name, dev->network);
501                 else
502                         p += sprintf(p, "%s", dev->name);
503
504                 ptr.value = buf;
505                 uci_add_list(ctx, &ptr);
506         }
507
508         ptr.o      = NULL;
509         ptr.option = "subnet";
510
511         fw3_foreach(sub, &z->subnets)
512         {
513                 if (!sub)
514                         continue;
515
516                 ptr.value = fw3_address_to_string(sub, true);
517                 uci_add_list(ctx, &ptr);
518         }
519
520         sprintf(buf, "0x%x", z->flags[0]);
521         ptr.o      = NULL;
522         ptr.option = "__flags_v4";
523         ptr.value  = buf;
524         uci_set(ctx, &ptr);
525
526         sprintf(buf, "0x%x", z->flags[1]);
527         ptr.o      = NULL;
528         ptr.option = "__flags_v6";
529         ptr.value  = buf;
530         uci_set(ctx, &ptr);
531 }
532
533 static void
534 write_ipset_uci(struct uci_context *ctx, struct fw3_ipset *s,
535                 struct uci_package *dest)
536 {
537         struct fw3_ipset_datatype *type;
538
539         char buf[sizeof("65535-65535\0")];
540
541         struct uci_ptr ptr = { .p = dest };
542
543         if (!s->enabled || s->external)
544                 return;
545
546         uci_add_section(ctx, dest, "ipset", &ptr.s);
547
548         ptr.o      = NULL;
549         ptr.option = "name";
550         ptr.value  = s->name;
551         uci_set(ctx, &ptr);
552
553         ptr.o      = NULL;
554         ptr.option = "storage";
555         ptr.value  = fw3_ipset_method_names[s->method];
556         uci_set(ctx, &ptr);
557
558         list_for_each_entry(type, &s->datatypes, list)
559         {
560                 sprintf(buf, "%s_%s", type->dir, fw3_ipset_type_names[type->type]);
561                 ptr.o      = NULL;
562                 ptr.option = "match";
563                 ptr.value  = buf;
564                 uci_add_list(ctx, &ptr);
565         }
566
567         if (s->iprange.set)
568         {
569                 ptr.o      = NULL;
570                 ptr.option = "iprange";
571                 ptr.value  = fw3_address_to_string(&s->iprange, false);
572                 uci_set(ctx, &ptr);
573         }
574
575         if (s->portrange.set)
576         {
577                 sprintf(buf, "%u-%u", s->portrange.port_min, s->portrange.port_max);
578                 ptr.o      = NULL;
579                 ptr.option = "portrange";
580                 ptr.value  = buf;
581                 uci_set(ctx, &ptr);
582         }
583 }
584
585 void
586 fw3_write_statefile(void *state)
587 {
588         FILE *sf;
589         struct fw3_state *s = state;
590         struct fw3_zone *z;
591         struct fw3_ipset *i;
592
593         struct uci_package *p;
594
595         if (fw3_no_family(s->defaults.flags[0]) &&
596             fw3_no_family(s->defaults.flags[1]))
597         {
598                 unlink(FW3_STATEFILE);
599         }
600         else
601         {
602                 sf = fopen(FW3_STATEFILE, "w+");
603
604                 if (!sf)
605                 {
606                         warn("Cannot create state %s: %s", FW3_STATEFILE, strerror(errno));
607                         return;
608                 }
609
610                 if ((p = uci_lookup_package(s->uci, "fw3_state")) != NULL)
611                         uci_unload(s->uci, p);
612
613                 uci_import(s->uci, sf, "fw3_state", NULL, true);
614
615                 if ((p = uci_lookup_package(s->uci, "fw3_state")) != NULL)
616                 {
617                         write_defaults_uci(s->uci, &s->defaults, p);
618
619                         list_for_each_entry(z, &s->zones, list)
620                                 write_zone_uci(s->uci, z, p);
621
622                         list_for_each_entry(i, &s->ipsets, list)
623                                 write_ipset_uci(s->uci, i, p);
624
625                         uci_export(s->uci, sf, p, true);
626                         uci_unload(s->uci, p);
627                 }
628
629                 fsync(fileno(sf));
630                 fclose(sf);
631         }
632 }
633
634
635 void
636 fw3_free_object(void *obj, const void *opts)
637 {
638         const struct fw3_option *ol;
639         struct list_head *list, *cur, *tmp;
640
641         for (ol = opts; ol->name; ol++)
642         {
643                 if (!ol->elem_size)
644                         continue;
645
646                 list = (struct list_head *)((char *)obj + ol->offset);
647                 list_for_each_safe(cur, tmp, list)
648                 {
649                         list_del(cur);
650                         free(cur);
651                 }
652         }
653
654         free(obj);
655 }
656
657 void
658 fw3_free_list(struct list_head *head)
659 {
660         struct list_head *entry, *tmp;
661
662         if (!head)
663                 return;
664
665         list_for_each_safe(entry, tmp, head)
666         {
667                 list_del(entry);
668                 free(entry);
669         }
670
671         free(head);
672 }
673
674 bool
675 fw3_hotplug(bool add, void *zone, void *device)
676 {
677         struct fw3_zone *z = zone;
678         struct fw3_device *d = device;
679
680         if (!*d->network)
681                 return false;
682
683         switch (fork())
684         {
685         case -1:
686                 warn("Unable to fork(): %s\n", strerror(errno));
687                 return false;
688
689         case 0:
690                 break;
691
692         default:
693                 return true;
694         }
695
696         close(0);
697         close(1);
698         close(2);
699         chdir("/");
700
701         clearenv();
702         setenv("ACTION",    add ? "add" : "remove", 1);
703         setenv("ZONE",      z->name,                1);
704         setenv("INTERFACE", d->network,             1);
705         setenv("DEVICE",    d->name,                1);
706
707         execl(FW3_HOTPLUG, FW3_HOTPLUG, "firewall", NULL);
708
709         /* unreached */
710         return false;
711 }