summaryrefslogtreecommitdiffstats
path: root/sys/netgraph/ng_nat.c
diff options
context:
space:
mode:
authorglebius <glebius@FreeBSD.org>2005-06-27 07:39:13 +0000
committerglebius <glebius@FreeBSD.org>2005-06-27 07:39:13 +0000
commit9c25e36cc6415532f6804a2e1f07ba5ba05b52b5 (patch)
tree07956e1a1151cf2101caa41258a651e9f9d835a7 /sys/netgraph/ng_nat.c
parent07317cc4f01f0501954f60e3a17e82187aa99a90 (diff)
downloadFreeBSD-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.c59
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);
}
OpenPOWER on IntegriCloud