2010-01-21 9 views
7

Ho provato a recuperare l'indirizzo del router in questo modo.Objective-C: come recuperare l'indirizzo del router?

- (NSString *) routerIp { 

    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 //ifa_addr 
      address = [NSString stringWithUTF8String:inet_ntoa(((struct sockaddr_in *)temp_addr->ifa_dstaddr)->sin_addr)]; 
     } 
     } 

     temp_addr = temp_addr->ifa_next; 
    } 
    } 

    // Free memory 
    freeifaddrs(interfaces); 

    return address; 
} 

L'indirizzo del router sembra sempre xxx.xxx.255.255 ma si suppone a guardare come xxx.xxx.0.1 o qualcosa in questo modo ...

C'è qualcosa da fare per ottenere il valido indirizzo?

Grazie per il vostro aiuto!

+0

ifa-> ifa_dstaddr è l'indirizzo di broadcast, che spiega la "255 del". – Bill

+0

controlla questo link potrebbe esserti utile http://stackoverflow.com/questions/6530322/fetching-ip-address-of-router-to-which-iphone-is-connessione –

risposta

1

xxx.xxx.255.255 è la maschera di sottorete. Hai bisogno dell'indirizzo del gateway.

Vedere tabella 3-10, c'è una voce per il router in thsi pdf: http://developer.apple.com/Mac/library/documentation/Networking/Conceptual/SystemConfigFrameworks/SystemConfigFrameworks.pdf

La versione HTML è qui: http://developer.apple.com/Mac/library/documentation/Networking/Conceptual/SystemConfigFrameworks/SC_Overview/SC_Overview.html

+0

In realtà è l'indirizzo di broadcast, non la maschera di sottorete. –

+0

Se è così, allora è un enorme dominio di trasmissione. Due ottetti di 255 sarebbero abbastanza grandi da trasmettere a poco meno di 2^16 = 65536 host. – pokstad

4

Ecco il codice che ho scritto per trovare i percorsi per la macchina . Ho copiato le chiamate di sistema dal codice per netstat. Tieni presente che mi è stato fortemente sconsigliato di farlo, poiché queste chiamate di sistema non sono un'API supportata e potrebbero cambiare in qualsiasi momento. Mi hanno consigliato di analizzare solo l'output di netstat.

CustomRoute.c:

#import "CustomRoute.h" 
@implementation CustomRoute 

+ (NSMutableArray*) getRoutes 
{ 
    NSMutableArray* routeArray = [NSMutableArray array]; 
    CustomRoute* route = nil; 

    size_t needed; 
    int mib[6]; 
    char *buf, *next, *lim; 
    register struct rt_msghdr2 *rtm; 

    mib[0] = CTL_NET; 
    mib[1] = PF_ROUTE; 
    mib[2] = 0; 
    mib[3] = 0; 
    mib[4] = NET_RT_DUMP2; 
    mib[5] = 0; 

    if (sysctl(mib, 6, NULL, &needed, NULL, 0) < 0) { 
     err(1, "sysctl: net.route.0.0.dump estimate"); 
    } 

    if ((buf = malloc(needed)) == 0) { 
     err(2, "malloc(%lu)", (unsigned long)needed); 
    } 
    if (sysctl(mib, 6, buf, &needed, NULL, 0) < 0) { 
     err(1, "sysctl: net.route.0.0.dump"); 
    } 

    lim = buf + needed; 

    for (next = buf; next < lim; next += rtm->rtm_msglen) { 
     rtm = (struct rt_msghdr2 *)next; 
     route = [self getRoute:rtm]; 
     if(route != nil) 
     { 
      [routeArray addObject:route]; 
     } 
    } 
    free(buf); 
    printf("Total routes: %u\n", [routeArray count]); 
    return routeArray; 
} 


+ (CustomRoute*) getRoute:(struct rt_msghdr2 *)rtm 
{ 
    //sockaddrs are after the message header 
    struct sockaddr* dst_sa = (struct sockaddr *)(rtm + 1); 

    CustomRoute* route = nil; 

    if(rtm->rtm_addrs & RTA_DST) 
    { 
     switch(dst_sa->sa_family) 
     { 
      case AF_INET: 
       if(dst_sa->sa_family == AF_INET && !((rtm->rtm_flags & RTF_WASCLONED) && (rtm->rtm_parentflags & RTF_PRCLONING))) 
       { 
        route = [[CustomRoute alloc] initWithRtm:rtm]; 
       } 
      break; 

     } 
    } 

    return route; 
} 

-(void) setAddr:(struct sockaddr*)sa index:(int)rtax_index 
{ 
    if(rtax_index >= 0 && rtax_index < RTAX_MAX) 
    { 
     memcpy(&(m_addrs[rtax_index]), sa, sizeof(struct sockaddr)); 
    } 

} 

-(NSString*) getDestination 
{ 
    return [self getAddrStringByIndex:RTAX_DST]; 
} 

-(NSString*) getNetmask 
{ 
    return [self getAddrStringByIndex:RTAX_NETMASK]; 
} 

-(NSString*) getGateway 
{ 
    return [self getAddrStringByIndex:RTAX_GATEWAY]; 
} 

-(NSString*) getDetails 
{ 
    NSMutableString* result = [[NSMutableString alloc] init]; 
    [result appendFormat: [NSString stringWithFormat: @"message type: 0x%06x\n", m_rtm.rtm_type]]; 
    [result appendFormat: [NSString stringWithFormat: @"flags: 0x%06x\n", m_rtm.rtm_flags]]; 
    [result appendFormat: [NSString stringWithFormat: @"addrs: 0x%06x\n", m_rtm.rtm_addrs]]; 


    return result; 
} 


-initWithRtm: (struct rt_msghdr2*) rtm 
{ 
    int i; 
    struct sockaddr* sa = (struct sockaddr*)(rtm + 1); 


    //copy over the route message 
    memcpy(&(m_rtm), rtm, sizeof(struct rt_msghdr2)); 
    for(i = 0; i < RTAX_MAX; i++) 
    { 
     [self setAddr:&(sa[i]) index:i]; 
    } 
    return self; 
} 

- init 
{ 
    memset(m_addrs, 0, sizeof(m_addrs)); 
    return self; 
} 

@end 


@implementation CustomRoute (Private) 

-(NSString*) getAddrStringByIndex: (int)rtax_index 
{ 
    NSString * routeString = nil; 
    struct sockaddr* sa = &(m_addrs[rtax_index]); 
    int flagVal = 1 << rtax_index; 

    if(!(m_rtm.rtm_addrs & flagVal)) 
    { 
     return @"none"; 
    } 


    if(rtax_index >= 0 && rtax_index < RTAX_MAX) 
    { 
     switch(sa->sa_family) 
     { 
      case AF_INET: 
      { 
       struct sockaddr_in* si = (struct sockaddr_in *)sa; 
       if(si->sin_addr.s_addr == INADDR_ANY) 
        routeString = @"default"; 
       else 
        routeString = [NSString stringWithCString:(char *)inet_ntoa(si->sin_addr) encoding:NSASCIIStringEncoding]; 
      } 
      break; 

      case AF_LINK: 
       { 
        struct sockaddr_dl* sdl = (struct sockaddr_dl*)sa; 
        if(sdl->sdl_nlen + sdl->sdl_alen + sdl->sdl_slen == 0) 
        { 
         routeString = [NSString stringWithFormat: @"link #%d", sdl->sdl_index]; 
        } 
        else 
         routeString = [NSString stringWithCString:link_ntoa(sdl) encoding:NSASCIIStringEncoding]; 
       } 
      break; 

      default: 
       { 
        char a[3 * sa->sa_len]; 
        char *cp; 
        char *sep = ""; 
        int i; 

        if(sa->sa_len == 0) 
        { 
         routeString = @"empty"; 
        } 
        else 
        { 
         a[0] = (char)NULL; 
         for(i = 0, cp = a; i < sa->sa_len; i++) 
         { 
          cp += sprintf(cp, "%s%02x", sep, (unsigned char)sa->sa_data[i]); 
          sep = ":"; 
         } 
         routeString = [NSString stringWithCString:a encoding:NSASCIIStringEncoding]; 
        } 
       } 
     } 
    } 
    return routeString; 
} 

@end 

CustomRoute.h:

#import <Cocoa/Cocoa.h> 
#import <net/route.h> 
#import <sys/socket.h> 
#import <netinet/in.h> 
#import <net/if_dl.h> 
#import <sys/sysctl.h> 

@interface CustomRoute : NSObject { 
    struct sockaddr  m_addrs[RTAX_MAX]; 
    struct rt_msghdr2 m_rtm; 
    int     m_len;  /* length of the sockaddr array */ 
} 

+ (NSMutableArray*) getRoutes; 
+ (CustomRoute*) getRoute:(struct rt_msghdr2 *)rtm; 

- (void) setAddr:(struct sockaddr*)sa index:(int)rtax_index; 

- (NSString*) getDestination; 
- (NSString*) getNetmask; 
- (NSString*) getGateway; 
- initWithRtm: (struct rt_msghdr2*) rtm; 


@end 
+0

Non è normale utilizzare librerie e framework per Mac OS su iOS. – Alena

10

ho cercato un modo per ottenere l'indirizzo IP del predefinito me stesso gateway. Mi concentrerò solo su questo - non ho bisogno di ottenere l'indirizzo MAC del router predefinito, quindi questo risponde solo parzialmente alla domanda dell'OP.

Non mi piaceva l'idea di analizzare l'output di netstat. Inoltre, non è possibile ottenere una route predefinita in base all'indirizzo IP di cui dispone un'interfaccia sulla macchina. Qualsiasi indirizzo IP compreso nello stesso intervallo può essere un gateway predefinito: l'unica regola è che sia l'IP che il gateway predefinito devono far parte della stessa subnet.

Un'altra cosa che volevo garantire è ottenere un indirizzo IP del gateway predefinito anche se a più di una delle mie interfacce locali è stato assegnato un indirizzo IP (ad es. Sono connesso al Wifi e al cavo Ethernet allo stesso tempo, e entrambe le interfacce sono attive, con un indirizzo IP su di esse). Per la mia applicazione, non importa quale interfaccia viene impostata la route predefinita (può essere en0, en1, ppp0 o qualsiasi altra cosa).

Penso che il modo migliore (e più simile ad Apple) per ottenere informazioni sia l'utilizzo di System Configuration Framework: i collegamenti nel post in alto in questo thread mi hanno indirizzato in quella direzione, ma in realtà non mi hanno dato molti dettagli su come usarlo, e non ho trovato la documentazione di Apple su di esso molto utile (almeno prendendo in considerazione il mio livello di abilità).

Per favore, non sono molto esperto in Objective-C - Sono nel mezzo di scrivere un'app di cui ho bisogno (e che non ho trovato), e per quell'app ho solo bisogno dell'IP indirizzo del gateway predefinito.

Quindi - ecco quello che sto facendo nella mia app, e sembra funzionare bene (più è molto più breve e più semplice rispetto alla maggior parte di altre soluzioni che ho trovato finora:

- (NSString *)defaultRouter { 

    SCDynamicStoreRef ds = SCDynamicStoreCreate(kCFAllocatorDefault, CFSTR("myapp"), NULL, NULL); 
    CFDictionaryRef dr = SCDynamicStoreCopyValue(ds, CFSTR("State:/Network/Global/IPv4")); 
    CFStringRef router = CFDictionaryGetValue(dr, CFSTR("Router")); 
    NSString *routerString = [NSString stringWithString:(__bridge NSString *)router]; 
    CFRelease(dr); 
    CFRelease(ds); 

    return routerString; 
} 

Si prega di notare che in la mia app, la precedente, fa parte di un metodo più grande (in realtà non ho un defaultRouter: metodo in là) Inoltre, ho omesso alcuni dei controlli (come [lunghezza di routerString] e così via) per brevità

Speriamo che qualcuno lo trovi utile, per favore sentitevi liberi di correggere eventuali errori che potrei avere nel codice qui sopra - Sono ancora un novellino!

PS. Ho avuto un'idea di cosa cercare quando ho controllato l'uscita di 'scutil', che utilizza il Framework Configuration Sistema stesso:

MacBook:~$ scutil 
> show State:/Network/Global/IPv4 
<dictionary> { 
    PrimaryInterface : en1 
    PrimaryService : <service_id> 
    Router : <ipv4_address> 
} 
> show State:/Network/Global/IPv6 
<dictionary> { 
    PrimaryInterface : en1 
    PrimaryService : <service_id> 
    Router : <ipv6_address> 
} 
+10

'SCDynamicStoreCreate' e' SCDynamicStoreCopyValue' non sono disponibili su iOS. Questo funzionerà solo per un Mac. – thegrinner

+0

@thegrinner non ho provato queste funzioni, ma queste funzioni sono disponibili sotto iOS. Puoi assicurarlo con il comando successivo: 'nm -m /Applicazioni/Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS8.1.sdk/System/Library/Frameworks/SystemConfiguration.framework/SystemConfiguration | grep SCDynamicStoreCreate' – Speakus

+0

No, questi non sono disponibili pubblicamente su iOS 8.1. In SCDynamicStore.h: SCDynamicStoreCreate \t \t \t ... \t \t \t \t __OSX_AVAILABLE_STARTING (__ MAC_10_1, __ IPHONE_NA); Il tentativo di fare riferimento a questi produce un errore del compilatore. –