1 /*
2 * (C) 2000-2006 by the netfilter coreteam <[email protected]>:
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; either version 2 of the License, or
7 * (at your option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write to the Free Software
16 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17 */
18 #include "config.h"
19 #include <ctype.h>
20 #include <errno.h>
21 #include <fcntl.h>
22 #include <inttypes.h>
23 #include <netdb.h>
24 #include <spawn.h>
25 #include <stdarg.h>
26 #include <stdbool.h>
27 #include <stdio.h>
28 #include <stdlib.h>
29 #include <string.h>
30 #include <unistd.h>
31 #include <netinet/ether.h>
32 #include <sys/socket.h>
33 #include <sys/stat.h>
34 #include <sys/statfs.h>
35 #include <sys/types.h>
36 #include <sys/utsname.h>
37 #include <sys/wait.h>
38 #include <arpa/inet.h>
39 #if defined(HAVE_LINUX_MAGIC_H)
40 # include <linux/magic.h> /* for PROC_SUPER_MAGIC */
41 #elif defined(HAVE_LINUX_PROC_FS_H)
42 # include <linux/proc_fs.h> /* Linux 2.4 */
43 #else
44 # define PROC_SUPER_MAGIC 0x9fa0
45 #endif
46
47 #include <xtables.h>
48 #include <limits.h> /* INT_MAX in ip_tables.h/ip6_tables.h */
49 #include <linux/netfilter_ipv4/ip_tables.h>
50 #include <linux/netfilter_ipv6/ip6_tables.h>
51 #include <libiptc/libxtc.h>
52 #include <libiptc/linux_list.h>
53
54 #ifndef NO_SHARED_LIBS
55 #include <dlfcn.h>
56 #endif
57 #ifndef IPT_SO_GET_REVISION_MATCH /* Old kernel source. */
58 # define IPT_SO_GET_REVISION_MATCH (IPT_BASE_CTL + 2)
59 # define IPT_SO_GET_REVISION_TARGET (IPT_BASE_CTL + 3)
60 #endif
61 #ifndef IP6T_SO_GET_REVISION_MATCH /* Old kernel source. */
62 # define IP6T_SO_GET_REVISION_MATCH 68
63 # define IP6T_SO_GET_REVISION_TARGET 69
64 #endif
65 #include <getopt.h>
66 #include "iptables/internal.h"
67
68 #define NPROTO 255
69
70 #ifndef PROC_SYS_MODPROBE
71 #define PROC_SYS_MODPROBE "/proc/sys/kernel/modprobe"
72 #endif
73
74 #ifndef ETH_ALEN
75 #define ETH_ALEN 6
76 #endif
77
78 /* we need this for ip6?tables-restore. ip6?tables-restore.c sets line to the
79 * current line of the input file, in order to give a more precise error
80 * message. ip6?tables itself doesn't need this, so it is initialized to the
81 * magic number of -1 */
82 int line = -1;
83
84 void basic_exit_err(enum xtables_exittype status, const char *msg, ...) __attribute__((noreturn, format(printf,2,3)));
85
86 struct xtables_globals *xt_params = NULL;
87
basic_exit_err(enum xtables_exittype status,const char * msg,...)88 void basic_exit_err(enum xtables_exittype status, const char *msg, ...)
89 {
90 va_list args;
91
92 va_start(args, msg);
93 fprintf(stderr, "%s v%s: ", xt_params->program_name, xt_params->program_version);
94 vfprintf(stderr, msg, args);
95 va_end(args);
96 fprintf(stderr, "\n");
97 if (status == PARAMETER_PROBLEM) {
98 if (line != -1)
99 fprintf(stderr, "Error occurred at line: %d\n", line);
100 fprintf(stderr, "Try `%s -h' or '%s --help' for more information.\n",
101 xt_params->program_name, xt_params->program_name);
102 } else if (status == VERSION_PROBLEM) {
103 fprintf(stderr,
104 "Perhaps %s or your kernel needs to be upgraded.\n",
105 xt_params->program_name);
106 }
107 /* On error paths, make sure that we don't leak memory */
108 xtables_free_opts(1);
109 exit(status);
110 }
111
xtables_free_opts(int unused)112 void xtables_free_opts(int unused)
113 {
114 if (xt_params->opts != xt_params->orig_opts) {
115 free(xt_params->opts);
116 xt_params->opts = NULL;
117 }
118 }
119
xtables_merge_options(struct option * orig_opts,struct option * oldopts,const struct option * newopts,unsigned int * option_offset)120 struct option *xtables_merge_options(struct option *orig_opts,
121 struct option *oldopts,
122 const struct option *newopts,
123 unsigned int *option_offset)
124 {
125 unsigned int num_oold = 0, num_old = 0, num_new = 0, i;
126 struct option *merge, *mp;
127
128 if (newopts == NULL)
129 return oldopts;
130
131 for (num_oold = 0; orig_opts[num_oold].name; num_oold++) ;
132 if (oldopts != NULL)
133 for (num_old = 0; oldopts[num_old].name; num_old++) ;
134 for (num_new = 0; newopts[num_new].name; num_new++) ;
135
136 /*
137 * Since @oldopts also has @orig_opts already (and does so at the
138 * start), skip these entries.
139 */
140 if (oldopts != NULL) {
141 oldopts += num_oold;
142 num_old -= num_oold;
143 }
144
145 merge = malloc(sizeof(*mp) * (num_oold + num_old + num_new + 1));
146 if (merge == NULL)
147 return NULL;
148
149 /* Let the base options -[ADI...] have precedence over everything */
150 memcpy(merge, orig_opts, sizeof(*mp) * num_oold);
151 mp = merge + num_oold;
152
153 /* Second, the new options */
154 xt_params->option_offset += XT_OPTION_OFFSET_SCALE;
155 *option_offset = xt_params->option_offset;
156 memcpy(mp, newopts, sizeof(*mp) * num_new);
157
158 for (i = 0; i < num_new; ++i, ++mp)
159 mp->val += *option_offset;
160
161 /* Third, the old options */
162 if (oldopts != NULL) {
163 memcpy(mp, oldopts, sizeof(*mp) * num_old);
164 mp += num_old;
165 }
166 xtables_free_opts(0);
167
168 /* Clear trailing entry */
169 memset(mp, 0, sizeof(*mp));
170 return merge;
171 }
172
173 static const struct xtables_afinfo afinfo_ipv4 = {
174 .kmod = "ip_tables",
175 .proc_exists = "/proc/net/ip_tables_names",
176 .libprefix = "libipt_",
177 .family = NFPROTO_IPV4,
178 .ipproto = IPPROTO_IP,
179 .so_rev_match = IPT_SO_GET_REVISION_MATCH,
180 .so_rev_target = IPT_SO_GET_REVISION_TARGET,
181 };
182
183 static const struct xtables_afinfo afinfo_ipv6 = {
184 .kmod = "ip6_tables",
185 .proc_exists = "/proc/net/ip6_tables_names",
186 .libprefix = "libip6t_",
187 .family = NFPROTO_IPV6,
188 .ipproto = IPPROTO_IPV6,
189 .so_rev_match = IP6T_SO_GET_REVISION_MATCH,
190 .so_rev_target = IP6T_SO_GET_REVISION_TARGET,
191 };
192
193 /* Dummy families for arptables-compat and ebtables-compat. Leave structure
194 * fields that we don't use unset.
195 */
196 static const struct xtables_afinfo afinfo_bridge = {
197 .libprefix = "libebt_",
198 .family = NFPROTO_BRIDGE,
199 };
200
201 static const struct xtables_afinfo afinfo_arp = {
202 .libprefix = "libarpt_",
203 .family = NFPROTO_ARP,
204 };
205
206 const struct xtables_afinfo *afinfo;
207
208 /* Search path for Xtables .so files */
209 static const char *xtables_libdir;
210
211 /* the path to command to load kernel module */
212 const char *xtables_modprobe_program;
213
214 /* Keep track of matches/targets pending full registration: linked lists. */
215 struct xtables_match *xtables_pending_matches;
216 struct xtables_target *xtables_pending_targets;
217
218 /* Keep track of fully registered external matches/targets: linked lists. */
219 struct xtables_match *xtables_matches;
220 struct xtables_target *xtables_targets;
221
222 /* Fully register a match/target which was previously partially registered. */
223 static bool xtables_fully_register_pending_match(struct xtables_match *me,
224 struct xtables_match *prev);
225 static bool xtables_fully_register_pending_target(struct xtables_target *me,
226 struct xtables_target *prev);
227
228 #ifndef NO_SHARED_LIBS
229 /* registry for loaded shared objects to close later */
230 struct dlreg {
231 struct dlreg *next;
232 void *handle;
233 };
234 static struct dlreg *dlreg = NULL;
235
dlreg_add(void * handle)236 static int dlreg_add(void *handle)
237 {
238 struct dlreg *new = malloc(sizeof(*new));
239
240 if (!new)
241 return -1;
242
243 new->handle = handle;
244 new->next = dlreg;
245 dlreg = new;
246 return 0;
247 }
248
dlreg_free(void)249 static void dlreg_free(void)
250 {
251 struct dlreg *next;
252
253 while (dlreg) {
254 next = dlreg->next;
255 dlclose(dlreg->handle);
256 free(dlreg);
257 dlreg = next;
258 }
259 }
260 #endif
261
262 struct notarget {
263 struct hlist_node node;
264 char name[];
265 };
266
267 #define NOTARGET_HSIZE 512
268 static struct hlist_head notargets[NOTARGET_HSIZE];
269
notargets_hlist_init(void)270 static void notargets_hlist_init(void)
271 {
272 int i;
273
274 for (i = 0; i < NOTARGET_HSIZE; i++)
275 INIT_HLIST_HEAD(¬argets[i]);
276 }
277
notargets_hlist_free(void)278 static void notargets_hlist_free(void)
279 {
280 struct hlist_node *pos, *n;
281 struct notarget *cur;
282 int i;
283
284 for (i = 0; i < NOTARGET_HSIZE; i++) {
285 hlist_for_each_entry_safe(cur, pos, n, ¬argets[i], node) {
286 hlist_del(&cur->node);
287 free(cur);
288 }
289 }
290 }
291
djb_hash(const char * key)292 static uint32_t djb_hash(const char *key)
293 {
294 uint32_t i, hash = 5381;
295
296 for (i = 0; i < strlen(key); i++)
297 hash = ((hash << 5) + hash) + key[i];
298
299 return hash;
300 }
301
notargets_hlist_lookup(const char * name)302 static struct notarget *notargets_hlist_lookup(const char *name)
303 {
304 uint32_t key = djb_hash(name) % NOTARGET_HSIZE;
305 struct hlist_node *node;
306 struct notarget *cur;
307
308 hlist_for_each_entry(cur, node, ¬argets[key], node) {
309 if (!strcmp(name, cur->name))
310 return cur;
311 }
312 return NULL;
313 }
314
notargets_hlist_insert(const char * name)315 static void notargets_hlist_insert(const char *name)
316 {
317 struct notarget *cur;
318
319 if (!name)
320 return;
321
322 cur = xtables_malloc(sizeof(*cur) + strlen(name) + 1);
323 strcpy(cur->name, name);
324 hlist_add_head(&cur->node, ¬argets[djb_hash(name) % NOTARGET_HSIZE]);
325 }
326
xtables_announce_chain(const char * name)327 void xtables_announce_chain(const char *name)
328 {
329 if (!notargets_hlist_lookup(name))
330 notargets_hlist_insert(name);
331 }
332
xtables_init(void)333 void xtables_init(void)
334 {
335 /* xtables cannot be used with setuid in a safe way. */
336 if (getuid() != geteuid())
337 _exit(111);
338
339 xtables_libdir = getenv("XTABLES_LIBDIR");
340 if (xtables_libdir != NULL)
341 return;
342 xtables_libdir = getenv("IPTABLES_LIB_DIR");
343 if (xtables_libdir != NULL) {
344 fprintf(stderr, "IPTABLES_LIB_DIR is deprecated, "
345 "use XTABLES_LIBDIR.\n");
346 return;
347 }
348 /*
349 * Well yes, IP6TABLES_LIB_DIR is of lower priority over
350 * IPTABLES_LIB_DIR since this moved to libxtables; I think that is ok
351 * for these env vars are deprecated anyhow, and in light of the
352 * (shared) libxt_*.so files, makes less sense to have
353 * IPTABLES_LIB_DIR != IP6TABLES_LIB_DIR.
354 */
355 xtables_libdir = getenv("IP6TABLES_LIB_DIR");
356 if (xtables_libdir != NULL) {
357 fprintf(stderr, "IP6TABLES_LIB_DIR is deprecated, "
358 "use XTABLES_LIBDIR.\n");
359 return;
360 }
361 xtables_libdir = XTABLES_LIBDIR;
362
363 notargets_hlist_init();
364 }
365
xtables_fini(void)366 void xtables_fini(void)
367 {
368 #ifndef NO_SHARED_LIBS
369 dlreg_free();
370 #endif
371 notargets_hlist_free();
372 }
373
xtables_set_nfproto(uint8_t nfproto)374 void xtables_set_nfproto(uint8_t nfproto)
375 {
376 switch (nfproto) {
377 case NFPROTO_IPV4:
378 afinfo = &afinfo_ipv4;
379 break;
380 case NFPROTO_IPV6:
381 afinfo = &afinfo_ipv6;
382 break;
383 case NFPROTO_BRIDGE:
384 afinfo = &afinfo_bridge;
385 break;
386 case NFPROTO_ARP:
387 afinfo = &afinfo_arp;
388 break;
389 default:
390 fprintf(stderr, "libxtables: unhandled NFPROTO in %s\n",
391 __func__);
392 }
393 }
394
395 /**
396 * xtables_set_params - set the global parameters used by xtables
397 * @xtp: input xtables_globals structure
398 *
399 * The app is expected to pass a valid xtables_globals data-filled
400 * with proper values
401 * @xtp cannot be NULL
402 *
403 * Returns -1 on failure to set and 0 on success
404 */
xtables_set_params(struct xtables_globals * xtp)405 int xtables_set_params(struct xtables_globals *xtp)
406 {
407 if (!xtp) {
408 fprintf(stderr, "%s: Illegal global params\n",__func__);
409 return -1;
410 }
411
412 xt_params = xtp;
413
414 if (!xt_params->exit_err)
415 xt_params->exit_err = basic_exit_err;
416
417 return 0;
418 }
419
xtables_init_all(struct xtables_globals * xtp,uint8_t nfproto)420 int xtables_init_all(struct xtables_globals *xtp, uint8_t nfproto)
421 {
422 xtables_init();
423 xtables_set_nfproto(nfproto);
424 return xtables_set_params(xtp);
425 }
426
427 /**
428 * xtables_*alloc - wrappers that exit on failure
429 */
xtables_calloc(size_t count,size_t size)430 void *xtables_calloc(size_t count, size_t size)
431 {
432 void *p;
433
434 if ((p = calloc(count, size)) == NULL) {
435 perror("ip[6]tables: calloc failed");
436 exit(1);
437 }
438
439 return p;
440 }
441
xtables_malloc(size_t size)442 void *xtables_malloc(size_t size)
443 {
444 void *p;
445
446 if ((p = malloc(size)) == NULL) {
447 perror("ip[6]tables: malloc failed");
448 exit(1);
449 }
450
451 return p;
452 }
453
xtables_realloc(void * ptr,size_t size)454 void *xtables_realloc(void *ptr, size_t size)
455 {
456 void *p;
457
458 if ((p = realloc(ptr, size)) == NULL) {
459 perror("ip[6]tables: realloc failed");
460 exit(1);
461 }
462
463 return p;
464 }
465
xtables_strdup(const char * s)466 char *xtables_strdup(const char *s)
467 {
468 char *dup = strdup(s);
469
470 if (!dup) {
471 perror("ip[6]tables: strdup failed");
472 exit(1);
473 }
474
475 return dup;
476 }
477
get_modprobe(void)478 static char *get_modprobe(void)
479 {
480 int procfile;
481 char *ret;
482 int count;
483
484 procfile = open(PROC_SYS_MODPROBE, O_RDONLY | O_CLOEXEC);
485 if (procfile < 0)
486 return NULL;
487
488 ret = malloc(PATH_MAX);
489 if (ret) {
490 count = read(procfile, ret, PATH_MAX);
491 if (count > 0 && count < PATH_MAX)
492 {
493 if (ret[count - 1] == '\n')
494 ret[count - 1] = '\0';
495 else
496 ret[count] = '\0';
497 close(procfile);
498 return ret;
499 }
500 }
501 free(ret);
502 close(procfile);
503 return NULL;
504 }
505
xtables_insmod(const char * modname,const char * modprobe,bool quiet)506 int xtables_insmod(const char *modname, const char *modprobe, bool quiet)
507 {
508 char *buf = NULL;
509 char *argv[4];
510 int status;
511 pid_t pid;
512
513 /* If they don't explicitly set it, read out of kernel */
514 if (!modprobe) {
515 buf = get_modprobe();
516 if (!buf)
517 return -1;
518 modprobe = buf;
519 }
520
521 argv[0] = (char *)modprobe;
522 argv[1] = (char *)modname;
523 argv[2] = quiet ? "-q" : NULL;
524 argv[3] = NULL;
525
526 /*
527 * Need to flush the buffer, or the child may output it again
528 * when switching the program thru execv.
529 */
530 fflush(stdout);
531
532 if (posix_spawn(&pid, argv[0], NULL, NULL, argv, NULL)) {
533 free(buf);
534 return -1;
535 } else {
536 waitpid(pid, &status, 0);
537 }
538
539 free(buf);
540 if (WIFEXITED(status) && WEXITSTATUS(status) == 0)
541 return 0;
542 return -1;
543 }
544
545 /* return true if a given file exists within procfs */
proc_file_exists(const char * filename)546 static bool proc_file_exists(const char *filename)
547 {
548 struct stat s;
549 struct statfs f;
550
551 if (lstat(filename, &s))
552 return false;
553 if (!S_ISREG(s.st_mode))
554 return false;
555 if (statfs(filename, &f))
556 return false;
557 if (f.f_type != PROC_SUPER_MAGIC)
558 return false;
559 return true;
560 }
561
xtables_load_ko(const char * modprobe,bool quiet)562 int xtables_load_ko(const char *modprobe, bool quiet)
563 {
564 static bool loaded = false;
565 int ret;
566
567 if (loaded)
568 return 0;
569
570 if (proc_file_exists(afinfo->proc_exists)) {
571 loaded = true;
572 return 0;
573 };
574
575 ret = xtables_insmod(afinfo->kmod, modprobe, quiet);
576 if (ret == 0)
577 loaded = true;
578
579 return ret;
580 }
581
582 /**
583 * xtables_strtou{i,l} - string to number conversion
584 * @s: input string
585 * @end: like strtoul's "end" pointer
586 * @value: pointer for result
587 * @min: minimum accepted value
588 * @max: maximum accepted value
589 *
590 * If @end is NULL, we assume the caller wants a "strict strtoul", and hence
591 * "15a" is rejected.
592 * In either case, the value obtained is compared for min-max compliance.
593 * Base is always 0, i.e. autodetect depending on @s.
594 *
595 * Returns true/false whether number was accepted. On failure, *value has
596 * undefined contents.
597 */
xtables_strtoul(const char * s,char ** end,uintmax_t * value,uintmax_t min,uintmax_t max)598 bool xtables_strtoul(const char *s, char **end, uintmax_t *value,
599 uintmax_t min, uintmax_t max)
600 {
601 uintmax_t v;
602 const char *p;
603 char *my_end;
604
605 errno = 0;
606 /* Since strtoul allows leading minus, we have to check for ourself. */
607 for (p = s; isspace(*p); ++p)
608 ;
609 if (*p == '-')
610 return false;
611 v = strtoumax(s, &my_end, 0);
612 if (my_end == s)
613 return false;
614 if (end != NULL)
615 *end = my_end;
616
617 if (errno != ERANGE && min <= v && (max == 0 || v <= max)) {
618 if (value != NULL)
619 *value = v;
620 if (end == NULL)
621 return *my_end == '\0';
622 return true;
623 }
624
625 return false;
626 }
627
xtables_strtoui(const char * s,char ** end,unsigned int * value,unsigned int min,unsigned int max)628 bool xtables_strtoui(const char *s, char **end, unsigned int *value,
629 unsigned int min, unsigned int max)
630 {
631 uintmax_t v;
632 bool ret;
633
634 ret = xtables_strtoul(s, end, &v, min, max);
635 if (ret && value != NULL)
636 *value = v;
637 return ret;
638 }
639
xtables_service_to_port(const char * name,const char * proto)640 int xtables_service_to_port(const char *name, const char *proto)
641 {
642 struct servent *service;
643
644 if ((service = getservbyname(name, proto)) != NULL)
645 return ntohs((unsigned short) service->s_port);
646
647 return -1;
648 }
649
xtables_parse_port(const char * port,const char * proto)650 uint16_t xtables_parse_port(const char *port, const char *proto)
651 {
652 unsigned int portnum;
653
654 if (xtables_strtoui(port, NULL, &portnum, 0, UINT16_MAX) ||
655 (portnum = xtables_service_to_port(port, proto)) != (unsigned)-1)
656 return portnum;
657
658 xt_params->exit_err(PARAMETER_PROBLEM,
659 "invalid port/service `%s' specified", port);
660 }
661
xtables_parse_interface(const char * arg,char * vianame,unsigned char * mask)662 void xtables_parse_interface(const char *arg, char *vianame,
663 unsigned char *mask)
664 {
665 unsigned int vialen = strlen(arg);
666 unsigned int i;
667
668 memset(mask, 0, IFNAMSIZ);
669 memset(vianame, 0, IFNAMSIZ);
670
671 if (vialen + 1 > IFNAMSIZ)
672 xt_params->exit_err(PARAMETER_PROBLEM,
673 "interface name `%s' must be shorter than IFNAMSIZ"
674 " (%i)", arg, IFNAMSIZ-1);
675
676 strcpy(vianame, arg);
677 if (vialen == 0)
678 return;
679 else if (vianame[vialen - 1] == '+') {
680 memset(mask, 0xFF, vialen - 1);
681 /* Don't remove `+' here! -HW */
682 } else {
683 /* Include nul-terminator in match */
684 memset(mask, 0xFF, vialen + 1);
685 }
686
687 /* Display warning on invalid characters */
688 for (i = 0; vianame[i]; i++) {
689 if (vianame[i] == '/' || vianame[i] == ' ') {
690 fprintf(stderr, "Warning: weird character in interface"
691 " `%s' ('/' and ' ' are not allowed by the kernel).\n",
692 vianame);
693 break;
694 }
695 }
696 }
697
698 #ifndef NO_SHARED_LIBS
load_extension(const char * search_path,const char * af_prefix,const char * name,bool is_target)699 static void *load_extension(const char *search_path, const char *af_prefix,
700 const char *name, bool is_target)
701 {
702 const char *all_prefixes[] = {af_prefix, "libxt_", NULL};
703 const char **prefix;
704 const char *dir = search_path, *next;
705 void *ptr = NULL;
706 struct stat sb;
707 char path[256];
708
709 do {
710 next = strchr(dir, ':');
711 if (next == NULL)
712 next = dir + strlen(dir);
713
714 for (prefix = all_prefixes; *prefix != NULL; ++prefix) {
715 void *handle;
716
717 snprintf(path, sizeof(path), "%.*s/%s%s.so",
718 (unsigned int)(next - dir), dir,
719 *prefix, name);
720
721 if (stat(path, &sb) != 0) {
722 if (errno == ENOENT)
723 continue;
724 fprintf(stderr, "%s: %s\n", path,
725 strerror(errno));
726 return NULL;
727 }
728 handle = dlopen(path, RTLD_NOW);
729 if (handle == NULL) {
730 fprintf(stderr, "%s: %s\n", path, dlerror());
731 break;
732 }
733
734 dlreg_add(handle);
735
736 if (is_target)
737 ptr = xtables_find_target(name, XTF_DONT_LOAD);
738 else
739 ptr = xtables_find_match(name,
740 XTF_DONT_LOAD, NULL);
741
742 if (ptr != NULL)
743 return ptr;
744
745 errno = ENOENT;
746 return NULL;
747 }
748 dir = next + 1;
749 } while (*next != '\0');
750
751 return NULL;
752 }
753 #endif
754
extension_cmp(const char * name1,const char * name2,uint32_t family)755 static bool extension_cmp(const char *name1, const char *name2, uint32_t family)
756 {
757 if (strcmp(name1, name2) == 0 &&
758 (family == afinfo->family ||
759 family == NFPROTO_UNSPEC))
760 return true;
761
762 return false;
763 }
764
765 struct xtables_match *
xtables_find_match(const char * name,enum xtables_tryload tryload,struct xtables_rule_match ** matches)766 xtables_find_match(const char *name, enum xtables_tryload tryload,
767 struct xtables_rule_match **matches)
768 {
769 struct xtables_match *prev = NULL;
770 struct xtables_match **dptr;
771 struct xtables_match *ptr;
772 const char *icmp6 = "icmp6";
773 bool found = false;
774 bool seen = false;
775
776 if (strlen(name) >= XT_EXTENSION_MAXNAMELEN)
777 xtables_error(PARAMETER_PROBLEM,
778 "Invalid match name \"%s\" (%u chars max)",
779 name, XT_EXTENSION_MAXNAMELEN - 1);
780
781 /* This is ugly as hell. Nonetheless, there is no way of changing
782 * this without hurting backwards compatibility */
783 if ( (strcmp(name,"icmpv6") == 0) ||
784 (strcmp(name,"ipv6-icmp") == 0) ||
785 (strcmp(name,"icmp6") == 0) )
786 name = icmp6;
787
788 /* Trigger delayed initialization */
789 for (dptr = &xtables_pending_matches; *dptr; ) {
790 if (extension_cmp(name, (*dptr)->name, (*dptr)->family)) {
791 ptr = *dptr;
792 *dptr = (*dptr)->next;
793 seen = true;
794 if (!found &&
795 xtables_fully_register_pending_match(ptr, prev)) {
796 found = true;
797 prev = ptr;
798 continue;
799 } else if (prev) {
800 continue;
801 }
802 *dptr = ptr;
803 }
804 dptr = &((*dptr)->next);
805 }
806
807 if (seen && !found)
808 fprintf(stderr,
809 "Warning: Extension %s is not supported, missing kernel module?\n",
810 name);
811
812 for (ptr = xtables_matches; ptr; ptr = ptr->next) {
813 if (extension_cmp(name, ptr->name, ptr->family)) {
814 struct xtables_match *clone;
815
816 /* First match of this type: */
817 if (ptr->m == NULL)
818 break;
819
820 /* Second and subsequent clones */
821 clone = xtables_malloc(sizeof(struct xtables_match));
822 memcpy(clone, ptr, sizeof(struct xtables_match));
823 clone->udata = NULL;
824 clone->mflags = 0;
825 /* This is a clone: */
826 clone->next = clone;
827
828 ptr = clone;
829 break;
830 }
831 }
832
833 #ifndef NO_SHARED_LIBS
834 if (!ptr && tryload != XTF_DONT_LOAD && tryload != XTF_DURING_LOAD) {
835 ptr = load_extension(xtables_libdir, afinfo->libprefix,
836 name, false);
837
838 if (ptr == NULL && tryload == XTF_LOAD_MUST_SUCCEED)
839 xt_params->exit_err(PARAMETER_PROBLEM,
840 "Couldn't load match `%s':%s\n",
841 name, strerror(errno));
842 }
843 #else
844 if (ptr && !ptr->loaded) {
845 if (tryload != XTF_DONT_LOAD)
846 ptr->loaded = 1;
847 else
848 ptr = NULL;
849 }
850 if(!ptr && (tryload == XTF_LOAD_MUST_SUCCEED)) {
851 xt_params->exit_err(PARAMETER_PROBLEM,
852 "Couldn't find match `%s'\n", name);
853 }
854 #endif
855
856 if (ptr && matches) {
857 struct xtables_rule_match **i;
858 struct xtables_rule_match *newentry;
859
860 newentry = xtables_malloc(sizeof(struct xtables_rule_match));
861
862 for (i = matches; *i; i = &(*i)->next) {
863 if (extension_cmp(name, (*i)->match->name,
864 (*i)->match->family))
865 (*i)->completed = true;
866 }
867 newentry->match = ptr;
868 newentry->completed = false;
869 newentry->next = NULL;
870 *i = newentry;
871 }
872
873 return ptr;
874 }
875
876 struct xtables_match *
xtables_find_match_revision(const char * name,enum xtables_tryload tryload,struct xtables_match * match,int revision)877 xtables_find_match_revision(const char *name, enum xtables_tryload tryload,
878 struct xtables_match *match, int revision)
879 {
880 if (!match) {
881 match = xtables_find_match(name, tryload, NULL);
882 if (!match)
883 return NULL;
884 }
885
886 while (1) {
887 if (match->revision == revision)
888 return match;
889 match = match->next;
890 if (!match)
891 return NULL;
892 if (!extension_cmp(name, match->name, match->family))
893 return NULL;
894 }
895 }
896
897 struct xtables_target *
xtables_find_target(const char * name,enum xtables_tryload tryload)898 xtables_find_target(const char *name, enum xtables_tryload tryload)
899 {
900 struct xtables_target *prev = NULL;
901 struct xtables_target **dptr;
902 struct xtables_target *ptr;
903 bool found = false;
904 bool seen = false;
905
906 /* Standard target? */
907 if (strcmp(name, "") == 0
908 || strcmp(name, XTC_LABEL_ACCEPT) == 0
909 || strcmp(name, XTC_LABEL_DROP) == 0
910 || strcmp(name, XTC_LABEL_QUEUE) == 0
911 || strcmp(name, XTC_LABEL_RETURN) == 0)
912 name = "standard";
913 /* known non-target? */
914 else if (notargets_hlist_lookup(name) &&
915 tryload != XTF_LOAD_MUST_SUCCEED)
916 return NULL;
917
918 /* Trigger delayed initialization */
919 for (dptr = &xtables_pending_targets; *dptr; ) {
920 if (extension_cmp(name, (*dptr)->name, (*dptr)->family)) {
921 ptr = *dptr;
922 *dptr = (*dptr)->next;
923 seen = true;
924 if (!found &&
925 xtables_fully_register_pending_target(ptr, prev)) {
926 found = true;
927 prev = ptr;
928 continue;
929 } else if (prev) {
930 continue;
931 }
932 *dptr = ptr;
933 }
934 dptr = &((*dptr)->next);
935 }
936
937 if (seen && !found)
938 fprintf(stderr,
939 "Warning: Extension %s is not supported, missing kernel module?\n",
940 name);
941
942 for (ptr = xtables_targets; ptr; ptr = ptr->next) {
943 if (extension_cmp(name, ptr->name, ptr->family)) {
944 #if 0 /* Code block below causes memory leak. (Bugs 162925719 and 168688680) */
945 struct xtables_target *clone;
946
947 /* First target of this type: */
948 if (ptr->t == NULL)
949 break;
950
951 /* Second and subsequent clones */
952 clone = xtables_malloc(sizeof(struct xtables_target));
953 memcpy(clone, ptr, sizeof(struct xtables_target));
954 clone->udata = NULL;
955 clone->tflags = 0;
956 /* This is a clone: */
957 clone->next = clone;
958
959 ptr = clone;
960 #endif
961 break;
962 }
963 }
964
965 #ifndef NO_SHARED_LIBS
966 if (!ptr && tryload != XTF_DONT_LOAD && tryload != XTF_DURING_LOAD) {
967 ptr = load_extension(xtables_libdir, afinfo->libprefix,
968 name, true);
969
970 if (ptr == NULL && tryload == XTF_LOAD_MUST_SUCCEED)
971 xt_params->exit_err(PARAMETER_PROBLEM,
972 "Couldn't load target `%s':%s\n",
973 name, strerror(errno));
974 }
975 #else
976 if (ptr && !ptr->loaded) {
977 if (tryload != XTF_DONT_LOAD)
978 ptr->loaded = 1;
979 else
980 ptr = NULL;
981 }
982 if (ptr == NULL && tryload == XTF_LOAD_MUST_SUCCEED) {
983 xt_params->exit_err(PARAMETER_PROBLEM,
984 "Couldn't find target `%s'\n", name);
985 }
986 #endif
987
988 if (ptr)
989 ptr->used = 1;
990 else
991 notargets_hlist_insert(name);
992
993 return ptr;
994 }
995
996 struct xtables_target *
xtables_find_target_revision(const char * name,enum xtables_tryload tryload,struct xtables_target * target,int revision)997 xtables_find_target_revision(const char *name, enum xtables_tryload tryload,
998 struct xtables_target *target, int revision)
999 {
1000 if (!target) {
1001 target = xtables_find_target(name, tryload);
1002 if (!target)
1003 return NULL;
1004 }
1005
1006 while (1) {
1007 if (target->revision == revision)
1008 return target;
1009 target = target->next;
1010 if (!target)
1011 return NULL;
1012 if (!extension_cmp(name, target->name, target->family))
1013 return NULL;
1014 }
1015 }
1016
xtables_compatible_revision(const char * name,uint8_t revision,int opt)1017 int xtables_compatible_revision(const char *name, uint8_t revision, int opt)
1018 {
1019 struct xt_get_revision rev;
1020 socklen_t s = sizeof(rev);
1021 int max_rev, sockfd;
1022
1023 sockfd = socket(afinfo->family, SOCK_RAW | SOCK_CLOEXEC, IPPROTO_RAW);
1024 if (sockfd < 0) {
1025 if (errno == EPERM) {
1026 /* revision 0 is always supported. */
1027 if (revision != 0)
1028 fprintf(stderr, "%s: Could not determine whether "
1029 "revision %u is supported, "
1030 "assuming it is.\n",
1031 name, revision);
1032 return 1;
1033 }
1034 fprintf(stderr, "Could not open socket to kernel: %s\n",
1035 strerror(errno));
1036 exit(1);
1037 }
1038
1039 xtables_load_ko(xtables_modprobe_program, true);
1040
1041 strncpy(rev.name, name, XT_EXTENSION_MAXNAMELEN - 1);
1042 rev.name[XT_EXTENSION_MAXNAMELEN - 1] = '\0';
1043 rev.revision = revision;
1044
1045 max_rev = getsockopt(sockfd, afinfo->ipproto, opt, &rev, &s);
1046 if (max_rev < 0) {
1047 /* Definitely don't support this? */
1048 if (errno == ENOENT || errno == EPROTONOSUPPORT) {
1049 close(sockfd);
1050 /* Pretend revision 0 support for better error messaging */
1051 if (revision == 0)
1052 fprintf(stderr,
1053 "Warning: Extension %s revision 0 not supported, missing kernel module?\n",
1054 name);
1055 return (revision == 0);
1056 } else if (errno == ENOPROTOOPT) {
1057 close(sockfd);
1058 /* Assume only revision 0 support (old kernel) */
1059 return (revision == 0);
1060 } else {
1061 fprintf(stderr, "getsockopt failed strangely: %s\n",
1062 strerror(errno));
1063 exit(1);
1064 }
1065 }
1066 close(sockfd);
1067 return 1;
1068 }
1069
1070
compatible_match_revision(const char * name,uint8_t revision)1071 static int compatible_match_revision(const char *name, uint8_t revision)
1072 {
1073 return xt_params->compat_rev(name, revision, afinfo->so_rev_match);
1074 }
1075
compatible_target_revision(const char * name,uint8_t revision)1076 static int compatible_target_revision(const char *name, uint8_t revision)
1077 {
1078 return xt_params->compat_rev(name, revision, afinfo->so_rev_target);
1079 }
1080
xtables_check_options(const char * name,const struct option * opt)1081 static void xtables_check_options(const char *name, const struct option *opt)
1082 {
1083 for (; opt->name != NULL; ++opt)
1084 if (opt->val < 0 || opt->val >= XT_OPTION_OFFSET_SCALE) {
1085 fprintf(stderr, "%s: Extension %s uses invalid "
1086 "option value %d\n",xt_params->program_name,
1087 name, opt->val);
1088 exit(1);
1089 }
1090 }
1091
1092 static int xtables_match_prefer(const struct xtables_match *a,
1093 const struct xtables_match *b);
1094
xtables_register_match(struct xtables_match * me)1095 void xtables_register_match(struct xtables_match *me)
1096 {
1097 struct xtables_match **pos;
1098 bool seen_myself = false;
1099
1100 if (me->next) {
1101 fprintf(stderr, "%s: match \"%s\" already registered\n",
1102 xt_params->program_name, me->name);
1103 exit(1);
1104 }
1105
1106 if (me->version == NULL) {
1107 fprintf(stderr, "%s: match %s<%u> is missing a version\n",
1108 xt_params->program_name, me->name, me->revision);
1109 exit(1);
1110 }
1111
1112 if (me->size != XT_ALIGN(me->size)) {
1113 fprintf(stderr, "%s: match \"%s\" has invalid size %u.\n",
1114 xt_params->program_name, me->name,
1115 (unsigned int)me->size);
1116 exit(1);
1117 }
1118
1119 if (strcmp(me->version, XTABLES_VERSION) != 0) {
1120 fprintf(stderr, "%s: match \"%s\" has version \"%s\", "
1121 "but \"%s\" is required.\n",
1122 xt_params->program_name, me->name,
1123 me->version, XTABLES_VERSION);
1124 exit(1);
1125 }
1126
1127 if (strlen(me->name) >= XT_EXTENSION_MAXNAMELEN) {
1128 fprintf(stderr, "%s: match `%s' has invalid name\n",
1129 xt_params->program_name, me->name);
1130 exit(1);
1131 }
1132
1133 if (me->real_name && strlen(me->real_name) >= XT_EXTENSION_MAXNAMELEN) {
1134 fprintf(stderr, "%s: match `%s' has invalid real name\n",
1135 xt_params->program_name, me->real_name);
1136 exit(1);
1137 }
1138
1139 if (me->family >= NPROTO) {
1140 fprintf(stderr,
1141 "%s: BUG: match %s has invalid protocol family\n",
1142 xt_params->program_name, me->name);
1143 exit(1);
1144 }
1145
1146 if (me->x6_options != NULL)
1147 xtables_option_metavalidate(me->name, me->x6_options);
1148 if (me->extra_opts != NULL)
1149 xtables_check_options(me->name, me->extra_opts);
1150
1151 /* order into linked list of matches pending full registration */
1152 for (pos = &xtables_pending_matches; *pos; pos = &(*pos)->next) {
1153 /* group by name and family */
1154 if (strcmp(me->name, (*pos)->name) ||
1155 me->family != (*pos)->family) {
1156 if (seen_myself)
1157 break; /* end of own group, append to it */
1158 continue;
1159 }
1160 /* found own group */
1161 seen_myself = true;
1162 if (xtables_match_prefer(me, *pos) >= 0)
1163 break; /* put preferred items first in group */
1164 }
1165 /* if own group was not found, prepend item */
1166 if (!*pos && !seen_myself)
1167 pos = &xtables_pending_matches;
1168
1169 me->next = *pos;
1170 *pos = me;
1171 #ifdef DEBUG
1172 printf("%s: inserted match %s (family %d, revision %d):\n",
1173 __func__, me->name, me->family, me->revision);
1174 for (pos = &xtables_pending_matches; *pos; pos = &(*pos)->next) {
1175 printf("%s:\tmatch %s (family %d, revision %d)\n", __func__,
1176 (*pos)->name, (*pos)->family, (*pos)->revision);
1177 }
1178 #endif
1179 }
1180
1181 /**
1182 * Compare two actions for their preference
1183 * @a: one action
1184 * @b: another
1185 *
1186 * Like strcmp, returns a negative number if @a is less preferred than @b,
1187 * positive number if @a is more preferred than @b, or zero if equally
1188 * preferred.
1189 */
1190 static int
xtables_mt_prefer(bool a_alias,unsigned int a_rev,unsigned int a_fam,bool b_alias,unsigned int b_rev,unsigned int b_fam)1191 xtables_mt_prefer(bool a_alias, unsigned int a_rev, unsigned int a_fam,
1192 bool b_alias, unsigned int b_rev, unsigned int b_fam)
1193 {
1194 /*
1195 * Alias ranks higher than no alias.
1196 * (We want the new action to be used whenever possible.)
1197 */
1198 if (!a_alias && b_alias)
1199 return -1;
1200 if (a_alias && !b_alias)
1201 return 1;
1202
1203 /* Higher revision ranks higher. */
1204 if (a_rev < b_rev)
1205 return -1;
1206 if (a_rev > b_rev)
1207 return 1;
1208
1209 /* NFPROTO_<specific> ranks higher than NFPROTO_UNSPEC. */
1210 if (a_fam == NFPROTO_UNSPEC && b_fam != NFPROTO_UNSPEC)
1211 return -1;
1212 if (a_fam != NFPROTO_UNSPEC && b_fam == NFPROTO_UNSPEC)
1213 return 1;
1214
1215 /* Must be the same thing. */
1216 return 0;
1217 }
1218
xtables_match_prefer(const struct xtables_match * a,const struct xtables_match * b)1219 static int xtables_match_prefer(const struct xtables_match *a,
1220 const struct xtables_match *b)
1221 {
1222 return xtables_mt_prefer(a->real_name != NULL,
1223 a->revision, a->family,
1224 b->real_name != NULL,
1225 b->revision, b->family);
1226 }
1227
xtables_target_prefer(const struct xtables_target * a,const struct xtables_target * b)1228 static int xtables_target_prefer(const struct xtables_target *a,
1229 const struct xtables_target *b)
1230 {
1231 /*
1232 * Note that if x->real_name==NULL, it will be set to x->name in
1233 * xtables_register_*; the direct pointer comparison here is therefore
1234 * legitimate to detect an alias.
1235 */
1236 return xtables_mt_prefer(a->real_name != NULL,
1237 a->revision, a->family,
1238 b->real_name != NULL,
1239 b->revision, b->family);
1240 }
1241
xtables_fully_register_pending_match(struct xtables_match * me,struct xtables_match * prev)1242 static bool xtables_fully_register_pending_match(struct xtables_match *me,
1243 struct xtables_match *prev)
1244 {
1245 struct xtables_match **i;
1246 const char *rn;
1247
1248 /* See if new match can be used. */
1249 rn = (me->real_name != NULL) ? me->real_name : me->name;
1250 if (!compatible_match_revision(rn, me->revision))
1251 return false;
1252
1253 if (!prev) {
1254 /* Append to list. */
1255 for (i = &xtables_matches; *i; i = &(*i)->next);
1256 } else {
1257 /* Append it */
1258 i = &prev->next;
1259 prev = prev->next;
1260 }
1261
1262 me->next = prev;
1263 *i = me;
1264
1265 me->m = NULL;
1266 me->mflags = 0;
1267
1268 return true;
1269 }
1270
xtables_register_matches(struct xtables_match * match,unsigned int n)1271 void xtables_register_matches(struct xtables_match *match, unsigned int n)
1272 {
1273 int i;
1274
1275 for (i = 0; i < n; i++)
1276 xtables_register_match(&match[i]);
1277 }
1278
xtables_register_target(struct xtables_target * me)1279 void xtables_register_target(struct xtables_target *me)
1280 {
1281 struct xtables_target **pos;
1282 bool seen_myself = false;
1283
1284 if (me->next) {
1285 fprintf(stderr, "%s: target \"%s\" already registered\n",
1286 xt_params->program_name, me->name);
1287 exit(1);
1288 }
1289
1290 if (me->version == NULL) {
1291 fprintf(stderr, "%s: target %s<%u> is missing a version\n",
1292 xt_params->program_name, me->name, me->revision);
1293 exit(1);
1294 }
1295
1296 if (me->size != XT_ALIGN(me->size)) {
1297 fprintf(stderr, "%s: target \"%s\" has invalid size %u.\n",
1298 xt_params->program_name, me->name,
1299 (unsigned int)me->size);
1300 exit(1);
1301 }
1302
1303 if (strcmp(me->version, XTABLES_VERSION) != 0) {
1304 fprintf(stderr, "%s: target \"%s\" has version \"%s\", "
1305 "but \"%s\" is required.\n",
1306 xt_params->program_name, me->name,
1307 me->version, XTABLES_VERSION);
1308 exit(1);
1309 }
1310
1311 if (strlen(me->name) >= XT_EXTENSION_MAXNAMELEN) {
1312 fprintf(stderr, "%s: target `%s' has invalid name\n",
1313 xt_params->program_name, me->name);
1314 exit(1);
1315 }
1316
1317 if (me->real_name && strlen(me->real_name) >= XT_EXTENSION_MAXNAMELEN) {
1318 fprintf(stderr, "%s: target `%s' has invalid real name\n",
1319 xt_params->program_name, me->real_name);
1320 exit(1);
1321 }
1322
1323 if (me->family >= NPROTO) {
1324 fprintf(stderr,
1325 "%s: BUG: target %s has invalid protocol family\n",
1326 xt_params->program_name, me->name);
1327 exit(1);
1328 }
1329
1330 if (me->x6_options != NULL)
1331 xtables_option_metavalidate(me->name, me->x6_options);
1332 if (me->extra_opts != NULL)
1333 xtables_check_options(me->name, me->extra_opts);
1334
1335 /* ignore not interested target */
1336 if (me->family != afinfo->family && me->family != AF_UNSPEC)
1337 return;
1338
1339 /* order into linked list of targets pending full registration */
1340 for (pos = &xtables_pending_targets; *pos; pos = &(*pos)->next) {
1341 /* group by name */
1342 if (!extension_cmp(me->name, (*pos)->name, (*pos)->family)) {
1343 if (seen_myself)
1344 break; /* end of own group, append to it */
1345 continue;
1346 }
1347 /* found own group */
1348 seen_myself = true;
1349 if (xtables_target_prefer(me, *pos) >= 0)
1350 break; /* put preferred items first in group */
1351 }
1352 /* if own group was not found, prepend item */
1353 if (!*pos && !seen_myself)
1354 pos = &xtables_pending_targets;
1355
1356 me->next = *pos;
1357 *pos = me;
1358 #ifdef DEBUG
1359 printf("%s: inserted target %s (family %d, revision %d):\n",
1360 __func__, me->name, me->family, me->revision);
1361 for (pos = &xtables_pending_targets; *pos; pos = &(*pos)->next) {
1362 printf("%s:\ttarget %s (family %d, revision %d)\n", __func__,
1363 (*pos)->name, (*pos)->family, (*pos)->revision);
1364 }
1365 #endif
1366 }
1367
xtables_fully_register_pending_target(struct xtables_target * me,struct xtables_target * prev)1368 static bool xtables_fully_register_pending_target(struct xtables_target *me,
1369 struct xtables_target *prev)
1370 {
1371 struct xtables_target **i;
1372 const char *rn;
1373
1374 if (strcmp(me->name, "standard") != 0) {
1375 /* See if new target can be used. */
1376 rn = (me->real_name != NULL) ? me->real_name : me->name;
1377 if (!compatible_target_revision(rn, me->revision))
1378 return false;
1379 }
1380
1381 if (!prev) {
1382 /* Prepend to list. */
1383 i = &xtables_targets;
1384 prev = xtables_targets;
1385 } else {
1386 /* Append it */
1387 i = &prev->next;
1388 prev = prev->next;
1389 }
1390
1391 me->next = prev;
1392 *i = me;
1393
1394 me->t = NULL;
1395 me->tflags = 0;
1396
1397 return true;
1398 }
1399
xtables_register_targets(struct xtables_target * target,unsigned int n)1400 void xtables_register_targets(struct xtables_target *target, unsigned int n)
1401 {
1402 int i;
1403
1404 for (i = 0; i < n; i++)
1405 xtables_register_target(&target[i]);
1406 }
1407
1408 /* receives a list of xtables_rule_match, release them */
xtables_rule_matches_free(struct xtables_rule_match ** matches)1409 void xtables_rule_matches_free(struct xtables_rule_match **matches)
1410 {
1411 struct xtables_rule_match *matchp, *tmp;
1412
1413 for (matchp = *matches; matchp;) {
1414 tmp = matchp->next;
1415 if (matchp->match->m) {
1416 free(matchp->match->m);
1417 matchp->match->m = NULL;
1418 }
1419 if (matchp->match == matchp->match->next) {
1420 free(matchp->match);
1421 matchp->match = NULL;
1422 }
1423 free(matchp);
1424 matchp = tmp;
1425 }
1426
1427 *matches = NULL;
1428 }
1429
1430 /**
1431 * xtables_param_act - act on condition
1432 * @status: a constant from enum xtables_exittype
1433 *
1434 * %XTF_ONLY_ONCE: print error message that option may only be used once.
1435 * @p1: module name (e.g. "mark")
1436 * @p2(...): option in conflict (e.g. "--mark")
1437 * @p3(...): condition to match on (see extensions/ for examples)
1438 *
1439 * %XTF_NO_INVERT: option does not support inversion
1440 * @p1: module name
1441 * @p2: option in conflict
1442 * @p3: condition to match on
1443 *
1444 * %XTF_BAD_VALUE: bad value for option
1445 * @p1: module name
1446 * @p2: option with which the problem occurred (e.g. "--mark")
1447 * @p3: string the user passed in (e.g. "99999999999999")
1448 *
1449 * %XTF_ONE_ACTION: two mutually exclusive actions have been specified
1450 * @p1: module name
1451 *
1452 * Displays an error message and exits the program.
1453 */
xtables_param_act(unsigned int status,const char * p1,...)1454 void xtables_param_act(unsigned int status, const char *p1, ...)
1455 {
1456 const char *p2, *p3;
1457 va_list args;
1458 bool b;
1459
1460 va_start(args, p1);
1461
1462 switch (status) {
1463 case XTF_ONLY_ONCE:
1464 p2 = va_arg(args, const char *);
1465 b = va_arg(args, unsigned int);
1466 if (!b) {
1467 va_end(args);
1468 return;
1469 }
1470 xt_params->exit_err(PARAMETER_PROBLEM,
1471 "%s: \"%s\" option may only be specified once",
1472 p1, p2);
1473 break;
1474 case XTF_NO_INVERT:
1475 p2 = va_arg(args, const char *);
1476 b = va_arg(args, unsigned int);
1477 if (!b) {
1478 va_end(args);
1479 return;
1480 }
1481 xt_params->exit_err(PARAMETER_PROBLEM,
1482 "%s: \"%s\" option cannot be inverted", p1, p2);
1483 break;
1484 case XTF_BAD_VALUE:
1485 p2 = va_arg(args, const char *);
1486 p3 = va_arg(args, const char *);
1487 xt_params->exit_err(PARAMETER_PROBLEM,
1488 "%s: Bad value for \"%s\" option: \"%s\"",
1489 p1, p2, p3);
1490 break;
1491 case XTF_ONE_ACTION:
1492 b = va_arg(args, unsigned int);
1493 if (!b) {
1494 va_end(args);
1495 return;
1496 }
1497 xt_params->exit_err(PARAMETER_PROBLEM,
1498 "%s: At most one action is possible", p1);
1499 break;
1500 default:
1501 xt_params->exit_err(status, p1, args);
1502 break;
1503 }
1504
1505 va_end(args);
1506 }
1507
xtables_ipaddr_to_numeric(const struct in_addr * addrp)1508 const char *xtables_ipaddr_to_numeric(const struct in_addr *addrp)
1509 {
1510 static char buf[16];
1511 const unsigned char *bytep = (const void *)&addrp->s_addr;
1512
1513 sprintf(buf, "%u.%u.%u.%u", bytep[0], bytep[1], bytep[2], bytep[3]);
1514 return buf;
1515 }
1516
ipaddr_to_host(const struct in_addr * addr)1517 static const char *ipaddr_to_host(const struct in_addr *addr)
1518 {
1519 static char hostname[NI_MAXHOST];
1520 struct sockaddr_in saddr = {
1521 .sin_family = AF_INET,
1522 .sin_addr = *addr,
1523 };
1524 int err;
1525
1526
1527 err = getnameinfo((const void *)&saddr, sizeof(struct sockaddr_in),
1528 hostname, sizeof(hostname) - 1, NULL, 0, 0);
1529 if (err != 0)
1530 return NULL;
1531
1532 return hostname;
1533 }
1534
ipaddr_to_network(const struct in_addr * addr)1535 static const char *ipaddr_to_network(const struct in_addr *addr)
1536 {
1537 struct netent *net;
1538
1539 if ((net = getnetbyaddr(ntohl(addr->s_addr), AF_INET)) != NULL)
1540 return net->n_name;
1541
1542 return NULL;
1543 }
1544
xtables_ipaddr_to_anyname(const struct in_addr * addr)1545 const char *xtables_ipaddr_to_anyname(const struct in_addr *addr)
1546 {
1547 const char *name;
1548
1549 if ((name = ipaddr_to_host(addr)) != NULL ||
1550 (name = ipaddr_to_network(addr)) != NULL)
1551 return name;
1552
1553 return xtables_ipaddr_to_numeric(addr);
1554 }
1555
xtables_ipmask_to_cidr(const struct in_addr * mask)1556 int xtables_ipmask_to_cidr(const struct in_addr *mask)
1557 {
1558 uint32_t maskaddr, bits;
1559 int i;
1560
1561 maskaddr = ntohl(mask->s_addr);
1562
1563 for (i = 32, bits = (uint32_t)-1; i >= 0; i--, bits <<= 1) {
1564 if (bits == maskaddr)
1565 return i;
1566 }
1567
1568 /* this mask cannot be converted to CIDR notation */
1569 return -1;
1570 }
1571
xtables_ipmask_to_numeric(const struct in_addr * mask)1572 const char *xtables_ipmask_to_numeric(const struct in_addr *mask)
1573 {
1574 static char buf[20];
1575 uint32_t cidr;
1576
1577 cidr = xtables_ipmask_to_cidr(mask);
1578 if (cidr == (unsigned int)-1) {
1579 /* mask was not a decent combination of 1's and 0's */
1580 sprintf(buf, "/%s", xtables_ipaddr_to_numeric(mask));
1581 return buf;
1582 } else if (cidr == 32) {
1583 /* we don't want to see "/32" */
1584 return "";
1585 }
1586
1587 sprintf(buf, "/%d", cidr);
1588 return buf;
1589 }
1590
__numeric_to_ipaddr(const char * dotted,bool is_mask)1591 static struct in_addr *__numeric_to_ipaddr(const char *dotted, bool is_mask)
1592 {
1593 static struct in_addr addr;
1594 unsigned char *addrp;
1595 unsigned int onebyte;
1596 char buf[20], *p, *q;
1597 int i;
1598
1599 /* copy dotted string, because we need to modify it */
1600 strncpy(buf, dotted, sizeof(buf) - 1);
1601 buf[sizeof(buf) - 1] = '\0';
1602 addrp = (void *)&addr.s_addr;
1603
1604 p = buf;
1605 for (i = 0; i < 3; ++i) {
1606 if ((q = strchr(p, '.')) == NULL) {
1607 if (is_mask)
1608 return NULL;
1609
1610 /* autocomplete, this is a network address */
1611 if (!xtables_strtoui(p, NULL, &onebyte, 0, UINT8_MAX))
1612 return NULL;
1613
1614 addrp[i] = onebyte;
1615 while (i < 3)
1616 addrp[++i] = 0;
1617
1618 return &addr;
1619 }
1620
1621 *q = '\0';
1622 if (!xtables_strtoui(p, NULL, &onebyte, 0, UINT8_MAX))
1623 return NULL;
1624
1625 addrp[i] = onebyte;
1626 p = q + 1;
1627 }
1628
1629 /* we have checked 3 bytes, now we check the last one */
1630 if (!xtables_strtoui(p, NULL, &onebyte, 0, UINT8_MAX))
1631 return NULL;
1632
1633 addrp[3] = onebyte;
1634 return &addr;
1635 }
1636
xtables_numeric_to_ipaddr(const char * dotted)1637 struct in_addr *xtables_numeric_to_ipaddr(const char *dotted)
1638 {
1639 return __numeric_to_ipaddr(dotted, false);
1640 }
1641
xtables_numeric_to_ipmask(const char * dotted)1642 struct in_addr *xtables_numeric_to_ipmask(const char *dotted)
1643 {
1644 return __numeric_to_ipaddr(dotted, true);
1645 }
1646
network_to_ipaddr(const char * name)1647 static struct in_addr *network_to_ipaddr(const char *name)
1648 {
1649 static struct in_addr addr;
1650 struct netent *net;
1651
1652 if ((net = getnetbyname(name)) != NULL) {
1653 if (net->n_addrtype != AF_INET)
1654 return NULL;
1655 addr.s_addr = htonl(net->n_net);
1656 return &addr;
1657 }
1658
1659 return NULL;
1660 }
1661
host_to_ipaddr(const char * name,unsigned int * naddr)1662 static struct in_addr *host_to_ipaddr(const char *name, unsigned int *naddr)
1663 {
1664 struct in_addr *addr;
1665 struct addrinfo hints;
1666 struct addrinfo *res, *p;
1667 int err;
1668 unsigned int i;
1669
1670 memset(&hints, 0, sizeof(hints));
1671 hints.ai_family = AF_INET;
1672 hints.ai_socktype = SOCK_RAW;
1673
1674 *naddr = 0;
1675 err = getaddrinfo(name, NULL, &hints, &res);
1676 if (err != 0)
1677 return NULL;
1678 for (p = res; p != NULL; p = p->ai_next)
1679 ++*naddr;
1680 addr = xtables_calloc(*naddr, sizeof(struct in_addr));
1681 for (i = 0, p = res; p != NULL; p = p->ai_next)
1682 memcpy(&addr[i++],
1683 &((const struct sockaddr_in *)p->ai_addr)->sin_addr,
1684 sizeof(struct in_addr));
1685 freeaddrinfo(res);
1686 return addr;
1687 }
1688
1689 static struct in_addr *
ipparse_hostnetwork(const char * name,unsigned int * naddrs)1690 ipparse_hostnetwork(const char *name, unsigned int *naddrs)
1691 {
1692 struct in_addr *addrptmp, *addrp;
1693
1694 if ((addrptmp = xtables_numeric_to_ipaddr(name)) != NULL ||
1695 (addrptmp = network_to_ipaddr(name)) != NULL) {
1696 addrp = xtables_malloc(sizeof(struct in_addr));
1697 memcpy(addrp, addrptmp, sizeof(*addrp));
1698 *naddrs = 1;
1699 return addrp;
1700 }
1701 if ((addrptmp = host_to_ipaddr(name, naddrs)) != NULL)
1702 return addrptmp;
1703
1704 xt_params->exit_err(PARAMETER_PROBLEM, "host/network `%s' not found", name);
1705 }
1706
parse_ipmask(const char * mask)1707 static struct in_addr *parse_ipmask(const char *mask)
1708 {
1709 static struct in_addr maskaddr;
1710 struct in_addr *addrp;
1711 unsigned int bits;
1712
1713 if (mask == NULL) {
1714 /* no mask at all defaults to 32 bits */
1715 maskaddr.s_addr = 0xFFFFFFFF;
1716 return &maskaddr;
1717 }
1718 if ((addrp = xtables_numeric_to_ipmask(mask)) != NULL)
1719 /* dotted_to_addr already returns a network byte order addr */
1720 return addrp;
1721 if (!xtables_strtoui(mask, NULL, &bits, 0, 32))
1722 xt_params->exit_err(PARAMETER_PROBLEM,
1723 "invalid mask `%s' specified", mask);
1724 if (bits != 0) {
1725 maskaddr.s_addr = htonl(0xFFFFFFFF << (32 - bits));
1726 return &maskaddr;
1727 }
1728
1729 maskaddr.s_addr = 0U;
1730 return &maskaddr;
1731 }
1732
xtables_ipparse_multiple(const char * name,struct in_addr ** addrpp,struct in_addr ** maskpp,unsigned int * naddrs)1733 void xtables_ipparse_multiple(const char *name, struct in_addr **addrpp,
1734 struct in_addr **maskpp, unsigned int *naddrs)
1735 {
1736 struct in_addr *addrp;
1737 char buf[256], *p, *next;
1738 unsigned int len, i, j, n, count = 1;
1739 const char *loop = name;
1740
1741 while ((loop = strchr(loop, ',')) != NULL) {
1742 ++count;
1743 ++loop; /* skip ',' */
1744 }
1745
1746 *addrpp = xtables_malloc(sizeof(struct in_addr) * count);
1747 *maskpp = xtables_malloc(sizeof(struct in_addr) * count);
1748
1749 loop = name;
1750
1751 for (i = 0; i < count; ++i) {
1752 while (isspace(*loop))
1753 ++loop;
1754 next = strchr(loop, ',');
1755 if (next != NULL)
1756 len = next - loop;
1757 else
1758 len = strlen(loop);
1759 if (len > sizeof(buf) - 1)
1760 xt_params->exit_err(PARAMETER_PROBLEM,
1761 "Hostname too long");
1762
1763 strncpy(buf, loop, len);
1764 buf[len] = '\0';
1765 if ((p = strrchr(buf, '/')) != NULL) {
1766 *p = '\0';
1767 addrp = parse_ipmask(p + 1);
1768 } else {
1769 addrp = parse_ipmask(NULL);
1770 }
1771 memcpy(*maskpp + i, addrp, sizeof(*addrp));
1772
1773 /* if a null mask is given, the name is ignored, like in "any/0" */
1774 if ((*maskpp + i)->s_addr == 0)
1775 /*
1776 * A bit pointless to process multiple addresses
1777 * in this case...
1778 */
1779 strcpy(buf, "0.0.0.0");
1780
1781 addrp = ipparse_hostnetwork(buf, &n);
1782 if (n > 1) {
1783 count += n - 1;
1784 *addrpp = xtables_realloc(*addrpp,
1785 sizeof(struct in_addr) * count);
1786 *maskpp = xtables_realloc(*maskpp,
1787 sizeof(struct in_addr) * count);
1788 for (j = 0; j < n; ++j)
1789 /* for each new addr */
1790 memcpy(*addrpp + i + j, addrp + j,
1791 sizeof(*addrp));
1792 for (j = 1; j < n; ++j)
1793 /* for each new mask */
1794 memcpy(*maskpp + i + j, *maskpp + i,
1795 sizeof(*addrp));
1796 i += n - 1;
1797 } else {
1798 memcpy(*addrpp + i, addrp, sizeof(*addrp));
1799 }
1800 /* free what ipparse_hostnetwork had allocated: */
1801 free(addrp);
1802 if (next == NULL)
1803 break;
1804 loop = next + 1;
1805 }
1806 *naddrs = count;
1807 for (i = 0; i < count; ++i)
1808 (*addrpp+i)->s_addr &= (*maskpp+i)->s_addr;
1809 }
1810
1811
1812 /**
1813 * xtables_ipparse_any - transform arbitrary name to in_addr
1814 *
1815 * Possible inputs (pseudo regex):
1816 * m{^($hostname|$networkname|$ipaddr)(/$mask)?}
1817 * "1.2.3.4/5", "1.2.3.4", "hostname", "networkname"
1818 */
xtables_ipparse_any(const char * name,struct in_addr ** addrpp,struct in_addr * maskp,unsigned int * naddrs)1819 void xtables_ipparse_any(const char *name, struct in_addr **addrpp,
1820 struct in_addr *maskp, unsigned int *naddrs)
1821 {
1822 unsigned int i, j, k, n;
1823 struct in_addr *addrp;
1824 char buf[256], *p;
1825
1826 strncpy(buf, name, sizeof(buf) - 1);
1827 buf[sizeof(buf) - 1] = '\0';
1828 if ((p = strrchr(buf, '/')) != NULL) {
1829 *p = '\0';
1830 addrp = parse_ipmask(p + 1);
1831 } else {
1832 addrp = parse_ipmask(NULL);
1833 }
1834 memcpy(maskp, addrp, sizeof(*maskp));
1835
1836 /* if a null mask is given, the name is ignored, like in "any/0" */
1837 if (maskp->s_addr == 0U)
1838 strcpy(buf, "0.0.0.0");
1839
1840 addrp = *addrpp = ipparse_hostnetwork(buf, naddrs);
1841 n = *naddrs;
1842 for (i = 0, j = 0; i < n; ++i) {
1843 addrp[j++].s_addr &= maskp->s_addr;
1844 for (k = 0; k < j - 1; ++k)
1845 if (addrp[k].s_addr == addrp[j-1].s_addr) {
1846 /*
1847 * Nuke the dup by copying an address from the
1848 * tail here, and check the current position
1849 * again (--j).
1850 */
1851 memcpy(&addrp[--j], &addrp[--*naddrs],
1852 sizeof(struct in_addr));
1853 break;
1854 }
1855 }
1856 }
1857
xtables_ip6addr_to_numeric(const struct in6_addr * addrp)1858 const char *xtables_ip6addr_to_numeric(const struct in6_addr *addrp)
1859 {
1860 /* 0000:0000:0000:0000:0000:0000:000.000.000.000
1861 * 0000:0000:0000:0000:0000:0000:0000:0000 */
1862 static char buf[50+1];
1863 return inet_ntop(AF_INET6, addrp, buf, sizeof(buf));
1864 }
1865
ip6addr_to_host(const struct in6_addr * addr)1866 static const char *ip6addr_to_host(const struct in6_addr *addr)
1867 {
1868 static char hostname[NI_MAXHOST];
1869 struct sockaddr_in6 saddr;
1870 int err;
1871
1872 memset(&saddr, 0, sizeof(struct sockaddr_in6));
1873 memcpy(&saddr.sin6_addr, addr, sizeof(*addr));
1874 saddr.sin6_family = AF_INET6;
1875
1876 err = getnameinfo((const void *)&saddr, sizeof(struct sockaddr_in6),
1877 hostname, sizeof(hostname) - 1, NULL, 0, 0);
1878 if (err != 0)
1879 return NULL;
1880
1881 return hostname;
1882 }
1883
xtables_ip6addr_to_anyname(const struct in6_addr * addr)1884 const char *xtables_ip6addr_to_anyname(const struct in6_addr *addr)
1885 {
1886 const char *name;
1887
1888 if ((name = ip6addr_to_host(addr)) != NULL)
1889 return name;
1890
1891 return xtables_ip6addr_to_numeric(addr);
1892 }
1893
xtables_ip6mask_to_cidr(const struct in6_addr * k)1894 int xtables_ip6mask_to_cidr(const struct in6_addr *k)
1895 {
1896 unsigned int bits = 0;
1897 uint32_t a, b, c, d;
1898
1899 a = ntohl(k->s6_addr32[0]);
1900 b = ntohl(k->s6_addr32[1]);
1901 c = ntohl(k->s6_addr32[2]);
1902 d = ntohl(k->s6_addr32[3]);
1903 while (a & 0x80000000U) {
1904 ++bits;
1905 a <<= 1;
1906 a |= (b >> 31) & 1;
1907 b <<= 1;
1908 b |= (c >> 31) & 1;
1909 c <<= 1;
1910 c |= (d >> 31) & 1;
1911 d <<= 1;
1912 }
1913 if (a != 0 || b != 0 || c != 0 || d != 0)
1914 return -1;
1915 return bits;
1916 }
1917
xtables_ip6mask_to_numeric(const struct in6_addr * addrp)1918 const char *xtables_ip6mask_to_numeric(const struct in6_addr *addrp)
1919 {
1920 static char buf[50+2];
1921 int l = xtables_ip6mask_to_cidr(addrp);
1922
1923 if (l == -1) {
1924 strcpy(buf, "/");
1925 strcat(buf, xtables_ip6addr_to_numeric(addrp));
1926 return buf;
1927 }
1928 /* we don't want to see "/128" */
1929 if (l == 128)
1930 return "";
1931 else
1932 sprintf(buf, "/%d", l);
1933 return buf;
1934 }
1935
xtables_numeric_to_ip6addr(const char * num)1936 struct in6_addr *xtables_numeric_to_ip6addr(const char *num)
1937 {
1938 static struct in6_addr ap;
1939
1940 if (inet_pton(AF_INET6, num, &ap) == 1)
1941 return ≈
1942
1943 return NULL;
1944 }
1945
1946 static struct in6_addr *
host_to_ip6addr(const char * name,unsigned int * naddr)1947 host_to_ip6addr(const char *name, unsigned int *naddr)
1948 {
1949 struct in6_addr *addr;
1950 struct addrinfo hints;
1951 struct addrinfo *res, *p;
1952 int err;
1953 unsigned int i;
1954
1955 memset(&hints, 0, sizeof(hints));
1956 hints.ai_family = AF_INET6;
1957 hints.ai_socktype = SOCK_RAW;
1958
1959 *naddr = 0;
1960 err = getaddrinfo(name, NULL, &hints, &res);
1961 if (err != 0)
1962 return NULL;
1963 /* Find length of address chain */
1964 for (p = res; p != NULL; p = p->ai_next)
1965 ++*naddr;
1966 /* Copy each element of the address chain */
1967 addr = xtables_calloc(*naddr, sizeof(struct in6_addr));
1968 for (i = 0, p = res; p != NULL; p = p->ai_next)
1969 memcpy(&addr[i++],
1970 &((const struct sockaddr_in6 *)p->ai_addr)->sin6_addr,
1971 sizeof(struct in6_addr));
1972 freeaddrinfo(res);
1973 return addr;
1974 }
1975
network_to_ip6addr(const char * name)1976 static struct in6_addr *network_to_ip6addr(const char *name)
1977 {
1978 /* abort();*/
1979 /* TODO: not implemented yet, but the exception breaks the
1980 * name resolvation */
1981 return NULL;
1982 }
1983
1984 static struct in6_addr *
ip6parse_hostnetwork(const char * name,unsigned int * naddrs)1985 ip6parse_hostnetwork(const char *name, unsigned int *naddrs)
1986 {
1987 struct in6_addr *addrp, *addrptmp;
1988
1989 if ((addrptmp = xtables_numeric_to_ip6addr(name)) != NULL ||
1990 (addrptmp = network_to_ip6addr(name)) != NULL) {
1991 addrp = xtables_malloc(sizeof(struct in6_addr));
1992 memcpy(addrp, addrptmp, sizeof(*addrp));
1993 *naddrs = 1;
1994 return addrp;
1995 }
1996 if ((addrp = host_to_ip6addr(name, naddrs)) != NULL)
1997 return addrp;
1998
1999 xt_params->exit_err(PARAMETER_PROBLEM, "host/network `%s' not found", name);
2000 }
2001
parse_ip6mask(char * mask)2002 static struct in6_addr *parse_ip6mask(char *mask)
2003 {
2004 static struct in6_addr maskaddr;
2005 struct in6_addr *addrp;
2006 unsigned int bits;
2007
2008 if (mask == NULL) {
2009 /* no mask at all defaults to 128 bits */
2010 memset(&maskaddr, 0xff, sizeof maskaddr);
2011 return &maskaddr;
2012 }
2013 if ((addrp = xtables_numeric_to_ip6addr(mask)) != NULL)
2014 return addrp;
2015 if (!xtables_strtoui(mask, NULL, &bits, 0, 128))
2016 xt_params->exit_err(PARAMETER_PROBLEM,
2017 "invalid mask `%s' specified", mask);
2018 if (bits != 0) {
2019 char *p = (void *)&maskaddr;
2020 memset(p, 0xff, bits / 8);
2021 memset(p + ((bits + 7) / 8), 0, (128 - bits) / 8);
2022 if (bits < 128)
2023 p[bits/8] = 0xff << (8 - (bits & 7));
2024 return &maskaddr;
2025 }
2026
2027 memset(&maskaddr, 0, sizeof(maskaddr));
2028 return &maskaddr;
2029 }
2030
2031 void
xtables_ip6parse_multiple(const char * name,struct in6_addr ** addrpp,struct in6_addr ** maskpp,unsigned int * naddrs)2032 xtables_ip6parse_multiple(const char *name, struct in6_addr **addrpp,
2033 struct in6_addr **maskpp, unsigned int *naddrs)
2034 {
2035 static const struct in6_addr zero_addr;
2036 struct in6_addr *addrp;
2037 char buf[256], *p, *next;
2038 unsigned int len, i, j, n, count = 1;
2039 const char *loop = name;
2040
2041 while ((loop = strchr(loop, ',')) != NULL) {
2042 ++count;
2043 ++loop; /* skip ',' */
2044 }
2045
2046 *addrpp = xtables_malloc(sizeof(struct in6_addr) * count);
2047 *maskpp = xtables_malloc(sizeof(struct in6_addr) * count);
2048
2049 loop = name;
2050
2051 for (i = 0; i < count /*NB: count can grow*/; ++i) {
2052 while (isspace(*loop))
2053 ++loop;
2054 next = strchr(loop, ',');
2055 if (next != NULL)
2056 len = next - loop;
2057 else
2058 len = strlen(loop);
2059 if (len > sizeof(buf) - 1)
2060 xt_params->exit_err(PARAMETER_PROBLEM,
2061 "Hostname too long");
2062
2063 strncpy(buf, loop, len);
2064 buf[len] = '\0';
2065 if ((p = strrchr(buf, '/')) != NULL) {
2066 *p = '\0';
2067 addrp = parse_ip6mask(p + 1);
2068 } else {
2069 addrp = parse_ip6mask(NULL);
2070 }
2071 memcpy(*maskpp + i, addrp, sizeof(*addrp));
2072
2073 /* if a null mask is given, the name is ignored, like in "any/0" */
2074 if (memcmp(*maskpp + i, &zero_addr, sizeof(zero_addr)) == 0)
2075 strcpy(buf, "::");
2076
2077 addrp = ip6parse_hostnetwork(buf, &n);
2078 if (n > 1) {
2079 count += n - 1;
2080 *addrpp = xtables_realloc(*addrpp,
2081 sizeof(struct in6_addr) * count);
2082 *maskpp = xtables_realloc(*maskpp,
2083 sizeof(struct in6_addr) * count);
2084 for (j = 0; j < n; ++j)
2085 /* for each new addr */
2086 memcpy(*addrpp + i + j, addrp + j,
2087 sizeof(*addrp));
2088 for (j = 1; j < n; ++j)
2089 /* for each new mask */
2090 memcpy(*maskpp + i + j, *maskpp + i,
2091 sizeof(*addrp));
2092 i += n - 1;
2093 } else {
2094 memcpy(*addrpp + i, addrp, sizeof(*addrp));
2095 }
2096 /* free what ip6parse_hostnetwork had allocated: */
2097 free(addrp);
2098 if (next == NULL)
2099 break;
2100 loop = next + 1;
2101 }
2102 *naddrs = count;
2103 for (i = 0; i < count; ++i)
2104 for (j = 0; j < 4; ++j)
2105 (*addrpp+i)->s6_addr32[j] &= (*maskpp+i)->s6_addr32[j];
2106 }
2107
xtables_ip6parse_any(const char * name,struct in6_addr ** addrpp,struct in6_addr * maskp,unsigned int * naddrs)2108 void xtables_ip6parse_any(const char *name, struct in6_addr **addrpp,
2109 struct in6_addr *maskp, unsigned int *naddrs)
2110 {
2111 static const struct in6_addr zero_addr;
2112 struct in6_addr *addrp;
2113 unsigned int i, j, k, n;
2114 char buf[256], *p;
2115
2116 strncpy(buf, name, sizeof(buf) - 1);
2117 buf[sizeof(buf)-1] = '\0';
2118 if ((p = strrchr(buf, '/')) != NULL) {
2119 *p = '\0';
2120 addrp = parse_ip6mask(p + 1);
2121 } else {
2122 addrp = parse_ip6mask(NULL);
2123 }
2124 memcpy(maskp, addrp, sizeof(*maskp));
2125
2126 /* if a null mask is given, the name is ignored, like in "any/0" */
2127 if (memcmp(maskp, &zero_addr, sizeof(zero_addr)) == 0)
2128 strcpy(buf, "::");
2129
2130 addrp = *addrpp = ip6parse_hostnetwork(buf, naddrs);
2131 n = *naddrs;
2132 for (i = 0, j = 0; i < n; ++i) {
2133 for (k = 0; k < 4; ++k)
2134 addrp[j].s6_addr32[k] &= maskp->s6_addr32[k];
2135 ++j;
2136 for (k = 0; k < j - 1; ++k)
2137 if (IN6_ARE_ADDR_EQUAL(&addrp[k], &addrp[j - 1])) {
2138 /*
2139 * Nuke the dup by copying an address from the
2140 * tail here, and check the current position
2141 * again (--j).
2142 */
2143 memcpy(&addrp[--j], &addrp[--*naddrs],
2144 sizeof(struct in_addr));
2145 break;
2146 }
2147 }
2148 }
2149
xtables_save_string(const char * value)2150 void xtables_save_string(const char *value)
2151 {
2152 static const char no_quote_chars[] = "_-0123456789"
2153 "abcdefghijklmnopqrstuvwxyz"
2154 "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
2155 static const char escape_chars[] = "\"\\'";
2156 size_t length;
2157 const char *p;
2158
2159 length = strspn(value, no_quote_chars);
2160 if (length > 0 && value[length] == 0) {
2161 /* no quoting required */
2162 putchar(' ');
2163 fputs(value, stdout);
2164 } else {
2165 /* there is at least one dangerous character in the
2166 value, which we have to quote. Write double quotes
2167 around the value and escape special characters with
2168 a backslash */
2169 printf(" \"");
2170
2171 for (p = strpbrk(value, escape_chars); p != NULL;
2172 p = strpbrk(value, escape_chars)) {
2173 if (p > value)
2174 fwrite(value, 1, p - value, stdout);
2175 putchar('\\');
2176 putchar(*p);
2177 value = p + 1;
2178 }
2179
2180 /* print the rest and finish the double quoted
2181 string */
2182 fputs(value, stdout);
2183 putchar('\"');
2184 }
2185 }
2186
2187 const struct xtables_pprot xtables_chain_protos[] = {
2188 {"tcp", IPPROTO_TCP},
2189 {"sctp", IPPROTO_SCTP},
2190 {"udp", IPPROTO_UDP},
2191 {"udplite", IPPROTO_UDPLITE},
2192 {"icmp", IPPROTO_ICMP},
2193 {"ipv6-icmp", IPPROTO_ICMPV6},
2194 {"icmpv6", IPPROTO_ICMPV6},
2195 {"esp", IPPROTO_ESP},
2196 {"ah", IPPROTO_AH},
2197 {"mobility-header", IPPROTO_MH},
2198 {"ipv6-mh", IPPROTO_MH},
2199 {"mh", IPPROTO_MH},
2200 {"all", 0},
2201 {NULL},
2202 };
2203
2204 uint16_t
xtables_parse_protocol(const char * s)2205 xtables_parse_protocol(const char *s)
2206 {
2207 const struct protoent *pent;
2208 unsigned int proto, i;
2209
2210 if (xtables_strtoui(s, NULL, &proto, 0, UINT8_MAX))
2211 return proto;
2212
2213 for (i = 0; xtables_chain_protos[i].name != NULL; ++i) {
2214 if (strcmp(s, xtables_chain_protos[i].name) == 0)
2215 return xtables_chain_protos[i].num;
2216 }
2217
2218 pent = getprotobyname(s);
2219 if (pent != NULL)
2220 return pent->p_proto;
2221
2222 xt_params->exit_err(PARAMETER_PROBLEM,
2223 "unknown protocol \"%s\" specified", s);
2224 return -1;
2225 }
2226
xtables_print_num(uint64_t number,unsigned int format)2227 void xtables_print_num(uint64_t number, unsigned int format)
2228 {
2229 if (!(format & FMT_KILOMEGAGIGA)) {
2230 printf(FMT("%8llu ","%llu "), (unsigned long long)number);
2231 return;
2232 }
2233 if (number <= 99999) {
2234 printf(FMT("%5llu ","%llu "), (unsigned long long)number);
2235 return;
2236 }
2237 number = (number + 500) / 1000;
2238 if (number <= 9999) {
2239 printf(FMT("%4lluK ","%lluK "), (unsigned long long)number);
2240 return;
2241 }
2242 number = (number + 500) / 1000;
2243 if (number <= 9999) {
2244 printf(FMT("%4lluM ","%lluM "), (unsigned long long)number);
2245 return;
2246 }
2247 number = (number + 500) / 1000;
2248 if (number <= 9999) {
2249 printf(FMT("%4lluG ","%lluG "), (unsigned long long)number);
2250 return;
2251 }
2252 number = (number + 500) / 1000;
2253 printf(FMT("%4lluT ","%lluT "), (unsigned long long)number);
2254 }
2255
2256 static const unsigned char mac_type_unicast[ETH_ALEN] = {};
2257 static const unsigned char msk_type_unicast[ETH_ALEN] = {1};
2258 static const unsigned char mac_type_multicast[ETH_ALEN] = {1};
2259 static const unsigned char msk_type_multicast[ETH_ALEN] = {1};
2260 #define ALL_ONE_MAC {0xff, 0xff, 0xff, 0xff, 0xff, 0xff}
2261 static const unsigned char mac_type_broadcast[ETH_ALEN] = ALL_ONE_MAC;
2262 static const unsigned char msk_type_broadcast[ETH_ALEN] = ALL_ONE_MAC;
2263 static const unsigned char mac_type_bridge_group[ETH_ALEN] = {0x01, 0x80, 0xc2};
2264 static const unsigned char msk_type_bridge_group[ETH_ALEN] = ALL_ONE_MAC;
2265 #undef ALL_ONE_MAC
2266
xtables_parse_mac_and_mask(const char * from,void * to,void * mask)2267 int xtables_parse_mac_and_mask(const char *from, void *to, void *mask)
2268 {
2269 char *p;
2270 int i;
2271 struct ether_addr *addr = NULL;
2272
2273 if (strcasecmp(from, "Unicast") == 0) {
2274 memcpy(to, mac_type_unicast, ETH_ALEN);
2275 memcpy(mask, msk_type_unicast, ETH_ALEN);
2276 return 0;
2277 }
2278 if (strcasecmp(from, "Multicast") == 0) {
2279 memcpy(to, mac_type_multicast, ETH_ALEN);
2280 memcpy(mask, msk_type_multicast, ETH_ALEN);
2281 return 0;
2282 }
2283 if (strcasecmp(from, "Broadcast") == 0) {
2284 memcpy(to, mac_type_broadcast, ETH_ALEN);
2285 memcpy(mask, msk_type_broadcast, ETH_ALEN);
2286 return 0;
2287 }
2288 if (strcasecmp(from, "BGA") == 0) {
2289 memcpy(to, mac_type_bridge_group, ETH_ALEN);
2290 memcpy(mask, msk_type_bridge_group, ETH_ALEN);
2291 return 0;
2292 }
2293 if ( (p = strrchr(from, '/')) != NULL) {
2294 *p = '\0';
2295 if (!(addr = ether_aton(p + 1)))
2296 return -1;
2297 memcpy(mask, addr, ETH_ALEN);
2298 } else
2299 memset(mask, 0xff, ETH_ALEN);
2300 if (!(addr = ether_aton(from)))
2301 return -1;
2302 memcpy(to, addr, ETH_ALEN);
2303 for (i = 0; i < ETH_ALEN; i++)
2304 ((char *)to)[i] &= ((char *)mask)[i];
2305 return 0;
2306 }
2307
xtables_print_well_known_mac_and_mask(const void * mac,const void * mask)2308 int xtables_print_well_known_mac_and_mask(const void *mac, const void *mask)
2309 {
2310 if (!memcmp(mac, mac_type_unicast, ETH_ALEN) &&
2311 !memcmp(mask, msk_type_unicast, ETH_ALEN))
2312 printf("Unicast");
2313 else if (!memcmp(mac, mac_type_multicast, ETH_ALEN) &&
2314 !memcmp(mask, msk_type_multicast, ETH_ALEN))
2315 printf("Multicast");
2316 else if (!memcmp(mac, mac_type_broadcast, ETH_ALEN) &&
2317 !memcmp(mask, msk_type_broadcast, ETH_ALEN))
2318 printf("Broadcast");
2319 else if (!memcmp(mac, mac_type_bridge_group, ETH_ALEN) &&
2320 !memcmp(mask, msk_type_bridge_group, ETH_ALEN))
2321 printf("BGA");
2322 else
2323 return -1;
2324 return 0;
2325 }
2326
xtables_print_mac(const unsigned char * macaddress)2327 void xtables_print_mac(const unsigned char *macaddress)
2328 {
2329 unsigned int i;
2330
2331 printf("%02x", macaddress[0]);
2332 for (i = 1; i < 6; ++i)
2333 printf(":%02x", macaddress[i]);
2334 }
2335
xtables_print_mac_and_mask(const unsigned char * mac,const unsigned char * mask)2336 void xtables_print_mac_and_mask(const unsigned char *mac, const unsigned char *mask)
2337 {
2338 static const char hlpmsk[] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
2339
2340 xtables_print_mac(mac);
2341
2342 if (memcmp(mask, hlpmsk, 6) == 0)
2343 return;
2344
2345 printf("/");
2346 xtables_print_mac(mask);
2347 }
2348
xtables_parse_val_mask(struct xt_option_call * cb,unsigned int * val,unsigned int * mask,const struct xtables_lmap * lmap)2349 void xtables_parse_val_mask(struct xt_option_call *cb,
2350 unsigned int *val, unsigned int *mask,
2351 const struct xtables_lmap *lmap)
2352 {
2353 char *end;
2354
2355 *mask = ~0U;
2356
2357 if (!xtables_strtoui(cb->arg, &end, val, 0, UINT32_MAX)) {
2358 if (lmap)
2359 goto name2val;
2360 else
2361 goto bad_val;
2362 }
2363
2364 if (*end == '\0')
2365 return;
2366
2367 if (*end != '/') {
2368 if (lmap)
2369 goto name2val;
2370 else
2371 goto garbage;
2372 }
2373
2374 if (!xtables_strtoui(end + 1, &end, mask, 0, UINT32_MAX))
2375 goto bad_val;
2376
2377 if (*end == '\0')
2378 return;
2379
2380 garbage:
2381 xt_params->exit_err(PARAMETER_PROBLEM,
2382 "%s: trailing garbage after value "
2383 "for option \"--%s\".\n",
2384 cb->ext_name, cb->entry->name);
2385
2386 bad_val:
2387 xt_params->exit_err(PARAMETER_PROBLEM,
2388 "%s: bad integer value for option \"--%s\", "
2389 "or out of range.\n",
2390 cb->ext_name, cb->entry->name);
2391
2392 name2val:
2393 *val = xtables_lmap_name2id(lmap, cb->arg);
2394 if ((int)*val == -1)
2395 xt_params->exit_err(PARAMETER_PROBLEM,
2396 "%s: could not map name %s to an integer value "
2397 "for option \"--%s\".\n",
2398 cb->ext_name, cb->arg, cb->entry->name);
2399 }
2400
xtables_print_val_mask(unsigned int val,unsigned int mask,const struct xtables_lmap * lmap)2401 void xtables_print_val_mask(unsigned int val, unsigned int mask,
2402 const struct xtables_lmap *lmap)
2403 {
2404 if (mask != ~0U) {
2405 printf(" 0x%x/0x%x", val, mask);
2406 return;
2407 }
2408
2409 if (lmap) {
2410 const char *name = xtables_lmap_id2name(lmap, val);
2411
2412 if (name) {
2413 printf(" %s", name);
2414 return;
2415 }
2416 }
2417
2418 printf(" 0x%x", val);
2419 }
2420
2421 int kernel_version;
2422
get_kernel_version(void)2423 void get_kernel_version(void)
2424 {
2425 static struct utsname uts;
2426 int x = 0, y = 0, z = 0;
2427
2428 if (uname(&uts) == -1) {
2429 fprintf(stderr, "Unable to retrieve kernel version.\n");
2430 xtables_free_opts(1);
2431 exit(1);
2432 }
2433
2434 sscanf(uts.release, "%d.%d.%d", &x, &y, &z);
2435 kernel_version = LINUX_VERSION(x, y, z);
2436 }
2437
2438 #include <linux/netfilter/nf_tables.h>
2439
2440 enum xt_xlate_type {
2441 XT_XLATE_RULE = 0,
2442 XT_XLATE_SET,
2443 __XT_XLATE_MAX
2444 };
2445
2446 struct xt_xlate {
2447 struct xt_xlate_buf {
2448 char *data;
2449 int size;
2450 int rem;
2451 int off;
2452 } buf[__XT_XLATE_MAX];
2453 char comment[NFT_USERDATA_MAXLEN];
2454 int family;
2455 };
2456
xt_xlate_alloc(int size)2457 struct xt_xlate *xt_xlate_alloc(int size)
2458 {
2459 struct xt_xlate *xl = xtables_malloc(sizeof(struct xt_xlate));
2460 int i;
2461
2462 for (i = 0; i < __XT_XLATE_MAX; i++) {
2463 xl->buf[i].data = xtables_malloc(size);
2464 xl->buf[i].data[0] = '\0';
2465 xl->buf[i].size = size;
2466 xl->buf[i].rem = size;
2467 xl->buf[i].off = 0;
2468 }
2469 xl->comment[0] = '\0';
2470
2471 return xl;
2472 }
2473
xt_xlate_free(struct xt_xlate * xl)2474 void xt_xlate_free(struct xt_xlate *xl)
2475 {
2476 int i;
2477
2478 for (i = 0; i < __XT_XLATE_MAX; i++)
2479 free(xl->buf[i].data);
2480
2481 free(xl);
2482 }
2483
isbrace(char c)2484 static bool isbrace(char c)
2485 {
2486 switch (c) {
2487 case '(':
2488 case ')':
2489 case '{':
2490 case '}':
2491 case '[':
2492 case ']':
2493 return true;
2494 }
2495 return false;
2496 }
2497
__xt_xlate_add(struct xt_xlate * xl,enum xt_xlate_type type,bool space,const char * fmt,va_list ap)2498 static void __xt_xlate_add(struct xt_xlate *xl, enum xt_xlate_type type,
2499 bool space, const char *fmt, va_list ap)
2500 {
2501 struct xt_xlate_buf *buf = &xl->buf[type];
2502 char tmpbuf[1024] = "";
2503 int len;
2504
2505 len = vsnprintf(tmpbuf, 1024, fmt, ap);
2506 if (len < 0 || len >= buf->rem - 1)
2507 xtables_error(RESOURCE_PROBLEM, "OOM");
2508
2509 if (space && buf->off &&
2510 !isspace(buf->data[buf->off - 1]) &&
2511 (isalnum(tmpbuf[0]) || isbrace(tmpbuf[0]))) {
2512 buf->data[buf->off] = ' ';
2513 buf->off++;
2514 buf->rem--;
2515 }
2516 sprintf(buf->data + buf->off, "%s", tmpbuf);
2517 buf->rem -= len;
2518 buf->off += len;
2519 }
2520
xt_xlate_rule_add(struct xt_xlate * xl,const char * fmt,...)2521 void xt_xlate_rule_add(struct xt_xlate *xl, const char *fmt, ...)
2522 {
2523 va_list ap;
2524
2525 va_start(ap, fmt);
2526 __xt_xlate_add(xl, XT_XLATE_RULE, true, fmt, ap);
2527 va_end(ap);
2528 }
2529
xt_xlate_rule_add_nospc(struct xt_xlate * xl,const char * fmt,...)2530 void xt_xlate_rule_add_nospc(struct xt_xlate *xl, const char *fmt, ...)
2531 {
2532 va_list ap;
2533
2534 va_start(ap, fmt);
2535 __xt_xlate_add(xl, XT_XLATE_RULE, false, fmt, ap);
2536 va_end(ap);
2537 }
2538
xt_xlate_set_add(struct xt_xlate * xl,const char * fmt,...)2539 void xt_xlate_set_add(struct xt_xlate *xl, const char *fmt, ...)
2540 {
2541 va_list ap;
2542
2543 va_start(ap, fmt);
2544 __xt_xlate_add(xl, XT_XLATE_SET, true, fmt, ap);
2545 va_end(ap);
2546 }
2547
xt_xlate_set_add_nospc(struct xt_xlate * xl,const char * fmt,...)2548 void xt_xlate_set_add_nospc(struct xt_xlate *xl, const char *fmt, ...)
2549 {
2550 va_list ap;
2551
2552 va_start(ap, fmt);
2553 __xt_xlate_add(xl, XT_XLATE_SET, false, fmt, ap);
2554 va_end(ap);
2555 }
2556
xt_xlate_add_comment(struct xt_xlate * xl,const char * comment)2557 void xt_xlate_add_comment(struct xt_xlate *xl, const char *comment)
2558 {
2559 strncpy(xl->comment, comment, NFT_USERDATA_MAXLEN - 1);
2560 xl->comment[NFT_USERDATA_MAXLEN - 1] = '\0';
2561 }
2562
xt_xlate_get_comment(struct xt_xlate * xl)2563 const char *xt_xlate_get_comment(struct xt_xlate *xl)
2564 {
2565 return xl->comment[0] ? xl->comment : NULL;
2566 }
2567
xl_xlate_set_family(struct xt_xlate * xl,uint8_t family)2568 void xl_xlate_set_family(struct xt_xlate *xl, uint8_t family)
2569 {
2570 xl->family = family;
2571 }
2572
xt_xlate_get_family(struct xt_xlate * xl)2573 uint8_t xt_xlate_get_family(struct xt_xlate *xl)
2574 {
2575 return xl->family;
2576 }
2577
xt_xlate_get(struct xt_xlate * xl)2578 const char *xt_xlate_get(struct xt_xlate *xl)
2579 {
2580 struct xt_xlate_buf *buf = &xl->buf[XT_XLATE_RULE];
2581
2582 while (buf->off && isspace(buf->data[buf->off - 1]))
2583 buf->data[--buf->off] = '\0';
2584
2585 return buf->data;
2586 }
2587
xt_xlate_set_get(struct xt_xlate * xl)2588 const char *xt_xlate_set_get(struct xt_xlate *xl)
2589 {
2590 return xl->buf[XT_XLATE_SET].data;
2591 }
2592