import synapse.exc as s_exc
import synapse.lib.types as s_types
import synapse.lib.module as s_module
dnsreplycodes = (
(0, 'NOERROR'),
(1, 'FORMERR'),
(2, 'SERVFAIL'),
(3, 'NXDOMAIN'),
(4, 'NOTIMP'),
(5, 'REFUSED'),
(6, 'YXDOMAIN'),
(7, 'YXRRSET'),
(8, 'NXRRSET'),
(9, 'NOTAUTH'),
(10, 'NOTZONE'),
(11, 'DSOTYPENI'),
(16, 'BADSIG'),
(17, 'BADKEY'),
(18, 'BADTIME'),
(19, 'BADMODE'),
(20, 'BADNAME'),
(21, 'BADALG'),
(22, 'BADTRUNC'),
(23, 'BADCOOKIE'),
)
[docs]
class DnsName(s_types.Str):
[docs]
def postTypeInit(self):
s_types.Str.postTypeInit(self)
self.inarpa = '.in-addr.arpa'
self.inarpa6 = '.ip6.arpa'
self.setNormFunc(str, self._normPyStr)
def _normPyStr(self, valu):
# Backwards compatible
norm = valu.lower()
norm = norm.strip() # type: str
# Break out fqdn / ipv4 / ipv6 subs :D
subs = {}
# ipv4
if norm.isnumeric():
# do-nothing for integer only strs
pass
elif norm.endswith(self.inarpa):
# Strip, reverse, check if ipv4
temp = norm[:-len(self.inarpa)]
temp = '.'.join(temp.split('.')[::-1])
try:
ipv4norm, info = self.modl.type('inet:ipv4').norm(temp)
except s_exc.BadTypeValu as e:
pass
else:
subs['ipv4'] = ipv4norm
elif norm.endswith(self.inarpa6):
parts = [c for c in norm[:-len(self.inarpa6)][::-1] if c != '.']
try:
if len(parts) != 32:
raise s_exc.BadTypeValu(mesg='Invalid number of ipv6 parts')
temp = int(''.join(parts), 16)
ipv6norm, info = self.modl.type('inet:ipv6').norm(temp)
except s_exc.BadTypeValu as e:
pass
else:
subs['ipv6'] = ipv6norm
ipv4 = info.get('subs').get('ipv4')
if ipv4 is not None:
subs['ipv4'] = ipv4
else:
# Try fallbacks to parse out possible ipv4/ipv6 garbage queries
try:
ipv4norm, info = self.modl.type('inet:ipv4').norm(norm)
except s_exc.BadTypeValu as e:
try:
ipv6norm, info = self.modl.type('inet:ipv6').norm(norm)
except s_exc.BadTypeValu as e2:
pass
else:
subs['ipv6'] = ipv6norm
ipv4 = info.get('subs').get('ipv4')
if ipv4 is not None:
subs['ipv4'] = ipv4
else:
subs['ipv4'] = ipv4norm
# Lastly, try give the norm'd valu a shot as an inet:fqdn
try:
fqdnnorm, info = self.modl.type('inet:fqdn').norm(norm)
except s_exc.BadTypeValu as e:
pass
else:
subs['fqdn'] = fqdnnorm
return norm, {'subs': subs}
[docs]
class DnsModule(s_module.CoreModule):
[docs]
def getModelDefs(self):
modl = {
'ctors': (
('inet:dns:name', 'synapse.models.dns.DnsName', {}, {
'doc': 'A DNS query name string. Likely an FQDN but not always.',
'ex': 'vertex.link',
}),
),
'types': (
('inet:dns:a', ('comp', {'fields': (('fqdn', 'inet:fqdn'), ('ipv4', 'inet:ipv4'))}), {
'ex': '(vertex.link,1.2.3.4)',
'doc': 'The result of a DNS A record lookup.'}),
('inet:dns:aaaa', ('comp', {'fields': (('fqdn', 'inet:fqdn'), ('ipv6', 'inet:ipv6'))}), {
'ex': '(vertex.link,2607:f8b0:4004:809::200e)',
'doc': 'The result of a DNS AAAA record lookup.'}),
('inet:dns:rev', ('comp', {'fields': (('ipv4', 'inet:ipv4'), ('fqdn', 'inet:fqdn'))}), {
'ex': '(1.2.3.4,vertex.link)',
'doc': 'The transformed result of a DNS PTR record lookup.'}),
('inet:dns:rev6', ('comp', {'fields': (('ipv6', 'inet:ipv6'), ('fqdn', 'inet:fqdn'))}), {
'ex': '(2607:f8b0:4004:809::200e,vertex.link)',
'doc': 'The transformed result of a DNS PTR record for an IPv6 address.'}),
('inet:dns:ns', ('comp', {'fields': (('zone', 'inet:fqdn'), ('ns', 'inet:fqdn'))}), {
'ex': '(vertex.link,ns.dnshost.com)',
'doc': 'The result of a DNS NS record lookup.'}),
('inet:dns:cname', ('comp', {'fields': (('fqdn', 'inet:fqdn'), ('cname', 'inet:fqdn'))}), {
'ex': '(foo.vertex.link,vertex.link)',
'doc': 'The result of a DNS CNAME record lookup.'}),
('inet:dns:mx', ('comp', {'fields': (('fqdn', 'inet:fqdn'), ('mx', 'inet:fqdn'))}), {
'ex': '(vertex.link,mail.vertex.link)',
'doc': 'The result of a DNS MX record lookup.'}),
('inet:dns:soa', ('guid', {}), {
'doc': 'The result of a DNS SOA record lookup.'}),
('inet:dns:txt', ('comp', {'fields': (('fqdn', 'inet:fqdn'), ('txt', 'str'))}), {
'ex': '(hehe.vertex.link,"fancy TXT record")',
'doc': 'The result of a DNS MX record lookup.'}),
('inet:dns:type', ('int', {}), {
'doc': 'A DNS query/answer type integer.'}),
('inet:dns:query',
('comp', {'fields': (('client', 'inet:client'), ('name', 'inet:dns:name'), ('type', 'int'))}), {
'ex': '(1.2.3.4, woot.com, 1)',
'doc': 'A DNS query unique to a given client.'}),
('inet:dns:request', ('guid', {}), {
'doc': 'A single instance of a DNS resolver request and optional reply info.'}),
('inet:dns:answer', ('guid', {}), {
'doc': 'A single answer from within a DNS reply.'}),
('inet:dns:wild:a', ('comp', {'fields': (('fqdn', 'inet:fqdn'), ('ipv4', 'inet:ipv4'))}), {
'doc': 'A DNS A wild card record and the IPv4 it resolves to.'}),
('inet:dns:wild:aaaa', ('comp', {'fields': (('fqdn', 'inet:fqdn'), ('ipv6', 'inet:ipv6'))}), {
'doc': 'A DNS AAAA wild card record and the IPv6 it resolves to.'}),
('inet:dns:dynreg', ('guid', {}), {
'doc': 'A dynamic DNS registration.'}),
),
'forms': (
('inet:dns:a', {}, (
('fqdn', ('inet:fqdn', {}), {'ro': True,
'doc': 'The domain queried for its DNS A record.'}),
('ipv4', ('inet:ipv4', {}), {'ro': True,
'doc': 'The IPv4 address returned in the A record.'}),
)),
('inet:dns:aaaa', {}, (
('fqdn', ('inet:fqdn', {}), {'ro': True,
'doc': 'The domain queried for its DNS AAAA record.'}),
('ipv6', ('inet:ipv6', {}), {'ro': True,
'doc': 'The IPv6 address returned in the AAAA record.'}),
)),
('inet:dns:rev', {}, (
('ipv4', ('inet:ipv4', {}), {'ro': True,
'doc': 'The IPv4 address queried for its DNS PTR record.'}),
('fqdn', ('inet:fqdn', {}), {'ro': True,
'doc': 'The domain returned in the PTR record.'}),
)),
('inet:dns:rev6', {}, (
('ipv6', ('inet:ipv6', {}), {'ro': True,
'doc': 'The IPv6 address queried for its DNS PTR record.'}),
('fqdn', ('inet:fqdn', {}), {'ro': True,
'doc': 'The domain returned in the PTR record.'}),
)),
('inet:dns:ns', {}, (
('zone', ('inet:fqdn', {}), {'ro': True,
'doc': 'The domain queried for its DNS NS record.'}),
('ns', ('inet:fqdn', {}), {'ro': True,
'doc': 'The domain returned in the NS record.'}),
)),
('inet:dns:cname', {}, (
('fqdn', ('inet:fqdn', {}), {'ro': True,
'doc': 'The domain queried for its CNAME record.'}),
('cname', ('inet:fqdn', {}), {'ro': True,
'doc': 'The domain returned in the CNAME record.'}),
)),
('inet:dns:mx', {}, (
('fqdn', ('inet:fqdn', {}), {'ro': True,
'doc': 'The domain queried for its MX record.'}),
('mx', ('inet:fqdn', {}), {'ro': True,
'doc': 'The domain returned in the MX record.'}),
)),
('inet:dns:soa', {}, (
('fqdn', ('inet:fqdn', {}), {
'doc': 'The domain queried for its SOA record.'}),
('ns', ('inet:fqdn', {}), {
'doc': 'The domain (MNAME) returned in the SOA record.'}),
('email', ('inet:email', {}), {
'doc': 'The email address (RNAME) returned in the SOA record.'}),
)),
('inet:dns:txt', {}, (
('fqdn', ('inet:fqdn', {}), {'ro': True,
'doc': 'The domain queried for its TXT record.'}),
('txt', ('str', {}), {'ro': True,
'doc': 'The string returned in the TXT record.'}),
)),
('inet:dns:query', {}, (
('client', ('inet:client', {}), {'ro': True, }),
('name', ('inet:dns:name', {}), {'ro': True, }),
('name:ipv4', ('inet:ipv4', {}), {}),
('name:ipv6', ('inet:ipv6', {}), {}),
('name:fqdn', ('inet:fqdn', {}), {}),
('type', ('int', {}), {'ro': True, }),
)),
('inet:dns:request', {}, (
('time', ('time', {}), {}),
('query', ('inet:dns:query', {}), {}),
('query:name', ('inet:dns:name', {}), {}),
('query:name:ipv4', ('inet:ipv4', {}), {}),
('query:name:ipv6', ('inet:ipv6', {}), {}),
('query:name:fqdn', ('inet:fqdn', {}), {}),
('query:type', ('int', {}), {}),
('server', ('inet:server', {}), {}),
('reply:code', ('int', {'enums': dnsreplycodes, 'enums:strict': False}), {
'doc': 'The DNS server response code.'}),
('exe', ('file:bytes', {}), {
'doc': 'The file containing the code that attempted the DNS lookup.'}),
('proc', ('it:exec:proc', {}), {
'doc': 'The process that attempted the DNS lookup.'}),
('host', ('it:host', {}), {
'doc': 'The host that attempted the DNS lookup.'}),
('sandbox:file', ('file:bytes', {}), {
'doc': 'The initial sample given to a sandbox environment to analyze.'}),
)),
('inet:dns:answer', {}, (
('ttl', ('int', {}), {}),
('request', ('inet:dns:request', {}), {}),
('a', ('inet:dns:a', {}), {
'doc': 'The DNS A record returned by the lookup.'}),
('ns', ('inet:dns:ns', {}), {
'doc': 'The DNS NS record returned by the lookup.'}),
('rev', ('inet:dns:rev', {}), {
'doc': 'The DNS PTR record returned by the lookup.'}),
('aaaa', ('inet:dns:aaaa', {}), {
'doc': 'The DNS AAAA record returned by the lookup.'}),
('rev6', ('inet:dns:rev6', {}), {
'doc': 'The DNS PTR record returned by the lookup of an IPv6 address.'}),
('cname', ('inet:dns:cname', {}), {
'doc': 'The DNS CNAME record returned by the lookup.'}),
('mx', ('inet:dns:mx', {}), {
'doc': 'The DNS MX record returned by the lookup.'}),
('mx:priority', ('int', {}), {
'doc': 'The DNS MX record priority.'}),
('soa', ('inet:dns:soa', {}), {
'doc': 'The domain queried for its SOA record.'}),
('txt', ('inet:dns:txt', {}), {
'doc': 'The DNS TXT record returned by the lookup.'}),
('time', ('time', {}), {
'doc': 'The time that the DNS response was transmitted.'}),
)),
('inet:dns:wild:a', {}, (
('fqdn', ('inet:fqdn', {}), {'ro': True,
'doc': 'The domain containing a wild card record.'}),
('ipv4', ('inet:ipv4', {}), {'ro': True,
'doc': 'The IPv4 address returned by wild card resolutions.'}),
)),
('inet:dns:wild:aaaa', {}, (
('fqdn', ('inet:fqdn', {}), {'ro': True,
'doc': 'The domain containing a wild card record.'}),
('ipv6', ('inet:ipv6', {}), {'ro': True,
'doc': 'The IPv6 address returned by wild card resolutions.'}),
)),
('inet:dns:dynreg', {}, (
('fqdn', ('inet:fqdn', {}), {
'doc': 'The FQDN registered within a dynamic DNS provider.'}),
('provider', ('ou:org', {}), {
'doc': 'The organization which provides the dynamic DNS FQDN.'}),
('provider:name', ('ou:name', {}), {
'doc': 'The name of the organization which provides the dynamic DNS FQDN.'}),
('provider:fqdn', ('inet:fqdn', {}), {
'doc': 'The FQDN of the organization which provides the dynamic DNS FQDN.'}),
('contact', ('ps:contact', {}), {
'doc': 'The contact information of the registrant.'}),
('created', ('time', {}), {
'doc': 'The time that the dynamic DNS registration was first created.'}),
('client', ('inet:client', {}), {
'doc': 'The network client address used to register the dynamic FQDN.'}),
('client:ipv4', ('inet:ipv4', {}), {
'doc': 'The client IPv4 address used to register the dynamic FQDN.'}),
('client:ipv6', ('inet:ipv6', {}), {
'doc': 'The client IPv6 address used to register the dynamic FQDN.'}),
)),
)
}
name = 'inet:dns'
return ((name, modl), )