git: aeddee83341e - main - pfctl: Split pool parsing into separate functions
- Go to: [ bottom of page ] [ top of archives ] [ this month ]
Date: Fri, 28 Mar 2025 16:08:53 UTC
The branch main has been updated by ks: URL: https://cgit.FreeBSD.org/src/commit/?id=aeddee83341eb3b847fb4862db5cd0a553bf4a36 commit aeddee83341eb3b847fb4862db5cd0a553bf4a36 Author: Kajetan Staszkiewicz <ks@FreeBSD.org> AuthorDate: 2025-03-28 16:08:34 +0000 Commit: Kajetan Staszkiewicz <ks@FreeBSD.org> CommitDate: 2025-03-28 16:08:34 +0000 pfctl: Split pool parsing into separate functions The pf pools are used in NAT, route-to and af-to rules. Some parts of code are duplicated between them. Create functions apply_redirspec(), apply_nat_ports() and apply_rdr_ports() to handle the common tasks. Simplify data structures used for pool parsing. Move the contents of struct redirection to struct redirspec. Map all ways of parsing pools directly onto struct redirspec. Name various forms of struct redirspect to hint where they are used. Remove struct redirspec *rroute from struct filter_opts, because filter_opts is bzero()'ed after the route part of rule is parsed, and thus can't be used. Add tests to ensure that parsing and error messages behave as expected. The tests have been written and tested with pfctl from before this patch. This is prerequisite for adding support for OpenBSD NAT syntax. Reviewed by: kp Approved by: kp (mentor) Sponsored by: InnoGames GmbH Differential Revision: https://reviews.freebsd.org/D49218 --- sbin/pfctl/parse.y | 569 ++++++++++++++++------------------- sbin/pfctl/pfctl.c | 10 + sbin/pfctl/pfctl_parser.h | 1 + sbin/pfctl/tests/files/Makefile | 2 +- sbin/pfctl/tests/files/pf1026.ok | 2 +- sbin/pfctl/tests/files/pf1027.ok | 2 +- sbin/pfctl/tests/files/pf1028.in | 1 + sbin/pfctl/tests/files/pf1028.ok | 1 + sbin/pfctl/tests/files/pf1029.in | 1 + sbin/pfctl/tests/files/pf1029.ok | 1 + sbin/pfctl/tests/files/pf1030.in | 1 + sbin/pfctl/tests/files/pf1030.ok | 1 + sbin/pfctl/tests/files/pf1031.in | 1 + sbin/pfctl/tests/files/pf1031.ok | 1 + sbin/pfctl/tests/files/pf1032.in | 1 + sbin/pfctl/tests/files/pf1032.ok | 1 + sbin/pfctl/tests/files/pf1033.fail | 1 + sbin/pfctl/tests/files/pf1033.in | 1 + sbin/pfctl/tests/files/pf1034.fail | 1 + sbin/pfctl/tests/files/pf1034.in | 1 + sbin/pfctl/tests/files/pf1035.in | 1 + sbin/pfctl/tests/files/pf1035.ok | 1 + sbin/pfctl/tests/files/pf1036.in | 1 + sbin/pfctl/tests/files/pf1036.ok | 1 + sbin/pfctl/tests/files/pf1037.in | 1 + sbin/pfctl/tests/files/pf1037.ok | 1 + sbin/pfctl/tests/files/pf1038.in | 1 + sbin/pfctl/tests/files/pf1038.ok | 1 + sbin/pfctl/tests/files/pf1039.in | 1 + sbin/pfctl/tests/files/pf1039.ok | 1 + sbin/pfctl/tests/files/pf1040.fail | 1 + sbin/pfctl/tests/files/pf1040.in | 1 + sbin/pfctl/tests/files/pf1040.ok | 1 + sbin/pfctl/tests/files/pf1041.in | 1 + sbin/pfctl/tests/files/pf1041.ok | 1 + sbin/pfctl/tests/files/pf1042.fail | 1 + sbin/pfctl/tests/files/pf1042.in | 1 + sbin/pfctl/tests/files/pf1043.fail | 1 + sbin/pfctl/tests/files/pf1043.in | 1 + sbin/pfctl/tests/files/pf1044.in | 1 + sbin/pfctl/tests/files/pf1044.ok | 1 + sbin/pfctl/tests/files/pf1045.in | 1 + sbin/pfctl/tests/files/pf1045.ok | 1 + sbin/pfctl/tests/files/pf1046.fail | 1 + sbin/pfctl/tests/files/pf1046.in | 1 + sbin/pfctl/tests/files/pf1047.fail | 1 + sbin/pfctl/tests/files/pf1047.in | 1 + sbin/pfctl/tests/files/pf1048.in | 1 + sbin/pfctl/tests/files/pf1048.ok | 1 + sbin/pfctl/tests/files/pf1049.in | 1 + sbin/pfctl/tests/files/pf1049.ok | 1 + sbin/pfctl/tests/files/pf1050.in | 1 + sbin/pfctl/tests/files/pf1050.ok | 1 + sbin/pfctl/tests/files/pf1051.in | 1 + sbin/pfctl/tests/files/pf1051.ok | 1 + sbin/pfctl/tests/files/pf1052.in | 1 + sbin/pfctl/tests/files/pf1052.ok | 1 + sbin/pfctl/tests/files/pf1053.in | 1 + sbin/pfctl/tests/files/pf1053.ok | 1 + sbin/pfctl/tests/files/pf1054.in | 3 + sbin/pfctl/tests/files/pf1054.ok | 1 + sbin/pfctl/tests/files/pf1055.in | 1 + sbin/pfctl/tests/files/pf1055.ok | 1 + sbin/pfctl/tests/files/pf1056.in | 1 + sbin/pfctl/tests/files/pf1056.ok | 1 + sbin/pfctl/tests/files/pf1057.in | 1 + sbin/pfctl/tests/files/pf1057.ok | 1 + sbin/pfctl/tests/files/pf1058.in | 1 + sbin/pfctl/tests/files/pf1058.ok | 1 + sbin/pfctl/tests/files/pf1059.in | 1 + sbin/pfctl/tests/files/pf1059.ok | 1 + sbin/pfctl/tests/files/pf1060.in | 1 + sbin/pfctl/tests/files/pf1060.ok | 1 + sbin/pfctl/tests/files/pf1061.in | 1 + sbin/pfctl/tests/files/pf1061.ok | 1 + sbin/pfctl/tests/files/pf1062.in | 1 + sbin/pfctl/tests/files/pf1062.ok | 1 + sbin/pfctl/tests/files/pf1063.in | 1 + sbin/pfctl/tests/files/pf1063.ok | 1 + sbin/pfctl/tests/files/pf1064.in | 1 + sbin/pfctl/tests/files/pf1064.ok | 1 + sbin/pfctl/tests/pfctl_test.c | 188 ++++++++++-- sbin/pfctl/tests/pfctl_test_list.inc | 37 +++ 83 files changed, 547 insertions(+), 341 deletions(-) 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); *** 920 LINES SKIPPED ***