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