声明:欢迎转载和引用,转载请注明出处。引用代码请保证代码完整性。
昨天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!\n";
-
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\n", 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\n", 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\n", 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\n",
-
len, (int)strlen(buffer));
-
if (len == -ECONNREFUSED) {
-
printk(KERN_ALERT "Receive Port Unreachable packet!\n");
-
}
-
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\n", 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\n", ifname, err);
-
goto bind_error;
-
}
-
err = connect_to_addr(sock);
-
if (err < 0) {
-
printk(KERN_ALERT "sock connect err, err=%d\n", err);
-
goto connect_error;
-
}
-
-
tinfo = kmalloc(sizeof(struct threadinfo), GFP_KERNEL);
-
if (!tinfo) {
-
printk(KERN_ALERT "kmalloc threadinfo err\n");
-
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\n",
-
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\n");
-
-
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":
阅读(9096) | 评论(0) | 转发(7) |