1 /* $Id: ipfrdr.c,v 1.20 2020/05/10 22:26:04 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 */
7
8 #include <sys/param.h>
9 #include <sys/types.h>
10 #include <sys/file.h>
11 /*
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>
15 */
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>
45
46 #include <arpa/inet.h>
47
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>
61
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"
68
69 #include "../macros.h"
70
71 #ifndef __P
72 # ifdef __STDC__
73 # define __P(x) x
74 # else
75 # define __P(x) ()
76 # endif
77 #endif
78 #ifndef __STDC__
79 # undef const
80 # define const
81 #endif
82
83 #ifndef U_32_T
84 # define U_32_T 1
85 # if defined(__NetBSD__) || defined(__OpenBSD__) || defined(__FreeBSD__) || \
86 defined(__sgi)
87 typedef u_int32_t u_32_t;
88 # else
89 # if defined(__alpha__) || defined(__alpha) || defined(_LP64)
90 typedef unsigned int u_32_t;
91 # else
92 # if SOLARIS2 >= 6
93 typedef uint32_t u_32_t;
94 # else
95 typedef unsigned int u_32_t;
96 # endif
97 # endif
98 # endif /* __NetBSD__ || __OpenBSD__ || __FreeBSD__ || __sgi */
99 #endif /* U_32_T */
100
101
102 #if defined(__NetBSD__) || defined(__OpenBSD__) || \
103 (_BSDI_VERSION >= 199701) || (__FreeBSD_version >= 300000) || \
104 SOLARIS || defined(__sgi) || defined(__osf__) || defined(linux)
105 # include <stdarg.h>
106 typedef int (* ioctlfunc_t) __P((int, ioctlcmd_t, ...));
107 #else
108 typedef int (* ioctlfunc_t) __P((dev_t, ioctlcmd_t, void *));
109 #endif
110 typedef void (* addfunc_t) __P((int, ioctlfunc_t, void *));
111 typedef int (* copyfunc_t) __P((void *, void *, size_t));
112
113
114 /*
115 * SunOS4
116 */
117 #if defined(sun) && !defined(__SVR4) && !defined(__svr4__)
118 extern int ioctl __P((int, int, void *));
119 #endif
120
121 #include "../upnpglobalvars.h"
122
123 /* group name */
124 static const char group_name[] = "miniupnpd";
125
126 static int dev = -1;
127 static int dev_ipl = -1;
128
129 /* IPFilter cannot store redirection descriptions, so we use our
130 * own structure to store them */
131 struct rdr_desc {
132 struct rdr_desc * next;
133 unsigned short eport;
134 int proto;
135 unsigned int timestamp;
136 char str[];
137 };
138
139 /* pointer to the chained list where descriptions are stored */
140 static struct rdr_desc * rdr_desc_list;
141
142 static void
add_redirect_desc(unsigned short eport,int proto,unsigned int timestamp,const char * desc)143 add_redirect_desc(unsigned short eport, int proto,
144 unsigned int timestamp, const char * desc)
145 {
146 struct rdr_desc * p;
147 size_t l;
148
149 if (desc != NULL) {
150 l = strlen(desc) + 1;
151 p = malloc(sizeof(struct rdr_desc) + l);
152 if (p) {
153 p->next = rdr_desc_list;
154 p->eport = eport;
155 p->proto = proto;
156 p->timestamp = timestamp;
157 memcpy(p->str, desc, l);
158 rdr_desc_list = p;
159 }
160 }
161 }
162
163 static void
del_redirect_desc(unsigned short eport,int proto)164 del_redirect_desc(unsigned short eport, int proto)
165 {
166 struct rdr_desc * p, * last;
167
168 last = NULL;
169 for (p = rdr_desc_list; p; p = p->next) {
170 if(p->eport == eport && p->proto == proto) {
171 if (last == NULL)
172 rdr_desc_list = p->next;
173 else
174 last->next = p->next;
175 free(p);
176 return;
177 }
178 }
179 }
180
181 static void
get_redirect_desc(unsigned short eport,int proto,char * desc,int desclen,unsigned int * timestamp)182 get_redirect_desc(unsigned short eport, int proto, char * desc, int desclen, unsigned int * timestamp)
183 {
184 struct rdr_desc * p;
185
186 if (desc == NULL || desclen == 0)
187 return;
188 for (p = rdr_desc_list; p; p = p->next) {
189 if (p->eport == eport && p->proto == proto)
190 {
191 strncpy(desc, p->str, desclen);
192 *timestamp = p->timestamp;
193 return;
194 }
195 }
196 return;
197 }
198
init_redirect(void)199 int init_redirect(void)
200 {
201
202 dev = open(IPNAT_NAME, O_RDWR);
203 if (dev < 0) {
204 syslog(LOG_ERR, "open(\"%s\"): %m", IPNAT_NAME);
205 return -1;
206 }
207 dev_ipl = open(IPL_NAME, O_RDWR);
208 if (dev_ipl < 0) {
209 syslog(LOG_ERR, "open(\"%s\"): %m", IPL_NAME);
210 return -1;
211 }
212 return 0;
213 }
214
shutdown_redirect(void)215 void shutdown_redirect(void)
216 {
217
218 if (dev >= 0) {
219 close(dev);
220 dev = -1;
221 }
222 if (dev_ipl >= 0) {
223 close(dev_ipl);
224 dev = -1;
225 }
226 return;
227 }
228
229 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)230 add_redirect_rule2(const char * ifname, const char * rhost,
231 unsigned short eport, const char * iaddr, unsigned short iport,
232 int proto, const char * desc, unsigned int timestamp)
233 {
234 struct ipnat ipnat;
235 struct ipfobj obj;
236 int r;
237
238 if (dev < 0) {
239 syslog(LOG_ERR, "%s not open", IPNAT_NAME);
240 return -1;
241 }
242
243 memset(&obj, 0, sizeof(obj));
244 memset(&ipnat, 0, sizeof(ipnat));
245
246 ipnat.in_redir = NAT_REDIRECT;
247 #if IPFILTER_VERSION >= 5000000
248 ipnat.in_pr[0] = proto;
249 ipnat.in_pr[1] = proto;
250 #else
251 ipnat.in_p = proto;
252 #endif
253 if (proto == IPPROTO_TCP)
254 ipnat.in_flags = IPN_TCP;
255 if (proto == IPPROTO_UDP)
256 ipnat.in_flags = IPN_UDP;
257 ipnat.in_dcmp = FR_EQUAL;
258 #if IPFILTER_VERSION >= 5000000
259 ipnat.in_dpmin = htons(eport);
260 ipnat.in_dpmax = htons(eport);
261 ipnat.in_dpnext = htons(iport);
262 ipnat.in_v[0] = 4;
263 ipnat.in_v[1] = 4;
264 #else
265 ipnat.in_pmin = htons(eport);
266 ipnat.in_pmax = htons(eport);
267 ipnat.in_pnext = htons(iport);
268 ipnat.in_v = 4;
269 #endif
270 strlcpy(ipnat.in_tag.ipt_tag, group_name, IPFTAG_LEN);
271
272 #ifdef USE_IFNAME_IN_RULES
273 if (ifname) {
274 #if IPFILTER_VERSION >= 5000000
275 /* XXX check for stack overflow ! */
276 ipnat.in_ifnames[0] = 0;
277 ipnat.in_ifnames[1] = 0;
278 strlcpy(ipnat.in_names, ifname, IFNAMSIZ);
279 ipnat.in_namelen = strlen(ipnat.in_names) + 1;
280 #else
281 strlcpy(ipnat.in_ifnames[0], ifname, IFNAMSIZ);
282 strlcpy(ipnat.in_ifnames[1], ifname, IFNAMSIZ);
283 #endif
284 }
285 #endif
286
287 if(rhost && rhost[0] != '\0' && rhost[0] != '*')
288 {
289 #if IPFILTER_VERSION >= 5000000
290 inet_pton(AF_INET, rhost, &ipnat.in_nsrc.na_addr[0].in4); /* in_nsrcip */
291 ipnat.in_nsrc.na_addr[1].in4.s_addr = 0xffffffff; /* in_nsrcmsk */
292 #else
293 inet_pton(AF_INET, rhost, &ipnat.in_src[0].in4);
294 ipnat.in_src[1].in4.s_addr = 0xffffffff;
295 #endif
296 }
297
298 #if IPFILTER_VERSION >= 5000000
299 inet_pton(AF_INET, iaddr, &ipnat.in_ndst.na_addr[0].in4); /* in_ndstip */
300 ipnat.in_ndst.na_addr[1].in4.s_addr = 0xffffffff; /* in_ndstmsk */
301 #else
302 inet_pton(AF_INET, iaddr, &ipnat.in_in[0].in4);
303 ipnat.in_in[1].in4.s_addr = 0xffffffff;
304 #endif
305
306 obj.ipfo_rev = IPFILTER_VERSION;
307 obj.ipfo_size = sizeof(ipnat);
308 obj.ipfo_ptr = &ipnat;
309 obj.ipfo_type = IPFOBJ_IPNAT;
310
311 r = ioctl(dev, SIOCADNAT, &obj);
312 if (r == -1)
313 syslog(LOG_ERR, "ioctl(SIOCADNAT): %m");
314 else
315 add_redirect_desc(eport, proto, timestamp, desc);
316 return r;
317 }
318
319 /* get_redirect_rule()
320 * return value : 0 success (found)
321 * -1 = error or rule not found */
322 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)323 get_redirect_rule(const char * ifname, unsigned short eport, int proto,
324 char * iaddr, int iaddrlen, unsigned short * iport,
325 char * desc, int desclen,
326 char * rhost, int rhostlen,
327 unsigned int * timestamp,
328 u_int64_t * packets, u_int64_t * bytes)
329 {
330 ipfgeniter_t iter;
331 ipfobj_t obj;
332 ipnat_t ipn;
333 int r;
334 UNUSED(ifname);
335
336 memset(&obj, 0, sizeof(obj));
337 obj.ipfo_rev = IPFILTER_VERSION;
338 obj.ipfo_type = IPFOBJ_GENITER;
339 obj.ipfo_size = sizeof(iter);
340 obj.ipfo_ptr = &iter;
341
342 iter.igi_type = IPFGENITER_IPNAT;
343 #if IPFILTER_VERSION > 4011300
344 iter.igi_nitems = 1;
345 #endif
346 iter.igi_data = &ipn;
347
348 if (dev < 0) {
349 syslog(LOG_ERR, "%s not open", IPNAT_NAME);
350 return -1;
351 }
352
353 r = -1;
354 do {
355 if (ioctl(dev, SIOCGENITER, &obj) == -1) {
356 syslog(LOG_ERR, "ioctl(dev, SIOCGENITER): %m");
357 break;
358 }
359 #if IPFILTER_VERSION >= 5000000
360 if (eport == ntohs(ipn.in_dpmin) &&
361 eport == ntohs(ipn.in_dpmax) &&
362 strcmp(ipn.in_tag.ipt_tag, group_name) == 0 &&
363 ipn.in_pr[0] == proto)
364 #else
365 if (eport == ntohs(ipn.in_pmin) &&
366 eport == ntohs(ipn.in_pmax) &&
367 strcmp(ipn.in_tag.ipt_tag, group_name) == 0 &&
368 ipn.in_p == proto)
369 #endif
370 {
371 strlcpy(desc, "", desclen);
372 if (packets != NULL)
373 *packets = 0;
374 if (bytes != NULL)
375 *bytes = 0;
376 if (iport != NULL)
377 #if IPFILTER_VERSION >= 5000000
378 *iport = ntohs(ipn.in_dpnext);
379 #else
380 *iport = ntohs(ipn.in_pnext);
381 #endif
382 if ((desc != NULL) && (timestamp != NULL))
383 get_redirect_desc(eport, proto, desc, desclen, timestamp);
384 if ((rhost != NULL) && (rhostlen > 0))
385 #if IPFILTER_VERSION >= 5000000
386 inet_ntop(AF_INET, &ipn.in_nsrc.na_addr[0].in4, rhost, rhostlen); /* in_nsrcip */
387 #else
388 inet_ntop(AF_INET, &ipn.in_src[0].in4, rhost, rhostlen);
389 #endif
390 #if IPFILTER_VERSION >= 5000000
391 inet_ntop(AF_INET, &ipn.in_ndst.na_addr[0].in4, iaddr, iaddrlen); /* in_ndstip */
392 #else
393 inet_ntop(AF_INET, &ipn.in_in[0].in4, iaddr, iaddrlen);
394 #endif
395 r = 0;
396 }
397 } while (ipn.in_next != NULL);
398 return r;
399 }
400
401
402 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)403 get_redirect_rule_by_index(int index,
404 char * ifname, unsigned short * eport,
405 char * iaddr, int iaddrlen, unsigned short * iport,
406 int * proto, char * desc, int desclen,
407 char * rhost, int rhostlen,
408 unsigned int * timestamp,
409 u_int64_t * packets, u_int64_t * bytes)
410 {
411 ipfgeniter_t iter;
412 ipfobj_t obj;
413 ipnat_t ipn;
414 int n, r;
415
416 if (index < 0)
417 return -1;
418
419 if (dev < 0) {
420 syslog(LOG_ERR, "%s not open", IPNAT_NAME);
421 return -1;
422 }
423
424 memset(&obj, 0, sizeof(obj));
425 obj.ipfo_rev = IPFILTER_VERSION;
426 obj.ipfo_ptr = &iter;
427 obj.ipfo_size = sizeof(iter);
428 obj.ipfo_type = IPFOBJ_GENITER;
429
430 iter.igi_type = IPFGENITER_IPNAT;
431 #if IPFILTER_VERSION > 4011300
432 iter.igi_nitems = 1;
433 #endif
434 iter.igi_data = &ipn;
435
436 n = 0;
437 r = -1;
438 do {
439 if (ioctl(dev, SIOCGENITER, &obj) == -1) {
440 syslog(LOG_ERR, "%s:ioctl(SIOCGENITER): %m",
441 "get_redirect_rule_by_index");
442 break;
443 }
444
445 if (strcmp(ipn.in_tag.ipt_tag, group_name) != 0)
446 continue;
447
448 if (index == n++) {
449 #if IPFILTER_VERSION >= 5000000
450 *proto = ipn.in_pr[0];
451 *eport = ntohs(ipn.in_dpmax);
452 *iport = ntohs(ipn.in_dpnext);
453 #else
454 *proto = ipn.in_p;
455 *eport = ntohs(ipn.in_pmax);
456 *iport = ntohs(ipn.in_pnext);
457 #endif
458
459 if (ifname)
460 #if IPFILTER_VERSION >= 5000000
461 strlcpy(ifname, ipn.in_names + ipn.in_ifnames[0], IFNAMSIZ);
462 #else
463 strlcpy(ifname, ipn.in_ifnames[0], IFNAMSIZ);
464 #endif
465 if (packets != NULL)
466 *packets = 0;
467 if (bytes != NULL)
468 *bytes = 0;
469 if ((desc != NULL) && (timestamp != NULL))
470 get_redirect_desc(*eport, *proto, desc, desclen, timestamp);
471 if ((rhost != NULL) && (rhostlen > 0))
472 #if IPFILTER_VERSION >= 5000000
473 inet_ntop(AF_INET, &ipn.in_nsrc.na_addr[0].in4, rhost, rhostlen); /* in_nsrcip */
474 #else
475 inet_ntop(AF_INET, &ipn.in_src[0].in4, rhost, rhostlen);
476 #endif
477 #if IPFILTER_VERSION >= 5000000
478 inet_ntop(AF_INET, &ipn.in_ndst.na_addr[0].in4, iaddr, iaddrlen); /* in_ndstip */
479 #else
480 inet_ntop(AF_INET, &ipn.in_in[0].in4, iaddr, iaddrlen);
481 #endif
482 r = 0;
483 }
484 } while (ipn.in_next != NULL);
485 return r;
486 }
487
488 static int
real_delete_redirect_rule(const char * ifname,unsigned short eport,int proto)489 real_delete_redirect_rule(const char * ifname, unsigned short eport, int proto)
490 {
491 ipfgeniter_t iter;
492 ipfobj_t obj;
493 ipnat_t ipn;
494 int r;
495 UNUSED(ifname);
496
497 memset(&obj, 0, sizeof(obj));
498 obj.ipfo_rev = IPFILTER_VERSION;
499 obj.ipfo_type = IPFOBJ_GENITER;
500 obj.ipfo_size = sizeof(iter);
501 obj.ipfo_ptr = &iter;
502
503 iter.igi_type = IPFGENITER_IPNAT;
504 #if IPFILTER_VERSION > 4011300
505 iter.igi_nitems = 1;
506 #endif
507 iter.igi_data = &ipn;
508
509 if (dev < 0) {
510 syslog(LOG_ERR, "%s not open", IPNAT_NAME);
511 return -1;
512 }
513
514 r = -1;
515 do {
516 if (ioctl(dev, SIOCGENITER, &obj) == -1) {
517 syslog(LOG_ERR, "%s:ioctl(SIOCGENITER): %m",
518 "delete_redirect_rule");
519 break;
520 }
521 #if IPFILTER_VERSION >= 5000000
522 if (eport == ntohs(ipn.in_dpmin) &&
523 eport == ntohs(ipn.in_dpmax) &&
524 strcmp(ipn.in_tag.ipt_tag, group_name) == 0 &&
525 ipn.in_pr[0] == proto)
526 #else
527 if (eport == ntohs(ipn.in_pmin) &&
528 eport == ntohs(ipn.in_pmax) &&
529 strcmp(ipn.in_tag.ipt_tag, group_name) == 0 &&
530 ipn.in_p == proto)
531 #endif
532 {
533 obj.ipfo_rev = IPFILTER_VERSION;
534 obj.ipfo_size = sizeof(ipn);
535 obj.ipfo_ptr = &ipn;
536 obj.ipfo_type = IPFOBJ_IPNAT;
537 r = ioctl(dev, SIOCRMNAT, &obj);
538 if (r == -1)
539 syslog(LOG_ERR, "%s:ioctl(SIOCRMNAT): %m",
540 "delete_redirect_rule");
541 /* Delete the desc even if the above failed */
542 del_redirect_desc(eport, proto);
543 break;
544 }
545 } while (ipn.in_next != NULL);
546 return r;
547 }
548
549 /* FIXME: For some reason, the iter isn't reset every other delete,
550 * so we attempt 2 deletes. */
551 int
delete_redirect_rule(const char * ifname,unsigned short eport,int proto)552 delete_redirect_rule(const char * ifname, unsigned short eport, int proto)
553 {
554 int r;
555
556 r = real_delete_redirect_rule(ifname, eport, proto);
557 if (r == -1)
558 r = real_delete_redirect_rule(ifname, eport, proto);
559 return r;
560 }
561
562 /* thanks to Seth Mos for this function */
563 int
add_filter_rule2(const char * ifname,const char * rhost,const char * iaddr,unsigned short eport,unsigned short iport,int proto,const char * desc)564 add_filter_rule2(const char * ifname, const char * rhost,
565 const char * iaddr, unsigned short eport, unsigned short iport,
566 int proto, const char * desc)
567 {
568 ipfobj_t obj;
569 frentry_t fr;
570 fripf_t ipffr;
571 int r;
572 UNUSED(ifname); UNUSED(desc);
573 UNUSED(iport);
574
575 if (dev_ipl < 0) {
576 syslog(LOG_ERR, "%s not open", IPL_NAME);
577 return -1;
578 }
579
580 memset(&obj, 0, sizeof(obj));
581 memset(&fr, 0, sizeof(fr));
582 memset(&ipffr, 0, sizeof(ipffr));
583
584 fr.fr_flags = FR_PASS|FR_KEEPSTATE|FR_QUICK|FR_INQUE;
585 if (GETFLAG(LOGPACKETSMASK))
586 fr.fr_flags |= FR_LOG|FR_LOGFIRST;
587 #if IPFILTER_VERSION >= 5000000
588 fr.fr_family = PF_INET;
589 #else
590 fr.fr_v = 4;
591 #endif
592
593 fr.fr_type = FR_T_IPF;
594 fr.fr_dun.fru_ipf = &ipffr;
595 fr.fr_dsize = sizeof(ipffr);
596 fr.fr_isc = (void *)-1;
597
598 fr.fr_proto = proto;
599 fr.fr_mproto = 0xff;
600 fr.fr_dcmp = FR_EQUAL;
601 fr.fr_dport = eport;
602 #ifdef USE_IFNAME_IN_RULES
603 if (ifname) {
604 #if IPFILTER_VERSION >= 5000000
605 /* XXX check for stack overflow ! */
606 fr.fr_ifnames[0] = fr.fr_namelen;
607 strlcpy(fr.fr_names + fr.fr_ifnames[0], ifname, IFNAMSIZ);
608 fr.fr_namelen += strlen(ifname) + 1;
609 #else
610 strlcpy(fr.fr_ifnames[0], ifname, IFNAMSIZ);
611 #endif
612 }
613 #endif
614 #if IPFILTER_VERSION >= 5000000
615 /* XXX check for stack overflow ! */
616 fr.fr_group = fr.fr_namelen;
617 strlcpy(fr.fr_names + fr.fr_group, group_name, FR_GROUPLEN);
618 fr.fr_namelen += strlen(group_name) + 1;
619 #else
620 strlcpy(fr.fr_group, group_name, sizeof(fr.fr_group));
621 #endif
622
623 if (proto == IPPROTO_TCP) {
624 fr.fr_tcpf = TH_SYN;
625 fr.fr_tcpfm = TH_SYN|TH_ACK|TH_RST|TH_FIN|TH_URG|TH_PUSH;
626 }
627
628 if(rhost && rhost[0] != '\0' && rhost[0] != '*')
629 {
630 inet_pton(AF_INET, rhost, &fr.fr_saddr);
631 fr.fr_smask = 0xffffffff;
632 }
633
634 inet_pton(AF_INET, iaddr, &fr.fr_daddr);
635 fr.fr_dmask = 0xffffffff;
636
637 obj.ipfo_rev = IPFILTER_VERSION;
638 obj.ipfo_ptr = &fr;
639 obj.ipfo_size = sizeof(fr);
640
641 r = ioctl(dev_ipl, SIOCINAFR, &obj);
642 if (r == -1) {
643 if (errno == ESRCH)
644 syslog(LOG_ERR,
645 "SIOCINAFR(missing 'head %s' rule?):%m",
646 group_name);
647 else
648 syslog(LOG_ERR, "SIOCINAFR:%m");
649 }
650 return r;
651 }
652
653 int
delete_filter_rule(const char * ifname,unsigned short eport,int proto)654 delete_filter_rule(const char * ifname, unsigned short eport, int proto)
655 {
656 ipfobj_t wobj, dobj;
657 ipfruleiter_t rule;
658 u_long darray[1000];
659 u_long array[1000];
660 friostat_t fio;
661 frentry_t *fp;
662 int r;
663 UNUSED(ifname);
664
665 if (dev_ipl < 0) {
666 syslog(LOG_ERR, "%s not open", IPL_NAME);
667 return -1;
668 }
669
670 wobj.ipfo_rev = IPFILTER_VERSION;
671 wobj.ipfo_type = IPFOBJ_IPFSTAT;
672 wobj.ipfo_size = sizeof(fio);
673 wobj.ipfo_ptr = &fio;
674
675 if (ioctl(dev_ipl, SIOCGETFS, &wobj) == -1) {
676 syslog(LOG_ERR, "ioctl(SIOCGETFS): %m");
677 return -1;
678 }
679
680 wobj.ipfo_rev = IPFILTER_VERSION;
681 wobj.ipfo_ptr = &rule;
682 wobj.ipfo_size = sizeof(rule);
683 wobj.ipfo_type = IPFOBJ_IPFITER;
684
685 fp = (frentry_t *)array;
686 fp->fr_dun.fru_data = darray;
687 fp->fr_dsize = sizeof(darray);
688
689 rule.iri_inout = 0;
690 rule.iri_active = fio.f_active;
691 #if IPFILTER_VERSION > 4011300
692 rule.iri_nrules = 1;
693 rule.iri_v = 4;
694 #endif
695 rule.iri_rule = fp;
696 strlcpy(rule.iri_group, group_name, sizeof(rule.iri_group));
697
698 dobj.ipfo_rev = IPFILTER_VERSION;
699 dobj.ipfo_size = sizeof(*fp);
700 dobj.ipfo_type = IPFOBJ_FRENTRY;
701
702 r = -1;
703 do {
704 memset(array, 0xff, sizeof(array));
705
706 if (ioctl(dev_ipl, SIOCIPFITER, &wobj) == -1) {
707 syslog(LOG_ERR, "ioctl(SIOCIPFITER): %m");
708 break;
709 }
710
711 if (fp->fr_data != NULL)
712 fp->fr_data = (char *)fp + sizeof(*fp);
713 if ((fp->fr_type & ~FR_T_BUILTIN) == FR_T_IPF &&
714 fp->fr_dport == eport &&
715 fp->fr_proto == proto)
716 {
717 dobj.ipfo_ptr = fp;
718
719 r = ioctl(dev_ipl, SIOCRMAFR, &dobj);
720 if (r == -1)
721 syslog(LOG_ERR, "ioctl(SIOCRMAFR): %m");
722 break;
723 }
724 } while (fp->fr_next != NULL);
725 return r;
726 }
727
728 unsigned short *
get_portmappings_in_range(unsigned short startport,unsigned short endport,int proto,unsigned int * number)729 get_portmappings_in_range(unsigned short startport, unsigned short endport,
730 int proto, unsigned int * number)
731 {
732 unsigned short *array, *array2;
733 unsigned int capacity;
734 unsigned short eport;
735 ipfgeniter_t iter;
736 ipfobj_t obj;
737 ipnat_t ipn;
738
739 *number = 0;
740 if (dev < 0) {
741 syslog(LOG_ERR, "%s not open", IPNAT_NAME);
742 return NULL;
743 }
744 capacity = 128;
745 array = calloc(capacity, sizeof(unsigned short));
746 if(!array)
747 {
748 syslog(LOG_ERR, "get_portmappings_in_range() : calloc error");
749 return NULL;
750 }
751
752 memset(&obj, 0, sizeof(obj));
753 obj.ipfo_rev = IPFILTER_VERSION;
754 obj.ipfo_ptr = &iter;
755 obj.ipfo_size = sizeof(iter);
756 obj.ipfo_type = IPFOBJ_GENITER;
757
758 iter.igi_type = IPFGENITER_IPNAT;
759 #if IPFILTER_VERSION > 4011300
760 iter.igi_nitems = 1;
761 #endif
762 iter.igi_data = &ipn;
763
764 do {
765 if (ioctl(dev, SIOCGENITER, &obj) == -1) {
766 syslog(LOG_ERR, "%s:ioctl(SIOCGENITER): %m",
767 "get_portmappings_in_range");
768 break;
769 }
770
771 if (strcmp(ipn.in_tag.ipt_tag, group_name) != 0)
772 continue;
773
774 #if IPFILTER_VERSION >= 5000000
775 eport = ntohs(ipn.in_dpmin);
776 if( (eport == ntohs(ipn.in_dpmax))
777 && (ipn.in_pr[0] == proto)
778 && (startport <= eport) && (eport <= endport) )
779 #else
780 eport = ntohs(ipn.in_pmin);
781 if( (eport == ntohs(ipn.in_pmax))
782 && (ipn.in_p == proto)
783 && (startport <= eport) && (eport <= endport) )
784 #endif
785 {
786 if(*number >= capacity)
787 {
788 /* need to increase the capacity of the array */
789 capacity += 128;
790 array2 = realloc(array, sizeof(unsigned short)*capacity);
791 if(!array2)
792 {
793 syslog(LOG_ERR, "get_portmappings_in_range() : realloc(%lu) error", sizeof(unsigned short)*capacity);
794 *number = 0;
795 free(array);
796 return NULL;
797 }
798 array = array2;
799 }
800 array[*number] = eport;
801 (*number)++;
802 }
803 } while (ipn.in_next != NULL);
804 return array;
805 }
806
807 /* update the port mapping internal port, description and timestamp */
808 int
update_portmapping(const char * ifname,unsigned short eport,int proto,unsigned short iport,const char * desc,unsigned int timestamp)809 update_portmapping(const char * ifname, unsigned short eport, int proto,
810 unsigned short iport, const char * desc,
811 unsigned int timestamp)
812 {
813 UNUSED(ifname); UNUSED(eport); UNUSED(proto);
814 UNUSED(iport); UNUSED(desc); UNUSED(timestamp);
815 /* TODO: implement update_portmapping() */
816 syslog(LOG_ERR, __FILE__ " update_portmapping() is not implemented");
817 return -1;
818 }
819
820 /* update the port mapping description and timestamp */
821 int
update_portmapping_desc_timestamp(const char * ifname,unsigned short eport,int proto,const char * desc,unsigned int timestamp)822 update_portmapping_desc_timestamp(const char * ifname,
823 unsigned short eport, int proto,
824 const char * desc, unsigned int timestamp)
825 {
826 UNUSED(ifname);
827 del_redirect_desc(eport, proto);
828 add_redirect_desc(eport,proto, timestamp, desc);
829 return 0;
830 }
831
832