diff options
author | Henning Brauer <henning@cvs.openbsd.org> | 2006-07-06 13:26:42 +0000 |
---|---|---|
committer | Henning Brauer <henning@cvs.openbsd.org> | 2006-07-06 13:26:42 +0000 |
commit | 1902c78559ad9225aeda2c22f42147de73f843de (patch) | |
tree | 8b5d36570320b4fff61b76d42193727c548c318c /sbin/pfctl | |
parent | 367622d0e98a37b07a5432206a26b01d218084cf (diff) |
add "rtable" to select alternate routing tables.
with & ok claudio hshoexer
Diffstat (limited to 'sbin/pfctl')
-rw-r--r-- | sbin/pfctl/parse.y | 164 | ||||
-rw-r--r-- | sbin/pfctl/pfctl_parser.c | 4 |
2 files changed, 114 insertions, 54 deletions
diff --git a/sbin/pfctl/parse.y b/sbin/pfctl/parse.y index 2189f474bcb..cc9bd4938f7 100644 --- a/sbin/pfctl/parse.y +++ b/sbin/pfctl/parse.y @@ -1,4 +1,4 @@ -/* $OpenBSD: parse.y,v 1.501 2006/06/17 11:38:41 henning Exp $ */ +/* $OpenBSD: parse.y,v 1.502 2006/07/06 13:26:41 henning Exp $ */ /* * Copyright (c) 2001 Markus Friedl. All rights reserved. @@ -205,10 +205,12 @@ struct filter_opts { char *tag; struct node_matchtag *match_tags; u_int8_t match_tag_not; + int rtableid; } filter_opts; struct antispoof_opts { char *label; + int rtableid; } antispoof_opts; struct scrub_opts { @@ -222,6 +224,7 @@ struct scrub_opts { int fragcache; int randomid; int reassemble_tcp; + int rtableid; } scrub_opts; struct queue_opts { @@ -332,6 +335,7 @@ typedef struct { u_int32_t number; int i; char *string; + int rtableid; struct { u_int8_t b1; u_int8_t b2; @@ -414,7 +418,7 @@ typedef struct { %token ANTISPOOF FOR %token BITMASK RANDOM SOURCEHASH ROUNDROBIN STATICPORT PROBABILITY %token ALTQ CBQ PRIQ HFSC BANDWIDTH TBRSIZE LINKSHARE REALTIME UPPERLIMIT -%token QUEUE PRIORITY QLIMIT +%token QUEUE PRIORITY QLIMIT RTABLE %token LOAD %token STICKYADDRESS MAXSRCSTATES MAXSRCNODES SOURCETRACK GLOBAL RULE %token MAXSRCCONN MAXSRCCONNRATE OVERLOAD FLUSH @@ -465,6 +469,7 @@ typedef struct { %type <v.pool_opts> pool_opts pool_opt pool_opts_l %type <v.matchtag_opts> matchtag matchtag_list matchtag_item %type <v.tagged> tagged +%type <v.rtableid> rtable %% ruleset : /* empty */ @@ -623,6 +628,7 @@ anchorrule : ANCHOR string dir interface af proto fromto filter_opts { r.direction = $3; r.af = $5; r.prob = $8.prob; + r.rtableid = $8.rtableid; r.match_tag_not = $8.match_tag_not; @@ -634,7 +640,7 @@ anchorrule : ANCHOR string dir interface af proto fromto filter_opts { 0, 0, 0, $8.match_tags, $2); free($2); } - | NATANCHOR string interface af proto fromto { + | NATANCHOR string interface af proto fromto rtable { struct pf_rule r; if (check_rulestate(PFCTL_STATE_NAT)) { @@ -645,6 +651,7 @@ anchorrule : ANCHOR string dir interface af proto fromto filter_opts { memset(&r, 0, sizeof(r)); r.action = PF_NAT; r.af = $4; + r.rtableid = $7; decide_address_family($6.src.host, &r.af); decide_address_family($6.dst.host, &r.af); @@ -654,7 +661,7 @@ anchorrule : ANCHOR string dir interface af proto fromto filter_opts { 0, 0, 0, 0, $2); free($2); } - | RDRANCHOR string interface af proto fromto { + | RDRANCHOR string interface af proto fromto rtable { struct pf_rule r; if (check_rulestate(PFCTL_STATE_NAT)) { @@ -665,6 +672,7 @@ anchorrule : ANCHOR string dir interface af proto fromto filter_opts { memset(&r, 0, sizeof(r)); r.action = PF_RDR; r.af = $4; + r.rtableid = $7; decide_address_family($6.src.host, &r.af); decide_address_family($6.dst.host, &r.af); @@ -695,7 +703,7 @@ anchorrule : ANCHOR string dir interface af proto fromto filter_opts { 0, 0, 0, 0, $2); free($2); } - | BINATANCHOR string interface af proto fromto { + | BINATANCHOR string interface af proto fromto rtable { struct pf_rule r; if (check_rulestate(PFCTL_STATE_NAT)) { @@ -706,6 +714,7 @@ anchorrule : ANCHOR string dir interface af proto fromto filter_opts { memset(&r, 0, sizeof(r)); r.action = PF_BINAT; r.af = $4; + r.rtableid = $7; if ($5 != NULL) { if ($5->next != NULL) { yyerror("proto list expansion" @@ -807,6 +816,7 @@ scrubrule : scrubaction dir logquick interface af proto fromto scrub_opts r.max_mss = $8.maxmss; if ($8.fragcache) r.rule_flag |= $8.fragcache; + r.rtableid = $8.rtableid; expand_rule(&r, $4, NULL, $6, $7.src_os, $7.src.host, $7.src.port, $7.dst.host, $7.dst.port, @@ -815,12 +825,14 @@ scrubrule : scrubaction dir logquick interface af proto fromto scrub_opts ; scrub_opts : { - bzero(&scrub_opts, sizeof scrub_opts); - } + bzero(&scrub_opts, sizeof scrub_opts); + scrub_opts.rtableid = -1; + } scrub_opts_l { $$ = scrub_opts; } | /* empty */ { bzero(&scrub_opts, sizeof scrub_opts); + scrub_opts.rtableid = -1; $$ = scrub_opts; } ; @@ -889,6 +901,13 @@ scrub_opt : NODF { } scrub_opts.randomid = 1; } + | RTABLE number { + if ($2 > RT_TABLEID_MAX || $2 < 0) { + yyerror("invalid rtable id"); + YYERROR; + } + scrub_opts.rtableid = $2; + } ; fragcache : FRAGMENT REASSEMBLE { $$ = 0; /* default */ } @@ -914,6 +933,7 @@ antispoof : ANTISPOOF logquick antispoof_ifspc af antispoof_opts { r.af = $4; if (rule_label(&r, $5.label)) YYERROR; + r.rtableid = $5.rtableid; j = calloc(1, sizeof(struct node_if)); if (j == NULL) err(1, "antispoof: calloc"); @@ -964,6 +984,7 @@ antispoof : ANTISPOOF logquick antispoof_ifspc af antispoof_opts { r.af = $4; if (rule_label(&r, $5.label)) YYERROR; + r.rtableid = $5.rtableid; if (hh != NULL) h = hh; else @@ -999,11 +1020,15 @@ antispoof_if : if_item { $$ = $1; } } ; -antispoof_opts : { bzero(&antispoof_opts, sizeof antispoof_opts); } +antispoof_opts : { + bzero(&antispoof_opts, sizeof antispoof_opts); + antispoof_opts.rtableid = -1; + } antispoof_opts_l { $$ = antispoof_opts; } | /* empty */ { bzero(&antispoof_opts, sizeof antispoof_opts); + antispoof_opts.rtableid = -1; $$ = antispoof_opts; } ; @@ -1019,6 +1044,13 @@ antispoof_opt : label { } antispoof_opts.label = $1; } + | RTABLE number { + if ($2 > RT_TABLEID_MAX || $2 < 0) { + yyerror("invalid rtable id"); + YYERROR; + } + antispoof_opts.rtableid = $2; + } ; not : '!' { $$ = 1; } @@ -1536,6 +1568,7 @@ pfrule : action dir logquick interface route af proto fromto r.log = $3.log; r.quick = $3.quick; r.prob = $9.prob; + r.rtableid = $9.rtableid; r.af = $6; if ($9.tag) @@ -1850,11 +1883,15 @@ pfrule : action dir logquick interface route af proto fromto } ; -filter_opts : { bzero(&filter_opts, sizeof filter_opts); } +filter_opts : { + bzero(&filter_opts, sizeof filter_opts); + filter_opts.rtableid = -1; + } filter_opts_l { $$ = filter_opts; } | /* empty */ { bzero(&filter_opts, sizeof filter_opts); + filter_opts.rtableid = -1; $$ = filter_opts; } ; @@ -1962,6 +1999,13 @@ filter_opt : USER uids { filter_opts.prob = (u_int32_t)p; free($2); } + | RTABLE number { + if ($2 > RT_TABLEID_MAX || $2 < 0) { + yyerror("invalid rtable id"); + YYERROR; + } + filter_opts.rtableid = $2; + } ; matchtag : TAGGED matchtag_item { @@ -3284,7 +3328,8 @@ nataction : no NAT natpass { } ; -natrule : nataction interface af proto fromto tag tagged redirpool pool_opts +natrule : nataction interface af proto fromto tag tagged rtable + redirpool pool_opts { struct pf_rule r; @@ -3323,47 +3368,48 @@ natrule : nataction interface af proto fromto tag tagged redirpool pool_opts YYERROR; } r.match_tag_not = $7.neg; + r.rtableid = $8; if (r.action == PF_NONAT || r.action == PF_NORDR) { - if ($8 != NULL) { + if ($9 != NULL) { yyerror("translation rule with 'no' " "does not need '->'"); YYERROR; } } else { - if ($8 == NULL || $8->host == NULL) { + if ($9 == NULL || $9->host == NULL) { yyerror("translation rule requires '-> " "address'"); YYERROR; } - if (!r.af && ! $8->host->ifindex) - r.af = $8->host->af; + if (!r.af && ! $9->host->ifindex) + r.af = $9->host->af; - remove_invalid_hosts(&$8->host, &r.af); - if (invalid_redirect($8->host, r.af)) + remove_invalid_hosts(&$9->host, &r.af); + if (invalid_redirect($9->host, r.af)) YYERROR; - if (check_netmask($8->host, r.af)) + if (check_netmask($9->host, r.af)) YYERROR; - r.rpool.proxy_port[0] = ntohs($8->rport.a); + r.rpool.proxy_port[0] = ntohs($9->rport.a); switch (r.action) { case PF_RDR: - if (!$8->rport.b && $8->rport.t && + if (!$9->rport.b && $9->rport.t && $5.dst.port != NULL) { r.rpool.proxy_port[1] = - ntohs($8->rport.a) + + ntohs($9->rport.a) + (ntohs( $5.dst.port->port[1]) - ntohs( $5.dst.port->port[0])); } else r.rpool.proxy_port[1] = - ntohs($8->rport.b); + ntohs($9->rport.b); break; case PF_NAT: r.rpool.proxy_port[1] = - ntohs($8->rport.b); + ntohs($9->rport.b); if (!r.rpool.proxy_port[0] && !r.rpool.proxy_port[1]) { r.rpool.proxy_port[0] = @@ -3378,25 +3424,25 @@ natrule : nataction interface af proto fromto tag tagged redirpool pool_opts break; } - r.rpool.opts = $9.type; + r.rpool.opts = $10.type; if ((r.rpool.opts & PF_POOL_TYPEMASK) == - PF_POOL_NONE && ($8->host->next != NULL || - $8->host->addr.type == PF_ADDR_TABLE || - DYNIF_MULTIADDR($8->host->addr))) + PF_POOL_NONE && ($9->host->next != NULL || + $9->host->addr.type == PF_ADDR_TABLE || + DYNIF_MULTIADDR($9->host->addr))) r.rpool.opts = PF_POOL_ROUNDROBIN; if ((r.rpool.opts & PF_POOL_TYPEMASK) != PF_POOL_ROUNDROBIN && - disallow_table($8->host, "tables are only " + disallow_table($9->host, "tables are only " "supported in round-robin redirection " "pools")) YYERROR; if ((r.rpool.opts & PF_POOL_TYPEMASK) != PF_POOL_ROUNDROBIN && - disallow_alias($8->host, "interface (%s) " + disallow_alias($9->host, "interface (%s) " "is only supported in round-robin " "redirection pools")) YYERROR; - if ($8->host->next != NULL) { + if ($9->host->next != NULL) { if ((r.rpool.opts & PF_POOL_TYPEMASK) != PF_POOL_ROUNDROBIN) { yyerror("only round-robin " @@ -3407,14 +3453,14 @@ natrule : nataction interface af proto fromto tag tagged redirpool pool_opts } } - if ($9.key != NULL) - memcpy(&r.rpool.key, $9.key, + if ($10.key != NULL) + memcpy(&r.rpool.key, $10.key, sizeof(struct pf_poolhashkey)); - if ($9.opts) - r.rpool.opts |= $9.opts; + if ($10.opts) + r.rpool.opts |= $10.opts; - if ($9.staticport) { + if ($10.staticport) { if (r.action != PF_NAT) { yyerror("the 'static-port' option is " "only valid with nat rules"); @@ -3433,15 +3479,15 @@ natrule : nataction interface af proto fromto tag tagged redirpool pool_opts r.rpool.proxy_port[1] = 0; } - expand_rule(&r, $2, $8 == NULL ? NULL : $8->host, $4, + expand_rule(&r, $2, $9 == NULL ? NULL : $9->host, $4, $5.src_os, $5.src.host, $5.src.port, $5.dst.host, $5.dst.port, 0, 0, 0, 0, ""); - free($8); + free($9); } ; -binatrule : no BINAT natpass interface af proto FROM host TO ipspec tag tagged - redirection +binatrule : no BINAT natpass interface af proto FROM host TO ipspec tag + tagged rtable redirection { struct pf_rule binat; struct pf_pooladdr *pa; @@ -3470,8 +3516,8 @@ binatrule : no BINAT natpass interface af proto FROM host TO ipspec tag tagged if (!binat.af && $10 != NULL && $10->af) binat.af = $10->af; - if (!binat.af && $13 != NULL && $13->host) - binat.af = $13->host->af; + if (!binat.af && $14 != NULL && $14->host) + binat.af = $14->host->af; if (!binat.af) { yyerror("address family (inet/inet6) " "undefined"); @@ -3500,6 +3546,7 @@ binatrule : no BINAT natpass interface af proto FROM host TO ipspec tag tagged YYERROR; } binat.match_tag_not = $12.neg; + binat.rtableid = $13; if ($6 != NULL) { binat.proto = $6->proto; @@ -3513,12 +3560,12 @@ binatrule : no BINAT natpass interface af proto FROM host TO ipspec tag tagged "interface (%s) as the source address of a binat " "rule")) YYERROR; - if ($13 != NULL && $13->host != NULL && disallow_table( - $13->host, "invalid use of table <%s> as the " + if ($14 != NULL && $14->host != NULL && disallow_table( + $14->host, "invalid use of table <%s> as the " "redirect address of a binat rule")) YYERROR; - if ($13 != NULL && $13->host != NULL && disallow_alias( - $13->host, "invalid use of interface (%s) as the " + if ($14 != NULL && $14->host != NULL && disallow_alias( + $14->host, "invalid use of interface (%s) as the " "redirect address of a binat rule")) YYERROR; @@ -3557,33 +3604,33 @@ binatrule : no BINAT natpass interface af proto FROM host TO ipspec tag tagged } if (binat.action == PF_NOBINAT) { - if ($13 != NULL) { + if ($14 != NULL) { yyerror("'no binat' rule does not need" " '->'"); YYERROR; } } else { - if ($13 == NULL || $13->host == NULL) { + if ($14 == NULL || $14->host == NULL) { yyerror("'binat' rule requires" " '-> address'"); YYERROR; } - remove_invalid_hosts(&$13->host, &binat.af); - if (invalid_redirect($13->host, binat.af)) + remove_invalid_hosts(&$14->host, &binat.af); + if (invalid_redirect($14->host, binat.af)) YYERROR; - if ($13->host->next != NULL) { + if ($14->host->next != NULL) { yyerror("binat rule must redirect to " "a single address"); YYERROR; } - if (check_netmask($13->host, binat.af)) + if (check_netmask($14->host, binat.af)) YYERROR; if (!PF_AZERO(&binat.src.addr.v.a.mask, binat.af) && !PF_AEQ(&binat.src.addr.v.a.mask, - &$13->host->addr.v.a.mask, binat.af)) { + &$14->host->addr.v.a.mask, binat.af)) { yyerror("'binat' source mask and " "redirect mask must be the same"); YYERROR; @@ -3593,12 +3640,12 @@ binatrule : no BINAT natpass interface af proto FROM host TO ipspec tag tagged pa = calloc(1, sizeof(struct pf_pooladdr)); if (pa == NULL) err(1, "binat: calloc"); - pa->addr = $13->host->addr; + pa->addr = $14->host->addr; pa->ifname[0] = 0; TAILQ_INSERT_TAIL(&binat.rpool.list, pa, entries); - free($13); + free($14); } pfctl_add_rule(pf, &binat, ""); @@ -3613,6 +3660,16 @@ tagged : /* empty */ { $$.neg = 0; $$.name = NULL; } | not TAGGED string { $$.neg = $1; $$.name = $3; } ; +rtable : /* empty */ { $$ = -1; } + | RTABLE number { + if ($2 > RT_TABLEID_MAX || $2 < 0) { + yyerror("invalid rtable id"); + YYERROR; + } + $$ = $2; + } + ; + route_host : STRING { $$ = calloc(1, sizeof(struct node_host)); if ($$ == NULL) @@ -4737,6 +4794,7 @@ lookup(char *s) { "round-robin", ROUNDROBIN}, { "route", ROUTE}, { "route-to", ROUTETO}, + { "rtable", RTABLE}, { "rule", RULE}, { "scrub", SCRUB}, { "set", SET}, diff --git a/sbin/pfctl/pfctl_parser.c b/sbin/pfctl/pfctl_parser.c index 40449787f90..4f522dcd854 100644 --- a/sbin/pfctl/pfctl_parser.c +++ b/sbin/pfctl/pfctl_parser.c @@ -1,4 +1,4 @@ -/* $OpenBSD: pfctl_parser.c,v 1.225 2006/06/30 16:52:27 deraadt Exp $ */ +/* $OpenBSD: pfctl_parser.c,v 1.226 2006/07/06 13:26:41 henning Exp $ */ /* * Copyright (c) 2001 Daniel Hartmeier @@ -967,6 +967,8 @@ print_rule(struct pf_rule *r, const char *anchor_call, int verbose) printf(" !"); printf(" tagged %s", r->match_tagname); } + if (r->rtableid != -1) + printf(" rtable %u", r->rtableid); if (!anchor_call[0] && (r->action == PF_NAT || r->action == PF_BINAT || r->action == PF_RDR)) { printf(" -> "); |