dyndyndong 0.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
data/bin/dyndyndong ADDED
@@ -0,0 +1,219 @@
1
+ #!/usr/bin/env ruby
2
+ #
3
+ # Copyleft shura. [shura1991@gmail.com]
4
+ #
5
+ # This file is part of DynDynDong.
6
+ #
7
+ # DynDynDong is free software: you can redistribute it and/or modify
8
+ # it under the terms of the GNU Affero General Public License as published
9
+ # by the Free Software Foundation, either version 3 of the License, or
10
+ # (at your option) any later version.
11
+ #
12
+ # DynDynDong is distributed in the hope that it will be useful,
13
+ # but WITHOUT ANY WARRANTY; without even the implied warranty of
14
+ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15
+ # GNU Affero General Public License for more details.
16
+ #
17
+ # You should have received a copy of the GNU Affero General Public License
18
+ # along with failirc. If not, see <http://www.gnu.org/licenses/>.
19
+
20
+ require 'dyndyndong'
21
+
22
+ def die(str)
23
+ STDERR.puts str
24
+ exit 1
25
+ end
26
+
27
+ def help
28
+ puts <<HELP
29
+ DynDynDong v#{DynDynDong::VERSION} is distributed under the GNU Affero General Public License.
30
+
31
+ USAGE: #{$0} [-d|-h|-1] [-c <config file>] [-D <delay>] [-s <service> <service args>]
32
+ -d|--daemon Run DynDynDong as a daemon (default no).
33
+ -h|--help Show this help.
34
+ -D|--delay Set time to wait between two cycles (default 600).
35
+ -1|--oneshot Do only a cycle (default no).
36
+ -c|--config Set alternative configuration file (default /etc/dyndyndong.conf).
37
+ -s|--service Start to parse a service, no defaults, you have to choose between:
38
+ - afraid For freedns.afraid.org
39
+ AVAILABLE ARGUMENTS:
40
+ -H|-host Set a single host or more hosts separated with ',' (comma), it can be repeated
41
+ - dyndns Fro dyndns.com
42
+ AVAILABLE ARGUMENTS:
43
+ -u|--username Set username for login, it can't be repeated
44
+ -p|--password Set password for login, it can't be repeated
45
+ -H|--host Set a single host or more hosts separated with ',' (comma), it can be repeated
46
+ -o|--offline Set a single host or more hosts separated with ',' (comma) to make offline, it
47
+ can be repeated
48
+ Parsing of services' arguments stop when an unrelated argument is given.
49
+ HELP
50
+ exit 0
51
+ end
52
+
53
+ CONFIG = '/etc/dyndyndong.conf'
54
+ DEFAULT_CONFIG = CONFIG.dup
55
+ oneshot = daemon = false
56
+
57
+ i, SERVICES = 0, {
58
+ :dyndns => [],
59
+ :afraid => []
60
+ }
61
+
62
+
63
+ while i < ARGV.size
64
+ parsed = false
65
+ case ARGV[i]
66
+ when '-d', '--daemon'
67
+ daemon = true
68
+ when '-h', '--help'
69
+ help
70
+ when /^-D/, '--delay'
71
+ if %w{-D --delay}.include?(ARGV[i])
72
+ delay = ARGV[i += 1]
73
+ else
74
+ delay = ARGV[i].gsub(/^-D/, '')
75
+ end
76
+ parsed = true
77
+ when '-1', '--oneshot'
78
+ parsed = oneshot = true
79
+ when /^-c/, '--config'
80
+ if %w{-c --config}.include?(ARGV[i])
81
+ CONFIG.replace(ARGV[i += 1])
82
+ else
83
+ CONFIG.replace(ARGV[i].gsub(/^-c/, ''))
84
+ end
85
+ parsed = true
86
+ when /^-s/, '--service'
87
+ if %w{-s --service}.include?(ARGV[i])
88
+ service = ARGV[i += 1]
89
+ else
90
+ service = ARGV[i].gsub(/^-s/, '')
91
+ end
92
+
93
+ case service
94
+ when 'dyndns'
95
+ srv = {:hosts => [], :offline => []}
96
+ while (i += 1) < ARGV.size
97
+ parsed = true
98
+ case ARGV[i]
99
+ when /^-u/, '--username'
100
+ die "Can't add more than one username" if srv[:username]
101
+
102
+ if %w{-u --username}.include?(ARGV[1])
103
+ srv[:username] = ARGV[i += 1]
104
+ else
105
+ srv[:username] = ARGV[i].gsub(/^-u/, '')
106
+ end
107
+ when /^-p/, '--password'
108
+ die "Can't add more than one password" if srv[:password]
109
+
110
+ if %w{-p --password}.include?(ARGV[1])
111
+ srv[:password] = ARGV[i += 1]
112
+ else
113
+ srv[:password] = ARGV[i].gsub(/^-p/, '')
114
+ end
115
+ when /^-H/, '--host'
116
+ if %w{-H --host}.include?(ARGV[i])
117
+ srv[:hosts] << ARGV[i += 1].split(',')
118
+ else
119
+ srv[:hosts] << ARGV[i].gsub(/^-H/, '').split(',')
120
+ end
121
+ when /^-o/, '--offline'
122
+ if %w{-o --offline}.include?(ARGV[i])
123
+ srv[:offline] << ARGV[i += 1].split(',')
124
+ else
125
+ srv[:offline] << ARGV[i].gsub(/^-o/).split(',')
126
+ end
127
+ else
128
+ parsed = false
129
+ break
130
+ end
131
+ end
132
+ srv[:hosts].flatten!
133
+ srv[:offline].flatten!
134
+ when 'afraid'
135
+ srv = []
136
+
137
+ while (i += 1) < ARGV.size
138
+ parsed = true
139
+ if ARGV[i] == '--host' or ARGV[i] == '-H'
140
+ srv += ARGV[i += 1].split(',').map {|h|
141
+ h.split(':')
142
+ }
143
+ elsif ARGV[i] =~ /^-H/
144
+ srv += ARGV[i].gsub(/^-H/, '').split(',').map {|h|
145
+ h.split(':')
146
+ }
147
+ else
148
+ parsed = false
149
+ break
150
+ end
151
+ end
152
+ else
153
+ die "Service #{service} doesn't exist"
154
+ end
155
+
156
+ i -= parsed ? 0 : 1
157
+ parsed = true
158
+
159
+ case service
160
+ when 'dyndns'
161
+ SERVICES[service.to_sym] << srv
162
+ when 'afraid'
163
+ SERVICES[service.to_sym] += srv
164
+ end
165
+ end
166
+
167
+ die "Unrecognized option #{ARGV[i].inspect}" if !parsed
168
+
169
+ i += 1
170
+ end
171
+
172
+ DAEMONIZE = daemon
173
+
174
+ DynDynDong.delay = delay if delay
175
+
176
+ die "You can't run client with --oneshot and --daemon simultaneously" if oneshot and DAEMONIZE
177
+
178
+ if SERVICES != {:dyndns=>[],:afraid=>[]}
179
+ if CONFIG == DEFAULT_CONFIG
180
+ SERVICES[:dyndns].each {|dyndns|
181
+ d = DynDynDong::DynDNS.new
182
+ d.username = dyndns[:username]
183
+ d.password = dyndns[:password]
184
+ dyndns[:hosts].each {|host|
185
+ d.host host
186
+ }
187
+ dyndns[:offline].each {|offline|
188
+ d.offline offline
189
+ }
190
+ }
191
+
192
+ SERVICES[:afraid].each {|afraid|
193
+ a = DynDynDong::Afraid.new
194
+ begin
195
+ a.host(*afraid)
196
+ rescue ArgumentError
197
+ die "Respect the syntax of afraid please."
198
+ end
199
+ }
200
+ else
201
+ die "You can't use a configure file with custom services"
202
+ end
203
+ else
204
+ begin
205
+ eval(File.read(CONFIG))
206
+ rescue Exception => e
207
+ die "Config error: #{e}"
208
+ end
209
+ end
210
+
211
+ if DAEMONIZE
212
+ DynDynDong::Daemon.start
213
+ else
214
+ if oneshot
215
+ DynDynDong::Client.start
216
+ else
217
+ DynDynDong::Client.start_loop
218
+ end
219
+ end
@@ -0,0 +1,38 @@
1
+ # Copyleft shura. [shura1991@gmail.com]
2
+ #
3
+ # This file is part of DynDynDong.
4
+ #
5
+ # DynDynDong is free software: you can redistribute it and/or modify
6
+ # it under the terms of the GNU Affero General Public License as published
7
+ # by the Free Software Foundation, either version 3 of the License, or
8
+ # (at your option) any later version.
9
+ #
10
+ # DynDynDong is distributed in the hope that it will be useful,
11
+ # but WITHOUT ANY WARRANTY; without even the implied warranty of
12
+ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13
+ # GNU Affero General Public License for more details.
14
+ #
15
+ # You should have received a copy of the GNU Affero General Public License
16
+ # along with failirc. If not, see <http://www.gnu.org/licenses/>.
17
+
18
+ require 'dyndyndong/services'
19
+ require 'dyndyndong/dyndyndong'
20
+
21
+ module DynDynDong
22
+
23
+ class Client
24
+ def self.start
25
+ DynDynDong::Service.each {|s|
26
+ s.fetch
27
+ }
28
+ end
29
+
30
+ def self.start_loop
31
+ while true
32
+ self.start
33
+ sleep DynDynDong.delay
34
+ end
35
+ end
36
+ end
37
+
38
+ end
@@ -0,0 +1,31 @@
1
+ # Copyleft shura. [shura1991@gmail.com]
2
+ #
3
+ # This file is part of DynDynDong.
4
+ #
5
+ # DynDynDong is free software: you can redistribute it and/or modify
6
+ # it under the terms of the GNU Affero General Public License as published
7
+ # by the Free Software Foundation, either version 3 of the License, or
8
+ # (at your option) any later version.
9
+ #
10
+ # DynDynDong is distributed in the hope that it will be useful,
11
+ # but WITHOUT ANY WARRANTY; without even the implied warranty of
12
+ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13
+ # GNU Affero General Public License for more details.
14
+ #
15
+ # You should have received a copy of the GNU Affero General Public License
16
+ # along with failirc. If not, see <http://www.gnu.org/licenses/>.
17
+
18
+ require 'dyndyndong/client'
19
+ require 'daemons'
20
+
21
+ module DynDynDong
22
+
23
+ class Daemon
24
+ def self.start
25
+ Daemons.daemonize
26
+
27
+ DynDynDong::Client.start_loop
28
+ end
29
+ end
30
+
31
+ end
@@ -0,0 +1,27 @@
1
+ # Copyleft shura. [shura1991@gmail.com]
2
+ #
3
+ # This file is part of DynDynDong.
4
+ #
5
+ # DynDynDong is free software: you can redistribute it and/or modify
6
+ # it under the terms of the GNU Affero General Public License as published
7
+ # by the Free Software Foundation, either version 3 of the License, or
8
+ # (at your option) any later version.
9
+ #
10
+ # DynDynDong is distributed in the hope that it will be useful,
11
+ # but WITHOUT ANY WARRANTY; without even the implied warranty of
12
+ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13
+ # GNU Affero General Public License for more details.
14
+ #
15
+ # You should have received a copy of the GNU Affero General Public License
16
+ # along with failirc. If not, see <http://www.gnu.org/licenses/>.
17
+
18
+ module DynDynDong
19
+ def self.delay
20
+ @delay || 600
21
+ end
22
+
23
+ def self.delay=(n)
24
+ raise Exception, "Insert a numeric value for delay" if !n.is_a?(Numeric)
25
+ @delay = n
26
+ end
27
+ end
@@ -0,0 +1,41 @@
1
+ # Copyleft shura. [shura1991@gmail.com]
2
+ #
3
+ # This file is part of DynDynDong.
4
+ #
5
+ # DynDynDong is free software: you can redistribute it and/or modify
6
+ # it under the terms of the GNU Affero General Public License as published
7
+ # by the Free Software Foundation, either version 3 of the License, or
8
+ # (at your option) any later version.
9
+ #
10
+ # DynDynDong is distributed in the hope that it will be useful,
11
+ # but WITHOUT ANY WARRANTY; without even the implied warranty of
12
+ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13
+ # GNU Affero General Public License for more details.
14
+ #
15
+ # You should have received a copy of the GNU Affero General Public License
16
+ # along with failirc. If not, see <http://www.gnu.org/licenses/>.
17
+
18
+ require 'net/http'
19
+
20
+ module DynDynDong
21
+
22
+ class Afraid < Service
23
+ def initialize(*args)
24
+ super(*args)
25
+ end
26
+
27
+ def host(domain, hash)
28
+ @hosts << [domain, hash]
29
+ end
30
+
31
+ def alias_host(domain, hash)
32
+ begin
33
+ res = Net::HTTP.get(URI.parse("http://freedns.afraid.org/dynamic/update.php?#{hash}"))
34
+ rescue Exception => e
35
+ return "#{e} -- skipping..."
36
+ end
37
+ res
38
+ end
39
+ end
40
+
41
+ end
@@ -0,0 +1,110 @@
1
+ # Copyleft shura. [shura1991@gmail.com]
2
+ #
3
+ # This file is part of DynDynDong.
4
+ #
5
+ # DynDynDong is free software: you can redistribute it and/or modify
6
+ # it under the terms of the GNU Affero General Public License as published
7
+ # by the Free Software Foundation, either version 3 of the License, or
8
+ # (at your option) any later version.
9
+ #
10
+ # DynDynDong is distributed in the hope that it will be useful,
11
+ # but WITHOUT ANY WARRANTY; without even the implied warranty of
12
+ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13
+ # GNU Affero General Public License for more details.
14
+ #
15
+ # You should have received a copy of the GNU Affero General Public License
16
+ # along with failirc. If not, see <http://www.gnu.org/licenses/>.
17
+
18
+ require 'net/http'
19
+
20
+ module DynDynDong
21
+
22
+ class DynDNS < Service
23
+ MSGTABLE = {
24
+ 'badauth' => 'The username and password pair do not match a real user.',
25
+ '!donator' => 'Option available only to credited users.',
26
+ 'good' => 'The update was successful, and the hostname is now updated.',
27
+ 'nochg' => 'The update changed no settings, and is considered abusive.',
28
+ 'notfqdn' => 'The hostname specified is not a fully-qualified domain name.',
29
+ 'nohost' => 'The hostname specified does not exist in this user account.',
30
+ 'numhost' => 'Too many hosts specified in an update.',
31
+ 'abuse' => 'The hostname specified is blocked for update abuse.',
32
+ 'badagent' => 'The user agent was not sent or HTTP method is not permitted.',
33
+ 'good 127.0.0.1' => 'Request was ignored because of agent that does not follow our specifications.',
34
+ 'dnserr' => 'DNS error encountered.',
35
+ '911' => 'There is a problem or scheduled maintenance on our side.'
36
+ }
37
+
38
+ def initialize(*args)
39
+ @user = nil
40
+ @pass = nil
41
+ @ip = getip
42
+ super(*args)
43
+ end
44
+
45
+ def username(u)
46
+ @user = u.to_s
47
+ end
48
+
49
+ def password(p)
50
+ @pass = p.to_s
51
+ end
52
+
53
+ alias username= username
54
+ alias password= password
55
+
56
+ def host(h)
57
+ begin
58
+ @hosts << [h.to_s, getip(h)]
59
+ rescue Exception => e
60
+ STDERR.puts "Ip detection error: #{e}, skipping..."
61
+ end
62
+ end
63
+
64
+ def offline(h)
65
+ begin
66
+ @hosts << [h.to_s, getip(h), true]
67
+ rescue Exception => e
68
+ STDERR.puts "Ip detection error: #{e}, skipping..."
69
+ end
70
+ end
71
+
72
+ def prefetch
73
+ if !(@user and @pass)
74
+ raise "username or password ungiven"
75
+ end
76
+ end
77
+
78
+ def alias_host(h, ip, offline = false)
79
+ return "Nothing to update." if ip == @ip
80
+
81
+ Net::HTTP.start('members.dyndns.org') {|http|
82
+ req = Net::HTTP::Get.new('/nic/update?hostname=%s&myip=%s&offline=%s' % [
83
+ URI.escape(h), @ip, (offline ? 'YES' : 'NOCHG')])
84
+ req.basic_auth @user, @pass
85
+ x = http.request(req).body.gsub(/#{Regexp.escape(@ip)}/, '').strip
86
+ MSGTABLE[x]
87
+ }
88
+ end
89
+
90
+ private
91
+ def getip(h = nil)
92
+ if h
93
+ addr = Socket::getaddrinfo(h, 'www', nil, Socket::SOCK_STREAM)[0][3]
94
+ if addr == Socket::getaddrinfo(Socket::gethostname, 'www', nil, Socket::SOCK_STREAM)[0][3]
95
+ return @ip
96
+ else
97
+ return addr
98
+ end
99
+ end
100
+ str = Net::HTTP.get(URI.parse('http://checkip.dyndns.org/')).
101
+ match(/<body>(.+?)<\/body>/)[1] rescue ""
102
+ if str =~ /^Current IP Address: \d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}$/
103
+ return str.gsub(/^Current IP Address: /, '')
104
+ else
105
+ raise "Couldn't retrieve ip."
106
+ end
107
+ end
108
+ end
109
+
110
+ end
@@ -0,0 +1,91 @@
1
+ # Copyleft shura. [shura1991@gmail.com]
2
+ #
3
+ # This file is part of DynDynDong.
4
+ #
5
+ # DynDynDong is free software: you can redistribute it and/or modify
6
+ # it under the terms of the GNU Affero General Public License as published
7
+ # by the Free Software Foundation, either version 3 of the License, or
8
+ # (at your option) any later version.
9
+ #
10
+ # DynDynDong is distributed in the hope that it will be useful,
11
+ # but WITHOUT ANY WARRANTY; without even the implied warranty of
12
+ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13
+ # GNU Affero General Public License for more details.
14
+ #
15
+ # You should have received a copy of the GNU Affero General Public License
16
+ # along with failirc. If not, see <http://www.gnu.org/licenses/>.
17
+
18
+ module DynDynDong
19
+
20
+ class Service
21
+
22
+ def initialize(&block)
23
+ @@instances ||= []
24
+ @@instances << self
25
+ @hosts = []
26
+ self.instance_eval(&block) if block
27
+ end
28
+
29
+ def fetch
30
+ begin
31
+ prefetch if (self.method(:prefetch) rescue nil)
32
+ rescue Exception => e
33
+ STDERR.puts("Prefetch error: #{e}, skipping...")
34
+ return
35
+ end
36
+
37
+ @hosts.each {|args|
38
+ STDOUT.write("Aliasing #{args.first}...")
39
+ begin
40
+ res = alias_host(*args)
41
+ STDOUT.write("\r--- #{args.first} \n\t#{res.gsub(/\n/, "\n\t")}\n")
42
+ rescue Exception => e
43
+ STDERR.puts("\tFetch error: #{e}, skipping...")
44
+ end
45
+ }
46
+
47
+ begin
48
+ postfetch if self.method(:postfetch) rescue nil
49
+ rescue Exception => e
50
+ STDERR.puts("Postfetch error: #{e}")
51
+ end
52
+ end
53
+
54
+ def method_missing(sym, *args, &block)
55
+ STDERR.puts("#{sym.to_s.inspect} missed for #{self.class}, skipping...")
56
+ end
57
+
58
+ def self.instances
59
+ @@instances ||=[]
60
+ @@instances
61
+ end
62
+
63
+ def self.inherited(obj)
64
+ @@services ||= []
65
+ @@services << obj
66
+ end
67
+
68
+ def self.services
69
+ @@services ||= []
70
+ @@services
71
+ end
72
+
73
+ def self.each
74
+ objs = []
75
+ self.instances.each {|i|
76
+ objs << i
77
+ yield i if block_given?
78
+ }
79
+ if block_given?
80
+ objs
81
+ else
82
+ Enumerator.new(objs)
83
+ end
84
+ end
85
+
86
+ end
87
+
88
+ end
89
+
90
+ require 'dyndyndong/services/afraid'
91
+ require 'dyndyndong/services/dyndns'
@@ -0,0 +1,22 @@
1
+ # Copyleft shura. [shura1991@gmail.com]
2
+ #
3
+ # This file is part of DynDynDong.
4
+ #
5
+ # DynDynDong is free software: you can redistribute it and/or modify
6
+ # it under the terms of the GNU Affero General Public License as published
7
+ # by the Free Software Foundation, either version 3 of the License, or
8
+ # (at your option) any later version.
9
+ #
10
+ # DynDynDong is distributed in the hope that it will be useful,
11
+ # but WITHOUT ANY WARRANTY; without even the implied warranty of
12
+ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13
+ # GNU Affero General Public License for more details.
14
+ #
15
+ # You should have received a copy of the GNU Affero General Public License
16
+ # along with failirc. If not, see <http://www.gnu.org/licenses/>.
17
+
18
+ module DynDynDong
19
+
20
+ VERSION = '0.0.1'
21
+
22
+ end
data/lib/dyndyndong.rb ADDED
@@ -0,0 +1,19 @@
1
+ # Copyleft shura. [shura1991@gmail.com]
2
+ #
3
+ # This file is part of DynDynDong.
4
+ #
5
+ # DynDynDong is free software: you can redistribute it and/or modify
6
+ # it under the terms of the GNU Affero General Public License as published
7
+ # by the Free Software Foundation, either version 3 of the License, or
8
+ # (at your option) any later version.
9
+ #
10
+ # DynDynDong is distributed in the hope that it will be useful,
11
+ # but WITHOUT ANY WARRANTY; without even the implied warranty of
12
+ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13
+ # GNU Affero General Public License for more details.
14
+ #
15
+ # You should have received a copy of the GNU Affero General Public License
16
+ # along with failirc. If not, see <http://www.gnu.org/licenses/>.
17
+
18
+ require 'dyndyndong/client'
19
+ require 'dyndyndong/daemon'
metadata ADDED
@@ -0,0 +1,84 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: dyndyndong
3
+ version: !ruby/object:Gem::Version
4
+ prerelease: false
5
+ segments:
6
+ - 0
7
+ - 0
8
+ - 1
9
+ version: 0.0.1
10
+ platform: ruby
11
+ authors:
12
+ - shura
13
+ autorequire:
14
+ bindir: bin
15
+ cert_chain: []
16
+
17
+ date: 2010-11-02 00:00:00 +01:00
18
+ default_executable:
19
+ dependencies:
20
+ - !ruby/object:Gem::Dependency
21
+ name: daemons
22
+ prerelease: false
23
+ requirement: &id001 !ruby/object:Gem::Requirement
24
+ none: false
25
+ requirements:
26
+ - - ">="
27
+ - !ruby/object:Gem::Version
28
+ segments:
29
+ - 0
30
+ version: "0"
31
+ type: :runtime
32
+ version_requirements: *id001
33
+ description: Ruby written dyndns client.
34
+ email: shura1991@gmail.com
35
+ executables:
36
+ - dyndyndong
37
+ extensions: []
38
+
39
+ extra_rdoc_files: []
40
+
41
+ files:
42
+ - lib/dyndyndong.rb
43
+ - lib/dyndyndong/services.rb
44
+ - lib/dyndyndong/version.rb
45
+ - lib/dyndyndong/services/dyndns.rb
46
+ - lib/dyndyndong/services/afraid.rb
47
+ - lib/dyndyndong/dyndyndong.rb
48
+ - lib/dyndyndong/daemon.rb
49
+ - lib/dyndyndong/client.rb
50
+ - bin/dyndyndong
51
+ has_rdoc: true
52
+ homepage: http://github.com/shurizzle/DynDynDong
53
+ licenses: []
54
+
55
+ post_install_message:
56
+ rdoc_options: []
57
+
58
+ require_paths:
59
+ - lib
60
+ required_ruby_version: !ruby/object:Gem::Requirement
61
+ none: false
62
+ requirements:
63
+ - - ">="
64
+ - !ruby/object:Gem::Version
65
+ segments:
66
+ - 0
67
+ version: "0"
68
+ required_rubygems_version: !ruby/object:Gem::Requirement
69
+ none: false
70
+ requirements:
71
+ - - ">="
72
+ - !ruby/object:Gem::Version
73
+ segments:
74
+ - 0
75
+ version: "0"
76
+ requirements: []
77
+
78
+ rubyforge_project:
79
+ rubygems_version: 1.3.7
80
+ signing_key:
81
+ specification_version: 3
82
+ summary: Ruby written client to update dynamic dns, it supports many services.
83
+ test_files: []
84
+