Subject: Re: MSS clamping proposal
To: None <tech-kern@NetBSD.ORG>
From: Martin Husemann <martin@duskware.de>
List: tech-kern
Date: 03/13/2002 22:11:56
--jI8keyz6grp/JLjh
Content-Type: text/plain; charset=us-ascii
Content-Disposition: inline
Ok, to me it looks like we nearly have a consensus.
I verified that you can do 1:1 NATs and clamp thereby, without actually
touching IP addresses:
List of active MAP/Redirect filters:
map pppoe0 217.0.156.252/32 -> 217.0.156.252/32 portmap tcp/udp 40000:42999 mssclamp 1452
map pppoe0 217.0.156.252/32 -> 217.0.156.252/32 mssclamp 1452
(There portmap line wasn't needed, I just forgot to delete it)
I cleaned up the code (long lines, etc...) and attach a new version (only
the ip_nat.c part has changed, IIRC).
Martin
--jI8keyz6grp/JLjh
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment; filename="clamp.patch"
Index: ip_nat.c
===================================================================
RCS file: /cvsroot/syssrc/sys/netinet/ip_nat.c,v
retrieving revision 1.44
diff -c -u -r1.44 ip_nat.c
--- ip_nat.c 2002/01/24 08:23:44 1.44
+++ ip_nat.c 2002/03/13 20:57:21
@@ -153,8 +153,8 @@
static hostmap_t *nat_hostmap __P((ipnat_t *, struct in_addr,
struct in_addr));
static void nat_hostmapdel __P((struct hostmap *));
+static void tcp_mss_clamp __P((tcphdr_t *, uint32_t, fr_info_t *, u_short *));
-
int nat_init()
{
KMALLOCS(nat_table[0], nat_t **, sizeof(nat_t *) * ipf_nattable_sz);
@@ -1127,6 +1127,47 @@
return i;
}
+/*
+ * Check for MSS option and clamp it if necessary.
+ */
+static __inline void
+tcp_mss_clamp(tcp, maxmss, fin, csump)
+ tcphdr_t *tcp;
+ uint32_t maxmss;
+ fr_info_t *fin;
+ u_short *csump;
+{
+ uint8_t *cp;
+ uint32_t opt, mss, sumd;
+ int hlen;
+
+ hlen = tcp->th_off << 2;
+ if (hlen > sizeof(*tcp)) {
+ cp = (uint8_t *)tcp + sizeof(*tcp);
+
+ while (hlen > 0) {
+ opt = *cp++;
+ switch(opt) {
+ case TCPOPT_MAXSEG:
+ ++cp;
+ mss = (uint32_t)ntohs(*(short *)cp);
+ if (mss > maxmss) {
+ *(short *)cp = htons((short)(maxmss));
+ CALC_SUMD(mss, maxmss, sumd);
+ fix_outcksum(fin, csump, sumd);
+ }
+ hlen = 0;
+ break;
+ case TCPOPT_EOL:
+ case TCPOPT_NOP:
+ hlen--;
+ default:
+ hlen -= *cp;
+ cp += *cp - 2;
+ }
+ }
+ }
+}
/*
* Create a new NAT table entry.
@@ -1459,6 +1500,7 @@
nat->nat_dir = direction;
nat->nat_ifp = fin->fin_ifp;
nat->nat_ptr = np;
+ nat->nat_mssclamp = np->in_mssclamp;
nat->nat_p = fin->fin_p;
nat->nat_bytes = 0;
nat->nat_pkts = 0;
@@ -2469,6 +2511,15 @@
*/
if (nat->nat_age == fr_tcpclosed)
nat->nat_age = fr_tcplastack;
+
+ /*
+ * Do a MSS CLAMPING on a SYN packet,
+ * only deal IPv4 for now.
+ */
+ if (nat->nat_mssclamp &&
+ (tcp->th_flags & TH_SYN) != 0)
+ tcp_mss_clamp(tcp, nat->nat_mssclamp, fin, csump);
+
MUTEX_EXIT(&nat->nat_lock);
} else if (fin->fin_p == IPPROTO_UDP) {
udphdr_t *udp = (udphdr_t *)tcp;
Index: ip_nat.h
===================================================================
RCS file: /cvsroot/syssrc/sys/netinet/ip_nat.h,v
retrieving revision 1.24
diff -c -u -r1.24 ip_nat.h
--- ip_nat.h 2002/01/24 08:23:14 1.24
+++ ip_nat.h 2002/03/13 20:57:21
@@ -77,6 +77,7 @@
struct in_addr nat_inip;
struct in_addr nat_outip;
struct in_addr nat_oip; /* other ip */
+ u_32_t nat_mssclamp; /* if != zero clamp MSS to this */
U_QUAD_T nat_pkts;
U_QUAD_T nat_bytes;
u_short nat_oport; /* other port */
@@ -113,6 +114,7 @@
struct in_addr in_nextip;
u_short in_pnext;
u_short in_ippip; /* IP #'s per IP# */
+ u_32_t in_mssclamp; /* if != zero clamp MSS to this */
u_32_t in_flags; /* From here to in_dport must be reflected */
u_short in_spare;
u_short in_ppip; /* ports per IP */
Index: natparse.c
===================================================================
RCS file: /cvsroot/basesrc/dist/ipf/natparse.c,v
retrieving revision 1.5
diff -c -u -r1.5 natparse.c
--- natparse.c 2002/01/24 08:21:35 1.5
+++ natparse.c 2002/03/13 20:58:36
@@ -697,6 +697,14 @@
cpp++;
}
+ if (*cpp && !strcasecmp(*cpp, "mssclamp")) {
+ cpp++;
+ if (*cpp) {
+ ipn.in_mssclamp = atoi(*cpp);
+ cpp++;
+ }
+ }
+
if (*cpp) {
fprintf(stderr, "%d: extra junk at the end of the line: %s\n",
linenum, *cpp);
Index: printnat.c
===================================================================
RCS file: /cvsroot/basesrc/dist/ipf/printnat.c,v
retrieving revision 1.2
diff -c -u -r1.2 printnat.c
--- printnat.c 2002/01/24 10:40:12 1.2
+++ printnat.c 2002/03/13 20:58:36
@@ -451,6 +451,8 @@
}
if (np->in_flags & IPN_FRAG)
printf(" frag");
+ if (np->in_mssclamp)
+ printf(" mssclamp %u", (unsigned)np->in_mssclamp);
printf("\n");
if (opts & OPT_DEBUG) {
printf("\tspace %lu nextip %s pnext %d", np->in_space,
--jI8keyz6grp/JLjh--