diff options
author | Ryan Thomas McBride <mcbride@cvs.openbsd.org> | 2002-11-23 05:22:25 +0000 |
---|---|---|
committer | Ryan Thomas McBride <mcbride@cvs.openbsd.org> | 2002-11-23 05:22:25 +0000 |
commit | 06753c3fd451cfd13f5a2063c539f12d67d5c991 (patch) | |
tree | 4e255b25bd0c5d522b84b3185b1d97b67a93de91 /sbin | |
parent | 1691df433770a29ad8547bf930bf7b9429c95b7c (diff) |
code to support loading of pf rules with multiple redirection addresses
(in nat, rdr, route-to, dup-to and reply-to)
Syntax looks like this, see pf.conf(5) for details:
nat on wi0 proto { tcp, icmp } from any to 192.168.0.2 -> \
192.168.0.16/29 source-hash random
rdr on wi0 proto { tcp } from any to 192.168.0.34 port 22 -> \
{ 192.168.0.8/31, 192.168.0.15 } port 22 round-robin
ok dhartmei@ henning@
Diffstat (limited to 'sbin')
-rw-r--r-- | sbin/pfctl/parse.y | 726 | ||||
-rw-r--r-- | sbin/pfctl/pf_print_state.c | 11 | ||||
-rw-r--r-- | sbin/pfctl/pf_print_state.h | 4 | ||||
-rw-r--r-- | sbin/pfctl/pfctl.c | 100 | ||||
-rw-r--r-- | sbin/pfctl/pfctl_parser.c | 138 | ||||
-rw-r--r-- | sbin/pfctl/pfctl_parser.h | 3 |
6 files changed, 731 insertions, 251 deletions
diff --git a/sbin/pfctl/parse.y b/sbin/pfctl/parse.y index fe3c2f40270..161ee0cc803 100644 --- a/sbin/pfctl/parse.y +++ b/sbin/pfctl/parse.y @@ -1,4 +1,4 @@ -/* $OpenBSD: parse.y,v 1.198 2002/11/22 12:24:30 henning Exp $ */ +/* $OpenBSD: parse.y,v 1.199 2002/11/23 05:22:24 mcbride Exp $ */ /* * Copyright (c) 2001 Markus Friedl. All rights reserved. @@ -48,6 +48,7 @@ #include <err.h> #include <pwd.h> #include <grp.h> +#include <md5.h> #include "pfctl_parser.h" #include "pfctl_altq.h" @@ -94,7 +95,6 @@ struct node_proto { struct node_host { struct pf_addr_wrap addr; - struct pf_addr mask; struct pf_addr bcast; sa_family_t af; u_int8_t not; @@ -181,10 +181,10 @@ int rdr_consistent(struct pf_rdr *); int yyparse(void); void set_ipmask(struct node_host *, u_int8_t); void expand_rdr(struct pf_rdr *, struct node_if *, struct node_proto *, - struct node_host *, struct node_host *); + struct node_host *, struct node_host *, struct node_host *); void expand_nat(struct pf_nat *, struct node_if *, struct node_proto *, struct node_host *, struct node_port *, - struct node_host *, struct node_port *); + struct node_host *, struct node_port *, struct node_host *); void expand_label_if(const char *, char *, const char *); void expand_label_addr(const char *, char *, u_int8_t, struct node_host *); void expand_label_port(const char *, char *, struct node_port *); @@ -193,10 +193,10 @@ void expand_label_nr(const char *, char *); void expand_label(char *, const char *, u_int8_t, struct node_host *, struct node_port *, struct node_host *, struct node_port *, u_int8_t); -void expand_rule(struct pf_rule *, struct node_if *, struct node_proto *, - struct node_host *, struct node_port *, struct node_host *, - struct node_port *, struct node_uid *, struct node_gid *, - struct node_icmp *); +void expand_rule(struct pf_rule *, struct node_if *, struct node_host *, + struct node_proto *, struct node_host *, struct node_port *, + struct node_host *, struct node_port *, struct node_uid *, + struct node_gid *, struct node_icmp *); void expand_altq(struct pf_altq *, struct node_if *, struct node_queue *); int expand_queue(struct pf_altq *, struct node_queue *, struct node_queue_bw); @@ -225,8 +225,8 @@ char * symget(const char *); void ifa_load(void); struct node_host *ifa_exists(char *); struct node_host *ifa_lookup(char *, enum pfctl_iflookup_mode); -struct node_host *ifa_pick_ip(struct node_host *, u_int8_t); -u_int16_t parseicmpspec(char *, u_int8_t); +struct node_host *ifa_pick_ips(struct node_host *, sa_family_t); +u_int16_t parseicmpspec(char *, sa_family_t); typedef struct { union { @@ -257,16 +257,21 @@ typedef struct { struct peer src, dst; } fromto; struct { - char *string; - struct pf_addr *addr; + struct node_host *host; u_int8_t rt; + u_int8_t pool_opts; sa_family_t af; + struct pf_poolhashkey *key; } route; struct redirection { - struct node_host *address; + struct node_host *host; struct range rport; } *redirection; struct { + int type; + struct pf_poolhashkey *key; + } pooltype; + struct { int action; struct node_state_opt *options; } keep_state; @@ -292,6 +297,7 @@ typedef struct { %token SET OPTIMIZATION TIMEOUT LIMIT LOGINTERFACE BLOCKPOLICY %token REQUIREORDER YES %token ANTISPOOF FOR +%token BITMASK RANDOM SOURCEHASH ROUNDROBIN KEY STATICPORT %token ALTQ SCHEDULER CBQ BANDWIDTH TBRSIZE %token QUEUE PRIORITY QLIMIT %token DEFAULT CONTROL BORROW RED ECN RIO @@ -301,18 +307,22 @@ typedef struct { %type <v.number> number port icmptype icmp6type minttl uid gid maxmss %type <v.number> tos %type <v.i> no dir log af nodf allowopts fragment fragcache +%type <v.i> staticport %type <v.b> action flag flags blockspec %type <v.range> dport rport +%type <v.pooltype> pooltype %type <v.proto> proto proto_list proto_item %type <v.icmp> icmpspec icmp_list icmp6_list icmp_item icmp6_item %type <v.fromto> fromto %type <v.peer> ipportspec -%type <v.host> ipspec xhost host address host_list +%type <v.host> ipspec xhost host address host_list +%type <v.host> redir_host_list redirspec +%type <v.host> route_host route_host_list routespec %type <v.port> portspec port_list port_item %type <v.uid> uids uid_list uid_item %type <v.gid> gids gid_list gid_item %type <v.route> route -%type <v.redirection> redirection +%type <v.redirection> redirection redirpool %type <v.string> label string %type <v.keep_state> keep %type <v.state_opt> state_opt_spec state_opt_list state_opt_item @@ -441,8 +451,9 @@ scrubrule : SCRUB dir interface af fromto nodf minttl maxmss fragcache if ($9) r.rule_flag |= $9; - expand_rule(&r, $3, NULL, $5.src.host, $5.src.port, - $5.dst.host, $5.dst.port, NULL, NULL, NULL); + expand_rule(&r, $3, NULL, NULL, + $5.src.host, $5.src.port, $5.dst.host, $5.dst.port, + NULL, NULL, NULL); } ; @@ -470,8 +481,8 @@ antispoof : ANTISPOOF logquick antispoof_ifspc af { j->not = 1; h = ifa_lookup(j->ifname, PFCTL_IFLOOKUP_NET); - expand_rule(&r, j, NULL, h, NULL, NULL, NULL, - NULL, NULL, NULL); + expand_rule(&r, j, NULL, NULL, h, NULL, NULL, + NULL, NULL, NULL, NULL); if ((i->ifa_flags & IFF_LOOPBACK) == 0) { memset(&r, 0, sizeof(r)); @@ -485,8 +496,8 @@ antispoof : ANTISPOOF logquick antispoof_ifspc af { h = ifa_lookup(i->ifname, PFCTL_IFLOOKUP_HOST); - expand_rule(&r, NULL, NULL, h, NULL, - NULL, NULL, NULL, NULL, NULL); + expand_rule(&r, NULL, NULL, NULL, h, + NULL, NULL, NULL, NULL, NULL, NULL); } } } @@ -756,28 +767,7 @@ pfrule : action dir logquick interface route af proto fromto if ($5.rt) { r.rt = $5.rt; - if ($5.string) { - strlcpy(r.rt_ifname, $5.string, - IFNAMSIZ); - if (ifa_exists(r.rt_ifname) == NULL) { - yyerror("unknown interface %s", - r.rt_ifname); - YYERROR; - } - free($5.string); - } - if ($5.addr) { - if (!r.af) - r.af = $5.af; - else if (r.af != $5.af) { - yyerror("address family" - " mismatch"); - YYERROR; - } - memcpy(&r.rt_addr, $5.addr, - sizeof(r.rt_addr)); - free($5.addr); - } + r.rt_pool.opts = $5.pool_opts; } if ($17) { @@ -800,8 +790,9 @@ pfrule : action dir logquick interface route af proto fromto free($18); } - expand_rule(&r, $4, $7, $8.src.host, $8.src.port, - $8.dst.host, $8.dst.port, $9, $10, $12); + expand_rule(&r, $4, $5.host, $7, + $8.src.host, $8.src.port, $8.dst.host, $8.dst.port, + $9, $10, $12); } ; @@ -1040,6 +1031,7 @@ address : '(' STRING ')' { if ($$ == NULL) err(1, "address: calloc"); $$->af = 0; + $$->ifname[0] = 0; set_ipmask($$, 128); $$->addr.addr_dyn = (struct pf_addr_dyn *)1; strncpy($$->addr.addr.pfa.ifname, $2, @@ -1579,24 +1571,88 @@ rport : STRING { } ; +redirspec : host { $$ = $1; } + | '{' redir_host_list '}' { $$ = $2; } + ; + +redir_host_list : host { $$ = $1; } + | redir_host_list comma host { + /* $3 may be a list, so use its tail pointer */ + $1->tail->next = $3->tail; + $1->tail = $3->tail; + $$ = $1; + } + ; + +redirpool : /* empty */ { $$ = NULL; } + | ARROW redirspec { + $$ = malloc(sizeof(struct redirection)); + if ($$ == NULL) + err(1, "redirection: malloc"); + $$->host = $2; + $$->rport.a = $$->rport.b = $$->rport.t = 0; + } + | ARROW redirspec PORT rport { + $$ = malloc(sizeof(struct redirection)); + if ($$ == NULL) + err(1, "redirection: malloc"); + $$->host = $2; + $$->rport = $4; + } + ; + +pooltype : /* empty */ { $$.type = PF_POOL_NONE; } + | BITMASK { $$.type = PF_POOL_BITMASK; } + | RANDOM { $$.type = PF_POOL_RANDOM; } + | SOURCEHASH { $$.type = PF_POOL_SRCHASH; } + | SOURCEHASH RANDOM + { + $$.key = malloc(sizeof(struct pf_poolhashkey)); + if ($$.key == NULL) + err(1, "pooltype: malloc"); + $$.type = PF_POOL_SRCKEYHASH; + $$.key->key32[0] = arc4random(); + $$.key->key32[1] = arc4random(); + $$.key->key32[2] = arc4random(); + $$.key->key32[3] = arc4random(); + } + | SOURCEHASH KEY string + { + MD5_CTX context; + + $$.key = malloc(sizeof(struct pf_poolhashkey)); + if ($$.key == NULL) + err(1, "pooltype: malloc"); + $$.type = PF_POOL_SRCKEYHASH; + MD5Init(&context); + MD5Update(&context, $3, strlen($3)); + MD5Final((unsigned char *)$$.key, &context); + } + | ROUNDROBIN { $$.type = PF_POOL_ROUNDROBIN; } + ; + +staticport : /* empty */ { $$ = 0; } + | STATICPORT { $$ = PF_POOL_STATICPORT; } + ; + redirection : /* empty */ { $$ = NULL; } | ARROW host { $$ = malloc(sizeof(struct redirection)); if ($$ == NULL) err(1, "redirection: malloc"); - $$->address = $2; + $$->host = $2; $$->rport.a = $$->rport.b = $$->rport.t = 0; } | ARROW host PORT rport { $$ = malloc(sizeof(struct redirection)); if ($$ == NULL) err(1, "redirection: malloc"); - $$->address = $2; + $$->host = $2; $$->rport = $4; } ; -natrule : no NAT interface af proto fromto redirection +natrule : no NAT interface af proto fromto redirpool pooltype staticport { struct pf_nat nat; @@ -1626,20 +1682,19 @@ natrule : no NAT interface af proto fromto redirection } else { struct node_host *n; - if ($7 == NULL || $7->address == NULL) { + if ($7 == NULL || $7->host == NULL) { yyerror("'nat' rule requires '-> " "address'"); YYERROR; } - if (!nat.af && !$7->address->ifindex) - nat.af = $7->address->af; - n = ifa_pick_ip($7->address, nat.af); + if (!nat.af && !$7->host->ifindex) + nat.af = $7->host->af; + + n = ifa_pick_ips($7->host, nat.af); if (n == NULL) YYERROR; if (!nat.af) nat.af = n->af; - memcpy(&nat.raddr, &n->addr, - sizeof(nat.raddr)); nat.proxy_port[0] = ntohs($7->rport.a); nat.proxy_port[1] = ntohs($7->rport.b); if (!nat.proxy_port[0] && !nat.proxy_port[1]) { @@ -1649,12 +1704,43 @@ natrule : no NAT interface af proto fromto redirection PF_NAT_PROXY_PORT_HIGH; } else if (!nat.proxy_port[1]) nat.proxy_port[1] = nat.proxy_port[0]; - free($7->address); - free($7); + } + + if ($7->host->next) { + nat.rpool.opts = $8.type; + if (nat.rpool.opts == PF_POOL_NONE) + nat.rpool.opts = PF_POOL_ROUNDROBIN; + if (nat.rpool.opts != PF_POOL_ROUNDROBIN) { + yyerror("nat: only round-robin valid " + "for multiple redirection " + "addresses"); + YYERROR; + } + } else { + if ((nat.af == AF_INET && + unmask(&$7->host->addr.mask, + nat.af) == 32) || + (nat.af == AF_INET6 && + unmask(&$7->host->addr.mask, + nat.af) == 128)) { + nat.rpool.opts = PF_POOL_NONE; + } else { + if ($8.type == PF_POOL_NONE) + nat.rpool.opts = + PF_POOL_ROUNDROBIN; + else + nat.rpool.opts = $8.type; + } + } + if ((nat.rpool.opts & PF_POOL_TYPEMASK) == + PF_POOL_SRCKEYHASH) { + memcpy(&nat.rpool.key, $8.key, + sizeof(struct pf_poolhashkey)); } expand_nat(&nat, $3, $5, $6.src.host, $6.src.port, - $6.dst.host, $6.dst.port); + $6.dst.host, $6.dst.port, $7->host); + free($7); } ; @@ -1702,8 +1788,8 @@ binatrule : no BINAT interface af proto FROM host TO ipspec redirection binat.af = $7->af; memcpy(&binat.saddr.addr, &$7->addr.addr, sizeof(binat.saddr.addr)); - memcpy(&binat.smask, &$7->mask, - sizeof(binat.smask)); + memcpy(&binat.saddr.mask, &$7->addr.mask, + sizeof(binat.saddr.mask)); free($7); } if ($9 != NULL) { @@ -1726,8 +1812,8 @@ binatrule : no BINAT interface af proto FROM host TO ipspec redirection binat.af = $9->af; memcpy(&binat.daddr.addr, &$9->addr.addr, sizeof(binat.daddr.addr)); - memcpy(&binat.dmask, &$9->mask, - sizeof(binat.dmask)); + memcpy(&binat.daddr.mask, &$9->addr.mask, + sizeof(binat.daddr.mask)); binat.dnot = $9->not; free($9); } @@ -1741,14 +1827,19 @@ binatrule : no BINAT interface af proto FROM host TO ipspec redirection } else { struct node_host *n; - if ($10 == NULL || $10->address == NULL) { + if ($10 == NULL || $10->host == NULL) { yyerror("'binat' rule requires" " '-> address'"); YYERROR; } - n = ifa_pick_ip($10->address, binat.af); + n = ifa_pick_ips($10->host, binat.af); if (n == NULL) YYERROR; + if (n->next != NULL) { + yyerror("multiple addresses in '-> " + "address'"); + YYERROR; + } if (n->addr.addr_dyn != NULL) { if (!binat.af) { yyerror("address family (inet/" @@ -1764,21 +1855,23 @@ binatrule : no BINAT interface af proto FROM host TO ipspec redirection binat.af = n->af; memcpy(&binat.raddr.addr, &n->addr.addr, sizeof(binat.raddr.addr)); - memcpy(&binat.rmask, &n->mask, - sizeof(binat.rmask)); - if (PF_ANEQ(&binat.smask, &binat.rmask, binat.af)) { + memcpy(&binat.raddr.mask, &n->addr.mask, + sizeof(binat.raddr.mask)); + if (!PF_AZERO(&binat.saddr.mask, binat.af) && + !PF_AEQ(&binat.saddr.mask, + &binat.raddr.mask, binat.af)) { yyerror("'binat' source mask and " "redirect mask must be the same"); YYERROR; - } - free($10->address); + } free($10); } pfctl_add_binat(pf, &binat); } + ; -rdrrule : no RDR interface af proto FROM ipspec TO ipspec dport redirection +rdrrule : no RDR interface af proto FROM ipspec TO ipspec dport redirpool pooltype { struct pf_rdr rdr; @@ -1790,19 +1883,19 @@ rdrrule : no RDR interface af proto FROM ipspec TO ipspec dport redirection rdr.no = $1; rdr.af = $4; if ($7 != NULL) { - memcpy(&rdr.saddr, &$7->addr, - sizeof(rdr.saddr)); - memcpy(&rdr.smask, &$7->mask, - sizeof(rdr.smask)); + memcpy(&rdr.saddr.addr, &$7->addr.addr, + sizeof(rdr.saddr.addr)); + memcpy(&rdr.saddr.mask, &$7->addr.mask, + sizeof(rdr.saddr.mask)); rdr.snot = $7->not; if (!rdr.af && !$7->ifindex) rdr.af = $7->af; } if ($9 != NULL) { - memcpy(&rdr.daddr, &$9->addr, - sizeof(rdr.daddr)); - memcpy(&rdr.dmask, &$9->mask, - sizeof(rdr.dmask)); + memcpy(&rdr.daddr.addr, &$9->addr.addr, + sizeof(rdr.daddr.addr)); + memcpy(&rdr.daddr.mask, &$9->addr.mask, + sizeof(rdr.daddr.mask)); rdr.dnot = $9->not; if (!rdr.af && !$9->ifindex) rdr.af = $9->af; @@ -1812,6 +1905,11 @@ rdrrule : no RDR interface af proto FROM ipspec TO ipspec dport redirection rdr.dport2 = $10.b; rdr.opts |= $10.t; + if ($12.type == PF_POOL_NONE) + rdr.rpool.opts = PF_POOL_RANDOM; + else + rdr.rpool.opts = $12.type; + if (rdr.no) { if ($11 != NULL) { yyerror("'no rdr' rule does not need '->'"); @@ -1820,27 +1918,53 @@ rdrrule : no RDR interface af proto FROM ipspec TO ipspec dport redirection } else { struct node_host *n; - if ($11 == NULL || $11->address == NULL) { + if ($11 == NULL || $11->host == NULL) { yyerror("'rdr' rule requires '-> " "address'"); YYERROR; - } - if (!rdr.af && !$11->address->ifindex) - rdr.af = $11->address->af; - n = ifa_pick_ip($11->address, rdr.af); + } + if (!rdr.af && !$11->host->ifindex) + rdr.af = $11->host->af; + + n = ifa_pick_ips($11->host, rdr.af); if (n == NULL) YYERROR; if (!rdr.af) rdr.af = n->af; - memcpy(&rdr.raddr, &n->addr, - sizeof(rdr.raddr)); - free($11->address); rdr.rport = $11->rport.a; rdr.opts |= $11->rport.t; - free($11); + } + if ($11->host->next) { + rdr.rpool.opts = $12.type; + if (rdr.rpool.opts == PF_POOL_NONE) + rdr.rpool.opts = PF_POOL_ROUNDROBIN; + if (rdr.rpool.opts != PF_POOL_ROUNDROBIN) { + yyerror("nat: only round-robin valid " + "for multiple redirection " + "addresses"); + YYERROR; + } + } else { + if ((rdr.af == AF_INET && + unmask(&$11->host->addr.mask, rdr.af) == 32) || + (rdr.af == AF_INET6 && + unmask(&$11->host->addr.mask, rdr.af) == 128)) { + rdr.rpool.opts = PF_POOL_NONE; + } else { + if ($12.type == PF_POOL_NONE) + rdr.rpool.opts = + PF_POOL_ROUNDROBIN; + else + rdr.rpool.opts = $12.type; + } + } + if ((rdr.rpool.opts & PF_POOL_TYPEMASK) == + PF_POOL_SRCKEYHASH) { + memcpy(&rdr.rpool.key, $12.key, + sizeof(struct pf_poolhashkey)); } - expand_rdr(&rdr, $3, $5, $7, $9); + expand_rdr(&rdr, $3, $5, $7, $9, $11->host); } ; @@ -1864,94 +1988,160 @@ dport : /* empty */ { } ; -route : /* empty */ { - $$.string = NULL; - $$.rt = 0; - $$.addr = NULL; - $$.af = 0; - } - | FASTROUTE { - $$.string = NULL; - $$.rt = PF_FASTROUTE; - $$.addr = NULL; - } - | ROUTETO '(' STRING address ')' { - if (($$.string = strdup($3)) == NULL) { +route_host : '(' STRING ')' { + if (($$->ifname = strdup($2)) == NULL) { yyerror("routeto: strdup"); YYERROR; } - $$.rt = PF_ROUTETO; - if ($4->addr.addr_dyn != NULL) { - yyerror("route-to does not support" - " dynamic addresses"); - YYERROR; - } - if ($4->next) { - yyerror("multiple route-to ip addresses"); + if (ifa_exists($$->ifname) == NULL) { + yyerror("routeto: unknown interface %s", + $$->ifname); YYERROR; } - $$.addr = &$4->addr.addr; - $$.af = $4->af; } - | ROUTETO STRING { - if (($$.string = strdup($2)) == NULL) { + | '(' STRING host ')' { + $$ = $3; + if (($$->ifname = strdup($2)) == NULL) { yyerror("routeto: strdup"); YYERROR; } - $$.rt = PF_ROUTETO; - $$.addr = NULL; - } - | REPLYTO '(' STRING address ')' { - if (($$.string = strdup($3)) == NULL) { - yyerror("reply-to: strdup"); + if (ifa_exists($$->ifname) == NULL) { + yyerror("routeto: unknown interface %s", + $$->ifname); YYERROR; } - $$.rt = PF_REPLYTO; - if ($4->addr.addr_dyn != NULL) { - yyerror("reply-to does not support" - " dynamic addresses"); + } + ; + +route_host_list : route_host { $$ = $1; } + | route_host_list comma route_host { + if ($1->af == 0) + $1->af = $3->af; + if ($1->af != $3->af) { + yyerror("all pool addresses must be in the " + "same address family"); YYERROR; + } + /* $3 may be a list, so use its tail pointer */ + $1->tail->next = $3->tail; + $1->tail = $3->tail; + $$ = $1; + } + ; + +routespec : route_host { $$ = $1; } + | '{' route_host_list '}' { $$ = $2; } + ; + + +route : /* empty */ { + $$.host = NULL; + $$.rt = 0; + $$.pool_opts = 0; + } + | FASTROUTE { + $$.host = NULL; + $$.rt = PF_FASTROUTE; + $$.pool_opts = 0; + } + | ROUTETO routespec pooltype { + $$.host = $2; + $$.rt = PF_ROUTETO; + + if ($2->next) { + $$.pool_opts = $3.type; + if ($$.pool_opts == PF_POOL_NONE) + $$.pool_opts = PF_POOL_ROUNDROBIN; + if ($$.pool_opts != PF_POOL_ROUNDROBIN) { + yyerror("nat: only round-robin valid " + "for multiple redirection " + "addresses"); + YYERROR; + } + } else { + if (($2->af == AF_INET && + unmask(&$2->addr.mask, $2->af) == 32) || + ($2->af == AF_INET6 && + unmask(&$2->addr.mask, $2->af) == 128)) { + $$.pool_opts = PF_POOL_NONE; + } else { + if ($3.type == PF_POOL_NONE) + $$.pool_opts = + PF_POOL_ROUNDROBIN; + else + $$.pool_opts = $3.type; + } } - if ($4->next) { - yyerror("multiple reply-to ip addresses"); - YYERROR; + if (($$.pool_opts & PF_POOL_TYPEMASK) == + PF_POOL_SRCKEYHASH) { + $$.key = $3.key; } - $$.addr = &$4->addr.addr; - $$.af = $4->af; } - | REPLYTO STRING { - if (($$.string = strdup($2)) == NULL) { - yyerror("reply-to: strdup"); - YYERROR; - } + | REPLYTO routespec pooltype { + $$.host = $2; $$.rt = PF_REPLYTO; - $$.addr = NULL; - } - | DUPTO '(' STRING address ')' { - if (($$.string = strdup($3)) == NULL) { - yyerror("dupto: strdup"); - YYERROR; - } - $$.rt = PF_DUPTO; - if ($4->addr.addr_dyn != NULL) { - yyerror("dup-to does not support" - " dynamic addresses"); - YYERROR; + + if ($2->next) { + $$.pool_opts = $3.type; + if ($$.pool_opts == PF_POOL_NONE) + $$.pool_opts = PF_POOL_ROUNDROBIN; + if ($$.pool_opts != PF_POOL_ROUNDROBIN) { + yyerror("nat: only round-robin valid " + "for multiple redirection " + "addresses"); + YYERROR; + } + } else { + if (($2->af == AF_INET && + unmask(&$2->addr.mask, $2->af) == 32) || + ($2->af == AF_INET6 && + unmask(&$2->addr.mask, $2->af) == 128)) { + $$.pool_opts = PF_POOL_NONE; + } else { + if ($3.type == PF_POOL_NONE) + $$.pool_opts = + PF_POOL_ROUNDROBIN; + else + $$.pool_opts = $3.type; + } } - if ($4->next) { - yyerror("multiple dup-to ip addresses"); - YYERROR; + if (($$.pool_opts & PF_POOL_TYPEMASK) == + PF_POOL_SRCKEYHASH) { + $$.key = $3.key; } - $$.addr = &$4->addr.addr; - $$.af = $4->af; } - | DUPTO STRING { - if (($$.string = strdup($2)) == NULL) { - yyerror("dupto: strdup"); - YYERROR; - } + | DUPTO routespec pooltype { + $$.host = $2; $$.rt = PF_DUPTO; - $$.addr = NULL; + + if ($2->next) { + $$.pool_opts = $3.type; + if ($$.pool_opts == PF_POOL_NONE) + $$.pool_opts = PF_POOL_ROUNDROBIN; + if ($$.pool_opts != PF_POOL_ROUNDROBIN) { + yyerror("nat: only round-robin valid " + "for multiple redirection " + "addresses"); + YYERROR; + } + } else { + if (($2->af == AF_INET && + unmask(&$2->addr.mask, $2->af) == 32) || + ($2->af == AF_INET6 && + unmask(&$2->addr.mask, $2->af) == 128)) { + $$.pool_opts = PF_POOL_NONE; + } else { + if ($3.type == PF_POOL_NONE) + $$.pool_opts = + PF_POOL_ROUNDROBIN; + else + $$.pool_opts = $3.type; + } + } + if (($$.pool_opts & PF_POOL_TYPEMASK) == + PF_POOL_SRCKEYHASH) { + $$.key = $3.key; + } } ; @@ -2067,10 +2257,17 @@ int nat_consistent(struct pf_nat *r) { int problems = 0; - - if (!r->af && (r->raddr.addr_dyn != NULL)) { - yyerror("dynamic addresses require address family (inet/inet6)"); - problems++; + struct pf_pooladdr *pa; + + if (!r->af) { + TAILQ_FOREACH(pa, &r->rpool.list, entries) { + if (pa->addr.addr_dyn != NULL) { + yyerror("dynamic addresses require " + "address family (inet/inet6)"); + problems++; + break; + } + } } return (-problems); } @@ -2079,16 +2276,28 @@ int rdr_consistent(struct pf_rdr *r) { int problems = 0; + struct pf_pooladdr *pa; if (r->proto != IPPROTO_TCP && r->proto != IPPROTO_UDP && (r->dport || r->dport2 || r->rport)) { yyerror("port only applies to tcp/udp"); problems++; } - if (!r->af && (r->saddr.addr_dyn != NULL || - r->daddr.addr_dyn != NULL || r->raddr.addr_dyn != NULL)) { - yyerror("dynamic addresses require address family (inet/inet6)"); - problems++; + if (!r->af) { + if (r->saddr.addr_dyn != NULL || r->daddr.addr_dyn != NULL) { + yyerror("dynamic addresses require address family " + "(inet/inet6)"); + problems++; + } else { + TAILQ_FOREACH(pa, &r->rpool.list, entries) { + if (pa->addr.addr_dyn != NULL) { + yyerror("dynamic addresses require " + "address family (inet/inet6)"); + problems++; + break; + } + } + } } return (-problems); } @@ -2166,7 +2375,7 @@ expand_label_addr(const char *name, char *label, sa_family_t af, PF_RULE_LABEL_SIZE); strlcat(tmp, ")", PF_RULE_LABEL_SIZE); } else if (!af || (PF_AZERO(&host->addr.addr, af) && - PF_AZERO(&host->mask, af))) + PF_AZERO(&host->addr.mask, af))) strlcat(tmp, "any", PF_RULE_LABEL_SIZE); else { char a[48]; @@ -2176,7 +2385,7 @@ expand_label_addr(const char *name, char *label, sa_family_t af, sizeof(a)) == NULL) strlcat(a, "?", sizeof(a)); strlcat(tmp, a, PF_RULE_LABEL_SIZE); - bits = unmask(&host->mask, af); + bits = unmask(&host->addr.mask, af); a[0] = 0; if ((af == AF_INET && bits < 32) || (af == AF_INET6 && bits < 128)) @@ -2400,16 +2609,18 @@ expand_queue(struct pf_altq *a, struct node_queue *nqueues, void expand_rule(struct pf_rule *r, - struct node_if *interfaces, struct node_proto *protos, - struct node_host *src_hosts, struct node_port *src_ports, - struct node_host *dst_hosts, struct node_port *dst_ports, - struct node_uid *uids, struct node_gid *gids, - struct node_icmp *icmp_types) + struct node_if *interfaces, struct node_host *rt_pool_hosts, + struct node_proto *protos, struct node_host *src_hosts, + struct node_port *src_ports, struct node_host *dst_hosts, + struct node_port *dst_ports, struct node_uid *uids, + struct node_gid *gids, struct node_icmp *icmp_types) { sa_family_t af = r->af; - int nomatch = 0, added = 0; + int added = 0, error = 0; char ifname[IF_NAMESIZE]; char label[PF_RULE_LABEL_SIZE]; + struct pf_pooladdr *pa; + struct node_host *h; char qname[PF_QNAME_SIZE]; u_int8_t flags, flagset; @@ -2461,14 +2672,12 @@ expand_rule(struct pf_rule *r, r->ifnot = interface->not; r->proto = proto->proto; r->src.addr = src_host->addr; - r->src.mask = src_host->mask; r->src.noroute = src_host->noroute; r->src.not = src_host->not; r->src.port[0] = src_port->port[0]; r->src.port[1] = src_port->port[1]; r->src.port_op = src_port->op; r->dst.addr = dst_host->addr; - r->dst.mask = dst_host->mask; r->dst.noroute = dst_host->noroute; r->dst.not = dst_host->not; r->dst.port[0] = dst_port->port[0]; @@ -2492,10 +2701,25 @@ expand_rule(struct pf_rule *r, } if (icmp_type->proto && r->proto != icmp_type->proto) { yyerror("icmp-type mismatch"); - nomatch++; + error++; + } + + TAILQ_INIT(&r->rt_pool.list); + for (h = rt_pool_hosts; h; h = h->next) { + pa = malloc(sizeof(struct pf_pooladdr)); + if (pa == NULL) { + yyerror("malloc"); + error++; + } + pa->addr = h->addr; + if (h->ifname != NULL) + strncpy(pa->ifname, h->ifname, IFNAMSIZ); + else + pa->ifname[0] = 0; + TAILQ_INSERT_TAIL(&r->rt_pool.list, pa, entries); } - if (rule_consistent(r) < 0 || nomatch) + if (rule_consistent(r) < 0 || error) yyerror("skipping filter rule due to errors"); else { r->nr = pf->rule_nr++; @@ -2514,6 +2738,7 @@ expand_rule(struct pf_rule *r, FREE_LIST(struct node_uid, uids); FREE_LIST(struct node_gid, gids); FREE_LIST(struct node_icmp, icmp_types); + FREE_LIST(struct node_host, rt_pool_hosts); if (!added) yyerror("rule expands to no valid combination"); @@ -2523,11 +2748,14 @@ void expand_nat(struct pf_nat *n, struct node_if *interfaces, struct node_proto *protos, struct node_host *src_hosts, struct node_port *src_ports, - struct node_host *dst_hosts, struct node_port *dst_ports) + struct node_host *dst_hosts, struct node_port *dst_ports, + struct node_host *rpool_hosts) { char ifname[IF_NAMESIZE]; + struct pf_pooladdr *pa; + struct node_host *h; sa_family_t af = n->af; - int added = 0; + int added = 0, error = 0; LOOP_THROUGH(struct node_if, interface, interfaces, LOOP_THROUGH(struct node_proto, proto, protos, @@ -2564,23 +2792,45 @@ expand_nat(struct pf_nat *n, n->ifnot = interface->not; n->proto = proto->proto; n->src.addr = src_host->addr; - n->src.mask = src_host->mask; n->src.noroute = src_host->noroute; n->src.not = src_host->not; n->src.port[0] = src_port->port[0]; n->src.port[1] = src_port->port[1]; n->src.port_op = src_port->op; n->dst.addr = dst_host->addr; - n->dst.mask = dst_host->mask; n->dst.noroute = dst_host->noroute; n->dst.not = dst_host->not; n->dst.port[0] = dst_port->port[0]; n->dst.port[1] = dst_port->port[1]; n->dst.port_op = dst_port->op; - if (nat_consistent(n) < 0) + TAILQ_INIT(&n->rpool.list); + for (h = rpool_hosts; h; h = h->next) { + pa = malloc(sizeof(struct pf_pooladdr)); + if (pa == NULL) { + yyerror("malloc"); + error++; + } + pa->addr = h->addr; + pa->ifname[0] = 0; + TAILQ_INSERT_TAIL(&n->rpool.list, pa, entries); + } + + TAILQ_INIT(&n->rpool.list); + for (h = rpool_hosts; h; h = h->next) { + pa = malloc(sizeof(struct pf_pooladdr)); + if (pa == NULL) { + yyerror("malloc"); + error++; + } + pa->addr = h->addr; + pa->ifname[0] = 0; + TAILQ_INSERT_TAIL(&n->rpool.list, pa, entries); + } + + if (nat_consistent(n) < 0 || error) yyerror("skipping nat rule due to errors"); - else { + else { pfctl_add_nat(pf, n); added++; } @@ -2593,6 +2843,7 @@ expand_nat(struct pf_nat *n, FREE_LIST(struct node_port, src_ports); FREE_LIST(struct node_host, dst_hosts); FREE_LIST(struct node_port, dst_ports); + FREE_LIST(struct node_host, rpool_hosts); if (!added) yyerror("nat rule expands to no valid combinations"); @@ -2601,11 +2852,13 @@ expand_nat(struct pf_nat *n, void expand_rdr(struct pf_rdr *r, struct node_if *interfaces, struct node_proto *protos, struct node_host *src_hosts, - struct node_host *dst_hosts) + struct node_host *dst_hosts, struct node_host *rpool_hosts) { sa_family_t af = r->af; - int added = 0; + int added = 0, error = 0; char ifname[IF_NAMESIZE]; + struct pf_pooladdr *pa; + struct node_host *h; LOOP_THROUGH(struct node_if, interface, interfaces, LOOP_THROUGH(struct node_proto, proto, protos, @@ -2640,11 +2893,21 @@ expand_rdr(struct pf_rdr *r, struct node_if *interfaces, r->proto = proto->proto; r->ifnot = interface->not; r->saddr = src_host->addr; - r->smask = src_host->mask; r->daddr = dst_host->addr; - r->dmask = dst_host->mask; - if (rdr_consistent(r) < 0) + TAILQ_INIT(&r->rpool.list); + for (h = rpool_hosts; h; h = h->next) { + pa = malloc(sizeof(struct pf_pooladdr)); + if (pa == NULL) { + yyerror("malloc"); + error++; + } + pa->addr = h->addr; + pa->ifname[0] = 0; + TAILQ_INSERT_TAIL(&r->rpool.list, pa, entries); + } + + if (rdr_consistent(r) < 0 || error) yyerror("skipping rdr rule due to errors"); else { pfctl_add_rdr(pf, r); @@ -2657,6 +2920,7 @@ expand_rdr(struct pf_rdr *r, struct node_if *interfaces, FREE_LIST(struct node_proto, protos); FREE_LIST(struct node_host, src_hosts); FREE_LIST(struct node_host, dst_hosts); + FREE_LIST(struct node_host, rpool_hosts); if (!added) yyerror("rdr rule expands to no valid combination"); @@ -2695,6 +2959,7 @@ lookup(char *s) { "any", ANY}, { "bandwidth", BANDWIDTH}, { "binat", BINAT}, + { "bitmask", BITMASK}, { "block", BLOCK}, { "block-policy", BLOCKPOLICY}, { "borrow", BORROW}, @@ -2719,6 +2984,7 @@ lookup(char *s) { "inet6", INET6}, { "ipv6-icmp-type", ICMP6TYPE}, { "keep", KEEP}, + { "key", KEY}, { "label", LABEL}, { "limit", LIMIT}, { "log", LOG}, @@ -2742,6 +3008,7 @@ lookup(char *s) { "qlimit", QLIMIT}, { "queue", QUEUE}, { "quick", QUICK}, + { "random", RANDOM}, { "rdr", RDR}, { "reassemble", FRAGNORM}, { "red", RED}, @@ -2752,10 +3019,12 @@ lookup(char *s) { "return-icmp6",RETURNICMP6}, { "return-rst", RETURNRST}, { "rio", RIO}, + { "round-robin",ROUNDROBIN}, { "route-to", ROUTETO}, { "scheduler", SCHEDULER}, { "scrub", SCRUB}, { "set", SET}, + { "source-hash",SOURCEHASH}, { "state", STATE}, { "tbrsize", TBRSIZE}, { "timeout", TIMEOUT}, @@ -2887,6 +3156,7 @@ top: while (1) { if ((c = lgetc(fin)) == EOF) return (0); + if (p + 1 >= buf + sizeof(buf) - 1) { yyerror("string too long"); return (findeol()); @@ -3037,7 +3307,7 @@ set_ipmask(struct node_host *h, u_int8_t b) struct pf_addr *m, *n; int i, j = 0; - m = &h->mask; + m = &h->addr.mask; for (i = 0; i < 4; i++) m->addr32[i] = 0; @@ -3141,7 +3411,7 @@ ifa_load(void) memcpy(&n->addr.addr, &((struct sockaddr_in *) ifa->ifa_addr)->sin_addr.s_addr, sizeof(struct in_addr)); - memcpy(&n->mask, &((struct sockaddr_in *) + memcpy(&n->addr.mask, &((struct sockaddr_in *) ifa->ifa_netmask)->sin_addr.s_addr, sizeof(struct in_addr)); if (ifa->ifa_broadaddr != NULL) @@ -3152,7 +3422,7 @@ ifa_load(void) memcpy(&n->addr.addr, &((struct sockaddr_in6 *) ifa->ifa_addr)->sin6_addr.s6_addr, sizeof(struct in6_addr)); - memcpy(&n->mask, &((struct sockaddr_in6 *) + memcpy(&n->addr.mask, &((struct sockaddr_in6 *) ifa->ifa_netmask)->sin6_addr.s6_addr, sizeof(struct in6_addr)); if (ifa->ifa_broadaddr != NULL) @@ -3226,7 +3496,8 @@ ifa_lookup(char *ifa_name, enum pfctl_iflookup_mode mode) memcpy(&n->addr.addr, &p->addr.addr, sizeof(struct pf_addr)); if (mode == PFCTL_IFLOOKUP_NET) - memcpy(&n->mask, &p->mask, sizeof(struct pf_addr)); + memcpy(&n->addr.mask, &p->addr.mask, + sizeof(struct pf_addr)); else { if (n->af == AF_INET) set_ipmask(n, 32); @@ -3251,33 +3522,67 @@ ifa_lookup(char *ifa_name, enum pfctl_iflookup_mode mode) } struct node_host * -ifa_pick_ip(struct node_host *nh, sa_family_t af) +ifa_pick_ips(struct node_host *nh, sa_family_t af) { - struct node_host *h, *n = NULL; - - if (af == 0 && nh && nh->next) { - yyerror("address family not given and translation address " - "expands to multiple IPs"); - return (NULL); - } - for (h = nh; h; h = h->next) { - if (h->af == af || h->af == 0 || af == 0) { - if (n != NULL) { - yyerror("translation address expands to " - "multiple IPs of this address family"); - return (NULL); + struct node_host *d, *h = nh, *n = NULL, *ip = NULL, *ip6 = NULL; + + while (h != NULL) { + switch (h->af) { + case AF_INET: + if (ip == NULL) { + ip = h; + ip->tail = ip; + } else { + ip->tail->next = h; + ip->tail = h; + } + h = h->next; + ip->tail->next = NULL; + n = ip; + break; + case AF_INET6: + if (ip6 == NULL) { + ip6 = h; + ip6->tail = ip6; + } else { + ip6->tail->next = h; + ip6->tail = h; } - n = h; + h = h->next; + ip6->tail->next = NULL; + n = ip6; + break; } } + + switch (af) { + case AF_INET: + n = ip; + h = ip6; + break; + case AF_INET6: + n = ip6; + h = ip; + break; + default: + if (ip && ip6) { + yyerror("address family not given and translation " + "address expands to multiple address families"); + return (NULL); + } + h = NULL; + break; + } + if (n == NULL) yyerror("no translation address with matching address family " "found."); - else { - n->next = NULL; - n->tail = n; - } + while (h != NULL) { + d = h; + h = h->next; + free(d); + } return (n); } @@ -3317,6 +3622,7 @@ host(char *s, int mask) h = calloc(1, sizeof(struct node_host)); if (h == NULL) err(1, "address: calloc"); + h->ifname = NULL; h->af = AF_INET; h->addr.addr_dyn = NULL; h->addr.addr.addr32[0] = ina.s_addr; @@ -3336,6 +3642,7 @@ host(char *s, int mask) n = calloc(1, sizeof(struct node_host)); if (n == NULL) err(1, "address: calloc"); + n->ifname = NULL; n->af = AF_INET6; n->addr.addr_dyn = NULL; memcpy(&n->addr.addr, @@ -3365,6 +3672,7 @@ host(char *s, int mask) n = calloc(1, sizeof(struct node_host)); if (n == NULL) err(1, "address: calloc"); + n->ifname = NULL; n->af = res->ai_family; n->addr.addr_dyn = NULL; if (res->ai_family == AF_INET) { diff --git a/sbin/pfctl/pf_print_state.c b/sbin/pfctl/pf_print_state.c index a1fb6d4e4d0..03b715dffcb 100644 --- a/sbin/pfctl/pf_print_state.c +++ b/sbin/pfctl/pf_print_state.c @@ -1,4 +1,4 @@ -/* $OpenBSD: pf_print_state.c,v 1.9 2002/11/02 15:29:28 dhartmei Exp $ */ +/* $OpenBSD: pf_print_state.c,v 1.10 2002/11/23 05:22:24 mcbride Exp $ */ /* * Copyright (c) 2001 Daniel Hartmeier @@ -58,7 +58,7 @@ void print_name(struct pf_addr *, struct pf_addr *, sa_family_t); void -print_addr(struct pf_addr_wrap *addr, struct pf_addr *mask, sa_family_t af) +print_addr(struct pf_addr_wrap *addr, sa_family_t af) { char buf[48]; @@ -70,8 +70,8 @@ print_addr(struct pf_addr_wrap *addr, struct pf_addr *mask, sa_family_t af) else printf("%s", buf); } - if (mask != NULL) { - int bits = unmask(mask, af); + if (! PF_AZERO(&addr->mask, af)) { + int bits = unmask(&addr->mask, af); if (bits != (af == AF_INET ? 32 : 128)) printf("/%d", bits); @@ -122,8 +122,9 @@ print_host(struct pf_state_host *h, sa_family_t af, int opts) struct pf_addr_wrap aw; aw.addr = h->addr; + memset(&aw.mask, 0xff, sizeof(aw.mask)); aw.addr_dyn = NULL; - print_addr(&aw, NULL, af); + print_addr(&aw, af); } if (p) { diff --git a/sbin/pfctl/pf_print_state.h b/sbin/pfctl/pf_print_state.h index 989cc344913..f125c154f2a 100644 --- a/sbin/pfctl/pf_print_state.h +++ b/sbin/pfctl/pf_print_state.h @@ -1,4 +1,4 @@ -/* $OpenBSD: pf_print_state.h,v 1.6 2002/10/25 10:40:45 camield Exp $ */ +/* $OpenBSD: pf_print_state.h,v 1.7 2002/11/23 05:22:24 mcbride Exp $ */ /* * Copyright (c) 2001 Daniel Hartmeier @@ -33,7 +33,7 @@ #ifndef _PF_PRINT_STATE_H_ #define _PF_PRINT_STATE_H_ -void print_addr(struct pf_addr_wrap *, struct pf_addr *, sa_family_t); +void print_addr(struct pf_addr_wrap *, sa_family_t); void print_host(struct pf_state_host *, sa_family_t, int); void print_seq(struct pf_state_peer *); void print_state(struct pf_state *s, int); diff --git a/sbin/pfctl/pfctl.c b/sbin/pfctl/pfctl.c index 21274068121..115b6cc9ed8 100644 --- a/sbin/pfctl/pfctl.c +++ b/sbin/pfctl/pfctl.c @@ -1,4 +1,4 @@ -/* $OpenBSD: pfctl.c,v 1.87 2002/11/22 12:24:30 henning Exp $ */ +/* $OpenBSD: pfctl.c,v 1.88 2002/11/23 05:22:24 mcbride Exp $ */ /* * Copyright (c) 2001 Daniel Hartmeier @@ -62,6 +62,8 @@ int pfctl_clear_nat(int, int); int pfctl_clear_altq(int, int); int pfctl_clear_states(int, int); int pfctl_kill_states(int, int); +int pfctl_get_pool(int, struct pf_pool *, u_int32_t, u_int32_t, int); +void pfctl_clear_pool(struct pf_pool *); int pfctl_show_rules(int, int, int); int pfctl_show_nat(int); int pfctl_show_altq(int); @@ -72,6 +74,7 @@ int pfctl_show_limits(int); int pfctl_rules(int, char *, int); int pfctl_debug(int, u_int32_t, int); int pfctl_clear_rule_counters(int, int); +int pfctl_add_pool(struct pfctl *, struct pf_pool *, sa_family_t); char *clearopt; char *rulesopt; @@ -290,7 +293,7 @@ pfctl_kill_states(int dev, int opts) killed = sources = dests = 0; memset(&psk, 0, sizeof(psk)); - memset(&psk.psk_src.mask, 0xff, sizeof(psk.psk_src.mask)); + memset(&psk.psk_src.addr.mask, 0xff, sizeof(psk.psk_src.addr.mask)); memset(&last_src, 0xff, sizeof(last_src)); memset(&last_dst, 0xff, sizeof(last_dst)); @@ -321,8 +324,8 @@ pfctl_kill_states(int dev, int opts) if (state_killers > 1) { dests = 0; - memset(&psk.psk_dst.mask, 0xff, - sizeof(psk.psk_dst.mask)); + memset(&psk.psk_dst.addr.mask, 0xff, + sizeof(psk.psk_dst.addr.mask)); memset(&last_dst, 0xff, sizeof(last_dst)); if ((ret_ga = getaddrinfo(state_kill[1], NULL, NULL, &res[1]))) { @@ -380,6 +383,52 @@ pfctl_kill_states(int dev, int opts) } int +pfctl_get_pool(int dev, struct pf_pool *pool, u_int32_t nr, + u_int32_t ticket, int id) +{ + struct pfioc_pooladdr pp; + struct pf_pooladdr *pa; + u_int32_t pnr, mpnr; + + pp.r_id = id; + pp.r_num = nr; + pp.ticket = ticket; + if (ioctl(dev, DIOCGETADDRS, &pp)) { + warnx("DIOCGETADDRS"); + return (-1); + } + mpnr = pp.nr; + TAILQ_INIT(&pool->list); + for (pnr = 0; pnr < mpnr; ++pnr) { + pp.nr = pnr; + if (ioctl(dev, DIOCGETADDR, &pp)) { + warnx("DIOCGETADDR"); + return (-1); + } + pa = malloc(sizeof(struct pf_pooladdr)); + if (pa == NULL) { + err(1, "malloc"); + return (-1); + } + bcopy(&pp.addr, pa, sizeof(struct pf_pooladdr)); + TAILQ_INSERT_HEAD(&pool->list, pa, entries); + } + + return (0); +} + +void +pfctl_clear_pool(struct pf_pool *pool) +{ + struct pf_pooladdr *pa; + + TAILQ_FOREACH(pa, &pool->list, entries) { + TAILQ_REMOVE(&pool->list, pa, entries); + free(pa); + } +} + +int pfctl_show_rules(int dev, int opts, int format) { struct pfioc_rule pr; @@ -396,6 +445,11 @@ pfctl_show_rules(int dev, int opts, int format) warnx("DIOCGETRULE"); return (-1); } + + if (pfctl_get_pool(dev, &pr.rule.rt_pool, + nr, pr.ticket, PF_POOL_RULE_RT) != 0) + return (-1); + switch (format) { case 1: if (pr.rule.label[0]) { @@ -416,6 +470,7 @@ pfctl_show_rules(int dev, int opts, int format) pr.rule.evaluations, pr.rule.packets, pr.rule.bytes, pr.rule.states); } + pfctl_clear_pool(&pr.rule.rt_pool); } return (0); } @@ -466,7 +521,11 @@ pfctl_show_nat(int dev) warnx("DIOCGETNAT"); return (-1); } + if (pfctl_get_pool(dev, &pn.nat.rpool, nr, + pn.ticket, PF_POOL_NAT_R) != 0) + return (-1); print_nat(&pn.nat); + pfctl_clear_pool(&pn.nat.rpool); } if (ioctl(dev, DIOCGETRDRS, &pr)) { warnx("DIOCGETRDRS"); @@ -479,7 +538,11 @@ pfctl_show_nat(int dev) warnx("DIOCGETRDR"); return (-1); } + if (pfctl_get_pool(dev, &pr.rdr.rpool, nr, + pr.ticket, PF_POOL_RDR_R) != 0) + return (-1); print_rdr(&pr.rdr); + pfctl_clear_pool(&pr.rdr.rpool); } if (ioctl(dev, DIOCGETBINATS, &pb)) { warnx("DIOCGETBINATS"); @@ -584,12 +647,32 @@ pfctl_show_limits(int dev) return (0); } -/* callbacks for rule/nat/rdr */ +/* callbacks for rule/nat/rdr/addr */ +int +pfctl_add_pool(struct pfctl *pf, struct pf_pool *p, sa_family_t af) +{ + struct pf_pooladdr *pa; + + if (ioctl(pf->dev, DIOCBEGINADDRS, &pf->paddr.ticket)) + err(1, "DIOCBEGINADDRS"); + + pf->paddr.af = af; + TAILQ_FOREACH(pa, &p->list, entries) { + memcpy(&pf->paddr.addr, pa, sizeof(struct pf_pooladdr)); + if ((pf->opts & PF_OPT_NOACTION) == 0) { + if (ioctl(pf->dev, DIOCADDADDR, &pf->paddr)) + err(1, "DIOCADDADDR"); + } + } + return (0); +} int pfctl_add_rule(struct pfctl *pf, struct pf_rule *r) { if ((loadopt & (PFCTL_FLAG_FILTER | PFCTL_FLAG_ALL)) != 0) { + if (pfctl_add_pool(pf, &r->rt_pool, r->af)) + return (1); memcpy(&pf->prule->rule, r, sizeof(pf->prule->rule)); if ((pf->opts & PF_OPT_NOACTION) == 0) { if (ioctl(pf->dev, DIOCADDRULE, pf->prule)) @@ -597,6 +680,7 @@ pfctl_add_rule(struct pfctl *pf, struct pf_rule *r) } if (pf->opts & PF_OPT_VERBOSE) print_rule(&pf->prule->rule); + pfctl_clear_pool(&pf->prule->rule.rt_pool); } return (0); } @@ -605,6 +689,8 @@ int pfctl_add_nat(struct pfctl *pf, struct pf_nat *n) { if ((loadopt & (PFCTL_FLAG_NAT | PFCTL_FLAG_ALL)) != 0) { + if (pfctl_add_pool(pf, &n->rpool, n->af)) + return (1); memcpy(&pf->pnat->nat, n, sizeof(pf->pnat->nat)); if ((pf->opts & PF_OPT_NOACTION) == 0) { if (ioctl(pf->dev, DIOCADDNAT, pf->pnat)) @@ -612,6 +698,7 @@ pfctl_add_nat(struct pfctl *pf, struct pf_nat *n) } if (pf->opts & PF_OPT_VERBOSE) print_nat(&pf->pnat->nat); + pfctl_clear_pool(&pf->pnat->nat.rpool); } return (0); } @@ -635,6 +722,8 @@ int pfctl_add_rdr(struct pfctl *pf, struct pf_rdr *r) { if ((loadopt & (PFCTL_FLAG_NAT | PFCTL_FLAG_ALL)) != 0) { + if (pfctl_add_pool(pf, &r->rpool, r->af)) + return (1); memcpy(&pf->prdr->rdr, r, sizeof(pf->prdr->rdr)); if ((pf->opts & PF_OPT_NOACTION) == 0) { if (ioctl(pf->dev, DIOCADDRDR, pf->prdr)) @@ -642,6 +731,7 @@ pfctl_add_rdr(struct pfctl *pf, struct pf_rdr *r) } if (pf->opts & PF_OPT_VERBOSE) print_rdr(&pf->prdr->rdr); + pfctl_clear_pool(&pf->prdr->rdr.rpool); } return (0); } diff --git a/sbin/pfctl/pfctl_parser.c b/sbin/pfctl/pfctl_parser.c index 0ce41ae24dc..69655829fc9 100644 --- a/sbin/pfctl/pfctl_parser.c +++ b/sbin/pfctl/pfctl_parser.c @@ -1,4 +1,4 @@ -/* $OpenBSD: pfctl_parser.c,v 1.105 2002/11/19 23:34:02 dhartmei Exp $ */ +/* $OpenBSD: pfctl_parser.c,v 1.106 2002/11/23 05:22:24 mcbride Exp $ */ /* * Copyright (c) 2001 Daniel Hartmeier @@ -353,22 +353,22 @@ print_fromto(struct pf_rule_addr *src, struct pf_rule_addr *dst, sa_family_t af, u_int8_t proto) { if (PF_AZERO(&src->addr.addr, AF_INET6) && - PF_AZERO(&src->mask, AF_INET6) && + PF_AZERO(&src->addr.mask, AF_INET6) && !src->noroute && !dst->noroute && !src->port_op && PF_AZERO(&dst->addr.addr, AF_INET6) && - PF_AZERO(&dst->mask, AF_INET6) && !dst->port_op) + PF_AZERO(&dst->addr.mask, AF_INET6) && !dst->port_op) printf("all "); else { printf("from "); if (src->noroute) printf("no-route "); else if (PF_AZERO(&src->addr.addr, AF_INET6) && - PF_AZERO(&src->mask, AF_INET6)) + PF_AZERO(&src->addr.mask, AF_INET6)) printf("any "); else { if (src->not) printf("! "); - print_addr(&src->addr, &src->mask, af); + print_addr(&src->addr, af); printf(" "); } if (src->port_op) @@ -380,12 +380,12 @@ print_fromto(struct pf_rule_addr *src, struct pf_rule_addr *dst, if (dst->noroute) printf("no-route "); else if (PF_AZERO(&dst->addr.addr, AF_INET6) && - PF_AZERO(&dst->mask, AF_INET6)) + PF_AZERO(&dst->addr.mask, AF_INET6)) printf("any "); else { if (dst->not) printf("! "); - print_addr(&dst->addr, &dst->mask, af); + print_addr(&dst->addr, af); printf(" "); } if (dst->port_op) @@ -396,6 +396,34 @@ print_fromto(struct pf_rule_addr *src, struct pf_rule_addr *dst, } void +print_pool(struct pf_pool *pool, int af, int id) +{ + struct pf_pooladdr *pooladdr; + + if (TAILQ_NEXT(TAILQ_FIRST(&pool->list), entries) != NULL) + printf("{ "); + TAILQ_FOREACH(pooladdr, &pool->list, entries){ + switch (id) { + case PF_POOL_NAT_R: + case PF_POOL_RDR_R: + print_addr(&pooladdr->addr, af); + break; + case PF_POOL_RULE_RT: + printf("( %s", pooladdr->ifname); + if (! PF_AZERO(&pooladdr->addr.addr, af)) + printf(" "); + print_addr(&pooladdr->addr, af); + printf(" )"); + break; + } + if (TAILQ_NEXT(pooladdr, entries) != NULL) + printf(", "); + else if (TAILQ_NEXT(TAILQ_FIRST(&pool->list), entries) != NULL) + printf(" }"); + } +} + +void print_nat(struct pf_nat *n) { if (n->no) @@ -424,7 +452,7 @@ print_nat(struct pf_nat *n) print_fromto(&n->src, &n->dst, n->af, n->proto); if (!n->no) { printf("-> "); - print_addr(&n->raddr, NULL, n->af); + print_pool(&n->rpool, n->af, PF_POOL_NAT_R); if (n->proxy_port[0] != PF_NAT_PROXY_PORT_LOW || n->proxy_port[1] != PF_NAT_PROXY_PORT_HIGH) { if (n->proxy_port[0] == n->proxy_port[1]) @@ -433,6 +461,27 @@ print_nat(struct pf_nat *n) printf(" port %u:%u", n->proxy_port[0], n->proxy_port[1]); } + switch (n->rpool.opts & 0x0f) { + case PF_POOL_NONE: + break; + case PF_POOL_BITMASK: + printf(" bitmask"); + break; + case PF_POOL_RANDOM: + printf(" random"); + break; + case PF_POOL_SRCHASH: + printf(" source-hash"); + break; + case PF_POOL_SRCKEYHASH: + printf(" source-hash key"); + break; + case PF_POOL_ROUNDROBIN: + printf(" round-robin"); + break; + } + if (n->rpool.opts & PF_POOL_STATICPORT) + printf(" static-port"); } printf("\n"); } @@ -462,19 +511,20 @@ print_binat(struct pf_binat *b) printf("proto %u ", b->proto); } printf("from "); - print_addr(&b->saddr, &b->smask, b->af); + print_addr(&b->saddr, b->af); printf(" "); printf("to "); - if (!PF_AZERO(&b->daddr.addr, b->af) || !PF_AZERO(&b->dmask, b->af)) { + if (!PF_AZERO(&b->daddr.addr, b->af) || + !PF_AZERO(&b->daddr.mask, b->af)) { if (b->dnot) printf("! "); - print_addr(&b->daddr, &b->dmask, b->af); + print_addr(&b->daddr, b->af); printf(" "); } else printf("any "); if (!b->no) { printf("-> "); - print_addr(&b->raddr, &b->rmask, b->af); + print_addr(&b->raddr, b->af); } printf("\n"); } @@ -506,18 +556,20 @@ print_rdr(struct pf_rdr *r) printf("proto %u ", r->proto); } printf("from "); - if (!PF_AZERO(&r->saddr.addr, r->af) || !PF_AZERO(&r->smask, r->af)) { + if (!PF_AZERO(&r->saddr.addr, r->af) || + !PF_AZERO(&r->saddr.mask, r->af)) { if (r->snot) printf("! "); - print_addr(&r->saddr, &r->smask, r->af); + print_addr(&r->saddr, r->af); printf(" "); } else printf("any "); printf("to "); - if (!PF_AZERO(&r->daddr.addr, r->af) || !PF_AZERO(&r->dmask, r->af)) { + if (!PF_AZERO(&r->daddr.addr, r->af) || + !PF_AZERO(&r->daddr.mask, r->af)) { if (r->dnot) printf("! "); - print_addr(&r->daddr, &r->dmask, r->af); + print_addr(&r->daddr, r->af); printf(" "); } else printf("any "); @@ -528,13 +580,31 @@ print_rdr(struct pf_rdr *r) } if (!r->no) { printf(" -> "); - print_addr(&r->raddr, NULL, r->af); - printf(" "); + print_pool(&r->rpool, r->af, PF_POOL_RDR_R); if (r->rport) { - printf("port %u", ntohs(r->rport)); + printf(" port %u", ntohs(r->rport)); if (r->opts & PF_RPORT_RANGE) printf(":*"); } + switch (r->rpool.opts & 0x0f) { + case PF_POOL_NONE: + break; + case PF_POOL_BITMASK: + printf(" bitmask"); + break; + case PF_POOL_RANDOM: + printf(" random"); + break; + case PF_POOL_SRCHASH: + printf(" source-hash"); + break; + case PF_POOL_SRCKEYHASH: + printf(" source-hash key"); + break; + case PF_POOL_ROUNDROBIN: + printf(" round-robin"); + break; + } } printf("\n"); } @@ -703,16 +773,26 @@ print_rule(struct pf_rule *r) printf("dup-to "); else if (r->rt == PF_FASTROUTE) printf("fastroute"); - if (r->af && !PF_AZERO(&r->rt_addr, r->af)) { - struct pf_addr_wrap aw; - - printf("(%s ", r->rt_ifname); - aw.addr = r->rt_addr; - aw.addr_dyn = NULL; - print_addr(&aw, NULL, r->af); - printf(")"); - } else if (r->rt_ifname[0]) - printf("%s", r->rt_ifname); + print_pool(&r->rt_pool, r->af, PF_POOL_RULE_RT); + switch (r->rt_pool.opts & 0x0f) { + case PF_POOL_NONE: + break; + case PF_POOL_BITMASK: + printf(" bitmask"); + break; + case PF_POOL_RANDOM: + printf(" random"); + break; + case PF_POOL_SRCHASH: + printf(" source-hash"); + break; + case PF_POOL_SRCKEYHASH: + printf(" source-hash key"); + break; + case PF_POOL_ROUNDROBIN: + printf(" round-robin"); + break; + } printf(" "); } if (r->af) { diff --git a/sbin/pfctl/pfctl_parser.h b/sbin/pfctl/pfctl_parser.h index 29c30e3685f..38b11a4e54f 100644 --- a/sbin/pfctl/pfctl_parser.h +++ b/sbin/pfctl/pfctl_parser.h @@ -1,4 +1,4 @@ -/* $OpenBSD: pfctl_parser.h,v 1.27 2002/11/18 22:49:15 henning Exp $ */ +/* $OpenBSD: pfctl_parser.h,v 1.28 2002/11/23 05:22:24 mcbride Exp $ */ /* * Copyright (c) 2001 Daniel Hartmeier @@ -57,6 +57,7 @@ struct pfctl { int dev; int opts; u_int16_t rule_nr; + struct pfioc_pooladdr paddr; struct pfioc_rule *prule; struct pfioc_nat *pnat; struct pfioc_binat *pbinat; |