Wednesday, October 12, 2011

dyndns for an iphone server

Dynamic IP are common at residential properties and are quite a problem if you want your home server to be constantly reachable from outside. The solution is a dynamic IP tracking host like dyndns. Since im working from a hacked iphone a second problem is that perl doesnt seem to exist for it. So using a standard package is a bit of an issue. Here is a quick hacked up ruby daemon that can handle the dyndns updates.

Save this ruby script at /var/mobile/dyndns/update_ip.rb, (dont forget to chmod it to runable.)

UPDATE: It appears that dyndns gets peeved if you keep updating to the same IP. The code has been patched for it.
#!/usr/bin/env ruby

require 'base64'

host = "example.dyndns.tv"
auth = Base64.encode64('user:password')
timeout = 600

while 1
  output = ""
  puts "Discovering current IP.."
  
  # current ip resolve from checkip.dyndns.com
  IO.popen("telnet checkip.dyndns.com 80", "w+") do |pipe|
    output = pipe.readline
    puts output
  
    pipe.puts "GET / HTTP/1.1"
    pipe.puts "Host: checkip.dyndns.com"
    pipe.puts "Connection: close"
    pipe.puts ""
    pipe.puts ""
  
    puts "SENT ip query.."
    output = pipe.readlines.join("");
    puts "---------------RESPONSE--------------------"
    puts output
    puts "---------------  END   --------------------"
    pipe.close_write
  end
  
  if output =~ /.*Current IP Address: ([0-9]+.[0-9]+.[0-9]+.[0-9]+).*/
     ip = $1
     ip = ip.chomp
     puts ""
     puts "DETECTED At: " + ip 
  end

  oldip = ""
  File.open('currentIP.txt', 'r') do |f|
    oldip = f.gets
    oldip = oldip.chomp
  end
  puts "PRIOR At: " + oldip   

  if oldip == ip 
    puts "MATCH sleeping..."
  else
    File.open('currentIP.txt', 'w') do |f|
      f.puts ip
    end  

    exit    
    puts ""
    puts "installing new IP..."
    
    #http://login:password@members.dyndns.org/nic/update?hostname=example.dyndns.tv&myip=99.99.99.99
    IO.popen("telnet members.dyndns.org 80", "w+") do |pipe|
      output = pipe.readline
      puts output
    
      pipe.puts "GET /nic/update?hostname=" + host + "&myip=" + ip + " HTTP/1.1"
      pipe.puts "Host: members.dyndns.org"
      pipe.puts "User-Agent: codeslimjim/1.0 rubyscript/1.0"
      pipe.puts "Authorization: Basic " + auth
      pipe.puts "Connection: close"
      pipe.puts ""
      pipe.puts ""
    
      puts "SENT new ip.."
      output = pipe.readlines
      puts "---------------RESPONSE--------------------"
      puts output
      puts "---------------  END   --------------------"
      pipe.close_write
    end
  end

  #timeout for x sec..
  sleep timeout
end

Then install the plist daemon
touch /Library/LaunchDaemons/com.dyndns.plist
chmod go-wrx /Library/LaunchDaemons/com.dyndns.plist
nano /Library/LaunchDaemons/com.dyndns.plist

Paste in the code
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN"
"http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
    <key>Label</key>
    <string>com.dyndns</string>
    <key>ProgramArguments</key>
    <array>
        <string>/var/mobile/dyndns/update_ip.rb</string>
    </array>
    <key>RunAtLoad</key>
    <true/>
    <key>KeepAlive</key>
    <true/>
    <key>UserName</key>
    <string>mobile</string>
    <key>WorkingDirectory</key>
    <string>/var/mobile/dyndns</string>
</dict>
</plist>

And boot/load up the daemon and test
launchctl load -w /Library/LaunchDaemons/com.dyndns.plist
ps aux | grep dyndns 

Remmber if u need to shut it down use
launchctl unload -w /Library/LaunchDaemons/com.dyndns.plist

No comments:

Post a Comment