Todos sabemos que podemos apagar el ordenador con un comando o bién con una combinación de pulsaciones de teclado o ratón, también hay programas que dado cierto evento hacen que se apague el sistema.
Esto no tiene ningún misterio, pero… ¿y si se trata de encenderlo?. Puede que con el solo hecho de pulsar el botón de encendido de la cpu nos sea suficiente (a veces con pulsar un botón del teclado o mover el ratón), sin embargo cuando no estamos físicamente presentes la cosa cambia: un cibercafe donde es más cómodo encender todos los ordenadores a la vez, o encender un ordenador remoto que por las noches se apaga para ahorrar electricidad, etc. Antiguamente los ordenadores se apagaban y punto, pero desde que irrumpió en el mercado el formato ATX de cajas y placas madre y con el estandar ACPI la cosa no ha hecho más que facilitarnos las cosas: ahora gracias a esos dos estandares somos capaces de apagar el ordenador por software, apagar el equipo ordenadamente por hardware, suspender, volver a reactivar, volver a encender, etc. En la parte que nos toca hay unos eventos que son capaces de encender un ordenador cuando este está apagado, y para la gestión remota de ese encendido se puede usar unos metodos denominados wake on ring, wake on modem (por modem) o wake on lan (por red).
Este artículo se centra en el método Wake On Lan (+ o – despertar por red). Este sistema se basa en que un ordenador cuando se apaga, no lo hace totalmente, sino que la fuente de alimentación sigue alimentando a la placa madre, y esta puede gestionar con muy bajo consumo los eventos que se den, como por ejemplo, encender el ordenador cuando recibe un paquete especial por la tarjeta de red. Este paquete, conocido como Magic Packet es muy simple y su formato consiste en 6 bytes con valor hexadecimal FF y otros 16 grupos de 6 bytes con la dirección MAC de la tarjeta de red. Da igual en que protocolo se envié ese paquete (IPX, TCP/IP, etc), con tal de que se envíe por toda la red. Así si se quiere encender un ordenador con una MAC 01:02:03.04:05:06 se enviaría un paquete con estos bytes en hexadecimal:
FFFFFFFFFFFF
010203040506010203040506010203040506010203040506
010203040506010203040506010203040506010203040506
010203040506010203040506010203040506010203040506
010203040506010203040506010203040506010203040506
El paquete debe enviarse a toda la red, por lo que hay que intentar que sea con el protocolo que se haga, este debe permitir enviar paquetes broadcast. Esto normalmente se puede conseguir con el protocolo IP, ya que poniendo como destinatario la dirección IP 255.255.255.255 debería llegar a todos los nodos de todas las redes que lo permitan. El TCP o UDP que venga por encima no es importante, aunque personalmente prefiero el UDP por no ser orientado a conexión. Por encima del UDP vendrá el magic packet. A continuación pongo un ejemplo de codigo fuente en varios lenguajes de programación para que podais probarlo (son tan cortos que no hacen falta comentarlos, tampoco tienen gestión de errores para su simplicidad), en vuestro caso solo tendrías que modificar el puerto (1976) y la dirección MAC (01:02:03:04:05:06):
C para Linux/Unix y Windows
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 |
#ifdef WIN32 #include <stdio.h> #include <winsock2.h> #else #include <sys/types.h> #include <sys/socket.h> #include <netinet/in.h> #endif void main(void) { int conexion; struct sockaddr_in direccion; unsigned char buffer[102]; unsigned char mac[]={0x01,0x02,0x03,0x04,0x5,0x06}; int valor=1,contador; #ifdef WIN32 WSADATA wsaData; WSAStartup( MAKEWORD( 2, 2 ), &wsaData ); #endif for(contador=0;contador<6;contador++) buffer[contador]=0xff; for(contador=6;contador<102;contador+=6) memmove(&buffer[contador],mac,6); memset(direccion.sin_zero,0,8); direccion.sin_family=AF_INET; direccion.sin_addr.s_addr=htonl(INADDR_BROADCAST); direccion.sin_port=htons(1976); conexion=socket(AF_INET,SOCK_DGRAM,0); valor=setsockopt(conexion, SOL_SOCKET, SO_BROADCAST, (char *)&valor, sizeof(int)); sendto(conexion,(char *)buffer,102,0,(struct sockaddr *)&direccion,sizeof(struct sockaddr_in)); #ifdef WIN32 WSACleanup(); #endif } |
Perl
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 |
use strict; use IO::Socket::INET; my $socket; my $msg; my $contador; $socket=new IO::Socket::INET->new(PeerPort=>1976, Proto=>'udp', PeerAddr=>'255.255.255.255', Broadcast=>1 ); $msg=""; for($contador=0;$contador<6;$contador++) { $msg.="\xff"; } for($contador=0;$contador<16;$contador++) { $msg.="\x01\x02\x03\x04\x05\x06"; } $socket->send($msg); |
Java
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 |
import java.net.*; import java.io.IOException; public class Wol { public static void main(String args[]) { byte mac[]={0x01,0x02,0x03,0x04,0x05,0x06}; byte buffer[]=new byte[102]; byte contador; for(contador=0;contador<6;contador++) buffer[contador]=(byte)0xff; for(contador=6;contador<102;contador+=6) System.arraycopy(mac,0,buffer,contador,6); try { DatagramSocket udp=new DatagramSocket(); udp.setBroadcast(true); udp.send(new DatagramPacket(buffer,102,InetAddress.getByName("255.255.255.255"),1976)); } catch(java.net.SocketException se) { System.err.println(se); } catch(java.net.UnknownHostException ue) { System.err.println(ue); } catch(java.io.IOException ie) { System.err.println(ie); } } } |
Visual Basic (Para que funcione debeis insertar un control Winsock)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 |
Dim buffer() As Byte Dim contador As Byte ReDim buffer(101) As Byte For contador = 0 To 5 buffer(contador) = &HFF Next For contador = 6 To 101 Step 6 buffer(contador) = &H1 buffer(contador + 1) = &H2 buffer(contador + 2) = &H3 buffer(contador + 3) = &H4 buffer(contador + 4) = &H5 buffer(contador + 5) = &H6 Next Winsock1.Protocol = sckUDPProtocol Winsock1.RemoteHost = "255.255.255.255" Winsock1.RemotePort = 1976 Winsock1.SendData buffer |
Por supuesto no hay método que sirva para marcar todas las tarjetas a la vez, así que habrá que ir una por una mandando el magic packet para que se vaya encendiendo cada ordenador. La tarjeta de red de cada ordenador apagado compara todos los paquetes que le llegan del tráfico de red para ver si contiene 16 veces su dirección MAC y así mandar a la placa madre que encienda el ordenador.
Las tarjetas de red que vengan incorporadas ya de fábrica en la placa madre ya tienen esta función activada. Sin embargo las que estan sueltas en ranuras PCI o ISA, deben:
1) Permitir el wake on lan (no todas tienen un firware con esa posibilidad)
2) La placa madre debe tener un conector de 3 pines que permita este evento.
3) Un cable que vaya desde la tarjeta hasta la placa madre.
En ambos casos se debe activar en la BIOS el mantenimiento de energía y posteriormente el evento WAKE ON LAN.
En mi portatil no puedo probar esta característica (cuando se apaga este, la tarjeta ethernet incorporada también se apaga). En el ordenador de sobremesa no me ha funcionado (tampoco funcionan eventos como el de encender el ordenador con una pulsación del teclado) y con el servidor me ha funcionado perfectamente.
El Magic Packet también se puede hacer desde Internet:
Si teneis conexión directa solo debeis modificar vuestro programa para que apunte a vuestra IP pública de Internet (si no es fija podeis usar cosas como dyndns).
Si no teneis conexión directa o no quereis usar un programa, podeis hacerlo desde aquí.
Sin embargo, a no ser que tengais un router que este conectado a Internet y donde podais poner rutas estáticas con IP, puertos y direcciones MAC no podreis hacerlo funcionar, ya que el router (como el mio) borra de la tabla arp las relaciones MAC/IP cuando detecta que no hay tráfico en una tarjeta determinada, por lo que aunque reciba un paquete que luego deba reenviar a una ip interna, lo ignora al no encontrarlo en la tabla; tampoco tiene opción para redireccionarlo como broadcast dentro de la red si no sabe que hacer con el.
Excelente artículo. Muchas gracias!
Al fin entendí de que se trataba el famoso «Wake On Lan»
Me va a ser muy util, gracias.
_________________________
No conocía tu blog pero me ha llamado la atención desde nedstat y debo admitir taxativamente que el tuyo va ser el unico enlace a blogs inteligentes que haya en el mio.
Gracias ;D
Vaya, pues muchas gracias por enlazarme 🙂
gracias por tan valiosa informacion. Tengo la necesidad de apagar y encender un modem dsl por lan usted sabe como podria hacerlo. gracias
Con las funciones de la api win32 RasDial y RasHangUp.
Hola, sabes como hacer esto mismo en php? No soy capaz de manejar el UDP desde allí.
Si no tienes problema, contacta conmigo en patoroco@gmail.com
Un saludo, y felicidades por la pagina.
En este mismo artículo hay un enlace de una página web donde puedes enviar magic packets además de incluirte el código fuente en php.
Hola, en la porción de Perl falta un ; despues del ultimo parentesis y antes de $msg=»»;
Saludos y muchas gracias
Cierto. Ya está corregido. Gracias por la anotación.
Excelente Este Articulo, muy bueno gracias por estas publicaciones.
Bueno te tengo un Reto. Codigo u Ocx o una idea para obtener la temperatura del la cpu. ya sea en Visual Basic o C.
Saludos
http://groups.google.de/group/microsoft.public.dotnet.languages.vb/msg/0b9464fcaf80b168
excelente el artículo! hace mucho que buscaba como hacer wakeup on lan desde internet… muchas gracias! 🙂
Si alguien está interesado en una utilidad gratuita para Windows XP que permite seleccionar a qué ordenadores enviar la señal de WakeUp, os recomiendo que probéis nuestro software:
Brindys BriWake
o la dirección http://www.brindys.com/briwake
Salu2,
Excelente articulo.
Necesito hacer algo parecido, pero sin WOL, es decir, apagar o reiniciar un PC remoto con c++.
Agradezco tu ayuda.
Mi mail es: sir_xpawn@hotmail.com
exelente, me ha funcionado de inmediato, solo tube que cambiar el la puerta de enlase y funciono, la cambie por la 9, es la prederminada en la mayoria de los casos..
¿Qué puerta de enlace?