]> git.saurik.com Git - apple/configd.git/blob - Plugins/KernelEventMonitor/eventmon.c
configd-395.7.tar.gz
[apple/configd.git] / Plugins / KernelEventMonitor / eventmon.c
1 /*
2 * Copyright (c) 2000-2008, 2010 Apple 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 <notify.h>
62
63 // from ip_fw2.c
64 #define KEV_LOG_SUBCLASS 10
65
66 static const char *inetEventName[] = {
67 "",
68 "INET address added",
69 "INET address changed",
70 "INET address deleted",
71 "INET destination address changed",
72 "INET broadcast address changed",
73 "INET netmask changed",
74 "INET ARP collision",
75 "INET port in use",
76 };
77
78 static const char *dlEventName[] = {
79 "",
80 "KEV_DL_SIFFLAGS",
81 "KEV_DL_SIFMETRICS",
82 "KEV_DL_SIFMTU",
83 "KEV_DL_SIFPHYS",
84 "KEV_DL_SIFMEDIA",
85 "KEV_DL_SIFGENERIC",
86 "KEV_DL_ADDMULTI",
87 "KEV_DL_DELMULTI",
88 "KEV_DL_IF_ATTACHED",
89 "KEV_DL_IF_DETACHING",
90 "KEV_DL_IF_DETACHED",
91 "KEV_DL_LINK_OFF",
92 "KEV_DL_LINK_ON",
93 "KEV_DL_PROTO_ATTACHED",
94 "KEV_DL_PROTO_DETACHED",
95 "KEV_DL_LINK_ADDRESS_CHANGED",
96 "KEV_DL_WAKEFLAGS_CHANGED",
97 #ifdef KEV_DL_IF_IDLE_ROUTE_REFCNT
98 "KEV_DL_IF_IDLE_ROUTE_REFCNT",
99 #endif // KEV_DL_IF_IDLE_ROUTE_REFCNT
100 };
101
102 static const char *inet6EventName[] = {
103 "",
104 "KEV_INET6_NEW_USER_ADDR",
105 "KEV_INET6_CHANGED_ADDR",
106 "KEV_INET6_ADDR_DELETED",
107 "KEV_INET6_NEW_LL_ADDR",
108 "KEV_INET6_NEW_RTADV_ADDR",
109 "KEV_INET6_DEFROUTER"
110 };
111
112 __private_extern__ Boolean network_changed = FALSE;
113 __private_extern__ SCDynamicStoreRef store = NULL;
114 __private_extern__ Boolean _verbose = FALSE;
115
116 __private_extern__
117 int
118 dgram_socket(int domain)
119 {
120 return (socket(domain, SOCK_DGRAM, 0));
121 }
122
123 static int
124 ifflags_set(int s, char * name, short flags)
125 {
126 struct ifreq ifr;
127 int ret;
128
129 bzero(&ifr, sizeof(ifr));
130 strlcpy(ifr.ifr_name, name, sizeof(ifr.ifr_name));
131 ret = ioctl(s, SIOCGIFFLAGS, (caddr_t)&ifr);
132 if (ret == -1) {
133 return (ret);
134 }
135 ifr.ifr_flags |= flags;
136 return (ioctl(s, SIOCSIFFLAGS, &ifr));
137 }
138
139 static int
140 ifflags_clear(int s, char * name, short flags)
141 {
142 struct ifreq ifr;
143 int ret;
144
145 bzero(&ifr, sizeof(ifr));
146 strlcpy(ifr.ifr_name, name, sizeof(ifr.ifr_name));
147 ret = ioctl(s, SIOCGIFFLAGS, (caddr_t)&ifr);
148 if (ret == -1) {
149 return (ret);
150 }
151 ifr.ifr_flags &= ~flags;
152 return (ioctl(s, SIOCSIFFLAGS, &ifr));
153 }
154
155 static void
156 mark_if_up(char * name)
157 {
158 int s = dgram_socket(AF_INET);
159 if (s == -1)
160 return;
161 ifflags_set(s, name, IFF_UP);
162 close(s);
163 }
164
165 static void
166 mark_if_down(char * name)
167 {
168 int s = dgram_socket(AF_INET);
169 if (s == -1)
170 return;
171 ifflags_clear(s, name, IFF_UP);
172 close(s);
173 }
174
175 static void
176 post_network_changed(void)
177 {
178 if (network_changed) {
179 uint32_t status;
180
181 status = notify_post("com.apple.system.config.network_change");
182 if (status != NOTIFY_STATUS_OK) {
183 SCLog(TRUE, LOG_ERR, CFSTR("notify_post() failed: error=%ld"), status);
184 }
185
186 network_changed = FALSE;
187 }
188
189 return;
190 }
191
192 static void
193 logEvent(CFStringRef evStr, struct kern_event_msg *ev_msg)
194 {
195 int i;
196 int j;
197
198 if (!_verbose) {
199 return;
200 }
201
202 SCLog(TRUE, LOG_DEBUG, CFSTR("%@ event:"), evStr);
203 SCLog(TRUE, LOG_DEBUG,
204 CFSTR(" Event size=%d, id=%d, vendor=%d, class=%d, subclass=%d, code=%d"),
205 ev_msg->total_size,
206 ev_msg->id,
207 ev_msg->vendor_code,
208 ev_msg->kev_class,
209 ev_msg->kev_subclass,
210 ev_msg->event_code);
211 for (i = 0, j = KEV_MSG_HEADER_SIZE; j < ev_msg->total_size; i++, j+=4) {
212 SCLog(TRUE, LOG_DEBUG, CFSTR(" Event data[%2d] = %08lx"), i, ev_msg->event_data[i]);
213 }
214 }
215
216 static const char *
217 inetEventNameString(uint32_t event_code)
218 {
219 if (event_code < sizeof(inetEventName) / sizeof(inetEventName[0])) {
220 return (inetEventName[event_code]);
221 }
222 return ("New Apple network INET subcode");
223 }
224
225 static const char *
226 inet6EventNameString(uint32_t event_code)
227 {
228 if (event_code < sizeof(inet6EventName) / sizeof(inet6EventName[0])) {
229 return (inet6EventName[event_code]);
230 }
231 return ("New Apple network INET6 subcode");
232 }
233
234 static const char *
235 dlEventNameString(uint32_t event_code)
236 {
237 if (event_code < sizeof(dlEventName) / sizeof(dlEventName[0])) {
238 return (dlEventName[event_code]);
239 }
240 return ("New Apple network DL subcode");
241 }
242
243 static void
244 copy_if_name(struct net_event_data * ev, char * ifr_name, int ifr_len)
245 {
246 snprintf(ifr_name, ifr_len, "%s%d", ev->if_name, ev->if_unit);
247 return;
248 }
249
250 static void
251 processEvent_Apple_Network(struct kern_event_msg *ev_msg)
252 {
253 const char * eventName = NULL;
254 int dataLen = (ev_msg->total_size - KEV_MSG_HEADER_SIZE);
255 void * event_data = &ev_msg->event_data[0];
256 Boolean handled = TRUE;
257 char ifr_name[IFNAMSIZ];
258
259 switch (ev_msg->kev_subclass) {
260 case KEV_INET_SUBCLASS : {
261 eventName = inetEventNameString(ev_msg->event_code);
262 switch (ev_msg->event_code) {
263 case KEV_INET_NEW_ADDR :
264 case KEV_INET_CHANGED_ADDR :
265 case KEV_INET_ADDR_DELETED :
266 case KEV_INET_SIFDSTADDR :
267 case KEV_INET_SIFBRDADDR :
268 case KEV_INET_SIFNETMASK : {
269 struct kev_in_data * ev;
270
271 ev = (struct kev_in_data *)event_data;
272 if (dataLen < sizeof(*ev)) {
273 handled = FALSE;
274 break;
275 }
276 copy_if_name(&ev->link_data, ifr_name, sizeof(ifr_name));
277 interface_update_ipv4(NULL, ifr_name);
278 break;
279 }
280 case KEV_INET_ARPCOLLISION : {
281 struct kev_in_collision * ev;
282
283 ev = (struct kev_in_collision *)event_data;
284 if ((dataLen < sizeof(*ev))
285 || (dataLen < (sizeof(*ev) + ev->hw_len))) {
286 handled = FALSE;
287 break;
288 }
289 copy_if_name(&ev->link_data, ifr_name, sizeof(ifr_name));
290 interface_collision_ipv4(ifr_name,
291 ev->ia_ipaddr,
292 ev->hw_len,
293 ev->hw_addr);
294 break;
295 }
296 #if !TARGET_OS_IPHONE
297 case KEV_INET_PORTINUSE : {
298 struct kev_in_portinuse * ev;
299 ev = (struct kev_in_portinuse *)event_data;
300 if (dataLen < sizeof(*ev)) {
301 handled = FALSE;
302 break;
303 }
304 port_in_use_ipv4(ev->port, ev->req_pid);
305 break;
306 }
307 #endif /* !TARGET_OS_IPHONE */
308 default :
309 handled = FALSE;
310 break;
311 }
312 break;
313 }
314 case KEV_INET6_SUBCLASS : {
315 struct kev_in6_data * ev;
316
317 eventName = inet6EventNameString(ev_msg->event_code);
318 ev = (struct kev_in6_data *)event_data;
319 switch (ev_msg->event_code) {
320 case KEV_INET6_NEW_USER_ADDR :
321 case KEV_INET6_CHANGED_ADDR :
322 case KEV_INET6_ADDR_DELETED :
323 case KEV_INET6_NEW_LL_ADDR :
324 case KEV_INET6_NEW_RTADV_ADDR :
325 case KEV_INET6_DEFROUTER :
326 if (dataLen < sizeof(*ev)) {
327 handled = FALSE;
328 break;
329 }
330 copy_if_name(&ev->link_data, ifr_name, sizeof(ifr_name));
331 interface_update_ipv6(NULL, ifr_name);
332 break;
333
334 default :
335 handled = FALSE;
336 break;
337 }
338 break;
339 }
340 case KEV_DL_SUBCLASS : {
341 struct net_event_data * ev;
342
343 eventName = dlEventNameString(ev_msg->event_code);
344 ev = (struct net_event_data *)event_data;
345 switch (ev_msg->event_code) {
346 case KEV_DL_IF_ATTACHED :
347 /*
348 * new interface added
349 */
350 if (dataLen < sizeof(*ev)) {
351 handled = FALSE;
352 break;
353 }
354 copy_if_name(ev, ifr_name, sizeof(ifr_name));
355 link_add(ifr_name);
356 break;
357
358 case KEV_DL_IF_DETACHED :
359 /*
360 * interface removed
361 */
362 if (dataLen < sizeof(*ev)) {
363 handled = FALSE;
364 break;
365 }
366 copy_if_name(ev, ifr_name, sizeof(ifr_name));
367 link_remove(ifr_name);
368 break;
369
370 case KEV_DL_IF_DETACHING :
371 /*
372 * interface detaching
373 */
374 if (dataLen < sizeof(*ev)) {
375 handled = FALSE;
376 break;
377 }
378 copy_if_name(ev, ifr_name, sizeof(ifr_name));
379 interface_detaching(ifr_name);
380 break;
381
382 case KEV_DL_PROTO_ATTACHED :
383 case KEV_DL_PROTO_DETACHED : {
384 struct kev_dl_proto_data * protoEvent;
385
386 protoEvent = (struct kev_dl_proto_data *)event_data;
387 if (dataLen < sizeof(*protoEvent)) {
388 handled = FALSE;
389 break;
390 }
391 copy_if_name(&protoEvent->link_data,
392 ifr_name, sizeof(ifr_name));
393 if (protoEvent->proto_remaining_count == 0) {
394 mark_if_down(ifr_name);
395 } else {
396 mark_if_up(ifr_name);
397 }
398 break;
399 }
400
401 case KEV_DL_LINK_OFF :
402 case KEV_DL_LINK_ON :
403 /*
404 * update the link status in the store
405 */
406 if (dataLen < sizeof(*ev)) {
407 handled = FALSE;
408 break;
409 }
410 copy_if_name(ev, ifr_name, sizeof(ifr_name));
411 link_update_status(ifr_name, FALSE);
412 break;
413
414 case KEV_DL_SIFFLAGS :
415 case KEV_DL_SIFMETRICS :
416 case KEV_DL_SIFMTU :
417 case KEV_DL_SIFPHYS :
418 case KEV_DL_SIFMEDIA :
419 case KEV_DL_SIFGENERIC :
420 case KEV_DL_ADDMULTI :
421 case KEV_DL_DELMULTI :
422 case KEV_DL_LINK_ADDRESS_CHANGED :
423 case KEV_DL_WAKEFLAGS_CHANGED :
424 #ifdef KEV_DL_IF_IDLE_ROUTE_REFCNT
425 case KEV_DL_IF_IDLE_ROUTE_REFCNT :
426 #endif // KEV_DL_IF_IDLE_ROUTE_REFCNT
427 break;
428
429 default :
430 handled = FALSE;
431 break;
432 }
433 break;
434 }
435 case KEV_LOG_SUBCLASS : {
436 break;
437 }
438 default :
439 handled = FALSE;
440 break;
441 }
442
443 if (handled == FALSE) {
444 CFStringRef evStr;
445
446 evStr = CFStringCreateWithCString(NULL,
447 (eventName != NULL) ? eventName : "New Apple network subclass",
448 kCFStringEncodingASCII);
449 logEvent(evStr, ev_msg);
450 CFRelease(evStr);
451 }
452 return;
453 }
454
455 static void
456 eventCallback(CFSocketRef s, CFSocketCallBackType type, CFDataRef address, const void *data, void *info)
457 {
458 int so = CFSocketGetNative(s);
459 int status;
460 char buf[1024];
461 struct kern_event_msg *ev_msg = (struct kern_event_msg *)&buf[0];
462 int offset = 0;
463
464 status = recv(so, &buf, sizeof(buf), 0);
465 if (status == -1) {
466 SCLog(TRUE, LOG_ERR, CFSTR("recv() failed: %s"), strerror(errno));
467 goto error;
468 }
469
470 cache_open();
471
472 while (offset < status) {
473 if ((offset + ev_msg->total_size) > status) {
474 SCLog(TRUE, LOG_NOTICE, CFSTR("missed SYSPROTO_EVENT event, buffer not big enough"));
475 break;
476 }
477
478 switch (ev_msg->vendor_code) {
479 case KEV_VENDOR_APPLE :
480 switch (ev_msg->kev_class) {
481 case KEV_NETWORK_CLASS :
482 processEvent_Apple_Network(ev_msg);
483 break;
484 case KEV_IOKIT_CLASS :
485 case KEV_SYSTEM_CLASS :
486 case KEV_APPLESHARE_CLASS :
487 case KEV_FIREWALL_CLASS :
488 case KEV_IEEE80211_CLASS :
489 break;
490 default :
491 /* unrecognized (Apple) event class */
492 logEvent(CFSTR("New (Apple) class"), ev_msg);
493 break;
494 }
495 break;
496 default :
497 /* unrecognized vendor code */
498 logEvent(CFSTR("New vendor"), ev_msg);
499 break;
500 }
501 offset += ev_msg->total_size;
502 ev_msg = (struct kern_event_msg *)&buf[offset];
503 }
504
505 cache_write(store);
506 cache_close();
507 post_network_changed();
508
509 return;
510
511 error :
512
513 SCLog(TRUE, LOG_ERR, CFSTR("kernel event monitor disabled."));
514 CFSocketInvalidate(s);
515 return;
516
517 }
518
519 __private_extern__
520 void
521 prime_KernelEventMonitor()
522 {
523 struct ifaddrs *ifap = NULL;
524 struct ifaddrs *scan;
525 int sock = -1;
526
527 SCLog(_verbose, LOG_DEBUG, CFSTR("prime() called"));
528
529 cache_open();
530
531 sock = dgram_socket(AF_INET);
532 if (sock == -1) {
533 SCLog(TRUE, LOG_ERR, CFSTR("could not get interface list, socket() failed: %s"), strerror(errno));
534 goto done;
535 }
536
537 if (getifaddrs(&ifap) == -1) {
538 SCLog(TRUE,
539 LOG_ERR,
540 CFSTR("could not get interface info, getifaddrs() failed: %s"),
541 strerror(errno));
542 goto done;
543 }
544
545 /* update list of interfaces & link status */
546 for (scan = ifap; scan != NULL; scan = scan->ifa_next) {
547 if (scan->ifa_addr == NULL
548 || scan->ifa_addr->sa_family != AF_LINK) {
549 continue;
550 }
551 /* get the per-interface link/media information */
552 link_add(scan->ifa_name);
553 }
554
555 /*
556 * update IPv4 network addresses already assigned to
557 * the interfaces.
558 */
559 interface_update_ipv4(ifap, NULL);
560
561 /*
562 * update IPv6 network addresses already assigned to
563 * the interfaces.
564 */
565 interface_update_ipv6(ifap, NULL);
566
567 freeifaddrs(ifap);
568
569 done:
570 if (sock != -1)
571 close(sock);
572
573 cache_write(store);
574 cache_close();
575
576 network_changed = TRUE;
577 post_network_changed();
578
579 return;
580 }
581
582 static CFStringRef
583 kevSocketCopyDescription(const void *info)
584 {
585 return CFStringCreateWithFormat(NULL, NULL, CFSTR("<kernel event socket>"));
586 }
587
588 __private_extern__
589 void
590 load_KernelEventMonitor(CFBundleRef bundle, Boolean bundleVerbose)
591 {
592 CFSocketContext context = { 0
593 , (void *)1
594 , NULL
595 , NULL
596 , kevSocketCopyDescription
597 };
598 CFSocketRef es;
599 struct kev_request kev_req;
600 CFRunLoopSourceRef rls;
601 int so;
602 int status;
603
604 if (bundleVerbose) {
605 _verbose = TRUE;
606 }
607
608 SCLog(_verbose, LOG_DEBUG, CFSTR("load() called"));
609 SCLog(_verbose, LOG_DEBUG, CFSTR(" bundle ID = %@"), CFBundleGetIdentifier(bundle));
610
611 /* open a "configd" session to allow cache updates */
612 store = SCDynamicStoreCreate(NULL,
613 CFSTR("Kernel Event Monitor plug-in"),
614 NULL,
615 NULL);
616 if (store == NULL) {
617 SCLog(TRUE, LOG_ERR, CFSTR("SCDnamicStoreCreate() failed: %s"), SCErrorString(SCError()));
618 SCLog(TRUE, LOG_ERR, CFSTR("kernel event monitor disabled."));
619 return;
620 }
621
622 /* Open an event socket */
623 so = socket(PF_SYSTEM, SOCK_RAW, SYSPROTO_EVENT);
624 if (so != -1) {
625 /* establish filter to return events of interest */
626 kev_req.vendor_code = KEV_VENDOR_APPLE;
627 kev_req.kev_class = KEV_NETWORK_CLASS;
628 kev_req.kev_subclass = KEV_ANY_SUBCLASS;
629 status = ioctl(so, SIOCSKEVFILT, &kev_req);
630 if (status) {
631 SCLog(TRUE, LOG_ERR, CFSTR("could not establish event filter, ioctl() failed: %s"), strerror(errno));
632 (void) close(so);
633 so = -1;
634 }
635 } else {
636 SCLog(TRUE, LOG_ERR, CFSTR("could not open event socket, socket() failed: %s"), strerror(errno));
637 }
638
639 if (so != -1) {
640 int yes = 1;
641
642 status = ioctl(so, FIONBIO, &yes);
643 if (status) {
644 SCLog(TRUE, LOG_ERR, CFSTR("could not set non-blocking io, ioctl() failed: %s"), strerror(errno));
645 (void) close(so);
646 so = -1;
647 }
648 }
649
650 if (so == -1) {
651 SCLog(TRUE, LOG_ERR, CFSTR("kernel event monitor disabled."));
652 CFRelease(store);
653 return;
654 }
655
656 /* Create a CFSocketRef for the PF_SYSTEM kernel event socket */
657 es = CFSocketCreateWithNative(NULL,
658 so,
659 kCFSocketReadCallBack,
660 eventCallback,
661 &context);
662
663 /* Create and add a run loop source for the event socket */
664 rls = CFSocketCreateRunLoopSource(NULL, es, 0);
665 CFRunLoopAddSource(CFRunLoopGetCurrent(), rls, kCFRunLoopDefaultMode);
666 CFRelease(rls);
667 CFRelease(es);
668
669 return;
670 }
671
672 #ifdef MAIN
673
674 #include "ev_dlil.c"
675
676 #define appendAddress appendAddress_v4
677 #define getIF getIF_v4
678 #define updateStore updateStore_v4
679 #include "ev_ipv4.c"
680 #undef appendAddress
681 #undef getIF
682 #undef updateStore
683
684 #define appendAddress appendAddress_v6
685 #define getIF getIF_v6
686 #define updateStore updateStore_v6
687 #include "ev_ipv6.c"
688 #undef appendAddress
689 #undef getIF
690 #undef updateStore
691
692 int
693 main(int argc, char **argv)
694 {
695 _sc_log = FALSE;
696 _sc_verbose = (argc > 1) ? TRUE : FALSE;
697
698 load_KernelEventMonitor(CFBundleGetMainBundle(), (argc > 1) ? TRUE : FALSE);
699 prime_KernelEventMonitor();
700 CFRunLoopRun();
701 /* not reached */
702 exit(0);
703 return 0;
704 }
705 #endif