2 * ipmaddr.c "ip maddress".
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.
9 * Authors: Alexey Kuznetsov, <kuznet@ms2.inr.ac.ru>
18 #include <sys/ioctl.h>
19 #include <sys/socket.h>
20 #include <linux/netdevice.h>
22 #include <linux/if_arp.h>
23 #include <linux/sockios.h>
24 #include <netinet/in.h>
25 #include <arpa/inet.h>
30 #include "net-support.h"
32 #include "pathnames.h"
37 /* These have nothing to do with rtnetlink. :-) */
41 char *Release = RELEASE,
42 *Version = "ipmaddr 1.0",
43 *Signature = "Alexey Kuznetsov, <kuznet@ms2.inr.ac.ru>";
45 static void version(void)
47 printf("%s\n%s\n%s\n", Release, Version, Signature);
51 static void usage(void) __attribute__((noreturn));
53 static void usage(void)
55 fprintf(stderr, _("Usage: ipmaddr [ add | del ] MULTIADDR dev STRING\n"));
56 fprintf(stderr, _(" ipmaddr show [ dev STRING ] [ ipv4 | ipv6 | link | all ]\n"));
57 fprintf(stderr, _(" ipmaddr -V | -version\n"));
61 static void print_lla(FILE *fp, int len, unsigned char *addr)
64 for (i=0; i<len; i++) {
66 fprintf(fp, "%02x", addr[i]);
68 fprintf(fp, ":%02x", addr[i]);
72 static int parse_lla(char *str, unsigned char *addr)
78 if (str[0] == ':' || str[0] == '.') {
84 if (sscanf(str, "%02x", &tmp) != 1)
93 static int parse_hex(char *str, unsigned char *addr)
101 if (sscanf(str, "%02x", &tmp) != 1)
112 struct ma_info *next;
120 void maddr_ins(struct ma_info **lst, struct ma_info *m)
124 for (; (mp=*lst) != NULL; lst = &mp->next) {
125 if (mp->index > m->index)
132 void read_dev_mcast(struct ma_info **result_p)
135 FILE *fp = fopen(_PATH_PROCNET_DEV_MCAST, "r");
140 while (fgets(buf, sizeof(buf), fp)) {
146 memset(&m, 0, sizeof(m));
147 sscanf(buf, "%d%s%d%d%s", &m.index, m.name, &m.users, &st,
149 if (filter_dev[0] && strcmp(filter_dev, m.name))
152 m.addr.family = AF_PACKET;
154 len = parse_hex(hexa, (unsigned char*)&m.addr.data);
156 struct ma_info *ma = malloc(sizeof(m));
158 memcpy(ma, &m, sizeof(m));
159 ma->addr.bytelen = len;
160 ma->addr.bitlen = len<<3;
162 ma->features = "static";
163 maddr_ins(result_p, ma);
169 void read_igmp(struct ma_info **result_p)
173 FILE *fp = fopen(_PATH_PROCNET_IGMP, "r");
177 memset(&m, 0, sizeof(m));
178 fgets(buf, sizeof(buf), fp);
180 m.addr.family = AF_INET;
184 while (fgets(buf, sizeof(buf), fp)) {
185 struct ma_info *ma = malloc(sizeof(m));
187 if (buf[0] != '\t') {
188 sscanf(buf, "%d%s", &m.index, m.name);
192 if (filter_dev[0] && strcmp(filter_dev, m.name))
195 sscanf(buf, "%08x%d", (__u32*)&m.addr.data, &m.users);
197 ma = malloc(sizeof(m));
198 memcpy(ma, &m, sizeof(m));
199 maddr_ins(result_p, ma);
205 void read_igmp6(struct ma_info **result_p)
208 FILE *fp = fopen(_PATH_PROCNET_IGMP6, "r");
213 while (fgets(buf, sizeof(buf), fp)) {
218 memset(&m, 0, sizeof(m));
219 sscanf(buf, "%d%s%s%d", &m.index, m.name, hexa, &m.users);
221 if (filter_dev[0] && strcmp(filter_dev, m.name))
224 m.addr.family = AF_INET6;
226 len = parse_hex(hexa, (unsigned char*)&m.addr.data);
228 struct ma_info *ma = malloc(sizeof(m));
230 memcpy(ma, &m, sizeof(m));
232 ma->addr.bytelen = len;
233 ma->addr.bitlen = len<<3;
234 maddr_ins(result_p, ma);
240 static void print_maddr(FILE *fp, struct ma_info *list)
244 if (list->addr.family == AF_PACKET) {
245 fprintf(fp, "link ");
246 print_lla(fp, list->addr.bytelen, (unsigned char*)list->addr.data);
249 switch(list->addr.family) {
251 fprintf(fp, "inet ");
254 fprintf(fp, "inet6 ");
257 fprintf(fp, _("family %d "), list->addr.family);
260 if (format_host(list->addr.family, list->addr.data, abuf, sizeof(abuf)))
261 fprintf(fp, "%s", abuf);
265 if (list->users != 1)
266 fprintf(fp, _(" users %d"), list->users);
268 fprintf(fp, " %s", list->features);
272 static void print_mlist(FILE *fp, struct ma_info *list)
276 for (; list; list = list->next) {
277 if (cur_index != list->index) {
278 cur_index = list->index;
279 fprintf(fp, "%d:\t%s\n", cur_index, list->name);
281 print_maddr(fp, list);
285 static int multiaddr_list(int argc, char **argv)
287 struct ma_info *list = NULL;
290 if (strcmp(*argv, "dev") == 0) {
294 strcpy(filter_dev, *argv);
295 } else if (strcmp(*argv, "all") == 0) {
296 filter_family = AF_UNSPEC;
297 } else if (strcmp(*argv, "ipv4") == 0) {
298 filter_family = AF_INET;
299 } else if (strcmp(*argv, "ipv6") == 0) {
300 filter_family = AF_INET6;
301 } else if (strcmp(*argv, "link") == 0) {
302 filter_family = AF_PACKET;
306 strcpy(filter_dev, *argv);
311 if (!filter_family || filter_family == AF_PACKET)
312 read_dev_mcast(&list);
313 if (!filter_family || filter_family == AF_INET)
315 if (!filter_family || filter_family == AF_INET6)
317 print_mlist(stdout, list);
321 int multiaddr_modify(int cmd, int argc, char **argv)
326 memset(&ifr, 0, sizeof(ifr));
334 if (strcmp(*argv, "dev") == 0) {
338 strncpy(ifr.ifr_name, *argv, IFNAMSIZ);
340 if (ifr.ifr_hwaddr.sa_data[0])
342 if (parse_lla(*argv, ifr.ifr_hwaddr.sa_data) < 0)
347 if (ifr.ifr_name[0] == 0)
350 fd = socket(AF_INET, SOCK_DGRAM, 0);
352 perror(_("Cannot create socket"));
355 if (ioctl(fd, cmd, (char*)&ifr) != 0) {
365 int do_multiaddr(int argc, char **argv)
368 return multiaddr_list(0, NULL);
369 if (matches(*argv, "add") == 0)
370 return multiaddr_modify(NEWADDR, argc-1, argv+1);
371 if (matches(*argv, "delete") == 0)
372 return multiaddr_modify(DELADDR, argc-1, argv+1);
373 if (matches(*argv, "list") == 0 || matches(*argv, "show") == 0
374 || matches(*argv, "lst") == 0)
375 return multiaddr_list(argc-1, argv+1);
379 int preferred_family = AF_UNSPEC;
381 int resolve_hosts = 0;
383 int main(int argc, char **argv)
387 basename = strrchr(argv[0], '/');
388 if (basename == NULL)
394 if (argv[1][0] != '-')
396 if (matches(argv[1], "-family") == 0) {
401 if (strcmp(argv[1], "inet") == 0)
402 preferred_family = AF_INET;
403 else if (strcmp(argv[1], "inet6") == 0)
404 preferred_family = AF_INET6;
407 } else if (matches(argv[1], "-stats") == 0 ||
408 matches(argv[1], "-statistics") == 0) {
410 } else if (matches(argv[1], "-resolve") == 0) {
412 } else if ((matches(argv[1], "-V") == 0) || matches(argv[1], "--version") == 0) {
419 return do_multiaddr(argc-1, argv+1);