10f66f451Sopenharmony_ci/* route.c - Display/edit network routing table. 20f66f451Sopenharmony_ci * 30f66f451Sopenharmony_ci * Copyright 2012 Ranjan Kumar <ranjankumar.bth@gmail.com> 40f66f451Sopenharmony_ci * Copyright 2013 Kyungwan Han <asura321@gmail.com> 50f66f451Sopenharmony_ci * Copyright 2020 Eric Molitor <eric@molitor.org> 60f66f451Sopenharmony_ci * 70f66f451Sopenharmony_ci * No Standard 80f66f451Sopenharmony_ci * 90f66f451Sopenharmony_ci * TODO: autodetect -net -host target dev -A (but complain) 100f66f451Sopenharmony_ci * route add -net target 10.0.0.0 netmask 255.0.0.0 dev eth0 110f66f451Sopenharmony_ci * route del delete 120f66f451Sopenharmony_ci * delete net route, must match netmask, informative error message 130f66f451Sopenharmony_ci * 140f66f451Sopenharmony_ci * mod dyn reinstate metric netmask gw mss window irtt dev 150f66f451Sopenharmony_ci 160f66f451Sopenharmony_ciUSE_ROUTE(NEWTOY(route, "?neA:", TOYFLAG_BIN)) 170f66f451Sopenharmony_ciconfig ROUTE 180f66f451Sopenharmony_ci bool "route" 190f66f451Sopenharmony_ci default n 200f66f451Sopenharmony_ci help 210f66f451Sopenharmony_ci usage: route [-ne] [-A [46]] [add|del TARGET [OPTIONS]] 220f66f451Sopenharmony_ci 230f66f451Sopenharmony_ci Display, add or delete network routes in the "Forwarding Information Base". 240f66f451Sopenharmony_ci 250f66f451Sopenharmony_ci -n Show numerical addresses (no DNS lookups) 260f66f451Sopenharmony_ci -e display netstat fields 270f66f451Sopenharmony_ci 280f66f451Sopenharmony_ci Routing means sending packets out a network interface to an address. 290f66f451Sopenharmony_ci The kernel can tell where to send packets one hop away by examining each 300f66f451Sopenharmony_ci interface's address and netmask, so the most common use of this command 310f66f451Sopenharmony_ci is to identify a "gateway" that forwards other traffic. 320f66f451Sopenharmony_ci 330f66f451Sopenharmony_ci Assigning an address to an interface automatically creates an appropriate 340f66f451Sopenharmony_ci network route ("ifconfig eth0 10.0.2.15/8" does "route add 10.0.0.0/8 eth0" 350f66f451Sopenharmony_ci for you), although some devices (such as loopback) won't show it in the 360f66f451Sopenharmony_ci table. For machines more than one hop away, you need to specify a gateway 370f66f451Sopenharmony_ci (ala "route add default gw 10.0.2.2"). 380f66f451Sopenharmony_ci 390f66f451Sopenharmony_ci The address "default" is a wildcard address (0.0.0.0/0) matching all 400f66f451Sopenharmony_ci packets without a more specific route. 410f66f451Sopenharmony_ci 420f66f451Sopenharmony_ci Available OPTIONS include: 430f66f451Sopenharmony_ci reject - blocking route (force match failure) 440f66f451Sopenharmony_ci dev NAME - force matching packets out this interface (ala "eth0") 450f66f451Sopenharmony_ci netmask - old way of saying things like ADDR/24 460f66f451Sopenharmony_ci gw ADDR - forward packets to gateway ADDR 470f66f451Sopenharmony_ci*/ 480f66f451Sopenharmony_ci 490f66f451Sopenharmony_ci#define FOR_route 500f66f451Sopenharmony_ci#include "toys.h" 510f66f451Sopenharmony_ci#include <net/route.h> 520f66f451Sopenharmony_ci 530f66f451Sopenharmony_ciGLOBALS( 540f66f451Sopenharmony_ci char *family; 550f66f451Sopenharmony_ci) 560f66f451Sopenharmony_ci 570f66f451Sopenharmony_ci#define DEFAULT_PREFIXLEN 128 580f66f451Sopenharmony_ci#define INVALID_ADDR 0xffffffffUL 590f66f451Sopenharmony_ci#define IPV6_ADDR_LEN 40 //32 + 7 (':') + 1 ('\0') 600f66f451Sopenharmony_ci 610f66f451Sopenharmony_cistruct _arglist { 620f66f451Sopenharmony_ci char *arg; 630f66f451Sopenharmony_ci int action; 640f66f451Sopenharmony_ci}; 650f66f451Sopenharmony_ci 660f66f451Sopenharmony_cistatic struct _arglist arglist1[] = { 670f66f451Sopenharmony_ci { "add", 1 }, { "del", 2 }, 680f66f451Sopenharmony_ci { "delete", 2 }, { NULL, 0 } 690f66f451Sopenharmony_ci}; 700f66f451Sopenharmony_ci 710f66f451Sopenharmony_cistatic struct _arglist arglist2[] = { 720f66f451Sopenharmony_ci { "-net", 1 }, { "-host", 2 }, 730f66f451Sopenharmony_ci { NULL, 0 } 740f66f451Sopenharmony_ci}; 750f66f451Sopenharmony_ci 760f66f451Sopenharmony_ci// to get the host name from the given ip. 770f66f451Sopenharmony_cistatic int get_hostname(char *ipstr, struct sockaddr_in *sockin) 780f66f451Sopenharmony_ci{ 790f66f451Sopenharmony_ci struct hostent *host; 800f66f451Sopenharmony_ci 810f66f451Sopenharmony_ci sockin->sin_family = AF_INET; 820f66f451Sopenharmony_ci sockin->sin_port = 0; 830f66f451Sopenharmony_ci 840f66f451Sopenharmony_ci if (!strcmp(ipstr, "default")) { 850f66f451Sopenharmony_ci sockin->sin_addr.s_addr = INADDR_ANY; 860f66f451Sopenharmony_ci return 1; 870f66f451Sopenharmony_ci } 880f66f451Sopenharmony_ci 890f66f451Sopenharmony_ci if (inet_aton(ipstr, &sockin->sin_addr)) return 0; 900f66f451Sopenharmony_ci if (!(host = gethostbyname(ipstr))) perror_exit("resolving '%s'", ipstr); 910f66f451Sopenharmony_ci memcpy(&sockin->sin_addr, host->h_addr_list[0], sizeof(struct in_addr)); 920f66f451Sopenharmony_ci 930f66f451Sopenharmony_ci return 0; 940f66f451Sopenharmony_ci} 950f66f451Sopenharmony_ci 960f66f451Sopenharmony_ci// used to extract the address info from the given ip. 970f66f451Sopenharmony_cistatic int get_addrinfo(char *ip, struct sockaddr_in6 *sock_in6) 980f66f451Sopenharmony_ci{ 990f66f451Sopenharmony_ci struct addrinfo hints, *result; 1000f66f451Sopenharmony_ci int status = 0; 1010f66f451Sopenharmony_ci 1020f66f451Sopenharmony_ci memset(&hints, 0, sizeof(struct addrinfo)); 1030f66f451Sopenharmony_ci hints.ai_family = AF_INET6; 1040f66f451Sopenharmony_ci if ((status = getaddrinfo(ip, NULL, &hints, &result))) { 1050f66f451Sopenharmony_ci perror_msg("getaddrinfo: %s", gai_strerror(status)); 1060f66f451Sopenharmony_ci return -1; 1070f66f451Sopenharmony_ci } 1080f66f451Sopenharmony_ci if (result) { 1090f66f451Sopenharmony_ci memcpy(sock_in6, result->ai_addr, sizeof(*sock_in6)); 1100f66f451Sopenharmony_ci freeaddrinfo(result); 1110f66f451Sopenharmony_ci } 1120f66f451Sopenharmony_ci return 0; 1130f66f451Sopenharmony_ci} 1140f66f451Sopenharmony_ci 1150f66f451Sopenharmony_cistatic void get_flag_value(char *str, int flags) 1160f66f451Sopenharmony_ci{ 1170f66f451Sopenharmony_ci // RTF_* bits in order: 1180f66f451Sopenharmony_ci // UP, GATEWAY, HOST, REINSTATE, DYNAMIC, MODIFIED, DEFAULT, ADDRCONF, CACHE 1190f66f451Sopenharmony_ci int i = 0, mask = 0x105003f; 1200f66f451Sopenharmony_ci 1210f66f451Sopenharmony_ci for (; mask; mask>>=1) if (mask&1) { 1220f66f451Sopenharmony_ci if (flags&(1<<i)) *str++ = "UGHRDMDAC"[i]; 1230f66f451Sopenharmony_ci i++; 1240f66f451Sopenharmony_ci } 1250f66f451Sopenharmony_ci *str = 0; 1260f66f451Sopenharmony_ci} 1270f66f451Sopenharmony_ci 1280f66f451Sopenharmony_ci// extract inet4 route info from /proc/net/route file and display it. 1290f66f451Sopenharmony_cistatic void display_routes(void) 1300f66f451Sopenharmony_ci{ 1310f66f451Sopenharmony_ci unsigned long dest, gate, mask; 1320f66f451Sopenharmony_ci int flags, ref, use, metric, mss, win, irtt, items; 1330f66f451Sopenharmony_ci char iface[64] = {0,}, flag_val[10]; //there are 9 flags "UGHRDMDAC" for route. 1340f66f451Sopenharmony_ci 1350f66f451Sopenharmony_ci FILE *fp = xfopen("/proc/net/route", "r"); 1360f66f451Sopenharmony_ci 1370f66f451Sopenharmony_ci xprintf("Kernel IP routing table\n" 1380f66f451Sopenharmony_ci "Destination Gateway Genmask Flags %s Iface\n", 1390f66f451Sopenharmony_ci (toys.optflags & FLAG_e)? " MSS Window irtt" : "Metric Ref Use"); 1400f66f451Sopenharmony_ci 1410f66f451Sopenharmony_ci if (fscanf(fp, "%*[^\n]\n") < 0) perror_exit("fscanf"); //skip 1st line 1420f66f451Sopenharmony_ci while ((items = fscanf(fp, "%63s%lx%lx%X%d%d%d%lx%d%d%d\n", iface, &dest, 1430f66f451Sopenharmony_ci &gate, &flags, &ref, &use, &metric, &mask, &mss, &win, &irtt)) == 11) 1440f66f451Sopenharmony_ci { 1450f66f451Sopenharmony_ci char *destip = toybuf, *gateip = toybuf+32, *maskip = toybuf+64; //ip string 16 1460f66f451Sopenharmony_ci 1470f66f451Sopenharmony_ci if (!(flags & RTF_UP)) continue; //skip down interfaces. 1480f66f451Sopenharmony_ci 1490f66f451Sopenharmony_ci if (!dest && !(toys.optflags & FLAG_n)) strcpy( destip, "default"); 1500f66f451Sopenharmony_ci else if (!inet_ntop(AF_INET, &dest, destip, 32)) perror_exit("inet"); 1510f66f451Sopenharmony_ci 1520f66f451Sopenharmony_ci if (!gate && !(toys.optflags & FLAG_n)) strcpy( gateip, "*"); 1530f66f451Sopenharmony_ci else if (!inet_ntop(AF_INET, &gate, gateip, 32)) perror_exit("inet"); 1540f66f451Sopenharmony_ci 1550f66f451Sopenharmony_ci if (!inet_ntop(AF_INET, &mask, maskip, 32)) perror_exit("inet"); 1560f66f451Sopenharmony_ci 1570f66f451Sopenharmony_ci //Get flag Values 1580f66f451Sopenharmony_ci get_flag_value(flag_val, flags); 1590f66f451Sopenharmony_ci if (flags & RTF_REJECT) flag_val[0] = '!'; 1600f66f451Sopenharmony_ci xprintf("%-15.15s %-15.15s %-16s%-6s", destip, gateip, maskip, flag_val); 1610f66f451Sopenharmony_ci if (toys.optflags & FLAG_e) xprintf("%5d %-5d %6d %s\n", mss, win, irtt, iface); 1620f66f451Sopenharmony_ci else xprintf("%-6d %-2d %7d %s\n", metric, ref, use, iface); 1630f66f451Sopenharmony_ci } 1640f66f451Sopenharmony_ci 1650f66f451Sopenharmony_ci if (items > 0 && feof(fp)) perror_exit("fscanf %d", items); 1660f66f451Sopenharmony_ci fclose(fp); 1670f66f451Sopenharmony_ci} 1680f66f451Sopenharmony_ci 1690f66f451Sopenharmony_ci/* 1700f66f451Sopenharmony_ci * find the given parameter in list like add/del/net/host. 1710f66f451Sopenharmony_ci * and if match found return the appropriate action. 1720f66f451Sopenharmony_ci */ 1730f66f451Sopenharmony_cistatic int get_action(char ***argv, struct _arglist *list) 1740f66f451Sopenharmony_ci{ 1750f66f451Sopenharmony_ci struct _arglist *alist; 1760f66f451Sopenharmony_ci 1770f66f451Sopenharmony_ci if (!**argv) return 0; 1780f66f451Sopenharmony_ci for (alist = list; alist->arg; alist++) { //find the given parameter in list 1790f66f451Sopenharmony_ci if (!strcmp(**argv, alist->arg)) { 1800f66f451Sopenharmony_ci *argv += 1; 1810f66f451Sopenharmony_ci return alist->action; 1820f66f451Sopenharmony_ci } 1830f66f451Sopenharmony_ci } 1840f66f451Sopenharmony_ci return 0; 1850f66f451Sopenharmony_ci} 1860f66f451Sopenharmony_ci 1870f66f451Sopenharmony_ci/* 1880f66f451Sopenharmony_ci * used to get the params like: metric, netmask, gw, mss, window, irtt, dev and their values. 1890f66f451Sopenharmony_ci * additionally set the flag values for reject, mod, dyn and reinstate. 1900f66f451Sopenharmony_ci */ 1910f66f451Sopenharmony_cistatic void get_next_params(char **argv, struct rtentry *rt, char **netmask) 1920f66f451Sopenharmony_ci{ 1930f66f451Sopenharmony_ci for (;*argv;argv++) { 1940f66f451Sopenharmony_ci if (!strcmp(*argv, "reject")) rt->rt_flags |= RTF_REJECT; 1950f66f451Sopenharmony_ci else if (!strcmp(*argv, "mod")) rt->rt_flags |= RTF_MODIFIED; 1960f66f451Sopenharmony_ci else if (!strcmp(*argv, "dyn")) rt->rt_flags |= RTF_DYNAMIC; 1970f66f451Sopenharmony_ci else if (!strcmp(*argv, "reinstate")) rt->rt_flags |= RTF_REINSTATE; 1980f66f451Sopenharmony_ci else { 1990f66f451Sopenharmony_ci if (!argv[1]) help_exit(0); 2000f66f451Sopenharmony_ci 2010f66f451Sopenharmony_ci //set the metric field in the routing table. 2020f66f451Sopenharmony_ci if (!strcmp(*argv, "metric")) 2030f66f451Sopenharmony_ci rt->rt_metric = atolx_range(argv[1], 0, ULONG_MAX) + 1; 2040f66f451Sopenharmony_ci else if (!strcmp(*argv, "netmask")) { 2050f66f451Sopenharmony_ci //when adding a network route, the netmask to be used. 2060f66f451Sopenharmony_ci struct sockaddr sock; 2070f66f451Sopenharmony_ci unsigned int addr_mask = (((struct sockaddr_in *)&((rt)->rt_genmask))->sin_addr.s_addr); 2080f66f451Sopenharmony_ci 2090f66f451Sopenharmony_ci if (addr_mask) help_exit("dup netmask"); 2100f66f451Sopenharmony_ci *netmask = argv[1]; 2110f66f451Sopenharmony_ci get_hostname(*netmask, (struct sockaddr_in *) &sock); 2120f66f451Sopenharmony_ci rt->rt_genmask = sock; 2130f66f451Sopenharmony_ci } else if (!strcmp(*argv, "gw")) { 2140f66f451Sopenharmony_ci //route packets via a gateway. 2150f66f451Sopenharmony_ci if (!(rt->rt_flags & RTF_GATEWAY)) { 2160f66f451Sopenharmony_ci if (!get_hostname(argv[1], (struct sockaddr_in *) &rt->rt_gateway)) 2170f66f451Sopenharmony_ci rt->rt_flags |= RTF_GATEWAY; 2180f66f451Sopenharmony_ci else perror_exit("gateway '%s' is a NETWORK", argv[1]); 2190f66f451Sopenharmony_ci } else help_exit("dup gw"); 2200f66f451Sopenharmony_ci } else if (!strcmp(*argv, "mss")) { 2210f66f451Sopenharmony_ci //set the TCP Maximum Segment Size for connections over this route. 2220f66f451Sopenharmony_ci rt->rt_mtu = atolx_range(argv[1], 64, 65536); 2230f66f451Sopenharmony_ci rt->rt_flags |= RTF_MSS; 2240f66f451Sopenharmony_ci } else if (!strcmp(*argv, "window")) { 2250f66f451Sopenharmony_ci //set the TCP window size for connections over this route to W bytes. 2260f66f451Sopenharmony_ci rt->rt_window = atolx_range(argv[1], 128, INT_MAX); //win low 2270f66f451Sopenharmony_ci rt->rt_flags |= RTF_WINDOW; 2280f66f451Sopenharmony_ci } else if (!strcmp(*argv, "irtt")) { 2290f66f451Sopenharmony_ci rt->rt_irtt = atolx_range(argv[1], 0, INT_MAX); 2300f66f451Sopenharmony_ci rt->rt_flags |= RTF_IRTT; 2310f66f451Sopenharmony_ci } else if (!strcmp(*argv, "dev") && !rt->rt_dev) rt->rt_dev = argv[1]; 2320f66f451Sopenharmony_ci else help_exit("no '%s'", *argv); 2330f66f451Sopenharmony_ci argv++; 2340f66f451Sopenharmony_ci } 2350f66f451Sopenharmony_ci } 2360f66f451Sopenharmony_ci 2370f66f451Sopenharmony_ci if (!rt->rt_dev && (rt->rt_flags & RTF_REJECT)) rt->rt_dev = (char *)"lo"; 2380f66f451Sopenharmony_ci} 2390f66f451Sopenharmony_ci 2400f66f451Sopenharmony_ci// verify the netmask and conflict in netmask and route address. 2410f66f451Sopenharmony_cistatic void verify_netmask(struct rtentry *rt, char *netmask) 2420f66f451Sopenharmony_ci{ 2430f66f451Sopenharmony_ci unsigned int addr_mask = (((struct sockaddr_in *)&((rt)->rt_genmask))->sin_addr.s_addr); 2440f66f451Sopenharmony_ci unsigned int router_addr = ~(unsigned int)(((struct sockaddr_in *)&((rt)->rt_dst))->sin_addr.s_addr); 2450f66f451Sopenharmony_ci 2460f66f451Sopenharmony_ci if (addr_mask) { 2470f66f451Sopenharmony_ci addr_mask = ~ntohl(addr_mask); 2480f66f451Sopenharmony_ci if ((rt->rt_flags & RTF_HOST) && addr_mask != INVALID_ADDR) 2490f66f451Sopenharmony_ci perror_exit("conflicting netmask and host route"); 2500f66f451Sopenharmony_ci if (addr_mask & (addr_mask + 1)) perror_exit("wrong netmask '%s'", netmask); 2510f66f451Sopenharmony_ci addr_mask = ((struct sockaddr_in *) &rt->rt_dst)->sin_addr.s_addr; 2520f66f451Sopenharmony_ci if (addr_mask & router_addr) perror_exit("conflicting netmask and route address"); 2530f66f451Sopenharmony_ci } 2540f66f451Sopenharmony_ci} 2550f66f451Sopenharmony_ci 2560f66f451Sopenharmony_ci// add/del a route. 2570f66f451Sopenharmony_cistatic void setroute(char **argv) 2580f66f451Sopenharmony_ci{ 2590f66f451Sopenharmony_ci struct rtentry rt; 2600f66f451Sopenharmony_ci char *netmask, *targetip; 2610f66f451Sopenharmony_ci int is_net_or_host = 0, sokfd, arg2_action; 2620f66f451Sopenharmony_ci int action = get_action(&argv, arglist1); //verify the arg for add/del. 2630f66f451Sopenharmony_ci 2640f66f451Sopenharmony_ci if (!action || !*argv) help_exit("setroute"); 2650f66f451Sopenharmony_ci 2660f66f451Sopenharmony_ci arg2_action = get_action(&argv, arglist2); //verify the arg for -net or -host 2670f66f451Sopenharmony_ci if (!*argv) help_exit("setroute"); 2680f66f451Sopenharmony_ci 2690f66f451Sopenharmony_ci memset(&rt, 0, sizeof(struct rtentry)); 2700f66f451Sopenharmony_ci targetip = *argv++; 2710f66f451Sopenharmony_ci 2720f66f451Sopenharmony_ci netmask = strchr(targetip, '/'); 2730f66f451Sopenharmony_ci if (netmask) { 2740f66f451Sopenharmony_ci *netmask++ = 0; 2750f66f451Sopenharmony_ci //used to verify the netmask and route conflict. 2760f66f451Sopenharmony_ci (((struct sockaddr_in *)&rt.rt_genmask)->sin_addr.s_addr) 2770f66f451Sopenharmony_ci = htonl((1<<(32-atolx_range(netmask, 0, 32)))-1); 2780f66f451Sopenharmony_ci rt.rt_genmask.sa_family = AF_INET; 2790f66f451Sopenharmony_ci netmask = 0; 2800f66f451Sopenharmony_ci } else netmask = "default"; 2810f66f451Sopenharmony_ci 2820f66f451Sopenharmony_ci is_net_or_host = get_hostname(targetip, (void *)&rt.rt_dst); 2830f66f451Sopenharmony_ci 2840f66f451Sopenharmony_ci if (arg2_action) is_net_or_host = arg2_action & 1; 2850f66f451Sopenharmony_ci rt.rt_flags = ((is_net_or_host) ? RTF_UP : (RTF_UP | RTF_HOST)); 2860f66f451Sopenharmony_ci 2870f66f451Sopenharmony_ci get_next_params(argv, &rt, (char **)&netmask); 2880f66f451Sopenharmony_ci verify_netmask(&rt, (char *)netmask); 2890f66f451Sopenharmony_ci 2900f66f451Sopenharmony_ci if ((action == 1) && (rt.rt_flags & RTF_HOST)) 2910f66f451Sopenharmony_ci (((struct sockaddr_in *)&((rt).rt_genmask))->sin_addr.s_addr) = INVALID_ADDR; 2920f66f451Sopenharmony_ci 2930f66f451Sopenharmony_ci sokfd = xsocket(AF_INET, SOCK_DGRAM, 0); 2940f66f451Sopenharmony_ci if (action == 1) xioctl(sokfd, SIOCADDRT, &rt); 2950f66f451Sopenharmony_ci else xioctl(sokfd, SIOCDELRT, &rt); 2960f66f451Sopenharmony_ci xclose(sokfd); 2970f66f451Sopenharmony_ci} 2980f66f451Sopenharmony_ci 2990f66f451Sopenharmony_ci/* 3000f66f451Sopenharmony_ci * get prefix len (if any) and remove the prefix from target ip. 3010f66f451Sopenharmony_ci * if no prefix then set default prefix len. 3020f66f451Sopenharmony_ci */ 3030f66f451Sopenharmony_cistatic void is_prefix_inet6(char **tip, struct in6_rtmsg *rt) 3040f66f451Sopenharmony_ci{ 3050f66f451Sopenharmony_ci unsigned long plen; 3060f66f451Sopenharmony_ci char *prefix = strchr(*tip, '/'); 3070f66f451Sopenharmony_ci 3080f66f451Sopenharmony_ci if (prefix) { 3090f66f451Sopenharmony_ci *prefix = '\0'; 3100f66f451Sopenharmony_ci plen = atolx_range(prefix + 1, 0, 128); //DEFAULT_PREFIXLEN); 3110f66f451Sopenharmony_ci } else plen = DEFAULT_PREFIXLEN; 3120f66f451Sopenharmony_ci 3130f66f451Sopenharmony_ci rt->rtmsg_flags = (plen == DEFAULT_PREFIXLEN) ? (RTF_UP | RTF_HOST) : RTF_UP; 3140f66f451Sopenharmony_ci rt->rtmsg_dst_len = plen; 3150f66f451Sopenharmony_ci} 3160f66f451Sopenharmony_ci 3170f66f451Sopenharmony_ci/* 3180f66f451Sopenharmony_ci * used to get the params like: metric, gw, dev and their values. 3190f66f451Sopenharmony_ci * additionally set the flag values for mod and dyn. 3200f66f451Sopenharmony_ci */ 3210f66f451Sopenharmony_cistatic void get_next_params_inet6(char **argv, struct sockaddr_in6 *sock_in6, struct in6_rtmsg *rt, char **dev_name) 3220f66f451Sopenharmony_ci{ 3230f66f451Sopenharmony_ci for (;*argv;argv++) { 3240f66f451Sopenharmony_ci if (!strcmp(*argv, "mod")) rt->rtmsg_flags |= RTF_MODIFIED; 3250f66f451Sopenharmony_ci else if (!strcmp(*argv, "dyn")) rt->rtmsg_flags |= RTF_DYNAMIC; 3260f66f451Sopenharmony_ci else { 3270f66f451Sopenharmony_ci if (!argv[1]) help_exit(0); 3280f66f451Sopenharmony_ci 3290f66f451Sopenharmony_ci if (!strcmp(*argv, "metric")) 3300f66f451Sopenharmony_ci rt->rtmsg_metric = atolx_range(argv[1], 0, ULONG_MAX); 3310f66f451Sopenharmony_ci else if (!strcmp(*argv, "gw")) { 3320f66f451Sopenharmony_ci //route packets via a gateway. 3330f66f451Sopenharmony_ci if (!(rt->rtmsg_flags & RTF_GATEWAY)) { 3340f66f451Sopenharmony_ci if (!get_addrinfo(argv[1], (struct sockaddr_in6 *) &sock_in6)) { 3350f66f451Sopenharmony_ci memcpy(&rt->rtmsg_gateway, sock_in6->sin6_addr.s6_addr, sizeof(struct in6_addr)); 3360f66f451Sopenharmony_ci rt->rtmsg_flags |= RTF_GATEWAY; 3370f66f451Sopenharmony_ci } else perror_exit("resolving '%s'", argv[1]); 3380f66f451Sopenharmony_ci } else help_exit(0); 3390f66f451Sopenharmony_ci } else if (!strcmp(*argv, "dev")) { 3400f66f451Sopenharmony_ci if (!*dev_name) *dev_name = argv[1]; 3410f66f451Sopenharmony_ci } else help_exit(0); 3420f66f451Sopenharmony_ci argv++; 3430f66f451Sopenharmony_ci } 3440f66f451Sopenharmony_ci } 3450f66f451Sopenharmony_ci} 3460f66f451Sopenharmony_ci 3470f66f451Sopenharmony_ci// add/del a route. 3480f66f451Sopenharmony_cistatic void setroute_inet6(char **argv) 3490f66f451Sopenharmony_ci{ 3500f66f451Sopenharmony_ci struct sockaddr_in6 sock_in6; 3510f66f451Sopenharmony_ci struct in6_rtmsg rt; 3520f66f451Sopenharmony_ci char *targetip, *dev_name = 0; 3530f66f451Sopenharmony_ci int sockfd, action = get_action(&argv, arglist1); 3540f66f451Sopenharmony_ci 3550f66f451Sopenharmony_ci if (!action || !*argv) help_exit(0); 3560f66f451Sopenharmony_ci memset(&sock_in6, 0, sizeof(struct sockaddr_in6)); 3570f66f451Sopenharmony_ci memset(&rt, 0, sizeof(struct in6_rtmsg)); 3580f66f451Sopenharmony_ci targetip = *argv++; 3590f66f451Sopenharmony_ci if (!*argv) help_exit(0); 3600f66f451Sopenharmony_ci 3610f66f451Sopenharmony_ci if (!strcmp(targetip, "default")) { 3620f66f451Sopenharmony_ci rt.rtmsg_flags = RTF_UP; 3630f66f451Sopenharmony_ci rt.rtmsg_dst_len = 0; 3640f66f451Sopenharmony_ci } else { 3650f66f451Sopenharmony_ci is_prefix_inet6((char **)&targetip, &rt); 3660f66f451Sopenharmony_ci if (get_addrinfo(targetip, (struct sockaddr_in6 *) &sock_in6)) 3670f66f451Sopenharmony_ci perror_exit("resolving '%s'", targetip); 3680f66f451Sopenharmony_ci } 3690f66f451Sopenharmony_ci rt.rtmsg_metric = 1; //default metric. 3700f66f451Sopenharmony_ci memcpy(&rt.rtmsg_dst, sock_in6.sin6_addr.s6_addr, sizeof(struct in6_addr)); 3710f66f451Sopenharmony_ci get_next_params_inet6(argv, &sock_in6, &rt, (char **)&dev_name); 3720f66f451Sopenharmony_ci 3730f66f451Sopenharmony_ci sockfd = xsocket(AF_INET6, SOCK_DGRAM, 0); 3740f66f451Sopenharmony_ci if (dev_name) { 3750f66f451Sopenharmony_ci char ifre_buf[sizeof(struct ifreq)] = {0,}; 3760f66f451Sopenharmony_ci struct ifreq *ifre = (struct ifreq*)ifre_buf; 3770f66f451Sopenharmony_ci xstrncpy(ifre->ifr_name, dev_name, IFNAMSIZ); 3780f66f451Sopenharmony_ci xioctl(sockfd, SIOGIFINDEX, ifre); 3790f66f451Sopenharmony_ci rt.rtmsg_ifindex = ifre->ifr_ifindex; 3800f66f451Sopenharmony_ci } 3810f66f451Sopenharmony_ci if (action == 1) xioctl(sockfd, SIOCADDRT, &rt); 3820f66f451Sopenharmony_ci else xioctl(sockfd, SIOCDELRT, &rt); 3830f66f451Sopenharmony_ci xclose(sockfd); 3840f66f451Sopenharmony_ci} 3850f66f451Sopenharmony_ci 3860f66f451Sopenharmony_ci/* 3870f66f451Sopenharmony_ci * format the dest and src address in ipv6 format. 3880f66f451Sopenharmony_ci * e.g. 2002:6b6d:26c8:d:ea03:9aff:fe65:9d62 3890f66f451Sopenharmony_ci */ 3900f66f451Sopenharmony_cistatic void ipv6_addr_formating(char *ptr, char *addr) 3910f66f451Sopenharmony_ci{ 3920f66f451Sopenharmony_ci int i = 0; 3930f66f451Sopenharmony_ci while (i <= IPV6_ADDR_LEN) { 3940f66f451Sopenharmony_ci if (!*ptr) { 3950f66f451Sopenharmony_ci if (i == IPV6_ADDR_LEN) { 3960f66f451Sopenharmony_ci addr[IPV6_ADDR_LEN - 1] = 0; //NULL terminating the ':' separated address. 3970f66f451Sopenharmony_ci break; 3980f66f451Sopenharmony_ci } 3990f66f451Sopenharmony_ci error_exit("IPv6 ip format error"); 4000f66f451Sopenharmony_ci } 4010f66f451Sopenharmony_ci addr[i++] = *ptr++; 4020f66f451Sopenharmony_ci if (!((i+1) % 5)) addr[i++] = ':'; //put ':' after 4th bit 4030f66f451Sopenharmony_ci } 4040f66f451Sopenharmony_ci} 4050f66f451Sopenharmony_ci 4060f66f451Sopenharmony_cistatic void display_routes6(void) 4070f66f451Sopenharmony_ci{ 4080f66f451Sopenharmony_ci char iface[16] = {0,}, ipv6_dest_addr[41]; 4090f66f451Sopenharmony_ci char ipv6_src_addr[41], flag_val[10], buf2[INET6_ADDRSTRLEN]; 4100f66f451Sopenharmony_ci int prefixlen, metric, use, refcount, flag, items = 0; 4110f66f451Sopenharmony_ci unsigned char buf[sizeof(struct in6_addr)]; 4120f66f451Sopenharmony_ci 4130f66f451Sopenharmony_ci FILE *fp = xfopen("/proc/net/ipv6_route", "r"); 4140f66f451Sopenharmony_ci 4150f66f451Sopenharmony_ci xprintf("Kernel IPv6 routing table\n" 4160f66f451Sopenharmony_ci "%-43s%-40s Flags Metric Ref Use Iface\n", "Destination", "Next Hop"); 4170f66f451Sopenharmony_ci 4180f66f451Sopenharmony_ci while ((items = fscanf(fp, "%32s%x%*s%*x%32s%x%x%x%x%15s\n", ipv6_dest_addr+8, 4190f66f451Sopenharmony_ci &prefixlen, ipv6_src_addr+8, &metric, &use, &refcount, &flag, 4200f66f451Sopenharmony_ci iface)) == 8) 4210f66f451Sopenharmony_ci { 4220f66f451Sopenharmony_ci if (!(flag & RTF_UP)) continue; //skip down interfaces. 4230f66f451Sopenharmony_ci 4240f66f451Sopenharmony_ci //ipv6_dest_addr+8: as the values are filled from the 8th location of the array. 4250f66f451Sopenharmony_ci ipv6_addr_formating(ipv6_dest_addr+8, ipv6_dest_addr); 4260f66f451Sopenharmony_ci ipv6_addr_formating(ipv6_src_addr+8, ipv6_src_addr); 4270f66f451Sopenharmony_ci 4280f66f451Sopenharmony_ci get_flag_value(flag_val, flag); 4290f66f451Sopenharmony_ci if (inet_pton(AF_INET6, ipv6_dest_addr, buf) <= 0) perror_exit("inet"); 4300f66f451Sopenharmony_ci if (inet_ntop(AF_INET6, buf, buf2, INET6_ADDRSTRLEN)) 4310f66f451Sopenharmony_ci sprintf(toybuf, "%s/%d", buf2, prefixlen); 4320f66f451Sopenharmony_ci 4330f66f451Sopenharmony_ci if (inet_pton(AF_INET6, ipv6_src_addr, buf) <= 0) perror_exit("inet"); 4340f66f451Sopenharmony_ci if (inet_ntop(AF_INET6, buf, buf2, INET6_ADDRSTRLEN)) 4350f66f451Sopenharmony_ci xprintf("%-43s %-39s %-5s %-6d %-4d %5d %-8s\n", 4360f66f451Sopenharmony_ci toybuf, buf2, flag_val, metric, refcount, use, iface); 4370f66f451Sopenharmony_ci } 4380f66f451Sopenharmony_ci if ((items > 0) && feof(fp)) perror_exit("fscanf"); 4390f66f451Sopenharmony_ci 4400f66f451Sopenharmony_ci fclose(fp); 4410f66f451Sopenharmony_ci} 4420f66f451Sopenharmony_ci 4430f66f451Sopenharmony_civoid route_main(void) 4440f66f451Sopenharmony_ci{ 4450f66f451Sopenharmony_ci if (!TT.family) TT.family = "inet"; 4460f66f451Sopenharmony_ci if (!*toys.optargs) { 4470f66f451Sopenharmony_ci if (!strcmp(TT.family, "inet")) display_routes(); 4480f66f451Sopenharmony_ci else if (!strcmp(TT.family, "inet6")) display_routes6(); 4490f66f451Sopenharmony_ci else help_exit(0); 4500f66f451Sopenharmony_ci } else { 4510f66f451Sopenharmony_ci if (!strcmp(TT.family, "inet6")) setroute_inet6(toys.optargs); 4520f66f451Sopenharmony_ci else setroute(toys.optargs); 4530f66f451Sopenharmony_ci } 4540f66f451Sopenharmony_ci} 455