mirror of
https://github.com/samba-team/samba.git
synced 2024-12-22 13:34:15 +03:00
scripts: Scripts to replay and generate samba traffic
Scripts to generate representative network traffic and replay this to a samba instance. For load testing, performance profiling and capacity planning. traffic_learner process a file generated by traffic_summary and generate a model that can be used by traffic_replay to generate samba network traffic. traffic_replay Replay a summary file generated by traffic_summary, or use a model created by traffic_learner to generate network traffic. Signed-off-by: Gary Lockyer <gary@catalyst.net.nz> Signed-off-by: Douglas Bagnall <douglas.bagnall@catalyst.net.nz> Reviewed-by: Douglas Bagnall <douglas.bagnall@catalyst.net.nz> Reviewed-by: Garming Sam <garming@catalyst.net.nz> Pair-programmed-with: Garming Sam <garming@catalyst.net.nz> Pair-programmed-with: Douglas Bagnall <douglas.bagnall@catalyst.net.nz> Pair-Programmed-With: Andrew Bartlett <abartlet@samba.org> Pair-Programmed-With: Tim Beale <timbeale@catalyst.net.nz>
This commit is contained in:
parent
74ebcf6dfc
commit
7057abcfcd
200
docs-xml/manpages/traffic_learner.7.xml
Normal file
200
docs-xml/manpages/traffic_learner.7.xml
Normal file
@ -0,0 +1,200 @@
|
||||
<?xml version="1.0" encoding="iso-8859-1"?>
|
||||
<!DOCTYPE refentry PUBLIC "-//Samba-Team//DTD DocBook V4.2-Based Variant V1.0//EN" "http://www.samba.org/samba/DTD/samba-doc">
|
||||
<refentry id="traffic_learner.7">
|
||||
|
||||
<refmeta>
|
||||
<refentrytitle>traffic_learner</refentrytitle>
|
||||
<manvolnum>7</manvolnum>
|
||||
<refmiscinfo class="source">Samba</refmiscinfo>
|
||||
<refmiscinfo class="manual">User Commands</refmiscinfo>
|
||||
<refmiscinfo class="version">4.7</refmiscinfo>
|
||||
</refmeta>
|
||||
|
||||
|
||||
<refnamediv>
|
||||
<refname>traffic_learner</refname>
|
||||
<refpurpose>Samba tool to assist with traffic generation.
|
||||
</refpurpose>
|
||||
</refnamediv>
|
||||
|
||||
<refsynopsisdiv>
|
||||
<cmdsynopsis>
|
||||
<command>traffic_learner</command>
|
||||
<arg choice="req">-o OUTPUT_FILE ...</arg>
|
||||
<arg choice="opt">-h</arg>
|
||||
<arg choice="opt">--dns-mode {inline|count}</arg>
|
||||
<arg choice="opt">SUMMARY_FILE</arg>
|
||||
<arg choice="opt">SUMMARY_FILE ...</arg>
|
||||
</cmdsynopsis>
|
||||
</refsynopsisdiv>
|
||||
|
||||
<refsect1>
|
||||
<title>DESCRIPTION</title>
|
||||
<para>This tool is part of the <citerefentry><refentrytitle>samba</refentrytitle>
|
||||
<manvolnum>7</manvolnum></citerefentry> suite.</para>
|
||||
|
||||
<para>This tool assists with generation of Samba traffic.
|
||||
It takes a traffic-summary file (produced by
|
||||
<command>traffic_summary.pl</command>) as input and produces a
|
||||
traffic-model file that can be used by <command>traffic_replay</command>
|
||||
for traffic generation.</para>
|
||||
|
||||
<para>The model file summarizes the types of traffic ('conversations'
|
||||
between a host and a Samba DC) that occur on a network. The model file
|
||||
describes the traffic in a way that allows it to be scaled so that
|
||||
either more (or fewer) packets get sent, and the packets can be sent at
|
||||
a faster (or slower) rate than that seen in the network.</para>
|
||||
</refsect1>
|
||||
|
||||
<refsect1>
|
||||
<title>OPTIONS</title>
|
||||
|
||||
<variablelist>
|
||||
|
||||
<varlistentry>
|
||||
<term>-h|--help</term>
|
||||
<listitem><para>
|
||||
Print a summary of command line options.
|
||||
</para></listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
<term>SUMMARY_FILE</term>
|
||||
<listitem><para>
|
||||
File containing a network traffic-summary. The traffic-summary file
|
||||
should be generated by <command>traffic_summary.pl</command> from a
|
||||
packet capture of actual network traffic.
|
||||
More than one file can be specified, in which case the traffic will
|
||||
be combined into a single traffic-model. If no SUMMARY_FILE is
|
||||
specified, this tool will read the traffic-summary from STDIN, i.e.
|
||||
you can pipe the output from traffic_summary.pl directly to this tool.
|
||||
</para></listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
<term>-o|--out OUTPUT_FILE</term>
|
||||
<listitem><para>
|
||||
The traffic-model that is produced will be written to this file. The
|
||||
OUTPUT_FILE can then be passed to <command>traffic_replay</command>
|
||||
to generate (and manipulate) Samba network traffic.
|
||||
</para></listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
<term>--dns-mode [inline|count]</term>
|
||||
<listitem><para>
|
||||
How DNS traffic should be handled by the model.
|
||||
</para></listitem>
|
||||
</varlistentry>
|
||||
|
||||
</variablelist>
|
||||
</refsect1>
|
||||
|
||||
<refsect1>
|
||||
<title>EXAMPLES</title>
|
||||
|
||||
<para>To take a traffic-summary file and produce a traffic-model
|
||||
file, use:</para>
|
||||
|
||||
<para><command>traffic_learner traffic-summary.txt
|
||||
-o traffic-model.txt</command></para>
|
||||
|
||||
<para>To generate a traffic-model from a packet capture, you can
|
||||
pipe the traffic summary to STDIN using:</para>
|
||||
|
||||
<para><command>tshark -r capture.pcapng -T pdml |
|
||||
traffic_summary.pl | traffic_learner -o traffic-model.txt</command></para>
|
||||
</refsect1>
|
||||
|
||||
<refsect1>
|
||||
<title>OUTPUT FILE FORMAT</title>
|
||||
|
||||
<para>The output model file describes a Markov model estimating the
|
||||
probability of a packet occurring given the last two packets.</para>
|
||||
|
||||
<para>The count of each continuation after a pair of
|
||||
successive packets is stored, and the ratios of these counts
|
||||
is used to calculate probabilities for the next packet.
|
||||
</para>
|
||||
|
||||
<para>The model is stored in JSON format, and also contains
|
||||
information about the conversation rate and DNS traffic
|
||||
rate.</para>
|
||||
|
||||
|
||||
<refsect2>
|
||||
<title>Example ngram listing</title>
|
||||
<para>The following listing shows a contrived example of a single ngram entry.
|
||||
</para>
|
||||
|
||||
<programlisting>
|
||||
"ngrams": {
|
||||
"ldap:0\tdcerpc:11": {
|
||||
"lsarpc:77": 1,
|
||||
"ldap:2": 370,
|
||||
"ldap:3": 62,
|
||||
"wait:3": 2,
|
||||
"-": 1
|
||||
}, <lineannotation>[...]</lineannotation>
|
||||
}
|
||||
</programlisting>
|
||||
<para> This counts the observed continuations after an ldap
|
||||
packet with opcode 0 (a bind) followed by a dcerpc packet with
|
||||
opcode 11 (also a bind). The most common next packet is
|
||||
"<code>ldap:2</code>" which is an unbind, so this is the most
|
||||
likely packet type to be selected in replay. At the other
|
||||
extreme, lsarpc opcode 77 (lookup names) has been seen only
|
||||
once, and it is unlikely but possible that this will be
|
||||
selected in replay.
|
||||
</para>
|
||||
<para> There are two special packet types here.
|
||||
"<code>wait:3</code>" refers to a temporary pause in the
|
||||
conversation, where the "<code>3</code>" pseudo-opcode indicates
|
||||
the length of the wait on an exponential scale. That is, a
|
||||
"<code>wait:4</code>" pause would be about 2.7 times longer that
|
||||
a "<code>wait:3</code>", which in turn would be similarly longer
|
||||
than a "<code>wait:2</code>".
|
||||
</para>
|
||||
|
||||
<para>The other special packet is "-", which represents the
|
||||
limit of the conversation. In the example, this indicates that
|
||||
one observed conversation ended after this particular ngram.
|
||||
This special opcode is also used at the beginning of
|
||||
conversations, which are indicated by the ngram "<code>-\t-</code>".
|
||||
</para>
|
||||
|
||||
|
||||
</refsect2>
|
||||
</refsect1>
|
||||
|
||||
<refsect1>
|
||||
<title>VERSION</title>
|
||||
|
||||
<para>This man page is complete for version 4 of the Samba
|
||||
suite.</para>
|
||||
</refsect1>
|
||||
|
||||
<refsect1>
|
||||
<title>SEE ALSO</title>
|
||||
<para>
|
||||
<citerefentry>
|
||||
<refentrytitle>traffic_replay</refentrytitle><manvolnum>7</manvolnum>
|
||||
</citerefentry>.
|
||||
</para>
|
||||
</refsect1>
|
||||
|
||||
<refsect1>
|
||||
<title>AUTHOR</title>
|
||||
|
||||
<para>The original Samba software and related utilities
|
||||
were created by Andrew Tridgell. Samba is now developed
|
||||
by the Samba Team as an Open Source project similar
|
||||
to the way the Linux kernel is developed.</para>
|
||||
|
||||
<para>The traffic_learner tool was developed by the Samba team at
|
||||
Catalyst IT Ltd.</para>
|
||||
|
||||
<para>The traffic_learner manpage was written by Tim Beale.</para>
|
||||
</refsect1>
|
||||
|
||||
</refentry>
|
566
docs-xml/manpages/traffic_replay.7.xml
Normal file
566
docs-xml/manpages/traffic_replay.7.xml
Normal file
@ -0,0 +1,566 @@
|
||||
<?xml version="1.0" encoding="iso-8859-1"?>
|
||||
<!DOCTYPE refentry PUBLIC "-//Samba-Team//DTD DocBook V4.2-Based Variant V1.0//EN" "http://www.samba.org/samba/DTD/samba-doc">
|
||||
<refentry id="traffic_replay.7">
|
||||
|
||||
<refmeta>
|
||||
<refentrytitle>traffic_replay</refentrytitle>
|
||||
<manvolnum>7</manvolnum>
|
||||
<refmiscinfo class="source">Samba</refmiscinfo>
|
||||
<refmiscinfo class="manual">User Commands</refmiscinfo>
|
||||
<refmiscinfo class="version">4.7</refmiscinfo>
|
||||
</refmeta>
|
||||
|
||||
|
||||
<refnamediv>
|
||||
<refname>traffic_replay</refname>
|
||||
<refpurpose>Samba traffic generation tool.
|
||||
</refpurpose>
|
||||
</refnamediv>
|
||||
|
||||
<refsynopsisdiv>
|
||||
<cmdsynopsis>
|
||||
<command>traffic_replay</command>
|
||||
<arg choice="opt">-F, --fixed-password <test-password></arg>
|
||||
<arg choice="opt">-S, --scale-traffic <scale by factor></arg>
|
||||
<arg choice="opt">-r, --replay-rate <scale by factor></arg>
|
||||
<arg choice="opt">-D, --duration <seconds></arg>
|
||||
<arg choice="opt">--traffic-summary <output file></arg>
|
||||
<arg choice="opt">-I, --instance-id <id></arg>
|
||||
<arg choice="opt">-K, --prefer-kerberos</arg>
|
||||
<arg choice="opt">-B, --badpassword-frequency <frequency></arg>
|
||||
<arg choice="opt">--dns-rate <rate></arg>
|
||||
<arg choice="opt">-t, --timing-data <file></arg>
|
||||
<arg choice="opt">-U, --username user</arg>
|
||||
<arg choice="opt">--password <password></arg>
|
||||
<arg choice="opt">-W --workgroup <workgroup></arg>
|
||||
<arg choice="opt">--realm <realm></arg>
|
||||
<arg choice="opt">-s, --config-file <file></arg>
|
||||
<arg choice="opt">-k, --kerberos <kerberos></arg>
|
||||
<arg choice="opt">--ipaddress <address></arg>
|
||||
<arg choice="opt">-P, --machine-pass</arg>
|
||||
<arg choice="opt">--option <option></arg>
|
||||
<arg choice="opt">-d, --debuglevel <debug level></arg>
|
||||
<arg choice="req">summary-file</arg>
|
||||
<arg choice="req">dns-hostname</arg>
|
||||
</cmdsynopsis>
|
||||
|
||||
<cmdsynopsis>
|
||||
<command>traffic_replay</command>
|
||||
<arg choice="opt">-G, --generate-users-only</arg>
|
||||
<arg choice="opt">-F, --fixed-password <test-password></arg>
|
||||
<arg choice="opt">-n, --number-of-users <total users></arg>
|
||||
<arg choice="opt">--number-of-groups <total groups></arg>
|
||||
<arg choice="opt">--average-groups-per-user <average number></arg>
|
||||
<arg choice="opt">--group-memberships <total memberships></arg>
|
||||
<arg choice="req">dns-hostname</arg>
|
||||
</cmdsynopsis>
|
||||
|
||||
<cmdsynopsis>
|
||||
<command>traffic_replay</command>
|
||||
<arg choice="req">-c|--clean-up</arg>
|
||||
<arg choice="req">dns-hostname</arg>
|
||||
</cmdsynopsis>
|
||||
|
||||
<cmdsynopsis>
|
||||
<command>traffic_replay</command>
|
||||
<arg choice="opt">-h, --help</arg>
|
||||
<arg choice="opt">-V, --version</arg>
|
||||
</cmdsynopsis>
|
||||
</refsynopsisdiv>
|
||||
|
||||
<refsect1>
|
||||
<title>DESCRIPTION</title>
|
||||
<para>This tool is part of the <citerefentry><refentrytitle>samba</refentrytitle>
|
||||
<manvolnum>7</manvolnum></citerefentry> suite.</para>
|
||||
<para>This tool generates traffic in order to measure the performance
|
||||
of a Samba DC, and to test how well Samba will scale as a network
|
||||
increases in size. It can simulate multiple different hosts making
|
||||
multiple different types of requests to a DC.</para>
|
||||
|
||||
<para>This tool is intended to run against a dedicated test DC (rather
|
||||
than a live DC that is handling real network traffic).</para>
|
||||
|
||||
<para>Note that a side-effect of running this tool is that user
|
||||
accounts will be created on the DC, in order to test various Samba
|
||||
operations. As creating accounts can be very time-consuming, these
|
||||
users will remain on the DC by default. To remove these accounts, use
|
||||
the --clean-up option.
|
||||
</para>
|
||||
</refsect1>
|
||||
|
||||
<refsect1>
|
||||
<title>OPTIONS</title>
|
||||
|
||||
<variablelist>
|
||||
|
||||
<varlistentry>
|
||||
<term>-h|--help</term>
|
||||
<listitem><para>
|
||||
Print a summary of command line options.
|
||||
</para></listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
<term>summary-file</term>
|
||||
<listitem><para>
|
||||
File containing the network traffic to replay. This should either be
|
||||
a traffic-summary (generated by <command>traffic_summary.pl</command>)
|
||||
or a traffic-model (generated by <command>traffic_learner</command>).
|
||||
Based on this file, this tool will generate 'conversations' which
|
||||
represent Samba activity between a network host and the DC.
|
||||
</para></listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
<term>dns-hostname</term>
|
||||
<listitem><para>
|
||||
The full DNS hostname of the DC that's being tested. The Samba activity
|
||||
in the summary-file will be replicated and directed at this DC. It's
|
||||
recommended that you use a dedicated DC for testing and don't try to run
|
||||
this tool against a DC that's processing live network traffic.
|
||||
</para></listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
<term>-F|--fixed-password <test-password></term>
|
||||
<listitem><para>
|
||||
Test users are created when this tool is run, so that actual Samba
|
||||
activity, such as authorizing users, can be mimicked. This option
|
||||
specifies the password that will be used for any test users that are
|
||||
created.</para>
|
||||
|
||||
<para>Note that any users created by this tool will remain on the DC
|
||||
until you run the --clean-up option. Therefore, the fixed-password
|
||||
option needs to be the same each time the tool is run, otherwise the
|
||||
test users won't authenticate correctly.
|
||||
</para></listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
<term>Traffic Model Options</term>
|
||||
<listitem><para>
|
||||
When the summary-file is a traffic-model (produced by
|
||||
<command>traffic_learner</command>), use these options to alter the
|
||||
traffic that gets generated.</para>
|
||||
<itemizedlist>
|
||||
<varlistentry>
|
||||
<term>-D|--duration <seconds></term>
|
||||
<listitem><para>
|
||||
Specifies the approximate duration in seconds to generate
|
||||
traffic for. The default is 60 seconds.
|
||||
</para></listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
<term>-r|--replay-rate <factor></term>
|
||||
<listitem><para>
|
||||
Replays the traffic faster by this factor. This option won't
|
||||
affect the number of conversations (which is based on the
|
||||
traffic model), but the rate at which the packets are sent will
|
||||
be increased.
|
||||
</para></listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
<term>-S|--scale-traffic <factor></term>
|
||||
<listitem><para>
|
||||
Increases the number of conversations by this factor. This
|
||||
option won't affect the rate at which packets get sent (which
|
||||
is still based on the traffic model), but it will mean more
|
||||
conversations get replayed.
|
||||
</para></listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
<term>--traffic-summary <output-file></term>
|
||||
<listitem><para>
|
||||
Instead of replaying a traffic-model, this option generates a
|
||||
traffic-summary file based on what traffic would be sent. Using
|
||||
a traffic-model allows you to scale the packet rate and number
|
||||
of packets sent. However, using a traffic-model introduces
|
||||
some randomness into the traffic generation. So running the
|
||||
same traffic_replay command multiple times using a model file
|
||||
may result in some differences in the actual traffic sent.
|
||||
However, running the same traffic_replay command multiple times
|
||||
with a traffic-summary file will always result in the same
|
||||
traffic being sent. </para>
|
||||
<para>
|
||||
For taking performance measurements over several test runs,
|
||||
it's recommended to use this option and replay the traffic from
|
||||
a traffic-summary file.
|
||||
</para></listitem>
|
||||
</varlistentry>
|
||||
</itemizedlist>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
<term>--generate-users-only</term>
|
||||
<listitem><para>Add extra user/groups on the DC to increase the DB
|
||||
size. By default, this tool automatically creates test users that map
|
||||
to the traffic conversations being generated. This option allows extra
|
||||
users to be created on top of this. Note that these extra users may
|
||||
not actually used for traffic generation - the traffic generation is
|
||||
still based on the number of conversations from the model/summary file.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
Generating a large number of users can take a long time, so it this
|
||||
option allows this to be done only once.</para>
|
||||
|
||||
<para>Note that the users created will remain on the DC until the
|
||||
tool is run with the --clean-up option. This means that it is best to
|
||||
only assign group memberships once, i.e. run --clean-up before
|
||||
assigning a different allocation of group memberships.</para>
|
||||
<itemizedlist>
|
||||
|
||||
<varlistentry>
|
||||
<term>-n|--number-of-users <total-users></term>
|
||||
<listitem><para>
|
||||
Specifies the total number of test users to create (excluding
|
||||
any machine accounts required for the traffic). Note that these
|
||||
extra users simply populate the DC's DB - the actual user
|
||||
traffic generated is still based on the summary-file.
|
||||
</para></listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
<term>--number-of-groups <total-groups></term>
|
||||
<listitem><para>
|
||||
Creates the specified number of groups, for assigning the test
|
||||
users to. Note that users are not automatically assigned to
|
||||
groups - use either --average-groups-per-user or
|
||||
--group-membership to do this.
|
||||
</para></listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
<term>--average-groups-per-user <average-groups></term>
|
||||
<listitem><para>
|
||||
Randomly assigns the test users to the test groups created.
|
||||
The group memberships are distributed so that the overall
|
||||
average groups that a user is member of matches this number.
|
||||
Some users will belong to more groups and some users will
|
||||
belong to fewer groups. This option is incompatible with
|
||||
the --group-membership option.
|
||||
</para></listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
<term>--group-memberships <total-memberships></term>
|
||||
<listitem><para>
|
||||
Randomly assigns the test users to the test groups created.
|
||||
The group memberships are distributed so that the total
|
||||
groups that a user is member of, across all users, matches
|
||||
this number. For example, with 100 users and 10 groups,
|
||||
--group-memberships=300 would assign a user to 3 groups
|
||||
on average. Some users will belong to more groups and some
|
||||
users will belong to fewer groups, but the total of all
|
||||
member linked attributes would be 300. This option is
|
||||
incompatible with the --group-membership option.
|
||||
</para></listitem>
|
||||
</varlistentry>
|
||||
</itemizedlist>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
<term>--clean-up</term>
|
||||
<listitem><para>
|
||||
Cleans up any users and groups that were created by previously running
|
||||
this tool. It is recommended you always clean up after running the tool.
|
||||
</para></listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
<term>-I|--instance-id <id></term>
|
||||
<listitem><para>
|
||||
Use this option to run multiple instances of the tool on the same DC at
|
||||
the same time. This adds a prefix to the test users generated to keep
|
||||
them separate on the DC.
|
||||
</para></listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
<term>-K|--prefer-kerberos</term>
|
||||
<listitem><para>
|
||||
Use Kerberos to authenticate the test users.
|
||||
</para></listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
<term>-B|--badpassword-frequency <frequency></term>
|
||||
<listitem><para>
|
||||
Use this option to simulate users trying to authenticate with an
|
||||
incorrect password.
|
||||
</para></listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
<term>--dns-rate <rate></term>
|
||||
<listitem><para>
|
||||
Increase the rate at which DNS packets get sent.
|
||||
</para></listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
<term>-t|--timing-data <file></term>
|
||||
<listitem><para>
|
||||
This writes extra timing data to the file specified. This is mostly
|
||||
used for reporting options, such as generating graphs.
|
||||
</para></listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
<term>Samba Common Options</term>
|
||||
<listitem>
|
||||
<itemizedlist>
|
||||
&stdarg.client.debug;
|
||||
&stdarg.configfile;
|
||||
&stdarg.option;
|
||||
<varlistentry>
|
||||
<term>--realm=REALM</term>
|
||||
<listitem><para>
|
||||
Set the realm name
|
||||
</para></listitem>
|
||||
</varlistentry>
|
||||
&stdarg.version;
|
||||
</itemizedlist>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
<term>Credential Options</term>
|
||||
<listitem>
|
||||
<itemizedlist>
|
||||
<varlistentry>
|
||||
<term>--simple-bind-dn=DN</term>
|
||||
<listitem><para>
|
||||
DN to use for a simple bind
|
||||
</para></listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
<term>--password=PASSWORD</term>
|
||||
<listitem><para>
|
||||
Password
|
||||
</para></listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
<term>-U USERNAME|--username=USERNAME</term>
|
||||
<listitem><para>
|
||||
Username
|
||||
</para></listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
<term>-W WORKGROUP|--workgroup=WORKGROUP</term>
|
||||
<listitem><para>
|
||||
Workgroup
|
||||
</para></listitem>
|
||||
</varlistentry>
|
||||
|
||||
&stdarg.kerberos;
|
||||
|
||||
<varlistentry>
|
||||
<term>--ipaddress=IPADDRESS</term>
|
||||
<listitem><para>
|
||||
IP address of the server
|
||||
</para></listitem>
|
||||
</varlistentry>
|
||||
|
||||
&stdarg.machinepass;
|
||||
</itemizedlist>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
|
||||
</variablelist>
|
||||
</refsect1>
|
||||
|
||||
<refsect1>
|
||||
<title>OPERATIONS</title>
|
||||
|
||||
<refsect2>
|
||||
<title>Generating a traffic-summary file</title>
|
||||
<para>To use this tool, you need either a traffic-summary file or a
|
||||
traffic-model file. To generate either of these files, you will need a
|
||||
packet capture of actual Samba activity on your network.</para>
|
||||
|
||||
<para>Use Wireshark to take a packet capture on your network of the
|
||||
traffic you want to generate. For example, if you want to simulate lots
|
||||
of users logging on, then take a capture at 8:30am when users are
|
||||
logging in.</para>
|
||||
|
||||
<para>Next, you need to convert your packet capture into a traffic
|
||||
summary file, using <command>traffic_summary.pl</command>. Basically
|
||||
this removes any sensitive information from the capture and summarizes
|
||||
what type of packet was sent and when.</para>
|
||||
|
||||
<para>Refer to the <command>traffic_summary.pl --help</command> help for more
|
||||
details, but the basic command will look something like:</para>
|
||||
|
||||
<para><command>tshark -r capture.pcapng -T pdml |
|
||||
traffic_summary.pl > traffic-summary.txt</command></para>
|
||||
</refsect2>
|
||||
|
||||
<refsect2>
|
||||
<title>Replaying a traffic-summary file</title>
|
||||
<para>Once you have a traffic-summary file, you can use it to generate
|
||||
traffic. The traffic_replay tool gets passed the traffic-summary file,
|
||||
along with the full DNS hostname of the DC being tested. You also need
|
||||
to provide some user credentials, and possibly the Samba realm and
|
||||
workgroup (although the realm and workgroup may be determined
|
||||
automatically, for example from the /etc/smb.conf file, if one is
|
||||
present). E.g.</para>
|
||||
|
||||
<para><command>traffic_replay traffic-summary.txt
|
||||
my-dc.samdom.example.com -UAdmin%password -W samdom
|
||||
--realm=samdom.example.com --fixed-password=blahblah123!</command>
|
||||
</para>
|
||||
|
||||
<para>This simply regenerates Samba activity seen in the traffic
|
||||
summary. The traffic is grouped into 'conversations' between a host and
|
||||
the DC. A user and machine account is created on the DC for each
|
||||
conversation, in order to allow logon and other operations to succeed.
|
||||
The script generates the same types of packets as those seen in the
|
||||
summary.</para>
|
||||
|
||||
<para>Creating users can be quite a time-consuming process, especially
|
||||
if a lot of conversations are being generated. To save time, the test
|
||||
users remain on the DC by default. You will need to run the --clean-up
|
||||
option to remove them, once you have finished generating traffic.
|
||||
Because the same test users are used across multiple runs of the tool,
|
||||
a consistent password for these users needs to be used - this is
|
||||
specified by the --fixed-password option.
|
||||
</para>
|
||||
|
||||
<para>The benefit of this tool over simply using tcprelay is that the
|
||||
traffic generated is independent of any specific network. No setup is
|
||||
needed beforehand on the test DC. The traffic no longer contains
|
||||
sensitive details, so the traffic summary could be potentially shared
|
||||
with other Samba developers.</para>
|
||||
|
||||
<para>However, replaying a traffic-summary directly is somewhat limited
|
||||
in what you can actually do. A more flexible approach is to generate
|
||||
the traffic using a model file.</para>
|
||||
</refsect2>
|
||||
|
||||
<refsect2>
|
||||
<title>Generating a traffic-model file</title>
|
||||
<para>To create a traffic-model file, simply pass the traffic-summary
|
||||
file to the <command>traffic_learner</command> script. E.g.</para>
|
||||
|
||||
<para><command>traffic_learner traffic-summary.txt
|
||||
-o traffic-model.txt</command></para>
|
||||
|
||||
<para>This generates a model of the Samba activity in your network.
|
||||
This model-file can now be used to generate traffic.</para>
|
||||
</refsect2>
|
||||
|
||||
<refsect2>
|
||||
<title>Replaying the traffic-model file</title>
|
||||
<para>Packet generation using a traffic-model file uses the same
|
||||
command as a traffic-summary file, e.g.</para>
|
||||
|
||||
<para><command>traffic_replay traffic-model.txt
|
||||
my-dc.samdom.example.com -UAdmin%password</command>
|
||||
</para>
|
||||
|
||||
<para>By default, this will generate 60 seconds worth of traffic based
|
||||
on the model. You can specify longer using the --duration parameter.
|
||||
</para>
|
||||
|
||||
<para>The traffic generated is an approximation of what was seen in
|
||||
the network capture. The traffic generation involves some randomness,
|
||||
so running the same command multiple times may result in slightly
|
||||
different traffic being generated.</para>
|
||||
|
||||
<para>As well as changing how long the model runs for, you can also
|
||||
change how many conversations get generated and how fast the traffic
|
||||
gets replayed. To roughly double the number of conversations that get
|
||||
replayed, use --scale-traffic=2 or to approximately halve the number
|
||||
use --scale-traffic=0.5. To approximately double how quickly the
|
||||
conversations get replayed, use --replay-rate=2, or to halve this use
|
||||
--replay-rate=0.5</para>
|
||||
|
||||
<para>For example, to generate approximately 10 times the amount of
|
||||
traffic seen over a two-minute period (based on the network capture),
|
||||
use:</para>
|
||||
|
||||
<para><command>traffic_replay traffic-model.txt
|
||||
my-dc.samdom.example.com -UAdmin%password --fixed-password=blahblah123!
|
||||
--scale-traffic=10 --duration=120</command></para>
|
||||
</refsect2>
|
||||
|
||||
<refsect2>
|
||||
<title>Scaling the number of users</title>
|
||||
<para>The performance of a Samba DC running a small subset of test
|
||||
users will be different to a fully-populated Samba DC running in a
|
||||
network. As the number of users increases, the size of the DB
|
||||
increases, and a very large DB will perform worse than a smaller DB.
|
||||
</para>
|
||||
|
||||
<para>To increase the size of the Samba DB, this tool can also create
|
||||
extra users and groups. These extra users are basically 'filler' for
|
||||
the DB. They won't actually be used to generate traffic, but they may
|
||||
slow down authentication of the test users.</para>
|
||||
|
||||
<para>For example, to populate the DB with an extra 5000 users (note
|
||||
this will take a while), use the command:</para>
|
||||
|
||||
<para><command>traffic_replay my-dc.samdom.example.com
|
||||
-UAdmin%password --generate-users-only --fixed-password=blahblah123!
|
||||
--number-of-users=5000</command></para>
|
||||
|
||||
<para>You can also create groups and assign users to groups. The users
|
||||
can be randomly assigned to groups - this includes any extra users
|
||||
created as well as the users that map to conversations. Use either
|
||||
--average-groups-per-user or --group-memberships to specify how many
|
||||
group memberships should be assigned to the test users.</para>
|
||||
|
||||
<para>For example, to assign the users in the replayed conversations
|
||||
into 10 groups on average, use a command like:</para>
|
||||
|
||||
<para><command>traffic_replay traffic-model.txt my-dc.samdom.example.com
|
||||
-UAdmin%password --fixed-password=blahblah123!
|
||||
--generate-users-only --number-of-groups=25 --average-groups-per-user=10
|
||||
</command></para>
|
||||
|
||||
<para>The users created by the test will have names like STGU-0-xyz.
|
||||
The groups generated have names like STGG-0-xyz.</para>
|
||||
</refsect2>
|
||||
</refsect1>
|
||||
|
||||
|
||||
<refsect1>
|
||||
<title>VERSION</title>
|
||||
|
||||
<para>This man page is complete for version 4 of the Samba
|
||||
suite.</para>
|
||||
</refsect1>
|
||||
|
||||
<refsect1>
|
||||
<title>SEE ALSO</title>
|
||||
<para>
|
||||
<citerefentry>
|
||||
<refentrytitle>traffic_learner</refentrytitle><manvolnum>7</manvolnum>
|
||||
</citerefentry>.
|
||||
</para>
|
||||
</refsect1>
|
||||
|
||||
<refsect1>
|
||||
<title>AUTHOR</title>
|
||||
|
||||
<para>The original Samba software and related utilities
|
||||
were created by Andrew Tridgell. Samba is now developed
|
||||
by the Samba Team as an Open Source project similar
|
||||
to the way the Linux kernel is developed.</para>
|
||||
|
||||
<para>The traffic_replay tool was developed by the Samba team at
|
||||
Catalyst IT Ltd.</para>
|
||||
|
||||
<para>The traffic_replay manpage was written by Tim Beale.</para>
|
||||
</refsect1>
|
||||
|
||||
</refentry>
|
@ -46,6 +46,8 @@ manpages='''
|
||||
manpages/smbtar.1
|
||||
manpages/smbtree.1
|
||||
manpages/testparm.1
|
||||
manpages/traffic_replay.7
|
||||
manpages/traffic_learner.7
|
||||
manpages/vfs_acl_tdb.8
|
||||
manpages/vfs_acl_xattr.8
|
||||
manpages/vfs_aio_fork.8
|
||||
|
16
python/samba/emulate/__init__.py
Normal file
16
python/samba/emulate/__init__.py
Normal file
@ -0,0 +1,16 @@
|
||||
# Package level initialisation
|
||||
#
|
||||
# Copyright (C) Catalyst IT Ltd. 2017
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation; either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
2019
python/samba/emulate/traffic.py
Normal file
2019
python/samba/emulate/traffic.py
Normal file
File diff suppressed because it is too large
Load Diff
935
python/samba/emulate/traffic_packets.py
Normal file
935
python/samba/emulate/traffic_packets.py
Normal file
@ -0,0 +1,935 @@
|
||||
# Dispatch for various request types.
|
||||
#
|
||||
# Copyright (C) Catalyst IT Ltd. 2017
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation; either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
#
|
||||
import os
|
||||
import ctypes
|
||||
import random
|
||||
|
||||
from samba.net import Net
|
||||
from samba.dcerpc import security, drsuapi, nbt, lsa, netlogon, ntlmssp
|
||||
from samba.dcerpc.netlogon import netr_WorkstationInformation
|
||||
from samba.dcerpc.security import dom_sid
|
||||
from samba.netbios import Node
|
||||
from samba.ndr import ndr_pack
|
||||
from samba.credentials import (
|
||||
CLI_CRED_NTLMv2_AUTH,
|
||||
MUST_USE_KERBEROS,
|
||||
DONT_USE_KERBEROS
|
||||
)
|
||||
from samba import NTSTATUSError
|
||||
from samba.ntstatus import NT_STATUS_OBJECT_NAME_NOT_FOUND
|
||||
from samba.dcerpc.misc import SEC_CHAN_WKSTA
|
||||
import samba
|
||||
samba.ensure_third_party_module("dns", "dnspython")
|
||||
import dns.resolver
|
||||
|
||||
def uint32(v):
|
||||
return ctypes.c_uint32(v).value
|
||||
|
||||
|
||||
def check_runtime_error(runtime, val):
|
||||
if runtime is None:
|
||||
return False
|
||||
|
||||
err32 = uint32(runtime[0])
|
||||
if err32 == val:
|
||||
return True
|
||||
|
||||
return False
|
||||
|
||||
|
||||
name_formats = [
|
||||
drsuapi.DRSUAPI_DS_NAME_FORMAT_FQDN_1779,
|
||||
drsuapi.DRSUAPI_DS_NAME_FORMAT_NT4_ACCOUNT,
|
||||
drsuapi.DRSUAPI_DS_NAME_FORMAT_DISPLAY,
|
||||
drsuapi.DRSUAPI_DS_NAME_FORMAT_GUID,
|
||||
drsuapi.DRSUAPI_DS_NAME_FORMAT_CANONICAL,
|
||||
drsuapi.DRSUAPI_DS_NAME_FORMAT_USER_PRINCIPAL,
|
||||
drsuapi.DRSUAPI_DS_NAME_FORMAT_CANONICAL_EX,
|
||||
drsuapi.DRSUAPI_DS_NAME_FORMAT_SERVICE_PRINCIPAL,
|
||||
drsuapi.DRSUAPI_DS_NAME_FORMAT_SID_OR_SID_HISTORY,
|
||||
drsuapi.DRSUAPI_DS_NAME_FORMAT_DNS_DOMAIN,
|
||||
drsuapi.DRSUAPI_DS_NAME_FORMAT_UPN_AND_ALTSECID,
|
||||
drsuapi.DRSUAPI_DS_NAME_FORMAT_NT4_ACCOUNT_NAME_SANS_DOMAIN_EX,
|
||||
drsuapi.DRSUAPI_DS_NAME_FORMAT_LIST_GLOBAL_CATALOG_SERVERS,
|
||||
drsuapi.DRSUAPI_DS_NAME_FORMAT_UPN_FOR_LOGON,
|
||||
drsuapi.DRSUAPI_DS_NAME_FORMAT_LIST_SERVERS_WITH_DCS_IN_SITE,
|
||||
drsuapi.DRSUAPI_DS_NAME_FORMAT_STRING_SID_NAME,
|
||||
drsuapi.DRSUAPI_DS_NAME_FORMAT_ALT_SECURITY_IDENTITIES_NAME,
|
||||
drsuapi.DRSUAPI_DS_NAME_FORMAT_LIST_NCS,
|
||||
drsuapi.DRSUAPI_DS_NAME_FORMAT_LIST_DOMAINS,
|
||||
drsuapi.DRSUAPI_DS_NAME_FORMAT_MAP_SCHEMA_GUID,
|
||||
drsuapi.DRSUAPI_DS_NAME_FORMAT_NT4_ACCOUNT_NAME_SANS_DOMAIN,
|
||||
drsuapi.DRSUAPI_DS_NAME_FORMAT_LIST_ROLES,
|
||||
drsuapi.DRSUAPI_DS_NAME_FORMAT_LIST_INFO_FOR_SERVER,
|
||||
drsuapi.DRSUAPI_DS_NAME_FORMAT_LIST_SERVERS_FOR_DOMAIN_IN_SITE,
|
||||
drsuapi.DRSUAPI_DS_NAME_FORMAT_LIST_DOMAINS_IN_SITE,
|
||||
drsuapi.DRSUAPI_DS_NAME_FORMAT_LIST_SERVERS_IN_SITE,
|
||||
drsuapi.DRSUAPI_DS_NAME_FORMAT_LIST_SITES,
|
||||
]
|
||||
|
||||
|
||||
def warning(message):
|
||||
print "\033[37;41;1m" "Warning: %s" "\033[00m" % (message)
|
||||
|
||||
###############################################################################
|
||||
#
|
||||
# Packet generation functions:
|
||||
#
|
||||
# All the packet generation functions have the following form:
|
||||
# packet_${protocol}_${opcode}(packet, conversation, context)
|
||||
#
|
||||
# The functions return true, if statistics should be collected for the packet
|
||||
# false, the packet has been ignored.
|
||||
#
|
||||
# Where:
|
||||
# protocol is the protocol, i.e. cldap, dcerpc, ...
|
||||
# opcode is the protocol op code i.e. type of the packet to be
|
||||
# generated.
|
||||
#
|
||||
# packet contains data about the captured/generated packet
|
||||
# provides any extra data needed to generate the packet
|
||||
#
|
||||
# conversation Details of the current client/server interaction
|
||||
#
|
||||
# context state data for the current interaction
|
||||
#
|
||||
#
|
||||
#
|
||||
# The following protocols are not currently handled:
|
||||
# smb
|
||||
# smb2
|
||||
# browser
|
||||
# smb_netlogon
|
||||
#
|
||||
# The following drsuapi replication packets are currently ignored:
|
||||
# DsReplicaSync
|
||||
# DsGetNCChanges
|
||||
# DsReplicaUpdateRefs
|
||||
|
||||
|
||||
# Packet generators that do NOTHING are assigned to the null_packet
|
||||
# function which allows the conversation generators to notice this and
|
||||
# avoid a whole lot of pointless work.
|
||||
def null_packet(packet, conversation, context):
|
||||
return False
|
||||
|
||||
|
||||
def packet_cldap_3(packet, conversation, context):
|
||||
# searchRequest
|
||||
net = Net(creds=context.creds, lp=context.lp)
|
||||
net.finddc(domain=context.lp.get('realm'),
|
||||
flags=(nbt.NBT_SERVER_LDAP |
|
||||
nbt.NBT_SERVER_DS |
|
||||
nbt.NBT_SERVER_WRITABLE))
|
||||
return True
|
||||
|
||||
|
||||
packet_cldap_5 = null_packet
|
||||
# searchResDone
|
||||
|
||||
packet_dcerpc_0 = null_packet
|
||||
# Request
|
||||
# Can be ignored, it's the continuation of an existing conversation
|
||||
|
||||
packet_dcerpc_2 = null_packet
|
||||
# Request
|
||||
# Server response, so should be ignored
|
||||
|
||||
packet_dcerpc_3 = null_packet
|
||||
|
||||
packet_dcerpc_11 = null_packet
|
||||
# Bind
|
||||
# creation of the rpc dcerpc connection is managed by the higher level
|
||||
# protocol drivers. So we ignore it when generating traffic
|
||||
|
||||
|
||||
packet_dcerpc_12 = null_packet
|
||||
# Bind_ack
|
||||
# Server response, so should be ignored
|
||||
|
||||
|
||||
packet_dcerpc_13 = null_packet
|
||||
# Bind_nak
|
||||
# Server response, so should be ignored
|
||||
|
||||
|
||||
packet_dcerpc_14 = null_packet
|
||||
# Alter_context
|
||||
# Generated as part of the connect process
|
||||
|
||||
|
||||
def packet_dcerpc_15(packet, conversation, context):
|
||||
# Alter_context_resp
|
||||
# This means it was GSSAPI/krb5 (probably)
|
||||
# Check the kerberos_state and issue a diagnostic if kerberos not enabled
|
||||
if context.user_creds.get_kerberos_state() == DONT_USE_KERBEROS:
|
||||
warning("Kerberos disabled but have dcerpc Alter_context_resp "
|
||||
"indicating Kerberos was used")
|
||||
return False
|
||||
|
||||
|
||||
def packet_dcerpc_16(packet, conversation, context):
|
||||
# AUTH3
|
||||
# This means it was NTLMSSP
|
||||
# Check the kerberos_state and issue a diagnostic if kerberos enabled
|
||||
if context.user_creds.get_kerberos_state() == MUST_USE_KERBEROS:
|
||||
warning("Kerberos enabled but have dcerpc AUTH3 "
|
||||
"indicating NTLMSSP was used")
|
||||
return False
|
||||
|
||||
|
||||
def packet_dns_0(packet, conversation, context):
|
||||
# query
|
||||
name, rtype = context.guess_a_dns_lookup()
|
||||
dns.resolver.query(name, rtype)
|
||||
return True
|
||||
|
||||
|
||||
packet_dns_1 = null_packet
|
||||
# response
|
||||
# Server response, so should be ignored
|
||||
|
||||
|
||||
def packet_drsuapi_0(packet, conversation, context):
|
||||
# DsBind
|
||||
context.get_drsuapi_connection_pair(True)
|
||||
return True
|
||||
|
||||
|
||||
NAME_FORMATS = [getattr(drsuapi, _x) for _x in dir(drsuapi)
|
||||
if 'NAME_FORMAT' in _x]
|
||||
|
||||
|
||||
def packet_drsuapi_12(packet, conversation, context):
|
||||
# DsCrackNames
|
||||
drs, handle = context.get_drsuapi_connection_pair()
|
||||
|
||||
names = drsuapi.DsNameString()
|
||||
names.str = context.server
|
||||
|
||||
req = drsuapi.DsNameRequest1()
|
||||
req.format_flags = 0
|
||||
req.format_offered = 7
|
||||
req.format_desired = random.choice(name_formats)
|
||||
req.codepage = 1252
|
||||
req.language = 1033 # German, I think
|
||||
req.format_flags = 0
|
||||
req.count = 1
|
||||
req.names = [names]
|
||||
|
||||
(result, ctr) = drs.DsCrackNames(handle, 1, req)
|
||||
return True
|
||||
|
||||
|
||||
def packet_drsuapi_13(packet, conversation, context):
|
||||
# DsWriteAccountSpn
|
||||
req = drsuapi.DsWriteAccountSpnRequest1()
|
||||
req.operation = drsuapi.DRSUAPI_DS_SPN_OPERATION_ADD
|
||||
(drs, handle) = context.get_drsuapi_connection_pair()
|
||||
(level, res) = drs.DsWriteAccountSpn(handle, 1, req)
|
||||
return True
|
||||
|
||||
|
||||
def packet_drsuapi_1(packet, conversation, context):
|
||||
# DsUnbind
|
||||
(drs, handle) = context.get_drsuapi_connection_pair()
|
||||
drs.DsUnbind(handle)
|
||||
del context.drsuapi_connections[-1]
|
||||
return True
|
||||
|
||||
|
||||
packet_drsuapi_2 = null_packet
|
||||
# DsReplicaSync
|
||||
# This is between DCs, triggered on a DB change
|
||||
# Ignoring for now
|
||||
|
||||
|
||||
packet_drsuapi_3 = null_packet
|
||||
# DsGetNCChanges
|
||||
# This is between DCs, trigger with DB operation,
|
||||
# or DsReplicaSync between DCs.
|
||||
# Ignoring for now
|
||||
|
||||
|
||||
packet_drsuapi_4 = null_packet
|
||||
# DsReplicaUpdateRefs
|
||||
# Ignoring for now
|
||||
|
||||
|
||||
packet_epm_3 = null_packet
|
||||
# Map
|
||||
# Will be generated by higher level protocol calls
|
||||
|
||||
|
||||
def packet_kerberos_(packet, conversation, context):
|
||||
# Use the presence of kerberos packets as a hint to enable kerberos
|
||||
# for the rest of the conversation.
|
||||
# i.e. kerberos packets are not explicitly generated.
|
||||
context.user_creds.set_kerberos_state(MUST_USE_KERBEROS)
|
||||
context.user_creds_bad.set_kerberos_state(MUST_USE_KERBEROS)
|
||||
context.machine_creds.set_kerberos_state(MUST_USE_KERBEROS)
|
||||
context.machine_creds_bad.set_kerberos_state(MUST_USE_KERBEROS)
|
||||
context.creds.set_kerberos_state(MUST_USE_KERBEROS)
|
||||
return False
|
||||
|
||||
|
||||
packet_ldap_ = null_packet
|
||||
# Unknown
|
||||
# The ldap payload was probably encrypted so just ignore it.
|
||||
|
||||
|
||||
def packet_ldap_0(packet, conversation, context):
|
||||
# bindRequest
|
||||
if packet.extra[5] == "simple":
|
||||
# Perform a simple bind.
|
||||
context.get_ldap_connection(new=True, simple=True)
|
||||
else:
|
||||
# Perform a sasl bind.
|
||||
context.get_ldap_connection(new=True, simple=False)
|
||||
return True
|
||||
|
||||
|
||||
packet_ldap_1 = null_packet
|
||||
# bindResponse
|
||||
# Server response ignored for traffic generation
|
||||
|
||||
|
||||
def packet_ldap_2(packet, conversation, context):
|
||||
# unbindRequest
|
||||
# pop the last one off -- most likely we're in a bind/unbind ping.
|
||||
del context.ldap_connections[-1:]
|
||||
return False
|
||||
|
||||
|
||||
def packet_ldap_3(packet, conversation, context):
|
||||
# searchRequest
|
||||
|
||||
(scope, dn_sig, filter, attrs, extra, desc, oid) = packet.extra
|
||||
if not scope:
|
||||
scope = 0
|
||||
|
||||
samdb = context.get_ldap_connection()
|
||||
dn = context.get_matching_dn(dn_sig)
|
||||
|
||||
samdb.search(dn, scope=int(scope), attrs=attrs.split(','))
|
||||
return True
|
||||
|
||||
|
||||
packet_ldap_4 = null_packet
|
||||
# searchResEntry
|
||||
# Server response ignored for traffic generation
|
||||
|
||||
|
||||
packet_ldap_5 = null_packet
|
||||
# Server response ignored for traffic generation
|
||||
|
||||
packet_ldap_6 = null_packet
|
||||
|
||||
packet_ldap_7 = null_packet
|
||||
|
||||
packet_ldap_8 = null_packet
|
||||
|
||||
packet_ldap_9 = null_packet
|
||||
|
||||
packet_ldap_16 = null_packet
|
||||
|
||||
packet_lsarpc_0 = null_packet
|
||||
# lsarClose
|
||||
|
||||
packet_lsarpc_1 = null_packet
|
||||
# lsarDelete
|
||||
|
||||
packet_lsarpc_2 = null_packet
|
||||
# lsarEnumeratePrivileges
|
||||
|
||||
packet_lsarpc_3 = null_packet
|
||||
# LsarQuerySecurityObject
|
||||
|
||||
packet_lsarpc_4 = null_packet
|
||||
# LsarSetSecurityObject
|
||||
|
||||
packet_lsarpc_5 = null_packet
|
||||
# LsarChangePassword
|
||||
|
||||
packet_lsarpc_6 = null_packet
|
||||
# lsa_OpenPolicy
|
||||
# We ignore this, but take it as a hint that the lsarpc handle should
|
||||
# be over a named pipe.
|
||||
#
|
||||
|
||||
|
||||
def packet_lsarpc_14(packet, conversation, context):
|
||||
# lsa_LookupNames
|
||||
c = context.get_lsarpc_named_pipe_connection()
|
||||
|
||||
objectAttr = lsa.ObjectAttribute()
|
||||
pol_handle = c.OpenPolicy2(u'', objectAttr,
|
||||
security.SEC_FLAG_MAXIMUM_ALLOWED)
|
||||
|
||||
sids = lsa.TransSidArray()
|
||||
names = [lsa.String("This Organization"),
|
||||
lsa.String("Digest Authentication")]
|
||||
level = 5
|
||||
count = 0
|
||||
c.LookupNames(pol_handle, names, sids, level, count)
|
||||
return True
|
||||
|
||||
|
||||
def packet_lsarpc_15(packet, conversation, context):
|
||||
# lsa_LookupSids
|
||||
c = context.get_lsarpc_named_pipe_connection()
|
||||
|
||||
objectAttr = lsa.ObjectAttribute()
|
||||
pol_handle = c.OpenPolicy2(u'', objectAttr,
|
||||
security.SEC_FLAG_MAXIMUM_ALLOWED)
|
||||
|
||||
sids = lsa.SidArray()
|
||||
sid = lsa.SidPtr()
|
||||
|
||||
x = dom_sid("S-1-5-7")
|
||||
sid.sid = x
|
||||
sids.sids = [sid]
|
||||
sids.num_sids = 1
|
||||
names = lsa.TransNameArray()
|
||||
level = 5
|
||||
count = 0
|
||||
|
||||
c.LookupSids(pol_handle, sids, names, level, count)
|
||||
return True
|
||||
|
||||
|
||||
def packet_lsarpc_39(packet, conversation, context):
|
||||
# lsa_QueryTrustedDomainInfoBySid
|
||||
# Samba does not support trusted domains, so this call is expected to fail
|
||||
#
|
||||
c = context.get_lsarpc_named_pipe_connection()
|
||||
|
||||
objectAttr = lsa.ObjectAttribute()
|
||||
|
||||
pol_handle = c.OpenPolicy2(u'', objectAttr,
|
||||
security.SEC_FLAG_MAXIMUM_ALLOWED)
|
||||
|
||||
domsid = security.dom_sid(context.domain_sid)
|
||||
level = 1
|
||||
try:
|
||||
c.QueryTrustedDomainInfoBySid(pol_handle, domsid, level)
|
||||
except NTSTATUSError as error:
|
||||
# Object Not found is the expected result, anything else is a
|
||||
# failure.
|
||||
if not check_runtime_error(error, NT_STATUS_OBJECT_NAME_NOT_FOUND):
|
||||
raise
|
||||
return True
|
||||
|
||||
|
||||
packet_lsarpc_40 = null_packet
|
||||
# lsa_SetTrustedDomainInfo
|
||||
# Not currently supported
|
||||
|
||||
|
||||
packet_lsarpc_43 = null_packet
|
||||
# LsaStorePrivateData
|
||||
|
||||
|
||||
packet_lsarpc_44 = null_packet
|
||||
# LsaRetrievePrivateData
|
||||
|
||||
|
||||
packet_lsarpc_68 = null_packet
|
||||
# LsarLookupNames3
|
||||
|
||||
|
||||
def packet_lsarpc_76(packet, conversation, context):
|
||||
# lsa_LookupSids3
|
||||
c = context.get_lsarpc_connection()
|
||||
sids = lsa.SidArray()
|
||||
sid = lsa.SidPtr()
|
||||
# Need a set
|
||||
x = dom_sid("S-1-5-7")
|
||||
sid.sid = x
|
||||
sids.sids = [sid]
|
||||
sids.num_sids = 1
|
||||
names = lsa.TransNameArray2()
|
||||
level = 5
|
||||
count = 0
|
||||
lookup_options = 0
|
||||
client_revision = 2
|
||||
c.LookupSids3(sids, names, level, count, lookup_options, client_revision)
|
||||
return True
|
||||
|
||||
|
||||
def packet_lsarpc_77(packet, conversation, context):
|
||||
# lsa_LookupNames4
|
||||
c = context.get_lsarpc_connection()
|
||||
sids = lsa.TransSidArray3()
|
||||
names = [lsa.String("This Organization"),
|
||||
lsa.String("Digest Authentication")]
|
||||
level = 5
|
||||
count = 0
|
||||
lookup_options = 0
|
||||
client_revision = 2
|
||||
c.LookupNames4(names, sids, level, count, lookup_options, client_revision)
|
||||
return True
|
||||
|
||||
|
||||
def packet_nbns_0(packet, conversation, context):
|
||||
# query
|
||||
n = Node()
|
||||
try:
|
||||
n.query_name("ANAME", context.server, timeout=4, broadcast=False)
|
||||
except:
|
||||
pass
|
||||
return True
|
||||
|
||||
|
||||
packet_nbns_1 = null_packet
|
||||
# response
|
||||
# Server response, not generated by the client
|
||||
|
||||
|
||||
packet_rpc_netlogon_0 = null_packet
|
||||
|
||||
packet_rpc_netlogon_1 = null_packet
|
||||
|
||||
packet_rpc_netlogon_4 = null_packet
|
||||
# NetrServerReqChallenge
|
||||
# generated by higher level protocol drivers
|
||||
# ignored for traffic generation
|
||||
|
||||
packet_rpc_netlogon_14 = null_packet
|
||||
|
||||
packet_rpc_netlogon_15 = null_packet
|
||||
|
||||
packet_rpc_netlogon_21 = null_packet
|
||||
# NetrLogonDummyRoutine1
|
||||
# Used to determine security settings. Triggered from schannel setup
|
||||
# So no need for an explicit generator
|
||||
|
||||
|
||||
packet_rpc_netlogon_26 = null_packet
|
||||
# NetrServerAuthenticate3
|
||||
# Triggered from schannel set up, no need for an explicit generator
|
||||
|
||||
|
||||
def packet_rpc_netlogon_29(packet, conversation, context):
|
||||
# NetrLogonGetDomainInfo [531]
|
||||
c = context.get_netlogon_connection()
|
||||
(auth, succ) = context.get_authenticator()
|
||||
query = netr_WorkstationInformation()
|
||||
|
||||
c.netr_LogonGetDomainInfo(context.server,
|
||||
context.netbios_name,
|
||||
auth,
|
||||
succ,
|
||||
2, # TODO are there other values?
|
||||
query)
|
||||
return True
|
||||
|
||||
|
||||
def packet_rpc_netlogon_30(packet, conversation, context):
|
||||
# NetrServerPasswordSet2
|
||||
c = context.get_netlogon_connection()
|
||||
(auth, succ) = context.get_authenticator()
|
||||
DATA_LEN = 512
|
||||
# Set the new password to the existing password, this generates the same
|
||||
# work load as a new value, and leaves the account password intact for
|
||||
# subsequent runs
|
||||
newpass = context.machine_creds.get_password().encode('utf-16-le')
|
||||
pwd_len = len(newpass)
|
||||
filler = [ord(x) for x in os.urandom(DATA_LEN - pwd_len)]
|
||||
pwd = netlogon.netr_CryptPassword()
|
||||
pwd.length = pwd_len
|
||||
pwd.data = filler + [ord(x) for x in newpass]
|
||||
context.machine_creds.encrypt_netr_crypt_password(pwd)
|
||||
c.netr_ServerPasswordSet2(context.server,
|
||||
context.machine_creds.get_workstation(),
|
||||
SEC_CHAN_WKSTA,
|
||||
context.netbios_name,
|
||||
auth,
|
||||
pwd)
|
||||
return True
|
||||
|
||||
|
||||
packet_rpc_netlogon_34 = null_packet
|
||||
|
||||
|
||||
def packet_rpc_netlogon_39(packet, conversation, context):
|
||||
# NetrLogonSamLogonEx [4331]
|
||||
def connect(creds):
|
||||
c = context.get_netlogon_connection()
|
||||
|
||||
# Disable Kerberos in cli creds to extract NTLM response
|
||||
old_state = creds.get_kerberos_state()
|
||||
creds.set_kerberos_state(DONT_USE_KERBEROS)
|
||||
|
||||
logon = samlogon_logon_info(context.domain,
|
||||
context.netbios_name,
|
||||
creds)
|
||||
logon_level = netlogon.NetlogonNetworkTransitiveInformation
|
||||
validation_level = netlogon.NetlogonValidationSamInfo4
|
||||
netr_flags = 0
|
||||
c.netr_LogonSamLogonEx(context.server,
|
||||
context.machine_creds.get_workstation(),
|
||||
logon_level,
|
||||
logon,
|
||||
validation_level,
|
||||
netr_flags)
|
||||
|
||||
creds.set_kerberos_state(old_state)
|
||||
|
||||
context.last_samlogon_bad =\
|
||||
context.with_random_bad_credentials(connect,
|
||||
context.user_creds,
|
||||
context.user_creds_bad,
|
||||
context.last_samlogon_bad)
|
||||
return True
|
||||
|
||||
|
||||
def samlogon_target(domain_name, computer_name):
|
||||
target_info = ntlmssp.AV_PAIR_LIST()
|
||||
target_info.count = 3
|
||||
computername = ntlmssp.AV_PAIR()
|
||||
computername.AvId = ntlmssp.MsvAvNbComputerName
|
||||
computername.Value = computer_name
|
||||
|
||||
domainname = ntlmssp.AV_PAIR()
|
||||
domainname.AvId = ntlmssp.MsvAvNbDomainName
|
||||
domainname.Value = domain_name
|
||||
|
||||
eol = ntlmssp.AV_PAIR()
|
||||
eol.AvId = ntlmssp.MsvAvEOL
|
||||
target_info.pair = [domainname, computername, eol]
|
||||
|
||||
return ndr_pack(target_info)
|
||||
|
||||
|
||||
def samlogon_logon_info(domain_name, computer_name, creds):
|
||||
|
||||
target_info_blob = samlogon_target(domain_name, computer_name)
|
||||
|
||||
challenge = b"abcdefgh"
|
||||
# User account under test
|
||||
response = creds.get_ntlm_response(flags=CLI_CRED_NTLMv2_AUTH,
|
||||
challenge=challenge,
|
||||
target_info=target_info_blob)
|
||||
|
||||
logon = netlogon.netr_NetworkInfo()
|
||||
|
||||
logon.challenge = [ord(x) for x in challenge]
|
||||
logon.nt = netlogon.netr_ChallengeResponse()
|
||||
logon.nt.length = len(response["nt_response"])
|
||||
logon.nt.data = [ord(x) for x in response["nt_response"]]
|
||||
logon.identity_info = netlogon.netr_IdentityInfo()
|
||||
|
||||
(username, domain) = creds.get_ntlm_username_domain()
|
||||
logon.identity_info.domain_name.string = domain
|
||||
logon.identity_info.account_name.string = username
|
||||
logon.identity_info.workstation.string = creds.get_workstation()
|
||||
|
||||
return logon
|
||||
|
||||
|
||||
def packet_rpc_netlogon_40(packet, conversation, context):
|
||||
# DsrEnumerateDomainTrusts
|
||||
c = context.get_netlogon_connection()
|
||||
c.netr_DsrEnumerateDomainTrusts(
|
||||
context.server,
|
||||
netlogon.NETR_TRUST_FLAG_IN_FOREST |
|
||||
netlogon.NETR_TRUST_FLAG_OUTBOUND |
|
||||
netlogon.NETR_TRUST_FLAG_INBOUND)
|
||||
return True
|
||||
|
||||
|
||||
def packet_rpc_netlogon_45(packet, conversation, context):
|
||||
# NetrLogonSamLogonWithFlags [7]
|
||||
def connect(creds):
|
||||
c = context.get_netlogon_connection()
|
||||
(auth, succ) = context.get_authenticator()
|
||||
|
||||
# Disable Kerberos in cli creds to extract NTLM response
|
||||
old_state = creds.get_kerberos_state()
|
||||
creds.set_kerberos_state(DONT_USE_KERBEROS)
|
||||
|
||||
logon = samlogon_logon_info(context.domain,
|
||||
context.netbios_name,
|
||||
creds)
|
||||
logon_level = netlogon.NetlogonNetworkTransitiveInformation
|
||||
validation_level = netlogon.NetlogonValidationSamInfo4
|
||||
netr_flags = 0
|
||||
c.netr_LogonSamLogonWithFlags(context.server,
|
||||
context.machine_creds.get_workstation(),
|
||||
auth,
|
||||
succ,
|
||||
logon_level,
|
||||
logon,
|
||||
validation_level,
|
||||
netr_flags)
|
||||
|
||||
creds.set_kerberos_state(old_state)
|
||||
|
||||
context.last_samlogon_bad =\
|
||||
context.with_random_bad_credentials(connect,
|
||||
context.user_creds,
|
||||
context.user_creds_bad,
|
||||
context.last_samlogon_bad)
|
||||
return True
|
||||
|
||||
|
||||
def packet_samr_0(packet, conversation, context):
|
||||
# Open
|
||||
c = context.get_samr_context()
|
||||
c.get_handle()
|
||||
return True
|
||||
|
||||
|
||||
def packet_samr_1(packet, conversation, context):
|
||||
# Close
|
||||
c = context.get_samr_context()
|
||||
s = c.get_connection()
|
||||
# close the last opened handle, may not always be accurate
|
||||
# but will do for load simulation
|
||||
if c.user_handle is not None:
|
||||
s.Close(c.user_handle)
|
||||
c.user_handle = None
|
||||
elif c.group_handle is not None:
|
||||
s.Close(c.group_handle)
|
||||
c.group_handle = None
|
||||
elif c.domain_handle is not None:
|
||||
s.Close(c.domain_handle)
|
||||
c.domain_handle = None
|
||||
c.rids = None
|
||||
elif c.handle is not None:
|
||||
s.Close(c.handle)
|
||||
c.handle = None
|
||||
c.domain_sid = None
|
||||
return True
|
||||
|
||||
|
||||
def packet_samr_3(packet, conversation, context):
|
||||
# QuerySecurity
|
||||
c = context.get_samr_context()
|
||||
s = c.get_connection()
|
||||
if c.user_handle is None:
|
||||
packet_samr_34(packet, conversation, context)
|
||||
s.QuerySecurity(c.user_handle, 1)
|
||||
return True
|
||||
|
||||
|
||||
def packet_samr_5(packet, conversation, context):
|
||||
# LookupDomain
|
||||
c = context.get_samr_context()
|
||||
s = c.get_connection()
|
||||
h = c.get_handle()
|
||||
d = lsa.String()
|
||||
d.string = context.domain
|
||||
c.domain_sid = s.LookupDomain(h, d)
|
||||
return True
|
||||
|
||||
|
||||
def packet_samr_6(packet, conversation, context):
|
||||
# EnumDomains
|
||||
c = context.get_samr_context()
|
||||
s = c.get_connection()
|
||||
h = c.get_handle()
|
||||
s.EnumDomains(h, 0, 0)
|
||||
return True
|
||||
|
||||
|
||||
def packet_samr_7(packet, conversation, context):
|
||||
# OpenDomain
|
||||
c = context.get_samr_context()
|
||||
s = c.get_connection()
|
||||
h = c.get_handle()
|
||||
if c.domain_sid is None:
|
||||
packet_samr_5(packet, conversation, context)
|
||||
|
||||
c.domain_handle = s.OpenDomain(h,
|
||||
security.SEC_FLAG_MAXIMUM_ALLOWED,
|
||||
c.domain_sid)
|
||||
return True
|
||||
|
||||
|
||||
SAMR_QUERY_DOMAIN_INFO_LEVELS = [8, 12]
|
||||
|
||||
|
||||
def packet_samr_8(packet, conversation, context):
|
||||
# QueryDomainInfo [228]
|
||||
c = context.get_samr_context()
|
||||
s = c.get_connection()
|
||||
if c.domain_handle is None:
|
||||
packet_samr_7(packet, conversation, context)
|
||||
level = random.choice(SAMR_QUERY_DOMAIN_INFO_LEVELS)
|
||||
s.QueryDomainInfo(c.domain_handle, level)
|
||||
return True
|
||||
|
||||
|
||||
packet_samr_14 = null_packet
|
||||
# CreateDomainAlias
|
||||
# Ignore these for now.
|
||||
|
||||
|
||||
def packet_samr_15(packet, conversation, context):
|
||||
# EnumDomainAliases
|
||||
c = context.get_samr_context()
|
||||
s = c.get_connection()
|
||||
if c.domain_handle is None:
|
||||
packet_samr_7(packet, conversation, context)
|
||||
|
||||
s.EnumDomainAliases(c.domain_handle, 100, 0)
|
||||
return True
|
||||
|
||||
|
||||
def packet_samr_16(packet, conversation, context):
|
||||
# GetAliasMembership
|
||||
c = context.get_samr_context()
|
||||
s = c.get_connection()
|
||||
if c.domain_handle is None:
|
||||
packet_samr_7(packet, conversation, context)
|
||||
|
||||
sids = lsa.SidArray()
|
||||
sid = lsa.SidPtr()
|
||||
sid.sid = c.domain_sid
|
||||
sids.sids = [sid]
|
||||
s.GetAliasMembership(c.domain_handle, sids)
|
||||
return True
|
||||
|
||||
|
||||
def packet_samr_17(packet, conversation, context):
|
||||
# LookupNames
|
||||
c = context.get_samr_context()
|
||||
s = c.get_connection()
|
||||
if c.domain_handle is None:
|
||||
packet_samr_7(packet, conversation, context)
|
||||
|
||||
name = lsa.String(context.username)
|
||||
c.rids = s.LookupNames(c.domain_handle, [name])
|
||||
return True
|
||||
|
||||
|
||||
def packet_samr_18(packet, conversation, context):
|
||||
# LookupRids
|
||||
c = context.get_samr_context()
|
||||
s = c.get_connection()
|
||||
if c.rids is None:
|
||||
packet_samr_17(packet, conversation, context)
|
||||
rids = []
|
||||
for r in c.rids:
|
||||
for i in r.ids:
|
||||
rids.append(i)
|
||||
s.LookupRids(c.domain_handle, rids)
|
||||
return True
|
||||
|
||||
|
||||
def packet_samr_19(packet, conversation, context):
|
||||
# OpenGroup
|
||||
c = context.get_samr_context()
|
||||
s = c.get_connection()
|
||||
if c.domain_handle is None:
|
||||
packet_samr_7(packet, conversation, context)
|
||||
|
||||
rid = 0x202 # Users I think.
|
||||
c.group_handle = s.OpenGroup(c.domain_handle,
|
||||
security.SEC_FLAG_MAXIMUM_ALLOWED,
|
||||
rid)
|
||||
return True
|
||||
|
||||
|
||||
def packet_samr_25(packet, conversation, context):
|
||||
# QueryGroupMember
|
||||
c = context.get_samr_context()
|
||||
s = c.get_connection()
|
||||
if c.group_handle is None:
|
||||
packet_samr_19(packet, conversation, context)
|
||||
s.QueryGroupMember(c.group_handle)
|
||||
return True
|
||||
|
||||
|
||||
def packet_samr_34(packet, conversation, context):
|
||||
# OpenUser
|
||||
c = context.get_samr_context()
|
||||
s = c.get_connection()
|
||||
if c.rids is None:
|
||||
packet_samr_17(packet, conversation, context)
|
||||
c.user_handle = s.OpenUser(c.domain_handle,
|
||||
security.SEC_FLAG_MAXIMUM_ALLOWED,
|
||||
c.rids[0].ids[0])
|
||||
return True
|
||||
|
||||
|
||||
def packet_samr_36(packet, conversation, context):
|
||||
# QueryUserInfo
|
||||
c = context.get_samr_context()
|
||||
s = c.get_connection()
|
||||
if c.user_handle is None:
|
||||
packet_samr_34(packet, conversation, context)
|
||||
level = 1
|
||||
s.QueryUserInfo(c.user_handle, level)
|
||||
return True
|
||||
|
||||
|
||||
packet_samr_37 = null_packet
|
||||
|
||||
|
||||
def packet_samr_39(packet, conversation, context):
|
||||
# GetGroupsForUser
|
||||
c = context.get_samr_context()
|
||||
s = c.get_connection()
|
||||
if c.user_handle is None:
|
||||
packet_samr_34(packet, conversation, context)
|
||||
s.GetGroupsForUser(c.user_handle)
|
||||
return True
|
||||
|
||||
|
||||
packet_samr_40 = null_packet
|
||||
|
||||
packet_samr_44 = null_packet
|
||||
|
||||
|
||||
def packet_samr_57(packet, conversation, context):
|
||||
# Connect2
|
||||
c = context.get_samr_context()
|
||||
c.get_handle()
|
||||
return True
|
||||
|
||||
|
||||
def packet_samr_64(packet, conversation, context):
|
||||
# Connect5
|
||||
c = context.get_samr_context()
|
||||
c.get_handle()
|
||||
return True
|
||||
|
||||
|
||||
packet_samr_68 = null_packet
|
||||
|
||||
|
||||
def packet_srvsvc_16(packet, conversation, context):
|
||||
# NetShareGetInfo
|
||||
s = context.get_srvsvc_connection()
|
||||
server_unc = "\\\\" + context.server
|
||||
share_name = "netlogon"
|
||||
level = 1
|
||||
s.NetShareGetInfo(server_unc, share_name, level)
|
||||
return True
|
||||
|
||||
|
||||
def packet_srvsvc_21(packet, conversation, context):
|
||||
# NetSrvGetInfo
|
||||
srvsvc = context.get_srvsvc_connection()
|
||||
server_unc = "\\\\" + context.server
|
||||
level = 102
|
||||
srvsvc.NetSrvGetInfo(server_unc, level)
|
||||
return True
|
60
python/samba/tests/blackbox/testdata/traffic-sample-very-short.model
vendored
Normal file
60
python/samba/tests/blackbox/testdata/traffic-sample-very-short.model
vendored
Normal file
@ -0,0 +1,60 @@
|
||||
{
|
||||
"ngrams": {
|
||||
"-\t-": {
|
||||
"cldap:3": 1,
|
||||
"ldap:3": 1
|
||||
},
|
||||
"-\tldap:3": {
|
||||
"wait:0": 1
|
||||
},
|
||||
"wait:0\trpc_netlogon:29": {
|
||||
"kerberos:": 1
|
||||
},
|
||||
"rpc_netlogon:29\tkerberos:": {
|
||||
"ldap:3": 1
|
||||
},
|
||||
"cldap:3\twait:0": {
|
||||
"rpc_netlogon:29": 1
|
||||
},
|
||||
"-\tcldap:3": {
|
||||
"cldap:3": 1
|
||||
},
|
||||
"ldap:3\twait:0": {
|
||||
"ldap:2": 1
|
||||
},
|
||||
"cldap:3\tcldap:3": {
|
||||
"cldap:3": 1,
|
||||
"wait:0": 1
|
||||
},
|
||||
"kerberos:\tldap:3": {
|
||||
"-": 1
|
||||
}
|
||||
},
|
||||
"conversation_rate": [
|
||||
2,
|
||||
0.12712717056274414
|
||||
],
|
||||
"dns": {
|
||||
"1": 9,
|
||||
"0": 9
|
||||
},
|
||||
"query_details": {
|
||||
"rpc_netlogon:29": {
|
||||
"-": 1
|
||||
},
|
||||
"cldap:3": {
|
||||
"\t\t\tNetlogon\t\t\t": 3
|
||||
},
|
||||
"ldap:3": {
|
||||
"\t\t\tsubschemaSubentry,dsServiceName,namingContexts,defaultNamingContext,schemaNamingContext,configurationNamingContext,rootDomainNamingContext,supportedControl,supportedLDAPVersion,supportedLDAPPolicies,supportedSASLMechanisms,dnsHostName,ldapServiceName,serverName,supportedCapabilities\t\t\t": 1,
|
||||
"2\tDC,DC\t\tcn\t\t\t": 1
|
||||
},
|
||||
"ldap:2": {
|
||||
"\t\t\t\t\t\t": 1
|
||||
},
|
||||
"kerberos:": {
|
||||
"": 1
|
||||
}
|
||||
},
|
||||
"cumulative_duration": 0.39243292808532715
|
||||
}
|
50
python/samba/tests/blackbox/testdata/traffic-sample-very-short.txt
vendored
Normal file
50
python/samba/tests/blackbox/testdata/traffic-sample-very-short.txt
vendored
Normal file
@ -0,0 +1,50 @@
|
||||
1487921562.592126000 11 3 1 dns 0 query
|
||||
1487921562.592285000 11 1 4 dns 0 query
|
||||
1487921562.592636000 11 4 1 dns 1 response
|
||||
1487921562.592911000 11 1 3 dns 1 response
|
||||
1487921562.593315000 06 3 5 1 ldap 3 searchRequest 2 DC,DC cn
|
||||
1487921562.596247000 11 3 1 dns 0 query
|
||||
1487921562.596362000 11 1 4 dns 0 query
|
||||
1487921562.596697000 11 4 1 dns 1 response
|
||||
1487921562.596921000 11 1 3 dns 1 response
|
||||
1487921562.598308000 11 3 1 dns 0 query
|
||||
1487921562.598414000 11 1 4 dns 0 query
|
||||
1487921562.598729000 11 4 1 dns 1 response
|
||||
1487921562.598963000 11 1 3 dns 1 response
|
||||
1487921562.607624000 11 6 1 dns 0 query
|
||||
1487921562.607956000 11 6 1 dns 0 query
|
||||
1487921562.608009000 11 1 6 dns 1 response
|
||||
1487921562.608232000 11 1 6 dns 1 response
|
||||
1487921562.612424000 11 6 1 dns 0 query
|
||||
1487921562.612648000 11 1 6 dns 1 response
|
||||
1487921562.720442000 11 6 1 cldap 3 searchRequest Netlogon
|
||||
1487921562.720706000 11 6 1 cldap 3 searchRequest Netlogon
|
||||
1487921562.721004000 11 6 1 cldap 3 searchRequest Netlogon
|
||||
1487921562.724801000 11 1 6 cldap 5 searchResDone
|
||||
1487921562.728632000 11 1 6 cldap 5 searchResDone
|
||||
1487921562.732508000 11 1 6 cldap 5 searchResDone
|
||||
1487921562.748004000 06 3 1 5 ldap 5 searchResDone
|
||||
1487921562.820387000 06 3 5 1 ldap 2 unbindRequest
|
||||
1487921562.831445000 06 14 6 1 dcerpc 11 Bind
|
||||
1487921562.831565000 06 14 1 6 dcerpc 12 Bind_ack
|
||||
1487921562.831776000 06 14 6 1 epm 3 Map
|
||||
1487921562.832483000 06 14 1 6 epm 3 Map
|
||||
1487921562.833521000 06 15 6 1 dcerpc 11 Bind
|
||||
1487921562.833775000 06 15 1 6 dcerpc 12 Bind_ack
|
||||
1487921562.833955000 06 15 6 1 rpc_netlogon 4 NetrServerReqChallenge
|
||||
1487921562.834039000 06 15 1 6 rpc_netlogon 4 NetrServerReqChallenge
|
||||
1487921562.834325000 06 15 6 1 rpc_netlogon 26 NetrServerAuthenticate3
|
||||
1487921562.834895000 06 15 1 6 rpc_netlogon 26 NetrServerAuthenticate3
|
||||
1487921562.835515000 06 16 6 1 dcerpc 11 Bind
|
||||
1487921562.836417000 06 16 1 6 dcerpc 12 Bind_ack
|
||||
1487921562.836694000 06 16 6 1 rpc_netlogon 21 NetrLogonDummyRoutine1
|
||||
1487921562.836917000 06 16 1 6 rpc_netlogon 21 NetrLogonDummyRoutine1
|
||||
1487921562.852041000 06 14 6 1 epm 3 Map
|
||||
1487921562.852687000 06 14 1 6 epm 3 Map
|
||||
1487921562.876310000 06 16 6 1 rpc_netlogon 29 NetrLogonGetDomainInfo
|
||||
1487921562.880868000 06 18 6 1 kerberos
|
||||
1487921562.881074000 06 16 1 6 rpc_netlogon 29 NetrLogonGetDomainInfo
|
||||
1487921562.884476000 06 19 6 1 ldap 3 searchRequest subschemaSubentry,dsServiceName,namingContexts,defaultNamingContext,schemaNamingContext,configurationNamingContext,rootDomainNamingContext,supportedControl,supportedLDAPVersion,supportedLDAPPolicies,supportedSASLMechanisms,dnsHostName,ldapServiceName,serverName,supportedCapabilities
|
||||
1487921562.885803000 06 18 1 6 kerberos
|
||||
1487921562.892086000 06 19 1 6 ldap 5 searchResDone
|
||||
1487921562.916946000 06 20 6 1 smb 0x72 Negotiate Protocol (0x72)
|
60
python/samba/tests/blackbox/testdata/traffic_learner.expected
vendored
Normal file
60
python/samba/tests/blackbox/testdata/traffic_learner.expected
vendored
Normal file
@ -0,0 +1,60 @@
|
||||
{
|
||||
"ngrams": {
|
||||
"-\t-": {
|
||||
"cldap:3": 1,
|
||||
"ldap:3": 1
|
||||
},
|
||||
"-\tldap:3": {
|
||||
"wait:0": 1
|
||||
},
|
||||
"wait:0\trpc_netlogon:29": {
|
||||
"kerberos:": 1
|
||||
},
|
||||
"rpc_netlogon:29\tkerberos:": {
|
||||
"ldap:3": 1
|
||||
},
|
||||
"cldap:3\twait:0": {
|
||||
"rpc_netlogon:29": 1
|
||||
},
|
||||
"-\tcldap:3": {
|
||||
"cldap:3": 1
|
||||
},
|
||||
"ldap:3\twait:0": {
|
||||
"ldap:2": 1
|
||||
},
|
||||
"cldap:3\tcldap:3": {
|
||||
"cldap:3": 1,
|
||||
"wait:0": 1
|
||||
},
|
||||
"kerberos:\tldap:3": {
|
||||
"-": 1
|
||||
}
|
||||
},
|
||||
"conversation_rate": [
|
||||
2,
|
||||
0.12712717056274414
|
||||
],
|
||||
"dns": {
|
||||
"1": 9,
|
||||
"0": 9
|
||||
},
|
||||
"query_details": {
|
||||
"rpc_netlogon:29": {
|
||||
"-": 1
|
||||
},
|
||||
"cldap:3": {
|
||||
"\t\t\tNetlogon\t\t\t": 3
|
||||
},
|
||||
"ldap:3": {
|
||||
"\t\t\tsubschemaSubentry,dsServiceName,namingContexts,defaultNamingContext,schemaNamingContext,configurationNamingContext,rootDomainNamingContext,supportedControl,supportedLDAPVersion,supportedLDAPPolicies,supportedSASLMechanisms,dnsHostName,ldapServiceName,serverName,supportedCapabilities\t\t\t": 1,
|
||||
"2\tDC,DC\t\tcn\t\t\t": 1
|
||||
},
|
||||
"ldap:2": {
|
||||
"\t\t\t\t\t\t": 1
|
||||
},
|
||||
"kerberos:": {
|
||||
"": 1
|
||||
}
|
||||
},
|
||||
"cumulative_duration": 0.39243292808532715
|
||||
}
|
10
python/samba/tests/blackbox/testdata/traffic_replay.expected
vendored
Normal file
10
python/samba/tests/blackbox/testdata/traffic_replay.expected
vendored
Normal file
@ -0,0 +1,10 @@
|
||||
0.000000 06 3 5 1 ldap 3 searchRequest 2 DC,DC cn
|
||||
0.127127 11 6 1 cldap 3 searchRequest Netlogon
|
||||
0.127391 11 6 1 cldap 3 searchRequest Netlogon
|
||||
0.127689 11 6 1 cldap 3 searchRequest Netlogon
|
||||
0.227072 06 3 5 1 ldap 2 unbindRequest
|
||||
0.282995 06 16 6 1 rpc_netlogon 29 NetrLogonGetDomainInfo
|
||||
0.287553 06 18 6 1 kerberos
|
||||
0.287759 06 16 1 6 rpc_netlogon 29 NetrLogonGetDomainInfo
|
||||
0.291161 06 19 6 1 ldap 3 searchRequest subschemaSubentry,dsServiceName,namingContexts,defaultNamingContext,schemaNamingContext,configurationNamingContext,rootDomainNamingContext,supportedControl,supportedLDAPVersion,supportedLDAPPolicies,supportedSASLMechanisms,dnsHostName,ldapServiceName,serverName,supportedCapabilities
|
||||
0.292488 06 18 1 6 kerberos
|
62
python/samba/tests/blackbox/traffic_learner.py
Normal file
62
python/samba/tests/blackbox/traffic_learner.py
Normal file
@ -0,0 +1,62 @@
|
||||
# Black box tests for script/traffic_leaner
|
||||
#
|
||||
# Copyright (C) Catalyst IT Ltd. 2017
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation; either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
"""Blackbox tests for traffic_leaner"""
|
||||
|
||||
from contextlib import contextmanager
|
||||
import os
|
||||
import tempfile
|
||||
|
||||
from samba.tests import BlackboxTestCase
|
||||
|
||||
LEARNER = "script/traffic_learner"
|
||||
DATA_DIR = "python/samba/tests/blackbox/testdata"
|
||||
|
||||
|
||||
@contextmanager
|
||||
def temp_file(temp_dir):
|
||||
try:
|
||||
tf = tempfile.NamedTemporaryFile(dir=temp_dir)
|
||||
name = tf.name
|
||||
tf.close()
|
||||
yield name
|
||||
finally:
|
||||
if os.path.exists(name):
|
||||
os.remove(name)
|
||||
|
||||
|
||||
class TrafficLearnerTests(BlackboxTestCase):
|
||||
|
||||
def test_no_output_file(self):
|
||||
"""Run the script with no output file specified"""
|
||||
expected = ("No output file was specified to write the model to.\n"
|
||||
"Please specify a filename using the --out option.\n")
|
||||
actual = self.check_output(LEARNER)
|
||||
self.assertEquals(expected, actual)
|
||||
|
||||
def test_model_generation(self):
|
||||
"""Ensure a model is generated from a summary file and it is
|
||||
correct"""
|
||||
|
||||
with temp_file(self.tempdir) as output:
|
||||
summary = os.path.join(DATA_DIR, "traffic-sample-very-short.txt")
|
||||
command = "%s %s --out %s" % (LEARNER, summary, output)
|
||||
self.check_run(command)
|
||||
expected_fn = os.path.join(DATA_DIR, "traffic_learner.expected")
|
||||
expected = open(expected_fn).readlines()
|
||||
actual = open(output).readlines()
|
||||
self.assertEquals(expected, actual)
|
106
python/samba/tests/blackbox/traffic_replay.py
Normal file
106
python/samba/tests/blackbox/traffic_replay.py
Normal file
@ -0,0 +1,106 @@
|
||||
# Black box tests for script/traffic_leaner
|
||||
#
|
||||
# Copyright (C) Catalyst IT Ltd. 2017
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation; either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
"""Blackbox tests for traffic_replay"""
|
||||
|
||||
from contextlib import contextmanager
|
||||
import os
|
||||
import tempfile
|
||||
|
||||
from samba.tests import BlackboxTestCase
|
||||
|
||||
DATA_DIR = "python/samba/tests/blackbox/testdata"
|
||||
SCRIPT = "script/traffic_replay"
|
||||
FIXED = "--fixed-password trafficreplay01%"
|
||||
SERVER = os.environ["SERVER"]
|
||||
PASSWORD = os.environ["PASSWORD"]
|
||||
USER = os.environ["USERNAME"]
|
||||
STD_OPTIONS = "-U%s%%%s %s" % (USER, PASSWORD, SERVER)
|
||||
SUMMARY = os.path.join(DATA_DIR, "traffic-sample-very-short.txt")
|
||||
EXPECTED_NAME = os.path.join(DATA_DIR, "traffic_replay.expected")
|
||||
|
||||
|
||||
@contextmanager
|
||||
def temp_file(temp_dir):
|
||||
try:
|
||||
tf = tempfile.NamedTemporaryFile(dir=temp_dir)
|
||||
name = tf.name
|
||||
tf.close()
|
||||
yield name
|
||||
finally:
|
||||
if os.path.exists(name):
|
||||
os.remove(name)
|
||||
|
||||
|
||||
class TrafficLearnerTests(BlackboxTestCase):
|
||||
|
||||
def tearDown(self):
|
||||
options = "--clean-up"
|
||||
command = "%s %s %s" % (SCRIPT, options, STD_OPTIONS)
|
||||
self.check_run(command)
|
||||
|
||||
def test_generate_users_only(self):
|
||||
"""Ensure the generate users only option functions correctly
|
||||
"""
|
||||
options = ("--generate-users-only --number-of-users 20 "
|
||||
"--number-of-groups 5 --average-groups-per-user 2")
|
||||
command = "%s %s %s %s %s" % (
|
||||
SCRIPT, SUMMARY, options, FIXED, STD_OPTIONS)
|
||||
self.check_run(command)
|
||||
|
||||
def test_summary_generation(self):
|
||||
"""Ensure a summary file is generated and the contents are correct"""
|
||||
|
||||
with temp_file(self.tempdir) as output:
|
||||
options = "--traffic-summary %s " % (output)
|
||||
command = "%s %s %s %s %s" % (
|
||||
SCRIPT, SUMMARY, options, FIXED, STD_OPTIONS)
|
||||
self.check_run(command)
|
||||
expected = (open(EXPECTED_NAME).readlines())
|
||||
actual = open(output).readlines()
|
||||
self.assertEquals(expected, actual)
|
||||
|
||||
def test_summary_replay(self):
|
||||
"""Ensure a summary file can be replayed against a DC
|
||||
"""
|
||||
|
||||
command = "%s %s %s %s" % (SCRIPT, SUMMARY, FIXED, STD_OPTIONS)
|
||||
self.check_run(command)
|
||||
|
||||
def test_summary_replay_no_fixed(self):
|
||||
"""Ensure a summary file with no fixed password fails
|
||||
"""
|
||||
|
||||
command = "%s %s %s" % (SCRIPT, SUMMARY, STD_OPTIONS)
|
||||
self.check_exit_code(command, 1)
|
||||
|
||||
def test_model_replay(self):
|
||||
"""Ensure a model can be replayed against a DC
|
||||
"""
|
||||
|
||||
model = "testdata/traffic-sample-very-short.model"
|
||||
command = "%s %s-D 5 %s %s" % (SCRIPT, model, FIXED, STD_OPTIONS)
|
||||
self.check_run(command)
|
||||
|
||||
def test_generate_users_only_no_password(self):
|
||||
"""Ensure the generate users only fails if no fixed_password supplied"
|
||||
"""
|
||||
options = ("--generate-users-only --number-of-users 20 "
|
||||
"--number-of-groups 5 --average-groups-per-user 2")
|
||||
summary = "testdata/traffic-sample-very-short.txt"
|
||||
command = "%s %s %s %s" % (SCRIPT, summary, options, STD_OPTIONS)
|
||||
self.check_exit_code(command, 1)
|
17
python/samba/tests/emulate/__init__.py
Normal file
17
python/samba/tests/emulate/__init__.py
Normal file
@ -0,0 +1,17 @@
|
||||
# Package initialisation
|
||||
#
|
||||
# Copyright (C) Catalyst IT Ltd. 2017
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation; either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
#
|
160
python/samba/tests/emulate/traffic.py
Normal file
160
python/samba/tests/emulate/traffic.py
Normal file
@ -0,0 +1,160 @@
|
||||
# Unit and integration tests for traffic.py
|
||||
#
|
||||
# Copyright (C) Catalyst IT Ltd. 2017
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation; either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
# from pprint import pprint
|
||||
from cStringIO import StringIO
|
||||
|
||||
import samba.tests
|
||||
|
||||
from samba.emulate import traffic
|
||||
|
||||
|
||||
TEST_FILE = 'testdata/traffic-sample-very-short.txt'
|
||||
|
||||
|
||||
class TrafficEmulatorTests(samba.tests.TestCase):
|
||||
def setUp(self):
|
||||
self.model = traffic.TrafficModel()
|
||||
|
||||
def tearDown(self):
|
||||
del self.model
|
||||
|
||||
def test_parse_ngrams_dns_included(self):
|
||||
model = traffic.TrafficModel()
|
||||
f = open(TEST_FILE)
|
||||
(conversations,
|
||||
interval,
|
||||
duration,
|
||||
dns_counts) = traffic.ingest_summaries([f], dns_mode='include')
|
||||
f.close()
|
||||
model.learn(conversations)
|
||||
expected_ngrams = {
|
||||
('-', '-'): ['dns:0', 'dns:0', 'dns:0', 'ldap:3'],
|
||||
('-', 'dns:0'): ['dns:0', 'dns:0', 'dns:0'],
|
||||
('-', 'ldap:3'): ['wait:0'],
|
||||
('cldap:3', 'cldap:3'): ['cldap:3', 'wait:0'],
|
||||
('cldap:3', 'wait:0'): ['rpc_netlogon:29'],
|
||||
('dns:0', 'dns:0'): ['dns:0', 'dns:0', 'dns:0', 'wait:0'],
|
||||
('dns:0', 'wait:0'): ['cldap:3'],
|
||||
('kerberos:', 'ldap:3'): ['-'],
|
||||
('ldap:3', 'wait:0'): ['ldap:2'],
|
||||
('rpc_netlogon:29', 'kerberos:'): ['ldap:3'],
|
||||
('wait:0', 'cldap:3'): ['cldap:3'],
|
||||
('wait:0', 'rpc_netlogon:29'): ['kerberos:']
|
||||
}
|
||||
expected_query_details = {
|
||||
'cldap:3': [('', '', '', 'Netlogon', '', '', ''),
|
||||
('', '', '', 'Netlogon', '', '', ''),
|
||||
('', '', '', 'Netlogon', '', '', '')],
|
||||
'dns:0': [(), (), (), (), (), (), (), (), ()],
|
||||
'kerberos:': [('',)],
|
||||
'ldap:2': [('', '', '', '', '', '', '')],
|
||||
'ldap:3': [('',
|
||||
'',
|
||||
'',
|
||||
'subschemaSubentry,dsServiceName,namingContexts,'
|
||||
'defaultNamingContext,schemaNamingContext,'
|
||||
'configurationNamingContext,rootDomainNamingContext,'
|
||||
'supportedControl,supportedLDAPVersion,'
|
||||
'supportedLDAPPolicies,supportedSASLMechanisms,'
|
||||
'dnsHostName,ldapServiceName,serverName,'
|
||||
'supportedCapabilities',
|
||||
'',
|
||||
'',
|
||||
''),
|
||||
('2', 'DC,DC', '', 'cn', '', '', '')],
|
||||
'rpc_netlogon:29': [()]
|
||||
}
|
||||
self.maxDiff = 5000
|
||||
ngrams = {k: sorted(v) for k, v in model.ngrams.items()}
|
||||
details = {k: sorted(v) for k, v in model.query_details.items()}
|
||||
|
||||
self.assertEqual(expected_ngrams, ngrams)
|
||||
self.assertEqual(expected_query_details, details)
|
||||
# We use a stringIO instead of a temporary file
|
||||
f = StringIO()
|
||||
model.save(f)
|
||||
|
||||
model2 = traffic.TrafficModel()
|
||||
f.seek(0)
|
||||
model2.load(f)
|
||||
|
||||
self.assertEqual(expected_ngrams, model2.ngrams)
|
||||
self.assertEqual(expected_query_details, model2.query_details)
|
||||
|
||||
def test_parse_ngrams(self):
|
||||
f = open(TEST_FILE)
|
||||
(conversations,
|
||||
interval,
|
||||
duration,
|
||||
dns_counts) = traffic.ingest_summaries([f])
|
||||
f.close()
|
||||
self.model.learn(conversations, dns_counts)
|
||||
# print 'ngrams'
|
||||
# pprint(self.model.ngrams, width=50)
|
||||
# print 'query_details'
|
||||
# pprint(self.model.query_details, width=55)
|
||||
expected_ngrams = {
|
||||
('-', '-'): ['cldap:3', 'ldap:3'],
|
||||
('-', 'cldap:3'): ['cldap:3'],
|
||||
('-', 'ldap:3'): ['wait:0'],
|
||||
('cldap:3', 'cldap:3'): ['cldap:3', 'wait:0'],
|
||||
('cldap:3', 'wait:0'): ['rpc_netlogon:29'],
|
||||
('kerberos:', 'ldap:3'): ['-'],
|
||||
('ldap:3', 'wait:0'): ['ldap:2'],
|
||||
('rpc_netlogon:29', 'kerberos:'): ['ldap:3'],
|
||||
('wait:0', 'rpc_netlogon:29'): ['kerberos:']
|
||||
}
|
||||
|
||||
expected_query_details = {
|
||||
'cldap:3': [('', '', '', 'Netlogon', '', '', ''),
|
||||
('', '', '', 'Netlogon', '', '', ''),
|
||||
('', '', '', 'Netlogon', '', '', '')],
|
||||
'kerberos:': [('',)],
|
||||
'ldap:2': [('', '', '', '', '', '', '')],
|
||||
'ldap:3': [('',
|
||||
'',
|
||||
'',
|
||||
'subschemaSubentry,dsServiceName,namingContexts,'
|
||||
'defaultNamingContext,schemaNamingContext,'
|
||||
'configurationNamingContext,rootDomainNamingContext,'
|
||||
'supportedControl,supportedLDAPVersion,'
|
||||
'supportedLDAPPolicies,supportedSASLMechanisms,'
|
||||
'dnsHostName,ldapServiceName,serverName,'
|
||||
'supportedCapabilities',
|
||||
'',
|
||||
'',
|
||||
''),
|
||||
('2', 'DC,DC', '', 'cn', '', '', '')],
|
||||
'rpc_netlogon:29': [()]
|
||||
}
|
||||
self.maxDiff = 5000
|
||||
ngrams = {k: sorted(v) for k, v in self.model.ngrams.items()}
|
||||
details = {k: sorted(v) for k, v in self.model.query_details.items()}
|
||||
|
||||
self.assertEqual(expected_ngrams, ngrams)
|
||||
self.assertEqual(expected_query_details, details)
|
||||
# We use a stringIO instead of a temporary file
|
||||
f = StringIO()
|
||||
self.model.save(f)
|
||||
|
||||
model2 = traffic.TrafficModel()
|
||||
f.seek(0)
|
||||
model2.load(f)
|
||||
|
||||
self.assertEqual(expected_ngrams, model2.ngrams)
|
||||
self.assertEqual(expected_query_details, model2.query_details)
|
724
python/samba/tests/emulate/traffic_packet.py
Normal file
724
python/samba/tests/emulate/traffic_packet.py
Normal file
@ -0,0 +1,724 @@
|
||||
# Unit and integration tests for traffic_packet.py
|
||||
#
|
||||
# Copyright (C) Catalyst IT Ltd. 2017
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation; either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
import os
|
||||
import shutil
|
||||
import tempfile
|
||||
|
||||
|
||||
from samba.auth import system_session
|
||||
|
||||
from samba.credentials import MUST_USE_KERBEROS, DONT_USE_KERBEROS
|
||||
from samba.emulate import traffic_packets as p
|
||||
from samba.emulate import traffic
|
||||
|
||||
from samba.samdb import SamDB
|
||||
import samba.tests
|
||||
|
||||
|
||||
class TrafficEmulatorPacketTests(samba.tests.TestCase):
|
||||
def setUp(self):
|
||||
super(TrafficEmulatorPacketTests, self).setUp()
|
||||
self.server = os.environ["SERVER"]
|
||||
self.domain = os.environ["DOMAIN"]
|
||||
self.host = os.environ["SERVER_IP"]
|
||||
self.lp = self.get_loadparm()
|
||||
self.session = system_session()
|
||||
self.credentials = self.get_credentials()
|
||||
|
||||
self.ldb = SamDB(url="ldap://%s" % self.host,
|
||||
session_info=self.session,
|
||||
credentials=self.credentials,
|
||||
lp=self.lp)
|
||||
self.domain_sid = self.ldb.get_domain_sid()
|
||||
|
||||
traffic.clean_up_accounts(self.ldb, 1)
|
||||
self.tempdir = tempfile.mkdtemp(prefix="traffic_packet_test_")
|
||||
self.context = traffic.ReplayContext(server=self.server,
|
||||
lp=self.lp,
|
||||
creds=self.credentials,
|
||||
tempdir=self.tempdir,
|
||||
ou=traffic.ou_name(self.ldb, 1),
|
||||
domain_sid=self.domain_sid)
|
||||
|
||||
self.conversation = traffic.Conversation()
|
||||
self.conversation.conversation_id = 1
|
||||
self.machinename = "STGM-1-1"
|
||||
self.machinepass = samba.generate_random_password(32, 32)
|
||||
self.username = "STGU-1-1"
|
||||
self.userpass = samba.generate_random_password(32, 32)
|
||||
account = traffic.ConversationAccounts(
|
||||
self.machinename,
|
||||
self.machinepass,
|
||||
self.username,
|
||||
self.userpass)
|
||||
|
||||
traffic.create_ou(self.ldb, 1)
|
||||
traffic.create_machine_account(self.ldb,
|
||||
1,
|
||||
self.machinename,
|
||||
self.machinepass)
|
||||
traffic.create_user_account(self.ldb,
|
||||
1,
|
||||
self.username,
|
||||
self.userpass)
|
||||
|
||||
self.context.generate_process_local_config(account, self.conversation)
|
||||
|
||||
def tearDown(self):
|
||||
super(TrafficEmulatorPacketTests, self).tearDown()
|
||||
traffic.clean_up_accounts(self.ldb, 1)
|
||||
shutil.rmtree(self.tempdir)
|
||||
|
||||
def test_packet_cldap_03(self):
|
||||
packet = traffic.Packet("0.0\t11\t1\t2\t1\tcldap\t3\tsearchRequest\t")
|
||||
self.assertTrue(p.packet_cldap_3(packet,
|
||||
self.conversation,
|
||||
self. context))
|
||||
|
||||
def test_packet_cldap_05(self):
|
||||
packet = traffic.Packet("0.0\t11\t1\t1\t2\tcldap\t5\tsearchResDone\t")
|
||||
self.assertFalse(p.packet_cldap_5(packet,
|
||||
self.conversation,
|
||||
self. context))
|
||||
|
||||
def test_packet_dcerpc_00(self):
|
||||
packet = traffic.Packet("0.0\t11\t1\t2\t1\tdcerpc\t0\tRequest\t")
|
||||
self.assertFalse(p.packet_dcerpc_0(packet,
|
||||
self.conversation,
|
||||
self. context))
|
||||
|
||||
def test_packet_dcerpc_02(self):
|
||||
packet = traffic.Packet("0.0\t11\t1\t1\t2\tdcerpc\t2\tResponse\t")
|
||||
self.assertFalse(p.packet_dcerpc_2(packet,
|
||||
self.conversation,
|
||||
self. context))
|
||||
|
||||
def test_packet_dcerpc_03(self):
|
||||
packet = traffic.Packet("0.0\t11\t1\t1\t2\tdcerpc\t3\t\t")
|
||||
self.assertFalse(p.packet_dcerpc_3(packet,
|
||||
self.conversation,
|
||||
self. context))
|
||||
|
||||
def test_packet_dcerpc_11(self):
|
||||
packet = traffic.Packet("0.0\t11\t1\t2\t1\tdcerpc\t11\tBind\t")
|
||||
self.assertFalse(p.packet_dcerpc_11(packet,
|
||||
self.conversation,
|
||||
self. context))
|
||||
|
||||
def test_packet_dcerpc_13(self):
|
||||
packet = traffic.Packet("0.0\t11\t1\t2\t1\tdcerpc\t13\t\t")
|
||||
self.assertFalse(p.packet_dcerpc_13(packet,
|
||||
self.conversation,
|
||||
self. context))
|
||||
|
||||
def test_packet_dcerpc_14(self):
|
||||
packet = traffic.Packet(
|
||||
"0.0\t11\t1\t2\t1\tdcerpc\t14\tAlter_context\t")
|
||||
self.assertFalse(p.packet_dcerpc_14(packet,
|
||||
self.conversation,
|
||||
self. context))
|
||||
|
||||
def test_packet_dcerpc_15(self):
|
||||
packet = traffic.Packet(
|
||||
"0.0\t11\t1\t1\t2\tdcerpc\t15\tAlter_context_resp\t")
|
||||
# Set user_creds MUST_USE_KERBEROS to suppress the warning message.
|
||||
self.context.user_creds.set_kerberos_state(MUST_USE_KERBEROS)
|
||||
self.assertFalse(p.packet_dcerpc_15(packet,
|
||||
self.conversation,
|
||||
self. context))
|
||||
|
||||
def test_packet_dcerpc_16(self):
|
||||
packet = traffic.Packet(
|
||||
"0.0\t11\t1\t1\t2\tdcerpc\t16\tAUTH3\t")
|
||||
self.assertFalse(p.packet_dcerpc_16(packet,
|
||||
self.conversation,
|
||||
self. context))
|
||||
|
||||
def test_packet_dns_01(self):
|
||||
packet = traffic.Packet(
|
||||
"0.0\t11\t1\t1\t2\tdns\t1\tresponse\t")
|
||||
self.assertFalse(p.packet_dns_1(packet,
|
||||
self.conversation,
|
||||
self. context))
|
||||
|
||||
def test_packet_drsuapi_00(self):
|
||||
packet = traffic.Packet(
|
||||
"0.0\t06\t1\t1\t2\tdrsuapi\t0\tDsBind\t")
|
||||
self.assertTrue(p.packet_drsuapi_0(packet,
|
||||
self.conversation,
|
||||
self. context))
|
||||
|
||||
def test_packet_drsuapi_01(self):
|
||||
packet = traffic.Packet(
|
||||
"0.0\t06\t1\t1\t2\tdrsuapi\t1\tDsUnBind\t")
|
||||
self.assertTrue(p.packet_drsuapi_1(packet,
|
||||
self.conversation,
|
||||
self. context))
|
||||
|
||||
def test_packet_drsuapi_02(self):
|
||||
packet = traffic.Packet(
|
||||
"0.0\t06\t1\t1\t2\tdrsuapi\t2\tDsReplicaSync\t")
|
||||
self.assertFalse(p.packet_drsuapi_2(packet,
|
||||
self.conversation,
|
||||
self. context))
|
||||
|
||||
def test_packet_drsuapi_03(self):
|
||||
packet = traffic.Packet(
|
||||
"0.0\t06\t1\t1\t2\tdrsuapi\t3\tDsGetNCChanges\t")
|
||||
self.assertFalse(p.packet_drsuapi_3(packet,
|
||||
self.conversation,
|
||||
self. context))
|
||||
|
||||
def test_packet_drsuapi_04(self):
|
||||
packet = traffic.Packet(
|
||||
"0.0\t06\t1\t1\t2\tdrsuapi\t4\tDsReplicaUpdateRefs\t")
|
||||
self.assertFalse(p.packet_drsuapi_4(packet,
|
||||
self.conversation,
|
||||
self. context))
|
||||
|
||||
def test_packet_drsuapi_12(self):
|
||||
packet = traffic.Packet(
|
||||
"0.0\t06\t1\t1\t2\tdrsuapi\t12\tDsCrackNames\t")
|
||||
self.assertTrue(p.packet_drsuapi_12(packet,
|
||||
self.conversation,
|
||||
self. context))
|
||||
|
||||
def test_packet_drsuapi_13(self):
|
||||
packet = traffic.Packet(
|
||||
"0.0\t06\t1\t1\t2\tdrsuapi\t13\tDsWriteAccountSpn\t")
|
||||
self.assertTrue(p.packet_drsuapi_13(packet,
|
||||
self.conversation,
|
||||
self. context))
|
||||
|
||||
def test_packet_epm_03(self):
|
||||
packet = traffic.Packet(
|
||||
"0.0\t06\t1\t1\t2\tepm\t3\tMap\t")
|
||||
self.assertFalse(p.packet_epm_3(packet,
|
||||
self.conversation,
|
||||
self. context))
|
||||
|
||||
def test_packet_kerberos(self):
|
||||
"""Kerberos packets are not generated, but are used as a hint to
|
||||
favour kerberos.
|
||||
"""
|
||||
packet = traffic.Packet(
|
||||
"0.0\t11\t1\t1\t2\tkerberos\t\t\t")
|
||||
self.assertFalse(p.packet_kerberos_(packet,
|
||||
self.conversation,
|
||||
self. context))
|
||||
self.assertEqual(MUST_USE_KERBEROS,
|
||||
self.context.user_creds.get_kerberos_state())
|
||||
self.assertEqual(MUST_USE_KERBEROS,
|
||||
self.context.user_creds_bad.get_kerberos_state())
|
||||
self.assertEqual(MUST_USE_KERBEROS,
|
||||
self.context.machine_creds.get_kerberos_state())
|
||||
self.assertEqual(MUST_USE_KERBEROS,
|
||||
self.context.machine_creds_bad.get_kerberos_state())
|
||||
self.assertEqual(MUST_USE_KERBEROS,
|
||||
self.context.creds.get_kerberos_state())
|
||||
|
||||
# Need to restore kerberos creds on the admin creds otherwise
|
||||
# subsequent tests fail
|
||||
self.credentials.set_kerberos_state(DONT_USE_KERBEROS)
|
||||
|
||||
def test_packet_ldap(self):
|
||||
packet = traffic.Packet(
|
||||
"0.0\t06\t1\t1\t2\tldap\t\t*** Unknown ***\t")
|
||||
self.assertFalse(p.packet_ldap_(packet,
|
||||
self.conversation,
|
||||
self. context))
|
||||
|
||||
def test_packet_ldap_00_sasl(self):
|
||||
packet = traffic.Packet(
|
||||
"0.0\t06\t1\t2\t1\tldap\t0\tbindRequest"
|
||||
"\t\t\t\t\t3\tsasl\t1.3.6.1.5.5.2")
|
||||
self.assertTrue(p.packet_ldap_0(packet,
|
||||
self.conversation,
|
||||
self. context))
|
||||
|
||||
def test_packet_ldap_00_simple(self):
|
||||
packet = traffic.Packet(
|
||||
"0.0\t06\t1\t2\t1\tldap\t0\tbindRequest"
|
||||
"\t\t\t\t\t0\tsimple\t")
|
||||
self.assertTrue(p.packet_ldap_0(packet,
|
||||
self.conversation,
|
||||
self. context))
|
||||
|
||||
def test_packet_ldap_01(self):
|
||||
packet = traffic.Packet(
|
||||
"0.0\t06\t1\t1\t2\tldap\t1\tbindResponse\t")
|
||||
self.assertFalse(p.packet_ldap_1(packet,
|
||||
self.conversation,
|
||||
self. context))
|
||||
|
||||
def test_packet_ldap_02(self):
|
||||
packet = traffic.Packet(
|
||||
"0.0\t06\t1\t2\t1\tldap\t2\tunbindRequest\t")
|
||||
self.assertFalse(p.packet_ldap_2(packet,
|
||||
self.conversation,
|
||||
self. context))
|
||||
|
||||
def test_packet_ldap_03(self):
|
||||
packet = traffic.Packet(
|
||||
"0.0\t06\t1\t2\t1\tldap\t3\tsearchRequest"
|
||||
"\t2\tDC,DC\t\tcn\t\t\t")
|
||||
self.assertTrue(p.packet_ldap_3(packet,
|
||||
self.conversation,
|
||||
self. context))
|
||||
|
||||
def test_packet_ldap_04(self):
|
||||
packet = traffic.Packet(
|
||||
"0.0\t06\t1\t1\t2\tldap\t4\tsearchResEntry\t")
|
||||
self.assertFalse(p.packet_ldap_4(packet,
|
||||
self.conversation,
|
||||
self. context))
|
||||
|
||||
def test_packet_ldap_05(self):
|
||||
packet = traffic.Packet(
|
||||
"0.0\t06\t1\t1\t2\tldap\t5\tsearchResDone\t")
|
||||
self.assertFalse(p.packet_ldap_5(packet,
|
||||
self.conversation,
|
||||
self. context))
|
||||
|
||||
def test_packet_ldap_06(self):
|
||||
packet = traffic.Packet(
|
||||
"0.0\t06\t1\t2\t1\tldap\t6\tmodifyRequest\t"
|
||||
"\t\t\t\t0\tadd")
|
||||
self.assertFalse(p.packet_ldap_6(packet,
|
||||
self.conversation,
|
||||
self. context))
|
||||
|
||||
def test_packet_ldap_07(self):
|
||||
packet = traffic.Packet(
|
||||
"0.0\t06\t1\t1\t2\tldap\t7\tmodifyResponse\t")
|
||||
self.assertFalse(p.packet_ldap_7(packet,
|
||||
self.conversation,
|
||||
self. context))
|
||||
|
||||
def test_packet_ldap_08(self):
|
||||
packet = traffic.Packet(
|
||||
"0.0\t06\t1\t2\t1\tldap\t8\taddRequest\t")
|
||||
self.assertFalse(p.packet_ldap_8(packet,
|
||||
self.conversation,
|
||||
self. context))
|
||||
|
||||
def test_packet_ldap_09(self):
|
||||
packet = traffic.Packet(
|
||||
"0.0\t06\t1\t1\t2\tldap\t9\taddResponse\t")
|
||||
self.assertFalse(p.packet_ldap_9(packet,
|
||||
self.conversation,
|
||||
self. context))
|
||||
|
||||
def test_packet_ldap_16(self):
|
||||
packet = traffic.Packet(
|
||||
"0.0\t06\t1\t2\t1\tldap\t16\tabandonRequest\t")
|
||||
self.assertFalse(p.packet_ldap_16(packet,
|
||||
self.conversation,
|
||||
self. context))
|
||||
|
||||
def test_packet_lsarpc_00(self):
|
||||
packet = traffic.Packet(
|
||||
"0.0\t06\t1\t2\t1\tlsarpc\t0\tlsa_Close\t")
|
||||
self.assertFalse(p.packet_lsarpc_1(packet,
|
||||
self.conversation,
|
||||
self. context))
|
||||
|
||||
def test_packet_lsarpc_01(self):
|
||||
packet = traffic.Packet(
|
||||
"0.0\t06\t1\t2\t1\tlsarpc\t1\tlsa_Delete\t")
|
||||
self.assertFalse(p.packet_lsarpc_1(packet,
|
||||
self.conversation,
|
||||
self. context))
|
||||
|
||||
def test_packet_lsarpc_02(self):
|
||||
packet = traffic.Packet(
|
||||
"0.0\t06\t1\t2\t1\tlsarpc\t2\tlsa_EnumeratePrivileges\t")
|
||||
self.assertFalse(p.packet_lsarpc_2(packet,
|
||||
self.conversation,
|
||||
self. context))
|
||||
|
||||
def test_packet_lsarpc_03(self):
|
||||
packet = traffic.Packet(
|
||||
"0.0\t06\t1\t2\t1\tlsarpc\t3\tlsa_QuerySecurityObject\t")
|
||||
self.assertFalse(p.packet_lsarpc_3(packet,
|
||||
self.conversation,
|
||||
self. context))
|
||||
|
||||
def test_packet_lsarpc_04(self):
|
||||
packet = traffic.Packet(
|
||||
"0.0\t06\t1\t2\t1\tlsarpc\t4\tlsa_SetSecurityObject\t")
|
||||
self.assertFalse(p.packet_lsarpc_4(packet,
|
||||
self.conversation,
|
||||
self. context))
|
||||
|
||||
def test_packet_lsarpc_05(self):
|
||||
packet = traffic.Packet(
|
||||
"0.0\t06\t1\t2\t1\tlsarpc\t5\tlsa_ChangePassword\t")
|
||||
self.assertFalse(p.packet_lsarpc_5(packet,
|
||||
self.conversation,
|
||||
self. context))
|
||||
|
||||
def test_packet_lsarpc_06(self):
|
||||
packet = traffic.Packet(
|
||||
"0.0\t06\t1\t2\t1\tlsarpc\t6\tlsa_OpenPolicy\t")
|
||||
self.assertFalse(p.packet_lsarpc_6(packet,
|
||||
self.conversation,
|
||||
self. context))
|
||||
|
||||
def test_packet_lsarpc_14(self):
|
||||
packet = traffic.Packet(
|
||||
"0.0\t06\t1\t2\t1\tlsarpc\t14\tlsa_LookupNames\t")
|
||||
self.assertTrue(p.packet_lsarpc_14(packet,
|
||||
self.conversation,
|
||||
self. context))
|
||||
|
||||
def test_packet_lsarpc_15(self):
|
||||
packet = traffic.Packet(
|
||||
"0.0\t06\t1\t2\t1\tlsarpc\t15\tlsa_LookupSids\t")
|
||||
self.assertTrue(p.packet_lsarpc_15(packet,
|
||||
self.conversation,
|
||||
self. context))
|
||||
|
||||
def test_packet_lsarpc_39(self):
|
||||
packet = traffic.Packet(
|
||||
"0.0\t06\t1\t2\t1\tlsarpc\t39\tlsa_QueryTrustedDomainInfoBySid\t")
|
||||
self.assertTrue(p.packet_lsarpc_39(packet,
|
||||
self.conversation,
|
||||
self. context))
|
||||
|
||||
def test_packet_lsarpc_40(self):
|
||||
packet = traffic.Packet(
|
||||
"0.0\t06\t1\t2\t1\tlsarpc\t40\tlsa_SetTrustedDomainInfo\t")
|
||||
self.assertFalse(p.packet_lsarpc_40(packet,
|
||||
self.conversation,
|
||||
self. context))
|
||||
|
||||
def test_packet_lsarpc_43(self):
|
||||
packet = traffic.Packet(
|
||||
"0.0\t06\t1\t2\t1\tlsarpc\t43\tlsa_StorePrivateData\t")
|
||||
self.assertFalse(p.packet_lsarpc_43(packet,
|
||||
self.conversation,
|
||||
self. context))
|
||||
|
||||
def test_packet_lsarpc_44(self):
|
||||
packet = traffic.Packet(
|
||||
"0.0\t06\t1\t2\t1\tlsarpc\t44\tlsa_RetrievePrivateData\t")
|
||||
self.assertFalse(p.packet_lsarpc_44(packet,
|
||||
self.conversation,
|
||||
self. context))
|
||||
|
||||
def test_packet_lsarpc_68(self):
|
||||
packet = traffic.Packet(
|
||||
"0.0\t06\t1\t2\t1\tlsarpc\t68\tlsa_LookupNames3\t")
|
||||
self.assertFalse(p.packet_lsarpc_68(packet,
|
||||
self.conversation,
|
||||
self. context))
|
||||
|
||||
def test_packet_lsarpc_76(self):
|
||||
packet = traffic.Packet(
|
||||
"0.0\t06\t1\t2\t1\tlsarpc\t76\tlsa_LookupSids3\t")
|
||||
self.assertTrue(p.packet_lsarpc_76(packet,
|
||||
self.conversation,
|
||||
self. context))
|
||||
|
||||
def test_packet_lsarpc_77(self):
|
||||
packet = traffic.Packet(
|
||||
"0.0\t06\t1\t2\t1\tlsarpc\t77\tlsa_LookupNames4\t")
|
||||
self.assertTrue(p.packet_lsarpc_77(packet,
|
||||
self.conversation,
|
||||
self. context))
|
||||
|
||||
def test_packet_nbns_00(self):
|
||||
packet = traffic.Packet(
|
||||
"0.0\t06\t1\t2\t1\tnbns\t0\tquery\t")
|
||||
self.assertTrue(p.packet_nbns_0(packet,
|
||||
self.conversation,
|
||||
self. context))
|
||||
|
||||
def test_packet_nbns_01(self):
|
||||
packet = traffic.Packet(
|
||||
"0.0\t06\t1\t1\t2\tnbns\t1\tresponse\t")
|
||||
self.assertTrue(p.packet_nbns_0(packet,
|
||||
self.conversation,
|
||||
self. context))
|
||||
|
||||
def test_packet_rpc_netlogon_00(self):
|
||||
packet = traffic.Packet(
|
||||
"0.0\t06\t1\t2\t1\trpc_netlogon\t0\tNetrLogonUasLogon\t")
|
||||
self.assertFalse(p.packet_rpc_netlogon_0(packet,
|
||||
self.conversation,
|
||||
self. context))
|
||||
|
||||
def test_packet_rpc_netlogon_01(self):
|
||||
packet = traffic.Packet(
|
||||
"0.0\t06\t1\t2\t1\trpc_netlogon\t1\tNetrLogonUasLogoff\t")
|
||||
self.assertFalse(p.packet_rpc_netlogon_1(packet,
|
||||
self.conversation,
|
||||
self. context))
|
||||
|
||||
def test_packet_rpc_netlogon_04(self):
|
||||
packet = traffic.Packet(
|
||||
"0.0\t06\t1\t2\t1\trpc_netlogon\t4\tNetrServerReqChallenge\t")
|
||||
self.assertFalse(p.packet_rpc_netlogon_4(packet,
|
||||
self.conversation,
|
||||
self. context))
|
||||
|
||||
def test_packet_rpc_netlogon_14(self):
|
||||
packet = traffic.Packet(
|
||||
"0.0\t06\t1\t2\t1\trpc_netlogon\t14\tNetrLogonControl2\t")
|
||||
self.assertFalse(p.packet_rpc_netlogon_14(packet,
|
||||
self.conversation,
|
||||
self. context))
|
||||
|
||||
def test_packet_rpc_netlogon_15(self):
|
||||
packet = traffic.Packet(
|
||||
"0.0\t06\t1\t2\t1\trpc_netlogon\t15\tNetrServerAuthenticate2\t")
|
||||
self.assertFalse(p.packet_rpc_netlogon_15(packet,
|
||||
self.conversation,
|
||||
self. context))
|
||||
|
||||
def test_packet_rpc_netlogon_21(self):
|
||||
packet = traffic.Packet(
|
||||
"0.0\t06\t1\t2\t1\trpc_netlogon\t21\tNetrLogonDummyRoutine1\t")
|
||||
self.assertFalse(p.packet_rpc_netlogon_21(packet,
|
||||
self.conversation,
|
||||
self. context))
|
||||
|
||||
def test_packet_rpc_netlogon_26(self):
|
||||
packet = traffic.Packet(
|
||||
"0.0\t06\t1\t2\t1\trpc_netlogon\t26\tNetrServerAuthenticate3\t")
|
||||
self.assertFalse(p.packet_rpc_netlogon_26(packet,
|
||||
self.conversation,
|
||||
self. context))
|
||||
|
||||
def test_packet_rpc_netlogon_29(self):
|
||||
packet = traffic.Packet(
|
||||
"0.0\t06\t1\t2\t1\trpc_netlogon\t29\tNetrLogonGetDomainInfo\t")
|
||||
self.assertTrue(p.packet_rpc_netlogon_29(packet,
|
||||
self.conversation,
|
||||
self. context))
|
||||
|
||||
def test_packet_rpc_netlogon_30(self):
|
||||
packet = traffic.Packet(
|
||||
"0.0\t06\t1\t2\t1\trpc_netlogon\t30\tNetrServerPasswordSet2\t")
|
||||
self.assertTrue(p.packet_rpc_netlogon_30(packet,
|
||||
self.conversation,
|
||||
self. context))
|
||||
|
||||
def test_packet_rpc_netlogon_34(self):
|
||||
packet = traffic.Packet(
|
||||
"0.0\t06\t1\t2\t1\trpc_netlogon\t34\tDsrGetDcNameEx2\t")
|
||||
self.assertFalse(p.packet_rpc_netlogon_34(packet,
|
||||
self.conversation,
|
||||
self. context))
|
||||
|
||||
def test_packet_rpc_netlogon_39(self):
|
||||
packet = traffic.Packet(
|
||||
"0.0\t06\t1\t2\t1\trpc_netlogon\t39\tNetrLogonSamLogonEx\t")
|
||||
self.assertTrue(p.packet_rpc_netlogon_39(packet,
|
||||
self.conversation,
|
||||
self. context))
|
||||
|
||||
def test_packet_rpc_netlogon_40(self):
|
||||
packet = traffic.Packet(
|
||||
"0.0\t06\t1\t2\t1\trpc_netlogon\t40\tDsrEnumerateDomainTrusts\t")
|
||||
self.assertTrue(p.packet_rpc_netlogon_40(packet,
|
||||
self.conversation,
|
||||
self. context))
|
||||
|
||||
def test_packet_rpc_netlogon_45(self):
|
||||
packet = traffic.Packet(
|
||||
"0.0\t06\t1\t2\t1\trpc_netlogon\t45\tNetrLogonSamLogonWithFlags\t")
|
||||
self.assertTrue(p.packet_rpc_netlogon_45(packet,
|
||||
self.conversation,
|
||||
self. context))
|
||||
|
||||
def test_packet_samr_00(self):
|
||||
packet = traffic.Packet(
|
||||
"0.0\t06\t1\t2\t1\tsamr\t0\tConnect\t")
|
||||
self.assertTrue(p.packet_samr_0(packet,
|
||||
self.conversation,
|
||||
self. context))
|
||||
|
||||
def test_packet_samr_01(self):
|
||||
packet = traffic.Packet(
|
||||
"0.0\t06\t1\t2\t1\tsamr\t1\tClose\t")
|
||||
self.assertTrue(p.packet_samr_1(packet,
|
||||
self.conversation,
|
||||
self. context))
|
||||
|
||||
def test_packet_samr_03(self):
|
||||
packet = traffic.Packet(
|
||||
"0.0\t06\t1\t2\t1\tsamr\t3\tQuerySecurity\t")
|
||||
self.assertTrue(p.packet_samr_3(packet,
|
||||
self.conversation,
|
||||
self. context))
|
||||
|
||||
def test_packet_samr_05(self):
|
||||
packet = traffic.Packet(
|
||||
"0.0\t06\t1\t2\t1\tsamr\t5\tLookupDomain\t")
|
||||
self.assertTrue(p.packet_samr_5(packet,
|
||||
self.conversation,
|
||||
self. context))
|
||||
|
||||
def test_packet_samr_06(self):
|
||||
packet = traffic.Packet(
|
||||
"0.0\t06\t1\t2\t1\tsamr\t6\tEnumDomains\t")
|
||||
self.assertTrue(p.packet_samr_6(packet,
|
||||
self.conversation,
|
||||
self. context))
|
||||
|
||||
def test_packet_samr_07(self):
|
||||
packet = traffic.Packet(
|
||||
"0.0\t06\t1\t2\t1\tsamr\t7\tOpenDomain\t")
|
||||
self.assertTrue(p.packet_samr_7(packet,
|
||||
self.conversation,
|
||||
self. context))
|
||||
|
||||
def test_packet_samr_08(self):
|
||||
packet = traffic.Packet(
|
||||
"0.0\t06\t1\t2\t1\tsamr\t8\tQueryDomainInfo'\t")
|
||||
self.assertTrue(p.packet_samr_8(packet,
|
||||
self.conversation,
|
||||
self. context))
|
||||
|
||||
def test_packet_samr_14(self):
|
||||
packet = traffic.Packet(
|
||||
"0.0\t06\t1\t2\t1\tsamr\t14\tCreateDomAlias\t")
|
||||
self.assertFalse(p.packet_samr_14(packet,
|
||||
self.conversation,
|
||||
self. context))
|
||||
|
||||
def test_packet_samr_15(self):
|
||||
packet = traffic.Packet(
|
||||
"0.0\t06\t1\t2\t1\tsamr\t15\tEnumDomainAliases\t")
|
||||
self.assertTrue(p.packet_samr_15(packet,
|
||||
self.conversation,
|
||||
self. context))
|
||||
|
||||
def test_packet_samr_16(self):
|
||||
packet = traffic.Packet(
|
||||
"0.0\t06\t1\t2\t1\tsamr\t16\tGetAliasMembership\t")
|
||||
self.assertTrue(p.packet_samr_16(packet,
|
||||
self.conversation,
|
||||
self. context))
|
||||
|
||||
def test_packet_samr_17(self):
|
||||
packet = traffic.Packet(
|
||||
"0.0\t06\t1\t2\t1\tsamr\t17\tLookupNames\t")
|
||||
self.assertTrue(p.packet_samr_17(packet,
|
||||
self.conversation,
|
||||
self. context))
|
||||
|
||||
def test_packet_samr_18(self):
|
||||
packet = traffic.Packet(
|
||||
"0.0\t06\t1\t2\t1\tsamr\t18\tLookupRids\t")
|
||||
self.assertTrue(p.packet_samr_18(packet,
|
||||
self.conversation,
|
||||
self. context))
|
||||
|
||||
def test_packet_samr_19(self):
|
||||
packet = traffic.Packet(
|
||||
"0.0\t06\t1\t2\t1\tsamr\t19\tOpenGroup\t")
|
||||
self.assertTrue(p.packet_samr_19(packet,
|
||||
self.conversation,
|
||||
self. context))
|
||||
|
||||
def test_packet_samr_25(self):
|
||||
packet = traffic.Packet(
|
||||
"0.0\t06\t1\t2\t1\tsamr\t25\tQueryGroupMember\t")
|
||||
self.assertTrue(p.packet_samr_25(packet,
|
||||
self.conversation,
|
||||
self. context))
|
||||
|
||||
def test_packet_samr_34(self):
|
||||
packet = traffic.Packet(
|
||||
"0.0\t06\t1\t2\t1\tsamr\t34\tOpenUser\t")
|
||||
self.assertTrue(p.packet_samr_34(packet,
|
||||
self.conversation,
|
||||
self. context))
|
||||
|
||||
def test_packet_samr_36(self):
|
||||
packet = traffic.Packet(
|
||||
"0.0\t06\t1\t2\t1\tsamr\t36\tQueryUserInfo\t")
|
||||
self.assertTrue(p.packet_samr_36(packet,
|
||||
self.conversation,
|
||||
self. context))
|
||||
|
||||
def test_packet_samr_37(self):
|
||||
packet = traffic.Packet(
|
||||
"0.0\t06\t1\t2\t1\tsamr\t37\tSetUserInfo\t")
|
||||
self.assertFalse(p.packet_samr_37(packet,
|
||||
self.conversation,
|
||||
self. context))
|
||||
|
||||
def test_packet_samr_39(self):
|
||||
packet = traffic.Packet(
|
||||
"0.0\t06\t1\t2\t1\tsamr\t39\tGetGroupsForUser\t")
|
||||
self.assertTrue(p.packet_samr_39(packet,
|
||||
self.conversation,
|
||||
self. context))
|
||||
|
||||
def test_packet_samr_40(self):
|
||||
packet = traffic.Packet(
|
||||
"0.0\t06\t1\t2\t1\tsamr\t40\tQueryDisplayInfo\t")
|
||||
self.assertFalse(p.packet_samr_40(packet,
|
||||
self.conversation,
|
||||
self. context))
|
||||
|
||||
def test_packet_samr_44(self):
|
||||
packet = traffic.Packet(
|
||||
"0.0\t06\t1\t2\t1\tsamr\t44\tGetUserPwInfo\t")
|
||||
self.assertFalse(p.packet_samr_44(packet,
|
||||
self.conversation,
|
||||
self. context))
|
||||
|
||||
def test_packet_samr_57(self):
|
||||
packet = traffic.Packet(
|
||||
"0.0\t06\t1\t2\t1\tsamr\t57\tConnect2\t")
|
||||
self.assertTrue(p.packet_samr_57(packet,
|
||||
self.conversation,
|
||||
self. context))
|
||||
|
||||
def test_packet_samr_64(self):
|
||||
packet = traffic.Packet(
|
||||
"0.0\t06\t1\t2\t1\tsamr\t64\tConnect5\t")
|
||||
self.assertTrue(p.packet_samr_64(packet,
|
||||
self.conversation,
|
||||
self. context))
|
||||
|
||||
def test_packet_samr_68(self):
|
||||
packet = traffic.Packet(
|
||||
"0.0\t06\t1\t2\t1\tsamr\t68\t\t")
|
||||
self.assertFalse(p.packet_samr_68(packet,
|
||||
self.conversation,
|
||||
self. context))
|
||||
|
||||
def test_packet_srvsvc_16(self):
|
||||
packet = traffic.Packet(
|
||||
"0.0\t06\t1\t2\t1\tsrvsvc\t16\tNetShareGetInfo\t")
|
||||
self.assertTrue(p.packet_srvsvc_16(packet,
|
||||
self.conversation,
|
||||
self. context))
|
||||
|
||||
def test_packet_srvsvc_21(self):
|
||||
packet = traffic.Packet(
|
||||
"0.0\t06\t1\t2\t1\tsrvsvc\t21\tNetSrvGetInfo\t")
|
||||
self.assertTrue(p.packet_srvsvc_21(packet,
|
||||
self.conversation,
|
||||
self. context))
|
63
script/traffic_learner
Executable file
63
script/traffic_learner
Executable file
@ -0,0 +1,63 @@
|
||||
#!/usr/bin/env python
|
||||
# Generate a traffic model from a traffic summary file
|
||||
#
|
||||
# Copyright (C) Catalyst IT Ltd. 2017
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation; either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
#
|
||||
|
||||
import sys
|
||||
import argparse
|
||||
|
||||
sys.path.insert(0, "bin/python")
|
||||
from samba.emulate import traffic
|
||||
|
||||
|
||||
def main():
|
||||
parser = argparse.ArgumentParser(description=__doc__,
|
||||
formatter_class=argparse.RawDescriptionHelpFormatter)
|
||||
parser.add_argument('-o', '--out', type=argparse.FileType('w'),
|
||||
help="write model here")
|
||||
parser.add_argument('--dns-mode', choices=['inline', 'count'],
|
||||
help='how to deal with DNS', default='count')
|
||||
parser.add_argument('SUMMARY_FILE', nargs='*', type=argparse.FileType('r'),
|
||||
default=[sys.stdin],
|
||||
help="read from this file (default STDIN)")
|
||||
args = parser.parse_args()
|
||||
|
||||
if not args.out:
|
||||
print >> sys.stdout, "No output file was specified to write the model to."
|
||||
print >> sys.stdout, "Please specify a filename using the --out option."
|
||||
return
|
||||
|
||||
if args.SUMMARY_FILE is sys.stdin:
|
||||
print >> sys.stderr, "reading from STDIN..."
|
||||
|
||||
(conversations,
|
||||
interval,
|
||||
duration,
|
||||
dns_counts) = traffic.ingest_summaries(args.SUMMARY_FILE,
|
||||
dns_mode=args.dns_mode)
|
||||
|
||||
model = traffic.TrafficModel()
|
||||
print >> sys.stderr, "learning model"
|
||||
if args.dns_mode == 'count':
|
||||
model.learn(conversations, dns_counts)
|
||||
else:
|
||||
model.learn(conversations)
|
||||
|
||||
model.save(args.out)
|
||||
|
||||
|
||||
main()
|
362
script/traffic_replay
Executable file
362
script/traffic_replay
Executable file
@ -0,0 +1,362 @@
|
||||
#!/usr/bin/env python
|
||||
# Generates samba network traffic
|
||||
#
|
||||
# Copyright (C) Catalyst IT Ltd. 2017
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation; either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
#
|
||||
import sys
|
||||
import os
|
||||
import optparse
|
||||
import tempfile
|
||||
import shutil
|
||||
|
||||
sys.path.insert(0, "bin/python")
|
||||
|
||||
from samba.emulate import traffic
|
||||
import samba.getopt as options
|
||||
|
||||
|
||||
def main():
|
||||
|
||||
desc = ("Generates network traffic 'conversations' based on <summary-file>"
|
||||
" (which should the output file produced by either traffic_learner"
|
||||
" or traffic_summary.pl). This traffic is sent to <dns-hostname>,"
|
||||
" which is the full DNS hostname of the DC being tested.")
|
||||
|
||||
parser = optparse.OptionParser(
|
||||
"%prog [--help|options] <summary-file> <dns-hostname>",
|
||||
description=desc)
|
||||
|
||||
parser.add_option('--dns-rate', type='float', default=0,
|
||||
help='fire extra DNS packets at this rate')
|
||||
parser.add_option('-B', '--badpassword-frequency',
|
||||
type='float', default=0.0,
|
||||
help='frequency of connections with bad passwords')
|
||||
parser.add_option('-K', '--prefer-kerberos',
|
||||
action="store_true",
|
||||
help='prefer kerberos when authenticating test users')
|
||||
parser.add_option('-I', '--instance-id', type='int', default=0,
|
||||
help='Instance number, when running multiple instances')
|
||||
parser.add_option('-t', '--timing-data',
|
||||
help=('write individual message timing data here '
|
||||
'(- for stdout)'))
|
||||
parser.add_option('--preserve-tempdir', default=False, action="store_true",
|
||||
help='do not delete temporary files')
|
||||
parser.add_option('-F', '--fixed-password',
|
||||
type='string', default=None,
|
||||
help=('Password used for the test users created. '
|
||||
'Required'))
|
||||
parser.add_option('-c', '--clean-up',
|
||||
action="store_true",
|
||||
help='Clean up the generated groups and user accounts')
|
||||
|
||||
model_group = optparse.OptionGroup(parser, 'Traffic Model Options',
|
||||
'These options alter the traffic '
|
||||
'generated when the summary-file is a '
|
||||
'traffic-model (produced by '
|
||||
'traffic_learner)')
|
||||
model_group.add_option('-S', '--scale-traffic', type='float', default=1.0,
|
||||
help='Increase the number of conversations by '
|
||||
'this factor')
|
||||
model_group.add_option('-D', '--duration', type='float', default=None,
|
||||
help=('Run model for this long (approx). '
|
||||
'Default 60s for models'))
|
||||
model_group.add_option('-r', '--replay-rate', type='float', default=1.0,
|
||||
help='Replay the traffic faster by this factor')
|
||||
model_group.add_option('--traffic-summary',
|
||||
help=('Generate a traffic summary file and write '
|
||||
'it here (- for stdout)'))
|
||||
parser.add_option_group(model_group)
|
||||
|
||||
user_gen_group = optparse.OptionGroup(parser, 'Generate User Options',
|
||||
"Add extra user/groups on the DC to "
|
||||
"increase the DB size. These extra "
|
||||
"users aren't used for traffic "
|
||||
"generation.")
|
||||
user_gen_group.add_option('-G', '--generate-users-only',
|
||||
action="store_true",
|
||||
help='Generate the users, but do not replay '
|
||||
'the traffic')
|
||||
user_gen_group.add_option('-n', '--number-of-users', type='int', default=0,
|
||||
help='Total number of test users to create')
|
||||
user_gen_group.add_option('--number-of-groups', type='int', default=0,
|
||||
help='Create this many groups')
|
||||
user_gen_group.add_option('--average-groups-per-user',
|
||||
type='int', default=0,
|
||||
help='Assign the test users to this '
|
||||
'many groups on average')
|
||||
user_gen_group.add_option('--group-memberships', type='int', default=0,
|
||||
help='Total memberships to assign across all '
|
||||
'test users and all groups')
|
||||
parser.add_option_group(user_gen_group)
|
||||
|
||||
sambaopts = options.SambaOptions(parser)
|
||||
parser.add_option_group(sambaopts)
|
||||
parser.add_option_group(options.VersionOptions(parser))
|
||||
credopts = options.CredentialsOptions(parser)
|
||||
parser.add_option_group(credopts)
|
||||
|
||||
# the --no-password credential doesn't make sense for this tool
|
||||
if parser.has_option('-N'):
|
||||
parser.remove_option('-N')
|
||||
|
||||
opts, args = parser.parse_args()
|
||||
|
||||
# First ensure we have reasonable arguments
|
||||
|
||||
if len(args) == 1:
|
||||
summary = None
|
||||
host = args[0]
|
||||
elif len(args) == 2:
|
||||
summary, host = args
|
||||
else:
|
||||
parser.print_usage()
|
||||
return
|
||||
|
||||
if opts.clean_up:
|
||||
print >>sys.stderr, "Removing user and machine accounts"
|
||||
lp = sambaopts.get_loadparm()
|
||||
creds = credopts.get_credentials(lp)
|
||||
ldb = traffic.openLdb(host, creds, lp)
|
||||
traffic.clean_up_accounts(ldb, opts.instance_id)
|
||||
exit(0)
|
||||
|
||||
if summary:
|
||||
if not os.path.exists(summary):
|
||||
print >>sys.stderr, "Summary file %s doesn't exist" % summary
|
||||
sys.exit(1)
|
||||
# the summary-file can be ommitted for --generate-users-only and
|
||||
# --cleanup-up, but it should be specified in all other cases
|
||||
elif not opts.generate_users_only:
|
||||
print >>sys.stderr, "No summary-file specified to replay traffic from"
|
||||
sys.exit(1)
|
||||
|
||||
if not opts.fixed_password:
|
||||
print >>sys.stderr, ("Please use --fixed-password to specify a password"
|
||||
" for the users created as part of this test")
|
||||
sys.exit(1)
|
||||
|
||||
lp = sambaopts.get_loadparm()
|
||||
creds = credopts.get_credentials(lp)
|
||||
|
||||
domain = opts.workgroup
|
||||
if domain:
|
||||
lp.set("workgroup", domain)
|
||||
else:
|
||||
domain = lp.get("workgroup")
|
||||
if domain == "WORKGROUP":
|
||||
print >>sys.stderr, ("NETBIOS domain does not appear to be "
|
||||
"specified, use the --workgroup option")
|
||||
sys.exit(1)
|
||||
|
||||
if not opts.realm and not lp.get('realm'):
|
||||
print >>sys.stderr, "Realm not specified, use the --realm option"
|
||||
sys.exit(1)
|
||||
|
||||
if opts.generate_users_only and not (opts.number_of_users or
|
||||
opts.number_of_groups):
|
||||
print >>sys.stderr, ("Please specify the number of users and/or groups "
|
||||
"to generate.")
|
||||
sys.exit(1)
|
||||
|
||||
if opts.group_memberships and opts.average_groups_per_user:
|
||||
print >>sys.stderr, ("--group-memberships and --average-groups-per-user"
|
||||
" are incompatible options - use one or the other")
|
||||
sys.exit(1)
|
||||
|
||||
if not opts.number_of_groups and opts.average_groups_per_user:
|
||||
print >>sys.stderr, ("--average-groups-per-user requires "
|
||||
"--number-of-groups")
|
||||
sys.exit(1)
|
||||
|
||||
if not opts.number_of_groups and opts.group_memberships:
|
||||
print >>sys.stderr, "--group-memberships requires --number-of-groups"
|
||||
sys.exit(1)
|
||||
|
||||
if opts.timing_data not in ('-', None):
|
||||
try:
|
||||
open(opts.timing_data, 'w').close()
|
||||
except IOError as e:
|
||||
print >> sys.stderr, ("the supplied timing data destination "
|
||||
"(%s) is not writable" % opts.timing_data)
|
||||
print >> sys.stderr, e
|
||||
sys.exit()
|
||||
|
||||
if opts.traffic_summary not in ('-', None):
|
||||
try:
|
||||
open(opts.traffic_summary, 'w').close()
|
||||
except IOError as e:
|
||||
print >> sys.stderr, ("the supplied traffic summary destination "
|
||||
"(%s) is not writable" % opts.traffic_summary)
|
||||
print >> sys.stderr, e
|
||||
sys.exit()
|
||||
|
||||
traffic.DEBUG_LEVEL = opts.debuglevel
|
||||
|
||||
duration = opts.duration
|
||||
if duration is None:
|
||||
duration = 60.0
|
||||
|
||||
# ingest the model or traffic summary
|
||||
if summary:
|
||||
try:
|
||||
conversations, interval, duration, dns_counts = \
|
||||
traffic.ingest_summaries([summary])
|
||||
|
||||
print >>sys.stderr, ("Using conversations from the traffic summary "
|
||||
"file specified")
|
||||
|
||||
# honour the specified duration if it's different to the
|
||||
# capture duration
|
||||
if opts.duration is not None:
|
||||
duration = opts.duration
|
||||
|
||||
except ValueError as e:
|
||||
if not e.message.startswith('need more than'):
|
||||
raise
|
||||
|
||||
model = traffic.TrafficModel()
|
||||
|
||||
try:
|
||||
model.load(summary)
|
||||
except ValueError:
|
||||
print >>sys.stderr, ("Could not parse %s. The summary file "
|
||||
"should be the output from either the "
|
||||
"traffic_summary.pl or "
|
||||
"traffic_learner scripts."
|
||||
% summary)
|
||||
sys.exit()
|
||||
|
||||
print >>sys.stderr, ("Using the specified model file to "
|
||||
"generate conversations")
|
||||
|
||||
conversations = model.generate_conversations(opts.scale_traffic,
|
||||
duration,
|
||||
opts.replay_rate)
|
||||
|
||||
else:
|
||||
conversations = []
|
||||
|
||||
if opts.debuglevel > 5:
|
||||
for c in conversations:
|
||||
for p in c.packets:
|
||||
print " ", p
|
||||
|
||||
print '=' * 72
|
||||
|
||||
if opts.number_of_users and opts.number_of_users < len(conversations):
|
||||
print >>sys.stderr, ("--number-of-users (%d) is less than the "
|
||||
"number of conversations to replay (%d)"
|
||||
% (opts.number_of_users, len(conversations)))
|
||||
sys.exit(1)
|
||||
|
||||
number_of_users = max(opts.number_of_users, len(conversations))
|
||||
max_memberships = number_of_users * opts.number_of_groups
|
||||
|
||||
if not opts.group_memberships and opts.average_groups_per_user:
|
||||
opts.group_memberships = opts.average_groups_per_user * number_of_users
|
||||
print >>sys.stderr, ("Using %d group-memberships based on %u average "
|
||||
"memberships for %d users"
|
||||
% (opts.group_memberships,
|
||||
opts.average_groups_per_user, number_of_users))
|
||||
|
||||
if opts.group_memberships > max_memberships:
|
||||
print >>sys.stderr, ("The group memberships specified (%d) exceeds "
|
||||
"the total users (%d) * total groups (%d)"
|
||||
% (opts.group_memberships, number_of_users,
|
||||
opts.number_of_groups))
|
||||
sys.exit(1)
|
||||
|
||||
try:
|
||||
ldb = traffic.openLdb(host, creds, lp)
|
||||
except:
|
||||
print >>sys.stderr, ("\nInitial LDAP connection failed! Did you supply "
|
||||
"a DNS host name and the correct credentials?")
|
||||
sys.exit(1)
|
||||
|
||||
if opts.generate_users_only:
|
||||
traffic.generate_users_and_groups(ldb,
|
||||
opts.instance_id,
|
||||
opts.fixed_password,
|
||||
opts.number_of_users,
|
||||
opts.number_of_groups,
|
||||
opts.group_memberships)
|
||||
sys.exit()
|
||||
|
||||
tempdir = tempfile.mkdtemp(prefix="samba_tg_")
|
||||
print >>sys.stderr, "Using temp dir %s" % tempdir
|
||||
|
||||
traffic.generate_users_and_groups(ldb,
|
||||
opts.instance_id,
|
||||
opts.fixed_password,
|
||||
number_of_users,
|
||||
opts.number_of_groups,
|
||||
opts.group_memberships)
|
||||
|
||||
accounts = traffic.generate_replay_accounts(ldb,
|
||||
opts.instance_id,
|
||||
len(conversations),
|
||||
opts.fixed_password)
|
||||
|
||||
statsdir = traffic.mk_masked_dir(tempdir, 'stats')
|
||||
|
||||
if opts.traffic_summary:
|
||||
if opts.traffic_summary == '-':
|
||||
summary_dest = sys.stdout
|
||||
else:
|
||||
summary_dest = open(opts.traffic_summary, 'w')
|
||||
|
||||
print >>sys.stderr, "Writing traffic summary"
|
||||
summaries = []
|
||||
for c in conversations:
|
||||
summaries += c.replay_as_summary_lines()
|
||||
|
||||
summaries.sort()
|
||||
for (time, line) in summaries:
|
||||
print >>summary_dest, line
|
||||
|
||||
exit(0)
|
||||
|
||||
traffic.replay(conversations, host,
|
||||
lp=lp,
|
||||
creds=creds,
|
||||
accounts=accounts,
|
||||
dns_rate=opts.dns_rate,
|
||||
duration=duration,
|
||||
badpassword_frequency=opts.badpassword_frequency,
|
||||
prefer_kerberos=opts.prefer_kerberos,
|
||||
statsdir=statsdir,
|
||||
domain=domain,
|
||||
base_dn=ldb.domain_dn(),
|
||||
ou=traffic.ou_name(ldb, opts.instance_id),
|
||||
tempdir=tempdir,
|
||||
domain_sid=ldb.get_domain_sid())
|
||||
|
||||
if opts.timing_data == '-':
|
||||
timing_dest = sys.stdout
|
||||
elif opts.timing_data is None:
|
||||
timing_dest = None
|
||||
else:
|
||||
timing_dest = open(opts.timing_data, 'w')
|
||||
|
||||
print >>sys.stderr, "Generating statistics"
|
||||
traffic.generate_stats(statsdir, timing_dest)
|
||||
|
||||
if not opts.preserve_tempdir:
|
||||
print >>sys.stderr, "Removing temporary directory"
|
||||
shutil.rmtree(tempdir)
|
||||
|
||||
|
||||
main()
|
@ -132,10 +132,6 @@ planpythontestsuite("none", "samba.tests.kcc.graph_utils")
|
||||
planpythontestsuite("none", "samba.tests.kcc.kcc_utils")
|
||||
planpythontestsuite("none", "samba.tests.kcc.ldif_import_export")
|
||||
plantestsuite("wafsamba.duplicate_symbols", "none", [os.path.join(srcdir(), "buildtools/wafsamba/test_duplicate_symbol.sh")])
|
||||
plantestsuite(
|
||||
"script.traffic_summary", "none",
|
||||
[os.path.join(srcdir(), "script/tests/test_traffic_summary.sh"),
|
||||
configuration])
|
||||
planpythontestsuite("none", "samba.tests.glue", py3_compatible=True)
|
||||
planpythontestsuite("none", "samba.tests.tdb_util", py3_compatible=True)
|
||||
|
||||
|
@ -688,6 +688,18 @@ for env in ["ad_dc_ntvfs", "vampire_dc", "promoted_dc"]:
|
||||
planoldpythontestsuite(env,
|
||||
"samba.tests.py_credentials",
|
||||
extra_args=['-U"$USERNAME%$PASSWORD"'])
|
||||
planoldpythontestsuite("ad_dc_ntvfs",
|
||||
"samba.tests.emulate.traffic",
|
||||
extra_args=['-U"$USERNAME%$PASSWORD"'])
|
||||
planoldpythontestsuite("ad_dc_ntvfs",
|
||||
"samba.tests.emulate.traffic_packet",
|
||||
extra_args=['-U"$USERNAME%$PASSWORD"'])
|
||||
planoldpythontestsuite("ad_dc_ntvfs",
|
||||
"samba.tests.blackbox.traffic_replay",
|
||||
extra_args=['-U"$USERNAME%$PASSWORD"'])
|
||||
planoldpythontestsuite("ad_dc_ntvfs",
|
||||
"samba.tests.blackbox.traffic_learner",
|
||||
extra_args=['-U"$USERNAME%$PASSWORD"'])
|
||||
|
||||
plantestsuite_loadlist("samba4.ldap.python(ad_dc_ntvfs)", "ad_dc_ntvfs", [python, os.path.join(samba4srcdir, "dsdb/tests/python/ldap.py"), '$SERVER', '-U"$USERNAME%$PASSWORD"', '--workgroup=$DOMAIN', '$LOADLIST', '$LISTOPT'])
|
||||
plantestsuite_loadlist("samba4.tokengroups.krb5.python(ad_dc_ntvfs)", "ad_dc_ntvfs:local", [python, os.path.join(samba4srcdir, "dsdb/tests/python/token_group.py"), '$SERVER', '-U"$USERNAME%$PASSWORD"', '--workgroup=$DOMAIN', '-k', 'yes', '$LOADLIST', '$LISTOPT'])
|
||||
|
60
testdata/traffic-sample-very-short.model
vendored
Normal file
60
testdata/traffic-sample-very-short.model
vendored
Normal file
@ -0,0 +1,60 @@
|
||||
{
|
||||
"ngrams": {
|
||||
"-\t-": {
|
||||
"cldap:3": 1,
|
||||
"ldap:3": 1
|
||||
},
|
||||
"-\tldap:3": {
|
||||
"wait:0": 1
|
||||
},
|
||||
"wait:0\trpc_netlogon:29": {
|
||||
"kerberos:": 1
|
||||
},
|
||||
"rpc_netlogon:29\tkerberos:": {
|
||||
"ldap:3": 1
|
||||
},
|
||||
"cldap:3\twait:0": {
|
||||
"rpc_netlogon:29": 1
|
||||
},
|
||||
"-\tcldap:3": {
|
||||
"cldap:3": 1
|
||||
},
|
||||
"ldap:3\twait:0": {
|
||||
"ldap:2": 1
|
||||
},
|
||||
"cldap:3\tcldap:3": {
|
||||
"cldap:3": 1,
|
||||
"wait:0": 1
|
||||
},
|
||||
"kerberos:\tldap:3": {
|
||||
"-": 1
|
||||
}
|
||||
},
|
||||
"conversation_rate": [
|
||||
2,
|
||||
0.12712717056274414
|
||||
],
|
||||
"dns": {
|
||||
"1": 9,
|
||||
"0": 9
|
||||
},
|
||||
"query_details": {
|
||||
"rpc_netlogon:29": {
|
||||
"-": 1
|
||||
},
|
||||
"cldap:3": {
|
||||
"\t\t\tNetlogon\t\t\t": 3
|
||||
},
|
||||
"ldap:3": {
|
||||
"\t\t\tsubschemaSubentry,dsServiceName,namingContexts,defaultNamingContext,schemaNamingContext,configurationNamingContext,rootDomainNamingContext,supportedControl,supportedLDAPVersion,supportedLDAPPolicies,supportedSASLMechanisms,dnsHostName,ldapServiceName,serverName,supportedCapabilities\t\t\t": 1,
|
||||
"2\tDC,DC\t\tcn\t\t\t": 1
|
||||
},
|
||||
"ldap:2": {
|
||||
"\t\t\t\t\t\t": 1
|
||||
},
|
||||
"kerberos:": {
|
||||
"": 1
|
||||
}
|
||||
},
|
||||
"cumulative_duration": 0.39243292808532715
|
||||
}
|
50
testdata/traffic-sample-very-short.txt
vendored
Normal file
50
testdata/traffic-sample-very-short.txt
vendored
Normal file
@ -0,0 +1,50 @@
|
||||
1487921562.592126000 11 3 1 dns 0 query
|
||||
1487921562.592285000 11 1 4 dns 0 query
|
||||
1487921562.592636000 11 4 1 dns 1 response
|
||||
1487921562.592911000 11 1 3 dns 1 response
|
||||
1487921562.593315000 06 3 5 1 ldap 3 searchRequest 2 DC,DC cn
|
||||
1487921562.596247000 11 3 1 dns 0 query
|
||||
1487921562.596362000 11 1 4 dns 0 query
|
||||
1487921562.596697000 11 4 1 dns 1 response
|
||||
1487921562.596921000 11 1 3 dns 1 response
|
||||
1487921562.598308000 11 3 1 dns 0 query
|
||||
1487921562.598414000 11 1 4 dns 0 query
|
||||
1487921562.598729000 11 4 1 dns 1 response
|
||||
1487921562.598963000 11 1 3 dns 1 response
|
||||
1487921562.607624000 11 6 1 dns 0 query
|
||||
1487921562.607956000 11 6 1 dns 0 query
|
||||
1487921562.608009000 11 1 6 dns 1 response
|
||||
1487921562.608232000 11 1 6 dns 1 response
|
||||
1487921562.612424000 11 6 1 dns 0 query
|
||||
1487921562.612648000 11 1 6 dns 1 response
|
||||
1487921562.720442000 11 6 1 cldap 3 searchRequest Netlogon
|
||||
1487921562.720706000 11 6 1 cldap 3 searchRequest Netlogon
|
||||
1487921562.721004000 11 6 1 cldap 3 searchRequest Netlogon
|
||||
1487921562.724801000 11 1 6 cldap 5 searchResDone
|
||||
1487921562.728632000 11 1 6 cldap 5 searchResDone
|
||||
1487921562.732508000 11 1 6 cldap 5 searchResDone
|
||||
1487921562.748004000 06 3 1 5 ldap 5 searchResDone
|
||||
1487921562.820387000 06 3 5 1 ldap 2 unbindRequest
|
||||
1487921562.831445000 06 14 6 1 dcerpc 11 Bind
|
||||
1487921562.831565000 06 14 1 6 dcerpc 12 Bind_ack
|
||||
1487921562.831776000 06 14 6 1 epm 3 Map
|
||||
1487921562.832483000 06 14 1 6 epm 3 Map
|
||||
1487921562.833521000 06 15 6 1 dcerpc 11 Bind
|
||||
1487921562.833775000 06 15 1 6 dcerpc 12 Bind_ack
|
||||
1487921562.833955000 06 15 6 1 rpc_netlogon 4 NetrServerReqChallenge
|
||||
1487921562.834039000 06 15 1 6 rpc_netlogon 4 NetrServerReqChallenge
|
||||
1487921562.834325000 06 15 6 1 rpc_netlogon 26 NetrServerAuthenticate3
|
||||
1487921562.834895000 06 15 1 6 rpc_netlogon 26 NetrServerAuthenticate3
|
||||
1487921562.835515000 06 16 6 1 dcerpc 11 Bind
|
||||
1487921562.836417000 06 16 1 6 dcerpc 12 Bind_ack
|
||||
1487921562.836694000 06 16 6 1 rpc_netlogon 21 NetrLogonDummyRoutine1
|
||||
1487921562.836917000 06 16 1 6 rpc_netlogon 21 NetrLogonDummyRoutine1
|
||||
1487921562.852041000 06 14 6 1 epm 3 Map
|
||||
1487921562.852687000 06 14 1 6 epm 3 Map
|
||||
1487921562.876310000 06 16 6 1 rpc_netlogon 29 NetrLogonGetDomainInfo
|
||||
1487921562.880868000 06 18 6 1 kerberos
|
||||
1487921562.881074000 06 16 1 6 rpc_netlogon 29 NetrLogonGetDomainInfo
|
||||
1487921562.884476000 06 19 6 1 ldap 3 searchRequest subschemaSubentry,dsServiceName,namingContexts,defaultNamingContext,schemaNamingContext,configurationNamingContext,rootDomainNamingContext,supportedControl,supportedLDAPVersion,supportedLDAPPolicies,supportedSASLMechanisms,dnsHostName,ldapServiceName,serverName,supportedCapabilities
|
||||
1487921562.885803000 06 18 1 6 kerberos
|
||||
1487921562.892086000 06 19 1 6 ldap 5 searchResDone
|
||||
1487921562.916946000 06 20 6 1 smb 0x72 Negotiate Protocol (0x72)
|
Loading…
Reference in New Issue
Block a user