IP adresimi programlı olarak iOS / macOS'ta nasıl alabilirim?


124

İPad'imin IP adresini programlı olarak almak istiyorum. IPv4 (ve IPv6) adreslerimin ne olduğunu öğrenmek için ağ alt sistemini nasıl sorgulayabilirim?

Not: IPv6'yı bir şekilde devre dışı bırakabilir miyim?


14
Yukarıdaki 'PS'nizle ilgili olarak, lütfen birinin cihazında IPv6'yı programlı olarak devre dışı bırakmayın. Bu çok kaba.
Jeremy Visser

IPv6'yı devre dışı bırakamazsınız. Zorunludur. Aslında, iOS uygulamanız IPv6'yı desteklemelidir.
Michael Hampton

Yanıtlar:


132

Aşağıdaki kod, bir iOS veya OSX cihazındaki tüm IPv4 ve IPv6 adreslerini bulur. İlk getIPAddressyöntem, bu yanıttaki eski kod olarak az ya da çok davranır: birini ya da diğerini tercih edebilirsiniz ve her zaman WIFI'ı hücresel olarak tercih eder (tabii ki bunu değiştirebilirsiniz).

Daha da ilginci, bulunan tüm adreslerin bir sözlüğünü döndürebilir, not uparayüzler için adresleri veya ilişkili adresleri atlayabilir loopback. Önceki kod ve bu konudaki diğer çözümler IPv6'nın kodunu doğru bir şekilde çözmeyecektir (inet_ntoa bunlarla başa çıkamaz). Bu bana bir Apple forumunda Jens Alfke tarafından belirtildi - kullanılacak uygun işlev inet_ntop'tur (man sayfasına bakın veya Jens tarafından sağlanan bu inet_ntop makalesine bakın .

Sözlük anahtarları "arabirim" "/" "ipv4 veya ipv6" biçimindedir.

#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;
}

DÜZENLEME1: Kod 16 Mayıs 2014'te güncellendi (lhunath tarafından belirtilen hata, yorumlara bakın). Geri döngü adresleri şimdi geri döndü, ancak testi kendi başınıza hariç tutmak için yorumunuzu kaldırmanız kolay.

DÜZENLEME2: (bilinmeyen bir kişi tarafından): 13 Mart 2015'te daha da iyileştirildi: Kullanıcının bir VPN kullanması durumunda (WiFi veya Hücresel üzerinden bağımsız olarak), önceki kod başarısız olacaktı. Artık VPN bağlantılarıyla bile çalışıyor. VPN bağlantılarına WiFi ve Hücreye göre öncelik verilir çünkü cihaz bu şekilde işler. Mac'teki VPN bağlantısı da IF utun0 kullandığından ancak test edilmediğinden, bu Mac'ler için bile çalışmalıdır.

DÜZENLEME3: (9/8/2016) @Qiulang'ın VPN koduyla (başka birinin eklediği) yaşadığı sorunlar (yorumlara bakın) göz önüne alındığında, bunu yorumladım. Bir kullanıcı VPN'i nasıl belirleyeceğini kesin olarak bilen biri varsa, lütfen bir yorumda bulunun.


ne sıklıkla addrNULL olur? kullanıcılarım bazen NULL alır. olası nedenlerin ne olduğunu biliyor musun?
HelmiB

Sadece AF_INETkontrol etmek için kullanıyorum . bu olabilir mi?
HelmiB

1
Bilmiyorum, ancak kullanıcılarınızın bir IPV6 ağında olabileceği kesin.
David H

2
3G ile tamamlandığı için bu "doğru" cevap olmalıdır. Güncelleme için teşekkürler.
palme

1
Bunun IPv6 ile doğru çalıştığını düşünmüyorum. İnet_ntoa işlevi bir IPv4 adresi alır, bu nedenle sa_type == AF_INET6 olduğu durumda, IPv6 adresini alıp IPv4'e yazarsınız ve bunu bir dizeye çevirirsiniz (temel olarak 128 bitin yüksek 32 bitinden adres.)
Jens Alfke

88

Uygulama dosyanızda .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
Arabirimler listesinde en0 arabirimi görünmez, bu nedenle yalnızca hata verir. Bir şeyin değişip değişmediğinden emin değilim, ancak kesinlikle benim için iOS
5.x'te çalışmıyor

11
Aşağıya bakarsanız, WIFI kapalıysa hücre (3G) adresini döndüren biraz değiştirilmiş bir kod bulacaksınız.
David H

1
Aşağıdaki kod yalnızca en0'ın IPv4 adresini verir. IPv6 ne olacak? Birisi onu nasıl geri alacağına dair bir kod örneği verebilir mi?
Oded Regev

2
Bu, cihaz kablosuz ağa bağlı olmadığında, ancak hücresel ağa bağlı olduğunda ip adresini bulamıyor
Mapedd

1
Aşağıdaki if koşulunu değiştirin: ([[NSString stringWithUTF8String: temp_addr-> ifa_name] isEqualToString: @ "en0"]) To if ([[NSString stringWithUTF8String: temp_addr-> ifa_name] isEqualToString] || [@ "en0 stringWithUTF8String: temp_addr-> ifa_name] isEqualToString: @ "pdp_ip0"]) cihaz WIFI'a bağlı değilken IP'yi almak için ..
Raju

4

Mevcut çözümlerin birçoğu yalnızca, bir Ethernet adaptörü aracılığıyla (yani Wifi veya 3G olmadan) kablolu bağlantılar için çalışmayan kablosuz arayüzleri dikkate alır; Kablolu arayüzler aracılığıyla elde edilen IP adreslerini de dikkate alan bu daha yeni çözüme bakın.

iPad: IP adresini programlı olarak KABLOLU olarak alma (kablosuz değil)


Mükemmel! Bunu yakında yukarıdaki koduma ekleyeceğim. En1 nedir - biliyor musunuz?
David H

1
Bilmiyorum, ama diğer en arayüzler gibi AF_INET ailesi olmadığını fark ettim
lundhjem

1
@DavidH son zamanlarda ethernet IP'si belirli iPad'lerde en1'de gösteriliyor, bu nedenle belirli senaryolarda AF_INET ailesinin bir üyesi olduğu anlaşılıyor. Bu arayüzü de kontrol etmelisiniz.
lundhjem

3

Swift 3'ü kullanarak IP adresini alın:

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

Mevcut çözüm OS X'te en0 cihazını döndürmez, aşağıdaki kod arabirimleri almak için Sistem Yapılandırma Çerçevesini kullanır ve ardından IP adresini almak için standart C işlevlerini kullanır.

#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;
}

Maalesef SCDynamicStoreCreate şu şekilde iOS'ta kullanılamıyor: SCDynamicStoreCopyValue
Alex Zavatone

1

Bu cevap, @ DavidH'nin cevabından esinlenmiştir. Ben, bazı sorunlar giderildi yerini inet_ntopile getnameinfohangi bir temizleyici yaklaşımını verir. Bunun, bir arabirim adını bir dizi IP adresiyle eşleştiren bir sözlük verdiğini unutmayın (bir arabirim, teknik olarak kendisiyle ilişkilendirilmiş birden çok IPv4 ve IPv6'ya sahip olabilir). IPv4 ve IPv6 arasında ayrım yapmaz:

  // 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;

Hiç görmedim strf- bu kodunuzda sahip olduğunuz yardımcı bir işlev mi?
David H

Evet, üzgünüm, yukarıdaki kodda birkaç yardımcı var. errve strf. Sadece yerini alabilir strfile -stringWithCString:encoding:. dosya ve satırı da çıkaran errbir NSLogsarmalayıcıdır. github.com/Lyndir/Pearl/blob/master/Pearl/...
lhunath

1

@ DavidH'nin cevabı, bu sonucu bazı 4G hücresel ağlardan alana kadar iyi çalışıyor:

{
    "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 kullanmıyorum, bu yüzden neden utun0 / ipv6'ya sahip olduğum hakkında hiçbir fikrim yok.

--- Güncellenmiş ---

Bu sorunu daha fazla ayıkladım ve diğer 4G ağlarında bile sahte bir vpn adresi alabileceğimi fark ettim (bu iOS hatası mı ??),

{
    ""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"";
}

Eğer vpn kullandıysam şunu alacağım:

{
    "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
}

Yani utun1 DEĞİL utun0

Neden vpn kontrolünü bırakmam gerektiğini anlamadan :(

---- Güncelleme ----

Apple'a bir hata (28131847) oluşturdum ve "Tüm utun arabirimleri VPN için değildir. Utun arabirimlerini kullanan başka işletim sistemi özellikleri vardır."

Ancak geçerli bir vpn IP adresini nasıl alacağımı sorduğumda, yanıtları hayal kırıklığına uğradı, "Ayarlar -> VPN'e gidebilir ve VPN'nin etkin olup olmadığını görmek için VPN yapılandırmanıza bakabilirsiniz. Bazı durumlarda, orada da IP adresi atanmış. Şimdi bu hata raporunu kapatıyoruz. " :(

---- güncelleme 2016/11/04 ---

Soruna tekrar çarptım ve düzeltmek için @ DavidH'nin yanıtını daha da değiştirmem gerekiyor:

4G ağındaydım ve şu adresi aldım:

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";
}

Orijinal cevabıyla, sahte olan ve bağlantı başarısız olan fe80 :: 8dd: 7d92: 4159: 170e wifi IP'sini alacağım.

Bu yüzden kodu beğenecek şekilde değiştirdim,

[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 sorunu hakkında dahili forumlarda yayınladım, Apple mühendisi yardım teklif etti. Benimle mac dot com'da çevrimdışı dhoerl ile iletişime geçmeniz gerekiyor
David H

1

Tüm detayları sunan bu dosyada hızlı için harika çözüm .

Uygulamamdan birinde wifi IP adresini almam gerekiyor. Yukarıdaki cevapları hızlı 3'te şöyle kullandım:

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
   }
}

Bu kodda, nilisteğe bağlı olarak kullandığım her ifadeyi kontrol etmem gerektiğinden çöküyor ?. Bu yüzden sınıfımda verilen bağlantılı dosyayı kullanmam daha iyi. Şimdi şu şekilde kontrol etmek benim için kolay hale geliyor:

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
}

İçin dizeyi ayrıştırdım "."çünkü Arabirim Sınıfı iPhone'umda en0"fb00 ::" gibi adres ve "101.10.1.1" gibi adres için iki arabirim döndürüyor


1
Potansiyel bir çözüme bağlantı her zaman memnuniyetle karşılanır, ancak lütfen bağlantının etrafına bağlam ekleyin, böylece diğer kullanıcılarınız bunun ne olduğu ve neden orada olduğu konusunda fikir sahibi olur. Hedef sitenin erişilemez olması veya kalıcı olarak çevrimdışı olması durumunda, her zaman önemli bir bağlantının en alakalı bölümünü alıntılayın. Harici bir siteye verilen bir bağlantıdan ancak fazlası olmanın , bazı yanıtların neden ve nasıl silineceği konusunda olası bir neden olduğunu göz önünde bulundurun. .
Paul Roub

1
Tamam, daha iyi anlamak için benim için ne kadar yararlı olacağı için buna göre güncellenecek
Max

1

IP adresini almak için basit bir dosya oluşturdum. Bu çözümü @ lundhjem, @ DavidH ve @ Ihunath'ın yanıtlarına dayandırdım. Kablolu bağlantıları dikkate alır. Yine de bu çözüme VPN eklemedim.

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'de benim için çalışmıyor. Bu düzeltmeyi kullanıyorum.

+ (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;
}
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.