• 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_target(const bool ipv6, const char *target)
344 {
345         const char *path = ipv6
346                 ? "/proc/net/ip6_tables_targets" : "/proc/net/ip_tables_targets";
347 
348         return file_contains(path, target);
349 }
350 
351 bool
352 fw3_lock_path(int *fd, const char *path)
353 {
354         int lock_fd = open(path, O_CREAT|O_WRONLY, S_IRUSR|S_IWUSR);
355 
356         if (lock_fd < 0)
357         {
358                 warn("Cannot create lock file %s: %s", path, strerror(errno));
359                 return false;
360         }
361 
362         if (flock(lock_fd, LOCK_EX))
363         {
364                 warn("Cannot acquire exclusive lock: %s", strerror(errno));
365                 close(lock_fd);
366                 return false;
367         }
368 
369         *fd = lock_fd;
370 
371         return true;
372 }
373 
374 bool
375 fw3_lock()
376 {
377         return fw3_lock_path(&fw3_lock_fd, FW3_LOCKFILE);
378 }
379 
380 
381 void
382 fw3_unlock_path(int *fd, const char *lockpath)
383 {
384         if (*fd < 0)
385                 return;
386 
387         if (flock(*fd, LOCK_UN))
388                 warn("Cannot release exclusive lock: %s", strerror(errno));
389 
390         close(*fd);
391 
392         *fd = -1;
393 }
394 
395 
396 void
397 fw3_unlock(void)
398 {
399         fw3_unlock_path(&fw3_lock_fd, FW3_LOCKFILE);
400 }
401 
402 
403 static void
404 write_defaults_uci(struct uci_context *ctx, struct fw3_defaults *d,
405                    struct uci_package *dest)
406 {
407         char buf[sizeof("0xffffffff")];
408         struct uci_ptr ptr = { .p = dest };
409 
410         uci_add_section(ctx, dest, "defaults", &ptr.s);
411 
412         ptr.o      = NULL;
413         ptr.option = "input";
414         ptr.value  = fw3_flag_names[d->policy_input];
415         uci_set(ctx, &ptr);
416 
417         ptr.o      = NULL;
418         ptr.option = "output";
419         ptr.value  = fw3_flag_names[d->policy_output];
420         uci_set(ctx, &ptr);
421 
422         ptr.o      = NULL;
423         ptr.option = "forward";
424         ptr.value  = fw3_flag_names[d->policy_forward];
425         uci_set(ctx, &ptr);
426 
427         snprintf(buf, sizeof(buf), "0x%x", d->flags[0]);
428         ptr.o      = NULL;
429         ptr.option = "__flags_v4";
430         ptr.value  = buf;
431         uci_set(ctx, &ptr);
432 
433         snprintf(buf, sizeof(buf), "0x%x", d->flags[1]);
434         ptr.o      = NULL;
435         ptr.option = "__flags_v6";
436         ptr.value  = buf;
437         uci_set(ctx, &ptr);
438 }
439 
440 static void
441 write_zone_uci(struct uci_context *ctx, struct fw3_zone *z,
442                struct uci_package *dest, struct ifaddrs *ifaddr)
443 {
444         struct fw3_device *dev;
445         struct fw3_address *sub;
446         struct ifaddrs *ifa;
447         enum fw3_family fam = FW3_FAMILY_ANY;
448 
449         char *p, buf[INET6_ADDRSTRLEN];
450 
451         struct uci_ptr ptr = { .p = dest };
452 
453         if (!z->enabled)
454                 return;
455 
456         if (fw3_no_table(z->flags[0]) && !fw3_no_table(z->flags[1]))
457                 fam = FW3_FAMILY_V6;
458         else if (!fw3_no_table(z->flags[0]) && fw3_no_table(z->flags[1]))
459                 fam = FW3_FAMILY_V4;
460         else if (fw3_no_table(z->flags[0]) && fw3_no_table(z->flags[1]))
461                 return;
462 
463         uci_add_section(ctx, dest, "zone", &ptr.s);
464 
465         ptr.o      = NULL;
466         ptr.option = "name";
467         ptr.value  = z->name;
468         uci_set(ctx, &ptr);
469 
470         ptr.o      = NULL;
471         ptr.option = "input";
472         ptr.value  = fw3_flag_names[z->policy_input];
473         uci_set(ctx, &ptr);
474 
475         ptr.o      = NULL;
476         ptr.option = "output";
477         ptr.value  = fw3_flag_names[z->policy_output];
478         uci_set(ctx, &ptr);
479 
480         ptr.o      = NULL;
481         ptr.option = "forward";
482         ptr.value  = fw3_flag_names[z->policy_forward];
483         uci_set(ctx, &ptr);
484 
485         ptr.o      = NULL;
486         ptr.option = "masq";
487         ptr.value  = z->masq ? "1" : "";
488         uci_set(ctx, &ptr);
489 
490         ptr.o      = NULL;
491         ptr.option = "mtu_fix";
492         ptr.value  = z->mtu_fix ? "1" : "";
493         uci_set(ctx, &ptr);
494 
495         ptr.o      = NULL;
496         ptr.option = "custom_chains";
497         ptr.value  = z->custom_chains ? "1" : "";
498         uci_set(ctx, &ptr);
499 
500         if (fam != FW3_FAMILY_ANY)
501         {
502                 ptr.o      = NULL;
503                 ptr.option = "family";
504                 ptr.value  = fw3_flag_names[fam];
505                 uci_set(ctx, &ptr);
506         }
507 
508         ptr.o      = NULL;
509         ptr.option = "device";
510 
511         fw3_foreach(dev, &z->devices)
512         {
513                 char *ep;
514 
515                 if (!dev)
516                         continue;
517 
518                 p = buf;
519                 ep = buf + sizeof(buf);
520 
521                 if (dev->invert)
522                         p += snprintf(p, ep - p, "!");
523 
524                 if (*dev->network)
525                         p += snprintf(p, ep - p, "%s@%s", dev->name, dev->network);
526                 else
527                         p += snprintf(p, ep - p, "%s", dev->name);
528 
529                 ptr.value = buf;
530                 uci_add_list(ctx, &ptr);
531         }
532 
533         ptr.o      = NULL;
534         ptr.option = "subnet";
535 
536         fw3_foreach(sub, &z->subnets)
537         {
538                 if (!sub)
539                         continue;
540 
541                 ptr.value = fw3_address_to_string(sub, true, false);
542                 uci_add_list(ctx, &ptr);
543         }
544 
545         ptr.o      = NULL;
546         ptr.option = "__addrs";
547 
548         fw3_foreach(dev, &z->devices)
549         {
550                 if (!dev)
551                         continue;
552 
553                 for (ifa = ifaddr; ifa; ifa = ifa->ifa_next)
554                 {
555                         if (!ifa->ifa_addr || strcmp(dev->name, ifa->ifa_name))
556                                 continue;
557 
558                         if (ifa->ifa_addr->sa_family == AF_INET)
559                                 inet_ntop(AF_INET,
560                                           &((struct sockaddr_in *)ifa->ifa_addr)->sin_addr,
561                                           buf, sizeof(buf));
562                         else if (ifa->ifa_addr->sa_family == AF_INET6)
563                                 inet_ntop(AF_INET6,
564                                           &((struct sockaddr_in6 *)ifa->ifa_addr)->sin6_addr,
565                                           buf, sizeof(buf));
566                         else
567                                 continue;
568 
569                         ptr.value = buf;
570                         uci_add_list(ctx, &ptr);
571                 }
572         }
573 
574         if (z->extra_src)
575         {
576                 ptr.o      = NULL;
577                 ptr.option = "extra_src";
578                 ptr.value  = z->extra_src;
579                 uci_set(ctx, &ptr);
580         }
581 
582         if (z->extra_dest)
583         {
584                 ptr.o      = NULL;
585                 ptr.option = "extra_dest";
586                 ptr.value  = z->extra_dest;
587                 uci_set(ctx, &ptr);
588         }
589 
590         snprintf(buf, sizeof(buf), "0x%x", z->flags[0]);
591         ptr.o      = NULL;
592         ptr.option = "__flags_v4";
593         ptr.value  = buf;
594         uci_set(ctx, &ptr);
595 
596         snprintf(buf, sizeof(buf), "0x%x", z->flags[1]);
597         ptr.o      = NULL;
598         ptr.option = "__flags_v6";
599         ptr.value  = buf;
600         uci_set(ctx, &ptr);
601 }
602 
603 static void
604 write_ipset_uci(struct uci_context *ctx, struct fw3_ipset *s,
605                 struct uci_package *dest)
606 {
607         struct fw3_ipset_datatype *type;
608 
609         char buf[sizeof("65535-65535")];
610 
611         struct uci_ptr ptr = { .p = dest };
612 
613         if (!s->enabled || s->external)
614                 return;
615 
616         uci_add_section(ctx, dest, "ipset", &ptr.s);
617 
618         ptr.o      = NULL;
619         ptr.option = "name";
620         ptr.value  = s->name;
621         uci_set(ctx, &ptr);
622 
623         ptr.o      = NULL;
624         ptr.option = "family";
625         if (s->family == FW3_FAMILY_V4)
626                 ptr.value = "ipv4";
627         else
628                 ptr.value = "ipv6";
629         uci_set(ctx, &ptr);
630 
631         ptr.o      = NULL;
632         ptr.option = "storage";
633         ptr.value  = fw3_ipset_method_names[s->method];
634         uci_set(ctx, &ptr);
635 
636         list_for_each_entry(type, &s->datatypes, list)
637         {
638                 snprintf(buf, sizeof(buf), "%s_%s", type->dir, fw3_ipset_type_names[type->type]);
639                 ptr.o      = NULL;
640                 ptr.option = "match";
641                 ptr.value  = buf;
642                 uci_add_list(ctx, &ptr);
643         }
644 
645         if (s->iprange.set)
646         {
647                 ptr.o      = NULL;
648                 ptr.option = "iprange";
649                 ptr.value  = fw3_address_to_string(&s->iprange, false, false);
650                 uci_set(ctx, &ptr);
651         }
652 
653         if (s->portrange.set)
654         {
655                 snprintf(buf, sizeof(buf), "%u-%u", s->portrange.port_min, s->portrange.port_max);
656                 ptr.o      = NULL;
657                 ptr.option = "portrange";
658                 ptr.value  = buf;
659                 uci_set(ctx, &ptr);
660         }
661 }
662 
663 void
664 fw3_write_statefile(void *state)
665 {
666         FILE *sf;
667         struct fw3_state *s = state;
668         struct fw3_zone *z;
669         struct fw3_ipset *i;
670         struct ifaddrs *ifaddr;
671 
672         struct uci_package *p;
673 
674         if (fw3_no_family(s->defaults.flags[0]) &&
675             fw3_no_family(s->defaults.flags[1]))
676         {
677                 unlink(FW3_STATEFILE);
678         }
679         else
680         {
681                 sf = fopen(FW3_STATEFILE, "w+");
682 
683                 if (!sf)
684                 {
685                         warn("Cannot create state %s: %s", FW3_STATEFILE, strerror(errno));
686                         return;
687                 }
688 
689                 if (getifaddrs(&ifaddr))
690                 {
691                         warn("Cannot get interface addresses: %s", strerror(errno));
692                         ifaddr = NULL;
693                 }
694 
695                 if ((p = uci_lookup_package(s->uci, "fw3_state")) != NULL)
696                         uci_unload(s->uci, p);
697 
698                 uci_import(s->uci, sf, "fw3_state", NULL, true);
699 
700                 if ((p = uci_lookup_package(s->uci, "fw3_state")) != NULL)
701                 {
702                         write_defaults_uci(s->uci, &s->defaults, p);
703 
704                         list_for_each_entry(z, &s->zones, list)
705                                 write_zone_uci(s->uci, z, p, ifaddr);
706 
707                         list_for_each_entry(i, &s->ipsets, list)
708                                 write_ipset_uci(s->uci, i, p);
709 
710                         uci_export(s->uci, sf, p, true);
711                         uci_unload(s->uci, p);
712                 }
713 
714                 fsync(fileno(sf));
715                 fclose(sf);
716 
717                 if (ifaddr)
718                         freeifaddrs(ifaddr);
719         }
720 }
721 
722 
723 void
724 fw3_free_object(void *obj, const void *opts)
725 {
726         const struct fw3_option *ol;
727         struct list_head *list, *cur, *tmp;
728 
729         for (ol = opts; ol->name; ol++)
730         {
731                 if (!ol->elem_size)
732                         continue;
733 
734                 list = (struct list_head *)((char *)obj + ol->offset);
735                 list_for_each_safe(cur, tmp, list)
736                 {
737                         list_del(cur);
738                         free(cur);
739                 }
740         }
741 
742         free(obj);
743 }
744 
745 void
746 fw3_free_list(struct list_head *head)
747 {
748         struct list_head *entry, *tmp;
749 
750         if (!head)
751                 return;
752 
753         list_for_each_safe(entry, tmp, head)
754         {
755                 list_del(entry);
756                 free(entry);
757         }
758 
759         free(head);
760 }
761 
762 bool
763 fw3_hotplug(bool add, void *zone, void *device)
764 {
765         struct fw3_zone *z = zone;
766         struct fw3_device *d = device;
767 
768         if (!*d->network)
769                 return false;
770 
771         switch (fork())
772         {
773         case -1:
774                 warn("Unable to fork(): %s\n", strerror(errno));
775                 return false;
776 
777         case 0:
778                 break;
779 
780         default:
781                 return true;
782         }
783 
784         close(0);
785         close(1);
786         close(2);
787         if (chdir("/")) {};
788 
789         clearenv();
790         setenv("ACTION",    add ? "add" : "remove", 1);
791         setenv("ZONE",      z->name,                1);
792         setenv("INTERFACE", d->network,             1);
793         setenv("DEVICE",    d->name,                1);
794 
795         execl(FW3_HOTPLUG, FW3_HOTPLUG, "firewall", NULL);
796 
797         /* unreached */
798         return false;
799 }
800 
801 int
802 fw3_netmask2bitlen(int family, void *mask)
803 {
804         int bits;
805         struct in_addr *v4;
806         struct in6_addr *v6;
807 
808         if (family == FW3_FAMILY_V6)
809                 for (bits = 0, v6 = mask;
810                      bits < 128 && (v6->s6_addr[bits / 8] << (bits % 8)) & 128;
811                      bits++);
812         else
813                 for (bits = 0, v4 = mask;
814                      bits < 32 && (ntohl(v4->s_addr) << bits) & 0x80000000;
815                      bits++);
816 
817         return bits;
818 }
819 
820 bool
821 fw3_bitlen2netmask(int family, int bits, void *mask)
822 {
823         int i;
824         uint8_t rem, b;
825         struct in_addr *v4;
826         struct in6_addr *v6;
827 
828         if (family == FW3_FAMILY_V6)
829         {
830                 if (bits < -128 || bits > 128)
831                         return false;
832 
833                 v6 = mask;
834                 rem = abs(bits);
835 
836                 for (i = 0; i < sizeof(v6->s6_addr); i++)
837                 {
838                         b = (rem > 8) ? 8 : rem;
839                         v6->s6_addr[i] = (uint8_t)(0xFF << (8 - b));
840                         rem -= b;
841                 }
842 
843                 if (bits < 0)
844                         for (i = 0; i < sizeof(v6->s6_addr); i++)
845                                 v6->s6_addr[i] = ~v6->s6_addr[i];
846         }
847         else
848         {
849                 if (bits < -32 || bits > 32)
850                         return false;
851 
852                 v4 = mask;
853                 v4->s_addr = bits ? htonl(~((1 << (32 - abs(bits))) - 1)) : 0;
854 
855                 if (bits < 0)
856                         v4->s_addr = ~v4->s_addr;
857         }
858 
859         return true;
860 }
861 
862 void
863 fw3_flush_conntrack(void *state)
864 {
865         bool found;
866         struct fw3_state *s = state;
867         struct fw3_address *addr;
868         struct fw3_device *dev;
869         struct fw3_zone *zone;
870         struct ifaddrs *ifaddr, *ifa;
871         struct sockaddr_in *sin;
872         struct sockaddr_in6 *sin6;
873         char buf[INET6_ADDRSTRLEN];
874         FILE *ct;
875 
876         if (!state)
877         {
878                 if ((ct = fopen("/proc/net/nf_conntrack", "w")) != NULL)
879                 {
880                         info(" * Flushing conntrack table ...");
881 
882                         fwrite("f\n", 1, 2, ct);
883                         fclose(ct);
884                 }
885 
886                 return;
887         }
888 
889         if (getifaddrs(&ifaddr))
890         {
891                 warn("Cannot get interface addresses: %s", strerror(errno));
892                 return;
893         }
894 
895         if ((ct = fopen("/proc/net/nf_conntrack", "w")) != NULL)
896         {
897                 list_for_each_entry(zone, &s->zones, list)
898                 list_for_each_entry(addr, &zone->old_addrs, list)
899                 {
900                         found = false;
901 
902                         list_for_each_entry(dev, &zone->devices, list)
903                         {
904                                 for (ifa = ifaddr; ifa && !found; ifa = ifa->ifa_next)
905                                 {
906                                         if (!ifa->ifa_addr || strcmp(dev->name, ifa->ifa_name))
907                                                 continue;
908 
909                                         sin = (struct sockaddr_in *)ifa->ifa_addr;
910                                         sin6 = (struct sockaddr_in6 *)ifa->ifa_addr;
911 
912                                         if (addr->family == FW3_FAMILY_V4 &&
913                                                 sin->sin_family == AF_INET)
914                                         {
915                                                 found = !memcmp(&addr->address.v4, &sin->sin_addr,
916                                                                                 sizeof(sin->sin_addr));
917                                         }
918                                         else if (addr->family == FW3_FAMILY_V6 &&
919                                                          sin6->sin6_family == AF_INET6)
920                                         {
921                                                 found = !memcmp(&addr->address.v6, &sin6->sin6_addr,
922                                                                                 sizeof(sin6->sin6_addr));
923                                         }
924                                 }
925 
926                                 if (found)
927                                         break;
928                         }
929 
930                         if (!found)
931                         {
932                                 inet_ntop(addr->family == FW3_FAMILY_V4 ? AF_INET : AF_INET6,
933                                                   &addr->address.v4, buf, sizeof(buf));
934 
935                                 info(" * Flushing conntrack: %s", buf);
936                                 fprintf(ct, "%s\n", buf);
937                         }
938                 }
939 
940                 fclose(ct);
941         }
942 
943         freeifaddrs(ifaddr);
944 }
945 
946 bool fw3_attr_parse_name_type(struct blob_attr *entry, const char **name, const char **type)
947 {
948         struct blob_attr *opt;
949         unsigned orem;
950 
951         if (!type || !name)
952                 return false;
953 
954         *type = NULL;
955 
956         blobmsg_for_each_attr(opt, entry, orem)
957                 if (!strcmp(blobmsg_name(opt), "type"))
958                         *type = blobmsg_get_string(opt);
959                 else if (!strcmp(blobmsg_name(opt), "name"))
960                         *name = blobmsg_get_string(opt);
961 
962         return *type != NULL ? true : false;
963 }
964 
965 const char *
966 fw3_protoname(void *proto)
967 {
968         static char buf[sizeof("4294967295")];
969         struct fw3_protocol *p = proto;
970         struct protoent *pe;
971 
972         if (!p)
973                 return "?";
974 
975         pe = getprotobynumber(p->protocol);
976 
977         if (!pe)
978         {
979                 snprintf(buf, sizeof(buf), "%u", p->protocol);
980                 return buf;
981         }
982 
983         return pe->p_name;
984 }
985 
986 bool
987 fw3_check_loopback_dev(const char *name)
988 {
989         struct ifreq ifr;
990         int s;
991         bool rv = false;
992 
993         s = socket(AF_LOCAL, SOCK_DGRAM, 0);
994 
995         if (s < 0)
996                 return false;
997 
998         memset(&ifr, 0, sizeof(ifr));
999         snprintf(ifr.ifr_name, sizeof(ifr.ifr_name), "%s", name);
1000 
1001         if (ioctl(s, SIOCGIFFLAGS, &ifr) >= 0) {
1002                 if (ifr.ifr_flags & IFF_LOOPBACK)
1003                         rv = true;
1004         }
1005 
1006         close(s);
1007 
1008         return rv;
1009 }
1010 
1011 bool
1012 fw3_check_loopback_addr(struct fw3_address *addr)
1013 {
1014         if (addr->family == FW3_FAMILY_V4 &&
1015             (ntohl(addr->address.v4.s_addr) >> IN_CLASSA_NSHIFT) == IN_LOOPBACKNET)
1016                 return true;
1017 
1018         if (addr->family == FW3_FAMILY_V6 && !addr->range &&
1019             fw3_netmask2bitlen(FW3_FAMILY_V6, &addr->mask.v6) == 128 &&
1020             IN6_IS_ADDR_LOOPBACK(&addr->address.v6))
1021                 return true;
1022 
1023         return false;
1024 }
1025 

This page was automatically generated by LXR 0.3.1.  •  OpenWrt