Find Mac OSX serial number - objective-c

How to find the Mac OSX serial number.
Sometimes it is required to get serial number of a mac, and you validate on that.
I needed the same, few years back, when I developed a plugin for OsiriX. I was asked to release it in such a way, only few systems can use that plugin.
If we get any better solution than this, that will be quite helpful for all of us.

The following code is mainly copied from Technical Note TN1103,
with small modifications to return an NSString and to make it compile with ARC:
#include <IOKit/IOKitLib.h>
- (NSString *)getSerialNumber
{
NSString *serial = nil;
io_service_t platformExpert = IOServiceGetMatchingService(kIOMasterPortDefault,
IOServiceMatching("IOPlatformExpertDevice"));
if (platformExpert) {
CFTypeRef serialNumberAsCFString =
IORegistryEntryCreateCFProperty(platformExpert,
CFSTR(kIOPlatformSerialNumberKey),
kCFAllocatorDefault, 0);
if (serialNumberAsCFString) {
serial = CFBridgingRelease(serialNumberAsCFString);
}
IOObjectRelease(platformExpert);
}
return serial;
}
You have to add the IOKit.framework to your build settings.

This is the Swift version of the solution:
var serialNumber: String? {
let platformExpert = IOServiceGetMatchingService(kIOMasterPortDefault, IOServiceMatching("IOPlatformExpertDevice") )
guard platformExpert > 0 else {
return nil
}
guard let serialNumber = (IORegistryEntryCreateCFProperty(platformExpert, kIOPlatformSerialNumberKey as CFString, kCFAllocatorDefault, 0).takeUnretainedValue() as? String) else {
return nil
}
IOObjectRelease(platformExpert)
return serialNumber
}

This is a C++ version based on the TN1103 that Martin mention above.
C++ example:
#include <CoreFoundation/CoreFoundation.h>
#include <IOKit/IOKitLib.h>
std::string example_class::getSerialNumber()
{
CFStringRef serial;
char buffer[64] = {0};
std::string seriaNumber("");
io_service_t platformExpert = IOServiceGetMatchingService(kIOMasterPortDefault,
IOServiceMatching("IOPlatformExpertDevice"));
if (platformExpert)
{
CFTypeRef serialNumberAsCFString = IORegistryEntryCreateCFProperty(platformExpert,
CFSTR(kIOPlatformSerialNumberKey),
kCFAllocatorDefault, 0);
if (serialNumberAsCFString) {
serial = (CFStringRef)serialNumberAsCFString;
}
if (CFStringGetCString(serial, buffer, 64, kCFStringEncodingUTF8)) {
seriaNumber = buffer;
}
IOObjectRelease(platformExpert);
}
return seriaNumber;
}

Related

CGDisplayIOServicePort is deprecated in OS X >= 10.9, how to replace?

I did small app to allow quickly change screen resolutions on multiple monitors. I want to show product name as title of the monitor, and it's very simple to find using this code:
NSDictionary *deviceInfo = (__bridge NSDictionary *)IODisplayCreateInfoDictionary(CGDisplayIOServicePort(dispID), kIODisplayOnlyPreferredName);
NSDictionary *localizedNames = [deviceInfo objectForKey:[NSString stringWithUTF8String:kDisplayProductName]];
if([localizedNames count] > 0) {
_title = [localizedNames objectForKey:[[localizedNames allKeys] objectAtIndex:0]];
} else {
_title = #"Unknown display";
}
But CGDisplayIOServicePort is deprecated in OS X >= 10.9 and Apple's documentation says there is no replacement. How to find service port or product name without using this method?
I tried to iterate through IO-registry and tried to use IOServiceGetMatchingServices method to find display services but I'm not very familiar with IO-registry so I couldn't find solution.
Thanks for help!
It looks like #Eun's post missed a piece of information to close this discussion. With a little search, I found that IOServicePortFromCGDisplayID is not an API which Apple provides. Rather, it's a piece of open source code found here:
https://github.com/glfw/glfw/blob/e0a6772e5e4c672179fc69a90bcda3369792ed1f/src/cocoa_monitor.m
I copied IOServicePortFromCGDisplayID and also 'getDisplayName' from it.
I needed two tweaks to make it work on OS X 10.10.
Remove the code to handle serial number in IOServicePortFromCGDisplayID. (CFDictionaryGetValue for
kDisplaySerialNumber returns NULL for me.)
Remove project specific
error handling code in getDisplayName.
If you need more information
Issue tracker of the problem: github.com/glfw/glfw/issues/165
Commit
for the solution:
github.com/glfw/glfw/commit/e0a6772e5e4c672179fc69a90bcda3369792ed1f
I would thank Matthew Henry who submitted the code there.
Here is my take on the issue. I also started with the code from GLFW 3.1, file cocoa_monitor.m.
But I had to modify it in different ways than Hiroshi said, so here goes:
// Get the name of the specified display
- (NSString*) screenNameForDisplay: (NSNumber*) screen_id
{
CGDirectDisplayID displayID = [screen_id unsignedIntValue];
io_service_t serv = [self IOServicePortFromCGDisplayID: displayID];
if (serv == 0)
return #"unknown";
CFDictionaryRef info = IODisplayCreateInfoDictionary(serv, kIODisplayOnlyPreferredName);
IOObjectRelease(serv);
CFStringRef display_name;
CFDictionaryRef names = CFDictionaryGetValue(info, CFSTR(kDisplayProductName));
if ( !names ||
!CFDictionaryGetValueIfPresent(names, CFSTR("en_US"), (const void**) & display_name) )
{
// This may happen if a desktop Mac is running headless
CFRelease( info );
return #"unknown";
}
NSString * displayname = [NSString stringWithString: (__bridge NSString *) display_name];
CFRelease(info);
return displayname;
}
// Returns the io_service_t (an int) corresponding to a CG display ID, or 0 on failure.
// The io_service_t should be released with IOObjectRelease when not needed.
- (io_service_t) IOServicePortFromCGDisplayID: (CGDirectDisplayID) displayID
{
io_iterator_t iter;
io_service_t serv, servicePort = 0;
CFMutableDictionaryRef matching = IOServiceMatching("IODisplayConnect");
// releases matching for us
kern_return_t err = IOServiceGetMatchingServices( kIOMasterPortDefault, matching, & iter );
if ( err )
return 0;
while ( (serv = IOIteratorNext(iter)) != 0 )
{
CFDictionaryRef displayInfo;
CFNumberRef vendorIDRef;
CFNumberRef productIDRef;
CFNumberRef serialNumberRef;
displayInfo = IODisplayCreateInfoDictionary( serv, kIODisplayOnlyPreferredName );
Boolean success;
success = CFDictionaryGetValueIfPresent( displayInfo, CFSTR(kDisplayVendorID), (const void**) & vendorIDRef );
success &= CFDictionaryGetValueIfPresent( displayInfo, CFSTR(kDisplayProductID), (const void**) & productIDRef );
if ( !success )
{
CFRelease(displayInfo);
continue;
}
SInt32 vendorID;
CFNumberGetValue( vendorIDRef, kCFNumberSInt32Type, &vendorID );
SInt32 productID;
CFNumberGetValue( productIDRef, kCFNumberSInt32Type, &productID );
// If a serial number is found, use it.
// Otherwise serial number will be nil (= 0) which will match with the output of 'CGDisplaySerialNumber'
SInt32 serialNumber = 0;
if ( CFDictionaryGetValueIfPresent(displayInfo, CFSTR(kDisplaySerialNumber), (const void**) & serialNumberRef) )
{
CFNumberGetValue( serialNumberRef, kCFNumberSInt32Type, &serialNumber );
}
// If the vendor and product id along with the serial don't match
// then we are not looking at the correct monitor.
// NOTE: The serial number is important in cases where two monitors
// are the exact same.
if( CGDisplayVendorNumber(displayID) != vendorID ||
CGDisplayModelNumber(displayID) != productID ||
CGDisplaySerialNumber(displayID) != serialNumber )
{
CFRelease(displayInfo);
continue;
}
servicePort = serv;
CFRelease(displayInfo);
break;
}
IOObjectRelease(iter);
return servicePort;
}
This works fine for me in a screensaver I wrote under macOS 10.11 (El Capitan).
I tested it with the built-in display of my MacBookPro and an Apple Display connected via Thunderbolt.
As of macOS 10.15 -[NSScreen localizedName] is available:
NSLog(#"Name of main display is %#", NSScreen.mainScreen.localizedName);
NSString* screenNameForDisplay(CGDirectDisplayID displayID)
{
NSString *screenName = nil;
io_service_t service = IOServicePortFromCGDisplayID(displayID);
if (service)
{
NSDictionary *deviceInfo = (NSDictionary *)IODisplayCreateInfoDictionary(service, kIODisplayOnlyPreferredName);
NSDictionary *localizedNames = [deviceInfo objectForKey:[NSString stringWithUTF8String:kDisplayProductName]];
if ([localizedNames count] > 0) {
screenName = [[localizedNames objectForKey:[[localizedNames allKeys] objectAtIndex:0]] retain];
}
[deviceInfo release];
}
return [screenName autorelease];
}

Generate SHA256 hash in Objective-C

So I need to generate a Sha256 password in Objective-C, and can't figure out for the life of me how to do it! Is there something easy I'm just missing?
I've tried implementing the following method (which was written for iPhone, but I figured maybe it'd work cross-platform, as some Objective-C code does)
-(NSString*)sha256HashFor:(NSString*)input
{
const char* str = [input UTF8String];
unsigned char result[CC_SHA256_DIGEST_LENGTH];
CC_SHA256(str, strlen(str), result);
NSMutableString *ret = [NSMutableString stringWithCapacity:CC_SHA256_DIGEST_LENGTH*2];
for(int i = 0; i<CC_SHA256_DIGEST_LENGTH; i++)
{
[ret appendFormat:#"%02x",result[i]];
}
return ret;
}
But that just spat out errors about CC_SHA256_DIGEST_LENGTH being an undeclared identifier.
You need to include the appropriate header file:
#include <CommonCrypto/CommonDigest.h>
According to the Cryptographic Services documentation this should be available on both iOS and OS X.
In OS X v10.5 and later and iOS 5.0 and later, Common Crypto provides low-level C support for encryption and decryption. Common Crypto is not as straightforward as Security Transforms, but provides a wider range of features, including additional hashing schemes, cipher modes, and so on.
#import <CommonCrypto/CommonDigest.h>
Objective-C: SHA256 is only two lines:
+ (NSData *)doSha256:(NSData *)dataIn {
NSMutableData *macOut = [NSMutableData dataWithLength:CC_SHA256_DIGEST_LENGTH];
CC_SHA256(dataIn.bytes, dataIn.length, macOut.mutableBytes);
return macOut;
}
Swift 3
func sha256Hex(string: String) -> String? {
guard let messageData = string.data(using:String.Encoding.utf8) else { return nil }
var digestData = Data(count: Int(CC_SHA256_DIGEST_LENGTH))
_ = digestData.withUnsafeMutableBytes {digestBytes in
messageData.withUnsafeBytes {messageBytes in
CC_SHA256(messageBytes, CC_LONG(messageData.count), digestBytes)
}
}
return digestData.map { String(format: "%02hhx", $0) }.joined()
}
// Test
let sha256HexString = sha256Hex(string:"Hello")
print("sha256HexString: \(sha256HexString!)")
sha256HexString: "185f8db32271fe25f561a6fc938b2e264306ec304eda518007d1764826381969"
Objective-C method whose output matches output from random site online
-(NSString*)sha256HashForText:(NSString*)text {
const char* utf8chars = [text UTF8String];
unsigned char result[CC_SHA256_DIGEST_LENGTH];
CC_SHA256(utf8chars, (CC_LONG)strlen(utf8chars), result);
NSMutableString *ret = [NSMutableString stringWithCapacity:CC_SHA256_DIGEST_LENGTH*2];
for(int i = 0; i<CC_SHA256_DIGEST_LENGTH; i++) {
[ret appendFormat:#"%02x",result[i]];
}
return ret;
}
Taken from this Gist.
a modified version of #zaph answer in Objective-C with NSString as input and output:
-(NSString*)sha256HashFor:(NSString*)input
{
NSData* data = [input dataUsingEncoding:NSUTF8StringEncoding];
NSMutableData *sha256Data = [NSMutableData dataWithLength:CC_SHA256_DIGEST_LENGTH];
CC_SHA256([data bytes], (CC_LONG)[data length], [sha256Data mutableBytes]);
return [sha256Data base64EncodedStringWithOptions:0];
}
Check out the NSHash cocoa pod. It has a bunch of different hashing methods including SHA256.
https://github.com/jerolimov/NSHash

<CFData 0x100516c60 [0x7fff71adaea0]>{length = 6, capacity = 6, bytes = 0x0022412b03ad}

Every time I start build my Xcode Project, I get this in the console:
<CFData 0x100516c60 [0x7fff71adaea0]>{length = 6, capacity = 6, bytes = 0x0022412b03ad}
I have no idea, what it means and what it's causing it.
Can someone help me?
Thx!
Edit:
I think this method creates it:
//
// PrimaryMac.m
// Network Radar
//
// Created by Daniel Diener on 06.07.11.
// Copyright 2011 __MyCompanyName__. All rights reserved.
//
#import "PrimaryMac.h"
#include <stdio.h>
#include <sys/param.h>
#include <sys/file.h>
#include <sys/socket.h>
#include <sys/sysctl.h>
#include <net/if.h>
#include <net/if_dl.h>
#include "if_types.h"
#include "route.h"
#include "if_ether.h"
#include <netinet/in.h>
#include <arpa/inet.h>
#include <err.h>
#include <errno.h>
#include <netdb.h>
#include <paths.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <CoreFoundation/CoreFoundation.h>
#include <IOKit/IOKitLib.h>
#include <IOKit/network/IOEthernetInterface.h>
#include <IOKit/network/IONetworkInterface.h>
#include <IOKit/network/IOEthernetController.h>
#implementation PrimaryMac
#synthesize localMac, remoteMac;
static kern_return_t FindEthernetInterfaces(io_iterator_t *matchingServices);
static kern_return_t GetMACAddress(io_iterator_t intfIterator, UInt8 *MACAddress, UInt8 bufferSize);
- (id)init
{
self = [super init];
if (self) {
}
return self;
}
//LOCAL MAC:::::::::::::::::::
// Returns an iterator containing the primary (built-in) Ethernet interface. The caller is responsible for
// releasing the iterator after the caller is done with it.
static kern_return_t FindEthernetInterfaces(io_iterator_t *matchingServices)
{
kern_return_t kernResult;
CFMutableDictionaryRef matchingDict;
CFMutableDictionaryRef propertyMatchDict;
// Ethernet interfaces are instances of class kIOEthernetInterfaceClass.
// IOServiceMatching is a convenience function to create a dictionary with the key kIOProviderClassKey and
// the specified value.
matchingDict = IOServiceMatching(kIOEthernetInterfaceClass);
// Note that another option here would be:
// matchingDict = IOBSDMatching("en0");
// but en0: isn't necessarily the primary interface, especially on systems with multiple Ethernet ports.
if (NULL == matchingDict) {
printf("IOServiceMatching returned a NULL dictionary.\n");
}
else {
// Each IONetworkInterface object has a Boolean property with the key kIOPrimaryInterface. Only the
// primary (built-in) interface has this property set to TRUE.
// IOServiceGetMatchingServices uses the default matching criteria defined by IOService. This considers
// only the following properties plus any family-specific matching in this order of precedence
// (see IOService::passiveMatch):
//
// kIOProviderClassKey (IOServiceMatching)
// kIONameMatchKey (IOServiceNameMatching)
// kIOPropertyMatchKey
// kIOPathMatchKey
// kIOMatchedServiceCountKey
// family-specific matching
// kIOBSDNameKey (IOBSDNameMatching)
// kIOLocationMatchKey
// The IONetworkingFamily does not define any family-specific matching. This means that in
// order to have IOServiceGetMatchingServices consider the kIOPrimaryInterface property, we must
// add that property to a separate dictionary and then add that to our matching dictionary
// specifying kIOPropertyMatchKey.
propertyMatchDict = CFDictionaryCreateMutable(kCFAllocatorDefault, 0,
&kCFTypeDictionaryKeyCallBacks,
&kCFTypeDictionaryValueCallBacks);
if (NULL == propertyMatchDict) {
printf("CFDictionaryCreateMutable returned a NULL dictionary.\n");
}
else {
// Set the value in the dictionary of the property with the given key, or add the key
// to the dictionary if it doesn't exist. This call retains the value object passed in.
CFDictionarySetValue(propertyMatchDict, CFSTR(kIOPrimaryInterface), kCFBooleanTrue);
// Now add the dictionary containing the matching value for kIOPrimaryInterface to our main
// matching dictionary. This call will retain propertyMatchDict, so we can release our reference
// on propertyMatchDict after adding it to matchingDict.
CFDictionarySetValue(matchingDict, CFSTR(kIOPropertyMatchKey), propertyMatchDict);
CFRelease(propertyMatchDict);
}
}
// IOServiceGetMatchingServices retains the returned iterator, so release the iterator when we're done with it.
// IOServiceGetMatchingServices also consumes a reference on the matching dictionary so we don't need to release
// the dictionary explicitly.
kernResult = IOServiceGetMatchingServices(kIOMasterPortDefault, matchingDict, matchingServices);
if (KERN_SUCCESS != kernResult) {
printf("IOServiceGetMatchingServices returned 0x%08x\n", kernResult);
}
return kernResult;
}
// Given an iterator across a set of Ethernet interfaces, return the MAC address of the last one.
// If no interfaces are found the MAC address is set to an empty string.
// In this sample the iterator should contain just the primary interface.
static kern_return_t GetMACAddress(io_iterator_t intfIterator, UInt8 *MACAddress, UInt8 bufferSize)
{
io_object_t intfService;
io_object_t controllerService;
kern_return_t kernResult = KERN_FAILURE;
// Make sure the caller provided enough buffer space. Protect against buffer overflow problems.
if (bufferSize < kIOEthernetAddressSize) {
return kernResult;
}
// Initialize the returned address
bzero(MACAddress, bufferSize);
// IOIteratorNext retains the returned object, so release it when we're done with it.
while ((intfService = IOIteratorNext(intfIterator)))
{
CFTypeRef MACAddressAsCFData;
// IONetworkControllers can't be found directly by the IOServiceGetMatchingServices call,
// since they are hardware nubs and do not participate in driver matching. In other words,
// registerService() is never called on them. So we've found the IONetworkInterface and will
// get its parent controller by asking for it specifically.
// IORegistryEntryGetParentEntry retains the returned object, so release it when we're done with it.
kernResult = IORegistryEntryGetParentEntry(intfService,
kIOServicePlane,
&controllerService);
if (KERN_SUCCESS != kernResult) {
printf("IORegistryEntryGetParentEntry returned 0x%08x\n", kernResult);
}
else {
// Retrieve the MAC address property from the I/O Registry in the form of a CFData
MACAddressAsCFData = IORegistryEntryCreateCFProperty(controllerService,
CFSTR(kIOMACAddress),
kCFAllocatorDefault,
0);
if (MACAddressAsCFData) {
CFShow(MACAddressAsCFData); // for display purposes only; output goes to stderr
// Get the raw bytes of the MAC address from the CFData
CFDataGetBytes(MACAddressAsCFData, CFRangeMake(0, kIOEthernetAddressSize), MACAddress);
CFRelease(MACAddressAsCFData);
}
// Done with the parent Ethernet controller object so we release it.
(void) IOObjectRelease(controllerService);
}
// Done with the Ethernet interface object so we release it.
(void) IOObjectRelease(intfService);
}
return kernResult;
}
- (void)createLocalMac{
kern_return_t kernResult = KERN_SUCCESS;
io_iterator_t intfIterator;
UInt8 MACAddress[kIOEthernetAddressSize];
kernResult = FindEthernetInterfaces(&intfIterator);
if (KERN_SUCCESS != kernResult) {
printf("FindEthernetInterfaces returned 0x%08x\n", kernResult);
}
else {
kernResult = GetMACAddress(intfIterator, MACAddress, sizeof(MACAddress));
if (KERN_SUCCESS != kernResult) {
printf("GetMACAddress returned 0x%08x\n", kernResult);
}
else {
localMac = [NSString stringWithFormat:#"%02x:%02x:%02x:%02x:%02x:%02x",
MACAddress[0], MACAddress[1], MACAddress[2], MACAddress[3], MACAddress[4], MACAddress[5]];
}
}
(void) IOObjectRelease(intfIterator); // Release the iterator.
}
//REMOTE MAC:::::::::::::::::::
- (void)createRemoteMac:(NSString *)ipAddr{
NSString *ret = nil;
in_addr_t addr = inet_addr([ipAddr UTF8String]);
size_t needed;
char *buf, *next;
struct rt_msghdr *rtm;
struct sockaddr_inarp *sin;
struct sockaddr_dl *sdl;
int mib[6];
mib[0] = CTL_NET;
mib[1] = PF_ROUTE;
mib[2] = 0;
mib[3] = AF_INET;
mib[4] = NET_RT_FLAGS;
mib[5] = RTF_LLINFO;
if (sysctl(mib, sizeof(mib) / sizeof(mib[0]), NULL, &needed, NULL, 0) < 0)
err(1, "route-sysctl-estimate");
if ((buf = (char*)malloc(needed)) == NULL)
err(1, "malloc");
if (sysctl(mib, sizeof(mib) / sizeof(mib[0]), buf, &needed, NULL, 0) < 0)
err(1, "retrieval of routing table");
for (next = buf; next < buf + needed; next += rtm->rtm_msglen) {
rtm = (struct rt_msghdr *)next;
sin = (struct sockaddr_inarp *)(rtm + 1);
sdl = (struct sockaddr_dl *)(sin + 1);
if (addr != sin->sin_addr.s_addr || sdl->sdl_alen < 6)
continue;
u_char *cp = (u_char*)LLADDR(sdl);
ret = [NSString stringWithFormat:#"%02X:%02X:%02X:%02X:%02X:%02X",
cp[0], cp[1], cp[2], cp[3], cp[4], cp[5]];
break;
}
free(buf);
remoteMac = ret;
}
- (void)dealloc {
[remoteMac release];
[localMac release];
[super dealloc];
}
#end
I use it to get the active interface's MAC address.
Your print statement is happening on this line using CFShow. Just comment that out :)
if (MACAddressAsCFData) {
//Comment out the CFShow here
CFShow(MACAddressAsCFData); // for display purposes only; output goes to stderr

cocoa - How to programmatically retrieve the amount of memory your application is using?

I would like to know how much memory my application is using. How would I be able to retrieve this programmatically? Is there an easy Cocoa way to do this, or would I have to go all the way down to C?
Thanks!
Working snippet:
struct task_basic_info info;
mach_msg_type_number_t size = sizeof(info);
kern_return_t kerr = task_info(mach_task_self(),
TASK_BASIC_INFO,
(task_info_t)&info,
&size);
if( kerr == KERN_SUCCESS ) {
NSLog(#"Memory in use (in bytes): %u", info.resident_size);
} else {
NSLog(#"Error with task_info(): %s", mach_error_string(kerr));
}
Unfortunately I don't know the original source anymore.
- (NSInteger)getMemoryUsedInMegaBytes
{
NSInteger memoryInBytes = [self getMemoryUsedInBytes];
return memoryInBytes/1048576;
}
- (NSInteger)getMemoryUsedInBytes
{
struct task_basic_info info;
mach_msg_type_number_t size = sizeof(info);
kern_return_t kerr = task_info(mach_task_self(),
TASK_BASIC_INFO,
(task_info_t)&info,
&size);
if( kerr == KERN_SUCCESS )
{
return info.resident_size;
}
else
{
return 0;
}
}

How to validate an IP address with regular expression in Objective-C?

How to validate an IP address in Objective-C?
Here's a category using the modern inet_pton which will return YES for a valid IPv4 or IPv6 string.
#include <arpa/inet.h>
#implementation NSString (IPValidation)
- (BOOL)isValidIPAddress
{
const char *utf8 = [self UTF8String];
int success;
struct in_addr dst;
success = inet_pton(AF_INET, utf8, &dst);
if (success != 1) {
struct in6_addr dst6;
success = inet_pton(AF_INET6, utf8, &dst6);
}
return success == 1;
}
#end
Here's an alternative approach that might also help. Let's assume you have an NSString* that contains your IP address, called ipAddressStr, of the format a.b.c.d:
int ipQuads[4];
const char *ipAddress = [ipAddressStr cStringUsingEncoding:NSUTF8StringEncoding];
sscanf(ipAddress, "%d.%d.%d.%d", &ipQuads[0], &ipQuads[1], &ipQuads[2], &ipQuads[3]);
#try {
for (int quad = 0; quad < 4; quad++) {
if ((ipQuads[quad] < 0) || (ipQuads[quad] > 255)) {
NSException *ipException = [NSException
exceptionWithName:#"IPNotFormattedCorrectly"
reason:#"IP range is invalid"
userInfo:nil];
#throw ipException;
}
}
}
#catch (NSException *exc) {
NSLog(#"ERROR: %#", [exc reason]);
}
You could modify the if conditional block to follow RFC 1918 guidelines, if you need that level of validation.
Swift edition:
func isIPAddressValid(ip: String) -> Bool {
guard let utf8Str = (ip as NSString).utf8String else {
return false
}
let utf8:UnsafePointer<Int8> = UnsafePointer(utf8Str)
var success: Int32
var dst: in_addr = in_addr()
success = inet_pton(AF_INET, utf8, &dst)
if (success != 1) {
var dst6: in6_addr? = in6_addr()
success = inet_pton(AF_INET6, utf8, &dst6);
}
return success == 1
}
A trick you can do is test the return of the inet_aton BSD call like this:
#include <arpa/inet.h>
- (BOOL)isIp:(NSString*)string{
struct in_addr pin;
int success = inet_aton([string UTF8String],&pin);
if (success == 1) return TRUE;
return FALSE;
}
Be aware however that this validates the string if it contains a ip address in any format, it is not restricted to the dotted format.