xtables.c revision e44ea7faa17c10c68f14f5338a7cc6e3291a0ce7
15208806f2708f761e97e62550561e3164b541770Yasuyuki KOZAKAI/*
25208806f2708f761e97e62550561e3164b541770Yasuyuki KOZAKAI * (C) 2000-2006 by the netfilter coreteam <coreteam@netfilter.org>:
35208806f2708f761e97e62550561e3164b541770Yasuyuki KOZAKAI *
45208806f2708f761e97e62550561e3164b541770Yasuyuki KOZAKAI *	This program is free software; you can redistribute it and/or modify
55208806f2708f761e97e62550561e3164b541770Yasuyuki KOZAKAI *	it under the terms of the GNU General Public License as published by
65208806f2708f761e97e62550561e3164b541770Yasuyuki KOZAKAI *	the Free Software Foundation; either version 2 of the License, or
75208806f2708f761e97e62550561e3164b541770Yasuyuki KOZAKAI *	(at your option) any later version.
85208806f2708f761e97e62550561e3164b541770Yasuyuki KOZAKAI *
95208806f2708f761e97e62550561e3164b541770Yasuyuki KOZAKAI *	This program is distributed in the hope that it will be useful,
105208806f2708f761e97e62550561e3164b541770Yasuyuki KOZAKAI *	but WITHOUT ANY WARRANTY; without even the implied warranty of
115208806f2708f761e97e62550561e3164b541770Yasuyuki KOZAKAI *	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
125208806f2708f761e97e62550561e3164b541770Yasuyuki KOZAKAI *	GNU General Public License for more details.
135208806f2708f761e97e62550561e3164b541770Yasuyuki KOZAKAI *
145208806f2708f761e97e62550561e3164b541770Yasuyuki KOZAKAI *	You should have received a copy of the GNU General Public License
155208806f2708f761e97e62550561e3164b541770Yasuyuki KOZAKAI *	along with this program; if not, write to the Free Software
165208806f2708f761e97e62550561e3164b541770Yasuyuki KOZAKAI *	Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
175208806f2708f761e97e62550561e3164b541770Yasuyuki KOZAKAI */
185208806f2708f761e97e62550561e3164b541770Yasuyuki KOZAKAI
193dfa4488b032fc32aaf2470f48ac1fc3a534794fYasuyuki KOZAKAI#include <errno.h>
200b82e8e81e887843011c8771f70d2302901f7e5eYasuyuki KOZAKAI#include <fcntl.h>
2104f8c54dc52e19096d31d94593bd1040716afe4dYasuyuki KOZAKAI#include <netdb.h>
22aafd269675fc45bac6340027c866ea6073643c3bJan Engelhardt#include <stdarg.h>
23cd9e7aa106e80c44bd526af74b616701b0772d05Jan Engelhardt#include <stdbool.h>
243dfa4488b032fc32aaf2470f48ac1fc3a534794fYasuyuki KOZAKAI#include <stdio.h>
253dfa4488b032fc32aaf2470f48ac1fc3a534794fYasuyuki KOZAKAI#include <stdlib.h>
260b82e8e81e887843011c8771f70d2302901f7e5eYasuyuki KOZAKAI#include <string.h>
270b82e8e81e887843011c8771f70d2302901f7e5eYasuyuki KOZAKAI#include <unistd.h>
280d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI#include <sys/socket.h>
290b82e8e81e887843011c8771f70d2302901f7e5eYasuyuki KOZAKAI#include <sys/stat.h>
300b82e8e81e887843011c8771f70d2302901f7e5eYasuyuki KOZAKAI#include <sys/types.h>
310b82e8e81e887843011c8771f70d2302901f7e5eYasuyuki KOZAKAI#include <sys/wait.h>
3208b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt#include <arpa/inet.h>
333dfa4488b032fc32aaf2470f48ac1fc3a534794fYasuyuki KOZAKAI
345208806f2708f761e97e62550561e3164b541770Yasuyuki KOZAKAI#include <xtables.h>
35ef18e8147903885708d1c264904129af4fb636d6Jan Engelhardt#include <libiptc/libxtc.h>
363dfa4488b032fc32aaf2470f48ac1fc3a534794fYasuyuki KOZAKAI
375a26b5fd7bf11ca93d54fe7dc24b3423fb7d89b2Mike Frysinger#ifndef NO_SHARED_LIBS
385a26b5fd7bf11ca93d54fe7dc24b3423fb7d89b2Mike Frysinger#include <dlfcn.h>
395a26b5fd7bf11ca93d54fe7dc24b3423fb7d89b2Mike Frysinger#endif
405a26b5fd7bf11ca93d54fe7dc24b3423fb7d89b2Mike Frysinger
410d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI#define NPROTO	255
420d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI
430b82e8e81e887843011c8771f70d2302901f7e5eYasuyuki KOZAKAI#ifndef PROC_SYS_MODPROBE
440b82e8e81e887843011c8771f70d2302901f7e5eYasuyuki KOZAKAI#define PROC_SYS_MODPROBE "/proc/sys/kernel/modprobe"
450b82e8e81e887843011c8771f70d2302901f7e5eYasuyuki KOZAKAI#endif
460b82e8e81e887843011c8771f70d2302901f7e5eYasuyuki KOZAKAI
47dacafa55379fd98212031d8c559096c91d7ce93bJan Engelhardt/**
48dacafa55379fd98212031d8c559096c91d7ce93bJan Engelhardt * Program will set this to its own name.
49dacafa55379fd98212031d8c559096c91d7ce93bJan Engelhardt */
50dacafa55379fd98212031d8c559096c91d7ce93bJan Engelhardtconst char *xtables_program_name;
51dacafa55379fd98212031d8c559096c91d7ce93bJan Engelhardt
5239bf9c8214d3073a496a8a1eff91046a8d6fbbdfJan Engelhardt/* Search path for Xtables .so files */
5339bf9c8214d3073a496a8a1eff91046a8d6fbbdfJan Engelhardtstatic const char *xtables_libdir;
540d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI
550b82e8e81e887843011c8771f70d2302901f7e5eYasuyuki KOZAKAI/* the path to command to load kernel module */
56c021c3ce7b1583eb5dd71b10ac3d8ab3cd36beaaJan Engelhardtconst char *xtables_modprobe_program;
570b82e8e81e887843011c8771f70d2302901f7e5eYasuyuki KOZAKAI
580d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI/* Keeping track of external matches and targets: linked lists.  */
590d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAIstruct xtables_match *xtables_matches;
600d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAIstruct xtables_target *xtables_targets;
610d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI
6239bf9c8214d3073a496a8a1eff91046a8d6fbbdfJan Engelhardtvoid xtables_init(void)
6339bf9c8214d3073a496a8a1eff91046a8d6fbbdfJan Engelhardt{
6439bf9c8214d3073a496a8a1eff91046a8d6fbbdfJan Engelhardt	xtables_libdir = getenv("XTABLES_LIBDIR");
6539bf9c8214d3073a496a8a1eff91046a8d6fbbdfJan Engelhardt	if (xtables_libdir != NULL)
6639bf9c8214d3073a496a8a1eff91046a8d6fbbdfJan Engelhardt		return;
6739bf9c8214d3073a496a8a1eff91046a8d6fbbdfJan Engelhardt	xtables_libdir = getenv("IPTABLES_LIB_DIR");
6839bf9c8214d3073a496a8a1eff91046a8d6fbbdfJan Engelhardt	if (xtables_libdir != NULL) {
6939bf9c8214d3073a496a8a1eff91046a8d6fbbdfJan Engelhardt		fprintf(stderr, "IPTABLES_LIB_DIR is deprecated, "
7039bf9c8214d3073a496a8a1eff91046a8d6fbbdfJan Engelhardt		        "use XTABLES_LIBDIR.\n");
7139bf9c8214d3073a496a8a1eff91046a8d6fbbdfJan Engelhardt		return;
7239bf9c8214d3073a496a8a1eff91046a8d6fbbdfJan Engelhardt	}
7339bf9c8214d3073a496a8a1eff91046a8d6fbbdfJan Engelhardt	xtables_libdir = XTABLES_LIBDIR;
7439bf9c8214d3073a496a8a1eff91046a8d6fbbdfJan Engelhardt}
7539bf9c8214d3073a496a8a1eff91046a8d6fbbdfJan Engelhardt
76630ef48037f3602333addfdb53789c9c6a4bb4c8Jan Engelhardt/**
77630ef48037f3602333addfdb53789c9c6a4bb4c8Jan Engelhardt * xtables_*alloc - wrappers that exit on failure
78630ef48037f3602333addfdb53789c9c6a4bb4c8Jan Engelhardt */
79630ef48037f3602333addfdb53789c9c6a4bb4c8Jan Engelhardtvoid *xtables_calloc(size_t count, size_t size)
803dfa4488b032fc32aaf2470f48ac1fc3a534794fYasuyuki KOZAKAI{
813dfa4488b032fc32aaf2470f48ac1fc3a534794fYasuyuki KOZAKAI	void *p;
823dfa4488b032fc32aaf2470f48ac1fc3a534794fYasuyuki KOZAKAI
833dfa4488b032fc32aaf2470f48ac1fc3a534794fYasuyuki KOZAKAI	if ((p = calloc(count, size)) == NULL) {
843dfa4488b032fc32aaf2470f48ac1fc3a534794fYasuyuki KOZAKAI		perror("ip[6]tables: calloc failed");
853dfa4488b032fc32aaf2470f48ac1fc3a534794fYasuyuki KOZAKAI		exit(1);
863dfa4488b032fc32aaf2470f48ac1fc3a534794fYasuyuki KOZAKAI	}
873dfa4488b032fc32aaf2470f48ac1fc3a534794fYasuyuki KOZAKAI
883dfa4488b032fc32aaf2470f48ac1fc3a534794fYasuyuki KOZAKAI	return p;
893dfa4488b032fc32aaf2470f48ac1fc3a534794fYasuyuki KOZAKAI}
903dfa4488b032fc32aaf2470f48ac1fc3a534794fYasuyuki KOZAKAI
91630ef48037f3602333addfdb53789c9c6a4bb4c8Jan Engelhardtvoid *xtables_malloc(size_t size)
923dfa4488b032fc32aaf2470f48ac1fc3a534794fYasuyuki KOZAKAI{
933dfa4488b032fc32aaf2470f48ac1fc3a534794fYasuyuki KOZAKAI	void *p;
943dfa4488b032fc32aaf2470f48ac1fc3a534794fYasuyuki KOZAKAI
953dfa4488b032fc32aaf2470f48ac1fc3a534794fYasuyuki KOZAKAI	if ((p = malloc(size)) == NULL) {
963dfa4488b032fc32aaf2470f48ac1fc3a534794fYasuyuki KOZAKAI		perror("ip[6]tables: malloc failed");
973dfa4488b032fc32aaf2470f48ac1fc3a534794fYasuyuki KOZAKAI		exit(1);
983dfa4488b032fc32aaf2470f48ac1fc3a534794fYasuyuki KOZAKAI	}
993dfa4488b032fc32aaf2470f48ac1fc3a534794fYasuyuki KOZAKAI
1003dfa4488b032fc32aaf2470f48ac1fc3a534794fYasuyuki KOZAKAI	return p;
1013dfa4488b032fc32aaf2470f48ac1fc3a534794fYasuyuki KOZAKAI}
1020b82e8e81e887843011c8771f70d2302901f7e5eYasuyuki KOZAKAI
1030b82e8e81e887843011c8771f70d2302901f7e5eYasuyuki KOZAKAIstatic char *get_modprobe(void)
1040b82e8e81e887843011c8771f70d2302901f7e5eYasuyuki KOZAKAI{
1050b82e8e81e887843011c8771f70d2302901f7e5eYasuyuki KOZAKAI	int procfile;
1060b82e8e81e887843011c8771f70d2302901f7e5eYasuyuki KOZAKAI	char *ret;
1070b82e8e81e887843011c8771f70d2302901f7e5eYasuyuki KOZAKAI
1080b82e8e81e887843011c8771f70d2302901f7e5eYasuyuki KOZAKAI#define PROCFILE_BUFSIZ	1024
1090b82e8e81e887843011c8771f70d2302901f7e5eYasuyuki KOZAKAI	procfile = open(PROC_SYS_MODPROBE, O_RDONLY);
1100b82e8e81e887843011c8771f70d2302901f7e5eYasuyuki KOZAKAI	if (procfile < 0)
1110b82e8e81e887843011c8771f70d2302901f7e5eYasuyuki KOZAKAI		return NULL;
1120b82e8e81e887843011c8771f70d2302901f7e5eYasuyuki KOZAKAI
1130b82e8e81e887843011c8771f70d2302901f7e5eYasuyuki KOZAKAI	ret = (char *) malloc(PROCFILE_BUFSIZ);
1140b82e8e81e887843011c8771f70d2302901f7e5eYasuyuki KOZAKAI	if (ret) {
1150b82e8e81e887843011c8771f70d2302901f7e5eYasuyuki KOZAKAI		memset(ret, 0, PROCFILE_BUFSIZ);
1160b82e8e81e887843011c8771f70d2302901f7e5eYasuyuki KOZAKAI		switch (read(procfile, ret, PROCFILE_BUFSIZ)) {
1170b82e8e81e887843011c8771f70d2302901f7e5eYasuyuki KOZAKAI		case -1: goto fail;
1180b82e8e81e887843011c8771f70d2302901f7e5eYasuyuki KOZAKAI		case PROCFILE_BUFSIZ: goto fail; /* Partial read.  Wierd */
1190b82e8e81e887843011c8771f70d2302901f7e5eYasuyuki KOZAKAI		}
1200b82e8e81e887843011c8771f70d2302901f7e5eYasuyuki KOZAKAI		if (ret[strlen(ret)-1]=='\n')
1210b82e8e81e887843011c8771f70d2302901f7e5eYasuyuki KOZAKAI			ret[strlen(ret)-1]=0;
1220b82e8e81e887843011c8771f70d2302901f7e5eYasuyuki KOZAKAI		close(procfile);
1230b82e8e81e887843011c8771f70d2302901f7e5eYasuyuki KOZAKAI		return ret;
1240b82e8e81e887843011c8771f70d2302901f7e5eYasuyuki KOZAKAI	}
1250b82e8e81e887843011c8771f70d2302901f7e5eYasuyuki KOZAKAI fail:
1260b82e8e81e887843011c8771f70d2302901f7e5eYasuyuki KOZAKAI	free(ret);
1270b82e8e81e887843011c8771f70d2302901f7e5eYasuyuki KOZAKAI	close(procfile);
1280b82e8e81e887843011c8771f70d2302901f7e5eYasuyuki KOZAKAI	return NULL;
1290b82e8e81e887843011c8771f70d2302901f7e5eYasuyuki KOZAKAI}
1300b82e8e81e887843011c8771f70d2302901f7e5eYasuyuki KOZAKAI
131c021c3ce7b1583eb5dd71b10ac3d8ab3cd36beaaJan Engelhardtint xtables_insmod(const char *modname, const char *modprobe, bool quiet)
1320b82e8e81e887843011c8771f70d2302901f7e5eYasuyuki KOZAKAI{
1330b82e8e81e887843011c8771f70d2302901f7e5eYasuyuki KOZAKAI	char *buf = NULL;
1340b82e8e81e887843011c8771f70d2302901f7e5eYasuyuki KOZAKAI	char *argv[4];
1350b82e8e81e887843011c8771f70d2302901f7e5eYasuyuki KOZAKAI	int status;
1360b82e8e81e887843011c8771f70d2302901f7e5eYasuyuki KOZAKAI
1370b82e8e81e887843011c8771f70d2302901f7e5eYasuyuki KOZAKAI	/* If they don't explicitly set it, read out of kernel */
1380b82e8e81e887843011c8771f70d2302901f7e5eYasuyuki KOZAKAI	if (!modprobe) {
1390b82e8e81e887843011c8771f70d2302901f7e5eYasuyuki KOZAKAI		buf = get_modprobe();
1400b82e8e81e887843011c8771f70d2302901f7e5eYasuyuki KOZAKAI		if (!buf)
1410b82e8e81e887843011c8771f70d2302901f7e5eYasuyuki KOZAKAI			return -1;
1420b82e8e81e887843011c8771f70d2302901f7e5eYasuyuki KOZAKAI		modprobe = buf;
1430b82e8e81e887843011c8771f70d2302901f7e5eYasuyuki KOZAKAI	}
1440b82e8e81e887843011c8771f70d2302901f7e5eYasuyuki KOZAKAI
1450b82e8e81e887843011c8771f70d2302901f7e5eYasuyuki KOZAKAI	switch (fork()) {
1460b82e8e81e887843011c8771f70d2302901f7e5eYasuyuki KOZAKAI	case 0:
1470b82e8e81e887843011c8771f70d2302901f7e5eYasuyuki KOZAKAI		argv[0] = (char *)modprobe;
1480b82e8e81e887843011c8771f70d2302901f7e5eYasuyuki KOZAKAI		argv[1] = (char *)modname;
1490b82e8e81e887843011c8771f70d2302901f7e5eYasuyuki KOZAKAI		if (quiet) {
1500b82e8e81e887843011c8771f70d2302901f7e5eYasuyuki KOZAKAI			argv[2] = "-q";
1510b82e8e81e887843011c8771f70d2302901f7e5eYasuyuki KOZAKAI			argv[3] = NULL;
1520b82e8e81e887843011c8771f70d2302901f7e5eYasuyuki KOZAKAI		} else {
1530b82e8e81e887843011c8771f70d2302901f7e5eYasuyuki KOZAKAI			argv[2] = NULL;
1540b82e8e81e887843011c8771f70d2302901f7e5eYasuyuki KOZAKAI			argv[3] = NULL;
1550b82e8e81e887843011c8771f70d2302901f7e5eYasuyuki KOZAKAI		}
1560b82e8e81e887843011c8771f70d2302901f7e5eYasuyuki KOZAKAI		execv(argv[0], argv);
1570b82e8e81e887843011c8771f70d2302901f7e5eYasuyuki KOZAKAI
1580b82e8e81e887843011c8771f70d2302901f7e5eYasuyuki KOZAKAI		/* not usually reached */
1590b82e8e81e887843011c8771f70d2302901f7e5eYasuyuki KOZAKAI		exit(1);
1600b82e8e81e887843011c8771f70d2302901f7e5eYasuyuki KOZAKAI	case -1:
1610b82e8e81e887843011c8771f70d2302901f7e5eYasuyuki KOZAKAI		return -1;
1620b82e8e81e887843011c8771f70d2302901f7e5eYasuyuki KOZAKAI
1630b82e8e81e887843011c8771f70d2302901f7e5eYasuyuki KOZAKAI	default: /* parent */
1640b82e8e81e887843011c8771f70d2302901f7e5eYasuyuki KOZAKAI		wait(&status);
1650b82e8e81e887843011c8771f70d2302901f7e5eYasuyuki KOZAKAI	}
1660b82e8e81e887843011c8771f70d2302901f7e5eYasuyuki KOZAKAI
1670b82e8e81e887843011c8771f70d2302901f7e5eYasuyuki KOZAKAI	free(buf);
1680b82e8e81e887843011c8771f70d2302901f7e5eYasuyuki KOZAKAI	if (WIFEXITED(status) && WEXITSTATUS(status) == 0)
1690b82e8e81e887843011c8771f70d2302901f7e5eYasuyuki KOZAKAI		return 0;
1700b82e8e81e887843011c8771f70d2302901f7e5eYasuyuki KOZAKAI	return -1;
1710b82e8e81e887843011c8771f70d2302901f7e5eYasuyuki KOZAKAI}
1720b82e8e81e887843011c8771f70d2302901f7e5eYasuyuki KOZAKAI
173c021c3ce7b1583eb5dd71b10ac3d8ab3cd36beaaJan Engelhardtint xtables_load_ko(const char *modprobe, bool quiet)
1740d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI{
175c021c3ce7b1583eb5dd71b10ac3d8ab3cd36beaaJan Engelhardt	static bool loaded = false;
1760d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI	static int ret = -1;
1770d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI
1780d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI	if (!loaded) {
1790d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI		ret = xtables_insmod(afinfo.kmod, modprobe, quiet);
1800d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI		loaded = (ret == 0);
1810d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI	}
1820d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI
1830d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI	return ret;
1840d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI}
1850d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI
1865f2922cfc0bbfbeb878f5c12e9fb3eb602ae5507Jan Engelhardt/**
1875f2922cfc0bbfbeb878f5c12e9fb3eb602ae5507Jan Engelhardt * xtables_strtou{i,l} - string to number conversion
1885f2922cfc0bbfbeb878f5c12e9fb3eb602ae5507Jan Engelhardt * @s:	input string
1895f2922cfc0bbfbeb878f5c12e9fb3eb602ae5507Jan Engelhardt * @end:	like strtoul's "end" pointer
1905f2922cfc0bbfbeb878f5c12e9fb3eb602ae5507Jan Engelhardt * @value:	pointer for result
1915f2922cfc0bbfbeb878f5c12e9fb3eb602ae5507Jan Engelhardt * @min:	minimum accepted value
1925f2922cfc0bbfbeb878f5c12e9fb3eb602ae5507Jan Engelhardt * @max:	maximum accepted value
1935f2922cfc0bbfbeb878f5c12e9fb3eb602ae5507Jan Engelhardt *
1945f2922cfc0bbfbeb878f5c12e9fb3eb602ae5507Jan Engelhardt * If @end is NULL, we assume the caller wants a "strict strtoul", and hence
1955f2922cfc0bbfbeb878f5c12e9fb3eb602ae5507Jan Engelhardt * "15a" is rejected.
1965f2922cfc0bbfbeb878f5c12e9fb3eb602ae5507Jan Engelhardt * In either case, the value obtained is compared for min-max compliance.
1975f2922cfc0bbfbeb878f5c12e9fb3eb602ae5507Jan Engelhardt * Base is always 0, i.e. autodetect depending on @s.
198cd9e7aa106e80c44bd526af74b616701b0772d05Jan Engelhardt *
1995f2922cfc0bbfbeb878f5c12e9fb3eb602ae5507Jan Engelhardt * Returns true/false whether number was accepted. On failure, *value has
2005f2922cfc0bbfbeb878f5c12e9fb3eb602ae5507Jan Engelhardt * undefined contents.
201cd9e7aa106e80c44bd526af74b616701b0772d05Jan Engelhardt */
2025f2922cfc0bbfbeb878f5c12e9fb3eb602ae5507Jan Engelhardtbool xtables_strtoul(const char *s, char **end, unsigned long *value,
2035f2922cfc0bbfbeb878f5c12e9fb3eb602ae5507Jan Engelhardt                     unsigned long min, unsigned long max)
204cd9e7aa106e80c44bd526af74b616701b0772d05Jan Engelhardt{
205cd9e7aa106e80c44bd526af74b616701b0772d05Jan Engelhardt	unsigned long v;
206cd9e7aa106e80c44bd526af74b616701b0772d05Jan Engelhardt	char *my_end;
207cd9e7aa106e80c44bd526af74b616701b0772d05Jan Engelhardt
208cd9e7aa106e80c44bd526af74b616701b0772d05Jan Engelhardt	errno = 0;
209cd9e7aa106e80c44bd526af74b616701b0772d05Jan Engelhardt	v = strtoul(s, &my_end, 0);
210cd9e7aa106e80c44bd526af74b616701b0772d05Jan Engelhardt
211cd9e7aa106e80c44bd526af74b616701b0772d05Jan Engelhardt	if (my_end == s)
212cd9e7aa106e80c44bd526af74b616701b0772d05Jan Engelhardt		return false;
213cd9e7aa106e80c44bd526af74b616701b0772d05Jan Engelhardt	if (end != NULL)
214cd9e7aa106e80c44bd526af74b616701b0772d05Jan Engelhardt		*end = my_end;
215cd9e7aa106e80c44bd526af74b616701b0772d05Jan Engelhardt
216cd9e7aa106e80c44bd526af74b616701b0772d05Jan Engelhardt	if (errno != ERANGE && min <= v && (max == 0 || v <= max)) {
217cd9e7aa106e80c44bd526af74b616701b0772d05Jan Engelhardt		if (value != NULL)
218cd9e7aa106e80c44bd526af74b616701b0772d05Jan Engelhardt			*value = v;
219cd9e7aa106e80c44bd526af74b616701b0772d05Jan Engelhardt		if (end == NULL)
220cd9e7aa106e80c44bd526af74b616701b0772d05Jan Engelhardt			return *my_end == '\0';
221cd9e7aa106e80c44bd526af74b616701b0772d05Jan Engelhardt		return true;
222cd9e7aa106e80c44bd526af74b616701b0772d05Jan Engelhardt	}
223cd9e7aa106e80c44bd526af74b616701b0772d05Jan Engelhardt
224cd9e7aa106e80c44bd526af74b616701b0772d05Jan Engelhardt	return false;
225cd9e7aa106e80c44bd526af74b616701b0772d05Jan Engelhardt}
226cd9e7aa106e80c44bd526af74b616701b0772d05Jan Engelhardt
2275f2922cfc0bbfbeb878f5c12e9fb3eb602ae5507Jan Engelhardtbool xtables_strtoui(const char *s, char **end, unsigned int *value,
2285f2922cfc0bbfbeb878f5c12e9fb3eb602ae5507Jan Engelhardt                     unsigned int min, unsigned int max)
229cd9e7aa106e80c44bd526af74b616701b0772d05Jan Engelhardt{
230cd9e7aa106e80c44bd526af74b616701b0772d05Jan Engelhardt	unsigned long v;
231cd9e7aa106e80c44bd526af74b616701b0772d05Jan Engelhardt	bool ret;
232cd9e7aa106e80c44bd526af74b616701b0772d05Jan Engelhardt
2335f2922cfc0bbfbeb878f5c12e9fb3eb602ae5507Jan Engelhardt	ret = xtables_strtoul(s, end, &v, min, max);
234cd9e7aa106e80c44bd526af74b616701b0772d05Jan Engelhardt	if (value != NULL)
235cd9e7aa106e80c44bd526af74b616701b0772d05Jan Engelhardt		*value = v;
236cd9e7aa106e80c44bd526af74b616701b0772d05Jan Engelhardt	return ret;
237cd9e7aa106e80c44bd526af74b616701b0772d05Jan Engelhardt}
238cd9e7aa106e80c44bd526af74b616701b0772d05Jan Engelhardt
23904f8c54dc52e19096d31d94593bd1040716afe4dYasuyuki KOZAKAIint service_to_port(const char *name, const char *proto)
24004f8c54dc52e19096d31d94593bd1040716afe4dYasuyuki KOZAKAI{
24104f8c54dc52e19096d31d94593bd1040716afe4dYasuyuki KOZAKAI	struct servent *service;
24204f8c54dc52e19096d31d94593bd1040716afe4dYasuyuki KOZAKAI
24304f8c54dc52e19096d31d94593bd1040716afe4dYasuyuki KOZAKAI	if ((service = getservbyname(name, proto)) != NULL)
24404f8c54dc52e19096d31d94593bd1040716afe4dYasuyuki KOZAKAI		return ntohs((unsigned short) service->s_port);
24504f8c54dc52e19096d31d94593bd1040716afe4dYasuyuki KOZAKAI
24604f8c54dc52e19096d31d94593bd1040716afe4dYasuyuki KOZAKAI	return -1;
24704f8c54dc52e19096d31d94593bd1040716afe4dYasuyuki KOZAKAI}
24804f8c54dc52e19096d31d94593bd1040716afe4dYasuyuki KOZAKAI
24904f8c54dc52e19096d31d94593bd1040716afe4dYasuyuki KOZAKAIu_int16_t parse_port(const char *port, const char *proto)
25004f8c54dc52e19096d31d94593bd1040716afe4dYasuyuki KOZAKAI{
2517a236f4cc685a420c1a782a5db614a93baf37ccfJan Engelhardt	unsigned int portnum;
25204f8c54dc52e19096d31d94593bd1040716afe4dYasuyuki KOZAKAI
2535f2922cfc0bbfbeb878f5c12e9fb3eb602ae5507Jan Engelhardt	if (xtables_strtoui(port, NULL, &portnum, 0, UINT16_MAX) ||
2549ee386a1b6d7704b259460152c959ab0e79e02aaMax Kellermann	    (portnum = service_to_port(port, proto)) != (unsigned)-1)
255213e185afbb298e6708881e4c2adffdc47a8b6daJan Engelhardt		return portnum;
25604f8c54dc52e19096d31d94593bd1040716afe4dYasuyuki KOZAKAI
25704f8c54dc52e19096d31d94593bd1040716afe4dYasuyuki KOZAKAI	exit_error(PARAMETER_PROBLEM,
25804f8c54dc52e19096d31d94593bd1040716afe4dYasuyuki KOZAKAI		   "invalid port/service `%s' specified", port);
25904f8c54dc52e19096d31d94593bd1040716afe4dYasuyuki KOZAKAI}
26004f8c54dc52e19096d31d94593bd1040716afe4dYasuyuki KOZAKAI
26104f8c54dc52e19096d31d94593bd1040716afe4dYasuyuki KOZAKAIvoid parse_interface(const char *arg, char *vianame, unsigned char *mask)
26204f8c54dc52e19096d31d94593bd1040716afe4dYasuyuki KOZAKAI{
26304f8c54dc52e19096d31d94593bd1040716afe4dYasuyuki KOZAKAI	int vialen = strlen(arg);
26404f8c54dc52e19096d31d94593bd1040716afe4dYasuyuki KOZAKAI	unsigned int i;
26504f8c54dc52e19096d31d94593bd1040716afe4dYasuyuki KOZAKAI
26604f8c54dc52e19096d31d94593bd1040716afe4dYasuyuki KOZAKAI	memset(mask, 0, IFNAMSIZ);
26704f8c54dc52e19096d31d94593bd1040716afe4dYasuyuki KOZAKAI	memset(vianame, 0, IFNAMSIZ);
26804f8c54dc52e19096d31d94593bd1040716afe4dYasuyuki KOZAKAI
26904f8c54dc52e19096d31d94593bd1040716afe4dYasuyuki KOZAKAI	if (vialen + 1 > IFNAMSIZ)
27004f8c54dc52e19096d31d94593bd1040716afe4dYasuyuki KOZAKAI		exit_error(PARAMETER_PROBLEM,
27104f8c54dc52e19096d31d94593bd1040716afe4dYasuyuki KOZAKAI			   "interface name `%s' must be shorter than IFNAMSIZ"
27204f8c54dc52e19096d31d94593bd1040716afe4dYasuyuki KOZAKAI			   " (%i)", arg, IFNAMSIZ-1);
27304f8c54dc52e19096d31d94593bd1040716afe4dYasuyuki KOZAKAI
27404f8c54dc52e19096d31d94593bd1040716afe4dYasuyuki KOZAKAI	strcpy(vianame, arg);
27504f8c54dc52e19096d31d94593bd1040716afe4dYasuyuki KOZAKAI	if ((vialen == 0) || (vialen == 1 && vianame[0] == '+'))
27604f8c54dc52e19096d31d94593bd1040716afe4dYasuyuki KOZAKAI		memset(mask, 0, IFNAMSIZ);
27704f8c54dc52e19096d31d94593bd1040716afe4dYasuyuki KOZAKAI	else if (vianame[vialen - 1] == '+') {
27804f8c54dc52e19096d31d94593bd1040716afe4dYasuyuki KOZAKAI		memset(mask, 0xFF, vialen - 1);
27904f8c54dc52e19096d31d94593bd1040716afe4dYasuyuki KOZAKAI		memset(mask + vialen - 1, 0, IFNAMSIZ - vialen + 1);
28004f8c54dc52e19096d31d94593bd1040716afe4dYasuyuki KOZAKAI		/* Don't remove `+' here! -HW */
28104f8c54dc52e19096d31d94593bd1040716afe4dYasuyuki KOZAKAI	} else {
28204f8c54dc52e19096d31d94593bd1040716afe4dYasuyuki KOZAKAI		/* Include nul-terminator in match */
28304f8c54dc52e19096d31d94593bd1040716afe4dYasuyuki KOZAKAI		memset(mask, 0xFF, vialen + 1);
28404f8c54dc52e19096d31d94593bd1040716afe4dYasuyuki KOZAKAI		memset(mask + vialen + 1, 0, IFNAMSIZ - vialen - 1);
28504f8c54dc52e19096d31d94593bd1040716afe4dYasuyuki KOZAKAI		for (i = 0; vianame[i]; i++) {
28604f8c54dc52e19096d31d94593bd1040716afe4dYasuyuki KOZAKAI			if (vianame[i] == ':' ||
28704f8c54dc52e19096d31d94593bd1040716afe4dYasuyuki KOZAKAI			    vianame[i] == '!' ||
28804f8c54dc52e19096d31d94593bd1040716afe4dYasuyuki KOZAKAI			    vianame[i] == '*') {
289aae4f82eb83d923f59a328d6e13396f424be28f9Max Kellermann				fprintf(stderr,
290aae4f82eb83d923f59a328d6e13396f424be28f9Max Kellermann					"Warning: weird character in interface"
291aae4f82eb83d923f59a328d6e13396f424be28f9Max Kellermann					" `%s' (No aliases, :, ! or *).\n",
292aae4f82eb83d923f59a328d6e13396f424be28f9Max Kellermann					vianame);
29304f8c54dc52e19096d31d94593bd1040716afe4dYasuyuki KOZAKAI				break;
29404f8c54dc52e19096d31d94593bd1040716afe4dYasuyuki KOZAKAI			}
29504f8c54dc52e19096d31d94593bd1040716afe4dYasuyuki KOZAKAI		}
29604f8c54dc52e19096d31d94593bd1040716afe4dYasuyuki KOZAKAI	}
29704f8c54dc52e19096d31d94593bd1040716afe4dYasuyuki KOZAKAI}
29804f8c54dc52e19096d31d94593bd1040716afe4dYasuyuki KOZAKAI
299cb25af809a8734c4766b6bfa4cca99596cbf01dbJan Engelhardt#ifndef NO_SHARED_LIBS
30021b41eea4724c57d2b6e5998cf38255046e43ad3Jan Engelhardtstatic void *load_extension(const char *search_path, const char *prefix,
30121b41eea4724c57d2b6e5998cf38255046e43ad3Jan Engelhardt    const char *name, bool is_target)
30221b41eea4724c57d2b6e5998cf38255046e43ad3Jan Engelhardt{
30321b41eea4724c57d2b6e5998cf38255046e43ad3Jan Engelhardt	const char *dir = search_path, *next;
30421b41eea4724c57d2b6e5998cf38255046e43ad3Jan Engelhardt	void *ptr = NULL;
30521b41eea4724c57d2b6e5998cf38255046e43ad3Jan Engelhardt	struct stat sb;
30621b41eea4724c57d2b6e5998cf38255046e43ad3Jan Engelhardt	char path[256];
30721b41eea4724c57d2b6e5998cf38255046e43ad3Jan Engelhardt
30821b41eea4724c57d2b6e5998cf38255046e43ad3Jan Engelhardt	do {
30921b41eea4724c57d2b6e5998cf38255046e43ad3Jan Engelhardt		next = strchr(dir, ':');
31021b41eea4724c57d2b6e5998cf38255046e43ad3Jan Engelhardt		if (next == NULL)
31121b41eea4724c57d2b6e5998cf38255046e43ad3Jan Engelhardt			next = dir + strlen(dir);
31221b41eea4724c57d2b6e5998cf38255046e43ad3Jan Engelhardt		snprintf(path, sizeof(path), "%.*s/libxt_%s.so",
3132c0a0c9eba1d1ab39dcde54bc822d4788f9531fcJan Engelhardt		         (unsigned int)(next - dir), dir, name);
31421b41eea4724c57d2b6e5998cf38255046e43ad3Jan Engelhardt
31521b41eea4724c57d2b6e5998cf38255046e43ad3Jan Engelhardt		if (dlopen(path, RTLD_NOW) != NULL) {
31621b41eea4724c57d2b6e5998cf38255046e43ad3Jan Engelhardt			/* Found library.  If it didn't register itself,
31721b41eea4724c57d2b6e5998cf38255046e43ad3Jan Engelhardt			   maybe they specified target as match. */
31821b41eea4724c57d2b6e5998cf38255046e43ad3Jan Engelhardt			if (is_target)
3192338efd8f799d8373dc196c797bda9690283b698Jan Engelhardt				ptr = xtables_find_target(name, XTF_DONT_LOAD);
32021b41eea4724c57d2b6e5998cf38255046e43ad3Jan Engelhardt			else
3212338efd8f799d8373dc196c797bda9690283b698Jan Engelhardt				ptr = xtables_find_match(name,
3222338efd8f799d8373dc196c797bda9690283b698Jan Engelhardt				      XTF_DONT_LOAD, NULL);
32321b41eea4724c57d2b6e5998cf38255046e43ad3Jan Engelhardt		} else if (stat(path, &sb) == 0) {
32421b41eea4724c57d2b6e5998cf38255046e43ad3Jan Engelhardt			fprintf(stderr, "%s: %s\n", path, dlerror());
32521b41eea4724c57d2b6e5998cf38255046e43ad3Jan Engelhardt		}
32621b41eea4724c57d2b6e5998cf38255046e43ad3Jan Engelhardt
32721b41eea4724c57d2b6e5998cf38255046e43ad3Jan Engelhardt		if (ptr != NULL)
32821b41eea4724c57d2b6e5998cf38255046e43ad3Jan Engelhardt			return ptr;
32921b41eea4724c57d2b6e5998cf38255046e43ad3Jan Engelhardt
33021b41eea4724c57d2b6e5998cf38255046e43ad3Jan Engelhardt		snprintf(path, sizeof(path), "%.*s/%s%s.so",
3312c0a0c9eba1d1ab39dcde54bc822d4788f9531fcJan Engelhardt		         (unsigned int)(next - dir), dir, prefix, name);
33221b41eea4724c57d2b6e5998cf38255046e43ad3Jan Engelhardt		if (dlopen(path, RTLD_NOW) != NULL) {
33321b41eea4724c57d2b6e5998cf38255046e43ad3Jan Engelhardt			if (is_target)
3342338efd8f799d8373dc196c797bda9690283b698Jan Engelhardt				ptr = xtables_find_target(name, XTF_DONT_LOAD);
33521b41eea4724c57d2b6e5998cf38255046e43ad3Jan Engelhardt			else
3362338efd8f799d8373dc196c797bda9690283b698Jan Engelhardt				ptr = xtables_find_match(name,
3372338efd8f799d8373dc196c797bda9690283b698Jan Engelhardt				      XTF_DONT_LOAD, NULL);
33821b41eea4724c57d2b6e5998cf38255046e43ad3Jan Engelhardt		} else if (stat(path, &sb) == 0) {
33921b41eea4724c57d2b6e5998cf38255046e43ad3Jan Engelhardt			fprintf(stderr, "%s: %s\n", path, dlerror());
34021b41eea4724c57d2b6e5998cf38255046e43ad3Jan Engelhardt		}
34121b41eea4724c57d2b6e5998cf38255046e43ad3Jan Engelhardt
34221b41eea4724c57d2b6e5998cf38255046e43ad3Jan Engelhardt		if (ptr != NULL)
34321b41eea4724c57d2b6e5998cf38255046e43ad3Jan Engelhardt			return ptr;
34421b41eea4724c57d2b6e5998cf38255046e43ad3Jan Engelhardt
34521b41eea4724c57d2b6e5998cf38255046e43ad3Jan Engelhardt		dir = next + 1;
34621b41eea4724c57d2b6e5998cf38255046e43ad3Jan Engelhardt	} while (*next != '\0');
34721b41eea4724c57d2b6e5998cf38255046e43ad3Jan Engelhardt
34821b41eea4724c57d2b6e5998cf38255046e43ad3Jan Engelhardt	return NULL;
34921b41eea4724c57d2b6e5998cf38255046e43ad3Jan Engelhardt}
350cb25af809a8734c4766b6bfa4cca99596cbf01dbJan Engelhardt#endif
35121b41eea4724c57d2b6e5998cf38255046e43ad3Jan Engelhardt
3522338efd8f799d8373dc196c797bda9690283b698Jan Engelhardtstruct xtables_match *
3532338efd8f799d8373dc196c797bda9690283b698Jan Engelhardtxtables_find_match(const char *name, enum xtables_tryload tryload,
3542338efd8f799d8373dc196c797bda9690283b698Jan Engelhardt		   struct xtables_rule_match **matches)
3550d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI{
3560d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI	struct xtables_match *ptr;
3570d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI	const char *icmp6 = "icmp6";
3580d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI
3590d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI	/* This is ugly as hell. Nonetheless, there is no way of changing
3600d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI	 * this without hurting backwards compatibility */
3610d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI	if ( (strcmp(name,"icmpv6") == 0) ||
3620d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI	     (strcmp(name,"ipv6-icmp") == 0) ||
3630d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI	     (strcmp(name,"icmp6") == 0) )
3640d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI		name = icmp6;
3650d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI
3660d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI	for (ptr = xtables_matches; ptr; ptr = ptr->next) {
3670d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI		if (strcmp(name, ptr->name) == 0) {
3680d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI			struct xtables_match *clone;
3690d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI
3700d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI			/* First match of this type: */
3710d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI			if (ptr->m == NULL)
3720d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI				break;
3730d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI
3740d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI			/* Second and subsequent clones */
375630ef48037f3602333addfdb53789c9c6a4bb4c8Jan Engelhardt			clone = xtables_malloc(sizeof(struct xtables_match));
3760d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI			memcpy(clone, ptr, sizeof(struct xtables_match));
3770d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI			clone->mflags = 0;
3780d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI			/* This is a clone: */
3790d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI			clone->next = clone;
3800d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI
3810d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI			ptr = clone;
3820d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI			break;
3830d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI		}
3840d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI	}
3850d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI
3860d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI#ifndef NO_SHARED_LIBS
3872338efd8f799d8373dc196c797bda9690283b698Jan Engelhardt	if (!ptr && tryload != XTF_DONT_LOAD && tryload != XTF_DURING_LOAD) {
38839bf9c8214d3073a496a8a1eff91046a8d6fbbdfJan Engelhardt		ptr = load_extension(xtables_libdir, afinfo.libprefix,
38939bf9c8214d3073a496a8a1eff91046a8d6fbbdfJan Engelhardt		      name, false);
390170af8c566faa9605c1ead558792a031f1d0d48dYasuyuki KOZAKAI
3912338efd8f799d8373dc196c797bda9690283b698Jan Engelhardt		if (ptr == NULL && tryload == XTF_LOAD_MUST_SUCCEED)
3920d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI			exit_error(PARAMETER_PROBLEM,
3930d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI				   "Couldn't load match `%s':%s\n",
3940d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI				   name, dlerror());
3950d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI	}
3960d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI#else
3970d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI	if (ptr && !ptr->loaded) {
3982338efd8f799d8373dc196c797bda9690283b698Jan Engelhardt		if (tryload != XTF_DONT_LOAD)
3990d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI			ptr->loaded = 1;
4000d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI		else
4010d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI			ptr = NULL;
4020d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI	}
4032338efd8f799d8373dc196c797bda9690283b698Jan Engelhardt	if(!ptr && (tryload == XTF_LOAD_MUST_SUCCEED)) {
4040d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI		exit_error(PARAMETER_PROBLEM,
4050d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI			   "Couldn't find match `%s'\n", name);
4060d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI	}
4070d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI#endif
4080d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI
4090d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI	if (ptr && matches) {
4100d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI		struct xtables_rule_match **i;
4110d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI		struct xtables_rule_match *newentry;
4120d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI
413630ef48037f3602333addfdb53789c9c6a4bb4c8Jan Engelhardt		newentry = xtables_malloc(sizeof(struct xtables_rule_match));
4140d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI
4150d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI		for (i = matches; *i; i = &(*i)->next) {
4160d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI			if (strcmp(name, (*i)->match->name) == 0)
4172338efd8f799d8373dc196c797bda9690283b698Jan Engelhardt				(*i)->completed = true;
4180d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI		}
4190d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI		newentry->match = ptr;
4202338efd8f799d8373dc196c797bda9690283b698Jan Engelhardt		newentry->completed = false;
4210d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI		newentry->next = NULL;
4220d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI		*i = newentry;
4230d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI	}
4240d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI
4250d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI	return ptr;
4260d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI}
4270d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI
4282338efd8f799d8373dc196c797bda9690283b698Jan Engelhardtstruct xtables_target *
4292338efd8f799d8373dc196c797bda9690283b698Jan Engelhardtxtables_find_target(const char *name, enum xtables_tryload tryload)
4300d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI{
4310d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI	struct xtables_target *ptr;
4320d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI
4330d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI	/* Standard target? */
4340d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI	if (strcmp(name, "") == 0
4350d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI	    || strcmp(name, XTC_LABEL_ACCEPT) == 0
4360d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI	    || strcmp(name, XTC_LABEL_DROP) == 0
4370d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI	    || strcmp(name, XTC_LABEL_QUEUE) == 0
4380d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI	    || strcmp(name, XTC_LABEL_RETURN) == 0)
4390d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI		name = "standard";
4400d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI
4410d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI	for (ptr = xtables_targets; ptr; ptr = ptr->next) {
4420d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI		if (strcmp(name, ptr->name) == 0)
4430d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI			break;
4440d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI	}
4450d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI
4460d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI#ifndef NO_SHARED_LIBS
4472338efd8f799d8373dc196c797bda9690283b698Jan Engelhardt	if (!ptr && tryload != XTF_DONT_LOAD && tryload != XTF_DURING_LOAD) {
44839bf9c8214d3073a496a8a1eff91046a8d6fbbdfJan Engelhardt		ptr = load_extension(xtables_libdir, afinfo.libprefix,
44939bf9c8214d3073a496a8a1eff91046a8d6fbbdfJan Engelhardt		      name, true);
450170af8c566faa9605c1ead558792a031f1d0d48dYasuyuki KOZAKAI
4512338efd8f799d8373dc196c797bda9690283b698Jan Engelhardt		if (ptr == NULL && tryload == XTF_LOAD_MUST_SUCCEED)
4520d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI			exit_error(PARAMETER_PROBLEM,
4530d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI				   "Couldn't load target `%s':%s\n",
4540d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI				   name, dlerror());
4550d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI	}
4560d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI#else
4570d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI	if (ptr && !ptr->loaded) {
4582338efd8f799d8373dc196c797bda9690283b698Jan Engelhardt		if (tryload != XTF_DONT_LOAD)
4590d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI			ptr->loaded = 1;
4600d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI		else
4610d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI			ptr = NULL;
4620d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI	}
4630d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI	if(!ptr && (tryload == LOAD_MUST_SUCCEED)) {
4640d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI		exit_error(PARAMETER_PROBLEM,
4650d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI			   "Couldn't find target `%s'\n", name);
4660d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI	}
4670d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI#endif
4680d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI
4690d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI	if (ptr)
4700d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI		ptr->used = 1;
4710d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI
4720d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI	return ptr;
4730d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI}
4740d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI
4750d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAIstatic int compatible_revision(const char *name, u_int8_t revision, int opt)
4760d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI{
4770d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI	struct xt_get_revision rev;
4780d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI	socklen_t s = sizeof(rev);
4790d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI	int max_rev, sockfd;
4800d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI
4810d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI	sockfd = socket(afinfo.family, SOCK_RAW, IPPROTO_RAW);
4820d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI	if (sockfd < 0) {
483df1ef3862761e534c6cec6bd9370285cb5909dd0Patrick McHardy		if (errno == EPERM) {
484df1ef3862761e534c6cec6bd9370285cb5909dd0Patrick McHardy			/* revision 0 is always supported. */
485df1ef3862761e534c6cec6bd9370285cb5909dd0Patrick McHardy			if (revision != 0)
486df1ef3862761e534c6cec6bd9370285cb5909dd0Patrick McHardy				fprintf(stderr, "Could not determine whether "
487df1ef3862761e534c6cec6bd9370285cb5909dd0Patrick McHardy						"revision %u is supported, "
488df1ef3862761e534c6cec6bd9370285cb5909dd0Patrick McHardy						"assuming it is.\n",
489df1ef3862761e534c6cec6bd9370285cb5909dd0Patrick McHardy					revision);
490df1ef3862761e534c6cec6bd9370285cb5909dd0Patrick McHardy			return 1;
491df1ef3862761e534c6cec6bd9370285cb5909dd0Patrick McHardy		}
4920d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI		fprintf(stderr, "Could not open socket to kernel: %s\n",
4930d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI			strerror(errno));
4940d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI		exit(1);
4950d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI	}
4960d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI
497c021c3ce7b1583eb5dd71b10ac3d8ab3cd36beaaJan Engelhardt	xtables_load_ko(xtables_modprobe_program, true);
4980d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI
4990d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI	strcpy(rev.name, name);
5000d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI	rev.revision = revision;
5010d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI
5020d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI	max_rev = getsockopt(sockfd, afinfo.ipproto, opt, &rev, &s);
5030d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI	if (max_rev < 0) {
5040d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI		/* Definitely don't support this? */
5050d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI		if (errno == ENOENT || errno == EPROTONOSUPPORT) {
5060d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI			close(sockfd);
5070d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI			return 0;
5080d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI		} else if (errno == ENOPROTOOPT) {
5090d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI			close(sockfd);
5100d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI			/* Assume only revision 0 support (old kernel) */
5110d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI			return (revision == 0);
5120d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI		} else {
5130d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI			fprintf(stderr, "getsockopt failed strangely: %s\n",
5140d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI				strerror(errno));
5150d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI			exit(1);
5160d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI		}
5170d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI	}
5180d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI	close(sockfd);
5190d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI	return 1;
5200d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI}
5210d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI
5220d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI
5230d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAIstatic int compatible_match_revision(const char *name, u_int8_t revision)
5240d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI{
5250d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI	return compatible_revision(name, revision, afinfo.so_rev_match);
5260d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI}
5270d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI
5280d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAIstatic int compatible_target_revision(const char *name, u_int8_t revision)
5290d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI{
5300d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI	return compatible_revision(name, revision, afinfo.so_rev_target);
5310d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI}
5320d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI
5330d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAIvoid xtables_register_match(struct xtables_match *me)
5340d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI{
5350d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI	struct xtables_match **i, *old;
5360d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI
537dacafa55379fd98212031d8c559096c91d7ce93bJan Engelhardt	if (strcmp(me->version, XTABLES_VERSION) != 0) {
538dacafa55379fd98212031d8c559096c91d7ce93bJan Engelhardt		fprintf(stderr, "%s: match \"%s\" has version \"%s\", "
539dacafa55379fd98212031d8c559096c91d7ce93bJan Engelhardt		        "but \"%s\" is required.\n",
540dacafa55379fd98212031d8c559096c91d7ce93bJan Engelhardt			xtables_program_name, me->name,
541dacafa55379fd98212031d8c559096c91d7ce93bJan Engelhardt			me->version, XTABLES_VERSION);
5420d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI		exit(1);
5430d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI	}
5440d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI
5450d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI	/* Revision field stole a char from name. */
5460d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI	if (strlen(me->name) >= XT_FUNCTION_MAXNAMELEN-1) {
5470d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI		fprintf(stderr, "%s: target `%s' has invalid name\n",
548dacafa55379fd98212031d8c559096c91d7ce93bJan Engelhardt			xtables_program_name, me->name);
5490d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI		exit(1);
5500d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI	}
5510d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI
5520d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI	if (me->family >= NPROTO) {
5530d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI		fprintf(stderr,
5540d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI			"%s: BUG: match %s has invalid protocol family\n",
555dacafa55379fd98212031d8c559096c91d7ce93bJan Engelhardt			xtables_program_name, me->name);
5560d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI		exit(1);
5570d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI	}
5580d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI
5590d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI	/* ignore not interested match */
56023545c2a7a31c68c1e49c7c901b632c2f1c59968Jan Engelhardt	if (me->family != afinfo.family && me->family != AF_UNSPEC)
5610d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI		return;
5620d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI
5632338efd8f799d8373dc196c797bda9690283b698Jan Engelhardt	old = xtables_find_match(me->name, XTF_DURING_LOAD, NULL);
5640d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI	if (old) {
56523545c2a7a31c68c1e49c7c901b632c2f1c59968Jan Engelhardt		if (old->revision == me->revision &&
56623545c2a7a31c68c1e49c7c901b632c2f1c59968Jan Engelhardt		    old->family == me->family) {
5670d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI			fprintf(stderr,
5680d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI				"%s: match `%s' already registered.\n",
569dacafa55379fd98212031d8c559096c91d7ce93bJan Engelhardt				xtables_program_name, me->name);
5700d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI			exit(1);
5710d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI		}
5720d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI
5730d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI		/* Now we have two (or more) options, check compatibility. */
5740d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI		if (compatible_match_revision(old->name, old->revision)
5750d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI		    && old->revision > me->revision)
5760d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI			return;
5770d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI
57823545c2a7a31c68c1e49c7c901b632c2f1c59968Jan Engelhardt		/* See if new match can be used. */
5790d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI		if (!compatible_match_revision(me->name, me->revision))
5800d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI			return;
5810d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI
58223545c2a7a31c68c1e49c7c901b632c2f1c59968Jan Engelhardt		/* Prefer !AF_UNSPEC over AF_UNSPEC for same revision. */
58323545c2a7a31c68c1e49c7c901b632c2f1c59968Jan Engelhardt		if (old->revision == me->revision && me->family == AF_UNSPEC)
58423545c2a7a31c68c1e49c7c901b632c2f1c59968Jan Engelhardt			return;
58523545c2a7a31c68c1e49c7c901b632c2f1c59968Jan Engelhardt
5860d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI		/* Delete old one. */
5870d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI		for (i = &xtables_matches; *i!=old; i = &(*i)->next);
5880d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI		*i = old->next;
5890d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI	}
5900d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI
5910d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI	if (me->size != XT_ALIGN(me->size)) {
5920d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI		fprintf(stderr, "%s: match `%s' has invalid size %u.\n",
593dacafa55379fd98212031d8c559096c91d7ce93bJan Engelhardt			xtables_program_name, me->name, (unsigned int)me->size);
5940d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI		exit(1);
5950d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI	}
5960d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI
5970d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI	/* Append to list. */
5980d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI	for (i = &xtables_matches; *i; i = &(*i)->next);
5990d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI	me->next = NULL;
6000d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI	*i = me;
6010d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI
6020d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI	me->m = NULL;
6030d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI	me->mflags = 0;
6040d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI}
6050d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI
6060d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAIvoid xtables_register_target(struct xtables_target *me)
6070d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI{
6080d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI	struct xtables_target *old;
6090d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI
610dacafa55379fd98212031d8c559096c91d7ce93bJan Engelhardt	if (strcmp(me->version, XTABLES_VERSION) != 0) {
611dacafa55379fd98212031d8c559096c91d7ce93bJan Engelhardt		fprintf(stderr, "%s: target \"%s\" has version \"%s\", "
612dacafa55379fd98212031d8c559096c91d7ce93bJan Engelhardt		        "but \"%s\" is required.\n",
613dacafa55379fd98212031d8c559096c91d7ce93bJan Engelhardt			xtables_program_name, me->name,
614dacafa55379fd98212031d8c559096c91d7ce93bJan Engelhardt			me->version, XTABLES_VERSION);
6150d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI		exit(1);
6160d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI	}
6170d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI
6180d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI	/* Revision field stole a char from name. */
6190d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI	if (strlen(me->name) >= XT_FUNCTION_MAXNAMELEN-1) {
6200d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI		fprintf(stderr, "%s: target `%s' has invalid name\n",
621dacafa55379fd98212031d8c559096c91d7ce93bJan Engelhardt			xtables_program_name, me->name);
6220d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI		exit(1);
6230d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI	}
6240d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI
6250d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI	if (me->family >= NPROTO) {
6260d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI		fprintf(stderr,
6270d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI			"%s: BUG: target %s has invalid protocol family\n",
628dacafa55379fd98212031d8c559096c91d7ce93bJan Engelhardt			xtables_program_name, me->name);
6290d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI		exit(1);
6300d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI	}
6310d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI
6320d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI	/* ignore not interested target */
63323545c2a7a31c68c1e49c7c901b632c2f1c59968Jan Engelhardt	if (me->family != afinfo.family && me->family != AF_UNSPEC)
6340d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI		return;
6350d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI
6362338efd8f799d8373dc196c797bda9690283b698Jan Engelhardt	old = xtables_find_target(me->name, XTF_DURING_LOAD);
6370d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI	if (old) {
6380d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI		struct xtables_target **i;
6390d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI
64023545c2a7a31c68c1e49c7c901b632c2f1c59968Jan Engelhardt		if (old->revision == me->revision &&
64123545c2a7a31c68c1e49c7c901b632c2f1c59968Jan Engelhardt		    old->family == me->family) {
6420d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI			fprintf(stderr,
6430d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI				"%s: target `%s' already registered.\n",
644dacafa55379fd98212031d8c559096c91d7ce93bJan Engelhardt				xtables_program_name, me->name);
6450d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI			exit(1);
6460d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI		}
6470d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI
6480d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI		/* Now we have two (or more) options, check compatibility. */
6490d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI		if (compatible_target_revision(old->name, old->revision)
6500d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI		    && old->revision > me->revision)
6510d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI			return;
6520d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI
65323545c2a7a31c68c1e49c7c901b632c2f1c59968Jan Engelhardt		/* See if new target can be used. */
6540d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI		if (!compatible_target_revision(me->name, me->revision))
6550d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI			return;
6560d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI
65723545c2a7a31c68c1e49c7c901b632c2f1c59968Jan Engelhardt		/* Prefer !AF_UNSPEC over AF_UNSPEC for same revision. */
65823545c2a7a31c68c1e49c7c901b632c2f1c59968Jan Engelhardt		if (old->revision == me->revision && me->family == AF_UNSPEC)
65923545c2a7a31c68c1e49c7c901b632c2f1c59968Jan Engelhardt			return;
66023545c2a7a31c68c1e49c7c901b632c2f1c59968Jan Engelhardt
6610d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI		/* Delete old one. */
6620d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI		for (i = &xtables_targets; *i!=old; i = &(*i)->next);
6630d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI		*i = old->next;
6640d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI	}
6650d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI
6660d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI	if (me->size != XT_ALIGN(me->size)) {
6670d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI		fprintf(stderr, "%s: target `%s' has invalid size %u.\n",
668dacafa55379fd98212031d8c559096c91d7ce93bJan Engelhardt			xtables_program_name, me->name, (unsigned int)me->size);
6690d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI		exit(1);
6700d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI	}
6710d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI
6720d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI	/* Prepend to list. */
6730d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI	me->next = xtables_targets;
6740d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI	xtables_targets = me;
6750d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI	me->t = NULL;
6760d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI	me->tflags = 0;
6770d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI}
678aafd269675fc45bac6340027c866ea6073643c3bJan Engelhardt
679a41545ca7cde43e0ba53260ba74bd9bf74025a68Jan Engelhardt/**
680a41545ca7cde43e0ba53260ba74bd9bf74025a68Jan Engelhardt * xtables_param_act - act on condition
681a41545ca7cde43e0ba53260ba74bd9bf74025a68Jan Engelhardt * @status:	a constant from enum xtables_exittype
682a41545ca7cde43e0ba53260ba74bd9bf74025a68Jan Engelhardt *
683a41545ca7cde43e0ba53260ba74bd9bf74025a68Jan Engelhardt * %XTF_ONLY_ONCE: print error message that option may only be used once.
684a41545ca7cde43e0ba53260ba74bd9bf74025a68Jan Engelhardt * @p1:		module name (e.g. "mark")
685a41545ca7cde43e0ba53260ba74bd9bf74025a68Jan Engelhardt * @p2(...):	option in conflict (e.g. "--mark")
686a41545ca7cde43e0ba53260ba74bd9bf74025a68Jan Engelhardt * @p3(...):	condition to match on (see extensions/ for examples)
687a41545ca7cde43e0ba53260ba74bd9bf74025a68Jan Engelhardt *
688a41545ca7cde43e0ba53260ba74bd9bf74025a68Jan Engelhardt * %XTF_NO_INVERT: option does not support inversion
689a41545ca7cde43e0ba53260ba74bd9bf74025a68Jan Engelhardt * @p1:		module name
690a41545ca7cde43e0ba53260ba74bd9bf74025a68Jan Engelhardt * @p2:		option in conflict
691a41545ca7cde43e0ba53260ba74bd9bf74025a68Jan Engelhardt * @p3:		condition to match on
692a41545ca7cde43e0ba53260ba74bd9bf74025a68Jan Engelhardt *
693a41545ca7cde43e0ba53260ba74bd9bf74025a68Jan Engelhardt * %XTF_BAD_VALUE: bad value for option
694a41545ca7cde43e0ba53260ba74bd9bf74025a68Jan Engelhardt * @p1:		module name
695a41545ca7cde43e0ba53260ba74bd9bf74025a68Jan Engelhardt * @p2:		option with which the problem occured (e.g. "--mark")
696a41545ca7cde43e0ba53260ba74bd9bf74025a68Jan Engelhardt * @p3:		string the user passed in (e.g. "99999999999999")
697a41545ca7cde43e0ba53260ba74bd9bf74025a68Jan Engelhardt *
698a41545ca7cde43e0ba53260ba74bd9bf74025a68Jan Engelhardt * %XTF_ONE_ACTION: two mutually exclusive actions have been specified
699a41545ca7cde43e0ba53260ba74bd9bf74025a68Jan Engelhardt * @p1:		module name
700a41545ca7cde43e0ba53260ba74bd9bf74025a68Jan Engelhardt *
701a41545ca7cde43e0ba53260ba74bd9bf74025a68Jan Engelhardt * Displays an error message and exits the program.
702a41545ca7cde43e0ba53260ba74bd9bf74025a68Jan Engelhardt */
703a41545ca7cde43e0ba53260ba74bd9bf74025a68Jan Engelhardtvoid xtables_param_act(unsigned int status, const char *p1, ...)
704aafd269675fc45bac6340027c866ea6073643c3bJan Engelhardt{
705aafd269675fc45bac6340027c866ea6073643c3bJan Engelhardt	const char *p2, *p3;
706aafd269675fc45bac6340027c866ea6073643c3bJan Engelhardt	va_list args;
707aafd269675fc45bac6340027c866ea6073643c3bJan Engelhardt	bool b;
708aafd269675fc45bac6340027c866ea6073643c3bJan Engelhardt
709aafd269675fc45bac6340027c866ea6073643c3bJan Engelhardt	va_start(args, p1);
710aafd269675fc45bac6340027c866ea6073643c3bJan Engelhardt
711aafd269675fc45bac6340027c866ea6073643c3bJan Engelhardt	switch (status) {
712a41545ca7cde43e0ba53260ba74bd9bf74025a68Jan Engelhardt	case XTF_ONLY_ONCE:
713aafd269675fc45bac6340027c866ea6073643c3bJan Engelhardt		p2 = va_arg(args, const char *);
714aafd269675fc45bac6340027c866ea6073643c3bJan Engelhardt		b  = va_arg(args, unsigned int);
715aafd269675fc45bac6340027c866ea6073643c3bJan Engelhardt		if (!b)
716aafd269675fc45bac6340027c866ea6073643c3bJan Engelhardt			return;
717aafd269675fc45bac6340027c866ea6073643c3bJan Engelhardt		exit_error(PARAMETER_PROBLEM,
718aafd269675fc45bac6340027c866ea6073643c3bJan Engelhardt		           "%s: \"%s\" option may only be specified once",
719aafd269675fc45bac6340027c866ea6073643c3bJan Engelhardt		           p1, p2);
720aafd269675fc45bac6340027c866ea6073643c3bJan Engelhardt		break;
721a41545ca7cde43e0ba53260ba74bd9bf74025a68Jan Engelhardt	case XTF_NO_INVERT:
722aafd269675fc45bac6340027c866ea6073643c3bJan Engelhardt		p2 = va_arg(args, const char *);
723aafd269675fc45bac6340027c866ea6073643c3bJan Engelhardt		b  = va_arg(args, unsigned int);
724aafd269675fc45bac6340027c866ea6073643c3bJan Engelhardt		if (!b)
725aafd269675fc45bac6340027c866ea6073643c3bJan Engelhardt			return;
726aafd269675fc45bac6340027c866ea6073643c3bJan Engelhardt		exit_error(PARAMETER_PROBLEM,
727aafd269675fc45bac6340027c866ea6073643c3bJan Engelhardt		           "%s: \"%s\" option cannot be inverted", p1, p2);
728aafd269675fc45bac6340027c866ea6073643c3bJan Engelhardt		break;
729a41545ca7cde43e0ba53260ba74bd9bf74025a68Jan Engelhardt	case XTF_BAD_VALUE:
730aafd269675fc45bac6340027c866ea6073643c3bJan Engelhardt		p2 = va_arg(args, const char *);
731aafd269675fc45bac6340027c866ea6073643c3bJan Engelhardt		p3 = va_arg(args, const char *);
732aafd269675fc45bac6340027c866ea6073643c3bJan Engelhardt		exit_error(PARAMETER_PROBLEM,
733aafd269675fc45bac6340027c866ea6073643c3bJan Engelhardt		           "%s: Bad value for \"%s\" option: \"%s\"",
734aafd269675fc45bac6340027c866ea6073643c3bJan Engelhardt		           p1, p2, p3);
735aafd269675fc45bac6340027c866ea6073643c3bJan Engelhardt		break;
736a41545ca7cde43e0ba53260ba74bd9bf74025a68Jan Engelhardt	case XTF_ONE_ACTION:
737aafd269675fc45bac6340027c866ea6073643c3bJan Engelhardt		b = va_arg(args, unsigned int);
738aafd269675fc45bac6340027c866ea6073643c3bJan Engelhardt		if (!b)
739aafd269675fc45bac6340027c866ea6073643c3bJan Engelhardt			return;
740aafd269675fc45bac6340027c866ea6073643c3bJan Engelhardt		exit_error(PARAMETER_PROBLEM,
741aafd269675fc45bac6340027c866ea6073643c3bJan Engelhardt		           "%s: At most one action is possible", p1);
742aafd269675fc45bac6340027c866ea6073643c3bJan Engelhardt		break;
743aafd269675fc45bac6340027c866ea6073643c3bJan Engelhardt	default:
744aafd269675fc45bac6340027c866ea6073643c3bJan Engelhardt		exit_error(status, p1, args);
745aafd269675fc45bac6340027c866ea6073643c3bJan Engelhardt		break;
746aafd269675fc45bac6340027c866ea6073643c3bJan Engelhardt	}
747aafd269675fc45bac6340027c866ea6073643c3bJan Engelhardt
748aafd269675fc45bac6340027c866ea6073643c3bJan Engelhardt	va_end(args);
749aafd269675fc45bac6340027c866ea6073643c3bJan Engelhardt}
75008b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt
751e44ea7faa17c10c68f14f5338a7cc6e3291a0ce7Jan Engelhardtconst char *xtables_ipaddr_to_numeric(const struct in_addr *addrp)
75208b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt{
75308b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt	static char buf[20];
75408b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt	const unsigned char *bytep = (const void *)&addrp->s_addr;
75508b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt
75608b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt	sprintf(buf, "%u.%u.%u.%u", bytep[0], bytep[1], bytep[2], bytep[3]);
75708b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt	return buf;
75808b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt}
75908b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt
76008b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardtstatic const char *ipaddr_to_host(const struct in_addr *addr)
76108b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt{
76208b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt	struct hostent *host;
76308b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt
76408b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt	host = gethostbyaddr(addr, sizeof(struct in_addr), AF_INET);
76508b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt	if (host == NULL)
76608b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt		return NULL;
76708b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt
76808b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt	return host->h_name;
76908b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt}
77008b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt
77108b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardtstatic const char *ipaddr_to_network(const struct in_addr *addr)
77208b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt{
77308b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt	struct netent *net;
77408b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt
77508b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt	if ((net = getnetbyaddr(ntohl(addr->s_addr), AF_INET)) != NULL)
77608b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt		return net->n_name;
77708b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt
77808b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt	return NULL;
77908b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt}
78008b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt
781e44ea7faa17c10c68f14f5338a7cc6e3291a0ce7Jan Engelhardtconst char *xtables_ipaddr_to_anyname(const struct in_addr *addr)
78208b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt{
78308b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt	const char *name;
78408b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt
78508b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt	if ((name = ipaddr_to_host(addr)) != NULL ||
78608b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt	    (name = ipaddr_to_network(addr)) != NULL)
78708b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt		return name;
78808b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt
789e44ea7faa17c10c68f14f5338a7cc6e3291a0ce7Jan Engelhardt	return xtables_ipaddr_to_numeric(addr);
79008b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt}
79108b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt
792e44ea7faa17c10c68f14f5338a7cc6e3291a0ce7Jan Engelhardtconst char *xtables_ipmask_to_numeric(const struct in_addr *mask)
79308b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt{
79408b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt	static char buf[20];
79508b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt	uint32_t maskaddr, bits;
79608b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt	int i;
79708b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt
79808b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt	maskaddr = ntohl(mask->s_addr);
79908b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt
80008b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt	if (maskaddr == 0xFFFFFFFFL)
80108b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt		/* we don't want to see "/32" */
80208b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt		return "";
80308b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt
80408b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt	i = 32;
80508b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt	bits = 0xFFFFFFFEL;
80608b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt	while (--i >= 0 && maskaddr != bits)
80708b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt		bits <<= 1;
80808b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt	if (i >= 0)
80908b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt		sprintf(buf, "/%d", i);
81008b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt	else
81108b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt		/* mask was not a decent combination of 1's and 0's */
812e44ea7faa17c10c68f14f5338a7cc6e3291a0ce7Jan Engelhardt		sprintf(buf, "/%s", xtables_ipaddr_to_numeric(mask));
81308b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt
81408b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt	return buf;
81508b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt}
81608b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt
817bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardtstatic struct in_addr *__numeric_to_ipaddr(const char *dotted, bool is_mask)
818bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt{
819bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	static struct in_addr addr;
820bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	unsigned char *addrp;
821bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	unsigned int onebyte;
822bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	char buf[20], *p, *q;
823bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	int i;
824bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt
825bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	/* copy dotted string, because we need to modify it */
826bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	strncpy(buf, dotted, sizeof(buf) - 1);
827bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	buf[sizeof(buf) - 1] = '\0';
828bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	addrp = (void *)&addr.s_addr;
829bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt
830bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	p = buf;
831bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	for (i = 0; i < 3; ++i) {
832bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt		if ((q = strchr(p, '.')) == NULL) {
833bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt			if (is_mask)
834bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt				return NULL;
835bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt
836bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt			/* autocomplete, this is a network address */
8375f2922cfc0bbfbeb878f5c12e9fb3eb602ae5507Jan Engelhardt			if (!xtables_strtoui(p, NULL, &onebyte, 0, UINT8_MAX))
838bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt				return NULL;
839bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt
840bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt			addrp[i] = onebyte;
841bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt			while (i < 3)
842bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt				addrp[++i] = 0;
843bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt
844bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt			return &addr;
845bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt		}
846bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt
847bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt		*q = '\0';
8485f2922cfc0bbfbeb878f5c12e9fb3eb602ae5507Jan Engelhardt		if (!xtables_strtoui(p, NULL, &onebyte, 0, UINT8_MAX))
849bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt			return NULL;
850bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt
851bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt		addrp[i] = onebyte;
852bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt		p = q + 1;
853bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	}
854bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt
855bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	/* we have checked 3 bytes, now we check the last one */
8565f2922cfc0bbfbeb878f5c12e9fb3eb602ae5507Jan Engelhardt	if (!xtables_strtoui(p, NULL, &onebyte, 0, UINT8_MAX))
857bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt		return NULL;
858bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt
859bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	addrp[3] = onebyte;
860bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	return &addr;
861bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt}
862bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt
863bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardtstruct in_addr *numeric_to_ipaddr(const char *dotted)
864bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt{
865bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	return __numeric_to_ipaddr(dotted, false);
866bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt}
867bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt
868bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardtstruct in_addr *numeric_to_ipmask(const char *dotted)
869bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt{
870bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	return __numeric_to_ipaddr(dotted, true);
871bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt}
872bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt
873bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardtstatic struct in_addr *network_to_ipaddr(const char *name)
874bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt{
875bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	static struct in_addr addr;
876bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	struct netent *net;
877bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt
878bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	if ((net = getnetbyname(name)) != NULL) {
879bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt		if (net->n_addrtype != AF_INET)
880bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt			return NULL;
881bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt		addr.s_addr = htonl(net->n_net);
882bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt		return &addr;
883bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	}
884bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt
885bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	return NULL;
886bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt}
887bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt
888bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardtstatic struct in_addr *host_to_ipaddr(const char *name, unsigned int *naddr)
889bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt{
890bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	struct hostent *host;
891bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	struct in_addr *addr;
892bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	unsigned int i;
893bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt
894bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	*naddr = 0;
895bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	if ((host = gethostbyname(name)) != NULL) {
896bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt		if (host->h_addrtype != AF_INET ||
897bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt		    host->h_length != sizeof(struct in_addr))
898bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt			return NULL;
899bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt
900bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt		while (host->h_addr_list[*naddr] != NULL)
901bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt			++*naddr;
902630ef48037f3602333addfdb53789c9c6a4bb4c8Jan Engelhardt		addr = xtables_calloc(*naddr, sizeof(struct in_addr) * *naddr);
903bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt		for (i = 0; i < *naddr; i++)
904bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt			memcpy(&addr[i], host->h_addr_list[i],
905bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt			       sizeof(struct in_addr));
906bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt		return addr;
907bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	}
908bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt
909bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	return NULL;
910bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt}
911bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt
912bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardtstatic struct in_addr *
913bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardtipparse_hostnetwork(const char *name, unsigned int *naddrs)
914bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt{
915bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	struct in_addr *addrptmp, *addrp;
916bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt
917bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	if ((addrptmp = numeric_to_ipaddr(name)) != NULL ||
918bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	    (addrptmp = network_to_ipaddr(name)) != NULL) {
919630ef48037f3602333addfdb53789c9c6a4bb4c8Jan Engelhardt		addrp = xtables_malloc(sizeof(struct in_addr));
920bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt		memcpy(addrp, addrptmp, sizeof(*addrp));
921bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt		*naddrs = 1;
922bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt		return addrp;
923bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	}
924bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	if ((addrptmp = host_to_ipaddr(name, naddrs)) != NULL)
925bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt		return addrptmp;
926bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt
927bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	exit_error(PARAMETER_PROBLEM, "host/network `%s' not found", name);
928bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt}
929bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt
930bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardtstatic struct in_addr *parse_ipmask(const char *mask)
931bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt{
932bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	static struct in_addr maskaddr;
933bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	struct in_addr *addrp;
934bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	unsigned int bits;
935bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt
936bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	if (mask == NULL) {
937bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt		/* no mask at all defaults to 32 bits */
938bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt		maskaddr.s_addr = 0xFFFFFFFF;
939bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt		return &maskaddr;
940bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	}
941bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	if ((addrp = numeric_to_ipmask(mask)) != NULL)
942bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt		/* dotted_to_addr already returns a network byte order addr */
943bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt		return addrp;
9445f2922cfc0bbfbeb878f5c12e9fb3eb602ae5507Jan Engelhardt	if (!xtables_strtoui(mask, NULL, &bits, 0, 32))
945bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt		exit_error(PARAMETER_PROBLEM,
946bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt			   "invalid mask `%s' specified", mask);
947bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	if (bits != 0) {
948bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt		maskaddr.s_addr = htonl(0xFFFFFFFF << (32 - bits));
949bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt		return &maskaddr;
950bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	}
951bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt
952bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	maskaddr.s_addr = 0U;
953bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	return &maskaddr;
954bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt}
955bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt
956bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardtvoid ipparse_hostnetworkmask(const char *name, struct in_addr **addrpp,
957bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt                             struct in_addr *maskp, unsigned int *naddrs)
958bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt{
959bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	unsigned int i, j, k, n;
960bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	struct in_addr *addrp;
961bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	char buf[256], *p;
962bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt
963bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	strncpy(buf, name, sizeof(buf) - 1);
964bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	buf[sizeof(buf) - 1] = '\0';
965bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	if ((p = strrchr(buf, '/')) != NULL) {
966bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt		*p = '\0';
967bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt		addrp = parse_ipmask(p + 1);
968bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	} else {
969bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt		addrp = parse_ipmask(NULL);
970bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	}
971bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	memcpy(maskp, addrp, sizeof(*maskp));
972bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt
973bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	/* if a null mask is given, the name is ignored, like in "any/0" */
974bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	if (maskp->s_addr == 0U)
975bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt		strcpy(buf, "0.0.0.0");
976bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt
977bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	addrp = *addrpp = ipparse_hostnetwork(buf, naddrs);
978bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	n = *naddrs;
979bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	for (i = 0, j = 0; i < n; ++i) {
980bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt		addrp[j++].s_addr &= maskp->s_addr;
981bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt		for (k = 0; k < j - 1; ++k)
982bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt			if (addrp[k].s_addr == addrp[j-1].s_addr) {
983bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt				--*naddrs;
984bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt				--j;
985bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt				break;
986bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt			}
987bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	}
988bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt}
989bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt
990e44ea7faa17c10c68f14f5338a7cc6e3291a0ce7Jan Engelhardtconst char *xtables_ip6addr_to_numeric(const struct in6_addr *addrp)
99108b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt{
99208b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt	/* 0000:0000:0000:0000:0000:000.000.000.000
99308b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt	 * 0000:0000:0000:0000:0000:0000:0000:0000 */
99408b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt	static char buf[50+1];
99508b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt	return inet_ntop(AF_INET6, addrp, buf, sizeof(buf));
99608b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt}
99708b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt
99808b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardtstatic const char *ip6addr_to_host(const struct in6_addr *addr)
99908b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt{
100008b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt	static char hostname[NI_MAXHOST];
100108b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt	struct sockaddr_in6 saddr;
100208b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt	int err;
100308b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt
100408b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt	memset(&saddr, 0, sizeof(struct sockaddr_in6));
100508b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt	memcpy(&saddr.sin6_addr, addr, sizeof(*addr));
100608b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt	saddr.sin6_family = AF_INET6;
100708b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt
100808b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt	err = getnameinfo((const void *)&saddr, sizeof(struct sockaddr_in6),
100908b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt	      hostname, sizeof(hostname) - 1, NULL, 0, 0);
101008b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt	if (err != 0) {
101108b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt#ifdef DEBUG
101208b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt		fprintf(stderr,"IP2Name: %s\n",gai_strerror(err));
101308b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt#endif
101408b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt		return NULL;
101508b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt	}
101608b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt
101708b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt#ifdef DEBUG
101808b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt	fprintf (stderr, "\naddr2host: %s\n", hostname);
101908b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt#endif
102008b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt	return hostname;
102108b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt}
102208b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt
1023e44ea7faa17c10c68f14f5338a7cc6e3291a0ce7Jan Engelhardtconst char *xtables_ip6addr_to_anyname(const struct in6_addr *addr)
102408b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt{
102508b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt	const char *name;
102608b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt
102708b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt	if ((name = ip6addr_to_host(addr)) != NULL)
102808b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt		return name;
102908b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt
1030e44ea7faa17c10c68f14f5338a7cc6e3291a0ce7Jan Engelhardt	return xtables_ip6addr_to_numeric(addr);
103108b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt}
103208b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt
103308b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardtstatic int ip6addr_prefix_length(const struct in6_addr *k)
103408b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt{
103508b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt	unsigned int bits = 0;
103608b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt	uint32_t a, b, c, d;
103708b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt
103848607816796124ce2177ee22645d3fd8180f1e98Jan Engelhardt	a = ntohl(k->s6_addr32[0]);
103948607816796124ce2177ee22645d3fd8180f1e98Jan Engelhardt	b = ntohl(k->s6_addr32[1]);
104048607816796124ce2177ee22645d3fd8180f1e98Jan Engelhardt	c = ntohl(k->s6_addr32[2]);
104148607816796124ce2177ee22645d3fd8180f1e98Jan Engelhardt	d = ntohl(k->s6_addr32[3]);
104208b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt	while (a & 0x80000000U) {
104308b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt		++bits;
104408b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt		a <<= 1;
104508b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt		a  |= (b >> 31) & 1;
104608b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt		b <<= 1;
104708b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt		b  |= (c >> 31) & 1;
104808b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt		c <<= 1;
104908b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt		c  |= (d >> 31) & 1;
105008b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt		d <<= 1;
105108b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt	}
105208b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt	if (a != 0 || b != 0 || c != 0 || d != 0)
105308b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt		return -1;
105408b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt	return bits;
105508b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt}
105608b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt
1057e44ea7faa17c10c68f14f5338a7cc6e3291a0ce7Jan Engelhardtconst char *xtables_ip6mask_to_numeric(const struct in6_addr *addrp)
105808b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt{
105908b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt	static char buf[50+2];
106008b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt	int l = ip6addr_prefix_length(addrp);
106108b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt
106208b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt	if (l == -1) {
106308b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt		strcpy(buf, "/");
1064e44ea7faa17c10c68f14f5338a7cc6e3291a0ce7Jan Engelhardt		strcat(buf, xtables_ip6addr_to_numeric(addrp));
106508b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt		return buf;
106608b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt	}
106708b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt	sprintf(buf, "/%d", l);
106808b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt	return buf;
106908b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt}
1070bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt
1071bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardtstruct in6_addr *numeric_to_ip6addr(const char *num)
1072bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt{
1073bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	static struct in6_addr ap;
1074bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	int err;
1075bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt
1076bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	if ((err = inet_pton(AF_INET6, num, &ap)) == 1)
1077bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt		return &ap;
1078bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt#ifdef DEBUG
1079bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	fprintf(stderr, "\nnumeric2addr: %d\n", err);
1080bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt#endif
1081bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	return NULL;
1082bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt}
1083bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt
1084bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardtstatic struct in6_addr *
1085bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardthost_to_ip6addr(const char *name, unsigned int *naddr)
1086bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt{
1087bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	static struct in6_addr *addr;
1088bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	struct addrinfo hints;
1089bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	struct addrinfo *res;
1090bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	int err;
1091bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt
1092bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	memset(&hints, 0, sizeof(hints));
1093bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	hints.ai_flags    = AI_CANONNAME;
1094bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	hints.ai_family   = AF_INET6;
1095bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	hints.ai_socktype = SOCK_RAW;
1096bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	hints.ai_protocol = IPPROTO_IPV6;
1097bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	hints.ai_next     = NULL;
1098bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt
1099bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	*naddr = 0;
1100bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	if ((err = getaddrinfo(name, NULL, &hints, &res)) != 0) {
1101bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt#ifdef DEBUG
1102bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt		fprintf(stderr,"Name2IP: %s\n",gai_strerror(err));
1103bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt#endif
1104bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt		return NULL;
1105bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	} else {
1106bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt		if (res->ai_family != AF_INET6 ||
1107bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt		    res->ai_addrlen != sizeof(struct sockaddr_in6))
1108bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt			return NULL;
1109bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt
1110bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt#ifdef DEBUG
1111bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt		fprintf(stderr, "resolved: len=%d  %s ", res->ai_addrlen,
1112bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt		        ip6addr_to_numeric(&((struct sockaddr_in6 *)res->ai_addr)->sin6_addr));
1113bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt#endif
1114bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt		/* Get the first element of the address-chain */
1115630ef48037f3602333addfdb53789c9c6a4bb4c8Jan Engelhardt		addr = xtables_malloc(sizeof(struct in6_addr));
1116bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt		memcpy(addr, &((const struct sockaddr_in6 *)res->ai_addr)->sin6_addr,
1117bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt		       sizeof(struct in6_addr));
1118bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt		freeaddrinfo(res);
1119bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt		*naddr = 1;
1120bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt		return addr;
1121bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	}
1122bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt
1123bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	return NULL;
1124bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt}
1125bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt
1126bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardtstatic struct in6_addr *network_to_ip6addr(const char *name)
1127bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt{
1128bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	/*	abort();*/
1129bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	/* TODO: not implemented yet, but the exception breaks the
1130bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	 *       name resolvation */
1131bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	return NULL;
1132bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt}
1133bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt
1134bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardtstatic struct in6_addr *
1135bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardtip6parse_hostnetwork(const char *name, unsigned int *naddrs)
1136bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt{
1137bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	struct in6_addr *addrp, *addrptmp;
1138bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt
1139bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	if ((addrptmp = numeric_to_ip6addr(name)) != NULL ||
1140bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	    (addrptmp = network_to_ip6addr(name)) != NULL) {
1141630ef48037f3602333addfdb53789c9c6a4bb4c8Jan Engelhardt		addrp = xtables_malloc(sizeof(struct in6_addr));
1142bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt		memcpy(addrp, addrptmp, sizeof(*addrp));
1143bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt		*naddrs = 1;
1144bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt		return addrp;
1145bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	}
1146bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	if ((addrp = host_to_ip6addr(name, naddrs)) != NULL)
1147bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt		return addrp;
1148bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt
1149bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	exit_error(PARAMETER_PROBLEM, "host/network `%s' not found", name);
1150bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt}
1151bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt
1152bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardtstatic struct in6_addr *parse_ip6mask(char *mask)
1153bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt{
1154bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	static struct in6_addr maskaddr;
1155bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	struct in6_addr *addrp;
1156bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	unsigned int bits;
1157bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt
1158bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	if (mask == NULL) {
1159bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt		/* no mask at all defaults to 128 bits */
1160bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt		memset(&maskaddr, 0xff, sizeof maskaddr);
1161bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt		return &maskaddr;
1162bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	}
1163bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	if ((addrp = numeric_to_ip6addr(mask)) != NULL)
1164bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt		return addrp;
11655f2922cfc0bbfbeb878f5c12e9fb3eb602ae5507Jan Engelhardt	if (!xtables_strtoui(mask, NULL, &bits, 0, 128))
1166bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt		exit_error(PARAMETER_PROBLEM,
1167bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt			   "invalid mask `%s' specified", mask);
1168bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	if (bits != 0) {
1169bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt		char *p = (void *)&maskaddr;
1170bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt		memset(p, 0xff, bits / 8);
1171bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt		memset(p + (bits / 8) + 1, 0, (128 - bits) / 8);
1172bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt		p[bits/8] = 0xff << (8 - (bits & 7));
1173bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt		return &maskaddr;
1174bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	}
1175bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt
1176bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	memset(&maskaddr, 0, sizeof(maskaddr));
1177bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	return &maskaddr;
1178bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt}
1179bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt
1180bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardtvoid ip6parse_hostnetworkmask(const char *name, struct in6_addr **addrpp,
1181bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt                              struct in6_addr *maskp, unsigned int *naddrs)
1182bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt{
1183bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	struct in6_addr *addrp;
1184bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	unsigned int i, j, k, n;
1185bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	char buf[256], *p;
1186bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt
1187bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	strncpy(buf, name, sizeof(buf) - 1);
1188bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	buf[sizeof(buf)-1] = '\0';
1189bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	if ((p = strrchr(buf, '/')) != NULL) {
1190bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt		*p = '\0';
1191bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt		addrp = parse_ip6mask(p + 1);
1192bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	} else {
1193bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt		addrp = parse_ip6mask(NULL);
1194bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	}
1195bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	memcpy(maskp, addrp, sizeof(*maskp));
1196bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt
1197bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	/* if a null mask is given, the name is ignored, like in "any/0" */
1198bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	if (memcmp(maskp, &in6addr_any, sizeof(in6addr_any)) == 0)
1199bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt		strcpy(buf, "::");
1200bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt
1201bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	addrp = *addrpp = ip6parse_hostnetwork(buf, naddrs);
1202bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	n = *naddrs;
1203bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	for (i = 0, j = 0; i < n; ++i) {
1204bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt		for (k = 0; k < 4; ++k)
12055a2208c3e62a150e6f6297abbfa63056ab4a8066Yasuyuki Kozakai			addrp[j].s6_addr32[k] &= maskp->s6_addr32[k];
1206bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt		++j;
1207bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt		for (k = 0; k < j - 1; ++k)
1208bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt			if (IN6_ARE_ADDR_EQUAL(&addrp[k], &addrp[j - 1])) {
1209bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt				--*naddrs;
1210bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt				--j;
1211bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt				break;
1212bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt			}
1213bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	}
1214bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt}
1215a5d099400fd6f9ad3880dda10f85d2aa36b5ec65Max Kellermann
1216a5d099400fd6f9ad3880dda10f85d2aa36b5ec65Max Kellermannvoid save_string(const char *value)
1217a5d099400fd6f9ad3880dda10f85d2aa36b5ec65Max Kellermann{
1218a5d099400fd6f9ad3880dda10f85d2aa36b5ec65Max Kellermann	static const char no_quote_chars[] = "_-0123456789"
1219a5d099400fd6f9ad3880dda10f85d2aa36b5ec65Max Kellermann		"abcdefghijklmnopqrstuvwxyz"
1220a5d099400fd6f9ad3880dda10f85d2aa36b5ec65Max Kellermann		"ABCDEFGHIJKLMNOPQRSTUVWXYZ";
1221a5d099400fd6f9ad3880dda10f85d2aa36b5ec65Max Kellermann	static const char escape_chars[] = "\"\\'";
1222a5d099400fd6f9ad3880dda10f85d2aa36b5ec65Max Kellermann	size_t length;
1223a5d099400fd6f9ad3880dda10f85d2aa36b5ec65Max Kellermann	const char *p;
1224a5d099400fd6f9ad3880dda10f85d2aa36b5ec65Max Kellermann
1225a5d099400fd6f9ad3880dda10f85d2aa36b5ec65Max Kellermann	length = strcspn(value, no_quote_chars);
1226a5d099400fd6f9ad3880dda10f85d2aa36b5ec65Max Kellermann	if (length > 0 && value[length] == 0) {
1227a5d099400fd6f9ad3880dda10f85d2aa36b5ec65Max Kellermann		/* no quoting required */
1228a5d099400fd6f9ad3880dda10f85d2aa36b5ec65Max Kellermann		fputs(value, stdout);
1229a5d099400fd6f9ad3880dda10f85d2aa36b5ec65Max Kellermann		putchar(' ');
1230a5d099400fd6f9ad3880dda10f85d2aa36b5ec65Max Kellermann	} else {
1231a5d099400fd6f9ad3880dda10f85d2aa36b5ec65Max Kellermann		/* there is at least one dangerous character in the
1232a5d099400fd6f9ad3880dda10f85d2aa36b5ec65Max Kellermann		   value, which we have to quote.  Write double quotes
1233a5d099400fd6f9ad3880dda10f85d2aa36b5ec65Max Kellermann		   around the value and escape special characters with
1234a5d099400fd6f9ad3880dda10f85d2aa36b5ec65Max Kellermann		   a backslash */
1235a5d099400fd6f9ad3880dda10f85d2aa36b5ec65Max Kellermann		putchar('"');
1236a5d099400fd6f9ad3880dda10f85d2aa36b5ec65Max Kellermann
1237a5d099400fd6f9ad3880dda10f85d2aa36b5ec65Max Kellermann		for (p = strpbrk(value, escape_chars); p != NULL;
1238a5d099400fd6f9ad3880dda10f85d2aa36b5ec65Max Kellermann		     p = strpbrk(value, escape_chars)) {
1239a5d099400fd6f9ad3880dda10f85d2aa36b5ec65Max Kellermann			if (p > value)
1240a5d099400fd6f9ad3880dda10f85d2aa36b5ec65Max Kellermann				fwrite(value, 1, p - value, stdout);
1241a5d099400fd6f9ad3880dda10f85d2aa36b5ec65Max Kellermann			putchar('\\');
1242a5d099400fd6f9ad3880dda10f85d2aa36b5ec65Max Kellermann			putchar(*p);
1243a5d099400fd6f9ad3880dda10f85d2aa36b5ec65Max Kellermann			value = p + 1;
1244a5d099400fd6f9ad3880dda10f85d2aa36b5ec65Max Kellermann		}
1245a5d099400fd6f9ad3880dda10f85d2aa36b5ec65Max Kellermann
1246a5d099400fd6f9ad3880dda10f85d2aa36b5ec65Max Kellermann		/* print the rest and finish the double quoted
1247a5d099400fd6f9ad3880dda10f85d2aa36b5ec65Max Kellermann		   string */
1248a5d099400fd6f9ad3880dda10f85d2aa36b5ec65Max Kellermann		fputs(value, stdout);
1249a5d099400fd6f9ad3880dda10f85d2aa36b5ec65Max Kellermann		printf("\" ");
1250a5d099400fd6f9ad3880dda10f85d2aa36b5ec65Max Kellermann	}
1251a5d099400fd6f9ad3880dda10f85d2aa36b5ec65Max Kellermann}
1252