2  * Copyright (c) 2017-2019 Apple Inc. All rights reserved.
 
   4  * @APPLE_LICENSE_HEADER_START@
 
   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
 
  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.
 
  21  * @APPLE_LICENSE_HEADER_END@
 
  25  * Modification History
 
  27  * November 15, 2017    Allan Nathanson <ajn@apple.com>
 
  32 #import "EventFactory.h"
 
  33 #import "SCLogParser.h"
 
  34 #import "InterfaceNamerParser.h"
 
  35 #import "IPMonitorParser.h"
 
  36 #import "KernelEventMonitorParser.h"
 
  37 #import "PreferencesMonitorParser.h"
 
  38 #import "StateDumpParser.h"
 
  39 #import "IPConfigurationParser.h"
 
  40 #import "SCDynamicStoreParser.h"
 
  41 #import "SCPreferencesParser.h"
 
  47 __log_Spectacles(void)
 
  49         static os_log_t log     = NULL;
 
  52                 log = os_log_create("com.apple.spectacles", "SystemConfiguration");
 
  59 #pragma mark SystemConfiguratioin Network Event Factory
 
  61 typedef NS_ENUM(NSInteger, LogAccumulatingState) {
 
  68 @interface EventFactory ()
 
  69 @property NSDictionary<NSString *, SCLogParser *> *parserMap;
 
  70 @property LogAccumulatingState accumulating;
 
  71 @property EFLogEvent *accumulatingEvent;
 
  72 @property NSString *accumulatingEventIdentifierString;
 
  75 @implementation EventFactory
 
  77 - (void)startWithLogSourceAttributes:(__unused NSDictionary<NSString *, NSObject *> *)attributes
 
  79         NSMutableDictionary<NSString *, SCLogParser *> *newParserMap = [[NSMutableDictionary alloc] init];
 
  82         parser = [[InterfaceNamerParser alloc] init];
 
  83         newParserMap[parser.category] = parser;
 
  85         parser = [[IPConfigurationParser alloc] init];
 
  86         newParserMap[parser.category] = parser;
 
  88         parser = [[IPMonitorParser alloc] init];
 
  89         newParserMap[parser.category] = parser;
 
  91         parser = [[KernelEventMonitorParser alloc] init];
 
  92         newParserMap[parser.category] = parser;
 
  94         parser = [[PreferencesMonitorParser alloc] init];
 
  95         newParserMap[parser.category] = parser;
 
  97         parser = [[StateDumpParser alloc] init];
 
  98         newParserMap[parser.category] = parser;
 
 100         parser = [[SCDynamicStoreParser alloc] init];
 
 101         newParserMap[parser.category] = parser;
 
 103         parser = [[SCPreferencesParser alloc] init];
 
 104         newParserMap[parser.category] = parser;
 
 106         _parserMap = [[NSDictionary alloc] initWithDictionary:newParserMap];
 
 108         _accumulating = NOT_ACCUMULATING;
 
 111 - (NSString *)logEventIdentifierString:(EFLogEvent *)logEvent
 
 113         NSString        *identifierString;
 
 115         identifierString = [[NSString alloc] initWithFormat:@"%@[%d]:%@:%@",
 
 117                                                         logEvent.processIdentifier,
 
 121         return identifierString;
 
 124 - (void)handleLogEvent:(EFLogEvent *)logEvent completionHandler:(void (^)(NSArray<EFEvent *> * _Nullable))completionHandler
 
 126         if ([logEvent.eventType isEqualToString:@"stateEvent"]) {
 
 127                 logEvent.subsystem = @"com.apple.SystemConfiguration";
 
 128                 logEvent.category = @"StateDump";
 
 129         } else if ([logEvent.subsystem isEqualToString:@"com.apple.IPConfiguration"]) {
 
 130                 logEvent.category = @"IPConfiguration";
 
 133         if (logEvent.category.length == 0) {
 
 134                 specs_log_debug("Skipped message without a category: %@", logEvent.eventMessage);
 
 135                 completionHandler(nil);
 
 139         if ([logEvent.subsystem isEqualToString:@"com.apple.SystemConfiguration"] &&
 
 140                 [logEvent.category  isEqualToString:@"IPMonitor"]) {
 
 141                 BOOL            appendMessage   = YES;
 
 144                 if (_accumulating != NOT_ACCUMULATING) {
 
 146                          * if we are accumulating a block of log messages
 
 148                         NSString *logEventIdentifierString = [self logEventIdentifierString:logEvent];
 
 149                         if ((_accumulating != NOT_ACCUMULATING) &&
 
 150                                 ![_accumulatingEventIdentifierString isEqualToString:logEventIdentifierString]) {
 
 151                                 // if the PID changed
 
 152                                 specs_log_debug("Dropped partial message block: %@", _accumulatingEvent.eventMessage);
 
 153                                 _accumulating = NOT_ACCUMULATING;
 
 154                                 _accumulatingEvent = nil;
 
 159                 switch (_accumulating) {
 
 160                         case NOT_ACCUMULATING : {
 
 161                                 if ([logEvent.eventMessage isEqualToString:@"Updating DNS configuration"]) {
 
 163                                           2019-10-10 14:07:32.891719-0400 0x350      Info        0x0                  70     0    configd: [com.apple.SystemConfiguration:IPMonitor] Updating DNS configuration
 
 164                                           2019-10-10 14:07:32.891722-0400 0x350      Info        0x0                  70     0    configd: [com.apple.SystemConfiguration:IPMonitor] DNS configuration
 
 166                                           2019-10-10 14:03:17.549361-0400 0x0        State       0x2ed40              70     14   configd: DNS Configuration
 
 169                                         _accumulating = ACCUMULATING_DNS;
 
 170                                         logEvent.eventMessage = @"DNS Configuration";
 
 171                                 } else if ([logEvent.eventMessage isEqualToString:@"Updating network information"]) {
 
 173                                           2019-10-10 14:07:32.889595-0400 0x350      Info        0x0                  70     0    configd: [com.apple.SystemConfiguration:IPMonitor] Updating network information
 
 174                                           2019-10-10 14:07:32.889596-0400 0x350      Info        0x0                  70     0    configd: [com.apple.SystemConfiguration:IPMonitor] Network information (generation 156994061625682 size=1180)
 
 176                                           2019-10-10 14:03:17.549364-0400 0x0        State       0x2ed40              70     14   configd: Network information
 
 177                                           Network information (generation 55086114928 size=724)
 
 179                                         _accumulating = ACCUMULATING_NWIv4;
 
 180                                         logEvent.eventMessage = @"Network information";
 
 183                                 if (_accumulating != NOT_ACCUMULATING) {
 
 184                                         // if we are now accumulating a block of messages
 
 185                                         _accumulatingEventIdentifierString = [self logEventIdentifierString:logEvent];
 
 186                                         _accumulatingEvent = logEvent;
 
 187                                         _accumulatingEvent.subsystem = @"com.apple.SystemConfiguration";
 
 188                                         _accumulatingEvent.category = @"StateDump";
 
 194                         case ACCUMULATING_DNS : {
 
 195                                 if ([logEvent.eventMessage hasPrefix:@"DNS configuration updated: "]) {
 
 202                         case ACCUMULATING_NWIv4 : {
 
 203                                 if ([logEvent.eventMessage isEqualToString:@"IPv6 network interface information"]) {
 
 204                                         _accumulating = ACCUMULATING_NWIv6;
 
 209                         case ACCUMULATING_NWIv6 : {
 
 210                                 if ([logEvent.eventMessage hasPrefix:@"   REACH : "]) {
 
 218                         _accumulatingEvent.eventMessage = [NSString stringWithFormat:@"%@\n%@",
 
 219                                                                                                         _accumulatingEvent.eventMessage,
 
 220                                                                                                         logEvent.eventMessage];
 
 224                         // if we have all we need, pass the [accumulated] event
 
 225                         logEvent = _accumulatingEvent;
 
 226                         _accumulating = NOT_ACCUMULATING;
 
 227                         _accumulatingEvent = nil;
 
 228                 } else if (_accumulating != NOT_ACCUMULATING) {
 
 229                         // if we are still (or now) accumulating
 
 230                         completionHandler(nil);
 
 235         SCLogParser *parser = _parserMap[logEvent.category];
 
 237                 specs_log_debug("Skipped message with an unknown category (%@): %@", logEvent.category, logEvent.eventMessage);
 
 238                 completionHandler(nil);
 
 242         NSArray<EFEvent *> *completeEvents = [parser.eventParser parseLogEventIntoMultipleEvents:logEvent];
 
 243         completionHandler(completeEvents);
 
 246 - (void)finishWithCompletionHandler:(void (^)(NSArray<EFEvent *> * _Nullable))completionHandler
 
 248         specs_log_notice("Event factory is finishing");
 
 249         completionHandler(nil);