]> git.saurik.com Git - apple/network_cmds.git/blob - netstat.tproj/mcast.c
6f97d39d950dc7981dfcf5c1fb6d4dc81a6d6174
[apple/network_cmds.git] / netstat.tproj / mcast.c
1 /*
2 * Copyright (c) 2007 Bruce M. Simpson <bms@FreeBSD.org>
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 *
14 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24 * SUCH DAMAGE.
25 *
26 */
27
28 #include <sys/cdefs.h>
29
30 /*
31 * Print the running system's current multicast group memberships.
32 * As this relies on getifmaddrs(), it may not be used with a core file.
33 */
34
35 #include <sys/types.h>
36 #include <sys/param.h>
37 #include <sys/sysctl.h>
38 #include <sys/ioctl.h>
39 #include <sys/socket.h>
40 #include <sys/errno.h>
41
42 #include <net/if.h>
43 #include <net/if_var.h>
44 #include <net/if_mib.h>
45 #include <net/if_types.h>
46 #include <net/if_dl.h>
47 #include <net/route.h>
48 #include <netinet/in.h>
49 #include <netinet/if_ether.h>
50 #include <arpa/inet.h>
51 #include <netdb.h>
52
53 #include <ctype.h>
54 #include <err.h>
55 #include <ifaddrs.h>
56 #include <sysexits.h>
57
58 #include <stddef.h>
59 #include <stdarg.h>
60 #include <stdlib.h>
61 #include <stdint.h>
62 #include <stdio.h>
63 #include <string.h>
64 #include <ifaddrs.h>
65
66
67 #include "netstat.h"
68
69 union sockunion {
70 struct sockaddr_storage ss;
71 struct sockaddr sa;
72 struct sockaddr_dl sdl;
73 struct sockaddr_in sin;
74 struct sockaddr_in6 sin6;
75 };
76 typedef union sockunion sockunion_t;
77
78 /*
79 * This may have been defined in <net/if.h>. Note that if <net/if.h> is
80 * to be included it must be included before this header file.
81 */
82 #ifndef ifa_broadaddr
83 #define ifa_broadaddr ifa_dstaddr /* broadcast address interface */
84 #endif
85
86 struct ifmaddrs {
87 struct ifmaddrs *ifma_next;
88 struct sockaddr *ifma_name;
89 struct sockaddr *ifma_addr;
90 struct sockaddr *ifma_lladdr;
91 };
92
93 void ifmalist_dump_af(const struct ifmaddrs * const ifmap, int const af);
94
95 #define SALIGN (sizeof(long) - 1)
96 #define SA_RLEN(sa) (sa ? ((sa)->sa_len ? (((sa)->sa_len + SALIGN) & ~SALIGN) : \
97 (SALIGN + 1)) : 0)
98 #define MAX_SYSCTL_TRY 5
99 #define RTA_MASKS (RTA_GATEWAY | RTA_IFP | RTA_IFA)
100
101 int getifmaddrs(struct ifmaddrs **);
102 void freeifmaddrs(struct ifmaddrs *);
103
104
105 int
106 getifmaddrs(struct ifmaddrs **pif)
107 {
108 int icnt = 1;
109 int dcnt = 0;
110 int ntry = 0;
111 size_t len;
112 size_t needed;
113 int mib[6];
114 int i;
115 char *buf;
116 char *data;
117 char *next;
118 char *p;
119 struct ifma_msghdr2 *ifmam;
120 struct ifmaddrs *ifa, *ift;
121 struct rt_msghdr *rtm;
122 struct sockaddr *sa;
123
124 mib[0] = CTL_NET;
125 mib[1] = PF_ROUTE;
126 mib[2] = 0; /* protocol */
127 mib[3] = 0; /* wildcard address family */
128 mib[4] = NET_RT_IFLIST2;
129 mib[5] = 0; /* no flags */
130 do {
131 if (sysctl(mib, 6, NULL, &needed, NULL, 0) < 0)
132 return (-1);
133 if ((buf = malloc(needed)) == NULL)
134 return (-1);
135 if (sysctl(mib, 6, buf, &needed, NULL, 0) < 0) {
136 if (errno != ENOMEM || ++ntry >= MAX_SYSCTL_TRY) {
137 free(buf);
138 return (-1);
139 }
140 free(buf);
141 buf = NULL;
142 }
143 } while (buf == NULL);
144
145 for (next = buf; next < buf + needed; next += rtm->rtm_msglen) {
146 rtm = (struct rt_msghdr *)(void *)next;
147 if (rtm->rtm_version != RTM_VERSION)
148 continue;
149 switch (rtm->rtm_type) {
150 case RTM_NEWMADDR2:
151 ifmam = (struct ifma_msghdr2 *)(void *)rtm;
152 if ((ifmam->ifmam_addrs & RTA_IFA) == 0)
153 break;
154 icnt++;
155 p = (char *)(ifmam + 1);
156 for (i = 0; i < RTAX_MAX; i++) {
157 if ((RTA_MASKS & ifmam->ifmam_addrs &
158 (1 << i)) == 0)
159 continue;
160 sa = (struct sockaddr *)(void *)p;
161 len = SA_RLEN(sa);
162 dcnt += len;
163 p += len;
164 }
165 break;
166 }
167 }
168
169 data = malloc(sizeof(struct ifmaddrs) * icnt + dcnt);
170 if (data == NULL) {
171 free(buf);
172 return (-1);
173 }
174
175 ifa = (struct ifmaddrs *)(void *)data;
176 data += sizeof(struct ifmaddrs) * icnt;
177
178 memset(ifa, 0, sizeof(struct ifmaddrs) * icnt);
179 ift = ifa;
180
181 for (next = buf; next < buf + needed; next += rtm->rtm_msglen) {
182 rtm = (struct rt_msghdr *)(void *)next;
183 if (rtm->rtm_version != RTM_VERSION)
184 continue;
185
186 switch (rtm->rtm_type) {
187 case RTM_NEWMADDR2:
188 ifmam = (struct ifma_msghdr2 *)(void *)rtm;
189 if ((ifmam->ifmam_addrs & RTA_IFA) == 0)
190 break;
191
192 p = (char *)(ifmam + 1);
193 for (i = 0; i < RTAX_MAX; i++) {
194 if ((RTA_MASKS & ifmam->ifmam_addrs &
195 (1 << i)) == 0)
196 continue;
197 sa = (struct sockaddr *)(void *)p;
198 len = SA_RLEN(sa);
199 switch (i) {
200 case RTAX_GATEWAY:
201 ift->ifma_lladdr =
202 (struct sockaddr *)(void *)data;
203 memcpy(data, p, len);
204 data += len;
205 break;
206
207 case RTAX_IFP:
208 ift->ifma_name =
209 (struct sockaddr *)(void *)data;
210 memcpy(data, p, len);
211 data += len;
212 break;
213
214 case RTAX_IFA:
215 ift->ifma_addr =
216 (struct sockaddr *)(void *)data;
217 memcpy(data, p, len);
218 data += len;
219 break;
220
221 default:
222 data += len;
223 break;
224 }
225 p += len;
226 }
227 ift->ifma_next = ift + 1;
228 ift = ift->ifma_next;
229 break;
230 }
231 }
232
233 free(buf);
234
235 if (ift > ifa) {
236 ift--;
237 ift->ifma_next = NULL;
238 *pif = ifa;
239 } else {
240 *pif = NULL;
241 free(ifa);
242 }
243 return (0);
244 }
245
246 void
247 freeifmaddrs(struct ifmaddrs *ifmp)
248 {
249
250 free(ifmp);
251 }
252
253 void
254 ifmalist_dump_af(const struct ifmaddrs * const ifmap, int const af)
255 {
256 const struct ifmaddrs *ifma;
257 sockunion_t *psa;
258 char myifname[IFNAMSIZ];
259 #ifdef INET6
260 char addrbuf[INET6_ADDRSTRLEN];
261 #endif
262 char *pcolon;
263 char *pafname, *pifname, *plladdr = NULL, *pgroup = NULL;
264 #ifdef INET6
265 void *in6addr;
266 #endif
267
268 switch (af) {
269 case AF_INET:
270 pafname = "IPv4";
271 break;
272 #ifdef INET6
273 case AF_INET6:
274 pafname = "IPv6";
275 break;
276 #endif
277 case AF_LINK:
278 pafname = "Link-layer";
279 break;
280 default:
281 return; /* XXX */
282 }
283
284 fprintf(stdout, "%s Multicast Group Memberships\n", pafname);
285 fprintf(stdout, "%-20s\t%-16s\t%s\n", "Group", "Link-layer Address",
286 "Netif");
287
288 for (ifma = ifmap; ifma; ifma = ifma->ifma_next) {
289
290 if (ifma->ifma_name == NULL || ifma->ifma_addr == NULL)
291 continue;
292
293 /* Group address */
294 psa = (sockunion_t *)ifma->ifma_addr;
295 if (psa->sa.sa_family != af)
296 continue;
297
298 switch (psa->sa.sa_family) {
299 case AF_INET:
300 pgroup = inet_ntoa(psa->sin.sin_addr);
301 break;
302 #ifdef INET6
303 case AF_INET6:
304 in6addr = &psa->sin6.sin6_addr;
305 inet_ntop(psa->sa.sa_family, in6addr, addrbuf,
306 sizeof(addrbuf));
307 pgroup = addrbuf;
308 break;
309 #endif
310 case AF_LINK:
311 if ((psa->sdl.sdl_alen == ETHER_ADDR_LEN) ||
312 (psa->sdl.sdl_type == IFT_ETHER)) {
313 pgroup =
314 ether_ntoa((struct ether_addr *)&psa->sdl.sdl_data);
315 #ifdef notyet
316 } else {
317 pgroup = addr2ascii(AF_LINK,
318 &psa->sdl,
319 sizeof(struct sockaddr_dl),
320 addrbuf);
321 #endif
322 }
323 break;
324 default:
325 continue; /* XXX */
326 }
327
328 /* Link-layer mapping, if any */
329 psa = (sockunion_t *)ifma->ifma_lladdr;
330 if (psa != NULL) {
331 if (psa->sa.sa_family == AF_LINK) {
332 if ((psa->sdl.sdl_alen == ETHER_ADDR_LEN) ||
333 (psa->sdl.sdl_type == IFT_ETHER)) {
334 /* IEEE 802 */
335 plladdr =
336 ether_ntoa((struct ether_addr *)&psa->sdl.sdl_data);
337 #ifdef notyet
338 } else {
339 /* something more exotic */
340 plladdr = addr2ascii(AF_LINK,
341 &psa->sdl,
342 sizeof(struct sockaddr_dl),
343 addrbuf);
344 #endif
345 }
346 } else {
347 int i;
348
349 /* not a link-layer address */
350 plladdr = "<invalid>";
351
352 for (i = 0; psa->sa.sa_len > 2 && i < psa->sa.sa_len - 2; i++)
353 printf("0x%x ", psa->sa.sa_data[i]);
354 printf("\n");
355 }
356 } else {
357 plladdr = "<none>";
358 }
359
360 /* Interface upon which the membership exists */
361 psa = (sockunion_t *)ifma->ifma_name;
362 if (psa != NULL && psa->sa.sa_family == AF_LINK) {
363 strlcpy(myifname, link_ntoa(&psa->sdl), IFNAMSIZ);
364 pcolon = strchr(myifname, ':');
365 if (pcolon)
366 *pcolon = '\0';
367 pifname = myifname;
368 } else {
369 pifname = "";
370 }
371
372 fprintf(stdout, "%-20s\t%-16s\t%s\n", pgroup, plladdr, pifname);
373 }
374 }
375
376 void
377 ifmalist_dump(void)
378 {
379 struct ifmaddrs *ifmap;
380
381 if (getifmaddrs(&ifmap))
382 err(EX_OSERR, "getifmaddrs");
383
384 ifmalist_dump_af(ifmap, AF_LINK);
385 fputs("\n", stdout);
386 ifmalist_dump_af(ifmap, AF_INET);
387 #ifdef INET6
388 fputs("\n", stdout);
389 ifmalist_dump_af(ifmap, AF_INET6);
390 #endif
391
392 freeifmaddrs(ifmap);
393 }
394