5

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;
}
Abhishek Sagar
  • 1,189
  • 4
  • 20
  • 44
  • Can you share the definition for myproto_protocol – talshorer May 05 '16 at 16:30
  • @talshorer, updated. But i guess that structure is related to only registering the function which will be handed over the SKB by L3 for ingressing packets for skb->protocol = IPPROTO_MYPROTO. – Abhishek Sagar May 05 '16 at 16:42
  • I have got the above problem resolved. I missed out adding inet_register_protosw() in init_module (). secondly, for structure : `struct proto myproto_prot` it is required to specify `.hash = myproto_lib_hash`, where `myproto_lib_hash()` is just a dummy fn with empty body (not specifying this will assert kernel). I have updated the code above. – Abhishek Sagar May 15 '16 at 06:42

0 Answers0