diff options
author | glebius <glebius@FreeBSD.org> | 2005-06-27 07:39:13 +0000 |
---|---|---|
committer | glebius <glebius@FreeBSD.org> | 2005-06-27 07:39:13 +0000 |
commit | 9c25e36cc6415532f6804a2e1f07ba5ba05b52b5 (patch) | |
tree | 07956e1a1151cf2101caa41258a651e9f9d835a7 /sys/netgraph/ng_nat.c | |
parent | 07317cc4f01f0501954f60e3a17e82187aa99a90 (diff) | |
download | FreeBSD-src-9c25e36cc6415532f6804a2e1f07ba5ba05b52b5.zip FreeBSD-src-9c25e36cc6415532f6804a2e1f07ba5ba05b52b5.tar.gz |
- After LibAlias processing check for TCP packet with th_x2 field
set. If found, then recalculate its checksum.
- Remove debugging printfs.
- Slightly rearrange code in ng_nat_rcvdata().
Approved by: re (scottl)
Diffstat (limited to 'sys/netgraph/ng_nat.c')
-rw-r--r-- | sys/netgraph/ng_nat.c | 59 |
1 files changed, 51 insertions, 8 deletions
diff --git a/sys/netgraph/ng_nat.c b/sys/netgraph/ng_nat.c index 2395ce5..bb3f828 100644 --- a/sys/netgraph/ng_nat.c +++ b/sys/netgraph/ng_nat.c @@ -38,9 +38,9 @@ #include <netinet/in_systm.h> #include <netinet/in.h> #include <netinet/ip.h> -#include <netinet/ip_icmp.h> +#include <netinet/ip_var.h> #include <netinet/tcp.h> -#include <netinet/udp.h> +#include <machine/in_cksum.h> #include <netinet/libalias/alias.h> @@ -232,24 +232,67 @@ ng_nat_rcvdata(hook_p hook, item_p item ) if (hook == priv->in) { rval = LibAliasIn(priv->lib, c, MCLBYTES); if (rval != PKT_ALIAS_OK) { - printf("in %u\n", rval); NG_FREE_ITEM(item); return (EINVAL); } - m->m_pkthdr.len = m->m_len = ntohs(ip->ip_len); - NG_FWD_ITEM_HOOK(error, item, priv->out); } else if (hook == priv->out) { rval = LibAliasOut(priv->lib, c, MCLBYTES); if (rval != PKT_ALIAS_OK) { - printf("out %u\n", rval); NG_FREE_ITEM(item); return (EINVAL); } - m->m_pkthdr.len = m->m_len = ntohs(ip->ip_len); - NG_FWD_ITEM_HOOK(error, item, priv->in); } else panic("ng_nat: unknown hook!\n"); + m->m_pkthdr.len = m->m_len = ntohs(ip->ip_len); + + if ((ip->ip_off & htons(IP_OFFMASK)) == 0 && + ip->ip_p == IPPROTO_TCP) { + struct tcphdr *th = (struct tcphdr *)(ip + 1); + + /* + * Here is our terrible HACK. + * + * Sometimes LibAlias edits contents of TCP packet. + * In this case it needs to recompute full TCP + * checksum. However, the problem is that LibAlias + * doesn't have any idea about checksum offloading + * in kernel. To workaround this, we do not do + * checksumming in LibAlias, but only mark the + * packets in th_x2 field. If we receive a marked + * packet, we calculate correct checksum for it + * aware of offloading. + * + * Why do I do such a terrible hack instead of + * recalculating checksum for each packet? + * Because the previous checksum was not checked! + * Recalculating checksums for EVERY packet will + * hide ALL transmission errors. Yes, marked packets + * still suffer from this problem. But, sigh, natd(8) + * has this problem, too. + */ + + if (th->th_x2) { + th->th_x2 = 0; + ip->ip_len = ntohs(ip->ip_len); + th->th_sum = in_pseudo(ip->ip_src.s_addr, + ip->ip_dst.s_addr, htons(IPPROTO_TCP + + ip->ip_len - (ip->ip_hl << 2))); + + if ((m->m_pkthdr.csum_flags & CSUM_TCP) == 0) { + m->m_pkthdr.csum_data = offsetof(struct tcphdr, + th_sum); + in_delayed_cksum(m); + } + ip->ip_len = htons(ip->ip_len); + } + } + + if (hook == priv->in) + NG_FWD_ITEM_HOOK(error, item, priv->out); + else + NG_FWD_ITEM_HOOK(error, item, priv->in); + return (error); } |