linux 下 nf_conntrack_tuple 跟踪记录

时间:2022-06-20 04:43:03
struct nf_conn {
        /* Usage count in here is 1 for hash table/destruct timer, 1 per skb, plus 1 for any connection(s) we are `master' for */
        struct  nf_conntrack  ct_general;                /* 连接跟踪的引用计数 */
        spinlock_t  lock;

        /* Connection tracking(链接跟踪)用来跟踪、记录每个链接的信息(目前仅支持IP协议的连接跟踪)。
            每个链接由“tuple”来唯一标识,这里的“tuple”对不同的协议会有不同的含义,例如对tcp,udp
                 来说就是五元组: (源IP,源端口,目的IP, 目的端口,协议号),对ICMP协议来说是: (源IP, 目
            的IP, id, type, code), 其中id,type与code都是icmp协议的信息。链接跟踪是防火墙实现状态检
            测的基础,很多功能都需要借助链接跟踪才能实现,例如NAT、快速转发、等等。*/

        struct  nf_conntrack_tuple_hash  tuplehash[IP_CT_DIR_MAX];
        
        unsigned long  status;                             /* 可以设置由enum ip_conntrack_status中描述的状态 */

        struct  nf_conn  *master;                        /* 如果该连接是某个连接的子连接,则master指向它的主连接 */
        /* Timer function; drops refcnt when it goes off. */
        struct  timer_list  timeout;

        union nf_conntrack_proto proto;                /* 用于保存不同协议的私有数据 */
        /* Extensions */
        struct nf_ct_ext *ext;                        /* 用于扩展结构 */
};
这个结构非常简单,其中最主要的就是tuplehash(跟踪连接双方向数据)和status(记录连接状态),这也连接跟踪最主要的功能。
#include <linux/kernel.h>#include <linux/module.h>#include <linux/autoconf.h>#include <linux/kthread.h>#include <linux/udp.h>#include <linux/rculist_nulls.h>#include <net/netfilter/nf_conntrack_acct.h>#include <linux/init.h>#include <linux/module.h>#include <linux/kernel.h>#include <linux/version.h>#include <linux/skbuff.h>#include <linux/in.h>#include <linux/ip.h>#include <linux/udp.h>#include <linux/tcp.h>#include <linux/icmp.h>#include <linux/if_arp.h>#include <linux/if_ether.h>#include <linux/if_packet.h>#include <linux/types.h>#include <linux/kmod.h>#include <linux/proc_fs.h>#include <linux/bitops.h>#include <linux/socket.h>#include <linux/netdevice.h>#include <linux/netfilter.h>#include <linux/netfilter_ipv4.h>#include <linux/netfilter_arp.h>#include <linux/netfilter_ipv4/ip_tables.h>#include <linux/netfilter_ipv4/ipt_multiport.h>#include <linux/netfilter_ipv4/ipt_iprange.h>#include <net/checksum.h>#include <net/route.h>#include <linux/netfilter/nf_conntrack_common.h>typedef   u8              __a_uint8_t;    typedef   s8              __a_int8_t;     typedef   u16             __a_uint16_t;   typedef   s16             __a_int16_t;    typedef   u32             __a_uint32_t;   typedef   s32             __a_int32_t;    typedef   u64             __a_uint64_t;   typedef   s64             __a_int64_t;     typedef __a_uint8_t    a_uint8_t;typedef __a_int8_t     a_int8_t;typedef __a_uint16_t   a_uint16_t;typedef __a_int16_t    a_int16_t;typedef __a_uint32_t   a_uint32_t;typedef __a_int32_t    a_int32_t;typedef __a_uint64_t   a_uint64_t;typedef __a_int64_t    a_int64_t;typedef a_uint32_t fal_ip4_addr_t;#define dprintf printk#define NAPT_AGE   0xestatic struct task_struct *test_TaskStruct;typedef struct{    a_uint32_t entry_id;    a_uint32_t flags;    a_uint32_t status;    a_uint32_t src_addr;    a_uint32_t dst_addr;    a_uint16_t src_port;    a_uint16_t dst_port;    a_uint32_t trans_addr;    a_uint16_t trans_port;} napt_entry_t;/*void cmd_print(char *fmt, ...){    va_list args;    va_start(args, fmt);   // if(out_fd)   //     vfprintf(out_fd, fmt, args);   // else        vfprintf(stdout, fmt, args);    va_end(args);}*/void cmd_data_print_ip4addr(char * param_name, a_uint32_t * buf, a_uint32_t size){    a_uint32_t i;    fal_ip4_addr_t ip4;    ip4 = *((fal_ip4_addr_t *) buf);    printk("%s", param_name);    for (i = 0; i < 3; i++) {        printk("%d.", (ip4 >> (24 - i * 8)) & 0xff);    }    printk("%d", (ip4 & 0xff));}void napt_entry_show(uint32_t ct_addr){  napt_entry_t  realnapt = {0};  napt_entry_t *entry=&realnapt;    if(!ct_addr)    {        return;    }    struct nf_conn *ct = (struct nf_conn *)ct_addr;    struct nf_conntrack_tuple *org_tuple, *rep_tuple;    if ((ct->status & IPS_NAT_MASK) == IPS_SRC_NAT)     //snat    {        org_tuple = &(ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple);        rep_tuple = &(ct->tuplehash[IP_CT_DIR_REPLY].tuple);    }    else                                                //dnat    {        org_tuple = &(ct->tuplehash[IP_CT_DIR_REPLY].tuple);        rep_tuple = &(ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple);    }    uint8_t protonum = org_tuple->dst.protonum;    entry->src_addr = org_tuple->src.u3.ip;    entry->src_port = org_tuple->src.u.all;    entry->dst_addr = org_tuple->dst.u3.ip;    entry->dst_port = org_tuple->dst.u.all;    entry->trans_addr = rep_tuple->dst.u3.ip;    entry->trans_port = rep_tuple->dst.u.all;    entry->status = NAPT_AGE;cmd_data_print_ip4addr("\n[src_addr]:",(a_uint32_t *) & (entry->src_addr),sizeof (fal_ip4_addr_t));cmd_data_print_ip4addr("\n[dst_addr]:",(a_uint32_t *) & (entry->dst_addr),sizeof (fal_ip4_addr_t));cmd_data_print_ip4addr("\n[trans_addr]:",(a_uint32_t *) & (entry->trans_addr),sizeof (fal_ip4_addr_t)); dprintf("\n[src_port]:0x%x  [dst_port]:0x%x  [trans_port]:0x%x  ", entry->src_port, entry->dst_port, entry->trans_port);if(org_tuple->src.l3num == AF_INET)    {        if(protonum == IPPROTO_TCP)        {            printk("[protcal]: TCP \n");        }        else if(protonum == IPPROTO_UDP)        {            printk("[protcal]: UDP \n");        }    }}uint32_t napt_entry_list(uint32_t *hash, uint32_t *iterate){    struct net *net = &init_net;    struct nf_conntrack_tuple_hash *h = NULL;    struct nf_conn *ct = NULL;    struct hlist_nulls_node *pos = (struct hlist_nulls_node *) (*iterate);    while(*hash < nf_conntrack_htable_size)    {        if(pos == 0)        {            /*get head for list*/            pos = rcu_dereference((&net->ct.hash[*hash])->first);        }        hlist_nulls_for_each_entry_from(h, pos, hnnode)        {            (*iterate) = (uint32_t)(pos->next);            ct = nf_ct_tuplehash_to_ctrack(h);            //return (uint32_t) ct;            napt_entry_show(ct);            msleep(100);        }        ++(*hash);        pos = 0;    }}void threadTask(){  uint32_t hash = 0, iterate = 0;while(1){ hash = 0;  if(kthread_should_stop())  {printk("threadTask: kthread_should_stop\n");break;  }  napt_entry_list(&hash,&iterate);{//schedule_timeout(80000*HZ);//让出CPU,使其他线程可以运行。//或者使用msleep(2000);//的底层实现就是schedule_timeout().}}}static int __init init_nat_test_module(void){ test_TaskStruct=kthread_create(threadTask,NULL,"KernelThead"); if(IS_ERR(test_TaskStruct)) { printk("kthread_create error\n"); } else {  wake_up_process(test_TaskStruct); } return 0;}static void __exit cleanup_anat_test_module(void){kthread_stop(test_TaskStruct);}module_init(init_nat_test_module);module_exit(cleanup_anat_test_module);MODULE_LICENSE("GPL");MODULE_AUTHOR("suiyuan from comba"); MODULE_DESCRIPTION("Led driver for nat test");
linux 下 nf_conntrack_tuple 跟踪记录