Как добавить новый пользовательский протокол уровня 4 (новый сокет Raw) в ядро ​​Linux?

Я пытаюсь добавить свой собственный настраиваемый протокол уровня 4 в Linux (ubuntu 14.04) — IPPROTO_MYPROTO в качестве загружаемого модуля ядра. Я сделал все необходимые шаги для регистрации протокола. Здесь я делюсь своим кодом.

Когда я пытаюсь отправить сообщение из пользовательской программы с помощью sendmsg(), я ожидаю, что соответствующая функция myproto_sendmsg() будет зарегистрирована через struct proto. структура должна вызываться в пространстве ядра. Но я наблюдаю, что, хотя myproto_sendmsg() в пространстве ядра не вызывается, машина назначения получает правильные данные. сюрприз! сюрприз!. Здесь работает udp sendmsg() fn по умолчанию, что похоже на незваного гостя, выполняющего свою работу.

Здесь вызов sendmsg() в пользовательском пространстве возвращает столько же байтов, сколько и send. Следовательно, 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;
}

person Abhishek Sagar    schedule 05.05.2016    source источник
comment
Можете ли вы поделиться определением для myproto_protocol   -  person talshorer    schedule 05.05.2016
comment
@talshorer, обновлено. Но я предполагаю, что эта структура связана только с регистрацией функции, которая будет передана SKB L3 для входящих пакетов для skb-›protocol = IPPROTO_MYPROTO.   -  person Abhishek Sagar    schedule 05.05.2016
comment
Я решил вышеуказанную проблему. Я пропустил добавление inet_register_protosw() в init_module(). во-вторых, для структуры : struct proto myproto_prot требуется указать .hash = myproto_lib_hash, где myproto_lib_hash() — это просто фиктивный fn с пустым телом (без указания этого будет утверждаться ядро). Я обновил код выше.   -  person Abhishek Sagar    schedule 15.05.2016