How to add a new custom layer 4 protocol (a new Raw socket) in linux kernel?

前提是你 提交于 2019-12-12 09:45:21

问题


i am trying adding my own customized layer 4 protocol in linux (ubuntu 14.04) - IPPROTO_MYPROTO as a loadable kernel module. I have done all necessary steps to register the protocol. Here i am sharing my code.

When i am trying to send a mesage from user space program using sendmsg(), i expect the corresponding fn myproto_sendmsg() registered via struct proto structure should be called in kernel space. But what i am observing is that though the myproto_sendmsg() in kernel space is not being called, yet destination machine is receiving the correct data. surprise ! surprise !. Is the default udp sendmsg() fn kicking in here which is like uninvited guest doing his work.

Here, sendmsg() call in user space returns as many bytes as send. Hence, fn returns success.

User space program :

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);
}

Kernel Module

/* 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;
}

来源:https://stackoverflow.com/questions/37054999/how-to-add-a-new-custom-layer-4-protocol-a-new-raw-socket-in-linux-kernel

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!