use dup'ed string in fw3_parse_monthdays()
[project/firewall3.git] / options.c
1 /*
2 * firewall3 - 3rd OpenWrt UCI firewall implementation
3 *
4 * Copyright (C) 2013 Jo-Philipp Wich <jow@openwrt.org>
5 *
6 * Permission to use, copy, modify, and/or distribute this software for any
7 * purpose with or without fee is hereby granted, provided that the above
8 * copyright notice and this permission notice appear in all copies.
9 *
10 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17 */
18
19 #include "options.h"
20
21
22 static bool
23 parse_enum(void *ptr, const char *val, const char **values, int min, int max)
24 {
25 int i, l = strlen(val);
26
27 if (l > 0)
28 {
29 for (i = 0; i <= (max - min); i++)
30 {
31 if (!strncasecmp(val, values[i], l))
32 {
33 *((int *)ptr) = min + i;
34 return true;
35 }
36 }
37 }
38
39 return false;
40 }
41
42
43 const char *fw3_flag_names[FW3_DEFAULT_DROP_INVALID + 1] = {
44 "filter",
45 "nat",
46 "mangle",
47 "raw",
48
49 "IPv4",
50 "IPv6",
51
52 "ACCEPT",
53 "REJECT",
54 "DROP",
55 "NOTRACK",
56 "DNAT",
57 "SNAT",
58 };
59
60 static const char *limit_units[] = {
61 "second",
62 "minute",
63 "hour",
64 "day",
65 };
66
67 static const char *ipset_methods[] = {
68 "bitmap",
69 "hash",
70 "list",
71 };
72
73 static const char *ipset_types[] = {
74 "ip",
75 "port",
76 "mac",
77 "net",
78 "set",
79 };
80
81 static const char *weekdays[] = {
82 "monday",
83 "tuesday",
84 "wednesday",
85 "thursday",
86 "friday",
87 "saturday",
88 "sunday",
89 };
90
91 static const char *include_types[] = {
92 "script",
93 "restore",
94 };
95
96
97 bool
98 fw3_parse_bool(void *ptr, const char *val)
99 {
100 if (!strcmp(val, "true") || !strcmp(val, "yes") || !strcmp(val, "1"))
101 *((bool *)ptr) = true;
102 else
103 *((bool *)ptr) = false;
104
105 return true;
106 }
107
108 bool
109 fw3_parse_int(void *ptr, const char *val)
110 {
111 int n = strtol(val, NULL, 10);
112
113 if (errno == ERANGE || errno == EINVAL)
114 return false;
115
116 *((int *)ptr) = n;
117
118 return true;
119 }
120
121 bool
122 fw3_parse_string(void *ptr, const char *val)
123 {
124 *((char **)ptr) = (char *)val;
125 return true;
126 }
127
128 bool
129 fw3_parse_target(void *ptr, const char *val)
130 {
131 return parse_enum(ptr, val, &fw3_flag_names[FW3_TARGET_ACCEPT],
132 FW3_TARGET_ACCEPT, FW3_TARGET_SNAT);
133 }
134
135 bool
136 fw3_parse_limit(void *ptr, const char *val)
137 {
138 struct fw3_limit *limit = ptr;
139 enum fw3_limit_unit u = FW3_LIMIT_UNIT_SECOND;
140 char *e;
141 int n;
142
143 if (*val == '!')
144 {
145 limit->invert = true;
146 while (isspace(*++val));
147 }
148
149 n = strtol(val, &e, 10);
150
151 if (errno == ERANGE || errno == EINVAL)
152 return false;
153
154 if (*e && *e++ != '/')
155 return false;
156
157 if (!strlen(e))
158 return false;
159
160 if (!parse_enum(&u, e, limit_units, 0, FW3_LIMIT_UNIT_DAY))
161 return false;
162
163 limit->rate = n;
164 limit->unit = u;
165
166 return true;
167 }
168
169 bool
170 fw3_parse_device(void *ptr, const char *val)
171 {
172 struct fw3_device *dev = ptr;
173
174 if (*val == '*')
175 {
176 dev->set = true;
177 dev->any = true;
178 return true;
179 }
180
181 if (*val == '!')
182 {
183 dev->invert = true;
184 while (isspace(*++val));
185 }
186
187 if (*val)
188 snprintf(dev->name, sizeof(dev->name), "%s", val);
189 else
190 return false;
191
192 dev->set = true;
193 return true;
194 }
195
196 bool
197 fw3_parse_address(void *ptr, const char *val)
198 {
199 struct fw3_address *addr = ptr;
200 struct in_addr v4;
201 struct in6_addr v6;
202 char *p, *s, *e;
203 int i, m = -1;
204
205 if (*val == '!')
206 {
207 addr->invert = true;
208 while (isspace(*++val));
209 }
210
211 s = strdup(val);
212
213 if (!s)
214 return false;
215
216 if ((p = strchr(s, '/')) != NULL)
217 {
218 *p++ = 0;
219 m = strtoul(p, &e, 10);
220
221 if ((e == p) || (*e != 0))
222 {
223 if (strchr(s, ':') || !inet_pton(AF_INET, p, &v4))
224 {
225 free(s);
226 return false;
227 }
228
229 for (i = 0, m = 32; !(v4.s_addr & 1) && (i < 32); i++)
230 {
231 m--;
232 v4.s_addr >>= 1;
233 }
234 }
235 }
236 else if ((p = strchr(s, '-')) != NULL)
237 {
238 *p++ = 0;
239
240 if (inet_pton(AF_INET6, p, &v6))
241 {
242 addr->family = FW3_FAMILY_V6;
243 addr->address2.v6 = v6;
244 addr->range = true;
245 }
246 else if (inet_pton(AF_INET, p, &v4))
247 {
248 addr->family = FW3_FAMILY_V4;
249 addr->address2.v4 = v4;
250 addr->range = true;
251 }
252 else
253 {
254 free(s);
255 return false;
256 }
257 }
258
259 if (inet_pton(AF_INET6, s, &v6))
260 {
261 addr->family = FW3_FAMILY_V6;
262 addr->address.v6 = v6;
263 addr->mask = (m >= 0) ? m : 128;
264 }
265 else if (inet_pton(AF_INET, s, &v4))
266 {
267 addr->family = FW3_FAMILY_V4;
268 addr->address.v4 = v4;
269 addr->mask = (m >= 0) ? m : 32;
270 }
271 else
272 {
273 free(s);
274 return false;
275 }
276
277 free(s);
278 addr->set = true;
279 return true;
280 }
281
282 bool
283 fw3_parse_mac(void *ptr, const char *val)
284 {
285 struct fw3_mac *addr = ptr;
286 struct ether_addr *mac;
287
288 if (*val == '!')
289 {
290 addr->invert = true;
291 while (isspace(*++val));
292 }
293
294 if ((mac = ether_aton(val)) != NULL)
295 {
296 addr->mac = *mac;
297 addr->set = true;
298 return true;
299 }
300
301 return false;
302 }
303
304 bool
305 fw3_parse_port(void *ptr, const char *val)
306 {
307 struct fw3_port *range = ptr;
308 uint16_t n;
309 uint16_t m;
310 char *p;
311
312 if (*val == '!')
313 {
314 range->invert = true;
315 while (isspace(*++val));
316 }
317
318 n = strtoul(val, &p, 10);
319
320 if (errno == ERANGE || errno == EINVAL)
321 return false;
322
323 if (*p && *p != '-' && *p != ':')
324 return false;
325
326 if (*p)
327 {
328 m = strtoul(++p, NULL, 10);
329
330 if (errno == ERANGE || errno == EINVAL || m < n)
331 return false;
332
333 range->port_min = n;
334 range->port_max = m;
335 }
336 else
337 {
338 range->port_min = n;
339 range->port_max = n;
340 }
341
342 range->set = true;
343 return true;
344 }
345
346 bool
347 fw3_parse_family(void *ptr, const char *val)
348 {
349 if (!strcmp(val, "any"))
350 *((enum fw3_family *)ptr) = FW3_FAMILY_ANY;
351 else if (!strcmp(val, "inet") || strrchr(val, '4'))
352 *((enum fw3_family *)ptr) = FW3_FAMILY_V4;
353 else if (!strcmp(val, "inet6") || strrchr(val, '6'))
354 *((enum fw3_family *)ptr) = FW3_FAMILY_V6;
355 else
356 return false;
357
358 return true;
359 }
360
361 bool
362 fw3_parse_icmptype(void *ptr, const char *val)
363 {
364 struct fw3_icmptype *icmp = ptr;
365 bool v4 = false;
366 bool v6 = false;
367 char *p;
368 int i;
369
370 for (i = 0; i < ARRAY_SIZE(fw3_icmptype_list_v4); i++)
371 {
372 if (!strcmp(val, fw3_icmptype_list_v4[i].name))
373 {
374 icmp->type = fw3_icmptype_list_v4[i].type;
375 icmp->code_min = fw3_icmptype_list_v4[i].code_min;
376 icmp->code_max = fw3_icmptype_list_v4[i].code_max;
377
378 v4 = true;
379 break;
380 }
381 }
382
383 for (i = 0; i < ARRAY_SIZE(fw3_icmptype_list_v6); i++)
384 {
385 if (!strcmp(val, fw3_icmptype_list_v6[i].name))
386 {
387 icmp->type6 = fw3_icmptype_list_v6[i].type;
388 icmp->code6_min = fw3_icmptype_list_v6[i].code_min;
389 icmp->code6_max = fw3_icmptype_list_v6[i].code_max;
390
391 v6 = true;
392 break;
393 }
394 }
395
396 if (!v4 && !v6)
397 {
398 i = strtoul(val, &p, 10);
399
400 if ((p == val) || (*p != '/' && *p != 0) || (i > 0xFF))
401 return false;
402
403 icmp->type = i;
404
405 if (*p == '/')
406 {
407 val = ++p;
408 i = strtoul(val, &p, 10);
409
410 if ((p == val) || (*p != 0) || (i > 0xFF))
411 return false;
412
413 icmp->code_min = i;
414 icmp->code_max = i;
415 }
416 else
417 {
418 icmp->code_min = 0;
419 icmp->code_max = 0xFF;
420 }
421
422 icmp->type6 = icmp->type;
423 icmp->code6_min = icmp->code_max;
424 icmp->code6_max = icmp->code_max;
425
426 v4 = true;
427 v6 = true;
428 }
429
430 icmp->family = (v4 && v6) ? FW3_FAMILY_ANY
431 : (v6 ? FW3_FAMILY_V6 : FW3_FAMILY_V4);
432
433 return true;
434 }
435
436 bool
437 fw3_parse_protocol(void *ptr, const char *val)
438 {
439 struct fw3_protocol *proto = ptr;
440 struct protoent *ent;
441
442 if (*val == '!')
443 {
444 proto->invert = true;
445 while (isspace(*++val));
446 }
447
448 if (!strcmp(val, "all"))
449 {
450 proto->any = true;
451 return true;
452 }
453 else if (!strcmp(val, "icmpv6"))
454 {
455 val = "ipv6-icmp";
456 }
457
458 ent = getprotobyname(val);
459
460 if (ent)
461 {
462 proto->protocol = ent->p_proto;
463 return true;
464 }
465
466 proto->protocol = strtoul(val, NULL, 10);
467 return (errno != ERANGE && errno != EINVAL);
468 }
469
470 bool
471 fw3_parse_ipset_method(void *ptr, const char *val)
472 {
473 return parse_enum(ptr, val, ipset_methods,
474 FW3_IPSET_METHOD_BITMAP, FW3_IPSET_METHOD_LIST);
475 }
476
477 bool
478 fw3_parse_ipset_datatype(void *ptr, const char *val)
479 {
480 struct fw3_ipset_datatype *type = ptr;
481
482 if (!strncmp(val, "dest_", 5))
483 {
484 val += 5;
485 type->dest = true;
486 }
487 else if (!strncmp(val, "dst_", 4))
488 {
489 val += 4;
490 type->dest = true;
491 }
492 else if (!strncmp(val, "src_", 4))
493 {
494 val += 4;
495 type->dest = false;
496 }
497
498 return parse_enum(&type->type, val, ipset_types,
499 FW3_IPSET_TYPE_IP, FW3_IPSET_TYPE_SET);
500 }
501
502 bool
503 fw3_parse_date(void *ptr, const char *val)
504 {
505 unsigned int year = 1970, mon = 1, day = 1, hour = 0, min = 0, sec = 0;
506 struct tm tm = { 0 };
507 char *p;
508
509 year = strtoul(val, &p, 10);
510 if ((*p != '-' && *p) || year < 1970 || year > 2038)
511 goto fail;
512 else if (!*p)
513 goto ret;
514
515 mon = strtoul(++p, &p, 10);
516 if ((*p != '-' && *p) || mon > 12)
517 goto fail;
518 else if (!*p)
519 goto ret;
520
521 day = strtoul(++p, &p, 10);
522 if ((*p != 'T' && *p) || day > 31)
523 goto fail;
524 else if (!*p)
525 goto ret;
526
527 hour = strtoul(++p, &p, 10);
528 if ((*p != ':' && *p) || hour > 23)
529 goto fail;
530 else if (!*p)
531 goto ret;
532
533 min = strtoul(++p, &p, 10);
534 if ((*p != ':' && *p) || min > 59)
535 goto fail;
536 else if (!*p)
537 goto ret;
538
539 sec = strtoul(++p, &p, 10);
540 if (*p || sec > 59)
541 goto fail;
542
543 ret:
544 tm.tm_year = year - 1900;
545 tm.tm_mon = mon - 1;
546 tm.tm_mday = day;
547 tm.tm_hour = hour;
548 tm.tm_min = min;
549 tm.tm_sec = sec;
550
551 if (mktime(&tm) >= 0)
552 {
553 *((struct tm *)ptr) = tm;
554 return true;
555 }
556
557 fail:
558 return false;
559 }
560
561 bool
562 fw3_parse_time(void *ptr, const char *val)
563 {
564 unsigned int hour = 0, min = 0, sec = 0;
565 char *p;
566
567 hour = strtoul(val, &p, 10);
568 if (*p != ':' || hour > 23)
569 goto fail;
570
571 min = strtoul(++p, &p, 10);
572 if ((*p != ':' && *p) || min > 59)
573 goto fail;
574 else if (!*p)
575 goto ret;
576
577 sec = strtoul(++p, &p, 10);
578 if (*p || sec > 59)
579 goto fail;
580
581 ret:
582 *((int *)ptr) = 60 * 60 * hour + 60 * min + sec;
583 return true;
584
585 fail:
586 return false;
587 }
588
589 bool
590 fw3_parse_weekdays(void *ptr, const char *val)
591 {
592 unsigned int w = 0;
593 char *p, *s;
594
595 if (*val == '!')
596 {
597 setbit(*(uint8_t *)ptr, 0);
598 while (isspace(*++val));
599 }
600
601 if (!(s = strdup(val)))
602 return false;
603
604 for (p = strtok(s, " \t"); p; p = strtok(NULL, " \t"))
605 {
606 if (!parse_enum(&w, p, weekdays, 1, 7))
607 {
608 w = strtoul(p, &p, 10);
609
610 if (*p || w < 1 || w > 7)
611 {
612 free(s);
613 return false;
614 }
615 }
616
617 setbit(*(uint8_t *)ptr, w);
618 }
619
620 free(s);
621 return true;
622 }
623
624 bool
625 fw3_parse_monthdays(void *ptr, const char *val)
626 {
627 unsigned int d;
628 char *p, *s;
629
630 if (*val == '!')
631 {
632 setbit(*(uint32_t *)ptr, 0);
633 while (isspace(*++val));
634 }
635
636 if (!(s = strdup(val)))
637 return false;
638
639 for (p = strtok(s, " \t"); p; p = strtok(NULL, " \t"))
640 {
641 d = strtoul(p, &p, 10);
642
643 if (*p || d < 1 || d > 31)
644 {
645 free(s);
646 return false;
647 }
648
649 setbit(*(uint32_t *)ptr, d);
650 }
651
652 free(s);
653 return true;
654 }
655
656 bool
657 fw3_parse_include_type(void *ptr, const char *val)
658 {
659 return parse_enum(ptr, val, include_types,
660 FW3_INC_TYPE_SCRIPT, FW3_INC_TYPE_RESTORE);
661 }
662
663
664 void
665 fw3_parse_options(void *s, const struct fw3_option *opts,
666 struct uci_section *section)
667 {
668 char *p;
669 bool known;
670 struct uci_element *e, *l;
671 struct uci_option *o;
672 const struct fw3_option *opt;
673 struct list_head *item;
674 struct list_head *dest;
675
676 uci_foreach_element(&section->options, e)
677 {
678 o = uci_to_option(e);
679 known = false;
680
681 for (opt = opts; opt->name; opt++)
682 {
683 if (!opt->parse)
684 continue;
685
686 if (strcmp(opt->name, e->name))
687 continue;
688
689 if (o->type == UCI_TYPE_LIST)
690 {
691 if (!opt->elem_size)
692 {
693 warn_elem(e, "must not be a list");
694 }
695 else
696 {
697 uci_foreach_element(&o->v.list, l)
698 {
699 if (!l->name)
700 continue;
701
702 item = malloc(opt->elem_size);
703
704 if (!item)
705 continue;
706
707 memset(item, 0, opt->elem_size);
708
709 if (!opt->parse(item, l->name))
710 {
711 warn_elem(e, "has invalid value '%s'", l->name);
712 free(item);
713 continue;
714 }
715
716 dest = (struct list_head *)((char *)s + opt->offset);
717 list_add_tail(item, dest);
718 }
719 }
720 }
721 else
722 {
723 if (!o->v.string)
724 continue;
725
726 if (!opt->elem_size)
727 {
728 if (!opt->parse((char *)s + opt->offset, o->v.string))
729 warn_elem(e, "has invalid value '%s'", o->v.string);
730 }
731 else
732 {
733 for (p = strtok(o->v.string, " \t");
734 p != NULL;
735 p = strtok(NULL, " \t"))
736 {
737 item = malloc(opt->elem_size);
738
739 if (!item)
740 continue;
741
742 memset(item, 0, opt->elem_size);
743
744 if (!opt->parse(item, p))
745 {
746 warn_elem(e, "has invalid value '%s'", p);
747 free(item);
748 continue;
749 }
750
751 dest = (struct list_head *)((char *)s + opt->offset);
752 list_add_tail(item, dest);
753 }
754 }
755 }
756
757 known = true;
758 break;
759 }
760
761 if (!known)
762 warn_elem(e, "is unknown");
763 }
764 }
765
766
767 void
768 fw3_format_in_out(struct fw3_device *in, struct fw3_device *out)
769 {
770 if (in && !in->any)
771 fw3_pr(" %s-i %s", in->invert ? "! " : "", in->name);
772
773 if (out && !out->any)
774 fw3_pr(" %s-o %s", out->invert ? "! " : "", out->name);
775 }
776
777 void
778 fw3_format_src_dest(struct fw3_address *src, struct fw3_address *dest)
779 {
780 char s[INET6_ADDRSTRLEN];
781
782 if ((src && src->range) || (dest && dest->range))
783 fw3_pr(" -m iprange");
784
785 if (src && src->set)
786 {
787 if (src->range)
788 {
789 inet_ntop(src->family == FW3_FAMILY_V4 ? AF_INET : AF_INET6,
790 &src->address.v4, s, sizeof(s));
791
792 fw3_pr(" %s--src-range %s", src->invert ? "! " : "", s);
793
794 inet_ntop(src->family == FW3_FAMILY_V4 ? AF_INET : AF_INET6,
795 &src->address2.v4, s, sizeof(s));
796
797 fw3_pr("-%s", s);
798 }
799 else
800 {
801 inet_ntop(src->family == FW3_FAMILY_V4 ? AF_INET : AF_INET6,
802 &src->address.v4, s, sizeof(s));
803
804 fw3_pr(" %s-s %s/%u", src->invert ? "! " : "", s, src->mask);
805 }
806 }
807
808 if (dest && dest->set)
809 {
810 if (dest->range)
811 {
812 inet_ntop(dest->family == FW3_FAMILY_V4 ? AF_INET : AF_INET6,
813 &dest->address.v4, s, sizeof(s));
814
815 fw3_pr(" %s--dst-range %s", dest->invert ? "! " : "", s);
816
817 inet_ntop(dest->family == FW3_FAMILY_V4 ? AF_INET : AF_INET6,
818 &dest->address2.v4, s, sizeof(s));
819
820 fw3_pr("-%s", s);
821 }
822 else
823 {
824 inet_ntop(dest->family == FW3_FAMILY_V4 ? AF_INET : AF_INET6,
825 &dest->address.v4, s, sizeof(s));
826
827 fw3_pr(" %s-d %s/%u", dest->invert ? "! " : "", s, dest->mask);
828 }
829 }
830 }
831
832 void
833 fw3_format_sport_dport(struct fw3_port *sp, struct fw3_port *dp)
834 {
835 if (sp && sp->set)
836 {
837 if (sp->port_min == sp->port_max)
838 fw3_pr(" %s--sport %u", sp->invert ? "! " : "", sp->port_min);
839 else
840 fw3_pr(" %s--sport %u:%u",
841 sp->invert ? "! " : "", sp->port_min, sp->port_max);
842 }
843
844 if (dp && dp->set)
845 {
846 if (dp->port_min == dp->port_max)
847 fw3_pr(" %s--dport %u", dp->invert ? "! " : "", dp->port_min);
848 else
849 fw3_pr(" %s--dport %u:%u",
850 dp->invert ? "! " : "", dp->port_min, dp->port_max);
851 }
852 }
853
854 void
855 fw3_format_mac(struct fw3_mac *mac)
856 {
857 if (!mac)
858 return;
859
860 fw3_pr(" -m mac %s--mac-source %s",
861 mac->invert ? "! " : "", ether_ntoa(&mac->mac));
862 }
863
864 void
865 fw3_format_protocol(struct fw3_protocol *proto, enum fw3_family family)
866 {
867 uint16_t pr;
868
869 if (!proto)
870 return;
871
872 pr = proto->protocol;
873
874 if (pr == 1 && family == FW3_FAMILY_V6)
875 pr = 58;
876
877 if (proto->any)
878 fw3_pr(" -p all");
879 else
880 fw3_pr(" %s-p %u", proto->invert ? "! " : "", pr);
881 }
882
883 void
884 fw3_format_icmptype(struct fw3_icmptype *icmp, enum fw3_family family)
885 {
886 if (!icmp)
887 return;
888
889 if (family != FW3_FAMILY_V6)
890 {
891 if (icmp->code_min == 0 && icmp->code_max == 0xFF)
892 fw3_pr(" %s--icmp-type %u", icmp->invert ? "! " : "", icmp->type);
893 else
894 fw3_pr(" %s--icmp-type %u/%u",
895 icmp->invert ? "! " : "", icmp->type, icmp->code_min);
896 }
897 else
898 {
899 if (icmp->code6_min == 0 && icmp->code6_max == 0xFF)
900 fw3_pr(" %s--icmpv6-type %u", icmp->invert ? "! " : "", icmp->type6);
901 else
902 fw3_pr(" %s--icmpv6-type %u/%u",
903 icmp->invert ? "! " : "", icmp->type6, icmp->code6_min);
904 }
905 }
906
907 void
908 fw3_format_limit(struct fw3_limit *limit)
909 {
910 if (!limit)
911 return;
912
913 if (limit->rate > 0)
914 {
915 fw3_pr(" -m limit %s--limit %u/%s",
916 limit->invert ? "! " : "",
917 limit->rate, limit_units[limit->unit]);
918
919 if (limit->burst > 0)
920 fw3_pr(" --limit-burst %u", limit->burst);
921 }
922 }
923
924 void
925 fw3_format_ipset(struct fw3_ipset *ipset, bool invert)
926 {
927 bool first = true;
928 const char *name = NULL;
929 struct fw3_ipset_datatype *type;
930
931 if (!ipset)
932 return;
933
934 if (ipset->external && *ipset->external)
935 name = ipset->external;
936 else
937 name = ipset->name;
938
939 fw3_pr(" -m set %s--match-set %s", invert ? "! " : "", name);
940
941 list_for_each_entry(type, &ipset->datatypes, list)
942 {
943 fw3_pr("%c%s", first ? ' ' : ',', type->dest ? "dst" : "src");
944 first = false;
945 }
946 }
947
948 void
949 fw3_format_time(struct fw3_time *time)
950 {
951 int i;
952 struct tm empty = { 0 };
953 char buf[sizeof("9999-99-99T23:59:59\0")];
954 bool d1 = memcmp(&time->datestart, &empty, sizeof(empty));
955 bool d2 = memcmp(&time->datestop, &empty, sizeof(empty));
956 bool first;
957
958 if (!d1 && !d2 && !time->timestart && !time->timestop &&
959 !(time->monthdays & 0xFFFFFFFE) && !(time->weekdays & 0xFE))
960 {
961 return;
962 }
963
964 fw3_pr(" -m time");
965
966 if (time->utc)
967 fw3_pr(" --utc");
968
969 if (d1)
970 {
971 strftime(buf, sizeof(buf), "%Y-%m-%dT%H:%M:%S", &time->datestart);
972 fw3_pr(" --datestart %s", buf);
973 }
974
975 if (d2)
976 {
977 strftime(buf, sizeof(buf), "%Y-%m-%dT%H:%M:%S", &time->datestop);
978 fw3_pr(" --datestop %s", buf);
979 }
980
981 if (time->timestart)
982 {
983 fw3_pr(" --timestart %02d:%02d:%02d",
984 time->timestart / 3600,
985 time->timestart % 3600 / 60,
986 time->timestart % 60);
987 }
988
989 if (time->timestop)
990 {
991 fw3_pr(" --timestop %02d:%02d:%02d",
992 time->timestop / 3600,
993 time->timestop % 3600 / 60,
994 time->timestop % 60);
995 }
996
997 if (time->monthdays & 0xFFFFFFFE)
998 {
999 fw3_pr(" %s--monthdays", hasbit(time->monthdays, 0) ? "! " : "");
1000
1001 for (i = 1, first = true; i < 32; i++)
1002 {
1003 if (hasbit(time->monthdays, i))
1004 {
1005 fw3_pr("%c%u", first ? ' ' : ',', i);
1006 first = false;
1007 }
1008 }
1009 }
1010
1011 if (time->weekdays & 0xFE)
1012 {
1013 fw3_pr(" %s--weekdays", hasbit(time->weekdays, 0) ? "! " : "");
1014
1015 for (i = 1, first = true; i < 8; i++)
1016 {
1017 if (hasbit(time->weekdays, i))
1018 {
1019 fw3_pr("%c%u", first ? ' ' : ',', i);
1020 first = false;
1021 }
1022 }
1023 }
1024 }
1025
1026 void
1027 __fw3_format_comment(const char *comment, ...)
1028 {
1029 va_list ap;
1030 int len = 0;
1031 const char *c;
1032
1033 if (!comment || !*comment)
1034 return;
1035
1036 fw3_pr(" -m comment --comment \"");
1037
1038 c = comment;
1039
1040 va_start(ap, comment);
1041
1042 do
1043 {
1044 while (*c)
1045 {
1046 switch (*c)
1047 {
1048 case '"':
1049 case '$':
1050 case '`':
1051 case '\\':
1052 fw3_pr("\\");
1053 /* fall through */
1054
1055 default:
1056 fw3_pr("%c", *c);
1057 break;
1058 }
1059
1060 c++;
1061
1062 if (len++ >= 255)
1063 goto end;
1064 }
1065
1066 c = va_arg(ap, const char *);
1067 }
1068 while (c);
1069
1070 end:
1071 va_end(ap);
1072 fw3_pr("\"");
1073 }
1074
1075 void
1076 fw3_format_extra(const char *extra)
1077 {
1078 if (!extra || !*extra)
1079 return;
1080
1081 fw3_pr(" %s", extra);
1082 }