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