linux使用 netlink 添加路由简单代码

1,在网上查了关于netlink的实现路由查询和添加路由的文章,资料很少,提供的代码都没有运行结果或者编译不了。所以从网上拷贝的代码仔细研究,一步一步的调试,添加很多printf语句查看各结构的值。

2,我主要参考的代码网页链接有:

http://downloads.open-mesh.org/svn/batman/tags/batman-0.3/linux/route.c   

(上面这个链接主要是用来实现添加/删除路由的程序的模块,没有这个源程序我也无从下手,大部分代码是从这个文件上面拷贝下来的)

3,需要注意的地方

      rtmsg结构体中的rtm_dst_len代表的是目的网络或目的主机掩码的位数,我以前总是以为是ip地址长度所以就填4,这是不对的,同理rtm_src_len也是一样,不过本程序填0就可以了,添加路由不需要源地址。

      nlmsghdr结构体中的nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK | NLM_F_CREATE | NLM_F_EXCL;如果单填 NLM_F_CREATE好像是不行的添加不了路由。

     我的linux是ubutun9.10,内核是2.6.31,其他linux系统编译是否有问题不清楚了。

4,长话不多说了,就看代码吧:

#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include


typedef __u32 u32;


int addattr_l(struct nlmsghdr *n, int maxlen, int type, void *data, int alen)
{
    int len = RTA_LENGTH(alen);
    struct rtattr *rta;
    if (NLMSG_ALIGN(n->nlmsg_len) + len > maxlen)
        return -1;
    rta = (struct rtattr*)(((char*)n) + NLMSG_ALIGN(n->nlmsg_len));
    rta->rta_type = type;
    rta->rta_len = len;
    memcpy(RTA_DATA(rta), data, alen);
    n->nlmsg_len = NLMSG_ALIGN(n->nlmsg_len) + len;
    fprintf(stderr,"\nattr len=%d\n",n->nlmsg_len);
    return 0;
}


void route_add(int fd, __u32* destination,__u32* gateway,unsigned int netmask)
{
    struct sockaddr_nl nladdr;
    int status;

    __u32 index=2; /* Output Interface ::: eth1,因为我的虚拟机没有eth0,是eth1接口所以是2,lo接口1,不知道其他机器是否有出入*/
    //__u32 source=254;

    // structure of the netlink packet.
    struct
    {
        struct nlmsghdr n;
        struct rtmsg r;
        char buf[1024];
    } req;
    nladdr.nl_family=AF_NETLINK;
    nladdr.nl_pad=0;
    nladdr.nl_pid=0;
    nladdr.nl_groups=0;
    status=bind(fd,(struct sockaddr *)&nladdr,sizeof(nladdr));
    if(status<0){
        perror("bind");
        exit(1);
    }
// Forming the iovector with the netlink packet.
//    struct iovec iov = { (void*)&req.n, req.n.nlmsg_len };

// Forming the message to be sent.
//    struct msghdr msg = { (void*)&nladdr, sizeof(nladdr), &iov, 1, NULL, 0, 0 };


    memset(&req, 0, sizeof(req));

// Initialisation of a few parameters
    memset(&nladdr,0,sizeof(nladdr));
    nladdr.nl_family= AF_NETLINK;
    nladdr.nl_pid=0;
    nladdr.nl_groups=0;

    req.n.nlmsg_len = NLMSG_LENGTH(sizeof(struct rtmsg));
    req.n.nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK | NLM_F_CREATE | NLM_F_EXCL;
    req.n.nlmsg_type = RTM_NEWROUTE;

    req.r.rtm_family = AF_INET;
    req.r.rtm_table = RT_TABLE_MAIN;
    req.r.rtm_protocol = RTPROT_STATIC;
    req.r.rtm_scope = RT_SCOPE_UNIVERSE;
    req.r.rtm_type = RTN_UNICAST;
    req.r.rtm_dst_len=netmask;   //目的网络子网掩码位数
    req.r.rtm_src_len=0;
    req.r.rtm_tos=0;
    req.r.rtm_flags=RT_TABLE_MAIN;


    
    req.n.nlmsg_len = NLMSG_LENGTH(sizeof(struct rtmsg)) ;

// RTA_DST and RTA_GW are the two esential parameters for adding a route,
// there are other parameters too which are not discussed here. For ipv4,
// the length of the address is 4 bytes.
    addattr_l(&req.n, sizeof(req), RTA_DST, destination, 4);
    addattr_l(&req.n, sizeof(req), RTA_GATEWAY, gateway, 4);
    addattr_l(&req.n, sizeof(req), RTA_OIF,&index, 4);


// sending the packet to the kernel.
    status=send(fd,&req,req.n.nlmsg_len,0);
    fprintf(stderr,"\nstatus=%d,添加路由成功\n",status);

}

int main(int argc ,char ** argv)
{
    int fd;
    __u32 dest,gate;  //dest 代表目的网络或主机,gate代表网关;
    if(argc!=4){
        printf("usage:%s 10.168.0.0 24 10.168.3.1\n",argv[0]);
        exit(1);
    }
    if(atoi(argv[2])<0||atoi(argv[2])>32){
        printf("unvalible netmask bits!!must be 0-32\n");
        exit(1);
    }

    if((fd=socket(AF_NETLINK,SOCK_RAW,NETLINK_ROUTE))<0){
        printf("error creating a socket\n");
        exit(1);
    }

    dest=inet_addr(argv[1]); /* unsigned int value for dest Ip address  ,这里的目的网络或主机地址都要转换成网络字节顺序*/
    gate=inet_addr(argv[3]); /* unsigned int value for gateway address ,也要转换成网络字节顺序 */
    route_add(fd,&dest,&gate,(unsigned int)atoi(argv[2]));
    return 0;
}


编译后要用root权限运行。

linux使用 netlink 添加路由简单代码_第1张图片

你可能感兴趣的:(linux网络编程)