Цель-C: Как получить адрес маршрутизатора? - PullRequest
7 голосов
/ 22 января 2010

Я пытался получить адрес маршрутизатора таким образом.

- (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 или что-то в этом роде ...

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

Спасибо за вашу помощь!

Ответы [ 3 ]

10 голосов
/ 04 декабря 2012

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

Мне не понравилась идея парсинга вывода 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:). Кроме того, я опускаю некоторые проверки (например, [routerString length] и т. Д.) Для краткости.

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

PS. Я получил представление о том, что искать, когда я проверил вывод 'scutil', который использует сам System Configuration 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>
}
4 голосов
/ 24 января 2010

Вот некоторый код, который я написал, чтобы найти маршруты для машины.Я скопировал системные вызовы из кода для 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
1 голос
/ 22 января 2010

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

См. Таблицу 3-10, в этом файле есть запись для маршрутизатора: 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

...