A lot of BIND specific checks

This commit is contained in:
Miek Gieben 2011-09-21 14:22:43 +02:00
parent a91881457e
commit da2e464de1
4 changed files with 138 additions and 52 deletions

View File

@ -6,6 +6,7 @@ import (
const (
QUERY_NOERROR string = "QUERY,NOERROR,qr,aa,tc,rd,ra,ad,cd,z,0,0,0,0,do,0"
QUERY_NOTIFY string = "NOTIFY,NOERROR,qr,AA,tc,RD,ra,ad,cd,Z,0,0,0,0,do,0"
QUERY_ALL string = "QUERY,NOERROR,QR,AA,TC,RD,RA,AD,CD,Z,0,0,0,0,DO,0"
)
@ -41,12 +42,26 @@ func dnsServer(l *lexer) stateFn {
// MaraDNS clears DO BIT, UDPSize to 0. REFUSED
l.emit(&item{itemVendor, MARA})
return dnsMaraLike
case !f.Do && f.UDPSize == 0 && f.Rcode == dns.RcodeSuccess:
// PowerDNS(SEC) clears DO bit, resets UDPSize. NOERROR
case !f.Do && f.UDPSize == 0 && f.Rcode == dns.RcodeSuccess:
// PowerDNS(SEC) clears DO bit, resets UDPSize. NOERROR
l.emit(&item{itemVendor, POWER})
return dnsPowerDNSLike
return dnsPowerdnsLike
case !f.Do && f.UDPSize == 0 && f.Rcode == dns.RcodeServerFailure:
// Neustar
l.emit(&item{itemVendor, NEUSTAR})
return dnsNeustarLike
case !f.Do && f.UDPSize == 0 && f.Rcode == dns.RcodeNotImplemented:
// Altas?
l.emit(&item{itemVendor, VERISIGN})
return dnsAtlasLike
case !f.Do && f.UDPSize == 4096 && f.Rcode == dns.RcodeServerFailure:
// BIND8
fallthrough
case f.Do && f.UDPSize == 4096 && f.Rcode == dns.RcodeServerFailure:
// BIND9 OLD
fallthrough
case f.Do && f.UDPSize == 4096 && f.Rcode == dns.RcodeRefused:
// BIND leaves DO bit, but sets UDPSize to 4096. REFUSED.
// BIND9 leaves DO bit, but sets UDPSize to 4096. REFUSED.
l.emit(&item{itemVendor, ISC})
return dnsBindLike
case f.Do && f.UDPSize == 4097 && f.Rcode == dns.RcodeFormatError:
@ -62,6 +77,9 @@ func dnsServer(l *lexer) stateFn {
func dnsNsdLike(l *lexer) stateFn {
l.verbose("NsdLike")
l.setString(QUERY_NOERROR)
l.setQuestion("authors.bind.", dns.TypeTXT, dns.ClassCHAOS)
l.probe()
return nil
}
@ -69,6 +87,57 @@ func dnsNsdLike(l *lexer) stateFn {
func dnsBindLike(l *lexer) stateFn {
l.verbose("BindLike")
l.emit(&item{itemSoftware, BIND})
// Repeat the query, as we get a lot of information from it
l.setString("QUERY,NOERROR,qr,aa,tc,RD,ra,ad,cd,z,0,0,0,0,DO,4097")
l.setQuestion(".", dns.TypeTXT, dns.ClassCHAOS)
f := l.probe()
switch {
case !f.Do && f.UDPSize == 4096 && f.Rcode == dns.RcodeServerFailure:
l.emit(&item{itemVersionMajor, "8"})
case f.Do && f.UDPSize == 4096 && f.Rcode == dns.RcodeServerFailure:
l.emit(&item{itemVersionMajor, "9"})
l.emit(&item{itemVersionMajor, "3"})
case f.Do && f.UDPSize == 4096 && f.Rcode == dns.RcodeRefused:
// BIND9 leaves DO bit, but sets UDPSize to 4096. REFUSED.
l.emit(&item{itemVersionMajor, "9"})
l.emit(&item{itemVersionMajor, "[7..]"})
}
// Try authors.bind
l.setString(QUERY_NOERROR)
l.setQuestion("authors.bind.", dns.TypeTXT, dns.ClassCHAOS)
f = l.probe()
switch f.Rcode {
case dns.RcodeServerFailure:
// No authors.bind < 9
l.emit(&item{itemVersionMajor, "8"})
case dns.RcodeSuccess, dns.RcodeRefused:
// BIND 9 or BIND 10
l.emit(&item{itemVersionMajor, "[9..10]"})
}
// The three BIND (8, 9 and 10) behave differently when
// receiving a notify query
l.setString(QUERY_NOTIFY)
l.setQuestion("bind.", dns.TypeSOA, dns.ClassNONE)
f = l.probe()
switch {
case f.Opcode == dns.OpcodeNotify:
if f.Rcode == dns.RcodeRefused {
l.emit(&item{itemVersionMajor, "9"})
}
if f.Rcode == dns.RcodeServerFailure {
l.emit(&item{itemVersionMajor, "8"})
}
case f.Opcode == dns.OpcodeQuery && f.Rcode == dns.RcodeSuccess:
l.emit(&item{itemVersionMajor, "10"})
if !f.Response {
// Cardinal sin
l.emit(&item{itemVersionMinor, "-devel"})
l.emit(&item{itemVersionPatch, "20110809"})
}
}
return nil
}
@ -84,8 +153,20 @@ func dnsMaraLike(l *lexer) stateFn {
return nil
}
func dnsPowerDNSLike(l *lexer) stateFn {
l.verbose("PowerDNSLike")
func dnsPowerdnsLike(l *lexer) stateFn {
l.verbose("PowerdnsLike")
return nil
}
func dnsNeustarLike(l *lexer) stateFn {
l.verbose("NeustarLike")
return nil
}
func dnsAtlasLike(l *lexer) stateFn {
l.verbose("AtlasLike")
return nil
}

View File

@ -11,18 +11,22 @@ import (
const (
// Detected software types
NSD = "NSD"
BIND = "BIND"
POWERDNS = "PowerDNS"
WINDOWSDNS = "Windows DNS"
MARADNS = "MaraDNS"
NSD = "NSD"
BIND = "BIND"
POWERDNS = "PowerDNS"
WINDOWSDNS = "Windows DNS"
MARADNS = "MaraDNS"
NEUSTARDNS = "Neustar DNS"
ATLAS = "Atlas"
// Vendors
ISC = "ISC"
MARA = "MaraDNS.org" // check
MARA = "MaraDNS.org" // check
NLNETLABS = "NLnet Labs"
MICROSOFT = "Microsoft"
POWER = "PowerDNS"
POWER = "PowerDNS.com"
NEUSTAR = "Neustar"
VERISIGN = "Verisign"
)
func startParse(addr string) {
@ -87,18 +91,18 @@ func (f *fingerprint) String() string {
return "<nil>"
}
// Use the same order as in Perl's fpdns. But use more flags.
var s string
if op, ok := dns.Opcode_str[f.Opcode]; ok {
s = op
} else { // number
s = valueOfInt(f.Opcode)
}
var s string
if op, ok := dns.Opcode_str[f.Opcode]; ok {
s = op
} else { // number
s = valueOfInt(f.Opcode)
}
if op, ok := dns.Rcode_str[f.Rcode]; ok {
s += "," + op
} else { // number
s += "," + valueOfInt(f.Rcode)
}
if op, ok := dns.Rcode_str[f.Rcode]; ok {
s += "," + op
} else { // number
s += "," + valueOfInt(f.Rcode)
}
s += valueOfBool(f.Response, ",qr")
s += valueOfBool(f.Authoritative, ",aa")
@ -109,21 +113,21 @@ func (f *fingerprint) String() string {
s += valueOfBool(f.CheckingDisabled, ",cd")
s += valueOfBool(f.Zero, ",z")
s += ","+valueOfInt(f.Question)
s += ","+valueOfInt(f.Answer)
s += ","+valueOfInt(f.Ns)
s += ","+valueOfInt(f.Extra)
s += "," + valueOfInt(f.Question)
s += "," + valueOfInt(f.Answer)
s += "," + valueOfInt(f.Ns)
s += "," + valueOfInt(f.Extra)
s += valueOfBool(f.Do, ",do")
s += ","+valueOfInt(f.UDPSize)
s += "," + valueOfInt(f.UDPSize)
return s
}
// fingerStringNoSections returns the strings representation
// without the sections' count and the EDNS0 stuff
func (f *fingerprint) StringNoSections() string {
s := strings.SplitN(f.String(), ",", 11)
return strings.Join(s[:10], ",")
s := strings.SplitN(f.String(), ",", 11)
return strings.Join(s[:10], ",")
}
// SetString set the string to fp.. todo
@ -131,17 +135,17 @@ func (f *fingerprint) setString(str string) {
for i, s := range strings.Split(str, ",") {
switch i {
case 0:
if op, ok := dns.Str_opcode[s]; ok {
f.Opcode = op
} else { // number
f.Opcode = valueOfString(s)
}
if op, ok := dns.Str_opcode[s]; ok {
f.Opcode = op
} else { // number
f.Opcode = valueOfString(s)
}
case 1:
if op, ok := dns.Str_rcode[s]; ok {
f.Rcode = op
} else { // number
f.Rcode = valueOfString(s)
}
if op, ok := dns.Str_rcode[s]; ok {
f.Rcode = op
} else { // number
f.Rcode = valueOfString(s)
}
case 2:
f.Response = s == strings.ToUpper("qr")
case 3:
@ -157,7 +161,7 @@ func (f *fingerprint) setString(str string) {
case 8:
f.CheckingDisabled = s == strings.ToUpper("cd")
case 9:
f.Zero = s == strings.ToUpper("z")
f.Zero = s == strings.ToUpper("z")
case 10, 11, 12, 13:
// Can not set content of the message
case 14:

View File

@ -17,11 +17,12 @@ type item struct {
}
const (
itemError itemType = iota
itemSoftware // the name of the DNS server software
itemVendor // vendor of the DNS software
itemVersionMin // the minimum version of the software (empty if not determined)
itemVersionMax // the maximum version of the software (empty if not determined)
itemError itemType = iota
itemSoftware // the name of the DNS server software
itemVendor // vendor of the DNS software
itemVersionMinor // the minor version of the software (empty if not determined)
itemVersionMajor // the major version of the software (empty if not determined)
itemVersionPatch // the patch level of the software (empty if not determined)
)
// stateFn represents the state of the scanner as a function that returns the next state.
@ -58,9 +59,9 @@ func (l *lexer) setString(s string) {
func (l *lexer) setQuestion(name string, t uint16, c uint16) {
l.q = dns.Question{name, t, c}
if l.debug {
fmt.Printf(" %s\n", l.q.String())
}
if l.debug {
fmt.Printf(" %s\n", l.q.String())
}
}
func (l *lexer) run() {

View File

@ -142,8 +142,8 @@ func NewClient() *Client {
c.Attempts = 1
c.ReplyChan = DefaultReplyChan
c.QueryChan = DefaultQueryChan
c.ReadTimeout = 0.5 * 1e9
c.WriteTimeout = 0.5 * 1e9
c.ReadTimeout = 1 * 1e9
c.WriteTimeout = 1 * 1e9
return c
}