Objective-C: ¿cómo recuperar la dirección del enrutador?

Traté de buscar la dirección del enrutador de esta manera.

- (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 enrutador siempre se ve como xxx.xxx.255.255, pero se supone que debe verse como xxx.xxx.0.1 o algo así …

¿Hay algo que hacer para obtener la dirección válida?

¡Gracias por tu ayuda!

He estado buscando una forma de obtener la dirección IP de la puerta de enlace predeterminada. 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 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 (por ejemplo, estoy conectado al Wifi y a la Ethernet alámbrica al mismo hora, 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 (y la mayoría de Apple) para obtener esa información es utilizar 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 sobre cómo Úselo, 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 dirección IP del valor predeterminado puerta.

Entonces, esto 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 del enrutador String], etc.) para abreviar.

Espero que alguien encuentre esto útil. Por favor, también puede corregir cualquier error que pueda tener en el código anterior. ¡Todavía soy un novato!

PD. Obtuve una idea de qué buscar cuando revisé el resultado de ‘scutil’, que usa el Marco de configuración del sistema mismo:

 MacBook:~$ scutil > show State:/Network/Global/IPv4  { PrimaryInterface : en1 PrimaryService :  Router :  } > show State:/Network/Global/IPv6  { PrimaryInterface : en1 PrimaryService :  Router :  } 

Aquí hay un código que escribí para encontrar las rutas de la máquina. Copié las llamadas al sistema desde el código de 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 la salida 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  #import  #import  #import  #import  #import  @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 

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

Consulte la tabla 3-10, hay una entrada para el enrutador en este 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