summaryrefslogtreecommitdiff
path: root/sys/net/pf.c
diff options
context:
space:
mode:
Diffstat (limited to 'sys/net/pf.c')
-rw-r--r--sys/net/pf.c241
1 files changed, 226 insertions, 15 deletions
diff --git a/sys/net/pf.c b/sys/net/pf.c
index 4d5345401bf..1b811219848 100644
--- a/sys/net/pf.c
+++ b/sys/net/pf.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: pf.c,v 1.176 2001/12/03 18:47:46 dhartmei Exp $ */
+/* $OpenBSD: pf.c,v 1.177 2001/12/10 18:08:11 dhartmei Exp $ */
/*
* Copyright (c) 2001 Daniel Hartmeier
@@ -153,6 +153,10 @@ int pftm_udp_multiple = 60; /* Bidirectional */
int pftm_icmp_first_packet = 20; /* First ICMP packet */
int pftm_icmp_error_reply = 10; /* Got error response */
+int pftm_other_first_packet = 60; /* First packet */
+int pftm_other_single = 30; /* Unidirectional */
+int pftm_other_multiple = 60; /* Bidirectional */
+
int pftm_frag = 30; /* Fragment expire */
int pftm_interval = 10; /* expire interval */
@@ -163,7 +167,8 @@ int *pftm_timeouts[PFTM_MAX] = { &pftm_tcp_first_packet,
&pftm_tcp_closed, &pftm_udp_first_packet,
&pftm_udp_single, &pftm_udp_multiple,
&pftm_icmp_first_packet, &pftm_icmp_error_reply,
- &pftm_frag, &pftm_interval };
+ &pftm_other_first_packet, &pftm_other_single,
+ &pftm_other_multiple, &pftm_frag, &pftm_interval };
struct pool pf_tree_pl, pf_rule_pl, pf_nat_pl, pf_sport_pl;
@@ -241,6 +246,8 @@ int pf_test_state_udp(struct pf_state **, int,
int pf_test_state_icmp(struct pf_state **, int,
struct ifnet *, struct mbuf *, int, int,
void *, struct pf_pdesc *);
+int pf_test_state_other(struct pf_state **, int,
+ struct ifnet *, struct pf_pdesc *);
void *pf_pull_hdr(struct mbuf *, int, void *, int,
u_short *, u_short *, int);
void pf_calc_skip_steps(struct pf_rulequeue *);
@@ -2710,7 +2717,7 @@ pf_get_rdr(struct ifnet *ifp, u_int8_t proto, struct pf_addr *saddr,
(!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 && (!r->dport || dport == r->dport)) ||
(r->dport2 && (ntohs(dport) >= ntohs(r->dport)) &&
ntohs(dport) <= ntohs(r->dport2))))
rm = r;
@@ -2779,8 +2786,10 @@ pf_test_tcp(struct pf_rule **rm, int direction, struct ifnet *ifp,
bport = th->th_dport;
if (rdr->opts & PF_RPORT_RANGE)
nport = pf_map_port_range(rdr, th->th_dport);
- else
+ else if (rdr->rport)
nport = rdr->rport;
+ else
+ nport = bport;
PF_ACPY(&baddr, daddr, af);
pf_change_ap(daddr, &th->th_dport, pd->ip_sum,
&th->th_sum, &rdr->raddr, nport, 0, af);
@@ -3002,8 +3011,10 @@ pf_test_udp(struct pf_rule **rm, int direction, struct ifnet *ifp,
bport = uh->uh_dport;
if (rdr->opts & PF_RPORT_RANGE)
nport = pf_map_port_range(rdr, uh->uh_dport);
- else
+ else if (rdr->rport)
nport = rdr->rport;
+ else
+ nport = bport;
PF_ACPY(&baddr, daddr, af);
pf_change_ap(daddr, &uh->uh_dport, pd->ip_sum,
@@ -3095,10 +3106,8 @@ pf_test_udp(struct pf_rule **rm, int direction, struct ifnet *ifp,
if ((*rm != NULL && (*rm)->keep_state) || nat != NULL ||
binat != NULL || rdr != NULL) {
/* create new state */
- u_int16_t len;
struct pf_state *s;
- len = pd->tot_len - off - sizeof(*uh);
s = pool_get(&pf_state_pl, PR_NOWAIT);
if (s == NULL) {
if (nport && nat != NULL)
@@ -3167,6 +3176,7 @@ pf_test_icmp(struct pf_rule **rm, int direction, struct ifnet *ifp,
{
struct pf_nat *nat = NULL;
struct pf_binat *binat = NULL;
+ struct pf_rdr *rdr = NULL;
struct pf_addr *saddr = pd->src, *daddr = pd->dst, baddr;
struct pf_rule *r;
u_short reason;
@@ -3237,8 +3247,28 @@ pf_test_icmp(struct pf_rule **rm, int direction, struct ifnet *ifp,
}
}
} else {
+ /* check incoming packet for RDR */
+ if ((rdr = pf_get_rdr(ifp, pd->proto,
+ saddr, daddr, 0, af)) != NULL) {
+ PF_ACPY(&baddr, daddr, af);
+ switch (af) {
+#ifdef INET
+ case AF_INET:
+ pf_change_a(&daddr->v4.s_addr,
+ pd->ip_sum, rdr->raddr.v4.s_addr, 0);
+ break;
+#endif /* INET */
+#ifdef INET6
+ case AF_INET6:
+ pf_change_a6(daddr, &pd->hdr.icmp6->icmp6_cksum,
+ &rdr->raddr, 0);
+ rewrite++;
+ break;
+#endif /* INET6 */
+ }
+ }
/* check incoming packet for BINAT */
- if ((binat = pf_get_binat(PF_IN, ifp, IPPROTO_ICMP,
+ else if ((binat = pf_get_binat(PF_IN, ifp, IPPROTO_ICMP,
daddr, saddr, af)) != NULL) {
PF_ACPY(&baddr, daddr, af);
switch (af) {
@@ -3307,12 +3337,11 @@ pf_test_icmp(struct pf_rule **rm, int direction, struct ifnet *ifp,
return (PF_DROP);
}
- if ((*rm != NULL && (*rm)->keep_state) || nat != NULL || binat != NULL) {
+ if ((*rm != NULL && (*rm)->keep_state) || nat != NULL ||
+ rdr != NULL || binat != NULL) {
/* create new state */
- u_int16_t len;
struct pf_state *s;
- len = pd->tot_len - off - ICMP_MINLEN;
s = pool_get(&pf_state_pl, PR_NOWAIT);
if (s == NULL)
return (PF_DROP);
@@ -3338,7 +3367,7 @@ pf_test_icmp(struct pf_rule **rm, int direction, struct ifnet *ifp,
s->lan.port = icmpid;
PF_ACPY(&s->ext.addr, saddr, af);
s->ext.port = icmpid;
- if (binat != NULL)
+ if (binat != NULL || rdr != NULL)
PF_ACPY(&s->gwy.addr, &baddr, af);
else
PF_ACPY(&s->gwy.addr, &s->lan.addr, af);
@@ -3376,8 +3405,10 @@ pf_test_other(struct pf_rule **rm, int direction, struct ifnet *ifp,
struct mbuf *m, void *h, struct pf_pdesc *pd)
{
struct pf_rule *r;
+ struct pf_nat *nat = NULL;
struct pf_binat *binat = NULL;
- struct pf_addr *saddr = pd->src, *daddr = pd->dst;
+ struct pf_rdr *rdr = NULL;
+ struct pf_addr *saddr = pd->src, *daddr = pd->dst, baddr;
u_int8_t af = pd->af;
*rm = NULL;
@@ -3386,6 +3417,7 @@ pf_test_other(struct pf_rule **rm, int direction, struct ifnet *ifp,
/* check outgoing packet for BINAT */
if ((binat = pf_get_binat(PF_OUT, ifp, pd->proto,
saddr, daddr, af)) != NULL) {
+ PF_ACPY(&baddr, saddr, af);
switch (af) {
#ifdef INET
case AF_INET:
@@ -3400,10 +3432,47 @@ pf_test_other(struct pf_rule **rm, int direction, struct ifnet *ifp,
#endif /* INET6 */
}
}
+ /* check outgoing packet for NAT */
+ 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_ACPY(saddr, &nat->raddr, af);
+ break;
+#endif /* INET6 */
+ }
+ }
} else {
+ /* check incoming packet for RDR */
+ if ((rdr = pf_get_rdr(ifp, pd->proto,
+ saddr, daddr, 0, af)) != NULL) {
+ PF_ACPY(&baddr, daddr, af);
+ switch (af) {
+#ifdef INET
+ case AF_INET:
+ pf_change_a(&daddr->v4.s_addr,
+ pd->ip_sum, rdr->raddr.v4.s_addr, 0);
+ break;
+#endif /* INET */
+#ifdef INET6
+ case AF_INET6:
+ PF_ACPY(daddr, &rdr->raddr, af);
+ break;
+#endif /* INET6 */
+ }
+ }
/* check incoming packet for BINAT */
- if ((binat = pf_get_binat(PF_IN, ifp, pd->proto,
+ else if ((binat = pf_get_binat(PF_IN, ifp, pd->proto,
daddr, saddr, af)) != NULL) {
+ PF_ACPY(&baddr, daddr, af);
switch (af) {
#ifdef INET
case AF_INET:
@@ -3461,6 +3530,60 @@ pf_test_other(struct pf_rule **rm, int direction, struct ifnet *ifp,
if ((*rm)->action != PF_PASS)
return (PF_DROP);
}
+
+ if ((*rm != NULL && (*rm)->keep_state) || nat != NULL ||
+ rdr != NULL || binat != NULL) {
+ /* create new state */
+ struct pf_state *s;
+
+ s = pool_get(&pf_state_pl, PR_NOWAIT);
+ if (s == NULL)
+ return (PF_DROP);
+
+ s->rule = *rm;
+ s->allow_opts = *rm && (*rm)->allow_opts;
+ s->log = *rm && ((*rm)->log & 2);
+ s->proto = pd->proto;
+ s->direction = direction;
+ s->af = af;
+ if (direction == PF_OUT) {
+ PF_ACPY(&s->gwy.addr, saddr, af);
+ s->gwy.port = 0;
+ PF_ACPY(&s->ext.addr, daddr, af);
+ s->ext.port = 0;
+ if (nat != NULL || binat != NULL)
+ PF_ACPY(&s->lan.addr, &baddr, af);
+ else
+ PF_ACPY(&s->lan.addr, &s->gwy.addr, af);
+ s->lan.port = 0;
+ } else {
+ PF_ACPY(&s->lan.addr, daddr, af);
+ s->lan.port = 0;
+ PF_ACPY(&s->ext.addr, saddr, af);
+ s->ext.port = 0;
+ if (binat != NULL || rdr != NULL)
+ PF_ACPY(&s->gwy.addr, &baddr, af);
+ else
+ PF_ACPY(&s->gwy.addr, &s->lan.addr, af);
+ s->gwy.port = 0;
+ }
+ s->src.seqlo = 0;
+ s->src.seqhi = 0;
+ s->src.seqdiff = 0;
+ s->src.max_win = 0;
+ s->src.state = 1;
+ s->dst.seqlo = 0;
+ s->dst.seqhi = 0;
+ s->dst.seqdiff = 0;
+ s->dst.max_win = 0;
+ s->dst.state = 0;
+ s->creation = pftv.tv_sec;
+ s->expire = pftv.tv_sec + pftm_other_first_packet;
+ s->packets = 1;
+ s->bytes = pd->tot_len;
+ pf_insert_state(s);
+ }
+
return (PF_PASS);
}
@@ -4280,6 +4403,89 @@ pf_test_state_icmp(struct pf_state **state, int direction, struct ifnet *ifp,
}
}
+int
+pf_test_state_other(struct pf_state **state, int direction, struct ifnet *ifp,
+ struct pf_pdesc *pd)
+{
+ struct pf_state_peer *src, *dst;
+ struct pf_tree_key key;
+
+ key.af = pd->af;
+ key.proto = pd->proto;
+ PF_ACPY(&key.addr[0], pd->src, key.af);
+ PF_ACPY(&key.addr[1], pd->dst, key.af);
+ key.port[0] = 0;
+ key.port[1] = 0;
+
+ 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 (direction == (*state)->direction) {
+ src = &(*state)->src;
+ dst = &(*state)->dst;
+ } else {
+ src = &(*state)->dst;
+ dst = &(*state)->src;
+ }
+
+ (*state)->packets++;
+ (*state)->bytes += pd->tot_len;
+
+ /* update states */
+ if (src->state < 1)
+ src->state = 1;
+ if (dst->state == 1)
+ dst->state = 2;
+
+ /* update expire time */
+ if (src->state == 2 && dst->state == 2)
+ (*state)->expire = pftv.tv_sec + pftm_other_multiple;
+ else
+ (*state)->expire = pftv.tv_sec + pftm_other_single;
+
+ /* translate source/destination address, if necessary */
+ if (STATE_TRANSLATE(*state)) {
+ if (direction == PF_OUT)
+ switch (pd->af) {
+#ifdef INET
+ case AF_INET:
+ pf_change_a(&pd->src->v4.s_addr,
+ pd->ip_sum, (*state)->gwy.addr.v4.s_addr, 0);
+ break;
+#endif /* INET */
+#ifdef INET6
+ case AF_INET6:
+ PF_ACPY(pd->src, &(*state)->gwy.addr, pd->af);
+ break;
+#endif /* INET6 */
+ }
+ else
+ switch (pd->af) {
+#ifdef INET
+ case AF_INET:
+ pf_change_a(&pd->dst->v4.s_addr,
+ pd->ip_sum, (*state)->lan.addr.v4.s_addr, 0);
+ break;
+#endif /* INET */
+#ifdef INET6
+ case AF_INET6:
+ PF_ACPY(pd->dst, &(*state)->lan.addr, pd->af);
+ break;
+#endif /* INET6 */
+ }
+ }
+
+ if ((*state)->rule != NULL) {
+ (*state)->rule->packets++;
+ (*state)->rule->bytes += pd->tot_len;
+ }
+ return (PF_PASS);
+}
+
/*
* ipoff and off are measured from the start of the mbuf chain.
* h must be at "ipoff" on the mbuf chain.
@@ -4716,7 +4922,12 @@ pf_test(int dir, struct ifnet *ifp, struct mbuf **m0)
}
default:
- action = pf_test_other(&r, dir, ifp, m, h, &pd);
+ action = pf_test_state_other(&s, dir, ifp, &pd);
+ if (action == PF_PASS) {
+ r = s->rule;
+ log = s->log;
+ } else if (s == NULL)
+ action = pf_test_other(&r, dir, ifp, m, h, &pd);
break;
}