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