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