Annotation of embedaddon/miniupnpd/ipf/ipfrdr.c, revision 1.1.1.1
1.1 misho 1: /* $Id: ipfrdr.c,v 1.11 2009/10/10 18:34:39 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:
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
81:
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 */
99:
100:
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));
111:
112:
113: /*
114: * SunOS4
115: */
116: #if defined(sun) && !defined(__SVR4) && !defined(__svr4__)
117: extern int ioctl __P((int, int, void *));
118: #endif
119:
120: #include "../upnpglobalvars.h"
121:
122: /* group name */
123: static const char group_name[] = "miniupnpd";
124:
125: static int dev = -1;
126: static int dev_ipl = -1;
127:
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: char str[];
135: };
136:
137: /* pointer to the chained list where descriptions are stored */
138: static struct rdr_desc * rdr_desc_list;
139:
140: static void
141: add_redirect_desc(unsigned short eport, int proto, const char * desc)
142: {
143: struct rdr_desc * p;
144: size_t l;
145:
146: if (desc != NULL) {
147: l = strlen(desc) + 1;
148: p = malloc(sizeof(struct rdr_desc) + l);
149: if (p) {
150: p->next = rdr_desc_list;
151: p->eport = eport;
152: p->proto = proto;
153: memcpy(p->str, desc, l);
154: rdr_desc_list = p;
155: }
156: }
157: }
158:
159: static void
160: del_redirect_desc(unsigned short eport, int proto)
161: {
162: struct rdr_desc * p, * last;
163:
164: last = NULL;
165: for (p = rdr_desc_list; p; p = p->next) {
166: if(p->eport == eport && p->proto == proto) {
167: if (last == NULL)
168: rdr_desc_list = p->next;
169: else
170: last->next = p->next;
171: free(p);
172: return;
173: }
174: }
175: }
176:
177: static void
178: get_redirect_desc(unsigned short eport, int proto, char * desc, int desclen)
179: {
180: struct rdr_desc * p;
181:
182: if (desc == NULL || desclen == 0)
183: return;
184: for (p = rdr_desc_list; p; p = p->next) {
185: if (p->eport == eport && p->proto == proto)
186: {
187: strncpy(desc, p->str, desclen);
188: return;
189: }
190: }
191: }
192:
193: int init_redirect(void)
194: {
195:
196: dev = open(IPNAT_NAME, O_RDWR);
197: if (dev < 0) {
198: syslog(LOG_ERR, "open(\"%s\"): %m", IPNAT_NAME);
199: return -1;
200: }
201: dev_ipl = open(IPL_NAME, O_RDWR);
202: if (dev_ipl < 0) {
203: syslog(LOG_ERR, "open(\"%s\"): %m", IPL_NAME);
204: return -1;
205: }
206: return 0;
207: }
208:
209: void shutdown_redirect(void)
210: {
211:
212: if (dev >= 0) {
213: close(dev);
214: dev = -1;
215: }
216: if (dev_ipl >= 0) {
217: close(dev_ipl);
218: dev = -1;
219: }
220: return;
221: }
222:
223: int
224: add_redirect_rule2(const char * ifname, unsigned short eport,
225: const char * iaddr, unsigned short iport, int proto,
226: const char * desc)
227: {
228: struct ipnat ipnat;
229: struct ipfobj obj;
230: int r;
231:
232: if (dev < 0) {
233: syslog(LOG_ERR, "%s not open", IPNAT_NAME);
234: return -1;
235: }
236:
237: memset(&obj, 0, sizeof(obj));
238: memset(&ipnat, 0, sizeof(ipnat));
239:
240: ipnat.in_redir = NAT_REDIRECT;
241: ipnat.in_p = proto;
242: if (proto == IPPROTO_TCP)
243: ipnat.in_flags = IPN_TCP;
244: if (proto == IPPROTO_UDP)
245: ipnat.in_flags = IPN_UDP;
246: ipnat.in_dcmp = FR_EQUAL;
247: ipnat.in_pmin = htons(eport);
248: ipnat.in_pmax = htons(eport);
249: ipnat.in_pnext = htons(iport);
250: ipnat.in_v = 4;
251: strlcpy(ipnat.in_tag.ipt_tag, group_name, IPFTAG_LEN);
252:
253: #ifdef USE_IFNAME_IN_RULES
254: if (ifname) {
255: strlcpy(ipnat.in_ifnames[0], ifname, IFNAMSIZ);
256: strlcpy(ipnat.in_ifnames[1], ifname, IFNAMSIZ);
257: }
258: #endif
259:
260: inet_pton(AF_INET, iaddr, &ipnat.in_in[0].in4);
261: ipnat.in_in[1].in4.s_addr = 0xffffffff;
262:
263: obj.ipfo_rev = IPFILTER_VERSION;
264: obj.ipfo_size = sizeof(ipnat);
265: obj.ipfo_ptr = &ipnat;
266: obj.ipfo_type = IPFOBJ_IPNAT;
267:
268: r = ioctl(dev, SIOCADNAT, &obj);
269: if (r == -1)
270: syslog(LOG_ERR, "ioctl(SIOCADNAT): %m");
271: else
272: add_redirect_desc(eport, proto, desc);
273: return r;
274: }
275:
276: /* get_redirect_rule()
277: * return value : 0 success (found)
278: * -1 = error or rule not found */
279: int
280: get_redirect_rule(const char * ifname, unsigned short eport, int proto,
281: char * iaddr, int iaddrlen, unsigned short * iport,
282: char * desc, int desclen,
283: u_int64_t * packets, u_int64_t * bytes)
284: {
285: ipfgeniter_t iter;
286: ipfobj_t obj;
287: ipnat_t ipn;
288: int r;
289:
290: memset(&obj, 0, sizeof(obj));
291: obj.ipfo_rev = IPFILTER_VERSION;
292: obj.ipfo_type = IPFOBJ_GENITER;
293: obj.ipfo_size = sizeof(iter);
294: obj.ipfo_ptr = &iter;
295:
296: iter.igi_type = IPFGENITER_IPNAT;
297: #if IPFILTER_VERSION > 4011300
298: iter.igi_nitems = 1;
299: #endif
300: iter.igi_data = &ipn;
301:
302: if (dev < 0) {
303: syslog(LOG_ERR, "%s not open", IPNAT_NAME);
304: return -1;
305: }
306:
307: r = -1;
308: do {
309: if (ioctl(dev, SIOCGENITER, &obj) == -1) {
310: syslog(LOG_ERR, "ioctl(dev, SIOCGENITER): %m");
311: break;
312: }
313: if (eport == ntohs(ipn.in_pmin) &&
314: eport == ntohs(ipn.in_pmax) &&
315: strcmp(ipn.in_tag.ipt_tag, group_name) == 0 &&
316: ipn.in_p == proto)
317: {
318: strlcpy(desc, "", desclen);
319: if (packets != NULL)
320: *packets = 0;
321: if (bytes != NULL)
322: *bytes = 0;
323: if (iport != NULL)
324: *iport = ntohs(ipn.in_pnext);
325: if (desc != NULL)
326: get_redirect_desc(eport, proto, desc, desclen);
327: inet_ntop(AF_INET, &ipn.in_in[0].in4, iaddr, iaddrlen);
328: r = 0;
329: }
330: } while (ipn.in_next != NULL);
331: return r;
332: }
333:
334:
335: int
336: get_redirect_rule_by_index(int index,
337: char * ifname, unsigned short * eport,
338: char * iaddr, int iaddrlen, unsigned short * iport,
339: int * proto, char * desc, int desclen,
340: u_int64_t * packets, u_int64_t * bytes)
341: {
342: ipfgeniter_t iter;
343: ipfobj_t obj;
344: ipnat_t ipn;
345: int n, r;
346:
347: if (index < 0)
348: return -1;
349:
350: if (dev < 0) {
351: syslog(LOG_ERR, "%s not open", IPNAT_NAME);
352: return -1;
353: }
354:
355: memset(&obj, 0, sizeof(obj));
356: obj.ipfo_rev = IPFILTER_VERSION;
357: obj.ipfo_ptr = &iter;
358: obj.ipfo_size = sizeof(iter);
359: obj.ipfo_type = IPFOBJ_GENITER;
360:
361: iter.igi_type = IPFGENITER_IPNAT;
362: #if IPFILTER_VERSION > 4011300
363: iter.igi_nitems = 1;
364: #endif
365: iter.igi_data = &ipn;
366:
367: n = 0;
368: r = -1;
369: do {
370: if (ioctl(dev, SIOCGENITER, &obj) == -1) {
371: syslog(LOG_ERR, "%s:ioctl(SIOCGENITER): %m",
372: "get_redirect_rule_by_index");
373: break;
374: }
375:
376: if (strcmp(ipn.in_tag.ipt_tag, group_name) != 0)
377: continue;
378:
379: if (index == n++) {
380: *proto = ipn.in_p;
381: *eport = ntohs(ipn.in_pmax);
382: *iport = ntohs(ipn.in_pnext);
383:
384: if (ifname)
385: strlcpy(ifname, ipn.in_ifnames[0], IFNAMSIZ);
386: if (packets != NULL)
387: *packets = 0;
388: if (bytes != NULL)
389: *bytes = 0;
390: if (desc != NULL)
391: get_redirect_desc(*eport, *proto, desc, desclen);
392: inet_ntop(AF_INET, &ipn.in_in[0].in4, iaddr, iaddrlen);
393: r = 0;
394: }
395: } while (ipn.in_next != NULL);
396: return r;
397: }
398:
399: static int
400: real_delete_redirect_rule(const char * ifname, unsigned short eport, int proto)
401: {
402: ipfgeniter_t iter;
403: ipfobj_t obj;
404: ipnat_t ipn;
405: int r;
406:
407: memset(&obj, 0, sizeof(obj));
408: obj.ipfo_rev = IPFILTER_VERSION;
409: obj.ipfo_type = IPFOBJ_GENITER;
410: obj.ipfo_size = sizeof(iter);
411: obj.ipfo_ptr = &iter;
412:
413: iter.igi_type = IPFGENITER_IPNAT;
414: #if IPFILTER_VERSION > 4011300
415: iter.igi_nitems = 1;
416: #endif
417: iter.igi_data = &ipn;
418:
419: if (dev < 0) {
420: syslog(LOG_ERR, "%s not open", IPNAT_NAME);
421: return -1;
422: }
423:
424: r = -1;
425: do {
426: if (ioctl(dev, SIOCGENITER, &obj) == -1) {
427: syslog(LOG_ERR, "%s:ioctl(SIOCGENITER): %m",
428: "delete_redirect_rule");
429: break;
430: }
431: if (eport == ntohs(ipn.in_pmin) &&
432: eport == ntohs(ipn.in_pmax) &&
433: strcmp(ipn.in_tag.ipt_tag, group_name) == 0 &&
434: ipn.in_p == proto)
435: {
436: obj.ipfo_rev = IPFILTER_VERSION;
437: obj.ipfo_size = sizeof(ipn);
438: obj.ipfo_ptr = &ipn;
439: obj.ipfo_type = IPFOBJ_IPNAT;
440: r = ioctl(dev, SIOCRMNAT, &obj);
441: if (r == -1)
442: syslog(LOG_ERR, "%s:ioctl(SIOCRMNAT): %m",
443: "delete_redirect_rule");
444: /* Delete the desc even if the above failed */
445: del_redirect_desc(eport, proto);
446: break;
447: }
448: } while (ipn.in_next != NULL);
449: return r;
450: }
451:
452: /* FIXME: For some reason, the iter isn't reset every other delete,
453: * so we attempt 2 deletes. */
454: int
455: delete_redirect_rule(const char * ifname, unsigned short eport, int proto)
456: {
457: int r;
458:
459: r = real_delete_redirect_rule(ifname, eport, proto);
460: if (r == -1)
461: r = real_delete_redirect_rule(ifname, eport, proto);
462: return r;
463: }
464:
465: /* thanks to Seth Mos for this function */
466: int
467: add_filter_rule2(const char * ifname, const char * iaddr,
468: unsigned short eport, unsigned short iport,
469: int proto, const char * desc)
470: {
471: ipfobj_t obj;
472: frentry_t fr;
473: fripf_t ipffr;
474: int r;
475:
476: if (dev_ipl < 0) {
477: syslog(LOG_ERR, "%s not open", IPL_NAME);
478: return -1;
479: }
480:
481: memset(&obj, 0, sizeof(obj));
482: memset(&fr, 0, sizeof(fr));
483: memset(&ipffr, 0, sizeof(ipffr));
484:
485: fr.fr_flags = FR_PASS|FR_KEEPSTATE|FR_QUICK|FR_INQUE;
486: if (GETFLAG(LOGPACKETSMASK))
487: fr.fr_flags |= FR_LOG|FR_LOGFIRST;
488: fr.fr_v = 4;
489:
490: fr.fr_type = FR_T_IPF;
491: fr.fr_dun.fru_ipf = &ipffr;
492: fr.fr_dsize = sizeof(ipffr);
493: fr.fr_isc = (void *)-1;
494:
495: fr.fr_proto = proto;
496: fr.fr_mproto = 0xff;
497: fr.fr_dcmp = FR_EQUAL;
498: fr.fr_dport = eport;
499: #ifdef USE_IFNAME_IN_RULES
500: if (ifname)
501: strlcpy(fr.fr_ifnames[0], ifname, IFNAMSIZ);
502: #endif
503: strlcpy(fr.fr_group, group_name, sizeof(fr.fr_group));
504:
505: if (proto == IPPROTO_TCP) {
506: fr.fr_tcpf = TH_SYN;
507: fr.fr_tcpfm = TH_SYN|TH_ACK|TH_RST|TH_FIN|TH_URG|TH_PUSH;
508: }
509:
510: inet_pton(AF_INET, iaddr, &fr.fr_daddr);
511: fr.fr_dmask = 0xffffffff;
512:
513: obj.ipfo_rev = IPFILTER_VERSION;
514: obj.ipfo_ptr = &fr;
515: obj.ipfo_size = sizeof(fr);
516:
517: r = ioctl(dev_ipl, SIOCINAFR, &obj);
518: if (r == -1) {
519: if (errno == ESRCH)
520: syslog(LOG_ERR,
521: "SIOCINAFR(missing 'head %s' rule?):%m",
522: group_name);
523: else
524: syslog(LOG_ERR, "SIOCINAFR:%m");
525: }
526: return r;
527: }
528:
529: int
530: delete_filter_rule(const char * ifname, unsigned short eport, int proto)
531: {
532: ipfobj_t wobj, dobj;
533: ipfruleiter_t rule;
534: u_long darray[1000];
535: u_long array[1000];
536: friostat_t fio;
537: frentry_t *fp;
538: int r;
539:
540: if (dev_ipl < 0) {
541: syslog(LOG_ERR, "%s not open", IPL_NAME);
542: return -1;
543: }
544:
545: wobj.ipfo_rev = IPFILTER_VERSION;
546: wobj.ipfo_type = IPFOBJ_IPFSTAT;
547: wobj.ipfo_size = sizeof(fio);
548: wobj.ipfo_ptr = &fio;
549:
550: if (ioctl(dev_ipl, SIOCGETFS, &wobj) == -1) {
551: syslog(LOG_ERR, "ioctl(SIOCGETFS): %m");
552: return -1;
553: }
554:
555: wobj.ipfo_rev = IPFILTER_VERSION;
556: wobj.ipfo_ptr = &rule;
557: wobj.ipfo_size = sizeof(rule);
558: wobj.ipfo_type = IPFOBJ_IPFITER;
559:
560: fp = (frentry_t *)array;
561: fp->fr_dun.fru_data = darray;
562: fp->fr_dsize = sizeof(darray);
563:
564: rule.iri_inout = 0;
565: rule.iri_active = fio.f_active;
566: #if IPFILTER_VERSION > 4011300
567: rule.iri_nrules = 1;
568: rule.iri_v = 4;
569: #endif
570: rule.iri_rule = fp;
571: strlcpy(rule.iri_group, group_name, sizeof(rule.iri_group));
572:
573: dobj.ipfo_rev = IPFILTER_VERSION;
574: dobj.ipfo_size = sizeof(*fp);
575: dobj.ipfo_type = IPFOBJ_FRENTRY;
576:
577: r = -1;
578: do {
579: memset(array, 0xff, sizeof(array));
580:
581: if (ioctl(dev_ipl, SIOCIPFITER, &wobj) == -1) {
582: syslog(LOG_ERR, "ioctl(SIOCIPFITER): %m");
583: break;
584: }
585:
586: if (fp->fr_data != NULL)
587: fp->fr_data = (char *)fp + sizeof(*fp);
588: if ((fp->fr_type & ~FR_T_BUILTIN) == FR_T_IPF &&
589: fp->fr_dport == eport &&
590: fp->fr_proto == proto)
591: {
592: dobj.ipfo_ptr = fp;
593:
594: r = ioctl(dev_ipl, SIOCRMAFR, &dobj);
595: if (r == -1)
596: syslog(LOG_ERR, "ioctl(SIOCRMAFR): %m");
597: break;
598: }
599: } while (fp->fr_next != NULL);
600: return r;
601: }
602:
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>