mirror of
https://github.com/jedisct1/dnsblast.git
synced 2025-01-18 12:05:35 +00:00
Initial import
This commit is contained in:
parent
4ef61ea9f9
commit
e26b3863b7
17
.gitignore
vendored
17
.gitignore
vendored
@ -1,12 +1,7 @@
|
|||||||
# Compiled Object files
|
*.dSYM
|
||||||
*.slo
|
*.log
|
||||||
*.lo
|
|
||||||
*.o
|
*.o
|
||||||
|
*.s
|
||||||
# Compiled Dynamic libraries
|
*~
|
||||||
*.so
|
.DS_Store
|
||||||
|
dnsblast
|
||||||
# Compiled Static libraries
|
|
||||||
*.lai
|
|
||||||
*.la
|
|
||||||
*.a
|
|
||||||
|
15
COPYING
Normal file
15
COPYING
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2012 Frank Denis <j at pureftpd dot org>
|
||||||
|
*
|
||||||
|
* Permission to use, copy, modify, and distribute this software for any
|
||||||
|
* purpose with or without fee is hereby granted, provided that the above
|
||||||
|
* copyright notice and this permission notice appear in all copies.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||||
|
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||||
|
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||||
|
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||||
|
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||||
|
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||||
|
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||||
|
*/
|
21
Makefile
Normal file
21
Makefile
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
|
||||||
|
OPTIMIZATION ?= -O2
|
||||||
|
STDFLAGS ?= -std=c99
|
||||||
|
DEBUGFLAGS ?= -Waggregate-return -Wcast-align -Wcast-qual \
|
||||||
|
-Wchar-subscripts -Wcomment -Wimplicit -Wmissing-declarations \
|
||||||
|
-Wmissing-prototypes -Wnested-externs -Wparentheses -Wwrite-strings \
|
||||||
|
-Wformat=2 -Wall -Wextra
|
||||||
|
|
||||||
|
CFLAGS ?= $(OPTIMIZATION) $(STDFLAGS) $(DEBUGFLAGS)
|
||||||
|
|
||||||
|
all: dnsblast
|
||||||
|
|
||||||
|
dnsblast: Makefile dnsblast.o
|
||||||
|
$(CC) dnsblast.o -o dnsblast $(LDFLAGS)
|
||||||
|
|
||||||
|
dnsblast.o: Makefile dnsblast.c dns.h dnsblast.h
|
||||||
|
$(CC) -c dnsblast.c -o dnsblast.o $(CFLAGS)
|
||||||
|
|
||||||
|
clean:
|
||||||
|
rm -f dnsblast *.a *.d *.o
|
||||||
|
rm -rf *.dSYM
|
105
README.markdown
Normal file
105
README.markdown
Normal file
@ -0,0 +1,105 @@
|
|||||||
|
DNSBlast
|
||||||
|
========
|
||||||
|
|
||||||
|
`dnsblast` is a simple and really stupid load testing tool for DNS resolvers.
|
||||||
|
|
||||||
|
Give it the IP address of a resolver, the total number of queries you
|
||||||
|
want to send, the rate (number of packets per second), and `dnsblast`
|
||||||
|
will tell you how well the resolver is able to keep up.
|
||||||
|
|
||||||
|
What it is:
|
||||||
|
-----------
|
||||||
|
|
||||||
|
- a tool to spot bugs in DNS resolvers.
|
||||||
|
- a tool to help you tune and tweak DNS resolver code in order to
|
||||||
|
improve it in some way.
|
||||||
|
- a tool to help you tune and tweak the operating system so that it
|
||||||
|
can properly cope with a slew of UDP packets.
|
||||||
|
- a tool to test a resolver with real queries sent to the real and
|
||||||
|
scary interwebz, not to a sandbox.
|
||||||
|
|
||||||
|
What it is not:
|
||||||
|
---------------
|
||||||
|
|
||||||
|
- a tool for DoS'ing resolvers. There are way more efficient ways to
|
||||||
|
achieve this.
|
||||||
|
- a benchmarking tool.
|
||||||
|
- a tool for testing anything but how the server behaves under load.
|
||||||
|
If you need a serious test suite, take a look at what Unbound
|
||||||
|
provides.
|
||||||
|
|
||||||
|
What it does:
|
||||||
|
-------------
|
||||||
|
|
||||||
|
It sends queries for names like
|
||||||
|
`<random char><random char><random char><random char>.com`.
|
||||||
|
|
||||||
|
Yes, that's 4 random characters dot com. Doing that achieves a
|
||||||
|
NXDOMAIN vs "oh cool, we got a reply" ratio that is surprisingly close
|
||||||
|
to the one you get from real queries made by real users.
|
||||||
|
|
||||||
|
Different query types are sent. Namely SOA, A, AAA, MX and TXT, and
|
||||||
|
the probability that a query type gets picked is also close to its
|
||||||
|
probability in the real world.
|
||||||
|
|
||||||
|
Names are occasionally repeated, also to get closer to what happens in
|
||||||
|
the real world. That triggers resolver code responsible for queuing
|
||||||
|
and merging queries.
|
||||||
|
|
||||||
|
The test is deterministic: the exact same sequence of packets is sent
|
||||||
|
every time you fire up `dnsblast`. The magic resides in the power of
|
||||||
|
the `rand()` function with a fixed seed.
|
||||||
|
|
||||||
|
What it does not:
|
||||||
|
-----------------
|
||||||
|
|
||||||
|
It doesn't support DNSSec, it doesn't send anything using TCP, it
|
||||||
|
doesn't pay attention to the content the resolver sents.
|
||||||
|
|
||||||
|
Fuzzing:
|
||||||
|
--------
|
||||||
|
|
||||||
|
In addition, `dnsblast` can send malformed queries.
|
||||||
|
|
||||||
|
Most resolvers just ignore these, so don't expect a high
|
||||||
|
replies/queries ratio. But this feature can also help spotting bugs.
|
||||||
|
|
||||||
|
The fuzzer is really, really, really simple, though. It just changes
|
||||||
|
some random bytes. It doesn't even pay attention to the server's
|
||||||
|
behavior.
|
||||||
|
|
||||||
|
How do I compile it?
|
||||||
|
--------------------
|
||||||
|
|
||||||
|
Type: `make`.
|
||||||
|
|
||||||
|
The code it trivial and should be fairly portable, although it only
|
||||||
|
gets tested on OSX and OpenBSD.
|
||||||
|
|
||||||
|
How do I use it?
|
||||||
|
----------------
|
||||||
|
|
||||||
|
To send a shitload of queries to 127.0.0.1:
|
||||||
|
dnsblast 127.0.0.1
|
||||||
|
|
||||||
|
To send 50,000 queries to 127.0.0.1:
|
||||||
|
|
||||||
|
dnsblast 127.0.0.1 50000
|
||||||
|
|
||||||
|
To send 50,000 queries at a rate of 100 queries per second:
|
||||||
|
|
||||||
|
dnsblast 127.0.0.1 50000 100
|
||||||
|
|
||||||
|
To send 50,000 queries at a rate of 100 qps to a non standard-port, like 5353:
|
||||||
|
|
||||||
|
dnsblast 127.0.0.1 50000 100 5353
|
||||||
|
|
||||||
|
To send malformed packets, prepend "fuzz":
|
||||||
|
|
||||||
|
dnsblast fuzz 127.0.0.1
|
||||||
|
dnsblast fuzz 127.0.0.1 50000
|
||||||
|
dnsblast fuzz 127.0.0.1 50000 100
|
||||||
|
dnsblast fuzz 127.0.0.1 50000 100 5353
|
||||||
|
|
||||||
|
If you think that it desperately cries for `getopt()`, you're absolutely correct.
|
||||||
|
|
@ -1,4 +0,0 @@
|
|||||||
dnsblast
|
|
||||||
========
|
|
||||||
|
|
||||||
A simple and stupid load testing tool for DNS resolvers
|
|
33
dns.h
Normal file
33
dns.h
Normal file
@ -0,0 +1,33 @@
|
|||||||
|
|
||||||
|
#ifndef __DNS_H__
|
||||||
|
#define __DNS_H__
|
||||||
|
|
||||||
|
#include <sys/types.h>
|
||||||
|
#include <inttypes.h>
|
||||||
|
|
||||||
|
#define TYPE_A 1U
|
||||||
|
#define TYPE_SOA 6U
|
||||||
|
#define TYPE_MX 15U
|
||||||
|
#define TYPE_TXT 16U
|
||||||
|
#define TYPE_AAAA 28U
|
||||||
|
|
||||||
|
#define FLAGS_OPCODE_QUERY 0x0
|
||||||
|
#define FLAGS_RECURSION_DESIRED 0x100
|
||||||
|
|
||||||
|
#define CLASS_IN 1U
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
uint16_t id;
|
||||||
|
uint16_t flags;
|
||||||
|
uint16_t qdcount;
|
||||||
|
uint16_t ancount;
|
||||||
|
uint16_t nscount;
|
||||||
|
uint16_t arcount;
|
||||||
|
} __attribute__((__packed__)) DNS_Header;
|
||||||
|
|
||||||
|
#define PUT_HTONS(dst, val) do { \
|
||||||
|
*dst++ = val >> 8; \
|
||||||
|
*dst++ = val & 0xff; \
|
||||||
|
} while (0)
|
||||||
|
|
||||||
|
#endif
|
379
dnsblast.c
Normal file
379
dnsblast.c
Normal file
@ -0,0 +1,379 @@
|
|||||||
|
|
||||||
|
#include "dnsblast.h"
|
||||||
|
|
||||||
|
static unsigned long long
|
||||||
|
get_nanoseconds(void)
|
||||||
|
{
|
||||||
|
struct timeval tv;
|
||||||
|
gettimeofday(&tv, NULL);
|
||||||
|
|
||||||
|
return tv.tv_sec * 1000000000LL + tv.tv_usec * 1000LL;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
init_context(Context * const context, const int sock,
|
||||||
|
const struct addrinfo * const ai, const _Bool fuzz)
|
||||||
|
{
|
||||||
|
const unsigned long long now = get_nanoseconds();
|
||||||
|
*context = (Context) {
|
||||||
|
.received_packets = 0UL, .sent_packets = 0UL,
|
||||||
|
.last_status_update = now, .startup_date = now,
|
||||||
|
.sock = sock, .ai = ai, .fuzz = fuzz, .sending = 1
|
||||||
|
};
|
||||||
|
|
||||||
|
DNS_Header * const question_header = (DNS_Header *) context->question;
|
||||||
|
*question_header = (DNS_Header) {
|
||||||
|
.flags = htons(FLAGS_OPCODE_QUERY | FLAGS_RECURSION_DESIRED),
|
||||||
|
.qdcount = htons(1U), .ancount = 0U, .nscount = 0U, .arcount = 0U
|
||||||
|
};
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
find_name_component_len(const char *name)
|
||||||
|
{
|
||||||
|
int name_pos = 0;
|
||||||
|
|
||||||
|
while (name[name_pos] != '.' && name[name_pos] != 0) {
|
||||||
|
if (name_pos >= UCHAR_MAX) {
|
||||||
|
return EOF;
|
||||||
|
}
|
||||||
|
name_pos++;
|
||||||
|
}
|
||||||
|
return name_pos;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
encode_name(unsigned char ** const encoded_ptr, size_t encoded_size,
|
||||||
|
const char * const name)
|
||||||
|
{
|
||||||
|
unsigned char *encoded = *encoded_ptr;
|
||||||
|
const char *name_current = name;
|
||||||
|
int name_current_pos;
|
||||||
|
|
||||||
|
assert(encoded_size > (size_t) 0U);
|
||||||
|
encoded_size--;
|
||||||
|
for (;;) {
|
||||||
|
name_current_pos = find_name_component_len(name);
|
||||||
|
if (name_current_pos == EOF ||
|
||||||
|
encoded_size <= (size_t) name_current_pos) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
*encoded++ = (unsigned char) name_current_pos;
|
||||||
|
memcpy(encoded, name_current, name_current_pos);
|
||||||
|
encoded_size -= name_current_pos - (size_t) 1U;
|
||||||
|
encoded += name_current_pos;
|
||||||
|
if (name_current[name_current_pos] == 0) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
name_current += name_current_pos + 1U;
|
||||||
|
}
|
||||||
|
*encoded++ = 0;
|
||||||
|
*encoded_ptr = encoded;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
fuzz(unsigned char * const question, const size_t packet_size)
|
||||||
|
{
|
||||||
|
int p = REFUZZ_PROBABILITY;
|
||||||
|
|
||||||
|
do {
|
||||||
|
question[rand() % packet_size] = rand() % 0xff;
|
||||||
|
} while (rand() < p && (p = p / 2) > 0);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
blast(Context * const context, const char * const name, const uint16_t type)
|
||||||
|
{
|
||||||
|
unsigned char * const question = context->question;
|
||||||
|
DNS_Header * const question_header = (DNS_Header *) question;
|
||||||
|
unsigned char * const question_data = question + sizeof *question_header;
|
||||||
|
const size_t sizeof_question_data =
|
||||||
|
sizeof question - sizeof *question_header;
|
||||||
|
|
||||||
|
question_header->id = context->id++;
|
||||||
|
unsigned char *msg = question_data;
|
||||||
|
assert(sizeof_question_data > (size_t) 2U);
|
||||||
|
encode_name(&msg, sizeof_question_data - (size_t) 2U, name);
|
||||||
|
PUT_HTONS(msg, type);
|
||||||
|
PUT_HTONS(msg, CLASS_IN);
|
||||||
|
const size_t packet_size = (size_t) (msg - question);
|
||||||
|
|
||||||
|
if (context->fuzz != 0) {
|
||||||
|
fuzz(question, packet_size);
|
||||||
|
}
|
||||||
|
while (sendto(context->sock, question, packet_size, 0,
|
||||||
|
context->ai->ai_addr, context->ai->ai_addrlen)
|
||||||
|
!= (ssize_t) packet_size) {
|
||||||
|
if (errno != EAGAIN && errno != EINTR) {
|
||||||
|
perror("sendto");
|
||||||
|
exit(EXIT_FAILURE);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
context->sent_packets++;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
usage(void) {
|
||||||
|
puts("\nUsage: dnsblast [fuzz] <host> [<count>] [<pps>] [<port>]\n");
|
||||||
|
exit(EXIT_SUCCESS);
|
||||||
|
}
|
||||||
|
|
||||||
|
static struct addrinfo *
|
||||||
|
resolve(const char * const host, const char * const port)
|
||||||
|
{
|
||||||
|
struct addrinfo *ai, hints;
|
||||||
|
|
||||||
|
memset(&hints, 0, sizeof hints);
|
||||||
|
hints = (struct addrinfo) {
|
||||||
|
.ai_family = AF_UNSPEC, .ai_flags = 0, .ai_socktype = SOCK_DGRAM,
|
||||||
|
.ai_protocol = IPPROTO_UDP
|
||||||
|
};
|
||||||
|
const int gai_err = getaddrinfo(host, port, &hints, &ai);
|
||||||
|
if (gai_err != 0) {
|
||||||
|
fprintf(stderr, "[%s:%s]: [%s]\n", host, port, gai_strerror(gai_err));
|
||||||
|
exit(EXIT_FAILURE);
|
||||||
|
}
|
||||||
|
return ai;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
get_random_name(char * const name, size_t name_size)
|
||||||
|
{
|
||||||
|
const char charset_alnum[36] = "abcdefghijklmnopqrstuvwxyz0123456789";
|
||||||
|
|
||||||
|
assert(name_size > (size_t) 8U);
|
||||||
|
const int r1 = rand(), r2 = rand();
|
||||||
|
name[0] = charset_alnum[(r1) % sizeof charset_alnum];
|
||||||
|
name[1] = charset_alnum[(r1 >> 16) % sizeof charset_alnum];
|
||||||
|
name[2] = charset_alnum[(r2) % sizeof charset_alnum];
|
||||||
|
name[3] = charset_alnum[(r2 >> 16) % sizeof charset_alnum];
|
||||||
|
name[4] = '.'; name[5] = 'c'; name[6] = 'o'; name[7] = 'm';
|
||||||
|
name[8] = 0;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static uint16_t
|
||||||
|
get_random_type(void)
|
||||||
|
{
|
||||||
|
const size_t weighted_types_len =
|
||||||
|
sizeof weighted_types / sizeof weighted_types[0];
|
||||||
|
size_t i = 0U;
|
||||||
|
const int rnd = rand();
|
||||||
|
int pos = RAND_MAX;
|
||||||
|
|
||||||
|
do {
|
||||||
|
pos -= weighted_types[i].weight;
|
||||||
|
if (rnd > pos) {
|
||||||
|
return weighted_types[i].type;
|
||||||
|
}
|
||||||
|
} while (++i < weighted_types_len);
|
||||||
|
|
||||||
|
return weighted_types[rand() % weighted_types_len].type;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
get_sock(const char * const host, const char * const port,
|
||||||
|
struct addrinfo ** const ai_ref)
|
||||||
|
{
|
||||||
|
int flag = 1;
|
||||||
|
int sock;
|
||||||
|
|
||||||
|
*ai_ref = resolve(host, port);
|
||||||
|
sock = socket((*ai_ref)->ai_family, (*ai_ref)->ai_socktype,
|
||||||
|
(*ai_ref)->ai_protocol);
|
||||||
|
if (sock == -1) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
setsockopt(sock, SOL_SOCKET, SO_RCVBUFFORCE,
|
||||||
|
&(int[]) { MAX_UDP_BUFFER_SIZE }, sizeof (int));
|
||||||
|
setsockopt(sock, SOL_SOCKET, SO_SNDBUFFORCE,
|
||||||
|
&(int[]) { MAX_UDP_BUFFER_SIZE }, sizeof (int));
|
||||||
|
#if defined(IP_MTU_DISCOVER) && defined(IP_PMTUDISC_DONT)
|
||||||
|
setsockopt(sock, IPPROTO_IP, IP_MTU_DISCOVER,
|
||||||
|
&(int[]) { IP_PMTUDISC_DONT }, sizeof (int));
|
||||||
|
#elif defined(IP_DONTFRAG)
|
||||||
|
setsockopt(sock, IPPROTO_IP, IP_DONTFRAG, &(int[]) { 0 }, sizeof (int));
|
||||||
|
#endif
|
||||||
|
assert(ioctl(sock, FIONBIO, &flag) == 0);
|
||||||
|
|
||||||
|
return sock;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
receive(Context * const context)
|
||||||
|
{
|
||||||
|
unsigned char buf[MAX_UDP_DATA_SIZE];
|
||||||
|
|
||||||
|
while (recv(context->sock, buf, sizeof buf, 0) == (ssize_t) -1) {
|
||||||
|
if (errno == EAGAIN) {
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
assert(errno == EINTR);
|
||||||
|
}
|
||||||
|
context->received_packets++;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
update_status(const Context * const context)
|
||||||
|
{
|
||||||
|
const unsigned long long now = get_nanoseconds();
|
||||||
|
const unsigned long long elapsed = now - context->startup_date;
|
||||||
|
unsigned long long rate =
|
||||||
|
context->received_packets * 1000000000ULL / elapsed;
|
||||||
|
if (rate > context->pps) {
|
||||||
|
rate = context->pps;
|
||||||
|
}
|
||||||
|
printf("Sent: [%lu] - Received: [%lu] - Reply rate: [%llu pps] - "
|
||||||
|
"Ratio: [%.2f%%] \r",
|
||||||
|
context->sent_packets, context->received_packets, rate,
|
||||||
|
(double) context->received_packets * 100.0 /
|
||||||
|
(double) context->sent_packets);
|
||||||
|
fflush(stdout);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
periodically_update_status(Context * const context)
|
||||||
|
{
|
||||||
|
unsigned long long now = get_nanoseconds();
|
||||||
|
|
||||||
|
if (now - context->last_status_update < UPDATE_STATUS_PERIOD) {
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
update_status(context);
|
||||||
|
context->last_status_update = now;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
empty_receive_queue(Context * const context)
|
||||||
|
{
|
||||||
|
while (receive(context) == 0)
|
||||||
|
;
|
||||||
|
periodically_update_status(context);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
throttled_receive(Context * const context)
|
||||||
|
{
|
||||||
|
unsigned long long now = get_nanoseconds(), now2;
|
||||||
|
const unsigned long long elapsed = now - context->startup_date;
|
||||||
|
const unsigned long long max_packets =
|
||||||
|
context->pps * elapsed / 1000000000UL;
|
||||||
|
|
||||||
|
if (context->sending == 1 && context->sent_packets <= max_packets) {
|
||||||
|
empty_receive_queue(context);
|
||||||
|
}
|
||||||
|
const unsigned long long excess = context->sent_packets - max_packets;
|
||||||
|
const unsigned long long time_to_wait = excess / context->pps;
|
||||||
|
int remaining_time = (int) (time_to_wait * 1000ULL);
|
||||||
|
int ret;
|
||||||
|
struct pollfd pfd = { .fd = context->sock,
|
||||||
|
.events = POLLIN | POLLERR };
|
||||||
|
if (context->sending == 0) {
|
||||||
|
remaining_time = -1;
|
||||||
|
} else if (remaining_time < 0) {
|
||||||
|
remaining_time = 0;
|
||||||
|
}
|
||||||
|
do {
|
||||||
|
ret = poll(&pfd, (nfds_t) 1, remaining_time);
|
||||||
|
if (ret == 0) {
|
||||||
|
periodically_update_status(context);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
if (ret == -1) {
|
||||||
|
if (errno != EAGAIN && errno != EINTR) {
|
||||||
|
perror("poll");
|
||||||
|
exit(EXIT_FAILURE);
|
||||||
|
}
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
assert(ret == 1);
|
||||||
|
empty_receive_queue(context);
|
||||||
|
now2 = get_nanoseconds();
|
||||||
|
remaining_time -= (now2 - now) / 1000;
|
||||||
|
now = now2;
|
||||||
|
} while (remaining_time > 0);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
main(int argc, char *argv[])
|
||||||
|
{
|
||||||
|
char name[100U] = ".";
|
||||||
|
Context context;
|
||||||
|
struct addrinfo *ai;
|
||||||
|
const char *host;
|
||||||
|
const char *port = "domain";
|
||||||
|
unsigned long pps = ULONG_MAX;
|
||||||
|
unsigned long send_count = ULONG_MAX;
|
||||||
|
int sock;
|
||||||
|
uint16_t type;
|
||||||
|
_Bool fuzz = 0;
|
||||||
|
|
||||||
|
if (argc < 2 || argc > 6) {
|
||||||
|
usage();
|
||||||
|
}
|
||||||
|
if (strcasecmp(argv[1], "fuzz") == 0) {
|
||||||
|
fuzz = 1;
|
||||||
|
argv++;
|
||||||
|
argc--;
|
||||||
|
}
|
||||||
|
if (argc < 1) {
|
||||||
|
usage();
|
||||||
|
}
|
||||||
|
host = argv[1];
|
||||||
|
if (argc > 2) {
|
||||||
|
send_count = strtoul(argv[2], NULL, 10);
|
||||||
|
}
|
||||||
|
if (argc > 3) {
|
||||||
|
pps = strtoul(argv[3], NULL, 10);
|
||||||
|
}
|
||||||
|
if (argc > 4) {
|
||||||
|
port = argv[4];
|
||||||
|
}
|
||||||
|
if ((sock = get_sock(host, port, &ai)) == -1) {
|
||||||
|
perror("Oops");
|
||||||
|
exit(EXIT_FAILURE);
|
||||||
|
}
|
||||||
|
init_context(&context, sock, ai, fuzz);
|
||||||
|
context.pps = pps;
|
||||||
|
srand(0U);
|
||||||
|
assert(send_count > 0UL);
|
||||||
|
do {
|
||||||
|
if (rand() > REPEATED_NAME_PROBABILITY) {
|
||||||
|
get_random_name(name, sizeof name);
|
||||||
|
}
|
||||||
|
type = get_random_type();
|
||||||
|
blast(&context, name, type);
|
||||||
|
throttled_receive(&context);
|
||||||
|
} while (--send_count > 0UL);
|
||||||
|
update_status(&context);
|
||||||
|
|
||||||
|
context.sending = 0;
|
||||||
|
while (context.sent_packets != context.received_packets) {
|
||||||
|
throttled_receive(&context);
|
||||||
|
}
|
||||||
|
freeaddrinfo(ai);
|
||||||
|
assert(close(sock) == 0);
|
||||||
|
update_status(&context);
|
||||||
|
putchar('\n');
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
74
dnsblast.h
Normal file
74
dnsblast.h
Normal file
@ -0,0 +1,74 @@
|
|||||||
|
|
||||||
|
#ifndef __DNSBLAST_H__
|
||||||
|
#define __DNSBLAST_H__ 1
|
||||||
|
|
||||||
|
#include <sys/types.h>
|
||||||
|
#include <sys/ioctl.h>
|
||||||
|
#include <sys/poll.h>
|
||||||
|
#include <sys/socket.h>
|
||||||
|
#include <sys/time.h>
|
||||||
|
|
||||||
|
#include <netdb.h>
|
||||||
|
#include <netinet/in.h>
|
||||||
|
|
||||||
|
#include <assert.h>
|
||||||
|
#include <errno.h>
|
||||||
|
#include <inttypes.h>
|
||||||
|
#include <limits.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <stddef.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <time.h>
|
||||||
|
|
||||||
|
#include "dns.h"
|
||||||
|
|
||||||
|
#define MAX_UDP_DATA_SIZE (0xffff - 20U - 8U)
|
||||||
|
|
||||||
|
#ifndef UPDATE_STATUS_PERIOD
|
||||||
|
# define UPDATE_STATUS_PERIOD 500000000ULL
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef MAX_UDP_BUFFER_SIZE
|
||||||
|
# define MAX_UDP_BUFFER_SIZE 2097152
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#define REPEATED_NAME_PROBABILITY (int) ((RAND_MAX * 13854LL) / 100000LL)
|
||||||
|
#define REFUZZ_PROBABILITY (int) ((RAND_MAX * 500LL) / 100000LL)
|
||||||
|
|
||||||
|
typedef struct Context_ {
|
||||||
|
unsigned char question[MAX_UDP_DATA_SIZE];
|
||||||
|
const struct addrinfo *ai;
|
||||||
|
unsigned long long last_status_update;
|
||||||
|
unsigned long long startup_date;
|
||||||
|
unsigned long pps;
|
||||||
|
unsigned long received_packets;
|
||||||
|
unsigned long sent_packets;
|
||||||
|
int sock;
|
||||||
|
uint16_t id;
|
||||||
|
_Bool fuzz;
|
||||||
|
_Bool sending;
|
||||||
|
} Context;
|
||||||
|
|
||||||
|
typedef struct WeightedType_ {
|
||||||
|
int weight;
|
||||||
|
uint16_t type;
|
||||||
|
} WeightedType;
|
||||||
|
|
||||||
|
const WeightedType weighted_types[] = {
|
||||||
|
{ .type = TYPE_A, .weight = (int) ((RAND_MAX * 77662LL) / 100000LL) },
|
||||||
|
{ .type = TYPE_SOA, .weight = (int) ((RAND_MAX * 803LL) / 100000LL) },
|
||||||
|
{ .type = TYPE_MX, .weight = (int) ((RAND_MAX * 5073LL) / 100000LL) },
|
||||||
|
{ .type = TYPE_TXT, .weight = (int) ((RAND_MAX * 2604LL) / 100000LL) },
|
||||||
|
{ .type = TYPE_AAAA, .weight = (int) ((RAND_MAX * 13858LL) / 100000LL) }
|
||||||
|
};
|
||||||
|
|
||||||
|
#ifndef SO_RCVBUFFORCE
|
||||||
|
# define SO_RCVBUFFORCE SO_RCVBUF
|
||||||
|
#endif
|
||||||
|
#ifndef SO_SNDBUFFORCE
|
||||||
|
# define SO_SNDBUFFORCE SO_SNDBUF
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif
|
Loading…
x
Reference in New Issue
Block a user