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