iOS / macOSでプログラムでIPアドレスを取得する方法


124

iPadのIPアドレスをプログラムで取得したいのですが。ネットワークサブシステムにクエリを実行して、自分のIPv4(およびIPv6)アドレスを確認するにはどうすればよいですか?

PS:どういうわけかIPv6を無効にできますか?


14
上記の「PS」に関して、誰かのデバイスでIPv6をプログラムで無効にしないでください。それはただの失礼です。
Jeremy Visser、2011

IPv6を無効にすることはできません。それが必須です。実際、iOSアプリはIPv6をサポートしている必要があります。
マイケルハンプトン

回答:


132

次のコードは、iOSまたはOSXデバイス上のすべてのIPv4およびIPv6アドレスを検索します。最初のgetIPAddress方法は、この回答の古いコードとほぼ同じように機能します。どちらか一方のタイプのアドレスを優先でき、常にセルラーよりもWIFIを優先します(明らかにこれを変更できます)。

さらに興味深いことに、見つかったすべてのアドレスのディクショナリを返し、not upインターフェイスのアドレスをスキップするか、に関連付けられたアドレスを返すことができますloopback。このトピックに関する前のコードと他のソリューションは、IPv6を正しくデコードしません(inet_ntoaはそれらを処理できません)。これはAppleフォーラムでJens Alfkeによって私に指摘されました-使用する適切な関数はinet_ntopです(manページを参照するか、またはJensによって提供されたこのinet_ntopの記事を参照してください)。

辞書キーの形式は、「インターフェース」「/」「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:(9/8/2016)VPNコード(他の誰かが追加したもの)で@Qiulang(コメントを参照)が経験した問題を考慮して、コメントアウトしました。誰もがユーザーVPNの指定方法を明確に知っている場合は、コメントを添えてお知らせください。


どのくらいの頻度でaddrNULLになりますか?ユーザーがNULLになる場合があります。考えられる理由を知っていますか?
HelmiB

AF_INET確認だけに使っています。これは?
HelmiB

1
わかりませんが、ユーザーがIPV6ネットワークに接続している可能性は確かです。
David H

2
これは3Gで完全であるため、「正しい」答えになるはずです。更新していただきありがとうございます。
Palme

1
これはIPv6では正しく動作しないと思います。inet_ntoa関数はIPv4アドレスを取得するため、sa_type == AF_INET6の場合、IPv6アドレスを取得してIPv4に型キャストし、それを文字列に変換します(基本的に128ビットの上位32ビットから)住所)
イェンス・アルフケ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インターフェースはインターフェースリストに表示されないため、エラーを返します。何かが変更されたかどうかは
わかり

11
下を見ると、WIFIがオフの場合にセル(3G)アドレスを返すわずかに変更されたコードが見つかります。
David H

1
次のコードは、en0のIPv4アドレスのみを提供します。IPv6についてはどうですか?誰かがそれを取得する方法のコードサンプルを提供できますか?
Oded Regev 2012年

2
デバイスがwifiに接続されていない場合、これはIPアドレスを見つけられませんが、セルラーネットワークに接続されます
Mapedd

1
以下のif条件を変更しますif([[[NSString stringWithUTF8String:temp_addr-> ifa_name] isEqualToString:@ "en0"])To if([[[NSString stringWithUTF8String:temp_addr-> ifa_name] isEqualToString:@ "en0"] || [[NSString stringWithUTF8String:temp_addr-> ifa_name] isEqualToString: "pdp_ip0" @])デバイスは、WIFIに接続されていない時にIPを取得するには...
ラジュ

4

多くの既存のソリューションは、ワイヤレスインターフェースのみを考慮しており、イーサネットアダプターを介した有線接続では機能しません(つまり、Wifiまたは3Gでは機能しません)。有線インターフェースを介して取得されたIPアドレスも考慮した、この最近のソリューションを参照してください。

iPad:プログラムでIPアドレスを取得する方法(ワイヤレス経由ではなく)


優れた!これを上のコードにすぐに追加します。en1とは-知っていますか?
デビッドH

1
私はそうしませんが、他のenインターフェースのようなAF_INETファミリーではないことに気付きました
lundhjem

1
@DavidHは最近、特定のiPadのen1でイーサネットIPが表示されているため、特定のシナリオでは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
}

それがあるのでutun1ませutun0

なぜ私はVPNチェックをドロップしなければならないのかわからない:(

----更新----

私はアップルにバグ(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の問題について社内フォーラムに投稿しました。アップルのエンジニアが手助けを申し出ました。Mac dot comでオフラインのドールに連絡する必要があります
David H

1

すべての詳細を提供するこのファイルの迅速な解決策。

私のアプリの1つで、wifi IPアドレスを取得する必要があります。私は上記の回答を、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
}

"."インターフェースクラスが私のiPhoneでen0「fb00 ::」のようなアドレスと「101.10.1.1」のようなアドレスの2つのインターフェースを返すため、文字列を解析しました


1
可能性のあるソリューションへのリンクはいつでも歓迎しますが、リンクの前後にコンテキスト追加して、他のユーザーがそれが何であるか、なぜそこにあるのかを理解できるようにしてください。ターゲットサイトに到達できない、または永久にオフラインになる場合に備えて、常に重要なリンクの最も関連性の高い部分を引用してください。外部サイトへのリンク以上のものであることが、なぜ、どのようにしていくつかの回答が削除されるのかについて考えられる理由であることを考慮に入れてください
ポールルーブ2017年

1
理解を深めるのに役立つので、適宜更新します
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.