xtables.c revision c436dad7cfdd80ca4a05ceed556c39babc266f55
1fd92a3dde32fd10df30c9eeb97641bc3c15b1e9bBehdad Esfahbod/* 22409d5f8d7dd8b535ce5ea29e933f7db27d33793Behdad Esfahbod * (C) 2000-2006 by the netfilter coreteam <coreteam@netfilter.org>: 3469524692bd0a258b28e63294c984e677a9c2477Behdad Esfahbod * 4fd92a3dde32fd10df30c9eeb97641bc3c15b1e9bBehdad Esfahbod * This program is free software; you can redistribute it and/or modify 5c755cb3e3ac55156d0d2ec05adea7a650b97cc41Behdad Esfahbod * it under the terms of the GNU General Public License as published by 6fd92a3dde32fd10df30c9eeb97641bc3c15b1e9bBehdad Esfahbod * the Free Software Foundation; either version 2 of the License, or 7fd92a3dde32fd10df30c9eeb97641bc3c15b1e9bBehdad Esfahbod * (at your option) any later version. 8fd92a3dde32fd10df30c9eeb97641bc3c15b1e9bBehdad Esfahbod * 9fd92a3dde32fd10df30c9eeb97641bc3c15b1e9bBehdad Esfahbod * This program is distributed in the hope that it will be useful, 10fd92a3dde32fd10df30c9eeb97641bc3c15b1e9bBehdad Esfahbod * but WITHOUT ANY WARRANTY; without even the implied warranty of 11fd92a3dde32fd10df30c9eeb97641bc3c15b1e9bBehdad Esfahbod * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12fd92a3dde32fd10df30c9eeb97641bc3c15b1e9bBehdad Esfahbod * GNU General Public License for more details. 13fd92a3dde32fd10df30c9eeb97641bc3c15b1e9bBehdad Esfahbod * 14fd92a3dde32fd10df30c9eeb97641bc3c15b1e9bBehdad Esfahbod * You should have received a copy of the GNU General Public License 15fd92a3dde32fd10df30c9eeb97641bc3c15b1e9bBehdad Esfahbod * along with this program; if not, write to the Free Software 16fd92a3dde32fd10df30c9eeb97641bc3c15b1e9bBehdad Esfahbod * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 17fd92a3dde32fd10df30c9eeb97641bc3c15b1e9bBehdad Esfahbod */ 18fd92a3dde32fd10df30c9eeb97641bc3c15b1e9bBehdad Esfahbod#include "config.h" 19fd92a3dde32fd10df30c9eeb97641bc3c15b1e9bBehdad Esfahbod#include <ctype.h> 20fd92a3dde32fd10df30c9eeb97641bc3c15b1e9bBehdad Esfahbod#include <errno.h> 21fd92a3dde32fd10df30c9eeb97641bc3c15b1e9bBehdad Esfahbod#include <fcntl.h> 22fd92a3dde32fd10df30c9eeb97641bc3c15b1e9bBehdad Esfahbod#include <inttypes.h> 23fd92a3dde32fd10df30c9eeb97641bc3c15b1e9bBehdad Esfahbod#include <netdb.h> 24fd92a3dde32fd10df30c9eeb97641bc3c15b1e9bBehdad Esfahbod#include <stdarg.h> 25fd92a3dde32fd10df30c9eeb97641bc3c15b1e9bBehdad Esfahbod#include <stdbool.h> 26f860366456d9e59b139a940da6d89c3c4fb9e96eBehdad Esfahbod#include <stdio.h> 27fd92a3dde32fd10df30c9eeb97641bc3c15b1e9bBehdad Esfahbod#include <stdlib.h> 28fd92a3dde32fd10df30c9eeb97641bc3c15b1e9bBehdad Esfahbod#include <string.h> 290f0cd9d361f1bb614aa3fd4616160d027062370eBehdad Esfahbod#include <unistd.h> 300f0cd9d361f1bb614aa3fd4616160d027062370eBehdad Esfahbod#include <sys/socket.h> 31fd92a3dde32fd10df30c9eeb97641bc3c15b1e9bBehdad Esfahbod#include <sys/stat.h> 32c57d454accff66e5f2c58006e8fb40bc020b6182Behdad Esfahbod#include <sys/statfs.h> 332c80296aa5991ad67483889147f5c84fefe54af2Behdad Esfahbod#include <sys/types.h> 34c57d454accff66e5f2c58006e8fb40bc020b6182Behdad Esfahbod#include <sys/utsname.h> 3522da7fd94d6318c52df69d70470a85464ffc533dBehdad Esfahbod#include <sys/wait.h> 361336ecdf8e4e9879b96b26ecfbf5c9ba6c49e2b9Behdad Esfahbod#include <arpa/inet.h> 37fd92a3dde32fd10df30c9eeb97641bc3c15b1e9bBehdad Esfahbod#if defined(HAVE_LINUX_MAGIC_H) 3823c86aa0009324433e78fcd0c47f2c0ff14b1949Behdad Esfahbod# include <linux/magic.h> /* for PROC_SUPER_MAGIC */ 392e96d2c6ee34142375373be07217c9953e7822ccBehdad Esfahbod#elif defined(HAVE_LINUX_PROC_FS_H) 402e96d2c6ee34142375373be07217c9953e7822ccBehdad Esfahbod# include <linux/proc_fs.h> /* Linux 2.4 */ 412e96d2c6ee34142375373be07217c9953e7822ccBehdad Esfahbod#else 422e96d2c6ee34142375373be07217c9953e7822ccBehdad Esfahbod# define PROC_SUPER_MAGIC 0x9fa0 4305ad6b50ac0a1b9a8da10d2ee2238068b7811e7dBehdad Esfahbod#endif 4405ad6b50ac0a1b9a8da10d2ee2238068b7811e7dBehdad Esfahbod 452e96d2c6ee34142375373be07217c9953e7822ccBehdad Esfahbod#include <xtables.h> 462e96d2c6ee34142375373be07217c9953e7822ccBehdad Esfahbod#include <limits.h> /* INT_MAX in ip_tables.h/ip6_tables.h */ 472e96d2c6ee34142375373be07217c9953e7822ccBehdad Esfahbod#include <linux/netfilter_ipv4/ip_tables.h> 4805ad6b50ac0a1b9a8da10d2ee2238068b7811e7dBehdad Esfahbod#include <linux/netfilter_ipv6/ip6_tables.h> 4905ad6b50ac0a1b9a8da10d2ee2238068b7811e7dBehdad Esfahbod#include <libiptc/libxtc.h> 5005ad6b50ac0a1b9a8da10d2ee2238068b7811e7dBehdad Esfahbod 5109675a8115b9d77261c33940401aa919cede8662Behdad Esfahbod#ifndef NO_SHARED_LIBS 5209675a8115b9d77261c33940401aa919cede8662Behdad Esfahbod#include <dlfcn.h> 53832a6f99b34f334b1e82b8e3a7ad137e823d203cBehdad Esfahbod#endif 542e96d2c6ee34142375373be07217c9953e7822ccBehdad Esfahbod#ifndef IPT_SO_GET_REVISION_MATCH /* Old kernel source. */ 5509675a8115b9d77261c33940401aa919cede8662Behdad Esfahbod# define IPT_SO_GET_REVISION_MATCH (IPT_BASE_CTL + 2) 56832a6f99b34f334b1e82b8e3a7ad137e823d203cBehdad Esfahbod# define IPT_SO_GET_REVISION_TARGET (IPT_BASE_CTL + 3) 57832a6f99b34f334b1e82b8e3a7ad137e823d203cBehdad Esfahbod#endif 582e96d2c6ee34142375373be07217c9953e7822ccBehdad Esfahbod#ifndef IP6T_SO_GET_REVISION_MATCH /* Old kernel source. */ 592e96d2c6ee34142375373be07217c9953e7822ccBehdad Esfahbod# define IP6T_SO_GET_REVISION_MATCH 68 602e96d2c6ee34142375373be07217c9953e7822ccBehdad Esfahbod# define IP6T_SO_GET_REVISION_TARGET 69 612e96d2c6ee34142375373be07217c9953e7822ccBehdad Esfahbod#endif 622e96d2c6ee34142375373be07217c9953e7822ccBehdad Esfahbod#include <getopt.h> 632e96d2c6ee34142375373be07217c9953e7822ccBehdad Esfahbod#include "iptables/internal.h" 642e96d2c6ee34142375373be07217c9953e7822ccBehdad Esfahbod#include "xshared.h" 652e96d2c6ee34142375373be07217c9953e7822ccBehdad Esfahbod 662e96d2c6ee34142375373be07217c9953e7822ccBehdad Esfahbod#define NPROTO 255 672e96d2c6ee34142375373be07217c9953e7822ccBehdad Esfahbod 682e96d2c6ee34142375373be07217c9953e7822ccBehdad Esfahbod#ifndef PROC_SYS_MODPROBE 692e96d2c6ee34142375373be07217c9953e7822ccBehdad Esfahbod#define PROC_SYS_MODPROBE "/proc/sys/kernel/modprobe" 702e96d2c6ee34142375373be07217c9953e7822ccBehdad Esfahbod#endif 712e96d2c6ee34142375373be07217c9953e7822ccBehdad Esfahbod 722e96d2c6ee34142375373be07217c9953e7822ccBehdad Esfahbod/* we need this for ip6?tables-restore. ip6?tables-restore.c sets line to the 732e96d2c6ee34142375373be07217c9953e7822ccBehdad Esfahbod * current line of the input file, in order to give a more precise error 742e96d2c6ee34142375373be07217c9953e7822ccBehdad Esfahbod * message. ip6?tables itself doesn't need this, so it is initialized to the 752e96d2c6ee34142375373be07217c9953e7822ccBehdad Esfahbod * magic number of -1 */ 762e96d2c6ee34142375373be07217c9953e7822ccBehdad Esfahbodint line = -1; 772e96d2c6ee34142375373be07217c9953e7822ccBehdad Esfahbod 782e96d2c6ee34142375373be07217c9953e7822ccBehdad Esfahbodvoid basic_exit_err(enum xtables_exittype status, const char *msg, ...) __attribute__((noreturn, format(printf,2,3))); 792e96d2c6ee34142375373be07217c9953e7822ccBehdad Esfahbod 802e96d2c6ee34142375373be07217c9953e7822ccBehdad Esfahbodstruct xtables_globals *xt_params = NULL; 812e96d2c6ee34142375373be07217c9953e7822ccBehdad Esfahbod 822e96d2c6ee34142375373be07217c9953e7822ccBehdad Esfahbodvoid basic_exit_err(enum xtables_exittype status, const char *msg, ...) 832e96d2c6ee34142375373be07217c9953e7822ccBehdad Esfahbod{ 842e96d2c6ee34142375373be07217c9953e7822ccBehdad Esfahbod va_list args; 852e96d2c6ee34142375373be07217c9953e7822ccBehdad Esfahbod 862e96d2c6ee34142375373be07217c9953e7822ccBehdad Esfahbod va_start(args, msg); 872e96d2c6ee34142375373be07217c9953e7822ccBehdad Esfahbod fprintf(stderr, "%s v%s: ", xt_params->program_name, xt_params->program_version); 882e96d2c6ee34142375373be07217c9953e7822ccBehdad Esfahbod vfprintf(stderr, msg, args); 892e96d2c6ee34142375373be07217c9953e7822ccBehdad Esfahbod va_end(args); 902e96d2c6ee34142375373be07217c9953e7822ccBehdad Esfahbod fprintf(stderr, "\n"); 912e96d2c6ee34142375373be07217c9953e7822ccBehdad Esfahbod exit(status); 922e96d2c6ee34142375373be07217c9953e7822ccBehdad Esfahbod} 932e96d2c6ee34142375373be07217c9953e7822ccBehdad Esfahbod 942e96d2c6ee34142375373be07217c9953e7822ccBehdad Esfahbodvoid xtables_free_opts(int unused) 952e96d2c6ee34142375373be07217c9953e7822ccBehdad Esfahbod{ 962e96d2c6ee34142375373be07217c9953e7822ccBehdad Esfahbod if (xt_params->opts != xt_params->orig_opts) { 972e96d2c6ee34142375373be07217c9953e7822ccBehdad Esfahbod free(xt_params->opts); 982e96d2c6ee34142375373be07217c9953e7822ccBehdad Esfahbod xt_params->opts = NULL; 992e96d2c6ee34142375373be07217c9953e7822ccBehdad Esfahbod } 1002e96d2c6ee34142375373be07217c9953e7822ccBehdad Esfahbod} 1012e96d2c6ee34142375373be07217c9953e7822ccBehdad Esfahbod 1022e96d2c6ee34142375373be07217c9953e7822ccBehdad Esfahbodstruct option *xtables_merge_options(struct option *orig_opts, 1032e96d2c6ee34142375373be07217c9953e7822ccBehdad Esfahbod struct option *oldopts, 1042e96d2c6ee34142375373be07217c9953e7822ccBehdad Esfahbod const struct option *newopts, 1052e96d2c6ee34142375373be07217c9953e7822ccBehdad Esfahbod unsigned int *option_offset) 1062e96d2c6ee34142375373be07217c9953e7822ccBehdad Esfahbod{ 1072e96d2c6ee34142375373be07217c9953e7822ccBehdad Esfahbod unsigned int num_oold = 0, num_old = 0, num_new = 0, i; 1082e96d2c6ee34142375373be07217c9953e7822ccBehdad Esfahbod struct option *merge, *mp; 1092e96d2c6ee34142375373be07217c9953e7822ccBehdad Esfahbod 1102e96d2c6ee34142375373be07217c9953e7822ccBehdad Esfahbod if (newopts == NULL) 1112e96d2c6ee34142375373be07217c9953e7822ccBehdad Esfahbod return oldopts; 1122e96d2c6ee34142375373be07217c9953e7822ccBehdad Esfahbod 1132e96d2c6ee34142375373be07217c9953e7822ccBehdad Esfahbod for (num_oold = 0; orig_opts[num_oold].name; num_oold++) ; 1142e96d2c6ee34142375373be07217c9953e7822ccBehdad Esfahbod if (oldopts != NULL) 1152e96d2c6ee34142375373be07217c9953e7822ccBehdad Esfahbod for (num_old = 0; oldopts[num_old].name; num_old++) ; 1162e96d2c6ee34142375373be07217c9953e7822ccBehdad Esfahbod for (num_new = 0; newopts[num_new].name; num_new++) ; 1172e96d2c6ee34142375373be07217c9953e7822ccBehdad Esfahbod 1182e96d2c6ee34142375373be07217c9953e7822ccBehdad Esfahbod /* 1192e96d2c6ee34142375373be07217c9953e7822ccBehdad Esfahbod * Since @oldopts also has @orig_opts already (and does so at the 1202e96d2c6ee34142375373be07217c9953e7822ccBehdad Esfahbod * start), skip these entries. 1212e96d2c6ee34142375373be07217c9953e7822ccBehdad Esfahbod */ 1222e96d2c6ee34142375373be07217c9953e7822ccBehdad Esfahbod oldopts += num_oold; 1232e96d2c6ee34142375373be07217c9953e7822ccBehdad Esfahbod num_old -= num_oold; 1242e96d2c6ee34142375373be07217c9953e7822ccBehdad Esfahbod 1252e96d2c6ee34142375373be07217c9953e7822ccBehdad Esfahbod merge = malloc(sizeof(*mp) * (num_oold + num_old + num_new + 1)); 1262e96d2c6ee34142375373be07217c9953e7822ccBehdad Esfahbod if (merge == NULL) 1272e96d2c6ee34142375373be07217c9953e7822ccBehdad Esfahbod return NULL; 1282e96d2c6ee34142375373be07217c9953e7822ccBehdad Esfahbod 1292e96d2c6ee34142375373be07217c9953e7822ccBehdad Esfahbod /* Let the base options -[ADI...] have precedence over everything */ 1307e8c38954649c0bf2e6051d84ca08dce090ec169Behdad Esfahbod memcpy(merge, orig_opts, sizeof(*mp) * num_oold); 1312e96d2c6ee34142375373be07217c9953e7822ccBehdad Esfahbod mp = merge + num_oold; 1322e96d2c6ee34142375373be07217c9953e7822ccBehdad Esfahbod 1332e96d2c6ee34142375373be07217c9953e7822ccBehdad Esfahbod /* Second, the new options */ 1342e96d2c6ee34142375373be07217c9953e7822ccBehdad Esfahbod xt_params->option_offset += XT_OPTION_OFFSET_SCALE; 1352e96d2c6ee34142375373be07217c9953e7822ccBehdad Esfahbod *option_offset = xt_params->option_offset; 1362e96d2c6ee34142375373be07217c9953e7822ccBehdad Esfahbod memcpy(mp, newopts, sizeof(*mp) * num_new); 1372e96d2c6ee34142375373be07217c9953e7822ccBehdad Esfahbod 1382e96d2c6ee34142375373be07217c9953e7822ccBehdad Esfahbod for (i = 0; i < num_new; ++i, ++mp) 1392e96d2c6ee34142375373be07217c9953e7822ccBehdad Esfahbod mp->val += *option_offset; 1402e96d2c6ee34142375373be07217c9953e7822ccBehdad Esfahbod 1412e96d2c6ee34142375373be07217c9953e7822ccBehdad Esfahbod /* Third, the old options */ 1422e96d2c6ee34142375373be07217c9953e7822ccBehdad Esfahbod memcpy(mp, oldopts, sizeof(*mp) * num_old); 1432e96d2c6ee34142375373be07217c9953e7822ccBehdad Esfahbod mp += num_old; 1442e96d2c6ee34142375373be07217c9953e7822ccBehdad Esfahbod xtables_free_opts(0); 1452e96d2c6ee34142375373be07217c9953e7822ccBehdad Esfahbod 1462e96d2c6ee34142375373be07217c9953e7822ccBehdad Esfahbod /* Clear trailing entry */ 1472e96d2c6ee34142375373be07217c9953e7822ccBehdad Esfahbod memset(mp, 0, sizeof(*mp)); 1482e96d2c6ee34142375373be07217c9953e7822ccBehdad Esfahbod return merge; 1492e96d2c6ee34142375373be07217c9953e7822ccBehdad Esfahbod} 1502e96d2c6ee34142375373be07217c9953e7822ccBehdad Esfahbod 1512e96d2c6ee34142375373be07217c9953e7822ccBehdad Esfahbodstatic const struct xtables_afinfo afinfo_ipv4 = { 1522e96d2c6ee34142375373be07217c9953e7822ccBehdad Esfahbod .kmod = "ip_tables", 1532e96d2c6ee34142375373be07217c9953e7822ccBehdad Esfahbod .proc_exists = "/proc/net/ip_tables_names", 1542e96d2c6ee34142375373be07217c9953e7822ccBehdad Esfahbod .libprefix = "libipt_", 1552e96d2c6ee34142375373be07217c9953e7822ccBehdad Esfahbod .family = NFPROTO_IPV4, 1562e96d2c6ee34142375373be07217c9953e7822ccBehdad Esfahbod .ipproto = IPPROTO_IP, 1572e96d2c6ee34142375373be07217c9953e7822ccBehdad Esfahbod .so_rev_match = IPT_SO_GET_REVISION_MATCH, 1582e96d2c6ee34142375373be07217c9953e7822ccBehdad Esfahbod .so_rev_target = IPT_SO_GET_REVISION_TARGET, 1592e96d2c6ee34142375373be07217c9953e7822ccBehdad Esfahbod}; 1602e96d2c6ee34142375373be07217c9953e7822ccBehdad Esfahbod 1612e96d2c6ee34142375373be07217c9953e7822ccBehdad Esfahbodstatic const struct xtables_afinfo afinfo_ipv6 = { 1622e96d2c6ee34142375373be07217c9953e7822ccBehdad Esfahbod .kmod = "ip6_tables", 1632e96d2c6ee34142375373be07217c9953e7822ccBehdad Esfahbod .proc_exists = "/proc/net/ip6_tables_names", 1642e96d2c6ee34142375373be07217c9953e7822ccBehdad Esfahbod .libprefix = "libip6t_", 1652e96d2c6ee34142375373be07217c9953e7822ccBehdad Esfahbod .family = NFPROTO_IPV6, 1662e96d2c6ee34142375373be07217c9953e7822ccBehdad Esfahbod .ipproto = IPPROTO_IPV6, 1672e96d2c6ee34142375373be07217c9953e7822ccBehdad Esfahbod .so_rev_match = IP6T_SO_GET_REVISION_MATCH, 1682e96d2c6ee34142375373be07217c9953e7822ccBehdad Esfahbod .so_rev_target = IP6T_SO_GET_REVISION_TARGET, 169101303dbf7cf15d044bf2518f14b3aec65970feaBehdad Esfahbod}; 170101303dbf7cf15d044bf2518f14b3aec65970feaBehdad Esfahbod 171101303dbf7cf15d044bf2518f14b3aec65970feaBehdad Esfahbodconst struct xtables_afinfo *afinfo; 172101303dbf7cf15d044bf2518f14b3aec65970feaBehdad Esfahbod 173101303dbf7cf15d044bf2518f14b3aec65970feaBehdad Esfahbod/* Search path for Xtables .so files */ 174101303dbf7cf15d044bf2518f14b3aec65970feaBehdad Esfahbodstatic const char *xtables_libdir; 175101303dbf7cf15d044bf2518f14b3aec65970feaBehdad Esfahbod 176101303dbf7cf15d044bf2518f14b3aec65970feaBehdad Esfahbod/* the path to command to load kernel module */ 177101303dbf7cf15d044bf2518f14b3aec65970feaBehdad Esfahbodconst char *xtables_modprobe_program; 1782e96d2c6ee34142375373be07217c9953e7822ccBehdad Esfahbod 1792e96d2c6ee34142375373be07217c9953e7822ccBehdad Esfahbod/* Keep track of matches/targets pending full registration: linked lists. */ 1801a31f9f820c4538015ddaf4ca2b790649c5997edBehdad Esfahbodstruct xtables_match *xtables_pending_matches; 18111fb16cb849285a178d9e80991b1d60a960326eeBehdad Esfahbodstruct xtables_target *xtables_pending_targets; 18211fb16cb849285a178d9e80991b1d60a960326eeBehdad Esfahbod 18311fb16cb849285a178d9e80991b1d60a960326eeBehdad Esfahbod/* Keep track of fully registered external matches/targets: linked lists. */ 18411fb16cb849285a178d9e80991b1d60a960326eeBehdad Esfahbodstruct xtables_match *xtables_matches; 1851a31f9f820c4538015ddaf4ca2b790649c5997edBehdad Esfahbodstruct xtables_target *xtables_targets; 1861a31f9f820c4538015ddaf4ca2b790649c5997edBehdad Esfahbod 1876faff8e4132197ba06f0e685b82efe35b546cf64Behdad Esfahbod/* Fully register a match/target which was previously partially registered. */ 188607feb7cff0e50f8738d2e49ca463fc9d7d494deBehdad Esfahbodstatic void xtables_fully_register_pending_match(struct xtables_match *me); 189607feb7cff0e50f8738d2e49ca463fc9d7d494deBehdad Esfahbodstatic void xtables_fully_register_pending_target(struct xtables_target *me); 1900f3fe37fccfb540437adf13dd580f2c5164a0b1fBehdad Esfahbod 191607feb7cff0e50f8738d2e49ca463fc9d7d494deBehdad Esfahbodvoid xtables_init(void) 1921a31f9f820c4538015ddaf4ca2b790649c5997edBehdad Esfahbod{ 1937627100f428ac0ec8509d961d368d2d25d8f0b6eBehdad Esfahbod xtables_libdir = getenv("XTABLES_LIBDIR"); 1947627100f428ac0ec8509d961d368d2d25d8f0b6eBehdad Esfahbod if (xtables_libdir != NULL) 195607feb7cff0e50f8738d2e49ca463fc9d7d494deBehdad Esfahbod return; 196607feb7cff0e50f8738d2e49ca463fc9d7d494deBehdad Esfahbod xtables_libdir = getenv("IPTABLES_LIB_DIR"); 197607feb7cff0e50f8738d2e49ca463fc9d7d494deBehdad Esfahbod if (xtables_libdir != NULL) { 1986faff8e4132197ba06f0e685b82efe35b546cf64Behdad Esfahbod fprintf(stderr, "IPTABLES_LIB_DIR is deprecated, " 1993ddf892b5328b74afb6e7d9da727d8771ca5d288Behdad Esfahbod "use XTABLES_LIBDIR.\n"); 2003ddf892b5328b74afb6e7d9da727d8771ca5d288Behdad Esfahbod return; 2017e08f1258da229dfaf7e1c4b5c41e5bb83906cb0Behdad Esfahbod } 2021a31f9f820c4538015ddaf4ca2b790649c5997edBehdad Esfahbod /* 2037e08f1258da229dfaf7e1c4b5c41e5bb83906cb0Behdad Esfahbod * Well yes, IP6TABLES_LIB_DIR is of lower priority over 2047e08f1258da229dfaf7e1c4b5c41e5bb83906cb0Behdad Esfahbod * IPTABLES_LIB_DIR since this moved to libxtables; I think that is ok 2056faff8e4132197ba06f0e685b82efe35b546cf64Behdad Esfahbod * for these env vars are deprecated anyhow, and in light of the 206607feb7cff0e50f8738d2e49ca463fc9d7d494deBehdad Esfahbod * (shared) libxt_*.so files, makes less sense to have 207607feb7cff0e50f8738d2e49ca463fc9d7d494deBehdad Esfahbod * IPTABLES_LIB_DIR != IP6TABLES_LIB_DIR. 2081a31f9f820c4538015ddaf4ca2b790649c5997edBehdad Esfahbod */ 209607feb7cff0e50f8738d2e49ca463fc9d7d494deBehdad Esfahbod xtables_libdir = getenv("IP6TABLES_LIB_DIR"); 210607feb7cff0e50f8738d2e49ca463fc9d7d494deBehdad Esfahbod if (xtables_libdir != NULL) { 2116faff8e4132197ba06f0e685b82efe35b546cf64Behdad Esfahbod fprintf(stderr, "IP6TABLES_LIB_DIR is deprecated, " 2123ddf892b5328b74afb6e7d9da727d8771ca5d288Behdad Esfahbod "use XTABLES_LIBDIR.\n"); 2133ddf892b5328b74afb6e7d9da727d8771ca5d288Behdad Esfahbod return; 214607feb7cff0e50f8738d2e49ca463fc9d7d494deBehdad Esfahbod } 215607feb7cff0e50f8738d2e49ca463fc9d7d494deBehdad Esfahbod xtables_libdir = XTABLES_LIBDIR; 216607feb7cff0e50f8738d2e49ca463fc9d7d494deBehdad Esfahbod} 217607feb7cff0e50f8738d2e49ca463fc9d7d494deBehdad Esfahbod 2186faff8e4132197ba06f0e685b82efe35b546cf64Behdad Esfahbodvoid xtables_set_nfproto(uint8_t nfproto) 219607feb7cff0e50f8738d2e49ca463fc9d7d494deBehdad Esfahbod{ 220607feb7cff0e50f8738d2e49ca463fc9d7d494deBehdad Esfahbod switch (nfproto) { 221607feb7cff0e50f8738d2e49ca463fc9d7d494deBehdad Esfahbod case NFPROTO_IPV4: 222607feb7cff0e50f8738d2e49ca463fc9d7d494deBehdad Esfahbod afinfo = &afinfo_ipv4; 223607feb7cff0e50f8738d2e49ca463fc9d7d494deBehdad Esfahbod break; 2246faff8e4132197ba06f0e685b82efe35b546cf64Behdad Esfahbod case NFPROTO_IPV6: 225607feb7cff0e50f8738d2e49ca463fc9d7d494deBehdad Esfahbod afinfo = &afinfo_ipv6; 226607feb7cff0e50f8738d2e49ca463fc9d7d494deBehdad Esfahbod break; 2271a31f9f820c4538015ddaf4ca2b790649c5997edBehdad Esfahbod default: 228607feb7cff0e50f8738d2e49ca463fc9d7d494deBehdad Esfahbod fprintf(stderr, "libxtables: unhandled NFPROTO in %s\n", 229607feb7cff0e50f8738d2e49ca463fc9d7d494deBehdad Esfahbod __func__); 2306faff8e4132197ba06f0e685b82efe35b546cf64Behdad Esfahbod } 231607feb7cff0e50f8738d2e49ca463fc9d7d494deBehdad Esfahbod} 232607feb7cff0e50f8738d2e49ca463fc9d7d494deBehdad Esfahbod 2331a31f9f820c4538015ddaf4ca2b790649c5997edBehdad Esfahbod/** 234607feb7cff0e50f8738d2e49ca463fc9d7d494deBehdad Esfahbod * xtables_set_params - set the global parameters used by xtables 235607feb7cff0e50f8738d2e49ca463fc9d7d494deBehdad Esfahbod * @xtp: input xtables_globals structure 2366faff8e4132197ba06f0e685b82efe35b546cf64Behdad Esfahbod * 2370b45479198d61d5135dad771e9c68408eb13f930Behdad Esfahbod * The app is expected to pass a valid xtables_globals data-filled 2380b45479198d61d5135dad771e9c68408eb13f930Behdad Esfahbod * with proper values 2391a31f9f820c4538015ddaf4ca2b790649c5997edBehdad Esfahbod * @xtp cannot be NULL 2400b45479198d61d5135dad771e9c68408eb13f930Behdad Esfahbod * 2410b45479198d61d5135dad771e9c68408eb13f930Behdad Esfahbod * Returns -1 on failure to set and 0 on success 2426faff8e4132197ba06f0e685b82efe35b546cf64Behdad Esfahbod */ 243c52ddab72e025d1bee8274c8f3416208b12f68f1Behdad Esfahbodint xtables_set_params(struct xtables_globals *xtp) 244c52ddab72e025d1bee8274c8f3416208b12f68f1Behdad Esfahbod{ 245c52ddab72e025d1bee8274c8f3416208b12f68f1Behdad Esfahbod if (!xtp) { 246c52ddab72e025d1bee8274c8f3416208b12f68f1Behdad Esfahbod fprintf(stderr, "%s: Illegal global params\n",__func__); 247c52ddab72e025d1bee8274c8f3416208b12f68f1Behdad Esfahbod return -1; 2482e96d2c6ee34142375373be07217c9953e7822ccBehdad Esfahbod } 249a3313e54008167e415b72c780ca7b9cda958d07eBehdad Esfahbod 250a3313e54008167e415b72c780ca7b9cda958d07eBehdad Esfahbod xt_params = xtp; 251a3313e54008167e415b72c780ca7b9cda958d07eBehdad Esfahbod 2525d874d566fe5d2cc4cfaf02c79b663d8a626ca1eBehdad Esfahbod if (!xt_params->exit_err) 2535d874d566fe5d2cc4cfaf02c79b663d8a626ca1eBehdad Esfahbod xt_params->exit_err = basic_exit_err; 2544751dec8be05883483fd5f6b474ebd22583ae566Behdad Esfahbod 255a3313e54008167e415b72c780ca7b9cda958d07eBehdad Esfahbod return 0; 256a3313e54008167e415b72c780ca7b9cda958d07eBehdad Esfahbod} 257a3313e54008167e415b72c780ca7b9cda958d07eBehdad Esfahbod 2582e96d2c6ee34142375373be07217c9953e7822ccBehdad Esfahbodint xtables_init_all(struct xtables_globals *xtp, uint8_t nfproto) 2592e96d2c6ee34142375373be07217c9953e7822ccBehdad Esfahbod{ 2602e96d2c6ee34142375373be07217c9953e7822ccBehdad Esfahbod xtables_init(); 261a3313e54008167e415b72c780ca7b9cda958d07eBehdad Esfahbod xtables_set_nfproto(nfproto); 262a3313e54008167e415b72c780ca7b9cda958d07eBehdad Esfahbod return xtables_set_params(xtp); 263a3313e54008167e415b72c780ca7b9cda958d07eBehdad Esfahbod} 264a3313e54008167e415b72c780ca7b9cda958d07eBehdad Esfahbod 265a3313e54008167e415b72c780ca7b9cda958d07eBehdad Esfahbod/** 2665d874d566fe5d2cc4cfaf02c79b663d8a626ca1eBehdad Esfahbod * xtables_*alloc - wrappers that exit on failure 267a3313e54008167e415b72c780ca7b9cda958d07eBehdad Esfahbod */ 268a3313e54008167e415b72c780ca7b9cda958d07eBehdad Esfahbodvoid *xtables_calloc(size_t count, size_t size) 269a3313e54008167e415b72c780ca7b9cda958d07eBehdad Esfahbod{ 2702e96d2c6ee34142375373be07217c9953e7822ccBehdad Esfahbod void *p; 271a3313e54008167e415b72c780ca7b9cda958d07eBehdad Esfahbod 272101303dbf7cf15d044bf2518f14b3aec65970feaBehdad Esfahbod if ((p = calloc(count, size)) == NULL) { 273101303dbf7cf15d044bf2518f14b3aec65970feaBehdad Esfahbod perror("ip[6]tables: calloc failed"); 274101303dbf7cf15d044bf2518f14b3aec65970feaBehdad Esfahbod exit(1); 275101303dbf7cf15d044bf2518f14b3aec65970feaBehdad Esfahbod } 276101303dbf7cf15d044bf2518f14b3aec65970feaBehdad Esfahbod 277101303dbf7cf15d044bf2518f14b3aec65970feaBehdad Esfahbod return p; 278101303dbf7cf15d044bf2518f14b3aec65970feaBehdad Esfahbod} 2794751dec8be05883483fd5f6b474ebd22583ae566Behdad Esfahbod 280101303dbf7cf15d044bf2518f14b3aec65970feaBehdad Esfahbodvoid *xtables_malloc(size_t size) 28149c5ec51444f27f33e1eb6aa1959c61b08fa89c0Behdad Esfahbod{ 2823ddf892b5328b74afb6e7d9da727d8771ca5d288Behdad Esfahbod void *p; 2833ddf892b5328b74afb6e7d9da727d8771ca5d288Behdad Esfahbod 2843ddf892b5328b74afb6e7d9da727d8771ca5d288Behdad Esfahbod if ((p = malloc(size)) == NULL) { 2852ec3ba46a3c24469096e901750e38f6ee555479aBehdad Esfahbod perror("ip[6]tables: malloc failed"); 2863ddf892b5328b74afb6e7d9da727d8771ca5d288Behdad Esfahbod exit(1); 2872ec3ba46a3c24469096e901750e38f6ee555479aBehdad Esfahbod } 288101303dbf7cf15d044bf2518f14b3aec65970feaBehdad Esfahbod 2892ec3ba46a3c24469096e901750e38f6ee555479aBehdad Esfahbod return p; 2903ddf892b5328b74afb6e7d9da727d8771ca5d288Behdad Esfahbod} 2913ddf892b5328b74afb6e7d9da727d8771ca5d288Behdad Esfahbod 2923ddf892b5328b74afb6e7d9da727d8771ca5d288Behdad Esfahbodvoid *xtables_realloc(void *ptr, size_t size) 2932ec3ba46a3c24469096e901750e38f6ee555479aBehdad Esfahbod{ 2943ddf892b5328b74afb6e7d9da727d8771ca5d288Behdad Esfahbod void *p; 2952ec3ba46a3c24469096e901750e38f6ee555479aBehdad Esfahbod 296101303dbf7cf15d044bf2518f14b3aec65970feaBehdad Esfahbod if ((p = realloc(ptr, size)) == NULL) { 2972ec3ba46a3c24469096e901750e38f6ee555479aBehdad Esfahbod perror("ip[6]tables: realloc failed"); 2983ddf892b5328b74afb6e7d9da727d8771ca5d288Behdad Esfahbod exit(1); 2992ec3ba46a3c24469096e901750e38f6ee555479aBehdad Esfahbod } 3003ddf892b5328b74afb6e7d9da727d8771ca5d288Behdad Esfahbod 3012ec3ba46a3c24469096e901750e38f6ee555479aBehdad Esfahbod return p; 3022ec3ba46a3c24469096e901750e38f6ee555479aBehdad Esfahbod} 30349c5ec51444f27f33e1eb6aa1959c61b08fa89c0Behdad Esfahbod 3043ddf892b5328b74afb6e7d9da727d8771ca5d288Behdad Esfahbodstatic char *get_modprobe(void) 30549c5ec51444f27f33e1eb6aa1959c61b08fa89c0Behdad Esfahbod{ 3063ddf892b5328b74afb6e7d9da727d8771ca5d288Behdad Esfahbod int procfile; 30749c5ec51444f27f33e1eb6aa1959c61b08fa89c0Behdad Esfahbod char *ret; 308101303dbf7cf15d044bf2518f14b3aec65970feaBehdad Esfahbod 3094751dec8be05883483fd5f6b474ebd22583ae566Behdad Esfahbod#define PROCFILE_BUFSIZ 1024 310a1f7b2856184959e965c9c2b80363f9f46d486a7Behdad Esfahbod procfile = open(PROC_SYS_MODPROBE, O_RDONLY); 3114751dec8be05883483fd5f6b474ebd22583ae566Behdad Esfahbod if (procfile < 0) 3123ddf892b5328b74afb6e7d9da727d8771ca5d288Behdad Esfahbod return NULL; 3134751dec8be05883483fd5f6b474ebd22583ae566Behdad Esfahbod if (fcntl(procfile, F_SETFD, FD_CLOEXEC) == -1) { 314101303dbf7cf15d044bf2518f14b3aec65970feaBehdad Esfahbod fprintf(stderr, "Could not set close on exec: %s\n", 31549c5ec51444f27f33e1eb6aa1959c61b08fa89c0Behdad Esfahbod strerror(errno)); 3163ddf892b5328b74afb6e7d9da727d8771ca5d288Behdad Esfahbod exit(1); 31749c5ec51444f27f33e1eb6aa1959c61b08fa89c0Behdad Esfahbod } 318a1f7b2856184959e965c9c2b80363f9f46d486a7Behdad Esfahbod 3192ec3ba46a3c24469096e901750e38f6ee555479aBehdad Esfahbod ret = malloc(PROCFILE_BUFSIZ); 3202ec3ba46a3c24469096e901750e38f6ee555479aBehdad Esfahbod if (ret) { 3213ddf892b5328b74afb6e7d9da727d8771ca5d288Behdad Esfahbod memset(ret, 0, PROCFILE_BUFSIZ); 3222ec3ba46a3c24469096e901750e38f6ee555479aBehdad Esfahbod switch (read(procfile, ret, PROCFILE_BUFSIZ)) { 323101303dbf7cf15d044bf2518f14b3aec65970feaBehdad Esfahbod case -1: goto fail; 3242ec3ba46a3c24469096e901750e38f6ee555479aBehdad Esfahbod case PROCFILE_BUFSIZ: goto fail; /* Partial read. Wierd */ 3253ddf892b5328b74afb6e7d9da727d8771ca5d288Behdad Esfahbod } 3262ec3ba46a3c24469096e901750e38f6ee555479aBehdad Esfahbod if (ret[strlen(ret)-1]=='\n') 3273ddf892b5328b74afb6e7d9da727d8771ca5d288Behdad Esfahbod ret[strlen(ret)-1]=0; 328a1f7b2856184959e965c9c2b80363f9f46d486a7Behdad Esfahbod close(procfile); 3293ddf892b5328b74afb6e7d9da727d8771ca5d288Behdad Esfahbod return ret; 3302ec3ba46a3c24469096e901750e38f6ee555479aBehdad Esfahbod } 3312ec3ba46a3c24469096e901750e38f6ee555479aBehdad Esfahbod fail: 33249c5ec51444f27f33e1eb6aa1959c61b08fa89c0Behdad Esfahbod free(ret); 33349c5ec51444f27f33e1eb6aa1959c61b08fa89c0Behdad Esfahbod close(procfile); 3343ddf892b5328b74afb6e7d9da727d8771ca5d288Behdad Esfahbod return NULL; 3353ddf892b5328b74afb6e7d9da727d8771ca5d288Behdad Esfahbod} 3362ec3ba46a3c24469096e901750e38f6ee555479aBehdad Esfahbod 33749c5ec51444f27f33e1eb6aa1959c61b08fa89c0Behdad Esfahbodint xtables_insmod(const char *modname, const char *modprobe, bool quiet) 3383ddf892b5328b74afb6e7d9da727d8771ca5d288Behdad Esfahbod{ 33949c5ec51444f27f33e1eb6aa1959c61b08fa89c0Behdad Esfahbod char *buf = NULL; 34049c5ec51444f27f33e1eb6aa1959c61b08fa89c0Behdad Esfahbod char *argv[4]; 34149c5ec51444f27f33e1eb6aa1959c61b08fa89c0Behdad Esfahbod int status; 34291689de2603e4151e2a2d3a3852c61667f0c6264Behdad Esfahbod 34391689de2603e4151e2a2d3a3852c61667f0c6264Behdad Esfahbod /* If they don't explicitly set it, read out of kernel */ 3446faff8e4132197ba06f0e685b82efe35b546cf64Behdad Esfahbod if (!modprobe) { 34591689de2603e4151e2a2d3a3852c61667f0c6264Behdad Esfahbod buf = get_modprobe(); 34691689de2603e4151e2a2d3a3852c61667f0c6264Behdad Esfahbod if (!buf) 34791689de2603e4151e2a2d3a3852c61667f0c6264Behdad Esfahbod return -1; 34891689de2603e4151e2a2d3a3852c61667f0c6264Behdad Esfahbod modprobe = buf; 34991689de2603e4151e2a2d3a3852c61667f0c6264Behdad Esfahbod } 3506faff8e4132197ba06f0e685b82efe35b546cf64Behdad Esfahbod 351101303dbf7cf15d044bf2518f14b3aec65970feaBehdad Esfahbod /* 352101303dbf7cf15d044bf2518f14b3aec65970feaBehdad Esfahbod * Need to flush the buffer, or the child may output it again 353101303dbf7cf15d044bf2518f14b3aec65970feaBehdad Esfahbod * when switching the program thru execv. 354101303dbf7cf15d044bf2518f14b3aec65970feaBehdad Esfahbod */ 355101303dbf7cf15d044bf2518f14b3aec65970feaBehdad Esfahbod fflush(stdout); 3566faff8e4132197ba06f0e685b82efe35b546cf64Behdad Esfahbod 357101303dbf7cf15d044bf2518f14b3aec65970feaBehdad Esfahbod switch (vfork()) { 358101303dbf7cf15d044bf2518f14b3aec65970feaBehdad Esfahbod case 0: 359101303dbf7cf15d044bf2518f14b3aec65970feaBehdad Esfahbod argv[0] = (char *)modprobe; 360101303dbf7cf15d044bf2518f14b3aec65970feaBehdad Esfahbod argv[1] = (char *)modname; 361101303dbf7cf15d044bf2518f14b3aec65970feaBehdad Esfahbod if (quiet) { 3626faff8e4132197ba06f0e685b82efe35b546cf64Behdad Esfahbod argv[2] = "-q"; 363101303dbf7cf15d044bf2518f14b3aec65970feaBehdad Esfahbod argv[3] = NULL; 364101303dbf7cf15d044bf2518f14b3aec65970feaBehdad Esfahbod } else { 365101303dbf7cf15d044bf2518f14b3aec65970feaBehdad Esfahbod argv[2] = NULL; 366101303dbf7cf15d044bf2518f14b3aec65970feaBehdad Esfahbod argv[3] = NULL; 367101303dbf7cf15d044bf2518f14b3aec65970feaBehdad Esfahbod } 3686faff8e4132197ba06f0e685b82efe35b546cf64Behdad Esfahbod execv(argv[0], argv); 369101303dbf7cf15d044bf2518f14b3aec65970feaBehdad Esfahbod 370101303dbf7cf15d044bf2518f14b3aec65970feaBehdad Esfahbod /* not usually reached */ 371101303dbf7cf15d044bf2518f14b3aec65970feaBehdad Esfahbod exit(1); 372101303dbf7cf15d044bf2518f14b3aec65970feaBehdad Esfahbod case -1: 373101303dbf7cf15d044bf2518f14b3aec65970feaBehdad Esfahbod free(buf); 374a1f7b2856184959e965c9c2b80363f9f46d486a7Behdad Esfahbod return -1; 375857027341423f15fd6084c7563cc355b06e7cbddBehdad Esfahbod 376857027341423f15fd6084c7563cc355b06e7cbddBehdad Esfahbod default: /* parent */ 377857027341423f15fd6084c7563cc355b06e7cbddBehdad Esfahbod wait(&status); 378857027341423f15fd6084c7563cc355b06e7cbddBehdad Esfahbod } 379857027341423f15fd6084c7563cc355b06e7cbddBehdad Esfahbod 380857027341423f15fd6084c7563cc355b06e7cbddBehdad Esfahbod free(buf); 381a1f7b2856184959e965c9c2b80363f9f46d486a7Behdad Esfahbod if (WIFEXITED(status) && WEXITSTATUS(status) == 0) 382a1f7b2856184959e965c9c2b80363f9f46d486a7Behdad Esfahbod return 0; 383a1f7b2856184959e965c9c2b80363f9f46d486a7Behdad Esfahbod return -1; 384832a6f99b34f334b1e82b8e3a7ad137e823d203cBehdad Esfahbod} 385832a6f99b34f334b1e82b8e3a7ad137e823d203cBehdad Esfahbod 386832a6f99b34f334b1e82b8e3a7ad137e823d203cBehdad Esfahbod/* return true if a given file exists within procfs */ 387832a6f99b34f334b1e82b8e3a7ad137e823d203cBehdad Esfahbodstatic bool proc_file_exists(const char *filename) 388832a6f99b34f334b1e82b8e3a7ad137e823d203cBehdad Esfahbod{ 389832a6f99b34f334b1e82b8e3a7ad137e823d203cBehdad Esfahbod struct stat s; 390832a6f99b34f334b1e82b8e3a7ad137e823d203cBehdad Esfahbod struct statfs f; 391832a6f99b34f334b1e82b8e3a7ad137e823d203cBehdad Esfahbod 392832a6f99b34f334b1e82b8e3a7ad137e823d203cBehdad Esfahbod if (lstat(filename, &s)) 393832a6f99b34f334b1e82b8e3a7ad137e823d203cBehdad Esfahbod return false; 394832a6f99b34f334b1e82b8e3a7ad137e823d203cBehdad Esfahbod if (!S_ISREG(s.st_mode)) 395832a6f99b34f334b1e82b8e3a7ad137e823d203cBehdad Esfahbod return false; 396a1f7b2856184959e965c9c2b80363f9f46d486a7Behdad Esfahbod if (statfs(filename, &f)) 397a1f7b2856184959e965c9c2b80363f9f46d486a7Behdad Esfahbod return false; 39804dc52fa15f5b7f9eb5f448ea43e7ef1b2269e88Behdad Esfahbod if (f.f_type != PROC_SUPER_MAGIC) 39904dc52fa15f5b7f9eb5f448ea43e7ef1b2269e88Behdad Esfahbod return false; 40004dc52fa15f5b7f9eb5f448ea43e7ef1b2269e88Behdad Esfahbod return true; 40104dc52fa15f5b7f9eb5f448ea43e7ef1b2269e88Behdad Esfahbod} 40204dc52fa15f5b7f9eb5f448ea43e7ef1b2269e88Behdad Esfahbod 40304dc52fa15f5b7f9eb5f448ea43e7ef1b2269e88Behdad Esfahbodint xtables_load_ko(const char *modprobe, bool quiet) 40404dc52fa15f5b7f9eb5f448ea43e7ef1b2269e88Behdad Esfahbod{ 40504dc52fa15f5b7f9eb5f448ea43e7ef1b2269e88Behdad Esfahbod static bool loaded = false; 406101303dbf7cf15d044bf2518f14b3aec65970feaBehdad Esfahbod int ret; 407101303dbf7cf15d044bf2518f14b3aec65970feaBehdad Esfahbod 4086faff8e4132197ba06f0e685b82efe35b546cf64Behdad Esfahbod if (loaded) 409101303dbf7cf15d044bf2518f14b3aec65970feaBehdad Esfahbod return 0; 410101303dbf7cf15d044bf2518f14b3aec65970feaBehdad Esfahbod 411101303dbf7cf15d044bf2518f14b3aec65970feaBehdad Esfahbod if (proc_file_exists(afinfo->proc_exists)) { 412101303dbf7cf15d044bf2518f14b3aec65970feaBehdad Esfahbod loaded = true; 413101303dbf7cf15d044bf2518f14b3aec65970feaBehdad Esfahbod return 0; 414101303dbf7cf15d044bf2518f14b3aec65970feaBehdad Esfahbod }; 4156faff8e4132197ba06f0e685b82efe35b546cf64Behdad Esfahbod 416101303dbf7cf15d044bf2518f14b3aec65970feaBehdad Esfahbod ret = xtables_insmod(afinfo->kmod, modprobe, quiet); 417101303dbf7cf15d044bf2518f14b3aec65970feaBehdad Esfahbod if (ret == 0) 418101303dbf7cf15d044bf2518f14b3aec65970feaBehdad Esfahbod loaded = true; 419101303dbf7cf15d044bf2518f14b3aec65970feaBehdad Esfahbod 420101303dbf7cf15d044bf2518f14b3aec65970feaBehdad Esfahbod return ret; 421101303dbf7cf15d044bf2518f14b3aec65970feaBehdad Esfahbod} 4226faff8e4132197ba06f0e685b82efe35b546cf64Behdad Esfahbod 423101303dbf7cf15d044bf2518f14b3aec65970feaBehdad Esfahbod/** 424101303dbf7cf15d044bf2518f14b3aec65970feaBehdad Esfahbod * xtables_strtou{i,l} - string to number conversion 425101303dbf7cf15d044bf2518f14b3aec65970feaBehdad Esfahbod * @s: input string 426101303dbf7cf15d044bf2518f14b3aec65970feaBehdad Esfahbod * @end: like strtoul's "end" pointer 427101303dbf7cf15d044bf2518f14b3aec65970feaBehdad Esfahbod * @value: pointer for result 428101303dbf7cf15d044bf2518f14b3aec65970feaBehdad Esfahbod * @min: minimum accepted value 429101303dbf7cf15d044bf2518f14b3aec65970feaBehdad Esfahbod * @max: maximum accepted value 4306faff8e4132197ba06f0e685b82efe35b546cf64Behdad Esfahbod * 431101303dbf7cf15d044bf2518f14b3aec65970feaBehdad Esfahbod * If @end is NULL, we assume the caller wants a "strict strtoul", and hence 432101303dbf7cf15d044bf2518f14b3aec65970feaBehdad Esfahbod * "15a" is rejected. 433101303dbf7cf15d044bf2518f14b3aec65970feaBehdad Esfahbod * In either case, the value obtained is compared for min-max compliance. 434101303dbf7cf15d044bf2518f14b3aec65970feaBehdad Esfahbod * Base is always 0, i.e. autodetect depending on @s. 435101303dbf7cf15d044bf2518f14b3aec65970feaBehdad Esfahbod * 436101303dbf7cf15d044bf2518f14b3aec65970feaBehdad Esfahbod * Returns true/false whether number was accepted. On failure, *value has 43791689de2603e4151e2a2d3a3852c61667f0c6264Behdad Esfahbod * undefined contents. 438101303dbf7cf15d044bf2518f14b3aec65970feaBehdad Esfahbod */ 439101303dbf7cf15d044bf2518f14b3aec65970feaBehdad Esfahbodbool xtables_strtoul(const char *s, char **end, uintmax_t *value, 440101303dbf7cf15d044bf2518f14b3aec65970feaBehdad Esfahbod uintmax_t min, uintmax_t max) 441101303dbf7cf15d044bf2518f14b3aec65970feaBehdad Esfahbod{ 442101303dbf7cf15d044bf2518f14b3aec65970feaBehdad Esfahbod uintmax_t v; 44349c5ec51444f27f33e1eb6aa1959c61b08fa89c0Behdad Esfahbod const char *p; 444fd92a3dde32fd10df30c9eeb97641bc3c15b1e9bBehdad Esfahbod char *my_end; 4450f0cd9d361f1bb614aa3fd4616160d027062370eBehdad Esfahbod 446 errno = 0; 447 /* Since strtoul allows leading minus, we have to check for ourself. */ 448 for (p = s; isspace(*p); ++p) 449 ; 450 if (*p == '-') 451 return false; 452 v = strtoumax(s, &my_end, 0); 453 if (my_end == s) 454 return false; 455 if (end != NULL) 456 *end = my_end; 457 458 if (errno != ERANGE && min <= v && (max == 0 || v <= max)) { 459 if (value != NULL) 460 *value = v; 461 if (end == NULL) 462 return *my_end == '\0'; 463 return true; 464 } 465 466 return false; 467} 468 469bool xtables_strtoui(const char *s, char **end, unsigned int *value, 470 unsigned int min, unsigned int max) 471{ 472 uintmax_t v; 473 bool ret; 474 475 ret = xtables_strtoul(s, end, &v, min, max); 476 if (value != NULL) 477 *value = v; 478 return ret; 479} 480 481int xtables_service_to_port(const char *name, const char *proto) 482{ 483 struct servent *service; 484 485 if ((service = getservbyname(name, proto)) != NULL) 486 return ntohs((unsigned short) service->s_port); 487 488 return -1; 489} 490 491uint16_t xtables_parse_port(const char *port, const char *proto) 492{ 493 unsigned int portnum; 494 495 if (xtables_strtoui(port, NULL, &portnum, 0, UINT16_MAX) || 496 (portnum = xtables_service_to_port(port, proto)) != (unsigned)-1) 497 return portnum; 498 499 xt_params->exit_err(PARAMETER_PROBLEM, 500 "invalid port/service `%s' specified", port); 501} 502 503void xtables_parse_interface(const char *arg, char *vianame, 504 unsigned char *mask) 505{ 506 unsigned int vialen = strlen(arg); 507 unsigned int i; 508 509 memset(mask, 0, IFNAMSIZ); 510 memset(vianame, 0, IFNAMSIZ); 511 512 if (vialen + 1 > IFNAMSIZ) 513 xt_params->exit_err(PARAMETER_PROBLEM, 514 "interface name `%s' must be shorter than IFNAMSIZ" 515 " (%i)", arg, IFNAMSIZ-1); 516 517 strcpy(vianame, arg); 518 if (vialen == 0) 519 return; 520 else if (vianame[vialen - 1] == '+') { 521 memset(mask, 0xFF, vialen - 1); 522 /* Don't remove `+' here! -HW */ 523 } else { 524 /* Include nul-terminator in match */ 525 memset(mask, 0xFF, vialen + 1); 526 for (i = 0; vianame[i]; i++) { 527 if (vianame[i] == '/' || 528 vianame[i] == ' ') { 529 fprintf(stderr, 530 "Warning: weird character in interface" 531 " `%s' ('/' and ' ' are not allowed by the kernel).\n", 532 vianame); 533 break; 534 } 535 } 536 } 537} 538 539#ifndef NO_SHARED_LIBS 540static void *load_extension(const char *search_path, const char *af_prefix, 541 const char *name, bool is_target) 542{ 543 const char *all_prefixes[] = {"libxt_", af_prefix, NULL}; 544 const char **prefix; 545 const char *dir = search_path, *next; 546 void *ptr = NULL; 547 struct stat sb; 548 char path[256]; 549 550 do { 551 next = strchr(dir, ':'); 552 if (next == NULL) 553 next = dir + strlen(dir); 554 555 for (prefix = all_prefixes; *prefix != NULL; ++prefix) { 556 snprintf(path, sizeof(path), "%.*s/%s%s.so", 557 (unsigned int)(next - dir), dir, 558 *prefix, name); 559 560 if (stat(path, &sb) != 0) { 561 if (errno == ENOENT) 562 continue; 563 fprintf(stderr, "%s: %s\n", path, 564 strerror(errno)); 565 return NULL; 566 } 567 if (dlopen(path, RTLD_NOW) == NULL) { 568 fprintf(stderr, "%s: %s\n", path, dlerror()); 569 break; 570 } 571 572 if (is_target) 573 ptr = xtables_find_target(name, XTF_DONT_LOAD); 574 else 575 ptr = xtables_find_match(name, 576 XTF_DONT_LOAD, NULL); 577 578 if (ptr != NULL) 579 return ptr; 580 581 fprintf(stderr, "%s: no \"%s\" extension found for " 582 "this protocol\n", path, name); 583 errno = ENOENT; 584 return NULL; 585 } 586 dir = next + 1; 587 } while (*next != '\0'); 588 589 return NULL; 590} 591#endif 592 593struct xtables_match * 594xtables_find_match(const char *name, enum xtables_tryload tryload, 595 struct xtables_rule_match **matches) 596{ 597 struct xtables_match **dptr; 598 struct xtables_match *ptr; 599 const char *icmp6 = "icmp6"; 600 601 if (strlen(name) >= XT_EXTENSION_MAXNAMELEN) 602 xtables_error(PARAMETER_PROBLEM, 603 "Invalid match name \"%s\" (%u chars max)", 604 name, XT_EXTENSION_MAXNAMELEN - 1); 605 606 /* This is ugly as hell. Nonetheless, there is no way of changing 607 * this without hurting backwards compatibility */ 608 if ( (strcmp(name,"icmpv6") == 0) || 609 (strcmp(name,"ipv6-icmp") == 0) || 610 (strcmp(name,"icmp6") == 0) ) 611 name = icmp6; 612 613 /* Trigger delayed initialization */ 614 for (dptr = &xtables_pending_matches; *dptr; ) { 615 if (strcmp(name, (*dptr)->name) == 0) { 616 ptr = *dptr; 617 *dptr = (*dptr)->next; 618 ptr->next = NULL; 619 xtables_fully_register_pending_match(ptr); 620 } else { 621 dptr = &((*dptr)->next); 622 } 623 } 624 625 for (ptr = xtables_matches; ptr; ptr = ptr->next) { 626 if (strcmp(name, ptr->name) == 0) { 627 struct xtables_match *clone; 628 629 /* First match of this type: */ 630 if (ptr->m == NULL) 631 break; 632 633 /* Second and subsequent clones */ 634 clone = xtables_malloc(sizeof(struct xtables_match)); 635 memcpy(clone, ptr, sizeof(struct xtables_match)); 636 clone->udata = NULL; 637 clone->mflags = 0; 638 /* This is a clone: */ 639 clone->next = clone; 640 641 ptr = clone; 642 break; 643 } 644 } 645 646#ifndef NO_SHARED_LIBS 647 if (!ptr && tryload != XTF_DONT_LOAD && tryload != XTF_DURING_LOAD) { 648 ptr = load_extension(xtables_libdir, afinfo->libprefix, 649 name, false); 650 651 if (ptr == NULL && tryload == XTF_LOAD_MUST_SUCCEED) 652 xt_params->exit_err(PARAMETER_PROBLEM, 653 "Couldn't load match `%s':%s\n", 654 name, strerror(errno)); 655 } 656#else 657 if (ptr && !ptr->loaded) { 658 if (tryload != XTF_DONT_LOAD) 659 ptr->loaded = 1; 660 else 661 ptr = NULL; 662 } 663 if(!ptr && (tryload == XTF_LOAD_MUST_SUCCEED)) { 664 xt_params->exit_err(PARAMETER_PROBLEM, 665 "Couldn't find match `%s'\n", name); 666 } 667#endif 668 669 if (ptr && matches) { 670 struct xtables_rule_match **i; 671 struct xtables_rule_match *newentry; 672 673 newentry = xtables_malloc(sizeof(struct xtables_rule_match)); 674 675 for (i = matches; *i; i = &(*i)->next) { 676 if (strcmp(name, (*i)->match->name) == 0) 677 (*i)->completed = true; 678 } 679 newentry->match = ptr; 680 newentry->completed = false; 681 newentry->next = NULL; 682 *i = newentry; 683 } 684 685 return ptr; 686} 687 688struct xtables_target * 689xtables_find_target(const char *name, enum xtables_tryload tryload) 690{ 691 struct xtables_target **dptr; 692 struct xtables_target *ptr; 693 694 /* Standard target? */ 695 if (strcmp(name, "") == 0 696 || strcmp(name, XTC_LABEL_ACCEPT) == 0 697 || strcmp(name, XTC_LABEL_DROP) == 0 698 || strcmp(name, XTC_LABEL_QUEUE) == 0 699 || strcmp(name, XTC_LABEL_RETURN) == 0) 700 name = "standard"; 701 702 /* Trigger delayed initialization */ 703 for (dptr = &xtables_pending_targets; *dptr; ) { 704 if (strcmp(name, (*dptr)->name) == 0) { 705 ptr = *dptr; 706 *dptr = (*dptr)->next; 707 ptr->next = NULL; 708 xtables_fully_register_pending_target(ptr); 709 } else { 710 dptr = &((*dptr)->next); 711 } 712 } 713 714 for (ptr = xtables_targets; ptr; ptr = ptr->next) { 715 if (strcmp(name, ptr->name) == 0) 716 break; 717 } 718 719#ifndef NO_SHARED_LIBS 720 if (!ptr && tryload != XTF_DONT_LOAD && tryload != XTF_DURING_LOAD) { 721 ptr = load_extension(xtables_libdir, afinfo->libprefix, 722 name, true); 723 724 if (ptr == NULL && tryload == XTF_LOAD_MUST_SUCCEED) 725 xt_params->exit_err(PARAMETER_PROBLEM, 726 "Couldn't load target `%s':%s\n", 727 name, strerror(errno)); 728 } 729#else 730 if (ptr && !ptr->loaded) { 731 if (tryload != XTF_DONT_LOAD) 732 ptr->loaded = 1; 733 else 734 ptr = NULL; 735 } 736 if (ptr == NULL && tryload == XTF_LOAD_MUST_SUCCEED) { 737 xt_params->exit_err(PARAMETER_PROBLEM, 738 "Couldn't find target `%s'\n", name); 739 } 740#endif 741 742 if (ptr) 743 ptr->used = 1; 744 745 return ptr; 746} 747 748static int compatible_revision(const char *name, uint8_t revision, int opt) 749{ 750 struct xt_get_revision rev; 751 socklen_t s = sizeof(rev); 752 int max_rev, sockfd; 753 754 sockfd = socket(afinfo->family, SOCK_RAW, IPPROTO_RAW); 755 if (sockfd < 0) { 756 if (errno == EPERM) { 757 /* revision 0 is always supported. */ 758 if (revision != 0) 759 fprintf(stderr, "%s: Could not determine whether " 760 "revision %u is supported, " 761 "assuming it is.\n", 762 name, revision); 763 return 1; 764 } 765 fprintf(stderr, "Could not open socket to kernel: %s\n", 766 strerror(errno)); 767 exit(1); 768 } 769 770 if (fcntl(sockfd, F_SETFD, FD_CLOEXEC) == -1) { 771 fprintf(stderr, "Could not set close on exec: %s\n", 772 strerror(errno)); 773 exit(1); 774 } 775 776 xtables_load_ko(xtables_modprobe_program, true); 777 778 strcpy(rev.name, name); 779 rev.revision = revision; 780 781 max_rev = getsockopt(sockfd, afinfo->ipproto, opt, &rev, &s); 782 if (max_rev < 0) { 783 /* Definitely don't support this? */ 784 if (errno == ENOENT || errno == EPROTONOSUPPORT) { 785 close(sockfd); 786 return 0; 787 } else if (errno == ENOPROTOOPT) { 788 close(sockfd); 789 /* Assume only revision 0 support (old kernel) */ 790 return (revision == 0); 791 } else { 792 fprintf(stderr, "getsockopt failed strangely: %s\n", 793 strerror(errno)); 794 exit(1); 795 } 796 } 797 close(sockfd); 798 return 1; 799} 800 801 802static int compatible_match_revision(const char *name, uint8_t revision) 803{ 804 return compatible_revision(name, revision, afinfo->so_rev_match); 805} 806 807static int compatible_target_revision(const char *name, uint8_t revision) 808{ 809 return compatible_revision(name, revision, afinfo->so_rev_target); 810} 811 812static void xtables_check_options(const char *name, const struct option *opt) 813{ 814 for (; opt->name != NULL; ++opt) 815 if (opt->val < 0 || opt->val >= XT_OPTION_OFFSET_SCALE) { 816 fprintf(stderr, "%s: Extension %s uses invalid " 817 "option value %d\n",xt_params->program_name, 818 name, opt->val); 819 exit(1); 820 } 821} 822 823void xtables_register_match(struct xtables_match *me) 824{ 825 if (me->version == NULL) { 826 fprintf(stderr, "%s: match %s<%u> is missing a version\n", 827 xt_params->program_name, me->name, me->revision); 828 exit(1); 829 } 830 if (strcmp(me->version, XTABLES_VERSION) != 0) { 831 fprintf(stderr, "%s: match \"%s\" has version \"%s\", " 832 "but \"%s\" is required.\n", 833 xt_params->program_name, me->name, 834 me->version, XTABLES_VERSION); 835 exit(1); 836 } 837 838 if (strlen(me->name) >= XT_EXTENSION_MAXNAMELEN) { 839 fprintf(stderr, "%s: match `%s' has invalid name\n", 840 xt_params->program_name, me->name); 841 exit(1); 842 } 843 844 if (me->family >= NPROTO) { 845 fprintf(stderr, 846 "%s: BUG: match %s has invalid protocol family\n", 847 xt_params->program_name, me->name); 848 exit(1); 849 } 850 851 if (me->real_name == NULL) 852 me->real_name = me->name; 853 if (me->x6_options != NULL) 854 xtables_option_metavalidate(me->name, me->x6_options); 855 if (me->extra_opts != NULL) 856 xtables_check_options(me->name, me->extra_opts); 857 858 /* ignore not interested match */ 859 if (me->family != afinfo->family && me->family != AF_UNSPEC) 860 return; 861 862 /* place on linked list of matches pending full registration */ 863 me->next = xtables_pending_matches; 864 xtables_pending_matches = me; 865} 866 867/** 868 * Compare two actions for their preference 869 * @a: one action 870 * @b: another 871 * 872 * Like strcmp, returns a negative number if @a is less preferred than @b, 873 * positive number if @a is more preferred than @b, or zero if equally 874 * preferred. 875 */ 876static int 877xtables_mt_prefer(bool a_alias, unsigned int a_rev, unsigned int a_fam, 878 bool b_alias, unsigned int b_rev, unsigned int b_fam) 879{ 880 /* 881 * Alias ranks higher than no alias. 882 * (We want the new action to be used whenever possible.) 883 */ 884 if (!a_alias && b_alias) 885 return -1; 886 if (a_alias && !b_alias) 887 return 1; 888 889 /* Higher revision ranks higher. */ 890 if (a_rev < b_rev) 891 return -1; 892 if (a_rev > b_rev) 893 return 1; 894 895 /* NFPROTO_<specific> ranks higher than NFPROTO_UNSPEC. */ 896 if (a_fam == NFPROTO_UNSPEC && b_fam != NFPROTO_UNSPEC) 897 return -1; 898 if (a_fam != NFPROTO_UNSPEC && b_fam == NFPROTO_UNSPEC) 899 return 1; 900 901 /* Must be the same thing. */ 902 return 0; 903} 904 905static int xtables_match_prefer(const struct xtables_match *a, 906 const struct xtables_match *b) 907{ 908 return xtables_mt_prefer(a->name != a->real_name, 909 a->revision, a->family, 910 b->name != b->real_name, 911 b->revision, b->family); 912} 913 914static int xtables_target_prefer(const struct xtables_target *a, 915 const struct xtables_target *b) 916{ 917 /* 918 * Note that if x->real_name==NULL, it will be set to x->name in 919 * xtables_register_*; the direct pointer comparison here is therefore 920 * legitimate to detect an alias. 921 */ 922 return xtables_mt_prefer(a->name != a->real_name, 923 a->revision, a->family, 924 b->name != b->real_name, 925 b->revision, b->family); 926} 927 928static void xtables_fully_register_pending_match(struct xtables_match *me) 929{ 930 struct xtables_match **i, *old; 931 int compare; 932 933 old = xtables_find_match(me->name, XTF_DURING_LOAD, NULL); 934 if (old) { 935 compare = xtables_match_prefer(old, me); 936 if (compare == 0) { 937 fprintf(stderr, 938 "%s: match `%s' already registered.\n", 939 xt_params->program_name, me->name); 940 exit(1); 941 } 942 943 /* Now we have two (or more) options, check compatibility. */ 944 if (compare > 0 && 945 compatible_match_revision(old->real_name, old->revision)) 946 return; 947 948 /* See if new match can be used. */ 949 if (!compatible_match_revision(me->real_name, me->revision)) 950 return; 951 952 /* Delete old one. */ 953 for (i = &xtables_matches; *i!=old; i = &(*i)->next); 954 *i = old->next; 955 } 956 957 if (me->size != XT_ALIGN(me->size)) { 958 fprintf(stderr, "%s: match `%s' has invalid size %u.\n", 959 xt_params->program_name, me->name, 960 (unsigned int)me->size); 961 exit(1); 962 } 963 964 /* Append to list. */ 965 for (i = &xtables_matches; *i; i = &(*i)->next); 966 me->next = NULL; 967 *i = me; 968 969 me->m = NULL; 970 me->mflags = 0; 971} 972 973void xtables_register_matches(struct xtables_match *match, unsigned int n) 974{ 975 do { 976 xtables_register_match(&match[--n]); 977 } while (n > 0); 978} 979 980void xtables_register_target(struct xtables_target *me) 981{ 982 if (me->version == NULL) { 983 fprintf(stderr, "%s: target %s<%u> is missing a version\n", 984 xt_params->program_name, me->name, me->revision); 985 exit(1); 986 } 987 if (strcmp(me->version, XTABLES_VERSION) != 0) { 988 fprintf(stderr, "%s: target \"%s\" has version \"%s\", " 989 "but \"%s\" is required.\n", 990 xt_params->program_name, me->name, 991 me->version, XTABLES_VERSION); 992 exit(1); 993 } 994 995 if (strlen(me->name) >= XT_EXTENSION_MAXNAMELEN) { 996 fprintf(stderr, "%s: target `%s' has invalid name\n", 997 xt_params->program_name, me->name); 998 exit(1); 999 } 1000 1001 if (me->family >= NPROTO) { 1002 fprintf(stderr, 1003 "%s: BUG: target %s has invalid protocol family\n", 1004 xt_params->program_name, me->name); 1005 exit(1); 1006 } 1007 1008 if (me->real_name == NULL) 1009 me->real_name = me->name; 1010 if (me->x6_options != NULL) 1011 xtables_option_metavalidate(me->name, me->x6_options); 1012 if (me->extra_opts != NULL) 1013 xtables_check_options(me->name, me->extra_opts); 1014 1015 /* ignore not interested target */ 1016 if (me->family != afinfo->family && me->family != AF_UNSPEC) 1017 return; 1018 1019 /* place on linked list of targets pending full registration */ 1020 me->next = xtables_pending_targets; 1021 xtables_pending_targets = me; 1022} 1023 1024static void xtables_fully_register_pending_target(struct xtables_target *me) 1025{ 1026 struct xtables_target *old; 1027 int compare; 1028 1029 old = xtables_find_target(me->name, XTF_DURING_LOAD); 1030 if (old) { 1031 struct xtables_target **i; 1032 1033 compare = xtables_target_prefer(old, me); 1034 if (compare == 0) { 1035 fprintf(stderr, 1036 "%s: target `%s' already registered.\n", 1037 xt_params->program_name, me->name); 1038 exit(1); 1039 } 1040 1041 /* Now we have two (or more) options, check compatibility. */ 1042 if (compare > 0 && 1043 compatible_target_revision(old->real_name, old->revision)) 1044 return; 1045 1046 /* See if new target can be used. */ 1047 if (!compatible_target_revision(me->real_name, me->revision)) 1048 return; 1049 1050 /* Delete old one. */ 1051 for (i = &xtables_targets; *i!=old; i = &(*i)->next); 1052 *i = old->next; 1053 } 1054 1055 if (me->size != XT_ALIGN(me->size)) { 1056 fprintf(stderr, "%s: target `%s' has invalid size %u.\n", 1057 xt_params->program_name, me->name, 1058 (unsigned int)me->size); 1059 exit(1); 1060 } 1061 1062 /* Prepend to list. */ 1063 me->next = xtables_targets; 1064 xtables_targets = me; 1065 me->t = NULL; 1066 me->tflags = 0; 1067} 1068 1069void xtables_register_targets(struct xtables_target *target, unsigned int n) 1070{ 1071 do { 1072 xtables_register_target(&target[--n]); 1073 } while (n > 0); 1074} 1075 1076/** 1077 * xtables_param_act - act on condition 1078 * @status: a constant from enum xtables_exittype 1079 * 1080 * %XTF_ONLY_ONCE: print error message that option may only be used once. 1081 * @p1: module name (e.g. "mark") 1082 * @p2(...): option in conflict (e.g. "--mark") 1083 * @p3(...): condition to match on (see extensions/ for examples) 1084 * 1085 * %XTF_NO_INVERT: option does not support inversion 1086 * @p1: module name 1087 * @p2: option in conflict 1088 * @p3: condition to match on 1089 * 1090 * %XTF_BAD_VALUE: bad value for option 1091 * @p1: module name 1092 * @p2: option with which the problem occured (e.g. "--mark") 1093 * @p3: string the user passed in (e.g. "99999999999999") 1094 * 1095 * %XTF_ONE_ACTION: two mutually exclusive actions have been specified 1096 * @p1: module name 1097 * 1098 * Displays an error message and exits the program. 1099 */ 1100void xtables_param_act(unsigned int status, const char *p1, ...) 1101{ 1102 const char *p2, *p3; 1103 va_list args; 1104 bool b; 1105 1106 va_start(args, p1); 1107 1108 switch (status) { 1109 case XTF_ONLY_ONCE: 1110 p2 = va_arg(args, const char *); 1111 b = va_arg(args, unsigned int); 1112 if (!b) { 1113 va_end(args); 1114 return; 1115 } 1116 xt_params->exit_err(PARAMETER_PROBLEM, 1117 "%s: \"%s\" option may only be specified once", 1118 p1, p2); 1119 break; 1120 case XTF_NO_INVERT: 1121 p2 = va_arg(args, const char *); 1122 b = va_arg(args, unsigned int); 1123 if (!b) { 1124 va_end(args); 1125 return; 1126 } 1127 xt_params->exit_err(PARAMETER_PROBLEM, 1128 "%s: \"%s\" option cannot be inverted", p1, p2); 1129 break; 1130 case XTF_BAD_VALUE: 1131 p2 = va_arg(args, const char *); 1132 p3 = va_arg(args, const char *); 1133 xt_params->exit_err(PARAMETER_PROBLEM, 1134 "%s: Bad value for \"%s\" option: \"%s\"", 1135 p1, p2, p3); 1136 break; 1137 case XTF_ONE_ACTION: 1138 b = va_arg(args, unsigned int); 1139 if (!b) { 1140 va_end(args); 1141 return; 1142 } 1143 xt_params->exit_err(PARAMETER_PROBLEM, 1144 "%s: At most one action is possible", p1); 1145 break; 1146 default: 1147 xt_params->exit_err(status, p1, args); 1148 break; 1149 } 1150 1151 va_end(args); 1152} 1153 1154const char *xtables_ipaddr_to_numeric(const struct in_addr *addrp) 1155{ 1156 static char buf[20]; 1157 const unsigned char *bytep = (const void *)&addrp->s_addr; 1158 1159 sprintf(buf, "%u.%u.%u.%u", bytep[0], bytep[1], bytep[2], bytep[3]); 1160 return buf; 1161} 1162 1163static const char *ipaddr_to_host(const struct in_addr *addr) 1164{ 1165 struct hostent *host; 1166 1167 host = gethostbyaddr(addr, sizeof(struct in_addr), AF_INET); 1168 if (host == NULL) 1169 return NULL; 1170 1171 return host->h_name; 1172} 1173 1174static const char *ipaddr_to_network(const struct in_addr *addr) 1175{ 1176 struct netent *net; 1177 1178 if ((net = getnetbyaddr(ntohl(addr->s_addr), AF_INET)) != NULL) 1179 return net->n_name; 1180 1181 return NULL; 1182} 1183 1184const char *xtables_ipaddr_to_anyname(const struct in_addr *addr) 1185{ 1186 const char *name; 1187 1188 if ((name = ipaddr_to_host(addr)) != NULL || 1189 (name = ipaddr_to_network(addr)) != NULL) 1190 return name; 1191 1192 return xtables_ipaddr_to_numeric(addr); 1193} 1194 1195int xtables_ipmask_to_cidr(const struct in_addr *mask) 1196{ 1197 uint32_t maskaddr, bits; 1198 int i; 1199 1200 maskaddr = ntohl(mask->s_addr); 1201 /* shortcut for /32 networks */ 1202 if (maskaddr == 0xFFFFFFFFL) 1203 return 32; 1204 1205 i = 32; 1206 bits = 0xFFFFFFFEL; 1207 while (--i >= 0 && maskaddr != bits) 1208 bits <<= 1; 1209 if (i >= 0) 1210 return i; 1211 1212 /* this mask cannot be converted to CIDR notation */ 1213 return -1; 1214} 1215 1216const char *xtables_ipmask_to_numeric(const struct in_addr *mask) 1217{ 1218 static char buf[20]; 1219 uint32_t cidr; 1220 1221 cidr = xtables_ipmask_to_cidr(mask); 1222 if (cidr < 0) { 1223 /* mask was not a decent combination of 1's and 0's */ 1224 sprintf(buf, "/%s", xtables_ipaddr_to_numeric(mask)); 1225 return buf; 1226 } else if (cidr == 32) { 1227 /* we don't want to see "/32" */ 1228 return ""; 1229 } 1230 1231 sprintf(buf, "/%d", cidr); 1232 return buf; 1233} 1234 1235static struct in_addr *__numeric_to_ipaddr(const char *dotted, bool is_mask) 1236{ 1237 static struct in_addr addr; 1238 unsigned char *addrp; 1239 unsigned int onebyte; 1240 char buf[20], *p, *q; 1241 int i; 1242 1243 /* copy dotted string, because we need to modify it */ 1244 strncpy(buf, dotted, sizeof(buf) - 1); 1245 buf[sizeof(buf) - 1] = '\0'; 1246 addrp = (void *)&addr.s_addr; 1247 1248 p = buf; 1249 for (i = 0; i < 3; ++i) { 1250 if ((q = strchr(p, '.')) == NULL) { 1251 if (is_mask) 1252 return NULL; 1253 1254 /* autocomplete, this is a network address */ 1255 if (!xtables_strtoui(p, NULL, &onebyte, 0, UINT8_MAX)) 1256 return NULL; 1257 1258 addrp[i] = onebyte; 1259 while (i < 3) 1260 addrp[++i] = 0; 1261 1262 return &addr; 1263 } 1264 1265 *q = '\0'; 1266 if (!xtables_strtoui(p, NULL, &onebyte, 0, UINT8_MAX)) 1267 return NULL; 1268 1269 addrp[i] = onebyte; 1270 p = q + 1; 1271 } 1272 1273 /* we have checked 3 bytes, now we check the last one */ 1274 if (!xtables_strtoui(p, NULL, &onebyte, 0, UINT8_MAX)) 1275 return NULL; 1276 1277 addrp[3] = onebyte; 1278 return &addr; 1279} 1280 1281struct in_addr *xtables_numeric_to_ipaddr(const char *dotted) 1282{ 1283 return __numeric_to_ipaddr(dotted, false); 1284} 1285 1286struct in_addr *xtables_numeric_to_ipmask(const char *dotted) 1287{ 1288 return __numeric_to_ipaddr(dotted, true); 1289} 1290 1291static struct in_addr *network_to_ipaddr(const char *name) 1292{ 1293 static struct in_addr addr; 1294 struct netent *net; 1295 1296 if ((net = getnetbyname(name)) != NULL) { 1297 if (net->n_addrtype != AF_INET) 1298 return NULL; 1299 addr.s_addr = htonl(net->n_net); 1300 return &addr; 1301 } 1302 1303 return NULL; 1304} 1305 1306static struct in_addr *host_to_ipaddr(const char *name, unsigned int *naddr) 1307{ 1308 struct hostent *host; 1309 struct in_addr *addr; 1310 unsigned int i; 1311 1312 *naddr = 0; 1313 if ((host = gethostbyname(name)) != NULL) { 1314 if (host->h_addrtype != AF_INET || 1315 host->h_length != sizeof(struct in_addr)) 1316 return NULL; 1317 1318 while (host->h_addr_list[*naddr] != NULL) 1319 ++*naddr; 1320 addr = xtables_calloc(*naddr, sizeof(struct in_addr)); 1321 for (i = 0; i < *naddr; i++) 1322 memcpy(&addr[i], host->h_addr_list[i], 1323 sizeof(struct in_addr)); 1324 return addr; 1325 } 1326 1327 return NULL; 1328} 1329 1330static struct in_addr * 1331ipparse_hostnetwork(const char *name, unsigned int *naddrs) 1332{ 1333 struct in_addr *addrptmp, *addrp; 1334 1335 if ((addrptmp = xtables_numeric_to_ipaddr(name)) != NULL || 1336 (addrptmp = network_to_ipaddr(name)) != NULL) { 1337 addrp = xtables_malloc(sizeof(struct in_addr)); 1338 memcpy(addrp, addrptmp, sizeof(*addrp)); 1339 *naddrs = 1; 1340 return addrp; 1341 } 1342 if ((addrptmp = host_to_ipaddr(name, naddrs)) != NULL) 1343 return addrptmp; 1344 1345 xt_params->exit_err(PARAMETER_PROBLEM, "host/network `%s' not found", name); 1346} 1347 1348static struct in_addr *parse_ipmask(const char *mask) 1349{ 1350 static struct in_addr maskaddr; 1351 struct in_addr *addrp; 1352 unsigned int bits; 1353 1354 if (mask == NULL) { 1355 /* no mask at all defaults to 32 bits */ 1356 maskaddr.s_addr = 0xFFFFFFFF; 1357 return &maskaddr; 1358 } 1359 if ((addrp = xtables_numeric_to_ipmask(mask)) != NULL) 1360 /* dotted_to_addr already returns a network byte order addr */ 1361 return addrp; 1362 if (!xtables_strtoui(mask, NULL, &bits, 0, 32)) 1363 xt_params->exit_err(PARAMETER_PROBLEM, 1364 "invalid mask `%s' specified", mask); 1365 if (bits != 0) { 1366 maskaddr.s_addr = htonl(0xFFFFFFFF << (32 - bits)); 1367 return &maskaddr; 1368 } 1369 1370 maskaddr.s_addr = 0U; 1371 return &maskaddr; 1372} 1373 1374void xtables_ipparse_multiple(const char *name, struct in_addr **addrpp, 1375 struct in_addr **maskpp, unsigned int *naddrs) 1376{ 1377 struct in_addr *addrp; 1378 char buf[256], *p, *next; 1379 unsigned int len, i, j, n, count = 1; 1380 const char *loop = name; 1381 1382 while ((loop = strchr(loop, ',')) != NULL) { 1383 ++count; 1384 ++loop; /* skip ',' */ 1385 } 1386 1387 *addrpp = xtables_malloc(sizeof(struct in_addr) * count); 1388 *maskpp = xtables_malloc(sizeof(struct in_addr) * count); 1389 1390 loop = name; 1391 1392 for (i = 0; i < count; ++i) { 1393 while (isspace(*loop)) 1394 ++loop; 1395 next = strchr(loop, ','); 1396 if (next != NULL) 1397 len = next - loop; 1398 else 1399 len = strlen(loop); 1400 if (len > sizeof(buf) - 1) 1401 xt_params->exit_err(PARAMETER_PROBLEM, 1402 "Hostname too long"); 1403 1404 strncpy(buf, loop, len); 1405 buf[len] = '\0'; 1406 if ((p = strrchr(buf, '/')) != NULL) { 1407 *p = '\0'; 1408 addrp = parse_ipmask(p + 1); 1409 } else { 1410 addrp = parse_ipmask(NULL); 1411 } 1412 memcpy(*maskpp + i, addrp, sizeof(*addrp)); 1413 1414 /* if a null mask is given, the name is ignored, like in "any/0" */ 1415 if ((*maskpp + i)->s_addr == 0) 1416 /* 1417 * A bit pointless to process multiple addresses 1418 * in this case... 1419 */ 1420 strcpy(buf, "0.0.0.0"); 1421 1422 addrp = ipparse_hostnetwork(buf, &n); 1423 if (n > 1) { 1424 count += n - 1; 1425 *addrpp = xtables_realloc(*addrpp, 1426 sizeof(struct in_addr) * count); 1427 *maskpp = xtables_realloc(*maskpp, 1428 sizeof(struct in_addr) * count); 1429 for (j = 0; j < n; ++j) 1430 /* for each new addr */ 1431 memcpy(*addrpp + i + j, addrp + j, 1432 sizeof(*addrp)); 1433 for (j = 1; j < n; ++j) 1434 /* for each new mask */ 1435 memcpy(*maskpp + i + j, *maskpp + i, 1436 sizeof(*addrp)); 1437 i += n - 1; 1438 } else { 1439 memcpy(*addrpp + i, addrp, sizeof(*addrp)); 1440 } 1441 /* free what ipparse_hostnetwork had allocated: */ 1442 free(addrp); 1443 if (next == NULL) 1444 break; 1445 loop = next + 1; 1446 } 1447 *naddrs = count; 1448 for (i = 0; i < count; ++i) 1449 (*addrpp+i)->s_addr &= (*maskpp+i)->s_addr; 1450} 1451 1452 1453/** 1454 * xtables_ipparse_any - transform arbitrary name to in_addr 1455 * 1456 * Possible inputs (pseudo regex): 1457 * m{^($hostname|$networkname|$ipaddr)(/$mask)?} 1458 * "1.2.3.4/5", "1.2.3.4", "hostname", "networkname" 1459 */ 1460void xtables_ipparse_any(const char *name, struct in_addr **addrpp, 1461 struct in_addr *maskp, unsigned int *naddrs) 1462{ 1463 unsigned int i, j, k, n; 1464 struct in_addr *addrp; 1465 char buf[256], *p; 1466 1467 strncpy(buf, name, sizeof(buf) - 1); 1468 buf[sizeof(buf) - 1] = '\0'; 1469 if ((p = strrchr(buf, '/')) != NULL) { 1470 *p = '\0'; 1471 addrp = parse_ipmask(p + 1); 1472 } else { 1473 addrp = parse_ipmask(NULL); 1474 } 1475 memcpy(maskp, addrp, sizeof(*maskp)); 1476 1477 /* if a null mask is given, the name is ignored, like in "any/0" */ 1478 if (maskp->s_addr == 0U) 1479 strcpy(buf, "0.0.0.0"); 1480 1481 addrp = *addrpp = ipparse_hostnetwork(buf, naddrs); 1482 n = *naddrs; 1483 for (i = 0, j = 0; i < n; ++i) { 1484 addrp[j++].s_addr &= maskp->s_addr; 1485 for (k = 0; k < j - 1; ++k) 1486 if (addrp[k].s_addr == addrp[j-1].s_addr) { 1487 /* 1488 * Nuke the dup by copying an address from the 1489 * tail here, and check the current position 1490 * again (--j). 1491 */ 1492 memcpy(&addrp[--j], &addrp[--*naddrs], 1493 sizeof(struct in_addr)); 1494 break; 1495 } 1496 } 1497} 1498 1499const char *xtables_ip6addr_to_numeric(const struct in6_addr *addrp) 1500{ 1501 /* 0000:0000:0000:0000:0000:0000:000.000.000.000 1502 * 0000:0000:0000:0000:0000:0000:0000:0000 */ 1503 static char buf[50+1]; 1504 return inet_ntop(AF_INET6, addrp, buf, sizeof(buf)); 1505} 1506 1507static const char *ip6addr_to_host(const struct in6_addr *addr) 1508{ 1509 static char hostname[NI_MAXHOST]; 1510 struct sockaddr_in6 saddr; 1511 int err; 1512 1513 memset(&saddr, 0, sizeof(struct sockaddr_in6)); 1514 memcpy(&saddr.sin6_addr, addr, sizeof(*addr)); 1515 saddr.sin6_family = AF_INET6; 1516 1517 err = getnameinfo((const void *)&saddr, sizeof(struct sockaddr_in6), 1518 hostname, sizeof(hostname) - 1, NULL, 0, 0); 1519 if (err != 0) { 1520#ifdef DEBUG 1521 fprintf(stderr,"IP2Name: %s\n",gai_strerror(err)); 1522#endif 1523 return NULL; 1524 } 1525 1526#ifdef DEBUG 1527 fprintf (stderr, "\naddr2host: %s\n", hostname); 1528#endif 1529 return hostname; 1530} 1531 1532const char *xtables_ip6addr_to_anyname(const struct in6_addr *addr) 1533{ 1534 const char *name; 1535 1536 if ((name = ip6addr_to_host(addr)) != NULL) 1537 return name; 1538 1539 return xtables_ip6addr_to_numeric(addr); 1540} 1541 1542int xtables_ip6mask_to_cidr(const struct in6_addr *k) 1543{ 1544 unsigned int bits = 0; 1545 uint32_t a, b, c, d; 1546 1547 a = ntohl(k->s6_addr32[0]); 1548 b = ntohl(k->s6_addr32[1]); 1549 c = ntohl(k->s6_addr32[2]); 1550 d = ntohl(k->s6_addr32[3]); 1551 while (a & 0x80000000U) { 1552 ++bits; 1553 a <<= 1; 1554 a |= (b >> 31) & 1; 1555 b <<= 1; 1556 b |= (c >> 31) & 1; 1557 c <<= 1; 1558 c |= (d >> 31) & 1; 1559 d <<= 1; 1560 } 1561 if (a != 0 || b != 0 || c != 0 || d != 0) 1562 return -1; 1563 return bits; 1564} 1565 1566const char *xtables_ip6mask_to_numeric(const struct in6_addr *addrp) 1567{ 1568 static char buf[50+2]; 1569 int l = xtables_ip6mask_to_cidr(addrp); 1570 1571 if (l == -1) { 1572 strcpy(buf, "/"); 1573 strcat(buf, xtables_ip6addr_to_numeric(addrp)); 1574 return buf; 1575 } 1576 sprintf(buf, "/%d", l); 1577 return buf; 1578} 1579 1580struct in6_addr *xtables_numeric_to_ip6addr(const char *num) 1581{ 1582 static struct in6_addr ap; 1583 int err; 1584 1585 if ((err = inet_pton(AF_INET6, num, &ap)) == 1) 1586 return ≈ 1587#ifdef DEBUG 1588 fprintf(stderr, "\nnumeric2addr: %d\n", err); 1589#endif 1590 return NULL; 1591} 1592 1593static struct in6_addr * 1594host_to_ip6addr(const char *name, unsigned int *naddr) 1595{ 1596 struct in6_addr *addr; 1597 struct addrinfo hints; 1598 struct addrinfo *res, *p; 1599 int err; 1600 unsigned int i; 1601 1602 memset(&hints, 0, sizeof(hints)); 1603 hints.ai_flags = AI_CANONNAME; 1604 hints.ai_family = AF_INET6; 1605 hints.ai_socktype = SOCK_RAW; 1606 1607 *naddr = 0; 1608 if ((err = getaddrinfo(name, NULL, &hints, &res)) != 0) { 1609#ifdef DEBUG 1610 fprintf(stderr,"Name2IP: %s\n",gai_strerror(err)); 1611#endif 1612 return NULL; 1613 } else { 1614 /* Find length of address chain */ 1615 for (p = res; p != NULL; p = p->ai_next) 1616 ++*naddr; 1617#ifdef DEBUG 1618 fprintf(stderr, "resolved: len=%d %s ", res->ai_addrlen, 1619 xtables_ip6addr_to_numeric(&((struct sockaddr_in6 *)res->ai_addr)->sin6_addr)); 1620#endif 1621 /* Copy each element of the address chain */ 1622 addr = xtables_calloc(*naddr, sizeof(struct in6_addr)); 1623 for (i = 0, p = res; p != NULL; p = p->ai_next) 1624 memcpy(&addr[i++], 1625 &((const struct sockaddr_in6 *)p->ai_addr)->sin6_addr, 1626 sizeof(struct in6_addr)); 1627 freeaddrinfo(res); 1628 return addr; 1629 } 1630 1631 return NULL; 1632} 1633 1634static struct in6_addr *network_to_ip6addr(const char *name) 1635{ 1636 /* abort();*/ 1637 /* TODO: not implemented yet, but the exception breaks the 1638 * name resolvation */ 1639 return NULL; 1640} 1641 1642static struct in6_addr * 1643ip6parse_hostnetwork(const char *name, unsigned int *naddrs) 1644{ 1645 struct in6_addr *addrp, *addrptmp; 1646 1647 if ((addrptmp = xtables_numeric_to_ip6addr(name)) != NULL || 1648 (addrptmp = network_to_ip6addr(name)) != NULL) { 1649 addrp = xtables_malloc(sizeof(struct in6_addr)); 1650 memcpy(addrp, addrptmp, sizeof(*addrp)); 1651 *naddrs = 1; 1652 return addrp; 1653 } 1654 if ((addrp = host_to_ip6addr(name, naddrs)) != NULL) 1655 return addrp; 1656 1657 xt_params->exit_err(PARAMETER_PROBLEM, "host/network `%s' not found", name); 1658} 1659 1660static struct in6_addr *parse_ip6mask(char *mask) 1661{ 1662 static struct in6_addr maskaddr; 1663 struct in6_addr *addrp; 1664 unsigned int bits; 1665 1666 if (mask == NULL) { 1667 /* no mask at all defaults to 128 bits */ 1668 memset(&maskaddr, 0xff, sizeof maskaddr); 1669 return &maskaddr; 1670 } 1671 if ((addrp = xtables_numeric_to_ip6addr(mask)) != NULL) 1672 return addrp; 1673 if (!xtables_strtoui(mask, NULL, &bits, 0, 128)) 1674 xt_params->exit_err(PARAMETER_PROBLEM, 1675 "invalid mask `%s' specified", mask); 1676 if (bits != 0) { 1677 char *p = (void *)&maskaddr; 1678 memset(p, 0xff, bits / 8); 1679 memset(p + (bits / 8) + 1, 0, (128 - bits) / 8); 1680 p[bits/8] = 0xff << (8 - (bits & 7)); 1681 return &maskaddr; 1682 } 1683 1684 memset(&maskaddr, 0, sizeof(maskaddr)); 1685 return &maskaddr; 1686} 1687 1688void 1689xtables_ip6parse_multiple(const char *name, struct in6_addr **addrpp, 1690 struct in6_addr **maskpp, unsigned int *naddrs) 1691{ 1692 static const struct in6_addr zero_addr; 1693 struct in6_addr *addrp; 1694 char buf[256], *p, *next; 1695 unsigned int len, i, j, n, count = 1; 1696 const char *loop = name; 1697 1698 while ((loop = strchr(loop, ',')) != NULL) { 1699 ++count; 1700 ++loop; /* skip ',' */ 1701 } 1702 1703 *addrpp = xtables_malloc(sizeof(struct in6_addr) * count); 1704 *maskpp = xtables_malloc(sizeof(struct in6_addr) * count); 1705 1706 loop = name; 1707 1708 for (i = 0; i < count /*NB: count can grow*/; ++i) { 1709 while (isspace(*loop)) 1710 ++loop; 1711 next = strchr(loop, ','); 1712 if (next != NULL) 1713 len = next - loop; 1714 else 1715 len = strlen(loop); 1716 if (len > sizeof(buf) - 1) 1717 xt_params->exit_err(PARAMETER_PROBLEM, 1718 "Hostname too long"); 1719 1720 strncpy(buf, loop, len); 1721 buf[len] = '\0'; 1722 if ((p = strrchr(buf, '/')) != NULL) { 1723 *p = '\0'; 1724 addrp = parse_ip6mask(p + 1); 1725 } else { 1726 addrp = parse_ip6mask(NULL); 1727 } 1728 memcpy(*maskpp + i, addrp, sizeof(*addrp)); 1729 1730 /* if a null mask is given, the name is ignored, like in "any/0" */ 1731 if (memcmp(*maskpp + i, &zero_addr, sizeof(zero_addr)) == 0) 1732 strcpy(buf, "::"); 1733 1734 addrp = ip6parse_hostnetwork(buf, &n); 1735 if (n > 1) { 1736 count += n - 1; 1737 *addrpp = xtables_realloc(*addrpp, 1738 sizeof(struct in6_addr) * count); 1739 *maskpp = xtables_realloc(*maskpp, 1740 sizeof(struct in6_addr) * count); 1741 for (j = 0; j < n; ++j) 1742 /* for each new addr */ 1743 memcpy(*addrpp + i + j, addrp + j, 1744 sizeof(*addrp)); 1745 for (j = 1; j < n; ++j) 1746 /* for each new mask */ 1747 memcpy(*maskpp + i + j, *maskpp + i, 1748 sizeof(*addrp)); 1749 i += n - 1; 1750 } else { 1751 memcpy(*addrpp + i, addrp, sizeof(*addrp)); 1752 } 1753 /* free what ip6parse_hostnetwork had allocated: */ 1754 free(addrp); 1755 if (next == NULL) 1756 break; 1757 loop = next + 1; 1758 } 1759 *naddrs = count; 1760 for (i = 0; i < count; ++i) 1761 for (j = 0; j < 4; ++j) 1762 (*addrpp+i)->s6_addr32[j] &= (*maskpp+i)->s6_addr32[j]; 1763} 1764 1765void xtables_ip6parse_any(const char *name, struct in6_addr **addrpp, 1766 struct in6_addr *maskp, unsigned int *naddrs) 1767{ 1768 static const struct in6_addr zero_addr; 1769 struct in6_addr *addrp; 1770 unsigned int i, j, k, n; 1771 char buf[256], *p; 1772 1773 strncpy(buf, name, sizeof(buf) - 1); 1774 buf[sizeof(buf)-1] = '\0'; 1775 if ((p = strrchr(buf, '/')) != NULL) { 1776 *p = '\0'; 1777 addrp = parse_ip6mask(p + 1); 1778 } else { 1779 addrp = parse_ip6mask(NULL); 1780 } 1781 memcpy(maskp, addrp, sizeof(*maskp)); 1782 1783 /* if a null mask is given, the name is ignored, like in "any/0" */ 1784 if (memcmp(maskp, &zero_addr, sizeof(zero_addr)) == 0) 1785 strcpy(buf, "::"); 1786 1787 addrp = *addrpp = ip6parse_hostnetwork(buf, naddrs); 1788 n = *naddrs; 1789 for (i = 0, j = 0; i < n; ++i) { 1790 for (k = 0; k < 4; ++k) 1791 addrp[j].s6_addr32[k] &= maskp->s6_addr32[k]; 1792 ++j; 1793 for (k = 0; k < j - 1; ++k) 1794 if (IN6_ARE_ADDR_EQUAL(&addrp[k], &addrp[j - 1])) { 1795 /* 1796 * Nuke the dup by copying an address from the 1797 * tail here, and check the current position 1798 * again (--j). 1799 */ 1800 memcpy(&addrp[--j], &addrp[--*naddrs], 1801 sizeof(struct in_addr)); 1802 break; 1803 } 1804 } 1805} 1806 1807void xtables_save_string(const char *value) 1808{ 1809 static const char no_quote_chars[] = "_-0123456789" 1810 "abcdefghijklmnopqrstuvwxyz" 1811 "ABCDEFGHIJKLMNOPQRSTUVWXYZ"; 1812 static const char escape_chars[] = "\"\\'"; 1813 size_t length; 1814 const char *p; 1815 1816 length = strspn(value, no_quote_chars); 1817 if (length > 0 && value[length] == 0) { 1818 /* no quoting required */ 1819 putchar(' '); 1820 fputs(value, stdout); 1821 } else { 1822 /* there is at least one dangerous character in the 1823 value, which we have to quote. Write double quotes 1824 around the value and escape special characters with 1825 a backslash */ 1826 printf(" \""); 1827 1828 for (p = strpbrk(value, escape_chars); p != NULL; 1829 p = strpbrk(value, escape_chars)) { 1830 if (p > value) 1831 fwrite(value, 1, p - value, stdout); 1832 putchar('\\'); 1833 putchar(*p); 1834 value = p + 1; 1835 } 1836 1837 /* print the rest and finish the double quoted 1838 string */ 1839 fputs(value, stdout); 1840 putchar('\"'); 1841 } 1842} 1843 1844const struct xtables_pprot xtables_chain_protos[] = { 1845 {"tcp", IPPROTO_TCP}, 1846 {"sctp", IPPROTO_SCTP}, 1847 {"udp", IPPROTO_UDP}, 1848 {"udplite", IPPROTO_UDPLITE}, 1849 {"icmp", IPPROTO_ICMP}, 1850 {"icmpv6", IPPROTO_ICMPV6}, 1851 {"ipv6-icmp", IPPROTO_ICMPV6}, 1852 {"esp", IPPROTO_ESP}, 1853 {"ah", IPPROTO_AH}, 1854 {"ipv6-mh", IPPROTO_MH}, 1855 {"mh", IPPROTO_MH}, 1856 {"all", 0}, 1857 {NULL}, 1858}; 1859 1860uint16_t 1861xtables_parse_protocol(const char *s) 1862{ 1863 const struct protoent *pent; 1864 unsigned int proto, i; 1865 1866 if (xtables_strtoui(s, NULL, &proto, 0, UINT8_MAX)) 1867 return proto; 1868 1869 /* first deal with the special case of 'all' to prevent 1870 * people from being able to redefine 'all' in nsswitch 1871 * and/or provoke expensive [not working] ldap/nis/... 1872 * lookups */ 1873 if (strcmp(s, "all") == 0) 1874 return 0; 1875 1876 pent = getprotobyname(s); 1877 if (pent != NULL) 1878 return pent->p_proto; 1879 1880 for (i = 0; i < ARRAY_SIZE(xtables_chain_protos); ++i) { 1881 if (xtables_chain_protos[i].name == NULL) 1882 continue; 1883 if (strcmp(s, xtables_chain_protos[i].name) == 0) 1884 return xtables_chain_protos[i].num; 1885 } 1886 xt_params->exit_err(PARAMETER_PROBLEM, 1887 "unknown protocol \"%s\" specified", s); 1888 return -1; 1889} 1890 1891int kernel_version; 1892 1893void get_kernel_version(void) 1894{ 1895 static struct utsname uts; 1896 int x = 0, y = 0, z = 0; 1897 1898 if (uname(&uts) == -1) { 1899 fprintf(stderr, "Unable to retrieve kernel version.\n"); 1900 xtables_free_opts(1); 1901 exit(1); 1902 } 1903 1904 sscanf(uts.release, "%d.%d.%d", &x, &y, &z); 1905 kernel_version = LINUX_VERSION(x, y, z); 1906} 1907