summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--libexec/ftp-proxy/util.c10
-rw-r--r--sbin/pfctl/parse.y455
-rw-r--r--sbin/pfctl/pfctl_parser.c303
-rw-r--r--sbin/pfctl/pfctl_parser.h10
-rw-r--r--share/man/man4/pf.412
-rw-r--r--share/man/man5/pf.conf.535
-rw-r--r--sys/net/pf.c1890
-rw-r--r--sys/net/pf_norm.c59
-rw-r--r--sys/net/pfvar.h235
-rw-r--r--sys/netinet6/ip6_input.c16
-rw-r--r--sys/netinet6/ip6_output.c15
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.