2 * (C) 2000-2006 by the netfilter coreteam <coreteam@netfilter.org>:
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.
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.
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.
30 #include <sys/socket.h>
32 #include <sys/statfs.h>
33 #include <sys/types.h>
34 #include <sys/utsname.h>
36 #include <arpa/inet.h>
37 #if defined(HAVE_LINUX_MAGIC_H)
38 # include <linux/magic.h> /* for PROC_SUPER_MAGIC */
39 #elif defined(HAVE_LINUX_PROC_FS_H)
40 # include <linux/proc_fs.h> /* Linux 2.4 */
42 # define PROC_SUPER_MAGIC 0x9fa0
46 #include <limits.h> /* INT_MAX in ip_tables.h/ip6_tables.h */
47 #include <linux/netfilter_ipv4/ip_tables.h>
48 #include <linux/netfilter_ipv6/ip6_tables.h>
49 #include <libiptc/libxtc.h>
51 #ifndef NO_SHARED_LIBS
54 #ifndef IPT_SO_GET_REVISION_MATCH /* Old kernel source. */
55 # define IPT_SO_GET_REVISION_MATCH (IPT_BASE_CTL + 2)
56 # define IPT_SO_GET_REVISION_TARGET (IPT_BASE_CTL + 3)
58 #ifndef IP6T_SO_GET_REVISION_MATCH /* Old kernel source. */
59 # define IP6T_SO_GET_REVISION_MATCH 68
60 # define IP6T_SO_GET_REVISION_TARGET 69
63 #include "iptables/internal.h"
68 #ifndef PROC_SYS_MODPROBE
69 #define PROC_SYS_MODPROBE "/proc/sys/kernel/modprobe"
72 /* we need this for ip6?tables-restore. ip6?tables-restore.c sets line to the
73 * current line of the input file, in order to give a more precise error
74 * message. ip6?tables itself doesn't need this, so it is initialized to the
75 * magic number of -1 */
78 void basic_exit_err(enum xtables_exittype status, const char *msg, ...) __attribute__((noreturn, format(printf,2,3)));
80 struct xtables_globals *xt_params = NULL;
82 void basic_exit_err(enum xtables_exittype status, const char *msg, ...)
87 fprintf(stderr, "%s v%s: ", xt_params->program_name, xt_params->program_version);
88 vfprintf(stderr, msg, args);
90 fprintf(stderr, "\n");
94 void xtables_free_opts(int unused)
96 if (xt_params->opts != xt_params->orig_opts) {
97 free(xt_params->opts);
98 xt_params->opts = NULL;
102 struct option *xtables_merge_options(struct option *orig_opts,
103 struct option *oldopts,
104 const struct option *newopts,
105 unsigned int *option_offset)
107 unsigned int num_oold = 0, num_old = 0, num_new = 0, i;
108 struct option *merge, *mp;
113 for (num_oold = 0; orig_opts[num_oold].name; num_oold++) ;
115 for (num_old = 0; oldopts[num_old].name; num_old++) ;
116 for (num_new = 0; newopts[num_new].name; num_new++) ;
119 * Since @oldopts also has @orig_opts already (and does so at the
120 * start), skip these entries.
125 merge = malloc(sizeof(*mp) * (num_oold + num_old + num_new + 1));
129 /* Let the base options -[ADI...] have precedence over everything */
130 memcpy(merge, orig_opts, sizeof(*mp) * num_oold);
131 mp = merge + num_oold;
133 /* Second, the new options */
134 xt_params->option_offset += XT_OPTION_OFFSET_SCALE;
135 *option_offset = xt_params->option_offset;
136 memcpy(mp, newopts, sizeof(*mp) * num_new);
138 for (i = 0; i < num_new; ++i, ++mp)
139 mp->val += *option_offset;
141 /* Third, the old options */
142 memcpy(mp, oldopts, sizeof(*mp) * num_old);
144 xtables_free_opts(0);
146 /* Clear trailing entry */
147 memset(mp, 0, sizeof(*mp));
151 static const struct xtables_afinfo afinfo_ipv4 = {
153 .proc_exists = "/proc/net/ip_tables_names",
154 .libprefix = "libipt_",
155 .family = NFPROTO_IPV4,
156 .ipproto = IPPROTO_IP,
157 .so_rev_match = IPT_SO_GET_REVISION_MATCH,
158 .so_rev_target = IPT_SO_GET_REVISION_TARGET,
161 static const struct xtables_afinfo afinfo_ipv6 = {
162 .kmod = "ip6_tables",
163 .proc_exists = "/proc/net/ip6_tables_names",
164 .libprefix = "libip6t_",
165 .family = NFPROTO_IPV6,
166 .ipproto = IPPROTO_IPV6,
167 .so_rev_match = IP6T_SO_GET_REVISION_MATCH,
168 .so_rev_target = IP6T_SO_GET_REVISION_TARGET,
171 /* Dummy families for arptables-compat and ebtables-compat. Leave structure
172 * fields that we don't use unset.
174 static const struct xtables_afinfo afinfo_bridge = {
175 .libprefix = "libebt_",
176 .family = NFPROTO_BRIDGE,
179 static const struct xtables_afinfo afinfo_arp = {
180 .libprefix = "libarpt_",
181 .family = NFPROTO_ARP,
184 const struct xtables_afinfo *afinfo;
186 /* Search path for Xtables .so files */
187 static const char *xtables_libdir;
189 /* the path to command to load kernel module */
190 const char *xtables_modprobe_program;
192 /* Keep track of matches/targets pending full registration: linked lists. */
193 struct xtables_match *xtables_pending_matches;
194 struct xtables_target *xtables_pending_targets;
196 /* Keep track of fully registered external matches/targets: linked lists. */
197 struct xtables_match *xtables_matches;
198 struct xtables_target *xtables_targets;
200 /* Fully register a match/target which was previously partially registered. */
201 static void xtables_fully_register_pending_match(struct xtables_match *me);
202 static void xtables_fully_register_pending_target(struct xtables_target *me);
204 void xtables_init(void)
206 xtables_libdir = getenv("XTABLES_LIBDIR");
207 if (xtables_libdir != NULL)
209 xtables_libdir = getenv("IPTABLES_LIB_DIR");
210 if (xtables_libdir != NULL) {
211 fprintf(stderr, "IPTABLES_LIB_DIR is deprecated, "
212 "use XTABLES_LIBDIR.\n");
216 * Well yes, IP6TABLES_LIB_DIR is of lower priority over
217 * IPTABLES_LIB_DIR since this moved to libxtables; I think that is ok
218 * for these env vars are deprecated anyhow, and in light of the
219 * (shared) libxt_*.so files, makes less sense to have
220 * IPTABLES_LIB_DIR != IP6TABLES_LIB_DIR.
222 xtables_libdir = getenv("IP6TABLES_LIB_DIR");
223 if (xtables_libdir != NULL) {
224 fprintf(stderr, "IP6TABLES_LIB_DIR is deprecated, "
225 "use XTABLES_LIBDIR.\n");
228 xtables_libdir = XTABLES_LIBDIR;
231 void xtables_set_nfproto(uint8_t nfproto)
235 afinfo = &afinfo_ipv4;
238 afinfo = &afinfo_ipv6;
241 afinfo = &afinfo_bridge;
244 afinfo = &afinfo_arp;
247 fprintf(stderr, "libxtables: unhandled NFPROTO in %s\n",
253 * xtables_set_params - set the global parameters used by xtables
254 * @xtp: input xtables_globals structure
256 * The app is expected to pass a valid xtables_globals data-filled
258 * @xtp cannot be NULL
260 * Returns -1 on failure to set and 0 on success
262 int xtables_set_params(struct xtables_globals *xtp)
265 fprintf(stderr, "%s: Illegal global params\n",__func__);
271 if (!xt_params->exit_err)
272 xt_params->exit_err = basic_exit_err;
277 int xtables_init_all(struct xtables_globals *xtp, uint8_t nfproto)
280 xtables_set_nfproto(nfproto);
281 return xtables_set_params(xtp);
285 * xtables_*alloc - wrappers that exit on failure
287 void *xtables_calloc(size_t count, size_t size)
291 if ((p = calloc(count, size)) == NULL) {
292 perror("ip[6]tables: calloc failed");
299 void *xtables_malloc(size_t size)
303 if ((p = malloc(size)) == NULL) {
304 perror("ip[6]tables: malloc failed");
311 void *xtables_realloc(void *ptr, size_t size)
315 if ((p = realloc(ptr, size)) == NULL) {
316 perror("ip[6]tables: realloc failed");
323 static char *get_modprobe(void)
329 procfile = open(PROC_SYS_MODPROBE, O_RDONLY);
332 if (fcntl(procfile, F_SETFD, FD_CLOEXEC) == -1) {
333 fprintf(stderr, "Could not set close on exec: %s\n",
338 ret = malloc(PATH_MAX);
340 count = read(procfile, ret, PATH_MAX);
341 if (count > 0 && count < PATH_MAX)
343 if (ret[count - 1] == '\n')
344 ret[count - 1] = '\0';
356 int xtables_insmod(const char *modname, const char *modprobe, bool quiet)
362 /* If they don't explicitly set it, read out of kernel */
364 buf = get_modprobe();
370 argv[0] = (char *)modprobe;
371 argv[1] = (char *)modname;
372 argv[2] = quiet ? "-q" : NULL;
376 * Need to flush the buffer, or the child may output it again
377 * when switching the program thru execv.
383 execv(argv[0], argv);
385 /* not usually reached */
391 default: /* parent */
396 if (WIFEXITED(status) && WEXITSTATUS(status) == 0)
401 /* return true if a given file exists within procfs */
402 static bool proc_file_exists(const char *filename)
407 if (lstat(filename, &s))
409 if (!S_ISREG(s.st_mode))
411 if (statfs(filename, &f))
413 if (f.f_type != PROC_SUPER_MAGIC)
418 int xtables_load_ko(const char *modprobe, bool quiet)
420 static bool loaded = false;
426 if (proc_file_exists(afinfo->proc_exists)) {
431 ret = xtables_insmod(afinfo->kmod, modprobe, quiet);
439 * xtables_strtou{i,l} - string to number conversion
441 * @end: like strtoul's "end" pointer
442 * @value: pointer for result
443 * @min: minimum accepted value
444 * @max: maximum accepted value
446 * If @end is NULL, we assume the caller wants a "strict strtoul", and hence
448 * In either case, the value obtained is compared for min-max compliance.
449 * Base is always 0, i.e. autodetect depending on @s.
451 * Returns true/false whether number was accepted. On failure, *value has
452 * undefined contents.
454 bool xtables_strtoul(const char *s, char **end, uintmax_t *value,
455 uintmax_t min, uintmax_t max)
462 /* Since strtoul allows leading minus, we have to check for ourself. */
463 for (p = s; isspace(*p); ++p)
467 v = strtoumax(s, &my_end, 0);
473 if (errno != ERANGE && min <= v && (max == 0 || v <= max)) {
477 return *my_end == '\0';
484 bool xtables_strtoui(const char *s, char **end, unsigned int *value,
485 unsigned int min, unsigned int max)
490 ret = xtables_strtoul(s, end, &v, min, max);
496 int xtables_service_to_port(const char *name, const char *proto)
498 struct servent *service;
500 if ((service = getservbyname(name, proto)) != NULL)
501 return ntohs((unsigned short) service->s_port);
506 uint16_t xtables_parse_port(const char *port, const char *proto)
508 unsigned int portnum;
510 if (xtables_strtoui(port, NULL, &portnum, 0, UINT16_MAX) ||
511 (portnum = xtables_service_to_port(port, proto)) != (unsigned)-1)
514 xt_params->exit_err(PARAMETER_PROBLEM,
515 "invalid port/service `%s' specified", port);
518 void xtables_parse_interface(const char *arg, char *vianame,
521 unsigned int vialen = strlen(arg);
524 memset(mask, 0, IFNAMSIZ);
525 memset(vianame, 0, IFNAMSIZ);
527 if (vialen + 1 > IFNAMSIZ)
528 xt_params->exit_err(PARAMETER_PROBLEM,
529 "interface name `%s' must be shorter than IFNAMSIZ"
530 " (%i)", arg, IFNAMSIZ-1);
532 strcpy(vianame, arg);
535 else if (vianame[vialen - 1] == '+') {
536 memset(mask, 0xFF, vialen - 1);
537 /* Don't remove `+' here! -HW */
539 /* Include nul-terminator in match */
540 memset(mask, 0xFF, vialen + 1);
541 for (i = 0; vianame[i]; i++) {
542 if (vianame[i] == '/' ||
545 "Warning: weird character in interface"
546 " `%s' ('/' and ' ' are not allowed by the kernel).\n",
554 #ifndef NO_SHARED_LIBS
555 static void *load_extension(const char *search_path, const char *af_prefix,
556 const char *name, bool is_target)
558 const char *all_prefixes[] = {af_prefix, "libxt_", NULL};
560 const char *dir = search_path, *next;
566 next = strchr(dir, ':');
568 next = dir + strlen(dir);
570 for (prefix = all_prefixes; *prefix != NULL; ++prefix) {
571 snprintf(path, sizeof(path), "%.*s/%s%s.so",
572 (unsigned int)(next - dir), dir,
575 if (stat(path, &sb) != 0) {
578 fprintf(stderr, "%s: %s\n", path,
582 if (dlopen(path, RTLD_NOW) == NULL) {
583 fprintf(stderr, "%s: %s\n", path, dlerror());
588 ptr = xtables_find_target(name, XTF_DONT_LOAD);
590 ptr = xtables_find_match(name,
591 XTF_DONT_LOAD, NULL);
600 } while (*next != '\0');
606 static bool extension_cmp(const char *name1, const char *name2, uint32_t family)
608 if (strcmp(name1, name2) == 0 &&
609 (family == afinfo->family ||
610 family == NFPROTO_UNSPEC))
616 struct xtables_match *
617 xtables_find_match(const char *name, enum xtables_tryload tryload,
618 struct xtables_rule_match **matches)
620 struct xtables_match **dptr;
621 struct xtables_match *ptr;
622 const char *icmp6 = "icmp6";
624 if (strlen(name) >= XT_EXTENSION_MAXNAMELEN)
625 xtables_error(PARAMETER_PROBLEM,
626 "Invalid match name \"%s\" (%u chars max)",
627 name, XT_EXTENSION_MAXNAMELEN - 1);
629 /* This is ugly as hell. Nonetheless, there is no way of changing
630 * this without hurting backwards compatibility */
631 if ( (strcmp(name,"icmpv6") == 0) ||
632 (strcmp(name,"ipv6-icmp") == 0) ||
633 (strcmp(name,"icmp6") == 0) )
636 /* Trigger delayed initialization */
637 for (dptr = &xtables_pending_matches; *dptr; ) {
638 if (extension_cmp(name, (*dptr)->name, (*dptr)->family)) {
640 *dptr = (*dptr)->next;
642 xtables_fully_register_pending_match(ptr);
644 dptr = &((*dptr)->next);
648 for (ptr = xtables_matches; ptr; ptr = ptr->next) {
649 if (extension_cmp(name, ptr->name, ptr->family)) {
650 struct xtables_match *clone;
652 /* First match of this type: */
656 /* Second and subsequent clones */
657 clone = xtables_malloc(sizeof(struct xtables_match));
658 memcpy(clone, ptr, sizeof(struct xtables_match));
661 /* This is a clone: */
669 #ifndef NO_SHARED_LIBS
670 if (!ptr && tryload != XTF_DONT_LOAD && tryload != XTF_DURING_LOAD) {
671 ptr = load_extension(xtables_libdir, afinfo->libprefix,
674 if (ptr == NULL && tryload == XTF_LOAD_MUST_SUCCEED)
675 xt_params->exit_err(PARAMETER_PROBLEM,
676 "Couldn't load match `%s':%s\n",
677 name, strerror(errno));
680 if (ptr && !ptr->loaded) {
681 if (tryload != XTF_DONT_LOAD)
686 if(!ptr && (tryload == XTF_LOAD_MUST_SUCCEED)) {
687 xt_params->exit_err(PARAMETER_PROBLEM,
688 "Couldn't find match `%s'\n", name);
692 if (ptr && matches) {
693 struct xtables_rule_match **i;
694 struct xtables_rule_match *newentry;
696 newentry = xtables_malloc(sizeof(struct xtables_rule_match));
698 for (i = matches; *i; i = &(*i)->next) {
699 if (extension_cmp(name, (*i)->match->name,
700 (*i)->match->family))
701 (*i)->completed = true;
703 newentry->match = ptr;
704 newentry->completed = false;
705 newentry->next = NULL;
712 struct xtables_target *
713 xtables_find_target(const char *name, enum xtables_tryload tryload)
715 struct xtables_target **dptr;
716 struct xtables_target *ptr;
718 /* Standard target? */
719 if (strcmp(name, "") == 0
720 || strcmp(name, XTC_LABEL_ACCEPT) == 0
721 || strcmp(name, XTC_LABEL_DROP) == 0
722 || strcmp(name, XTC_LABEL_QUEUE) == 0
723 || strcmp(name, XTC_LABEL_RETURN) == 0)
726 /* Trigger delayed initialization */
727 for (dptr = &xtables_pending_targets; *dptr; ) {
728 if (extension_cmp(name, (*dptr)->name, (*dptr)->family)) {
730 *dptr = (*dptr)->next;
732 xtables_fully_register_pending_target(ptr);
734 dptr = &((*dptr)->next);
738 for (ptr = xtables_targets; ptr; ptr = ptr->next) {
739 if (extension_cmp(name, ptr->name, ptr->family))
743 #ifndef NO_SHARED_LIBS
744 if (!ptr && tryload != XTF_DONT_LOAD && tryload != XTF_DURING_LOAD) {
745 ptr = load_extension(xtables_libdir, afinfo->libprefix,
748 if (ptr == NULL && tryload == XTF_LOAD_MUST_SUCCEED)
749 xt_params->exit_err(PARAMETER_PROBLEM,
750 "Couldn't load target `%s':%s\n",
751 name, strerror(errno));
754 if (ptr && !ptr->loaded) {
755 if (tryload != XTF_DONT_LOAD)
760 if (ptr == NULL && tryload == XTF_LOAD_MUST_SUCCEED) {
761 xt_params->exit_err(PARAMETER_PROBLEM,
762 "Couldn't find target `%s'\n", name);
772 int xtables_compatible_revision(const char *name, uint8_t revision, int opt)
774 struct xt_get_revision rev;
775 socklen_t s = sizeof(rev);
778 sockfd = socket(afinfo->family, SOCK_RAW, IPPROTO_RAW);
780 if (errno == EPERM) {
781 /* revision 0 is always supported. */
783 fprintf(stderr, "%s: Could not determine whether "
784 "revision %u is supported, "
789 fprintf(stderr, "Could not open socket to kernel: %s\n",
794 if (fcntl(sockfd, F_SETFD, FD_CLOEXEC) == -1) {
795 fprintf(stderr, "Could not set close on exec: %s\n",
800 xtables_load_ko(xtables_modprobe_program, true);
802 strncpy(rev.name, name, XT_EXTENSION_MAXNAMELEN - 1);
803 rev.name[XT_EXTENSION_MAXNAMELEN - 1] = '\0';
804 rev.revision = revision;
806 max_rev = getsockopt(sockfd, afinfo->ipproto, opt, &rev, &s);
808 /* Definitely don't support this? */
809 if (errno == ENOENT || errno == EPROTONOSUPPORT) {
812 } else if (errno == ENOPROTOOPT) {
814 /* Assume only revision 0 support (old kernel) */
815 return (revision == 0);
817 fprintf(stderr, "getsockopt failed strangely: %s\n",
827 static int compatible_match_revision(const char *name, uint8_t revision)
829 return xt_params->compat_rev(name, revision, afinfo->so_rev_match);
832 static int compatible_target_revision(const char *name, uint8_t revision)
834 return xt_params->compat_rev(name, revision, afinfo->so_rev_target);
837 static void xtables_check_options(const char *name, const struct option *opt)
839 for (; opt->name != NULL; ++opt)
840 if (opt->val < 0 || opt->val >= XT_OPTION_OFFSET_SCALE) {
841 fprintf(stderr, "%s: Extension %s uses invalid "
842 "option value %d\n",xt_params->program_name,
848 void xtables_register_match(struct xtables_match *me)
850 if (me->version == NULL) {
851 fprintf(stderr, "%s: match %s<%u> is missing a version\n",
852 xt_params->program_name, me->name, me->revision);
855 if (strcmp(me->version, XTABLES_VERSION) != 0) {
856 fprintf(stderr, "%s: match \"%s\" has version \"%s\", "
857 "but \"%s\" is required.\n",
858 xt_params->program_name, me->name,
859 me->version, XTABLES_VERSION);
863 if (strlen(me->name) >= XT_EXTENSION_MAXNAMELEN) {
864 fprintf(stderr, "%s: match `%s' has invalid name\n",
865 xt_params->program_name, me->name);
869 if (me->family >= NPROTO) {
871 "%s: BUG: match %s has invalid protocol family\n",
872 xt_params->program_name, me->name);
876 if (me->x6_options != NULL)
877 xtables_option_metavalidate(me->name, me->x6_options);
878 if (me->extra_opts != NULL)
879 xtables_check_options(me->name, me->extra_opts);
881 /* ignore not interested match */
882 if (me->family != afinfo->family && me->family != AF_UNSPEC)
885 /* place on linked list of matches pending full registration */
886 me->next = xtables_pending_matches;
887 xtables_pending_matches = me;
891 * Compare two actions for their preference
895 * Like strcmp, returns a negative number if @a is less preferred than @b,
896 * positive number if @a is more preferred than @b, or zero if equally
900 xtables_mt_prefer(bool a_alias, unsigned int a_rev, unsigned int a_fam,
901 bool b_alias, unsigned int b_rev, unsigned int b_fam)
904 * Alias ranks higher than no alias.
905 * (We want the new action to be used whenever possible.)
907 if (!a_alias && b_alias)
909 if (a_alias && !b_alias)
912 /* Higher revision ranks higher. */
918 /* NFPROTO_<specific> ranks higher than NFPROTO_UNSPEC. */
919 if (a_fam == NFPROTO_UNSPEC && b_fam != NFPROTO_UNSPEC)
921 if (a_fam != NFPROTO_UNSPEC && b_fam == NFPROTO_UNSPEC)
924 /* Must be the same thing. */
928 static int xtables_match_prefer(const struct xtables_match *a,
929 const struct xtables_match *b)
931 return xtables_mt_prefer(a->real_name != NULL,
932 a->revision, a->family,
933 b->real_name != NULL,
934 b->revision, b->family);
937 static int xtables_target_prefer(const struct xtables_target *a,
938 const struct xtables_target *b)
941 * Note that if x->real_name==NULL, it will be set to x->name in
942 * xtables_register_*; the direct pointer comparison here is therefore
943 * legitimate to detect an alias.
945 return xtables_mt_prefer(a->real_name != NULL,
946 a->revision, a->family,
947 b->real_name != NULL,
948 b->revision, b->family);
951 static void xtables_fully_register_pending_match(struct xtables_match *me)
953 struct xtables_match **i, *old;
957 old = xtables_find_match(me->name, XTF_DURING_LOAD, NULL);
959 compare = xtables_match_prefer(old, me);
962 "%s: match `%s' already registered.\n",
963 xt_params->program_name, me->name);
967 /* Now we have two (or more) options, check compatibility. */
968 rn = (old->real_name != NULL) ? old->real_name : old->name;
970 compatible_match_revision(rn, old->revision))
973 /* See if new match can be used. */
974 rn = (me->real_name != NULL) ? me->real_name : me->name;
975 if (!compatible_match_revision(rn, me->revision))
978 /* Delete old one. */
979 for (i = &xtables_matches; *i!=old; i = &(*i)->next);
983 if (me->size != XT_ALIGN(me->size)) {
984 fprintf(stderr, "%s: match `%s' has invalid size %u.\n",
985 xt_params->program_name, me->name,
986 (unsigned int)me->size);
990 /* Append to list. */
991 for (i = &xtables_matches; *i; i = &(*i)->next);
999 void xtables_register_matches(struct xtables_match *match, unsigned int n)
1002 xtables_register_match(&match[--n]);
1006 void xtables_register_target(struct xtables_target *me)
1008 if (me->version == NULL) {
1009 fprintf(stderr, "%s: target %s<%u> is missing a version\n",
1010 xt_params->program_name, me->name, me->revision);
1013 if (strcmp(me->version, XTABLES_VERSION) != 0) {
1014 fprintf(stderr, "%s: target \"%s\" has version \"%s\", "
1015 "but \"%s\" is required.\n",
1016 xt_params->program_name, me->name,
1017 me->version, XTABLES_VERSION);
1021 if (strlen(me->name) >= XT_EXTENSION_MAXNAMELEN) {
1022 fprintf(stderr, "%s: target `%s' has invalid name\n",
1023 xt_params->program_name, me->name);
1027 if (me->family >= NPROTO) {
1029 "%s: BUG: target %s has invalid protocol family\n",
1030 xt_params->program_name, me->name);
1034 if (me->x6_options != NULL)
1035 xtables_option_metavalidate(me->name, me->x6_options);
1036 if (me->extra_opts != NULL)
1037 xtables_check_options(me->name, me->extra_opts);
1039 /* ignore not interested target */
1040 if (me->family != afinfo->family && me->family != AF_UNSPEC)
1043 /* place on linked list of targets pending full registration */
1044 me->next = xtables_pending_targets;
1045 xtables_pending_targets = me;
1048 static void xtables_fully_register_pending_target(struct xtables_target *me)
1050 struct xtables_target *old;
1054 old = xtables_find_target(me->name, XTF_DURING_LOAD);
1056 struct xtables_target **i;
1058 compare = xtables_target_prefer(old, me);
1061 "%s: target `%s' already registered.\n",
1062 xt_params->program_name, me->name);
1066 /* Now we have two (or more) options, check compatibility. */
1067 rn = (old->real_name != NULL) ? old->real_name : old->name;
1069 compatible_target_revision(rn, old->revision))
1072 /* See if new target can be used. */
1073 rn = (me->real_name != NULL) ? me->real_name : me->name;
1074 if (!compatible_target_revision(rn, me->revision))
1077 /* Delete old one. */
1078 for (i = &xtables_targets; *i!=old; i = &(*i)->next);
1082 if (me->size != XT_ALIGN(me->size)) {
1083 fprintf(stderr, "%s: target `%s' has invalid size %u.\n",
1084 xt_params->program_name, me->name,
1085 (unsigned int)me->size);
1089 /* Prepend to list. */
1090 me->next = xtables_targets;
1091 xtables_targets = me;
1096 void xtables_register_targets(struct xtables_target *target, unsigned int n)
1099 xtables_register_target(&target[--n]);
1103 /* receives a list of xtables_rule_match, release them */
1104 void xtables_rule_matches_free(struct xtables_rule_match **matches)
1106 struct xtables_rule_match *matchp, *tmp;
1108 for (matchp = *matches; matchp;) {
1110 if (matchp->match->m) {
1111 free(matchp->match->m);
1112 matchp->match->m = NULL;
1114 if (matchp->match == matchp->match->next) {
1115 free(matchp->match);
1116 matchp->match = NULL;
1126 * xtables_param_act - act on condition
1127 * @status: a constant from enum xtables_exittype
1129 * %XTF_ONLY_ONCE: print error message that option may only be used once.
1130 * @p1: module name (e.g. "mark")
1131 * @p2(...): option in conflict (e.g. "--mark")
1132 * @p3(...): condition to match on (see extensions/ for examples)
1134 * %XTF_NO_INVERT: option does not support inversion
1136 * @p2: option in conflict
1137 * @p3: condition to match on
1139 * %XTF_BAD_VALUE: bad value for option
1141 * @p2: option with which the problem occurred (e.g. "--mark")
1142 * @p3: string the user passed in (e.g. "99999999999999")
1144 * %XTF_ONE_ACTION: two mutually exclusive actions have been specified
1147 * Displays an error message and exits the program.
1149 void xtables_param_act(unsigned int status, const char *p1, ...)
1151 const char *p2, *p3;
1159 p2 = va_arg(args, const char *);
1160 b = va_arg(args, unsigned int);
1165 xt_params->exit_err(PARAMETER_PROBLEM,
1166 "%s: \"%s\" option may only be specified once",
1170 p2 = va_arg(args, const char *);
1171 b = va_arg(args, unsigned int);
1176 xt_params->exit_err(PARAMETER_PROBLEM,
1177 "%s: \"%s\" option cannot be inverted", p1, p2);
1180 p2 = va_arg(args, const char *);
1181 p3 = va_arg(args, const char *);
1182 xt_params->exit_err(PARAMETER_PROBLEM,
1183 "%s: Bad value for \"%s\" option: \"%s\"",
1186 case XTF_ONE_ACTION:
1187 b = va_arg(args, unsigned int);
1192 xt_params->exit_err(PARAMETER_PROBLEM,
1193 "%s: At most one action is possible", p1);
1196 xt_params->exit_err(status, p1, args);
1203 const char *xtables_ipaddr_to_numeric(const struct in_addr *addrp)
1205 static char buf[20];
1206 const unsigned char *bytep = (const void *)&addrp->s_addr;
1208 sprintf(buf, "%u.%u.%u.%u", bytep[0], bytep[1], bytep[2], bytep[3]);
1212 static const char *ipaddr_to_host(const struct in_addr *addr)
1214 static char hostname[NI_MAXHOST];
1215 struct sockaddr_in saddr = {
1216 .sin_family = AF_INET,
1222 err = getnameinfo((const void *)&saddr, sizeof(struct sockaddr_in),
1223 hostname, sizeof(hostname) - 1, NULL, 0, 0);
1230 static const char *ipaddr_to_network(const struct in_addr *addr)
1234 if ((net = getnetbyaddr(ntohl(addr->s_addr), AF_INET)) != NULL)
1240 const char *xtables_ipaddr_to_anyname(const struct in_addr *addr)
1244 if ((name = ipaddr_to_host(addr)) != NULL ||
1245 (name = ipaddr_to_network(addr)) != NULL)
1248 return xtables_ipaddr_to_numeric(addr);
1251 int xtables_ipmask_to_cidr(const struct in_addr *mask)
1253 uint32_t maskaddr, bits;
1256 maskaddr = ntohl(mask->s_addr);
1257 /* shortcut for /32 networks */
1258 if (maskaddr == 0xFFFFFFFFL)
1263 while (--i >= 0 && maskaddr != bits)
1268 /* this mask cannot be converted to CIDR notation */
1272 const char *xtables_ipmask_to_numeric(const struct in_addr *mask)
1274 static char buf[20];
1277 cidr = xtables_ipmask_to_cidr(mask);
1278 if (cidr == (unsigned int)-1) {
1279 /* mask was not a decent combination of 1's and 0's */
1280 sprintf(buf, "/%s", xtables_ipaddr_to_numeric(mask));
1282 } else if (cidr == 32) {
1283 /* we don't want to see "/32" */
1287 sprintf(buf, "/%d", cidr);
1291 static struct in_addr *__numeric_to_ipaddr(const char *dotted, bool is_mask)
1293 static struct in_addr addr;
1294 unsigned char *addrp;
1295 unsigned int onebyte;
1296 char buf[20], *p, *q;
1299 /* copy dotted string, because we need to modify it */
1300 strncpy(buf, dotted, sizeof(buf) - 1);
1301 buf[sizeof(buf) - 1] = '\0';
1302 addrp = (void *)&addr.s_addr;
1305 for (i = 0; i < 3; ++i) {
1306 if ((q = strchr(p, '.')) == NULL) {
1310 /* autocomplete, this is a network address */
1311 if (!xtables_strtoui(p, NULL, &onebyte, 0, UINT8_MAX))
1322 if (!xtables_strtoui(p, NULL, &onebyte, 0, UINT8_MAX))
1329 /* we have checked 3 bytes, now we check the last one */
1330 if (!xtables_strtoui(p, NULL, &onebyte, 0, UINT8_MAX))
1337 struct in_addr *xtables_numeric_to_ipaddr(const char *dotted)
1339 return __numeric_to_ipaddr(dotted, false);
1342 struct in_addr *xtables_numeric_to_ipmask(const char *dotted)
1344 return __numeric_to_ipaddr(dotted, true);
1347 static struct in_addr *network_to_ipaddr(const char *name)
1349 static struct in_addr addr;
1352 if ((net = getnetbyname(name)) != NULL) {
1353 if (net->n_addrtype != AF_INET)
1355 addr.s_addr = htonl(net->n_net);
1362 static struct in_addr *host_to_ipaddr(const char *name, unsigned int *naddr)
1364 struct in_addr *addr;
1365 struct addrinfo hints;
1366 struct addrinfo *res, *p;
1370 memset(&hints, 0, sizeof(hints));
1371 hints.ai_flags = AI_CANONNAME;
1372 hints.ai_family = AF_INET;
1373 hints.ai_socktype = SOCK_RAW;
1376 if ((err = getaddrinfo(name, NULL, &hints, &res)) != 0) {
1379 for (p = res; p != NULL; p = p->ai_next)
1381 addr = xtables_calloc(*naddr, sizeof(struct in_addr));
1382 for (i = 0, p = res; p != NULL; p = p->ai_next)
1384 &((const struct sockaddr_in *)p->ai_addr)->sin_addr,
1385 sizeof(struct in_addr));
1393 static struct in_addr *
1394 ipparse_hostnetwork(const char *name, unsigned int *naddrs)
1396 struct in_addr *addrptmp, *addrp;
1398 if ((addrptmp = xtables_numeric_to_ipaddr(name)) != NULL ||
1399 (addrptmp = network_to_ipaddr(name)) != NULL) {
1400 addrp = xtables_malloc(sizeof(struct in_addr));
1401 memcpy(addrp, addrptmp, sizeof(*addrp));
1405 if ((addrptmp = host_to_ipaddr(name, naddrs)) != NULL)
1408 xt_params->exit_err(PARAMETER_PROBLEM, "host/network `%s' not found", name);
1411 static struct in_addr *parse_ipmask(const char *mask)
1413 static struct in_addr maskaddr;
1414 struct in_addr *addrp;
1418 /* no mask at all defaults to 32 bits */
1419 maskaddr.s_addr = 0xFFFFFFFF;
1422 if ((addrp = xtables_numeric_to_ipmask(mask)) != NULL)
1423 /* dotted_to_addr already returns a network byte order addr */
1425 if (!xtables_strtoui(mask, NULL, &bits, 0, 32))
1426 xt_params->exit_err(PARAMETER_PROBLEM,
1427 "invalid mask `%s' specified", mask);
1429 maskaddr.s_addr = htonl(0xFFFFFFFF << (32 - bits));
1433 maskaddr.s_addr = 0U;
1437 void xtables_ipparse_multiple(const char *name, struct in_addr **addrpp,
1438 struct in_addr **maskpp, unsigned int *naddrs)
1440 struct in_addr *addrp;
1441 char buf[256], *p, *next;
1442 unsigned int len, i, j, n, count = 1;
1443 const char *loop = name;
1445 while ((loop = strchr(loop, ',')) != NULL) {
1447 ++loop; /* skip ',' */
1450 *addrpp = xtables_malloc(sizeof(struct in_addr) * count);
1451 *maskpp = xtables_malloc(sizeof(struct in_addr) * count);
1455 for (i = 0; i < count; ++i) {
1456 while (isspace(*loop))
1458 next = strchr(loop, ',');
1463 if (len > sizeof(buf) - 1)
1464 xt_params->exit_err(PARAMETER_PROBLEM,
1465 "Hostname too long");
1467 strncpy(buf, loop, len);
1469 if ((p = strrchr(buf, '/')) != NULL) {
1471 addrp = parse_ipmask(p + 1);
1473 addrp = parse_ipmask(NULL);
1475 memcpy(*maskpp + i, addrp, sizeof(*addrp));
1477 /* if a null mask is given, the name is ignored, like in "any/0" */
1478 if ((*maskpp + i)->s_addr == 0)
1480 * A bit pointless to process multiple addresses
1483 strcpy(buf, "0.0.0.0");
1485 addrp = ipparse_hostnetwork(buf, &n);
1488 *addrpp = xtables_realloc(*addrpp,
1489 sizeof(struct in_addr) * count);
1490 *maskpp = xtables_realloc(*maskpp,
1491 sizeof(struct in_addr) * count);
1492 for (j = 0; j < n; ++j)
1493 /* for each new addr */
1494 memcpy(*addrpp + i + j, addrp + j,
1496 for (j = 1; j < n; ++j)
1497 /* for each new mask */
1498 memcpy(*maskpp + i + j, *maskpp + i,
1502 memcpy(*addrpp + i, addrp, sizeof(*addrp));
1504 /* free what ipparse_hostnetwork had allocated: */
1511 for (i = 0; i < count; ++i)
1512 (*addrpp+i)->s_addr &= (*maskpp+i)->s_addr;
1517 * xtables_ipparse_any - transform arbitrary name to in_addr
1519 * Possible inputs (pseudo regex):
1520 * m{^($hostname|$networkname|$ipaddr)(/$mask)?}
1521 * "1.2.3.4/5", "1.2.3.4", "hostname", "networkname"
1523 void xtables_ipparse_any(const char *name, struct in_addr **addrpp,
1524 struct in_addr *maskp, unsigned int *naddrs)
1526 unsigned int i, j, k, n;
1527 struct in_addr *addrp;
1530 strncpy(buf, name, sizeof(buf) - 1);
1531 buf[sizeof(buf) - 1] = '\0';
1532 if ((p = strrchr(buf, '/')) != NULL) {
1534 addrp = parse_ipmask(p + 1);
1536 addrp = parse_ipmask(NULL);
1538 memcpy(maskp, addrp, sizeof(*maskp));
1540 /* if a null mask is given, the name is ignored, like in "any/0" */
1541 if (maskp->s_addr == 0U)
1542 strcpy(buf, "0.0.0.0");
1544 addrp = *addrpp = ipparse_hostnetwork(buf, naddrs);
1546 for (i = 0, j = 0; i < n; ++i) {
1547 addrp[j++].s_addr &= maskp->s_addr;
1548 for (k = 0; k < j - 1; ++k)
1549 if (addrp[k].s_addr == addrp[j-1].s_addr) {
1551 * Nuke the dup by copying an address from the
1552 * tail here, and check the current position
1555 memcpy(&addrp[--j], &addrp[--*naddrs],
1556 sizeof(struct in_addr));
1562 const char *xtables_ip6addr_to_numeric(const struct in6_addr *addrp)
1564 /* 0000:0000:0000:0000:0000:0000:000.000.000.000
1565 * 0000:0000:0000:0000:0000:0000:0000:0000 */
1566 static char buf[50+1];
1567 return inet_ntop(AF_INET6, addrp, buf, sizeof(buf));
1570 static const char *ip6addr_to_host(const struct in6_addr *addr)
1572 static char hostname[NI_MAXHOST];
1573 struct sockaddr_in6 saddr;
1576 memset(&saddr, 0, sizeof(struct sockaddr_in6));
1577 memcpy(&saddr.sin6_addr, addr, sizeof(*addr));
1578 saddr.sin6_family = AF_INET6;
1580 err = getnameinfo((const void *)&saddr, sizeof(struct sockaddr_in6),
1581 hostname, sizeof(hostname) - 1, NULL, 0, 0);
1588 const char *xtables_ip6addr_to_anyname(const struct in6_addr *addr)
1592 if ((name = ip6addr_to_host(addr)) != NULL)
1595 return xtables_ip6addr_to_numeric(addr);
1598 int xtables_ip6mask_to_cidr(const struct in6_addr *k)
1600 unsigned int bits = 0;
1601 uint32_t a, b, c, d;
1603 a = ntohl(k->s6_addr32[0]);
1604 b = ntohl(k->s6_addr32[1]);
1605 c = ntohl(k->s6_addr32[2]);
1606 d = ntohl(k->s6_addr32[3]);
1607 while (a & 0x80000000U) {
1617 if (a != 0 || b != 0 || c != 0 || d != 0)
1622 const char *xtables_ip6mask_to_numeric(const struct in6_addr *addrp)
1624 static char buf[50+2];
1625 int l = xtables_ip6mask_to_cidr(addrp);
1629 strcat(buf, xtables_ip6addr_to_numeric(addrp));
1632 /* we don't want to see "/128" */
1636 sprintf(buf, "/%d", l);
1640 struct in6_addr *xtables_numeric_to_ip6addr(const char *num)
1642 static struct in6_addr ap;
1645 if ((err = inet_pton(AF_INET6, num, &ap)) == 1)
1651 static struct in6_addr *
1652 host_to_ip6addr(const char *name, unsigned int *naddr)
1654 struct in6_addr *addr;
1655 struct addrinfo hints;
1656 struct addrinfo *res, *p;
1660 memset(&hints, 0, sizeof(hints));
1661 hints.ai_flags = AI_CANONNAME;
1662 hints.ai_family = AF_INET6;
1663 hints.ai_socktype = SOCK_RAW;
1666 if ((err = getaddrinfo(name, NULL, &hints, &res)) != 0) {
1669 /* Find length of address chain */
1670 for (p = res; p != NULL; p = p->ai_next)
1672 /* Copy each element of the address chain */
1673 addr = xtables_calloc(*naddr, sizeof(struct in6_addr));
1674 for (i = 0, p = res; p != NULL; p = p->ai_next)
1676 &((const struct sockaddr_in6 *)p->ai_addr)->sin6_addr,
1677 sizeof(struct in6_addr));
1685 static struct in6_addr *network_to_ip6addr(const char *name)
1688 /* TODO: not implemented yet, but the exception breaks the
1689 * name resolvation */
1693 static struct in6_addr *
1694 ip6parse_hostnetwork(const char *name, unsigned int *naddrs)
1696 struct in6_addr *addrp, *addrptmp;
1698 if ((addrptmp = xtables_numeric_to_ip6addr(name)) != NULL ||
1699 (addrptmp = network_to_ip6addr(name)) != NULL) {
1700 addrp = xtables_malloc(sizeof(struct in6_addr));
1701 memcpy(addrp, addrptmp, sizeof(*addrp));
1705 if ((addrp = host_to_ip6addr(name, naddrs)) != NULL)
1708 xt_params->exit_err(PARAMETER_PROBLEM, "host/network `%s' not found", name);
1711 static struct in6_addr *parse_ip6mask(char *mask)
1713 static struct in6_addr maskaddr;
1714 struct in6_addr *addrp;
1718 /* no mask at all defaults to 128 bits */
1719 memset(&maskaddr, 0xff, sizeof maskaddr);
1722 if ((addrp = xtables_numeric_to_ip6addr(mask)) != NULL)
1724 if (!xtables_strtoui(mask, NULL, &bits, 0, 128))
1725 xt_params->exit_err(PARAMETER_PROBLEM,
1726 "invalid mask `%s' specified", mask);
1728 char *p = (void *)&maskaddr;
1729 memset(p, 0xff, bits / 8);
1730 memset(p + ((bits + 7) / 8), 0, (128 - bits) / 8);
1732 p[bits/8] = 0xff << (8 - (bits & 7));
1736 memset(&maskaddr, 0, sizeof(maskaddr));
1741 xtables_ip6parse_multiple(const char *name, struct in6_addr **addrpp,
1742 struct in6_addr **maskpp, unsigned int *naddrs)
1744 static const struct in6_addr zero_addr;
1745 struct in6_addr *addrp;
1746 char buf[256], *p, *next;
1747 unsigned int len, i, j, n, count = 1;
1748 const char *loop = name;
1750 while ((loop = strchr(loop, ',')) != NULL) {
1752 ++loop; /* skip ',' */
1755 *addrpp = xtables_malloc(sizeof(struct in6_addr) * count);
1756 *maskpp = xtables_malloc(sizeof(struct in6_addr) * count);
1760 for (i = 0; i < count /*NB: count can grow*/; ++i) {
1761 while (isspace(*loop))
1763 next = strchr(loop, ',');
1768 if (len > sizeof(buf) - 1)
1769 xt_params->exit_err(PARAMETER_PROBLEM,
1770 "Hostname too long");
1772 strncpy(buf, loop, len);
1774 if ((p = strrchr(buf, '/')) != NULL) {
1776 addrp = parse_ip6mask(p + 1);
1778 addrp = parse_ip6mask(NULL);
1780 memcpy(*maskpp + i, addrp, sizeof(*addrp));
1782 /* if a null mask is given, the name is ignored, like in "any/0" */
1783 if (memcmp(*maskpp + i, &zero_addr, sizeof(zero_addr)) == 0)
1786 addrp = ip6parse_hostnetwork(buf, &n);
1789 *addrpp = xtables_realloc(*addrpp,
1790 sizeof(struct in6_addr) * count);
1791 *maskpp = xtables_realloc(*maskpp,
1792 sizeof(struct in6_addr) * count);
1793 for (j = 0; j < n; ++j)
1794 /* for each new addr */
1795 memcpy(*addrpp + i + j, addrp + j,
1797 for (j = 1; j < n; ++j)
1798 /* for each new mask */
1799 memcpy(*maskpp + i + j, *maskpp + i,
1803 memcpy(*addrpp + i, addrp, sizeof(*addrp));
1805 /* free what ip6parse_hostnetwork had allocated: */
1812 for (i = 0; i < count; ++i)
1813 for (j = 0; j < 4; ++j)
1814 (*addrpp+i)->s6_addr32[j] &= (*maskpp+i)->s6_addr32[j];
1817 void xtables_ip6parse_any(const char *name, struct in6_addr **addrpp,
1818 struct in6_addr *maskp, unsigned int *naddrs)
1820 static const struct in6_addr zero_addr;
1821 struct in6_addr *addrp;
1822 unsigned int i, j, k, n;
1825 strncpy(buf, name, sizeof(buf) - 1);
1826 buf[sizeof(buf)-1] = '\0';
1827 if ((p = strrchr(buf, '/')) != NULL) {
1829 addrp = parse_ip6mask(p + 1);
1831 addrp = parse_ip6mask(NULL);
1833 memcpy(maskp, addrp, sizeof(*maskp));
1835 /* if a null mask is given, the name is ignored, like in "any/0" */
1836 if (memcmp(maskp, &zero_addr, sizeof(zero_addr)) == 0)
1839 addrp = *addrpp = ip6parse_hostnetwork(buf, naddrs);
1841 for (i = 0, j = 0; i < n; ++i) {
1842 for (k = 0; k < 4; ++k)
1843 addrp[j].s6_addr32[k] &= maskp->s6_addr32[k];
1845 for (k = 0; k < j - 1; ++k)
1846 if (IN6_ARE_ADDR_EQUAL(&addrp[k], &addrp[j - 1])) {
1848 * Nuke the dup by copying an address from the
1849 * tail here, and check the current position
1852 memcpy(&addrp[--j], &addrp[--*naddrs],
1853 sizeof(struct in_addr));
1859 void xtables_save_string(const char *value)
1861 static const char no_quote_chars[] = "_-0123456789"
1862 "abcdefghijklmnopqrstuvwxyz"
1863 "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
1864 static const char escape_chars[] = "\"\\'";
1868 length = strspn(value, no_quote_chars);
1869 if (length > 0 && value[length] == 0) {
1870 /* no quoting required */
1872 fputs(value, stdout);
1874 /* there is at least one dangerous character in the
1875 value, which we have to quote. Write double quotes
1876 around the value and escape special characters with
1880 for (p = strpbrk(value, escape_chars); p != NULL;
1881 p = strpbrk(value, escape_chars)) {
1883 fwrite(value, 1, p - value, stdout);
1889 /* print the rest and finish the double quoted
1891 fputs(value, stdout);
1896 const struct xtables_pprot xtables_chain_protos[] = {
1897 {"tcp", IPPROTO_TCP},
1898 {"sctp", IPPROTO_SCTP},
1899 {"udp", IPPROTO_UDP},
1900 {"udplite", IPPROTO_UDPLITE},
1901 {"icmp", IPPROTO_ICMP},
1902 {"icmpv6", IPPROTO_ICMPV6},
1903 {"ipv6-icmp", IPPROTO_ICMPV6},
1904 {"esp", IPPROTO_ESP},
1906 {"ipv6-mh", IPPROTO_MH},
1913 xtables_parse_protocol(const char *s)
1915 const struct protoent *pent;
1916 unsigned int proto, i;
1918 if (xtables_strtoui(s, NULL, &proto, 0, UINT8_MAX))
1921 /* first deal with the special case of 'all' to prevent
1922 * people from being able to redefine 'all' in nsswitch
1923 * and/or provoke expensive [not working] ldap/nis/...
1925 if (strcmp(s, "all") == 0)
1928 pent = getprotobyname(s);
1930 return pent->p_proto;
1932 for (i = 0; i < ARRAY_SIZE(xtables_chain_protos); ++i) {
1933 if (xtables_chain_protos[i].name == NULL)
1935 if (strcmp(s, xtables_chain_protos[i].name) == 0)
1936 return xtables_chain_protos[i].num;
1938 xt_params->exit_err(PARAMETER_PROBLEM,
1939 "unknown protocol \"%s\" specified", s);
1943 void xtables_print_num(uint64_t number, unsigned int format)
1945 if (!(format & FMT_KILOMEGAGIGA)) {
1946 printf(FMT("%8llu ","%llu "), (unsigned long long)number);
1949 if (number <= 99999) {
1950 printf(FMT("%5llu ","%llu "), (unsigned long long)number);
1953 number = (number + 500) / 1000;
1954 if (number <= 9999) {
1955 printf(FMT("%4lluK ","%lluK "), (unsigned long long)number);
1958 number = (number + 500) / 1000;
1959 if (number <= 9999) {
1960 printf(FMT("%4lluM ","%lluM "), (unsigned long long)number);
1963 number = (number + 500) / 1000;
1964 if (number <= 9999) {
1965 printf(FMT("%4lluG ","%lluG "), (unsigned long long)number);
1968 number = (number + 500) / 1000;
1969 printf(FMT("%4lluT ","%lluT "), (unsigned long long)number);
1974 void get_kernel_version(void)
1976 static struct utsname uts;
1977 int x = 0, y = 0, z = 0;
1979 if (uname(&uts) == -1) {
1980 fprintf(stderr, "Unable to retrieve kernel version.\n");
1981 xtables_free_opts(1);
1985 sscanf(uts.release, "%d.%d.%d", &x, &y, &z);
1986 kernel_version = LINUX_VERSION(x, y, z);
1989 #include <linux/netfilter/nf_tables.h>
1998 char comment[NFT_USERDATA_MAXLEN];
2001 struct xt_xlate *xt_xlate_alloc(int size)
2003 struct xt_xlate *xl;
2005 xl = malloc(sizeof(struct xt_xlate));
2007 xtables_error(RESOURCE_PROBLEM, "OOM");
2009 xl->buf.data = malloc(size);
2010 if (xl->buf.data == NULL)
2011 xtables_error(RESOURCE_PROBLEM, "OOM");
2013 xl->buf.size = size;
2016 xl->comment[0] = '\0';
2021 void xt_xlate_free(struct xt_xlate *xl)
2027 void xt_xlate_add(struct xt_xlate *xl, const char *fmt, ...)
2033 len = vsnprintf(xl->buf.data + xl->buf.off, xl->buf.rem, fmt, ap);
2034 if (len < 0 || len >= xl->buf.rem)
2035 xtables_error(RESOURCE_PROBLEM, "OOM");
2042 void xt_xlate_add_comment(struct xt_xlate *xl, const char *comment)
2044 strncpy(xl->comment, comment, NFT_USERDATA_MAXLEN - 1);
2045 xl->comment[NFT_USERDATA_MAXLEN - 1] = '\0';
2048 const char *xt_xlate_get_comment(struct xt_xlate *xl)
2050 return xl->comment[0] ? xl->comment : NULL;
2053 const char *xt_xlate_get(struct xt_xlate *xl)
2055 return xl->buf.data;