xref: /aosp_15_r20/external/iptables/libxtables/xtoptions.c (revision a71a954618bbadd4a345637e5edcf36eec826889)
1 /*
2  *	Argument parser
3  *	Copyright © Jan Engelhardt, 2011
4  *
5  *	This program is free software; you can redistribute it and/or
6  *	modify it under the terms of the GNU General Public License as
7  *	published by the Free Software Foundation; either version 2 of
8  *	the License, or (at your option) any later version.
9  */
10 #include <ctype.h>
11 #include <errno.h>
12 #include <getopt.h>
13 #include <limits.h>
14 #include <netdb.h>
15 #include <stdbool.h>
16 #include <stdint.h>
17 #include <stdio.h>
18 #include <stdlib.h>
19 #include <string.h>
20 #include <syslog.h>
21 #include <arpa/inet.h>
22 #include <netinet/ip.h>
23 #include "xtables.h"
24 #ifndef IPTOS_NORMALSVC
25 #	define IPTOS_NORMALSVC 0
26 #endif
27 
28 #define XTOPT_MKPTR(cb) \
29 	((void *)((char *)(cb)->data + (cb)->entry->ptroff))
30 
31 /**
32  * Simple key-value pairs for syslog levels
33  */
34 struct syslog_level {
35 	char name[8];
36 	uint8_t level;
37 };
38 
39 struct tos_value_mask {
40 	uint8_t value, mask;
41 };
42 
43 static const size_t xtopt_psize[] = {
44 	/*
45 	 * All types not listed here, and thus essentially being initialized to
46 	 * zero have zero on purpose.
47 	 */
48 	[XTTYPE_UINT8]       = sizeof(uint8_t),
49 	[XTTYPE_UINT16]      = sizeof(uint16_t),
50 	[XTTYPE_UINT32]      = sizeof(uint32_t),
51 	[XTTYPE_UINT64]      = sizeof(uint64_t),
52 	[XTTYPE_UINT8RC]     = sizeof(uint8_t[2]),
53 	[XTTYPE_UINT16RC]    = sizeof(uint16_t[2]),
54 	[XTTYPE_UINT32RC]    = sizeof(uint32_t[2]),
55 	[XTTYPE_UINT64RC]    = sizeof(uint64_t[2]),
56 	[XTTYPE_DOUBLE]      = sizeof(double),
57 	[XTTYPE_STRING]      = -1,
58 	[XTTYPE_SYSLOGLEVEL] = sizeof(uint8_t),
59 	[XTTYPE_HOST]        = sizeof(union nf_inet_addr),
60 	[XTTYPE_HOSTMASK]    = sizeof(union nf_inet_addr),
61 	[XTTYPE_PROTOCOL]    = sizeof(uint8_t),
62 	[XTTYPE_PORT]        = sizeof(uint16_t),
63 	[XTTYPE_PORTRC]      = sizeof(uint16_t[2]),
64 	[XTTYPE_PLENMASK]    = sizeof(union nf_inet_addr),
65 	[XTTYPE_ETHERMAC]    = sizeof(uint8_t[6]),
66 };
67 
68 /**
69  * Creates getopt options from the x6-style option map, and assigns each a
70  * getopt id.
71  */
72 struct option *
xtables_options_xfrm(struct option * orig_opts,struct option * oldopts,const struct xt_option_entry * entry,unsigned int * offset)73 xtables_options_xfrm(struct option *orig_opts, struct option *oldopts,
74 		     const struct xt_option_entry *entry, unsigned int *offset)
75 {
76 	unsigned int num_orig, num_old = 0, num_new, i;
77 	struct option *merge, *mp;
78 
79 	if (entry == NULL)
80 		return oldopts;
81 	for (num_orig = 0; orig_opts[num_orig].name != NULL; ++num_orig)
82 		;
83 	if (oldopts != NULL)
84 		for (num_old = 0; oldopts[num_old].name != NULL; ++num_old)
85 			;
86 	for (num_new = 0; entry[num_new].name != NULL; ++num_new)
87 		;
88 
89 	/*
90 	 * Since @oldopts also has @orig_opts already (and does so at the
91 	 * start), skip these entries.
92 	 */
93 	if (oldopts != NULL) {
94 		oldopts += num_orig;
95 		num_old -= num_orig;
96 	}
97 
98 	merge = malloc(sizeof(*mp) * (num_orig + num_old + num_new + 1));
99 	if (merge == NULL)
100 		return NULL;
101 
102 	/* Let the base options -[ADI...] have precedence over everything */
103 	memcpy(merge, orig_opts, sizeof(*mp) * num_orig);
104 	mp = merge + num_orig;
105 
106 	/* Second, the new options */
107 	xt_params->option_offset += XT_OPTION_OFFSET_SCALE;
108 	*offset = xt_params->option_offset;
109 
110 	for (i = 0; i < num_new; ++i, ++mp, ++entry) {
111 		mp->name         = entry->name;
112 		mp->has_arg      = entry->type != XTTYPE_NONE;
113 		mp->flag         = NULL;
114 		mp->val          = entry->id + *offset;
115 	}
116 
117 	/* Third, the old options */
118 	if (oldopts != NULL) {
119 		memcpy(mp, oldopts, sizeof(*mp) * num_old);
120 		mp += num_old;
121 	}
122 	xtables_free_opts(0);
123 
124 	/* Clear trailing entry */
125 	memset(mp, 0, sizeof(*mp));
126 	return merge;
127 }
128 
129 /**
130  * Give the upper limit for a certain type.
131  */
xtopt_max_by_type(enum xt_option_type type)132 static uintmax_t xtopt_max_by_type(enum xt_option_type type)
133 {
134 	switch (type) {
135 	case XTTYPE_UINT8:
136 	case XTTYPE_UINT8RC:
137 		return UINT8_MAX;
138 	case XTTYPE_UINT16:
139 	case XTTYPE_UINT16RC:
140 		return UINT16_MAX;
141 	case XTTYPE_UINT32:
142 	case XTTYPE_UINT32RC:
143 		return UINT32_MAX;
144 	case XTTYPE_UINT64:
145 	case XTTYPE_UINT64RC:
146 		return UINT64_MAX;
147 	default:
148 		return 0;
149 	}
150 }
151 
152 /**
153  * Return the size of a single entity based upon a type - predominantly an
154  * XTTYPE_UINT*RC type.
155  */
xtopt_esize_by_type(enum xt_option_type type)156 static size_t xtopt_esize_by_type(enum xt_option_type type)
157 {
158 	switch (type) {
159 	case XTTYPE_UINT8RC:
160 		return xtopt_psize[XTTYPE_UINT8];
161 	case XTTYPE_UINT16RC:
162 		return xtopt_psize[XTTYPE_UINT16];
163 	case XTTYPE_UINT32RC:
164 		return xtopt_psize[XTTYPE_UINT32];
165 	case XTTYPE_UINT64RC:
166 		return xtopt_psize[XTTYPE_UINT64];
167 	default:
168 		return xtopt_psize[type];
169 	}
170 }
171 
172 /**
173  * Require a simple integer.
174  */
xtopt_parse_int(struct xt_option_call * cb)175 static void xtopt_parse_int(struct xt_option_call *cb)
176 {
177 	const struct xt_option_entry *entry = cb->entry;
178 	uintmax_t lmin = 0, lmax = xtopt_max_by_type(entry->type);
179 	uintmax_t value;
180 
181 	if (cb->entry->min != 0)
182 		lmin = cb->entry->min;
183 	if (cb->entry->max != 0)
184 		lmax = cb->entry->max;
185 
186 	if (!xtables_strtoul(cb->arg, NULL, &value, lmin, lmax))
187 		xt_params->exit_err(PARAMETER_PROBLEM,
188 			"%s: bad value for option \"--%s\", "
189 			"or out of range (%ju-%ju).\n",
190 			cb->ext_name, entry->name, lmin, lmax);
191 
192 	if (entry->type == XTTYPE_UINT8) {
193 		cb->val.u8 = value;
194 		if (entry->flags & XTOPT_PUT)
195 			*(uint8_t *)XTOPT_MKPTR(cb) = cb->val.u8;
196 	} else if (entry->type == XTTYPE_UINT16) {
197 		cb->val.u16 = value;
198 		if (entry->flags & XTOPT_PUT)
199 			*(uint16_t *)XTOPT_MKPTR(cb) = cb->val.u16;
200 	} else if (entry->type == XTTYPE_UINT32) {
201 		cb->val.u32 = value;
202 		if (entry->flags & XTOPT_PUT)
203 			*(uint32_t *)XTOPT_MKPTR(cb) = cb->val.u32;
204 	} else if (entry->type == XTTYPE_UINT64) {
205 		cb->val.u64 = value;
206 		if (entry->flags & XTOPT_PUT)
207 			*(uint64_t *)XTOPT_MKPTR(cb) = cb->val.u64;
208 	}
209 }
210 
211 /**
212  * Require a simple floating point number.
213  */
xtopt_parse_float(struct xt_option_call * cb)214 static void xtopt_parse_float(struct xt_option_call *cb)
215 {
216 	const struct xt_option_entry *entry = cb->entry;
217 	double value;
218 	char *end;
219 
220 	value = strtod(cb->arg, &end);
221 	if (end == cb->arg || *end != '\0' ||
222 	    (entry->min != entry->max &&
223 	    (value < entry->min || value > entry->max)))
224 		xt_params->exit_err(PARAMETER_PROBLEM,
225 			"%s: bad value for option \"--%s\", "
226 			"or out of range (%u-%u).\n",
227 			cb->ext_name, entry->name, entry->min, entry->max);
228 
229 	cb->val.dbl = value;
230 	if (entry->flags & XTOPT_PUT)
231 		*(double *)XTOPT_MKPTR(cb) = cb->val.dbl;
232 }
233 
234 /**
235  * Copy the parsed value to the appropriate entry in cb->val.
236  */
xtopt_mint_value_to_cb(struct xt_option_call * cb,uintmax_t value)237 static void xtopt_mint_value_to_cb(struct xt_option_call *cb, uintmax_t value)
238 {
239 	const struct xt_option_entry *entry = cb->entry;
240 
241 	if (cb->nvals >= ARRAY_SIZE(cb->val.u32_range))
242 		return;
243 	if (entry->type == XTTYPE_UINT8RC)
244 		cb->val.u8_range[cb->nvals] = value;
245 	else if (entry->type == XTTYPE_UINT16RC)
246 		cb->val.u16_range[cb->nvals] = value;
247 	else if (entry->type == XTTYPE_UINT32RC)
248 		cb->val.u32_range[cb->nvals] = value;
249 	else if (entry->type == XTTYPE_UINT64RC)
250 		cb->val.u64_range[cb->nvals] = value;
251 }
252 
253 /**
254  * Copy the parsed value to the data area, using appropriate type access.
255  */
xtopt_mint_value_to_ptr(struct xt_option_call * cb,void ** datap,uintmax_t value)256 static void xtopt_mint_value_to_ptr(struct xt_option_call *cb, void **datap,
257 				    uintmax_t value)
258 {
259 	const struct xt_option_entry *entry = cb->entry;
260 	void *data = *datap;
261 
262 	if (!(entry->flags & XTOPT_PUT))
263 		return;
264 	if (entry->type == XTTYPE_UINT8RC)
265 		*(uint8_t *)data = value;
266 	else if (entry->type == XTTYPE_UINT16RC)
267 		*(uint16_t *)data = value;
268 	else if (entry->type == XTTYPE_UINT32RC)
269 		*(uint32_t *)data = value;
270 	else if (entry->type == XTTYPE_UINT64RC)
271 		*(uint64_t *)data = value;
272 	data += xtopt_esize_by_type(entry->type);
273 	*datap = data;
274 }
275 
276 /**
277  * Multiple integer parse routine.
278  *
279  * This function is capable of parsing any number of fields. Only the first
280  * two values from the string will be put into @cb however (and as such,
281  * @cb->val.uXX_range is just that large) to cater for the few extensions that
282  * do not have a range[2] field, but {min, max}, and which cannot use
283  * XTOPT_POINTER.
284  */
xtopt_parse_mint(struct xt_option_call * cb)285 static void xtopt_parse_mint(struct xt_option_call *cb)
286 {
287 	const struct xt_option_entry *entry = cb->entry;
288 	const char *arg;
289 	size_t esize = xtopt_esize_by_type(entry->type);
290 	const uintmax_t lmax = xtopt_max_by_type(entry->type);
291 	void *put = XTOPT_MKPTR(cb);
292 	unsigned int maxiter;
293 	uintmax_t value;
294 	char *end = "";
295 	char sep = ':';
296 
297 	maxiter = entry->size / esize;
298 	if (maxiter == 0)
299 		maxiter = ARRAY_SIZE(cb->val.u32_range);
300 	if (entry->size % esize != 0)
301 		xt_params->exit_err(OTHER_PROBLEM, "%s: memory block does "
302 			"not have proper size\n", __func__);
303 
304 	cb->nvals = 0;
305 	for (arg = cb->arg, end = (char *)arg; ; arg = end + 1) {
306 		if (cb->nvals == maxiter)
307 			xt_params->exit_err(PARAMETER_PROBLEM, "%s: Too many "
308 				"components for option \"--%s\" (max: %u)\n",
309 				cb->ext_name, entry->name, maxiter);
310 		if (*arg == '\0' || *arg == sep) {
311 			/* Default range components when field not spec'd. */
312 			end = (char *)arg;
313 			value = (cb->nvals == 1) ? lmax : 0;
314 		} else {
315 			if (!xtables_strtoul(arg, &end, &value, 0, lmax))
316 				xt_params->exit_err(PARAMETER_PROBLEM,
317 					"%s: bad value for option \"--%s\" near "
318 					"\"%s\", or out of range (0-%ju).\n",
319 					cb->ext_name, entry->name, arg, lmax);
320 			if (*end != '\0' && *end != sep)
321 				xt_params->exit_err(PARAMETER_PROBLEM,
322 					"%s: Argument to \"--%s\" has "
323 					"unexpected characters near \"%s\".\n",
324 					cb->ext_name, entry->name, end);
325 		}
326 		xtopt_mint_value_to_cb(cb, value);
327 		++cb->nvals;
328 		xtopt_mint_value_to_ptr(cb, &put, value);
329 		if (*end == '\0')
330 			break;
331 	}
332 }
333 
xtopt_parse_string(struct xt_option_call * cb)334 static void xtopt_parse_string(struct xt_option_call *cb)
335 {
336 	const struct xt_option_entry *entry = cb->entry;
337 	size_t z = strlen(cb->arg);
338 	char *p;
339 
340 	if (entry->min != 0 && z < entry->min)
341 		xt_params->exit_err(PARAMETER_PROBLEM,
342 			"Argument must have a minimum length of "
343 			"%u characters\n", entry->min);
344 	if (entry->max != 0 && z > entry->max)
345 		xt_params->exit_err(PARAMETER_PROBLEM,
346 			"Argument must have a maximum length of "
347 			"%u characters\n", entry->max);
348 	if (!(entry->flags & XTOPT_PUT))
349 		return;
350 	if (z >= entry->size)
351 		z = entry->size - 1;
352 	p = XTOPT_MKPTR(cb);
353 	strncpy(p, cb->arg, z);
354 	p[z] = '\0';
355 }
356 
357 static const struct tos_symbol_info {
358 	unsigned char value;
359 	const char *name;
360 } tos_symbol_names[] = {
361 	{IPTOS_LOWDELAY,    "Minimize-Delay"},
362 	{IPTOS_THROUGHPUT,  "Maximize-Throughput"},
363 	{IPTOS_RELIABILITY, "Maximize-Reliability"},
364 	{IPTOS_MINCOST,     "Minimize-Cost"},
365 	{IPTOS_NORMALSVC,   "Normal-Service"},
366 	{},
367 };
368 
369 /*
370  * tos_parse_numeric - parse a string like "15/255"
371  *
372  * @str:	input string
373  * @tvm:	(value/mask) tuple
374  * @max:	maximum allowed value (must be pow(2,some_int)-1)
375  */
tos_parse_numeric(const char * str,struct xt_option_call * cb,unsigned int max)376 static bool tos_parse_numeric(const char *str, struct xt_option_call *cb,
377                               unsigned int max)
378 {
379 	unsigned int value;
380 	char *end;
381 
382 	xtables_strtoui(str, &end, &value, 0, max);
383 	cb->val.tos_value = value;
384 	cb->val.tos_mask  = max;
385 
386 	if (*end == '/') {
387 		const char *p = end + 1;
388 
389 		if (!xtables_strtoui(p, &end, &value, 0, max))
390 			xtables_error(PARAMETER_PROBLEM, "Illegal value: \"%s\"",
391 			           str);
392 		cb->val.tos_mask = value;
393 	}
394 
395 	if (*end != '\0')
396 		xtables_error(PARAMETER_PROBLEM, "Illegal value: \"%s\"", str);
397 	return true;
398 }
399 
400 /**
401  * @str:	input string
402  * @tvm:	(value/mask) tuple
403  * @def_mask:	mask to force when a symbolic name is used
404  */
xtopt_parse_tosmask(struct xt_option_call * cb)405 static void xtopt_parse_tosmask(struct xt_option_call *cb)
406 {
407 	const struct tos_symbol_info *symbol;
408 	char *tmp;
409 
410 	if (xtables_strtoui(cb->arg, &tmp, NULL, 0, UINT8_MAX)) {
411 		tos_parse_numeric(cb->arg, cb, UINT8_MAX);
412 		return;
413 	}
414 	/*
415 	 * This is our way we deal with different defaults
416 	 * for different revisions.
417 	 */
418 	cb->val.tos_mask = cb->entry->max;
419 	for (symbol = tos_symbol_names; symbol->name != NULL; ++symbol)
420 		if (strcasecmp(cb->arg, symbol->name) == 0) {
421 			cb->val.tos_value = symbol->value;
422 			return;
423 		}
424 
425 	xtables_error(PARAMETER_PROBLEM, "Symbolic name \"%s\" is unknown",
426 		      cb->arg);
427 }
428 
429 /**
430  * Validate the input for being conformant to "mark[/mask]".
431  */
xtopt_parse_markmask(struct xt_option_call * cb)432 static void xtopt_parse_markmask(struct xt_option_call *cb)
433 {
434 	xtables_parse_mark_mask(cb, &cb->val.mark, &cb->val.mask);
435 }
436 
xtopt_sysloglvl_compare(const void * a,const void * b)437 static int xtopt_sysloglvl_compare(const void *a, const void *b)
438 {
439 	const char *name = a;
440 	const struct syslog_level *entry = b;
441 
442 	return strcmp(name, entry->name);
443 }
444 
xtopt_parse_sysloglevel(struct xt_option_call * cb)445 static void xtopt_parse_sysloglevel(struct xt_option_call *cb)
446 {
447 	static const struct syslog_level log_names[] = { /* must be sorted */
448 		{"alert",   LOG_ALERT},
449 		{"crit",    LOG_CRIT},
450 		{"debug",   LOG_DEBUG},
451 		{"emerg",   LOG_EMERG},
452 		{"error",   LOG_ERR}, /* deprecated */
453 		{"info",    LOG_INFO},
454 		{"notice",  LOG_NOTICE},
455 		{"panic",   LOG_EMERG}, /* deprecated */
456 		{"warning", LOG_WARNING},
457 	};
458 	const struct syslog_level *e;
459 	unsigned int num = 0;
460 
461 	if (!xtables_strtoui(cb->arg, NULL, &num, 0, 7)) {
462 		e = bsearch(cb->arg, log_names, ARRAY_SIZE(log_names),
463 			    sizeof(*log_names), xtopt_sysloglvl_compare);
464 		if (e == NULL)
465 			xt_params->exit_err(PARAMETER_PROBLEM,
466 				"log level \"%s\" unknown\n", cb->arg);
467 		num = e->level;
468 	}
469 	cb->val.syslog_level = num;
470 	if (cb->entry->flags & XTOPT_PUT)
471 		*(uint8_t *)XTOPT_MKPTR(cb) = num;
472 }
473 
xtables_sa_host(const void * sa,unsigned int afproto)474 static void *xtables_sa_host(const void *sa, unsigned int afproto)
475 {
476 	if (afproto == AF_INET6)
477 		return &((struct sockaddr_in6 *)sa)->sin6_addr;
478 	else if (afproto == AF_INET)
479 		return &((struct sockaddr_in *)sa)->sin_addr;
480 	return (void *)sa;
481 }
482 
xtables_sa_hostlen(unsigned int afproto)483 static socklen_t xtables_sa_hostlen(unsigned int afproto)
484 {
485 	if (afproto == AF_INET6)
486 		return sizeof(struct in6_addr);
487 	else if (afproto == AF_INET)
488 		return sizeof(struct in_addr);
489 	return 0;
490 }
491 
492 /**
493  * Accepts: a hostname (DNS), or a single inetaddr - without any mask. The
494  * result is stored in @cb->val.haddr. Additionally, @cb->val.hmask and
495  * @cb->val.hlen are set for completeness to the appropriate values.
496  */
xtopt_parse_host(struct xt_option_call * cb)497 static void xtopt_parse_host(struct xt_option_call *cb)
498 {
499 	struct addrinfo hints = {.ai_family = afinfo->family};
500 	unsigned int adcount = 0;
501 	struct addrinfo *res, *p;
502 	int ret;
503 
504 	ret = getaddrinfo(cb->arg, NULL, &hints, &res);
505 	if (ret != 0)
506 		xt_params->exit_err(PARAMETER_PROBLEM,
507 			"getaddrinfo: %s\n", gai_strerror(ret));
508 
509 	memset(&cb->val.hmask, 0xFF, sizeof(cb->val.hmask));
510 	cb->val.hlen = (afinfo->family == NFPROTO_IPV4) ? 32 : 128;
511 
512 	for (p = res; p != NULL; p = p->ai_next) {
513 		if (adcount == 0) {
514 			memset(&cb->val.haddr, 0, sizeof(cb->val.haddr));
515 			memcpy(&cb->val.haddr,
516 			       xtables_sa_host(p->ai_addr, p->ai_family),
517 			       xtables_sa_hostlen(p->ai_family));
518 			++adcount;
519 			continue;
520 		}
521 		if (memcmp(&cb->val.haddr,
522 		    xtables_sa_host(p->ai_addr, p->ai_family),
523 		    xtables_sa_hostlen(p->ai_family)) != 0)
524 			xt_params->exit_err(PARAMETER_PROBLEM,
525 				"%s resolves to more than one address\n",
526 				cb->arg);
527 	}
528 
529 	freeaddrinfo(res);
530 	if (cb->entry->flags & XTOPT_PUT)
531 		/* Validation in xtables_option_metavalidate */
532 		memcpy(XTOPT_MKPTR(cb), &cb->val.haddr,
533 		       sizeof(cb->val.haddr));
534 }
535 
536 /**
537  * @name:	port name, or number as a string (e.g. "http" or "80")
538  *
539  * Resolve a port name to a number. Returns the port number in integral
540  * form on success, or <0 on error. (errno will not be set.)
541  */
xtables_getportbyname(const char * name)542 static int xtables_getportbyname(const char *name)
543 {
544 	struct addrinfo *res = NULL, *p;
545 	int ret;
546 
547 	ret = getaddrinfo(NULL, name, NULL, &res);
548 	if (ret != 0)
549 		return -1;
550 	ret = -1;
551 	for (p = res; p != NULL; p = p->ai_next) {
552 		if (p->ai_family == AF_INET6) {
553 			ret = ((struct sockaddr_in6 *)p->ai_addr)->sin6_port;
554 			break;
555 		} else if (p->ai_family == AF_INET) {
556 			ret = ((struct sockaddr_in *)p->ai_addr)->sin_port;
557 			break;
558 		}
559 	}
560 	freeaddrinfo(res);
561 	if (ret < 0)
562 		return ret;
563 	return ntohs(ret);
564 }
565 
566 /**
567  * Validate and parse a protocol specification (number or name) by use of
568  * /etc/protocols and put the result into @cb->val.protocol.
569  */
xtopt_parse_protocol(struct xt_option_call * cb)570 static void xtopt_parse_protocol(struct xt_option_call *cb)
571 {
572 	cb->val.protocol = xtables_parse_protocol(cb->arg);
573 	if (cb->entry->flags & XTOPT_PUT)
574 		*(uint8_t *)XTOPT_MKPTR(cb) = cb->val.protocol;
575 }
576 
577 /**
578  * Validate and parse a port specification and put the result into
579  * @cb->val.port.
580  */
xtopt_parse_port(struct xt_option_call * cb)581 static void xtopt_parse_port(struct xt_option_call *cb)
582 {
583 	const struct xt_option_entry *entry = cb->entry;
584 	int ret;
585 
586 	ret = xtables_getportbyname(cb->arg);
587 	if (ret < 0)
588 		xt_params->exit_err(PARAMETER_PROBLEM,
589 			"Port \"%s\" does not resolve to anything.\n",
590 			cb->arg);
591 	if (entry->flags & XTOPT_NBO)
592 		ret = htons(ret);
593 	cb->val.port = ret;
594 	if (entry->flags & XTOPT_PUT)
595 		*(uint16_t *)XTOPT_MKPTR(cb) = cb->val.port;
596 }
597 
xtopt_parse_mport(struct xt_option_call * cb)598 static void xtopt_parse_mport(struct xt_option_call *cb)
599 {
600 	static const size_t esize = sizeof(uint16_t);
601 	const struct xt_option_entry *entry = cb->entry;
602 	char *lo_arg, *wp_arg, *arg;
603 	unsigned int maxiter;
604 	int value;
605 
606 	wp_arg = lo_arg = xtables_strdup(cb->arg);
607 
608 	maxiter = entry->size / esize;
609 	if (maxiter == 0)
610 		maxiter = 2; /* ARRAY_SIZE(cb->val.port_range) */
611 	if (entry->size % esize != 0)
612 		xt_params->exit_err(OTHER_PROBLEM, "%s: memory block does "
613 			"not have proper size\n", __func__);
614 
615 	cb->val.port_range[0] = 0;
616 	cb->val.port_range[1] = UINT16_MAX;
617 	cb->nvals = 0;
618 
619 	while ((arg = strsep(&wp_arg, ":")) != NULL) {
620 		if (cb->nvals == maxiter)
621 			xt_params->exit_err(PARAMETER_PROBLEM, "%s: Too many "
622 				"components for option \"--%s\" (max: %u)\n",
623 				cb->ext_name, entry->name, maxiter);
624 		if (*arg == '\0') {
625 			++cb->nvals;
626 			continue;
627 		}
628 
629 		value = xtables_getportbyname(arg);
630 		if (value < 0)
631 			xt_params->exit_err(PARAMETER_PROBLEM,
632 				"Port \"%s\" does not resolve to "
633 				"anything.\n", arg);
634 		if (entry->flags & XTOPT_NBO)
635 			value = htons(value);
636 		if (cb->nvals < ARRAY_SIZE(cb->val.port_range))
637 			cb->val.port_range[cb->nvals] = value;
638 		++cb->nvals;
639 	}
640 
641 	if (cb->nvals == 1) {
642 		cb->val.port_range[1] = cb->val.port_range[0];
643 		++cb->nvals;
644 	}
645 	if (entry->flags & XTOPT_PUT)
646 		memcpy(XTOPT_MKPTR(cb), cb->val.port_range, sizeof(uint16_t) *
647 		       (cb->nvals <= maxiter ? cb->nvals : maxiter));
648 	free(lo_arg);
649 }
650 
xtopt_parse_mask(struct xt_option_call * cb)651 static int xtopt_parse_mask(struct xt_option_call *cb)
652 {
653 	struct addrinfo hints = {.ai_family = afinfo->family,
654 				 .ai_flags = AI_NUMERICHOST };
655 	struct addrinfo *res;
656 	int ret;
657 
658 	ret = getaddrinfo(cb->arg, NULL, &hints, &res);
659 	if (ret != 0)
660 		return 0;
661 
662 	memcpy(&cb->val.hmask, xtables_sa_host(res->ai_addr, res->ai_family),
663 	       xtables_sa_hostlen(res->ai_family));
664 
665 	switch(afinfo->family) {
666 	case AF_INET:
667 		cb->val.hlen = xtables_ipmask_to_cidr(&cb->val.hmask.in);
668 		break;
669 	case AF_INET6:
670 		cb->val.hlen = xtables_ip6mask_to_cidr(&cb->val.hmask.in6);
671 		break;
672 	}
673 
674 	freeaddrinfo(res);
675 	return 1;
676 }
677 
678 /**
679  * Parse an integer and ensure it is within the address family's prefix length
680  * limits. The result is stored in @cb->val.hlen.
681  */
xtopt_parse_plen(struct xt_option_call * cb)682 static void xtopt_parse_plen(struct xt_option_call *cb)
683 {
684 	const struct xt_option_entry *entry = cb->entry;
685 	unsigned int prefix_len = 128; /* happiness is a warm gcc */
686 
687 	cb->val.hlen = (afinfo->family == NFPROTO_IPV4) ? 32 : 128;
688 	if (!xtables_strtoui(cb->arg, NULL, &prefix_len, 0, cb->val.hlen)) {
689 		/* Is this mask expressed in full format? e.g. 255.255.255.0 */
690 		if (xtopt_parse_mask(cb))
691 			return;
692 
693 		xt_params->exit_err(PARAMETER_PROBLEM,
694 			"%s: bad value for option \"--%s\", "
695 			"neither a valid network mask "
696 			"nor valid CIDR (%u-%u).\n",
697 			cb->ext_name, entry->name, 0, cb->val.hlen);
698 	}
699 	cb->val.hlen = prefix_len;
700 }
701 
702 /**
703  * Reuse xtopt_parse_plen for testing the integer. Afterwards convert this to
704  * a bitmask, and make it available through @cb->val.hmask (hlen remains
705  * valid). If %XTOPT_PUT is used, hmask will be copied to the target area.
706  */
xtopt_parse_plenmask(struct xt_option_call * cb)707 static void xtopt_parse_plenmask(struct xt_option_call *cb)
708 {
709 	const struct xt_option_entry *entry = cb->entry;
710 	uint32_t *mask = cb->val.hmask.all;
711 
712 	xtopt_parse_plen(cb);
713 
714 	memset(mask, 0xFF, sizeof(union nf_inet_addr));
715 	/* This shifting is AF-independent. */
716 	if (cb->val.hlen == 0) {
717 		mask[0] = mask[1] = mask[2] = mask[3] = 0;
718 	} else if (cb->val.hlen <= 32) {
719 		mask[0] <<= 32 - cb->val.hlen;
720 		mask[1] = mask[2] = mask[3] = 0;
721 	} else if (cb->val.hlen <= 64) {
722 		mask[1] <<= 32 - (cb->val.hlen - 32);
723 		mask[2] = mask[3] = 0;
724 	} else if (cb->val.hlen <= 96) {
725 		mask[2] <<= 32 - (cb->val.hlen - 64);
726 		mask[3] = 0;
727 	} else if (cb->val.hlen <= 128) {
728 		mask[3] <<= 32 - (cb->val.hlen - 96);
729 	}
730 	mask[0] = htonl(mask[0]);
731 	mask[1] = htonl(mask[1]);
732 	mask[2] = htonl(mask[2]);
733 	mask[3] = htonl(mask[3]);
734 	if (entry->flags & XTOPT_PUT)
735 		memcpy(XTOPT_MKPTR(cb), mask, sizeof(union nf_inet_addr));
736 }
737 
xtopt_parse_hostmask(struct xt_option_call * cb)738 static void xtopt_parse_hostmask(struct xt_option_call *cb)
739 {
740 	const char *orig_arg = cb->arg;
741 	char *work, *p;
742 
743 	if (strchr(cb->arg, '/') == NULL) {
744 		xtopt_parse_host(cb);
745 		return;
746 	}
747 	work = xtables_strdup(orig_arg);
748 	p = strchr(work, '/'); /* by def this can't be NULL now */
749 	*p++ = '\0';
750 	/*
751 	 * Because xtopt_parse_host and xtopt_parse_plenmask would store
752 	 * different things in the same target area, XTTYPE_HOSTMASK must
753 	 * disallow XTOPT_PUT, which it does by forcing its absence,
754 	 * cf. not being listed in xtopt_psize.
755 	 */
756 	cb->arg = work;
757 	xtopt_parse_host(cb);
758 	cb->arg = p;
759 	xtopt_parse_plenmask(cb);
760 	cb->arg = orig_arg;
761 	free(work);
762 }
763 
xtopt_parse_ethermac(struct xt_option_call * cb)764 static void xtopt_parse_ethermac(struct xt_option_call *cb)
765 {
766 	const char *arg = cb->arg;
767 	unsigned int i;
768 	char *end;
769 
770 	for (i = 0; i < ARRAY_SIZE(cb->val.ethermac) - 1; ++i) {
771 		cb->val.ethermac[i] = strtoul(arg, &end, 16);
772 		if (*end != ':' || end - arg > 2)
773 			goto out;
774 		arg = end + 1;
775 	}
776 	i = ARRAY_SIZE(cb->val.ethermac) - 1;
777 	cb->val.ethermac[i] = strtoul(arg, &end, 16);
778 	if (*end != '\0' || end - arg > 2)
779 		goto out;
780 	if (cb->entry->flags & XTOPT_PUT)
781 		memcpy(XTOPT_MKPTR(cb), cb->val.ethermac,
782 		       sizeof(cb->val.ethermac));
783 	return;
784  out:
785 	xt_params->exit_err(PARAMETER_PROBLEM, "Invalid MAC address specified.");
786 }
787 
788 static void (*const xtopt_subparse[])(struct xt_option_call *) = {
789 	[XTTYPE_UINT8]       = xtopt_parse_int,
790 	[XTTYPE_UINT16]      = xtopt_parse_int,
791 	[XTTYPE_UINT32]      = xtopt_parse_int,
792 	[XTTYPE_UINT64]      = xtopt_parse_int,
793 	[XTTYPE_UINT8RC]     = xtopt_parse_mint,
794 	[XTTYPE_UINT16RC]    = xtopt_parse_mint,
795 	[XTTYPE_UINT32RC]    = xtopt_parse_mint,
796 	[XTTYPE_UINT64RC]    = xtopt_parse_mint,
797 	[XTTYPE_DOUBLE]      = xtopt_parse_float,
798 	[XTTYPE_STRING]      = xtopt_parse_string,
799 	[XTTYPE_TOSMASK]     = xtopt_parse_tosmask,
800 	[XTTYPE_MARKMASK32]  = xtopt_parse_markmask,
801 	[XTTYPE_SYSLOGLEVEL] = xtopt_parse_sysloglevel,
802 	[XTTYPE_HOST]        = xtopt_parse_host,
803 	[XTTYPE_HOSTMASK]    = xtopt_parse_hostmask,
804 	[XTTYPE_PROTOCOL]    = xtopt_parse_protocol,
805 	[XTTYPE_PORT]        = xtopt_parse_port,
806 	[XTTYPE_PORTRC]      = xtopt_parse_mport,
807 	[XTTYPE_PLEN]        = xtopt_parse_plen,
808 	[XTTYPE_PLENMASK]    = xtopt_parse_plenmask,
809 	[XTTYPE_ETHERMAC]    = xtopt_parse_ethermac,
810 };
811 
812 /**
813  * The master option parsing routine. May be used for the ".x6_parse"
814  * function pointer in extensions if fully automatic parsing is desired.
815  * It may be also called manually from a custom x6_parse function.
816  */
xtables_option_parse(struct xt_option_call * cb)817 void xtables_option_parse(struct xt_option_call *cb)
818 {
819 	const struct xt_option_entry *entry = cb->entry;
820 	unsigned int eflag = 1 << cb->entry->id;
821 
822 	/*
823 	 * With {.id = P_FOO, .excl = P_FOO} we can have simple double-use
824 	 * prevention. Though it turned out that this is too much typing (most
825 	 * of the options are one-time use only), so now we also have
826 	 * %XTOPT_MULTI.
827 	 */
828 	if ((!(entry->flags & XTOPT_MULTI) || (entry->excl & eflag)) &&
829 	    cb->xflags & eflag)
830 		xt_params->exit_err(PARAMETER_PROBLEM,
831 			"%s: option \"--%s\" can only be used once.\n",
832 			cb->ext_name, cb->entry->name);
833 	if (cb->invert && !(entry->flags & XTOPT_INVERT))
834 		xt_params->exit_err(PARAMETER_PROBLEM,
835 			"%s: option \"--%s\" cannot be inverted.\n",
836 			cb->ext_name, entry->name);
837 	if (entry->type != XTTYPE_NONE && optarg == NULL)
838 		xt_params->exit_err(PARAMETER_PROBLEM,
839 			"%s: option \"--%s\" requires an argument.\n",
840 			cb->ext_name, entry->name);
841 	/*
842 	 * Fill in fallback value for "nvals", in case an extension (as it
843 	 * happened with libxt_conntrack.2) tries to read it, despite not using
844 	 * a *RC option type.
845 	 */
846 	cb->nvals = 1;
847 	if (entry->type < ARRAY_SIZE(xtopt_subparse) &&
848 	    xtopt_subparse[entry->type] != NULL)
849 		xtopt_subparse[entry->type](cb);
850 	/* Exclusion with other flags tested later in finalize. */
851 	cb->xflags |= 1 << entry->id;
852 }
853 
854 /**
855  * Verifies that an extension's option map descriptor is valid, and ought to
856  * be called right after the extension has been loaded, and before option
857  * merging/xfrm.
858  */
xtables_option_metavalidate(const char * name,const struct xt_option_entry * entry)859 void xtables_option_metavalidate(const char *name,
860 				 const struct xt_option_entry *entry)
861 {
862 	for (; entry->name != NULL; ++entry) {
863 		if (entry->id >= CHAR_BIT * sizeof(unsigned int) ||
864 		    entry->id >= XT_OPTION_OFFSET_SCALE)
865 			xt_params->exit_err(OTHER_PROBLEM,
866 				"Extension %s uses invalid ID %u\n",
867 				name, entry->id);
868 		if (!(entry->flags & XTOPT_PUT)) {
869 			if (entry->ptroff != 0)
870 				xt_params->exit_err(OTHER_PROBLEM,
871 					"%s: ptroff for \"--%s\" is non-"
872 					"zero but no XTOPT_PUT is specified. "
873 					"Oversight?", name, entry->name);
874 			continue;
875 		}
876 		if (entry->type >= ARRAY_SIZE(xtopt_psize) ||
877 		    xtopt_psize[entry->type] == 0)
878 			xt_params->exit_err(OTHER_PROBLEM,
879 				"%s: entry type of option \"--%s\" cannot be "
880 				"combined with XTOPT_PUT\n",
881 				name, entry->name);
882 		if (xtopt_psize[entry->type] != -1 &&
883 		    xtopt_psize[entry->type] != entry->size)
884 			xt_params->exit_err(OTHER_PROBLEM,
885 				"%s: option \"--%s\" points to a memory block "
886 				"of wrong size (expected %zu, got %zu)\n",
887 				name, entry->name,
888 				xtopt_psize[entry->type], entry->size);
889 	}
890 }
891 
892 /**
893  * Find an option entry by its id.
894  */
895 static const struct xt_option_entry *
xtables_option_lookup(const struct xt_option_entry * entry,unsigned int id)896 xtables_option_lookup(const struct xt_option_entry *entry, unsigned int id)
897 {
898 	for (; entry->name != NULL; ++entry)
899 		if (entry->id == id)
900 			return entry;
901 	return NULL;
902 }
903 
904 /**
905  * @c:		getopt id (i.e. with offset)
906  * @fw:		struct ipt_entry or ip6t_entry
907  *
908  * Dispatch arguments to the appropriate parse function, based upon the
909  * extension's choice of API.
910  */
xtables_option_tpcall(unsigned int c,char ** argv,bool invert,struct xtables_target * t,void * fw)911 void xtables_option_tpcall(unsigned int c, char **argv, bool invert,
912 			   struct xtables_target *t, void *fw)
913 {
914 	struct xt_option_call cb;
915 
916 	if (t->x6_parse == NULL) {
917 		if (t->parse != NULL)
918 			t->parse(c - t->option_offset, argv, invert,
919 				 &t->tflags, fw, &t->t);
920 		return;
921 	}
922 
923 	c -= t->option_offset;
924 	cb.entry = xtables_option_lookup(t->x6_options, c);
925 	if (cb.entry == NULL)
926 		xtables_error(OTHER_PROBLEM,
927 			      "Extension does not know id %u", c);
928 	cb.arg      = optarg;
929 	cb.invert   = invert;
930 	cb.ext_name = t->name;
931 	cb.data     = t->t->data;
932 	cb.xflags   = t->tflags;
933 	cb.target   = &t->t;
934 	cb.xt_entry = fw;
935 	cb.udata    = t->udata;
936 	t->x6_parse(&cb);
937 	t->tflags = cb.xflags;
938 }
939 
940 /**
941  * @c:		getopt id (i.e. with offset)
942  * @fw:		struct ipt_entry or ip6t_entry
943  *
944  * Dispatch arguments to the appropriate parse function, based upon the
945  * extension's choice of API.
946  */
xtables_option_mpcall(unsigned int c,char ** argv,bool invert,struct xtables_match * m,void * fw)947 void xtables_option_mpcall(unsigned int c, char **argv, bool invert,
948 			   struct xtables_match *m, void *fw)
949 {
950 	struct xt_option_call cb;
951 
952 	if (m->x6_parse == NULL) {
953 		if (m->parse != NULL)
954 			m->parse(c - m->option_offset, argv, invert,
955 				 &m->mflags, fw, &m->m);
956 		return;
957 	}
958 
959 	c -= m->option_offset;
960 	cb.entry = xtables_option_lookup(m->x6_options, c);
961 	if (cb.entry == NULL)
962 		xtables_error(OTHER_PROBLEM,
963 			      "Extension does not know id %u", c);
964 	cb.arg      = optarg;
965 	cb.invert   = invert;
966 	cb.ext_name = m->name;
967 	cb.data     = m->m->data;
968 	cb.xflags   = m->mflags;
969 	cb.match    = &m->m;
970 	cb.xt_entry = fw;
971 	cb.udata    = m->udata;
972 	m->x6_parse(&cb);
973 	m->mflags = cb.xflags;
974 }
975 
976 /**
977  * @name:	name of extension
978  * @entry:	current option (from all ext's entries) being validated
979  * @xflags:	flags the extension has collected
980  * @i:		conflicting option (id) to test for
981  */
982 static void
xtables_option_fcheck2(const char * name,const struct xt_option_entry * entry,const struct xt_option_entry * other,unsigned int xflags)983 xtables_option_fcheck2(const char *name, const struct xt_option_entry *entry,
984 		       const struct xt_option_entry *other,
985 		       unsigned int xflags)
986 {
987 	unsigned int ef = 1 << entry->id, of = 1 << other->id;
988 
989 	if (entry->also & of && !(xflags & of))
990 		xt_params->exit_err(PARAMETER_PROBLEM,
991 			"%s: option \"--%s\" also requires \"--%s\".\n",
992 			name, entry->name, other->name);
993 
994 	if (!(entry->excl & of))
995 		/* Use of entry does not collide with other option, good. */
996 		return;
997 	if ((xflags & (ef | of)) != (ef | of))
998 		/* Conflicting options were not used. */
999 		return;
1000 
1001 	xt_params->exit_err(PARAMETER_PROBLEM,
1002 		"%s: option \"--%s\" cannot be used together with \"--%s\".\n",
1003 		name, entry->name, other->name);
1004 }
1005 
1006 /**
1007  * @name:	name of extension
1008  * @xflags:	accumulated flags
1009  * @entry:	extension's option table
1010  *
1011  * Check that all option constraints have been met. This effectively replaces
1012  * ->final_check of the older API.
1013  */
xtables_options_fcheck(const char * name,unsigned int xflags,const struct xt_option_entry * table)1014 void xtables_options_fcheck(const char *name, unsigned int xflags,
1015 			    const struct xt_option_entry *table)
1016 {
1017 	const struct xt_option_entry *entry, *other;
1018 	unsigned int i;
1019 
1020 	for (entry = table; entry->name != NULL; ++entry) {
1021 		if (entry->flags & XTOPT_MAND &&
1022 		    !(xflags & (1 << entry->id)))
1023 			xt_params->exit_err(PARAMETER_PROBLEM,
1024 				"%s: option \"--%s\" must be specified\n",
1025 				name, entry->name);
1026 		if (!(xflags & (1 << entry->id)))
1027 			/* Not required, not specified, thus skip. */
1028 			continue;
1029 
1030 		for (i = 0; i < CHAR_BIT * sizeof(entry->id); ++i) {
1031 			if (entry->id == i)
1032 				/*
1033 				 * Avoid conflict with self. Multi-use check
1034 				 * was done earlier in xtables_option_parse.
1035 				 */
1036 				continue;
1037 			other = xtables_option_lookup(table, i);
1038 			if (other == NULL)
1039 				continue;
1040 			xtables_option_fcheck2(name, entry, other, xflags);
1041 		}
1042 	}
1043 }
1044 
1045 /**
1046  * Dispatch arguments to the appropriate final_check function, based upon the
1047  * extension's choice of API.
1048  */
xtables_option_tfcall(struct xtables_target * t)1049 void xtables_option_tfcall(struct xtables_target *t)
1050 {
1051 	if (t->x6_fcheck != NULL) {
1052 		struct xt_fcheck_call cb;
1053 
1054 		cb.ext_name = t->name;
1055 		cb.data     = t->t->data;
1056 		cb.xflags   = t->tflags;
1057 		cb.udata    = t->udata;
1058 		t->x6_fcheck(&cb);
1059 	} else if (t->final_check != NULL) {
1060 		t->final_check(t->tflags);
1061 	}
1062 	if (t->x6_options != NULL)
1063 		xtables_options_fcheck(t->name, t->tflags, t->x6_options);
1064 }
1065 
1066 /**
1067  * Dispatch arguments to the appropriate final_check function, based upon the
1068  * extension's choice of API.
1069  */
xtables_option_mfcall(struct xtables_match * m)1070 void xtables_option_mfcall(struct xtables_match *m)
1071 {
1072 	if (m->x6_fcheck != NULL) {
1073 		struct xt_fcheck_call cb;
1074 
1075 		cb.ext_name = m->name;
1076 		cb.data     = m->m->data;
1077 		cb.xflags   = m->mflags;
1078 		cb.udata    = m->udata;
1079 		m->x6_fcheck(&cb);
1080 	} else if (m->final_check != NULL) {
1081 		m->final_check(m->mflags);
1082 	}
1083 	if (m->x6_options != NULL)
1084 		xtables_options_fcheck(m->name, m->mflags, m->x6_options);
1085 }
1086 
xtables_lmap_init(const char * file)1087 struct xtables_lmap *xtables_lmap_init(const char *file)
1088 {
1089 	struct xtables_lmap *lmap_head = NULL, *lmap_prev = NULL, *lmap_this;
1090 	char buf[512];
1091 	FILE *fp;
1092 	char *cur, *nxt;
1093 	int id;
1094 
1095 	fp = fopen(file, "re");
1096 	if (fp == NULL)
1097 		return NULL;
1098 
1099 	while (fgets(buf, sizeof(buf), fp) != NULL) {
1100 		cur = buf;
1101 		while (isspace(*cur))
1102 			++cur;
1103 		if (*cur == '#' || *cur == '\n' || *cur == '\0')
1104 			continue;
1105 
1106 		/* iproute2 allows hex and dec format */
1107 		errno = 0;
1108 		id = strtoul(cur, &nxt, strncmp(cur, "0x", 2) == 0 ? 16 : 10);
1109 		if (nxt == cur || errno != 0)
1110 			continue;
1111 
1112 		/* same boundaries as in iproute2 */
1113 		if (id < 0 || id > 255)
1114 			continue;
1115 		cur = nxt;
1116 
1117 		if (!isspace(*cur))
1118 			continue;
1119 		while (isspace(*cur))
1120 			++cur;
1121 		if (*cur == '#' || *cur == '\n' || *cur == '\0')
1122 			continue;
1123 		nxt = cur;
1124 		while (*nxt != '\0' && !isspace(*nxt))
1125 			++nxt;
1126 		if (nxt == cur)
1127 			continue;
1128 		*nxt = '\0';
1129 
1130 		/* found valid data */
1131 		lmap_this = malloc(sizeof(*lmap_this));
1132 		if (lmap_this == NULL) {
1133 			perror("malloc");
1134 			goto out;
1135 		}
1136 		lmap_this->id   = id;
1137 		lmap_this->name = xtables_strdup(cur);
1138 		lmap_this->next = NULL;
1139 
1140 		if (lmap_prev != NULL)
1141 			lmap_prev->next = lmap_this;
1142 		else
1143 			lmap_head = lmap_this;
1144 		lmap_prev = lmap_this;
1145 	}
1146 
1147 	fclose(fp);
1148 	return lmap_head;
1149  out:
1150 	fclose(fp);
1151 	xtables_lmap_free(lmap_head);
1152 	return NULL;
1153 }
1154 
xtables_lmap_free(struct xtables_lmap * head)1155 void xtables_lmap_free(struct xtables_lmap *head)
1156 {
1157 	struct xtables_lmap *next;
1158 
1159 	for (; head != NULL; head = next) {
1160 		next = head->next;
1161 		free(head->name);
1162 		free(head);
1163 	}
1164 }
1165 
xtables_lmap_name2id(const struct xtables_lmap * head,const char * name)1166 int xtables_lmap_name2id(const struct xtables_lmap *head, const char *name)
1167 {
1168 	for (; head != NULL; head = head->next)
1169 		if (strcmp(head->name, name) == 0)
1170 			return head->id;
1171 	return -1;
1172 }
1173 
xtables_lmap_id2name(const struct xtables_lmap * head,int id)1174 const char *xtables_lmap_id2name(const struct xtables_lmap *head, int id)
1175 {
1176 	for (; head != NULL; head = head->next)
1177 		if (head->id == id)
1178 			return head->name;
1179 	return NULL;
1180 }
1181