Missing dependency spotted by Robert P Day.
[oweals/busybox.git] / networking / libiproute / ipaddress.c
1 /*
2  * ipaddress.c          "ip address".
3  *
4  * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
5  *
6  * Authors:     Alexey Kuznetsov, <kuznet@ms2.inr.ac.ru>
7  *
8  * Changes:
9  *      Laszlo Valko <valko@linux.karinthy.hu> 990223: address label must be zero terminated
10  */
11
12 #include <sys/socket.h>
13 #include <sys/ioctl.h>
14
15 #include <fnmatch.h>
16 #include <stdlib.h>
17 #include <string.h>
18 #include <unistd.h>
19
20 #include <arpa/inet.h>
21
22 #include <net/if.h>
23 #include <net/if_arp.h>
24
25 #include "rt_names.h"
26 #include "utils.h"
27 #include "ip_common.h"
28
29 #include "libbb.h"
30
31 static struct
32 {
33         int ifindex;
34         int family;
35         int oneline;
36         int showqueue;
37         inet_prefix pfx;
38         int scope, scopemask;
39         int flags, flagmask;
40         int up;
41         char *label;
42         int flushed;
43         char *flushb;
44         int flushp;
45         int flushe;
46         struct rtnl_handle *rth;
47 } filter;
48
49 static void print_link_flags(FILE *fp, unsigned flags, unsigned mdown)
50 {
51         fprintf(fp, "<");
52         flags &= ~IFF_RUNNING;
53 #define _PF(f) if (flags&IFF_##f) { \
54                   flags &= ~IFF_##f ; \
55                   fprintf(fp, #f "%s", flags ? "," : ""); }
56         _PF(LOOPBACK);
57         _PF(BROADCAST);
58         _PF(POINTOPOINT);
59         _PF(MULTICAST);
60         _PF(NOARP);
61 #if 0
62         _PF(ALLMULTI);
63         _PF(PROMISC);
64         _PF(MASTER);
65         _PF(SLAVE);
66         _PF(DEBUG);
67         _PF(DYNAMIC);
68         _PF(AUTOMEDIA);
69         _PF(PORTSEL);
70         _PF(NOTRAILERS);
71 #endif
72         _PF(UP);
73 #undef _PF
74         if (flags)
75                 fprintf(fp, "%x", flags);
76         if (mdown)
77                 fprintf(fp, ",M-DOWN");
78         fprintf(fp, "> ");
79 }
80
81 static void print_queuelen(char *name)
82 {
83         struct ifreq ifr;
84         int s;
85
86         s = socket(AF_INET, SOCK_STREAM, 0);
87         if (s < 0)
88                 return;
89
90         memset(&ifr, 0, sizeof(ifr));
91         strcpy(ifr.ifr_name, name);
92         if (ioctl(s, SIOCGIFTXQLEN, &ifr) < 0) {
93                 perror("SIOCGIFXQLEN");
94                 close(s);
95                 return;
96         }
97         close(s);
98
99         if (ifr.ifr_qlen)
100                 printf("qlen %d", ifr.ifr_qlen);
101 }
102
103 static int print_linkinfo(struct sockaddr_nl ATTRIBUTE_UNUSED *who,
104                 struct nlmsghdr *n, void ATTRIBUTE_UNUSED *arg)
105 {
106         FILE *fp = (FILE*)arg;
107         struct ifinfomsg *ifi = NLMSG_DATA(n);
108         struct rtattr * tb[IFLA_MAX+1];
109         int len = n->nlmsg_len;
110         unsigned m_flag = 0;
111
112         if (n->nlmsg_type != RTM_NEWLINK && n->nlmsg_type != RTM_DELLINK)
113                 return 0;
114
115         len -= NLMSG_LENGTH(sizeof(*ifi));
116         if (len < 0)
117                 return -1;
118
119         if (filter.ifindex && ifi->ifi_index != filter.ifindex)
120                 return 0;
121         if (filter.up && !(ifi->ifi_flags&IFF_UP))
122                 return 0;
123
124         memset(tb, 0, sizeof(tb));
125         parse_rtattr(tb, IFLA_MAX, IFLA_RTA(ifi), len);
126         if (tb[IFLA_IFNAME] == NULL) {
127                 bb_error_msg("nil ifname");
128                 return -1;
129         }
130         if (filter.label &&
131             (!filter.family || filter.family == AF_PACKET) &&
132             fnmatch(filter.label, RTA_DATA(tb[IFLA_IFNAME]), 0))
133                 return 0;
134
135         if (n->nlmsg_type == RTM_DELLINK)
136                 fprintf(fp, "Deleted ");
137
138         fprintf(fp, "%d: %s", ifi->ifi_index,
139                 tb[IFLA_IFNAME] ? (char*)RTA_DATA(tb[IFLA_IFNAME]) : "<nil>");
140
141         if (tb[IFLA_LINK]) {
142                 SPRINT_BUF(b1);
143                 int iflink = *(int*)RTA_DATA(tb[IFLA_LINK]);
144                 if (iflink == 0)
145                         fprintf(fp, "@NONE: ");
146                 else {
147                         fprintf(fp, "@%s: ", ll_idx_n2a(iflink, b1));
148                         m_flag = ll_index_to_flags(iflink);
149                         m_flag = !(m_flag & IFF_UP);
150                 }
151         } else {
152                 fprintf(fp, ": ");
153         }
154         print_link_flags(fp, ifi->ifi_flags, m_flag);
155
156         if (tb[IFLA_MTU])
157                 fprintf(fp, "mtu %u ", *(int*)RTA_DATA(tb[IFLA_MTU]));
158         if (tb[IFLA_QDISC])
159                 fprintf(fp, "qdisc %s ", (char*)RTA_DATA(tb[IFLA_QDISC]));
160 #ifdef IFLA_MASTER
161         if (tb[IFLA_MASTER]) {
162                 SPRINT_BUF(b1);
163                 fprintf(fp, "master %s ", ll_idx_n2a(*(int*)RTA_DATA(tb[IFLA_MASTER]), b1));
164         }
165 #endif
166         if (filter.showqueue)
167                 print_queuelen((char*)RTA_DATA(tb[IFLA_IFNAME]));
168
169         if (!filter.family || filter.family == AF_PACKET) {
170                 SPRINT_BUF(b1);
171                 fprintf(fp, "%s", _SL_);
172                 fprintf(fp, "    link/%s ", ll_type_n2a(ifi->ifi_type, b1, sizeof(b1)));
173
174                 if (tb[IFLA_ADDRESS]) {
175                         fprintf(fp, "%s", ll_addr_n2a(RTA_DATA(tb[IFLA_ADDRESS]),
176                                                       RTA_PAYLOAD(tb[IFLA_ADDRESS]),
177                                                       ifi->ifi_type,
178                                                       b1, sizeof(b1)));
179                 }
180                 if (tb[IFLA_BROADCAST]) {
181                         if (ifi->ifi_flags&IFF_POINTOPOINT)
182                                 fprintf(fp, " peer ");
183                         else
184                                 fprintf(fp, " brd ");
185                         fprintf(fp, "%s", ll_addr_n2a(RTA_DATA(tb[IFLA_BROADCAST]),
186                                                       RTA_PAYLOAD(tb[IFLA_BROADCAST]),
187                                                       ifi->ifi_type,
188                                                       b1, sizeof(b1)));
189                 }
190         }
191         fprintf(fp, "\n");
192         fflush(fp);
193         return 0;
194 }
195
196 static int flush_update(void)
197 {
198         if (rtnl_send(filter.rth, filter.flushb, filter.flushp) < 0) {
199                 perror("Failed to send flush request\n");
200                 return -1;
201         }
202         filter.flushp = 0;
203         return 0;
204 }
205
206 static int print_addrinfo(struct sockaddr_nl ATTRIBUTE_UNUSED *who,
207                 struct nlmsghdr *n, void ATTRIBUTE_UNUSED *arg)
208 {
209         FILE *fp = (FILE*)arg;
210         struct ifaddrmsg *ifa = NLMSG_DATA(n);
211         int len = n->nlmsg_len;
212         struct rtattr * rta_tb[IFA_MAX+1];
213         char abuf[256];
214         SPRINT_BUF(b1);
215
216         if (n->nlmsg_type != RTM_NEWADDR && n->nlmsg_type != RTM_DELADDR)
217                 return 0;
218         len -= NLMSG_LENGTH(sizeof(*ifa));
219         if (len < 0) {
220                 bb_error_msg("wrong nlmsg len %d", len);
221                 return -1;
222         }
223
224         if (filter.flushb && n->nlmsg_type != RTM_NEWADDR)
225                 return 0;
226
227         memset(rta_tb, 0, sizeof(rta_tb));
228         parse_rtattr(rta_tb, IFA_MAX, IFA_RTA(ifa), n->nlmsg_len - NLMSG_LENGTH(sizeof(*ifa)));
229
230         if (!rta_tb[IFA_LOCAL])
231                 rta_tb[IFA_LOCAL] = rta_tb[IFA_ADDRESS];
232         if (!rta_tb[IFA_ADDRESS])
233                 rta_tb[IFA_ADDRESS] = rta_tb[IFA_LOCAL];
234
235         if (filter.ifindex && filter.ifindex != ifa->ifa_index)
236                 return 0;
237         if ((filter.scope^ifa->ifa_scope)&filter.scopemask)
238                 return 0;
239         if ((filter.flags^ifa->ifa_flags)&filter.flagmask)
240                 return 0;
241         if (filter.label) {
242                 const char *label;
243                 if (rta_tb[IFA_LABEL])
244                         label = RTA_DATA(rta_tb[IFA_LABEL]);
245                 else
246                         label = ll_idx_n2a(ifa->ifa_index, b1);
247                 if (fnmatch(filter.label, label, 0) != 0)
248                         return 0;
249         }
250         if (filter.pfx.family) {
251                 if (rta_tb[IFA_LOCAL]) {
252                         inet_prefix dst;
253                         memset(&dst, 0, sizeof(dst));
254                         dst.family = ifa->ifa_family;
255                         memcpy(&dst.data, RTA_DATA(rta_tb[IFA_LOCAL]), RTA_PAYLOAD(rta_tb[IFA_LOCAL]));
256                         if (inet_addr_match(&dst, &filter.pfx, filter.pfx.bitlen))
257                                 return 0;
258                 }
259         }
260
261         if (filter.flushb) {
262                 struct nlmsghdr *fn;
263                 if (NLMSG_ALIGN(filter.flushp) + n->nlmsg_len > filter.flushe) {
264                         if (flush_update())
265                                 return -1;
266                 }
267                 fn = (struct nlmsghdr*)(filter.flushb + NLMSG_ALIGN(filter.flushp));
268                 memcpy(fn, n, n->nlmsg_len);
269                 fn->nlmsg_type = RTM_DELADDR;
270                 fn->nlmsg_flags = NLM_F_REQUEST;
271                 fn->nlmsg_seq = ++filter.rth->seq;
272                 filter.flushp = (((char*)fn) + n->nlmsg_len) - filter.flushb;
273                 filter.flushed++;
274                 return 0;
275         }
276
277         if (n->nlmsg_type == RTM_DELADDR)
278                 fprintf(fp, "Deleted ");
279
280         if (filter.oneline)
281                 fprintf(fp, "%u: %s", ifa->ifa_index, ll_index_to_name(ifa->ifa_index));
282         if (ifa->ifa_family == AF_INET)
283                 fprintf(fp, "    inet ");
284         else if (ifa->ifa_family == AF_INET6)
285                 fprintf(fp, "    inet6 ");
286         else
287                 fprintf(fp, "    family %d ", ifa->ifa_family);
288
289         if (rta_tb[IFA_LOCAL]) {
290                 fprintf(fp, "%s", rt_addr_n2a(ifa->ifa_family,
291                                               RTA_PAYLOAD(rta_tb[IFA_LOCAL]),
292                                               RTA_DATA(rta_tb[IFA_LOCAL]),
293                                               abuf, sizeof(abuf)));
294
295                 if (rta_tb[IFA_ADDRESS] == NULL ||
296                     memcmp(RTA_DATA(rta_tb[IFA_ADDRESS]), RTA_DATA(rta_tb[IFA_LOCAL]), 4) == 0) {
297                         fprintf(fp, "/%d ", ifa->ifa_prefixlen);
298                 } else {
299                         fprintf(fp, " peer %s/%d ",
300                                 rt_addr_n2a(ifa->ifa_family,
301                                             RTA_PAYLOAD(rta_tb[IFA_ADDRESS]),
302                                             RTA_DATA(rta_tb[IFA_ADDRESS]),
303                                             abuf, sizeof(abuf)),
304                                 ifa->ifa_prefixlen);
305                 }
306         }
307
308         if (rta_tb[IFA_BROADCAST]) {
309                 fprintf(fp, "brd %s ",
310                         rt_addr_n2a(ifa->ifa_family,
311                                     RTA_PAYLOAD(rta_tb[IFA_BROADCAST]),
312                                     RTA_DATA(rta_tb[IFA_BROADCAST]),
313                                     abuf, sizeof(abuf)));
314         }
315         if (rta_tb[IFA_ANYCAST]) {
316                 fprintf(fp, "any %s ",
317                         rt_addr_n2a(ifa->ifa_family,
318                                     RTA_PAYLOAD(rta_tb[IFA_ANYCAST]),
319                                     RTA_DATA(rta_tb[IFA_ANYCAST]),
320                                     abuf, sizeof(abuf)));
321         }
322         fprintf(fp, "scope %s ", rtnl_rtscope_n2a(ifa->ifa_scope, b1, sizeof(b1)));
323         if (ifa->ifa_flags&IFA_F_SECONDARY) {
324                 ifa->ifa_flags &= ~IFA_F_SECONDARY;
325                 fprintf(fp, "secondary ");
326         }
327         if (ifa->ifa_flags&IFA_F_TENTATIVE) {
328                 ifa->ifa_flags &= ~IFA_F_TENTATIVE;
329                 fprintf(fp, "tentative ");
330         }
331         if (ifa->ifa_flags&IFA_F_DEPRECATED) {
332                 ifa->ifa_flags &= ~IFA_F_DEPRECATED;
333                 fprintf(fp, "deprecated ");
334         }
335         if (!(ifa->ifa_flags&IFA_F_PERMANENT)) {
336                 fprintf(fp, "dynamic ");
337         } else
338                 ifa->ifa_flags &= ~IFA_F_PERMANENT;
339         if (ifa->ifa_flags)
340                 fprintf(fp, "flags %02x ", ifa->ifa_flags);
341         if (rta_tb[IFA_LABEL])
342                 fprintf(fp, "%s", (char*)RTA_DATA(rta_tb[IFA_LABEL]));
343         if (rta_tb[IFA_CACHEINFO]) {
344                 struct ifa_cacheinfo *ci = RTA_DATA(rta_tb[IFA_CACHEINFO]);
345                 char buf[128];
346                 fprintf(fp, "%s", _SL_);
347                 if (ci->ifa_valid == 0xFFFFFFFFU)
348                         sprintf(buf, "valid_lft forever");
349                 else
350                         sprintf(buf, "valid_lft %dsec", ci->ifa_valid);
351                 if (ci->ifa_prefered == 0xFFFFFFFFU)
352                         sprintf(buf+strlen(buf), " preferred_lft forever");
353                 else
354                         sprintf(buf+strlen(buf), " preferred_lft %dsec", ci->ifa_prefered);
355                 fprintf(fp, "       %s", buf);
356         }
357         fprintf(fp, "\n");
358         fflush(fp);
359         return 0;
360 }
361
362
363 struct nlmsg_list
364 {
365         struct nlmsg_list *next;
366         struct nlmsghdr   h;
367 };
368
369 static int print_selected_addrinfo(int ifindex, struct nlmsg_list *ainfo, FILE *fp)
370 {
371         for ( ;ainfo ;  ainfo = ainfo->next) {
372                 struct nlmsghdr *n = &ainfo->h;
373                 struct ifaddrmsg *ifa = NLMSG_DATA(n);
374
375                 if (n->nlmsg_type != RTM_NEWADDR)
376                         continue;
377
378                 if (n->nlmsg_len < NLMSG_LENGTH(sizeof(ifa)))
379                         return -1;
380
381                 if (ifa->ifa_index != ifindex ||
382                     (filter.family && filter.family != ifa->ifa_family))
383                         continue;
384
385                 print_addrinfo(NULL, n, fp);
386         }
387         return 0;
388 }
389
390
391 static int store_nlmsg(struct sockaddr_nl *who, struct nlmsghdr *n, void *arg)
392 {
393         struct nlmsg_list **linfo = (struct nlmsg_list**)arg;
394         struct nlmsg_list *h;
395         struct nlmsg_list **lp;
396
397         h = malloc(n->nlmsg_len+sizeof(void*));
398         if (h == NULL)
399                 return -1;
400
401         memcpy(&h->h, n, n->nlmsg_len);
402         h->next = NULL;
403
404         for (lp = linfo; *lp; lp = &(*lp)->next) /* NOTHING */;
405         *lp = h;
406
407         ll_remember_index(who, n, NULL);
408         return 0;
409 }
410
411 static void ipaddr_reset_filter(int _oneline)
412 {
413         memset(&filter, 0, sizeof(filter));
414         filter.oneline = _oneline;
415 }
416
417 int ipaddr_list_or_flush(int argc, char **argv, int flush)
418 {
419         static const char *const option[] = { "to", "scope", "up", "label", "dev", 0 };
420
421         struct nlmsg_list *linfo = NULL;
422         struct nlmsg_list *ainfo = NULL;
423         struct nlmsg_list *l;
424         struct rtnl_handle rth;
425         char *filter_dev = NULL;
426         int no_link = 0;
427
428         ipaddr_reset_filter(oneline);
429         filter.showqueue = 1;
430
431         if (filter.family == AF_UNSPEC)
432                 filter.family = preferred_family;
433
434         if (flush) {
435                 if (argc <= 0) {
436                         fprintf(stderr, "Flush requires arguments.\n");
437                         return -1;
438                 }
439                 if (filter.family == AF_PACKET) {
440                         fprintf(stderr, "Cannot flush link addresses.\n");
441                         return -1;
442                 }
443         }
444
445         while (argc > 0) {
446                 const int option_num = compare_string_array(option, *argv);
447                 switch (option_num) {
448                         case 0: /* to */
449                                 NEXT_ARG();
450                                 get_prefix(&filter.pfx, *argv, filter.family);
451                                 if (filter.family == AF_UNSPEC) {
452                                         filter.family = filter.pfx.family;
453                                 }
454                                 break;
455                         case 1: /* scope */
456                         {
457                                 uint32_t scope = 0;
458                                 NEXT_ARG();
459                                 filter.scopemask = -1;
460                                 if (rtnl_rtscope_a2n(&scope, *argv)) {
461                                         if (strcmp(*argv, "all") != 0) {
462                                                 invarg("invalid \"scope\"\n", *argv);
463                                         }
464                                         scope = RT_SCOPE_NOWHERE;
465                                         filter.scopemask = 0;
466                                 }
467                                 filter.scope = scope;
468                                 break;
469                         }
470                         case 2: /* up */
471                                 filter.up = 1;
472                                 break;
473                         case 3: /* label */
474                                 NEXT_ARG();
475                                 filter.label = *argv;
476                                 break;
477                         case 4: /* dev */
478                                 NEXT_ARG();
479                         default:
480                                 if (filter_dev) {
481                                         duparg2("dev", *argv);
482                                 }
483                                 filter_dev = *argv;
484                 }
485                 argv++;
486                 argc--;
487         }
488
489         if (rtnl_open(&rth, 0) < 0)
490                 exit(1);
491
492         if (rtnl_wilddump_request(&rth, preferred_family, RTM_GETLINK) < 0) {
493                 bb_perror_msg_and_die("Cannot send dump request");
494         }
495
496         if (rtnl_dump_filter(&rth, store_nlmsg, &linfo, NULL, NULL) < 0) {
497                 bb_error_msg_and_die("Dump terminated");
498         }
499
500         if (filter_dev) {
501                 filter.ifindex = ll_name_to_index(filter_dev);
502                 if (filter.ifindex <= 0) {
503                         bb_error_msg("Device \"%s\" does not exist", filter_dev);
504                         return -1;
505                 }
506         }
507
508         if (flush) {
509                 int round = 0;
510                 char flushb[4096-512];
511
512                 filter.flushb = flushb;
513                 filter.flushp = 0;
514                 filter.flushe = sizeof(flushb);
515                 filter.rth = &rth;
516
517                 for (;;) {
518                         if (rtnl_wilddump_request(&rth, filter.family, RTM_GETADDR) < 0) {
519                                 perror("Cannot send dump request");
520                                 exit(1);
521                         }
522                         filter.flushed = 0;
523                         if (rtnl_dump_filter(&rth, print_addrinfo, stdout, NULL, NULL) < 0) {
524                                 fprintf(stderr, "Flush terminated\n");
525                                 exit(1);
526                         }
527                         if (filter.flushed == 0) {
528 #if 0
529                                 if (round == 0)
530                                         fprintf(stderr, "Nothing to flush.\n");
531 #endif
532                                 fflush(stdout);
533                                 return 0;
534                         }
535                         round++;
536                         if (flush_update() < 0)
537                                 exit(1);
538                 }
539         }
540
541         if (filter.family != AF_PACKET) {
542                 if (rtnl_wilddump_request(&rth, filter.family, RTM_GETADDR) < 0) {
543                         bb_perror_msg_and_die("Cannot send dump request");
544                 }
545
546                 if (rtnl_dump_filter(&rth, store_nlmsg, &ainfo, NULL, NULL) < 0) {
547                         bb_error_msg_and_die("Dump terminated");
548                 }
549         }
550
551
552         if (filter.family && filter.family != AF_PACKET) {
553                 struct nlmsg_list **lp;
554                 lp=&linfo;
555
556                 if (filter.oneline)
557                         no_link = 1;
558
559                 while ((l=*lp)!=NULL) {
560                         int ok = 0;
561                         struct ifinfomsg *ifi = NLMSG_DATA(&l->h);
562                         struct nlmsg_list *a;
563
564                         for (a=ainfo; a; a=a->next) {
565                                 struct nlmsghdr *n = &a->h;
566                                 struct ifaddrmsg *ifa = NLMSG_DATA(n);
567
568                                 if (ifa->ifa_index != ifi->ifi_index ||
569                                     (filter.family && filter.family != ifa->ifa_family))
570                                         continue;
571                                 if ((filter.scope^ifa->ifa_scope)&filter.scopemask)
572                                         continue;
573                                 if ((filter.flags^ifa->ifa_flags)&filter.flagmask)
574                                         continue;
575                                 if (filter.pfx.family || filter.label) {
576                                         struct rtattr *tb[IFA_MAX+1];
577                                         memset(tb, 0, sizeof(tb));
578                                         parse_rtattr(tb, IFA_MAX, IFA_RTA(ifa), IFA_PAYLOAD(n));
579                                         if (!tb[IFA_LOCAL])
580                                                 tb[IFA_LOCAL] = tb[IFA_ADDRESS];
581
582                                         if (filter.pfx.family && tb[IFA_LOCAL]) {
583                                                 inet_prefix dst;
584                                                 memset(&dst, 0, sizeof(dst));
585                                                 dst.family = ifa->ifa_family;
586                                                 memcpy(&dst.data, RTA_DATA(tb[IFA_LOCAL]), RTA_PAYLOAD(tb[IFA_LOCAL]));
587                                                 if (inet_addr_match(&dst, &filter.pfx, filter.pfx.bitlen))
588                                                         continue;
589                                         }
590                                         if (filter.label) {
591                                                 SPRINT_BUF(b1);
592                                                 const char *label;
593                                                 if (tb[IFA_LABEL])
594                                                         label = RTA_DATA(tb[IFA_LABEL]);
595                                                 else
596                                                         label = ll_idx_n2a(ifa->ifa_index, b1);
597                                                 if (fnmatch(filter.label, label, 0) != 0)
598                                                         continue;
599                                         }
600                                 }
601
602                                 ok = 1;
603                                 break;
604                         }
605                         if (!ok)
606                                 *lp = l->next;
607                         else
608                                 lp = &l->next;
609                 }
610         }
611
612         for (l=linfo; l; l = l->next) {
613                 if (no_link || print_linkinfo(NULL, &l->h, stdout) == 0) {
614                         struct ifinfomsg *ifi = NLMSG_DATA(&l->h);
615                         if (filter.family != AF_PACKET)
616                                 print_selected_addrinfo(ifi->ifi_index, ainfo, stdout);
617                 }
618                 fflush(stdout);
619         }
620
621         exit(0);
622 }
623
624 static int default_scope(inet_prefix *lcl)
625 {
626         if (lcl->family == AF_INET) {
627                 if (lcl->bytelen >= 1 && *(__u8*)&lcl->data == 127)
628                         return RT_SCOPE_HOST;
629         }
630         return 0;
631 }
632
633 static int ipaddr_modify(int cmd, int argc, char **argv)
634 {
635         static const char *const option[] = {
636                 "peer", "remote", "broadcast", "brd",
637                 "anycast", "scope", "dev", "label", "local", 0
638         };
639
640         struct rtnl_handle rth;
641         struct {
642                 struct nlmsghdr         n;
643                 struct ifaddrmsg        ifa;
644                 char                    buf[256];
645         } req;
646         char  *d = NULL;
647         char  *l = NULL;
648         inet_prefix lcl;
649         inet_prefix peer;
650         int local_len = 0;
651         int peer_len = 0;
652         int brd_len = 0;
653         int any_len = 0;
654         int scoped = 0;
655
656         memset(&req, 0, sizeof(req));
657
658         req.n.nlmsg_len = NLMSG_LENGTH(sizeof(struct ifaddrmsg));
659         req.n.nlmsg_flags = NLM_F_REQUEST;
660         req.n.nlmsg_type = cmd;
661         req.ifa.ifa_family = preferred_family;
662
663         while (argc > 0) {
664                 const int option_num = compare_string_array(option, *argv);
665                 switch (option_num) {
666                         case 0: /* peer */
667                         case 1: /* remote */
668                                 NEXT_ARG();
669
670                                 if (peer_len) {
671                                         duparg("peer", *argv);
672                                 }
673                                 get_prefix(&peer, *argv, req.ifa.ifa_family);
674                                 peer_len = peer.bytelen;
675                                 if (req.ifa.ifa_family == AF_UNSPEC) {
676                                         req.ifa.ifa_family = peer.family;
677                                 }
678                                 addattr_l(&req.n, sizeof(req), IFA_ADDRESS, &peer.data, peer.bytelen);
679                                 req.ifa.ifa_prefixlen = peer.bitlen;
680                                 break;
681                         case 2: /* broadcast */
682                         case 3: /* brd */
683                         {
684                                 inet_prefix addr;
685                                 NEXT_ARG();
686                                 if (brd_len) {
687                                         duparg("broadcast", *argv);
688                                 }
689                                 if (strcmp(*argv, "+") == 0) {
690                                         brd_len = -1;
691                                 }
692                                 else if (strcmp(*argv, "-") == 0) {
693                                         brd_len = -2;
694                                 } else {
695                                         get_addr(&addr, *argv, req.ifa.ifa_family);
696                                         if (req.ifa.ifa_family == AF_UNSPEC)
697                                                 req.ifa.ifa_family = addr.family;
698                                         addattr_l(&req.n, sizeof(req), IFA_BROADCAST, &addr.data, addr.bytelen);
699                                         brd_len = addr.bytelen;
700                                 }
701                                 break;
702                         }
703                         case 4: /* anycast */
704                         {
705                                 inet_prefix addr;
706                                 NEXT_ARG();
707                                 if (any_len) {
708                                         duparg("anycast", *argv);
709                                 }
710                                 get_addr(&addr, *argv, req.ifa.ifa_family);
711                                 if (req.ifa.ifa_family == AF_UNSPEC) {
712                                         req.ifa.ifa_family = addr.family;
713                                 }
714                                 addattr_l(&req.n, sizeof(req), IFA_ANYCAST, &addr.data, addr.bytelen);
715                                 any_len = addr.bytelen;
716                                 break;
717                         }
718                         case 5: /* scope */
719                         {
720                                 uint32_t scope = 0;
721                                 NEXT_ARG();
722                                 if (rtnl_rtscope_a2n(&scope, *argv)) {
723                                         invarg(*argv, "invalid scope value");
724                                 }
725                                 req.ifa.ifa_scope = scope;
726                                 scoped = 1;
727                                 break;
728                         }
729                         case 6: /* dev */
730                                 NEXT_ARG();
731                                 d = *argv;
732                                 break;
733                         case 7: /* label */
734                                 NEXT_ARG();
735                                 l = *argv;
736                                 addattr_l(&req.n, sizeof(req), IFA_LABEL, l, strlen(l)+1);
737                                 break;
738                         case 8: /* local */
739                                 NEXT_ARG();
740                         default:
741                                 if (local_len) {
742                                         duparg2("local", *argv);
743                                 }
744                                 get_prefix(&lcl, *argv, req.ifa.ifa_family);
745                                 if (req.ifa.ifa_family == AF_UNSPEC) {
746                                         req.ifa.ifa_family = lcl.family;
747                                 }
748                                 addattr_l(&req.n, sizeof(req), IFA_LOCAL, &lcl.data, lcl.bytelen);
749                                 local_len = lcl.bytelen;
750                 }
751                 argc--;
752                 argv++;
753         }
754
755         if (d == NULL) {
756                 bb_error_msg("Not enough information: \"dev\" argument is required");
757                 return -1;
758         }
759         if (l && matches(d, l) != 0) {
760                 bb_error_msg_and_die("\"dev\" (%s) must match \"label\" (%s)", d, l);
761         }
762
763         if (peer_len == 0 && local_len && cmd != RTM_DELADDR) {
764                 peer = lcl;
765                 addattr_l(&req.n, sizeof(req), IFA_ADDRESS, &lcl.data, lcl.bytelen);
766         }
767         if (req.ifa.ifa_prefixlen == 0)
768                 req.ifa.ifa_prefixlen = lcl.bitlen;
769
770         if (brd_len < 0 && cmd != RTM_DELADDR) {
771                 inet_prefix brd;
772                 int i;
773                 if (req.ifa.ifa_family != AF_INET) {
774                         bb_error_msg("Broadcast can be set only for IPv4 addresses");
775                         return -1;
776                 }
777                 brd = peer;
778                 if (brd.bitlen <= 30) {
779                         for (i=31; i>=brd.bitlen; i--) {
780                                 if (brd_len == -1)
781                                         brd.data[0] |= htonl(1<<(31-i));
782                                 else
783                                         brd.data[0] &= ~htonl(1<<(31-i));
784                         }
785                         addattr_l(&req.n, sizeof(req), IFA_BROADCAST, &brd.data, brd.bytelen);
786                         brd_len = brd.bytelen;
787                 }
788         }
789         if (!scoped && cmd != RTM_DELADDR)
790                 req.ifa.ifa_scope = default_scope(&lcl);
791
792         if (rtnl_open(&rth, 0) < 0)
793                 exit(1);
794
795         ll_init_map(&rth);
796
797         if ((req.ifa.ifa_index = ll_name_to_index(d)) == 0) {
798                 bb_error_msg("Cannot find device \"%s\"", d);
799                 return -1;
800         }
801
802         if (rtnl_talk(&rth, &req.n, 0, 0, NULL, NULL, NULL) < 0)
803                 exit(2);
804
805         exit(0);
806 }
807
808 int do_ipaddr(int argc, char **argv)
809 {
810         static const char *const commands[] = {
811                 "add", "delete", "list", "show", "lst", "flush", 0
812         };
813
814         int command_num = 2;
815
816         if (*argv) {
817                 command_num = compare_string_array(commands, *argv);
818         }
819         switch (command_num) {
820                 case 0: /* add */
821                         return ipaddr_modify(RTM_NEWADDR, argc-1, argv+1);
822                 case 1: /* delete */
823                         return ipaddr_modify(RTM_DELADDR, argc-1, argv+1);
824                 case 2: /* list */
825                 case 3: /* show */
826                 case 4: /* lst */
827                         return ipaddr_list_or_flush(argc-1, argv+1, 0);
828                 case 5: /* flush */
829                         return ipaddr_list_or_flush(argc-1, argv+1, 1);
830         }
831         bb_error_msg_and_die("Unknown command %s", *argv);
832 }