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., 675 Mass Ave, Cambridge, MA 02139, USA.
17 */
18 #include <ctype.h>
19 #include <errno.h>
20 #include <fcntl.h>
21 #include <inttypes.h>
22 #include <netdb.h>
23 #include <stdarg.h>
24 #include <stdbool.h>
25 #include <stdio.h>
26 #include <stdlib.h>
27 #include <string.h>
28 #include <unistd.h>
29 #include <sys/socket.h>
30 #include <sys/stat.h>
31 #include <sys/statfs.h>
32 #include <sys/types.h>
33 #include <sys/wait.h>
34 #include <arpa/inet.h>
35 #include <linux/magic.h> /* for PROC_SUPER_MAGIC */
36
37 #include <xtables.h>
38 #include <limits.h> /* INT_MAX in ip_tables.h/ip6_tables.h */
39 #include <linux/netfilter_ipv4/ip_tables.h>
40 #include <linux/netfilter_ipv6/ip6_tables.h>
41 #include <libiptc/libxtc.h>
42
43 #ifndef NO_SHARED_LIBS
44 #include <dlfcn.h>
45 #endif
46 #ifndef IPT_SO_GET_REVISION_MATCH /* Old kernel source. */
47 # define IPT_SO_GET_REVISION_MATCH (IPT_BASE_CTL + 2)
48 # define IPT_SO_GET_REVISION_TARGET (IPT_BASE_CTL + 3)
49 #endif
50 #ifndef IP6T_SO_GET_REVISION_MATCH /* Old kernel source. */
51 # define IP6T_SO_GET_REVISION_MATCH 68
52 # define IP6T_SO_GET_REVISION_TARGET 69
53 #endif
54 #include <getopt.h>
55 #include "iptables/internal.h"
56 #include "xshared.h"
57
58 #define NPROTO 255
59
60 #ifndef PROC_SYS_MODPROBE
61 #define PROC_SYS_MODPROBE "/proc/sys/kernel/modprobe"
62 #endif
63
64 /* we need this for ip6?tables-restore. ip6?tables-restore.c sets line to the
65 * current line of the input file, in order to give a more precise error
66 * message. ip6?tables itself doesn't need this, so it is initialized to the
67 * magic number of -1 */
68 int line = -1;
69
70 void basic_exit_err(enum xtables_exittype status, const char *msg, ...) __attribute__((noreturn, format(printf,2,3)));
71
72 struct xtables_globals *xt_params = NULL;
73
basic_exit_err(enum xtables_exittype status,const char * msg,...)74 void basic_exit_err(enum xtables_exittype status, const char *msg, ...)
75 {
76 va_list args;
77
78 va_start(args, msg);
79 fprintf(stderr, "%s v%s: ", xt_params->program_name, xt_params->program_version);
80 vfprintf(stderr, msg, args);
81 va_end(args);
82 fprintf(stderr, "\n");
83 exit(status);
84 }
85
xtables_free_opts(int unused)86 void xtables_free_opts(int unused)
87 {
88 if (xt_params->opts != xt_params->orig_opts) {
89 free(xt_params->opts);
90 xt_params->opts = NULL;
91 }
92 }
93
xtables_merge_options(struct option * orig_opts,struct option * oldopts,const struct option * newopts,unsigned int * option_offset)94 struct option *xtables_merge_options(struct option *orig_opts,
95 struct option *oldopts,
96 const struct option *newopts,
97 unsigned int *option_offset)
98 {
99 unsigned int num_oold = 0, num_old = 0, num_new = 0, i;
100 struct option *merge, *mp;
101
102 if (newopts == NULL)
103 return oldopts;
104
105 for (num_oold = 0; orig_opts[num_oold].name; num_oold++) ;
106 if (oldopts != NULL)
107 for (num_old = 0; oldopts[num_old].name; num_old++) ;
108 for (num_new = 0; newopts[num_new].name; num_new++) ;
109
110 /*
111 * Since @oldopts also has @orig_opts already (and does so at the
112 * start), skip these entries.
113 */
114 oldopts += num_oold;
115 num_old -= num_oold;
116
117 merge = malloc(sizeof(*mp) * (num_oold + num_old + num_new + 1));
118 if (merge == NULL)
119 return NULL;
120
121 /* Let the base options -[ADI...] have precedence over everything */
122 memcpy(merge, orig_opts, sizeof(*mp) * num_oold);
123 mp = merge + num_oold;
124
125 /* Second, the new options */
126 xt_params->option_offset += XT_OPTION_OFFSET_SCALE;
127 *option_offset = xt_params->option_offset;
128 memcpy(mp, newopts, sizeof(*mp) * num_new);
129
130 for (i = 0; i < num_new; ++i, ++mp)
131 mp->val += *option_offset;
132
133 /* Third, the old options */
134 memcpy(mp, oldopts, sizeof(*mp) * num_old);
135 mp += num_old;
136 xtables_free_opts(0);
137
138 /* Clear trailing entry */
139 memset(mp, 0, sizeof(*mp));
140 return merge;
141 }
142
143 static const struct xtables_afinfo afinfo_ipv4 = {
144 .kmod = "ip_tables",
145 .proc_exists = "/proc/net/ip_tables_names",
146 .libprefix = "libipt_",
147 .family = NFPROTO_IPV4,
148 .ipproto = IPPROTO_IP,
149 .so_rev_match = IPT_SO_GET_REVISION_MATCH,
150 .so_rev_target = IPT_SO_GET_REVISION_TARGET,
151 };
152
153 static const struct xtables_afinfo afinfo_ipv6 = {
154 .kmod = "ip6_tables",
155 .proc_exists = "/proc/net/ip6_tables_names",
156 .libprefix = "libip6t_",
157 .family = NFPROTO_IPV6,
158 .ipproto = IPPROTO_IPV6,
159 .so_rev_match = IP6T_SO_GET_REVISION_MATCH,
160 .so_rev_target = IP6T_SO_GET_REVISION_TARGET,
161 };
162
163 const struct xtables_afinfo *afinfo;
164
165 /* Search path for Xtables .so files */
166 static const char *xtables_libdir;
167
168 /* the path to command to load kernel module */
169 const char *xtables_modprobe_program;
170
171 /* Keep track of matches/targets pending full registration: linked lists. */
172 struct xtables_match *xtables_pending_matches;
173 struct xtables_target *xtables_pending_targets;
174
175 /* Keep track of fully registered external matches/targets: linked lists. */
176 struct xtables_match *xtables_matches;
177 struct xtables_target *xtables_targets;
178
179 /* Fully register a match/target which was previously partially registered. */
180 static void xtables_fully_register_pending_match(struct xtables_match *me);
181 static void xtables_fully_register_pending_target(struct xtables_target *me);
182
xtables_init(void)183 void xtables_init(void)
184 {
185 xtables_libdir = getenv("XTABLES_LIBDIR");
186 if (xtables_libdir != NULL)
187 return;
188 xtables_libdir = getenv("IPTABLES_LIB_DIR");
189 if (xtables_libdir != NULL) {
190 fprintf(stderr, "IPTABLES_LIB_DIR is deprecated, "
191 "use XTABLES_LIBDIR.\n");
192 return;
193 }
194 /*
195 * Well yes, IP6TABLES_LIB_DIR is of lower priority over
196 * IPTABLES_LIB_DIR since this moved to libxtables; I think that is ok
197 * for these env vars are deprecated anyhow, and in light of the
198 * (shared) libxt_*.so files, makes less sense to have
199 * IPTABLES_LIB_DIR != IP6TABLES_LIB_DIR.
200 */
201 xtables_libdir = getenv("IP6TABLES_LIB_DIR");
202 if (xtables_libdir != NULL) {
203 fprintf(stderr, "IP6TABLES_LIB_DIR is deprecated, "
204 "use XTABLES_LIBDIR.\n");
205 return;
206 }
207 xtables_libdir = XTABLES_LIBDIR;
208 }
209
xtables_set_nfproto(uint8_t nfproto)210 void xtables_set_nfproto(uint8_t nfproto)
211 {
212 switch (nfproto) {
213 case NFPROTO_IPV4:
214 afinfo = &afinfo_ipv4;
215 break;
216 case NFPROTO_IPV6:
217 afinfo = &afinfo_ipv6;
218 break;
219 default:
220 fprintf(stderr, "libxtables: unhandled NFPROTO in %s\n",
221 __func__);
222 }
223 }
224
225 /**
226 * xtables_set_params - set the global parameters used by xtables
227 * @xtp: input xtables_globals structure
228 *
229 * The app is expected to pass a valid xtables_globals data-filled
230 * with proper values
231 * @xtp cannot be NULL
232 *
233 * Returns -1 on failure to set and 0 on success
234 */
xtables_set_params(struct xtables_globals * xtp)235 int xtables_set_params(struct xtables_globals *xtp)
236 {
237 if (!xtp) {
238 fprintf(stderr, "%s: Illegal global params\n",__func__);
239 return -1;
240 }
241
242 xt_params = xtp;
243
244 if (!xt_params->exit_err)
245 xt_params->exit_err = basic_exit_err;
246
247 return 0;
248 }
249
xtables_init_all(struct xtables_globals * xtp,uint8_t nfproto)250 int xtables_init_all(struct xtables_globals *xtp, uint8_t nfproto)
251 {
252 xtables_init();
253 xtables_set_nfproto(nfproto);
254 return xtables_set_params(xtp);
255 }
256
257 /**
258 * xtables_*alloc - wrappers that exit on failure
259 */
xtables_calloc(size_t count,size_t size)260 void *xtables_calloc(size_t count, size_t size)
261 {
262 void *p;
263
264 if ((p = calloc(count, size)) == NULL) {
265 perror("ip[6]tables: calloc failed");
266 exit(1);
267 }
268
269 return p;
270 }
271
xtables_malloc(size_t size)272 void *xtables_malloc(size_t size)
273 {
274 void *p;
275
276 if ((p = malloc(size)) == NULL) {
277 perror("ip[6]tables: malloc failed");
278 exit(1);
279 }
280
281 return p;
282 }
283
xtables_realloc(void * ptr,size_t size)284 void *xtables_realloc(void *ptr, size_t size)
285 {
286 void *p;
287
288 if ((p = realloc(ptr, size)) == NULL) {
289 perror("ip[6]tables: realloc failed");
290 exit(1);
291 }
292
293 return p;
294 }
295
get_modprobe(void)296 static char *get_modprobe(void)
297 {
298 int procfile;
299 char *ret;
300
301 #define PROCFILE_BUFSIZ 1024
302 procfile = open(PROC_SYS_MODPROBE, O_RDONLY);
303 if (procfile < 0)
304 return NULL;
305 if (fcntl(procfile, F_SETFD, FD_CLOEXEC) == -1) {
306 fprintf(stderr, "Could not set close on exec: %s\n",
307 strerror(errno));
308 exit(1);
309 }
310
311 ret = malloc(PROCFILE_BUFSIZ);
312 if (ret) {
313 memset(ret, 0, PROCFILE_BUFSIZ);
314 switch (read(procfile, ret, PROCFILE_BUFSIZ)) {
315 case -1: goto fail;
316 case PROCFILE_BUFSIZ: goto fail; /* Partial read. Wierd */
317 }
318 if (ret[strlen(ret)-1]=='\n')
319 ret[strlen(ret)-1]=0;
320 close(procfile);
321 return ret;
322 }
323 fail:
324 free(ret);
325 close(procfile);
326 return NULL;
327 }
328
xtables_insmod(const char * modname,const char * modprobe,bool quiet)329 int xtables_insmod(const char *modname, const char *modprobe, bool quiet)
330 {
331 char *buf = NULL;
332 char *argv[4];
333 int status;
334
335 /* If they don't explicitly set it, read out of kernel */
336 if (!modprobe) {
337 buf = get_modprobe();
338 if (!buf)
339 return -1;
340 modprobe = buf;
341 }
342
343 /*
344 * Need to flush the buffer, or the child may output it again
345 * when switching the program thru execv.
346 */
347 fflush(stdout);
348
349 switch (vfork()) {
350 case 0:
351 argv[0] = (char *)modprobe;
352 argv[1] = (char *)modname;
353 if (quiet) {
354 argv[2] = "-q";
355 argv[3] = NULL;
356 } else {
357 argv[2] = NULL;
358 argv[3] = NULL;
359 }
360 execv(argv[0], argv);
361
362 /* not usually reached */
363 exit(1);
364 case -1:
365 return -1;
366
367 default: /* parent */
368 wait(&status);
369 }
370
371 free(buf);
372 if (WIFEXITED(status) && WEXITSTATUS(status) == 0)
373 return 0;
374 return -1;
375 }
376
377 /* return true if a given file exists within procfs */
proc_file_exists(const char * filename)378 static bool proc_file_exists(const char *filename)
379 {
380 struct stat s;
381 struct statfs f;
382
383 if (lstat(filename, &s))
384 return false;
385 if (!S_ISREG(s.st_mode))
386 return false;
387 if (statfs(filename, &f))
388 return false;
389 if (f.f_type != PROC_SUPER_MAGIC)
390 return false;
391 return true;
392 }
393
xtables_load_ko(const char * modprobe,bool quiet)394 int xtables_load_ko(const char *modprobe, bool quiet)
395 {
396 static bool loaded = false;
397 int ret;
398
399 if (loaded)
400 return 0;
401
402 if (proc_file_exists(afinfo->proc_exists)) {
403 loaded = true;
404 return 0;
405 };
406
407 ret = xtables_insmod(afinfo->kmod, modprobe, quiet);
408 if (ret == 0)
409 loaded = true;
410
411 return ret;
412 }
413
414 /**
415 * xtables_strtou{i,l} - string to number conversion
416 * @s: input string
417 * @end: like strtoul's "end" pointer
418 * @value: pointer for result
419 * @min: minimum accepted value
420 * @max: maximum accepted value
421 *
422 * If @end is NULL, we assume the caller wants a "strict strtoul", and hence
423 * "15a" is rejected.
424 * In either case, the value obtained is compared for min-max compliance.
425 * Base is always 0, i.e. autodetect depending on @s.
426 *
427 * Returns true/false whether number was accepted. On failure, *value has
428 * undefined contents.
429 */
xtables_strtoul(const char * s,char ** end,uintmax_t * value,uintmax_t min,uintmax_t max)430 bool xtables_strtoul(const char *s, char **end, uintmax_t *value,
431 uintmax_t min, uintmax_t max)
432 {
433 uintmax_t v;
434 const char *p;
435 char *my_end;
436
437 errno = 0;
438 /* Since strtoul allows leading minus, we have to check for ourself. */
439 for (p = s; isspace(*p); ++p)
440 ;
441 if (*p == '-')
442 return false;
443 v = strtoumax(s, &my_end, 0);
444 if (my_end == s)
445 return false;
446 if (end != NULL)
447 *end = my_end;
448
449 if (errno != ERANGE && min <= v && (max == 0 || v <= max)) {
450 if (value != NULL)
451 *value = v;
452 if (end == NULL)
453 return *my_end == '\0';
454 return true;
455 }
456
457 return false;
458 }
459
xtables_strtoui(const char * s,char ** end,unsigned int * value,unsigned int min,unsigned int max)460 bool xtables_strtoui(const char *s, char **end, unsigned int *value,
461 unsigned int min, unsigned int max)
462 {
463 uintmax_t v;
464 bool ret;
465
466 ret = xtables_strtoul(s, end, &v, min, max);
467 if (value != NULL)
468 *value = v;
469 return ret;
470 }
471
xtables_service_to_port(const char * name,const char * proto)472 int xtables_service_to_port(const char *name, const char *proto)
473 {
474 struct servent *service;
475
476 if ((service = getservbyname(name, proto)) != NULL)
477 return ntohs((unsigned short) service->s_port);
478
479 return -1;
480 }
481
xtables_parse_port(const char * port,const char * proto)482 uint16_t xtables_parse_port(const char *port, const char *proto)
483 {
484 unsigned int portnum;
485
486 if (xtables_strtoui(port, NULL, &portnum, 0, UINT16_MAX) ||
487 (portnum = xtables_service_to_port(port, proto)) != (unsigned)-1)
488 return portnum;
489
490 xt_params->exit_err(PARAMETER_PROBLEM,
491 "invalid port/service `%s' specified", port);
492 }
493
xtables_parse_interface(const char * arg,char * vianame,unsigned char * mask)494 void xtables_parse_interface(const char *arg, char *vianame,
495 unsigned char *mask)
496 {
497 unsigned int vialen = strlen(arg);
498 unsigned int i;
499
500 memset(mask, 0, IFNAMSIZ);
501 memset(vianame, 0, IFNAMSIZ);
502
503 if (vialen + 1 > IFNAMSIZ)
504 xt_params->exit_err(PARAMETER_PROBLEM,
505 "interface name `%s' must be shorter than IFNAMSIZ"
506 " (%i)", arg, IFNAMSIZ-1);
507
508 strcpy(vianame, arg);
509 if (vialen == 0)
510 memset(mask, 0, IFNAMSIZ);
511 else if (vianame[vialen - 1] == '+') {
512 memset(mask, 0xFF, vialen - 1);
513 memset(mask + vialen - 1, 0, IFNAMSIZ - vialen + 1);
514 /* Don't remove `+' here! -HW */
515 } else {
516 /* Include nul-terminator in match */
517 memset(mask, 0xFF, vialen + 1);
518 memset(mask + vialen + 1, 0, IFNAMSIZ - vialen - 1);
519 for (i = 0; vianame[i]; i++) {
520 if (vianame[i] == '/' ||
521 vianame[i] == ' ') {
522 fprintf(stderr,
523 "Warning: weird character in interface"
524 " `%s' ('/' and ' ' are not allowed by the kernel).\n",
525 vianame);
526 break;
527 }
528 }
529 }
530 }
531
532 #ifndef NO_SHARED_LIBS
load_extension(const char * search_path,const char * af_prefix,const char * name,bool is_target)533 static void *load_extension(const char *search_path, const char *af_prefix,
534 const char *name, bool is_target)
535 {
536 const char *all_prefixes[] = {"libxt_", af_prefix, NULL};
537 const char **prefix;
538 const char *dir = search_path, *next;
539 void *ptr = NULL;
540 struct stat sb;
541 char path[256];
542
543 do {
544 next = strchr(dir, ':');
545 if (next == NULL)
546 next = dir + strlen(dir);
547
548 for (prefix = all_prefixes; *prefix != NULL; ++prefix) {
549 snprintf(path, sizeof(path), "%.*s/%s%s.so",
550 (unsigned int)(next - dir), dir,
551 *prefix, name);
552
553 if (stat(path, &sb) != 0) {
554 if (errno == ENOENT)
555 continue;
556 fprintf(stderr, "%s: %s\n", path,
557 strerror(errno));
558 return NULL;
559 }
560 if (dlopen(path, RTLD_NOW) == NULL) {
561 fprintf(stderr, "%s: %s\n", path, dlerror());
562 break;
563 }
564
565 if (is_target)
566 ptr = xtables_find_target(name, XTF_DONT_LOAD);
567 else
568 ptr = xtables_find_match(name,
569 XTF_DONT_LOAD, NULL);
570
571 if (ptr != NULL)
572 return ptr;
573
574 fprintf(stderr, "%s: no \"%s\" extension found for "
575 "this protocol\n", path, name);
576 errno = ENOENT;
577 return NULL;
578 }
579 dir = next + 1;
580 } while (*next != '\0');
581
582 return NULL;
583 }
584 #endif
585
586 struct xtables_match *
xtables_find_match(const char * name,enum xtables_tryload tryload,struct xtables_rule_match ** matches)587 xtables_find_match(const char *name, enum xtables_tryload tryload,
588 struct xtables_rule_match **matches)
589 {
590 struct xtables_match **dptr;
591 struct xtables_match *ptr;
592 const char *icmp6 = "icmp6";
593
594 if (strlen(name) >= XT_EXTENSION_MAXNAMELEN)
595 xtables_error(PARAMETER_PROBLEM,
596 "Invalid match name \"%s\" (%u chars max)",
597 name, XT_EXTENSION_MAXNAMELEN - 1);
598
599 /* This is ugly as hell. Nonetheless, there is no way of changing
600 * this without hurting backwards compatibility */
601 if ( (strcmp(name,"icmpv6") == 0) ||
602 (strcmp(name,"ipv6-icmp") == 0) ||
603 (strcmp(name,"icmp6") == 0) )
604 name = icmp6;
605
606 /* Trigger delayed initialization */
607 for (dptr = &xtables_pending_matches; *dptr; ) {
608 if (strcmp(name, (*dptr)->name) == 0) {
609 ptr = *dptr;
610 *dptr = (*dptr)->next;
611 ptr->next = NULL;
612 xtables_fully_register_pending_match(ptr);
613 } else {
614 dptr = &((*dptr)->next);
615 }
616 }
617
618 for (ptr = xtables_matches; ptr; ptr = ptr->next) {
619 if (strcmp(name, ptr->name) == 0) {
620 struct xtables_match *clone;
621
622 /* First match of this type: */
623 if (ptr->m == NULL)
624 break;
625
626 /* Second and subsequent clones */
627 clone = xtables_malloc(sizeof(struct xtables_match));
628 memcpy(clone, ptr, sizeof(struct xtables_match));
629 clone->mflags = 0;
630 /* This is a clone: */
631 clone->next = clone;
632
633 ptr = clone;
634 break;
635 }
636 }
637
638 #ifndef NO_SHARED_LIBS
639 if (!ptr && tryload != XTF_DONT_LOAD && tryload != XTF_DURING_LOAD) {
640 ptr = load_extension(xtables_libdir, afinfo->libprefix,
641 name, false);
642
643 if (ptr == NULL && tryload == XTF_LOAD_MUST_SUCCEED)
644 xt_params->exit_err(PARAMETER_PROBLEM,
645 "Couldn't load match `%s':%s\n",
646 name, strerror(errno));
647 }
648 #else
649 if (ptr && !ptr->loaded) {
650 if (tryload != XTF_DONT_LOAD)
651 ptr->loaded = 1;
652 else
653 ptr = NULL;
654 }
655 if(!ptr && (tryload == XTF_LOAD_MUST_SUCCEED)) {
656 xt_params->exit_err(PARAMETER_PROBLEM,
657 "Couldn't find match `%s'\n", name);
658 }
659 #endif
660
661 if (ptr && matches) {
662 struct xtables_rule_match **i;
663 struct xtables_rule_match *newentry;
664
665 newentry = xtables_malloc(sizeof(struct xtables_rule_match));
666
667 for (i = matches; *i; i = &(*i)->next) {
668 if (strcmp(name, (*i)->match->name) == 0)
669 (*i)->completed = true;
670 }
671 newentry->match = ptr;
672 newentry->completed = false;
673 newentry->next = NULL;
674 *i = newentry;
675 }
676
677 return ptr;
678 }
679
680 struct xtables_target *
xtables_find_target(const char * name,enum xtables_tryload tryload)681 xtables_find_target(const char *name, enum xtables_tryload tryload)
682 {
683 struct xtables_target **dptr;
684 struct xtables_target *ptr;
685
686 /* Standard target? */
687 if (strcmp(name, "") == 0
688 || strcmp(name, XTC_LABEL_ACCEPT) == 0
689 || strcmp(name, XTC_LABEL_DROP) == 0
690 || strcmp(name, XTC_LABEL_QUEUE) == 0
691 || strcmp(name, XTC_LABEL_RETURN) == 0)
692 name = "standard";
693
694 /* Trigger delayed initialization */
695 for (dptr = &xtables_pending_targets; *dptr; ) {
696 if (strcmp(name, (*dptr)->name) == 0) {
697 ptr = *dptr;
698 *dptr = (*dptr)->next;
699 ptr->next = NULL;
700 xtables_fully_register_pending_target(ptr);
701 } else {
702 dptr = &((*dptr)->next);
703 }
704 }
705
706 for (ptr = xtables_targets; ptr; ptr = ptr->next) {
707 if (strcmp(name, ptr->name) == 0)
708 break;
709 }
710
711 #ifndef NO_SHARED_LIBS
712 if (!ptr && tryload != XTF_DONT_LOAD && tryload != XTF_DURING_LOAD) {
713 ptr = load_extension(xtables_libdir, afinfo->libprefix,
714 name, true);
715
716 if (ptr == NULL && tryload == XTF_LOAD_MUST_SUCCEED)
717 xt_params->exit_err(PARAMETER_PROBLEM,
718 "Couldn't load target `%s':%s\n",
719 name, strerror(errno));
720 }
721 #else
722 if (ptr && !ptr->loaded) {
723 if (tryload != XTF_DONT_LOAD)
724 ptr->loaded = 1;
725 else
726 ptr = NULL;
727 }
728 if (ptr == NULL && tryload == XTF_LOAD_MUST_SUCCEED) {
729 xt_params->exit_err(PARAMETER_PROBLEM,
730 "Couldn't find target `%s'\n", name);
731 }
732 #endif
733
734 if (ptr)
735 ptr->used = 1;
736
737 return ptr;
738 }
739
compatible_revision(const char * name,uint8_t revision,int opt)740 static int compatible_revision(const char *name, uint8_t revision, int opt)
741 {
742 struct xt_get_revision rev;
743 socklen_t s = sizeof(rev);
744 int max_rev, sockfd;
745
746 sockfd = socket(afinfo->family, SOCK_RAW, IPPROTO_RAW);
747 if (sockfd < 0) {
748 if (errno == EPERM) {
749 /* revision 0 is always supported. */
750 if (revision != 0)
751 fprintf(stderr, "%s: Could not determine whether "
752 "revision %u is supported, "
753 "assuming it is.\n",
754 name, revision);
755 return 1;
756 }
757 fprintf(stderr, "Could not open socket to kernel: %s\n",
758 strerror(errno));
759 exit(1);
760 }
761
762 if (fcntl(sockfd, F_SETFD, FD_CLOEXEC) == -1) {
763 fprintf(stderr, "Could not set close on exec: %s\n",
764 strerror(errno));
765 exit(1);
766 }
767
768 xtables_load_ko(xtables_modprobe_program, true);
769
770 strcpy(rev.name, name);
771 rev.revision = revision;
772
773 max_rev = getsockopt(sockfd, afinfo->ipproto, opt, &rev, &s);
774 if (max_rev < 0) {
775 /* Definitely don't support this? */
776 if (errno == ENOENT || errno == EPROTONOSUPPORT) {
777 close(sockfd);
778 return 0;
779 } else if (errno == ENOPROTOOPT) {
780 close(sockfd);
781 /* Assume only revision 0 support (old kernel) */
782 return (revision == 0);
783 } else {
784 fprintf(stderr, "getsockopt failed strangely: %s\n",
785 strerror(errno));
786 exit(1);
787 }
788 }
789 close(sockfd);
790 return 1;
791 }
792
793
compatible_match_revision(const char * name,uint8_t revision)794 static int compatible_match_revision(const char *name, uint8_t revision)
795 {
796 return compatible_revision(name, revision, afinfo->so_rev_match);
797 }
798
compatible_target_revision(const char * name,uint8_t revision)799 static int compatible_target_revision(const char *name, uint8_t revision)
800 {
801 return compatible_revision(name, revision, afinfo->so_rev_target);
802 }
803
xtables_check_options(const char * name,const struct option * opt)804 static void xtables_check_options(const char *name, const struct option *opt)
805 {
806 for (; opt->name != NULL; ++opt)
807 if (opt->val < 0 || opt->val >= XT_OPTION_OFFSET_SCALE) {
808 fprintf(stderr, "%s: Extension %s uses invalid "
809 "option value %d\n",xt_params->program_name,
810 name, opt->val);
811 exit(1);
812 }
813 }
814
xtables_register_match(struct xtables_match * me)815 void xtables_register_match(struct xtables_match *me)
816 {
817 if (me->version == NULL) {
818 fprintf(stderr, "%s: match %s<%u> is missing a version\n",
819 xt_params->program_name, me->name, me->revision);
820 exit(1);
821 }
822 if (strcmp(me->version, XTABLES_VERSION) != 0) {
823 fprintf(stderr, "%s: match \"%s\" has version \"%s\", "
824 "but \"%s\" is required.\n",
825 xt_params->program_name, me->name,
826 me->version, XTABLES_VERSION);
827 exit(1);
828 }
829
830 if (strlen(me->name) >= XT_EXTENSION_MAXNAMELEN) {
831 fprintf(stderr, "%s: match `%s' has invalid name\n",
832 xt_params->program_name, me->name);
833 exit(1);
834 }
835
836 if (me->family >= NPROTO) {
837 fprintf(stderr,
838 "%s: BUG: match %s has invalid protocol family\n",
839 xt_params->program_name, me->name);
840 exit(1);
841 }
842
843 if (me->x6_options != NULL)
844 xtables_option_metavalidate(me->name, me->x6_options);
845 if (me->extra_opts != NULL)
846 xtables_check_options(me->name, me->extra_opts);
847
848 /* ignore not interested match */
849 if (me->family != afinfo->family && me->family != AF_UNSPEC)
850 return;
851
852 /* place on linked list of matches pending full registration */
853 me->next = xtables_pending_matches;
854 xtables_pending_matches = me;
855 }
856
xtables_fully_register_pending_match(struct xtables_match * me)857 static void xtables_fully_register_pending_match(struct xtables_match *me)
858 {
859 struct xtables_match **i, *old;
860
861 old = xtables_find_match(me->name, XTF_DURING_LOAD, NULL);
862 if (old) {
863 if (old->revision == me->revision &&
864 old->family == me->family) {
865 fprintf(stderr,
866 "%s: match `%s' already registered.\n",
867 xt_params->program_name, me->name);
868 exit(1);
869 }
870
871 /* Now we have two (or more) options, check compatibility. */
872 if (compatible_match_revision(old->name, old->revision)
873 && old->revision > me->revision)
874 return;
875
876 /* See if new match can be used. */
877 if (!compatible_match_revision(me->name, me->revision))
878 return;
879
880 /* Prefer !AF_UNSPEC over AF_UNSPEC for same revision. */
881 if (old->revision == me->revision && me->family == AF_UNSPEC)
882 return;
883
884 /* Delete old one. */
885 for (i = &xtables_matches; *i!=old; i = &(*i)->next);
886 *i = old->next;
887 }
888
889 if (me->size != XT_ALIGN(me->size)) {
890 fprintf(stderr, "%s: match `%s' has invalid size %u.\n",
891 xt_params->program_name, me->name,
892 (unsigned int)me->size);
893 exit(1);
894 }
895
896 /* Append to list. */
897 for (i = &xtables_matches; *i; i = &(*i)->next);
898 me->next = NULL;
899 *i = me;
900
901 me->m = NULL;
902 me->mflags = 0;
903 }
904
xtables_register_matches(struct xtables_match * match,unsigned int n)905 void xtables_register_matches(struct xtables_match *match, unsigned int n)
906 {
907 do {
908 xtables_register_match(&match[--n]);
909 } while (n > 0);
910 }
911
xtables_register_target(struct xtables_target * me)912 void xtables_register_target(struct xtables_target *me)
913 {
914 if (me->version == NULL) {
915 fprintf(stderr, "%s: target %s<%u> is missing a version\n",
916 xt_params->program_name, me->name, me->revision);
917 exit(1);
918 }
919 if (strcmp(me->version, XTABLES_VERSION) != 0) {
920 fprintf(stderr, "%s: target \"%s\" has version \"%s\", "
921 "but \"%s\" is required.\n",
922 xt_params->program_name, me->name,
923 me->version, XTABLES_VERSION);
924 exit(1);
925 }
926
927 if (strlen(me->name) >= XT_EXTENSION_MAXNAMELEN) {
928 fprintf(stderr, "%s: target `%s' has invalid name\n",
929 xt_params->program_name, me->name);
930 exit(1);
931 }
932
933 if (me->family >= NPROTO) {
934 fprintf(stderr,
935 "%s: BUG: target %s has invalid protocol family\n",
936 xt_params->program_name, me->name);
937 exit(1);
938 }
939
940 if (me->x6_options != NULL)
941 xtables_option_metavalidate(me->name, me->x6_options);
942 if (me->extra_opts != NULL)
943 xtables_check_options(me->name, me->extra_opts);
944
945 /* ignore not interested target */
946 if (me->family != afinfo->family && me->family != AF_UNSPEC)
947 return;
948
949 /* place on linked list of targets pending full registration */
950 me->next = xtables_pending_targets;
951 xtables_pending_targets = me;
952 }
953
xtables_fully_register_pending_target(struct xtables_target * me)954 static void xtables_fully_register_pending_target(struct xtables_target *me)
955 {
956 struct xtables_target *old;
957
958 old = xtables_find_target(me->name, XTF_DURING_LOAD);
959 if (old) {
960 struct xtables_target **i;
961
962 if (old->revision == me->revision &&
963 old->family == me->family) {
964 fprintf(stderr,
965 "%s: target `%s' already registered.\n",
966 xt_params->program_name, me->name);
967 exit(1);
968 }
969
970 /* Now we have two (or more) options, check compatibility. */
971 if (compatible_target_revision(old->name, old->revision)
972 && old->revision > me->revision)
973 return;
974
975 /* See if new target can be used. */
976 if (!compatible_target_revision(me->name, me->revision))
977 return;
978
979 /* Prefer !AF_UNSPEC over AF_UNSPEC for same revision. */
980 if (old->revision == me->revision && me->family == AF_UNSPEC)
981 return;
982
983 /* Delete old one. */
984 for (i = &xtables_targets; *i!=old; i = &(*i)->next);
985 *i = old->next;
986 }
987
988 if (me->size != XT_ALIGN(me->size)) {
989 fprintf(stderr, "%s: target `%s' has invalid size %u.\n",
990 xt_params->program_name, me->name,
991 (unsigned int)me->size);
992 exit(1);
993 }
994
995 /* Prepend to list. */
996 me->next = xtables_targets;
997 xtables_targets = me;
998 me->t = NULL;
999 me->tflags = 0;
1000 }
1001
xtables_register_targets(struct xtables_target * target,unsigned int n)1002 void xtables_register_targets(struct xtables_target *target, unsigned int n)
1003 {
1004 do {
1005 xtables_register_target(&target[--n]);
1006 } while (n > 0);
1007 }
1008
1009 /**
1010 * xtables_param_act - act on condition
1011 * @status: a constant from enum xtables_exittype
1012 *
1013 * %XTF_ONLY_ONCE: print error message that option may only be used once.
1014 * @p1: module name (e.g. "mark")
1015 * @p2(...): option in conflict (e.g. "--mark")
1016 * @p3(...): condition to match on (see extensions/ for examples)
1017 *
1018 * %XTF_NO_INVERT: option does not support inversion
1019 * @p1: module name
1020 * @p2: option in conflict
1021 * @p3: condition to match on
1022 *
1023 * %XTF_BAD_VALUE: bad value for option
1024 * @p1: module name
1025 * @p2: option with which the problem occured (e.g. "--mark")
1026 * @p3: string the user passed in (e.g. "99999999999999")
1027 *
1028 * %XTF_ONE_ACTION: two mutually exclusive actions have been specified
1029 * @p1: module name
1030 *
1031 * Displays an error message and exits the program.
1032 */
xtables_param_act(unsigned int status,const char * p1,...)1033 void xtables_param_act(unsigned int status, const char *p1, ...)
1034 {
1035 const char *p2, *p3;
1036 va_list args;
1037 bool b;
1038
1039 va_start(args, p1);
1040
1041 switch (status) {
1042 case XTF_ONLY_ONCE:
1043 p2 = va_arg(args, const char *);
1044 b = va_arg(args, unsigned int);
1045 if (!b)
1046 return;
1047 xt_params->exit_err(PARAMETER_PROBLEM,
1048 "%s: \"%s\" option may only be specified once",
1049 p1, p2);
1050 break;
1051 case XTF_NO_INVERT:
1052 p2 = va_arg(args, const char *);
1053 b = va_arg(args, unsigned int);
1054 if (!b)
1055 return;
1056 xt_params->exit_err(PARAMETER_PROBLEM,
1057 "%s: \"%s\" option cannot be inverted", p1, p2);
1058 break;
1059 case XTF_BAD_VALUE:
1060 p2 = va_arg(args, const char *);
1061 p3 = va_arg(args, const char *);
1062 xt_params->exit_err(PARAMETER_PROBLEM,
1063 "%s: Bad value for \"%s\" option: \"%s\"",
1064 p1, p2, p3);
1065 break;
1066 case XTF_ONE_ACTION:
1067 b = va_arg(args, unsigned int);
1068 if (!b)
1069 return;
1070 xt_params->exit_err(PARAMETER_PROBLEM,
1071 "%s: At most one action is possible", p1);
1072 break;
1073 default:
1074 xt_params->exit_err(status, p1, args);
1075 break;
1076 }
1077
1078 va_end(args);
1079 }
1080
xtables_ipaddr_to_numeric(const struct in_addr * addrp)1081 const char *xtables_ipaddr_to_numeric(const struct in_addr *addrp)
1082 {
1083 static char buf[20];
1084 const unsigned char *bytep = (const void *)&addrp->s_addr;
1085
1086 sprintf(buf, "%u.%u.%u.%u", bytep[0], bytep[1], bytep[2], bytep[3]);
1087 return buf;
1088 }
1089
ipaddr_to_host(const struct in_addr * addr)1090 static const char *ipaddr_to_host(const struct in_addr *addr)
1091 {
1092 struct hostent *host;
1093
1094 host = gethostbyaddr(addr, sizeof(struct in_addr), AF_INET);
1095 if (host == NULL)
1096 return NULL;
1097
1098 return host->h_name;
1099 }
1100
ipaddr_to_network(const struct in_addr * addr)1101 static const char *ipaddr_to_network(const struct in_addr *addr)
1102 {
1103 struct netent *net;
1104
1105 if ((net = getnetbyaddr(ntohl(addr->s_addr), AF_INET)) != NULL)
1106 return net->n_name;
1107
1108 return NULL;
1109 }
1110
xtables_ipaddr_to_anyname(const struct in_addr * addr)1111 const char *xtables_ipaddr_to_anyname(const struct in_addr *addr)
1112 {
1113 const char *name;
1114
1115 if ((name = ipaddr_to_host(addr)) != NULL ||
1116 (name = ipaddr_to_network(addr)) != NULL)
1117 return name;
1118
1119 return xtables_ipaddr_to_numeric(addr);
1120 }
1121
xtables_ipmask_to_numeric(const struct in_addr * mask)1122 const char *xtables_ipmask_to_numeric(const struct in_addr *mask)
1123 {
1124 static char buf[20];
1125 uint32_t maskaddr, bits;
1126 int i;
1127
1128 maskaddr = ntohl(mask->s_addr);
1129
1130 if (maskaddr == 0xFFFFFFFFL)
1131 /* we don't want to see "/32" */
1132 return "";
1133
1134 i = 32;
1135 bits = 0xFFFFFFFEL;
1136 while (--i >= 0 && maskaddr != bits)
1137 bits <<= 1;
1138 if (i >= 0)
1139 sprintf(buf, "/%d", i);
1140 else
1141 /* mask was not a decent combination of 1's and 0's */
1142 sprintf(buf, "/%s", xtables_ipaddr_to_numeric(mask));
1143
1144 return buf;
1145 }
1146
__numeric_to_ipaddr(const char * dotted,bool is_mask)1147 static struct in_addr *__numeric_to_ipaddr(const char *dotted, bool is_mask)
1148 {
1149 static struct in_addr addr;
1150 unsigned char *addrp;
1151 unsigned int onebyte;
1152 char buf[20], *p, *q;
1153 int i;
1154
1155 /* copy dotted string, because we need to modify it */
1156 strncpy(buf, dotted, sizeof(buf) - 1);
1157 buf[sizeof(buf) - 1] = '\0';
1158 addrp = (void *)&addr.s_addr;
1159
1160 p = buf;
1161 for (i = 0; i < 3; ++i) {
1162 if ((q = strchr(p, '.')) == NULL) {
1163 if (is_mask)
1164 return NULL;
1165
1166 /* autocomplete, this is a network address */
1167 if (!xtables_strtoui(p, NULL, &onebyte, 0, UINT8_MAX))
1168 return NULL;
1169
1170 addrp[i] = onebyte;
1171 while (i < 3)
1172 addrp[++i] = 0;
1173
1174 return &addr;
1175 }
1176
1177 *q = '\0';
1178 if (!xtables_strtoui(p, NULL, &onebyte, 0, UINT8_MAX))
1179 return NULL;
1180
1181 addrp[i] = onebyte;
1182 p = q + 1;
1183 }
1184
1185 /* we have checked 3 bytes, now we check the last one */
1186 if (!xtables_strtoui(p, NULL, &onebyte, 0, UINT8_MAX))
1187 return NULL;
1188
1189 addrp[3] = onebyte;
1190 return &addr;
1191 }
1192
xtables_numeric_to_ipaddr(const char * dotted)1193 struct in_addr *xtables_numeric_to_ipaddr(const char *dotted)
1194 {
1195 return __numeric_to_ipaddr(dotted, false);
1196 }
1197
xtables_numeric_to_ipmask(const char * dotted)1198 struct in_addr *xtables_numeric_to_ipmask(const char *dotted)
1199 {
1200 return __numeric_to_ipaddr(dotted, true);
1201 }
1202
network_to_ipaddr(const char * name)1203 static struct in_addr *network_to_ipaddr(const char *name)
1204 {
1205 static struct in_addr addr;
1206 struct netent *net;
1207
1208 if ((net = getnetbyname(name)) != NULL) {
1209 if (net->n_addrtype != AF_INET)
1210 return NULL;
1211 addr.s_addr = htonl(net->n_net);
1212 return &addr;
1213 }
1214
1215 return NULL;
1216 }
1217
host_to_ipaddr(const char * name,unsigned int * naddr)1218 static struct in_addr *host_to_ipaddr(const char *name, unsigned int *naddr)
1219 {
1220 struct hostent *host;
1221 struct in_addr *addr;
1222 unsigned int i;
1223
1224 *naddr = 0;
1225 if ((host = gethostbyname(name)) != NULL) {
1226 if (host->h_addrtype != AF_INET ||
1227 host->h_length != sizeof(struct in_addr))
1228 return NULL;
1229
1230 while (host->h_addr_list[*naddr] != NULL)
1231 ++*naddr;
1232 addr = xtables_calloc(*naddr, sizeof(struct in_addr));
1233 for (i = 0; i < *naddr; i++)
1234 memcpy(&addr[i], host->h_addr_list[i],
1235 sizeof(struct in_addr));
1236 return addr;
1237 }
1238
1239 return NULL;
1240 }
1241
1242 static struct in_addr *
ipparse_hostnetwork(const char * name,unsigned int * naddrs)1243 ipparse_hostnetwork(const char *name, unsigned int *naddrs)
1244 {
1245 struct in_addr *addrptmp, *addrp;
1246
1247 if ((addrptmp = xtables_numeric_to_ipaddr(name)) != NULL ||
1248 (addrptmp = network_to_ipaddr(name)) != NULL) {
1249 addrp = xtables_malloc(sizeof(struct in_addr));
1250 memcpy(addrp, addrptmp, sizeof(*addrp));
1251 *naddrs = 1;
1252 return addrp;
1253 }
1254 if ((addrptmp = host_to_ipaddr(name, naddrs)) != NULL)
1255 return addrptmp;
1256
1257 xt_params->exit_err(PARAMETER_PROBLEM, "host/network `%s' not found", name);
1258 }
1259
parse_ipmask(const char * mask)1260 static struct in_addr *parse_ipmask(const char *mask)
1261 {
1262 static struct in_addr maskaddr;
1263 struct in_addr *addrp;
1264 unsigned int bits;
1265
1266 if (mask == NULL) {
1267 /* no mask at all defaults to 32 bits */
1268 maskaddr.s_addr = 0xFFFFFFFF;
1269 return &maskaddr;
1270 }
1271 if ((addrp = xtables_numeric_to_ipmask(mask)) != NULL)
1272 /* dotted_to_addr already returns a network byte order addr */
1273 return addrp;
1274 if (!xtables_strtoui(mask, NULL, &bits, 0, 32))
1275 xt_params->exit_err(PARAMETER_PROBLEM,
1276 "invalid mask `%s' specified", mask);
1277 if (bits != 0) {
1278 maskaddr.s_addr = htonl(0xFFFFFFFF << (32 - bits));
1279 return &maskaddr;
1280 }
1281
1282 maskaddr.s_addr = 0U;
1283 return &maskaddr;
1284 }
1285
xtables_ipparse_multiple(const char * name,struct in_addr ** addrpp,struct in_addr ** maskpp,unsigned int * naddrs)1286 void xtables_ipparse_multiple(const char *name, struct in_addr **addrpp,
1287 struct in_addr **maskpp, unsigned int *naddrs)
1288 {
1289 struct in_addr *addrp;
1290 char buf[256], *p;
1291 unsigned int len, i, j, n, count = 1;
1292 const char *loop = name;
1293
1294 while ((loop = strchr(loop, ',')) != NULL) {
1295 ++count;
1296 ++loop; /* skip ',' */
1297 }
1298
1299 *addrpp = xtables_malloc(sizeof(struct in_addr) * count);
1300 *maskpp = xtables_malloc(sizeof(struct in_addr) * count);
1301
1302 loop = name;
1303
1304 for (i = 0; i < count; ++i) {
1305 if (loop == NULL)
1306 break;
1307 if (*loop == ',')
1308 ++loop;
1309 if (*loop == '\0')
1310 break;
1311 p = strchr(loop, ',');
1312 if (p != NULL)
1313 len = p - loop;
1314 else
1315 len = strlen(loop);
1316 if (len == 0 || sizeof(buf) - 1 < len)
1317 break;
1318
1319 strncpy(buf, loop, len);
1320 buf[len] = '\0';
1321 loop += len;
1322 if ((p = strrchr(buf, '/')) != NULL) {
1323 *p = '\0';
1324 addrp = parse_ipmask(p + 1);
1325 } else {
1326 addrp = parse_ipmask(NULL);
1327 }
1328 memcpy(*maskpp + i, addrp, sizeof(*addrp));
1329
1330 /* if a null mask is given, the name is ignored, like in "any/0" */
1331 if ((*maskpp + i)->s_addr == 0)
1332 /*
1333 * A bit pointless to process multiple addresses
1334 * in this case...
1335 */
1336 strcpy(buf, "0.0.0.0");
1337
1338 addrp = ipparse_hostnetwork(buf, &n);
1339 if (n > 1) {
1340 count += n - 1;
1341 *addrpp = xtables_realloc(*addrpp,
1342 sizeof(struct in_addr) * count);
1343 *maskpp = xtables_realloc(*maskpp,
1344 sizeof(struct in_addr) * count);
1345 for (j = 0; j < n; ++j)
1346 /* for each new addr */
1347 memcpy(*addrpp + i + j, addrp + j,
1348 sizeof(*addrp));
1349 for (j = 1; j < n; ++j)
1350 /* for each new mask */
1351 memcpy(*maskpp + i + j, *maskpp + i,
1352 sizeof(*addrp));
1353 i += n - 1;
1354 } else {
1355 memcpy(*addrpp + i, addrp, sizeof(*addrp));
1356 }
1357 /* free what ipparse_hostnetwork had allocated: */
1358 free(addrp);
1359 }
1360 *naddrs = count;
1361 for (i = 0; i < count; ++i)
1362 (*addrpp+i)->s_addr &= (*maskpp+i)->s_addr;
1363 }
1364
1365
1366 /**
1367 * xtables_ipparse_any - transform arbitrary name to in_addr
1368 *
1369 * Possible inputs (pseudo regex):
1370 * m{^($hostname|$networkname|$ipaddr)(/$mask)?}
1371 * "1.2.3.4/5", "1.2.3.4", "hostname", "networkname"
1372 */
xtables_ipparse_any(const char * name,struct in_addr ** addrpp,struct in_addr * maskp,unsigned int * naddrs)1373 void xtables_ipparse_any(const char *name, struct in_addr **addrpp,
1374 struct in_addr *maskp, unsigned int *naddrs)
1375 {
1376 unsigned int i, j, k, n;
1377 struct in_addr *addrp;
1378 char buf[256], *p;
1379
1380 strncpy(buf, name, sizeof(buf) - 1);
1381 buf[sizeof(buf) - 1] = '\0';
1382 if ((p = strrchr(buf, '/')) != NULL) {
1383 *p = '\0';
1384 addrp = parse_ipmask(p + 1);
1385 } else {
1386 addrp = parse_ipmask(NULL);
1387 }
1388 memcpy(maskp, addrp, sizeof(*maskp));
1389
1390 /* if a null mask is given, the name is ignored, like in "any/0" */
1391 if (maskp->s_addr == 0U)
1392 strcpy(buf, "0.0.0.0");
1393
1394 addrp = *addrpp = ipparse_hostnetwork(buf, naddrs);
1395 n = *naddrs;
1396 for (i = 0, j = 0; i < n; ++i) {
1397 addrp[j++].s_addr &= maskp->s_addr;
1398 for (k = 0; k < j - 1; ++k)
1399 if (addrp[k].s_addr == addrp[j-1].s_addr) {
1400 /*
1401 * Nuke the dup by copying an address from the
1402 * tail here, and check the current position
1403 * again (--j).
1404 */
1405 memcpy(&addrp[--j], &addrp[--*naddrs],
1406 sizeof(struct in_addr));
1407 break;
1408 }
1409 }
1410 }
1411
xtables_ip6addr_to_numeric(const struct in6_addr * addrp)1412 const char *xtables_ip6addr_to_numeric(const struct in6_addr *addrp)
1413 {
1414 /* 0000:0000:0000:0000:0000:0000:000.000.000.000
1415 * 0000:0000:0000:0000:0000:0000:0000:0000 */
1416 static char buf[50+1];
1417 return inet_ntop(AF_INET6, addrp, buf, sizeof(buf));
1418 }
1419
ip6addr_to_host(const struct in6_addr * addr)1420 static const char *ip6addr_to_host(const struct in6_addr *addr)
1421 {
1422 static char hostname[NI_MAXHOST];
1423 struct sockaddr_in6 saddr;
1424 int err;
1425
1426 memset(&saddr, 0, sizeof(struct sockaddr_in6));
1427 memcpy(&saddr.sin6_addr, addr, sizeof(*addr));
1428 saddr.sin6_family = AF_INET6;
1429
1430 err = getnameinfo((const void *)&saddr, sizeof(struct sockaddr_in6),
1431 hostname, sizeof(hostname) - 1, NULL, 0, 0);
1432 if (err != 0) {
1433 #ifdef DEBUG
1434 fprintf(stderr,"IP2Name: %s\n",gai_strerror(err));
1435 #endif
1436 return NULL;
1437 }
1438
1439 #ifdef DEBUG
1440 fprintf (stderr, "\naddr2host: %s\n", hostname);
1441 #endif
1442 return hostname;
1443 }
1444
xtables_ip6addr_to_anyname(const struct in6_addr * addr)1445 const char *xtables_ip6addr_to_anyname(const struct in6_addr *addr)
1446 {
1447 const char *name;
1448
1449 if ((name = ip6addr_to_host(addr)) != NULL)
1450 return name;
1451
1452 return xtables_ip6addr_to_numeric(addr);
1453 }
1454
ip6addr_prefix_length(const struct in6_addr * k)1455 static int ip6addr_prefix_length(const struct in6_addr *k)
1456 {
1457 unsigned int bits = 0;
1458 uint32_t a, b, c, d;
1459
1460 a = ntohl(k->s6_addr32[0]);
1461 b = ntohl(k->s6_addr32[1]);
1462 c = ntohl(k->s6_addr32[2]);
1463 d = ntohl(k->s6_addr32[3]);
1464 while (a & 0x80000000U) {
1465 ++bits;
1466 a <<= 1;
1467 a |= (b >> 31) & 1;
1468 b <<= 1;
1469 b |= (c >> 31) & 1;
1470 c <<= 1;
1471 c |= (d >> 31) & 1;
1472 d <<= 1;
1473 }
1474 if (a != 0 || b != 0 || c != 0 || d != 0)
1475 return -1;
1476 return bits;
1477 }
1478
xtables_ip6mask_to_numeric(const struct in6_addr * addrp)1479 const char *xtables_ip6mask_to_numeric(const struct in6_addr *addrp)
1480 {
1481 static char buf[50+2];
1482 int l = ip6addr_prefix_length(addrp);
1483
1484 if (l == -1) {
1485 strcpy(buf, "/");
1486 strcat(buf, xtables_ip6addr_to_numeric(addrp));
1487 return buf;
1488 }
1489 sprintf(buf, "/%d", l);
1490 return buf;
1491 }
1492
xtables_numeric_to_ip6addr(const char * num)1493 struct in6_addr *xtables_numeric_to_ip6addr(const char *num)
1494 {
1495 static struct in6_addr ap;
1496 int err;
1497
1498 if ((err = inet_pton(AF_INET6, num, &ap)) == 1)
1499 return ≈
1500 #ifdef DEBUG
1501 fprintf(stderr, "\nnumeric2addr: %d\n", err);
1502 #endif
1503 return NULL;
1504 }
1505
1506 static struct in6_addr *
host_to_ip6addr(const char * name,unsigned int * naddr)1507 host_to_ip6addr(const char *name, unsigned int *naddr)
1508 {
1509 struct in6_addr *addr;
1510 struct addrinfo hints;
1511 struct addrinfo *res, *p;
1512 int err;
1513 unsigned int i;
1514
1515 memset(&hints, 0, sizeof(hints));
1516 hints.ai_flags = AI_CANONNAME;
1517 hints.ai_family = AF_INET6;
1518 hints.ai_socktype = SOCK_RAW;
1519
1520 *naddr = 0;
1521 if ((err = getaddrinfo(name, NULL, &hints, &res)) != 0) {
1522 #ifdef DEBUG
1523 fprintf(stderr,"Name2IP: %s\n",gai_strerror(err));
1524 #endif
1525 return NULL;
1526 } else {
1527 /* Find length of address chain */
1528 for (p = res; p != NULL; p = p->ai_next)
1529 ++*naddr;
1530 #ifdef DEBUG
1531 fprintf(stderr, "resolved: len=%d %s ", res->ai_addrlen,
1532 xtables_ip6addr_to_numeric(&((struct sockaddr_in6 *)res->ai_addr)->sin6_addr));
1533 #endif
1534 /* Copy each element of the address chain */
1535 addr = xtables_calloc(*naddr, sizeof(struct in6_addr));
1536 for (i = 0, p = res; p != NULL; p = p->ai_next)
1537 memcpy(&addr[i++],
1538 &((const struct sockaddr_in6 *)p->ai_addr)->sin6_addr,
1539 sizeof(struct in6_addr));
1540 freeaddrinfo(res);
1541 return addr;
1542 }
1543
1544 return NULL;
1545 }
1546
network_to_ip6addr(const char * name)1547 static struct in6_addr *network_to_ip6addr(const char *name)
1548 {
1549 /* abort();*/
1550 /* TODO: not implemented yet, but the exception breaks the
1551 * name resolvation */
1552 return NULL;
1553 }
1554
1555 static struct in6_addr *
ip6parse_hostnetwork(const char * name,unsigned int * naddrs)1556 ip6parse_hostnetwork(const char *name, unsigned int *naddrs)
1557 {
1558 struct in6_addr *addrp, *addrptmp;
1559
1560 if ((addrptmp = xtables_numeric_to_ip6addr(name)) != NULL ||
1561 (addrptmp = network_to_ip6addr(name)) != NULL) {
1562 addrp = xtables_malloc(sizeof(struct in6_addr));
1563 memcpy(addrp, addrptmp, sizeof(*addrp));
1564 *naddrs = 1;
1565 return addrp;
1566 }
1567 if ((addrp = host_to_ip6addr(name, naddrs)) != NULL)
1568 return addrp;
1569
1570 xt_params->exit_err(PARAMETER_PROBLEM, "host/network `%s' not found", name);
1571 }
1572
parse_ip6mask(char * mask)1573 static struct in6_addr *parse_ip6mask(char *mask)
1574 {
1575 static struct in6_addr maskaddr;
1576 struct in6_addr *addrp;
1577 unsigned int bits;
1578
1579 if (mask == NULL) {
1580 /* no mask at all defaults to 128 bits */
1581 memset(&maskaddr, 0xff, sizeof maskaddr);
1582 return &maskaddr;
1583 }
1584 if ((addrp = xtables_numeric_to_ip6addr(mask)) != NULL)
1585 return addrp;
1586 if (!xtables_strtoui(mask, NULL, &bits, 0, 128))
1587 xt_params->exit_err(PARAMETER_PROBLEM,
1588 "invalid mask `%s' specified", mask);
1589 if (bits != 0) {
1590 char *p = (void *)&maskaddr;
1591 memset(p, 0xff, bits / 8);
1592 memset(p + (bits / 8) + 1, 0, (128 - bits) / 8);
1593 p[bits/8] = 0xff << (8 - (bits & 7));
1594 return &maskaddr;
1595 }
1596
1597 memset(&maskaddr, 0, sizeof(maskaddr));
1598 return &maskaddr;
1599 }
1600
1601 void
xtables_ip6parse_multiple(const char * name,struct in6_addr ** addrpp,struct in6_addr ** maskpp,unsigned int * naddrs)1602 xtables_ip6parse_multiple(const char *name, struct in6_addr **addrpp,
1603 struct in6_addr **maskpp, unsigned int *naddrs)
1604 {
1605 static const struct in6_addr zero_addr;
1606 struct in6_addr *addrp;
1607 char buf[256], *p;
1608 unsigned int len, i, j, n, count = 1;
1609 const char *loop = name;
1610
1611 while ((loop = strchr(loop, ',')) != NULL) {
1612 ++count;
1613 ++loop; /* skip ',' */
1614 }
1615
1616 *addrpp = xtables_malloc(sizeof(struct in6_addr) * count);
1617 *maskpp = xtables_malloc(sizeof(struct in6_addr) * count);
1618
1619 loop = name;
1620
1621 for (i = 0; i < count /*NB: count can grow*/; ++i) {
1622 if (loop == NULL)
1623 break;
1624 if (*loop == ',')
1625 ++loop;
1626 if (*loop == '\0')
1627 break;
1628 p = strchr(loop, ',');
1629 if (p != NULL)
1630 len = p - loop;
1631 else
1632 len = strlen(loop);
1633 if (len == 0 || sizeof(buf) - 1 < len)
1634 break;
1635
1636 strncpy(buf, loop, len);
1637 buf[len] = '\0';
1638 loop += len;
1639 if ((p = strrchr(buf, '/')) != NULL) {
1640 *p = '\0';
1641 addrp = parse_ip6mask(p + 1);
1642 } else {
1643 addrp = parse_ip6mask(NULL);
1644 }
1645 memcpy(*maskpp + i, addrp, sizeof(*addrp));
1646
1647 /* if a null mask is given, the name is ignored, like in "any/0" */
1648 if (memcmp(*maskpp + i, &zero_addr, sizeof(zero_addr)) == 0)
1649 strcpy(buf, "::");
1650
1651 addrp = ip6parse_hostnetwork(buf, &n);
1652 if (n > 1) {
1653 count += n - 1;
1654 *addrpp = xtables_realloc(*addrpp,
1655 sizeof(struct in6_addr) * count);
1656 *maskpp = xtables_realloc(*maskpp,
1657 sizeof(struct in6_addr) * count);
1658 for (j = 0; j < n; ++j)
1659 /* for each new addr */
1660 memcpy(*addrpp + i + j, addrp + j,
1661 sizeof(*addrp));
1662 for (j = 1; j < n; ++j)
1663 /* for each new mask */
1664 memcpy(*maskpp + i + j, *maskpp + i,
1665 sizeof(*addrp));
1666 i += n - 1;
1667 } else {
1668 memcpy(*addrpp + i, addrp, sizeof(*addrp));
1669 }
1670 /* free what ip6parse_hostnetwork had allocated: */
1671 free(addrp);
1672 }
1673 *naddrs = count;
1674 for (i = 0; i < count; ++i)
1675 for (j = 0; j < 4; ++j)
1676 (*addrpp+i)->s6_addr32[j] &= (*maskpp+i)->s6_addr32[j];
1677 }
1678
xtables_ip6parse_any(const char * name,struct in6_addr ** addrpp,struct in6_addr * maskp,unsigned int * naddrs)1679 void xtables_ip6parse_any(const char *name, struct in6_addr **addrpp,
1680 struct in6_addr *maskp, unsigned int *naddrs)
1681 {
1682 static const struct in6_addr zero_addr;
1683 struct in6_addr *addrp;
1684 unsigned int i, j, k, n;
1685 char buf[256], *p;
1686
1687 strncpy(buf, name, sizeof(buf) - 1);
1688 buf[sizeof(buf)-1] = '\0';
1689 if ((p = strrchr(buf, '/')) != NULL) {
1690 *p = '\0';
1691 addrp = parse_ip6mask(p + 1);
1692 } else {
1693 addrp = parse_ip6mask(NULL);
1694 }
1695 memcpy(maskp, addrp, sizeof(*maskp));
1696
1697 /* if a null mask is given, the name is ignored, like in "any/0" */
1698 if (memcmp(maskp, &zero_addr, sizeof(zero_addr)) == 0)
1699 strcpy(buf, "::");
1700
1701 addrp = *addrpp = ip6parse_hostnetwork(buf, naddrs);
1702 n = *naddrs;
1703 for (i = 0, j = 0; i < n; ++i) {
1704 for (k = 0; k < 4; ++k)
1705 addrp[j].s6_addr32[k] &= maskp->s6_addr32[k];
1706 ++j;
1707 for (k = 0; k < j - 1; ++k)
1708 if (IN6_ARE_ADDR_EQUAL(&addrp[k], &addrp[j - 1])) {
1709 /*
1710 * Nuke the dup by copying an address from the
1711 * tail here, and check the current position
1712 * again (--j).
1713 */
1714 memcpy(&addrp[--j], &addrp[--*naddrs],
1715 sizeof(struct in_addr));
1716 break;
1717 }
1718 }
1719 }
1720
xtables_save_string(const char * value)1721 void xtables_save_string(const char *value)
1722 {
1723 static const char no_quote_chars[] = "_-0123456789"
1724 "abcdefghijklmnopqrstuvwxyz"
1725 "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
1726 static const char escape_chars[] = "\"\\'";
1727 size_t length;
1728 const char *p;
1729
1730 length = strspn(value, no_quote_chars);
1731 if (length > 0 && value[length] == 0) {
1732 /* no quoting required */
1733 putchar(' ');
1734 fputs(value, stdout);
1735 } else {
1736 /* there is at least one dangerous character in the
1737 value, which we have to quote. Write double quotes
1738 around the value and escape special characters with
1739 a backslash */
1740 printf(" \"");
1741
1742 for (p = strpbrk(value, escape_chars); p != NULL;
1743 p = strpbrk(value, escape_chars)) {
1744 if (p > value)
1745 fwrite(value, 1, p - value, stdout);
1746 putchar('\\');
1747 putchar(*p);
1748 value = p + 1;
1749 }
1750
1751 /* print the rest and finish the double quoted
1752 string */
1753 fputs(value, stdout);
1754 putchar('\"');
1755 }
1756 }
1757
1758 /**
1759 * Check for option-intrapositional negation.
1760 * Do not use in new code.
1761 */
xtables_check_inverse(const char option[],int * invert,int * my_optind,int argc,char ** argv)1762 int xtables_check_inverse(const char option[], int *invert,
1763 int *my_optind, int argc, char **argv)
1764 {
1765 if (option == NULL || strcmp(option, "!") != 0)
1766 return false;
1767
1768 fprintf(stderr, "Using intrapositioned negation "
1769 "(`--option ! this`) is deprecated in favor of "
1770 "extrapositioned (`! --option this`).\n");
1771
1772 if (*invert)
1773 xt_params->exit_err(PARAMETER_PROBLEM,
1774 "Multiple `!' flags not allowed");
1775 *invert = true;
1776 if (my_optind != NULL) {
1777 optarg = argv[*my_optind];
1778 ++*my_optind;
1779 if (argc && *my_optind > argc)
1780 xt_params->exit_err(PARAMETER_PROBLEM,
1781 "no argument following `!'");
1782 }
1783
1784 return true;
1785 }
1786
1787 const struct xtables_pprot xtables_chain_protos[] = {
1788 {"tcp", IPPROTO_TCP},
1789 {"sctp", IPPROTO_SCTP},
1790 {"udp", IPPROTO_UDP},
1791 {"udplite", IPPROTO_UDPLITE},
1792 {"icmp", IPPROTO_ICMP},
1793 {"icmpv6", IPPROTO_ICMPV6},
1794 {"ipv6-icmp", IPPROTO_ICMPV6},
1795 {"esp", IPPROTO_ESP},
1796 {"ah", IPPROTO_AH},
1797 {"ipv6-mh", IPPROTO_MH},
1798 {"mh", IPPROTO_MH},
1799 {"all", 0},
1800 {NULL},
1801 };
1802
1803 uint16_t
xtables_parse_protocol(const char * s)1804 xtables_parse_protocol(const char *s)
1805 {
1806 const struct protoent *pent;
1807 unsigned int proto, i;
1808
1809 if (xtables_strtoui(s, NULL, &proto, 0, UINT8_MAX))
1810 return proto;
1811
1812 /* first deal with the special case of 'all' to prevent
1813 * people from being able to redefine 'all' in nsswitch
1814 * and/or provoke expensive [not working] ldap/nis/...
1815 * lookups */
1816 if (strcmp(s, "all") == 0)
1817 return 0;
1818
1819 pent = getprotobyname(s);
1820 if (pent != NULL)
1821 return pent->p_proto;
1822
1823 for (i = 0; i < ARRAY_SIZE(xtables_chain_protos); ++i) {
1824 if (xtables_chain_protos[i].name == NULL)
1825 continue;
1826 if (strcmp(s, xtables_chain_protos[i].name) == 0)
1827 return xtables_chain_protos[i].num;
1828 }
1829 xt_params->exit_err(PARAMETER_PROBLEM,
1830 "unknown protocol \"%s\" specified", s);
1831 return -1;
1832 }
1833