diff options
Diffstat (limited to 'sbin')
-rw-r--r-- | sbin/pfctl/parse.y | 455 | ||||
-rw-r--r-- | sbin/pfctl/pfctl_parser.c | 303 | ||||
-rw-r--r-- | sbin/pfctl/pfctl_parser.h | 10 |
3 files changed, 585 insertions, 183 deletions
diff --git a/sbin/pfctl/parse.y b/sbin/pfctl/parse.y index e266dafdb5c..3cd689ce45b 100644 --- a/sbin/pfctl/parse.y +++ b/sbin/pfctl/parse.y @@ -1,4 +1,4 @@ -/* $OpenBSD: parse.y,v 1.31 2001/09/12 16:37:14 markus Exp $ */ +/* $OpenBSD: parse.y,v 1.32 2001/09/15 03:54:40 frantzen Exp $ */ /* * Copyright (c) 2001 Markus Friedl. All rights reserved. @@ -33,6 +33,7 @@ #include <netinet/in_systm.h> #include <netinet/ip.h> #include <netinet/ip_icmp.h> +#include <netinet/icmp6.h> #include <net/pfvar.h> #include <arpa/inet.h> @@ -65,8 +66,9 @@ struct node_proto { }; struct node_host { - u_int32_t addr; - u_int32_t mask; + struct pf_addr addr; + struct pf_addr mask; + u_int8_t af; u_int8_t not; struct node_host *next; }; @@ -77,6 +79,13 @@ struct node_port { struct node_port *next; }; +struct node_icmp { + u_int8_t code; + u_int8_t type; + u_int8_t proto; + struct node_icmp *next; +}; + struct peer { struct node_host *host; struct node_port *port; @@ -85,19 +94,22 @@ struct peer { int rule_consistent(struct pf_rule *); int yyparse(void); struct pf_rule_addr *new_addr(void); -u_int32_t ipmask(u_int8_t); +void ipmask(struct pf_addr *, u_int8_t, int); void expand_rule_hosts(struct pf_rule *, struct node_if *, struct node_proto *, struct node_host *, struct node_port *, - struct node_host *, struct node_port *); + struct node_host *, struct node_port *, + struct node_icmp *); void expand_rule_protos(struct pf_rule *, struct node_if *, struct node_proto *, struct node_host *, struct node_port *, - struct node_host *, struct node_port *); + struct node_host *, struct node_port *, + struct node_icmp *); void expand_rule(struct pf_rule *, struct node_if *, struct node_proto *, struct node_host *, struct node_port *, - struct node_host *, struct node_port *); + struct node_host *, struct node_port *, + struct node_icmp *); struct sym { struct sym *next; @@ -126,6 +138,7 @@ typedef struct { } range; struct node_if *interface; struct node_proto *proto; + struct node_icmp *icmp; struct node_host *host; struct node_port *port; struct peer peer; @@ -139,20 +152,22 @@ typedef struct { %} %token PASS BLOCK SCRUB RETURN IN OUT LOG LOGALL QUICK ON FROM TO FLAGS -%token RETURNRST RETURNICMP PROTO ALL ANY ICMPTYPE CODE KEEP MODULATE STATE -%token PORT RDR NAT ARROW NODF MINTTL ERROR BINAT -%token <v.string> STRING -%token <v.number> NUMBER +%token RETURNRST RETURNICMP RETURNICMP6 PROTO INET INET6 ALL ANY ICMPTYPE +%token ICMP6TYPE CODE KEEP MODULATE STATE PORT RDR NAT BINAT ARROW NODF +%token MINTTL IPV6ADDR ERROR +%token <v.string> STRING +%token <v.number> NUMBER %token <v.i> PORTUNARY PORTBINARY %type <v.interface> interface if_list if_item_not if_item -%type <v.number> port icmptype minttl -%type <v.i> dir log quick keep nodf -%type <v.b> action icmpspec flag flags blockspec +%type <v.number> port icmptype icmp6type minttl +%type <v.i> dir log quick af keep nodf +%type <v.b> action flag flags blockspec %type <v.range> dport rport %type <v.proto> proto proto_list proto_item +%type <v.icmp> icmpspec icmp_list icmp6_list icmp_item icmp6_item %type <v.fromto> fromto %type <v.peer> ipportspec -%type <v.host> ipspec xhost host address host_list +%type <v.host> ipspec xhost host address host_list IPV6ADDR %type <v.port> portspec port_list port_item %% @@ -176,7 +191,7 @@ varset : STRING PORTUNARY STRING } ; -pfrule : action dir log quick interface proto fromto flags icmpspec keep nodf minttl +pfrule : action dir log quick interface af proto fromto flags icmpspec keep nodf minttl { struct pf_rule r; @@ -195,19 +210,19 @@ pfrule : action dir log quick interface proto fromto flags icmpspec keep nodf m r.log = $3; r.quick = $4; - r.flags = $8.b1; - r.flagset = $8.b2; - r.type = $9.b1; - r.code = $9.b2; - r.keep_state = $10; + r.af = $6; + r.flags = $9.b1; + r.flagset = $9.b2; + + r.keep_state = $11; - if ($11) - r.rule_flag |= PFRULE_NODF; if ($12) - r.min_ttl = $12; + r.rule_flag |= PFRULE_NODF; + if ($13) + r.min_ttl = $13; - expand_rule(&r, $5, $6, $7.src.host, $7.src.port, - $7.dst.host, $7.dst.port); + expand_rule(&r, $5, $7, $8.src.host, $8.src.port, + $8.dst.host, $8.dst.port, $10); } ; @@ -222,10 +237,27 @@ blockspec : /* empty */ { $$.b2 = 0; $$.w = 0; } $$.b2 = 0; $$.w = (ICMP_UNREACH << 8) | ICMP_UNREACH_PORT; } + | RETURNICMP6 { + $$.b2 = 0; + $$.w = (ICMP6_DST_UNREACH << 8) | + ICMP6_DST_UNREACH_NOPORT; + } | RETURNICMP '(' STRING ')' { struct icmpcodeent *p; - if ((p = geticmpcodebyname(ICMP_UNREACH, $3)) == NULL) { + if ((p = geticmpcodebyname(ICMP_UNREACH, $3, + IPPROTO_ICMP)) == NULL) { + yyerror("unknown icmp code %s", $3); + YYERROR; + } + $$.w = (p->type << 8) | p->code; + $$.b2 = 0; + } + | RETURNICMP6 '(' STRING ')' { + struct icmpcodeent *p; + + if ((p = geticmpcodebyname(ICMP6_DST_UNREACH, $3, + IPPROTO_ICMPV6)) == NULL) { yyerror("unknown icmp code %s", $3); YYERROR; } @@ -269,6 +301,10 @@ if_item : STRING { } ; +af : /* empty */ { $$ = 0; } + | INET { $$ = AF_INET; } + | INET6 { $$ = AF_INET6; } + proto : /* empty */ { $$ = NULL; } | PROTO proto_item { $$ = $2; } | PROTO '{' proto_list '}' { $$ = $3; } @@ -340,29 +376,51 @@ xhost : '!' host { $$ = $2; $$->not = 1; } host : address { $$ = $1; - $$->mask = 0xffffffff; + if ($$->af == AF_INET) + ipmask(&$$->mask, 32, AF_INET); + else + ipmask(&$$->mask, 128, AF_INET6); } | address '/' NUMBER { - if ($3 < 0 || $3 > 32) { - yyerror("illegal netmask value %d", $3); - YYERROR; + if ($$->af == AF_INET) { + if ($3 < 0 || $3 > 32) { + yyerror("illegal netmask value %d", $3); + YYERROR; + } + } else { + if ($3 < 0 || $3 > 128) { + yyerror("illegal netmask value %d", $3); + YYERROR; + } } $$ = $1; - $$->mask = ipmask($3); + ipmask(&$$->mask, $3, $$->af); } ; address : STRING { struct hostent *hp; - if ((hp = gethostbyname($1)) == NULL) { - yyerror("cannot resolve %s", $1); - YYERROR; + if ((hp = gethostbyname2($1, AF_INET)) == NULL) { + if ((hp = gethostbyname2($1, AF_INET6)) + == NULL) { + yyerror("cannot resolve %s", $1); + YYERROR; + } else { + $$ = calloc(1, sizeof(struct node_host)); + if ($$ == NULL) + err(1, "address: calloc"); + $$->af = AF_INET6; + memcpy(&$$->addr, hp->h_addr, + sizeof(struct pf_addr)); + } + } else { + $$ = calloc(1, sizeof(struct node_host)); + if ($$ == NULL) + err(1, "address: calloc"); + $$->af = AF_INET; + memcpy(&$$->addr, hp->h_addr, sizeof(u_int32_t)); } - $$ = calloc(1, sizeof(struct node_host)); - if ($$ == NULL) - err(1, "address: calloc"); - memcpy(&$$->addr, hp->h_addr, sizeof(u_int32_t)); } | NUMBER '.' NUMBER '.' NUMBER '.' NUMBER { if ($1 < 0 || $3 < 0 || $5 < 0 || $7 < 0 || @@ -374,8 +432,11 @@ address : STRING { $$ = calloc(1, sizeof(struct node_host)); if ($$ == NULL) err(1, "address: calloc"); - $$->addr = htonl(($1 << 24) | ($3 << 16) | ($5 << 8) | $7); + $$->af = AF_INET; + $$->addr.addr32[0] = htonl(($1 << 24) | + ($3 << 16) | ($5 << 8) | $7); } + | IPV6ADDR { $$ = $1; } ; portspec : port_item { $$ = $1; } @@ -453,32 +514,105 @@ flags : /* empty */ { $$.b1 = 0; $$.b2 = 0; } | FLAGS "/" flag { $$.b1 = 0; $$.b2 = $3.b1; } ; -icmpspec : /* empty */ { $$.b1 = 0; $$.b2 = 0; } - | ICMPTYPE icmptype { $$.b1 = $2; $$.b2 = 0; } - | ICMPTYPE icmptype CODE NUMBER { - if ($4 < 0 || $4 > 255) { - yyerror("illegal icmp code %d", $4); +icmpspec : /* empty */ { $$ = NULL; } + | ICMPTYPE icmp_item { $$ = $2; } + | ICMPTYPE '{' icmp_list '}' { $$ = $3; } + | ICMP6TYPE icmp6_item { $$ = $2; } + | ICMP6TYPE '{' icmp6_list '}' { $$ = $3; } + ; + +icmp_list : icmp_item { $$ = $1; } + | icmp_list ',' icmp_item { $3->next = $1; $$ = $3; } + ; + +icmp6_list : icmp6_item { $$ = $1; } + | icmp6_list ',' icmp6_item { $3->next = $1; $$ = $3; } + ; + +icmp_item : icmptype { + $$ = malloc(sizeof(struct node_icmp)); + if ($$ == NULL) + err(1, "icmp_item: malloc"); + $$->type = $1; + $$->code = 0; + $$->proto = IPPROTO_ICMP; + $$->next = NULL; + } + | icmptype CODE NUMBER { + $$ = malloc(sizeof(struct node_icmp)); + if ($$ == NULL) + err(1, "icmp_item: malloc"); + if ($3 < 0 || $3 > 255) { + yyerror("illegal icmp code %d", $3); YYERROR; } - $$.b1 = $2; - $$.b2 = $4 + 1; + $$->code = $1; + $$->type = $3 + 1; + $$->proto = IPPROTO_ICMP; + $$->next = NULL; } - | ICMPTYPE icmptype CODE STRING { + | icmptype CODE STRING { struct icmpcodeent *p; - $$.b1 = $2; - if ((p = geticmpcodebyname($2, $4)) == NULL) { - yyerror("unknown icmp-code %s", $4); + $$ = malloc(sizeof(struct node_icmp)); + if ($$ == NULL) + err(1, "icmp_item: malloc"); + $$->type = $1; + if ((p = geticmpcodebyname($1, $3, + IPPROTO_ICMP)) == NULL) { + yyerror("unknown icmp-code %s", $3); YYERROR; } - $$.b2 = p->code + 1; + $$->code = p->code + 1; + $$->proto = IPPROTO_ICMP; + $$->next = NULL; + } + ; + +icmp6_item : icmp6type { + $$ = malloc(sizeof(struct node_icmp)); + if ($$ == NULL) + err(1, "icmp_item: malloc"); + $$->type = $1; + $$->code = 0; + $$->proto = IPPROTO_ICMPV6; + $$->next = NULL; + } + | icmp6type CODE NUMBER { + $$ = malloc(sizeof(struct node_icmp)); + if ($$ == NULL) + err(1, "icmp_item: malloc"); + if ($3 < 0 || $3 > 255) { + yyerror("illegal icmp6 code %d", $3); + YYERROR; + } + $$->type = $1; + $$->code = $3 + 1; + $$->proto = IPPROTO_ICMPV6; + $$->next = NULL; + } + | icmp6type CODE STRING { + struct icmpcodeent *p; + + $$ = malloc(sizeof(struct node_icmp)); + if ($$ == NULL) + err(1, "icmp_item: malloc"); + $$->type = $1; + if ((p = geticmpcodebyname($1, $3, + IPPROTO_ICMPV6)) == NULL) { + yyerror("unknown icmp6-code %s", $3); + YYERROR; + } + $$->code = p->code + 1; + $$->proto = IPPROTO_ICMPV6; + $$->next = NULL; } ; icmptype : STRING { struct icmptypeent *p; - if ((p = geticmptypebyname($1)) == NULL) { + if ((p = geticmptypebyname($1, IPPROTO_ICMP)) == NULL) { yyerror("unknown icmp-type %s", $1); YYERROR; } @@ -493,6 +627,24 @@ icmptype : STRING { } ; +icmp6type : STRING { + struct icmptypeent *p; + + if ((p = geticmptypebyname($1, + IPPROTO_ICMPV6)) == NULL) { + yyerror("unknown ipv6-icmp-type %s", $1); + YYERROR; + } + $$ = p->type + 1; + } + | NUMBER { + if ($1 < 0 || $1 > 255) { + yyerror("illegal icmp6 type %d", $1); + YYERROR; + } + $$ = $1 + 1; + } + ; keep : /* empty */ { $$ = 0; } | KEEP STATE { $$ = PF_STATE_NORMAL; } @@ -532,15 +684,30 @@ natrule : NAT interface proto FROM ipspec TO ipspec ARROW address nat.proto = $3->proto; free($3); } + if ($5 != NULL && $7 != NULL) { + if ($5->af && $7->af && $5->af != $7->af) { + yyerror("nat ip versions must match"); + YYERROR; + } else { + if ($5->af) + nat.af = $5->af; + else if ($7->af) + nat.af = $7->af; + } + } if ($5 != NULL) { - nat.saddr = $5->addr; - nat.smask = $5->mask; + memcpy(&nat.saddr, &$5->addr, + sizeof(nat.saddr)); + memcpy(&nat.smask, &$5->mask, + sizeof(nat.smask)); nat.snot = $5->not; free($5); } if ($7 != NULL) { - nat.daddr = $7->addr; - nat.dmask = $7->mask; + memcpy(&nat.daddr, &$7->addr, + sizeof(nat.daddr)); + memcpy(&nat.dmask, &$7->mask, + sizeof(nat.dmask)); nat.dnot = $7->not; free($7); } @@ -549,7 +716,13 @@ natrule : NAT interface proto FROM ipspec TO ipspec ARROW address yyerror("nat rule requires redirection address"); YYERROR; } - nat.raddr = $9->addr; + /* we don't support IPv4 <-> IPv6 nat... yet */ + if (nat.af && $9->af != nat.af) { + yyerror("nat ip versions must match"); + YYERROR; + } else + nat.af = $9->af; + memcpy(&nat.raddr, &$9->addr, sizeof(nat.raddr)); free($9); pfctl_add_nat(pf, &nat); } @@ -573,13 +746,27 @@ binatrule : BINAT interface proto FROM address TO ipspec ARROW address binat.proto = $3->proto; free($3); } + if ($5 != NULL && $7 != NULL) { + if ($5->af && $7->af && $5->af != $7->af) { + yyerror("nat ip versions must match"); + YYERROR; + } else { + if ($5->af) + binat.af = $5->af; + else if ($7->af) + binat.af = $7->af; + } + } if ($5 != NULL) { - binat.saddr = $5->addr; + memcpy(&binat.saddr, &$5->addr, + sizeof(binat.saddr)); free($5); } if ($7 != NULL) { - binat.daddr = $7->addr; - binat.dmask = $7->mask; + memcpy(&binat.daddr, &$7->addr, + sizeof(binat.daddr)); + memcpy(&binat.dmask, &$7->mask, + sizeof(binat.dmask)); binat.dnot = $7->not; free($7); } @@ -588,7 +775,7 @@ binatrule : BINAT interface proto FROM address TO ipspec ARROW address yyerror("binat rule requires redirection address"); YYERROR; } - binat.raddr = $9->addr; + memcpy(&binat.raddr, &$9->addr, sizeof(binat.raddr)); free($9); pfctl_add_binat(pf, &binat); } @@ -612,15 +799,30 @@ rdrrule : RDR interface proto FROM ipspec TO ipspec dport ARROW address rport rdr.proto = $3->proto; free($3); } + if ($5 != NULL && $7 != NULL) { + if ($5->af && $7->af && $5->af != $7->af) { + yyerror("rdr ip versions must match"); + YYERROR; + } else { + if ($5->af) + rdr.af = $5->af; + else if ($7->af) + rdr.af = $7->af; + } + } if ($5 != NULL) { - rdr.saddr = $5->addr; - rdr.smask = $5->mask; + memcpy(&rdr.saddr, &$5->addr, + sizeof(rdr.saddr)); + memcpy(&rdr.smask, &$5->mask, + sizeof(rdr.smask)); rdr.snot = $5->not; free($5); } if ($7 != NULL) { - rdr.daddr = $7->addr; - rdr.dmask = $7->mask; + memcpy(&rdr.daddr, &$7->addr, + sizeof(rdr.daddr)); + memcpy(&rdr.dmask, &$7->mask, + sizeof(rdr.dmask)); rdr.dnot = $7->not; free($7); } @@ -633,7 +835,12 @@ rdrrule : RDR interface proto FROM ipspec TO ipspec dport ARROW address rport yyerror("rdr rule requires redirection address"); YYERROR; } - rdr.raddr = $10->addr; + if (rdr.af && $10->af != rdr.af) { + yyerror("rdr ip versions must match"); + YYERROR; + } else + rdr.af = $10->af; + memcpy(&rdr.raddr, &$10->addr, sizeof(rdr.raddr)); free($10); rdr.rport = $11.a; @@ -726,10 +933,20 @@ rule_consistent(struct pf_rule *r) yyerror("port only applies to tcp/udp"); problems++; } - if (r->proto != IPPROTO_ICMP && (r->type || r->code)) { + if (r->proto != IPPROTO_ICMP && r->proto != IPPROTO_ICMPV6 && + (r->type || r->code)) { yyerror("icmp-type/code only applies to icmp"); problems++; } + if (!r->af && (r->type || r->code)) { + yyerror("must indicate address family with icmp-type/code"); + problems++; + } + if ((r->proto == IPPROTO_ICMP && r->af == AF_INET6) || + (r->proto == IPPROTO_ICMPV6 && r->af == AF_INET)) { + yyerror("icmp version does not match address family"); + problems++; + } if (r->keep_state == PF_STATE_MODULATE && r->proto && r->proto != IPPROTO_TCP) { yyerror("modulate state can only be applied to TCP rules"); @@ -761,10 +978,12 @@ rule_consistent(struct pf_rule *r) void expand_rule_hosts(struct pf_rule *r, struct node_if *interface, struct node_proto *proto, struct node_host *src_hosts, struct node_port *src_ports, - struct node_host *dst_hosts, struct node_port *dst_ports) + struct node_host *dst_hosts, struct node_port *dst_ports, + struct node_icmp *icmp_type) { struct node_host *src_host, *dst_host; struct node_port *src_port, *dst_port; + int nomatch = 0; src_host = src_hosts; while (src_host != NULL) { @@ -789,7 +1008,28 @@ void expand_rule_hosts(struct pf_rule *r, r->dst.port[0] = dst_port->port[0]; r->dst.port[1] = dst_port->port[1]; r->dst.port_op = dst_port->op; - if (rule_consistent(r) < 0) + r->type = icmp_type->type; + r->code = icmp_type->code; + + if (src_host->af && + dst_host->af && + (src_host->af != + dst_host->af)) { + yyerror("address family" + " mismatch"); + nomatch++; + } else if (src_host->af) + r->af = src_host->af; + else if (dst_host->af) + r->af = dst_host->af; + + if (icmp_type->proto && + r->proto != icmp_type->proto) { + yyerror("icmp-type mismatch"); + nomatch++; + } + + if (rule_consistent(r) < 0 || nomatch) yyerror("skipping rule " "due to errors"); else @@ -807,14 +1047,20 @@ void expand_rule_hosts(struct pf_rule *r, void expand_rule_protos(struct pf_rule *r, struct node_if *interface, struct node_proto *protos, struct node_host *src_hosts, struct node_port *src_ports, - struct node_host *dst_hosts, struct node_port *dst_ports) + struct node_host *dst_hosts, struct node_port *dst_ports, + struct node_icmp *icmp_types) { struct node_proto *proto; + struct node_icmp *icmp_type; proto = protos; while (proto != NULL) { - expand_rule_hosts(r, interface, proto, src_hosts, - src_ports, dst_hosts, dst_ports); + icmp_type = icmp_types; + while (icmp_type != NULL) { + expand_rule_hosts(r, interface, proto, src_hosts, + src_ports, dst_hosts, dst_ports, icmp_type); + icmp_type = icmp_type->next; + } proto = proto->next; } } @@ -823,7 +1069,8 @@ void expand_rule(struct pf_rule *r, struct node_if *interfaces, struct node_proto *protos, struct node_host *src_hosts, struct node_port *src_ports, - struct node_host *dst_hosts, struct node_port *dst_ports) + struct node_host *dst_hosts, struct node_port *dst_ports, + struct node_icmp *icmp_types) { struct node_if *interface; @@ -833,11 +1080,12 @@ expand_rule(struct pf_rule *r, CHECK_ROOT(struct node_port, src_ports); CHECK_ROOT(struct node_host, dst_hosts); CHECK_ROOT(struct node_port, dst_ports); + CHECK_ROOT(struct node_icmp, icmp_types); interface = interfaces; while (interface != NULL) { expand_rule_protos(r, interface, protos, src_hosts, - src_ports, dst_hosts, dst_ports); + src_ports, dst_hosts, dst_ports, icmp_types); interface = interface->next; } @@ -847,6 +1095,8 @@ expand_rule(struct pf_rule *r, FREE_LIST(struct node_port, src_ports); FREE_LIST(struct node_host, dst_hosts); FREE_LIST(struct node_port, dst_ports); + FREE_LIST(struct node_icmp, icmp_types); + } #undef FREE_LIST @@ -868,7 +1118,10 @@ lookup(char *s) { "flags", FLAGS}, { "from", FROM}, { "icmp-type", ICMPTYPE}, + { "ipv6-icmp-type", ICMP6TYPE}, { "in", IN}, + { "inet", INET}, + { "inet6", INET6}, { "keep", KEEP}, { "log", LOG}, { "log-all", LOGALL}, @@ -885,6 +1138,7 @@ lookup(char *s) { "rdr", RDR}, { "return", RETURN}, { "return-icmp",RETURNICMP}, + { "return-icmp6",RETURNICMP6}, { "return-rst", RETURNRST}, { "scrub", SCRUB}, { "state", STATE}, @@ -1085,6 +1339,42 @@ top: break; } + /* Need to parse v6 addresses before tokenizing numbers. ick */ + if (isxdigit(c) || c == ':') { + struct node_host *node = NULL; + u_int32_t addr[4]; + char lookahead[46]; + int i = 0, notv6addr = 0; + + lookahead[i] = c; + + while (i < sizeof(lookahead) && + (isxdigit(c) || c == ':' || c == '.')) { + lookahead[++i] = c = lgetc(fin); + } + + /* quick check avoids calling inet_pton too often */ + if (isalnum(c)) { + notv6addr++; + } + lungetc(lookahead[i], fin); + lookahead[i] = '\0'; + + if(!notv6addr && inet_pton(AF_INET6, lookahead, &addr) == 1) { + node = calloc(1, sizeof(struct node_host)); + node->af = AF_INET6; + memcpy (&node->addr, &addr, sizeof(addr)); + yylval.v.host = node; + return IPV6ADDR; + } else { + free(node); + while (i > 1) { + lungetc(lookahead[--i], fin); + } + c = lookahead[--i]; + } + } + if (isdigit(c)) { int index = 0, base = 10; u_int64_t n = 0; @@ -1181,15 +1471,18 @@ parse_nat(FILE *input, struct pfctl *xpf) return (errors ? -1 : 0); } -u_int32_t -ipmask(u_int8_t b) +void +ipmask(struct pf_addr *m, u_int8_t b, int af) { - u_int32_t m = 0; - int i; + int i, j = 0; + while (b >= 32) { + m->addr32[j++] = 0xffffffff; + b -= 32; + } for (i = 31; i > 31-b; --i) - m |= (1 << i); - return (htonl(m)); + m->addr32[j] |= (1 << i); + m->addr32[j] = htonl(m->addr32[j]); } struct pf_rule_addr * diff --git a/sbin/pfctl/pfctl_parser.c b/sbin/pfctl/pfctl_parser.c index 859d9402b5b..b85403aadc2 100644 --- a/sbin/pfctl/pfctl_parser.c +++ b/sbin/pfctl/pfctl_parser.c @@ -1,4 +1,4 @@ -/* $OpenBSD: pfctl_parser.c,v 1.47 2001/09/06 18:05:46 jasoni Exp $ */ +/* $OpenBSD: pfctl_parser.c,v 1.48 2001/09/15 03:54:40 frantzen Exp $ */ /* * Copyright (c) 2001 Daniel Hartmeier @@ -37,6 +37,7 @@ #include <netinet/in_systm.h> #include <netinet/ip.h> #include <netinet/ip_icmp.h> +#include <netinet/icmp6.h> #define TCPSTATES #include <netinet/tcp_fsm.h> #include <net/pfvar.h> @@ -53,8 +54,9 @@ #include "pfctl_parser.h" -void print_addr (u_int32_t); -void print_host (struct pf_state_host *); +int unmask (struct pf_addr *, int); +void print_addr (struct pf_addr *, struct pf_addr *, int); +void print_host (struct pf_state_host *, int); void print_seq (struct pf_state_peer *); void print_port (u_int8_t, u_int16_t, u_int16_t, char *); void print_flags (u_int8_t); @@ -90,6 +92,35 @@ struct icmptypeent icmp_type[] = { }; +struct icmptypeent icmp6_type[] = { + { "unreach", ICMP6_DST_UNREACH }, + { "toobig", ICMP6_PACKET_TOO_BIG }, + { "timex", ICMP6_TIME_EXCEEDED }, + { "paramprob", ICMP6_PARAM_PROB }, + { "echoreq", ICMP6_ECHO_REQUEST }, + { "echorep", ICMP6_ECHO_REPLY }, + { "groupqry", ICMP6_MEMBERSHIP_QUERY }, + { "listqry", MLD6_LISTENER_QUERY }, + { "grouprep", ICMP6_MEMBERSHIP_REPORT }, + { "listenrep", MLD6_LISTENER_REPORT }, + { "groupterm", ICMP6_MEMBERSHIP_REDUCTION }, + { "listendone", MLD6_LISTENER_DONE }, + { "routersol", ND_ROUTER_SOLICIT }, + { "routeradv", ND_ROUTER_ADVERT }, + { "neighbrsol", ND_NEIGHBOR_SOLICIT }, + { "neighbradv", ND_NEIGHBOR_ADVERT }, + { "redir", ND_REDIRECT }, + { "routrrenum", ICMP6_ROUTER_RENUMBERING }, + { "wrureq", ICMP6_WRUREQUEST }, + { "wrurep", ICMP6_WRUREPLY }, + { "fqdnreq", ICMP6_FQDN_QUERY }, + { "fqdnrep", ICMP6_FQDN_REPLY }, + { "niqry", ICMP6_NI_QUERY }, + { "nirep", ICMP6_NI_REPLY }, + { "mtraceresp", MLD6_MTRACE_RESP }, + { "mtrace", MLD6_MTRACE } +}; + struct icmpcodeent icmp_code[] = { { "net-unr", ICMP_UNREACH, ICMP_UNREACH_NET }, { "host-unr", ICMP_UNREACH, ICMP_UNREACH_HOST }, @@ -123,69 +154,154 @@ struct icmpcodeent icmp_code[] = { { "decrypt-fail", ICMP_PHOTURIS, ICMP_PHOTURIS_DECRYPT_FAILED } }; +struct icmpcodeent icmp6_code[] = { + { "admin-unr", ICMP6_DST_UNREACH, ICMP6_DST_UNREACH_NOROUTE }, + { "noroute-unr", ICMP6_DST_UNREACH, ICMP6_DST_UNREACH_ADMIN }, + { "notnbr-unr", ICMP6_DST_UNREACH, ICMP6_DST_UNREACH_NOTNEIGHBOR }, + { "beyond-unr", ICMP6_DST_UNREACH, ICMP6_DST_UNREACH_BEYONDSCOPE }, + { "addr-unr", ICMP6_DST_UNREACH, ICMP6_DST_UNREACH_ADDR }, + { "port-unr", ICMP6_DST_UNREACH, ICMP6_DST_UNREACH_NOPORT }, + { "transit", ICMP6_TIME_EXCEEDED, ICMP6_TIME_EXCEED_TRANSIT }, + { "reassemb", ICMP6_TIME_EXCEEDED, ICMP6_TIME_EXCEED_REASSEMBLY }, + { "badhead", ICMP6_PARAM_PROB, ICMP6_PARAMPROB_HEADER }, + { "nxthdr", ICMP6_PARAM_PROB, ICMP6_PARAMPROB_NEXTHEADER }, + { "redironlink", ND_REDIRECT, ND_REDIRECT_ONLINK }, + { "redirrouter", ND_REDIRECT, ND_REDIRECT_ROUTER } +}; + + struct icmptypeent * -geticmptypebynumber(u_int8_t type) +geticmptypebynumber(u_int8_t type, u_int8_t proto) { unsigned i; - for(i=0; i < (sizeof (icmp_type) / sizeof(icmp_type[0])); i++) { - if(type == icmp_type[i].type) - return (&icmp_type[i]); + if (proto == IPPROTO_ICMP) { + for(i=0; i < (sizeof (icmp_type) / sizeof(icmp_type[0])); i++) { + if(type == icmp_type[i].type) + return (&icmp_type[i]); + } + } else { + for(i=0; i < (sizeof (icmp6_type) / + sizeof(icmp6_type[0])); i++) { + if(type == icmp6_type[i].type) + return (&icmp6_type[i]); + } } - return (0); + return (NULL); } struct icmptypeent * -geticmptypebyname(char *w) +geticmptypebyname(char *w, u_int8_t proto) { unsigned i; - for(i=0; i < (sizeof (icmp_type) / sizeof(icmp_type[0])); i++) { - if(!strcmp(w, icmp_type[i].name)) - return (&icmp_type[i]); + if (proto == IPPROTO_ICMP) { + for(i=0; i < (sizeof (icmp_type) / sizeof(icmp_type[0])); i++) { + if(!strcmp(w, icmp_type[i].name)) + return (&icmp_type[i]); + } + } else { + for(i=0; i < (sizeof (icmp6_type) / + sizeof(icmp6_type[0])); i++) { + if(!strcmp(w, icmp6_type[i].name)) + return (&icmp6_type[i]); + } } - return (0); + return (NULL); } struct icmpcodeent * -geticmpcodebynumber(u_int8_t type, u_int8_t code) +geticmpcodebynumber(u_int8_t type, u_int8_t code, u_int8_t proto) { unsigned i; - for(i=0; i < (sizeof (icmp_code) / sizeof(icmp_code[0])); i++) { - if (type == icmp_code[i].type && code == icmp_code[i].code) - return (&icmp_code[i]); + if (proto == IPPROTO_ICMP) { + for(i=0; i < (sizeof (icmp_code) / sizeof(icmp_code[0])); i++) { + if (type == icmp_code[i].type && + code == icmp_code[i].code) + return (&icmp_code[i]); + } + } else { + for(i=0; i < (sizeof (icmp6_code) / + sizeof(icmp6_code[0])); i++) { + if (type == icmp6_code[i].type && + code == icmp6_code[i].code) + return (&icmp6_code[i]); + } } - return (0); + return (NULL); } struct icmpcodeent * -geticmpcodebyname(u_long type, char *w) +geticmpcodebyname(u_long type, char *w, u_int8_t proto) { unsigned i; - for(i=0; i < (sizeof (icmp_code) / sizeof(icmp_code[0])); i++) { - if (type == icmp_code[i].type && !strcmp(w, icmp_code[i].name)) - return (&icmp_code[i]); + if (proto == IPPROTO_ICMP) { + for(i=0; i < (sizeof (icmp_code) / sizeof(icmp_code[0])); i++) { + if (type == icmp_code[i].type && + !strcmp(w, icmp_code[i].name)) + return (&icmp_code[i]); + } + } else { + for(i=0; i < (sizeof (icmp6_code) / + sizeof(icmp6_code[0])); i++) { + if (type == icmp6_code[i].type && + !strcmp(w, icmp6_code[i].name)) + return (&icmp6_code[i]); + } + } + return (NULL); +} + +int +unmask(struct pf_addr *m, int af) +{ + int i = 31, j = 0, b = 0, msize; + u_int32_t tmp; + + if (af == AF_INET) + msize = 1; + else + msize = 4; + while (j < msize && m->addr32[j] == 0xffffffff) { + b += 32; + j++; } - return (0); + if (j < msize) { + tmp = ntohl(m->addr32[j]); + for (i = 31; tmp & (1 << i); --i) + b++; + } + return (b); } void -print_addr(u_int32_t a) +print_addr(struct pf_addr *addr, struct pf_addr *mask, int af) { - a = ntohl(a); - printf("%u.%u.%u.%u", (a>>24)&255, (a>>16)&255, (a>>8)&255, a&255); + char buf[48]; + const char *bf; + + bf = inet_ntop(af, addr, buf, sizeof(buf)); + printf("%s", bf); + if (mask != NULL) { + if (!PF_AZERO(mask, af)) + printf("/%u", unmask(mask, af)); + } } void -print_host(struct pf_state_host *h) +print_host(struct pf_state_host *h, int af) { - u_int32_t a = ntohl(h->addr); u_int16_t p = ntohs(h->port); - printf("%u.%u.%u.%u:%u", (a>>24)&255, (a>>16)&255, (a>>8)&255, a&255, p); + print_addr(&h->addr, NULL, af); + if (af == AF_INET) + printf(":%u", p); + else + printf("[%u]", p); } + void print_seq(struct pf_state_peer *p) @@ -250,31 +366,23 @@ print_nat(struct pf_nat *n) printf("%s ", n->ifname); } printf("from "); - if (n->saddr || n->smask) { + if (!PF_AZERO(&n->saddr, n->af) || !PF_AZERO(&n->smask, n->af)) { if (n->snot) printf("! "); - print_addr(n->saddr); - if (n->smask != 0xFFFFFFFF) { - printf("/"); - print_addr(n->smask); - } + print_addr(&n->saddr, &n->smask, n->af); printf(" "); } else printf("any "); printf("to "); - if (n->daddr || n->dmask) { - if (n->dnot) + if (!PF_AZERO(&n->daddr, n->af) || !PF_AZERO(&n->dmask, n->af)) { + if (n->snot) printf("! "); - print_addr(n->daddr); - if (n->dmask != 0xFFFFFFFF) { - printf("/"); - print_addr(n->dmask); - } + print_addr(&n->daddr, &n->dmask, n->af); printf(" "); } else printf("any "); printf("-> "); - print_addr(n->raddr); + print_addr(&n->raddr, NULL, n->af); printf(" "); switch (n->proto) { case IPPROTO_TCP: @@ -310,22 +418,18 @@ print_binat(struct pf_binat *b) break; } printf("from "); - print_addr(b->saddr); + print_addr(&b->saddr, NULL, b->af); printf(" "); printf("to "); - if (b->daddr || b->dmask) { + if (!PF_AZERO(&b->daddr, b->af) || !PF_AZERO(&b->dmask, b->af)) { if (b->dnot) printf("! "); - print_addr(b->daddr); - if (b->dmask != 0xFFFFFFFF) { - printf("/"); - print_addr(b->dmask); - } + print_addr(&b->daddr, &b->dmask, b->af); printf(" "); } else printf("any "); printf("-> "); - print_addr(b->raddr); + print_addr(&b->raddr, NULL, b->af); printf("\n"); } @@ -348,26 +452,18 @@ print_rdr(struct pf_rdr *r) break; } printf("from "); - if (r->saddr || r->smask) { + if (!PF_AZERO(&r->saddr, r->af) || !PF_AZERO(&r->smask, r->af)) { if (r->snot) printf("! "); - print_addr(r->saddr); - if (r->smask != 0xFFFFFFFF) { - printf("/"); - print_addr(r->smask); - } + print_addr(&r->saddr, &r->smask, r->af); printf(" "); } else printf("any "); printf("to "); - if (r->daddr || r->dmask) { - if (r->dnot) + if (!PF_AZERO(&r->daddr, r->af) || !PF_AZERO(&r->dmask, r->af)) { + if (r->snot) printf("! "); - print_addr(r->daddr); - if (r->dmask != 0xFFFFFFFF) { - printf("/"); - print_addr(r->dmask); - } + print_addr(&r->daddr, &r->dmask, r->af); printf(" "); } else printf("any "); @@ -375,7 +471,7 @@ print_rdr(struct pf_rdr *r) if (r->opts & PF_DPORT_RANGE) printf(":%u", ntohs(r->dport2)); printf(" -> "); - print_addr(r->raddr); + print_addr(&r->raddr, NULL, r->af); printf(" "); printf("port %u", ntohs(r->rport)); if (r->opts & PF_RPORT_RANGE) @@ -407,14 +503,22 @@ print_status(struct pf_status *s) printf("Misc"); break; } - printf("\nBytes In: %-10llu Bytes Out: %-10llu\n", - s->bcounters[PF_IN], s->bcounters[PF_OUT]); - printf("Inbound Packets: Passed: %-10llu Dropped: %-10llu\n", - s->pcounters[PF_IN][PF_PASS], - s->pcounters[PF_IN][PF_DROP]); - printf("Outbound Packets: Passed: %-10llu Dropped: %-10llu\n", - s->pcounters[PF_OUT][PF_PASS], - s->pcounters[PF_OUT][PF_DROP]); + printf("\nBytes In IPv4: %-10llu Bytes Out: %-10llu\n", + s->bcounters[0][PF_IN], s->bcounters[0][PF_OUT]); + printf(" IPv6: %-10llu Bytes Out: %-10llu\n", + s->bcounters[1][PF_IN], s->bcounters[1][PF_OUT]); + printf("Inbound Packets IPv4: Passed: %-10llu Dropped: %-10llu\n", + s->pcounters[0][PF_IN][PF_PASS], + s->pcounters[0][PF_IN][PF_DROP]); + printf(" IPv6: Passed: %-10llu Dropped: %-10llu\n", + s->pcounters[1][PF_IN][PF_PASS], + s->pcounters[1][PF_IN][PF_DROP]); + printf("Outbound Packets IPv4: Passed: %-10llu Dropped: %-10llu\n", + s->pcounters[0][PF_OUT][PF_PASS], + s->pcounters[0][PF_OUT][PF_DROP]); + printf(" IPv6: Passed: %-10llu Dropped: %-10llu\n", + s->pcounters[1][PF_OUT][PF_PASS], + s->pcounters[1][PF_OUT][PF_DROP]); printf("States: %u\n", s->states); printf("pf Counters\n"); for (i = 0; i < FCNT_MAX; i++) @@ -446,6 +550,7 @@ print_state(struct pf_state *s) case IPPROTO_UDP: printf("UDP "); break; + case IPPROTO_ICMPV6: case IPPROTO_ICMP: printf("ICMP "); break; @@ -453,19 +558,20 @@ print_state(struct pf_state *s) printf("???? "); break; } - if ((s->lan.addr != s->gwy.addr) || (s->lan.port != s->gwy.port)) { - print_host(&s->lan); + if (PF_ANEQ(&s->lan.addr, &s->gwy.addr, s->af) || + (s->lan.port != s->gwy.port)) { + print_host(&s->lan, s->af); if (s->direction == PF_OUT) printf(" -> "); else printf(" <- "); } - print_host(&s->gwy); + print_host(&s->gwy, s->af); if (s->direction == PF_OUT) printf(" -> "); else printf(" <- "); - print_host(&s->ext); + print_host(&s->ext, s->af); printf(" "); if (s->proto == IPPROTO_TCP) { @@ -515,7 +621,7 @@ print_rule(struct pf_rule *r) printf("return-icmp"); ic = geticmpcodebynumber(r->return_icmp >> 8, - r->return_icmp & 255); + r->return_icmp & 255, r->proto); if ((ic == NULL) || (ic->type != ICMP_UNREACH)) printf("(%u,%u) ", r->return_icmp >> 8, r->return_icmp & 255); @@ -538,6 +644,12 @@ print_rule(struct pf_rule *r) printf("quick "); if (r->ifname[0]) printf("on %s ", r->ifname); + if (r->af) { + if (r->af == AF_INET) + printf("inet "); + else + printf("inet6 "); + } if (r->proto) { struct protoent *p = getprotobynumber(r->proto); if (p != NULL) @@ -545,20 +657,20 @@ print_rule(struct pf_rule *r) else printf("proto %u ", r->proto); } - if (!r->src.addr && !r->src.mask && !r->src.port_op && !r->dst.addr && ! r->dst.mask && !r->dst.port_op) + if (PF_AZERO(&r->src.addr, AF_INET6) && + PF_AZERO(&r->src.mask, AF_INET6) && + !r->src.port_op && PF_AZERO(&r->dst.addr, AF_INET6) && + PF_AZERO(&r->dst.mask, AF_INET6) && !r->dst.port_op) printf("all "); else { printf("from "); - if (!r->src.addr && !r->src.mask) + if (PF_AZERO(&r->src.addr, AF_INET6) && + PF_AZERO(&r->src.mask, AF_INET6)) printf("any "); else { if (r->src.not) printf("! "); - print_addr(r->src.addr); - if (r->src.mask != 0xFFFFFFFF) { - printf("/"); - print_addr(r->src.mask); - } + print_addr(&r->src.addr, &r->src.mask, r->af); printf(" "); } if (r->src.port_op) @@ -567,16 +679,13 @@ print_rule(struct pf_rule *r) r->proto == IPPROTO_TCP ? "tcp" : "udp"); printf("to "); - if (!r->dst.addr && !r->dst.mask) + if (PF_AZERO(&r->dst.addr, AF_INET6) && + PF_AZERO(&r->dst.mask, AF_INET6)) printf("any "); else { if (r->dst.not) printf("! "); - print_addr(r->dst.addr); - if (r->dst.mask != 0xFFFFFFFF) { - printf("/"); - print_addr(r->dst.mask); - } + print_addr(&r->dst.addr, &r->dst.mask, r->af); printf(" "); } if (r->dst.port_op) @@ -594,7 +703,7 @@ print_rule(struct pf_rule *r) if (r->type) { struct icmptypeent *p; - p = geticmptypebynumber(r->type-1); + p = geticmptypebynumber(r->type-1, r->proto); if (p != NULL) printf("icmp-type %s ", p->name); else @@ -602,7 +711,7 @@ print_rule(struct pf_rule *r) if (r->code) { struct icmpcodeent *p; - p = geticmpcodebynumber(r->type-1, r->code-1); + p = geticmpcodebynumber(r->type-1, r->code-1, r->proto); if (p != NULL) printf("code %s ", p->name); else @@ -625,13 +734,13 @@ int parse_flags(char *s) { char *p, *q; - u_int8_t f = 0; + u_int8_t f = 0; - for (p = s; *p; p++) { + for (p = s; *p; p++) { if ((q = strchr(tcpflags, *p)) == NULL) return -1; else f |= 1 << (q - tcpflags); - } - return (f ? f : 63); + } + return (f ? f : 63); } diff --git a/sbin/pfctl/pfctl_parser.h b/sbin/pfctl/pfctl_parser.h index 19ec3c76760..67984ac96fc 100644 --- a/sbin/pfctl/pfctl_parser.h +++ b/sbin/pfctl/pfctl_parser.h @@ -1,4 +1,4 @@ -/* $OpenBSD: pfctl_parser.h,v 1.9 2001/09/06 18:05:46 jasoni Exp $ */ +/* $OpenBSD: pfctl_parser.h,v 1.10 2001/09/15 03:54:40 frantzen Exp $ */ /* * Copyright (c) 2001 Daniel Hartmeier @@ -69,9 +69,9 @@ struct icmpcodeent { u_int8_t code; }; -struct icmptypeent *geticmptypebynumber(u_int8_t); -struct icmptypeent *geticmptypebyname(char *); -struct icmpcodeent *geticmpcodebynumber(u_int8_t, u_int8_t); -struct icmpcodeent *geticmpcodebyname(u_long, char *); +struct icmptypeent *geticmptypebynumber(u_int8_t, u_int8_t); +struct icmptypeent *geticmptypebyname(char *, u_int8_t); +struct icmpcodeent *geticmpcodebynumber(u_int8_t, u_int8_t, u_int8_t); +struct icmpcodeent *geticmpcodebyname(u_long, char *, u_int8_t); #endif /* _PFCTL_PARSER_H_ */ |