diff --git a/kernelExtension/kernelExtension.xcodeproj/project.pbxproj b/kernelExtension/kernelExtension.xcodeproj/project.pbxproj index 19ee286..bb4c4fb 100644 --- a/kernelExtension/kernelExtension.xcodeproj/project.pbxproj +++ b/kernelExtension/kernelExtension.xcodeproj/project.pbxproj @@ -138,7 +138,7 @@ 7D5208E81E41C23900832F57 /* Project object */ = { isa = PBXProject; attributes = { - LastUpgradeCheck = 0820; + LastUpgradeCheck = 0900; ORGANIZATIONNAME = "Objective-See"; TargetAttributes = { 7D5208F01E41C23900832F57 = { @@ -200,7 +200,9 @@ CLANG_CXX_LIBRARY = "libc++"; CLANG_ENABLE_MODULES = YES; CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; CLANG_WARN_CONSTANT_CONVERSION = YES; CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; CLANG_WARN_DOCUMENTATION_COMMENTS = YES; @@ -208,7 +210,11 @@ CLANG_WARN_ENUM_CONVERSION = YES; CLANG_WARN_INFINITE_RECURSION = YES; CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; CLANG_WARN_SUSPICIOUS_MOVE = YES; CLANG_WARN_SUSPICIOUS_MOVES = YES; CLANG_WARN_UNREACHABLE_CODE = YES; @@ -232,7 +238,7 @@ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; - MACOSX_DEPLOYMENT_TARGET = 10.12; + MACOSX_DEPLOYMENT_TARGET = 10.10; MTL_ENABLE_DEBUG_INFO = YES; ONLY_ACTIVE_ARCH = YES; SDKROOT = macosx; @@ -248,7 +254,9 @@ CLANG_CXX_LIBRARY = "libc++"; CLANG_ENABLE_MODULES = YES; CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; CLANG_WARN_CONSTANT_CONVERSION = YES; CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; CLANG_WARN_DOCUMENTATION_COMMENTS = YES; @@ -256,7 +264,11 @@ CLANG_WARN_ENUM_CONVERSION = YES; CLANG_WARN_INFINITE_RECURSION = YES; CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; CLANG_WARN_SUSPICIOUS_MOVE = YES; CLANG_WARN_SUSPICIOUS_MOVES = YES; CLANG_WARN_UNREACHABLE_CODE = YES; @@ -274,7 +286,7 @@ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; - MACOSX_DEPLOYMENT_TARGET = 10.12; + MACOSX_DEPLOYMENT_TARGET = 10.10; MTL_ENABLE_DEBUG_INFO = NO; SDKROOT = macosx; }; diff --git a/kernelExtension/kernelExtension/broadcastEvents.cpp b/kernelExtension/kernelExtension/broadcastEvents.cpp index 3f8929a..8131e3b 100644 --- a/kernelExtension/kernelExtension/broadcastEvents.cpp +++ b/kernelExtension/kernelExtension/broadcastEvents.cpp @@ -43,7 +43,6 @@ bool initBroadcast() } //broadcast an event to user mode -//TODO: when IPV6 is supported; sockaddr/vs sockaddr_in/sockaddr_in6 for size bool broadcastEvent(int type, socket_t so, const struct sockaddr *to) { //return var @@ -56,10 +55,10 @@ bool broadcastEvent(int type, socket_t so, const struct sockaddr *to) int processID = 0; //local socket address - struct sockaddr_in localAddress = {0}; + struct sockaddr_in6 localAddress = {0}; //remote socket address - struct sockaddr_in remoteAddress = {0}; + struct sockaddr_in6 remoteAddress = {0}; //socket type int socketType = 0; @@ -166,6 +165,7 @@ bool broadcastEvent(int type, socket_t so, const struct sockaddr *to) return result; } +/* //broadcast an DNS reponse to user mode bool broadcastDNSReponse(int type, void* packet, size_t length) { @@ -228,4 +228,5 @@ bool broadcastDNSReponse(int type, void* packet, size_t length) return result; } +*/ diff --git a/kernelExtension/kernelExtension/broadcastEvents.hpp b/kernelExtension/kernelExtension/broadcastEvents.hpp index 512a9d2..66bd8d5 100644 --- a/kernelExtension/kernelExtension/broadcastEvents.hpp +++ b/kernelExtension/kernelExtension/broadcastEvents.hpp @@ -33,6 +33,6 @@ bool initBroadcast(); bool broadcastEvent(int type, socket_t so, const struct sockaddr *to); //broadcast an DNS reponse to user mode -bool broadcastDNSReponse(int type, void* packet, size_t length); +//bool broadcastDNSReponse(int type, void* packet, size_t length); #endif diff --git a/kernelExtension/kernelExtension/driver.cpp b/kernelExtension/kernelExtension/driver.cpp index 2af71e3..f6b38a6 100644 --- a/kernelExtension/kernelExtension/driver.cpp +++ b/kernelExtension/kernelExtension/driver.cpp @@ -99,7 +99,7 @@ bool com_objective_see_firewall::start(IOService *provider) } //init shared data queue - sharedDataQueue = IOSharedDataQueue::withCapacity(sizeof(firewallEvent) * (MAX_FIREWALL_EVENT + DATA_QUEUE_ENTRY_HEADER_SIZE)); + sharedDataQueue = IOSharedDataQueue::withCapacity(sizeof(firewallEvent) * (MAX_FIREWALL_EVENTS + DATA_QUEUE_ENTRY_HEADER_SIZE)); if(NULL == sharedDataQueue) { //bail diff --git a/kernelExtension/kernelExtension/socketEvents.cpp b/kernelExtension/kernelExtension/socketEvents.cpp index 9dc1def..f8073fe 100644 --- a/kernelExtension/kernelExtension/socketEvents.cpp +++ b/kernelExtension/kernelExtension/socketEvents.cpp @@ -16,12 +16,6 @@ #include -/* TODOs: - - a) add IPV6 support - -*/ - /* socket events called by OS */ static void detach(void *cookie, socket_t so); static errno_t attach(void **cookie, socket_t so); @@ -90,6 +84,50 @@ static struct sflt_filter udpFilterIPV4 = { NULL }; +//socket filter, TCP IPV6 +static struct sflt_filter tcpFilterIPV6 = { + FLT_TCPIPV6_HANDLE, + SFLT_GLOBAL, + (char*)BUNDLE_ID, + unregistered, + attach, + detach, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + connect_out, + NULL, + NULL, + NULL, + NULL, + NULL +}; + +//socket filter, UDP IPV4 +static struct sflt_filter udpFilterIPV6 = { + FLT_UDPIPV6_HANDLE, + SFLT_GLOBAL, + (char*)BUNDLE_ID, + unregistered, + attach, + detach, + NULL, + NULL, + NULL, + data_in, + data_out, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL +}; + //register socket filters kern_return_t registerSocketFilters() @@ -104,12 +142,13 @@ kern_return_t registerSocketFilters() IOLog("LULU: in %s\n", __FUNCTION__); //sanity check - // TODO: when IPV6 support added, add here too if( (true == gRegisteredTCPIPV4) || - (true == gRegisteredUDPIPV4) ) + (true == gRegisteredUDPIPV4) || + (true == gRegisteredTCPIPV6) || + (true == gRegisteredUDPIPV6) ) { //err msg - IOLog("LULU ERROR: socket filters already registered (%d/%d)\n", gRegisteredTCPIPV4, gRegisteredUDPIPV4); + IOLog("LULU ERROR: socket filters already registered (%d/%d/%d/%d)\n", gRegisteredTCPIPV4, gRegisteredUDPIPV4, gRegisteredTCPIPV6, gRegisteredUDPIPV6); //bail goto bail; @@ -117,11 +156,11 @@ kern_return_t registerSocketFilters() //register socket filter // ->AF_INET domain, SOCK_STREAM type, TCP protocol - status = sflt_register(&tcpFilterIPV4, PF_INET, SOCK_STREAM, IPPROTO_TCP); + status = sflt_register(&tcpFilterIPV4, AF_INET, SOCK_STREAM, IPPROTO_TCP); if(kIOReturnSuccess != status) { //err msg - IOLog("LULU ERROR: sflt_register failed with %d\n", status); + IOLog("LULU ERROR: sflt_register('tcpFilterIPV4') failed with %d\n", status); //bail goto bail; @@ -135,11 +174,11 @@ kern_return_t registerSocketFilters() //register socket filter // ->AF_INET domain, SOCK_DGRAM type, UDP protocol - status = sflt_register(&udpFilterIPV4, PF_INET, SOCK_DGRAM, IPPROTO_UDP); + status = sflt_register(&udpFilterIPV4, AF_INET, SOCK_DGRAM, IPPROTO_UDP); if(kIOReturnSuccess != status) { //err msg - IOLog("LULU ERROR: sflt_register failed with %d\n", status); + IOLog("LULU ERROR: sflt_register('udpFilterIPV4') failed with %d\n", status); //bail goto bail; @@ -150,6 +189,42 @@ kern_return_t registerSocketFilters() //dbg msg IOLog("LULU: registerd socker filter for udp ipv4\n"); + + //register socket filter + // ->AF_INET6 domain, SOCK_STREAM type, TCP protocol + status = sflt_register(&tcpFilterIPV6, AF_INET6, SOCK_STREAM, IPPROTO_TCP); + if(kIOReturnSuccess != status) + { + //err msg + IOLog("LULU ERROR: sflt_register('tcpFilterIPV6') failed with %d\n", status); + + //bail + goto bail; + } + + //set global flag + gRegisteredTCPIPV6 = true; + + //dbg msg + IOLog("LULU: registerd socker filter for tcp ipv6\n"); + + //register socket filter + // ->AF_INET6 domain, SOCK_DGRAM type, UDP protocol + status = sflt_register(&udpFilterIPV6, AF_INET6, SOCK_DGRAM, IPPROTO_UDP); + if(kIOReturnSuccess != status) + { + //err msg + IOLog("LULU ERROR: sflt_register('udpFilterIPV6') failed with %d\n", status); + + //bail + goto bail; + } + + //set global flag + gRegisteredUDPIPV6 = true; + + //dbg msg + IOLog("LULU: registerd socker filter for udp ipv6\n"); //happy result = kIOReturnSuccess; @@ -169,12 +244,13 @@ kern_return_t unregisterSocketFilters() IOLog("LULU: in %s\n", __FUNCTION__); //sanity check - // TODO: when IPV6 support added, add here too if( (false == gRegisteredTCPIPV4) || - (false == gRegisteredUDPIPV4) ) + (false == gRegisteredUDPIPV4) || + (false == gRegisteredTCPIPV6) || + (false == gRegisteredUDPIPV6) ) { //err msg - IOLog("LULU ERROR: socket filters already unregistered (%d/%d)\n", gRegisteredTCPIPV4, gRegisteredUDPIPV4); + IOLog("LULU ERROR: socket filters already unregistered (%d/%d/%d/%d)\n", gRegisteredTCPIPV4, gRegisteredUDPIPV4, gRegisteredTCPIPV6, gRegisteredUDPIPV6); //bail goto bail; @@ -206,12 +282,40 @@ kern_return_t unregisterSocketFilters() gUnregisteringUDPIPV4 = true; } + //TCP IPV6 + // when filter's been registered & not currently unregistering + // ->invoke sflt_unregister to unregister, and set global flag + if( (true == gRegisteredTCPIPV6) && + (true != gUnregisteringTCPIPV6)) + { + //unregister + sflt_unregister(FLT_TCPIPV6_HANDLE); + + //set global flag + gUnregisteringTCPIPV6 = true; + } + + //UDP IPV6 + // when filter's been registered & not currently unregistering + // ->invoke sflt_unregister to unregister, and set global flag + if( (true == gRegisteredUDPIPV6) && + (true != gUnregisteringUDPIPV6)) + { + //unregister + sflt_unregister(FLT_UDPIPV6_HANDLE); + + //set global flag + gUnregisteringUDPIPV6 = true; + } + //filter still registered? if( (true == gRegisteredTCPIPV4) || - (true == gRegisteredUDPIPV4) ) + (true == gRegisteredUDPIPV4) || + (true == gRegisteredTCPIPV6) || + (true == gRegisteredUDPIPV6) ) { //err msg - IOLog("LULU ERROR: socket filter(s) still registered %d/%d\n", gRegisteredTCPIPV4, gRegisteredUDPIPV4); + IOLog("LULU ERROR: socket filter(s) still registered %d/%d/%d/%d\n", gRegisteredTCPIPV4, gRegisteredUDPIPV4, gRegisteredTCPIPV6, gRegisteredUDPIPV6); //set error status = EBUSY; @@ -235,20 +339,39 @@ static void unregistered(sflt_handle handle) //dbg msg IOLog("LULU: in %s\n", __FUNCTION__); - //tcp ipv4 - // ->set flag - if(FLT_TCPIPV4_HANDLE == handle) - { - //set - gRegisteredTCPIPV4 = false; - } - - //tcp ipv4 - // ->set flag - else if(FLT_UDPIPV4_HANDLE == handle) - { - //set - gRegisteredUDPIPV4 = false; + //set appropriate handle + switch (handle) { + + //tcp ipv4 + case FLT_TCPIPV4_HANDLE: + + //set + gRegisteredTCPIPV4 = false; + break; + + //udp ipv4 + case FLT_UDPIPV4_HANDLE: + + //set + gRegisteredUDPIPV4 = false; + break; + + //tcp ipv6 + case FLT_TCPIPV6_HANDLE: + + //set + gRegisteredTCPIPV6 = false; + break; + + //udp ipv6 + case FLT_UDPIPV6_HANDLE: + + //set + gRegisteredUDPIPV6 = false; + break; + + default: + break; } return; @@ -280,7 +403,7 @@ static kern_return_t attach(void **cookie, socket_t so) } //set rule action - // ->not found, block, allow, etc + // not found, block, allow, etc ((struct cookieStruct*)(*cookie))->ruleAction = queryRule(proc_selfpid()); //dbg msg @@ -314,7 +437,6 @@ static void detach(void *cookie, socket_t so) return; } - //callback for incoming data // only interested in DNS responses for IP:URL mappings // code inspired by: https://github.com/williamluke/peerguardian-linux/blob/master/pgosx/kern/ppfilter.c @@ -332,9 +454,15 @@ static errno_t data_in(void *cookie, socket_t so, const struct sockaddr *from, m //mem buffer mbuf_t memBuffer = NULL; + //response size + size_t responseSize = 0; + //dns header dnsHeader* dnsHeader = NULL; + //firewall event + firewallEvent event = {0}; + //destination socket ('from') might be null? // if so, grab it via 'getpeername' from the socket if(NULL == from) @@ -431,126 +559,25 @@ static errno_t data_in(void *cookie, socket_t so, const struct sockaddr *from, m goto bail; } - //ok, likely candidate - // let's broadcast to user mode for parsing - if(true != broadcastDNSReponse(EVENT_DNS_RESPONSE, mbuf_data(memBuffer), mbuf_len(memBuffer))) - { - //err msg - IOLog("LULU ERROR: failed to broadcast DNS response to user mode\n"); - - //bail - goto bail; - - } + //zero out event struct + bzero(&event, sizeof(firewallEvent)); - - /* - + //set type + event.dnsResponseEvent.type = EVENT_DNS_RESPONSE; - mbuf_t mdata = *data; - while (mdata && MBUF_TYPE_DATA != mbuf_type(mdata)) { - mdata = mbuf_next(mdata); - } - if (!mdata) - return (0); + //set size + // max, 512 + responseSize = MIN(sizeof(event.dnsResponseEvent.response), mbuf_len(memBuffer)); - char *pkt = (char*)mbuf_data(mdata); - if (!pkt) - return (0); - size_t len = mbuf_len(mdata); - - char* dnsData = pkt+sizeof(struct dns_header); - - //dbg msg - printf("LULUX: port (dns): %d\n", port); - printf("LULUX: length: %d\n", len); - - - dns_header* header = (struct dns_header*)pkt; - - printf("LULUX DNS HEADER\n"); - printf("LULUX id:%x\n", ntohs(header->id)); - printf("LULUX flags:%x\n", ntohs(header->flags)); - - if((ntohs(header->flags)) & (1<<(15))) - { - printf("LULUX top bit set: Response (%d)\n", (ntohs(header->flags)) & (1<<(15))); - } - else - { - printf("LULUX ignoring, as not response\n"); - - //ignore - return kIOReturnSuccess; - } - - - //log show --style syslog | grep LULUX - - if(0 == ((ntohs(header->flags)) & (1<<(0)))) - { - printf("LULUX bottom bit set yah: no errors\n"); - } - - - if(0 == ntohs(header->ancount)) - { - printf("LULUX ignoring, as no answers\n"); - //ignore - return kIOReturnSuccess; - - } - - printf("LULUX # questions:%d\n", ntohs(header->qdcount)); - printf("LULUX # answers:%d\n", ntohs(header->ancount)); - printf("LULUX # ns:%d\n", ntohs(header->nscount)); - printf("LULUX # ar:%d\n", ntohs(header->arcount)); - - */ - //broadcast to user more for parsing - - //printf("LULUX # would broadcast to user mode\n"); - - //return kIOReturnSuccess; - - /* - - int numRRs = ntohs(header->qdcount) + ntohs(header->ancount) + ntohs(header->nscount) + ntohs(header->arcount); - int i; - - printf("LULUX: (%d)", numRRs); - - //numRRs = 0; - for(i=0; itype); - int clas = ntohs(RRd->clas); - int ttl = (uint32_t)ntohl(RRd->ttl); - int rdlength = ntohs(RRd->rdlength); - uint8_t* rd = (uint8_t*)(char*)(&RRd->rdlength + sizeof(uint16_t)); - - printf("LULUX type(%d):",type); printRRType( ntohs(RRd->type) ); printf("\n"); - printf("LULUX class:%d TTL:%d RDlength:%d\n", clas, ttl, rdlength); - if( rdlength != 0 ){ - printf("LULUX data:"); - printf("LULUX %d.%d.%d.%d",rd[0], rd[1], rd[2], rd[3] ); - printf("\n"); - } - - } - */ + //copy response + memcpy(event.dnsResponseEvent.response, mbuf_data(memBuffer), responseSize); + //queue it up + sharedDataQueue->enqueue_tail(&event, sizeof(firewallEvent)); bail: return kIOReturnSuccess; - } @@ -615,7 +642,7 @@ static kern_return_t connect_out(void *cookie, socket_t so, const struct sockadd } //process -// ->block/allow, or ask user and put thread to sleep +// block/allow, or ask user and put thread to sleep kern_return_t process(void *cookie, socket_t so, const struct sockaddr *to) { //result @@ -640,9 +667,12 @@ kern_return_t process(void *cookie, socket_t so, const struct sockaddr *to) char processName[PATH_MAX] = {0}; //what does rule say? - // ->loop until we have an answer + // loop until we have an answer while(true) { + //reset + bzero(&event, sizeof(event)); + //extract action action = ((struct cookieStruct*)cookie)->ruleAction; @@ -685,8 +715,11 @@ kern_return_t process(void *cookie, socket_t so, const struct sockaddr *to) //zero out bzero(&event, sizeof(firewallEvent)); + //set type + event.networkOutEvent.type = EVENT_NETWORK_OUT; + //add pid - event.pid = proc_selfpid(); + event.networkOutEvent.pid = proc_selfpid(); //init length socketTypeLength = sizeof(socketType); @@ -695,14 +728,14 @@ kern_return_t process(void *cookie, socket_t so, const struct sockaddr *to) sock_getsockopt(so, SOL_SOCKET, SO_TYPE, &socketType, &socketTypeLength); //save type - event.socketType = socketType; + event.networkOutEvent.socketType = socketType; //UDP sockets destination socket might be null - // ->so grab via 'getpeername' and save as 'remote addr' + // so grab via 'getpeername' and save as 'remote addr' if(NULL == to) { //copy into 'remote addr' for user mode - if(0 != sock_getpeername(so, (struct sockaddr*)&(event.remoteAddress), sizeof(struct sockaddr_in))) + if(0 != sock_getpeername(so, (struct sockaddr*)&(event.networkOutEvent.remoteAddress), sizeof(event.networkOutEvent.remoteAddress))) { //err msg IOLog("LULU ERROR: sock_getpeername() failed"); @@ -716,7 +749,7 @@ kern_return_t process(void *cookie, socket_t so, const struct sockaddr *to) else { //add remote (destination) socket addr - memcpy(&(event.remoteAddress), to, sizeof(struct sockaddr)); + memcpy(&(event.networkOutEvent.remoteAddress), to, sizeof(event.networkOutEvent.remoteAddress)); } //queue it up @@ -731,7 +764,7 @@ kern_return_t process(void *cookie, socket_t so, const struct sockaddr *to) //sleep reason = IOLockSleep(ruleEventLock, &ruleEventLock, THREAD_ABORTSAFE); - //TODO: fix panic + //TODO: fix panic, think if kext is unloaded (sets ruleEventLock to NULL) this can still wake up? // "Preemption level underflow, possible cause unlocking an unlocked mutex or spinlock" // seems to happen when process is killed or kext unloaded while in the IOLockSleep!? diff --git a/kernelExtension/kernelExtension/socketEvents.hpp b/kernelExtension/kernelExtension/socketEvents.hpp index a1ce778..a5af42a 100644 --- a/kernelExtension/kernelExtension/socketEvents.hpp +++ b/kernelExtension/kernelExtension/socketEvents.hpp @@ -10,7 +10,6 @@ #ifndef socketEvents_h #define socketEvents_h - extern "C" { @@ -23,18 +22,26 @@ extern "C" } +#define LULU_FLT_HANDLE_BASE 0x4c754c75 + //socket filter handles -#define FLT_TCPIPV4_HANDLE 'tcp4' -#define FLT_UDPIPV4_HANDLE 'udp4' +// inspired by 'peerguardian' ppfilter.c +#define FLT_TCPIPV4_HANDLE (LULU_FLT_HANDLE_BASE - (AF_INET + IPPROTO_TCP)) +#define FLT_UDPIPV4_HANDLE (LULU_FLT_HANDLE_BASE - (AF_INET + IPPROTO_UDP)) +#define FLT_TCPIPV6_HANDLE (LULU_FLT_HANDLE_BASE - (AF_INET6 + IPPROTO_TCP)) +#define FLT_UDPIPV6_HANDLE (LULU_FLT_HANDLE_BASE - (AF_INET6 + IPPROTO_UDP)) //flag for socket filter registration static boolean_t gRegisteredTCPIPV4 = FALSE; static boolean_t gRegisteredUDPIPV4 = FALSE; +static boolean_t gRegisteredTCPIPV6 = FALSE; +static boolean_t gRegisteredUDPIPV6 = FALSE; //flag for socket filter unregistration static boolean_t gUnregisteringTCPIPV4 = FALSE; static boolean_t gUnregisteringUDPIPV4 = FALSE; - +static boolean_t gUnregisteringTCPIPV6 = FALSE; +static boolean_t gUnregisteringUDPIPV6 = FALSE; /* FUNCTIONS */ @@ -47,5 +54,4 @@ kern_return_t process(void *cookie, socket_t so, const struct sockaddr *to); //unregister socket filters kern_return_t unregisterSocketFilters(); - #endif /* socketEvents_h */ diff --git a/kernelExtension/kernelExtension/userInterface.cpp b/kernelExtension/kernelExtension/userInterface.cpp index 1781095..79118b6 100755 --- a/kernelExtension/kernelExtension/userInterface.cpp +++ b/kernelExtension/kernelExtension/userInterface.cpp @@ -153,7 +153,7 @@ bool com_objectivesee_driver_LuLu::initWithTask (task_t owningTask, void* securi } //call super - if(true != super::initWithTask(owningTask, securityToken , type, properties)) + if(true != super::initWithTask(owningTask, securityToken, type, properties)) { //bail goto bail; diff --git a/launchDaemon/launchDaemon.xcodeproj/project.pbxproj b/launchDaemon/launchDaemon.xcodeproj/project.pbxproj index 1d1f6ff..4354b63 100644 --- a/launchDaemon/launchDaemon.xcodeproj/project.pbxproj +++ b/launchDaemon/launchDaemon.xcodeproj/project.pbxproj @@ -16,7 +16,7 @@ 7D6E87701F3AE6FA00D6BD7C /* libprocInfo.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 7D6E876F1F3AE6FA00D6BD7C /* libprocInfo.a */; }; 7D7755D41F02DF9500D0017D /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 7D7755D31F02DF9500D0017D /* main.m */; }; 7D7755F91F02E1F400D0017D /* KextListener.m in Sources */ = {isa = PBXBuildFile; fileRef = 7D7755F71F02E1F400D0017D /* KextListener.m */; }; - 7D7755FC1F02EBBE00D0017D /* logging.m in Sources */ = {isa = PBXBuildFile; fileRef = 7D7755FA1F02EBBE00D0017D /* logging.m */; }; + 7D7755FC1F02EBBE00D0017D /* Logging.m in Sources */ = {isa = PBXBuildFile; fileRef = 7D7755FA1F02EBBE00D0017D /* Logging.m */; }; 7DD2BF5C1F1DAEFD00B33214 /* Rule.m in Sources */ = {isa = PBXBuildFile; fileRef = 7DD2BF5A1F1DAEFD00B33214 /* Rule.m */; }; 7DD2BF681F1DC42700B33214 /* Utilities.m in Sources */ = {isa = PBXBuildFile; fileRef = 7DD2BF671F1DC42700B33214 /* Utilities.m */; }; 7DD2BF761F1E9CE700B33214 /* NSMutableArray+QueueAdditions.m in Sources */ = {isa = PBXBuildFile; fileRef = 7DD2BF731F1E9CE700B33214 /* NSMutableArray+QueueAdditions.m */; }; @@ -48,16 +48,16 @@ 7D4FF8CA1F0EDD4F001A4A68 /* rules.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = rules.plist; sourceTree = ""; }; 7D4FF8CB1F0EF2F9001A4A68 /* UserComms.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = UserComms.h; sourceTree = ""; }; 7D4FF8CC1F0EF2F9001A4A68 /* UserComms.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = UserComms.m; sourceTree = ""; }; - 7D4FF8CE1F0EF360001A4A68 /* userCommsInterface.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = userCommsInterface.h; path = ../../shared/userCommsInterface.h; sourceTree = ""; }; + 7D4FF8CE1F0EF360001A4A68 /* UserCommsInterface.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = UserCommsInterface.h; path = ../../shared/UserCommsInterface.h; sourceTree = ""; }; 7D6E876E1F3AE5E900D6BD7C /* procInfo.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = procInfo.h; sourceTree = ""; }; 7D6E876F1F3AE6FA00D6BD7C /* libprocInfo.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; name = libprocInfo.a; path = launchDaemon/libs/libprocInfo.a; sourceTree = ""; }; 7D7755D01F02DF9500D0017D /* LuLuDaemon */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = LuLuDaemon; sourceTree = BUILT_PRODUCTS_DIR; }; 7D7755D31F02DF9500D0017D /* main.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = ""; }; 7D7755F71F02E1F400D0017D /* KextListener.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = KextListener.m; sourceTree = ""; }; 7D7755F81F02E1F400D0017D /* KextListener.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = KextListener.h; sourceTree = ""; }; - 7D7755FA1F02EBBE00D0017D /* logging.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = logging.m; path = ../../shared/logging.m; sourceTree = ""; }; - 7D7755FB1F02EBBE00D0017D /* logging.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = logging.h; path = ../../shared/logging.h; sourceTree = ""; }; - 7D7755FD1F02EC1800D0017D /* const.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = const.h; path = ../../shared/const.h; sourceTree = ""; }; + 7D7755FA1F02EBBE00D0017D /* Logging.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = Logging.m; path = ../../shared/Logging.m; sourceTree = ""; }; + 7D7755FB1F02EBBE00D0017D /* Logging.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = Logging.h; path = ../../shared/Logging.h; sourceTree = ""; }; + 7D7755FD1F02EC1800D0017D /* Const.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = Const.h; path = ../../shared/Const.h; sourceTree = ""; }; 7D7756081F05D63E00D0017D /* UserClientShared.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = UserClientShared.h; path = ../../shared/UserClientShared.h; sourceTree = ""; }; 7DD2BF5A1F1DAEFD00B33214 /* Rule.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = Rule.m; path = ../../shared/Rule.m; sourceTree = ""; }; 7DD2BF611F1DAFF800B33214 /* Rule.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = Rule.h; path = ../../shared/Rule.h; sourceTree = ""; }; @@ -146,10 +146,10 @@ 7DD2BF611F1DAFF800B33214 /* Rule.h */, 7DD2BF5A1F1DAEFD00B33214 /* Rule.m */, 7D7756081F05D63E00D0017D /* UserClientShared.h */, - 7D7755FD1F02EC1800D0017D /* const.h */, - 7D7755FA1F02EBBE00D0017D /* logging.m */, - 7D7755FB1F02EBBE00D0017D /* logging.h */, - 7D4FF8CE1F0EF360001A4A68 /* userCommsInterface.h */, + 7D7755FD1F02EC1800D0017D /* Const.h */, + 7D7755FA1F02EBBE00D0017D /* Logging.m */, + 7D7755FB1F02EBBE00D0017D /* Logging.h */, + 7D4FF8CE1F0EF360001A4A68 /* UserCommsInterface.h */, ); name = shared; sourceTree = ""; @@ -180,7 +180,7 @@ 7D7755C81F02DF9400D0017D /* Project object */ = { isa = PBXProject; attributes = { - LastUpgradeCheck = 0820; + LastUpgradeCheck = 0900; ORGANIZATIONNAME = "Objective-See"; TargetAttributes = { 7D7755CF1F02DF9500D0017D = { @@ -222,7 +222,7 @@ 7D4FF8C91F0E1770001A4A68 /* ProcListener.m in Sources */, 7D7755D41F02DF9500D0017D /* main.m in Sources */, 7D4FF8CD1F0EF2F9001A4A68 /* UserComms.m in Sources */, - 7D7755FC1F02EBBE00D0017D /* logging.m in Sources */, + 7D7755FC1F02EBBE00D0017D /* Logging.m in Sources */, 7D4FF3721F0B6D3100A59A05 /* KextComms.m in Sources */, ); runOnlyForDeploymentPostprocessing = 0; @@ -239,7 +239,9 @@ CLANG_CXX_LIBRARY = "libc++"; CLANG_ENABLE_MODULES = YES; CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; CLANG_WARN_CONSTANT_CONVERSION = YES; CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; CLANG_WARN_DOCUMENTATION_COMMENTS = YES; @@ -247,7 +249,11 @@ CLANG_WARN_ENUM_CONVERSION = YES; CLANG_WARN_INFINITE_RECURSION = YES; CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; CLANG_WARN_SUSPICIOUS_MOVE = YES; CLANG_WARN_UNREACHABLE_CODE = YES; CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; @@ -270,7 +276,7 @@ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; - MACOSX_DEPLOYMENT_TARGET = 10.12; + MACOSX_DEPLOYMENT_TARGET = 10.10; MTL_ENABLE_DEBUG_INFO = YES; ONLY_ACTIVE_ARCH = YES; SDKROOT = macosx; @@ -286,7 +292,9 @@ CLANG_CXX_LIBRARY = "libc++"; CLANG_ENABLE_MODULES = YES; CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; CLANG_WARN_CONSTANT_CONVERSION = YES; CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; CLANG_WARN_DOCUMENTATION_COMMENTS = YES; @@ -294,7 +302,11 @@ CLANG_WARN_ENUM_CONVERSION = YES; CLANG_WARN_INFINITE_RECURSION = YES; CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; CLANG_WARN_SUSPICIOUS_MOVE = YES; CLANG_WARN_UNREACHABLE_CODE = YES; CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; @@ -311,7 +323,7 @@ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; - MACOSX_DEPLOYMENT_TARGET = 10.12; + MACOSX_DEPLOYMENT_TARGET = 10.10; MTL_ENABLE_DEBUG_INFO = NO; SDKROOT = macosx; }; @@ -326,6 +338,7 @@ "$(inherited)", "$(PROJECT_DIR)/launchDaemon/libs", ); + OTHER_CODE_SIGN_FLAGS = ""; PRODUCT_NAME = LuLuDaemon; }; name = Debug; @@ -339,6 +352,8 @@ "$(inherited)", "$(PROJECT_DIR)/launchDaemon/libs", ); + OTHER_CODE_SIGN_FLAGS = "-o hard,kill"; + OTHER_LDFLAGS = "-Wl,-sectcreate,__RESTRICT,__restrict,/dev/null"; PRODUCT_NAME = LuLuDaemon; }; name = Release; diff --git a/launchDaemon/launchDaemon/KextListener.h b/launchDaemon/launchDaemon/KextListener.h index f546de2..0c647d0 100644 --- a/launchDaemon/launchDaemon/KextListener.h +++ b/launchDaemon/launchDaemon/KextListener.h @@ -14,6 +14,9 @@ #import #import +#import "procInfo.h" +#import "UserClientShared.h" + //custom struct for network events // format of data that's broadcast from kext struct connectionEvent @@ -61,4 +64,7 @@ struct connectionEvent //remove process from list of alerts -(void)resetAlert:(pid_t)pid; +//create an alert object +-(NSMutableDictionary*)createAlert:(struct networkOutEvent_s*)event process:(Process*)process; + @end diff --git a/launchDaemon/launchDaemon/KextListener.m b/launchDaemon/launchDaemon/KextListener.m index 1a6cd35..1f76ea4 100644 --- a/launchDaemon/launchDaemon/KextListener.m +++ b/launchDaemon/launchDaemon/KextListener.m @@ -66,9 +66,6 @@ -(void)monitor //start thread to get connection notifications from kext //[NSThread detachNewThreadSelector:@selector(recvNotifications) toTarget:self withObject:nil]; - //start thread to get dns requests from the kext - [NSThread detachNewThreadSelector:@selector(recvDNSResponses) toTarget:self withObject:nil]; - //start thread to listen for queue events from kext [NSThread detachNewThreadSelector:@selector(processEvents) toTarget:self withObject:nil]; @@ -145,7 +142,6 @@ -(void)recvNotifications //...any class kevRequest.kev_class = KEV_ANY_CLASS; - //TODO: maybe just say network events? //...any subclass kevRequest.kev_subclass = KEV_ANY_SUBCLASS; @@ -226,343 +222,6 @@ -(void)recvNotifications */ -//thread function -// recv() & parse DNS requests from the kext -// note this info is just to provide URL (instead of IP addr) in alert, so if packet can't easily be parse, we just give up --(void)recvDNSResponses -{ - //status var - int status = -1; - - //system socket - int systemSocket = -1; - - //struct for vendor code - // ->set via call to ioctl/SIOCGKEVVENDOR - struct kev_vendor_code vendorCode = {0}; - - //struct for kernel request - // ->set filtering options - struct kev_request kevRequest = {0}; - - //struct for broadcast data from the kext - struct kern_event_msg *kernEventMsg = {0}; - - //message from kext - // add a plus one so can always stop parsing on (final) NULL - unsigned char kextMsg[MAX_KEV_MSG+1] = {0}; - - //bytes received from system socket - ssize_t bytesReceived = -1; - - //dns header - struct dnsHeader* dnsHeader = NULL; - - //dns data - unsigned char* dnsData = NULL; - - //offset to URL - NSUInteger urlOffset = 0; - - //URL - NSMutableString* url = nil; - - //type - // A, AAAA - unsigned short addressType = 0; - - //ip address - NSString* ipAddress = nil; - - //flag - BOOL validPacket = YES; - - //create system socket - systemSocket = socket(PF_SYSTEM, SOCK_RAW, SYSPROTO_EVENT); - if(-1 == systemSocket) - { - //set status var - status = errno; - - //err msg - logMsg(LOG_ERR, [NSString stringWithFormat:@"socket(PF_SYSTEM, ..., SYSPROTO_EVENT) failed with %d", status]); - - //bail - goto bail; - } - - //set vendor name string - strncpy(vendorCode.vendor_string, OBJECTIVE_SEE_VENDOR, KEV_VENDOR_CODE_MAX_STR_LEN); - - //get vendor name -> vendor code mapping - status = ioctl(systemSocket, SIOCGKEVVENDOR, &vendorCode); - if(0 != status) - { - //err msg - logMsg(LOG_ERR, [NSString stringWithFormat:@"ioctl(...,SIOCGKEVVENDOR,...) failed with %d", status]); - - //bail - goto bail; - } - - //init filtering options - // ->only interested in objective-see's events - kevRequest.vendor_code = vendorCode.vendor_code; - - //...any class - kevRequest.kev_class = KEV_ANY_CLASS; - - //...any subclass - kevRequest.kev_subclass = KEV_ANY_SUBCLASS; - - //tell kernel what we want to filter on - status = ioctl(systemSocket, SIOCSKEVFILT, &kevRequest); - if(0 != status) - { - //err msg - logMsg(LOG_ERR, [NSString stringWithFormat:@"ioctl(...,SIOCSKEVFILT,...) failed with %d", status]); - - //goto bail; - goto bail; - } - - //dbg msg - #ifdef DEBUG - logMsg(LOG_DEBUG, @"created system socket & set options, now entering recv() loop"); - #endif - - //foreverz - // ->listen/parse - while(YES) - { - //reset - validPacket = YES; - - //reset - memset(kextMsg, 0x0, sizeof(kextMsg)); - - //ask the kext for DNS response events - // call will block until event is ready - bytesReceived = recv(systemSocket, kextMsg, sizeof(kextMsg)-1, 0); - - //type cast - // ->to access kev_event_msg header - kernEventMsg = (struct kern_event_msg*)kextMsg; - - //sanity check - // ->make sure data recv'd looks ok, sizewise - if( (bytesReceived < KEV_MSG_HEADER_SIZE) || - (bytesReceived != kernEventMsg->total_size)) - { - //dbg msg - #ifdef DEBUG - logMsg(LOG_DEBUG, [NSString stringWithFormat:@"recv count: %d, wanted: %d", (int)bytesReceived, kernEventMsg->total_size]); - #endif - - //ignore - continue; - } - - //only care about DNS response - if(EVENT_DNS_RESPONSE != kernEventMsg->event_code) - { - //skip - continue; - } - - //type cast custom data - // begins right after kernel message header - dnsHeader = (struct dnsHeader*)&kernEventMsg->event_data[0]; - - //dbg msg - logMsg(LOG_DEBUG, [NSString stringWithFormat:@"recv'd %0zx bytes from kernel", bytesReceived]); - - /* print out packet - unsigned char* bytes = (char*)&kernEventMsg->event_data[0] - for(int i = 0; iqdcount); i++) - { - //sanity check - if(dnsData >= kextMsg+sizeof(kextMsg)) - { - //not valid - validPacket = NO; - - break; - } - - //skip over URL - // look for NULL terminator - while(*dnsData++); - - //skip question type - dnsData += sizeof(unsigned short); - - //skip question class - dnsData += sizeof(unsigned short); - - } - - //invalid? - if(YES != validPacket) - { - //skip - continue; - } - - //now, parse answers - // this is all we really care about - for(NSUInteger i = 0; i < ntohs(dnsHeader->ancount); i++) - { - //first byte indicates a pointer? - if(0xC0 != *dnsData++) - { - //not valid - validPacket = NO; - - break; - } - - //extract URL offset - urlOffset = *dnsData++ & 0xFF; - if(urlOffset >= bytesReceived) - { - //not valid - validPacket = NO; - - break; - } - - //extract URL - // pass in offset and end of packet - url = extractDNSURL((unsigned char*)dnsHeader + urlOffset, (unsigned char*)dnsHeader + bytesReceived); - if(0 == url.length) - { - //not valid - validPacket = NO; - - break; - } - - //dbg msg - //logMsg(LOG_DEBUG, [NSString stringWithFormat:@"extracted url: %@", url]); - - //extract address type - addressType = ntohs(*(unsigned short*)dnsData); - - //only accept A and AAAA - if( (0x1 != addressType) && - (0x1C != addressType) ) - { - //not valid - validPacket = NO; - - break; - } - - //skip over type - dnsData += sizeof(unsigned short); - - //skip class - dnsData += sizeof(unsigned short); - - //skip ttl - dnsData += sizeof(unsigned int); - - //type A - if(0x1 == addressType) - { - //length should be 4 - if(0x4 != ntohs(*(unsigned short*)dnsData)) - { - //not valid - validPacket = NO; - - break; - } - - //skip over length - dnsData += sizeof(unsigned short); - - //covert - ipAddress = convertIPAddr(dnsData, AF_INET); - - //skip over IP address - // for IPv4 addresses, this will always be 4 - dnsData += 0x4; - } - - //type AAAA - if(0x1C == addressType) - { - //length should be 0x10 - if(0x10 != ntohs(*(unsigned short*)dnsData)) - { - //not valid - validPacket = NO; - - break; - } - - //skip over length - dnsData += sizeof(unsigned short); - - //convert - ipAddress = convertIPAddr(dnsData, AF_INET6); - - //skip over IP address - // for IPv4 addresses, this will always be 0x10 - dnsData += 0x10; - } - - //add to DNS 'cache' - if(0 != ipAddress.length) - { - //dbg msg - logMsg(LOG_DEBUG, [NSString stringWithFormat:@"adding %@ -> %@ to DNS 'cache'", url, ipAddress]); - - //add - self.dnsCache[ipAddress] = url; - } - - }//parse answers - - //invalid? - if(YES != validPacket) - { - //skip - continue; - } - - }//while(YES) - -bail: - - //close socket - if(-1 != systemSocket) - { - //close - close(systemSocket); - - //unset - systemSocket = -1; - } - - return; -} - - //process events from the kernel (queue) // based on code from Singh's 'Mac OS X Internals' pp. 1466 -(void)processEvents @@ -586,15 +245,6 @@ -(void)processEvents //size of data item on queue UInt32 eventSize = 0; - //alert info - NSMutableDictionary* alert = nil; - - //process obj - Process* process = nil; - - //matching rule obj - Rule* matchingRule = nil; - //init size of data item on queue eventSize = sizeof(firewallEvent); @@ -655,106 +305,29 @@ -(void)processEvents } //dbg msg - logMsg(LOG_DEBUG, [NSString stringWithFormat:@"event from kernel queue: %d / %@", event.pid, convertSocketAddr((struct sockaddr*)&(event.remoteAddress))]); + logMsg(LOG_DEBUG, [NSString stringWithFormat:@"dequeued new firewall event from kernel (type: %d)", event.genericEvent.type]); - //ignore if alert has already been shown for this process - // if rule is deleted or process ends, this will be reset - if(YES == [self.alerts containsObject:[NSNumber numberWithUnsignedShort:event.pid]]) + //parse/handle event + switch(event.genericEvent.type) { - //dbg msg - logMsg(LOG_DEBUG, [NSString stringWithFormat:@"alert already shown for this process (%d), so ignoring", event.pid]); - - //next - continue; - } - - //nap a bit - // ->for a processes fork/exec, this should process monitor time to register exec event - [NSThread sleepForTimeInterval:0.5f]; - - //try find process via process monitor - // waits up to one second, since sometime delay in process events - process = [self findProcess:event.pid]; - if(nil == process) - { - //dbg msg - logMsg(LOG_DEBUG, [NSString stringWithFormat:@"couldn't find process (%d) in process monitor", event.pid]); - - //couldn't find proc - // ->did it die already? - if(YES != isProcessAlive(event.pid)) - { - //dbg msg - logMsg(LOG_DEBUG, @"process is dead, so ignoring"); + //network out events + case EVENT_NETWORK_OUT: - //next - continue; - } - - //manually create process obj - process = [[Process alloc] init:event.pid]; - } - - //check again - // ->should have a process obj now - if(nil == process) - { - //err msg - logMsg(LOG_ERR, [NSString stringWithFormat:@"failed to find and/or create process object for %d", event.pid]); - - //ignore - // ->not sure what else to do - continue; - } - - //existing rule for process (path)? - // TODO: pass in process obj to also validate signature & user - matchingRule = [rules find:process.path]; - if(nil != matchingRule) - { - //dbg msg - logMsg(LOG_DEBUG, [NSString stringWithFormat:@"found matching rule: %@\n", matchingRule]); - - //tell kernel to add rule for this process - [kextComms addRule:event.pid action:matchingRule.action.unsignedIntValue]; - } - - //process doesn't (yet) have a rule - // if there is an active/enable client, send alert to display/ask user - else - { - //no clients || client disabled - // default to allow process out... - if( (STATUS_CLIENT_DISABLED == clientStatus) || - (STATUS_CLIENT_UNKNOWN == clientStatus) ) - { - //dbg msg - // also log to file - logMsg(LOG_DEBUG|LOG_TO_FILE, @"no active (enabled) client, so telling kernel to 'allow'"); + //process + [self processNetworkOut:&event.networkOutEvent]; + break; - //allow - [kextComms addRule:event.pid action:RULE_STATE_ALLOW]; - } - - //client is active/enabled - // queue up alert to trigger delivery to client - else - { - //create alert - alert = [self createAlert:&event process:process]; - - //dbg msg - logMsg(LOG_DEBUG, [NSString stringWithFormat:@"no rule found, adding alert to queue: %@", alert]); + //dns response events + case EVENT_DNS_RESPONSE: - //add to global queue - // ->this will trigger processing of alert - [eventQueue enqueue:alert]; + //process + [self processDNSResponse:&event.dnsResponseEvent]; + break; - //note the fact that an alert was shown for this process - [self.alerts addObject:[NSNumber numberWithUnsignedShort:event.pid]]; - } + default: + break; } - + } //IODataQueueDataAvailable } //IODataQueueWaitForAvailableData @@ -793,6 +366,296 @@ -(void)processEvents return; } +//process a network out event from the kernel +// if there is no matching rule, will tell client to show alert +-(void)processNetworkOut:(struct networkOutEvent_s*)event +{ + //alert info + NSMutableDictionary* alert = nil; + + //process obj + Process* process = nil; + + //matching rule obj + Rule* matchingRule = nil; + + //dbg msg + logMsg(LOG_DEBUG, [NSString stringWithFormat:@"processing 'network out' event from kernel queue: %d / %@", event->pid, convertSocketAddr((struct sockaddr*)&(event->remoteAddress))]); + + //ignore if alert has already been shown for this process + // if rule is deleted or process ends, this will be reset + if(YES == [self.alerts containsObject:[NSNumber numberWithUnsignedShort:event->pid]]) + { + //dbg msg + logMsg(LOG_DEBUG, [NSString stringWithFormat:@"alert already shown for this process (%d), so ignoring", event->pid]); + + //bail + goto bail; + } + + //nap a bit + // ->for a processes fork/exec, this should process monitor time to register exec event + [NSThread sleepForTimeInterval:0.5f]; + + //try find process via process monitor + // waits up to one second, since sometime delay in process events + process = [self findProcess:event->pid]; + if(nil == process) + { + //dbg msg + logMsg(LOG_DEBUG, [NSString stringWithFormat:@"couldn't find process (%d) in process monitor", event->pid]); + + //couldn't find proc + // ->did it die already? + if(YES != isProcessAlive(event->pid)) + { + //dbg msg + logMsg(LOG_DEBUG, @"process is dead, so ignoring"); + + //bail + goto bail; + } + + //manually create process obj + process = [[Process alloc] init:event->pid]; + } + + //check again + // ->should have a process obj now + if(nil == process) + { + //err msg + logMsg(LOG_ERR, [NSString stringWithFormat:@"failed to find and/or create process object for %d", event->pid]); + + //bail + // not sure what else to do + goto bail; + } + + //existing rule for process (path)? + // TODO: pass in process obj to also validate signature & user + matchingRule = [rules find:process.path]; + if(nil != matchingRule) + { + //dbg msg + logMsg(LOG_DEBUG, [NSString stringWithFormat:@"found matching rule: %@\n", matchingRule]); + + //tell kernel to add rule for this process + [kextComms addRule:event->pid action:matchingRule.action.unsignedIntValue]; + } + + //process doesn't (yet) have a rule + // if there is an active/enable client, send alert to display/ask user + else + { + //no clients || client disabled + // default to allow process out... + if( (STATUS_CLIENT_DISABLED == clientStatus) || + (STATUS_CLIENT_UNKNOWN == clientStatus) ) + { + //dbg msg + // also log to file + logMsg(LOG_DEBUG|LOG_TO_FILE, @"no active (enabled) client, so telling kernel to 'allow'"); + + //allow + [kextComms addRule:event->pid action:RULE_STATE_ALLOW]; + } + + //client is active/enabled + // queue up alert to trigger delivery to client + else + { + //create alert + alert = [self createAlert:event process:process]; + + //dbg msg + logMsg(LOG_DEBUG, [NSString stringWithFormat:@"no rule found, adding alert to queue: %@", alert]); + + //add to global queue + // ->this will trigger processing of alert + [eventQueue enqueue:alert]; + + //note the fact that an alert was shown for this process + [self.alerts addObject:[NSNumber numberWithUnsignedShort:event->pid]]; + } + } + +bail: + + return; +} + +//process a network out event from the kernel +// if there is no matching rule, will tell client to show alert +-(void)processDNSResponse:(struct dnsResponseEvent_s*)event +{ + //dns header + struct dnsHeader* dnsHeader = NULL; + + //dns data + unsigned char* dnsData = NULL; + + //offset to URL + NSUInteger urlOffset = 0; + + //URL + NSMutableString* url = nil; + + //type + // A, AAAA + unsigned short addressType = 0; + + //ip address + NSString* ipAddress = nil; + + //dbg msg + logMsg(LOG_DEBUG, [NSString stringWithFormat:@"LULU processing 'dns response' event from kernel"]); + + //type cast + dnsHeader = (struct dnsHeader*)event->response; + + //print out dns response + /* + for(int i = 0; iresponse); i++) + logMsg(LOG_DEBUG, [NSString stringWithFormat:@"%d/%02x", i, event->response[i] & 0xFF]); + */ + + //init pointer to DNS data + // begins right after (fixed) DNS header + dnsData = (unsigned char*)((unsigned char*)dnsHeader + sizeof(struct dnsHeader)); + + //skip over any question entries + // they should always come first, ya? + for(NSUInteger i = 0; i < ntohs(dnsHeader->qdcount); i++) + { + //sanity check + if(dnsData >= event->response+sizeof(event->response)) + { + //bail + goto bail; + } + + //skip over URL + // look for NULL terminator + while(*dnsData++); + + //skip question type + dnsData += sizeof(unsigned short); + + //skip question class + dnsData += sizeof(unsigned short); + } + + //now, parse answers + // this is all we really care about + for(NSUInteger i = 0; i < ntohs(dnsHeader->ancount); i++) + { + //first byte indicates a pointer? + if(0xC0 != *dnsData++) + { + //bail + goto bail; + } + + //extract URL offset + urlOffset = *dnsData++ & 0xFF; + if(urlOffset >= sizeof(event->response)) + { + //bail + goto bail; + } + + //extract URL + // pass in offset and end of packet + url = extractDNSURL((unsigned char*)dnsHeader + urlOffset, (unsigned char*)dnsHeader + sizeof(event->response)); + if(0 == url.length) + { + //bail + goto bail; + } + + //dbg msg + //logMsg(LOG_DEBUG, [NSString stringWithFormat:@"extracted url: %@", url]); + + //extract address type + addressType = ntohs(*(unsigned short*)dnsData); + + //only accept A and AAAA + if( (0x1 != addressType) && + (0x1C != addressType) ) + { + //bail + goto bail; + } + + //skip over type + dnsData += sizeof(unsigned short); + + //skip class + dnsData += sizeof(unsigned short); + + //skip ttl + dnsData += sizeof(unsigned int); + + //type A + if(0x1 == addressType) + { + //length should be 4 + if(0x4 != ntohs(*(unsigned short*)dnsData)) + { + //bail + goto bail; + } + + //skip over length + dnsData += sizeof(unsigned short); + + //covert + ipAddress = convertIPAddr(dnsData, AF_INET); + + //skip over IP address + // for IPv4 addresses, this will always be 4 + dnsData += 0x4; + } + + //type AAAA + if(0x1C == addressType) + { + //length should be 0x10 + if(0x10 != ntohs(*(unsigned short*)dnsData)) + { + //bail + goto bail; + } + + //skip over length + dnsData += sizeof(unsigned short); + + //convert + ipAddress = convertIPAddr(dnsData, AF_INET6); + + //skip over IP address + // for IPv4 addresses, this will always be 0x10 + dnsData += 0x10; + } + + //add to DNS 'cache' + if(0 != ipAddress.length) + { + //dbg msg + logMsg(LOG_DEBUG, [NSString stringWithFormat:@"adding %@ -> %@ to DNS 'cache'", url, ipAddress]); + + //add + self.dnsCache[ipAddress] = url; + } + + }//parse answers + +bail: + + return; +} + //remove process from list of alerts -(void)resetAlert:(pid_t)pid { @@ -831,7 +694,8 @@ -(Process*)findProcess:(pid_t)pid } //create an alert object --(NSMutableDictionary*)createAlert:(firewallEvent*)event process:(Process*)process +// note: can treat sockaddr_in and sockaddr_in6 as 'same same' for family, port, etc +-(NSMutableDictionary*)createAlert:(struct networkOutEvent_s*)event process:(Process*)process { //event for alert NSMutableDictionary* alertInfo = nil; @@ -872,9 +736,9 @@ -(NSMutableDictionary*)createAlert:(firewallEvent*)event process:(Process*)proce alertInfo[ALERT_HOSTNAME] = remoteHost; } } - + //add (remote) port - alertInfo[ALERT_PORT] = [NSNumber numberWithUnsignedShort:ntohs(event->remoteAddress.sin_port)]; + alertInfo[ALERT_PORT] = [NSNumber numberWithUnsignedShort:ntohs(event->remoteAddress.sin6_port)]; //add protocol (socket type) alertInfo[ALERT_PROTOCOL] = [NSNumber numberWithInt:event->socketType]; diff --git a/launchDaemon/launchDaemon/Rules.h b/launchDaemon/launchDaemon/Rules.h index 6896e2b..8495c6b 100644 --- a/launchDaemon/launchDaemon/Rules.h +++ b/launchDaemon/launchDaemon/Rules.h @@ -44,7 +44,6 @@ -(BOOL)add:(NSString*)path action:(NSUInteger)action type:(NSUInteger)type user:(NSUInteger)user; //add to kernel -// TOOD: check hash, etc -(void)addToKernel:(Rule*)rule; //delete rule diff --git a/launchDaemon/launchDaemon/Rules.m b/launchDaemon/launchDaemon/Rules.m index 015c777..b765adc 100644 --- a/launchDaemon/launchDaemon/Rules.m +++ b/launchDaemon/launchDaemon/Rules.m @@ -125,18 +125,6 @@ -(BOOL)save // TODO: note: in the future, the installer will control this more, like whether to skip, baseline only apple apps, etc -(void)startBaselining { - //check if baselining was already done - // this is done by seeing if there are any rules w/ type 'baseline' - for(NSString* path in self.rules.allKeys) - { - //baseline rule? - if(RULE_TYPE_BASELINE == ((Rule*)self.rules[path]).type.intValue) - { - //bail - goto bail; - } - } - //dbg msg logMsg(LOG_DEBUG, @"generating 'allow' rules for all existing applications"); @@ -257,9 +245,9 @@ -(Rule*)find:(NSString*)path } } - //TOOD: validate binary still matches hash + //TODO: validate binary still matches hash - //TOOD: check that rule is for this user! + //TODO: check that rule is for this user! bail: @@ -299,7 +287,8 @@ -(BOOL)add:(NSString*)path action:(NSUInteger)action type:(NSUInteger)type user: [self save]; } - //tell kernel to add + //for any other process + // tell kernel to add rule [self addToKernel:rule]; //happy @@ -311,7 +300,7 @@ -(BOOL)add:(NSString*)path action:(NSUInteger)action type:(NSUInteger)type user: } //add to kernel -// TOOD: check hash, etc +// TODO: check hash, etc -(void)addToKernel:(Rule*)rule { //find processes and add diff --git a/launchDaemon/launchDaemon/UserComms.m b/launchDaemon/launchDaemon/UserComms.m index 7072d71..f16108c 100644 --- a/launchDaemon/launchDaemon/UserComms.m +++ b/launchDaemon/launchDaemon/UserComms.m @@ -98,7 +98,7 @@ -(void)setClientStatus:(NSInteger)status //get rules // optionally wait (blocks) for change --(void)getRules:(BOOL)wait4Change reply:(void (^)(NSDictionary*))reply; +-(void)getRules:(BOOL)wait4Change reply:(void (^)(NSDictionary*))reply { //dbg msg logMsg(LOG_DEBUG, @"XPC request: GET RULES"); @@ -171,11 +171,14 @@ -(void)deleteRule:(NSString*)path } //import rules --(void)importRules:(NSString*)rulesFile +-(void)importRules:(NSString*)rulesFile reply:(void (^)(BOOL))reply { //error NSError* error = nil; + //flag + BOOL importedRules = NO; + //dbg msg logMsg(LOG_DEBUG, [NSString stringWithFormat:@"XPC request: IMPORT RULES (%@)", rulesFile]); @@ -220,11 +223,17 @@ -(void)importRules:(NSString*)rulesFile } } + //happy + importedRules = YES; + //signal all threads that rules changed while(0 != dispatch_semaphore_signal(rulesChanged)); bail: + //return rules + reply(importedRules); + return; } @@ -305,9 +314,14 @@ -(void)alertResponse:(NSMutableDictionary*)alert // TODO: add support for 'user' [kextComms addRule:pid action:action]; - //update rules - // ->type is 'user' - [rules add:path action:action type:RULE_TYPE_USER user:user]; + //don't add a permanent rule if it was passively allowed + if( (nil == alert[ALERT_PASSIVELY_ALLOWED]) || + (YES != [alert[ALERT_PASSIVELY_ALLOWED] boolValue]) ) + { + //update rules + // ->type is 'user' + [rules add:path action:action type:RULE_TYPE_USER user:user]; + } //signal all threads that rules changed while(0 != dispatch_semaphore_signal(rulesChanged)); diff --git a/launchDaemon/launchDaemon/libs/libprocInfo.a b/launchDaemon/launchDaemon/libs/libprocInfo.a index c577a8c..07374d8 100644 Binary files a/launchDaemon/launchDaemon/libs/libprocInfo.a and b/launchDaemon/launchDaemon/libs/libprocInfo.a differ diff --git a/launchDaemon/launchDaemon/main.m b/launchDaemon/launchDaemon/main.m index 1445a32..4b0621b 100644 --- a/launchDaemon/launchDaemon/main.m +++ b/launchDaemon/launchDaemon/main.m @@ -44,7 +44,7 @@ //init a handler for SIGTERM // can perform actions such as disabling firewall and closing logging -void register4Shutdown(); +void register4Shutdown(void); //main // init & kickoff stuffz @@ -52,12 +52,30 @@ int main(int argc, const char * argv[]) { @autoreleasepool { + //flag for first time running + BOOL firstRun = NO; + + //log file path + NSString* logPath = nil; + //user comms listener (XPC) obj UserCommsListener* userCommsListener = nil; //dbg msg logMsg(LOG_DEBUG, @"launch daemon started"); + //init log path + // '/Library/Logs/Lulu.log' + logPath = [@"/Library/Logs/" stringByAppendingPathComponent:LOG_FILE_NAME]; + + //set 'first run' flag + // log file not present is the indicator for this + if(YES != [[NSFileManager defaultManager] fileExistsAtPath:logPath]) + { + //set flag + firstRun = YES; + } + //alloc/init kernel comms object kextComms = [[KextComms alloc] init]; @@ -65,7 +83,7 @@ int main(int argc, const char * argv[]) processListener = [[ProcessListener alloc] init]; //init logging - if(YES != initLogging()) + if(YES != initLogging(logPath)) { //err msg logMsg(LOG_ERR, @"failed to init logging"); @@ -105,11 +123,15 @@ int main(int argc, const char * argv[]) //dbg msg logMsg(LOG_DEBUG, [NSString stringWithFormat:@"loaded rules from %@", RULES_FILE]); - - //add default/pre-existing apps - // has logic to only do this first time - [rules startBaselining]; - + + //first run? + // add default/pre-existing apps + if(YES == firstRun) + { + //baseline + [rules startBaselining]; + } + //init rule changed semaphore rulesChanged = dispatch_semaphore_create(0); diff --git a/launchDaemon/launchDaemon/procInfo.h b/launchDaemon/launchDaemon/procInfo.h old mode 100755 new mode 100644 index 779bd76..f876ee6 --- a/launchDaemon/launchDaemon/procInfo.h +++ b/launchDaemon/launchDaemon/procInfo.h @@ -32,7 +32,7 @@ /* TYPEDEFS */ //block for library -typedef void (^ProcessCallbackBlock)(Process*); +typedef void (^ProcessCallbackBlock)(Process* _Nonnull); /* OBJECT: PROCESS INFO */ @@ -40,13 +40,13 @@ typedef void (^ProcessCallbackBlock)(Process*); @interface ProcInfo : NSObject //start monitoring --(BOOL)start:(ProcessCallbackBlock)callback; +-(BOOL)start:(ProcessCallbackBlock _Nonnull )callback; //stop monitoring -(void)stop; //get list of running processes --(NSMutableArray*)currentProcesses; +-(NSMutableArray* _Nonnull)currentProcesses; @end @@ -63,7 +63,7 @@ typedef void (^ProcessCallbackBlock)(Process*); @property pid_t ppid; //user id -@property uid_t user; +@property uid_t uid; //type // used by process mon @@ -73,26 +73,26 @@ typedef void (^ProcessCallbackBlock)(Process*); @property u_int32_t exit; //path -@property (nonatomic, retain) NSString* path; +@property (nonatomic, retain) NSString* _Nullable path; //args -@property (nonatomic, retain) NSMutableArray* arguments; +@property (nonatomic, retain) NSMutableArray* _Nonnull arguments; //ancestors -@property (nonatomic, retain) NSMutableArray* ancestors; +@property (nonatomic, retain) NSMutableArray* _Nonnull ancestors; //Binary object -// ->has path, hash, etc -@property (nonatomic, retain) Binary* binary; +// has path, hash, etc +@property (nonatomic, retain) Binary* _Nonnull binary; //timestamp -@property (nonatomic, retain) NSDate* timestamp; +@property (nonatomic, retain) NSDate* _Nonnull timestamp; /* METHODS */ //init with a pid -// ->method will then (try) fill out rest of object --(id)init:(pid_t)processID; +// method will then (try) fill out rest of object +-(id _Nullable )init:(pid_t)processID; //set process's path -(void)pathFromPid; @@ -115,16 +115,23 @@ typedef void (^ProcessCallbackBlock)(Process*); /* PROPERTIES */ //path -@property (nonatomic, retain)NSString* path; +@property (nonatomic, retain)NSString* _Nonnull path; //name -@property (nonatomic, retain)NSString* name; +@property (nonatomic, retain)NSString* _Nonnull name; + +//icon +@property (nonatomic, retain)NSImage* _Nonnull icon; //file attributes -@property (nonatomic, retain)NSDictionary* attributes; +@property (nonatomic, retain)NSDictionary* _Nullable attributes; + +//bundle +// nil for non-apps +@property (nonatomic, retain)NSBundle* _Nullable bundle; //signing info -@property (nonatomic, retain)NSDictionary* signingInfo; +@property (nonatomic, retain)NSDictionary* _Nonnull signingInfo; //flag indicating binary belongs to Apple OS @property BOOL isApple; @@ -135,7 +142,7 @@ typedef void (^ProcessCallbackBlock)(Process*); /* METHODS */ //init w/ an info dictionary --(id)init:(NSString*)path; +-(id _Nonnull )init:(NSString* _Nonnull)path; @end diff --git a/loginItem/loginItem.xcodeproj/project.pbxproj b/loginItem/loginItem.xcodeproj/project.pbxproj index 057f6ab..9bc5d75 100644 --- a/loginItem/loginItem.xcodeproj/project.pbxproj +++ b/loginItem/loginItem.xcodeproj/project.pbxproj @@ -14,7 +14,7 @@ 7D3B75151F13354900568828 /* MainMenu.xib in Resources */ = {isa = PBXBuildFile; fileRef = 7D3B75011F13354900568828 /* MainMenu.xib */; }; 7D3B751A1F13354900568828 /* statusIcon.png in Resources */ = {isa = PBXBuildFile; fileRef = 7D3B750B1F13354900568828 /* statusIcon.png */; }; 7D3B751B1F13354900568828 /* statusIcon@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = 7D3B750C1F13354900568828 /* statusIcon@2x.png */; }; - 7D3B75251F13357D00568828 /* logging.m in Sources */ = {isa = PBXBuildFile; fileRef = 7D3B75231F13357D00568828 /* logging.m */; }; + 7D3B75251F13357D00568828 /* Logging.m in Sources */ = {isa = PBXBuildFile; fileRef = 7D3B75231F13357D00568828 /* Logging.m */; }; 7D46FF111F60EBAE00FEB0F8 /* luluText.png in Resources */ = {isa = PBXBuildFile; fileRef = 7D46FF0F1F60EBAE00FEB0F8 /* luluText.png */; }; 7D46FF121F60EBAE00FEB0F8 /* luluIcon.png in Resources */ = {isa = PBXBuildFile; fileRef = 7D46FF101F60EBAE00FEB0F8 /* luluIcon.png */; }; 7D5C5F521F200B9200C0E94A /* Utilities.m in Sources */ = {isa = PBXBuildFile; fileRef = 7D5C5F511F200B9200C0E94A /* Utilities.m */; }; @@ -54,9 +54,9 @@ 7D3B750B1F13354900568828 /* statusIcon.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = statusIcon.png; sourceTree = ""; }; 7D3B750C1F13354900568828 /* statusIcon@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "statusIcon@2x.png"; sourceTree = ""; }; 7D3B75211F13357D00568828 /* userCommsInterface.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = userCommsInterface.h; path = ../shared/userCommsInterface.h; sourceTree = ""; }; - 7D3B75221F13357D00568828 /* const.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = const.h; path = ../shared/const.h; sourceTree = ""; }; - 7D3B75231F13357D00568828 /* logging.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = logging.m; path = ../shared/logging.m; sourceTree = ""; }; - 7D3B75241F13357D00568828 /* logging.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = logging.h; path = ../shared/logging.h; sourceTree = ""; }; + 7D3B75221F13357D00568828 /* Const.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = Const.h; path = ../shared/Const.h; sourceTree = ""; }; + 7D3B75231F13357D00568828 /* Logging.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = Logging.m; path = ../shared/Logging.m; sourceTree = ""; }; + 7D3B75241F13357D00568828 /* Logging.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = Logging.h; path = ../shared/Logging.h; sourceTree = ""; }; 7D46FF061F5F6CAB00FEB0F8 /* LuLu Helper.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; name = "LuLu Helper.entitlements"; path = "loginItem/LuLu Helper.entitlements"; sourceTree = ""; }; 7D46FF0F1F60EBAE00FEB0F8 /* luluText.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = luluText.png; sourceTree = ""; }; 7D46FF101F60EBAE00FEB0F8 /* luluIcon.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = luluIcon.png; sourceTree = ""; }; @@ -149,9 +149,9 @@ 7DD2BF781F1EAC9C00B33214 /* DaemonComms.h */, 7DD2BF791F1EAC9C00B33214 /* DaemonComms.m */, 7D3B75211F13357D00568828 /* userCommsInterface.h */, - 7D3B75221F13357D00568828 /* const.h */, - 7D3B75231F13357D00568828 /* logging.m */, - 7D3B75241F13357D00568828 /* logging.h */, + 7D3B75221F13357D00568828 /* Const.h */, + 7D3B75231F13357D00568828 /* Logging.m */, + 7D3B75241F13357D00568828 /* Logging.h */, ); name = shared; sourceTree = ""; @@ -247,7 +247,7 @@ 7D7755DB1F02E05B00D0017D /* Project object */ = { isa = PBXProject; attributes = { - LastUpgradeCheck = 0820; + LastUpgradeCheck = 0900; ORGANIZATIONNAME = "Objective-See"; TargetAttributes = { 7D7755E21F02E05B00D0017D = { @@ -318,7 +318,7 @@ 7D3B75141F13354900568828 /* StatusBarMenu.m in Sources */, 7D7755EB1F02E05B00D0017D /* main.m in Sources */, 7DD260131F25307B00277EC4 /* HyperlinkTextField.m in Sources */, - 7D3B75251F13357D00568828 /* logging.m in Sources */, + 7D3B75251F13357D00568828 /* Logging.m in Sources */, 7DD2600F1F252E8C00277EC4 /* VirusTotalViewController.m in Sources */, 7D5C5F521F200B9200C0E94A /* Utilities.m in Sources */, 7D7755E81F02E05B00D0017D /* AppDelegate.m in Sources */, @@ -362,7 +362,9 @@ CLANG_CXX_LIBRARY = "libc++"; CLANG_ENABLE_MODULES = YES; CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; CLANG_WARN_CONSTANT_CONVERSION = YES; CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; CLANG_WARN_DOCUMENTATION_COMMENTS = YES; @@ -370,7 +372,11 @@ CLANG_WARN_ENUM_CONVERSION = YES; CLANG_WARN_INFINITE_RECURSION = YES; CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; CLANG_WARN_SUSPICIOUS_MOVE = YES; CLANG_WARN_UNREACHABLE_CODE = YES; CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; @@ -393,7 +399,7 @@ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; - MACOSX_DEPLOYMENT_TARGET = 10.12; + MACOSX_DEPLOYMENT_TARGET = 10.10; MTL_ENABLE_DEBUG_INFO = YES; ONLY_ACTIVE_ARCH = YES; SDKROOT = macosx; @@ -409,7 +415,9 @@ CLANG_CXX_LIBRARY = "libc++"; CLANG_ENABLE_MODULES = YES; CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; CLANG_WARN_CONSTANT_CONVERSION = YES; CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; CLANG_WARN_DOCUMENTATION_COMMENTS = YES; @@ -417,7 +425,11 @@ CLANG_WARN_ENUM_CONVERSION = YES; CLANG_WARN_INFINITE_RECURSION = YES; CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; CLANG_WARN_SUSPICIOUS_MOVE = YES; CLANG_WARN_UNREACHABLE_CODE = YES; CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; @@ -434,7 +446,7 @@ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; - MACOSX_DEPLOYMENT_TARGET = 10.12; + MACOSX_DEPLOYMENT_TARGET = 10.10; MTL_ENABLE_DEBUG_INFO = NO; SDKROOT = macosx; }; @@ -450,6 +462,7 @@ DEVELOPMENT_TEAM = VBG97UB4TA; INFOPLIST_FILE = loginItem/Info.plist; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks"; + OTHER_CODE_SIGN_FLAGS = ""; PRODUCT_BUNDLE_IDENTIFIER = "com.objective-see.luluHelper"; PRODUCT_NAME = "LuLu Helper"; }; @@ -465,6 +478,8 @@ DEVELOPMENT_TEAM = VBG97UB4TA; INFOPLIST_FILE = loginItem/Info.plist; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks"; + OTHER_CODE_SIGN_FLAGS = "-o hard,kill"; + OTHER_LDFLAGS = "-Wl,-sectcreate,__RESTRICT,__restrict,/dev/null"; PRODUCT_BUNDLE_IDENTIFIER = "com.objective-see.luluHelper"; PRODUCT_NAME = "LuLu Helper"; }; diff --git a/loginItem/loginItem/AlertMonitor.h b/loginItem/loginItem/AlertMonitor.h index 39c6f28..ec87fd9 100644 --- a/loginItem/loginItem/AlertMonitor.h +++ b/loginItem/loginItem/AlertMonitor.h @@ -27,4 +27,11 @@ // ->wait for & display alerts -(void)monitor; +//when client is in passive mode: allow +-(void)passivelyAllow:(DaemonComms*)daemonComms alert:(NSDictionary*)alert; + +//callback handler +// ->invoked when window closes +-(void)alertWindowClosed:(id)object; + @end diff --git a/loginItem/loginItem/AlertMonitor.m b/loginItem/loginItem/AlertMonitor.m index e799609..0425e74 100644 --- a/loginItem/loginItem/AlertMonitor.m +++ b/loginItem/loginItem/AlertMonitor.m @@ -7,6 +7,7 @@ // copyright (c) 2017 Objective-See. All rights reserved. // +#import "const.h" #import "logging.h" #import "AppDelegate.h" #import "DaemonComms.h" @@ -28,65 +29,128 @@ -(void)monitor // use local var here, as we need to block daemonComms = [[DaemonComms alloc] init]; + //passive flag + __block BOOL inPassiveMode = NO; + //init sema self.semaphore = dispatch_semaphore_create(0); //process alerts - // ->call daemon and block, then display, and repeat! + // call daemon and block, then display, and repeat! while(YES) { + //pool + @autoreleasepool + { + //dbg msg logMsg(LOG_DEBUG, @"requesting alert from daemon, will block"); //wait for alert from daemon via XPC [daemonComms alertRequest:^(NSDictionary* alert) - { + { //dbg msg logMsg(LOG_DEBUG, [NSString stringWithFormat:@"got alert from daemon: %@", alert]); - //show alert window on main thread - dispatch_async(dispatch_get_main_queue(), ^{ + //set flag + // is client in passive mode? + inPassiveMode = [[[NSUserDefaults alloc] initWithSuiteName:@"group.com.objective-see.lulu"] boolForKey:PREF_PASSIVE_MODE]; + //passive mode? + // don't show alert, just respond w/ allow + if(YES == inPassiveMode) + { //dbg msg - logMsg(LOG_DEBUG, [NSString stringWithFormat:@"showing window for alert: %@", alert]); - - //alloc - if(nil == self.alertWindow) - { - alertWindow = [[AlertWindowController alloc] initWithWindowNibName:@"AlertWindow"]; - } - - //configure alert window with data from daemon - self.alertWindow.alert = alert; - - //show (now configured), alert - [self.alertWindow showWindow:self]; + // also log to file + logMsg(LOG_DEBUG|LOG_TO_FILE, @"client in passive mode, so telling daemon just to 'allow'"); - //make it key window - [self.alertWindow.window makeKeyAndOrderFront:self]; + //passively allow + [self passivelyAllow:daemonComms alert:alert]; - //make window front - [NSApp activateIgnoringOtherApps:YES]; + //signal alert is processed + dispatch_semaphore_signal(self.semaphore); + } - //register for close event - // callback will signal semaphore - [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(alertWindowClosed:) name:NSWindowWillCloseNotification object:self.alertWindow.window]; - - }); - + //show alert + else + { + //show alert window on main thread + dispatch_async(dispatch_get_main_queue(), ^{ + + //dbg msg + logMsg(LOG_DEBUG, [NSString stringWithFormat:@"showing window for alert: %@", alert]); + + //alloc/init + if(nil == self.alertWindow) + { + //alloc/init + alertWindow = [[AlertWindowController alloc] initWithWindowNibName:@"AlertWindow"]; + } + + //configure alert window with data from daemon + self.alertWindow.alert = alert; + + //show (now configured), alert + [self.alertWindow showWindow:self]; + + //make it key window + [self.alertWindow.window makeKeyAndOrderFront:self]; + + //make window front + [NSApp activateIgnoringOtherApps:YES]; + + //register for close event + // callback will signal semaphore + [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(alertWindowClosed:) name:NSWindowWillCloseNotification object:self.alertWindow.window]; + + }); + } }]; - //wait for alert window to close + //wait for alert to be processed dispatch_semaphore_wait(self.semaphore, DISPATCH_TIME_FOREVER); - //show alert window on main thread - dispatch_sync(dispatch_get_main_queue(), ^{ + //alert shown? + // unregister window notification + if(YES != inPassiveMode) + { + //remove notification watch + dispatch_sync(dispatch_get_main_queue(), ^{ - //remove notification observer - [[NSNotificationCenter defaultCenter] removeObserver: self name: NSWindowWillCloseNotification object:self.alertWindow.window]; + //remove notification observer + [[NSNotificationCenter defaultCenter] removeObserver: self name: NSWindowWillCloseNotification object:self.alertWindow.window]; + + }); + } + + //pool + } - }); - } + }//forevers + + return; +} + +//when client is in passive mode: allow +-(void)passivelyAllow:(DaemonComms*)daemonComms alert:(NSDictionary*)alert +{ + //response + NSMutableDictionary* response = nil; + + //init response with initial alert + response = [NSMutableDictionary dictionaryWithDictionary:alert]; + + //add action, allow + response[ALERT_ACTION] = [NSNumber numberWithInt:RULE_STATE_ALLOW]; + + //add current user + response[ALERT_USER] = [NSNumber numberWithUnsignedInteger:getuid()]; + + //indicate that it was passively allowed + response[ALERT_PASSIVELY_ALLOWED] = [NSNumber numberWithBool:YES]; + + //send response to daemon + [daemonComms alertResponse:response]; return; } diff --git a/loginItem/loginItem/AlertWindow.xib b/loginItem/loginItem/AlertWindow.xib index a8632a8..a67e047 100644 --- a/loginItem/loginItem/AlertWindow.xib +++ b/loginItem/loginItem/AlertWindow.xib @@ -1,7 +1,6 @@ - @@ -30,25 +29,29 @@ - - - + + + + + - + - - - - - + - + + + + - - - - + + + + + + - - - - + + + + + + - - - + + + + + - + @@ -111,7 +125,7 @@ - + @@ -138,7 +152,7 @@ - + @@ -174,38 +188,48 @@ - + - - - - + + + + + + - - - - + + + + + + - + - - + + + + + - - + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -241,7 +295,7 @@ - + @@ -336,7 +390,6 @@ - diff --git a/loginItem/loginItem/AlertWindowController.h b/loginItem/loginItem/AlertWindowController.h index fbc270c..3eedd02 100644 --- a/loginItem/loginItem/AlertWindowController.h +++ b/loginItem/loginItem/AlertWindowController.h @@ -19,12 +19,6 @@ //alert info @property(nonatomic, retain)NSDictionary* alert; - -//@property(nonatomic, retain)VirusTotalViewController* popoverVC; - -//view controller for ancestry view/popover -@property (weak) IBOutlet ParentsWindowController *ancestryViewController; - /* TOP */ //process icon @@ -45,6 +39,9 @@ //popover for virus total @property (strong) IBOutlet NSPopover *virusTotalPopover; +//view controller for ancestry view/popover +@property (weak) IBOutlet ParentsWindowController *ancestryViewController; + //ancestry button @property (weak) IBOutlet NSButton *ancestryButton; @@ -71,10 +68,16 @@ //outline view in ancestry popover @property (weak) IBOutlet NSOutlineView *ancestryOutline; + +//text cell for ancestry popover @property (weak) IBOutlet NSTextFieldCell *ancestryTextCell; /* METHODS */ +//lulu allowed/blocked from talking to internet? +// will fact, will determine state of virus total button +-(void)setVTButtonState; + //automatically invoked when user clicks process ancestry button // ->depending on state, show/populate the popup, or close it -(IBAction)vtButtonHandler:(id)sender; diff --git a/loginItem/loginItem/AlertWindowController.m b/loginItem/loginItem/AlertWindowController.m index 0d3962a..5712862 100644 --- a/loginItem/loginItem/AlertWindowController.m +++ b/loginItem/loginItem/AlertWindowController.m @@ -7,6 +7,8 @@ // copyright (c) 2017 Objective-See. All rights reserved. // +//TODO: don't show popover if ancestors are nil? + #import #import "const.h" @@ -16,21 +18,17 @@ #import "DaemonComms.h" #import "AlertWindowController.h" -//TODO: -// maybe disable VT button if LuLu helper is not approved for network connections (as we only show one connection at a time) - @implementation AlertWindowController @synthesize alert; @synthesize signedIcon; @synthesize processIcon; @synthesize processName; +@synthesize ancestryButton; @synthesize ancestryPopover; @synthesize virusTotalButton; @synthesize virusTotalPopover; -@synthesize ancestryButton; - //center window // ->also, transparency -(void)awakeFromNib @@ -51,7 +49,7 @@ -(void)awakeFromNib } //update alert window -- (void)windowDidChangeOcclusionState:(NSNotification *)notification +-(void)windowDidChangeOcclusionState:(NSNotification *)notification { //remote addr NSString* remoteAddress = nil; @@ -81,10 +79,26 @@ - (void)windowDidChangeOcclusionState:(NSNotification *)notification //unset port & proto self.portProto.stringValue = @""; + //alert window maximized? + // unzoom to bring it back to its default size + if(YES == self.window.zoomed) + { + //reset width (horizontal) + [self.window.contentView addConstraints: [NSLayoutConstraint constraintsWithVisualFormat:@"H:|[window(0@745)]|" + options:0 metrics:nil views:NSDictionaryOfVariableBindings(self.window)]]; + } + + //make un-modal + //[[NSApplication sharedApplication] stopModal]; + //bail goto bail; } + //lulu allowed/blocked from talking to internet? + // will fact, will determine state of virus total button + [self setVTButtonState]; + //host name? if(nil != self.alert[ALERT_HOSTNAME]) { @@ -136,12 +150,27 @@ - (void)windowDidChangeOcclusionState:(NSNotification *)notification //make window front [NSApp activateIgnoringOtherApps:YES]; - + + //make modal + [[NSApplication sharedApplication] runModalForWindow:self.window]; + bail: return; } + +//window closing +// make sure we're unmodal +- (void)windowWillClose:(NSNotification *)notification +{ + //stop modal + [[NSApplication sharedApplication] stopModal]; + + return; +} + + //covert number protocol to name -(NSString*)convertProtocol { @@ -177,6 +206,49 @@ -(NSString*)convertProtocol return protocol; } +//lulu allowed/blocked from talking to internet? +// will fact, will determine state of virus total button +-(void)setVTButtonState +{ + //flag + __block BOOL shouldDisable = YES; + + //daemon comms object + DaemonComms* daemonComms = nil; + + //init daemom comms + daemonComms = [[DaemonComms alloc] init]; + + //get rules from daemon via XPC + [daemonComms getRules:NO reply:^(NSDictionary* daemonRules) + { + //look for an allow rule for lulu + for(NSString* processPath in daemonRules.allKeys) + { + //is allow rule, match us? + if( (YES == [processPath isEqualToString:NSProcessInfo.processInfo.arguments[0]]) && + (RULE_STATE_ALLOW == [[daemonRules[processPath] objectForKey:RULE_ACTION] intValue]) ) + { + + //dbg msg + logMsg(LOG_DEBUG, @"lulu/helper is allowed to access the network"); + + //ok there is a rule for lulu, allowing it + // thus, virus total can be queried (i.e. it won't be blocked) + shouldDisable = NO; + + //done + break; + } + } + + //set button state + self.virusTotalButton.enabled = !shouldDisable; + + }]; + + return; +} //set signing icon // TODO: maybe make this clickable/more info? (signing auths, etc) @@ -313,7 +385,6 @@ -(IBAction)ancestryButtonHandler:(id)sender self.ancestryViewController.processHierarchy = processHierarchy; //dynamically (re)size popover - // TODO: this needs some TLC [self setPopoverSize]; //reload it @@ -381,7 +452,7 @@ -(void)setPopoverSize //calculate width // ->first w/ indentation - currentRowWidth = [self.ancestryOutline indentationPerLevel] * i; + currentRowWidth = [self.ancestryOutline indentationPerLevel] * (i+1); //calculate width // ->then size of string in row @@ -453,7 +524,7 @@ -(IBAction)handleUserResponse:(id)sender response = [NSMutableDictionary dictionaryWithDictionary:self.alert]; //init daemon - // use local var here, as we need to block + // use local var here, as iVar blocks daemonComms = [[DaemonComms alloc] init]; //block diff --git a/loginItem/loginItem/StatusBarMenu.h b/loginItem/loginItem/StatusBarMenu.h index 65ab8bb..d145d80 100644 --- a/loginItem/loginItem/StatusBarMenu.h +++ b/loginItem/loginItem/StatusBarMenu.h @@ -29,5 +29,4 @@ //init -(id)init:(NSMenu*)menu; - @end diff --git a/loginItem/loginItem/VirusTotal.m b/loginItem/loginItem/VirusTotal.m index 7beec77..b008953 100755 --- a/loginItem/loginItem/VirusTotal.m +++ b/loginItem/loginItem/VirusTotal.m @@ -92,6 +92,9 @@ -(BOOL)queryVT:(NSMutableDictionary*)item //bail goto bail; } + + //dbg msg + logMsg(LOG_DEBUG, [NSString stringWithFormat:@"posting request (%@) to %@", queryURL, postData]); //make query to VT response = [self postRequest:queryURL postData:postData]; @@ -160,6 +163,9 @@ -(NSDictionary*)postRequest:(NSURL*)url postData:(NSData*)postData //send request [[[NSURLSession sharedSession] dataTaskWithRequest:request completionHandler:^(NSData* data, NSURLResponse* response, NSError* error) { + //dbg msg + logMsg(LOG_DEBUG, [NSString stringWithFormat:@"got response %lu", (long)((NSHTTPURLResponse *)response).statusCode]); + //sanity check(s) if( (nil != data) && (nil == error) && diff --git a/loginItem/loginItem/VirusTotalViewController.m b/loginItem/loginItem/VirusTotalViewController.m index b81b414..cbae81e 100644 --- a/loginItem/loginItem/VirusTotalViewController.m +++ b/loginItem/loginItem/VirusTotalViewController.m @@ -97,13 +97,8 @@ -(void)queryVT // ->also check for error (offline, etc) if(YES == [vtObj queryVT:item]) { - //update UI on main thread - dispatch_sync(dispatch_get_main_queue(), ^{ - - //update UI - [self displayResults:item]; - - }); + //modal window, so use 'performSelectorOnMainThread' to update + [self performSelectorOnMainThread:@selector(displayResults:) withObject:item waitUntilDone:YES]; } //error @@ -112,13 +107,8 @@ -(void)queryVT //err msg logMsg(LOG_ERR, [NSString stringWithFormat:@"failed to query virus total: %@", item]); - //show error on main thread - dispatch_sync(dispatch_get_main_queue(), ^{ - - //show error - [self showError]; - - }); + //modal window, so use 'performSelectorOnMainThread' to update + [self performSelectorOnMainThread:@selector(showError) withObject:nil waitUntilDone:YES]; } bail: @@ -140,7 +130,7 @@ -(void)displayResults:(NSMutableDictionary*)item //hide spinner self.vtSpinner.hidden = YES; - + // [self.message setAllowsEditingTextAttributes: YES]; [self.message setSelectable: YES]; diff --git a/lulu.xcworkspace/contents.xcworkspacedata b/lulu.xcworkspace/contents.xcworkspacedata index ae35924..1ad16f7 100644 --- a/lulu.xcworkspace/contents.xcworkspacedata +++ b/lulu.xcworkspace/contents.xcworkspacedata @@ -8,13 +8,6 @@ location = "group:configure/configure.sh"> - - - - @@ -29,6 +22,13 @@ location = "group:launchDaemon.xcodeproj"> + + + + diff --git a/mainApp/mainApp.xcodeproj/project.pbxproj b/mainApp/mainApp.xcodeproj/project.pbxproj index 61acf5a..b460419 100644 --- a/mainApp/mainApp.xcodeproj/project.pbxproj +++ b/mainApp/mainApp.xcodeproj/project.pbxproj @@ -22,7 +22,7 @@ 7D564DDE1F18441500B8AAD6 /* RuleRowCell.m in Sources */ = {isa = PBXBuildFile; fileRef = 7D564DCA1F18441500B8AAD6 /* RuleRowCell.m */; }; 7D564DDF1F18441500B8AAD6 /* HyperlinkTextField.m in Sources */ = {isa = PBXBuildFile; fileRef = 7D564DCE1F18441500B8AAD6 /* HyperlinkTextField.m */; }; 7D564DE01F18441500B8AAD6 /* RuleRow.m in Sources */ = {isa = PBXBuildFile; fileRef = 7D564DD11F18441500B8AAD6 /* RuleRow.m */; }; - 7D564DE61F18446200B8AAD6 /* logging.m in Sources */ = {isa = PBXBuildFile; fileRef = 7D564DE41F18446200B8AAD6 /* logging.m */; }; + 7D564DE61F18446200B8AAD6 /* Logging.m in Sources */ = {isa = PBXBuildFile; fileRef = 7D564DE41F18446200B8AAD6 /* Logging.m */; }; 7D564DEA1F1855E900B8AAD6 /* UpdateWindowController.m in Sources */ = {isa = PBXBuildFile; fileRef = 7D564DE71F1855E900B8AAD6 /* UpdateWindowController.m */; }; 7D564DEB1F1855E900B8AAD6 /* UpdateWindow.xib in Resources */ = {isa = PBXBuildFile; fileRef = 7D564DE81F1855E900B8AAD6 /* UpdateWindow.xib */; }; 7D704AB71F6C83BF0067224E /* importRules.png in Resources */ = {isa = PBXBuildFile; fileRef = 7D704AB51F6C83BF0067224E /* importRules.png */; }; @@ -88,9 +88,9 @@ 7D564DD01F18441500B8AAD6 /* RuleRow.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RuleRow.h; sourceTree = ""; }; 7D564DD11F18441500B8AAD6 /* RuleRow.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RuleRow.m; sourceTree = ""; }; 7D564DD21F18441500B8AAD6 /* RuleRowCell.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RuleRowCell.h; sourceTree = ""; }; - 7D564DE31F18446200B8AAD6 /* const.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = const.h; path = ../shared/const.h; sourceTree = ""; }; - 7D564DE41F18446200B8AAD6 /* logging.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = logging.m; path = ../shared/logging.m; sourceTree = ""; }; - 7D564DE51F18446200B8AAD6 /* logging.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = logging.h; path = ../shared/logging.h; sourceTree = ""; }; + 7D564DE31F18446200B8AAD6 /* Const.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = Const.h; path = ../shared/Const.h; sourceTree = ""; }; + 7D564DE41F18446200B8AAD6 /* Logging.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = Logging.m; path = ../shared/Logging.m; sourceTree = ""; }; + 7D564DE51F18446200B8AAD6 /* Logging.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = Logging.h; path = ../shared/Logging.h; sourceTree = ""; }; 7D564DE71F1855E900B8AAD6 /* UpdateWindowController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = UpdateWindowController.m; path = ../shared/UpdateWindowController.m; sourceTree = ""; }; 7D564DE81F1855E900B8AAD6 /* UpdateWindow.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; name = UpdateWindow.xib; path = ../shared/UpdateWindow.xib; sourceTree = ""; }; 7D564DE91F1855E900B8AAD6 /* UpdateWindowController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = UpdateWindowController.h; path = ../shared/UpdateWindowController.h; sourceTree = ""; }; @@ -242,11 +242,11 @@ 7D564DE21F18445400B8AAD6 /* shared */ = { isa = PBXGroup; children = ( - 7D564DE31F18446200B8AAD6 /* const.h */, + 7D564DE31F18446200B8AAD6 /* Const.h */, 7D2582551F19FAD700D28B95 /* DaemonComms.h */, 7D2582561F19FAD700D28B95 /* DaemonComms.m */, - 7D564DE51F18446200B8AAD6 /* logging.h */, - 7D564DE41F18446200B8AAD6 /* logging.m */, + 7D564DE51F18446200B8AAD6 /* Logging.h */, + 7D564DE41F18446200B8AAD6 /* Logging.m */, 7DD2BF601F1DAFE100B33214 /* Rule.h */, 7DD2BF5D1F1DAF0C00B33214 /* Rule.m */, 7D2582581F19FB6000D28B95 /* UserCommsInterface.h */, @@ -289,7 +289,7 @@ 7D564DA11F18434F00B8AAD6 /* Project object */ = { isa = PBXProject; attributes = { - LastUpgradeCheck = 0820; + LastUpgradeCheck = 0900; ORGANIZATIONNAME = "Objective-See"; TargetAttributes = { 7D564DA81F18434F00B8AAD6 = { @@ -380,7 +380,7 @@ 7D564DE01F18441500B8AAD6 /* RuleRow.m in Sources */, 7D2582571F19FAD700D28B95 /* DaemonComms.m in Sources */, 7DD2BF581F1C59E900B33214 /* AddRuleWindowController.m in Sources */, - 7D564DE61F18446200B8AAD6 /* logging.m in Sources */, + 7D564DE61F18446200B8AAD6 /* Logging.m in Sources */, 7D16D69A1F65EF9900DB3161 /* Update.m in Sources */, 7D564DB11F18434F00B8AAD6 /* main.m in Sources */, 7D564DD91F18441500B8AAD6 /* RulesWindowController.m in Sources */, @@ -425,7 +425,9 @@ CLANG_CXX_LIBRARY = "libc++"; CLANG_ENABLE_MODULES = YES; CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; CLANG_WARN_CONSTANT_CONVERSION = YES; CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; CLANG_WARN_DOCUMENTATION_COMMENTS = YES; @@ -433,7 +435,11 @@ CLANG_WARN_ENUM_CONVERSION = YES; CLANG_WARN_INFINITE_RECURSION = YES; CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; CLANG_WARN_SUSPICIOUS_MOVE = YES; CLANG_WARN_UNREACHABLE_CODE = YES; CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; @@ -456,7 +462,7 @@ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; - MACOSX_DEPLOYMENT_TARGET = 10.12; + MACOSX_DEPLOYMENT_TARGET = 10.10; MTL_ENABLE_DEBUG_INFO = YES; ONLY_ACTIVE_ARCH = YES; SDKROOT = macosx; @@ -472,7 +478,9 @@ CLANG_CXX_LIBRARY = "libc++"; CLANG_ENABLE_MODULES = YES; CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; CLANG_WARN_CONSTANT_CONVERSION = YES; CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; CLANG_WARN_DOCUMENTATION_COMMENTS = YES; @@ -480,7 +488,11 @@ CLANG_WARN_ENUM_CONVERSION = YES; CLANG_WARN_INFINITE_RECURSION = YES; CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; CLANG_WARN_SUSPICIOUS_MOVE = YES; CLANG_WARN_UNREACHABLE_CODE = YES; CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; @@ -497,7 +509,7 @@ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; - MACOSX_DEPLOYMENT_TARGET = 10.12; + MACOSX_DEPLOYMENT_TARGET = 10.10; MTL_ENABLE_DEBUG_INFO = NO; SDKROOT = macosx; }; @@ -513,6 +525,7 @@ DEVELOPMENT_TEAM = ""; INFOPLIST_FILE = mainApp/Info.plist; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks"; + OTHER_CODE_SIGN_FLAGS = ""; PRODUCT_BUNDLE_IDENTIFIER = "com.objective-see.lulu"; PRODUCT_NAME = LuLu; }; @@ -528,6 +541,8 @@ DEVELOPMENT_TEAM = ""; INFOPLIST_FILE = mainApp/Info.plist; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks"; + OTHER_CODE_SIGN_FLAGS = "-o hard,kill"; + OTHER_LDFLAGS = "-Wl,-sectcreate,__RESTRICT,__restrict,/dev/null"; PRODUCT_BUNDLE_IDENTIFIER = "com.objective-see.lulu"; PRODUCT_NAME = LuLu; }; diff --git a/mainApp/mainApp.xcodeproj/xcshareddata/xcschemes/mainApp.xcscheme b/mainApp/mainApp.xcodeproj/xcshareddata/xcschemes/mainApp.xcscheme deleted file mode 100644 index 968802b..0000000 --- a/mainApp/mainApp.xcodeproj/xcshareddata/xcschemes/mainApp.xcscheme +++ /dev/null @@ -1,105 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/mainApp/mainApp/AboutWindow.xib b/mainApp/mainApp/AboutWindow.xib index c1ae155..5a3d26b 100644 --- a/mainApp/mainApp/AboutWindow.xib +++ b/mainApp/mainApp/AboutWindow.xib @@ -1,7 +1,6 @@ - @@ -18,7 +17,7 @@ - + diff --git a/mainApp/mainApp/AddRule.xib b/mainApp/mainApp/AddRule.xib index 00aa598..22ba39f 100755 --- a/mainApp/mainApp/AddRule.xib +++ b/mainApp/mainApp/AddRule.xib @@ -1,8 +1,8 @@ - + - + @@ -19,43 +19,16 @@ - - + + + - + - - - - - - + + + + + @@ -86,7 +64,7 @@ Gw - - - + + + + + + - - - + + + + + + + + + + + + + + + + + + + + + + + - + diff --git a/mainApp/mainApp/AddRuleWindowController.m b/mainApp/mainApp/AddRuleWindowController.m index b999727..fef6a1f 100755 --- a/mainApp/mainApp/AddRuleWindowController.m +++ b/mainApp/mainApp/AddRuleWindowController.m @@ -58,56 +58,39 @@ -(void)controlTextDidBeginEditing:(NSNotification *)obj } //automatically called when text changes -// ensure 'add' button state is correct -// enabled when there is text -// disabled when there is no test +// invoke helper to set icon, and enable/select 'add' button -(void)controlTextDidChange:(NSNotification *)notification { - //not text field? - if([notification object] != self.processPath) + //text field? + // update the UI + if([notification object] == self.processPath) { - //bail - goto bail; + //update + [self updateUI]; } - - //set state - self.addButton.enabled = (BOOL)self.processPath.stringValue.length; - + + bail: return; } //automatically called when 'enter' is hit -// set icon, and enable/select 'add' button +// invoke helper to set icon, and enable/select 'add' button -(void)controlTextDidEndEditing:(NSNotification *)notification { - //icon - NSImage* processIcon = nil; - - //not text field? - if([notification object] != self.processPath) + //text field? + // update the UI + if([notification object] == self.processPath) { - //bail - goto bail; - } - - //get icon - processIcon = getIconForProcess(self.processPath.stringValue); - if(nil != processIcon) - { - //add - self.icon.image = processIcon; + //update + [self updateUI]; + + //make 'add' selected + [self.window makeFirstResponder:self.addButton]; + } - //enable 'add' button - self.addButton.enabled = YES; - - //make 'add' selected - [self.window makeFirstResponder:self.addButton]; - -bail: - return; } @@ -151,6 +134,9 @@ -(IBAction)browseButtonHandler:(id)sender //allow directories (app bundles) panel.canChooseDirectories = YES; + //can open app bundles + panel.treatsFilePackagesAsDirectories = YES; + //start in /Apps panel.directoryURL = [NSURL fileURLWithPath:@"/Applications"]; @@ -170,9 +156,12 @@ -(IBAction)browseButtonHandler:(id)sender //set text self.processPath.stringValue = panel.URL.path; + //update UI + [self updateUI]; + //make 'add' selected - // will also trigger 'end editing' for text field [self.window makeFirstResponder:self.addButton]; + bail: @@ -199,4 +188,38 @@ -(IBAction)addButtonHandler:(id)sender return; } +//update the UI +// set icon, and enable/select 'add' button +-(void)updateUI +{ + //icon + NSImage* processIcon = nil; + + //blank + // disable 'add' button + if(0 == self.processPath.stringValue.length) + { + //set state + self.addButton.enabled = NO; + + //bail + goto bail; + } + + //get icon + processIcon = getIconForProcess(self.processPath.stringValue); + if(nil != processIcon) + { + //add + self.icon.image = processIcon; + } + + //enable 'add' button + self.addButton.enabled = YES; + +bail: + + return; +} + @end diff --git a/mainApp/mainApp/Preferences.xib b/mainApp/mainApp/Preferences.xib index cea0625..949e718 100644 --- a/mainApp/mainApp/Preferences.xib +++ b/mainApp/mainApp/Preferences.xib @@ -1,7 +1,6 @@ - @@ -24,9 +23,8 @@ - - + @@ -87,7 +85,7 @@ - + @@ -116,7 +114,7 @@ - + @@ -152,7 +150,7 @@ - + diff --git a/mainApp/mainApp/RulesWindowController.m b/mainApp/mainApp/RulesWindowController.m index 423aab5..081af79 100644 --- a/mainApp/mainApp/RulesWindowController.m +++ b/mainApp/mainApp/RulesWindowController.m @@ -38,12 +38,12 @@ -(void)windowDidLoad //alloc filtered rules array rulesFiltered = [NSMutableArray array]; - //start by no filtering - self.shouldFilter = NO; - //init daemon comms obj daemonComms = [[DaemonComms alloc] init]; + //start by no filtering + self.shouldFilter = NO; + //unset message self.rulesStatusMsg.stringValue = @""; @@ -71,7 +71,7 @@ -(void)windowDidLoad }]; //in background - // ->monitor / process new rules + // monitor & process new rules [self performSelectorInBackground:@selector(listenForRuleChanges) withObject:nil]; } @@ -146,11 +146,20 @@ -(IBAction)importRules:(id)sender logMsg(LOG_DEBUG, [NSString stringWithFormat:@"importing rules from %@", panel.URL.path]); //send msg to daemon to XPC - // TODO: check that this succeeded! - [self.daemonComms importRules:panel.URL.path]; - - //update msg - self.rulesStatusMsg.stringValue = @"imported rules"; + if(YES != [self.daemonComms importRules:panel.URL.path]) + { + //err msg + logMsg(LOG_ERR, @"failed to import rules"); + + //update msg + self.rulesStatusMsg.stringValue = @"failed to import rules"; + } + //happy + else + { + //update msg + self.rulesStatusMsg.stringValue = @"imported rules"; + } }//clicked 'ok' (to save) @@ -429,6 +438,10 @@ -(void)listenForRuleChanges // call daemon and block, then display, and repeat! while(YES) { + //pool + @autoreleasepool + { + //dbg msg logMsg(LOG_DEBUG, @"requesting rules from daemon, will block"); @@ -462,12 +475,15 @@ -(void)listenForRuleChanges //wait for resposne, before to asking again dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER); + + }//pool } return; } //process rules dictionary received from daemon +// convert each rule dictionary into a Rule object -(void)processRulesDictionary:(NSDictionary*)daemonRules { //rule obj diff --git a/shared/DaemonComms.h b/shared/DaemonComms.h index 8ff4d0d..570abfd 100644 --- a/shared/DaemonComms.h +++ b/shared/DaemonComms.h @@ -33,7 +33,7 @@ -(void)deleteRule:(NSString*)processPath; //import rules --(void)importRules:(NSString*)rulesFile; +-(BOOL)importRules:(NSString*)rulesFile; //ask for alert -(void)alertRequest:(void (^)(NSDictionary* alert))reply; diff --git a/shared/DaemonComms.m b/shared/DaemonComms.m index 8b36490..25a432b 100644 --- a/shared/DaemonComms.m +++ b/shared/DaemonComms.m @@ -7,8 +7,8 @@ // copyright (c) 2017 Objective-See. All rights reserved. // -#import "const.h" -#import "logging.h" +#import "Const.h" +#import "Logging.h" #import "DaemonComms.h" @implementation DaemonComms @@ -61,7 +61,7 @@ -(void)getRules:(BOOL)wait4Change reply:(void (^)(NSDictionary*))reply; //dbg msg logMsg(LOG_DEBUG, [NSString stringWithFormat:@"sending request, via XPC, to get rules (wait: %d)", wait4Change]); - + //make XPC request to get rules [[self.xpcServiceConnection remoteObjectProxyWithErrorHandler:^(NSError * proxyError) { //err msg @@ -86,7 +86,7 @@ -(void)addRule:(NSString*)processPath action:(NSUInteger)action //dbg msg logMsg(LOG_DEBUG, @"sending request, via XPC, to add rule"); - //add rule + //make XPC request to add rule [[self.xpcServiceConnection remoteObjectProxyWithErrorHandler:^(NSError * proxyError) { //err msg @@ -115,20 +115,36 @@ -(void)deleteRule:(NSString*)processPath } //import rules --(void)importRules:(NSString*)rulesFile +-(BOOL)importRules:(NSString*)rulesFile { + //flag + __block BOOL importedRules = NO; + + //init wait sema + __block dispatch_semaphore_t semaphore = dispatch_semaphore_create(0); + //dbg msg logMsg(LOG_DEBUG, @"sending request, via XPC, to import rules"); //import rules [[self.xpcServiceConnection remoteObjectProxyWithErrorHandler:^(NSError * proxyError) { - //err msg - logMsg(LOG_ERR, [NSString stringWithFormat:@"failed to execute 'importRules' method on launch daemon (error: %@)", proxyError]); - - }] importRules:rulesFile]; + //err msg + logMsg(LOG_ERR, [NSString stringWithFormat:@"failed to execute 'importRules' method on launch daemon (error: %@)", proxyError]); + + }] importRules:rulesFile reply:^(BOOL result) + { + //set flag + importedRules = YES; + + //signal response was received + dispatch_semaphore_signal(semaphore); + }]; - return; + //wait for response to be received + dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER); + + return importedRules; } //ask (and then block) for an alert diff --git a/shared/Rule.m b/shared/Rule.m index 97f4f23..af6fcd8 100644 --- a/shared/Rule.m +++ b/shared/Rule.m @@ -8,9 +8,9 @@ // #import "Rule.h" -#import "const.h" +#import "Const.h" #import "Utilities.h" -#import "logging.h" +#import "Logging.h" @implementation Rule diff --git a/shared/Update.m b/shared/Update.m index ef1fb09..6123f6b 100644 --- a/shared/Update.m +++ b/shared/Update.m @@ -7,9 +7,9 @@ // copyright (c) 2017 Objective-See. All rights reserved. // -#import "const.h" +#import "Const.h" #import "Update.h" -#import "logging.h" +#import "Logging.h" #import "Utilities.h" #import "AppDelegate.h" diff --git a/shared/UpdateWindowController.m b/shared/UpdateWindowController.m index e6d8f4b..8654aeb 100644 --- a/shared/UpdateWindowController.m +++ b/shared/UpdateWindowController.m @@ -7,8 +7,8 @@ // copyright (c) 2017 Objective-See. All rights reserved. // -#import "const.h" -#import "logging.h" +#import "Const.h" +#import "Logging.h" #import "Utilities.h" #import "AppDelegate.h" #import "UpdateWindowController.h" diff --git a/shared/UserClientShared.h b/shared/UserClientShared.h index 5b0cd85..0e73978 100755 --- a/shared/UserClientShared.h +++ b/shared/UserClientShared.h @@ -35,26 +35,62 @@ enum dispatchSelectors { kTestUserClientMethodCount }; +//type +struct genericEvent_s +{ + //type + UInt32 type; +}; -//firewall event struct -typedef struct { +//network out event struct +struct networkOutEvent_s { + + //type + UInt32 type; //process pid - UInt32 pid; + UInt32 pid; //socket type int socketType; //local socket address - struct sockaddr_in localAddress; + struct sockaddr_in6 localAddress; //remote socket address - struct sockaddr_in remoteAddress; + struct sockaddr_in6 remoteAddress; +}; + +//dns response out event struct +struct dnsResponseEvent_s { + + //type + UInt32 type; + + //response + unsigned char response[512]; +}; + +//firewall event union +// holds various structs, but max size will be 'padding' +typedef union +{ + //generic event + struct genericEvent_s genericEvent; + + //network out event + struct networkOutEvent_s networkOutEvent; + + //dns response event + struct dnsResponseEvent_s dnsResponseEvent; + + //padding + unsigned char padding[sizeof(UInt32) + 512]; } firewallEvent; -//dns header -//http://www.nersc.gov/~scottc/software/snort/dns_head.html +//dns header struct +// from: http://www.nersc.gov/~scottc/software/snort/dns_head.html #pragma pack(push,1) struct dnsHeader { unsigned short id; @@ -66,14 +102,4 @@ struct dnsHeader { }; #pragma pack(pop) -//TODO -#pragma pack(push,1) -typedef struct { - uint16_t type; - uint16_t clas; - uint32_t ttl; - uint16_t rdlength; -} static_RR; -#pragma pack(pop) - #endif diff --git a/shared/UserCommsInterface.h b/shared/UserCommsInterface.h index fbf3706..fd96fc5 100644 --- a/shared/UserCommsInterface.h +++ b/shared/UserCommsInterface.h @@ -29,7 +29,7 @@ -(void)deleteRule:(NSString*)path; //import rules --(void)importRules:(NSString*)rulesFile; +-(void)importRules:(NSString*)rulesFile reply:(void (^)(BOOL))reply; //process alert request from client -(void)alertRequest:(void (^)(NSDictionary* alert))reply; diff --git a/shared/Utilities.h b/shared/Utilities.h index 78431c9..83d7b49 100644 --- a/shared/Utilities.h +++ b/shared/Utilities.h @@ -25,7 +25,7 @@ NSString* getAppBinary(NSString* appPath); //get app's version // ->extracted from Info.plist -NSString* getAppVersion(); +NSString* getAppVersion(void); //check if process is alive BOOL isProcessAlive(pid_t processID); diff --git a/shared/Utilities.m b/shared/Utilities.m index 90d8e86..17d8ef4 100644 --- a/shared/Utilities.m +++ b/shared/Utilities.m @@ -7,8 +7,8 @@ // copyright (c) 2017 Objective-See. All rights reserved. // -#import "const.h" -#import "logging.h" +#import "Const.h" +#import "Logging.h" #import "Utilities.h" #import @@ -503,7 +503,7 @@ BOOL setFilePermissions(NSString* file, int permissions, BOOL recursive) NSImage* icon = nil; //system's document icon - //static NSData* documentIcon = nil; + static NSData* documentIcon = nil; //bundle NSBundle* appBundle = nil; @@ -542,6 +542,24 @@ BOOL setFilePermissions(NSString* file, int permissions, BOOL recursive) //extract icon icon = [[NSWorkspace sharedWorkspace] iconForFile:path]; + //load system document icon + // ->static var, so only load once + if(nil == documentIcon) + { + //load + documentIcon = [[[NSWorkspace sharedWorkspace] iconForFileType: + NSFileTypeForHFSTypeCode(kGenericDocumentIcon)] TIFFRepresentation]; + } + + //if 'iconForFile' method doesn't find and icon, it returns the system 'document' icon + // ->the system 'application' icon seems more applicable, so use that here... + if(YES == [[icon TIFFRepresentation] isEqual:documentIcon]) + { + //set icon to system 'applicaiton' icon + icon = [[NSWorkspace sharedWorkspace] + iconForFileType: NSFileTypeForHFSTypeCode(kGenericApplicationIcon)]; + } + //'iconForFileType' returns small icons // ->so set size to 64 [icon setSize:NSMakeSize(128, 128)]; @@ -859,7 +877,7 @@ pid_t getParentID(int pid) return parentID; } - +//TODO: use proc info lib! //build an array of processes ancestry // ->start with process and go 'back' till initial ancestor NSMutableArray* generateProcessHierarchy(pid_t pid) diff --git a/shared/const.h b/shared/const.h index 5121d0f..549945c 100644 --- a/shared/const.h +++ b/shared/const.h @@ -7,8 +7,8 @@ // copyright (c) 2017 Objective-See. All rights reserved. // -#ifndef Const_h -#define Const_h +#ifndef const_h +#define const_h //vendor id string #define OBJECTIVE_SEE_VENDOR "com.objectiveSee" @@ -23,15 +23,18 @@ # define DEBUG_PRINT(x) do {} while (0) #endif +//firewall event: network out +#define EVENT_NETWORK_OUT 0x0 + +//firewall event: dns response +#define EVENT_DNS_RESPONSE 0x1 + //connect out (TCP) #define EVENT_CONNECT_OUT 0x1 //data out (UDP) #define EVENT_DATA_OUT 0x2 -//dns response -#define EVENT_DNS_RESPONSE 0x3 - //log to file flag #define LOG_TO_FILE 0x10 @@ -39,7 +42,7 @@ #define MAX_KEV_MSG 254 //max Q items -#define MAX_FIREWALL_EVENT 512 +#define MAX_FIREWALL_EVENTS 512 #define LULU_SERVICE_NAME "com_objective_see_firewall" @@ -156,6 +159,7 @@ #define ALERT_PROTOCOL @"protocol" #define ALERT_ACTION @"action" #define ALERT_SIGNINGINFO @"signingInfo" +#define ALERT_PASSIVELY_ALLOWED @"passivelyAllowed" //signature status #define KEY_SIGNATURE_STATUS @"signatureStatus" @@ -178,5 +182,4 @@ //preferences window #define WINDOW_PREFERENCES 1 - #endif /* const_h */ diff --git a/shared/logging.h b/shared/logging.h index 15b13b9..b9e7a47 100644 --- a/shared/logging.h +++ b/shared/logging.h @@ -20,13 +20,13 @@ void logMsg(int level, NSString* msg); //prep/open log file -BOOL initLogging(); +BOOL initLogging(NSString* logPath); //get path to log file -NSString* logFilePath(); +NSString* logFilePath(void); //de-init logging -void deinitLogging(); +void deinitLogging(void); //log to file void log2File(NSString* msg); diff --git a/shared/logging.m b/shared/logging.m index c06cd80..9e3f4a4 100644 --- a/shared/logging.m +++ b/shared/logging.m @@ -7,8 +7,8 @@ // copyright (c) 2017 Objective-See. All rights reserved. // -#import "const.h" -#import "logging.h" +#import "Const.h" +#import "Logging.h" //global log file handle NSFileHandle* logFileHandle = nil; @@ -104,18 +104,11 @@ void deinitLogging() } //prep/open log file -BOOL initLogging() +BOOL initLogging(NSString* logPath) { //ret var BOOL bRet = NO; - //log file path - NSString* logPath = nil; - - //init log path - // '/Library/Logs/Lulu.log' - logPath = [@"/Library/Logs/" stringByAppendingPathComponent:LOG_FILE_NAME]; - //first time // create file if(YES != [[NSFileManager defaultManager] fileExistsAtPath:logPath])