1 /* $Id: obsdrdr.c,v 1.83 2014/06/27 13:08:49 nanard Exp $ */
3 * http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/
4 * (c) 2006-2014 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 * keep state label "test label" -> 192.168.0.42 port 12345
13 * or a rdr rule + a pass rule :
14 * rdr quick on xl1 inet proto udp from any to any port = 54321 \
15 * keep state label "test label" -> 192.168.0.42 port 12345
16 * pass in quick on xl1 inet proto udp from any to 192.168.0.42 port = 12345 \
17 * flags S/SA keep state label "test label"
19 * - OpenBSD starting from version 4.7
20 * match in on xl1 inet proto udp from any to any port 54321 \
21 * label "test label" rdr-to 192.168.0.42 port 12345
23 * pass in quick on xl1 inet proto udp from any to any port 54321 \
24 * label "test label" rdr-to 192.168.0.42 port 12345
29 * - PF_ENABLE_FILTER_RULES
30 * If set, two rules are created : rdr + pass. Else a rdr/pass rule
32 * - USE_IFNAME_IN_RULES
33 * If set the interface name is set in the rule.
34 * - PFRULE_INOUT_COUNTS
35 * Must be set with OpenBSD version 3.8 and up.
36 * - PFRULE_HAS_RTABLEID
37 * Must be set with OpenBSD version 4.0 and up.
39 * Must be set with OpenBSD version 4.7 and up.
42 #include <sys/types.h>
43 #include <sys/socket.h>
44 #include <sys/param.h>
46 #include <netinet/in.h>
47 #include <netinet/tcp.h>
48 #include <arpa/inet.h>
50 #include <net/pf/pfvar.h>
55 #include <net/pfvar.h>
58 #include <sys/ioctl.h>
65 #include "../macros.h"
66 #include "../config.h"
68 #include "../upnpglobalvars.h"
71 #error "USE_PF macro is undefined, check consistency between config.h and Makefile"
74 /* list too keep timestamps for port mappings having a lease duration */
75 struct timestamp_entry
{
76 struct timestamp_entry
* next
;
77 unsigned int timestamp
;
82 static struct timestamp_entry
* timestamp_list
= NULL
;
85 get_timestamp(unsigned short eport
, int proto
)
87 struct timestamp_entry
* e
;
90 if(e
->eport
== eport
&& e
->protocol
== (short)proto
)
98 remove_timestamp_entry(unsigned short eport
, int proto
)
100 struct timestamp_entry
* e
;
101 struct timestamp_entry
* * p
;
105 if(e
->eport
== eport
&& e
->protocol
== (short)proto
) {
106 /* remove the entry */
116 /* /dev/pf when opened */
119 /* shutdown_redirect() :
120 * close the /dev/pf device */
122 shutdown_redirect(void)
125 syslog(LOG_ERR
, "close(\"/dev/pf\"): %m");
129 /* open the device */
133 struct pf_status status
;
136 dev
= open("/dev/pf", O_RDWR
);
138 syslog(LOG_ERR
, "open(\"/dev/pf\"): %m");
141 if(ioctl(dev
, DIOCGETSTATUS
, &status
)<0) {
142 syslog(LOG_ERR
, "DIOCGETSTATUS: %m");
145 if(!status
.running
) {
146 syslog(LOG_ERR
, "pf is disabled");
155 clear_redirect_rules(void)
157 struct pfioc_trans io
;
158 struct pfioc_trans_e ioe
;
160 syslog(LOG_ERR
, "pf device is not open");
163 memset(&ioe
, 0, sizeof(ioe
));
165 io
.esize
= sizeof(ioe
);
168 ioe
.rs_num
= PF_RULESET_RDR
;
170 ioe
.type
= PF_TRANS_RULESET
;
172 strlcpy(ioe
.anchor
, anchor_name
, MAXPATHLEN
);
173 if(ioctl(dev
, DIOCXBEGIN
, &io
) < 0)
175 syslog(LOG_ERR
, "ioctl(dev, DIOCXBEGIN, ...): %m");
178 if(ioctl(dev
, DIOCXCOMMIT
, &io
) < 0)
180 syslog(LOG_ERR
, "ioctl(dev, DIOCXCOMMIT, ...): %m");
189 clear_filter_rules(void)
191 #ifndef PF_ENABLE_FILTER_RULES
194 struct pfioc_trans io
;
195 struct pfioc_trans_e ioe
;
197 syslog(LOG_ERR
, "pf device is not open");
200 memset(&ioe
, 0, sizeof(ioe
));
202 io
.esize
= sizeof(ioe
);
205 ioe
.rs_num
= PF_RULESET_FILTER
;
208 ioe
.type
= PF_TRANS_RULESET
;
210 strlcpy(ioe
.anchor
, anchor_name
, MAXPATHLEN
);
211 if(ioctl(dev
, DIOCXBEGIN
, &io
) < 0)
213 syslog(LOG_ERR
, "ioctl(dev, DIOCXBEGIN, ...): %m");
216 if(ioctl(dev
, DIOCXCOMMIT
, &io
) < 0)
218 syslog(LOG_ERR
, "ioctl(dev, DIOCXCOMMIT, ...): %m");
228 /* add_redirect_rule2() :
229 * create a rdr rule */
231 add_redirect_rule2(const char * ifname
,
232 const char * rhost
, unsigned short eport
,
233 const char * iaddr
, unsigned short iport
, int proto
,
234 const char * desc
, unsigned int timestamp
)
237 struct pfioc_rule pcr
;
239 struct pfioc_pooladdr pp
;
240 struct pf_pooladdr
*a
;
243 syslog(LOG_ERR
, "pf device is not open");
247 memset(&pcr
, 0, sizeof(pcr
));
248 strlcpy(pcr
.anchor
, anchor_name
, MAXPATHLEN
);
251 memset(&pp
, 0, sizeof(pp
));
252 strlcpy(pp
.anchor
, anchor_name
, MAXPATHLEN
);
253 if(ioctl(dev
, DIOCBEGINADDRS
, &pp
) < 0)
255 syslog(LOG_ERR
, "ioctl(dev, DIOCBEGINADDRS, ...): %m");
260 pcr
.pool_ticket
= pp
.ticket
;
264 pcr
.rule
.direction
= PF_IN
;
265 /*pcr.rule.src.addr.type = PF_ADDR_NONE;*/
266 pcr
.rule
.src
.addr
.type
= PF_ADDR_ADDRMASK
;
267 pcr
.rule
.dst
.addr
.type
= PF_ADDR_ADDRMASK
;
268 pcr
.rule
.nat
.addr
.type
= PF_ADDR_NONE
;
269 pcr
.rule
.rdr
.addr
.type
= PF_ADDR_ADDRMASK
;
273 pcr
.rule
.dst
.xport
.range
.op
= PF_OP_EQ
;
274 pcr
.rule
.dst
.xport
.range
.port
[0] = htons(eport
);
275 pcr
.rule
.dst
.xport
.range
.port
[1] = htons(eport
);
277 pcr
.rule
.dst
.port_op
= PF_OP_EQ
;
278 pcr
.rule
.dst
.port
[0] = htons(eport
);
279 pcr
.rule
.dst
.port
[1] = htons(eport
);
282 pcr
.rule
.action
= PF_RDR
;
283 #ifndef PF_ENABLE_FILTER_RULES
284 pcr
.rule
.natpass
= 1;
286 pcr
.rule
.natpass
= 0;
289 #ifndef PF_ENABLE_FILTER_RULES
290 pcr
.rule
.action
= PF_PASS
;
292 pcr
.rule
.action
= PF_MATCH
;
295 pcr
.rule
.af
= AF_INET
;
296 #ifdef USE_IFNAME_IN_RULES
298 strlcpy(pcr
.rule
.ifname
, ifname
, IFNAMSIZ
);
300 pcr
.rule
.proto
= proto
;
301 pcr
.rule
.log
= (GETFLAG(LOGPACKETSMASK
))?1:0; /*logpackets;*/
302 #ifdef PFRULE_HAS_RTABLEID
303 pcr
.rule
.rtableid
= -1; /* first appeared in OpenBSD 4.0 */
305 #ifdef PFRULE_HAS_ONRDOMAIN
306 pcr
.rule
.onrdomain
= -1; /* first appeared in OpenBSD 5.0 */
309 pcr
.rule
.keep_state
= PF_STATE_NORMAL
;
311 strlcpy(pcr
.rule
.tagname
, tag
, PF_TAG_NAME_SIZE
);
312 strlcpy(pcr
.rule
.label
, desc
, PF_RULE_LABEL_SIZE
);
313 if(rhost
&& rhost
[0] != '\0' && rhost
[0] != '*')
315 inet_pton(AF_INET
, rhost
, &pcr
.rule
.src
.addr
.v
.a
.addr
.v4
.s_addr
);
316 pcr
.rule
.src
.addr
.v
.a
.mask
.v4
.s_addr
= htonl(INADDR_NONE
);
319 pcr
.rule
.rpool
.proxy_port
[0] = iport
;
320 pcr
.rule
.rpool
.proxy_port
[1] = iport
;
321 TAILQ_INIT(&pcr
.rule
.rpool
.list
);
322 a
= calloc(1, sizeof(struct pf_pooladdr
));
323 inet_pton(AF_INET
, iaddr
, &a
->addr
.v
.a
.addr
.v4
.s_addr
);
324 a
->addr
.v
.a
.mask
.v4
.s_addr
= htonl(INADDR_NONE
);
325 TAILQ_INSERT_TAIL(&pcr
.rule
.rpool
.list
, a
, entries
);
327 memcpy(&pp
.addr
, a
, sizeof(struct pf_pooladdr
));
328 if(ioctl(dev
, DIOCADDADDR
, &pp
) < 0)
330 syslog(LOG_ERR
, "ioctl(dev, DIOCADDADDR, ...): %m");
336 pcr
.rule
.rdr
.proxy_port
[0] = iport
;
337 pcr
.rule
.rdr
.proxy_port
[1] = iport
;
338 inet_pton(AF_INET
, iaddr
, &pcr
.rule
.rdr
.addr
.v
.a
.addr
.v4
.s_addr
);
339 pcr
.rule
.rdr
.addr
.v
.a
.mask
.v4
.s_addr
= htonl(INADDR_NONE
);
343 pcr
.action
= PF_CHANGE_GET_TICKET
;
344 if(ioctl(dev
, DIOCCHANGERULE
, &pcr
) < 0)
346 syslog(LOG_ERR
, "ioctl(dev, DIOCCHANGERULE, ...) PF_CHANGE_GET_TICKET: %m");
351 pcr
.action
= PF_CHANGE_ADD_TAIL
;
352 if(ioctl(dev
, DIOCCHANGERULE
, &pcr
) < 0)
354 syslog(LOG_ERR
, "ioctl(dev, DIOCCHANGERULE, ...) PF_CHANGE_ADD_TAIL: %m");
363 if(r
== 0 && timestamp
> 0)
365 struct timestamp_entry
* tmp
;
366 tmp
= malloc(sizeof(struct timestamp_entry
));
369 tmp
->next
= timestamp_list
;
370 tmp
->timestamp
= timestamp
;
372 tmp
->protocol
= (short)proto
;
373 timestamp_list
= tmp
;
379 /* thanks to Seth Mos for this function */
381 add_filter_rule2(const char * ifname
,
382 const char * rhost
, const char * iaddr
,
383 unsigned short eport
, unsigned short iport
,
384 int proto
, const char * desc
)
386 #ifndef PF_ENABLE_FILTER_RULES
388 UNUSED(rhost
); UNUSED(iaddr
);
389 UNUSED(eport
); UNUSED(iport
);
390 UNUSED(proto
); UNUSED(desc
);
394 struct pfioc_rule pcr
;
396 struct pfioc_pooladdr pp
;
398 #ifndef USE_IFNAME_IN_RULES
403 syslog(LOG_ERR
, "pf device is not open");
407 memset(&pcr
, 0, sizeof(pcr
));
408 strlcpy(pcr
.anchor
, anchor_name
, MAXPATHLEN
);
411 memset(&pp
, 0, sizeof(pp
));
412 strlcpy(pp
.anchor
, anchor_name
, MAXPATHLEN
);
413 if(ioctl(dev
, DIOCBEGINADDRS
, &pp
) < 0)
415 syslog(LOG_ERR
, "ioctl(dev, DIOCBEGINADDRS, ...): %m");
420 pcr
.pool_ticket
= pp
.ticket
;
425 pcr
.rule
.dst
.port_op
= PF_OP_EQ
;
426 pcr
.rule
.dst
.port
[0] = htons(iport
);
427 pcr
.rule
.direction
= PF_IN
;
428 pcr
.rule
.action
= PF_PASS
;
429 pcr
.rule
.af
= AF_INET
;
430 #ifdef USE_IFNAME_IN_RULES
432 strlcpy(pcr
.rule
.ifname
, ifname
, IFNAMSIZ
);
434 pcr
.rule
.proto
= proto
;
435 pcr
.rule
.quick
= (GETFLAG(PFNOQUICKRULESMASK
))?0:1;
436 pcr
.rule
.log
= (GETFLAG(LOGPACKETSMASK
))?1:0; /*logpackets;*/
437 /* see the discussion on the forum :
438 * http://miniupnp.tuxfamily.org/forum/viewtopic.php?p=638 */
439 pcr
.rule
.flags
= TH_SYN
;
440 pcr
.rule
.flagset
= (TH_SYN
|TH_ACK
);
441 #ifdef PFRULE_HAS_RTABLEID
442 pcr
.rule
.rtableid
= -1; /* first appeared in OpenBSD 4.0 */
444 #ifdef PFRULE_HAS_ONRDOMAIN
445 pcr
.rule
.onrdomain
= -1; /* first appeared in OpenBSD 5.0 */
447 pcr
.rule
.keep_state
= 1;
448 strlcpy(pcr
.rule
.label
, desc
, PF_RULE_LABEL_SIZE
);
450 strlcpy(pcr
.rule
.qname
, queue
, PF_QNAME_SIZE
);
452 strlcpy(pcr
.rule
.tagname
, tag
, PF_TAG_NAME_SIZE
);
454 if(rhost
&& rhost
[0] != '\0' && rhost
[0] != '*')
456 inet_pton(AF_INET
, rhost
, &pcr
.rule
.src
.addr
.v
.a
.addr
.v4
.s_addr
);
457 pcr
.rule
.src
.addr
.v
.a
.mask
.v4
.s_addr
= htonl(INADDR_NONE
);
459 /* we want any - iaddr port = # keep state label */
460 inet_pton(AF_INET
, iaddr
, &pcr
.rule
.dst
.addr
.v
.a
.addr
.v4
.s_addr
);
461 pcr
.rule
.dst
.addr
.v
.a
.mask
.v4
.s_addr
= htonl(INADDR_NONE
);
463 pcr
.rule
.rpool
.proxy_port
[0] = iport
;
464 pcr
.rule
.rpool
.proxy_port
[1] = iport
;
465 TAILQ_INIT(&pcr
.rule
.rpool
.list
);
469 pcr
.action
= PF_CHANGE_GET_TICKET
;
470 if(ioctl(dev
, DIOCCHANGERULE
, &pcr
) < 0)
472 syslog(LOG_ERR
, "ioctl(dev, DIOCCHANGERULE, ...) PF_CHANGE_GET_TICKET: %m");
477 pcr
.action
= PF_CHANGE_ADD_TAIL
;
478 if(ioctl(dev
, DIOCCHANGERULE
, &pcr
) < 0)
480 syslog(LOG_ERR
, "ioctl(dev, DIOCCHANGERULE, ...) PF_CHANGE_ADD_TAIL: %m");
490 /* get_redirect_rule()
491 * return value : 0 success (found)
492 * -1 = error or rule not found */
494 get_redirect_rule(const char * ifname
, unsigned short eport
, int proto
,
495 char * iaddr
, int iaddrlen
, unsigned short * iport
,
496 char * desc
, int desclen
,
497 char * rhost
, int rhostlen
,
498 unsigned int * timestamp
,
499 u_int64_t
* packets
, u_int64_t
* bytes
)
502 struct pfioc_rule pr
;
504 struct pfioc_pooladdr pp
;
509 syslog(LOG_ERR
, "pf device is not open");
512 memset(&pr
, 0, sizeof(pr
));
513 strlcpy(pr
.anchor
, anchor_name
, MAXPATHLEN
);
515 pr
.rule
.action
= PF_RDR
;
517 if(ioctl(dev
, DIOCGETRULES
, &pr
) < 0)
519 syslog(LOG_ERR
, "ioctl(dev, DIOCGETRULES, ...): %m");
526 if(ioctl(dev
, DIOCGETRULE
, &pr
) < 0)
528 syslog(LOG_ERR
, "ioctl(dev, DIOCGETRULE): %m");
532 if( (eport
== ntohs(pr
.rule
.dst
.xport
.range
.port
[0]))
533 && (eport
== ntohs(pr
.rule
.dst
.xport
.range
.port
[1]))
535 if( (eport
== ntohs(pr
.rule
.dst
.port
[0]))
536 && (eport
== ntohs(pr
.rule
.dst
.port
[1]))
538 && (pr
.rule
.proto
== proto
) )
541 *iport
= pr
.rule
.rpool
.proxy_port
[0];
543 *iport
= pr
.rule
.rdr
.proxy_port
[0];
546 strlcpy(desc
, pr
.rule
.label
, desclen
);
547 #ifdef PFRULE_INOUT_COUNTS
549 *packets
= pr
.rule
.packets
[0] + pr
.rule
.packets
[1];
551 *bytes
= pr
.rule
.bytes
[0] + pr
.rule
.bytes
[1];
554 *packets
= pr
.rule
.packets
;
556 *bytes
= pr
.rule
.bytes
;
559 memset(&pp
, 0, sizeof(pp
));
560 strlcpy(pp
.anchor
, anchor_name
, MAXPATHLEN
);
561 pp
.r_action
= PF_RDR
;
563 pp
.ticket
= pr
.ticket
;
564 if(ioctl(dev
, DIOCGETADDRS
, &pp
) < 0)
566 syslog(LOG_ERR
, "ioctl(dev, DIOCGETADDRS, ...): %m");
571 syslog(LOG_NOTICE
, "No address associated with pf rule");
574 pp
.nr
= 0; /* first */
575 if(ioctl(dev
, DIOCGETADDR
, &pp
) < 0)
577 syslog(LOG_ERR
, "ioctl(dev, DIOCGETADDR, ...): %m");
580 inet_ntop(AF_INET
, &pp
.addr
.addr
.v
.a
.addr
.v4
.s_addr
,
583 inet_ntop(AF_INET
, &pr
.rule
.rdr
.addr
.v
.a
.addr
.v4
.s_addr
,
586 if(rhost
&& rhostlen
> 0)
588 if (pr
.rule
.src
.addr
.v
.a
.addr
.v4
.s_addr
== 0)
590 rhost
[0] = '\0'; /* empty string */
594 inet_ntop(AF_INET
, &pr
.rule
.src
.addr
.v
.a
.addr
.v4
.s_addr
,
599 *timestamp
= get_timestamp(eport
, proto
);
608 priv_delete_redirect_rule(const char * ifname
, unsigned short eport
,
609 int proto
, unsigned short * iport
,
613 struct pfioc_rule pr
;
617 syslog(LOG_ERR
, "pf device is not open");
620 memset(&pr
, 0, sizeof(pr
));
621 strlcpy(pr
.anchor
, anchor_name
, MAXPATHLEN
);
623 pr
.rule
.action
= PF_RDR
;
625 if(ioctl(dev
, DIOCGETRULES
, &pr
) < 0)
627 syslog(LOG_ERR
, "ioctl(dev, DIOCGETRULES, ...): %m");
634 if(ioctl(dev
, DIOCGETRULE
, &pr
) < 0)
636 syslog(LOG_ERR
, "ioctl(dev, DIOCGETRULE): %m");
640 if( (eport
== ntohs(pr
.rule
.dst
.xport
.range
.port
[0]))
641 && (eport
== ntohs(pr
.rule
.dst
.xport
.range
.port
[1]))
643 if( (eport
== ntohs(pr
.rule
.dst
.port
[0]))
644 && (eport
== ntohs(pr
.rule
.dst
.port
[1]))
646 && (pr
.rule
.proto
== proto
) )
648 /* retrieve iport in order to remove filter rule */
650 if(iport
) *iport
= pr
.rule
.rpool
.proxy_port
[0];
653 /* retrieve internal address */
654 struct pfioc_pooladdr pp
;
655 memset(&pp
, 0, sizeof(pp
));
656 strlcpy(pp
.anchor
, anchor_name
, MAXPATHLEN
);
657 pp
.r_action
= PF_RDR
;
659 pp
.ticket
= pr
.ticket
;
660 if(ioctl(dev
, DIOCGETADDRS
, &pp
) < 0)
662 syslog(LOG_ERR
, "ioctl(dev, DIOCGETADDRS, ...): %m");
667 syslog(LOG_NOTICE
, "No address associated with pf rule");
670 pp
.nr
= 0; /* first */
671 if(ioctl(dev
, DIOCGETADDR
, &pp
) < 0)
673 syslog(LOG_ERR
, "ioctl(dev, DIOCGETADDR, ...): %m");
676 *iaddr
= pp
.addr
.addr
.v
.a
.addr
.v4
.s_addr
;
679 if(iport
) *iport
= pr
.rule
.rdr
.proxy_port
[0];
682 /* retrieve internal address */
683 *iaddr
= pr
.rule
.rdr
.addr
.v
.a
.addr
.v4
.s_addr
;
686 pr
.action
= PF_CHANGE_GET_TICKET
;
687 if(ioctl(dev
, DIOCCHANGERULE
, &pr
) < 0)
689 syslog(LOG_ERR
, "ioctl(dev, DIOCCHANGERULE, ...) PF_CHANGE_GET_TICKET: %m");
692 pr
.action
= PF_CHANGE_REMOVE
;
694 if(ioctl(dev
, DIOCCHANGERULE
, &pr
) < 0)
696 syslog(LOG_ERR
, "ioctl(dev, DIOCCHANGERULE, ...) PF_CHANGE_REMOVE: %m");
699 remove_timestamp_entry(eport
, proto
);
708 delete_redirect_rule(const char * ifname
, unsigned short eport
,
711 return priv_delete_redirect_rule(ifname
, eport
, proto
, NULL
, NULL
);
715 priv_delete_filter_rule(const char * ifname
, unsigned short iport
,
716 int proto
, in_addr_t iaddr
)
718 #ifndef PF_ENABLE_FILTER_RULES
719 UNUSED(ifname
); UNUSED(iport
); UNUSED(proto
); UNUSED(iaddr
);
723 struct pfioc_rule pr
;
726 syslog(LOG_ERR
, "pf device is not open");
729 memset(&pr
, 0, sizeof(pr
));
730 strlcpy(pr
.anchor
, anchor_name
, MAXPATHLEN
);
731 pr
.rule
.action
= PF_PASS
;
732 if(ioctl(dev
, DIOCGETRULES
, &pr
) < 0)
734 syslog(LOG_ERR
, "ioctl(dev, DIOCGETRULES, ...): %m");
741 if(ioctl(dev
, DIOCGETRULE
, &pr
) < 0)
743 syslog(LOG_ERR
, "ioctl(dev, DIOCGETRULE): %m");
747 syslog(LOG_DEBUG
, "%2d port=%hu proto=%d addr=%8x",
748 i
, ntohs(pr
.rule
.dst
.port
[0]), pr
.rule
.proto
,
749 pr
.rule
.dst
.addr
.v
.a
.addr
.v4
.s_addr
);
750 /*pr.rule.dst.addr.v.a.mask.v4.s_addr*/
752 if( (iport
== ntohs(pr
.rule
.dst
.port
[0]))
753 && (pr
.rule
.proto
== proto
) &&
754 (iaddr
== pr
.rule
.dst
.addr
.v
.a
.addr
.v4
.s_addr
)
757 pr
.action
= PF_CHANGE_GET_TICKET
;
758 if(ioctl(dev
, DIOCCHANGERULE
, &pr
) < 0)
760 syslog(LOG_ERR
, "ioctl(dev, DIOCCHANGERULE, ...) PF_CHANGE_GET_TICKET: %m");
763 pr
.action
= PF_CHANGE_REMOVE
;
765 if(ioctl(dev
, DIOCCHANGERULE
, &pr
) < 0)
767 syslog(LOG_ERR
, "ioctl(dev, DIOCCHANGERULE, ...) PF_CHANGE_REMOVE: %m");
779 delete_redirect_and_filter_rules(const char * ifname
, unsigned short eport
,
783 unsigned short iport
;
785 r
= priv_delete_redirect_rule(ifname
, eport
, proto
, &iport
, &iaddr
);
788 r
= priv_delete_filter_rule(ifname
, iport
, proto
, iaddr
);
794 get_redirect_rule_by_index(int index
,
795 char * ifname
, unsigned short * eport
,
796 char * iaddr
, int iaddrlen
, unsigned short * iport
,
797 int * proto
, char * desc
, int desclen
,
798 char * rhost
, int rhostlen
,
799 unsigned int * timestamp
,
800 u_int64_t
* packets
, u_int64_t
* bytes
)
803 struct pfioc_rule pr
;
805 struct pfioc_pooladdr pp
;
810 syslog(LOG_ERR
, "pf device is not open");
813 memset(&pr
, 0, sizeof(pr
));
814 strlcpy(pr
.anchor
, anchor_name
, MAXPATHLEN
);
816 pr
.rule
.action
= PF_RDR
;
818 if(ioctl(dev
, DIOCGETRULES
, &pr
) < 0)
820 syslog(LOG_ERR
, "ioctl(dev, DIOCGETRULES, ...): %m");
827 if(ioctl(dev
, DIOCGETRULE
, &pr
) < 0)
829 syslog(LOG_ERR
, "ioctl(dev, DIOCGETRULE): %m");
832 *proto
= pr
.rule
.proto
;
834 *eport
= ntohs(pr
.rule
.dst
.xport
.range
.port
[0]);
836 *eport
= ntohs(pr
.rule
.dst
.port
[0]);
839 *iport
= pr
.rule
.rpool
.proxy_port
[0];
841 *iport
= pr
.rule
.rdr
.proxy_port
[0];
844 strlcpy(ifname
, pr
.rule
.ifname
, IFNAMSIZ
);
846 strlcpy(desc
, pr
.rule
.label
, desclen
);
847 #ifdef PFRULE_INOUT_COUNTS
849 *packets
= pr
.rule
.packets
[0] + pr
.rule
.packets
[1];
851 *bytes
= pr
.rule
.bytes
[0] + pr
.rule
.bytes
[1];
854 *packets
= pr
.rule
.packets
;
856 *bytes
= pr
.rule
.bytes
;
859 memset(&pp
, 0, sizeof(pp
));
860 strlcpy(pp
.anchor
, anchor_name
, MAXPATHLEN
);
861 pp
.r_action
= PF_RDR
;
863 pp
.ticket
= pr
.ticket
;
864 if(ioctl(dev
, DIOCGETADDRS
, &pp
) < 0)
866 syslog(LOG_ERR
, "ioctl(dev, DIOCGETADDRS, ...): %m");
871 syslog(LOG_NOTICE
, "No address associated with pf rule");
874 pp
.nr
= 0; /* first */
875 if(ioctl(dev
, DIOCGETADDR
, &pp
) < 0)
877 syslog(LOG_ERR
, "ioctl(dev, DIOCGETADDR, ...): %m");
880 inet_ntop(AF_INET
, &pp
.addr
.addr
.v
.a
.addr
.v4
.s_addr
,
883 inet_ntop(AF_INET
, &pr
.rule
.rdr
.addr
.v
.a
.addr
.v4
.s_addr
,
886 if(rhost
&& rhostlen
> 0)
888 if (pr
.rule
.src
.addr
.v
.a
.addr
.v4
.s_addr
== 0)
890 rhost
[0] = '\0'; /* empty string */
894 inet_ntop(AF_INET
, &pr
.rule
.src
.addr
.v
.a
.addr
.v4
.s_addr
,
899 *timestamp
= get_timestamp(*eport
, *proto
);
905 /* return an (malloc'ed) array of "external" port for which there is
906 * a port mapping. number is the size of the array */
908 get_portmappings_in_range(unsigned short startport
, unsigned short endport
,
909 int proto
, unsigned int * number
)
911 unsigned short * array
;
912 unsigned int capacity
;
914 unsigned short eport
;
915 struct pfioc_rule pr
;
919 syslog(LOG_ERR
, "pf device is not open");
923 array
= calloc(capacity
, sizeof(unsigned short));
926 syslog(LOG_ERR
, "get_portmappings_in_range() : calloc error");
929 memset(&pr
, 0, sizeof(pr
));
930 strlcpy(pr
.anchor
, anchor_name
, MAXPATHLEN
);
932 pr
.rule
.action
= PF_RDR
;
934 if(ioctl(dev
, DIOCGETRULES
, &pr
) < 0)
936 syslog(LOG_ERR
, "ioctl(dev, DIOCGETRULES, ...): %m");
944 if(ioctl(dev
, DIOCGETRULE
, &pr
) < 0)
946 syslog(LOG_ERR
, "ioctl(dev, DIOCGETRULE): %m");
950 eport
= ntohs(pr
.rule
.dst
.xport
.range
.port
[0]);
951 if( (eport
== ntohs(pr
.rule
.dst
.xport
.range
.port
[1]))
953 eport
= ntohs(pr
.rule
.dst
.port
[0]);
954 if( (eport
== ntohs(pr
.rule
.dst
.port
[1]))
956 && (pr
.rule
.proto
== proto
)
957 && (startport
<= eport
) && (eport
<= endport
) )
959 if(*number
>= capacity
)
961 /* need to increase the capacity of the array */
963 array
= realloc(array
, sizeof(unsigned short)*capacity
);
966 syslog(LOG_ERR
, "get_portmappings_in_range() : realloc(%lu) error", sizeof(unsigned short)*capacity
);
971 array
[*number
] = eport
;
978 /* this function is only for testing */
985 struct pfioc_rule pr
;
987 struct pfioc_pooladdr pp
;
992 perror("pf dev not open");
995 memset(&pr
, 0, sizeof(pr
));
996 strlcpy(pr
.anchor
, anchor_name
, MAXPATHLEN
);
997 pr
.rule
.action
= PF_RDR
;
998 if(ioctl(dev
, DIOCGETRULES
, &pr
) < 0)
999 perror("DIOCGETRULES");
1000 printf("ticket = %d, nr = %d\n", pr
.ticket
, pr
.nr
);
1004 printf("-- rule %d --\n", i
);
1006 if(ioctl(dev
, DIOCGETRULE
, &pr
) < 0)
1007 perror("DIOCGETRULE");
1008 printf(" %s %s %d:%d -> %d:%d proto %d keep_state=%d action=%d\n",
1010 inet_ntop(AF_INET
, &pr
.rule
.src
.addr
.v
.a
.addr
.v4
.s_addr
, buf
, 32),
1011 (int)ntohs(pr
.rule
.dst
.port
[0]),
1012 (int)ntohs(pr
.rule
.dst
.port
[1]),
1014 (int)pr
.rule
.rpool
.proxy_port
[0],
1015 (int)pr
.rule
.rpool
.proxy_port
[1],
1017 (int)pr
.rule
.rdr
.proxy_port
[0],
1018 (int)pr
.rule
.rdr
.proxy_port
[1],
1021 (int)pr
.rule
.keep_state
,
1022 (int)pr
.rule
.action
);
1023 printf(" description: \"%s\"\n", pr
.rule
.label
);
1025 memset(&pp
, 0, sizeof(pp
));
1026 strlcpy(pp
.anchor
, anchor_name
, MAXPATHLEN
);
1027 pp
.r_action
= PF_RDR
;
1029 pp
.ticket
= pr
.ticket
;
1030 if(ioctl(dev
, DIOCGETADDRS
, &pp
) < 0)
1031 perror("DIOCGETADDRS");
1032 printf(" nb pool addr = %d ticket=%d\n", pp
.nr
, pp
.ticket
);
1033 /*if(ioctl(dev, DIOCGETRULE, &pr) < 0)
1034 perror("DIOCGETRULE"); */
1035 pp
.nr
= 0; /* first */
1036 if(ioctl(dev
, DIOCGETADDR
, &pp
) < 0)
1037 perror("DIOCGETADDR");
1038 /* addr.v.a.addr.v4.s_addr */
1039 printf(" %s\n", inet_ntop(AF_INET
, &pp
.addr
.addr
.v
.a
.addr
.v4
.s_addr
, buf
, 32));
1041 printf(" rule_flag=%08x action=%d direction=%d log=%d logif=%d "
1042 "quick=%d ifnot=%d af=%d type=%d code=%d rdr.port_op=%d rdr.opts=%d\n",
1043 pr
.rule
.rule_flag
, pr
.rule
.action
, pr
.rule
.direction
,
1044 pr
.rule
.log
, pr
.rule
.logif
, pr
.rule
.quick
, pr
.rule
.ifnot
,
1045 pr
.rule
.af
, pr
.rule
.type
, pr
.rule
.code
,
1046 pr
.rule
.rdr
.port_op
, pr
.rule
.rdr
.opts
);
1047 printf(" %s\n", inet_ntop(AF_INET
, &pr
.rule
.rdr
.addr
.v
.a
.addr
.v4
.s_addr
, buf
, 32));