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