Home | History | Annotate | Download | only in pending
      1 /* ip.c - Show / manipulate routing, devices, policy routing and tunnels.
      2  *
      3  * Copyright 2014 Sameer Prakash Pradhan <sameer.p.pradhan (at) gmail.com>
      4  * Copyright 2014 Ranjan Kumar <ranjankumar.bth (at) gmail.com>
      5  * Copyright 2014 Rajni Kant <rajnikant12345 (at) gmail.com>
      6  * Copyright 2014 Bilal Qureshi <bilal.jmi (at) gmail.com>
      7  *
      8  * No Standard.
      9  *
     10 USE_IP(NEWTOY(ip, NULL, TOYFLAG_SBIN))
     11 USE_IP(OLDTOY(ipaddr, ip, TOYFLAG_SBIN))
     12 USE_IP(OLDTOY(iplink, ip, TOYFLAG_SBIN))
     13 USE_IP(OLDTOY(iproute, ip, TOYFLAG_SBIN))
     14 USE_IP(OLDTOY(iprule, ip, TOYFLAG_SBIN))
     15 USE_IP(OLDTOY(iptunnel, ip, TOYFLAG_SBIN))
     16 
     17 config IP
     18   bool "ip"
     19   default n
     20   help
     21     usage: ip [ OPTIONS ] OBJECT { COMMAND }
     22 
     23     Show / manipulate routing, devices, policy routing and tunnels.
     24 
     25     where OBJECT := {address | link | route | rule | tunnel}
     26     OPTIONS := { -f[amily] { inet | inet6 | link } | -o[neline] }
     27 */
     28 #define FOR_ip
     29 #include "toys.h"
     30 #include <linux/netlink.h>
     31 #include <linux/rtnetlink.h>
     32 #include <linux/if_ether.h>
     33 #include <linux/if_addr.h>
     34 #include <net/if_arp.h>
     35 #include <ifaddrs.h>
     36 #include <fnmatch.h>
     37 #include <netinet/ip.h>
     38 #include <linux/if_tunnel.h>
     39 
     40 GLOBALS(
     41   char stats, singleline, flush, *filter_dev, gbuf[8192];
     42   int sockfd, connected, from_ok, route_cmd;
     43   int8_t addressfamily, is_addr;
     44 )
     45 
     46 struct arglist {
     47   char *name;
     48   int idx;
     49 };
     50 
     51 static struct
     52 {
     53   int ifindex, scope, scopemask, up, to;
     54   char *label, *addr;
     55 } addrinfo;
     56 
     57 struct linkdata  {
     58   struct linkdata *next, *prev;
     59   int flags, iface_idx, mtu, txqueuelen, parent,iface_type;
     60   char qdiscpline[IFNAMSIZ+1], state[IFNAMSIZ+1], type[IFNAMSIZ+1],
     61        iface[IFNAMSIZ+1], laddr[64], bcast[64];
     62   struct  rtnl_link_stats rt_stat;
     63 }*linfo;
     64 
     65 typedef int (*cmdobj)(char **argv);
     66 
     67 #define MESG_LEN 8192
     68 
     69 // For "/etc/iproute2/RPDB_tables"
     70 enum {
     71   RPDB_rtdsfield = 1,
     72   RPDB_rtprotos = 2,
     73   RPDB_rtrealms = 3,
     74   RPDB_rtscopes = 4,
     75   RPDB_rttables = 5
     76 };
     77 
     78 #define RPDB_ENTRIES 256
     79 static int8_t rttable_init;
     80 static int8_t rtprotos_init;
     81 static int8_t rtdsfield_init;
     82 static int8_t rtscope_init;
     83 static int8_t rtrealms_init;
     84 
     85 static struct arglist *rt_dsfield[RPDB_ENTRIES];
     86 static struct arglist *rt_protos[RPDB_ENTRIES];
     87 static struct arglist *rt_tables[RPDB_ENTRIES];
     88 static struct arglist *rt_realms[RPDB_ENTRIES];
     89 static struct arglist *rt_scope[RPDB_ENTRIES];
     90 
     91 static struct arglist rtmtypes[] = { {"none", RTN_UNSPEC},
     92   {"unicast", RTN_UNICAST}, {"local", RTN_LOCAL},
     93   {"broadcast", RTN_BROADCAST}, {"anycast", RTN_ANYCAST},
     94   {"multicast", RTN_MULTICAST}, {"blackhole", RTN_BLACKHOLE},
     95   {"unreachable", RTN_UNREACHABLE}, {"prohibit", RTN_PROHIBIT},
     96   {"throw", RTN_THROW}, {"nat", RTN_NAT},
     97   {"xresolve", RTN_XRESOLVE}, {NULL, -1}
     98 };
     99 
    100 static int filter_nlmesg(int (*fun)(struct nlmsghdr *mhdr, char **), char **);
    101 static int  ipaddr_print(struct linkdata *, int flg);
    102 
    103 
    104 // ===========================================================================
    105 // Common Code for IP Options (like: addr, link, route etc.)
    106 // ===========================================================================
    107 static int substring_to_idx(char *str, struct arglist *list)
    108 {
    109   struct arglist *alist;
    110   int len;
    111 
    112   if (!str) return -1;
    113   len = strlen(str);
    114 
    115   for (alist = list; alist->name; alist++)
    116     if (!memcmp(str, alist->name, len)) return alist->idx;
    117   return -1;
    118 }
    119 
    120 static int string_to_idx(char *str, struct arglist *list)
    121 {
    122   struct arglist *alist;
    123 
    124   if (!str) return -1;
    125   for (alist = list; alist->name; alist++)
    126     if (!strcmp(str, alist->name)) return alist->idx;
    127   return -1;
    128 }
    129 
    130 static char *idx_to_string(int idx, struct arglist *list)
    131 {
    132   struct arglist *alist;
    133 
    134   if (idx < 0) return NULL;
    135   for (alist = list; alist->name; alist++)
    136     if (idx == alist->idx) return alist->name;
    137   return NULL;
    138 }
    139 
    140 static void iphelp(void)
    141 {
    142   toys.exithelp = 1;
    143   error_exit(NULL);
    144 }
    145 
    146 static void send_nlmesg(int type, int flags, int family,
    147     void *buf, int blen)
    148 {
    149   struct {
    150     struct nlmsghdr nlh;
    151     struct rtgenmsg g;
    152   } req;
    153 
    154   if (!buf) {
    155     memset(&req, 0, sizeof(req));
    156     req.nlh.nlmsg_len = sizeof(req);
    157     req.nlh.nlmsg_type = type;
    158     req.nlh.nlmsg_flags = flags;
    159     req.g.rtgen_family = family;
    160     buf = &req;
    161     blen = sizeof(req);
    162   }
    163   if (send(TT.sockfd , (void*)buf, blen, 0) < 0)
    164     perror_exit("Unable to send data on socket.");
    165 }
    166 
    167 // Parse /etc/iproute2/RPDB_tables and prepare list.
    168 static void parseRPDB(char *fname, struct arglist **list, int32_t size)
    169 {
    170   char *line;
    171   int fd = open(fname, O_RDONLY);
    172 
    173   if (fd < 0) return;
    174   for (; (line = get_line(fd)); free(line)) {
    175     char *ptr = line;
    176     int32_t idx;
    177 
    178     while (*ptr == ' ' || *ptr == '\t') ptr++;
    179     if (*ptr == 0 || *ptr == '#' || *ptr == '\n') continue;
    180     if ((sscanf(ptr, "0x%x %s\n", &idx, toybuf) != 2) &&
    181         (sscanf(ptr, "0x%x %s #", &idx, toybuf) != 2) &&
    182         (sscanf(ptr, "%d %s\n", &idx, toybuf) != 2) &&
    183         (sscanf(ptr, "%d %s #", &idx, toybuf) != 2)) {
    184       error_msg("Corrupted '%s' file", fname);
    185       xclose(fd);
    186       free(line);
    187       return;
    188     }
    189     if (idx >= 0 && idx < size) {
    190       int index = idx & (size-1);
    191       if (list[index]) free(list[index]->name);
    192       else list[index] = xzalloc(sizeof(struct arglist));
    193       list[index]->idx = idx;
    194       list[index]->name = xstrdup(toybuf);
    195     }
    196   }
    197   xclose(fd);
    198 }
    199 
    200 static void free_alist(struct arglist **list)
    201 {
    202   int i;
    203   for (i = 0;i<RPDB_ENTRIES;i++) {
    204     if (list[i]) {
    205       free(list[i]->name);
    206       free(list[i]);
    207     }
    208   }
    209 }
    210 
    211 static void init_arglist(struct arglist **list,int value, char* name)
    212 {
    213   if (!list[value]) list[value] =  xzalloc(sizeof(struct arglist));
    214   list[value]->idx = value;
    215   list[value]->name = xstrdup(name);
    216 }
    217 
    218 static struct arglist **getlist(u_int8_t whichDB)
    219 {
    220   struct arglist **alist;
    221 
    222   switch (whichDB) {
    223     case RPDB_rtdsfield:
    224       alist = rt_dsfield;
    225       if (!rtdsfield_init) {
    226         rtdsfield_init = 1;
    227         parseRPDB("/etc/iproute2/rt_dsfield", alist, ARRAY_LEN(rt_dsfield));
    228       }
    229       break;
    230     case RPDB_rtprotos:
    231       alist = rt_protos;
    232       if (!rttable_init) {
    233         rtprotos_init = 1;
    234         init_arglist(rt_protos,0,"none");
    235         init_arglist(rt_protos,1,"redirect");
    236         init_arglist(rt_protos,2,"kernel");
    237         init_arglist(rt_protos,3,"boot");
    238         init_arglist(rt_protos,4,"static");
    239         init_arglist(rt_protos,8,"gated");
    240         init_arglist(rt_protos,9,"ra");
    241         init_arglist(rt_protos,10,"mrt");
    242         init_arglist(rt_protos,11,"zebra");
    243         init_arglist(rt_protos,12,"bird");
    244         parseRPDB("/etc/iproute2/rt_protos", alist, ARRAY_LEN(rt_protos));
    245       }
    246       break;
    247     case RPDB_rtrealms:
    248       alist = rt_realms;
    249       if (!rtrealms_init) {
    250         rtrealms_init = 1;
    251         init_arglist(rt_realms,0,"unspec");
    252         parseRPDB("/etc/iproute2/rt_realms", alist, ARRAY_LEN(rt_realms));
    253       }
    254       break;
    255     case RPDB_rtscopes:
    256       alist = rt_scope;
    257       if (!rtscope_init) {
    258         rtscope_init = 1;
    259         init_arglist(rt_scope,0,"global");
    260         init_arglist(rt_scope,200,"site");
    261         init_arglist(rt_scope,253,"link");
    262         init_arglist(rt_scope,254,"host");
    263         init_arglist(rt_scope,255,"nowhere");
    264         parseRPDB("/etc/iproute2/rt_scopes", alist, ARRAY_LEN(rt_scope));
    265       }
    266       break;
    267     case RPDB_rttables:
    268       alist = rt_tables;
    269       if (!rttable_init) {
    270         rttable_init = 1;
    271         init_arglist(rt_tables,RT_TABLE_DEFAULT,"default");
    272         init_arglist(rt_tables,RT_TABLE_MAIN,"main");
    273         init_arglist(rt_tables,RT_TABLE_LOCAL,"local");
    274         parseRPDB("/etc/iproute2/rt_tables", alist, ARRAY_LEN(rt_tables));
    275       }
    276       break;
    277     default:
    278       error_exit("wrong database");
    279       break; // Unreachable code.
    280   }
    281   return alist;
    282 }
    283 
    284 /*
    285  * Parse RPBD tables (if not parsed already).
    286  * return RPDB table name as per idx.
    287  */
    288 static char *namefromRPDB(int idx, u_int8_t whichDB)
    289 {
    290   struct arglist **alist;
    291 
    292   if (idx < 0 || idx >= RPDB_ENTRIES) {
    293     snprintf(toybuf, RPDB_ENTRIES, "%u", idx);
    294     return toybuf;
    295   }
    296 
    297   alist = getlist(whichDB);
    298 
    299   if (alist[idx] && alist[idx]->name) return alist[idx]->name;
    300 
    301   if (whichDB == RPDB_rtdsfield) snprintf(toybuf, RPDB_ENTRIES, "0x%02x", idx);
    302   else snprintf(toybuf, RPDB_ENTRIES, "%u", idx);
    303 
    304   return toybuf;
    305 }
    306 
    307 static int idxfromRPDB(char *name, u_int8_t whichDB)
    308 {
    309   struct arglist **alist;
    310   long i = 0;
    311   char *ptr = NULL;
    312 
    313   for (alist = getlist(whichDB); i < RPDB_ENTRIES; i++) {
    314     if (!alist[i] || !alist[i]->name) continue;
    315     if (!strcmp(alist[i]->name, name)) return i;
    316   }
    317   i = strtol(name, &ptr, 0);
    318   if (errno || (ptr && *ptr) || i < 0 || i > 255)
    319     return -1;
    320   return i;
    321 }
    322 
    323 static char *rtmtype_idx2str(u_int8_t idx)
    324 {
    325   char *name = idx_to_string(idx, rtmtypes);
    326 
    327   if (!name) snprintf(toybuf, RPDB_ENTRIES, "%u", idx);
    328   else snprintf(toybuf, sizeof(toybuf), "%s", name);
    329   return toybuf;
    330 }
    331 
    332 static int rtmtype_str2idx(char *name)
    333 {
    334   int idx = string_to_idx(name, rtmtypes);
    335 
    336   if (idx < 0) return atolx_range(name, 0, 255);
    337   return idx;
    338 }
    339 
    340 /*
    341  * Used to get the prefix value in binary form.
    342  * For IPv4: non-standard parsing used; as 10.10 will be treated as 10.10.0.0
    343  * unlike inet_aton which is 10.0.0.10
    344  */
    345 static int get_prefix(uint32_t *addr, uint8_t *af, char *name, int family)
    346 {
    347   if (family == AF_PACKET) error_exit("'%s' may be inet prefix", name);
    348   if (!memcmp(name, "default", strlen(name))
    349       || !memcmp(name, "all", strlen(name))
    350       || !memcmp(name, "any", strlen(name))) {
    351     *af = family;
    352     return 0;
    353   }
    354   if (strchr(name, ':')) {
    355     *af = AF_INET6;
    356     if (family != AF_UNSPEC && family != AF_INET6) return 1;
    357     if (inet_pton(AF_INET6, name, (void *)addr) != 1)
    358       return 1;
    359   } else { // for IPv4.
    360     char *ptr = name;
    361     uint8_t count = 0;
    362 
    363     *af = AF_INET;
    364     if (family != AF_UNSPEC && family != AF_INET) return 1;
    365     while (*ptr) {
    366       int val, len = 0;
    367 
    368       if (*ptr == '.') ptr++;
    369       sscanf(ptr, "%d%n", &val, &len);
    370       if (!len || len > 3 || val < 0 || val > 255 || count > 3) return 1;
    371       ptr += len;
    372       ((uint8_t*)addr)[count++] = val;
    373     }
    374   }
    375   return 0;
    376 }
    377 
    378 /*
    379  * Used to calculate netmask, which can be in the form of
    380  * either 255.255.255.0 or 24 or default or any or all strings.
    381  */
    382 static int get_nmask_prefix(uint32_t *netmask, uint8_t af,
    383     char *name, uint8_t family)
    384 {
    385   char *ptr;
    386   uint32_t naddr[4] = {0,};
    387   uint64_t plen;
    388   uint8_t naf = AF_UNSPEC;
    389 
    390   *netmask = (af == AF_INET6) ? 128 : 32; // set default netmask
    391   plen = strtoul(name, &ptr, 0);
    392 
    393   if (!ptr || ptr == name || *ptr || !plen || plen > *netmask) {
    394     if (get_prefix(naddr, &naf, name, family)) return -1;
    395     if (naf == AF_INET) {
    396       uint32_t mask = htonl(*naddr), host = ~mask;
    397       if (host & (host + 1)) return -1;
    398       for (plen = 0; mask; mask <<= 1) ++plen;
    399       if (plen > 32) return -1;
    400     }
    401   }
    402   *netmask = plen;
    403   return 0;
    404 }
    405 
    406 /*
    407  * Parse prefix, which will be in form of
    408  * either default or default/default or default/24 or default/255.255.255.0
    409  * or 10.20.30.40 or 10.20.30.40/default or 10.20.30.40/24
    410  * or 10.20.30.40/255.255.255.0
    411  */
    412 static void parse_prefix(uint32_t *addr, uint32_t *netmask, uint8_t *len,
    413     char *name, int family)
    414 {
    415   uint8_t af = AF_UNSPEC;
    416   char *slash = strchr(name, '/');
    417 
    418   if (slash) *slash = 0;
    419   if (get_prefix(addr, &af, name, family)) error_exit("Invalid prefix");
    420 
    421   if (slash) { // grab netmask.
    422     if (get_nmask_prefix(netmask, af, slash+1, family))
    423       error_exit("Invalid prefix");
    424     *slash ='/';
    425   }
    426   else if (af == AF_INET && *addr) *netmask = 32;
    427   else if (af == AF_INET6 && (*addr || *(addr+3))) *netmask = 128;
    428 
    429   if (!*addr && !slash && !af) *len = 0;
    430   else *len = (af == AF_INET6) ? 16 : 4;
    431 }
    432 
    433 static void add_string_to_rtattr(struct nlmsghdr *n, int maxlen,
    434     int type, void *data, int alen)
    435 {
    436   int len = RTA_LENGTH(alen);
    437   struct rtattr *rta;
    438 
    439   if ((int)(NLMSG_ALIGN(n->nlmsg_len) + len) > maxlen) return;
    440   rta = (struct rtattr*)(((char*)n) + NLMSG_ALIGN(n->nlmsg_len));
    441   rta->rta_type = type;
    442   rta->rta_len = len;
    443   memcpy(RTA_DATA(rta), data, alen);
    444   n->nlmsg_len = NLMSG_ALIGN(n->nlmsg_len) + len;
    445 }
    446 
    447 
    448 
    449 // ===========================================================================
    450 // Code for ip link.
    451 // ===========================================================================
    452 #ifndef NLMSG_TAIL
    453 #define NLMSG_TAIL(nmsg) \
    454   ((struct rtattr *) (((void *) (nmsg)) + NLMSG_ALIGN((nmsg)->nlmsg_len)))
    455 #endif
    456 
    457 static uint32_t get_ifaceindex(char *name, int ext)
    458 {
    459   struct if_nameindex *if_ni, *i;
    460   int index = -1;
    461 
    462   if_ni = if_nameindex();
    463   if (!if_ni) perror_exit("if_nameindex");
    464 
    465   for (i = if_ni; i->if_index && i->if_name; i++)
    466     if (!strcmp(name, i->if_name)) {
    467       index = i->if_index;
    468       break;
    469     }
    470   if_freenameindex(if_ni);
    471   if (index == -1 && ext) perror_exit("can't find device '%s'", name);
    472   return index;
    473 }
    474 
    475 static void fill_hwaddr(char *arg, int len, unsigned char *address)
    476 {
    477   int count = 0, val, length;
    478 
    479   while (count < len) {
    480     val = length = 0;
    481     if (!arg) error_exit("bad hw-addr '%s'", "");
    482     if (*arg == ':') arg++, count++;
    483     sscanf(arg, "%2x%n", &val, &length);
    484     if (!length || length > 2)
    485       error_exit("bad hw-addr '%s'", arg);
    486     arg += length;
    487     count += length;
    488     *address++ = val;
    489   }
    490 }
    491 
    492 // Multimach = 1, single match = 0
    493 static char *get_flag_string(struct arglist *aflags, int flags, int ismulti)
    494 {
    495   struct arglist *p = aflags;
    496   char *out = NULL, *tmp = NULL;
    497 
    498   for (; p->name; p++) {
    499     int test = (ismulti ? p->idx & flags : 0) || p->idx == flags;
    500     if (test) { // flags can be zero
    501       tmp = out ? xmprintf("%s,%s", out, p->name) : xmprintf("%s", p->name);
    502       if (out) free(out);
    503       out = tmp;
    504     }
    505   }
    506   return out;
    507 }
    508 
    509 static void vlan_parse_opt(char **argv, struct nlmsghdr *n, unsigned int size)
    510 {
    511   struct arglist vlan_optlist[] = {{"id", 0}, {"protocol", 1},
    512     {"reorder_hdr", 2}, {"gvrp", 3}, {NULL,-1}};
    513   struct arglist vlan_protolist[] = {{"802.1q", 0}, {"802.1ad", 1}, {NULL,-1}};
    514   struct arglist on_off[] = { {"on", 0}, {"off", 1}, {NULL,-1}};
    515   int idx;
    516   struct ifla_vlan_flags flags;
    517 
    518   memset(&flags, 0, sizeof(flags));
    519   for (; *argv; argv++) {
    520     int param, proto;
    521 
    522     if ((idx = substring_to_idx(*argv++, vlan_optlist)) == -1) iphelp();
    523     switch (idx) {
    524       case 0: // ARG_id
    525         if (!*argv) iphelp();
    526         param = atolx(*argv);
    527         add_string_to_rtattr(n, size, IFLA_VLAN_ID, &param, sizeof(param));
    528         break;
    529       case 1: // ARG_protocol
    530         if (!*argv) error_exit("Invalid vlan id.");
    531         if ((idx = substring_to_idx(*argv, vlan_protolist)) == -1) iphelp();
    532         if (!idx) proto = ETH_P_8021Q; // PROTO_8021Q - 0
    533         else if (idx == 1) proto = 0x88A8; // ETH Protocol - 8021AD
    534         // IFLA VLAN PROTOCOL - 5
    535         add_string_to_rtattr(n, size, 5, &proto, sizeof(proto));
    536         break;
    537       case 2: // ARG_reorder_hdr
    538       case 3: // ARG_gvrp
    539         if ((param = substring_to_idx(*argv, on_off)) == -1) iphelp();
    540 
    541         flags.mask |= (idx -1); // VLAN FLAG REORDER Header
    542         flags.flags &= ~(idx -1); // VLAN FLAG REORDER Header
    543         if (!param) flags.flags |= (idx -1); // VLAN FLAG REORDER Header
    544         break;
    545     }
    546   }
    547   if (flags.mask)
    548     add_string_to_rtattr(n, size, IFLA_VLAN_FLAGS, &flags, sizeof(flags));
    549 }
    550 
    551 static int linkupdate(char **argv)
    552 {
    553   struct {
    554     struct nlmsghdr mhdr;
    555     struct ifinfomsg info;
    556     char buf[1024];
    557   } request;
    558   char *name, *dev, *type, *link, *addr;
    559   struct rtattr *attr = NULL;
    560   int len = 0, add = (*argv[-1] == 'a') ? 1 : 0;
    561 
    562   name = dev = type = link = addr = NULL;
    563   for (; *argv; argv++) {
    564     struct arglist objectlist[] = { {"type", 0}, {"name", 1}, {"link", 2},
    565       {"address", 3}, {NULL,-1}};
    566     uint8_t idx = substring_to_idx(*argv, objectlist);
    567 
    568     if (!idx) {
    569       type = *++argv;
    570       break;
    571     }
    572     else if (idx == 1) dev = name = *++argv;
    573     else if (idx == 2) link = *++argv;
    574     else if (idx == 3) addr = *++argv;
    575     else if (!dev) name = dev = *argv;
    576   }
    577 
    578   if (!name && !add)
    579     error_exit("Not enough information: \"dev\" argument is required.\n");
    580   else if (!type  && add)
    581     error_exit("Not enough information: \"type\" argument is required.\n");
    582 
    583   memset(&request, 0, sizeof(request));
    584   request.mhdr.nlmsg_len = NLMSG_LENGTH(sizeof(struct ifinfomsg));
    585   request.mhdr.nlmsg_flags = NLM_F_REQUEST|NLM_F_ACK;
    586   if (add) {
    587     request.mhdr.nlmsg_flags |= NLM_F_CREATE|NLM_F_EXCL;
    588     request.mhdr.nlmsg_type = RTM_NEWLINK;
    589   } else {
    590     request.mhdr.nlmsg_type = RTM_DELLINK;
    591     request.info.ifi_index = get_ifaceindex(name, 1);
    592   }
    593   request.info.ifi_family = AF_UNSPEC;
    594   attr = NLMSG_TAIL(&request.mhdr);
    595   if (type) {
    596     add_string_to_rtattr(&request.mhdr, sizeof(request),
    597         IFLA_LINKINFO, NULL, 0);
    598     add_string_to_rtattr(&request.mhdr, sizeof(request),
    599         IFLA_INFO_KIND, type, strlen(type));
    600     if (!strcmp(type, "vlan")) {
    601       struct rtattr *data = NLMSG_TAIL(&request.mhdr);
    602       add_string_to_rtattr(&request.mhdr, sizeof(request),
    603           IFLA_INFO_DATA, NULL, 0);
    604       vlan_parse_opt(++argv, &request.mhdr, sizeof(request));
    605       data->rta_len = (void *)NLMSG_TAIL(&request.mhdr) - (void *)data;
    606     }
    607     attr->rta_len = (void *)NLMSG_TAIL(&request.mhdr) - (void *)attr;
    608   }
    609 
    610   if (link) {
    611     uint32_t idx = get_ifaceindex(link, 1);
    612     add_string_to_rtattr(&request.mhdr, sizeof(request),
    613         IFLA_LINK, &idx, sizeof(uint32_t));
    614   }
    615   if (addr) {
    616     char abuf[IF_NAMESIZE] = {0,};
    617 
    618     fill_hwaddr(addr, IF_NAMESIZE, (unsigned char *)abuf);
    619     add_string_to_rtattr(&request.mhdr, sizeof(request),
    620         IFLA_ADDRESS, abuf, strlen(abuf));
    621   }
    622   if (!name) {
    623     snprintf(toybuf, IFNAMSIZ, "%s%d", type, 0);
    624     for (len = 1; ; len++) {
    625       if (!get_ifaceindex(toybuf, 0)) break;
    626       snprintf(toybuf, IFNAMSIZ, "%s%d", type, len);
    627     }
    628     name = toybuf;
    629   }
    630   len = strlen(name) + 1;
    631   if (len < 2 || len > IFNAMSIZ) error_exit("Invalid device name.");
    632   add_string_to_rtattr(&request.mhdr, sizeof(request), IFLA_IFNAME, name, len);
    633 
    634   send_nlmesg(0, 0, 0, (void *)&request, request.mhdr.nlmsg_len);
    635   return (filter_nlmesg(NULL,NULL));
    636 }
    637 
    638 static int link_set(char **argv)
    639 {
    640   struct arglist cmd_objectlist[] = {{"up", 0}, {"down", 1}, {"arp", 2},
    641     {"multicast", 3}, {"dynamic", 4}, {"name", 5}, {"txqueuelen", 6},
    642     {"mtu", 7},{"address", 8}, {"broadcast", 9}, {NULL,-1}};
    643   int case_flags[] = {IFF_NOARP,IFF_MULTICAST,IFF_DYNAMIC};
    644   struct ifreq req;
    645   int idx, flags = 0, masks = 0xffff, fd;
    646 
    647   memset(&req, 0, sizeof(req));
    648   if (!*argv) error_exit("\"dev\" missing");
    649   xstrncpy(req.ifr_name, *argv, IF_NAMESIZE);
    650   fd = xsocket(AF_INET, SOCK_DGRAM, 0);
    651   xioctl(fd, SIOCGIFINDEX, &req);
    652   for (++argv; *argv;) {
    653     if ((idx = substring_to_idx(*argv++, cmd_objectlist)) == -1) iphelp();
    654     switch(idx) {
    655       case 0:
    656         flags |= IFF_UP; break;
    657       case 1:
    658         masks &= ~IFF_UP; break;
    659       case 2:
    660       case 3:
    661       case 4:
    662         if (!*argv) iphelp();
    663         else if (!strcmp(*argv, "on")) {
    664           if (idx == 2) {
    665             masks &= ~case_flags[idx-2];
    666             flags &= ~case_flags[idx-2];
    667           } else flags |= case_flags[idx-2];
    668         } else if (!strcmp(*argv,"off")) {
    669           if (idx == 2) {
    670             masks |= case_flags[idx-2];
    671             flags |= case_flags[idx-2];
    672           } else masks &= ~case_flags[idx-2];
    673         } else iphelp();
    674         ++argv;
    675         break;
    676       case 5:
    677         xstrncpy(req.ifr_ifru.ifru_newname, *argv, IF_NAMESIZE);
    678         xioctl(fd, SIOCSIFNAME, &req);
    679         xstrncpy(req.ifr_name, *argv++, IF_NAMESIZE);
    680         xioctl(fd, SIOCGIFINDEX, &req);
    681         break;
    682       case 6:
    683         req.ifr_ifru.ifru_ivalue = atolx(*argv++);
    684         xioctl(fd, SIOCSIFTXQLEN, &req);
    685         break;
    686       case 7:
    687         req.ifr_ifru.ifru_mtu = atolx(*argv++);
    688         xioctl(fd, SIOCSIFMTU, &req);
    689         break;
    690       case 8:
    691         xioctl(fd, SIOCGIFHWADDR, &req);
    692         fill_hwaddr(*argv++, IF_NAMESIZE,
    693             (unsigned char *)(req.ifr_hwaddr.sa_data));
    694         xioctl(fd, SIOCSIFHWADDR, &req);
    695         break;
    696       case 9:
    697         xioctl(fd, SIOCGIFHWADDR, &req);
    698         fill_hwaddr(*argv++, IF_NAMESIZE,
    699             (unsigned char *)(req.ifr_hwaddr.sa_data));
    700         xioctl(fd, SIOCSIFHWBROADCAST, &req);
    701         break;
    702     }
    703   }
    704   xioctl(fd, SIOCGIFFLAGS, &req);
    705   req.ifr_ifru.ifru_flags |= flags;
    706   req.ifr_ifru.ifru_flags &= masks;
    707   xioctl(fd, SIOCSIFFLAGS, &req);
    708   xclose(fd);
    709   return 0;
    710 }
    711 
    712 static void print_stats(struct  rtnl_link_stats *rtstat)
    713 {
    714   char *line_feed = (!TT.singleline ? "\n    " : " ");
    715 
    716   if (TT.stats > 0) {
    717     xprintf("    RX: bytes  packets  errors  "
    718         "dropped  overrun  mcast%s%-10u %-8u %-7u %-8u %-8u %-8u\n",
    719         line_feed, rtstat->rx_bytes, rtstat->rx_packets, rtstat->rx_errors,
    720         rtstat->rx_dropped, rtstat->rx_over_errors, rtstat->multicast);
    721     if (TT.stats > 1) {
    722       xprintf("    RX: errors  length  crc  "
    723           "frame  fifo  missed%s%-10u %-8u %-7u %-8u %-8u %-8u\n",
    724           line_feed, rtstat->rx_errors, rtstat->rx_length_errors,
    725           rtstat->rx_crc_errors, rtstat->rx_frame_errors,
    726           rtstat->rx_fifo_errors, rtstat->rx_missed_errors);
    727     }
    728     xprintf("    TX: bytes  packets  errors  "
    729         "dropped  carrier  collsns%s%-10u %-8u %-7u %-8u %-8u %-8u\n",
    730         line_feed, rtstat->tx_bytes, rtstat->tx_packets, rtstat->tx_errors,
    731         rtstat->tx_dropped, rtstat->tx_carrier_errors, rtstat->collisions);
    732     if (TT.stats > 1) {
    733       xprintf("    TX: errors  aborted  fifo  window  "
    734           "heartbeat%s%-10u %-8u %-7u %-8u %-8u\n",
    735           line_feed, rtstat->tx_errors, rtstat->tx_aborted_errors,
    736           rtstat->tx_fifo_errors, rtstat->tx_window_errors,
    737           rtstat->tx_heartbeat_errors);
    738     }
    739   }
    740 }
    741 
    742 static int print_link_output(struct linkdata *link)
    743 {
    744   char *line_feed = " ", *flags,*peer = "brd";
    745   struct arglist iface_flags[] = {{"",0},{"UP", IFF_UP},
    746     {"BROADCAST", IFF_BROADCAST}, {"DEBUG", IFF_DEBUG},
    747     {"LOOPBACK", IFF_LOOPBACK}, {"POINTOPOINT", IFF_POINTOPOINT},
    748     {"NOTRAILERS", IFF_NOTRAILERS}, {"RUNNING", IFF_RUNNING},
    749     {"NOARP", IFF_NOARP}, {"PROMISC",IFF_PROMISC},
    750     {"ALLMULTI", IFF_ALLMULTI}, {"MASTER", IFF_MASTER}, {"SLAVE", IFF_SLAVE},
    751     {"MULTICAST", IFF_MULTICAST}, {"PORTSEL", IFF_PORTSEL},
    752     {"AUTOMEDIA", IFF_AUTOMEDIA}, {"DYNAMIC", IFF_DYNAMIC}, {NULL,-1}};
    753 
    754   if (link->parent != -1) {
    755     int fd = 0;
    756     struct ifreq req;
    757 
    758     memset(&req, 0, sizeof(req));
    759     if_indextoname( link->parent,req.ifr_ifrn.ifrn_name);
    760     fd = xsocket(AF_INET, SOCK_DGRAM, 0);
    761     if (ioctl(fd, SIOCGIFTXQLEN, &req)) perror("");
    762     else link->txqueuelen = req.ifr_ifru.ifru_ivalue;
    763     xclose(fd);
    764   }
    765 
    766   if (TT.is_addr && addrinfo.label && fnmatch(addrinfo.label, link->iface, 0))
    767     return 0;
    768 
    769 
    770   if (!(flags = get_flag_string(iface_flags, link->flags, 1)))
    771     error_exit("Invalid data.");
    772   if (!TT.singleline) line_feed="\n    ";
    773   if (link->parent != -1) {
    774     char iface[IF_NAMESIZE];
    775 
    776     if (!if_indextoname(link->parent, iface)) perror_exit(NULL);
    777     sprintf(toybuf,"%s@%s", link->iface, iface);
    778   }
    779   if (link->flags & IFF_POINTOPOINT) peer = "peer";
    780   if (TT.is_addr && TT.singleline && TT.addressfamily)
    781     xprintf("%d: %s", link->iface_idx,
    782         ((link->parent == -1) ? link->iface : toybuf));
    783   else xprintf("%d: %s: <%s> mtu %d qdisc %s state %s qlen %d",
    784       link->iface_idx, ((link->parent == -1) ? link->iface : toybuf), flags,
    785       link->mtu, link->qdiscpline, link->state, link->txqueuelen);
    786 
    787   if (!TT.addressfamily || TT.addressfamily == AF_PACKET)
    788     xprintf("%slink/%s %s %s %s",
    789         line_feed, link->type, link->laddr, peer ,link->bcast);
    790 
    791   xputc('\n');
    792 
    793   //user can specify stats flag two times
    794   //one for stats and other for erros e.g. -s and -s -s
    795   print_stats(&link->rt_stat);
    796   free(flags);
    797 
    798   return 0;
    799 }
    800 
    801 static void fill_address(void *p, char *ip)
    802 {
    803   unsigned char *ptr = (unsigned char*)p;
    804   snprintf(ip, 64, " %02x:%02x:%02x:%02x:%02x:%02x",
    805       ptr[0], ptr[1], ptr[2], ptr[3], ptr[4], ptr[5]);
    806 }
    807 
    808 static int get_link_info(struct nlmsghdr* h,struct linkdata* link,char **argv)
    809 {
    810   struct ifinfomsg *iface = NLMSG_DATA(h);
    811   struct rtattr *attr = IFLA_RTA(iface);
    812   int len = h->nlmsg_len - NLMSG_LENGTH(sizeof(*iface));
    813   struct arglist hwtypes[]={{"generic",0},{"ether",ARPHRD_ETHER},
    814     {"loopback", ARPHRD_LOOPBACK},{"sit",ARPHRD_SIT},
    815 #ifdef ARPHRD_INFINIBAND
    816     {"infiniband",ARPHRD_INFINIBAND},
    817 #endif
    818 #ifdef ARPHRD_IEEE802_TR
    819     {"ieee802",ARPHRD_IEEE802}, {"tr",ARPHRD_IEEE802_TR},
    820 #else
    821     {"tr",ARPHRD_IEEE802},
    822 #endif
    823 #ifdef ARPHRD_IEEE80211
    824     {"ieee802.11",ARPHRD_IEEE80211},
    825 #endif
    826 #ifdef ARPHRD_IEEE1394
    827     {"ieee1394",ARPHRD_IEEE1394},
    828 #endif
    829     {"irda",ARPHRD_IRDA},{"slip",ARPHRD_SLIP},{"cslip",ARPHRD_CSLIP},
    830     {"slip6",ARPHRD_SLIP6}, {"cslip6",ARPHRD_CSLIP6}, {"ppp",ARPHRD_PPP},
    831     {"ipip",ARPHRD_TUNNEL}, {"tunnel6",ARPHRD_TUNNEL6},
    832     {"gre",ARPHRD_IPGRE},
    833 #ifdef ARPHRD_VOID
    834     {"void",ARPHRD_VOID},
    835 #endif
    836     {NULL,-1}};
    837   char *lname = get_flag_string(hwtypes, iface->ifi_type, 0);
    838 
    839   link->next = link->prev = 0;
    840   link->iface_type = iface->ifi_type;
    841   if (!lname) error_exit("Invalid link.");
    842   xstrncpy(link->type, lname, IFNAMSIZ);
    843   free(lname);
    844   link->iface_idx = iface->ifi_index;
    845   link->flags = iface->ifi_flags;
    846   if (*argv && !strcasecmp("up",*argv) && !(link->flags & IFF_UP)) return 1;
    847   link->parent =  -1;
    848   for (; RTA_OK(attr, len); attr = RTA_NEXT(attr, len)) {
    849     switch(attr->rta_type) {
    850       case IFLA_IFNAME:
    851         snprintf(link->iface, IFNAMSIZ, "%s",(char *) RTA_DATA(attr));
    852         break;
    853       case IFLA_ADDRESS:
    854         if ( iface->ifi_type== ARPHRD_TUNNEL ||
    855             iface->ifi_type == ARPHRD_SIT ||
    856             iface->ifi_type == ARPHRD_IPGRE)
    857           inet_ntop(AF_INET, RTA_DATA(attr), link->laddr, 64);
    858         else fill_address(RTA_DATA(attr), link->laddr);
    859         break;
    860       case IFLA_BROADCAST:
    861         if (iface->ifi_type== ARPHRD_TUNNEL ||
    862             iface->ifi_type == ARPHRD_SIT ||
    863             iface->ifi_type == ARPHRD_IPGRE)
    864           inet_ntop(AF_INET, RTA_DATA(attr), link->bcast, 64);
    865         else  fill_address(RTA_DATA(attr), link->bcast);
    866         break;
    867       case IFLA_MTU:
    868         link->mtu = *((int*)(RTA_DATA(attr)));
    869         break;
    870       case IFLA_QDISC:
    871         snprintf(link->qdiscpline, IFNAMSIZ, "%s", (char *) RTA_DATA(attr));
    872         break;
    873       case IFLA_STATS  :
    874         link->rt_stat = *((struct rtnl_link_stats*) RTA_DATA(attr));
    875         break;
    876       case IFLA_LINK:
    877         link->parent = *((int*)(RTA_DATA(attr)));
    878         break;
    879       case IFLA_TXQLEN:
    880         link->txqueuelen = *((int*)(RTA_DATA(attr)));
    881         break;
    882       case IFLA_OPERSTATE:
    883         {
    884           struct arglist flags[]={{"UNKNOWN", 0}, {"NOTPRESENT", 1},
    885             {"DOWN", 2}, {"LOWERLAYERDOWN", 3}, {"TESTING", 4},
    886             {"DORMANT", 5}, {"UP", 6}, {NULL, -1}};
    887           if (!(lname = get_flag_string(flags, *((int*)(RTA_DATA(attr))), 0)))
    888             error_exit("Invalid state.");
    889           xstrncpy(link->state, lname,IFNAMSIZ);
    890           free(lname);
    891         }
    892         break;
    893       default: break;
    894     }
    895   }
    896   return 0;
    897 }
    898 
    899 static int display_link_info(struct nlmsghdr *mhdr, char **argv)
    900 {
    901   struct linkdata link;
    902 
    903   if (!get_link_info(mhdr, &link, argv)) {
    904     if (TT.is_addr) {
    905       struct linkdata *lnk = xzalloc(sizeof(struct linkdata));
    906       memcpy(lnk, &link, sizeof(struct linkdata));
    907       dlist_add_nomalloc((struct double_list **)&linfo,
    908           (struct double_list *)lnk);
    909     }
    910     else print_link_output(&link);
    911   }
    912   return 0;
    913 }
    914 
    915 static int link_show(char **argv)
    916 {
    917   struct {
    918     struct nlmsghdr mhdr;
    919     struct ifinfomsg info;
    920   } request;
    921   uint32_t index = 0;
    922 
    923   if (*argv && strcasecmp("up",*argv)) index = get_ifaceindex(*argv, 1);
    924   memset(&request, 0, sizeof(request));
    925   request.mhdr.nlmsg_len = NLMSG_LENGTH(sizeof(struct ifinfomsg));
    926   request.mhdr.nlmsg_flags = NLM_F_REQUEST|NLM_F_ACK;
    927   if (!index) request.mhdr.nlmsg_flags |= NLM_F_ROOT|NLM_F_MATCH;
    928   else request.info.ifi_change =  0xffffffff; // used in single operation
    929   request.mhdr.nlmsg_type = RTM_GETLINK;
    930   request.info.ifi_index = index;
    931   request.info.ifi_family = AF_UNSPEC;
    932   send_nlmesg(0, 0, 0, (void*)&request, sizeof(request));
    933   return (filter_nlmesg(display_link_info, argv));
    934 }
    935 
    936 static int iplink(char **argv)
    937 {
    938   int idx;
    939   cmdobj ipcmd, cmdobjlist[] = {linkupdate, link_set, link_show};
    940   struct arglist cmd_objectlist[] = {{"add", 0}, {"delete", 0},
    941     {"set", 1}, {"show", 2}, {"list", 2}, {"lst", 2}, {NULL,-1}};
    942 
    943   if (!*argv) idx = 2;
    944   else if ((idx = substring_to_idx(*argv++, cmd_objectlist)) == -1) iphelp();
    945   ipcmd = cmdobjlist[idx];
    946   return ipcmd(argv);
    947 }
    948 
    949 // ===========================================================================
    950 // Code for ip addr.
    951 // ===========================================================================
    952 
    953 static int print_addrinfo(struct nlmsghdr *h, int flag_l)
    954 {
    955   struct rtattr *rta, *rta_tb[IFA_MAX+1] = {0,};
    956   char *family = toybuf, *scope = toybuf+256, *label = toybuf+512,
    957        *brd = toybuf+768, *peer = toybuf+1024, *any = toybuf+1280,
    958        lbuf[INET6_ADDRSTRLEN] = {0,}, lbuf_ifa[INET6_ADDRSTRLEN] = {0,};
    959   struct ifaddrmsg *ifa = NLMSG_DATA(h);
    960   int len;
    961 
    962   if ((len = h->nlmsg_len - NLMSG_LENGTH(sizeof(*ifa))) < 0) {
    963     error_msg("wrong nlmsg len %d", len);
    964     return 0;
    965   }
    966 
    967   for (rta = IFA_RTA(ifa); RTA_OK(rta, len); rta=RTA_NEXT(rta, len))
    968     if (rta->rta_type <= IFA_MAX) rta_tb[rta->rta_type] = rta;
    969 
    970   if (!rta_tb[IFA_LOCAL]) rta_tb[IFA_LOCAL] = rta_tb[IFA_ADDRESS];
    971   if (!rta_tb[IFA_ADDRESS]) rta_tb[IFA_ADDRESS] = rta_tb[IFA_LOCAL];
    972   if ((addrinfo.scope ^ ifa->ifa_scope)&addrinfo.scopemask) return 0;
    973   if (addrinfo.ifindex && addrinfo.ifindex != ifa->ifa_index) return 0;
    974 
    975   if (flag_l && addrinfo.label && ifa->ifa_family == AF_INET6) return 0;
    976   if ((rta_tb[IFA_LABEL])) {
    977     xstrncpy(label, RTA_DATA(rta_tb[IFA_LABEL]), 256);
    978     label[255] = '\0';
    979     if (addrinfo.label && fnmatch(addrinfo.label, label, 0))
    980       return 0;
    981   }
    982 
    983   if (TT.flush) {
    984     if (ifa->ifa_index == addrinfo.ifindex) {
    985       h->nlmsg_type = RTM_DELADDR;
    986       h->nlmsg_flags = NLM_F_REQUEST;
    987       send_nlmesg(RTM_DELADDR, 0, 0, h, h->nlmsg_len);
    988       return 0;
    989     }
    990   }
    991 
    992   if (h->nlmsg_type == RTM_DELADDR) printf("Deleted ");
    993 
    994   if (TT.singleline) {
    995     if (!if_indextoname(ifa->ifa_index, lbuf)) perror_exit(NULL);
    996     printf("%u: %s",ifa->ifa_index, lbuf);
    997   }
    998 
    999   sprintf(scope, " scope %s ", namefromRPDB(ifa->ifa_scope, RPDB_rtscopes));
   1000 
   1001   if (ifa->ifa_family == AF_INET) strcpy(family, "    inet ");
   1002   else if (ifa->ifa_family == AF_INET6) strcpy(family, "    inet6 ");
   1003   else sprintf(family, "    family %d", ifa->ifa_family);
   1004 
   1005   if (rta_tb[IFA_LOCAL]) {
   1006     if (!inet_ntop(ifa->ifa_family, RTA_DATA(rta_tb[IFA_LOCAL]),
   1007           lbuf, sizeof(lbuf))) perror_exit("inet");
   1008 
   1009     sprintf(family+strlen(family), lbuf, strlen(lbuf));
   1010     if (!rta_tb[IFA_ADDRESS] || !memcmp(RTA_DATA(rta_tb[IFA_ADDRESS]),
   1011           RTA_DATA(rta_tb[IFA_LOCAL]), 4))
   1012       sprintf(family+strlen(family), "/%d ", ifa->ifa_prefixlen);
   1013     else {
   1014       if (!inet_ntop(ifa->ifa_family, RTA_DATA(rta_tb[IFA_ADDRESS]),
   1015             lbuf_ifa, sizeof(lbuf_ifa))) perror_exit("inet");
   1016       sprintf(peer, " peer %s/%d ", lbuf_ifa, ifa->ifa_prefixlen);
   1017     }
   1018   }
   1019 
   1020   if (addrinfo.to && strcmp(addrinfo.addr, lbuf))
   1021     return 0;
   1022 
   1023   if (rta_tb[IFA_BROADCAST]) {
   1024     if (!inet_ntop(ifa->ifa_family, RTA_DATA(rta_tb[IFA_BROADCAST]),
   1025           lbuf, sizeof(lbuf))) perror_exit("inet");
   1026     sprintf(brd, " brd %s", lbuf);
   1027   }else brd = "";
   1028 
   1029   if (rta_tb[IFA_ANYCAST]) {
   1030     if (!inet_ntop(ifa->ifa_family, RTA_DATA(rta_tb[IFA_ANYCAST]),
   1031           lbuf, sizeof(lbuf))) perror_exit("inet");
   1032     sprintf(any, " any %s", lbuf);
   1033   }
   1034 
   1035   if (ifa->ifa_family == AF_INET)
   1036     printf("%s%s%s%s%s %c", family, brd, peer, scope, label,
   1037         (TT.singleline? '\0' : '\n'));
   1038   else printf("%s%s %c", family, scope, (TT.singleline? '\0' : '\n'));
   1039   if (TT.singleline && (ifa->ifa_family == AF_INET)) xputc('\n');
   1040 
   1041   if (rta_tb[IFA_CACHEINFO]) {
   1042     struct ifa_cacheinfo *ci = RTA_DATA(rta_tb[IFA_CACHEINFO]);
   1043 
   1044     printf("%c      valid_lft ", (TT.singleline? '\\' : '\0'));
   1045     if (ci->ifa_valid ==  0xFFFFFFFFU) printf("forever");
   1046     else printf("%usec", ci->ifa_valid);
   1047     printf(" preferred_lft ");
   1048     if (ci->ifa_prefered ==  0xFFFFFFFFU) printf("forever");
   1049     else printf("%dsec", ci->ifa_prefered);
   1050     xputc('\n');
   1051   }
   1052   return 0;
   1053 }
   1054 
   1055 static int ipaddrupdate(char **argv)
   1056 {
   1057   int length, cmd = !memcmp("add", argv[-1], strlen(argv[-1]))
   1058     ? RTM_NEWADDR: RTM_DELADDR;
   1059   int idx = 0,length_brd = 0, length_peer = 0,length_any = 0,length_local = 0,
   1060       scoped = 0;
   1061   char *dev = NULL,*label = NULL, reply[8192];
   1062 
   1063   struct nlmsghdr *addr_ptr = NULL;
   1064   struct nlmsgerr *err = NULL;
   1065   struct arglist cmd_objectlist[] = {{"dev",0}, {"peer", 1},
   1066     {"remote", 2}, {"broadcast", 3}, {"brd", 4}, {"label", 5},
   1067     {"anycast", 6},{"scope", 7}, {"local", 8}, {NULL, -1}};
   1068   struct {
   1069     struct nlmsghdr nlm;
   1070     struct ifaddrmsg ifadd;
   1071     char buf[256];
   1072   } req;
   1073   typedef struct {
   1074     int family, bytelen, bitlen;
   1075     __u32  data[8];
   1076   } option_data;
   1077   option_data local;
   1078 
   1079   memset(&req, 0, sizeof(req));
   1080   req.nlm.nlmsg_len = NLMSG_LENGTH(sizeof(struct ifaddrmsg));
   1081   req.nlm.nlmsg_flags = NLM_F_REQUEST|NLM_F_ACK;
   1082   req.nlm.nlmsg_type = cmd;
   1083   req.ifadd.ifa_family = TT.addressfamily;
   1084 
   1085   while (*argv) {
   1086     idx = substring_to_idx(*argv, cmd_objectlist);
   1087     if (idx >= 0)
   1088       if (!*++argv)
   1089         error_exit("Incomplete Command line");
   1090     switch(idx) {
   1091       case 0:
   1092         dev = *argv;
   1093         break;
   1094       case 1:
   1095       case 2:
   1096         {
   1097           uint32_t addr[4] = {0,}, netmask = 0;
   1098           uint8_t len = 0;
   1099           parse_prefix(addr, &netmask, &len, *argv,
   1100               req.ifadd.ifa_family);
   1101           if (len)
   1102             req.ifadd.ifa_family = ((len == 4) ? AF_INET : AF_INET6);
   1103           length_peer = len;
   1104           add_string_to_rtattr(&req.nlm, sizeof(req),
   1105               IFA_ADDRESS, addr, len);
   1106           req.ifadd.ifa_prefixlen = netmask;
   1107         }
   1108         break;
   1109       case 3:
   1110       case 4:
   1111         if (*argv[0] == '+') {
   1112           length_brd = -1;
   1113         } else if (*argv[0] == '-') {
   1114           length_brd = -2;
   1115         } else {
   1116           uint32_t addr[4] = {0,};
   1117           uint8_t af = AF_UNSPEC;
   1118 
   1119           if (get_prefix(addr, &af, *argv, req.ifadd.ifa_family))
   1120             error_exit("Invalid prefix");
   1121 
   1122           length_brd = ((af == AF_INET6) ? 16 : 4);
   1123           if (req.ifadd.ifa_family == AF_UNSPEC)
   1124             req.ifadd.ifa_family = af;
   1125           add_string_to_rtattr(&req.nlm, sizeof(req),
   1126               IFA_BROADCAST, &addr, length_brd);
   1127         }
   1128         break;
   1129       case 5:
   1130         label = *argv;
   1131         add_string_to_rtattr(&req.nlm, sizeof(req),
   1132             IFA_LABEL, label, strlen(label) + 1);
   1133         break;
   1134       case 6:
   1135         {
   1136           uint32_t addr[4] = {0,};
   1137           uint8_t af = AF_UNSPEC;
   1138 
   1139           if (get_prefix(addr, &af, *argv, req.ifadd.ifa_family))
   1140             error_exit("Invalid prefix");
   1141           length_any = ((af == AF_INET6) ? 16 : 4);
   1142           if (req.ifadd.ifa_family == AF_UNSPEC)
   1143             req.ifadd.ifa_family = af;
   1144           add_string_to_rtattr(&req.nlm, sizeof(req),
   1145               IFA_ANYCAST, &addr, length_any);
   1146         }
   1147         break;
   1148       case 7:
   1149         {
   1150           int scope = idxfromRPDB(*argv, RPDB_rtscopes);
   1151           if (scope < 0) error_exit("wrong scope '%s'", *argv);
   1152           req.ifadd.ifa_scope = scope;
   1153           scoped = 1;
   1154         }
   1155         break;
   1156       default:
   1157         {
   1158           //local is by default
   1159           uint32_t addr[8] = {0,}, netmask = 0;
   1160           uint8_t len = 0;
   1161 
   1162           parse_prefix(addr, &netmask, &len, *argv,
   1163               req.ifadd.ifa_family);
   1164           if (len)
   1165             req.ifadd.ifa_family = ((len == 4) ? AF_INET : AF_INET6);
   1166           length_local = len;
   1167           local.bitlen = netmask;
   1168           local.bytelen = len;
   1169           memcpy(local.data, addr, sizeof(local.data));
   1170           local.family = req.ifadd.ifa_family;
   1171           add_string_to_rtattr(&req.nlm, sizeof(req),
   1172               IFA_LOCAL, &local.data, local.bytelen);
   1173         }
   1174         break;
   1175     }
   1176     argv++;
   1177   }
   1178   if (!dev) error_exit("need \"dev \" argument");
   1179   if (label && strncmp(dev, label, strlen(dev)) != 0)
   1180     error_exit("\"dev\" (%s) must match \"label\" (%s)", dev, label);
   1181 
   1182   if (length_peer == 0 && length_local && cmd != RTM_DELADDR){
   1183     add_string_to_rtattr(&req.nlm, sizeof(req),
   1184         IFA_ADDRESS, &local.data, local.bytelen);
   1185   }
   1186 
   1187   if (length_brd < 0 && cmd != RTM_DELADDR){
   1188     int i;
   1189 
   1190     if (req.ifadd.ifa_family != AF_INET)
   1191       error_exit("broadcast can be set only for IPv4 addresses");
   1192 
   1193     if (local.bitlen <= 30) {
   1194       for (i = 31; i >= local.bitlen; i--) {
   1195         if (length_brd == -1)
   1196           local.data[0] |= htonl(1<<(31-i));
   1197         else
   1198           local.data[0] &= ~htonl(1<<(31-i));
   1199       }
   1200       add_string_to_rtattr(&req.nlm, sizeof(req),
   1201           IFA_BROADCAST, &local.data, local.bytelen);
   1202       length_brd = local.bytelen;
   1203     }
   1204   }
   1205   if (req.ifadd.ifa_prefixlen == 0)
   1206     req.ifadd.ifa_prefixlen = local.bitlen;
   1207   if (!scoped && (cmd != RTM_DELADDR) && (local.family == AF_INET)
   1208       && (local.bytelen >= 1 && *(uint8_t*)&local.data == 127))
   1209     req.ifadd.ifa_scope = RT_SCOPE_HOST;
   1210   req.ifadd.ifa_index = get_ifaceindex(dev, 1);
   1211 
   1212   send_nlmesg(RTM_NEWADDR, 0, AF_UNSPEC, (void *)&req, req.nlm.nlmsg_len);
   1213   length = recv(TT.sockfd, reply, sizeof(reply), 0);
   1214   addr_ptr = (struct nlmsghdr *) reply;
   1215   for (; NLMSG_OK(addr_ptr, length); addr_ptr = NLMSG_NEXT(addr_ptr, length)) {
   1216     if (addr_ptr->nlmsg_type == NLMSG_DONE)
   1217       return 1;
   1218     if (addr_ptr->nlmsg_type == NLMSG_ERROR)
   1219       err = (struct nlmsgerr*) NLMSG_DATA(addr_ptr);
   1220     if (err && err->error) {
   1221       errno = -err->error;
   1222       perror_exit("RTNETLINK answers:");
   1223     }
   1224   }
   1225   return 0;
   1226 }
   1227 
   1228 static int ipaddr_listflush(char **argv)
   1229 {
   1230   int idx; uint32_t netmask = 0, found = 0;
   1231   char *tmp = NULL, *name = NULL;
   1232   struct double_list *dlist;
   1233   struct arglist cmd_objectlist[] = {{"to", 0}, {"scope", 1}, {"up", 2},
   1234     {"label", 3}, {"dev", 4}, {NULL, -1}};
   1235 
   1236   TT.flush = *argv[-1] == 'f' ? 1 : 0;
   1237   memset(&addrinfo, 0, sizeof(addrinfo));
   1238 
   1239   if (TT.flush) {
   1240     if (!*argv)
   1241       error_exit("Incomplete command for \"flush\"");
   1242     if (TT.addressfamily == AF_PACKET)
   1243       error_exit("Can't flush link Addressess");
   1244   }
   1245   addrinfo.scope = -1;
   1246   while (*argv) {
   1247     switch (idx = substring_to_idx(*argv, cmd_objectlist)) {
   1248       case 0:
   1249         {// ADDR_TO
   1250           if (!*++argv) error_exit("Incomplete Command line");
   1251           else if (!strcmp(*argv, "0")) return 0;
   1252           uint32_t addr[4] = {0,};
   1253           uint8_t len = 0;
   1254 
   1255           addrinfo.to = 1;
   1256           parse_prefix(addr, &netmask, &len, *argv, TT.addressfamily);
   1257           if (len)
   1258             TT.addressfamily = ((len == 4) ? AF_INET : AF_INET6);
   1259           addrinfo.addr  = strtok(*argv, "/");
   1260         }
   1261         break;
   1262       case 1: // ADDR_SCOPE
   1263         {
   1264           int scope = 0;
   1265           if (!*++argv) error_exit("Incomplete Command line");
   1266           name = *argv;
   1267 
   1268           addrinfo.scopemask = -1;
   1269           if (isdigit(**argv)) {
   1270             int idx = atolx(*argv);
   1271 
   1272             name = xstrdup(namefromRPDB(idx, RPDB_rtscopes));
   1273           }
   1274           if ((scope = idxfromRPDB(name, RPDB_rtscopes)) < 0) {
   1275             if (strcmp(name, "all"))
   1276               error_exit("wrong scope '%s'", name);
   1277             scope = RT_SCOPE_NOWHERE;
   1278             addrinfo.scopemask = 0;
   1279           }
   1280 
   1281           if (isdigit(**argv))
   1282             free(name);
   1283           addrinfo.scope = scope;
   1284         }
   1285         break;
   1286       case 2: // ADDR_UP
   1287         addrinfo.up = 1;
   1288         break;
   1289       case 3: // ADDR_LABEL
   1290         if (!*++argv) error_exit("Incomplete Command line");
   1291         addrinfo.label = *argv;
   1292         break;
   1293       case 4: // ADDR_DEV
   1294         if (!*++argv) error_exit("Incomplete Command line");
   1295 
   1296       default:
   1297         if (TT.filter_dev)
   1298           error_exit("Either \"dev\" is duplicate or %s is garbage",
   1299               *argv);
   1300         TT.filter_dev = *argv;
   1301         break;
   1302     }
   1303     argv++;
   1304   }
   1305 
   1306   link_show(&tmp);
   1307   while ( linfo && (dlist = dlist_pop(&linfo))){
   1308     struct linkdata *tmp  = (struct linkdata*) dlist;
   1309     char *temp = &tmp->iface[0];
   1310 
   1311     if (TT.filter_dev && strcmp(TT.filter_dev, temp))
   1312       continue;
   1313     found = 1;
   1314     if (TT.flush && addrinfo.label) ipaddr_print( tmp, 0);
   1315     if (addrinfo.up && !(tmp->flags & IFF_UP)){
   1316       ipaddr_print(tmp, 0);
   1317       continue;
   1318     }
   1319     if (addrinfo.label){
   1320       if ( fnmatch(addrinfo.label, temp, 0)) {
   1321         ipaddr_print(tmp, 1);
   1322         continue;
   1323       }
   1324     }
   1325     if (!TT.addressfamily && ! TT.flush ) print_link_output(tmp);
   1326 
   1327     ipaddr_print(tmp, 0);
   1328     free(tmp);
   1329   }
   1330   if (TT.filter_dev && !found)
   1331     error_exit("Device \"%s\" doesn't exist. \n", TT.filter_dev);
   1332   return 0;
   1333 }
   1334 
   1335 static int ipaddr_print( struct linkdata *link, int flag_l)
   1336 {
   1337   struct nlmsghdr *addr_ptr;
   1338   int ip_match = 0;
   1339 
   1340   addrinfo.ifindex = link->iface_idx;
   1341   send_nlmesg(RTM_GETADDR, NLM_F_ROOT|NLM_F_MATCH|NLM_F_REQUEST,
   1342       AF_UNSPEC, NULL, 0);
   1343   if (TT.addressfamily == AF_PACKET) print_link_output(link);
   1344 
   1345   if (addrinfo.label){
   1346     char *col = strchr(addrinfo.label, ':');
   1347     if (!col && (fnmatch(addrinfo.label, &link->iface[0], 0)))
   1348       return 0;
   1349   }
   1350 
   1351   while (1){
   1352     int len = recv(TT.sockfd, TT.gbuf, sizeof(TT.gbuf), 0);
   1353     addr_ptr = (struct nlmsghdr *)TT.gbuf;
   1354     struct ifaddrmsg *addressInfo = NLMSG_DATA(addr_ptr);
   1355     char lbuf[INET6_ADDRSTRLEN];
   1356     struct rtattr *rta, *rta_tb[IFA_MAX+1] = {0,};
   1357 
   1358     int len1 = addr_ptr->nlmsg_len - NLMSG_LENGTH(sizeof(*addressInfo));
   1359     if (len1 > 0) {
   1360       for (; NLMSG_OK(addr_ptr, len); addr_ptr = NLMSG_NEXT(addr_ptr, len)) {
   1361         addressInfo = NLMSG_DATA(addr_ptr);
   1362         if (TT.addressfamily && TT.addressfamily != addressInfo->ifa_family)
   1363           continue;
   1364         if (addrinfo.ifindex && addrinfo.ifindex != addressInfo->ifa_index)
   1365           continue;
   1366 
   1367         if (addrinfo.to) {
   1368           memset(rta_tb, 0, sizeof(rta_tb));
   1369           int rt_len = IFA_PAYLOAD(addr_ptr);
   1370           for (rta = IFA_RTA(addressInfo); RTA_OK(rta, rt_len); rta=RTA_NEXT(rta, rt_len)) {
   1371             if (rta->rta_type <= IFA_MAX) rta_tb[rta->rta_type] = rta;
   1372           }
   1373           if (!rta_tb[IFA_LOCAL]) rta_tb[IFA_LOCAL] = rta_tb[IFA_ADDRESS];
   1374           if (rta_tb[IFA_LOCAL]) {
   1375             if (!inet_ntop(TT.addressfamily, RTA_DATA(rta_tb[IFA_LOCAL]),
   1376                   lbuf, sizeof(lbuf))) perror_exit("inet");
   1377             if (strcmp(addrinfo.addr, lbuf))
   1378               continue;
   1379             ip_match=1;
   1380           }
   1381           if (!ip_match)
   1382             continue;
   1383         }
   1384 
   1385         if (!TT.flush){
   1386           if (addrinfo.scope != -1 && TT.addressfamily && TT.addressfamily ==
   1387               addressInfo->ifa_family &&
   1388               (addrinfo.ifindex == addressInfo->ifa_index)) {
   1389             if ((addrinfo.scope ^ addressInfo->ifa_scope) & addrinfo.scopemask)
   1390               continue;
   1391             else if (addrinfo.up && (link->flags & IFF_UP))
   1392               print_link_output(link);
   1393             else if (!addrinfo.up) print_link_output(link);
   1394           }
   1395           if (TT.addressfamily &&
   1396               (addrinfo.ifindex == addressInfo->ifa_index) &&
   1397               (addrinfo.scope == -1)){
   1398             if (addrinfo.up && (link->flags & IFF_UP))
   1399               print_link_output(link);
   1400             else if (!addrinfo.up) print_link_output(link);
   1401           }
   1402         }
   1403 
   1404         for (; NLMSG_OK(addr_ptr, len); addr_ptr = NLMSG_NEXT(addr_ptr, len)) {
   1405           if ((addr_ptr->nlmsg_type == RTM_NEWADDR))
   1406             print_addrinfo(addr_ptr, flag_l);
   1407           if ((addr_ptr->nlmsg_type == NLMSG_DONE) ||
   1408               (addr_ptr->nlmsg_type == NLMSG_ERROR) ||
   1409               (TT.flush && addrinfo.to))
   1410             goto ret_stop;
   1411         }
   1412         if ((addr_ptr->nlmsg_type == NLMSG_DONE) ||
   1413             (addr_ptr->nlmsg_type == NLMSG_ERROR))
   1414           break;
   1415       }
   1416     }
   1417     else
   1418       return 0;
   1419   }
   1420 
   1421 ret_stop:
   1422   return 0;
   1423 }
   1424 
   1425 static int ipaddr(char **argv)
   1426 {
   1427   int    idx;
   1428   cmdobj ipcmd, cmdobjlist[] = {ipaddrupdate, ipaddr_listflush};
   1429   struct arglist cmd_objectlist[] = { {"add", 0}, {"delete", 0},
   1430     {"list", 1},{"show", 1},{"lst", 1}, {"flush", 1}, {NULL,-1}};
   1431 
   1432   TT.is_addr++;
   1433   if (!*argv) idx = 1;
   1434   else if ((idx = substring_to_idx(*argv++, cmd_objectlist)) == -1) iphelp();
   1435 
   1436   ipcmd = cmdobjlist[idx];
   1437   return ipcmd(argv);
   1438 }
   1439 
   1440 // ===========================================================================
   1441 // code for ip route
   1442 // ===========================================================================
   1443 struct I_data {
   1444   unsigned char family;
   1445   uint32_t addr[8] , netmask ;
   1446   uint8_t len ;
   1447 };
   1448 
   1449 struct {
   1450   int tb,idev,odev,proto;
   1451   struct I_data rvia, rdst, mdst, rsrc, msrc;
   1452 } gfilter;
   1453 
   1454 static void show_iproute_help(void)
   1455 {
   1456   char *errmsg = "\n\n" \
   1457        "iproute { list | flush } SELECTOR\n" \
   1458        "iproute get ADDRESS [from ADDRESS iif STRING]\n" \
   1459        "	[oif STRING]\n" \
   1460        "iproute { add | del | change | append | replace | test } ROUTE\n" \
   1461        "	SELECTOR := [root PREFIX] [match PREFIX] [proto RTPROTO]\n" \
   1462        "	ROUTE := [TYPE] PREFIX [proto RTPROTO] [metric METRIC]";
   1463 
   1464   error_exit(errmsg);
   1465 }
   1466 
   1467 static int display_route_info(struct nlmsghdr *mhdr, char **argv)
   1468 {
   1469   char *inetval = NULL, out[1024] = {0};
   1470   struct rtmsg *msg = NLMSG_DATA(mhdr);
   1471   struct rtattr *rta, *attr[RTA_MAX+1] = {0,};
   1472   int32_t tvar, msglen = mhdr->nlmsg_len - NLMSG_LENGTH(sizeof(struct rtmsg));
   1473   int hlen = ((msg->rtm_family == AF_INET) ? 32
   1474       : ((msg->rtm_family == AF_INET6) ? 128 : -1));
   1475 
   1476   if (mhdr->nlmsg_type != RTM_NEWROUTE) return 0;
   1477   if (msglen < 0) return 1;
   1478 
   1479   if (msg->rtm_family == AF_INET6) {
   1480     if (gfilter.tb) {
   1481       if (gfilter.tb < 0) {
   1482         if (!(msg->rtm_flags & RTM_F_CLONED)) return 0;
   1483       } else {
   1484         if (msg->rtm_flags & RTM_F_CLONED) return 0;
   1485         if (gfilter.tb == RT_TABLE_LOCAL && msg->rtm_type != RTN_LOCAL)
   1486           return 0;
   1487         else if (gfilter.tb == RT_TABLE_MAIN && msg->rtm_type == RTN_LOCAL)
   1488           return 0;
   1489       }
   1490     }
   1491   }
   1492   else if (gfilter.tb > 0 && gfilter.tb != msg->rtm_table) return 0;
   1493 
   1494   if (gfilter.proto && (msg->rtm_protocol != gfilter.proto)) return 0;
   1495 
   1496 
   1497   if (gfilter.rdst.family && (msg->rtm_family != gfilter.rdst.family ||
   1498         gfilter.rdst.netmask > msg->rtm_dst_len)) return 0;
   1499   if (gfilter.mdst.family && (msg->rtm_family != gfilter.mdst.family
   1500         || (gfilter.mdst.netmask < msg->rtm_dst_len))) return 0;
   1501   if (gfilter.rsrc.family && (msg->rtm_family != gfilter.rsrc.family
   1502         || gfilter.rsrc.netmask > msg->rtm_src_len)) return 0;
   1503   if (gfilter.msrc.family && (msg->rtm_family != gfilter.msrc.family
   1504         || (gfilter.msrc.netmask < msg->rtm_src_len))) return 0;
   1505   tvar = msglen;
   1506 
   1507   for (rta = RTM_RTA(msg); RTA_OK(rta, tvar); rta=RTA_NEXT(rta, tvar))
   1508     if (rta->rta_type <= RTA_MAX) attr[rta->rta_type] = rta;
   1509 
   1510   if (msg->rtm_type != RTN_UNICAST)
   1511     sprintf(out,"%s%s ", out,rtmtype_idx2str(msg->rtm_type));
   1512   if (attr[RTA_DST]) {
   1513     inetval = (char *)inet_ntop(msg->rtm_family, RTA_DATA(attr[RTA_DST]),
   1514         toybuf, sizeof(toybuf));
   1515     if (gfilter.rdst.family &&
   1516         memcmp(RTA_DATA(attr[RTA_DST]), &gfilter.rdst.addr, gfilter.rdst.len))
   1517       return 0;
   1518     if (gfilter.mdst.family &&
   1519         memcmp(RTA_DATA(attr[RTA_DST]), &gfilter.mdst.addr, gfilter.mdst.len))
   1520       return 0;
   1521     sprintf(out,"%s%s",out,inetval);
   1522   }
   1523   if (msg->rtm_dst_len) sprintf(out,"%s/%d ", out,msg->rtm_dst_len);
   1524   else sprintf(out,"%s%s",out,"default ");
   1525 
   1526   if (attr[RTA_SRC]) {
   1527     inetval = (char *)inet_ntop(msg->rtm_family, RTA_DATA(attr[RTA_SRC]),
   1528         toybuf, sizeof(toybuf));
   1529     if (gfilter.rsrc.family &&
   1530         memcmp(RTA_DATA(attr[RTA_SRC]), &gfilter.rsrc.addr, gfilter.rsrc.len))
   1531       return 0;
   1532     if (gfilter.msrc.family &&
   1533         memcmp(RTA_DATA(attr[RTA_SRC]), &gfilter.msrc.addr, gfilter.msrc.len))
   1534       return 0;
   1535     sprintf(out, "%s from %s", out, inetval);
   1536   }
   1537   if (msg->rtm_src_len) sprintf(out, "%s/%d ", out, msg->rtm_src_len);
   1538 
   1539   if (attr[RTA_GATEWAY]) {
   1540     inetval = (char *)inet_ntop(msg->rtm_family, RTA_DATA(attr[RTA_GATEWAY]),
   1541         toybuf, sizeof(toybuf));
   1542     sprintf(out, "%s via %s ", out, inetval);
   1543   }
   1544   if (gfilter.rvia.family) {
   1545     char tmp[256];
   1546 
   1547     if (!attr[RTA_GATEWAY]) return 0;
   1548     if (strcmp((char *)inet_ntop(msg->rtm_family, gfilter.rvia.addr,
   1549             tmp, sizeof(tmp)), inetval)) return 0;
   1550   }
   1551 
   1552   if (gfilter.odev != 0) if (!attr[RTA_OIF]) return 0;
   1553   if (attr[RTA_OIF]) {
   1554     if (gfilter.odev !=0 && gfilter.odev != *(int*)RTA_DATA(attr[RTA_OIF]))
   1555       return 0;
   1556     sprintf(out, "%s dev %s ", out,
   1557         if_indextoname(*(int*)RTA_DATA(attr[RTA_OIF]), toybuf));
   1558   }
   1559 
   1560   if (attr[RTA_PREFSRC] && hlen) {
   1561     inetval = (char *)inet_ntop(msg->rtm_family, RTA_DATA(attr[RTA_PREFSRC]),
   1562         toybuf, sizeof(toybuf));
   1563     sprintf(out, "%s src %s ", out, inetval);
   1564   }
   1565   if (attr[RTA_PRIORITY])
   1566     sprintf(out, "%s metric %d ", out, *(uint32_t*)RTA_DATA(attr[RTA_PRIORITY]));
   1567   if (msg->rtm_family == AF_INET6) {
   1568     struct rta_cacheinfo *ci = NULL;
   1569     if (attr[RTA_CACHEINFO]) ci = RTA_DATA(attr[RTA_CACHEINFO]);
   1570     if ((msg->rtm_flags & RTM_F_CLONED) || (ci && ci->rta_expires)) {
   1571       if (msg->rtm_flags & RTM_F_CLONED) sprintf(out, "%s%s    cache ",
   1572           out, (!TT.singleline ? "\n" : " "));
   1573       if (ci && ci->rta_expires) {
   1574         int hz = 0;
   1575         FILE *fp = xfopen("/proc/net/psched","r");
   1576 
   1577         if (fp) {
   1578           unsigned int nom, denom;
   1579 
   1580           if (fscanf(fp, "%*08x%*08x%08x%08x", &nom, &denom) == 2)
   1581             if (nom == 1000000)
   1582               hz = denom;
   1583           fclose(fp);
   1584         }
   1585         if (!hz) hz = sysconf(_SC_CLK_TCK);
   1586         sprintf(out, "%s expires %dsec", out, ci->rta_expires /hz);
   1587       }
   1588       if (ci && ci->rta_error) sprintf(out, "%s error %d", out, ci->rta_error);
   1589     }
   1590     else if (ci && ci->rta_error)
   1591       sprintf(out, "%s error %d", out, ci->rta_error);
   1592   }
   1593   if (attr[RTA_IIF] && !gfilter.idev)
   1594     sprintf(out, "%s iif %s", out,
   1595         if_indextoname(*(int*)RTA_DATA(attr[RTA_IIF]), toybuf));
   1596   if (TT.flush || (TT.connected && !TT.from_ok))
   1597     memcpy(toybuf, (void*)mhdr,mhdr->nlmsg_len);
   1598 
   1599   if (TT.flush) {
   1600     int sockfd = 0;
   1601     struct nlmsghdr* mhdr = (struct nlmsghdr*)toybuf;
   1602     struct rtmsg *msg = NLMSG_DATA(mhdr);
   1603     int tvar, msglen = mhdr->nlmsg_len - NLMSG_LENGTH(sizeof(struct rtmsg));
   1604     struct rtattr *rta, *attr[RTA_MAX+1] = {0,};
   1605 
   1606     tvar = msglen;
   1607     for (rta = RTM_RTA(msg); RTA_OK(rta, tvar); rta=RTA_NEXT(rta, tvar))
   1608       if (rta->rta_type <= RTA_MAX) attr[rta->rta_type] = rta;
   1609 
   1610     if (msg->rtm_family == AF_INET6
   1611         && !msg->rtm_dst_len
   1612         && msg->rtm_type == RTN_UNREACHABLE
   1613         && attr[RTA_PRIORITY]
   1614         && *(int*)RTA_DATA(attr[RTA_PRIORITY]) == -1)
   1615       return 0;
   1616 
   1617     mhdr->nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK;
   1618     mhdr->nlmsg_type  = RTM_DELROUTE;
   1619     mhdr->nlmsg_pid = 0;
   1620     sockfd = xsocket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
   1621     if (send(sockfd , (void*)mhdr, mhdr->nlmsg_len, 0) < 0)
   1622       perror_exit("Unable to send data on socket.");
   1623 
   1624     while (1) {
   1625       struct nlmsghdr *mhdr;
   1626       int msglen = recv(sockfd, toybuf, sizeof(toybuf), 0);
   1627 
   1628       if ((msglen < 0) && (errno == EINTR || errno == EAGAIN)) continue;
   1629       else if (msglen < 0) {
   1630         error_msg("netlink receive error %s", strerror(errno));
   1631         xclose(sockfd);
   1632         return 1;
   1633       } else if (!msglen) {
   1634         error_msg("EOF on netlink");
   1635         xclose(sockfd);
   1636         return 1;
   1637       }
   1638 
   1639       for (mhdr = (struct nlmsghdr*)toybuf; NLMSG_OK(mhdr, msglen);
   1640           mhdr = NLMSG_NEXT(mhdr, msglen)) {
   1641         switch (mhdr->nlmsg_type) {
   1642           case NLMSG_DONE:
   1643             xclose(sockfd);
   1644             return 0;
   1645           case NLMSG_ERROR:
   1646             {
   1647               struct nlmsgerr *merr = (struct nlmsgerr*)NLMSG_DATA(mhdr);
   1648 
   1649               if (merr->error == 0)  { xclose(sockfd); return 0; }
   1650               if (mhdr->nlmsg_len < NLMSG_LENGTH(sizeof(struct nlmsgerr)))
   1651                 error_msg("ERROR truncated");
   1652               else {
   1653                 errno = -merr->error;
   1654                 perror_msg("RTNETLINK answers");
   1655               }
   1656               xclose(sockfd);
   1657               return 1;
   1658             }
   1659           default:
   1660             break;
   1661         }
   1662       } // End of for loop.
   1663     } // End of while loop.
   1664 
   1665     xclose(sockfd);
   1666   } else printf("%s\n",out);
   1667   return 0;
   1668 }
   1669 
   1670 static int route_get(char **argv)
   1671 {
   1672   int idx, flag;
   1673   struct arglist cmd_objectlist[] = {{"from", 0}, {"iif", 1}, {"oif", 2},
   1674     {"dev", 3}, {"notify", 4}, {"connected", 5}, {"to", 6}, {NULL, -1}};
   1675   char *idev = NULL, *odev = NULL;
   1676   struct {
   1677     struct nlmsghdr mhdr;
   1678     struct rtmsg msg;
   1679     char buf[1024];
   1680   } request;
   1681 
   1682   memset(&request, 0, sizeof(request));
   1683   request.mhdr.nlmsg_len = NLMSG_LENGTH(sizeof(struct rtmsg));
   1684   request.mhdr.nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK;
   1685   request.mhdr.nlmsg_type = RTM_GETROUTE;
   1686   request.msg.rtm_family = AF_UNSPEC;
   1687 
   1688   for (; *argv; argv++) {
   1689     switch(idx = substring_to_idx(*argv, cmd_objectlist)) {
   1690       case 0: TT.from_ok = 1; // dst address
   1691       case 6: argv++; //fallthrough
   1692       default:
   1693               {
   1694                 uint32_t addr[8] = {0,}, netmask = 0;
   1695                 uint8_t len = 0;
   1696 
   1697                 if (!*argv) error_exit("'%s': Missing Prefix", argv[-1]);
   1698                 parse_prefix(addr, &netmask, &len, *argv, request.msg.rtm_family);
   1699                 if (len) request.msg.rtm_family = ((len == 4) ? AF_INET : AF_INET6);
   1700                 netmask = (request.msg.rtm_family == AF_INET6) ? 128 : 32;
   1701                 if (!idx) request.msg.rtm_src_len = netmask;
   1702                 else request.msg.rtm_dst_len = netmask;
   1703                 add_string_to_rtattr(&request.mhdr, sizeof(request),
   1704                     (!idx ? RTA_SRC : RTA_DST), addr, len);
   1705                 break;
   1706               }
   1707       case 1:
   1708       case 2:
   1709       case 3:
   1710               if (!*++argv) show_iproute_help();
   1711               if (idx == 1) idev = *argv, flag = RTA_IIF;
   1712               else odev = *argv, flag = RTA_OIF;
   1713               idx = get_ifaceindex(*argv, 1);
   1714               add_string_to_rtattr(&request.mhdr, sizeof(request),
   1715                   flag, (char*)&idx, sizeof(idx));
   1716               break;
   1717       case 4:
   1718               request.msg.rtm_flags |= RTM_F_NOTIFY;
   1719               break;
   1720       case 5:
   1721               TT.connected = 1;
   1722               break;
   1723     }
   1724   }
   1725   if (!request.msg.rtm_dst_len)
   1726     error_exit("need at least destination address");
   1727 
   1728   send_nlmesg(0, 0, 0, &request, sizeof(request));
   1729   filter_nlmesg(display_route_info, NULL);
   1730 
   1731   if (TT.connected && !TT.from_ok) {
   1732     struct nlmsghdr *mhdr = (struct nlmsghdr*)toybuf;
   1733     struct rtmsg *msg = NLMSG_DATA(mhdr);
   1734     int tvar, msglen = mhdr->nlmsg_len - NLMSG_LENGTH(sizeof(struct rtmsg));
   1735     struct rtattr *rta, *attr[RTA_MAX+1] = {0,};
   1736 
   1737     if (mhdr->nlmsg_type != RTM_NEWROUTE) error_exit("not a route?");
   1738     if (msglen < 0) error_exit("wrong len %d", msglen);
   1739 
   1740     tvar = msglen;
   1741     for (rta = RTM_RTA(msg); RTA_OK(rta, tvar); rta=RTA_NEXT(rta, tvar))
   1742       if (rta->rta_type <= RTA_MAX) attr[rta->rta_type] = rta;
   1743 
   1744     if (attr[RTA_PREFSRC]) {
   1745       attr[RTA_PREFSRC]->rta_type = RTA_SRC;
   1746       msg->rtm_src_len = 8*RTA_PAYLOAD(attr[RTA_PREFSRC]);
   1747     } else if (!attr[RTA_SRC]) error_exit("can't connect the route");
   1748 
   1749     if (!odev && attr[RTA_OIF]) attr[RTA_OIF]->rta_type = 0;
   1750     if (attr[RTA_GATEWAY]) attr[RTA_GATEWAY]->rta_type = 0;
   1751     if (!idev && attr[RTA_IIF]) attr[RTA_IIF]->rta_type = 0;
   1752     mhdr->nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK;
   1753     mhdr->nlmsg_type  = RTM_GETROUTE;
   1754     mhdr->nlmsg_pid = 0;
   1755     xclose(TT.sockfd);
   1756     TT.sockfd = xsocket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
   1757     send_nlmesg(0, 0, 0, mhdr, mhdr->nlmsg_len);
   1758     filter_nlmesg(display_route_info, NULL);
   1759   }
   1760   return 0;
   1761 }
   1762 
   1763 static int route_show_flush(char **argv)
   1764 {
   1765   struct arglist cmd_objectlist[] = {{"protocol", 0}, {"dev", 1}, {"oif", 2},
   1766     {"iif", 3}, {"via", 4}, {"table", 5}, {"cache", 6}, {"from", 7},
   1767     {"to", 8}, {"all", 9}, {"root", 10}, {"match", 11}, {"exact", 12},
   1768     {"main", 13}, {NULL,-1}};
   1769   int family = TT.addressfamily, idx;
   1770   struct {
   1771     struct nlmsghdr mhdr;
   1772     struct rtmsg msg;
   1773   } request;
   1774 
   1775   if (*argv[-1] == 'f') TT.flush = 1;
   1776   if (TT.flush && !*argv) show_iproute_help();
   1777 
   1778   gfilter.tb = RT_TABLE_MAIN;
   1779   for (; *argv; argv++) {
   1780     switch (idx = substring_to_idx(*argv, cmd_objectlist)) {
   1781       case 0:
   1782         if (!*++argv) show_iproute_help();
   1783         if ((idx = idxfromRPDB(*argv,RPDB_rtprotos)) < 0)
   1784           error_exit("Invalid argument protocol.");
   1785         gfilter.proto = idx;
   1786         break;
   1787       case 1:
   1788       case 2:
   1789       case 3:
   1790         {
   1791           if (!*++argv) show_iproute_help();
   1792           int dev = get_ifaceindex(*argv, 1);
   1793 
   1794           if (idx == 3) gfilter.idev = dev;
   1795           else gfilter.odev = dev;
   1796         }
   1797         break;
   1798       case 4:
   1799         if (!*++argv) show_iproute_help();
   1800         parse_prefix(gfilter.rvia.addr, &gfilter.rvia.netmask,
   1801             &gfilter.rvia.len, *argv, gfilter.rvia.family);
   1802         if (gfilter.rvia.len)
   1803           gfilter.rvia.family = ((gfilter.rvia.len == 4) ?
   1804               AF_INET : AF_INET6);
   1805         break;
   1806       case 5:
   1807         if (!*++argv) show_iproute_help();
   1808         idx = substring_to_idx(*argv, cmd_objectlist);
   1809         if (idx == 6) gfilter.tb = -1;
   1810         else if (idx == 9) gfilter.tb = 0;
   1811         else if (idx != 13) {
   1812           if ((gfilter.tb = idxfromRPDB(*argv, RPDB_rttables)) < 0)
   1813             error_exit("table %s is invalid.", *argv);
   1814         }
   1815         break;
   1816       case 6:
   1817         gfilter.tb = -1;
   1818         break;
   1819       case 7:
   1820         if (!*++argv) show_iproute_help();
   1821         idx = substring_to_idx(*argv, cmd_objectlist);
   1822         if (idx < 0)  if (!*++argv) show_iproute_help();
   1823         if (idx == 10)
   1824            if (!*++argv) show_iproute_help();
   1825           parse_prefix(gfilter.rsrc.addr, &gfilter.rsrc.netmask,
   1826               &gfilter.rsrc.len, *argv, gfilter.rsrc.family);
   1827         if (gfilter.rsrc.len)
   1828           gfilter.rsrc.family = ((gfilter.rsrc.len == 4) ?
   1829               AF_INET : AF_INET6);
   1830         else {
   1831           if ((idx == 12 ||idx == 11) && !*++argv) show_iproute_help();
   1832           parse_prefix(gfilter.msrc.addr, &gfilter.msrc.netmask,
   1833               &gfilter.msrc.len, *argv, gfilter.msrc.family);
   1834           if (gfilter.msrc.len)
   1835             gfilter.msrc.family = ((gfilter.msrc.len == 4) ?
   1836                 AF_INET : AF_INET6);
   1837           if (idx != 11) gfilter.rsrc = gfilter.msrc;
   1838         }
   1839         break;
   1840       case 8:
   1841         idx = substring_to_idx(*argv, cmd_objectlist);
   1842         if (idx != -1 && !*++argv) show_iproute_help();
   1843       default: // fallthrough
   1844         if (idx == 10) {
   1845           if (!*++argv) show_iproute_help();
   1846           parse_prefix(gfilter.rdst.addr, &gfilter.rdst.netmask,
   1847               &gfilter.rdst.len, *argv, gfilter.rdst.family);
   1848         if (gfilter.rdst.len)
   1849           gfilter.rdst.family = ((gfilter.rdst.len == 4) ?
   1850               AF_INET : AF_INET6);
   1851         }
   1852         else {
   1853           if ((idx == 12 ||idx == 11) && !*++argv) show_iproute_help();
   1854           parse_prefix(gfilter.mdst.addr, &gfilter.mdst.netmask,
   1855               &gfilter.mdst.len, *argv, gfilter.mdst.family);
   1856           if (gfilter.mdst.len)
   1857             gfilter.mdst.family = ((gfilter.mdst.len == 4) ?
   1858                 AF_INET : AF_INET6);
   1859           if (idx != 11) gfilter.rdst = gfilter.mdst;
   1860         }
   1861         break;
   1862     }
   1863   }
   1864   if (family == AF_UNSPEC && gfilter.tb) family = AF_INET;
   1865 
   1866   if (TT.flush) {
   1867     if (gfilter.tb < 0) { // flush table cache
   1868       if (family != AF_INET6) {
   1869         FILE *fp = xfopen("/proc/sys/net/ipv4/route/flush", "w");
   1870 
   1871         if (fwrite("-1",1,2,fp) < 2) error_exit("can't flush routing cache");
   1872         fclose(fp);
   1873       }
   1874       if (family == AF_INET) return 0;
   1875     }
   1876   }
   1877 
   1878   memset(&request, 0, sizeof (request));
   1879   request.mhdr.nlmsg_len = NLMSG_LENGTH(sizeof (struct rtmsg));
   1880   request.mhdr.nlmsg_flags = NLM_F_REQUEST;
   1881   request.mhdr.nlmsg_flags |= NLM_F_ROOT | NLM_F_MATCH;
   1882   request.mhdr.nlmsg_type = RTM_GETROUTE;
   1883   request.msg.rtm_family = family;
   1884   if (gfilter.tb < 0) request.msg.rtm_flags = RTM_F_CLONED;
   1885   send_nlmesg(0, 0, 0, (void*)&request, sizeof (request));
   1886   return (filter_nlmesg(display_route_info, NULL));
   1887 }
   1888 
   1889 static int route_update(char **argv, unsigned int route_flags)
   1890 {
   1891   char mxbuf[256], *d = NULL;
   1892   struct rtattr *mxrta = (void*)mxbuf;
   1893   unsigned mxlock = 0, ok = 0;
   1894   int idx;
   1895   uint32_t addr[8] = {0,}, netmask = 0;
   1896   uint8_t len = 0;
   1897 
   1898   struct arglist cmd_objectlist[] = {{"src", 0}, {"via", 1}, {"mtu", 2},
   1899     {"lock", 3}, {"protocol", 4}, {"table", 5}, {"dev", 6}, {"oif", 7},
   1900     {"to", 8}, {"metric", 9}, {NULL,-1}
   1901   };
   1902   enum {
   1903     gtwy_ok = 1,
   1904     dst_ok = 2,
   1905     proto_ok = 4,
   1906     type_ok = 8
   1907   };
   1908   struct {
   1909     struct nlmsghdr hdr;
   1910     struct rtmsg msg;
   1911     char buf[1024];
   1912   } req;
   1913 
   1914   memset(&req, 0, sizeof(req));
   1915   req.hdr.nlmsg_len = NLMSG_LENGTH(sizeof(struct rtmsg));
   1916   req.hdr.nlmsg_flags = NLM_F_ACK| NLM_F_REQUEST | route_flags;
   1917   req.hdr.nlmsg_type = TT.route_cmd;
   1918   req.msg.rtm_family = AF_UNSPEC;
   1919   req.msg.rtm_table = RT_TABLE_MAIN;
   1920   req.msg.rtm_scope = RT_SCOPE_NOWHERE;
   1921 
   1922   if (TT.route_cmd != RTM_DELROUTE) {
   1923     req.msg.rtm_protocol = RTPROT_BOOT;
   1924     req.msg.rtm_scope = RT_SCOPE_UNIVERSE;
   1925     req.msg.rtm_type = RTN_UNICAST;
   1926   }
   1927 
   1928   mxrta->rta_type = RTA_METRICS;
   1929   mxrta->rta_len = RTA_LENGTH(0);
   1930 
   1931   for (; *argv; argv++) {
   1932     idx = substring_to_idx(*argv, cmd_objectlist);
   1933     if (!idx) {
   1934       if (!*++argv) show_iproute_help();
   1935       parse_prefix(addr, &netmask, &len, *argv, req.msg.rtm_family);
   1936       if (len) req.msg.rtm_family = ((len == 4) ? AF_INET : AF_INET6);
   1937       add_string_to_rtattr(&req.hdr, sizeof(req), RTA_PREFSRC, addr, len);
   1938     } else if (idx == 1) {
   1939       ok |= gtwy_ok;
   1940       if (!*++argv) show_iproute_help();
   1941       parse_prefix(addr, &netmask, &len, *argv, req.msg.rtm_family);
   1942       if (len) req.msg.rtm_family = ((len == 4) ? AF_INET : AF_INET6);
   1943       add_string_to_rtattr(&req.hdr, sizeof(req),RTA_GATEWAY, addr, len);
   1944     } else if (idx == 2) {
   1945       if (!*++argv) show_iproute_help();
   1946       if (substring_to_idx(*argv, cmd_objectlist ) == 3) {
   1947         mxlock |= (1 << RTAX_MTU);
   1948         if (!*++argv) show_iproute_help();
   1949       }
   1950       idx = atolx(*argv);
   1951       add_string_to_rtattr(&req.hdr, sizeof(req),
   1952           RTAX_MTU, (char*)&idx, sizeof(idx));
   1953     } else if (idx == 4) {
   1954       if (!*++argv) show_iproute_help();
   1955       if ((idx = idxfromRPDB(*argv,RPDB_rtprotos)) < 0)
   1956       error_exit("Invalid argument protocol %s.",*argv);
   1957       req.msg.rtm_protocol = idx;
   1958       ok |= proto_ok;
   1959     } else if (idx == 5) {
   1960       if (!*++argv) show_iproute_help();
   1961       req.msg.rtm_table = idxfromRPDB(*argv, RPDB_rttables);
   1962     } else if (idx == 6 || idx == 7) {
   1963       if (!*++argv) show_iproute_help();
   1964       d = *argv;
   1965     } else if (idx == 9) {
   1966       unsigned long metric;
   1967       unsigned int res;
   1968       char* ptr;
   1969       if (!*++argv) show_iproute_help();
   1970       metric = strtoul(*argv, &ptr, 0);
   1971 		  if (!(!*ptr && metric <= 0xFFFFFFFFUL))
   1972         error_exit("Invalid argument metric %s.",*argv);
   1973       else
   1974         res = metric;
   1975       add_string_to_rtattr(&req.hdr, sizeof(req),
   1976           RTA_PRIORITY, (char*)&res, sizeof(res));
   1977     } else {
   1978       if (idx == 8)
   1979         if (!*++argv) show_iproute_help();
   1980       idx = substring_to_idx(*argv,rtmtypes);
   1981       if (idx != -1) {
   1982         if (!*++argv) show_iproute_help();
   1983         req.msg.rtm_type = idx;
   1984         ok |= type_ok;
   1985       }
   1986       if (ok & dst_ok) error_exit("Duplicate argument 'to'");
   1987       parse_prefix(addr, &netmask, &len, *argv, req.msg.rtm_family);
   1988       if (len) req.msg.rtm_family = ((len == 4) ? AF_INET : AF_INET6);
   1989       req.msg.rtm_dst_len = netmask;
   1990       ok |= dst_ok;
   1991       if (len) add_string_to_rtattr(&req.hdr, sizeof(req),RTA_DST, addr, len);
   1992     }
   1993   }
   1994 
   1995   if (d) {
   1996     idx = get_ifaceindex(d,1);
   1997     add_string_to_rtattr(&req.hdr, sizeof(req),
   1998         RTA_OIF, (char*)&idx, sizeof(idx));
   1999   }
   2000   if (mxrta->rta_len > RTA_LENGTH(0)) {
   2001     if (mxlock)
   2002       add_string_to_rtattr(&req.hdr, sizeof(req),
   2003           RTAX_LOCK, (char*)&mxlock, sizeof(mxlock));
   2004     add_string_to_rtattr(&req.hdr, sizeof(req),
   2005         RTA_METRICS, RTA_DATA(mxrta), RTA_PAYLOAD(mxrta));
   2006   }
   2007 
   2008   if (req.msg.rtm_type == RTN_LOCAL || req.msg.rtm_type == RTN_NAT)
   2009     req.msg.rtm_scope = RT_SCOPE_HOST;
   2010   else if (req.msg.rtm_type == RTN_BROADCAST||req.msg.rtm_type == RTN_MULTICAST
   2011       || req.msg.rtm_type == RTN_ANYCAST)
   2012     req.msg.rtm_scope = RT_SCOPE_LINK;
   2013   else if (req.msg.rtm_type == RTN_UNICAST || req.msg.rtm_type == RTN_UNSPEC) {
   2014     if (TT.route_cmd == RTM_DELROUTE)
   2015       req.msg.rtm_scope = RT_SCOPE_NOWHERE;
   2016     else if (!(ok & gtwy_ok))
   2017       req.msg.rtm_scope = RT_SCOPE_LINK;
   2018   }
   2019   if (req.msg.rtm_family == AF_UNSPEC) req.msg.rtm_family = AF_INET;
   2020   send_nlmesg(0, 0, 0, &req, sizeof(req));
   2021   filter_nlmesg(NULL, NULL);
   2022   return 0;
   2023 }
   2024 
   2025 static int iproute(char **argv)
   2026 {
   2027   int idx = 1;
   2028   struct arglist cmd_objectlist1[] = {{"add", 0}, {"append", 1},{"change", 2},
   2029     {"chg", 3},{"delete",4}, {"get", 5}, {"list", 6}, {"show", 7},
   2030     {"prepend", 8},{"replace", 9},{"test", 10}, {"flush", 11},{NULL,-1}};
   2031 
   2032   TT.route_cmd = RTM_NEWROUTE;
   2033   switch (idx = substring_to_idx(*argv , cmd_objectlist1)) {
   2034     case 0: // add
   2035       return route_update(++argv , NLM_F_CREATE|NLM_F_EXCL);
   2036     case 1: // append
   2037       return route_update(++argv , NLM_F_CREATE|NLM_F_APPEND);
   2038     case 2: // change
   2039     case 3: // chg
   2040       return route_update(++argv , NLM_F_REPLACE);
   2041     case 4: // delete
   2042       TT.route_cmd = RTM_DELROUTE;
   2043       return route_update(++argv , RTM_DELROUTE);
   2044     case 5:
   2045       return route_get(++argv);
   2046     case 6:
   2047     case 7:
   2048       return route_show_flush(++argv);
   2049     case 8: // prepend
   2050       return route_update(++argv , NLM_F_CREATE);
   2051     case 9: // replace
   2052       return route_update(++argv ,  NLM_F_CREATE|NLM_F_REPLACE);
   2053     case 10: // test
   2054       return route_update(++argv , NLM_F_EXCL);
   2055     case 11: // flush
   2056       return route_show_flush(++argv);
   2057     default:
   2058       if (!*argv) return route_show_flush(argv);
   2059       else show_iproute_help();
   2060   }
   2061   return 0; // non reachable code.
   2062 }
   2063 
   2064 
   2065 // ===========================================================================
   2066 // code for ip rule.
   2067 // ===========================================================================
   2068 static void show_iprule_help(void)
   2069 {
   2070   char *errmsg = "Usage: ip rule [ list | add | del ] SELECTOR ACTION\n"
   2071     "SELECTOR := [ from PREFIX ] [ to PREFIX ] [pref NUMBER] [ tos TOS ]\n"
   2072     "            [ fwmark FWMARK] [ dev/iif STRING ] [type TYPE]\n"
   2073     "ACTION := [ table TABLE_ID ] [ realms [SRCREALM/]DSTREALM ]";
   2074 
   2075   error_exit(errmsg);
   2076 }
   2077 
   2078 static int ruleupdate(char **argv)
   2079 {
   2080   int8_t idx, tflag = 0, opt = (*argv[-1] == 'a') ? RTM_NEWRULE : RTM_DELRULE;
   2081   struct arglist options[] = {{"from", 0}, {"to", 1}, {"preference", 2},
   2082     {"order", 2}, {"priority", 2}, {"tos", 3}, {"dsfield", 3}, {"fwmark", 4},
   2083     {"realms", 5}, {"table", 6}, {"lookup", 6}, {"dev", 7}, {"iif", 7},
   2084     {"nat", 8}, {"map-to", 8}, {"type", 9}, {"help", 10}, {NULL, -1}};
   2085   struct {
   2086     struct nlmsghdr mhdr;
   2087     struct rtmsg    msg;
   2088     char buf[1024];
   2089   } request;
   2090 
   2091   memset(&request, 0, sizeof(request));
   2092   request.mhdr.nlmsg_type = opt;
   2093   request.mhdr.nlmsg_len = NLMSG_LENGTH(sizeof(struct rtmsg));
   2094   request.mhdr.nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK |
   2095     ((opt == RTM_DELRULE) ? 0 : NLM_F_CREATE | NLM_F_EXCL);
   2096   request.msg.rtm_family = TT.addressfamily;
   2097   request.msg.rtm_protocol = RTPROT_BOOT;
   2098   request.msg.rtm_scope = RT_SCOPE_UNIVERSE;
   2099   request.msg.rtm_table = 0;
   2100   request.msg.rtm_type = ((opt == RTM_DELRULE) ? RTN_UNSPEC : RTN_UNICAST);
   2101 
   2102   for (; *argv; argv++) {
   2103     switch ((idx = substring_to_idx(*argv, options))) {
   2104       case 0:
   2105       case 1:
   2106         { // e.g. from IP/Netmask and to IP/Netmask.
   2107           uint32_t addr[4] = {0,}, netmask = 0;
   2108           uint8_t len = 0, *tmp;
   2109 
   2110           if (!*++argv) error_exit("'%s': Missing Prefix", argv[-1]);
   2111           parse_prefix(addr, &netmask, &len, *argv, request.msg.rtm_family);
   2112 
   2113           tmp = idx ? &request.msg.rtm_dst_len : &request.msg.rtm_src_len;
   2114           if (!netmask) *tmp = 0;
   2115           else *tmp = netmask;
   2116 
   2117           add_string_to_rtattr(&request.mhdr, sizeof(request),
   2118               (idx ? RTA_DST : RTA_SRC), addr, len);
   2119         }
   2120         break;
   2121       case 2:
   2122       case 4:
   2123         { // e.g. Preference p# and fwmark MARK
   2124           uint32_t pref;
   2125           char *ptr;
   2126 
   2127           if (!*++argv)
   2128             error_exit("Missing %s", (idx == 2) ? "Preference" : "fwmark");
   2129           pref = strtoul(*argv, &ptr, 0);
   2130           if (!ptr || (ptr == *argv) || *ptr  || pref > 0xFFFFFFFFUL)
   2131             error_exit("Invalid %s",  (idx == 2) ? "Preference" : "fwmark");
   2132           add_string_to_rtattr(&request.mhdr, sizeof(request),
   2133               ((idx == 2) ? RTA_PRIORITY : RTA_PROTOINFO),
   2134               (void *)&pref, sizeof(uint32_t));
   2135         }
   2136         break;
   2137       case 3:
   2138         {
   2139           uint32_t tos;
   2140           if (!*++argv) error_exit("Missing TOS key");
   2141           if ((tos = idxfromRPDB(*argv, RPDB_rtdsfield)) < 0)
   2142             error_exit("Invalid TOS");
   2143           request.msg.rtm_tos = tos;
   2144         }
   2145         break;
   2146       case 5:
   2147         { // e.g. realms FROM_realm/TO_realm
   2148           uint32_t realms = 0;
   2149           int ret;
   2150           char *ptr;
   2151 
   2152           if (!*++argv) error_exit("Missing REALMSID");
   2153           if ((ptr = strchr(*argv, '/'))) {
   2154             *ptr = 0;
   2155             if ((ret = idxfromRPDB(*argv, RPDB_rtrealms)) < 0)
   2156               error_exit("Invalid realms");
   2157             realms = ret;
   2158             realms <<= 16;
   2159             *ptr++ = '/';
   2160           } else ptr = *argv;
   2161           if ((ret = idxfromRPDB(ptr, RPDB_rtrealms)) < 0)
   2162             error_exit("Invalid realms");
   2163           realms |= ret;
   2164           add_string_to_rtattr(&request.mhdr, sizeof(request),
   2165               RTA_FLOW, (void *)&realms, sizeof(uint32_t));
   2166         }
   2167         break;
   2168       case 6:
   2169         { // e.g. table tid/tableName
   2170           int tid;
   2171           if (!*++argv) error_exit("Missing TableID");
   2172           if ((tid = idxfromRPDB(*argv, RPDB_rttables)) < 0)
   2173             error_exit("Invalid TID");
   2174           request.msg.rtm_table = tid;
   2175           tflag = 1;
   2176         }
   2177         break;
   2178       case 7:
   2179         {
   2180           if (!*++argv) error_exit("Missing dev/iif NAME");
   2181           add_string_to_rtattr(&request.mhdr, sizeof(request),
   2182               RTA_IIF, *argv, strlen(*argv)+1);
   2183         }
   2184         break;
   2185       case 8:
   2186         {
   2187           uint32_t addr[4] = {0,};
   2188           uint8_t af = AF_UNSPEC;
   2189 
   2190           if (!*++argv) error_exit("Missing nat/map-to ADDRESS");
   2191           if (get_prefix(addr, &af /* Un-used variable */, *argv, AF_INET))
   2192             error_exit("Invalid mapping Address");
   2193 
   2194           add_string_to_rtattr(&request.mhdr, sizeof(request),
   2195               RTA_GATEWAY, addr, sizeof(uint32_t));
   2196           request.msg.rtm_type = RTN_NAT;
   2197         }
   2198         break;
   2199       case 9:
   2200         {
   2201           if (!*++argv) error_exit("TYPE Missing");
   2202           request.msg.rtm_type = rtmtype_str2idx(*argv);
   2203         }
   2204         break;
   2205       case 10:
   2206         show_iprule_help();
   2207         break; // Unreachable code.
   2208       default:
   2209         error_exit("Invalid argument '%s'", *argv);
   2210         break; // Unreachable code.
   2211     }
   2212   }
   2213 
   2214   if (!request.msg.rtm_family) request.msg.rtm_family = AF_INET;
   2215   if (!tflag && opt == RTM_NEWRULE) request.msg.rtm_table = RT_TABLE_MAIN;
   2216 
   2217   send_nlmesg(0, 0, 0, &request, sizeof(request));
   2218   return (filter_nlmesg(NULL, NULL));
   2219 }
   2220 
   2221 static int show_rules(struct nlmsghdr *mhdr,
   2222     char **argv __attribute__ ((__unused__)))
   2223 {
   2224   struct rtmsg *msg = NLMSG_DATA(mhdr);
   2225   struct rtattr *rta, *attr[RTA_MAX+1] = {0,};
   2226   int32_t tvar, msglen = mhdr->nlmsg_len - NLMSG_LENGTH(sizeof(struct rtmsg));
   2227   int hlen = ((msg->rtm_family == AF_INET) ? 32
   2228       : ((msg->rtm_family == AF_INET6) ? 128 : -1));
   2229 
   2230   if (mhdr->nlmsg_type != RTM_NEWRULE) return 0;
   2231   if (msglen < 0) return 1;
   2232 
   2233   tvar = msglen;
   2234   for (rta = RTM_RTA(msg); RTA_OK(rta, tvar); rta=RTA_NEXT(rta, tvar))
   2235     if (rta->rta_type <= RTA_MAX) attr[rta->rta_type] = rta;
   2236 
   2237   if (tvar) error_msg("deficit %d, rtalen = %d!", tvar, rta->rta_len);
   2238 
   2239   printf("%u:\tfrom ", attr[RTA_PRIORITY] ?
   2240       *(unsigned *)RTA_DATA(attr[RTA_PRIORITY]) : 0);
   2241 
   2242   if (attr[RTA_SRC]) {
   2243     printf("%s", (msg->rtm_family == AF_INET || msg->rtm_family == AF_INET6)
   2244         ? inet_ntop(msg->rtm_family, RTA_DATA(attr[RTA_SRC]),
   2245           toybuf, sizeof(toybuf))
   2246         : "???");
   2247     (msg->rtm_src_len != hlen) ? printf("/%u", msg->rtm_src_len) : 0;
   2248   } else msg->rtm_src_len ? printf("0/%d", msg->rtm_src_len) : printf("all");
   2249 
   2250   xputc(' ');
   2251   if (attr[RTA_DST]) {
   2252     printf("to %s", (msg->rtm_family == AF_INET || msg->rtm_family == AF_INET6)
   2253         ? inet_ntop(msg->rtm_family, RTA_DATA(attr[RTA_DST]),
   2254           toybuf, sizeof(toybuf))  : "???");
   2255     (msg->rtm_dst_len != hlen) ? printf("/%u", msg->rtm_dst_len) : xputc(' ');
   2256   } else if (msg->rtm_dst_len)
   2257     printf("to 0/%d ", msg->rtm_dst_len);
   2258 
   2259   if (msg->rtm_tos)
   2260     printf("tos %s ", namefromRPDB(msg->rtm_tos, RPDB_rtdsfield));
   2261 
   2262   if (attr[RTA_PROTOINFO])
   2263     printf("fwmark %#x ", *(uint32_t*)RTA_DATA(attr[RTA_PROTOINFO]));
   2264 
   2265   if (attr[RTA_IIF]) printf("iif %s ", (char*)RTA_DATA(attr[RTA_IIF]));
   2266 
   2267   if (msg->rtm_table)
   2268     printf("lookup %s ", namefromRPDB(msg->rtm_table, RPDB_rttables));
   2269 
   2270   if (attr[RTA_FLOW]) {
   2271     u_int32_t from, to = *(u_int32_t *)RTA_DATA(attr[RTA_FLOW]);
   2272     char *format = "realms %s/";
   2273 
   2274     to = (from = (to >> 16)) & 0xFFFF;
   2275     format = (from ? format: "%s");
   2276     printf(format, namefromRPDB((from ? from : to), RPDB_rtrealms));
   2277   }
   2278 
   2279   if (msg->rtm_type == RTN_NAT) {
   2280     if (!attr[RTA_GATEWAY]) printf("masquerade");
   2281     else printf("map-to %s ", inet_ntop(msg->rtm_family,
   2282           RTA_DATA(attr[RTA_GATEWAY]), toybuf, sizeof(toybuf)));
   2283   } else if (msg->rtm_type != RTN_UNICAST)
   2284     printf("%s", rtmtype_idx2str(msg->rtm_type));
   2285 
   2286   xputc('\n');
   2287   return 0;
   2288 }
   2289 
   2290 static int rulelist(char **argv)
   2291 {
   2292   if (*argv) {
   2293     error_msg("'ip rule show' does not take any arguments.");
   2294     return 1;
   2295   }
   2296   send_nlmesg(RTM_GETRULE, NLM_F_ROOT | NLM_F_MATCH | NLM_F_REQUEST,
   2297       ((TT.addressfamily != AF_UNSPEC) ? TT.addressfamily : AF_INET), NULL, 0);
   2298   return filter_nlmesg(show_rules, argv);
   2299 }
   2300 
   2301 static int iprule(char **argv)
   2302 {
   2303   int idx;
   2304   struct arglist options[] = {{"add", 0}, {"delete", 0}, {"list", 1},
   2305     {"show", 1}, {NULL, -1}};
   2306   cmdobj ipcmd, cmdobjlist[] = {ruleupdate, rulelist};
   2307 
   2308   if (!*argv) idx = 1;
   2309   else if ((idx = substring_to_idx(*argv++, options)) == -1)
   2310     show_iprule_help();
   2311   ipcmd = cmdobjlist[idx];
   2312   return ipcmd(argv);
   2313 }
   2314 //============================================================================
   2315 // code for ip tunnel.
   2316 //============================================================================
   2317 static void show_iptunnel_help(void)
   2318 {
   2319   char *errmsg = "Usage: iptunnel { add | change | del | show } [NAME]\n"
   2320     "           [mode { ipip | gre | sit }] [remote ADDR] [local ADDR]\n"
   2321     "           [[i|o]seq] [[i|o]key KEY] [[i|o]csum] [ttl TTL]\n"
   2322     "           [tos TOS] [[no]pmtudisc] [dev PHYS_DEV]";
   2323 
   2324   error_exit(errmsg);
   2325 }
   2326 
   2327 static int tnl_ioctl(char *dev, int rtype, struct ip_tunnel_parm *ptnl)
   2328 {
   2329   struct ifreq req;
   2330   int fd, ret = 0;
   2331 
   2332   if ((rtype == SIOCCHGTUNNEL || rtype == SIOCDELTUNNEL) && *ptnl->name)
   2333     xstrncpy(req.ifr_name, ptnl->name, IF_NAMESIZE);
   2334   else xstrncpy(req.ifr_name, dev, IF_NAMESIZE);
   2335 
   2336   if (rtype != SIOCGIFHWADDR) req.ifr_ifru.ifru_data = (void*)ptnl;
   2337   fd = xsocket(AF_INET, SOCK_DGRAM, 0);
   2338 
   2339   if (rtype == SIOCGETTUNNEL) ret = ioctl(fd, rtype, &req);
   2340   else if (rtype == SIOCGIFHWADDR)
   2341     ret = (ioctl(fd, rtype, &req) < 0) ? -1 : req.ifr_addr.sa_family;
   2342   else xioctl(fd, rtype, &req);
   2343 
   2344   close(fd);
   2345   return ret;
   2346 }
   2347 
   2348 static int display_tunnel(struct ip_tunnel_parm *ptnl)
   2349 {
   2350   char rmt_addr[64], lcl_addr[64], ikey_str[64], okey_str[64];
   2351 
   2352   printf("%s: %s/ip", ptnl->name, ptnl->iph.protocol == IPPROTO_IPIP ? "ip" :
   2353       (ptnl->iph.protocol == IPPROTO_GRE ? "gre" :
   2354        (ptnl->iph.protocol == IPPROTO_IPV6 ? "ipv6" : "unknown")));
   2355   printf("  remote %s  local %s ", ptnl->iph.daddr ?
   2356       inet_ntop(AF_INET, &ptnl->iph.daddr, rmt_addr, sizeof(rmt_addr)) : "any",
   2357       ptnl->iph.saddr ? inet_ntop(AF_INET, &ptnl->iph.saddr, lcl_addr,
   2358         sizeof(lcl_addr)) : "any");
   2359   if (ptnl->link) {
   2360     struct ifreq req;
   2361     int fd;
   2362 
   2363     req.ifr_ifindex = ptnl->link;
   2364     fd = xsocket(AF_INET, SOCK_DGRAM, 0);
   2365     if (ioctl(fd, SIOCGIFNAME, &req) < 0) perror_msg("SIOCGIFNAME");
   2366     else printf(" dev %s ", req.ifr_name);
   2367     close(fd);
   2368   }
   2369   if (ptnl->iph.ttl) printf(" ttl %d ", ptnl->iph.ttl);
   2370   else printf(" ttl inherit ");
   2371 
   2372   if (ptnl->iph.tos) {
   2373     printf(" tos");
   2374     if (ptnl->iph.tos & 1) printf(" inherit");
   2375     if (ptnl->iph.tos & ~1) printf("%c%s ", ptnl->iph.tos & 1 ? '/' : ' ',
   2376         namefromRPDB((ptnl->iph.tos & ~1), RPDB_rtdsfield));
   2377   }
   2378   if (!(ptnl->iph.frag_off & htons(IP_DF))) printf(" nopmtudisc");
   2379   inet_ntop(AF_INET, &ptnl->i_key, ikey_str, sizeof(ikey_str));
   2380   if ((ptnl->i_flags & GRE_KEY) && (ptnl->o_flags & GRE_KEY)
   2381       && ptnl->o_key == ptnl->i_key) printf(" key %s", ikey_str);
   2382   else if ((ptnl->i_flags | ptnl->o_flags) & GRE_KEY) {
   2383     inet_ntop(AF_INET, &ptnl->o_key, okey_str, sizeof(okey_str));
   2384     if (ptnl->i_flags & GRE_KEY) printf(" ikey %s ", ikey_str);
   2385     if (ptnl->o_flags & GRE_KEY) printf(" okey %s ", okey_str);
   2386   }
   2387   if (ptnl->i_flags & GRE_SEQ) printf("\n  Drop packets out of sequence.\n");
   2388   if (ptnl->i_flags & GRE_CSUM)
   2389     printf("\n  Checksum in received packet is required.");
   2390   if (ptnl->o_flags & GRE_SEQ) printf("\n  Sequence packets on output.");
   2391   if (ptnl->o_flags & GRE_CSUM) printf("\n  Checksum output packets.");
   2392   xputc('\n');
   2393   return 0;
   2394 }
   2395 
   2396 static int read_tunnel(struct ip_tunnel_parm *ptnl)
   2397 {
   2398   int count = 0;
   2399   char iface[IF_NAMESIZE];
   2400   struct ip_tunnel_parm iptnl;
   2401   FILE *fp = xfopen("/proc/net/dev", "r");
   2402 
   2403   while (fgets(toybuf, sizeof(toybuf), fp)) {
   2404     char *ptr;
   2405     int ret;
   2406 
   2407     if (count++ < 2) continue; // 1st two lines are header.
   2408 
   2409     ptr = strchr(toybuf, ':');
   2410     if (!ptr || (*ptr++ = 0, sscanf(toybuf, "%s", iface) != 1))
   2411       error_exit("invalid format of '/proc/net/dev'");
   2412     if (*ptnl->name && strcmp(ptnl->name, iface)) continue;
   2413     if ((ret = tnl_ioctl(iface, SIOCGIFHWADDR, &iptnl)) < 0) {
   2414       error_msg("failed to get type of '%s'", iface);
   2415       continue;
   2416     }
   2417     if (ret != ARPHRD_TUNNEL && ret !=  ARPHRD_SIT &&
   2418         ret != ARPHRD_IPGRE) continue;
   2419 
   2420     memset(&iptnl, 0, sizeof(iptnl));
   2421     if (tnl_ioctl(iface, SIOCGETTUNNEL, &iptnl) < 0) continue;
   2422     if ((ptnl->link && iptnl.link != ptnl->link) || (*ptnl->name &&
   2423           strcmp(iptnl.name, ptnl->name)) || (ptnl->iph.daddr &&
   2424           iptnl.iph.daddr != ptnl->iph.daddr) || (ptnl->iph.saddr &&
   2425             iptnl.iph.saddr != ptnl->iph.saddr) || (ptnl->i_key &&
   2426               iptnl.i_key != ptnl->i_key)) continue;
   2427     display_tunnel(&iptnl);
   2428   }
   2429   fclose(fp);
   2430   return 0;
   2431 }
   2432 
   2433 static void parse_iptunnel_args(struct ip_tunnel_parm *ptnl, char **argv,
   2434     int ipt_opt_idx)
   2435 {
   2436   int idx;
   2437   uint8_t af = AF_INET;
   2438   uint32_t addr = 0;
   2439   struct arglist opts[] = { {"mode", 0}, {"key", 1}, {"ikey", 2},
   2440     {"okey", 3}, {"seq", 4}, {"iseq", 5}, {"oseq", 6}, {"csum", 7},
   2441     {"icsum", 8}, {"ocsum", 9}, {"nopmtudisc", 10}, {"pmtudisc", 11},
   2442     {"remote", 12}, {"local", 13},{"dev", 14}, {"ttl", 15}, {"tos", 16},
   2443     {"dsfield", 17}, {"name", 18}, {NULL, -1}
   2444   };
   2445 
   2446   ptnl->iph.version = 4; // The value indicates the version of IP (4 or 6)
   2447   ptnl->iph.ihl = 5; // Minimum Internet Header Length
   2448   // frag_off is measured in units of 8 octets (64 bits)
   2449   ptnl->iph.frag_off = htons(IP_DF);
   2450   if (*argv && ipt_opt_idx <= 2 && string_to_idx(*argv, opts) == -1) {
   2451     xstrncpy(ptnl->name, *argv, IF_NAMESIZE);
   2452     if (ipt_opt_idx == 1) {
   2453       struct ip_tunnel_parm iptnl_old;
   2454 
   2455       memset(&iptnl_old, 0, sizeof(iptnl_old));
   2456       tnl_ioctl(ptnl->name, SIOCGETTUNNEL, &iptnl_old);
   2457       *ptnl = iptnl_old;
   2458     }
   2459     argv++;
   2460   }
   2461   for (; *argv; argv++, addr = 0) {
   2462     switch (idx = string_to_idx(*argv, opts)) {
   2463       case 0:
   2464         if (!*++argv) error_exit("mode is missing");
   2465         if ((!strcmp("ipip", *argv) || !strcmp("ip/ip", *argv)))
   2466           ptnl->iph.protocol = IPPROTO_IPIP;
   2467         else if ((!strcmp("gre", *argv) || !strcmp("gre/ip", *argv)))
   2468           ptnl->iph.protocol = IPPROTO_GRE;
   2469         else if ((!strcmp("sit", *argv) || !strcmp("ipv6/ip", *argv)))
   2470           ptnl->iph.protocol = IPPROTO_IPV6;
   2471         else show_iptunnel_help();
   2472         break;
   2473       case 1:
   2474       case 2:
   2475       case 3:
   2476         {
   2477           struct addrinfo *info, hint;
   2478           int ret;
   2479 
   2480           if (!*++argv) error_exit("key value is missing");
   2481           memset(&hint, 0, sizeof(hint));
   2482           hint.ai_family = AF_INET;
   2483           ret = getaddrinfo(*argv, NULL, &hint, &info);
   2484           if (ret || !info) error_exit("invalid argument to key");
   2485           freeaddrinfo(info);
   2486 
   2487           if (strchr(*argv, '.')) {
   2488             if (get_prefix(&addr, &af, *argv, AF_INET))
   2489               error_exit("invalid key '%s'", *argv);
   2490           } else {
   2491             unsigned key_val;
   2492 
   2493             sscanf(*argv, "%u", &key_val);
   2494             addr = htonl(key_val);
   2495           }
   2496           if (idx == 1) {
   2497             ptnl->i_flags |= GRE_KEY;
   2498             ptnl->o_flags |= GRE_KEY;
   2499             ptnl->i_key = ptnl->o_key = addr;
   2500           } else if (idx == 2) {
   2501             ptnl->i_flags |= GRE_KEY;
   2502             ptnl->i_key = addr;
   2503           } else {
   2504             ptnl->o_flags |= GRE_KEY;
   2505             ptnl->o_key = addr;
   2506           }
   2507         }
   2508         break;
   2509       case 4:
   2510         ptnl->i_flags |= GRE_SEQ;
   2511         ptnl->o_flags |= GRE_SEQ;
   2512         break;
   2513       case 5:
   2514         ptnl->i_flags |= GRE_SEQ;
   2515         break;
   2516       case 6:
   2517         ptnl->o_flags |= GRE_SEQ;
   2518         break;
   2519       case 7:
   2520         ptnl->i_flags |= GRE_CSUM;
   2521         ptnl->o_flags |= GRE_CSUM;
   2522         break;
   2523       case 8:
   2524         ptnl->i_flags |= GRE_CSUM;
   2525         break;
   2526       case 9:
   2527         ptnl->o_flags |= GRE_CSUM;
   2528         break;
   2529       case 10:
   2530         ptnl->iph.frag_off = 0;
   2531         break;
   2532       case 11:
   2533         ptnl->iph.frag_off = htons(IP_DF);
   2534         break;
   2535       case 12:
   2536       case 13:
   2537         if (!*++argv) error_exit("remote/local address is missing");
   2538         if (get_prefix(&addr, &af, *argv, AF_INET))
   2539           error_exit("invalid remote/local address '%s'", *argv);
   2540         (idx == 12) ? (ptnl->iph.daddr = addr) : (ptnl->iph.saddr = addr);
   2541         break;
   2542       case 14:
   2543         if (!*++argv) error_exit("device name is missing");
   2544         else {
   2545           struct ifreq req;
   2546           int fd;
   2547 
   2548           xstrncpy(req.ifr_name, *argv, IFNAMSIZ);
   2549           fd = xsocket(AF_INET, SOCK_DGRAM, 0);
   2550           xioctl(fd, SIOCGIFINDEX, &req);
   2551           close(fd);
   2552           ptnl->link = req.ifr_ifindex;
   2553         }
   2554         break;
   2555       case 15:
   2556         if (!*++argv) error_exit("ttl value is missing");
   2557         if (strcmp(*argv, "inherit"))
   2558           ptnl->iph.ttl = atolx_range(*argv, 0, 255);
   2559         break;
   2560       case 16:
   2561       case 17:
   2562         if (!*++argv) error_exit("tos value is missing");
   2563         if (strcmp(*argv, "inherit")) {
   2564           char *ptr;
   2565           unsigned long tval = strtoul(*argv, &ptr, 16);
   2566 
   2567           if (tval > 255) error_exit("invalid tos value '%s'", *argv);
   2568           if (*ptr) {
   2569             int ret;
   2570 
   2571             if ((ret = idxfromRPDB(*argv, RPDB_rtdsfield)) < 0)
   2572               error_exit("invalid tos value");
   2573             ptnl->iph.tos = ret;
   2574           } else ptnl->iph.tos = tval;
   2575         } else ptnl->iph.tos = 1;
   2576         break;
   2577       case 18:
   2578         if (*ptnl->name) error_exit("invalid tunnel");
   2579         else {
   2580           if (!*++argv) error_exit("name is missing");
   2581           xstrncpy(ptnl->name, *argv, IF_NAMESIZE);
   2582         }
   2583         break;
   2584       default:
   2585         if (*ptnl->name) error_exit("invalid tunnel");
   2586         xstrncpy(ptnl->name, *argv, IF_NAMESIZE);
   2587         break;
   2588     }
   2589   }
   2590   if (ptnl->iph.protocol == IPPROTO_IPIP ||
   2591       ptnl->iph.protocol == IPPROTO_IPV6) {
   2592     if ((ptnl->i_flags & GRE_KEY) || (ptnl->o_flags & GRE_KEY))
   2593       error_exit("[i|o]key is allowed with gre only");
   2594     if ((ptnl->i_flags & GRE_SEQ) || (ptnl->o_flags & GRE_SEQ))
   2595       error_exit("[i|o]seq is allowed with gre only");
   2596     if ((ptnl->i_flags & GRE_CSUM) || (ptnl->o_flags & GRE_CSUM))
   2597       error_exit("[i|o]csum is allowed with gre only");
   2598   }
   2599   if (!ptnl->i_key && IN_MULTICAST(ntohl(ptnl->iph.daddr))) {
   2600     ptnl->i_key = ptnl->iph.daddr;
   2601     ptnl->i_flags |= GRE_KEY;
   2602   }
   2603   if (!ptnl->o_key && IN_MULTICAST(ntohl(ptnl->iph.daddr))) {
   2604     ptnl->o_key = ptnl->iph.daddr;
   2605     ptnl->o_flags |= GRE_KEY;
   2606   }
   2607   if (IN_MULTICAST(ntohl(ptnl->iph.daddr)) && !ptnl->iph.saddr)
   2608     error_exit("broadcast tunnel requires a source address");
   2609 }
   2610 
   2611 static int tunnellist(char **argv)
   2612 {
   2613   struct ip_tunnel_parm iptnl;
   2614   int ret = 0;
   2615 
   2616   memset(&iptnl, 0, sizeof(iptnl));
   2617   parse_iptunnel_args(&iptnl, argv, 3);
   2618 
   2619   if (iptnl.iph.protocol == IPPROTO_IPIP)
   2620     ret = tnl_ioctl(*iptnl.name ? iptnl.name : "tunl0", SIOCGETTUNNEL, &iptnl);
   2621   else if (iptnl.iph.protocol == IPPROTO_GRE)
   2622     ret = tnl_ioctl(*iptnl.name ? iptnl.name : "gre0", SIOCGETTUNNEL, &iptnl);
   2623   else if (iptnl.iph.protocol == IPPROTO_IPV6)
   2624     ret = tnl_ioctl(*iptnl.name ? iptnl.name : "sit0", SIOCGETTUNNEL, &iptnl);
   2625   else return read_tunnel(&iptnl);
   2626 
   2627   if (ret < 0) {
   2628     perror_msg("SIOCGETTUNNEL");
   2629     return ret;
   2630   } else return display_tunnel(&iptnl);
   2631 }
   2632 
   2633 // Performing add, change, & delete tunnel action, according to passed req_type
   2634 static int tunnelupdate(char **argv)
   2635 {
   2636   struct ip_tunnel_parm iptnl;
   2637   int idx = 2, rtype = SIOCDELTUNNEL;
   2638 
   2639   if (*argv[-1] == 'a') {
   2640     idx = 0;
   2641     rtype = SIOCADDTUNNEL;
   2642   } else if (*argv[-1] == 'c') {
   2643     idx = 1;
   2644     rtype = SIOCCHGTUNNEL;
   2645   }
   2646 
   2647   memset(&iptnl, 0, sizeof(iptnl));
   2648   parse_iptunnel_args(&iptnl, argv, idx);
   2649   if (idx != 2 && iptnl.iph.ttl && !(iptnl.iph.frag_off))
   2650     error_exit("ttl > 0 and nopmtudisc are incompatible");
   2651   if (iptnl.iph.protocol == IPPROTO_IPIP)
   2652     return (tnl_ioctl("tunl0", rtype, &iptnl) < 0) ? 1 : 0;
   2653   else if (iptnl.iph.protocol == IPPROTO_GRE)
   2654     return (tnl_ioctl("gre0", rtype, &iptnl) < 0) ? 1 : 0;
   2655   else if (iptnl.iph.protocol == IPPROTO_IPV6)
   2656     return (tnl_ioctl("sit0", rtype, &iptnl) < 0) ? 1 : 0;
   2657   else {
   2658     if (idx != 2) error_exit("invalid tunnel mode");
   2659     return (tnl_ioctl(iptnl.name, rtype, &iptnl) < 0) ? 1 : 0;
   2660   }
   2661 }
   2662 
   2663 static int iptunnel(char **argv)
   2664 {
   2665   int idx;
   2666   struct arglist opts[] = {{"add", 0}, {"change", 0}, {"del", 0},
   2667     {"delete", 0}, {"show", 1}, {"list", 1}, {"lst", 1}, {NULL, -1}
   2668   };
   2669   cmdobj ipcmd, cmdobjlist[] = {tunnelupdate, tunnellist};
   2670 
   2671   if (!*argv) idx = 1;
   2672   else if ((idx = substring_to_idx(*argv++, opts)) == -1)
   2673     show_iptunnel_help();
   2674   ipcmd = cmdobjlist[idx];
   2675   return ipcmd(argv);
   2676 }
   2677 
   2678 // ===========================================================================
   2679 // Common code, which is used for all ip options.
   2680 // ===========================================================================
   2681 
   2682 // Parse netlink messages and call input callback handler for action
   2683 static int filter_nlmesg(int (*fun)(struct nlmsghdr *mhdr, char **argv),
   2684     char **argv)
   2685 {
   2686   while (1) {
   2687     struct nlmsghdr *mhdr;
   2688     int msglen = recv(TT.sockfd, TT.gbuf, MESG_LEN, 0);
   2689 
   2690     if ((msglen < 0) && (errno == EINTR || errno == EAGAIN)) continue;
   2691     else if (msglen < 0) {
   2692       error_msg("netlink receive error %s", strerror(errno));
   2693       return 1;
   2694     } else if (!msglen) {
   2695       error_msg("EOF on netlink");
   2696       return 1;
   2697     }
   2698 
   2699     for (mhdr = (struct nlmsghdr*)TT.gbuf; NLMSG_OK(mhdr, msglen);
   2700         mhdr = NLMSG_NEXT(mhdr, msglen)) {
   2701       int err;
   2702       if (mhdr->nlmsg_pid != getpid())
   2703         continue;
   2704       switch (mhdr->nlmsg_type) {
   2705         case NLMSG_DONE:
   2706           return 0;
   2707         case NLMSG_ERROR:
   2708           {
   2709             struct nlmsgerr *merr = (struct nlmsgerr*)NLMSG_DATA(mhdr);
   2710 
   2711             if (merr->error == 0) return 0;
   2712             if (mhdr->nlmsg_len < NLMSG_LENGTH(sizeof(struct nlmsgerr)))
   2713               error_msg("ERROR truncated");
   2714             else {
   2715               errno = -merr->error;
   2716               perror_msg("RTNETLINK answers");
   2717             }
   2718             return 1;
   2719           }
   2720         default:
   2721           if (fun && (err = fun(mhdr, argv))) return err;
   2722           break;
   2723       }
   2724     } // End of for loop.
   2725   } // End of while loop.
   2726   return 0;
   2727 }
   2728 
   2729 void ip_main(void)
   2730 {
   2731   char **optargv = toys.argv;
   2732   int idx, isip = !(toys.which->name[2]); //1 -> if only ip
   2733   cmdobj ipcmd, cmdobjlist[] = {ipaddr, iplink, iproute, iprule, iptunnel};
   2734 
   2735   for (++optargv; *optargv; ++optargv) {
   2736     char *ptr = *optargv;
   2737     struct arglist ip_options[] = {{"oneline", 0}, {"family",  1},
   2738       {"4", 1}, {"6", 1}, {"0", 1}, {"stats", 2}, {NULL, -1}};
   2739 
   2740     if (*ptr != '-') break;
   2741     else if ((*(ptr+1) == '-') && (*(ptr+2))) ptr +=2;
   2742     //escape "--" and stop ip arg parsing.
   2743     else if ((*(ptr+1) == '-') && (!*(ptr+2))) {
   2744       *ptr +=1;
   2745       break;
   2746     } else ptr +=1;
   2747     switch (substring_to_idx(ptr, ip_options)) {
   2748       case 0: TT.singleline = 1;
   2749               break;
   2750       case 1: {
   2751                 if (isdigit(*ptr)) {
   2752                   long num = atolx(ptr);
   2753                   if (num == 4) TT.addressfamily  = AF_INET;
   2754                   else if (num == 6) TT.addressfamily  = AF_INET6;
   2755                   else TT.addressfamily = AF_PACKET;
   2756                 } else {
   2757                   struct arglist ip_aflist[] = {{"inet", AF_INET},
   2758                     {"inet6", AF_INET6}, {"link", AF_PACKET}, {NULL, -1}};
   2759 
   2760                   if (!*++optargv) iphelp();
   2761                   if ((TT.addressfamily = string_to_idx(*optargv, ip_aflist)) == -1)
   2762                     error_exit("wrong family '%s'", *optargv);
   2763                 }
   2764               }
   2765               break;
   2766       case 2:
   2767               TT.stats++;
   2768               break;
   2769       default: iphelp();
   2770                break; // unreachable code.
   2771     }
   2772   }
   2773 
   2774   TT.sockfd = xsocket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
   2775 
   2776   if (isip) {// only for ip
   2777     if (*optargv) {
   2778       struct arglist ip_objectlist[] = { {"address", 0}, {"link", 1},
   2779         {"route", 2}, {"rule", 3}, {"tunnel", 4}, {"tunl", 4}, {NULL, -1}};
   2780 
   2781       if ((idx = substring_to_idx(*optargv, ip_objectlist)) == -1) iphelp();
   2782       ipcmd = cmdobjlist[idx];
   2783       toys.exitval = ipcmd(++optargv);
   2784     } else iphelp();
   2785   } else {
   2786     struct arglist ip_objectlist[] = { {"ipaddr", 0}, {"iplink", 1},
   2787       {"iproute", 2}, {"iprule", 3}, {"iptunnel", 4}, {NULL, -1}};
   2788     if ((idx = string_to_idx(toys.which->name, ip_objectlist)) == -1)
   2789       iphelp();
   2790     ipcmd = cmdobjlist[idx];
   2791     toys.exitval = ipcmd(optargv);
   2792   }
   2793   xclose(TT.sockfd);
   2794   if (rtdsfield_init) free_alist(rt_dsfield);
   2795   if (rtrealms_init) free_alist(rt_realms);
   2796   if (rtscope_init) free_alist(rt_scope);
   2797   if (rttable_init) free_alist(rt_tables);
   2798   if (rtprotos_init) free_alist(rt_protos);
   2799 }
   2800