summaryrefslogtreecommitdiff
path: root/sys
diff options
context:
space:
mode:
Diffstat (limited to 'sys')
-rw-r--r--sys/net/pf.c234
1 files changed, 154 insertions, 80 deletions
diff --git a/sys/net/pf.c b/sys/net/pf.c
index b06ef47eb28..e0839244b70 100644
--- a/sys/net/pf.c
+++ b/sys/net/pf.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: pf.c,v 1.44 2001/06/26 04:24:45 itojun Exp $ */
+/* $OpenBSD: pf.c,v 1.45 2001/06/26 04:57:34 itojun Exp $ */
/*
* Copyright (c) 2001, Daniel Hartmeier
@@ -160,7 +160,7 @@ struct pf_state *pf_test_state_udp(int, struct ifnet *, struct mbuf **,
int, int, struct ip *, struct udphdr *);
struct pf_state *pf_test_state_icmp(int, struct ifnet *, struct mbuf **,
int, int, struct ip *, struct icmp *);
-void *pull_hdr(struct ifnet *, struct mbuf **, int, int, int,
+void *pull_hdr(struct ifnet *, struct mbuf **, int, int, void *, int,
struct ip *, int *);
int pf_test(int, struct ifnet *, struct mbuf **);
int pflog_packet(struct mbuf *, int, short,int,
@@ -1223,6 +1223,7 @@ pf_test_tcp(int direction, struct ifnet *ifp, struct mbuf **m,
u_int16_t bport;
struct pf_rule *r, *rm = NULL;
u_int16_t nr = 1, mnr = 0;
+ int rewrite = 0;
if (direction == PF_OUT) {
/* check outgoing packet for NAT */
@@ -1232,6 +1233,7 @@ pf_test_tcp(int direction, struct ifnet *ifp, struct mbuf **m,
bport = th->th_sport;
change_ap(&h->ip_src.s_addr, &th->th_sport, &h->ip_sum,
&th->th_sum, nat->daddr, htons(pf_next_port_tcp));
+ rewrite++;
}
} else {
/* check incoming packet for RDR */
@@ -1241,6 +1243,7 @@ pf_test_tcp(int direction, struct ifnet *ifp, struct mbuf **m,
bport = th->th_dport;
change_ap(&h->ip_dst.s_addr, &th->th_dport,
&h->ip_sum, &th->th_sum, rdr->raddr, rdr->rport);
+ rewrite++;
}
}
@@ -1267,17 +1270,23 @@ pf_test_tcp(int direction, struct ifnet *ifp, struct mbuf **m,
nr++;
}
+ /* XXX will log packet before rewrite */
if ((rm != NULL) && rm->log)
PFLOG_PACKET(h, *m, AF_INET, direction, mnr, rm);
if ((rm != NULL) && (rm->action == PF_DROP_RST)) {
/* undo NAT/RST changes, if they have taken place */
- if (nat != NULL)
+ if (nat != NULL) {
change_ap(&h->ip_src.s_addr, &th->th_sport,
&h->ip_sum, &th->th_sum, baddr, bport);
- else if (rdr != NULL)
+ rewrite++;
+ }
+ else if (rdr != NULL) {
change_ap(&h->ip_dst.s_addr, &th->th_dport,
&h->ip_sum, &th->th_sum, baddr, bport);
+ rewrite++;
+ }
+
send_reset(direction, ifp, h, off, th);
return (PF_DROP);
}
@@ -1343,6 +1352,12 @@ pf_test_tcp(int direction, struct ifnet *ifp, struct mbuf **m,
insert_state(s);
}
+ /* copy back packet headers if we performed NAT operations */
+ if (rewrite) {
+ m_copyback((*m), ipoff, sizeof(*h), (caddr_t)h);
+ m_copyback((*m), off, sizeof(*th), (caddr_t)th);
+ }
+
return (PF_PASS);
}
@@ -1356,6 +1371,7 @@ pf_test_udp(int direction, struct ifnet *ifp, struct mbuf **m,
u_int16_t bport;
struct pf_rule *r, *rm = NULL;
u_int16_t nr = 1, mnr = 0;
+ int rewrite = 0;
if (direction == PF_OUT) {
/* check outgoing packet for NAT */
@@ -1364,6 +1380,7 @@ pf_test_udp(int direction, struct ifnet *ifp, struct mbuf **m,
bport = uh->uh_sport;
change_ap(&h->ip_src.s_addr, &uh->uh_sport, &h->ip_sum,
&uh->uh_sum, nat->daddr, htons(pf_next_port_udp));
+ rewrite++;
}
} else {
/* check incoming packet for RDR */
@@ -1373,6 +1390,7 @@ pf_test_udp(int direction, struct ifnet *ifp, struct mbuf **m,
bport = uh->uh_dport;
change_ap(&h->ip_dst.s_addr, &uh->uh_dport,
&h->ip_sum, &uh->uh_sum, rdr->raddr, rdr->rport);
+ rewrite++;
}
}
@@ -1398,6 +1416,7 @@ pf_test_udp(int direction, struct ifnet *ifp, struct mbuf **m,
nr++;
}
+ /* XXX will log packet before rewrite */
if (rm != NULL && rm->log)
PFLOG_PACKET(h, *m, AF_INET, direction, mnr, rm);
@@ -1459,6 +1478,12 @@ pf_test_udp(int direction, struct ifnet *ifp, struct mbuf **m,
insert_state(s);
}
+ /* copy back packet headers if we performed NAT operations */
+ if (rewrite) {
+ m_copyback((*m), ipoff, sizeof(*h), (caddr_t)h);
+ m_copyback((*m), off, sizeof(*uh), (caddr_t)uh);
+ }
+
return (PF_PASS);
}
@@ -1470,12 +1495,14 @@ pf_test_icmp(int direction, struct ifnet *ifp, struct mbuf **m,
u_int32_t baddr;
struct pf_rule *r, *rm = NULL;
u_int16_t nr = 1, mnr = 0;
+ int rewrite = 0;
if (direction == PF_OUT) {
/* check outgoing packet for NAT */
if ((nat = get_nat(ifp, IPPROTO_ICMP, h->ip_src.s_addr)) != NULL) {
baddr = h->ip_src.s_addr;
change_a(&h->ip_src.s_addr, &h->ip_sum, nat->daddr);
+ rewrite++;
}
}
@@ -1499,6 +1526,7 @@ pf_test_icmp(int direction, struct ifnet *ifp, struct mbuf **m,
nr++;
}
+ /* XXX will log packet before rewrite */
if (rm != NULL && rm->log)
PFLOG_PACKET(h, *m, AF_INET, direction, mnr, rm);
@@ -1549,6 +1577,12 @@ pf_test_icmp(int direction, struct ifnet *ifp, struct mbuf **m,
insert_state(s);
}
+ /* copy back packet headers if we performed NAT operations */
+ if (rewrite) {
+ m_copyback((*m), ipoff, sizeof(*h), (caddr_t)h);
+ m_copyback((*m), off, sizeof(*ih), (caddr_t)ih);
+ }
+
return (PF_PASS);
}
@@ -1558,6 +1592,7 @@ pf_test_state_tcp(int direction, struct ifnet *ifp, struct mbuf **m,
{
struct pf_state *s;
struct pf_tree_key key;
+ int rewrite = 0;
key.proto = IPPROTO_TCP;
key.addr[0] = h->ip_src.s_addr;
@@ -1679,6 +1714,7 @@ pf_test_state_tcp(int direction, struct ifnet *ifp, struct mbuf **m,
change_ap(&h->ip_dst.s_addr, &th->th_dport,
&h->ip_sum, &th->th_sum,
s->lan.addr, s->lan.port);
+ rewrite++;
}
} else {
@@ -1696,6 +1732,12 @@ pf_test_state_tcp(int direction, struct ifnet *ifp, struct mbuf **m,
s = NULL;
}
+ /* copy back packet headers if we performed NAT operations */
+ if (rewrite) {
+ m_copyback((*m), ipoff, sizeof(*h), (caddr_t)h);
+ m_copyback((*m), off, sizeof(*th), (caddr_t)th);
+ }
+
return (s);
}
return (NULL);
@@ -1707,6 +1749,7 @@ pf_test_state_udp(int direction, struct ifnet *ifp, struct mbuf **m,
{
struct pf_state *s;
struct pf_tree_key key;
+ int rewrite = 0;
key.proto = IPPROTO_UDP;
key.addr[0] = h->ip_src.s_addr;
@@ -1754,6 +1797,13 @@ pf_test_state_udp(int direction, struct ifnet *ifp, struct mbuf **m,
change_ap(&h->ip_dst.s_addr, &uh->uh_dport,
&h->ip_sum, &uh->uh_sum,
s->lan.addr, s->lan.port);
+ rewrite++;
+ }
+
+ /* copy back packet headers if we performed NAT operations */
+ if (rewrite) {
+ m_copyback((*m), ipoff, sizeof(*h), (caddr_t)h);
+ m_copyback((*m), off, sizeof(*uh), (caddr_t)uh);
}
return (s);
@@ -1766,6 +1816,7 @@ pf_test_state_icmp(int direction, struct ifnet *ifp, struct mbuf **m,
int ipoff, int off, struct ip *h, struct icmp *ih)
{
u_int16_t len = h->ip_len - off - sizeof(*ih);
+ int rewrite = 0;
if (ih->icmp_type != ICMP_UNREACH &&
ih->icmp_type != ICMP_SOURCEQUENCH &&
@@ -1803,6 +1854,16 @@ pf_test_state_icmp(int direction, struct ifnet *ifp, struct mbuf **m,
else
change_a(&h->ip_dst.s_addr, &h->ip_sum,
s->lan.addr);
+ rewrite++;
+ }
+
+ /*
+ * copy back packet headers if we performed NAT
+ * operations
+ */
+ if (rewrite) {
+ m_copyback((*m), ipoff, sizeof(*h), (caddr_t)h);
+ m_copyback((*m), off, sizeof(*ih), (caddr_t)ih);
}
return (s);
@@ -1816,46 +1877,45 @@ pf_test_state_icmp(int direction, struct ifnet *ifp, struct mbuf **m,
* Extract the inner TCP/UDP header and search for that state.
*/
- struct ip *h2;
+ struct ip h2;
+ int ipoff2;
int off2;
int dummy;
- off += 8; /* offset of h2 in mbuf chain */
- h2 = pull_hdr(ifp, m, 0, off, sizeof(*h2), h, &dummy);
- if (!h2) {
+ ipoff2 = off + 8; /* offset of h2 in mbuf chain */
+ if (!pull_hdr(ifp, m, 0, ipoff2, &h2, sizeof(h2), h, &dummy)) {
printf("pf: ICMP error message too short\n");
return (NULL);
}
/* offset of protocol header that follows h2 */
- off2 = off + (h2->ip_hl << 2);
+ off2 = ipoff2 + (h2.ip_hl << 2);
- switch (h2->ip_p) {
+ switch (h2.ip_p) {
case IPPROTO_TCP: {
- struct tcphdr *th;
+ struct tcphdr th;
u_int32_t seq, end;
struct pf_state *s;
struct pf_tree_key key;
struct pf_state_peer *src, *dst;
int ackskew;
- th = pull_hdr(ifp, m, off, off2, sizeof(*th), h2,
- &dummy);
- if (!th) {
+ if (!pull_hdr(ifp, m, ipoff2, off2, &th, sizeof(th),
+ &h2, &dummy)) {
printf("pf: "
"ICMP error message too short\n");
return NULL;
}
- seq = ntohl(th->th_seq);
- end = seq + h2->ip_len - ((h2->ip_hl + th->th_off)<<2) +
- ((th->th_flags & TH_SYN) ? 1 : 0) +
- ((th->th_flags & TH_FIN) ? 1 : 0);
+ seq = ntohl(th.th_seq);
+ end = seq + h2.ip_len - ((h2.ip_hl + th.th_off)<<2) +
+ ((th.th_flags & TH_SYN) ? 1 : 0) +
+ ((th.th_flags & TH_FIN) ? 1 : 0);
key.proto = IPPROTO_TCP;
- key.addr[0] = h2->ip_dst.s_addr;
- key.port[0] = th->th_dport;
- key.addr[1] = h2->ip_src.s_addr;
- key.port[1] = th->th_sport;
+ key.addr[0] = h2.ip_dst.s_addr;
+ key.port[0] = th.th_dport;
+ key.addr[1] = h2.ip_src.s_addr;
+ key.port[1] = th.th_sport;
s = find_state((direction == PF_IN) ? tree_ext_gwy :
tree_lan_ext, &key);
@@ -1865,10 +1925,10 @@ pf_test_state_icmp(int direction, struct ifnet *ifp, struct mbuf **m,
src = (direction == s->direction) ? &s->dst : &s->src;
dst = (direction == s->direction) ? &s->src : &s->dst;
- if ((th->th_flags & TH_ACK) == 0 && th->th_ack == 0)
+ if ((th.th_flags & TH_ACK) == 0 && th.th_ack == 0)
ackskew = 0;
else
- ackskew = dst->seqlo - ntohl(th->th_ack);
+ ackskew = dst->seqlo - ntohl(th.th_ack);
if (!SEQ_GEQ(src->seqhi, end) ||
!SEQ_GEQ(seq, src->seqlo - dst->max_win) ||
!(ackskew >= -MAXACKWINDOW) ||
@@ -1876,7 +1936,7 @@ pf_test_state_icmp(int direction, struct ifnet *ifp, struct mbuf **m,
printf("pf: BAD ICMP state: ");
print_state(direction, s);
- print_flags(th->th_flags);
+ print_flags(th.th_flags);
printf(" seq=%lu\n", seq);
return (NULL);
}
@@ -1884,39 +1944,53 @@ pf_test_state_icmp(int direction, struct ifnet *ifp, struct mbuf **m,
if (s->lan.addr != s->gwy.addr ||
s->lan.port != s->gwy.port) {
if (direction == PF_IN) {
- change_icmp(&h2->ip_src.s_addr,
- &th->th_sport, &h->ip_dst.s_addr,
- s->lan.addr, s->lan.port, &th->th_sum,
- &h2->ip_sum, &ih->icmp_cksum,
+ change_icmp(&h2.ip_src.s_addr,
+ &th.th_sport, &h->ip_dst.s_addr,
+ s->lan.addr, s->lan.port, &th.th_sum,
+ &h2.ip_sum, &ih->icmp_cksum,
&h->ip_sum);
} else {
- change_icmp(&h2->ip_dst.s_addr,
- &th->th_dport, &h->ip_src.s_addr,
- s->gwy.addr, s->gwy.port, &th->th_sum,
- &h2->ip_sum, &ih->icmp_cksum,
+ change_icmp(&h2.ip_dst.s_addr,
+ &th.th_dport, &h->ip_src.s_addr,
+ s->gwy.addr, s->gwy.port, &th.th_sum,
+ &h2.ip_sum, &ih->icmp_cksum,
&h->ip_sum);
}
+ rewrite++;
+ }
+
+ /*
+ * copy back packet headers if we performed NAT
+ * operations
+ */
+ if (rewrite) {
+ m_copyback((*m), ipoff, sizeof(*h), (caddr_t)h);
+ m_copyback((*m), off, sizeof(*ih), (caddr_t)ih);
+ m_copyback((*m), ipoff2, sizeof(h2),
+ (caddr_t)&h2);
+ m_copyback((*m), off2, sizeof(th),
+ (caddr_t)&th);
}
+
return (s);
break;
}
case IPPROTO_UDP: {
- struct udphdr *uh;
+ struct udphdr uh;
struct pf_state *s;
struct pf_tree_key key;
- uh = pull_hdr(ifp, m, off, off2, sizeof(*uh), h2,
- &dummy);
- if (!uh) {
+ if (!pull_hdr(ifp, m, ipoff2, off2, &uh, sizeof(uh),
+ &h2, &dummy)) {
printf("pf: ICMP error message too short\n");
return NULL;
}
key.proto = IPPROTO_UDP;
- key.addr[0] = h2->ip_dst.s_addr;
- key.port[0] = uh->uh_dport;
- key.addr[1] = h2->ip_src.s_addr;
- key.port[1] = uh->uh_sport;
+ key.addr[0] = h2.ip_dst.s_addr;
+ key.port[0] = uh.uh_dport;
+ key.addr[1] = h2.ip_src.s_addr;
+ key.port[1] = uh.uh_sport;
s = find_state(direction == PF_IN ? tree_ext_gwy :
tree_lan_ext, &key);
@@ -1926,19 +2000,34 @@ pf_test_state_icmp(int direction, struct ifnet *ifp, struct mbuf **m,
if (s->lan.addr != s->gwy.addr ||
s->lan.port != s->gwy.port) {
if (direction == PF_IN) {
- change_icmp(&h2->ip_src.s_addr,
- &uh->uh_sport, &h->ip_dst.s_addr,
- s->lan.addr, s->lan.port, &uh->uh_sum,
- &h2->ip_sum, &ih->icmp_cksum,
+ change_icmp(&h2.ip_src.s_addr,
+ &uh.uh_sport, &h->ip_dst.s_addr,
+ s->lan.addr, s->lan.port, &uh.uh_sum,
+ &h2.ip_sum, &ih->icmp_cksum,
&h->ip_sum);
} else {
- change_icmp(&h2->ip_dst.s_addr,
- &uh->uh_dport, &h->ip_src.s_addr,
- s->gwy.addr, s->gwy.port, &uh->uh_sum,
- &h2->ip_sum, &ih->icmp_cksum,
+ change_icmp(&h2.ip_dst.s_addr,
+ &uh.uh_dport, &h->ip_src.s_addr,
+ s->gwy.addr, s->gwy.port, &uh.uh_sum,
+ &h2.ip_sum, &ih->icmp_cksum,
&h->ip_sum);
}
+ rewrite++;
+ }
+
+ /*
+ * copy back packet headers if we performed NAT
+ * operations
+ */
+ if (rewrite) {
+ m_copyback((*m), ipoff, sizeof(*h), (caddr_t)h);
+ m_copyback((*m), off, sizeof(*ih), (caddr_t)ih);
+ m_copyback((*m), ipoff2, sizeof(h2),
+ (caddr_t)&h2);
+ m_copyback((*m), off2, sizeof(uh),
+ (caddr_t)&uh);
}
+
return (s);
break;
}
@@ -1956,12 +2045,10 @@ pf_test_state_icmp(int direction, struct ifnet *ifp, struct mbuf **m,
* h must be at "ipoff" on the mbuf chain.
*/
void *
-pull_hdr(struct ifnet *ifp, struct mbuf **m, int ipoff, int off, int len,
- struct ip *h, int *action)
+pull_hdr(struct ifnet *ifp, struct mbuf **m, int ipoff, int off, void *p,
+ int len, struct ip *h, int *action)
{
u_int16_t fragoff = (h->ip_off & IP_OFFMASK) << 3;
- struct mbuf *n;
- int newoff;
/* sanity check */
if (ipoff > off) {
@@ -1985,18 +2072,8 @@ pull_hdr(struct ifnet *ifp, struct mbuf **m, int ipoff, int off, int len,
print_ip(ifp, h);
return (NULL);
}
- /*
- * XXX should use m_copydata, but NAT portion tries to touch mbuf
- * directly
- */
- n = m_pulldown((*m), off, len, &newoff);
- if (!n) {
- printf("pf: pullup proto header failed\n");
- *action = PF_DROP;
- *m = NULL;
- return (NULL);
- }
- return (mtod(n, char *) + newoff);
+ m_copydata((*m), off, len, p);
+ return p;
}
int
@@ -2034,41 +2111,38 @@ pf_test(int direction, struct ifnet *ifp, struct mbuf **m)
switch (h->ip_p) {
case IPPROTO_TCP: {
- struct tcphdr *th = pull_hdr(ifp, m, 0, off, sizeof(*th), h,
- &action);
+ struct tcphdr th;
- if (th == NULL)
+ if (!pull_hdr(ifp, m, 0, off, &th, sizeof(th), h, &action))
goto done;
- if (pf_test_state_tcp(direction, ifp, m, 0, off, h, th))
+ if (pf_test_state_tcp(direction, ifp, m, 0, off, h, &th))
action = PF_PASS;
else
- action = pf_test_tcp(direction, ifp, m, 0, off, h, th);
+ action = pf_test_tcp(direction, ifp, m, 0, off, h, &th);
break;
}
case IPPROTO_UDP: {
- struct udphdr *uh = pull_hdr(ifp, m, 0, off, sizeof(*uh), h,
- &action);
+ struct udphdr uh;
- if (uh == NULL)
+ if (!pull_hdr(ifp, m, 0, off, &uh, sizeof(uh), h, &action))
goto done;
- if (pf_test_state_udp(direction, ifp, m, 0, off, h, uh))
+ if (pf_test_state_udp(direction, ifp, m, 0, off, h, &uh))
action = PF_PASS;
else
- action = pf_test_udp(direction, ifp, m, 0, off, h, uh);
+ action = pf_test_udp(direction, ifp, m, 0, off, h, &uh);
break;
}
case IPPROTO_ICMP: {
- struct icmp *ih = pull_hdr(ifp, m, 0, off, sizeof(*ih), h,
- &action);
+ struct icmp ih;
- if (ih == NULL)
+ if (!pull_hdr(ifp, m, 0, off, &ih, sizeof(ih), h, &action))
goto done;
- if (pf_test_state_icmp(direction, ifp, m, 0, off, h, ih))
+ if (pf_test_state_icmp(direction, ifp, m, 0, off, h, &ih))
action = PF_PASS;
else
- action = pf_test_icmp(direction, ifp, m, 0, off, h, ih);
+ action = pf_test_icmp(direction, ifp, m, 0, off, h, &ih);
break;
}