简体   繁体   中英

Netlink sockets does not add routes to routing table for IPv6

I want to be able to add a new IPv6 address but have not been able to so far..The program runs with success but nothing is reflected in the routing table.

#include <sys/socket.h>


 #include <stdlib.h>
    #include <stdio.h>
    #include <string.h>
    #include <linux/netlink.h>
    #include <linux/rtnetlink.h>
    #include <arpa/inet.h>
    #include <unistd.h>
    #include <net/if.h>
    #include <sys/types.h>


    #define BUFSIZE 4095

    struct route_info
    {
    char*       dst_addr;
    char*       src_addr;
    char*       gateway;
    char        ifName[IF_NAMESIZE];

    };


    void fillRoutes(struct route_info* rinfo, const char* dst_addr, const char* src_addr, const char* gateway, const char* ifname)
    {
    int pton_fd;

    pton_fd = inet_pton(AF_INET6, "2001::4", (struct in_addr *)&rinfo->dst_addr);
    if (pton_fd <= 0)
    {
        perror("pton errror at dst_addr");
        exit(EXIT_FAILURE);
    }

    pton_fd = inet_pton(AF_INET6, "2001::3", (struct in_addr *)&rinfo->gateway);
    if (pton_fd <= 0)
    {
        perror("gateway error");
        exit(EXIT_FAILURE);
    }

    }

    int addAttr(struct nlmsghdr *nl, int maxlen, int type, void *data, int attr_len )
    {
    struct rtattr *rta;
    int len = RTA_LENGTH(attr_len);
    if(NLMSG_ALIGN(nl->nlmsg_len) + len > maxlen)
    {
        perror("inside attr()");
        exit(EXIT_FAILURE);
    } 

    nl->nlmsg_len = NLMSG_ALIGN(nl->nlmsg_len) + len;
    rta = (struct rtattr *)((char *)nl + NLMSG_ALIGN(nl->nlmsg_len));
    rta->rta_type = type;
    rta->rta_len = len;
    memcpy(RTA_DATA(rta), data, attr_len);
    //nl->nlmsg_len = NLMSG_ALIGN(nl->nlmsg_len) + len;
    fprintf(stderr, "attr len=%d\n",nl->nlmsg_len);
    return 0;
   }
    int main (int argc, char **argv)
    {
    int             bytes_sent;
    int             msg_seq =1;
    int             rtnetlink_socket = -1;
    struct sockaddr_nl  addr;
    struct rtmsg        *raddr;
    struct nlmsghdr     *nl;
    struct iovec        iov;
    struct msghdr       msg;
    char            dst_addr[30];
    char            src_addr[30];
    char            gateway[30];
    char            ifname[30];
    char            msgbuf[BUFSIZE];
    struct route_info   rinfo;

    memset(&addr, 0, sizeof(addr));
        memset(msgbuf, 0, BUFSIZE);

    if ((rtnetlink_socket = socket(AF_NETLINK, SOCK_DGRAM, NETLINK_ROUTE)) < 0)
    {
        perror("socket");
        exit(EXIT_FAILURE);
    }
    nl = (struct nlmsghdr *)msgbuf;
    raddr = (struct rtmsg*)NLMSG_DATA(nl);

    nl->nlmsg_len = NLMSG_LENGTH(sizeof(struct rtmsg));
    nl->nlmsg_type = RTM_NEWROUTE;
    nl->nlmsg_flags = NLM_F_REQUEST | NLM_F_CREATE;
    nl->nlmsg_seq = msg_seq++;
    nl->nlmsg_pid = getpid();

    //fill entries for routing table

    raddr->rtm_family = AF_INET6;
        raddr->rtm_dst_len = 128;
        raddr->rtm_src_len = 0;
        raddr->rtm_table = RT_TABLE_MAIN;
        raddr->rtm_protocol = RTPROT_STATIC;
        raddr->rtm_scope = RT_SCOPE_UNIVERSE;
        raddr->rtm_type = RTN_UNICAST;
    raddr->rtm_flags = RTM_F_NOTIFY;
    raddr->rtm_tos = 0;

    fillRoutes(&rinfo, dst_addr, src_addr, gateway, ifname);

    addAttr(nl, BUFSIZE, RTA_DST, &rinfo.dst_addr, 16);
    addAttr(nl, BUFSIZE, RTA_GATEWAY, &rinfo.gateway, 16);

    if((bytes_sent = send(rtnetlink_socket, nl, nl->nlmsg_len, 0)) < 0)
    {
        perror("failed to write to socket");
        exit(EXIT_FAILURE);
    }

    printf("No of bytes sent :%d\n", bytes_sent);

    return 0;
}

This gives me the attrbute value 48 in when RTA_DST and 68 when RTA_GATEWAY. Where am I making a mistake. I don't seem to find the bug. Any help is appreciated!

You are sending the NEWROUTE request to your own process by setting wrong PID in the nlmsghdr.

nl->nlmsg_pid = getpid(); /* This is your own process ID*/

you need to send it to kernel , with PID 0, so replacing it with

nl->nlmsg_pid = 0;

will send it to the kernel and only then kernel can incorporate it into the routing table.

Another point, for sending data/control information over netlink socket, sendmsg() is a preferred way to go. I am not sure how send() is working here as it is intended to work over a connected state. See man pages . It is stated that send() returns -1 for local errors only and does not detect remote errors, which might be another problem later.

I have moved

nl->nlmsg_len = NLMSG_ALIGN(nl->nlmsg_len) + len;

after

rta = (struct rtattr *) ((char *) nl + NLMSG_ALIGN(nl->nlmsg_len));

which helped (actually it is already commented in the orig, code)

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM