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 #if 0 /* Code block below causes memory leak. (Bugs 162925719 and 168688680) */
950 struct xtables_target *clone;
951
952 /* First target of this type: */
953 if (ptr->t == NULL)
954 break;
955
956 /* Second and subsequent clones */
957 clone = xtables_malloc(sizeof(struct xtables_target));
958 memcpy(clone, ptr, sizeof(struct xtables_target));
959 clone->udata = NULL;
960 clone->tflags = 0;
961 /* This is a clone: */
962 clone->next = clone;
963
964 ptr = clone;
965 #endif
966 break;
967 }
968 }
969
970 #ifndef NO_SHARED_LIBS
971 if (!ptr && tryload != XTF_DONT_LOAD && tryload != XTF_DURING_LOAD) {
972 ptr = load_extension(xtables_libdir, afinfo->libprefix,
973 name, true);
974
975 if (ptr == NULL && tryload == XTF_LOAD_MUST_SUCCEED)
976 xt_params->exit_err(PARAMETER_PROBLEM,
977 "Couldn't load target `%s':%s\n",
978 name, strerror(errno));
979 }
980 #else
981 if (ptr && !ptr->loaded) {
982 if (tryload != XTF_DONT_LOAD)
983 ptr->loaded = 1;
984 else
985 ptr = NULL;
986 }
987 if (ptr == NULL && tryload == XTF_LOAD_MUST_SUCCEED) {
988 xt_params->exit_err(PARAMETER_PROBLEM,
989 "Couldn't find target `%s'\n", name);
990 }
991 #endif
992
993 if (ptr)
994 ptr->used = 1;
995 else
996 notargets_hlist_insert(name);
997
998 return ptr;
999 }
1000
1001 struct xtables_target *
xtables_find_target_revision(const char * name,enum xtables_tryload tryload,struct xtables_target * target,int revision)1002 xtables_find_target_revision(const char *name, enum xtables_tryload tryload,
1003 struct xtables_target *target, int revision)
1004 {
1005 if (!target) {
1006 target = xtables_find_target(name, tryload);
1007 if (!target)
1008 return NULL;
1009 }
1010
1011 while (1) {
1012 if (target->revision == revision)
1013 return target;
1014 target = target->next;
1015 if (!target)
1016 return NULL;
1017 if (!extension_cmp(name, target->name, target->family))
1018 return NULL;
1019 }
1020 }
1021
xtables_compatible_revision(const char * name,uint8_t revision,int opt)1022 int xtables_compatible_revision(const char *name, uint8_t revision, int opt)
1023 {
1024 struct xt_get_revision rev;
1025 socklen_t s = sizeof(rev);
1026 int max_rev, sockfd;
1027
1028 sockfd = socket(afinfo->family, SOCK_RAW | SOCK_CLOEXEC, IPPROTO_RAW);
1029 if (sockfd < 0) {
1030 if (errno == EPERM) {
1031 /* revision 0 is always supported. */
1032 if (revision != 0)
1033 fprintf(stderr, "%s: Could not determine whether "
1034 "revision %u is supported, "
1035 "assuming it is.\n",
1036 name, revision);
1037 return 1;
1038 }
1039 fprintf(stderr, "Could not open socket to kernel: %s\n",
1040 strerror(errno));
1041 exit(1);
1042 }
1043
1044 xtables_load_ko(xtables_modprobe_program, true);
1045
1046 strncpy(rev.name, name, XT_EXTENSION_MAXNAMELEN - 1);
1047 rev.name[XT_EXTENSION_MAXNAMELEN - 1] = '\0';
1048 rev.revision = revision;
1049
1050 max_rev = getsockopt(sockfd, afinfo->ipproto, opt, &rev, &s);
1051 if (max_rev < 0) {
1052 /* Definitely don't support this? */
1053 if (errno == ENOENT || errno == EPROTONOSUPPORT) {
1054 close(sockfd);
1055 /* Pretend revision 0 support for better error messaging */
1056 if (revision == 0)
1057 fprintf(stderr,
1058 "Warning: Extension %s revision 0 not supported, missing kernel module?\n",
1059 name);
1060 return (revision == 0);
1061 } else if (errno == ENOPROTOOPT) {
1062 close(sockfd);
1063 /* Assume only revision 0 support (old kernel) */
1064 return (revision == 0);
1065 } else {
1066 fprintf(stderr, "getsockopt failed strangely: %s\n",
1067 strerror(errno));
1068 exit(1);
1069 }
1070 }
1071 close(sockfd);
1072 return 1;
1073 }
1074
1075
compatible_match_revision(const char * name,uint8_t revision)1076 static int compatible_match_revision(const char *name, uint8_t revision)
1077 {
1078 return xt_params->compat_rev(name, revision, afinfo->so_rev_match);
1079 }
1080
compatible_target_revision(const char * name,uint8_t revision)1081 static int compatible_target_revision(const char *name, uint8_t revision)
1082 {
1083 return xt_params->compat_rev(name, revision, afinfo->so_rev_target);
1084 }
1085
xtables_check_options(const char * name,const struct option * opt)1086 static void xtables_check_options(const char *name, const struct option *opt)
1087 {
1088 for (; opt->name != NULL; ++opt)
1089 if (opt->val < 0 || opt->val >= XT_OPTION_OFFSET_SCALE) {
1090 fprintf(stderr, "%s: Extension %s uses invalid "
1091 "option value %d\n",xt_params->program_name,
1092 name, opt->val);
1093 exit(1);
1094 }
1095 }
1096
1097 static int xtables_match_prefer(const struct xtables_match *a,
1098 const struct xtables_match *b);
1099
xtables_register_match(struct xtables_match * me)1100 void xtables_register_match(struct xtables_match *me)
1101 {
1102 struct xtables_match **pos;
1103 bool seen_myself = false;
1104
1105 if (me->next) {
1106 fprintf(stderr, "%s: match \"%s\" already registered\n",
1107 xt_params->program_name, me->name);
1108 exit(1);
1109 }
1110
1111 if (me->version == NULL) {
1112 fprintf(stderr, "%s: match %s<%u> is missing a version\n",
1113 xt_params->program_name, me->name, me->revision);
1114 exit(1);
1115 }
1116
1117 if (me->size != XT_ALIGN(me->size)) {
1118 fprintf(stderr, "%s: match \"%s\" has invalid size %u.\n",
1119 xt_params->program_name, me->name,
1120 (unsigned int)me->size);
1121 exit(1);
1122 }
1123
1124 if (strcmp(me->version, XTABLES_VERSION) != 0) {
1125 fprintf(stderr, "%s: match \"%s\" has version \"%s\", "
1126 "but \"%s\" is required.\n",
1127 xt_params->program_name, me->name,
1128 me->version, XTABLES_VERSION);
1129 exit(1);
1130 }
1131
1132 if (strlen(me->name) >= XT_EXTENSION_MAXNAMELEN) {
1133 fprintf(stderr, "%s: match `%s' has invalid name\n",
1134 xt_params->program_name, me->name);
1135 exit(1);
1136 }
1137
1138 if (me->real_name && strlen(me->real_name) >= XT_EXTENSION_MAXNAMELEN) {
1139 fprintf(stderr, "%s: match `%s' has invalid real name\n",
1140 xt_params->program_name, me->real_name);
1141 exit(1);
1142 }
1143
1144 if (me->family >= NPROTO) {
1145 fprintf(stderr,
1146 "%s: BUG: match %s has invalid protocol family\n",
1147 xt_params->program_name, me->name);
1148 exit(1);
1149 }
1150
1151 if (me->x6_options != NULL)
1152 xtables_option_metavalidate(me->name, me->x6_options);
1153 if (me->extra_opts != NULL)
1154 xtables_check_options(me->name, me->extra_opts);
1155
1156 /* order into linked list of matches pending full registration */
1157 for (pos = &xtables_pending_matches; *pos; pos = &(*pos)->next) {
1158 /* group by name and family */
1159 if (strcmp(me->name, (*pos)->name) ||
1160 me->family != (*pos)->family) {
1161 if (seen_myself)
1162 break; /* end of own group, append to it */
1163 continue;
1164 }
1165 /* found own group */
1166 seen_myself = true;
1167 if (xtables_match_prefer(me, *pos) >= 0)
1168 break; /* put preferred items first in group */
1169 }
1170 /* if own group was not found, prepend item */
1171 if (!*pos && !seen_myself)
1172 pos = &xtables_pending_matches;
1173
1174 me->next = *pos;
1175 *pos = me;
1176 #ifdef DEBUG
1177 #define printmatch(m, sfx) \
1178 printf("match %s (", (m)->name); \
1179 if ((m)->real_name) \
1180 printf("alias %s, ", (m)->real_name); \
1181 printf("family %d, revision %d)%s", (m)->family, (m)->revision, sfx);
1182
1183 {
1184 int i = 1;
1185
1186 printf("%s: inserted ", __func__);
1187 printmatch(me, ":\n");
1188 for (pos = &xtables_pending_matches; *pos; pos = &(*pos)->next) {
1189 printf("pos %d:\t", i++);
1190 printmatch(*pos, "\n");
1191 }
1192 }
1193 #endif
1194 }
1195
1196 /**
1197 * Compare two actions for their preference
1198 * @a: one action
1199 * @b: another
1200 *
1201 * Like strcmp, returns a negative number if @a is less preferred than @b,
1202 * positive number if @a is more preferred than @b, or zero if equally
1203 * preferred.
1204 */
1205 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)1206 xtables_mt_prefer(bool a_alias, unsigned int a_rev, unsigned int a_fam,
1207 bool b_alias, unsigned int b_rev, unsigned int b_fam)
1208 {
1209 /*
1210 * Alias ranks higher than no alias.
1211 * (We want the new action to be used whenever possible.)
1212 */
1213 if (!a_alias && b_alias)
1214 return -1;
1215 if (a_alias && !b_alias)
1216 return 1;
1217
1218 /* Higher revision ranks higher. */
1219 if (a_rev < b_rev)
1220 return -1;
1221 if (a_rev > b_rev)
1222 return 1;
1223
1224 /* NFPROTO_<specific> ranks higher than NFPROTO_UNSPEC. */
1225 if (a_fam == NFPROTO_UNSPEC && b_fam != NFPROTO_UNSPEC)
1226 return -1;
1227 if (a_fam != NFPROTO_UNSPEC && b_fam == NFPROTO_UNSPEC)
1228 return 1;
1229
1230 /* Must be the same thing. */
1231 return 0;
1232 }
1233
xtables_match_prefer(const struct xtables_match * a,const struct xtables_match * b)1234 static int xtables_match_prefer(const struct xtables_match *a,
1235 const struct xtables_match *b)
1236 {
1237 return xtables_mt_prefer(a->real_name != NULL,
1238 a->revision, a->family,
1239 b->real_name != NULL,
1240 b->revision, b->family);
1241 }
1242
xtables_target_prefer(const struct xtables_target * a,const struct xtables_target * b)1243 static int xtables_target_prefer(const struct xtables_target *a,
1244 const struct xtables_target *b)
1245 {
1246 /*
1247 * Note that if x->real_name==NULL, it will be set to x->name in
1248 * xtables_register_*; the direct pointer comparison here is therefore
1249 * legitimate to detect an alias.
1250 */
1251 return xtables_mt_prefer(a->real_name != NULL,
1252 a->revision, a->family,
1253 b->real_name != NULL,
1254 b->revision, b->family);
1255 }
1256
xtables_fully_register_pending_match(struct xtables_match * me,struct xtables_match * prev)1257 static bool xtables_fully_register_pending_match(struct xtables_match *me,
1258 struct xtables_match *prev)
1259 {
1260 struct xtables_match **i;
1261 const char *rn;
1262
1263 /* See if new match can be used. */
1264 rn = (me->real_name != NULL) ? me->real_name : me->name;
1265 if (!compatible_match_revision(rn, me->revision))
1266 return false;
1267
1268 if (!prev) {
1269 /* Append to list. */
1270 for (i = &xtables_matches; *i; i = &(*i)->next);
1271 } else {
1272 /* Append it */
1273 i = &prev->next;
1274 prev = prev->next;
1275 }
1276
1277 me->next = prev;
1278 *i = me;
1279
1280 me->m = NULL;
1281 me->mflags = 0;
1282
1283 return true;
1284 }
1285
xtables_register_matches(struct xtables_match * match,unsigned int n)1286 void xtables_register_matches(struct xtables_match *match, unsigned int n)
1287 {
1288 int i;
1289
1290 for (i = 0; i < n; i++)
1291 xtables_register_match(&match[i]);
1292 }
1293
xtables_register_target(struct xtables_target * me)1294 void xtables_register_target(struct xtables_target *me)
1295 {
1296 struct xtables_target **pos;
1297 bool seen_myself = false;
1298
1299 if (me->next) {
1300 fprintf(stderr, "%s: target \"%s\" already registered\n",
1301 xt_params->program_name, me->name);
1302 exit(1);
1303 }
1304
1305 if (me->version == NULL) {
1306 fprintf(stderr, "%s: target %s<%u> is missing a version\n",
1307 xt_params->program_name, me->name, me->revision);
1308 exit(1);
1309 }
1310
1311 if (me->size != XT_ALIGN(me->size)) {
1312 fprintf(stderr, "%s: target \"%s\" has invalid size %u.\n",
1313 xt_params->program_name, me->name,
1314 (unsigned int)me->size);
1315 exit(1);
1316 }
1317
1318 if (strcmp(me->version, XTABLES_VERSION) != 0) {
1319 fprintf(stderr, "%s: target \"%s\" has version \"%s\", "
1320 "but \"%s\" is required.\n",
1321 xt_params->program_name, me->name,
1322 me->version, XTABLES_VERSION);
1323 exit(1);
1324 }
1325
1326 if (strlen(me->name) >= XT_EXTENSION_MAXNAMELEN) {
1327 fprintf(stderr, "%s: target `%s' has invalid name\n",
1328 xt_params->program_name, me->name);
1329 exit(1);
1330 }
1331
1332 if (me->real_name && strlen(me->real_name) >= XT_EXTENSION_MAXNAMELEN) {
1333 fprintf(stderr, "%s: target `%s' has invalid real name\n",
1334 xt_params->program_name, me->real_name);
1335 exit(1);
1336 }
1337
1338 if (me->family >= NPROTO) {
1339 fprintf(stderr,
1340 "%s: BUG: target %s has invalid protocol family\n",
1341 xt_params->program_name, me->name);
1342 exit(1);
1343 }
1344
1345 if (me->x6_options != NULL)
1346 xtables_option_metavalidate(me->name, me->x6_options);
1347 if (me->extra_opts != NULL)
1348 xtables_check_options(me->name, me->extra_opts);
1349
1350 /* ignore not interested target */
1351 if (me->family != afinfo->family && me->family != AF_UNSPEC)
1352 return;
1353
1354 /* order into linked list of targets pending full registration */
1355 for (pos = &xtables_pending_targets; *pos; pos = &(*pos)->next) {
1356 /* group by name */
1357 if (!extension_cmp(me->name, (*pos)->name, (*pos)->family)) {
1358 if (seen_myself)
1359 break; /* end of own group, append to it */
1360 continue;
1361 }
1362 /* found own group */
1363 seen_myself = true;
1364 if (xtables_target_prefer(me, *pos) >= 0)
1365 break; /* put preferred items first in group */
1366 }
1367 /* if own group was not found, prepend item */
1368 if (!*pos && !seen_myself)
1369 pos = &xtables_pending_targets;
1370
1371 me->next = *pos;
1372 *pos = me;
1373 #ifdef DEBUG
1374 printf("%s: inserted target %s (family %d, revision %d):\n",
1375 __func__, me->name, me->family, me->revision);
1376 for (pos = &xtables_pending_targets; *pos; pos = &(*pos)->next) {
1377 printf("%s:\ttarget %s (family %d, revision %d)\n", __func__,
1378 (*pos)->name, (*pos)->family, (*pos)->revision);
1379 }
1380 #endif
1381 }
1382
xtables_fully_register_pending_target(struct xtables_target * me,struct xtables_target * prev)1383 static bool xtables_fully_register_pending_target(struct xtables_target *me,
1384 struct xtables_target *prev)
1385 {
1386 struct xtables_target **i;
1387 const char *rn;
1388
1389 if (strcmp(me->name, "standard") != 0) {
1390 /* See if new target can be used. */
1391 rn = (me->real_name != NULL) ? me->real_name : me->name;
1392 if (!compatible_target_revision(rn, me->revision))
1393 return false;
1394 }
1395
1396 if (!prev) {
1397 /* Prepend to list. */
1398 i = &xtables_targets;
1399 prev = xtables_targets;
1400 } else {
1401 /* Append it */
1402 i = &prev->next;
1403 prev = prev->next;
1404 }
1405
1406 me->next = prev;
1407 *i = me;
1408
1409 me->t = NULL;
1410 me->tflags = 0;
1411
1412 return true;
1413 }
1414
xtables_register_targets(struct xtables_target * target,unsigned int n)1415 void xtables_register_targets(struct xtables_target *target, unsigned int n)
1416 {
1417 int i;
1418
1419 for (i = 0; i < n; i++)
1420 xtables_register_target(&target[i]);
1421 }
1422
1423 /* receives a list of xtables_rule_match, release them */
xtables_rule_matches_free(struct xtables_rule_match ** matches)1424 void xtables_rule_matches_free(struct xtables_rule_match **matches)
1425 {
1426 struct xtables_rule_match *matchp, *tmp;
1427
1428 for (matchp = *matches; matchp;) {
1429 tmp = matchp->next;
1430 if (matchp->match->m) {
1431 free(matchp->match->m);
1432 matchp->match->m = NULL;
1433 }
1434 if (matchp->match->udata_size) {
1435 free(matchp->match->udata);
1436 matchp->match->udata = NULL;
1437 }
1438 if (matchp->match == matchp->match->next) {
1439 free(matchp->match);
1440 matchp->match = NULL;
1441 }
1442 free(matchp);
1443 matchp = tmp;
1444 }
1445
1446 *matches = NULL;
1447 }
1448
1449 /**
1450 * xtables_param_act - act on condition
1451 * @status: a constant from enum xtables_exittype
1452 *
1453 * %XTF_ONLY_ONCE: print error message that option may only be used once.
1454 * @p1: module name (e.g. "mark")
1455 * @p2(...): option in conflict (e.g. "--mark")
1456 * @p3(...): condition to match on (see extensions/ for examples)
1457 *
1458 * %XTF_NO_INVERT: option does not support inversion
1459 * @p1: module name
1460 * @p2: option in conflict
1461 * @p3: condition to match on
1462 *
1463 * %XTF_BAD_VALUE: bad value for option
1464 * @p1: module name
1465 * @p2: option with which the problem occurred (e.g. "--mark")
1466 * @p3: string the user passed in (e.g. "99999999999999")
1467 *
1468 * %XTF_ONE_ACTION: two mutually exclusive actions have been specified
1469 * @p1: module name
1470 *
1471 * Displays an error message and exits the program.
1472 */
xtables_param_act(unsigned int status,const char * p1,...)1473 void xtables_param_act(unsigned int status, const char *p1, ...)
1474 {
1475 const char *p2, *p3;
1476 va_list args;
1477 bool b;
1478
1479 va_start(args, p1);
1480
1481 switch (status) {
1482 case XTF_ONLY_ONCE:
1483 p2 = va_arg(args, const char *);
1484 b = va_arg(args, unsigned int);
1485 if (!b) {
1486 va_end(args);
1487 return;
1488 }
1489 xt_params->exit_err(PARAMETER_PROBLEM,
1490 "%s: \"%s\" option may only be specified once",
1491 p1, p2);
1492 break;
1493 case XTF_NO_INVERT:
1494 p2 = va_arg(args, const char *);
1495 b = va_arg(args, unsigned int);
1496 if (!b) {
1497 va_end(args);
1498 return;
1499 }
1500 xt_params->exit_err(PARAMETER_PROBLEM,
1501 "%s: \"%s\" option cannot be inverted", p1, p2);
1502 break;
1503 case XTF_BAD_VALUE:
1504 p2 = va_arg(args, const char *);
1505 p3 = va_arg(args, const char *);
1506 xt_params->exit_err(PARAMETER_PROBLEM,
1507 "%s: Bad value for \"%s\" option: \"%s\"",
1508 p1, p2, p3);
1509 break;
1510 case XTF_ONE_ACTION:
1511 b = va_arg(args, unsigned int);
1512 if (!b) {
1513 va_end(args);
1514 return;
1515 }
1516 xt_params->exit_err(PARAMETER_PROBLEM,
1517 "%s: At most one action is possible", p1);
1518 break;
1519 default:
1520 xt_params->exit_err(status, p1, args);
1521 break;
1522 }
1523
1524 va_end(args);
1525 }
1526
xtables_ipaddr_to_numeric(const struct in_addr * addrp)1527 const char *xtables_ipaddr_to_numeric(const struct in_addr *addrp)
1528 {
1529 static char buf[INET_ADDRSTRLEN];
1530
1531 return inet_ntop(AF_INET, addrp, buf, sizeof(buf));
1532 }
1533
ipaddr_to_host(const struct in_addr * addr)1534 static const char *ipaddr_to_host(const struct in_addr *addr)
1535 {
1536 static char hostname[NI_MAXHOST];
1537 struct sockaddr_in saddr = {
1538 .sin_family = AF_INET,
1539 .sin_addr = *addr,
1540 };
1541 int err;
1542
1543
1544 err = getnameinfo((const void *)&saddr, sizeof(struct sockaddr_in),
1545 hostname, sizeof(hostname) - 1, NULL, 0, 0);
1546 if (err != 0)
1547 return NULL;
1548
1549 return hostname;
1550 }
1551
ipaddr_to_network(const struct in_addr * addr)1552 static const char *ipaddr_to_network(const struct in_addr *addr)
1553 {
1554 struct netent *net;
1555
1556 if ((net = getnetbyaddr(ntohl(addr->s_addr), AF_INET)) != NULL)
1557 return net->n_name;
1558
1559 return NULL;
1560 }
1561
xtables_ipaddr_to_anyname(const struct in_addr * addr)1562 const char *xtables_ipaddr_to_anyname(const struct in_addr *addr)
1563 {
1564 const char *name;
1565
1566 if ((name = ipaddr_to_host(addr)) != NULL ||
1567 (name = ipaddr_to_network(addr)) != NULL)
1568 return name;
1569
1570 return xtables_ipaddr_to_numeric(addr);
1571 }
1572
xtables_ipmask_to_cidr(const struct in_addr * mask)1573 int xtables_ipmask_to_cidr(const struct in_addr *mask)
1574 {
1575 uint32_t maskaddr, bits;
1576 int i;
1577
1578 maskaddr = ntohl(mask->s_addr);
1579
1580 for (i = 32, bits = (uint32_t)-1; i >= 0; i--, bits <<= 1) {
1581 if (bits == maskaddr)
1582 return i;
1583 }
1584
1585 /* this mask cannot be converted to CIDR notation */
1586 return -1;
1587 }
1588
xtables_ipmask_to_numeric(const struct in_addr * mask)1589 const char *xtables_ipmask_to_numeric(const struct in_addr *mask)
1590 {
1591 static char buf[INET_ADDRSTRLEN + 1];
1592 uint32_t cidr;
1593
1594 cidr = xtables_ipmask_to_cidr(mask);
1595 if (cidr == (unsigned int)-1) {
1596 /* mask was not a decent combination of 1's and 0's */
1597 buf[0] = '/';
1598 inet_ntop(AF_INET, mask, buf + 1, sizeof(buf) - 1);
1599 return buf;
1600 } else if (cidr == 32) {
1601 /* we don't want to see "/32" */
1602 return "";
1603 }
1604
1605 sprintf(buf, "/%d", cidr);
1606 return buf;
1607 }
1608
__numeric_to_ipaddr(const char * dotted,bool is_mask)1609 static struct in_addr *__numeric_to_ipaddr(const char *dotted, bool is_mask)
1610 {
1611 static struct in_addr addr;
1612 unsigned char *addrp;
1613 unsigned int onebyte;
1614 char buf[20], *p, *q;
1615 int i;
1616
1617 /* copy dotted string, because we need to modify it */
1618 strncpy(buf, dotted, sizeof(buf) - 1);
1619 buf[sizeof(buf) - 1] = '\0';
1620 addrp = (void *)&addr.s_addr;
1621
1622 p = buf;
1623 for (i = 0; i < 3; ++i) {
1624 if ((q = strchr(p, '.')) == NULL) {
1625 if (is_mask)
1626 return NULL;
1627
1628 /* autocomplete, this is a network address */
1629 if (!xtables_strtoui(p, NULL, &onebyte, 0, UINT8_MAX))
1630 return NULL;
1631
1632 addrp[i] = onebyte;
1633 while (i < 3)
1634 addrp[++i] = 0;
1635
1636 return &addr;
1637 }
1638
1639 *q = '\0';
1640 if (!xtables_strtoui(p, NULL, &onebyte, 0, UINT8_MAX))
1641 return NULL;
1642
1643 addrp[i] = onebyte;
1644 p = q + 1;
1645 }
1646
1647 /* we have checked 3 bytes, now we check the last one */
1648 if (!xtables_strtoui(p, NULL, &onebyte, 0, UINT8_MAX))
1649 return NULL;
1650
1651 addrp[3] = onebyte;
1652 return &addr;
1653 }
1654
xtables_numeric_to_ipaddr(const char * dotted)1655 struct in_addr *xtables_numeric_to_ipaddr(const char *dotted)
1656 {
1657 return __numeric_to_ipaddr(dotted, false);
1658 }
1659
xtables_numeric_to_ipmask(const char * dotted)1660 struct in_addr *xtables_numeric_to_ipmask(const char *dotted)
1661 {
1662 return __numeric_to_ipaddr(dotted, true);
1663 }
1664
network_to_ipaddr(const char * name)1665 static struct in_addr *network_to_ipaddr(const char *name)
1666 {
1667 static struct in_addr addr;
1668 struct netent *net;
1669
1670 if ((net = getnetbyname(name)) != NULL) {
1671 if (net->n_addrtype != AF_INET)
1672 return NULL;
1673 addr.s_addr = htonl(net->n_net);
1674 return &addr;
1675 }
1676
1677 return NULL;
1678 }
1679
host_to_ipaddr(const char * name,unsigned int * naddr)1680 static struct in_addr *host_to_ipaddr(const char *name, unsigned int *naddr)
1681 {
1682 struct in_addr *addr;
1683 struct addrinfo hints;
1684 struct addrinfo *res, *p;
1685 int err;
1686 unsigned int i;
1687
1688 memset(&hints, 0, sizeof(hints));
1689 hints.ai_family = AF_INET;
1690 hints.ai_socktype = SOCK_RAW;
1691
1692 *naddr = 0;
1693 err = getaddrinfo(name, NULL, &hints, &res);
1694 if (err != 0)
1695 return NULL;
1696 for (p = res; p != NULL; p = p->ai_next)
1697 ++*naddr;
1698 addr = xtables_calloc(*naddr, sizeof(struct in_addr));
1699 for (i = 0, p = res; p != NULL; p = p->ai_next)
1700 memcpy(&addr[i++],
1701 &((const struct sockaddr_in *)p->ai_addr)->sin_addr,
1702 sizeof(struct in_addr));
1703 freeaddrinfo(res);
1704 return addr;
1705 }
1706
1707 static struct in_addr *
ipparse_hostnetwork(const char * name,unsigned int * naddrs)1708 ipparse_hostnetwork(const char *name, unsigned int *naddrs)
1709 {
1710 struct in_addr *addrptmp, *addrp;
1711
1712 if ((addrptmp = xtables_numeric_to_ipaddr(name)) != NULL ||
1713 (addrptmp = network_to_ipaddr(name)) != NULL) {
1714 addrp = xtables_malloc(sizeof(struct in_addr));
1715 memcpy(addrp, addrptmp, sizeof(*addrp));
1716 *naddrs = 1;
1717 return addrp;
1718 }
1719 if ((addrptmp = host_to_ipaddr(name, naddrs)) != NULL)
1720 return addrptmp;
1721
1722 xt_params->exit_err(PARAMETER_PROBLEM, "host/network `%s' not found", name);
1723 }
1724
parse_ipmask(const char * mask)1725 static struct in_addr *parse_ipmask(const char *mask)
1726 {
1727 static struct in_addr maskaddr;
1728 struct in_addr *addrp;
1729 unsigned int bits;
1730
1731 if (mask == NULL) {
1732 /* no mask at all defaults to 32 bits */
1733 maskaddr.s_addr = 0xFFFFFFFF;
1734 return &maskaddr;
1735 }
1736 if ((addrp = xtables_numeric_to_ipmask(mask)) != NULL)
1737 /* dotted_to_addr already returns a network byte order addr */
1738 return addrp;
1739 if (!xtables_strtoui(mask, NULL, &bits, 0, 32))
1740 xt_params->exit_err(PARAMETER_PROBLEM,
1741 "invalid mask `%s' specified", mask);
1742 if (bits != 0) {
1743 maskaddr.s_addr = htonl(0xFFFFFFFF << (32 - bits));
1744 return &maskaddr;
1745 }
1746
1747 maskaddr.s_addr = 0U;
1748 return &maskaddr;
1749 }
1750
xtables_ipparse_multiple(const char * name,struct in_addr ** addrpp,struct in_addr ** maskpp,unsigned int * naddrs)1751 void xtables_ipparse_multiple(const char *name, struct in_addr **addrpp,
1752 struct in_addr **maskpp, unsigned int *naddrs)
1753 {
1754 struct in_addr *addrp;
1755 char buf[256], *p, *next;
1756 unsigned int len, i, j, n, count = 1;
1757 const char *loop = name;
1758
1759 while ((loop = strchr(loop, ',')) != NULL) {
1760 ++count;
1761 ++loop; /* skip ',' */
1762 }
1763
1764 *addrpp = xtables_malloc(sizeof(struct in_addr) * count);
1765 *maskpp = xtables_malloc(sizeof(struct in_addr) * count);
1766
1767 loop = name;
1768
1769 for (i = 0; i < count; ++i) {
1770 while (isspace(*loop))
1771 ++loop;
1772 next = strchr(loop, ',');
1773 if (next != NULL)
1774 len = next - loop;
1775 else
1776 len = strlen(loop);
1777 if (len > sizeof(buf) - 1)
1778 xt_params->exit_err(PARAMETER_PROBLEM,
1779 "Hostname too long");
1780
1781 strncpy(buf, loop, len);
1782 buf[len] = '\0';
1783 if ((p = strrchr(buf, '/')) != NULL) {
1784 *p = '\0';
1785 addrp = parse_ipmask(p + 1);
1786 } else {
1787 addrp = parse_ipmask(NULL);
1788 }
1789 memcpy(*maskpp + i, addrp, sizeof(*addrp));
1790
1791 /* if a null mask is given, the name is ignored, like in "any/0" */
1792 if ((*maskpp + i)->s_addr == 0)
1793 /*
1794 * A bit pointless to process multiple addresses
1795 * in this case...
1796 */
1797 strcpy(buf, "0.0.0.0");
1798
1799 addrp = ipparse_hostnetwork(buf, &n);
1800 if (n > 1) {
1801 count += n - 1;
1802 *addrpp = xtables_realloc(*addrpp,
1803 sizeof(struct in_addr) * count);
1804 *maskpp = xtables_realloc(*maskpp,
1805 sizeof(struct in_addr) * count);
1806 for (j = 0; j < n; ++j)
1807 /* for each new addr */
1808 memcpy(*addrpp + i + j, addrp + j,
1809 sizeof(*addrp));
1810 for (j = 1; j < n; ++j)
1811 /* for each new mask */
1812 memcpy(*maskpp + i + j, *maskpp + i,
1813 sizeof(*addrp));
1814 i += n - 1;
1815 } else {
1816 memcpy(*addrpp + i, addrp, sizeof(*addrp));
1817 }
1818 /* free what ipparse_hostnetwork had allocated: */
1819 free(addrp);
1820 if (next == NULL)
1821 break;
1822 loop = next + 1;
1823 }
1824 *naddrs = count;
1825 for (i = 0; i < count; ++i)
1826 (*addrpp+i)->s_addr &= (*maskpp+i)->s_addr;
1827 }
1828
1829
1830 /**
1831 * xtables_ipparse_any - transform arbitrary name to in_addr
1832 *
1833 * Possible inputs (pseudo regex):
1834 * m{^($hostname|$networkname|$ipaddr)(/$mask)?}
1835 * "1.2.3.4/5", "1.2.3.4", "hostname", "networkname"
1836 */
xtables_ipparse_any(const char * name,struct in_addr ** addrpp,struct in_addr * maskp,unsigned int * naddrs)1837 void xtables_ipparse_any(const char *name, struct in_addr **addrpp,
1838 struct in_addr *maskp, unsigned int *naddrs)
1839 {
1840 unsigned int i, j, k, n;
1841 struct in_addr *addrp;
1842 char buf[256], *p;
1843
1844 strncpy(buf, name, sizeof(buf) - 1);
1845 buf[sizeof(buf) - 1] = '\0';
1846 if ((p = strrchr(buf, '/')) != NULL) {
1847 *p = '\0';
1848 addrp = parse_ipmask(p + 1);
1849 } else {
1850 addrp = parse_ipmask(NULL);
1851 }
1852 memcpy(maskp, addrp, sizeof(*maskp));
1853
1854 /* if a null mask is given, the name is ignored, like in "any/0" */
1855 if (maskp->s_addr == 0U)
1856 strcpy(buf, "0.0.0.0");
1857
1858 addrp = *addrpp = ipparse_hostnetwork(buf, naddrs);
1859 n = *naddrs;
1860 for (i = 0, j = 0; i < n; ++i) {
1861 addrp[j++].s_addr &= maskp->s_addr;
1862 for (k = 0; k < j - 1; ++k)
1863 if (addrp[k].s_addr == addrp[j-1].s_addr) {
1864 /*
1865 * Nuke the dup by copying an address from the
1866 * tail here, and check the current position
1867 * again (--j).
1868 */
1869 memcpy(&addrp[--j], &addrp[--*naddrs],
1870 sizeof(struct in_addr));
1871 break;
1872 }
1873 }
1874 }
1875
xtables_ip6addr_to_numeric(const struct in6_addr * addrp)1876 const char *xtables_ip6addr_to_numeric(const struct in6_addr *addrp)
1877 {
1878 static char buf[INET6_ADDRSTRLEN];
1879
1880 return inet_ntop(AF_INET6, addrp, buf, sizeof(buf));
1881 }
1882
ip6addr_to_host(const struct in6_addr * addr)1883 static const char *ip6addr_to_host(const struct in6_addr *addr)
1884 {
1885 static char hostname[NI_MAXHOST];
1886 struct sockaddr_in6 saddr;
1887 int err;
1888
1889 memset(&saddr, 0, sizeof(struct sockaddr_in6));
1890 memcpy(&saddr.sin6_addr, addr, sizeof(*addr));
1891 saddr.sin6_family = AF_INET6;
1892
1893 err = getnameinfo((const void *)&saddr, sizeof(struct sockaddr_in6),
1894 hostname, sizeof(hostname) - 1, NULL, 0, 0);
1895 if (err != 0)
1896 return NULL;
1897
1898 return hostname;
1899 }
1900
xtables_ip6addr_to_anyname(const struct in6_addr * addr)1901 const char *xtables_ip6addr_to_anyname(const struct in6_addr *addr)
1902 {
1903 const char *name;
1904
1905 if ((name = ip6addr_to_host(addr)) != NULL)
1906 return name;
1907
1908 return xtables_ip6addr_to_numeric(addr);
1909 }
1910
xtables_ip6mask_to_cidr(const struct in6_addr * k)1911 int xtables_ip6mask_to_cidr(const struct in6_addr *k)
1912 {
1913 unsigned int bits = 0;
1914 uint32_t a, b, c, d;
1915
1916 a = ntohl(k->s6_addr32[0]);
1917 b = ntohl(k->s6_addr32[1]);
1918 c = ntohl(k->s6_addr32[2]);
1919 d = ntohl(k->s6_addr32[3]);
1920 while (a & 0x80000000U) {
1921 ++bits;
1922 a <<= 1;
1923 a |= (b >> 31) & 1;
1924 b <<= 1;
1925 b |= (c >> 31) & 1;
1926 c <<= 1;
1927 c |= (d >> 31) & 1;
1928 d <<= 1;
1929 }
1930 if (a != 0 || b != 0 || c != 0 || d != 0)
1931 return -1;
1932 return bits;
1933 }
1934
xtables_ip6mask_to_numeric(const struct in6_addr * addrp)1935 const char *xtables_ip6mask_to_numeric(const struct in6_addr *addrp)
1936 {
1937 static char buf[INET6_ADDRSTRLEN + 1];
1938 int l = xtables_ip6mask_to_cidr(addrp);
1939
1940 if (l == -1) {
1941 strcpy(buf, "/");
1942 inet_ntop(AF_INET6, addrp, buf + 1, sizeof(buf) - 1);
1943 return buf;
1944 }
1945 /* we don't want to see "/128" */
1946 if (l == 128)
1947 return "";
1948 else
1949 sprintf(buf, "/%d", l);
1950 return buf;
1951 }
1952
xtables_numeric_to_ip6addr(const char * num)1953 struct in6_addr *xtables_numeric_to_ip6addr(const char *num)
1954 {
1955 static struct in6_addr ap;
1956
1957 if (inet_pton(AF_INET6, num, &ap) == 1)
1958 return ≈
1959
1960 return NULL;
1961 }
1962
1963 static struct in6_addr *
host_to_ip6addr(const char * name,unsigned int * naddr)1964 host_to_ip6addr(const char *name, unsigned int *naddr)
1965 {
1966 struct in6_addr *addr;
1967 struct addrinfo hints;
1968 struct addrinfo *res, *p;
1969 int err;
1970 unsigned int i;
1971
1972 memset(&hints, 0, sizeof(hints));
1973 hints.ai_family = AF_INET6;
1974 hints.ai_socktype = SOCK_RAW;
1975
1976 *naddr = 0;
1977 err = getaddrinfo(name, NULL, &hints, &res);
1978 if (err != 0)
1979 return NULL;
1980 /* Find length of address chain */
1981 for (p = res; p != NULL; p = p->ai_next)
1982 ++*naddr;
1983 /* Copy each element of the address chain */
1984 addr = xtables_calloc(*naddr, sizeof(struct in6_addr));
1985 for (i = 0, p = res; p != NULL; p = p->ai_next)
1986 memcpy(&addr[i++],
1987 &((const struct sockaddr_in6 *)p->ai_addr)->sin6_addr,
1988 sizeof(struct in6_addr));
1989 freeaddrinfo(res);
1990 return addr;
1991 }
1992
network_to_ip6addr(const char * name)1993 static struct in6_addr *network_to_ip6addr(const char *name)
1994 {
1995 /* abort();*/
1996 /* TODO: not implemented yet, but the exception breaks the
1997 * name resolvation */
1998 return NULL;
1999 }
2000
2001 static struct in6_addr *
ip6parse_hostnetwork(const char * name,unsigned int * naddrs)2002 ip6parse_hostnetwork(const char *name, unsigned int *naddrs)
2003 {
2004 struct in6_addr *addrp, *addrptmp;
2005
2006 if ((addrptmp = xtables_numeric_to_ip6addr(name)) != NULL ||
2007 (addrptmp = network_to_ip6addr(name)) != NULL) {
2008 addrp = xtables_malloc(sizeof(struct in6_addr));
2009 memcpy(addrp, addrptmp, sizeof(*addrp));
2010 *naddrs = 1;
2011 return addrp;
2012 }
2013 if ((addrp = host_to_ip6addr(name, naddrs)) != NULL)
2014 return addrp;
2015
2016 xt_params->exit_err(PARAMETER_PROBLEM, "host/network `%s' not found", name);
2017 }
2018
parse_ip6mask(char * mask)2019 static struct in6_addr *parse_ip6mask(char *mask)
2020 {
2021 static struct in6_addr maskaddr;
2022 struct in6_addr *addrp;
2023 unsigned int bits;
2024
2025 if (mask == NULL) {
2026 /* no mask at all defaults to 128 bits */
2027 memset(&maskaddr, 0xff, sizeof maskaddr);
2028 return &maskaddr;
2029 }
2030 if ((addrp = xtables_numeric_to_ip6addr(mask)) != NULL)
2031 return addrp;
2032 if (!xtables_strtoui(mask, NULL, &bits, 0, 128))
2033 xt_params->exit_err(PARAMETER_PROBLEM,
2034 "invalid mask `%s' specified", mask);
2035 if (bits != 0) {
2036 char *p = (void *)&maskaddr;
2037 memset(p, 0xff, bits / 8);
2038 memset(p + ((bits + 7) / 8), 0, (128 - bits) / 8);
2039 if (bits < 128)
2040 p[bits/8] = 0xff << (8 - (bits & 7));
2041 return &maskaddr;
2042 }
2043
2044 memset(&maskaddr, 0, sizeof(maskaddr));
2045 return &maskaddr;
2046 }
2047
2048 void
xtables_ip6parse_multiple(const char * name,struct in6_addr ** addrpp,struct in6_addr ** maskpp,unsigned int * naddrs)2049 xtables_ip6parse_multiple(const char *name, struct in6_addr **addrpp,
2050 struct in6_addr **maskpp, unsigned int *naddrs)
2051 {
2052 static const struct in6_addr zero_addr;
2053 struct in6_addr *addrp;
2054 char buf[256], *p, *next;
2055 unsigned int len, i, j, n, count = 1;
2056 const char *loop = name;
2057
2058 while ((loop = strchr(loop, ',')) != NULL) {
2059 ++count;
2060 ++loop; /* skip ',' */
2061 }
2062
2063 *addrpp = xtables_malloc(sizeof(struct in6_addr) * count);
2064 *maskpp = xtables_malloc(sizeof(struct in6_addr) * count);
2065
2066 loop = name;
2067
2068 for (i = 0; i < count /*NB: count can grow*/; ++i) {
2069 while (isspace(*loop))
2070 ++loop;
2071 next = strchr(loop, ',');
2072 if (next != NULL)
2073 len = next - loop;
2074 else
2075 len = strlen(loop);
2076 if (len > sizeof(buf) - 1)
2077 xt_params->exit_err(PARAMETER_PROBLEM,
2078 "Hostname too long");
2079
2080 strncpy(buf, loop, len);
2081 buf[len] = '\0';
2082 if ((p = strrchr(buf, '/')) != NULL) {
2083 *p = '\0';
2084 addrp = parse_ip6mask(p + 1);
2085 } else {
2086 addrp = parse_ip6mask(NULL);
2087 }
2088 memcpy(*maskpp + i, addrp, sizeof(*addrp));
2089
2090 /* if a null mask is given, the name is ignored, like in "any/0" */
2091 if (memcmp(*maskpp + i, &zero_addr, sizeof(zero_addr)) == 0)
2092 strcpy(buf, "::");
2093
2094 addrp = ip6parse_hostnetwork(buf, &n);
2095 if (n > 1) {
2096 count += n - 1;
2097 *addrpp = xtables_realloc(*addrpp,
2098 sizeof(struct in6_addr) * count);
2099 *maskpp = xtables_realloc(*maskpp,
2100 sizeof(struct in6_addr) * count);
2101 for (j = 0; j < n; ++j)
2102 /* for each new addr */
2103 memcpy(*addrpp + i + j, addrp + j,
2104 sizeof(*addrp));
2105 for (j = 1; j < n; ++j)
2106 /* for each new mask */
2107 memcpy(*maskpp + i + j, *maskpp + i,
2108 sizeof(*addrp));
2109 i += n - 1;
2110 } else {
2111 memcpy(*addrpp + i, addrp, sizeof(*addrp));
2112 }
2113 /* free what ip6parse_hostnetwork had allocated: */
2114 free(addrp);
2115 if (next == NULL)
2116 break;
2117 loop = next + 1;
2118 }
2119 *naddrs = count;
2120 for (i = 0; i < count; ++i)
2121 for (j = 0; j < 4; ++j)
2122 (*addrpp+i)->s6_addr32[j] &= (*maskpp+i)->s6_addr32[j];
2123 }
2124
xtables_ip6parse_any(const char * name,struct in6_addr ** addrpp,struct in6_addr * maskp,unsigned int * naddrs)2125 void xtables_ip6parse_any(const char *name, struct in6_addr **addrpp,
2126 struct in6_addr *maskp, unsigned int *naddrs)
2127 {
2128 static const struct in6_addr zero_addr;
2129 struct in6_addr *addrp;
2130 unsigned int i, j, k, n;
2131 char buf[256], *p;
2132
2133 strncpy(buf, name, sizeof(buf) - 1);
2134 buf[sizeof(buf)-1] = '\0';
2135 if ((p = strrchr(buf, '/')) != NULL) {
2136 *p = '\0';
2137 addrp = parse_ip6mask(p + 1);
2138 } else {
2139 addrp = parse_ip6mask(NULL);
2140 }
2141 memcpy(maskp, addrp, sizeof(*maskp));
2142
2143 /* if a null mask is given, the name is ignored, like in "any/0" */
2144 if (memcmp(maskp, &zero_addr, sizeof(zero_addr)) == 0)
2145 strcpy(buf, "::");
2146
2147 addrp = *addrpp = ip6parse_hostnetwork(buf, naddrs);
2148 n = *naddrs;
2149 for (i = 0, j = 0; i < n; ++i) {
2150 for (k = 0; k < 4; ++k)
2151 addrp[j].s6_addr32[k] &= maskp->s6_addr32[k];
2152 ++j;
2153 for (k = 0; k < j - 1; ++k)
2154 if (IN6_ARE_ADDR_EQUAL(&addrp[k], &addrp[j - 1])) {
2155 /*
2156 * Nuke the dup by copying an address from the
2157 * tail here, and check the current position
2158 * again (--j).
2159 */
2160 memcpy(&addrp[--j], &addrp[--*naddrs],
2161 sizeof(struct in_addr));
2162 break;
2163 }
2164 }
2165 }
2166
xtables_save_string(const char * value)2167 void xtables_save_string(const char *value)
2168 {
2169 static const char no_quote_chars[] = "_-0123456789"
2170 "abcdefghijklmnopqrstuvwxyz"
2171 "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
2172 static const char escape_chars[] = "\"\\'";
2173 size_t length;
2174 const char *p;
2175
2176 length = strspn(value, no_quote_chars);
2177 if (length > 0 && value[length] == 0) {
2178 /* no quoting required */
2179 putchar(' ');
2180 fputs(value, stdout);
2181 } else {
2182 /* there is at least one dangerous character in the
2183 value, which we have to quote. Write double quotes
2184 around the value and escape special characters with
2185 a backslash */
2186 printf(" \"");
2187
2188 for (p = strpbrk(value, escape_chars); p != NULL;
2189 p = strpbrk(value, escape_chars)) {
2190 if (p > value)
2191 fwrite(value, 1, p - value, stdout);
2192 putchar('\\');
2193 putchar(*p);
2194 value = p + 1;
2195 }
2196
2197 /* print the rest and finish the double quoted
2198 string */
2199 fputs(value, stdout);
2200 putchar('\"');
2201 }
2202 }
2203
2204 const struct xtables_pprot xtables_chain_protos[] = {
2205 {"tcp", IPPROTO_TCP},
2206 {"sctp", IPPROTO_SCTP},
2207 {"udp", IPPROTO_UDP},
2208 {"udplite", IPPROTO_UDPLITE},
2209 {"icmp", IPPROTO_ICMP},
2210 {"ipv6-icmp", IPPROTO_ICMPV6},
2211 {"icmpv6", IPPROTO_ICMPV6},
2212 {"esp", IPPROTO_ESP},
2213 {"ah", IPPROTO_AH},
2214 {"mobility-header", IPPROTO_MH},
2215 {"ipv6-mh", IPPROTO_MH},
2216 {"mh", IPPROTO_MH},
2217 {"dccp", IPPROTO_DCCP},
2218 {"ipcomp", IPPROTO_COMP},
2219 {"all", 0},
2220 {NULL},
2221 };
2222
2223 uint16_t
xtables_parse_protocol(const char * s)2224 xtables_parse_protocol(const char *s)
2225 {
2226 const struct protoent *pent;
2227 unsigned int proto, i;
2228
2229 if (xtables_strtoui(s, NULL, &proto, 0, UINT8_MAX))
2230 return proto;
2231
2232 for (i = 0; xtables_chain_protos[i].name != NULL; ++i) {
2233 if (strcmp(s, xtables_chain_protos[i].name) == 0)
2234 return xtables_chain_protos[i].num;
2235 }
2236
2237 pent = getprotobyname(s);
2238 if (pent != NULL)
2239 return pent->p_proto;
2240
2241 xt_params->exit_err(PARAMETER_PROBLEM,
2242 "unknown protocol \"%s\" specified", s);
2243 return -1;
2244 }
2245
xtables_print_num(uint64_t number,unsigned int format)2246 void xtables_print_num(uint64_t number, unsigned int format)
2247 {
2248 if (!(format & FMT_KILOMEGAGIGA)) {
2249 printf(FMT("%8llu ","%llu "), (unsigned long long)number);
2250 return;
2251 }
2252 if (number <= 99999) {
2253 printf(FMT("%5llu ","%llu "), (unsigned long long)number);
2254 return;
2255 }
2256 number = (number + 500) / 1000;
2257 if (number <= 9999) {
2258 printf(FMT("%4lluK ","%lluK "), (unsigned long long)number);
2259 return;
2260 }
2261 number = (number + 500) / 1000;
2262 if (number <= 9999) {
2263 printf(FMT("%4lluM ","%lluM "), (unsigned long long)number);
2264 return;
2265 }
2266 number = (number + 500) / 1000;
2267 if (number <= 9999) {
2268 printf(FMT("%4lluG ","%lluG "), (unsigned long long)number);
2269 return;
2270 }
2271 number = (number + 500) / 1000;
2272 printf(FMT("%4lluT ","%lluT "), (unsigned long long)number);
2273 }
2274
2275 static const unsigned char mac_type_unicast[ETH_ALEN] = {};
2276 static const unsigned char msk_type_unicast[ETH_ALEN] = {1};
2277 static const unsigned char mac_type_multicast[ETH_ALEN] = {1};
2278 static const unsigned char msk_type_multicast[ETH_ALEN] = {1};
2279 #define ALL_ONE_MAC {0xff, 0xff, 0xff, 0xff, 0xff, 0xff}
2280 static const unsigned char mac_type_broadcast[ETH_ALEN] = ALL_ONE_MAC;
2281 static const unsigned char msk_type_broadcast[ETH_ALEN] = ALL_ONE_MAC;
2282 static const unsigned char mac_type_bridge_group[ETH_ALEN] = {0x01, 0x80, 0xc2};
2283 static const unsigned char msk_type_bridge_group[ETH_ALEN] = ALL_ONE_MAC;
2284 #undef ALL_ONE_MAC
2285
xtables_parse_mac_and_mask(const char * from,void * to,void * mask)2286 int xtables_parse_mac_and_mask(const char *from, void *to, void *mask)
2287 {
2288 char *p;
2289 int i;
2290 struct ether_addr *addr = NULL;
2291
2292 if (strcasecmp(from, "Unicast") == 0) {
2293 memcpy(to, mac_type_unicast, ETH_ALEN);
2294 memcpy(mask, msk_type_unicast, ETH_ALEN);
2295 return 0;
2296 }
2297 if (strcasecmp(from, "Multicast") == 0) {
2298 memcpy(to, mac_type_multicast, ETH_ALEN);
2299 memcpy(mask, msk_type_multicast, ETH_ALEN);
2300 return 0;
2301 }
2302 if (strcasecmp(from, "Broadcast") == 0) {
2303 memcpy(to, mac_type_broadcast, ETH_ALEN);
2304 memcpy(mask, msk_type_broadcast, ETH_ALEN);
2305 return 0;
2306 }
2307 if (strcasecmp(from, "BGA") == 0) {
2308 memcpy(to, mac_type_bridge_group, ETH_ALEN);
2309 memcpy(mask, msk_type_bridge_group, ETH_ALEN);
2310 return 0;
2311 }
2312 if ( (p = strrchr(from, '/')) != NULL) {
2313 *p = '\0';
2314 if (!(addr = ether_aton(p + 1)))
2315 return -1;
2316 memcpy(mask, addr, ETH_ALEN);
2317 } else
2318 memset(mask, 0xff, ETH_ALEN);
2319 if (!(addr = ether_aton(from)))
2320 return -1;
2321 memcpy(to, addr, ETH_ALEN);
2322 for (i = 0; i < ETH_ALEN; i++)
2323 ((char *)to)[i] &= ((char *)mask)[i];
2324 return 0;
2325 }
2326
xtables_print_well_known_mac_and_mask(const void * mac,const void * mask)2327 int xtables_print_well_known_mac_and_mask(const void *mac, const void *mask)
2328 {
2329 if (!memcmp(mac, mac_type_unicast, ETH_ALEN) &&
2330 !memcmp(mask, msk_type_unicast, ETH_ALEN))
2331 printf("Unicast");
2332 else if (!memcmp(mac, mac_type_multicast, ETH_ALEN) &&
2333 !memcmp(mask, msk_type_multicast, ETH_ALEN))
2334 printf("Multicast");
2335 else if (!memcmp(mac, mac_type_broadcast, ETH_ALEN) &&
2336 !memcmp(mask, msk_type_broadcast, ETH_ALEN))
2337 printf("Broadcast");
2338 else if (!memcmp(mac, mac_type_bridge_group, ETH_ALEN) &&
2339 !memcmp(mask, msk_type_bridge_group, ETH_ALEN))
2340 printf("BGA");
2341 else
2342 return -1;
2343 return 0;
2344 }
2345
xtables_print_mac(const unsigned char * macaddress)2346 void xtables_print_mac(const unsigned char *macaddress)
2347 {
2348 unsigned int i;
2349
2350 printf("%02x", macaddress[0]);
2351 for (i = 1; i < 6; ++i)
2352 printf(":%02x", macaddress[i]);
2353 }
2354
xtables_print_mac_and_mask(const unsigned char * mac,const unsigned char * mask)2355 void xtables_print_mac_and_mask(const unsigned char *mac, const unsigned char *mask)
2356 {
2357 static const char hlpmsk[] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
2358
2359 xtables_print_mac(mac);
2360
2361 if (memcmp(mask, hlpmsk, 6) == 0)
2362 return;
2363
2364 printf("/");
2365 xtables_print_mac(mask);
2366 }
2367
xtables_parse_val_mask(struct xt_option_call * cb,unsigned int * val,unsigned int * mask,const struct xtables_lmap * lmap)2368 void xtables_parse_val_mask(struct xt_option_call *cb,
2369 unsigned int *val, unsigned int *mask,
2370 const struct xtables_lmap *lmap)
2371 {
2372 char *end;
2373
2374 *mask = ~0U;
2375
2376 if (!xtables_strtoui(cb->arg, &end, val, 0, UINT32_MAX)) {
2377 if (lmap)
2378 goto name2val;
2379 else
2380 goto bad_val;
2381 }
2382
2383 if (*end == '\0')
2384 return;
2385
2386 if (*end != '/') {
2387 if (lmap)
2388 goto name2val;
2389 else
2390 goto garbage;
2391 }
2392
2393 if (!xtables_strtoui(end + 1, &end, mask, 0, UINT32_MAX))
2394 goto bad_val;
2395
2396 if (*end == '\0')
2397 return;
2398
2399 garbage:
2400 xt_params->exit_err(PARAMETER_PROBLEM,
2401 "%s: trailing garbage after value "
2402 "for option \"--%s\".\n",
2403 cb->ext_name, cb->entry->name);
2404
2405 bad_val:
2406 xt_params->exit_err(PARAMETER_PROBLEM,
2407 "%s: bad integer value for option \"--%s\", "
2408 "or out of range.\n",
2409 cb->ext_name, cb->entry->name);
2410
2411 name2val:
2412 *val = xtables_lmap_name2id(lmap, cb->arg);
2413 if ((int)*val == -1)
2414 xt_params->exit_err(PARAMETER_PROBLEM,
2415 "%s: could not map name %s to an integer value "
2416 "for option \"--%s\".\n",
2417 cb->ext_name, cb->arg, cb->entry->name);
2418 }
2419
xtables_print_val_mask(unsigned int val,unsigned int mask,const struct xtables_lmap * lmap)2420 void xtables_print_val_mask(unsigned int val, unsigned int mask,
2421 const struct xtables_lmap *lmap)
2422 {
2423 if (mask != ~0U) {
2424 printf(" 0x%x/0x%x", val, mask);
2425 return;
2426 }
2427
2428 if (lmap) {
2429 const char *name = xtables_lmap_id2name(lmap, val);
2430
2431 if (name) {
2432 printf(" %s", name);
2433 return;
2434 }
2435 }
2436
2437 printf(" 0x%x", val);
2438 }
2439
2440 int kernel_version;
2441
get_kernel_version(void)2442 void get_kernel_version(void)
2443 {
2444 static struct utsname uts;
2445 int x = 0, y = 0, z = 0;
2446
2447 if (uname(&uts) == -1) {
2448 fprintf(stderr, "Unable to retrieve kernel version.\n");
2449 xtables_free_opts(1);
2450 exit(1);
2451 }
2452
2453 sscanf(uts.release, "%d.%d.%d", &x, &y, &z);
2454 kernel_version = LINUX_VERSION(x, y, z);
2455 }
2456
2457 #include <linux/netfilter/nf_tables.h>
2458
2459 enum xt_xlate_type {
2460 XT_XLATE_RULE = 0,
2461 XT_XLATE_SET,
2462 __XT_XLATE_MAX
2463 };
2464
2465 struct xt_xlate {
2466 struct xt_xlate_buf {
2467 char *data;
2468 int size;
2469 int rem;
2470 int off;
2471 } buf[__XT_XLATE_MAX];
2472 char comment[NFT_USERDATA_MAXLEN];
2473 int family;
2474 };
2475
xt_xlate_alloc(int size)2476 struct xt_xlate *xt_xlate_alloc(int size)
2477 {
2478 struct xt_xlate *xl = xtables_malloc(sizeof(struct xt_xlate));
2479 int i;
2480
2481 for (i = 0; i < __XT_XLATE_MAX; i++) {
2482 xl->buf[i].data = xtables_malloc(size);
2483 xl->buf[i].data[0] = '\0';
2484 xl->buf[i].size = size;
2485 xl->buf[i].rem = size;
2486 xl->buf[i].off = 0;
2487 }
2488 xl->comment[0] = '\0';
2489
2490 return xl;
2491 }
2492
xt_xlate_free(struct xt_xlate * xl)2493 void xt_xlate_free(struct xt_xlate *xl)
2494 {
2495 int i;
2496
2497 for (i = 0; i < __XT_XLATE_MAX; i++)
2498 free(xl->buf[i].data);
2499
2500 free(xl);
2501 }
2502
isbrace(char c)2503 static bool isbrace(char c)
2504 {
2505 switch (c) {
2506 case '(':
2507 case ')':
2508 case '{':
2509 case '}':
2510 case '[':
2511 case ']':
2512 return true;
2513 }
2514 return false;
2515 }
2516
__xt_xlate_add(struct xt_xlate * xl,enum xt_xlate_type type,bool space,const char * fmt,va_list ap)2517 static void __xt_xlate_add(struct xt_xlate *xl, enum xt_xlate_type type,
2518 bool space, const char *fmt, va_list ap)
2519 {
2520 struct xt_xlate_buf *buf = &xl->buf[type];
2521 char tmpbuf[1024] = "";
2522 int len;
2523
2524 len = vsnprintf(tmpbuf, 1024, fmt, ap);
2525 if (len < 0 || len >= buf->rem - 1)
2526 xtables_error(RESOURCE_PROBLEM, "OOM");
2527
2528 if (space && buf->off &&
2529 !isspace(buf->data[buf->off - 1]) &&
2530 (isalnum(tmpbuf[0]) || isbrace(tmpbuf[0]))) {
2531 buf->data[buf->off] = ' ';
2532 buf->off++;
2533 buf->rem--;
2534 }
2535 sprintf(buf->data + buf->off, "%s", tmpbuf);
2536 buf->rem -= len;
2537 buf->off += len;
2538 }
2539
xt_xlate_rule_add(struct xt_xlate * xl,const char * fmt,...)2540 void xt_xlate_rule_add(struct xt_xlate *xl, const char *fmt, ...)
2541 {
2542 va_list ap;
2543
2544 va_start(ap, fmt);
2545 __xt_xlate_add(xl, XT_XLATE_RULE, true, fmt, ap);
2546 va_end(ap);
2547 }
2548
xt_xlate_rule_add_nospc(struct xt_xlate * xl,const char * fmt,...)2549 void xt_xlate_rule_add_nospc(struct xt_xlate *xl, const char *fmt, ...)
2550 {
2551 va_list ap;
2552
2553 va_start(ap, fmt);
2554 __xt_xlate_add(xl, XT_XLATE_RULE, false, fmt, ap);
2555 va_end(ap);
2556 }
2557
xt_xlate_set_add(struct xt_xlate * xl,const char * fmt,...)2558 void xt_xlate_set_add(struct xt_xlate *xl, const char *fmt, ...)
2559 {
2560 va_list ap;
2561
2562 va_start(ap, fmt);
2563 __xt_xlate_add(xl, XT_XLATE_SET, true, fmt, ap);
2564 va_end(ap);
2565 }
2566
xt_xlate_set_add_nospc(struct xt_xlate * xl,const char * fmt,...)2567 void xt_xlate_set_add_nospc(struct xt_xlate *xl, const char *fmt, ...)
2568 {
2569 va_list ap;
2570
2571 va_start(ap, fmt);
2572 __xt_xlate_add(xl, XT_XLATE_SET, false, fmt, ap);
2573 va_end(ap);
2574 }
2575
xt_xlate_add_comment(struct xt_xlate * xl,const char * comment)2576 void xt_xlate_add_comment(struct xt_xlate *xl, const char *comment)
2577 {
2578 strncpy(xl->comment, comment, NFT_USERDATA_MAXLEN - 1);
2579 xl->comment[NFT_USERDATA_MAXLEN - 1] = '\0';
2580 }
2581
xt_xlate_get_comment(struct xt_xlate * xl)2582 const char *xt_xlate_get_comment(struct xt_xlate *xl)
2583 {
2584 return xl->comment[0] ? xl->comment : NULL;
2585 }
2586
xl_xlate_set_family(struct xt_xlate * xl,uint8_t family)2587 void xl_xlate_set_family(struct xt_xlate *xl, uint8_t family)
2588 {
2589 xl->family = family;
2590 }
2591
xt_xlate_get_family(struct xt_xlate * xl)2592 uint8_t xt_xlate_get_family(struct xt_xlate *xl)
2593 {
2594 return xl->family;
2595 }
2596
xt_xlate_get(struct xt_xlate * xl)2597 const char *xt_xlate_get(struct xt_xlate *xl)
2598 {
2599 struct xt_xlate_buf *buf = &xl->buf[XT_XLATE_RULE];
2600
2601 while (buf->off && isspace(buf->data[buf->off - 1]))
2602 buf->data[--buf->off] = '\0';
2603
2604 return buf->data;
2605 }
2606
xt_xlate_set_get(struct xt_xlate * xl)2607 const char *xt_xlate_set_get(struct xt_xlate *xl)
2608 {
2609 return xl->buf[XT_XLATE_SET].data;
2610 }
2611