Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
S
surykatka
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
2
Merge Requests
2
Analytics
Analytics
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Commits
Issue Boards
Open sidebar
nexedi
surykatka
Commits
77772997
Commit
77772997
authored
Nov 18, 2021
by
Romain Courteaud
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
report MX conf issue (ie, unexpected open port 25)
parent
19d1bbb3
Changes
4
Show whitespace changes
Inline
Side-by-side
Showing
4 changed files
with
335 additions
and
98 deletions
+335
-98
src/surykatka/bot.py
src/surykatka/bot.py
+127
-40
src/surykatka/dns.py
src/surykatka/dns.py
+7
-2
tests/test_bot.py
tests/test_bot.py
+152
-44
tests/test_dns.py
tests/test_dns.py
+49
-12
No files found.
src/surykatka/bot.py
View file @
77772997
...
...
@@ -124,34 +124,62 @@ def filterWarningStatus(
if
not
status_dict
[
"dns_server"
]:
del
status_dict
[
"dns_server"
]
mx_domain_dict
=
{}
for
i
in
range
(
len
(
status_dict
[
"dns_query"
])
-
1
,
-
1
,
-
1
):
state
=
status_dict
[
"dns_query"
][
i
][
"response"
]
if
state
!=
""
:
if
state
==
""
:
if
status_dict
[
"dns_query"
][
i
][
"rdtype"
]
==
"MX"
:
# No MX is allowed
del
status_dict
[
"dns_query"
][
i
]
else
:
# Keep track of possible domain handling MX
if
status_dict
[
"dns_query"
][
i
][
"rdtype"
]
==
"MX"
:
for
mx_domain
in
state
.
split
(
", "
):
mx_domain_dict
[
mx_domain
]
=
True
del
status_dict
[
"dns_query"
][
i
]
if
not
status_dict
[
"dns_query"
]:
del
status_dict
[
"dns_query"
]
if
not
status_dict
[
"missing_data"
]:
del
status_dict
[
"missing_data"
]
for
i
in
range
(
len
(
status_dict
[
"
htt
p_server"
])
-
1
,
-
1
,
-
1
):
state
=
status_dict
[
"
htt
p_server"
][
i
][
"state"
]
for
i
in
range
(
len
(
status_dict
[
"
tc
p_server"
])
-
1
,
-
1
,
-
1
):
state
=
status_dict
[
"
tc
p_server"
][
i
][
"state"
]
# Skip if all domains lead to not critical urls
prefix
=
""
if
status_dict
[
"
htt
p_server"
][
i
][
"port"
]
==
80
:
if
status_dict
[
"
tc
p_server"
][
i
][
"port"
]
==
80
:
prefix
=
"http://"
elif
status_dict
[
"
htt
p_server"
][
i
][
"port"
]
==
443
:
elif
status_dict
[
"
tc
p_server"
][
i
][
"port"
]
==
443
:
prefix
=
"https://"
domain_list
=
status_dict
[
"http_server"
][
i
][
"domain"
].
split
(
", "
)
elif
status_dict
[
"tcp_server"
][
i
][
"port"
]
==
25
:
prefix
=
"smtp://"
else
:
raise
NotImplementedError
(
"Not supported server port %i"
%
status_dict
[
"tcp_server"
][
i
][
"port"
]
)
domain_list
=
status_dict
[
"tcp_server"
][
i
][
"domain"
].
split
(
", "
)
domain_list
=
[
x
for
x
in
domain_list
if
"%s%s"
%
(
prefix
,
x
)
not
in
not_critical_url_list
]
if
(
state
==
"open"
)
or
(
not
domain_list
):
del
status_dict
[
"http_server"
][
i
]
if
not
status_dict
[
"http_server"
]:
del
status_dict
[
"http_server"
]
if
status_dict
[
"tcp_server"
][
i
][
"port"
]
==
25
:
has_intersection
=
(
len
(
set
(
mx_domain_dict
.
keys
()).
intersection
(
domain_list
))
!=
0
)
if
((
state
==
"open"
)
and
has_intersection
)
or
(
(
state
!=
"open"
)
and
(
not
has_intersection
)
):
# if one MX points to this server, port should be open
# if no MX points to this serverm port should NOT be open
del
status_dict
[
"tcp_server"
][
i
]
elif
(
state
==
"open"
)
or
(
not
domain_list
):
del
status_dict
[
"tcp_server"
][
i
]
if
not
status_dict
[
"tcp_server"
]:
del
status_dict
[
"tcp_server"
]
for
i
in
range
(
len
(
status_dict
[
"ssl_certificate"
])
-
1
,
-
1
,
-
1
):
not_after
=
status_dict
[
"ssl_certificate"
][
i
][
"not_after"
]
...
...
@@ -289,6 +317,10 @@ class WebBot:
server_ip_dict
=
getDomainIpDict
(
self
.
_db
,
status_id
,
resolver_ip_list
,
domain_list
,
"A"
,
timeout
)
# Check the mail configuration for every domain (MX and SPF)
getDomainIpDict
(
self
.
_db
,
status_id
,
resolver_ip_list
,
domain_list
,
"MX"
,
timeout
)
# Check TCP port for the list of IP found
# XXX For now, check http/https only
...
...
@@ -296,12 +328,16 @@ class WebBot:
url_dict
=
{}
for
server_ip
in
server_ip_list
:
# XXX Check SSL certificate expiration
for
port
,
protocol
in
[(
80
,
"http"
),
(
443
,
"https"
)]:
for
port
,
protocol
in
[
(
80
,
"http"
),
(
443
,
"https"
),
(
25
,
"smtp"
),
]:
if
isTcpPortOpen
(
self
.
_db
,
server_ip
,
port
,
status_id
,
timeout
):
for
hostname
in
server_ip_dict
[
server_ip
]:
if
port
==
443
:
if
port
in
[
443
,
587
]
:
# Store certificate information
if
not
hasValidSSLCertificate
(
self
.
_db
,
...
...
@@ -328,6 +364,9 @@ class WebBot:
# Check HTTP Status
for
url
in
url_dict
:
if
url
.
startswith
(
"smtp"
):
# XXX TODO implement smtp connection check
continue
for
ip
in
url_dict
[
url
]:
checkHttpStatus
(
self
.
_db
,
...
...
@@ -373,7 +412,10 @@ class WebBot:
"registrar"
:
domain_change
[
"registrar"
],
"whois_server"
:
domain_change
[
"whois_server"
],
"creation_date"
:
rfc822
(
domain_change
[
"creation_date"
])
if
(
type
(
domain_change
[
"creation_date"
])
is
datetime
.
datetime
)
if
(
type
(
domain_change
[
"creation_date"
])
is
datetime
.
datetime
)
else
None
,
"updated_date"
:
rfc822
(
domain_change
[
"updated_date"
])
if
(
domain_change
[
"updated_date"
]
is
datetime
.
datetime
)
...
...
@@ -417,46 +459,91 @@ class WebBot:
}
)
result_dict
[
"missing_data"
]
=
[]
for
resolver_ip
in
self
.
config
[
"NAMESERVER"
].
split
():
if
resolver_ip
not
in
checked_resolver_ip_dict
:
result_dict
[
"missing_data"
].
append
(
{
"text"
:
resolver_ip
,
"date"
:
result_dict
[
"bot_status"
][
0
][
"date"
],
}
)
checked_domain_dict
=
{}
# Report list of DNS query
query
=
reportDnsQuery
(
self
.
_db
,
domain
=
domain_list
,
resolver_ip
=
resolver_ip_list
,
rdtype
=
"A"
,
rdtype
=
[
"A"
,
"MX"
]
,
)
server_ip_dict
=
{}
result_dict
[
"dns_query"
]
=
[]
for
dns_change
in
query
.
dicts
().
iterator
():
checked_domain_dict
[
dns_change
[
"domain"
]]
=
True
if
dns_change
[
"domain"
]
not
in
checked_domain_dict
:
checked_domain_dict
[
dns_change
[
"domain"
]]
=
{}
checked_domain_dict
[
dns_change
[
"domain"
]][
dns_change
[
"rdtype"
]
]
=
dns_change
[
"response"
]
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"
],
}
)
for
server_ip
in
dns_change
[
"response"
].
split
(
", "
):
for
domain
in
domain_list
:
if
domain
in
checked_domain_dict
:
if
"A"
in
checked_domain_dict
[
domain
]:
for
server_ip
in
checked_domain_dict
[
domain
][
"A"
].
split
(
", "
):
if
not
server_ip
:
# drop empty response
continue
if
server_ip
not
in
server_ip_dict
:
server_ip_dict
[
server_ip
]
=
[]
if
dns_change
[
"domain"
]
not
in
server_ip_dict
[
server_ip
]:
server_ip_dict
[
server_ip
].
append
(
dns_change
[
"domain"
])
if
domain
not
in
server_ip_dict
[
server_ip
]:
server_ip_dict
[
server_ip
].
append
(
domain
)
else
:
result_dict
[
"missing_data"
].
append
(
{
"text"
:
"(A) "
+
domain
,
"date"
:
result_dict
[
"bot_status"
][
0
][
"date"
],
}
)
result_dict
[
"missing_data"
]
=
[]
for
resolver_ip
in
self
.
config
[
"NAMESERVER"
].
split
():
if
resolver_ip
not
in
checked_resolver_ip_dict
:
if
"MX"
in
checked_domain_dict
[
domain
]:
if
checked_domain_dict
[
domain
][
"MX"
]:
for
mx_domain
in
checked_domain_dict
[
domain
][
"MX"
].
split
(
", "
):
if
mx_domain
not
in
checked_domain_dict
:
result_dict
[
"missing_data"
].
append
(
{
"text"
:
resolver_ip
,
"text"
:
"(MX "
+
domain
+
") "
+
mx_domain
,
"date"
:
result_dict
[
"bot_status"
][
0
][
"date"
],
}
)
else
:
result_dict
[
"missing_data"
].
append
(
{
"text"
:
"(MX) "
+
domain
,
"date"
:
result_dict
[
"bot_status"
][
0
][
"date"
],
}
)
for
domain
in
domain_list
:
if
domain
not
in
checked_domain_dict
:
else
:
result_dict
[
"missing_data"
].
append
(
{
"text"
:
domain
,
...
...
@@ -467,14 +554,14 @@ class WebBot:
# Report the list of CDN status
query
=
reportNetwork
(
self
.
_db
,
port
=
[
"80"
,
"443"
],
port
=
[
"80"
,
"443"
,
"25"
],
transport
=
"TCP"
,
ip
=
[
x
for
x
in
server_ip_dict
.
keys
()],
)
url_dict
=
{}
result_dict
[
"
htt
p_server"
]
=
[]
result_dict
[
"
tc
p_server"
]
=
[]
for
network_change
in
query
.
dicts
().
iterator
():
result_dict
[
"
htt
p_server"
].
append
(
result_dict
[
"
tc
p_server"
].
append
(
{
"ip"
:
network_change
[
"ip"
],
"state"
:
network_change
[
"state"
],
...
...
@@ -485,9 +572,9 @@ class WebBot:
)
if
network_change
[
"state"
]
==
"open"
:
for
hostname
in
server_ip_dict
[
network_change
[
"ip"
]]:
protocol
=
(
"http"
if
(
network_change
[
"port"
]
==
80
)
else
"https"
)
protocol
=
{
80
:
"http"
,
443
:
"https"
,
25
:
"smtp"
}[
network_change
[
"port"
]
]
url
=
"%s://%s"
%
(
protocol
,
hostname
)
if
url
not
in
url_dict
:
url_dict
[
url
]
=
[]
...
...
@@ -553,7 +640,7 @@ class WebBot:
{
"text"
:
"(%s ->) %s"
%
(
network_change
[
"url"
],
redirect_url
),
"date"
:
r
esult_dict
[
"bot_status"
][
0
][
"date"
]
,
"date"
:
r
fc822
(
network_change
[
"status"
])
,
}
)
result_dict
[
"http_query"
].
append
(
...
...
src/surykatka/dns.py
View file @
77772997
...
...
@@ -104,12 +104,16 @@ def buildResolver(resolver_ip, timeout):
def
queryDNS
(
db
,
status_id
,
resolver_ip
,
domain_text
,
rdtype
,
timeout
=
TIMEOUT
):
# only A (and AAAA) has address property
assert
rdtype
==
"A"
assert
rdtype
in
[
"A"
,
"MX"
],
rdtype
resolver
=
buildResolver
(
resolver_ip
,
timeout
)
try
:
answer_list
=
[
(
x
.
address
if
(
rdtype
==
"A"
)
else
x
.
exchange
.
derelativize
(
domain_text
).
to_text
()[:
-
1
]
)
for
x
in
resolver
.
query
(
domain_text
,
rdtype
,
raise_on_no_answer
=
False
)
...
...
@@ -121,6 +125,7 @@ def queryDNS(db, status_id, resolver_ip, domain_text, rdtype, timeout=TIMEOUT):
dns_resolver
.
NoNameservers
,
):
answer_list
=
[]
# how to differentiate no answer from empty answer
logDnsQuery
(
db
,
status_id
,
resolver_ip
,
domain_text
,
rdtype
,
answer_list
)
return
answer_list
...
...
tests/test_bot.py
View file @
77772997
...
...
@@ -20,7 +20,7 @@
import
unittest
from
surykatka.bot
import
WebBot
import
mock
from
test_dns
import
MockAnswer
from
test_dns
import
MockAnswer
A
,
MockAnswerMX
from
test_domain
import
MockAnswer
as
MockWhoisAnswer
import
surykatka.dns
...
...
@@ -61,8 +61,9 @@ def checkDnsChange(bot, result_list):
bot
.
_db
.
DnsChange
.
select
()
.
order_by
(
bot
.
_db
.
DnsChange
.
resolver_ip
.
asc
())
.
order_by
(
bot
.
_db
.
DnsChange
.
domain
.
asc
())
.
order_by
(
bot
.
_db
.
DnsChange
.
rdtype
.
asc
())
)
db_result_list
=
[(
x
.
resolver_ip
,
x
.
domain
)
for
x
in
select_list
]
db_result_list
=
[(
x
.
resolver_ip
,
x
.
domain
,
x
.
rdtype
)
for
x
in
select_list
]
assert
bot
.
_db
.
DnsChange
.
select
().
count
()
==
len
(
result_list
),
db_result_list
...
...
@@ -94,7 +95,7 @@ class SurykatkaBotTestCase(unittest.TestCase):
)
as
mock_query
:
mock_get_default_resolver
.
return_value
=
resolver
mock_query
.
return_value
=
[
MockAnswer
(
"1.2.3.4"
)
]
mock_query
.
side_effect
=
[[
MockAnswerA
(
"1.2.3.4"
)]
]
bot
=
WebBot
(
mapping
=
{
"SQLITE"
:
":memory:"
})
bot
.
initDB
()
bot
.
iterateLoop
()
...
...
@@ -106,7 +107,7 @@ class SurykatkaBotTestCase(unittest.TestCase):
checkNetworkChange
(
bot
,
[(
resolver_ip
,
53
)])
checkDnsChange
(
bot
,
[(
resolver_ip
,
"example.org"
)])
checkDnsChange
(
bot
,
[(
resolver_ip
,
"example.org"
,
"A"
)])
checkSslChange
(
bot
,
[])
...
...
@@ -154,7 +155,11 @@ class SurykatkaBotTestCase(unittest.TestCase):
"country"
,
)
mock_get_default_resolver
.
return_value
=
resolver
mock_query
.
return_value
=
[
MockAnswer
(
"1.2.3.4"
)]
mock_query
.
side_effect
=
[
[
MockAnswerA
(
"1.2.3.4"
)],
[
MockAnswerA
(
"1.2.3.4"
)],
[
MockAnswerMX
(
""
)],
]
mock_create_default_context
.
return_value
.
wrap_socket
.
return_value
.
getpeercert
.
side_effect
=
[
b""
,
{
...
...
@@ -173,16 +178,28 @@ class SurykatkaBotTestCase(unittest.TestCase):
bot
.
iterateLoop
()
assert
mock_whois
.
call_count
==
1
assert
mock_query
.
call_count
==
2
assert
mock_socket
.
call_count
==
3
assert
mock_query
.
call_count
==
3
assert
mock_socket
.
call_count
==
4
assert
mock_create_default_context
.
call_count
==
1
assert
mock_request
.
call_count
==
2
checkNetworkChange
(
bot
,
[(
resolver_ip
,
53
),
(
"1.2.3.4"
,
80
),
(
"1.2.3.4"
,
443
)]
bot
,
[
(
"1.2.3.4"
,
25
),
(
resolver_ip
,
53
),
(
"1.2.3.4"
,
80
),
(
"1.2.3.4"
,
443
),
],
)
checkDnsChange
(
bot
,
[(
resolver_ip
,
"example.org"
)])
checkDnsChange
(
bot
,
[
(
resolver_ip
,
"example.org"
,
"A"
),
(
resolver_ip
,
"example.org"
,
"MX"
),
],
)
checkDomainChange
(
bot
,
[
"example.org"
])
...
...
@@ -240,7 +257,14 @@ class SurykatkaBotTestCase(unittest.TestCase):
"country"
,
)
mock_request
.
return_value
.
headers
=
{
"Etag"
:
"foobar"
}
mock_query
.
return_value
=
[
MockAnswer
(
"1.2.3.4"
)]
mock_query
.
side_effect
=
[
[
MockAnswerA
(
"1.2.3.4"
)],
[
MockAnswerA
(
"1.2.3.4"
)],
[
MockAnswerA
(
"1.2.3.4"
)],
[
MockAnswerA
(
"1.2.3.4"
)],
[
MockAnswerMX
(
""
)],
[
MockAnswerMX
(
""
)],
]
mock_create_default_context
.
return_value
.
wrap_socket
.
return_value
.
getpeercert
.
side_effect
=
[
b""
,
{
...
...
@@ -254,14 +278,15 @@ class SurykatkaBotTestCase(unittest.TestCase):
bot
.
iterateLoop
()
assert
mock_whois
.
call_count
==
1
assert
mock_query
.
call_count
==
4
assert
mock_socket
.
call_count
==
3
assert
mock_query
.
call_count
==
6
assert
mock_socket
.
call_count
==
4
assert
mock_create_default_context
.
call_count
==
1
assert
mock_request
.
call_count
==
2
checkNetworkChange
(
bot
,
[
(
"1.2.3.4"
,
25
),
(
resolver_ip
,
53
),
(
resolver_ip_2
,
53
),
(
"1.2.3.4"
,
80
),
...
...
@@ -272,7 +297,13 @@ class SurykatkaBotTestCase(unittest.TestCase):
checkDomainChange
(
bot
,
[
"example.org"
])
checkDnsChange
(
bot
,
[(
resolver_ip
,
"example.org"
),
(
resolver_ip_2
,
"example.org"
)]
bot
,
[
(
resolver_ip
,
"example.org"
,
"A"
),
(
resolver_ip_2
,
"example.org"
,
"A"
),
(
resolver_ip
,
"example.org"
,
"MX"
),
(
resolver_ip_2
,
"example.org"
,
"MX"
),
],
)
checkSslChange
(
bot
,
[(
"1.2.3.4"
,
443
,
"example.org"
)])
...
...
@@ -330,7 +361,13 @@ class SurykatkaBotTestCase(unittest.TestCase):
"country"
,
)
mock_request
.
return_value
.
headers
=
{
"Etag"
:
"foobar"
}
mock_query
.
return_value
=
[
MockAnswer
(
"1.2.3.4"
)]
mock_query
.
side_effect
=
[
[
MockAnswerA
(
"1.2.3.4"
)],
[
MockAnswerA
(
"1.2.3.4"
)],
[
MockAnswerA
(
"1.2.3.4"
)],
[
MockAnswerMX
(
""
)],
[
MockAnswerMX
(
""
)],
]
mock_create_default_context
.
return_value
.
wrap_socket
.
return_value
.
getpeercert
.
side_effect
=
[
b""
,
{
...
...
@@ -351,18 +388,32 @@ class SurykatkaBotTestCase(unittest.TestCase):
bot
.
iterateLoop
()
assert
mock_whois
.
call_count
==
1
assert
mock_query
.
call_count
==
3
assert
mock_socket
.
call_count
==
4
assert
mock_query
.
call_count
==
5
assert
mock_socket
.
call_count
==
5
assert
mock_create_default_context
.
call_count
==
2
assert
mock_request
.
call_count
==
4
checkNetworkChange
(
bot
,
[(
resolver_ip
,
53
),
(
"1.2.3.4"
,
80
),
(
"1.2.3.4"
,
443
)]
bot
,
[
(
"1.2.3.4"
,
25
),
(
resolver_ip
,
53
),
(
"1.2.3.4"
,
80
),
(
"1.2.3.4"
,
443
),
],
)
checkDomainChange
(
bot
,
[
"example.org"
])
checkDnsChange
(
bot
,
[(
resolver_ip
,
domain_1
),
(
resolver_ip
,
domain_2
)])
checkDnsChange
(
bot
,
[
(
resolver_ip
,
domain_1
,
"A"
),
(
resolver_ip
,
domain_2
,
"A"
),
(
resolver_ip
,
domain_1
,
"MX"
),
(
resolver_ip
,
domain_2
,
"MX"
),
],
)
checkSslChange
(
bot
,
[(
"1.2.3.4"
,
443
,
domain_1
),
(
"1.2.3.4"
,
443
,
domain_2
)]
...
...
@@ -422,9 +473,10 @@ class SurykatkaBotTestCase(unittest.TestCase):
"country"
,
)
mock_request
.
return_value
.
headers
=
{
"Etag"
:
"foobar"
}
mock_query
.
return_value
=
[
MockAnswer
(
"1.2.3.4"
),
MockAnswer
(
"1.2.3.5"
),
mock_query
.
side_effect
=
[
[
MockAnswerA
(
"1.2.3.4"
),
MockAnswerA
(
"1.2.3.5"
),],
[
MockAnswerA
(
"1.2.3.4"
),
MockAnswerA
(
"1.2.3.5"
),],
[
MockAnswerMX
(
""
)],
]
mock_create_default_context
.
return_value
.
wrap_socket
.
return_value
.
getpeercert
.
side_effect
=
[
b""
,
...
...
@@ -446,14 +498,16 @@ class SurykatkaBotTestCase(unittest.TestCase):
bot
.
iterateLoop
()
assert
mock_whois
.
call_count
==
1
assert
mock_query
.
call_count
==
2
assert
mock_socket
.
call_count
==
6
assert
mock_query
.
call_count
==
3
assert
mock_socket
.
call_count
==
8
assert
mock_create_default_context
.
call_count
==
2
assert
mock_request
.
call_count
==
4
checkNetworkChange
(
bot
,
[
(
"1.2.3.4"
,
25
),
(
"1.2.3.5"
,
25
),
(
resolver_ip
,
53
),
(
"1.2.3.4"
,
80
),
(
"1.2.3.5"
,
80
),
...
...
@@ -464,7 +518,9 @@ class SurykatkaBotTestCase(unittest.TestCase):
checkDomainChange
(
bot
,
[
"example.org"
])
checkDnsChange
(
bot
,
[(
resolver_ip
,
domain
)])
checkDnsChange
(
bot
,
[(
resolver_ip
,
domain
,
"A"
),
(
resolver_ip
,
domain
,
"MX"
)]
)
checkSslChange
(
bot
,
...
...
@@ -526,7 +582,13 @@ class SurykatkaBotTestCase(unittest.TestCase):
"country"
,
)
mock_request
.
return_value
.
headers
=
{
"Etag"
:
"foobar"
}
mock_query
.
return_value
=
[
MockAnswer
(
"1.2.3.4"
)]
mock_query
.
side_effect
=
[
[
MockAnswerA
(
"1.2.3.4"
)],
[
MockAnswerA
(
"1.2.3.4"
)],
[
MockAnswerA
(
"1.2.3.4"
)],
[
MockAnswerMX
(
""
)],
[
MockAnswerMX
(
""
)],
]
mock_create_default_context
.
return_value
.
wrap_socket
.
return_value
.
getpeercert
.
side_effect
=
[
b""
,
{
...
...
@@ -547,18 +609,32 @@ class SurykatkaBotTestCase(unittest.TestCase):
bot
.
iterateLoop
()
assert
mock_whois
.
call_count
==
1
assert
mock_query
.
call_count
==
3
assert
mock_socket
.
call_count
==
4
assert
mock_query
.
call_count
==
5
assert
mock_socket
.
call_count
==
5
assert
mock_create_default_context
.
call_count
==
2
assert
mock_request
.
call_count
==
4
checkNetworkChange
(
bot
,
[(
resolver_ip
,
53
),
(
"1.2.3.4"
,
80
),
(
"1.2.3.4"
,
443
)]
bot
,
[
(
"1.2.3.4"
,
25
),
(
resolver_ip
,
53
),
(
"1.2.3.4"
,
80
),
(
"1.2.3.4"
,
443
),
],
)
checkDomainChange
(
bot
,
[
"example.org"
])
checkDnsChange
(
bot
,
[(
resolver_ip
,
domain
),
(
resolver_ip
,
sub_domain
)])
checkDnsChange
(
bot
,
[
(
resolver_ip
,
domain
,
"A"
),
(
resolver_ip
,
sub_domain
,
"A"
),
(
resolver_ip
,
domain
,
"MX"
),
(
resolver_ip
,
sub_domain
,
"MX"
),
],
)
checkSslChange
(
bot
,
[(
"1.2.3.4"
,
443
,
domain
),
(
"1.2.3.4"
,
443
,
sub_domain
)]
...
...
@@ -620,7 +696,11 @@ class SurykatkaBotTestCase(unittest.TestCase):
"country"
,
)
mock_request
.
return_value
.
headers
=
{
"Etag"
:
"foobar"
}
mock_query
.
return_value
=
[
MockAnswer
(
"1.2.3.4"
)]
mock_query
.
side_effect
=
[
[
MockAnswerA
(
"1.2.3.4"
)],
[
MockAnswerA
(
"1.2.3.4"
)],
[
MockAnswerMX
(
""
)],
]
mock_create_default_context
.
return_value
.
wrap_socket
.
return_value
.
getpeercert
.
side_effect
=
[
b""
,
{
...
...
@@ -634,19 +714,30 @@ class SurykatkaBotTestCase(unittest.TestCase):
bot
.
iterateLoop
()
assert
mock_whois
.
call_count
==
1
assert
mock_query
.
call_count
==
2
assert
mock_socket
.
call_count
==
3
assert
mock_query
.
call_count
==
3
assert
mock_socket
.
call_count
==
4
assert
mock_create_default_context
.
call_count
==
1
assert
mock_request
.
call_count
==
2
checkNetworkChange
(
bot
,
[(
resolver_ip
,
53
),
(
"1.2.3.4"
,
80
),
(
"1.2.3.4"
,
443
)]
bot
,
[
(
"1.2.3.4"
,
25
),
(
resolver_ip
,
53
),
(
"1.2.3.4"
,
80
),
(
"1.2.3.4"
,
443
),
],
)
checkDomainChange
(
bot
,
[
"foo.example.com"
])
checkDnsChange
(
bot
,
[(
resolver_ip
,
"example.org"
),
(
resolver_ip
,
sub_domain
)]
bot
,
[
(
resolver_ip
,
"example.org"
,
"A"
),
(
resolver_ip
,
sub_domain
,
"A"
),
(
resolver_ip
,
sub_domain
,
"MX"
),
],
)
checkSslChange
(
bot
,
[(
"1.2.3.4"
,
443
,
sub_domain
)])
...
...
@@ -703,7 +794,11 @@ class SurykatkaBotTestCase(unittest.TestCase):
"country"
,
)
mock_request
.
return_value
.
headers
=
{
"Etag"
:
"foobar"
}
mock_query
.
return_value
=
[
MockAnswer
(
"1.2.3.4"
)]
mock_query
.
side_effect
=
[
[
MockAnswerA
(
"1.2.3.4"
)],
[
MockAnswerA
(
"1.2.3.4"
)],
[
MockAnswerMX
(
""
)],
]
mock_create_default_context
.
return_value
.
wrap_socket
.
return_value
.
getpeercert
.
side_effect
=
[
b""
,
{
...
...
@@ -716,18 +811,26 @@ class SurykatkaBotTestCase(unittest.TestCase):
bot
.
iterateLoop
()
assert
mock_whois
.
call_count
==
1
assert
mock_query
.
call_count
==
2
assert
mock_socket
.
call_count
==
3
assert
mock_query
.
call_count
==
3
assert
mock_socket
.
call_count
==
4
assert
mock_create_default_context
.
call_count
==
1
assert
mock_request
.
call_count
==
3
checkNetworkChange
(
bot
,
[(
resolver_ip
,
53
),
(
"1.2.3.4"
,
80
),
(
"1.2.3.4"
,
443
)]
bot
,
[
(
"1.2.3.4"
,
25
),
(
resolver_ip
,
53
),
(
"1.2.3.4"
,
80
),
(
"1.2.3.4"
,
443
),
],
)
checkDomainChange
(
bot
,
[
"example.org"
])
checkDnsChange
(
bot
,
[(
resolver_ip
,
domain
)])
checkDnsChange
(
bot
,
[(
resolver_ip
,
domain
,
"A"
),
(
resolver_ip
,
domain
,
"MX"
)]
)
checkSslChange
(
bot
,
[(
"1.2.3.4"
,
443
,
domain
)])
...
...
@@ -782,11 +885,11 @@ class SurykatkaBotTestCase(unittest.TestCase):
"country"
,
)
mock_request
.
return_value
.
headers
=
{
"Etag"
:
"foobar"
}
mock_query
.
side_effect
=
[[
MockAnswer
(
"1.2.3.4"
)
],
[]]
mock_query
.
side_effect
=
[[
MockAnswer
A
(
"1.2.3.4"
)],
[
],
[]]
bot
.
iterateLoop
()
assert
mock_whois
.
call_count
==
1
assert
mock_query
.
call_count
==
2
assert
mock_query
.
call_count
==
3
assert
mock_socket
.
call_count
==
0
assert
mock_request
.
call_count
==
0
...
...
@@ -795,7 +898,12 @@ class SurykatkaBotTestCase(unittest.TestCase):
checkDomainChange
(
bot
,
[
"example2.org"
])
checkDnsChange
(
bot
,
[(
resolver_ip
,
domain
),
(
resolver_ip
,
"example2.org"
)]
bot
,
[
(
resolver_ip
,
domain
,
"A"
),
(
resolver_ip
,
"example2.org"
,
"A"
),
(
resolver_ip
,
"example2.org"
,
"MX"
),
],
)
checkHttpCodeChange
(
bot
,
[])
...
...
@@ -834,7 +942,7 @@ class SurykatkaBotStatusTestCase(unittest.TestCase):
"missing_data"
:
[
{
"text"
:
resolver_ip
,
"date"
:
result
[
"bot_status"
][
0
][
"date"
]}
],
"
htt
p_server"
:
[],
"
tc
p_server"
:
[],
"ssl_certificate"
:
[],
"http_query"
:
[],
}
...
...
@@ -869,7 +977,7 @@ class SurykatkaBotStatusTestCase(unittest.TestCase):
assert
len
(
result
[
"dns_server"
])
==
0
assert
len
(
result
[
"whois"
])
==
0
assert
len
(
result
[
"dns_query"
])
==
0
assert
len
(
result
[
"
htt
p_server"
])
==
0
assert
len
(
result
[
"
tc
p_server"
])
==
0
assert
len
(
result
[
"ssl_certificate"
])
==
0
assert
len
(
result
[
"http_query"
])
==
0
# +1 for example.org
...
...
tests/test_dns.py
View file @
77772997
...
...
@@ -32,13 +32,19 @@ from surykatka.dns import (
)
from
surykatka.status
import
logStatus
import
mock
from
dns
import
name
as
dns_name
class
MockAnswer
(
object
):
class
MockAnswer
A
(
object
):
def
__init__
(
self
,
address
):
self
.
address
=
address
class
MockAnswerMX
(
object
):
def
__init__
(
self
,
label
):
self
.
exchange
=
dns_name
.
Name
(
dns_name
.
from_text
(
label
))
class
SurykatkaDNSTestCase
(
unittest
.
TestCase
):
def
setUp
(
self
):
self
.
db
=
LogDB
(
":memory:"
)
...
...
@@ -253,7 +259,7 @@ class SurykatkaDNSTestCase(unittest.TestCase):
################################################
# queryDNS
################################################
def
test_queryDNS_
default
(
self
):
def
test_queryDNS_
A
(
self
):
resolver_ip
=
"127.0.0.1"
domain
=
"example.org"
rdtype
=
"A"
...
...
@@ -263,8 +269,8 @@ class SurykatkaDNSTestCase(unittest.TestCase):
"surykatka.dns.dns_resolver.Resolver.query"
)
as
mock_query
:
mock_query
.
return_value
=
[
MockAnswer
(
"4.3.2.1"
),
MockAnswer
(
"1.2.3.4"
),
MockAnswer
A
(
"4.3.2.1"
),
MockAnswer
A
(
"1.2.3.4"
),
]
result
=
queryDNS
(
self
.
db
,
status_id
,
resolver_ip
,
domain
,
rdtype
)
...
...
@@ -281,6 +287,37 @@ class SurykatkaDNSTestCase(unittest.TestCase):
assert
self
.
db
.
DnsChange
.
get
().
status_id
==
status_id
assert
result
==
[
"1.2.3.4"
,
"4.3.2.1"
]
def
test_queryDNS_MX
(
self
):
resolver_ip
=
"127.0.0.1"
domain
=
"example.org"
rdtype
=
"MX"
status_id
=
logStatus
(
self
.
db
,
"foo"
)
with
mock
.
patch
(
"surykatka.dns.dns_resolver.Resolver.query"
)
as
mock_query
:
mock_query
.
return_value
=
[
MockAnswerMX
(
"mail1.example.org"
),
MockAnswerMX
(
"mail2.example.org"
),
]
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
==
"mail1.example.org, mail2.example.org"
)
assert
self
.
db
.
DnsChange
.
get
().
status_id
==
status_id
assert
result
==
[
"mail1.example.org"
,
"mail2.example.org"
]
def
test_queryDNS_rejectRdtype
(
self
):
resolver_ip
=
"127.0.0.1"
domain
=
"example.org"
...
...
@@ -423,8 +460,8 @@ class SurykatkaDNSTestCase(unittest.TestCase):
"surykatka.dns.dns_resolver.Resolver.query"
)
as
mock_query
:
mock_query
.
return_value
=
[
MockAnswer
(
"4.3.2.1"
),
MockAnswer
(
"1.2.3.4"
),
MockAnswer
A
(
"4.3.2.1"
),
MockAnswer
A
(
"1.2.3.4"
),
]
result
=
getReachableResolverList
(
self
.
db
,
status_id
,
[
resolver_ip
]
...
...
@@ -502,8 +539,8 @@ class SurykatkaDNSTestCase(unittest.TestCase):
"surykatka.dns.dns_resolver.Resolver.query"
)
as
mock_query
:
mock_query
.
return_value
=
[
MockAnswer
(
"4.3.2.1"
),
MockAnswer
(
"1.2.3.4"
),
MockAnswer
A
(
"4.3.2.1"
),
MockAnswer
A
(
"1.2.3.4"
),
]
result
=
getDomainIpDict
(
self
.
db
,
status_id
,
resolver_ip_list
,
domain_list
,
rdtype
...
...
@@ -531,8 +568,8 @@ class SurykatkaDNSTestCase(unittest.TestCase):
"surykatka.dns.dns_resolver.Resolver.query"
)
as
mock_query
:
mock_query
.
side_effect
=
[
[
MockAnswer
(
"4.3.2.1"
),
MockAnswer
(
"1.2.3.4"
)],
[
MockAnswer
(
"4.3.2.1"
),
MockAnswer
(
"1.2.3.5"
)],
[
MockAnswer
A
(
"4.3.2.1"
),
MockAnswerA
(
"1.2.3.4"
)],
[
MockAnswer
A
(
"4.3.2.1"
),
MockAnswerA
(
"1.2.3.5"
)],
]
result
=
getDomainIpDict
(
self
.
db
,
status_id
,
resolver_ip_list
,
domain_list
,
rdtype
...
...
@@ -564,8 +601,8 @@ class SurykatkaDNSTestCase(unittest.TestCase):
"surykatka.dns.dns_resolver.Resolver.query"
)
as
mock_query
:
mock_query
.
side_effect
=
[
[
MockAnswer
(
"4.3.2.1"
),
MockAnswer
(
"1.2.3.4"
)],
[
MockAnswer
(
"4.3.2.1"
),
MockAnswer
(
"1.2.3.5"
)],
[
MockAnswer
A
(
"4.3.2.1"
),
MockAnswerA
(
"1.2.3.4"
)],
[
MockAnswer
A
(
"4.3.2.1"
),
MockAnswerA
(
"1.2.3.5"
)],
]
result
=
getDomainIpDict
(
self
.
db
,
status_id
,
resolver_ip_list
,
domain_list
,
rdtype
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment