1
0
mirror of https://github.com/samba-team/samba.git synced 2025-01-21 18:04:06 +03:00

traffic: load dns query from file and write stats to file

Signed-off-by: Joe Guo <joeg@catalyst.net.nz>
Reviewed-by: Andrew Bartlett <abartlet@samba.org>
Reviewed-by: Andreas Schneider <asn@samba.org>

Autobuild-User(master): Andrew Bartlett <abartlet@samba.org>
Autobuild-Date(master): Wed May  1 01:10:42 UTC 2019 on sn-devel-184
This commit is contained in:
Joe Guo 2019-03-26 17:48:39 +13:00 committed by Andrew Bartlett
parent 35e52ebdd6
commit 2ee72cc615
2 changed files with 72 additions and 13 deletions

View File

@ -28,6 +28,8 @@ import signal
from errno import ECHILD, ESRCH from errno import ECHILD, ESRCH
from collections import OrderedDict, Counter, defaultdict, namedtuple from collections import OrderedDict, Counter, defaultdict, namedtuple
from dns.resolver import query as dns_query
from samba.emulate import traffic_packets from samba.emulate import traffic_packets
from samba.samdb import SamDB from samba.samdb import SamDB
import ldb import ldb
@ -967,22 +969,56 @@ class DnsHammer(Conversation):
"""A lightweight conversation that generates a lot of dns:0 packets on """A lightweight conversation that generates a lot of dns:0 packets on
the fly""" the fly"""
def __init__(self, dns_rate, duration): def __init__(self, dns_rate, duration, query_file=None):
n = int(dns_rate * duration) n = int(dns_rate * duration)
self.times = [random.uniform(0, duration) for i in range(n)] self.times = [random.uniform(0, duration) for i in range(n)]
self.times.sort() self.times.sort()
self.rate = dns_rate self.rate = dns_rate
self.duration = duration self.duration = duration
self.start_time = 0 self.start_time = 0
self.msg = random_colour_print() self.query_choices = self._get_query_choices(query_file=query_file)
def __str__(self): def __str__(self):
return ("<DnsHammer %d packets over %.1fs (rate %.2f)>" % return ("<DnsHammer %d packets over %.1fs (rate %.2f)>" %
(len(self.times), self.duration, self.rate)) (len(self.times), self.duration, self.rate))
def _get_query_choices(self, query_file=None):
"""
Read dns query choices from a file, or return default
rname may contain format string like `{realm}`
realm can be fetched from context.realm
"""
if query_file:
with open(query_file, 'r') as f:
text = f.read()
choices = []
for line in text.splitlines():
line = line.strip()
if line and not line.startswith('#'):
args = line.split(',')
assert len(args) == 4
choices.append(args)
return choices
else:
return [
(0, '{realm}', 'A', 'yes'),
(1, '{realm}', 'NS', 'yes'),
(2, '*.{realm}', 'A', 'no'),
(3, '*.{realm}', 'NS', 'no'),
(10, '_msdcs.{realm}', 'A', 'yes'),
(11, '_msdcs.{realm}', 'NS', 'yes'),
(20, 'nx.realm.com', 'A', 'no'),
(21, 'nx.realm.com', 'NS', 'no'),
(22, '*.nx.realm.com', 'A', 'no'),
(23, '*.nx.realm.com', 'NS', 'no'),
]
def replay(self, context=None): def replay(self, context=None):
assert context
assert context.realm
start = time.time() start = time.time()
fn = traffic_packets.packet_dns_0
for t in self.times: for t in self.times:
now = time.time() - start now = time.time() - start
gap = t - now gap = t - now
@ -990,16 +1026,21 @@ class DnsHammer(Conversation):
if sleep_time > 0: if sleep_time > 0:
time.sleep(sleep_time) time.sleep(sleep_time)
opcode, rname, rtype, exist = random.choice(self.query_choices)
rname = rname.format(realm=context.realm)
success = True
packet_start = time.time() packet_start = time.time()
try: try:
fn(None, None, context) answers = dns_query(rname, rtype)
if exist == 'yes' and not len(answers):
# expect answers but didn't get, fail
success = False
except Exception:
success = False
finally:
end = time.time() end = time.time()
duration = end - packet_start duration = end - packet_start
print("%f\tDNS\tdns\t0\t%f\tTrue\t" % (end, duration)) print("%f\tDNS\tdns\t%s\t%f\t%s\t" % (end, opcode, duration, success))
except Exception as e:
end = time.time()
duration = end - packet_start
print("%f\tDNS\tdns\t0\t%f\tFalse\t%s" % (end, duration, e))
def ingest_summaries(files, dns_mode='count'): def ingest_summaries(files, dns_mode='count'):
@ -1516,17 +1557,30 @@ def replay_seq_in_fork(cs, start, context, account, client_id, server_id=1):
os._exit(status) os._exit(status)
def dnshammer_in_fork(dns_rate, duration): def dnshammer_in_fork(dns_rate, duration, context, query_file=None):
sys.stdout.flush() sys.stdout.flush()
sys.stderr.flush() sys.stderr.flush()
pid = os.fork() pid = os.fork()
if pid != 0: if pid != 0:
return pid return pid
sys.stdin.close()
os.close(0)
try:
sys.stdout.close()
os.close(1)
except IOError as e:
LOGGER.warn("stdout closing failed with %s" % e)
pass
filename = os.path.join(context.statsdir, 'stats-dns')
sys.stdout = open(filename, 'w')
try: try:
status = 0 status = 0
signal.signal(signal.SIGTERM, flushing_signal_handler) signal.signal(signal.SIGTERM, flushing_signal_handler)
hammer = DnsHammer(dns_rate, duration) hammer = DnsHammer(dns_rate, duration, query_file=query_file)
hammer.replay() hammer.replay(context=context)
except Exception: except Exception:
status = 1 status = 1
print(("EXCEPTION in child PID %d, the DNS hammer" % (os.getpid())), print(("EXCEPTION in child PID %d, the DNS hammer" % (os.getpid())),
@ -1544,6 +1598,7 @@ def replay(conversation_seq,
lp=None, lp=None,
accounts=None, accounts=None,
dns_rate=0, dns_rate=0,
dns_query_file=None,
duration=None, duration=None,
latency_timeout=1.0, latency_timeout=1.0,
stop_on_any_error=False, stop_on_any_error=False,
@ -1593,7 +1648,8 @@ def replay(conversation_seq,
children = {} children = {}
try: try:
if dns_rate: if dns_rate:
pid = dnshammer_in_fork(dns_rate, duration) pid = dnshammer_in_fork(dns_rate, duration, context,
query_file=dns_query_file)
children[pid] = 1 children[pid] = 1
for i, cs in enumerate(conversation_seq): for i, cs in enumerate(conversation_seq):

View File

@ -50,6 +50,8 @@ def main():
parser.add_option('--dns-rate', type='float', default=0, parser.add_option('--dns-rate', type='float', default=0,
help='fire extra DNS packets at this rate') help='fire extra DNS packets at this rate')
parser.add_option('--dns-query-file', dest="dns_query_file",
help='A file contains DNS query list')
parser.add_option('-B', '--badpassword-frequency', parser.add_option('-B', '--badpassword-frequency',
type='float', default=0.0, type='float', default=0.0,
help='frequency of connections with bad passwords') help='frequency of connections with bad passwords')
@ -403,6 +405,7 @@ def main():
creds=creds, creds=creds,
accounts=accounts, accounts=accounts,
dns_rate=opts.dns_rate, dns_rate=opts.dns_rate,
dns_query_file=opts.dns_query_file,
duration=opts.duration, duration=opts.duration,
latency_timeout=opts.latency_timeout, latency_timeout=opts.latency_timeout,
badpassword_frequency=opts.badpassword_frequency, badpassword_frequency=opts.badpassword_frequency,