mirror of
https://git.FreeBSD.org/src.git
synced 2025-01-01 12:19:28 +00:00
Add ipfw_pmod kernel module.
The module is designed for modification of a packets of any protocols. For now it implements only TCP MSS modification. It adds the external action handler for "tcp-setmss" action. A rule with tcp-setmss action does additional check for protocol and TCP flags. If SYN flag is present, it parses TCP options and modifies MSS option if its value is greater than configured value in the rule. Then it adjustes TCP checksum if needed. After handling the search continues with the next rule. Obtained from: Yandex LLC MFC after: 2 weeks Relnotes: yes Sponsored by: Yandex LLC No objection from: #network Differential Revision: https://reviews.freebsd.org/D10150
This commit is contained in:
parent
11c56650f0
commit
aac74aeac7
Notes:
svn2git
2020-12-20 02:59:44 +00:00
svn path=/head/; revision=316435
@ -1,7 +1,7 @@
|
||||
.\"
|
||||
.\" $FreeBSD$
|
||||
.\"
|
||||
.Dd March 15, 2017
|
||||
.Dd April 3, 2017
|
||||
.Dt IPFW 8
|
||||
.Os
|
||||
.Sh NAME
|
||||
@ -1118,6 +1118,20 @@ It is also possible to use the
|
||||
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
|
||||
|
@ -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 @@ static struct _s_x rule_eactions[] = {
|
||||
{ "nat64lsn", TOK_NAT64LSN },
|
||||
{ "nat64stl", TOK_NAT64STL },
|
||||
{ "nptv6", TOK_NPTV6 },
|
||||
{ "tcp-setmss", TOK_TCPSETMSS },
|
||||
{ NULL, 0 } /* terminator */
|
||||
};
|
||||
|
||||
@ -272,6 +274,7 @@ static struct _s_x rule_actions[] = {
|
||||
{ "call", TOK_CALL },
|
||||
{ "return", TOK_RETURN },
|
||||
{ "eaction", TOK_EACTION },
|
||||
{ "tcp-setmss", TOK_TCPSETMSS },
|
||||
{ NULL, 0 } /* terminator */
|
||||
};
|
||||
|
||||
@ -4007,6 +4010,26 @@ compile_rule(char *av[], uint32_t *rbuf, int *rbufsize, struct tidx *tstate)
|
||||
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)
|
||||
|
@ -284,6 +284,8 @@ enum tokens {
|
||||
TOK_INTPREFIX,
|
||||
TOK_EXTPREFIX,
|
||||
TOK_PREFIXLEN,
|
||||
|
||||
TOK_TCPSETMSS,
|
||||
};
|
||||
|
||||
/*
|
||||
|
@ -971,6 +971,9 @@ device lagg
|
||||
#
|
||||
# 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.
|
||||
|
@ -4230,6 +4230,8 @@ netpfil/ipfw/nptv6/ip_fw_nptv6.c optional inet inet6 ipfirewall \
|
||||
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
|
||||
|
@ -426,6 +426,7 @@ IPFIREWALL_NAT64_DIRECT_OUTPUT opt_ipfw.h
|
||||
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
|
||||
|
@ -173,6 +173,7 @@ SUBDIR= \
|
||||
ipfw_nat \
|
||||
${_ipfw_nat64} \
|
||||
${_ipfw_nptv6} \
|
||||
${_ipfw_pmod} \
|
||||
${_ipmi} \
|
||||
ip6_mroute_mod \
|
||||
ip_mroute_mod \
|
||||
@ -443,6 +444,7 @@ _toecore= toecore
|
||||
_if_enc= if_enc
|
||||
_if_gif= if_gif
|
||||
_if_gre= if_gre
|
||||
_ipfw_pmod= ipfw_pmod
|
||||
.if ${MK_IPSEC_SUPPORT} != "no"
|
||||
_ipsec= ipsec
|
||||
.endif
|
||||
|
8
sys/modules/ipfw_pmod/Makefile
Normal file
8
sys/modules/ipfw_pmod/Makefile
Normal file
@ -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>
|
101
sys/netpfil/ipfw/pmod/ip_fw_pmod.c
Normal file
101
sys/netpfil/ipfw/pmod/ip_fw_pmod.c
Normal file
@ -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);
|
36
sys/netpfil/ipfw/pmod/pmod.h
Normal file
36
sys/netpfil/ipfw/pmod/pmod.h
Normal file
@ -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_ */
|
||||
|
246
sys/netpfil/ipfw/pmod/tcpmod.c
Normal file
246
sys/netpfil/ipfw/pmod/tcpmod.c
Normal file
@ -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;
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user