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