mirror of
https://github.com/objective-see/TaskExplorer.git
synced 2026-03-22 07:02:39 +00:00
initial commit
This commit is contained in:
@@ -0,0 +1,33 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>CFBundleDevelopmentRegion</key>
|
||||
<string>en</string>
|
||||
<key>CFBundleDisplayName</key>
|
||||
<string>remoteTaskService</string>
|
||||
<key>CFBundleExecutable</key>
|
||||
<string>$(EXECUTABLE_NAME)</string>
|
||||
<key>CFBundleIdentifier</key>
|
||||
<string>com.objective-see.$(PRODUCT_NAME:rfc1034identifier)</string>
|
||||
<key>CFBundleInfoDictionaryVersion</key>
|
||||
<string>6.0</string>
|
||||
<key>CFBundleName</key>
|
||||
<string>$(PRODUCT_NAME)</string>
|
||||
<key>CFBundlePackageType</key>
|
||||
<string>XPC!</string>
|
||||
<key>CFBundleShortVersionString</key>
|
||||
<string>1.0</string>
|
||||
<key>CFBundleSignature</key>
|
||||
<string>????</string>
|
||||
<key>CFBundleVersion</key>
|
||||
<string>1</string>
|
||||
<key>NSHumanReadableCopyright</key>
|
||||
<string>Copyright © 2015 Lucas Derraugh. All rights reserved.</string>
|
||||
<key>XPCService</key>
|
||||
<dict>
|
||||
<key>ServiceType</key>
|
||||
<string>Application</string>
|
||||
</dict>
|
||||
</dict>
|
||||
</plist>
|
||||
@@ -0,0 +1,50 @@
|
||||
//
|
||||
// main.m
|
||||
// remoteTaskService
|
||||
//
|
||||
// Created by Patrick Wardle on 5/27/15.
|
||||
// Copyright (c) 2015 Lucas Derraugh. All rights reserved.
|
||||
//
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
#import "remoteTaskService.h"
|
||||
#import "serviceInterface.h"
|
||||
|
||||
@interface ServiceDelegate : NSObject <NSXPCListenerDelegate>
|
||||
@end
|
||||
|
||||
@implementation ServiceDelegate
|
||||
|
||||
- (BOOL)listener:(NSXPCListener *)listener shouldAcceptNewConnection:(NSXPCConnection *)newConnection {
|
||||
// This method is where the NSXPCListener configures, accepts, and resumes a new incoming NSXPCConnection.
|
||||
|
||||
// Configure the connection.
|
||||
// First, set the interface that the exported object implements.
|
||||
newConnection.exportedInterface = [NSXPCInterface interfaceWithProtocol:@protocol(remoteTaskProto)];
|
||||
|
||||
// Next, set the object that the connection exports. All messages sent on the connection to this service will be sent to the exported object to handle. The connection retains the exported object.
|
||||
remoteTaskService *exportedObject = [remoteTaskService new];
|
||||
newConnection.exportedObject = exportedObject;
|
||||
|
||||
// Resuming the connection allows the system to deliver more incoming messages.
|
||||
[newConnection resume];
|
||||
|
||||
// Returning YES from this method tells the system that you have accepted this connection. If you want to reject the connection for some reason, call -invalidate on the connection and return NO.
|
||||
return YES;
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
int main(int argc, const char *argv[])
|
||||
{
|
||||
// Create the delegate for the service.
|
||||
ServiceDelegate *delegate = [ServiceDelegate new];
|
||||
|
||||
// Set up the one NSXPCListener for this service. It will handle all incoming connections.
|
||||
NSXPCListener *listener = [NSXPCListener serviceListener];
|
||||
listener.delegate = delegate;
|
||||
|
||||
// Resuming the serviceListener starts this service. This method does not return.
|
||||
[listener resume];
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
//
|
||||
// remoteTaskService.h
|
||||
// remoteTaskService
|
||||
//
|
||||
// Created by Patrick Wardle on 5/27/15.
|
||||
// Copyright (c) 2015 Lucas Derraugh. All rights reserved.
|
||||
//
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
#import "serviceInterface.h"
|
||||
|
||||
// This object implements the protocol which we have defined. It provides the actual behavior for the service. It is 'exported' by the service to make it available to the process hosting the service over an NSXPCConnection.
|
||||
@interface remoteTaskService : NSObject <remoteTaskProto, NSXPCListenerDelegate>
|
||||
|
||||
|
||||
//
|
||||
+(remoteTaskService *)defaultService;
|
||||
|
||||
@end
|
||||
|
||||
|
||||
//convert a socket type in to string
|
||||
NSString* socketType2String(int type);
|
||||
|
||||
//convert a socket family into string
|
||||
NSString* socketFamily2String(int family);
|
||||
|
||||
//convert a socket protocol into string
|
||||
NSString* socketProto2String(int proto);
|
||||
|
||||
//convert a socket state into string
|
||||
NSString* socketState2String(int state);
|
||||
@@ -0,0 +1,744 @@
|
||||
//
|
||||
// remoteTaskService.m
|
||||
// remoteTaskService
|
||||
//
|
||||
// Created by Patrick Wardle on 5/27/15.
|
||||
// Copyright (c) 2015 Lucas Derraugh. All rights reserved.
|
||||
//
|
||||
//TODO: make sure task is still active (maybe in client, b4 calling this?!
|
||||
|
||||
#import "remoteTaskService.h"
|
||||
#import "Consts.h"
|
||||
|
||||
#import <mach-o/dyld_images.h>
|
||||
#import <mach/mach_init.h>
|
||||
#import <mach/mach_vm.h>
|
||||
#import <sys/types.h>
|
||||
#import <mach/mach.h>
|
||||
#import <sys/ptrace.h>
|
||||
#import <sys/wait.h>
|
||||
#import <sys/sysctl.h>
|
||||
#import <sys/proc_info.h>
|
||||
#import <libproc.h>
|
||||
#import <arpa/inet.h>
|
||||
#import <netinet/tcp_fsm.h>
|
||||
#import <netdb.h>
|
||||
|
||||
|
||||
|
||||
static const char *socketFamilies[] =
|
||||
{
|
||||
"AF_UNSPEC",
|
||||
"AF_UNIX",
|
||||
"AF_INET",
|
||||
"AF_IMPLINK",
|
||||
"AF_PUP",
|
||||
"AF_CHAOS",
|
||||
"AF_NS",
|
||||
"AF_ISO",
|
||||
"AF_ECMA",
|
||||
"AF_DATAKIT",
|
||||
"AF_CCITT",
|
||||
"AF_SNA",
|
||||
"AF_DECnet",
|
||||
"AF_DLI",
|
||||
"AF_LAT",
|
||||
"AF_HYLINK",
|
||||
"AF_APPLETALK",
|
||||
"AF_ROUTE",
|
||||
"AF_LINK",
|
||||
"#define",
|
||||
"AF_COIP",
|
||||
"AF_CNT",
|
||||
"pseudo_AF_RTIP",
|
||||
"AF_IPX",
|
||||
"AF_SIP",
|
||||
"pseudo_AF_PIP",
|
||||
"pseudo_AF_BLUE",
|
||||
"AF_NDRV",
|
||||
"AF_ISDN",
|
||||
"pseudo_AF_KEY",
|
||||
"AF_INET6",
|
||||
"AF_NATM",
|
||||
"AF_SYSTEM",
|
||||
"AF_NETBIOS",
|
||||
"AF_PPP",
|
||||
"pseudo_AF_HDRCMPLT",
|
||||
"AF_RESERVED_36",
|
||||
};
|
||||
#define SOCKET_FAMILY_MAX (int)(sizeof(socketFamilies)/sizeof(char *))
|
||||
|
||||
|
||||
//32bit
|
||||
struct dyld_image_info_32 {
|
||||
int imageLoadAddress;
|
||||
int imageFilePath;
|
||||
int imageFileModDate;
|
||||
};
|
||||
|
||||
@implementation remoteTaskService
|
||||
|
||||
+ (remoteTaskService *)defaultService {
|
||||
static dispatch_once_t onceToken;
|
||||
static remoteTaskService *shared;
|
||||
dispatch_once(&onceToken, ^{
|
||||
shared = [remoteTaskService new];
|
||||
});
|
||||
return shared;
|
||||
}
|
||||
|
||||
//enumerate dylibs for a specified task
|
||||
// ->dylibs returned in array arg
|
||||
-(void)enumerateDylibs:(NSNumber*)taskPID withReply:(void (^)(NSMutableArray *))reply;
|
||||
{
|
||||
//status
|
||||
kern_return_t status = !KERN_SUCCESS;
|
||||
|
||||
//task for remote process
|
||||
task_t remoteTask = 0;
|
||||
|
||||
//remote read addr
|
||||
vm_address_t remoteReadAddr = 0;
|
||||
|
||||
//number of remote bytes to read
|
||||
mach_msg_type_number_t bytesToRead = 0;
|
||||
|
||||
//dyld info structure
|
||||
// ->contains remote addr/size of dyld_all_image_infos
|
||||
struct task_dyld_info dyldInfo = {0};
|
||||
|
||||
//set size of task info
|
||||
mach_msg_type_number_t taskInfoSize = 0;
|
||||
|
||||
//pointer to structure for...
|
||||
// ->populated by mach_vm_read()
|
||||
struct dyld_all_image_infos* allImageInfo = NULL;
|
||||
|
||||
//number of bytes read for dyld_all_image_infos
|
||||
mach_msg_type_number_t aifBytesRead = 0;
|
||||
|
||||
//array of structs w/ dylib info
|
||||
void* dyldImageInfos = NULL;
|
||||
|
||||
//number of bytes read for list of dyld_image_infos
|
||||
mach_msg_type_number_t diiBytesRead = 0;
|
||||
|
||||
//pointer to dylib info struct
|
||||
// ->depending on remote (target) process either dyld_image_info or dyld_image_info_32
|
||||
void* imageInfo = NULL;
|
||||
|
||||
//buffer for dylib path
|
||||
char* dylibPath = NULL;
|
||||
|
||||
//number of bytes read for dyld_all_image_infos
|
||||
mach_msg_type_number_t dpBytesRead = 0;
|
||||
|
||||
//dylibs
|
||||
NSMutableArray* dylibPaths = nil;
|
||||
|
||||
//alloc array for dylibs
|
||||
dylibPaths = [NSMutableArray array];
|
||||
|
||||
//get task for pid
|
||||
// ->allows access to read remote process memory
|
||||
status = task_for_pid(mach_task_self(), [taskPID intValue], &remoteTask);
|
||||
if(KERN_SUCCESS != status)
|
||||
{
|
||||
//err msg
|
||||
NSLog(@"ERROR: task_for_pid() failed w/ %d", status);
|
||||
|
||||
//bail
|
||||
goto bail;
|
||||
}
|
||||
|
||||
//set task info size
|
||||
taskInfoSize = TASK_DYLD_INFO_COUNT;
|
||||
|
||||
//get TASK_DYLD_INFO
|
||||
// ->populates task_dyld_info structure
|
||||
status = task_info(remoteTask, TASK_DYLD_INFO, (task_info_t)&dyldInfo, &taskInfoSize);
|
||||
if(KERN_SUCCESS != status)
|
||||
{
|
||||
//bail
|
||||
goto bail;
|
||||
}
|
||||
|
||||
//dbg msg
|
||||
//NSLog(@"got dyld_info: %#llx : %llx - %d", dyldInfo.all_image_info_addr, dyldInfo.all_image_info_size, dyldInfo.all_image_info_format);
|
||||
|
||||
//remotely read dyld_all_image_infos
|
||||
status = mach_vm_read(remoteTask, (vm_address_t)dyldInfo.all_image_info_addr, dyldInfo.all_image_info_size, (vm_offset_t*)&allImageInfo, &aifBytesRead);
|
||||
if(KERN_SUCCESS != status)
|
||||
{
|
||||
//err msg
|
||||
NSLog(@"ERROR: mach_vm_read() failed w/ %d", status);
|
||||
|
||||
//bail
|
||||
goto bail;
|
||||
}
|
||||
|
||||
//set remote read addr & size
|
||||
// ->64bit mode
|
||||
if(TASK_DYLD_ALL_IMAGE_INFO_64 == dyldInfo.all_image_info_format)
|
||||
{
|
||||
//straight assign
|
||||
remoteReadAddr = (vm_address_t)allImageInfo->infoArray;
|
||||
|
||||
//init output size
|
||||
bytesToRead = allImageInfo->infoArrayCount * sizeof(struct dyld_image_info);
|
||||
}
|
||||
//set remote read addr & size
|
||||
// ->32bit mode
|
||||
else
|
||||
{
|
||||
//hack, can use 64bit version of struct (since 'infoArray' is first pointer
|
||||
// ->but zero out top bits
|
||||
remoteReadAddr = (vm_address_t)allImageInfo->infoArray & 0xFFFFFFFF;
|
||||
|
||||
//init output size
|
||||
bytesToRead = allImageInfo->infoArrayCount * sizeof(struct dyld_image_info_32);
|
||||
}
|
||||
|
||||
//read remote array of dyld_image_info/32 structs
|
||||
status = mach_vm_read(remoteTask, (vm_address_t)remoteReadAddr, bytesToRead, (vm_offset_t*)&dyldImageInfos, &diiBytesRead);
|
||||
|
||||
//check
|
||||
if(KERN_SUCCESS != status)
|
||||
{
|
||||
//err msg
|
||||
NSLog(@"ERROR: mach_vm_read() failed w/ %d", status);
|
||||
|
||||
//bail
|
||||
goto bail;
|
||||
}
|
||||
|
||||
//iterate over all dyld_image_info_32/dyld_image_info structs
|
||||
// ->extract and remotely read address to dylib path
|
||||
for(NSUInteger i = 0; i<allImageInfo->infoArrayCount; i++)
|
||||
{
|
||||
//reset
|
||||
dpBytesRead = 0;
|
||||
|
||||
//advance to next image_info struct and set remote read addr
|
||||
// ->64bit mode
|
||||
if(TASK_DYLD_ALL_IMAGE_INFO_64 == dyldInfo.all_image_info_format)
|
||||
{
|
||||
//next dyld_image_info struct
|
||||
imageInfo = (unsigned char*)dyldImageInfos + i * sizeof(struct dyld_image_info);
|
||||
|
||||
//remote read addr
|
||||
remoteReadAddr = (vm_address_t)((struct dyld_image_info*)imageInfo)->imageFilePath;
|
||||
}
|
||||
//advance to next image_info struct and set remote read addr
|
||||
// ->64bit mode
|
||||
else
|
||||
{
|
||||
//next dyld_image_info_32 struct
|
||||
imageInfo = (unsigned char*)dyldImageInfos + i * sizeof(struct dyld_image_info_32);
|
||||
|
||||
//remote read addr
|
||||
remoteReadAddr = (vm_address_t)((struct dyld_image_info_32*)imageInfo)->imageFilePath & 0xFFFFFFFF;
|
||||
}
|
||||
|
||||
//remotely read into dylib's path!
|
||||
// ->seems to always fail for first image, which is base executable...
|
||||
status = mach_vm_read(remoteTask, (vm_address_t)remoteReadAddr, PATH_MAX, (vm_offset_t*)&dylibPath, &dpBytesRead);
|
||||
if( (KERN_SUCCESS != status) ||
|
||||
(NULL == dylibPath) )
|
||||
{
|
||||
//err msg
|
||||
//NSLog(@"ERROR: mach_vm_read() failed w/ %d", status);
|
||||
|
||||
//try next
|
||||
continue;
|
||||
}
|
||||
|
||||
//dbg msg
|
||||
//NSLog(@"path (%d): %s", dpBytesRead, dylibPath);
|
||||
|
||||
//save it
|
||||
[dylibPaths addObject:[NSString stringWithUTF8String:dylibPath]];
|
||||
|
||||
//dealloc
|
||||
mach_vm_deallocate(mach_task_self(), (vm_offset_t)dylibPath, dpBytesRead);
|
||||
|
||||
|
||||
}//for all dyld_image_info_32/dyld_image_info structs
|
||||
|
||||
//bail
|
||||
bail:
|
||||
|
||||
//dealloc list of dylib info structs
|
||||
if(NULL != dyldImageInfos)
|
||||
{
|
||||
//dealloc
|
||||
mach_vm_deallocate(mach_task_self(), (vm_offset_t)dyldImageInfos, diiBytesRead);
|
||||
}
|
||||
|
||||
//dealloc dyld_all_image_infos struct
|
||||
if(NULL != allImageInfo)
|
||||
{
|
||||
//dealloc
|
||||
mach_vm_deallocate(mach_task_self(), (vm_offset_t)allImageInfo, aifBytesRead);
|
||||
}
|
||||
|
||||
//invoke reply block
|
||||
reply(dylibPaths);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
//enumerate open files
|
||||
// ->accomplish this via lsof, since proc_pidinfo() misses some files...
|
||||
-(void)enumerateFiles:(NSNumber*)taskPID withReply:(void (^)(NSMutableArray *))reply;
|
||||
{
|
||||
//task
|
||||
NSTask* task = nil;
|
||||
|
||||
//pipe
|
||||
NSPipe* pipe = nil;
|
||||
|
||||
//results
|
||||
NSData* results = nil;
|
||||
|
||||
//results split on '\n'
|
||||
NSArray* splitResults = nil;
|
||||
|
||||
//file path
|
||||
NSString* filePath = nil;
|
||||
|
||||
//file info dictionary
|
||||
NSMutableDictionary* fileInfo = nil;
|
||||
|
||||
//files
|
||||
NSMutableArray* files = nil;
|
||||
|
||||
//init task
|
||||
task = [[NSTask alloc] init];
|
||||
|
||||
//init pipe
|
||||
pipe = [NSPipe pipe];
|
||||
|
||||
//init array for files
|
||||
files = [NSMutableArray array];
|
||||
|
||||
//set task's stdout to pipe
|
||||
[task setStandardOutput:pipe];
|
||||
|
||||
//set task's stderr to pipe
|
||||
[task setStandardError:pipe];
|
||||
|
||||
//set launch path
|
||||
[task setLaunchPath:LSOF];
|
||||
|
||||
//set tasks's args
|
||||
// -> -Fn -p <taskPid>
|
||||
[task setArguments:@[@"-Fn", @"-p", taskPID.stringValue]];
|
||||
|
||||
//launch
|
||||
[task launch];
|
||||
|
||||
//get results
|
||||
results = [[[task standardOutput] fileHandleForReading] readDataToEndOfFile];
|
||||
|
||||
//sanity check(s)
|
||||
if( (nil == results) ||
|
||||
(0 == results.length) )
|
||||
{
|
||||
//bail
|
||||
goto bail;
|
||||
}
|
||||
|
||||
//split results into array
|
||||
splitResults = [[[NSString alloc] initWithData:results encoding:NSUTF8StringEncoding] componentsSeparatedByString:@"\n"];
|
||||
|
||||
//sanity check(s)
|
||||
if( (nil == splitResults) ||
|
||||
(0 == splitResults.count) )
|
||||
{
|
||||
//bail
|
||||
goto bail;
|
||||
}
|
||||
|
||||
//iterate over all results
|
||||
// ->make file info dictionary for files (not sockets, etc)
|
||||
for(NSString* result in splitResults)
|
||||
{
|
||||
//skip any odd/weird/short lines
|
||||
// lsof outpupt will be in format: 'n<filePath'>
|
||||
if( (YES != [result hasPrefix:@"n"]) ||
|
||||
(result.length < 0x2) )
|
||||
{
|
||||
//skip
|
||||
continue;
|
||||
}
|
||||
|
||||
//init file path
|
||||
// ->result, minus first (lsof-added) char
|
||||
filePath = [result substringFromIndex:0x1];
|
||||
|
||||
//skip 'non files'
|
||||
if(YES != [[NSFileManager defaultManager] fileExistsAtPath:filePath])
|
||||
{
|
||||
//skip
|
||||
continue;
|
||||
}
|
||||
|
||||
//also skip files such as '/', /dev/null, etc
|
||||
if( (YES == [filePath isEqualToString:@"/"]) ||
|
||||
(YES == [filePath isEqualToString:@"/dev/null"]) )
|
||||
{
|
||||
//skip
|
||||
continue;
|
||||
}
|
||||
|
||||
//alloc info dictionary
|
||||
fileInfo = [NSMutableDictionary dictionary];
|
||||
|
||||
//add path
|
||||
fileInfo[KEY_FILE_PATH] = filePath;
|
||||
|
||||
//save
|
||||
[files addObject:fileInfo];
|
||||
}
|
||||
|
||||
//bail
|
||||
bail:
|
||||
|
||||
//invoke reply
|
||||
reply(files);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
//TODO: soi_rcv/soi_snd to get packets!?
|
||||
//enumerate network connections
|
||||
-(void)enumerateNetwork:(NSNumber*)taskPID withReply:(void (^)(NSMutableArray *))reply;
|
||||
{
|
||||
//task's sockets
|
||||
NSMutableArray* sockets = nil;
|
||||
|
||||
//socket info dictionary
|
||||
NSMutableDictionary* socket = nil;
|
||||
|
||||
//size
|
||||
int bufferSize = -1;
|
||||
|
||||
//proc handles
|
||||
struct proc_fdinfo *procFDInfo = NULL;
|
||||
|
||||
//number of handle
|
||||
int numberOfProcFDs = 0;
|
||||
|
||||
//socket handle struct
|
||||
struct socket_fdinfo socketInfo = {0};
|
||||
|
||||
//socket local addr
|
||||
// ->big enough for both IPv4 and IPv6
|
||||
char localIPAddr[INET6_ADDRSTRLEN] = {0};
|
||||
|
||||
//socket remote addr
|
||||
// ->big enough for both IPv4 and IPv6
|
||||
char remoteIPAddr[INET6_ADDRSTRLEN] = {0};
|
||||
|
||||
//socket remote port
|
||||
short remotePort = 0;
|
||||
|
||||
//alloc array for sockets
|
||||
sockets = [NSMutableArray array];
|
||||
|
||||
//invoke proc_pidinfo w/ NULL
|
||||
// ->get's required buffer size
|
||||
bufferSize = proc_pidinfo([taskPID intValue], PROC_PIDLISTFDS, 0, 0, 0);
|
||||
if(bufferSize <= 0)
|
||||
{
|
||||
//bail
|
||||
goto bail;
|
||||
}
|
||||
|
||||
//alloc buffer for handles
|
||||
procFDInfo = (struct proc_fdinfo *)malloc(bufferSize);
|
||||
|
||||
//sanity check
|
||||
if(NULL == procFDInfo)
|
||||
{
|
||||
//bail
|
||||
goto bail;
|
||||
}
|
||||
|
||||
//get proc's handles
|
||||
bufferSize = proc_pidinfo([taskPID intValue], PROC_PIDLISTFDS, 0, procFDInfo, bufferSize);
|
||||
if(bufferSize <= 0)
|
||||
{
|
||||
//bail
|
||||
goto bail;
|
||||
}
|
||||
|
||||
//calc number of handles
|
||||
numberOfProcFDs = bufferSize / PROC_PIDLISTFD_SIZE;
|
||||
|
||||
//iterate over all file descriptors
|
||||
// ->only care about sockets though...
|
||||
for(NSUInteger i = 0; i < numberOfProcFDs; i++)
|
||||
{
|
||||
//skip all non-sockets
|
||||
if(PROX_FDTYPE_SOCKET != procFDInfo[i].proc_fdtype)
|
||||
{
|
||||
//skip
|
||||
continue;
|
||||
}
|
||||
|
||||
//get (detailed) info about socket
|
||||
// ->should return # of bytes that matches size of socket struct
|
||||
if(sizeof(struct socket_fdinfo) != proc_pidfdinfo([taskPID intValue], procFDInfo[i].proc_fd, PROC_PIDFDSOCKETINFO, &socketInfo, sizeof(struct socket_fdinfo)))
|
||||
{
|
||||
//skip
|
||||
continue;
|
||||
}
|
||||
|
||||
//skip any non-internet sockets
|
||||
if( (socketInfo.psi.soi_family != AF_INET) &&
|
||||
(socketInfo.psi.soi_family != AF_INET6) )
|
||||
{
|
||||
//skip
|
||||
continue;
|
||||
}
|
||||
|
||||
//alloc dictionary for socket
|
||||
socket = [NSMutableDictionary dictionary];
|
||||
|
||||
//add local port
|
||||
socket[KEY_LOCAL_PORT] = [NSNumber numberWithShort:ntohs(socketInfo.psi.soi_proto.pri_tcp.tcpsi_ini.insi_lport)];
|
||||
|
||||
//get remote port
|
||||
remotePort = ntohs(socketInfo.psi.soi_proto.pri_tcp.tcpsi_ini.insi_fport);
|
||||
|
||||
//IPv4 sockets
|
||||
if(socketInfo.psi.soi_family == AF_INET)
|
||||
{
|
||||
//get local ip addr
|
||||
inet_ntop(AF_INET, &socketInfo.psi.soi_proto.pri_tcp.tcpsi_ini.insi_laddr.ina_46.i46a_addr4, localIPAddr, sizeof(localIPAddr));
|
||||
|
||||
//add local ip addr
|
||||
socket[KEY_LOCAL_ADDR] = [NSString stringWithUTF8String:localIPAddr];
|
||||
|
||||
//for connected sessions
|
||||
// ->get/save remote ip addr
|
||||
if(0 != remotePort)
|
||||
{
|
||||
//add remote port
|
||||
socket[KEY_REMOTE_PORT] = [NSNumber numberWithShort:remotePort];
|
||||
|
||||
//get remote ip addr
|
||||
inet_ntop(AF_INET, &socketInfo.psi.soi_proto.pri_tcp.tcpsi_ini.insi_faddr.ina_46.i46a_addr4, remoteIPAddr, sizeof(remoteIPAddr));
|
||||
|
||||
//add remote ip addr
|
||||
socket[KEY_REMOTE_ADDR] = [NSString stringWithUTF8String:remoteIPAddr];
|
||||
}
|
||||
}
|
||||
//IPv6 sockets
|
||||
else if(socketInfo.psi.soi_family == AF_INET6)
|
||||
{
|
||||
//get local ip addr
|
||||
inet_ntop(AF_INET6, &socketInfo.psi.soi_proto.pri_tcp.tcpsi_ini.insi_laddr.ina_6, localIPAddr, sizeof(localIPAddr));
|
||||
|
||||
//add local ip addr
|
||||
socket[KEY_LOCAL_ADDR] = [NSString stringWithUTF8String:localIPAddr];
|
||||
|
||||
//for connected sessions
|
||||
// ->get remote ip addr
|
||||
if(0 != remotePort)
|
||||
{
|
||||
//add remote port
|
||||
socket[KEY_REMOTE_PORT] = [NSNumber numberWithShort:remotePort];
|
||||
|
||||
//get remote ip addr
|
||||
inet_ntop(AF_INET6, &socketInfo.psi.soi_proto.pri_tcp.tcpsi_ini.insi_faddr.ina_6, remoteIPAddr, sizeof(remoteIPAddr));
|
||||
|
||||
//add remote ip addr
|
||||
socket[KEY_REMOTE_ADDR] = [NSString stringWithUTF8String:remoteIPAddr];
|
||||
}
|
||||
}
|
||||
|
||||
//set type
|
||||
socket[KEY_SOCKET_TYPE] = socketType2String(socketInfo.psi.soi_type);
|
||||
|
||||
//set family
|
||||
// ->for now this will only be 'AF_INET' or 'AF_INET6'
|
||||
socket[KEY_SOCKET_FAMILY] = socketFamily2String(socketInfo.psi.soi_family);
|
||||
|
||||
//set protocol
|
||||
socket[KEY_SOCKET_PROTO] = socketProto2String(socketInfo.psi.soi_protocol);
|
||||
|
||||
//get state
|
||||
// ->only for stream stockets though
|
||||
if(SOCK_STREAM == socketInfo.psi.soi_type)
|
||||
{
|
||||
//set state
|
||||
// ->for now, this will only be 'listening' or 'established'
|
||||
socket[KEY_SOCKET_STATE] = socketState2String(socketInfo.psi.soi_proto.pri_tcp.tcpsi_state);
|
||||
|
||||
}
|
||||
|
||||
//add
|
||||
[sockets addObject:socket];
|
||||
|
||||
}//all FDs
|
||||
|
||||
|
||||
//bail
|
||||
bail:
|
||||
|
||||
//free buffer
|
||||
if(nil != procFDInfo)
|
||||
{
|
||||
//free
|
||||
free(procFDInfo);
|
||||
}
|
||||
|
||||
//invoke reply
|
||||
reply(sockets);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
|
||||
//convert a socket type into string
|
||||
NSString* socketType2String(int type)
|
||||
{
|
||||
//socket type
|
||||
NSString* socketType = nil;
|
||||
|
||||
//convert
|
||||
switch(type)
|
||||
{
|
||||
//stream
|
||||
case SOCK_STREAM:
|
||||
socketType = @"SOCK_STREAM";
|
||||
break;
|
||||
|
||||
//dgram
|
||||
case SOCK_DGRAM:
|
||||
socketType = @"SOCK_DGRAM";
|
||||
break;
|
||||
|
||||
//raw
|
||||
case SOCK_RAW:
|
||||
socketType = @"SOCK_RAW";
|
||||
break;
|
||||
|
||||
//rdm
|
||||
case SOCK_RDM:
|
||||
socketType = @"SOCK_RDM";
|
||||
break;
|
||||
|
||||
//seq packet
|
||||
case SOCK_SEQPACKET:
|
||||
socketType = @"SOCK_SEQPACKET";
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return socketType;
|
||||
}
|
||||
|
||||
|
||||
//convert a socket family into string
|
||||
NSString* socketFamily2String(int family)
|
||||
{
|
||||
//socket family
|
||||
NSString* socketFamily = nil;
|
||||
|
||||
//sanity check
|
||||
if( (family < 0) ||
|
||||
(family >= SOCKET_FAMILY_MAX) )
|
||||
{
|
||||
//bail
|
||||
goto bail;
|
||||
}
|
||||
|
||||
//init socket family string
|
||||
socketFamily = [NSString stringWithUTF8String:socketFamilies[family]];
|
||||
|
||||
//bail
|
||||
bail:
|
||||
|
||||
return socketFamily;
|
||||
}
|
||||
|
||||
//convert a socket protocol into string
|
||||
NSString* socketProto2String(int proto)
|
||||
{
|
||||
//socket proto
|
||||
NSString* socketProto = nil;
|
||||
|
||||
//proto struct
|
||||
struct protoent *protoInfo = NULL;
|
||||
|
||||
//get proto info
|
||||
protoInfo = getprotobynumber(proto);
|
||||
|
||||
//sanity check
|
||||
if(NULL == protoInfo)
|
||||
{
|
||||
//bail
|
||||
goto bail;
|
||||
}
|
||||
|
||||
//init proto string
|
||||
// ->name comes from struct
|
||||
socketProto = [NSString stringWithUTF8String:protoInfo->p_name];
|
||||
|
||||
//bail
|
||||
bail:
|
||||
|
||||
return socketProto;
|
||||
}
|
||||
|
||||
|
||||
//convert a socket state into string
|
||||
NSString* socketState2String(int state)
|
||||
{
|
||||
//socket proto
|
||||
NSString* socketState = nil;
|
||||
|
||||
//convert to string
|
||||
switch(state)
|
||||
{
|
||||
//listening
|
||||
case TCPS_LISTEN:
|
||||
|
||||
//set
|
||||
socketState = SOCKET_LISTENING;
|
||||
break;
|
||||
|
||||
//established
|
||||
case TCPS_ESTABLISHED:
|
||||
|
||||
//set
|
||||
socketState = SOCKET_ESTABLISHED;
|
||||
break;
|
||||
|
||||
default:
|
||||
|
||||
//TODO: what states?
|
||||
NSLog(@"unknown state: %d", state);
|
||||
|
||||
//can't return nil
|
||||
//TODO: hrmm
|
||||
socketState = @"unknown";
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
return socketState;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user