2
# $Id: generic.rb,v 1.26 2003/12/01 09:45:15 sdalu Exp $
5
# CONTACT : zonecheck@nic.fr
6
# AUTHOR : Stephane D'Alu <sdalu@nic.fr>
8
# CREATED : 2002/08/02 13:58:17
9
# REVISION : $Revision: 1.26 $
10
# DATE : $Date: 2003/12/01 09:45:15 $
12
# CONTRIBUTORS: (see also CREDITS file)
15
# LICENSE : GPL v2 (or MIT/X11-like after agreement)
16
# COPYRIGHT : AFNIC (c) 2003
18
# This file is part of ZoneCheck.
20
# ZoneCheck is free software; you can redistribute it and/or modify it
21
# under the terms of the GNU General Public License as published by
22
# the Free Software Foundation; either version 2 of the License, or
23
# (at your option) any later version.
25
# ZoneCheck is distributed in the hope that it will be useful, but
26
# WITHOUT ANY WARRANTY; without even the implied warranty of
27
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
28
# General Public License for more details.
30
# You should have received a copy of the GNU General Public License
31
# along with ZoneCheck; if not, write to the Free Software Foundation,
32
# Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
39
## Check syntax validity of the domain name
41
class DomainNameSyntax < Test
42
with_msgcat 'test/generic.%s'
44
#-- Checks --------------------------------------------------
45
# DESC: A domainname should only contains A-Z a-Z 0-9 '-' '.'
47
@domain.name.to_s =~ /^[A-Za-z0-9\-\.]+$/
50
# DESC: A domainname should not countain a double hyphen
52
! (@domain.name.to_s =~ /--/)
55
# DESC: A domainname should not start or end with an hyphen
57
! (@domain.name.to_s =~ /(^|\.)-|-(\.|$)/)
64
## Check basic absurdity with the nameserver IP addresses
66
class ServerAddress < Test
67
with_msgcat 'test/generic.%s'
69
#-- Initialization ------------------------------------------
72
@cache.create(:ip, :by_subnet)
75
#-- Shortcuts -----------------------------------------------
78
ip = @domain.ns.collect { |ns, ips| ips }
85
@domain.ns.each { |ns, ips|
86
return ns if ips.include?(ip)
92
@cache.use(:by_subnet) {
95
net = case i # decide of subnet size:
96
when Address::IPv4 then i.prefix(28) # /28 for IPv4
97
when Address::IPv6 then i.prefix(64) # /64 for IPv6
99
nethosts[net] = [ ] unless nethosts.has_key?(net)
106
#-- Checks --------------------------------------------------
107
# DESC: Addresses should be distincts
109
# Ok all addresses are distincts
110
return true if ip == ip.uniq
112
# Create data for failure handling
114
@domain.ns.each { |ns, ips|
116
hosts[i] = [ ] unless hosts.has_key?(i)
120
hosts.delete_if { |k, v| v.size < 2 }
121
hosts.each { |k, v| # Got at least 1 entry as ip != ip.uniq
122
return { 'ip' => k, 'ns' => v.join(', ') }
126
# DESC: Addresses should avoid belonging to the same network
128
# Only keep list of hosts on same subnet
129
same_net = by_subnet.dup.delete_if { |k, v| v.size < 2 }
131
# Ok all hosts are on different subnets
132
return true if same_net.empty?
134
# Create output data for failure
136
same_net.each { |k, v|
137
hlist = (v.collect { |i| ns = ns_from_ip(i) }).join(', ')
139
when Address::IPv4 then 28
140
when Address::IPv6 then 64
142
subnetlist << "#{k}/#{prefix} (#{hlist})"
144
return { 'subnets' => subnetlist.join(', ') }
147
# DESC: Addresses should avoid belonging ALL to the same network
148
# WARN: Test is wrong in case of IPv4 and IPv6
149
def chk_ip_all_same_net
150
# Ok not all hosts are on the same subnet
151
return true unless ((by_subnet.size == 1) &&
152
(by_subnet.values[0].size > 1))
154
# Create output data for failure
155
subnet = by_subnet.keys[0]
157
when Address::IPv4 then 28
158
when Address::IPv6 then 64
160
return { 'subnet' => "#{subnet}/#{prefix}" }
163
# DESC: Addresses should avoid belonging ALL to the same AS
165
asn = ip.collect { |addr|
166
aname = NResolv::DNS::Name::create(addr.to_dnsform +
167
'.asn.routeviews.org.')
168
txtres = @cm[nil].txt(aname, NResolv::DNS::Resource::IN::TXT)
172
asn.size > 1 ? true : { 'asn' => asn[0] }
178
## Check for nameserver!
180
class NameServers < Test
181
with_msgcat 'test/generic.%s'
183
#-- Checks --------------------------------------------------
184
# DESC: A domain should have a nameserver!
186
@domain.ns.length >= 1
189
# DESC: A domain should have at least 2 nameservers
191
@domain.ns.length >= 2
199
class Delegation < Test
200
with_msgcat 'test/generic.%s'
202
#-- Initialisation ------------------------------------------
203
def initialize(*args)
205
@querysize = const('delegation_query_size').to_i
208
#-- Checks --------------------------------------------------
209
def chk_delegation_udp512
211
msg = NResolv::DNS::Message::Answer::new
212
msg.question.add(NResolv::DNS::Name::Root,
213
NResolv::DNS::Resource::IN::NS)
214
@domain.ns.each { |ns, ips|
215
msg.authority.add(@domain.name,
216
NResolv::DNS::Resource::IN::NS::new(ns),
219
excess = (msg.to_wire.size + @querysize-1) - 512
221
return true if excess <= 0
222
{ 'excess' => excess }
225
def chk_delegation_udp512_additional
227
msg = NResolv::DNS::Message::Answer::new
228
msg.question.add(NResolv::DNS::Name::Root,
229
NResolv::DNS::Resource::IN::NS)
230
@domain.ns.each { |ns, ips|
231
msg.answer.add(@domain.name,
232
NResolv::DNS::Resource::IN::NS::new(ns),
235
if ns.in_domain?(@domain.name)
237
msg.additional.add(ns, ip.to_dnsressource, dummyttl) }
241
excess = (msg.to_wire.size + @querysize-1) - 512
243
return true if excess <= 0
244
{ 'excess' => excess }