声明:欢迎转载和引用,转载请注明出处。引用代码请保证代码完整性。
From: http://blog.chinaunix.net/uid-20662820-id-3784251.html
昨天CU论坛有人问到如何在内核模块发送数据包,于是找到了之前写的代码,跟大家分享一下。
该代码SLES 11 sp2内核3.0.13上编译运行通过。
点击(
此处)折叠或打开
- /*
- * Kernel Send Udp packet Module
- *
- * This program
is free software; you can redistribute it
and/or modify
- * it under the terms of the GNU General
Public License as published by
- * the Free Software Foundation; either version 2 of the License,
or
- * (at your
option) any later version.
- *
- * This program
is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY
or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General
Public License for more details.
- *
- * You should have received a copy of the GNU General
Public License
- * along with this program;
if not, write
to the Free Software
- * Foundation, Inc., 59 Temple Place
- Suite 330, Boston, MA 02111-1307, USA.
- *
- * Copyright(C) Tony
<tingw.liu@gmail.com> 2007-2013
- *
- */
- #include <linux/module.h>
- #include <linux/moduleparam.h>
- #include <linux/netfilter.h>
- #include <linux/ip.h>
- #include <net/tcp.h>
- #include <net/udp.h>
- #include <net/icmp.h>
- #include <linux/skbuff.h>
- #include <net/sock.h>
- #include <linux/net.h>
- #include <linux/inetdevice.h>
- #include <linux/in.h>
- #include <linux/kernel.h>
- #include <linux/types.h>
- #include <asm/unaligned.h>
- #include <linux/kthread.h>
- MODULE_LICENSE("GPL");
- MODULE_AUTHOR("Tony ");
- char *ifname =
"eth0";
- module_param(ifname, charp, 0644);
- MODULE_PARM_DESC(ifname,
"Send packets from which net device");
- char *buffer =
"Tony test from kernel!
";
- module_param(buffer, charp, 0644);
- MODULE_PARM_DESC(buffer,
"Packet content");
- __u32 dstip = 0xc0a80056;
- module_param(dstip, uint, 0644);
- __s16 dstport = 8000;
- module_param(dstport, short, 0644);
- long timeout = 1;
- module_param(timeout, long, 0644);
- MODULE_PARM_DESC(timeout,
"Interval between send packets, default 1(unit second)");
- static struct task_struct *kthreadtask
= NULL;
- static int bind_to_device(struct socket
*sock, char
*ifname)
- {
- struct net *net;
- struct net_device *dev;
- __be32 addr;
- struct sockaddr_in sin;
- int err;
- net = sock_net(sock->sk);
- dev = __dev_get_by_name(net, ifname);
- if (!dev)
{
- printk(KERN_ALERT
"No such device named %s
", ifname);
- return -ENODEV;
- }
- addr = inet_select_addr(dev, 0, RT_SCOPE_UNIVERSE);
- sin.sin_family
= AF_INET;
- sin.sin_addr.s_addr
= addr;
- sin.sin_port
= 0;
- err = sock->ops->bind(sock,
(struct sockaddr*)&sin, sizeof(sin));
- if (err
< 0)
{
- printk(KERN_ALERT
"sock bind err, err=%d
",
err);
- return err;
- }
- return 0;
- }
- static int connect_to_addr(struct socket
*sock)
- {
- struct sockaddr_in daddr;
- int err;
- daddr.sin_family
= AF_INET;
- daddr.sin_addr.s_addr
= cpu_to_be32(dstip);
- daddr.sin_port
= cpu_to_be16(dstport);
- err = sock->ops->connect(sock,
(struct sockaddr*)&daddr,
- sizeof(struct sockaddr), 0);
- if (err
< 0)
{
- printk(KERN_ALERT
"sock connect err, err=%d
",
err);
- return err;
- }
- return 0;
- }
- struct threadinfo{
- struct socket *sock;
- char *buffer;
- };
- static int sendthread(void
*data)
- {
- struct kvec iov;
- struct threadinfo *tinfo
= data;
- struct msghdr msg =
{.msg_flags
= MSG_DONTWAIT|MSG_NOSIGNAL};
- int len;
- while (!kthread_should_stop())
{
- iov.iov_base
= (void *)tinfo->buffer;
- iov.iov_len
= strlen(tinfo->buffer);
- len = kernel_sendmsg(tinfo->sock,
&msg,
&iov, 1, strlen(tinfo->buffer));
- if (len
!= strlen(buffer))
{
- printk(KERN_ALERT
"kernel_sendmsg err, len=%d, buffer=%d
",
- len,
(int)strlen(buffer));
- if
(len ==
-ECONNREFUSED)
{
- printk(KERN_ALERT
"Receive Port Unreachable packet!
");
- }
- break;
- }
- schedule_timeout_interruptible(timeout
* HZ);
- }
- kthreadtask =
NULL;
- sk_release_kernel(tinfo->sock->sk);
- kfree(tinfo);
- return 0;
- }
- static int __init udp_send_init(void)
- {
- int err
= 0;
- struct socket *sock;
- struct threadinfo *tinfo;
- err = sock_create_kern(PF_INET, SOCK_DGRAM, IPPROTO_UDP,
&sock);
- if (err
< 0)
{
- printk(KERN_ALERT
"UDP create sock err, err=%d
",
err);
- goto create_error;
- }
- sock->sk->sk_reuse
= 1;
- err = bind_to_device(sock, ifname);
- if (err
< 0)
{
- printk(KERN_ALERT
"Bind to %s err, err=%d
", ifname,
err);
- goto bind_error;
- }
- err = connect_to_addr(sock);
- if (err
< 0)
{
- printk(KERN_ALERT
"sock connect err, err=%d
",
err);
- goto connect_error;
- }
-
- tinfo = kmalloc(sizeof(struct threadinfo), GFP_KERNEL);
- if (!tinfo)
{
- printk(KERN_ALERT
"kmalloc threadinfo err
");
- goto kmalloc_error;
- }
- tinfo->sock
= sock;
- tinfo->buffer
= buffer;
- kthreadtask = kthread_run(sendthread, tinfo,
"Tony-sendmsg");
- if (IS_ERR(kthreadtask))
{
- printk(KERN_ALERT
"create sendmsg thread err, err=%ld
",
- PTR_ERR(kthreadtask));
- goto thread_error;
- }
- return 0;
- thread_error:
- kfree(tinfo);
- kmalloc_error:
- bind_error:
- connect_error:
- sk_release_kernel(sock->sk);
- kthreadtask =
NULL;
- create_error:
- return -1;
- }
- static void __exit udp_send_exit(void)
- {
-
- if (kthreadtask)
{
- kthread_stop(kthreadtask);
- }
- printk(KERN_ALERT
"UDP send quit
");
- return;
- }
- module_init(udp_send_init);
- 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":