应用层创建socket,内核模块通过该socket发送数据包

1780阅读 0评论2013-09-23 joepayne
分类:LINUX

声明:欢迎转载和引用,转载请注明出处。引用代码请保证代码完整性。
本博文将讲解一种内核态通过应用层创建的socket发送数据包的方法。


首先应用层创建socket,并且调用connect。


如图所示,向192.168.0.86的8000端口建立udp连接。获取到进程pid=9707,对应的socket的文件句柄fd=3。

在192.168.0.86机器上开启netcat

内核层根据进程pid和文件句柄fd,获取到对应的socket结构体,然后通过该socket发送数据包。


这个时候在192.168.0.86上就可以看到通过应用层创建的socket发送的数据包




应用层代码:

点击(此处)折叠或打开

  1. #include <sys/types.h>
  2. #include <sys/socket.h>
  3. #include <arpa/inet.h>
  4. #include <stdio.h>
  5. #include <string.h>
  6. #include <stdarg.h>
  7. #include <stdlib.h>
  8. #include <errno.h>
  9. #include <pthread.h>
  10. #define MAXLINE 100
  11. struct thread_info {
  12.     unsigned long long packet;
  13.     unsigned long long bytes;
  14. };
  15. void err_quit(char * fmt,...)
  16. {
  17.     char buf[MAXLINE+1];
  18.     va_list ap;
  19.     va_start(ap,fmt);
  20.     vsnprintf(buf,sizeof(buf),fmt,ap);
  21.     va_end(ap);
  22.     fputs(buf,stdout);
  23.     fputs("\n",stdout);
  24.     exit(1);
  25. }
  26. void dg_cli(int sockfd,const struct sockaddr *servaddr,socklen_t serlen)
  27. {
  28.     int n;
  29.     int pret;
  30.     pthread_t id;
  31.     struct thread_info info;
  32.     char sendline[MAXLINE],recvline[MAXLINE];
  33.     info.packet=0;
  34.     info.bytes=0;
  35.     bzero(sendline,MAXLINE);
  36.     strcpy(sendline,"TEST BOY\n");
  37. restart:
  38.     connect(sockfd, servaddr, serlen);
  39.     while(1) {
  40.         sleep(10);
  41.     }
  42.     while(1){
  43.         pret = send(sockfd,sendline,strlen(sendline),0);
  44.         if(pret < 0){
  45.             //printf("errno=%d, errstr=%s\n", errno, strerror(errno));
  46.             if(errno == 111){
  47.                 printf("I received udp port unreachable packet\n");
  48.                 sleep(1);
  49.                 goto restart;
  50.             }
  51.         }else{
  52.             printf("OK\n");
  53.         }
  54.         sleep(1);
  55.     }
  56. }
  57. int main(int argc,char **argv)
  58. {
  59.     int sockfd;
  60.     struct sockaddr_in servaddr;
  61.     if(argc!=3)
  62.         err_quit("usage:client ");
  63.     bzero(&servaddr,sizeof(servaddr));;
  64.     servaddr.sin_family=AF_INET;
  65.     servaddr.sin_port=htons(atoi(argv[2]));
  66.     inet_pton(AF_INET,argv[1],&servaddr.sin_addr);
  67.     if((sockfd=socket(AF_INET,SOCK_DGRAM,0))<0)
  68.         err_quit("socket error");
  69.     dg_cli(sockfd,(struct sockaddr*)&servaddr,sizeof(servaddr));
  70.     exit(0);
  71. }
内核层代码:

点击(此处)折叠或打开

  1. /*
  2.  * Kernel Send Udp packet Use userspace socket!
  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.  *        2013-07-04 08:09:07 CST
  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. #include <linux/fdtable.h>
  38. #include <linux/file.h>

  39. MODULE_LICENSE("GPL");
  40. MODULE_AUTHOR("Tony ");

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

  44. pid_t pidnr = 1000;
  45. module_param(pidnr, int, 0644);
  46. MODULE_PARM_DESC(pidnr, "Process pid");

  47. int fd = 4;
  48. module_param(fd, int, 0644);
  49. MODULE_PARM_DESC(fd, "Socket file fd");

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


  53. static struct task_struct *kthreadtask = NULL;

  54. struct file *sockfile = NULL;


  55. struct threadinfo{
  56.     struct socket *sock;
  57.     char *buffer;
  58. };

  59. static struct socket *sock_from_file(struct file *file, int *err)
  60. {
  61.     /* FIXME: Warning....
  62.      Because socket_file_ops is a static variable, so
  63.      we can't check if the file is a socket like kernel
  64.      function sock_from_file.
  65.      So..., we doesn't check if the file is a socket and kernel
  66.      will panic if the file is not a socket
  67.      */


  68.     //if (file->f_op == &socket_file_ops)
  69.         return file->private_data;    /* set in sock_map_fd */

  70.     *err = -ENOTSOCK;
  71.     return NULL;
  72. }


  73. static struct socket *find_sock_by_pid_fd(pid_t pidnr, int fd, int *err)
  74. {
  75.     struct task_struct *p;
  76.     struct file *file;
  77.     struct files_struct *files;
  78.     struct socket *sock;
  79.     struct pid *pid;
  80.     pid = find_get_pid(pidnr);
  81.     p = get_pid_task(pid, PIDTYPE_PID);
  82.     if (!p) {
  83.         printk(KERN_ALERT "find_task_by_vpid error!\n");
  84.         return NULL;
  85.     }


  86.     /*
  87.      Next code learn from fget()
  88.      Because kernel fget() function use "current" variable,
  89.      so rewrite
  90.     */
  91.     files = p->files;
  92.     rcu_read_lock();
  93.     file = fcheck_files(files, fd);
  94.     if (file) {
  95.         if (file->f_mode & FMODE_PATH || !atomic_long_inc_not_zero(&file->f_count))
  96.             file = NULL;
  97.     }
  98.     rcu_read_unlock();
  99.     if (!file) {
  100.         printk(KERN_ALERT "Can't get file from fd\n");
  101.         return NULL;
  102.     }


  103.     sockfile = file;
  104.     sock = sock_from_file(sockfile, err);
  105.     if (!sock) {
  106.         fput(sockfile);
  107.         sockfile = NULL;
  108.     }
  109.     return sock;
  110. }
  111. static int sendthread(void *data)
  112. {
  113.     struct kvec iov;
  114.     struct threadinfo *tinfo = data;
  115.     struct msghdr msg = {.msg_flags = MSG_DONTWAIT|MSG_NOSIGNAL};
  116.     int len;
  117.     while (!kthread_should_stop()) {
  118.         iov.iov_base = (void *)tinfo->buffer;
  119.         iov.iov_len = strlen(tinfo->buffer);
  120.         len = kernel_sendmsg(tinfo->sock, &msg, &iov, 1, strlen(tinfo->buffer));
  121.         if (len != strlen(buffer)) {
  122.             printk(KERN_ALERT "kernel_sendmsg err, len=%d, buffer=%d\n",
  123.                     len, (int)strlen(buffer));
  124.             if (len == -ECONNREFUSED) {
  125.                 printk(KERN_ALERT "Receive Port Unreachable packet!\n");
  126.             }
  127.             break;
  128.         }
  129.         schedule_timeout_interruptible(timeout * HZ);
  130.     }
  131.     kthreadtask = NULL;
  132.     kfree(tinfo);

  133.     return 0;
  134. }

  135. static int __init udp_send_init(void)
  136. {
  137.     int err = 0;
  138.     struct socket *sock;
  139.     struct threadinfo *tinfo;

  140.     sock = find_sock_by_pid_fd(pidnr, fd, &err);    
  141.     if (!sock) {
  142.         printk(KERN_ALERT "find_sock error\n");
  143.         goto find_error;
  144.     }
  145.     tinfo = kmalloc(sizeof(struct threadinfo), GFP_KERNEL);
  146.     if (!tinfo) {
  147.         printk(KERN_ALERT "kmalloc threadinfo err\n");
  148.         goto kmalloc_error;
  149.     }
  150.     tinfo->sock = sock;
  151.     tinfo->buffer = buffer;
  152.     kthreadtask = kthread_run(sendthread, tinfo, "Tony-sendmsg");

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

  159. thread_error:
  160.     kfree(tinfo);
  161. kmalloc_error:
  162.     kthreadtask = NULL;
  163. find_error:
  164.     return -1;
  165. }

  166. static void __exit udp_send_exit(void)
  167. {

  168.     if (kthreadtask) {
  169.         kthread_stop(kthreadtask);
  170.     }

  171.     if (sockfile) {
  172.         fput(sockfile);
  173.     }
  174.     printk(KERN_ALERT "UDP send quit\n");

  175.     return;
  176. }


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

上一篇:关于const 和volatile的理解
下一篇:Linux系统中,read文件过程分析