• source navigation  • diff markup  • identifier search  • freetext search  • 

Sources/firewall3/utils.c

  1 /*
  2  * firewall3 - 3rd OpenWrt UCI firewall implementation
  3  *
  4  *   Copyright (C) 2013 Jo-Philipp Wich <jo@mein.io>
  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 #define _GNU_SOURCE
 20 
 21 #include <net/if.h>
 22 #include <sys/ioctl.h>
 23 
 24 #include "utils.h"
 25 #include "options.h"
 26 
 27 #include "zones.h"
 28 #include "ipsets.h"
 29 
 30 
 31 static int fw3_lock_fd = -1;
 32 static pid_t pipe_pid = -1;
 33 static FILE *pipe_fd = NULL;
 34 
 35 bool fw3_pr_debug = false;
 36 
 37 
 38 static void
 39 warn_elem_section_name(struct uci_section *s, bool find_name)
 40 {
 41         int i = 0;
 42         struct uci_option *o;
 43         struct uci_element *tmp;
 44 
 45         if (s->anonymous)
 46         {
 47                 uci_foreach_element(&s->package->sections, tmp)
 48                 {
 49                         if (strcmp(uci_to_section(tmp)->type, s->type))
 50                                 continue;
 51 
 52                         if (&s->e == tmp)
 53                                 break;
 54 
 55                         i++;
 56                 }
 57 
 58                 fprintf(stderr, "@%s[%d]", s->type, i);
 59 
 60                 if (find_name)
 61                 {
 62                         uci_foreach_element(&s->options, tmp)
 63                         {
 64                                 o = uci_to_option(tmp);
 65 
 66                                 if (!strcmp(tmp->name, "name") && (o->type == UCI_TYPE_STRING))
 67                                 {
 68                                         fprintf(stderr, " (%s)", o->v.string);
 69                                         break;
 70                                 }
 71                         }
 72                 }
 73         }
 74         else
 75         {
 76                 fprintf(stderr, "'%s'", s->e.name);
 77         }
 78 
 79         if (find_name)
 80                 fprintf(stderr, " ");
 81 }
 82 
 83 void
 84 warn_elem(struct uci_element *e, const char *format, ...)
 85 {
 86         if (e->type == UCI_TYPE_SECTION)
 87         {
 88                 fprintf(stderr, "Warning: Section ");
 89                 warn_elem_section_name(uci_to_section(e), true);
 90         }
 91         else if (e->type == UCI_TYPE_OPTION)
 92         {
 93                 fprintf(stderr, "Warning: Option ");
 94                 warn_elem_section_name(uci_to_option(e)->section, false);
 95                 fprintf(stderr, ".%s ", e->name);
 96         }
 97 
 98     va_list argptr;
 99     va_start(argptr, format);
100     vfprintf(stderr, format, argptr);
101     va_end(argptr);
102 
103         fprintf(stderr, "\n");
104 }
105 
106 void
107 warn(const char* format, ...)
108 {
109         fprintf(stderr, "Warning: ");
110     va_list argptr;
111     va_start(argptr, format);
112     vfprintf(stderr, format, argptr);
113     va_end(argptr);
114         fprintf(stderr, "\n");
115 }
116 
117 void
118 error(const char* format, ...)
119 {
120         fprintf(stderr, "Error: ");
121     va_list argptr;
122     va_start(argptr, format);
123     vfprintf(stderr, format, argptr);
124     va_end(argptr);
125         fprintf(stderr, "\n");
126 
127         exit(1);
128 }
129 
130 void
131 info(const char* format, ...)
132 {
133         va_list argptr;
134     va_start(argptr, format);
135     vfprintf(stderr, format, argptr);
136     va_end(argptr);
137         fprintf(stderr, "\n");
138 }
139 
140 void *
141 fw3_alloc(size_t size)
142 {
143         void *mem;
144 
145         mem = calloc(1, size);
146 
147         if (!mem)
148                 error("Out of memory while allocating %zd bytes", size);
149 
150         return mem;
151 }
152 
153 char *
154 fw3_strdup(const char *s)
155 {
156         char *ns;
157 
158         ns = strdup(s);
159 
160         if (!ns)
161                 error("Out of memory while duplicating string '%s'", s);
162 
163         return ns;
164 }
165 
166 const char *
167 fw3_find_command(const char *cmd)
168 {
169         struct stat s;
170         int plen = 0, clen = strlen(cmd) + 1;
171         char *search, *p;
172         static char path[PATH_MAX];
173 
174         if (!stat(cmd, &s) && S_ISREG(s.st_mode))
175                 return cmd;
176 
177         search = getenv("PATH");
178 
179         if (!search)
180                 search = "/bin:/usr/bin:/sbin:/usr/sbin";
181 
182         p = search;
183 
184         do
185         {
186                 if (*p != ':' && *p != '\0')
187                         continue;
188 
189                 plen = p - search;
190 
191                 if ((plen + clen) >= sizeof(path))
192                         continue;
193 
194                 snprintf(path, sizeof(path), "%.*s/%s", plen, search, cmd);
195 
196                 if (!stat(path, &s) && S_ISREG(s.st_mode))
197                         return path;
198 
199                 search = p + 1;
200         }
201         while (*p++);
202 
203         return NULL;
204 }
205 
206 bool
207 fw3_stdout_pipe(void)
208 {
209         pipe_fd = stdout;
210         return true;
211 }
212 
213 bool
214 __fw3_command_pipe(bool silent, const char *command, ...)
215 {
216         pid_t pid;
217         va_list argp;
218         int pfds[2];
219         int argn;
220         char *arg, **args, **tmp;
221 
222         command = fw3_find_command(command);
223 
224         if (!command)
225                 return false;
226 
227         if (pipe(pfds))
228                 return false;
229 
230         argn = 2;
231         args = calloc(argn, sizeof(arg));
232 
233         if (!args)
234                 return false;
235 
236         args[0] = (char *)command;
237         args[1] = NULL;
238 
239         va_start(argp, command);
240 
241         while ((arg = va_arg(argp, char *)) != NULL)
242         {
243                 tmp = realloc(args, ++argn * sizeof(arg));
244 
245                 if (!tmp)
246                         break;
247 
248                 args = tmp;
249                 args[argn-2] = arg;
250                 args[argn-1] = NULL;
251         }
252 
253         va_end(argp);
254 
255         switch ((pid = fork()))
256         {
257         case -1:
258                 free(args);
259                 return false;
260 
261         case 0:
262                 dup2(pfds[0], 0);
263 
264                 close(pfds[0]);
265                 close(pfds[1]);
266 
267                 close(1);
268 
269                 if (silent)
270                         close(2);
271 
272                 execv(command, args);
273 
274         default:
275                 signal(SIGPIPE, SIG_IGN);
276                 pipe_pid = pid;
277                 close(pfds[0]);
278                 fcntl(pfds[1], F_SETFD, fcntl(pfds[1], F_GETFD) | FD_CLOEXEC);
279         }
280 
281         pipe_fd = fdopen(pfds[1], "w");
282         free(args);
283         return true;
284 }
285 
286 void
287 fw3_pr(const char *fmt, ...)
288 {
289         va_list args;
290 
291         if (fw3_pr_debug && pipe_fd != stdout)
292         {
293                 va_start(args, fmt);
294                 vfprintf(stderr, fmt, args);
295                 va_end(args);
296         }
297 
298         va_start(args, fmt);
299         vfprintf(pipe_fd, fmt, args);
300         va_end(args);
301 }
302 
303 void
304 fw3_command_close(void)
305 {
306         if (pipe_fd && pipe_fd != stdout)
307                 fclose(pipe_fd);
308 
309         if (pipe_pid > -1)
310                 waitpid(pipe_pid, NULL, 0);
311 
312         signal(SIGPIPE, SIG_DFL);
313 
314         pipe_fd = NULL;
315         pipe_pid = -1;
316 }
317 
318 static bool
319 file_contains(const char *path, const char *str)
320 {
321         FILE *f;
322         char line[12];
323         bool seen = false;
324 
325         if (!(f = fopen(path, "r")))
326                 return false;
327 
328         while (fgets(line, sizeof(line), f))
329         {
330                 if (!strncmp(line, str, strlen(str)))
331                 {
332                         seen = true;
333                         break;
334                 }
335         }
336 
337         fclose(f);
338 
339         return seen;
340 }
341 
342 bool
343 fw3_has_table(const bool ipv6, const char *table)
344 {
345         const char *path = ipv6
346                 ? "/proc/net/ip6_tables_names" : "/proc/net/ip_tables_names";
347 
348         return file_contains(path, table);
349 }
350 
351 bool
352 fw3_has_target(const bool ipv6, const char *target)
353 {
354         const char *path = ipv6
355                 ? "/proc/net/ip6_tables_targets" : "/proc/net/ip_tables_targets";
356 
357         return file_contains(path, target);
358 }
359 
360 bool
361 fw3_lock_path(int *fd, const char *path)
362 {
363         int lock_fd = open(path, O_CREAT|O_WRONLY, S_IRUSR|S_IWUSR);
364 
365         if (lock_fd < 0)
366         {
367                 warn("Cannot create lock file %s: %s", path, strerror(errno));
368                 return false;
369         }
370 
371         if (flock(lock_fd, LOCK_EX))
372         {
373                 warn("Cannot acquire exclusive lock: %s", strerror(errno));
374                 close(lock_fd);
375                 return false;
376         }
377 
378         *fd = lock_fd;
379 
380         return true;
381 }
382 
383 bool
384 fw3_lock()
385 {
386         return fw3_lock_path(&fw3_lock_fd, FW3_LOCKFILE);
387 }
388 
389 
390 void
391 fw3_unlock_path(int *fd, const char *lockpath)
392 {
393         if (*fd < 0)
394                 return;
395 
396         if (flock(*fd, LOCK_UN))
397                 warn("Cannot release exclusive lock: %s", strerror(errno));
398 
399         close(*fd);
400         unlink(FW3_LOCKFILE);
401 
402         *fd = -1;
403 }
404 
405 
406 void
407 fw3_unlock(void)
408 {
409         fw3_unlock_path(&fw3_lock_fd, FW3_LOCKFILE);
410 }
411 
412 
413 static void
414 write_defaults_uci(struct uci_context *ctx, struct fw3_defaults *d,
415                    struct uci_package *dest)
416 {
417         char buf[sizeof("0xffffffff")];
418         struct uci_ptr ptr = { .p = dest };
419 
420         uci_add_section(ctx, dest, "defaults", &ptr.s);
421 
422         ptr.o      = NULL;
423         ptr.option = "input";
424         ptr.value  = fw3_flag_names[d->policy_input];
425         uci_set(ctx, &ptr);
426 
427         ptr.o      = NULL;
428         ptr.option = "output";
429         ptr.value  = fw3_flag_names[d->policy_output];
430         uci_set(ctx, &ptr);
431 
432         ptr.o      = NULL;
433         ptr.option = "forward";
434         ptr.value  = fw3_flag_names[d->policy_forward];
435         uci_set(ctx, &ptr);
436 
437         snprintf(buf, sizeof(buf), "0x%x", d->flags[0]);
438         ptr.o      = NULL;
439         ptr.option = "__flags_v4";
440         ptr.value  = buf;
441         uci_set(ctx, &ptr);
442 
443         snprintf(buf, sizeof(buf), "0x%x", d->flags[1]);
444         ptr.o      = NULL;
445         ptr.option = "__flags_v6";
446         ptr.value  = buf;
447         uci_set(ctx, &ptr);
448 }
449 
450 static void
451 write_zone_uci(struct uci_context *ctx, struct fw3_zone *z,
452                struct uci_package *dest, struct ifaddrs *ifaddr)
453 {
454         struct fw3_device *dev;
455         struct fw3_address *sub;
456         struct ifaddrs *ifa;
457         enum fw3_family fam = FW3_FAMILY_ANY;
458 
459         char *p, buf[INET6_ADDRSTRLEN];
460 
461         struct uci_ptr ptr = { .p = dest };
462 
463         if (!z->enabled)
464                 return;
465 
466         if (fw3_no_table(z->flags[0]) && !fw3_no_table(z->flags[1]))
467                 fam = FW3_FAMILY_V6;
468         else if (!fw3_no_table(z->flags[0]) && fw3_no_table(z->flags[1]))
469                 fam = FW3_FAMILY_V4;
470         else if (fw3_no_table(z->flags[0]) && fw3_no_table(z->flags[1]))
471                 return;
472 
473         uci_add_section(ctx, dest, "zone", &ptr.s);
474 
475         ptr.o      = NULL;
476         ptr.option = "name";
477         ptr.value  = z->name;
478         uci_set(ctx, &ptr);
479 
480         ptr.o      = NULL;
481         ptr.option = "input";
482         ptr.value  = fw3_flag_names[z->policy_input];
483         uci_set(ctx, &ptr);
484 
485         ptr.o      = NULL;
486         ptr.option = "output";
487         ptr.value  = fw3_flag_names[z->policy_output];
488         uci_set(ctx, &ptr);
489 
490         ptr.o      = NULL;
491         ptr.option = "forward";
492         ptr.value  = fw3_flag_names[z->policy_forward];
493         uci_set(ctx, &ptr);
494 
495         ptr.o      = NULL;
496         ptr.option = "masq";
497         ptr.value  = z->masq ? "1" : "";
498         uci_set(ctx, &ptr);
499 
500         ptr.o      = NULL;
501         ptr.option = "mtu_fix";
502         ptr.value  = z->mtu_fix ? "1" : "";
503         uci_set(ctx, &ptr);
504 
505         ptr.o      = NULL;
506         ptr.option = "custom_chains";
507         ptr.value  = z->custom_chains ? "1" : "";
508         uci_set(ctx, &ptr);
509 
510         if (fam != FW3_FAMILY_ANY)
511         {
512                 ptr.o      = NULL;
513                 ptr.option = "family";
514                 ptr.value  = fw3_flag_names[fam];
515                 uci_set(ctx, &ptr);
516         }
517 
518         ptr.o      = NULL;
519         ptr.option = "device";
520 
521         fw3_foreach(dev, &z->devices)
522         {
523                 char *ep;
524 
525                 if (!dev)
526                         continue;
527 
528                 p = buf;
529                 ep = buf + sizeof(buf);
530 
531                 if (dev->invert)
532                         p += snprintf(p, ep - p, "!");
533 
534                 if (*dev->network)
535                         p += snprintf(p, ep - p, "%s@%s", dev->name, dev->network);
536                 else
537                         p += snprintf(p, ep - p, "%s", dev->name);
538 
539                 ptr.value = buf;
540                 uci_add_list(ctx, &ptr);
541         }
542 
543         ptr.o      = NULL;
544         ptr.option = "subnet";
545 
546         fw3_foreach(sub, &z->subnets)
547         {
548                 if (!sub)
549                         continue;
550 
551                 ptr.value = fw3_address_to_string(sub, true, false);
552                 uci_add_list(ctx, &ptr);
553         }
554 
555         ptr.o      = NULL;
556         ptr.option = "__addrs";
557 
558         fw3_foreach(dev, &z->devices)
559         {
560                 if (!dev)
561                         continue;
562 
563                 for (ifa = ifaddr; ifa; ifa = ifa->ifa_next)
564                 {
565                         if (!ifa->ifa_addr || strcmp(dev->name, ifa->ifa_name))
566                                 continue;
567 
568                         if (ifa->ifa_addr->sa_family == AF_INET)
569                                 inet_ntop(AF_INET,
570                                           &((struct sockaddr_in *)ifa->ifa_addr)->sin_addr,
571                                           buf, sizeof(buf));
572                         else if (ifa->ifa_addr->sa_family == AF_INET6)
573                                 inet_ntop(AF_INET6,
574                                           &((struct sockaddr_in6 *)ifa->ifa_addr)->sin6_addr,
575                                           buf, sizeof(buf));
576                         else
577                                 continue;
578 
579                         ptr.value = buf;
580                         uci_add_list(ctx, &ptr);
581                 }
582         }
583 
584         if (z->extra_src)
585         {
586                 ptr.o      = NULL;
587                 ptr.option = "extra_src";
588                 ptr.value  = z->extra_src;
589                 uci_set(ctx, &ptr);
590         }
591 
592         if (z->extra_dest)
593         {
594                 ptr.o      = NULL;
595                 ptr.option = "extra_dest";
596                 ptr.value  = z->extra_dest;
597                 uci_set(ctx, &ptr);
598         }
599 
600         snprintf(buf, sizeof(buf), "0x%x", z->flags[0]);
601         ptr.o      = NULL;
602         ptr.option = "__flags_v4";
603         ptr.value  = buf;
604         uci_set(ctx, &ptr);
605 
606         snprintf(buf, sizeof(buf), "0x%x", z->flags[1]);
607         ptr.o      = NULL;
608         ptr.option = "__flags_v6";
609         ptr.value  = buf;
610         uci_set(ctx, &ptr);
611 }
612 
613 static void
614 write_ipset_uci(struct uci_context *ctx, struct fw3_ipset *s,
615                 struct uci_package *dest)
616 {
617         struct fw3_ipset_datatype *type;
618 
619         char buf[sizeof("65535-65535")];
620 
621         struct uci_ptr ptr = { .p = dest };
622 
623         if (!s->enabled || s->external)
624                 return;
625 
626         uci_add_section(ctx, dest, "ipset", &ptr.s);
627 
628         ptr.o      = NULL;
629         ptr.option = "name";
630         ptr.value  = s->name;
631         uci_set(ctx, &ptr);
632 
633         ptr.o      = NULL;
634         ptr.option = "family";
635         if (s->family == FW3_FAMILY_V4)
636                 ptr.value = "ipv4";
637         else
638                 ptr.value = "ipv6";
639         uci_set(ctx, &ptr);
640 
641         ptr.o      = NULL;
642         ptr.option = "storage";
643         ptr.value  = fw3_ipset_method_names[s->method];
644         uci_set(ctx, &ptr);
645 
646         list_for_each_entry(type, &s->datatypes, list)
647         {
648                 snprintf(buf, sizeof(buf), "%s_%s", type->dir, fw3_ipset_type_names[type->type]);
649                 ptr.o      = NULL;
650                 ptr.option = "match";
651                 ptr.value  = buf;
652                 uci_add_list(ctx, &ptr);
653         }
654 
655         if (s->iprange.set)
656         {
657                 ptr.o      = NULL;
658                 ptr.option = "iprange";
659                 ptr.value  = fw3_address_to_string(&s->iprange, false, false);
660                 uci_set(ctx, &ptr);
661         }
662 
663         if (s->portrange.set)
664         {
665                 snprintf(buf, sizeof(buf), "%u-%u", s->portrange.port_min, s->portrange.port_max);
666                 ptr.o      = NULL;
667                 ptr.option = "portrange";
668                 ptr.value  = buf;
669                 uci_set(ctx, &ptr);
670         }
671 }
672 
673 void
674 fw3_write_statefile(void *state)
675 {
676         FILE *sf;
677         struct fw3_state *s = state;
678         struct fw3_zone *z;
679         struct fw3_ipset *i;
680         struct ifaddrs *ifaddr;
681 
682         struct uci_package *p;
683 
684         if (fw3_no_family(s->defaults.flags[0]) &&
685             fw3_no_family(s->defaults.flags[1]))
686         {
687                 unlink(FW3_STATEFILE);
688         }
689         else
690         {
691                 sf = fopen(FW3_STATEFILE, "w+");
692 
693                 if (!sf)
694                 {
695                         warn("Cannot create state %s: %s", FW3_STATEFILE, strerror(errno));
696                         return;
697                 }
698 
699                 if (getifaddrs(&ifaddr))
700                 {
701                         warn("Cannot get interface addresses: %s", strerror(errno));
702                         ifaddr = NULL;
703                 }
704 
705                 if ((p = uci_lookup_package(s->uci, "fw3_state")) != NULL)
706                         uci_unload(s->uci, p);
707 
708                 uci_import(s->uci, sf, "fw3_state", NULL, true);
709 
710                 if ((p = uci_lookup_package(s->uci, "fw3_state")) != NULL)
711                 {
712                         write_defaults_uci(s->uci, &s->defaults, p);
713 
714                         list_for_each_entry(z, &s->zones, list)
715                                 write_zone_uci(s->uci, z, p, ifaddr);
716 
717                         list_for_each_entry(i, &s->ipsets, list)
718                                 write_ipset_uci(s->uci, i, p);
719 
720                         uci_export(s->uci, sf, p, true);
721                         uci_unload(s->uci, p);
722                 }
723 
724                 fsync(fileno(sf));
725                 fclose(sf);
726 
727                 if (ifaddr)
728                         freeifaddrs(ifaddr);
729         }
730 }
731 
732 
733 void
734 fw3_free_object(void *obj, const void *opts)
735 {
736         const struct fw3_option *ol;
737         struct list_head *list, *cur, *tmp;
738 
739         for (ol = opts; ol->name; ol++)
740         {
741                 if (!ol->elem_size)
742                         continue;
743 
744                 list = (struct list_head *)((char *)obj + ol->offset);
745                 list_for_each_safe(cur, tmp, list)
746                 {
747                         list_del(cur);
748                         free(cur);
749                 }
750         }
751 
752         free(obj);
753 }
754 
755 void
756 fw3_free_list(struct list_head *head)
757 {
758         struct list_head *entry, *tmp;
759 
760         if (!head)
761                 return;
762 
763         list_for_each_safe(entry, tmp, head)
764         {
765                 list_del(entry);
766                 free(entry);
767         }
768 
769         free(head);
770 }
771 
772 bool
773 fw3_hotplug(bool add, void *zone, void *device)
774 {
775         struct fw3_zone *z = zone;
776         struct fw3_device *d = device;
777 
778         if (!*d->network)
779                 return false;
780 
781         switch (fork())
782         {
783         case -1:
784                 warn("Unable to fork(): %s\n", strerror(errno));
785                 return false;
786 
787         case 0:
788                 break;
789 
790         default:
791                 return true;
792         }
793 
794         close(0);
795         close(1);
796         close(2);
797         if (chdir("/")) {};
798 
799         clearenv();
800         setenv("ACTION",    add ? "add" : "remove", 1);
801         setenv("ZONE",      z->name,                1);
802         setenv("INTERFACE", d->network,             1);
803         setenv("DEVICE",    d->name,                1);
804 
805         execl(FW3_HOTPLUG, FW3_HOTPLUG, "firewall", NULL);
806 
807         /* unreached */
808         return false;
809 }
810 
811 int
812 fw3_netmask2bitlen(int family, void *mask)
813 {
814         int bits;
815         struct in_addr *v4;
816         struct in6_addr *v6;
817 
818         if (family == FW3_FAMILY_V6)
819                 for (bits = 0, v6 = mask;
820                      bits < 128 && (v6->s6_addr[bits / 8] << (bits % 8)) & 128;
821                      bits++);
822         else
823                 for (bits = 0, v4 = mask;
824                      bits < 32 && (ntohl(v4->s_addr) << bits) & 0x80000000;
825                      bits++);
826 
827         return bits;
828 }
829 
830 bool
831 fw3_bitlen2netmask(int family, int bits, void *mask)
832 {
833         int i;
834         uint8_t rem, b;
835         struct in_addr *v4;
836         struct in6_addr *v6;
837 
838         if (family == FW3_FAMILY_V6)
839         {
840                 if (bits < -128 || bits > 128)
841                         return false;
842 
843                 v6 = mask;
844                 rem = abs(bits);
845 
846                 for (i = 0; i < sizeof(v6->s6_addr); i++)
847                 {
848                         b = (rem > 8) ? 8 : rem;
849                         v6->s6_addr[i] = (uint8_t)(0xFF << (8 - b));
850                         rem -= b;
851                 }
852 
853                 if (bits < 0)
854                         for (i = 0; i < sizeof(v6->s6_addr); i++)
855                                 v6->s6_addr[i] = ~v6->s6_addr[i];
856         }
857         else
858         {
859                 if (bits < -32 || bits > 32)
860                         return false;
861 
862                 v4 = mask;
863                 v4->s_addr = bits ? htonl(~((1 << (32 - abs(bits))) - 1)) : 0;
864 
865                 if (bits < 0)
866                         v4->s_addr = ~v4->s_addr;
867         }
868 
869         return true;
870 }
871 
872 void
873 fw3_flush_conntrack(void *state)
874 {
875         bool found;
876         struct fw3_state *s = state;
877         struct fw3_address *addr;
878         struct fw3_device *dev;
879         struct fw3_zone *zone;
880         struct ifaddrs *ifaddr, *ifa;
881         struct sockaddr_in *sin;
882         struct sockaddr_in6 *sin6;
883         char buf[INET6_ADDRSTRLEN];
884         FILE *ct;
885 
886         if (!state)
887         {
888                 if ((ct = fopen("/proc/net/nf_conntrack", "w")) != NULL)
889                 {
890                         info(" * Flushing conntrack table ...");
891 
892                         fwrite("f\n", 1, 2, ct);
893                         fclose(ct);
894                 }
895 
896                 return;
897         }
898 
899         if (getifaddrs(&ifaddr))
900         {
901                 warn("Cannot get interface addresses: %s", strerror(errno));
902                 return;
903         }
904 
905         if ((ct = fopen("/proc/net/nf_conntrack", "w")) != NULL)
906         {
907                 list_for_each_entry(zone, &s->zones, list)
908                 list_for_each_entry(addr, &zone->old_addrs, list)
909                 {
910                         found = false;
911 
912                         list_for_each_entry(dev, &zone->devices, list)
913                         {
914                                 for (ifa = ifaddr; ifa && !found; ifa = ifa->ifa_next)
915                                 {
916                                         if (!ifa->ifa_addr || strcmp(dev->name, ifa->ifa_name))
917                                                 continue;
918 
919                                         sin = (struct sockaddr_in *)ifa->ifa_addr;
920                                         sin6 = (struct sockaddr_in6 *)ifa->ifa_addr;
921 
922                                         if (addr->family == FW3_FAMILY_V4 &&
923                                                 sin->sin_family == AF_INET)
924                                         {
925                                                 found = !memcmp(&addr->address.v4, &sin->sin_addr,
926                                                                                 sizeof(sin->sin_addr));
927                                         }
928                                         else if (addr->family == FW3_FAMILY_V6 &&
929                                                          sin6->sin6_family == AF_INET6)
930                                         {
931                                                 found = !memcmp(&addr->address.v6, &sin6->sin6_addr,
932                                                                                 sizeof(sin6->sin6_addr));
933                                         }
934                                 }
935 
936                                 if (found)
937                                         break;
938                         }
939 
940                         if (!found)
941                         {
942                                 inet_ntop(addr->family == FW3_FAMILY_V4 ? AF_INET : AF_INET6,
943                                                   &addr->address.v4, buf, sizeof(buf));
944 
945                                 info(" * Flushing conntrack: %s", buf);
946                                 fprintf(ct, "%s\n", buf);
947                         }
948                 }
949 
950                 fclose(ct);
951         }
952 
953         freeifaddrs(ifaddr);
954 }
955 
956 bool fw3_attr_parse_name_type(struct blob_attr *entry, const char **name, const char **type)
957 {
958         struct blob_attr *opt;
959         unsigned orem;
960 
961         if (!type || !name)
962                 return false;
963 
964         *type = NULL;
965 
966         blobmsg_for_each_attr(opt, entry, orem)
967                 if (!strcmp(blobmsg_name(opt), "type"))
968                         *type = blobmsg_get_string(opt);
969                 else if (!strcmp(blobmsg_name(opt), "name"))
970                         *name = blobmsg_get_string(opt);
971 
972         return *type != NULL ? true : false;
973 }
974 
975 const char *
976 fw3_protoname(void *proto)
977 {
978         static char buf[sizeof("4294967295")];
979         struct fw3_protocol *p = proto;
980         struct protoent *pe;
981 
982         if (!p)
983                 return "?";
984 
985         pe = getprotobynumber(p->protocol);
986 
987         if (!pe)
988         {
989                 snprintf(buf, sizeof(buf), "%u", p->protocol);
990                 return buf;
991         }
992 
993         return pe->p_name;
994 }
995 
996 bool
997 fw3_check_loopback_dev(const char *name)
998 {
999         struct ifreq ifr;
1000         int s;
1001         bool rv = false;
1002 
1003         s = socket(AF_LOCAL, SOCK_DGRAM, 0);
1004 
1005         if (s < 0)
1006                 return false;
1007 
1008         memset(&ifr, 0, sizeof(ifr));
1009         snprintf(ifr.ifr_name, sizeof(ifr.ifr_name), "%s", name);
1010 
1011         if (ioctl(s, SIOCGIFFLAGS, &ifr) >= 0) {
1012                 if (ifr.ifr_flags & IFF_LOOPBACK)
1013                         rv = true;
1014         }
1015 
1016         close(s);
1017 
1018         return rv;
1019 }
1020 
1021 bool
1022 fw3_check_loopback_addr(struct fw3_address *addr)
1023 {
1024         if (addr->family == FW3_FAMILY_V4 &&
1025             (ntohl(addr->address.v4.s_addr) >> IN_CLASSA_NSHIFT) == IN_LOOPBACKNET)
1026                 return true;
1027 
1028         if (addr->family == FW3_FAMILY_V6 && !addr->range &&
1029             fw3_netmask2bitlen(FW3_FAMILY_V6, &addr->mask.v6) == 128 &&
1030             IN6_IS_ADDR_LOOPBACK(&addr->address.v6))
1031                 return true;
1032 
1033         return false;
1034 }
1035 

This page was automatically generated by LXR 0.3.1.  •  OpenWrt