iOS / macOS에서 프로그래밍 방식으로 내 IP 주소를 얻는 방법은 무엇입니까?


124

프로그래밍 방식으로 내 iPad의 IP 주소를 얻고 싶습니다. 내 IPv4 (및 IPv6) 주소가 무엇인지 확인하기 위해 네트워킹 하위 시스템을 쿼리하려면 어떻게해야합니까?

PS : 어떻게 든 IPv6를 비활성화 할 수 있습니까?


14
위의 'PS'와 관련하여 다른 사람의 장치에서 프로그래밍 방식으로 IPv6를 비활성화하지 마십시오. 그냥 무례합니다.
Jeremy Visser 2013-08-16

IPv6를 비활성화 할 수 없습니다. 필수입니다. 실제로 iOS 앱은 IPv6를 지원해야합니다.
Michael Hampton

답변:


132

다음 코드는 iOS 또는 OSX 장치에서 모든 IPv4 및 IPv6 주소를 찾습니다. 첫 번째 getIPAddress방법은이 답변의 이전 코드처럼 다소간 작동합니다. 하나 또는 다른 유형의 주소를 선호 할 수 있으며 항상 셀룰러보다 WIFI를 선호합니다 (분명히 이것을 변경할 수 있음).

더 흥미롭게도 발견 된 모든 주소의 사전을 반환하고 not up인터페이스의 주소를 건너 뛰 거나와 관련된 주소를 반환 할 수 있습니다 loopback. 이 주제에 대한 이전 코드와 다른 솔루션은 IPv6를 올바르게 디코딩하지 않습니다 (inet_ntoa는이를 처리 할 수 ​​없습니다). 이것은 Apple 포럼에서 Jens Alfke 가 저에게 지적했습니다 . 적절한 기능은 inet_ntop입니다 (맨 페이지를 보거나 Jens가 제공하는 이 inet_ntop 기사를 참조하십시오 .

사전 키의 형식은 "interface" "/" "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;
}

EDIT1 : 코드가 2014 년 5 월 16 일에 업데이트되었습니다 (Lhunath가 지적한 버그, 주석 참조). 이제 루프백 주소가 반환되었지만 테스트의 주석 처리를 제거하여 직접 제외 할 수 있습니다.

EDIT2 : (알 수없는 사람에 의해) : 2015 년 3 월 13 일 추가 개선 : 사용자가 VPN을 사용하는 경우 (WiFi 또는 셀룰러를 통해) 이전 코드가 실패했을 것입니다. 이제 VPN 연결에서도 작동합니다. VPN 연결은 장치가 처리하는 방식이므로 WiFi 및 셀보다 우선합니다. Mac의 VPN 연결도 IF utun0을 사용하지만 테스트되지 않았기 때문에 Mac에서도 작동합니다.

EDIT3 : (2016 년 9 월 8 일) VPN 코드 (다른 사람이 추가 한)로 @Qiulang (댓글 참조)이 경험 한 문제를 감안할 때 주석 처리했습니다. 사용자 VPN을 지정하는 방법을 확실히 아는 사람이 있으면 댓글을 달아주세요.


얼마나 자주 addrNULL을 얻습니까? 내 사용자는 때때로 NULL을 얻습니다. 가능한 이유가 무엇인지 알고 있습니까?
HelmiB

AF_INET확인 용도로만 사용 하고 있습니다. 이것이 될 수 있습니까?
HelmiB

1
모르겠지만 사용자가 IPV6 네트워크에있을 수 있다는 것은 확실합니다.
David H

2
이것은 3G로 완성되므로 "정답"이어야합니다. 업데이트 해주셔서 감사합니다.
palme 2013-09-20

1
IPv6에서는 이것이 제대로 작동하지 않는다고 생각합니다. inet_ntoa 함수는 IPv4 주소를 사용하므로 sa_type == AF_INET6 인 경우 IPv6 주소를 가져와 IPv4로 타입 캐스팅하고 문자열로 변환합니다 (기본적으로 128 비트의 상위 32 비트에서 주소.)
Jens Alfke 2013 년

88

구현 파일 .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;

} 

1
인터페이스 목록에 en0 인터페이스가 표시되지 않으므로 오류 만 반환합니다. 뭔가 변경되었는지 확실하지 않지만 iOS 5.x에서 확실히 작동하지 않습니다
wuf810

11
아래를 보면 WIFI가 꺼져있는 경우 셀 (3G) 주소를 반환하는 약간 수정 된 코드가 있습니다.
David H

1
다음 코드는 en0의 IPv4 주소 만 제공합니다. IPv6은 어떻습니까? 누군가 그것을 검색하는 방법에 대한 코드 샘플을 줄 수 있습니까?
Oded Regev

2
이것은 장치가 Wi-Fi에 연결되지 않고 셀룰러 네트워크에 연결되어있을 때 IP 주소를 찾지 못합니다
Mapedd

1
if ([[NSString stringWithUTF8String : temp_addr-> ifa_name] isEqualToString : @ "en0"]) 아래의 if 조건을 수정합니다. if ([[NSString stringWithUTF8String : temp_addr-> ifa_name] isEqualToString : @ "en0"] || [[NSString stringWithUTF8String : temp_addr-> ifa_name] isEqualToString : @ "pdp_ip0"]) WIFI 장치에 연결되지 않은 IP .. 도착
라주

4

기존의 많은 솔루션은 이더넷 어댑터 (예 : Wi-Fi 또는 3G 없음)를 통한 유선 연결에는 작동하지 않는 무선 인터페이스 만 고려합니다. 유선 인터페이스를 통해 얻은 IP 주소도 고려하는이 ​​최신 솔루션을 참조하십시오.

iPad : 프로그래밍 방식으로 WIRED IP 주소를 얻는 방법 (무선을 통하지 않음)


우수한! 조만간 위의 코드에 이것을 추가 할 것입니다. en1은 무엇입니까-알고 있습니까?
David H

1
난 몰라,하지만 난 그게 인터페이스 엔 다른 같은 AF_INET 가족이 아니다 통지를했다
lundhjem

1
@DavidH는 최근에 이더넷 IP가 특정 iPad의 en1에 표시되었으므로 특정 시나리오에서 AF_INET 제품군의 구성원이기도 ​​한 것으로 보입니다. 인터페이스도 확인해야합니다.
lundhjem

3

Swift 3을 사용하여 IP 주소 가져 오기 :

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
}

1

현재 솔루션은 OS X에서 en0 장치를 반환하지 않습니다. 다음 코드는 시스템 구성 프레임 워크를 사용하여 인터페이스를 가져온 다음 표준 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;
}

그대로 슬프게도, SCDynamicStoreCreate은 iOS에서 사용할 수 없습니다 : SCDynamicStoreCopyValue
알렉스 Zavatone

1

이 답변은 @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-그것이 당신의 코드에있는 도우미 함수인가?
David H

예, 죄송합니다. 위 코드에는 몇 가지 도우미가 있습니다. errstrf. 당신은 대체 할 수 있습니다 strf-stringWithCString:encoding:. 파일 및 라인도 출력 err하는 NSLog래퍼입니다. github.com/Lyndir/Pearl/blob/master/Pearl/…
lhunath

1

@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을 사용했는지 모르겠습니다.

--- 업데이트 됨 ---

이 문제를 추가로 디버깅하고 다른 4G 네트워크에서도 가짜 VPN 주소를 얻을 수 있음을 발견했습니다 (이 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
}

따라서 utun0이 아닌 utun1입니다.

왜 VPN 검사를 중단해야하는지 알지 못하고 :(

---- 업데이트 ----

Apple에 버그 (28131847)를 제기하고 "모든 utun 인터페이스가 VPN 용은 아닙니다. utun 인터페이스를 사용하는 다른 OS 기능이 있습니다."라고 답했습니다.

그러나 내가 유효한 VPN IP 주소를 얻는 방법을 물었을 때, 그들의 대답은 다소 실망 스러웠습니다. "설정-> 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;
     }
 } ];

VPN 문제에 대한 내부 포럼에 게시했는데 Apple 엔지니어가 도움을 제공했습니다. 나는 당신이 맥 닷컴에서 오프라인 dhoerl에 연락해야합니다
David H

1

모든 세부 정보를 제공하는 이 파일의 신속한 솔루션입니다 .

내 앱 중 하나에서 Wi-Fi IP 주소를 가져와야합니다. 위의 답변을 다음과 같이 신속한 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
}

"."인터페이스 클래스가 en0"fb00 ::"과 같은 주소와 "101.10.1.1"과 같은 주소에 대해 내 iPhone에서 두 개의 인터페이스를 반환 하기 때문에 문자열을 구문 분석 했습니다.


1
잠재적 인 솔루션에 대한 링크는 항상 환영합니다. 그러나 링크 주변에 컨텍스트추가 하여 동료 사용자가 그것이 무엇인지, 왜 거기에 있는지 알 수 있도록하십시오. 대상 사이트에 연결할 수 없거나 영구적으로 오프라인 상태가되는 경우를 대비하여 항상 중요한 링크에서 가장 관련성이 높은 부분을 인용하십시오. 되는 것을 고려 보다 외부 사이트로의 링크보다 거의 것은 에 관해서는 가능한 이유가 왜 그리고 어떻게 어떤 답변 삭제입니까? .
Paul Roub 2017-06-24

1
Ok가 그에 따라 더 나은 이해를 위해 도움이 될 것입니다.
Max

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

0

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;
}
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.