Frequently, while at the office or out of town, I find (to my dismay) that I need to access files on my desktop computer at home. The inevitable results are special trips and wasted time. While I could leave my desktop on indefinitely and access files remotely as, the inordinate amount of electricity that it consumes literally doubles my electric bill. Wake on LAN (WOL) would be another option, but I don't want to give anyone in the world the ability to start my computer. Moreover, if I should ever crash my system while logged in remotely, I need a way to force it to reboot. With this project, I've solved both problems for good, for the cost of about 3 months of running my desktop all day.Parts:
- Arduino Duemilanove
- Arduino Ethernet Shield
- Arduino ProtoShield Kit
- Wire Wrap Pins
- 3:8 Decoders (x2, optional)
- 16 Pin IC Socket (x2, for the decoders)
- SPST 5VDC Reed Relay
- PNP General Purpose Transistor (such as the 2N3906)
- Resistors (1 4.7k and 1 10k)
- Various plugs/jacks for connecting the Arduino to my PC.
- Power Switch Extension Cable (If you don\'t want to cut the power switch cable in your case)
The heart of this project is an Arduino Duemilanove microcontroller, equipped with an Ethernet adapter, and a home-made circuit that connects it to power switch on my computer. The Arduino is always on, so at any point in time (and from anywhere in the world), I can command the Arduino to start up my computer.
The simplest possible implementation would have the Arduino trigger the power switch any time it received a packet on some specific port. While this might work in practice, there is one obvious problem--it would allow anyone in the world to start up or shut down my computer (most likely accidentally). I've addressed this problem in the carefully crafted software running on both the Arduino, and my laptop, from which I access the Arduino remotely.
My first layer of security is a set of randomly-selected 64-bit binary strings that encode the messages to the Arduino. The Arduino component of my software will respond only to one of these exact strings. The chances of a stray packet carrying the startup signal reaching the Arduino are negligible.
As a second layer of security (which is undoubtedly overkill), I implemented some rudimentary cryptography in the communication protocol. Prior to sending any message, my laptop and the Arduino exchange a secret key with Diffie-Hellman key exchange. All messages between my laptop and the Arduino are encrypted with the key. Moreover, the key is invalidated after each message, which ensures that no message to or from the Arduino will be repeated in my lifetime.
To avoid the lose of unsaved work, I need to ensure that my software won't accidentally shut off my computer. I've handled this problem with some simple status checking. Before the Arduino triggers the power switch, it sends my desktop an ICMP echo request (ping). If it receives a response, it knows that my desktop is already on, and ignores the power request. Only if it receives will trigger the power button.
Because I can't change the Arduino software remotely, most of the code runs on my laptop. The Arduino supports only a small set of low-level functions for communication. A typical exchange works as follows:
1. My laptop randomly picks number a, and then computes g^a mod p, where p (a prime) and g are randomly selected integers, known in advance by both my laptop and the Arduino. My laptop places the resulting 64-bit number in a single UDP packet. The packet also includes 8-bit sequence number (since UDP does not guarantee in-order delivery) and an 8-bit code that indicates a key-exchange request.
2. When the Arduino receives the packet, it first checks the 8-bit code and concludes that the packet is a key-exchange request. It then proceeds to pick a random number b, and computes g^b (mod p). It places the result in a response packet contains, which it sends back to my laptop. The response contains the same sequence number (so that my laptop knows which message the Arduino is responding to), and the same 8-bit key exchange code.
3. The Arduino now knows b (which it picked itself) and g^a (mod p) (which it received in the key request packet). It then computes (g^a)^b mod p. Similarly, my laptop knows a (which it picked itself) and g^b mod p (which it received from the Arduino). It then computes (g^b)^a (mod p). Each computation produces the same result, which serves as a secret key known by only the Arduino and my laptop. This is mechanism is called Diffie-Hellman key exchange.
4. After my laptop has computed the key, it needs to determine if my desktop is already on. To this end, my laptop sends a second packet to the Arduino, carrying a pre-determined message that indicates a status query. The first byte of this packet is a code which indicates that the packet contains an encrypted command. As with the key exchange, the second byte contains a sequence number. The final 8 bytes contain the pre-determined message, encrypted with the key. 5. When the Arduino receives the packet, it once again starts by investigating the first byte, which reveals that the packet contains an encrypted command. The Arduino then proceeds to decrypt the command with the key. Finally, by comparing to the pre-determined constants, the Arduino discovers that the command is a status request.
6. To determine if my desktop is on, the Arduino sends an ICMP ping. If, after four attempts, it does not receive a response, it assumes that my desktop is off. In each case, the Arduino sends a pre-determined random binary string as its response, also encrypted with the key. The first and second bytes contain, respectively, the 8-bit message code and the sequence number used by the incoming packet. The Arduino also invalidates the key, which will cause it to ignore any incoming commands until a new key is exchanged.
7. When my laptop receives the response, it decrypts with the key (which it has not yet invalidated itself). If the key indicates that my desktop is on, my laptop does nothing more. If my desktop is off, my laptop initiates a new key exchange.
8. After the new key exchange, my laptop sends another pre-determined message encrypted with the new key, indicating that the Arduino should trigger the power button. The Arduino responds by sending the power-on signal to the switch-control circuit. The power-on signal is a 6-bit code, written in parallel to 6 of the Arduino's digital output pins. The switch-control circuit uses two 74ALS138 3:8 decoders to select a single combination of these 6 pins as the switch-control signal. This is intended to prevent the Arduino from accidentally triggering the power switch after a software or hardware glitch.
9. After triggering the power switch, the Arduino responds with a pre-determined acknowledge message (encrypted with the key) and invalidates the key.
All normal exchanges between the Arduino and my laptop consist of a message sent to the Arduino containing a message code, sequence number, and message data, followed by a response from the Arduino to my laptop with the same message code and sequence number. To deal with packet loss, I use two additional pre-determined messages. First, if after a short timeout interval, my laptop has not received a response, it can send a special repeat-request packet. When the Arduino receives a repeat request packet (again indicated by the first byte) it retransmits the last packet it sent. If multiple copies of a packet are sent, my laptop uses the sequence numbers to eliminate duplicates.
If the Arduino is delayed (for example, while waiting for ping responses from my desktop), it can send a special wait message, again indicated by the first byte. If my laptop receives a wait message, it will reset its timer to zero, thus avoiding timeout.
If my desktop should ever crash while I'm logged on remotely, my laptop can also send a force shutdown message. My laptop will send this message regardless of whether my desktop is on or off. When the Arduino receives a force-shutdown message, it will press and hold the power button for 10 seconds. I do occasionally crash my computer while doing research (it's easy to do when you're dealing with 100,000 x 100,000 matrices), so this is a very useful feature.
The power switch control circuit uses a reed relay to short out the power switch pins on my motherboard. I installed a jack in the back of my case, which gives me access to the power pins from the outside. I tapped the wires from my case power switch, so that the front panel power button still functions.
For those interested, my software is available for download.
My ICMP Ping Library
The TrueRandom Library
Visual Studio 2008 Project
Windows Binary (32 and 64 bit versions included)
Note: The control program will create the registry key HKEY_CURRENT_USER\Software\Remote_Startup to store the IP address and port number. If you run the software but don't intend to use it in the future, you can use regedit to remove this key. The software will not make any other changes to your system.
Nice job Blake! You come up with the most amazing gadgetry and hardware, keep it comin! You're soon to hit it big with a patent and not have to worry about working ever again, that is working for money, I believe you will be coming up with some awesome things in the future. Much respect and kudos!
I think this is something similar:
It looks to me like that device would be used to reboot a router if it loses connectivity. That would actually complement this project nicely, since it would allow me to control my desktop even if my router crashes.
Very interesting! - thanks for writing up.
Are you able to release the schematic and code?
Did you consider an implementation without the need for some Windows software? - either running a web server on the Arduino or having a secure web interface running elsewhere which talks to the Arduino.
Looking at the project you could have easily implemented a Wakeup-on-LAN to start the computer.
I will release the code at some point in the next day or two. I did consider using the Arduino as a web server, but I decided to go with the Windows software because it keeps the code running on the Arduino much simpler, and less likely to break. If the code on my laptop breaks, I can fix it easily. I also thought about running a script on the web server that hosts this site, but that would involve some support from my web host.
If you actually read this page, you would find several reasons why I didn't use Wake on LAN.
Are you going to post schematics and/or build instructions?
The only custom-built circuit is the relay board. The schematic for that is available--the link is in the caption below the photo of the board.
Is there any chance you could provide clearer (e.g. bigger) photos of the relay board? When I enlarge them enough to see they are pretty lo-rez and hard to see. Thanks!
Clicking any of the photos will open a higher resolution image.
Will this also work with Arduino UNO?
Probably. I don't have an UNO, so I can't be sure.
Hi BLAKE, if u provide schematic it will help me a lot, hoping positive result....
Hi Blake, This is a long shot but, I was wondering if it wood be possible to update the code to be compatible with
arduno 1.0-rc 1 (http://code.google.com/p/arduino/wiki/Arduino1)
The reason i ask is because they have changed the Ethernet library to include native DHCP and they have changed UDP.
Any help will be greatly appreciated.
PS This project is great
How would i get a boolean result from the library?
EG. If the ping fails to return a false, if it succeeds return a true?
I wanted to use your Ping-Library in addition with a webserver running on an arduino. I used socket 3 because the others are already occupied by the webserver and some udp communication. After doing the ping I loose connection to the webserver, and I cannot regain it. Looks like the ping code switches something in the W5100? How can I quit the library properly and continue working with TCP on the other sockets?
Any idea what I am doing wrong?
Thanks for the library so far...
It's been long since I worked with that code, so I don't have any great ideas about what could be wrong. I would suggest looking at the datasheet for the W5100. That's how I figured out how to implement this to begin with. If you fix the problem, I would be happy to host it here (and give you credit).
Wow, I had made something similar a couple of weeks ago to control a some computers using by using an arduino connected to my main server by usb. However, I didn't implement any of those excellent security procedures (Though not very necessary when over USB.) or a GUI. I love the security features though, well done! If no one else has recommended it and it still applies to your setup, you could put the arduino in the case and draw power from the 5 volt standby rail on the atx power connector (the purple wire).
That sounds like a cool project! I did at one point consider powering the thing off my system's PSU, but I opted for having the thing electrically isolated from my system as much as possible. I'm a little paranoid about that, because I once had a homebrew lighting circuit short out and do serious damage to my motherboard.
Thanks for the library, it was exactly what I needed. I have used it to create a visual alert for when my server is offline. I have credited you in the source code and on my site, http://labby.co.uk/2012/08/arduino-visual-icmp-ping-server
Any thoughts on emulating a keyboard after boot up so that a password can be entered? I'm uneasy about disabling that just to get remote access.
Why does the Ping always return "Request Timed Out
" and pingStatus is 0. Doesn't matter if the pinged machine is connected or not.
This is a really great concept, and I was wondering if the raspberry pi would allow something similar.. Also, I would love to see the following features - First replace the home made cable with an ethernet cable (use the extra pairs for reset, and sensor led activity). Next, the possibility of controlling multiple computers. The end device could look like an ethernet router - with one port for IP, the others for each computer to remote control. FInally an Html5 web interface to see led activity, hit reset or power off any remote computer would be so great!
Greetings Blake, Your ICMP library works great on the Arduino UNO, but won't currently compile against the Arduino Due. Is there an updated version that may address this for 32-bit Arduino users?
Hi Blake, Thanks for the great and easy to use PING code. I'm using it to test the uptime and delay of my local network and it works great. I'd like to ping external servers as well, but when their IP address changes I lose them. Can ping accept, say, "google.com" as an address instead of numeric IPs? Thanks, Tim
Hi Tim, The library only supports IP addresses, although I would consider support for DNS names at some point. In the meantime, there's an easy workaround--just DNS-resolve the host you want to ping (thereby obtaining an IP address) and then ping that IP address. The Ethernet library already supports DNS, so you can look there for an example (https://github.com/arduino/Arduino/blob/master/libraries/Ethernet/EthernetClient.cpp, line 30). I hope that helps! --Blake
Excellent! That's perfect. Thanks again!
© 2007 Blake Foster.
Great idea. You always have been a font of creativity. You always amaze me.
Did you apply for a patent?
And, did you check the US patent office to make sure you have not violated any existing patents?
Oh, by the way, according to my kids, and co-workers, I am a carbon-based life form sometimes referred to as humanoid.