MSS clamping patch for ipnat
by Manuel Kasper <mk at neon1 dot net>
04/17/2004
This patch for ipfilter on FreeBSD 4.9 adds two sysctls that can be used to do
MSS clamping regardless of any ipnat rules (i.e. to clamp the MSS when no NAT is
required). It even works with an empty ipnat ruleset. If a matching NAT rule
with the mssclamp keyword is found, the MSS given in that rule is honored;
otherwise, the default (as set with the sysctl) is applied.
net.inet.ipf.fr_mssclamp
set to the desired MSS (usually MTU - 40), or 0 to disable
net.inet.ipf.fr_mssif
set to the interface name on which MSS clamping should take place
(empty string = disable)
Example (PPPoE with MPD):
sysctl net.inet.ipf.fr_mssif=ng0
sysctl net.inet.ipf.fr_mssclamp=1452
This patch is against ipfilter 3.4.33, so make sure to install that first
(FreeBSD 4.9 comes with buggy ipfilter 3.4.31).
--- sys/contrib/ipfilter/netinet/ip_nat.c.orig Wed Feb 11 16:16:22 2004
+++ sys/contrib/ipfilter/netinet/ip_nat.c Sat Apr 17 20:59:53 2004
@@ -126,6 +126,9 @@
ipnat_t **rdr_rules = NULL;
hostmap_t **maptable = NULL;
+int fr_mssclamp = 0;
+char fr_mssif[IFNAMSIZ] = "";
+
u_long fr_defnatage = DEF_NAT_AGE,
fr_defnaticmpage = 6; /* 3 seconds */
natstat_t nat_stats;
@@ -2374,8 +2377,10 @@
void *sifp;
u_32_t iph;
nat_t *nat;
+ int clamped = 0;
+ int retval = 0;
- if (nat_list == NULL || (fr_nat_lock))
+ if (fr_nat_lock)
return 0;
if ((fr = fin->fin_fr) && !(fr->fr_flags & FR_DUP) &&
@@ -2399,6 +2404,9 @@
}
ipa = fin->fin_saddr;
+
+ if (nat_list == NULL)
+ goto ip_natout_mss;
READ_ENTER(&ipf_nat);
@@ -2554,9 +2562,11 @@
* only deal IPv4 for now.
*/
if (nat->nat_mssclamp &&
- (tcp->th_flags & TH_SYN) != 0)
+ (tcp->th_flags & TH_SYN) != 0) {
nat_mssclamp(tcp, nat->nat_mssclamp,
fin, csump);
+ clamped = 1;
+ }
MUTEX_EXIT(&nat->nat_lock);
} else if (fin->fin_p == IPPROTO_UDP) {
@@ -2586,13 +2596,29 @@
} else
i = 1;
ATOMIC_INCL(nat_stats.ns_mapped[1]);
- RWLOCK_EXIT(&ipf_nat); /* READ */
- fin->fin_ifp = sifp;
- return i;
+ retval = i;
}
RWLOCK_EXIT(&ipf_nat); /* READ/WRITE */
+
+ip_natout_mss:
+ /* Handle MSS clamping, if necessary */
+ if (!clamped && (fr_mssclamp > 0) && (fr_mssif[0] != 0) &&
+ (fin->fin_off == 0) && !(fin->fin_fl & FI_SHORT) &&
+ (fin->fin_p == IPPROTO_TCP)) {
+
+ if ((tcp->th_flags & TH_SYN) != 0) {
+
+ /* Does the interface name match? */
+ char tmpifn[IFNAMSIZ];
+ snprintf(tmpifn, IFNAMSIZ, "%s%d", ifp->if_name, ifp->if_unit);
+
+ if (strncmp(tmpifn, fr_mssif, IFNAMSIZ) == 0)
+ nat_mssclamp(tcp, fr_mssclamp, fin, &tcp->th_sum);
+ }
+ }
+
fin->fin_ifp = sifp;
- return 0;
+ return retval;
}
@@ -2614,8 +2640,10 @@
int i, icmpset = 0;
nat_t *nat;
u_32_t iph;
+ int clamped = 0;
+ int retval = 0;
- if ((nat_list == NULL) || (ip->ip_v != 4) || (fr_nat_lock))
+ if ((ip->ip_v != 4) || (fr_nat_lock))
return 0;
if ((fin->fin_off == 0) && !(fin->fin_fl & FI_SHORT)) {
@@ -2633,6 +2661,9 @@
in = fin->fin_dst;
/* make sure the source address is to be redirected */
src = fin->fin_src;
+
+ if (nat_list == NULL)
+ goto ip_natin_mss;
READ_ENTER(&ipf_nat);
@@ -2775,9 +2806,11 @@
* only deal IPv4 for now.
*/
if (nat->nat_mssclamp &&
- (tcp->th_flags & TH_SYN) != 0)
+ (tcp->th_flags & TH_SYN) != 0) {
nat_mssclamp(tcp, nat->nat_mssclamp,
fin, csump);
+ clamped = 1;
+ }
MUTEX_EXIT(&nat->nat_lock);
} else if (fin->fin_p == IPPROTO_UDP) {
@@ -2797,11 +2830,28 @@
}
}
ATOMIC_INCL(nat_stats.ns_mapped[0]);
- RWLOCK_EXIT(&ipf_nat); /* READ */
- return 1;
+ retval = 1;
}
RWLOCK_EXIT(&ipf_nat); /* READ/WRITE */
- return 0;
+
+ip_natin_mss:
+ /* Handle MSS clamping, if necessary */
+ if (!clamped && (fr_mssclamp > 0) && (fr_mssif[0] != 0) &&
+ (fin->fin_off == 0) && !(fin->fin_fl & FI_SHORT) &&
+ (fin->fin_p == IPPROTO_TCP)) {
+
+ if ((tcp->th_flags & TH_SYN) != 0) {
+
+ /* Does the interface name match? */
+ char tmpifn[IFNAMSIZ];
+ snprintf(tmpifn, IFNAMSIZ, "%s%d", ifp->if_name, ifp->if_unit);
+
+ if (strncmp(tmpifn, fr_mssif, IFNAMSIZ) == 0)
+ nat_mssclamp(tcp, fr_mssclamp, fin, &tcp->th_sum);
+ }
+ }
+
+ return retval;
}
--- sys/contrib/ipfilter/netinet/ip_nat.h.orig Wed Feb 11 16:16:37 2004
+++ sys/contrib/ipfilter/netinet/ip_nat.h Sat Apr 17 20:45:37 2004
@@ -302,6 +302,8 @@
extern void ip_natsync __P((void *));
extern u_long fr_defnatage;
extern u_long fr_defnaticmpage;
+extern int fr_mssclamp;
+extern char fr_mssif[];
extern nat_t **nat_table[2];
extern nat_t *nat_instances;
extern ipnat_t **nat_rules;
--- sys/contrib/ipfilter/netinet/mlf_ipl.c.orig Tue Jun 4 16:51:31 2002
+++ sys/contrib/ipfilter/netinet/mlf_ipl.c Sat Apr 17 20:45:42 2004
@@ -131,6 +131,10 @@
&fr_defaultauthage, 0, "");
SYSCTL_INT(_net_inet_ipf, OID_AUTO, ippr_ftp_pasvonly, CTLFLAG_RW,
&ippr_ftp_pasvonly, 0, "");
+SYSCTL_INT(_net_inet_ipf, OID_AUTO, fr_mssclamp, CTLFLAG_RW,
+ &fr_mssclamp, 0, "");
+SYSCTL_STRING(_net_inet_ipf, OID_AUTO, fr_mssif, CTLFLAG_RW,
+ fr_mssif, IFNAMSIZ, "");
#endif
#ifdef DEVFS
--- sys/contrib/ipfilter/netinet/mlfk_ipl.c.orig Mon Aug 27 23:14:04 2001
+++ sys/contrib/ipfilter/netinet/mlfk_ipl.c Sat Apr 17 20:45:44 2004
@@ -102,6 +102,10 @@
SYSCTL_INT(_net_inet_ipf, OID_AUTO, fr_minttl, CTLFLAG_RW, &fr_minttl, 0, "");
SYSCTL_INT(_net_inet_ipf, OID_AUTO, fr_minttllog, CTLFLAG_RW,
&fr_minttllog, 0, "");
+SYSCTL_INT(_net_inet_ipf, OID_AUTO, fr_mssclamp, CTLFLAG_RW,
+ &fr_mssclamp, 0, "");
+SYSCTL_STRING(_net_inet_ipf, OID_AUTO, fr_mssif, CTLFLAG_RW,
+ fr_mssif, IFNAMSIZ, "");
#define CDEV_MAJOR 79
static struct cdevsw ipl_cdevsw = { |