2010-01-21 27 views
7

Intenté buscar la dirección del enrutador de esta manera.Objective-C: cómo recuperar la dirección del enrutador?

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

La dirección del router siempre parece xxx.xxx.255.255 pero se supone que parecen xxx.xxx.0.1 o algo así ...

¿Hay algo que hacer para obtener la validez ¿dirección?

Gracias por su ayuda!

+0

ifa-> ifa_dstaddr es la dirección de difusión, lo que explica el "255 de". – Bill

+0

echa un vistazo a este enlace puede ser útil http://stackoverflow.com/questions/6530322/fetching-ip-address-of-router-to-which-isonectado –

Respuesta

1

xxx.xxx.255.255 es la máscara de subred. Necesitas la dirección de la puerta de enlace.

Ver tabla 3-10, hay una entrada para el router en thsi pdf: http://developer.apple.com/Mac/library/documentation/Networking/Conceptual/SystemConfigFrameworks/SystemConfigFrameworks.pdf

La versión HTML está aquí: http://developer.apple.com/Mac/library/documentation/Networking/Conceptual/SystemConfigFrameworks/SC_Overview/SC_Overview.html

+0

En realidad es la dirección de difusión, no la máscara de subred. –

+0

Si ese es el caso, entonces es un gran dominio de transmisión. Dos octetos de 255 serían lo suficientemente grandes como para transmitir a poco menos de 2^16 = 65536 hosts. – pokstad

4

Aquí hay un código que escribí para encontrar las rutas para la máquina . Copié las llamadas al sistema desde el código para netstat. Tenga en cuenta que se me recomendó encarecidamente que no lo haga, ya que estas llamadas al sistema no son compatibles y pueden cambiar en cualquier momento. Me recomendaron que solo analizara el resultado de 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

No es normal utilizar bibliotecas y marcos de Mac OS en iOS. – Alena

10

He estado buscando una manera de obtener la dirección IP de la puerta de enlace predeterminada a mí mismo. Voy a centrarme solo en esto: no necesito obtener la dirección MAC del enrutador predeterminado, así que esto solo responde parcialmente a la pregunta del OP.

No me gustó la idea de analizar la salida de netstat. Además, no puede obtener una ruta predeterminada en función de la dirección IP que tiene una interfaz en su máquina. Cualquier dirección IP dentro del mismo rango que la suya puede ser una puerta de enlace predeterminada: la única regla es que tanto su IP como la puerta de enlace predeterminada deben ser parte de la misma subred.

Una cosa más que quería asegurar es obtener una dirección IP de la puerta de enlace predeterminada incluso si más de una de mis interfaces locales tiene una dirección IP asignada a la misma (por ejemplo, estoy conectado al Wifi y al cable Ethernet al mismo tiempo, y ambas interfaces están arriba, con una dirección IP en ellas). Para mi aplicación, no importa a qué interfaz se establezca la ruta predeterminada (puede ser en0, en1, ppp0 o cualquier otra cosa).

Creo que la mejor forma (y la más similar a Apple) para obtener esa información es usar el Marco de Configuración del Sistema - los enlaces en la publicación de arriba en este hilo me indicaron en esa dirección, pero realmente no dieron muchos detalles en cuanto a cómo usarlo, y no encontré la documentación de Apple muy útil (al menos teniendo en cuenta mi nivel de habilidad).

Tenga en cuenta que no tengo mucha experiencia en Objective-C: estoy escribiendo una aplicación que necesito (y que no pude encontrar), y para esa aplicación solo necesito la IP dirección de la puerta de enlace predeterminada.

Por lo tanto - aquí es lo que estoy haciendo en mi aplicación, y parece estar funcionando bien (además es mucho más corto y más simple que la mayoría de las otras soluciones que he encontrado hasta ahora:

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

Tenga en cuenta que en mi aplicación, lo anterior es parte de un método más grande (en realidad no tengo un método defaultRouter:). Además, he omitido algunas de las comprobaciones (como [longitud de routerString] y así sucesivamente) para abreviar.

Esperemos que alguien encuentre esto útil. También puede corregir cualquier error que pueda tener en el código anterior - ¡Todavía soy un novato!

PS. Tengo una idea de lo que debe buscar cuando he comprobado la salida de 'scutil', que utiliza el marco de configuración del sistema en sí:

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' y' SCDynamicStoreCopyValue' no están disponibles en iOS. Esto solo funcionará para una Mac. – thegrinner

+0

@thegrinner no probé estos funcs, pero estas funciones están disponibles en iOS. Puede asegurar esto con el siguiente comando: 'nm -m /Applications/Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS8.1.sdk/System/Library/Frameworks/SystemConfiguration.framework/SystemConfiguration | grep SCDynamicStoreCreate' – Speakus

+0

No, estos no están disponibles públicamente en iOS 8.1. En SCDynamicStore.h: SCDynamicStoreCreate \t \t \t ... \t \t \t \t __OSX_AVAILABLE_STARTING (__ MAC_10_1, __ IPHONE_NA); Intentar hacer referencia a estos produce un error de compilación. –

Cuestiones relacionadas