A lot of BIND specific checks
This commit is contained in:
parent
a91881457e
commit
da2e464de1
|
@ -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
|
||||
}
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -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() {
|
||||
|
|
Loading…
Reference in New Issue