1 /* $Id: obsdrdr.c,v 1.74 2012/05/01 09:20:43 nanard Exp $ */
3 * http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/
4 * (c) 2006-2012 Thomas Bernard
5 * This software is subject to the conditions detailed
6 * in the LICENCE file provided within the distribution */
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
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
25 * - PF_ENABLE_FILTER_RULES
26 * If set, two rules are created : rdr + pass. Else a rdr/pass rule
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.
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>
42 #include <netinet/in.h>
43 #include <netinet/tcp.h>
44 #include <arpa/inet.h>
46 #include <net/pf/pfvar.h>
48 #include <net/pfvar.h>
51 #include <sys/ioctl.h>
58 #include "../macros.h"
59 #include "../config.h"
61 #include "../upnpglobalvars.h"
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
;
71 static struct timestamp_entry
* timestamp_list
= NULL
;
74 get_timestamp(unsigned short eport
, int proto
)
76 struct timestamp_entry
* e
;
79 if(e
->eport
== eport
&& e
->protocol
== (short)proto
)
87 remove_timestamp_entry(unsigned short eport
, int proto
)
89 struct timestamp_entry
* e
;
90 struct timestamp_entry
* * p
;
94 if(e
->eport
== eport
&& e
->protocol
== (short)proto
) {
95 /* remove the entry */
105 /* /dev/pf when opened */
108 /* shutdown_redirect() :
109 * close the /dev/pf device */
111 shutdown_redirect(void)
114 syslog(LOG_ERR
, "close(\"/dev/pf\"): %m");
118 /* open the device */
122 struct pf_status status
;
125 dev
= open("/dev/pf", O_RDWR
);
127 syslog(LOG_ERR
, "open(\"/dev/pf\"): %m");
130 if(ioctl(dev
, DIOCGETSTATUS
, &status
)<0) {
131 syslog(LOG_ERR
, "DIOCGETSTATUS: %m");
134 if(!status
.running
) {
135 syslog(LOG_ERR
, "pf is disabled");
144 clear_redirect_rules(void)
146 struct pfioc_trans io
;
147 struct pfioc_trans_e ioe
;
149 syslog(LOG_ERR
, "pf device is not open");
152 memset(&ioe
, 0, sizeof(ioe
));
154 io
.esize
= sizeof(ioe
);
157 ioe
.rs_num
= PF_RULESET_RDR
;
159 ioe
.type
= PF_TRANS_RULESET
;
161 strlcpy(ioe
.anchor
, anchor_name
, MAXPATHLEN
);
162 if(ioctl(dev
, DIOCXBEGIN
, &io
) < 0)
164 syslog(LOG_ERR
, "ioctl(dev, DIOCXBEGIN, ...): %m");
167 if(ioctl(dev
, DIOCXCOMMIT
, &io
) < 0)
169 syslog(LOG_ERR
, "ioctl(dev, DIOCXCOMMIT, ...): %m");
178 /* add_redirect_rule2() :
179 * create a rdr rule */
181 add_redirect_rule2(const char * ifname
,
182 const char * rhost
, unsigned short eport
,
183 const char * iaddr
, unsigned short iport
, int proto
,
184 const char * desc
, unsigned int timestamp
)
187 struct pfioc_rule pcr
;
189 struct pfioc_pooladdr pp
;
190 struct pf_pooladdr
*a
;
193 syslog(LOG_ERR
, "pf device is not open");
197 memset(&pcr
, 0, sizeof(pcr
));
198 strlcpy(pcr
.anchor
, anchor_name
, MAXPATHLEN
);
201 memset(&pp
, 0, sizeof(pp
));
202 strlcpy(pp
.anchor
, anchor_name
, MAXPATHLEN
);
203 if(ioctl(dev
, DIOCBEGINADDRS
, &pp
) < 0)
205 syslog(LOG_ERR
, "ioctl(dev, DIOCBEGINADDRS, ...): %m");
210 pcr
.pool_ticket
= pp
.ticket
;
214 pcr
.rule
.direction
= PF_IN
;
215 /*pcr.rule.src.addr.type = PF_ADDR_NONE;*/
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
;
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
);
226 pcr
.rule
.action
= PF_RDR
;
227 #ifndef PF_ENABLE_FILTER_RULES
228 pcr
.rule
.natpass
= 1;
230 pcr
.rule
.natpass
= 0;
233 #ifndef PF_ENABLE_FILTER_RULES
234 pcr
.rule
.action
= PF_PASS
;
236 pcr
.rule
.action
= PF_MATCH
;
239 pcr
.rule
.af
= AF_INET
;
240 #ifdef USE_IFNAME_IN_RULES
242 strlcpy(pcr
.rule
.ifname
, ifname
, IFNAMSIZ
);
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 */
249 #ifdef PFRULE_HAS_ONRDOMAIN
250 pcr
.rule
.onrdomain
= -1; /* first appeared in OpenBSD 5.0 */
253 pcr
.rule
.keep_state
= PF_STATE_NORMAL
;
255 strlcpy(pcr
.rule
.tagname
, tag
, PF_TAG_NAME_SIZE
);
256 strlcpy(pcr
.rule
.label
, desc
, PF_RULE_LABEL_SIZE
);
257 if(rhost
&& rhost
[0] != '\0' && rhost
[0] != '*')
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
);
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
);
271 memcpy(&pp
.addr
, a
, sizeof(struct pf_pooladdr
));
272 if(ioctl(dev
, DIOCADDADDR
, &pp
) < 0)
274 syslog(LOG_ERR
, "ioctl(dev, DIOCADDADDR, ...): %m");
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
);
287 pcr
.action
= PF_CHANGE_GET_TICKET
;
288 if(ioctl(dev
, DIOCCHANGERULE
, &pcr
) < 0)
290 syslog(LOG_ERR
, "ioctl(dev, DIOCCHANGERULE, ...) PF_CHANGE_GET_TICKET: %m");
295 pcr
.action
= PF_CHANGE_ADD_TAIL
;
296 if(ioctl(dev
, DIOCCHANGERULE
, &pcr
) < 0)
298 syslog(LOG_ERR
, "ioctl(dev, DIOCCHANGERULE, ...) PF_CHANGE_ADD_TAIL: %m");
307 if(r
== 0 && timestamp
> 0)
309 struct timestamp_entry
* tmp
;
310 tmp
= malloc(sizeof(struct timestamp_entry
));
313 tmp
->next
= timestamp_list
;
314 tmp
->timestamp
= timestamp
;
316 tmp
->protocol
= (short)proto
;
317 timestamp_list
= tmp
;
323 /* thanks to Seth Mos for this function */
325 add_filter_rule2(const char * ifname
,
326 const char * rhost
, const char * iaddr
,
327 unsigned short eport
, unsigned short iport
,
328 int proto
, const char * desc
)
330 #ifndef PF_ENABLE_FILTER_RULES
332 UNUSED(rhost
); UNUSED(iaddr
);
333 UNUSED(eport
); UNUSED(iport
);
334 UNUSED(proto
); UNUSED(desc
);
338 struct pfioc_rule pcr
;
340 struct pfioc_pooladdr pp
;
341 struct pf_pooladdr
*a
;
344 syslog(LOG_ERR
, "pf device is not open");
348 memset(&pcr
, 0, sizeof(pcr
));
349 strlcpy(pcr
.anchor
, anchor_name
, MAXPATHLEN
);
352 memset(&pp
, 0, sizeof(pp
));
353 strlcpy(pp
.anchor
, anchor_name
, MAXPATHLEN
);
354 if(ioctl(dev
, DIOCBEGINADDRS
, &pp
) < 0)
356 syslog(LOG_ERR
, "ioctl(dev, DIOCBEGINADDRS, ...): %m");
361 pcr
.pool_ticket
= pp
.ticket
;
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
374 strlcpy(pcr
.rule
.ifname
, ifname
, IFNAMSIZ
);
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
384 pcr
.rule
.rtableid
= -1; /* first appeared in OpenBSD 4.0 */
386 #ifdef PFRULE_HAS_ONRDOMAIN
387 pcr
.rule
.onrdomain
= -1; /* first appeared in OpenBSD 5.0 */
389 pcr
.rule
.keep_state
= 1;
390 strlcpy(pcr
.rule
.label
, desc
, PF_RULE_LABEL_SIZE
);
392 strlcpy(pcr
.rule
.qname
, queue
, PF_QNAME_SIZE
);
394 strlcpy(pcr
.rule
.tagname
, tag
, PF_TAG_NAME_SIZE
);
396 if(rhost
&& rhost
[0] != '\0' && rhost
[0] != '*')
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
);
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
);
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)); */
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)
419 syslog(LOG_ERR
, "ioctl(dev, DIOCADDADDR, ...): %m");
428 pcr
.action
= PF_CHANGE_GET_TICKET
;
429 if(ioctl(dev
, DIOCCHANGERULE
, &pcr
) < 0)
431 syslog(LOG_ERR
, "ioctl(dev, DIOCCHANGERULE, ...) PF_CHANGE_GET_TICKET: %m");
436 pcr
.action
= PF_CHANGE_ADD_TAIL
;
437 if(ioctl(dev
, DIOCCHANGERULE
, &pcr
) < 0)
439 syslog(LOG_ERR
, "ioctl(dev, DIOCCHANGERULE, ...) PF_CHANGE_ADD_TAIL: %m");
452 /* get_redirect_rule()
453 * return value : 0 success (found)
454 * -1 = error or rule not found */
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
,
459 char * rhost
, int rhostlen
,
460 unsigned int * timestamp
,
461 u_int64_t
* packets
, u_int64_t
* bytes
)
464 struct pfioc_rule pr
;
466 struct pfioc_pooladdr pp
;
471 syslog(LOG_ERR
, "pf device is not open");
474 memset(&pr
, 0, sizeof(pr
));
475 strlcpy(pr
.anchor
, anchor_name
, MAXPATHLEN
);
477 pr
.rule
.action
= PF_RDR
;
479 if(ioctl(dev
, DIOCGETRULES
, &pr
) < 0)
481 syslog(LOG_ERR
, "ioctl(dev, DIOCGETRULES, ...): %m");
488 if(ioctl(dev
, DIOCGETRULE
, &pr
) < 0)
490 syslog(LOG_ERR
, "ioctl(dev, DIOCGETRULE): %m");
493 if( (eport
== ntohs(pr
.rule
.dst
.port
[0]))
494 && (eport
== ntohs(pr
.rule
.dst
.port
[1]))
495 && (pr
.rule
.proto
== proto
) )
498 *iport
= pr
.rule
.rpool
.proxy_port
[0];
500 *iport
= pr
.rule
.rdr
.proxy_port
[0];
503 strlcpy(desc
, pr
.rule
.label
, desclen
);
504 #ifdef PFRULE_INOUT_COUNTS
506 *packets
= pr
.rule
.packets
[0] + pr
.rule
.packets
[1];
508 *bytes
= pr
.rule
.bytes
[0] + pr
.rule
.bytes
[1];
511 *packets
= pr
.rule
.packets
;
513 *bytes
= pr
.rule
.bytes
;
516 memset(&pp
, 0, sizeof(pp
));
517 strlcpy(pp
.anchor
, anchor_name
, MAXPATHLEN
);
518 pp
.r_action
= PF_RDR
;
520 pp
.ticket
= pr
.ticket
;
521 if(ioctl(dev
, DIOCGETADDRS
, &pp
) < 0)
523 syslog(LOG_ERR
, "ioctl(dev, DIOCGETADDRS, ...): %m");
528 syslog(LOG_NOTICE
, "No address associated with pf rule");
531 pp
.nr
= 0; /* first */
532 if(ioctl(dev
, DIOCGETADDR
, &pp
) < 0)
534 syslog(LOG_ERR
, "ioctl(dev, DIOCGETADDR, ...): %m");
537 inet_ntop(AF_INET
, &pp
.addr
.addr
.v
.a
.addr
.v4
.s_addr
,
540 inet_ntop(AF_INET
, &pr
.rule
.rdr
.addr
.v
.a
.addr
.v4
.s_addr
,
543 if(rhost
&& rhostlen
> 0)
545 if (pr
.rule
.src
.addr
.v
.a
.addr
.v4
.s_addr
== 0)
547 rhost
[0] = '\0'; /* empty string */
551 inet_ntop(AF_INET
, &pr
.rule
.src
.addr
.v
.a
.addr
.v4
.s_addr
,
556 *timestamp
= get_timestamp(eport
, proto
);
565 delete_redirect_rule(const char * ifname
, unsigned short eport
, int proto
)
568 struct pfioc_rule pr
;
572 syslog(LOG_ERR
, "pf device is not open");
575 memset(&pr
, 0, sizeof(pr
));
576 strlcpy(pr
.anchor
, anchor_name
, MAXPATHLEN
);
578 pr
.rule
.action
= PF_RDR
;
580 if(ioctl(dev
, DIOCGETRULES
, &pr
) < 0)
582 syslog(LOG_ERR
, "ioctl(dev, DIOCGETRULES, ...): %m");
589 if(ioctl(dev
, DIOCGETRULE
, &pr
) < 0)
591 syslog(LOG_ERR
, "ioctl(dev, DIOCGETRULE): %m");
594 if( (eport
== ntohs(pr
.rule
.dst
.port
[0]))
595 && (eport
== ntohs(pr
.rule
.dst
.port
[1]))
596 && (pr
.rule
.proto
== proto
) )
598 pr
.action
= PF_CHANGE_GET_TICKET
;
599 if(ioctl(dev
, DIOCCHANGERULE
, &pr
) < 0)
601 syslog(LOG_ERR
, "ioctl(dev, DIOCCHANGERULE, ...) PF_CHANGE_GET_TICKET: %m");
604 pr
.action
= PF_CHANGE_REMOVE
;
606 if(ioctl(dev
, DIOCCHANGERULE
, &pr
) < 0)
608 syslog(LOG_ERR
, "ioctl(dev, DIOCCHANGERULE, ...) PF_CHANGE_REMOVE: %m");
611 remove_timestamp_entry(eport
, proto
);
620 delete_filter_rule(const char * ifname
, unsigned short eport
, int proto
)
622 #ifndef PF_ENABLE_FILTER_RULES
623 UNUSED(ifname
); UNUSED(eport
); UNUSED(proto
);
627 struct pfioc_rule pr
;
629 syslog(LOG_ERR
, "pf device is not open");
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)
637 syslog(LOG_ERR
, "ioctl(dev, DIOCGETRULES, ...): %m");
644 if(ioctl(dev
, DIOCGETRULE
, &pr
) < 0)
646 syslog(LOG_ERR
, "ioctl(dev, DIOCGETRULE): %m");
649 if( (eport
== ntohs(pr
.rule
.dst
.port
[0]))
650 && (pr
.rule
.proto
== proto
) )
652 pr
.action
= PF_CHANGE_GET_TICKET
;
653 if(ioctl(dev
, DIOCCHANGERULE
, &pr
) < 0)
655 syslog(LOG_ERR
, "ioctl(dev, DIOCCHANGERULE, ...) PF_CHANGE_GET_TICKET: %m");
658 pr
.action
= PF_CHANGE_REMOVE
;
660 if(ioctl(dev
, DIOCCHANGERULE
, &pr
) < 0)
662 syslog(LOG_ERR
, "ioctl(dev, DIOCCHANGERULE, ...) PF_CHANGE_REMOVE: %m");
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
,
678 char * rhost
, int rhostlen
,
679 unsigned int * timestamp
,
680 u_int64_t
* packets
, u_int64_t
* bytes
)
683 struct pfioc_rule pr
;
685 struct pfioc_pooladdr pp
;
690 syslog(LOG_ERR
, "pf device is not open");
693 memset(&pr
, 0, sizeof(pr
));
694 strlcpy(pr
.anchor
, anchor_name
, MAXPATHLEN
);
696 pr
.rule
.action
= PF_RDR
;
698 if(ioctl(dev
, DIOCGETRULES
, &pr
) < 0)
700 syslog(LOG_ERR
, "ioctl(dev, DIOCGETRULES, ...): %m");
707 if(ioctl(dev
, DIOCGETRULE
, &pr
) < 0)
709 syslog(LOG_ERR
, "ioctl(dev, DIOCGETRULE): %m");
712 *proto
= pr
.rule
.proto
;
713 *eport
= ntohs(pr
.rule
.dst
.port
[0]);
715 *iport
= pr
.rule
.rpool
.proxy_port
[0];
717 *iport
= pr
.rule
.rdr
.proxy_port
[0];
720 strlcpy(ifname
, pr
.rule
.ifname
, IFNAMSIZ
);
722 strlcpy(desc
, pr
.rule
.label
, desclen
);
723 #ifdef PFRULE_INOUT_COUNTS
725 *packets
= pr
.rule
.packets
[0] + pr
.rule
.packets
[1];
727 *bytes
= pr
.rule
.bytes
[0] + pr
.rule
.bytes
[1];
730 *packets
= pr
.rule
.packets
;
732 *bytes
= pr
.rule
.bytes
;
735 memset(&pp
, 0, sizeof(pp
));
736 strlcpy(pp
.anchor
, anchor_name
, MAXPATHLEN
);
737 pp
.r_action
= PF_RDR
;
739 pp
.ticket
= pr
.ticket
;
740 if(ioctl(dev
, DIOCGETADDRS
, &pp
) < 0)
742 syslog(LOG_ERR
, "ioctl(dev, DIOCGETADDRS, ...): %m");
747 syslog(LOG_NOTICE
, "No address associated with pf rule");
750 pp
.nr
= 0; /* first */
751 if(ioctl(dev
, DIOCGETADDR
, &pp
) < 0)
753 syslog(LOG_ERR
, "ioctl(dev, DIOCGETADDR, ...): %m");
756 inet_ntop(AF_INET
, &pp
.addr
.addr
.v
.a
.addr
.v4
.s_addr
,
759 inet_ntop(AF_INET
, &pr
.rule
.rdr
.addr
.v
.a
.addr
.v4
.s_addr
,
762 if(rhost
&& rhostlen
> 0)
764 if (pr
.rule
.src
.addr
.v
.a
.addr
.v4
.s_addr
== 0)
766 rhost
[0] = '\0'; /* empty string */
770 inet_ntop(AF_INET
, &pr
.rule
.src
.addr
.v
.a
.addr
.v4
.s_addr
,
775 *timestamp
= get_timestamp(*eport
, *proto
);
781 /* return an (malloc'ed) array of "external" port for which there is
782 * a port mapping. number is the size of the array */
784 get_portmappings_in_range(unsigned short startport
, unsigned short endport
,
785 int proto
, unsigned int * number
)
787 unsigned short * array
;
788 unsigned int capacity
;
790 unsigned short eport
;
791 struct pfioc_rule pr
;
795 syslog(LOG_ERR
, "pf device is not open");
799 array
= calloc(capacity
, sizeof(unsigned short));
802 syslog(LOG_ERR
, "get_portmappings_in_range() : calloc error");
805 memset(&pr
, 0, sizeof(pr
));
806 strlcpy(pr
.anchor
, anchor_name
, MAXPATHLEN
);
808 pr
.rule
.action
= PF_RDR
;
810 if(ioctl(dev
, DIOCGETRULES
, &pr
) < 0)
812 syslog(LOG_ERR
, "ioctl(dev, DIOCGETRULES, ...): %m");
820 if(ioctl(dev
, DIOCGETRULE
, &pr
) < 0)
822 syslog(LOG_ERR
, "ioctl(dev, DIOCGETRULE): %m");
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
) )
830 if(*number
>= capacity
)
832 /* need to increase the capacity of the array */
834 array
= realloc(array
, sizeof(unsigned short)*capacity
);
837 syslog(LOG_ERR
, "get_portmappings_in_range() : realloc(%lu) error", sizeof(unsigned short)*capacity
);
842 array
[*number
] = eport
;
849 /* this function is only for testing */
856 struct pfioc_rule pr
;
858 struct pfioc_pooladdr pp
;
863 perror("pf dev not open");
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
);
875 printf("-- rule %d --\n", i
);
877 if(ioctl(dev
, DIOCGETRULE
, &pr
) < 0)
878 perror("DIOCGETRULE");
879 printf(" %s %s %d:%d -> %d:%d proto %d keep_state=%d action=%d\n",
881 inet_ntop(AF_INET
, &pr
.rule
.src
.addr
.v
.a
.addr
.v4
.s_addr
, buf
, 32),
882 (int)ntohs(pr
.rule
.dst
.port
[0]),
883 (int)ntohs(pr
.rule
.dst
.port
[1]),
885 (int)pr
.rule
.rpool
.proxy_port
[0],
886 (int)pr
.rule
.rpool
.proxy_port
[1],
888 (int)pr
.rule
.rdr
.proxy_port
[0],
889 (int)pr
.rule
.rdr
.proxy_port
[1],
892 (int)pr
.rule
.keep_state
,
893 (int)pr
.rule
.action
);
894 printf(" description: \"%s\"\n", pr
.rule
.label
);
896 memset(&pp
, 0, sizeof(pp
));
897 strlcpy(pp
.anchor
, anchor_name
, MAXPATHLEN
);
898 pp
.r_action
= PF_RDR
;
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));
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));