]+CELLSPACING=")-\d+"', r'\g<1>0"', l, 1)
for nsec_name in self.nsec_rr_status[n]:
if not self.nsec_rr_status[n][nsec_name]:
self.nsec_rr_status[n][nsec_name] = COLORS['bogus']
l = re.sub(r'(]+PORT="%s")' % nsec_name, r'\1 COLOR="%s"' % self.nsec_rr_status[n][nsec_name], l, 1)
n.attr['label'] = '<%s>' % l
def _set_node_status(self, n):
status = self.status_for_node(n)
node_id = n.replace('*', '_')
for serialized in self.node_info[node_id]:
serialized['status'] = Status.rrset_status_mapping[status]
def add_trust(self, trusted_keys, supported_algs=None):
trusted_keys = tuple_to_dict(trusted_keys)
if supported_algs is not None:
supported_algs.intersection_update(crypto._supported_algs)
else:
supported_algs = crypto._supported_algs
dlv_nodes = []
trusted_zone_top_names = set([self.get_zone(z)[3] for z in trusted_keys])
for zone in trusted_keys:
zone_top_name = self.get_zone(zone)[3]
if not self.G.has_node(zone_top_name) or zone_top_name not in self.subgraph_not_stub:
continue
# if at least one algorithm in trusted keys for the zone is
# supported, then give zone no initial marking; otherwise mark it
# as insecure
algs = set([d.algorithm for d in trusted_keys[zone]])
if algs.intersection(supported_algs):
self.G.get_node(zone_top_name).attr['color'] = ''
else:
self.G.get_node(zone_top_name).attr['color'] = COLORS['insecure']
for dnskey in trusted_keys[zone]:
try:
dnskey_node = self.get_dnskey(self.id_for_dnskey(zone, dnskey), zone, dnskey.algorithm, Response.DNSKEYMeta.calc_key_tag(dnskey))
dnskey_node.attr['peripheries'] = 2
if self.G.get_node(zone_top_name).attr['color'] == '':
self._add_trust_to_nodes_in_chain(dnskey_node, trusted_zone_top_names, dlv_nodes, False, [])
except KeyError:
dnskey_node = self.add_dnskey_non_existent(zone, zone, dnskey.algorithm, Response.DNSKEYMeta.calc_key_tag(dnskey))
dnskey_node.attr['peripheries'] = 2
# determine DLV zones based on DLV nodes
dlv_trusted_zone_top_names = []
for dlv_node in dlv_nodes:
dlv_trusted_zone_top_names.append(self.node_subgraph_name[dlv_node])
# now traverse clusters and mark insecure nodes in secure delegations as bad
for zone in trusted_keys:
S, zone_node_str, zone_bottom_name, zone_top_name = self.get_zone(zone)
if not self.G.has_node(zone_top_name) or zone_top_name not in self.subgraph_not_stub:
continue
# don't yet mark subdomains of DLV zones, as we have yet
# to add trust to them
if zone_top_name not in dlv_trusted_zone_top_names:
self._add_trust_to_orphaned_nodes(zone_node_str, [])
# now that we can show which zones are provably insecure, we
# can apply trust from the DLV zones
for dlv_node in dlv_nodes:
self._add_trust_to_nodes_in_chain(dlv_node, trusted_zone_top_names, [], True, [])
# now mark the orphaned nodes
for dlv_node in dlv_nodes:
zone_node_str = self.node_subgraph_name[dlv_node][:-4]
self._add_trust_to_orphaned_nodes(zone_node_str, [])
for n in self.G.nodes():
# set the status of (only) the cluster top node as well
if n.attr['shape'] == 'point' and n.endswith('_top'):
pass
elif n.attr['shape'] not in ('ellipse', 'rectangle') and not n.startswith('NSEC'):
continue
self._set_non_existent_color(n)
self._set_nsec_color(n)
self._set_node_status(n)
def status_for_node(self, n, port=None):
n = self.G.get_node(n)
if n.attr['color'] in (COLORS['secure'], COLORS['secure_non_existent']):
status = Status.RRSET_STATUS_SECURE
elif n.attr['color'] in (COLORS['bogus'], COLORS['bogus_non_existent']):
if port is not None and self.nsec_rr_status[n][port] == COLORS['secure']:
status = Status.RRSET_STATUS_SECURE
else:
status = Status.RRSET_STATUS_BOGUS
else:
if n.startswith('DNSKEY') and \
DASHED_STYLE_RE.search(n.attr['style']):
status = Status.RRSET_STATUS_NON_EXISTENT
else:
status = Status.RRSET_STATUS_INSECURE
return status
def secure_nsec3_optout_nodes_covering_node(self, n):
return [x for x in self.G.out_neighbors(n) if x.startswith('NSEC') and \
OPTOUT_STYLE_RE.search(x.attr['label']) is not None and \
x.attr['color'] == COLORS['secure']]
def secure_nsec_nodes_covering_node(self, n):
return [x for x in self.G.out_neighbors(n) if x.startswith('NSEC') and \
x.attr['color'] == COLORS['secure']]
def is_invis(self, n):
return INVIS_STYLE_RE.search(self.G.get_node(n).attr['style']) is not None
def _add_trust_to_nodes_in_chain(self, n, trusted_zones, dlv_nodes, force, trace):
if n in trace:
return
is_ds = n.startswith('DS-') or n.startswith('DLV-')
is_dlv = n.startswith('DLV-')
is_dnskey = n.startswith('DNSKEY-')
is_nsec = n.startswith('NSEC')
is_dname = n.endswith('|DNAME')
if is_dlv and not force:
dlv_nodes.append(n)
return
# if n isn't a DNSKEY, DS/DLV, or NSEC record,
# then don't follow back edges
if not (is_ds or is_dnskey or is_nsec or is_dname):
return
is_revoked = n.attr['penwidth'] == '4.0'
is_trust_anchor = n.attr['peripheries'] == '2'
top_name = self.G.get_node(self.node_subgraph_name[n])
# trust anchor and revoked DNSKEY must be self-signed
if is_revoked or is_trust_anchor:
valid_self_loop = False
if self.G.has_edge(n,n):
for e1 in self.G.out_edges(n) + self.G.in_edges(n):
if (n,n) == e1 and \
e1.attr['color'] == COLORS['secure']:
valid_self_loop = True
# mark all the DNSKEY RRsets as valid
for rrsig in self.node_mapping[e1.attr['id']]:
self.secure_dnskey_rrsets.add(rrsig.rrset)
break
#XXX revisit if we want to do this here
if is_revoked and n.attr['color'] == COLORS['secure'] and not valid_self_loop:
n.attr['color'] = COLORS['bogus']
# mark the zone as "secure" as there is a secure entry point;
# descendants will be so marked by following the delegation edges
if is_trust_anchor and valid_self_loop:
n.attr['color'] = COLORS['secure']
top_name.attr['color'] = COLORS['secure']
node_trusted = n.attr['color'] == COLORS['secure']
if is_dnskey and not node_trusted:
# Here we are shortcutting the traversal because we are no longer
# propagating trust. But we still need to learn of any DLV nodes.
if not force:
S = self.G.get_subgraph(top_name[:-4])
for n in S.nodes():
if n.startswith('DLV-'):
dlv_nodes.append(n)
return
# iterate through each edge and propagate trust from this node
for e in self.G.in_edges(n):
p = e[0]
# if this is an edge used for formatting node (invis), then don't
# follow it
if INVIS_STYLE_RE.search(e.attr['style']) is not None:
continue
prev_top_name = self.G.get_node(self.node_subgraph_name[p])
# don't derive trust from parent if there is a trust anchor at the
# child
if is_ds and prev_top_name in trusted_zones:
continue
# if the previous node is already secure, then no need to follow it
if p.attr['color'] == COLORS['secure']:
continue
# if this is a DLV node, then the zone it covers must be marked
# as insecure through previous trust traversal (not because of
# a local trust anchor, which case is handled above)
if is_dlv:
if prev_top_name.attr['color'] not in ('', COLORS['insecure']):
continue
# reset the security of this top_name
prev_top_name.attr['color'] = ''
# if this is a non-matching edge (dashed) then don't follow it
if DASHED_STYLE_RE.search(e.attr['style']) is not None:
continue
# derive trust for the previous node using the current node and the
# color of the edge in between
prev_node_trusted = node_trusted and e.attr['color'] == COLORS['secure']
if is_ds:
# if this is an edge between DS and DNSKEY, then the DNSKEY is
# not considered secure unless it has a valid self-loop (in
# addition to the connecting edge being valid)
valid_self_loop = False
if self.G.has_edge(p,p):
for e1 in self.G.out_edges(p) + self.G.in_edges(p):
if (p,p) == e1 and \
e1.attr['color'] == COLORS['secure']:
valid_self_loop = True
# mark all the DNSKEY RRsets as valid
for rrsig in self.node_mapping[e1.attr['id']]:
self.secure_dnskey_rrsets.add(rrsig.rrset)
break
prev_node_trusted = prev_node_trusted and valid_self_loop
# if p is an NSEC (set) node, then we need to check that all the
# NSEC RRs have been authenticated before we mark this one as
# authenticated.
elif p.startswith('NSEC'):
rrsig_status = list(self.node_mapping[e.attr['id']])[0]
nsec_name = lb2s(rrsig_status.rrset.rrset.name.canonicalize().to_text()).replace(r'"', r'\"')
if prev_node_trusted:
self.nsec_rr_status[p][nsec_name] = COLORS['secure']
for nsec_name in self.nsec_rr_status[p]:
if self.nsec_rr_status[p][nsec_name] != COLORS['secure']:
prev_node_trusted = False
if is_nsec:
# if this is an NSEC, then only propagate trust if the previous
# node (i.e., the node it covers) is an RRset
if prev_node_trusted and p.attr['shape'] == 'rectangle':
p.attr['color'] = COLORS['secure']
elif prev_node_trusted:
p.attr['color'] = COLORS['secure']
self._add_trust_to_nodes_in_chain(p, trusted_zones, dlv_nodes, force, trace+[n])
def _add_trust_to_orphaned_nodes(self, subgraph_name, trace):
if subgraph_name in trace:
return
top_name = self.G.get_node(subgraph_name + '_top')
bottom_name = self.G.get_node(subgraph_name + '_bottom')
# if this subgraph (zone) is provably insecure, then don't process
# further
if top_name.attr['color'] == COLORS['insecure']:
return
# iterate through each node in the subgraph (zone) and mark as bogus
# all nodes that are not already marked as secure
S = self.G.get_subgraph(subgraph_name)
for n in S.nodes():
# don't mark invisible nodes (zone marking as secure/insecure is handled in the
# traversal at the delegation point below).
if INVIS_STYLE_RE.search(n.attr['style']) is not None:
continue
# if node is non-existent, then don't mark it, unless we are talking about an RRset
# or a non-existent trust anchor; it doesn't make sense to mark other nodes
# as bogus
if DASHED_STYLE_RE.search(n.attr['style']) is not None and not (n.attr['shape'] == 'rectangle' or \
n.attr['peripheries'] == 2):
continue
# if the name is already marked as secure
if n.attr['color'] == COLORS['secure']:
# don't mark it as bogus
continue
n.attr['color'] = COLORS['bogus']
# propagate trust through each descendant node
for p in self.G.predecessors(bottom_name):
e = self.G.get_edge(p, bottom_name)
child_subgraph_name = p[:-4]
if top_name.attr['color'] == COLORS['secure']:
# if this subgraph (zone) is secure, and the delegation is also
# secure, then mark the delegated subgraph (zone) as secure.
if e.attr['color'] == COLORS['secure']:
p.attr['color'] = COLORS['secure']
# if this subgraph (zone) is secure, and the delegation is not
# bogus (DNSSEC broken), then mark it as provably insecure.
elif e.attr['color'] != COLORS['bogus']:
# in this case, it's possible that the proven insecurity is
# dependent on NSEC/NSEC3 records that need to be
# authenticated. Before marking this as insecure, reach
# back up for NSEC records. If any are found, make sure at
# least one has been authenticated (i.e., has secure
# color).
nsec_found = False
nsec_authenticated = False
for n in self.G.out_neighbors(p):
if not n.startswith('NSEC'):
continue
# check that this node is in the zone we're coming from
if self.node_subgraph_name[n] != top_name:
continue
nsec_found = True
if n.attr['color'] == COLORS['secure']:
nsec_authenticated = True
break
# or if there are DS, then there are algorithms that are
# not understood (otherwise it would not be insecure).
# Check that at least one of the DS nodes was marked as
# secure.
ds_found = False
ds_authenticated = False
S = self.G.get_subgraph(child_subgraph_name)
for n in S.nodes():
# we're only concerned with DNSKEYs
if not n.startswith('DNSKEY-'):
continue
# we're looking for DS records
for d in self.G.out_neighbors(n):
if not (d.startswith('DS-') or d.startswith('DLV-')):
continue
# check that this node is in the zone we're coming from
if self.node_subgraph_name[d] != top_name:
continue
ds_found = True
if d.attr['color'] == COLORS['secure']:
ds_authenticated = True
break
if nsec_found and not nsec_authenticated:
pass
elif ds_found and not ds_authenticated:
pass
else:
p.attr['color'] = COLORS['insecure']
# if the child was not otherwise marked, then mark it as bogus
if p.attr['color'] == '':
p.attr['color'] = COLORS['bogus']
self._add_trust_to_orphaned_nodes(child_subgraph_name, trace+[subgraph_name])
def remove_extra_edges(self, show_redundant=False):
#XXX this assumes DNSKEYs with same name as apex
for S in self.G.subgraphs():
non_dnskey = set()
all_dnskeys = set()
ds_dnskeys = set()
ta_dnskeys = set()
ksks = set()
zsks = set()
sep_bit = set()
revoked_dnskeys = set()
non_existent_dnskeys = set()
existing_dnskeys = set()
for n in S.nodes():
if not n.startswith('DNSKEY-'):
if n.attr['shape'] != 'point':
non_dnskey.add(n)
continue
all_dnskeys.add(n)
in_edges = self.G.in_edges(n)
out_edges = self.G.out_edges(n)
ds_edges = [x for x in out_edges if x[1].startswith('DS-') or x[1].startswith('DLV-')]
is_ksk = bool([x for x in in_edges if x[0].startswith('DNSKEY-')])
is_zsk = bool([x for x in in_edges if NODE_DNSKEY_CDNSKEY_CDS_RE.match(x[0]) is None])
non_existent = DASHED_STYLE_RE.search(n.attr['style']) is not None
has_sep_bit = n.attr['fillcolor'] == 'lightgray'
if is_ksk:
ksks.add(n)
if is_zsk:
zsks.add(n)
if has_sep_bit:
sep_bit.add(n)
if n.attr['peripheries'] == '2':
ta_dnskeys.add(n)
if ds_edges:
ds_dnskeys.add(n)
if n.attr['penwidth'] == '4.0':
revoked_dnskeys.add(n)
if non_existent:
non_existent_dnskeys.add(n)
else:
existing_dnskeys.add(n)
seps = ds_dnskeys.union(ta_dnskeys).intersection(ksks).difference(revoked_dnskeys)
ksk_only = ksks.difference(zsks).difference(revoked_dnskeys)
zsk_only = zsks.difference(ksks).difference(revoked_dnskeys)
# if all keys have only KSK roles (i.e., none are signing the zone
# data), then try to distinguish using SEP bit
if ksk_only and not zsks and sep_bit:
ksk_only.intersection_update(sep_bit)
if seps:
top_level_keys = seps
else:
if ksk_only:
top_level_keys = ksk_only
elif ksks:
top_level_keys = ksks
elif sep_bit:
top_level_keys = sep_bit
else:
top_level_keys = all_dnskeys
if top_level_keys:
# If there aren't any KSKs or ZSKs, then signing roles are
# unknown, and the top-level keys are organized by SEP bit.
# Because there are no roles, every key is an "island" (i.e.,
# not signed by any top-level keys), so only look for "islands"
# if there are ZSKs or KSKs.
if zsks or ksks:
for n in all_dnskeys.difference(top_level_keys):
if set(self.G.out_neighbors(n)).intersection(top_level_keys):
# If this key is already signed by a top-level, then
# it's not in an island.
pass
else:
# Otherwise, find out what keys are connected to this one
neighbors = set(self.G.neighbors(n))
# If this key is ksk only, then it is always a top-level key.
if n in ksk_only:
top_level_keys.add(n)
# If this key is not a ksk, and there are ksks, then
# it's not a top-level key.
elif n not in ksks and neighbors.intersection(ksks):
pass
# If this key does not have its sep bit set, and there
# are others that do, then it's not a top-level key.
elif n not in sep_bit and neighbors.intersection(sep_bit):
pass
# Otherwise, it's on the same rank as all the others,
# so it is a top-level key.
else:
top_level_keys.add(n)
# In the case where a top-level key is signing zone data, and
# there are other top-level keys that are not signing zone data,
# remove it from the top-level keys list, and don't add an edge
# to the top. This will make the other top-level keys appear
# "higher".
for n in list(top_level_keys):
if n in zsks and set(self.G.neighbors(n)).intersection(top_level_keys).intersection(ksk_only):
top_level_keys.remove(n)
else:
self.G.add_edge(n, self.node_subgraph_name[n], style='invis')
# Now handle all the keys not at the top level
non_top_level_keys = all_dnskeys.difference(top_level_keys)
if non_top_level_keys:
# If there are any keys that are not at the top level, then
# determine whether they should be connected to the
# top-level keys, to the top, or left alone.
for n in non_top_level_keys:
# Non-existent DNSKEYs corresponding to DS and trust
# anchors should be connected to the top.
if n in non_existent_dnskeys:
if n in ds_dnskeys or n in ta_dnskeys:
self.G.add_edge(n, self.node_subgraph_name[n], style='invis')
# If not linked to any other DNSKEYs, then link to
# top-level keys.
elif not [x for x in self.G.out_neighbors(n) if x.startswith('DNSKEY')]:
for m in top_level_keys:
if not self.G.has_edge(n, m):
self.G.add_edge(n, m, style='invis')
intermediate_keys = non_top_level_keys
else:
intermediate_keys = top_level_keys
# If there are ZSKs (and possible ZSKs only signing zone data),
# then make those the intermediate keys, instead of using all
# the top-level (or non-top-level) keys.
if zsk_only:
intermediate_keys = zsk_only
elif zsks:
intermediate_keys = zsks
# Link non-keys to intermediate DNSKEYs
for n in non_dnskey:
if [x for x in self.G.out_neighbors(n) if x.startswith('DNSKEY') or x.startswith('NSEC')]:
continue
for m in intermediate_keys:
# we only link to non-existent DNSKEYs corresponding to
# DS records if there aren't any existing DNSKEYs.
if m in ds_dnskeys and m in non_existent_dnskeys:
if existing_dnskeys:
continue
self.G.add_edge(n, m, style='invis')
else:
# For all non-existent non-DNSKEYs, add an edge to the top
for n in non_dnskey:
if [x for x in self.G.out_neighbors(n) if x.startswith('DNSKEY') or x.startswith('NSEC')]:
continue
self.G.add_edge(n, self.node_subgraph_name[n], style='invis')
for n in ksks:
retain_edge_default = n in top_level_keys
for e in self.G.in_edges(n):
m = e[0]
if not m.startswith('DNSKEY-'):
continue
if n == m:
continue
if retain_edge_default and m in top_level_keys:
retain_edge = False
else:
retain_edge = retain_edge_default
if not retain_edge:
if show_redundant:
self.G.get_edge(m, n).attr['constraint'] = 'false'
else:
try:
del self.node_info[e.attr.get('id', None)]
except KeyError:
pass
self.G.remove_edge(m, n)
././@PaxHeader 0000000 0000000 0000000 00000000034 00000000000 010212 x ustar 00 28 mtime=1745253948.3985322
dnsviz-0.11.1/dnsviz.egg-info/ 0000755 0001750 0001750 00000000000 15001473074 015151 5 ustar 00casey casey ././@PaxHeader 0000000 0000000 0000000 00000000026 00000000000 010213 x ustar 00 22 mtime=1745253948.0
dnsviz-0.11.1/dnsviz.egg-info/PKG-INFO 0000644 0001750 0001750 00000003425 15001473074 016252 0 ustar 00casey casey Metadata-Version: 2.4
Name: dnsviz
Version: 0.11.1
Summary: DNS analysis and visualization tool suite
Home-page: https://github.com/dnsviz/dnsviz/
Author: Casey Deccio
Author-email: casey@deccio.net
License: LICENSE
Classifier: Development Status :: 5 - Production/Stable
Classifier: Environment :: Console
Classifier: Environment :: Web Environment
Classifier: Intended Audience :: Developers
Classifier: Intended Audience :: System Administrators
Classifier: License :: OSI Approved :: GNU General Public License v2 or later (GPLv2+)
Classifier: Natural Language :: English
Classifier: Operating System :: MacOS :: MacOS X
Classifier: Operating System :: POSIX
Classifier: Programming Language :: Python :: 2.7
Classifier: Programming Language :: Python :: 3.5
Classifier: Programming Language :: Python :: 3.6
Classifier: Programming Language :: Python :: 3.7
Classifier: Programming Language :: Python :: 3.8
Classifier: Programming Language :: Python :: 3.9
Classifier: Programming Language :: Python :: 3.10
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Topic :: Internet :: Name Service (DNS)
Classifier: Topic :: Scientific/Engineering :: Visualization
Classifier: Topic :: System :: Networking :: Monitoring
Requires: pygraphviz (>=1.3)
Requires: cryptography (>=36.0.0)
Requires: dnspython (>=1.13)
License-File: LICENSE
License-File: COPYRIGHT
Dynamic: author
Dynamic: author-email
Dynamic: classifier
Dynamic: description
Dynamic: home-page
Dynamic: license
Dynamic: license-file
Dynamic: requires
Dynamic: summary
DNSViz is a tool suite for analysis and visualization of Domain Name System
(DNS) behavior, including its security extensions (DNSSEC). This tool suite
powers the Web-based analysis available at http://dnsviz.net/ .
././@PaxHeader 0000000 0000000 0000000 00000000026 00000000000 010213 x ustar 00 22 mtime=1745253948.0
dnsviz-0.11.1/dnsviz.egg-info/SOURCES.txt 0000644 0001750 0001750 00000010030 15001473074 017027 0 ustar 00casey casey COPYRIGHT
LICENSE
MANIFEST.in
README.md
requirements.txt
setup.cfg
setup.py
bin/dnsviz
contrib/digviz
contrib/dnsviz-lg-ws.js
contrib/dnsviz-lg.cgi
contrib/dnsviz-lg-java/net/dnsviz/applet/DNSLookingGlassApplet.java
contrib/dnsviz-lg-java/net/dnsviz/lookingglass/DNSLookingGlass.java
contrib/dnsviz-lg-java/net/dnsviz/transport/DNSQueryTransportHandler.java
contrib/dnsviz-lg-java/net/dnsviz/transport/DNSQueryTransportHandlerComparator.java
contrib/dnsviz-lg-java/net/dnsviz/transport/DNSQueryTransportHandlerTCP.java
contrib/dnsviz-lg-java/net/dnsviz/transport/DNSQueryTransportHandlerUDP.java
contrib/dnsviz-lg-java/net/dnsviz/transport/DNSQueryTransportManager.java
contrib/dnsviz-lg-java/net/dnsviz/transport/Errno.java
contrib/dnsviz-lg-java/net/dnsviz/util/Base64.java
contrib/dnsviz-lg-java/net/dnsviz/util/Base64Decoder.java
contrib/dnsviz-lg-java/net/dnsviz/util/Base64Encoder.java
contrib/dnsviz-lg-java/net/dnsviz/util/DNSSettings.java
contrib/dnsviz-lg-java/net/dnsviz/websocket/WebSocketClient.java
dnsviz/__init__.py
dnsviz/base32.py
dnsviz/config.py.in
dnsviz/crypto.py
dnsviz/format.py
dnsviz/ipaddr.py
dnsviz/query.py
dnsviz/resolver.py
dnsviz/response.py
dnsviz/transport.py
dnsviz/util.py
dnsviz.egg-info/PKG-INFO
dnsviz.egg-info/SOURCES.txt
dnsviz.egg-info/dependency_links.txt
dnsviz.egg-info/top_level.txt
dnsviz/analysis/__init__.py
dnsviz/analysis/errors.py
dnsviz/analysis/offline.py
dnsviz/analysis/online.py
dnsviz/analysis/status.py
dnsviz/commands/__init__.py
dnsviz/commands/graph.py
dnsviz/commands/grok.py
dnsviz/commands/lookingglass.py
dnsviz/commands/print.py
dnsviz/commands/probe.py
dnsviz/commands/query.py
dnsviz/viz/__init__.py
dnsviz/viz/dnssec.py
doc/COPYRIGHT
doc/Makefile
doc/dnsviz-graph.html
doc/images/error.png
doc/images/logo-16x16.png
doc/images/logo-220x100.png
doc/images/logo-60x60.png
doc/images/warning.png
doc/man/dnsviz-graph.1
doc/man/dnsviz-grok.1
doc/man/dnsviz-print.1
doc/man/dnsviz-probe.1
doc/man/dnsviz-query.1
doc/man/dnsviz.1
doc/src/alias.dot
doc/src/cdnskey-cds-nodnskey.dot
doc/src/cdnskey-cds.dot
doc/src/delegation-bogus.dot
doc/src/delegation-incomplete.dot
doc/src/delegation-lame.dot
doc/src/delegation-secure.dot
doc/src/delegation.dot
doc/src/dname-invalid.dot
doc/src/dname.dot
doc/src/dnskey-revoke.dot
doc/src/dnskey-sep.dot
doc/src/dnskey-trust-anchor.dot
doc/src/dnskey.dot
doc/src/ds-invalid-digest.dot
doc/src/ds-invalid.dot
doc/src/ds-nodnskey.dot
doc/src/ds-pre-revoke.dot
doc/src/ds-unknown-alg.dot
doc/src/ds.dot
doc/src/edges-errors.dot
doc/src/edges-warnings.dot
doc/src/error.svg
doc/src/logo.svg
doc/src/nodata.dot
doc/src/nodes-bogus.dot
doc/src/nodes-errors.dot
doc/src/nodes-insecure.dot
doc/src/nodes-secure.dot
doc/src/nodes-warnings.dot
doc/src/nsec-ds.dot
doc/src/nsec-invalid.dot
doc/src/nsec-partial-bogus.dot
doc/src/nsec.dot
doc/src/nsec3-optout.dot
doc/src/nsec3.dot
doc/src/nxdomain.dot
doc/src/response-error.dot
doc/src/response-warning.dot
doc/src/rrset.dot
doc/src/rrsig-dnskey-pruned.dot
doc/src/rrsig-dnskey-redundant.dot
doc/src/rrsig-dnskey.dot
doc/src/rrsig-ds.dot
doc/src/rrsig-nsec.dot
doc/src/rrsig-rrset-expired.dot
doc/src/rrsig-rrset-invalid-sig.dot
doc/src/rrsig-rrset-invalid.dot
doc/src/rrsig-rrset-nodnskey.dot
doc/src/rrsig-rrset-pre-revoke.dot
doc/src/rrsig-rrset-unknown-alg.dot
doc/src/rrsig-rrset.dot
doc/src/warning.svg
doc/src/wildcard.dot
doc/src/zone-errors.dot
doc/src/zone-warnings.dot
doc/src/zone.dot
share/css/dnsviz.css
share/hints/named.root
share/html/dnssec-template.html
share/js/dnsviz.js
share/trusted-keys/root.txt
tests/test_00_setup.py
tests/test_11_response.py
tests/test_61_dnsviz_probe_options.py
tests/test_62_dnsviz_graph_options.py
tests/test_63_dnsviz_grok_options.py
tests/test_64_dnsviz_print_options.py
tests/test_71_dnsviz_probe_run_offline.py
tests/test_72_dnsviz_graph_run.py
tests/test_73_dnsviz_grok_run.py
tests/test_74_dnsviz_print_run.py
tests/test_81_dnsviz_probe_run_online.py
tests/test_99_cleanup.py
tests/vars.py
tests/zones/unsigned/example.com-probe-auth.json
tests/zones/unsigned/example.com.zone
tests/zones/unsigned/example.com.zone-delegation ././@PaxHeader 0000000 0000000 0000000 00000000026 00000000000 010213 x ustar 00 22 mtime=1745253948.0
dnsviz-0.11.1/dnsviz.egg-info/dependency_links.txt 0000644 0001750 0001750 00000000001 15001473074 021217 0 ustar 00casey casey
././@PaxHeader 0000000 0000000 0000000 00000000026 00000000000 010213 x ustar 00 22 mtime=1745253948.0
dnsviz-0.11.1/dnsviz.egg-info/top_level.txt 0000644 0001750 0001750 00000000007 15001473074 017700 0 ustar 00casey casey dnsviz
././@PaxHeader 0000000 0000000 0000000 00000000034 00000000000 010212 x ustar 00 28 mtime=1745253948.3905313
dnsviz-0.11.1/doc/ 0000755 0001750 0001750 00000000000 15001473074 012707 5 ustar 00casey casey ././@PaxHeader 0000000 0000000 0000000 00000000026 00000000000 010213 x ustar 00 22 mtime=1745253811.0
dnsviz-0.11.1/doc/COPYRIGHT 0000644 0001750 0001750 00000002317 15001472663 014210 0 ustar 00casey casey src/warning.svg:
Imported on July 11, 2016.
Author: user:Penubag / Wikimedia Commons / Public Domain
Downloaded from:
https://upload.wikimedia.org/wikipedia/commons/7/74/Ambox_warning_yellow.svg
License statement:
https://commons.wikimedia.org/wiki/File:Ambox_warning_yellow.svg
This work has been released into the public domain by its author, penubag.
This applies worldwide.
In some countries this may not be legally possible; if so:
penubag grants anyone the right to use this work for any purpose, without
any conditions, unless such conditions are required by law.
src/error.svg:
Imported on July 11, 2016.
Author: user:Penubag / Wikimedia Commons / Public Domain
Downloaded from:
https://upload.wikimedia.org/wikipedia/commons/1/15/Ambox_warning_pn.svg
License statement:
https://commons.wikimedia.org/wiki/File:Ambox_warning_pn.svg
I, the copyright holder of this work, release this work into the public
domain. This applies worldwide.
In some countries this may not be legally possible; if so:
I grant anyone the right to use this work for any purpose, without any
conditions, unless such conditions are required by law.
././@PaxHeader 0000000 0000000 0000000 00000000026 00000000000 010213 x ustar 00 22 mtime=1745253811.0
dnsviz-0.11.1/doc/Makefile 0000644 0001750 0001750 00000003734 15001472663 014361 0 ustar 00casey casey DOT=dot
INKSCAPE=inkscape
SRCDIR=src
IMGDIR=images
DOTFILES = $(wildcard $(SRCDIR)/*dot)
DOTPNGFILES = $(DOTFILES:$(SRCDIR)/%.dot=$(IMGDIR)/%.png)
all: $(DOTPNGFILES)
# make png files from dot files
$(DOTPNGFILES): $(IMGDIR)/%.png: $(SRCDIR)/%.dot
$(DOT) -Tpng $< > $@ || ( rm $@ && false )
# make icon-sized png files from warning.svg and error.svg
ICONSVGFILES = $(SRCDIR)/warning.svg $(SRCDIR)/error.svg
ICONPNGFILES = $(ICONSVGFILES:$(SRCDIR)/%.svg=$(IMGDIR)/%.png)
ICONWIDTH = 25
icons: $(ICONPNGFILES)
$(ICONPNGFILES): $(IMGDIR)/%.png: $(SRCDIR)/%.svg
HOME=/var/tmp $(INKSCAPE) --export-width=$(ICONWIDTH) --export-type=png --export-filename=$@ $<
# make banner png 220x100 file from logo.svg
LOGOSVGFILE = $(SRCDIR)/logo.svg
LOGOBANNERPNGFILE = $(IMGDIR)/logo-220x100.png
LOGOBANNERVIEWBOX = 58 43 381 173
LOGOBANNERHEIGHT = 100
# make square icon png 60x60 file from logo.svg
LOGOICONPNGFILE = $(IMGDIR)/logo-60x60.png
LOGOICONVIEWBOX = 335 43 103 103
LOGOICONHEIGHT = 50
# make square favico png 16x16 file from logo.svg
LOGOFAVICONPNGFILE = $(IMGDIR)/logo-16x16.png
LOGOFAVICONVIEWBOX = 335 43 103 103
LOGOFAVICONHEIGHT = 16
logo: $(LOGOBANNERPNGFILE) $(LOGOICONPNGFILE) $(LOGOFAVICONPNGFILE)
$(LOGOBANNERPNGFILE): $(LOGOSVGFILE)
cat $< | sed 's/viewBox="0 0 504 252"/viewBox="$(LOGOBANNERVIEWBOX)"/' | HOME=/var/tmp $(INKSCAPE) --export-height=$(LOGOBANNERHEIGHT) --export-type=png --export-filename=$@ --pipe
$(LOGOICONPNGFILE): $(LOGOSVGFILE)
cat $< | sed 's/viewBox="0 0 504 252"/viewBox="$(LOGOICONVIEWBOX)"/' | HOME=/var/tmp $(INKSCAPE) --export-height=$(LOGOICONHEIGHT) --export-type=png --export-filename=$@ --pipe
$(LOGOFAVICONPNGFILE): $(LOGOSVGFILE)
cat $< | sed 's/viewBox="0 0 504 252"/viewBox="$(LOGOFAVICONVIEWBOX)"/' | HOME=/var/tmp $(INKSCAPE) --export-height=$(LOGOFAVICONHEIGHT) --export-type=png --export-filename=$@ --pipe
.PHONY: clean
clean:
rm -rf $(DOTPNGFILES)
rm -rf $(ICONPNGFILES)
rm -rf $(LOGOBANNERPNGFILE) $(LOGOICONPNGFILE) $(LOGOFAVICONPNGFILE)
././@PaxHeader 0000000 0000000 0000000 00000000026 00000000000 010213 x ustar 00 22 mtime=1745253811.0
dnsviz-0.11.1/doc/dnsviz-graph.html 0000644 0001750 0001750 00000065437 15001472663 016233 0 ustar 00casey casey
DNSViz

| Nodes in DNSViz are clustered by the
zone to which the represented information belongs.
Each zone is labeled with the name of the zone origin and the time at
which the zone was last analyzed. |
 | Thick lines between zones denote
delegations of namespace from one zone to another, as
indicated by the presence of NS (name server) resource records (RRs)
for the delegated namespace. In this example, the black, solid
line indicates a standard, insecure delegation (i.e.,
sans DNSSEC). Other possible delegation statuses are described in the
following entries. |
 | If the designated name servers for a
zone cannot not be properly resolved or if the servers do not properly
respond to queries, then the delegation is considered
lame and is represented by a dashed, yellow
line. |
 | If the delegation is
incomplete, as indicated by the presence of NS records
in the zone itself but not in its parent zone, then the delegation is
represented by a dashed, yellow line. |
 | If the delegation is
secure by DNSSEC standards, then the delegation
is represented by a solid, blue line. |
 | If the delegation is
bogus by DNSSEC standards, then the delegation
is represented by a dashed, red line. |
 | Resource record sets
(RRsets) returned in the response (usually in the answer
section) are represented as rectangular nodes with rounded corners.
Among the most common record types are SOA (start of authority), A
(IPv4 address), AAAA (IPv6 address), MX (mail exchange), and CNAME
(canonical name). RRsets that are specific to DNSSEC, such as the
DNSKEY, DS, RRSIG, NSEC and
NSEC3 RR types, are represented as other node types, as specified
elsewhere in this guide. |
 | Aliases resulting from
CNAME RRs are represented by a black edge from one RRset (with the
alias name) to another (with the canonical
name). |
 | A DNAME RR is used to alias an entire
namespace into another. DNAME responses include synthesized CNAME RRs
for the aliasing directed by the DNAME RR. DNAME records are
shown in DNSViz with their respective CNAME records. A solid, blue
line between DNAME node and CNAME node indicates that the DNAME
expansion was valid. |
 | A solid, red line between DNAME node
and CNAME node indicates that the DNAME expansion was
invalid. |
 |
If the response to a query is a name error
(NXDOMAIN), this negative response is represented by a
rectangular node with diagonals drawn at each corner, and with a dashed
border, lighter in color. A node representing the SOA RR returned in
the negative response (if any) is also
included. |
 |
If the response to a query has a NOERROR status but
contains no answer data (NO DATA) for the type, this
negative response is represented by a rectangular node with rounded
corners, and with a dashed border, lighter in color. A node
representing the SOA RR returned in the negative response (if any) is
also included. |
 | DNSKEY RRs
include public key and meta information to enable resolvers to validate
signatures made by the corresponding private keys. In DNSViz,
each DNSKEY RR is represented as an elliptical node in the zone
to which it belongs. The DNSKEY RR for the example.com zone has algorithm
8 (RSA/SHA-256) and key tag 12345, both of are used to
identify the DNSKEY. Each DNSKEY node is decorated based on the
attributes of the corresponding DNSKEY RR, as described in the
following entries. |
 | A gray fill indicates that the
Secure Entry Point (SEP) bit is set in the
flags field of the DNSKEY RR. This bit is
typically used to designate a DNSKEY for usage as a key signing
key (KSK), a DNSKEY that is used to sign the DNSKEY RRset of
a zone, providing a secure entry point into a zone via DS RRs or a
trust anchor at the resolver. |
 | A thick border indicates
that the revoke bit is set in the
flags field of the DNSKEY RR. Resolvers which
implement the trust anchor rollover procedures documented in RFC 5011
recognize the revoke bit as a signal that the DNSKEY should no longer
be used as a trust anchor by the resolver. For a DNSKEY to be properly
revoked, it must also be self-signing (i.e., used to sign the DNSKEY
RRset), which proves that the revocation was made by a party that has
access to the private key. |
 | A double border
indicates that the DNSKEY has been designated as a trust
anchor. A trust anchor must be self-signing (i.e., used
to sign the DNSKEY RRset). |
| DS (delegation signer) RRs exist
in the parent of a signed zone to establish a SEP into the zone. Each
DS RR specifies an algorithm and key tag corresponding to a DNSKEY RR
in the signed zone and includes a cryptographic hash of that DNSKEY
RR. In DNSViz DS RRs with the same DNSKEY algorithm and key tag
are typically displayed as a single node since they usually correspond
to the same DNSKEY RR with different digest algorithms. The DS for
example.com has algorithm 8 and key tag
12345, and maps to the corresponding DNSKEY RR with digest algorithms 1
(SHA1) and 2 (SHA-256). In this example, the blue color of the
arrow pointing from DS to DNSKEY indicates that the digest contained in
each of the DS RRs is valid, and corresponds to an existing DNSKEY in
example.com. However, other circumstances
may exist, which are shown in the following entries. |
 | A solid red line from DS to
DNSKEY indicates that a DNSKEY exists matching the algorithm and key
tag of the DS RR, but the digest of the DNSKEY in the DS RR
does not match. |
 | A dashed gray line from
DS to a DNSKEY with a dashed gray border indicates that no
DNSKEY matching the algorithm and key tag of the DS RR
exists in the child zone. Extraneous DS RRs in a parent zone do
not, in and of themselves, constitute an error. For example, sometimes
they are deliberately pre-published before their corresponding DNSKEYs,
as part of a key rollover. However, for every DNSSEC
algorithm in the DS RRset for the child zone, a
matching DNSKEY must be used to sign the DNSKEY RRset in the child
zone, as per RFC 4035. |
 | A
special case of a DS with no matching DNSKEY is when the DS
matched a DNSKEY prior to its revocation, but the
ramifications are the same as if it didn't match any DNSKEY. The line
is simply drawn to help identify the cause of the otherwise
non-existent DNSKEY. In the example at the left the key tag of
the DS records isn't actually 54321; rather, 54321 is the new key tag
resulting from having set the revoke bit in the DNSKEY
RR. |
 | When the algorithm
and key tag of a DS RR match those of a DNSKEY RR, but the
digest algorithm is unknown or unsupported, then the line
between DS and DNSKEY is yellow. In the example at the left digest
algorithm 19 is unknown. |
 | When the use of a DS
corresponding to a DNSKEY is invalid, independent of the
correctness of its digest, the line between DS and DNSKEY is red and
dashed. An example scenario is when the DNSKEY has the revoke bit set,
which is disallowed by RFC 5011. |
 |
NSEC and NSEC3 RRs are
used within DNSSEC to prove the legitimacy of a negative response
(i.e., NXDOMAIN or NO DATA) using authenticated denial of
existence or hashed authenticated denial of
existence, respectively. In DNSViz the NSEC or NSEC3
RR(s) returned by a server to authenticate a negative response are
represented by a rectangular node with several compartments. The
bottom compartment is labeled with either NSEC or NSEC3, depending on
the type of record. Each compartment on the top row represents an
NSEC or NSEC3 record in the set--there will be between one and
three.
An edge extends from the NSEC or NSEC3 node to the
corresponding negative response, as in the figure to the left. If the
edge is solid blue, then the NSEC or NSEC3 RRs returned prove the
validity of the negative response. |
 | A special case of NSEC/NSEC3 RRs is
that in which they serve to prove the non-existence of Delegation
Signer (DS) records. The proof of absence of DS records constitutes an
insecure delegation, in which any trust at the parent
zone does not propagate to the child zone. The NSEC/NSEC3 proof
involving DS records is graphically represented with an edge from the
NSEC/NSEC3 node to the box representing the child zone. |
 | The opt-out flag is set
in NSEC3 RRs to indicate that their presence is only sufficient to
prove insecure delegations (i.e., lack of DS records) and nothing more.
Thus, a name error (NXDOMAIN) response, for example, cannot be securely
proven when the NSEC3 uses opt-out. NSEC3 records with the
opt-out flag set are colored with a gray background. |
 | A solid
red edge from the NSEC or NSEC3 node to the negative response indicates
that the NSEC or NSEC3 RRs included in in the response do not prove the
validity of the negative response. |
 | Each RRSIG RR contains
the cryptographic signature made by a DNSKEY over an RRset. Using the
DNSKEY with the same algorithm and key tag as the RRSIG, the RRset
which was signed, and the RRSIG itself, a resolver may determine the
correctness of the signature and authenticate the RRset. In
DNSViz RRSIGs are represented as directed edges from the DNSKEY that
made the signature to the RRset that was signed. The edges in the
example denote RRSIGs made by the example.com DNSKEY with algorithm 8 and key tag
12345, which cover the example.com/A RRset. |
 | A solid red edge
indicates an RRSIG in which the cryptographic signature is
invalid. |
 | A solid purple edge
indicates that an RRSIG is invalid because it is outside its
validity period, as defined by the
inception and expiration date fields
in the RRSIG RR. |
 | A dashed gray line stemming from a DNSKEY
with a dashed gray border indicates that no DNSKEY matching the
algorithm and key tag of the RRSIG RR could be found in the
DNSKEY RRset (or the DNSKEY RRset could not be
retrieved). Extraneous RRSIG RRs do not, in and of themselves,
constitute an error. For example, sometimes they are deliberately
pre-published before their corresponding DNSKEYs, as part of an
algorithm rollover. However, every RRset must be covered by RRSIGs for
every algorithm in the DNSKEY RRset, as per RFC
4035. |
 | A special case of an RRSIG with no
matching DNSKEY is when the RRSIG matched a DNSKEY prior to its
revocation, but the ramifications are the same as if it
didn't match any DNSKEY. The line is simply drawn to help identify the
cause of the otherwise non-existent DNSKEY. In the example at the
left the key tag of the RRSIG RR isn't actually 12345; rather, 12345 is
the new key tag resulting from having set the revoke bit in the DNSKEY
RR. |
 | When the algorithm and key tag of an RRSIG RR
match those of a DNSKEY RR, but the cryptographic algorithm
associated with the RRSIG is unknown or unsupported, then
the line stemming from the DNSKEY is yellow. In the example at the
left algorithm 22 is unknown. |
 | When an RRSIG is
invalid, independent of the correctness of its temporal
validity period and its cryptographic signature, the line stemming from
the DNSKEY is red and dashed. Example scenarios might be when the
DNSKEY has the revoke bit set or when the signer field
in the RRSIG RR does not match the name of the zone apex. Such
scenarios are disallowed by RFCs 5011 and 4035,
respectively. |
 | Just like other
RRsets, a DNSKEY RRset is signed as an RRset, which comprises all the
collective DNSKEY RRs at the zone apex. Because each DNSKEY RR is
represented as a node in DNSViz, a single RRSIG covering the DNSKEY
RRset is represented by edges drawn from the node representing the
signing DNSKEY to the nodes representing every DNSKEY RR in the
set. In the example at the left, the example.com/DNSKEY RRset is comprised of the three
DNSKEY nodes shown, and the blue edges going to each of them collectively
represent a single RRSIG corresponding to the key with algorithm 8 and
key tag 54321. |
 | In some DNSSEC
implementations, multiple DNSKEYs sign the DNSKEY RRset, even though
only a subset are designated to provide secure entry into the zone
(e.g., via matching DS records in the parent zone). While there is
nothing inherently wrong with this configuration, graphically
representing such scenarios can be visually complex because of the
cycles and redundancy created in the graph. |
 | In order to represent
trust propagation in a simplified fashion, eliminating graphic
redundancies, DNSViz exhibits the following behavior. For
every DNSKEY signing the DNSKEY RRset, a self-directed
edge is added to the node, indicating that the DNSKEY is
self-signing. Additionally, if the DNSKEY is
designated as a (SEP) into the zone, then edges are
drawn from its node to nodes representing all other DNSKEY RRs in the
DNSKEY RRset. If there is no true SEP, (e.g., no DS RRs in the
parent zone), then SEP(s) are inferred based on their signing role
(e.g., signing DNSKEY RRset or other RRsets) and properties (e.g., SEP
bit). |
 | Like the DNSKEY
RRset, a single DS RRset might be represented as several different
nodes. As such a single RRSIG covering the DS RRset is represented by
edges drawn from the node representing the signing DNSKEY to the nodes
representing every DS RR in the set. In the example at the left,
the example.com/DS RRset is comprised of
both DS nodes shown, and the blue edges going to both of them
collectively represent a single RRSIG corresponding to the key with
algorithm 8 and key tag 12345. |
 | Because an NSEC or
NSEC3 node represents one or more RRsets and at least one RRSIG per
RRset is anticipated, multiple RRSIG edges will be drawn from DNSKEY
to NSEC or NSEC3 nodes, each pointing to the respective compartment
corresponding to the NSEC or NSEC3 record. |
 | CDNSKEY and CDS records are
used by the child zone to signal to its parent the DS record(s) that
it desires to be published, per RFC 7344. The CDNSKEY and CDS RRsets
are represented as any other RRset (see RRsets);
that is, there is a single node per RRset, as opposed to a single node
per CDNSKEY or CDS record.
CDNSKEY and CDS RRsets are mapped to the DNSKEYs they correspond to
with a gray edge from the RRset to the DNSKEY node. |
 |
If the DNSKEY referenced does not exist, the DNSKEY node is
represented with a dashed gray border (see
DNSKEY RRs and
DS RRs). |
 | When the RRSIG covering an RRset has a
labels field with value greater than the number of labels in the name,
it is indicative that the resulting RRset was formed by a wildcard
expansion. The server must additionally include an NSEC or NSEC3 proof
that the name to which the wildcard is expanded does not
exist. DNSViz represents wildcards by displaying both the
wildcard RRset and the NSEC or NSEC3 proof. In the example at the left,
the RRset foobar.example.com resulted from
the wildcard expansion of *.example.com. |
 | Beginning at the DNSKEYs designated as
trust anchors, DNSViz traverses the nodes and edges in the graph to
classify each node as having one of three DNSSEC statuses, depending on
the status of the RRset which it represents: secure,
bogus, or insecure. In DNSViz, node
status is indicated by the color of the nodes (Note that there isn't
always a one-to-one mapping between node and RRset, but the node status
will be consistent among all nodes comprising an RRset. An example is
the DNSKEY nodes for a zone, which all have the same status even though
the DNSKEY RRset is split among different nodes). Nodes with blue
outline indicate that they are secure, that there is
an unbroken chain of trust from anchor to RRset. |
 | Nodes with red outline indicate that
they are bogus, that the chain of trust from an anchor
has been broken. |
 | Because the NSEC and
NSEC3 nodes often represent multiple NSEC or NSEC3 RRs, it is
possible that a proper subset of the RRs are secure, while others in
the set are not (e.g., missing or expired RRSIG). In this case, the
outline of the compartments representing secure NSEC or NSEC3 RRs
will be colored blue, while the others will be red. Because the
status of the collective set of NSEC and NSEC3 RRs is dependent on
the status of all the individual NSEC and NSEC3 RRs, the greater node
is only colored blue if all the compartments are colored
blue. |
 | Nodes with black outline indicate
that they are insecure, that no chain of trust exists;
if any anchors exist then an insecure delegation is demonstrated to
prove that no chain should exist from the anchors. This is equivalent
to DNS without DNSSEC. |
 | If one or more warnings are
detected with the data represented by a node in the graph, then a
warning icon is displayed in the node. |
 | Similarly, the warning icon is
displayed alongside edges whose represented data has
warnings. |
 | The warning icon is also
displayed within the cluster representing a zone if there are
zone-related warnings. |
 | If one or more errors (more
severe than warnings) are detected with the data represented by a node
in the graph, then an error icon is displayed in the
node. |
 | Similarly, the error icon is
displayed alongside edges whose represented data has
errors. |
 | The error icon is also displayed
within the cluster representing a zone if there are zone-related
errors. |
 | A warning icon with an italicized
label denotes a warning for a response that isn't represented
elsewhere in the graph, such as a referral with the authoritative
answer flag set. |
 | An error icon with an italicized
label denotes a response error, e.g., due to timeout, malformed response,
or invalid RCODE. |
././@PaxHeader 0000000 0000000 0000000 00000000034 00000000000 010212 x ustar 00 28 mtime=1745253948.3905313
dnsviz-0.11.1/doc/images/ 0000755 0001750 0001750 00000000000 15001473074 014154 5 ustar 00casey casey ././@PaxHeader 0000000 0000000 0000000 00000000026 00000000000 010213 x ustar 00 22 mtime=1745253811.0
dnsviz-0.11.1/doc/images/error.png 0000644 0001750 0001750 00000002141 15001472663 016014 0 ustar 00casey casey ‰PNG
IHDR 5¿7¶ sBIT|dˆ pHYs é éT’K tEXtSoftware www.inkscape.org›î< ÞIDATH‰”]hSgÇïÉÉñ$kÒ˜4¦IÚ$˜YÓ¤v›ÌJ„uØ)lŒ±•2:w3¢¦“é@ÝÍv3˜»q0Pƒ
'Þ¤c‚È”êè…Ȱ~ÁØðB:1Óœ÷cMkÒªÓÍç¼ç}Þÿïù?çáÀ\gV¬8~iÍšß?^¿þÅ'9g=nâÑTj¨”ɼÖ&îܯV«Ñ§
1 žÏd[BX «ÂáöäÔÔ'€xj³Ù}]™ÙµcÛ¬»yójµš*ƒèËåÞo.YiÍòPÈ]~þüW€ïC^èéù:
µˆT
kp%%JJVÕjå¶o_Ç¿´í‘C®›íËf_7€Ö½u+·7oÆ$H)ét»÷ìÙ#•JÅùÏžž‚‹9Z)ôÊ•ôŒìîf¼§OJ<)YY¯ç"·n½ý(7…]²dhY*õœçyHc0[¶055…RŠ_ïÞÅ.•RâZ–U˜˜øtïÞ½‘'‚}™Ì´¶¤”Ø7Ò^,’N§(‹Dvì@*…çy´Ž''<ÌÍ!Ç»º$#‘n)%Êuyft€R©@?n©Dpp©h-Š/¾·{÷îÜcAB ”JI¥ð¤$02‚ÕÞ@¹\&ÓÛÛ@¢ZE[²^')e`ÉéÓ_ò€‘^ éËå¾ aéyÓ6<<··zõjðùftœtšØÈR)””ä¯^}iÏÎåùmkrÝl¾³óÕÙÉ oÛ†ðûçöK¥…B¡¥¨t¥‚X¼OJB÷îù“ããG »9§ÅÚž\î§X[[Z)…¿X$¶kˆûE…ÃaÇaéÒ¥÷«t„ãðçÉ“ P«E—oÚôÛÏ.L.pòm4úJw4ÚïÕëH)‰µ jµùüÂßUzt”`¡€‚EÆXÉS§>¯T*¡ˆ‘O$k-©Á¡!ܾ¾bår™|>ϱcÇZÞÛfÙ¾}h@Abz:½~ýC߯8ÚÑñQ4˜YŸx¥² µæÆc¸råÊ‚ýĆ
,^»5£,R;ÆÆÆº ìƒx6«J)QJa|>þ:sáº`¦)¾Û¿ŸÉË—y+›å'0
Àì]φDêõ`üܹ/€7ÄñÎÎï—Åão*¥˜iY7Â4tCX¦y=ïù¶m{—†‡×Úñ`ðe¯áBÏž…i=wp¾x³¨irb€€”þ¶kרק§?sC¡wë¶2ÆÌ$XF”1à÷c Õ˜´æ™f'ÆaŒhn´í»g2¿ü;®8•H IEND®B`‚ ././@PaxHeader 0000000 0000000 0000000 00000000026 00000000000 010213 x ustar 00 22 mtime=1745253811.0
dnsviz-0.11.1/doc/images/logo-16x16.png 0000644 0001750 0001750 00000001117 15001472663 016410 0 ustar 00casey casey ‰PNG
IHDR óÿa sBIT|dˆ pHYs & |