linux 下 nf_conntrack_tuple 跟踪记录

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   0xe
static 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 跟踪记录_第1张图片

你可能感兴趣的:(linux 下 nf_conntrack_tuple 跟踪记录)