2010-01-21 2 views
7

Я попытался найти адрес маршрутизатора таким образом.Цель-C: Как получить адрес маршрутизатора?

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

адрес маршрутизатора всегда выглядит xxx.xxx.255.255, но он должен выглядеть xxx.xxx.0.1 или что-то так ...

Есть ли что-нибудь сделать, чтобы получить действительный адрес?

Благодарим за помощь!

+0

ifa-> ifa_dstaddr это широковещательный адрес, который объясняет «255-х». – Bill

+0

проверить эту ссылку может быть полезно для вас http://stackoverflow.com/questions/6530322/fetching-ip-address-of-router-to-which-iphone-is-connected –

ответ

1

xxx.xxx.255.255 - маска подсети. Вам нужен адрес шлюза.

смотрите таблицу 3-10, есть запись для маршрутизатора в Thsi PDF: http://developer.apple.com/Mac/library/documentation/Networking/Conceptual/SystemConfigFrameworks/SystemConfigFrameworks.pdf

HTML-версия находится здесь: http://developer.apple.com/Mac/library/documentation/Networking/Conceptual/SystemConfigFrameworks/SC_Overview/SC_Overview.html

+0

Это фактически широковещательный адрес, а не маска подсети. –

+0

Если это так, то это огромный домен вещания. Два октета 255 были бы достаточно большими, чтобы транслировать только до 2^16 = 65536 хостов. – pokstad

4

Вот некоторый код, который я написал, чтобы найти пути для машины , Я скопировал системные вызовы из кода для netstat. Обратите внимание, что я настоятельно рекомендовал это делать, поскольку эти системные вызовы не поддерживаются API и могут меняться в любое время. Они рекомендовали мне просто разобрать вывод 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

Это не нормально использовать библиотеки и фреймворки Mac OS на iOS. – Alena

10

Я искал способ, чтобы получить IP-адрес шлюза по умолчанию сам. Я собираюсь сосредоточиться именно на этом - мне не нужно было получать MAC-адрес маршрутизатора по умолчанию, так что это лишь частично отвечает на вопрос OP.

Мне не понравилась синтаксическая обработка вывода netstat. Кроме того, вы не можете получить маршрут по умолчанию на основе IP-адреса, который имеет интерфейс на вашем компьютере. Любой IP-адрес в том же диапазоне, что и ваш, может быть шлюзом по умолчанию - единственное правило заключается в том, что ваш IP-адрес и шлюз по умолчанию должны быть частью одной и той же подсети.

Еще одна вещь, которую я хотел бы обеспечить, - это получить IP-адрес шлюза по умолчанию, даже если для одного из моих локальных интерфейсов назначен назначенный ему IP-адрес (например, я подключен к Wi-Fi и проводному Ethernet в то же время, и оба интерфейса вверх, с IP-адресом на них). Для моего приложения не имеет значения, с каким интерфейсом устанавливается маршрут по умолчанию (он может быть en0, en1, ppp0 или вообще что-либо еще).

Я думаю, что лучший (и самый похожий на Apple) способ получить эту информацию - использовать System Configuration Framework - ссылки в сообщении выше в этом потоке указывали мне в этом направлении, но на самом деле не дали подробностей как использовать его, и я не нашел документацию Apple на нем очень полезной (по крайней мере, учитывая мой уровень квалификации).

Пожалуйста, помните, что я не очень опытен в Objective-C. Я нахожусь в середине написания приложения, которое мне нужно (и которое я не мог найти), и для этого приложения мне просто нужен IP-адрес адрес шлюза по умолчанию.

Итак - вот что я делаю в моем приложении, и это, кажется, работает хорошо (плюс намного короче и проще, чем большинство других решений, которые я нашел до сих пор:

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

Обратите внимание, что в мое приложение, приведенное выше, является частью более крупного метода (у меня на самом деле нет метода defaultRouter:). Я также пропустил некоторые проверки (например, [длина маршрутизатора] и т. д.) для краткости.

Надеюсь, кто-то посчитает это полезным. Также не стесняйтесь исправить любые ошибки, которые могут возникнуть в коде выше - я все еще новичок!

PS. Я получил представление о том, что нужно искать, когда я проверил выход «scutil», которая использует Framework конфигурации системы сам:

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' и' SCDynamicStoreCopyValue' недоступны в iOS. Это будет работать только для Mac. – thegrinner

+0

@thegrinner Я не пробовал эти funcs, но эти функции доступны в iOS. Вы можете обеспечить это следующей командой: '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

Нет, они недоступны для iOS 8.1. В SCDynamicStore.h: SCDynamicStoreCreate \t \t \t ... \t \t \t \t __OSX_AVAILABLE_STARTING (__ MAC_10_1, __ IPHONE_NA); Попытка ссылаться на них вызывает ошибку компилятора. –

 Смежные вопросы

  • Нет связанных вопросов^_^