Chinaunix首页 | 论坛 | 博客
  • 博客访问: 3934711
  • 博文数量: 93
  • 博客积分: 3189
  • 博客等级: 中校
  • 技术积分: 4229
  • 用 户 组: 普通用户
  • 注册时间: 2009-02-02 13:29
个人简介

出没于杭州和青岛的程序猿一枚,对内核略懂一二

文章分类

全部博文(93)

文章存档

2016年(2)

2015年(3)

2014年(11)

2013年(29)

2012年(16)

2011年(5)

2010年(5)

2009年(22)

分类: LINUX

2013-07-02 12:45:18

声明:欢迎转载和引用,转载请注明出处。引用代码请保证代码完整性。

昨天CU论坛有人问到如何在内核模块发送数据包,于是找到了之前写的代码,跟大家分享一下。
该代码SLES 11 sp2内核3.0.13上编译运行通过。

点击(此处)折叠或打开

  1. /*
  2.  * Kernel Send Udp packet Module
  3.  *
  4.  * This program is free software; you can redistribute it and/or modify
  5.  * it under the terms of the GNU General Public License as published by
  6.  * the Free Software Foundation; either version 2 of the License, or
  7.  * (at your option) any later version.
  8.  *
  9.  * This program is distributed in the hope that it will be useful,
  10.  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  11.  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  12.  * GNU General Public License for more details.
  13.  *
  14.  * You should have received a copy of the GNU General Public License
  15.  * along with this program; if not, write to the Free Software
  16.  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
  17.  *
  18.  * Copyright(C) Tony <tingw.liu@gmail.com> 2007-2013
  19.  *
  20.  */


  21. #include <linux/module.h>
  22. #include <linux/moduleparam.h>
  23. #include <linux/netfilter.h>
  24. #include <linux/ip.h>
  25. #include <net/tcp.h>
  26. #include <net/udp.h>
  27. #include <net/icmp.h>
  28. #include <linux/skbuff.h>
  29. #include <net/sock.h>
  30. #include <linux/net.h>
  31. #include <linux/inetdevice.h>
  32. #include <linux/in.h>
  33. #include <linux/kernel.h>
  34. #include <linux/types.h>
  35. #include <asm/unaligned.h>
  36. #include <linux/kthread.h>

  37. MODULE_LICENSE("GPL");
  38. MODULE_AUTHOR("Tony ");
  39. char *ifname = "eth0";
  40. module_param(ifname, charp, 0644);
  41. MODULE_PARM_DESC(ifname, "Send packets from which net device");

  42. char *buffer = "Tony test from kernel!\n";
  43. module_param(buffer, charp, 0644);
  44. MODULE_PARM_DESC(buffer, "Packet content");

  45. __u32 dstip = 0xc0a80056;
  46. module_param(dstip, uint, 0644);

  47. __s16 dstport = 8000;
  48. module_param(dstport, short, 0644);

  49. long timeout = 1;
  50. module_param(timeout, long, 0644);
  51. MODULE_PARM_DESC(timeout, "Interval between send packets, default 1(unit second)");


  52. static struct task_struct *kthreadtask = NULL;

  53. static int bind_to_device(struct socket *sock, char *ifname)
  54. {
  55.     struct net *net;
  56.     struct net_device *dev;
  57.     __be32 addr;
  58.     struct sockaddr_in sin;
  59.     int err;
  60.     net = sock_net(sock->sk);
  61.     dev = __dev_get_by_name(net, ifname);

  62.     if (!dev) {
  63.         printk(KERN_ALERT "No such device named %s\n", ifname);
  64.         return -ENODEV;    
  65.     }
  66.     addr = inet_select_addr(dev, 0, RT_SCOPE_UNIVERSE);
  67.     sin.sin_family = AF_INET;
  68.     sin.sin_addr.s_addr = addr;
  69.     sin.sin_port = 0;
  70.     err = sock->ops->bind(sock, (struct sockaddr*)&sin, sizeof(sin));
  71.     if (err < 0) {
  72.         printk(KERN_ALERT "sock bind err, err=%d\n", err);
  73.         return err;
  74.     }
  75.     return 0;
  76. }

  77. static int connect_to_addr(struct socket *sock)
  78. {
  79.     struct sockaddr_in daddr;
  80.     int err;
  81.     daddr.sin_family = AF_INET;
  82.     daddr.sin_addr.s_addr = cpu_to_be32(dstip);
  83.     daddr.sin_port = cpu_to_be16(dstport);
  84.     err = sock->ops->connect(sock, (struct sockaddr*)&daddr,
  85.             sizeof(struct sockaddr), 0);
  86.     if (err < 0) {
  87.         printk(KERN_ALERT "sock connect err, err=%d\n", err);
  88.         return err;
  89.     }
  90.     return 0;
  91. }

  92. struct threadinfo{
  93.     struct socket *sock;
  94.     char *buffer;
  95. };

  96. static int sendthread(void *data)
  97. {
  98.     struct kvec iov;
  99.     struct threadinfo *tinfo = data;
  100.     struct msghdr msg = {.msg_flags = MSG_DONTWAIT|MSG_NOSIGNAL};
  101.     int len;
  102.     while (!kthread_should_stop()) {
  103.         iov.iov_base = (void *)tinfo->buffer;
  104.         iov.iov_len = strlen(tinfo->buffer);
  105.         len = kernel_sendmsg(tinfo->sock, &msg, &iov, 1, strlen(tinfo->buffer));
  106.         if (len != strlen(buffer)) {
  107.             printk(KERN_ALERT "kernel_sendmsg err, len=%d, buffer=%d\n",
  108.                     len, (int)strlen(buffer));
  109.             if (len == -ECONNREFUSED) {
  110.                 printk(KERN_ALERT "Receive Port Unreachable packet!\n");
  111.             }
  112.             break;
  113.         }
  114.         schedule_timeout_interruptible(timeout * HZ);
  115.     }
  116.     kthreadtask = NULL;
  117.     sk_release_kernel(tinfo->sock->sk);
  118.     kfree(tinfo);

  119.     return 0;
  120. }

  121. static int __init udp_send_init(void)
  122. {
  123.     int err = 0;
  124.     struct socket *sock;
  125.     struct threadinfo *tinfo;

  126.     err = sock_create_kern(PF_INET, SOCK_DGRAM, IPPROTO_UDP, &sock);
  127.     if (err < 0) {
  128.         printk(KERN_ALERT "UDP create sock err, err=%d\n", err);
  129.         goto create_error;
  130.     }
  131.     sock->sk->sk_reuse = 1;


  132.     err = bind_to_device(sock, ifname);
  133.     if (err < 0) {
  134.         printk(KERN_ALERT "Bind to %s err, err=%d\n", ifname, err);
  135.         goto bind_error;
  136.     }    
  137.     err = connect_to_addr(sock);
  138.     if (err < 0) {
  139.         printk(KERN_ALERT "sock connect err, err=%d\n", err);
  140.         goto connect_error;
  141.     }
  142.     
  143.     tinfo = kmalloc(sizeof(struct threadinfo), GFP_KERNEL);
  144.     if (!tinfo) {
  145.         printk(KERN_ALERT "kmalloc threadinfo err\n");
  146.         goto kmalloc_error;
  147.     }
  148.     tinfo->sock = sock;
  149.     tinfo->buffer = buffer;
  150.     kthreadtask = kthread_run(sendthread, tinfo, "Tony-sendmsg");

  151.     if (IS_ERR(kthreadtask)) {
  152.         printk(KERN_ALERT "create sendmsg thread err, err=%ld\n",
  153.                 PTR_ERR(kthreadtask));
  154.         goto thread_error;
  155.     }
  156.     return 0;

  157. thread_error:
  158.     kfree(tinfo);
  159. kmalloc_error:
  160. bind_error:
  161. connect_error:
  162.     sk_release_kernel(sock->sk);
  163.     kthreadtask = NULL;
  164. create_error:
  165.     return -1;
  166. }

  167. static void __exit udp_send_exit(void)
  168. {
  169.     
  170.     if (kthreadtask) {
  171.         kthread_stop(kthreadtask);
  172.     }
  173.     printk(KERN_ALERT "UDP send quit\n");

  174.     return;
  175. }


  176. module_init(udp_send_init);
  177. module_exit(udp_send_exit);

下面是测试效果:
在192.168.0.86机器上开启netcat从8000端口接收数据包:

在192.168.0.3机器上加载该内核模块:

这个时候,在192.168.0.86机器上就可以每隔1秒钟接收到一个数据包:

在192.168.0.3的机器上可以看到发送数据包的内核线程“Tony-sendmsg":

阅读(9096) | 评论(0) | 转发(7) |
给主人留下些什么吧!~~