netfilterフック2

netfilterフックルーチンその2
以下の4箇所のフックポイントでフックしパケットの内容をmessagesに出力する。
・PRE_ROUTING
・POST_ROUTING
・LOCAL_IN
・LOCAL_OUT
あくまで解析/デバッグ用。ログ吐きすぎ。

ビルドの方法などは以下参照。
http://d.hatena.ne.jp/kwata8459/20121115/1352986791

/*
 * exp_netfilter2.c
 */

#include <linux/types.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/skbuff.h>
#include <linux/netfilter.h>
#include <linux/netfilter_ipv4.h>
#include <linux/ip.h>
#include <linux/udp.h>
#include <linux/tcp.h>

#define DRIVER_AUTHOR "NABETI"
#define DRIVER_DESC "netfilter experiment"

void yydump(char *p, int length);
void dump_sk_buff(struct sk_buff *skb);
void dump_ip(struct iphdr* iph);
void dump_tcp(struct tcphdr* tcph);
void dump_udp(struct udphdr* udph);

static struct nf_hook_ops nfho_pre_routing;
static struct nf_hook_ops nfho_post_routing;
static struct nf_hook_ops nfho_local_in;
static struct nf_hook_ops nfho_local_out;


//----------------------------------
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 *))
{
const char *str_hooknum[NF_INET_NUMHOOKS] = {
  "NF_INET_PRE_ROUTING",
  "NF_INET_LOCAL_IN",
  "NF_INET_FORWARD",
  "NF_INET_LOCAL_OUT",
  "NF_INET_POST_ROUTING"
  };

  printk(KERN_INFO "[NFE] --- hook_func ------------------\n");

  if((0 <= hooknum) && (hooknum < NF_INET_NUMHOOKS)){
    printk(KERN_INFO "hooknum    : %s\n", str_hooknum[hooknum]);
  }
  else{
    printk(KERN_INFO "hooknum    : %s\n", "Unknown Hooknum");
  }

  printk(KERN_INFO "in         : %s\n", in->name);
  printk(KERN_INFO "out        : %s\n", out->name);

  dump_sk_buff(skb);

  printk(KERN_INFO "\n");

  return NF_ACCEPT;
}


//----------------------------------
static int __init nfe_init(void)
{


  printk(KERN_INFO "[NFE] nfe_init\n");

  nfho_pre_routing.hook     = hook_func;
  nfho_pre_routing.hooknum  = NF_INET_PRE_ROUTING;
  nfho_pre_routing.pf       = PF_INET;
  nfho_pre_routing.priority = NF_IP_PRI_FIRST;
  nf_register_hook(&nfho_pre_routing);

  nfho_post_routing.hook     = hook_func;
  nfho_post_routing.hooknum  = NF_INET_POST_ROUTING;
  nfho_post_routing.pf       = PF_INET;
  nfho_post_routing.priority = NF_IP_PRI_FIRST;
  nf_register_hook(&nfho_post_routing);

  nfho_local_in.hook     = hook_func;
  nfho_local_in.hooknum  = NF_INET_LOCAL_IN;
  nfho_local_in.pf       = PF_INET;
  nfho_local_in.priority = NF_IP_PRI_FIRST;
  nf_register_hook(&nfho_local_in);

  nfho_local_out.hook     = hook_func;
  nfho_local_out.hooknum  = NF_INET_LOCAL_OUT;
  nfho_local_out.pf       = PF_INET;
  nfho_local_out.priority = NF_IP_PRI_FIRST;
  nf_register_hook(&nfho_local_out);

  return 0;
}




//----------------------------------
static void __exit nfe_exit(void)
{
  printk(KERN_INFO "[NFE] nfe_exit\n");

  nf_unregister_hook(&nfho_pre_routing);
  nf_unregister_hook(&nfho_post_routing);
  nf_unregister_hook(&nfho_local_in);
  nf_unregister_hook(&nfho_local_out);
}


//----------------------------------
// Dump sk_buff
//----------------------------------
void dump_sk_buff(struct sk_buff *skb)
{
  printk(KERN_INFO "next       : %p\n", skb->next);
  printk(KERN_INFO "prev       : %p\n", skb->prev);
  printk(KERN_INFO "tstamp.tv64: %llu\n", skb->tstamp.tv64);
  printk(KERN_INFO "dev.name   : %s\n", skb->dev->name);
  printk(KERN_INFO "len        : %d\n", skb->len);
  printk(KERN_INFO "data_len   : %d\n", skb->data_len);
  printk(KERN_INFO "mac_len    : %d\n", skb->mac_len);
  printk(KERN_INFO "hdr_len    : %d\n", skb->hdr_len);
  printk(KERN_INFO "priority   : %d\n", skb->priority);
  printk(KERN_INFO "protocol   : %d\n", skb->protocol);

  printk(KERN_INFO "head       : %p\n", skb->head);
  printk(KERN_INFO "data       : %p\n", skb->data);
  printk(KERN_INFO "tail       : %p\n", skb->tail);
  printk(KERN_INFO "end        : %p\n", skb->end);

  printk(KERN_INFO "skb_mac_header()       : %p\n", skb_mac_header(skb));
  printk(KERN_INFO "skb_network_header()   : %p\n", skb_network_header(skb));
  printk(KERN_INFO "skb_transport_header() : %p\n", skb_transport_header(skb));

  dump_ip((struct iphdr*)skb_network_header(skb));

  yydump(skb->head, skb->end - skb->head);
}


//----------------------------------
// Dump IP packet
//----------------------------------
void dump_ip(struct iphdr* iph)
{
  char *ps = NULL;

  printk(KERN_INFO "iphdr.version : %d\n", iph->version);
  printk(KERN_INFO "iphdr.ihl     : %d\n", iph->ihl);
  printk(KERN_INFO "iphdr.tos     : %02x\n", iph->tos);
  printk(KERN_INFO "iphdr.tot_len : %d\n", iph->tot_len);
  printk(KERN_INFO "iphdr.id      : %04x\n", iph->id);

  switch(iph->protocol){
  case 1: ps = "ICMP"; break;
  case 4: ps = "IPv4"; break;
  case 6: ps = "TCP"; break;
  case 17: ps = "UDP"; break;
  default: sprintf(ps, "<%d>", iph->protocol); break;
  }

  printk(KERN_INFO "iphdr.protocol: %s\n", ps);

  printk(KERN_INFO "iphdr.saddr   : %08x\n", iph->saddr);
  printk(KERN_INFO "iphdr.daddr   : %08x\n", iph->daddr);

  switch(iph->protocol){
  case 6: dump_tcp((struct tcphdr*)((char *)iph + sizeof(struct iphdr))); break;
  case 17: dump_udp((struct udphdr*)((char *)iph + sizeof(struct iphdr))); break;
  }

}


//----------------------------------
// Dump TCP packet
//----------------------------------
void dump_tcp(struct tcphdr* tcph)
{
  char buf[128];

  sprintf(buf, "Flags -- ");

  printk(KERN_INFO "tcphdr.source : %u\n", tcph->source);
  printk(KERN_INFO "tcphdr.dest   : %u\n", tcph->dest);
  printk(KERN_INFO "tcphdr.seq    : %u\n", tcph->seq);
  printk(KERN_INFO "tcphdr.ack_seq: %u\n", tcph->ack_seq);
  printk(KERN_INFO "tcphdr.window : %u\n", tcph->window);

  if(tcph->fin == 1) strcat(buf, "[FIN]");
  if(tcph->syn == 1) strcat(buf, "[SYN]");
  if(tcph->rst == 1) strcat(buf, "[RST]");
  if(tcph->psh == 1) strcat(buf, "[PSH]");
  if(tcph->ack == 1) strcat(buf, "[ACK]");
  if(tcph->urg == 1) strcat(buf, "[URG]");
  if(tcph->ece == 1) strcat(buf, "[ECE]");
  if(tcph->cwr == 1) strcat(buf, "[CWR]");
  strcat(buf, "\n");
  printk(KERN_INFO "%s",buf);
}

//----------------------------------
// Dump UDP packet
//----------------------------------
void dump_udp(struct udphdr* udph)
{
  printk(KERN_INFO "udphdr.source : %u\n", udph->source);
  printk(KERN_INFO "udphdr.dest   : %u\n", udph->dest);
  printk(KERN_INFO "udphdr.len    : %u\n", udph->len);
}


//----------------------------------
// hex dump to /var/log/messages
//----------------------------------
void yydump(char *p, int length)
{
int address = (int)p;
char data[17];
int i;
char buf[128];
char tmp[32];

 data[16] = 0; /* for string terminator */

 for(;length>0;){
   sprintf(buf, "%08X :", address);

   for(i=0;i<16;i++){
     data[i] = *p++;	
     length--;

     /* data is out of range */
     if(length < 0){
       sprintf(tmp, "  ");
       strcat(buf, tmp);
       data[i] = ' ';
     }
     else{
       sprintf(tmp, "%02X", (unsigned char)data[i]);
       strcat(buf, tmp);
       /* eliminate undisplayable character */
       if((data[i] < 0x20) || (0x7E < data[i])){
	 data[i] = '.';
       }
     }
   }
   sprintf(tmp, " :  %s\n", data);
   strcat(buf, tmp);
   address += 16;

   printk(KERN_INFO "%s",buf);
 }
}


module_init(nfe_init);
module_exit(nfe_exit);

MODULE_LICENSE("GPLv3");
MODULE_AUTHOR(DRIVER_AUTHOR);
MODULE_DESCRIPTION(DRIVER_DESC);