LinuxSir.cn,穿越时空的Linuxsir!

 找回密码
 注册
搜索
热搜: shell linux mysql
查看: 1442|回复: 5

内核模块中创建tcp连接

[复制链接]
发表于 2008-6-3 15:35:41 | 显示全部楼层 |阅读模式
在网上到处搜不到如何在内核中创建tcp连接,后来自己参考内核源代码中的linux/net/sunrpc/xprtsock.c写了一个可用的测试程序,与大家分享,代码有可以改进的地方还请高手都指教呀^_^
  1. /* code is referred to linux/net/sunrpc/xprtsock.c */
  2. #include <linux/module.h>
  3. #include <linux/kernel.h>
  4. #include <linux/init.h>
  5. #include <linux/types.h>
  6. #include <linux/errno.h>
  7. #include <linux/socket.h>
  8. #include <linux/in.h>
  9. #include <linux/inet.h>
  10. #include <linux/net.h>
  11. #include <linux/tcp.h>
  12. #include <net/sock.h>
  13. #include <net/checksum.h>
  14. #include <net/tcp.h>
  15. static char *peer_addr = "192.168.0.100";
  16. static unsigned short peer_port = 21;
  17. static char *msg = "USER anonymous\r\n";
  18. static struct socket *sock = NULL;
  19. static struct work_struct work;
  20. static int recvd = 0;
  21. static int tcp_sendto(struct socket *sock, void * buff, size_t len,
  22.                 unsigned flags, struct sockaddr *addr, int addr_len) {
  23.   struct kvec vec;
  24.   struct msghdr msg;
  25.   vec.iov_base=buff;
  26.   vec.iov_len=len;
  27.   memset(&msg, 0x00, sizeof(msg));
  28.   msg.msg_name=addr;
  29.   msg.msg_namelen=addr_len;
  30.   msg.msg_flags = flags | MSG_DONTWAIT | MSG_NOSIGNAL;
  31.   return kernel_sendmsg(sock, &msg, &vec, 1, len);
  32. }
  33. static void kernsock_send_msg(void) {
  34.         int n;
  35.   struct sockaddr_in addr;
  36.   
  37.   memset(&addr, 0x00, sizeof(addr));
  38.   addr.sin_family = AF_INET;
  39.   addr.sin_port = htons(peer_port);
  40.   addr.sin_addr.s_addr = in_aton(peer_addr);
  41.   n = tcp_sendto(sock, msg, strlen(msg), 0, (struct sockaddr *)&addr, sizeof(addr));
  42.   printk("send %d bytes\n", n);
  43. }
  44. static int kernsock_tcp_data_recv(read_descriptor_t *rd_desc, struct sk_buff *skb, unsigned int offset, size_t len) {
  45.         struct iphdr *ip;
  46.         struct tcphdr *tcp;
  47.         char *tcp_data;
  48.         int        payload,doff;
  49.                
  50.         printk("kernsock_tcp_data_recv started:offset:%d,len:%d\n",offset,len);
  51.        
  52.         if (!skb) return 0;
  53.        
  54.         if (!(skb->nh.iph)) return 0;
  55.        
  56.         ip = skb->nh.iph;
  57.         if(ip->protocol == IPPROTO_TCP) {
  58.                 tcp = (struct tcphdr *)(skb->h.th);
  59.                 printk("src=%u.%u.%u.%u:%u,dest=%u.%u.%u.%u:%u\n",NIPQUAD(ip->saddr),ntohs(tcp->source),NIPQUAD(ip->daddr),ntohs(tcp->dest));
  60.                
  61.                 payload = ntohs(ip->tot_len) - (ip->ihl << 2);
  62.                 doff = tcp->doff << 2;
  63.                 tcp_data = (char *)((int)tcp + doff);
  64.                        
  65.                 if(tcp->psh) {
  66.                         printk("peer sent psh:%.*s\n",payload - doff,tcp_data);
  67.                         recvd = 1;
  68.                 }
  69.         }
  70.         printk("kernsock_tcp_data_recv done\n");
  71.         return len;
  72. }
  73. static void kernsock_tcp_data_ready(struct sock *sk, int bytes) {
  74.         read_descriptor_t rd_desc;
  75.         read_lock(&sk->sk_callback_lock);
  76.         printk("kernsock_tcp_data_ready\n");
  77.         rd_desc.arg.data = NULL;
  78.         rd_desc.count = 65536;
  79.         tcp_read_sock(sk, &rd_desc, kernsock_tcp_data_recv);
  80.         read_unlock(&sk->sk_callback_lock);
  81. }
  82. static void kernsock_tcp_state_change(struct sock *sk) {
  83.         read_lock(&sk->sk_callback_lock);
  84.         switch (sk->sk_state) {
  85.         case TCP_ESTABLISHED:
  86.                 printk("TCP_ESTABLISHED\n");
  87.                 break;
  88.         case TCP_SYN_SENT:
  89.                 printk("TCP_SYN_SENT\n");
  90.                 break;
  91.         case TCP_SYN_RECV:
  92.                 printk("TCP_SYN_RECV\n");
  93.                 break;
  94.         case TCP_CLOSE_WAIT:
  95.                 printk("TCP_CLOSE_WAIT\n");
  96.                 break;
  97.         }
  98.         read_unlock(&sk->sk_callback_lock);
  99. }
  100. static void kernsock_tcp_write_space(struct sock *sk) {
  101.         read_lock(&sk->sk_callback_lock);
  102.         printk("kernsock_tcp_write_space\n");
  103.         read_unlock(&sk->sk_callback_lock);
  104. }
  105. static void tcp_connect_worker(struct sockaddr_in *addr) {
  106.         int err, status = -EIO;
  107.         struct sock *sk;
  108.        
  109.         /* start from scratch */
  110.         if ((err = sock_create_kern(PF_INET, SOCK_STREAM, IPPROTO_TCP, &sock)) < 0) {
  111.                 printk("can't create TCP transport socket (%d).\n", -err);
  112.                 return;
  113.         }
  114.         sk = sock->sk;
  115.         write_lock_bh(&sk->sk_callback_lock);
  116.         sk->sk_data_ready = kernsock_tcp_data_ready;
  117.         sk->sk_state_change = kernsock_tcp_state_change;
  118.         sk->sk_write_space = kernsock_tcp_write_space;
  119.         sk->sk_allocation = GFP_ATOMIC;
  120.         /* socket options */
  121.         sk->sk_userlocks |= SOCK_BINDPORT_LOCK;
  122.         sock_reset_flag(sk, SOCK_LINGER);
  123.         tcp_sk(sk)->linger2 = 0;
  124.         tcp_sk(sk)->nonagle |= TCP_NAGLE_OFF;
  125.         write_unlock_bh(&sk->sk_callback_lock);
  126.         status = sock->ops->connect(sock, (struct sockaddr *) addr, sizeof(struct sockaddr_in), O_NONBLOCK);
  127.         if (status < 0) {
  128.                 switch (status) {
  129.                         case -EINPROGRESS:
  130.                                 printk("EINPROGRESS\n");
  131.                                 break;
  132.                         case -EALREADY:
  133.                                 printk("EALREADY\n");
  134.                                 break;
  135.                         case -ECONNREFUSED:
  136.                                 printk("ECONNREFUSED\n");
  137.                                 break;
  138.                         case -ECONNRESET:
  139.                                 printk("ECONNRESET\n");
  140.                                 break;
  141.                 }
  142.         }
  143. }
  144. static int __init socket_init(void){
  145.     struct sockaddr_in addr;
  146.    
  147.     memset(&addr, 0x00, sizeof(addr));
  148.     addr.sin_family = AF_INET;
  149.     addr.sin_port = htons(peer_port);
  150.     addr.sin_addr.s_addr = in_aton(peer_addr);
  151.     tcp_connect_worker(&addr);
  152.    
  153.     msleep(1000);
  154.     if(recvd) {
  155.             INIT_WORK(&work, kernsock_send_msg, NULL);
  156.                   schedule_work(&work);
  157.           } else {
  158.                   printk("time out\n");
  159.           }
  160.     return 0;
  161. }
  162. static void __exit socket_exit(void) {
  163.     sock_release(sock);
  164. }
  165. module_init(socket_init);
  166. module_exit(socket_exit);
复制代码
发表于 2008-6-3 16:09:48 | 显示全部楼层
没有提供Makefile??
回复 支持 反对

使用道具 举报

 楼主| 发表于 2008-6-3 16:26:37 | 显示全部楼层
Post by realtang;1858581
没有提供Makefile??
  1. obj-m := kernsock.o
  2. all:make -C /usr/src/linux-2.6-2.6.18/ M=`pwd` modules
复制代码

直接make命令就可以了
然后insmod kernsock.ko后就开始测试了
卸载用rmmod kersock.ko

代码中的这几个变量需要自己修改一下
static char *peer_addr = "192.168.0.100";
static unsigned short peer_port = 21;
static char *msg = "USER anonymous\r\n";
回复 支持 反对

使用道具 举报

发表于 2008-6-3 16:50:32 | 显示全部楼层
如果被连接机器不响应,会不会导致内核被挂起,死机?
回复 支持 反对

使用道具 举报

 楼主| 发表于 2008-6-3 17:02:49 | 显示全部楼层
Post by realtang;1858599
如果被连接机器不响应,会不会导致内核被挂起,死机?


呵呵,安全起见测试内核模块还是用windows + vmware,测试起来感觉很不错,不用再提心吊胆,呵呵
回复 支持 反对

使用道具 举报

发表于 2009-9-3 14:43:41 | 显示全部楼层
楼主强人,我现在也在做内核socket的编程,找了很多例子,不过也没有合适的,楼主的内核socket客户端的代码我试过了,可以向用户的server端发代码,不知楼主是否也做了内核socket 服务器端的代码,如果有,麻烦楼主提供下,多谢了,我的邮箱  happytianli@cse.buaa.edu.cn
回复 支持 反对

使用道具 举报

您需要登录后才可以回帖 登录 | 注册

本版积分规则

快速回复 返回顶部 返回列表