Page MenuHomeFreeBSD

D10150.diff
No OneTemporary

D10150.diff

Index: head/sbin/ipfw/ipfw.8
===================================================================
--- head/sbin/ipfw/ipfw.8
+++ head/sbin/ipfw/ipfw.8
@@ -1,7 +1,7 @@
.\"
.\" $FreeBSD$
.\"
-.Dd March 15, 2017
+.Dd April 3, 2017
.Dt IPFW 8
.Os
.Sh NAME
@@ -1118,6 +1118,20 @@
keyword with setdscp.
If the tablearg value is not within the 0..64 range, lower 6 bits of supplied
value are used.
+.It Cm tcp-setmss Ar mss
+Set the Maximum Segment Size (MSS) in the TCP segment to value
+.Ar mss .
+The kernel module
+.Cm ipfw_pmod
+should be loaded or kernel should have
+.Cm options IPFIREWALL_PMOD
+to be able use this action.
+This command does not change a packet if original MSS value is lower than
+specified value.
+Both TCP over IPv4 and over IPv6 are supported.
+Regardless of matched a packet or not by the
+.Cm tcp-setmss
+rule, the search continues with the next rule.
.It Cm reass
Queue and reassemble IP fragments.
If the packet is not fragmented, counters are updated and
Index: head/sbin/ipfw/ipfw2.h
===================================================================
--- head/sbin/ipfw/ipfw2.h
+++ head/sbin/ipfw/ipfw2.h
@@ -284,6 +284,8 @@
TOK_INTPREFIX,
TOK_EXTPREFIX,
TOK_PREFIXLEN,
+
+ TOK_TCPSETMSS,
};
/*
Index: head/sbin/ipfw/ipfw2.c
===================================================================
--- head/sbin/ipfw/ipfw2.c
+++ head/sbin/ipfw/ipfw2.c
@@ -36,6 +36,7 @@
#include <pwd.h>
#include <stdio.h>
#include <stdarg.h>
+#include <stdint.h>
#include <stdlib.h>
#include <string.h>
#include <sysexits.h>
@@ -238,6 +239,7 @@
{ "nat64lsn", TOK_NAT64LSN },
{ "nat64stl", TOK_NAT64STL },
{ "nptv6", TOK_NPTV6 },
+ { "tcp-setmss", TOK_TCPSETMSS },
{ NULL, 0 } /* terminator */
};
@@ -272,6 +274,7 @@
{ "call", TOK_CALL },
{ "return", TOK_RETURN },
{ "eaction", TOK_EACTION },
+ { "tcp-setmss", TOK_TCPSETMSS },
{ NULL, 0 } /* terminator */
};
@@ -4007,6 +4010,26 @@
fill_cmd(action, O_CALLRETURN, F_NOT, 0);
break;
+ case TOK_TCPSETMSS: {
+ u_long mss;
+ uint16_t idx;
+
+ idx = pack_object(tstate, "tcp-setmss", IPFW_TLV_EACTION);
+ if (idx == 0)
+ errx(EX_DATAERR, "pack_object failed");
+ fill_cmd(action, O_EXTERNAL_ACTION, 0, idx);
+ NEED1("Missing MSS value");
+ action = next_cmd(action, &ablen);
+ action->len = 1;
+ CHECK_ACTLEN;
+ mss = strtoul(*av, NULL, 10);
+ if (mss == 0 || mss > UINT16_MAX)
+ errx(EX_USAGE, "invalid MSS value %s", *av);
+ fill_cmd(action, O_EXTERNAL_DATA, 0, (uint16_t)mss);
+ av++;
+ break;
+ }
+
default:
av--;
if (match_token(rule_eactions, *av) == -1)
Index: head/sys/conf/NOTES
===================================================================
--- head/sys/conf/NOTES
+++ head/sys/conf/NOTES
@@ -971,6 +971,9 @@
#
# IPFIREWALL_NPTV6 adds support for in kernel NPTv6 in ipfw.
#
+# IPFIREWALL_PMOD adds support for protocols modification module. Currently
+# it supports only TCP MSS modification.
+#
# IPSTEALTH enables code to support stealth forwarding (i.e., forwarding
# packets without touching the TTL). This can be useful to hide firewalls
# from traceroute and similar tools.
Index: head/sys/conf/files
===================================================================
--- head/sys/conf/files
+++ head/sys/conf/files
@@ -4230,6 +4230,8 @@
ipfirewall_nptv6
netpfil/ipfw/nptv6/nptv6.c optional inet inet6 ipfirewall \
ipfirewall_nptv6
+netpfil/ipfw/pmod/ip_fw_pmod.c optional inet ipfirewall_pmod
+netpfil/ipfw/pmod/tcpmod.c optional inet ipfirewall_pmod
netpfil/pf/if_pflog.c optional pflog pf inet
netpfil/pf/if_pfsync.c optional pfsync pf inet
netpfil/pf/pf.c optional pf inet
Index: head/sys/conf/options
===================================================================
--- head/sys/conf/options
+++ head/sys/conf/options
@@ -426,6 +426,7 @@
IPFIREWALL_NPTV6 opt_ipfw.h
IPFIREWALL_VERBOSE opt_ipfw.h
IPFIREWALL_VERBOSE_LIMIT opt_ipfw.h
+IPFIREWALL_PMOD opt_ipfw.h
IPSEC opt_ipsec.h
IPSEC_DEBUG opt_ipsec.h
IPSEC_SUPPORT opt_ipsec.h
Index: head/sys/modules/Makefile
===================================================================
--- head/sys/modules/Makefile
+++ head/sys/modules/Makefile
@@ -173,6 +173,7 @@
ipfw_nat \
${_ipfw_nat64} \
${_ipfw_nptv6} \
+ ${_ipfw_pmod} \
${_ipmi} \
ip6_mroute_mod \
ip_mroute_mod \
@@ -443,6 +444,7 @@
_if_enc= if_enc
_if_gif= if_gif
_if_gre= if_gre
+_ipfw_pmod= ipfw_pmod
.if ${MK_IPSEC_SUPPORT} != "no"
_ipsec= ipsec
.endif
Index: head/sys/modules/ipfw_pmod/Makefile
===================================================================
--- head/sys/modules/ipfw_pmod/Makefile
+++ head/sys/modules/ipfw_pmod/Makefile
@@ -0,0 +1,8 @@
+# $FreeBSD$
+
+.PATH: ${SRCTOP}/sys/netpfil/ipfw/pmod
+
+KMOD= ipfw_pmod
+SRCS= ip_fw_pmod.c tcpmod.c opt_inet.h opt_inet6.h
+
+.include <bsd.kmod.mk>
Index: head/sys/netpfil/ipfw/pmod/ip_fw_pmod.c
===================================================================
--- head/sys/netpfil/ipfw/pmod/ip_fw_pmod.c
+++ head/sys/netpfil/ipfw/pmod/ip_fw_pmod.c
@@ -0,0 +1,101 @@
+/*-
+ * Copyright (c) 2017 Yandex LLC
+ * Copyright (c) 2017 Andrey V. Elsukov <ae@FreeBSD.org>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/kernel.h>
+#include <sys/lock.h>
+#include <sys/malloc.h>
+#include <sys/module.h>
+#include <sys/rwlock.h>
+#include <sys/socket.h>
+
+#include <net/if.h>
+#include <net/vnet.h>
+
+#include <netinet/in.h>
+#include <netinet/ip_var.h>
+#include <netinet/ip_fw.h>
+
+#include <netpfil/ipfw/ip_fw_private.h>
+#include <netpfil/ipfw/pmod/pmod.h>
+
+static int
+vnet_ipfw_pmod_init(const void *arg __unused)
+{
+ int error;
+
+ error = tcpmod_init(&V_layer3_chain, IS_DEFAULT_VNET(curvnet));
+ return (error);
+}
+
+static int
+vnet_ipfw_pmod_uninit(const void *arg __unused)
+{
+
+ tcpmod_uninit(&V_layer3_chain, IS_DEFAULT_VNET(curvnet));
+ return (0);
+}
+
+static int
+ipfw_pmod_modevent(module_t mod, int type, void *unused)
+{
+
+ switch (type) {
+ case MOD_LOAD:
+ case MOD_UNLOAD:
+ break;
+ default:
+ return (EOPNOTSUPP);
+ }
+ return (0);
+}
+
+static moduledata_t ipfw_pmod_mod = {
+ "ipfw_pmod",
+ ipfw_pmod_modevent,
+ 0
+};
+
+/* Define startup order. */
+#define IPFW_PMOD_SI_SUB_FIREWALL SI_SUB_PROTO_IFATTACHDOMAIN
+#define IPFW_PMOD_MODEVENT_ORDER (SI_ORDER_ANY - 128) /* after ipfw */
+#define IPFW_PMOD_MODULE_ORDER (IPFW_PMOD_MODEVENT_ORDER + 1)
+#define IPFW_PMOD_VNET_ORDER (IPFW_PMOD_MODEVENT_ORDER + 2)
+
+DECLARE_MODULE(ipfw_pmod, ipfw_pmod_mod, IPFW_PMOD_SI_SUB_FIREWALL,
+ IPFW_PMOD_MODULE_ORDER);
+MODULE_DEPEND(ipfw_pmod, ipfw, 3, 3, 3);
+MODULE_VERSION(ipfw_pmod, 1);
+
+VNET_SYSINIT(vnet_ipfw_pmod_init, IPFW_PMOD_SI_SUB_FIREWALL,
+ IPFW_PMOD_VNET_ORDER, vnet_ipfw_pmod_init, NULL);
+VNET_SYSUNINIT(vnet_ipfw_pmod_uninit, IPFW_PMOD_SI_SUB_FIREWALL,
+ IPFW_PMOD_VNET_ORDER, vnet_ipfw_pmod_uninit, NULL);
Index: head/sys/netpfil/ipfw/pmod/pmod.h
===================================================================
--- head/sys/netpfil/ipfw/pmod/pmod.h
+++ head/sys/netpfil/ipfw/pmod/pmod.h
@@ -0,0 +1,36 @@
+/*-
+ * Copyright (c) 2017 Yandex LLC
+ * Copyright (c) 2017 Andrey V. Elsukov <ae@FreeBSD.org>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+
+#ifndef _IP_FW_PMOD_H_
+#define _IP_FW_PMOD_H_
+
+int tcpmod_init(struct ip_fw_chain *ch, int first);
+void tcpmod_uninit(struct ip_fw_chain *ch, int last);
+#endif /* _IP_FW_PMOD_H_ */
+
Index: head/sys/netpfil/ipfw/pmod/tcpmod.c
===================================================================
--- head/sys/netpfil/ipfw/pmod/tcpmod.c
+++ head/sys/netpfil/ipfw/pmod/tcpmod.c
@@ -0,0 +1,246 @@
+/*-
+ * Copyright (c) 2017 Yandex LLC
+ * Copyright (c) 2017 Andrey V. Elsukov <ae@FreeBSD.org>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "opt_inet.h"
+#include "opt_inet6.h"
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/errno.h>
+#include <sys/kernel.h>
+#include <sys/mbuf.h>
+#include <sys/module.h>
+#include <sys/socket.h>
+
+#include <net/if.h>
+#include <net/if_var.h>
+#include <net/pfil.h>
+#include <net/vnet.h>
+
+#include <netinet/in.h>
+#include <netinet/ip.h>
+#include <netinet/ip_var.h>
+#include <netinet/tcp.h>
+#include <netinet/ip_fw.h>
+#include <netinet/ip6.h>
+
+#include <netpfil/ipfw/ip_fw_private.h>
+#include <netpfil/ipfw/pmod/pmod.h>
+
+#include <machine/in_cksum.h>
+
+static VNET_DEFINE(uint16_t, tcpmod_setmss_eid) = 0;
+#define V_tcpmod_setmss_eid VNET(tcpmod_setmss_eid)
+
+static int
+tcpmod_setmss(struct mbuf **mp, struct tcphdr *tcp, int tlen, uint16_t mss)
+{
+ struct mbuf *m;
+ u_char *cp;
+ int optlen, ret;
+ uint16_t oldmss, csum;
+
+ m = *mp;
+ ret = IP_FW_DENY;
+ if (m->m_len < m->m_pkthdr.len) {
+ /*
+ * We shouldn't have any data, IP packet contains only
+ * TCP header with options.
+ */
+ *mp = m = m_pullup(m, m->m_pkthdr.len);
+ if (m == NULL)
+ return (ret);
+ }
+ /* Parse TCP options. */
+ for (tlen -= sizeof(struct tcphdr), cp = (u_char *)(tcp + 1);
+ tlen > 0; tlen -= optlen, cp += optlen) {
+ if (cp[0] == TCPOPT_EOL)
+ break;
+ if (cp[0] == TCPOPT_NOP) {
+ optlen = 1;
+ continue;
+ }
+ if (tlen < 2)
+ break;
+ optlen = cp[1];
+ if (optlen < 2 || optlen > tlen)
+ break;
+ if (cp[0] == TCPOPT_MAXSEG) {
+ if (optlen != TCPOLEN_MAXSEG)
+ break;
+ ret = 0; /* report success */
+ bcopy(cp + 2, &oldmss, sizeof(oldmss));
+ /* Do not update lower MSS value */
+ if (oldmss <= mss)
+ break;
+ bcopy(&mss, cp + 2, sizeof(mss));
+ /* Update checksum if it is not delayed. */
+ if ((m->m_pkthdr.csum_flags &
+ (CSUM_TCP | CSUM_TCP_IPV6)) == 0) {
+ bcopy(&tcp->th_sum, &csum, sizeof(csum));
+ csum = cksum_adjust(csum, oldmss, mss);
+ bcopy(&csum, &tcp->th_sum, sizeof(csum));
+ }
+ break;
+ }
+ }
+
+ return (ret);
+}
+
+#ifdef INET6
+static int
+tcpmod_ipv6_setmss(struct mbuf **mp, uint16_t mss)
+{
+ struct ip6_hdr *ip6;
+ struct ip6_hbh *hbh;
+ struct tcphdr *tcp;
+ int hlen, plen, proto;
+
+ ip6 = mtod(*mp, struct ip6_hdr *);
+ hlen = sizeof(*ip6);
+ proto = ip6->ip6_nxt;
+ /*
+ * Skip IPv6 extension headers and get the TCP header.
+ * ipfw_chk() has already done this work. So we are sure that
+ * we will not do an access to the out of bounds. For this
+ * reason we skip some checks here.
+ */
+ while (proto == IPPROTO_HOPOPTS || proto == IPPROTO_ROUTING ||
+ proto == IPPROTO_DSTOPTS) {
+ hbh = mtodo(*mp, hlen);
+ proto = hbh->ip6h_nxt;
+ hlen += hbh->ip6h_len << 3;
+ }
+ tcp = mtodo(*mp, hlen);
+ plen = (*mp)->m_pkthdr.len - hlen;
+ hlen = tcp->th_off << 2;
+ /* We must have TCP options and enough data in a packet. */
+ if (hlen <= sizeof(struct tcphdr) || hlen > plen)
+ return (IP_FW_DENY);
+ return (tcpmod_setmss(mp, tcp, hlen, mss));
+}
+#endif /* INET6 */
+
+#ifdef INET
+static int
+tcpmod_ipv4_setmss(struct mbuf **mp, uint16_t mss)
+{
+ struct tcphdr *tcp;
+ struct ip *ip;
+ int hlen, plen;
+
+ ip = mtod(*mp, struct ip *);
+ hlen = ip->ip_hl << 2;
+ tcp = mtodo(*mp, hlen);
+ plen = (*mp)->m_pkthdr.len - hlen;
+ hlen = tcp->th_off << 2;
+ /* We must have TCP options and enough data in a packet. */
+ if (hlen <= sizeof(struct tcphdr) || hlen > plen)
+ return (IP_FW_DENY);
+ return (tcpmod_setmss(mp, tcp, hlen, mss));
+}
+#endif /* INET */
+
+/*
+ * ipfw external action handler.
+ */
+static int
+ipfw_tcpmod(struct ip_fw_chain *chain, struct ip_fw_args *args,
+ ipfw_insn *cmd, int *done)
+{
+ ipfw_insn *icmd;
+ int ret;
+
+ *done = 0; /* try next rule if not matched */
+ ret = IP_FW_DENY;
+ icmd = cmd + 1;
+ if (cmd->opcode != O_EXTERNAL_ACTION ||
+ cmd->arg1 != V_tcpmod_setmss_eid ||
+ icmd->opcode != O_EXTERNAL_DATA ||
+ icmd->len != F_INSN_SIZE(ipfw_insn))
+ return (ret);
+
+ /*
+ * NOTE: ipfw_chk() can set f_id.proto from IPv6 fragment header,
+ * but f_id._flags can be filled only from real TCP header.
+ *
+ * NOTE: ipfw_chk() drops very short packets in the PULLUP_TO()
+ * macro. But we need to check that mbuf is contiguous more than
+ * IP+IP_options/IP_extensions+tcphdr length, because TCP header
+ * must have TCP options, and ipfw_chk() does PULLUP_TO() size of
+ * struct tcphdr.
+ *
+ * NOTE: we require only the presence of SYN flag. User should
+ * properly configure the rule to select the direction of packets,
+ * that should be modified.
+ */
+ if (args->f_id.proto != IPPROTO_TCP ||
+ (args->f_id._flags & TH_SYN) == 0)
+ return (ret);
+
+ switch (args->f_id.addr_type) {
+#ifdef INET
+ case 4:
+ ret = tcpmod_ipv4_setmss(&args->m, htons(icmd->arg1));
+ break;
+#endif
+#ifdef INET6
+ case 6:
+ ret = tcpmod_ipv6_setmss(&args->m, htons(icmd->arg1));
+ break;
+#endif
+ }
+ /*
+ * We return zero in both @ret and @done on success, and ipfw_chk()
+ * will update rule counters. Otherwise a packet will not be matched
+ * by rule.
+ */
+ return (ret);
+}
+
+int
+tcpmod_init(struct ip_fw_chain *ch, int first)
+{
+
+ V_tcpmod_setmss_eid = ipfw_add_eaction(ch, ipfw_tcpmod, "tcp-setmss");
+ if (V_tcpmod_setmss_eid == 0)
+ return (ENXIO);
+ return (0);
+}
+
+void
+tcpmod_uninit(struct ip_fw_chain *ch, int last)
+{
+
+ ipfw_del_eaction(ch, V_tcpmod_setmss_eid);
+ V_tcpmod_setmss_eid = 0;
+}
+

File Metadata

Mime Type
text/plain
Expires
Wed, Feb 18, 10:00 AM (1 h, 42 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
28844700
Default Alt Text
D10150.diff (16 KB)

Event Timeline