ฉันต้องการรับที่อยู่ IP ของ iPad โดยใช้โปรแกรม ฉันจะสอบถามระบบย่อยเครือข่ายเพื่อค้นหาว่าที่อยู่ IPv4 (และ IPv6) ของฉันคืออะไร
PS: ฉันสามารถปิด IPv6 ได้หรือไม่?
ฉันต้องการรับที่อยู่ IP ของ iPad โดยใช้โปรแกรม ฉันจะสอบถามระบบย่อยเครือข่ายเพื่อค้นหาว่าที่อยู่ IPv4 (และ IPv6) ของฉันคืออะไร
PS: ฉันสามารถปิด IPv6 ได้หรือไม่?
คำตอบ:
รหัสต่อไปนี้ค้นหาที่อยู่ IPv4 และ IPv6 ทั้งหมดบนอุปกรณ์ iOS หรือ OSX getIPAddress
วิธีแรกทำหน้าที่มากกว่าหรือน้อยกว่าเป็นรหัสที่เก่ากว่าในคำตอบนี้: คุณสามารถเลือกที่อยู่แบบใดแบบหนึ่งหรือแบบอื่นก็ได้และจะชอบ WIFI มากกว่าเซลลูลาร์ (เห็นได้ชัดว่าคุณสามารถเปลี่ยนแปลงสิ่งนี้ได้)
น่าสนใจมากขึ้นก็สามารถกลับมาเป็นพจนานุกรมที่อยู่ทั้งหมดที่พบข้ามอยู่สำหรับอินเตอร์เฟซหรือที่อยู่เชื่อมโยงกับnot up
loopback
รหัสก่อนหน้านี้รวมทั้งวิธีแก้ปัญหาอื่น ๆ ในหัวข้อนี้จะไม่สามารถถอดรหัส IPv6 ได้อย่างถูกต้อง (inet_ntoa ไม่สามารถจัดการได้) สิ่งนี้ถูกชี้ให้ฉันเห็นโดยJens Alfkeในฟอรัมของ Apple - ฟังก์ชั่นที่เหมาะสมในการใช้คือ inet_ntop (ดูที่หน้าคนและหรืออ้างถึงบทความinet_ntopนี้โดย Jens
คีย์พจนานุกรมมีรูปแบบ "อินเตอร์เฟส" "/" "ipv4 หรือ ipv6"
#include <ifaddrs.h>
#include <arpa/inet.h>
#include <net/if.h>
#define IOS_CELLULAR @"pdp_ip0"
#define IOS_WIFI @"en0"
//#define IOS_VPN @"utun0"
#define IP_ADDR_IPv4 @"ipv4"
#define IP_ADDR_IPv6 @"ipv6"
- (NSString *)getIPAddress:(BOOL)preferIPv4
{
NSArray *searchArray = preferIPv4 ?
@[ /*IOS_VPN @"/" IP_ADDR_IPv4, IOS_VPN @"/" IP_ADDR_IPv6,*/ IOS_WIFI @"/" IP_ADDR_IPv4, IOS_WIFI @"/" IP_ADDR_IPv6, IOS_CELLULAR @"/" IP_ADDR_IPv4, IOS_CELLULAR @"/" IP_ADDR_IPv6 ] :
@[ /*IOS_VPN @"/" IP_ADDR_IPv6, IOS_VPN @"/" IP_ADDR_IPv4,*/ IOS_WIFI @"/" IP_ADDR_IPv6, IOS_WIFI @"/" IP_ADDR_IPv4, IOS_CELLULAR @"/" IP_ADDR_IPv6, IOS_CELLULAR @"/" IP_ADDR_IPv4 ] ;
NSDictionary *addresses = [self getIPAddresses];
NSLog(@"addresses: %@", addresses);
__block NSString *address;
[searchArray enumerateObjectsUsingBlock:^(NSString *key, NSUInteger idx, BOOL *stop)
{
address = addresses[key];
if(address) *stop = YES;
} ];
return address ? address : @"0.0.0.0";
}
- (NSDictionary *)getIPAddresses
{
NSMutableDictionary *addresses = [NSMutableDictionary dictionaryWithCapacity:8];
// retrieve the current interfaces - returns 0 on success
struct ifaddrs *interfaces;
if(!getifaddrs(&interfaces)) {
// Loop through linked list of interfaces
struct ifaddrs *interface;
for(interface=interfaces; interface; interface=interface->ifa_next) {
if(!(interface->ifa_flags & IFF_UP) /* || (interface->ifa_flags & IFF_LOOPBACK) */ ) {
continue; // deeply nested code harder to read
}
const struct sockaddr_in *addr = (const struct sockaddr_in*)interface->ifa_addr;
char addrBuf[ MAX(INET_ADDRSTRLEN, INET6_ADDRSTRLEN) ];
if(addr && (addr->sin_family==AF_INET || addr->sin_family==AF_INET6)) {
NSString *name = [NSString stringWithUTF8String:interface->ifa_name];
NSString *type;
if(addr->sin_family == AF_INET) {
if(inet_ntop(AF_INET, &addr->sin_addr, addrBuf, INET_ADDRSTRLEN)) {
type = IP_ADDR_IPv4;
}
} else {
const struct sockaddr_in6 *addr6 = (const struct sockaddr_in6*)interface->ifa_addr;
if(inet_ntop(AF_INET6, &addr6->sin6_addr, addrBuf, INET6_ADDRSTRLEN)) {
type = IP_ADDR_IPv6;
}
}
if(type) {
NSString *key = [NSString stringWithFormat:@"%@/%@", name, type];
addresses[key] = [NSString stringWithUTF8String:addrBuf];
}
}
}
// Free memory
freeifaddrs(interfaces);
}
return [addresses count] ? addresses : nil;
}
แก้ไข 1: รหัสอัปเดตเมื่อวันที่ 16 พฤษภาคม 2557 (จุดบกพร่องชี้โดย lhunath ดูความคิดเห็น) ตอนนี้ที่อยู่ Loopback ถูกส่งกลับแล้ว แต่คุณสามารถยกเลิกการใส่ข้อคิดเห็นการทดสอบเพื่อแยกออกด้วยตัวเองได้ง่าย
แก้ไข 2: (โดยบุคคลที่ไม่รู้จัก): ปรับปรุงเพิ่มเติมในวันที่ 13 มีนาคม 2558: ในกรณีที่ผู้ใช้ใช้ VPN (โดยไม่คำนึงถึง WiFi หรือเซลลูลาร์) รหัสก่อนหน้านี้จะล้มเหลว ตอนนี้ใช้งานได้แม้กับการเชื่อมต่อ VPN การเชื่อมต่อ VPN มีความสำคัญเหนือกว่า WiFi และ Cell เพราะนั่นคือวิธีที่อุปกรณ์จัดการ สิ่งนี้ควรใช้ได้กับ Macs เนื่องจากการเชื่อมต่อ VPN บน Mac นั้นใช้ IF utun0 แต่ไม่ได้ทดสอบ
แก้ไข 3: (9/8/2559) จากปัญหาที่ @Qiulang พบ (ดูความคิดเห็น) เกี่ยวกับรหัส VPN (ซึ่งมีคนอื่นเพิ่มเข้ามา) ฉันได้แสดงความคิดเห็นแล้ว หากใครทราบวิธีการระบุผู้ใช้ VPN อย่างชัดเจนโปรดแจ้งความคิดเห็น
addr
ได้รับ NULL บ่อยแค่ไหน? ผู้ใช้ของฉันจะได้รับ NULL เป็นครั้งคราว คุณรู้ไหมว่ามีสาเหตุอะไรบ้าง?
AF_INET
เพื่อตรวจสอบเท่านั้น อาจเป็นสิ่งนี้?
ในไฟล์การนำไปใช้งานของคุณ. m
#import <ifaddrs.h>
#import <arpa/inet.h>
// Get IP Address
- (NSString *)getIPAddress {
NSString *address = @"error";
struct ifaddrs *interfaces = NULL;
struct ifaddrs *temp_addr = NULL;
int success = 0;
// retrieve the current interfaces - returns 0 on success
success = getifaddrs(&interfaces);
if (success == 0) {
// Loop through linked list of interfaces
temp_addr = interfaces;
while(temp_addr != NULL) {
if(temp_addr->ifa_addr->sa_family == AF_INET) {
// Check if interface is en0 which is the wifi connection on the iPhone
if([[NSString stringWithUTF8String:temp_addr->ifa_name] isEqualToString:@"en0"]) {
// Get NSString from C String
address = [NSString stringWithUTF8String:inet_ntoa(((struct sockaddr_in *)temp_addr->ifa_addr)->sin_addr)];
}
}
temp_addr = temp_addr->ifa_next;
}
}
// Free memory
freeifaddrs(interfaces);
return address;
}
โซลูชันที่มีอยู่จำนวนมากพิจารณาเฉพาะอินเทอร์เฟซไร้สายซึ่งใช้ไม่ได้กับการเชื่อมต่อแบบใช้สายผ่านอะแดปเตอร์อีเทอร์เน็ต (เช่นไม่มี Wifi หรือ 3G) ดูโซลูชันล่าสุดนี้ซึ่งพิจารณาที่อยู่ IP ที่ได้รับผ่านอินเทอร์เฟซแบบใช้สายด้วย
iPad: วิธีรับที่อยู่ IP โดยใช้โปรแกรม WIRED (ไม่ใช่ผ่านระบบไร้สาย)
รับที่อยู่ IP โดยใช้ Swift 3:
func getIPAddress() -> String {
var address: String = "error"
var interfaces: ifaddrs? = nil
var temp_addr: ifaddrs? = nil
var success: Int = 0
// retrieve the current interfaces - returns 0 on success
success = getifaddrs(interfaces)
if success == 0 {
// Loop through linked list of interfaces
temp_addr = interfaces
while temp_addr != nil {
if temp_addr?.ifa_addr?.sa_family == AF_INET {
// Check if interface is en0 which is the wifi connection on the iPhone
if (String(utf8String: temp_addr?.ifa_name) == "en0") {
// Get NSString from C String
address = String(utf8String: inet_ntoa((temp_addr?.ifa_addr as? sockaddr_in)?.sin_addr))
}
}
temp_addr = temp_addr?.ifa_next
}
}
// Free memory
freeifaddrs(interfaces)
return address
}
โซลูชันปัจจุบันไม่ส่งคืนอุปกรณ์ en0 บน OS X รหัสต่อไปนี้ใช้ System Configuration Framework เพื่อรับอินเทอร์เฟซจากนั้นใช้ฟังก์ชัน C มาตรฐานเพื่อรับที่อยู่ IP
#include <stdio.h>
#include <string.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <netdb.h>
#include <sys/ioctl.h>
#include <net/if.h>
#define IFT_ETHER 0x6
#include <SystemConfiguration/SCDynamicStore.h>
+(void)getInterfaces
{
SCDynamicStoreRef storeRef = SCDynamicStoreCreate(NULL, (CFStringRef)@"FindCurrentInterfaceIpMac", NULL, NULL);
CFPropertyListRef global = SCDynamicStoreCopyValue (storeRef,CFSTR("State:/Network/Interface"));
id primaryInterface = [(__bridge NSDictionary *)global valueForKey:@"Interfaces"];
for (NSString* item in primaryInterface)
{
if(get_iface_address([item UTF8String]))
{
NSString *ip = [NSString stringWithUTF8String:get_iface_address([item UTF8String])];
NSLog(@"interface: %@ - %@",item,ip);
} else
NSLog(@"interface: %@",item);
}
}
static char * get_iface_address (char *interface)
{
int sock;
uint32_t ip;
struct ifreq ifr;
char *val;
if (!interface)
return NULL;
/* determine UDN according to MAC address */
sock = socket (AF_INET, SOCK_STREAM, 0);
if (sock < 0)
{
perror ("socket");
return NULL;
}
strcpy (ifr.ifr_name, interface);
ifr.ifr_addr.sa_family = AF_INET;
if (ioctl (sock, SIOCGIFADDR, &ifr) < 0)
{
perror ("ioctl");
close (sock);
return NULL;
}
val = (char *) malloc (16 * sizeof (char));
ip = ((struct sockaddr_in *) &ifr.ifr_addr)->sin_addr.s_addr;
ip = ntohl (ip);
sprintf (val, "%d.%d.%d.%d",
(ip >> 24) & 0xFF, (ip >> 16) & 0xFF, (ip >> 8) & 0xFF, ip & 0xFF);
close (sock);
return val;
}
คำตอบนี้ได้รับแรงบันดาลใจจากคำตอบของ @ DavidH ฉันแก้ไขปัญหาบางอย่างแทนที่inet_ntop
ด้วยgetnameinfo
ซึ่งช่วยให้แนวทางที่สะอาดขึ้น โปรดทราบว่าสิ่งนี้ให้พจนานุกรมที่แมปชื่ออินเทอร์เฟซกับอาร์เรย์ของที่อยู่ IP (อินเทอร์เฟซสามารถมี IPv4 และ IPv6 หลายตัวที่เชื่อมโยงกันในทางเทคนิค) ไม่แยกความแตกต่างระหว่าง IPv4 และ IPv6:
// Get all our interface addresses.
struct ifaddrs *ifAddresses;
if (getifaddrs( &ifAddresses ) != 0) {
NSLog( @"Couldn't get interface addresses: %d", errno );
return nil;
}
int error;
char host[MAX( INET_ADDRSTRLEN, INET6_ADDRSTRLEN )];
_ipAddressesByInterface = [NSMutableDictionary dictionaryWithCapacity:8];
for (struct ifaddrs *ifAddress = ifAddresses; ifAddress; ifAddress = ifAddress->ifa_next) {
if (!(ifAddress->ifa_flags & IFF_UP) || (ifAddress->ifa_flags & IFF_LOOPBACK))
// Ignore interfaces that aren't up and loopback interfaces.
continue;
if (ifAddress->ifa_addr->sa_family != AF_INET && ifAddress->ifa_addr->sa_family != AF_INET6)
// Ignore non-internet addresses.
continue;
if ((error = getnameinfo( ifAddress->ifa_addr, ifAddress->ifa_addr->sa_len, host, sizeof( host ), NULL, 0, NI_NUMERICHOST )) != noErr) {
// Couldn't to format host name for this address.
NSLog( @"Couldn't resolve host name for address: %s", gai_strerror( error ) );
continue;
}
NSString *ifName = [NSString stringWithCString:ifAddress->ifa_name encoding: NSUTF8StringEncoding];
NSMutableArray *ifIpAddresses = _ipAddressesByInterface[ifName];
if (!ifIpAddresses)
ifIpAddresses = _ipAddressesByInterface[ifName] = [NSMutableArray arrayWithCapacity:2];
[ifIpAddresses addObject:[NSString stringWithCString:host encoding: NSUTF8StringEncoding]];
}
freeifaddrs( ifAddresses );
return _ipAddressesByInterface;
strf
- เป็นฟังก์ชันตัวช่วยที่คุณมีในรหัสของคุณหรือไม่?
err
และstrf
. คุณสามารถแทนที่strf
ด้วย-stringWithCString:encoding:
. err
เป็นNSLog
wrapper ที่ส่งออกไฟล์ & บรรทัดด้วย github.com/Lyndir/Pearl/blob/master/Pearl/…
คำตอบของ @ DavidH ใช้งานได้ดีจนกระทั่งฉันได้ผลลัพธ์นี้จากเครือข่ายมือถือ 4G:
{
"lo0/ipv4" = "127.0.0.1";
"lo0/ipv6" = "fe80::1";
"pdp_ip0/ipv4" = "10.132.76.168";
"utun0/ipv6" = "fe80::72c3:e25e:da85:b730";
}
ฉันไม่ได้ใช้ VPN ดังนั้นฉันจึงไม่รู้ว่าทำไมฉันถึงมี utun0 / ipv6
- อัปเดต -
ฉันแก้ไขปัญหานี้เพิ่มเติมและพบว่าฉันสามารถรับที่อยู่ VPN ปลอมได้แม้ในเครือข่าย 4G อื่น ๆ (นี่คือข้อบกพร่องของ iOS หรือไม่?)
{
""awdl0/ipv6"" = ""fe80::c018:9fff:feb2:988"";
""en0/ipv6"" = ""fe80::181a:2e43:f91b:db2b"";
""lo0/ipv4"" = ""127.0.0.1"";
""lo0/ipv6"" = ""fe80::1"";
""pdp_ip0/ipv4"" = ""10.48.10.210"";
""utun0/ipv4"" = ""192.168.99.2"";
}
หากฉันใช้ vpn ฉันจะได้รับสิ่งนี้:
{
"lo0/ipv4" = "127.0.0.1";
"lo0/ipv6" = "fe80::1";
"pdp_ip0/ipv4" = "10.49.187.23";
"utun0/ipv6" = "fe80::5748:5b5d:2bf0:658d";
"utun1/ipv4" = "192.168.99.2"; //the real one
}
ดังนั้นจึงเป็นutun1ไม่ใช่utun0
โดยไม่ทราบสาเหตุว่าทำไมฉันจึงต้องปล่อย vpn check :(
---- ปรับปรุง ----
ฉันยกข้อผิดพลาด (28131847) ไปที่ apple และตอบกลับว่า "อินเทอร์เฟซ utun ไม่ใช่ทั้งหมดสำหรับ VPN มีคุณสมบัติระบบปฏิบัติการอื่น ๆ ที่ใช้อินเทอร์เฟซ utun"
แต่เมื่อฉันถามว่าจะรับที่อยู่ IP VPN ที่ถูกต้องได้อย่างไรคำตอบของพวกเขาก็ค่อนข้างผิดหวัง "คุณสามารถไปที่การตั้งค่า -> VPN และดูการกำหนดค่า VPN ของคุณเพื่อดูว่า VPN ใช้งานได้หรือไม่ในบางกรณีคุณสามารถดู ได้กำหนดที่อยู่ IP ไว้ที่นั่นด้วยขณะนี้เรากำลังปิดรายงานข้อบกพร่องนี้ " :(
---- อัปเดต 2016/11/04 ----
ฉันพบปัญหาอีกครั้งและฉันต้องการแก้ไขคำตอบของ @ DavidH เพิ่มเติมเพื่อแก้ไข:
ฉันอยู่ในเครือข่าย 4G และได้รับที่อยู่นี้:
addresses: {
"awdl0/ipv6" = "fe80::98fd:e6ff:fea9:3afd";
"en0/ipv6" = "fe80::8dd:7d92:4159:170e";
"lo0/ipv4" = "127.0.0.1";
"lo0/ipv6" = "fe80::1";
"pdp_ip0/ipv4" = "10.37.212.102";
"utun0/ipv6" = "fe80::279c:ea56:a2ef:d128";
}
ด้วยคำตอบเดิมของเขาฉันจะได้รับ wifi IP fe80 :: 8dd: 7d92: 4159: 170e ซึ่งเป็นของปลอมและการเชื่อมต่อล้มเหลว
ดังนั้นฉันจึงแก้ไขโค้ดให้ชอบ
[searchArray enumerateObjectsUsingBlock:^(NSString *key, NSUInteger idx, BOOL *stop)
{
if ((internetReach.isReachableViaWiFi && [key hasPrefix:IOS_WIFI]) ||
(internetReach.isReachableViaWWAN && [key hasPrefix:IOS_CELLULAR])) {
address = addresses[key];
if(address) *stop = YES;
}
} ];
ทางออกที่ดีสำหรับความรวดเร็วในไฟล์นี้ซึ่งให้รายละเอียดทั้งหมด
ในแอปหนึ่งของฉันฉันต้องการดึงข้อมูลที่อยู่ IP wifi ฉันใช้คำตอบข้างต้นแล้วใน swift 3 เช่นนี้:
let WIFI_IF = "en0"
let UNKNOWN_IP_ADDRESS = ""
var addresses: [AnyHashable: Any] = ["wireless": UNKNOWN_IP_ADDRESS, "wired": UNKNOWN_IP_ADDRESS, "cell": UNKNOWN_IP_ADDRESS]
var interfaces: UnsafeMutablePointer<ifaddrs>? = nil
var temp_addr: UnsafeMutablePointer<ifaddrs>? = nil
var success: Int = 0
success = Int(getifaddrs(&interfaces))
if success == 0 {
temp_addr = interfaces
while temp_addr != nil {
if temp_addr?.pointee.ifa_addr == nil {
continue
}
if temp_addr?.pointee.ifa_addr.pointee.sa_family == UInt8(AF_INET) {
if (String(utf8String: (temp_addr?.pointee.ifa_name)!) == WIFI_IF) {
addresses["wireless"] = String(utf8String: inet_ntoa(((temp_addr?.pointee.ifa_addr as? sockaddr_in)?.sin_addr)!))
}
}
temp_addr = temp_addr?.pointee.ifa_next
}
}
ในรหัสนี้มันเกิดปัญหาเพราะผมมีการตรวจสอบในแต่ละคำสั่งฉันได้ใช้เป็นตัวเลือกด้วยnil
?
ดังนั้นจึงเป็นการดีกว่าสำหรับฉันที่จะใช้ไฟล์ที่เชื่อมโยงในชั้นเรียนของฉัน มันกลายเป็นเรื่องง่ายสำหรับฉันที่จะตรวจสอบตอนนี้เช่น:
class func getWifiIPAddress() -> String {
var wifiIp = ""
let WIFI_IF = "en0"
let allInterface = Interface.allInterfaces()
for interf in allInterface {
if interf.name == WIFI_IF {
if let address = interf.address {
if address.contains(".") {
wifiIp = address
break
}
}
}
}
return wifiIp
}
ฉันได้แยกวิเคราะห์สตริง"."
เนื่องจาก Interface Class ส่งคืนสองอินเทอร์เฟซใน iPhone ของฉันสำหรับที่en0
อยู่เช่น "fb00 ::" และที่อยู่เช่น "101.10.1.1"
ฉันสร้างไฟล์ง่ายๆสำหรับรับที่อยู่ IP ฉันใช้วิธีแก้ปัญหานี้จากคำตอบของ @lundhjem, @ DavidH และ @ Ihunath พิจารณาการเชื่อมต่อแบบใช้สาย ฉันยังไม่ได้รวม VPN ไว้ในโซลูชันนี้
PCNetwork.h
#import <Foundation/Foundation.h>
NS_ASSUME_NONNULL_BEGIN
@interface PCNetwork : NSObject
+ (NSString *)getIPAddress; // Prefers IPv4
+ (NSString *)getIPAddress:(BOOL)preferIPv4;
+ (NSDictionary *)getIPAddresses;
@end
NS_ASSUME_NONNULL_END
PCNetwork.m
#import "PCNetwork.h"
#include <ifaddrs.h>
#include <arpa/inet.h>
#include <net/if.h>
#define IP_UNKNOWN @"0.0.0.0"
#define IP_ADDR_IPv4 @"ipv4"
#define IP_ADDR_IPv6 @"ipv6"
@implementation PCNetwork
#pragma mark - IP
+ (NSString *)getIPAddress {
return [self getIPAddress:YES];
}
+ (NSString *)getIPAddress:(BOOL)preferIPv4 {
NSArray *searchArray = [self getAllIFSearchArray:preferIPv4];
NSDictionary *addresses = [self getIPAddresses];
DLog(@"addresses: %@", addresses);
__block NSString *address = nil;
[searchArray enumerateObjectsUsingBlock:^(NSString *key, NSUInteger idx, BOOL *stop) {
address = addresses[key];
if(address) *stop = YES;
}];
return address ?: IP_UNKNOWN;
}
+ (NSDictionary *)getIPAddresses {
NSMutableDictionary *addresses = [NSMutableDictionary dictionary];
struct ifaddrs *interfaces;
BOOL success = !getifaddrs(&interfaces); // Retrieve the current interfaces : returns 0 on success
if (success) {
struct ifaddrs *temp_interface;
for (temp_interface = interfaces; temp_interface; temp_interface = temp_interface->ifa_next) { // Loop through linked list of interfaces
if (!(temp_interface->ifa_flags & IFF_UP) || (temp_interface->ifa_flags & IFF_LOOPBACK)) { // Ignore interfaces that aren't up and loopback interfaces.
continue;
}
if (!temp_interface->ifa_addr) {
continue;
}
const struct sockaddr_in *temp_addr = (const struct sockaddr_in*)temp_interface->ifa_addr;
if (temp_addr->sin_family == AF_INET || temp_addr->sin_family == AF_INET6) {
char addrBuf[MAX(INET_ADDRSTRLEN, INET6_ADDRSTRLEN)];
NSString *name = [NSString stringWithUTF8String:temp_interface->ifa_name];
NSString *type = nil;
if (temp_addr->sin_family == AF_INET) {
if (inet_ntop(AF_INET, &temp_addr->sin_addr, addrBuf, INET_ADDRSTRLEN)) {
type = IP_ADDR_IPv4;
}
} else {
const struct sockaddr_in6 *addr6 = (const struct sockaddr_in6*)temp_interface->ifa_addr; // AF_INET6
if (inet_ntop(AF_INET6, &addr6->sin6_addr, addrBuf, INET6_ADDRSTRLEN)) {
type = IP_ADDR_IPv6;
}
}
if (type) {
NSString *key = [NSString stringWithFormat:@"%@/%@", name, type];
addresses[key] = [NSString stringWithUTF8String:addrBuf];
}
}
}
freeifaddrs(interfaces); // Free memory
}
return addresses.count ? addresses.copy : nil;
}
#pragma mark - Inter Frame Spacing
+ (NSArray *)getAllIFSearchArray:(BOOL)preferIPv4 {
NSArray *KNOWN_WIFI_IFS = @[@"en0"];
NSArray *KNOWN_WIRED_IFS = @[@"en1",@"en2",@"en3",@"en4"];
NSArray *KNOWN_CELL_IFS = @[@"pdp_ip0",@"pdp_ip1",@"pdp_ip2",@"pdp_ip3"];
NSMutableArray *searchArray = [NSMutableArray array];
// Add wifi
[searchArray addObjectsFromArray:[self getIFSearchArrayWith:KNOWN_WIFI_IFS preferIPv4:preferIPv4]];
// Add cell
[searchArray addObjectsFromArray:[self getIFSearchArrayWith:KNOWN_CELL_IFS preferIPv4:preferIPv4]];
// Add wired
[searchArray addObjectsFromArray:[self getIFSearchArrayWith:KNOWN_WIRED_IFS preferIPv4:preferIPv4]];
return searchArray.copy;
}
+ (NSArray *)getIFSearchArrayWith:(NSArray *)iFList preferIPv4:(BOOL)preferIPv4 {
NSMutableArray *searchArray = [NSMutableArray array];
for (NSString *iFType in iFList) {
if (preferIPv4) {
[searchArray addObject:[NSString stringWithFormat:@"%@/%@", iFType, IP_ADDR_IPv4]];
[searchArray addObject:[NSString stringWithFormat:@"%@/%@", iFType, IP_ADDR_IPv6]];
} else {
[searchArray addObject:[NSString stringWithFormat:@"%@/%@", iFType, IP_ADDR_IPv6]];
[searchArray addObject:[NSString stringWithFormat:@"%@/%@", iFType, IP_ADDR_IPv4]];
}
}
return searchArray.copy;
}
@end
ใน iOS 13.4.1 ไม่ทำงานสำหรับฉัน ฉันใช้การแก้ไขนี้
+ (NSString *)getIPAddress{
NSArray *searchArray =
@[ IOS_VPN @"/" IP_ADDR_IPv4, IOS_VPN @"/" IP_ADDR_IPv6, IOS_WIFI @"/" IP_ADDR_IPv4, IOS_WIFI @"/" IP_ADDR_IPv6, IOS_4_3G @"/" IP_ADDR_IPv4, IOS_4_3G @"/" IP_ADDR_IPv6, IOS_CELLULAR @"/" IP_ADDR_IPv4, IOS_CELLULAR @"/" IP_ADDR_IPv6];
__block NSDictionary *addresses = [self getIPAddressArray];
__block NSString *address;
[searchArray enumerateObjectsUsingBlock:^(NSString *key, NSUInteger idx, BOOL *stop)
{
address = addresses[key];
if ([key rangeOfString:@"ipv6"].length > 0 && ![[NSString stringWithFormat:@"%@",addresses[key]] hasPrefix:@"(null)"] ) {
if ( ![addresses[key] hasPrefix:@"fe80"]) {
// isIpv6 = YES;
*stop = YES;
}
}else{
if([self isValidatIP:address]) {
*stop = YES;
}
}
} ];
return address ? address : @"error";
}
+ (NSString *)getIPType{
NSString *ipAddress = [self getIPAddress];
if ([self isValidatIP:ipAddress]) {
return @"04";//ipv4
}else{
return @"06";//ipv6
}
}
+ (NSDictionary *)getIPAddressArray{
NSMutableDictionary *addresses = [NSMutableDictionary dictionaryWithCapacity:8];
// retrieve the current interfaces - returns 0 on success
struct ifaddrs *interfaces;
if(!getifaddrs(&interfaces)) {
// Loop through linked list of interfaces
struct ifaddrs *interface;
for(interface=interfaces; interface; interface=interface->ifa_next) {
if(!(interface->ifa_flags & IFF_UP) /* || (interface->ifa_flags & IFF_LOOPBACK) */ ) {
continue; // deeply nested code harder to read
}
const struct sockaddr_in *addr = (const struct sockaddr_in*)interface->ifa_addr;
char addrBuf[ MAX(INET_ADDRSTRLEN, INET6_ADDRSTRLEN) ];
if(addr && (addr->sin_family==AF_INET || addr->sin_family==AF_INET6)) {
NSString *name = [NSString stringWithUTF8String:interface->ifa_name];
NSString *type;
if(addr->sin_family == AF_INET) {
if(inet_ntop(AF_INET, &addr->sin_addr, addrBuf, INET_ADDRSTRLEN)) {
type = IP_ADDR_IPv4;
}
} else {
const struct sockaddr_in6 *addr6 = (const struct sockaddr_in6*)interface->ifa_addr;
if(inet_ntop(AF_INET6, &addr6->sin6_addr, addrBuf, INET6_ADDRSTRLEN)) {
type = IP_ADDR_IPv6;
}
}
if(type) {
NSString *key = [NSString stringWithFormat:@"%@/%@", name, type];
addresses[key] = [NSString stringWithUTF8String:addrBuf];
}
}
}
// Free memory
freeifaddrs(interfaces);
}
return [addresses count] ? addresses : nil;
}
+ (BOOL)isValidatIP:(NSString *)ipAddress {
if (ipAddress.length == 0) {
return NO;
}
NSString *urlRegEx = @"^([01]?\\d\\d?|2[0-4]\\d|25[0-5])\\."
"([01]?\\d\\d?|2[0-4]\\d|25[0-5])\\."
"([01]?\\d\\d?|2[0-4]\\d|25[0-5])\\."
"([01]?\\d\\d?|2[0-4]\\d|25[0-5])$";
NSError *error;
NSRegularExpression *regex = [NSRegularExpression regularExpressionWithPattern:urlRegEx options:0 error:&error];
if (regex != nil) {
NSTextCheckingResult *firstMatch=[regex firstMatchInString:ipAddress options:0 range:NSMakeRange(0, [ipAddress length])];
if (firstMatch) {
NSRange resultRange = [firstMatch rangeAtIndex:0];
NSString *result=[ipAddress substringWithRange:resultRange];
//输出结果
NSLog(@"%@",result);
return YES;
}
}
return NO;
}