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
49a3a992
Commit
49a3a992
authored
Dec 01, 2021
by
Romain Courteaud
🐙
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Report PTR record
Allow empty ptr
parent
f2c18185
Changes
4
Hide whitespace changes
Inline
Side-by-side
Showing
4 changed files
with
115 additions
and
12 deletions
+115
-12
src/surykatka/bot.py
src/surykatka/bot.py
+34
-2
src/surykatka/dns.py
src/surykatka/dns.py
+9
-2
tests/test_bot.py
tests/test_bot.py
+26
-8
tests/test_dns.py
tests/test_dns.py
+46
-0
No files found.
src/surykatka/bot.py
View file @
49a3a992
...
...
@@ -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"
]
)
...
...
src/surykatka/dns.py
View file @
49a3a992
...
...
@@ -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
(
...
...
tests/test_bot.py
View file @
49a3a992
...
...
@@ -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"
),
],
)
...
...
tests/test_dns.py
View file @
49a3a992
...
...
@@ -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"
...
...
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