Miniupnpd v. 1.5 (20110618)
[tomato.git] / release / src / router / miniupnpd / pf / obsdrdr.c
blob0b62f57b194d2543f713eb4775ccd77655d1d15c
1 /* $Id: obsdrdr.c,v 1.66 2011/06/17 22:47:12 nanard Exp $ */
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 */
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
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
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.
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>
58 #include "../config.h"
59 #include "obsdrdr.h"
60 #include "../upnpglobalvars.h"
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;
70 static struct timestamp_entry * timestamp_list = NULL;
72 static unsigned int
73 get_timestamp(unsigned short eport, int proto)
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;
82 return 0;
85 static void
86 remove_timestamp_entry(unsigned short eport, int proto)
88 struct timestamp_entry * e;
89 struct timestamp_entry * * p;
90 p = &timestamp_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;
99 p = &(e->next);
100 e = *p;
104 /* anchor name */
105 static const char anchor_name[] = "miniupnpd";
107 /* /dev/pf when opened */
108 static int dev = -1;
110 /* shutdown_redirect() :
111 * close the /dev/pf device */
112 void
113 shutdown_redirect(void)
115 if(close(dev)<0)
116 syslog(LOG_ERR, "close(\"/dev/pf\"): %m");
117 dev = -1;
120 /* open the device */
122 init_redirect(void)
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;
132 if(ioctl(dev, DIOCGETSTATUS, &status)<0) {
133 syslog(LOG_ERR, "DIOCGETSTATUS: %m");
134 return -1;
136 if(!status.running) {
137 syslog(LOG_ERR, "pf is disabled");
138 return -1;
140 return 0;
143 #if TEST
144 /* for debug */
146 clear_redirect_rules(void)
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;
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)
166 syslog(LOG_ERR, "ioctl(dev, DIOCXBEGIN, ...): %m");
167 goto error;
169 if(ioctl(dev, DIOCXCOMMIT, &io) < 0)
171 syslog(LOG_ERR, "ioctl(dev, DIOCXCOMMIT, ...): %m");
172 goto error;
174 return 0;
175 error:
176 return -1;
178 #endif
180 /* add_redirect_rule2() :
181 * create a rdr rule */
183 add_redirect_rule2(const char * ifname,
184 const char * rhost, unsigned short eport,
185 const char * iaddr, unsigned short iport, int proto,
186 const char * desc, unsigned int timestamp)
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;
198 r = 0;
199 memset(&pcr, 0, sizeof(pcr));
200 strlcpy(pcr.anchor, anchor_name, MAXPATHLEN);
202 #ifndef PF_NEWSTYLE
203 memset(&pp, 0, sizeof(pp));
204 strlcpy(pp.anchor, anchor_name, MAXPATHLEN);
205 if(ioctl(dev, DIOCBEGINADDRS, &pp) < 0)
207 syslog(LOG_ERR, "ioctl(dev, DIOCBEGINADDRS, ...): %m");
208 r = -1;
210 else
212 pcr.pool_ticket = pp.ticket;
213 #else
214 if(1)
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
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);
256 if(rhost && rhost[0] != '\0' && rhost[0] != '*')
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);
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);
270 memcpy(&pp.addr, a, sizeof(struct pf_pooladdr));
271 if(ioctl(dev, DIOCADDADDR, &pp) < 0)
273 syslog(LOG_ERR, "ioctl(dev, DIOCADDADDR, ...): %m");
274 r = -1;
276 else
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)
285 #endif
286 pcr.action = PF_CHANGE_GET_TICKET;
287 if(ioctl(dev, DIOCCHANGERULE, &pcr) < 0)
289 syslog(LOG_ERR, "ioctl(dev, DIOCCHANGERULE, ...) PF_CHANGE_GET_TICKET: %m");
290 r = -1;
292 else
294 pcr.action = PF_CHANGE_ADD_TAIL;
295 if(ioctl(dev, DIOCCHANGERULE, &pcr) < 0)
297 syslog(LOG_ERR, "ioctl(dev, DIOCCHANGERULE, ...) PF_CHANGE_ADD_TAIL: %m");
298 r = -1;
302 #ifndef PF_NEWSTYLE
303 free(a);
304 #endif
306 if(r == 0 && timestamp > 0)
308 struct timestamp_entry * tmp;
309 tmp = malloc(sizeof(struct timestamp_entry));
310 if(tmp)
312 tmp->next = timestamp_list;
313 tmp->timestamp = timestamp;
314 tmp->eport = eport;
315 tmp->protocol = (short)proto;
316 timestamp_list = tmp;
319 return r;
322 /* thanks to Seth Mos for this function */
324 add_filter_rule2(const char * ifname,
325 const char * rhost, const char * iaddr,
326 unsigned short eport, unsigned short iport,
327 int proto, const char * desc)
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;
342 r = 0;
343 memset(&pcr, 0, sizeof(pcr));
344 strlcpy(pcr.anchor, anchor_name, MAXPATHLEN);
346 #ifndef PF_NEWSTYLE
347 memset(&pp, 0, sizeof(pp));
348 strlcpy(pp.anchor, anchor_name, MAXPATHLEN);
349 if(ioctl(dev, DIOCBEGINADDRS, &pp) < 0)
351 syslog(LOG_ERR, "ioctl(dev, DIOCBEGINADDRS, ...): %m");
352 r = -1;
354 else
356 pcr.pool_ticket = pp.ticket;
357 #else
358 if(1)
360 #endif
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);
388 if(rhost && rhost[0] != '\0' && rhost[0] != '*')
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);
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);
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)); */
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)
411 syslog(LOG_ERR, "ioctl(dev, DIOCADDADDR, ...): %m");
412 r = -1;
414 else
416 #else
417 if(1)
419 #endif
420 pcr.action = PF_CHANGE_GET_TICKET;
421 if(ioctl(dev, DIOCCHANGERULE, &pcr) < 0)
423 syslog(LOG_ERR, "ioctl(dev, DIOCCHANGERULE, ...) PF_CHANGE_GET_TICKET: %m");
424 r = -1;
426 else
428 pcr.action = PF_CHANGE_ADD_TAIL;
429 if(ioctl(dev, DIOCCHANGERULE, &pcr) < 0)
431 syslog(LOG_ERR, "ioctl(dev, DIOCCHANGERULE, ...) PF_CHANGE_ADD_TAIL: %m");
432 r = -1;
436 #ifndef PF_NEWSTYLE
437 free(a);
438 #endif
440 return r;
441 #endif
444 /* get_redirect_rule()
445 * return value : 0 success (found)
446 * -1 = error or rule not found */
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, unsigned int * timestamp,
451 u_int64_t * packets, u_int64_t * bytes)
453 int i, n;
454 struct pfioc_rule pr;
455 #ifndef PF_NEWSTYLE
456 struct pfioc_pooladdr pp;
457 #endif
458 if(dev<0) {
459 syslog(LOG_ERR, "pf device is not open");
460 return -1;
462 memset(&pr, 0, sizeof(pr));
463 strlcpy(pr.anchor, anchor_name, MAXPATHLEN);
464 #ifndef PF_NEWSTYLE
465 pr.rule.action = PF_RDR;
466 #endif
467 if(ioctl(dev, DIOCGETRULES, &pr) < 0)
469 syslog(LOG_ERR, "ioctl(dev, DIOCGETRULES, ...): %m");
470 goto error;
472 n = pr.nr;
473 for(i=0; i<n; i++)
475 pr.nr = i;
476 if(ioctl(dev, DIOCGETRULE, &pr) < 0)
478 syslog(LOG_ERR, "ioctl(dev, DIOCGETRULE): %m");
479 goto error;
481 if( (eport == ntohs(pr.rule.dst.port[0]))
482 && (eport == ntohs(pr.rule.dst.port[1]))
483 && (pr.rule.proto == proto) )
485 #ifndef PF_NEWSTYLE
486 *iport = pr.rule.rpool.proxy_port[0];
487 #else
488 *iport = pr.rule.rdr.proxy_port[0];
489 #endif
490 if(desc)
491 strlcpy(desc, pr.rule.label, desclen);
492 #ifdef PFRULE_INOUT_COUNTS
493 if(packets)
494 *packets = pr.rule.packets[0] + pr.rule.packets[1];
495 if(bytes)
496 *bytes = pr.rule.bytes[0] + pr.rule.bytes[1];
497 #else
498 if(packets)
499 *packets = pr.rule.packets;
500 if(bytes)
501 *bytes = pr.rule.bytes;
502 #endif
503 #ifndef PF_NEWSTYLE
504 memset(&pp, 0, sizeof(pp));
505 strlcpy(pp.anchor, anchor_name, MAXPATHLEN);
506 pp.r_action = PF_RDR;
507 pp.r_num = i;
508 pp.ticket = pr.ticket;
509 if(ioctl(dev, DIOCGETADDRS, &pp) < 0)
511 syslog(LOG_ERR, "ioctl(dev, DIOCGETADDRS, ...): %m");
512 goto error;
514 if(pp.nr != 1)
516 syslog(LOG_NOTICE, "No address associated with pf rule");
517 goto error;
519 pp.nr = 0; /* first */
520 if(ioctl(dev, DIOCGETADDR, &pp) < 0)
522 syslog(LOG_ERR, "ioctl(dev, DIOCGETADDR, ...): %m");
523 goto error;
525 inet_ntop(AF_INET, &pp.addr.addr.v.a.addr.v4.s_addr,
526 iaddr, iaddrlen);
527 #else
528 inet_ntop(AF_INET, &pr.rule.rdr.addr.v.a.addr.v4.s_addr,
529 iaddr, iaddrlen);
530 #endif
531 if(timestamp)
532 *timestamp = get_timestamp(eport, proto);
533 return 0;
536 error:
537 return -1;
541 delete_redirect_rule(const char * ifname, unsigned short eport, int proto)
543 int i, n;
544 struct pfioc_rule pr;
545 if(dev<0) {
546 syslog(LOG_ERR, "pf device is not open");
547 return -1;
549 memset(&pr, 0, sizeof(pr));
550 strlcpy(pr.anchor, anchor_name, MAXPATHLEN);
551 #ifndef PF_NEWSTYLE
552 pr.rule.action = PF_RDR;
553 #endif
554 if(ioctl(dev, DIOCGETRULES, &pr) < 0)
556 syslog(LOG_ERR, "ioctl(dev, DIOCGETRULES, ...): %m");
557 goto error;
559 n = pr.nr;
560 for(i=0; i<n; i++)
562 pr.nr = i;
563 if(ioctl(dev, DIOCGETRULE, &pr) < 0)
565 syslog(LOG_ERR, "ioctl(dev, DIOCGETRULE): %m");
566 goto error;
568 if( (eport == ntohs(pr.rule.dst.port[0]))
569 && (eport == ntohs(pr.rule.dst.port[1]))
570 && (pr.rule.proto == proto) )
572 pr.action = PF_CHANGE_GET_TICKET;
573 if(ioctl(dev, DIOCCHANGERULE, &pr) < 0)
575 syslog(LOG_ERR, "ioctl(dev, DIOCCHANGERULE, ...) PF_CHANGE_GET_TICKET: %m");
576 goto error;
578 pr.action = PF_CHANGE_REMOVE;
579 pr.nr = i;
580 if(ioctl(dev, DIOCCHANGERULE, &pr) < 0)
582 syslog(LOG_ERR, "ioctl(dev, DIOCCHANGERULE, ...) PF_CHANGE_REMOVE: %m");
583 goto error;
585 remove_timestamp_entry(eport, proto);
586 return 0;
589 error:
590 return -1;
594 delete_filter_rule(const char * ifname, unsigned short eport, int proto)
596 #ifndef PF_ENABLE_FILTER_RULES
597 return 0;
598 #else
599 int i, n;
600 struct pfioc_rule pr;
601 if(dev<0) {
602 syslog(LOG_ERR, "pf device is not open");
603 return -1;
605 memset(&pr, 0, sizeof(pr));
606 strlcpy(pr.anchor, anchor_name, MAXPATHLEN);
607 pr.rule.action = PF_PASS;
608 if(ioctl(dev, DIOCGETRULES, &pr) < 0)
610 syslog(LOG_ERR, "ioctl(dev, DIOCGETRULES, ...): %m");
611 goto error;
613 n = pr.nr;
614 for(i=0; i<n; i++)
616 pr.nr = i;
617 if(ioctl(dev, DIOCGETRULE, &pr) < 0)
619 syslog(LOG_ERR, "ioctl(dev, DIOCGETRULE): %m");
620 goto error;
622 if( (eport == ntohs(pr.rule.dst.port[0]))
623 && (pr.rule.proto == proto) )
625 pr.action = PF_CHANGE_GET_TICKET;
626 if(ioctl(dev, DIOCCHANGERULE, &pr) < 0)
628 syslog(LOG_ERR, "ioctl(dev, DIOCCHANGERULE, ...) PF_CHANGE_GET_TICKET: %m");
629 goto error;
631 pr.action = PF_CHANGE_REMOVE;
632 pr.nr = i;
633 if(ioctl(dev, DIOCCHANGERULE, &pr) < 0)
635 syslog(LOG_ERR, "ioctl(dev, DIOCCHANGERULE, ...) PF_CHANGE_REMOVE: %m");
636 goto error;
638 return 0;
641 error:
642 return -1;
643 #endif
647 get_redirect_rule_by_index(int index,
648 char * ifname, unsigned short * eport,
649 char * iaddr, int iaddrlen, unsigned short * iport,
650 int * proto, char * desc, int desclen,
651 char * rhost, int rhostlen,
652 unsigned int * timestamp,
653 u_int64_t * packets, u_int64_t * bytes)
655 int n;
656 struct pfioc_rule pr;
657 #ifndef PF_NEWSTYLE
658 struct pfioc_pooladdr pp;
659 #endif
660 if(index < 0)
661 return -1;
662 if(dev<0) {
663 syslog(LOG_ERR, "pf device is not open");
664 return -1;
666 memset(&pr, 0, sizeof(pr));
667 strlcpy(pr.anchor, anchor_name, MAXPATHLEN);
668 #ifndef PF_NEWSTYLE
669 pr.rule.action = PF_RDR;
670 #endif
671 if(ioctl(dev, DIOCGETRULES, &pr) < 0)
673 syslog(LOG_ERR, "ioctl(dev, DIOCGETRULES, ...): %m");
674 goto error;
676 n = pr.nr;
677 if(index >= n)
678 goto error;
679 pr.nr = index;
680 if(ioctl(dev, DIOCGETRULE, &pr) < 0)
682 syslog(LOG_ERR, "ioctl(dev, DIOCGETRULE): %m");
683 goto error;
685 *proto = pr.rule.proto;
686 *eport = ntohs(pr.rule.dst.port[0]);
687 #ifndef PF_NEWSTYLE
688 *iport = pr.rule.rpool.proxy_port[0];
689 #else
690 *iport = pr.rule.rdr.proxy_port[0];
691 #endif
692 if(ifname)
693 strlcpy(ifname, pr.rule.ifname, IFNAMSIZ);
694 if(desc)
695 strlcpy(desc, pr.rule.label, desclen);
696 #ifdef PFRULE_INOUT_COUNTS
697 if(packets)
698 *packets = pr.rule.packets[0] + pr.rule.packets[1];
699 if(bytes)
700 *bytes = pr.rule.bytes[0] + pr.rule.bytes[1];
701 #else
702 if(packets)
703 *packets = pr.rule.packets;
704 if(bytes)
705 *bytes = pr.rule.bytes;
706 #endif
707 #ifndef PF_NEWSTYLE
708 memset(&pp, 0, sizeof(pp));
709 strlcpy(pp.anchor, anchor_name, MAXPATHLEN);
710 pp.r_action = PF_RDR;
711 pp.r_num = index;
712 pp.ticket = pr.ticket;
713 if(ioctl(dev, DIOCGETADDRS, &pp) < 0)
715 syslog(LOG_ERR, "ioctl(dev, DIOCGETADDRS, ...): %m");
716 goto error;
718 if(pp.nr != 1)
720 syslog(LOG_NOTICE, "No address associated with pf rule");
721 goto error;
723 pp.nr = 0; /* first */
724 if(ioctl(dev, DIOCGETADDR, &pp) < 0)
726 syslog(LOG_ERR, "ioctl(dev, DIOCGETADDR, ...): %m");
727 goto error;
729 inet_ntop(AF_INET, &pp.addr.addr.v.a.addr.v4.s_addr,
730 iaddr, iaddrlen);
731 #else
732 inet_ntop(AF_INET, &pr.rule.rdr.addr.v.a.addr.v4.s_addr,
733 iaddr, iaddrlen);
734 #endif
735 if(rhost && rhostlen > 0)
737 if (pr.rule.src.addr.v.a.addr.v4.s_addr == 0)
739 rhost[0] = '\0'; /* empty string */
741 else
743 inet_ntop(AF_INET, &pr.rule.src.addr.v.a.addr.v4.s_addr,
744 rhost, rhostlen);
747 if(timestamp)
748 *timestamp = get_timestamp(*eport, *proto);
749 return 0;
750 error:
751 return -1;
754 /* return an (malloc'ed) array of "external" port for which there is
755 * a port mapping. number is the size of the array */
756 unsigned short *
757 get_portmappings_in_range(unsigned short startport, unsigned short endport,
758 int proto, unsigned int * number)
760 unsigned short * array;
761 unsigned int capacity;
762 int i, n;
763 unsigned short eport;
764 struct pfioc_rule pr;
766 *number = 0;
767 if(dev<0) {
768 syslog(LOG_ERR, "pf device is not open");
769 return NULL;
771 capacity = 128;
772 array = calloc(capacity, sizeof(unsigned short));
773 if(!array)
775 syslog(LOG_ERR, "get_portmappings_in_range() : calloc error");
776 return NULL;
778 memset(&pr, 0, sizeof(pr));
779 strlcpy(pr.anchor, anchor_name, MAXPATHLEN);
780 #ifndef PF_NEWSTYLE
781 pr.rule.action = PF_RDR;
782 #endif
783 if(ioctl(dev, DIOCGETRULES, &pr) < 0)
785 syslog(LOG_ERR, "ioctl(dev, DIOCGETRULES, ...): %m");
786 free(array);
787 return NULL;
789 n = pr.nr;
790 for(i=0; i<n; i++)
792 pr.nr = i;
793 if(ioctl(dev, DIOCGETRULE, &pr) < 0)
795 syslog(LOG_ERR, "ioctl(dev, DIOCGETRULE): %m");
796 continue;
798 eport = ntohs(pr.rule.dst.port[0]);
799 if( (eport == ntohs(pr.rule.dst.port[1]))
800 && (pr.rule.proto == proto)
801 && (startport <= eport) && (eport <= endport) )
803 if(*number >= capacity)
805 /* need to increase the capacity of the array */
806 capacity += 128;
807 array = realloc(array, sizeof(unsigned short)*capacity);
808 if(!array)
810 syslog(LOG_ERR, "get_portmappings_in_range() : realloc(%lu) error", sizeof(unsigned short)*capacity);
811 *number = 0;
812 return NULL;
815 array[*number] = eport;
816 (*number)++;
819 return array;
822 /* this function is only for testing */
823 #if TEST
824 void
825 list_rules(void)
827 char buf[32];
828 int i, n;
829 struct pfioc_rule pr;
830 #ifndef PF_NEWSTYLE
831 struct pfioc_pooladdr pp;
832 #endif
834 if(dev<0)
836 perror("pf dev not open");
837 return ;
839 memset(&pr, 0, sizeof(pr));
840 strlcpy(pr.anchor, anchor_name, MAXPATHLEN);
841 pr.rule.action = PF_RDR;
842 if(ioctl(dev, DIOCGETRULES, &pr) < 0)
843 perror("DIOCGETRULES");
844 printf("ticket = %d, nr = %d\n", pr.ticket, pr.nr);
845 n = pr.nr;
846 for(i=0; i<n; i++)
848 printf("-- rule %d --\n", i);
849 pr.nr = i;
850 if(ioctl(dev, DIOCGETRULE, &pr) < 0)
851 perror("DIOCGETRULE");
852 printf(" %s %s %d:%d -> %d:%d proto %d keep_state=%d action=%d\n",
853 pr.rule.ifname,
854 inet_ntop(AF_INET, &pr.rule.src.addr.v.a.addr.v4.s_addr, buf, 32);
855 (int)ntohs(pr.rule.dst.port[0]),
856 (int)ntohs(pr.rule.dst.port[1]),
857 #ifndef PF_NEWSTYLE
858 (int)pr.rule.rpool.proxy_port[0],
859 (int)pr.rule.rpool.proxy_port[1],
860 #else
861 (int)pr.rule.rdr.proxy_port[0],
862 (int)pr.rule.rdr.proxy_port[1],
863 #endif
864 (int)pr.rule.proto,
865 (int)pr.rule.keep_state,
866 (int)pr.rule.action);
867 printf(" description: \"%s\"\n", pr.rule.label);
868 #ifndef PF_NEWSTYLE
869 memset(&pp, 0, sizeof(pp));
870 strlcpy(pp.anchor, anchor_name, MAXPATHLEN);
871 pp.r_action = PF_RDR;
872 pp.r_num = i;
873 pp.ticket = pr.ticket;
874 if(ioctl(dev, DIOCGETADDRS, &pp) < 0)
875 perror("DIOCGETADDRS");
876 printf(" nb pool addr = %d ticket=%d\n", pp.nr, pp.ticket);
877 /*if(ioctl(dev, DIOCGETRULE, &pr) < 0)
878 perror("DIOCGETRULE"); */
879 pp.nr = 0; /* first */
880 if(ioctl(dev, DIOCGETADDR, &pp) < 0)
881 perror("DIOCGETADDR");
882 /* addr.v.a.addr.v4.s_addr */
883 printf(" %s\n", inet_ntop(AF_INET, &pp.addr.addr.v.a.addr.v4.s_addr, buf, 32));
884 #else
885 printf(" rule_flag=%08x action=%d direction=%d log=%d logif=%d "
886 "quick=%d ifnot=%d af=%d type=%d code=%d rdr.port_op=%d rdr.opts=%d\n",
887 pr.rule.rule_flag, pr.rule.action, pr.rule.direction,
888 pr.rule.log, pr.rule.logif, pr.rule.quick, pr.rule.ifnot,
889 pr.rule.af, pr.rule.type, pr.rule.code,
890 pr.rule.rdr.port_op, pr.rule.rdr.opts);
891 printf(" %s\n", inet_ntop(AF_INET, &pr.rule.rdr.addr.v.a.addr.v4.s_addr, buf, 32));
892 #endif
895 #endif