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