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