Skip to content
Snippets Groups Projects
Commit 3cd215da authored by Daniel Salzman's avatar Daniel Salzman
Browse files

Clean project directory

parent ef5413cb
No related branches found
No related tags found
No related merge requests found
Coding style
============
* Indentation: TAB (8 spaces width)
* Braces: K&R, 1TBS
* Max line width: 80 chars
* Pointer asterisk attached to the name of the variable
* Own structures/types: _t suffix (f.e. nameserver_t)
* Header guard format: _KNOTD_HEADER_H_
* Spaces around binary operators
* Space between keyword and bracket (f.e. "if (predicate)")
* No space between variable and typecast (f.e. "return (int)val;")
To sum it up, Linux KNF is used, see [1].
[1] Linux Coding Style:
http://kerneltrap.org/files/Jeremy/CodingStyle.txt
AStyle command format
=====================
astyle --style=1tbs -t8 -w -p -H -U -j --align-pointer=name
Doxygen
=======
* Format: Qt-style
* "\brief", not "@brief"
* "/*!", not "/**"
* Order of sections
* brief description
* long description
* notes
* warnings
* parameters
* return values
* todos
* Always use \brief (no autobrief)
* Indent text (using spaces only) in multiple-line sections
* In multi-line comments, opening line (/*!) should be empty
* One empty line between two consecutive sections
* Struct and union members documented on the same line if the comment fits
* Use \retval (or more of them) instead of \return
if the function returns some distinct values
(such as 0 for no error, -1 for something else, etc.)
Example
=======
/*!
* \brief Some structure.
*
* Longer description.
*/
struct some_struct {
/*!
* \brief This comment does not fit on the same line as the member
* as it is rather large.
*/
int fd;
int flags; /*!< Flags. */
};
/*!
* \brief Brief description of some function.
*
* Longer description.
*
* \note This function is deprecated.
*
* \warning Do not use this function!
*
* \param param1 Some parameter.
* \param param2 Other parameter. This one has rather large comment,
* so its next line is indented for better readability.
*
* \retval 0 on success.
* \retval -1 if some error occured.
*
* \todo Remove (deprecated).
*/
This diff is collapsed.
This diff is collapsed.
......@@ -16,11 +16,6 @@ Optional packages:
Dependencies for building documentation:
* texinfo
Knot DNS requires compiler to support atomic intrinsics.
GCC version at least 4.1 supports legacy atomic builtins, however 4.7
or newer is preferred.
Clang supports atomics since version 2.9.
By default Knot DNS is distributed with a slower zone file parser because of
smaller source file and quick compile time. In most cases it is sufficient.
If you plan to process large zone files, we recommend to build Knot DNS
......@@ -30,119 +25,49 @@ and it is normal if the C compiler takes much more time (minutes).
Installation
============
Knot DNS may be already included in your operating system distribution and
Knot DNS may already be included in your operating system distribution and
therefore can be installed from packages (Linux) or ports (BSD). This is
always preferred unless you want to test the latest features, contribute to
Knot development, or you just know what you are doing.
Following sections describe how to build Knot DNS from the source code.
Installation on Debian based distributions
==========================================
The following steps should work (verified in VirtualBox only)
for the distribution/architecture/release combinations as listed bellow.
1) Install prerequisites
----------------------------------------------
Debian (AMD64, I386) 6.0.2.1 (squeeze)
Ubuntu Server (AMD64, I386) 10.04 LTS
Ubuntu Desktop (AMD64, I386) 10.04 LTS
----------------------------------------------
# Make the system up-to-date
Debian based distributions
--------------------------
Update the system:
$ sudo apt-get update
$ sudo apt-get upgrade
# Ensure all prerequisites are installed
$ sudo apt-get install git-core autoconf libtool flex bison libssl-dev liburcu-dev
Install prerequisites:
$ sudo apt-get install git-core libtool autoconf flex bison libssl-dev liburcu-dev
# Install optional packages (POSIX 1003.1e capabilities)
$ sudo apt-get install libcap-ng-dev
Install optional packages:
($ sudo apt-get install libcap-ng-dev)
($ sudo apt-get install ragel)
# If the liburcu-dev package is not present, install it directly
# Get the source code
$ git clone git://git.nic.cz/knot-dns.git
$ cd knot-dns
$ autoreconf -if
$ ./configure
$ make
$ sudo make install
$ sudo ldconfig
Installation on Fedora
======================
Notice: Knot DNS is available in official distribution repositories since
Fedora 18 (Spherical Cow). Search for 'knot' package.
All commands with the '#' prompt should be run as the root user, commands with
the '$' prompt should be run as a regular non-root user.
If the liburcu-dev package is not present, install it from the source code
(http://lttng.org/urcu)
Fedora like distributions
-------------------------
Update the system:
# yum upgrade
$ yum upgrade
Ensure all base development tools are available:
# yum install @buildsys-build
$ yum install @buildsys-build
Ensure all prerequisites are installed:
# yum install libtool autoconf flex bison openssl-devel userspace-rcu-devel
You can also install optional packages:
# yum install libcap-ng-devel ragel
Download the latest source code from Git and compile it:
$ git clone git://git.nic.cz/knot-dns.git
$ cd knot
$ autoreconf -if
$ ./configure
$ make
Install Knot DNS into system (run only if you really know what these commands do):
# make install
# ldconfig
$ yum install libtool autoconf flex bison openssl-devel userspace-rcu-devel
Installation on BSD
===================
Not all prerequisites are available as ports on BSD.
- liburcu must be compiled from sources
- version 0.6.4 compiles on BSD without any source code modifications
- in case of x86_64 build, CFLAGS nad build type has to be set appropriately.
$ CFLAGS=-fPIC ./configure --build amd64
- flex must be newer version from ports that support reentrant parsers
Knot DNS requires more recent version of flex from ports, to prevent name clash
specify flex destination.
$ cd <knot sources>
$ autoreconf -if
$ ./configure
$ make && sudo make install
It is also present in port tree, so you can install it from there.
$ cd /usr/ports/dns/knot
$ sudo make install
Installation on OpenBSD/NetBSD
==============================
Also works for OS X, if you don't want to install gcc from ports.
Prerequisites:
- flex and bison from packages
$ mkdir liburcu && cd liburcu
$ wget "http://lttng.org/files/urcu/userspace-rcu-0.8.0.tar.bz2"
$ autoconf && ./configure && make && sudo make install
$ # or follow installation instructions in INSTALL
Knot DNS installation is the same as in previous section (Installation on BSD).
Installation on OS X
====================
Install optional packages:
($ yum install libcap-ng-devel)
($ yum install ragel)
OS X
----
Not all prerequisites are preinstalled for OS X.
- liburcu must be compiled from sources
- liburcu requires gcc-4.6 from MacPorts, as it depends on __thread keyword
$ CC=gcc-mp-4.6 ARCH=x86_64 ./configure
......@@ -152,32 +77,54 @@ Not all prerequisites are preinstalled for OS X.
Compiling Knot DNS with gcc-mp-4.6 is recommended, but not necessary.
2) Install Knot DNS
Knot DNS requires compiler to support atomic intrinsics.
GCC version at least 4.1 supports legacy atomic builtins, however 4.7
or newer is preferred.
Clang supports atomics since version 2.9.
Get the source code:
$ git clone git://git.nic.cz/knot-dns.git
Or extract source package to knot-dns directory
Compile Knot
$ cd knot-dns
$ autoreconf -if
$ ./configure
$ make
Install Knot DNS into system:
$ sudo make install
$ sudo ldconfig
Running
=======
First, each server needs configuration file.
Please see samples/knot.sample.conf for reference.
More examples can be found in samples/knot.full.conf
1) Each server needs configuration file. Please see samples/knot.sample.conf
for reference or samples/knot.full.conf for more examples.
Configuration file has to specify:
* storage for PID files, journal files etc.
* network interfaces
* served zones
$ cp samples/knot.sample.conf myserver.conf
$ vim myserver.conf # or your favourite text editor
$ knotd -h # see what it can do
- storage for PID files, journal files etc.
- network interfaces
- served zones
Second, prepare working directory.
E.g. use the default config file:
$ cd /etc/knot
$ mv knot.sample.conf knot.conf
Modify the config:
$ vim knot.conf
$ mkdir -p /tmp/knot-minimal/samples; cp samples/example.com.zone /tmp/knot-minimal/samples/
2) Prepare working directory
$ mv example.com.zone /var/lib/knot/
Third, let's start the server. This can be done by running the 'knotd' command.
3) Start the server. This can be done by running the 'knotd' command.
Alternatively, your distribution should have an init script available, if you've
installed Knot using a binary package.
Lets start our server in foreground to see if it runs:
Start Knot in foreground to see if it runs:
$ knotd -c myserver.conf
For more information, refer to the user manual.
For more information, refer to the user manual or:
$ knotc -h
$ knotd -h
Knot DNS THANKS file
Knot DNS was originally written by CZ.NIC Labs. It would not be what
Knot DNS was originally written by CZ.NIC Labs. It would not be what
it is today without the invaluable help of these people, who have
reported problems, suggested improvements, or submitted actual code.
Please help us keep this list complete and free from errors. Also see
Please help us keep this list complete and free from errors. Also see
the AUTHORS file for the list of people with contributions significant
enough to warrant copyright assignment.
......@@ -12,26 +10,3 @@ Geert Hendrickx geert@hendrickx.be
Michal 'vorner' Vaner vorner@ucw.cz
Ondřej Caletka ondrej@caletka.cz
Anand Buddhdev anandb@ripe.net
================
Local Variables:
mode: text
coding: utf-8
End:
Copyright (C) 2011 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
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/>.
--style=1tbs
--indent=tab=8
--indent-preprocessor
--pad-oper
--pad-header
--unpad-paren
--add-brackets
--convert-tabs
--align-pointer=name
--mode=c
--lineend=linux
......@@ -86,3 +86,5 @@ void estimator_rrset_memsize_wrap(const scanner_t *scanner);
void estimator_free_trie_node(value_t *val, void *data);
#endif /* _KNOT_ESTIMATOR_H_ */
/*! @} */
/*
TCP query version of queryperf
querytcp.c
fujiwara@jprs.co.jp
2009.08.12
version 0.4
queryperf for tcp query
This program measures DNS server performance of TCP query.
o Running environment:
Development environment:
Linux
FreeBSD
MacOS X 10.3.4
o How to make:
Linux: gcc -D_LINUX -Wall -O2 -g -lm -o querytcp querytcp.c
FreeBSD: gcc -Wall -O2 -g -lm -o querytcp querytcp.c
MacOS X: gcc -Wall -O2 -g -lm -lresolv -o querytcp querytcp.c
o changes
2010/6/7: Linux compatibility
2009/8/12: Remove use of res_mkquery
*/
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <strings.h>
#include <netdb.h>
#include <errno.h>
#include <math.h>
#include <err.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <arpa/nameser.h>
#include <arpa/inet.h>
#include <resolv.h>
#include <sys/time.h>
#include <sys/socket.h>
#include <fcntl.h>
#include <math.h>
#ifndef NO_SYS_SELECT_H
#include <sys/select.h>
#endif
#ifdef __APPLE__
#include <nameser8_compat.h>
#endif
#ifndef ns_t_soa
#define ns_t_soa T_SOA
#endif
#ifndef ns_t_ns
#define ns_t_ns T_NS
#endif
#ifndef ns_c_in
#define ns_c_in C_IN
#endif
#ifdef NOINET6
#undef AF_INET6
#endif
#define Global
#ifndef PACKETSZ
#define PACKETSZ 512
#endif
/* debug.c */
void hexdump(char *title, unsigned char *memory, int len)
{
printf("[ %s ", title);
while (len-- > 0)
printf("%02x ", *memory++);
printf("]\n");
}
#define Xmalloc(size) Xrealloc(NULL, size)
void *Xrealloc(void *p, int size)
{
int sz;
sz = (size > 0) ? size : -size;
if (p == NULL) {
p = malloc(sz);
} else {
p = realloc(p, sz);
}
if (p == NULL) {
char buf[100];
snprintf(buf, sizeof buf, "size=%d", size);
perror(buf);
exit(1);
}
if (size < 0)
memset(p, 0, sz);
return p;
}
/* strlcpy() emulation for Linux. */
#ifdef _LINUX
static inline size_t strlcpy(char *destination, const char *source, size_t size)
{
if(strncpy(destination, source, size) == NULL)
return 0;
return size;
}
#endif
/*
NULL ... returns NULL
*/
char *Xstrdup(char *p)
{
char *q;
int len;
if (p == NULL)
return NULL;
len = strlen(p) + 1;
q = Xmalloc(len);
strlcpy(q, p, len);
return q;
}
typedef int64_t timediff_t;
/* packet buffer */
static struct timeval current;
static struct timeval start, send_finished;;
static fd_set fdset0r, fdset0w;
static int nfds;
static struct sockaddr_storage remote;
static int remote_len = 0;
static int finished = 0;
static timediff_t Timeout = 10*1000000LL;
unsigned short counter = 0;
#define UpdateCurrentTime gettimeofday(&current, NULL)
#define RECVBUFSIZ 65537
#define SENDBUFSIZ 512
struct dnsheader {
unsigned short id; // 2
unsigned char flag1, flag2; // 2
unsigned short qdcount, ancount, nscount, arcount; // 8
};
/*
+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
|QR| Opcode |AA|TC|RD|RA| Z | RCODE |
+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
*/
struct queries {
struct tcpdns {
unsigned short len;
union {
struct dnsheader h;
unsigned char dnsdata[SENDBUFSIZ];
} u;
} send;
unsigned char recvbuf[RECVBUFSIZ];
int sendlen;
int sent_flag:1;
int tcpstate:2;
int fd;
int rpos;
int wpos;
int no;
struct timeval sent; /* long tv_sec, long tv_usec */
};
struct queries *Queries;
#define NQUERY 100
#define TCP_NONE 0
#define TCP_WRITABLE 1
#define TCP_READABLE 2
/* input */
char *ServerName = "127.0.0.1";
char *ServerPort = "53";
int family = PF_UNSPEC;
char *datafile = NULL;
int TimeLimit = 20;
int EDNS0 = 0;
int DNSSEC = 0;
int recursion = 0;
FILE *fp = NULL;
int datafileloop = 0;
int verbose = 0;
int nQueries = 120;
int printrcode = 0;
char *rcodestr[]= {
"NOERROR", "FormatError", "ServerFailure", "NameError",
"NotImplemented", "Reused", "RCODE06", "RCODE07",
"RCODE08", "RCODE09", "RCODE10", "RCODE11",
"RCODE12", "RCODE13", "RCODE14", "RCODE15",
};
timediff_t timediff(struct timeval *a, struct timeval *b) /* u sec */
{
return (a->tv_sec - b->tv_sec) * 1000000 + (a->tv_usec - b->tv_usec);
}
#define TIMEOUTERROR -10000
#define ERROROFFSET -20000
#define ERRZEROREAD -30000
uint64_t countrcode[16];
uint64_t response_size_sum = 0;
uint64_t response_size_sum2 = 0;
uint64_t countanswers = 0;
uint64_t countqueries = 0;
uint64_t countzeroread = 0;
uint64_t counttimeout = 0;
uint64_t counterror = 0;
int response_size_min = 0;
int response_size_max = 0;
void register_response(struct queries *q, int timeout, char *note)
{
u_char *p;
int size;
int rcode;
int id;
id = ntohs(q->send.u.h.id);
if (note == NULL)
note = "";
countqueries++;
if (timeout >= 0) {
p = q->recvbuf;
NS_GET16(size, p);
response_size_sum += size;
response_size_sum2 += size * size;
if (response_size_min == 0 || response_size_min > size)
response_size_min = size;
if (response_size_max == 0 || response_size_max < size)
response_size_max = size;
rcode = p[3] & 0x0f;
countrcode[rcode]++;
countanswers++;
if (verbose)
printf("recv response id=%d rcode=%d size=%d rtt=%d\n", id, rcode, size, timeout);
} else if (timeout == ERRZEROREAD) {
countzeroread++;
if (verbose)
printf("recv response id=%d zeroread\n", id);
} else if (timeout == TIMEOUTERROR) {
counttimeout++;
if (verbose)
printf("recv timeout id=%d %lld usec\n", id, timediff(&current, &q->sent));
} else {
counterror++;
if (verbose) {
printf("recv error id=%d errno=%d at %s (%s)\n", id, ERROROFFSET - timeout, note, strerror(errno));
}
}
#ifdef DEBUG
printf("%ld.%03ld no=%d fd=%d %d %s\n", q->sent.tv_sec, q->sent.tv_usec/1000, q->no, q->fd, timeout, note);
fflush(stdout);
#endif
}
void output()
{
double response_size_average, response_size_variance, et;
et = ((double)timediff(&current, &start))/1000000.0;
printf("elapsed time: %.3f\n", et);
printf("tcp qps: %.3f\n", (double)countanswers/et);
printf("sent: %lld\n", countqueries);
printf("answer: %lld %3.1f%%\n", countanswers,
(double)((double)countanswers/(double)countqueries*100.0));
printf("error: %lld %3.1f%%\n", counterror,
(double)((double)counterror/(double)countqueries*100.0));
printf("zeroread: %lld %3.1f%%\n", countzeroread,
(double)((double)countzeroread/(double)countqueries*100.0));
printf("timeout: %lld %3.1f%%\n", counttimeout,
(double)((double)counttimeout/(double)countqueries*100.0));
response_size_average = (double)response_size_sum/countanswers;
response_size_variance = (double)response_size_sum2 / countanswers
- response_size_average * response_size_average;
printf("response size: %d/%.3f/%d/%.3f bytes\n", response_size_min, response_size_average, response_size_max, sqrt(response_size_variance));
if (printrcode) {
int i;
for (i = 0; i < 16; i++) {
if (countrcode[i] != 0) {
printf("%s %lld %5.1f\n", rcodestr[i], countrcode[i], ((double)countrcode[i])/((double)countanswers)*100.0);
}
}
}
}
void tcp_close(struct queries *q)
{
#ifdef DEBUG
printf("tcp_close no=%d fd=%d\n", q->no, q->fd);
#endif
if (q->fd >= 0) {
close(q->fd);
FD_CLR(q->fd, &fdset0r);
FD_CLR(q->fd, &fdset0w);
}
q->sent_flag = 0;
q->tcpstate = TCP_NONE;
q->fd = -1;
}
void tcp_send(struct queries *q)
{
int len;
len = send(q->fd, &q->send, q->sendlen, MSG_NOSIGNAL);
#ifdef DEBUG
printf("tcp_send no=%d fd=%d %d:%d:%d\n", q->no, q->fd, len, q->wpos, q->sendlen);
#endif
if (len < 0) {
if (errno == ENOTCONN) {
printf("tcp_send no=%d fd=%d ENOTCONN return\n", q->no, q->fd);
return;
}
register_response(q, ERROROFFSET - errno, "tcp_send");
tcp_close(q);
return;
}
if (len != q->sendlen) {
register_response(q, ERROROFFSET - errno, "tcp_send:sendto");
tcp_close(q);
return;
}
FD_CLR(q->fd, &fdset0w);
FD_SET(q->fd, &fdset0r);
}
struct typecodes {
char *name;
int code;
} typecodes[] = {
{ "A", ns_t_a },
{ "NS", ns_t_ns },
{ "SOA", ns_t_soa },
{ "PTR", ns_t_ptr },
{ "HINFO", ns_t_hinfo },
{ "MX", ns_t_mx },
{ "TXT", ns_t_txt },
{ "SIG", ns_t_sig },
{ "KEY", ns_t_key },
{ "AAAA", ns_t_aaaa },
{ "NXT", ns_t_nxt },
{ "SRV", ns_t_srv },
{ "NAPTR", ns_t_naptr },
{ NULL, -1 },
};
int stringtodname(unsigned char *qname, unsigned char *buff, unsigned char *lim)
{
unsigned char *p, *s, *t;
int count, total;
t = qname;
p = buff;
total = 0;
for ( ;; ) {
s = p++;
count = 0;
if (p >= lim) return -1;
while (*t != 0 && *t != '.')
if (p < lim) {
*p++ = *t++;
count++;
} else
return -1;
*s = count;
if (count == 0)
break;
if (count > 63)
return -1;
total += count + 1;
if (*t == '.') t++;
}
if (total > 250 || !(*t == 0 || (*t == '.' && t[1] == 0)))
return -1;
return p - buff;
}
void send_query_error(char *mesg)
{
err(1, "Packet size exceed: %s", mesg);
}
void send_query(struct queries *q)
{
u_char *p, *lim;
char *qname;
int qclass;
int qtype;
int tmp;
struct typecodes *t = typecodes;
u_char buff[512];
static char sep[] = "\n\t ";
static int lineno = 0;
/*
SEND E[send_packet_pos]
*/
if (q->sent_flag) {
register_response(q, TIMEOUTERROR, "send_query");
tcp_close(q);
}
if (fp == NULL) {
qname = "version.bind";
qclass = ns_c_chaos;
qtype = ns_t_txt;
} else {
do {
if (fgets((char*)buff, sizeof(char)*512, fp) == NULL) {
if (datafileloop == 1) {
finished = 1;
fclose(fp);
fp = NULL;
return;
}
if (datafileloop > 0)
datafileloop--;
rewind(fp);
lineno = 0;
if (fgets((char*)buff, sizeof(char)*512, fp) == NULL)
err(1, "cannot rewind input file");
}
lineno++;
} while(buff[0] == '#');
qname = strtok((char*)buff, sep);
p = (u_char*) strtok(NULL, sep);
if (p != NULL) {
while(t->name != NULL) {
if (!strcasecmp(t->name, (char*)p))
break;
t++;
}
qtype = t->code;
} else {
qtype = ns_t_a;
}
if (qname == NULL || qtype < 0)
err(1, "datafile format error at line %d, qname=%s qtype=%d", lineno, qname, qtype);
qclass = ns_c_in;
}
q->send.u.h.id = counter++;
q->send.u.h.flag1 = recursion ? 1 : 0; /* Query,OP=0,AA=0,TC=0,RD=0/1 */
q->send.u.h.flag2 = 0;
q->send.u.h.qdcount = htons(1);
q->send.u.h.ancount = 0;
q->send.u.h.nscount = 0;
q->send.u.h.arcount = 0;
p = q->send.u.dnsdata + sizeof(q->send.u.h);
lim = p + sizeof(q->send.u.dnsdata);
if ((tmp = stringtodname((u_char*) qname, p, lim)) < 0)
send_query_error(qname);
p += tmp;
*(unsigned short *)p = htons(qtype);
p += sizeof(unsigned short);
*(unsigned short *)p = htons(qclass);
p += sizeof(unsigned short);
q->sendlen = p - q->send.u.dnsdata;
if (EDNS0) {
#define EDNS0size 11
if (q->sendlen + EDNS0size >= sizeof(q->send.u.dnsdata))
send_query_error("ENDS0");
*p++ = 0; /* . */
*(unsigned short *)p = htons(ns_t_opt);
p += 2;
*(unsigned short *)p = htons(4096);
p += 2;
*p++ = 0;
*p++ = 0;
*p++ = (DNSSEC == 0) ? 0 : 0x80; /* eflag: DO bit */
*p++ = 0;
*p++ = 0;
*p++ = 0;
q->sendlen += EDNS0size;
p = (u_char*) &q->send.u.dnsdata;
q->send.u.h.ancount = htons(1);
}
q->send.len = htons(q->sendlen);
q->sendlen += sizeof(q->send.len);
q->wpos = 0;
q->rpos = 0;
q->sent = current;
if (verbose > 0) {
int id = ntohs(*(unsigned short *)&q->send.u.dnsdata);
printf("sending query(%s,%d,%d) id=%d %d bytes to %s\n", qname, qclass, qtype, id, q->sendlen, ServerName);
hexdump("sending packet header:", (unsigned char*) &q->send.u.h, 12);
}
if (q->fd > 0)
err(1, "q->fd > 0 but ignored\n");
q->fd = socket(remote.ss_family, SOCK_STREAM, 0);
tmp = fcntl(q->fd, F_GETFL, 0);
fcntl(q->fd, F_SETFL, O_NONBLOCK | tmp);
int conn_ret = connect(q->fd, (struct sockaddr *)&remote, remote_len);
if(conn_ret < 0 && errno != EINPROGRESS) {
register_response(q, ERROROFFSET - errno, "send_query:socket+fcntl+connect");
tcp_close(q);
return;
}
#ifdef DEBUG
printf("send_query no=%d fd=%d socket|connect\n", q->no, q->fd);
#endif
q->tcpstate = TCP_WRITABLE;
FD_SET(q->fd, &fdset0w);
FD_CLR(q->fd, &fdset0r);
if (nfds <= q->fd) {
nfds = q->fd + 1;
}
q->sent = current;
q->sent_flag = 1;
}
int UpdateQuery()
{
int i;
timediff_t t, min = Timeout;
struct queries *q;
int free = 0;
if (!finished && TimeLimit > 0) {
if ((t = timediff(&current, &start)) > TimeLimit * 1000000LL) {
finished = 1;
send_finished = current;
}
}
for(i = 0; i < nQueries; i++) {
q = &Queries[i];
if (q->sent_flag) {
if ((t = timediff(&current, &q->sent)) > Timeout) {
/* timeouted */
register_response(q, TIMEOUTERROR, "UpdateQuery");
tcp_close(q);
} else
if (t < min)
min = t;
}
if (!q->sent_flag) {
if (!finished)
send_query(q);
else
free++;
}
}
if (free == nQueries)
min = -1; /* finished */
return min;
}
char *skipname(char *p)
{
while(*p > 0 && *p < 0x40) p += *p + 1;
if (*p == 0)
return p+1;
return p+2;
}
#define Hexdump(A,B,C)
void tcp_receive(struct queries *q)
{
int len, len2;
timediff_t tmp;
unsigned char *recvp;
/*printf("tcp_receive %s\n", q->nameserverlabel);*/
len = read(q->fd, q->recvbuf + q->rpos, len2 = RECVBUFSIZ - q->rpos);
if (len < 0) {
if (errno == EAGAIN)
return;
register_response(q, ERROROFFSET - errno, "tcp_receive:read");
tcp_close(q);
return;
}
if (len == 0) {
register_response(q, ERRZEROREAD, "tcp_receive:read");
tcp_close(q);
return;
}
q->rpos += len;
if (q->rpos < 2)
return;
len2 = ntohs(*(unsigned short *)(q->recvbuf));
if (q->rpos >= len2 + 2) {
/* finished */
recvp = q->recvbuf + 2;
if (memcmp(recvp, q->send.u.dnsdata, 2) == 0) {
if ((recvp[2] & 1) == 0 /* RA bit */
|| (recvp[3] & 15) != 0 /* RCODE must be 0 */
) {
/*
fprintf(stderr, "WRONG AA=%d RCODE=%d\n",
((recvp[2]>>2) & 1), recvp[3]&15);
*/
}
tmp = timediff(&current, &q->sent);
register_response(q, tmp, "tcp_receive");
tcp_close(q);
return;
} else {
printf("no=%d fd=%d unknown recv %d bytes, len=%d\n", q->no, q->fd, q->rpos, ntohs(*(unsigned short *)(q->recvbuf)));
hexdump("", q->recvbuf, len);
/*
fprintf(stderr, "unknown recv from %s, %d bytes %02x %02x\n", q->nameserverlabel, q->rpos, recvp[0], recvp[1]);
*/
tcp_close(q);
}
}
}
void query()
{
fd_set fdsetr, fdsetw;
struct timeval timeout;
int min;
struct queries *q;
int i, n;
struct addrinfo hints, *res0;
int error;
Queries = Xmalloc(sizeof(Queries[0]) * nQueries);
memset(&remote, 0, sizeof(remote));
memset(&hints, 0, sizeof(hints));
hints.ai_family = family;
hints.ai_socktype = SOCK_STREAM;
printf("resolving: %s:%s\n", ServerName, ServerPort);
error = getaddrinfo(ServerName, 0, &hints, &res0);
if (error) {
errx(1, "%s", gai_strerror(error));
}
/* Update server port. */
int port = atoi(ServerPort);
if (res0->ai_family == AF_INET6) {
struct sockaddr_in6 *ipv6 = (struct sockaddr_in6*)res0->ai_addr;
ipv6->sin6_port = htons(port);
} else {
struct sockaddr_in *ipv4 = (struct sockaddr_in*)res0->ai_addr;
ipv4->sin_port = htons(port);
}
remote_len = res0->ai_addrlen;
memcpy(&remote, res0->ai_addr, res0->ai_addrlen);
memset(&countrcode, 0, sizeof(countrcode));
res_init();
_res.options ^= ~RES_RECURSE;
_res.options |= RES_AAONLY;
for (i = 0; i < nQueries; i++) {
Queries[i].sent_flag = 0;
Queries[i].no = i;
}
FD_ZERO(&fdset0r);
FD_ZERO(&fdset0w);
nfds = 0;
UpdateCurrentTime;
start = current;
finished = 0;
for (;;) {
UpdateCurrentTime;
if ((min = UpdateQuery()) < 0)
break;
timeout.tv_sec = min / 1000000;
timeout.tv_usec = min % 1000000;
fdsetr = fdset0r;
fdsetw = fdset0w;
n = select(nfds, &fdsetr, &fdsetw, NULL, &timeout);
UpdateCurrentTime;
for(i = 0; i < nQueries; i++) {
q = &Queries[i];
if (q->fd < 0 || !q->sent_flag)
continue;
if (FD_ISSET(q->fd, &fdsetw)) {
tcp_send(q);
} else if (FD_ISSET(q->fd, &fdsetr)) {
tcp_receive(q);
}
}
}
}
void usage()
{
fprintf(stderr,
"querytcp [-d datafile] [-s server_addr] [-p port] [-q num_queries] [-t timeout] [l limit] [-4] [-6] [-h]\n"
" -d specifies the input data file (default: stdin)\n"
" -s sets the server to query (default: 127.0.0.1)\n"
" -p sets the port on which to query the server (default: 53)\n"
" -q specifies the maximum number of queries outstanding (default: 120)\n"
" -t specifies the timeout for query completion in seconds (default: 10)\n"
" -l specifies how a limit for how long to run tests in seconds (no default)\n"
" -e enable EDNS0\n"
" -D set DO bit\n"
" -r set RD bit\n"
"\n"
"\n"
"\n"
" -c print the number of packets with each rcode\n"
" -v verbose: report the RCODE of each response on stdout\n"
" -h print this usage\n"
);
exit(1);
}
int main(int argc, char *argv[])
{
int ch, i;
printf("dnsheader size: %d\n", sizeof(struct dnsheader));
while ((ch = getopt(argc, argv, "d:s:p:q:t:l:46eDrvh")) != -1) {
switch (ch) {
case 'q':
nQueries = atoi(optarg);
if (nQueries < 1)
err(1, "-q requires natural number");
break;
case 'p':
ServerPort = Xstrdup(optarg);
break;
case 's':
ServerName = Xstrdup(optarg);
break;
case 'd':
datafile = Xstrdup(optarg);
if ((fp = fopen(datafile, "r")) == NULL)
err(1, "cannot open %s", optarg);
break;
case 't':
i = atoi(optarg);
if (i < 1)
err(1, "-t timeout > 0");
Timeout = (int64_t)i * 1000000LL;
break;
case 'l':
TimeLimit = atoi(optarg);
break;
case '4':
family = AF_INET;
break;
case '6':
family = AF_INET6;
break;
case 'e':
EDNS0 = 1;
break;
case 'D':
DNSSEC = 1;
break;
case 'r':
recursion = 1;
break;
case 'v':
verbose = 1;
break;
case 'c':
printrcode = 1;
break;
case 'h':
default:
usage();
}
}
argc -= optind;
argv += optind;
query();
output();
return 0;
}
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment