免费注册 查看新帖 |

Chinaunix

  平台 论坛 博客 文库
最近访问板块 发新帖
查看: 1366 | 回复: 0
打印 上一主题 下一主题

netlink+netfilter实例分析 [复制链接]

论坛徽章:
0
跳转到指定楼层
1 [收藏(0)] [报告]
发表于 2009-09-09 20:24 |只看该作者 |倒序浏览
再次见识了内核的伟大,大半年不碰,忘记的一干二净!!!写netfilter,netlink不得不提的就是九贱和duanjigang了...
   Linux 用户态与内核态的交互——netlink 篇
       http://bbs.chinaunix.net/viewthread.php?tid=822500
  netlink socket 编程之 why & how
          http://linux.chinaunix.net/bbs/viewthread.php?tid=1031932&extra=page%3D1%26amp%3Bfilter%3Ddigest
  有了上面两篇文章加kernel source基本上你可以干许多事了...
  环境:
       centos5.2 2.6.18
  作用:
       ./user -i 禁止ping
       ./user -d ipaddr 禁止指定ip的tcp连接
       iptables+netfilter这一套以前一直是限于理论层面,今天就自己实践了下.
  我这里只是写我写程序的过程中遇到的问题,一些概念上的东东,上面两位大师已经写得很好了,我就不班门弄斧了.

          struct sock* netlink_kernel_create(int unit, unsigned int groups,
                      void (*input)(struct sock *sk, int len),
                      struct module *module)
      
why&how那篇是:

        struct sock * netlink_kernel_create(int unit, void (*input)(struct sock *sk, int len));
      
取数据我这里传的是结构体

         nlh = (struct nlmsghdr*)skb->data;
         icmp_off = ((OWN *)NLMSG_DATA(nlh))->icmp_off;
         drop_ip = ((OWN *)NLMSG_DATA(nlh))->drop_ip;
     
netlink主要就是create和取数据那个地方,我这里是看kernel source追寻到了,不同的版本可能不一样.

        nfho.hook      = hook_func;
        nfho.hooknum   = NF_IP_LOCAL_IN;
        nfho.pf        = PF_INET;
        nfho.priority  = NF_IP_PRI_FIRST;
       nf_register_hook(&nfho);
     
想挂多个hook的话可以
    nf_register_hook(&nfho);
          nf_register_hook(&nfho1);   
  
也可以

          nf_register_hooks(opts, ARRAY_SIZE(opts));
      
取头,可以去ip.h tcp.h等去找

        skb_header_pointer
     
好了废话了这么多,上代码了
   内核态程序

      #include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include "hook.h"
static struct nf_hook_ops nfho;
struct sock *nl_sk = NULL;
EXPORT_SYMBOL_GPL(nl_sk);
static int icmp_off = 0;
static unsigned int drop_ip = 0;
void input (struct sock* sk, int len)
{
  struct sk_buff* skb = NULL;
  struct nlmsghdr* nlh = NULL;
  printk("net_link: data is ready to read.\n");
  while((skb = skb_dequeue(&sk->sk_receive_queue))!=NULL)
   {
    nlh = (struct nlmsghdr*)skb->data;
    icmp_off = ((OWN *)NLMSG_DATA(nlh))->icmp_off;
    drop_ip = ((OWN *)NLMSG_DATA(nlh))->drop_ip;
   }
  return;
}
static int test_netlink(void) {
  nl_sk = netlink_kernel_create(NETLINK_TEST, 0, input, THIS_MODULE);
  if (!nl_sk) {
    printk(KERN_ERR "net_link: Cannot create netlink socket.\n");
    return -EIO;
  }
  printk("net_link: create socket ok.\n");
  return 0;
}
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 *))
{
   struct sk_buff *sb = *skb;
   struct iphdr     *iph ;
   iph = ip_hdr(sb);
   switch(iph->protocol)
    {
     case IPPROTO_ICMP:{
         struct icmphdr _icmph;
         struct icmphdr* ich;
         ich = skb_header_pointer(sb, iph->ihl*4, sizeof(_icmph), &_icmph);
         printk("icmp type %u\n", ich->type);
         if(icmp_off == 1)
          {
            printk("now we drop icmp from %d.%d.%d.%d\n", NIPQUAD(iph->saddr));
            return NF_DROP;
          }
         break;
       }
     case IPPROTO_TCP:{
         struct tcphdr* th = NULL;
         struct tcphdr _tcph;
         th = skb_header_pointer(sb, iph->ihl*4, sizeof(_tcph), &_tcph);
         if(th == NULL)
          {
            printk("get tcp header error\n");
            return NF_DROP;
          }
         //unsigned int sip = ntohs(th->source);
         printk("saddr:%d.%d.%d.%d,sport:%u\n", NIPQUAD(iph->saddr),ntohs(th->source));
         printk("daddr:%d.%d.%d.%d,dport:%u\n", NIPQUAD(iph->daddr),ntohs(th->dest));
         if(iph->saddr ==drop_ip)
          {
            printk("now we drop tcp from %d.%d.%d.%d\n", NIPQUAD(iph->saddr));
             return NF_DROP;
          }
         break;
       }
     default:
         break;
    }
  return NF_ACCEPT;
}
static int __init hook_init()
{
       printk("insmod hook test!\n");
       test_netlink();
       nfho.hook      = hook_func;
       nfho.hooknum   = NF_IP_LOCAL_IN;
       nfho.pf        = PF_INET;
       nfho.priority  = NF_IP_PRI_FIRST;
   
       nf_register_hook(&nfho);
       return 0;
}
static void __exit hook_exit()
{
    printk("rmmod hook test!\n");
    nf_unregister_hook(&nfho);
    if (nl_sk != NULL){
      sock_release(nl_sk->sk_socket);
  }
}
module_init(hook_init);
module_exit(hook_exit);
   
用户态:

#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include "hook.h"
#define MAX_PAYLOAD 1024 /* maximum payload size*/
struct sockaddr_nl src_addr, dest_addr;
struct nlmsghdr *nlh = NULL;
struct iovec iov;
int sock_fd;
struct msghdr msg;
struct option longopts[] =
{
   {"icmp",no_argument, NULL, 'i'},
   {"help",no_argument, NULL, 'h'},
   {"drop",required_argument, NULL, 'd'},
   {0,0,0,0}
  };
void print_help(char* str)
{
fprintf(stderr,"%s --icmp(-i)\n",str);
fprintf(stderr,"%s --drop(-d)\n",str);
fprintf(stderr,"eg:\n%s -i -d 202.114.85.105\n",str);
}
void init_own(OWN** own)
{
*own = (OWN*)malloc(sizeof(OWN));
(*own)->icmp_off = 0;
(*own)->drop_ip = 0;
}        
int main(int argc, char* argv[])
{
   int c;
   OWN* own = NULL;
   init_own(&own);
   while((c=getopt_long(argc, argv, "hid:", longopts, NULL))!=-1)   
    {
      switch(c)
       {
         case 'i':
          {
            own->icmp_off = 1;
            break;
          }
         case 'd':
          {
            own->drop_ip = inet_addr(optarg);
            break;
          }
         case 'h':
           {
            print_help(argv[0]);
            return -1;
           }
        
         default:
          break;
       }
    }  
   sock_fd = socket(PF_NETLINK, SOCK_RAW, NETLINK_TEST);
   memset(&msg, 0, sizeof(msg));
   memset(&src_addr, 0, sizeof(src_addr));
   src_addr.nl_family = AF_NETLINK;
   src_addr.nl_pid = getpid(); /* self pid */
   src_addr.nl_groups = 0; /* not in mcast groups */
   bind(sock_fd, (struct sockaddr*)&src_addr, sizeof(src_addr));
   memset(&dest_addr, 0, sizeof(dest_addr));
   dest_addr.nl_family = AF_NETLINK;
   dest_addr.nl_pid = 0; /* For Linux Kernel */
   dest_addr.nl_groups = 0; /* unicast */
   nlh=(struct nlmsghdr *)malloc(NLMSG_SPACE(MAX_PAYLOAD));
   /* Fill the netlink message header */
   nlh->nlmsg_len = NLMSG_SPACE(MAX_PAYLOAD);
   nlh->nlmsg_pid = getpid(); /* self pid */
   nlh->nlmsg_flags = 0;
   /* Fill in the netlink message payload */
   printf("%d, %d\n", own->icmp_off, own->drop_ip);
   memcpy(NLMSG_DATA(nlh),own ,sizeof(OWN));
   iov.iov_base = (void *)nlh;
   iov.iov_len = nlh->nlmsg_len;
   msg.msg_name = (void *)&dest_addr;
   msg.msg_namelen = sizeof(dest_addr);
   msg.msg_iov = &iov;
   msg.msg_iovlen = 1;
   printf(" Sending message. ...\n");
   sendmsg(sock_fd, &msg, 0);
   close(sock_fd);
   free(own);
   return 0;
}
Makefile  头文件

文件:
netlink+netfilter.rar
大小:
2KB
下载:
下载
hook.h
#define NETLINK_TEST 21
typedef struct my
{
  int icmp_off;
  unsigned int drop_ip;
}OWN;
makefile:
  obj-m += hook.o
KDIR := /lib/modules/$(shell uname -r)/build
all:
        make -C $(KDIR) M=$(shell pwd) modules
        gcc -Wall -o user user.c
clean:
        make -C $(KDIR) M=$(shell pwd) clean
        rm -f *odule* user
usage:
         1.make
         2. insmod hook.ko (建议tail -f /var/log/messages查看是否success尤其是netlink create是否成功)
         3.默认你是可以ping, 和tcp得(我实验室只有两台机子A 202.114.85.105)
         4. ./user -i  -d 202.114.85.105 (A机不能ping和ftp B)
         5../user (取消限制了,可以ping和ftp B)
再次试验成功上传代码:


本文来自ChinaUnix博客,如果查看原文请点:http://blog.chinaunix.net/u2/76292/showart_2049327.html
您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

  

北京盛拓优讯信息技术有限公司. 版权所有 京ICP备16024965号-6 北京市公安局海淀分局网监中心备案编号:11010802020122 niuxiaotong@pcpop.com 17352615567
未成年举报专区
中国互联网协会会员  联系我们:huangweiwei@itpub.net
感谢所有关心和支持过ChinaUnix的朋友们 转载本站内容请注明原作者名及出处

清除 Cookies - ChinaUnix - Archiver - WAP - TOP