blob: 262d3e356cfa290ac264ce328e26ff6503d66789 [file] [log] [blame]
"Robert P. J. Day"63fc1a92006-07-02 19:47:05 +00001/* vi: set sw=4 ts=4: */
Glenn L McGrath9a2d2722002-11-10 01:33:55 +00002/*
3 * ipaddress.c "ip address".
4 *
Bernhard Reutner-Fischer20f40002006-01-30 17:17:14 +00005 * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
Glenn L McGrath9a2d2722002-11-10 01:33:55 +00006 *
7 * Authors: Alexey Kuznetsov, <kuznet@ms2.inr.ac.ru>
8 *
9 * Changes:
10 * Laszlo Valko <valko@linux.karinthy.hu> 990223: address label must be zero terminated
11 */
12
Rob Landleyecae66a2006-06-02 20:53:38 +000013#include "libbb.h"
Glenn L McGrath9a2d2722002-11-10 01:33:55 +000014#include <sys/socket.h>
15#include <sys/ioctl.h>
Glenn L McGrath275be872002-12-16 07:37:21 +000016
Glenn L McGrath9a2d2722002-11-10 01:33:55 +000017#include <fnmatch.h>
Glenn L McGrath275be872002-12-16 07:37:21 +000018#include <string.h>
19#include <unistd.h>
20
Eric Andersen8004bb72003-01-14 08:06:07 +000021#include <net/if.h>
22#include <net/if_arp.h>
Glenn L McGrath9a2d2722002-11-10 01:33:55 +000023
24#include "rt_names.h"
25#include "utils.h"
Bernhard Reutner-Fischer1d62d3b2005-10-08 20:47:15 +000026#include "ip_common.h"
Glenn L McGrath9a2d2722002-11-10 01:33:55 +000027
Glenn L McGrath9a2d2722002-11-10 01:33:55 +000028
29static struct
30{
31 int ifindex;
32 int family;
33 int oneline;
34 int showqueue;
35 inet_prefix pfx;
36 int scope, scopemask;
37 int flags, flagmask;
38 int up;
39 char *label;
Glenn L McGrathd66370c2003-01-13 21:40:38 +000040 int flushed;
41 char *flushb;
42 int flushp;
43 int flushe;
Glenn L McGrath9a2d2722002-11-10 01:33:55 +000044 struct rtnl_handle *rth;
45} filter;
46
Eric Andersen14f5c8d2005-04-16 19:39:00 +000047static void print_link_flags(FILE *fp, unsigned flags, unsigned mdown)
Glenn L McGrath9a2d2722002-11-10 01:33:55 +000048{
49 fprintf(fp, "<");
50 flags &= ~IFF_RUNNING;
51#define _PF(f) if (flags&IFF_##f) { \
Tim Rikerc1ef7bd2006-01-25 00:08:53 +000052 flags &= ~IFF_##f ; \
53 fprintf(fp, #f "%s", flags ? "," : ""); }
Glenn L McGrath9a2d2722002-11-10 01:33:55 +000054 _PF(LOOPBACK);
55 _PF(BROADCAST);
56 _PF(POINTOPOINT);
57 _PF(MULTICAST);
58 _PF(NOARP);
59#if 0
60 _PF(ALLMULTI);
61 _PF(PROMISC);
62 _PF(MASTER);
63 _PF(SLAVE);
64 _PF(DEBUG);
65 _PF(DYNAMIC);
66 _PF(AUTOMEDIA);
67 _PF(PORTSEL);
68 _PF(NOTRAILERS);
69#endif
70 _PF(UP);
71#undef _PF
Tim Rikerc1ef7bd2006-01-25 00:08:53 +000072 if (flags)
Glenn L McGrath9a2d2722002-11-10 01:33:55 +000073 fprintf(fp, "%x", flags);
74 if (mdown)
75 fprintf(fp, ",M-DOWN");
76 fprintf(fp, "> ");
77}
78
Glenn L McGrath2626ef62002-12-02 01:40:05 +000079static void print_queuelen(char *name)
Glenn L McGrath9a2d2722002-11-10 01:33:55 +000080{
81 struct ifreq ifr;
82 int s;
83
84 s = socket(AF_INET, SOCK_STREAM, 0);
85 if (s < 0)
86 return;
87
88 memset(&ifr, 0, sizeof(ifr));
89 strcpy(ifr.ifr_name, name);
Eric Andersenc7bda1c2004-03-15 08:29:22 +000090 if (ioctl(s, SIOCGIFTXQLEN, &ifr) < 0) {
Glenn L McGrath9a2d2722002-11-10 01:33:55 +000091 perror("SIOCGIFXQLEN");
92 close(s);
93 return;
94 }
95 close(s);
96
97 if (ifr.ifr_qlen)
98 printf("qlen %d", ifr.ifr_qlen);
99}
100
Bernhard Reutner-Fischer20f40002006-01-30 17:17:14 +0000101static int print_linkinfo(struct sockaddr_nl ATTRIBUTE_UNUSED *who,
102 struct nlmsghdr *n, void ATTRIBUTE_UNUSED *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) {
Manuel Novoa III cad53642003-03-19 09:13:01 +0000125 bb_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]));
Eric Andersenc7bda1c2004-03-15 08:29:22 +0000166
Glenn L McGrath9a2d2722002-11-10 01:33:55 +0000167 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 McGrathd66370c2003-01-13 21:40:38 +0000194static int flush_update(void)
195{
196 if (rtnl_send(filter.rth, filter.flushb, filter.flushp) < 0) {
197 perror("Failed to send flush request\n");
198 return -1;
199 }
200 filter.flushp = 0;
201 return 0;
202}
203
Bernhard Reutner-Fischer20f40002006-01-30 17:17:14 +0000204static int print_addrinfo(struct sockaddr_nl ATTRIBUTE_UNUSED *who,
205 struct nlmsghdr *n, void ATTRIBUTE_UNUSED *arg)
Glenn L McGrath9a2d2722002-11-10 01:33:55 +0000206{
207 FILE *fp = (FILE*)arg;
208 struct ifaddrmsg *ifa = NLMSG_DATA(n);
209 int len = n->nlmsg_len;
210 struct rtattr * rta_tb[IFA_MAX+1];
211 char abuf[256];
212 SPRINT_BUF(b1);
213
214 if (n->nlmsg_type != RTM_NEWADDR && n->nlmsg_type != RTM_DELADDR)
215 return 0;
216 len -= NLMSG_LENGTH(sizeof(*ifa));
217 if (len < 0) {
Manuel Novoa III cad53642003-03-19 09:13:01 +0000218 bb_error_msg("wrong nlmsg len %d", len);
Glenn L McGrath9a2d2722002-11-10 01:33:55 +0000219 return -1;
220 }
221
Glenn L McGrathd66370c2003-01-13 21:40:38 +0000222 if (filter.flushb && n->nlmsg_type != RTM_NEWADDR)
223 return 0;
224
Glenn L McGrath9a2d2722002-11-10 01:33:55 +0000225 memset(rta_tb, 0, sizeof(rta_tb));
226 parse_rtattr(rta_tb, IFA_MAX, IFA_RTA(ifa), n->nlmsg_len - NLMSG_LENGTH(sizeof(*ifa)));
227
228 if (!rta_tb[IFA_LOCAL])
229 rta_tb[IFA_LOCAL] = rta_tb[IFA_ADDRESS];
230 if (!rta_tb[IFA_ADDRESS])
231 rta_tb[IFA_ADDRESS] = rta_tb[IFA_LOCAL];
232
233 if (filter.ifindex && filter.ifindex != ifa->ifa_index)
234 return 0;
235 if ((filter.scope^ifa->ifa_scope)&filter.scopemask)
236 return 0;
237 if ((filter.flags^ifa->ifa_flags)&filter.flagmask)
238 return 0;
239 if (filter.label) {
Glenn L McGrath9a2d2722002-11-10 01:33:55 +0000240 const char *label;
241 if (rta_tb[IFA_LABEL])
242 label = RTA_DATA(rta_tb[IFA_LABEL]);
243 else
244 label = ll_idx_n2a(ifa->ifa_index, b1);
245 if (fnmatch(filter.label, label, 0) != 0)
246 return 0;
247 }
248 if (filter.pfx.family) {
249 if (rta_tb[IFA_LOCAL]) {
250 inet_prefix dst;
251 memset(&dst, 0, sizeof(dst));
252 dst.family = ifa->ifa_family;
253 memcpy(&dst.data, RTA_DATA(rta_tb[IFA_LOCAL]), RTA_PAYLOAD(rta_tb[IFA_LOCAL]));
254 if (inet_addr_match(&dst, &filter.pfx, filter.pfx.bitlen))
255 return 0;
256 }
257 }
258
Glenn L McGrathd66370c2003-01-13 21:40:38 +0000259 if (filter.flushb) {
260 struct nlmsghdr *fn;
261 if (NLMSG_ALIGN(filter.flushp) + n->nlmsg_len > filter.flushe) {
262 if (flush_update())
263 return -1;
264 }
265 fn = (struct nlmsghdr*)(filter.flushb + NLMSG_ALIGN(filter.flushp));
266 memcpy(fn, n, n->nlmsg_len);
267 fn->nlmsg_type = RTM_DELADDR;
268 fn->nlmsg_flags = NLM_F_REQUEST;
269 fn->nlmsg_seq = ++filter.rth->seq;
270 filter.flushp = (((char*)fn) + n->nlmsg_len) - filter.flushb;
271 filter.flushed++;
272 return 0;
273 }
274
Glenn L McGrath9a2d2722002-11-10 01:33:55 +0000275 if (n->nlmsg_type == RTM_DELADDR)
276 fprintf(fp, "Deleted ");
277
278 if (filter.oneline)
279 fprintf(fp, "%u: %s", ifa->ifa_index, ll_index_to_name(ifa->ifa_index));
280 if (ifa->ifa_family == AF_INET)
281 fprintf(fp, " inet ");
282 else if (ifa->ifa_family == AF_INET6)
283 fprintf(fp, " inet6 ");
284 else
285 fprintf(fp, " family %d ", ifa->ifa_family);
286
287 if (rta_tb[IFA_LOCAL]) {
288 fprintf(fp, "%s", rt_addr_n2a(ifa->ifa_family,
289 RTA_PAYLOAD(rta_tb[IFA_LOCAL]),
290 RTA_DATA(rta_tb[IFA_LOCAL]),
291 abuf, sizeof(abuf)));
292
293 if (rta_tb[IFA_ADDRESS] == NULL ||
294 memcmp(RTA_DATA(rta_tb[IFA_ADDRESS]), RTA_DATA(rta_tb[IFA_LOCAL]), 4) == 0) {
295 fprintf(fp, "/%d ", ifa->ifa_prefixlen);
296 } else {
297 fprintf(fp, " peer %s/%d ",
298 rt_addr_n2a(ifa->ifa_family,
299 RTA_PAYLOAD(rta_tb[IFA_ADDRESS]),
300 RTA_DATA(rta_tb[IFA_ADDRESS]),
301 abuf, sizeof(abuf)),
302 ifa->ifa_prefixlen);
303 }
304 }
305
306 if (rta_tb[IFA_BROADCAST]) {
307 fprintf(fp, "brd %s ",
308 rt_addr_n2a(ifa->ifa_family,
309 RTA_PAYLOAD(rta_tb[IFA_BROADCAST]),
310 RTA_DATA(rta_tb[IFA_BROADCAST]),
311 abuf, sizeof(abuf)));
312 }
313 if (rta_tb[IFA_ANYCAST]) {
314 fprintf(fp, "any %s ",
315 rt_addr_n2a(ifa->ifa_family,
316 RTA_PAYLOAD(rta_tb[IFA_ANYCAST]),
317 RTA_DATA(rta_tb[IFA_ANYCAST]),
318 abuf, sizeof(abuf)));
319 }
320 fprintf(fp, "scope %s ", rtnl_rtscope_n2a(ifa->ifa_scope, b1, sizeof(b1)));
321 if (ifa->ifa_flags&IFA_F_SECONDARY) {
322 ifa->ifa_flags &= ~IFA_F_SECONDARY;
323 fprintf(fp, "secondary ");
324 }
325 if (ifa->ifa_flags&IFA_F_TENTATIVE) {
326 ifa->ifa_flags &= ~IFA_F_TENTATIVE;
327 fprintf(fp, "tentative ");
328 }
329 if (ifa->ifa_flags&IFA_F_DEPRECATED) {
330 ifa->ifa_flags &= ~IFA_F_DEPRECATED;
331 fprintf(fp, "deprecated ");
332 }
333 if (!(ifa->ifa_flags&IFA_F_PERMANENT)) {
334 fprintf(fp, "dynamic ");
335 } else
336 ifa->ifa_flags &= ~IFA_F_PERMANENT;
337 if (ifa->ifa_flags)
338 fprintf(fp, "flags %02x ", ifa->ifa_flags);
339 if (rta_tb[IFA_LABEL])
340 fprintf(fp, "%s", (char*)RTA_DATA(rta_tb[IFA_LABEL]));
341 if (rta_tb[IFA_CACHEINFO]) {
342 struct ifa_cacheinfo *ci = RTA_DATA(rta_tb[IFA_CACHEINFO]);
343 char buf[128];
344 fprintf(fp, "%s", _SL_);
345 if (ci->ifa_valid == 0xFFFFFFFFU)
346 sprintf(buf, "valid_lft forever");
347 else
348 sprintf(buf, "valid_lft %dsec", ci->ifa_valid);
349 if (ci->ifa_prefered == 0xFFFFFFFFU)
350 sprintf(buf+strlen(buf), " preferred_lft forever");
351 else
352 sprintf(buf+strlen(buf), " preferred_lft %dsec", ci->ifa_prefered);
353 fprintf(fp, " %s", buf);
354 }
355 fprintf(fp, "\n");
356 fflush(fp);
357 return 0;
358}
359
360
361struct nlmsg_list
362{
363 struct nlmsg_list *next;
364 struct nlmsghdr h;
365};
366
Glenn L McGrath2626ef62002-12-02 01:40:05 +0000367static int print_selected_addrinfo(int ifindex, struct nlmsg_list *ainfo, FILE *fp)
Glenn L McGrath9a2d2722002-11-10 01:33:55 +0000368{
369 for ( ;ainfo ; ainfo = ainfo->next) {
370 struct nlmsghdr *n = &ainfo->h;
371 struct ifaddrmsg *ifa = NLMSG_DATA(n);
372
373 if (n->nlmsg_type != RTM_NEWADDR)
374 continue;
375
376 if (n->nlmsg_len < NLMSG_LENGTH(sizeof(ifa)))
377 return -1;
378
Eric Andersenc7bda1c2004-03-15 08:29:22 +0000379 if (ifa->ifa_index != ifindex ||
Glenn L McGrath9a2d2722002-11-10 01:33:55 +0000380 (filter.family && filter.family != ifa->ifa_family))
381 continue;
382
383 print_addrinfo(NULL, n, fp);
384 }
385 return 0;
386}
387
388
Glenn L McGrath2626ef62002-12-02 01:40:05 +0000389static int store_nlmsg(struct sockaddr_nl *who, struct nlmsghdr *n, void *arg)
Glenn L McGrath9a2d2722002-11-10 01:33:55 +0000390{
391 struct nlmsg_list **linfo = (struct nlmsg_list**)arg;
392 struct nlmsg_list *h;
393 struct nlmsg_list **lp;
394
395 h = malloc(n->nlmsg_len+sizeof(void*));
396 if (h == NULL)
397 return -1;
398
399 memcpy(&h->h, n, n->nlmsg_len);
400 h->next = NULL;
401
402 for (lp = linfo; *lp; lp = &(*lp)->next) /* NOTHING */;
403 *lp = h;
404
405 ll_remember_index(who, n, NULL);
406 return 0;
407}
408
Glenn L McGrath2626ef62002-12-02 01:40:05 +0000409static void ipaddr_reset_filter(int _oneline)
Glenn L McGrath9a2d2722002-11-10 01:33:55 +0000410{
Glenn L McGrath2626ef62002-12-02 01:40:05 +0000411 memset(&filter, 0, sizeof(filter));
412 filter.oneline = _oneline;
413}
414
Rob Landleydfba7412006-03-06 20:47:33 +0000415int ipaddr_list_or_flush(int argc, char **argv, int flush)
Glenn L McGrath2626ef62002-12-02 01:40:05 +0000416{
Rob Landley0a7c8ef2006-02-22 17:01:00 +0000417 static const char *const option[] = { "to", "scope", "up", "label", "dev", 0 };
418
Glenn L McGrath9a2d2722002-11-10 01:33:55 +0000419 struct nlmsg_list *linfo = NULL;
420 struct nlmsg_list *ainfo = NULL;
421 struct nlmsg_list *l;
422 struct rtnl_handle rth;
423 char *filter_dev = NULL;
424 int no_link = 0;
425
426 ipaddr_reset_filter(oneline);
427 filter.showqueue = 1;
428
429 if (filter.family == AF_UNSPEC)
430 filter.family = preferred_family;
431
Glenn L McGrathd66370c2003-01-13 21:40:38 +0000432 if (flush) {
433 if (argc <= 0) {
Bernhard Reutner-Fischer19008b82006-06-07 20:17:41 +0000434 bb_error_msg(bb_msg_requires_arg, "flush");
Glenn L McGrathd66370c2003-01-13 21:40:38 +0000435 return -1;
436 }
437 if (filter.family == AF_PACKET) {
Bernhard Reutner-Fischer19008b82006-06-07 20:17:41 +0000438 bb_error_msg("Cannot flush link addresses.");
Glenn L McGrathd66370c2003-01-13 21:40:38 +0000439 return -1;
440 }
441 }
442
Glenn L McGrath9a2d2722002-11-10 01:33:55 +0000443 while (argc > 0) {
"Vladimir N. Oleynik"2f0a5f92005-12-06 12:00:39 +0000444 const int option_num = compare_string_array(option, *argv);
Glenn L McGrath2626ef62002-12-02 01:40:05 +0000445 switch (option_num) {
446 case 0: /* to */
Glenn L McGrath9a2d2722002-11-10 01:33:55 +0000447 NEXT_ARG();
Glenn L McGrath2626ef62002-12-02 01:40:05 +0000448 get_prefix(&filter.pfx, *argv, filter.family);
449 if (filter.family == AF_UNSPEC) {
450 filter.family = filter.pfx.family;
451 }
452 break;
453 case 1: /* scope */
454 {
Eric Andersend78aea82006-01-30 18:00:02 +0000455 uint32_t scope = 0;
Glenn L McGrath2626ef62002-12-02 01:40:05 +0000456 NEXT_ARG();
457 filter.scopemask = -1;
458 if (rtnl_rtscope_a2n(&scope, *argv)) {
459 if (strcmp(*argv, "all") != 0) {
Bernhard Reutner-Fischer19008b82006-06-07 20:17:41 +0000460 invarg(*argv, "scope");
Glenn L McGrath2626ef62002-12-02 01:40:05 +0000461 }
462 scope = RT_SCOPE_NOWHERE;
463 filter.scopemask = 0;
464 }
465 filter.scope = scope;
466 break;
Glenn L McGrath9a2d2722002-11-10 01:33:55 +0000467 }
Glenn L McGrath2626ef62002-12-02 01:40:05 +0000468 case 2: /* up */
469 filter.up = 1;
470 break;
471 case 3: /* label */
472 NEXT_ARG();
473 filter.label = *argv;
474 break;
475 case 4: /* dev */
476 NEXT_ARG();
477 default:
478 if (filter_dev) {
479 duparg2("dev", *argv);
480 }
481 filter_dev = *argv;
Glenn L McGrath9a2d2722002-11-10 01:33:55 +0000482 }
Glenn L McGrath2626ef62002-12-02 01:40:05 +0000483 argv++;
484 argc--;
Glenn L McGrath9a2d2722002-11-10 01:33:55 +0000485 }
486
487 if (rtnl_open(&rth, 0) < 0)
488 exit(1);
489
490 if (rtnl_wilddump_request(&rth, preferred_family, RTM_GETLINK) < 0) {
Manuel Novoa III cad53642003-03-19 09:13:01 +0000491 bb_perror_msg_and_die("Cannot send dump request");
Glenn L McGrath9a2d2722002-11-10 01:33:55 +0000492 }
493
494 if (rtnl_dump_filter(&rth, store_nlmsg, &linfo, NULL, NULL) < 0) {
Manuel Novoa III cad53642003-03-19 09:13:01 +0000495 bb_error_msg_and_die("Dump terminated");
Glenn L McGrath9a2d2722002-11-10 01:33:55 +0000496 }
497
498 if (filter_dev) {
499 filter.ifindex = ll_name_to_index(filter_dev);
500 if (filter.ifindex <= 0) {
Rob Landley0a7c8ef2006-02-22 17:01:00 +0000501 bb_error_msg("Device \"%s\" does not exist", filter_dev);
Glenn L McGrath9a2d2722002-11-10 01:33:55 +0000502 return -1;
503 }
504 }
505
Glenn L McGrathd66370c2003-01-13 21:40:38 +0000506 if (flush) {
Glenn L McGrathd66370c2003-01-13 21:40:38 +0000507 char flushb[4096-512];
508
509 filter.flushb = flushb;
510 filter.flushp = 0;
511 filter.flushe = sizeof(flushb);
512 filter.rth = &rth;
513
514 for (;;) {
515 if (rtnl_wilddump_request(&rth, filter.family, RTM_GETADDR) < 0) {
516 perror("Cannot send dump request");
517 exit(1);
518 }
519 filter.flushed = 0;
520 if (rtnl_dump_filter(&rth, print_addrinfo, stdout, NULL, NULL) < 0) {
521 fprintf(stderr, "Flush terminated\n");
522 exit(1);
523 }
524 if (filter.flushed == 0) {
Glenn L McGrathd66370c2003-01-13 21:40:38 +0000525 fflush(stdout);
526 return 0;
527 }
Glenn L McGrathd66370c2003-01-13 21:40:38 +0000528 if (flush_update() < 0)
529 exit(1);
530 }
531 }
532
Glenn L McGrath9a2d2722002-11-10 01:33:55 +0000533 if (filter.family != AF_PACKET) {
534 if (rtnl_wilddump_request(&rth, filter.family, RTM_GETADDR) < 0) {
Manuel Novoa III cad53642003-03-19 09:13:01 +0000535 bb_perror_msg_and_die("Cannot send dump request");
Glenn L McGrath9a2d2722002-11-10 01:33:55 +0000536 }
537
538 if (rtnl_dump_filter(&rth, store_nlmsg, &ainfo, NULL, NULL) < 0) {
Manuel Novoa III cad53642003-03-19 09:13:01 +0000539 bb_error_msg_and_die("Dump terminated");
Glenn L McGrath9a2d2722002-11-10 01:33:55 +0000540 }
541 }
542
543
544 if (filter.family && filter.family != AF_PACKET) {
545 struct nlmsg_list **lp;
546 lp=&linfo;
547
548 if (filter.oneline)
549 no_link = 1;
550
551 while ((l=*lp)!=NULL) {
552 int ok = 0;
553 struct ifinfomsg *ifi = NLMSG_DATA(&l->h);
554 struct nlmsg_list *a;
555
556 for (a=ainfo; a; a=a->next) {
557 struct nlmsghdr *n = &a->h;
558 struct ifaddrmsg *ifa = NLMSG_DATA(n);
559
Eric Andersenc7bda1c2004-03-15 08:29:22 +0000560 if (ifa->ifa_index != ifi->ifi_index ||
Glenn L McGrath9a2d2722002-11-10 01:33:55 +0000561 (filter.family && filter.family != ifa->ifa_family))
562 continue;
563 if ((filter.scope^ifa->ifa_scope)&filter.scopemask)
564 continue;
565 if ((filter.flags^ifa->ifa_flags)&filter.flagmask)
566 continue;
567 if (filter.pfx.family || filter.label) {
568 struct rtattr *tb[IFA_MAX+1];
569 memset(tb, 0, sizeof(tb));
570 parse_rtattr(tb, IFA_MAX, IFA_RTA(ifa), IFA_PAYLOAD(n));
571 if (!tb[IFA_LOCAL])
572 tb[IFA_LOCAL] = tb[IFA_ADDRESS];
573
574 if (filter.pfx.family && tb[IFA_LOCAL]) {
575 inet_prefix dst;
576 memset(&dst, 0, sizeof(dst));
577 dst.family = ifa->ifa_family;
578 memcpy(&dst.data, RTA_DATA(tb[IFA_LOCAL]), RTA_PAYLOAD(tb[IFA_LOCAL]));
579 if (inet_addr_match(&dst, &filter.pfx, filter.pfx.bitlen))
580 continue;
581 }
582 if (filter.label) {
583 SPRINT_BUF(b1);
584 const char *label;
585 if (tb[IFA_LABEL])
586 label = RTA_DATA(tb[IFA_LABEL]);
587 else
588 label = ll_idx_n2a(ifa->ifa_index, b1);
589 if (fnmatch(filter.label, label, 0) != 0)
590 continue;
591 }
592 }
593
594 ok = 1;
595 break;
596 }
597 if (!ok)
598 *lp = l->next;
599 else
600 lp = &l->next;
601 }
602 }
603
604 for (l=linfo; l; l = l->next) {
605 if (no_link || print_linkinfo(NULL, &l->h, stdout) == 0) {
606 struct ifinfomsg *ifi = NLMSG_DATA(&l->h);
607 if (filter.family != AF_PACKET)
608 print_selected_addrinfo(ifi->ifi_index, ainfo, stdout);
609 }
610 fflush(stdout);
611 }
612
613 exit(0);
614}
615
Glenn L McGrath2626ef62002-12-02 01:40:05 +0000616static int default_scope(inet_prefix *lcl)
Glenn L McGrath9a2d2722002-11-10 01:33:55 +0000617{
618 if (lcl->family == AF_INET) {
619 if (lcl->bytelen >= 1 && *(__u8*)&lcl->data == 127)
620 return RT_SCOPE_HOST;
621 }
622 return 0;
623}
624
Glenn L McGrath2626ef62002-12-02 01:40:05 +0000625static int ipaddr_modify(int cmd, int argc, char **argv)
Glenn L McGrath9a2d2722002-11-10 01:33:55 +0000626{
Rob Landley0a7c8ef2006-02-22 17:01:00 +0000627 static const char *const option[] = {
628 "peer", "remote", "broadcast", "brd",
629 "anycast", "scope", "dev", "label", "local", 0
630 };
631
Glenn L McGrath9a2d2722002-11-10 01:33:55 +0000632 struct rtnl_handle rth;
633 struct {
Tim Rikerc1ef7bd2006-01-25 00:08:53 +0000634 struct nlmsghdr n;
635 struct ifaddrmsg ifa;
636 char buf[256];
Glenn L McGrath9a2d2722002-11-10 01:33:55 +0000637 } req;
638 char *d = NULL;
639 char *l = NULL;
640 inet_prefix lcl;
641 inet_prefix peer;
642 int local_len = 0;
643 int peer_len = 0;
644 int brd_len = 0;
645 int any_len = 0;
646 int scoped = 0;
647
648 memset(&req, 0, sizeof(req));
649
650 req.n.nlmsg_len = NLMSG_LENGTH(sizeof(struct ifaddrmsg));
651 req.n.nlmsg_flags = NLM_F_REQUEST;
652 req.n.nlmsg_type = cmd;
653 req.ifa.ifa_family = preferred_family;
654
655 while (argc > 0) {
"Vladimir N. Oleynik"2f0a5f92005-12-06 12:00:39 +0000656 const int option_num = compare_string_array(option, *argv);
Glenn L McGrath2626ef62002-12-02 01:40:05 +0000657 switch (option_num) {
658 case 0: /* peer */
659 case 1: /* remote */
Glenn L McGrath9a2d2722002-11-10 01:33:55 +0000660 NEXT_ARG();
Glenn L McGrath2626ef62002-12-02 01:40:05 +0000661
662 if (peer_len) {
663 duparg("peer", *argv);
664 }
665 get_prefix(&peer, *argv, req.ifa.ifa_family);
666 peer_len = peer.bytelen;
667 if (req.ifa.ifa_family == AF_UNSPEC) {
668 req.ifa.ifa_family = peer.family;
669 }
670 addattr_l(&req.n, sizeof(req), IFA_ADDRESS, &peer.data, peer.bytelen);
671 req.ifa.ifa_prefixlen = peer.bitlen;
672 break;
673 case 2: /* broadcast */
674 case 3: /* brd */
675 {
676 inet_prefix addr;
677 NEXT_ARG();
678 if (brd_len) {
679 duparg("broadcast", *argv);
680 }
681 if (strcmp(*argv, "+") == 0) {
682 brd_len = -1;
683 }
684 else if (strcmp(*argv, "-") == 0) {
685 brd_len = -2;
686 } else {
687 get_addr(&addr, *argv, req.ifa.ifa_family);
688 if (req.ifa.ifa_family == AF_UNSPEC)
689 req.ifa.ifa_family = addr.family;
690 addattr_l(&req.n, sizeof(req), IFA_BROADCAST, &addr.data, addr.bytelen);
691 brd_len = addr.bytelen;
692 }
693 break;
Glenn L McGrath9a2d2722002-11-10 01:33:55 +0000694 }
Glenn L McGrath2626ef62002-12-02 01:40:05 +0000695 case 4: /* anycast */
696 {
697 inet_prefix addr;
698 NEXT_ARG();
699 if (any_len) {
700 duparg("anycast", *argv);
701 }
702 get_addr(&addr, *argv, req.ifa.ifa_family);
703 if (req.ifa.ifa_family == AF_UNSPEC) {
704 req.ifa.ifa_family = addr.family;
705 }
706 addattr_l(&req.n, sizeof(req), IFA_ANYCAST, &addr.data, addr.bytelen);
707 any_len = addr.bytelen;
708 break;
709 }
710 case 5: /* scope */
711 {
Eric Andersend78aea82006-01-30 18:00:02 +0000712 uint32_t scope = 0;
Glenn L McGrath2626ef62002-12-02 01:40:05 +0000713 NEXT_ARG();
714 if (rtnl_rtscope_a2n(&scope, *argv)) {
Bernhard Reutner-Fischer19008b82006-06-07 20:17:41 +0000715 invarg(*argv, "scope");
Glenn L McGrath2626ef62002-12-02 01:40:05 +0000716 }
717 req.ifa.ifa_scope = scope;
718 scoped = 1;
719 break;
720 }
721 case 6: /* dev */
722 NEXT_ARG();
723 d = *argv;
724 break;
725 case 7: /* label */
726 NEXT_ARG();
727 l = *argv;
728 addattr_l(&req.n, sizeof(req), IFA_LABEL, l, strlen(l)+1);
729 break;
730 case 8: /* local */
731 NEXT_ARG();
732 default:
733 if (local_len) {
734 duparg2("local", *argv);
735 }
736 get_prefix(&lcl, *argv, req.ifa.ifa_family);
737 if (req.ifa.ifa_family == AF_UNSPEC) {
738 req.ifa.ifa_family = lcl.family;
739 }
740 addattr_l(&req.n, sizeof(req), IFA_LOCAL, &lcl.data, lcl.bytelen);
741 local_len = lcl.bytelen;
Glenn L McGrath9a2d2722002-11-10 01:33:55 +0000742 }
Glenn L McGrath2626ef62002-12-02 01:40:05 +0000743 argc--;
744 argv++;
Glenn L McGrath9a2d2722002-11-10 01:33:55 +0000745 }
Glenn L McGrath2626ef62002-12-02 01:40:05 +0000746
Glenn L McGrath9a2d2722002-11-10 01:33:55 +0000747 if (d == NULL) {
Bernhard Reutner-Fischer19008b82006-06-07 20:17:41 +0000748 bb_error_msg(bb_msg_requires_arg,"\"dev\"");
Glenn L McGrath9a2d2722002-11-10 01:33:55 +0000749 return -1;
750 }
751 if (l && matches(d, l) != 0) {
Rob Landley0a7c8ef2006-02-22 17:01:00 +0000752 bb_error_msg_and_die("\"dev\" (%s) must match \"label\" (%s)", d, l);
Glenn L McGrath9a2d2722002-11-10 01:33:55 +0000753 }
754
755 if (peer_len == 0 && local_len && cmd != RTM_DELADDR) {
756 peer = lcl;
757 addattr_l(&req.n, sizeof(req), IFA_ADDRESS, &lcl.data, lcl.bytelen);
758 }
759 if (req.ifa.ifa_prefixlen == 0)
760 req.ifa.ifa_prefixlen = lcl.bitlen;
761
762 if (brd_len < 0 && cmd != RTM_DELADDR) {
763 inet_prefix brd;
764 int i;
765 if (req.ifa.ifa_family != AF_INET) {
Manuel Novoa III cad53642003-03-19 09:13:01 +0000766 bb_error_msg("Broadcast can be set only for IPv4 addresses");
Glenn L McGrath9a2d2722002-11-10 01:33:55 +0000767 return -1;
768 }
769 brd = peer;
770 if (brd.bitlen <= 30) {
771 for (i=31; i>=brd.bitlen; i--) {
772 if (brd_len == -1)
773 brd.data[0] |= htonl(1<<(31-i));
774 else
775 brd.data[0] &= ~htonl(1<<(31-i));
776 }
777 addattr_l(&req.n, sizeof(req), IFA_BROADCAST, &brd.data, brd.bytelen);
778 brd_len = brd.bytelen;
779 }
780 }
781 if (!scoped && cmd != RTM_DELADDR)
782 req.ifa.ifa_scope = default_scope(&lcl);
783
784 if (rtnl_open(&rth, 0) < 0)
785 exit(1);
786
787 ll_init_map(&rth);
788
789 if ((req.ifa.ifa_index = ll_name_to_index(d)) == 0) {
Manuel Novoa III cad53642003-03-19 09:13:01 +0000790 bb_error_msg("Cannot find device \"%s\"", d);
Glenn L McGrath9a2d2722002-11-10 01:33:55 +0000791 return -1;
792 }
793
794 if (rtnl_talk(&rth, &req.n, 0, 0, NULL, NULL, NULL) < 0)
795 exit(2);
796
797 exit(0);
798}
799
Rob Landleydfba7412006-03-06 20:47:33 +0000800int do_ipaddr(int argc, char **argv)
Glenn L McGrath9a2d2722002-11-10 01:33:55 +0000801{
Rob Landley0a7c8ef2006-02-22 17:01:00 +0000802 static const char *const commands[] = {
803 "add", "delete", "list", "show", "lst", "flush", 0
804 };
805
"Vladimir N. Oleynik"2f0a5f92005-12-06 12:00:39 +0000806 int command_num = 2;
Glenn L McGrath2626ef62002-12-02 01:40:05 +0000807
808 if (*argv) {
809 command_num = compare_string_array(commands, *argv);
810 }
811 switch (command_num) {
812 case 0: /* add */
813 return ipaddr_modify(RTM_NEWADDR, argc-1, argv+1);
814 case 1: /* delete */
815 return ipaddr_modify(RTM_DELADDR, argc-1, argv+1);
816 case 2: /* list */
817 case 3: /* show */
818 case 4: /* lst */
Glenn L McGrathd66370c2003-01-13 21:40:38 +0000819 return ipaddr_list_or_flush(argc-1, argv+1, 0);
820 case 5: /* flush */
821 return ipaddr_list_or_flush(argc-1, argv+1, 1);
Glenn L McGrath2626ef62002-12-02 01:40:05 +0000822 }
Manuel Novoa III cad53642003-03-19 09:13:01 +0000823 bb_error_msg_and_die("Unknown command %s", *argv);
Glenn L McGrath9a2d2722002-11-10 01:33:55 +0000824}