- Objective-C
/// MARK - WXIPConfig.h
#import <Foundation/Foundation.h>
static const NSString * _Nonnull kWXConfigInterfaceWifi = @"en0";
static const NSString * _Nonnull kWXConfigInterfaceCellular = @"pdp_ip0";
static const NSString * _Nonnull kWXConfigInterfaceVPN = @"utun0";
static const NSString * _Nonnull kWXIPConfigIPV4 = @"ipv4";
static const NSString * _Nonnull kWXIPConfigIPV6 = @"ipv6";
typedef NSDictionary<NSString*, NSString*> WXConfigIPMap;
NS_ASSUME_NONNULL_BEGIN
@interface WXIPConfig : NSObject
+ (NSString *)keyWithName: (NSString*)name version: (NSString*)version;
+ (nonnull WXConfigIPMap*)getAllIPs;
+ (nullable NSString*)getIPWithInterface: (NSString*)interface version: (NSString*)version;
@end
NS_ASSUME_NONNULL_END
// MARK - WXIPConfig.m
#import "WXIPConfig.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/ioctl.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netdb.h>
#include <arpa/inet.h>
#include <sys/sockio.h>
#include <net/if.h>
#include <errno.h>
#include <net/if_dl.h>
#include <net/ethernet.h>
#include <ifaddrs.h>
#include <arpa/inet.h>
@implementation WXIPConfig
+ (NSString *)keyWithName: (NSString*)name version: (NSString*)version {
return [NSString stringWithFormat:@"%@/%@", name, version];
}
+ (nonnull NSDictionary *)getAllIPs {
NSMutableDictionary *ips = [[NSMutableDictionary alloc] initWithCapacity:32];
struct ifaddrs *interfaces;
if (!getifaddrs(&interfaces)) {
struct ifaddrs *temp_interface;
for (temp_interface = interfaces; temp_interface != NULL; temp_interface = temp_interface->ifa_next) {
const struct sockaddr_in *addr = (const struct sockaddr_in*)temp_interface->ifa_addr;
if (addr == NULL) {
continue;
}
sa_family_t family = addr->sin_family;
if (!(family == AF_INET || family == AF_INET6)) {
continue;
}
NSString *name = [NSString stringWithUTF8String:temp_interface->ifa_name];
const NSString *version;
char addrBuffer[MAX(INET_ADDRSTRLEN, INET6_ADDRSTRLEN)];
const char *result;
if (family == AF_INET) {
version = kWXIPConfigIPV4;
result = inet_ntop(AF_INET, &addr->sin_addr, addrBuffer, INET_ADDRSTRLEN);
} else {
version = kWXIPConfigIPV6;
const struct sockaddr_in6 *addr6 = (const struct sockaddr_in6*)temp_interface->ifa_addr;
result = inet_ntop(AF_INET6, &addr6->sin6_addr, addrBuffer, INET6_ADDRSTRLEN);
}
if (result != NULL) {
NSString *key = [NSString stringWithFormat:@"%@/%@", name, version];
ips[key] = [NSString stringWithUTF8String:addrBuffer];
}
}
}
return ips;
}
+ (nullable NSString*)getIPWithInterface: (NSString*)interface version: (NSString*)version {
NSString *key = [WXIPConfig keyWithName:interface version:version];
return [WXIPConfig getAllIPs][key];
}
@end
- Swift
// Key = 接口名称+IP版本
public enum IPMapKey: RawRepresentable, Hashable, Equatable {
case ipv4(String)
case ipv6(String)
public typealias RawValue = String
public var rawValue: String {
switch self {
case .ipv4(let if_name):
return "\(if_name)/ipv4"
case .ipv6(let if_name):
return "\(if_name)/ipv6"
}
}
public init?(rawValue: String) {
return nil
}
init?(sa_family: Int32, ifa_name: String?) {
guard let name = ifa_name else { return nil }
switch sa_family {
case AF_INET:
self = .ipv4(name)
case AF_INET6:
self = .ipv6(name)
default:
return nil
}
}
}
extension IPMapKey: CustomStringConvertible {
public var description: String {
return rawValue
}
}
public enum IPValue {
case ipv4(String)
case ipv6(String)
init?(sa_family: Int32, ifa_addr: String?) {
guard let addr = ifa_addr else { return nil }
switch sa_family {
case AF_INET:
self = .ipv4(addr)
case AF_INET6:
self = .ipv6(addr)
default:
return nil
}
}
}
extension IPValue: CustomStringConvertible {
public var description: String {
switch self {
case .ipv4(let ip):
return ip
case .ipv6(let ip):
return ip
}
}
}
public typealias IPMap = [IPMapKey: IPValue]
public class IPConfig {
public static let Wifi = "en0"
public static let Cellular = "pdp_ip0"
public static let VPN = "utun0"
/// 获取所有IP地址
public class func getAllIPs() -> IPMap {
var ips: IPMap = [:]
var interfaces: UnsafeMutablePointer<ifaddrs>? = nil
defer {
if interfaces != nil {
free(interfaces)
}
}
guard getifaddrs(&interfaces) == 0 else { return ips }
var temp_interface: UnsafeMutablePointer<ifaddrs>? = interfaces
while let interface = temp_interface {
if let ifa_addr = interface.pointee.ifa_addr?.pointee {
let sa_family = Int32(ifa_addr.sa_family)
let ifa_name = String(cString: interface.pointee.ifa_name, encoding: .utf8)
if let key = IPMapKey(sa_family: sa_family, ifa_name: ifa_name) {
let len_t = max(INET_ADDRSTRLEN, INET6_ADDRSTRLEN)
var inaddr = unsafeBitCast(ifa_addr, to: sockaddr_in.self).sin_addr
var buffer = [CChar](repeating: 0, count: Int(len_t))
inet_ntop(sa_family, UnsafeRawPointer(&inaddr), &buffer, UInt32(len_t))
let addr = String(cString: buffer, encoding: .utf8)
ips[key] = IPValue(sa_family: sa_family, ifa_addr: addr)
}
}
temp_interface = interface.pointee.ifa_next
}
return ips
}
public class func getIPWithKey(_ key: IPMapKey) -> IPValue? {
return getAllIPs()[key]
}
}
附上Demo地址