Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/dnsviz/dnsviz.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorCasey Deccio <casey@deccio.net>2019-03-07 23:57:05 +0300
committerCasey Deccio <casey@deccio.net>2019-03-07 23:57:05 +0300
commit7dbc582e4ac9fbd8e5c5c1e32fb71ca00df2a32e (patch)
treed49ddc4c59325ebc4fe17bb0fb31a8e5b0fb6d97
parent5cdbd10c3f1ad79d7074ce6a13c843820fb750bc (diff)
Mark the use of private IP addresses as an error
-rw-r--r--dnsviz/analysis/errors.py25
-rw-r--r--dnsviz/analysis/offline.py32
-rw-r--r--dnsviz/commands/graph.py6
-rw-r--r--dnsviz/commands/grok.py6
-rw-r--r--dnsviz/commands/print.py6
-rw-r--r--doc/man/dnsviz-graph.17
-rw-r--r--doc/man/dnsviz-grok.17
-rw-r--r--doc/man/dnsviz-print.17
8 files changed, 90 insertions, 6 deletions
diff --git a/dnsviz/analysis/errors.py b/dnsviz/analysis/errors.py
index 3ba1a26..b4665ef 100644
--- a/dnsviz/analysis/errors.py
+++ b/dnsviz/analysis/errors.py
@@ -1844,6 +1844,31 @@ class NoAddressForNSName(NSNameError):
code = 'NO_ADDRESS_FOR_NS_NAME'
description_template = "The following NS name(s) did not resolve to address(es): %(names_text)s"
+class PrivateAddressNS(NSNameError):
+ pass
+
+class NSNameResolvesToPrivateIP(PrivateAddressNS):
+ '''
+ >>> e = NSNameResolvesToPrivateIP(names=('ns1.foo.baz.',))
+ >>> e.description
+ 'The following NS name(s) resolved to IP address(es) in private IP address space: ns1.foo.baz.'
+ '''
+
+ _abstract = False
+ code = 'NS_NAME_PRIVATE_IP'
+ description_template = "The following NS name(s) resolved to IP address(es) in private IP address space: %(names_text)s"
+
+class GlueReferencesPrivateIP(PrivateAddressNS):
+ '''
+ >>> e = GlueReferencesPrivateIP(names=('ns1.foo.baz.',))
+ >>> e.description
+ 'Glue for the following NS name(s) referenced IP address(es) in private IP address space: ns1.foo.baz.'
+ '''
+
+ _abstract = False
+ code = 'GLUE_PRIVATE_IP'
+ description_template = "Glue for the following NS name(s) referenced IP address(es) in private IP address space: %(names_text)s"
+
class GlueMismatchError(DelegationError):
'''
>>> e = GlueMismatchError(name='ns1.foo.baz.', glue_addresses=('192.0.2.1',), auth_addresses=('192.0.2.2',))
diff --git a/dnsviz/analysis/offline.py b/dnsviz/analysis/offline.py
index 3ec0bcc..3b64149 100644
--- a/dnsviz/analysis/offline.py
+++ b/dnsviz/analysis/offline.py
@@ -40,6 +40,7 @@ import dns.flags, dns.rcode, dns.rdataclass, dns.rdatatype
from dnsviz import crypto
import dnsviz.format as fmt
+from dnsviz.ipaddr import *
import dnsviz.query as Q
from dnsviz import response as Response
from dnsviz.util import tuple_to_dict
@@ -96,6 +97,7 @@ class OfflineDomainNameAnalysis(OnlineDomainNameAnalysis):
def __init__(self, *args, **kwargs):
self._strict_cookies = kwargs.pop('strict_cookies', False)
+ self._allow_private = kwargs.pop('allow_private', False)
super(OfflineDomainNameAnalysis, self).__init__(*args, **kwargs)
@@ -1686,6 +1688,11 @@ class OfflineDomainNameAnalysis(OnlineDomainNameAnalysis):
names_missing_glue = []
names_missing_auth = []
+ names_auth_private = set()
+ names_auth_zero = set()
+ names_glue_private = set()
+ names_glue_zero = set()
+
for name in all_names:
# if name resolution resulted in an error (other than NXDOMAIN)
if name not in auth_mapping:
@@ -1698,6 +1705,13 @@ class OfflineDomainNameAnalysis(OnlineDomainNameAnalysis):
if not auth_mapping[name]:
names_missing_auth.append(name)
+ for addr in auth_addrs:
+ if LOOPBACK_IPV4_RE.match(addr) or addr == LOOPBACK_IPV6 or \
+ RFC_1918_RE.match(addr) or LINK_LOCAL_RE.match(addr) or UNIQ_LOCAL_RE.match(addr):
+ names_auth_private.add(name)
+ if ZERO_SLASH8_RE.search(addr):
+ names_auth_zero.add(name)
+
if names_from_parent:
name_in_parent = name in names_from_parent
elif self.delegation_status == Status.DELEGATION_STATUS_INCOMPLETE:
@@ -1710,6 +1724,13 @@ class OfflineDomainNameAnalysis(OnlineDomainNameAnalysis):
if name.is_subdomain(self.name) and not glue_mapping[name]:
names_missing_glue.append(name)
+ for addr in glue_mapping[name]:
+ if LOOPBACK_IPV4_RE.match(addr) or addr == LOOPBACK_IPV6 or \
+ RFC_1918_RE.match(addr) or LINK_LOCAL_RE.match(addr) or UNIQ_LOCAL_RE.match(addr):
+ names_glue_private.add(name)
+ if ZERO_SLASH8_RE.search(addr):
+ names_glue_zero.add(name)
+
# if there are both glue and authoritative addresses supplied, check that it matches the authoritative response
if glue_mapping[name] and auth_addrs:
# there are authoritative address records either of type A
@@ -1764,6 +1785,17 @@ class OfflineDomainNameAnalysis(OnlineDomainNameAnalysis):
names_error_resolving.sort()
self.zone_errors.append(Errors.ErrorResolvingNSName(names=[fmt.humanize_name(x) for x in names_error_resolving]))
+ if not self._allow_private:
+ if names_auth_private:
+ names_auth_private = list(names_auth_private)
+ names_auth_private.sort()
+ self.zone_errors.append(Errors.NSNameResolvesToPrivateIP(names=[fmt.humanize_name(x) for x in names_auth_private]))
+
+ if names_glue_private:
+ names_glue_private = list(names_glue_private)
+ names_glue_private.sort()
+ self.delegation_errors[dns.rdatatype.DS].append(Errors.GlueReferencesPrivateIP(names=[fmt.humanize_name(x) for x in names_glue_private]))
+
if names_with_no_glue_ipv4:
names_with_no_glue_ipv4.sort()
for name in names_with_no_glue_ipv4:
diff --git a/dnsviz/commands/graph.py b/dnsviz/commands/graph.py
index e64c239..f6b53d4 100644
--- a/dnsviz/commands/graph.py
+++ b/dnsviz/commands/graph.py
@@ -78,6 +78,7 @@ Options:
-r <filename> - Read diagnostic queries from a file.
-t <filename> - Use trusted keys from the designated file.
-C - Enforce DNS cookies strictly.
+ -P - Allow private IP addresses for authoritative DNS servers.
-R <type>[,<type>...]
- Process queries of only the specified type(s).
-e - Do not remove redundant RRSIG edges from the graph.
@@ -156,7 +157,7 @@ def main(argv):
test_pygraphviz()
try:
- opts, args = getopt.getopt(argv[1:], 'f:r:R:et:COo:T:h')
+ opts, args = getopt.getopt(argv[1:], 'f:r:R:et:CPOo:T:h')
except getopt.GetoptError as e:
sys.stderr.write('%s\n' % str(e))
sys.exit(1)
@@ -201,6 +202,7 @@ def main(argv):
rdtypes = None
strict_cookies = '-C' in opts
+ allow_private = '-P' in opts
remove_edges = '-e' not in opts
@@ -305,7 +307,7 @@ def main(argv):
if name_str not in analysis_structured or analysis_structured[name_str].get('stub', True):
logger.error('The analysis of "%s" was not found in the input.' % lb2s(name.to_text()))
continue
- name_obj = OfflineDomainNameAnalysis.deserialize(name, analysis_structured, cache, strict_cookies=strict_cookies)
+ name_obj = OfflineDomainNameAnalysis.deserialize(name, analysis_structured, cache, strict_cookies=strict_cookies, allow_private=allow_private)
name_objs.append(name_obj)
if latest_analysis_date is None or latest_analysis_date > name_obj.analysis_end:
diff --git a/dnsviz/commands/grok.py b/dnsviz/commands/grok.py
index 752b1ef..96f7875 100644
--- a/dnsviz/commands/grok.py
+++ b/dnsviz/commands/grok.py
@@ -108,6 +108,7 @@ Options:
-r <filename> - Read diagnostic queries from a file.
-t <filename> - Use trusted keys from the designated file.
-C - Enforce DNS cookies strictly.
+ -P - Allow private IP addresses for authoritative DNS servers.
-o <filename> - Save the output to the specified file.
-c - Format JSON output minimally, instead of "pretty".
-l <loglevel> - Log at the specified level: error, warning, info, debug.
@@ -170,7 +171,7 @@ def test_pygraphviz():
def main(argv):
try:
try:
- opts, args = getopt.getopt(argv[1:], 'f:r:t:Co:cl:h')
+ opts, args = getopt.getopt(argv[1:], 'f:r:t:CPo:cl:h')
except getopt.GetoptError as e:
sys.stderr.write('%s\n' % str(e))
sys.exit(1)
@@ -216,6 +217,7 @@ def main(argv):
loglevel = logging.DEBUG
strict_cookies = '-C' in opts
+ allow_private = '-P' in opts
if '-r' not in opts or opts['-r'] == '-':
opt_r = sys.stdin.fileno()
@@ -320,7 +322,7 @@ def main(argv):
if name_str not in analysis_structured or analysis_structured[name_str].get('stub', True):
logger.error('The analysis of "%s" was not found in the input.' % lb2s(name.to_text()))
continue
- name_obj = OfflineDomainNameAnalysis.deserialize(name, analysis_structured, cache, strict_cookies=strict_cookies)
+ name_obj = OfflineDomainNameAnalysis.deserialize(name, analysis_structured, cache, strict_cookies=strict_cookies, allow_private=allow_private)
name_objs.append(name_obj)
if not name_objs:
diff --git a/dnsviz/commands/print.py b/dnsviz/commands/print.py
index 0b8d3b9..aac7bc9 100644
--- a/dnsviz/commands/print.py
+++ b/dnsviz/commands/print.py
@@ -74,6 +74,7 @@ Options:
-r <filename> - Read diagnostic queries from a file.
-t <filename> - Use trusted keys from the designated file.
-C - Enforce DNS cookies strictly.
+ -P - Allow private IP addresses for authoritative DNS servers.
-R <type>[,<type>...]
- Process queries of only the specified type(s).
-O - Derive the filename(s) from domain name(s).
@@ -312,7 +313,7 @@ def main(argv):
test_pygraphviz()
try:
- opts, args = getopt.getopt(argv[1:], 'f:r:R:t:COo:h')
+ opts, args = getopt.getopt(argv[1:], 'f:r:R:t:CPOo:h')
except getopt.GetoptError as e:
sys.stderr.write('%s\n' % str(e))
sys.exit(1)
@@ -357,6 +358,7 @@ def main(argv):
rdtypes = None
strict_cookies = '-C' in opts
+ allow_private = '-P' in opts
if '-o' in opts and '-O' in opts:
sys.stderr.write('The -o and -O options may not be used together.\n')
@@ -449,7 +451,7 @@ def main(argv):
if name_str not in analysis_structured or analysis_structured[name_str].get('stub', True):
logger.error('The analysis of "%s" was not found in the input.' % lb2s(name.to_text()))
continue
- name_obj = TTLAgnosticOfflineDomainNameAnalysis.deserialize(name, analysis_structured, cache, strict_cookies=strict_cookies)
+ name_obj = TTLAgnosticOfflineDomainNameAnalysis.deserialize(name, analysis_structured, cache, strict_cookies=strict_cookies, allow_private=allow_private)
name_objs.append(name_obj)
if latest_analysis_date is None or latest_analysis_date > name_obj.analysis_end:
diff --git a/doc/man/dnsviz-graph.1 b/doc/man/dnsviz-graph.1
index c6b6f5a..480a9c9 100644
--- a/doc/man/dnsviz-graph.1
+++ b/doc/man/dnsviz-graph.1
@@ -83,6 +83,13 @@ Enforce DNS cookies strictly. Require a server to return a "BADCOOKIE" response
when a query contains a COOKIE option with no server cookie or with an invalid
server cookie.
.TP
+.B -P
+Allow private IP addresses for authoritative DNS servers. By default, if the
+IP address corresponding to an authoritative server is in IP address space
+designated as "private", it is flagged as an error. However, there are some
+cases where this is allowed. For example, if the diagnostic queries are issued
+to servers in an experimental environment, this might be permissible.
+.TP
.B -R \fItype\fR[,\fItype...\fI]
Process queries of only the specified type(s) (e.g., A, AAAA). The default is
to process all types queried as part of the diagnostic input.
diff --git a/doc/man/dnsviz-grok.1 b/doc/man/dnsviz-grok.1
index 3f0b352..acd8ae5 100644
--- a/doc/man/dnsviz-grok.1
+++ b/doc/man/dnsviz-grok.1
@@ -81,6 +81,13 @@ Enforce DNS cookies strictly. Require a server to return a "BADCOOKIE" response
when a query contains a COOKIE option with no server cookie or with an invalid
server cookie.
.TP
+.B -P
+Allow private IP addresses for authoritative DNS servers. By default, if the
+IP address corresponding to an authoritative server is in IP address space
+designated as "private", it is flagged as an error. However, there are some
+cases where this is allowed. For example, if the diagnostic queries are issued
+to servers in an experimental environment, this might be permissible.
+.TP
\fB-o\fR \fIfilename\fR
Write the output to the specified file instead of to standard output, which
is the default.
diff --git a/doc/man/dnsviz-print.1 b/doc/man/dnsviz-print.1
index cd5fec8..b29672c 100644
--- a/doc/man/dnsviz-print.1
+++ b/doc/man/dnsviz-print.1
@@ -83,6 +83,13 @@ Enforce DNS cookies strictly. Require a server to return a "BADCOOKIE" response
when a query contains a COOKIE option with no server cookie or with an invalid
server cookie.
.TP
+.B -P
+Allow private IP addresses for authoritative DNS servers. By default, if the
+IP address corresponding to an authoritative server is in IP address space
+designated as "private", it is flagged as an error. However, there are some
+cases where this is allowed. For example, if the diagnostic queries are issued
+to servers in an experimental environment, this might be permissible.
+.TP
.B -R \fItype\fR[,\fItype...\fR]
Process queries of only the specified type(s) (e.g., A, AAAA). The default is
to process all types queried as part of the diagnostic input.