blob: 2821f2e8d6dcba84ab5498842d63d96f07b6fb09 [file] [log] [blame]
Glenn L McGrath9a2d2722002-11-10 01:33:55 +00001/*
2 * ipaddress.c "ip address".
3 *
4 * This program is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU General Public License
6 * as published by the Free Software Foundation; either version
7 * 2 of the License, or (at your option) any later version.
8 *
9 * Authors: Alexey Kuznetsov, <kuznet@ms2.inr.ac.ru>
10 *
11 * Changes:
12 * Laszlo Valko <valko@linux.karinthy.hu> 990223: address label must be zero terminated
13 */
14
Glenn L McGrath9a2d2722002-11-10 01:33:55 +000015#include <sys/socket.h>
16#include <sys/ioctl.h>
Glenn L McGrath275be872002-12-16 07:37:21 +000017
Glenn L McGrath9a2d2722002-11-10 01:33:55 +000018#include <fnmatch.h>
Glenn L McGrath275be872002-12-16 07:37:21 +000019#include <stdlib.h>
20#include <string.h>
21#include <unistd.h>
22
23#include <arpa/inet.h>
Glenn L McGrath9a2d2722002-11-10 01:33:55 +000024
Glenn L McGrath84cc4e72002-12-11 03:55:52 +000025#define sysinfo kernel_sysinfo
Glenn L McGrath9a2d2722002-11-10 01:33:55 +000026#include <linux/if_arp.h>
Glenn L McGrath84cc4e72002-12-11 03:55:52 +000027#undef sysinfo
Glenn L McGrath9a2d2722002-11-10 01:33:55 +000028
29#include "rt_names.h"
30#include "utils.h"
Glenn L McGrath9a2d2722002-11-10 01:33:55 +000031
Glenn L McGrath275be872002-12-16 07:37:21 +000032#include "libbb.h"
Glenn L McGrath9a2d2722002-11-10 01:33:55 +000033
34static struct
35{
36 int ifindex;
37 int family;
38 int oneline;
39 int showqueue;
40 inet_prefix pfx;
41 int scope, scopemask;
42 int flags, flagmask;
43 int up;
44 char *label;
45 struct rtnl_handle *rth;
46} filter;
47
Glenn L McGrath9a2d2722002-11-10 01:33:55 +000048void print_link_flags(FILE *fp, unsigned flags, unsigned mdown)
49{
50 fprintf(fp, "<");
51 flags &= ~IFF_RUNNING;
52#define _PF(f) if (flags&IFF_##f) { \
53 flags &= ~IFF_##f ; \
54 fprintf(fp, #f "%s", flags ? "," : ""); }
55 _PF(LOOPBACK);
56 _PF(BROADCAST);
57 _PF(POINTOPOINT);
58 _PF(MULTICAST);
59 _PF(NOARP);
60#if 0
61 _PF(ALLMULTI);
62 _PF(PROMISC);
63 _PF(MASTER);
64 _PF(SLAVE);
65 _PF(DEBUG);
66 _PF(DYNAMIC);
67 _PF(AUTOMEDIA);
68 _PF(PORTSEL);
69 _PF(NOTRAILERS);
70#endif
71 _PF(UP);
72#undef _PF
73 if (flags)
74 fprintf(fp, "%x", flags);
75 if (mdown)
76 fprintf(fp, ",M-DOWN");
77 fprintf(fp, "> ");
78}
79
Glenn L McGrath2626ef62002-12-02 01:40:05 +000080static void print_queuelen(char *name)
Glenn L McGrath9a2d2722002-11-10 01:33:55 +000081{
82 struct ifreq ifr;
83 int s;
84
85 s = socket(AF_INET, SOCK_STREAM, 0);
86 if (s < 0)
87 return;
88
89 memset(&ifr, 0, sizeof(ifr));
90 strcpy(ifr.ifr_name, name);
91 if (ioctl(s, SIOCGIFTXQLEN, &ifr) < 0) {
92 perror("SIOCGIFXQLEN");
93 close(s);
94 return;
95 }
96 close(s);
97
98 if (ifr.ifr_qlen)
99 printf("qlen %d", ifr.ifr_qlen);
100}
101
Glenn L McGrath2626ef62002-12-02 01:40:05 +0000102static int print_linkinfo(struct sockaddr_nl *who, struct nlmsghdr *n, void *arg)
Glenn L McGrath9a2d2722002-11-10 01:33:55 +0000103{
104 FILE *fp = (FILE*)arg;
105 struct ifinfomsg *ifi = NLMSG_DATA(n);
106 struct rtattr * tb[IFLA_MAX+1];
107 int len = n->nlmsg_len;
108 unsigned m_flag = 0;
109
110 if (n->nlmsg_type != RTM_NEWLINK && n->nlmsg_type != RTM_DELLINK)
111 return 0;
112
113 len -= NLMSG_LENGTH(sizeof(*ifi));
114 if (len < 0)
115 return -1;
116
117 if (filter.ifindex && ifi->ifi_index != filter.ifindex)
118 return 0;
119 if (filter.up && !(ifi->ifi_flags&IFF_UP))
120 return 0;
121
122 memset(tb, 0, sizeof(tb));
123 parse_rtattr(tb, IFLA_MAX, IFLA_RTA(ifi), len);
124 if (tb[IFLA_IFNAME] == NULL) {
Glenn L McGrathdf725362002-11-28 10:49:14 +0000125 error_msg("nil ifname");
Glenn L McGrath9a2d2722002-11-10 01:33:55 +0000126 return -1;
127 }
128 if (filter.label &&
129 (!filter.family || filter.family == AF_PACKET) &&
130 fnmatch(filter.label, RTA_DATA(tb[IFLA_IFNAME]), 0))
131 return 0;
132
133 if (n->nlmsg_type == RTM_DELLINK)
134 fprintf(fp, "Deleted ");
135
136 fprintf(fp, "%d: %s", ifi->ifi_index,
137 tb[IFLA_IFNAME] ? (char*)RTA_DATA(tb[IFLA_IFNAME]) : "<nil>");
138
139 if (tb[IFLA_LINK]) {
140 SPRINT_BUF(b1);
141 int iflink = *(int*)RTA_DATA(tb[IFLA_LINK]);
142 if (iflink == 0)
143 fprintf(fp, "@NONE: ");
144 else {
145 fprintf(fp, "@%s: ", ll_idx_n2a(iflink, b1));
146 m_flag = ll_index_to_flags(iflink);
147 m_flag = !(m_flag & IFF_UP);
148 }
149 } else {
150 fprintf(fp, ": ");
151 }
152 print_link_flags(fp, ifi->ifi_flags, m_flag);
153
154 if (tb[IFLA_MTU])
155 fprintf(fp, "mtu %u ", *(int*)RTA_DATA(tb[IFLA_MTU]));
156 if (tb[IFLA_QDISC])
157 fprintf(fp, "qdisc %s ", (char*)RTA_DATA(tb[IFLA_QDISC]));
158#ifdef IFLA_MASTER
159 if (tb[IFLA_MASTER]) {
160 SPRINT_BUF(b1);
161 fprintf(fp, "master %s ", ll_idx_n2a(*(int*)RTA_DATA(tb[IFLA_MASTER]), b1));
162 }
163#endif
164 if (filter.showqueue)
165 print_queuelen((char*)RTA_DATA(tb[IFLA_IFNAME]));
166
167 if (!filter.family || filter.family == AF_PACKET) {
168 SPRINT_BUF(b1);
169 fprintf(fp, "%s", _SL_);
170 fprintf(fp, " link/%s ", ll_type_n2a(ifi->ifi_type, b1, sizeof(b1)));
171
172 if (tb[IFLA_ADDRESS]) {
173 fprintf(fp, "%s", ll_addr_n2a(RTA_DATA(tb[IFLA_ADDRESS]),
174 RTA_PAYLOAD(tb[IFLA_ADDRESS]),
175 ifi->ifi_type,
176 b1, sizeof(b1)));
177 }
178 if (tb[IFLA_BROADCAST]) {
179 if (ifi->ifi_flags&IFF_POINTOPOINT)
180 fprintf(fp, " peer ");
181 else
182 fprintf(fp, " brd ");
183 fprintf(fp, "%s", ll_addr_n2a(RTA_DATA(tb[IFLA_BROADCAST]),
184 RTA_PAYLOAD(tb[IFLA_BROADCAST]),
185 ifi->ifi_type,
186 b1, sizeof(b1)));
187 }
188 }
189 fprintf(fp, "\n");
190 fflush(fp);
191 return 0;
192}
193
Glenn L McGrath2626ef62002-12-02 01:40:05 +0000194static int print_addrinfo(struct sockaddr_nl *who, struct nlmsghdr *n, void *arg)
Glenn L McGrath9a2d2722002-11-10 01:33:55 +0000195{
196 FILE *fp = (FILE*)arg;
197 struct ifaddrmsg *ifa = NLMSG_DATA(n);
198 int len = n->nlmsg_len;
199 struct rtattr * rta_tb[IFA_MAX+1];
200 char abuf[256];
201 SPRINT_BUF(b1);
202
203 if (n->nlmsg_type != RTM_NEWADDR && n->nlmsg_type != RTM_DELADDR)
204 return 0;
205 len -= NLMSG_LENGTH(sizeof(*ifa));
206 if (len < 0) {
Glenn L McGrathdf725362002-11-28 10:49:14 +0000207 error_msg("wrong nlmsg len %d", len);
Glenn L McGrath9a2d2722002-11-10 01:33:55 +0000208 return -1;
209 }
210
211 memset(rta_tb, 0, sizeof(rta_tb));
212 parse_rtattr(rta_tb, IFA_MAX, IFA_RTA(ifa), n->nlmsg_len - NLMSG_LENGTH(sizeof(*ifa)));
213
214 if (!rta_tb[IFA_LOCAL])
215 rta_tb[IFA_LOCAL] = rta_tb[IFA_ADDRESS];
216 if (!rta_tb[IFA_ADDRESS])
217 rta_tb[IFA_ADDRESS] = rta_tb[IFA_LOCAL];
218
219 if (filter.ifindex && filter.ifindex != ifa->ifa_index)
220 return 0;
221 if ((filter.scope^ifa->ifa_scope)&filter.scopemask)
222 return 0;
223 if ((filter.flags^ifa->ifa_flags)&filter.flagmask)
224 return 0;
225 if (filter.label) {
Glenn L McGrath9a2d2722002-11-10 01:33:55 +0000226 const char *label;
227 if (rta_tb[IFA_LABEL])
228 label = RTA_DATA(rta_tb[IFA_LABEL]);
229 else
230 label = ll_idx_n2a(ifa->ifa_index, b1);
231 if (fnmatch(filter.label, label, 0) != 0)
232 return 0;
233 }
234 if (filter.pfx.family) {
235 if (rta_tb[IFA_LOCAL]) {
236 inet_prefix dst;
237 memset(&dst, 0, sizeof(dst));
238 dst.family = ifa->ifa_family;
239 memcpy(&dst.data, RTA_DATA(rta_tb[IFA_LOCAL]), RTA_PAYLOAD(rta_tb[IFA_LOCAL]));
240 if (inet_addr_match(&dst, &filter.pfx, filter.pfx.bitlen))
241 return 0;
242 }
243 }
244
245 if (n->nlmsg_type == RTM_DELADDR)
246 fprintf(fp, "Deleted ");
247
248 if (filter.oneline)
249 fprintf(fp, "%u: %s", ifa->ifa_index, ll_index_to_name(ifa->ifa_index));
250 if (ifa->ifa_family == AF_INET)
251 fprintf(fp, " inet ");
252 else if (ifa->ifa_family == AF_INET6)
253 fprintf(fp, " inet6 ");
254 else
255 fprintf(fp, " family %d ", ifa->ifa_family);
256
257 if (rta_tb[IFA_LOCAL]) {
258 fprintf(fp, "%s", rt_addr_n2a(ifa->ifa_family,
259 RTA_PAYLOAD(rta_tb[IFA_LOCAL]),
260 RTA_DATA(rta_tb[IFA_LOCAL]),
261 abuf, sizeof(abuf)));
262
263 if (rta_tb[IFA_ADDRESS] == NULL ||
264 memcmp(RTA_DATA(rta_tb[IFA_ADDRESS]), RTA_DATA(rta_tb[IFA_LOCAL]), 4) == 0) {
265 fprintf(fp, "/%d ", ifa->ifa_prefixlen);
266 } else {
267 fprintf(fp, " peer %s/%d ",
268 rt_addr_n2a(ifa->ifa_family,
269 RTA_PAYLOAD(rta_tb[IFA_ADDRESS]),
270 RTA_DATA(rta_tb[IFA_ADDRESS]),
271 abuf, sizeof(abuf)),
272 ifa->ifa_prefixlen);
273 }
274 }
275
276 if (rta_tb[IFA_BROADCAST]) {
277 fprintf(fp, "brd %s ",
278 rt_addr_n2a(ifa->ifa_family,
279 RTA_PAYLOAD(rta_tb[IFA_BROADCAST]),
280 RTA_DATA(rta_tb[IFA_BROADCAST]),
281 abuf, sizeof(abuf)));
282 }
283 if (rta_tb[IFA_ANYCAST]) {
284 fprintf(fp, "any %s ",
285 rt_addr_n2a(ifa->ifa_family,
286 RTA_PAYLOAD(rta_tb[IFA_ANYCAST]),
287 RTA_DATA(rta_tb[IFA_ANYCAST]),
288 abuf, sizeof(abuf)));
289 }
290 fprintf(fp, "scope %s ", rtnl_rtscope_n2a(ifa->ifa_scope, b1, sizeof(b1)));
291 if (ifa->ifa_flags&IFA_F_SECONDARY) {
292 ifa->ifa_flags &= ~IFA_F_SECONDARY;
293 fprintf(fp, "secondary ");
294 }
295 if (ifa->ifa_flags&IFA_F_TENTATIVE) {
296 ifa->ifa_flags &= ~IFA_F_TENTATIVE;
297 fprintf(fp, "tentative ");
298 }
299 if (ifa->ifa_flags&IFA_F_DEPRECATED) {
300 ifa->ifa_flags &= ~IFA_F_DEPRECATED;
301 fprintf(fp, "deprecated ");
302 }
303 if (!(ifa->ifa_flags&IFA_F_PERMANENT)) {
304 fprintf(fp, "dynamic ");
305 } else
306 ifa->ifa_flags &= ~IFA_F_PERMANENT;
307 if (ifa->ifa_flags)
308 fprintf(fp, "flags %02x ", ifa->ifa_flags);
309 if (rta_tb[IFA_LABEL])
310 fprintf(fp, "%s", (char*)RTA_DATA(rta_tb[IFA_LABEL]));
311 if (rta_tb[IFA_CACHEINFO]) {
312 struct ifa_cacheinfo *ci = RTA_DATA(rta_tb[IFA_CACHEINFO]);
313 char buf[128];
314 fprintf(fp, "%s", _SL_);
315 if (ci->ifa_valid == 0xFFFFFFFFU)
316 sprintf(buf, "valid_lft forever");
317 else
318 sprintf(buf, "valid_lft %dsec", ci->ifa_valid);
319 if (ci->ifa_prefered == 0xFFFFFFFFU)
320 sprintf(buf+strlen(buf), " preferred_lft forever");
321 else
322 sprintf(buf+strlen(buf), " preferred_lft %dsec", ci->ifa_prefered);
323 fprintf(fp, " %s", buf);
324 }
325 fprintf(fp, "\n");
326 fflush(fp);
327 return 0;
328}
329
330
331struct nlmsg_list
332{
333 struct nlmsg_list *next;
334 struct nlmsghdr h;
335};
336
Glenn L McGrath2626ef62002-12-02 01:40:05 +0000337static int print_selected_addrinfo(int ifindex, struct nlmsg_list *ainfo, FILE *fp)
Glenn L McGrath9a2d2722002-11-10 01:33:55 +0000338{
339 for ( ;ainfo ; ainfo = ainfo->next) {
340 struct nlmsghdr *n = &ainfo->h;
341 struct ifaddrmsg *ifa = NLMSG_DATA(n);
342
343 if (n->nlmsg_type != RTM_NEWADDR)
344 continue;
345
346 if (n->nlmsg_len < NLMSG_LENGTH(sizeof(ifa)))
347 return -1;
348
349 if (ifa->ifa_index != ifindex ||
350 (filter.family && filter.family != ifa->ifa_family))
351 continue;
352
353 print_addrinfo(NULL, n, fp);
354 }
355 return 0;
356}
357
358
Glenn L McGrath2626ef62002-12-02 01:40:05 +0000359static int store_nlmsg(struct sockaddr_nl *who, struct nlmsghdr *n, void *arg)
Glenn L McGrath9a2d2722002-11-10 01:33:55 +0000360{
361 struct nlmsg_list **linfo = (struct nlmsg_list**)arg;
362 struct nlmsg_list *h;
363 struct nlmsg_list **lp;
364
365 h = malloc(n->nlmsg_len+sizeof(void*));
366 if (h == NULL)
367 return -1;
368
369 memcpy(&h->h, n, n->nlmsg_len);
370 h->next = NULL;
371
372 for (lp = linfo; *lp; lp = &(*lp)->next) /* NOTHING */;
373 *lp = h;
374
375 ll_remember_index(who, n, NULL);
376 return 0;
377}
378
Glenn L McGrath2626ef62002-12-02 01:40:05 +0000379static void ipaddr_reset_filter(int _oneline)
Glenn L McGrath9a2d2722002-11-10 01:33:55 +0000380{
Glenn L McGrath2626ef62002-12-02 01:40:05 +0000381 memset(&filter, 0, sizeof(filter));
382 filter.oneline = _oneline;
383}
384
385extern int ipaddr_list(int argc, char **argv)
386{
387 const char *option[] = { "to", "scope", "up", "label", "dev", 0 };
Glenn L McGrath9a2d2722002-11-10 01:33:55 +0000388 struct nlmsg_list *linfo = NULL;
389 struct nlmsg_list *ainfo = NULL;
390 struct nlmsg_list *l;
391 struct rtnl_handle rth;
392 char *filter_dev = NULL;
393 int no_link = 0;
394
395 ipaddr_reset_filter(oneline);
396 filter.showqueue = 1;
397
398 if (filter.family == AF_UNSPEC)
399 filter.family = preferred_family;
400
401 while (argc > 0) {
Glenn L McGrath2626ef62002-12-02 01:40:05 +0000402 const unsigned short option_num = compare_string_array(option, *argv);
403 switch (option_num) {
404 case 0: /* to */
Glenn L McGrath9a2d2722002-11-10 01:33:55 +0000405 NEXT_ARG();
Glenn L McGrath2626ef62002-12-02 01:40:05 +0000406 get_prefix(&filter.pfx, *argv, filter.family);
407 if (filter.family == AF_UNSPEC) {
408 filter.family = filter.pfx.family;
409 }
410 break;
411 case 1: /* scope */
412 {
413 int scope = 0;
414 NEXT_ARG();
415 filter.scopemask = -1;
416 if (rtnl_rtscope_a2n(&scope, *argv)) {
417 if (strcmp(*argv, "all") != 0) {
418 invarg("invalid \"scope\"\n", *argv);
419 }
420 scope = RT_SCOPE_NOWHERE;
421 filter.scopemask = 0;
422 }
423 filter.scope = scope;
424 break;
Glenn L McGrath9a2d2722002-11-10 01:33:55 +0000425 }
Glenn L McGrath2626ef62002-12-02 01:40:05 +0000426 case 2: /* up */
427 filter.up = 1;
428 break;
429 case 3: /* label */
430 NEXT_ARG();
431 filter.label = *argv;
432 break;
433 case 4: /* dev */
434 NEXT_ARG();
435 default:
436 if (filter_dev) {
437 duparg2("dev", *argv);
438 }
439 filter_dev = *argv;
Glenn L McGrath9a2d2722002-11-10 01:33:55 +0000440 }
Glenn L McGrath2626ef62002-12-02 01:40:05 +0000441 argv++;
442 argc--;
Glenn L McGrath9a2d2722002-11-10 01:33:55 +0000443 }
444
445 if (rtnl_open(&rth, 0) < 0)
446 exit(1);
447
448 if (rtnl_wilddump_request(&rth, preferred_family, RTM_GETLINK) < 0) {
Glenn L McGrathdf725362002-11-28 10:49:14 +0000449 perror_msg_and_die("Cannot send dump request");
Glenn L McGrath9a2d2722002-11-10 01:33:55 +0000450 }
451
452 if (rtnl_dump_filter(&rth, store_nlmsg, &linfo, NULL, NULL) < 0) {
Glenn L McGrathdf725362002-11-28 10:49:14 +0000453 error_msg_and_die("Dump terminated");
Glenn L McGrath9a2d2722002-11-10 01:33:55 +0000454 }
455
456 if (filter_dev) {
457 filter.ifindex = ll_name_to_index(filter_dev);
458 if (filter.ifindex <= 0) {
Glenn L McGrathdf725362002-11-28 10:49:14 +0000459 error_msg("Device \"%s\" does not exist.", filter_dev);
Glenn L McGrath9a2d2722002-11-10 01:33:55 +0000460 return -1;
461 }
462 }
463
464 if (filter.family != AF_PACKET) {
465 if (rtnl_wilddump_request(&rth, filter.family, RTM_GETADDR) < 0) {
Glenn L McGrathdf725362002-11-28 10:49:14 +0000466 perror_msg_and_die("Cannot send dump request");
Glenn L McGrath9a2d2722002-11-10 01:33:55 +0000467 }
468
469 if (rtnl_dump_filter(&rth, store_nlmsg, &ainfo, NULL, NULL) < 0) {
Glenn L McGrathdf725362002-11-28 10:49:14 +0000470 error_msg_and_die("Dump terminated");
Glenn L McGrath9a2d2722002-11-10 01:33:55 +0000471 }
472 }
473
474
475 if (filter.family && filter.family != AF_PACKET) {
476 struct nlmsg_list **lp;
477 lp=&linfo;
478
479 if (filter.oneline)
480 no_link = 1;
481
482 while ((l=*lp)!=NULL) {
483 int ok = 0;
484 struct ifinfomsg *ifi = NLMSG_DATA(&l->h);
485 struct nlmsg_list *a;
486
487 for (a=ainfo; a; a=a->next) {
488 struct nlmsghdr *n = &a->h;
489 struct ifaddrmsg *ifa = NLMSG_DATA(n);
490
491 if (ifa->ifa_index != ifi->ifi_index ||
492 (filter.family && filter.family != ifa->ifa_family))
493 continue;
494 if ((filter.scope^ifa->ifa_scope)&filter.scopemask)
495 continue;
496 if ((filter.flags^ifa->ifa_flags)&filter.flagmask)
497 continue;
498 if (filter.pfx.family || filter.label) {
499 struct rtattr *tb[IFA_MAX+1];
500 memset(tb, 0, sizeof(tb));
501 parse_rtattr(tb, IFA_MAX, IFA_RTA(ifa), IFA_PAYLOAD(n));
502 if (!tb[IFA_LOCAL])
503 tb[IFA_LOCAL] = tb[IFA_ADDRESS];
504
505 if (filter.pfx.family && tb[IFA_LOCAL]) {
506 inet_prefix dst;
507 memset(&dst, 0, sizeof(dst));
508 dst.family = ifa->ifa_family;
509 memcpy(&dst.data, RTA_DATA(tb[IFA_LOCAL]), RTA_PAYLOAD(tb[IFA_LOCAL]));
510 if (inet_addr_match(&dst, &filter.pfx, filter.pfx.bitlen))
511 continue;
512 }
513 if (filter.label) {
514 SPRINT_BUF(b1);
515 const char *label;
516 if (tb[IFA_LABEL])
517 label = RTA_DATA(tb[IFA_LABEL]);
518 else
519 label = ll_idx_n2a(ifa->ifa_index, b1);
520 if (fnmatch(filter.label, label, 0) != 0)
521 continue;
522 }
523 }
524
525 ok = 1;
526 break;
527 }
528 if (!ok)
529 *lp = l->next;
530 else
531 lp = &l->next;
532 }
533 }
534
535 for (l=linfo; l; l = l->next) {
536 if (no_link || print_linkinfo(NULL, &l->h, stdout) == 0) {
537 struct ifinfomsg *ifi = NLMSG_DATA(&l->h);
538 if (filter.family != AF_PACKET)
539 print_selected_addrinfo(ifi->ifi_index, ainfo, stdout);
540 }
541 fflush(stdout);
542 }
543
544 exit(0);
545}
546
Glenn L McGrath2626ef62002-12-02 01:40:05 +0000547static int default_scope(inet_prefix *lcl)
Glenn L McGrath9a2d2722002-11-10 01:33:55 +0000548{
549 if (lcl->family == AF_INET) {
550 if (lcl->bytelen >= 1 && *(__u8*)&lcl->data == 127)
551 return RT_SCOPE_HOST;
552 }
553 return 0;
554}
555
Glenn L McGrath2626ef62002-12-02 01:40:05 +0000556static int ipaddr_modify(int cmd, int argc, char **argv)
Glenn L McGrath9a2d2722002-11-10 01:33:55 +0000557{
Glenn L McGrath2626ef62002-12-02 01:40:05 +0000558 const char *option[] = { "peer", "remote", "broadcast", "brd",
559 "anycast", "scope", "dev", "label", "local", 0 };
Glenn L McGrath9a2d2722002-11-10 01:33:55 +0000560 struct rtnl_handle rth;
561 struct {
562 struct nlmsghdr n;
563 struct ifaddrmsg ifa;
564 char buf[256];
565 } req;
566 char *d = NULL;
567 char *l = NULL;
568 inet_prefix lcl;
569 inet_prefix peer;
570 int local_len = 0;
571 int peer_len = 0;
572 int brd_len = 0;
573 int any_len = 0;
574 int scoped = 0;
575
576 memset(&req, 0, sizeof(req));
577
578 req.n.nlmsg_len = NLMSG_LENGTH(sizeof(struct ifaddrmsg));
579 req.n.nlmsg_flags = NLM_F_REQUEST;
580 req.n.nlmsg_type = cmd;
581 req.ifa.ifa_family = preferred_family;
582
583 while (argc > 0) {
Glenn L McGrath2626ef62002-12-02 01:40:05 +0000584 const unsigned short option_num = compare_string_array(option, *argv);
585 switch (option_num) {
586 case 0: /* peer */
587 case 1: /* remote */
Glenn L McGrath9a2d2722002-11-10 01:33:55 +0000588 NEXT_ARG();
Glenn L McGrath2626ef62002-12-02 01:40:05 +0000589
590 if (peer_len) {
591 duparg("peer", *argv);
592 }
593 get_prefix(&peer, *argv, req.ifa.ifa_family);
594 peer_len = peer.bytelen;
595 if (req.ifa.ifa_family == AF_UNSPEC) {
596 req.ifa.ifa_family = peer.family;
597 }
598 addattr_l(&req.n, sizeof(req), IFA_ADDRESS, &peer.data, peer.bytelen);
599 req.ifa.ifa_prefixlen = peer.bitlen;
600 break;
601 case 2: /* broadcast */
602 case 3: /* brd */
603 {
604 inet_prefix addr;
605 NEXT_ARG();
606 if (brd_len) {
607 duparg("broadcast", *argv);
608 }
609 if (strcmp(*argv, "+") == 0) {
610 brd_len = -1;
611 }
612 else if (strcmp(*argv, "-") == 0) {
613 brd_len = -2;
614 } else {
615 get_addr(&addr, *argv, req.ifa.ifa_family);
616 if (req.ifa.ifa_family == AF_UNSPEC)
617 req.ifa.ifa_family = addr.family;
618 addattr_l(&req.n, sizeof(req), IFA_BROADCAST, &addr.data, addr.bytelen);
619 brd_len = addr.bytelen;
620 }
621 break;
Glenn L McGrath9a2d2722002-11-10 01:33:55 +0000622 }
Glenn L McGrath2626ef62002-12-02 01:40:05 +0000623 case 4: /* anycast */
624 {
625 inet_prefix addr;
626 NEXT_ARG();
627 if (any_len) {
628 duparg("anycast", *argv);
629 }
630 get_addr(&addr, *argv, req.ifa.ifa_family);
631 if (req.ifa.ifa_family == AF_UNSPEC) {
632 req.ifa.ifa_family = addr.family;
633 }
634 addattr_l(&req.n, sizeof(req), IFA_ANYCAST, &addr.data, addr.bytelen);
635 any_len = addr.bytelen;
636 break;
637 }
638 case 5: /* scope */
639 {
640 int scope = 0;
641 NEXT_ARG();
642 if (rtnl_rtscope_a2n(&scope, *argv)) {
643 invarg(*argv, "invalid scope value.");
644 }
645 req.ifa.ifa_scope = scope;
646 scoped = 1;
647 break;
648 }
649 case 6: /* dev */
650 NEXT_ARG();
651 d = *argv;
652 break;
653 case 7: /* label */
654 NEXT_ARG();
655 l = *argv;
656 addattr_l(&req.n, sizeof(req), IFA_LABEL, l, strlen(l)+1);
657 break;
658 case 8: /* local */
659 NEXT_ARG();
660 default:
661 if (local_len) {
662 duparg2("local", *argv);
663 }
664 get_prefix(&lcl, *argv, req.ifa.ifa_family);
665 if (req.ifa.ifa_family == AF_UNSPEC) {
666 req.ifa.ifa_family = lcl.family;
667 }
668 addattr_l(&req.n, sizeof(req), IFA_LOCAL, &lcl.data, lcl.bytelen);
669 local_len = lcl.bytelen;
Glenn L McGrath9a2d2722002-11-10 01:33:55 +0000670 }
Glenn L McGrath2626ef62002-12-02 01:40:05 +0000671 argc--;
672 argv++;
Glenn L McGrath9a2d2722002-11-10 01:33:55 +0000673 }
Glenn L McGrath2626ef62002-12-02 01:40:05 +0000674
Glenn L McGrath9a2d2722002-11-10 01:33:55 +0000675 if (d == NULL) {
Glenn L McGrathdf725362002-11-28 10:49:14 +0000676 error_msg("Not enough information: \"dev\" argument is required.");
Glenn L McGrath9a2d2722002-11-10 01:33:55 +0000677 return -1;
678 }
679 if (l && matches(d, l) != 0) {
Glenn L McGrathdf725362002-11-28 10:49:14 +0000680 error_msg_and_die("\"dev\" (%s) must match \"label\" (%s).", d, l);
Glenn L McGrath9a2d2722002-11-10 01:33:55 +0000681 }
682
683 if (peer_len == 0 && local_len && cmd != RTM_DELADDR) {
684 peer = lcl;
685 addattr_l(&req.n, sizeof(req), IFA_ADDRESS, &lcl.data, lcl.bytelen);
686 }
687 if (req.ifa.ifa_prefixlen == 0)
688 req.ifa.ifa_prefixlen = lcl.bitlen;
689
690 if (brd_len < 0 && cmd != RTM_DELADDR) {
691 inet_prefix brd;
692 int i;
693 if (req.ifa.ifa_family != AF_INET) {
Glenn L McGrathdf725362002-11-28 10:49:14 +0000694 error_msg("Broadcast can be set only for IPv4 addresses");
Glenn L McGrath9a2d2722002-11-10 01:33:55 +0000695 return -1;
696 }
697 brd = peer;
698 if (brd.bitlen <= 30) {
699 for (i=31; i>=brd.bitlen; i--) {
700 if (brd_len == -1)
701 brd.data[0] |= htonl(1<<(31-i));
702 else
703 brd.data[0] &= ~htonl(1<<(31-i));
704 }
705 addattr_l(&req.n, sizeof(req), IFA_BROADCAST, &brd.data, brd.bytelen);
706 brd_len = brd.bytelen;
707 }
708 }
709 if (!scoped && cmd != RTM_DELADDR)
710 req.ifa.ifa_scope = default_scope(&lcl);
711
712 if (rtnl_open(&rth, 0) < 0)
713 exit(1);
714
715 ll_init_map(&rth);
716
717 if ((req.ifa.ifa_index = ll_name_to_index(d)) == 0) {
Glenn L McGrathdf725362002-11-28 10:49:14 +0000718 error_msg("Cannot find device \"%s\"", d);
Glenn L McGrath9a2d2722002-11-10 01:33:55 +0000719 return -1;
720 }
721
722 if (rtnl_talk(&rth, &req.n, 0, 0, NULL, NULL, NULL) < 0)
723 exit(2);
724
725 exit(0);
726}
727
Glenn L McGrath2626ef62002-12-02 01:40:05 +0000728extern int do_ipaddr(int argc, char **argv)
Glenn L McGrath9a2d2722002-11-10 01:33:55 +0000729{
Glenn L McGrath2626ef62002-12-02 01:40:05 +0000730 const char *commands[] = { "add", "delete", "list", "show", "lst", 0 };
731 unsigned short command_num = 2;
732
733 if (*argv) {
734 command_num = compare_string_array(commands, *argv);
735 }
736 switch (command_num) {
737 case 0: /* add */
738 return ipaddr_modify(RTM_NEWADDR, argc-1, argv+1);
739 case 1: /* delete */
740 return ipaddr_modify(RTM_DELADDR, argc-1, argv+1);
741 case 2: /* list */
742 case 3: /* show */
743 case 4: /* lst */
744 return ipaddr_list(argc-1, argv+1);
745 }
746 error_msg_and_die("Unknown command %s", *argv);
Glenn L McGrath9a2d2722002-11-10 01:33:55 +0000747}