diff options
Diffstat (limited to 'sbin')
87 files changed, 582 insertions, 392 deletions
diff --git a/sbin/mount_nfs/mount_nfs.c b/sbin/mount_nfs/mount_nfs.c index 189bdd70b398..6ba51eeec588 100644 --- a/sbin/mount_nfs/mount_nfs.c +++ b/sbin/mount_nfs/mount_nfs.c @@ -587,6 +587,7 @@ getnfsargs(char **specp, char **hostpp, struct iovec **iov, int *iovlen) char *hostp, *delimp, *errstr, *spec; size_t len; static char nam[MNAMELEN + 1], pname[MAXHOSTNAMELEN + 5]; + bool resolved; spec = *specp; if (*spec == '[' && (delimp = strchr(spec + 1, ']')) != NULL && @@ -643,30 +644,7 @@ getnfsargs(char **specp, char **hostpp, struct iovec **iov, int *iovlen) else if (nfsproto == IPPROTO_UDP) hints.ai_socktype = SOCK_DGRAM; - if (getaddrinfo(hostp, portspec, &hints, &ai_nfs) != 0) { - hints.ai_flags = AI_CANONNAME; - if ((ecode = getaddrinfo(hostp, portspec, &hints, &ai_nfs)) - != 0) { - if (portspec == NULL) - errx(1, "%s: %s", hostp, gai_strerror(ecode)); - else - errx(1, "%s:%s: %s", hostp, portspec, - gai_strerror(ecode)); - return (0); - } - - /* - * For a Kerberized nfs mount where the "principal" - * argument has not been set, add it here. - */ - if (got_principal == 0 && secflavor != AUTH_SYS && - ai_nfs->ai_canonname != NULL) { - snprintf(pname, sizeof (pname), "nfs@%s", - ai_nfs->ai_canonname); - build_iovec(iov, iovlen, "principal", pname, - strlen(pname) + 1); - } - } + resolved = (getaddrinfo(hostp, portspec, &hints, &ai_nfs) == 0); if ((opflags & (BGRNDNOW | ISBGRND)) == BGRNDNOW) { warnx("Mount %s:%s, backgrounding", @@ -678,6 +656,37 @@ getnfsargs(char **specp, char **hostpp, struct iovec **iov, int *iovlen) ret = TRYRET_LOCALERR; for (;;) { + if (!resolved) { + hints.ai_flags = AI_CANONNAME; + if ((ecode = getaddrinfo(hostp, portspec, &hints, + &ai_nfs)) != 0) { + if (portspec == NULL) + warnx("%s: %s", hostp, + gai_strerror(ecode)); + else + warnx("%s:%s: %s", hostp, portspec, + gai_strerror(ecode)); + if (ecode == EAI_AGAIN && + (opflags & (BGRNDNOW | BGRND))) + goto retry; + else + exit(1); + } + resolved = true; + /* + * For a Kerberized nfs mount where the + * "principal" argument has not been set, add + * it here. + */ + if (got_principal == 0 && secflavor != AUTH_SYS && + ai_nfs->ai_canonname != NULL) { + snprintf(pname, sizeof (pname), "nfs@%s", + ai_nfs->ai_canonname); + build_iovec(iov, iovlen, "principal", pname, + strlen(pname) + 1); + } + } + /* * Try each entry returned by getaddrinfo(). Note the * occurrence of remote errors by setting `remoteerr'. @@ -705,7 +714,7 @@ getnfsargs(char **specp, char **hostpp, struct iovec **iov, int *iovlen) /* Exit if all errors were local. */ if (!remoteerr) exit(1); - +retry: /* * If retrycnt == 0, we are to keep retrying forever. * Otherwise decrement it, and exit if it hits zero. diff --git a/sbin/pfctl/parse.y b/sbin/pfctl/parse.y index 8f732bdf268a..ea81efd7fd94 100644 --- a/sbin/pfctl/parse.y +++ b/sbin/pfctl/parse.y @@ -227,10 +227,6 @@ struct range { int b; int t; }; -struct redirection { - struct node_host *host; - struct range rport; -}; static struct pool_opts { int marker; @@ -245,9 +241,10 @@ static struct pool_opts { } pool_opts; struct redirspec { - struct redirection *rdr; + struct node_host *host; + struct range rport; struct pool_opts pool_opts; - int af; + int af; }; static struct filter_opts { @@ -302,9 +299,8 @@ static struct filter_opts { struct node_host *addr; u_int16_t port; } divert; - struct redirspec nat; - struct redirspec rdr; - struct redirspec rroute; + struct redirspec *nat; + struct redirspec *rdr; /* new-style scrub opts */ int nodf; int minttl; @@ -382,9 +378,11 @@ void expand_eth_rule(struct pfctl_eth_rule *, struct node_mac *, struct node_mac *, struct node_host *, struct node_host *, const char *, const char *); +int apply_rdr_ports(struct pfctl_rule *r, struct pfctl_pool *, struct redirspec *); +int apply_nat_ports(struct pfctl_pool *, struct redirspec *); +int apply_redirspec(struct pfctl_pool *, struct redirspec *); void expand_rule(struct pfctl_rule *, struct node_if *, struct redirspec *, struct redirspec *, struct redirspec *, - struct node_host *, struct node_host *, struct node_host *, struct node_proto *, struct node_os *, struct node_host *, struct node_port *, struct node_host *, struct node_port *, struct node_uid *, struct node_gid *, struct node_if *, @@ -463,13 +461,10 @@ typedef struct { } etheraddr; char *bridge_to; struct { - struct node_host *host; + struct redirspec *redirspec; u_int8_t rt; - u_int8_t pool_opts; - sa_family_t af; - struct pf_poolhashkey *key; } route; - struct redirection *redirection; + struct redirspec *redirspec; struct { int action; struct node_state_opt *options; @@ -554,14 +549,15 @@ int parseport(char *, struct range *r, int); %type <v.fromto> fromto l3fromto %type <v.peer> ipportspec from to %type <v.host> ipspec toipspec xhost host dynaddr host_list -%type <v.host> redir_host_list redirspec -%type <v.host> route_host route_host_list routespec +%type <v.host> redir_host redir_host_list routespec +%type <v.host> route_host route_host_list %type <v.os> os xos os_list %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 redirpool +%type <v.redirspec> no_port_redirspec port_redirspec route_redirspec +%type <v.redirspec> binat_redirspec nat_redirspec %type <v.string> label stringall tag anchorname %type <v.string> string varstring numberstring %type <v.keep_state> keep @@ -965,7 +961,8 @@ anchorrule : ANCHOR anchorname dir quick interface af proto fromto YYERROR; } - memset(&r, 0, sizeof(r)); + pfctl_init_rule(&r); + if (pf->astack[pf->asd + 1]) { if ($2 && strchr($2, '/') != NULL) { free($2); @@ -978,7 +975,7 @@ anchorrule : ANCHOR anchorname dir quick interface af proto fromto pfctl_anchor_setup(&r, &pf->astack[pf->asd]->ruleset, $2 ? $2 : pf->alast->name); - + if (r.anchor == NULL) err(1, "anchorrule: unable to " "create ruleset"); @@ -1082,7 +1079,7 @@ anchorrule : ANCHOR anchorname dir quick interface af proto fromto decide_address_family($8.src.host, &r.af); decide_address_family($8.dst.host, &r.af); - expand_rule(&r, $5, NULL, NULL, NULL, NULL, NULL, NULL, + expand_rule(&r, $5, NULL, NULL, NULL, $7, $8.src_os, $8.src.host, $8.src.port, $8.dst.host, $8.dst.port, $9.uid, $9.gid, $9.rcv, $9.icmpspec, pf->astack[pf->asd + 1] ? pf->alast->name : $2); @@ -1097,7 +1094,8 @@ anchorrule : ANCHOR anchorname dir quick interface af proto fromto YYERROR; } - memset(&r, 0, sizeof(r)); + pfctl_init_rule(&r); + r.action = PF_NAT; r.af = $4; r.rtableid = $7; @@ -1105,7 +1103,7 @@ anchorrule : ANCHOR anchorname dir quick interface af proto fromto decide_address_family($6.src.host, &r.af); decide_address_family($6.dst.host, &r.af); - expand_rule(&r, $3, NULL, NULL, NULL, NULL, NULL, NULL, + expand_rule(&r, $3, NULL, NULL, NULL, $5, $6.src_os, $6.src.host, $6.src.port, $6.dst.host, $6.dst.port, 0, 0, 0, 0, $2); free($2); @@ -1118,7 +1116,8 @@ anchorrule : ANCHOR anchorname dir quick interface af proto fromto YYERROR; } - memset(&r, 0, sizeof(r)); + pfctl_init_rule(&r); + r.action = PF_RDR; r.af = $4; r.rtableid = $7; @@ -1147,7 +1146,7 @@ anchorrule : ANCHOR anchorname dir quick interface af proto fromto r.dst.port_op = $6.dst.port->op; } - expand_rule(&r, $3, NULL, NULL, NULL, NULL, NULL, NULL, + expand_rule(&r, $3, NULL, NULL, NULL, $5, $6.src_os, $6.src.host, $6.src.port, $6.dst.host, $6.dst.port, 0, 0, 0, 0, $2); free($2); @@ -1160,7 +1159,8 @@ anchorrule : ANCHOR anchorname dir quick interface af proto fromto YYERROR; } - memset(&r, 0, sizeof(r)); + pfctl_init_rule(&r); + r.action = PF_BINAT; r.af = $4; r.rtableid = $7; @@ -1425,7 +1425,7 @@ scrubrule : scrubaction dir logquick interface af proto fromto scrub_opts if (check_rulestate(PFCTL_STATE_SCRUB)) YYERROR; - memset(&r, 0, sizeof(r)); + pfctl_init_rule(&r); r.action = $1.b1; r.direction = $2; @@ -1470,7 +1470,7 @@ scrubrule : scrubaction dir logquick interface af proto fromto scrub_opts r.match_tag_not = $8.match_tag_not; r.rtableid = $8.rtableid; - expand_rule(&r, $4, NULL, NULL, NULL, NULL, NULL, NULL, + expand_rule(&r, $4, NULL, NULL, NULL, $6, $7.src_os, $7.src.host, $7.src.port, $7.dst.host, $7.dst.port, NULL, NULL, NULL, NULL, ""); } @@ -1587,7 +1587,7 @@ antispoof : ANTISPOOF logquick antispoof_ifspc af antispoof_opts { YYERROR; for (i = $3; i; i = i->next) { - bzero(&r, sizeof(r)); + pfctl_init_rule(&r); r.action = PF_DROP; r.direction = PF_IN; @@ -1635,9 +1635,9 @@ antispoof : ANTISPOOF logquick antispoof_ifspc af antispoof_opts { } if (h != NULL) - expand_rule(&r, j, NULL, NULL, NULL, NULL, NULL, NULL, - NULL, NULL, h, NULL, NULL, NULL, NULL, NULL, - NULL, NULL, ""); + expand_rule(&r, j, NULL, NULL, NULL, + NULL, NULL, h, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, ""); if ((i->ifa_flags & IFF_LOOPBACK) == 0) { bzero(&r, sizeof(r)); @@ -1657,9 +1657,10 @@ antispoof : ANTISPOOF logquick antispoof_ifspc af antispoof_opts { else h = ifa_lookup(i->ifname, 0); if (h != NULL) - expand_rule(&r, NULL, NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, h, NULL, NULL, - NULL, NULL, NULL, NULL, NULL, ""); + expand_rule(&r, NULL, NULL, + NULL, NULL, NULL, NULL, h, + NULL, NULL, NULL, NULL, + NULL, NULL, NULL, ""); } else free(hh); } @@ -2371,7 +2372,7 @@ pfrule : action dir logquick interface route af proto fromto if (check_rulestate(PFCTL_STATE_FILTER)) YYERROR; - memset(&r, 0, sizeof(r)); + pfctl_init_rule(&r); r.action = $1.b1; switch ($1.b2) { @@ -2728,44 +2729,14 @@ pfrule : action dir logquick interface route af proto fromto YYERROR; } r.rt = $5.rt; - r.route.opts = $5.pool_opts; - if ($5.key != NULL) - memcpy(&r.route.key, $5.key, - sizeof(struct pf_poolhashkey)); - } - if (r.rt) { - decide_address_family($5.host, &r.af); + decide_address_family($5.redirspec->host, &r.af); if (!(r.rule_flag & PFRULE_AFTO)) - remove_invalid_hosts(&$5.host, &r.af); - if ($5.host == NULL) { + remove_invalid_hosts(&($5.redirspec->host), &r.af); + if ($5.redirspec->host == NULL) { yyerror("no routing address with " "matching address family found."); YYERROR; } - if ((r.route.opts & PF_POOL_TYPEMASK) == - PF_POOL_NONE && ($5.host->next != NULL || - $5.host->addr.type == PF_ADDR_TABLE || - DYNIF_MULTIADDR($5.host->addr))) - r.route.opts |= PF_POOL_ROUNDROBIN; - if ($5.host->next != NULL && - !PF_POOL_DYNTYPE(r.route.opts)) { - yyerror("address pool option " - "not supported by type"); - } - if (!PF_POOL_DYNTYPE(r.route.opts) && - (disallow_table($5.host, - "tables are not supported by pool type") || - disallow_alias($5.host, - "interface (%s) is not supported by pool type"))) - YYERROR; - if ($5.host->next != NULL) { - if ((r.route.opts & PF_POOL_TYPEMASK) != - PF_POOL_ROUNDROBIN) { - yyerror("r.route.opts must " - "be PF_POOL_ROUNDROBIN"); - YYERROR; - } - } } if ($9.queues.qname != NULL) { if (strlcpy(r.qname, $9.queues.qname, @@ -2824,19 +2795,10 @@ pfrule : action dir logquick interface route af proto fromto } if ($9.marker & FOM_AFTO) { - r.naf = $9.nat.af; - - r.nat.opts = $9.nat.pool_opts.type; - r.nat.opts |= $9.nat.pool_opts.opts; - - if (!PF_POOL_DYNTYPE(r.nat.opts) && - disallow_table($9.nat.rdr->host, "tables are not " - "supported by pool type")) - YYERROR; + r.naf = $9.nat->af; } - expand_rule(&r, $4, &$9.nat, &$9.rdr, &$9.rroute, - NULL, $9.nat.rdr ? $9.nat.rdr->host : NULL, $5.host, + expand_rule(&r, $4, $9.nat, $9.rdr, $5.redirspec, $7, $8.src_os, $8.src.host, $8.src.port, $8.dst.host, $8.dst.port, $9.uid, $9.gid, $9.rcv, $9.icmpspec, ""); } @@ -3053,8 +3015,8 @@ filter_opt : USER uids { filter_opts.marker |= FOM_SCRUB_TCP; filter_opts.marker |= $3.marker; } - | AFTO af FROM redirspec pool_opts { - if (filter_opts.nat.rdr) { + | AFTO af FROM port_redirspec { + if (filter_opts.nat) { yyerror("cannot respecify af-to"); YYERROR; } @@ -3062,26 +3024,18 @@ filter_opt : USER uids { yyerror("no address family specified"); YYERROR; } + + filter_opts.nat = $4; + filter_opts.nat->af = $2; if ($4->af && $4->af != $2) { yyerror("af-to addresses must be in the " "target address family"); YYERROR; } - filter_opts.nat.af = $2; - filter_opts.nat.rdr = calloc(1, sizeof(struct redirection)); - if (filter_opts.nat.rdr == NULL) - err(1, "af-to: calloc"); - filter_opts.nat.rdr->host = $4; - memcpy(&filter_opts.nat.pool_opts, &$5, - sizeof(filter_opts.nat.pool_opts)); - filter_opts.rdr.rdr = - calloc(1, sizeof(struct redirection)); - bzero(&filter_opts.rdr.pool_opts, - sizeof(filter_opts.rdr.pool_opts)); filter_opts.marker |= FOM_AFTO; } - | AFTO af FROM redirspec pool_opts TO redirspec pool_opts { - if (filter_opts.nat.rdr) { + | AFTO af FROM port_redirspec TO port_redirspec { + if (filter_opts.nat) { yyerror("cannot respecify af-to"); YYERROR; } @@ -3089,26 +3043,16 @@ filter_opt : USER uids { yyerror("no address family specified"); YYERROR; } - if (($4->af && $4->af != $2) || - ($7->af && $7->af != $2)) { + filter_opts.nat = $4; + filter_opts.nat->af = $2; + filter_opts.rdr = $6; + filter_opts.rdr->af = $2; + if (($4->af && $4->host->af != $2) || + ($6->af && $6->host->af != $2)) { yyerror("af-to addresses must be in the " "target address family"); YYERROR; } - filter_opts.nat.af = $2; - filter_opts.nat.rdr = calloc(1, sizeof(struct redirection)); - if (filter_opts.nat.rdr == NULL) - err(1, "af-to: calloc"); - filter_opts.nat.rdr->host = $4; - memcpy(&filter_opts.nat.pool_opts, &$5, - sizeof(filter_opts.nat.pool_opts)); - filter_opts.rdr.af = $2; - filter_opts.rdr.rdr = calloc(1, sizeof(struct redirection)); - if (filter_opts.rdr.rdr == NULL) - err(1, "af-to: calloc"); - filter_opts.rdr.rdr->host = $7; - memcpy(&filter_opts.nat.pool_opts, &$8, - sizeof(filter_opts.nat.pool_opts)); filter_opts.marker |= FOM_AFTO; } | filter_sets @@ -4580,7 +4524,7 @@ portstar : numberstring { } ; -redirspec : host { $$ = $1; } +redir_host : host { $$ = $1; } | '{' optnl redir_host_list '}' { $$ = $3; } ; @@ -4592,20 +4536,41 @@ redir_host_list : host optnl { $$ = $1; } } ; -redirpool : /* empty */ { $$ = NULL; } - | ARROW redirspec { - $$ = calloc(1, sizeof(struct redirection)); +/* Redirection without port */ +no_port_redirspec: redir_host pool_opts { + $$ = calloc(1, sizeof(struct redirspec)); if ($$ == NULL) - err(1, "redirection: calloc"); - $$->host = $2; + err(1, "redirspec: calloc"); + $$->host = $1; + $$->pool_opts = $2; $$->rport.a = $$->rport.b = $$->rport.t = 0; } - | ARROW redirspec PORT portstar { - $$ = calloc(1, sizeof(struct redirection)); + ; + +/* Redirection with optional port */ +port_redirspec : no_port_redirspec; + | redir_host PORT portstar pool_opts { + $$ = calloc(1, sizeof(struct redirspec)); if ($$ == NULL) - err(1, "redirection: calloc"); - $$->host = $2; - $$->rport = $4; + err(1, "redirspec: calloc"); + $$->host = $1; + $$->rport = $3; + $$->pool_opts = $4; + } + +/* Redirection with an arrow and an optional port: FreeBSD NAT rules */ +nat_redirspec : ARROW port_redirspec { + $$ = $2; + } + ; + +/* Redirection with interfaces and without ports: route-to rules */ +route_redirspec : routespec pool_opts { + $$ = calloc(1, sizeof(struct redirspec)); + if ($$ == NULL) + err(1, "redirspec: calloc"); + $$->host = $1; + $$->pool_opts = $2; } ; @@ -4756,18 +4721,18 @@ pool_opt : BITMASK { } ; -redirection : /* empty */ { $$ = NULL; } +binat_redirspec : /* empty */ { $$ = NULL; } | ARROW host { - $$ = calloc(1, sizeof(struct redirection)); + $$ = calloc(1, sizeof(struct redirspec)); if ($$ == NULL) - err(1, "redirection: calloc"); + err(1, "redirspec: calloc"); $$->host = $2; $$->rport.a = $$->rport.b = $$->rport.t = 0; } | ARROW host PORT portstar { - $$ = calloc(1, sizeof(struct redirection)); + $$ = calloc(1, sizeof(struct redirspec)); if ($$ == NULL) - err(1, "redirection: calloc"); + err(1, "redirspec: calloc"); $$->host = $2; $$->rport = $4; } @@ -4808,7 +4773,7 @@ nataction : no NAT natpasslog { ; natrule : nataction interface af proto fromto tag tagged rtable - redirpool pool_opts + nat_redirspec { struct pfctl_rule r; struct node_state_opt *o; @@ -4816,7 +4781,7 @@ natrule : nataction interface af proto fromto tag tagged rtable if (check_rulestate(PFCTL_STATE_NAT)) YYERROR; - memset(&r, 0, sizeof(r)); + pfctl_init_rule(&r); r.action = $1.b1; r.natpass = $1.b2; @@ -4875,110 +4840,6 @@ natrule : nataction interface af proto fromto tag tagged rtable } if (check_netmask($9->host, r.af)) YYERROR; - - r.rdr.proxy_port[0] = ntohs($9->rport.a); - - switch (r.action) { - case PF_RDR: - if (!$9->rport.b && $9->rport.t && - $5.dst.port != NULL) { - r.rdr.proxy_port[1] = - ntohs($9->rport.a) + - (ntohs( - $5.dst.port->port[1]) - - ntohs( - $5.dst.port->port[0])); - } else - r.rdr.proxy_port[1] = - ntohs($9->rport.b); - break; - case PF_NAT: - r.rdr.proxy_port[1] = - ntohs($9->rport.b); - if (!r.rdr.proxy_port[0] && - !r.rdr.proxy_port[1]) { - r.rdr.proxy_port[0] = - PF_NAT_PROXY_PORT_LOW; - r.rdr.proxy_port[1] = - PF_NAT_PROXY_PORT_HIGH; - } else if (!r.rdr.proxy_port[1]) - r.rdr.proxy_port[1] = - r.rdr.proxy_port[0]; - break; - default: - break; - } - - r.rdr.opts = $10.type; - if ((r.rdr.opts & PF_POOL_TYPEMASK) == - PF_POOL_NONE && ($9->host->next != NULL || - $9->host->addr.type == PF_ADDR_TABLE || - DYNIF_MULTIADDR($9->host->addr))) - r.rdr.opts = PF_POOL_ROUNDROBIN; - if (!PF_POOL_DYNTYPE(r.rdr.opts) && - (disallow_table($9->host, - "tables are not supported by pool type") || - disallow_alias($9->host, - "interface (%s) is not supported by pool type"))) - YYERROR; - if ($9->host->next != NULL) { - if ((r.rdr.opts & PF_POOL_TYPEMASK) != - PF_POOL_ROUNDROBIN) { - yyerror("only round-robin " - "valid for multiple " - "redirection addresses"); - YYERROR; - } - } - } - - if ($10.key != NULL) - memcpy(&r.rdr.key, $10.key, - sizeof(struct pf_poolhashkey)); - - if ($10.opts) - r.rdr.opts |= $10.opts; - - if ($10.staticport) { - if (r.action != PF_NAT) { - yyerror("the 'static-port' option is " - "only valid with nat rules"); - YYERROR; - } - if (r.rdr.proxy_port[0] != - PF_NAT_PROXY_PORT_LOW && - r.rdr.proxy_port[1] != - PF_NAT_PROXY_PORT_HIGH) { - yyerror("the 'static-port' option can't" - " be used when specifying a port" - " range"); - YYERROR; - } - r.rdr.proxy_port[0] = 0; - r.rdr.proxy_port[1] = 0; - } - - if ($10.mape.offset) { - if (r.action != PF_NAT) { - yyerror("the 'map-e-portset' option is" - " only valid with nat rules"); - YYERROR; - } - if ($10.staticport) { - yyerror("the 'map-e-portset' option" - " can't be used 'static-port'"); - YYERROR; - } - if (r.rdr.proxy_port[0] != - PF_NAT_PROXY_PORT_LOW && - r.rdr.proxy_port[1] != - PF_NAT_PROXY_PORT_HIGH) { - yyerror("the 'map-e-portset' option" - " can't be used when specifying" - " a port range"); - YYERROR; - } - r.rdr.mape = $10.mape; } o = keep_state_defaults; @@ -4996,16 +4857,14 @@ natrule : nataction interface af proto fromto tag tagged rtable o = o->next; } - expand_rule(&r, $2, NULL, NULL, NULL, - $9 == NULL ? NULL : $9->host, NULL, NULL, $4, + expand_rule(&r, $2, NULL, $9, NULL, $4, $5.src_os, $5.src.host, $5.src.port, $5.dst.host, $5.dst.port, 0, 0, 0, 0, ""); - free($9); } ; binatrule : no BINAT natpasslog interface af proto FROM ipspec toipspec tag - tagged rtable redirection + tagged rtable binat_redirspec { struct pfctl_rule binat; struct pf_pooladdr *pa; @@ -5016,7 +4875,7 @@ binatrule : no BINAT natpasslog interface af proto FROM ipspec toipspec tag "permitted as a binat destination")) YYERROR; - memset(&binat, 0, sizeof(binat)); + pfctl_init_rule(&binat); if ($1 && $3.b1) { yyerror("\"pass\" not valid with \"no\""); @@ -5249,36 +5108,23 @@ routespec : route_host { $$ = $1; } ; route : /* empty */ { - $$.host = NULL; - $$.rt = 0; - $$.pool_opts = 0; + $$.rt = PF_NOPFROUTE; } | FASTROUTE { /* backwards-compat */ - $$.host = NULL; - $$.rt = 0; - $$.pool_opts = 0; + $$.rt = PF_NOPFROUTE; } - | ROUTETO routespec pool_opts { - $$.host = $2; + | ROUTETO route_redirspec { $$.rt = PF_ROUTETO; - $$.pool_opts = $3.type | $3.opts; - if ($3.key != NULL) - $$.key = $3.key; + $$.redirspec = $2; } - | REPLYTO routespec pool_opts { - $$.host = $2; + | REPLYTO route_redirspec { $$.rt = PF_REPLYTO; - $$.pool_opts = $3.type | $3.opts; - if ($3.key != NULL) - $$.key = $3.key; + $$.redirspec = $2; } - | DUPTO routespec pool_opts { - $$.host = $2; + | DUPTO route_redirspec { $$.rt = PF_DUPTO; - $$.pool_opts = $3.type | $3.opts; - if ($3.key != NULL) - $$.key = $3.key; + $$.redirspec = $2; } ; @@ -6161,12 +6007,144 @@ expand_eth_rule(struct pfctl_eth_rule *r, FREE_LIST(struct node_host, ipdsts); } +int +apply_rdr_ports(struct pfctl_rule *r, struct pfctl_pool *rpool, struct redirspec *rs) +{ + if (rs == NULL) + return 0; + + rpool->proxy_port[0] = ntohs(rs->rport.a); + + if (!rs->rport.b && rs->rport.t && r->dst.port != NULL) { + rpool->proxy_port[1] = ntohs(rs->rport.a) + + (ntohs(r->dst.port[1]) - ntohs(r->dst.port[0])); + } else + r->rdr.proxy_port[1] = ntohs(rs->rport.b); + + if (rs->pool_opts.staticport) { + yyerror("the 'static-port' option is only valid with nat rules"); + return 1; + } + + if (rs->pool_opts.mape.offset) { + yyerror("the 'map-e-portset' option is only valid with nat rules"); + return 1; + } + + return 0; +} + +int +apply_nat_ports(struct pfctl_pool *rpool, struct redirspec *rs) +{ + if (rs == NULL) + return 0; + + rpool->proxy_port[0] = ntohs(rs->rport.a); + rpool->proxy_port[1] = ntohs(rs->rport.b); + if (!rpool->proxy_port[0] && !rpool->proxy_port[1]) { + rpool->proxy_port[0] = PF_NAT_PROXY_PORT_LOW; + rpool->proxy_port[1] = PF_NAT_PROXY_PORT_HIGH; + } else if (!rpool->proxy_port[1]) + rpool->proxy_port[1] = rpool->proxy_port[0]; + + if (rs->pool_opts.staticport) { + if (rpool->proxy_port[0] != PF_NAT_PROXY_PORT_LOW && + rpool->proxy_port[1] != PF_NAT_PROXY_PORT_HIGH) { + yyerror("the 'static-port' option can't" + " be used when specifying a port" + " range"); + return 1; + } + rpool->proxy_port[0] = 0; + rpool->proxy_port[1] = 0; + } + + if (rs->pool_opts.mape.offset) { + if (rs->pool_opts.staticport) { + yyerror("the 'map-e-portset' option" + " can't be used 'static-port'"); + return 1; + } + if (rpool->proxy_port[0] != PF_NAT_PROXY_PORT_LOW && + rpool->proxy_port[1] != PF_NAT_PROXY_PORT_HIGH) { + yyerror("the 'map-e-portset' option" + " can't be used when specifying" + " a port range"); + return 1; + } + rpool->mape = rs->pool_opts.mape; + } + + return 0; +} + +int +apply_redirspec(struct pfctl_pool *rpool, struct redirspec *rs) +{ + struct node_host *h; + struct pf_pooladdr *pa; + + if (rs == NULL) + return 0; + + rpool->opts = rs->pool_opts.type; + + if ((rpool->opts & PF_POOL_TYPEMASK) == PF_POOL_NONE && + (rs->host->next != NULL || + rs->host->addr.type == PF_ADDR_TABLE || + DYNIF_MULTIADDR(rs->host->addr))) + rpool->opts = PF_POOL_ROUNDROBIN; + + if (!PF_POOL_DYNTYPE(rpool->opts) && + (disallow_table(rs->host, "tables are not supported by pool type") || + disallow_alias(rs->host, "interface (%s) is not supported by pool type"))) + return 1; + + if (rs->host->next != NULL && + ((rpool->opts & PF_POOL_TYPEMASK) != PF_POOL_ROUNDROBIN)) { + yyerror("r.route.opts must be PF_POOL_ROUNDROBIN"); + return 1; + } + + if (rs->host->next != NULL) { + if ((rpool->opts & PF_POOL_TYPEMASK) != + PF_POOL_ROUNDROBIN) { + yyerror("only round-robin valid for multiple " + "redirection addresses"); + return 1; + } + } + + rpool->opts |= rs->pool_opts.opts; + + if (rs->pool_opts.key != NULL) + memcpy(&(rpool->key), rs->pool_opts.key, + sizeof(struct pf_poolhashkey)); + + TAILQ_INIT(&(rpool->list)); + for (h = rs->host; h != NULL; h = h->next) { + pa = calloc(1, sizeof(struct pf_pooladdr)); + if (pa == NULL) + err(1, "expand_rule: calloc"); + pa->addr = h->addr; + if (h->ifname != NULL) { + if (strlcpy(pa->ifname, h->ifname, + sizeof(pa->ifname)) >= sizeof(pa->ifname)) + errx(1, "expand_rule: strlcpy"); + } else + pa->ifname[0] = 0; + TAILQ_INSERT_TAIL(&(rpool->list), pa, entries); + } + + return 0; +} + void expand_rule(struct pfctl_rule *r, struct node_if *interfaces, struct redirspec *nat, struct redirspec *rdr, struct redirspec *route, - struct node_host *rdr_hosts, struct node_host *nat_hosts, - struct node_host *route_hosts, struct node_proto *protos, + struct node_proto *protos, struct node_os *src_oses, 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, @@ -6178,8 +6156,7 @@ expand_rule(struct pfctl_rule *r, char label[PF_RULE_MAX_LABEL_COUNT][PF_RULE_LABEL_SIZE]; char tagname[PF_TAG_NAME_SIZE]; char match_tagname[PF_TAG_NAME_SIZE]; - struct pf_pooladdr *pa; - struct node_host *h, *osrch, *odsth; + struct node_host *osrch, *odsth; u_int8_t flags, flagset, keep_state; memcpy(label, r->label, sizeof(r->label)); @@ -6317,52 +6294,16 @@ expand_rule(struct pfctl_rule *r, r->os_fingerprint = PF_OSFP_ANY; } - TAILQ_INIT(&r->rdr.list); - for (h = rdr_hosts; h != NULL; h = h->next) { - pa = calloc(1, sizeof(struct pf_pooladdr)); - if (pa == NULL) - err(1, "expand_rule: calloc"); - pa->addr = h->addr; - if (h->ifname != NULL) { - if (strlcpy(pa->ifname, h->ifname, - sizeof(pa->ifname)) >= - sizeof(pa->ifname)) - errx(1, "expand_rule: strlcpy"); - } else - pa->ifname[0] = 0; - TAILQ_INSERT_TAIL(&r->rdr.list, pa, entries); - } - TAILQ_INIT(&r->nat.list); - for (h = nat_hosts; h != NULL; h = h->next) { - pa = calloc(1, sizeof(struct pf_pooladdr)); - if (pa == NULL) - err(1, "expand_rule: calloc"); - pa->addr = h->addr; - if (h->ifname != NULL) { - if (strlcpy(pa->ifname, h->ifname, - sizeof(pa->ifname)) >= - sizeof(pa->ifname)) - errx(1, "expand_rule: strlcpy"); - } else - pa->ifname[0] = 0; - TAILQ_INSERT_TAIL(&r->nat.list, pa, entries); - } - TAILQ_INIT(&r->route.list); - for (h = route_hosts; h != NULL; h = h->next) { - pa = calloc(1, sizeof(struct pf_pooladdr)); - if (pa == NULL) - err(1, "expand_rule: calloc"); - pa->addr = h->addr; - if (h->ifname != NULL) { - if (strlcpy(pa->ifname, h->ifname, - sizeof(pa->ifname)) >= - sizeof(pa->ifname)) - errx(1, "expand_rule: strlcpy"); - } else - pa->ifname[0] = 0; - TAILQ_INSERT_TAIL(&r->route.list, pa, entries); + if (r->action == PF_RDR) { + error += apply_rdr_ports(r, &(r->rdr), rdr); + } else if (r->action == PF_NAT) { + error += apply_nat_ports(&(r->rdr), rdr); } + error += apply_redirspec(&(r->nat), nat); + error += apply_redirspec(&(r->rdr), rdr); + error += apply_redirspec(&(r->route), route); + r->nat.proxy_port[0] = PF_NAT_PROXY_PORT_LOW; r->nat.proxy_port[1] = PF_NAT_PROXY_PORT_HIGH; @@ -6395,8 +6336,18 @@ expand_rule(struct pfctl_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, rdr_hosts); - FREE_LIST(struct node_host, nat_hosts); + if (nat) { + FREE_LIST(struct node_host, nat->host); + free(nat); + } + if (rdr) { + FREE_LIST(struct node_host, rdr->host); + free(rdr); + } + if (route) { + FREE_LIST(struct node_host, route->host); + free(route); + } if (!added) yyerror("rule expands to no valid combination"); diff --git a/sbin/pfctl/pfctl.c b/sbin/pfctl/pfctl.c index fd76a1926457..7e06f4136686 100644 --- a/sbin/pfctl/pfctl.c +++ b/sbin/pfctl/pfctl.c @@ -1737,6 +1737,16 @@ pfctl_add_pool(struct pfctl *pf, struct pfctl_pool *p, sa_family_t af, int which return (0); } +void +pfctl_init_rule(struct pfctl_rule *r) +{ + + memset(r, 0, sizeof(struct pfctl_rule)); + TAILQ_INIT(&(r->rdr.list)); + TAILQ_INIT(&(r->nat.list)); + TAILQ_INIT(&(r->route.list)); +} + int pfctl_append_rule(struct pfctl *pf, struct pfctl_rule *r, const char *anchor_call) diff --git a/sbin/pfctl/pfctl.h b/sbin/pfctl/pfctl.h index ffd37cf023a6..b4f8c97854d1 100644 --- a/sbin/pfctl/pfctl.h +++ b/sbin/pfctl/pfctl.h @@ -59,8 +59,6 @@ int pfr_get_fd(void); int pfr_add_table(struct pfr_table *, int *, int); int pfr_del_table(struct pfr_table *, int *, int); int pfr_get_tables(struct pfr_table *, struct pfr_table *, int *, int); -int pfr_get_tstats(struct pfr_table *, struct pfr_tstats *, int *, int); -int pfr_clr_tstats(struct pfr_table *, int, int *, int); int pfr_clr_astats(struct pfr_table *, struct pfr_addr *, int, int *, int); int pfr_clr_addrs(struct pfr_table *, int *, int); int pfr_add_addrs(struct pfr_table *, struct pfr_addr *, int, int *, int); diff --git a/sbin/pfctl/pfctl_parser.h b/sbin/pfctl/pfctl_parser.h index e916f5e7c100..7ab872c6ee41 100644 --- a/sbin/pfctl/pfctl_parser.h +++ b/sbin/pfctl/pfctl_parser.h @@ -277,6 +277,7 @@ TAILQ_HEAD(pf_opt_queue, pf_opt_rule); int pfctl_rules(int, char *, int, int, char *, struct pfr_buffer *); int pfctl_optimize_ruleset(struct pfctl *, struct pfctl_ruleset *); +void pfctl_init_rule(struct pfctl_rule *r); int pfctl_append_rule(struct pfctl *, struct pfctl_rule *, const char *); int pfctl_append_eth_rule(struct pfctl *, struct pfctl_eth_rule *, const char *); diff --git a/sbin/pfctl/pfctl_radix.c b/sbin/pfctl/pfctl_radix.c index 3b0cc615e5a2..1d1918e29f44 100644 --- a/sbin/pfctl/pfctl_radix.c +++ b/sbin/pfctl/pfctl_radix.c @@ -235,29 +235,6 @@ pfr_clr_astats(struct pfr_table *tbl, struct pfr_addr *addr, int size, } int -pfr_clr_tstats(struct pfr_table *tbl, int size, int *nzero, int flags) -{ - struct pfioc_table io; - - if (size < 0 || (size && !tbl)) { - errno = EINVAL; - return (-1); - } - bzero(&io, sizeof io); - io.pfrio_flags = flags; - io.pfrio_buffer = tbl; - io.pfrio_esize = sizeof(*tbl); - io.pfrio_size = size; - if (ioctl(dev, DIOCRCLRTSTATS, &io)) { - pfr_report_error(tbl, &io, "clear tstats from"); - return (-1); - } - if (nzero) - *nzero = io.pfrio_nzero; - return (0); -} - -int pfr_tst_addrs(struct pfr_table *tbl, struct pfr_addr *addr, int size, int *nmatch, int flags) { diff --git a/sbin/pfctl/pfctl_table.c b/sbin/pfctl/pfctl_table.c index 57f7354b0172..834f74811ea2 100644 --- a/sbin/pfctl/pfctl_table.c +++ b/sbin/pfctl/pfctl_table.c @@ -396,7 +396,7 @@ pfctl_table(int argc, char *argv[], char *tname, const char *command, opts & PF_OPT_USEDNS); } else if (!strcmp(command, "zero")) { flags |= PFR_FLAG_ADDRSTOO; - RVTEST(pfr_clr_tstats(&table, 1, &nzero, flags)); + RVTEST(pfctl_clear_tstats(pfh, &table, &nzero, flags)); xprintf(opts, "%d table/stats cleared", nzero); } else warnx("pfctl_table: unknown command '%s'", command); diff --git a/sbin/pfctl/tests/files/Makefile b/sbin/pfctl/tests/files/Makefile index 27cf512d81c5..fc52b1db3c30 100644 --- a/sbin/pfctl/tests/files/Makefile +++ b/sbin/pfctl/tests/files/Makefile @@ -4,6 +4,6 @@ TESTSDIR= ${TESTSBASE}/sbin/pfctl/files BINDIR= ${TESTSDIR} # We use ${.CURDIR} as workaround so that the glob patterns work. -FILES!= echo ${.CURDIR}/pf????.in ${.CURDIR}/pf????.include ${.CURDIR}/pf????.ok +FILES!= echo ${.CURDIR}/pf????.in ${.CURDIR}/pf????.include ${.CURDIR}/pf????.ok ${.CURDIR}/pf????.fail .include <bsd.progs.mk> diff --git a/sbin/pfctl/tests/files/pf1026.ok b/sbin/pfctl/tests/files/pf1026.ok index 5b849fe80bd3..323036f2b800 100644 --- a/sbin/pfctl/tests/files/pf1026.ok +++ b/sbin/pfctl/tests/files/pf1026.ok @@ -1 +1 @@ -pass in on epair2b route-to (epair0a 192.0.2.2) inet6 from any to 64:ff9b::/96 flags S/SA keep state af-to inet from (epair0a) +pass in on epair2b route-to (epair0a 192.0.2.2) inet6 from any to 64:ff9b::/96 flags S/SA keep state af-to inet from (epair0a) round-robin diff --git a/sbin/pfctl/tests/files/pf1027.ok b/sbin/pfctl/tests/files/pf1027.ok index 5a3f30ae1592..b50f1e216837 100644 --- a/sbin/pfctl/tests/files/pf1027.ok +++ b/sbin/pfctl/tests/files/pf1027.ok @@ -1 +1 @@ -pass in on epair2b reply-to (epair0a 2001:db8::1) inet6 from any to 64:ff9b::/96 flags S/SA keep state af-to inet from (epair0a) +pass in on epair2b reply-to (epair0a 2001:db8::1) inet6 from any to 64:ff9b::/96 flags S/SA keep state af-to inet from (epair0a) round-robin diff --git a/sbin/pfctl/tests/files/pf1028.in b/sbin/pfctl/tests/files/pf1028.in new file mode 100644 index 000000000000..2386fcb52249 --- /dev/null +++ b/sbin/pfctl/tests/files/pf1028.in @@ -0,0 +1 @@ +rdr on vtnet0 proto tcp from 192.0.2.1 to 192.0.2.2 -> 192.0.2.3 diff --git a/sbin/pfctl/tests/files/pf1028.ok b/sbin/pfctl/tests/files/pf1028.ok new file mode 100644 index 000000000000..07be890f4e05 --- /dev/null +++ b/sbin/pfctl/tests/files/pf1028.ok @@ -0,0 +1 @@ +rdr on vtnet0 inet proto tcp from 192.0.2.1 to 192.0.2.2 -> 192.0.2.3 diff --git a/sbin/pfctl/tests/files/pf1029.in b/sbin/pfctl/tests/files/pf1029.in new file mode 100644 index 000000000000..73815839aadd --- /dev/null +++ b/sbin/pfctl/tests/files/pf1029.in @@ -0,0 +1 @@ +rdr on vtnet0 proto tcp from 192.0.2.1 to 192.0.2.2 -> 192.0.2.3 port 1002 diff --git a/sbin/pfctl/tests/files/pf1029.ok b/sbin/pfctl/tests/files/pf1029.ok new file mode 100644 index 000000000000..6e9083bf856a --- /dev/null +++ b/sbin/pfctl/tests/files/pf1029.ok @@ -0,0 +1 @@ +rdr on vtnet0 inet proto tcp from 192.0.2.1 to 192.0.2.2 -> 192.0.2.3 port 1002 diff --git a/sbin/pfctl/tests/files/pf1030.in b/sbin/pfctl/tests/files/pf1030.in new file mode 100644 index 000000000000..b6f891998a71 --- /dev/null +++ b/sbin/pfctl/tests/files/pf1030.in @@ -0,0 +1 @@ +rdr on vtnet0 proto tcp from 192.0.2.1 to 192.0.2.2 -> 192.0.2.3 port 50001:65535 diff --git a/sbin/pfctl/tests/files/pf1030.ok b/sbin/pfctl/tests/files/pf1030.ok new file mode 100644 index 000000000000..4f6b2eba2f39 --- /dev/null +++ b/sbin/pfctl/tests/files/pf1030.ok @@ -0,0 +1 @@ +rdr on vtnet0 inet proto tcp from 192.0.2.1 to 192.0.2.2 -> 192.0.2.3 port 50001:65535 diff --git a/sbin/pfctl/tests/files/pf1031.in b/sbin/pfctl/tests/files/pf1031.in new file mode 100644 index 000000000000..7cad4ae64000 --- /dev/null +++ b/sbin/pfctl/tests/files/pf1031.in @@ -0,0 +1 @@ +rdr on vtnet0 proto tcp from 192.0.2.1 to 192.0.2.2 port 1004:2004 -> 192.0.2.3 port 1004 diff --git a/sbin/pfctl/tests/files/pf1031.ok b/sbin/pfctl/tests/files/pf1031.ok new file mode 100644 index 000000000000..8dd7fe027716 --- /dev/null +++ b/sbin/pfctl/tests/files/pf1031.ok @@ -0,0 +1 @@ +rdr on vtnet0 inet proto tcp from 192.0.2.1 to 192.0.2.2 port 1004:2004 -> 192.0.2.3 port 1004 diff --git a/sbin/pfctl/tests/files/pf1032.in b/sbin/pfctl/tests/files/pf1032.in new file mode 100644 index 000000000000..a2eec78da045 --- /dev/null +++ b/sbin/pfctl/tests/files/pf1032.in @@ -0,0 +1 @@ +rdr on vtnet0 proto tcp from 192.0.2.1 to 192.0.2.2 port 1005:2005 -> 192.0.2.3 port 3004:* diff --git a/sbin/pfctl/tests/files/pf1032.ok b/sbin/pfctl/tests/files/pf1032.ok new file mode 100644 index 000000000000..3b3f124efc33 --- /dev/null +++ b/sbin/pfctl/tests/files/pf1032.ok @@ -0,0 +1 @@ +rdr on vtnet0 inet proto tcp from 192.0.2.1 to 192.0.2.2 port 1005:2005 -> 192.0.2.3 port 3004:4004 diff --git a/sbin/pfctl/tests/files/pf1033.fail b/sbin/pfctl/tests/files/pf1033.fail new file mode 100644 index 000000000000..d9fbfe4296e3 --- /dev/null +++ b/sbin/pfctl/tests/files/pf1033.fail @@ -0,0 +1 @@ +the 'static-port' option is only valid with nat rules diff --git a/sbin/pfctl/tests/files/pf1033.in b/sbin/pfctl/tests/files/pf1033.in new file mode 100644 index 000000000000..76f33e7e8f0e --- /dev/null +++ b/sbin/pfctl/tests/files/pf1033.in @@ -0,0 +1 @@ +rdr on vtnet0 proto tcp from 192.0.2.1 to 192.0.2.2 -> 192.0.2.3 static-port diff --git a/sbin/pfctl/tests/files/pf1034.fail b/sbin/pfctl/tests/files/pf1034.fail new file mode 100644 index 000000000000..e407996a8fa3 --- /dev/null +++ b/sbin/pfctl/tests/files/pf1034.fail @@ -0,0 +1 @@ +the 'map-e-portset' option is only valid with nat rules diff --git a/sbin/pfctl/tests/files/pf1034.in b/sbin/pfctl/tests/files/pf1034.in new file mode 100644 index 000000000000..be847a8af241 --- /dev/null +++ b/sbin/pfctl/tests/files/pf1034.in @@ -0,0 +1 @@ +rdr on vtnet0 proto tcp from 192.0.2.1 to 192.0.2.2 -> 192.0.2.3 map-e-portset 6/8/0x34 diff --git a/sbin/pfctl/tests/files/pf1035.in b/sbin/pfctl/tests/files/pf1035.in new file mode 100644 index 000000000000..9382ffedc8c9 --- /dev/null +++ b/sbin/pfctl/tests/files/pf1035.in @@ -0,0 +1 @@ +nat on vtnet0 proto tcp from 192.0.2.1 to 192.0.2.2 -> 192.0.2.3 diff --git a/sbin/pfctl/tests/files/pf1035.ok b/sbin/pfctl/tests/files/pf1035.ok new file mode 100644 index 000000000000..be573ef460f5 --- /dev/null +++ b/sbin/pfctl/tests/files/pf1035.ok @@ -0,0 +1 @@ +nat on vtnet0 inet proto tcp from 192.0.2.1 to 192.0.2.2 -> 192.0.2.3 diff --git a/sbin/pfctl/tests/files/pf1036.in b/sbin/pfctl/tests/files/pf1036.in new file mode 100644 index 000000000000..81718c908303 --- /dev/null +++ b/sbin/pfctl/tests/files/pf1036.in @@ -0,0 +1 @@ +nat on vtnet0 proto tcp from 192.0.2.1 to 192.0.2.2 -> 192.0.2.3 port 50001:65535 diff --git a/sbin/pfctl/tests/files/pf1036.ok b/sbin/pfctl/tests/files/pf1036.ok new file mode 100644 index 000000000000..be573ef460f5 --- /dev/null +++ b/sbin/pfctl/tests/files/pf1036.ok @@ -0,0 +1 @@ +nat on vtnet0 inet proto tcp from 192.0.2.1 to 192.0.2.2 -> 192.0.2.3 diff --git a/sbin/pfctl/tests/files/pf1037.in b/sbin/pfctl/tests/files/pf1037.in new file mode 100644 index 000000000000..a30f6c0e7bbe --- /dev/null +++ b/sbin/pfctl/tests/files/pf1037.in @@ -0,0 +1 @@ +nat on vtnet0 proto tcp from 192.0.2.1 to 192.0.2.2 -> 192.0.2.3 port 1003 diff --git a/sbin/pfctl/tests/files/pf1037.ok b/sbin/pfctl/tests/files/pf1037.ok new file mode 100644 index 000000000000..020e2de28dec --- /dev/null +++ b/sbin/pfctl/tests/files/pf1037.ok @@ -0,0 +1 @@ +nat on vtnet0 inet proto tcp from 192.0.2.1 to 192.0.2.2 -> 192.0.2.3 port 1003 diff --git a/sbin/pfctl/tests/files/pf1038.in b/sbin/pfctl/tests/files/pf1038.in new file mode 100644 index 000000000000..532060e56494 --- /dev/null +++ b/sbin/pfctl/tests/files/pf1038.in @@ -0,0 +1 @@ +nat on vtnet0 proto tcp from 192.0.2.1 to 192.0.2.2 -> 192.0.2.3 port 1004:2004 diff --git a/sbin/pfctl/tests/files/pf1038.ok b/sbin/pfctl/tests/files/pf1038.ok new file mode 100644 index 000000000000..a4021db7b1b2 --- /dev/null +++ b/sbin/pfctl/tests/files/pf1038.ok @@ -0,0 +1 @@ +nat on vtnet0 inet proto tcp from 192.0.2.1 to 192.0.2.2 -> 192.0.2.3 port 1004:2004 diff --git a/sbin/pfctl/tests/files/pf1039.in b/sbin/pfctl/tests/files/pf1039.in new file mode 100644 index 000000000000..dba14b0625de --- /dev/null +++ b/sbin/pfctl/tests/files/pf1039.in @@ -0,0 +1 @@ +nat on vtnet0 proto tcp from 192.0.2.1 to 192.0.2.2 -> 192.0.2.3 static-port diff --git a/sbin/pfctl/tests/files/pf1039.ok b/sbin/pfctl/tests/files/pf1039.ok new file mode 100644 index 000000000000..80cfbe742865 --- /dev/null +++ b/sbin/pfctl/tests/files/pf1039.ok @@ -0,0 +1 @@ +nat on vtnet0 inet proto tcp from 192.0.2.1 to 192.0.2.2 -> 192.0.2.3 static-port diff --git a/sbin/pfctl/tests/files/pf1040.fail b/sbin/pfctl/tests/files/pf1040.fail new file mode 100644 index 000000000000..5b9afc22b441 --- /dev/null +++ b/sbin/pfctl/tests/files/pf1040.fail @@ -0,0 +1 @@ +the 'static-port' option can't be used when specifying a port range diff --git a/sbin/pfctl/tests/files/pf1040.in b/sbin/pfctl/tests/files/pf1040.in new file mode 100644 index 000000000000..38d7292a560a --- /dev/null +++ b/sbin/pfctl/tests/files/pf1040.in @@ -0,0 +1 @@ +nat on vtnet0 proto tcp from 192.0.2.1 to 192.0.2.2 -> 192.0.2.3 port 1006 static-port diff --git a/sbin/pfctl/tests/files/pf1040.ok b/sbin/pfctl/tests/files/pf1040.ok new file mode 100644 index 000000000000..ffe2e023f77c --- /dev/null +++ b/sbin/pfctl/tests/files/pf1040.ok @@ -0,0 +1 @@ +nat on vtnet0 inet proto tcp from 192.0.2.1 to 192.0.2.2 -> 192.0.2.3 map-e-portset 6/8/52 diff --git a/sbin/pfctl/tests/files/pf1041.in b/sbin/pfctl/tests/files/pf1041.in new file mode 100644 index 000000000000..4c384ac70e05 --- /dev/null +++ b/sbin/pfctl/tests/files/pf1041.in @@ -0,0 +1 @@ +nat on vtnet0 proto tcp from 192.0.2.1 to 192.0.2.2 -> 192.0.2.3 map-e-portset 6/8/0x34 diff --git a/sbin/pfctl/tests/files/pf1041.ok b/sbin/pfctl/tests/files/pf1041.ok new file mode 100644 index 000000000000..ffe2e023f77c --- /dev/null +++ b/sbin/pfctl/tests/files/pf1041.ok @@ -0,0 +1 @@ +nat on vtnet0 inet proto tcp from 192.0.2.1 to 192.0.2.2 -> 192.0.2.3 map-e-portset 6/8/52 diff --git a/sbin/pfctl/tests/files/pf1042.fail b/sbin/pfctl/tests/files/pf1042.fail new file mode 100644 index 000000000000..56e174a5ece5 --- /dev/null +++ b/sbin/pfctl/tests/files/pf1042.fail @@ -0,0 +1 @@ +the 'map-e-portset' option can't be used 'static-port' diff --git a/sbin/pfctl/tests/files/pf1042.in b/sbin/pfctl/tests/files/pf1042.in new file mode 100644 index 000000000000..906f637b6a0a --- /dev/null +++ b/sbin/pfctl/tests/files/pf1042.in @@ -0,0 +1 @@ +nat on vtnet0 proto tcp from 192.0.2.1 to 192.0.2.2 -> 192.0.2.3 static-port map-e-portset 6/8/0x34 diff --git a/sbin/pfctl/tests/files/pf1043.fail b/sbin/pfctl/tests/files/pf1043.fail new file mode 100644 index 000000000000..cdfab00916a2 --- /dev/null +++ b/sbin/pfctl/tests/files/pf1043.fail @@ -0,0 +1 @@ +the 'map-e-portset' option can't be used when specifying a port range diff --git a/sbin/pfctl/tests/files/pf1043.in b/sbin/pfctl/tests/files/pf1043.in new file mode 100644 index 000000000000..15428a9e54bc --- /dev/null +++ b/sbin/pfctl/tests/files/pf1043.in @@ -0,0 +1 @@ +nat on vtnet0 proto tcp from 192.0.2.1 to 192.0.2.2 -> 192.0.2.3 port 1007 map-e-portset 6/8/0x34 diff --git a/sbin/pfctl/tests/files/pf1044.in b/sbin/pfctl/tests/files/pf1044.in new file mode 100644 index 000000000000..6a927b66b83f --- /dev/null +++ b/sbin/pfctl/tests/files/pf1044.in @@ -0,0 +1 @@ +nat on vtnet0 proto tcp from 192.0.2.1 to 192.0.2.2 -> <targets> sticky-address diff --git a/sbin/pfctl/tests/files/pf1044.ok b/sbin/pfctl/tests/files/pf1044.ok new file mode 100644 index 000000000000..a68b1daaa73a --- /dev/null +++ b/sbin/pfctl/tests/files/pf1044.ok @@ -0,0 +1 @@ +nat on vtnet0 inet proto tcp from 192.0.2.1 to 192.0.2.2 -> <targets> round-robin sticky-address diff --git a/sbin/pfctl/tests/files/pf1045.in b/sbin/pfctl/tests/files/pf1045.in new file mode 100644 index 000000000000..38f708ce19b8 --- /dev/null +++ b/sbin/pfctl/tests/files/pf1045.in @@ -0,0 +1 @@ +nat on vtnet0 proto tcp from 192.0.2.1 to 192.0.2.2 -> 203.0.113.0/24 bitmask diff --git a/sbin/pfctl/tests/files/pf1045.ok b/sbin/pfctl/tests/files/pf1045.ok new file mode 100644 index 000000000000..5388db7e58a4 --- /dev/null +++ b/sbin/pfctl/tests/files/pf1045.ok @@ -0,0 +1 @@ +nat on vtnet0 inet proto tcp from 192.0.2.1 to 192.0.2.2 -> 203.0.113.0/24 bitmask diff --git a/sbin/pfctl/tests/files/pf1046.fail b/sbin/pfctl/tests/files/pf1046.fail new file mode 100644 index 000000000000..b152f9063241 --- /dev/null +++ b/sbin/pfctl/tests/files/pf1046.fail @@ -0,0 +1 @@ +tables are not supported by pool type diff --git a/sbin/pfctl/tests/files/pf1046.in b/sbin/pfctl/tests/files/pf1046.in new file mode 100644 index 000000000000..e4a9f79efd6f --- /dev/null +++ b/sbin/pfctl/tests/files/pf1046.in @@ -0,0 +1 @@ +nat on vtnet0 proto tcp from 192.0.2.1 to 192.0.2.2 -> <targets> bitmask diff --git a/sbin/pfctl/tests/files/pf1047.fail b/sbin/pfctl/tests/files/pf1047.fail new file mode 100644 index 000000000000..239b96b2fed4 --- /dev/null +++ b/sbin/pfctl/tests/files/pf1047.fail @@ -0,0 +1 @@ +interface \(vtnet1\) is not supported by pool type diff --git a/sbin/pfctl/tests/files/pf1047.in b/sbin/pfctl/tests/files/pf1047.in new file mode 100644 index 000000000000..369bfcb0fb26 --- /dev/null +++ b/sbin/pfctl/tests/files/pf1047.in @@ -0,0 +1 @@ +nat on vtnet0 proto tcp from 192.0.2.1 to 192.0.2.2 -> (vtnet1) bitmask diff --git a/sbin/pfctl/tests/files/pf1048.in b/sbin/pfctl/tests/files/pf1048.in new file mode 100644 index 000000000000..01232a33b5d8 --- /dev/null +++ b/sbin/pfctl/tests/files/pf1048.in @@ -0,0 +1 @@ +nat on vtnet0 proto tcp from 192.0.2.1 to 192.0.2.2 -> 203.0.113.0/24 random diff --git a/sbin/pfctl/tests/files/pf1048.ok b/sbin/pfctl/tests/files/pf1048.ok new file mode 100644 index 000000000000..35e86fc676fc --- /dev/null +++ b/sbin/pfctl/tests/files/pf1048.ok @@ -0,0 +1 @@ +nat on vtnet0 inet proto tcp from 192.0.2.1 to 192.0.2.2 -> 203.0.113.0/24 random diff --git a/sbin/pfctl/tests/files/pf1049.in b/sbin/pfctl/tests/files/pf1049.in new file mode 100644 index 000000000000..3f2e5acf8265 --- /dev/null +++ b/sbin/pfctl/tests/files/pf1049.in @@ -0,0 +1 @@ +nat on vtnet0 proto tcp from 192.0.2.1 to 192.0.2.2 -> { 192.0.2.3 } diff --git a/sbin/pfctl/tests/files/pf1049.ok b/sbin/pfctl/tests/files/pf1049.ok new file mode 100644 index 000000000000..be573ef460f5 --- /dev/null +++ b/sbin/pfctl/tests/files/pf1049.ok @@ -0,0 +1 @@ +nat on vtnet0 inet proto tcp from 192.0.2.1 to 192.0.2.2 -> 192.0.2.3 diff --git a/sbin/pfctl/tests/files/pf1050.in b/sbin/pfctl/tests/files/pf1050.in new file mode 100644 index 000000000000..69ccaf445c3b --- /dev/null +++ b/sbin/pfctl/tests/files/pf1050.in @@ -0,0 +1 @@ +nat on vtnet0 proto tcp from 192.0.2.1 to 192.0.2.2 -> <targets> diff --git a/sbin/pfctl/tests/files/pf1050.ok b/sbin/pfctl/tests/files/pf1050.ok new file mode 100644 index 000000000000..24ca9b459bb7 --- /dev/null +++ b/sbin/pfctl/tests/files/pf1050.ok @@ -0,0 +1 @@ +nat on vtnet0 inet proto tcp from 192.0.2.1 to 192.0.2.2 -> <targets> round-robin diff --git a/sbin/pfctl/tests/files/pf1051.in b/sbin/pfctl/tests/files/pf1051.in new file mode 100644 index 000000000000..734da64a372c --- /dev/null +++ b/sbin/pfctl/tests/files/pf1051.in @@ -0,0 +1 @@ +nat on vtnet0 proto tcp from 192.0.2.1 to 192.0.2.2 -> { 203.0.113.1 203.0.113.2 } diff --git a/sbin/pfctl/tests/files/pf1051.ok b/sbin/pfctl/tests/files/pf1051.ok new file mode 100644 index 000000000000..86f23488be41 --- /dev/null +++ b/sbin/pfctl/tests/files/pf1051.ok @@ -0,0 +1 @@ +nat on vtnet0 inet proto tcp from 192.0.2.1 to 192.0.2.2 -> { 203.0.113.1, 203.0.113.2 } round-robin diff --git a/sbin/pfctl/tests/files/pf1052.in b/sbin/pfctl/tests/files/pf1052.in new file mode 100644 index 000000000000..2ea770f3c06e --- /dev/null +++ b/sbin/pfctl/tests/files/pf1052.in @@ -0,0 +1 @@ +nat on vtnet0 proto tcp from 192.0.2.1 to 192.0.2.2 -> { 203.0.113.1 <targets> } diff --git a/sbin/pfctl/tests/files/pf1052.ok b/sbin/pfctl/tests/files/pf1052.ok new file mode 100644 index 000000000000..b71d105eb77a --- /dev/null +++ b/sbin/pfctl/tests/files/pf1052.ok @@ -0,0 +1 @@ +nat on vtnet0 inet proto tcp from 192.0.2.1 to 192.0.2.2 -> { 203.0.113.1, <targets> } round-robin diff --git a/sbin/pfctl/tests/files/pf1053.in b/sbin/pfctl/tests/files/pf1053.in new file mode 100644 index 000000000000..f0cced0b64a2 --- /dev/null +++ b/sbin/pfctl/tests/files/pf1053.in @@ -0,0 +1 @@ +nat on vtnet0 proto tcp from 192.0.2.1 to 192.0.2.2 -> 203.0.113.0/24 diff --git a/sbin/pfctl/tests/files/pf1053.ok b/sbin/pfctl/tests/files/pf1053.ok new file mode 100644 index 000000000000..de321b8c738f --- /dev/null +++ b/sbin/pfctl/tests/files/pf1053.ok @@ -0,0 +1 @@ +nat on vtnet0 inet proto tcp from 192.0.2.1 to 192.0.2.2 -> 203.0.113.0/24 diff --git a/sbin/pfctl/tests/files/pf1054.in b/sbin/pfctl/tests/files/pf1054.in new file mode 100644 index 000000000000..9e66bb2a81d6 --- /dev/null +++ b/sbin/pfctl/tests/files/pf1054.in @@ -0,0 +1,3 @@ +# XXX: it causes just the 0th address to be used without cycling +# Probably a bug +nat on vtnet0 proto tcp from 192.0.2.1 to 192.0.2.2 -> 203.0.113.0/24 round-robin diff --git a/sbin/pfctl/tests/files/pf1054.ok b/sbin/pfctl/tests/files/pf1054.ok new file mode 100644 index 000000000000..3d7ab7974d87 --- /dev/null +++ b/sbin/pfctl/tests/files/pf1054.ok @@ -0,0 +1 @@ +nat on vtnet0 inet proto tcp from 192.0.2.1 to 192.0.2.2 -> 203.0.113.0/24 round-robin diff --git a/sbin/pfctl/tests/files/pf1055.in b/sbin/pfctl/tests/files/pf1055.in new file mode 100644 index 000000000000..c116ef5fd43e --- /dev/null +++ b/sbin/pfctl/tests/files/pf1055.in @@ -0,0 +1 @@ +nat on vtnet0 proto tcp from 192.0.2.1 to 192.0.2.2 -> 203.0.113.0/24 source-hash 0x42424242424242424242424242424242 diff --git a/sbin/pfctl/tests/files/pf1055.ok b/sbin/pfctl/tests/files/pf1055.ok new file mode 100644 index 000000000000..468e47012169 --- /dev/null +++ b/sbin/pfctl/tests/files/pf1055.ok @@ -0,0 +1 @@ +nat on vtnet0 inet proto tcp from 192.0.2.1 to 192.0.2.2 -> 203.0.113.0/24 source-hash 0x42424242424242424242424242424242 diff --git a/sbin/pfctl/tests/files/pf1056.in b/sbin/pfctl/tests/files/pf1056.in new file mode 100644 index 000000000000..bd2af077fc3f --- /dev/null +++ b/sbin/pfctl/tests/files/pf1056.in @@ -0,0 +1 @@ +pass in on vtnet0 inet6 from any to 64:ff9b::/96 af-to inet from 203.0.113.1 to 203.0.113.2 diff --git a/sbin/pfctl/tests/files/pf1056.ok b/sbin/pfctl/tests/files/pf1056.ok new file mode 100644 index 000000000000..0397570dbce0 --- /dev/null +++ b/sbin/pfctl/tests/files/pf1056.ok @@ -0,0 +1 @@ +pass in on vtnet0 inet6 from any to 64:ff9b::/96 flags S/SA keep state af-to inet from 203.0.113.1 to 203.0.113.2 diff --git a/sbin/pfctl/tests/files/pf1057.in b/sbin/pfctl/tests/files/pf1057.in new file mode 100644 index 000000000000..0e26976e5a0d --- /dev/null +++ b/sbin/pfctl/tests/files/pf1057.in @@ -0,0 +1 @@ +nat on vtnet0 proto tcp from 192.0.2.1 to 192.0.2.2 -> vlan1057 diff --git a/sbin/pfctl/tests/files/pf1057.ok b/sbin/pfctl/tests/files/pf1057.ok new file mode 100644 index 000000000000..7626951e138c --- /dev/null +++ b/sbin/pfctl/tests/files/pf1057.ok @@ -0,0 +1 @@ +nat on vtnet0 inet proto tcp from 192.0.2.1 to 192.0.2.2 -> 203.0.113.5 diff --git a/sbin/pfctl/tests/files/pf1058.in b/sbin/pfctl/tests/files/pf1058.in new file mode 100644 index 000000000000..27c0ef1d69b3 --- /dev/null +++ b/sbin/pfctl/tests/files/pf1058.in @@ -0,0 +1 @@ +nat on vtnet0 proto tcp from 192.0.2.1 to 192.0.2.2 -> { 203.0.113.1 vlan1058 } diff --git a/sbin/pfctl/tests/files/pf1058.ok b/sbin/pfctl/tests/files/pf1058.ok new file mode 100644 index 000000000000..b1d2b07a58b4 --- /dev/null +++ b/sbin/pfctl/tests/files/pf1058.ok @@ -0,0 +1 @@ +nat on vtnet0 inet proto tcp from 192.0.2.1 to 192.0.2.2 -> { 203.0.113.1, 203.0.113.5 } round-robin diff --git a/sbin/pfctl/tests/files/pf1059.in b/sbin/pfctl/tests/files/pf1059.in new file mode 100644 index 000000000000..92ed5c50656b --- /dev/null +++ b/sbin/pfctl/tests/files/pf1059.in @@ -0,0 +1 @@ +nat on vtnet0 proto tcp from 192.0.2.1 to 192.0.2.2 -> (vlan1059) diff --git a/sbin/pfctl/tests/files/pf1059.ok b/sbin/pfctl/tests/files/pf1059.ok new file mode 100644 index 000000000000..6b028f18ee60 --- /dev/null +++ b/sbin/pfctl/tests/files/pf1059.ok @@ -0,0 +1 @@ +nat on vtnet0 inet proto tcp from 192.0.2.1 to 192.0.2.2 -> (vlan1059) round-robin diff --git a/sbin/pfctl/tests/files/pf1060.in b/sbin/pfctl/tests/files/pf1060.in new file mode 100644 index 000000000000..85cdd19f2897 --- /dev/null +++ b/sbin/pfctl/tests/files/pf1060.in @@ -0,0 +1 @@ +nat on vtnet0 proto tcp from 192.0.2.1 to 192.0.2.2 -> { 203.0.113.0 (vlan1060) } diff --git a/sbin/pfctl/tests/files/pf1060.ok b/sbin/pfctl/tests/files/pf1060.ok new file mode 100644 index 000000000000..3364b3cbdcc5 --- /dev/null +++ b/sbin/pfctl/tests/files/pf1060.ok @@ -0,0 +1 @@ +nat on vtnet0 inet proto tcp from 192.0.2.1 to 192.0.2.2 -> { 203.0.113.0, (vlan1060) } round-robin diff --git a/sbin/pfctl/tests/files/pf1061.in b/sbin/pfctl/tests/files/pf1061.in new file mode 100644 index 000000000000..32eb8272db8b --- /dev/null +++ b/sbin/pfctl/tests/files/pf1061.in @@ -0,0 +1 @@ +nat on vtnet0 proto tcp from 2001:db8::1 to 2001:db8::2 -> vlan1061:0 diff --git a/sbin/pfctl/tests/files/pf1061.ok b/sbin/pfctl/tests/files/pf1061.ok new file mode 100644 index 000000000000..d2e6d969cb11 --- /dev/null +++ b/sbin/pfctl/tests/files/pf1061.ok @@ -0,0 +1 @@ +nat on vtnet0 inet6 proto tcp from 2001:db8::1 to 2001:db8::2 -> 2001:db8::cb00:7105 diff --git a/sbin/pfctl/tests/files/pf1062.in b/sbin/pfctl/tests/files/pf1062.in new file mode 100644 index 000000000000..4d6a0ecc2e92 --- /dev/null +++ b/sbin/pfctl/tests/files/pf1062.in @@ -0,0 +1 @@ +nat on vtnet0 proto tcp from 2001:db8::1 to 2001:db8::2 -> { 2001:db8::3 vlan1062:0 } diff --git a/sbin/pfctl/tests/files/pf1062.ok b/sbin/pfctl/tests/files/pf1062.ok new file mode 100644 index 000000000000..cb5db62ded1d --- /dev/null +++ b/sbin/pfctl/tests/files/pf1062.ok @@ -0,0 +1 @@ +nat on vtnet0 inet6 proto tcp from 2001:db8::1 to 2001:db8::2 -> { 2001:db8::3, 2001:db8::cb00:7105 } round-robin diff --git a/sbin/pfctl/tests/files/pf1063.in b/sbin/pfctl/tests/files/pf1063.in new file mode 100644 index 000000000000..3d164538640d --- /dev/null +++ b/sbin/pfctl/tests/files/pf1063.in @@ -0,0 +1 @@ +nat on vtnet0 proto tcp from 2001:db8::1 to 2001:db8::2 -> (vlan1063) diff --git a/sbin/pfctl/tests/files/pf1063.ok b/sbin/pfctl/tests/files/pf1063.ok new file mode 100644 index 000000000000..13189e00cc8a --- /dev/null +++ b/sbin/pfctl/tests/files/pf1063.ok @@ -0,0 +1 @@ +nat on vtnet0 inet6 proto tcp from 2001:db8::1 to 2001:db8::2 -> (vlan1063) round-robin diff --git a/sbin/pfctl/tests/files/pf1064.in b/sbin/pfctl/tests/files/pf1064.in new file mode 100644 index 000000000000..78d04135154f --- /dev/null +++ b/sbin/pfctl/tests/files/pf1064.in @@ -0,0 +1 @@ +nat on vtnet0 proto tcp from 2001:db8::1 to 2001:db8::2 -> { fe80::2 (vlan1064) } diff --git a/sbin/pfctl/tests/files/pf1064.ok b/sbin/pfctl/tests/files/pf1064.ok new file mode 100644 index 000000000000..ed15d054ab34 --- /dev/null +++ b/sbin/pfctl/tests/files/pf1064.ok @@ -0,0 +1 @@ +nat on vtnet0 inet6 proto tcp from 2001:db8::1 to 2001:db8::2 -> { fe80::2, (vlan1064) } round-robin diff --git a/sbin/pfctl/tests/pfctl_test.c b/sbin/pfctl/tests/pfctl_test.c index cc69ed4e002a..dbdcaa4900ea 100644 --- a/sbin/pfctl/tests/pfctl_test.c +++ b/sbin/pfctl/tests/pfctl_test.c @@ -119,27 +119,14 @@ read_file(const char *filename) } static void -run_pfctl_test(const char *input_path, const char *expected_path, - const atf_tc_t *tc) +run_command_pipe(const char *argv[], struct sbuf **output) { - int status; + posix_spawn_file_actions_t action; pid_t pid; int pipefds[2]; - char input_files_path[PATH_MAX]; - struct sbuf *expected_output; - struct sbuf *real_output; - posix_spawn_file_actions_t action; - - if (!check_pf_module_available()) - atf_tc_skip("pf(4) is not loaded"); - - /* The test inputs need to be able to use relative includes. */ - snprintf(input_files_path, sizeof(input_files_path), "%s/files", - atf_tc_get_config_var(tc, "srcdir")); - ATF_REQUIRE_ERRNO(0, chdir(input_files_path) == 0); + int status; ATF_REQUIRE_ERRNO(0, pipe(pipefds) == 0); - expected_output = read_file(expected_path); posix_spawn_file_actions_init(&action); posix_spawn_file_actions_addclose(&action, STDIN_FILENO); @@ -147,27 +134,118 @@ run_pfctl_test(const char *input_path, const char *expected_path, posix_spawn_file_actions_adddup2(&action, pipefds[0], STDOUT_FILENO); posix_spawn_file_actions_adddup2(&action, pipefds[0], STDERR_FILENO); - const char *argv[] = { "pfctl", "-o", "none", "-nvf", input_path, - NULL }; - printf("Running %s %s %s %s %s\n", argv[0], argv[1], argv[2], argv[3], - argv[4]); + printf("Running "); + for (int i=0; argv[i] != NULL; i++) + printf("%s ", argv[i]); + printf("\n"); + status = posix_spawnp( - &pid, "pfctl", &action, NULL, __DECONST(char **, argv), environ); + &pid, argv[0], &action, NULL, __DECONST(char **, argv), environ); ATF_REQUIRE_EQ_MSG( status, 0, "posix_spawn failed: %s", strerror(errno)); posix_spawn_file_actions_destroy(&action); close(pipefds[0]); - real_output = read_fd(pipefds[1], 0); - printf("---\n%s---\n", sbuf_data(real_output)); + (*output) = read_fd(pipefds[1], 0); + printf("---\n%s---\n", sbuf_data(*output)); ATF_REQUIRE_EQ(waitpid(pid, &status, 0), pid); ATF_REQUIRE_MSG(WIFEXITED(status), - "pfctl returned non-zero! Output:\n %s", sbuf_data(real_output)); + "%s returned non-zero! Output:\n %s", argv[0], sbuf_data(*output)); + close(pipefds[1]); +} + +static void +run_command(const char *argv[]) +{ + posix_spawn_file_actions_t action; + pid_t pid; + int status; + + posix_spawn_file_actions_init(&action); + posix_spawn_file_actions_addopen(&action, STDOUT_FILENO, "/dev/null", O_WRONLY, 0); + posix_spawn_file_actions_addopen(&action, STDERR_FILENO, "/dev/null", O_WRONLY, 0); + posix_spawn_file_actions_addopen(&action, STDIN_FILENO, "/dev/zero", O_RDONLY, 0); + + printf("Running "); + for (int i=0; argv[i] != NULL; i++) + printf("%s ", argv[i]); + printf("\n"); + + status = posix_spawnp( + &pid, argv[0], &action, NULL, __DECONST(char **, argv), environ); + posix_spawn_file_actions_destroy(&action); + waitpid(pid, &status, 0); +} + +static void +run_pfctl_test(const char *input_path, const char *output_path, + const atf_tc_t *tc, bool test_failure) +{ + char input_files_path[PATH_MAX]; + struct sbuf *expected_output; + struct sbuf *real_output; + + if (!check_pf_module_available()) + atf_tc_skip("pf(4) is not loaded"); + + /* The test inputs need to be able to use relative includes. */ + snprintf(input_files_path, sizeof(input_files_path), "%s/files", + atf_tc_get_config_var(tc, "srcdir")); + ATF_REQUIRE_ERRNO(0, chdir(input_files_path) == 0); + expected_output = read_file(output_path); + + const char *argv[] = { "pfctl", "-o", "none", "-nvf", input_path, + NULL }; + run_command_pipe(argv, &real_output); + + if (test_failure) { + /* + * Error output contains additional strings like line number + * or "skipping rule due to errors", so use regexp to see + * if the expected error message is there somewhere. + */ + ATF_CHECK_MATCH(sbuf_data(expected_output), sbuf_data(real_output)); + sbuf_delete(expected_output); + } else { + ATF_CHECK_STREQ(sbuf_data(expected_output), sbuf_data(real_output)); + sbuf_delete(expected_output); + } - ATF_CHECK_STREQ(sbuf_data(expected_output), sbuf_data(real_output)); - sbuf_delete(expected_output); sbuf_delete(real_output); - close(pipefds[1]); +} + +static void +do_pf_test_iface_create(const char *number) +{ + struct sbuf *ifconfig_output; + char ifname[16] = {0}; + + snprintf(ifname, sizeof(ifname), "vlan%s", number); + const char *argv[] = { "ifconfig", ifname, "create", NULL}; + run_command_pipe(argv, &ifconfig_output); + sbuf_delete(ifconfig_output); + + const char *argv_inet[] = { "ifconfig", ifname, "inet", "203.0.113.5/30", NULL}; + run_command_pipe(argv_inet, &ifconfig_output); + sbuf_delete(ifconfig_output); + + const char *argv_inet6[] = { "ifconfig", ifname, "inet6", "2001:db8::203.0.113.5/126", NULL}; + run_command_pipe(argv_inet6, &ifconfig_output); + sbuf_delete(ifconfig_output); + + const char *argv_show[] = { "ifconfig", ifname, NULL}; + run_command_pipe(argv_show, &ifconfig_output); + sbuf_delete(ifconfig_output); +} + +static void +do_pf_test_iface_remove(const char *number) +{ + char ifname[16] = {0}; + + snprintf(ifname, sizeof(ifname), "vlan%s", number); + const char *argv[] = { "ifconfig", ifname, "destroy", NULL}; + run_command(argv); } static void @@ -179,7 +257,21 @@ do_pf_test(const char *number, const atf_tc_t *tc) atf_tc_get_config_var(tc, "srcdir"), number); asprintf(&expected_path, "%s/files/pf%s.ok", atf_tc_get_config_var(tc, "srcdir"), number); - run_pfctl_test(input_path, expected_path, tc); + run_pfctl_test(input_path, expected_path, tc, false); + free(input_path); + free(expected_path); +} + +static void +do_pf_test_fail(const char *number, const atf_tc_t *tc) +{ + char *input_path; + char *expected_path; + asprintf(&input_path, "%s/files/pf%s.in", + atf_tc_get_config_var(tc, "srcdir"), number); + asprintf(&expected_path, "%s/files/pf%s.fail", + atf_tc_get_config_var(tc, "srcdir"), number); + run_pfctl_test(input_path, expected_path, tc, true); free(input_path); free(expected_path); } @@ -190,10 +282,11 @@ do_selfpf_test(const char *number, const atf_tc_t *tc) char *expected_path; asprintf(&expected_path, "%s/files/pf%s.ok", atf_tc_get_config_var(tc, "srcdir"), number); - run_pfctl_test(expected_path, expected_path, tc); + run_pfctl_test(expected_path, expected_path, tc, false); free(expected_path); } +/* Standard tests perform the normal test and then the selfpf test */ #define PFCTL_TEST(number, descr) \ ATF_TC(pf##number); \ ATF_TC_HEAD(pf##number, tc) \ @@ -213,16 +306,53 @@ do_selfpf_test(const char *number, const atf_tc_t *tc) { \ do_selfpf_test(#number, tc); \ } +/* Tests for failure perform only the normal test */ +#define PFCTL_TEST_FAIL(number, descr) \ + ATF_TC(pf##number); \ + ATF_TC_HEAD(pf##number, tc) \ + { \ + atf_tc_set_md_var(tc, "descr", descr); \ + } \ + ATF_TC_BODY(pf##number, tc) \ + { \ + do_pf_test_fail(#number, tc); \ + } +/* Tests with interface perform only the normal test */ +#define PFCTL_TEST_IFACE(number, descr) \ + ATF_TC_WITH_CLEANUP(pf##number); \ + ATF_TC_HEAD(pf##number, tc) \ + { \ + atf_tc_set_md_var(tc, "descr", descr); \ + atf_tc_set_md_var(tc, "execenv", "jail"); \ + atf_tc_set_md_var(tc, "execenv.jail.params", "vnet"); \ + } \ + ATF_TC_BODY(pf##number, tc) \ + { \ + do_pf_test_iface_create(#number); \ + do_pf_test(#number, tc); \ + } \ + ATF_TC_CLEANUP(pf##number, tc) \ + { \ + do_pf_test_iface_remove(#number); \ + } #include "pfctl_test_list.inc" #undef PFCTL_TEST +#undef PFCTL_TEST_FAIL +#undef PFCTL_TEST_IFACE ATF_TP_ADD_TCS(tp) { #define PFCTL_TEST(number, descr) \ ATF_TP_ADD_TC(tp, pf##number); \ ATF_TP_ADD_TC(tp, selfpf##number); +#define PFCTL_TEST_FAIL(number, descr) \ + ATF_TP_ADD_TC(tp, pf##number); +#define PFCTL_TEST_IFACE(number, descr) \ + ATF_TP_ADD_TC(tp, pf##number); #include "pfctl_test_list.inc" #undef PFCTL_TEST +#undef PFCTL_TEST_FAIL +#undef PFCTL_TEST_IFACE return atf_no_error(); } diff --git a/sbin/pfctl/tests/pfctl_test_list.inc b/sbin/pfctl/tests/pfctl_test_list.inc index 7dd3a2af0eea..c6329b978a21 100644 --- a/sbin/pfctl/tests/pfctl_test_list.inc +++ b/sbin/pfctl/tests/pfctl_test_list.inc @@ -136,3 +136,40 @@ PFCTL_TEST(1024, "nat64") PFCTL_TEST(1025, "nat64 with implicit address family") PFCTL_TEST(1026, "nat64 with route-to") PFCTL_TEST(1027, "nat64 with reply-to") +PFCTL_TEST(1028, "RDR pool: For RDR rules no port specified means keep port") +PFCTL_TEST(1029, "RDR pool: A single port is shown") +PFCTL_TEST(1030, "RDR pool: The default values are shown for RDR rules") +PFCTL_TEST(1031, "RDR pool: Multiple ports redirected to a single port") +PFCTL_TEST(1032, "RDR pool: Multiple ports redirected to a port range") +PFCTL_TEST_FAIL(1033, "RDR pool: static-port can't be used with RDR rules") +PFCTL_TEST_FAIL(1034, "RDR pool: MAP-E port can't be used with RDR rules") +PFCTL_TEST(1035, "NAT pool: For NAT rules no port specified means default values") +PFCTL_TEST(1036, "NAT pool: Default port numbers are not shown, even if explicitly applied") +PFCTL_TEST(1037, "NAT pool: Single port") +PFCTL_TEST(1038, "NAT pool: Two ports") +PFCTL_TEST(1039, "NAT pool: Static port") +PFCTL_TEST_FAIL(1040, "NAT pool: Static port can't be used with port numbers") +PFCTL_TEST(1041, "NAT pool: MAP-E is displayed using decimal system") +PFCTL_TEST_FAIL(1042, "NAT pool: MAP-E port can't be used with static port") +PFCTL_TEST_FAIL(1043, "NAT pool: MAP-E port can't be used with port numbers") +PFCTL_TEST(1044, "pool: sticky-address is applied on top of round-robin") +PFCTL_TEST(1045, "pool: bitmask is allowed for prefixes") +PFCTL_TEST_FAIL(1046, "pool: bitmask is not allowed for tables") +PFCTL_TEST_FAIL(1047, "pool: bitmask is not allowed for interfaces in brackets") +PFCTL_TEST(1048, "pool: random is allowed for prefixes") +PFCTL_TEST(1049, "pool: round-robin is not set for a single host, even if it looks like a table") +PFCTL_TEST(1050, "pool: round-robin is set automatically for tables") +PFCTL_TEST(1051, "pool: round-robin is set automatically for multiple targets") +PFCTL_TEST(1052, "pool: hosts and table are allowed, round-robin is automatically set") +PFCTL_TEST(1053, "pool: round-robin is not set automatically for prefixes") +PFCTL_TEST(1054, "pool: round-robin is allowed for prefixes") +PFCTL_TEST(1055, "pool: source hash") +PFCTL_TEST(1056, "af-to: from and to") +PFCTL_TEST_IFACE(1057, "Interface translation: IPv4 rule, interface without brackets is translated") +PFCTL_TEST_IFACE(1058, "Interface translation: IPv4 rule, interface without brackets is translated, extra host, round-robin is applied") +PFCTL_TEST_IFACE(1059, "Interface translation: IPv4 rule, interface with brackets is not translated, round-robin is applied") +PFCTL_TEST_IFACE(1060, "Interface translation: IPv4 rule, interface with brackets is not translated, extra host, round-robin is applied") +PFCTL_TEST_IFACE(1061, "Interface translation: IPv6 rule, interface without brackets is translated") +PFCTL_TEST_IFACE(1062, "Interface translation: IPv6 rule, interface without brackets is translated, extra host, round-robin is applied") +PFCTL_TEST_IFACE(1063, "Interface translation: IPv6 rule, interface with brackets is not translated, round-robin is applied") +PFCTL_TEST_IFACE(1064, "Interface translation: IPv6 rule, interface with brackets is not translated, extra host, round robin is applied") |