BIND 10 trac1450, updated. 38201ca33116b1149304ef93683228b8f838dae7 checkpoint of TCP DNS perf tool (debug platform busy)
BIND 10 source code commits
bind10-changes at lists.isc.org
Thu Mar 28 00:51:28 UTC 2013
The branch, trac1450 has been updated
via 38201ca33116b1149304ef93683228b8f838dae7 (commit)
from 45ae3e1322d8d8095e610f2fcfe5ee70d4fac445 (commit)
Those revisions listed above that are new to this repository have
not appeared on any other notification email; so we list those
revisions in full, below.
- Log -----------------------------------------------------------------
commit 38201ca33116b1149304ef93683228b8f838dae7
Author: Francis Dupont <fdupont at isc.org>
Date: Thu Mar 28 01:50:51 2013 +0100
checkpoint of TCP DNS perf tool (debug platform busy)
-----------------------------------------------------------------------
Summary of changes:
tests/tools/perfdhcp/perftcpdns.c | 3136 ++++++++++---------------------------
1 file changed, 850 insertions(+), 2286 deletions(-)
-----------------------------------------------------------------------
diff --git a/tests/tools/perfdhcp/perftcpdns.c b/tests/tools/perfdhcp/perftcpdns.c
index e43b37f..f3b5561 100644
--- a/tests/tools/perfdhcp/perftcpdns.c
+++ b/tests/tools/perfdhcp/perftcpdns.c
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2011 Internet Systems Consortium, Inc. ("ISC")
+ * Copyright (C) 2013 Internet Systems Consortium, Inc. ("ISC")
*
* Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
@@ -19,7 +19,7 @@
#endif
#include <sys/types.h>
-#include <sys/select.h>
+#include <sys/poll.h>
#include <sys/socket.h>
#include <sys/wait.h>
@@ -41,151 +41,61 @@
#include <time.h>
#include <unistd.h>
-/* DHCPv4 defines (to be moved/shared) */
-
-#define DHCP_OFF_OPCODE 0
-#define DHCP_OFF_HTYPE 1
-#define DHCP_OFF_HLEN 2
-#define DHCP_OFF_HOPS 3
-#define DHCP_OFF_XID 4
-#define DHCP_OFF_SECS 8
-#define DHCP_OFF_FLAGS 10
-#define DHCP_OFF_CIADDR 12
-#define DHCP_OFF_YIADDR 16
-#define DHCP_OFF_SADDR 20
-#define DHCP_OFF_GIADDR 24
-#define DHCP_OFF_CHADDR 28
-#define DHCP_OFF_SNAME 44
-#define DHCP_OFF_FILE 108
-#define DHCP_OFF_COOKIE 236
-#define DHCP_OFF_OPTIONS 240
-
-#define BOOTP_OP_REQUEST 1
-#define BOOTP_OP_REPLY 2
-#define BOOTP_MIN_LEN 300
-
-#define DHCP_OP_DISCOVER 1
-#define DHCP_OP_OFFER 2
-#define DHCP_OP_REQUEST 3
-#define DHCP_OP_DECLINE 4
-#define DHCP_OP_ACK 5
-#define DHCP_OP_NAK 6
-#define DHCP_OP_RELEASE 7
-#define DHCP_OP_INFORM 8
-
-#define DHCP_HTYPE_ETHER 1
-
-#define DHCP_OPT_PAD 0
-#define DHCP_OPT_SUBNET_MASK 1
-#define DHCP_OPT_TIME_OFFSET 2
-#define DHCP_OPT_ROUTERS 3
-#define DHCP_OPT_DNS_SERVERS 6
-#define DHCP_OPT_HOST_NAME 12
-#define DHCP_OPT_DOMAIN_NAME 15
-#define DHCP_OPT_BROADCAST 28
-#define DHCP_OPT_DHCP_ADDRESS 50
-#define DHCP_OPT_DHCP_LEASE 51
-#define DHCP_OPT_DHCP_MSGTYPE 53
-#define DHCP_OPT_DHCP_SRVID 54
-#define DHCP_OPT_DHCP_PRL 55
-#define DHCP_OPT_END 255
-
-#define DHCP_OPTLEN_SRVID 6
-
-/* DHCPv6 defines (to be moved/shared) */
-
-#define DHCP6_OFF_MSGTYP 0
-#define DHCP6_OFF_XID 1
-#define DHCP6_OFF_OPTIONS 4
-
-#define DHCP6_OP_SOLICIT 1
-#define DHCP6_OP_ADVERTISE 2
-#define DHCP6_OP_REQUEST 3
-#define DHCP6_OP_REPLY 7
-
-#define DHCP6_OPT_CLIENTID 1
-#define DHCP6_OPT_SERVERID 2
-#define DHCP6_OPT_IA_NA 3
-#define DHCP6_OPT_ORO 6
-#define DHCP6_OPT_ELAPSED_TIME 8
-#define DHCP6_OPT_STATUS_CODE 13
-#define DHCP6_OPT_RAPID_COMMIT 14
-#define DHCP6_OPT_NAME_SERVERS 23
-#define DHCP6_OPT_DOMAIN_SEARCH 24
-
-#define DHCP6_ST_SUCCESS 0
-#define DHCP6_ST_NOADDRSAVAIL 2
-
-#define DHCP6_DUID_LLT 1
-#define DHCP6_DUID_EPOCH 946684800
-
-/* tail queue macros (from FreeBSD 8.2 /sys/sys/queue.h, to be moved/shared) */
-
-#define ISC_TAILQ_HEAD(name, type) \
-struct name { \
- struct type *tqh_first; \
- struct type **tqh_last; \
-}
-
-#define ISC_TAILQ_ENTRY(type) \
-struct { \
- struct type *tqe_next; \
- struct type **tqe_prev; \
-}
-
-#define ISC_TAILQ_EMPTY(head) ((head)->tqh_first == NULL)
-
-#define ISC_TAILQ_FIRST(head) ((head)->tqh_first)
-
-#define ISC_TAILQ_LAST(head, headname) \
- (*(((struct headname *)((head)->tqh_last))->tqh_last))
-
-#define ISC_TAILQ_NEXT(elm, field) ((elm)->field.tqe_next)
-
-#define ISC_TAILQ_PREV(elm, headname, field) \
- (*(((struct headname *)((elm)->field.tqe_prev))->tqh_last))
-
-#define ISC_TAILQ_INIT(head) do { \
- ISC_TAILQ_FIRST((head)) = NULL; \
- (head)->tqh_last = &ISC_TAILQ_FIRST((head)); \
-} while (0)
-
-#define ISC_TAILQ_INSERT_HEAD(head, elm, field) do { \
- ISC_TAILQ_NEXT((elm), field) = ISC_TAILQ_FIRST((head)); \
- if (!ISC_TAILQ_EMPTY((head))) \
- ISC_TAILQ_FIRST((head))->field.tqe_prev = \
- &ISC_TAILQ_NEXT((elm), field); \
- else \
- (head)->tqh_last = &ISC_TAILQ_NEXT((elm), field); \
- ISC_TAILQ_FIRST((head)) = (elm); \
- (elm)->field.tqe_prev = &ISC_TAILQ_FIRST((head)); \
-} while (0)
-
-#define ISC_TAILQ_INSERT_TAIL(head, elm, field) do { \
- ISC_TAILQ_NEXT((elm), field) = NULL; \
- (elm)->field.tqe_prev = (head)->tqh_last; \
- *(head)->tqh_last = (elm); \
- (head)->tqh_last = &ISC_TAILQ_NEXT((elm), field); \
-} while (0)
-
-#define ISC_TAILQ_REMOVE(head, elm, field) do { \
- if ((ISC_TAILQ_NEXT((elm), field)) != NULL) \
- ISC_TAILQ_NEXT((elm), field)->field.tqe_prev = \
- (elm)->field.tqe_prev; \
- else \
- (head)->tqh_last = (elm)->field.tqe_prev; \
- *(elm)->field.tqe_prev = ISC_TAILQ_NEXT((elm), field); \
-} while (0)
-
-#define ISC_TAILQ_FOREACH(var, head, field) \
- for ((var) = ISC_TAILQ_FIRST((head)); \
- (var); \
- (var) = ISC_TAILQ_NEXT((var), field))
-
-#define ISC_TAILQ_FOREACH_SAFE(var, head, field, tvar) \
- for ((var) = ISC_TAILQ_FIRST((head)); \
- (var) && ((tvar) = ISC_TAILQ_NEXT((var), field), 1); \
- (var) = (tvar))
+/* DNS defines */
+
+#define NS_TYPE_A 1
+#define NS_TYPE_NS 2
+#define NS_TYPE_CNAME 5
+#define NS_TYPE_SOA 6
+#define NS_TYPE_NULL 10
+#define NS_TYPE_PTR 12
+#define NS_TYPE_MX 15
+#define NS_TYPE_TXT 16
+#define NS_TYPE_AAAA 28
+#define NS_TYPE_OPT 41
+#define NS_TYPE_DS 43
+#define NS_TYPE_RRSIG 46
+#define NS_TYPE_NSEC 47
+#define NS_TYPE_DNSKEY 48
+#define NS_TYPE_NSEC3 50
+#define NS_TYPE_NSEC3PARAM 51
+#define NS_TYPE_TSIG 250
+#define NS_TYPE_IXFR 251
+#define NS_TYPE_AXFR 252
+#define NS_TYPE_ANY 255
+
+#define NS_CLASS_IN 1
+#define NS_CLASS_ANY 255
+
+#define NS_OFF_LENGTH 0
+#define NS_OFF_ID 2
+#define NS_OFF_FLAGS 4
+#define NS_OFF_QDCOUNT 6
+#define NS_OFF_ANCOUNT 8
+#define NS_OFF_NSCOUNT 10
+#define NS_OFF_ARCOUNT 12
+#define NS_OFF_QUESTION 14
+
+#define NS_FLAG_QR 0x8000U
+#define NS_FLAG_AA 0x0400U
+#define NS_FLAG_TC 0x0200U
+#define NS_FLAG_RD 0x0100U
+#define NS_FLAG_RA 0x0080U
+#define NS_FLAG_AD 0x0020U
+#define NS_FLAG_CD 0x0010U
+
+#define NS_XFLAG_DO 0x8000U
+
+#define NS_OPCODE_MASK 0x7000U
+#define NS_OPCODE_QUERY 0
+
+#define NS_RCODE_MASK 0x000fU
+#define NS_RCODE_NOERROR 0
+#define NS_RCODE_FORMERR 1
+#define NS_RCODE_SERVFAIL 2
+#define NS_RCODE_NXDOMAIN 3
+#define NS_RCODE_NOIMP 4
+#define NS_RCODE_REFUSED 5
/*
* Data structures
@@ -195,85 +105,67 @@ struct { \
* exchange:
* - per exchange values:
* * order (for debugging)
- * * xid (even/odd for 4 packet exchanges)
+ * * id
* * random (for debugging)
* * time-stamps
- * * server ID (for 3rd packet)
- * * IA_NA (for IPv6 3rd packet)
*
- * sent/rcvd global chains, "next to be received" on entry cache,
- * and hash table for xid -> data structure fast matching
- * (using the assumption collisions are unlikely, cf birthday problem)
+ * sent/rcvd chain, "next to be received" on entry cache.
*/
struct exchange { /* per exchange structure */
- ISC_TAILQ_ENTRY(exchange) gchain; /* global chaining */
- ISC_TAILQ_ENTRY(exchange) hchain; /* hash table chaining */
- uint64_t order0, order2; /* number of this exchange */
- uint32_t xid; /* transaction ID */
+ int chain; /* chaining */
+ int sock; /* socket descriptor */
+ uint64_t order; /* number of this exchange */
+ uint16_t id; /* ID */
uint32_t rnd; /* random part */
- struct timespec ts0, ts1, ts2, ts3; /* timespecs */
- uint8_t *sid; /* server ID */
- size_t sidlen; /* server ID length */
- uint8_t *iana; /* (IPv6) IA_NA */
- size_t ianalen; /* (IPv6) IA_NA length */
+ struct timespec ts0, ts1; /* timespecs */
};
-struct exchange *xnext0, *xnext2; /* next to be received */
-ISC_TAILQ_HEAD(xlist, exchange); /* exchange list */
-struct xlist xsent0, xsent2, xrcvd0, xrcvd2; /* sent and received lists */
-uint64_t xscount0, xscount2; /* sent counters */
-uint64_t xrcount0, xrcount2; /* received counters */
-caddr_t exchanges0, exchanges2; /* hash tables */
-uint32_t hashsize0, hashsize2; /* hash table sizes */
+struct exchange *xlist; /* exchange list */
+struct pollfd *plist; /* pollfd list */
+int xlast; /* number of exchanges */
+int xconn; /* connecting list */
+int xsent; /* sent list */
+int xfree; /* free list */
+int xused; /* next to be used list */
+uint64_t xccount; /* connected counters */
+uint64_t xscount; /* sent counters */
+uint64_t xrcount; /* received counters */
/*
* statictics counters and accumulators
*/
-uint64_t tooshort, orphans, locallimit; /* error counters */
+uint64_t tooshort, locallimit; /* error counters */
uint64_t latesent, compsend, latercvd; /* rate stats */
-uint64_t multrcvd, shortwait, collected[2]; /* rate stats (cont) */
-double dmin0 = 999999999., dmin2 = 999999999.; /* minimum delays */
-double dmax0 = 0., dmax2 = 0.; /* maximum delays */
-double dsum0 = 0., dsum2 = 0.; /* delay sums */
-double dsumsq0 = 0., dsumsq2 = 0.; /* square delay sums */
+uint64_t shortwait, collected; /* rate stats (cont) */
+double dmin = 999999999.; /* minimum delay */
+double dmax = 0.; /* maximum delay */
+double dsum = 0.; /* delay sum */
+double dsumsq = 0.; /* square delay sum */
/*
* command line parameters
*/
int ipversion = 0; /* IP version */
-int simple; /* DO/SA in place of DORR/SARR */
int rate; /* rate in exchange per second */
int report; /* delay between two reports */
uint32_t range; /* randomization range */
uint32_t maxrandom; /* maximum random value */
int basecnt; /* base count */
-char *base[4]; /* bases */
-int gotnumreq; /* numreq[0] was set */
-int numreq[2]; /* number of exchange */
+char *base[2]; /* bases */
+int numreq; /* number of exchange */
int period; /* test period */
-int gotlosttime; /* losttime[0] was set */
-double losttime[2] = {1., 1.}; /* time after a request is lost */
-int gotmaxdrop; /* max{p}drop[0] was set */
-int maxdrop[2]; /* maximum number of lost requests */
-double maxpdrop[2] = { 0., 0.}; /* maximum percentage */
+double losttime = 1.; /* time after a request is lost */
+int maxdrop; /* maximum number of lost requests */
+double maxpdrop = 0.; /* maximum percentage */
char *localname; /* local address or interface */
-int isinterface; /* interface vs local address */
int preload; /* preload exchanges */
int aggressivity = 1; /* back to back exchanges */
-int localport; /* local port number (host endian) */
int seeded; /* is a seed provided */
unsigned int seed; /* randomization seed */
-int isbroadcast; /* use broadcast */
-int rapidcommit; /* add rapid commit option */
-int usefirst; /* where to take the server-ID */
-char *templatefile[2]; /* template file name */
-int xidoffset[2] = {-1, -1}; /* template offsets (xid)*/
-int rndoffset[2] = {-1, -1}; /* template offsets (random) */
-int elpoffset = -1; /* template offset (elapsed time) */
-int sidoffset = -1; /* template offset (server ID) */
-int ripoffset = -1; /* template offset (requested IP) */
+char *templatefile; /* template file name */
+int rndoffset = -1; /* template offset (random) */
char *diags; /* diagnostic selectors */
char *wrapped; /* wrapped command */
char *servername; /* server */
@@ -282,14 +174,14 @@ char *servername; /* server */
* global variables
*/
+int locbind;
struct sockaddr_storage localaddr; /* local socket address */
struct sockaddr_storage serveraddr; /* server socket address */
-int sock; /* socket descriptor */
int interrupted, fatal; /* to finish flags */
uint8_t obuf[4096], ibuf[4096]; /* I/O buffers */
-char tbuf[8200]; /* template buffer */
+char tbuf[512]; /* template buffer */
struct timespec boot; /* the date of boot */
struct timespec last; /* the date of last send */
@@ -297,70 +189,16 @@ struct timespec due; /* the date of next send */
struct timespec dreport; /* the date of next reporting */
struct timespec finished; /* the date of finish */
-uint8_t *gsrvid; /* global server id */
-size_t gsrvidlen; /* and its length */
-uint8_t gsrvidbuf[64]; /* and its storage */
-
-/* MAC address */
-uint8_t mac_prefix[6] = { 0x00, 0x0c, 0x01, 0x02, 0x03, 0x04 };
-
-/* DUID prefix */
-uint8_t *duid_prefix;
-int duid_length;
-
-/* magic cookie for BOOTP/DHCPv4 */
-uint8_t dhcp_cookie[4] = { 0x63, 0x82, 0x53, 0x63 };
-
/*
- * templates
- *
- * note: the only hard point is what are the offsets:
- * - xid_discover4 and xid_request4: first of the 4 octet long
- * transaction ID (default DHCP_OFF_XID = 4)
- * - random_discover4 and random_request4: last of the 6 octet long
- * MAC address (default DHCP_OFF_CHADDR + 6 = 28 + 6)
- * - elapsed_request4: first of the 2 octet long secs field
- * (default DHCP_OFF_SECS = 8, 0 means disabled)
- * - serverid_request4: first of the 6 octet long server ID option
- * (no default, required)
- * - reqaddr_request4: first of the 4 octet long requested IP address
- * option content (i.e., the address itself, btw OFFER yiaddr)
- * (no default, required)
- * - xid_solicit6 and xid_request6: first of the 3 octet long
- * transaction ID (default DHCP6_OFF_XID = 1)
- * - random_solicit6 and random_request6: last of the DUID in the
- * client ID option (no default, required when rate is set)
- * - elapsed_request6: first of the 2 octet long content of
- * the option elapsed time option (no default, 0 means disabled)
- * - serverid_request6: position where the variable length server ID
- * option is inserted (no default, required, set to length means append)
- * - reqaddr_request6: position where of the variable length requested
- * IP address option is inserted (no default, required, set to
- * length means append)
+ * template
*/
-size_t length_discover4;
-uint8_t template_discover4[4096];
-size_t xid_discover4;
-size_t random_discover4;
-size_t length_request4;
-uint8_t template_request4[4096];
-size_t xid_request4;
-size_t elapsed_request4;
-size_t random_request4;
-size_t serverid_request4;
-size_t reqaddr_request4;
-size_t length_solicit6;
-uint8_t template_solicit6[4096];
-size_t xid_solicit6;
-size_t random_solicit6;
-size_t length_request6;
-uint8_t template_request6[4096];
-size_t xid_request6;
-size_t elapsed_request6;
-size_t random_request6;
-size_t serverid_request6;
-size_t reqaddr_request6;
+size_t length_query4;
+uint8_t template_query4[4096];
+size_t random_query4;
+size_t length_query6;
+uint8_t template_query6[4096];
+size_t random_query6;
/*
* initialize data structures handling exchanges
@@ -369,40 +207,22 @@ size_t reqaddr_request6;
void
inits(void)
{
- struct xlist *bucket;
- caddr_t p;
- size_t len, i;
-
- ISC_TAILQ_INIT(&xsent0);
- ISC_TAILQ_INIT(&xsent2);
- ISC_TAILQ_INIT(&xrcvd0);
- ISC_TAILQ_INIT(&xrcvd2);
-
- /// compute hashsizes
- hashsize0 = 1024;
- len = sizeof(*bucket) * hashsize0;
- exchanges0 = malloc(len);
- if (exchanges0 == NULL) {
- perror("malloc(exchanges0)");
+ xlist = (struct exchange *) malloc(xlast * sizeof(struct exchange));
+ if (xlist == NULL) {
+ perror("malloc(exchanges)");
exit(1);
}
- for (i = 0, p = exchanges0; i < hashsize0; i++, p += sizeof(*bucket)) {
- bucket = (struct xlist *) p;
- ISC_TAILQ_INIT(bucket);
- }
- if (simple != 0)
- return;
- hashsize2 = 1024;
- len = sizeof(*bucket) * hashsize2;
- exchanges2 = malloc(len);
- if (exchanges2 == NULL) {
- perror("malloc(exchanges2)");
+ memset(xlist, 0, xlast * sizeof(struct exchange));
+ xconn = xsent = -1;
+ xfree = -1;
+ xused = 0;
+
+ plist = (struct pollfd *) malloc(xlast * sizeof(struct pollfd));
+ if (plist == NULL) {
+ perror("malloc(pollfd)");
exit(1);
}
- for (i = 0, p = exchanges2; i < hashsize2; i++, p += sizeof(*bucket)) {
- bucket = (struct xlist *) p;
- ISC_TAILQ_INIT(bucket);
- }
+ memset(plist, 0, xlast * sizeof(struct pollfd));
}
/*
@@ -447,334 +267,167 @@ randomize(size_t offset, uint32_t r)
}
/*
- * receive a reply (4th packet), shared between IPv4 and IPv6:
- * - transaction ID xid
+ * receive a response, shared between IPv4 and IPv6:
* - receiving time-stamp now
- * called from receive[46]() when the xid is odd
+ * called from receive[46]()
*/
void
-receive_reply(uint32_t xid, struct timespec *now)
+receive_reply(int idx, struct timespec *now)
{
- struct exchange *x, *t;
- struct xlist *bucket;
- uint32_t hash;
- int checklost;
+ struct exchange *x = xlist + idx;
double delta;
- /* bucket is needed even when the next cache matches */
- hash = (xid >> 1) & (hashsize2 - 1);
- bucket = (struct xlist *) (exchanges2 + hash * sizeof(*bucket));
- /* try the 'next to be received' cache */
- if ((xnext2 != NULL) && (xnext2->xid == xid)) {
- x = xnext2;
- goto found;
- }
- /* usually the lost probability is low for request/reply */
- checklost = 1;
- /* look for the exchange */
- ISC_TAILQ_FOREACH_SAFE(x, bucket, hchain, t) {
- double waited;
-
- if (x->xid == xid)
- goto found;
- if (checklost <= 0)
- continue;
- checklost = 0;
- /* check for a timed-out exchange */
- waited = now->tv_sec - x->ts2.tv_sec;
- waited += (now->tv_nsec - x->ts2.tv_nsec) / 1e9;
- if (waited < losttime[1])
- continue;
- /* garbage collect timed-out exchange */
- ISC_TAILQ_REMOVE(bucket, x, hchain);
- ISC_TAILQ_REMOVE(&xsent2, x, gchain);
- free(x);
- collected[1] += 1;
- }
- /* no match? very late or not for us */
- orphans++;
- return;
-
- /* got it: update stats and move to the received queue */
- found:
- xrcount2++;
- x->ts3 = *now;
- delta = x->ts3.tv_sec - x->ts2.tv_sec;
- delta += (x->ts3.tv_nsec - x->ts2.tv_nsec) / 1e9;
- if (delta < dmin2)
- dmin2 = delta;
- if (delta > dmax2)
- dmax2 = delta;
- dsum2 += delta;
- dsumsq2 += delta * delta;
- xnext2 = ISC_TAILQ_NEXT(x, gchain);
- ISC_TAILQ_REMOVE(bucket, x, hchain);
- ISC_TAILQ_REMOVE(&xsent2, x, gchain);
- ISC_TAILQ_INSERT_TAIL(&xrcvd2, x, gchain);
+ /* got it: update stats */
+ xrcount++;
+ x->ts1 = *now;
+ delta = x->ts1.tv_sec - x->ts0.tv_sec;
+ delta += (x->ts1.tv_nsec - x->ts0.tv_nsec) / 1e9;
+ if (delta < dmin)
+ dmin = delta;
+ if (delta > dmax)
+ dmax = delta;
+ dsum += delta;
+ dsumsq += delta * delta;
}
/*
- * get the DHCPv4 socket descriptor
- * (the only complexity is broadcast enabling: there is no easy way to
- * recognize broadcast addresses, so the command line -B flag)
+ * get the TCP DNS socket descriptor (IPv4)
*/
-void
+int
getsock4(void)
{
- int ret;
+ int sock;
+ int flags;
- /* update local port */
- if (localport != 0) {
- uint16_t lp = htons((uint16_t) localport);
+ errno = 0;
+ sock = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP);
+ if (sock < 0)
+ return -errno;
- ((struct sockaddr_in *) &localaddr)->sin_port = lp;
- }
- sock = socket(PF_INET, SOCK_DGRAM, IPPROTO_UDP);
- if (sock < 0) {
- perror("socket");
- exit(1);
+ /* make the socket descriptor not blocking */
+ flags = fcntl(sock, F_GETFL, 0);
+ if (flags == -1) {
+ (void) close(sock);
+ return -errno;
}
- ret = bind(sock,
- (struct sockaddr *) &localaddr,
- sizeof(struct sockaddr_in));
- if (ret < 0) {
- perror("bind");
- exit(1);
+ if (fcntl(sock, F_SETFL, flags | O_NONBLOCK) == -1) {
+ (void) close(sock);
+ return -errno;
}
- /* enable broadcast if needed or required */
- if (isbroadcast != 0) {
- int on = 1;
- ret = setsockopt(sock,
- SOL_SOCKET, SO_BROADCAST,
- &on, sizeof(on));
- if (ret < 0) {
- perror("setsockopt(SO_BROADCAST)");
- exit(1);
+ /* bind if wanted */
+ if (locbind) {
+ if (bind(sock,
+ (struct sockaddr *) &localaddr,
+ sizeof(struct sockaddr_in)) < 0) {
+ (void) close(sock);
+ return -errno;
}
}
-}
-
-/*
- * build a DHCPv4 DISCOVER from a relay template
- * (implicit parameters are the local (giaddr) and MAC addresses (chaddr))
- * (assume the link is Ethernet)
- */
-void
-build_template_discover4(void)
-{
- uint8_t *p = template_discover4;
-
- length_discover4 = BOOTP_MIN_LEN;
- xid_discover4 = DHCP_OFF_XID;
- random_discover4 = DHCP_OFF_CHADDR + 6;
- /* opcode */
- p[DHCP_OFF_OPCODE] = BOOTP_OP_REQUEST;
- /* hardware address type */
- p[DHCP_OFF_HTYPE] = DHCP_HTYPE_ETHER;
- /* hardware address length */
- p[DHCP_OFF_HLEN] = 6;
- /* hops */
- p[DHCP_OFF_HOPS] = 1;
- /* gateway address */
- memcpy(p + DHCP_OFF_GIADDR,
- &((struct sockaddr_in *) &localaddr)->sin_addr,
- 4);
- /* hardware address */
- memcpy(p + DHCP_OFF_CHADDR, mac_prefix, 6);
- /* cookie */
- memcpy(p + DHCP_OFF_COOKIE, dhcp_cookie, 4);
- /* options */
- p += DHCP_OFF_OPTIONS;
- /* inline DHCP message type */
- *p++ = DHCP_OPT_DHCP_MSGTYPE;
- *p++ = 1;
- *p++ = DHCP_OP_DISCOVER;
- /* inline DHCP parameter request list (default) */
- *p++ = DHCP_OPT_DHCP_PRL;
- *p++ = 7;
- *p++ = DHCP_OPT_SUBNET_MASK;
- *p++ = DHCP_OPT_BROADCAST;
- *p++ = DHCP_OPT_TIME_OFFSET;
- *p++ = DHCP_OPT_ROUTERS;
- *p++ = DHCP_OPT_DOMAIN_NAME;
- *p++ = DHCP_OPT_DNS_SERVERS;
- *p++ = DHCP_OPT_HOST_NAME;
- /* end */
- *p = DHCP_OPT_END;
-}
-
-/*
- * get a DHCPv4 client/relay first packet (usually a DISCOVER) template
- * from the file given in the command line (-T<template-file>)
- * and xid/rnd offsets (-X<xid-offset> and -O<random-offset>)
- */
-
-void
-get_template_discover4(void)
-{
- uint8_t *p = template_discover4;
- int fd, cc, i, j;
-
- fd = open(templatefile[0], O_RDONLY);
- if (fd < 0) {
- fprintf(stderr, "open(%s): %s\n",
- templatefile[0], strerror(errno));
- exit(2);
- }
- cc = read(fd, tbuf, sizeof(tbuf));
- (void) close(fd);
- if (cc < 0) {
- fprintf(stderr, "read(%s): %s\n",
- templatefile[0], strerror(errno));
- exit(1);
- }
- if (cc < 100) {
- fprintf(stderr, "file '%s' too short\n", templatefile[0]);
- exit(2);
- }
- if (cc > 8193) {
- fprintf(stderr,"file '%s' too large\n", templatefile[0]);
- exit(2);
- }
- j = 0;
- for (i = 0; i < cc; i++) {
- if (isspace((int) tbuf[i]))
- continue;
- if (!isxdigit((int) tbuf[i])) {
- fprintf(stderr,
- "illegal char[%d]='%c' in file '%s'\n",
- i, (int) tbuf[i], templatefile[0]);
- exit(2);
+ /* connect */
+ if (connect(sock,
+ (struct sockaddr *) &serveraddr,
+ sizeof(struct sockaddr_in)) < 0) {
+ if (errno != EINPROGRESS) {
+ (void) close(sock);
+ return -errno;
}
- tbuf[j] = tbuf[i];
- j++;
- }
- cc = j;
- if ((cc & 1) != 0) {
- fprintf(stderr,
- "odd number of hexadecimal digits in file '%s'\n",
- templatefile[0]);
- exit(2);
- }
- length_discover4 = cc >> 1;
- for (i = 0; i < cc; i += 2)
- (void) sscanf(tbuf + i, "%02hhx", &p[i >> 1]);
- if (xidoffset[0] >= 0)
- xid_discover4 = (size_t) xidoffset[0];
- else
- xid_discover4 = DHCP_OFF_XID;
- if (xid_discover4 + 4 > length_discover4) {
- fprintf(stderr,
- "xid (at %zu) outside the template (length %zu)?\n",
- xid_discover4, length_discover4);
- exit(2);
- }
- if (rndoffset[0] >= 0)
- random_discover4 = (size_t) rndoffset[0];
- else
- random_discover4 = DHCP_OFF_CHADDR + 6;
- if (random_discover4 > length_discover4) {
- fprintf(stderr,
- "random (at %zu) outside the template (length %zu)?\n",
- random_discover4, length_discover4);
- exit(2);
}
+ return sock;
}
/*
- * build a DHCPv4 REQUEST from a relay template
- * (implicit parameters are the local (giaddr) and MAC addresses (chaddr))
- * (assume the link is Ethernet)
+ * build a TCP DNS QUERY (IPv4)
*/
void
-build_template_request4(void)
+build_template_query4(void)
{
- uint8_t *p = template_request4;
-
- length_request4 = BOOTP_MIN_LEN;
- xid_request4 = DHCP_OFF_XID;
- elapsed_request4 = DHCP_OFF_SECS;
- random_request4 = DHCP_OFF_CHADDR + 6;
- /* opcode */
- p[DHCP_OFF_OPCODE] = BOOTP_OP_REQUEST;
- /* hardware address type */
- p[DHCP_OFF_HTYPE] = DHCP_HTYPE_ETHER;
- /* hardware address length */
- p[DHCP_OFF_HLEN] = 6;
- /* hops */
- p[DHCP_OFF_HOPS] = 1;
- /* gateway address */
- memcpy(p + DHCP_OFF_GIADDR,
- &((struct sockaddr_in *) &localaddr)->sin_addr,
- 4);
- /* hardware address */
- memcpy(p + DHCP_OFF_CHADDR, mac_prefix, 6);
- /* cookie */
- memcpy(p + DHCP_OFF_COOKIE, dhcp_cookie, 4);
- /* options */
- p += DHCP_OFF_OPTIONS;
- /* inline DHCP message type */
- *p++ = DHCP_OPT_DHCP_MSGTYPE;
- *p++ = 1;
- *p++ = DHCP_OP_REQUEST;
- /* place for DHCP server id (option) */
- serverid_request4 = p - template_request4;
- p += DHCP_OPTLEN_SRVID;
- /* place for DHCP requested IP address (address) */
- *p++ = DHCP_OPT_DHCP_ADDRESS;
+ uint8_t *p = template_query4;
+ uint16_t v;
+
+ /* flags */
+ p += NS_OFF_FLAGS;
+ v = NS_FLAG_RD;
+ *p++ = v >> 8;
+ *p++ = v & 0xff;
+ /* qdcount */
+ v = 1;
+ *p++ = v >> 8;
+ *p++ = v & 0xff;
+ /* ancount */
+ v = 0;
+ *p++ = v >> 8;
+ *p++ = v & 0xff;
+ /* nscount */
+ v = 0;
+ *p++ = v >> 8;
+ *p++ = v & 0xff;
+ /* arcount */
+ v = 0;
+ *p++ = v >> 8;
+ *p++ = v & 0xff;
+ /* icann.link */
+ *p++ = 5;
+ *p++ = 'i';
+ *p++ = 'c';
+ *p++ = 'a';
+ *p++ = 'n';
+ *p++ = 'n';
*p++ = 4;
- reqaddr_request4 = p - template_request4;
- p += 4;
- /* inline DHCP parameter request list (default) */
- *p++ = DHCP_OPT_DHCP_PRL;
- *p++ = 7;
- *p++ = DHCP_OPT_SUBNET_MASK;
- *p++ = DHCP_OPT_BROADCAST;
- *p++ = DHCP_OPT_TIME_OFFSET;
- *p++ = DHCP_OPT_ROUTERS;
- *p++ = DHCP_OPT_DOMAIN_NAME;
- *p++ = DHCP_OPT_DNS_SERVERS;
- *p++ = DHCP_OPT_HOST_NAME;
- /* end */
- *p = DHCP_OPT_END;
+ *p++ = 'l';
+ *p++ = 'i';
+ *p++ = 'n';
+ *p++ = 'k';
+ *p++ = 0;
+ /* type A */
+ v = NS_TYPE_A;
+ *p++ = v >> 8;
+ *p++ = v & 0xff;
+ /* class IN */
+ v = NS_CLASS_IN;
+ *p++ = v >> 8;
+ *p++ = v & 0xff;
+ /* length */
+ length_query4 = p - template_query4;
+ template_query4[0] = (length_query4 >> 8) & 0xff;
+ template_query4[1] = length_query4 & 0xff;
}
/*
- * get a DHCPv4 client/relay third packet (usually a REQUEST) template
+ * get a TCP/IPv4 DNS client QUERY template
* from the file given in the command line (-T<template-file>)
- * and offsets (-X,-O,-E,-S,-I).
+ * and rnd offset (-O<random-offset>)
*/
void
-get_template_request4(void)
+get_template_query4(void)
{
- uint8_t *p = template_request4;
+ uint8_t *p = template_query4;
int fd, cc, i, j;
- fd = open(templatefile[1], O_RDONLY);
+ fd = open(templatefile, O_RDONLY);
if (fd < 0) {
fprintf(stderr, "open(%s): %s\n",
- templatefile[1], strerror(errno));
+ templatefile, strerror(errno));
exit(2);
}
cc = read(fd, tbuf, sizeof(tbuf));
(void) close(fd);
if (cc < 0) {
fprintf(stderr, "read(%s): %s\n",
- templatefile[1], strerror(errno));
+ templatefile, strerror(errno));
exit(1);
}
- if (cc < 100) {
- fprintf(stderr, "file '%s' too short\n", templatefile[1]);
+ if (cc < NS_OFF_QUESTION + 4) {
+ fprintf(stderr,"file '%s' too small\n", templatefile);
exit(2);
}
- if (cc > 8193) {
- fprintf(stderr,"file '%s' too large\n", templatefile[1]);
+ if (cc > 511) {
+ fprintf(stderr,"file '%s' too large\n", templatefile);
exit(2);
}
j = 0;
@@ -784,7 +437,7 @@ get_template_request4(void)
if (!isxdigit((int) tbuf[i])) {
fprintf(stderr,
"illegal char[%d]='%c' in file '%s'\n",
- i, (int) tbuf[i], templatefile[1]);
+ i, (int) tbuf[i], templatefile);
exit(2);
}
tbuf[j] = tbuf[i];
@@ -794,167 +447,83 @@ get_template_request4(void)
if ((cc & 1) != 0) {
fprintf(stderr,
"odd number of hexadecimal digits in file '%s'\n",
- templatefile[1]);
+ templatefile);
exit(2);
}
- length_request4 = cc >> 1;
+ length_query4 = cc >> 1;
for (i = 0; i < cc; i += 2)
(void) sscanf(tbuf + i, "%02hhx", &p[i >> 1]);
- if (xidoffset[1] >= 0)
- xid_request4 = (size_t) xidoffset[1];
- else
- xid_request4 = DHCP_OFF_XID;
- if (xid_request4 + 4 > length_request4) {
- fprintf(stderr,
- "xid (at %zu) outside the template (length %zu)?\n",
- xid_request4, length_request4);
- exit(2);
- }
- if (rndoffset[1] >= 0)
- random_request4 = (size_t) rndoffset[1];
- else
- random_request4 = DHCP_OFF_CHADDR + 6;
- if (random_request4 > length_request4) {
+ if (rndoffset >= 0)
+ random_query4 = (size_t) rndoffset;
+ if (random_query4 > length_query4) {
fprintf(stderr,
"random (at %zu) outside the template (length %zu)?\n",
- random_request4, length_request4);
- exit(2);
- }
- if (elpoffset >= 0)
- elapsed_request4 = (size_t) elpoffset;
- else
- elapsed_request4 = DHCP_OFF_SECS;
- if (elapsed_request4 + 2 > length_request4) {
- fprintf(stderr,
- "secs (at %zu) outside the template (length %zu)?\n",
- elapsed_request4, length_request4);
- exit(2);
- }
- serverid_request4 = (size_t) sidoffset;
- if (serverid_request4 + 6 > length_request4) {
- fprintf(stderr,
- "server-id option (at %zu) outside the template "
- "(length %zu)?\n",
- serverid_request4, length_request4);
- exit(2);
- }
- reqaddr_request4 = (size_t) ripoffset;
- if (reqaddr_request4 + 4 > length_request4) {
- fprintf(stderr,
- "requested-ip-address option (at %zu) outside "
- "the template (length %zu)?\n",
- reqaddr_request4, length_request4);
+ random_query4, length_query4);
exit(2);
}
}
/*
- * send the DHCPv4 REQUEST third packet
- * (the transaction ID is odd)
- * (TODO: check for errors in the OFFER)
+ * connect the TCP DNS QUERY (IPv4)
*/
-void
-send_request4(struct exchange *x0)
+int
+connect4(void)
{
struct exchange *x;
- struct xlist *bucket;
- uint32_t hash;
+ struct pollfd *p;
ssize_t ret;
+ int idx;
+
+ if (xfree >= 0) {
+ idx = xfree;
+ x = xlist + idx;
+ p = plist + idx;
+ xfree = x->chain;
+ } else if (xused < xlast) {
+ idx = xused;
+ x = xlist + idx;
+ p = plist + idx;
+ xused++;
+ } else
+ return -ENOMEM;
- x = (struct exchange *) malloc(sizeof(*x));
- if (x == NULL) {
- locallimit++;
- perror("send2");
- return;
- }
-
- memcpy(x, x0, sizeof(*x));
- x->order2 = xscount2++;
- x->xid |= 1;
- hash = x->xid >> 1;
-
- ISC_TAILQ_INSERT_TAIL(&xsent2, x, gchain);
- hash &= hashsize2 - 1;
- bucket = (struct xlist *) (exchanges2 + hash * sizeof(*bucket));
- ISC_TAILQ_INSERT_TAIL(bucket, x, hchain);
-
- memcpy(obuf, template_request4, length_request4);
- /* xid */
- memcpy(obuf + xid_request4, &x->xid, 4);
- /* random */
- randomize(random_request4, x->rnd);
- /* secs */
- if (elapsed_request4 > 0) {
- int secs;
-
- secs = x->ts1.tv_sec - x->ts0.tv_sec;
- if (x->ts1.tv_nsec < x->ts0.tv_nsec)
- secs += 1;
- if (secs > 0) {
- obuf[elapsed_request4] = secs >> 8;
- obuf[elapsed_request4 + 1] = secs & 0xff;
- }
- }
- /* server ID */
- memcpy(obuf + serverid_request4, x->sid, x->sidlen);
- /* requested IP address */
- memcpy(obuf + reqaddr_request4, ibuf + DHCP_OFF_YIADDR, 4);
-
- /* timestamp */
- ret = clock_gettime(CLOCK_REALTIME, &x->ts2);
- if (ret < 0) {
- perror("clock_gettime(send2)");
- fatal = 1;
- return;
- }
- ret = sendto(sock, obuf, length_request4, 0,
- (struct sockaddr *) &serveraddr,
- sizeof(struct sockaddr_in));
- if (ret >= 0)
- return;
- if ((errno == EAGAIN) || (errno == EWOULDBLOCK) ||
- (errno == ENOBUFS) || (errno == ENOMEM))
- locallimit++;
- perror("send2");
+ memset(x, 0, sizeof(*x));
+ memset(p, 0, sizeof(*p));
+ x->sock = getsock4();
+ if (x->sock < 0) {
+ x->chain = xfree;
+ xfree = idx;
+ return x->sock;
+ }
+ p->fd = x->sock;
+ p->events = POLLOUT;
+ x->chain = xconn;
+ xconn = idx;
+ x->order = xccount++;
+ x->id = (uint16_t) random();
+ if (random_query4 > 0)
+ x->rnd = (uint32_t) random();
+ return idx;
}
/*
- * send the DHCPv4 DISCOVER first packet
- * (for 4-exchange, the transaction ID xid is even)
+ * send the TCP DNS QUERY (IPv4)
*/
int
-send4(void)
+send4(struct exchange *x)
{
- struct exchange *x;
- struct xlist *bucket;
- uint32_t hash;
ssize_t ret;
- x = (struct exchange *) malloc(sizeof(*x));
- if (x == NULL)
- return -ENOMEM;
-
- memset(x, 0, sizeof(*x));
- x->order0 = xscount0++;
- hash = x->rnd = (uint32_t) random();
- if (simple == 0)
- x->xid = hash << 1;
- else
- x->xid = hash;
-
- ISC_TAILQ_INSERT_TAIL(&xsent0, x, gchain);
- hash &= hashsize0 - 1;
- bucket = (struct xlist *) (exchanges0 + hash * sizeof(*bucket));
- ISC_TAILQ_INSERT_TAIL(bucket, x, hchain);
-
- memcpy(obuf, template_discover4, length_discover4);
- /* xid */
- memcpy(obuf + xid_discover4, &x->xid, 4);
+ memcpy(obuf, template_query4, length_query4);
+ /* ID */
+ memcpy(obuf + NS_OFF_ID, &x->id, 2);
/* random */
- x->rnd = randomize(random_discover4, x->rnd);
+ if (random_query4 > 0)
+ x->rnd = randomize(random_query4, x->rnd);
/* timestamp */
+ errno = 0;
ret = clock_gettime(CLOCK_REALTIME, &last);
if (ret < 0) {
perror("clock_gettime(send)");
@@ -962,425 +531,321 @@ send4(void)
return -errno;
}
x->ts0 = last;
- errno = 0;
- ret = sendto(sock, obuf, length_discover4, 0,
- (struct sockaddr *) &serveraddr,
- sizeof(struct sockaddr_in));
- if (ret == (ssize_t) length_discover4)
+ ret = send(x->sock, obuf, length_query4, 0);
+ if (ret == (ssize_t) length_query4)
return 0;
return -errno;
}
/*
- * scan a DHCPv4 OFFER to get its server-id option
+ * poll connected and send (IPv4)
*/
-int
-scan_for_srvid4(struct exchange *x, size_t cc)
+void
+pollsend4(void)
{
- size_t off = DHCP_OFF_OPTIONS;
-
- for (;;) {
- if (off + DHCP_OPTLEN_SRVID > cc) {
- fprintf(stderr, "truncated\n");
- return -1;
- }
- if (ibuf[off] == DHCP_OPT_DHCP_SRVID)
- break;
- if (ibuf[off] == DHCP_OPT_END) {
- fprintf(stderr, "server-id not found\n");
- return -1;
- }
- if (ibuf[off] == DHCP_OPT_PAD) {
- off++;
- continue;
- }
- off += 2 + ibuf[off + 1];
+ struct exchange *x;
+ struct pollfd *p;
+ int idx = xconn, prev = -1;
+ int cnt = 10;
+ int err;
+ socklen_t len = sizeof(int);
+
+ while (--cnt >= 0) {
+ if (idx < 0)
+ return;
+ x = xlist + idx;
+ p = plist + idx;
+ if (p->fd < 0)
+ goto next;
+ if ((p->revents & POLLOUT) == 0)
+ goto next;
+ p->revents = 0;
+ if (getsockopt(p->fd, SOL_SOCKET, SO_ERROR,
+ &err, &len) < 0)
+ goto close;
+ if (err != 0)
+ goto close;
+ if (send4(x) < 0)
+ goto close;
+ xscount++;
+ p->events = POLLIN;
+ if (prev < 0)
+ xconn = x->chain;
+ else
+ xlist[prev].chain = x->chain;
+ prev = idx;
+ idx = x->chain;
+ x->chain = xsent;
+ xsent = prev;
+ continue;
+ next:
+ prev = idx;
+ idx = x->chain;
+ continue;
+ close:
+ (void) close(p->fd);
+ p->fd = -1;
+ if (prev < 0)
+ xconn = x->chain;
+ else
+ xlist[prev].chain = x->chain;
+ prev = idx;
+ idx = x->chain;
+ x->chain = xfree;
+ xfree = prev;
}
- /* check length */
- if (ibuf[off + 1] != DHCP_OPTLEN_SRVID - 2) {
- fprintf(stderr,
- "bad server-id length (%hhu)\n",
- ibuf[off + 1]);
- return -1;
- }
- /* cache it in the global variables when required and not yet done */
- if ((usefirst != 0) && (gsrvid == NULL)) {
- memcpy(gsrvidbuf, ibuf + off, DHCP_OPTLEN_SRVID);
- gsrvid = gsrvidbuf;
- gsrvidlen = DHCP_OPTLEN_SRVID;
- }
- x->sid = ibuf + off;
- x->sidlen = DHCP_OPTLEN_SRVID;
- return 0;
}
/*
- * receive a DHCPv4 packet
+ * receive a TCP DNS RESPONSE (IPv4)
*/
void
-receive4(void)
+receive4(struct exchange *x)
{
- struct exchange *x, *t;
- struct xlist *bucket;
+ struct pollfd *p;
struct timespec now;
+ int idx = x - xlist;
ssize_t cc;
- uint32_t xid, hash;
- int checklost = 0;
+ uint16_t v;
double delta;
- cc = recv(sock, ibuf, sizeof(ibuf), 0);
+ cc = recv(x->sock, ibuf, sizeof(ibuf), 0);
if (cc < 0) {
if ((errno == EAGAIN) ||
(errno == EWOULDBLOCK) ||
(errno == EINTR))
- return;
+ goto close;
perror("recv");
fatal = 1;
- return;
+ goto close;
}
/* enforce a reasonable length */
- if (cc < BOOTP_MIN_LEN) {
+ if (cc < length_query4) {
tooshort++;
- return;
- }
- /* must be a BOOTP REPLY */
- if (ibuf[DHCP_OFF_OPCODE] != BOOTP_OP_REPLY)
- return;
+ goto close;
+ }
+ /* must match the ID */
+ if (memcmp(ibuf + NS_OFF_ID, &x->id, 2) != 0)
+ goto close;
+ /* must be a response */
+ memcpy(ibuf + NS_OFF_FLAGS, &v, 2);
+ v = ntohs(v);
+ if ((v & NS_FLAG_QR) == 0)
+ goto close;
if (clock_gettime(CLOCK_REALTIME, &now) < 0) {
perror("clock_gettime(receive)");
fatal = 1;
- return;
- }
- memcpy(&xid, ibuf + xid_discover4, 4);
- /* 4-packet exchange even/odd xid */
- if (simple == 0) {
- if ((xid & 1) != 0) {
- receive_reply(xid, &now);
- return;
- }
- hash = (xid >> 1) & (hashsize0 - 1);
- } else
- hash = xid & (hashsize0 - 1);
- /* now it is the second packet, get the bucket which is needed */
- bucket = (struct xlist *) (exchanges0 + hash * sizeof(*bucket));
- /* try the 'next to be received' cache */
- if ((xnext0 != NULL) && (xnext0->xid == xid)) {
- x = xnext0;
- goto found;
- }
- /* if the rate is not illimited, garbage collect up to 3
- timed-out exchanges */
- if (rate != 0)
- checklost = 3;
- /* look for the exchange */
- ISC_TAILQ_FOREACH_SAFE(x, bucket, hchain, t) {
- double waited;
-
- if (x->xid == xid)
- goto found;
- if (checklost <= 0)
- continue;
- /* check for a timed-out exchange */
- waited = now.tv_sec - x->ts0.tv_sec;
- waited += (now.tv_nsec - x->ts0.tv_nsec) / 1e9;
- if (waited < losttime[0]) {
- checklost = 0;
- continue;
- }
- /* garbage collect timed-out exchange */
- checklost--;
- ISC_TAILQ_REMOVE(bucket, x, hchain);
- ISC_TAILQ_REMOVE(&xsent0, x, gchain);
- free(x);
- collected[0] += 1;
- }
- /* no match? very late or not for us */
- orphans++;
- return;
-
- /* got it: update stats and move to the received queue */
- found:
- xrcount0++;
- x->ts1 = now;
- delta = x->ts1.tv_sec - x->ts0.tv_sec;
- delta += (x->ts1.tv_nsec - x->ts0.tv_nsec) / 1e9;
- if (delta < dmin0)
- dmin0 = delta;
- if (delta > dmax0)
- dmax0 = delta;
- dsum0 += delta;
- dsumsq0 += delta * delta;
- xnext0 = ISC_TAILQ_NEXT(x, gchain);
- ISC_TAILQ_REMOVE(bucket, x, hchain);
- ISC_TAILQ_REMOVE(&xsent0, x, gchain);
- ISC_TAILQ_INSERT_TAIL(&xrcvd0, x, gchain);
- /* if the exchange is not finished, go to the second part */
- if (simple == 0) {
- int ret = 0;
-
- /* the server-ID option is needed */
- if ((usefirst != 0) && (gsrvid != NULL)) {
- x->sid = gsrvid;
- x->sidlen = gsrvidlen;
- } else
- ret = scan_for_srvid4(x, cc);
- if (ret >= 0)
- send_request4(x);
+ goto close;
}
+ receive_reply(idx, &now);
+ close:
+ p = plist + idx;
+ p->fd = -1;
+ (void) close(x->sock);
}
/*
- * get the DHCPv6 socket descriptor
+ * poll receive and timeouts (IPv4)
*/
void
-getsock6(void)
+pollrecv4(void)
{
- struct sockaddr_in6 *s6 = (struct sockaddr_in6 *) &serveraddr;
- int ret;
-
- /* update local port */
- if (localport != 0) {
- uint16_t lp = htons((uint16_t) localport);
-
- ((struct sockaddr_in6 *) &localaddr)->sin6_port = lp;
- }
- sock = socket(PF_INET6, SOCK_DGRAM, IPPROTO_UDP);
- if (sock < 0) {
- perror("socket");
- exit(1);
- }
- /* perform the multicast stuff when the destination is multicast */
- if (IN6_IS_ADDR_MULTICAST(&s6->sin6_addr)) {
- int hops = 1;
-
- ret = setsockopt(sock,
- IPPROTO_IPV6, IPV6_MULTICAST_HOPS,
- &hops, sizeof(hops));
- if (ret < 0) {
- perror("setsockopt(IPV6_MULTICAST_HOPS)");
- exit(1);
- }
- }
- if (isinterface && IN6_IS_ADDR_MULTICAST(&s6->sin6_addr)) {
- unsigned idx = if_nametoindex(localname);
+ struct exchange *x;
+ struct pollfd *p;
+ struct timespec now;
+ int idx = xsent, prev = -1;
+ int cnt = 5;
+ int checklost = 1;
+ double waited;
- if (idx == 0) {
- fprintf(stderr,
- "if_nametoindex(%s) failed\n",
- localname);
- exit(1);
- }
- ret = setsockopt(sock,
- IPPROTO_IPV6, IPV6_MULTICAST_IF,
- &idx, sizeof(idx));
- if (ret < 0) {
- perror("setsockopt(IPV6_MULTICAST_IF)");
- exit(1);
+ while (--cnt >= 0) {
+ if (idx < 0)
+ return;
+ x = xlist + idx;
+ p = plist + idx;
+ if (p->fd < 0)
+ goto next;
+ if ((p->revents & POLLIN) == 0) {
+ if (checklost == 0)
+ goto next;
+ /* check for a timed-out exchange */
+ if (clock_gettime(CLOCK_REALTIME, &now) < 0) {
+ perror("clock_gettime(receive)");
+ fatal = 1;
+ return;
+ }
+ waited = now.tv_sec - x->ts0.tv_sec;
+ waited += (now.tv_nsec - x->ts0.tv_nsec) / 1e9;
+ if (waited < losttime) {
+ checklost = 0;
+ goto next;
+ }
+ /* garbage collect timed-out exchange */
+ p->fd = -1;
+ (void) close(x->sock);
+ if (prev < 0)
+ xsent = x->chain;
+ else
+ xlist[prev].chain = x->chain;
+ prev = idx;
+ idx = x->chain;
+ x->chain = xfree;
+ xfree = idx;
+ collected += 1;
+ continue;
}
+ receive4(x);
+ prev = idx;
+ idx = x->chain;
+ x->chain = xfree;
+ xfree = idx;
+ continue;
+ next:
+ prev = idx;
+ idx = x->chain;
}
}
/*
- * build a DHCPv6 SOLICIT template
- * (implicit parameter is the DUID, don't assume an Ethernet link)
+ * get the TCP DNS socket descriptor (IPv6)
*/
-void
-build_template_solicit6(void)
+int
+getsock6(void)
{
- uint8_t *p = template_solicit6;
-
- xid_solicit6 = DHCP6_OFF_XID;
- /* message type */
- p[DHCP6_OFF_MSGTYP] = DHCP6_OP_SOLICIT;
- /* options */
- p += DHCP6_OFF_OPTIONS;
- /* elapsed time */
- p[1] = DHCP6_OPT_ELAPSED_TIME;
- p[3] = 2;
- p += 6;
- /* rapid commit */
- if (rapidcommit != 0) {
- p[1] = DHCP6_OPT_RAPID_COMMIT;
- p += 4;
- }
- /* client ID */
- p[1] = DHCP6_OPT_CLIENTID;
- p[3] = duid_length;
- memcpy(p + 4, duid_prefix, duid_length);
- p += 4 + duid_length;
- random_solicit6 = p - template_solicit6;
- /* option request option */
- p[1] = DHCP6_OPT_ORO;
- p[3] = 4;
- p[5] = DHCP6_OPT_NAME_SERVERS;
- p[7] = DHCP6_OPT_DOMAIN_SEARCH;
- p += 8;
- /* IA_NA (IAID = 1, T1 = 3600, T2 = 5400) */
- p[1] = DHCP6_OPT_IA_NA;
- p[3] = 12;
- p[7] = 1;
- p[10] = 3600 >> 8;
- p[11] = 3600 & 0xff;
- p[14] = 5400 >> 8;
- p[15] = 5400 & 0xff;
- p += 16;
- /* set length */
- length_solicit6 = p - template_solicit6;
-}
-
-/*
- * get a DHCPv6 first packet (usually a SOLICIT) template
- * from the file given in the command line (-T<template-file>)
- * and xid/rnd offsets (-X<xid-offset> and -O<random-offset>)
- */
+ int sock;
+ int flags;
-void
-get_template_solicit6(void)
-{
- uint8_t *p = template_solicit6;
- int fd, cc, i, j;
+ errno = 0;
+ sock = socket(PF_INET6, SOCK_STREAM, IPPROTO_TCP);
+ if (sock < 0)
+ return -errno;
- fd = open(templatefile[0], O_RDONLY);
- if (fd < 0) {
- fprintf(stderr, "open(%s): %s\n",
- templatefile[0], strerror(errno));
- exit(2);
- }
- cc = read(fd, tbuf, sizeof(tbuf));
- (void) close(fd);
- if (cc < 0) {
- fprintf(stderr, "read(%s): %s\n",
- templatefile[0], strerror(errno));
- exit(1);
- }
- if (cc < 10) {
- fprintf(stderr, "file '%s' too short\n", templatefile[0]);
- exit(2);
+ /* make the socket descriptor not blocking */
+ flags = fcntl(sock, F_GETFL, 0);
+ if (flags == -1) {
+ (void) close(sock);
+ return -errno;
}
- if (cc > 8193) {
- fprintf(stderr,"file '%s' too large\n", templatefile[0]);
- exit(2);
+ if (fcntl(sock, F_SETFL, flags | O_NONBLOCK) == -1) {
+ (void) close(sock);
+ return -errno;
}
- j = 0;
- for (i = 0; i < cc; i++) {
- if (isspace((int) tbuf[i]))
- continue;
- if (!isxdigit((int) tbuf[i])) {
- fprintf(stderr,
- "illegal char[%d]='%c' in file '%s'\n",
- i, (int) tbuf[i], templatefile[0]);
- exit(2);
+
+ /* bind if wanted */
+ if (locbind) {
+ if (bind(sock,
+ (struct sockaddr *) &localaddr,
+ sizeof(struct sockaddr_in6)) < 0) {
+ (void) close(sock);
+ return -errno;
}
- tbuf[j] = tbuf[i];
- j++;
- }
- cc = j;
- if ((cc & 1) != 0) {
- fprintf(stderr,
- "odd number of hexadecimal digits in file '%s'\n",
- templatefile[0]);
- exit(2);
}
- length_solicit6 = cc >> 1;
- for (i = 0; i < cc; i += 2)
- (void) sscanf(tbuf + i, "%02hhx", &p[i >> 1]);
- if (xidoffset[0] >= 0)
- xid_solicit6 = (size_t) xidoffset[0];
- else
- xid_solicit6 = DHCP6_OFF_XID;
- if (xid_solicit6 + 3 > length_solicit6) {
- fprintf(stderr,
- "xid (at %zu) is outside the template (length %zu)?\n",
- xid_solicit6, length_solicit6);
- exit(2);
- }
- if (rndoffset[0] >= 0)
- random_solicit6 = (size_t) rndoffset[0];
- else
- random_solicit6 = 0;
- if (random_solicit6 > length_solicit6) {
- fprintf(stderr,
- "random (at %zu) outside the template (length %zu)?\n",
- random_solicit6, length_solicit6);
- exit(2);
+
+ /* connect */
+ if (connect(sock,
+ (struct sockaddr *) &serveraddr,
+ sizeof(struct sockaddr_in6)) < 0) {
+ if (errno != EINPROGRESS) {
+ (void) close(sock);
+ return -errno;
+ }
}
+ return sock;
}
/*
- * build a DHCPv6 REQUEST template
- * (implicit parameter is the DUID, don't assume an Ethernet link)
+ * build a TCP DNS QUERY (IPv6)
*/
void
-build_template_request6(void)
+build_template_query6(void)
{
- uint8_t *p = template_request6;
-
- xid_request6 = DHCP6_OFF_XID;
- /* message type */
- p[DHCP6_OFF_MSGTYP] = DHCP6_OP_REQUEST;
- /* options */
- p += DHCP6_OFF_OPTIONS;
- /* elapsed time */
- p[1] = DHCP6_OPT_ELAPSED_TIME;
- p[3] = 2;
- p += 4;
- elapsed_request6 = p - template_request6;
- p += 2;
- /* client ID */
- p[1] = DHCP6_OPT_CLIENTID;
- p[3] = duid_length;
- memcpy(p + 4, duid_prefix, duid_length);
- p += 4 + duid_length;
- random_request6 = p - template_request6;
- /* option request option */
- p[1] = DHCP6_OPT_ORO;
- p[3] = 4;
- p[5] = DHCP6_OPT_NAME_SERVERS;
- p[7] = DHCP6_OPT_DOMAIN_SEARCH;
- p += 8;
- /* server ID and IA_NA */
- serverid_request6 = p - template_request6;
- reqaddr_request6 = p - template_request6;
- /* set length */
- length_request6 = p - template_request6;
+ uint8_t *p = template_query6;
+ uint16_t v;
+
+ /* flags */
+ p += NS_OFF_FLAGS;
+ v = NS_FLAG_RD;
+ *p++ = v >> 8;
+ *p++ = v & 0xff;
+ /* qdcount */
+ v = 1;
+ *p++ = v >> 8;
+ *p++ = v & 0xff;
+ /* ancount */
+ v = 0;
+ *p++ = v >> 8;
+ *p++ = v & 0xff;
+ /* nscount */
+ v = 0;
+ *p++ = v >> 8;
+ *p++ = v & 0xff;
+ /* arcount */
+ v = 0;
+ *p++ = v >> 8;
+ *p++ = v & 0xff;
+ /* icann.link */
+ *p++ = 5;
+ *p++ = 'i';
+ *p++ = 'c';
+ *p++ = 'a';
+ *p++ = 'n';
+ *p++ = 'n';
+ *p++ = 4;
+ *p++ = 'l';
+ *p++ = 'i';
+ *p++ = 'n';
+ *p++ = 'k';
+ *p++ = 0;
+ /* type AAAA */
+ v = NS_TYPE_AAAA;
+ *p++ = v >> 8;
+ *p++ = v & 0xff;
+ /* class IN */
+ v = NS_CLASS_IN;
+ *p++ = v >> 8;
+ *p++ = v & 0xff;
+ /* length */
+ length_query6 = p - template_query6;
+ template_query6[0] = (length_query6 >> 8) & 0xff;
+ template_query6[1] = length_query6 & 0xff;
}
/*
- * get a DHCPv6 third packet (usually a REQUEST) template
+ * get a TCP/IPv6 DNS clinet QUERY template
* from the file given in the command line (-T<template-file>)
- * and offsets (-X,-O,-E,-S,-I).
+ * and rnd offset (-O<random-offset>)
*/
void
-get_template_request6(void)
+get_template_query6(void)
{
- uint8_t *p = template_request6;
+ uint8_t *p = template_query6;
int fd, cc, i, j;
- fd = open(templatefile[1], O_RDONLY);
+ fd = open(templatefile, O_RDONLY);
if (fd < 0) {
fprintf(stderr, "open(%s): %s\n",
- templatefile[1], strerror(errno));
+ templatefile, strerror(errno));
exit(2);
}
cc = read(fd, tbuf, sizeof(tbuf));
(void) close(fd);
if (cc < 0) {
fprintf(stderr, "read(%s): %s\n",
- templatefile[1], strerror(errno));
+ templatefile, strerror(errno));
exit(1);
}
- if (cc < 10) {
- fprintf(stderr, "file '%s' too short\n", templatefile[1]);
+ if (cc < NS_OFF_QUESTION + 4) {
+ fprintf(stderr, "file '%s' too short\n", templatefile);
exit(2);
}
- if (cc > 8193) {
- fprintf(stderr,"file '%s' too large\n", templatefile[1]);
+ if (cc > 511) {
+ fprintf(stderr,"file '%s' too large\n", templatefile);
exit(2);
}
j = 0;
@@ -1390,7 +855,7 @@ get_template_request6(void)
if (!isxdigit((int) tbuf[i])) {
fprintf(stderr,
"illegal char[%d]='%c' in file '%s'\n",
- i, (int) tbuf[i], templatefile[1]);
+ i, (int) tbuf[i], templatefile);
exit(2);
}
tbuf[j] = tbuf[i];
@@ -1400,193 +865,83 @@ get_template_request6(void)
if ((cc & 1) != 0) {
fprintf(stderr,
"odd number of hexadecimal digits in file '%s'\n",
- templatefile[1]);
+ templatefile);
exit(2);
}
- length_request6 = cc >> 1;
+ length_query6 = cc >> 1;
for (i = 0; i < cc; i += 2)
(void) sscanf(tbuf + i, "%02hhx", &p[i >> 1]);
- if (xidoffset[1] >= 0)
- xid_request6 = (size_t) xidoffset[1];
- else
- xid_request6 = DHCP6_OFF_XID;
- if (xid_request6 + 3 > length_request6) {
- fprintf(stderr,
- "xid (at %zu) is outside the template (length %zu)?\n",
- xid_request6, length_request6);
- exit(2);
- }
- if (rndoffset[1] >= 0)
- random_request6 = (size_t) rndoffset[1];
- else
- random_request6 = 0;
- if (random_request6 > length_request6) {
+ if (rndoffset >= 0)
+ random_query6 = (size_t) rndoffset;
+ if (random_query6 > length_query6) {
fprintf(stderr,
"random (at %zu) outside the template (length %zu)?\n",
- random_request6, length_request6);
- exit(2);
- }
- if (elpoffset >= 0)
- elapsed_request6 = (size_t) elpoffset;
- if (elapsed_request6 + 2 > length_request6) {
- fprintf(stderr,
- "secs (at %zu) outside the template (length %zu)?\n",
- elapsed_request6, length_request6);
- exit(2);
- }
- serverid_request6 = (size_t) sidoffset;
- if (serverid_request6 > length_request6) {
- fprintf(stderr,
- "server-id option (at %zu) outside the template "
- "(length %zu)?\n",
- serverid_request6, length_request6);
- exit(2);
- }
- reqaddr_request6 = (size_t) ripoffset;
- if (reqaddr_request6 > length_request6) {
- fprintf(stderr,
- "requested-ip-address option (at %zu) outside "
- "the template (length %zu)?\n",
- reqaddr_request6, length_request6);
+ random_query6, length_query6);
exit(2);
}
}
/*
- * send the DHCPv6 REQUEST third packet
- * (the transaction ID is odd)
- * (TODO: check for errors in the ADVERTISE)
+ * connect the TCP DNS QUERY (IPv6)
*/
-void
-send_request6(struct exchange *x0)
+int
+connect6(void)
{
struct exchange *x;
- struct xlist *bucket;
- size_t len;
- uint32_t hash;
+ struct pollfd *p;
ssize_t ret;
-
- x = (struct exchange *) malloc(sizeof(*x));
- if (x == NULL) {
- locallimit++;
- perror("send2");
- return;
- }
-
- memcpy(x, x0, sizeof(*x));
- x->order2 = xscount2++;
- x->xid |= 1;
- hash = x->xid >> 1;
-
- ISC_TAILQ_INSERT_TAIL(&xsent2, x, gchain);
- hash &= hashsize2 - 1;
- bucket = (struct xlist *) (exchanges2 + hash * sizeof(*bucket));
- ISC_TAILQ_INSERT_TAIL(bucket, x, hchain);
-
- len = length_request6;
- memcpy(obuf, template_request6, len);
- /* xid */
- obuf[xid_request6] = x->xid >> 16;
- obuf[xid_request6 + 1] = x->xid >> 8;
- obuf[xid_request6 + 2] = x->xid;
- /* random */
- randomize(random_request6, x->rnd);
- /* elapsed time */
- if (elapsed_request6 > 0) {
- int et;
-
- et = (x->ts1.tv_sec - x->ts0.tv_sec) * 100;
- et += (x->ts1.tv_nsec - x->ts0.tv_nsec) / 10000000;
- if (et > 65535) {
- obuf[elapsed_request6] = 0xff;
- obuf[elapsed_request6 + 1] = 0xff;
- } else if (et > 0) {
- obuf[elapsed_request6] = et >> 8;
- obuf[elapsed_request6 + 1] = et & 0xff;
- }
- }
- /* server ID */
- if (serverid_request6 < length_request6)
- memmove(obuf + serverid_request6 + x->sidlen,
- obuf + serverid_request6,
- x->sidlen);
- memcpy(obuf + serverid_request6, x->sid, x->sidlen);
- len += x->sidlen;
- /* IA_NA */
- if (reqaddr_request6 < serverid_request6) {
- memmove(obuf + reqaddr_request6 + x->ianalen,
- obuf + reqaddr_request6,
- x->ianalen);
- memcpy(obuf + reqaddr_request6, x->iana, x->ianalen);
- } else if (reqaddr_request6 < length_request6) {
- memmove(obuf + reqaddr_request6 + x->sidlen + x->ianalen,
- obuf + reqaddr_request6 + x->sidlen,
- x->ianalen);
- memcpy(obuf + reqaddr_request6+ x->sidlen,
- x->iana,
- x->ianalen);
+ int idx;
+
+ if (xfree >= 0) {
+ idx = xfree;
+ x = xlist + idx;
+ p = plist + idx;
+ xfree = x->chain;
+ } else if (xused < xlast) {
+ idx = xused;
+ x = xlist + idx;
+ p = plist + idx;
+ xused++;
} else
- memcpy(obuf + len, x->iana, x->ianalen);
- len += x->ianalen;
+ return -ENOMEM;
- /* timestamp */
- ret = clock_gettime(CLOCK_REALTIME, &x->ts2);
- if (ret < 0) {
- perror("clock_gettime(send2)");
- fatal = 1;
- return;
- }
- ret = sendto(sock, obuf, len, 0,
- (struct sockaddr *) &serveraddr,
- sizeof(struct sockaddr_in6));
- if (ret >= 0)
- return;
- if ((errno == EAGAIN) || (errno == EWOULDBLOCK) ||
- (errno == ENOBUFS) || (errno == ENOMEM))
- locallimit++;
- perror("send2");
+ memset(x, 0, sizeof(*x));
+ memset(p, 0, sizeof(*p));
+ x->sock = getsock6();
+ if (x->sock < 0) {
+ x->chain = xfree;
+ xfree = idx;
+ return x->sock;
+ }
+ p->fd = x->sock;
+ p->events = POLLOUT;
+ x->chain = xconn;
+ xconn = idx;
+ x->order = xccount++;
+ x->id = (uint16_t) random();
+ if (random_query6 > 0)
+ x->rnd = (uint32_t) random();
+ return idx;
}
/*
- * send the DHCPv6 SOLICIT first packet
- * (for 4-exchange, the transaction ID xid is even)
+ * send the TCP DNS QUERY (IPv6)
*/
int
-send6(void)
+send6(struct exchange *x)
{
- struct exchange *x;
- struct xlist *bucket;
- uint32_t hash;
ssize_t ret;
- x = (struct exchange *) malloc(sizeof(*x));
- if (x == NULL)
- return -ENOMEM;
-
- memset(x, 0, sizeof(*x));
- x->order0 = xscount0++;
- hash = x->rnd = (uint32_t) random();
- if (simple == 0)
- x->xid = (hash << 1) & 0x00ffffff;
- else
- x->xid = hash & 0x00ffffff;
-
- ISC_TAILQ_INSERT_TAIL(&xsent0, x, gchain);
- hash &= hashsize0 - 1;
- bucket = (struct xlist *) (exchanges0 + hash * sizeof(*bucket));
- ISC_TAILQ_INSERT_TAIL(bucket, x, hchain);
-
- memcpy(obuf, template_solicit6, length_solicit6);
- /* xid */
- obuf[xid_solicit6] = x->xid >> 16;
- obuf[xid_solicit6 + 1] = x->xid >> 8;
- obuf[xid_solicit6 + 2] = x->xid;
+ memcpy(obuf, template_query6, length_query6);
+ /* ID */
+ memcpy(obuf + NS_OFF_ID, &x->id, 2);
/* random */
- x->rnd = randomize(random_solicit6, x->rnd);
-
+ if (random_query6 > 0)
+ x->rnd = randomize(random_query6, x->rnd);
/* timestamp */
+ errno = 0;
ret = clock_gettime(CLOCK_REALTIME, &last);
if (ret < 0) {
perror("clock_gettime(send)");
@@ -1594,279 +949,184 @@ send6(void)
return -errno;
}
x->ts0 = last;
- errno = 0;
- ret = sendto(sock, obuf, length_solicit6, 0,
- (struct sockaddr *) &serveraddr,
- sizeof(struct sockaddr_in6));
- if (ret == (ssize_t) length_solicit6)
+ ret = send(x->sock, obuf, length_query6, 0);
+ if (ret == (ssize_t) length_query6)
return 0;
return -errno;
}
/*
- * scan a DHCPv6 ADVERTISE to get its server-id option
+ * poll connected and send (IPv6)
*/
-int
-scan_for_srvid6(struct exchange *x, size_t cc)
-{
- size_t off = DHCP6_OFF_OPTIONS, len;
-
- for (;;) {
- if (off + 4 > cc) {
- fprintf(stderr, "server-id not found\n");
- return -1;
- }
- if ((ibuf[off] == 0) && (ibuf[off + 1] == DHCP6_OPT_SERVERID))
- break;
- off += 4 + (ibuf[off + 2] << 8) + ibuf[off + 3];
- }
- len = 4 + (ibuf[off + 2] << 8) + ibuf[off + 3];
- /* cache it in the global variables when required and not yet done */
- if ((usefirst != 0) && (gsrvid == NULL)) {
- if (len <= sizeof(gsrvidbuf)) {
- memcpy(gsrvidbuf, ibuf + off, len);
- gsrvid = gsrvidbuf;
- gsrvidlen = len;
- } else {
- gsrvid = (uint8_t *) malloc(len);
- if (gsrvid == NULL) {
- perror("malloc(gsrvid");
- return -1;
- }
- memcpy(gsrvid, ibuf + off, len);
- gsrvidlen = len;
- }
- }
- x->sid = ibuf + off;
- x->sidlen = len;
- return 0;
-}
-
-/*
- * scan a DHCPv6 ADVERTISE to get its IA_NA option
- * (TODO: check for errors)
- */
-
-int
-scan_for_ia_na(struct exchange *x, size_t cc)
+void
+pollsend6(void)
{
- size_t off = DHCP6_OFF_OPTIONS, len;
-
- for (;;) {
- if (off + 4 > cc) {
- fprintf(stderr, "ia-na not found\n");
- return -1;
- }
- if ((ibuf[off] == 0) && (ibuf[off + 1] == DHCP6_OPT_IA_NA))
- break;
- off += 4 + (ibuf[off + 2] << 8) + ibuf[off + 3];
+ struct exchange *x;
+ struct pollfd *p;
+ int idx = xconn, prev = -1;
+ int cnt = 10;
+ int err;
+ socklen_t len = sizeof(int);
+
+ while (--cnt >= 0) {
+ if (idx < 0)
+ return;
+ x = xlist + idx;
+ p = plist + idx;
+ if (p->fd < 0)
+ goto next;
+ if ((p->revents & POLLOUT) == 0)
+ goto next;
+ p->revents = 0;
+ if (getsockopt(p->fd, SOL_SOCKET, SO_ERROR,
+ &err, &len) < 0)
+ goto close;
+ if (err != 0)
+ goto close;
+ if (send6(x) < 0)
+ goto close;
+ xscount++;
+ p->events = POLLIN;
+ if (prev < 0)
+ xconn = x->chain;
+ else
+ xlist[prev].chain = x->chain;
+ prev = idx;
+ idx = x->chain;
+ x->chain = xsent;
+ xsent = prev;
+ continue;
+ next:
+ prev = idx;
+ idx = x->chain;
+ continue;
+ close:
+ (void) close(p->fd);
+ p->fd = -1;
+ if (prev < 0)
+ xconn = x->chain;
+ else
+ xlist[prev].chain = x->chain;
+ prev = idx;
+ idx = x->chain;
+ x->chain = xfree;
+ xfree = prev;
}
- len = 4 + (ibuf[off + 2] << 8) + ibuf[off + 3];
- x->iana = ibuf + off;
- x->ianalen = len;
- return 0;
}
/*
- * receive a DHCPv6 packet
+ * receive a TCP DNS RESPONSE (IPv6)
*/
void
-receive6(void)
+receive6(struct exchange *x)
{
- struct exchange *x, *t;
- struct xlist *bucket;
+ struct pollfd *p;
struct timespec now;
+ int idx = x - xlist;
ssize_t cc;
- uint32_t xid, hash;
- int checklost = 0;
+ uint16_t v;
double delta;
- cc = recv(sock, ibuf, sizeof(ibuf), 0);
+ cc = recv(x->sock, ibuf, sizeof(ibuf), 0);
if (cc < 0) {
if ((errno == EAGAIN) ||
(errno == EWOULDBLOCK) ||
(errno == EINTR))
- return;
+ goto close;
perror("recv");
fatal = 1;
- return;
+ goto close;
}
/* enforce a reasonable length */
- if (cc < 22) {
+ if (cc < length_query6) {
tooshort++;
- return;
- }
+ goto close;
+ }
+ /* must match the ID */
+ if (memcmp(ibuf + NS_OFF_ID, &x->id, 2) != 0)
+ goto close;
+ /* must be a response */
+ memcpy(ibuf + NS_OFF_FLAGS, &v, 2);
+ v = ntohs(v);
+ if ((v & NS_FLAG_QR) == 0)
+ goto close;
if (clock_gettime(CLOCK_REALTIME, &now) < 0) {
perror("clock_gettime(receive)");
fatal = 1;
- return;
- }
- xid = ibuf[xid_solicit6] << 16;
- xid |= ibuf[xid_solicit6 + 1] << 8;
- xid |= ibuf[xid_solicit6 + 2];
- /* 4-packet exchange even/odd xid */
- if (simple == 0) {
- if ((xid & 1) != 0) {
- receive_reply(xid, &now);
- return;
- }
- hash = (xid >> 1) & (hashsize0 - 1);
- } else
- hash = xid & (hashsize0 - 1);
- /* now it is the second packet, get the bucket which is needed */
- bucket = (struct xlist *) (exchanges0 + hash * sizeof(*bucket));
- /* try the 'next to be received' cache */
- if ((xnext0 != NULL) && (xnext0->xid == xid)) {
- x = xnext0;
- goto found;
- }
- /* if the rate is not illimited, garbage collect up to 3
- timed-out exchanges */
- if (rate != 0)
- checklost = 3;
- /* look for the exchange */
- ISC_TAILQ_FOREACH_SAFE(x, bucket, hchain, t) {
- double waited;
-
- if (x->xid == xid)
- goto found;
- if (checklost <= 0)
- continue;
- /* check for a timed-out exchange */
- waited = now.tv_sec - x->ts0.tv_sec;
- waited += (now.tv_nsec - x->ts0.tv_nsec) / 1e9;
- if (waited < losttime[0]) {
- checklost = 0;
- continue;
- }
- /* garbage collect timed-out exchange */
- checklost--;
- ISC_TAILQ_REMOVE(bucket, x, hchain);
- ISC_TAILQ_REMOVE(&xsent0, x, gchain);
- free(x);
- collected[0] += 1;
- }
- /* no match? very late or not for us */
- orphans++;
- return;
-
- /* got it: update stats and move to the received queue */
- found:
- xrcount0++;
- x->ts1 = now;
- delta = x->ts1.tv_sec - x->ts0.tv_sec;
- delta += (x->ts1.tv_nsec - x->ts0.tv_nsec) / 1e9;
- if (delta < dmin0)
- dmin0 = delta;
- if (delta > dmax0)
- dmax0 = delta;
- dsum0 += delta;
- dsumsq0 += delta * delta;
- xnext0 = ISC_TAILQ_NEXT(x, gchain);
- ISC_TAILQ_REMOVE(bucket, x, hchain);
- ISC_TAILQ_REMOVE(&xsent0, x, gchain);
- ISC_TAILQ_INSERT_TAIL(&xrcvd0, x, gchain);
- /* if the exchange is not finished, go to the second part */
- if (simple == 0) {
- int ret = 0;
-
- /* the server-ID option is needed */
- if ((usefirst != 0) && (gsrvid != NULL)) {
- x->sid = gsrvid;
- x->sidlen = gsrvidlen;
- } else
- ret = scan_for_srvid6(x, cc);
- /* and the IA_NA option too */
- if (ret >= 0)
- ret = scan_for_ia_na(x, cc);
- if (ret >= 0)
- send_request6(x);
+ goto close;
}
+ receive_reply(idx, &now);
+ close:
+ p = plist + idx;
+ p->fd = -1;
+ (void) close(x->sock);
}
/*
- * decode a base command line parameter
- * (currently only MAC address and DUID are supported)
+ * poll receive and timeouts (IPv6)
*/
void
-decodebase(void)
+pollrecv6(void)
{
- char *b0 = base[basecnt];
-
- /* MAC address (alias Ethernet address) */
- if ((strncasecmp(b0, "mac=", 4) == 0) ||
- (strncasecmp(b0, "ether=", 6) == 0)) {
- char *b;
-
- b = strchr(b0, '=') + 1;
- if (sscanf(b, "%02hhx:%02hhx:%02hhx:%02hhx:%02hhx:%02hhx",
- &mac_prefix[0], &mac_prefix[1],
- &mac_prefix[2], &mac_prefix[3],
- &mac_prefix[4], &mac_prefix[5]) == 6) {
- if ((diags != NULL) && (strchr(diags, 'a') != NULL))
- printf("set MAC to %s\n", b);
- return;
- }
- fprintf(stderr,
- "expected base in '%*s=xx:xx:xx:xx:xx:xx' format\n",
- (int) (b - b0 - 1), b0);
- exit(2);
- }
- /* DUID */
- if (strncasecmp(b0, "duid=", 5) == 0) {
- char *b;
- size_t i, l;
+ struct exchange *x;
+ struct pollfd *p;
+ struct timespec now;
+ int idx = xsent, prev = -1;
+ int cnt = 5;
+ int checklost = 1;
+ double waited;
- if (duid_prefix != NULL) {
- fprintf(stderr, "duid was already set?\n");
- exit(2);
- }
- b = strchr(b0, '=') + 1;
- l = 0;
- while (*b != '\0') {
- if (!isxdigit((int) *b)) {
- fprintf(stderr,
- "illegal char '%c' in duid\n",
- (int) *b);
- exit(2);
+ while (--cnt >= 0) {
+ if (idx < 0)
+ return;
+ x = xlist + idx;
+ p = plist + idx;
+ if (p->fd < 0)
+ goto next;
+ if ((p->revents & POLLIN) == 0) {
+ if (checklost == 0)
+ goto next;
+ /* check for a timed-out exchange */
+ if (clock_gettime(CLOCK_REALTIME, &now) < 0) {
+ perror("clock_gettime(receive)");
+ fatal = 1;
+ return;
}
- b++;
- l++;
- }
- if ((l & 1) != 0) {
- fprintf(stderr,
- "odd number of hexadecimal digits in duid\n");
- exit(2);
- }
- l /= 2;
- if (l > 64) {
- fprintf(stderr, "duid too large\n");
- exit(2);
- }
- duid_prefix = (uint8_t *) malloc(l);
- if (duid_prefix == NULL) {
- perror("malloc(duid)");
- exit(1);
- }
- b = strchr(b0, '=') + 1;
- for (i = 0; i < l; i++, b += 2)
- (void) sscanf(b, "%02hhx", &duid_prefix[i]);
- duid_length = l;
- if ((diags != NULL) && (strchr(diags, 'a') != NULL)) {
- b = strchr(b0, '=') + 1;
- printf("set DUID[%d] to %s\n",
- duid_length, b);
+ waited = now.tv_sec - x->ts0.tv_sec;
+ waited += (now.tv_nsec - x->ts0.tv_nsec) / 1e9;
+ if (waited < losttime) {
+ checklost = 0;
+ goto next;
+ }
+ /* garbage collect timed-out exchange */
+ p->fd = -1;
+ (void) close(x->sock);
+ if (prev < 0)
+ xsent = x->chain;
+ else
+ xlist[prev].chain = x->chain;
+ prev = idx;
+ idx = x->chain;
+ x->chain = xfree;
+ xfree = idx;
+ collected += 1;
+ continue;
}
- return;
+ receive6(x);
+ prev = idx;
+ idx = x->chain;
+ x->chain = xfree;
+ xfree = idx;
+ continue;
+ next:
+ prev = idx;
+ idx = x->chain;
}
- /* other */
- fprintf(stderr, "not yet supported base '%s'\n", b0);
- exit(2);
}
-
+
/*
* get the server socket address from the command line:
* - flags: inherited from main, 0 or AI_NUMERICHOST (for literals)
@@ -1882,14 +1142,14 @@ getserveraddr(const int flags)
memset(&hints, 0, sizeof(hints));
if (ipversion == 4) {
hints.ai_family = AF_INET;
- service = "67";
+ service = "53";
} else {
hints.ai_family = AF_INET6;
- service = "547";
+ service = "53";
}
- hints.ai_socktype = SOCK_DGRAM;
+ hints.ai_socktype = SOCK_STREAM;
hints.ai_flags = AI_ADDRCONFIG | AI_NUMERICSERV | flags;
- hints.ai_protocol = IPPROTO_UDP;
+ hints.ai_protocol = IPPROTO_TCP;
ret = getaddrinfo(servername, service, &hints, &res);
if (ret != 0) {
@@ -1906,67 +1166,7 @@ getserveraddr(const int flags)
}
/*
- * get the interface from the command line:
- * - name of the interface
- * - socket address to fill
- * (in IPv6, get the first link-local address)
- */
-
-void
-getinterface(const char *name, struct sockaddr_storage *ss)
-{
- struct ifaddrs *ifaddr, *ifa;
- int ret;
- size_t len;
-
- ret = getifaddrs(&ifaddr);
- if (ret < 0) {
- perror("getifaddrs");
- exit(1);
- }
-
- for (ifa = ifaddr; ifa != NULL; ifa = ifa->ifa_next) {
- if (ifa->ifa_name == NULL)
- continue;
- if (strcmp(ifa->ifa_name, name) != 0)
- continue;
- if ((ifa->ifa_flags & IFF_UP) == 0)
- continue;
- if ((ifa->ifa_flags & IFF_MULTICAST) == 0)
- continue;
- if (ifa->ifa_addr == NULL)
- continue;
- if ((ipversion == 4) &&
- (ifa->ifa_addr->sa_family != AF_INET))
- continue;
- if (ipversion == 6) {
- struct sockaddr_in6 *a6;
-
- a6 = (struct sockaddr_in6 *) ifa->ifa_addr;
- if (a6->sin6_family != AF_INET6)
- continue;
- if (!IN6_IS_ADDR_LINKLOCAL(&a6->sin6_addr))
- continue;
- }
- if (ipversion == 4)
- len = sizeof(struct sockaddr_in);
- else
- len = sizeof(struct sockaddr_in6);
- memcpy(ss, ifa->ifa_addr, len);
- /* fill the server port */
- if (ipversion == 4)
- ((struct sockaddr_in *) ss)->sin_port = htons(67);
- else
- ((struct sockaddr_in6 *) ss)->sin6_port = htons(546);
- return;
- }
- fprintf(stderr, "can't find interface %s\n", name);
- exit(1);
-}
-
-/*
* get the local socket address from the command line
- * (if it doesn't work, try an interface name)
*/
void
@@ -1979,25 +1179,16 @@ getlocaladdr(void)
memset(&hints, 0, sizeof(hints));
if (ipversion == 4) {
hints.ai_family = AF_INET;
- service = "67";
+ service = "53";
} else {
hints.ai_family = AF_INET6;
- service = "546";
+ service = "53";
}
- hints.ai_socktype = SOCK_DGRAM;
+ hints.ai_socktype = SOCK_STREAM;
hints.ai_flags = AI_ADDRCONFIG | AI_NUMERICSERV;
- hints.ai_protocol = IPPROTO_UDP;
+ hints.ai_protocol = IPPROTO_TCP;
ret = getaddrinfo(localname, service, &hints, &res);
- if ((ret == EAI_NONAME)
-#ifdef EAI_NODATA
- || (ret == EAI_NODATA)
-#endif
- ) {
- isinterface = 1;
- getinterface(localname, &localaddr);
- return;
- }
if (ret != 0) {
fprintf(stderr,
"bad -l<local-addr=%s>: %s\n",
@@ -2008,62 +1199,13 @@ getlocaladdr(void)
/* refuse multiple addresses */
if (res->ai_next != NULL) {
fprintf(stderr,
- "ambiguous -l<local-addr=%s>\n",
- localname);
- exit(2);
- }
- memcpy(&localaddr, res->ai_addr, res->ai_addrlen);
- freeaddrinfo(res);
- return;
-}
-
-/*
- * get the local socket address from the server one
- */
-
-void
-getlocal(void)
-{
- int ret, s;
- socklen_t l;
-
- if (ipversion == 4) {
- l = sizeof(struct sockaddr_in);
- s = socket(PF_INET, SOCK_DGRAM, 0);
- } else {
- l = sizeof(struct sockaddr_in6);
- s = socket(PF_INET6, SOCK_DGRAM, 0);
- }
- if (s < 0) {
- perror("socket");
- exit(1);
- }
- if ((ipversion == 4) && (isbroadcast != 0)) {
- int on = 1;
-
- ret = setsockopt(s, SOL_SOCKET, SO_BROADCAST, &on, sizeof(on));
- if (ret < 0) {
- perror("setsockopt(SO_BROADCAST)");
- exit(1);
- }
- }
- ret = connect(s, (struct sockaddr *) &serveraddr, l);
- if (ret < 0) {
- perror("connect");
- exit(1);
- }
- l = sizeof(localaddr);
- ret = getsockname(s, (struct sockaddr *) &localaddr, &l);
- if (ret < 0) {
- perror("getsockname");
- exit(1);
+ "ambiguous -l<local-addr=%s>\n",
+ localname);
+ exit(2);
}
- (void) close(s);
- /* fill the local port */
- if (ipversion == 4)
- ((struct sockaddr_in *) &localaddr)->sin_port = htons(67);
- else
- ((struct sockaddr_in6 *) &localaddr)->sin6_port = htons(546);
+ memcpy(&localaddr, res->ai_addr, res->ai_addrlen);
+ freeaddrinfo(res);
+ return;
}
/*
@@ -2076,37 +1218,17 @@ reporting(void)
{
dreport.tv_sec += report;
- if (xscount2 == 0) {
+ if (xscount == 0) {
printf("sent: %llu, received: %llu (drops: %lld)",
- (unsigned long long) xscount0,
- (unsigned long long) xrcount0,
- (long long) (xscount0 - xrcount0));
- if (!ISC_TAILQ_EMPTY(&xrcvd0)) {
+ (unsigned long long) xscount,
+ (unsigned long long) xrcount,
+ (long long) (xscount - xrcount));
+ if (xrcount != 0) {
double avg;
- avg = dsum0 / xrcount0;
+ avg = dsum / xrcount;
printf(" average: %.3f ms", avg * 1e3);
}
- } else {
- printf("sent: %llu/%llu received: %llu/%llu "
- "(drops: %lld/%lld)",
- (unsigned long long) xscount0,
- (unsigned long long) xscount2,
- (unsigned long long) xrcount0,
- (unsigned long long) xrcount2,
- (long long) (xscount0 - xrcount0),
- (long long) (xscount2 - xrcount2));
- if (!ISC_TAILQ_EMPTY(&xrcvd0)) {
- double avg0, avg2;
-
- avg0 = dsum0 / xrcount0;
- if (xrcount2 != 0)
- avg2 = dsum2 / xrcount2;
- else
- avg2 = 0.;
- printf(" average: %.3f/%.3f ms",
- avg0 * 1e3, avg2 * 1e3);
- }
}
printf("\n");
}
@@ -2154,72 +1276,43 @@ void
usage(void)
{
fprintf(stderr, "%s",
-"perfdhcp [-hv] [-4|-6] [-r<rate>] [-t<report>] [-R<range>] [-b<base>]\n"
+"perftcpdns [-hv] [-4|-6] [-r<rate>] [-t<report>] [-R<range>] [-b<base>]\n"
" [-n<num-request>] [-p<test-period>] [-d<drop-time>] [-D<max-drop>]\n"
-" [-l<local-addr|interface>] [-P<preload>] [-a<aggressivity>]\n"
-" [-L<local-port>] [-s<seed>] [-i] [-B] [-c] [-1]\n"
-" [-T<template-file>] [-X<xid-offset>] [-O<random-offset]\n"
-" [-E<time-offset>] [-S<srvid-offset>] [-I<ip-offset>]\n"
+" [-l<local-addr>] [-P<preload>] [-a<aggressivity>]\n"
+" [-L<local-port>] [-s<seed>] [-M<memory>]\n"
+" [-T<template-file>] [-O<random-offset]\n"
" [-x<diagnostic-selector>] [-w<wrapped>] [server]\n"
"\f\n"
-"The [server] argument is the name/address of the DHCP server to\n"
-"contact. For DHCPv4 operation, exchanges are initiated by\n"
-"transmitting a DHCP DISCOVER to this address.\n"
+"The [server] argument is the name/address of the DNS server to contact.\n"
"\n"
-"For DHCPv6 operation, exchanges are initiated by transmitting a DHCP\n"
-"SOLICIT to this address. In the DHCPv6 case, the special name 'all'\n"
-"can be used to refer to All_DHCP_Relay_Agents_and_Servers (the\n"
-"multicast address FF02::1:2), or the special name 'servers' to refer\n"
-"to All_DHCP_Servers (the multicast address FF05::1:3). The [server]\n"
-"argument is optional only in the case that -l is used to specify an\n"
-"interface, in which case [server] defaults to 'all'.\n"
-"\n"
-"The default is to perform a single 4-way exchange, effectively pinging\n"
-"the server.\n"
"The -r option is used to set up a performance test, without\n"
"it exchanges are initiated as fast as possible.\n"
"\n"
"Options:\n"
-"-1: Take the server-ID option from the first received message.\n"
-"-4: DHCPv4 operation (default). This is incompatible with the -6 option.\n"
-"-6: DHCPv6 operation. This is incompatible with the -4 option.\n"
+"-4: TCP/IPv4 operation (default). This is incompatible with the -6 option.\n"
+"-6: TCP/IPv6 operation. This is incompatible with the -4 option.\n"
"-a<aggressivity>: When the target sending rate is not yet reached,\n"
" control how many exchanges are initiated before the next pause.\n"
-"-b<base>: The base MAC, DUID, IP, etc, used to simulate different\n"
-" clients. This can be specified multiple times, each instance is\n"
+"-b<base>: The base XXX, etc, used to simulate different queries\n"
+" This can be specified multiple times, each instance is\n"
" in the <type>=<value> form, for instance:\n"
-" (and default) MAC=00:0c:01:02:03:04.\n"
-"-d<drop-time>: Specify the time after which a request is treated as\n"
+" (and default) XXX=...\n"
+"-d<drop-time>: Specify the time after which a query is treated as\n"
" having been lost. The value is given in seconds and may contain a\n"
" fractional component. The default is 1 second.\n"
-"-E<time-offset>: Offset of the (DHCPv4) secs field / (DHCPv6)\n"
-" elapsed-time option in the (second/request) template.\n"
-" The value 0 disables it.\n"
"-h: Print this help.\n"
-"-i: Do only the initial part of an exchange: DO or SA, depending on\n"
-" whether -6 is given.\n"
-"-I<ip-offset>: Offset of the (DHCPv4) IP address in the requested-IP\n"
-" option / (DHCPv6) IA_NA option in the (second/request) template.\n"
-"-l<local-addr|interface>: For DHCPv4 operation, specify the local\n"
-" hostname/address to use when communicating with the server. By\n"
-" default, the interface address through which traffic would\n"
-" normally be routed to the server is used.\n"
-" For DHCPv6 operation, specify the name of the network interface\n"
-" via which exchanges are initiated.\n"
-"-L<local-port>: Specify the local port to use\n"
-" (the value 0 means to use the default).\n"
+"-l<local-addr>: Specify the local hostname/address to use when\n"
+" communicating with the server.\n"
+"-M<memory>: Size of the tables (default 60000)\n"
"-O<random-offset>: Offset of the last octet to randomize in the template.\n"
"-P<preload>: Initiate first <preload> exchanges back to back at startup.\n"
-"-r<rate>: Initiate <rate> DORA/SARR (or if -i is given, DO/SA)\n"
-" exchanges per second. A periodic report is generated showing the\n"
-" number of exchanges which were not completed, as well as the\n"
-" average response latency. The program continues until\n"
-" interrupted, at which point a final report is generated.\n"
-"-R<range>: Specify how many different clients are used. With 1\n"
-" (the default), all requests seem to come from the same client.\n"
+
+"-r<rate>: Initiate <rate> TCP DNS exchanges per second. A periodic\n"
+" report is generated showing the number of exchanges which were not\n"
+" completed, as well as the average response latency. The program\n"
+" continues until interrupted, at which point a final report is\n"
+" generated.\n"
"-s<seed>: Specify the seed for randomization, making it repeatable.\n"
-"-S<srvid-offset>: Offset of the server-ID option in the\n"
-" (second/request) template.\n"
"-T<template-file>: The name of a file containing the template to use\n"
" as a stream of hexadecimal digits.\n"
"-v: Report the version number of this program.\n"
@@ -2233,16 +1326,8 @@ usage(void)
" * 'e': print the exit reason\n"
" * 'i': print rate processing details\n"
" * 'r': print randomization details\n"
-" * 's': print first server-id\n"
" * 't': when finished, print timers of all successful exchanges\n"
" * 'T': when finished, print templates\n"
-"-X<xid-offset>: Transaction ID (aka. xid) offset in the template.\n"
-"\n"
-"DHCPv4 only options:\n"
-"-B: Force broadcast handling.\n"
-"\n"
-"DHCPv6 only options:\n"
-"-c: Add a rapid commit option (exchanges will be SA).\n"
"\n"
"The remaining options are used only in conjunction with -r:\n"
"\n"
@@ -2263,8 +1348,6 @@ usage(void)
"\n"
"Errors:\n"
"- tooshort: received a too short message\n"
-"- orphans: received a message which doesn't match an exchange\n"
-" (duplicate, late or not related)\n"
"- locallimit: reached to local system limits when sending a message.\n"
"\n"
"Exit status:\n"
@@ -2289,7 +1372,7 @@ main(const int argc, char * const argv[])
extern char *optarg;
extern int optind;
-#define OPTIONS "hv46r:t:R:b:n:p:d:D:l:P:a:L:s:iBc1T:X:O:E:S:I:x:w:"
+#define OPTIONS "hv46M:r:t:R:b:n:p:d:D:l:P:a:s:T:O:x:w:"
/* decode options */
while ((opt = getopt(argc, argv, OPTIONS)) != -1)
@@ -2320,6 +1403,15 @@ main(const int argc, char * const argv[])
ipversion = 6;
break;
+ case 'M':
+ xlast = atoi(optarg);
+ if (xlast <= 1000) {
+ fprintf(stderr, "memory must be greater than 1000\n");
+ usage();
+ exit(2);
+ }
+ break;
+
case 'r':
rate = atoi(optarg);
if (rate <= 0) {
@@ -2360,25 +1452,24 @@ main(const int argc, char * const argv[])
break;
case 'b':
- if (basecnt > 3) {
+ if (basecnt > 1) {
fprintf(stderr, "too many bases\n");
usage();
exit(2);
}
base[basecnt] = optarg;
- decodebase();
+ /* decodebase(); */
basecnt++;
break;
case 'n':
- numreq[gotnumreq] = atoi(optarg);
- if (numreq[gotnumreq] <= 0) {
+ numreq = atoi(optarg);
+ if (numreq <= 0) {
fprintf(stderr,
"num-request must be a positive integer\n");
usage();
exit(2);
}
- gotnumreq = 1;
break;
case 'p':
@@ -2392,39 +1483,35 @@ main(const int argc, char * const argv[])
break;
case 'd':
- losttime[gotlosttime] = atof(optarg);
- if (losttime[gotlosttime] <= 0.) {
+ losttime = atof(optarg);
+ if (losttime <= 0.) {
fprintf(stderr,
"drop-time must be a positive number\n");
usage();
exit(2);
}
- gotlosttime = 1;
break;
case 'D':
pc = strchr(optarg, '%');
if (pc != NULL) {
*pc = '\0';
- maxpdrop[gotmaxdrop] = atof(optarg);
- if ((maxpdrop[gotmaxdrop] <= 0) ||
- (maxpdrop[gotmaxdrop] >= 100)) {
+ maxpdrop = atof(optarg);
+ if ((maxpdrop <= 0) || (maxpdrop >= 100)) {
fprintf(stderr,
"invalid drop-time percentage\n");
usage();
exit(2);
}
- gotmaxdrop = 1;
break;
}
- maxdrop[gotmaxdrop] = atoi(optarg);
- if (maxdrop[gotmaxdrop] <= 0) {
+ maxdrop = atoi(optarg);
+ if (maxdrop <= 0) {
fprintf(stderr,
"max-drop must be a positive integer\n");
usage();
exit(2);
}
- gotmaxdrop = 1;
break;
case 'l':
@@ -2451,111 +1538,25 @@ main(const int argc, char * const argv[])
}
break;
- case 'L':
- localport = atoi(optarg);
- if (localport < 0) {
- fprintf(stderr,
- "local-port must not be a negative integer\n");
- usage();
- exit(2);
- }
- if (localport > (int) UINT16_MAX) {
- fprintf(stderr,
- "local-port must be lower than %d\n",
- (int) UINT16_MAX);
- usage();
- exit(2);
- }
- break;
-
case 's':
seeded = 1;
seed = (unsigned int) atol(optarg);
break;
- case 'i':
- simple = 1;
- break;
-
- case 'B':
- isbroadcast = 1;
- break;
-
- case 'c':
- rapidcommit = 1;
- break;
-
- case '1':
- usefirst = 1;
- break;
-
case 'T':
- if (templatefile[0] != NULL) {
- if (templatefile[1] != NULL) {
- fprintf(stderr,
- "template-files are already set\n");
- usage();
- exit(2);
- }
- templatefile[1] = optarg;
- } else
- templatefile[0] = optarg;
- break;
-
- case 'X':
- if (xidoffset[0] >= 0)
- i = 1;
- else
- i = 0;
- xidoffset[i] = atoi(optarg);
- if (xidoffset[i] <= 0) {
- fprintf(stderr,
- "xid-offset must be a positive integer\n");
+ if (templatefile != NULL) {
+ fprintf(stderr, "template-file is already set\n");
usage();
exit(2);
}
+ templatefile = optarg;
break;
case 'O':
- if (rndoffset[0] >= 0)
- i = 1;
- else
- i = 0;
- rndoffset[i] = atoi(optarg);
- if (rndoffset[i] < 3) {
- fprintf(stderr,
- "random-offset must be greater than 3\n");
- usage();
- exit(2);
- }
- break;
-
- case 'E':
- elpoffset = atoi(optarg);
- if (elpoffset < 0) {
- fprintf(stderr,
- "time-offset must not be a "
- "negative integer\n");
- usage();
- exit(2);
- }
- break;
-
- case 'S':
- sidoffset = atoi(optarg);
- if (sidoffset <= 0) {
- fprintf(stderr,
- "srvid-offset must be a positive integer\n");
- usage();
- exit(2);
- }
- break;
-
- case 'I':
- ripoffset = atoi(optarg);
- if (ripoffset <= 0) {
+ rndoffset = atoi(optarg);
+ if (rndoffset < 14) {
fprintf(stderr,
- "ip-offset must be a positive integer\n");
+ "random-offset must be greater than 14\n");
usage();
exit(2);
}
@@ -2577,24 +1578,15 @@ main(const int argc, char * const argv[])
/* adjust some global variables */
if (ipversion == 0)
ipversion = 4;
- if (templatefile[1] != NULL) {
- if (xidoffset[1] < 0)
- xidoffset[1] = xidoffset[0];
- if (rndoffset[1] < 0)
- rndoffset[1] = rndoffset[0];
- }
+ if (rate == 0)
+ rate = 100;
+ if (xlast == 0)
+ xlast = 60000;
/* when required, print the internal view of the command line */
if ((diags != NULL) && (strchr(diags, 'a') != NULL)) {
printf("IPv%d", ipversion);
- if (simple != 0) {
- if (ipversion == 4)
- printf(" DO only");
- else
- printf(" SA only");
- }
- if (rate != 0)
- printf(" rate=%d", rate);
+ printf(" rate=%d", rate);
if (report != 0)
printf(" report=%d", report);
if (range != 0) {
@@ -2608,179 +1600,32 @@ main(const int argc, char * const argv[])
if (basecnt != 0)
for (i = 0; i < basecnt; i++)
printf(" base[%d]='%s'", i, base[i]);
- if (gotnumreq != 0)
- printf(" num-request=%d,%d", numreq[0], numreq[1]);
+ if (numreq != 0)
+ printf(" num-request=%d", numreq);
if (period != 0)
printf(" test-period=%d", period);
- printf(" drop-time=%g,%g", losttime[0], losttime[1]);
- if ((maxdrop[0] != 0) || (maxdrop[1] != 0))
- printf(" max-drop=%d,%d", maxdrop[0], maxdrop[1]);
- if ((maxpdrop[0] != 0.) || (maxpdrop[1] != 0.))
- printf(" max-drop=%2.2f%%,%2.2f%%",
- maxpdrop[0], maxpdrop[1]);
+ printf(" drop-time=%g", losttime);
+ if (maxdrop != 0)
+ printf(" max-drop=%d", maxdrop);
+ if (maxpdrop != 0.)
+ printf(" max-drop=%2.2f%%", maxpdrop);
if (preload != 0)
printf(" preload=%d", preload);
printf(" aggressivity=%d", aggressivity);
- if (localport != 0)
- printf(" local-port=%d", localport);
if (seeded)
printf(" seed=%u", seed);
- if (isbroadcast != 0)
- printf(" broadcast");
- if (rapidcommit != 0)
- printf(" rapid-commit");
- if (usefirst != 0)
- printf(" use-first");
- if ((templatefile[0] != NULL) && (templatefile[1] == NULL))
- printf(" template-file='%s'", templatefile[0]);
- else if (templatefile[1] != NULL)
- printf(" template-file='%s','%s'",
- templatefile[0], templatefile[1]);
- if ((xidoffset[0] >= 0) && (xidoffset[1] < 0))
- printf(" xid-offset=%d", xidoffset[0]);
- else if (xidoffset[1] >= 0)
- printf(" xid-offset=%d,%d",
- xidoffset[0], xidoffset[1]);
- if ((rndoffset[0] >= 0) && (rndoffset[1] < 0))
- printf(" xid-offset=%d", rndoffset[0]);
- else if (rndoffset[1] >= 0)
- printf(" xid-offset=%d,%d",
- rndoffset[0], rndoffset[1]);
- if (elpoffset >= 0)
- printf(" time-offset=%d", elpoffset);
- if (sidoffset >= 0)
- printf(" srvid-offset=%d", sidoffset);
- if (ripoffset >= 0)
- printf(" ip-offset=%d", ripoffset);
+ if (templatefile != NULL)
+ printf(" template-file='%s'", templatefile);
+ if (rndoffset >= 0)
+ printf(" rnd-offset=%d", rndoffset);
printf(" diagnotic-selectors='%s'", diags);
if (wrapped != NULL)
printf(" wrapped='%s'", wrapped);
printf("\n");
}
- /* check DHCPv4 only options */
- if ((ipversion != 4) && (isbroadcast != 0)) {
- fprintf(stderr, "-b is not compatible with IPv6 (-6)\n");
- usage();
- exit(2);
- }
-
- /* check DHCPv6 only options */
- if ((ipversion != 6) && (rapidcommit != 0)) {
- fprintf(stderr, "-6 (IPv6) must be set to use -c\n");
- usage();
- exit(2);
- }
-
- /* check 4-packet (aka not simple) mode options */
- if ((simple != 0) && (numreq[1] != 0)) {
- fprintf(stderr,
- "second -n<num-request> is not compatible with -i\n");
- usage();
- exit(2);
- }
- if ((simple != 0) && (losttime[1] != 1.)) {
- fprintf(stderr,
- "second -d<drop-time> is not compatible with -i\n");
- usage();
- exit(2);
- }
- if ((simple != 0) &&
- ((maxdrop[1] != 0) || (maxpdrop[1] != 0.))) {
- fprintf(stderr,
- "second -D<max-drop> is not compatible with -i\n");
- usage();
- exit(2);
- }
- if ((simple != 0) && (usefirst != 0)) {
- fprintf(stderr,
- "-1 is not compatible with -i\n");
- usage();
- exit(2);
- }
- if ((simple != 0) && (templatefile[1] != NULL)) {
- fprintf(stderr,
- "second -T<template-file> is not "
- "compatible with -i\n");
- usage();
- exit(2);
- }
- if ((simple != 0) && (xidoffset[1] >= 0)) {
- fprintf(stderr,
- "second -X<xid-offset> is not compatible with -i\n");
- usage();
- exit(2);
- }
- if ((simple != 0) && (rndoffset[1] >= 0)) {
- fprintf(stderr,
- "second -O<random-offset is not compatible with -i\n");
- usage();
- exit(2);
- }
- if ((simple != 0) && (elpoffset >= 0)) {
- fprintf(stderr,
- "-E<time-offset> is not compatible with -i\n");
- usage();
- exit(2);
- }
- if ((simple != 0) && (sidoffset >= 0)) {
- fprintf(stderr,
- "-S<srvid-offset> is not compatible with -i\n");
- usage();
- exit(2);
- }
- if ((simple != 0) && (ripoffset >= 0)) {
- fprintf(stderr,
- "-I<ip-offset> is not compatible with -i\n");
- usage();
- exit(2);
- }
-
-
- /* check simple mode options */
- if ((simple == 0) && (rapidcommit != 0)) {
- fprintf(stderr, "-i must be set to use -c\n");
- usage();
- exit(2);
- }
-
- /* check rate '-r' options */
- if ((rate == 0) && (report != 0)) {
- fprintf(stderr,
- "-r<rate> must be set to use -t<report>\n");
- usage();
- exit(2);
- }
- if ((rate == 0) && ((numreq[0] != 0) || (numreq[1] != 0))) {
- fprintf(stderr,
- "-r<rate> must be set to use -n<num-request>\n");
- usage();
- exit(2);
- }
- if ((rate == 0) && (period != 0)) {
- fprintf(stderr,
- "-r<rate> must be set to use -p<test-period>\n");
- usage();
- exit(2);
- }
- if ((rate == 0) &&
- ((maxdrop[0] != 0) || (maxdrop[1] != 0) ||
- (maxpdrop[0] != 0.) || (maxpdrop[1] != 0.))) {
- fprintf(stderr,
- "-r<rate> must be set to use -D<max-drop>\n");
- usage();
- exit(2);
- }
-
- /* check (first) template file options */
- if ((templatefile[0] == NULL) && (xidoffset[0] >= 0)) {
- fprintf(stderr,
- "-T<template-file> must be set to "
- "use -X<xid-offset>\n");
- usage();
- exit(2);
- }
- if ((templatefile[0] == NULL) && (rndoffset[0] >= 0)) {
+ /* check template file options */
+ if ((templatefile == NULL) && (rndoffset >= 0)) {
fprintf(stderr,
"-T<template-file> must be set to "
"use -O<random-offset>\n");
@@ -2788,51 +1633,14 @@ main(const int argc, char * const argv[])
exit(2);
}
- /* check (second) template file options */
- if ((templatefile[1] == NULL) && (elpoffset >= 0)) {
- fprintf(stderr,
- "second/request -T<template-file> must be set to "
- "use -E<time-offset>\n");
- usage();
- exit(2);
- }
- if ((templatefile[1] == NULL) && (sidoffset >= 0)) {
- fprintf(stderr,
- "second/request -T<template-file> must be set to "
- "use -S<srvid-offset>\n");
- usage();
- exit(2);
- }
- if ((templatefile[1] == NULL) && (ripoffset >= 0)) {
- fprintf(stderr,
- "second/request -T<template-file> must be set to "
- "use -I<ip-offset>\n");
- usage();
- exit(2);
- }
-
/* check various template file(s) and other condition(s) options */
- if ((templatefile[0] != NULL) && (range > 0) && (rndoffset[0] < 0)) {
+ if ((templatefile != NULL) && (range > 0) && (rndoffset < 0)) {
fprintf(stderr,
"-O<random-offset> must be set when "
"-T<template-file> and -R<range> are used\n");
usage();
exit(2);
}
- if ((templatefile[1] != NULL) && (sidoffset < 0)) {
- fprintf(stderr,
- "-S<srvid-offset> must be set when second "
- "-T<template-file> is used\n");
- usage();
- exit(2);
- }
- if ((templatefile[1] != NULL) && (ripoffset < 0)) {
- fprintf(stderr,
- "-I<ip-offset> must be set when second "
- "-T<template-file> is used\n");
- usage();
- exit(2);
- }
/* get the server argument */
if (optind < argc - 1) {
@@ -2840,65 +1648,30 @@ main(const int argc, char * const argv[])
usage();
exit(2);
}
- if (optind == argc - 1) {
+ if (optind == argc - 1)
servername = argv[optind];
- /* decode special cases */
- if ((ipversion == 4) &&
- (strcmp(servername, "all") == 0)) {
- flags = AI_NUMERICHOST;
- isbroadcast = 1;
- servername = "255.255.255.255";
- } else if ((ipversion == 6) &&
- (strcmp(servername, "all") == 0)) {
- flags = AI_NUMERICHOST;
- servername = "FF02::1:2";
- } else if ((ipversion == 6) &&
- (strcmp(servername, "servers") == 0)) {
- flags = AI_NUMERICHOST;
- servername = "FF05::1:3";
- }
- }
/* handle the local '-l' address/interface */
if (localname != NULL) {
/* given */
getlocaladdr();
- if ((diags != NULL) && (strchr(diags, 'a') != NULL)) {
- if (isinterface)
- printf("interface='%s'\n", localname);
- else
- printf("local-addr='%s'\n", localname);
- }
- /* get the not given server from it */
- if (servername == NULL) {
- if (isinterface && (ipversion == 4)) {
- flags = AI_NUMERICHOST;
- isbroadcast = 1;
- servername = "255.255.255.255";
- } else if (isinterface && (ipversion == 6)) {
- flags = AI_NUMERICHOST;
- servername = "FF02::1:2";
- } else {
- fprintf(stderr,
- "without an interface "
- "server is required\n");
- usage();
- exit(2);
- }
- }
- } else if (servername == NULL) {
- fprintf(stderr, "without an interface server is required\n");
+ if ((diags != NULL) && (strchr(diags, 'a') != NULL))
+ printf("local-addr='%s'\n", localname);
+ }
+
+ /* get the server socket address */
+ if (servername == NULL) {
+ fprintf(stderr, "server is required\n");
usage();
exit(2);
}
- /* get the server socket address */
getserveraddr(flags);
+
/* finish local/server socket address stuff and print it */
if ((diags != NULL) && (strchr(diags, 'a') != NULL))
printf("server='%s'\n", servername);
- if (localname == NULL)
- getlocal();
- if ((diags != NULL) && (strchr(diags, 'a') != NULL)) {
+ if ((localname != NULL) &&
+ (diags != NULL) && (strchr(diags, 'a') != NULL)) {
char addr[NI_MAXHOST];
ret = getnameinfo((struct sockaddr *) &localaddr,
@@ -2922,46 +1695,15 @@ main(const int argc, char * const argv[])
/* get the socket descriptor and template(s) */
if (ipversion == 4) {
- getsock4();
- if (templatefile[0] == NULL)
- build_template_discover4();
+ if (templatefile == NULL)
+ build_template_query4();
else
- get_template_discover4();
- if (simple == 0) {
- if (templatefile[1] == NULL)
- build_template_request4();
- else
- get_template_request4();
- }
+ get_template_query4();
} else {
- getsock6();
- if (duid_prefix != NULL) {
- if (templatefile[0] == NULL)
- build_template_solicit6();
- else
- get_template_solicit6();
- if (simple == 0) {
- if (templatefile[1] == NULL)
- build_template_request6();
- else
- get_template_request6();
- }
- }
- }
- /* sanity check */
- if ((unsigned) sock > FD_SETSIZE) {
- fprintf(stderr, "socket descriptor (%d) too large?!\n", sock);
- exit(1);
- }
- /* make the socket descriptor not blocking */
- flags = fcntl(sock, F_GETFL, 0);
- if (flags < 0) {
- perror("fcntl(F_GETFL)");
- exit(1);
- }
- if (fcntl(sock, F_SETFL, flags | O_NONBLOCK) < 0) {
- perror("fcntl(F_SETFL)");
- exit(1);
+ if (templatefile == NULL)
+ build_template_query6();
+ else
+ get_template_query6();
}
/* wrapped start */
@@ -2989,36 +1731,6 @@ main(const int argc, char * const argv[])
dreport.tv_nsec = boot.tv_nsec;
}
- /* compute the DUID (the current date is needed) */
- if ((ipversion == 6) && (duid_prefix == NULL)) {
- uint32_t curdate;
-
- duid_length = 14;
- duid_prefix = (uint8_t *) malloc(duid_length);
- if (duid_prefix == NULL) {
- perror("malloc(duid)");
- exit(1);
- }
- duid_prefix[0] = DHCP6_DUID_LLT >> 8;
- duid_prefix[1] = DHCP6_DUID_LLT;
- duid_prefix[2] = DHCP_HTYPE_ETHER >> 8;
- duid_prefix[3] = DHCP_HTYPE_ETHER;
- curdate = htonl(boot.tv_sec - DHCP6_DUID_EPOCH);
- memcpy(duid_prefix + 4, &curdate, 4);
- memcpy(duid_prefix + 8, mac_prefix, 6);
- /* the DUID is in template(s) */
- if (templatefile[0] == NULL)
- build_template_solicit6();
- else
- get_template_solicit6();
- if (simple == 0) {
- if (templatefile[1] == NULL)
- build_template_request6();
- else
- get_template_request6();
- }
- }
-
/* seed the random generator */
if (seeded == 0)
seed = (unsigned int) (boot.tv_sec + boot.tv_nsec);
@@ -3028,23 +1740,25 @@ main(const int argc, char * const argv[])
compsend = preload + 1;
for (i = 0; i <= preload; i++) {
if (ipversion == 4)
- ret = send4();
+ ret = connect4();
else
- ret = send6();
+ ret = connect6();
if (ret < 0) {
/* failure at the first packet is fatal */
if (i == 0) {
fprintf(stderr,
- "initial send failed: %s\n",
+ "initial connect failed: %s\n",
strerror(-ret));
exit(1);
}
- if ((errno == EAGAIN) ||
- (errno == EWOULDBLOCK) ||
- (errno == ENOBUFS) ||
- (errno == ENOMEM))
+ if ((ret == -EAGAIN) ||
+ (ret == -EWOULDBLOCK) ||
+ (ret == -ENOBUFS) ||
+ (ret == -ENOMEM))
locallimit++;
- fprintf(stderr, "preload send: %s\n", strerror(-ret));
+ fprintf(stderr,
+ "preload connect failed: %s\n",
+ strerror(-ret));
break;
}
}
@@ -3055,7 +1769,7 @@ main(const int argc, char * const argv[])
/* main loop */
for (;;) {
struct timespec now, ts;
- fd_set rfds;
+ unsigned int nfds;
/* immediate loop exit conditions */
if (interrupted) {
@@ -3114,71 +1828,51 @@ main(const int argc, char * const argv[])
latesent++;
}
- /* pselect() */
- FD_ZERO(&rfds);
- FD_SET(sock, &rfds);
- ret = pselect(sock + 1, &rfds, NULL, NULL, &ts, NULL);
+ /* ppoll() */
+ nfds = (unsigned int) xused;
+ ret = ppoll(plist, nfds, &ts, NULL);
if (ret < 0) {
if (errno == EINTR)
continue;
- perror("pselect");
+ perror("ppoll");
fatal = 1;
continue;
- }
+ } else if (ret == 0)
+ continue;
/* packet(s) to receive */
- while (ret == 1) {
- if (ipversion == 4)
- receive4();
- else
- receive6();
- if (recv(sock, ibuf, sizeof(ibuf), MSG_PEEK) <= 0)
- ret = 0;
- else
- multrcvd++;
- }
+ if (ipversion == 4)
+ pollrecv4();
+ else
+ pollrecv6();
+ if (fatal)
+ continue;
+
+ /* connections to finish */
+ if (ipversion == 4)
+ pollsend4();
+ else
+ pollsend6();
if (fatal)
continue;
/* check receive loop exit conditions */
- if ((numreq[0] != 0) && ((int) xscount0 >= numreq[0])) {
- if ((diags != NULL) && (strchr(diags, 'e') != NULL))
- printf("reached num-request0\n");
- break;
- }
- if ((numreq[1] != 0) && ((int) xscount2 >= numreq[1])) {
- if ((diags != NULL) && (strchr(diags, 'e') != NULL))
- printf("reached num-request2\n");
- break;
- }
- if ((maxdrop[0] != 0) &&
- ((int) (xscount0 - xrcount0) > maxdrop[0])) {
- if ((diags != NULL) && (strchr(diags, 'e') != NULL))
- printf("reached max-drop%s (absolute)\n",
- simple != 0 ? "" : "0");
- break;
- }
- if ((maxdrop[1] != 0) &&
- ((int) (xscount2 - xrcount2) > maxdrop[1])) {
+ if ((numreq != 0) && ((int) xscount >= numreq)) {
if ((diags != NULL) && (strchr(diags, 'e') != NULL))
- printf("reached max-drop2 (absolute)\n");
+ printf("reached num-request\n");
break;
}
- if ((maxpdrop[0] != 0.) &&
- (xscount0 > 10) &&
- (((100. * (xscount0 - xrcount0)) / xscount0)
- > maxpdrop[0])) {
+ if ((maxdrop != 0) &&
+ ((int) (xscount - xrcount) > maxdrop)) {
if ((diags != NULL) && (strchr(diags, 'e') != NULL))
- printf("reached max-drop%s (percent)\n",
- simple != 0 ? "" : "0");
+ printf("reached max-drop (absolute)\n");
break;
}
- if ((maxpdrop[1] != 0.) &&
- (xscount2 > 10) &&
- (((100. * (xscount2 - xrcount2)) / xscount2)
- > maxpdrop[1])) {
+ if ((maxpdrop != 0.) &&
+ (xscount > 10) &&
+ (((100. * (xscount - xrcount)) / xscount) > maxpdrop)) {
if ((diags != NULL) && (strchr(diags, 'e') != NULL))
- printf("reached max-drop2 (percent)\n");
+ printf("reached max-drop (percent)\n");
break;
}
@@ -3208,31 +1902,23 @@ main(const int argc, char * const argv[])
/* send packets */
for (;;) {
if (ipversion == 4)
- ret = send4();
+ ret = connect4();
else
- ret = send6();
+ ret = connect6();
if (ret < 0) {
- if ((errno == EAGAIN) ||
- (errno == EWOULDBLOCK) ||
- (errno == ENOBUFS) ||
- (errno == ENOMEM))
+ if ((ret == -EAGAIN) ||
+ (ret == -EWOULDBLOCK) ||
+ (ret == -ENOBUFS) ||
+ (ret == -ENOMEM))
locallimit++;
fprintf(stderr,
- "send: %s\n", strerror(-ret));
+ "connect: %s\n",
+ strerror(-ret));
break;
}
i--;
if (i == 0)
break;
- /* check for late packets to receive */
- if (recv(sock, ibuf, sizeof(ibuf),
- MSG_PEEK) > 0) {
- latercvd++;
- if (ipversion == 4)
- receive4();
- else
- receive6();
- }
}
} else
/* there was no packet to send */
@@ -3253,23 +1939,12 @@ main(const int argc, char * const argv[])
}
/* main statictics */
- if (xscount2 == 0)
- printf("sent: %llu, received: %llu (drops: %lld)\n",
- (unsigned long long) xscount0,
- (unsigned long long) xrcount0,
- (long long) (xscount0 - xrcount0));
- else
- printf("sent: %llu/%llu, received: %llu/%llu "
- "(drops: %lld/%lld)\n",
- (unsigned long long) xscount0,
- (unsigned long long) xscount2,
- (unsigned long long) xrcount0,
- (unsigned long long) xrcount2,
- (long long) (xscount0 - xrcount0),
- (long long) (xscount2 - xrcount2));
- printf("tooshort: %llu, orphans: %llu, local limits: %llu\n",
+ printf("sent: %llu, received: %llu (drops: %lld)\n",
+ (unsigned long long) xscount,
+ (unsigned long long) xrcount,
+ (long long) (xscount - xrcount));
+ printf("tooshort: %llu, local limits: %llu\n",
(unsigned long long) tooshort,
- (unsigned long long) orphans,
(unsigned long long) locallimit);
/* print the rate */
@@ -3278,181 +1953,70 @@ main(const int argc, char * const argv[])
dall = (finished.tv_nsec - boot.tv_nsec) / 1e9;
dall += finished.tv_sec - boot.tv_sec;
- erate = xrcount0 / dall;
- if (rate != 0)
- printf("rate: %f (expected %d)\n", erate, rate);
- else
- printf("rate: %f\n", erate);
+ erate = xrcount / dall;
+ printf("rate: %f (expected %d)\n", erate, rate);
}
/* rate processing instrumentation */
if ((diags != NULL) && (strchr(diags, 'i') != NULL)) {
printf("latesent: %llu, compsend: %llu, shortwait: %llu\n"
- "multrcvd: %llu, latercvd: %llu, collected:%llu/%llu\n",
+ "latercvd: %llu, collected:%llu\n",
(unsigned long long) latesent,
(unsigned long long) compsend,
(unsigned long long) shortwait,
- (unsigned long long) multrcvd,
(unsigned long long) latercvd,
- (unsigned long long) collected[0],
- (unsigned long long) collected[1]);
+ (unsigned long long) collected);
}
/* round-time trip statistics */
- if (xrcount2 != 0) {
- double avg0, avg2, stddev0, stddev2;
-
- avg0 = dsum0 / xrcount0;
- avg2 = dsum2 / xrcount2;
- stddev0 = sqrt(dsumsq0 / xrcount0 - avg0 * avg0);
- stddev2 = sqrt(dsumsq2 / xrcount2 - avg2 * avg2);
- printf("RTT0: min/avg/max/stddev: %.3f/%.3f/%.3f/%.3f ms\n",
- dmin0 * 1e3, avg0 * 1e3, dmax0 * 1e3, stddev0 * 1e3);
- printf("RTT2: min/avg/max/stddev: %.3f/%.3f/%.3f/%.3f ms\n",
- dmin2 * 1e3, avg2 * 1e3, dmax2 * 1e3, stddev2 * 1e3);
- } else if (xrcount0 != 0) {
+ if (xrcount != 0) {
double avg, stddev;
- avg = dsum0 / xrcount0;
- stddev = sqrt(dsumsq0 / xrcount0 - avg * avg);
- printf("RTT%s: min/avg/max/stddev: %.3f/%.3f/%.3f/%.3f ms\n",
- simple != 0 ? "" : "0",
- dmin0 * 1e3, avg * 1e3, dmax0 * 1e3, stddev * 1e3);
- }
-
- /* (first) server-ID option content */
- if ((diags != NULL) && (strchr(diags, 's') != NULL) &&
- !ISC_TAILQ_EMPTY(&xrcvd0)) {
- struct exchange *x;
- size_t n;
-
- printf("server-id: ");
- x = ISC_TAILQ_FIRST(&xrcvd0);
- if (ipversion == 4)
- n = 2;
- else
- n = 4;
- for (; n < x->sidlen; n++)
- printf("%02hhx", x->sid[n]);
- printf("\n");
- }
-
- /* all time-stamps */
- if ((diags != NULL) && (strchr(diags, 't') != NULL) &&
- !ISC_TAILQ_EMPTY(&xrcvd0)) {
- struct exchange *x;
-
- printf("\n\n");
- ISC_TAILQ_FOREACH(x, &xrcvd0, gchain)
- printf("%ld.%09ld %ld.%09ld\n",
- (long) x->ts0.tv_sec, x->ts0.tv_nsec,
- (long) x->ts1.tv_sec, x->ts1.tv_nsec);
-
+ avg = dsum / xrcount;
+ stddev = sqrt(dsumsq / xrcount - avg * avg);
+ printf("RTT: min/avg/max/stddev: %.3f/%.3f/%.3f/%.3f ms\n",
+ dmin * 1e3, avg * 1e3, dmax * 1e3, stddev * 1e3);
}
- if ((diags != NULL) && (strchr(diags, 't') != NULL) &&
- !ISC_TAILQ_EMPTY(&xrcvd2)) {
- struct exchange *x;
-
- printf("--\n");
- ISC_TAILQ_FOREACH(x, &xrcvd2, gchain)
- printf("%ld.%09ld %ld.%09ld %ld.%09ld %ld.%09ld\n",
- (long) x->ts0.tv_sec, x->ts0.tv_nsec,
- (long) x->ts1.tv_sec, x->ts1.tv_nsec,
- (long) x->ts2.tv_sec, x->ts2.tv_nsec,
- (long) x->ts3.tv_sec, x->ts3.tv_nsec);
-
- }
- if ((diags != NULL) && (strchr(diags, 't') != NULL) &&
- !ISC_TAILQ_EMPTY(&xrcvd0))
- printf("\n\n");
+ printf("\n");
/* template(s) */
if ((diags != NULL) && (strchr(diags, 'T') != NULL)) {
size_t n;
if (ipversion == 4) {
- printf("length = %zu\n", length_discover4);
- printf("xid offset = %d\n", DHCP_OFF_XID);
- printf("xid length = 4\n");
- printf("random offset = %zu\n", random_discover4);
+ printf("length = %zu\n", length_query4);
+ printf("random offset = %zu\n", random_query4);
printf("content:\n");
- for (n = 0; n < length_discover4; n++) {
+ for (n = 0; n < length_query4; n++) {
printf("%s%02hhx",
(n & 15) == 0 ? "" : " ",
- template_discover4[n]);
+ template_query4[n]);
if ((n & 15) == 15)
printf("\n");
}
if ((n & 15) != 15)
printf("\n");
- if (simple != 0)
- goto doneT;
- printf("--\n");
- printf("length = %zu\n", length_request4);
- printf("xid offset = %d\n", DHCP_OFF_XID);
- printf("xid length = 4\n");
- printf("random offset = %zu\n", random_request4);
- if (elapsed_request4 > 0)
- printf("secs offset = %zu\n",
- elapsed_request4);
- printf("server-id offset = %zu\n", serverid_request4);
- printf("server-id length = %d\n", DHCP_OPTLEN_SRVID);
- printf("content:\n");
- printf("requested-ip-address offset = %zu\n",
- reqaddr_request4);
- printf("requested-ip-address length = %d\n", 4);
- for (n = 0; n < length_request4; n++) {
- printf("%s%02hhx",
- (n & 15) == 0 ? "" : " ",
- template_request4[n]);
- if ((n & 15) == 15)
- printf("\n");
- }
printf("\n");
} else {
- printf("length = %zu\n", length_solicit6);
- printf("xid offset = %d\n", DHCP6_OFF_XID);
- printf("xid length = 3\n");
- printf("random offset = %zu\n", random_solicit6);
- for (n = 0; n < length_solicit6; n++) {
+ printf("length = %zu\n", length_query6);
+ printf("random offset = %zu\n", random_query6);
+ for (n = 0; n < length_query6; n++) {
printf("%s%02hhx",
(n & 15) == 0 ? "" : " ",
- template_solicit6[n]);
+ template_query6[n]);
if ((n & 15) == 15)
printf("\n");
}
if ((n & 15) != 15)
printf("\n");
- if (simple != 0)
- goto doneT;
- printf("--\n");
- printf("length = %zu\n", length_request6);
- printf("xid offset = %d\n", DHCP_OFF_XID);
- printf("xid length = 4\n");
- printf("random offset = %zu\n", random_request6);
- if (elapsed_request6 > 0)
- printf("secs offset = %zu\n",
- elapsed_request6);
- printf("server-id offset = %zu\n", serverid_request6);
- printf("content:\n");
- printf("requested-ip-address offset = %zu\n",
- reqaddr_request6);
- for (n = 0; n < length_request6; n++) {
- printf("%s%02hhx",
- (n & 15) == 0 ? "" : " ",
- template_request6[n]);
- if ((n & 15) == 15)
- printf("\n");
- }
printf("\n");
}
}
- doneT:
/* compute the exit code (and exit) */
if (fatal)
exit(1);
- else if ((xscount0 == xrcount0) && (xscount2 == xrcount2))
+ else if (xscount == xrcount)
exit(0);
else
exit(3);
More information about the bind10-changes
mailing list