]> git.saurik.com Git - apple/configd.git/blob - Plugins/KernelEventMonitor/eventmon.c
configd-130.tar.gz
[apple/configd.git] / Plugins / KernelEventMonitor / eventmon.c
1 /*
2 * Copyright (c) 2000-2003 Apple Computer, Inc. All rights reserved.
3 *
4 * @APPLE_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. Please obtain a copy of the License at
10 * http://www.opensource.apple.com/apsl/ and read it before using this
11 * file.
12 *
13 * The Original Code and all software distributed under the License are
14 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
15 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
16 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
18 * Please see the License for the specific language governing rights and
19 * limitations under the License.
20 *
21 * @APPLE_LICENSE_HEADER_END@
22 */
23
24 /*
25 * Modification History
26 *
27 * December 3, 2002 Dieter Siegmund <dieter@apple.com>
28 * - handle the new KEV_INET_ARPCOLLISION event
29 * - format the event into a DynamicStore key
30 * State:/Network/Interface/ifname/IPv4Collision/ip_addr/hw_addr
31 * and send a notification on the key
32 *
33 * August 8, 2002 Allan Nathanson <ajn@apple.com>
34 * - added support for KEV_INET6_xxx events
35 *
36 * January 6, 2002 Jessica Vazquez <vazquez@apple.com>
37 * - added handling for KEV_ATALK_xxx events
38 *
39 * July 2, 2001 Dieter Siegmund <dieter@apple.com>
40 * - added handling for KEV_DL_PROTO_{ATTACHED, DETACHED}
41 * - mark an interface up if the number of protocols remaining is not 0,
42 * mark an interface down if the number is zero
43 * - allocate socket on demand instead of keeping it open all the time
44 *
45 * June 23, 2001 Allan Nathanson <ajn@apple.com>
46 * - update to public SystemConfiguration.framework APIs
47 *
48 * May 17, 2001 Allan Nathanson <ajn@apple.com>
49 * - add/maintain per-interface address/netmask/destaddr information
50 * in the dynamic store.
51 *
52 * June 30, 2000 Allan Nathanson <ajn@apple.com>
53 * - initial revision
54 */
55
56 #include "eventmon.h"
57 #include "cache.h"
58 #include "ev_dlil.h"
59 #include "ev_ipv4.h"
60 #include "ev_ipv6.h"
61 #include "ev_appletalk.h"
62
63 static const char *inetEventName[] = {
64 "",
65 "INET address added",
66 "INET address changed",
67 "INET address deleted",
68 "INET destination address changed",
69 "INET broadcast address changed",
70 "INET netmask changed",
71 "INET ARP collision",
72 };
73
74 static const char *dlEventName[] = {
75 "",
76 "KEV_DL_SIFFLAGS",
77 "KEV_DL_SIFMETRICS",
78 "KEV_DL_SIFMTU",
79 "KEV_DL_SIFPHYS",
80 "KEV_DL_SIFMEDIA",
81 "KEV_DL_SIFGENERIC",
82 "KEV_DL_ADDMULTI",
83 "KEV_DL_DELMULTI",
84 "KEV_DL_IF_ATTACHED",
85 "KEV_DL_IF_DETACHING",
86 "KEV_DL_IF_DETACHED",
87 "KEV_DL_LINK_OFF",
88 "KEV_DL_LINK_ON",
89 "KEV_DL_PROTO_ATTACHED",
90 "KEV_DL_PROTO_DETACHED",
91 };
92
93 static const char *atalkEventName[] = {
94 "",
95 "KEV_ATALK_ENABLED",
96 "KEV_ATALK_DISABLED",
97 "KEV_ATALK_ZONEUPDATED",
98 "KEV_ATALK_ROUTERUP",
99 "KEV_ATALK_ROUTERUP_INVALID",
100 "KEV_ATALK_ROUTERDOWN",
101 "KEV_ATALK_ZONELISTCHANGED"
102 };
103
104 static const char *inet6EventName[] = {
105 "",
106 "KEV_INET6_NEW_USER_ADDR",
107 "KEV_INET6_CHANGED_ADDR",
108 "KEV_INET6_ADDR_DELETED",
109 "KEV_INET6_NEW_LL_ADDR",
110 "KEV_INET6_NEW_RTADV_ADDR",
111 "KEV_INET6_DEFROUTER"
112
113 };
114
115
116 __private_extern__ SCDynamicStoreRef store = NULL;
117 __private_extern__ Boolean _verbose = FALSE;
118
119
120 __private_extern__
121 int
122 dgram_socket(int domain)
123 {
124 return (socket(domain, SOCK_DGRAM, 0));
125 }
126
127 static int
128 ifflags_set(int s, char * name, short flags)
129 {
130 struct ifreq ifr;
131 int ret;
132
133 bzero(&ifr, sizeof(ifr));
134 strncpy(ifr.ifr_name, name, sizeof(ifr.ifr_name));
135 ret = ioctl(s, SIOCGIFFLAGS, (caddr_t)&ifr);
136 if (ret < 0) {
137 return (ret);
138 }
139 ifr.ifr_flags |= flags;
140 return (ioctl(s, SIOCSIFFLAGS, &ifr));
141 }
142
143 static int
144 ifflags_clear(int s, char * name, short flags)
145 {
146 struct ifreq ifr;
147 int ret;
148
149 bzero(&ifr, sizeof(ifr));
150 strncpy(ifr.ifr_name, name, sizeof(ifr.ifr_name));
151 ret = ioctl(s, SIOCGIFFLAGS, (caddr_t)&ifr);
152 if (ret < 0) {
153 return (ret);
154 }
155 ifr.ifr_flags &= ~flags;
156 return (ioctl(s, SIOCSIFFLAGS, &ifr));
157 }
158
159 static void
160 mark_if_up(char * name)
161 {
162 int s = dgram_socket(AF_INET);
163 if (s < 0)
164 return;
165 ifflags_set(s, name, IFF_UP);
166 close(s);
167 }
168
169 static void
170 mark_if_down(char * name)
171 {
172 int s = dgram_socket(AF_INET);
173 if (s < 0)
174 return;
175 ifflags_clear(s, name, IFF_UP);
176 close(s);
177 }
178
179 static void
180 logEvent(CFStringRef evStr, struct kern_event_msg *ev_msg)
181 {
182 int i;
183 int j;
184
185 SCLog(_verbose, LOG_DEBUG, CFSTR("%@ event:"), evStr);
186 SCLog(_verbose, LOG_DEBUG,
187 CFSTR(" Event size=%d, id=%d, vendor=%d, class=%d, subclass=%d, code=%d"),
188 ev_msg->total_size,
189 ev_msg->id,
190 ev_msg->vendor_code,
191 ev_msg->kev_class,
192 ev_msg->kev_subclass,
193 ev_msg->event_code);
194 for (i = 0, j = KEV_MSG_HEADER_SIZE; j < ev_msg->total_size; i++, j+=4) {
195 SCLog(_verbose, LOG_DEBUG, CFSTR(" Event data[%2d] = %08lx"), i, ev_msg->event_data[i]);
196 }
197 }
198
199 static const char *
200 inetEventNameString(u_long event_code)
201 {
202 if (event_code <= KEV_INET_ARPCOLLISION) {
203 return (inetEventName[event_code]);
204 }
205 return ("New Apple network INET subcode");
206 }
207
208 static const char *
209 inet6EventNameString(u_long event_code)
210 {
211 if (event_code <= KEV_INET6_DEFROUTER) {
212 return (inet6EventName[event_code]);
213 }
214 return ("New Apple network INET6 subcode");
215 }
216
217 static const char *
218 dlEventNameString(u_long event_code)
219 {
220 if (event_code <= KEV_DL_PROTO_DETACHED) {
221 return (dlEventName[event_code]);
222 }
223 return ("New Apple network DL subcode");
224 }
225
226 static const char *
227 atalkEventNameString(u_long event_code)
228 {
229 if (event_code <= KEV_ATALK_ZONELISTCHANGED) {
230 return (atalkEventName[event_code]);
231 }
232 return ("New Apple network AppleTalk subcode");
233 }
234
235
236 static void
237 copy_if_name(struct net_event_data * ev, char * ifr_name, int ifr_len)
238 {
239 snprintf(ifr_name, ifr_len, "%s%ld", ev->if_name, ev->if_unit);
240 return;
241 }
242
243 static void
244 processEvent_Apple_Network(struct kern_event_msg *ev_msg)
245 {
246 const char * eventName = NULL;
247 int dataLen = (ev_msg->total_size - KEV_MSG_HEADER_SIZE);
248 void * event_data = &ev_msg->event_data[0];
249 Boolean handled = TRUE;
250 char ifr_name[IFNAMSIZ+1];
251
252 switch (ev_msg->kev_subclass) {
253 case KEV_INET_SUBCLASS : {
254 eventName = inetEventNameString(ev_msg->event_code);
255 switch (ev_msg->event_code) {
256 case KEV_INET_NEW_ADDR :
257 case KEV_INET_CHANGED_ADDR :
258 case KEV_INET_ADDR_DELETED :
259 case KEV_INET_SIFDSTADDR :
260 case KEV_INET_SIFBRDADDR :
261 case KEV_INET_SIFNETMASK : {
262 struct kev_in_data * ev;
263
264 ev = (struct kev_in_data *)event_data;
265 if (dataLen < sizeof(*ev)) {
266 handled = FALSE;
267 break;
268 }
269 copy_if_name(&ev->link_data, ifr_name, sizeof(ifr_name));
270 interface_update_ipv4(NULL, ifr_name);
271 break;
272 }
273 case KEV_INET_ARPCOLLISION : {
274 struct kev_in_collision * ev;
275
276 ev = (struct kev_in_collision *)event_data;
277 if ((dataLen < sizeof(*ev))
278 || (dataLen < (sizeof(*ev) + ev->hw_len))) {
279 handled = FALSE;
280 break;
281 }
282 copy_if_name(&ev->link_data, ifr_name, sizeof(ifr_name));
283 interface_collision_ipv4(ifr_name,
284 ev->ia_ipaddr,
285 ev->hw_len,
286 ev->hw_addr);
287 break;
288 }
289 default :
290 handled = FALSE;
291 break;
292 }
293 break;
294 }
295 case KEV_INET6_SUBCLASS : {
296 struct kev_in6_data * ev;
297
298 eventName = inet6EventNameString(ev_msg->event_code);
299 ev = (struct kev_in6_data *)event_data;
300 switch (ev_msg->event_code) {
301 case KEV_INET6_NEW_USER_ADDR :
302 case KEV_INET6_CHANGED_ADDR :
303 case KEV_INET6_ADDR_DELETED :
304 case KEV_INET6_NEW_LL_ADDR :
305 case KEV_INET6_NEW_RTADV_ADDR :
306 case KEV_INET6_DEFROUTER :
307 if (dataLen < sizeof(*ev)) {
308 handled = FALSE;
309 break;
310 }
311 copy_if_name(&ev->link_data, ifr_name, sizeof(ifr_name));
312 interface_update_ipv6(NULL, ifr_name);
313 break;
314
315 default :
316 handled = FALSE;
317 break;
318 }
319 break;
320 }
321 case KEV_DL_SUBCLASS : {
322 struct net_event_data * ev;
323
324 eventName = dlEventNameString(ev_msg->event_code);
325 ev = (struct net_event_data *)event_data;
326 switch (ev_msg->event_code) {
327 case KEV_DL_IF_ATTACHED :
328 /*
329 * new interface added
330 */
331 if (dataLen < sizeof(*ev)) {
332 handled = FALSE;
333 break;
334 }
335 copy_if_name(ev, ifr_name, sizeof(ifr_name));
336 link_add(ifr_name);
337 break;
338
339 case KEV_DL_IF_DETACHED :
340 /*
341 * interface removed
342 */
343 if (dataLen < sizeof(*ev)) {
344 handled = FALSE;
345 break;
346 }
347 copy_if_name(ev, ifr_name, sizeof(ifr_name));
348 link_remove(ifr_name);
349 break;
350
351 case KEV_DL_IF_DETACHING :
352 /*
353 * interface detaching
354 */
355 if (dataLen < sizeof(*ev)) {
356 handled = FALSE;
357 break;
358 }
359 copy_if_name(ev, ifr_name, sizeof(ifr_name));
360 interface_detaching(ifr_name);
361 break;
362
363 case KEV_DL_SIFFLAGS :
364 case KEV_DL_SIFMETRICS :
365 case KEV_DL_SIFMTU :
366 case KEV_DL_SIFPHYS :
367 case KEV_DL_SIFMEDIA :
368 case KEV_DL_SIFGENERIC :
369 case KEV_DL_ADDMULTI :
370 case KEV_DL_DELMULTI :
371 handled = FALSE;
372 break;
373
374 case KEV_DL_PROTO_ATTACHED :
375 case KEV_DL_PROTO_DETACHED : {
376 struct kev_dl_proto_data * protoEvent;
377
378 protoEvent = (struct kev_dl_proto_data *)event_data;
379 if (dataLen < sizeof(*protoEvent)) {
380 handled = FALSE;
381 break;
382 }
383 copy_if_name(&protoEvent->link_data,
384 ifr_name, sizeof(ifr_name));
385 if (protoEvent->proto_remaining_count == 0) {
386 mark_if_down(ifr_name);
387 } else {
388 mark_if_up(ifr_name);
389 }
390 break;
391 }
392
393 case KEV_DL_LINK_OFF :
394 case KEV_DL_LINK_ON :
395 /*
396 * update the link status in the store
397 */
398 if (dataLen < sizeof(*ev)) {
399 handled = FALSE;
400 break;
401 }
402 copy_if_name(ev, ifr_name, sizeof(ifr_name));
403 link_update_status(ifr_name, FALSE);
404 break;
405
406 default :
407 handled = FALSE;
408 break;
409 }
410 break;
411 }
412 case KEV_ATALK_SUBCLASS: {
413 struct kev_atalk_data * ev;
414
415 eventName = atalkEventNameString(ev_msg->event_code);
416 ev = (struct kev_atalk_data *)event_data;
417 if (dataLen < sizeof(*ev)) {
418 handled = FALSE;
419 break;
420 }
421 copy_if_name(&ev->link_data, ifr_name, sizeof(ifr_name));
422 switch (ev_msg->event_code) {
423 case KEV_ATALK_ENABLED:
424 interface_update_atalk_address(ev, ifr_name);
425 break;
426
427 case KEV_ATALK_DISABLED:
428 interface_update_shutdown_atalk();
429 break;
430
431 case KEV_ATALK_ZONEUPDATED:
432 interface_update_atalk_zone(ev, ifr_name);
433 break;
434
435 case KEV_ATALK_ROUTERUP:
436 case KEV_ATALK_ROUTERUP_INVALID:
437 case KEV_ATALK_ROUTERDOWN:
438 interface_update_appletalk(NULL, ifr_name);
439 break;
440
441 case KEV_ATALK_ZONELISTCHANGED:
442 break;
443
444 default :
445 handled = FALSE;
446 break;
447 }
448 break;
449 }
450 default :
451 handled = FALSE;
452 break;
453 }
454
455 if (handled == FALSE) {
456 CFStringRef evStr;
457
458 evStr = CFStringCreateWithCString(NULL,
459 (eventName != NULL) ? eventName : "New Apple network subclass",
460 kCFStringEncodingASCII);
461 logEvent(evStr, ev_msg);
462 CFRelease(evStr);
463 }
464 return;
465 }
466
467
468 static void
469 processEvent_Apple_IOKit(struct kern_event_msg *ev_msg)
470 {
471 switch (ev_msg->kev_subclass) {
472 default :
473 logEvent(CFSTR("New Apple IOKit subclass"), ev_msg);
474 break;
475 }
476
477 return;
478 }
479
480
481 static void
482 eventCallback(CFSocketRef s, CFSocketCallBackType type, CFDataRef address, const void *data, void *info)
483 {
484 int so = CFSocketGetNative(s);
485 int status;
486 char buf[1024];
487 struct kern_event_msg *ev_msg = (struct kern_event_msg *)&buf[0];
488 int offset = 0;
489
490 status = recv(so, &buf, sizeof(buf), 0);
491 if (status == -1) {
492 SCLog(TRUE, LOG_ERR, CFSTR("recv() failed: %s"), strerror(errno));
493 goto error;
494 }
495
496 cache_open();
497
498 while (offset < status) {
499 if ((offset + ev_msg->total_size) > status) {
500 SCLog(TRUE, LOG_NOTICE, CFSTR("missed SYSPROTO_EVENT event, buffer not big enough"));
501 break;
502 }
503
504 switch (ev_msg->vendor_code) {
505 case KEV_VENDOR_APPLE :
506 switch (ev_msg->kev_class) {
507 case KEV_NETWORK_CLASS :
508 processEvent_Apple_Network(ev_msg);
509 break;
510 case KEV_IOKIT_CLASS :
511 processEvent_Apple_IOKit(ev_msg);
512 break;
513 default :
514 /* unrecognized (Apple) event class */
515 logEvent(CFSTR("New (Apple) class"), ev_msg);
516 break;
517 }
518 break;
519 default :
520 /* unrecognized vendor code */
521 logEvent(CFSTR("New vendor"), ev_msg);
522 break;
523 }
524 offset += ev_msg->total_size;
525 ev_msg = (struct kern_event_msg *)&buf[offset];
526 }
527
528 cache_write(store);
529 cache_close();
530
531 return;
532
533 error :
534
535 SCLog(TRUE, LOG_ERR, CFSTR("kernel event monitor disabled."));
536 CFSocketInvalidate(s);
537 return;
538
539 }
540
541
542 __private_extern__
543 void
544 prime_KernelEventMonitor()
545 {
546 struct ifaddrs *ifap = NULL;
547 struct ifaddrs *scan;
548 int sock = -1;
549
550 SCLog(_verbose, LOG_DEBUG, CFSTR("prime() called"));
551
552 cache_open();
553
554 sock = dgram_socket(AF_INET);
555 if (sock == -1) {
556 SCLog(TRUE, LOG_ERR, CFSTR("could not get interface list, socket() failed: %s"), strerror(errno));
557 goto done;
558 }
559
560 if (getifaddrs(&ifap) < 0) {
561 SCLog(TRUE,
562 LOG_ERR,
563 CFSTR("could not get interface info, getifaddrs() failed: %s"),
564 strerror(errno));
565 goto done;
566 }
567
568 /* update list of interfaces & link status */
569 for (scan = ifap; scan != NULL; scan = scan->ifa_next) {
570 if (scan->ifa_addr == NULL
571 || scan->ifa_addr->sa_family != AF_LINK) {
572 continue;
573 }
574 /* get the per-interface link/media information */
575 link_add(scan->ifa_name);
576 }
577
578 /*
579 * update IPv4 network addresses already assigned to
580 * the interfaces.
581 */
582 interface_update_ipv4(ifap, NULL);
583
584 /*
585 * update IPv6 network addresses already assigned to
586 * the interfaces.
587 */
588 interface_update_ipv6(ifap, NULL);
589
590 /*
591 * update AppleTalk network addresses already assigned
592 * to the interfaces.
593 */
594 interface_update_appletalk(ifap, NULL);
595
596 freeifaddrs(ifap);
597
598 done:
599 if (sock >= 0)
600 close(sock);
601
602 cache_write(store);
603 cache_close();
604
605 return;
606 }
607
608
609 __private_extern__
610 void
611 load_KernelEventMonitor(CFBundleRef bundle, Boolean bundleVerbose)
612 {
613 int so;
614 int status;
615 struct kev_request kev_req;
616 CFSocketRef es;
617 CFSocketContext context = { 0, NULL, NULL, NULL, NULL };
618 CFRunLoopSourceRef rls;
619
620 if (bundleVerbose) {
621 _verbose = TRUE;
622 }
623
624 SCLog(_verbose, LOG_DEBUG, CFSTR("load() called"));
625 SCLog(_verbose, LOG_DEBUG, CFSTR(" bundle ID = %@"), CFBundleGetIdentifier(bundle));
626
627 /* open a "configd" session to allow cache updates */
628 store = SCDynamicStoreCreate(NULL,
629 CFSTR("Kernel Event Monitor plug-in"),
630 NULL,
631 NULL);
632 if (!store) {
633 SCLog(TRUE, LOG_ERR, CFSTR("SCDnamicStoreCreate() failed: %s"), SCErrorString(SCError()));
634 SCLog(TRUE, LOG_ERR, CFSTR("kernel event monitor disabled."));
635 return;
636 }
637
638 /* Open an event socket */
639 so = socket(PF_SYSTEM, SOCK_RAW, SYSPROTO_EVENT);
640 if (so != -1) {
641 /* establish filter to return all events */
642 kev_req.vendor_code = 0;
643 kev_req.kev_class = 0; /* Not used if vendor_code is 0 */
644 kev_req.kev_subclass = 0; /* Not used if either kev_class OR vendor_code are 0 */
645 status = ioctl(so, SIOCSKEVFILT, &kev_req);
646 if (status) {
647 SCLog(TRUE, LOG_ERR, CFSTR("could not establish event filter, ioctl() failed: %s"), strerror(errno));
648 (void) close(so);
649 so = -1;
650 }
651 } else {
652 SCLog(TRUE, LOG_ERR, CFSTR("could not open event socket, socket() failed: %s"), strerror(errno));
653 }
654
655 if (so != -1) {
656 int yes = 1;
657
658 status = ioctl(so, FIONBIO, &yes);
659 if (status) {
660 SCLog(TRUE, LOG_ERR, CFSTR("could not set non-blocking io, ioctl() failed: %s"), strerror(errno));
661 (void) close(so);
662 so = -1;
663 }
664 }
665
666 if (so == -1) {
667 SCLog(TRUE, LOG_ERR, CFSTR("kernel event monitor disabled."));
668 CFRelease(store);
669 return;
670 }
671
672 /* Create a CFSocketRef for the PF_SYSTEM kernel event socket */
673 es = CFSocketCreateWithNative(NULL,
674 so,
675 kCFSocketReadCallBack,
676 eventCallback,
677 &context);
678
679 /* Create and add a run loop source for the event socket */
680 rls = CFSocketCreateRunLoopSource(NULL, es, 0);
681 CFRunLoopAddSource(CFRunLoopGetCurrent(), rls, kCFRunLoopDefaultMode);
682 CFRelease(rls);
683 CFRelease(es);
684
685 return;
686 }
687
688 #ifdef MAIN
689
690 #include "ev_dlil.c"
691
692 #define appendAddress appendAddress_v4
693 #define getIF getIF_v4
694 #define updateStore updateStore_v4
695 #include "ev_ipv4.c"
696 #undef appendAddress
697 #undef getIF
698 #undef updateStore
699
700 #define appendAddress appendAddress_v6
701 #define getIF getIF_v6
702 #define updateStore updateStore_v6
703 #include "ev_ipv6.c"
704 #undef appendAddress
705 #undef getIF
706 #undef updateStore
707
708 #define getIF getIF_at
709 #define updateStore updateStore_at
710 #include "ev_appletalk.c"
711 #undef getIF
712 #undef updateStore
713
714 int
715 main(int argc, char **argv)
716 {
717 _sc_log = FALSE;
718 _sc_verbose = (argc > 1) ? TRUE : FALSE;
719
720 load_KernelEventMonitor(CFBundleGetMainBundle(), (argc > 1) ? TRUE : FALSE);
721 prime_KernelEventMonitor();
722 CFRunLoopRun();
723 /* not reached */
724 exit(0);
725 return 0;
726 }
727 #endif