Soru iPhone / iPad / OSX: IP adresimi programlı olarak nasıl alabilirim?


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

Teşekkürler. Not: Bir şekilde IPv6'yı devre dışı bırakabilir miyim?


116
2017-08-16 02:25


Menşei


Yukarıdaki 'PS' ile ilgili olarak, lütfen birisinin cihazındaki IPv6'yı programla devre dışı bırakmayın. Bu sadece düz kaba. - Jeremy Visser
IPv6'yı devre dışı bırakamazsınız. Bu zorunludur. Aslında, iOS uygulamanız IPv6'yı desteklemelidir. - Michael Hampton


Cevaplar:


Aşağıdaki kod bir iOS veya OSX cihazındaki tüm IPv4 ve IPv6 adreslerini bulur. İlk getIPAddress yöntem, bu cevabın eski kodu kadar az ya da çok hareket eder: bir ya da diğer tip adresi tercih edebilir ve her zaman hücresel üzerinden WIFI tercih eder (bunu açıkça değiştirebilirsiniz).

Daha ilginç olarak, bulunan tüm adreslerin sözlüğünü döndürebilir, adresleri atlayabilir not up arayüzler veya ilişkili adresler loopback. Önceki kodun yanı sıra bu konudaki diğer çözümler IPv6'nın kodunu çözemez (inet_ntoa bunlarla ilgilenemez). Bu bana tarafından işaret edildi Jens Alfke bir Apple forumunda - kullanmak için uygun işlev inet_ntop'dur (man sayfasına bakın ve buna bakın). inet_ntop makale ayrıca Jens tarafından sağlanmıştır.

Sözlük tuşları "interface" "/" "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;
}

EDIT1: Kod 16 Mayıs 2014'te güncellendi (hata, lhunath tarafından işaret edildi, yorumlara bakın). Loopback adresleri şimdi geri döndü, ancak testi kendiniz hariç tutmak için testten çekinmeniz çok kolay.

EDIT2: (bazı bilinmeyen kişiler tarafından): 13 Mart 2015'ten itibaren geliştirildi: Kullanıcının bir VPN kullanması durumunda (WiFi veya Hücresel'den bağımsız olarak), önceki kod başarısız olabilirdi. Şimdi, VPN bağlantıları ile bile çalışır. VPN bağlantıları, WiFi ve Hücre üzerinde önceliğe sahiptir çünkü cihaz bu şekilde işler. Mac’te VPN bağlantısı olduğu için bu, Mac’lerde bile çalışmalı, ancak IF utun0’ı kullanıyor ancak test edilmiyor.

EDIT3: (9/8/2016) @Qiulang'ın (yorumlarına bakın) VPN koduyla (ki bir başkasının eklediği) yaşadığı problemler göz önüne alındığında, bunu açıkladım. Bir kullanıcının bir VPN'yi nasıl belirleyeceğini kesin olarak bilen biri varsa lütfen yorum yapın.


125
2018-05-29 17:02



Ne sıklıkla addr NULL alır? Kullanıcılarım bazen NULL alır. olası nedenleri biliyor musun? - HelmiB
Sadece kullanıyorum AF_INET kontrol etmek. bu olabilir mi? - HelmiB
Bilmiyorum, ancak kullanıcılarınızın bir IPV6 ağında olabileceği kesin. - David H
3G ile tamamlandığı için bu "doğru" cevap olmalıdır. Güncelleme için teşekkürler. - palme
Bunun IPv6 ile doğru şekilde çalıştığını düşünmüyorum. İnet_ntoa işlevi bir IPv4 adresi alır, bu nedenle sa_type == AF_INET6 olduğu yerde, IPv6 adresini alıp IPv4'e türünü yazmak ve bunu bir dizeye çevirmek (temelde 128 bitlik yüksek 32 bitten) adres.) - Jens Alfke


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;

} 

88
2017-08-16 02:32



Arabirimler listesinde en0 arabirimi görünmüyor, bu yüzden sadece hata döndürüyor. İOS 5.x'te bir şey değişip değişmediğinden emin değilim. - wuf810
Aşağıya bakarsanız WIFI kapalı ise hücre (3G) adresini döndüren biraz değiştirilmiş kod bulacaksınız. - David H
Aşağıdaki kod sadece en0 IPv4 adresini verir. IPv6'dan ne haber? Birisi nasıl alınacağına dair bir kod örneği verebilir mi? - Oded Regev
Vay!! Bir çekicilik gibi çalışan +1 :) - swiftBoy
Bu cihaz, kablosuz ağa bağlı değil, ancak cellluar ağına bağlıyken ip adresi bulamıyor - Mapedd


IP adresi arama servislerinden birini aramak kolay mıdır? Kurdum http://ipof.in cihaz IP adresini JSON / XML veya düz metin olarak döndüren bir hizmet olarak. Onları burada bulabilirsiniz

http://ipof.in/json

http://ipof.in/xml

http://ipof.in/txt

HTTPS istiyorsanız, aynı URL’leri kullanabilirsiniz. https önek. Avantajı, Wifi'da olsanız bile, genel adresi alacağınızdır.


17
2018-01-06 14:18



Cevabını düşürdüğümden sonra tekrar inceledim ve çok üzgünüm. Kafam karıştı. Cevabınız çok iyi :(. Ama şu anda reddedemiyorum veya tekrar tekrar tavsiye edemem :(. - Huynh Inc
Müthiş şeyler, eminim birkaç durumda kullanışlı olacak. Herhangi bir kullanım kısıtlaması veya uygunluk garantisi var mı? - ekscrypto
Şu anda hem kısıtlama hem de garanti olmaksızın @ekscrypto bir şey değil, ancak oldukça istikrarlı ve günde birkaç bin kez vuruş yaptı. - vivekv
İOS'ta, genel IP Adresini listelenen tüm yanıtlardan doğru olarak döndüren tek yöntem budur. - Alex Zavatone
Bu sadece bir IPv4 adresi döndürür. - Michael Hampton


Birçok mevcut çözüm sadece bir Ethernet adaptörüyle (yani Wifi veya 3G olmadan) kablolu bağlantılar için çalışmayan kablosuz arabirimleri dikkate alır; Kablolu arayüzler aracılığıyla elde edilen IP adreslerini de dikkate alan bu yeni çözümü görün.

iPad: IP adresi programlı olarak nasıl alınır (kablosuz olarak değil)


3
2018-04-12 23:31



Mükemmel! Bunu yakında koduma ekleyeceğim. En1 nedir - biliyor musunuz? - David H
Yapmıyorum ama AF_INET ailesinin diğer arabirimler gibi olmadığını fark ettim - lundhjem


Swift 3 kullanarak IP adresini al:

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
}

2
2018-06-14 12:12





Mevcut çözüm, en0 cihazını OS X'de geri göndermez; aşağıdaki kod, arabirimleri almak için Sistem Yapılandırma Çerçevesini kullanır ve 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;
}

1
2017-12-19 10:23



Ne yazık ki SCDynamicStoreCreate iOS'ta şu anda kullanılamıyor: SCDynamicStoreCopyValue - Alex Zavatone


Bu cevap, DavidH'ın cevabından esinlenmiştir. Bazı sorunları çözdüm, değiştirdim inet_ntop ile getnameinfo Bu daha temiz bir yaklaşım sağlar. Bunun bir arabirim adını bir IP adresleri dizisi ile eşleyen bir sözlük oluşturduğunu unutmayın (bir arabirim, teknik olarak birden çok IPv4 ve IPv6 ile ilişkilendirilmiş 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;

1
2018-05-09 15:25



hiç görmedim strf - Bu senin kodunda bir yardımcı fonksiyon mu? - David H
Evet, üzgünüm, yukarıdaki kodda birkaç yardımcı var. err ve strf. Sadece değiştirebilirsiniz strf ile -stringWithCString:encoding:. err bir NSLog dosya ve satırı da çıktılayan sarmalayıcı. github.com/Lyndir/Pearl/blob/master/Pearl/... - lhunath


DavidH'nin cevabı, bu sonucu 4G hücresel şebekeden elde edene 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 olduğumu bilmiyorum.

--- Güncellenmiş ---

Bu sorunu daha fazla hata ayıklamak ve diğer 4G ağlarda bile sahte bir vpn adresi alabildiğimi fark ettim (bu iOS hatası mıdır?),

{
    ""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 kullanmış olsaydım bunu alırı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
}

İşte bu utun1 DEĞİL utun0

Neden sadece vpn kontrolünü bırakmak zorunda olduğumu anlamadan :(

---- güncelleme ----

Elmaya bir hata (28131847) yükledim ve "Tüm utun arabirimleri VPN için değil." Utun arabirimlerini kullanan başka işletim sistemi özellikleri var. "

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

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

Sorunu tekrar gördüm ve düzeltmek için DavidH'nin cevabını 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";
}

Onun orijinal cevabı ile sahte ve bağlantı başarısız oldu wifi IP fe80 :: 8dd: 7d92: 4159: 170e alacaksınız.

Bu yüzden kodu 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;
     }
 } ];

1
2017-09-01 14:28



VPN sorunuyla ilgili iç forumlarda yayınladım, Apple mühendis yardım teklif etti. Mac dot com'da çevrimdışı dhoerl ile iletişime geçmene ihtiyacım var - David H


Hızlıca geçmek için harika çözüm Bu dosya tüm detaylara hizmet eder.

Bir uygulamamda wifi IP adresini almam gerekiyor. Yukarıdaki yanıtları 3 gibi hızlı bir şekilde 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, çöküyor çünkü kontrol etmem gerekiyor nil her deyimde isteğe bağlı olarak kullandım ?. Bu yüzden sınıfımda verilen bağlantılı dosyayı kullanmam benim için daha iyi. Şimdi kontrol etmek benim için kolay olur:

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
}

Dizesini ayrıştırdım "." Çünkü Arayüz Sınıfı benim iPhone'umda iki arabirim döndürüyor en0 "fb00 ::" gibi adres ve "101.10.1.1" gibi bir adres


0
2018-06-24 16:50



Potansiyel bir çözümün bağlantısı her zaman bekler ama lütfen bağlantı etrafında bağlam ekle böylece diğer kullanıcılarınız ne olduğu ve neden orada olduğu hakkında biraz fikir sahibi olacaklar. Hedef siteye ulaşılamaması veya sürekli olarak çevrimdışı olması durumunda, her zaman önemli bir bağlantının en alakalı bölümünü belirtin. Olduğunu hesaba katın Harici bir siteye linkten çok daha fazlası için olası bir nedendir Bazı cevaplar neden ve nasıl silinir?. - Paul Roub
Tamam, daha iyi bir anlayış için benim için ne kadar yararlı olur diye buna göre güncellenir - Max