diff options
author | 2003-06-20 18:24:57 +0000 | |
---|---|---|
committer | 2003-06-20 18:24:57 +0000 | |
commit | e1ffe03eb75c86d9dc45daedc91e8494e7578e97 (patch) | |
tree | 892881040f2cd1ca397814f8a5b76cee3a94fa7e | |
parent | tweak; (diff) | |
download | wireguard-openbsd-e1ffe03eb75c86d9dc45daedc91e8494e7578e97.tar.xz wireguard-openbsd-e1ffe03eb75c86d9dc45daedc91e8494e7578e97.zip |
Add MSS support to the synproxy. The client's MSS is sent to the server,
the server's MSS is guessed based on the routing table and interface MTU.
Fine patch entirely from Krists Krilovs <pow@pow.za.net>, ok frantzen@
Note: ABI change (new field in struct pf_state), requires a pfctl rebuild
(and tcpdump for pfsync).
-rw-r--r-- | sys/net/pf.c | 147 | ||||
-rw-r--r-- | sys/net/pfvar.h | 3 |
2 files changed, 132 insertions, 18 deletions
diff --git a/sys/net/pf.c b/sys/net/pf.c index 83afd580d05..bdd9d41201b 100644 --- a/sys/net/pf.c +++ b/sys/net/pf.c @@ -1,4 +1,4 @@ -/* $OpenBSD: pf.c,v 1.365 2003/06/20 17:38:24 dhartmei Exp $ */ +/* $OpenBSD: pf.c,v 1.366 2003/06/20 18:24:57 dhartmei Exp $ */ /* * Copyright (c) 2001 Daniel Hartmeier @@ -138,7 +138,7 @@ void pf_change_icmp(struct pf_addr *, u_int16_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); + u_int8_t, u_int16_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, @@ -209,6 +209,10 @@ int pf_socket_lookup(uid_t *, gid_t *, int, sa_family_t, int, struct pf_pdesc *); u_int8_t pf_get_wscale(struct mbuf *, int, u_int16_t, sa_family_t); +u_int16_t pf_get_mss(struct mbuf *, int, u_int16_t, + sa_family_t); +u_int16_t pf_calc_mss(struct pf_addr *, sa_family_t, + u_int16_t); int pf_check_proto_cksum(struct mbuf *, int, int, u_int8_t, sa_family_t); @@ -495,6 +499,7 @@ pf_purge_expired_states(void) cur->state->lan.port, cur->state->src.seqhi, cur->state->src.seqlo + 1, + 0, TH_RST|TH_ACK, 0, 0); RB_REMOVE(pf_state_tree, &tree_ext_gwy, cur); @@ -1079,11 +1084,11 @@ void 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) + u_int8_t flags, u_int16_t win, u_int16_t mss, u_int8_t ttl) { struct mbuf *m; struct m_tag *mtag; - int len; + int len, tlen; #ifdef INET struct ip *h; #endif /* INET */ @@ -1091,16 +1096,22 @@ pf_send_tcp(const struct pf_rule *r, sa_family_t af, struct ip6_hdr *h6; #endif /* INET6 */ struct tcphdr *th; + char *opt; + /* maximum segment size tcp option */ + tlen = sizeof(struct tcphdr); + if (mss) + tlen += 4; + switch (af) { #ifdef INET case AF_INET: - len = sizeof(struct ip) + sizeof(struct tcphdr); + len = sizeof(struct ip) + tlen; break; #endif /* INET */ #ifdef INET6 case AF_INET6: - len = sizeof(struct ip6_hdr) + sizeof(struct tcphdr); + len = sizeof(struct ip6_hdr) + tlen; break; #endif /* INET6 */ } @@ -1141,7 +1152,7 @@ pf_send_tcp(const struct pf_rule *r, sa_family_t af, /* IP header fields included in the TCP checksum */ h->ip_p = IPPROTO_TCP; - h->ip_len = htons(sizeof(*th)); + h->ip_len = htons(tlen); h->ip_src.s_addr = saddr->v4.s_addr; h->ip_dst.s_addr = daddr->v4.s_addr; @@ -1154,7 +1165,7 @@ pf_send_tcp(const struct pf_rule *r, sa_family_t af, /* IP header fields included in the TCP checksum */ h6->ip6_nxt = IPPROTO_TCP; - h6->ip6_plen = htons(sizeof(*th)); + h6->ip6_plen = htons(tlen); memcpy(&h6->ip6_src, &saddr->v6, sizeof(struct in6_addr)); memcpy(&h6->ip6_dst, &daddr->v6, sizeof(struct in6_addr)); @@ -1168,10 +1179,18 @@ pf_send_tcp(const struct pf_rule *r, sa_family_t af, th->th_dport = dport; th->th_seq = htonl(seq); th->th_ack = htonl(ack); - th->th_off = sizeof(*th) >> 2; + th->th_off = tlen >> 2; th->th_flags = flags; th->th_win = htons(win); + if (mss) { + opt = (char *)(th + 1); + opt[0] = TCPOPT_MAXSEG; + opt[1] = 4; + HTONS(mss); + bcopy((caddr_t)&mss, (caddr_t)(opt + 2), 2); + } + switch (af) { #ifdef INET case AF_INET: @@ -1194,7 +1213,7 @@ pf_send_tcp(const struct pf_rule *r, sa_family_t af, case AF_INET6: /* TCP checksum */ th->th_sum = in6_cksum(m, IPPROTO_TCP, - sizeof(struct ip6_hdr), sizeof(*th)); + sizeof(struct ip6_hdr), tlen); h6->ip6_vfc |= IPV6_VERSION; h6->ip6_hlim = IPV6_DEFHLIM; @@ -1983,6 +2002,94 @@ pf_get_wscale(struct mbuf *m, int off, u_int16_t th_off, sa_family_t af) return (wscale); } +u_int16_t +pf_get_mss(struct mbuf *m, int off, u_int16_t th_off, sa_family_t af) +{ + int hlen; + u_int8_t hdr[60]; + u_int8_t *opt, optlen; + u_int16_t mss = tcp_mssdflt; + + hlen = th_off << 2; /* hlen <= sizeof(hdr) */ + if (hlen <= sizeof(struct tcphdr)) + return (0); + if (!pf_pull_hdr(m, off, hdr, hlen, NULL, NULL, af)) + return (0); + opt = hdr + sizeof(struct tcphdr); + hlen -= sizeof(struct tcphdr); + while (hlen >= TCPOLEN_MAXSEG) { + switch (*opt) { + case TCPOPT_EOL: + case TCPOPT_NOP: + ++opt; + --hlen; + break; + case TCPOPT_MAXSEG: + bcopy((caddr_t)(opt + 2), (caddr_t)&mss, 2); + /* fallthrough */ + default: + optlen = opt[1]; + if (optlen < 2) + optlen = 2; + hlen -= optlen; + opt += optlen; + } + } + return (mss); +} + +u_int16_t +pf_calc_mss(struct pf_addr *addr, sa_family_t af, u_int16_t offer) +{ +#ifdef INET + struct sockaddr_in *dst; + struct route ro; +#endif /* INET */ +#ifdef INET6 + struct sockaddr_in6 *dst6; + struct route_in6 ro6; +#endif /* INET6 */ + struct rtentry *rt = NULL; + int hlen; + u_int16_t mss = tcp_mssdflt; + + switch (af) { +#ifdef INET + case AF_INET: + hlen = sizeof(struct ip); + bzero(&ro, sizeof(ro)); + dst = (struct sockaddr_in *)&ro.ro_dst; + dst->sin_family = AF_INET; + dst->sin_len = sizeof(*dst); + dst->sin_addr = addr->v4; + rtalloc_noclone(&ro, NO_CLONING); + rt = ro.ro_rt; + break; +#endif /* INET */ +#ifdef INET6 + case AF_INET6: + hlen = sizeof(struct ip6_hdr); + bzero(&ro6, sizeof(ro6)); + dst6 = (struct sockaddr_in6 *)&ro6.ro_dst; + dst6->sin6_family = AF_INET6; + dst6->sin6_len = sizeof(*dst6); + dst6->sin6_addr = addr->v6; + rtalloc_noclone((struct route *)&ro6, NO_CLONING); + rt = ro6.ro_rt; + break; +#endif /* INET6 */ + } + + if (rt && rt->rt_ifp) { + mss = rt->rt_ifp->if_mtu - hlen - sizeof(struct tcphdr); + mss = max(tcp_mssdflt, mss); + RTFREE(rt); + } + mss = min(mss, offer); + mss = max(mss, 64); /* sanity - at least max opt space */ + return (mss); +} + int pf_test_tcp(struct pf_rule **rm, struct pf_state **sm, int direction, struct ifnet *ifp, struct mbuf *m, int ipoff, int off, void *h, @@ -2003,6 +2110,7 @@ pf_test_tcp(struct pf_rule **rm, struct pf_state **sm, int direction, int rewrite = 0; struct pf_tag *pftag = NULL; int tag = -1; + u_int16_t mss = tcp_mssdflt; if (direction == PF_OUT) { bport = nport = th->th_sport; @@ -2134,7 +2242,7 @@ pf_test_tcp(struct pf_rule **rm, struct pf_state **sm, int direction, 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, + ntohl(th->th_ack), ack, TH_RST|TH_ACK, 0, 0, r->return_ttl); } else if ((af == AF_INET) && r->return_icmp) pf_send_icmp(m, r->return_icmp >> 8, @@ -2279,9 +2387,14 @@ 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(); + /* Find mss option */ + mss = pf_get_mss(m, off, th->th_off, af); + mss = pf_calc_mss(saddr, af, mss); + mss = pf_calc_mss(daddr, af, mss); + s->src.mss = mss; 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); + ntohl(th->th_seq) + 1, TH_SYN|TH_ACK, 0, s->src.mss, 0); return (PF_SYNPROXY_DROP); } } @@ -3126,7 +3239,7 @@ pf_test_state_tcp(struct pf_state **state, int direction, struct ifnet *ifp, 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); + TH_SYN|TH_ACK, 0, (*state)->src.mss, 0); return (PF_SYNPROXY_DROP); } else if (!(th->th_flags & TH_ACK) || (ntohl(th->th_ack) != (*state)->src.seqhi + 1) || @@ -3155,7 +3268,7 @@ pf_test_state_tcp(struct pf_state **state, int direction, struct ifnet *ifp, (*state)->dst.seqhi = arc4random(); pf_send_tcp((*state)->rule.ptr, pd->af, &src->addr, &dst->addr, src->port, dst->port, - (*state)->dst.seqhi, 0, TH_SYN, 0, 0); + (*state)->dst.seqhi, 0, TH_SYN, 0, (*state)->src.mss, 0); return (PF_SYNPROXY_DROP); } else if (((th->th_flags & (TH_SYN|TH_ACK)) != (TH_SYN|TH_ACK)) || @@ -3167,11 +3280,11 @@ pf_test_state_tcp(struct pf_state **state, int direction, struct ifnet *ifp, 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); + TH_ACK, (*state)->src.max_win, 0, 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); + TH_ACK, (*state)->dst.max_win, 0, 0); (*state)->src.seqdiff = (*state)->dst.seqhi - (*state)->src.seqlo; (*state)->dst.seqdiff = (*state)->src.seqhi - @@ -3438,7 +3551,7 @@ pf_test_state_tcp(struct pf_state **state, int direction, struct ifnet *ifp, 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, + TH_RST|TH_ACK, 0, 0, (*state)->rule.ptr->return_ttl); } src->seqlo = 0; diff --git a/sys/net/pfvar.h b/sys/net/pfvar.h index 746fd7151b5..5bea9368633 100644 --- a/sys/net/pfvar.h +++ b/sys/net/pfvar.h @@ -1,4 +1,4 @@ -/* $OpenBSD: pfvar.h,v 1.155 2003/06/09 11:14:46 mcbride Exp $ */ +/* $OpenBSD: pfvar.h,v 1.156 2003/06/20 18:24:57 dhartmei Exp $ */ /* * Copyright (c) 2001 Daniel Hartmeier @@ -441,6 +441,7 @@ struct pf_state_peer { u_int16_t max_win; /* largest window (pre scaling) */ u_int8_t state; /* active state level */ u_int8_t wscale; /* window scaling factor */ + u_int16_t mss; /* Maximum segment size option */ struct pf_state_scrub *scrub; /* state is scrubbed */ }; |