Compare commits
29 Commits
Author | SHA1 | Date | |
---|---|---|---|
c025a0894c
|
|||
a820d11e0e
|
|||
d8b9de5fcc
|
|||
d79f5821c5
|
|||
f74b311170
|
|||
acd8602891
|
|||
403a583942
|
|||
8725ce0aeb
|
|||
c45d408be1 | |||
8a1b74fe0f
|
|||
22ef5331af
|
|||
efeccef2aa
|
|||
4092e4e2cb | |||
db90716837
|
|||
24adbab4aa
|
|||
76a24b10f2
|
|||
2609fdd758
|
|||
440a9f4287
|
|||
4c2d9d51e1
|
|||
920b0a8952
|
|||
575113ed69
|
|||
0164eae199
|
|||
c7a602ae4e
|
|||
d0db0c62aa
|
|||
1d373df954
|
|||
895c80b5bf
|
|||
13751fed51
|
|||
a1ee92d8f2
|
|||
c745b96e08
|
7
.gitmodules
vendored
7
.gitmodules
vendored
@ -1,7 +1,6 @@
|
|||||||
[submodule "dnspython"]
|
|
||||||
path = dnspython
|
|
||||||
url = https://github.com/farrokhi/dnspython.git
|
|
||||||
branch = python3
|
|
||||||
[submodule "cymruwhois"]
|
[submodule "cymruwhois"]
|
||||||
path = cymruwhois
|
path = cymruwhois
|
||||||
url = https://github.com/JustinAzoff/python-cymruwhois.git
|
url = https://github.com/JustinAzoff/python-cymruwhois.git
|
||||||
|
[submodule "dnspython-orig"]
|
||||||
|
path = dnspython
|
||||||
|
url = https://github.com/rthalley/dnspython/
|
||||||
|
@ -1,5 +1,10 @@
|
|||||||
language: python
|
language: python
|
||||||
python: "3.4"
|
python:
|
||||||
|
- "3.3"
|
||||||
|
- "3.4"
|
||||||
|
- "3.5"
|
||||||
|
- "3.5-dev" # 3.5 development branch
|
||||||
|
- "nightly" # currently points to 3.6-dev
|
||||||
install: pip install --process-dependency-links dnsdiag
|
install: pip install --process-dependency-links dnsdiag
|
||||||
script: nosetests dnstraceroute.py
|
script: nosetests dnstraceroute.py
|
||||||
|
|
||||||
|
30
README.md
30
README.md
@ -35,6 +35,10 @@ submodule update --init` and project directory to pull the required code.
|
|||||||
|
|
||||||
# installation
|
# installation
|
||||||
|
|
||||||
|
There are several ways that you can use this toolset. However using the sourcecode is always recommended.
|
||||||
|
|
||||||
|
## From Source Code
|
||||||
|
|
||||||
1. You can checkout this git repo and its submodules
|
1. You can checkout this git repo and its submodules
|
||||||
|
|
||||||
```
|
```
|
||||||
@ -49,6 +53,10 @@ git submodule update --init
|
|||||||
pip3 install --process-dependency-links dnsdiag
|
pip3 install --process-dependency-links dnsdiag
|
||||||
```
|
```
|
||||||
|
|
||||||
|
## From Binary
|
||||||
|
|
||||||
|
From time to time, binary version will be released for Windows, Mac OS X and Linux platforms. You can grab the latest release from [releases page](https://github.com/farrokhi/dnsdiag/releases).
|
||||||
|
|
||||||
# dnsping
|
# dnsping
|
||||||
dnsping pings a DNS resolver by sending an arbitrary DNS query for given number
|
dnsping pings a DNS resolver by sending an arbitrary DNS query for given number
|
||||||
of times:
|
of times:
|
||||||
@ -99,17 +107,17 @@ dnseval is a bulk ping utility that sends an arbitrary DNS query to a give list
|
|||||||
of DNS servers. This script is meant for comparing response time of multiple
|
of DNS servers. This script is meant for comparing response time of multiple
|
||||||
DNS servers at once:
|
DNS servers at once:
|
||||||
```
|
```
|
||||||
% ./dnseval.py wikipedia.org
|
% ./dnseval.py -f public-v4.txt -c3 ripe.net
|
||||||
server avg(ms) min(ms) max(ms) stddev(ms) lost(%)
|
server avg(ms) min(ms) max(ms) stddev(ms) lost(%) flags
|
||||||
--------------------------------------------------------------------------
|
----------------------------------------------------------------------------------
|
||||||
4.2.2.1 151.067 131.270 221.742 28.643 %10
|
8.8.8.8 210.225 109.864 407.420 170.785 %0 QR RD RA
|
||||||
4.2.2.2 142.175 132.921 178.133 13.348 %0
|
8.8.4.4 107.850 93.134 120.578 13.830 %0 QR RD RA
|
||||||
64.6.64.6 133.047 109.145 162.938 20.609 %0
|
ns.ripe.net 118.911 114.874 123.389 4.275 %0 QR AA RD
|
||||||
64.6.65.6 377.270 97.669 661.471 172.717 %0
|
4.2.2.1 104.380 102.449 106.588 2.083 %0 QR RD RA
|
||||||
8.8.4.4 389.048 294.581 511.134 67.953 %0
|
4.2.2.2 131.056 99.143 193.711 54.264 %0 QR RD RA
|
||||||
8.8.8.8 0.000 0.000 0.000 0.000 %100
|
4.2.2.3 98.956 97.463 100.310 1.429 %0 QR RD RA
|
||||||
208.67.222.222 179.068 135.975 258.582 50.681 %0
|
4.2.2.4 223.173 97.418 463.728 208.398 %0 QR RD RA
|
||||||
208.67.220.220 137.817 135.822 140.113 1.504 %0
|
4.2.2.5 104.290 97.264 117.878 11.770 %0 QR RD RA
|
||||||
```
|
```
|
||||||
|
|
||||||
### Author
|
### Author
|
||||||
|
96
dnseval.py
96
dnseval.py
@ -37,7 +37,7 @@ from statistics import stdev
|
|||||||
import dns.rdatatype
|
import dns.rdatatype
|
||||||
import dns.resolver
|
import dns.resolver
|
||||||
|
|
||||||
__VERSION__ = 1.0
|
__VERSION__ = 1.4
|
||||||
__PROGNAME__ = os.path.basename(sys.argv[0])
|
__PROGNAME__ = os.path.basename(sys.argv[0])
|
||||||
shutdown = False
|
shutdown = False
|
||||||
|
|
||||||
@ -69,18 +69,66 @@ def maxlen(names):
|
|||||||
return len(sn[-1])
|
return len(sn[-1])
|
||||||
|
|
||||||
|
|
||||||
|
def _order_flags(table):
|
||||||
|
return sorted(table.items(), reverse=True)
|
||||||
|
|
||||||
|
|
||||||
|
def flags_to_text(flags):
|
||||||
|
# Standard DNS flags
|
||||||
|
|
||||||
|
QR = 0x8000
|
||||||
|
AA = 0x0400
|
||||||
|
TC = 0x0200
|
||||||
|
RD = 0x0100
|
||||||
|
RA = 0x0080
|
||||||
|
AD = 0x0020
|
||||||
|
CD = 0x0010
|
||||||
|
|
||||||
|
# EDNS flags
|
||||||
|
|
||||||
|
DO = 0x8000
|
||||||
|
|
||||||
|
_by_text = {
|
||||||
|
'QR': QR,
|
||||||
|
'AA': AA,
|
||||||
|
'TC': TC,
|
||||||
|
'RD': RD,
|
||||||
|
'RA': RA,
|
||||||
|
'AD': AD,
|
||||||
|
'CD': CD
|
||||||
|
}
|
||||||
|
|
||||||
|
_by_value = dict([(y, x) for x, y in _by_text.items()])
|
||||||
|
_flags_order = _order_flags(_by_value)
|
||||||
|
|
||||||
|
_by_value = dict([(y, x) for x, y in _by_text.items()])
|
||||||
|
|
||||||
|
order = sorted(_by_value.items(), reverse=True)
|
||||||
|
text_flags = []
|
||||||
|
for k, v in order:
|
||||||
|
if flags & k != 0:
|
||||||
|
text_flags.append(v)
|
||||||
|
else:
|
||||||
|
text_flags.append('--')
|
||||||
|
|
||||||
|
return ' '.join(text_flags)
|
||||||
|
|
||||||
|
|
||||||
def dnsping(host, server, dnsrecord, timeout, count):
|
def dnsping(host, server, dnsrecord, timeout, count):
|
||||||
resolver = dns.resolver.Resolver()
|
resolver = dns.resolver.Resolver()
|
||||||
resolver.nameservers = [server]
|
resolver.nameservers = [server]
|
||||||
resolver.timeout = timeout
|
resolver.timeout = timeout
|
||||||
resolver.lifetime = timeout
|
resolver.lifetime = timeout
|
||||||
resolver.retry_servfail = 0
|
resolver.retry_servfail = 0
|
||||||
|
flags = 0
|
||||||
|
answers = None
|
||||||
|
resolver.use_edns(edns=True, payload=0, ednsflags=8)
|
||||||
|
|
||||||
response_time = []
|
response_times = []
|
||||||
i = 0
|
i = 0
|
||||||
|
|
||||||
for i in range(count):
|
for i in range(count):
|
||||||
if shutdown:
|
if shutdown: # user pressed CTRL+C
|
||||||
break
|
break
|
||||||
try:
|
try:
|
||||||
stime = time.time()
|
stime = time.time()
|
||||||
@ -92,18 +140,18 @@ def dnsping(host, server, dnsrecord, timeout, count):
|
|||||||
pass
|
pass
|
||||||
else:
|
else:
|
||||||
elapsed = (etime - stime) * 1000 # convert to milliseconds
|
elapsed = (etime - stime) * 1000 # convert to milliseconds
|
||||||
response_time.append(elapsed)
|
response_times.append(elapsed)
|
||||||
|
|
||||||
r_sent = i + 1
|
r_sent = i + 1
|
||||||
r_received = len(response_time)
|
r_received = len(response_times)
|
||||||
r_lost = r_sent - r_received
|
r_lost = r_sent - r_received
|
||||||
r_lost_percent = (100 * r_lost) / r_sent
|
r_lost_percent = (100 * r_lost) / r_sent
|
||||||
if response_time:
|
if response_times:
|
||||||
r_min = min(response_time)
|
r_min = min(response_times)
|
||||||
r_max = max(response_time)
|
r_max = max(response_times)
|
||||||
r_avg = sum(response_time) / r_received
|
r_avg = sum(response_times) / r_received
|
||||||
if len(response_time) > 1:
|
if len(response_times) > 1:
|
||||||
r_stddev = stdev(response_time)
|
r_stddev = stdev(response_times)
|
||||||
else:
|
else:
|
||||||
r_stddev = 0
|
r_stddev = 0
|
||||||
else:
|
else:
|
||||||
@ -112,19 +160,23 @@ def dnsping(host, server, dnsrecord, timeout, count):
|
|||||||
r_avg = 0
|
r_avg = 0
|
||||||
r_stddev = 0
|
r_stddev = 0
|
||||||
|
|
||||||
return (server, r_avg, r_min, r_max, r_stddev, r_lost_percent)
|
if answers:
|
||||||
|
flags = answers.response.flags
|
||||||
|
|
||||||
|
return server, r_avg, r_min, r_max, r_stddev, r_lost_percent, flags
|
||||||
|
|
||||||
|
|
||||||
def main():
|
def main():
|
||||||
try:
|
try:
|
||||||
signal.signal(signal.SIGTSTP, signal.SIG_IGN) # ignore CTRL+Z
|
signal.signal(signal.SIGTSTP, signal.SIG_IGN) # ignore CTRL+Z
|
||||||
signal.signal(signal.SIGINT, signal_handler) # ignore CTRL+C
|
signal.signal(signal.SIGINT, signal_handler) # catch CTRL+C
|
||||||
except AttributeError: # Some systems may not support all signals
|
except AttributeError: # Some systems (e.g. Windows) may not support all signals
|
||||||
pass
|
pass
|
||||||
|
|
||||||
if len(sys.argv) == 1:
|
if len(sys.argv) == 1:
|
||||||
usage()
|
usage()
|
||||||
|
|
||||||
|
# defaults
|
||||||
dnsrecord = 'A'
|
dnsrecord = 'A'
|
||||||
count = 10
|
count = 10
|
||||||
waittime = 5
|
waittime = 5
|
||||||
@ -172,10 +224,13 @@ def main():
|
|||||||
f = [name.strip() for name in f]
|
f = [name.strip() for name in f]
|
||||||
width = maxlen(f)
|
width = maxlen(f)
|
||||||
blanks = (width - 5) * ' '
|
blanks = (width - 5) * ' '
|
||||||
print('server ', blanks, ' avg(ms) min(ms) max(ms) stddev(ms) lost(%)')
|
print('server ', blanks, ' avg(ms) min(ms) max(ms) stddev(ms) lost(%) flags')
|
||||||
print((60 + width) * '-')
|
print((84 + width) * '-')
|
||||||
for server in f:
|
for server in f:
|
||||||
# check if we have a valid dns server address
|
# check if we have a valid dns server address
|
||||||
|
if server.lstrip() == '': # deal with empty lines
|
||||||
|
continue
|
||||||
|
server = server.replace(' ', '')
|
||||||
try:
|
try:
|
||||||
ipaddress.ip_address(server)
|
ipaddress.ip_address(server)
|
||||||
except ValueError: # so it is not a valid IPv4 or IPv6 address, so try to resolve host name
|
except ValueError: # so it is not a valid IPv4 or IPv6 address, so try to resolve host name
|
||||||
@ -184,17 +239,20 @@ def main():
|
|||||||
except OSError:
|
except OSError:
|
||||||
print('Error: cannot resolve hostname:', server)
|
print('Error: cannot resolve hostname:', server)
|
||||||
s = None
|
s = None
|
||||||
|
except:
|
||||||
|
pass
|
||||||
else:
|
else:
|
||||||
s = server
|
s = server
|
||||||
|
|
||||||
if not s:
|
if not s:
|
||||||
continue
|
continue
|
||||||
(s, r_avg, r_min, r_max, r_stddev, r_lost_percent) = dnsping(hostname, s, dnsrecord, waittime,
|
(s, r_avg, r_min, r_max, r_stddev, r_lost_percent, flags) = dnsping(hostname, s, dnsrecord, waittime,
|
||||||
count)
|
count)
|
||||||
|
|
||||||
s = server.ljust(width + 1)
|
s = server.ljust(width + 1)
|
||||||
print("%s %-8.3f %-8.3f %-8.3f %-8.3f %%%d" % (
|
text_flags = flags_to_text(flags)
|
||||||
s, r_avg, r_min, r_max, r_stddev, r_lost_percent), flush=True)
|
print("%s %-8.3f %-8.3f %-8.3f %-8.3f %%%-3d %25s" % (
|
||||||
|
s, r_avg, r_min, r_max, r_stddev, r_lost_percent, text_flags), flush=True)
|
||||||
|
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
print('error: %s' % e)
|
print('error: %s' % e)
|
||||||
|
11
dnsping.py
11
dnsping.py
@ -34,10 +34,11 @@ import sys
|
|||||||
import time
|
import time
|
||||||
from statistics import stdev
|
from statistics import stdev
|
||||||
|
|
||||||
|
import dns.flags
|
||||||
import dns.rdatatype
|
import dns.rdatatype
|
||||||
import dns.resolver
|
import dns.resolver
|
||||||
|
|
||||||
__VERSION__ = 1.1
|
__VERSION__ = 1.4
|
||||||
__PROGNAME__ = os.path.basename(sys.argv[0])
|
__PROGNAME__ = os.path.basename(sys.argv[0])
|
||||||
shutdown = False
|
shutdown = False
|
||||||
|
|
||||||
@ -95,8 +96,8 @@ def main():
|
|||||||
|
|
||||||
try:
|
try:
|
||||||
opts, args = getopt.getopt(sys.argv[1:], "qhc:s:t:w:vp:P:S:T46",
|
opts, args = getopt.getopt(sys.argv[1:], "qhc:s:t:w:vp:P:S:T46",
|
||||||
["help", "output=", "count=", "server=", "quiet", "type=", "wait=", "verbose",
|
["help", "count=", "server=", "quiet", "type=", "wait=", "verbose",
|
||||||
"port", "dstport=", "srcip=", "tcp", "ipv4", "ipv6"])
|
"port=", "srcip=", "tcp", "ipv4", "ipv6", "srcport="])
|
||||||
except getopt.GetoptError as err:
|
except getopt.GetoptError as err:
|
||||||
# print help information and exit:
|
# print help information and exit:
|
||||||
print(err) # will print something like "option -a not recognized"
|
print(err) # will print something like "option -a not recognized"
|
||||||
@ -167,7 +168,8 @@ def main():
|
|||||||
break
|
break
|
||||||
try:
|
try:
|
||||||
stime = time.time()
|
stime = time.time()
|
||||||
answers = resolver.query(hostname, dnsrecord, source_port=src_port, source=src_ip, tcp=use_tcp, af=af)
|
answers = resolver.query(hostname, dnsrecord, source_port=src_port, source=src_ip, tcp=use_tcp,
|
||||||
|
raise_on_no_answer=False)
|
||||||
etime = time.time()
|
etime = time.time()
|
||||||
except dns.resolver.NoNameservers as e:
|
except dns.resolver.NoNameservers as e:
|
||||||
if not quiet:
|
if not quiet:
|
||||||
@ -198,6 +200,7 @@ def main():
|
|||||||
len(str(answers.rrset)), dnsserver, i, elapsed))
|
len(str(answers.rrset)), dnsserver, i, elapsed))
|
||||||
if verbose:
|
if verbose:
|
||||||
print(answers.rrset)
|
print(answers.rrset)
|
||||||
|
print("flags:", dns.flags.to_text(answers.response.flags))
|
||||||
|
|
||||||
r_sent = i + 1
|
r_sent = i + 1
|
||||||
r_received = len(response_time)
|
r_received = len(response_time)
|
||||||
|
Submodule dnspython updated: bc7445dcd5...a55e23fbc4
@ -35,13 +35,28 @@ import socket
|
|||||||
import sys
|
import sys
|
||||||
import time
|
import time
|
||||||
|
|
||||||
|
import dns.query
|
||||||
import dns.rdatatype
|
import dns.rdatatype
|
||||||
import dns.resolver
|
import dns.resolver
|
||||||
|
|
||||||
from cymruwhois import cymruwhois
|
from cymruwhois import cymruwhois
|
||||||
|
|
||||||
__author__ = 'Babak Farrokhi (babak@farrokhi.net)'
|
__author__ = 'Babak Farrokhi (babak@farrokhi.net)'
|
||||||
__license__ = 'BSD'
|
__license__ = 'BSD'
|
||||||
__version__ = 1.3
|
__version__ = 1.4
|
||||||
|
_ttl = None
|
||||||
|
quiet = False
|
||||||
|
|
||||||
|
|
||||||
|
class CustomSocket(socket.socket):
|
||||||
|
def __init__(self, *args, **kwargs):
|
||||||
|
super(CustomSocket, self).__init__(*args, **kwargs)
|
||||||
|
|
||||||
|
def sendto(self, *args, **kwargs):
|
||||||
|
global _ttl
|
||||||
|
if _ttl:
|
||||||
|
self.setsockopt(socket.SOL_IP, socket.IP_TTL, _ttl)
|
||||||
|
super(CustomSocket, self).sendto(*args, **kwargs)
|
||||||
|
|
||||||
|
|
||||||
def test_import():
|
def test_import():
|
||||||
@ -79,14 +94,14 @@ def whoisrecord(ip):
|
|||||||
currenttime = time.time()
|
currenttime = time.time()
|
||||||
ts = currenttime
|
ts = currenttime
|
||||||
if ip in whois:
|
if ip in whois:
|
||||||
ASN, ts = whois[ip]
|
asn, ts = whois[ip]
|
||||||
else:
|
else:
|
||||||
ts = 0
|
ts = 0
|
||||||
if ((currenttime - ts) > 36000):
|
if (currenttime - ts) > 36000:
|
||||||
c = cymruwhois.Client()
|
c = cymruwhois.Client()
|
||||||
ASN = c.lookup(ip)
|
asn = c.lookup(ip)
|
||||||
whois[ip] = (ASN, currenttime)
|
whois[ip] = (asn, currenttime)
|
||||||
return ASN
|
return asn
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
return e
|
return e
|
||||||
|
|
||||||
@ -153,15 +168,20 @@ def expert_report(trace_path, color_mode):
|
|||||||
print(" %s[*]%s public DNS server is next to a reserved IP address (possible hijacking)" % (color.R, color.N))
|
print(" %s[*]%s public DNS server is next to a reserved IP address (possible hijacking)" % (color.R, color.N))
|
||||||
return
|
return
|
||||||
|
|
||||||
## no expert info available
|
# no expert info available
|
||||||
print(" %s[*]%s No expert hint available for this trace" % (color.G, color.N))
|
print(" %s[*]%s No expert hint available for this trace" % (color.G, color.N))
|
||||||
|
|
||||||
|
|
||||||
def ping(resolver, hostname, dnsrecord, ttl):
|
def ping(resolver, hostname, dnsrecord, ttl):
|
||||||
|
global _ttl
|
||||||
|
|
||||||
reached = False
|
reached = False
|
||||||
|
|
||||||
|
dns.query.socket_factory = CustomSocket
|
||||||
|
_ttl = ttl
|
||||||
|
|
||||||
try:
|
try:
|
||||||
resolver.query(hostname, dnsrecord, ipttl=ttl)
|
resolver.query(hostname, dnsrecord)
|
||||||
|
|
||||||
except dns.resolver.NoNameservers as e:
|
except dns.resolver.NoNameservers as e:
|
||||||
if not quiet:
|
if not quiet:
|
||||||
@ -203,7 +223,6 @@ def main():
|
|||||||
dnsrecord = 'A'
|
dnsrecord = 'A'
|
||||||
count = 30
|
count = 30
|
||||||
timeout = 1
|
timeout = 1
|
||||||
quiet = False
|
|
||||||
dnsserver = dns.resolver.get_default_resolver().nameservers[0]
|
dnsserver = dns.resolver.get_default_resolver().nameservers[0]
|
||||||
dest_port = 53
|
dest_port = 53
|
||||||
hops = 0
|
hops = 0
|
||||||
@ -330,11 +349,11 @@ def main():
|
|||||||
if curr_addr:
|
if curr_addr:
|
||||||
as_name = ""
|
as_name = ""
|
||||||
if as_lookup:
|
if as_lookup:
|
||||||
ASN = whoisrecord(curr_addr)
|
asn = whoisrecord(curr_addr)
|
||||||
as_name = ''
|
as_name = ''
|
||||||
try:
|
try:
|
||||||
if ASN and ASN.asn != "NA":
|
if asn and asn.asn != "NA":
|
||||||
as_name = "[%s %s] " % (ASN.asn, ASN.owner)
|
as_name = "[%s %s] " % (asn.asn, asn.owner)
|
||||||
except AttributeError:
|
except AttributeError:
|
||||||
if shutdown:
|
if shutdown:
|
||||||
sys.exit(0)
|
sys.exit(0)
|
||||||
|
0
requirements.txt
Normal file
0
requirements.txt
Normal file
32
setup.py
32
setup.py
@ -1,29 +1,37 @@
|
|||||||
from setuptools import setup, find_packages
|
from setuptools import setup, find_packages
|
||||||
|
|
||||||
setup(
|
setup(
|
||||||
name = "dnsdiag",
|
name="dnsdiag",
|
||||||
version = "1.3.3",
|
version="1.3.5",
|
||||||
packages = find_packages(),
|
packages=find_packages(),
|
||||||
scripts = ['dnsping.py', 'dnstraceroute.py', 'dnseval.py'],
|
|
||||||
classifiers=[
|
classifiers=[
|
||||||
"Topic :: System :: Networking",
|
"Topic :: System :: Networking",
|
||||||
"Environment :: Console",
|
"Environment :: Console",
|
||||||
"Intended Audience :: Developers",
|
"Intended Audience :: Developers",
|
||||||
"License :: OSI Approved :: BSD License",
|
"License :: OSI Approved :: BSD License",
|
||||||
'Programming Language :: Python :: 3.4',
|
"Programming Language :: Python :: 3.4",
|
||||||
|
"Topic :: Internet :: Name Service (DNS)",
|
||||||
"Development Status :: 5 - Production/Stable",
|
"Development Status :: 5 - Production/Stable",
|
||||||
"Operating System :: OS Independent",
|
"Operating System :: OS Independent",
|
||||||
],
|
],
|
||||||
|
|
||||||
author = "Babak Farrokhi",
|
author="Babak Farrokhi",
|
||||||
author_email = "babak@farrokhi.net",
|
author_email="babak@farrokhi.net",
|
||||||
description = "DNS Diagnostics and measurement tools (ping, traceroute)",
|
description="DNS Diagnostics and measurement tools (ping, traceroute)",
|
||||||
long_description = """
|
long_description="""
|
||||||
DNSDiag provides a handful of tools to measure and diagnose your DNS
|
DNSDiag provides a handful of tools to measure and diagnose your DNS
|
||||||
performance and integrity. Using dnsping, dnstraceroute and dnseval tools
|
performance and integrity. Using dnsping, dnstraceroute and dnseval tools
|
||||||
you can measure your DNS response quality from delay and loss perspective
|
you can measure your DNS response quality from delay and loss perspective
|
||||||
as well as tracing the path your DNS query takes to get to DNS server.
|
as well as tracing the path your DNS query takes to get to DNS server.
|
||||||
""",
|
""",
|
||||||
license = "BSD",
|
license="BSD",
|
||||||
keywords = "dns traceroute ping",
|
keywords="dns traceroute ping",
|
||||||
url = "https://dnsdiag.org/",
|
url="https://dnsdiag.org/",
|
||||||
|
entry_points={
|
||||||
|
'console_scripts': [
|
||||||
|
'dnsping = dnsping:main',
|
||||||
|
'dnstraceroute = dnstraceroute:main',
|
||||||
|
'dnseval = dnseval:main',
|
||||||
|
]
|
||||||
|
}
|
||||||
)
|
)
|
||||||
|
Reference in New Issue
Block a user