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 ( const (
QUERY_NOERROR string = "QUERY,NOERROR,qr,aa,tc,rd,ra,ad,cd,z,0,0,0,0,do,0" 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" 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 // MaraDNS clears DO BIT, UDPSize to 0. REFUSED
l.emit(&item{itemVendor, MARA}) l.emit(&item{itemVendor, MARA})
return dnsMaraLike return dnsMaraLike
case !f.Do && f.UDPSize == 0 && f.Rcode == dns.RcodeSuccess: case !f.Do && f.UDPSize == 0 && f.Rcode == dns.RcodeSuccess:
// PowerDNS(SEC) clears DO bit, resets UDPSize. NOERROR // PowerDNS(SEC) clears DO bit, resets UDPSize. NOERROR
l.emit(&item{itemVendor, POWER}) 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: 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}) l.emit(&item{itemVendor, ISC})
return dnsBindLike return dnsBindLike
case f.Do && f.UDPSize == 4097 && f.Rcode == dns.RcodeFormatError: case f.Do && f.UDPSize == 4097 && f.Rcode == dns.RcodeFormatError:
@ -62,6 +77,9 @@ func dnsServer(l *lexer) stateFn {
func dnsNsdLike(l *lexer) stateFn { func dnsNsdLike(l *lexer) stateFn {
l.verbose("NsdLike") l.verbose("NsdLike")
l.setString(QUERY_NOERROR)
l.setQuestion("authors.bind.", dns.TypeTXT, dns.ClassCHAOS)
l.probe()
return nil return nil
} }
@ -69,6 +87,57 @@ func dnsNsdLike(l *lexer) stateFn {
func dnsBindLike(l *lexer) stateFn { func dnsBindLike(l *lexer) stateFn {
l.verbose("BindLike") 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 return nil
} }
@ -84,8 +153,20 @@ func dnsMaraLike(l *lexer) stateFn {
return nil return nil
} }
func dnsPowerDNSLike(l *lexer) stateFn { func dnsPowerdnsLike(l *lexer) stateFn {
l.verbose("PowerDNSLike") 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 return nil
} }

View File

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

View File

@ -17,11 +17,12 @@ type item struct {
} }
const ( const (
itemError itemType = iota itemError itemType = iota
itemSoftware // the name of the DNS server software itemSoftware // the name of the DNS server software
itemVendor // vendor of the DNS software itemVendor // vendor of the DNS software
itemVersionMin // the minimum version of the software (empty if not determined) itemVersionMinor // the minor version of the software (empty if not determined)
itemVersionMax // the maximum 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. // 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) { func (l *lexer) setQuestion(name string, t uint16, c uint16) {
l.q = dns.Question{name, t, c} l.q = dns.Question{name, t, c}
if l.debug { if l.debug {
fmt.Printf(" %s\n", l.q.String()) fmt.Printf(" %s\n", l.q.String())
} }
} }
func (l *lexer) run() { func (l *lexer) run() {

View File

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