Annotation of embedaddon/miniupnpd/pf/obsdrdr.c, revision 1.1.1.3
1.1.1.3 ! misho 1: /* $Id: obsdrdr.c,v 1.74 2012/05/01 09:20:43 nanard Exp $ */
1.1 misho 2: /* MiniUPnP project
3: * http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/
1.1.1.3 ! misho 4: * (c) 2006-2012 Thomas Bernard
1.1 misho 5: * This software is subject to the conditions detailed
6: * in the LICENCE file provided within the distribution */
7:
8: /*
9: * pf rules created (with ext_if = xl1)
10: * - OpenBSD up to version 4.6 :
11: * rdr pass on xl1 inet proto udp from any to any port = 54321 \
12: * label "test label" -> 192.168.0.141 port 12345
13: * or a rdr rule + a pass rule
14: *
15: * - OpenBSD starting from version 4.7
16: * match in on xl1 inet proto udp from any to any port 54321 \
17: * label "test label" rdr-to 192.168.0.141 port 12345
18: * or
19: * pass in quick on xl1 inet proto udp from any to any port 54321 \
20: * label "test label" rdr-to 192.168.0.141 port 12345
21: *
22: *
23: *
24: * Macros/#defines :
25: * - PF_ENABLE_FILTER_RULES
26: * If set, two rules are created : rdr + pass. Else a rdr/pass rule
27: * is created.
28: * - USE_IFNAME_IN_RULES
29: * If set the interface name is set in the rule.
30: * - PFRULE_INOUT_COUNTS
31: * Must be set with OpenBSD version 3.8 and up.
32: * - PFRULE_HAS_RTABLEID
33: * Must be set with OpenBSD version 4.0 and up.
34: * - PF_NEWSSTYLE
35: * Must be set with OpenBSD version 4.7 and up.
36: */
37:
38: #include <sys/types.h>
39: #include <sys/socket.h>
40: #include <sys/param.h>
41: #include <net/if.h>
42: #include <netinet/in.h>
43: #include <netinet/tcp.h>
44: #include <arpa/inet.h>
45: #ifdef __DragonFly__
46: #include <net/pf/pfvar.h>
47: #else
48: #include <net/pfvar.h>
49: #endif
50: #include <fcntl.h>
51: #include <sys/ioctl.h>
52: #include <unistd.h>
53: #include <string.h>
54: #include <syslog.h>
55: #include <stdio.h>
56: #include <stdlib.h>
57:
1.1.1.3 ! misho 58: #include "../macros.h"
1.1 misho 59: #include "../config.h"
60: #include "obsdrdr.h"
61: #include "../upnpglobalvars.h"
62:
1.1.1.2 misho 63: /* list too keep timestamps for port mappings having a lease duration */
64: struct timestamp_entry {
65: struct timestamp_entry * next;
66: unsigned int timestamp;
67: unsigned short eport;
68: short protocol;
69: };
70:
71: static struct timestamp_entry * timestamp_list = NULL;
72:
73: static unsigned int
74: get_timestamp(unsigned short eport, int proto)
75: {
76: struct timestamp_entry * e;
77: e = timestamp_list;
78: while(e) {
79: if(e->eport == eport && e->protocol == (short)proto)
80: return e->timestamp;
81: e = e->next;
82: }
83: return 0;
84: }
85:
86: static void
87: remove_timestamp_entry(unsigned short eport, int proto)
88: {
89: struct timestamp_entry * e;
90: struct timestamp_entry * * p;
91: p = ×tamp_list;
92: e = *p;
93: while(e) {
94: if(e->eport == eport && e->protocol == (short)proto) {
95: /* remove the entry */
96: *p = e->next;
97: free(e);
98: return;
99: }
100: p = &(e->next);
101: e = *p;
102: }
103: }
104:
1.1 misho 105: /* /dev/pf when opened */
1.1.1.3 ! misho 106: int dev = -1;
1.1 misho 107:
108: /* shutdown_redirect() :
109: * close the /dev/pf device */
110: void
111: shutdown_redirect(void)
112: {
113: if(close(dev)<0)
114: syslog(LOG_ERR, "close(\"/dev/pf\"): %m");
115: dev = -1;
116: }
117:
118: /* open the device */
119: int
120: init_redirect(void)
121: {
122: struct pf_status status;
123: if(dev>=0)
124: shutdown_redirect();
125: dev = open("/dev/pf", O_RDWR);
126: if(dev<0) {
127: syslog(LOG_ERR, "open(\"/dev/pf\"): %m");
128: return -1;
129: }
130: if(ioctl(dev, DIOCGETSTATUS, &status)<0) {
131: syslog(LOG_ERR, "DIOCGETSTATUS: %m");
132: return -1;
133: }
134: if(!status.running) {
135: syslog(LOG_ERR, "pf is disabled");
136: return -1;
137: }
138: return 0;
139: }
140:
141: #if TEST
142: /* for debug */
143: int
144: clear_redirect_rules(void)
145: {
146: struct pfioc_trans io;
147: struct pfioc_trans_e ioe;
148: if(dev<0) {
149: syslog(LOG_ERR, "pf device is not open");
150: return -1;
151: }
152: memset(&ioe, 0, sizeof(ioe));
153: io.size = 1;
154: io.esize = sizeof(ioe);
155: io.array = &ioe;
156: #ifndef PF_NEWSTYLE
157: ioe.rs_num = PF_RULESET_RDR;
158: #else
159: ioe.type = PF_TRANS_RULESET;
160: #endif
161: strlcpy(ioe.anchor, anchor_name, MAXPATHLEN);
162: if(ioctl(dev, DIOCXBEGIN, &io) < 0)
163: {
164: syslog(LOG_ERR, "ioctl(dev, DIOCXBEGIN, ...): %m");
165: goto error;
166: }
167: if(ioctl(dev, DIOCXCOMMIT, &io) < 0)
168: {
169: syslog(LOG_ERR, "ioctl(dev, DIOCXCOMMIT, ...): %m");
170: goto error;
171: }
172: return 0;
173: error:
174: return -1;
175: }
176: #endif
177:
178: /* add_redirect_rule2() :
179: * create a rdr rule */
180: int
1.1.1.2 misho 181: add_redirect_rule2(const char * ifname,
182: const char * rhost, unsigned short eport,
1.1 misho 183: const char * iaddr, unsigned short iport, int proto,
1.1.1.2 misho 184: const char * desc, unsigned int timestamp)
1.1 misho 185: {
186: int r;
187: struct pfioc_rule pcr;
188: #ifndef PF_NEWSTYLE
189: struct pfioc_pooladdr pp;
190: struct pf_pooladdr *a;
191: #endif
192: if(dev<0) {
193: syslog(LOG_ERR, "pf device is not open");
194: return -1;
195: }
196: r = 0;
197: memset(&pcr, 0, sizeof(pcr));
198: strlcpy(pcr.anchor, anchor_name, MAXPATHLEN);
199:
200: #ifndef PF_NEWSTYLE
201: memset(&pp, 0, sizeof(pp));
202: strlcpy(pp.anchor, anchor_name, MAXPATHLEN);
203: if(ioctl(dev, DIOCBEGINADDRS, &pp) < 0)
204: {
205: syslog(LOG_ERR, "ioctl(dev, DIOCBEGINADDRS, ...): %m");
206: r = -1;
207: }
208: else
209: {
210: pcr.pool_ticket = pp.ticket;
211: #else
212: if(1)
213: {
214: pcr.rule.direction = PF_IN;
1.1.1.3 ! misho 215: /*pcr.rule.src.addr.type = PF_ADDR_NONE;*/
1.1 misho 216: pcr.rule.src.addr.type = PF_ADDR_ADDRMASK;
217: pcr.rule.dst.addr.type = PF_ADDR_ADDRMASK;
218: pcr.rule.nat.addr.type = PF_ADDR_NONE;
219: pcr.rule.rdr.addr.type = PF_ADDR_ADDRMASK;
220: #endif
1.1.1.3 ! misho 221:
1.1 misho 222: pcr.rule.dst.port_op = PF_OP_EQ;
223: pcr.rule.dst.port[0] = htons(eport);
224: pcr.rule.dst.port[1] = htons(eport);
225: #ifndef PF_NEWSTYLE
226: pcr.rule.action = PF_RDR;
227: #ifndef PF_ENABLE_FILTER_RULES
228: pcr.rule.natpass = 1;
229: #else
230: pcr.rule.natpass = 0;
231: #endif
232: #else
233: #ifndef PF_ENABLE_FILTER_RULES
234: pcr.rule.action = PF_PASS;
235: #else
236: pcr.rule.action = PF_MATCH;
237: #endif
238: #endif
239: pcr.rule.af = AF_INET;
240: #ifdef USE_IFNAME_IN_RULES
241: if(ifname)
242: strlcpy(pcr.rule.ifname, ifname, IFNAMSIZ);
243: #endif
244: pcr.rule.proto = proto;
245: pcr.rule.log = (GETFLAG(LOGPACKETSMASK))?1:0; /*logpackets;*/
246: #ifdef PFRULE_HAS_RTABLEID
247: pcr.rule.rtableid = -1; /* first appeared in OpenBSD 4.0 */
248: #endif
1.1.1.3 ! misho 249: #ifdef PFRULE_HAS_ONRDOMAIN
! 250: pcr.rule.onrdomain = -1; /* first appeared in OpenBSD 5.0 */
! 251: #endif
1.1 misho 252: pcr.rule.quick = 1;
253: pcr.rule.keep_state = PF_STATE_NORMAL;
254: if(tag)
255: strlcpy(pcr.rule.tagname, tag, PF_TAG_NAME_SIZE);
256: strlcpy(pcr.rule.label, desc, PF_RULE_LABEL_SIZE);
1.1.1.2 misho 257: if(rhost && rhost[0] != '\0' && rhost[0] != '*')
258: {
259: inet_pton(AF_INET, rhost, &pcr.rule.src.addr.v.a.addr.v4.s_addr);
260: pcr.rule.src.addr.v.a.mask.v4.s_addr = htonl(INADDR_NONE);
261: }
1.1 misho 262: #ifndef PF_NEWSTYLE
263: pcr.rule.rpool.proxy_port[0] = iport;
264: pcr.rule.rpool.proxy_port[1] = iport;
265: TAILQ_INIT(&pcr.rule.rpool.list);
266: a = calloc(1, sizeof(struct pf_pooladdr));
267: inet_pton(AF_INET, iaddr, &a->addr.v.a.addr.v4.s_addr);
268: a->addr.v.a.mask.v4.s_addr = htonl(INADDR_NONE);
269: TAILQ_INSERT_TAIL(&pcr.rule.rpool.list, a, entries);
270:
271: memcpy(&pp.addr, a, sizeof(struct pf_pooladdr));
272: if(ioctl(dev, DIOCADDADDR, &pp) < 0)
273: {
274: syslog(LOG_ERR, "ioctl(dev, DIOCADDADDR, ...): %m");
275: r = -1;
276: }
277: else
278: {
279: #else
280: pcr.rule.rdr.proxy_port[0] = iport;
281: pcr.rule.rdr.proxy_port[1] = iport;
282: inet_pton(AF_INET, iaddr, &pcr.rule.rdr.addr.v.a.addr.v4.s_addr);
283: pcr.rule.rdr.addr.v.a.mask.v4.s_addr = htonl(INADDR_NONE);
284: if(1)
285: {
286: #endif
287: pcr.action = PF_CHANGE_GET_TICKET;
288: if(ioctl(dev, DIOCCHANGERULE, &pcr) < 0)
289: {
290: syslog(LOG_ERR, "ioctl(dev, DIOCCHANGERULE, ...) PF_CHANGE_GET_TICKET: %m");
291: r = -1;
292: }
293: else
294: {
295: pcr.action = PF_CHANGE_ADD_TAIL;
296: if(ioctl(dev, DIOCCHANGERULE, &pcr) < 0)
297: {
298: syslog(LOG_ERR, "ioctl(dev, DIOCCHANGERULE, ...) PF_CHANGE_ADD_TAIL: %m");
299: r = -1;
300: }
301: }
302: }
303: #ifndef PF_NEWSTYLE
304: free(a);
305: #endif
306: }
1.1.1.2 misho 307: if(r == 0 && timestamp > 0)
308: {
309: struct timestamp_entry * tmp;
310: tmp = malloc(sizeof(struct timestamp_entry));
311: if(tmp)
312: {
313: tmp->next = timestamp_list;
314: tmp->timestamp = timestamp;
315: tmp->eport = eport;
316: tmp->protocol = (short)proto;
317: timestamp_list = tmp;
318: }
319: }
1.1 misho 320: return r;
321: }
322:
323: /* thanks to Seth Mos for this function */
324: int
1.1.1.2 misho 325: add_filter_rule2(const char * ifname,
326: const char * rhost, const char * iaddr,
1.1 misho 327: unsigned short eport, unsigned short iport,
328: int proto, const char * desc)
329: {
330: #ifndef PF_ENABLE_FILTER_RULES
1.1.1.3 ! misho 331: UNUSED(ifname);
! 332: UNUSED(rhost); UNUSED(iaddr);
! 333: UNUSED(eport); UNUSED(iport);
! 334: UNUSED(proto); UNUSED(desc);
1.1 misho 335: return 0;
336: #else
337: int r;
338: struct pfioc_rule pcr;
339: #ifndef PF_NEWSTYLE
340: struct pfioc_pooladdr pp;
341: struct pf_pooladdr *a;
342: #endif
343: if(dev<0) {
344: syslog(LOG_ERR, "pf device is not open");
345: return -1;
346: }
347: r = 0;
348: memset(&pcr, 0, sizeof(pcr));
349: strlcpy(pcr.anchor, anchor_name, MAXPATHLEN);
350:
351: #ifndef PF_NEWSTYLE
352: memset(&pp, 0, sizeof(pp));
353: strlcpy(pp.anchor, anchor_name, MAXPATHLEN);
354: if(ioctl(dev, DIOCBEGINADDRS, &pp) < 0)
355: {
356: syslog(LOG_ERR, "ioctl(dev, DIOCBEGINADDRS, ...): %m");
357: r = -1;
358: }
359: else
360: {
361: pcr.pool_ticket = pp.ticket;
362: #else
363: if(1)
364: {
365: #endif
1.1.1.3 ! misho 366:
1.1 misho 367: pcr.rule.dst.port_op = PF_OP_EQ;
368: pcr.rule.dst.port[0] = htons(eport);
369: pcr.rule.direction = PF_IN;
370: pcr.rule.action = PF_PASS;
371: pcr.rule.af = AF_INET;
372: #ifdef USE_IFNAME_IN_RULES
373: if(ifname)
374: strlcpy(pcr.rule.ifname, ifname, IFNAMSIZ);
375: #endif
376: pcr.rule.proto = proto;
377: pcr.rule.quick = (GETFLAG(PFNOQUICKRULESMASK))?0:1;
378: pcr.rule.log = (GETFLAG(LOGPACKETSMASK))?1:0; /*logpackets;*/
379: /* see the discussion on the forum :
380: * http://miniupnp.tuxfamily.org/forum/viewtopic.php?p=638 */
381: pcr.rule.flags = TH_SYN;
382: pcr.rule.flagset = (TH_SYN|TH_ACK);
383: #ifdef PFRULE_HAS_RTABLEID
1.1.1.3 ! misho 384: pcr.rule.rtableid = -1; /* first appeared in OpenBSD 4.0 */
! 385: #endif
! 386: #ifdef PFRULE_HAS_ONRDOMAIN
! 387: pcr.rule.onrdomain = -1; /* first appeared in OpenBSD 5.0 */
1.1 misho 388: #endif
389: pcr.rule.keep_state = 1;
390: strlcpy(pcr.rule.label, desc, PF_RULE_LABEL_SIZE);
391: if(queue)
392: strlcpy(pcr.rule.qname, queue, PF_QNAME_SIZE);
393: if(tag)
394: strlcpy(pcr.rule.tagname, tag, PF_TAG_NAME_SIZE);
395:
1.1.1.2 misho 396: if(rhost && rhost[0] != '\0' && rhost[0] != '*')
397: {
398: inet_pton(AF_INET, rhost, &pcr.rule.src.addr.v.a.addr.v4.s_addr);
399: pcr.rule.src.addr.v.a.mask.v4.s_addr = htonl(INADDR_NONE);
400: }
1.1 misho 401: #ifndef PF_NEWSTYLE
402: pcr.rule.rpool.proxy_port[0] = eport;
403: a = calloc(1, sizeof(struct pf_pooladdr));
404: inet_pton(AF_INET, iaddr, &a->addr.v.a.addr.v4.s_addr);
405: a->addr.v.a.mask.v4.s_addr = htonl(INADDR_NONE);
406: memcpy(&pp.addr, a, sizeof(struct pf_pooladdr));
407: TAILQ_INIT(&pcr.rule.rpool.list);
408: inet_pton(AF_INET, iaddr, &a->addr.v.a.addr.v4.s_addr);
409: TAILQ_INSERT_TAIL(&pcr.rule.rpool.list, a, entries);
1.1.1.3 ! misho 410:
1.1 misho 411: /* we have any - any port = # keep state label */
412: /* we want any - iaddr port = # keep state label */
413: /* memcpy(&pcr.rule.dst, a, sizeof(struct pf_pooladdr)); */
414:
415: memcpy(&pp.addr, a, sizeof(struct pf_pooladdr));
416: strlcpy(pcr.rule.label, desc, PF_RULE_LABEL_SIZE);
417: if(ioctl(dev, DIOCADDADDR, &pp) < 0)
418: {
419: syslog(LOG_ERR, "ioctl(dev, DIOCADDADDR, ...): %m");
420: r = -1;
421: }
422: else
423: {
424: #else
425: if(1)
426: {
427: #endif
428: pcr.action = PF_CHANGE_GET_TICKET;
429: if(ioctl(dev, DIOCCHANGERULE, &pcr) < 0)
430: {
431: syslog(LOG_ERR, "ioctl(dev, DIOCCHANGERULE, ...) PF_CHANGE_GET_TICKET: %m");
432: r = -1;
433: }
434: else
435: {
436: pcr.action = PF_CHANGE_ADD_TAIL;
437: if(ioctl(dev, DIOCCHANGERULE, &pcr) < 0)
438: {
439: syslog(LOG_ERR, "ioctl(dev, DIOCCHANGERULE, ...) PF_CHANGE_ADD_TAIL: %m");
440: r = -1;
441: }
442: }
443: }
444: #ifndef PF_NEWSTYLE
445: free(a);
446: #endif
447: }
448: return r;
449: #endif
450: }
451:
452: /* get_redirect_rule()
453: * return value : 0 success (found)
454: * -1 = error or rule not found */
455: int
456: get_redirect_rule(const char * ifname, unsigned short eport, int proto,
457: char * iaddr, int iaddrlen, unsigned short * iport,
458: char * desc, int desclen,
1.1.1.2 misho 459: char * rhost, int rhostlen,
460: unsigned int * timestamp,
1.1 misho 461: u_int64_t * packets, u_int64_t * bytes)
462: {
463: int i, n;
464: struct pfioc_rule pr;
465: #ifndef PF_NEWSTYLE
466: struct pfioc_pooladdr pp;
467: #endif
1.1.1.3 ! misho 468: UNUSED(ifname);
! 469:
1.1 misho 470: if(dev<0) {
471: syslog(LOG_ERR, "pf device is not open");
472: return -1;
473: }
474: memset(&pr, 0, sizeof(pr));
475: strlcpy(pr.anchor, anchor_name, MAXPATHLEN);
476: #ifndef PF_NEWSTYLE
477: pr.rule.action = PF_RDR;
478: #endif
479: if(ioctl(dev, DIOCGETRULES, &pr) < 0)
480: {
481: syslog(LOG_ERR, "ioctl(dev, DIOCGETRULES, ...): %m");
482: goto error;
483: }
484: n = pr.nr;
485: for(i=0; i<n; i++)
486: {
487: pr.nr = i;
488: if(ioctl(dev, DIOCGETRULE, &pr) < 0)
489: {
490: syslog(LOG_ERR, "ioctl(dev, DIOCGETRULE): %m");
491: goto error;
492: }
493: if( (eport == ntohs(pr.rule.dst.port[0]))
494: && (eport == ntohs(pr.rule.dst.port[1]))
495: && (pr.rule.proto == proto) )
496: {
497: #ifndef PF_NEWSTYLE
498: *iport = pr.rule.rpool.proxy_port[0];
499: #else
500: *iport = pr.rule.rdr.proxy_port[0];
501: #endif
502: if(desc)
503: strlcpy(desc, pr.rule.label, desclen);
504: #ifdef PFRULE_INOUT_COUNTS
505: if(packets)
506: *packets = pr.rule.packets[0] + pr.rule.packets[1];
507: if(bytes)
508: *bytes = pr.rule.bytes[0] + pr.rule.bytes[1];
509: #else
510: if(packets)
511: *packets = pr.rule.packets;
512: if(bytes)
513: *bytes = pr.rule.bytes;
514: #endif
515: #ifndef PF_NEWSTYLE
516: memset(&pp, 0, sizeof(pp));
517: strlcpy(pp.anchor, anchor_name, MAXPATHLEN);
518: pp.r_action = PF_RDR;
519: pp.r_num = i;
520: pp.ticket = pr.ticket;
521: if(ioctl(dev, DIOCGETADDRS, &pp) < 0)
522: {
523: syslog(LOG_ERR, "ioctl(dev, DIOCGETADDRS, ...): %m");
524: goto error;
525: }
526: if(pp.nr != 1)
527: {
528: syslog(LOG_NOTICE, "No address associated with pf rule");
529: goto error;
530: }
531: pp.nr = 0; /* first */
532: if(ioctl(dev, DIOCGETADDR, &pp) < 0)
533: {
534: syslog(LOG_ERR, "ioctl(dev, DIOCGETADDR, ...): %m");
535: goto error;
536: }
537: inet_ntop(AF_INET, &pp.addr.addr.v.a.addr.v4.s_addr,
538: iaddr, iaddrlen);
539: #else
540: inet_ntop(AF_INET, &pr.rule.rdr.addr.v.a.addr.v4.s_addr,
541: iaddr, iaddrlen);
542: #endif
1.1.1.2 misho 543: if(rhost && rhostlen > 0)
544: {
545: if (pr.rule.src.addr.v.a.addr.v4.s_addr == 0)
546: {
547: rhost[0] = '\0'; /* empty string */
548: }
549: else
550: {
551: inet_ntop(AF_INET, &pr.rule.src.addr.v.a.addr.v4.s_addr,
552: rhost, rhostlen);
553: }
554: }
555: if(timestamp)
556: *timestamp = get_timestamp(eport, proto);
1.1 misho 557: return 0;
558: }
559: }
560: error:
561: return -1;
562: }
563:
564: int
565: delete_redirect_rule(const char * ifname, unsigned short eport, int proto)
566: {
567: int i, n;
568: struct pfioc_rule pr;
1.1.1.3 ! misho 569: UNUSED(ifname);
! 570:
1.1 misho 571: if(dev<0) {
572: syslog(LOG_ERR, "pf device is not open");
573: return -1;
574: }
575: memset(&pr, 0, sizeof(pr));
576: strlcpy(pr.anchor, anchor_name, MAXPATHLEN);
577: #ifndef PF_NEWSTYLE
578: pr.rule.action = PF_RDR;
579: #endif
580: if(ioctl(dev, DIOCGETRULES, &pr) < 0)
581: {
582: syslog(LOG_ERR, "ioctl(dev, DIOCGETRULES, ...): %m");
583: goto error;
584: }
585: n = pr.nr;
586: for(i=0; i<n; i++)
587: {
588: pr.nr = i;
589: if(ioctl(dev, DIOCGETRULE, &pr) < 0)
590: {
591: syslog(LOG_ERR, "ioctl(dev, DIOCGETRULE): %m");
592: goto error;
593: }
594: if( (eport == ntohs(pr.rule.dst.port[0]))
595: && (eport == ntohs(pr.rule.dst.port[1]))
596: && (pr.rule.proto == proto) )
597: {
598: pr.action = PF_CHANGE_GET_TICKET;
599: if(ioctl(dev, DIOCCHANGERULE, &pr) < 0)
600: {
601: syslog(LOG_ERR, "ioctl(dev, DIOCCHANGERULE, ...) PF_CHANGE_GET_TICKET: %m");
602: goto error;
603: }
604: pr.action = PF_CHANGE_REMOVE;
605: pr.nr = i;
606: if(ioctl(dev, DIOCCHANGERULE, &pr) < 0)
607: {
608: syslog(LOG_ERR, "ioctl(dev, DIOCCHANGERULE, ...) PF_CHANGE_REMOVE: %m");
609: goto error;
610: }
1.1.1.2 misho 611: remove_timestamp_entry(eport, proto);
1.1 misho 612: return 0;
613: }
614: }
615: error:
616: return -1;
617: }
618:
619: int
620: delete_filter_rule(const char * ifname, unsigned short eport, int proto)
621: {
622: #ifndef PF_ENABLE_FILTER_RULES
1.1.1.3 ! misho 623: UNUSED(ifname); UNUSED(eport); UNUSED(proto);
1.1 misho 624: return 0;
625: #else
626: int i, n;
627: struct pfioc_rule pr;
628: if(dev<0) {
629: syslog(LOG_ERR, "pf device is not open");
630: return -1;
631: }
632: memset(&pr, 0, sizeof(pr));
633: strlcpy(pr.anchor, anchor_name, MAXPATHLEN);
634: pr.rule.action = PF_PASS;
635: if(ioctl(dev, DIOCGETRULES, &pr) < 0)
636: {
637: syslog(LOG_ERR, "ioctl(dev, DIOCGETRULES, ...): %m");
638: goto error;
639: }
640: n = pr.nr;
641: for(i=0; i<n; i++)
642: {
643: pr.nr = i;
644: if(ioctl(dev, DIOCGETRULE, &pr) < 0)
645: {
646: syslog(LOG_ERR, "ioctl(dev, DIOCGETRULE): %m");
647: goto error;
648: }
649: if( (eport == ntohs(pr.rule.dst.port[0]))
650: && (pr.rule.proto == proto) )
651: {
652: pr.action = PF_CHANGE_GET_TICKET;
653: if(ioctl(dev, DIOCCHANGERULE, &pr) < 0)
654: {
655: syslog(LOG_ERR, "ioctl(dev, DIOCCHANGERULE, ...) PF_CHANGE_GET_TICKET: %m");
656: goto error;
657: }
658: pr.action = PF_CHANGE_REMOVE;
659: pr.nr = i;
660: if(ioctl(dev, DIOCCHANGERULE, &pr) < 0)
661: {
662: syslog(LOG_ERR, "ioctl(dev, DIOCCHANGERULE, ...) PF_CHANGE_REMOVE: %m");
663: goto error;
664: }
665: return 0;
666: }
667: }
668: error:
669: return -1;
670: #endif
671: }
672:
673: int
674: get_redirect_rule_by_index(int index,
675: char * ifname, unsigned short * eport,
676: char * iaddr, int iaddrlen, unsigned short * iport,
677: int * proto, char * desc, int desclen,
1.1.1.2 misho 678: char * rhost, int rhostlen,
679: unsigned int * timestamp,
1.1 misho 680: u_int64_t * packets, u_int64_t * bytes)
681: {
682: int n;
683: struct pfioc_rule pr;
684: #ifndef PF_NEWSTYLE
685: struct pfioc_pooladdr pp;
686: #endif
687: if(index < 0)
688: return -1;
689: if(dev<0) {
690: syslog(LOG_ERR, "pf device is not open");
691: return -1;
692: }
693: memset(&pr, 0, sizeof(pr));
694: strlcpy(pr.anchor, anchor_name, MAXPATHLEN);
695: #ifndef PF_NEWSTYLE
696: pr.rule.action = PF_RDR;
697: #endif
698: if(ioctl(dev, DIOCGETRULES, &pr) < 0)
699: {
700: syslog(LOG_ERR, "ioctl(dev, DIOCGETRULES, ...): %m");
701: goto error;
702: }
703: n = pr.nr;
704: if(index >= n)
705: goto error;
706: pr.nr = index;
707: if(ioctl(dev, DIOCGETRULE, &pr) < 0)
708: {
709: syslog(LOG_ERR, "ioctl(dev, DIOCGETRULE): %m");
710: goto error;
711: }
712: *proto = pr.rule.proto;
713: *eport = ntohs(pr.rule.dst.port[0]);
714: #ifndef PF_NEWSTYLE
715: *iport = pr.rule.rpool.proxy_port[0];
716: #else
717: *iport = pr.rule.rdr.proxy_port[0];
718: #endif
719: if(ifname)
720: strlcpy(ifname, pr.rule.ifname, IFNAMSIZ);
721: if(desc)
722: strlcpy(desc, pr.rule.label, desclen);
723: #ifdef PFRULE_INOUT_COUNTS
724: if(packets)
725: *packets = pr.rule.packets[0] + pr.rule.packets[1];
726: if(bytes)
727: *bytes = pr.rule.bytes[0] + pr.rule.bytes[1];
728: #else
729: if(packets)
730: *packets = pr.rule.packets;
731: if(bytes)
732: *bytes = pr.rule.bytes;
733: #endif
734: #ifndef PF_NEWSTYLE
735: memset(&pp, 0, sizeof(pp));
736: strlcpy(pp.anchor, anchor_name, MAXPATHLEN);
737: pp.r_action = PF_RDR;
738: pp.r_num = index;
739: pp.ticket = pr.ticket;
740: if(ioctl(dev, DIOCGETADDRS, &pp) < 0)
741: {
742: syslog(LOG_ERR, "ioctl(dev, DIOCGETADDRS, ...): %m");
743: goto error;
744: }
745: if(pp.nr != 1)
746: {
747: syslog(LOG_NOTICE, "No address associated with pf rule");
748: goto error;
749: }
750: pp.nr = 0; /* first */
751: if(ioctl(dev, DIOCGETADDR, &pp) < 0)
752: {
753: syslog(LOG_ERR, "ioctl(dev, DIOCGETADDR, ...): %m");
754: goto error;
755: }
756: inet_ntop(AF_INET, &pp.addr.addr.v.a.addr.v4.s_addr,
757: iaddr, iaddrlen);
758: #else
759: inet_ntop(AF_INET, &pr.rule.rdr.addr.v.a.addr.v4.s_addr,
760: iaddr, iaddrlen);
761: #endif
1.1.1.2 misho 762: if(rhost && rhostlen > 0)
763: {
764: if (pr.rule.src.addr.v.a.addr.v4.s_addr == 0)
765: {
766: rhost[0] = '\0'; /* empty string */
767: }
768: else
769: {
770: inet_ntop(AF_INET, &pr.rule.src.addr.v.a.addr.v4.s_addr,
771: rhost, rhostlen);
772: }
773: }
774: if(timestamp)
775: *timestamp = get_timestamp(*eport, *proto);
1.1 misho 776: return 0;
777: error:
778: return -1;
779: }
780:
1.1.1.2 misho 781: /* return an (malloc'ed) array of "external" port for which there is
782: * a port mapping. number is the size of the array */
783: unsigned short *
784: get_portmappings_in_range(unsigned short startport, unsigned short endport,
785: int proto, unsigned int * number)
786: {
787: unsigned short * array;
788: unsigned int capacity;
789: int i, n;
790: unsigned short eport;
791: struct pfioc_rule pr;
792:
793: *number = 0;
794: if(dev<0) {
795: syslog(LOG_ERR, "pf device is not open");
796: return NULL;
797: }
798: capacity = 128;
799: array = calloc(capacity, sizeof(unsigned short));
800: if(!array)
801: {
802: syslog(LOG_ERR, "get_portmappings_in_range() : calloc error");
803: return NULL;
804: }
805: memset(&pr, 0, sizeof(pr));
806: strlcpy(pr.anchor, anchor_name, MAXPATHLEN);
807: #ifndef PF_NEWSTYLE
808: pr.rule.action = PF_RDR;
809: #endif
810: if(ioctl(dev, DIOCGETRULES, &pr) < 0)
811: {
812: syslog(LOG_ERR, "ioctl(dev, DIOCGETRULES, ...): %m");
813: free(array);
814: return NULL;
815: }
816: n = pr.nr;
817: for(i=0; i<n; i++)
818: {
819: pr.nr = i;
820: if(ioctl(dev, DIOCGETRULE, &pr) < 0)
821: {
822: syslog(LOG_ERR, "ioctl(dev, DIOCGETRULE): %m");
823: continue;
824: }
825: eport = ntohs(pr.rule.dst.port[0]);
826: if( (eport == ntohs(pr.rule.dst.port[1]))
827: && (pr.rule.proto == proto)
828: && (startport <= eport) && (eport <= endport) )
829: {
830: if(*number >= capacity)
831: {
832: /* need to increase the capacity of the array */
833: capacity += 128;
834: array = realloc(array, sizeof(unsigned short)*capacity);
835: if(!array)
836: {
837: syslog(LOG_ERR, "get_portmappings_in_range() : realloc(%lu) error", sizeof(unsigned short)*capacity);
838: *number = 0;
839: return NULL;
840: }
841: }
842: array[*number] = eport;
843: (*number)++;
844: }
845: }
846: return array;
847: }
848:
1.1 misho 849: /* this function is only for testing */
850: #if TEST
851: void
852: list_rules(void)
853: {
854: char buf[32];
855: int i, n;
856: struct pfioc_rule pr;
857: #ifndef PF_NEWSTYLE
858: struct pfioc_pooladdr pp;
859: #endif
860:
861: if(dev<0)
862: {
863: perror("pf dev not open");
864: return ;
865: }
866: memset(&pr, 0, sizeof(pr));
867: strlcpy(pr.anchor, anchor_name, MAXPATHLEN);
868: pr.rule.action = PF_RDR;
869: if(ioctl(dev, DIOCGETRULES, &pr) < 0)
870: perror("DIOCGETRULES");
871: printf("ticket = %d, nr = %d\n", pr.ticket, pr.nr);
872: n = pr.nr;
873: for(i=0; i<n; i++)
874: {
875: printf("-- rule %d --\n", i);
876: pr.nr = i;
877: if(ioctl(dev, DIOCGETRULE, &pr) < 0)
878: perror("DIOCGETRULE");
1.1.1.2 misho 879: printf(" %s %s %d:%d -> %d:%d proto %d keep_state=%d action=%d\n",
1.1 misho 880: pr.rule.ifname,
1.1.1.3 ! misho 881: inet_ntop(AF_INET, &pr.rule.src.addr.v.a.addr.v4.s_addr, buf, 32),
1.1 misho 882: (int)ntohs(pr.rule.dst.port[0]),
883: (int)ntohs(pr.rule.dst.port[1]),
884: #ifndef PF_NEWSTYLE
885: (int)pr.rule.rpool.proxy_port[0],
886: (int)pr.rule.rpool.proxy_port[1],
887: #else
888: (int)pr.rule.rdr.proxy_port[0],
889: (int)pr.rule.rdr.proxy_port[1],
890: #endif
891: (int)pr.rule.proto,
892: (int)pr.rule.keep_state,
893: (int)pr.rule.action);
894: printf(" description: \"%s\"\n", pr.rule.label);
895: #ifndef PF_NEWSTYLE
896: memset(&pp, 0, sizeof(pp));
897: strlcpy(pp.anchor, anchor_name, MAXPATHLEN);
898: pp.r_action = PF_RDR;
899: pp.r_num = i;
900: pp.ticket = pr.ticket;
901: if(ioctl(dev, DIOCGETADDRS, &pp) < 0)
902: perror("DIOCGETADDRS");
903: printf(" nb pool addr = %d ticket=%d\n", pp.nr, pp.ticket);
904: /*if(ioctl(dev, DIOCGETRULE, &pr) < 0)
905: perror("DIOCGETRULE"); */
906: pp.nr = 0; /* first */
907: if(ioctl(dev, DIOCGETADDR, &pp) < 0)
908: perror("DIOCGETADDR");
909: /* addr.v.a.addr.v4.s_addr */
910: printf(" %s\n", inet_ntop(AF_INET, &pp.addr.addr.v.a.addr.v4.s_addr, buf, 32));
911: #else
912: printf(" rule_flag=%08x action=%d direction=%d log=%d logif=%d "
913: "quick=%d ifnot=%d af=%d type=%d code=%d rdr.port_op=%d rdr.opts=%d\n",
914: pr.rule.rule_flag, pr.rule.action, pr.rule.direction,
915: pr.rule.log, pr.rule.logif, pr.rule.quick, pr.rule.ifnot,
916: pr.rule.af, pr.rule.type, pr.rule.code,
917: pr.rule.rdr.port_op, pr.rule.rdr.opts);
918: printf(" %s\n", inet_ntop(AF_INET, &pr.rule.rdr.addr.v.a.addr.v4.s_addr, buf, 32));
919: #endif
920: }
921: }
922: #endif
923:
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>