diff options
-rw-r--r-- | libexec/ftp-proxy/util.c | 10 | ||||
-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 | ||||
-rw-r--r-- | share/man/man4/pf.4 | 12 | ||||
-rw-r--r-- | share/man/man5/pf.conf.5 | 35 | ||||
-rw-r--r-- | sys/net/pf.c | 1890 | ||||
-rw-r--r-- | sys/net/pf_norm.c | 59 | ||||
-rw-r--r-- | sys/net/pfvar.h | 235 | ||||
-rw-r--r-- | sys/netinet6/ip6_input.c | 16 | ||||
-rw-r--r-- | sys/netinet6/ip6_output.c | 15 |
11 files changed, 2321 insertions, 719 deletions
diff --git a/libexec/ftp-proxy/util.c b/libexec/ftp-proxy/util.c index 8c55b1d9c6d..a0b2755bf2d 100644 --- a/libexec/ftp-proxy/util.c +++ b/libexec/ftp-proxy/util.c @@ -1,4 +1,4 @@ -/* $OpenBSD: util.c,v 1.5 2001/09/05 20:40:10 beck Exp $ */ +/* $OpenBSD: util.c,v 1.6 2001/09/15 03:54:40 frantzen Exp $ */ /* * Copyright (c) 1996-2001 @@ -95,10 +95,12 @@ get_proxy_env(int connected_fd, struct sockaddr_in *real_server_sa_ptr, /* * Build up the pf natlook structure. + * Just for IPv4 right now */ memset((void *)&natlook, 0, sizeof(natlook)); - natlook.saddr = client_sa_ptr->sin_addr.s_addr; - natlook.daddr = real_server_sa_ptr->sin_addr.s_addr; + natlook.af = AF_INET; + natlook.saddr.addr32[0] = client_sa_ptr->sin_addr.s_addr; + natlook.daddr.addr32[0] = real_server_sa_ptr->sin_addr.s_addr; natlook.proto = IPPROTO_TCP; natlook.sport = client_sa_ptr->sin_port; natlook.dport = real_server_sa_ptr->sin_port; @@ -135,7 +137,7 @@ get_proxy_env(int connected_fd, struct sockaddr_in *real_server_sa_ptr, */ memset((void *)real_server_sa_ptr, 0, sizeof(struct sockaddr_in)); real_server_sa_ptr->sin_port = natlook.rdport; - real_server_sa_ptr->sin_addr.s_addr = natlook.rdaddr; + real_server_sa_ptr->sin_addr.s_addr = natlook.rdaddr.addr32[0]; real_server_sa_ptr->sin_len = sizeof(struct sockaddr_in); real_server_sa_ptr->sin_family = AF_INET; return(0); 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_ */ diff --git a/share/man/man4/pf.4 b/share/man/man4/pf.4 index 2d1baef5fb0..1edbd9a21e3 100644 --- a/share/man/man4/pf.4 +++ b/share/man/man4/pf.4 @@ -1,4 +1,4 @@ -.\" $OpenBSD: pf.4,v 1.5 2001/09/05 12:34:44 dhartmei Exp $ +.\" $OpenBSD: pf.4,v 1.6 2001/09/15 03:54:40 frantzen Exp $ .\" .\" Copyright (C) 2001, Kjell Wooding. All rights reserved. .\" @@ -37,7 +37,7 @@ .Sh DESCRIPTION The .Nm -interface is a packet filter pseudo-device for IPv4. +interface is a packet filter pseudo-device for IPv4 and IPv6. .Pp .Nm is administered using the @@ -158,10 +158,10 @@ Gets the internal packet filter statistics. Looks up a state table entry by source and destination addresses and ports. .Bd -literal struct pfioc_natlook { - u_int32_t saddr; - u_int32_t daddr; - u_int32_t rsaddr; - u_int32_t rdaddr; + struct pf_addr saddr; + struct pf_addr daddr; + struct pf_addr rsaddr; + struct pf_addr rdaddr; u_int16_t sport; u_int16_t dport; u_int16_t rsport; diff --git a/share/man/man5/pf.conf.5 b/share/man/man5/pf.conf.5 index cfd0bc37d43..7c2279e6f2b 100644 --- a/share/man/man5/pf.conf.5 +++ b/share/man/man5/pf.conf.5 @@ -1,4 +1,4 @@ -.\" $OpenBSD: pf.conf.5,v 1.13 2001/08/28 08:48:57 dhartmei Exp $ +.\" $OpenBSD: pf.conf.5,v 1.14 2001/09/15 03:54:40 frantzen Exp $ .\" .\" Copyright (c) 2001, Daniel Hartmeier .\" All rights reserved. @@ -46,16 +46,19 @@ Syntax for filter rules in BNF: .Bd -literal rule = action ( "in" | "out" ) [ "log" | "log-all" ] [ "quick" ] - [ "on" interface-name ] + [ "on" interface-name ] [ af ] [ "proto" ( proto-name | proto-number | "{" proto-list "}" ) ] hosts - [ flags ] [ icmp-type ] [ "keep-state" ] [ "modulate-state" ] + [ flags ] ( [ icmp-type ] | [ ipv6-icmp-type ] ) + [ "keep-state" ] [ "modulate-state" ] [ "no-df" ] [ "min-ttl" number ] . action = "pass" | "block" [ return ] | "scrub" . return = "return-rst" | - "return-icmp" [ "(" ( icmp-code-name | icmp-code-number ) ")" ] . + "return-icmp" [ "(" ( icmp-code-name | icmp-code-number ) ")" ] | + "return-icmp6" [ "(" ( icmp-code-name | icmp-code-number ) ")" ] . +af = "inet" | "inet6" . proto-list = ( proto-name | proto-number ) [ "," proto-list ] . hosts = "all" | @@ -73,8 +76,12 @@ binary-op = port-number ( "<>" | "><" ) port-number . flags = "flags" ( flag-set | flag-set "/" flag-set | "/" flag-set ) . flag-set = [ "F" ] [ "S" ] [ "R" ] [ "P" ] [ "A" ] [ "U" ] . -icmp-type = "icmp-type" ( icmp-type-name | icmp-type-number ) - [ "code" ( icmp-code-name | icmp-code-number ) ] . +icmp-type = "icmp-type" ( icmp-type-code | "{" icmp-list "}" ) . +ipv6-icmp-type = "ipv6-icmp-type" ( icmp-type-code | "{" icmp-list "}" ) . +icmp-type-code = ( icmp-type-name | icmp-type-number ) + [ "code" ( icmp-code-name | icmp-code-number ) ] . +icmp-list = icmp-type-code [ "," icmp-list ] . + .Ed .Sh FILTER RULES Filter rules are typically manipulated using @@ -115,6 +122,7 @@ to the sender, where applicable. .It Em scrub The packet is run through normalization/defragmentation. Scrub rules are not considered last matching rules. +IPv6 packets are not defragmented. .El .Sh LOGGING .Bl -tag -width Fl @@ -160,9 +168,12 @@ To cover both directions, two rules are needed. .Ss on <interface> The rule applies only to packets coming in on or going out through this particular interface. +.Ss <af> +The rule applies only to packets of this address family. +Supported values are inet and inet6. .Ss proto <protocol> The rule applies only to packets of this protocol. -Common protocols used here are tcp, udp and icmp. +Common protocols used here are tcp, udp, icmp and ipv6-icmp. .Ss from <source> port <source> to <dest> port <dest> The rule applies only to packets with the specified source and destination addresses/ports. @@ -215,9 +226,13 @@ rule. This is more restrictive than the previous example. If the first set is not specified, it defaults to none. All of SYN, FIN, RST and ACK must be unset. .El -.Ss icmp-type <type> code <code> -The rule only applies to ICMP packets with the specified type and code. -This parameter is only valid for rules that cover protocol icmp. +.Ss icmp-type <type> code <code> and ipv6-icmp-type <type> code <code> +The rule only applies to ICMP or ICMPV6 packets with the specified type +and code. +This parameter is only valid for rules that cover protocols icmp or +ipv6-icmp. +The protocol and the icmp type indicator (icmp-type or ipv6-icmp-type) +must match. .Sh MACROS .Em pfctl supports macro definition and expansion like: diff --git a/sys/net/pf.c b/sys/net/pf.c index f14f0bd3cda..acf11375412 100644 --- a/sys/net/pf.c +++ b/sys/net/pf.c @@ -1,4 +1,4 @@ -/* $OpenBSD: pf.c,v 1.149 2001/09/14 20:22:18 jasoni Exp $ */ +/* $OpenBSD: pf.c,v 1.150 2001/09/15 03:54:40 frantzen Exp $ */ /* * Copyright (c) 2001 Daniel Hartmeier @@ -64,6 +64,13 @@ #include "bpfilter.h" #include "pflog.h" +#ifdef INET6 +#include <netinet/ip6.h> +#include <netinet/in_pcb.h> +#include <netinet/icmp6.h> +#endif /* INET6 */ + + #define DPFPRINTF(n, x) if (pf_status.debug >= (n)) printf x /* @@ -85,6 +92,15 @@ struct pf_port_node { }; LIST_HEAD(pf_port_list, pf_port_node); +/* structure for ipsec and ipv6 option header template */ +struct _opt6 { + u_int8_t opt6_nxt; /* next header */ + u_int8_t opt6_hlen; /* header extension length */ + u_int16_t _pad; + u_int32_t ah_spi; /* security parameter index + for authentication header */ +}; + /* * Global variables */ @@ -151,6 +167,10 @@ struct pool pf_rdr_pl, pf_state_pl, pf_binat_pl; int pf_tree_key_compare(struct pf_tree_key *, struct pf_tree_key *); +int pf_compare_addr(struct pf_addr *, struct pf_addr *, + u_int8_t); +void pf_addrcpy(struct pf_addr *, struct pf_addr *, + u_int8_t); int pf_compare_rules(struct pf_rule *, struct pf_rule *); int pf_compare_nats(struct pf_nat *, struct pf_nat *); @@ -166,7 +186,7 @@ struct pf_tree_node *pf_tree_search(struct pf_tree_node *, void pf_insert_state(struct pf_state *); void pf_purge_expired_states(void); -void pf_print_host(u_int32_t, u_int16_t); +void pf_print_host(struct pf_addr *, u_int16_t, u_int8_t); void pf_print_state(struct pf_state *); void pf_print_flags(u_int8_t); @@ -177,41 +197,48 @@ int pfioctl(dev_t, u_long, caddr_t, int, struct proc *); u_int16_t pf_cksum_fixup(u_int16_t, u_int16_t, u_int16_t, u_int8_t); -void pf_change_ap(u_int32_t *, u_int16_t *, u_int16_t *, - u_int16_t *, u_int32_t, u_int16_t, u_int8_t); +void pf_change_ap(struct pf_addr *, u_int16_t *, + u_int16_t *, u_int16_t *, struct pf_addr *, + u_int16_t, u_int8_t, int); void pf_change_a(u_int32_t *, u_int16_t *, u_int32_t, u_int8_t); -void pf_change_icmp(u_int32_t *, u_int16_t *, u_int32_t *, - u_int32_t, u_int16_t, u_int16_t *, u_int16_t *, - u_int16_t *, u_int16_t *, u_int8_t); -void pf_send_reset(struct ip *, int, struct tcphdr *); -void pf_send_icmp(struct mbuf *, u_int8_t, u_int8_t); +#ifdef INET6 +void pf_change_a6(struct pf_addr *, u_int16_t *, + struct pf_addr *, u_int8_t); +#endif /* INET6 */ +void pf_change_icmp(struct pf_addr *, u_int16_t *, + struct pf_addr *, struct pf_addr *, u_int16_t, + u_int16_t *, u_int16_t *, u_int16_t *, + u_int16_t *, u_int8_t, int); +void pf_send_reset(int, struct tcphdr *, + struct pf_pdesc *, int); +void pf_send_icmp(struct mbuf *, u_int8_t, u_int8_t, int); u_int16_t pf_map_port_range(struct pf_rdr *, u_int16_t); -struct pf_nat *pf_get_nat(struct ifnet *, u_int8_t, u_int32_t, - u_int32_t); -struct pf_binat *pf_get_binat(int direction, struct ifnet *, u_int8_t, - u_int32_t, u_int32_t); -struct pf_rdr *pf_get_rdr(struct ifnet *, u_int8_t, u_int32_t, - u_int32_t, u_int16_t); -int pf_test_tcp(int, struct ifnet *, struct mbuf *, - int, int, struct ip *, struct tcphdr *); -int pf_test_udp(int, struct ifnet *, struct mbuf *, - int, int, struct ip *, struct udphdr *); +struct pf_nat *pf_get_nat(struct ifnet *, u_int8_t, + struct pf_addr *, struct pf_addr *, int); +struct pf_binat *pf_get_binat(int, struct ifnet *, u_int8_t, + struct pf_addr *, struct pf_addr *, int); +struct pf_rdr *pf_get_rdr(struct ifnet *, u_int8_t, + struct pf_addr *, struct pf_addr *, u_int16_t, int); +int pf_test_tcp(int, struct ifnet *, struct mbuf *, int, + int, void *, struct pf_pdesc *); +int pf_test_udp(int, struct ifnet *, struct mbuf *, int, + int, void *, struct pf_pdesc *); int pf_test_icmp(int, struct ifnet *, struct mbuf *, - int, int, struct ip *, struct icmp *); + int, int, void *, struct pf_pdesc *); int pf_test_other(int, struct ifnet *, struct mbuf *, - struct ip *); + void *, struct pf_pdesc *); int pf_test_state_tcp(struct pf_state **, int, struct ifnet *, struct mbuf *, int, int, - struct ip *, struct tcphdr *); + void *, struct pf_pdesc *); int pf_test_state_udp(struct pf_state **, int, struct ifnet *, struct mbuf *, int, int, - struct ip *, struct udphdr *); + void *, struct pf_pdesc *); int pf_test_state_icmp(struct pf_state **, int, struct ifnet *, struct mbuf *, int, int, - struct ip *, struct icmp *); + void *, struct pf_pdesc *); void *pf_pull_hdr(struct mbuf *, int, void *, int, - u_short *, u_short *); + u_short *, u_short *, int); void pf_calc_skip_steps(struct pf_rulequeue *); int pf_get_sport(u_int8_t, u_int16_t, u_int16_t, @@ -220,23 +247,33 @@ void pf_put_sport(u_int8_t, u_int16_t); int pf_add_sport(struct pf_port_list *, u_int16_t); int pf_chk_sport(struct pf_port_list *, u_int16_t); int pf_normalize_tcp(int, struct ifnet *, struct mbuf *, - int, int, struct ip *, struct tcphdr *); + int, int, void *, struct pf_pdesc *); + #if NPFLOG > 0 #define PFLOG_PACKET(x,a,b,c,d,e) \ do { \ - HTONS((x)->ip_len); \ - HTONS((x)->ip_off); \ - pflog_packet(a,b,c,d,e); \ - NTOHS((x)->ip_len); \ - NTOHS((x)->ip_off); \ + if (b == AF_INET) { \ + HTONS(((struct ip *)x)->ip_len); \ + HTONS(((struct ip *)x)->ip_off); \ + pflog_packet(a,b,c,d,e); \ + NTOHS(((struct ip *)x)->ip_len); \ + NTOHS(((struct ip *)x)->ip_off); \ + } else { \ + pflog_packet(a,b,c,d,e); \ + } \ } while (0) #else #define PFLOG_PACKET(x,a,b,c,d,e) ((void)0) #endif #define STATE_TRANSLATE(s) \ - ((s)->lan.addr != (s)->gwy.addr || (s)->lan.port != (s)->gwy.port) + (s)->lan.addr.addr32[0] != (s)->gwy.addr.addr32[0] || \ + ((s)->af == AF_INET6 && \ + ((s)->lan.addr.addr32[1] != (s)->gwy.addr.addr32[1] || \ + (s)->lan.addr.addr32[2] != (s)->gwy.addr.addr32[2] || \ + (s)->lan.addr.addr32[3] != (s)->gwy.addr.addr32[3])) || \ + (s)->lan.port != (s)->gwy.port int pf_tree_key_compare(struct pf_tree_key *a, struct pf_tree_key *b) @@ -249,14 +286,59 @@ pf_tree_key_compare(struct pf_tree_key *a, struct pf_tree_key *b) */ if ((diff = a->proto - b->proto) != 0) return (diff); - if (a->addr[0].s_addr > b->addr[0].s_addr) - return 1; - if (a->addr[0].s_addr < b->addr[0].s_addr) - return -1; - if (a->addr[1].s_addr > b->addr[1].s_addr) - return 1; - if (a->addr[1].s_addr < b->addr[1].s_addr) - return -1; + if ((diff = a->af - b->af) != 0) + return (diff); + switch (a->af) { +#ifdef INET + case AF_INET: + if (a->addr[0].addr32[0] > b->addr[0].addr32[0]) + return 1; + if (a->addr[0].addr32[0] < b->addr[0].addr32[0]) + return -1; + if (a->addr[1].addr32[0] > b->addr[1].addr32[0]) + return 1; + if (a->addr[1].addr32[0] < b->addr[1].addr32[0]) + return -1; + break; +#endif /* INET */ +#ifdef INET6 + case AF_INET6: + if (a->addr[0].addr32[0] > b->addr[0].addr32[0]) + return 1; + if (a->addr[0].addr32[0] < b->addr[0].addr32[0]) + return -1; + if (a->addr[0].addr32[1] > b->addr[0].addr32[1]) + return 1; + if (a->addr[0].addr32[1] < b->addr[0].addr32[1]) + return -1; + if (a->addr[0].addr32[2] > b->addr[0].addr32[2]) + return 1; + if (a->addr[0].addr32[2] < b->addr[0].addr32[2]) + return -1; + if (a->addr[0].addr32[3] > b->addr[0].addr32[3]) + return 1; + if (a->addr[0].addr32[3] < b->addr[0].addr32[3]) + return -1; + if (a->addr[1].addr32[0] > b->addr[1].addr32[0]) + return 1; + if (a->addr[1].addr32[0] < b->addr[1].addr32[0]) + return -1; + if (a->addr[1].addr32[1] > b->addr[1].addr32[1]) + return 1; + if (a->addr[1].addr32[1] < b->addr[1].addr32[1]) + return -1; + if (a->addr[1].addr32[2] > b->addr[1].addr32[2]) + return 1; + if (a->addr[1].addr32[2] < b->addr[1].addr32[2]) + return -1; + if (a->addr[1].addr32[3] > b->addr[1].addr32[3]) + return 1; + if (a->addr[1].addr32[3] < b->addr[1].addr32[3]) + return -1; + break; +#endif /* INET6 */ + } + if ((diff = a->port[0] - b->port[0]) != 0) return (diff); if ((diff = a->port[1] - b->port[1]) != 0) @@ -265,6 +347,26 @@ pf_tree_key_compare(struct pf_tree_key *a, struct pf_tree_key *b) return (0); } +#ifdef INET6 +void +pf_addrcpy(struct pf_addr *dst, struct pf_addr *src, u_int8_t af) +{ + switch(af) { +#ifdef INET + case AF_INET: + dst->addr32[0] = src->addr32[0]; + break; +#endif /* INET */ + case AF_INET6: + dst->addr32[0] = src->addr32[0]; + dst->addr32[1] = src->addr32[1]; + dst->addr32[2] = src->addr32[2]; + dst->addr32[3] = src->addr32[3]; + break; + } +} +#endif + int pf_compare_rules(struct pf_rule *a, struct pf_rule *b) { @@ -274,6 +376,7 @@ pf_compare_rules(struct pf_rule *a, struct pf_rule *b) a->log != b->log || a->quick != b->quick || a->keep_state != b->keep_state || + a->af != b->af || a->proto != b->proto || a->type != b->type || a->code != b->code || @@ -294,16 +397,22 @@ pf_compare_rules(struct pf_rule *a, struct pf_rule *b) int pf_compare_nats(struct pf_nat *a, struct pf_nat *b) { - if (a->saddr != b->saddr || - a->smask != b->smask || - a->daddr != b->daddr || - a->dmask != b->dmask || - a->raddr != b->raddr || - a->proto != b->proto || + if (a->proto != b->proto || + a->af != b->af || a->snot != b->snot || a->dnot != b->dnot || a->ifnot != b->ifnot) return (1); + if (PF_ANEQ(&a->saddr, &b->saddr, a->af)) + return (1); + if (PF_ANEQ(&a->smask, &b->smask, a->af)) + return (1); + if (PF_ANEQ(&a->daddr, &b->daddr, a->af)) + return (1); + if (PF_ANEQ(&a->dmask, &b->dmask, a->af)) + return (1); + if (PF_ANEQ(&a->raddr, &b->raddr, a->af)) + return (1); if (strcmp(a->ifname, b->ifname)) return (1); return (0); @@ -312,12 +421,17 @@ pf_compare_nats(struct pf_nat *a, struct pf_nat *b) int pf_compare_binats(struct pf_binat *a, struct pf_binat *b) { - if (a->saddr != b->saddr || - a->daddr != b->daddr || - a->dmask != b->dmask || - a->raddr != b->raddr || - a->proto != b->proto || - a->dnot != b->dnot) + if (PF_ANEQ(&a->saddr, &b->saddr, a->af)) + return (1); + if (PF_ANEQ(&a->daddr, &b->daddr, a->af)) + return (1); + if (PF_ANEQ(&a->dmask, &b->dmask, a->af)) + return (1); + if (PF_ANEQ(&a->raddr, &b->raddr, a->af)) + return (1); + if (a->proto != b->proto || + a->dnot != b->dnot || + a->af != b->af) return (1); if (strcmp(a->ifname, b->ifname)) return (1); @@ -327,20 +441,26 @@ pf_compare_binats(struct pf_binat *a, struct pf_binat *b) int pf_compare_rdrs(struct pf_rdr *a, struct pf_rdr *b) { - if (a->saddr != b->saddr || - a->smask != b->smask || - a->daddr != b->daddr || - a->dmask != b->dmask || - a->raddr != b->raddr || - a->dport != b->dport || + if (a->dport != b->dport || a->dport2 != b->dport2 || a->rport != b->rport || a->proto != b->proto || + a->af != b->af || a->snot != b->snot || a->dnot != b->dnot || a->ifnot != b->ifnot || a->opts != b->opts) return (1); + if (PF_ANEQ(&a->saddr, &b->saddr, a->af)) + return (1); + if (PF_ANEQ(&a->smask, &b->smask, a->af)) + return (1); + if (PF_ANEQ(&a->daddr, &b->daddr, a->af)) + return (1); + if (PF_ANEQ(&a->dmask, &b->dmask, a->af)) + return (1); + if (PF_ANEQ(&a->raddr, &b->raddr, a->af)) + return (1); if (strcmp(a->ifname, b->ifname)) return (1); return (0); @@ -612,10 +732,11 @@ pf_insert_state(struct pf_state *state) struct pf_tree_key key; struct pf_state *s; + key.af = state->af; key.proto = state->proto; - key.addr[0].s_addr = state->lan.addr; + PF_ACPY(&key.addr[0], &state->lan.addr, state->af); key.port[0] = state->lan.port; - key.addr[1].s_addr = state->ext.addr; + PF_ACPY(&key.addr[1], &state->ext.addr, state->af); key.port[1] = state->ext.port; /* sanity checks can be removed later, should never occur */ if ((s = pf_find_state(tree_lan_ext, &key)) != NULL) { @@ -623,9 +744,9 @@ pf_insert_state(struct pf_state *state) printf("pf: ERROR! insert invalid\n"); printf(" key already in tree_lan_ext\n"); printf(" key: proto = %u, lan = ", state->proto); - pf_print_host(key.addr[0].s_addr, key.port[0]); + pf_print_host(&key.addr[0], key.port[0], key.af); printf(", ext = "); - pf_print_host(key.addr[1].s_addr, key.port[1]); + pf_print_host(&key.addr[1], key.port[1], key.af); printf("\n state: "); pf_print_state(s); printf("\n"); @@ -637,19 +758,20 @@ pf_insert_state(struct pf_state *state) ("pf: ERROR! insert failed\n")); } + key.af = state->af; key.proto = state->proto; - key.addr[0].s_addr = state->ext.addr; + PF_ACPY(&key.addr[0], &state->ext.addr, state->af); key.port[0] = state->ext.port; - key.addr[1].s_addr = state->gwy.addr; + PF_ACPY(&key.addr[1], &state->gwy.addr, state->af); key.port[1] = state->gwy.port; if ((s = pf_find_state(tree_ext_gwy, &key)) != NULL) { if (pf_status.debug >= PF_DEBUG_URGENT) { printf("pf: ERROR! insert invalid\n"); printf(" key already in tree_ext_gwy\n"); printf(" key: proto = %u, ext = ", state->proto); - pf_print_host(key.addr[0].s_addr, key.port[0]); + pf_print_host(&key.addr[0], key.port[0], key.af); printf(", gwy = "); - pf_print_host(key.addr[1].s_addr, key.port[1]); + pf_print_host(&key.addr[1], key.port[1], key.af); printf("\n state: "); pf_print_state(s); printf("\n"); @@ -673,10 +795,13 @@ pf_purge_expired_states(void) cur = pf_tree_first(tree_ext_gwy); while (cur != NULL) { if (cur->state->expire <= pftv.tv_sec) { + key.af = cur->state->af; key.proto = cur->state->proto; - key.addr[0].s_addr = cur->state->lan.addr; + PF_ACPY(&key.addr[0], &cur->state->lan.addr, + cur->state->af); key.port[0] = cur->state->lan.port; - key.addr[1].s_addr = cur->state->ext.addr; + PF_ACPY(&key.addr[1], &cur->state->ext.addr, + cur->state->af); key.port[1] = cur->state->ext.port; /* remove state from second tree */ if (pf_find_state(tree_lan_ext, &key) != cur->state) @@ -716,12 +841,62 @@ pf_purge_expired_states(void) } void -pf_print_host(u_int32_t a, u_int16_t p) +pf_print_host(struct pf_addr *addr, u_int16_t p, u_int8_t af) { - a = ntohl(a); - p = ntohs(p); - printf("%u.%u.%u.%u:%u", (a>>24)&255, (a>>16)&255, (a>>8)&255, a&255, - p); + switch(af) { +#ifdef INET + case AF_INET: { + u_int32_t a = ntohl(addr->addr32[0]); + p = ntohs(p); + printf("%u.%u.%u.%u:%u", (a>>24)&255, (a>>16)&255, + (a>>8)&255, a&255, p); + break; + } +#endif /* INET */ +#ifdef INET6 + case AF_INET6: { + u_int16_t b; + u_int8_t i, curstart = 255, curend = 0, + maxstart = 0, maxend = 0; + for (i = 0; i < 8; i++) { + if (!addr->addr16[i]) { + if (curstart == 255) + curstart = i; + else + curend = i; + } else { + if (curstart) { + if ((curend - curstart) > + (maxend - maxstart)) { + maxstart = curstart; + maxend = curend; + curstart = 255; + } + } + } + } + for (i = 0; i < 8; i++) { + if (i >= maxstart && i <= maxend) { + if (maxend != 7) { + if (i == maxstart) + printf(":"); + } else { + if (i == maxend) + printf(":"); + } + } else { + b = ntohs(addr->addr16[i]); + printf("%x", b); + if (i < 7) + printf(":"); + } + } + p = ntohs(p); + printf("[%u]", p); + break; + } +#endif /* INET6 */ + } } void @@ -741,11 +916,11 @@ pf_print_state(struct pf_state *s) printf("%u ", s->proto); break; } - pf_print_host(s->lan.addr, s->lan.port); + pf_print_host(&s->lan.addr, s->lan.port, s->af); printf(" "); - pf_print_host(s->gwy.addr, s->gwy.port); + pf_print_host(&s->gwy.addr, s->gwy.port, s->af); printf(" "); - pf_print_host(s->ext.addr, s->ext.port); + pf_print_host(&s->ext.addr, s->ext.port, s->af); printf(" [lo=%lu high=%lu win=%u modulator=%u]", s->src.seqlo, s->src.seqhi, s->src.max_win, s->src.seqdiff); printf(" [lo=%lu high=%lu win=%u modulator=%u]", s->dst.seqlo, @@ -914,6 +1089,18 @@ pfioctl(dev_t dev, u_long cmd, caddr_t addr, int flags, struct proc *p) break; } bcopy(&pr->rule, rule, sizeof(struct pf_rule)); +#ifndef INET + if (rule->af == AF_INET) { + error = EAFNOSUPPORT; + break; + } +#endif /* INET */ +#ifndef INET6 + if (rule->af == AF_INET6) { + error = EAFNOSUPPORT; + break; + } +#endif /* INET6 */ tail = TAILQ_LAST(pf_rules_inactive, pf_rulequeue); if (tail) rule->nr = tail->nr + 1; @@ -1023,6 +1210,18 @@ pfioctl(dev_t dev, u_long cmd, caddr_t addr, int flags, struct proc *p) break; } bcopy(&pcr->newrule, newrule, sizeof(struct pf_rule)); +#ifndef INET + if (newrule->af == AF_INET) { + error = EAFNOSUPPORT; + break; + } +#endif /* INET */ +#ifndef INET6 + if (newrule->af == AF_INET6) { + error = EAFNOSUPPORT; + break; + } +#endif /* INET6 */ newrule->ifp = NULL; if (newrule->ifname[0]) { newrule->ifp = ifunit(newrule->ifname); @@ -1111,6 +1310,18 @@ pfioctl(dev_t dev, u_long cmd, caddr_t addr, int flags, struct proc *p) break; } bcopy(&pn->nat, nat, sizeof(struct pf_nat)); +#ifndef INET + if (nat->af == AF_INET) { + error = EAFNOSUPPORT; + break; + } +#endif /* INET */ +#ifndef INET6 + if (nat->af == AF_INET6) { + error = EAFNOSUPPORT; + break; + } +#endif /* INET6 */ if (nat->ifname[0]) { nat->ifp = ifunit(nat->ifname); if (nat->ifp == NULL) { @@ -1206,6 +1417,18 @@ pfioctl(dev_t dev, u_long cmd, caddr_t addr, int flags, struct proc *p) break; } bcopy(&pcn->newnat, newnat, sizeof(struct pf_nat)); +#ifndef INET + if (newnat->af == AF_INET) { + error = EAFNOSUPPORT; + break; + } +#endif /* INET */ +#ifndef INET6 + if (newnat->af == AF_INET6) { + error = EAFNOSUPPORT; + break; + } +#endif /* INET6 */ newnat->ifp = NULL; if (newnat->ifname[0]) { newnat->ifp = ifunit(newnat->ifname); @@ -1281,6 +1504,18 @@ pfioctl(dev_t dev, u_long cmd, caddr_t addr, int flags, struct proc *p) break; } bcopy(&pb->binat, binat, sizeof(struct pf_binat)); +#ifndef INET + if (binat->af == AF_INET) { + error = EAFNOSUPPORT; + break; + } +#endif /* INET */ +#ifndef INET6 + if (binat->af == AF_INET6) { + error = EAFNOSUPPORT; + break; + } +#endif /* INET6 */ if (binat->ifname[0]) { binat->ifp = ifunit(binat->ifname); if (binat->ifp == NULL) { @@ -1375,8 +1610,20 @@ pfioctl(dev_t dev, u_long cmd, caddr_t addr, int flags, struct proc *p) error = ENOMEM; break; } - bcopy(&pcn->newbinat, newbinat, - sizeof(struct pf_binat)); + bcopy(&pcn->newbinat, newbinat, + sizeof(struct pf_binat)); +#ifndef INET + if (newbinat->af == AF_INET) { + error = EAFNOSUPPORT; + break; + } +#endif /* INET */ +#ifndef INET6 + if (newbinat->af == AF_INET6) { + error = EAFNOSUPPORT; + break; + } +#endif /* INET6 */ newbinat->ifp = NULL; if (newbinat->ifname[0]) { newbinat->ifp = ifunit(newbinat->ifname); @@ -1453,6 +1700,18 @@ pfioctl(dev_t dev, u_long cmd, caddr_t addr, int flags, struct proc *p) break; } bcopy(&pr->rdr, rdr, sizeof(struct pf_rdr)); +#ifndef INET + if (rdr->af == AF_INET) { + error = EAFNOSUPPORT; + break; + } +#endif /* INET */ +#ifndef INET6 + if (rdr->af == AF_INET6) { + error = EAFNOSUPPORT; + break; + } +#endif /* INET6 */ if (rdr->ifname[0]) { rdr->ifp = ifunit(rdr->ifname); if (rdr->ifp == NULL) { @@ -1548,6 +1807,18 @@ pfioctl(dev_t dev, u_long cmd, caddr_t addr, int flags, struct proc *p) break; } bcopy(&pcn->newrdr, newrdr, sizeof(struct pf_rdr)); +#ifndef INET + if (newrdr->af == AF_INET) { + error = EAFNOSUPPORT; + break; + } +#endif /* INET */ +#ifndef INET6 + if (newrdr->af == AF_INET6) { + error = EAFNOSUPPORT; + break; + } +#endif /* INET6 */ newrdr->ifp = NULL; if (newrdr->ifname[0]) { newrdr->ifp = ifunit(newrdr->ifname); @@ -1714,6 +1985,7 @@ pfioctl(dev_t dev, u_long cmd, caddr_t addr, int flags, struct proc *p) struct pf_tree_key key; int direction = pnl->direction; + key.af = pnl->af; key.proto = pnl->proto; /* @@ -1721,12 +1993,14 @@ pfioctl(dev_t dev, u_long cmd, caddr_t addr, int flags, struct proc *p) * the lookup so we ask for what happens with the return * traffic, enabling us to find it in the state tree. */ - key.addr[1].s_addr = pnl->saddr; + PF_ACPY(&key.addr[1], &pnl->saddr, pnl->af); key.port[1] = pnl->sport; - key.addr[0].s_addr = pnl->daddr; + PF_ACPY(&key.addr[0], &pnl->daddr, pnl->af); key.port[0] = pnl->dport; - if (!pnl->proto || !pnl->saddr || !pnl->daddr || + if (!pnl->proto || + !PF_AZERO(&pnl->saddr, pnl->af) || + !PF_AZERO(&pnl->daddr, pnl->af) || !pnl->dport || !pnl->sport) error = EINVAL; else { @@ -1737,14 +2011,18 @@ pfioctl(dev_t dev, u_long cmd, caddr_t addr, int flags, struct proc *p) st = pf_find_state(tree_lan_ext, &key); if (st != NULL) { if (direction == PF_IN) { - pnl->rsaddr = st->lan.addr; + PF_ACPY(&pnl->rsaddr, &st->lan.addr, + st->af); pnl->rsport = st->lan.port; - pnl->rdaddr = pnl->daddr; + PF_ACPY(&pnl->rdaddr, &pnl->daddr, + pnl->af); pnl->rdport = pnl->dport; } else { - pnl->rdaddr = st->gwy.addr; + PF_ACPY(&pnl->rdaddr, &st->gwy.addr, + st->af); pnl->rdport = st->gwy.port; - pnl->rsaddr = pnl->saddr; + PF_ACPY(&pnl->rsaddr, &pnl->saddr, + pnl->af); pnl->rsport = pnl->sport; } } else @@ -1821,20 +2099,21 @@ pf_calc_skip_steps(struct pf_rulequeue *rules) s = TAILQ_NEXT(r, entries); while (a && s != NULL) { PF_CALC_SKIP_STEP(0, s->ifp == r->ifp); - PF_CALC_SKIP_STEP(1, s->proto == r->proto); - PF_CALC_SKIP_STEP(2, - s->src.addr == r->src.addr && - s->src.mask == r->src.mask && - s->src.not == r->src.not); + PF_CALC_SKIP_STEP(1, s->af == r->af); + PF_CALC_SKIP_STEP(2, s->proto == r->proto); PF_CALC_SKIP_STEP(3, - s->src.port[0] == r->src.port[0] && + PF_AEQ(&s->src.addr, &r->src.addr, r->af) && + PF_AEQ(&s->src.mask, &r->src.mask, r->af) && + s->src.not == r->src.not); + PF_CALC_SKIP_STEP(4, + s->src.port[0] == r->src.port[0] && s->src.port[1] == r->src.port[1] && s->src.port_op == r->src.port_op); - PF_CALC_SKIP_STEP(4, - s->dst.addr == r->dst.addr && - s->dst.mask == r->dst.mask && - s->dst.not == r->dst.not); PF_CALC_SKIP_STEP(5, + PF_AEQ(&s->dst.addr, &r->dst.addr, r->af) && + PF_AEQ(&s->dst.mask, &r->dst.mask, r->af) && + s->dst.not == r->dst.not); + PF_CALC_SKIP_STEP(6, s->dst.port[0] == r->dst.port[0] && s->dst.port[1] == r->dst.port[1] && s->dst.port_op == r->dst.port_op); @@ -1860,18 +2139,47 @@ pf_cksum_fixup(u_int16_t cksum, u_int16_t old, u_int16_t new, u_int8_t udp) } void -pf_change_ap(u_int32_t *a, u_int16_t *p, u_int16_t *ic, u_int16_t *pc, - u_int32_t an, u_int16_t pn, u_int8_t u) +pf_change_ap(struct pf_addr *a, u_int16_t *p, u_int16_t *ic, u_int16_t *pc, + struct pf_addr *an, u_int16_t pn, u_int8_t u, int af) { - u_int32_t ao = *a; + struct pf_addr ao; u_int16_t po = *p; - *a = an; - *ic = pf_cksum_fixup(pf_cksum_fixup(*ic, ao / 65536, - an / 65536, 0), ao % 65536, an % 65536, 0); + PF_ACPY(&ao, a, af); + PF_ACPY(a, an, af); + *p = pn; - *pc = pf_cksum_fixup(pf_cksum_fixup(pf_cksum_fixup(*pc, ao / 65536, - an / 65536, u), ao % 65536, an % 65536, u), po, pn, u); + + switch (af) { +#ifdef INET + case AF_INET: + *ic = pf_cksum_fixup(pf_cksum_fixup(*ic, + ao.addr16[0], an->addr16[0], 0), + ao.addr16[1], an->addr16[1], 0); + *p = pn; + *pc = pf_cksum_fixup(pf_cksum_fixup(pf_cksum_fixup(*pc, + ao.addr16[0], an->addr16[0], u), + ao.addr16[1], an->addr16[1], u), + po, pn, u); + break; +#endif /* INET */ +#ifdef INET6 + case AF_INET6: + *pc = pf_cksum_fixup(pf_cksum_fixup(pf_cksum_fixup( + pf_cksum_fixup(pf_cksum_fixup(pf_cksum_fixup( + pf_cksum_fixup(pf_cksum_fixup(pf_cksum_fixup(*pc, + ao.addr16[0], an->addr16[0], u), + ao.addr16[1], an->addr16[1], u), + ao.addr16[2], an->addr16[2], u), + ao.addr16[3], an->addr16[3], u), + ao.addr16[4], an->addr16[4], u), + ao.addr16[5], an->addr16[5], u), + ao.addr16[6], an->addr16[6], u), + ao.addr16[7], an->addr16[7], u), + po, pn, u); + break; +#endif /* INET6 */ + } } void @@ -1881,17 +2189,44 @@ pf_change_a(u_int32_t *a, u_int16_t *c, u_int32_t an, u_int8_t u) *a = an; *c = pf_cksum_fixup(pf_cksum_fixup(*c, ao / 65536, an / 65536, u), - ao % 65536, an % 65536, u); + ao % 65536, an % 65536, u); } +#ifdef INET6 void -pf_change_icmp(u_int32_t *ia, u_int16_t *ip, u_int32_t *oa, u_int32_t na, - u_int16_t np, u_int16_t *pc, u_int16_t *h2c, u_int16_t *ic, u_int16_t *hc, - u_int8_t u) +pf_change_a6(struct pf_addr *a, u_int16_t *c, struct pf_addr *an, u_int8_t u) { - u_int32_t oia = *ia, ooa = *oa, opc, oh2c = *h2c; + struct pf_addr ao; + + PF_ACPY(&ao, a, AF_INET6); + PF_ACPY(a, an, AF_INET6); + + *c = pf_cksum_fixup(pf_cksum_fixup(pf_cksum_fixup( + pf_cksum_fixup(pf_cksum_fixup(pf_cksum_fixup( + pf_cksum_fixup(pf_cksum_fixup(*c, + ao.addr16[0], an->addr16[0], u), + ao.addr16[1], an->addr16[1], u), + ao.addr16[2], an->addr16[2], u), + ao.addr16[3], an->addr16[3], u), + ao.addr16[4], an->addr16[4], u), + ao.addr16[5], an->addr16[5], u), + ao.addr16[6], an->addr16[6], u), + ao.addr16[7], an->addr16[7], u); +} +#endif /* INET6 */ + +void +pf_change_icmp(struct pf_addr *ia, u_int16_t *ip, struct pf_addr *oa, + struct pf_addr *na, u_int16_t np, u_int16_t *pc, u_int16_t *h2c, + u_int16_t *ic, u_int16_t *hc, u_int8_t u, int af) +{ + struct pf_addr oia, ooa; + u_int32_t opc, oh2c = *h2c; u_int16_t oip = *ip; + PF_ACPY(&oia, ia, af); + PF_ACPY(&ooa, oa, af); + if (pc != NULL) opc = *pc; /* Change inner protocol port, fix inner protocol checksum. */ @@ -1901,28 +2236,91 @@ pf_change_icmp(u_int32_t *ia, u_int16_t *ip, u_int32_t *oa, u_int32_t na, *ic = pf_cksum_fixup(*ic, oip, *ip, 0); if (pc != NULL) *ic = pf_cksum_fixup(*ic, opc, *pc, 0); - /* Change inner ip address, fix inner ip checksum and icmp checksum. */ - *ia = na; - *h2c = pf_cksum_fixup(pf_cksum_fixup(*h2c, oia / 65536, *ia / 65536, 0), - oia % 65536, *ia % 65536, 0); - *ic = pf_cksum_fixup(pf_cksum_fixup(*ic, oia / 65536, *ia / 65536, 0), - oia % 65536, *ia % 65536, 0); + PF_ACPY(ia, na, af); + /* Change inner ip address, fix inner ipv4 checksum and icmp checksum. */ + switch (af) { +#ifdef INET + case AF_INET: + *h2c = pf_cksum_fixup(pf_cksum_fixup(*h2c, + oia.addr16[0], ia->addr16[0], 0), + oia.addr16[1], ia->addr16[1], 0); + *ic = pf_cksum_fixup(pf_cksum_fixup(*ic, + oia.addr16[0], ia->addr16[0], 0), + oia.addr16[1], ia->addr16[1], 0); + break; +#endif /* INET */ +#ifdef INET6 + case AF_INET6: + *ic = pf_cksum_fixup(pf_cksum_fixup(pf_cksum_fixup( + pf_cksum_fixup(pf_cksum_fixup(pf_cksum_fixup( + pf_cksum_fixup(pf_cksum_fixup(*ic, + oia.addr16[0], ia->addr16[0], u), + oia.addr16[1], ia->addr16[1], u), + oia.addr16[2], ia->addr16[2], u), + oia.addr16[3], ia->addr16[3], u), + oia.addr16[4], ia->addr16[4], u), + oia.addr16[5], ia->addr16[5], u), + oia.addr16[6], ia->addr16[6], u), + oia.addr16[7], ia->addr16[7], u); + break; +#endif /* INET6 */ + } *ic = pf_cksum_fixup(*ic, oh2c, *h2c, 0); - /* Change outer ip address, fix outer ip checksum. */ - *oa = na; - *hc = pf_cksum_fixup(pf_cksum_fixup(*hc, ooa / 65536, *oa / 65536, 0), - ooa % 65536, *oa % 65536, 0); + /* Change outer ip address, fix outer ipv4 or icmpv6 checksum. */ + PF_ACPY(oa, na, af); + switch (af) { +#ifdef INET + case AF_INET: + *hc = pf_cksum_fixup(pf_cksum_fixup(*hc, + ooa.addr16[0], oa->addr16[0], 0), + ooa.addr16[1], oa->addr16[1], 0); + break; +#endif /* INET */ +#ifdef INET6 + case AF_INET6: + *ic = pf_cksum_fixup(pf_cksum_fixup(pf_cksum_fixup( + pf_cksum_fixup(pf_cksum_fixup(pf_cksum_fixup( + pf_cksum_fixup(pf_cksum_fixup(*ic, + ooa.addr16[0], oa->addr16[0], u), + ooa.addr16[1], oa->addr16[1], u), + ooa.addr16[2], oa->addr16[2], u), + ooa.addr16[3], oa->addr16[3], u), + ooa.addr16[4], oa->addr16[4], u), + ooa.addr16[5], oa->addr16[5], u), + ooa.addr16[6], oa->addr16[6], u), + ooa.addr16[7], oa->addr16[7], u); + break; +#endif /* INET6 */ + } } void -pf_send_reset(struct ip *h, int off, struct tcphdr *th) +pf_send_reset(int off, struct tcphdr *th, struct pf_pdesc *pd, int af) { struct mbuf *m; struct m_tag *mtag; - int len = sizeof(struct ip) + sizeof(struct tcphdr); + int len; +#ifdef INET struct ip *h2; +#endif /* INET */ +#ifdef INET6 + struct ip6_hdr *h2_6; +#endif /* INET6 */ struct tcphdr *th2; + switch (af) { +#ifdef INET + case AF_INET: + len = sizeof(struct ip) + sizeof(struct tcphdr); + break; +#endif /* INET */ +#ifdef INET6 + case AF_INET6: + len = sizeof(struct ip6_hdr) + sizeof(struct tcphdr); + break; +#endif /* INET6 */ + } + /* don't reply to RST packets */ if (th->th_flags & TH_RST) return; @@ -1941,23 +2339,43 @@ pf_send_reset(struct ip *h, int off, struct tcphdr *th) m->m_pkthdr.len = m->m_len = len; m->m_pkthdr.rcvif = NULL; bzero(m->m_data, len); - h2 = mtod(m, struct ip *); - - /* IP header fields included in the TCP checksum */ - h2->ip_p = IPPROTO_TCP; - h2->ip_len = htons(sizeof(*th2)); - h2->ip_src.s_addr = h->ip_dst.s_addr; - h2->ip_dst.s_addr = h->ip_src.s_addr; + switch (af) { +#ifdef INET + case AF_INET: + h2 = mtod(m, struct ip *); + + /* IP header fields included in the TCP checksum */ + h2->ip_p = IPPROTO_TCP; + h2->ip_len = htons(sizeof(*th2)); + h2->ip_src.s_addr = pd->dst->v4.s_addr; + h2->ip_dst.s_addr = pd->src->v4.s_addr; + + th2 = (struct tcphdr *)((caddr_t)h2 + sizeof(struct ip)); + break; +#endif /* INET */ +#ifdef INET6 + case AF_INET6: + h2_6 = mtod(m, struct ip6_hdr *); + + /* IP header fields included in the TCP checksum */ + h2_6->ip6_nxt = IPPROTO_TCP; + h2_6->ip6_plen = htons(sizeof(*th2)); + memcpy(&h2_6->ip6_src, pd->dst, sizeof(struct in6_addr)); + memcpy(&h2_6->ip6_dst, pd->src, sizeof(struct in6_addr)); + + th2 = (struct tcphdr *)((caddr_t)h2_6 + sizeof(struct ip6_hdr)); + break; +#endif /* INET6 */ + } /* TCP header */ - th2 = (struct tcphdr *)((caddr_t)h2 + sizeof(struct ip)); th2->th_sport = th->th_dport; th2->th_dport = th->th_sport; if (th->th_flags & TH_ACK) { th2->th_seq = th->th_ack; th2->th_flags = TH_RST; } else { - int tlen = h->ip_len - off - (th->th_off << 2); + int tlen = pd->p_len - off - (th->th_off << 2); if (th->th_flags & TH_SYN) tlen++; if (th->th_flags & TH_FIN) @@ -1967,21 +2385,37 @@ pf_send_reset(struct ip *h, int off, struct tcphdr *th) } th2->th_off = sizeof(*th2) >> 2; - /* TCP checksum */ - th2->th_sum = in_cksum(m, len); - - /* Finish the IP header */ - h2->ip_v = 4; - h2->ip_hl = sizeof(*h2) >> 2; - h2->ip_ttl = 128; - h2->ip_sum = 0; - h2->ip_len = len; - h2->ip_off = 0; - ip_output(m, NULL, NULL, 0, NULL, NULL); + switch (af) { +#ifdef INET + case AF_INET: + /* TCP checksum */ + th2->th_sum = in_cksum(m, len); + + /* Finish the IP header */ + h2->ip_v = 4; + h2->ip_hl = sizeof(*h2) >> 2; + h2->ip_ttl = 128; + h2->ip_sum = 0; + h2->ip_len = len; + h2->ip_off = 0; + ip_output(m, NULL, NULL, 0, NULL, NULL); + break; +#endif /* INET */ +#ifdef INET6 + case AF_INET6: + /* TCP checksum */ + th2->th_sum = in6_cksum(m, IPPROTO_TCP, + sizeof(struct ip6_hdr), sizeof(*th)); + + h2_6->ip6_hlim = 128; + + ip6_output(m, NULL, NULL, 0, NULL, NULL); +#endif /* INET6 */ + } } void -pf_send_icmp(struct mbuf *m, u_int8_t type, u_int8_t code) +pf_send_icmp(struct mbuf *m, u_int8_t type, u_int8_t code, int af) { struct m_tag *mtag; struct mbuf *m0; @@ -1995,7 +2429,18 @@ pf_send_icmp(struct mbuf *m, u_int8_t type, u_int8_t code) return; } m_tag_prepend(m0, mtag); - icmp_error(m0, type, code, 0, 0); + switch (af) { +#ifdef INET + case AF_INET: + icmp_error(m0, type, code, 0, 0); + break; +#endif /* INET */ +#ifdef INET6 + case AF_INET6: + icmp6_error(m0, type, code, 0); + break; +#endif /* INET6 */ + } } /* @@ -2004,9 +2449,33 @@ pf_send_icmp(struct mbuf *m, u_int8_t type, u_int8_t code) * are different. */ int -pf_match_addr(u_int8_t n, u_int32_t a, u_int32_t m, u_int32_t b) +pf_match_addr(u_int8_t n, struct pf_addr *a, struct pf_addr *m, + struct pf_addr *b, int af) { - if ((a & m) == (b & m)) { + int match = 0; + switch (af) { +#ifdef INET + case AF_INET: + if ((a->addr32[0] & m->addr32[0]) == + (b->addr32[0] & m->addr32[0])) + match++; + break; +#endif /* INET */ +#ifdef INET6 + case AF_INET6: + if (((a->addr32[0] & m->addr32[0]) == + (b->addr32[0] & m->addr32[0])) && + ((a->addr32[1] & m->addr32[1]) == + (b->addr32[1] & m->addr32[1])) && + ((a->addr32[2] & m->addr32[2]) == + (b->addr32[2] & m->addr32[2])) && + ((a->addr32[3] & m->addr32[3]) == + (b->addr32[3] & m->addr32[3]))) + match++; + break; +#endif /* INET6 */ + } + if (match) { if (n) return (0); else @@ -2146,7 +2615,8 @@ found: } struct pf_nat * -pf_get_nat(struct ifnet *ifp, u_int8_t proto, u_int32_t saddr, u_int32_t daddr) +pf_get_nat(struct ifnet *ifp, u_int8_t proto, struct pf_addr *saddr, + struct pf_addr *daddr, int af) { struct pf_nat *n, *nm = NULL; @@ -2155,8 +2625,9 @@ pf_get_nat(struct ifnet *ifp, u_int8_t proto, u_int32_t saddr, u_int32_t daddr) if (((n->ifp == NULL) || (n->ifp == ifp && !n->ifnot) || (n->ifp != ifp && n->ifnot)) && (!n->proto || n->proto == proto) && - pf_match_addr(n->snot, n->saddr, n->smask, saddr) && - pf_match_addr(n->dnot, n->daddr, n->dmask, daddr)) + (!n->af || n->af == af) && + PF_MATCHA(n->snot, &n->saddr, &n->smask, saddr, af) && + PF_MATCHA(n->dnot, &n->daddr, &n->dmask, daddr, af)) nm = n; else n = TAILQ_NEXT(n, entries); @@ -2166,21 +2637,26 @@ pf_get_nat(struct ifnet *ifp, u_int8_t proto, u_int32_t saddr, u_int32_t daddr) struct pf_binat * pf_get_binat(int direction, struct ifnet *ifp, u_int8_t proto, - u_int32_t saddr, u_int32_t daddr) + struct pf_addr *saddr, struct pf_addr *daddr, int af) { struct pf_binat *b, *bm = NULL; + struct pf_addr fullmask; + + memset(&fullmask, 0xff, sizeof(fullmask)); b = TAILQ_FIRST(pf_binats_active); while (b && bm == NULL) { if (direction == PF_OUT && b->ifp == ifp && (!b->proto || b->proto == proto) && - pf_match_addr(0, b->saddr, 0xffffffff, saddr) && - pf_match_addr(b->dnot, b->daddr, b->dmask, daddr)) + (!b->af || b->af == af) && + PF_MATCHA(0, &b->saddr, &fullmask, saddr, af) && + PF_MATCHA(b->dnot, &b->daddr, &b->dmask, daddr, af)) bm = b; else if (direction == PF_IN && b->ifp == ifp && (!b->proto || b->proto == proto) && - pf_match_addr(0, b->raddr, 0xffffffff, saddr) && - pf_match_addr(b->dnot, b->daddr, b->dmask, daddr)) + (!b->af || b->af == af) && + PF_MATCHA(0, &b->raddr, &fullmask, saddr, af) && + PF_MATCHA(b->dnot, &b->daddr, &b->dmask, daddr, af)) bm = b; else b = TAILQ_NEXT(b, entries); @@ -2189,8 +2665,8 @@ pf_get_binat(int direction, struct ifnet *ifp, u_int8_t proto, } struct pf_rdr * -pf_get_rdr(struct ifnet *ifp, u_int8_t proto, u_int32_t saddr, u_int32_t daddr, - u_int16_t dport) +pf_get_rdr(struct ifnet *ifp, u_int8_t proto, struct pf_addr *saddr, + struct pf_addr *daddr, u_int16_t dport, int af) { struct pf_rdr *r, *rm = NULL; @@ -2199,8 +2675,9 @@ pf_get_rdr(struct ifnet *ifp, u_int8_t proto, u_int32_t saddr, u_int32_t daddr, if (((r->ifp == NULL) || (r->ifp == ifp && !r->ifnot) || (r->ifp != ifp && r->ifnot)) && (!r->proto || r->proto == proto) && - pf_match_addr(r->snot, r->saddr, r->smask, saddr) && - pf_match_addr(r->dnot, r->daddr, r->dmask, daddr) && + (!r->af || r->af == af) && + PF_MATCHA(r->snot, &r->saddr, &r->smask, saddr, af) && + PF_MATCHA(r->dnot, &r->daddr, &r->dmask, daddr, af) && ((!r->dport2 && dport == r->dport) || (r->dport2 && (ntohs(dport) >= ntohs(r->dport)) && ntohs(dport) <= ntohs(r->dport2)))) @@ -2223,67 +2700,65 @@ pf_map_port_range(struct pf_rdr *rdr, u_int16_t port) return htons((u_int16_t)nport); } + int pf_test_tcp(int direction, struct ifnet *ifp, struct mbuf *m, - int ipoff, int off, struct ip *h, struct tcphdr *th) + int ipoff, int off, void *h, struct pf_pdesc *pd) { struct pf_nat *nat = NULL; struct pf_binat *binat = NULL; struct pf_rdr *rdr = NULL; - u_int32_t baddr; - u_int16_t bport, nport = 0; + struct pf_addr *saddr = pd->src, *daddr = pd->dst, baddr; + struct tcphdr *th = pd->hdr.tcp; struct pf_rule *r, *rm = NULL; + u_int16_t bport, nport = 0, af = pd->af; u_short reason; int rewrite = 0, error; if (direction == PF_OUT) { /* check outgoing packet for BINAT */ if ((binat = pf_get_binat(PF_OUT, ifp, IPPROTO_TCP, - h->ip_src.s_addr, h->ip_dst.s_addr)) != NULL) { - baddr = h->ip_src.s_addr; + saddr, daddr, af)) != NULL) { + PF_ACPY(&baddr, saddr, af); bport = th->th_sport; - pf_change_ap(&h->ip_src.s_addr, &th->th_sport, - &h->ip_sum, &th->th_sum, binat->raddr, - th->th_sport, 0); + pf_change_ap(saddr, &th->th_sport, pd->ip_sum, + &th->th_sum, &binat->raddr, th->th_sport, 0, af); rewrite++; } /* check outgoing packet for NAT */ else if ((nat = pf_get_nat(ifp, IPPROTO_TCP, - h->ip_src.s_addr, h->ip_dst.s_addr)) != NULL) { - baddr = h->ip_src.s_addr; + saddr, daddr, af)) != NULL) { bport = th->th_sport; error = pf_get_sport(IPPROTO_TCP, 50001, 65535, &nport); if (error) return (PF_DROP); - pf_change_ap(&h->ip_src.s_addr, &th->th_sport, - &h->ip_sum, &th->th_sum, nat->raddr, - htons(nport), 0); + PF_ACPY(&baddr, saddr, af); + pf_change_ap(saddr, &th->th_sport, pd->ip_sum, + &th->th_sum, &nat->raddr, htons(nport), 0, af); rewrite++; } } else { /* check incoming packet for RDR */ - if ((rdr = pf_get_rdr(ifp, IPPROTO_TCP, h->ip_src.s_addr, - h->ip_dst.s_addr, th->th_dport)) != NULL) { - baddr = h->ip_dst.s_addr; + if ((rdr = pf_get_rdr(ifp, IPPROTO_TCP, saddr, daddr, + th->th_dport, af)) != NULL) { bport = th->th_dport; if (rdr->opts & PF_RPORT_RANGE) nport = pf_map_port_range(rdr, th->th_dport); else nport = rdr->rport; - - pf_change_ap(&h->ip_dst.s_addr, &th->th_dport, - &h->ip_sum, &th->th_sum, rdr->raddr, nport, 0); + PF_ACPY(&baddr, daddr, af); + pf_change_ap(daddr, &th->th_dport, pd->ip_sum, + &th->th_sum, &rdr->raddr, nport, 0, af); rewrite++; } /* check incoming packet for BINAT */ else if ((binat = pf_get_binat(PF_IN, ifp, IPPROTO_TCP, - h->ip_dst.s_addr, h->ip_dst.s_addr)) != NULL) { - baddr = h->ip_dst.s_addr; + daddr, saddr, af)) != NULL) { + PF_ACPY(&baddr, daddr, af); bport = th->th_dport; - pf_change_ap(&h->ip_dst.s_addr, &th->th_dport, - &h->ip_sum, &th->th_sum, binat->saddr, - th->th_dport, 0); + pf_change_ap(daddr, &th->th_dport, pd->ip_sum, + &th->th_sum, &binat->saddr, th->th_dport, 0, af); rewrite++; } } @@ -2297,20 +2772,22 @@ pf_test_tcp(int direction, struct ifnet *ifp, struct mbuf *m, r->evaluations++; if (r->ifp != NULL && r->ifp != ifp) r = r->skip[0]; - else if (r->proto && r->proto != h->ip_p) + else if (r->af && r->af != af) r = r->skip[1]; - else if (r->src.mask && !pf_match_addr(r->src.not, - r->src.addr, r->src.mask, h->ip_src.s_addr)) + else if (r->proto && r->proto != IPPROTO_TCP) r = r->skip[2]; + else if (!PF_AZERO(&r->src.mask, af) && !PF_MATCHA(r->src.not, + &r->src.addr, &r->src.mask, saddr, af)) + r = r->skip[3]; else if (r->src.port_op && !pf_match_port(r->src.port_op, r->src.port[0], r->src.port[1], th->th_sport)) - r = r->skip[3]; - else if (r->dst.mask && !pf_match_addr(r->dst.not, - r->dst.addr, r->dst.mask, h->ip_dst.s_addr)) r = r->skip[4]; + else if (!PF_AZERO(&r->dst.mask, af) && !PF_MATCHA(r->dst.not, + &r->dst.addr, &r->dst.mask, daddr, af)) + r = r->skip[5]; else if (r->dst.port_op && !pf_match_port(r->dst.port_op, r->dst.port[0], r->dst.port[1], th->th_dport)) - r = r->skip[5]; + r = r->skip[6]; else if (r->direction != direction) r = TAILQ_NEXT(r, entries); else if ((r->flagset & th->th_flags) != r->flags) @@ -2325,32 +2802,32 @@ pf_test_tcp(int direction, struct ifnet *ifp, struct mbuf *m, if (rm != NULL) { rm->packets++; - rm->bytes += h->ip_len; + rm->bytes += pd->tot_len; REASON_SET(&reason, PFRES_MATCH); /* XXX will log packet before rewrite */ if (rm->log) - PFLOG_PACKET(h, m, AF_INET, direction, reason, rm); + PFLOG_PACKET(h, m, af, direction, reason, rm); if ((rm->action == PF_DROP) && ((rm->rule_flag & PFRULE_RETURNRST) || rm->return_icmp)) { /* undo NAT/RST changes, if they have taken place */ if (nat != NULL || - (binat != NULL && direction == PF_OUT)) { - pf_change_ap(&h->ip_src.s_addr, &th->th_sport, - &h->ip_sum, &th->th_sum, baddr, bport, 0); + (binat != NULL && direction == PF_OUT)) { + pf_change_ap(saddr, &th->th_sport, pd->ip_sum, + &th->th_sum, &baddr, bport, 0, af); rewrite++; } else if (rdr != NULL || - (binat != NULL && direction == PF_IN)) { - pf_change_ap(&h->ip_dst.s_addr, &th->th_dport, - &h->ip_sum, &th->th_sum, baddr, bport, 0); + (binat != NULL && direction == PF_IN)) { + pf_change_ap(daddr, &th->th_dport, pd->ip_sum, + &th->th_sum, &baddr, bport, 0, af); rewrite++; } if (rm->rule_flag & PFRULE_RETURNRST) - pf_send_reset(h, off, th); - else + pf_send_reset(off, th, pd, af); + else pf_send_icmp(m, rm->return_icmp >> 8, - rm->return_icmp & 255); + rm->return_icmp & 255, af); } if (rm->action == PF_DROP) { @@ -2365,7 +2842,7 @@ pf_test_tcp(int direction, struct ifnet *ifp, struct mbuf *m, u_int16_t len; struct pf_state *s; - len = h->ip_len - off - (th->th_off << 2); + len = pd->tot_len - off - (th->th_off << 2); s = pool_get(&pf_state_pl, PR_NOWAIT); if (s == NULL) { if (nport && nat != NULL) @@ -2377,28 +2854,30 @@ pf_test_tcp(int direction, struct ifnet *ifp, struct mbuf *m, s->log = rm && (rm->log & 2); s->proto = IPPROTO_TCP; s->direction = direction; + s->af = af; if (direction == PF_OUT) { - s->gwy.addr = h->ip_src.s_addr; + PF_ACPY(&s->gwy.addr, saddr, af); s->gwy.port = th->th_sport; /* sport */ - s->ext.addr = h->ip_dst.s_addr; + PF_ACPY(&s->ext.addr, daddr, af); s->ext.port = th->th_dport; if (nat != NULL || binat != NULL) { + PF_ACPY(&s->lan.addr, &baddr, af); s->lan.addr = baddr; s->lan.port = bport; } else { - s->lan.addr = s->gwy.addr; + PF_ACPY(&s->lan.addr, &s->gwy.addr, af); s->lan.port = s->gwy.port; } } else { - s->lan.addr = h->ip_dst.s_addr; + PF_ACPY(&s->lan.addr, daddr, af); s->lan.port = th->th_dport; - s->ext.addr = h->ip_src.s_addr; + PF_ACPY(&s->ext.addr, saddr, af); s->ext.port = th->th_sport; - if (binat != NULL || rdr != NULL) { - s->gwy.addr = baddr; + if (binat != NULL ||rdr != NULL) { + PF_ACPY(&s->gwy.addr, &baddr, af); s->gwy.port = bport; } else { - s->gwy.addr = s->lan.addr; + PF_ACPY(&s->gwy.addr, &s->lan.addr, af); s->gwy.port = s->lan.port; } } @@ -2429,7 +2908,7 @@ pf_test_tcp(int direction, struct ifnet *ifp, struct mbuf *m, s->creation = pftv.tv_sec; s->expire = pftv.tv_sec + pftm_tcp_first_packet; s->packets = 1; - s->bytes = h->ip_len; + s->bytes = pd->tot_len; pf_insert_state(s); } @@ -2442,13 +2921,14 @@ pf_test_tcp(int direction, struct ifnet *ifp, struct mbuf *m, int pf_test_udp(int direction, struct ifnet *ifp, struct mbuf *m, - int ipoff, int off, struct ip *h, struct udphdr *uh) + int ipoff, int off, void *h, struct pf_pdesc *pd) { struct pf_nat *nat = NULL; struct pf_binat *binat = NULL; struct pf_rdr *rdr = NULL; - u_int32_t baddr; - u_int16_t bport, nport = 0; + struct pf_addr *saddr = pd->src, *daddr = pd->dst, baddr; + struct udphdr *uh = pd->hdr.udp; + u_int16_t bport, nport = 0, af = pd->af; struct pf_rule *r, *rm = NULL; u_short reason; int rewrite = 0, error; @@ -2456,53 +2936,48 @@ pf_test_udp(int direction, struct ifnet *ifp, struct mbuf *m, if (direction == PF_OUT) { /* check outgoing packet for BINAT */ if ((binat = pf_get_binat(PF_OUT, ifp, IPPROTO_UDP, - h->ip_src.s_addr, h->ip_dst.s_addr)) != NULL) { - baddr = h->ip_src.s_addr; + saddr, daddr, af)) != NULL) { + PF_ACPY(&baddr, saddr, af); bport = uh->uh_sport; - pf_change_ap(&h->ip_src.s_addr, &uh->uh_sport, - &h->ip_sum, &uh->uh_sum, binat->raddr, - uh->uh_sport, 1); + pf_change_ap(saddr, &uh->uh_sport, pd->ip_sum, + &uh->uh_sum, &binat->raddr, uh->uh_sport, 1, af); rewrite++; } /* check outgoing packet for NAT */ else if ((nat = pf_get_nat(ifp, IPPROTO_UDP, - h->ip_src.s_addr, h->ip_dst.s_addr)) != NULL) { - baddr = h->ip_src.s_addr; + saddr, daddr, af)) != NULL) { bport = uh->uh_sport; error = pf_get_sport(IPPROTO_UDP, 50001, 65535, &nport); if (error) return (PF_DROP); - pf_change_ap(&h->ip_src.s_addr, &uh->uh_sport, - &h->ip_sum, &uh->uh_sum, nat->raddr, - htons(nport), 1); + PF_ACPY(&baddr, saddr, af); + pf_change_ap(saddr, &uh->uh_sport, pd->ip_sum, + &uh->uh_sum, &nat->raddr, htons(nport), 1, af); rewrite++; } } else { /* check incoming packet for RDR */ - if ((rdr = pf_get_rdr(ifp, IPPROTO_UDP, h->ip_src.s_addr, - h->ip_dst.s_addr, uh->uh_dport)) != NULL) { - baddr = h->ip_dst.s_addr; + if ((rdr = pf_get_rdr(ifp, IPPROTO_UDP, saddr, daddr, + uh->uh_dport, af)) != NULL) { bport = uh->uh_dport; if (rdr->opts & PF_RPORT_RANGE) nport = pf_map_port_range(rdr, uh->uh_dport); else nport = rdr->rport; - pf_change_ap(&h->ip_dst.s_addr, &uh->uh_dport, - &h->ip_sum, &uh->uh_sum, rdr->raddr, - nport, 1); - + PF_ACPY(&baddr, daddr, af); + pf_change_ap(daddr, &uh->uh_dport, pd->ip_sum, + &uh->uh_sum, &rdr->raddr, nport, 1, af); rewrite++; } /* check incoming packet for BINAT */ else if ((binat = pf_get_binat(PF_IN, ifp, IPPROTO_UDP, - h->ip_dst.s_addr, h->ip_dst.s_addr)) != NULL) { - baddr = h->ip_dst.s_addr; + daddr, daddr, af)) != NULL) { + PF_ACPY(&baddr, daddr, af); bport = uh->uh_dport; - pf_change_ap(&h->ip_dst.s_addr, &uh->uh_dport, - &h->ip_sum, &uh->uh_sum, binat->saddr, - uh->uh_dport, 1); + pf_change_ap(daddr, &uh->uh_dport, pd->ip_sum, + &uh->uh_sum, &binat->saddr, uh->uh_dport, 1, af); rewrite++; } } @@ -2514,22 +2989,27 @@ pf_test_udp(int direction, struct ifnet *ifp, struct mbuf *m, continue; } r->evaluations++; + if (r->ifp != NULL && r->ifp != ifp) r = r->skip[0]; - else if (r->proto && r->proto != h->ip_p) + else if (r->af && r->af != af) r = r->skip[1]; - else if (r->src.mask && !pf_match_addr(r->src.not, - r->src.addr, r->src.mask, h->ip_src.s_addr)) + else if (r->proto && r->proto != IPPROTO_UDP) r = r->skip[2]; - else if (r->src.port_op && !pf_match_port(r->src.port_op, - r->src.port[0], r->src.port[1], uh->uh_sport)) + else if (!PF_AZERO(&r->src.mask, af) && + !PF_MATCHA(r->src.not, &r->src.addr, &r->src.mask, + saddr, af)) r = r->skip[3]; - else if (r->dst.mask && !pf_match_addr(r->dst.not, - r->dst.addr, r->dst.mask, h->ip_dst.s_addr)) - r = r->skip[4]; + else if (r->src.port_op && !pf_match_port(r->src.port_op, + r->src.port[0], r->src.port[1], uh->uh_sport)) + r = r->skip[4]; + else if (!PF_AZERO(&r->dst.mask, af) && + !PF_MATCHA(r->dst.not, &r->dst.addr, &r->dst.mask, + daddr, af)) + r = r->skip[5]; else if (r->dst.port_op && !pf_match_port(r->dst.port_op, r->dst.port[0], r->dst.port[1], uh->uh_dport)) - r = r->skip[5]; + r = r->skip[6]; else if (r->direction != direction) r = TAILQ_NEXT(r, entries); else { @@ -2542,28 +3022,29 @@ pf_test_udp(int direction, struct ifnet *ifp, struct mbuf *m, if (rm != NULL) { rm->packets++; - rm->bytes += h->ip_len; + rm->bytes += pd->tot_len; REASON_SET(&reason, PFRES_MATCH); /* XXX will log packet before rewrite */ if (rm->log) - PFLOG_PACKET(h, m, AF_INET, direction, reason, rm); + PFLOG_PACKET(h, m, af, direction, reason, rm); if ((rm->action == PF_DROP) && rm->return_icmp) { /* undo NAT/RST changes, if they have taken place */ if (nat != NULL || (binat != NULL && direction == PF_OUT)) { - pf_change_ap(&h->ip_src.s_addr, &uh->uh_sport, - &h->ip_sum, &uh->uh_sum, baddr, bport, 1); + pf_change_ap(saddr, &uh->uh_sport, pd->ip_sum, + &uh->uh_sum, &baddr, bport, 1, af); rewrite++; } else if (rdr != NULL || (binat != NULL && direction == PF_IN)) { - pf_change_ap(&h->ip_dst.s_addr, &uh->uh_dport, - &h->ip_sum, &uh->uh_sum, baddr, bport, 1); + pf_change_ap(daddr, &uh->uh_dport, pd->ip_sum, + &uh->uh_sum, &baddr, bport, 1, af); rewrite++; + } pf_send_icmp(m, rm->return_icmp >> 8, - rm->return_icmp & 255); + rm->return_icmp & 255, af); } if (rm->action == PF_DROP) { @@ -2578,7 +3059,7 @@ pf_test_udp(int direction, struct ifnet *ifp, struct mbuf *m, u_int16_t len; struct pf_state *s; - len = h->ip_len - off - sizeof(*uh); + len = pd->tot_len - off - sizeof(*uh); s = pool_get(&pf_state_pl, PR_NOWAIT); if (s == NULL) { if (nport && nat != NULL) @@ -2590,28 +3071,29 @@ pf_test_udp(int direction, struct ifnet *ifp, struct mbuf *m, s->log = rm && (rm->log & 2); s->proto = IPPROTO_UDP; s->direction = direction; + s->af = af; if (direction == PF_OUT) { - s->gwy.addr = h->ip_src.s_addr; + PF_ACPY(&s->gwy.addr, saddr, af); s->gwy.port = uh->uh_sport; - s->ext.addr = h->ip_dst.s_addr; + PF_ACPY(&s->ext.addr, daddr, af); s->ext.port = uh->uh_dport; if (nat != NULL || binat != NULL) { - s->lan.addr = baddr; + PF_ACPY(&s->lan.addr, &baddr, af); s->lan.port = bport; } else { - s->lan.addr = s->gwy.addr; + PF_ACPY(&s->lan.addr, &s->gwy.addr, af); s->lan.port = s->gwy.port; } } else { - s->lan.addr = h->ip_dst.s_addr; + PF_ACPY(&s->lan.addr, daddr, af); s->lan.port = uh->uh_dport; - s->ext.addr = h->ip_src.s_addr; + PF_ACPY(&s->ext.addr, saddr, af); s->ext.port = uh->uh_sport; if (binat != NULL || rdr != NULL) { - s->gwy.addr = baddr; + PF_ACPY(&s->gwy.addr, &baddr, af); s->gwy.port = bport; } else { - s->gwy.addr = s->lan.addr; + PF_ACPY(&s->gwy.addr, &s->lan.addr, af); s->gwy.port = s->lan.port; } } @@ -2628,7 +3110,7 @@ pf_test_udp(int direction, struct ifnet *ifp, struct mbuf *m, s->creation = pftv.tv_sec; s->expire = pftv.tv_sec + pftm_udp_first_packet; s->packets = 1; - s->bytes = h->ip_len; + s->bytes = pd->tot_len; pf_insert_state(s); } @@ -2641,35 +3123,91 @@ pf_test_udp(int direction, struct ifnet *ifp, struct mbuf *m, int pf_test_icmp(int direction, struct ifnet *ifp, struct mbuf *m, - int ipoff, int off, struct ip *h, struct icmp *ih) + int ipoff, int off, void *h, struct pf_pdesc *pd) { struct pf_nat *nat = NULL; struct pf_binat *binat = NULL; - u_int32_t baddr; + struct pf_addr *saddr = pd->src, *daddr = pd->dst, baddr; struct pf_rule *r, *rm = NULL; u_short reason; + u_int16_t icmpid, af = pd->af; + u_int8_t icmptype, icmpcode; + + switch (pd->proto) { +#ifdef INET + case IPPROTO_ICMP: + icmptype = pd->hdr.icmp->icmp_type; + icmpcode = pd->hdr.icmp->icmp_code; + icmpid = pd->hdr.icmp->icmp_id; + break; +#endif /* INET */ +#ifdef INET6 + case IPPROTO_ICMPV6: + icmptype = pd->hdr.icmp6->icmp6_type; + icmpcode = pd->hdr.icmp6->icmp6_code; + icmpid = pd->hdr.icmp6->icmp6_id; + break; +#endif /* INET6 */ + } if (direction == PF_OUT) { /* check outgoing packet for BINAT */ if ((binat = pf_get_binat(PF_OUT, ifp, IPPROTO_ICMP, - h->ip_src.s_addr, h->ip_dst.s_addr)) != NULL) { - baddr = h->ip_src.s_addr; - pf_change_a(&h->ip_src.s_addr, &h->ip_sum, - binat->raddr, 0); + saddr, daddr, af)) != NULL) { + PF_ACPY(&baddr, saddr, af); + switch (af) { +#ifdef INET + case AF_INET: + pf_change_a(&saddr->v4.s_addr, pd->ip_sum, + binat->raddr.v4.s_addr, 0); + break; +#endif /* INET */ +#ifdef INET6 + case AF_INET6: + pf_change_a6(saddr, &pd->hdr.icmp6->icmp6_cksum, + &binat->raddr, 0); + break; +#endif /* INET6 */ + } } /* check outgoing packet for NAT */ - else if ((nat = pf_get_nat(ifp, IPPROTO_ICMP, - h->ip_src.s_addr, h->ip_dst.s_addr)) != NULL) { - baddr = h->ip_src.s_addr; - pf_change_a(&h->ip_src.s_addr, &h->ip_sum, nat->raddr, 0); + else if ((nat = pf_get_nat(ifp, pd->proto, + saddr, daddr, af)) != NULL) { + PF_ACPY(&baddr, saddr, af); + switch (af) { +#ifdef INET + case AF_INET: + pf_change_a(&saddr->v4.s_addr, + pd->ip_sum, nat->raddr.v4.s_addr, 0); + break; +#endif /* INET */ +#ifdef INET6 + case AF_INET6: + pf_change_a6(saddr, &pd->hdr.icmp6->icmp6_cksum, + &nat->raddr, 0); + break; +#endif /* INET6 */ + } } } else { /* check incoming packet for BINAT */ if ((binat = pf_get_binat(PF_IN, ifp, IPPROTO_ICMP, - h->ip_dst.s_addr, h->ip_src.s_addr)) != NULL) { - baddr = h->ip_dst.s_addr; - pf_change_a(&h->ip_dst.s_addr, &h->ip_sum, - binat->saddr, 0); + daddr, saddr, af)) != NULL) { + PF_ACPY(&baddr, daddr, af); + switch (af) { +#ifdef INET + case AF_INET: + pf_change_a(&daddr->v4.s_addr, + pd->ip_sum, binat->saddr.v4.s_addr, 0); + break; +#endif /* INET */ +#ifdef INET6 + case AF_INET6: + pf_change_a6(daddr, &pd->hdr.icmp6->icmp6_cksum, + &binat->saddr, 0); + break; +#endif /* INET6 */ + } } } @@ -2682,19 +3220,23 @@ pf_test_icmp(int direction, struct ifnet *ifp, struct mbuf *m, r->evaluations++; if (r->ifp != NULL && r->ifp != ifp) r = r->skip[0]; - else if (r->proto && r->proto != h->ip_p) + else if (r->af && r->af != af) r = r->skip[1]; - else if (r->src.mask && !pf_match_addr(r->src.not, - r->src.addr, r->src.mask, h->ip_src.s_addr)) + else if (r->proto && r->proto != pd->proto) r = r->skip[2]; - else if (r->dst.mask && !pf_match_addr(r->dst.not, - r->dst.addr, r->dst.mask, h->ip_dst.s_addr)) - r = r->skip[4]; + else if (!PF_AZERO(&r->src.mask, af) && !PF_MATCHA(r->src.not, + &r->src.addr, &r->src.mask, saddr, af)) + r = r->skip[3]; + else if (!PF_AZERO(&r->dst.mask, af) && !PF_MATCHA(r->dst.not, + &r->dst.addr, &r->dst.mask, daddr, af)) + r = r->skip[5]; else if (r->direction != direction) r = TAILQ_NEXT(r, entries); - else if (r->type && r->type != ih->icmp_type + 1) + else if (r->ifp != NULL && r->ifp != ifp) r = TAILQ_NEXT(r, entries); - else if (r->code && r->code != ih->icmp_code + 1) + else if (r->type && r->type != icmptype + 1) + r = TAILQ_NEXT(r, entries); + else if (r->code && r->code != icmpcode + 1) r = TAILQ_NEXT(r, entries); else { rm = r; @@ -2706,12 +3248,12 @@ pf_test_icmp(int direction, struct ifnet *ifp, struct mbuf *m, if (rm != NULL) { rm->packets++; - rm->bytes += h->ip_len; + rm->bytes += pd->tot_len; REASON_SET(&reason, PFRES_MATCH); /* XXX will log packet before rewrite */ if (rm->log) - PFLOG_PACKET(h, m, AF_INET, direction, reason, rm); + PFLOG_PACKET(h, m, af, direction, reason, rm); if (rm->action != PF_PASS) return (PF_DROP); @@ -2720,39 +3262,38 @@ pf_test_icmp(int direction, struct ifnet *ifp, struct mbuf *m, if ((rm != NULL && rm->keep_state) || nat != NULL || binat != NULL) { /* create new state */ u_int16_t len; - u_int16_t id; struct pf_state *s; - len = h->ip_len - off - ICMP_MINLEN; - id = ih->icmp_id; + len = pd->tot_len - off - ICMP_MINLEN; s = pool_get(&pf_state_pl, PR_NOWAIT); if (s == NULL) return (PF_DROP); s->rule = rm; s->log = rm && (rm->log & 2); - s->proto = IPPROTO_ICMP; + s->proto = pd->proto; s->direction = direction; + s->af = af; if (direction == PF_OUT) { - s->gwy.addr = h->ip_src.s_addr; - s->gwy.port = id; - s->ext.addr = h->ip_dst.s_addr; - s->ext.port = id; - if (nat != NULL || binat != NULL) - s->lan.addr = baddr; + PF_ACPY(&s->gwy.addr, saddr, af); + s->gwy.port = icmpid; + PF_ACPY(&s->ext.addr, daddr, af); + s->ext.port = icmpid; + if (nat != NULL || binat != NULL) + PF_ACPY(&s->lan.addr, &baddr, af); else - s->lan.addr = s->gwy.addr; - s->lan.port = id; + PF_ACPY(&s->lan.addr, &s->gwy.addr, af); + s->lan.port = icmpid; } else { - s->lan.addr = h->ip_dst.s_addr; - s->lan.port = id; - s->ext.addr = h->ip_src.s_addr; - s->ext.port = id; + PF_ACPY(&s->lan.addr, daddr, af); + s->lan.port = icmpid; + PF_ACPY(&s->ext.addr, saddr, af); + s->ext.port = icmpid; if (binat != NULL) - s->gwy.addr = baddr; + PF_ACPY(&s->gwy.addr, &baddr, af); else - s->gwy.addr = s->lan.addr; - s->gwy.port = id; + PF_ACPY(&s->gwy.addr, &s->lan.addr, af); + s->gwy.port = icmpid; } s->src.seqlo = 0; s->src.seqhi = 0; @@ -2767,7 +3308,7 @@ pf_test_icmp(int direction, struct ifnet *ifp, struct mbuf *m, s->creation = pftv.tv_sec; s->expire = pftv.tv_sec + pftm_icmp_first_packet; s->packets = 1; - s->bytes = h->ip_len; + s->bytes = pd->tot_len; pf_insert_state(s); } @@ -2775,24 +3316,49 @@ pf_test_icmp(int direction, struct ifnet *ifp, struct mbuf *m, } int -pf_test_other(int direction, struct ifnet *ifp, struct mbuf *m, struct ip *h) +pf_test_other(int direction, struct ifnet *ifp, struct mbuf *m, + void *h, struct pf_pdesc *pd) { struct pf_rule *r, *rm = NULL; struct pf_binat *binat = NULL; + struct pf_addr *saddr = pd->src, *daddr = pd->dst; + u_int8_t af = pd->af; if (direction == PF_OUT) { /* check outgoing packet for BINAT */ - if ((binat = pf_get_binat(PF_OUT, ifp, NULL, h->ip_src.s_addr, - h->ip_dst.s_addr)) != NULL) { - pf_change_a(&h->ip_src.s_addr, &h->ip_sum, - binat->raddr, 0); + if ((binat = pf_get_binat(PF_OUT, ifp, pd->proto, + saddr, daddr, af)) != NULL) { + switch (af) { +#ifdef INET + case AF_INET: + pf_change_a(&saddr->v4.s_addr, pd->ip_sum, + binat->raddr.v4.s_addr, 0); + break; +#endif /* INET */ +#ifdef INET6 + case AF_INET6: + PF_ACPY(saddr, &binat->raddr, af); + break; +#endif /* INET6 */ + } } } else { /* check incoming packet for BINAT */ - if ((binat = pf_get_binat(PF_IN, ifp, NULL, h->ip_dst.s_addr, - h->ip_src.s_addr)) != NULL) { - pf_change_a(&h->ip_dst.s_addr, &h->ip_sum, - binat->saddr, 0); + if ((binat = pf_get_binat(PF_IN, ifp, pd->proto, + daddr, saddr, af)) != NULL) { + switch (af) { +#ifdef INET + case AF_INET: + pf_change_a(&daddr->v4.s_addr, + pd->ip_sum, binat->saddr.v4.s_addr, 0); + break; +#endif /* INET */ +#ifdef INET6 + case AF_INET6: + PF_ACPY(daddr, &binat->saddr, af); + break; +#endif /* INET6 */ + } } } @@ -2805,14 +3371,16 @@ pf_test_other(int direction, struct ifnet *ifp, struct mbuf *m, struct ip *h) r->evaluations++; if (r->ifp != NULL && r->ifp != ifp) r = r->skip[0]; - else if (r->proto && r->proto != h->ip_p) + else if (r->af && r->af != af) r = r->skip[1]; - else if (r->src.mask && !pf_match_addr(r->src.not, - r->src.addr, r->src.mask, h->ip_src.s_addr)) + else if (r->proto && r->proto != pd->proto) r = r->skip[2]; - else if (r->dst.mask && !pf_match_addr(r->dst.not, - r->dst.addr, r->dst.mask, h->ip_dst.s_addr)) - r = r->skip[4]; + else if (!PF_AZERO(&r->src.mask, af) && !PF_MATCHA(r->src.not, + &r->src.addr, &r->src.mask, pd->src, af)) + r = r->skip[3]; + else if (!PF_AZERO(&r->dst.mask, af) && !PF_MATCHA(r->dst.not, + &r->dst.addr, &r->dst.mask, pd->dst, af)) + r = r->skip[5]; else if (r->direction != direction) r = TAILQ_NEXT(r, entries); else { @@ -2827,10 +3395,10 @@ pf_test_other(int direction, struct ifnet *ifp, struct mbuf *m, struct ip *h) u_short reason; rm->packets++; - rm->bytes += h->ip_len; + rm->bytes += pd->tot_len; REASON_SET(&reason, PFRES_MATCH); if (rm->log) - PFLOG_PACKET(h, m, AF_INET, direction, reason, rm); + PFLOG_PACKET(h, m, af, direction, reason, rm); if (rm->action != PF_PASS) return (PF_DROP); @@ -2840,19 +3408,20 @@ pf_test_other(int direction, struct ifnet *ifp, struct mbuf *m, struct ip *h) int pf_test_state_tcp(struct pf_state **state, int direction, struct ifnet *ifp, - struct mbuf *m, int ipoff, int off, struct ip *h, struct tcphdr *th) + struct mbuf *m, int ipoff, int off, void *h, struct pf_pdesc *pd) { struct pf_tree_key key; - u_int16_t len = h->ip_len - off - (th->th_off << 2); + struct tcphdr *th = pd->hdr.tcp; u_int16_t win = ntohs(th->th_win); u_int32_t ack, end, seq; int ackskew; struct pf_state_peer *src, *dst; + key.af = pd->af; key.proto = IPPROTO_TCP; - key.addr[0] = h->ip_src; + PF_ACPY(&key.addr[0], pd->src, key.af); + PF_ACPY(&key.addr[1], pd->dst, key.af); key.port[0] = th->th_sport; - key.addr[1] = h->ip_dst; key.port[1] = th->th_dport; if (direction == PF_IN) @@ -2892,7 +3461,7 @@ pf_test_state_tcp(struct pf_state **state, int direction, struct ifnet *ifp, ack = ntohl(th->th_ack); } - end = seq + len; + end = seq + pd->p_len; if (th->th_flags & TH_SYN) end++; if (th->th_flags & TH_FIN) @@ -2920,7 +3489,7 @@ pf_test_state_tcp(struct pf_state **state, int direction, struct ifnet *ifp, src->seqdiff), 0); pf_change_a(&th->th_ack, &th->th_sum, htonl(ack), 0); } - end = seq + len; + end = seq + pd->p_len; if (th->th_flags & TH_SYN) end++; if (th->th_flags & TH_FIN) @@ -2959,7 +3528,7 @@ pf_test_state_tcp(struct pf_state **state, int direction, struct ifnet *ifp, /* Acking not more than one window forward */ (*state)->packets++; - (*state)->bytes += h->ip_len; + (*state)->bytes += pd->tot_len; /* update max window */ if (src->max_win < win) @@ -3040,11 +3609,11 @@ pf_test_state_tcp(struct pf_state **state, int direction, struct ifnet *ifp, pf_print_state(*state); pf_print_flags(th->th_flags); printf(" seq=%lu ack=%lu len=%u ackskew=%d pkts=%d\n", - seq, ack, len, ackskew, (*state)->packets); + seq, ack, pd->p_len, ackskew, (*state)->packets); } (*state)->packets++; - (*state)->bytes += h->ip_len; + (*state)->bytes += pd->tot_len; /* update max window */ if (src->max_win < win) @@ -3075,7 +3644,7 @@ pf_test_state_tcp(struct pf_state **state, int direction, struct ifnet *ifp, pf_print_state(*state); pf_print_flags(th->th_flags); printf(" seq=%lu ack=%lu len=%u ackskew=%d pkts=%d " - "dir=%s,%s\n", seq, ack, len, ackskew, + "dir=%s,%s\n", seq, ack, pd->p_len, ackskew, ++(*state)->packets, direction == PF_IN ? "in" : "out", direction == (*state)->direction ? "fwd" : "rev"); @@ -3095,15 +3664,13 @@ pf_test_state_tcp(struct pf_state **state, int direction, struct ifnet *ifp, /* translate source/destination address, if needed */ if (STATE_TRANSLATE(*state)) { if (direction == PF_OUT) - pf_change_ap(&h->ip_src.s_addr, - &th->th_sport, &h->ip_sum, - &th->th_sum, (*state)->gwy.addr, - (*state)->gwy.port, 0); + pf_change_ap(pd->src, &th->th_sport, pd->ip_sum, + &th->th_sum, &(*state)->gwy.addr, + (*state)->gwy.port, 0, pd->af); else - pf_change_ap(&h->ip_dst.s_addr, - &th->th_dport, &h->ip_sum, - &th->th_sum, (*state)->lan.addr, - (*state)->lan.port, 0); + pf_change_ap(pd->dst, &th->th_dport, pd->ip_sum, + &th->th_sum, &(*state)->lan.addr, + (*state)->lan.port, 0, pd->af); m_copyback(m, off, sizeof(*th), (caddr_t)th); } else if (src->seqdiff) { /* Copyback sequence modulation */ @@ -3112,23 +3679,25 @@ pf_test_state_tcp(struct pf_state **state, int direction, struct ifnet *ifp, if ((*state)->rule != NULL) { (*state)->rule->packets++; - (*state)->rule->bytes += h->ip_len; + (*state)->rule->bytes += pd->tot_len; } return (PF_PASS); } int pf_test_state_udp(struct pf_state **state, int direction, struct ifnet *ifp, - struct mbuf *m, int ipoff, int off, struct ip *h, struct udphdr *uh) + struct mbuf *m, int ipoff, int off, void *h, struct pf_pdesc *pd) { struct pf_state_peer *src, *dst; struct pf_tree_key key; + struct udphdr *uh = pd->hdr.udp; + key.af = pd->af; key.proto = IPPROTO_UDP; - key.addr[0] = h->ip_src; - key.port[0] = uh->uh_sport; - key.addr[1] = h->ip_dst; - key.port[1] = uh->uh_dport; + PF_ACPY(&key.addr[0], pd->src, key.af); + PF_ACPY(&key.addr[1], pd->dst, key.af); + key.port[0] = pd->hdr.udp->uh_sport; + key.port[1] = pd->hdr.udp->uh_dport; if (direction == PF_IN) *state = pf_find_state(tree_ext_gwy, &key); @@ -3146,7 +3715,7 @@ pf_test_state_udp(struct pf_state **state, int direction, struct ifnet *ifp, } (*state)->packets++; - (*state)->bytes += h->ip_len; + (*state)->bytes += pd->tot_len; /* update states */ if (src->state < 1) @@ -3163,32 +3732,63 @@ pf_test_state_udp(struct pf_state **state, int direction, struct ifnet *ifp, /* translate source/destination address, if necessary */ if (STATE_TRANSLATE(*state)) { if (direction == PF_OUT) - pf_change_ap(&h->ip_src.s_addr, &uh->uh_sport, - &h->ip_sum, &uh->uh_sum, - (*state)->gwy.addr, (*state)->gwy.port, 1); + pf_change_ap(pd->src, &uh->uh_sport, pd->ip_sum, + &uh->uh_sum, &(*state)->gwy.addr, + (*state)->gwy.port, 1, pd->af); else - pf_change_ap(&h->ip_dst.s_addr, &uh->uh_dport, - &h->ip_sum, &uh->uh_sum, - (*state)->lan.addr, (*state)->lan.port, 1); + pf_change_ap(pd->dst, &uh->uh_dport, pd->ip_sum, + &uh->uh_sum, &(*state)->lan.addr, + (*state)->lan.port, 1, pd->af); m_copyback(m, off, sizeof(*uh), (caddr_t)uh); } if ((*state)->rule != NULL) { (*state)->rule->packets++; - (*state)->rule->bytes += h->ip_len; + (*state)->rule->bytes += pd->tot_len; } return (PF_PASS); } int pf_test_state_icmp(struct pf_state **state, int direction, struct ifnet *ifp, - struct mbuf *m, int ipoff, int off, struct ip *h, struct icmp *ih) + struct mbuf *m, int ipoff, int off, void *h, struct pf_pdesc *pd) { - if (ih->icmp_type != ICMP_UNREACH && - ih->icmp_type != ICMP_SOURCEQUENCH && - ih->icmp_type != ICMP_REDIRECT && - ih->icmp_type != ICMP_TIMXCEED && - ih->icmp_type != ICMP_PARAMPROB) { + struct pf_addr *saddr = pd->src, *daddr = pd->dst; + u_int16_t icmpid, *icmpsum; + u_int8_t icmptype; + int state_icmp = 0; + + switch (pd->proto) { +#ifdef INET + case IPPROTO_ICMP: + icmptype = pd->hdr.icmp->icmp_type; + icmpid = pd->hdr.icmp->icmp_id; + icmpsum = &pd->hdr.icmp->icmp_cksum; + + if (icmptype == ICMP_UNREACH || + icmptype == ICMP_SOURCEQUENCH || + icmptype == ICMP_REDIRECT || + icmptype == ICMP_TIMXCEED || + icmptype == ICMP_PARAMPROB) + state_icmp++; + break; +#endif /* INET */ +#ifdef INET6 + case IPPROTO_ICMPV6: + icmptype = pd->hdr.icmp6->icmp6_type; + icmpid = pd->hdr.icmp6->icmp6_id; + icmpsum = &pd->hdr.icmp6->icmp6_cksum; + + if (icmptype == ICMP6_DST_UNREACH || + icmptype == ICMP6_PACKET_TOO_BIG || + icmptype == ICMP6_TIME_EXCEEDED || + icmptype == ICMP6_PARAM_PROB) + state_icmp++; + break; +#endif /* INET6 */ + } + + if (!state_icmp) { /* * ICMP query/reply message not related to a TCP/UDP packet. @@ -3196,11 +3796,12 @@ pf_test_state_icmp(struct pf_state **state, int direction, struct ifnet *ifp, */ struct pf_tree_key key; - key.proto = IPPROTO_ICMP; - key.addr[0] = h->ip_src; - key.port[0] = ih->icmp_id; - key.addr[1] = h->ip_dst; - key.port[1] = ih->icmp_id; + key.af = pd->af; + key.proto = pd->proto; + PF_ACPY(&key.addr[0], saddr, key.af); + PF_ACPY(&key.addr[1], daddr, key.af); + key.port[0] = icmpid; + key.port[1] = icmpid; if (direction == PF_IN) *state = pf_find_state(tree_ext_gwy, &key); @@ -3210,47 +3811,139 @@ pf_test_state_icmp(struct pf_state **state, int direction, struct ifnet *ifp, return (PF_DROP); (*state)->packets++; - (*state)->bytes += h->ip_len; + (*state)->bytes += pd->tot_len; (*state)->expire = pftv.tv_sec + pftm_icmp_error_reply; /* translate source/destination address, if needed */ - if ((*state)->lan.addr != (*state)->gwy.addr) { - if (direction == PF_OUT) - pf_change_a(&h->ip_src.s_addr, - &h->ip_sum, (*state)->gwy.addr, 0); - else - pf_change_a(&h->ip_dst.s_addr, - &h->ip_sum, (*state)->lan.addr, 0); + if (PF_ANEQ(&(*state)->lan.addr, &(*state)->gwy.addr, pd->af)) { + if (direction == PF_OUT) { + switch (pd->af) { +#ifdef INET + case AF_INET: + pf_change_a(&saddr->v4.s_addr, + pd->ip_sum, + (*state)->gwy.addr.v4.s_addr, 0); + break; +#endif /* INET */ +#ifdef INET6 + case AF_INET6: + pf_change_a6(saddr, + &pd->hdr.icmp6->icmp6_cksum, + &(*state)->gwy.addr, 0); + break; +#endif /* INET6 */ + } + } else { + switch (pd->af) { +#ifdef INET + case AF_INET: + pf_change_a(&daddr->v4.s_addr, + pd->ip_sum, + (*state)->lan.addr.v4.s_addr, 0); + break; +#endif /* INET */ +#ifdef INET6 + case AF_INET6: + pf_change_a6(daddr, + &pd->hdr.icmp6->icmp6_cksum, + &(*state)->lan.addr, 0); + break; +#endif /* INET6 */ + } + } } return (PF_PASS); } else { - /* * ICMP error message in response to a TCP/UDP packet. * Extract the inner TCP/UDP header and search for that state. */ + struct pf_pdesc pd2; +#ifdef INET struct ip h2; +#endif /* INET */ +#ifdef INET6 + struct ip6_hdr h2_6; + int terminal = 0; +#endif /* INET6 */ int ipoff2; int off2; - ipoff2 = off + ICMP_MINLEN; /* offset of h2 in mbuf chain */ - if (!pf_pull_hdr(m, ipoff2, &h2, sizeof(h2), NULL, NULL)) { - DPFPRINTF(PF_DEBUG_MISC, - ("pf: ICMP error message too short (ip)\n")); - return (PF_DROP); - } + pd2.af = pd->af; + switch (pd->af) { +#ifdef INET + case AF_INET: + /* offset of h2 in mbuf chain */ + ipoff2 = off + ICMP_MINLEN; - /* ICMP error messages don't refer to non-first fragments */ - if (h2.ip_off & IP_OFFMASK) - return (PF_DROP); + if (!pf_pull_hdr(m, ipoff2, &h2, sizeof(h2), + NULL, NULL, pd2.af)) { + DPFPRINTF(PF_DEBUG_MISC, + ("pf: ICMP error message too short (ip)\n")); + return (PF_DROP); + } + /* ICMP error messages don't refer to non-first fragments */ + if (h2.ip_off & IP_OFFMASK) + return (PF_DROP); + + /* offset of protocol header that follows h2 */ + off2 = ipoff2 + (h2.ip_hl << 2); - /* offset of protocol header that follows h2 */ - off2 = ipoff2 + (h2.ip_hl << 2); + pd2.src = (struct pf_addr *)&h2.ip_src; + pd2.dst = (struct pf_addr *)&h2.ip_dst; + pd2.ip_sum = &h2.ip_sum; + break; +#endif /* INET */ +#ifdef INET6 + case AF_INET6: + ipoff2 = off + sizeof(struct icmp6_hdr); + + if (!pf_pull_hdr(m, ipoff2, &h2_6, sizeof(h2_6), + NULL, NULL, pd2.af)) { + DPFPRINTF(PF_DEBUG_MISC, + ("pf: ICMP error message too short (ip6)\n")); + return (PF_DROP); + } + pd2.proto = h2_6.ip6_nxt; + pd2.src = (struct pf_addr *)&h2_6.ip6_src; + pd2.dst = (struct pf_addr *)&h2_6.ip6_dst; + pd2.ip_sum = NULL; + do { + while (off >= m->m_len) { + off -= m->m_len; + m = m->m_next; + } - switch (h2.ip_p) { + switch (pd2.proto) { + case IPPROTO_FRAGMENT: + /* XXX we don't handle fagments yet */ + return (PF_DROP); + case IPPROTO_AH: + case IPPROTO_HOPOPTS: + case IPPROTO_ROUTING: + case IPPROTO_DSTOPTS: { + /* get next header and header length */ + struct _opt6 *opt6; + + opt6 = (struct _opt6 *)(mtod(m, caddr_t) + off2); + pd2.proto = opt6->opt6_nxt; + off2 += (opt6->opt6_hlen + 1) * 8; + /* goto the next header */ + break; + } + default: + terminal++; + break; + } + } while (!terminal); + break; +#endif /* INET6 */ + } + + switch (pd2.proto) { case IPPROTO_TCP: { struct tcphdr th; u_int32_t seq; @@ -3262,16 +3955,17 @@ pf_test_state_icmp(struct pf_state **state, int direction, struct ifnet *ifp, * expected. Don't access any TCP header fields after * th_seq, an ackskew test is not possible. */ - if (!pf_pull_hdr(m, off2, &th, 8, NULL, NULL)) { + if (!pf_pull_hdr(m, off2, &th, 8, NULL, NULL, pd2.af)) { DPFPRINTF(PF_DEBUG_MISC, ("pf: ICMP error message too short (tcp)\n")); return (PF_DROP); } + key.af = pd2.af; key.proto = IPPROTO_TCP; - key.addr[0] = h2.ip_dst; + PF_ACPY(&key.addr[0], pd2.dst, pd2.af); key.port[0] = th.th_dport; - key.addr[1] = h2.ip_src; + PF_ACPY(&key.addr[1], pd2.src, pd2.af); key.port[1] = th.th_sport; if (direction == PF_IN) @@ -3307,22 +4001,36 @@ pf_test_state_icmp(struct pf_state **state, int direction, struct ifnet *ifp, if (STATE_TRANSLATE(*state)) { if (direction == PF_IN) { - pf_change_icmp(&h2.ip_src.s_addr, - &th.th_sport, &h->ip_dst.s_addr, - (*state)->lan.addr, + pf_change_icmp(pd2.src, &th.th_sport, + saddr, &(*state)->lan.addr, (*state)->lan.port, NULL, - &h2.ip_sum, &ih->icmp_cksum, - &h->ip_sum, 0); + pd2.ip_sum, icmpsum, + pd->ip_sum, 0, pd2.af); } else { - pf_change_icmp(&h2.ip_dst.s_addr, - &th.th_dport, &h->ip_src.s_addr, - (*state)->gwy.addr, + pf_change_icmp(pd2.dst, &th.th_dport, + saddr, &(*state)->gwy.addr, (*state)->gwy.port, NULL, - &h2.ip_sum, &ih->icmp_cksum, - &h->ip_sum, 0); + pd2.ip_sum, icmpsum, + pd->ip_sum, 0, pd2.af); + } + switch (pd2.af) { +#ifdef INET + case AF_INET: + m_copyback(m, off, ICMP_MINLEN, + (caddr_t)pd->hdr.icmp); + m_copyback(m, ipoff2, sizeof(h2), + (caddr_t)&h2); + break; +#endif /* INET */ +#ifdef INET6 + case AF_INET6: + m_copyback(m, off, ICMP_MINLEN, + (caddr_t)pd->hdr.icmp6); + m_copyback(m, ipoff2, sizeof(h2_6), + (caddr_t)&h2_6); + break; +#endif /* INET6 */ } - m_copyback(m, off, ICMP_MINLEN, (caddr_t)ih); - m_copyback(m, ipoff2, sizeof(h2), (caddr_t)&h2); m_copyback(m, off2, 8, (caddr_t)&th); } else if (src->seqdiff) { m_copyback(m, off2, 8, (caddr_t)&th); @@ -3336,16 +4044,17 @@ pf_test_state_icmp(struct pf_state **state, int direction, struct ifnet *ifp, struct pf_tree_key key; if (!pf_pull_hdr(m, off2, &uh, sizeof(uh), - NULL, NULL)) { + NULL, NULL, pd2.af)) { DPFPRINTF(PF_DEBUG_MISC, ("pf: ICMP error message too short (udp)\n")); return (PF_DROP); } + key.af = pd2.af; key.proto = IPPROTO_UDP; - key.addr[0] = h2.ip_dst; + PF_ACPY(&key.addr[0], pd2.dst, pd2.af); key.port[0] = uh.uh_dport; - key.addr[1] = h2.ip_src; + PF_ACPY(&key.addr[1], pd2.src, pd2.af); key.port[1] = uh.uh_sport; if (direction == PF_IN) @@ -3357,23 +4066,36 @@ pf_test_state_icmp(struct pf_state **state, int direction, struct ifnet *ifp, if (STATE_TRANSLATE(*state)) { if (direction == PF_IN) { - pf_change_icmp(&h2.ip_src.s_addr, - &uh.uh_sport, &h->ip_dst.s_addr, - (*state)->lan.addr, + pf_change_icmp(pd2.src, &uh.uh_sport, + daddr, &(*state)->lan.addr, (*state)->lan.port, &uh.uh_sum, - &h2.ip_sum, &ih->icmp_cksum, - &h->ip_sum, 1); + pd2.ip_sum, icmpsum, + pd->ip_sum, 1, pd2.af); } else { - pf_change_icmp(&h2.ip_dst.s_addr, - &uh.uh_dport, &h->ip_src.s_addr, - (*state)->gwy.addr, + pf_change_icmp(pd2.dst, &uh.uh_dport, + saddr, &(*state)->gwy.addr, (*state)->gwy.port, &uh.uh_sum, - &h2.ip_sum, &ih->icmp_cksum, - &h->ip_sum, 1); + pd2.ip_sum, icmpsum, + pd->ip_sum, 1, pd2.af); + } + switch (pd2.af) { +#ifdef INET + case AF_INET: + m_copyback(m, off, ICMP_MINLEN, + (caddr_t)pd->hdr.icmp); + m_copyback(m, ipoff2, sizeof(h2), + (caddr_t)&h2); + break; +#endif /* INET */ +#ifdef INET6 + case AF_INET6: + m_copyback(m, off, ICMP_MINLEN, + (caddr_t)pd->hdr.icmp6); + m_copyback(m, ipoff2, sizeof(h2_6), + (caddr_t)&h2_6); + break; +#endif /* INET6 */ } - m_copyback(m, off, ICMP_MINLEN, (caddr_t)ih); - m_copyback(m, ipoff2, sizeof(h2), - (caddr_t)&h2); m_copyback(m, off2, sizeof(uh), (caddr_t)&uh); } @@ -3381,21 +4103,23 @@ pf_test_state_icmp(struct pf_state **state, int direction, struct ifnet *ifp, return (PF_PASS); break; } +#ifdef INET case IPPROTO_ICMP: { struct icmp iih; struct pf_tree_key key; if (!pf_pull_hdr(m, off2, &iih, ICMP_MINLEN, - NULL, NULL)) { + NULL, NULL, pd2.af)) { DPFPRINTF(PF_DEBUG_MISC, ("pf: ICMP error message too short (icmp)\n")); return (PF_DROP); } + key.af = pd2.af; key.proto = IPPROTO_ICMP; - key.addr[0] = h2.ip_dst; + PF_ACPY(&key.addr[0], pd2.dst, pd2.af); key.port[0] = iih.icmp_id; - key.addr[1] = h2.ip_src; + PF_ACPY(&key.addr[1], pd2.src, pd2.af); key.port[1] = iih.icmp_id; if (direction == PF_IN) @@ -3407,21 +4131,20 @@ pf_test_state_icmp(struct pf_state **state, int direction, struct ifnet *ifp, if (STATE_TRANSLATE(*state)) { if (direction == PF_IN) { - pf_change_icmp(&h2.ip_src.s_addr, - &iih.icmp_id, &h->ip_dst.s_addr, - (*state)->lan.addr, + pf_change_icmp(pd2.src, &iih.icmp_id, + daddr, &(*state)->lan.addr, (*state)->lan.port, NULL, - &h2.ip_sum, &ih->icmp_cksum, - &h->ip_sum, 0); + pd2.ip_sum, icmpsum, + pd->ip_sum, 0, AF_INET); } else { - pf_change_icmp(&h2.ip_dst.s_addr, - &iih.icmp_id, &h->ip_src.s_addr, - (*state)->gwy.addr, + pf_change_icmp(pd2.dst, &iih.icmp_id, + saddr, &(*state)->gwy.addr, (*state)->gwy.port, NULL, - &h2.ip_sum, &ih->icmp_cksum, - &h->ip_sum, 0); + pd2.ip_sum, icmpsum, + pd->ip_sum, 0, AF_INET); } - m_copyback(m, off, ICMP_MINLEN, (caddr_t)ih); + m_copyback(m, off, ICMP_MINLEN, + (caddr_t)pd->hdr.icmp); m_copyback(m, ipoff2, sizeof(h2), (caddr_t)&h2); m_copyback(m, off2, ICMP_MINLEN, @@ -3431,6 +4154,59 @@ pf_test_state_icmp(struct pf_state **state, int direction, struct ifnet *ifp, return (PF_PASS); break; } +#endif /* INET */ +#ifdef INET6 + case IPPROTO_ICMPV6: { + struct icmp6_hdr iih; + struct pf_tree_key key; + + if (!pf_pull_hdr(m, off2, &iih, ICMP_MINLEN, + NULL, NULL, pd2.af)) { + DPFPRINTF(PF_DEBUG_MISC, + ("pf: ICMP error message too short (icmp6)\n")); + return (PF_DROP); + } + + key.af = pd2.af; + key.proto = IPPROTO_ICMPV6; + PF_ACPY(&key.addr[0], pd2.dst, pd2.af); + key.port[0] = iih.icmp6_id; + PF_ACPY(&key.addr[1], pd2.src, pd2.af); + key.port[1] = iih.icmp6_id; + + if (direction == PF_IN) + *state = pf_find_state(tree_ext_gwy, &key); + else + *state = pf_find_state(tree_lan_ext, &key); + if (*state == NULL) + return (PF_DROP); + + if (STATE_TRANSLATE(*state)) { + if (direction == PF_IN) { + pf_change_icmp(pd2.src, &iih.icmp6_id, + daddr, &(*state)->lan.addr, + (*state)->lan.port, NULL, + pd2.ip_sum, icmpsum, + pd->ip_sum, 0, AF_INET6); + } else { + pf_change_icmp(pd2.dst, &iih.icmp6_id, + saddr, &(*state)->gwy.addr, + (*state)->gwy.port, NULL, + pd2.ip_sum, icmpsum, + pd->ip_sum, 0, AF_INET6); + } + m_copyback(m, off, ICMP_MINLEN, + (caddr_t)pd->hdr.icmp6); + m_copyback(m, ipoff2, sizeof(h2_6), + (caddr_t)&h2_6); + m_copyback(m, off2, ICMP_MINLEN, + (caddr_t)&iih); + } + + return (PF_PASS); + break; + } +#endif /* INET6 */ default: DPFPRINTF(PF_DEBUG_MISC, ("pf: ICMP error message for bad proto\n")); @@ -3446,29 +4222,47 @@ pf_test_state_icmp(struct pf_state **state, int direction, struct ifnet *ifp, */ void * pf_pull_hdr(struct mbuf *m, int off, void *p, int len, - u_short *actionp, u_short *reasonp) + u_short *actionp, u_short *reasonp, int af) { - struct ip *h = mtod(m, struct ip *); - u_int16_t fragoff = (h->ip_off & IP_OFFMASK) << 3; - - if (fragoff) { - if (fragoff >= len) - ACTION_SET(actionp, PF_PASS); - else { + switch (af) { +#ifdef INET + case AF_INET: { + struct ip *h = mtod(m, struct ip *); + u_int16_t fragoff = (h->ip_off & IP_OFFMASK) << 3; + + if (fragoff) { + if (fragoff >= len) + ACTION_SET(actionp, PF_PASS); + else { + ACTION_SET(actionp, PF_DROP); + REASON_SET(reasonp, PFRES_FRAG); + } + return (NULL); + } + if (m->m_pkthdr.len < off + len || h->ip_len < off + len) { ACTION_SET(actionp, PF_DROP); - REASON_SET(reasonp, PFRES_FRAG); + REASON_SET(reasonp, PFRES_SHORT); + return (NULL); } - return (NULL); } - if (m->m_pkthdr.len < off + len || h->ip_len < off + len) { - ACTION_SET(actionp, PF_DROP); - REASON_SET(reasonp, PFRES_SHORT); - return (NULL); +#endif /* INET */ +#ifdef INET6 + case AF_INET6: { + struct ip6_hdr *h = mtod(m, struct ip6_hdr *); + if (m->m_pkthdr.len < off + len || + (ntohs(h->ip6_plen) + sizeof(struct ip6_hdr)) < off + len) { + ACTION_SET(actionp, PF_DROP); + REASON_SET(reasonp, PFRES_SHORT); + return (NULL); + } + } +#endif /* INET6 */ } m_copydata(m, off, len, p); return (p); } +#ifdef INET int pf_test(int dir, struct ifnet *ifp, struct mbuf **m0) { @@ -3477,6 +4271,7 @@ pf_test(int dir, struct ifnet *ifp, struct mbuf **m0) struct ip *h; struct pf_rule *r = NULL; struct pf_state *s = NULL; + struct pf_pdesc pd; int off; if (!pf_status.running || @@ -3519,51 +4314,65 @@ pf_test(int dir, struct ifnet *ifp, struct mbuf **m0) goto done; } + pd.src = (struct pf_addr *)&h->ip_src; + pd.dst = (struct pf_addr *)&h->ip_dst; + pd.ip_sum = &h->ip_sum; + pd.proto = h->ip_p; + pd.af = AF_INET; + pd.tot_len = h->ip_len; + switch (h->ip_p) { case IPPROTO_TCP: { struct tcphdr th; + pd.hdr.tcp = &th; - if (!pf_pull_hdr(m, off, &th, sizeof(th), &action, &reason)) { + if (!pf_pull_hdr(m, off, &th, sizeof(th), + &action, &reason, AF_INET)) { log = action != PF_PASS; goto done; } - action = pf_normalize_tcp(dir, ifp, m, 0, off, h, &th); + pd.p_len = pd.tot_len - off - (th.th_off << 2); + action = pf_normalize_tcp(dir, ifp, m, 0, off, h, &pd); if (action == PF_DROP) break; - action = pf_test_state_tcp(&s, dir, ifp, m, 0, off, h , &th); + action = pf_test_state_tcp(&s, dir, ifp, m, 0, off, h, &pd); if (action == PF_PASS) { r = s->rule; log = s->log; } else if (s == NULL) - action = pf_test_tcp(dir, ifp, m, 0, off, h , &th); + action = pf_test_tcp(dir, ifp, m, 0, off, h, &pd); break; } case IPPROTO_UDP: { struct udphdr uh; + pd.hdr.udp = &uh; - if (!pf_pull_hdr(m, off, &uh, sizeof(uh), &action, &reason)) { + if (!pf_pull_hdr(m, off, &uh, sizeof(uh), + &action, &reason, AF_INET)) { log = action != PF_PASS; goto done; } - action = pf_test_state_udp(&s, dir, ifp, m, 0, off, h, &uh); + action = pf_test_state_udp(&s, dir, ifp, m, 0, off, h, &pd); if (action == PF_PASS) { r = s->rule; log = s->log; } else if (s == NULL) - action = pf_test_udp(dir, ifp, m, 0, off, h, &uh); + action = pf_test_udp(dir, ifp, m, 0, off, h, &pd); break; } case IPPROTO_ICMP: { struct icmp ih; + pd.hdr.icmp = &ih; - if (!pf_pull_hdr(m, off, &ih, ICMP_MINLEN, &action, &reason)) { + if (!pf_pull_hdr(m, off, &ih, ICMP_MINLEN, + &action, &reason, AF_INET)) { log = action != PF_PASS; goto done; } - action = pf_test_state_icmp(&s, dir, ifp, m, 0, off, h, &ih); + action = pf_test_state_icmp(&s, dir, ifp, m, 0, off, h, &pd); if (action == PF_PASS) { r = s->rule; if (r != NULL) { @@ -3572,18 +4381,18 @@ pf_test(int dir, struct ifnet *ifp, struct mbuf **m0) } log = s->log; } else if (s == NULL) - action = pf_test_icmp(dir, ifp, m, 0, off, h, &ih); + action = pf_test_icmp(dir, ifp, m, 0, off, h, &pd); break; } default: - action = pf_test_other(dir, ifp, m, h); + action = pf_test_other(dir, ifp, m, h, &pd); break; } if (ifp == status_ifp) { - pf_status.bcounters[dir] += h->ip_len; - pf_status.pcounters[dir][action]++; + pf_status.bcounters[0][dir] += pd.tot_len; + pf_status.pcounters[0][dir][action]++; } done: @@ -3600,3 +4409,172 @@ done: } return (action); } +#endif /* INET */ + +#ifdef INET6 +int +pf_test6(int dir, struct ifnet *ifp, struct mbuf **m0) +{ + u_short action, reason = 0, log = 0; + struct mbuf *m = *m0; + struct ip6_hdr *h; + struct pf_rule *r = NULL; + struct pf_state *s = NULL; + struct pf_pdesc pd; + int off, terminal = 0; + + if (!pf_status.running || + (m_tag_find(m, PACKET_TAG_PF_GENERATED, NULL) != NULL)) + return (PF_PASS); + +#ifdef DIAGNOSTIC + if ((m->m_flags & M_PKTHDR) == 0) + panic("non-M_PKTHDR is passed to pf_test"); +#endif + + /* purge expire states */ + microtime(&pftv); + if (pftv.tv_sec - pf_last_purge >= pftm_interval) { + pf_purge_expired_states(); + pf_purge_expired_fragments(); + pf_last_purge = pftv.tv_sec; + } + + if (m->m_pkthdr.len < sizeof(*h)) { + action = PF_DROP; + REASON_SET(&reason, PFRES_SHORT); + log = 1; + goto done; + } + + m = *m0; + h = mtod(m, struct ip6_hdr *); + + pd.src = (struct pf_addr *)&h->ip6_src; + pd.dst = (struct pf_addr *)&h->ip6_dst; + pd.ip_sum = NULL; + pd.af = AF_INET6; + pd.tot_len = ntohs(h->ip6_plen) + sizeof(struct ip6_hdr); + + off = ((caddr_t)h - m->m_data) + sizeof(struct ip6_hdr); + pd.proto = h->ip6_nxt; + do { + while (off >= m->m_len) { + off -= m->m_len; + m = m->m_next; + } + + switch (pd.proto) { + case IPPROTO_FRAGMENT: + /* XXX we don't handle fragments yet */ + action = PF_DROP; + REASON_SET(&reason, PFRES_FRAG); + goto done; + case IPPROTO_AH: + case IPPROTO_HOPOPTS: + case IPPROTO_ROUTING: + case IPPROTO_DSTOPTS: { + /* get next header and header length */ + struct _opt6 *opt6; + + opt6 = (struct _opt6 *)(mtod(m, caddr_t) + off); + pd.proto = opt6->opt6_nxt; + off += (opt6->opt6_hlen + 1) * 8; + /* goto the next header */ + break; + } + default: + terminal++; + break; + } + } while (!terminal); + + switch (pd.proto) { + + case IPPROTO_TCP: { + struct tcphdr th; + pd.hdr.tcp = &th; + + if (!pf_pull_hdr(m, off, &th, sizeof(th), + &action, &reason, AF_INET6)) { + log = action != PF_PASS; + goto done; + } + pd.p_len = pd.tot_len - off - (th.th_off << 2); + action = pf_normalize_tcp(dir, ifp, m, 0, off, h, &pd); + if (action == PF_DROP) + break; + action = pf_test_state_tcp(&s, dir, ifp, m, 0, off, h, &pd); + if (action == PF_PASS) { + r = s->rule; + log = s->log; + } else if (s == NULL) + action = pf_test_tcp(dir, ifp, m, 0, off, h, &pd); + break; + } + + case IPPROTO_UDP: { + struct udphdr uh; + pd.hdr.udp = &uh; + + if (!pf_pull_hdr(m, off, &uh, sizeof(uh), + &action, &reason, AF_INET6)) { + log = action != PF_PASS; + goto done; + } + action = pf_test_state_udp(&s, dir, ifp, m, 0, off, h, &pd); + if (action == PF_PASS) { + r = s->rule; + log = s->log; + } else if (s == NULL) + action = pf_test_udp(dir, ifp, m, 0, off, h, &pd); + break; + } + + case IPPROTO_ICMPV6: { + struct icmp6_hdr ih; + pd.hdr.icmp6 = &ih; + + if (!pf_pull_hdr(m, off, &ih, sizeof(&ih), + &action, &reason, AF_INET6)) { + log = action != PF_PASS; + goto done; + } + action = pf_test_state_icmp(&s, dir, ifp, m, 0, off, h, &pd); + if (action == PF_PASS) { + r = s->rule; + if (r != NULL) { + r->packets++; + r->bytes += h->ip6_plen; + } + log = s->log; + } else if (s == NULL) + action = pf_test_icmp(dir, ifp, m, 0, off, h, &pd); + break; + } + + default: + action = pf_test_other(dir, ifp, m, h, &pd); + break; + } + + if (ifp == status_ifp) { + pf_status.bcounters[1][dir] += h->ip6_plen; + pf_status.pcounters[1][dir][action]++; + } + +done: + if (log) { + struct pf_rule r0; + + if (r == NULL) { + r0.ifp = ifp; + r0.action = action; + r0.nr = -1; + r = &r0; + } + PFLOG_PACKET(h, m, AF_INET6, dir, reason, r); + } + return (action); +} +#endif /* INET6 */ diff --git a/sys/net/pf_norm.c b/sys/net/pf_norm.c index 8663998cc76..b95bf74b33a 100644 --- a/sys/net/pf_norm.c +++ b/sys/net/pf_norm.c @@ -1,4 +1,4 @@ -/* $OpenBSD: pf_norm.c,v 1.10 2001/09/08 02:10:33 provos Exp $ */ +/* $OpenBSD: pf_norm.c,v 1.11 2001/09/15 03:54:40 frantzen Exp $ */ /* * Copyright 2001 Niels Provos <provos@citi.umich.edu> @@ -88,7 +88,7 @@ struct mbuf *pf_reassemble(struct mbuf **, struct pf_fragment *, struct pf_frent *, int); u_int16_t pf_cksum_fixup(u_int16_t, u_int16_t, u_int16_t); int pf_normalize_tcp(int, struct ifnet *, struct mbuf *, - int, int, struct ip *, struct tcphdr *); + int, int, void *, struct pf_pdesc *); #define PFFRAG_FRENT_HIWAT 5000 /* Number of fragment entries */ #define PFFRAG_FRAG_HIWAT 1000 /* Number of fragmented packets */ @@ -96,14 +96,18 @@ int pf_normalize_tcp(int, struct ifnet *, struct mbuf *, #define DPFPRINTF(x) if (pf_status.debug) printf x #if NPFLOG > 0 -#define PFLOG_PACKET(x,a,b,c,d,e) \ - do { \ - HTONS((x)->ip_len); \ - HTONS((x)->ip_off); \ - pflog_packet(a,b,c,d,e); \ - NTOHS((x)->ip_len); \ - NTOHS((x)->ip_off); \ - } while (0) +#define PFLOG_PACKET(x,a,b,c,d,e) \ + do { \ + if (b == AF_INET) { \ + HTONS(((struct ip *)x)->ip_len); \ + HTONS(((struct ip *)x)->ip_off); \ + pflog_packet(a,b,c,d,e); \ + NTOHS(((struct ip *)x)->ip_len); \ + NTOHS(((struct ip *)x)->ip_off); \ + } else { \ + pflog_packet(a,b,c,d,e); \ + } \ + } while (0) #else #define PFLOG_PACKET(x,a,b,c,d,e) ((void)0) #endif @@ -194,8 +198,9 @@ void pf_ip2key(struct pf_tree_key *key, struct ip *ip) { key->proto = ip->ip_p; - key->addr[0] = ip->ip_src; - key->addr[1] = ip->ip_dst; + key->af = AF_INET; + key->addr[0].addr32[0] = ip->ip_src.s_addr; + key->addr[1].addr32[0] = ip->ip_dst.s_addr; key->port[0] = ip->ip_id; key->port[1] = 0; } @@ -227,8 +232,8 @@ pf_remove_fragment(struct pf_fragment *frag) struct pf_tree_key key; key.proto = frag->fr_p; - key.addr[0] = frag->fr_src; - key.addr[1] = frag->fr_dst; + key.addr[0].addr32[0] = frag->fr_src.s_addr; + key.addr[1].addr32[0] = frag->fr_dst.s_addr; key.port[0] = frag->fr_id; key.port[1] = 0; @@ -440,7 +445,7 @@ pf_normalize_ip(struct mbuf **m0, int dir, struct ifnet *ifp, u_short *reason) TAILQ_FOREACH(r, pf_rules_active, entries) { if ((r->action == PF_SCRUB) && - MATCH_TUPLE(h, r, dir, ifp)) + MATCH_TUPLE(h, r, dir, ifp, AF_INET)) break; } @@ -549,11 +554,12 @@ pf_normalize_ip(struct mbuf **m0, int dir, struct ifnet *ifp, u_short *reason) int pf_normalize_tcp(int dir, struct ifnet *ifp, struct mbuf *m, int ipoff, - int off, struct ip *h, struct tcphdr *th) + int off, void *h, struct pf_pdesc *pd) { struct pf_rule *r, *rm = NULL; + struct tcphdr *th = pd->hdr.tcp; int rewrite = 0, reason; - u_int8_t flags; + u_int8_t flags, af = pd->af; r = TAILQ_FIRST(pf_rules_active); while (r != NULL) { @@ -563,20 +569,25 @@ pf_normalize_tcp(int dir, struct ifnet *ifp, struct mbuf *m, int ipoff, } if (r->ifp != NULL && r->ifp != ifp) r = r->skip[0]; - else if (r->proto && r->proto != h->ip_p) + else if (r->af && r->af != af) r = r->skip[1]; - else if (r->src.mask && !pf_match_addr(r->src.not, - r->src.addr, r->src.mask, h->ip_src.s_addr)) + else if (r->proto && r->proto != pd->proto) r = r->skip[2]; + else if (!PF_AZERO(&r->src.mask, af) && + !PF_MATCHA(r->src.not, &r->src.addr, &r->src.mask, + pd->src, af)) + r = r->skip[3]; else if (r->src.port_op && !pf_match_port(r->src.port_op, r->src.port[0], r->src.port[1], th->th_sport)) - r = r->skip[3]; - else if (r->dst.mask && !pf_match_addr(r->dst.not, - r->dst.addr, r->dst.mask, h->ip_dst.s_addr)) r = r->skip[4]; + else if (!PF_AZERO(&r->dst.mask, af) && + !PF_MATCHA(r->dst.not, + &r->dst.addr, &r->dst.mask, + pd->dst, af)) + r = r->skip[5]; else if (r->dst.port_op && !pf_match_port(r->dst.port_op, r->dst.port[0], r->dst.port[1], th->th_dport)) - r = r->skip[5]; + r = r->skip[6]; else if (r->direction != dir) r = TAILQ_NEXT(r, entries); else if (r->ifp != NULL && r->ifp != ifp) diff --git a/sys/net/pfvar.h b/sys/net/pfvar.h index 2f761dd6687..2aa6f33118f 100644 --- a/sys/net/pfvar.h +++ b/sys/net/pfvar.h @@ -1,4 +1,4 @@ -/* $OpenBSD: pfvar.h,v 1.50 2001/09/06 18:05:46 jasoni Exp $ */ +/* $OpenBSD: pfvar.h,v 1.51 2001/09/15 03:54:40 frantzen Exp $ */ /* * Copyright (c) 2001 Daniel Hartmeier @@ -50,9 +50,137 @@ enum { PFTM_TCP_FIRST_PACKET=0, PFTM_TCP_OPENING=1, PFTM_TCP_ESTABLISHED=2, PFTM_ICMP_FIRST_PACKET=9, PFTM_ICMP_ERROR_REPLY=10, PFTM_FRAG=11, PFTM_INTERVAL=12, PFTM_MAX=13 }; +struct pf_addr { + union { + struct in_addr v4; + struct in6_addr v6; + u_int8_t addr8[16]; + u_int16_t addr16[8]; + u_int32_t addr32[4]; + } pfa; /* 128-bit address */ +#define v4 pfa.v4 +#define v6 pfa.v6 +#define addr8 pfa.addr8 +#define addr16 pfa.addr16 +#define addr32 pfa.addr32 +}; + +/* + * Address manipulation macros + */ + +#ifdef _KERNEL + +#ifdef INET +#ifndef INET6 +#define PF_INET_ONLY +#endif /* ! INET6 */ +#endif /* INET */ + +#ifdef INET6 +#ifndef INET +#define PF_INET6_ONLY +#endif /* ! INET */ +#endif /* INET6 */ + +#ifdef INET +#ifdef INET6 +#define PF_INET_INET6 +#endif /* INET6 */ +#endif /* INET */ + +#else + +#define PF_INET_INET6 + +#endif /* _KERNEL */ + +/* Both IPv4 and IPv6 */ +#ifdef PF_INET_INET6 + +#define PF_AEQ(a, b, c) \ + ((c == AF_INET && (a)->addr32[0] == (b)->addr32[0]) || \ + (c == AF_INET6 && (a)->addr32[0] == (b)->addr32[0] && \ + (a)->addr32[1] == (b)->addr32[1] && \ + (a)->addr32[2] == (b)->addr32[2] && \ + (a)->addr32[3] == (b)->addr32[3])) \ + +#define PF_ANEQ(a, b, c) \ + ((c == AF_INET && (a)->addr32[0] != (b)->addr32[0]) || \ + (c == AF_INET6 && ((a)->addr32[0] != (b)->addr32[0] || \ + (a)->addr32[1] != (b)->addr32[1] || \ + (a)->addr32[2] != (b)->addr32[2] || \ + (a)->addr32[3] != (b)->addr32[3]))) \ + +#define PF_AZERO(a, c) \ + ((c == AF_INET && !(a)->addr32[0]) || \ + (c == AF_INET6 && !(a)->addr32[0] && \ + !(a)->addr32[1] && !(a)->addr32[2] && \ + !(a)->addr32[3] )) \ + +#define PF_MATCHA(n, a, m, b, f) \ + pf_match_addr(n, a, m, b, f) + +#define PF_ACPY(a, b, f) \ + pf_addrcpy(a, b, f) + +#else + +/* Just IPv6 */ +#ifdef PF_INET6_ONLY + +#define PF_AEQ(a, b, c) \ + ((a)->addr32[0] == (b)->addr32[0] && \ + (a)->addr32[1] == (b)->addr32[1] && \ + (a)->addr32[2] == (b)->addr32[2] && \ + (a)->addr32[3] == (b)->addr32[3]) \ + +#define PF_ANEQ(a, b, c) \ + ((a)->addr32[0] != (b)->addr32[0] || \ + (a)->addr32[1] != (b)->addr32[1] || \ + (a)->addr32[2] != (b)->addr32[2] || \ + (a)->addr32[3] != (b)->addr32[3]) \ + +#define PF_AZERO(a, c) \ + (!(a)->addr32[0] && \ + !(a)->addr32[1] && \ + !(a)->addr32[2] && \ + !(a)->addr32[3] ) \ + +#define PF_MATCHA(n, a, m, b, f) \ + pf_match_addr(n, a, m, b, f) + +#define PF_ACPY(a, b, f) \ + pf_addrcpy(a, b, f) + +#else + +/* Just IPv4 */ +#ifdef PF_INET_ONLY + +#define PF_AEQ(a, b, c) \ + ((a)->addr32[0] == (b)->addr32[0]) + +#define PF_ANEQ(a, b, c) \ + ((a)->addr32[0] != (b)->addr32[0]) + +#define PF_AZERO(a, c) \ + (!(a)->addr32[0]) + +#define PF_MATCHA(n, a, m, b, f) \ + pf_match_addr(n, a, m, b, f) + +#define PF_ACPY(a, b, f) \ + (a)->v4.s_addr = (b)->v4.s_addr + + +#endif /* PF_INET_ONLY */ +#endif /* PF_INET6_ONLY */ +#endif /* PF_INET_INET6 */ + struct pf_rule_addr { - u_int32_t addr; - u_int32_t mask; + struct pf_addr addr; + struct pf_addr mask; u_int16_t port[2]; u_int8_t not; u_int8_t port_op; @@ -81,9 +209,11 @@ struct pf_rule { #define PF_STATE_NORMAL 0x1 #define PF_STATE_MODULATE 0x2 u_int8_t keep_state; + u_int8_t af; u_int8_t proto; u_int8_t type; u_int8_t code; + u_int8_t flags; u_int8_t flagset; @@ -96,7 +226,7 @@ struct pf_rule { #define PFRULE_NODF 0x02 struct pf_state_host { - u_int32_t addr; + struct pf_addr addr; u_int16_t port; }; @@ -120,31 +250,35 @@ struct pf_state { u_int32_t expire; u_int32_t packets; u_int32_t bytes; + u_int8_t af; u_int8_t proto; u_int8_t direction; u_int8_t log; }; -#define MATCH_TUPLE(h,r,d,i) \ +#define MATCH_TUPLE(h,r,d,i,a) \ ( \ (r->direction == d) && \ (r->ifp == NULL || r->ifp == i) && \ (!r->proto || r->proto == h->ip_p) && \ - (!r->src.mask || pf_match_addr(r->src.not, r->src.addr, \ - r->src.mask, h->ip_src.s_addr)) && \ - (!r->dst.mask || pf_match_addr(r->dst.not, r->dst.addr, \ - r->dst.mask, h->ip_dst.s_addr)) \ + (!r->src.mask.addr32[0] || \ + pf_match_addr(r->src.not, &(r)->src.addr, \ + &(r)->src.mask, (struct pf_addr *)&h->ip_src.s_addr, a)) && \ + (!r->dst.mask.addr32[0] || \ + pf_match_addr(r->dst.not, &(r)->dst.addr, \ + &(r)->dst.mask, (struct pf_addr *)&h->ip_dst.s_addr, a)) \ ) struct pf_nat { char ifname[IFNAMSIZ]; struct ifnet *ifp; TAILQ_ENTRY(pf_nat) entries; - u_int32_t saddr; - u_int32_t smask; - u_int32_t daddr; - u_int32_t dmask; - u_int32_t raddr; + struct pf_addr saddr; + struct pf_addr smask; + struct pf_addr daddr; + struct pf_addr dmask; + struct pf_addr raddr; + u_int8_t af; u_int8_t proto; u_int8_t snot; u_int8_t dnot; @@ -155,10 +289,11 @@ struct pf_binat { char ifname[IFNAMSIZ]; struct ifnet *ifp; TAILQ_ENTRY(pf_binat) entries; - u_int32_t saddr; - u_int32_t daddr; - u_int32_t dmask; - u_int32_t raddr; + struct pf_addr saddr; + struct pf_addr daddr; + struct pf_addr dmask; + struct pf_addr raddr; + u_int8_t af; u_int8_t proto; u_int8_t dnot; }; @@ -167,14 +302,15 @@ struct pf_rdr { char ifname[IFNAMSIZ]; struct ifnet *ifp; TAILQ_ENTRY(pf_rdr) entries; - u_int32_t saddr; - u_int32_t smask; - u_int32_t daddr; - u_int32_t dmask; - u_int32_t raddr; + struct pf_addr saddr; + struct pf_addr smask; + struct pf_addr daddr; + struct pf_addr dmask; + struct pf_addr raddr; u_int16_t dport; u_int16_t dport2; u_int16_t rport; + u_int8_t af; u_int8_t proto; u_int8_t snot; u_int8_t dnot; @@ -183,13 +319,36 @@ struct pf_rdr { }; struct pf_tree_key { - struct in_addr addr[2]; + struct pf_addr addr[2]; u_int16_t port[2]; u_int8_t proto; + u_int8_t af; }; TAILQ_HEAD(pf_rulequeue, pf_rule); +struct pf_pdesc { + struct pf_addr *src; + struct pf_addr *dst; + u_int16_t *ip_sum; + u_int64_t tot_len; /* Make Mickey money */ + u_int32_t p_len; /* total length of payload */ + + u_int16_t flags; /* Let SCRUB trigger behavior in + * state code. Easier than tags */ + u_int8_t af; + u_int8_t proto; + union { + struct tcphdr *tcp; + struct udphdr *udp; + struct icmp *icmp; +#ifdef INET6 + struct icmp6_hdr *icmp6; +#endif /* INET6 */ + void *any; + } hdr; +}; + /* flags for RDR options */ #define PF_DPORT_RANGE 0x01 /* Dest port uses range */ #define PF_RPORT_RANGE 0x02 /* RDR'ed port uses range */ @@ -242,8 +401,8 @@ TAILQ_HEAD(pf_rulequeue, pf_rule); struct pf_status { u_int64_t counters[PFRES_MAX]; u_int64_t fcounters[FCNT_MAX]; - u_int64_t pcounters[2][3]; - u_int64_t bcounters[2]; + u_int64_t pcounters[2][2][3]; + u_int64_t bcounters[2][2]; u_int32_t running; u_int32_t states; u_int32_t since; @@ -279,14 +438,15 @@ struct pfioc_changenat { }; struct pfioc_natlook { - u_int32_t saddr; - u_int32_t daddr; - u_int32_t rsaddr; - u_int32_t rdaddr; + struct pf_addr saddr; + struct pf_addr daddr; + struct pf_addr rsaddr; + struct pf_addr rdaddr; u_int16_t sport; u_int16_t dport; u_int16_t rsport; u_int16_t rdport; + u_int8_t af; u_int8_t proto; u_int8_t direction; }; @@ -298,9 +458,9 @@ struct pfioc_binat { }; struct pfioc_changebinat { - u_int32_t action; - struct pf_binat oldbinat; - struct pf_binat newbinat; + u_int32_t action; + struct pf_binat oldbinat; + struct pf_binat newbinat; }; struct pfioc_rdr { @@ -382,7 +542,13 @@ struct pfioc_tm { #ifdef _KERNEL +#ifdef INET int pf_test(int, struct ifnet *, struct mbuf **); +#endif /* INET */ + +#ifdef INET6 +int pf_test6(int, struct ifnet *, struct mbuf **); +#endif /* INET */ struct pf_tree_node; struct pf_state @@ -393,7 +559,8 @@ int pf_tree_remove(struct pf_tree_node **, struct pf_tree_node *, struct pf_tree_key *); int pflog_packet(struct mbuf *, int, u_short, u_short, struct pf_rule *); -int pf_match_addr(u_int8_t, u_int32_t, u_int32_t, u_int32_t); +int pf_match_addr(u_int8_t, struct pf_addr *, struct pf_addr *, + struct pf_addr *, int); int pf_match_port(u_int8_t, u_int16_t, u_int16_t, u_int16_t); void pf_normalize_init(void); diff --git a/sys/netinet6/ip6_input.c b/sys/netinet6/ip6_input.c index 1ae9ff7183d..d2dd44d14f8 100644 --- a/sys/netinet6/ip6_input.c +++ b/sys/netinet6/ip6_input.c @@ -1,4 +1,4 @@ -/* $OpenBSD: ip6_input.c,v 1.32 2001/06/27 05:50:07 kjc Exp $ */ +/* $OpenBSD: ip6_input.c,v 1.33 2001/09/15 03:54:40 frantzen Exp $ */ /* $KAME: ip6_input.c,v 1.188 2001/03/29 05:34:31 itojun Exp $ */ /* @@ -65,6 +65,8 @@ * @(#)ip_input.c 8.2 (Berkeley) 1/4/94 */ +#include "pf.h" + #include <sys/param.h> #include <sys/systm.h> #include <sys/malloc.h> @@ -108,6 +110,10 @@ #include "gif.h" #include "bpfilter.h" +#if NPF > 0 +#include <net/pfvar.h> +#endif + extern struct domain inet6domain; extern struct ip6protosw inet6sw[]; @@ -255,6 +261,14 @@ ip6_input(m) IP6_EXTHDR_CHECK(m, 0, sizeof(struct ip6_hdr), /*nothing*/); #endif +#if NPF > 0 + /* + * Packet filter + */ + if (pf_test6(PF_IN, m->m_pkthdr.rcvif, &m) != PF_PASS) + goto bad; +#endif + if (m->m_len < sizeof(struct ip6_hdr)) { struct ifnet *inifp; inifp = m->m_pkthdr.rcvif; diff --git a/sys/netinet6/ip6_output.c b/sys/netinet6/ip6_output.c index 939533952b5..c195c1fc38a 100644 --- a/sys/netinet6/ip6_output.c +++ b/sys/netinet6/ip6_output.c @@ -1,4 +1,4 @@ -/* $OpenBSD: ip6_output.c,v 1.49 2001/08/22 14:18:36 niklas Exp $ */ +/* $OpenBSD: ip6_output.c,v 1.50 2001/09/15 03:54:40 frantzen Exp $ */ /* $KAME: ip6_output.c,v 1.172 2001/03/25 09:55:56 itojun Exp $ */ /* @@ -65,6 +65,8 @@ * @(#)ip_output.c 8.3 (Berkeley) 1/21/94 */ +#include "pf.h" + #include <sys/param.h> #include <sys/malloc.h> #include <sys/mbuf.h> @@ -89,6 +91,10 @@ #include <netinet6/ip6_var.h> #include <netinet6/nd6.h> +#if NPF > 0 +#include <net/pfvar.h> +#endif + #ifdef IPSEC #include <netinet/ip_ah.h> #include <netinet/ip_esp.h> @@ -874,6 +880,13 @@ skip_ipsec2:; m->m_pkthdr.rcvif = NULL; } +#if NPF > 0 + if (pf_test6(PF_OUT, ifp, &m) != PF_PASS) { + error = EHOSTUNREACH; + goto done; + } +#endif + /* * Send the packet to the outgoing interface. * If necessary, do IPv6 fragmentation before sending. |