xtables.c revision 213e185afbb298e6708881e4c2adffdc47a8b6da
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
470d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAIchar *lib_dir;
480d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI
490b82e8e81e887843011c8771f70d2302901f7e5eYasuyuki KOZAKAI/* the path to command to load kernel module */
50dbb77543ad6afe29e9a1881b2d4fc212de621a55Jan Engelhardtconst char *modprobe_program = NULL;
510b82e8e81e887843011c8771f70d2302901f7e5eYasuyuki KOZAKAI
520d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI/* Keeping track of external matches and targets: linked lists.  */
530d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAIstruct xtables_match *xtables_matches;
540d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAIstruct xtables_target *xtables_targets;
550d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI
563dfa4488b032fc32aaf2470f48ac1fc3a534794fYasuyuki KOZAKAIvoid *fw_calloc(size_t count, size_t size)
573dfa4488b032fc32aaf2470f48ac1fc3a534794fYasuyuki KOZAKAI{
583dfa4488b032fc32aaf2470f48ac1fc3a534794fYasuyuki KOZAKAI	void *p;
593dfa4488b032fc32aaf2470f48ac1fc3a534794fYasuyuki KOZAKAI
603dfa4488b032fc32aaf2470f48ac1fc3a534794fYasuyuki KOZAKAI	if ((p = calloc(count, size)) == NULL) {
613dfa4488b032fc32aaf2470f48ac1fc3a534794fYasuyuki KOZAKAI		perror("ip[6]tables: calloc failed");
623dfa4488b032fc32aaf2470f48ac1fc3a534794fYasuyuki KOZAKAI		exit(1);
633dfa4488b032fc32aaf2470f48ac1fc3a534794fYasuyuki KOZAKAI	}
643dfa4488b032fc32aaf2470f48ac1fc3a534794fYasuyuki KOZAKAI
653dfa4488b032fc32aaf2470f48ac1fc3a534794fYasuyuki KOZAKAI	return p;
663dfa4488b032fc32aaf2470f48ac1fc3a534794fYasuyuki KOZAKAI}
673dfa4488b032fc32aaf2470f48ac1fc3a534794fYasuyuki KOZAKAI
683dfa4488b032fc32aaf2470f48ac1fc3a534794fYasuyuki KOZAKAIvoid *fw_malloc(size_t size)
693dfa4488b032fc32aaf2470f48ac1fc3a534794fYasuyuki KOZAKAI{
703dfa4488b032fc32aaf2470f48ac1fc3a534794fYasuyuki KOZAKAI	void *p;
713dfa4488b032fc32aaf2470f48ac1fc3a534794fYasuyuki KOZAKAI
723dfa4488b032fc32aaf2470f48ac1fc3a534794fYasuyuki KOZAKAI	if ((p = malloc(size)) == NULL) {
733dfa4488b032fc32aaf2470f48ac1fc3a534794fYasuyuki KOZAKAI		perror("ip[6]tables: malloc failed");
743dfa4488b032fc32aaf2470f48ac1fc3a534794fYasuyuki KOZAKAI		exit(1);
753dfa4488b032fc32aaf2470f48ac1fc3a534794fYasuyuki KOZAKAI	}
763dfa4488b032fc32aaf2470f48ac1fc3a534794fYasuyuki KOZAKAI
773dfa4488b032fc32aaf2470f48ac1fc3a534794fYasuyuki KOZAKAI	return p;
783dfa4488b032fc32aaf2470f48ac1fc3a534794fYasuyuki KOZAKAI}
790b82e8e81e887843011c8771f70d2302901f7e5eYasuyuki KOZAKAI
800b82e8e81e887843011c8771f70d2302901f7e5eYasuyuki KOZAKAIstatic char *get_modprobe(void)
810b82e8e81e887843011c8771f70d2302901f7e5eYasuyuki KOZAKAI{
820b82e8e81e887843011c8771f70d2302901f7e5eYasuyuki KOZAKAI	int procfile;
830b82e8e81e887843011c8771f70d2302901f7e5eYasuyuki KOZAKAI	char *ret;
840b82e8e81e887843011c8771f70d2302901f7e5eYasuyuki KOZAKAI
850b82e8e81e887843011c8771f70d2302901f7e5eYasuyuki KOZAKAI#define PROCFILE_BUFSIZ	1024
860b82e8e81e887843011c8771f70d2302901f7e5eYasuyuki KOZAKAI	procfile = open(PROC_SYS_MODPROBE, O_RDONLY);
870b82e8e81e887843011c8771f70d2302901f7e5eYasuyuki KOZAKAI	if (procfile < 0)
880b82e8e81e887843011c8771f70d2302901f7e5eYasuyuki KOZAKAI		return NULL;
890b82e8e81e887843011c8771f70d2302901f7e5eYasuyuki KOZAKAI
900b82e8e81e887843011c8771f70d2302901f7e5eYasuyuki KOZAKAI	ret = (char *) malloc(PROCFILE_BUFSIZ);
910b82e8e81e887843011c8771f70d2302901f7e5eYasuyuki KOZAKAI	if (ret) {
920b82e8e81e887843011c8771f70d2302901f7e5eYasuyuki KOZAKAI		memset(ret, 0, PROCFILE_BUFSIZ);
930b82e8e81e887843011c8771f70d2302901f7e5eYasuyuki KOZAKAI		switch (read(procfile, ret, PROCFILE_BUFSIZ)) {
940b82e8e81e887843011c8771f70d2302901f7e5eYasuyuki KOZAKAI		case -1: goto fail;
950b82e8e81e887843011c8771f70d2302901f7e5eYasuyuki KOZAKAI		case PROCFILE_BUFSIZ: goto fail; /* Partial read.  Wierd */
960b82e8e81e887843011c8771f70d2302901f7e5eYasuyuki KOZAKAI		}
970b82e8e81e887843011c8771f70d2302901f7e5eYasuyuki KOZAKAI		if (ret[strlen(ret)-1]=='\n')
980b82e8e81e887843011c8771f70d2302901f7e5eYasuyuki KOZAKAI			ret[strlen(ret)-1]=0;
990b82e8e81e887843011c8771f70d2302901f7e5eYasuyuki KOZAKAI		close(procfile);
1000b82e8e81e887843011c8771f70d2302901f7e5eYasuyuki KOZAKAI		return ret;
1010b82e8e81e887843011c8771f70d2302901f7e5eYasuyuki KOZAKAI	}
1020b82e8e81e887843011c8771f70d2302901f7e5eYasuyuki KOZAKAI fail:
1030b82e8e81e887843011c8771f70d2302901f7e5eYasuyuki KOZAKAI	free(ret);
1040b82e8e81e887843011c8771f70d2302901f7e5eYasuyuki KOZAKAI	close(procfile);
1050b82e8e81e887843011c8771f70d2302901f7e5eYasuyuki KOZAKAI	return NULL;
1060b82e8e81e887843011c8771f70d2302901f7e5eYasuyuki KOZAKAI}
1070b82e8e81e887843011c8771f70d2302901f7e5eYasuyuki KOZAKAI
1080b82e8e81e887843011c8771f70d2302901f7e5eYasuyuki KOZAKAIint xtables_insmod(const char *modname, const char *modprobe, int quiet)
1090b82e8e81e887843011c8771f70d2302901f7e5eYasuyuki KOZAKAI{
1100b82e8e81e887843011c8771f70d2302901f7e5eYasuyuki KOZAKAI	char *buf = NULL;
1110b82e8e81e887843011c8771f70d2302901f7e5eYasuyuki KOZAKAI	char *argv[4];
1120b82e8e81e887843011c8771f70d2302901f7e5eYasuyuki KOZAKAI	int status;
1130b82e8e81e887843011c8771f70d2302901f7e5eYasuyuki KOZAKAI
1140b82e8e81e887843011c8771f70d2302901f7e5eYasuyuki KOZAKAI	/* If they don't explicitly set it, read out of kernel */
1150b82e8e81e887843011c8771f70d2302901f7e5eYasuyuki KOZAKAI	if (!modprobe) {
1160b82e8e81e887843011c8771f70d2302901f7e5eYasuyuki KOZAKAI		buf = get_modprobe();
1170b82e8e81e887843011c8771f70d2302901f7e5eYasuyuki KOZAKAI		if (!buf)
1180b82e8e81e887843011c8771f70d2302901f7e5eYasuyuki KOZAKAI			return -1;
1190b82e8e81e887843011c8771f70d2302901f7e5eYasuyuki KOZAKAI		modprobe = buf;
1200b82e8e81e887843011c8771f70d2302901f7e5eYasuyuki KOZAKAI	}
1210b82e8e81e887843011c8771f70d2302901f7e5eYasuyuki KOZAKAI
1220b82e8e81e887843011c8771f70d2302901f7e5eYasuyuki KOZAKAI	switch (fork()) {
1230b82e8e81e887843011c8771f70d2302901f7e5eYasuyuki KOZAKAI	case 0:
1240b82e8e81e887843011c8771f70d2302901f7e5eYasuyuki KOZAKAI		argv[0] = (char *)modprobe;
1250b82e8e81e887843011c8771f70d2302901f7e5eYasuyuki KOZAKAI		argv[1] = (char *)modname;
1260b82e8e81e887843011c8771f70d2302901f7e5eYasuyuki KOZAKAI		if (quiet) {
1270b82e8e81e887843011c8771f70d2302901f7e5eYasuyuki KOZAKAI			argv[2] = "-q";
1280b82e8e81e887843011c8771f70d2302901f7e5eYasuyuki KOZAKAI			argv[3] = NULL;
1290b82e8e81e887843011c8771f70d2302901f7e5eYasuyuki KOZAKAI		} else {
1300b82e8e81e887843011c8771f70d2302901f7e5eYasuyuki KOZAKAI			argv[2] = NULL;
1310b82e8e81e887843011c8771f70d2302901f7e5eYasuyuki KOZAKAI			argv[3] = NULL;
1320b82e8e81e887843011c8771f70d2302901f7e5eYasuyuki KOZAKAI		}
1330b82e8e81e887843011c8771f70d2302901f7e5eYasuyuki KOZAKAI		execv(argv[0], argv);
1340b82e8e81e887843011c8771f70d2302901f7e5eYasuyuki KOZAKAI
1350b82e8e81e887843011c8771f70d2302901f7e5eYasuyuki KOZAKAI		/* not usually reached */
1360b82e8e81e887843011c8771f70d2302901f7e5eYasuyuki KOZAKAI		exit(1);
1370b82e8e81e887843011c8771f70d2302901f7e5eYasuyuki KOZAKAI	case -1:
1380b82e8e81e887843011c8771f70d2302901f7e5eYasuyuki KOZAKAI		return -1;
1390b82e8e81e887843011c8771f70d2302901f7e5eYasuyuki KOZAKAI
1400b82e8e81e887843011c8771f70d2302901f7e5eYasuyuki KOZAKAI	default: /* parent */
1410b82e8e81e887843011c8771f70d2302901f7e5eYasuyuki KOZAKAI		wait(&status);
1420b82e8e81e887843011c8771f70d2302901f7e5eYasuyuki KOZAKAI	}
1430b82e8e81e887843011c8771f70d2302901f7e5eYasuyuki KOZAKAI
1440b82e8e81e887843011c8771f70d2302901f7e5eYasuyuki KOZAKAI	free(buf);
1450b82e8e81e887843011c8771f70d2302901f7e5eYasuyuki KOZAKAI	if (WIFEXITED(status) && WEXITSTATUS(status) == 0)
1460b82e8e81e887843011c8771f70d2302901f7e5eYasuyuki KOZAKAI		return 0;
1470b82e8e81e887843011c8771f70d2302901f7e5eYasuyuki KOZAKAI	return -1;
1480b82e8e81e887843011c8771f70d2302901f7e5eYasuyuki KOZAKAI}
1490b82e8e81e887843011c8771f70d2302901f7e5eYasuyuki KOZAKAI
1500d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAIint load_xtables_ko(const char *modprobe, int quiet)
1510d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI{
1520d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI	static int loaded = 0;
1530d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI	static int ret = -1;
1540d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI
1550d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI	if (!loaded) {
1560d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI		ret = xtables_insmod(afinfo.kmod, modprobe, quiet);
1570d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI		loaded = (ret == 0);
1580d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI	}
1590d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI
1600d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI	return ret;
1610d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI}
1620d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI
16304f8c54dc52e19096d31d94593bd1040716afe4dYasuyuki KOZAKAIint string_to_number_ll(const char *s, unsigned long long min,
16404f8c54dc52e19096d31d94593bd1040716afe4dYasuyuki KOZAKAI			unsigned long long max, unsigned long long *ret)
16504f8c54dc52e19096d31d94593bd1040716afe4dYasuyuki KOZAKAI{
16604f8c54dc52e19096d31d94593bd1040716afe4dYasuyuki KOZAKAI	unsigned long long number;
16704f8c54dc52e19096d31d94593bd1040716afe4dYasuyuki KOZAKAI	char *end;
16804f8c54dc52e19096d31d94593bd1040716afe4dYasuyuki KOZAKAI
16904f8c54dc52e19096d31d94593bd1040716afe4dYasuyuki KOZAKAI	/* Handle hex, octal, etc. */
17004f8c54dc52e19096d31d94593bd1040716afe4dYasuyuki KOZAKAI	errno = 0;
17104f8c54dc52e19096d31d94593bd1040716afe4dYasuyuki KOZAKAI	number = strtoull(s, &end, 0);
17204f8c54dc52e19096d31d94593bd1040716afe4dYasuyuki KOZAKAI	if (*end == '\0' && end != s) {
17304f8c54dc52e19096d31d94593bd1040716afe4dYasuyuki KOZAKAI		/* we parsed a number, let's see if we want this */
17404f8c54dc52e19096d31d94593bd1040716afe4dYasuyuki KOZAKAI		if (errno != ERANGE && min <= number && (!max || number <= max)) {
17504f8c54dc52e19096d31d94593bd1040716afe4dYasuyuki KOZAKAI			*ret = number;
17604f8c54dc52e19096d31d94593bd1040716afe4dYasuyuki KOZAKAI			return 0;
17704f8c54dc52e19096d31d94593bd1040716afe4dYasuyuki KOZAKAI		}
17804f8c54dc52e19096d31d94593bd1040716afe4dYasuyuki KOZAKAI	}
17904f8c54dc52e19096d31d94593bd1040716afe4dYasuyuki KOZAKAI	return -1;
18004f8c54dc52e19096d31d94593bd1040716afe4dYasuyuki KOZAKAI}
18104f8c54dc52e19096d31d94593bd1040716afe4dYasuyuki KOZAKAI
18204f8c54dc52e19096d31d94593bd1040716afe4dYasuyuki KOZAKAIint string_to_number_l(const char *s, unsigned long min, unsigned long max,
18304f8c54dc52e19096d31d94593bd1040716afe4dYasuyuki KOZAKAI		       unsigned long *ret)
18404f8c54dc52e19096d31d94593bd1040716afe4dYasuyuki KOZAKAI{
18504f8c54dc52e19096d31d94593bd1040716afe4dYasuyuki KOZAKAI	int result;
18604f8c54dc52e19096d31d94593bd1040716afe4dYasuyuki KOZAKAI	unsigned long long number;
18704f8c54dc52e19096d31d94593bd1040716afe4dYasuyuki KOZAKAI
18804f8c54dc52e19096d31d94593bd1040716afe4dYasuyuki KOZAKAI	result = string_to_number_ll(s, min, max, &number);
18904f8c54dc52e19096d31d94593bd1040716afe4dYasuyuki KOZAKAI	*ret = (unsigned long)number;
19004f8c54dc52e19096d31d94593bd1040716afe4dYasuyuki KOZAKAI
19104f8c54dc52e19096d31d94593bd1040716afe4dYasuyuki KOZAKAI	return result;
19204f8c54dc52e19096d31d94593bd1040716afe4dYasuyuki KOZAKAI}
19304f8c54dc52e19096d31d94593bd1040716afe4dYasuyuki KOZAKAI
19404f8c54dc52e19096d31d94593bd1040716afe4dYasuyuki KOZAKAIint string_to_number(const char *s, unsigned int min, unsigned int max,
19504f8c54dc52e19096d31d94593bd1040716afe4dYasuyuki KOZAKAI		unsigned int *ret)
19604f8c54dc52e19096d31d94593bd1040716afe4dYasuyuki KOZAKAI{
19704f8c54dc52e19096d31d94593bd1040716afe4dYasuyuki KOZAKAI	int result;
19804f8c54dc52e19096d31d94593bd1040716afe4dYasuyuki KOZAKAI	unsigned long number;
19904f8c54dc52e19096d31d94593bd1040716afe4dYasuyuki KOZAKAI
20004f8c54dc52e19096d31d94593bd1040716afe4dYasuyuki KOZAKAI	result = string_to_number_l(s, min, max, &number);
20104f8c54dc52e19096d31d94593bd1040716afe4dYasuyuki KOZAKAI	*ret = (unsigned int)number;
20204f8c54dc52e19096d31d94593bd1040716afe4dYasuyuki KOZAKAI
20304f8c54dc52e19096d31d94593bd1040716afe4dYasuyuki KOZAKAI	return result;
20404f8c54dc52e19096d31d94593bd1040716afe4dYasuyuki KOZAKAI}
20504f8c54dc52e19096d31d94593bd1040716afe4dYasuyuki KOZAKAI
206cd9e7aa106e80c44bd526af74b616701b0772d05Jan Engelhardt/*
207cd9e7aa106e80c44bd526af74b616701b0772d05Jan Engelhardt * strtonum{,l} - string to number conversion
208cd9e7aa106e80c44bd526af74b616701b0772d05Jan Engelhardt *
209cd9e7aa106e80c44bd526af74b616701b0772d05Jan Engelhardt * If @end is NULL, we assume the caller does not want
210cd9e7aa106e80c44bd526af74b616701b0772d05Jan Engelhardt * a case like "15a", so reject it.
211cd9e7aa106e80c44bd526af74b616701b0772d05Jan Engelhardt */
212cd9e7aa106e80c44bd526af74b616701b0772d05Jan Engelhardtbool strtonuml(const char *s, char **end, unsigned long *value,
213cd9e7aa106e80c44bd526af74b616701b0772d05Jan Engelhardt               unsigned long min, unsigned long max)
214cd9e7aa106e80c44bd526af74b616701b0772d05Jan Engelhardt{
215cd9e7aa106e80c44bd526af74b616701b0772d05Jan Engelhardt	unsigned long v;
216cd9e7aa106e80c44bd526af74b616701b0772d05Jan Engelhardt	char *my_end;
217cd9e7aa106e80c44bd526af74b616701b0772d05Jan Engelhardt
218cd9e7aa106e80c44bd526af74b616701b0772d05Jan Engelhardt	errno = 0;
219cd9e7aa106e80c44bd526af74b616701b0772d05Jan Engelhardt	v = strtoul(s, &my_end, 0);
220cd9e7aa106e80c44bd526af74b616701b0772d05Jan Engelhardt
221cd9e7aa106e80c44bd526af74b616701b0772d05Jan Engelhardt	if (my_end == s)
222cd9e7aa106e80c44bd526af74b616701b0772d05Jan Engelhardt		return false;
223cd9e7aa106e80c44bd526af74b616701b0772d05Jan Engelhardt	if (end != NULL)
224cd9e7aa106e80c44bd526af74b616701b0772d05Jan Engelhardt		*end = my_end;
225cd9e7aa106e80c44bd526af74b616701b0772d05Jan Engelhardt
226cd9e7aa106e80c44bd526af74b616701b0772d05Jan Engelhardt	if (errno != ERANGE && min <= v && (max == 0 || v <= max)) {
227cd9e7aa106e80c44bd526af74b616701b0772d05Jan Engelhardt		if (value != NULL)
228cd9e7aa106e80c44bd526af74b616701b0772d05Jan Engelhardt			*value = v;
229cd9e7aa106e80c44bd526af74b616701b0772d05Jan Engelhardt		if (end == NULL)
230cd9e7aa106e80c44bd526af74b616701b0772d05Jan Engelhardt			return *my_end == '\0';
231cd9e7aa106e80c44bd526af74b616701b0772d05Jan Engelhardt		return true;
232cd9e7aa106e80c44bd526af74b616701b0772d05Jan Engelhardt	}
233cd9e7aa106e80c44bd526af74b616701b0772d05Jan Engelhardt
234cd9e7aa106e80c44bd526af74b616701b0772d05Jan Engelhardt	return false;
235cd9e7aa106e80c44bd526af74b616701b0772d05Jan Engelhardt}
236cd9e7aa106e80c44bd526af74b616701b0772d05Jan Engelhardt
237cd9e7aa106e80c44bd526af74b616701b0772d05Jan Engelhardtbool strtonum(const char *s, char **end, unsigned int *value,
238cd9e7aa106e80c44bd526af74b616701b0772d05Jan Engelhardt                  unsigned int min, unsigned int max)
239cd9e7aa106e80c44bd526af74b616701b0772d05Jan Engelhardt{
240cd9e7aa106e80c44bd526af74b616701b0772d05Jan Engelhardt	unsigned long v;
241cd9e7aa106e80c44bd526af74b616701b0772d05Jan Engelhardt	bool ret;
242cd9e7aa106e80c44bd526af74b616701b0772d05Jan Engelhardt
243cd9e7aa106e80c44bd526af74b616701b0772d05Jan Engelhardt	ret = strtonuml(s, end, &v, min, max);
244cd9e7aa106e80c44bd526af74b616701b0772d05Jan Engelhardt	if (value != NULL)
245cd9e7aa106e80c44bd526af74b616701b0772d05Jan Engelhardt		*value = v;
246cd9e7aa106e80c44bd526af74b616701b0772d05Jan Engelhardt	return ret;
247cd9e7aa106e80c44bd526af74b616701b0772d05Jan Engelhardt}
248cd9e7aa106e80c44bd526af74b616701b0772d05Jan Engelhardt
24904f8c54dc52e19096d31d94593bd1040716afe4dYasuyuki KOZAKAIint service_to_port(const char *name, const char *proto)
25004f8c54dc52e19096d31d94593bd1040716afe4dYasuyuki KOZAKAI{
25104f8c54dc52e19096d31d94593bd1040716afe4dYasuyuki KOZAKAI	struct servent *service;
25204f8c54dc52e19096d31d94593bd1040716afe4dYasuyuki KOZAKAI
25304f8c54dc52e19096d31d94593bd1040716afe4dYasuyuki KOZAKAI	if ((service = getservbyname(name, proto)) != NULL)
25404f8c54dc52e19096d31d94593bd1040716afe4dYasuyuki KOZAKAI		return ntohs((unsigned short) service->s_port);
25504f8c54dc52e19096d31d94593bd1040716afe4dYasuyuki KOZAKAI
25604f8c54dc52e19096d31d94593bd1040716afe4dYasuyuki KOZAKAI	return -1;
25704f8c54dc52e19096d31d94593bd1040716afe4dYasuyuki KOZAKAI}
25804f8c54dc52e19096d31d94593bd1040716afe4dYasuyuki KOZAKAI
25904f8c54dc52e19096d31d94593bd1040716afe4dYasuyuki KOZAKAIu_int16_t parse_port(const char *port, const char *proto)
26004f8c54dc52e19096d31d94593bd1040716afe4dYasuyuki KOZAKAI{
2617a236f4cc685a420c1a782a5db614a93baf37ccfJan Engelhardt	unsigned int portnum;
26204f8c54dc52e19096d31d94593bd1040716afe4dYasuyuki KOZAKAI
26304f8c54dc52e19096d31d94593bd1040716afe4dYasuyuki KOZAKAI	if ((string_to_number(port, 0, 65535, &portnum)) != -1 ||
2649ee386a1b6d7704b259460152c959ab0e79e02aaMax Kellermann	    (portnum = service_to_port(port, proto)) != (unsigned)-1)
265213e185afbb298e6708881e4c2adffdc47a8b6daJan Engelhardt		return portnum;
26604f8c54dc52e19096d31d94593bd1040716afe4dYasuyuki KOZAKAI
26704f8c54dc52e19096d31d94593bd1040716afe4dYasuyuki KOZAKAI	exit_error(PARAMETER_PROBLEM,
26804f8c54dc52e19096d31d94593bd1040716afe4dYasuyuki KOZAKAI		   "invalid port/service `%s' specified", port);
26904f8c54dc52e19096d31d94593bd1040716afe4dYasuyuki KOZAKAI}
27004f8c54dc52e19096d31d94593bd1040716afe4dYasuyuki KOZAKAI
27104f8c54dc52e19096d31d94593bd1040716afe4dYasuyuki KOZAKAIvoid parse_interface(const char *arg, char *vianame, unsigned char *mask)
27204f8c54dc52e19096d31d94593bd1040716afe4dYasuyuki KOZAKAI{
27304f8c54dc52e19096d31d94593bd1040716afe4dYasuyuki KOZAKAI	int vialen = strlen(arg);
27404f8c54dc52e19096d31d94593bd1040716afe4dYasuyuki KOZAKAI	unsigned int i;
27504f8c54dc52e19096d31d94593bd1040716afe4dYasuyuki KOZAKAI
27604f8c54dc52e19096d31d94593bd1040716afe4dYasuyuki KOZAKAI	memset(mask, 0, IFNAMSIZ);
27704f8c54dc52e19096d31d94593bd1040716afe4dYasuyuki KOZAKAI	memset(vianame, 0, IFNAMSIZ);
27804f8c54dc52e19096d31d94593bd1040716afe4dYasuyuki KOZAKAI
27904f8c54dc52e19096d31d94593bd1040716afe4dYasuyuki KOZAKAI	if (vialen + 1 > IFNAMSIZ)
28004f8c54dc52e19096d31d94593bd1040716afe4dYasuyuki KOZAKAI		exit_error(PARAMETER_PROBLEM,
28104f8c54dc52e19096d31d94593bd1040716afe4dYasuyuki KOZAKAI			   "interface name `%s' must be shorter than IFNAMSIZ"
28204f8c54dc52e19096d31d94593bd1040716afe4dYasuyuki KOZAKAI			   " (%i)", arg, IFNAMSIZ-1);
28304f8c54dc52e19096d31d94593bd1040716afe4dYasuyuki KOZAKAI
28404f8c54dc52e19096d31d94593bd1040716afe4dYasuyuki KOZAKAI	strcpy(vianame, arg);
28504f8c54dc52e19096d31d94593bd1040716afe4dYasuyuki KOZAKAI	if ((vialen == 0) || (vialen == 1 && vianame[0] == '+'))
28604f8c54dc52e19096d31d94593bd1040716afe4dYasuyuki KOZAKAI		memset(mask, 0, IFNAMSIZ);
28704f8c54dc52e19096d31d94593bd1040716afe4dYasuyuki KOZAKAI	else if (vianame[vialen - 1] == '+') {
28804f8c54dc52e19096d31d94593bd1040716afe4dYasuyuki KOZAKAI		memset(mask, 0xFF, vialen - 1);
28904f8c54dc52e19096d31d94593bd1040716afe4dYasuyuki KOZAKAI		memset(mask + vialen - 1, 0, IFNAMSIZ - vialen + 1);
29004f8c54dc52e19096d31d94593bd1040716afe4dYasuyuki KOZAKAI		/* Don't remove `+' here! -HW */
29104f8c54dc52e19096d31d94593bd1040716afe4dYasuyuki KOZAKAI	} else {
29204f8c54dc52e19096d31d94593bd1040716afe4dYasuyuki KOZAKAI		/* Include nul-terminator in match */
29304f8c54dc52e19096d31d94593bd1040716afe4dYasuyuki KOZAKAI		memset(mask, 0xFF, vialen + 1);
29404f8c54dc52e19096d31d94593bd1040716afe4dYasuyuki KOZAKAI		memset(mask + vialen + 1, 0, IFNAMSIZ - vialen - 1);
29504f8c54dc52e19096d31d94593bd1040716afe4dYasuyuki KOZAKAI		for (i = 0; vianame[i]; i++) {
29604f8c54dc52e19096d31d94593bd1040716afe4dYasuyuki KOZAKAI			if (vianame[i] == ':' ||
29704f8c54dc52e19096d31d94593bd1040716afe4dYasuyuki KOZAKAI			    vianame[i] == '!' ||
29804f8c54dc52e19096d31d94593bd1040716afe4dYasuyuki KOZAKAI			    vianame[i] == '*') {
299aae4f82eb83d923f59a328d6e13396f424be28f9Max Kellermann				fprintf(stderr,
300aae4f82eb83d923f59a328d6e13396f424be28f9Max Kellermann					"Warning: weird character in interface"
301aae4f82eb83d923f59a328d6e13396f424be28f9Max Kellermann					" `%s' (No aliases, :, ! or *).\n",
302aae4f82eb83d923f59a328d6e13396f424be28f9Max Kellermann					vianame);
30304f8c54dc52e19096d31d94593bd1040716afe4dYasuyuki KOZAKAI				break;
30404f8c54dc52e19096d31d94593bd1040716afe4dYasuyuki KOZAKAI			}
30504f8c54dc52e19096d31d94593bd1040716afe4dYasuyuki KOZAKAI		}
30604f8c54dc52e19096d31d94593bd1040716afe4dYasuyuki KOZAKAI	}
30704f8c54dc52e19096d31d94593bd1040716afe4dYasuyuki KOZAKAI}
30804f8c54dc52e19096d31d94593bd1040716afe4dYasuyuki KOZAKAI
309cb25af809a8734c4766b6bfa4cca99596cbf01dbJan Engelhardt#ifndef NO_SHARED_LIBS
31021b41eea4724c57d2b6e5998cf38255046e43ad3Jan Engelhardtstatic void *load_extension(const char *search_path, const char *prefix,
31121b41eea4724c57d2b6e5998cf38255046e43ad3Jan Engelhardt    const char *name, bool is_target)
31221b41eea4724c57d2b6e5998cf38255046e43ad3Jan Engelhardt{
31321b41eea4724c57d2b6e5998cf38255046e43ad3Jan Engelhardt	const char *dir = search_path, *next;
31421b41eea4724c57d2b6e5998cf38255046e43ad3Jan Engelhardt	void *ptr = NULL;
31521b41eea4724c57d2b6e5998cf38255046e43ad3Jan Engelhardt	struct stat sb;
31621b41eea4724c57d2b6e5998cf38255046e43ad3Jan Engelhardt	char path[256];
31721b41eea4724c57d2b6e5998cf38255046e43ad3Jan Engelhardt
31821b41eea4724c57d2b6e5998cf38255046e43ad3Jan Engelhardt	do {
31921b41eea4724c57d2b6e5998cf38255046e43ad3Jan Engelhardt		next = strchr(dir, ':');
32021b41eea4724c57d2b6e5998cf38255046e43ad3Jan Engelhardt		if (next == NULL)
32121b41eea4724c57d2b6e5998cf38255046e43ad3Jan Engelhardt			next = dir + strlen(dir);
32221b41eea4724c57d2b6e5998cf38255046e43ad3Jan Engelhardt		snprintf(path, sizeof(path), "%.*s/libxt_%s.so",
3232c0a0c9eba1d1ab39dcde54bc822d4788f9531fcJan Engelhardt		         (unsigned int)(next - dir), dir, name);
32421b41eea4724c57d2b6e5998cf38255046e43ad3Jan Engelhardt
32521b41eea4724c57d2b6e5998cf38255046e43ad3Jan Engelhardt		if (dlopen(path, RTLD_NOW) != NULL) {
32621b41eea4724c57d2b6e5998cf38255046e43ad3Jan Engelhardt			/* Found library.  If it didn't register itself,
32721b41eea4724c57d2b6e5998cf38255046e43ad3Jan Engelhardt			   maybe they specified target as match. */
32821b41eea4724c57d2b6e5998cf38255046e43ad3Jan Engelhardt			if (is_target)
32921b41eea4724c57d2b6e5998cf38255046e43ad3Jan Engelhardt				ptr = find_target(name, DONT_LOAD);
33021b41eea4724c57d2b6e5998cf38255046e43ad3Jan Engelhardt			else
33121b41eea4724c57d2b6e5998cf38255046e43ad3Jan Engelhardt				ptr = find_match(name, DONT_LOAD, NULL);
33221b41eea4724c57d2b6e5998cf38255046e43ad3Jan Engelhardt		} else if (stat(path, &sb) == 0) {
33321b41eea4724c57d2b6e5998cf38255046e43ad3Jan Engelhardt			fprintf(stderr, "%s: %s\n", path, dlerror());
33421b41eea4724c57d2b6e5998cf38255046e43ad3Jan Engelhardt		}
33521b41eea4724c57d2b6e5998cf38255046e43ad3Jan Engelhardt
33621b41eea4724c57d2b6e5998cf38255046e43ad3Jan Engelhardt		if (ptr != NULL)
33721b41eea4724c57d2b6e5998cf38255046e43ad3Jan Engelhardt			return ptr;
33821b41eea4724c57d2b6e5998cf38255046e43ad3Jan Engelhardt
33921b41eea4724c57d2b6e5998cf38255046e43ad3Jan Engelhardt		snprintf(path, sizeof(path), "%.*s/%s%s.so",
3402c0a0c9eba1d1ab39dcde54bc822d4788f9531fcJan Engelhardt		         (unsigned int)(next - dir), dir, prefix, name);
34121b41eea4724c57d2b6e5998cf38255046e43ad3Jan Engelhardt		if (dlopen(path, RTLD_NOW) != NULL) {
34221b41eea4724c57d2b6e5998cf38255046e43ad3Jan Engelhardt			if (is_target)
34321b41eea4724c57d2b6e5998cf38255046e43ad3Jan Engelhardt				ptr = find_target(name, DONT_LOAD);
34421b41eea4724c57d2b6e5998cf38255046e43ad3Jan Engelhardt			else
34521b41eea4724c57d2b6e5998cf38255046e43ad3Jan Engelhardt				ptr = find_match(name, DONT_LOAD, NULL);
34621b41eea4724c57d2b6e5998cf38255046e43ad3Jan Engelhardt		} else if (stat(path, &sb) == 0) {
34721b41eea4724c57d2b6e5998cf38255046e43ad3Jan Engelhardt			fprintf(stderr, "%s: %s\n", path, dlerror());
34821b41eea4724c57d2b6e5998cf38255046e43ad3Jan Engelhardt		}
34921b41eea4724c57d2b6e5998cf38255046e43ad3Jan Engelhardt
35021b41eea4724c57d2b6e5998cf38255046e43ad3Jan Engelhardt		if (ptr != NULL)
35121b41eea4724c57d2b6e5998cf38255046e43ad3Jan Engelhardt			return ptr;
35221b41eea4724c57d2b6e5998cf38255046e43ad3Jan Engelhardt
35321b41eea4724c57d2b6e5998cf38255046e43ad3Jan Engelhardt		dir = next + 1;
35421b41eea4724c57d2b6e5998cf38255046e43ad3Jan Engelhardt	} while (*next != '\0');
35521b41eea4724c57d2b6e5998cf38255046e43ad3Jan Engelhardt
35621b41eea4724c57d2b6e5998cf38255046e43ad3Jan Engelhardt	return NULL;
35721b41eea4724c57d2b6e5998cf38255046e43ad3Jan Engelhardt}
358cb25af809a8734c4766b6bfa4cca99596cbf01dbJan Engelhardt#endif
35921b41eea4724c57d2b6e5998cf38255046e43ad3Jan Engelhardt
3600d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAIstruct xtables_match *find_match(const char *name, enum xt_tryload tryload,
3610d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI				 struct xtables_rule_match **matches)
3620d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI{
3630d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI	struct xtables_match *ptr;
3640d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI	const char *icmp6 = "icmp6";
3650d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI
3660d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI	/* This is ugly as hell. Nonetheless, there is no way of changing
3670d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI	 * this without hurting backwards compatibility */
3680d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI	if ( (strcmp(name,"icmpv6") == 0) ||
3690d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI	     (strcmp(name,"ipv6-icmp") == 0) ||
3700d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI	     (strcmp(name,"icmp6") == 0) )
3710d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI		name = icmp6;
3720d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI
3730d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI	for (ptr = xtables_matches; ptr; ptr = ptr->next) {
3740d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI		if (strcmp(name, ptr->name) == 0) {
3750d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI			struct xtables_match *clone;
3760d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI
3770d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI			/* First match of this type: */
3780d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI			if (ptr->m == NULL)
3790d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI				break;
3800d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI
3810d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI			/* Second and subsequent clones */
3820d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI			clone = fw_malloc(sizeof(struct xtables_match));
3830d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI			memcpy(clone, ptr, sizeof(struct xtables_match));
3840d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI			clone->mflags = 0;
3850d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI			/* This is a clone: */
3860d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI			clone->next = clone;
3870d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI
3880d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI			ptr = clone;
3890d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI			break;
3900d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI		}
3910d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI	}
3920d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI
3930d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI#ifndef NO_SHARED_LIBS
3940d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI	if (!ptr && tryload != DONT_LOAD && tryload != DURING_LOAD) {
39521b41eea4724c57d2b6e5998cf38255046e43ad3Jan Engelhardt		ptr = load_extension(lib_dir, afinfo.libprefix, name, false);
396170af8c566faa9605c1ead558792a031f1d0d48dYasuyuki KOZAKAI
397170af8c566faa9605c1ead558792a031f1d0d48dYasuyuki KOZAKAI		if (ptr == NULL && tryload == LOAD_MUST_SUCCEED)
3980d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI			exit_error(PARAMETER_PROBLEM,
3990d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI				   "Couldn't load match `%s':%s\n",
4000d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI				   name, dlerror());
4010d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI	}
4020d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI#else
4030d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI	if (ptr && !ptr->loaded) {
4040d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI		if (tryload != DONT_LOAD)
4050d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI			ptr->loaded = 1;
4060d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI		else
4070d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI			ptr = NULL;
4080d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI	}
4090d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI	if(!ptr && (tryload == LOAD_MUST_SUCCEED)) {
4100d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI		exit_error(PARAMETER_PROBLEM,
4110d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI			   "Couldn't find match `%s'\n", name);
4120d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI	}
4130d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI#endif
4140d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI
4150d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI	if (ptr && matches) {
4160d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI		struct xtables_rule_match **i;
4170d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI		struct xtables_rule_match *newentry;
4180d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI
4190d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI		newentry = fw_malloc(sizeof(struct xtables_rule_match));
4200d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI
4210d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI		for (i = matches; *i; i = &(*i)->next) {
4220d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI			if (strcmp(name, (*i)->match->name) == 0)
4230d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI				(*i)->completed = 1;
4240d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI		}
4250d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI		newentry->match = ptr;
4260d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI		newentry->completed = 0;
4270d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI		newentry->next = NULL;
4280d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI		*i = newentry;
4290d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI	}
4300d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI
4310d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI	return ptr;
4320d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI}
4330d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI
4340d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI
4350d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAIstruct xtables_target *find_target(const char *name, enum xt_tryload tryload)
4360d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI{
4370d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI	struct xtables_target *ptr;
4380d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI
4390d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI	/* Standard target? */
4400d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI	if (strcmp(name, "") == 0
4410d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI	    || strcmp(name, XTC_LABEL_ACCEPT) == 0
4420d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI	    || strcmp(name, XTC_LABEL_DROP) == 0
4430d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI	    || strcmp(name, XTC_LABEL_QUEUE) == 0
4440d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI	    || strcmp(name, XTC_LABEL_RETURN) == 0)
4450d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI		name = "standard";
4460d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI
4470d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI	for (ptr = xtables_targets; ptr; ptr = ptr->next) {
4480d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI		if (strcmp(name, ptr->name) == 0)
4490d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI			break;
4500d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI	}
4510d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI
4520d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI#ifndef NO_SHARED_LIBS
4530d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI	if (!ptr && tryload != DONT_LOAD && tryload != DURING_LOAD) {
45421b41eea4724c57d2b6e5998cf38255046e43ad3Jan Engelhardt		ptr = load_extension(lib_dir, afinfo.libprefix, name, true);
455170af8c566faa9605c1ead558792a031f1d0d48dYasuyuki KOZAKAI
456170af8c566faa9605c1ead558792a031f1d0d48dYasuyuki KOZAKAI		if (ptr == NULL && tryload == LOAD_MUST_SUCCEED)
4570d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI			exit_error(PARAMETER_PROBLEM,
4580d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI				   "Couldn't load target `%s':%s\n",
4590d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI				   name, dlerror());
4600d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI	}
4610d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI#else
4620d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI	if (ptr && !ptr->loaded) {
4630d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI		if (tryload != DONT_LOAD)
4640d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI			ptr->loaded = 1;
4650d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI		else
4660d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI			ptr = NULL;
4670d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI	}
4680d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI	if(!ptr && (tryload == LOAD_MUST_SUCCEED)) {
4690d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI		exit_error(PARAMETER_PROBLEM,
4700d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI			   "Couldn't find target `%s'\n", name);
4710d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI	}
4720d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI#endif
4730d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI
4740d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI	if (ptr)
4750d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI		ptr->used = 1;
4760d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI
4770d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI	return ptr;
4780d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI}
4790d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI
4800d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAIstatic int compatible_revision(const char *name, u_int8_t revision, int opt)
4810d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI{
4820d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI	struct xt_get_revision rev;
4830d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI	socklen_t s = sizeof(rev);
4840d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI	int max_rev, sockfd;
4850d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI
4860d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI	sockfd = socket(afinfo.family, SOCK_RAW, IPPROTO_RAW);
4870d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI	if (sockfd < 0) {
488df1ef3862761e534c6cec6bd9370285cb5909dd0Patrick McHardy		if (errno == EPERM) {
489df1ef3862761e534c6cec6bd9370285cb5909dd0Patrick McHardy			/* revision 0 is always supported. */
490df1ef3862761e534c6cec6bd9370285cb5909dd0Patrick McHardy			if (revision != 0)
491df1ef3862761e534c6cec6bd9370285cb5909dd0Patrick McHardy				fprintf(stderr, "Could not determine whether "
492df1ef3862761e534c6cec6bd9370285cb5909dd0Patrick McHardy						"revision %u is supported, "
493df1ef3862761e534c6cec6bd9370285cb5909dd0Patrick McHardy						"assuming it is.\n",
494df1ef3862761e534c6cec6bd9370285cb5909dd0Patrick McHardy					revision);
495df1ef3862761e534c6cec6bd9370285cb5909dd0Patrick McHardy			return 1;
496df1ef3862761e534c6cec6bd9370285cb5909dd0Patrick McHardy		}
4970d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI		fprintf(stderr, "Could not open socket to kernel: %s\n",
4980d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI			strerror(errno));
4990d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI		exit(1);
5000d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI	}
5010d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI
502dbb77543ad6afe29e9a1881b2d4fc212de621a55Jan Engelhardt	load_xtables_ko(modprobe_program, 1);
5030d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI
5040d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI	strcpy(rev.name, name);
5050d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI	rev.revision = revision;
5060d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI
5070d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI	max_rev = getsockopt(sockfd, afinfo.ipproto, opt, &rev, &s);
5080d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI	if (max_rev < 0) {
5090d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI		/* Definitely don't support this? */
5100d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI		if (errno == ENOENT || errno == EPROTONOSUPPORT) {
5110d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI			close(sockfd);
5120d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI			return 0;
5130d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI		} else if (errno == ENOPROTOOPT) {
5140d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI			close(sockfd);
5150d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI			/* Assume only revision 0 support (old kernel) */
5160d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI			return (revision == 0);
5170d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI		} else {
5180d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI			fprintf(stderr, "getsockopt failed strangely: %s\n",
5190d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI				strerror(errno));
5200d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI			exit(1);
5210d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI		}
5220d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI	}
5230d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI	close(sockfd);
5240d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI	return 1;
5250d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI}
5260d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI
5270d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI
5280d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAIstatic int compatible_match_revision(const char *name, u_int8_t revision)
5290d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI{
5300d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI	return compatible_revision(name, revision, afinfo.so_rev_match);
5310d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI}
5320d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI
5330d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAIstatic int compatible_target_revision(const char *name, u_int8_t revision)
5340d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI{
5350d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI	return compatible_revision(name, revision, afinfo.so_rev_target);
5360d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI}
5370d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI
5380d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAIvoid xtables_register_match(struct xtables_match *me)
5390d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI{
5400d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI	struct xtables_match **i, *old;
5410d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI
5420d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI	if (strcmp(me->version, program_version) != 0) {
5430d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI		fprintf(stderr, "%s: match `%s' v%s (I'm v%s).\n",
5440d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI			program_name, me->name, me->version, program_version);
5450d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI		exit(1);
5460d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI	}
5470d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI
5480d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI	/* Revision field stole a char from name. */
5490d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI	if (strlen(me->name) >= XT_FUNCTION_MAXNAMELEN-1) {
5500d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI		fprintf(stderr, "%s: target `%s' has invalid name\n",
5510d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI			program_name, me->name);
5520d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI		exit(1);
5530d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI	}
5540d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI
5550d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI	if (me->family >= NPROTO) {
5560d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI		fprintf(stderr,
5570d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI			"%s: BUG: match %s has invalid protocol family\n",
5580d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI			program_name, me->name);
5590d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI		exit(1);
5600d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI	}
5610d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI
5620d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI	/* ignore not interested match */
56323545c2a7a31c68c1e49c7c901b632c2f1c59968Jan Engelhardt	if (me->family != afinfo.family && me->family != AF_UNSPEC)
5640d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI		return;
5650d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI
5660d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI	old = find_match(me->name, DURING_LOAD, NULL);
5670d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI	if (old) {
56823545c2a7a31c68c1e49c7c901b632c2f1c59968Jan Engelhardt		if (old->revision == me->revision &&
56923545c2a7a31c68c1e49c7c901b632c2f1c59968Jan Engelhardt		    old->family == me->family) {
5700d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI			fprintf(stderr,
5710d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI				"%s: match `%s' already registered.\n",
5720d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI				program_name, me->name);
5730d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI			exit(1);
5740d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI		}
5750d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI
5760d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI		/* Now we have two (or more) options, check compatibility. */
5770d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI		if (compatible_match_revision(old->name, old->revision)
5780d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI		    && old->revision > me->revision)
5790d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI			return;
5800d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI
58123545c2a7a31c68c1e49c7c901b632c2f1c59968Jan Engelhardt		/* See if new match can be used. */
5820d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI		if (!compatible_match_revision(me->name, me->revision))
5830d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI			return;
5840d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI
58523545c2a7a31c68c1e49c7c901b632c2f1c59968Jan Engelhardt		/* Prefer !AF_UNSPEC over AF_UNSPEC for same revision. */
58623545c2a7a31c68c1e49c7c901b632c2f1c59968Jan Engelhardt		if (old->revision == me->revision && me->family == AF_UNSPEC)
58723545c2a7a31c68c1e49c7c901b632c2f1c59968Jan Engelhardt			return;
58823545c2a7a31c68c1e49c7c901b632c2f1c59968Jan Engelhardt
5890d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI		/* Delete old one. */
5900d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI		for (i = &xtables_matches; *i!=old; i = &(*i)->next);
5910d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI		*i = old->next;
5920d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI	}
5930d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI
5940d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI	if (me->size != XT_ALIGN(me->size)) {
5950d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI		fprintf(stderr, "%s: match `%s' has invalid size %u.\n",
5960d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI			program_name, me->name, (unsigned int)me->size);
5970d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI		exit(1);
5980d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI	}
5990d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI
6000d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI	/* Append to list. */
6010d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI	for (i = &xtables_matches; *i; i = &(*i)->next);
6020d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI	me->next = NULL;
6030d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI	*i = me;
6040d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI
6050d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI	me->m = NULL;
6060d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI	me->mflags = 0;
6070d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI}
6080d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI
6090d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAIvoid xtables_register_target(struct xtables_target *me)
6100d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI{
6110d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI	struct xtables_target *old;
6120d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI
6130d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI	if (strcmp(me->version, program_version) != 0) {
6140d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI		fprintf(stderr, "%s: target `%s' v%s (I'm v%s).\n",
6150d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI			program_name, me->name, me->version, program_version);
6160d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI		exit(1);
6170d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI	}
6180d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI
6190d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI	/* Revision field stole a char from name. */
6200d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI	if (strlen(me->name) >= XT_FUNCTION_MAXNAMELEN-1) {
6210d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI		fprintf(stderr, "%s: target `%s' has invalid name\n",
6220d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI			program_name, me->name);
6230d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI		exit(1);
6240d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI	}
6250d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI
6260d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI	if (me->family >= NPROTO) {
6270d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI		fprintf(stderr,
6280d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI			"%s: BUG: target %s has invalid protocol family\n",
6290d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI			program_name, me->name);
6300d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI		exit(1);
6310d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI	}
6320d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI
6330d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI	/* ignore not interested target */
63423545c2a7a31c68c1e49c7c901b632c2f1c59968Jan Engelhardt	if (me->family != afinfo.family && me->family != AF_UNSPEC)
6350d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI		return;
6360d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI
6370d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI	old = find_target(me->name, DURING_LOAD);
6380d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI	if (old) {
6390d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI		struct xtables_target **i;
6400d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI
64123545c2a7a31c68c1e49c7c901b632c2f1c59968Jan Engelhardt		if (old->revision == me->revision &&
64223545c2a7a31c68c1e49c7c901b632c2f1c59968Jan Engelhardt		    old->family == me->family) {
6430d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI			fprintf(stderr,
6440d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI				"%s: target `%s' already registered.\n",
6450d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI				program_name, me->name);
6460d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI			exit(1);
6470d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI		}
6480d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI
6490d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI		/* Now we have two (or more) options, check compatibility. */
6500d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI		if (compatible_target_revision(old->name, old->revision)
6510d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI		    && old->revision > me->revision)
6520d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI			return;
6530d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI
65423545c2a7a31c68c1e49c7c901b632c2f1c59968Jan Engelhardt		/* See if new target can be used. */
6550d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI		if (!compatible_target_revision(me->name, me->revision))
6560d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI			return;
6570d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI
65823545c2a7a31c68c1e49c7c901b632c2f1c59968Jan Engelhardt		/* Prefer !AF_UNSPEC over AF_UNSPEC for same revision. */
65923545c2a7a31c68c1e49c7c901b632c2f1c59968Jan Engelhardt		if (old->revision == me->revision && me->family == AF_UNSPEC)
66023545c2a7a31c68c1e49c7c901b632c2f1c59968Jan Engelhardt			return;
66123545c2a7a31c68c1e49c7c901b632c2f1c59968Jan Engelhardt
6620d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI		/* Delete old one. */
6630d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI		for (i = &xtables_targets; *i!=old; i = &(*i)->next);
6640d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI		*i = old->next;
6650d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI	}
6660d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI
6670d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI	if (me->size != XT_ALIGN(me->size)) {
6680d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI		fprintf(stderr, "%s: target `%s' has invalid size %u.\n",
6690d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI			program_name, me->name, (unsigned int)me->size);
6700d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI		exit(1);
6710d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI	}
6720d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI
6730d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI	/* Prepend to list. */
6740d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI	me->next = xtables_targets;
6750d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI	xtables_targets = me;
6760d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI	me->t = NULL;
6770d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI	me->tflags = 0;
6780d502bcdbc97ed359e84f6a21dfa0049b3b60a6cYasuyuki KOZAKAI}
679aafd269675fc45bac6340027c866ea6073643c3bJan Engelhardt
680aafd269675fc45bac6340027c866ea6073643c3bJan Engelhardtvoid param_act(unsigned int status, const char *p1, ...)
681aafd269675fc45bac6340027c866ea6073643c3bJan Engelhardt{
682aafd269675fc45bac6340027c866ea6073643c3bJan Engelhardt	const char *p2, *p3;
683aafd269675fc45bac6340027c866ea6073643c3bJan Engelhardt	va_list args;
684aafd269675fc45bac6340027c866ea6073643c3bJan Engelhardt	bool b;
685aafd269675fc45bac6340027c866ea6073643c3bJan Engelhardt
686aafd269675fc45bac6340027c866ea6073643c3bJan Engelhardt	va_start(args, p1);
687aafd269675fc45bac6340027c866ea6073643c3bJan Engelhardt
688aafd269675fc45bac6340027c866ea6073643c3bJan Engelhardt	switch (status) {
689aafd269675fc45bac6340027c866ea6073643c3bJan Engelhardt	case P_ONLY_ONCE:
690aafd269675fc45bac6340027c866ea6073643c3bJan Engelhardt		p2 = va_arg(args, const char *);
691aafd269675fc45bac6340027c866ea6073643c3bJan Engelhardt		b  = va_arg(args, unsigned int);
692aafd269675fc45bac6340027c866ea6073643c3bJan Engelhardt		if (!b)
693aafd269675fc45bac6340027c866ea6073643c3bJan Engelhardt			return;
694aafd269675fc45bac6340027c866ea6073643c3bJan Engelhardt		exit_error(PARAMETER_PROBLEM,
695aafd269675fc45bac6340027c866ea6073643c3bJan Engelhardt		           "%s: \"%s\" option may only be specified once",
696aafd269675fc45bac6340027c866ea6073643c3bJan Engelhardt		           p1, p2);
697aafd269675fc45bac6340027c866ea6073643c3bJan Engelhardt		break;
698aafd269675fc45bac6340027c866ea6073643c3bJan Engelhardt	case P_NO_INVERT:
699aafd269675fc45bac6340027c866ea6073643c3bJan Engelhardt		p2 = va_arg(args, const char *);
700aafd269675fc45bac6340027c866ea6073643c3bJan Engelhardt		b  = va_arg(args, unsigned int);
701aafd269675fc45bac6340027c866ea6073643c3bJan Engelhardt		if (!b)
702aafd269675fc45bac6340027c866ea6073643c3bJan Engelhardt			return;
703aafd269675fc45bac6340027c866ea6073643c3bJan Engelhardt		exit_error(PARAMETER_PROBLEM,
704aafd269675fc45bac6340027c866ea6073643c3bJan Engelhardt		           "%s: \"%s\" option cannot be inverted", p1, p2);
705aafd269675fc45bac6340027c866ea6073643c3bJan Engelhardt		break;
706aafd269675fc45bac6340027c866ea6073643c3bJan Engelhardt	case P_BAD_VALUE:
707aafd269675fc45bac6340027c866ea6073643c3bJan Engelhardt		p2 = va_arg(args, const char *);
708aafd269675fc45bac6340027c866ea6073643c3bJan Engelhardt		p3 = va_arg(args, const char *);
709aafd269675fc45bac6340027c866ea6073643c3bJan Engelhardt		exit_error(PARAMETER_PROBLEM,
710aafd269675fc45bac6340027c866ea6073643c3bJan Engelhardt		           "%s: Bad value for \"%s\" option: \"%s\"",
711aafd269675fc45bac6340027c866ea6073643c3bJan Engelhardt		           p1, p2, p3);
712aafd269675fc45bac6340027c866ea6073643c3bJan Engelhardt		break;
713aafd269675fc45bac6340027c866ea6073643c3bJan Engelhardt	case P_ONE_ACTION:
714aafd269675fc45bac6340027c866ea6073643c3bJan Engelhardt		b = va_arg(args, unsigned int);
715aafd269675fc45bac6340027c866ea6073643c3bJan Engelhardt		if (!b)
716aafd269675fc45bac6340027c866ea6073643c3bJan Engelhardt			return;
717aafd269675fc45bac6340027c866ea6073643c3bJan Engelhardt		exit_error(PARAMETER_PROBLEM,
718aafd269675fc45bac6340027c866ea6073643c3bJan Engelhardt		           "%s: At most one action is possible", p1);
719aafd269675fc45bac6340027c866ea6073643c3bJan Engelhardt		break;
720aafd269675fc45bac6340027c866ea6073643c3bJan Engelhardt	default:
721aafd269675fc45bac6340027c866ea6073643c3bJan Engelhardt		exit_error(status, p1, args);
722aafd269675fc45bac6340027c866ea6073643c3bJan Engelhardt		break;
723aafd269675fc45bac6340027c866ea6073643c3bJan Engelhardt	}
724aafd269675fc45bac6340027c866ea6073643c3bJan Engelhardt
725aafd269675fc45bac6340027c866ea6073643c3bJan Engelhardt	va_end(args);
726aafd269675fc45bac6340027c866ea6073643c3bJan Engelhardt}
72708b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt
72808b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardtconst char *ipaddr_to_numeric(const struct in_addr *addrp)
72908b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt{
73008b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt	static char buf[20];
73108b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt	const unsigned char *bytep = (const void *)&addrp->s_addr;
73208b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt
73308b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt	sprintf(buf, "%u.%u.%u.%u", bytep[0], bytep[1], bytep[2], bytep[3]);
73408b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt	return buf;
73508b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt}
73608b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt
73708b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardtstatic const char *ipaddr_to_host(const struct in_addr *addr)
73808b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt{
73908b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt	struct hostent *host;
74008b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt
74108b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt	host = gethostbyaddr(addr, sizeof(struct in_addr), AF_INET);
74208b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt	if (host == NULL)
74308b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt		return NULL;
74408b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt
74508b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt	return host->h_name;
74608b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt}
74708b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt
74808b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardtstatic const char *ipaddr_to_network(const struct in_addr *addr)
74908b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt{
75008b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt	struct netent *net;
75108b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt
75208b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt	if ((net = getnetbyaddr(ntohl(addr->s_addr), AF_INET)) != NULL)
75308b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt		return net->n_name;
75408b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt
75508b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt	return NULL;
75608b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt}
75708b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt
75808b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardtconst char *ipaddr_to_anyname(const struct in_addr *addr)
75908b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt{
76008b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt	const char *name;
76108b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt
76208b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt	if ((name = ipaddr_to_host(addr)) != NULL ||
76308b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt	    (name = ipaddr_to_network(addr)) != NULL)
76408b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt		return name;
76508b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt
76608b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt	return ipaddr_to_numeric(addr);
76708b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt}
76808b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt
76908b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardtconst char *ipmask_to_numeric(const struct in_addr *mask)
77008b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt{
77108b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt	static char buf[20];
77208b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt	uint32_t maskaddr, bits;
77308b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt	int i;
77408b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt
77508b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt	maskaddr = ntohl(mask->s_addr);
77608b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt
77708b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt	if (maskaddr == 0xFFFFFFFFL)
77808b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt		/* we don't want to see "/32" */
77908b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt		return "";
78008b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt
78108b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt	i = 32;
78208b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt	bits = 0xFFFFFFFEL;
78308b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt	while (--i >= 0 && maskaddr != bits)
78408b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt		bits <<= 1;
78508b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt	if (i >= 0)
78608b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt		sprintf(buf, "/%d", i);
78708b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt	else
78808b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt		/* mask was not a decent combination of 1's and 0's */
78908b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt		sprintf(buf, "/%s", ipaddr_to_numeric(mask));
79008b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt
79108b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt	return buf;
79208b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt}
79308b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt
794bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardtstatic struct in_addr *__numeric_to_ipaddr(const char *dotted, bool is_mask)
795bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt{
796bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	static struct in_addr addr;
797bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	unsigned char *addrp;
798bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	unsigned int onebyte;
799bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	char buf[20], *p, *q;
800bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	int i;
801bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt
802bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	/* copy dotted string, because we need to modify it */
803bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	strncpy(buf, dotted, sizeof(buf) - 1);
804bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	buf[sizeof(buf) - 1] = '\0';
805bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	addrp = (void *)&addr.s_addr;
806bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt
807bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	p = buf;
808bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	for (i = 0; i < 3; ++i) {
809bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt		if ((q = strchr(p, '.')) == NULL) {
810bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt			if (is_mask)
811bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt				return NULL;
812bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt
813bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt			/* autocomplete, this is a network address */
814bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt			if (!strtonum(p, NULL, &onebyte, 0, 255))
815bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt				return NULL;
816bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt
817bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt			addrp[i] = onebyte;
818bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt			while (i < 3)
819bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt				addrp[++i] = 0;
820bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt
821bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt			return &addr;
822bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt		}
823bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt
824bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt		*q = '\0';
825bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt		if (!strtonum(p, NULL, &onebyte, 0, 255))
826bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt			return NULL;
827bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt
828bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt		addrp[i] = onebyte;
829bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt		p = q + 1;
830bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	}
831bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt
832bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	/* we have checked 3 bytes, now we check the last one */
833bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	if (!strtonum(p, NULL, &onebyte, 0, 255))
834bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt		return NULL;
835bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt
836bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	addrp[3] = onebyte;
837bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	return &addr;
838bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt}
839bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt
840bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardtstruct in_addr *numeric_to_ipaddr(const char *dotted)
841bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt{
842bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	return __numeric_to_ipaddr(dotted, false);
843bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt}
844bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt
845bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardtstruct in_addr *numeric_to_ipmask(const char *dotted)
846bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt{
847bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	return __numeric_to_ipaddr(dotted, true);
848bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt}
849bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt
850bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardtstatic struct in_addr *network_to_ipaddr(const char *name)
851bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt{
852bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	static struct in_addr addr;
853bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	struct netent *net;
854bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt
855bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	if ((net = getnetbyname(name)) != NULL) {
856bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt		if (net->n_addrtype != AF_INET)
857bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt			return NULL;
858bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt		addr.s_addr = htonl(net->n_net);
859bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt		return &addr;
860bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	}
861bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt
862bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	return NULL;
863bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt}
864bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt
865bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardtstatic struct in_addr *host_to_ipaddr(const char *name, unsigned int *naddr)
866bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt{
867bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	struct hostent *host;
868bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	struct in_addr *addr;
869bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	unsigned int i;
870bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt
871bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	*naddr = 0;
872bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	if ((host = gethostbyname(name)) != NULL) {
873bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt		if (host->h_addrtype != AF_INET ||
874bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt		    host->h_length != sizeof(struct in_addr))
875bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt			return NULL;
876bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt
877bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt		while (host->h_addr_list[*naddr] != NULL)
878bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt			++*naddr;
879bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt		addr = fw_calloc(*naddr, sizeof(struct in_addr) * *naddr);
880bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt		for (i = 0; i < *naddr; i++)
881bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt			memcpy(&addr[i], host->h_addr_list[i],
882bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt			       sizeof(struct in_addr));
883bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt		return addr;
884bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	}
885bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt
886bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	return NULL;
887bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt}
888bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt
889bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardtstatic struct in_addr *
890bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardtipparse_hostnetwork(const char *name, unsigned int *naddrs)
891bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt{
892bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	struct in_addr *addrptmp, *addrp;
893bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt
894bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	if ((addrptmp = numeric_to_ipaddr(name)) != NULL ||
895bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	    (addrptmp = network_to_ipaddr(name)) != NULL) {
896bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt		addrp = fw_malloc(sizeof(struct in_addr));
897bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt		memcpy(addrp, addrptmp, sizeof(*addrp));
898bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt		*naddrs = 1;
899bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt		return addrp;
900bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	}
901bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	if ((addrptmp = host_to_ipaddr(name, naddrs)) != NULL)
902bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt		return addrptmp;
903bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt
904bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	exit_error(PARAMETER_PROBLEM, "host/network `%s' not found", name);
905bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt}
906bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt
907bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardtstatic struct in_addr *parse_ipmask(const char *mask)
908bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt{
909bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	static struct in_addr maskaddr;
910bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	struct in_addr *addrp;
911bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	unsigned int bits;
912bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt
913bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	if (mask == NULL) {
914bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt		/* no mask at all defaults to 32 bits */
915bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt		maskaddr.s_addr = 0xFFFFFFFF;
916bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt		return &maskaddr;
917bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	}
918bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	if ((addrp = numeric_to_ipmask(mask)) != NULL)
919bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt		/* dotted_to_addr already returns a network byte order addr */
920bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt		return addrp;
921bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	if (string_to_number(mask, 0, 32, &bits) == -1)
922bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt		exit_error(PARAMETER_PROBLEM,
923bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt			   "invalid mask `%s' specified", mask);
924bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	if (bits != 0) {
925bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt		maskaddr.s_addr = htonl(0xFFFFFFFF << (32 - bits));
926bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt		return &maskaddr;
927bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	}
928bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt
929bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	maskaddr.s_addr = 0U;
930bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	return &maskaddr;
931bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt}
932bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt
933bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardtvoid ipparse_hostnetworkmask(const char *name, struct in_addr **addrpp,
934bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt                             struct in_addr *maskp, unsigned int *naddrs)
935bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt{
936bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	unsigned int i, j, k, n;
937bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	struct in_addr *addrp;
938bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	char buf[256], *p;
939bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt
940bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	strncpy(buf, name, sizeof(buf) - 1);
941bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	buf[sizeof(buf) - 1] = '\0';
942bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	if ((p = strrchr(buf, '/')) != NULL) {
943bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt		*p = '\0';
944bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt		addrp = parse_ipmask(p + 1);
945bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	} else {
946bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt		addrp = parse_ipmask(NULL);
947bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	}
948bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	memcpy(maskp, addrp, sizeof(*maskp));
949bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt
950bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	/* if a null mask is given, the name is ignored, like in "any/0" */
951bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	if (maskp->s_addr == 0U)
952bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt		strcpy(buf, "0.0.0.0");
953bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt
954bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	addrp = *addrpp = ipparse_hostnetwork(buf, naddrs);
955bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	n = *naddrs;
956bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	for (i = 0, j = 0; i < n; ++i) {
957bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt		addrp[j++].s_addr &= maskp->s_addr;
958bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt		for (k = 0; k < j - 1; ++k)
959bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt			if (addrp[k].s_addr == addrp[j-1].s_addr) {
960bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt				--*naddrs;
961bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt				--j;
962bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt				break;
963bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt			}
964bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	}
965bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt}
966bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt
96708b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardtconst char *ip6addr_to_numeric(const struct in6_addr *addrp)
96808b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt{
96908b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt	/* 0000:0000:0000:0000:0000:000.000.000.000
97008b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt	 * 0000:0000:0000:0000:0000:0000:0000:0000 */
97108b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt	static char buf[50+1];
97208b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt	return inet_ntop(AF_INET6, addrp, buf, sizeof(buf));
97308b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt}
97408b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt
97508b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardtstatic const char *ip6addr_to_host(const struct in6_addr *addr)
97608b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt{
97708b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt	static char hostname[NI_MAXHOST];
97808b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt	struct sockaddr_in6 saddr;
97908b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt	int err;
98008b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt
98108b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt	memset(&saddr, 0, sizeof(struct sockaddr_in6));
98208b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt	memcpy(&saddr.sin6_addr, addr, sizeof(*addr));
98308b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt	saddr.sin6_family = AF_INET6;
98408b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt
98508b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt	err = getnameinfo((const void *)&saddr, sizeof(struct sockaddr_in6),
98608b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt	      hostname, sizeof(hostname) - 1, NULL, 0, 0);
98708b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt	if (err != 0) {
98808b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt#ifdef DEBUG
98908b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt		fprintf(stderr,"IP2Name: %s\n",gai_strerror(err));
99008b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt#endif
99108b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt		return NULL;
99208b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt	}
99308b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt
99408b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt#ifdef DEBUG
99508b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt	fprintf (stderr, "\naddr2host: %s\n", hostname);
99608b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt#endif
99708b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt	return hostname;
99808b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt}
99908b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt
100008b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardtconst char *ip6addr_to_anyname(const struct in6_addr *addr)
100108b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt{
100208b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt	const char *name;
100308b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt
100408b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt	if ((name = ip6addr_to_host(addr)) != NULL)
100508b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt		return name;
100608b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt
100708b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt	return ip6addr_to_numeric(addr);
100808b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt}
100908b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt
101008b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardtstatic int ip6addr_prefix_length(const struct in6_addr *k)
101108b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt{
101208b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt	unsigned int bits = 0;
101308b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt	uint32_t a, b, c, d;
101408b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt
101548607816796124ce2177ee22645d3fd8180f1e98Jan Engelhardt	a = ntohl(k->s6_addr32[0]);
101648607816796124ce2177ee22645d3fd8180f1e98Jan Engelhardt	b = ntohl(k->s6_addr32[1]);
101748607816796124ce2177ee22645d3fd8180f1e98Jan Engelhardt	c = ntohl(k->s6_addr32[2]);
101848607816796124ce2177ee22645d3fd8180f1e98Jan Engelhardt	d = ntohl(k->s6_addr32[3]);
101908b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt	while (a & 0x80000000U) {
102008b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt		++bits;
102108b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt		a <<= 1;
102208b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt		a  |= (b >> 31) & 1;
102308b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt		b <<= 1;
102408b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt		b  |= (c >> 31) & 1;
102508b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt		c <<= 1;
102608b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt		c  |= (d >> 31) & 1;
102708b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt		d <<= 1;
102808b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt	}
102908b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt	if (a != 0 || b != 0 || c != 0 || d != 0)
103008b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt		return -1;
103108b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt	return bits;
103208b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt}
103308b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt
103408b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardtconst char *ip6mask_to_numeric(const struct in6_addr *addrp)
103508b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt{
103608b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt	static char buf[50+2];
103708b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt	int l = ip6addr_prefix_length(addrp);
103808b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt
103908b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt	if (l == -1) {
104008b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt		strcpy(buf, "/");
104108b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt		strcat(buf, ip6addr_to_numeric(addrp));
104208b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt		return buf;
104308b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt	}
104408b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt	sprintf(buf, "/%d", l);
104508b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt	return buf;
104608b1616e068166e016b3ee7110db10ae5d853422Jan Engelhardt}
1047bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt
1048bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardtstruct in6_addr *numeric_to_ip6addr(const char *num)
1049bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt{
1050bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	static struct in6_addr ap;
1051bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	int err;
1052bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt
1053bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	if ((err = inet_pton(AF_INET6, num, &ap)) == 1)
1054bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt		return &ap;
1055bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt#ifdef DEBUG
1056bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	fprintf(stderr, "\nnumeric2addr: %d\n", err);
1057bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt#endif
1058bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	return NULL;
1059bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt}
1060bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt
1061bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardtstatic struct in6_addr *
1062bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardthost_to_ip6addr(const char *name, unsigned int *naddr)
1063bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt{
1064bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	static struct in6_addr *addr;
1065bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	struct addrinfo hints;
1066bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	struct addrinfo *res;
1067bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	int err;
1068bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt
1069bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	memset(&hints, 0, sizeof(hints));
1070bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	hints.ai_flags    = AI_CANONNAME;
1071bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	hints.ai_family   = AF_INET6;
1072bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	hints.ai_socktype = SOCK_RAW;
1073bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	hints.ai_protocol = IPPROTO_IPV6;
1074bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	hints.ai_next     = NULL;
1075bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt
1076bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	*naddr = 0;
1077bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	if ((err = getaddrinfo(name, NULL, &hints, &res)) != 0) {
1078bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt#ifdef DEBUG
1079bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt		fprintf(stderr,"Name2IP: %s\n",gai_strerror(err));
1080bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt#endif
1081bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt		return NULL;
1082bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	} else {
1083bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt		if (res->ai_family != AF_INET6 ||
1084bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt		    res->ai_addrlen != sizeof(struct sockaddr_in6))
1085bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt			return NULL;
1086bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt
1087bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt#ifdef DEBUG
1088bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt		fprintf(stderr, "resolved: len=%d  %s ", res->ai_addrlen,
1089bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt		        ip6addr_to_numeric(&((struct sockaddr_in6 *)res->ai_addr)->sin6_addr));
1090bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt#endif
1091bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt		/* Get the first element of the address-chain */
1092bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt		addr = fw_malloc(sizeof(struct in6_addr));
1093bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt		memcpy(addr, &((const struct sockaddr_in6 *)res->ai_addr)->sin6_addr,
1094bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt		       sizeof(struct in6_addr));
1095bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt		freeaddrinfo(res);
1096bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt		*naddr = 1;
1097bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt		return addr;
1098bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	}
1099bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt
1100bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	return NULL;
1101bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt}
1102bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt
1103bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardtstatic struct in6_addr *network_to_ip6addr(const char *name)
1104bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt{
1105bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	/*	abort();*/
1106bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	/* TODO: not implemented yet, but the exception breaks the
1107bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	 *       name resolvation */
1108bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	return NULL;
1109bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt}
1110bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt
1111bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardtstatic struct in6_addr *
1112bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardtip6parse_hostnetwork(const char *name, unsigned int *naddrs)
1113bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt{
1114bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	struct in6_addr *addrp, *addrptmp;
1115bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt
1116bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	if ((addrptmp = numeric_to_ip6addr(name)) != NULL ||
1117bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	    (addrptmp = network_to_ip6addr(name)) != NULL) {
1118bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt		addrp = fw_malloc(sizeof(struct in6_addr));
1119bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt		memcpy(addrp, addrptmp, sizeof(*addrp));
1120bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt		*naddrs = 1;
1121bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt		return addrp;
1122bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	}
1123bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	if ((addrp = host_to_ip6addr(name, naddrs)) != NULL)
1124bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt		return addrp;
1125bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt
1126bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	exit_error(PARAMETER_PROBLEM, "host/network `%s' not found", name);
1127bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt}
1128bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt
1129bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardtstatic struct in6_addr *parse_ip6mask(char *mask)
1130bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt{
1131bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	static struct in6_addr maskaddr;
1132bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	struct in6_addr *addrp;
1133bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	unsigned int bits;
1134bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt
1135bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	if (mask == NULL) {
1136bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt		/* no mask at all defaults to 128 bits */
1137bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt		memset(&maskaddr, 0xff, sizeof maskaddr);
1138bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt		return &maskaddr;
1139bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	}
1140bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	if ((addrp = numeric_to_ip6addr(mask)) != NULL)
1141bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt		return addrp;
1142bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	if (string_to_number(mask, 0, 128, &bits) == -1)
1143bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt		exit_error(PARAMETER_PROBLEM,
1144bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt			   "invalid mask `%s' specified", mask);
1145bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	if (bits != 0) {
1146bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt		char *p = (void *)&maskaddr;
1147bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt		memset(p, 0xff, bits / 8);
1148bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt		memset(p + (bits / 8) + 1, 0, (128 - bits) / 8);
1149bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt		p[bits/8] = 0xff << (8 - (bits & 7));
1150bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt		return &maskaddr;
1151bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	}
1152bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt
1153bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	memset(&maskaddr, 0, sizeof(maskaddr));
1154bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	return &maskaddr;
1155bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt}
1156bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt
1157bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardtvoid ip6parse_hostnetworkmask(const char *name, struct in6_addr **addrpp,
1158bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt                              struct in6_addr *maskp, unsigned int *naddrs)
1159bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt{
1160bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	struct in6_addr *addrp;
1161bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	unsigned int i, j, k, n;
1162bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	char buf[256], *p;
1163bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt
1164bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	strncpy(buf, name, sizeof(buf) - 1);
1165bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	buf[sizeof(buf)-1] = '\0';
1166bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	if ((p = strrchr(buf, '/')) != NULL) {
1167bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt		*p = '\0';
1168bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt		addrp = parse_ip6mask(p + 1);
1169bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	} else {
1170bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt		addrp = parse_ip6mask(NULL);
1171bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	}
1172bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	memcpy(maskp, addrp, sizeof(*maskp));
1173bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt
1174bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	/* if a null mask is given, the name is ignored, like in "any/0" */
1175bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	if (memcmp(maskp, &in6addr_any, sizeof(in6addr_any)) == 0)
1176bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt		strcpy(buf, "::");
1177bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt
1178bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	addrp = *addrpp = ip6parse_hostnetwork(buf, naddrs);
1179bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	n = *naddrs;
1180bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	for (i = 0, j = 0; i < n; ++i) {
1181bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt		for (k = 0; k < 4; ++k)
11825a2208c3e62a150e6f6297abbfa63056ab4a8066Yasuyuki Kozakai			addrp[j].s6_addr32[k] &= maskp->s6_addr32[k];
1183bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt		++j;
1184bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt		for (k = 0; k < j - 1; ++k)
1185bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt			if (IN6_ARE_ADDR_EQUAL(&addrp[k], &addrp[j - 1])) {
1186bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt				--*naddrs;
1187bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt				--j;
1188bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt				break;
1189bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt			}
1190bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt	}
1191bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt}
1192a5d099400fd6f9ad3880dda10f85d2aa36b5ec65Max Kellermann
1193a5d099400fd6f9ad3880dda10f85d2aa36b5ec65Max Kellermannvoid save_string(const char *value)
1194a5d099400fd6f9ad3880dda10f85d2aa36b5ec65Max Kellermann{
1195a5d099400fd6f9ad3880dda10f85d2aa36b5ec65Max Kellermann	static const char no_quote_chars[] = "_-0123456789"
1196a5d099400fd6f9ad3880dda10f85d2aa36b5ec65Max Kellermann		"abcdefghijklmnopqrstuvwxyz"
1197a5d099400fd6f9ad3880dda10f85d2aa36b5ec65Max Kellermann		"ABCDEFGHIJKLMNOPQRSTUVWXYZ";
1198a5d099400fd6f9ad3880dda10f85d2aa36b5ec65Max Kellermann	static const char escape_chars[] = "\"\\'";
1199a5d099400fd6f9ad3880dda10f85d2aa36b5ec65Max Kellermann	size_t length;
1200a5d099400fd6f9ad3880dda10f85d2aa36b5ec65Max Kellermann	const char *p;
1201a5d099400fd6f9ad3880dda10f85d2aa36b5ec65Max Kellermann
1202a5d099400fd6f9ad3880dda10f85d2aa36b5ec65Max Kellermann	length = strcspn(value, no_quote_chars);
1203a5d099400fd6f9ad3880dda10f85d2aa36b5ec65Max Kellermann	if (length > 0 && value[length] == 0) {
1204a5d099400fd6f9ad3880dda10f85d2aa36b5ec65Max Kellermann		/* no quoting required */
1205a5d099400fd6f9ad3880dda10f85d2aa36b5ec65Max Kellermann		fputs(value, stdout);
1206a5d099400fd6f9ad3880dda10f85d2aa36b5ec65Max Kellermann		putchar(' ');
1207a5d099400fd6f9ad3880dda10f85d2aa36b5ec65Max Kellermann	} else {
1208a5d099400fd6f9ad3880dda10f85d2aa36b5ec65Max Kellermann		/* there is at least one dangerous character in the
1209a5d099400fd6f9ad3880dda10f85d2aa36b5ec65Max Kellermann		   value, which we have to quote.  Write double quotes
1210a5d099400fd6f9ad3880dda10f85d2aa36b5ec65Max Kellermann		   around the value and escape special characters with
1211a5d099400fd6f9ad3880dda10f85d2aa36b5ec65Max Kellermann		   a backslash */
1212a5d099400fd6f9ad3880dda10f85d2aa36b5ec65Max Kellermann		putchar('"');
1213a5d099400fd6f9ad3880dda10f85d2aa36b5ec65Max Kellermann
1214a5d099400fd6f9ad3880dda10f85d2aa36b5ec65Max Kellermann		for (p = strpbrk(value, escape_chars); p != NULL;
1215a5d099400fd6f9ad3880dda10f85d2aa36b5ec65Max Kellermann		     p = strpbrk(value, escape_chars)) {
1216a5d099400fd6f9ad3880dda10f85d2aa36b5ec65Max Kellermann			if (p > value)
1217a5d099400fd6f9ad3880dda10f85d2aa36b5ec65Max Kellermann				fwrite(value, 1, p - value, stdout);
1218a5d099400fd6f9ad3880dda10f85d2aa36b5ec65Max Kellermann			putchar('\\');
1219a5d099400fd6f9ad3880dda10f85d2aa36b5ec65Max Kellermann			putchar(*p);
1220a5d099400fd6f9ad3880dda10f85d2aa36b5ec65Max Kellermann			value = p + 1;
1221a5d099400fd6f9ad3880dda10f85d2aa36b5ec65Max Kellermann		}
1222a5d099400fd6f9ad3880dda10f85d2aa36b5ec65Max Kellermann
1223a5d099400fd6f9ad3880dda10f85d2aa36b5ec65Max Kellermann		/* print the rest and finish the double quoted
1224a5d099400fd6f9ad3880dda10f85d2aa36b5ec65Max Kellermann		   string */
1225a5d099400fd6f9ad3880dda10f85d2aa36b5ec65Max Kellermann		fputs(value, stdout);
1226a5d099400fd6f9ad3880dda10f85d2aa36b5ec65Max Kellermann		printf("\" ");
1227a5d099400fd6f9ad3880dda10f85d2aa36b5ec65Max Kellermann	}
1228a5d099400fd6f9ad3880dda10f85d2aa36b5ec65Max Kellermann}
1229