Commit 49a3a992 authored by Romain Courteaud's avatar Romain Courteaud

Report PTR record

Allow empty ptr
parent f2c18185
......@@ -27,6 +27,7 @@ from .dns import (
getDomainIpDict,
reportDnsQuery,
packDns,
reverseIp,
)
from .domain import (
queryWhois,
......@@ -135,8 +136,8 @@ def filterWarningStatus(
for i in range(len(status_dict["dns_query"]) - 1, -1, -1):
state = status_dict["dns_query"][i]["response"]
if state == "":
if status_dict["dns_query"][i]["rdtype"] in ("MX", "TXT"):
# No MX/TXT is allowed
if status_dict["dns_query"][i]["rdtype"] in ("MX", "TXT", "PTR"):
# No MX/TXT/PTR is allowed
# XXX report empty SPF!
del status_dict["dns_query"][i]
else:
......@@ -334,6 +335,16 @@ class WebBot:
self._db, status_id, resolver_ip_list, domain_list, "TXT", timeout
)
# Query PTR record
getDomainIpDict(
self._db,
status_id,
resolver_ip_list,
[reverseIp(x) for x in server_ip_dict.keys()],
"PTR",
timeout,
)
# Check TCP port for the list of IP found
# XXX For now, check http/https only
server_ip_list = [x for x in server_ip_dict.keys()]
......@@ -582,6 +593,26 @@ class WebBot:
}
)
# Report PTR
# Report list of DNS query
query = reportDnsQuery(
self._db,
domain=[reverseIp(x) for x in server_ip_dict.keys()],
resolver_ip=resolver_ip_list,
rdtype=["PTR"],
)
for dns_change in query.dicts().iterator():
# XXX Duplicated code
result_dict["dns_query"].append(
{
"domain": dns_change["domain"],
"rdtype": dns_change["rdtype"],
"resolver_ip": dns_change["resolver_ip"],
"date": rfc822(dns_change["status"]),
"response": dns_change["response"],
}
)
# Report the list of CDN status
query = reportNetwork(
self._db,
......@@ -662,6 +693,7 @@ class WebBot:
# Confirm that redirection url are checked
if network_change["status_code"] in (301, 302, 303):
# XXX check full url
redirect_url = getRootUrl(
network_change["http_header_dict"]["Location"]
)
......
......@@ -21,6 +21,7 @@ from dns import (
resolver as dns_resolver,
name as dns_name,
exception as dns_exception,
reversename as dns_reversename,
)
from .network import logNetwork
from peewee import fn
......@@ -102,9 +103,13 @@ def buildResolver(resolver_ip, timeout):
return resolver
def reverseIp(ip):
return dns_reversename.from_address(ip)
def queryDNS(db, status_id, resolver_ip, domain_text, rdtype, timeout=TIMEOUT):
# only A (and AAAA) has address property
assert rdtype in ["A", "MX", "TXT"], rdtype
assert rdtype in ["A", "MX", "TXT", "PTR"], rdtype
resolver = buildResolver(resolver_ip, timeout)
try:
......@@ -115,7 +120,9 @@ def queryDNS(db, status_id, resolver_ip, domain_text, rdtype, timeout=TIMEOUT):
else (
x.exchange.derelativize(domain_text).to_text()[:-1]
if (rdtype == "MX")
else x.to_text()
else (
x.to_text()[:-1] if (rdtype == "PTR") else x.to_text()
)
)
)
for x in resolver.query(
......
......@@ -20,7 +20,7 @@
import unittest
from surykatka.bot import WebBot
import mock
from test_dns import MockAnswerA, MockAnswerMX, MockAnswerTXT
from test_dns import MockAnswerA, MockAnswerMX, MockAnswerTXT, MockAnswerPTR
from test_domain import MockAnswer as MockWhoisAnswer
import surykatka.dns
......@@ -160,6 +160,7 @@ class SurykatkaBotTestCase(unittest.TestCase):
[MockAnswerA("1.2.3.4")],
[MockAnswerMX("")],
[MockAnswerTXT("")],
[MockAnswerPTR("example.org")],
]
mock_create_default_context.return_value.wrap_socket.return_value.getpeercert.side_effect = [
b"",
......@@ -179,7 +180,7 @@ class SurykatkaBotTestCase(unittest.TestCase):
bot.iterateLoop()
assert mock_whois.call_count == 1
assert mock_query.call_count == 4
assert mock_query.call_count == 5
assert mock_socket.call_count == 4
assert mock_create_default_context.call_count == 1
assert mock_request.call_count == 2
......@@ -199,6 +200,7 @@ class SurykatkaBotTestCase(unittest.TestCase):
[
(resolver_ip, "example.org", "A"),
(resolver_ip, "example.org", "MX"),
(resolver_ip, "4.3.2.1.in-addr.arpa.", "PTR"),
(resolver_ip, "example.org", "TXT"),
],
)
......@@ -268,6 +270,8 @@ class SurykatkaBotTestCase(unittest.TestCase):
[MockAnswerMX("")],
[MockAnswerTXT("")],
[MockAnswerTXT("")],
[MockAnswerPTR("example.org.")],
[MockAnswerPTR("example.org.")],
]
mock_create_default_context.return_value.wrap_socket.return_value.getpeercert.side_effect = [
b"",
......@@ -282,7 +286,7 @@ class SurykatkaBotTestCase(unittest.TestCase):
bot.iterateLoop()
assert mock_whois.call_count == 1
assert mock_query.call_count == 8
assert mock_query.call_count == 10
assert mock_socket.call_count == 4
assert mock_create_default_context.call_count == 1
assert mock_request.call_count == 2
......@@ -307,6 +311,8 @@ class SurykatkaBotTestCase(unittest.TestCase):
(resolver_ip_2, "example.org", "A"),
(resolver_ip, "example.org", "MX"),
(resolver_ip_2, "example.org", "MX"),
(resolver_ip, "4.3.2.1.in-addr.arpa.", "PTR"),
(resolver_ip_2, "4.3.2.1.in-addr.arpa.", "PTR"),
(resolver_ip, "example.org", "TXT"),
(resolver_ip_2, "example.org", "TXT"),
],
......@@ -375,6 +381,7 @@ class SurykatkaBotTestCase(unittest.TestCase):
[MockAnswerMX("")],
[MockAnswerTXT("")],
[MockAnswerTXT("")],
[MockAnswerPTR("example.org.")],
]
mock_create_default_context.return_value.wrap_socket.return_value.getpeercert.side_effect = [
b"",
......@@ -396,7 +403,7 @@ class SurykatkaBotTestCase(unittest.TestCase):
bot.iterateLoop()
assert mock_whois.call_count == 1
assert mock_query.call_count == 7
assert mock_query.call_count == 8
assert mock_socket.call_count == 5
assert mock_create_default_context.call_count == 2
assert mock_request.call_count == 4
......@@ -420,6 +427,7 @@ class SurykatkaBotTestCase(unittest.TestCase):
(resolver_ip, domain_2, "A"),
(resolver_ip, domain_1, "MX"),
(resolver_ip, domain_2, "MX"),
(resolver_ip, "4.3.2.1.in-addr.arpa.", "PTR"),
(resolver_ip, domain_1, "TXT"),
(resolver_ip, domain_2, "TXT"),
],
......@@ -488,6 +496,8 @@ class SurykatkaBotTestCase(unittest.TestCase):
[MockAnswerA("1.2.3.4"), MockAnswerA("1.2.3.5"),],
[MockAnswerMX("")],
[MockAnswerTXT("")],
[MockAnswerPTR(domain)],
[MockAnswerPTR(domain)],
]
mock_create_default_context.return_value.wrap_socket.return_value.getpeercert.side_effect = [
b"",
......@@ -509,7 +519,7 @@ class SurykatkaBotTestCase(unittest.TestCase):
bot.iterateLoop()
assert mock_whois.call_count == 1
assert mock_query.call_count == 4
assert mock_query.call_count == 6
assert mock_socket.call_count == 8
assert mock_create_default_context.call_count == 2
assert mock_request.call_count == 4
......@@ -534,6 +544,8 @@ class SurykatkaBotTestCase(unittest.TestCase):
[
(resolver_ip, domain, "A"),
(resolver_ip, domain, "MX"),
(resolver_ip, "4.3.2.1.in-addr.arpa.", "PTR"),
(resolver_ip, "5.3.2.1.in-addr.arpa.", "PTR"),
(resolver_ip, domain, "TXT"),
],
)
......@@ -606,6 +618,7 @@ class SurykatkaBotTestCase(unittest.TestCase):
[MockAnswerMX("")],
[MockAnswerTXT("")],
[MockAnswerTXT("")],
[MockAnswerTXT(domain)],
]
mock_create_default_context.return_value.wrap_socket.return_value.getpeercert.side_effect = [
b"",
......@@ -627,7 +640,7 @@ class SurykatkaBotTestCase(unittest.TestCase):
bot.iterateLoop()
assert mock_whois.call_count == 1
assert mock_query.call_count == 7
assert mock_query.call_count == 8
assert mock_socket.call_count == 5
assert mock_create_default_context.call_count == 2
assert mock_request.call_count == 4
......@@ -651,6 +664,7 @@ class SurykatkaBotTestCase(unittest.TestCase):
(resolver_ip, sub_domain, "A"),
(resolver_ip, domain, "MX"),
(resolver_ip, sub_domain, "MX"),
(resolver_ip, "4.3.2.1.in-addr.arpa.", "PTR"),
(resolver_ip, domain, "TXT"),
(resolver_ip, sub_domain, "TXT"),
],
......@@ -721,6 +735,7 @@ class SurykatkaBotTestCase(unittest.TestCase):
[MockAnswerA("1.2.3.4")],
[MockAnswerMX("")],
[MockAnswerTXT("")],
[MockAnswerPTR(domain)],
]
mock_create_default_context.return_value.wrap_socket.return_value.getpeercert.side_effect = [
b"",
......@@ -735,7 +750,7 @@ class SurykatkaBotTestCase(unittest.TestCase):
bot.iterateLoop()
assert mock_whois.call_count == 1
assert mock_query.call_count == 4
assert mock_query.call_count == 5
assert mock_socket.call_count == 4
assert mock_create_default_context.call_count == 1
assert mock_request.call_count == 2
......@@ -758,6 +773,7 @@ class SurykatkaBotTestCase(unittest.TestCase):
(resolver_ip, "example.org", "A"),
(resolver_ip, sub_domain, "A"),
(resolver_ip, sub_domain, "MX"),
(resolver_ip, "4.3.2.1.in-addr.arpa.", "PTR"),
(resolver_ip, sub_domain, "TXT"),
],
)
......@@ -821,6 +837,7 @@ class SurykatkaBotTestCase(unittest.TestCase):
[MockAnswerA("1.2.3.4")],
[MockAnswerMX("")],
[MockAnswerTXT("")],
[MockAnswerPTR("example.org.")],
]
mock_create_default_context.return_value.wrap_socket.return_value.getpeercert.side_effect = [
b"",
......@@ -834,7 +851,7 @@ class SurykatkaBotTestCase(unittest.TestCase):
bot.iterateLoop()
assert mock_whois.call_count == 1
assert mock_query.call_count == 4
assert mock_query.call_count == 5
assert mock_socket.call_count == 4
assert mock_create_default_context.call_count == 1
assert mock_request.call_count == 3
......@@ -856,6 +873,7 @@ class SurykatkaBotTestCase(unittest.TestCase):
[
(resolver_ip, domain, "A"),
(resolver_ip, domain, "MX"),
(resolver_ip, "4.3.2.1.in-addr.arpa.", "PTR"),
(resolver_ip, domain, "TXT"),
],
)
......
......@@ -29,6 +29,7 @@ from surykatka.dns import (
queryDNS,
getReachableResolverList,
getDomainIpDict,
reverseIp,
)
from surykatka.status import logStatus
import mock
......@@ -53,11 +54,31 @@ class MockAnswerTXT(object):
return self.text
class MockAnswerPTR(MockAnswerTXT):
def __init__(self, text):
super().__init__(text)
class SurykatkaDNSTestCase(unittest.TestCase):
def setUp(self):
self.db = LogDB(":memory:")
self.db.createTables()
################################################
# reverseIp
################################################
def test_reverseIp(self):
with mock.patch(
"surykatka.dns.dns_reversename.from_address"
) as mock_from_address:
mock_from_address.return_value = "1.foo.bar."
result = reverseIp("1")
assert mock_from_address.call_count == 1
mock_from_address.assert_called_with("1")
assert result == "1.foo.bar."
################################################
# expandDomainList
################################################
......@@ -354,6 +375,31 @@ class SurykatkaDNSTestCase(unittest.TestCase):
assert self.db.DnsChange.get().status_id == status_id
assert result == ['"foo=bar"', '"v=spf1 -all"']
def test_queryDNS_PTR(self):
resolver_ip = "127.0.0.1"
domain = "example.org"
rdtype = "PTR"
status_id = logStatus(self.db, "foo")
with mock.patch(
"surykatka.dns.dns_resolver.Resolver.query"
) as mock_query:
mock_query.return_value = [MockAnswerPTR("foo.bar.")]
result = queryDNS(self.db, status_id, resolver_ip, domain, rdtype)
assert mock_query.call_count == 1
mock_query.assert_called_with(
domain, rdtype, raise_on_no_answer=False
)
assert self.db.DnsChange.select().count() == 1
assert self.db.DnsChange.get().resolver_ip == resolver_ip
assert self.db.DnsChange.get().domain == domain
assert self.db.DnsChange.get().rdtype == rdtype
assert self.db.DnsChange.get().response == "foo.bar"
assert self.db.DnsChange.get().status_id == status_id
assert result == ["foo.bar"]
def test_queryDNS_rejectRdtype(self):
resolver_ip = "127.0.0.1"
domain = "example.org"
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment