如何在linux内核中添加一个新的自定义第4层协议(一个新的原始套接字)?

我想在linux(ubuntu 14.04)中添加自己定制的第4层协议–IPPROTO_MYPROTO作为可加载的内核模块。 我已经完成了所有必要的步骤来注册协议。 在这里,我分享我的代码。

当我试图从sendmsg()发送用户空间程序的消息时,我期望通过struct proto结构注册的相应的fn myproto_sendmsg()应该在内核空间中调用。 但是我正在观察的是,虽然内核空间中的myproto_sendmsg()没有被调用,但是目标机器正在接收正确的数据。 惊喜! 惊喜! 。 是默认的udp sendmsg()fn在这里踢,就像是不速之客做他的工作。

在这里,用户空间中的sendmsg()调用返回与发送一样多的字节。 因此,FN返回成功。

用户空间程序:

void forwardUDP( int destination_node ,char sendString[] ) { struct msghdr msg; destination_node = destination_node % N; //destination node to which data is to be forwaded int sock, rc; struct sockaddr_in server_addr; struct iovec iov; struct hostent *host; //hostent predefined structure use to store info about host host = (struct hostent *) gethostbyname(node[destination_node].ip_address);//gethostbyname returns a pointer to hostent if ((sock = socket(AF_INET, SOCK_RAW, 5)) == -1) { perror("socket"); exit(1); } //destination address structure server_addr.sin_family = AF_INET; server_addr.sin_port = htons(node[destination_node].udpportno); server_addr.sin_addr = *((struct in_addr *)host->h_addr); //host->h_addr gives address of host bzero(&(server_addr.sin_zero),8); /* fill the messsage structure*/ memset(&msg, 0 , sizeof(struct msghdr)); memset(&iov, 0, sizeof(struct iovec)); msg.msg_name = (void *)&server_addr; msg.msg_namelen = sizeof(struct sockaddr_in); printf("sendString = %s\n", sendString); iov.iov_base = (void *)sendString; iov.iov_len = strlen(sendString); msg.msg_iov = &iov; printf("len = %d\n", strlen(sendString)); #if 1 msg.msg_iovlen = 1; msg.msg_control = NULL; msg.msg_controllen = 0; msg.msg_flags = 0; #endif //sendto(sock, sendString, strlen(sendString), 0,(struct sockaddr *)&server_addr, sizeof(struct sockaddr)); **rc = sendmsg(sock, &msg, 0);** printf("rc = %d\n", rc); //sendto() function shall send a message through a connectionless-mode socket. printf("\nFORWARD REQUEST : '%s' has been forwarded to node ---->%d\n",sendString,destination_node); //close(sock); } 

内核模块

 /* Define the handler which will recieve all ingress packets for protocol = IPPROTO_MYPROTO defined in net/protocol.h */ /* Resgiter the call backs for pkt reception */ static const struct net_protocol myproto_protocol = { .handler = myproto_rcv, .err_handler = myproto_err, .no_policy = 1, .netns_ok = 1, }; static struct inet_protosw myproto_protosw; int myproto_rcv(struct sk_buff *skb){ printk(KERN_INFO "myproto_rcv is called\n"); return 0; } int myproto_sendmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg, size_t len){ printk(KERN_INFO "myproto_sendmsg() is called\n"); return 0; } void myproto_lib_close(struct sock *sk, long timeout){ printk(KERN_INFO "close is called\n"); return; } int myproto_recvmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg, size_t len, int noblock, int flags, int *addr_len){ printk(KERN_INFO "myproto_recvmsg() is called.\n"); printk(KERN_INFO "iocb = 0x%x,\nsk = 0x%x,\nmsg = 0x%x,\nlen = %d,\nnoblock = %d,\nflags = %d,\naddr_len = 0x%x", iocb, sk, msg, len, noblock, flags, addr_len); return 0; } /* Socket structure for Custom protocol, see struct udp_sock for example*/ struct myproto_sock{ struct inet_sock inet; // should be first member __u16 len; }; void myproto_lib_hash(struct sock *sk){ printk(KERN_INFO "myproto_lib_hash() is called"); } /* Define the **struct proto** structure for the Custom protocol defined in net/sock.h */ struct proto myproto_prot = { .name = "MYPROTO", .owner = THIS_MODULE, .close = myproto_lib_close, .sendmsg = myproto_sendmsg, .hash = myproto_lib_hash, .recvmsg = myproto_recvmsg, .obj_size = sizeof(struct myproto_sock), .slab_flags = SLAB_DESTROY_BY_RCU, }; int init_module(void); void cleanup_module(void); int init_module(void) { int rc = 0; rc = proto_register(&myproto_prot, 1); if(rc == 0){ printk(KERN_INFO "Protocol registration is successful\n"); } else{ printk(KERN_INFO "Protocol registration is failed\n"); cleanup_module(); return rc; } rc = inet_add_protocol(&myproto_protocol, IPPROTO_MYPROTO); if(rc == 0){ printk(KERN_INFO "Protocol insertion in inet_protos[] is successful\n"); } else{ printk(KERN_INFO "Protocol insertion in inet_protos[] is failed\n"); cleanup_module(); return rc; } memset(&myproto_protosw, 0 ,sizeof(myproto_protosw)); myproto_protosw.type = SOCK_RAW; myproto_protosw.protocol = IPPROTO_MYPROTO; myproto_protosw.prot = &myproto_prot; extern const struct proto_ops inet_dgram_ops; // defined in ipv4/af_inet.c myproto_protosw.ops = &inet_dgram_ops; myproto_protosw.flags = INET_PROTOSW_REUSE; inet_register_protosw(&myproto_protosw); return 0; } void cleanup_module(void) { int rc = 0; rc = inet_del_protocol(&myproto_protocol, IPPROTO_MYPROTO); if(rc == 0) printk(KERN_INFO "Protocol removed successful\n"); else printk(KERN_INFO "Protocol removal failed\n"); proto_unregister(&myproto_prot); printk(KERN_INFO "Module cleaned up\n"); return; }