2012-07-17 15 views
15

Tengo que ser capaz de detectar un cambio de dirección IP para mi cliente Mac. Necesito realizar una acción cada vez que obtengo una nueva, cuando paso del wifi al cableado ...Cómo detectar el cambio de dirección IP en OSX mediante programación en C o C++

¿Alguien ha hecho algo similar? Actualmente sondeo cada minuto y necesito cambiar eso para ser más impulsado por el evento.

+0

En un término más general, mi pregunta debería ser: En OS X ¿Cómo realizar una acción durante el cambio de una dirección IP? – reza

+0

Si su intención es detectar cuándo cambia la dirección IP predeterminada para que pueda realizar alguna acción (por ejemplo, enviar la nueva dirección a algún servidor), ya está.Si se trata de otra cosa, cuéntenos qué es esa otra cosa en realidad, en lugar de adivinar el paso siguiente hacia lo que desea lograr. (Idealmente, debe presentar una nueva pregunta para eso en lugar de cambiar esta, porque tal como está, esta es una buena pregunta, con lo que espero sea una muy buena respuesta, incluso si no es realmente su pregunta). – abarnert

Respuesta

22

Existen varias formas de hacerlo, desde las notificaciones de IOKit en adelante, pero la más simple es probablemente la estructura SystemConfiguration.

El primer paso es encender scutil y jugar con él para averiguar qué tecla (s) que desea notificación en:

$ scutil 
> list 
... 
> n.add State:/Network/Global/IPv4 
> n.watch 
... unplug your network cable (or disconnect from WiFi) 
notification callback (store address = 0x10e80e3c0). 
changed key [0] = State:/Network/Global/IPv4 

vistazo a eso, lo consiguió en el primer intento. :) Pero si desea ver una NIC en particular, o usar IPv6 en lugar de v4, etc., obviamente querrá una clave diferente de la lista. Tenga en cuenta que puede usar patrones regex (estilo POSIX, como se define en man 3 regex), por lo que si desea ver, digamos, cualquier NIC para IPv4, puede usar State:/Network/Interface/.*/IPv4, o si quiere decir IPv4 o IPv6 global, State:/Network/Global/IPv., etc.

Ahora solo llama a SCDynamicStoreSetNotificationKeys con las teclas que desee.

Tenga en cuenta que SCDynamicStoreSetNotificationKeys pueden tener patrones de expresiones regulares (estilo POSIX, como se define por el hombre 3 de expresiones regulares)

Puesto que es un poco doloroso en C, lo escribiré en Python:

#!/usr/bin/python 

from Foundation import * 
from SystemConfiguration import * 

def callback(store, keys, info): 
    for key in keys: 
    print key, SCDynamicStoreCopyValue(store, key) 

store = SCDynamicStoreCreate(None, 
          "global-network-watcher", 
          callback, 
          None) 
SCDynamicStoreSetNotificationKeys(store, 
            None, 
            ['State:/Network/Global/IPv4']) 
CFRunLoopAddSource(CFRunLoopGetCurrent(), 
        SCDynamicStoreCreateRunLoopSource(None, store, 0), 
        kCFRunLoopCommonModes) 
CFRunLoopRun() 

El La razón principal por la que esto es más doloroso en C es que necesita docenas de líneas repetitivas para cosas como crear un CFArray con un CFString, imprimir valores de CFString, administrar la vida útil de los objetos, etc. Del comentario de Jeremy Friesner, hay C++ sample code disponible si prefieres leer 113 líneas de C++ que 17 líneas de Python. Pero, en realidad, sólo hay una línea de aquí que debe ser desconocido para alguien que nunca ha usado Python:

def callback(store, keys, info): 
    for key in keys: 
    print key, SCDynamicStoreCopyValue(store, key) 

... es el equivalente a la definición C:

void callback(SCDynamicStoreRef store, CFArrayRef keys, void *info) { 
    /* iterate over keys, printing something for each one */ 
} 

Curiosamente, no puedo encontrar la referencia real o documentación de guía sobre SystemConfiguration; lo único que aparece para SCDynamicStoreSetNotificationKeys o funciones relacionadas se encuentra en la sección de Firewalls Firewalls de CFNetwork Programming Guide. Pero la nota técnica original TN1145: Living in a Dynamic TCP/IP Environment todavía existe, y tiene suficientes antecedentes y código de muestra para averiguar cómo escribir esto usted mismo (y cómo detectar las nuevas direcciones IP cuando se le notifica).

Obviamente, esto requiere que sepa exactamente qué está tratando de observar. Si no lo sabes, nadie puede decirte cómo vigilarlo. Su pregunta original fue cómo "detectar un cambio de dirección IP".

Lo que el código anterior hará es detectar cuando cambia su dirección predeterminada. Esa es la dirección que se utiliza cuando conecta un socket a una dirección de Internet sin vincularlo, o enlaza un socket a '0.0.0.0' para actuar como un servidor de Internet. Si no ha escrito el código del servidor que le importa, casi todos los clientes de la red hacen lo primero, y la mayoría de los servidores lo hacen a menos que los configure de otra manera, por lo que probablemente sea todo lo que le preocupa.

Ahora vamos a ir a través de los ejemplos en sus comentarios uno por uno:

si yo estoy tratando de determinar un cambio de red, wifi a internet

No hay tal cosa como el cambio de WiFi a LAN. Cuando te conectas a una LAN, el WiFi sigue funcionando. Por supuesto, puede desactivarlo manualmente antes o después de conectarse a la LAN, pero no es necesario, y es un paso separado, con una notificación por separado.

Normalmente, agregar una LAN cambiará su dirección predeterminada a la dirección de la LAN, por lo que /Network/Global le avisará. Si el sistema operativo puede indicar que la LAN no está realmente conectada a Internet, o si ha cambiado algunas configuraciones ocultas para hacer que prefiera WiFi a LAN, etc., no cambiará la dirección predeterminada, y /Network/Global no lo notificará, pero probablemente no te importe.

Si le importa si una interfaz en particular obtiene, pierde o cambia una dirección, puede ver esa interfaz. En la mayoría de las Mac, la Ethernet incorporada es en0, y la WiFi incorporada es en1, pero por supuesto puede tener un conector WiFi USB de terceros, o puede estar usando un teléfono celular atado, o puede estar interesado no tanto en la dirección IP real de la LAN como en la dirección VPN de la VPN a la que está conectada la LAN, etc. Si está escribiendo algo especial, probablemente sepa qué interfaz le interesa, para que pueda ver, por ejemplo, State:/Network/Interface/en0/IPv4. Si desea que se le notifique sobre cualquier cambio en la interfaz pase lo que pase, solo mire State:/Network/Interface/.*/IPv4.

o hotspot wifi u otra

El cambio de una red WiFi a otra (punto de conexión o de otro modo) cambiará en1-o, si está utilizando un adaptador WiFi de terceros, algún otro interfaz. Si su dirección predeterminada en ese momento proviene de WiFi, también cambiará Global, lo que significa que el código anterior funcionará como está. Si su dirección predeterminada sigue siendo su LAN, Global no cambiará, pero probablemente no le importe. Si le importa, vea Interface/en1 o Interface/.*, etc., como se indica arriba.

lo que todos los ajustes de la red deben estar viendo que para IPv4 y 6

simplemente reemplazar IPv4 con IPv6, o utiliza IPv.. ¿Pero realmente te importa IPv6?

qué más

¿Qué más importa? Si hay algo de lo que realmente deseas notificación, presumiblemente sabes lo que es ese algo.

Más allá de eso, si el sistema le dice que la dirección foo en la interfaz de la barra ha cambiado a "ZZ9 Plural Z Alpha", y nunca ha oído hablar del protocolo foo, ¿qué podría hacer con esa información? Pero si realmente lo quiere de todos modos, nuevamente, puede usar un patrón de expresión regular para observar cualquier cosa debajo de cada interfaz.

+0

Concur - Estuve a mitad de camino escribiendo algo similar - sin el agradable grito de scutil. :) – Joe

+0

Esto es fantástico, gracias. No leo Python. ¿Qué está haciendo esto? – reza

+3

Hay un programa de ejemplo de C/C++ trivial pero ejecutable en http://www.lcscanada.com/jaf/osx_ip_change_notify.cpp (derivado del código de Tech Note de Apple) ... compilarlo con "g ++ osx_ip_change_notify.cpp - framework SystemConfiguration -framework Carbon " –

Cuestiones relacionadas