xtables.c revision aae6be9edc99e58164a3592c510fe5488141c698
1116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch/*
2116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch * (C) 2000-2006 by the netfilter coreteam <coreteam@netfilter.org>:
3116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch *
4116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch *	This program is free software; you can redistribute it and/or modify
5116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch *	it under the terms of the GNU General Public License as published by
6116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch *	the Free Software Foundation; either version 2 of the License, or
7116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch *	(at your option) any later version.
8116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch *
9116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch *	This program is distributed in the hope that it will be useful,
10116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch *	but WITHOUT ANY WARRANTY; without even the implied warranty of
11116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch *	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch *	GNU General Public License for more details.
13116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch *
14116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch *	You should have received a copy of the GNU General Public License
15116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch *	along with this program; if not, write to the Free Software
16116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch *	Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
17116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch */
18116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch
19116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch#include <errno.h>
20116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch#include <fcntl.h>
21116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch#include <netdb.h>
22116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch#include <stdarg.h>
23116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch#include <stdbool.h>
24116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch#include <stdio.h>
25116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch#include <stdlib.h>
26116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch#include <string.h>
27116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch#include <unistd.h>
28116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch#include <sys/socket.h>
29116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch#include <sys/stat.h>
30116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch#include <sys/types.h>
31116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch#include <sys/wait.h>
32116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch#include <arpa/inet.h>
33116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch
34116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch#include <xtables.h>
35116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch#include <libiptc/libxtc.h>
36116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch
37116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch#ifndef NO_SHARED_LIBS
38116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch#include <dlfcn.h>
39116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch#endif
40116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch
41116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch#define NPROTO	255
42116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch
43116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch#ifndef PROC_SYS_MODPROBE
44116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch#define PROC_SYS_MODPROBE "/proc/sys/kernel/modprobe"
45116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch#endif
46116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch
47116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch/**
48116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch * Program will set this to its own name.
49116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch */
50116680a4aac90f2aa7413d9095a592090648e557Ben Murdochconst char *xtables_program_name;
51116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch
52116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch/* Search path for Xtables .so files */
53116680a4aac90f2aa7413d9095a592090648e557Ben Murdochstatic const char *xtables_libdir;
54116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch
55116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch/* the path to command to load kernel module */
56116680a4aac90f2aa7413d9095a592090648e557Ben Murdochconst char *xtables_modprobe_program;
57116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch
58116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch/* Keeping track of external matches and targets: linked lists.  */
59116680a4aac90f2aa7413d9095a592090648e557Ben Murdochstruct xtables_match *xtables_matches;
60116680a4aac90f2aa7413d9095a592090648e557Ben Murdochstruct xtables_target *xtables_targets;
61116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch
62116680a4aac90f2aa7413d9095a592090648e557Ben Murdochvoid xtables_init(void)
63116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch{
64116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch	xtables_libdir = getenv("XTABLES_LIBDIR");
65116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch	if (xtables_libdir != NULL)
66116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch		return;
67116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch	xtables_libdir = getenv("IPTABLES_LIB_DIR");
68116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch	if (xtables_libdir != NULL) {
69116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch		fprintf(stderr, "IPTABLES_LIB_DIR is deprecated, "
70116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch		        "use XTABLES_LIBDIR.\n");
71116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch		return;
72116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch	}
73116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch	xtables_libdir = XTABLES_LIBDIR;
74116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch}
75116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch
76116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch/**
77116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch * xtables_*alloc - wrappers that exit on failure
78116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch */
79116680a4aac90f2aa7413d9095a592090648e557Ben Murdochvoid *xtables_calloc(size_t count, size_t size)
80116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch{
81116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch	void *p;
82116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch
83116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch	if ((p = calloc(count, size)) == NULL) {
84116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch		perror("ip[6]tables: calloc failed");
85116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch		exit(1);
86116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch	}
87116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch
88116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch	return p;
89116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch}
90116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch
91116680a4aac90f2aa7413d9095a592090648e557Ben Murdochvoid *xtables_malloc(size_t size)
92116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch{
93116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch	void *p;
94116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch
95116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch	if ((p = malloc(size)) == NULL) {
96116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch		perror("ip[6]tables: malloc failed");
97116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch		exit(1);
98116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch	}
99116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch
100116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch	return p;
101116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch}
102116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch
103116680a4aac90f2aa7413d9095a592090648e557Ben Murdochstatic char *get_modprobe(void)
104116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch{
105116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch	int procfile;
106116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch	char *ret;
107116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch
108116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch#define PROCFILE_BUFSIZ	1024
109116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch	procfile = open(PROC_SYS_MODPROBE, O_RDONLY);
110116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch	if (procfile < 0)
111116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch		return NULL;
112116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch
113116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch	ret = (char *) malloc(PROCFILE_BUFSIZ);
114116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch	if (ret) {
115116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch		memset(ret, 0, PROCFILE_BUFSIZ);
116116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch		switch (read(procfile, ret, PROCFILE_BUFSIZ)) {
117116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch		case -1: goto fail;
118116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch		case PROCFILE_BUFSIZ: goto fail; /* Partial read.  Wierd */
119116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch		}
120116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch		if (ret[strlen(ret)-1]=='\n')
121116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch			ret[strlen(ret)-1]=0;
122116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch		close(procfile);
123116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch		return ret;
124116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch	}
125116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch fail:
126116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch	free(ret);
127116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch	close(procfile);
128116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch	return NULL;
129116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch}
130116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch
131116680a4aac90f2aa7413d9095a592090648e557Ben Murdochint xtables_insmod(const char *modname, const char *modprobe, bool quiet)
132116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch{
133116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch	char *buf = NULL;
134	char *argv[4];
135	int status;
136
137	/* If they don't explicitly set it, read out of kernel */
138	if (!modprobe) {
139		buf = get_modprobe();
140		if (!buf)
141			return -1;
142		modprobe = buf;
143	}
144
145	switch (fork()) {
146	case 0:
147		argv[0] = (char *)modprobe;
148		argv[1] = (char *)modname;
149		if (quiet) {
150			argv[2] = "-q";
151			argv[3] = NULL;
152		} else {
153			argv[2] = NULL;
154			argv[3] = NULL;
155		}
156		execv(argv[0], argv);
157
158		/* not usually reached */
159		exit(1);
160	case -1:
161		return -1;
162
163	default: /* parent */
164		wait(&status);
165	}
166
167	free(buf);
168	if (WIFEXITED(status) && WEXITSTATUS(status) == 0)
169		return 0;
170	return -1;
171}
172
173int xtables_load_ko(const char *modprobe, bool quiet)
174{
175	static bool loaded = false;
176	static int ret = -1;
177
178	if (!loaded) {
179		ret = xtables_insmod(afinfo.kmod, modprobe, quiet);
180		loaded = (ret == 0);
181	}
182
183	return ret;
184}
185
186/**
187 * xtables_strtou{i,l} - string to number conversion
188 * @s:	input string
189 * @end:	like strtoul's "end" pointer
190 * @value:	pointer for result
191 * @min:	minimum accepted value
192 * @max:	maximum accepted value
193 *
194 * If @end is NULL, we assume the caller wants a "strict strtoul", and hence
195 * "15a" is rejected.
196 * In either case, the value obtained is compared for min-max compliance.
197 * Base is always 0, i.e. autodetect depending on @s.
198 *
199 * Returns true/false whether number was accepted. On failure, *value has
200 * undefined contents.
201 */
202bool xtables_strtoul(const char *s, char **end, unsigned long *value,
203                     unsigned long min, unsigned long max)
204{
205	unsigned long v;
206	char *my_end;
207
208	errno = 0;
209	v = strtoul(s, &my_end, 0);
210
211	if (my_end == s)
212		return false;
213	if (end != NULL)
214		*end = my_end;
215
216	if (errno != ERANGE && min <= v && (max == 0 || v <= max)) {
217		if (value != NULL)
218			*value = v;
219		if (end == NULL)
220			return *my_end == '\0';
221		return true;
222	}
223
224	return false;
225}
226
227bool xtables_strtoui(const char *s, char **end, unsigned int *value,
228                     unsigned int min, unsigned int max)
229{
230	unsigned long v;
231	bool ret;
232
233	ret = xtables_strtoul(s, end, &v, min, max);
234	if (value != NULL)
235		*value = v;
236	return ret;
237}
238
239int xtables_service_to_port(const char *name, const char *proto)
240{
241	struct servent *service;
242
243	if ((service = getservbyname(name, proto)) != NULL)
244		return ntohs((unsigned short) service->s_port);
245
246	return -1;
247}
248
249u_int16_t xtables_parse_port(const char *port, const char *proto)
250{
251	unsigned int portnum;
252
253	if (xtables_strtoui(port, NULL, &portnum, 0, UINT16_MAX) ||
254	    (portnum = xtables_service_to_port(port, proto)) != (unsigned)-1)
255		return portnum;
256
257	exit_error(PARAMETER_PROBLEM,
258		   "invalid port/service `%s' specified", port);
259}
260
261void xtables_parse_interface(const char *arg, char *vianame,
262			     unsigned char *mask)
263{
264	int vialen = strlen(arg);
265	unsigned int i;
266
267	memset(mask, 0, IFNAMSIZ);
268	memset(vianame, 0, IFNAMSIZ);
269
270	if (vialen + 1 > IFNAMSIZ)
271		exit_error(PARAMETER_PROBLEM,
272			   "interface name `%s' must be shorter than IFNAMSIZ"
273			   " (%i)", arg, IFNAMSIZ-1);
274
275	strcpy(vianame, arg);
276	if ((vialen == 0) || (vialen == 1 && vianame[0] == '+'))
277		memset(mask, 0, IFNAMSIZ);
278	else if (vianame[vialen - 1] == '+') {
279		memset(mask, 0xFF, vialen - 1);
280		memset(mask + vialen - 1, 0, IFNAMSIZ - vialen + 1);
281		/* Don't remove `+' here! -HW */
282	} else {
283		/* Include nul-terminator in match */
284		memset(mask, 0xFF, vialen + 1);
285		memset(mask + vialen + 1, 0, IFNAMSIZ - vialen - 1);
286		for (i = 0; vianame[i]; i++) {
287			if (vianame[i] == ':' ||
288			    vianame[i] == '!' ||
289			    vianame[i] == '*') {
290				fprintf(stderr,
291					"Warning: weird character in interface"
292					" `%s' (No aliases, :, ! or *).\n",
293					vianame);
294				break;
295			}
296		}
297	}
298}
299
300#ifndef NO_SHARED_LIBS
301static void *load_extension(const char *search_path, const char *prefix,
302    const char *name, bool is_target)
303{
304	const char *dir = search_path, *next;
305	void *ptr = NULL;
306	struct stat sb;
307	char path[256];
308
309	do {
310		next = strchr(dir, ':');
311		if (next == NULL)
312			next = dir + strlen(dir);
313		snprintf(path, sizeof(path), "%.*s/libxt_%s.so",
314		         (unsigned int)(next - dir), dir, name);
315
316		if (dlopen(path, RTLD_NOW) != NULL) {
317			/* Found library.  If it didn't register itself,
318			   maybe they specified target as match. */
319			if (is_target)
320				ptr = xtables_find_target(name, XTF_DONT_LOAD);
321			else
322				ptr = xtables_find_match(name,
323				      XTF_DONT_LOAD, NULL);
324		} else if (stat(path, &sb) == 0) {
325			fprintf(stderr, "%s: %s\n", path, dlerror());
326		}
327
328		if (ptr != NULL)
329			return ptr;
330
331		snprintf(path, sizeof(path), "%.*s/%s%s.so",
332		         (unsigned int)(next - dir), dir, prefix, name);
333		if (dlopen(path, RTLD_NOW) != NULL) {
334			if (is_target)
335				ptr = xtables_find_target(name, XTF_DONT_LOAD);
336			else
337				ptr = xtables_find_match(name,
338				      XTF_DONT_LOAD, NULL);
339		} else if (stat(path, &sb) == 0) {
340			fprintf(stderr, "%s: %s\n", path, dlerror());
341		}
342
343		if (ptr != NULL)
344			return ptr;
345
346		dir = next + 1;
347	} while (*next != '\0');
348
349	return NULL;
350}
351#endif
352
353struct xtables_match *
354xtables_find_match(const char *name, enum xtables_tryload tryload,
355		   struct xtables_rule_match **matches)
356{
357	struct xtables_match *ptr;
358	const char *icmp6 = "icmp6";
359
360	/* This is ugly as hell. Nonetheless, there is no way of changing
361	 * this without hurting backwards compatibility */
362	if ( (strcmp(name,"icmpv6") == 0) ||
363	     (strcmp(name,"ipv6-icmp") == 0) ||
364	     (strcmp(name,"icmp6") == 0) )
365		name = icmp6;
366
367	for (ptr = xtables_matches; ptr; ptr = ptr->next) {
368		if (strcmp(name, ptr->name) == 0) {
369			struct xtables_match *clone;
370
371			/* First match of this type: */
372			if (ptr->m == NULL)
373				break;
374
375			/* Second and subsequent clones */
376			clone = xtables_malloc(sizeof(struct xtables_match));
377			memcpy(clone, ptr, sizeof(struct xtables_match));
378			clone->mflags = 0;
379			/* This is a clone: */
380			clone->next = clone;
381
382			ptr = clone;
383			break;
384		}
385	}
386
387#ifndef NO_SHARED_LIBS
388	if (!ptr && tryload != XTF_DONT_LOAD && tryload != XTF_DURING_LOAD) {
389		ptr = load_extension(xtables_libdir, afinfo.libprefix,
390		      name, false);
391
392		if (ptr == NULL && tryload == XTF_LOAD_MUST_SUCCEED)
393			exit_error(PARAMETER_PROBLEM,
394				   "Couldn't load match `%s':%s\n",
395				   name, dlerror());
396	}
397#else
398	if (ptr && !ptr->loaded) {
399		if (tryload != XTF_DONT_LOAD)
400			ptr->loaded = 1;
401		else
402			ptr = NULL;
403	}
404	if(!ptr && (tryload == XTF_LOAD_MUST_SUCCEED)) {
405		exit_error(PARAMETER_PROBLEM,
406			   "Couldn't find match `%s'\n", name);
407	}
408#endif
409
410	if (ptr && matches) {
411		struct xtables_rule_match **i;
412		struct xtables_rule_match *newentry;
413
414		newentry = xtables_malloc(sizeof(struct xtables_rule_match));
415
416		for (i = matches; *i; i = &(*i)->next) {
417			if (strcmp(name, (*i)->match->name) == 0)
418				(*i)->completed = true;
419		}
420		newentry->match = ptr;
421		newentry->completed = false;
422		newentry->next = NULL;
423		*i = newentry;
424	}
425
426	return ptr;
427}
428
429struct xtables_target *
430xtables_find_target(const char *name, enum xtables_tryload tryload)
431{
432	struct xtables_target *ptr;
433
434	/* Standard target? */
435	if (strcmp(name, "") == 0
436	    || strcmp(name, XTC_LABEL_ACCEPT) == 0
437	    || strcmp(name, XTC_LABEL_DROP) == 0
438	    || strcmp(name, XTC_LABEL_QUEUE) == 0
439	    || strcmp(name, XTC_LABEL_RETURN) == 0)
440		name = "standard";
441
442	for (ptr = xtables_targets; ptr; ptr = ptr->next) {
443		if (strcmp(name, ptr->name) == 0)
444			break;
445	}
446
447#ifndef NO_SHARED_LIBS
448	if (!ptr && tryload != XTF_DONT_LOAD && tryload != XTF_DURING_LOAD) {
449		ptr = load_extension(xtables_libdir, afinfo.libprefix,
450		      name, true);
451
452		if (ptr == NULL && tryload == XTF_LOAD_MUST_SUCCEED)
453			exit_error(PARAMETER_PROBLEM,
454				   "Couldn't load target `%s':%s\n",
455				   name, dlerror());
456	}
457#else
458	if (ptr && !ptr->loaded) {
459		if (tryload != XTF_DONT_LOAD)
460			ptr->loaded = 1;
461		else
462			ptr = NULL;
463	}
464	if(!ptr && (tryload == LOAD_MUST_SUCCEED)) {
465		exit_error(PARAMETER_PROBLEM,
466			   "Couldn't find target `%s'\n", name);
467	}
468#endif
469
470	if (ptr)
471		ptr->used = 1;
472
473	return ptr;
474}
475
476static int compatible_revision(const char *name, u_int8_t revision, int opt)
477{
478	struct xt_get_revision rev;
479	socklen_t s = sizeof(rev);
480	int max_rev, sockfd;
481
482	sockfd = socket(afinfo.family, SOCK_RAW, IPPROTO_RAW);
483	if (sockfd < 0) {
484		if (errno == EPERM) {
485			/* revision 0 is always supported. */
486			if (revision != 0)
487				fprintf(stderr, "Could not determine whether "
488						"revision %u is supported, "
489						"assuming it is.\n",
490					revision);
491			return 1;
492		}
493		fprintf(stderr, "Could not open socket to kernel: %s\n",
494			strerror(errno));
495		exit(1);
496	}
497
498	xtables_load_ko(xtables_modprobe_program, true);
499
500	strcpy(rev.name, name);
501	rev.revision = revision;
502
503	max_rev = getsockopt(sockfd, afinfo.ipproto, opt, &rev, &s);
504	if (max_rev < 0) {
505		/* Definitely don't support this? */
506		if (errno == ENOENT || errno == EPROTONOSUPPORT) {
507			close(sockfd);
508			return 0;
509		} else if (errno == ENOPROTOOPT) {
510			close(sockfd);
511			/* Assume only revision 0 support (old kernel) */
512			return (revision == 0);
513		} else {
514			fprintf(stderr, "getsockopt failed strangely: %s\n",
515				strerror(errno));
516			exit(1);
517		}
518	}
519	close(sockfd);
520	return 1;
521}
522
523
524static int compatible_match_revision(const char *name, u_int8_t revision)
525{
526	return compatible_revision(name, revision, afinfo.so_rev_match);
527}
528
529static int compatible_target_revision(const char *name, u_int8_t revision)
530{
531	return compatible_revision(name, revision, afinfo.so_rev_target);
532}
533
534void xtables_register_match(struct xtables_match *me)
535{
536	struct xtables_match **i, *old;
537
538	if (strcmp(me->version, XTABLES_VERSION) != 0) {
539		fprintf(stderr, "%s: match \"%s\" has version \"%s\", "
540		        "but \"%s\" is required.\n",
541			xtables_program_name, me->name,
542			me->version, XTABLES_VERSION);
543		exit(1);
544	}
545
546	/* Revision field stole a char from name. */
547	if (strlen(me->name) >= XT_FUNCTION_MAXNAMELEN-1) {
548		fprintf(stderr, "%s: target `%s' has invalid name\n",
549			xtables_program_name, me->name);
550		exit(1);
551	}
552
553	if (me->family >= NPROTO) {
554		fprintf(stderr,
555			"%s: BUG: match %s has invalid protocol family\n",
556			xtables_program_name, me->name);
557		exit(1);
558	}
559
560	/* ignore not interested match */
561	if (me->family != afinfo.family && me->family != AF_UNSPEC)
562		return;
563
564	old = xtables_find_match(me->name, XTF_DURING_LOAD, NULL);
565	if (old) {
566		if (old->revision == me->revision &&
567		    old->family == me->family) {
568			fprintf(stderr,
569				"%s: match `%s' already registered.\n",
570				xtables_program_name, me->name);
571			exit(1);
572		}
573
574		/* Now we have two (or more) options, check compatibility. */
575		if (compatible_match_revision(old->name, old->revision)
576		    && old->revision > me->revision)
577			return;
578
579		/* See if new match can be used. */
580		if (!compatible_match_revision(me->name, me->revision))
581			return;
582
583		/* Prefer !AF_UNSPEC over AF_UNSPEC for same revision. */
584		if (old->revision == me->revision && me->family == AF_UNSPEC)
585			return;
586
587		/* Delete old one. */
588		for (i = &xtables_matches; *i!=old; i = &(*i)->next);
589		*i = old->next;
590	}
591
592	if (me->size != XT_ALIGN(me->size)) {
593		fprintf(stderr, "%s: match `%s' has invalid size %u.\n",
594			xtables_program_name, me->name, (unsigned int)me->size);
595		exit(1);
596	}
597
598	/* Append to list. */
599	for (i = &xtables_matches; *i; i = &(*i)->next);
600	me->next = NULL;
601	*i = me;
602
603	me->m = NULL;
604	me->mflags = 0;
605}
606
607void xtables_register_target(struct xtables_target *me)
608{
609	struct xtables_target *old;
610
611	if (strcmp(me->version, XTABLES_VERSION) != 0) {
612		fprintf(stderr, "%s: target \"%s\" has version \"%s\", "
613		        "but \"%s\" is required.\n",
614			xtables_program_name, me->name,
615			me->version, XTABLES_VERSION);
616		exit(1);
617	}
618
619	/* Revision field stole a char from name. */
620	if (strlen(me->name) >= XT_FUNCTION_MAXNAMELEN-1) {
621		fprintf(stderr, "%s: target `%s' has invalid name\n",
622			xtables_program_name, me->name);
623		exit(1);
624	}
625
626	if (me->family >= NPROTO) {
627		fprintf(stderr,
628			"%s: BUG: target %s has invalid protocol family\n",
629			xtables_program_name, me->name);
630		exit(1);
631	}
632
633	/* ignore not interested target */
634	if (me->family != afinfo.family && me->family != AF_UNSPEC)
635		return;
636
637	old = xtables_find_target(me->name, XTF_DURING_LOAD);
638	if (old) {
639		struct xtables_target **i;
640
641		if (old->revision == me->revision &&
642		    old->family == me->family) {
643			fprintf(stderr,
644				"%s: target `%s' already registered.\n",
645				xtables_program_name, me->name);
646			exit(1);
647		}
648
649		/* Now we have two (or more) options, check compatibility. */
650		if (compatible_target_revision(old->name, old->revision)
651		    && old->revision > me->revision)
652			return;
653
654		/* See if new target can be used. */
655		if (!compatible_target_revision(me->name, me->revision))
656			return;
657
658		/* Prefer !AF_UNSPEC over AF_UNSPEC for same revision. */
659		if (old->revision == me->revision && me->family == AF_UNSPEC)
660			return;
661
662		/* Delete old one. */
663		for (i = &xtables_targets; *i!=old; i = &(*i)->next);
664		*i = old->next;
665	}
666
667	if (me->size != XT_ALIGN(me->size)) {
668		fprintf(stderr, "%s: target `%s' has invalid size %u.\n",
669			xtables_program_name, me->name, (unsigned int)me->size);
670		exit(1);
671	}
672
673	/* Prepend to list. */
674	me->next = xtables_targets;
675	xtables_targets = me;
676	me->t = NULL;
677	me->tflags = 0;
678}
679
680/**
681 * xtables_param_act - act on condition
682 * @status:	a constant from enum xtables_exittype
683 *
684 * %XTF_ONLY_ONCE: print error message that option may only be used once.
685 * @p1:		module name (e.g. "mark")
686 * @p2(...):	option in conflict (e.g. "--mark")
687 * @p3(...):	condition to match on (see extensions/ for examples)
688 *
689 * %XTF_NO_INVERT: option does not support inversion
690 * @p1:		module name
691 * @p2:		option in conflict
692 * @p3:		condition to match on
693 *
694 * %XTF_BAD_VALUE: bad value for option
695 * @p1:		module name
696 * @p2:		option with which the problem occured (e.g. "--mark")
697 * @p3:		string the user passed in (e.g. "99999999999999")
698 *
699 * %XTF_ONE_ACTION: two mutually exclusive actions have been specified
700 * @p1:		module name
701 *
702 * Displays an error message and exits the program.
703 */
704void xtables_param_act(unsigned int status, const char *p1, ...)
705{
706	const char *p2, *p3;
707	va_list args;
708	bool b;
709
710	va_start(args, p1);
711
712	switch (status) {
713	case XTF_ONLY_ONCE:
714		p2 = va_arg(args, const char *);
715		b  = va_arg(args, unsigned int);
716		if (!b)
717			return;
718		exit_error(PARAMETER_PROBLEM,
719		           "%s: \"%s\" option may only be specified once",
720		           p1, p2);
721		break;
722	case XTF_NO_INVERT:
723		p2 = va_arg(args, const char *);
724		b  = va_arg(args, unsigned int);
725		if (!b)
726			return;
727		exit_error(PARAMETER_PROBLEM,
728		           "%s: \"%s\" option cannot be inverted", p1, p2);
729		break;
730	case XTF_BAD_VALUE:
731		p2 = va_arg(args, const char *);
732		p3 = va_arg(args, const char *);
733		exit_error(PARAMETER_PROBLEM,
734		           "%s: Bad value for \"%s\" option: \"%s\"",
735		           p1, p2, p3);
736		break;
737	case XTF_ONE_ACTION:
738		b = va_arg(args, unsigned int);
739		if (!b)
740			return;
741		exit_error(PARAMETER_PROBLEM,
742		           "%s: At most one action is possible", p1);
743		break;
744	default:
745		exit_error(status, p1, args);
746		break;
747	}
748
749	va_end(args);
750}
751
752const char *xtables_ipaddr_to_numeric(const struct in_addr *addrp)
753{
754	static char buf[20];
755	const unsigned char *bytep = (const void *)&addrp->s_addr;
756
757	sprintf(buf, "%u.%u.%u.%u", bytep[0], bytep[1], bytep[2], bytep[3]);
758	return buf;
759}
760
761static const char *ipaddr_to_host(const struct in_addr *addr)
762{
763	struct hostent *host;
764
765	host = gethostbyaddr(addr, sizeof(struct in_addr), AF_INET);
766	if (host == NULL)
767		return NULL;
768
769	return host->h_name;
770}
771
772static const char *ipaddr_to_network(const struct in_addr *addr)
773{
774	struct netent *net;
775
776	if ((net = getnetbyaddr(ntohl(addr->s_addr), AF_INET)) != NULL)
777		return net->n_name;
778
779	return NULL;
780}
781
782const char *xtables_ipaddr_to_anyname(const struct in_addr *addr)
783{
784	const char *name;
785
786	if ((name = ipaddr_to_host(addr)) != NULL ||
787	    (name = ipaddr_to_network(addr)) != NULL)
788		return name;
789
790	return xtables_ipaddr_to_numeric(addr);
791}
792
793const char *xtables_ipmask_to_numeric(const struct in_addr *mask)
794{
795	static char buf[20];
796	uint32_t maskaddr, bits;
797	int i;
798
799	maskaddr = ntohl(mask->s_addr);
800
801	if (maskaddr == 0xFFFFFFFFL)
802		/* we don't want to see "/32" */
803		return "";
804
805	i = 32;
806	bits = 0xFFFFFFFEL;
807	while (--i >= 0 && maskaddr != bits)
808		bits <<= 1;
809	if (i >= 0)
810		sprintf(buf, "/%d", i);
811	else
812		/* mask was not a decent combination of 1's and 0's */
813		sprintf(buf, "/%s", xtables_ipaddr_to_numeric(mask));
814
815	return buf;
816}
817
818static struct in_addr *__numeric_to_ipaddr(const char *dotted, bool is_mask)
819{
820	static struct in_addr addr;
821	unsigned char *addrp;
822	unsigned int onebyte;
823	char buf[20], *p, *q;
824	int i;
825
826	/* copy dotted string, because we need to modify it */
827	strncpy(buf, dotted, sizeof(buf) - 1);
828	buf[sizeof(buf) - 1] = '\0';
829	addrp = (void *)&addr.s_addr;
830
831	p = buf;
832	for (i = 0; i < 3; ++i) {
833		if ((q = strchr(p, '.')) == NULL) {
834			if (is_mask)
835				return NULL;
836
837			/* autocomplete, this is a network address */
838			if (!xtables_strtoui(p, NULL, &onebyte, 0, UINT8_MAX))
839				return NULL;
840
841			addrp[i] = onebyte;
842			while (i < 3)
843				addrp[++i] = 0;
844
845			return &addr;
846		}
847
848		*q = '\0';
849		if (!xtables_strtoui(p, NULL, &onebyte, 0, UINT8_MAX))
850			return NULL;
851
852		addrp[i] = onebyte;
853		p = q + 1;
854	}
855
856	/* we have checked 3 bytes, now we check the last one */
857	if (!xtables_strtoui(p, NULL, &onebyte, 0, UINT8_MAX))
858		return NULL;
859
860	addrp[3] = onebyte;
861	return &addr;
862}
863
864struct in_addr *xtables_numeric_to_ipaddr(const char *dotted)
865{
866	return __numeric_to_ipaddr(dotted, false);
867}
868
869struct in_addr *xtables_numeric_to_ipmask(const char *dotted)
870{
871	return __numeric_to_ipaddr(dotted, true);
872}
873
874static struct in_addr *network_to_ipaddr(const char *name)
875{
876	static struct in_addr addr;
877	struct netent *net;
878
879	if ((net = getnetbyname(name)) != NULL) {
880		if (net->n_addrtype != AF_INET)
881			return NULL;
882		addr.s_addr = htonl(net->n_net);
883		return &addr;
884	}
885
886	return NULL;
887}
888
889static struct in_addr *host_to_ipaddr(const char *name, unsigned int *naddr)
890{
891	struct hostent *host;
892	struct in_addr *addr;
893	unsigned int i;
894
895	*naddr = 0;
896	if ((host = gethostbyname(name)) != NULL) {
897		if (host->h_addrtype != AF_INET ||
898		    host->h_length != sizeof(struct in_addr))
899			return NULL;
900
901		while (host->h_addr_list[*naddr] != NULL)
902			++*naddr;
903		addr = xtables_calloc(*naddr, sizeof(struct in_addr) * *naddr);
904		for (i = 0; i < *naddr; i++)
905			memcpy(&addr[i], host->h_addr_list[i],
906			       sizeof(struct in_addr));
907		return addr;
908	}
909
910	return NULL;
911}
912
913static struct in_addr *
914ipparse_hostnetwork(const char *name, unsigned int *naddrs)
915{
916	struct in_addr *addrptmp, *addrp;
917
918	if ((addrptmp = xtables_numeric_to_ipaddr(name)) != NULL ||
919	    (addrptmp = network_to_ipaddr(name)) != NULL) {
920		addrp = xtables_malloc(sizeof(struct in_addr));
921		memcpy(addrp, addrptmp, sizeof(*addrp));
922		*naddrs = 1;
923		return addrp;
924	}
925	if ((addrptmp = host_to_ipaddr(name, naddrs)) != NULL)
926		return addrptmp;
927
928	exit_error(PARAMETER_PROBLEM, "host/network `%s' not found", name);
929}
930
931static struct in_addr *parse_ipmask(const char *mask)
932{
933	static struct in_addr maskaddr;
934	struct in_addr *addrp;
935	unsigned int bits;
936
937	if (mask == NULL) {
938		/* no mask at all defaults to 32 bits */
939		maskaddr.s_addr = 0xFFFFFFFF;
940		return &maskaddr;
941	}
942	if ((addrp = xtables_numeric_to_ipmask(mask)) != NULL)
943		/* dotted_to_addr already returns a network byte order addr */
944		return addrp;
945	if (!xtables_strtoui(mask, NULL, &bits, 0, 32))
946		exit_error(PARAMETER_PROBLEM,
947			   "invalid mask `%s' specified", mask);
948	if (bits != 0) {
949		maskaddr.s_addr = htonl(0xFFFFFFFF << (32 - bits));
950		return &maskaddr;
951	}
952
953	maskaddr.s_addr = 0U;
954	return &maskaddr;
955}
956
957void ipparse_hostnetworkmask(const char *name, struct in_addr **addrpp,
958                             struct in_addr *maskp, unsigned int *naddrs)
959{
960	unsigned int i, j, k, n;
961	struct in_addr *addrp;
962	char buf[256], *p;
963
964	strncpy(buf, name, sizeof(buf) - 1);
965	buf[sizeof(buf) - 1] = '\0';
966	if ((p = strrchr(buf, '/')) != NULL) {
967		*p = '\0';
968		addrp = parse_ipmask(p + 1);
969	} else {
970		addrp = parse_ipmask(NULL);
971	}
972	memcpy(maskp, addrp, sizeof(*maskp));
973
974	/* if a null mask is given, the name is ignored, like in "any/0" */
975	if (maskp->s_addr == 0U)
976		strcpy(buf, "0.0.0.0");
977
978	addrp = *addrpp = ipparse_hostnetwork(buf, naddrs);
979	n = *naddrs;
980	for (i = 0, j = 0; i < n; ++i) {
981		addrp[j++].s_addr &= maskp->s_addr;
982		for (k = 0; k < j - 1; ++k)
983			if (addrp[k].s_addr == addrp[j-1].s_addr) {
984				--*naddrs;
985				--j;
986				break;
987			}
988	}
989}
990
991const char *xtables_ip6addr_to_numeric(const struct in6_addr *addrp)
992{
993	/* 0000:0000:0000:0000:0000:000.000.000.000
994	 * 0000:0000:0000:0000:0000:0000:0000:0000 */
995	static char buf[50+1];
996	return inet_ntop(AF_INET6, addrp, buf, sizeof(buf));
997}
998
999static const char *ip6addr_to_host(const struct in6_addr *addr)
1000{
1001	static char hostname[NI_MAXHOST];
1002	struct sockaddr_in6 saddr;
1003	int err;
1004
1005	memset(&saddr, 0, sizeof(struct sockaddr_in6));
1006	memcpy(&saddr.sin6_addr, addr, sizeof(*addr));
1007	saddr.sin6_family = AF_INET6;
1008
1009	err = getnameinfo((const void *)&saddr, sizeof(struct sockaddr_in6),
1010	      hostname, sizeof(hostname) - 1, NULL, 0, 0);
1011	if (err != 0) {
1012#ifdef DEBUG
1013		fprintf(stderr,"IP2Name: %s\n",gai_strerror(err));
1014#endif
1015		return NULL;
1016	}
1017
1018#ifdef DEBUG
1019	fprintf (stderr, "\naddr2host: %s\n", hostname);
1020#endif
1021	return hostname;
1022}
1023
1024const char *xtables_ip6addr_to_anyname(const struct in6_addr *addr)
1025{
1026	const char *name;
1027
1028	if ((name = ip6addr_to_host(addr)) != NULL)
1029		return name;
1030
1031	return xtables_ip6addr_to_numeric(addr);
1032}
1033
1034static int ip6addr_prefix_length(const struct in6_addr *k)
1035{
1036	unsigned int bits = 0;
1037	uint32_t a, b, c, d;
1038
1039	a = ntohl(k->s6_addr32[0]);
1040	b = ntohl(k->s6_addr32[1]);
1041	c = ntohl(k->s6_addr32[2]);
1042	d = ntohl(k->s6_addr32[3]);
1043	while (a & 0x80000000U) {
1044		++bits;
1045		a <<= 1;
1046		a  |= (b >> 31) & 1;
1047		b <<= 1;
1048		b  |= (c >> 31) & 1;
1049		c <<= 1;
1050		c  |= (d >> 31) & 1;
1051		d <<= 1;
1052	}
1053	if (a != 0 || b != 0 || c != 0 || d != 0)
1054		return -1;
1055	return bits;
1056}
1057
1058const char *xtables_ip6mask_to_numeric(const struct in6_addr *addrp)
1059{
1060	static char buf[50+2];
1061	int l = ip6addr_prefix_length(addrp);
1062
1063	if (l == -1) {
1064		strcpy(buf, "/");
1065		strcat(buf, xtables_ip6addr_to_numeric(addrp));
1066		return buf;
1067	}
1068	sprintf(buf, "/%d", l);
1069	return buf;
1070}
1071
1072struct in6_addr *xtables_numeric_to_ip6addr(const char *num)
1073{
1074	static struct in6_addr ap;
1075	int err;
1076
1077	if ((err = inet_pton(AF_INET6, num, &ap)) == 1)
1078		return &ap;
1079#ifdef DEBUG
1080	fprintf(stderr, "\nnumeric2addr: %d\n", err);
1081#endif
1082	return NULL;
1083}
1084
1085static struct in6_addr *
1086host_to_ip6addr(const char *name, unsigned int *naddr)
1087{
1088	static struct in6_addr *addr;
1089	struct addrinfo hints;
1090	struct addrinfo *res;
1091	int err;
1092
1093	memset(&hints, 0, sizeof(hints));
1094	hints.ai_flags    = AI_CANONNAME;
1095	hints.ai_family   = AF_INET6;
1096	hints.ai_socktype = SOCK_RAW;
1097	hints.ai_protocol = IPPROTO_IPV6;
1098	hints.ai_next     = NULL;
1099
1100	*naddr = 0;
1101	if ((err = getaddrinfo(name, NULL, &hints, &res)) != 0) {
1102#ifdef DEBUG
1103		fprintf(stderr,"Name2IP: %s\n",gai_strerror(err));
1104#endif
1105		return NULL;
1106	} else {
1107		if (res->ai_family != AF_INET6 ||
1108		    res->ai_addrlen != sizeof(struct sockaddr_in6))
1109			return NULL;
1110
1111#ifdef DEBUG
1112		fprintf(stderr, "resolved: len=%d  %s ", res->ai_addrlen,
1113		        ip6addr_to_numeric(&((struct sockaddr_in6 *)res->ai_addr)->sin6_addr));
1114#endif
1115		/* Get the first element of the address-chain */
1116		addr = xtables_malloc(sizeof(struct in6_addr));
1117		memcpy(addr, &((const struct sockaddr_in6 *)res->ai_addr)->sin6_addr,
1118		       sizeof(struct in6_addr));
1119		freeaddrinfo(res);
1120		*naddr = 1;
1121		return addr;
1122	}
1123
1124	return NULL;
1125}
1126
1127static struct in6_addr *network_to_ip6addr(const char *name)
1128{
1129	/*	abort();*/
1130	/* TODO: not implemented yet, but the exception breaks the
1131	 *       name resolvation */
1132	return NULL;
1133}
1134
1135static struct in6_addr *
1136ip6parse_hostnetwork(const char *name, unsigned int *naddrs)
1137{
1138	struct in6_addr *addrp, *addrptmp;
1139
1140	if ((addrptmp = xtables_numeric_to_ip6addr(name)) != NULL ||
1141	    (addrptmp = network_to_ip6addr(name)) != NULL) {
1142		addrp = xtables_malloc(sizeof(struct in6_addr));
1143		memcpy(addrp, addrptmp, sizeof(*addrp));
1144		*naddrs = 1;
1145		return addrp;
1146	}
1147	if ((addrp = host_to_ip6addr(name, naddrs)) != NULL)
1148		return addrp;
1149
1150	exit_error(PARAMETER_PROBLEM, "host/network `%s' not found", name);
1151}
1152
1153static struct in6_addr *parse_ip6mask(char *mask)
1154{
1155	static struct in6_addr maskaddr;
1156	struct in6_addr *addrp;
1157	unsigned int bits;
1158
1159	if (mask == NULL) {
1160		/* no mask at all defaults to 128 bits */
1161		memset(&maskaddr, 0xff, sizeof maskaddr);
1162		return &maskaddr;
1163	}
1164	if ((addrp = xtables_numeric_to_ip6addr(mask)) != NULL)
1165		return addrp;
1166	if (!xtables_strtoui(mask, NULL, &bits, 0, 128))
1167		exit_error(PARAMETER_PROBLEM,
1168			   "invalid mask `%s' specified", mask);
1169	if (bits != 0) {
1170		char *p = (void *)&maskaddr;
1171		memset(p, 0xff, bits / 8);
1172		memset(p + (bits / 8) + 1, 0, (128 - bits) / 8);
1173		p[bits/8] = 0xff << (8 - (bits & 7));
1174		return &maskaddr;
1175	}
1176
1177	memset(&maskaddr, 0, sizeof(maskaddr));
1178	return &maskaddr;
1179}
1180
1181void ip6parse_hostnetworkmask(const char *name, struct in6_addr **addrpp,
1182                              struct in6_addr *maskp, unsigned int *naddrs)
1183{
1184	struct in6_addr *addrp;
1185	unsigned int i, j, k, n;
1186	char buf[256], *p;
1187
1188	strncpy(buf, name, sizeof(buf) - 1);
1189	buf[sizeof(buf)-1] = '\0';
1190	if ((p = strrchr(buf, '/')) != NULL) {
1191		*p = '\0';
1192		addrp = parse_ip6mask(p + 1);
1193	} else {
1194		addrp = parse_ip6mask(NULL);
1195	}
1196	memcpy(maskp, addrp, sizeof(*maskp));
1197
1198	/* if a null mask is given, the name is ignored, like in "any/0" */
1199	if (memcmp(maskp, &in6addr_any, sizeof(in6addr_any)) == 0)
1200		strcpy(buf, "::");
1201
1202	addrp = *addrpp = ip6parse_hostnetwork(buf, naddrs);
1203	n = *naddrs;
1204	for (i = 0, j = 0; i < n; ++i) {
1205		for (k = 0; k < 4; ++k)
1206			addrp[j].s6_addr32[k] &= maskp->s6_addr32[k];
1207		++j;
1208		for (k = 0; k < j - 1; ++k)
1209			if (IN6_ARE_ADDR_EQUAL(&addrp[k], &addrp[j - 1])) {
1210				--*naddrs;
1211				--j;
1212				break;
1213			}
1214	}
1215}
1216
1217void save_string(const char *value)
1218{
1219	static const char no_quote_chars[] = "_-0123456789"
1220		"abcdefghijklmnopqrstuvwxyz"
1221		"ABCDEFGHIJKLMNOPQRSTUVWXYZ";
1222	static const char escape_chars[] = "\"\\'";
1223	size_t length;
1224	const char *p;
1225
1226	length = strcspn(value, no_quote_chars);
1227	if (length > 0 && value[length] == 0) {
1228		/* no quoting required */
1229		fputs(value, stdout);
1230		putchar(' ');
1231	} else {
1232		/* there is at least one dangerous character in the
1233		   value, which we have to quote.  Write double quotes
1234		   around the value and escape special characters with
1235		   a backslash */
1236		putchar('"');
1237
1238		for (p = strpbrk(value, escape_chars); p != NULL;
1239		     p = strpbrk(value, escape_chars)) {
1240			if (p > value)
1241				fwrite(value, 1, p - value, stdout);
1242			putchar('\\');
1243			putchar(*p);
1244			value = p + 1;
1245		}
1246
1247		/* print the rest and finish the double quoted
1248		   string */
1249		fputs(value, stdout);
1250		printf("\" ");
1251	}
1252}
1253