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