linux route 实现

本文详细介绍了如何使用Linux下的route命令来设置静态路由表,包括IPv4和IPv6路由的添加与删除操作。通过具体的命令实例展示了如何配置目标地址、子网掩码、网关以及设备接口等关键参数。

http://www.cnblogs.com/wangshide/archive/2012/10/25/2740410.html

linux route 实现

  1. 实现前的准备工作

我们首先应该知道可以用 route, ip 命令来设置系统的静态路由表。

route # <== 查看路由表

Destination Gateway Genmask Flags Metric Ref Use Iface
10.0.0.0 * 255.255.255.0 U 1 0 0 eth0
link-local * 255.255.0.0 U 1000 0 0 eth0
default RTA1025W.home 0.0.0.0 UG 0 0 0 eth0

First entry tell you the following:

Any traffic with destination 10.0.0.0 will not be using a gateway (thats the * on the line), will be using a 255.255.255.0 net mask, route is UP (that's the meaning of the U) and which interface the route uses. IF you do ifconfig -a you will probably see that your eth0 IP address is within the 10.0.0.0 range, so this is you local network route.

Third entry tells you the following:

If any traffic does not fit the traffic defined on any other rules then use this route. Imagine you want to visit www.yahoo.com, the address will be translated (I don't know what is the result address but its not in the 10.0.0.0 range for sure), because it wont fit on the 1st and the 2nd route it will be routed using the RTA1025W.home gateway, the metric will not mather and it will be using the interface defined on the default route line.

Q: Great, thanks! One more: if I send a datagram to a computer in my network, doesn’t it have to go through the router? If so, isn’t it using a gateway? Thanks

A: You router is your gateway in your route table, is your router not RTA1025W?

Q: Yes it is. So when two computers in my home network communicate, they have to go through the router right? I’m asking because for the first rule it is not defined as a gateway. Maybe its a gateway only when it is used to send information outside of the network?

A: Yeah, but the first rule tells your system that if the address translate from a hostname fits the first line (so all 10.0.0.0 addresses you can create with a netmask of 255.255.255.0), will not be routed to a gateway, that way your computers can communicate with each other without having to pass on the router (you can actually turn it off and your computers can contact each other).
1.1 查看一个命令的系统调用过程

  root # strace route …

  rout # strace ip …

  通过上面的命令可以看到,route命令主要使用了 ioctl() 函数来设置路由,而ip命令主要使用了 ioctl(), recvmsg(), sendmsg()等函数。为什么不用ioctl()来统一设置呢?这是一个问题。
1.2 获取源码

  root # route –version
  net-tools 1.60

route命令来自 net-tools 1.60 源码包:net-tools 1.60下载

  root@fs000:~# ip -V
  ip utility, iproute2-ss051107

ip命令来自 iproute2 源码包:iproute2 下载
1.3 学习源码

  1. 数据结构
    复制代码

/* This structure gets passed by the SIOCADDRT and SIOCDELRT calls. */
struct rtentry

/* Structure describing an Internet socket address. */
struct sockaddr_in

/* ipv6 route struct */
struct in6_rtmsg rt;

/* for IPv6. */
struct sockaddr_in6

/* interface request struct */
struct ifreq

复制代码

  1. ioctl() 函数

      其主要功能与参数可以参考:Linux 网络编程之ioctl函数

    1. 代码实现
      复制代码

/*
* author: wangsd
* description: setting the static route
* copyright: GPL
* history:
* 2012.10.31 1.0 version ipv4/ipv6 route add/del
*/

include

include

include

include

include

include

include

include

include

include

include

include

define RTACTION_ADD 1 /* add action */

define RTACTION_DEL 2 /* del action */

void usage();
int inet_setroute(int action, char **args);
int inet6_setroute(int action, char **args);

/* main function */
int main(int argc, char **argv)
{
int action = 0;
if(argc < 5)
{
usage();
return -1;
}
if(strcmp(argv[1], “-A”))
{
usage();
return -1;
}

if(!strcmp(argv[3], "add"))
{
    action = RTACTION_ADD;
}
if(!strcmp(argv[3], "del"))
{
    action = RTACTION_DEL;
}

/* add or del a ipv4 route item */
if(!strcmp(argv[2], "inet"))
{
    inet_setroute(action, argv+4);
}
/* add  or del a ipv6 route item */
if(!strcmp(argv[2], "inet6"))
{
    inet6_setroute(action, argv+4);
}
return 0;

}

/* print usage information */
void usage()
{
printf(“IPv4 Command: route -A inet add/del -net/-host TARGET netmask ”
“NETMASK gw GETWAY dev DEVICE mtu MTU\n”);
printf(“IPv6 Command: route -A inet6 add/del -net TARGET/PREFIX ”
“gw GETWAY dev DEVICE mtu MTU\n”);
return ;
}

/*
* IPv4 add/del route item in route table
*/
int inet_setroute(int action, char **args)
{
struct rtentry route; /* route item struct */
char target[128] = {0};
char gateway[128] = {0};
char netmask[128] = {0};

struct sockaddr_in *addr;

int skfd;

/* clear route struct by 0 */
memset((char *)&route, 0x00, sizeof(route));

/* default target is net (host)*/
route.rt_flags = RTF_UP ;

args++;
while(args)
{
    if(*args == NULL)
    {
        break;
    }
    if(!strcmp(*args, "-net"))
    {/* default is a network target */
        args++;
        strcpy(target, *args);
        addr = (struct sockaddr_in*) &route.rt_dst;
        addr->sin_family = AF_INET;
        addr->sin_addr.s_addr = inet_addr(target);
        args++;
        continue;
    }
    else if(!strcmp(*args, "-host"))
    {/* target is a host */
        args++;
        strcpy(target, *args);
        addr = (struct sockaddr_in*) &route.rt_dst;
        addr->sin_family = AF_INET;
        addr->sin_addr.s_addr = inet_addr(target);
        route.rt_flags |= RTF_HOST;
        args++;
        continue;
    }
    else
    {
        usage();
        return -1;
    }
    if(!strcmp(*args, "netmask"))
    {/* netmask setting */
        args++;
        strcpy(netmask, *args);
        addr = (struct sockaddr_in*) &route.rt_genmask;
        addr->sin_family = AF_INET;
        addr->sin_addr.s_addr = inet_addr(netmask);
        args++;
        continue;
    }
    if(!strcmp(*args, "gw") || !strcmp(*args, "gateway"))
    {/* gateway setting */
        args++;
        strcpy(gateway, *args);
        addr = (struct sockaddr_in*) &route.rt_gateway;
        addr->sin_family = AF_INET;
        addr->sin_addr.s_addr = inet_addr(gateway);
        route.rt_flags |= RTF_GATEWAY;
        args++;
        continue;
    }
    if(!strcmp(*args, "device") || !strcmp(*args, "dev"))
    {/* device setting */
        args++;
        route.rt_dev = *args;
        args++;
        continue;
    }
    if(!strcmp(*args, "mtu"))
    {/* mtu setting */
        args++;
        route.rt_flags |= RTF_MTU;
        route.rt_mtu = atoi(*args);
        args++;
        continue;
    }
    /* if you have other options, please put them in this place,
      like the options above. */
}

/* create a socket */
skfd = socket(AF_INET, SOCK_DGRAM, 0);
if(skfd < 0)
{
    perror("socket");
    return -1;
}

/* tell the kernel to accept this route */
if(action == RTACTION_DEL)
{/* del a route item */
    if(ioctl(skfd, SIOCDELRT, &route) < 0)
    {
        perror("SIOCDELRT");
        close(skfd);
        return -1;
    }
}
else
{/* add a route item */
    if(ioctl(skfd, SIOCADDRT, &route) < 0)
    {
        perror("SIOCADDRT");
        close(skfd);
        return -1;
    }
}
(void) close(skfd);
return 0;

}

int INET6_resolve(char *name, struct sockaddr_in6 *sin6);
int INET6_input(int type, char *bufp, struct sockaddr *sap);
int INET6_getsock(char *bufp, struct sockaddr *sap);

/* IPv6 add/del route item in route table */
/* main part of this function is from net-tools inet6_sr.c file */
int inet6_setroute(int action, char **args)
{
struct in6_rtmsg rt; /* ipv6 route struct */
struct ifreq ifr; /* interface request struct */
struct sockaddr_in6 sa6; /* ipv6 socket address */
char target[128];
char gateway[128] = “NONE”;
int metric;
int prefix_len; /* network prefix length */
char devname = NULL; / device name */
char *cp;
int mtu = 0;

int skfd = -1;

if (*args == NULL )
{
    usage();
    return -1;
}

args++;
strcpy(target, *args);

if (!strcmp(target, "default"))
{
    prefix_len = 0;
    memset(&sa6, 0, sizeof(sa6));
} else
{
    if ((cp = strchr(target, '/')))
    {
        prefix_len = atol(cp + 1);
        if ((prefix_len < 0) || (prefix_len > 128))
            usage();
        *cp = 0;
    } else
    {
        prefix_len = 128;
    }
    if (INET6_input(1, target, (struct sockaddr *) &sa6) < 0
            && INET6_input(0, target, (struct sockaddr *) &sa6) < 0)
    {
        return (1);
    }
}

/* Clean out the RTREQ structure. */
memset((char *) &rt, 0, sizeof(struct in6_rtmsg));

memcpy(&rt.rtmsg_dst, sa6.sin6_addr.s6_addr, sizeof(struct in6_addr));

/* Fill in the other fields. */
rt.rtmsg_flags = RTF_UP;
if (prefix_len == 128)
    rt.rtmsg_flags |= RTF_HOST;
rt.rtmsg_metric = 1;
rt.rtmsg_dst_len = prefix_len;

args++;
while (*args)
 {
     if (!strcmp(*args, "metric"))
     {
         args++;
         if (!*args || !isdigit(**args))
         {
             usage();
             return -1;
         }
         metric = atoi(*args);
         rt.rtmsg_metric = metric;
         args++;
         continue;
     }
     if (!strcmp(*args, "gw") || !strcmp(*args, "gateway"))
     {
         args++;
         if (!*args)
             return -1;
         if (rt.rtmsg_flags & RTF_GATEWAY)
             return -1;
         strcpy(gateway, *args);
         if (INET6_input(1, gateway, (struct sockaddr *) &sa6) < 0)
         {
             return -1;
         }
         memcpy(&rt.rtmsg_gateway, sa6.sin6_addr.s6_addr,
                 sizeof(struct in6_addr));
         rt.rtmsg_flags |= RTF_GATEWAY;
         args++;
         continue;
     }
     if (!strcmp(*args, "mod"))
     {
         args++;
         rt.rtmsg_flags |= RTF_MODIFIED;
         continue;
     }
     if (!strcmp(*args, "dyn"))
     {
         args++;
         rt.rtmsg_flags |= RTF_DYNAMIC;
         continue;
     }
     if (!strcmp(*args, "mtu"))
     {
         args++;
         mtu = atoi(*args);
         args++;
         continue;
     }
     if (!strcmp(*args, "device") || !strcmp(*args, "dev"))
     {
         args++;
         if (!*args)
             return -1;
     } else if (args[1])
         return -1;

     devname = *args;
     args++;
 }

/* Create a socket to the INET6 kernel. */
if ((skfd = socket(AF_INET6, SOCK_DGRAM, 0)) < 0)
{
    perror("socket");
    return -1;
}

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

if (devname)
{/* device setting */
    strcpy(ifr.ifr_name, devname);

    if (ioctl(skfd, SIOGIFINDEX, &ifr) < 0)
    {
        perror("SIOGIFINDEX");
        return -1;
    }
    rt.rtmsg_ifindex = ifr.ifr_ifindex;
}

if (mtu)
{/* mtu setting */
    ifr.ifr_mtu = mtu;

    if (ioctl(skfd, SIOCSIFMTU, &ifr) < 0)
    {
        perror("SIOCGIFMTU");
        return -1;
    }
}

/* Tell the kernel to accept this route. */
if (action == RTACTION_DEL)
{
    if (ioctl(skfd, SIOCDELRT, &rt) < 0)
    {
        perror("SIOCDELRT");
        close(skfd);
        return -1;
    }
} else
{
    if (ioctl(skfd, SIOCADDRT, &rt) < 0)
    {
        perror("SIOCADDRT");
        close(skfd);
        return -1;
    }
}

/* Close the socket. */
(void) close(skfd);
return (0);

}

/*
* following functions are ipv6 address transfrom
* (from string to address struct and so on.)
* these functions from net-tools inet6.c file.
*/

int INET6_resolve(char *name, struct sockaddr_in6 *sin6)
{
struct addrinfo req, *ai;
int s;

memset (&req, '\0', sizeof req);
req.ai_family = AF_INET6;
if ((s = getaddrinfo(name, NULL, &req, &ai))) 
{
    //perror("getaddrinfo");
    fprintf(stderr, "getaddrinfo: %s: %d\n", name, s);
    return -1;
}
memcpy(sin6, ai->ai_addr, sizeof(struct sockaddr_in6));

freeaddrinfo(ai);

return (0);

}
int INET6_getsock(char *bufp, struct sockaddr *sap)
{
struct sockaddr_in6 *sin6;

sin6 = (struct sockaddr_in6 *) sap;
sin6->sin6_family = AF_INET6;
sin6->sin6_port = 0;

if (inet_pton(AF_INET6, bufp, sin6->sin6_addr.s6_addr) <= 0)
return (-1);

return 16;            /* ?;) */

}

int INET6_input(int type, char *bufp, struct sockaddr *sap)
{
switch (type)
{
case 1:
return (INET6_getsock(bufp, sap));
default:
return (INET6_resolve(bufp, (struct sockaddr_in6 *) sap));
}
}

/————————end———————————–/

复制代码
命令投入的例子:

IPv4

my_route -A inet add -net 192.56.76.0 netmask 255.255.255.0 dev eth0
my_route -A inet add -net 192.56.76.0 netmask 255.255.255.0 dev eth0

IPv6

my_route -A inet6 add -net ::/0 dev eth0 mtu 1500
my_route -A inet6 del -net ::/0 dev eth0 mtu 1500

### Linux 中 `route del` 命令的使用 在 Linux 系统中,`route` 是用于管理路由表的一个工具。通过该命令可以查看、添加或删除网络路由条目。其中,`route del` 用于从系统的路由表中移除指定的路由记录。 以下是 `route del` 的基本语法: ```bash route del [-net|-host] target [gw Gw] [metric M] [[dev] If] ``` #### 参数说明 - `-net`: 表示目标是一个网络地址。 - `-host`: 表示目标是一个主机地址。 - `target`: 要删除的目标网络或主机 IP 地址。 - `gw Gw`: 可选参数,表示网关地址。 - `metric M`: 可选参数,表示跃点数。 - `[dev] If`: 指定接口名称。 #### 使用示例 1. **删除特定主机的路由** 删除到主机 `192.168.1.100` 的路由: ```bash route del -host 192.168.1.100 gw 192.168.1.1 dev eth0 ``` 2. **删除整个子网的路由** 删除通往 `192.168.1.0/24` 子网的路由: ```bash route del -net 192.168.1.0 netmask 255.255.255.0 gw 192.168.1.1 dev eth0 ``` 3. **删除默认路由** 如果需要删除当前配置中的默认路由,默认网关为 `192.168.1.1`: ```bash route del default gw 192.168.1.1 ``` 需要注意的是,在现代 Linux 发行版中(如 Ubuntu 16.04 或更高版本),推荐使用更强大的 `ip` 工具来替代传统的 `route` 命令[^1]。例如,可以通过以下方式实现相同功能: ```bash # 删除默认路由 ip route del default via 192.168.1.1 # 删除特定子网路由 ip route del 192.168.1.0/24 via 192.168.1.1 dev eth0 ``` 尽管如此,了解并掌握传统 `route` 命令仍然有助于兼容旧系统环境下的操作需求。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值