Linux中netfilter模块编程实践

简介:


 上篇我们看了netfilter的实现机制,这篇来实现下netfilter模块实操一把。

为了注册一个钩子,需要填充nf_hook_ops结构体,包括优先级,钩子地点和钩子函数。然后调用nf_register_hook()函数。

1.   数据结构

 

 

struct nf_hook_ops {

        /* User fills in from here down. */

        nf_hookfn               *hook;

        struct net_device       *dev;

        void                    *priv;                   

        u_int8_t                pf;

        unsigned int            hooknum;

        /* Hooks are ordered in ascending priority. */

        int                     priority;                

};

定义在include/linux/netfilter.h

 

2.   模块代码一丢弃所有UDP输入包

本DEMO实现将所有输入的UDP包丢弃。钩子函数为hook_func,通过ip头的协议来指定,协议17就是表示此包是UDP包,如果将17改成1就会丢弃icmp包了。

.hooknum = 1表示是入口点过滤 NF_IP_LOCAL_IN ,如果改成3就是NF_IP_LOCAL_OUT了,这个定在内核文件include/uapi/linux/netfilter_ipv4.h,如下:

/* IP Hooks */           

/* After promisc drops, checksum checks. */

#define NF_IP_PRE_ROUTING       0

/* If the packet is destined for this box. */

#define NF_IP_LOCAL_IN          1

/* If the packet is destined for another interface. */

#define NF_IP_FORWARD           2

/* Packets coming from a local process. */

#define NF_IP_LOCAL_OUT         3

/* Packets about to hit the wire. */

#define NF_IP_POST_ROUTING      4

#define NF_IP_NUMHOOKS          5

编写源码netmod.c如下:

#include <linux/module.h>

#include <linux/kernel.h>

#include <linux/netfilter_ipv4.h>

#include <linux/skbuff.h>

#include <linux/udp.h>

#include <linux/ip.h>

 

/* This function to be called by hook. */

static unsigned int

hook_func (unsigned int hooknum,

         struct sk_buff *skb,

         const struct net_device *in,

         const struct net_device *out, int (*okfn) (struct sk_buff *))

{

  struct udphdr *udp_header;

  struct iphdr *ip_header = (struct iphdr *) skb_network_header (skb);

 

  if (ip_header->protocol == 17)

    {

      udp_header = (struct udphdr *) skb_transport_header (skb);

      printk (KERN_INFO "Drop udp packet.\n");

 

      return NF_DROP;

    }

 

  return NF_ACCEPT;

}

 

static struct nf_hook_ops nfho = {

  .hook = hook_func,

  .hooknum = 1,             /* NF_IP_LOCAL_IN */

  .pf = PF_INET,

  .priority = NF_IP_PRI_FIRST,

};

 

static int __init

init_nf (void)

{

  printk (KERN_INFO "Register netfilter module.\n");

  nf_register_hook (&nfho);

 

  return 0;

}

 

static void __exit

exit_nf (void)

{

  printk (KERN_INFO "Unregister netfilter module.\n");

  nf_unregister_hook (&nfho);

}

 

module_init (init_nf);

module_exit (exit_nf);

MODULE_LICENSE ("GPL");

编写Makefile如下:

obj-m := netmod.o

modules-objs:= netmod.o

 

KDIR := /lib/modules/`uname -r`/build

PWD := $(shell pwd)

 

default:

              make -C $(KDIR) M=$(PWD) modules

 

clean:

            rm -rf *.o .* .cmd *.ko *.mod.c .tmp_versions

       编译后即可使用insmod将模块插入到系统中。

       测试完毕后,记得卸载模块,不然后来的同学可能需要去定位网络问题了。

3.   模块代码二丢弃指定IP的TCP输入包

关于模块参数的导入,使用module_param。

module_param的定义可以在include/linux/moduleparam.h文件里面查看到,它的原型为:

module_param(name, type, perm);

module_param_array(name, type, nump, perm);

       其中module_param是用来传递变量参数的,module_param_array是用来传递数组参数的。

name是在模块中定义的变量名称,type是变量的类型,perm是权限掩码。

权限在include/linux/stat.h中有定义

#define S_IRWXU 00700

#define S_IRUSR 00400

#define S_IWUSR 00200

#define S_IXUSR 00100

#define S_IRWXG 00070

#define S_IRGRP 00040

#define S_IWGRP 00020

#define S_IXGRP 00010

#define S_IRWXO 00007

#define S_IROTH 00004

#define S_IWOTH 00002

#define S_IXOTH 00001

另外nump是传入数组的数目,是一个int指针。参数可以是以下类型:

byte、short、ushort、int、uint、long、ulong、char(字符指针)、bool、invbool(布尔的反,invbool 类型颠倒了值, 所以真值变成 false,)

可以在导入的时候修改模块参数值:

insmod netmod.ko name=hello

       源码如下:

#include <linux/module.h>

#include <linux/kernel.h>

#include <linux/netfilter_ipv4.h>

#include <linux/skbuff.h>

#include <linux/udp.h>

#include <linux/ip.h>

#include <net/ip.h>

#include <linux/inet.h> /*in_aton()*/

 

/* This function to be called by hook. */

MODULE_LICENSE("Dual BSD/GPL"); 

 

static char* n_ip = "192.168.1.63"; //ip=192.168.1.61

module_param(n_ip, charp, S_IRUGO);

 

static unsigned int

hook_func (unsigned int hooknum,

         struct sk_buff *skb,

         const struct net_device *in,

         const struct net_device *out, int (*okfn) (struct sk_buff *))

{

  struct tcphdr *tcph = tcp_hdr (skb);

  struct iphdr *iph = ip_hdr (skb);

  struct tcphdr *modtcph;

  unsigned char *tail;

  unsigned char *user_data;

  unsigned char *it;

  struct sk_buff *modskb;

  char *tempPay;

  char *payload;       //Char array to store original payload before modifications

  int lenOrig;

  int lenNew;

  u16 sport, dport;

  u32 saddr, daddr;

  int i1,i2,i3,i4;

 

  //tempPay = kmalloc (1500, GFP_KERNEL);

  //payload = kmalloc (1500, GFP_KERNEL);

  if (!skb)

    return NF_ACCEPT;

  saddr = ntohl (iph->saddr);

  daddr = ntohl (iph->daddr);

  sport = ntohs (tcph->source);

  dport = ntohs (tcph->dest);

  tail = skb_tail_pointer (skb);

 

  user_data = (unsigned char *) ((unsigned char *) tcph + (tcph->doff * 4));

//3232235837 = 192.168.1.61

  if (iph->saddr == in_aton(n_ip) ) //判断ip地址

    {                 

      i1 = saddr>>24;

      i2 = (saddr>>16) & 0x000000ff;

      i3 = (saddr>>8) & 0x000000ff;

      i4 = saddr & 0x000000ff;

 

      printk ("saddr == %d.%d.%d.%d\n ",i1,i2,i3,i4);

      //printk ("saddr == %s\n",iph->saddr);

     

      ip_send_check (iph);

      for (it=user_data;it!=tail;it++)

      {

        *it++;

          printk("%x",*it);

      }

      printk ("\n");

    }

  return NF_ACCEPT;

}

 

static struct nf_hook_ops nfho = {

  .hook = hook_func,

  .hooknum = 3,             /* NF_IP_LOCAL_IN */

  .pf = PF_INET,

  .priority = NF_IP_PRI_FIRST,

};

 

static int __init

init_nf (void)

{

  printk (KERN_INFO "Register netfilter module.\n");

  nf_register_hook (&nfho);

  printk (" n_ip:%s\n",n_ip);

 

  return 0;

}

 

static void __exit

exit_nf (void)

{

  printk (KERN_INFO "Unregister netfilter module.\n");

  nf_unregister_hook (&nfho);

}

 

module_init (init_nf);

module_exit (exit_nf);

MODULE_LICENSE ("GPL");

4.   参考

Writing a Module For netfilter

 

 

 

目录
相关文章
|
4月前
|
Shell Linux
Linux shell编程学习笔记30:打造彩色的选项菜单
Linux shell编程学习笔记30:打造彩色的选项菜单
|
27天前
|
存储 监控 Linux
嵌入式Linux系统编程 — 5.3 times、clock函数获取进程时间
在嵌入式Linux系统编程中,`times`和 `clock`函数是获取进程时间的两个重要工具。`times`函数提供了更详细的进程和子进程时间信息,而 `clock`函数则提供了更简单的处理器时间获取方法。根据具体需求选择合适的函数,可以更有效地进行性能分析和资源管理。通过本文的介绍,希望能帮助您更好地理解和使用这两个函数,提高嵌入式系统编程的效率和效果。
94 13
|
1月前
|
监控 算法 Linux
Linux内核锁机制深度剖析与实践优化####
本文作为一篇技术性文章,深入探讨了Linux操作系统内核中锁机制的工作原理、类型及其在并发控制中的应用,旨在为开发者提供关于如何有效利用这些工具来提升系统性能和稳定性的见解。不同于常规摘要的概述性质,本文将直接通过具体案例分析,展示在不同场景下选择合适的锁策略对于解决竞争条件、死锁问题的重要性,以及如何根据实际需求调整锁的粒度以达到最佳效果,为读者呈现一份实用性强的实践指南。 ####
|
1月前
|
缓存 监控 网络协议
Linux操作系统的内核优化与实践####
本文旨在探讨Linux操作系统内核的优化策略与实际应用案例,深入分析内核参数调优、编译选项配置及实时性能监控的方法。通过具体实例讲解如何根据不同应用场景调整内核设置,以提升系统性能和稳定性,为系统管理员和技术爱好者提供实用的优化指南。 ####
|
2月前
|
关系型数据库 MySQL Linux
Linux环境下MySQL数据库自动定时备份实践
数据库备份是确保数据安全的重要措施。在Linux环境下,实现MySQL数据库的自动定时备份可以通过多种方式完成。本文将介绍如何使用`cron`定时任务和`mysqldump`工具来实现MySQL数据库的每日自动备份。
174 3
|
2月前
|
运维 监控 Shell
深入理解Linux系统下的Shell脚本编程
【10月更文挑战第24天】本文将深入浅出地介绍Linux系统中Shell脚本的基础知识和实用技巧,帮助读者从零开始学习编写Shell脚本。通过本文的学习,你将能够掌握Shell脚本的基本语法、变量使用、流程控制以及函数定义等核心概念,并学会如何将这些知识应用于实际问题解决中。文章还将展示几个实用的Shell脚本例子,以加深对知识点的理解和应用。无论你是运维人员还是软件开发者,这篇文章都将为你提供强大的Linux自动化工具。
|
3月前
|
监控 Linux 云计算
Linux操作系统在云计算环境中的实践与优化###
【10月更文挑战第16天】 本文探讨了Linux操作系统在云计算环境中的应用实践,重点分析了其在稳定性、安全性和高效性方面的优势。通过具体案例,阐述了Linux如何支持虚拟化技术、实现资源高效分配以及与其他开源技术的无缝集成。文章还提供了针对Linux系统在云计算中的优化建议,包括内核参数调整、文件系统选择和性能监控工具的应用,旨在帮助读者更好地理解和应用Linux于云计算场景。 ###
72 3
|
3月前
|
Ubuntu Linux
Linux实践|设置静态 IP 地址
Linux实践|设置静态 IP 地址
82 0
Linux实践|设置静态 IP 地址
|
4月前
|
Shell Linux
Linux shell编程学习笔记82:w命令——一览无余
Linux shell编程学习笔记82:w命令——一览无余
|
4月前
|
Unix Linux 网络安全
python中连接linux好用的模块paramiko(附带案例)
该文章详细介绍了如何使用Python的Paramiko模块来连接Linux服务器,包括安装配置及通过密码或密钥进行身份验证的示例。
186 1