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