Linux下使用Netfilter强制清除IPv4 DF标志

clear ip df kernel module

此模块比较简单, 主要目的在使用GRE隧道时强制对数据报文长度>GRE隧道MTU的IPv4 DF标志的报文进行分片. Linux默认丢弃此类报文并根据PMTUD是否响应ICMP报文, 而不是直接进行分片!
加载此模块后会对所有数据ipv4报文强制清除DF标志.
:
未启用PMTUD功能;
Linux GRE 隧道默认MTU 1476, 默认对所有未设置DF标志报文进行分片后再ENCAP;

prepare

yum install gcc makc perl elfutils-libelf-devel kernel-devel kernel-headers

source

#ifdef    MODVERSIONS
#include  
#endif

#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include         /* for put_user */
#include         /* for put_user */


#include "dbg.h"

#define MTU_DST		1400

#define MKIPV4(a,b,c,d) \
	(u32)(((__u8)d & 0xFF) << 24 | ((__u8)c & 0xFF) << 16 | ((__u8)b & 0xFF) << 8 | (a & 0xFF))

#if LINUX_VERSION_CODE <= KERNEL_VERSION(4, 13, 0)
/*
 include/linux/netfilter.h
typedef unsigned int nf_hookfn(const struct nf_hook_ops *ops,
                   struct sk_buff *skb,
                   const struct net_device *in,
                   const struct net_device *out,
#ifndef __GENKSYMS__
                   const struct nf_hook_state *state
#else
                   int (*okfn)(struct sk_buff *)
#endif
                   );

*/
static unsigned int
nf_ip_input(const struct nf_hook_ops *ops,
	   struct sk_buff *skb,
	   const struct net_device *in,
	   const struct net_device *out,
#ifndef __GENKSYMS__
	   const struct nf_hook_state *state
#else
	   int (*okfn)(struct sk_buff *)
#endif
)
#else
/*
 typedef unsigned int nf_hookfn(void *priv,
                   struct sk_buff *skb,
                   const struct nf_hook_state *state);
*/

static unsigned int
nf_ip_input(void *priv,
          struct sk_buff *skb,
          const struct nf_hook_state *state)
#endif
{
	struct iphdr *iph = NULL;
    iph = ip_hdr(skb);
    if (iph->frag_off & __constant_htons(IP_DF)) {
        iph->frag_off &= ~(__constant_htons(IP_DF));
        iph->check = 0;
        iph->check = ip_fast_csum((unsigned char *)iph, iph->ihl);
    }
	return NF_ACCEPT;
}

static struct nf_hook_ops nf_hook_ops[] __read_mostly = {
    {
        .hook       = nf_ip_input,
#if LINUX_VERSION_CODE <= KERNEL_VERSION(3, 10, 0)
        .owner      = THIS_MODULE,
#endif
        .pf         = PF_INET,
        .hooknum    = NF_INET_PRE_ROUTING,
        .priority   = NF_IP_PRI_FIRST,
    },
};

int nf_ip_df_init( void )
{
	int err = 0;
	pr_notice( "nf_ip_df_init..\n" );
#if LINUX_VERSION_CODE >= KERNEL_VERSION(4,13,0) 
	err = nf_register_net_hook(&init_net, nf_hook_ops);
#else
	err = nf_register_hooks(nf_hook_ops, ARRAY_SIZE(nf_hook_ops));
#endif
    if (err < 0) {
        pr_notice("nf_ip_df_init: can't register hooks.\n");
    }
	pr_emerg( "INT_MIN = %d\n", INT_MIN );
	pr_info( "ip_mtu: register hooks success.\n" );
	return err;
}

void nf_ip_df_fini(void)
{
	pr_notice( "nf_ip_df_fini..\n" );
#if LINUX_VERSION_CODE >= KERNEL_VERSION(4,13,0) 
	nf_unregister_net_hook(&init_net, nf_hook_ops);
#else
	nf_unregister_hooks(nf_hook_ops, ARRAY_SIZE(nf_hook_ops));
#endif
}

module_init(nf_ip_df_init);
module_exit(nf_ip_df_fini);
MODULE_LICENSE( "GPL" );

Makefile

ARCH := x86
KVER := $(shell uname -r)
KSP ?= /lib/modules/$(KVER)/build

#EXTRA_CFLAGS +=-DTEST

obj-m += ip_df.o

all: clean
	make -C $(KSP) M=`pwd` modules

clean:
	make -C $(KSP) M=`pwd` clean
	rm -f Module.symvers
	rm -f modules.order

test:
	insmod ip_df.ko

你可能感兴趣的:(系统管理,内核技术)