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

Sources/firewall3/options.c

  1 /*
  2  * firewall3 - 3rd OpenWrt UCI firewall implementation
  3  *
  4  *   Copyright (C) 2013-2014 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 #include "options.h"
 20 #include "ubus.h"
 21 
 22 
 23 static bool
 24 put_value(void *ptr, void *val, int elem_size, bool is_list)
 25 {
 26         void *copy;
 27 
 28         if (is_list)
 29         {
 30                 copy = malloc(elem_size);
 31 
 32                 if (!copy)
 33                         return false;
 34 
 35                 memcpy(copy, val, elem_size);
 36                 list_add_tail((struct list_head *)copy, (struct list_head *)ptr);
 37                 return true;
 38         }
 39 
 40         memcpy(ptr, val, elem_size);
 41         return false;
 42 }
 43 
 44 static bool
 45 parse_enum(void *ptr, const char *val, const char **values, int min, int max)
 46 {
 47         int i, l = strlen(val);
 48 
 49         if (l > 0)
 50         {
 51                 for (i = 0; i <= (max - min); i++)
 52                 {
 53                         if (!strncasecmp(val, values[i], l))
 54                         {
 55                                 *((int *)ptr) = min + i;
 56                                 return true;
 57                         }
 58                 }
 59         }
 60 
 61         return false;
 62 }
 63 
 64 
 65 const char *fw3_flag_names[__FW3_FLAG_MAX] = {
 66         "filter",
 67         "nat",
 68         "mangle",
 69         "raw",
 70 
 71         "IPv4",
 72         "IPv6",
 73 
 74         "ACCEPT",
 75         "REJECT",
 76         "DROP",
 77         "NOTRACK",
 78         "HELPER",
 79         "MARK",
 80         "DSCP",
 81         "DNAT",
 82         "SNAT",
 83         "MASQUERADE",
 84 
 85         "ACCEPT",
 86         "REJECT",
 87         "DROP",
 88 };
 89 
 90 const char *fw3_reject_code_names[__FW3_REJECT_CODE_MAX] = {
 91         "tcp-reset",
 92         "port-unreach",
 93         "adm-prohibited",
 94 };
 95 
 96 const char *fw3_limit_units[__FW3_LIMIT_UNIT_MAX] = {
 97         "second",
 98         "minute",
 99         "hour",
100         "day",
101 };
102 
103 const char *fw3_ipset_method_names[__FW3_IPSET_METHOD_MAX] = {
104         "(bug)",
105         "bitmap",
106         "hash",
107         "list",
108 };
109 
110 const char *fw3_ipset_type_names[__FW3_IPSET_TYPE_MAX] = {
111         "(bug)",
112         "ip",
113         "port",
114         "mac",
115         "net",
116         "set",
117 };
118 
119 static const char *weekdays[] = {
120         "monday",
121         "tuesday",
122         "wednesday",
123         "thursday",
124         "friday",
125         "saturday",
126         "sunday",
127 };
128 
129 static const char *include_types[] = {
130         "script",
131         "restore",
132 };
133 
134 static const char *reflection_sources[] = {
135         "internal",
136         "external",
137 };
138 
139 static const struct { const char *name; uint8_t dscp; } dscp_classes[] = {
140         { "CS0",  0x00 },
141         { "CS1",  0x08 },
142         { "CS2",  0x10 },
143         { "CS3",  0x18 },
144         { "CS4",  0x20 },
145         { "CS5",  0x28 },
146         { "CS6",  0x30 },
147         { "CS7",  0x38 },
148         { "BE",   0x00 },
149         { "LE",   0x01 },
150         { "AF11", 0x0a },
151         { "AF12", 0x0c },
152         { "AF13", 0x0e },
153         { "AF21", 0x12 },
154         { "AF22", 0x14 },
155         { "AF23", 0x16 },
156         { "AF31", 0x1a },
157         { "AF32", 0x1c },
158         { "AF33", 0x1e },
159         { "AF41", 0x22 },
160         { "AF42", 0x24 },
161         { "AF43", 0x26 },
162         { "EF",   0x2e }
163 };
164 
165 
166 bool
167 fw3_parse_bool(void *ptr, const char *val, bool is_list)
168 {
169         if (!strcmp(val, "true") || !strcmp(val, "yes") || !strcmp(val, "1"))
170                 *((bool *)ptr) = true;
171         else
172                 *((bool *)ptr) = false;
173 
174         return true;
175 }
176 
177 bool
178 fw3_parse_int(void *ptr, const char *val, bool is_list)
179 {
180         char *e;
181         int n = strtol(val, &e, 0);
182 
183         if (e == val || *e)
184                 return false;
185 
186         *((int *)ptr) = n;
187 
188         return true;
189 }
190 
191 bool
192 fw3_parse_string(void *ptr, const char *val, bool is_list)
193 {
194         *((char **)ptr) = (char *)val;
195         return true;
196 }
197 
198 bool
199 fw3_parse_target(void *ptr, const char *val, bool is_list)
200 {
201         return parse_enum(ptr, val, &fw3_flag_names[FW3_FLAG_ACCEPT],
202                           FW3_FLAG_ACCEPT, FW3_FLAG_MASQUERADE);
203 }
204 
205 bool
206 fw3_parse_reject_code(void *ptr, const char *val, bool is_list)
207 {
208         return parse_enum(ptr, val, &fw3_reject_code_names[FW3_REJECT_CODE_TCP_RESET],
209                           FW3_REJECT_CODE_TCP_RESET, FW3_REJECT_CODE_ADM_PROHIBITED);
210 }
211 
212 bool
213 fw3_parse_limit(void *ptr, const char *val, bool is_list)
214 {
215         struct fw3_limit *limit = ptr;
216         enum fw3_limit_unit u = FW3_LIMIT_UNIT_SECOND;
217         char *e;
218         int n;
219 
220         if (*val == '!')
221         {
222                 limit->invert = true;
223                 while (isspace(*++val));
224         }
225 
226         n = strtol(val, &e, 10);
227 
228         if (errno == ERANGE || errno == EINVAL)
229                 return false;
230 
231         if (*e && *e++ != '/')
232                 return false;
233 
234         if (!strlen(e))
235                 return false;
236 
237         if (!parse_enum(&u, e, fw3_limit_units, 0, FW3_LIMIT_UNIT_DAY))
238                 return false;
239 
240         limit->rate = n;
241         limit->unit = u;
242 
243         return true;
244 }
245 
246 bool
247 fw3_parse_device(void *ptr, const char *val, bool is_list)
248 {
249         char *p;
250         struct fw3_device dev = { };
251 
252         if (*val == '*')
253         {
254                 dev.set = true;
255                 dev.any = true;
256                 put_value(ptr, &dev, sizeof(dev), is_list);
257                 return true;
258         }
259 
260         if (*val == '!')
261         {
262                 dev.invert = true;
263                 while (isspace(*++val));
264         }
265 
266         if ((p = strchr(val, '@')) != NULL)
267         {
268                 *p++ = 0;
269                 snprintf(dev.network, sizeof(dev.network), "%s", p);
270         }
271 
272         if (*val)
273                 snprintf(dev.name, sizeof(dev.name), "%s", val);
274         else
275                 return false;
276 
277         dev.set = true;
278         put_value(ptr, &dev, sizeof(dev), is_list);
279         return true;
280 }
281 
282 bool
283 fw3_parse_address(void *ptr, const char *val, bool is_list)
284 {
285         struct fw3_address addr = { };
286         struct in_addr v4;
287         struct in6_addr v6;
288         char *p = NULL, *m = NULL, *s, *e;
289         int bits = -1;
290 
291         if (*val == '!')
292         {
293                 addr.invert = true;
294                 while (isspace(*++val));
295         }
296 
297         s = strdup(val);
298 
299         if (!s)
300                 return false;
301 
302         if ((m = strchr(s, '/')) != NULL)
303                 *m++ = 0;
304         else if ((p = strchr(s, '-')) != NULL)
305                 *p++ = 0;
306 
307         if (inet_pton(AF_INET6, s, &v6))
308         {
309                 addr.family = FW3_FAMILY_V6;
310                 addr.address.v6 = v6;
311 
312                 if (m)
313                 {
314                         if (!inet_pton(AF_INET6, m, &v6))
315                         {
316                                 bits = strtol(m, &e, 10);
317 
318                                 if ((*e != 0) || !fw3_bitlen2netmask(addr.family, bits, &v6))
319                                         goto fail;
320                         }
321 
322                         addr.mask.v6 = v6;
323                 }
324                 else if (p)
325                 {
326                         if (!inet_pton(AF_INET6, p, &addr.mask.v6))
327                                 goto fail;
328 
329                         addr.range = true;
330                 }
331                 else
332                 {
333                         memset(addr.mask.v6.s6_addr, 0xFF, 16);
334                 }
335         }
336         else if (inet_pton(AF_INET, s, &v4))
337         {
338                 addr.family = FW3_FAMILY_V4;
339                 addr.address.v4 = v4;
340 
341                 if (m)
342                 {
343                         if (!inet_pton(AF_INET, m, &v4))
344                         {
345                                 bits = strtol(m, &e, 10);
346 
347                                 if ((*e != 0) || !fw3_bitlen2netmask(addr.family, bits, &v4))
348                                         goto fail;
349                         }
350 
351                         addr.mask.v4 = v4;
352                 }
353                 else if (p)
354                 {
355                         if (!inet_pton(AF_INET, p, &addr.mask.v4))
356                                 goto fail;
357 
358                         addr.range = true;
359                 }
360                 else
361                 {
362                         addr.mask.v4.s_addr = 0xFFFFFFFF;
363                 }
364         }
365         else
366         {
367                 goto fail;
368         }
369 
370         free(s);
371         addr.set = true;
372         put_value(ptr, &addr, sizeof(addr), is_list);
373         return true;
374 
375 fail:
376         free(s);
377         return false;
378 }
379 
380 bool
381 fw3_parse_network(void *ptr, const char *val, bool is_list)
382 {
383         struct fw3_device dev = { };
384         struct fw3_address *addr, *tmp;
385         LIST_HEAD(addr_list);
386         int n_addrs;
387 
388         if (!fw3_parse_address(ptr, val, is_list))
389         {
390                 if (!fw3_parse_device(&dev, val, false))
391                         return false;
392 
393                 n_addrs = fw3_ubus_address(&addr_list, dev.name);
394 
395                 list_for_each_entry(addr, &addr_list, list)
396                 {
397                         addr->invert = dev.invert;
398                         addr->resolved = true;
399                 }
400 
401                 /* add an empty address member with .set = false, .resolved = true
402                  * to signal resolving failure to callers */
403                 if (n_addrs == 0)
404                 {
405                         tmp = fw3_alloc(sizeof(*tmp));
406                         tmp->resolved = true;
407 
408                         list_add_tail(&tmp->list, &addr_list);
409                 }
410 
411                 if (is_list)
412                 {
413                         list_splice_tail(&addr_list, ptr);
414                 }
415                 else if (!list_empty(&addr_list))
416                 {
417                         memcpy(ptr, list_first_entry(&addr_list, typeof(*addr), list),
418                                sizeof(*addr));
419 
420                         list_for_each_entry_safe(addr, tmp, &addr_list, list)
421                                 free(addr);
422                 }
423         }
424 
425         return true;
426 }
427 
428 bool
429 fw3_parse_mac(void *ptr, const char *val, bool is_list)
430 {
431         struct fw3_mac addr = { };
432         struct ether_addr *mac;
433 
434         if (*val == '!')
435         {
436                 addr.invert = true;
437                 while (isspace(*++val));
438         }
439 
440         if ((mac = ether_aton(val)) != NULL)
441         {
442                 addr.mac = *mac;
443                 addr.set = true;
444 
445                 put_value(ptr, &addr, sizeof(addr), is_list);
446                 return true;
447         }
448 
449         return false;
450 }
451 
452 bool
453 fw3_parse_port(void *ptr, const char *val, bool is_list)
454 {
455         struct fw3_port range = { };
456         uint16_t n;
457         uint16_t m;
458         char *p;
459 
460         if (*val == '!')
461         {
462                 range.invert = true;
463                 while (isspace(*++val));
464         }
465 
466         n = strtoul(val, &p, 10);
467 
468         if (errno == ERANGE || errno == EINVAL)
469                 return false;
470 
471         if (*p && *p != '-' && *p != ':')
472                 return false;
473 
474         if (*p)
475         {
476                 m = strtoul(++p, NULL, 10);
477 
478                 if (errno == ERANGE || errno == EINVAL || m < n)
479                         return false;
480 
481                 range.port_min = n;
482                 range.port_max = m;
483         }
484         else
485         {
486                 range.port_min = n;
487                 range.port_max = n;
488         }
489 
490         range.set = true;
491         put_value(ptr, &range, sizeof(range), is_list);
492         return true;
493 }
494 
495 bool
496 fw3_parse_family(void *ptr, const char *val, bool is_list)
497 {
498         if (!strcmp(val, "any") || !strcmp(val, "*"))
499                 *((enum fw3_family *)ptr) = FW3_FAMILY_ANY;
500         else if (!strcmp(val, "inet") || strrchr(val, '4'))
501                 *((enum fw3_family *)ptr) = FW3_FAMILY_V4;
502         else if (!strcmp(val, "inet6") || strrchr(val, '6'))
503                 *((enum fw3_family *)ptr) = FW3_FAMILY_V6;
504         else
505                 return false;
506 
507         return true;
508 }
509 
510 bool
511 fw3_parse_icmptype(void *ptr, const char *val, bool is_list)
512 {
513         struct fw3_icmptype icmp = { };
514         bool v4 = false;
515         bool v6 = false;
516         char *p;
517         int i;
518 
519         for (i = 0; i < ARRAY_SIZE(fw3_icmptype_list_v4); i++)
520         {
521                 if (!strcmp(val, fw3_icmptype_list_v4[i].name))
522                 {
523                         icmp.type     = fw3_icmptype_list_v4[i].type;
524                         icmp.code_min = fw3_icmptype_list_v4[i].code_min;
525                         icmp.code_max = fw3_icmptype_list_v4[i].code_max;
526 
527                         v4 = true;
528                         break;
529                 }
530         }
531 
532         for (i = 0; i < ARRAY_SIZE(fw3_icmptype_list_v6); i++)
533         {
534                 if (!strcmp(val, fw3_icmptype_list_v6[i].name))
535                 {
536                         icmp.type6     = fw3_icmptype_list_v6[i].type;
537                         icmp.code6_min = fw3_icmptype_list_v6[i].code_min;
538                         icmp.code6_max = fw3_icmptype_list_v6[i].code_max;
539 
540                         v6 = true;
541                         break;
542                 }
543         }
544 
545         if (!v4 && !v6)
546         {
547                 i = strtoul(val, &p, 10);
548 
549                 if ((p == val) || (*p != '/' && *p != 0) || (i > 0xFF))
550                         return false;
551 
552                 icmp.type = i;
553 
554                 if (*p == '/')
555                 {
556                         val = ++p;
557                         i = strtoul(val, &p, 10);
558 
559                         if ((p == val) || (*p != 0) || (i > 0xFF))
560                                 return false;
561 
562                         icmp.code_min = i;
563                         icmp.code_max = i;
564                 }
565                 else
566                 {
567                         icmp.code_min = 0;
568                         icmp.code_max = 0xFF;
569                 }
570 
571                 icmp.type6     = icmp.type;
572                 icmp.code6_min = icmp.code_min;
573                 icmp.code6_max = icmp.code_max;
574 
575                 v4 = true;
576                 v6 = true;
577         }
578 
579         icmp.family = (v4 && v6) ? FW3_FAMILY_ANY
580                                  : (v6 ? FW3_FAMILY_V6 : FW3_FAMILY_V4);
581 
582         put_value(ptr, &icmp, sizeof(icmp), is_list);
583         return true;
584 }
585 
586 bool
587 fw3_parse_protocol(void *ptr, const char *val, bool is_list)
588 {
589         struct fw3_protocol proto = { };
590         struct protoent *ent;
591         char *e;
592 
593         if (*val == '!')
594         {
595                 proto.invert = true;
596                 while (isspace(*++val));
597         }
598 
599         if (!strcmp(val, "all") || !strcmp(val, "any") || !strcmp(val, "*"))
600         {
601                 proto.any = true;
602                 put_value(ptr, &proto, sizeof(proto), is_list);
603                 return true;
604         }
605         else if (!strcmp(val, "icmpv6"))
606         {
607                 val = "ipv6-icmp";
608         }
609         else if (!strcmp(val, "tcpudp"))
610         {
611                 proto.protocol = 6;
612                 if (put_value(ptr, &proto, sizeof(proto), is_list))
613                 {
614                         proto.protocol = 17;
615                         put_value(ptr, &proto, sizeof(proto), is_list);
616                 }
617 
618                 return true;
619         }
620 
621         ent = getprotobyname(val);
622 
623         if (ent)
624         {
625                 proto.protocol = ent->p_proto;
626                 put_value(ptr, &proto, sizeof(proto), is_list);
627                 return true;
628         }
629 
630         proto.protocol = strtoul(val, &e, 10);
631 
632         if ((e == val) || (*e != 0))
633                 return false;
634 
635         put_value(ptr, &proto, sizeof(proto), is_list);
636         return true;
637 }
638 
639 bool
640 fw3_parse_ipset_method(void *ptr, const char *val, bool is_list)
641 {
642         return parse_enum(ptr, val, &fw3_ipset_method_names[FW3_IPSET_METHOD_BITMAP],
643                           FW3_IPSET_METHOD_BITMAP, FW3_IPSET_METHOD_LIST);
644 }
645 
646 bool
647 fw3_parse_ipset_datatype(void *ptr, const char *val, bool is_list)
648 {
649         struct fw3_ipset_datatype type = { };
650 
651         type.dir = "src";
652 
653         if (!strncmp(val, "dest_", 5))
654         {
655                 val += 5;
656                 type.dir = "dst";
657         }
658         else if (!strncmp(val, "dst_", 4))
659         {
660                 val += 4;
661                 type.dir = "dst";
662         }
663         else if (!strncmp(val, "src_", 4))
664         {
665                 val += 4;
666                 type.dir = "src";
667         }
668 
669         if (parse_enum(&type.type, val, &fw3_ipset_type_names[FW3_IPSET_TYPE_IP],
670                        FW3_IPSET_TYPE_IP, FW3_IPSET_TYPE_SET))
671         {
672                 put_value(ptr, &type, sizeof(type), is_list);
673                 return true;
674         }
675 
676         return false;
677 }
678 
679 bool
680 fw3_parse_date(void *ptr, const char *val, bool is_list)
681 {
682         unsigned int year = 1970, mon = 1, day = 1, hour = 0, min = 0, sec = 0;
683         struct tm tm = { 0 };
684         time_t ts;
685         char *p;
686 
687         year = strtoul(val, &p, 10);
688         if ((*p != '-' && *p) || year < 1970 || year > 2038)
689                 goto fail;
690         else if (!*p)
691                 goto ret;
692 
693         mon = strtoul(++p, &p, 10);
694         if ((*p != '-' && *p) || mon > 12)
695                 goto fail;
696         else if (!*p)
697                 goto ret;
698 
699         day = strtoul(++p, &p, 10);
700         if ((*p != 'T' && *p) || day > 31)
701                 goto fail;
702         else if (!*p)
703                 goto ret;
704 
705         hour = strtoul(++p, &p, 10);
706         if ((*p != ':' && *p) || hour > 23)
707                 goto fail;
708         else if (!*p)
709                 goto ret;
710 
711         min = strtoul(++p, &p, 10);
712         if ((*p != ':' && *p) || min > 59)
713                 goto fail;
714         else if (!*p)
715                 goto ret;
716 
717         sec = strtoul(++p, &p, 10);
718         if (*p || sec > 59)
719                 goto fail;
720 
721 ret:
722         tm.tm_year = year - 1900;
723         tm.tm_mon  = mon - 1;
724         tm.tm_mday = day;
725         tm.tm_hour = hour;
726         tm.tm_min  = min;
727         tm.tm_sec  = sec;
728 
729         ts = mktime(&tm) - timezone;
730 
731         if (ts >= 0)
732         {
733                 gmtime_r(&ts, (struct tm *)ptr);
734                 return true;
735         }
736 
737 fail:
738         return false;
739 }
740 
741 bool
742 fw3_parse_time(void *ptr, const char *val, bool is_list)
743 {
744         unsigned int hour = 0, min = 0, sec = 0;
745         char *p;
746 
747         hour = strtoul(val, &p, 10);
748         if (*p != ':' || hour > 23)
749                 goto fail;
750 
751         min = strtoul(++p, &p, 10);
752         if ((*p != ':' && *p) || min > 59)
753                 goto fail;
754         else if (!*p)
755                 goto ret;
756 
757         sec = strtoul(++p, &p, 10);
758         if (*p || sec > 59)
759                 goto fail;
760 
761 ret:
762         *((int *)ptr) = 60 * 60 * hour + 60 * min + sec;
763         return true;
764 
765 fail:
766         return false;
767 }
768 
769 bool
770 fw3_parse_weekdays(void *ptr, const char *val, bool is_list)
771 {
772         unsigned int w = 0;
773         char *p, *s;
774 
775         if (*val == '!')
776         {
777                 fw3_setbit(*(uint8_t *)ptr, 0);
778                 while (isspace(*++val));
779         }
780 
781         if (!(s = strdup(val)))
782                 return false;
783 
784         for (p = strtok(s, " \t"); p; p = strtok(NULL, " \t"))
785         {
786                 if (!parse_enum(&w, p, weekdays, 1, 7))
787                 {
788                         w = strtoul(p, &p, 10);
789 
790                         if (*p || w < 1 || w > 7)
791                         {
792                                 free(s);
793                                 return false;
794                         }
795                 }
796 
797                 fw3_setbit(*(uint8_t *)ptr, w);
798         }
799 
800         free(s);
801         return true;
802 }
803 
804 bool
805 fw3_parse_monthdays(void *ptr, const char *val, bool is_list)
806 {
807         unsigned int d;
808         char *p, *s;
809 
810         if (*val == '!')
811         {
812                 fw3_setbit(*(uint32_t *)ptr, 0);
813                 while (isspace(*++val));
814         }
815 
816         if (!(s = strdup(val)))
817                 return false;
818 
819         for (p = strtok(s, " \t"); p; p = strtok(NULL, " \t"))
820         {
821                 d = strtoul(p, &p, 10);
822 
823                 if (*p || d < 1 || d > 31)
824                 {
825                         free(s);
826                         return false;
827                 }
828 
829                 fw3_setbit(*(uint32_t *)ptr, d);
830         }
831 
832         free(s);
833         return true;
834 }
835 
836 bool
837 fw3_parse_include_type(void *ptr, const char *val, bool is_list)
838 {
839         return parse_enum(ptr, val, include_types,
840                           FW3_INC_TYPE_SCRIPT, FW3_INC_TYPE_RESTORE);
841 }
842 
843 bool
844 fw3_parse_reflection_source(void *ptr, const char *val, bool is_list)
845 {
846         return parse_enum(ptr, val, reflection_sources,
847                           FW3_REFLECTION_INTERNAL, FW3_REFLECTION_EXTERNAL);
848 }
849 
850 bool
851 fw3_parse_mark(void *ptr, const char *val, bool is_list)
852 {
853         uint32_t n;
854         char *s, *e;
855         struct fw3_mark *m = ptr;
856 
857         if (*val == '!')
858         {
859                 m->invert = true;
860                 while (isspace(*++val));
861         }
862 
863         if ((s = strchr(val, '/')) != NULL)
864                 *s++ = 0;
865 
866         n = strtoul(val, &e, 0);
867 
868         if (e == val || *e)
869                 return false;
870 
871         m->mark = n;
872         m->mask = 0xFFFFFFFF;
873 
874         if (s)
875         {
876                 n = strtoul(s, &e, 0);
877 
878                 if (e == s || *e)
879                         return false;
880 
881                 m->mask = n;
882         }
883 
884         m->set = true;
885         return true;
886 }
887 
888 bool
889 fw3_parse_dscp(void *ptr, const char *val, bool is_list)
890 {
891         uint32_t n;
892         char *e;
893         struct fw3_dscp *d = ptr;
894 
895         if (*val == '!')
896         {
897                 d->invert = true;
898                 while (isspace(*++val));
899         }
900 
901         for (n = 0; n < sizeof(dscp_classes) / sizeof(dscp_classes[0]); n++)
902         {
903                 if (strcmp(dscp_classes[n].name, val))
904                         continue;
905 
906                 d->set = true;
907                 d->dscp = dscp_classes[n].dscp;
908                 return true;
909         }
910 
911         n = strtoul(val, &e, 0);
912 
913         if (e == val || *e || n > 0x3F)
914                 return false;
915 
916         d->set = true;
917         d->dscp = n;
918         return true;
919 }
920 
921 bool
922 fw3_parse_setmatch(void *ptr, const char *val, bool is_list)
923 {
924         struct fw3_setmatch *m = ptr;
925         char *p, *s;
926         int i;
927 
928         if (*val == '!')
929         {
930                 m->invert = true;
931                 while (isspace(*++val));
932         }
933 
934         if (!(s = strdup(val)))
935                 return false;
936 
937         if (!(p = strtok(s, " \t")))
938         {
939                 free(s);
940                 return false;
941         }
942 
943         snprintf(m->name, sizeof(m->name), "%s", p);
944 
945         for (i = 0, p = strtok(NULL, " \t,");
946              i < 3 && p != NULL;
947              i++, p = strtok(NULL, " \t,"))
948         {
949                 if (!strncmp(p, "dest", 4) || !strncmp(p, "dst", 3))
950                         m->dir[i] = "dst";
951                 else if (!strncmp(p, "src", 3))
952                         m->dir[i] = "src";
953         }
954 
955         free(s);
956 
957         m->set = true;
958         return true;
959 }
960 
961 bool
962 fw3_parse_direction(void *ptr, const char *val, bool is_list)
963 {
964         bool *is_out = ptr;
965         bool valid = true;
966 
967         if (!strcmp(val, "in") || !strcmp(val, "ingress"))
968                 *is_out = false;
969         else if (!strcmp(val, "out") || !strcmp(val, "egress"))
970                 *is_out = true;
971         else
972                 valid = false;
973 
974         return valid;
975 }
976 
977 bool
978 fw3_parse_cthelper(void *ptr, const char *val, bool is_list)
979 {
980         struct fw3_cthelpermatch m = { };
981 
982         if (*val == '!')
983         {
984                 m.invert = true;
985                 while (isspace(*++val));
986         }
987 
988         if (*val)
989         {
990                 m.set = true;
991                 snprintf(m.name, sizeof(m.name), "%s", val);
992                 put_value(ptr, &m, sizeof(m), is_list);
993                 return true;
994         }
995 
996         return false;
997 }
998 
999 bool
1000 fw3_parse_setentry(void *ptr, const char *val, bool is_list)
1001 {
1002         struct fw3_setentry e = { };
1003 
1004         e.value = val;
1005         put_value(ptr, &e, sizeof(e), is_list);
1006 
1007         return true;
1008 }
1009 
1010 
1011 bool
1012 fw3_parse_options(void *s, const struct fw3_option *opts,
1013                   struct uci_section *section)
1014 {
1015         char *p, *v;
1016         bool known, inv;
1017         struct uci_element *e, *l;
1018         struct uci_option *o;
1019         const struct fw3_option *opt;
1020         struct list_head *dest;
1021         bool valid = true;
1022 
1023         uci_foreach_element(&section->options, e)
1024         {
1025                 o = uci_to_option(e);
1026                 known = false;
1027 
1028                 for (opt = opts; opt->name; opt++)
1029                 {
1030                         if (!opt->parse)
1031                                 continue;
1032 
1033                         if (strcmp(opt->name, e->name))
1034                                 continue;
1035 
1036                         if (o->type == UCI_TYPE_LIST)
1037                         {
1038                                 if (!opt->elem_size)
1039                                 {
1040                                         warn_elem(e, "must not be a list");
1041                                         valid = false;
1042                                 }
1043                                 else
1044                                 {
1045                                         dest = (struct list_head *)((char *)s + opt->offset);
1046 
1047                                         uci_foreach_element(&o->v.list, l)
1048                                         {
1049                                                 if (!l->name)
1050                                                         continue;
1051 
1052                                                 if (!opt->parse(dest, l->name, true))
1053                                                 {
1054                                                         warn_elem(e, "has invalid value '%s'", l->name);
1055                                                         valid = false;
1056                                                         continue;
1057                                                 }
1058                                         }
1059                                 }
1060                         }
1061                         else
1062                         {
1063                                 v = o->v.string;
1064 
1065                                 if (!v)
1066                                         continue;
1067 
1068                                 if (!opt->elem_size)
1069                                 {
1070                                         if (!opt->parse((char *)s + opt->offset, o->v.string, false))
1071                                         {
1072                                                 warn_elem(e, "has invalid value '%s'", o->v.string);
1073                                                 valid = false;
1074                                         }
1075                                 }
1076                                 else
1077                                 {
1078                                         inv = false;
1079                                         dest = (struct list_head *)((char *)s + opt->offset);
1080 
1081                                         for (p = strtok(v, " \t"); p != NULL; p = strtok(NULL, " \t"))
1082                                         {
1083                                                 /* If we encounter a sole "!" token, assume that it
1084                                                  * is meant to be part of the next token, so silently
1085                                                  * skip it and remember the state... */
1086                                                 if (!strcmp(p, "!"))
1087                                                 {
1088                                                         inv = true;
1089                                                         continue;
1090                                                 }
1091 
1092                                                 /* The previous token was a sole "!", rewind pointer
1093                                                  * back by one byte to precede the value with an
1094                                                  * exclamation mark which effectively turns
1095                                                  * ("!", "foo") into ("!foo") */
1096                                                 if (inv)
1097                                                 {
1098                                                         *--p = '!';
1099                                                         inv = false;
1100                                                 }
1101 
1102                                                 if (!opt->parse(dest, p, true))
1103                                                 {
1104                                                         warn_elem(e, "has invalid value '%s'", p);
1105                                                         valid = false;
1106                                                         continue;
1107                                                 }
1108                                         }
1109 
1110                                         /* The last token was a sole "!" without any subsequent
1111                                          * text, so pass it to the option parser as-is. */
1112                                         if (inv && !opt->parse(dest, "!", true))
1113                                         {
1114                                                 warn_elem(e, "has invalid value '%s'", p);
1115                                                 valid = false;
1116                                         }
1117                                 }
1118                         }
1119 
1120                         known = true;
1121                         break;
1122                 }
1123 
1124                 if (!known)
1125                         warn_elem(e, "is unknown");
1126         }
1127 
1128         return valid;
1129 }
1130 
1131 
1132 bool
1133 fw3_parse_blob_options(void *s, const struct fw3_option *opts,
1134                        struct blob_attr *a, const char *name)
1135 {
1136         char *p, *v, buf[16];
1137         bool known;
1138         unsigned rem, erem;
1139         struct blob_attr *o, *e;
1140         const struct fw3_option *opt;
1141         struct list_head *dest;
1142         bool valid = true;
1143 
1144         blobmsg_for_each_attr(o, a, rem)
1145         {
1146                 known = false;
1147 
1148                 for (opt = opts; opt->name; opt++)
1149                 {
1150                         if (!opt->parse)
1151                                 continue;
1152 
1153                         if (strcmp(opt->name, blobmsg_name(o)))
1154                                 continue;
1155 
1156                         if (blobmsg_type(o) == BLOBMSG_TYPE_ARRAY)
1157                         {
1158                                 if (!opt->elem_size)
1159                                 {
1160                                         fprintf(stderr, "%s: '%s' must not be a list\n",
1161                                                 name, opt->name);
1162 
1163                                         valid = false;
1164                                 }
1165                                 else
1166                                 {
1167                                         dest = (struct list_head *)((char *)s + opt->offset);
1168 
1169                                         blobmsg_for_each_attr(e, o, erem)
1170                                         {
1171                                                 if (blobmsg_type(e) == BLOBMSG_TYPE_INT32) {
1172                                                         snprintf(buf, sizeof(buf), "%d", blobmsg_get_u32(e));
1173                                                         v = buf;
1174                                                 } else if (blobmsg_type(o) == BLOBMSG_TYPE_BOOL) {
1175                                                         snprintf(buf, sizeof(buf), "%d", blobmsg_get_bool(o));
1176                                                         v = buf;
1177                                                 } else {
1178                                                         v = blobmsg_get_string(e);
1179                                                 }
1180 
1181                                                 if (!opt->parse(dest, v, true))
1182                                                 {
1183                                                         fprintf(stderr, "%s: '%s' has invalid value '%s'\n",
1184                                                                 name, opt->name, v);
1185                                                         valid = false;
1186                                                         continue;
1187                                                 }
1188                                         }
1189                                 }
1190                         }
1191                         else
1192                         {
1193                                 if (blobmsg_type(o) == BLOBMSG_TYPE_INT32) {
1194                                         snprintf(buf, sizeof(buf), "%d", blobmsg_get_u32(o));
1195                                         v = buf;
1196                                 } else if (blobmsg_type(o) == BLOBMSG_TYPE_BOOL) {
1197                                         snprintf(buf, sizeof(buf), "%d", blobmsg_get_bool(o));
1198                                         v = buf;
1199                                 } else {
1200                                         v = blobmsg_get_string(o);
1201                                 }
1202 
1203                                 if (!v)
1204                                         continue;
1205 
1206                                 if (!opt->elem_size)
1207                                 {
1208                                         if (!opt->parse((char *)s + opt->offset, v, false))
1209                                         {
1210                                                 fprintf(stderr, "%s: '%s' has invalid value '%s'\n",
1211                                                         name, opt->name, v);
1212                                                 valid = false;
1213                                         }
1214                                 }
1215                                 else
1216                                 {
1217                                         dest = (struct list_head *)((char *)s + opt->offset);
1218 
1219                                         for (p = strtok(v, " \t"); p != NULL; p = strtok(NULL, " \t"))
1220                                         {
1221                                                 if (!opt->parse(dest, p, true))
1222                                                 {
1223                                                         fprintf(stderr, "%s: '%s' has invalid value '%s'\n",
1224                                                                 name, opt->name, p);
1225                                                         valid = false;
1226                                                         continue;
1227                                                 }
1228                                         }
1229                                 }
1230                         }
1231 
1232                         known = true;
1233                         break;
1234                 }
1235 
1236                 if (!known && strcmp(blobmsg_name(o), "type"))
1237                         fprintf(stderr, "%s: '%s' is unknown\n", name, blobmsg_name(o));
1238         }
1239 
1240         return valid;
1241 }
1242 
1243 
1244 const char *
1245 fw3_address_to_string(struct fw3_address *address, bool allow_invert, bool as_cidr)
1246 {
1247         char *p, ip[INET6_ADDRSTRLEN];
1248         static char buf[INET6_ADDRSTRLEN * 2 + 2];
1249         size_t rem = sizeof(buf);
1250         int len;
1251 
1252         p = buf;
1253 
1254         if (address->invert && allow_invert) {
1255                 *p++ = '!';
1256                 *p = 0;
1257                 rem--;
1258         }
1259 
1260         inet_ntop(address->family == FW3_FAMILY_V4 ? AF_INET : AF_INET6,
1261                   &address->address.v4, ip, sizeof(ip));
1262 
1263         len = snprintf(p, rem, "%s", ip);
1264 
1265         if (len < 0 || len >= rem)
1266                 return buf;
1267 
1268         rem -= len;
1269         p += len;
1270 
1271         if (address->range)
1272         {
1273                 inet_ntop(address->family == FW3_FAMILY_V4 ? AF_INET : AF_INET6,
1274                           &address->mask.v4, ip, sizeof(ip));
1275 
1276                 snprintf(p, rem, "-%s", ip);
1277         }
1278         else if (!as_cidr)
1279         {
1280                 inet_ntop(address->family == FW3_FAMILY_V4 ? AF_INET : AF_INET6,
1281                           &address->mask.v4, ip, sizeof(ip));
1282 
1283                 snprintf(p, rem, "/%s", ip);
1284         }
1285         else
1286         {
1287                 snprintf(p, rem, "/%u",
1288                          fw3_netmask2bitlen(address->family, &address->mask.v6));
1289         }
1290 
1291         return buf;
1292 }
1293 

This page was automatically generated by LXR 0.3.1.  •  OpenWrt