1 /* $Id: iptcrdr.c,v 1.67 2020/11/11 12:09:05 nanard Exp $ */
2 /* vim: tabstop=4 shiftwidth=4 noexpandtab
3  * MiniUPnP project
4  * http://miniupnp.free.fr/ or https://miniupnp.tuxfamily.org/
5  * (c) 2006-2020 Thomas Bernard
6  * This software is subject to the conditions detailed
7  * in the LICENCE file provided within the distribution */
8 #include <stdio.h>
9 #include <stdlib.h>
10 #include <string.h>
11 #include <syslog.h>
12 #include <errno.h>
13 #include <sys/socket.h>
14 #include <netinet/in.h>
15 #include <arpa/inet.h>
16 #include <dlfcn.h>
17 #include <xtables.h>
18 #include <linux/netfilter/xt_DSCP.h>
19 #include <libiptc/libiptc.h>
20 
21 #include <linux/version.h>
22 
23 #include "config.h"
24 
25 #ifdef IPTABLES_143
26 /* IPTABLES API version >= 1.4.3 */
27 
28 /* added in order to compile on gentoo :
29  * http://miniupnp.tuxfamily.org/forum/viewtopic.php?p=2183 */
30 #define BUILD_BUG_ON_ZERO(e) (sizeof(struct { int:-!!(e); }))
31 #define __must_be_array(a) \
32 	BUILD_BUG_ON_ZERO(__builtin_types_compatible_p(typeof(a), typeof(&a[0])))
33 #define ARRAY_SIZE(arr) (sizeof(arr) / sizeof((arr)[0]) + __must_be_array(arr))
34 #define LIST_POISON2  ((void *) 0x00200200 )
35 
36 #if 0
37 #include <linux/netfilter/nf_nat.h>
38 #else
39 #include "tiny_nf_nat.h"
40 #endif
41 #define ip_nat_multi_range	nf_nat_multi_range
42 #define ip_nat_range		nf_nat_range
43 #define IPTC_HANDLE		struct iptc_handle *
44 #else
45 /* IPTABLES API version < 1.4.3 */
46 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,22)
47 #include <linux/netfilter_ipv4/ip_nat.h>
48 #else
49 #if 0
50 #include <linux/netfilter/nf_nat.h>
51 #else
52 #include "tiny_nf_nat.h"
53 #endif
54 #endif
55 #define IPTC_HANDLE		iptc_handle_t
56 #endif
57 
58 /* IPT_ALIGN was renamed XT_ALIGN in iptables-1.4.11 */
59 #ifndef IPT_ALIGN
60 #define IPT_ALIGN XT_ALIGN
61 #endif
62 
63 #include "../macros.h"
64 #include "iptcrdr.h"
65 #include "../upnpglobalvars.h"
66 
67 /* chain names to use in the nat and filter tables. */
68 
69 /* iptables -t nat -N MINIUPNPD
70  * iptables -t nat -A PREROUTING -i <ext_if_name> -j MINIUPNPD */
71 static const char * miniupnpd_nat_chain = "MINIUPNPD";
72 
73 /* iptables -t nat -N MINIUPNPD-POSTROUTING
74  * iptables -t nat -A POSTROUTING -o <ext_if_name> -j MINIUPNPD-POSTROUTING */
75 static const char * miniupnpd_nat_postrouting_chain = "MINIUPNPD-POSTROUTING";
76 
77 /* iptables -t filter -N MINIUPNPD
78  * iptables -t filter -A FORWARD -i <ext_if_name> ! -o <ext_if_name> -j MINIUPNPD */
79 static const char * miniupnpd_forward_chain = "MINIUPNPD";
80 
81 /**
82  * used by the core to override default chain names if specified in config file
83  * @param param which string to set
84  * @param string the new name to use. Do not dispose after setting (i.e. use strdup if not static).
85  * @return 0 if successful
86  */
87 int
set_rdr_name(rdr_name_type param,const char * string)88 set_rdr_name(rdr_name_type param, const char *string)
89 {
90 	if (string == NULL || strlen(string) > 30 || string[0] == '\0') {
91 		syslog(LOG_ERR, "%s(): invalid string argument '%s'", "set_rdr_name", string);
92 		return -1;
93 	}
94 	switch (param) {
95 		case RDR_NAT_PREROUTING_CHAIN_NAME:
96 			miniupnpd_nat_chain = string;
97 			break;
98 		case RDR_NAT_POSTROUTING_CHAIN_NAME:
99 			miniupnpd_nat_postrouting_chain = string;
100 			break;
101 		case RDR_FORWARD_CHAIN_NAME:
102 			miniupnpd_forward_chain = string;
103 			break;
104 		default:
105 			syslog(LOG_ERR, "%s(): tried to set invalid string parameter: %d", "set_rdr_name", param);
106 			return -2;
107 	}
108 	return 0;
109 }
110 
111 /* local functions declarations */
112 static int
113 addnatrule(int proto, unsigned short eport,
114            const char * iaddr, unsigned short iport,
115            const char * rhost);
116 
117 static int
118 add_filter_rule(int proto, const char * rhost,
119                 const char * iaddr, unsigned short iport);
120 
121 #ifdef ENABLE_PORT_TRIGGERING
122 static int
123 addmasqueraderule(int proto,
124            unsigned short eport,
125            const char * iaddr, unsigned short iport,
126            const char * rhost/*, const char * extif*/);
127 #endif /* ENABLE_PORT_TRIGGERING */
128 
129 static int
130 addpeernatrule(int proto,
131            const char * eaddr, unsigned short eport,
132            const char * iaddr, unsigned short iport,
133            const char * rhost, unsigned short rport);
134 
135 static int
136 addpeerdscprule(int proto, unsigned char dscp,
137            const char * iaddr, unsigned short iport,
138            const char * rhost, unsigned short rport);
139 
140 /* dummy init and shutdown functions
141  * Only test iptc_init() */
init_redirect(void)142 int init_redirect(void)
143 {
144 	IPTC_HANDLE h;
145 
146 	h = iptc_init("nat");
147 	if(!h) {
148 		syslog(LOG_ERR, "iptc_init() failed : %s",
149 		       iptc_strerror(errno));
150 		return -1;
151 	} else {
152 #ifdef IPTABLES_143
153 		iptc_free(h);
154 #else
155 		iptc_free(&h);
156 #endif
157 	}
158 	return 0;
159 }
160 
shutdown_redirect(void)161 void shutdown_redirect(void)
162 {
163 	return;
164 }
165 
166 /* convert an ip address to string */
snprintip(char * dst,size_t size,uint32_t ip)167 static int snprintip(char * dst, size_t size, uint32_t ip)
168 {
169 	return snprintf(dst, size,
170 	       "%u.%u.%u.%u", ip >> 24, (ip >> 16) & 0xff,
171 	       (ip >> 8) & 0xff, ip & 0xff);
172 }
173 
174 /* netfilter cannot store redirection descriptions, so we use our
175  * own structure to store them */
176 struct rdr_desc {
177 	struct rdr_desc * next;
178 	unsigned int timestamp;
179 	unsigned short eport;
180 	short proto;
181 	char str[];
182 };
183 
184 /* pointer to the chained list where descriptions are stored */
185 static struct rdr_desc * rdr_desc_list = 0;
186 
187 /* add a description to the list of redirection descriptions */
188 static void
add_redirect_desc(unsigned short eport,int proto,const char * desc,unsigned int timestamp)189 add_redirect_desc(unsigned short eport, int proto,
190                   const char * desc, unsigned int timestamp)
191 {
192 	struct rdr_desc * p;
193 	size_t l;
194 	/* set a default description if none given */
195 	if(!desc)
196 		desc = "miniupnpd";
197 	l = strlen(desc) + 1;
198 	p = malloc(sizeof(struct rdr_desc) + l);
199 	if(p)
200 	{
201 		p->next = rdr_desc_list;
202 		p->timestamp = timestamp;
203 		p->eport = eport;
204 		p->proto = (short)proto;
205 		memcpy(p->str, desc, l);
206 		rdr_desc_list = p;
207 	}
208 }
209 
210 /* delete a description from the list */
211 static void
del_redirect_desc(unsigned short eport,int proto)212 del_redirect_desc(unsigned short eport, int proto)
213 {
214 	struct rdr_desc * p, * last;
215 	p = rdr_desc_list;
216 	last = 0;
217 	while(p)
218 	{
219 		if(p->eport == eport && p->proto == proto)
220 		{
221 			if(!last)
222 				rdr_desc_list = p->next;
223 			else
224 				last->next = p->next;
225 			free(p);
226 			return;
227 		}
228 		last = p;
229 		p = p->next;
230 	}
231 }
232 
233 /* go through the list to find the description */
234 static void
get_redirect_desc(unsigned short eport,int proto,char * desc,int desclen,unsigned int * timestamp)235 get_redirect_desc(unsigned short eport, int proto,
236                   char * desc, int desclen,
237                   unsigned int * timestamp)
238 {
239 	struct rdr_desc * p;
240 	for(p = rdr_desc_list; p; p = p->next)
241 	{
242 		if(p->eport == eport && p->proto == (short)proto)
243 		{
244 			if(desc)
245 				strncpy(desc, p->str, desclen);
246 			if(timestamp)
247 				*timestamp = p->timestamp;
248 			return;
249 		}
250 	}
251 	/* if no description was found, return miniupnpd as default */
252 	if(desc)
253 		strncpy(desc, "miniupnpd", desclen);
254 	if(timestamp)
255 		*timestamp = 0;
256 }
257 
258 /* add_redirect_rule2() */
259 int
add_redirect_rule2(const char * ifname,const char * rhost,unsigned short eport,const char * iaddr,unsigned short iport,int proto,const char * desc,unsigned int timestamp)260 add_redirect_rule2(const char * ifname,
261                    const char * rhost, unsigned short eport,
262                    const char * iaddr, unsigned short iport, int proto,
263 				   const char * desc, unsigned int timestamp)
264 {
265 	int r;
266 	UNUSED(ifname);
267 
268 	r = addnatrule(proto, eport, iaddr, iport, rhost);
269 	if(r >= 0) {
270 		add_redirect_desc(eport, proto, desc, timestamp);
271 #ifdef ENABLE_PORT_TRIGGERING
272 		/* we now always setup SNAT to support bidirectional mapping
273 		 * we cannot expect that iport == eport on all the firewall.
274 		 */
275 		/* TODO : check if this should be done only with UDP */
276 		r = addmasqueraderule(proto, eport, iaddr, iport, rhost/*, ifname*/);
277 		if(r < 0) {
278 			syslog(LOG_NOTICE, "add_redirect_rule2(): addmasqueraderule returned %d", r);
279 		}
280 #endif /* ENABLE_PORT_TRIGGERING */
281 	}
282 	return r;
283 }
284 
285 /* add_peer_redirect_rule2() */
286 int
add_peer_redirect_rule2(const char * ifname,const char * rhost,unsigned short rport,const char * eaddr,unsigned short eport,const char * iaddr,unsigned short iport,int proto,const char * desc,unsigned int timestamp)287 add_peer_redirect_rule2(const char * ifname,
288                    const char * rhost, unsigned short rport,
289                    const char * eaddr, unsigned short eport,
290                    const char * iaddr, unsigned short iport, int proto,
291                    const char * desc, unsigned int timestamp)
292 {
293 	int r;
294 	UNUSED(ifname);
295 
296 	r = addpeernatrule(proto, eaddr, eport, iaddr, iport, rhost, rport);
297 	if(r >= 0)
298 		add_redirect_desc(eport, proto, desc, timestamp);
299 	return r;
300 }
301 
302 int
add_peer_dscp_rule2(const char * ifname,const char * rhost,unsigned short rport,unsigned char dscp,const char * iaddr,unsigned short iport,int proto,const char * desc,unsigned int timestamp)303 add_peer_dscp_rule2(const char * ifname,
304                    const char * rhost, unsigned short rport,
305                    unsigned char dscp,
306                    const char * iaddr, unsigned short iport, int proto,
307                    const char * desc, unsigned int timestamp)
308 {
309 	int r;
310 	UNUSED(ifname);
311 	UNUSED(desc);
312 	UNUSED(timestamp);
313 
314 	r = addpeerdscprule(proto, dscp, iaddr, iport, rhost, rport);
315 /*	if(r >= 0)
316 		add_redirect_desc(dscp, proto, desc, timestamp); */
317 	return r;
318 }
319 
320 int
add_filter_rule2(const char * ifname,const char * rhost,const char * iaddr,unsigned short eport,unsigned short iport,int proto,const char * desc)321 add_filter_rule2(const char * ifname,
322                  const char * rhost, const char * iaddr,
323                  unsigned short eport, unsigned short iport,
324                  int proto, const char * desc)
325 {
326 	UNUSED(ifname);
327 	UNUSED(eport);
328 	UNUSED(desc);
329 
330 	return add_filter_rule(proto, rhost, iaddr, iport);
331 }
332 
333 /* get_redirect_rule()
334  * returns -1 if the rule is not found */
335 int
get_redirect_rule(const char * ifname,unsigned short eport,int proto,char * iaddr,int iaddrlen,unsigned short * iport,char * desc,int desclen,char * rhost,int rhostlen,unsigned int * timestamp,u_int64_t * packets,u_int64_t * bytes)336 get_redirect_rule(const char * ifname, unsigned short eport, int proto,
337                   char * iaddr, int iaddrlen, unsigned short * iport,
338                   char * desc, int desclen,
339                   char * rhost, int rhostlen,
340                   unsigned int * timestamp,
341                   u_int64_t * packets, u_int64_t * bytes)
342 {
343 	return get_nat_redirect_rule(miniupnpd_nat_chain,
344 	                             ifname, eport, proto,
345 	                             iaddr, iaddrlen, iport,
346 	                             desc, desclen,
347 	                             rhost, rhostlen,
348 	                             timestamp, packets, bytes);
349 }
350 
351 int
get_nat_redirect_rule(const char * nat_chain_name,const char * ifname,unsigned short eport,int proto,char * iaddr,int iaddrlen,unsigned short * iport,char * desc,int desclen,char * rhost,int rhostlen,unsigned int * timestamp,u_int64_t * packets,u_int64_t * bytes)352 get_nat_redirect_rule(const char * nat_chain_name, const char * ifname, unsigned short eport, int proto,
353                   char * iaddr, int iaddrlen, unsigned short * iport,
354                   char * desc, int desclen,
355                   char * rhost, int rhostlen,
356                   unsigned int * timestamp,
357                   u_int64_t * packets, u_int64_t * bytes)
358 {
359 	int r = -1;
360 	IPTC_HANDLE h;
361 	const struct ipt_entry * e;
362 	const struct ipt_entry_target * target;
363 	const struct ip_nat_multi_range * mr;
364 	const struct ipt_entry_match *match;
365 	UNUSED(ifname);
366 
367 	h = iptc_init("nat");
368 	if(!h)
369 	{
370 		syslog(LOG_ERR, "%s() : iptc_init() failed : %s",
371 		       "get_nat_redirect_rule", iptc_strerror(errno));
372 		return -1;
373 	}
374 	if(!iptc_is_chain(nat_chain_name, h))
375 	{
376 		syslog(LOG_ERR, "chain %s not found", nat_chain_name);
377 	}
378 	else
379 	{
380 #ifdef IPTABLES_143
381 		for(e = iptc_first_rule(nat_chain_name, h);
382 		    e;
383 			e = iptc_next_rule(e, h))
384 #else
385 		for(e = iptc_first_rule(nat_chain_name, &h);
386 		    e;
387 			e = iptc_next_rule(e, &h))
388 #endif
389 		{
390 			if(proto==e->ip.proto)
391 			{
392 				match = (const struct ipt_entry_match *)&e->elems;
393 				if(0 == strncmp(match->u.user.name, "tcp", IPT_FUNCTION_MAXNAMELEN))
394 				{
395 					const struct ipt_tcp * info;
396 					info = (const struct ipt_tcp *)match->data;
397 					if(eport != info->dpts[0])
398 						continue;
399 				}
400 				else
401 				{
402 					const struct ipt_udp * info;
403 					info = (const struct ipt_udp *)match->data;
404 					if(eport != info->dpts[0])
405 						continue;
406 				}
407 				target = (void *)e + e->target_offset;
408 				/* target = ipt_get_target(e); */
409 				mr = (const struct ip_nat_multi_range *)&target->data[0];
410 				snprintip(iaddr, iaddrlen, ntohl(mr->range[0].min_ip));
411 				*iport = ntohs(mr->range[0].min.all);
412 				get_redirect_desc(eport, proto, desc, desclen, timestamp);
413 				if(packets)
414 					*packets = e->counters.pcnt;
415 				if(bytes)
416 					*bytes = e->counters.bcnt;
417 				/* rhost */
418 				if(e->ip.src.s_addr && rhost) {
419 					snprintip(rhost, rhostlen, ntohl(e->ip.src.s_addr));
420 				}
421 				r = 0;
422 				break;
423 			}
424 		}
425 	}
426 	if(h)
427 #ifdef IPTABLES_143
428 		iptc_free(h);
429 #else
430 		iptc_free(&h);
431 #endif
432 	return r;
433 }
434 
435 /* get_redirect_rule_by_index()
436  * return -1 when the rule was not found */
437 int
get_redirect_rule_by_index(int index,char * ifname,unsigned short * eport,char * iaddr,int iaddrlen,unsigned short * iport,int * proto,char * desc,int desclen,char * rhost,int rhostlen,unsigned int * timestamp,u_int64_t * packets,u_int64_t * bytes)438 get_redirect_rule_by_index(int index,
439                            char * ifname, unsigned short * eport,
440                            char * iaddr, int iaddrlen, unsigned short * iport,
441                            int * proto, char * desc, int desclen,
442                            char * rhost, int rhostlen,
443                            unsigned int * timestamp,
444                            u_int64_t * packets, u_int64_t * bytes)
445 {
446 	int r = -1;
447 	int i = 0;
448 	IPTC_HANDLE h;
449 	const struct ipt_entry * e;
450 	const struct ipt_entry_target * target;
451 	const struct ip_nat_multi_range * mr;
452 	const struct ipt_entry_match *match;
453 	UNUSED(ifname);
454 
455 	h = iptc_init("nat");
456 	if(!h)
457 	{
458 		syslog(LOG_ERR, "%s() : iptc_init() failed : %s",
459 		       "get_redirect_rule_by_index", iptc_strerror(errno));
460 		return -1;
461 	}
462 	if(!iptc_is_chain(miniupnpd_nat_chain, h))
463 	{
464 		syslog(LOG_ERR, "chain %s not found", miniupnpd_nat_chain);
465 	}
466 	else
467 	{
468 #ifdef IPTABLES_143
469 		for(e = iptc_first_rule(miniupnpd_nat_chain, h);
470 		    e;
471 			e = iptc_next_rule(e, h))
472 #else
473 		for(e = iptc_first_rule(miniupnpd_nat_chain, &h);
474 		    e;
475 			e = iptc_next_rule(e, &h))
476 #endif
477 		{
478 			if(i==index)
479 			{
480 				*proto = e->ip.proto;
481 				match = (const struct ipt_entry_match *)&e->elems;
482 				if(0 == strncmp(match->u.user.name, "tcp", IPT_FUNCTION_MAXNAMELEN))
483 				{
484 					const struct ipt_tcp * info;
485 					info = (const struct ipt_tcp *)match->data;
486 					*eport = info->dpts[0];
487 				}
488 				else
489 				{
490 					const struct ipt_udp * info;
491 					info = (const struct ipt_udp *)match->data;
492 					*eport = info->dpts[0];
493 				}
494 				target = (void *)e + e->target_offset;
495 				mr = (const struct ip_nat_multi_range *)&target->data[0];
496 				snprintip(iaddr, iaddrlen, ntohl(mr->range[0].min_ip));
497 				*iport = ntohs(mr->range[0].min.all);
498 				get_redirect_desc(*eport, *proto, desc, desclen, timestamp);
499 				if(packets)
500 					*packets = e->counters.pcnt;
501 				if(bytes)
502 					*bytes = e->counters.bcnt;
503 				/* rhost */
504 				if(rhost && rhostlen > 0) {
505 					if(e->ip.src.s_addr) {
506 						snprintip(rhost, rhostlen, ntohl(e->ip.src.s_addr));
507 					} else {
508 						rhost[0] = '\0';
509 					}
510 				}
511 				r = 0;
512 				break;
513 			}
514 			i++;
515 		}
516 	}
517 	if(h)
518 #ifdef IPTABLES_143
519 		iptc_free(h);
520 #else
521 		iptc_free(&h);
522 #endif
523 	return r;
524 }
525 
526 /* get_peer_rule_by_index()
527  * return -1 when the rule was not found */
528 int
get_peer_rule_by_index(int index,char * ifname,unsigned short * eport,char * iaddr,int iaddrlen,unsigned short * iport,int * proto,char * desc,int desclen,char * rhost,int rhostlen,unsigned short * rport,unsigned int * timestamp,u_int64_t * packets,u_int64_t * bytes)529 get_peer_rule_by_index(int index,
530                            char * ifname, unsigned short * eport,
531                            char * iaddr, int iaddrlen, unsigned short * iport,
532                            int * proto, char * desc, int desclen,
533                            char * rhost, int rhostlen, unsigned short * rport,
534                            unsigned int * timestamp,
535                            u_int64_t * packets, u_int64_t * bytes)
536 {
537 	int r = -1;
538 	int i = 0;
539 	IPTC_HANDLE h;
540 	const struct ipt_entry * e;
541 	const struct ipt_entry_target * target;
542 	const struct ip_nat_multi_range * mr;
543 	const struct ipt_entry_match *match;
544 	UNUSED(ifname);
545 
546 	h = iptc_init("nat");
547 	if(!h)
548 	{
549 		syslog(LOG_ERR, "%s() : iptc_init() failed : %s",
550 		       "get_peer_rule_by_index", iptc_strerror(errno));
551 		return -1;
552 	}
553 	if(!iptc_is_chain(miniupnpd_nat_postrouting_chain, h))
554 	{
555 		syslog(LOG_ERR, "chain %s not found", miniupnpd_nat_postrouting_chain);
556 	}
557 	else
558 	{
559 #ifdef IPTABLES_143
560 		for(e = iptc_first_rule(miniupnpd_nat_postrouting_chain, h);
561 		    e;
562 			e = iptc_next_rule(e, h))
563 #else
564 		for(e = iptc_first_rule(miniupnpd_nat_postrouting_chain, &h);
565 		    e;
566 			e = iptc_next_rule(e, &h))
567 #endif
568 		{
569 			if(i==index)
570 			{
571 				*proto = e->ip.proto;
572 				match = (const struct ipt_entry_match *)&e->elems;
573 				if(0 == strncmp(match->u.user.name, "tcp", IPT_FUNCTION_MAXNAMELEN))
574 				{
575 					const struct ipt_tcp * info;
576 					info = (const struct ipt_tcp *)match->data;
577 					if (rport)
578 						*rport = info->dpts[0];
579 					if (iport)
580 						*iport = info->spts[0];
581 				}
582 				else
583 				{
584 					const struct ipt_udp * info;
585 					info = (const struct ipt_udp *)match->data;
586 					if (rport)
587 						*rport = info->dpts[0];
588 					if (iport)
589 						*iport = info->spts[0];
590 				}
591 				target = (void *)e + e->target_offset;
592 				mr = (const struct ip_nat_multi_range *)&target->data[0];
593 				*eport = ntohs(mr->range[0].min.all);
594 				get_redirect_desc(*eport, *proto, desc, desclen, timestamp);
595 				if(packets)
596 					*packets = e->counters.pcnt;
597 				if(bytes)
598 					*bytes = e->counters.bcnt;
599 				/* rhost */
600 				if(rhost && rhostlen > 0) {
601 					if(e->ip.dst.s_addr) {
602 						snprintip(rhost, rhostlen, ntohl(e->ip.dst.s_addr));
603 					} else {
604 						rhost[0] = '\0';
605 					}
606 				}
607 				if(iaddr && iaddrlen > 0) {
608 					if(e->ip.src.s_addr) {
609 						snprintip(iaddr, iaddrlen, ntohl(e->ip.src.s_addr));
610 					} else {
611 						rhost[0] = '\0';
612 					}
613 				}
614 				r = 0;
615 				break;
616 			}
617 			i++;
618 		}
619 	}
620 	if(h)
621 #ifdef IPTABLES_143
622 		iptc_free(h);
623 #else
624 		iptc_free(&h);
625 #endif
626 	return r;
627 }
628 
629 /* delete_rule_and_commit() :
630  * subfunction used in delete_redirect_and_filter_rules() */
631 static int
delete_rule_and_commit(unsigned int index,IPTC_HANDLE h,const char * miniupnpd_chain,const char * logcaller)632 delete_rule_and_commit(unsigned int index, IPTC_HANDLE h,
633                        const char * miniupnpd_chain,
634                        const char * logcaller)
635 {
636 	int r = 0;
637 #ifdef IPTABLES_143
638 	if(!iptc_delete_num_entry(miniupnpd_chain, index, h))
639 #else
640 	if(!iptc_delete_num_entry(miniupnpd_chain, index, &h))
641 #endif
642 	{
643 		syslog(LOG_ERR, "%s() : iptc_delete_num_entry(): %s\n",
644 	    	   logcaller, iptc_strerror(errno));
645 		r = -1;
646 	}
647 #ifdef IPTABLES_143
648 	else if(!iptc_commit(h))
649 #else
650 	else if(!iptc_commit(&h))
651 #endif
652 	{
653 		syslog(LOG_ERR, "%s() : iptc_commit(): %s\n",
654 	    	   logcaller, iptc_strerror(errno));
655 		r = -1;
656 	}
657 	if(h)
658 #ifdef IPTABLES_143
659 		iptc_free(h);
660 #else
661 		iptc_free(&h);
662 #endif
663 	return r;
664 }
665 
666 /* delete_filter_rule()
667  */
668 int
delete_filter_rule(const char * ifname,unsigned short port,int proto)669 delete_filter_rule(const char * ifname, unsigned short port, int proto)
670 {
671 	int r = -1;
672 	unsigned index = 0;
673 	unsigned i = 0;
674 	IPTC_HANDLE h;
675 	const struct ipt_entry * e;
676 	const struct ipt_entry_match *match;
677 	UNUSED(ifname);
678 
679 	if((h = iptc_init("filter")))
680 	{
681 		i = 0;
682 		/* we must find the right index for the filter rule */
683 #ifdef IPTABLES_143
684 		for(e = iptc_first_rule(miniupnpd_forward_chain, h);
685 		    e;
686 			e = iptc_next_rule(e, h), i++)
687 #else
688 		for(e = iptc_first_rule(miniupnpd_forward_chain, &h);
689 		    e;
690 			e = iptc_next_rule(e, &h), i++)
691 #endif
692 		{
693 			if(proto==e->ip.proto)
694 			{
695 				match = (const struct ipt_entry_match *)&e->elems;
696 				/*syslog(LOG_DEBUG, "filter rule #%u: %s %s",
697 				       i, match->u.user.name, inet_ntoa(e->ip.dst));*/
698 				if(0 == strncmp(match->u.user.name, "tcp", IPT_FUNCTION_MAXNAMELEN))
699 				{
700 					const struct ipt_tcp * info;
701 					info = (const struct ipt_tcp *)match->data;
702 					if(port != info->dpts[0])
703 						continue;
704 				}
705 				else
706 				{
707 					const struct ipt_udp * info;
708 					info = (const struct ipt_udp *)match->data;
709 					if(port != info->dpts[0])
710 						continue;
711 				}
712 				index = i;
713 				/*syslog(LOG_INFO, "Trying to delete filter rule at index %u", index);*/
714 				r = delete_rule_and_commit(index, h, miniupnpd_forward_chain, "delete_filter_rule");
715 				h = NULL;
716 				break;
717 			}
718 		}
719 	}
720 	if(h)
721 #ifdef IPTABLES_143
722 		iptc_free(h);
723 #else
724 		iptc_free(&h);
725 #endif
726 	return r;
727 }
728 
729 /* delete_redirect_and_filter_rules()
730  */
731 int
delete_redirect_and_filter_rules(unsigned short eport,int proto)732 delete_redirect_and_filter_rules(unsigned short eport, int proto)
733 {
734 	int r = -1, r2 = -1;
735 	unsigned index = 0;
736 	unsigned i = 0;
737 	IPTC_HANDLE h;
738 	const struct ipt_entry * e;
739 	const struct ipt_entry_target * target;
740 	const struct ip_nat_multi_range * mr;
741 	const struct ipt_entry_match *match;
742 	unsigned short iport = 0;
743 	uint32_t iaddr = 0;
744 
745 	h = iptc_init("nat");
746 	if(!h)
747 	{
748 		syslog(LOG_ERR, "%s() : iptc_init() failed : %s",
749 		       "delete_redirect_and_filter_rules", iptc_strerror(errno));
750 		return -1;
751 	}
752 	/* First step : find the right nat rule */
753 	if(!iptc_is_chain(miniupnpd_nat_chain, h))
754 	{
755 		syslog(LOG_ERR, "chain %s not found", miniupnpd_nat_chain);
756 	}
757 	else
758 	{
759 #ifdef IPTABLES_143
760 		for(e = iptc_first_rule(miniupnpd_nat_chain, h);
761 		    e;
762 			e = iptc_next_rule(e, h), i++)
763 #else
764 		for(e = iptc_first_rule(miniupnpd_nat_chain, &h);
765 		    e;
766 			e = iptc_next_rule(e, &h), i++)
767 #endif
768 		{
769 			if(proto==e->ip.proto)
770 			{
771 				match = (const struct ipt_entry_match *)&e->elems;
772 				if(0 == strncmp(match->u.user.name, "tcp", IPT_FUNCTION_MAXNAMELEN))
773 				{
774 					const struct ipt_tcp * info;
775 					info = (const struct ipt_tcp *)match->data;
776 					if(eport != info->dpts[0])
777 						continue;
778 				}
779 				else
780 				{
781 					const struct ipt_udp * info;
782 					info = (const struct ipt_udp *)match->data;
783 					if(eport != info->dpts[0])
784 						continue;
785 				}
786 				/* get the index, the internal address and the internal port
787 				 * of the rule */
788 				index = i;
789 				target = (void *)e + e->target_offset;
790 				mr = (const struct ip_nat_multi_range *)&target->data[0];
791 				iaddr = mr->range[0].min_ip;
792 				iport = ntohs(mr->range[0].min.all);
793 				r = 0;
794 				break;
795 			}
796 		}
797 	}
798 	if(h)
799 #ifdef IPTABLES_143
800 		iptc_free(h);
801 #else
802 		iptc_free(&h);
803 #endif
804 	if(r == 0)
805 	{
806 		syslog(LOG_INFO, "Trying to delete nat rule at index %u", index);
807 		/* Now delete both rules */
808 		/* first delete the nat rule */
809 		h = iptc_init("nat");
810 		if(h)
811 		{
812 			r = delete_rule_and_commit(index, h, miniupnpd_nat_chain, "delete_redirect_rule");
813 		}
814 		if((r == 0) && (h = iptc_init("filter")))
815 		{
816 			i = 0;
817 			/* we must find the right index for the filter rule */
818 #ifdef IPTABLES_143
819 			for(e = iptc_first_rule(miniupnpd_forward_chain, h);
820 			    e;
821 				e = iptc_next_rule(e, h), i++)
822 #else
823 			for(e = iptc_first_rule(miniupnpd_forward_chain, &h);
824 			    e;
825 				e = iptc_next_rule(e, &h), i++)
826 #endif
827 			{
828 				if(proto==e->ip.proto)
829 				{
830 					match = (const struct ipt_entry_match *)&e->elems;
831 					/*syslog(LOG_DEBUG, "filter rule #%u: %s %s",
832 					       i, match->u.user.name, inet_ntoa(e->ip.dst));*/
833 					if(0 == strncmp(match->u.user.name, "tcp", IPT_FUNCTION_MAXNAMELEN))
834 					{
835 						const struct ipt_tcp * info;
836 						info = (const struct ipt_tcp *)match->data;
837 						if(iport != info->dpts[0])
838 							continue;
839 					}
840 					else
841 					{
842 						const struct ipt_udp * info;
843 						info = (const struct ipt_udp *)match->data;
844 						if(iport != info->dpts[0])
845 							continue;
846 					}
847 					if(iaddr != e->ip.dst.s_addr)
848 						continue;
849 					index = i;
850 					syslog(LOG_INFO, "Trying to delete filter rule at index %u", index);
851 					r = delete_rule_and_commit(index, h, miniupnpd_forward_chain, "delete_filter_rule");
852 					h = NULL;
853 					break;
854 				}
855 			}
856 		}
857 		if(h)
858 #ifdef IPTABLES_143
859 			iptc_free(h);
860 #else
861 			iptc_free(&h);
862 #endif
863 	}
864 
865 	/*delete PEER rule*/
866 	if((h = iptc_init("nat")))
867 	{
868 		i = 0;
869 		/* we must find the right index for the filter rule */
870 #ifdef IPTABLES_143
871 		for(e = iptc_first_rule(miniupnpd_nat_postrouting_chain, h);
872 		    e;
873 			e = iptc_next_rule(e, h), i++)
874 #else
875 		for(e = iptc_first_rule(miniupnpd_nat_postrouting_chain, &h);
876 		    e;
877 			e = iptc_next_rule(e, &h), i++)
878 #endif
879 		{
880 			if(proto==e->ip.proto)
881 			{
882 				target = (void *)e + e->target_offset;
883 				mr = (const struct ip_nat_multi_range *)&target->data[0];
884 				syslog(LOG_DEBUG, "postrouting rule #%u: %s %s %hu",
885 				       i, target->u.user.name, inet_ntoa(e->ip.src), ntohs(mr->range[0].min.all));
886 				/* target->u.user.name SNAT / MASQUERADE */
887 				if (eport != ntohs(mr->range[0].min.all)) {
888 					continue;
889 				}
890 				iaddr = e->ip.src.s_addr;
891 				match = (const struct ipt_entry_match *)&e->elems;
892 				if(0 == strncmp(match->u.user.name, "tcp", IPT_FUNCTION_MAXNAMELEN))
893 				{
894 					const struct ipt_tcp * info;
895 					info = (const struct ipt_tcp *)match->data;
896 					iport = info->spts[0];
897 				}
898 				else
899 				{
900 					const struct ipt_udp * info;
901 					info = (const struct ipt_udp *)match->data;
902 					iport = info->spts[0];
903 				}
904 
905 				index = i;
906 				syslog(LOG_INFO, "Trying to delete peer rule at index %u", index);
907 				r2 = delete_rule_and_commit(index, h, miniupnpd_nat_postrouting_chain, "delete_peer_rule");
908 				h = NULL;
909 				break;
910 			}
911 		}
912 	}
913 
914 	if(h)
915 #ifdef IPTABLES_143
916 		iptc_free(h);
917 #else
918 		iptc_free(&h);
919 #endif
920 	/*delete DSCP rule*/
921 	if((r2==0)&&(h = iptc_init("mangle")))
922 	{
923 		i = 0;
924 		index = -1;
925 		/* we must find the right index for the filter rule */
926 #ifdef IPTABLES_143
927 		for(e = iptc_first_rule(miniupnpd_nat_chain, h);
928 		    e;
929 			e = iptc_next_rule(e, h), i++)
930 #else
931 		for(e = iptc_first_rule(miniupnpd_nat_chain, &h);
932 		    e;
933 			e = iptc_next_rule(e, &h), i++)
934 #endif
935 		{
936 			if(proto==e->ip.proto)
937 			{
938 				match = (const struct ipt_entry_match *)&e->elems;
939 				/*syslog(LOG_DEBUG, "filter rule #%u: %s %s",
940 				       i, match->u.user.name, inet_ntoa(e->ip.dst));*/
941 				if(0 == strncmp(match->u.user.name, "tcp", IPT_FUNCTION_MAXNAMELEN))
942 				{
943 					const struct ipt_tcp * info;
944 					info = (const struct ipt_tcp *)match->data;
945 					if(iport != info->spts[0])
946 						continue;
947 				}
948 				else
949 				{
950 					const struct ipt_udp * info;
951 					info = (const struct ipt_udp *)match->data;
952 					if(iport != info->spts[0])
953 						continue;
954 				}
955 				if(iaddr != e->ip.src.s_addr)
956 					continue;
957 				index = i;
958 				syslog(LOG_INFO, "Trying to delete dscp rule at index %u", index);
959 				r2 = delete_rule_and_commit(index, h, miniupnpd_nat_chain, "delete_dscp_rule");
960 				h = NULL;
961 				break;
962 			}
963 		}
964 	if (h)
965 	#ifdef IPTABLES_143
966 		iptc_free(h);
967 	#else
968 		iptc_free(&h);
969 	#endif
970 	}
971 
972 	del_redirect_desc(eport, proto);
973 	return r*r2;
974 }
975 
976 /* ==================================== */
977 /* TODO : add the -m state --state NEW,ESTABLISHED,RELATED
978  * only for the filter rule */
979 static struct ipt_entry_match *
get_tcp_match(unsigned short dport,unsigned short sport)980 get_tcp_match(unsigned short dport, unsigned short sport)
981 {
982 	struct ipt_entry_match *match;
983 	struct ipt_tcp * tcpinfo;
984 	size_t size;
985 	size =   IPT_ALIGN(sizeof(struct ipt_entry_match))
986 	       + IPT_ALIGN(sizeof(struct ipt_tcp));
987 	match = calloc(1, size);
988 	match->u.match_size = size;
989 	strncpy(match->u.user.name, "tcp", sizeof(match->u.user.name));
990 	tcpinfo = (struct ipt_tcp *)match->data;
991 	if (sport == 0) {
992 		tcpinfo->spts[0] = 0;		/* all source ports */
993 		tcpinfo->spts[1] = 0xFFFF;
994 	} else {
995 		tcpinfo->spts[0] = sport;	   /* specified source port */
996 		tcpinfo->spts[1] = sport;
997 	}
998 	if (dport == 0) {
999 		tcpinfo->dpts[0] = 0;	   /* all destination ports */
1000 		tcpinfo->dpts[1] = 0xFFFF;
1001 	} else {
1002 		tcpinfo->dpts[0] = dport;	/* specified destination port */
1003 		tcpinfo->dpts[1] = dport;
1004 	}
1005 	return match;
1006 }
1007 
1008 static struct ipt_entry_match *
get_udp_match(unsigned short dport,unsigned short sport)1009 get_udp_match(unsigned short dport, unsigned short sport)
1010 {
1011 	struct ipt_entry_match *match;
1012 	struct ipt_udp * udpinfo;
1013 	size_t size;
1014 	size =   IPT_ALIGN(sizeof(struct ipt_entry_match))
1015 	       + IPT_ALIGN(sizeof(struct ipt_udp));
1016 	match = calloc(1, size);
1017 	match->u.match_size = size;
1018 	strncpy(match->u.user.name, "udp", sizeof(match->u.user.name));
1019 	udpinfo = (struct ipt_udp *)match->data;
1020 	if (sport == 0) {
1021 		udpinfo->spts[0] = 0;	   /* all source ports */
1022 		udpinfo->spts[1] = 0xFFFF;
1023 	} else {
1024 		udpinfo->spts[0] = sport;	   /* specified source port */
1025 		udpinfo->spts[1] = sport;
1026 	}
1027 	if (dport == 0) {
1028 		udpinfo->dpts[0] = 0;	   /* all destination ports */
1029 		udpinfo->dpts[1] = 0xFFFF;
1030 	} else {
1031 		udpinfo->dpts[0] = dport;   /* specified destination port */
1032 		udpinfo->dpts[1] = dport;
1033 	}
1034 	return match;
1035 }
1036 
1037 static struct ipt_entry_target *
get_dnat_target(const char * daddr,unsigned short dport)1038 get_dnat_target(const char * daddr, unsigned short dport)
1039 {
1040 	struct ipt_entry_target * target;
1041 	struct ip_nat_multi_range * mr;
1042 	struct ip_nat_range * range;
1043 	size_t size;
1044 
1045 	size =   IPT_ALIGN(sizeof(struct ipt_entry_target))
1046 	       + IPT_ALIGN(sizeof(struct ip_nat_multi_range));
1047 	target = calloc(1, size);
1048 	target->u.target_size = size;
1049 	strncpy(target->u.user.name, "DNAT", sizeof(target->u.user.name));
1050 	/* one ip_nat_range already included in ip_nat_multi_range */
1051 	mr = (struct ip_nat_multi_range *)&target->data[0];
1052 	mr->rangesize = 1;
1053 	range = &mr->range[0];
1054 	range->min_ip = range->max_ip = inet_addr(daddr);
1055 	range->flags |= IP_NAT_RANGE_MAP_IPS;
1056 	range->min.all = range->max.all = htons(dport);
1057 	range->flags |= IP_NAT_RANGE_PROTO_SPECIFIED;
1058 	return target;
1059 }
1060 
1061 static struct ipt_entry_target *
get_snat_target(const char * saddr,unsigned short sport)1062 get_snat_target(const char * saddr, unsigned short sport)
1063 {
1064 	struct ipt_entry_target * target;
1065 	struct ip_nat_multi_range * mr;
1066 	struct ip_nat_range * range;
1067 	size_t size;
1068 
1069 	size =   IPT_ALIGN(sizeof(struct ipt_entry_target))
1070 	       + IPT_ALIGN(sizeof(struct ip_nat_multi_range));
1071 	target = calloc(1, size);
1072 	target->u.target_size = size;
1073 	strncpy(target->u.user.name, "SNAT", sizeof(target->u.user.name));
1074 	/* one ip_nat_range already included in ip_nat_multi_range */
1075 	mr = (struct ip_nat_multi_range *)&target->data[0];
1076 	mr->rangesize = 1;
1077 	range = &mr->range[0];
1078 	range->min_ip = range->max_ip = inet_addr(saddr);
1079 	range->flags |= IP_NAT_RANGE_MAP_IPS;
1080 	range->min.all = range->max.all = htons(sport);
1081 	range->flags |= IP_NAT_RANGE_PROTO_SPECIFIED;
1082 	return target;
1083 }
1084 
1085 static struct ipt_entry_target *
get_dscp_target(unsigned char dscp)1086 get_dscp_target(unsigned char dscp)
1087 {
1088 	struct ipt_entry_target * target;
1089 	struct xt_DSCP_info * di;
1090 	size_t size;
1091 
1092 	size =   IPT_ALIGN(sizeof(struct ipt_entry_target))
1093 	       + IPT_ALIGN(sizeof(struct xt_DSCP_info));
1094 	target = calloc(1, size);
1095 	target->u.target_size = size;
1096 	strncpy(target->u.user.name, "DSCP", sizeof(target->u.user.name));
1097 	/* one ip_nat_range already included in ip_nat_multi_range */
1098 	di = (struct xt_DSCP_info *)&target->data[0];
1099 	di->dscp=dscp;
1100 	return target;
1101 }
1102 
1103 #ifdef ENABLE_PORT_TRIGGERING
1104 static struct ipt_entry_target *
get_masquerade_target(unsigned short port)1105 get_masquerade_target(unsigned short port)
1106 {
1107 	struct ipt_entry_target * target;
1108 	struct ip_nat_multi_range * mr;
1109 	struct ip_nat_range * range;
1110 	size_t size;
1111 
1112 	size =   IPT_ALIGN(sizeof(struct ipt_entry_target))
1113 	       + IPT_ALIGN(sizeof(struct ip_nat_multi_range));
1114 	target = calloc(1, size);
1115 	target->u.target_size = size;
1116 	strncpy(target->u.user.name, "MASQUERADE", sizeof(target->u.user.name));
1117 	/* one ip_nat_range already included in ip_nat_multi_range */
1118 	mr = (struct ip_nat_multi_range *)&target->data[0];
1119 	mr->rangesize = 1;
1120 	range = &mr->range[0];
1121 	range->min.tcp.port = range->max.tcp.port = htons(port);
1122 	/*range->min.all = range->max.all = htons(port);*/
1123 	range->flags |= IP_NAT_RANGE_PROTO_SPECIFIED;
1124 	return target;
1125 }
1126 #endif /* ENABLE_PORT_TRIGGERING */
1127 
1128 /* iptc_init_verify_and_append()
1129  * return 0 on success, -1 on failure */
1130 static int
iptc_init_verify_and_append(const char * table,const char * miniupnpd_chain,struct ipt_entry * e,const char * logcaller)1131 iptc_init_verify_and_append(const char * table,
1132                             const char * miniupnpd_chain,
1133                             struct ipt_entry * e,
1134                             const char * logcaller)
1135 {
1136 	IPTC_HANDLE h;
1137 	h = iptc_init(table);
1138 	if(!h)
1139 	{
1140 		syslog(LOG_ERR, "%s() : iptc_init() error : %s\n",
1141 		       logcaller, iptc_strerror(errno));
1142 		return -1;
1143 	}
1144 	if(!iptc_is_chain(miniupnpd_chain, h))
1145 	{
1146 		syslog(LOG_ERR, "%s() : chain %s not found",
1147 		       logcaller, miniupnpd_chain);
1148 		if(h)
1149 #ifdef IPTABLES_143
1150 			iptc_free(h);
1151 #else
1152 			iptc_free(&h);
1153 #endif
1154 		return -1;
1155 	}
1156 	/* iptc_insert_entry(miniupnpd_chain, e, n, h/&h) could also be used */
1157 #ifdef IPTABLES_143
1158 	if(!iptc_append_entry(miniupnpd_chain, e, h))
1159 #else
1160 	if(!iptc_append_entry(miniupnpd_chain, e, &h))
1161 #endif
1162 	{
1163 		syslog(LOG_ERR, "%s() : iptc_append_entry() error : %s\n",
1164 		       logcaller, iptc_strerror(errno));
1165 		if(h)
1166 #ifdef IPTABLES_143
1167 			iptc_free(h);
1168 #else
1169 			iptc_free(&h);
1170 #endif
1171 		return -1;
1172 	}
1173 #ifdef IPTABLES_143
1174 	if(!iptc_commit(h))
1175 #else
1176 	if(!iptc_commit(&h))
1177 #endif
1178 	{
1179 		syslog(LOG_ERR, "%s() : iptc_commit() error : %s\n",
1180 		       logcaller, iptc_strerror(errno));
1181 		if(h)
1182 #ifdef IPTABLES_143
1183 			iptc_free(h);
1184 #else
1185 			iptc_free(&h);
1186 #endif
1187 		return -1;
1188 	}
1189 	if(h)
1190 #ifdef IPTABLES_143
1191 		iptc_free(h);
1192 #else
1193 		iptc_free(&h);
1194 #endif
1195 	return 0;
1196 }
1197 
1198 /* add nat rule
1199  * iptables -t nat -A MINIUPNPD -p <proto> [-s <rhost>] --dport <eport> -j DNAT --to <iaddr>:<iport>
1200  * */
1201 static int
addnatrule(int proto,unsigned short eport,const char * iaddr,unsigned short iport,const char * rhost)1202 addnatrule(int proto, unsigned short eport,
1203            const char * iaddr, unsigned short iport,
1204            const char * rhost)
1205 {
1206 	int r = 0;
1207 	struct ipt_entry * e;
1208 	struct ipt_entry * tmp;
1209 	struct ipt_entry_match *match = NULL;
1210 	struct ipt_entry_target *target = NULL;
1211 
1212 	e = calloc(1, sizeof(struct ipt_entry));
1213 	if(!e) {
1214 		syslog(LOG_ERR, "%s: calloc(%d) error", "addnatrule",
1215 		       (int)sizeof(struct ipt_entry));
1216 		return -1;
1217 	}
1218 	e->ip.proto = proto;
1219 	if(proto == IPPROTO_TCP) {
1220 		match = get_tcp_match(eport, 0);
1221 	} else {
1222 		match = get_udp_match(eport, 0);
1223 	}
1224 #ifdef NFC_UNKNOWN
1225 	e->nfcache = NFC_UNKNOWN;
1226 #endif
1227 	target = get_dnat_target(iaddr, iport);
1228 #ifdef NFC_IP_DST_PT
1229 	e->nfcache |= NFC_IP_DST_PT;
1230 #endif
1231 	tmp = realloc(e, sizeof(struct ipt_entry)
1232 	               + match->u.match_size
1233 				   + target->u.target_size);
1234 	if(!tmp) {
1235 		syslog(LOG_ERR, "%s: realloc(%d) error", "addnatrule",
1236 		       (int)(sizeof(struct ipt_entry) + match->u.match_size + target->u.target_size));
1237 		free(e);
1238 		free(match);
1239 		free(target);
1240 		return -1;
1241 	}
1242 	e = tmp;
1243 	memcpy(e->elems, match, match->u.match_size);
1244 	memcpy(e->elems + match->u.match_size, target, target->u.target_size);
1245 	e->target_offset = sizeof(struct ipt_entry)
1246 	                   + match->u.match_size;
1247 	e->next_offset = sizeof(struct ipt_entry)
1248 	                 + match->u.match_size
1249 					 + target->u.target_size;
1250 	/* remote host */
1251 	if(rhost && (rhost[0] != '\0') && (0 != strcmp(rhost, "*"))) {
1252 		e->ip.src.s_addr = inet_addr(rhost);
1253 		e->ip.smsk.s_addr = INADDR_NONE;
1254 	}
1255 
1256 	r = iptc_init_verify_and_append("nat", miniupnpd_nat_chain, e, "addnatrule");
1257 	free(target);
1258 	free(match);
1259 	free(e);
1260 	return r;
1261 }
1262 
1263 /* for "Port Triggering"
1264  * Section 2.5.16 figure 2.2 in UPnP-gw-WANIPConnection-v2-Service.pdf
1265  *
1266  *   When a control point creates a port forwarding rule with AddPortMapping()
1267  *   action for inbound traffic , this rule MUST also be applied when NAT port
1268  *   triggering occurs for outbound traffic.
1269  *
1270  * iptables -t nat -A MINIUPNPD-POSTROUTING {-o <extif>} -s <iaddr>
1271  *          -p <proto> [-d <rhost>] --sport <iport> -j MASQUERADE --to-ports <eport>
1272  */
1273 #ifdef ENABLE_PORT_TRIGGERING
1274 static int
addmasqueraderule(int proto,unsigned short eport,const char * iaddr,unsigned short iport,const char * rhost)1275 addmasqueraderule(int proto,
1276            unsigned short eport,
1277            const char * iaddr, unsigned short iport,
1278            const char * rhost/*, const char * extif*/)
1279 {
1280 	int r = 0;
1281 	struct ipt_entry * e;
1282 	struct ipt_entry * tmp;
1283 	struct ipt_entry_match *match = NULL;
1284 	struct ipt_entry_target *target = NULL;
1285 
1286 	e = calloc(1, sizeof(struct ipt_entry));
1287 	if(!e) {
1288 		syslog(LOG_ERR, "%s: calloc(%d) error", "addmasqueraderule",
1289 		       (int)sizeof(struct ipt_entry));
1290 		return -1;
1291 	}
1292 	e->ip.proto = proto;
1293 	if(proto == IPPROTO_TCP) {
1294 		match = get_tcp_match(0, iport);
1295 	} else {
1296 		match = get_udp_match(0, iport);
1297 	}
1298 #ifdef NFC_UNKNOWN
1299 	e->nfcache = NFC_UNKNOWN;
1300 #endif
1301 	target = get_masquerade_target(eport);
1302 #ifdef NFC_IP_DST_PT
1303 	e->nfcache |= NFC_IP_DST_PT;
1304 #endif
1305 	tmp = realloc(e, sizeof(struct ipt_entry)
1306 	               + match->u.match_size
1307 				   + target->u.target_size);
1308 	if(!tmp) {
1309 		syslog(LOG_ERR, "%s: realloc(%d) error", "addmasqueraderule",
1310 		       (int)(sizeof(struct ipt_entry) + match->u.match_size + target->u.target_size));
1311 		free(e);
1312 		free(match);
1313 		free(target);
1314 		return -1;
1315 	}
1316 	e = tmp;
1317 	memcpy(e->elems, match, match->u.match_size);
1318 	memcpy(e->elems + match->u.match_size, target, target->u.target_size);
1319 	e->target_offset = sizeof(struct ipt_entry)
1320 	                   + match->u.match_size;
1321 	e->next_offset = sizeof(struct ipt_entry)
1322 	                 + match->u.match_size
1323 					 + target->u.target_size;
1324 #if 0
1325 	/* do not add outiface (-o) to rule, as the MINIUPNPD-POSTROUTING chain
1326 	 * should already have matched it */
1327 	if(extif != NULL) {
1328 		strncpy(e->ip.outiface, extif, sizeof(e->ip.outiface));
1329 		memset(e->ip.outiface_mask, 0xff, strlen(e->ip.outiface) + 1);/* Include nul-terminator in match */
1330 	}
1331 #endif
1332 	/* internal host */
1333 	if(iaddr && (iaddr[0] != '\0') && (0 != strcmp(iaddr, "*")))
1334 	{
1335 		e->ip.src.s_addr = inet_addr(iaddr);
1336 		e->ip.smsk.s_addr = INADDR_NONE;
1337 	}
1338 	/* remote host */
1339 	if(rhost && (rhost[0] != '\0') && (0 != strcmp(rhost, "*"))) {
1340 		e->ip.dst.s_addr = inet_addr(rhost);
1341 		e->ip.dmsk.s_addr = INADDR_NONE;
1342 	}
1343 
1344 	r = iptc_init_verify_and_append("nat", miniupnpd_nat_postrouting_chain, e, "addmasqueraderule");
1345 	free(target);
1346 	free(match);
1347 	free(e);
1348 	return r;
1349 }
1350 #endif /* ENABLE_PORT_TRIGGERING */
1351 
1352 /* called by add_peer_redirect_rule2()
1353  *
1354  * iptables -t nat -A MINIUPNPD-POSTROUTING -s <iaddr> -d <rhost>
1355  *    -p <proto> --sport <iport> --dport <rport> -j SNAT
1356  *    --to-source <eaddr>:<eport> */
1357 static int
addpeernatrule(int proto,const char * eaddr,unsigned short eport,const char * iaddr,unsigned short iport,const char * rhost,unsigned short rport)1358 addpeernatrule(int proto,
1359            const char * eaddr, unsigned short eport,
1360            const char * iaddr, unsigned short iport,
1361            const char * rhost, unsigned short rport)
1362 {
1363 	int r = 0;
1364 	struct ipt_entry * e;
1365 	struct ipt_entry * tmp;
1366 	struct ipt_entry_match *match = NULL;
1367 	struct ipt_entry_target *target = NULL;
1368 
1369 	e = calloc(1, sizeof(struct ipt_entry));
1370 	if(!e) {
1371 		syslog(LOG_ERR, "%s: calloc(%d) error", "addpeernatrule",
1372 		       (int)sizeof(struct ipt_entry));
1373 		return -1;
1374 	}
1375 	e->ip.proto = proto;
1376 	/* TODO: Fill port matches and SNAT */
1377 	if(proto == IPPROTO_TCP) {
1378 		match = get_tcp_match(rport, iport);
1379 	} else {
1380 		match = get_udp_match(rport, iport);
1381 	}
1382 #ifdef NFC_UNKNOWN
1383 	e->nfcache = NFC_UNKNOWN;
1384 #endif
1385 	target = get_snat_target(eaddr, eport);
1386 #ifdef NFC_IP_DST_PT
1387 	e->nfcache |= NFC_IP_DST_PT;
1388 #endif
1389 #ifdef NFC_IP_SRC_PT
1390 	e->nfcache |= NFC_IP_SRC_PT;
1391 #endif
1392 	tmp = realloc(e, sizeof(struct ipt_entry)
1393 	               + match->u.match_size
1394 				   + target->u.target_size);
1395 	if(!tmp) {
1396 		syslog(LOG_ERR, "%s: realloc(%d) error", "addpeernatrule",
1397 		       (int)(sizeof(struct ipt_entry) + match->u.match_size + target->u.target_size));
1398 		free(e);
1399 		free(match);
1400 		free(target);
1401 		return -1;
1402 	}
1403 	e = tmp;
1404 	memcpy(e->elems, match, match->u.match_size);
1405 	memcpy(e->elems + match->u.match_size, target, target->u.target_size);
1406 	e->target_offset = sizeof(struct ipt_entry)
1407 	                   + match->u.match_size;
1408 	e->next_offset = sizeof(struct ipt_entry)
1409 	                 + match->u.match_size
1410 					 + target->u.target_size;
1411 
1412 	/* internal host */
1413 	if(iaddr && (iaddr[0] != '\0') && (0 != strcmp(iaddr, "*")))
1414 	{
1415 		e->ip.src.s_addr = inet_addr(iaddr);
1416 		e->ip.smsk.s_addr = INADDR_NONE;
1417 	}
1418 	/* remote host */
1419 	if(rhost && (rhost[0] != '\0') && (0 != strcmp(rhost, "*")))
1420 	{
1421 		e->ip.dst.s_addr = inet_addr(rhost);
1422 		e->ip.dmsk.s_addr = INADDR_NONE;
1423 	}
1424 
1425 	r = iptc_init_verify_and_append("nat", miniupnpd_nat_postrouting_chain, e, "addpeernatrule");
1426 	free(target);
1427 	free(match);
1428 	free(e);
1429 	return r;
1430 }
1431 
1432 /* called by add_peer_dscp_rule2()
1433  * iptables -t mangle -A MINIUPNPD -s <iaddr> -d <rhost>
1434  *    -p <proto> --sport <iport> --dport <rport> -j DSCP
1435  *    --set-dscp 0xXXXX                   */
1436 static int
addpeerdscprule(int proto,unsigned char dscp,const char * iaddr,unsigned short iport,const char * rhost,unsigned short rport)1437 addpeerdscprule(int proto, unsigned char dscp,
1438            const char * iaddr, unsigned short iport,
1439            const char * rhost, unsigned short rport)
1440 {
1441 	int r = 0;
1442 	struct ipt_entry * e;
1443 	struct ipt_entry * tmp;
1444 	struct ipt_entry_match *match = NULL;
1445 	struct ipt_entry_target *target = NULL;
1446 
1447 	e = calloc(1, sizeof(struct ipt_entry));
1448 	if(!e) {
1449 		syslog(LOG_ERR, "%s: calloc(%d) error", "addpeerdscprule",
1450 		       (int)sizeof(struct ipt_entry));
1451 		return -1;
1452 	}
1453 	e->ip.proto = proto;
1454 	/* TODO: Fill port matches and SNAT */
1455 	if(proto == IPPROTO_TCP) {
1456 		match = get_tcp_match(rport, iport);
1457 	} else {
1458 		match = get_udp_match(rport, iport);
1459 	}
1460 #ifdef NFC_UNKNOWN
1461 	e->nfcache = NFC_UNKNOWN;
1462 #endif
1463 	target = get_dscp_target(dscp);
1464 #ifdef NFC_IP_DST_PT
1465 	e->nfcache |= NFC_IP_DST_PT;
1466 #endif
1467 #ifdef NFC_IP_SRC_PT
1468 	e->nfcache |= NFC_IP_SRC_PT;
1469 #endif
1470 	tmp = realloc(e, sizeof(struct ipt_entry)
1471 	               + match->u.match_size
1472 				   + target->u.target_size);
1473 	if(!tmp) {
1474 		syslog(LOG_ERR, "%s: realloc(%d) error", "addpeerdscprule",
1475 		       (int)(sizeof(struct ipt_entry) + match->u.match_size + target->u.target_size));
1476 		free(e);
1477 		free(match);
1478 		free(target);
1479 		return -1;
1480 	}
1481 	e = tmp;
1482 	memcpy(e->elems, match, match->u.match_size);
1483 	memcpy(e->elems + match->u.match_size, target, target->u.target_size);
1484 	e->target_offset = sizeof(struct ipt_entry)
1485 	                   + match->u.match_size;
1486 	e->next_offset = sizeof(struct ipt_entry)
1487 	                 + match->u.match_size
1488 					 + target->u.target_size;
1489 
1490 	/* internal host */
1491 	if(iaddr && (iaddr[0] != '\0') && (0 != strcmp(iaddr, "*")))
1492 	{
1493 		e->ip.src.s_addr = inet_addr(iaddr);
1494 		e->ip.smsk.s_addr = INADDR_NONE;
1495 	}
1496 	/* remote host */
1497 	if(rhost && (rhost[0] != '\0') && (0 != strcmp(rhost, "*")))
1498 	{
1499 		e->ip.dst.s_addr = inet_addr(rhost);
1500 		e->ip.dmsk.s_addr = INADDR_NONE;
1501 	}
1502 
1503 	r = iptc_init_verify_and_append("mangle", miniupnpd_nat_chain, e,
1504 	                                "addpeerDSCPrule");
1505 	free(target);
1506 	free(match);
1507 	free(e);
1508 	return r;
1509 }
1510 
1511 
1512 /* ================================= */
1513 static struct ipt_entry_target *
get_accept_target(void)1514 get_accept_target(void)
1515 {
1516 	struct ipt_entry_target * target = NULL;
1517 	size_t size;
1518 	size =   IPT_ALIGN(sizeof(struct ipt_entry_target))
1519 	       + IPT_ALIGN(sizeof(int));
1520 	target = calloc(1, size);
1521 	target->u.user.target_size = size;
1522 	strncpy(target->u.user.name, "ACCEPT", sizeof(target->u.user.name));
1523 	return target;
1524 }
1525 
1526 /* add_filter_rule()
1527  * iptables -t filter -A MINIUPNPD [-s <rhost>] -p <proto> -d <iaddr> --dport <iport> -j ACCEPT */
1528 static int
add_filter_rule(int proto,const char * rhost,const char * iaddr,unsigned short iport)1529 add_filter_rule(int proto, const char * rhost,
1530                 const char * iaddr, unsigned short iport)
1531 {
1532 	int r = 0;
1533 	struct ipt_entry * e;
1534 	struct ipt_entry * tmp;
1535 	struct ipt_entry_match *match = NULL;
1536 	struct ipt_entry_target *target = NULL;
1537 
1538 	e = calloc(1, sizeof(struct ipt_entry));
1539 	if(!e) {
1540 		syslog(LOG_ERR, "%s: calloc(%d) error", "add_filter_rule",
1541 		       (int)sizeof(struct ipt_entry));
1542 		return -1;
1543 	}
1544 	e->ip.proto = proto;
1545 	if(proto == IPPROTO_TCP) {
1546 		match = get_tcp_match(iport,0);
1547 	} else {
1548 		match = get_udp_match(iport,0);
1549 	}
1550 	e->ip.dst.s_addr = inet_addr(iaddr);
1551 	e->ip.dmsk.s_addr = INADDR_NONE;
1552 #ifdef NFC_UNKNOWN
1553 	e->nfcache = NFC_UNKNOWN;
1554 #endif
1555 	target = get_accept_target();
1556 #ifdef NFC_IP_DST_PT
1557 	e->nfcache |= NFC_IP_DST_PT;
1558 #endif
1559 	tmp = realloc(e, sizeof(struct ipt_entry)
1560 	               + match->u.match_size
1561 				   + target->u.target_size);
1562 	if(!tmp) {
1563 		syslog(LOG_ERR, "%s: realloc(%d) error", "add_filter_rule",
1564 		       (int)(sizeof(struct ipt_entry) + match->u.match_size + target->u.target_size));
1565 		free(e);
1566 		free(match);
1567 		free(target);
1568 		return -1;
1569 	}
1570 	e = tmp;
1571 	memcpy(e->elems, match, match->u.match_size);
1572 	memcpy(e->elems + match->u.match_size, target, target->u.target_size);
1573 	e->target_offset = sizeof(struct ipt_entry)
1574 	                   + match->u.match_size;
1575 	e->next_offset = sizeof(struct ipt_entry)
1576 	                 + match->u.match_size
1577 					 + target->u.target_size;
1578 	/* remote host */
1579 	if(rhost && (rhost[0] != '\0') && (0 != strcmp(rhost, "*")))
1580 	{
1581 		e->ip.src.s_addr = inet_addr(rhost);
1582 		e->ip.smsk.s_addr = INADDR_NONE;
1583 	}
1584 
1585 	r = iptc_init_verify_and_append("filter", miniupnpd_forward_chain, e, "add_filter_rule");
1586 	free(target);
1587 	free(match);
1588 	free(e);
1589 	return r;
1590 }
1591 
1592 /* return an (malloc'ed) array of "external" port for which there is
1593  * a port mapping. number is the size of the array */
1594 unsigned short *
get_portmappings_in_range(unsigned short startport,unsigned short endport,int proto,unsigned int * number)1595 get_portmappings_in_range(unsigned short startport, unsigned short endport,
1596                           int proto, unsigned int * number)
1597 {
1598 	unsigned short * array;
1599 	unsigned int capacity;
1600 	unsigned short eport;
1601 	IPTC_HANDLE h;
1602 	const struct ipt_entry * e;
1603 	const struct ipt_entry_match *match;
1604 
1605 	*number = 0;
1606 	capacity = 128;
1607 	array = calloc(capacity, sizeof(unsigned short));
1608 	if(!array)
1609 	{
1610 		syslog(LOG_ERR, "%s() : calloc error", "get_portmappings_in_range");
1611 		return NULL;
1612 	}
1613 
1614 	h = iptc_init("nat");
1615 	if(!h)
1616 	{
1617 		syslog(LOG_ERR, "%s() : iptc_init() failed : %s",
1618 		       "get_portmappings_in_range", iptc_strerror(errno));
1619 		free(array);
1620 		return NULL;
1621 	}
1622 	if(!iptc_is_chain(miniupnpd_nat_chain, h))
1623 	{
1624 		syslog(LOG_ERR, "chain %s not found", miniupnpd_nat_chain);
1625 		free(array);
1626 		array = NULL;
1627 	}
1628 	else
1629 	{
1630 #ifdef IPTABLES_143
1631 		for(e = iptc_first_rule(miniupnpd_nat_chain, h);
1632 		    e;
1633 			e = iptc_next_rule(e, h))
1634 #else
1635 		for(e = iptc_first_rule(miniupnpd_nat_chain, &h);
1636 		    e;
1637 			e = iptc_next_rule(e, &h))
1638 #endif
1639 		{
1640 			if(proto == e->ip.proto)
1641 			{
1642 				match = (const struct ipt_entry_match *)&e->elems;
1643 				if(0 == strncmp(match->u.user.name, "tcp", IPT_FUNCTION_MAXNAMELEN))
1644 				{
1645 					const struct ipt_tcp * info;
1646 					info = (const struct ipt_tcp *)match->data;
1647 					eport = info->dpts[0];
1648 				}
1649 				else
1650 				{
1651 					const struct ipt_udp * info;
1652 					info = (const struct ipt_udp *)match->data;
1653 					eport = info->dpts[0];
1654 				}
1655 				if(startport <= eport && eport <= endport)
1656 				{
1657 					if(*number >= capacity)
1658 					{
1659 						unsigned short * tmp;
1660 						/* need to increase the capacity of the array */
1661 						capacity += 128;
1662 						if (capacity <= *number)
1663 							capacity = *number + 1;
1664 						tmp = realloc(array, sizeof(unsigned short)*capacity);
1665 						if(!tmp)
1666 						{
1667 							syslog(LOG_ERR, "get_portmappings_in_range() : realloc(%u) error",
1668 							       (unsigned)sizeof(unsigned short)*capacity);
1669 							*number = 0;
1670 							free(array);
1671 							array = NULL;
1672 							break;
1673 						}
1674 						array = tmp;
1675 					}
1676 					array[*number] = eport;
1677 					(*number)++;
1678 				}
1679 			}
1680 		}
1681 	}
1682 	if(h)
1683 #ifdef IPTABLES_143
1684 		iptc_free(h);
1685 #else
1686 		iptc_free(&h);
1687 #endif
1688 	return array;
1689 }
1690 
1691 int
update_portmapping_desc_timestamp(const char * ifname,unsigned short eport,int proto,const char * desc,unsigned int timestamp)1692 update_portmapping_desc_timestamp(const char * ifname,
1693                    unsigned short eport, int proto,
1694                    const char * desc, unsigned int timestamp)
1695 {
1696 	UNUSED(ifname);
1697 	del_redirect_desc(eport, proto);
1698 	add_redirect_desc(eport, proto, desc, timestamp);
1699 	return 0;
1700 }
1701 
1702 static int
update_rule_and_commit(const char * table,const char * chain,unsigned index,const struct ipt_entry * e)1703 update_rule_and_commit(const char * table, const char * chain,
1704                        unsigned index, const struct ipt_entry * e)
1705 {
1706 	IPTC_HANDLE h;
1707 	int r = 0;
1708 
1709 	h = iptc_init(table);
1710 	if(!h)
1711 	{
1712 		syslog(LOG_ERR, "%s() : iptc_init() failed : %s",
1713 		       "update_rule_and_commit", iptc_strerror(errno));
1714 		return -1;
1715 	}
1716 #ifdef IPTABLES_143
1717 	if(!iptc_replace_entry(chain, e, index, h))
1718 #else
1719 	if(!iptc_replace_entry(chain, e, index, &h))
1720 #endif
1721 	{
1722 		syslog(LOG_ERR, "%s(): iptc_replace_entry: %s",
1723 		       "update_rule_and_commit", iptc_strerror(errno));
1724 		r = -1;
1725 	}
1726 #ifdef IPTABLES_143
1727 	else if(!iptc_commit(h))
1728 #else
1729 	else if(!iptc_commit(&h))
1730 #endif
1731 	{
1732 		syslog(LOG_ERR, "%s(): iptc_commit: %s",
1733 		       "update_rule_and_commit", iptc_strerror(errno));
1734 		r = -1;
1735 	}
1736 #ifdef IPTABLES_143
1737 	iptc_free(h);
1738 #else
1739 	iptc_free(&h);
1740 #endif
1741 	return r;
1742 }
1743 
1744 int
update_portmapping(const char * ifname,unsigned short eport,int proto,unsigned short iport,const char * desc,unsigned int timestamp)1745 update_portmapping(const char * ifname, unsigned short eport, int proto,
1746                    unsigned short iport, const char * desc,
1747                    unsigned int timestamp)
1748 {
1749 	int r = 0;
1750 	int found = 0;
1751 	unsigned index = 0;
1752 	unsigned i = 0;
1753 	IPTC_HANDLE h;
1754 	const struct ipt_entry * e;
1755 	struct ipt_entry * new_e = NULL;
1756 	size_t entry_len;
1757 	struct ipt_entry_target * target;
1758 	struct ip_nat_multi_range * mr;
1759 	const struct ipt_entry_match *match;
1760 	uint32_t iaddr = 0;
1761 	unsigned short old_iport = 0;
1762 
1763 	h = iptc_init("nat");
1764 	if(!h)
1765 	{
1766 		syslog(LOG_ERR, "%s() : iptc_init() failed : %s",
1767 		       "update_portmapping", iptc_strerror(errno));
1768 		return -1;
1769 	}
1770 	/* First step : find the right nat rule */
1771 	if(!iptc_is_chain(miniupnpd_nat_chain, h))
1772 	{
1773 		syslog(LOG_ERR, "chain %s not found", miniupnpd_nat_chain);
1774 		r = -1;
1775 	}
1776 	else
1777 	{
1778 #ifdef IPTABLES_143
1779 		for(e = iptc_first_rule(miniupnpd_nat_chain, h);
1780 		    e;
1781 			e = iptc_next_rule(e, h), i++)
1782 #else
1783 		for(e = iptc_first_rule(miniupnpd_nat_chain, &h);
1784 		    e;
1785 			e = iptc_next_rule(e, &h), i++)
1786 #endif
1787 		{
1788 			if(proto==e->ip.proto)
1789 			{
1790 				match = (const struct ipt_entry_match *)&e->elems;
1791 				if(0 == strncmp(match->u.user.name, "tcp", IPT_FUNCTION_MAXNAMELEN))
1792 				{
1793 					const struct ipt_tcp * info;
1794 					info = (const struct ipt_tcp *)match->data;
1795 					if(eport != info->dpts[0])
1796 						continue;
1797 				}
1798 				else
1799 				{
1800 					const struct ipt_udp * info;
1801 					info = (const struct ipt_udp *)match->data;
1802 					if(eport != info->dpts[0])
1803 						continue;
1804 				}
1805 				/* we found the right rule */
1806 				found = 1;
1807 				index = i;
1808 				target = (void *)e + e->target_offset;
1809 				mr = (struct ip_nat_multi_range *)&target->data[0];
1810 				iaddr = mr->range[0].min_ip;
1811 				old_iport = ntohs(mr->range[0].min.all);
1812 				entry_len = sizeof(struct ipt_entry) + match->u.match_size + target->u.target_size;
1813 				new_e = malloc(entry_len);
1814 				if(new_e == NULL) {
1815 					syslog(LOG_ERR, "%s: malloc(%u) error",
1816 					       "update_portmapping", (unsigned)entry_len);
1817 					r = -1;
1818 				}
1819 				else
1820 				{
1821 					memcpy(new_e, e, entry_len);
1822 				}
1823 				break;
1824 			}
1825 		}
1826 	}
1827 #ifdef IPTABLES_143
1828 	iptc_free(h);
1829 #else
1830 	iptc_free(&h);
1831 #endif
1832 	if(!found || r < 0)
1833 		return -1;
1834 	syslog(LOG_INFO, "Trying to update nat rule at index %u", index);
1835 	target = (void *)new_e + new_e->target_offset;
1836 	mr = (struct ip_nat_multi_range *)&target->data[0];
1837 	mr->range[0].min.all = mr->range[0].max.all = htons(iport);
1838 	/* first update the nat rule */
1839 	r = update_rule_and_commit("nat", miniupnpd_nat_chain, index, new_e);
1840 	free(new_e); new_e = NULL;
1841 	if(r < 0)
1842 		return r;
1843 
1844 	/* update filter rule */
1845 	h = iptc_init("filter");
1846 	if(!h)
1847 	{
1848 		syslog(LOG_ERR, "%s() : iptc_init() failed : %s",
1849 		       "update_portmapping", iptc_strerror(errno));
1850 		return -1;
1851 	}
1852 	i = 0; found = 0;
1853 	if(!iptc_is_chain(miniupnpd_forward_chain, h))
1854 	{
1855 		syslog(LOG_ERR, "chain %s not found", miniupnpd_forward_chain);
1856 	}
1857 	else
1858 	{
1859 		/* we must find the right index for the filter rule */
1860 #ifdef IPTABLES_143
1861 		for(e = iptc_first_rule(miniupnpd_forward_chain, h);
1862 		    e;
1863 			e = iptc_next_rule(e, h), i++)
1864 #else
1865 		for(e = iptc_first_rule(miniupnpd_forward_chain, &h);
1866 		    e;
1867 			e = iptc_next_rule(e, &h), i++)
1868 #endif
1869 		{
1870 			if(proto!=e->ip.proto)
1871 				continue;
1872 			target = (void *)e + e->target_offset;
1873 			match = (const struct ipt_entry_match *)&e->elems;
1874 			if(0 == strncmp(match->u.user.name, "tcp", IPT_FUNCTION_MAXNAMELEN))
1875 			{
1876 				const struct ipt_tcp * info;
1877 				info = (const struct ipt_tcp *)match->data;
1878 				if(old_iport != info->dpts[0])
1879 					continue;
1880 			}
1881 			else
1882 			{
1883 				const struct ipt_udp * info;
1884 				info = (const struct ipt_udp *)match->data;
1885 				if(old_iport != info->dpts[0])
1886 					continue;
1887 			}
1888 			if(iaddr != e->ip.dst.s_addr)
1889 				continue;
1890 			index = i;
1891 			found = 1;
1892 			entry_len = sizeof(struct ipt_entry) + match->u.match_size + target->u.target_size;
1893 			new_e = malloc(entry_len);
1894 			if(new_e == NULL) {
1895 				syslog(LOG_ERR, "%s: malloc(%u) error",
1896 				       "update_portmapping", (unsigned)entry_len);
1897 				r = -1;
1898 			} else {
1899 				memcpy(new_e, e, entry_len);
1900 				target = (void *)new_e + new_e->target_offset;
1901 				if (target->u.user.name[0] == '\0' && iptc_get_target(e, h)) {
1902 					strncpy(target->u.user.name, iptc_get_target(e, h), sizeof(target->u.user.name));
1903 				}
1904 			}
1905 			break;
1906 		}
1907 	}
1908 #ifdef IPTABLES_143
1909 	iptc_free(h);
1910 #else
1911 	iptc_free(&h);
1912 #endif
1913 	if(!found || r < 0)
1914 		return -1;
1915 
1916 	syslog(LOG_INFO, "Trying to update filter rule at index %u", index);
1917 	match = (struct ipt_entry_match *)&new_e->elems;
1918 	if(0 == strncmp(match->u.user.name, "tcp", IPT_FUNCTION_MAXNAMELEN))
1919 	{
1920 		struct ipt_tcp * info;
1921 		info = (struct ipt_tcp *)match->data;
1922 		info->dpts[0] = info->dpts[1] = iport;
1923 	}
1924 	else
1925 	{
1926 		struct ipt_udp * info;
1927 		info = (struct ipt_udp *)match->data;
1928 		info->dpts[0] = info->dpts[1] = iport;
1929 	}
1930 	r = update_rule_and_commit("filter", miniupnpd_forward_chain, index, new_e);
1931 	free(new_e); new_e = NULL;
1932 	if(r < 0)
1933 		return r;
1934 
1935 #ifdef ENABLE_PORT_TRIGGERING
1936 	/* update snat rule */
1937 	h = iptc_init("nat");
1938 	if(!h)
1939 	{
1940 		syslog(LOG_ERR, "%s() : iptc_init() failed : %s",
1941 		       "update_portmapping", iptc_strerror(errno));
1942 		goto skip;
1943 	}
1944 	i = 0; found = 0;
1945 	if(!iptc_is_chain(miniupnpd_nat_postrouting_chain, h))
1946 	{
1947 		syslog(LOG_ERR, "chain %s not found", miniupnpd_nat_postrouting_chain);
1948 	}
1949 	else
1950 	{
1951 		/* we must find the right index for the filter rule */
1952 #ifdef IPTABLES_143
1953 		for(e = iptc_first_rule(miniupnpd_nat_postrouting_chain, h);
1954 		    e;
1955 			e = iptc_next_rule(e, h), i++)
1956 #else
1957 		for(e = iptc_first_rule(miniupnpd_nat_postrouting_chain, &h);
1958 		    e;
1959 			e = iptc_next_rule(e, &h), i++)
1960 #endif
1961 		{
1962 			if(proto==e->ip.proto)
1963 			{
1964 				target = (void *)e + e->target_offset;
1965 				mr = (struct ip_nat_multi_range *)&target->data[0];
1966 				syslog(LOG_DEBUG, "postrouting rule #%u: %s %s %hu",
1967 						i, target->u.user.name, inet_ntoa(e->ip.src), ntohs(mr->range[0].min.all));
1968 				/* target->u.user.name SNAT / MASQUERADE */
1969 				if (eport != ntohs(mr->range[0].min.all)) {
1970 					continue;
1971 				}
1972 				match = (const struct ipt_entry_match *)&e->elems;
1973 				if(0 == strncmp(match->u.user.name, "tcp", IPT_FUNCTION_MAXNAMELEN))
1974 				{
1975 					const struct ipt_tcp * info;
1976 					info = (const struct ipt_tcp *)match->data;
1977 					if(old_iport != info->spts[0])
1978 						continue;
1979 				}
1980 				else
1981 				{
1982 					const struct ipt_udp * info;
1983 					info = (const struct ipt_udp *)match->data;
1984 					if(old_iport != info->spts[0])
1985 						continue;
1986 				}
1987 				if (iaddr != e->ip.src.s_addr) {
1988 					continue;
1989 				}
1990 				index = i;
1991 				found = 1;
1992 				entry_len = sizeof(struct ipt_entry) + match->u.match_size + target->u.target_size;
1993 				new_e = malloc(entry_len);
1994 				if(new_e == NULL) {
1995 					syslog(LOG_ERR, "%s: malloc(%u) error",
1996 							"update_portmapping", (unsigned)entry_len);
1997 					r = -1;
1998 				} else {
1999 					memcpy(new_e, e, entry_len);
2000 				}
2001 				break;
2002 			}
2003 		}
2004 	}
2005 #ifdef IPTABLES_143
2006 	iptc_free(h);
2007 #else
2008 	iptc_free(&h);
2009 #endif
2010 	if(!found || r < 0)
2011 		goto skip;
2012 
2013 	syslog(LOG_INFO, "Trying to update snat rule at index %u", index);
2014 	match = (struct ipt_entry_match *)&new_e->elems;
2015 	if(0 == strncmp(match->u.user.name, "tcp", IPT_FUNCTION_MAXNAMELEN))
2016 	{
2017 		struct ipt_tcp * info;
2018 		info = (struct ipt_tcp *)match->data;
2019 		info->spts[0] = info->spts[1] = iport;
2020 	}
2021 	else
2022 	{
2023 		struct ipt_udp * info;
2024 		info = (struct ipt_udp *)match->data;
2025 		info->spts[0] = info->spts[1] = iport;
2026 	}
2027 	r = update_rule_and_commit("nat", miniupnpd_nat_postrouting_chain, index, new_e);
2028 	free(new_e); new_e = NULL;
2029 	if(r < 0)
2030 		syslog(LOG_INFO, "Trying to update snat rule at index %u fail!", index);
2031 
2032 skip:
2033 #endif /* ENABLE_PORT_TRIGGERING */
2034 	return update_portmapping_desc_timestamp(ifname, eport, proto, desc, timestamp);
2035 }
2036 
2037 /* ================================ */
2038 #ifdef DEBUG
2039 static int
print_match(const struct ipt_entry_match * match)2040 print_match(const struct ipt_entry_match *match)
2041 {
2042 	printf("match %s :\n", match->u.user.name);
2043 	if(0 == strncmp(match->u.user.name, "tcp", IPT_FUNCTION_MAXNAMELEN))
2044 	{
2045 		struct ipt_tcp * tcpinfo;
2046 		tcpinfo = (struct ipt_tcp *)match->data;
2047 		printf("  srcport = %hu:%hu dstport = %hu:%hu\n",
2048 		       tcpinfo->spts[0], tcpinfo->spts[1],
2049 			   tcpinfo->dpts[0], tcpinfo->dpts[1]);
2050 	}
2051 	else if(0 == strncmp(match->u.user.name, "udp", IPT_FUNCTION_MAXNAMELEN))
2052 	{
2053 		struct ipt_udp * udpinfo;
2054 		udpinfo = (struct ipt_udp *)match->data;
2055 		printf("  srcport = %hu:%hu dstport = %hu:%hu\n",
2056 		       udpinfo->spts[0], udpinfo->spts[1],
2057 			   udpinfo->dpts[0], udpinfo->dpts[1]);
2058 	}
2059 	return 0;
2060 }
2061 
2062 static void
print_iface(const char * iface,const unsigned char * mask,int invert)2063 print_iface(const char * iface, const unsigned char * mask, int invert)
2064 {
2065 	unsigned i;
2066 	if(mask[0] == 0)
2067 		return;
2068 	if(invert)
2069 		printf("! ");
2070 	for(i=0; i<IFNAMSIZ; i++)
2071 	{
2072 		if(mask[i])
2073 		{
2074 			if(iface[i])
2075 				putchar(iface[i]);
2076 		}
2077 		else
2078 		{
2079 			if(iface[i-1])
2080 				putchar('+');
2081 			break;
2082 		}
2083 	}
2084 }
2085 
2086 static void
printip(uint32_t ip)2087 printip(uint32_t ip)
2088 {
2089 	printf("%u.%u.%u.%u", ip >> 24, (ip >> 16) & 0xff,
2090 	       (ip >> 8) & 0xff, ip & 0xff);
2091 }
2092 
2093 /* for debug */
2094 /* read the "filter" and "nat" tables */
2095 int
list_redirect_rule(const char * ifname)2096 list_redirect_rule(const char * ifname)
2097 {
2098 	IPTC_HANDLE h;
2099 	const struct ipt_entry * e;
2100 	const struct ipt_entry_target * target;
2101 	const struct ip_nat_multi_range * mr;
2102 	const char * target_str;
2103 	char addr[16], mask[16];
2104 	unsigned int index;
2105 	(void)ifname;
2106 
2107 	h = iptc_init("nat");
2108 	if(!h)
2109 	{
2110 		printf("iptc_init() error : %s\n", iptc_strerror(errno));
2111 		return -1;
2112 	}
2113 	if(!iptc_is_chain(miniupnpd_nat_chain, h))
2114 	{
2115 		printf("chain %s not found\n", miniupnpd_nat_chain);
2116 #ifdef IPTABLES_143
2117 		iptc_free(h);
2118 #else
2119 		iptc_free(&h);
2120 #endif
2121 		return -1;
2122 	}
2123 	index = 0;
2124 #ifdef IPTABLES_143
2125 	for(e = iptc_first_rule(miniupnpd_nat_chain, h);
2126 		e;
2127 		e = iptc_next_rule(e, h))
2128 	{
2129 		target_str = iptc_get_target(e, h);
2130 #else
2131 	for(e = iptc_first_rule(miniupnpd_nat_chain, &h);
2132 		e;
2133 		e = iptc_next_rule(e, &h))
2134 	{
2135 		target_str = iptc_get_target(e, &h);
2136 #endif
2137 		printf("=== rule #%u ===\n", index);
2138 		inet_ntop(AF_INET, &e->ip.src, addr, sizeof(addr));
2139 		inet_ntop(AF_INET, &e->ip.smsk, mask, sizeof(mask));
2140 		printf("src = %s%s/%s\t", (e->ip.invflags & IPT_INV_SRCIP)?"! ":"",
2141 		       /*inet_ntoa(e->ip.src), inet_ntoa(e->ip.smsk)*/
2142 		       addr, mask);
2143 		inet_ntop(AF_INET, &e->ip.dst, addr, sizeof(addr));
2144 		inet_ntop(AF_INET, &e->ip.dmsk, mask, sizeof(mask));
2145 		printf("dst = %s%s/%s\n", (e->ip.invflags & IPT_INV_DSTIP)?"! ":"",
2146 		       /*inet_ntoa(e->ip.dst), inet_ntoa(e->ip.dmsk)*/
2147 		       addr, mask);
2148 		/*printf("in_if = %s  out_if = %s\n", e->ip.iniface, e->ip.outiface);*/
2149 		printf("in_if = ");
2150 		print_iface(e->ip.iniface, e->ip.iniface_mask,
2151 		            e->ip.invflags & IPT_INV_VIA_IN);
2152 		printf("\tout_if = ");
2153 		print_iface(e->ip.outiface, e->ip.outiface_mask,
2154 		            e->ip.invflags & IPT_INV_VIA_OUT);
2155 		printf("\n");
2156 		printf("ip.proto = %s%d\n", (e->ip.invflags & IPT_INV_PROTO)?"! ":"",
2157 		       e->ip.proto);
2158 		/* display matches stuff */
2159 		if(e->target_offset)
2160 		{
2161 			IPT_MATCH_ITERATE(e, print_match);
2162 			/*printf("\n");*/
2163 		}
2164 		printf("target = %s :\n", target_str);
2165 		target = (void *)e + e->target_offset;
2166 		mr = (const struct ip_nat_multi_range *)&target->data[0];
2167 		printf("  ips ");
2168 		printip(ntohl(mr->range[0].min_ip));
2169 		printf(" ");
2170 		printip(ntohl(mr->range[0].max_ip));
2171 		printf("\n  ports %hu %hu\n", ntohs(mr->range[0].min.all),
2172 		          ntohs(mr->range[0].max.all));
2173 		printf("  flags = %x\n", mr->range[0].flags);
2174 		index++;
2175 	}
2176 	if(h)
2177 #ifdef IPTABLES_143
2178 		iptc_free(h);
2179 #else
2180 		iptc_free(&h);
2181 #endif
2182 	printf("======\n");
2183 	return 0;
2184 }
2185 #endif
2186