Module: DDNSUpdate

Defined in:
lib/ddnsupdate.rb

Defined Under Namespace

Classes: UpdateError

Class Method Summary collapse

Class Method Details

.determine_current_ip(zone, soa = nil) ⇒ Object



37
38
39
40
# File 'lib/ddnsupdate.rb', line 37

def self.determine_current_ip(zone, soa=nil)
  soa = determine_soa(zone) unless !soa.nil?
  %x{dig @#{soa} #{zone} A +short }
end

.determine_local_ipObject



42
43
44
45
46
47
48
49
50
51
# File 'lib/ddnsupdate.rb', line 42

def self.determine_local_ip
  orig, Socket.do_not_reverse_lookup = Socket.do_not_reverse_lookup, true  # turn off reverse DNS resolution temporarily

  UDPSocket.open do |s|
    s.connect '64.233.187.99', 1
    s.addr.last
  end
ensure
    Socket.do_not_reverse_lookup = orig
end

.determine_remote_ipObject



53
54
55
# File 'lib/ddnsupdate.rb', line 53

def self.determine_remote_ip
  Net::HTTP.get(URI.parse('http://www.whatismyip.org/'))
end

.determine_soa(zone) ⇒ Object



15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
# File 'lib/ddnsupdate.rb', line 15

def self.determine_soa(zone)
  current = zone.gsub(/\.$/, "")
  soa = nil
  while soa.nil? and not current.match /\.*\..*/
    soa = %x{dig -t SOA #{current} +noquestion +nostats +nocmd +noqr +nocomments +noadditional +nottlid}
    if not soa.nil?
      #Split lines into an array, filtering out comments and blanks
      soa = soa.split("\n").delete_if { |el| el.start_with?(";") || el.empty? }
      #Split remaining line into whitespace delimited fields
      if not soa.empty?
        soa = soa[0].split(/\s/)
        #Find the field we actually want, stripping the trailing dot
        soa = soa[soa.index("SOA") + 1].gsub(/\.$/, "")
      else
        soa = nil
      end
    end
    current.sub! /^.*?\./, ""
  end
  return soa
end

.keygen(input) ⇒ Object



11
12
13
# File 'lib/ddnsupdate.rb', line 11

def self.keygen(input)
  Base64.encode64(Digest::MD5.hexdigest(input.downcase))
end

.update(zone, ip, key, wild = false, soa = nil) ⇒ Object

Raises:



57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
# File 'lib/ddnsupdate.rb', line 57

def self.update(zone, ip, key, wild = false, soa = nil)
  soa         = determine_soa(zone) if soa.nil?
  raise UpdateError, "can't find SOA for #{zone}" if soa.nil?
  curip       = determine_current_ip(zone, soa)

  if curip != ip
    delete_seq  = <<-";"
                  server #{soa}
                  key #{zone}. #{key}
                  prereq yxdomain #{zone}.
                  update delete #{zone}. A
                  ;
    delete_seq += "                    update delete *.#{zone}. A\n" if wild
    delete_seq += "                    send\n"

    create_seq  = <<-";"
                  server #{soa}
                  key #{zone}. #{key}
                  prereq nxdomain #{zone}.
                  update add #{zone}. 300 A #{ip}
                  ;
    create_seq += "                    update add *.#{zone}. 300 A #{ip}\n" if wild
    create_seq += "                    send\n"

    Open3.popen3("nsupdate") do |stdin, stdout, stderr|
      stdin << delete_seq << create_seq
      stdin.close_write
      err = stderr.read
      raise UpdateError, err unless err.empty?
    end
    true
  else
    false
  end
end