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