miniupnpd 1.9 (20160113)
[tomato.git] / release / src / router / miniupnpd / ipf / ipfrdr.c
blob5a2dc02c6d33d264e47e88c8629b6c9b2acd0544
1 /* $Id: ipfrdr.c,v 1.17 2016/01/13 15:51:07 nanard Exp $ */
2 /* MiniUPnP project
3 * http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/
4 * (c) 2007 Darren Reed
5 * This software is subject to the conditions detailed
6 * in the LICENCE file provided within the distribution */
8 #include <sys/param.h>
9 #include <sys/types.h>
10 #include <sys/file.h>
12 * This is a workaround for <sys/uio.h> troubles on FreeBSD, HPUX, OpenBSD.
13 * Needed here because on some systems <sys/uio.h> gets included by things
14 * like <sys/socket.h>
16 #ifndef _KERNEL
17 # define ADD_KERNEL
18 # define _KERNEL
19 # define KERNEL
20 #endif
21 #ifdef __OpenBSD__
22 struct file;
23 #endif
24 #include <sys/uio.h>
25 #ifdef ADD_KERNEL
26 # undef _KERNEL
27 # undef KERNEL
28 #endif
29 #include <sys/time.h>
30 #include <sys/socket.h>
31 #include <sys/syslog.h>
32 #include <sys/ioctl.h>
33 #include <net/if.h>
34 #if __FreeBSD_version >= 300000
35 # include <net/if_var.h>
36 #endif
37 #include <netinet/in.h>
38 #include <netinet/in_systm.h>
39 #include <netinet/ip.h>
40 #include <netinet/ip_icmp.h>
41 #ifndef TCP_PAWS_IDLE /* IRIX */
42 # include <netinet/tcp.h>
43 #endif
44 #include <netinet/udp.h>
46 #include <arpa/inet.h>
48 #include <errno.h>
49 #include <limits.h>
50 #include <netdb.h>
51 #include <stdlib.h>
52 #include <fcntl.h>
53 #include <syslog.h>
54 #include <stddef.h>
55 #include <stdio.h>
56 #if !defined(__SVR4) && !defined(__svr4__) && defined(sun)
57 # include <strings.h>
58 #endif
59 #include <string.h>
60 #include <unistd.h>
62 #include "../config.h"
63 #include "netinet/ipl.h"
64 #include "netinet/ip_compat.h"
65 #include "netinet/ip_fil.h"
66 #include "netinet/ip_nat.h"
67 #include "netinet/ip_state.h"
70 #ifndef __P
71 # ifdef __STDC__
72 # define __P(x) x
73 # else
74 # define __P(x) ()
75 # endif
76 #endif
77 #ifndef __STDC__
78 # undef const
79 # define const
80 #endif
82 #ifndef U_32_T
83 # define U_32_T 1
84 # if defined(__NetBSD__) || defined(__OpenBSD__) || defined(__FreeBSD__) || \
85 defined(__sgi)
86 typedef u_int32_t u_32_t;
87 # else
88 # if defined(__alpha__) || defined(__alpha) || defined(_LP64)
89 typedef unsigned int u_32_t;
90 # else
91 # if SOLARIS2 >= 6
92 typedef uint32_t u_32_t;
93 # else
94 typedef unsigned int u_32_t;
95 # endif
96 # endif
97 # endif /* __NetBSD__ || __OpenBSD__ || __FreeBSD__ || __sgi */
98 #endif /* U_32_T */
101 #if defined(__NetBSD__) || defined(__OpenBSD__) || \
102 (_BSDI_VERSION >= 199701) || (__FreeBSD_version >= 300000) || \
103 SOLARIS || defined(__sgi) || defined(__osf__) || defined(linux)
104 # include <stdarg.h>
105 typedef int (* ioctlfunc_t) __P((int, ioctlcmd_t, ...));
106 #else
107 typedef int (* ioctlfunc_t) __P((dev_t, ioctlcmd_t, void *));
108 #endif
109 typedef void (* addfunc_t) __P((int, ioctlfunc_t, void *));
110 typedef int (* copyfunc_t) __P((void *, void *, size_t));
114 * SunOS4
116 #if defined(sun) && !defined(__SVR4) && !defined(__svr4__)
117 extern int ioctl __P((int, int, void *));
118 #endif
120 #include "../upnpglobalvars.h"
122 /* group name */
123 static const char group_name[] = "miniupnpd";
125 static int dev = -1;
126 static int dev_ipl = -1;
128 /* IPFilter cannot store redirection descriptions, so we use our
129 * own structure to store them */
130 struct rdr_desc {
131 struct rdr_desc * next;
132 unsigned short eport;
133 int proto;
134 unsigned int timestamp;
135 char str[];
138 /* pointer to the chained list where descriptions are stored */
139 static struct rdr_desc * rdr_desc_list;
141 static void
142 add_redirect_desc(unsigned short eport, int proto,
143 unsigned int timestamp, const char * desc)
145 struct rdr_desc * p;
146 size_t l;
148 if (desc != NULL) {
149 l = strlen(desc) + 1;
150 p = malloc(sizeof(struct rdr_desc) + l);
151 if (p) {
152 p->next = rdr_desc_list;
153 p->eport = eport;
154 p->proto = proto;
155 p->timestamp = timestamp;
156 memcpy(p->str, desc, l);
157 rdr_desc_list = p;
162 static void
163 del_redirect_desc(unsigned short eport, int proto)
165 struct rdr_desc * p, * last;
167 last = NULL;
168 for (p = rdr_desc_list; p; p = p->next) {
169 if(p->eport == eport && p->proto == proto) {
170 if (last == NULL)
171 rdr_desc_list = p->next;
172 else
173 last->next = p->next;
174 free(p);
175 return;
180 static void
181 get_redirect_desc(unsigned short eport, int proto, char * desc, int desclen, unsigned int * timestamp)
183 struct rdr_desc * p;
185 if (desc == NULL || desclen == 0)
186 return;
187 for (p = rdr_desc_list; p; p = p->next) {
188 if (p->eport == eport && p->proto == proto)
190 strncpy(desc, p->str, desclen);
191 *timestamp = p->timestamp;
192 return;
195 return;
198 int init_redirect(void)
201 dev = open(IPNAT_NAME, O_RDWR);
202 if (dev < 0) {
203 syslog(LOG_ERR, "open(\"%s\"): %m", IPNAT_NAME);
204 return -1;
206 dev_ipl = open(IPL_NAME, O_RDWR);
207 if (dev_ipl < 0) {
208 syslog(LOG_ERR, "open(\"%s\"): %m", IPL_NAME);
209 return -1;
211 return 0;
214 void shutdown_redirect(void)
217 if (dev >= 0) {
218 close(dev);
219 dev = -1;
221 if (dev_ipl >= 0) {
222 close(dev_ipl);
223 dev = -1;
225 return;
229 add_redirect_rule2(const char * ifname, const char * rhost,
230 unsigned short eport, const char * iaddr, unsigned short iport,
231 int proto, const char * desc, unsigned int timestamp)
233 struct ipnat ipnat;
234 struct ipfobj obj;
235 int r;
237 if (dev < 0) {
238 syslog(LOG_ERR, "%s not open", IPNAT_NAME);
239 return -1;
242 memset(&obj, 0, sizeof(obj));
243 memset(&ipnat, 0, sizeof(ipnat));
245 ipnat.in_redir = NAT_REDIRECT;
246 #if IPFILTER_VERSION >= 5000000
247 ipnat.in_pr[0] = proto;
248 ipnat.in_pr[1] = proto;
249 #else
250 ipnat.in_p = proto;
251 #endif
252 if (proto == IPPROTO_TCP)
253 ipnat.in_flags = IPN_TCP;
254 if (proto == IPPROTO_UDP)
255 ipnat.in_flags = IPN_UDP;
256 ipnat.in_dcmp = FR_EQUAL;
257 #if IPFILTER_VERSION >= 5000000
258 ipnat.in_dpmin = htons(eport);
259 ipnat.in_dpmax = htons(eport);
260 ipnat.in_dpnext = htons(iport);
261 ipnat.in_v[0] = 4;
262 ipnat.in_v[1] = 4;
263 #else
264 ipnat.in_pmin = htons(eport);
265 ipnat.in_pmax = htons(eport);
266 ipnat.in_pnext = htons(iport);
267 ipnat.in_v = 4;
268 #endif
269 strlcpy(ipnat.in_tag.ipt_tag, group_name, IPFTAG_LEN);
271 #ifdef USE_IFNAME_IN_RULES
272 if (ifname) {
273 #if IPFILTER_VERSION >= 5000000
274 /* XXX check for stack overflow ! */
275 ipnat.in_ifnames[0] = 0;
276 ipnat.in_ifnames[1] = 0;
277 strlcpy(ipnat.in_names, ifname, IFNAMSIZ);
278 ipnat.in_namelen = strlen(ipnat.in_names) + 1;
279 #else
280 strlcpy(ipnat.in_ifnames[0], ifname, IFNAMSIZ);
281 strlcpy(ipnat.in_ifnames[1], ifname, IFNAMSIZ);
282 #endif
284 #endif
286 if(rhost && rhost[0] != '\0' && rhost[0] != '*')
288 #if IPFILTER_VERSION >= 5000000
289 inet_pton(AF_INET, rhost, &ipnat.in_nsrc.na_addr[0].in4); /* in_nsrcip */
290 ipnat.in_nsrc.na_addr[1].in4.s_addr = 0xffffffff; /* in_nsrcmsk */
291 #else
292 inet_pton(AF_INET, rhost, &ipnat.in_src[0].in4);
293 ipnat.in_src[1].in4.s_addr = 0xffffffff;
294 #endif
297 #if IPFILTER_VERSION >= 5000000
298 inet_pton(AF_INET, iaddr, &ipnat.in_ndst.na_addr[0].in4); /* in_ndstip */
299 ipnat.in_ndst.na_addr[1].in4.s_addr = 0xffffffff; /* in_ndstmsk */
300 #else
301 inet_pton(AF_INET, iaddr, &ipnat.in_in[0].in4);
302 ipnat.in_in[1].in4.s_addr = 0xffffffff;
303 #endif
305 obj.ipfo_rev = IPFILTER_VERSION;
306 obj.ipfo_size = sizeof(ipnat);
307 obj.ipfo_ptr = &ipnat;
308 obj.ipfo_type = IPFOBJ_IPNAT;
310 r = ioctl(dev, SIOCADNAT, &obj);
311 if (r == -1)
312 syslog(LOG_ERR, "ioctl(SIOCADNAT): %m");
313 else
314 add_redirect_desc(eport, proto, timestamp, desc);
315 return r;
318 /* get_redirect_rule()
319 * return value : 0 success (found)
320 * -1 = error or rule not found */
322 get_redirect_rule(const char * ifname, unsigned short eport, int proto,
323 char * iaddr, int iaddrlen, unsigned short * iport,
324 char * desc, int desclen,
325 char * rhost, int rhostlen,
326 unsigned int * timestamp,
327 u_int64_t * packets, u_int64_t * bytes)
329 ipfgeniter_t iter;
330 ipfobj_t obj;
331 ipnat_t ipn;
332 int r;
334 memset(&obj, 0, sizeof(obj));
335 obj.ipfo_rev = IPFILTER_VERSION;
336 obj.ipfo_type = IPFOBJ_GENITER;
337 obj.ipfo_size = sizeof(iter);
338 obj.ipfo_ptr = &iter;
340 iter.igi_type = IPFGENITER_IPNAT;
341 #if IPFILTER_VERSION > 4011300
342 iter.igi_nitems = 1;
343 #endif
344 iter.igi_data = &ipn;
346 if (dev < 0) {
347 syslog(LOG_ERR, "%s not open", IPNAT_NAME);
348 return -1;
351 r = -1;
352 do {
353 if (ioctl(dev, SIOCGENITER, &obj) == -1) {
354 syslog(LOG_ERR, "ioctl(dev, SIOCGENITER): %m");
355 break;
357 #if IPFILTER_VERSION >= 5000000
358 if (eport == ntohs(ipn.in_dpmin) &&
359 eport == ntohs(ipn.in_dpmax) &&
360 strcmp(ipn.in_tag.ipt_tag, group_name) == 0 &&
361 ipn.in_pr[0] == proto)
362 #else
363 if (eport == ntohs(ipn.in_pmin) &&
364 eport == ntohs(ipn.in_pmax) &&
365 strcmp(ipn.in_tag.ipt_tag, group_name) == 0 &&
366 ipn.in_p == proto)
367 #endif
369 strlcpy(desc, "", desclen);
370 if (packets != NULL)
371 *packets = 0;
372 if (bytes != NULL)
373 *bytes = 0;
374 if (iport != NULL)
375 #if IPFILTER_VERSION >= 5000000
376 *iport = ntohs(ipn.in_dpnext);
377 #else
378 *iport = ntohs(ipn.in_pnext);
379 #endif
380 if ((desc != NULL) && (timestamp != NULL))
381 get_redirect_desc(eport, proto, desc, desclen, timestamp);
382 if ((rhost != NULL) && (rhostlen > 0))
383 #if IPFILTER_VERSION >= 5000000
384 inet_ntop(AF_INET, &ipn.in_nsrc.na_addr[0].in4, rhost, rhostlen); /* in_nsrcip */
385 #else
386 inet_ntop(AF_INET, &ipn.in_src[0].in4, rhost, rhostlen);
387 #endif
388 #if IPFILTER_VERSION >= 5000000
389 inet_ntop(AF_INET, &ipn.in_ndst.na_addr[0].in4, iaddr, iaddrlen); /* in_ndstip */
390 #else
391 inet_ntop(AF_INET, &ipn.in_in[0].in4, iaddr, iaddrlen);
392 #endif
393 r = 0;
395 } while (ipn.in_next != NULL);
396 return r;
401 get_redirect_rule_by_index(int index,
402 char * ifname, unsigned short * eport,
403 char * iaddr, int iaddrlen, unsigned short * iport,
404 int * proto, char * desc, int desclen,
405 char * rhost, int rhostlen,
406 unsigned int * timestamp,
407 u_int64_t * packets, u_int64_t * bytes)
409 ipfgeniter_t iter;
410 ipfobj_t obj;
411 ipnat_t ipn;
412 int n, r;
414 if (index < 0)
415 return -1;
417 if (dev < 0) {
418 syslog(LOG_ERR, "%s not open", IPNAT_NAME);
419 return -1;
422 memset(&obj, 0, sizeof(obj));
423 obj.ipfo_rev = IPFILTER_VERSION;
424 obj.ipfo_ptr = &iter;
425 obj.ipfo_size = sizeof(iter);
426 obj.ipfo_type = IPFOBJ_GENITER;
428 iter.igi_type = IPFGENITER_IPNAT;
429 #if IPFILTER_VERSION > 4011300
430 iter.igi_nitems = 1;
431 #endif
432 iter.igi_data = &ipn;
434 n = 0;
435 r = -1;
436 do {
437 if (ioctl(dev, SIOCGENITER, &obj) == -1) {
438 syslog(LOG_ERR, "%s:ioctl(SIOCGENITER): %m",
439 "get_redirect_rule_by_index");
440 break;
443 if (strcmp(ipn.in_tag.ipt_tag, group_name) != 0)
444 continue;
446 if (index == n++) {
447 #if IPFILTER_VERSION >= 5000000
448 *proto = ipn.in_pr[0];
449 *eport = ntohs(ipn.in_dpmax);
450 *iport = ntohs(ipn.in_dpnext);
451 #else
452 *proto = ipn.in_p;
453 *eport = ntohs(ipn.in_pmax);
454 *iport = ntohs(ipn.in_pnext);
455 #endif
457 if (ifname)
458 #if IPFILTER_VERSION >= 5000000
459 strlcpy(ifname, ipn.in_names + ipn.in_ifnames[0], IFNAMSIZ);
460 #else
461 strlcpy(ifname, ipn.in_ifnames[0], IFNAMSIZ);
462 #endif
463 if (packets != NULL)
464 *packets = 0;
465 if (bytes != NULL)
466 *bytes = 0;
467 if ((desc != NULL) && (timestamp != NULL))
468 get_redirect_desc(*eport, *proto, desc, desclen, timestamp);
469 if ((rhost != NULL) && (rhostlen > 0))
470 #if IPFILTER_VERSION >= 5000000
471 inet_ntop(AF_INET, &ipn.in_nsrc.na_addr[0].in4, rhost, rhostlen); /* in_nsrcip */
472 #else
473 inet_ntop(AF_INET, &ipn.in_src[0].in4, rhost, rhostlen);
474 #endif
475 #if IPFILTER_VERSION >= 5000000
476 inet_ntop(AF_INET, &ipn.in_ndst.na_addr[0].in4, iaddr, iaddrlen); /* in_ndstip */
477 #else
478 inet_ntop(AF_INET, &ipn.in_in[0].in4, iaddr, iaddrlen);
479 #endif
480 r = 0;
482 } while (ipn.in_next != NULL);
483 return r;
486 static int
487 real_delete_redirect_rule(const char * ifname, unsigned short eport, int proto)
489 ipfgeniter_t iter;
490 ipfobj_t obj;
491 ipnat_t ipn;
492 int r;
494 memset(&obj, 0, sizeof(obj));
495 obj.ipfo_rev = IPFILTER_VERSION;
496 obj.ipfo_type = IPFOBJ_GENITER;
497 obj.ipfo_size = sizeof(iter);
498 obj.ipfo_ptr = &iter;
500 iter.igi_type = IPFGENITER_IPNAT;
501 #if IPFILTER_VERSION > 4011300
502 iter.igi_nitems = 1;
503 #endif
504 iter.igi_data = &ipn;
506 if (dev < 0) {
507 syslog(LOG_ERR, "%s not open", IPNAT_NAME);
508 return -1;
511 r = -1;
512 do {
513 if (ioctl(dev, SIOCGENITER, &obj) == -1) {
514 syslog(LOG_ERR, "%s:ioctl(SIOCGENITER): %m",
515 "delete_redirect_rule");
516 break;
518 #if IPFILTER_VERSION >= 5000000
519 if (eport == ntohs(ipn.in_dpmin) &&
520 eport == ntohs(ipn.in_dpmax) &&
521 strcmp(ipn.in_tag.ipt_tag, group_name) == 0 &&
522 ipn.in_pr[0] == proto)
523 #else
524 if (eport == ntohs(ipn.in_pmin) &&
525 eport == ntohs(ipn.in_pmax) &&
526 strcmp(ipn.in_tag.ipt_tag, group_name) == 0 &&
527 ipn.in_p == proto)
528 #endif
530 obj.ipfo_rev = IPFILTER_VERSION;
531 obj.ipfo_size = sizeof(ipn);
532 obj.ipfo_ptr = &ipn;
533 obj.ipfo_type = IPFOBJ_IPNAT;
534 r = ioctl(dev, SIOCRMNAT, &obj);
535 if (r == -1)
536 syslog(LOG_ERR, "%s:ioctl(SIOCRMNAT): %m",
537 "delete_redirect_rule");
538 /* Delete the desc even if the above failed */
539 del_redirect_desc(eport, proto);
540 break;
542 } while (ipn.in_next != NULL);
543 return r;
546 /* FIXME: For some reason, the iter isn't reset every other delete,
547 * so we attempt 2 deletes. */
549 delete_redirect_rule(const char * ifname, unsigned short eport, int proto)
551 int r;
553 r = real_delete_redirect_rule(ifname, eport, proto);
554 if (r == -1)
555 r = real_delete_redirect_rule(ifname, eport, proto);
556 return r;
559 /* thanks to Seth Mos for this function */
561 add_filter_rule2(const char * ifname, const char * rhost,
562 const char * iaddr, unsigned short eport, unsigned short iport,
563 int proto, const char * desc)
565 ipfobj_t obj;
566 frentry_t fr;
567 fripf_t ipffr;
568 int r;
570 if (dev_ipl < 0) {
571 syslog(LOG_ERR, "%s not open", IPL_NAME);
572 return -1;
575 memset(&obj, 0, sizeof(obj));
576 memset(&fr, 0, sizeof(fr));
577 memset(&ipffr, 0, sizeof(ipffr));
579 fr.fr_flags = FR_PASS|FR_KEEPSTATE|FR_QUICK|FR_INQUE;
580 if (GETFLAG(LOGPACKETSMASK))
581 fr.fr_flags |= FR_LOG|FR_LOGFIRST;
582 #if IPFILTER_VERSION >= 5000000
583 fr.fr_family = PF_INET;
584 #else
585 fr.fr_v = 4;
586 #endif
588 fr.fr_type = FR_T_IPF;
589 fr.fr_dun.fru_ipf = &ipffr;
590 fr.fr_dsize = sizeof(ipffr);
591 fr.fr_isc = (void *)-1;
593 fr.fr_proto = proto;
594 fr.fr_mproto = 0xff;
595 fr.fr_dcmp = FR_EQUAL;
596 fr.fr_dport = eport;
597 #ifdef USE_IFNAME_IN_RULES
598 if (ifname) {
599 #if IPFILTER_VERSION >= 5000000
600 /* XXX check for stack overflow ! */
601 fr.fr_ifnames[0] = fr.fr_namelen;
602 strlcpy(fr.fr_names + fr.fr_ifnames[0], ifname, IFNAMSIZ);
603 fr.fr_namelen += strlen(ifname) + 1;
604 #else
605 strlcpy(fr.fr_ifnames[0], ifname, IFNAMSIZ);
606 #endif
608 #endif
609 #if IPFILTER_VERSION >= 5000000
610 /* XXX check for stack overflow ! */
611 fr.fr_group = fr.fr_namelen;
612 strlcpy(fr.fr_names + fr.fr_group, group_name, FR_GROUPLEN);
613 fr.fr_namelen += strlen(group_name) + 1;
614 #else
615 strlcpy(fr.fr_group, group_name, sizeof(fr.fr_group));
616 #endif
618 if (proto == IPPROTO_TCP) {
619 fr.fr_tcpf = TH_SYN;
620 fr.fr_tcpfm = TH_SYN|TH_ACK|TH_RST|TH_FIN|TH_URG|TH_PUSH;
623 if(rhost && rhost[0] != '\0' && rhost[0] != '*')
625 inet_pton(AF_INET, rhost, &fr.fr_saddr);
626 fr.fr_smask = 0xffffffff;
629 inet_pton(AF_INET, iaddr, &fr.fr_daddr);
630 fr.fr_dmask = 0xffffffff;
632 obj.ipfo_rev = IPFILTER_VERSION;
633 obj.ipfo_ptr = &fr;
634 obj.ipfo_size = sizeof(fr);
636 r = ioctl(dev_ipl, SIOCINAFR, &obj);
637 if (r == -1) {
638 if (errno == ESRCH)
639 syslog(LOG_ERR,
640 "SIOCINAFR(missing 'head %s' rule?):%m",
641 group_name);
642 else
643 syslog(LOG_ERR, "SIOCINAFR:%m");
645 return r;
649 delete_filter_rule(const char * ifname, unsigned short eport, int proto)
651 ipfobj_t wobj, dobj;
652 ipfruleiter_t rule;
653 u_long darray[1000];
654 u_long array[1000];
655 friostat_t fio;
656 frentry_t *fp;
657 int r;
659 if (dev_ipl < 0) {
660 syslog(LOG_ERR, "%s not open", IPL_NAME);
661 return -1;
664 wobj.ipfo_rev = IPFILTER_VERSION;
665 wobj.ipfo_type = IPFOBJ_IPFSTAT;
666 wobj.ipfo_size = sizeof(fio);
667 wobj.ipfo_ptr = &fio;
669 if (ioctl(dev_ipl, SIOCGETFS, &wobj) == -1) {
670 syslog(LOG_ERR, "ioctl(SIOCGETFS): %m");
671 return -1;
674 wobj.ipfo_rev = IPFILTER_VERSION;
675 wobj.ipfo_ptr = &rule;
676 wobj.ipfo_size = sizeof(rule);
677 wobj.ipfo_type = IPFOBJ_IPFITER;
679 fp = (frentry_t *)array;
680 fp->fr_dun.fru_data = darray;
681 fp->fr_dsize = sizeof(darray);
683 rule.iri_inout = 0;
684 rule.iri_active = fio.f_active;
685 #if IPFILTER_VERSION > 4011300
686 rule.iri_nrules = 1;
687 rule.iri_v = 4;
688 #endif
689 rule.iri_rule = fp;
690 strlcpy(rule.iri_group, group_name, sizeof(rule.iri_group));
692 dobj.ipfo_rev = IPFILTER_VERSION;
693 dobj.ipfo_size = sizeof(*fp);
694 dobj.ipfo_type = IPFOBJ_FRENTRY;
696 r = -1;
697 do {
698 memset(array, 0xff, sizeof(array));
700 if (ioctl(dev_ipl, SIOCIPFITER, &wobj) == -1) {
701 syslog(LOG_ERR, "ioctl(SIOCIPFITER): %m");
702 break;
705 if (fp->fr_data != NULL)
706 fp->fr_data = (char *)fp + sizeof(*fp);
707 if ((fp->fr_type & ~FR_T_BUILTIN) == FR_T_IPF &&
708 fp->fr_dport == eport &&
709 fp->fr_proto == proto)
711 dobj.ipfo_ptr = fp;
713 r = ioctl(dev_ipl, SIOCRMAFR, &dobj);
714 if (r == -1)
715 syslog(LOG_ERR, "ioctl(SIOCRMAFR): %m");
716 break;
718 } while (fp->fr_next != NULL);
719 return r;
722 unsigned short *
723 get_portmappings_in_range(unsigned short startport, unsigned short endport,
724 int proto, unsigned int * number)
726 unsigned short *array, *array2;
727 unsigned int capacity;
728 unsigned short eport;
729 ipfgeniter_t iter;
730 ipfobj_t obj;
731 ipnat_t ipn;
733 *number = 0;
734 if (dev < 0) {
735 syslog(LOG_ERR, "%s not open", IPNAT_NAME);
736 return NULL;
738 capacity = 128;
739 array = calloc(capacity, sizeof(unsigned short));
740 if(!array)
742 syslog(LOG_ERR, "get_portmappings_in_range() : calloc error");
743 return NULL;
746 memset(&obj, 0, sizeof(obj));
747 obj.ipfo_rev = IPFILTER_VERSION;
748 obj.ipfo_ptr = &iter;
749 obj.ipfo_size = sizeof(iter);
750 obj.ipfo_type = IPFOBJ_GENITER;
752 iter.igi_type = IPFGENITER_IPNAT;
753 #if IPFILTER_VERSION > 4011300
754 iter.igi_nitems = 1;
755 #endif
756 iter.igi_data = &ipn;
758 do {
759 if (ioctl(dev, SIOCGENITER, &obj) == -1) {
760 syslog(LOG_ERR, "%s:ioctl(SIOCGENITER): %m",
761 "get_portmappings_in_range");
762 break;
765 if (strcmp(ipn.in_tag.ipt_tag, group_name) != 0)
766 continue;
768 #if IPFILTER_VERSION >= 5000000
769 eport = ntohs(ipn.in_dpmin);
770 if( (eport == ntohs(ipn.in_dpmax))
771 && (ipn.in_pr[0] == proto)
772 && (startport <= eport) && (eport <= endport) )
773 #else
774 eport = ntohs(ipn.in_pmin);
775 if( (eport == ntohs(ipn.in_pmax))
776 && (ipn.in_p == proto)
777 && (startport <= eport) && (eport <= endport) )
778 #endif
780 if(*number >= capacity)
782 /* need to increase the capacity of the array */
783 capacity += 128;
784 array2 = realloc(array, sizeof(unsigned short)*capacity);
785 if(!array2)
787 syslog(LOG_ERR, "get_portmappings_in_range() : realloc(%lu) error", sizeof(unsigned short)*capacity);
788 *number = 0;
789 free(array);
790 return NULL;
792 array = array2;
794 array[*number] = eport;
795 (*number)++;
797 } while (ipn.in_next != NULL);
798 return array;