summaryrefslogtreecommitdiff
path: root/sys/net/pf.c
diff options
context:
space:
mode:
authorDaniel Hartmeier <dhartmei@cvs.openbsd.org>2003-05-18 18:33:29 +0000
committerDaniel Hartmeier <dhartmei@cvs.openbsd.org>2003-05-18 18:33:29 +0000
commit83f54bd6f28f561dfb8e52c42c2d6fd9859cca77 (patch)
tree87fd87c8301ccf5403a0c84fdddd60aa431b04a2 /sys/net/pf.c
parent536b0a768d2e81733ebb3f937834bc339f0f4628 (diff)
Merge pf_send_ack() and _send_syn() into a generic _send_tcp().
In the SYN proxy, generate ACKs with proper window sizes after the handshakes.
Diffstat (limited to 'sys/net/pf.c')
-rw-r--r--sys/net/pf.c280
1 files changed, 96 insertions, 184 deletions
diff --git a/sys/net/pf.c b/sys/net/pf.c
index d00781ac12a..8b5b10d86ab 100644
--- a/sys/net/pf.c
+++ b/sys/net/pf.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: pf.c,v 1.358 2003/05/17 21:15:23 dhartmei Exp $ */
+/* $OpenBSD: pf.c,v 1.359 2003/05/18 18:33:28 dhartmei Exp $ */
/*
* Copyright (c) 2001 Daniel Hartmeier
@@ -135,12 +135,10 @@ 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, sa_family_t);
-void pf_send_syn(sa_family_t, const struct pf_addr *,
- const struct pf_addr *, u_int16_t, u_int16_t,
- u_int32_t);
-void pf_send_ack(int, struct tcphdr *,
- struct pf_pdesc *, sa_family_t, u_int8_t,
- struct pf_rule *, u_int8_t, u_int32_t);
+void pf_send_tcp(const struct pf_rule *, sa_family_t,
+ const struct pf_addr *, const struct pf_addr *,
+ u_int16_t, u_int16_t, u_int32_t, u_int32_t,
+ u_int8_t, u_int16_t, u_int8_t);
void pf_send_icmp(struct mbuf *, u_int8_t, u_int8_t,
sa_family_t, struct pf_rule *);
struct pf_rule *pf_match_translation(int, struct ifnet *, u_int8_t,
@@ -487,6 +485,16 @@ pf_purge_expired_states(void)
next = RB_NEXT(pf_state_tree, &tree_ext_gwy, cur);
if (pf_state_expires(cur->state) <= time.tv_sec) {
+ if (cur->state->src.state == PF_TCPS_PROXY_DST)
+ pf_send_tcp(cur->state->rule.ptr,
+ cur->state->af,
+ &cur->state->ext.addr,
+ &cur->state->lan.addr,
+ cur->state->ext.port,
+ cur->state->lan.port,
+ cur->state->src.seqhi,
+ cur->state->src.seqlo + 1,
+ TH_RST|TH_ACK, 0, 0);
RB_REMOVE(pf_state_tree, &tree_ext_gwy, cur);
/* Need this key's peer (in the other tree) */
@@ -1067,9 +1075,10 @@ pf_change_icmp(struct pf_addr *ia, u_int16_t *ip, struct pf_addr *oa,
}
void
-pf_send_syn(sa_family_t af, const struct pf_addr *saddr,
- const struct pf_addr *daddr, u_int16_t sport, u_int16_t dport,
- u_int32_t isn)
+pf_send_tcp(const struct pf_rule *r, sa_family_t af,
+ const struct pf_addr *saddr, const struct pf_addr *daddr,
+ u_int16_t sport, u_int16_t dport, u_int32_t seq, u_int32_t ack,
+ u_int8_t flags, u_int16_t win, u_int8_t ttl)
{
struct mbuf *m;
struct m_tag *mtag;
@@ -1105,6 +1114,21 @@ pf_send_syn(sa_family_t af, const struct pf_addr *saddr,
return;
}
m_tag_prepend(m, mtag);
+#ifdef ALTQ
+ if (r != NULL && r->qid) {
+ struct altq_tag *atag;
+
+ mtag = m_tag_get(PACKET_TAG_PF_QID, sizeof(*atag), M_NOWAIT);
+ if (mtag != NULL) {
+ atag = (struct altq_tag *)(mtag + 1);
+ atag->qid = r->qid;
+ /* add hints for ecn */
+ atag->af = af;
+ atag->hdr = mtod(m, struct ip *);
+ m_tag_prepend(m, mtag);
+ }
+ }
+#endif
m->m_data += max_linkhdr;
m->m_pkthdr.len = m->m_len = len;
m->m_pkthdr.rcvif = NULL;
@@ -1141,13 +1165,11 @@ pf_send_syn(sa_family_t af, const struct pf_addr *saddr,
/* TCP header */
th->th_sport = sport;
th->th_dport = dport;
- th->th_seq = htonl(isn);
- th->th_ack = 0;
+ th->th_seq = htonl(seq);
+ th->th_ack = htonl(ack);
th->th_off = sizeof(*th) >> 2;
- th->th_flags = TH_SYN;
- th->th_win = htons(1);
- th->th_sum = 0;
- th->th_urp = 0;
+ th->th_flags = flags;
+ th->th_win = htons(win);
switch (af) {
#ifdef INET
@@ -1158,10 +1180,11 @@ pf_send_syn(sa_family_t af, const struct pf_addr *saddr,
/* Finish the IP header */
h->ip_v = 4;
h->ip_hl = sizeof(*h) >> 2;
- h->ip_ttl = ip_defttl;
- h->ip_sum = 0;
+ h->ip_tos = IPTOS_LOWDELAY;
h->ip_len = len;
h->ip_off = ip_mtudisc ? IP_DF : 0;
+ h->ip_ttl = ttl ? ttl : ip_defttl;
+ h->ip_sum = 0;
ip_output(m, (void *)NULL, (void *)NULL, 0, (void *)NULL,
(void *)NULL);
break;
@@ -1181,151 +1204,6 @@ pf_send_syn(sa_family_t af, const struct pf_addr *saddr,
}
void
-pf_send_ack(int off, struct tcphdr *th, struct pf_pdesc *pd, sa_family_t af,
- u_int8_t return_ttl, struct pf_rule *r, u_int8_t flags, u_int32_t isn)
-{
- struct mbuf *m;
- struct m_tag *mtag;
- 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;
-
- /* create outgoing mbuf */
- mtag = m_tag_get(PACKET_TAG_PF_GENERATED, 0, M_NOWAIT);
- if (mtag == NULL)
- return;
- m = m_gethdr(M_DONTWAIT, MT_HEADER);
- if (m == NULL) {
- m_tag_free(mtag);
- return;
- }
- m_tag_prepend(m, mtag);
- m->m_data += max_linkhdr;
- m->m_pkthdr.len = m->m_len = len;
- m->m_pkthdr.rcvif = NULL;
- bzero(m->m_data, len);
- 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->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 = flags;
- } else {
- int tlen = pd->p_len;
- if (th->th_flags & TH_SYN)
- tlen++;
- if (th->th_flags & TH_FIN)
- tlen++;
- th2->th_ack = htonl(ntohl(th->th_seq) + tlen);
- th2->th_flags = TH_ACK | flags;
- if (flags & TH_SYN)
- th2->th_seq = htonl(isn);
- }
- th2->th_off = sizeof(*th2) >> 2;
-
-#ifdef ALTQ
- if (r->qid) {
- struct altq_tag *atag;
-
- mtag = m_tag_get(PACKET_TAG_PF_QID, sizeof(*atag), M_NOWAIT);
- if (mtag != NULL) {
- atag = (struct altq_tag *)(mtag + 1);
- atag->qid = r->qid;
- /* add hints for ecn */
- atag->af = af;
- atag->hdr = mtod(m, struct ip *);
- m_tag_prepend(m, mtag);
- }
- }
-#endif
-
- 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;
- if (!return_ttl)
- return_ttl = ip_defttl;
- h2->ip_ttl = return_ttl;
- h2->ip_sum = 0;
- h2->ip_len = len;
- h2->ip_off = ip_mtudisc ? IP_DF : 0;
- ip_output(m, (void *)NULL, (void *)NULL, 0, (void *)NULL,
- (void *)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_vfc |= IPV6_VERSION;
- if (!return_ttl)
- return_ttl = IPV6_DEFHLIM;
- h2_6->ip6_hlim = return_ttl;
-
- 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, sa_family_t af,
struct pf_rule *r)
{
@@ -2235,11 +2113,20 @@ pf_test_tcp(struct pf_rule **rm, struct pf_state **sm, int direction,
&th->th_sum, &baddr, bport, 0, af);
rewrite++;
}
- if ((r->rule_flag & PFRULE_RETURNRST) ||
- (r->rule_flag & PFRULE_RETURN))
- pf_send_ack(off, th, pd, af,
- r->return_ttl, r, TH_RST, 0);
- else if ((af == AF_INET) && r->return_icmp)
+ if (((r->rule_flag & PFRULE_RETURNRST) ||
+ (r->rule_flag & PFRULE_RETURN)) &&
+ !(th->th_flags & TH_RST)) {
+ u_int32_t ack = ntohl(th->th_seq) + pd->p_len;
+
+ if (th->th_flags & TH_SYN)
+ ack++;
+ if (th->th_flags & TH_FIN)
+ ack++;
+ pf_send_tcp(r, af, pd->dst,
+ pd->src, th->th_dport, th->th_sport,
+ ntohl(th->th_ack), ack, TH_RST|TH_ACK, 0,
+ r->return_ttl);
+ } else if ((af == AF_INET) && r->return_icmp)
pf_send_icmp(m, r->return_icmp >> 8,
r->return_icmp & 255, af, r);
else if ((af == AF_INET6) && r->return_icmp6)
@@ -2382,8 +2269,9 @@ pf_test_tcp(struct pf_rule **rm, struct pf_state **sm, int direction,
pd->ip_sum, &th->th_sum, &baddr,
bport, 0, af);
s->src.seqhi = arc4random();
- pf_send_ack(off, th, pd, af, r->return_ttl, r,
- TH_SYN, s->src.seqhi);
+ pf_send_tcp(r, af, daddr, saddr, th->th_dport,
+ th->th_sport, s->src.seqhi,
+ ntohl(th->th_seq) + 1, TH_SYN|TH_ACK, 0, 0);
return (PF_SYNPROXY_DROP);
}
}
@@ -3268,8 +3156,10 @@ pf_test_state_tcp(struct pf_state **state, int direction, struct ifnet *ifp,
if (th->th_flags & TH_SYN) {
if (ntohl(th->th_seq) != (*state)->src.seqlo)
return (PF_DROP);
- pf_send_ack(off, th, pd, pd->af, 0, (*state)->rule.ptr,
- TH_SYN, (*state)->src.seqhi);
+ pf_send_tcp((*state)->rule.ptr, pd->af, pd->dst,
+ pd->src, th->th_dport, th->th_sport,
+ (*state)->src.seqhi, ntohl(th->th_seq) + 1,
+ TH_SYN|TH_ACK, 0, 0);
return (PF_SYNPROXY_DROP);
} else if (!(th->th_flags & TH_ACK) ||
(ntohl(th->th_ack) != (*state)->src.seqhi + 1) ||
@@ -3279,21 +3169,26 @@ pf_test_state_tcp(struct pf_state **state, int direction, struct ifnet *ifp,
(*state)->src.state = PF_TCPS_PROXY_DST;
}
if ((*state)->src.state == PF_TCPS_PROXY_DST) {
+ struct pf_state_host *src, *dst;
+
+ if (direction == PF_OUT) {
+ src = &(*state)->gwy;
+ dst = &(*state)->ext;
+ } else {
+ src = &(*state)->ext;
+ dst = &(*state)->lan;
+ }
if (direction == (*state)->direction) {
if (((th->th_flags & (TH_SYN|TH_ACK)) != TH_ACK) ||
(ntohl(th->th_ack) != (*state)->src.seqhi + 1) ||
(ntohl(th->th_seq) != (*state)->src.seqlo + 1))
return (PF_DROP);
+ (*state)->src.max_win = MAX(ntohs(th->th_win), 1);
if ((*state)->dst.seqhi == 1)
(*state)->dst.seqhi = arc4random();
- if (direction == PF_OUT)
- pf_send_syn(pd->af, &(*state)->gwy.addr,
- &(*state)->ext.addr, (*state)->gwy.port,
- (*state)->ext.port, (*state)->dst.seqhi);
- else
- pf_send_syn(pd->af, &(*state)->ext.addr,
- &(*state)->lan.addr, (*state)->ext.port,
- (*state)->lan.port, (*state)->dst.seqhi);
+ pf_send_tcp((*state)->rule.ptr, pd->af, &src->addr,
+ &dst->addr, src->port, dst->port,
+ (*state)->dst.seqhi, 0, TH_SYN, 0, 0);
return (PF_SYNPROXY_DROP);
} else if (((th->th_flags & (TH_SYN|TH_ACK)) !=
(TH_SYN|TH_ACK)) ||
@@ -3302,8 +3197,14 @@ pf_test_state_tcp(struct pf_state **state, int direction, struct ifnet *ifp,
else {
(*state)->dst.max_win = MAX(ntohs(th->th_win), 1);
(*state)->dst.seqlo = ntohl(th->th_seq);
- pf_send_ack(off, th, pd, pd->af, 0,
- (*state)->rule.ptr, 0, 0);
+ pf_send_tcp((*state)->rule.ptr, pd->af, pd->dst,
+ pd->src, th->th_dport, th->th_sport,
+ ntohl(th->th_ack), ntohl(th->th_seq) + 1,
+ TH_ACK, (*state)->src.max_win, 0);
+ pf_send_tcp((*state)->rule.ptr, pd->af, &src->addr,
+ &dst->addr, src->port, dst->port,
+ (*state)->src.seqhi + 1, (*state)->src.seqlo + 1,
+ TH_ACK, (*state)->dst.max_win, 0);
(*state)->src.seqdiff = (*state)->dst.seqhi -
(*state)->src.seqlo;
(*state)->dst.seqdiff = (*state)->src.seqhi -
@@ -3560,8 +3461,19 @@ pf_test_state_tcp(struct pf_state **state, int direction, struct ifnet *ifp,
if ((*state)->dst.state == TCPS_SYN_SENT &&
(*state)->src.state == TCPS_SYN_SENT) {
/* Send RST for state mismatches during handshake */
- pf_send_ack(off, th, pd, pd->af, 0,
- (*state)->rule.ptr, TH_RST, 0);
+ if (!(th->th_flags & TH_RST)) {
+ u_int32_t ack = ntohl(th->th_seq) + pd->p_len;
+
+ if (th->th_flags & TH_SYN)
+ ack++;
+ if (th->th_flags & TH_FIN)
+ ack++;
+ pf_send_tcp((*state)->rule.ptr, pd->af,
+ pd->dst, pd->src, th->th_dport,
+ th->th_sport, ntohl(th->th_ack), ack,
+ TH_RST|TH_ACK, 0,
+ (*state)->rule.ptr->return_ttl);
+ }
src->seqlo = 0;
src->seqhi = 1;
src->max_win = 1;