0

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!

Akshay
  • 329
  • 1
  • 7
  • 19
  • No @purpletech. I accomplished the same feat by using the **system()** and passing the _route_ command as parameters to the system(). You can look up more at this [link](http://www.tutorialspoint.com/c_standard_library/c_function_system.htm) – Akshay Aug 11 '14 at 22:53
  • I dont want to call system(..) . I used ioctl – resultsway Aug 12 '14 at 20:02
  • Yes that is also another way of doing it. But since I was working on a POC getting into ioctl was not required. – Akshay Aug 12 '14 at 20:58
  • I see a little problem here, in your code you set `nl->nlmsg_pid = getpid();` In my opinion, this should be set to the receiver's PID that is `0` for kernel. – JuliandotNut Aug 14 '14 at 15:00

2 Answers2

0

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.

JuliandotNut
  • 1,169
  • 1
  • 12
  • 22
0

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)