fix: populate ldns submodule and add autotools to LDNS build stage
- Re-cloned zonemaster-ldns with --recurse-submodules so the bundled ldns C library source (including Changelog and configure.ac) is present - Added autoconf, automake, libtool to Dockerfile.backend ldns-build stage so libtoolize + autoreconf can generate ldns/configure during make Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
5
zonemaster-ldns/ldns/examples/README
Normal file
5
zonemaster-ldns/ldns/examples/README
Normal file
@@ -0,0 +1,5 @@
|
||||
These tools are examples of ldns usage. They are not meant for production
|
||||
systems and will not be supported as such.
|
||||
|
||||
Compilation:
|
||||
autoreconf && ./configure && make
|
||||
175
zonemaster-ldns/ldns/examples/fake-rfc2553.h
Normal file
175
zonemaster-ldns/ldns/examples/fake-rfc2553.h
Normal file
@@ -0,0 +1,175 @@
|
||||
/* From openssh 4.3p2 filename openbsd-compat/fake-rfc2553.h */
|
||||
/*
|
||||
* Copyright (C) 2000-2003 Damien Miller. All rights reserved.
|
||||
* Copyright (C) 1999 WIDE Project. All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 3. Neither the name of the project nor the names of its contributors
|
||||
* may be used to endorse or promote products derived from this software
|
||||
* without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Pseudo-implementation of RFC2553 name / address resolution functions
|
||||
*
|
||||
* But these functions are not implemented correctly. The minimum subset
|
||||
* is implemented for ssh use only. For example, this routine assumes
|
||||
* that ai_family is AF_INET. Don't use it for another purpose.
|
||||
*/
|
||||
|
||||
#ifndef _FAKE_RFC2553_H
|
||||
#define _FAKE_RFC2553_H
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <sys/socket.h>
|
||||
#include <netdb.h>
|
||||
#include <limits.h>
|
||||
|
||||
/*
|
||||
* First, socket and INET6 related definitions
|
||||
*/
|
||||
#ifndef HAVE_STRUCT_SOCKADDR_STORAGE
|
||||
#ifndef _SS_MAXSIZE
|
||||
# define _SS_MAXSIZE 128 /* Implementation specific max size */
|
||||
# define _SS_PADSIZE (_SS_MAXSIZE - sizeof (struct sockaddr))
|
||||
struct sockaddr_storage {
|
||||
struct sockaddr ss_sa;
|
||||
char __ss_pad2[_SS_PADSIZE];
|
||||
};
|
||||
# define ss_family ss_sa.sa_family
|
||||
#endif /* _SS_MAXSIZE */
|
||||
#endif /* !HAVE_STRUCT_SOCKADDR_STORAGE */
|
||||
|
||||
#ifndef IN6_IS_ADDR_LOOPBACK
|
||||
# define IN6_IS_ADDR_LOOPBACK(a) \
|
||||
(((uint32_t *)(a))[0] == 0 && ((uint32_t *)(a))[1] == 0 && \
|
||||
((uint32_t *)(a))[2] == 0 && ((uint32_t *)(a))[3] == htonl(1))
|
||||
#endif /* !IN6_IS_ADDR_LOOPBACK */
|
||||
|
||||
#ifndef HAVE_STRUCT_IN6_ADDR
|
||||
struct in6_addr {
|
||||
uint8_t s6_addr[16];
|
||||
};
|
||||
#endif /* !HAVE_STRUCT_IN6_ADDR */
|
||||
|
||||
#ifndef HAVE_STRUCT_SOCKADDR_IN6
|
||||
struct sockaddr_in6 {
|
||||
unsigned short sin6_family;
|
||||
uint16_t sin6_port;
|
||||
uint32_t sin6_flowinfo;
|
||||
struct in6_addr sin6_addr;
|
||||
};
|
||||
#endif /* !HAVE_STRUCT_SOCKADDR_IN6 */
|
||||
|
||||
#ifndef AF_INET6
|
||||
/* Define it to something that should never appear */
|
||||
#define AF_INET6 AF_MAX
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Next, RFC2553 name / address resolution API
|
||||
*/
|
||||
|
||||
#ifndef NI_NUMERICHOST
|
||||
# define NI_NUMERICHOST (1)
|
||||
#endif
|
||||
#ifndef NI_NAMEREQD
|
||||
# define NI_NAMEREQD (1<<1)
|
||||
#endif
|
||||
#ifndef NI_NUMERICSERV
|
||||
# define NI_NUMERICSERV (1<<2)
|
||||
#endif
|
||||
|
||||
#ifndef AI_PASSIVE
|
||||
# define AI_PASSIVE (1)
|
||||
#endif
|
||||
#ifndef AI_CANONNAME
|
||||
# define AI_CANONNAME (1<<1)
|
||||
#endif
|
||||
#ifndef AI_NUMERICHOST
|
||||
# define AI_NUMERICHOST (1<<2)
|
||||
#endif
|
||||
|
||||
#ifndef NI_MAXSERV
|
||||
# define NI_MAXSERV 32
|
||||
#endif /* !NI_MAXSERV */
|
||||
#ifndef NI_MAXHOST
|
||||
# define NI_MAXHOST 1025
|
||||
#endif /* !NI_MAXHOST */
|
||||
|
||||
#ifndef INT_MAX
|
||||
#define INT_MAX 0xffffffff
|
||||
#endif
|
||||
|
||||
#ifndef EAI_NODATA
|
||||
# define EAI_NODATA (INT_MAX - 1)
|
||||
#endif
|
||||
#ifndef EAI_MEMORY
|
||||
# define EAI_MEMORY (INT_MAX - 2)
|
||||
#endif
|
||||
#ifndef EAI_NONAME
|
||||
# define EAI_NONAME (INT_MAX - 3)
|
||||
#endif
|
||||
#ifndef EAI_SYSTEM
|
||||
# define EAI_SYSTEM (INT_MAX - 4)
|
||||
#endif
|
||||
|
||||
#ifndef HAVE_STRUCT_ADDRINFO
|
||||
struct addrinfo {
|
||||
int ai_flags; /* AI_PASSIVE, AI_CANONNAME */
|
||||
int ai_family; /* PF_xxx */
|
||||
int ai_socktype; /* SOCK_xxx */
|
||||
int ai_protocol; /* 0 or IPPROTO_xxx for IPv4 and IPv6 */
|
||||
size_t ai_addrlen; /* length of ai_addr */
|
||||
char *ai_canonname; /* canonical name for hostname */
|
||||
struct sockaddr *ai_addr; /* binary address */
|
||||
struct addrinfo *ai_next; /* next structure in linked list */
|
||||
};
|
||||
#endif /* !HAVE_STRUCT_ADDRINFO */
|
||||
|
||||
#ifndef HAVE_GETADDRINFO
|
||||
#ifdef getaddrinfo
|
||||
# undef getaddrinfo
|
||||
#endif
|
||||
#define getaddrinfo(a,b,c,d) (ssh_getaddrinfo(a,b,c,d))
|
||||
int getaddrinfo(const char *, const char *,
|
||||
const struct addrinfo *, struct addrinfo **);
|
||||
#endif /* !HAVE_GETADDRINFO */
|
||||
|
||||
#if !defined(HAVE_GAI_STRERROR) && !defined(HAVE_CONST_GAI_STRERROR_PROTO)
|
||||
#define gai_strerror(a) (ssh_gai_strerror(a))
|
||||
char *gai_strerror(int);
|
||||
#endif /* !HAVE_GAI_STRERROR */
|
||||
|
||||
#ifndef HAVE_FREEADDRINFO
|
||||
#define freeaddrinfo(a) (ssh_freeaddrinfo(a))
|
||||
void freeaddrinfo(struct addrinfo *);
|
||||
#endif /* !HAVE_FREEADDRINFO */
|
||||
|
||||
#ifndef HAVE_GETNAMEINFO
|
||||
#define getnameinfo(a,b,c,d,e,f,g) (ssh_getnameinfo(a,b,c,d,e,f,g))
|
||||
int getnameinfo(const struct sockaddr *, size_t, char *, size_t,
|
||||
char *, size_t, int);
|
||||
#endif /* !HAVE_GETNAMEINFO */
|
||||
|
||||
#endif /* !_FAKE_RFC2553_H */
|
||||
|
||||
26
zonemaster-ldns/ldns/examples/ldns-chaos.1
Normal file
26
zonemaster-ldns/ldns/examples/ldns-chaos.1
Normal file
@@ -0,0 +1,26 @@
|
||||
.TH ldns-chaos 1 "27 Apr 2005"
|
||||
.SH NAME
|
||||
ldns-chaos \- give some information about a nameserver
|
||||
.SH SYNOPSIS
|
||||
.B ldns-chaos
|
||||
.IR NAMESERVER
|
||||
|
||||
.SH DESCRIPTION
|
||||
\fBldns-chaos\fR retrieves all the addresses of the nameserver and then queries
|
||||
each address for its \fIversion.bind\fR and \fIhostname.bind\fR.
|
||||
.PP
|
||||
\fBldns-chaos\fR is a bit more complex than \fBldns-mx\fR.
|
||||
|
||||
.SH OPTIONS
|
||||
\fBldns-chaos\fR has no options.
|
||||
|
||||
.SH AUTHOR
|
||||
Written by the ldns team as an example for ldns usage.
|
||||
|
||||
.SH REPORTING BUGS
|
||||
Report bugs to <dns-team@nlnetlabs.nl>.
|
||||
|
||||
.SH COPYRIGHT
|
||||
Copyright (C) 2005 NLnet Labs. This is free software. There is NO
|
||||
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR
|
||||
PURPOSE.
|
||||
125
zonemaster-ldns/ldns/examples/ldns-chaos.c
Normal file
125
zonemaster-ldns/ldns/examples/ldns-chaos.c
Normal file
@@ -0,0 +1,125 @@
|
||||
/*
|
||||
* chaos is a small programs that prints some information
|
||||
* about a nameserver
|
||||
*
|
||||
* (c) NLnet Labs, 2005 - 2008
|
||||
*
|
||||
* See the file LICENSE for the license
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include <ldns/ldns.h>
|
||||
|
||||
static int
|
||||
usage(FILE *fp, char *prog) {
|
||||
fprintf(fp, "%s server\n", prog);
|
||||
fprintf(fp, " print out some information about server\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
main(int argc, char *argv[])
|
||||
{
|
||||
ldns_resolver *res;
|
||||
ldns_rdf *name;
|
||||
ldns_rdf *version, *id;
|
||||
ldns_pkt *p;
|
||||
ldns_rr_list *addr;
|
||||
ldns_rr_list *info;
|
||||
ldns_status s;
|
||||
ldns_rdf *pop;
|
||||
size_t i;
|
||||
|
||||
if (argc != 2) {
|
||||
usage(stdout, argv[0]);
|
||||
exit(EXIT_FAILURE);
|
||||
} else {
|
||||
/* create a rdf from the command line arg */
|
||||
name = ldns_dname_new_frm_str(argv[1]);
|
||||
if (!name) {
|
||||
usage(stdout, argv[0]);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
}
|
||||
|
||||
/* create rdf for what we are going to ask */
|
||||
version = ldns_dname_new_frm_str("version.bind");
|
||||
id = ldns_dname_new_frm_str("hostname.bind");
|
||||
|
||||
/* create a new resolver from /etc/resolv.conf */
|
||||
s = ldns_resolver_new_frm_file(&res, NULL);
|
||||
if (s != LDNS_STATUS_OK) {
|
||||
ldns_rdf_deep_free(name);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
ldns_resolver_set_retry(res, 1); /* don't want to wait too long */
|
||||
|
||||
/* use the resolver to send it a query for the a/aaaa of name */
|
||||
addr = ldns_get_rr_list_addr_by_name(res, name, LDNS_RR_CLASS_IN, LDNS_RD);
|
||||
if (!addr) {
|
||||
fprintf(stderr, " *** could not get an address for %s\n", argv[1]);
|
||||
ldns_rdf_deep_free(name);
|
||||
ldns_resolver_deep_free(res);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
/* remove current list of nameservers from resolver */
|
||||
while((pop = ldns_resolver_pop_nameserver(res))) { ldns_rdf_deep_free(pop); }
|
||||
|
||||
|
||||
/* can be multihomed */
|
||||
for(i = 0; i < ldns_rr_list_rr_count(addr); i++) {
|
||||
if (i > 0) {
|
||||
fprintf(stdout, "\n");
|
||||
}
|
||||
|
||||
if (ldns_resolver_push_nameserver_rr(res,
|
||||
ldns_rr_list_rr(addr, i)) != LDNS_STATUS_OK) {
|
||||
printf("Error adding nameserver to resolver\n");
|
||||
}
|
||||
|
||||
ldns_rr_print(stdout, ldns_rr_list_rr(addr, i));
|
||||
fprintf(stdout, "\n");
|
||||
|
||||
p = ldns_resolver_query(res, version, LDNS_RR_TYPE_TXT,
|
||||
LDNS_RR_CLASS_CH, LDNS_RD);
|
||||
if (p) {
|
||||
ldns_pkt_print(stdout, p);
|
||||
info = ldns_pkt_rr_list_by_type(p,
|
||||
LDNS_RR_TYPE_TXT, LDNS_SECTION_ANSWER);
|
||||
|
||||
if (info) {
|
||||
ldns_rr_list_print(stdout, info);
|
||||
ldns_rr_list_deep_free(info);
|
||||
} else {
|
||||
printf(" *** version retrieval failed\n");
|
||||
}
|
||||
ldns_pkt_free(p);
|
||||
} else {
|
||||
printf(" *** query failed\n");
|
||||
}
|
||||
|
||||
p = ldns_resolver_query(res, id, LDNS_RR_TYPE_TXT,
|
||||
LDNS_RR_CLASS_CH, LDNS_RD);
|
||||
if (p) {
|
||||
info = ldns_pkt_rr_list_by_type(p,
|
||||
LDNS_RR_TYPE_TXT, LDNS_SECTION_ANSWER);
|
||||
if (info) {
|
||||
ldns_rr_list_print(stdout, info);
|
||||
ldns_rr_list_deep_free(info);
|
||||
} else {
|
||||
printf(" *** id retrieval failed\n");
|
||||
}
|
||||
ldns_pkt_free(p);
|
||||
} else {
|
||||
printf(" *** query failed for\n");
|
||||
}
|
||||
ldns_rdf_deep_free(ldns_resolver_pop_nameserver(res));
|
||||
|
||||
}
|
||||
|
||||
ldns_rdf_deep_free(name);
|
||||
ldns_resolver_deep_free(res);
|
||||
exit(EXIT_SUCCESS);
|
||||
}
|
||||
71
zonemaster-ldns/ldns/examples/ldns-compare-zones.1
Normal file
71
zonemaster-ldns/ldns/examples/ldns-compare-zones.1
Normal file
@@ -0,0 +1,71 @@
|
||||
.TH ldns-compare-zones 1 "17 Oct 2007"
|
||||
.SH NAME
|
||||
ldns-compare-zones \- read and compare two zonefiles and print differences
|
||||
.SH SYNOPSIS
|
||||
.B ldns-compare-zones
|
||||
.IR [-c]
|
||||
.IR [-U]
|
||||
.IR [-u]
|
||||
.IR [-i]
|
||||
.IR [-d]
|
||||
.IR [-z]
|
||||
.IR [-s]
|
||||
.IR ZONEFILE1
|
||||
.IR ZONEFILE2
|
||||
.SH DESCRIPTION
|
||||
\fBldns-compare-zones\fR reads two DNS zone files and prints number of differences.
|
||||
.nf
|
||||
Output is formatted to:
|
||||
+NUM_INS \-NUM_DEL ~NUM_CHG
|
||||
|
||||
Except with the \fI-U\fR or \fI-u\fR option. Then the output is formatted to:
|
||||
+NUM_INS \-NUM_DEL ~NUM_CHG =NUM_EQ
|
||||
|
||||
.fi
|
||||
The major comparison is based on the owner name. If an owner name is present in zonefile 1, but not in zonefile 2, the resource records with this owner name are considered deleted, and counted as NUM_DEL. If an owner name is present in zonefile 2, but not in zonefile 1, the resource records with this owner name are considered inserted, and counted as NUM_INS. If an owner name is present in both, but there is a difference in the amount or content of the records, these are considered changed, and counted as NUM_CHG.
|
||||
.SH OPTIONS
|
||||
.TP
|
||||
\fB-c\fR
|
||||
Print resource records whose owner names are in both zone files, but with different resource records. (a.k.a. changed)
|
||||
.TP
|
||||
\fB-U\fR
|
||||
From resource records whose owner names are in both zone files, but with different resource records, print the unchanged records too (a.k.a. changed++).
|
||||
.TP
|
||||
\fB-u\fR
|
||||
Print resource records whose owner names are in both zone files, and which resource records are the same. (a.k.a. unchanged)
|
||||
.TP
|
||||
\fB-i\fR
|
||||
Print resource records whose owner names are present only in ZONEFILE2 (a.k.a. inserted)
|
||||
.TP
|
||||
\fB-d\fR
|
||||
Print resource records whose owner names are present only in ZONEFILE1 (a.k.a. deleted)
|
||||
.TP
|
||||
\fB-a\fR
|
||||
Print all changes (except unchanged). Specifying this option is the same as specifying \-c \-i
|
||||
and \-d.
|
||||
.TP
|
||||
\fB-z\fR
|
||||
Suppress zone sorting; this option is not recommended; it can cause records
|
||||
to be incorrectly marked as changed, depending of the nature of the changes.
|
||||
.TP
|
||||
\fB-s\fR
|
||||
Do not exclude the SOA record from the comparison. The SOA record may
|
||||
then show up as changed due to a new serial number. Off by default since
|
||||
you may be interested to know if (other zone apex elements) have changed.
|
||||
.TP
|
||||
\fB-e\fR
|
||||
Exit with status code 2 when zones differ.
|
||||
.TP
|
||||
\fB-h\fR
|
||||
Show usage and exit
|
||||
.TP
|
||||
\fB-v\fR
|
||||
Show the version and exit
|
||||
.SH AUTHOR
|
||||
Written by Ondřej Surý <ondrej@sury.org> for CZ.NIC, z.s.p.o. (czech domain registry)
|
||||
.SH REPORTING BUGS
|
||||
Report bugs to <ondrej@sury.org>.
|
||||
.SH COPYRIGHT
|
||||
Copyright (C) 2005 CZ.NIC, z.s.p.o.. This is free software. There is NO
|
||||
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR
|
||||
PURPOSE.
|
||||
361
zonemaster-ldns/ldns/examples/ldns-compare-zones.c
Normal file
361
zonemaster-ldns/ldns/examples/ldns-compare-zones.c
Normal file
@@ -0,0 +1,361 @@
|
||||
/*
|
||||
* ldns-compare-zones compares two zone files
|
||||
*
|
||||
* Written by Ondrej Sury in 2007
|
||||
*
|
||||
* Modified a bit by NLnet Labs.
|
||||
*
|
||||
* See the file LICENSE for the license
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
#include <unistd.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdarg.h>
|
||||
#include <time.h>
|
||||
|
||||
#include <ldns/ldns.h>
|
||||
|
||||
#include <errno.h>
|
||||
|
||||
#define OP_INS '+'
|
||||
#define OP_DEL '-'
|
||||
#define OP_CHG '~'
|
||||
#define OP_EQ '='
|
||||
|
||||
static void
|
||||
usage(char *prog)
|
||||
{
|
||||
printf("Usage: %s [-v] [-i] [-d] [-c] [-u] [-s] [-e] "
|
||||
"<zonefile1> <zonefile2>\n", prog);
|
||||
printf(" -i - print inserted\n");
|
||||
printf(" -d - print deleted\n");
|
||||
printf(" -c - print changed\n");
|
||||
printf(" -u - print unchanged\n");
|
||||
printf(" -U - print unchanged records in changed names\n");
|
||||
printf(" -a - print all differences (-i -d -c)\n");
|
||||
printf(" -s - do not exclude SOA record from comparison\n");
|
||||
printf(" -z - do not sort zones\n");
|
||||
printf(" -e - exit with status 2 on changed zones\n");
|
||||
printf(" -h - show usage and exit\n");
|
||||
printf(" -v - show the version and exit\n");
|
||||
}
|
||||
|
||||
int
|
||||
main(int argc, char **argv)
|
||||
{
|
||||
char *fn1, *fn2;
|
||||
FILE *fp1, *fp2;
|
||||
ldns_zone *z1, *z2;
|
||||
ldns_status s;
|
||||
size_t i , j;
|
||||
size_t k , l;
|
||||
size_t nc1 , nc2;
|
||||
ldns_rr_list *rrl1, *rrl2;
|
||||
int rr_cmp, rr_chg = 0;
|
||||
ldns_rr *rr1 = NULL, *rr2 = NULL, *rrx = NULL;
|
||||
int line_nr1 = 0, line_nr2 = 0;
|
||||
size_t rrc1 , rrc2;
|
||||
size_t num_ins = 0, num_del = 0, num_chg = 0, num_eq = 0;
|
||||
int c;
|
||||
bool opt_deleted = false, opt_inserted = false;
|
||||
bool opt_changed = false, opt_unchanged = false, opt_Unchanged = false;
|
||||
bool sort = true, inc_soa = false;
|
||||
bool opt_exit_status = false;
|
||||
char op = 0;
|
||||
|
||||
while ((c = getopt(argc, argv, "ahvdicuUesz")) != -1) {
|
||||
switch (c) {
|
||||
case 'h':
|
||||
usage(argv[0]);
|
||||
exit(EXIT_SUCCESS);
|
||||
break;
|
||||
case 'v':
|
||||
printf("%s version %s (ldns version %s)\n",
|
||||
argv[0],
|
||||
LDNS_VERSION,
|
||||
ldns_version());
|
||||
exit(EXIT_SUCCESS);
|
||||
break;
|
||||
case 'e':
|
||||
opt_exit_status = true;
|
||||
break;
|
||||
case 's':
|
||||
inc_soa = true;
|
||||
break;
|
||||
case 'z':
|
||||
sort = false;
|
||||
break;
|
||||
case 'd':
|
||||
opt_deleted = true;
|
||||
break;
|
||||
case 'i':
|
||||
opt_inserted = true;
|
||||
break;
|
||||
case 'c':
|
||||
opt_changed = true;
|
||||
break;
|
||||
|
||||
case 'u':
|
||||
opt_unchanged = true;
|
||||
opt_Unchanged = true;
|
||||
break;
|
||||
|
||||
case 'U':
|
||||
opt_Unchanged = true;
|
||||
opt_changed = true;
|
||||
break;
|
||||
|
||||
case 'a':
|
||||
opt_deleted = true;
|
||||
opt_inserted = true;
|
||||
opt_changed = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
argc -= optind;
|
||||
argv += optind;
|
||||
|
||||
if (argc != 2) {
|
||||
argv -= optind;
|
||||
usage(argv[0]);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
fn1 = argv[0];
|
||||
fp1 = fopen(fn1, "r");
|
||||
if (!fp1) {
|
||||
fprintf(stderr, "Unable to open %s: %s\n", fn1, strerror(errno));
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
/* Read first zone */
|
||||
s = ldns_zone_new_frm_fp_l(&z1, fp1, NULL, 0,
|
||||
LDNS_RR_CLASS_IN, &line_nr1);
|
||||
if (s != LDNS_STATUS_OK) {
|
||||
fclose(fp1);
|
||||
fprintf(stderr, "%s: %s at line %d\n",
|
||||
fn1,
|
||||
ldns_get_errorstr_by_id(s),
|
||||
line_nr1);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
fclose(fp1);
|
||||
|
||||
fn2 = argv[1];
|
||||
fp2 = fopen(fn2, "r");
|
||||
if (!fp2) {
|
||||
fprintf(stderr, "Unable to open %s: %s\n", fn2, strerror(errno));
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
/* Read second zone */
|
||||
s = ldns_zone_new_frm_fp_l(&z2, fp2, NULL, 0,
|
||||
LDNS_RR_CLASS_IN, &line_nr2);
|
||||
if (s != LDNS_STATUS_OK) {
|
||||
ldns_zone_deep_free(z1);
|
||||
fclose(fp2);
|
||||
fprintf(stderr, "%s: %s at line %d\n",
|
||||
fn2,
|
||||
ldns_get_errorstr_by_id(s),
|
||||
line_nr2);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
fclose(fp2);
|
||||
|
||||
rrl1 = ldns_zone_rrs(z1);
|
||||
rrc1 = ldns_rr_list_rr_count(rrl1);
|
||||
|
||||
rrl2 = ldns_zone_rrs(z2);
|
||||
rrc2 = ldns_rr_list_rr_count(rrl2);
|
||||
|
||||
if (sort) {
|
||||
/* canonicalize zone 1 */
|
||||
ldns_rr2canonical(ldns_zone_soa(z1));
|
||||
for (i = 0; i < ldns_rr_list_rr_count(ldns_zone_rrs(z1)); i++) {
|
||||
ldns_rr2canonical(ldns_rr_list_rr(ldns_zone_rrs(z1), i));
|
||||
}
|
||||
/* sort zone 1 */
|
||||
ldns_zone_sort(z1);
|
||||
/* canonicalize zone 2 */
|
||||
ldns_rr2canonical(ldns_zone_soa(z2));
|
||||
for (i = 0; i < ldns_rr_list_rr_count(ldns_zone_rrs(z2)); i++) {
|
||||
ldns_rr2canonical(ldns_rr_list_rr(ldns_zone_rrs(z2), i));
|
||||
}
|
||||
/* sort zone 2 */
|
||||
ldns_zone_sort(z2);
|
||||
}
|
||||
|
||||
if(inc_soa) {
|
||||
ldns_rr_list* wsoa = ldns_rr_list_new();
|
||||
ldns_rr_list_push_rr(wsoa, ldns_zone_soa(z1));
|
||||
ldns_rr_list_cat(wsoa, rrl1);
|
||||
rrl1 = wsoa;
|
||||
rrc1 = ldns_rr_list_rr_count(rrl1);
|
||||
wsoa = ldns_rr_list_new();
|
||||
ldns_rr_list_push_rr(wsoa, ldns_zone_soa(z2));
|
||||
ldns_rr_list_cat(wsoa, rrl2);
|
||||
rrl2 = wsoa;
|
||||
rrc2 = ldns_rr_list_rr_count(rrl2);
|
||||
if(sort) {
|
||||
ldns_rr_list_sort(rrl1);
|
||||
ldns_rr_list_sort(rrl2);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Walk through both zones. The previously seen resource record is
|
||||
* kept (in the variable rrx) so that we can recognize when we are
|
||||
* handling a new owner name. If the owner name changes, we have to
|
||||
* set the operator again.
|
||||
*/
|
||||
for (i = 0, j = 0; i < rrc1 || j < rrc2;) {
|
||||
rr_cmp = 0;
|
||||
if (i < rrc1 && j < rrc2) {
|
||||
rr1 = ldns_rr_list_rr(rrl1, i);
|
||||
rr2 = ldns_rr_list_rr(rrl2, j);
|
||||
rr_cmp = ldns_rr_compare(rr1, rr2);
|
||||
|
||||
rr_chg = ldns_dname_compare(ldns_rr_owner(rr1),
|
||||
ldns_rr_owner(rr2));
|
||||
} else if (i >= rrc1) {
|
||||
/* we have reached the end of zone 1, so the current record
|
||||
* from zone 2 automatically sorts higher
|
||||
*/
|
||||
rr1 = NULL;
|
||||
rr2 = ldns_rr_list_rr(rrl2, j);
|
||||
rr_chg = rr_cmp = 1;
|
||||
} else if (j >= rrc2) {
|
||||
/* we have reached the end of zone 2, so the current record
|
||||
* from zone 1 automatically sorts lower
|
||||
*/
|
||||
rr1 = ldns_rr_list_rr(rrl1, i);
|
||||
rr2 = NULL;
|
||||
rr_chg = rr_cmp = -1;
|
||||
}
|
||||
if (rr_cmp < 0) {
|
||||
if ((rrx != NULL) && (ldns_dname_compare(ldns_rr_owner(rr1),
|
||||
ldns_rr_owner(rrx)
|
||||
) != 0)) {
|
||||
/* The owner name is different, forget previous rr */
|
||||
rrx = NULL;
|
||||
}
|
||||
if (rrx == NULL) {
|
||||
if (rr_chg == 0) {
|
||||
num_chg++;
|
||||
op = OP_CHG;
|
||||
} else {
|
||||
num_del++;
|
||||
op = OP_DEL;
|
||||
}
|
||||
rrx = rr1;
|
||||
}
|
||||
if (((op == OP_DEL) && opt_deleted) ||
|
||||
((op == OP_CHG) && opt_changed)) {
|
||||
printf("%c-", op);
|
||||
ldns_rr_print(stdout, rr1);
|
||||
}
|
||||
i++;
|
||||
} else if (rr_cmp > 0) {
|
||||
if ((rrx != NULL) && (ldns_dname_compare(ldns_rr_owner(rr2),
|
||||
ldns_rr_owner(rrx)
|
||||
) != 0)) {
|
||||
rrx = NULL;
|
||||
}
|
||||
if (rrx == NULL) {
|
||||
if (rr_chg == 0) {
|
||||
num_chg++;
|
||||
op = OP_CHG;
|
||||
} else {
|
||||
num_ins++;
|
||||
op = OP_INS;
|
||||
}
|
||||
/* remember this rr for it's name in the next iteration */
|
||||
rrx = rr2;
|
||||
}
|
||||
if (((op == OP_INS) && opt_inserted) ||
|
||||
((op == OP_CHG) && opt_changed)) {
|
||||
printf("%c+", op);
|
||||
ldns_rr_print(stdout, rr2);
|
||||
}
|
||||
j++;
|
||||
} else {
|
||||
if ((rrx != NULL) && (ldns_dname_compare(ldns_rr_owner(rr1),
|
||||
ldns_rr_owner(rrx)
|
||||
) != 0)) {
|
||||
rrx = NULL;
|
||||
}
|
||||
if (rrx == NULL) {
|
||||
rrx = rr1;
|
||||
|
||||
/* Are all rrs with this name equal? */
|
||||
for ( k = i + 1
|
||||
; k < rrc1 &&
|
||||
ldns_dname_compare(ldns_rr_owner(rr1),
|
||||
ldns_rr_owner(ldns_rr_list_rr(rrl1, k))) == 0
|
||||
; k++);
|
||||
|
||||
|
||||
for ( l = j + 1
|
||||
; l < rrc2 &&
|
||||
ldns_dname_compare(ldns_rr_owner(rr2),
|
||||
ldns_rr_owner(ldns_rr_list_rr(rrl2, l))) == 0
|
||||
; l++);
|
||||
|
||||
if ((k - i) != (l - j)) {
|
||||
op = OP_CHG;
|
||||
num_chg++;
|
||||
} else {
|
||||
nc1 = k - i;
|
||||
nc2 = l - j;
|
||||
for ( k = i + 1, l = j + 1
|
||||
; (k - i) < nc1 && (l - j) < nc2 &&
|
||||
ldns_rr_compare(ldns_rr_list_rr(rrl1, k),
|
||||
ldns_rr_list_rr(rrl2, l)) == 0
|
||||
; k++, l++);
|
||||
if ((k - i) < nc1) {
|
||||
op = OP_CHG;
|
||||
num_chg++;
|
||||
} else {
|
||||
op = OP_EQ;
|
||||
num_eq++;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (((op == OP_EQ ) && opt_unchanged) ||
|
||||
((op == OP_CHG) && opt_Unchanged && opt_changed)) {
|
||||
printf("%c=", op);
|
||||
ldns_rr_print(stdout, rr1);
|
||||
}
|
||||
i++;
|
||||
j++;
|
||||
}
|
||||
}
|
||||
|
||||
if (opt_unchanged || opt_Unchanged)
|
||||
printf("\t%c%u\t%c%u\t%c%u\t%c%u\n",
|
||||
OP_INS,
|
||||
(unsigned int) num_ins,
|
||||
OP_DEL,
|
||||
(unsigned int) num_del,
|
||||
OP_CHG,
|
||||
(unsigned int) num_chg,
|
||||
OP_EQ,
|
||||
(unsigned int) num_eq);
|
||||
else
|
||||
printf("\t%c%u\t%c%u\t%c%u\n",
|
||||
OP_INS,
|
||||
(unsigned int) num_ins,
|
||||
OP_DEL,
|
||||
(unsigned int) num_del,
|
||||
OP_CHG,
|
||||
(unsigned int) num_chg);
|
||||
|
||||
/* Free resources */
|
||||
if(inc_soa) {
|
||||
ldns_rr_list_free(rrl1);
|
||||
ldns_rr_list_free(rrl2);
|
||||
}
|
||||
ldns_zone_deep_free(z2);
|
||||
ldns_zone_deep_free(z1);
|
||||
|
||||
return opt_exit_status && (num_ins || num_del || num_chg) ? 2 : 0;
|
||||
}
|
||||
179
zonemaster-ldns/ldns/examples/ldns-dane.1.in
Normal file
179
zonemaster-ldns/ldns/examples/ldns-dane.1.in
Normal file
@@ -0,0 +1,179 @@
|
||||
.TH ldns-dane 1 "17 September 2012"
|
||||
.SH NAME
|
||||
ldns-dane \- verify or create TLS authentication with DANE (RFC6698)
|
||||
.SH SYNOPSIS
|
||||
.PD 0
|
||||
.B ldns-dane
|
||||
.IR [OPTIONS]
|
||||
.IR verify
|
||||
.IR name
|
||||
.IR port
|
||||
.PP
|
||||
.B ldns-dane
|
||||
.IR [OPTIONS]
|
||||
.IR -t
|
||||
.IR tlsafile
|
||||
.IR verify
|
||||
|
||||
.B ldns-dane
|
||||
.IR [OPTIONS]
|
||||
.IR create
|
||||
.IR name
|
||||
.IR port
|
||||
.PP
|
||||
[
|
||||
.IR Certificate-usage
|
||||
[
|
||||
.IR Selector
|
||||
[
|
||||
.IR Matching-type
|
||||
] ] ]
|
||||
|
||||
.B ldns-dane
|
||||
.IR -h
|
||||
.PP
|
||||
.B ldns-dane
|
||||
.IR -v
|
||||
.PD 1
|
||||
|
||||
.SH DESCRIPTION
|
||||
|
||||
In the first form:
|
||||
A TLS connection to \fIname\fR:\fIport\fR is established.
|
||||
The TLSA resource record(s) for \fIname\fR are used to authenticate
|
||||
the connection.
|
||||
|
||||
In the second form:
|
||||
The TLSA record(s) are read from \fItlsafile\fR and used to authenticate
|
||||
the TLS service they reference.
|
||||
|
||||
In the third form:
|
||||
A TLS connection to \fIname\fR:\fIport\fR is established and used to
|
||||
create the TLSA resource record(s) that would authenticate the connection.
|
||||
The parameters for TLSA rr creation are:
|
||||
|
||||
.PD 0
|
||||
.I Certificate-usage\fR:
|
||||
.RS
|
||||
.IP "0 | PKIX-TA"
|
||||
CA constraint
|
||||
.IP "1 | PKIX-EE"
|
||||
Service certificate constraint
|
||||
.IP "2 | DANE-TA"
|
||||
Trust anchor assertion
|
||||
.IP "3 | DANE-EE"
|
||||
Domain-issued certificate (default)
|
||||
.RE
|
||||
|
||||
.I Selector\fR:
|
||||
.RS
|
||||
.IP "0 | Cert"
|
||||
Full certificate
|
||||
.IP "1 | SPKI"
|
||||
SubjectPublicKeyInfo (default)
|
||||
.RE
|
||||
|
||||
.I Matching-type\fR:
|
||||
.RS
|
||||
.IP "0 | Full"
|
||||
No hash used
|
||||
.IP "1 | SHA2-256"
|
||||
SHA-256 (default)
|
||||
.IP "2 | SHA2-512"
|
||||
SHA-512
|
||||
.RE
|
||||
.PD 1
|
||||
|
||||
.SH OPTIONS
|
||||
.IP -4
|
||||
TLS connect IPv4 only
|
||||
.IP -6
|
||||
TLS connect IPv6 only
|
||||
.IP "-a \fIaddress\fR"
|
||||
Don't try to resolve \fIname\fR, but connect to \fIaddress\fR instead.
|
||||
|
||||
This option may be given more than once.
|
||||
.IP -b
|
||||
print "\fIname\fR\. TYPE52 \\# \fIsize\fR \fIhexdata\fR" form instead
|
||||
of TLSA presentation format.
|
||||
.IP "-c \fIcertfile\fR"
|
||||
Do not TLS connect to \fIname\fR:\fIport\fR, but authenticate (or make
|
||||
TLSA records) for the certificate (chain) in \fIcertfile\fR instead.
|
||||
.IP -d
|
||||
Assume DNSSEC validity even when the TLSA records were acquired insecure
|
||||
or were bogus.
|
||||
.IP "-f \fICAfile\fR"
|
||||
Use CAfile to validate. @DEFAULT_CAFILE@
|
||||
.IP -h
|
||||
Print short usage help
|
||||
.IP -i
|
||||
Interact after connecting.
|
||||
.IP "-k \fIkeyfile\fR"
|
||||
Specify a file that contains a trusted DNSKEY or DS rr.
|
||||
Key(s) are used when chasing signatures (i.e. \fI-S\fR is given).
|
||||
|
||||
This option may be given more than once.
|
||||
|
||||
Alternatively, if \fB-k\fR is not specified, and a default trust anchor
|
||||
(@LDNS_TRUST_ANCHOR_FILE@) exists and contains a valid DNSKEY or DS record,
|
||||
it will be used as the trust anchor.
|
||||
.IP -n
|
||||
Do \fBnot\fR verify server name in certificate.
|
||||
.IP "-o \fIoffset\fR"
|
||||
When creating a "Trust anchor assertion" TLSA resource record,
|
||||
select the \fIoffset\fRth certificate offset from the end
|
||||
of the validation chain. 0 means the last certificate, 1 the one but last,
|
||||
2 the second but last, etc.
|
||||
|
||||
When \fIoffset\fR is \-1 (the default), the last certificate
|
||||
is used (like with 0) that MUST be self-signed. This can help to make
|
||||
sure that the intended (self signed) trust anchor is actually present
|
||||
in the server certificate chain (which is a DANE requirement).
|
||||
.IP "-p \fICApath\fR"
|
||||
Use certificates in the \fICApath\fR directory to validate. @DEFAULT_CAPATH@
|
||||
.IP -s
|
||||
When creating TLSA resource records with the "CA Constraint" and the
|
||||
"Service Certificate Constraint" certificate usage, do not validate and
|
||||
assume PKIX is valid.
|
||||
|
||||
For "CA Constraint" this means that verification should end with a
|
||||
self-signed certificate.
|
||||
.IP -S
|
||||
Chase signature(s) to a known key.
|
||||
|
||||
Without this option, the local network is trusted to provide
|
||||
a DNSSEC resolver (i.e. AD bit is checked).
|
||||
.IP "-t \fItlsafile\fR"
|
||||
Read TLSA record(s) from \fItlsafile\fR. When \fIname\fR and \fIport\fR
|
||||
are also given, only TLSA records that match the \fIname\fR, \fIport\fR and
|
||||
\fItransport\fR are used. Otherwise the owner name of the TLSA record(s)
|
||||
will be used to determine \fIname\fR, \fIport\fR and \fItransport\fR.
|
||||
.IP -T
|
||||
Return exit status 2 for PKIX validated connections without (secure)
|
||||
TLSA records(s)
|
||||
.IP -u
|
||||
Use UDP transport instead of TCP.
|
||||
.IP -v
|
||||
Show version and exit.
|
||||
|
||||
.SH "FILES"
|
||||
.TP
|
||||
@LDNS_TRUST_ANCHOR_FILE@
|
||||
The file from which trusted keys are loaded for signature chasing,
|
||||
when no \fB-k\fR option is given.
|
||||
|
||||
.SH "SEE ALSO"
|
||||
.LP
|
||||
unbound-anchor(8)
|
||||
|
||||
.SH AUTHOR
|
||||
Written by the ldns team as an example for ldns usage.
|
||||
|
||||
.SH REPORTING BUGS
|
||||
Report bugs to <dns-team@nlnetlabs.nl>.
|
||||
|
||||
.SH COPYRIGHT
|
||||
Copyright (C) 2012 NLnet Labs. This is free software. There is NO
|
||||
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR
|
||||
PURPOSE.
|
||||
|
||||
2053
zonemaster-ldns/ldns/examples/ldns-dane.c
Normal file
2053
zonemaster-ldns/ldns/examples/ldns-dane.c
Normal file
File diff suppressed because it is too large
Load Diff
151
zonemaster-ldns/ldns/examples/ldns-dpa.1
Normal file
151
zonemaster-ldns/ldns/examples/ldns-dpa.1
Normal file
@@ -0,0 +1,151 @@
|
||||
.TH dpa 1 "1 Nov 2005"
|
||||
.SH NAME
|
||||
dpa \- DNS Packet Analyzer. Analyze DNS packets in ip trace files
|
||||
.SH SYNOPSIS
|
||||
.B dpa
|
||||
[
|
||||
.IR OPTION
|
||||
]
|
||||
.IR TRACEFILE
|
||||
|
||||
.SH DESCRIPTION
|
||||
\fBdpa\fR is used to analyze dns packets in trace files. It has 3 main options: count, filter, and count uniques (i.e. count all different occurrences).
|
||||
|
||||
.SH OPTIONS
|
||||
.TP
|
||||
\fB-c\fR \fIexpressionlist\fR
|
||||
Count occurrences of matching expressions
|
||||
|
||||
.TP
|
||||
\fB-f\fR \fIexpression\fR
|
||||
Filter: only process packets that match the expression
|
||||
|
||||
.TP
|
||||
\fB-h\fR
|
||||
Show usage
|
||||
|
||||
.TP
|
||||
\fB-p\fR
|
||||
Show the total number of correct DNS packets, and percentage of \-u and
|
||||
\-c values (of the total of matching on the \-f filter. if no filter is
|
||||
given, percentages are on all correct dns packets)
|
||||
|
||||
.TP
|
||||
\fB-of\fR \fIfile\fR
|
||||
Write all packets that match the \-f flag to file, as pcap data.
|
||||
|
||||
.TP
|
||||
\fB-ofh\fR \fIfile\fR
|
||||
Write all packets that match the \-f flag to file, in hexadecimal format,
|
||||
readable by drill.
|
||||
|
||||
.TP
|
||||
\fB-s\fR
|
||||
Show possible match names
|
||||
|
||||
.TP
|
||||
\fB-s\fR \fImatchname\fR
|
||||
show possible match operators and values for name
|
||||
|
||||
.TP
|
||||
\fB-sf\fR
|
||||
Only evaluate packets (in representation format) that match the \-f filter.
|
||||
If no \-f was given, evaluate all correct dns packets.
|
||||
|
||||
.TP
|
||||
\fB-u\fR \fImatchnamelist\fR
|
||||
Count every occurrence of every value of the matchname (for instance, count all packetsizes, see EXAMPLES in ldns-dpa(1) ).
|
||||
|
||||
.TP
|
||||
\fB-ua\fR
|
||||
For every matchname in \-u, show the average value of all matches. Behaviour for match types that do not have an integer value is undefined.
|
||||
|
||||
.TP
|
||||
\fB-uac\fR
|
||||
For every matchname in \-u, show the average number of times this value was encountered.
|
||||
|
||||
.TP
|
||||
\fB-um\fR \fInumber\fR
|
||||
Only show the results from \-u for values that occurred more than <number> times.
|
||||
|
||||
.TP
|
||||
\fB-v\fR \fIlevel\fR
|
||||
Set verbosity to level (1-5, 5 being the highest). Mostly used for debugging.
|
||||
|
||||
.TP
|
||||
\fB-notip\fR \fIfile\fR
|
||||
Write packets that were not recognized as IP packets to file (as pcap data).
|
||||
|
||||
.TP
|
||||
\fB-baddns\fR \fIfile\fR
|
||||
Write dns packets that were too mangled to parse to file (as pcap data).
|
||||
|
||||
.TP
|
||||
\fB-version\fR
|
||||
Show version and exit
|
||||
|
||||
.SH LIST AND MATCHES
|
||||
|
||||
A <matchnamelist> is a comma separated list of match names (use \-s to see possible match names).
|
||||
A <expressionlist> is a comma separated list of expressions.
|
||||
|
||||
An expression has the following form:
|
||||
<expr>: (<expr>)
|
||||
<expr> | <expr>
|
||||
<expr> & <expr>
|
||||
<match>
|
||||
|
||||
<match>: <matchname> <operator> <value>
|
||||
|
||||
<operator>:
|
||||
= equal to <value>
|
||||
!= not equal to <value>
|
||||
> greater than <value>
|
||||
< lesser than <value>
|
||||
>= greater than or equal to <value>
|
||||
<= lesser than or equal to <value>
|
||||
~= contains <value>
|
||||
|
||||
See the \-s option for possible matchnames, operators and values.
|
||||
|
||||
.SH EXAMPLES
|
||||
|
||||
.TP
|
||||
ldns-dpa \-u packetsize \-p test.tr
|
||||
Count all different packetsizes in test.tr and show the percentages.
|
||||
|
||||
.TP
|
||||
ldns-dpa \-f "edns=1&qr=0" \-of edns.tr test.tr
|
||||
Filter out all edns enable queries in test.tr and put them in edns.tr
|
||||
|
||||
.TP
|
||||
ldns-dpa \-f edns=1 \-c tc=1 \-u rcode test.tr
|
||||
For all edns packets, count the number of truncated packets and all their rcodes in test.tr.
|
||||
|
||||
.TP
|
||||
ldns-dpa \-c tc=1,qr=0,qr=1,opcode=QUERY test.tr
|
||||
For all packets, count the number of truncated packets, the number of packets with qr=0, the number of packets with qr=1 and the number of queries in test.tr.
|
||||
|
||||
.TP
|
||||
ldns-dpa \-u packetsize \-ua test.tr
|
||||
Show all packet sizes and the average packet size per packet.
|
||||
|
||||
.TP
|
||||
ldns-dpa \-u srcaddress \-uac test.tr
|
||||
Show all packet source addresses and the average number of packets sent from this address.
|
||||
|
||||
.TP
|
||||
sudo tcpdump \-i eth0 \-s 0 \-U \-w \- port 53 | ldns-dpa \-f qr=0 \-sf
|
||||
Print all query packets seen on the specified interface.
|
||||
|
||||
|
||||
.SH AUTHOR
|
||||
Written by Jelte Jansen for NLnetLabs.
|
||||
|
||||
.SH REPORTING BUGS
|
||||
Report bugs to <dns-team@nlnetlabs.nl>.
|
||||
|
||||
.SH COPYRIGHT
|
||||
Copyright (C) 2005 NLnet Labs. This is free software. There is NO
|
||||
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR
|
||||
PURPOSE.
|
||||
2857
zonemaster-ldns/ldns/examples/ldns-dpa.c
Normal file
2857
zonemaster-ldns/ldns/examples/ldns-dpa.c
Normal file
File diff suppressed because it is too large
Load Diff
92
zonemaster-ldns/ldns/examples/ldns-dpa.h
Normal file
92
zonemaster-ldns/ldns/examples/ldns-dpa.h
Normal file
@@ -0,0 +1,92 @@
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
#include <assert.h>
|
||||
|
||||
#if STDC_HEADERS
|
||||
#include <stdlib.h>
|
||||
#include <stddef.h>
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_STDINT_H
|
||||
#include <stdint.h>
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_SYS_SOCKET_H
|
||||
#include <sys/socket.h>
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_NETINET_IN_H
|
||||
#include <netinet/in.h>
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_ARPA_INET_H
|
||||
#include <arpa/inet.h>
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_NETINET_UDP_H
|
||||
#include <netinet/udp.h>
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_TIME_H
|
||||
#include <time.h>
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_PCAP_H
|
||||
#include <pcap.h>
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_NETINET_IN_SYSTM_H
|
||||
#include <netinet/in_systm.h>
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_NETINET_IP_H
|
||||
#include <netinet/ip.h>
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_NET_IF_H
|
||||
#include <net/if.h>
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_NETINET_IF_ETHER_H
|
||||
#include <netinet/if_ether.h>
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_WINSOCK2_H
|
||||
#define USE_WINSOCK 1
|
||||
#include <winsock2.h>
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_WS2TCPIP_H
|
||||
#include <ws2tcpip.h>
|
||||
#endif
|
||||
|
||||
#ifndef HAVE_GETADDRINFO
|
||||
#include <fake-rfc2553.h>
|
||||
#endif
|
||||
|
||||
#ifndef HAVE_RANDOM
|
||||
/* random can be replaced by rand for ldnsexamples */
|
||||
#define random rand
|
||||
#endif
|
||||
|
||||
#ifndef HAVE_SRANDOM
|
||||
/* srandom can be replaced by srand for ldnsexamples */
|
||||
#define srandom srand
|
||||
#endif
|
||||
|
||||
extern char *optarg;
|
||||
extern int optind, opterr;
|
||||
|
||||
#ifndef EXIT_FAILURE
|
||||
#define EXIT_FAILURE 1
|
||||
#endif
|
||||
#ifndef EXIT_SUCCESS
|
||||
#define EXIT_SUCCESS 0
|
||||
#endif
|
||||
|
||||
#ifdef S_SPLINT_S
|
||||
#define FD_ZERO(a) /* a */
|
||||
#define FD_SET(a,b) /* a, b */
|
||||
#endif
|
||||
|
||||
98
zonemaster-ldns/ldns/examples/ldns-gen-zone.1
Normal file
98
zonemaster-ldns/ldns/examples/ldns-gen-zone.1
Normal file
@@ -0,0 +1,98 @@
|
||||
.TH ldns-gen-zone 1 "10 June 2010"
|
||||
.SH NAME
|
||||
ldns-gen-zone \- read a zonefile and print it while adding DS records and extra RR's
|
||||
.SH SYNOPSIS
|
||||
.B ldns-gen-zone
|
||||
.IR ZONEFILE
|
||||
|
||||
.SH DESCRIPTION
|
||||
|
||||
\fBldns-gen-zone\fR reads a DNS zone file and prints it.
|
||||
|
||||
It is build for speed, not for a nice formatting. The output
|
||||
has one resource record per line and no pretty-printing makeup.
|
||||
|
||||
DNSSEC data (NSEC, NSEC3, RRSIG or DNSKEY) is not stripped. You may want to
|
||||
use \fBldns-read-zone\fR for that. Existing DS records are also not stripped.
|
||||
|
||||
The idea is to use this tool for quickly generating a representative
|
||||
artificial zonefile from a real zonefile, to use it for testing purposes.
|
||||
|
||||
.SH OPTIONS
|
||||
.TP
|
||||
\fB-a NUM\fR
|
||||
Adds NUM extra artificial NS RRSets to the output.
|
||||
The RRSets owner names start
|
||||
with 'xn--' in an attempt to ensure uniqueness (nl.-zone does not support
|
||||
IDN's - and this tool was written with that knowledge in mind).
|
||||
|
||||
An artificial NS RRSet has two NS records; ns1.example.com and
|
||||
ns2.example.com.
|
||||
|
||||
.TP
|
||||
\fB-p NUM\fR
|
||||
Add NUM% of DS RRSets to the NS RRSets (anywhere between
|
||||
1-4 DS records per RRSet).
|
||||
|
||||
.TP
|
||||
\fB-o ORIGIN\fR
|
||||
Sets an $ORIGIN, which can be handy if the one in the zonefile
|
||||
is set to '@' for example. If there is an $ORIGIN in the zonefile,
|
||||
this option will silently be ignored.
|
||||
|
||||
.TP
|
||||
\fB-s\fR
|
||||
This is the recommended way of processing large zones that
|
||||
are already sorted and canonicalized (ie lowercase). It skips the
|
||||
sorting and canonicalization step that is required for properly
|
||||
grouping RRSets together (before adding any DS records to them. Skipping
|
||||
this step will speed things up.
|
||||
|
||||
It is not recommended to use this option if you want to add DS records
|
||||
to unsorted, non-canonicalized zones.
|
||||
|
||||
.TP
|
||||
\fB-h\fR
|
||||
Show usage and exit.
|
||||
|
||||
.TP
|
||||
\fB-v\fR
|
||||
Show version and exit.
|
||||
|
||||
.SH EXAMPLES
|
||||
|
||||
.TP
|
||||
\fBldns-gen-zone \-a 100000 \-p 10 \-s ./zonefile.txt\fR
|
||||
Read a zonefile, add 100.000 artificial NS RRSets and 10% of DS records,
|
||||
print it to standard output. Don't sort (will only work well if the input
|
||||
zonefile is already sorted and canonicalized).
|
||||
|
||||
.TP
|
||||
\fBldns-gen-zone \-p 10 \-s \-o nl zonefile.txt | named-compilezone \-s relative \-i none \-o zonefile_10.txt nl /dev/stdin\fR
|
||||
This creates a nicely formatted zone file with the help of \fBnamed-compilezone\fR.
|
||||
It adds 10% DS records to the .nl zone, reformats it and saves it as \fBzonefile_10.txt\fR.
|
||||
|
||||
.SH AUTHOR
|
||||
Initially written by Marco Davids, several modifications added by Miek
|
||||
Gieben, both from SIDN.
|
||||
|
||||
.SH REPORTING BUGS
|
||||
Report bugs to <dns-team@nlnetlabs.nl>.
|
||||
|
||||
.SH BUGS
|
||||
Only undiscovered ones.
|
||||
|
||||
.SH CAVEATS
|
||||
May require a machine with a considerable amount of memory for large zone files.
|
||||
|
||||
Fake DS records hashes are generated as digest type SHA-256 (RFC4509). Be aware not to change
|
||||
the DIGESTTYPE #define in the source code in anything else but 2 if you want
|
||||
to keep things realistic.
|
||||
|
||||
Despite a number of efforts, this program is still not the fastest in the
|
||||
world.
|
||||
|
||||
.SH COPYRIGHT
|
||||
Copyright (C) 2010 SIDN. This is free software. There is NO
|
||||
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR
|
||||
PURPOSE.
|
||||
307
zonemaster-ldns/ldns/examples/ldns-gen-zone.c
Normal file
307
zonemaster-ldns/ldns/examples/ldns-gen-zone.c
Normal file
@@ -0,0 +1,307 @@
|
||||
/*
|
||||
* Reads a zone file from disk and prints it to stdout, one RR per line.
|
||||
* Adds artificial DS records and RRs.
|
||||
* For the purpose of generating a test zone file
|
||||
*
|
||||
* (c) SIDN 2010/2011 - Marco Davids/Miek Gieben
|
||||
*
|
||||
* See the LICENSE file for the license
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
#include <unistd.h>
|
||||
#include <stdlib.h>
|
||||
#include <ldns/ldns.h>
|
||||
#include <errno.h>
|
||||
|
||||
#define NUM_DS 4 /* maximum of 4 DS records per delegation */
|
||||
#define ALGO 8 /* Algorithm to use for fake DS records - RSASHA256 - RFC5702 */
|
||||
#define DIGESTTYPE 2 /* Digest type to use for fake DS records - SHA-256 - RFC 4509 */
|
||||
|
||||
|
||||
/**
|
||||
* Usage function.
|
||||
*
|
||||
*/
|
||||
static void
|
||||
usage(FILE *fp, char *prog) {
|
||||
fprintf(fp, "\n\nUsage: %s [-hsv] [-ap NUM] [-o ORIGIN] [<zonefile>]\n", prog);
|
||||
fprintf(fp, "\tReads a zonefile and add some artificial NS RRsets and DS records.\n");
|
||||
fprintf(fp, "\tIf no zonefile is given, the zone is read from stdin.\n");
|
||||
fprintf(fp, "\t-a <NUM> add NUM artificial delegations (NS RRSets) to output.\n");
|
||||
fprintf(fp, "\t-p <NUM> add NUM percent of DS RRset's to the NS RRsets (1-%d RR's per DS RRset).\n", NUM_DS);
|
||||
fprintf(fp, "\t-o ORIGIN sets an $ORIGIN, which can be handy if the one in the zonefile is set to @.\n");
|
||||
fprintf(fp, "\t-s if input zone file is already sorted and canonicalized (ie all lowercase),\n\t use this option to speed things up while inserting DS records.\n");
|
||||
fprintf(fp, "\t-h show this text.\n");
|
||||
fprintf(fp, "\t-v shows the version and exits.\n");
|
||||
fprintf(fp, "\nif no file is given standard input is read.\n\n");
|
||||
}
|
||||
|
||||
/**
|
||||
* Insert the DS records, return the amount added.
|
||||
*
|
||||
*/
|
||||
static int
|
||||
insert_ds(ldns_rdf *dsowner, uint32_t ttl)
|
||||
{
|
||||
int d, dsrand;
|
||||
int keytag = 0;
|
||||
char *dsownerstr;
|
||||
char digeststr[70];
|
||||
|
||||
/**
|
||||
* Average the amount of DS records per delegation a little.
|
||||
*/
|
||||
dsrand = 1+rand() % NUM_DS;
|
||||
for(d = 0; d < dsrand; d++) {
|
||||
keytag = 1+rand() % 65535;
|
||||
/**
|
||||
* Dynamic hashes method below is still too slow... 20% slower than a fixed string...
|
||||
*
|
||||
* We assume RAND_MAX is 32 bit, http://www.gnu.org/s/libc/manual/html_node/ISO-Random.html
|
||||
* 2147483647 or 0x7FFFFFFF
|
||||
*/
|
||||
snprintf(digeststr, 65,
|
||||
"%08x%08x%08x%08x%08x%08x%08x%08x",
|
||||
(unsigned) rand()%RAND_MAX, (unsigned) rand()%RAND_MAX, (unsigned) rand()%RAND_MAX,
|
||||
(unsigned) rand()%RAND_MAX, (unsigned) rand()%RAND_MAX, (unsigned) rand()%RAND_MAX,
|
||||
(unsigned) rand()%RAND_MAX, (unsigned) rand()%RAND_MAX);
|
||||
dsownerstr = ldns_rdf2str(dsowner);
|
||||
fprintf(stdout, "%s\t%u\tIN\tDS\t%d %d %d %s\n", dsownerstr, (unsigned) ttl, keytag, ALGO, DIGESTTYPE, digeststr);
|
||||
}
|
||||
return dsrand;
|
||||
}
|
||||
|
||||
int
|
||||
main(int argc, char **argv) {
|
||||
char *filename, *rrstr, *ownerstr;
|
||||
const char *classtypestr1 = "IN NS ns1.example.com.";
|
||||
const char *classtypestr2 = "IN NS ns2.example.com.";
|
||||
const size_t classtypelen = strlen(classtypestr1);
|
||||
/* Simply because this was developed by SIDN and we don't use xn-- for .nl :-) */
|
||||
const char *punystr = "xn--fake-rr";
|
||||
const size_t punylen = strlen(punystr);
|
||||
size_t rrstrlen, ownerlen;
|
||||
FILE *fp;
|
||||
int c, nsrand;
|
||||
uint32_t ttl;
|
||||
int counta,countd,countr;
|
||||
ldns_zone *z;
|
||||
ldns_rdf *origin = NULL;
|
||||
int line_nr = 0;
|
||||
int addrrs = 0;
|
||||
int dsperc = 0;
|
||||
bool canonicalize = true;
|
||||
bool sort = true;
|
||||
bool do_ds = false;
|
||||
ldns_status s;
|
||||
size_t i;
|
||||
ldns_rr_list *rrset_list;
|
||||
ldns_rdf *owner;
|
||||
ldns_rr_type cur_rr_type;
|
||||
ldns_rr *cur_rr;
|
||||
ldns_status status;
|
||||
|
||||
counta = countd = countr = 0;
|
||||
|
||||
/**
|
||||
* Set some random seed.
|
||||
*/
|
||||
srand((unsigned int)time(NULL));
|
||||
|
||||
/**
|
||||
* Commandline options.
|
||||
*/
|
||||
while ((c = getopt(argc, argv, "a:p:shvo:")) != -1) {
|
||||
switch (c) {
|
||||
case 'a':
|
||||
addrrs = atoi(optarg);
|
||||
if (addrrs <= 0) {
|
||||
fprintf(stderr, "error\n");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
break;
|
||||
case 'o':
|
||||
origin = ldns_rdf_new_frm_str(LDNS_RDF_TYPE_DNAME, optarg);
|
||||
if (!origin) {
|
||||
fprintf(stderr, "error: creating origin from -o %s failed.\n", optarg);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
break;
|
||||
case 'p':
|
||||
dsperc = atoi(optarg);
|
||||
if (dsperc < 0 || dsperc > 100) {
|
||||
fprintf(stderr, "error: percentage of signed delegations must be between [0-100].\n");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
do_ds = true;
|
||||
break;
|
||||
case 's':
|
||||
sort = false;
|
||||
canonicalize = false;
|
||||
break;
|
||||
case 'h':
|
||||
usage(stdout, argv[0]);
|
||||
exit(EXIT_SUCCESS);
|
||||
case 'v':
|
||||
fprintf(stdout, "ldns-gen-zone version %s (ldns version %s)\n", LDNS_VERSION, ldns_version());
|
||||
exit(EXIT_SUCCESS);
|
||||
default:
|
||||
fprintf(stderr, "\nTry -h for more information.\n\n");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
}
|
||||
argc -= optind;
|
||||
argv += optind;
|
||||
|
||||
/**
|
||||
* Read zone.
|
||||
*/
|
||||
if (argc == 0) {
|
||||
fp = stdin;
|
||||
} else {
|
||||
filename = argv[0];
|
||||
fp = fopen(filename, "r");
|
||||
if (!fp) {
|
||||
fprintf(stderr, "Unable to open %s: %s\n", filename, strerror (errno));
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
}
|
||||
s = ldns_zone_new_frm_fp_l(&z, fp, origin, 0, LDNS_RR_CLASS_IN, &line_nr);
|
||||
if (s != LDNS_STATUS_OK) {
|
||||
fprintf(stderr, "%s at line %d\n", ldns_get_errorstr_by_id(s), line_nr);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
if (!ldns_zone_soa(z)) {
|
||||
fprintf(stderr, "No zone data seen\n");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
ttl = ldns_rr_ttl(ldns_zone_soa(z));
|
||||
if (!origin) {
|
||||
origin = ldns_rr_owner(ldns_zone_soa(z));
|
||||
// Check for root (.) origin here TODO(MG)
|
||||
}
|
||||
ownerstr = ldns_rdf2str(origin);
|
||||
if (!ownerstr) {
|
||||
fprintf(stderr, "ldns_rdf2str(origin) failed\n");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
ownerlen = strlen(ownerstr);
|
||||
|
||||
ldns_rr_print(stdout, ldns_zone_soa(z));
|
||||
|
||||
if (addrrs > 0) {
|
||||
while (addrrs > counta) {
|
||||
counta++;
|
||||
rrstrlen = punylen + ownerlen + classtypelen + 4;
|
||||
rrstrlen *= 2; /* estimate */
|
||||
rrstr = (char*)malloc(rrstrlen);
|
||||
if (!rrstr) {
|
||||
fprintf(stderr, "malloc() failed: Out of memory\n");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
(void)snprintf(rrstr, rrstrlen, "%s%d.%s %u %s", punystr, counta,
|
||||
ownerstr, (unsigned) ttl, classtypestr1);
|
||||
status = ldns_rr_new_frm_str(&cur_rr, rrstr, 0, NULL, NULL);
|
||||
if (status == LDNS_STATUS_OK) {
|
||||
ldns_rr_print(stdout, cur_rr);
|
||||
ldns_rr_free(cur_rr);
|
||||
} else {
|
||||
fprintf(stderr, "ldns_rr_new_frm_str() failed\n");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
(void)snprintf(rrstr, rrstrlen, "%s%d.%s %u %s", punystr, counta,
|
||||
ownerstr, (unsigned) ttl, classtypestr2);
|
||||
status = ldns_rr_new_frm_str(&cur_rr, rrstr, 0, NULL, NULL);
|
||||
if (status == LDNS_STATUS_OK) {
|
||||
ldns_rr_print(stdout, cur_rr);
|
||||
} else {
|
||||
fprintf(stderr, "ldns_rr_new_frm_str() failed\n");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
free(rrstr);
|
||||
|
||||
/* may we add a DS record as well? */
|
||||
if (do_ds) {
|
||||
/*
|
||||
* Per definition this may not be the same as the origin, so no
|
||||
* check required same for NS check - so the only thing left is some
|
||||
* randomization.
|
||||
*/
|
||||
nsrand = rand() % 100;
|
||||
if (nsrand < dsperc) {
|
||||
owner = ldns_rr_owner(cur_rr);
|
||||
ttl = ldns_rr_ttl(cur_rr);
|
||||
countd += insert_ds(owner, ttl);
|
||||
}
|
||||
}
|
||||
ldns_rr_free(cur_rr);
|
||||
}
|
||||
}
|
||||
|
||||
if (!do_ds) {
|
||||
ldns_rr_list_print(stdout, ldns_zone_rrs(z));
|
||||
} else {
|
||||
/*
|
||||
* We use dns_rr_list_pop_rrset and that requires a sorted list weird things may happen
|
||||
* if the -s option was used on unsorted, non-canonicalized input
|
||||
*/
|
||||
if (canonicalize) {
|
||||
ldns_rr2canonical(ldns_zone_soa(z));
|
||||
for (i = 0; i < ldns_rr_list_rr_count(ldns_zone_rrs(z)); i++) {
|
||||
ldns_rr2canonical(ldns_rr_list_rr(ldns_zone_rrs(z), i));
|
||||
}
|
||||
}
|
||||
|
||||
if (sort) {
|
||||
ldns_zone_sort(z);
|
||||
}
|
||||
|
||||
/* Work on a per RRset basis for DS records - weird things will happen if the -s option
|
||||
* was used in combination with an unsorted zone file
|
||||
*/
|
||||
while((rrset_list = ldns_rr_list_pop_rrset(ldns_zone_rrs(z)))) {
|
||||
owner = ldns_rr_list_owner(rrset_list);
|
||||
cur_rr_type = ldns_rr_list_type(rrset_list);
|
||||
/**
|
||||
* Print them...
|
||||
*/
|
||||
cur_rr = ldns_rr_list_pop_rr(rrset_list);
|
||||
while (cur_rr) {
|
||||
ttl = ldns_rr_ttl(cur_rr);
|
||||
fprintf(stdout, "%s", ldns_rr2str(cur_rr));
|
||||
cur_rr = ldns_rr_list_pop_rr(rrset_list);
|
||||
}
|
||||
/*
|
||||
* And all the way at the end a DS record if
|
||||
* we are dealing with an NS rrset
|
||||
*/
|
||||
nsrand = rand() % 100;
|
||||
if (nsrand == 0) {
|
||||
nsrand = 100;
|
||||
}
|
||||
|
||||
if ((cur_rr_type == LDNS_RR_TYPE_NS) &&
|
||||
(ldns_rdf_compare(owner, origin) != 0) && (nsrand < dsperc)) {
|
||||
/**
|
||||
* No DS records for the $ORIGIN, only for delegations, obey dsperc.
|
||||
*/
|
||||
countr++;
|
||||
countd += insert_ds(owner, ttl);
|
||||
}
|
||||
ldns_rr_list_free(rrset_list);
|
||||
ldns_rdf_free(owner);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* And done...
|
||||
*/
|
||||
fclose(fp);
|
||||
fprintf(stdout, ";; Added %d DS records (percentage was %d) to %d NS RRset's (from input-zone: %d, from added: %d)\n;; lines in original input-zone: %d\n",
|
||||
countd, dsperc, counta + countr, countr, counta, line_nr);
|
||||
exit(EXIT_SUCCESS);
|
||||
}
|
||||
52
zonemaster-ldns/ldns/examples/ldns-key2ds.1
Normal file
52
zonemaster-ldns/ldns/examples/ldns-key2ds.1
Normal file
@@ -0,0 +1,52 @@
|
||||
.TH ldns-key2ds 1 "30 May 2005"
|
||||
.SH NAME
|
||||
ldns-key2ds \- transform a DNSKEY RR to a DS RR
|
||||
.SH SYNOPSIS
|
||||
.B ldns-key2ds
|
||||
.IR file
|
||||
|
||||
.SH DESCRIPTION
|
||||
\fBldns-key2ds\fR is used to transform a public DNSKEY RR to a DS RR.
|
||||
When run it will read \fIfile\fR with a DNSKEY RR in it and
|
||||
it will create a .ds file with the DS RR in it.
|
||||
|
||||
It prints out the basename for this file (K<name>+<alg>+<id>).
|
||||
|
||||
By default it takes a pick of algorithm similar to the key algorithm,
|
||||
SHA1 for RSASHA1, and so on.
|
||||
|
||||
.SH OPTIONS
|
||||
.TP
|
||||
\fB-f\fR
|
||||
Ignore SEP flag (i.e. make DS records for any key)
|
||||
|
||||
.TP
|
||||
\fB-n\fR
|
||||
Write the result DS Resource Record to stdout instead of a file
|
||||
|
||||
.TP
|
||||
\fB-1\fR
|
||||
Use SHA1 as the hash function.
|
||||
|
||||
.TP
|
||||
\fB-2\fR
|
||||
Use SHA256 as the hash function
|
||||
|
||||
.TP
|
||||
\fB-g\fR
|
||||
Use GOST as the hash function
|
||||
|
||||
.TP
|
||||
\fB-4\fR
|
||||
Use SHA384 as the hash function
|
||||
|
||||
.SH AUTHOR
|
||||
Written by the ldns team as an example for ldns usage.
|
||||
|
||||
.SH REPORTING BUGS
|
||||
Report bugs to <dns-team@nlnetlabs.nl>.
|
||||
|
||||
.SH COPYRIGHT
|
||||
Copyright (C) 2005 NLnet Labs. This is free software. There is NO
|
||||
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR
|
||||
PURPOSE.
|
||||
205
zonemaster-ldns/ldns/examples/ldns-key2ds.c
Normal file
205
zonemaster-ldns/ldns/examples/ldns-key2ds.c
Normal file
@@ -0,0 +1,205 @@
|
||||
/*
|
||||
* key2ds transforms a public key into its DS
|
||||
* It (currently) prints out the public key
|
||||
*
|
||||
* (c) NLnet Labs, 2005 - 2008
|
||||
* See the file LICENSE for the license
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include <ldns/ldns.h>
|
||||
|
||||
#include <errno.h>
|
||||
|
||||
static void
|
||||
usage(FILE *fp, char *prog) {
|
||||
fprintf(fp, "%s [-fn] [-1|-2] keyfile\n", prog);
|
||||
fprintf(fp, " Generate a DS RR from the DNSKEYS in keyfile\n");
|
||||
fprintf(fp, " The following file will be created: ");
|
||||
fprintf(fp, "K<name>+<alg>+<id>.ds\n");
|
||||
fprintf(fp, " The base name (K<name>+<alg>+<id> will be printed to stdout\n");
|
||||
fprintf(fp, "Options:\n");
|
||||
fprintf(fp, " -f: ignore SEP flag (i.e. make DS records for any key)\n");
|
||||
fprintf(fp, " -n: do not write DS records to file(s) but to stdout\n");
|
||||
fprintf(fp, " (default) use similar hash to the key algorithm.\n");
|
||||
fprintf(fp, " -1: use SHA1 for the DS hash\n");
|
||||
fprintf(fp, " -2: use SHA256 for the DS hash\n");
|
||||
#ifdef USE_GOST
|
||||
fprintf(fp, " -g: use GOST for the DS hash\n");
|
||||
#endif
|
||||
#ifdef USE_ECDSA
|
||||
fprintf(fp, " -4: use SHA384 for the DS hash\n");
|
||||
#endif
|
||||
}
|
||||
|
||||
static int
|
||||
is_suitable_dnskey(ldns_rr *rr, int sep_only)
|
||||
{
|
||||
if (!rr || ldns_rr_get_type(rr) != LDNS_RR_TYPE_DNSKEY) {
|
||||
return 0;
|
||||
}
|
||||
return !sep_only ||
|
||||
(ldns_rdf2native_int16(ldns_rr_dnskey_flags(rr)) &
|
||||
LDNS_KEY_SEP_KEY);
|
||||
}
|
||||
|
||||
static ldns_hash
|
||||
suitable_hash(ldns_signing_algorithm algorithm)
|
||||
{
|
||||
switch (algorithm) {
|
||||
case LDNS_SIGN_RSASHA256:
|
||||
case LDNS_SIGN_RSASHA512:
|
||||
return LDNS_SHA256;
|
||||
case LDNS_SIGN_ECC_GOST:
|
||||
#ifdef USE_GOST
|
||||
return LDNS_HASH_GOST;
|
||||
#else
|
||||
return LDNS_SHA256;
|
||||
#endif
|
||||
#ifdef USE_ECDSA
|
||||
case LDNS_SIGN_ECDSAP256SHA256:
|
||||
return LDNS_SHA256;
|
||||
case LDNS_SIGN_ECDSAP384SHA384:
|
||||
return LDNS_SHA384;
|
||||
#endif
|
||||
#ifdef USE_ED25519
|
||||
case LDNS_SIGN_ED25519:
|
||||
return LDNS_SHA256;
|
||||
#endif
|
||||
#ifdef USE_ED448
|
||||
case LDNS_SIGN_ED448:
|
||||
return LDNS_SHA256;
|
||||
#endif
|
||||
default: break;
|
||||
}
|
||||
return LDNS_SHA1;
|
||||
}
|
||||
|
||||
int
|
||||
main(int argc, char *argv[])
|
||||
{
|
||||
FILE *keyfp, *dsfp;
|
||||
char *keyname;
|
||||
char *dsname;
|
||||
char *owner;
|
||||
ldns_rr *k, *ds;
|
||||
ldns_signing_algorithm alg;
|
||||
ldns_hash h;
|
||||
int similar_hash=1;
|
||||
char *program = argv[0];
|
||||
int nofile = 0;
|
||||
ldns_rdf *origin = NULL;
|
||||
ldns_status result = LDNS_STATUS_OK;
|
||||
int sep_only = 1;
|
||||
|
||||
h = LDNS_SHA1;
|
||||
|
||||
argv++, argc--;
|
||||
while (argc && argv[0][0] == '-') {
|
||||
if (strcmp(argv[0], "-1") == 0) {
|
||||
h = LDNS_SHA1;
|
||||
similar_hash = 0;
|
||||
}
|
||||
if (strcmp(argv[0], "-2") == 0) {
|
||||
h = LDNS_SHA256;
|
||||
similar_hash = 0;
|
||||
}
|
||||
#ifdef USE_GOST
|
||||
if (strcmp(argv[0], "-g") == 0) {
|
||||
if(!ldns_key_EVP_load_gost_id()) {
|
||||
fprintf(stderr, "error: libcrypto does not provide GOST\n");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
h = LDNS_HASH_GOST;
|
||||
similar_hash = 0;
|
||||
}
|
||||
#endif
|
||||
#ifdef USE_ECDSA
|
||||
if (strcmp(argv[0], "-4") == 0) {
|
||||
h = LDNS_SHA384;
|
||||
similar_hash = 0;
|
||||
}
|
||||
#endif
|
||||
if (strcmp(argv[0], "-f") == 0) {
|
||||
sep_only = 0;
|
||||
}
|
||||
if (strcmp(argv[0], "-n") == 0) {
|
||||
nofile=1;
|
||||
}
|
||||
argv++, argc--;
|
||||
}
|
||||
|
||||
if (argc != 1) {
|
||||
usage(stderr, program);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
keyname = strdup(argv[0]);
|
||||
|
||||
keyfp = fopen(keyname, "r");
|
||||
if (!keyfp) {
|
||||
fprintf(stderr, "Failed to open public key file %s: %s\n", keyname,
|
||||
strerror(errno));
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
while (result == LDNS_STATUS_OK) {
|
||||
result = ldns_rr_new_frm_fp(&k, keyfp, 0, &origin, NULL);
|
||||
while (result == LDNS_STATUS_SYNTAX_ORIGIN ||
|
||||
result == LDNS_STATUS_SYNTAX_TTL ||
|
||||
(result == LDNS_STATUS_OK && !is_suitable_dnskey(k, sep_only))
|
||||
) {
|
||||
if (result == LDNS_STATUS_OK) {
|
||||
ldns_rr_free(k);
|
||||
}
|
||||
result = ldns_rr_new_frm_fp(&k, keyfp, 0, &origin, NULL);
|
||||
}
|
||||
if (result == LDNS_STATUS_SYNTAX_EMPTY) {
|
||||
/* we're done */
|
||||
break;
|
||||
}
|
||||
if (result != LDNS_STATUS_OK) {
|
||||
fprintf(stderr, "Could not read public key from file %s: %s\n", keyname, ldns_get_errorstr_by_id(result));
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
owner = ldns_rdf2str(ldns_rr_owner(k));
|
||||
alg = ldns_rdf2native_int8(ldns_rr_dnskey_algorithm(k));
|
||||
if(similar_hash)
|
||||
h = suitable_hash(alg);
|
||||
|
||||
ds = ldns_key_rr2ds(k, h);
|
||||
if (!ds) {
|
||||
fprintf(stderr, "Conversion to a DS RR failed\n");
|
||||
ldns_rr_free(k);
|
||||
free(owner);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
/* print the public key RR to .key */
|
||||
dsname = LDNS_XMALLOC(char, strlen(owner) + 16);
|
||||
snprintf(dsname, strlen(owner) + 15, "K%s+%03u+%05u.ds", owner, alg, (unsigned int) ldns_calc_keytag(k));
|
||||
|
||||
if (nofile)
|
||||
ldns_rr_print(stdout,ds);
|
||||
else {
|
||||
dsfp = fopen(dsname, "w");
|
||||
if (!dsfp) {
|
||||
fprintf(stderr, "Unable to open %s: %s\n", dsname, strerror(errno));
|
||||
exit(EXIT_FAILURE);
|
||||
} else {
|
||||
ldns_rr_print(dsfp, ds);
|
||||
fclose(dsfp);
|
||||
fprintf(stdout, "K%s+%03u+%05u\n", owner, alg, (unsigned int) ldns_calc_keytag(k));
|
||||
}
|
||||
}
|
||||
|
||||
ldns_rr_free(ds);
|
||||
ldns_rr_free(k);
|
||||
free(owner);
|
||||
LDNS_FREE(dsname);
|
||||
}
|
||||
fclose(keyfp);
|
||||
free(keyname);
|
||||
exit(EXIT_SUCCESS);
|
||||
}
|
||||
64
zonemaster-ldns/ldns/examples/ldns-keyfetcher.1
Normal file
64
zonemaster-ldns/ldns/examples/ldns-keyfetcher.1
Normal file
@@ -0,0 +1,64 @@
|
||||
.TH ldns-keyfetcher 1 "4 Apr 2006"
|
||||
.SH NAME
|
||||
ldns-keyfetcher \- retrieve the DNSSEC DNSKEYs for a zone
|
||||
.SH SYNOPSIS
|
||||
.B ldns-keyfetcher
|
||||
[
|
||||
.IR OPTIONS
|
||||
]
|
||||
.IR DOMAIN
|
||||
|
||||
.SH DESCRIPTION
|
||||
\fBldns-keyfetcher\fR is used to retrieve the DNSKEYs of a zone.
|
||||
|
||||
First it finds all authoritative nameservers of the zone by tracing it from
|
||||
the root down. All authoritative nameservers are then queried (using TCP)
|
||||
for the DNSKEY RRset of the zone apex. If the results are all the same,
|
||||
the key resource record set is printed.
|
||||
|
||||
|
||||
.SH OPTIONS
|
||||
\fB-4\fR \fI\fR
|
||||
Only use IPv4
|
||||
|
||||
\fB-6\fR \fI\fR
|
||||
Only use IPv6
|
||||
|
||||
\fB-h\fR \fI\fR
|
||||
Show a help text and exit
|
||||
|
||||
\fB-i\fR
|
||||
Insecurer mode; there will only be one query for the DNSKEYS. There will not
|
||||
be crosschecking of all authoritative nameservers.
|
||||
|
||||
\fB-v\fR \fIverbosity\fR
|
||||
|
||||
Set the verbosity level. The following levels are available:
|
||||
|
||||
0: default, only print the DNSKEY RRset found, or an error on failure.
|
||||
1: Show the nameservers that are queried
|
||||
2: Show more info on what is checked
|
||||
3: Show the intermediate results (authority and dnskey rrsets)
|
||||
4: Print the answer packets that are returned
|
||||
|
||||
\fB-r\fR \fIfile\fR
|
||||
|
||||
Use file as the root hints file, should contain A records in presentation
|
||||
format. The default is /etc/named.root. You can get this file from
|
||||
http://www.internic.net/zones/named.root.
|
||||
|
||||
\fB-s\fR \fI\fR
|
||||
Don't print the keys to stdout, but store them in files.
|
||||
|
||||
The filenames will be of the format K<file>.+<alg>.+<keytag>.key
|
||||
|
||||
.SH AUTHOR
|
||||
Written by Jelte Jansen for NLnet Labs.
|
||||
|
||||
.SH REPORTING BUGS
|
||||
Report bugs to <dns-team@nlnetlabs.nl>.
|
||||
|
||||
.SH COPYRIGHT
|
||||
Copyright (C) 2006 NLnet Labs. This is free software. There is NO
|
||||
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR
|
||||
PURPOSE.
|
||||
737
zonemaster-ldns/ldns/examples/ldns-keyfetcher.c
Normal file
737
zonemaster-ldns/ldns/examples/ldns-keyfetcher.c
Normal file
@@ -0,0 +1,737 @@
|
||||
/*
|
||||
* ldns-keyfetcher retrieves the DNSKEYS for a certain domain
|
||||
* It traces the authoritative nameservers down from the root
|
||||
* And uses TCP, to minimize spoofing danger.
|
||||
*
|
||||
* (c) NLnet Labs, 2006 - 2008
|
||||
* See the file LICENSE for the license
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
#include <ldns/ldns.h>
|
||||
#include <errno.h>
|
||||
|
||||
int verbosity = 0;
|
||||
/* 0=use both ip4 and ip6 (default). 1=ip4only. 2=ip6only. */
|
||||
uint8_t address_family = 0;
|
||||
bool store_in_file = false;
|
||||
|
||||
static void
|
||||
usage(FILE *fp, char *prog) {
|
||||
fprintf(fp, "%s domain\n", prog);
|
||||
fprintf(fp, " retrieve the dnskeys for a domain\n");
|
||||
fprintf(fp, "Options:\n");
|
||||
fprintf(fp, "-4\t\tUse IPv4 only\n");
|
||||
fprintf(fp, "-6\t\tUse IPv6 only\n");
|
||||
fprintf(fp, "-h\t\tShow this help\n");
|
||||
fprintf(fp, "-i\t\tInsecurer mode; don't do checks, just query for the keys\n");
|
||||
fprintf(fp, "-r <file>\tUse file to read root hints from\n");
|
||||
fprintf(fp, "-s\t\tDon't print the keys but store them in files\n\t\tcalled K<file>.+<alg>.+<keytag>.key\n");
|
||||
fprintf(fp, "-v <int>\tVerbosity level (0-5, not verbose-very verbose)\n");
|
||||
}
|
||||
|
||||
static ldns_rr_list *
|
||||
retrieve_dnskeys(ldns_resolver *local_res, ldns_rdf *name, ldns_rr_type t,
|
||||
ldns_rr_class c, ldns_rr_list *dns_root)
|
||||
{
|
||||
ldns_resolver *res;
|
||||
ldns_pkt *p;
|
||||
ldns_rr_list *new_nss_a;
|
||||
ldns_rr_list *new_nss_aaaa;
|
||||
ldns_rr_list *new_nss;
|
||||
ldns_rr_list *ns_addr;
|
||||
ldns_rr_list *ns_addr2;
|
||||
uint16_t loop_count;
|
||||
ldns_rdf *pop;
|
||||
ldns_status status;
|
||||
size_t i;
|
||||
|
||||
size_t nss_i;
|
||||
ldns_rr_list *answer_list = NULL;
|
||||
ldns_rr_list *authority_list = NULL;
|
||||
|
||||
size_t last_nameserver_count;
|
||||
ldns_rdf **last_nameservers;
|
||||
|
||||
loop_count = 0;
|
||||
new_nss_a = NULL;
|
||||
new_nss_aaaa = NULL;
|
||||
new_nss = NULL;
|
||||
ns_addr = NULL;
|
||||
ns_addr2 = NULL;
|
||||
p = ldns_pkt_new();
|
||||
res = ldns_resolver_new();
|
||||
|
||||
if (!p || !res) {
|
||||
fprintf(stderr, "Memory allocation failed");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (verbosity >= 2) {
|
||||
printf("Finding dnskey data for zone: ");
|
||||
ldns_rdf_print(stdout, name);
|
||||
printf("\n\n");
|
||||
}
|
||||
|
||||
/* transfer some properties of local_res to res,
|
||||
* because they were given on the command line */
|
||||
ldns_resolver_set_ip6(res,
|
||||
ldns_resolver_ip6(local_res));
|
||||
ldns_resolver_set_port(res,
|
||||
ldns_resolver_port(local_res));
|
||||
ldns_resolver_set_debug(res,
|
||||
ldns_resolver_debug(local_res));
|
||||
ldns_resolver_set_dnssec(res,
|
||||
ldns_resolver_dnssec(local_res));
|
||||
ldns_resolver_set_fail(res,
|
||||
ldns_resolver_fail(local_res));
|
||||
ldns_resolver_set_usevc(res,
|
||||
ldns_resolver_usevc(local_res));
|
||||
ldns_resolver_set_random(res,
|
||||
ldns_resolver_random(local_res));
|
||||
ldns_resolver_set_recursive(res, false);
|
||||
|
||||
/* setup the root nameserver in the new resolver */
|
||||
status = ldns_resolver_push_nameserver_rr_list(res, dns_root);
|
||||
if (status != LDNS_STATUS_OK) {
|
||||
fprintf(stderr, "Error setting root nameservers in resolver: %s\n", ldns_get_errorstr_by_id(status));
|
||||
return NULL;
|
||||
}
|
||||
|
||||
ldns_pkt_free(p);
|
||||
status = ldns_resolver_send(&p, res, name, t, c, 0);
|
||||
if (status != LDNS_STATUS_OK) {
|
||||
fprintf(stderr, "Error querying root servers: %s\n", ldns_get_errorstr_by_id(status));
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (ldns_pkt_get_rcode(p) != LDNS_RCODE_NOERROR) {
|
||||
printf("Error in packet:\n");
|
||||
ldns_pkt_print(stdout, p);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (verbosity >= 4) {
|
||||
ldns_pkt_print(stdout, p);
|
||||
printf("\n\n");
|
||||
}
|
||||
|
||||
/* from now on, use TCP */
|
||||
ldns_resolver_set_usevc(res, true);
|
||||
|
||||
while(status == LDNS_STATUS_OK &&
|
||||
ldns_pkt_reply_type(p) == LDNS_PACKET_REFERRAL) {
|
||||
|
||||
if (verbosity >= 3) {
|
||||
printf("This is a delegation!\n\n");
|
||||
}
|
||||
if (address_family == 0 || address_family == 1) {
|
||||
new_nss_a = ldns_pkt_rr_list_by_type(p,
|
||||
LDNS_RR_TYPE_A, LDNS_SECTION_ADDITIONAL);
|
||||
} else {
|
||||
new_nss_a = ldns_rr_list_new();
|
||||
}
|
||||
if (address_family == 0 || address_family == 2) {
|
||||
new_nss_aaaa = ldns_pkt_rr_list_by_type(p,
|
||||
LDNS_RR_TYPE_AAAA, LDNS_SECTION_ADDITIONAL);
|
||||
} else {
|
||||
new_nss_aaaa = ldns_rr_list_new();
|
||||
}
|
||||
new_nss = ldns_pkt_rr_list_by_type(p,
|
||||
LDNS_RR_TYPE_NS, LDNS_SECTION_AUTHORITY);
|
||||
|
||||
/* remove the old nameserver from the resolver */
|
||||
while((pop = ldns_resolver_pop_nameserver(res))) { ldns_rdf_deep_free(pop); }
|
||||
|
||||
/* also check for new_nss emptiness */
|
||||
|
||||
if (!new_nss_aaaa && !new_nss_a) {
|
||||
/*
|
||||
* no nameserver found!!!
|
||||
* try to resolve the names we do got
|
||||
*/
|
||||
if (verbosity >= 3) {
|
||||
printf("Did not get address record for nameserver, doing separate query.\n");
|
||||
}
|
||||
ns_addr = ldns_rr_list_new();
|
||||
for(i = 0; (size_t) i < ldns_rr_list_rr_count(new_nss); i++) {
|
||||
/* get the name of the nameserver */
|
||||
pop = ldns_rr_rdf(ldns_rr_list_rr(new_nss, i), 0);
|
||||
if (!pop) {
|
||||
break;
|
||||
}
|
||||
|
||||
/* retrieve it's addresses */
|
||||
ns_addr2 = ldns_get_rr_list_addr_by_name(local_res, pop, c, 0);
|
||||
if (!ldns_rr_list_cat(ns_addr, ns_addr2)) {
|
||||
fprintf(stderr, "Internal error adding nameserver address.\n");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
ldns_rr_list_free(ns_addr2);
|
||||
}
|
||||
|
||||
if (ns_addr) {
|
||||
if (ldns_resolver_push_nameserver_rr_list(res, ns_addr) !=
|
||||
LDNS_STATUS_OK) {
|
||||
fprintf(stderr, "Error adding new nameservers");
|
||||
ldns_pkt_free(p);
|
||||
return NULL;
|
||||
}
|
||||
ldns_rr_list_deep_free(ns_addr);
|
||||
} else {
|
||||
ldns_rr_list_print(stdout, ns_addr);
|
||||
fprintf(stderr, "Could not find the nameserver ip addr; abort");
|
||||
ldns_pkt_free(p);
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
/* normally, the first working ns is used, but we need all now, so do it one by one
|
||||
* if the answer is null, take it from the next resolver
|
||||
* if the answer is not, compare it to that of the next resolver
|
||||
* error if different, continue if the same
|
||||
* if answer list null and no resolvers left die.
|
||||
*/
|
||||
|
||||
ldns_rr_list_deep_free(answer_list);
|
||||
ldns_rr_list_deep_free(authority_list);
|
||||
answer_list = NULL;
|
||||
authority_list = NULL;
|
||||
for (nss_i = 0; nss_i < ldns_rr_list_rr_count(new_nss_aaaa); nss_i++) {
|
||||
while((pop = ldns_resolver_pop_nameserver(res))) { ldns_rdf_deep_free(pop); }
|
||||
|
||||
status = ldns_resolver_push_nameserver(res, ldns_rr_rdf(ldns_rr_list_rr(new_nss_aaaa, nss_i), 0));
|
||||
if (status != LDNS_STATUS_OK) {
|
||||
fprintf(stderr, "Error adding nameserver to resolver: %s\n", ldns_get_errorstr_by_id(status));
|
||||
}
|
||||
|
||||
if (verbosity >= 1) {
|
||||
fprintf(stdout, "Querying nameserver: ");
|
||||
ldns_rdf_print(stdout, ldns_rr_owner(ldns_rr_list_rr(new_nss_aaaa, nss_i)));
|
||||
fprintf(stdout, " (");
|
||||
ldns_rdf_print(stdout, ldns_rr_rdf(ldns_rr_list_rr(new_nss_aaaa, nss_i), 0));
|
||||
fprintf(stdout, ")\n");
|
||||
}
|
||||
status = ldns_resolver_push_nameserver(res, ldns_rr_rdf(ldns_rr_list_rr(new_nss_aaaa, nss_i), 0));
|
||||
if (status != LDNS_STATUS_OK) {
|
||||
fprintf(stderr, "Error adding nameserver to resolver: %s\n", ldns_get_errorstr_by_id(status));
|
||||
}
|
||||
|
||||
ldns_pkt_free(p);
|
||||
status = ldns_resolver_send(&p, res, name, t, c, 0);
|
||||
if (status == LDNS_STATUS_OK && p) {
|
||||
if (ldns_pkt_get_rcode(p) != LDNS_RCODE_NOERROR) {
|
||||
printf("Error in packet:\n");
|
||||
ldns_pkt_print(stdout, p);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (verbosity >= 4) {
|
||||
ldns_pkt_print(stdout, p);
|
||||
printf("\n\n");
|
||||
}
|
||||
|
||||
if (answer_list) {
|
||||
if (verbosity >= 2) {
|
||||
printf("Comparing answer list of answer to previous\n\n");
|
||||
}
|
||||
ldns_rr_list_sort(ldns_pkt_answer(p));
|
||||
ldns_rr_list_sort(answer_list);
|
||||
if (ldns_rr_list_compare(answer_list, ldns_pkt_answer(p)) != 0) {
|
||||
fprintf(stderr, "ERROR: different answer answer from nameserver\n");
|
||||
fprintf(stderr, "\nI had (from previous servers):\n");
|
||||
ldns_rr_list_print(stderr, answer_list);
|
||||
fprintf(stderr, "\nI received (from nameserver at ");
|
||||
ldns_rdf_print(stderr, ldns_resolver_nameservers(res)[0]);
|
||||
fprintf(stderr, "):\n");
|
||||
ldns_rr_list_print(stderr, ldns_pkt_answer(p));
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
} else {
|
||||
answer_list = ldns_rr_list_clone(ldns_pkt_answer(p));
|
||||
ldns_rr_list_sort(answer_list);
|
||||
if (verbosity >= 2) {
|
||||
printf("First answer list for this set, nothing to compare with\n\n");
|
||||
}
|
||||
}
|
||||
if (authority_list) {
|
||||
if (verbosity >= 2) {
|
||||
printf("Comparing authority list of answer to previous\n\n");
|
||||
}
|
||||
ldns_rr_list_sort(ldns_pkt_authority(p));
|
||||
ldns_rr_list_sort(authority_list);
|
||||
if (ldns_rr_list_compare(authority_list, ldns_pkt_authority(p)) != 0) {
|
||||
fprintf(stderr, "ERROR: different authority answer from nameserver\n");
|
||||
fprintf(stderr, "\nI had (from previous servers):\n");
|
||||
ldns_rr_list_print(stderr, authority_list);
|
||||
fprintf(stderr, "\nI received (from nameserver at ");
|
||||
ldns_rdf_print(stderr, ldns_resolver_nameservers(res)[0]);
|
||||
fprintf(stderr, "):\n");
|
||||
ldns_rr_list_print(stderr, ldns_pkt_authority(p));
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
} else {
|
||||
authority_list = ldns_rr_list_clone(ldns_pkt_authority(p));
|
||||
ldns_rr_list_sort(authority_list);
|
||||
if (verbosity >= 2) {
|
||||
printf("First authority list for this set, nothing to compare with\n\n");
|
||||
}
|
||||
if (verbosity >= 3) {
|
||||
printf("NS RRset:\n");
|
||||
ldns_rr_list_print(stdout, authority_list);
|
||||
printf("\n");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ldns_rr_list_deep_free(answer_list);
|
||||
ldns_rr_list_deep_free(authority_list);
|
||||
answer_list = NULL;
|
||||
authority_list = NULL;
|
||||
for (nss_i = 0; nss_i < ldns_rr_list_rr_count(new_nss_a); nss_i++) {
|
||||
|
||||
while((pop = ldns_resolver_pop_nameserver(res))) {ldns_rdf_deep_free(pop); }
|
||||
|
||||
if (verbosity >= 1) {
|
||||
fprintf(stdout, "Querying nameserver: ");
|
||||
ldns_rdf_print(stdout, ldns_rr_owner(ldns_rr_list_rr(new_nss_a, nss_i)));
|
||||
fprintf(stdout, " (");
|
||||
ldns_rdf_print(stdout, ldns_rr_rdf(ldns_rr_list_rr(new_nss_a, nss_i), 0));
|
||||
fprintf(stdout, ")\n");
|
||||
}
|
||||
status = ldns_resolver_push_nameserver(res, ldns_rr_rdf(ldns_rr_list_rr(new_nss_a, nss_i), 0));
|
||||
if (status != LDNS_STATUS_OK) {
|
||||
fprintf(stderr, "Error adding nameserver to resolver: %s\n", ldns_get_errorstr_by_id(status));
|
||||
}
|
||||
|
||||
ldns_pkt_free(p);
|
||||
status = ldns_resolver_send(&p, res, name, t, c, 0);
|
||||
|
||||
if (status == LDNS_STATUS_OK) {
|
||||
if (ldns_pkt_get_rcode(p) != LDNS_RCODE_NOERROR) {
|
||||
printf("Error in packet:\n");
|
||||
ldns_pkt_print(stdout, p);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (verbosity >= 4) {
|
||||
ldns_pkt_print(stdout, p);
|
||||
printf("\n\n");
|
||||
}
|
||||
|
||||
if (answer_list) {
|
||||
if (verbosity >= 2) {
|
||||
printf("Comparing answer list of answer to previous\n\n");
|
||||
}
|
||||
ldns_rr_list_sort(ldns_pkt_answer(p));
|
||||
ldns_rr_list_sort(answer_list);
|
||||
if (ldns_rr_list_compare(answer_list, ldns_pkt_answer(p)) != 0) {
|
||||
fprintf(stderr, "ERROR: different answer answer from nameserver\n");
|
||||
fprintf(stderr, "\nI had (from previous servers):\n");
|
||||
ldns_rr_list_print(stderr, answer_list);
|
||||
fprintf(stderr, "\nI received (from nameserver at ");
|
||||
ldns_rdf_print(stderr, ldns_resolver_nameservers(res)[0]);
|
||||
fprintf(stderr, "):\n");
|
||||
ldns_rr_list_print(stderr, ldns_pkt_answer(p));
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
} else {
|
||||
if (verbosity >= 2) {
|
||||
printf("First answer list for this set, nothing to compare with\n\n");
|
||||
}
|
||||
answer_list = ldns_rr_list_clone(ldns_pkt_answer(p));
|
||||
ldns_rr_list_sort(answer_list);
|
||||
}
|
||||
if (authority_list) {
|
||||
if (verbosity >= 2) {
|
||||
printf("Comparing authority list of answer to previous\n\n");
|
||||
}
|
||||
ldns_rr_list_sort(ldns_pkt_authority(p));
|
||||
ldns_rr_list_sort(authority_list);
|
||||
if (ldns_rr_list_compare(authority_list, ldns_pkt_authority(p)) != 0) {
|
||||
fprintf(stderr, "ERROR: different authority answer from nameserver\n");
|
||||
fprintf(stderr, "\nI had (from previous servers):\n");
|
||||
ldns_rr_list_print(stderr, authority_list);
|
||||
fprintf(stderr, "\nI received (from nameserver at ");
|
||||
ldns_rdf_print(stderr, ldns_resolver_nameservers(res)[0]);
|
||||
fprintf(stderr, "):\n");
|
||||
ldns_rr_list_print(stderr, ldns_pkt_authority(p));
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
} else {
|
||||
if (verbosity >= 2) {
|
||||
printf("First authority list for this set, nothing to compare with\n\n");
|
||||
}
|
||||
authority_list = ldns_rr_list_clone(ldns_pkt_authority(p));
|
||||
ldns_rr_list_sort(authority_list);
|
||||
if (verbosity >= 3) {
|
||||
printf("NS RRset:\n");
|
||||
ldns_rr_list_print(stdout, authority_list);
|
||||
printf("\n");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
ldns_rr_list_deep_free(authority_list);
|
||||
authority_list = NULL;
|
||||
|
||||
if (loop_count++ > 20) {
|
||||
/* unlikely that we are doing something useful */
|
||||
fprintf(stderr, "Looks like we are looping");
|
||||
ldns_pkt_free(p);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
ldns_pkt_free(p);
|
||||
|
||||
if (verbosity >= 3) {
|
||||
fprintf(stdout, "This level ok. Continuing to next.\n\n");
|
||||
}
|
||||
|
||||
status = ldns_resolver_send(&p, res, name, t, c, 0);
|
||||
|
||||
if (status != LDNS_STATUS_OK) {
|
||||
fprintf(stderr, "Error querying root servers: %s\n", ldns_get_errorstr_by_id(status));
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (ldns_pkt_get_rcode(p) != LDNS_RCODE_NOERROR) {
|
||||
printf("Error in packet:\n");
|
||||
ldns_pkt_print(stdout, p);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (verbosity >= 4) {
|
||||
ldns_pkt_print(stdout, p);
|
||||
printf("\n\n");
|
||||
}
|
||||
|
||||
|
||||
ldns_rr_list_deep_free(new_nss_aaaa);
|
||||
ldns_rr_list_deep_free(new_nss_a);
|
||||
ldns_rr_list_deep_free(new_nss);
|
||||
new_nss_aaaa = NULL;
|
||||
new_nss_a = NULL;
|
||||
ns_addr = NULL;
|
||||
}
|
||||
|
||||
ldns_rr_list_deep_free(answer_list);
|
||||
answer_list = NULL;
|
||||
/* clone the nameserver list, we are going to handle them one by one */
|
||||
last_nameserver_count = 0;
|
||||
last_nameservers = LDNS_XMALLOC(ldns_rdf *, ldns_resolver_nameserver_count(res));
|
||||
|
||||
pop = NULL;
|
||||
while((pop = ldns_resolver_pop_nameserver(res))) {
|
||||
last_nameservers[last_nameserver_count] = pop;
|
||||
last_nameserver_count++;
|
||||
}
|
||||
|
||||
for (nss_i = 0; nss_i < last_nameserver_count; nss_i++) {
|
||||
/* remove previous nameserver */
|
||||
while((pop = ldns_resolver_pop_nameserver(res))) { ldns_rdf_deep_free(pop); }
|
||||
|
||||
if (verbosity >= 1) {
|
||||
printf("Querying nameserver: ");
|
||||
ldns_rdf_print(stdout, last_nameservers[nss_i]);
|
||||
printf("\n");
|
||||
}
|
||||
status = ldns_resolver_push_nameserver(res, last_nameservers[nss_i]);
|
||||
if (status != LDNS_STATUS_OK) {
|
||||
fprintf(stderr, "Error adding nameserver to resolver: %s\n", ldns_get_errorstr_by_id(status));
|
||||
}
|
||||
|
||||
ldns_pkt_free(p);
|
||||
status = ldns_resolver_send(&p, res, name, t, c, 0);
|
||||
|
||||
if (!p) {
|
||||
fprintf(stderr, "no packet received\n");
|
||||
LDNS_FREE(last_nameservers);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (status == LDNS_STATUS_RES_NO_NS) {
|
||||
fprintf(stderr, "Error: nameserver at ");
|
||||
ldns_rdf_print(stderr, last_nameservers[nss_i]);
|
||||
fprintf(stderr, " not responding. Unable to check RRset here, aborting.\n");
|
||||
LDNS_FREE(last_nameservers);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (ldns_pkt_get_rcode(p) != LDNS_RCODE_NOERROR) {
|
||||
printf("Error in packet:\n");
|
||||
ldns_pkt_print(stdout, p);
|
||||
LDNS_FREE(last_nameservers);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (answer_list) {
|
||||
if (verbosity >= 2) {
|
||||
printf("1Comparing answer rr list of answer to previous\n");
|
||||
}
|
||||
ldns_rr_list_sort(ldns_pkt_answer(p));
|
||||
ldns_rr_list_sort(answer_list);
|
||||
if (ldns_rr_list_compare(answer_list, ldns_pkt_answer(p)) != 0) {
|
||||
printf("ERROR: different answer section in response from nameserver\n");
|
||||
fprintf(stderr, "\nI had:\n");
|
||||
ldns_rr_list_print(stderr, answer_list);
|
||||
fprintf(stderr, "\nI received (from nameserver at ");
|
||||
ldns_rdf_print(stderr, ldns_resolver_nameservers(res)[0]);
|
||||
fprintf(stderr, "):\n");
|
||||
ldns_rr_list_print(stderr, ldns_pkt_answer(p));
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
} else {
|
||||
if (verbosity >= 2) {
|
||||
printf("First answer rr list for this set, nothing to compare with\n");
|
||||
}
|
||||
answer_list = ldns_rr_list_clone(ldns_pkt_answer(p));
|
||||
if (verbosity >= 3) {
|
||||
printf("DNSKEY RRset:\n");
|
||||
ldns_rr_list_print(stdout, answer_list);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
for (nss_i = 0; nss_i < last_nameserver_count; nss_i++) {
|
||||
ldns_rdf_deep_free(last_nameservers[nss_i]);
|
||||
}
|
||||
LDNS_FREE(last_nameservers);
|
||||
ldns_resolver_deep_free(res);
|
||||
ldns_pkt_free(p);
|
||||
return answer_list;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* The file with the given path should contain a list of NS RRs
|
||||
* for the root zone and A records for those NS RRs.
|
||||
* Read them, check them, and append the a records to the rr list given.
|
||||
*/
|
||||
static ldns_rr_list *
|
||||
read_root_hints(const char *filename)
|
||||
{
|
||||
FILE *fp = NULL;
|
||||
int line_nr = 0;
|
||||
ldns_zone *z;
|
||||
ldns_status status;
|
||||
ldns_rr_list *addresses = NULL;
|
||||
ldns_rr *rr;
|
||||
size_t i;
|
||||
|
||||
fp = fopen(filename, "r");
|
||||
if (!fp) {
|
||||
fprintf(stderr, "Unable to open %s for reading: %s\n", filename, strerror(errno));
|
||||
return NULL;
|
||||
}
|
||||
|
||||
status = ldns_zone_new_frm_fp_l(&z, fp, NULL, 0, 0, &line_nr);
|
||||
fclose(fp);
|
||||
if (status != LDNS_STATUS_OK) {
|
||||
fprintf(stderr, "Error reading root hints file: %s\n", ldns_get_errorstr_by_id(status));
|
||||
return NULL;
|
||||
} else {
|
||||
addresses = ldns_rr_list_new();
|
||||
for (i = 0; i < ldns_rr_list_rr_count(ldns_zone_rrs(z)); i++) {
|
||||
rr = ldns_rr_list_rr(ldns_zone_rrs(z), i);
|
||||
if ((address_family == 0 || address_family == 1) &&
|
||||
ldns_rr_get_type(rr) == LDNS_RR_TYPE_A ) {
|
||||
ldns_rr_list_push_rr(addresses, ldns_rr_clone(rr));
|
||||
}
|
||||
if ((address_family == 0 || address_family == 2) &&
|
||||
ldns_rr_get_type(rr) == LDNS_RR_TYPE_AAAA) {
|
||||
ldns_rr_list_push_rr(addresses, ldns_rr_clone(rr));
|
||||
}
|
||||
}
|
||||
ldns_zone_deep_free(z);
|
||||
return addresses;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
main(int argc, char *argv[])
|
||||
{
|
||||
ldns_resolver *res;
|
||||
ldns_rdf *ns;
|
||||
ldns_rdf *domain;
|
||||
ldns_rr_list *l = NULL;
|
||||
|
||||
ldns_rr_list *dns_root = NULL;
|
||||
const char *root_file = "/etc/named.root";
|
||||
|
||||
ldns_status status;
|
||||
|
||||
int i;
|
||||
|
||||
char *domain_str;
|
||||
char *outputfile_str;
|
||||
ldns_buffer *outputfile_buffer;
|
||||
FILE *outputfile;
|
||||
ldns_rr *k;
|
||||
|
||||
bool insecure = false;
|
||||
ldns_pkt *pkt;
|
||||
|
||||
domain = NULL;
|
||||
res = NULL;
|
||||
|
||||
if (argc < 2) {
|
||||
usage(stdout, argv[0]);
|
||||
exit(EXIT_FAILURE);
|
||||
} else {
|
||||
for (i = 1; i < argc; i++) {
|
||||
if (strncmp("-4", argv[i], 3) == 0) {
|
||||
if (address_family != 0) {
|
||||
fprintf(stderr, "Options -4 and -6 cannot be specified at the same time\n");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
address_family = 1;
|
||||
} else if (strncmp("-6", argv[i], 3) == 0) {
|
||||
if (address_family != 0) {
|
||||
fprintf(stderr, "Options -4 and -6 cannot be specified at the same time\n");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
address_family = 2;
|
||||
} else if (strncmp("-h", argv[i], 3) == 0) {
|
||||
usage(stdout, argv[0]);
|
||||
exit(EXIT_SUCCESS);
|
||||
} else if (strncmp("-i", argv[i], 2) == 0) {
|
||||
insecure = true;
|
||||
} else if (strncmp("-r", argv[i], 2) == 0) {
|
||||
if (strlen(argv[i]) > 2) {
|
||||
root_file = argv[i]+2;
|
||||
} else if (i+1 >= argc) {
|
||||
usage(stdout, argv[0]);
|
||||
exit(EXIT_FAILURE);
|
||||
} else {
|
||||
root_file = argv[i+1];
|
||||
i++;
|
||||
}
|
||||
} else if (strncmp("-s", argv[i], 3) == 0) {
|
||||
store_in_file = true;
|
||||
} else if (strncmp("-v", argv[i], 2) == 0) {
|
||||
if (strlen(argv[i]) > 2) {
|
||||
verbosity = atoi(argv[i]+2);
|
||||
} else if (i+1 > argc) {
|
||||
usage(stdout, argv[0]);
|
||||
exit(EXIT_FAILURE);
|
||||
} else {
|
||||
verbosity = atoi(argv[i+1]);
|
||||
i++;
|
||||
}
|
||||
} else {
|
||||
/* create a rdf from the command line arg */
|
||||
if (domain) {
|
||||
fprintf(stdout, "You can only specify one domain at a time\n");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
domain = ldns_dname_new_frm_str(argv[i]);
|
||||
}
|
||||
|
||||
}
|
||||
if (!domain) {
|
||||
usage(stdout, argv[0]);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
}
|
||||
|
||||
dns_root = read_root_hints(root_file);
|
||||
if (!dns_root) {
|
||||
fprintf(stderr, "cannot read the root hints file\n");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
/* create a new resolver from /etc/resolv.conf */
|
||||
status = ldns_resolver_new_frm_file(&res, NULL);
|
||||
|
||||
if (status != LDNS_STATUS_OK) {
|
||||
fprintf(stderr, "Warning: Unable to create stub resolver from /etc/resolv.conf:\n");
|
||||
fprintf(stderr, "%s\n", ldns_get_errorstr_by_id(status));
|
||||
fprintf(stderr, "defaulting to nameserver at 127.0.0.1 for separate nameserver name lookups\n");
|
||||
do {
|
||||
res = ldns_resolver_new();
|
||||
if (res) {
|
||||
ns = ldns_rdf_new_frm_str(LDNS_RDF_TYPE_A,
|
||||
"127.0.0.1");
|
||||
if (ns) {
|
||||
status = ldns_resolver_push_nameserver(
|
||||
res, ns);
|
||||
if (status == LDNS_STATUS_OK) {
|
||||
break;
|
||||
}
|
||||
ldns_rdf_deep_free(ns);
|
||||
}
|
||||
ldns_resolver_free(res);
|
||||
}
|
||||
fprintf(stderr, "Unable to create stub resolver: %s\n",
|
||||
ldns_get_errorstr_by_id(status));
|
||||
exit(EXIT_FAILURE);
|
||||
|
||||
} while (false);
|
||||
ldns_rdf_deep_free(ns);
|
||||
}
|
||||
|
||||
ldns_resolver_set_ip6(res, address_family);
|
||||
|
||||
if (insecure) {
|
||||
pkt = ldns_resolver_query(res, domain, LDNS_RR_TYPE_DNSKEY, LDNS_RR_CLASS_IN, LDNS_RD);
|
||||
if (pkt) {
|
||||
l = ldns_pkt_rr_list_by_type(pkt, LDNS_RR_TYPE_DNSKEY, LDNS_SECTION_ANY_NOQUESTION);
|
||||
}
|
||||
} else {
|
||||
l = retrieve_dnskeys(res, domain, LDNS_RR_TYPE_DNSKEY, LDNS_RR_CLASS_IN, dns_root);
|
||||
}
|
||||
|
||||
/* separator for result data and verbosity data */
|
||||
if (verbosity > 0) {
|
||||
fprintf(stdout, "; ---------------------------\n");
|
||||
fprintf(stdout, "; Got the following keys:\n");
|
||||
}
|
||||
if (l) {
|
||||
if (store_in_file) {
|
||||
/* create filename:
|
||||
* K<domain>.+<alg>.+<id>.key
|
||||
*/
|
||||
for (i = 0; (size_t) i < ldns_rr_list_rr_count(l); i++) {
|
||||
k = ldns_rr_list_rr(l, (size_t) i);
|
||||
|
||||
outputfile_buffer = ldns_buffer_new(300);
|
||||
domain_str = ldns_rdf2str(ldns_rr_owner(k));
|
||||
ldns_buffer_printf(outputfile_buffer, "K%s+%03u+%05u.key", domain_str, ldns_rdf2native_int8(ldns_rr_rdf(k, 2)),
|
||||
(unsigned int) ldns_calc_keytag(k));
|
||||
outputfile_str = ldns_buffer_export(outputfile_buffer);
|
||||
|
||||
if (verbosity >= 1) {
|
||||
fprintf(stdout, "Writing key to file %s\n", outputfile_str);
|
||||
}
|
||||
|
||||
outputfile = fopen(outputfile_str, "w");
|
||||
if (!outputfile) {
|
||||
fprintf(stderr, "Error writing key to file %s: %s\n", outputfile_str, strerror(errno));
|
||||
} else {
|
||||
ldns_rr_print(outputfile, k);
|
||||
fclose(outputfile);
|
||||
}
|
||||
|
||||
LDNS_FREE(domain_str);
|
||||
LDNS_FREE(outputfile_str);
|
||||
LDNS_FREE(outputfile_buffer);
|
||||
}
|
||||
} else {
|
||||
ldns_rr_list_print(stdout, l);
|
||||
}
|
||||
} else {
|
||||
fprintf(stderr, "no answer packet received, stub resolver config:\n");
|
||||
ldns_resolver_print(stderr, res);
|
||||
}
|
||||
|
||||
ldns_rdf_deep_free(domain);
|
||||
ldns_resolver_deep_free(res);
|
||||
ldns_rr_list_deep_free(l);
|
||||
ldns_rr_list_deep_free(dns_root);
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
69
zonemaster-ldns/ldns/examples/ldns-keygen.1
Normal file
69
zonemaster-ldns/ldns/examples/ldns-keygen.1
Normal file
@@ -0,0 +1,69 @@
|
||||
.TH ldns-keygen 1 "27 May 2008"
|
||||
.SH NAME
|
||||
ldns-keygen \- generate a DNSSEC key pair
|
||||
.SH SYNOPSIS
|
||||
.B ldns-keygen
|
||||
[
|
||||
.IR OPTION
|
||||
]
|
||||
.IR DOMAIN
|
||||
|
||||
.SH DESCRIPTION
|
||||
\fBldns-keygen\fR is used to generate a private/public keypair. When run, it
|
||||
will create 3 files; a .key file with the public DNSKEY, a .private
|
||||
file with the private keydata and a .ds with the DS record of the
|
||||
DNSKEY record.
|
||||
|
||||
\fBldns-keygen\fR can also be used to create symmetric keys (for TSIG) by
|
||||
selecting the appropriate algorithm: \%\fIhmac-md5.sig-alg.reg.int\fR,
|
||||
\%\fIhmac-sha1\fR, \%\fIhmac-sha224\fR, \%\fIhmac-sha256\fR, \%\fIhmac-sha384\fR or \%\fIhmac-sha512\fR.
|
||||
In that case no DS record will be created and no .ds file.
|
||||
|
||||
\fBldns-keygen\fR prints the basename for the key files:
|
||||
K<name>+<alg>+<id>
|
||||
|
||||
.SH OPTIONS
|
||||
.TP
|
||||
\fB-a \fI<algorithm>\fR
|
||||
Create a key with this algorithm. Specifying 'list' here gives a list of supported algorithms.
|
||||
Several alias names are also accepted (from older versions and other software),
|
||||
the list gives names from the RFC. Also the plain algo number is accepted.
|
||||
|
||||
.TP
|
||||
\fB-b \fI<bits>\fR
|
||||
Use this many bits for the key length.
|
||||
|
||||
.TP
|
||||
\fB-k\fR
|
||||
When given, generate a key signing key. This just sets the flag field to
|
||||
257 instead of 256 in the DNSKEY RR in the .key file.
|
||||
|
||||
.TP
|
||||
\fB-r \fIdevice\fR
|
||||
Make ldns-keygen use this file to seed the random generator with. This will
|
||||
default to /dev/random.
|
||||
|
||||
.TP
|
||||
\fB-s\fR
|
||||
ldns-keygen will create symbolic links named \fB.private\fR to
|
||||
the new generated private key, \fB.key\fR to the public DNSKEY
|
||||
and \fB.ds\fR to the file containing DS record data.
|
||||
|
||||
.TP
|
||||
\fB-f\fR
|
||||
force symlinks to be overwritten if they exist.
|
||||
|
||||
.TP
|
||||
\fB-v\fR
|
||||
Show the version and exit
|
||||
|
||||
.SH AUTHOR
|
||||
Written by the ldns team as an example for ldns usage.
|
||||
|
||||
.SH REPORTING BUGS
|
||||
Report bugs to <dns-team@nlnetlabs.nl>.
|
||||
|
||||
.SH COPYRIGHT
|
||||
Copyright (C) 2005-2008 NLnet Labs. This is free software. There is NO
|
||||
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR
|
||||
PURPOSE.
|
||||
475
zonemaster-ldns/ldns/examples/ldns-keygen.c
Normal file
475
zonemaster-ldns/ldns/examples/ldns-keygen.c
Normal file
@@ -0,0 +1,475 @@
|
||||
/*
|
||||
* keygen is a small programs that generate a dnskey and private key
|
||||
* for a particular domain.
|
||||
*
|
||||
* (c) NLnet Labs, 2005 - 2008
|
||||
* See the file LICENSE for the license
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include <ldns/ldns.h>
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <fcntl.h>
|
||||
#include <errno.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#ifdef HAVE_SSL
|
||||
static void
|
||||
usage(FILE *fp, char *prog) {
|
||||
fprintf(fp, "%s -a <algorithm> [-b bits] [-r /dev/random] [-s] [-f] [-v] domain\n",
|
||||
prog);
|
||||
fprintf(fp, " generate a new key pair for domain\n");
|
||||
fprintf(fp, " -a <alg>\tuse the specified algorithm (-a list to");
|
||||
fprintf(fp, " show a list)\n");
|
||||
fprintf(fp, " -k\t\tset the flags to 257; key signing key\n");
|
||||
fprintf(fp, " -b <bits>\tspecify the keylength\n");
|
||||
fprintf(fp, " -r <random>\tspecify a random device (defaults to /dev/random)\n");
|
||||
fprintf(fp, "\t\tto seed the random generator with\n");
|
||||
fprintf(fp, " -s\t\tcreate additional symlinks with constant names\n");
|
||||
fprintf(fp, " -f\t\tforce override of existing symlinks\n");
|
||||
fprintf(fp, " -v\t\tshow the version and exit\n");
|
||||
fprintf(fp, " The following files will be created:\n");
|
||||
fprintf(fp, " K<name>+<alg>+<id>.key\tPublic key in RR format\n");
|
||||
fprintf(fp, " K<name>+<alg>+<id>.private\tPrivate key in key format\n");
|
||||
fprintf(fp, " K<name>+<alg>+<id>.ds\tDS in RR format (only for DNSSEC KSK keys)\n");
|
||||
fprintf(fp, " The base name (K<name>+<alg>+<id> will be printed to stdout\n");
|
||||
}
|
||||
|
||||
static void
|
||||
show_algorithms(FILE *out)
|
||||
{
|
||||
ldns_lookup_table *lt = ldns_signing_algorithms;
|
||||
fprintf(out, "Possible algorithms:\n");
|
||||
|
||||
while (lt->name) {
|
||||
fprintf(out, "%s\n", lt->name);
|
||||
lt++;
|
||||
}
|
||||
}
|
||||
|
||||
static int
|
||||
remove_symlink(const char *symlink_name)
|
||||
{
|
||||
int result;
|
||||
|
||||
if ((result = unlink(symlink_name)) == -1) {
|
||||
if (errno == ENOENT) {
|
||||
/* it's OK if the link simply didn't exist */
|
||||
result = 0;
|
||||
} else {
|
||||
/* error if unlink fail */
|
||||
fprintf(stderr, "Can't delete symlink %s: %s\n", symlink_name, strerror(errno));
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
static int
|
||||
create_symlink(const char *symlink_destination, const char *symlink_name)
|
||||
{
|
||||
int result = 0;
|
||||
|
||||
if (!symlink_name)
|
||||
return result; /* no arg "-s" at all */
|
||||
|
||||
#ifdef HAVE_SYMLINK
|
||||
if ((result = symlink(symlink_destination, symlink_name)) == -1) {
|
||||
fprintf(stderr, "Unable to create symlink %s -> %s: %s\n", symlink_name, symlink_destination, strerror(errno));
|
||||
}
|
||||
#else
|
||||
fprintf(stderr, "Unable to create symlink %s -> %s: no symlink()\n", symlink_name, symlink_destination);
|
||||
#endif
|
||||
return result;
|
||||
}
|
||||
|
||||
int
|
||||
main(int argc, char *argv[])
|
||||
{
|
||||
int c;
|
||||
int fd;
|
||||
char *prog;
|
||||
|
||||
/* default key size */
|
||||
uint16_t def_bits = 1024;
|
||||
uint16_t bits = def_bits;
|
||||
bool had_bits = false;
|
||||
bool ksk;
|
||||
|
||||
FILE *file;
|
||||
FILE *random;
|
||||
char *filename;
|
||||
char *owner;
|
||||
bool symlink_create;
|
||||
bool symlink_override;
|
||||
|
||||
ldns_signing_algorithm algorithm;
|
||||
ldns_rdf *domain;
|
||||
ldns_rr *pubkey;
|
||||
ldns_key *key;
|
||||
ldns_rr *ds;
|
||||
|
||||
prog = strdup(argv[0]);
|
||||
algorithm = 0;
|
||||
random = NULL;
|
||||
ksk = false; /* don't create a ksk per default */
|
||||
symlink_create = false;
|
||||
symlink_override = false;
|
||||
|
||||
while ((c = getopt(argc, argv, "a:kb:r:sfv")) != -1) {
|
||||
switch (c) {
|
||||
case 'a':
|
||||
if (algorithm != 0) {
|
||||
fprintf(stderr, "The -a argument can only be used once\n");
|
||||
exit(1);
|
||||
}
|
||||
if (strncmp(optarg, "list", 5) == 0) {
|
||||
show_algorithms(stdout);
|
||||
exit(EXIT_SUCCESS);
|
||||
}
|
||||
algorithm = ldns_get_signing_algorithm_by_name(optarg);
|
||||
if (algorithm == 0) {
|
||||
fprintf(stderr, "Algorithm %s not found\n", optarg);
|
||||
show_algorithms(stderr);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
break;
|
||||
case 'b':
|
||||
bits = (uint16_t) atoi(optarg);
|
||||
if (bits == 0) {
|
||||
fprintf(stderr, "%s: %s %d", prog, "Can not parse the -b argument, setting it to the default\n", (int) def_bits);
|
||||
bits = def_bits;
|
||||
} else
|
||||
had_bits = true;
|
||||
break;
|
||||
case 'k':
|
||||
ksk = true;
|
||||
break;
|
||||
case 'r':
|
||||
random = fopen(optarg, "r");
|
||||
if (!random) {
|
||||
fprintf(stderr, "Cannot open random file %s: %s\n", optarg, strerror(errno));
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
break;
|
||||
case 's':
|
||||
symlink_create = true;
|
||||
break;
|
||||
case 'f':
|
||||
symlink_override = true;
|
||||
break;
|
||||
case 'v':
|
||||
printf("DNSSEC key generator version %s (ldns version %s)\n", LDNS_VERSION, ldns_version());
|
||||
exit(EXIT_SUCCESS);
|
||||
break;
|
||||
default:
|
||||
usage(stderr, prog);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
}
|
||||
argc -= optind;
|
||||
argv += optind;
|
||||
|
||||
if (algorithm == 0) {
|
||||
printf("Please use the -a argument to provide an algorithm\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
if (argc != 1) {
|
||||
usage(stderr, prog);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
free(prog);
|
||||
|
||||
/* check whether key size is within RFC boundaries */
|
||||
switch (algorithm) {
|
||||
case LDNS_SIGN_RSAMD5:
|
||||
case LDNS_SIGN_RSASHA1:
|
||||
case LDNS_SIGN_RSASHA1_NSEC3:
|
||||
case LDNS_SIGN_RSASHA256:
|
||||
case LDNS_SIGN_RSASHA512:
|
||||
if (bits < 512 || bits > 4096) {
|
||||
fprintf(stderr, "For RSA, the key size must be between ");
|
||||
fprintf(stderr, " 512 and 4096 bits. Aborting.\n");
|
||||
exit(1);
|
||||
}
|
||||
break;
|
||||
#ifdef USE_DSA
|
||||
case LDNS_SIGN_DSA:
|
||||
case LDNS_SIGN_DSA_NSEC3:
|
||||
if (bits < 512 || bits > 1024) {
|
||||
fprintf(stderr, "For DSA, the key size must be between ");
|
||||
fprintf(stderr, " 512 and 1024 bits. Aborting.\n");
|
||||
exit(1);
|
||||
}
|
||||
break;
|
||||
#endif /* USE_DSA */
|
||||
#ifdef USE_GOST
|
||||
case LDNS_SIGN_ECC_GOST:
|
||||
if(!ldns_key_EVP_load_gost_id()) {
|
||||
fprintf(stderr, "error: libcrypto does not provide GOST\n");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
break;
|
||||
#endif
|
||||
#ifdef USE_ECDSA
|
||||
case LDNS_SIGN_ECDSAP256SHA256:
|
||||
case LDNS_SIGN_ECDSAP384SHA384:
|
||||
break;
|
||||
#endif
|
||||
case LDNS_SIGN_HMACMD5:
|
||||
if (!had_bits) {
|
||||
bits = 512;
|
||||
} else if (bits < 1 || bits > 512) {
|
||||
fprintf(stderr, "For hmac-md5, the key size must be ");
|
||||
fprintf(stderr, "between 1 and 512 bits. Aborting.\n");
|
||||
exit(1);
|
||||
}
|
||||
break;
|
||||
case LDNS_SIGN_HMACSHA1:
|
||||
if (!had_bits) {
|
||||
bits = 160;
|
||||
} else if (bits < 1 || bits > 160) {
|
||||
fprintf(stderr, "For hmac-sha1, the key size must be ");
|
||||
fprintf(stderr, "between 1 and 160 bits. Aborting.\n");
|
||||
exit(1);
|
||||
}
|
||||
break;
|
||||
|
||||
case LDNS_SIGN_HMACSHA224:
|
||||
if (!had_bits) {
|
||||
bits = 224;
|
||||
} else if (bits < 1 || bits > 224) {
|
||||
fprintf(stderr, "For hmac-sha224, the key size must be ");
|
||||
fprintf(stderr, "between 1 and 224 bits. Aborting.\n");
|
||||
exit(1);
|
||||
}
|
||||
break;
|
||||
|
||||
case LDNS_SIGN_HMACSHA256:
|
||||
if (!had_bits) {
|
||||
bits = 256;
|
||||
} else if (bits < 1 || bits > 256) {
|
||||
fprintf(stderr, "For hmac-sha256, the key size must be ");
|
||||
fprintf(stderr, "between 1 and 256 bits. Aborting.\n");
|
||||
exit(1);
|
||||
}
|
||||
break;
|
||||
|
||||
case LDNS_SIGN_HMACSHA384:
|
||||
if (!had_bits) {
|
||||
bits = 384;
|
||||
} else if (bits < 1 || bits > 384) {
|
||||
fprintf(stderr, "For hmac-sha384, the key size must be ");
|
||||
fprintf(stderr, "between 1 and 384 bits. Aborting.\n");
|
||||
exit(1);
|
||||
}
|
||||
break;
|
||||
|
||||
case LDNS_SIGN_HMACSHA512:
|
||||
if (!had_bits) {
|
||||
bits = 512;
|
||||
} else if (bits < 1 || bits > 512) {
|
||||
fprintf(stderr, "For hmac-sha512, the key size must be ");
|
||||
fprintf(stderr, "between 1 and 512 bits. Aborting.\n");
|
||||
exit(1);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
if (!random) {
|
||||
random = fopen("/dev/random", "r");
|
||||
if (!random) {
|
||||
fprintf(stderr, "Cannot open random file %s: %s\n", optarg, strerror(errno));
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
}
|
||||
|
||||
(void)ldns_init_random(random, (unsigned int) bits/8);
|
||||
fclose(random);
|
||||
|
||||
/* create an rdf from the domain name */
|
||||
domain = ldns_dname_new_frm_str(argv[0]);
|
||||
|
||||
/* generate a new key */
|
||||
key = ldns_key_new_frm_algorithm(algorithm, bits);
|
||||
if(!key) {
|
||||
fprintf(stderr, "cannot generate key of algorithm %s\n",
|
||||
ldns_pkt_algorithm2str((ldns_algorithm)algorithm));
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
/* set the owner name in the key - this is a /separate/ step */
|
||||
ldns_key_set_pubkey_owner(key, domain);
|
||||
|
||||
/* ksk flag */
|
||||
if (ksk) {
|
||||
ldns_key_set_flags(key, ldns_key_flags(key) + 1);
|
||||
}
|
||||
|
||||
/* create the public from the ldns_key */
|
||||
pubkey = ldns_key2rr(key);
|
||||
if (!pubkey) {
|
||||
fprintf(stderr, "Could not extract the public key from the key structure...");
|
||||
ldns_key_deep_free(key);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
owner = ldns_rdf2str(ldns_rr_owner(pubkey));
|
||||
|
||||
/* calculate and set the keytag */
|
||||
ldns_key_set_keytag(key, ldns_calc_keytag(pubkey));
|
||||
|
||||
/* build the DS record */
|
||||
switch (algorithm) {
|
||||
#ifdef USE_ECDSA
|
||||
case LDNS_SIGN_ECDSAP384SHA384:
|
||||
ds = ldns_key_rr2ds(pubkey, LDNS_SHA384);
|
||||
break;
|
||||
case LDNS_SIGN_ECDSAP256SHA256:
|
||||
#endif
|
||||
#ifdef USE_ED25519
|
||||
case LDNS_SIGN_ED25519:
|
||||
#endif
|
||||
#ifdef USE_ED448
|
||||
case LDNS_SIGN_ED448:
|
||||
#endif
|
||||
case LDNS_SIGN_RSASHA256:
|
||||
case LDNS_SIGN_RSASHA512:
|
||||
ds = ldns_key_rr2ds(pubkey, LDNS_SHA256);
|
||||
break;
|
||||
case LDNS_SIGN_ECC_GOST:
|
||||
#ifdef USE_GOST
|
||||
ds = ldns_key_rr2ds(pubkey, LDNS_HASH_GOST);
|
||||
#else
|
||||
ds = ldns_key_rr2ds(pubkey, LDNS_SHA256);
|
||||
#endif
|
||||
break;
|
||||
default:
|
||||
ds = ldns_key_rr2ds(pubkey, LDNS_SHA1);
|
||||
break;
|
||||
}
|
||||
|
||||
/* maybe a symlinks should be removed */
|
||||
if (symlink_create && symlink_override) {
|
||||
if (remove_symlink(".key") != 0) {
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
if (remove_symlink(".private") != 0) {
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
if (remove_symlink(".ds") != 0) {
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
}
|
||||
|
||||
/* print the public key RR to .key */
|
||||
filename = LDNS_XMALLOC(char, strlen(owner) + 17);
|
||||
snprintf(filename, strlen(owner) + 16, "K%s+%03u+%05u.key", owner, algorithm, (unsigned int) ldns_key_keytag(key));
|
||||
file = fopen(filename, "w");
|
||||
if (!file) {
|
||||
fprintf(stderr, "Unable to open %s: %s\n", filename, strerror(errno));
|
||||
ldns_key_deep_free(key);
|
||||
free(owner);
|
||||
ldns_rr_free(pubkey);
|
||||
ldns_rr_free(ds);
|
||||
LDNS_FREE(filename);
|
||||
exit(EXIT_FAILURE);
|
||||
} else {
|
||||
/* temporarily set question so that TTL is not printed */
|
||||
ldns_rr_set_question(pubkey, true);
|
||||
ldns_rr_print(file, pubkey);
|
||||
ldns_rr_set_question(pubkey, false);
|
||||
fclose(file);
|
||||
if (symlink_create) {
|
||||
if (create_symlink(filename, ".key") != 0) {
|
||||
goto silentfail;
|
||||
}
|
||||
}
|
||||
LDNS_FREE(filename);
|
||||
}
|
||||
|
||||
/* print the priv key to stderr */
|
||||
filename = LDNS_XMALLOC(char, strlen(owner) + 21);
|
||||
snprintf(filename, strlen(owner) + 20, "K%s+%03u+%05u.private", owner, algorithm, (unsigned int) ldns_key_keytag(key));
|
||||
/* use open() here to prevent creating world-readable private keys (CVE-2014-3209)*/
|
||||
fd = open(filename, O_WRONLY | O_CREAT | O_TRUNC, S_IRUSR | S_IWUSR);
|
||||
if (fd < 0) {
|
||||
goto fail;
|
||||
}
|
||||
|
||||
file = fdopen(fd, "w");
|
||||
if (!file) {
|
||||
goto fail;
|
||||
}
|
||||
|
||||
ldns_key_print(file, key);
|
||||
fclose(file);
|
||||
if (symlink_create) {
|
||||
if (create_symlink(filename, ".private") != 0) {
|
||||
goto silentfail;
|
||||
}
|
||||
}
|
||||
LDNS_FREE(filename);
|
||||
|
||||
/* print the DS to .ds */
|
||||
if (ksk && algorithm != LDNS_SIGN_HMACMD5 &&
|
||||
algorithm != LDNS_SIGN_HMACSHA1 &&
|
||||
algorithm != LDNS_SIGN_HMACSHA224 &&
|
||||
algorithm != LDNS_SIGN_HMACSHA256 &&
|
||||
algorithm != LDNS_SIGN_HMACSHA384 &&
|
||||
algorithm != LDNS_SIGN_HMACSHA512) {
|
||||
filename = LDNS_XMALLOC(char, strlen(owner) + 16);
|
||||
snprintf(filename, strlen(owner) + 15, "K%s+%03u+%05u.ds", owner, algorithm, (unsigned int) ldns_key_keytag(key));
|
||||
file = fopen(filename, "w");
|
||||
if (!file) {
|
||||
fprintf(stderr, "Unable to open %s: %s\n", filename, strerror(errno));
|
||||
ldns_key_deep_free(key);
|
||||
free(owner);
|
||||
ldns_rr_free(pubkey);
|
||||
ldns_rr_free(ds);
|
||||
LDNS_FREE(filename);
|
||||
exit(EXIT_FAILURE);
|
||||
} else {
|
||||
/* temporarily set question so that TTL is not printed */
|
||||
ldns_rr_set_question(ds, true);
|
||||
ldns_rr_print(file, ds);
|
||||
ldns_rr_set_question(ds, false);
|
||||
fclose(file);
|
||||
if (symlink_create) {
|
||||
if (create_symlink(filename, ".ds") != 0) {
|
||||
goto silentfail;
|
||||
}
|
||||
}
|
||||
LDNS_FREE(filename);
|
||||
}
|
||||
}
|
||||
|
||||
fprintf(stdout, "K%s+%03u+%05u\n", owner, algorithm, (unsigned int) ldns_key_keytag(key));
|
||||
ldns_key_deep_free(key);
|
||||
free(owner);
|
||||
ldns_rr_free(pubkey);
|
||||
ldns_rr_free(ds);
|
||||
exit(EXIT_SUCCESS);
|
||||
|
||||
fail:
|
||||
fprintf(stderr, "Unable to open %s: %s\n", filename, strerror(errno));
|
||||
silentfail:
|
||||
ldns_key_deep_free(key);
|
||||
free(owner);
|
||||
ldns_rr_free(pubkey);
|
||||
ldns_rr_free(ds);
|
||||
LDNS_FREE(filename);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
#else
|
||||
int
|
||||
main(int argc, char **argv)
|
||||
{
|
||||
fprintf(stderr, "ldns-keygen needs OpenSSL support, which has not been compiled in\n");
|
||||
return 1;
|
||||
}
|
||||
#endif /* HAVE_SSL */
|
||||
23
zonemaster-ldns/ldns/examples/ldns-mx.1
Normal file
23
zonemaster-ldns/ldns/examples/ldns-mx.1
Normal file
@@ -0,0 +1,23 @@
|
||||
.TH ldns-mx 1 "27 Apr 2005"
|
||||
.SH NAME
|
||||
ldns-mx \- print out the mx record(s) for a domain
|
||||
.SH SYNOPSIS
|
||||
.B ldns-mx
|
||||
.IR DOMAIN
|
||||
|
||||
.SH DESCRIPTION
|
||||
\fBldns-mx\fR is used to print out mx information of a domain.
|
||||
|
||||
.SH OPTIONS
|
||||
\fBldns-mx\fR has no options.
|
||||
|
||||
.SH AUTHOR
|
||||
Written by the ldns team as an example for ldns usage.
|
||||
|
||||
.SH REPORTING BUGS
|
||||
Report bugs to <dns-team@nlnetlabs.nl>.
|
||||
|
||||
.SH COPYRIGHT
|
||||
Copyright (C) 2005 NLnet Labs. This is free software. There is NO
|
||||
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR
|
||||
PURPOSE.
|
||||
97
zonemaster-ldns/ldns/examples/ldns-mx.c
Normal file
97
zonemaster-ldns/ldns/examples/ldns-mx.c
Normal file
@@ -0,0 +1,97 @@
|
||||
/*
|
||||
* mx is a small program that prints out the mx records
|
||||
* for a particular domain
|
||||
* (c) NLnet Labs, 2005 - 2008
|
||||
* See the file LICENSE for the license
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include <ldns/ldns.h>
|
||||
|
||||
static int
|
||||
usage(FILE *fp, char *prog) {
|
||||
fprintf(fp, "%s domain\n", prog);
|
||||
fprintf(fp, " print out the mx for domain\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
main(int argc, char *argv[])
|
||||
{
|
||||
ldns_resolver *res;
|
||||
ldns_rdf *domain;
|
||||
ldns_pkt *p;
|
||||
ldns_rr_list *mx;
|
||||
ldns_status s;
|
||||
|
||||
p = NULL;
|
||||
mx = NULL;
|
||||
domain = NULL;
|
||||
res = NULL;
|
||||
|
||||
if (argc != 2) {
|
||||
usage(stdout, argv[0]);
|
||||
exit(EXIT_FAILURE);
|
||||
} else {
|
||||
/* create a rdf from the command line arg */
|
||||
domain = ldns_dname_new_frm_str(argv[1]);
|
||||
if (!domain) {
|
||||
usage(stdout, argv[0]);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
if (! ldns_dname_str_absolute(argv[1]) &&
|
||||
ldns_dname_absolute(domain)) {
|
||||
|
||||
/* ldns_dname_new_frm_str makes absolute dnames always!
|
||||
* So deabsolutify domain.
|
||||
* TODO: Create ldns_dname_new_frm_str_relative? Yuck!
|
||||
*/
|
||||
ldns_rdf_set_size(domain, ldns_rdf_size(domain) - 1);
|
||||
}
|
||||
}
|
||||
|
||||
/* create a new resolver from /etc/resolv.conf */
|
||||
s = ldns_resolver_new_frm_file(&res, NULL);
|
||||
|
||||
if (s != LDNS_STATUS_OK) {
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
/* use the resolver to send a query for the mx
|
||||
* records of the domain given on the command line
|
||||
*/
|
||||
p = ldns_resolver_search(res,
|
||||
domain,
|
||||
LDNS_RR_TYPE_MX,
|
||||
LDNS_RR_CLASS_IN,
|
||||
LDNS_RD);
|
||||
|
||||
ldns_rdf_deep_free(domain);
|
||||
|
||||
if (!p) {
|
||||
exit(EXIT_FAILURE);
|
||||
} else {
|
||||
/* retrieve the MX records from the answer section of that
|
||||
* packet
|
||||
*/
|
||||
mx = ldns_pkt_rr_list_by_type(p,
|
||||
LDNS_RR_TYPE_MX,
|
||||
LDNS_SECTION_ANSWER);
|
||||
if (!mx) {
|
||||
fprintf(stderr,
|
||||
" *** invalid answer name %s after MX query for %s\n",
|
||||
argv[1], argv[1]);
|
||||
ldns_pkt_free(p);
|
||||
ldns_resolver_deep_free(res);
|
||||
exit(EXIT_FAILURE);
|
||||
} else {
|
||||
ldns_rr_list_sort(mx);
|
||||
ldns_rr_list_print(stdout, mx);
|
||||
ldns_rr_list_deep_free(mx);
|
||||
}
|
||||
}
|
||||
ldns_pkt_free(p);
|
||||
ldns_resolver_deep_free(res);
|
||||
return 0;
|
||||
}
|
||||
70
zonemaster-ldns/ldns/examples/ldns-notify.1
Normal file
70
zonemaster-ldns/ldns/examples/ldns-notify.1
Normal file
@@ -0,0 +1,70 @@
|
||||
.TH ldns-notify 1 "9 Jan 2007"
|
||||
.SH NAME
|
||||
ldns-notify \- notify DNS servers that updates are available
|
||||
.SH SYNOPSIS
|
||||
.B ldns-notify
|
||||
[options]
|
||||
\-z zone
|
||||
.IR servers
|
||||
|
||||
.SH DESCRIPTION
|
||||
|
||||
\fBldns-notify\fR sends a NOTIFY message to DNS servers. This tells them
|
||||
that an updated zone is available at the master servers. It can perform
|
||||
TSIG signatures and it can add a SOA serial number of the updated zone.
|
||||
If a server already has that serial number it will disregard the message.
|
||||
|
||||
.SH OPTIONS
|
||||
.TP
|
||||
\fB-z zone\fR
|
||||
The zone that is updated.
|
||||
|
||||
.TP
|
||||
\fB-I address\fR
|
||||
Source IP to send query from.
|
||||
|
||||
.TP
|
||||
\fB-h\fR
|
||||
Show usage and exit
|
||||
|
||||
.TP
|
||||
\fB-v\fR
|
||||
Show the version and exit
|
||||
|
||||
.TP
|
||||
\fB-s serial\fR
|
||||
Append a SOA record indicating the serial number of the updated zone.
|
||||
|
||||
.TP
|
||||
\fB-p port\fR
|
||||
Use port as destination port (default the DNS port 53) for the UDP packets.
|
||||
|
||||
.TP
|
||||
\fB-y key:data[:algo] \fR
|
||||
Use the given TSIG key and base64-data, and optionally an algorithm to sign
|
||||
the NOTIFY. The algorithm defaults to hmac-md5.sig-alg.reg.int.
|
||||
|
||||
.TP
|
||||
\fB-d\fR
|
||||
Print verbose debug information. The query that is sent and the query
|
||||
that is received.
|
||||
|
||||
.TP
|
||||
\fB-r num\fR
|
||||
Specify the maximum number of retries before notify gives up trying to
|
||||
send the UDP packet.
|
||||
|
||||
.SH EXIT CODE
|
||||
The program exits with a 0 exit code if all servers replied an
|
||||
acknowledgement to the notify message, and a failure exit code otherwise.
|
||||
|
||||
.SH AUTHOR
|
||||
Written by the ldns team as an example for ldns usage.
|
||||
|
||||
.SH REPORTING BUGS
|
||||
Report bugs to <dns-team@nlnetlabs.nl>.
|
||||
|
||||
.SH COPYRIGHT
|
||||
Copyright (C) 2005 NLnet Labs. This is free software. There is NO
|
||||
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR
|
||||
PURPOSE.
|
||||
402
zonemaster-ldns/ldns/examples/ldns-notify.c
Normal file
402
zonemaster-ldns/ldns/examples/ldns-notify.c
Normal file
@@ -0,0 +1,402 @@
|
||||
/*
|
||||
* ldns-notify.c - ldns-notify(8)
|
||||
*
|
||||
* Copyright (c) 2001-2008, NLnet Labs, All right reserved
|
||||
*
|
||||
* See LICENSE for the license
|
||||
*
|
||||
* send a notify packet to a server
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
/* ldns */
|
||||
#include <ldns/ldns.h>
|
||||
|
||||
#ifdef HAVE_NETDB_H
|
||||
#include <netdb.h>
|
||||
#endif
|
||||
#include <errno.h>
|
||||
|
||||
static int verbose = 1;
|
||||
static int max_num_retry = 15; /* times to try */
|
||||
|
||||
static void
|
||||
usage(void)
|
||||
{
|
||||
fprintf(stderr, "usage: ldns-notify [other options] -z zone <servers>\n");
|
||||
fprintf(stderr, "Ldns notify utility\n\n");
|
||||
fprintf(stderr, " Supported options:\n");
|
||||
fprintf(stderr, "\t-z zone\t\tThe zone\n");
|
||||
fprintf(stderr, "\t-I <address>\tsource address to query from\n");
|
||||
fprintf(stderr, "\t-s version\tSOA version number to include\n");
|
||||
fprintf(stderr, "\t-y <name:key[:algo]>\tspecify named base64 tsig key"
|
||||
", and optional an\n\t\t\t"
|
||||
"algorithm (defaults to hmac-md5.sig-alg.reg.int)\n");
|
||||
fprintf(stderr, "\t-p port\t\tport to use to send to\n");
|
||||
fprintf(stderr, "\t-v\t\tPrint version information\n");
|
||||
fprintf(stderr, "\t-d\t\tPrint verbose debug information\n");
|
||||
fprintf(stderr, "\t-r num\t\tmax number of retries (%d)\n",
|
||||
max_num_retry);
|
||||
fprintf(stderr, "\t-h\t\tPrint this help information\n\n");
|
||||
fprintf(stderr, "Report bugs to <dns-team@nlnetlabs.nl>\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
static void
|
||||
version(void)
|
||||
{
|
||||
fprintf(stderr, "%s version %s\n", PACKAGE_NAME, PACKAGE_VERSION);
|
||||
fprintf(stderr, "Written by NLnet Labs.\n\n");
|
||||
fprintf(stderr,
|
||||
"Copyright (C) 2001-2008 NLnet Labs. This is free software.\n"
|
||||
"There is NO warranty; not even for MERCHANTABILITY or FITNESS\n"
|
||||
"FOR A PARTICULAR PURPOSE.\n");
|
||||
exit(0);
|
||||
}
|
||||
|
||||
static void
|
||||
notify_host(int s, struct addrinfo* res, uint8_t* wire, size_t wiresize,
|
||||
const char* addrstr)
|
||||
{
|
||||
int timeout_retry = 5; /* seconds */
|
||||
int num_retry = max_num_retry;
|
||||
#ifndef S_SPLINT_S
|
||||
fd_set rfds;
|
||||
#endif
|
||||
struct timeval tv;
|
||||
int retval = 0;
|
||||
ssize_t received = 0;
|
||||
int got_ack = 0;
|
||||
socklen_t addrlen = 0;
|
||||
uint8_t replybuf[2048];
|
||||
ldns_status status;
|
||||
ldns_pkt* pkt = NULL;
|
||||
|
||||
while(!got_ack) {
|
||||
/* send it */
|
||||
if(sendto(s, (void*)wire, wiresize, 0,
|
||||
res->ai_addr, res->ai_addrlen) == -1) {
|
||||
printf("warning: send to %s failed: %s\n",
|
||||
addrstr, strerror(errno));
|
||||
#ifndef USE_WINSOCK
|
||||
close(s);
|
||||
#else
|
||||
closesocket(s);
|
||||
#endif
|
||||
return;
|
||||
}
|
||||
|
||||
/* wait for ACK packet */
|
||||
#ifndef S_SPLINT_S
|
||||
FD_ZERO(&rfds);
|
||||
FD_SET(s, &rfds);
|
||||
tv.tv_sec = timeout_retry; /* seconds */
|
||||
#endif
|
||||
tv.tv_usec = 0; /* microseconds */
|
||||
retval = select(s + 1, &rfds, NULL, NULL, &tv);
|
||||
if (retval == -1) {
|
||||
printf("error waiting for reply from %s: %s\n",
|
||||
addrstr, strerror(errno));
|
||||
#ifndef USE_WINSOCK
|
||||
close(s);
|
||||
#else
|
||||
closesocket(s);
|
||||
#endif
|
||||
return;
|
||||
}
|
||||
if(retval == 0) {
|
||||
num_retry--;
|
||||
if(num_retry == 0) {
|
||||
printf("error: failed to send notify to %s.\n",
|
||||
addrstr);
|
||||
exit(1);
|
||||
}
|
||||
printf("timeout (%d s) expired, retry notify to %s.\n",
|
||||
timeout_retry, addrstr);
|
||||
}
|
||||
if (retval == 1) {
|
||||
got_ack = 1;
|
||||
}
|
||||
}
|
||||
|
||||
/* got reply */
|
||||
addrlen = res->ai_addrlen;
|
||||
received = recvfrom(s, (void*)replybuf, sizeof(replybuf), 0,
|
||||
res->ai_addr, &addrlen);
|
||||
res->ai_addrlen = addrlen;
|
||||
|
||||
#ifndef USE_WINSOCK
|
||||
close(s);
|
||||
#else
|
||||
closesocket(s);
|
||||
#endif
|
||||
if (received == -1) {
|
||||
printf("recv %s failed: %s\n", addrstr, strerror(errno));
|
||||
return;
|
||||
}
|
||||
|
||||
/* check reply */
|
||||
status = ldns_wire2pkt(&pkt, replybuf, (size_t)received);
|
||||
if(status != LDNS_STATUS_OK) {
|
||||
ssize_t i;
|
||||
printf("Could not parse reply packet: %s\n",
|
||||
ldns_get_errorstr_by_id(status));
|
||||
if (verbose > 1) {
|
||||
printf("hexdump of reply: ");
|
||||
for(i=0; i<received; i++)
|
||||
printf("%02x", (unsigned)replybuf[i]);
|
||||
printf("\n");
|
||||
}
|
||||
exit(1);
|
||||
}
|
||||
|
||||
if(verbose) {
|
||||
ssize_t i;
|
||||
printf("# reply from %s:\n", addrstr);
|
||||
ldns_pkt_print(stdout, pkt);
|
||||
if (verbose > 1) {
|
||||
printf("hexdump of reply: ");
|
||||
for(i=0; i<received; i++)
|
||||
printf("%02x", (unsigned)replybuf[i]);
|
||||
printf("\n");
|
||||
}
|
||||
}
|
||||
ldns_pkt_free(pkt);
|
||||
}
|
||||
|
||||
int
|
||||
main(int argc, char **argv)
|
||||
{
|
||||
int c;
|
||||
int i;
|
||||
|
||||
/* LDNS types */
|
||||
ldns_pkt *notify;
|
||||
ldns_rr *question;
|
||||
ldns_rdf *ldns_zone_name = NULL;
|
||||
ldns_status status;
|
||||
const char *zone_name = NULL;
|
||||
int include_soa = 0;
|
||||
uint32_t soa_version = 0;
|
||||
int do_hexdump = 1;
|
||||
uint8_t *wire = NULL;
|
||||
size_t wiresize = 0;
|
||||
const char *port = "53";
|
||||
char *tsig_sep;
|
||||
const char *tsig_name = NULL, *tsig_data = NULL, *tsig_algo = NULL;
|
||||
int error;
|
||||
struct addrinfo from_hints, *from0 = NULL;
|
||||
|
||||
srandom(time(NULL) ^ getpid());
|
||||
|
||||
while ((c = getopt(argc, argv, "vhdp:r:s:y:z:I:")) != -1) {
|
||||
switch (c) {
|
||||
case 'd':
|
||||
verbose++;
|
||||
break;
|
||||
case 'p':
|
||||
port = optarg;
|
||||
break;
|
||||
case 'r':
|
||||
max_num_retry = atoi(optarg);
|
||||
break;
|
||||
case 's':
|
||||
include_soa = 1;
|
||||
soa_version = (uint32_t)atoi(optarg);
|
||||
break;
|
||||
case 'y':
|
||||
if (!(tsig_sep = strchr(optarg, ':'))) {
|
||||
printf("TSIG argument is not in form "
|
||||
"<name:key[:algo]> %s\n", optarg);
|
||||
exit(1);
|
||||
}
|
||||
tsig_name = optarg;
|
||||
*tsig_sep++ = '\0';
|
||||
tsig_data = tsig_sep;
|
||||
if ((tsig_sep = strchr(tsig_sep, ':'))) {
|
||||
*tsig_sep++ = '\0';
|
||||
tsig_algo = tsig_sep;
|
||||
} else {
|
||||
tsig_algo = "hmac-md5.sig-alg.reg.int.";
|
||||
}
|
||||
/* With dig TSIG keys are also specified with -y,
|
||||
* but format with drill is: -y <name:key[:algo]>
|
||||
* and with dig: -y [hmac:]name:key
|
||||
*
|
||||
* When we detect an unknown tsig algorithm in algo,
|
||||
* but a known algorithm in name, we cane assume dig
|
||||
* order was used.
|
||||
*
|
||||
* Following if statement is to anticipate and correct
|
||||
* dig order
|
||||
*/
|
||||
if (strcasecmp(tsig_algo, "hmac-md5.sig-alg.reg.int")&&
|
||||
strcasecmp(tsig_algo, "hmac-md5") &&
|
||||
strcasecmp(tsig_algo, "hmac-sha1") &&
|
||||
strcasecmp(tsig_algo, "hmac-sha256") &&
|
||||
strcasecmp(tsig_algo, "hmac-sha384") &&
|
||||
strcasecmp(tsig_algo, "hmac-sha512") &&
|
||||
! (strcasecmp(tsig_name, "hmac-md5.sig-alg.reg.int")
|
||||
&& strcasecmp(tsig_name, "hmac-md5")
|
||||
&& strcasecmp(tsig_name, "hmac-sha1")
|
||||
&& strcasecmp(tsig_name, "hmac-sha256")
|
||||
&& strcasecmp(tsig_name, "hmac-sha384")
|
||||
&& strcasecmp(tsig_name, "hmac-sha512"))) {
|
||||
|
||||
/* Roll options */
|
||||
const char *tmp_tsig_algo = tsig_name;
|
||||
tsig_name = tsig_data;
|
||||
tsig_data = tsig_algo;
|
||||
tsig_algo = tmp_tsig_algo;
|
||||
}
|
||||
printf("Sign with name: %s, data: %s, algorithm: %s\n"
|
||||
, tsig_name, tsig_data, tsig_algo);
|
||||
break;
|
||||
case 'z':
|
||||
zone_name = optarg;
|
||||
ldns_zone_name = ldns_dname_new_frm_str(zone_name);
|
||||
if(!ldns_zone_name) {
|
||||
printf("cannot parse zone name: %s\n",
|
||||
zone_name);
|
||||
exit(1);
|
||||
}
|
||||
break;
|
||||
case 'I':
|
||||
memset(&from_hints, 0, sizeof(from_hints));
|
||||
from_hints.ai_family = AF_UNSPEC;
|
||||
from_hints.ai_socktype = SOCK_DGRAM;
|
||||
from_hints.ai_protocol = IPPROTO_UDP;
|
||||
from_hints.ai_flags = AI_NUMERICHOST;
|
||||
error = getaddrinfo(optarg, 0, &from_hints, &from0);
|
||||
if (error) {
|
||||
printf("bad address: %s: %s\n", optarg,
|
||||
gai_strerror(error));
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
break;
|
||||
case 'v':
|
||||
version();
|
||||
/* fallthrough */
|
||||
case 'h':
|
||||
case '?':
|
||||
default:
|
||||
usage();
|
||||
}
|
||||
}
|
||||
argc -= optind;
|
||||
argv += optind;
|
||||
|
||||
if (argc == 0 || zone_name == NULL) {
|
||||
usage();
|
||||
}
|
||||
|
||||
notify = ldns_pkt_new();
|
||||
question = ldns_rr_new();
|
||||
|
||||
if (!notify || !question) {
|
||||
/* bail out */
|
||||
printf("error: cannot create ldns types\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
/* create the rr for inside the pkt */
|
||||
ldns_rr_set_class(question, LDNS_RR_CLASS_IN);
|
||||
ldns_rr_set_owner(question, ldns_zone_name);
|
||||
ldns_rr_set_type(question, LDNS_RR_TYPE_SOA);
|
||||
ldns_rr_set_question(question, true);
|
||||
ldns_pkt_set_opcode(notify, LDNS_PACKET_NOTIFY);
|
||||
ldns_pkt_push_rr(notify, LDNS_SECTION_QUESTION, question);
|
||||
ldns_pkt_set_aa(notify, true);
|
||||
ldns_pkt_set_random_id(notify);
|
||||
if(include_soa) {
|
||||
char buf[10240];
|
||||
ldns_rr *soa_rr=NULL;
|
||||
ldns_rdf *prev=NULL;
|
||||
snprintf(buf, sizeof(buf), "%s 3600 IN SOA . . %u 0 0 0 0",
|
||||
zone_name, (unsigned)soa_version);
|
||||
/*printf("Adding soa %s\n", buf);*/
|
||||
status = ldns_rr_new_frm_str(&soa_rr, buf, 3600, NULL, &prev);
|
||||
if(status != LDNS_STATUS_OK) {
|
||||
printf("Error adding SOA version: %s\n",
|
||||
ldns_get_errorstr_by_id(status));
|
||||
}
|
||||
ldns_pkt_push_rr(notify, LDNS_SECTION_ANSWER, soa_rr);
|
||||
}
|
||||
|
||||
if(tsig_name && tsig_data) {
|
||||
#ifdef HAVE_SSL
|
||||
status = ldns_pkt_tsig_sign(notify, tsig_name,
|
||||
tsig_data, 300, tsig_algo, NULL);
|
||||
if(status != LDNS_STATUS_OK) {
|
||||
printf("Error TSIG sign query: %s\n",
|
||||
ldns_get_errorstr_by_id(status));
|
||||
}
|
||||
#else
|
||||
fprintf(stderr, "Warning: TSIG needs OpenSSL support, which has not been compiled in, TSIG skipped\n");
|
||||
#endif
|
||||
}
|
||||
|
||||
if(verbose) {
|
||||
printf("# Sending packet:\n");
|
||||
ldns_pkt_print(stdout, notify);
|
||||
|
||||
}
|
||||
|
||||
status = ldns_pkt2wire(&wire, notify, &wiresize);
|
||||
if (status) {
|
||||
printf("Error converting notify packet to hex: %s\n",
|
||||
ldns_get_errorstr_by_id(status));
|
||||
} else if(wiresize == 0) {
|
||||
printf("Error converting notify packet to hex.\n");
|
||||
exit(1);
|
||||
}
|
||||
if(do_hexdump && verbose > 1) {
|
||||
printf("Hexdump of notify packet:\n");
|
||||
for(i=0; i<(int)wiresize; i++)
|
||||
printf("%02x", (unsigned)wire[i]);
|
||||
printf("\n");
|
||||
}
|
||||
|
||||
for(i=0; i<argc; i++)
|
||||
{
|
||||
struct addrinfo hints, *res0, *ai_res;
|
||||
int default_family = AF_UNSPEC;
|
||||
|
||||
if(verbose)
|
||||
printf("# sending to %s\n", argv[i]);
|
||||
memset(&hints, 0, sizeof(hints));
|
||||
hints.ai_family = default_family;
|
||||
/* if(strchr(argv[i], ':')) hints.ai_family = AF_INET6; */
|
||||
hints.ai_socktype = SOCK_DGRAM;
|
||||
hints.ai_protocol = IPPROTO_UDP;
|
||||
error = getaddrinfo(argv[i], port, &hints, &res0);
|
||||
if (error) {
|
||||
printf("skipping bad address: %s: %s\n", argv[i],
|
||||
gai_strerror(error));
|
||||
continue;
|
||||
}
|
||||
for (ai_res = res0; ai_res; ai_res = ai_res->ai_next) {
|
||||
int s;
|
||||
|
||||
if (from0 && ai_res->ai_family != from0->ai_family)
|
||||
continue;
|
||||
|
||||
s = socket(ai_res->ai_family, ai_res->ai_socktype,
|
||||
ai_res->ai_protocol);
|
||||
if(s == -1)
|
||||
continue;
|
||||
if (from0 && bind(s, from0->ai_addr, from0->ai_addrlen)) {
|
||||
perror("Could not bind to source IP");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
/* send the notify */
|
||||
notify_host(s, ai_res, wire, wiresize, argv[i]);
|
||||
}
|
||||
freeaddrinfo(res0);
|
||||
}
|
||||
|
||||
ldns_pkt_free(notify);
|
||||
free(wire);
|
||||
return 0;
|
||||
}
|
||||
34
zonemaster-ldns/ldns/examples/ldns-nsec3-hash.1
Normal file
34
zonemaster-ldns/ldns/examples/ldns-nsec3-hash.1
Normal file
@@ -0,0 +1,34 @@
|
||||
.TH ldns-nsec3-hash.c 1 "10 Dec 2008"
|
||||
.SH NAME
|
||||
ldns-nsec3-hash \- print out the NSEC3 hash for a domain name
|
||||
.SH SYNOPSIS
|
||||
.B ldns-nsec3-hash
|
||||
.IR <domain_name>
|
||||
|
||||
.SH DESCRIPTION
|
||||
\fBldns-nsec3-hash\fR is used to print out the NSEC3 hash for the given domain name.
|
||||
|
||||
.SH OPTIONS
|
||||
.TP
|
||||
\fB-a\fR \fInumber\fR
|
||||
Use the given algorithm number for the hash calculation. Defaults to 1 (SHA-1).
|
||||
|
||||
.TP
|
||||
\fB-s\fR \fIsalt\fR
|
||||
Use the given salt for the hash calculation. Salt value should be in hexadecimal format.
|
||||
|
||||
.TP
|
||||
\fB-t\fR \fIcount\fR
|
||||
Use count iterations for the hash calculation.
|
||||
|
||||
|
||||
.SH AUTHOR
|
||||
Written by the ldns team as an example for ldns usage.
|
||||
|
||||
.SH REPORTING BUGS
|
||||
Report bugs to <dns-team@nlnetlabs.nl>.
|
||||
|
||||
.SH COPYRIGHT
|
||||
Copyright (C) 2008 NLnet Labs. This is free software. There is NO
|
||||
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR
|
||||
PURPOSE.
|
||||
131
zonemaster-ldns/ldns/examples/ldns-nsec3-hash.c
Normal file
131
zonemaster-ldns/ldns/examples/ldns-nsec3-hash.c
Normal file
@@ -0,0 +1,131 @@
|
||||
/*
|
||||
* ldns-signzone signs a zone file
|
||||
*
|
||||
* (c) NLnet Labs, 2005 - 2008
|
||||
* See the file LICENSE for the license
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include <errno.h>
|
||||
|
||||
#include <time.h>
|
||||
|
||||
#include <ldns/ldns.h>
|
||||
#include <ldns/keys.h>
|
||||
|
||||
#ifdef HAVE_SSL
|
||||
#include <openssl/conf.h>
|
||||
#endif /* HAVE_SSL */
|
||||
|
||||
#define MAX_FILENAME_LEN 250
|
||||
int verbosity = 1;
|
||||
|
||||
static void
|
||||
usage(FILE *fp, const char *prog) {
|
||||
fprintf(fp, "%s [OPTIONS] <domain name>\n", prog);
|
||||
fprintf(fp, " prints the NSEC3 hash of the given domain name\n");
|
||||
fprintf(fp, "-a [algorithm] hashing algorithm\n");
|
||||
fprintf(fp, "-t [number] number of hash iterations\n");
|
||||
fprintf(fp, "-s [string] salt\n");
|
||||
}
|
||||
|
||||
int
|
||||
main(int argc, char *argv[])
|
||||
{
|
||||
ldns_rdf *dname, *hashed_dname;
|
||||
uint8_t nsec3_algorithm = 1;
|
||||
size_t nsec3_iterations_cmd = 1;
|
||||
uint16_t nsec3_iterations = 1;
|
||||
uint8_t nsec3_salt_length = 0;
|
||||
uint8_t *nsec3_salt = NULL;
|
||||
|
||||
char *prog = strdup(argv[0]);
|
||||
|
||||
int c;
|
||||
while ((c = getopt(argc, argv, "a:s:t:")) != -1) {
|
||||
switch (c) {
|
||||
case 'a':
|
||||
nsec3_algorithm = (uint8_t) atoi(optarg);
|
||||
break;
|
||||
case 's':
|
||||
if (strlen(optarg) % 2 != 0) {
|
||||
fprintf(stderr, "Salt value is not valid hex data, not a multiple of 2 characters\n");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
if (strlen(optarg) > 512) {
|
||||
fprintf(stderr, "Salt too long\n");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
if (nsec3_salt) LDNS_FREE(nsec3_salt);
|
||||
nsec3_salt_length = (uint8_t) (strlen(optarg) / 2);
|
||||
nsec3_salt = LDNS_XMALLOC(uint8_t, nsec3_salt_length);
|
||||
for (c = 0; c < (int) strlen(optarg); c += 2) {
|
||||
if (isxdigit((int) optarg[c]) && isxdigit((int) optarg[c+1])) {
|
||||
nsec3_salt[c/2] = (uint8_t) ldns_hexdigit_to_int(optarg[c]) * 16 +
|
||||
ldns_hexdigit_to_int(optarg[c+1]);
|
||||
} else {
|
||||
fprintf(stderr, "Salt value is not valid hex data.\n");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
}
|
||||
|
||||
break;
|
||||
case 't':
|
||||
nsec3_iterations_cmd = (size_t) atol(optarg);
|
||||
if (nsec3_iterations_cmd > LDNS_NSEC3_MAX_ITERATIONS) {
|
||||
fprintf(stderr, "Iterations count can not exceed %u, quitting\n", LDNS_NSEC3_MAX_ITERATIONS);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
nsec3_iterations = (uint16_t) nsec3_iterations_cmd;
|
||||
break;
|
||||
default:
|
||||
usage(stderr, prog);
|
||||
exit(EXIT_SUCCESS);
|
||||
}
|
||||
}
|
||||
|
||||
argc -= optind;
|
||||
argv += optind;
|
||||
|
||||
if (argc < 1) {
|
||||
printf("Error: not enough arguments\n");
|
||||
usage(stdout, prog);
|
||||
exit(EXIT_FAILURE);
|
||||
} else {
|
||||
dname = ldns_dname_new_frm_str(argv[0]);
|
||||
if (!dname) {
|
||||
free(prog);
|
||||
if (nsec3_salt) free(nsec3_salt);
|
||||
fprintf(stderr,
|
||||
"Error: unable to parse domain name\n");
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
hashed_dname = ldns_nsec3_hash_name(dname,
|
||||
nsec3_algorithm,
|
||||
nsec3_iterations,
|
||||
nsec3_salt_length,
|
||||
nsec3_salt);
|
||||
if (!hashed_dname) {
|
||||
free(prog);
|
||||
if (nsec3_salt) free(nsec3_salt);
|
||||
fprintf(stderr,
|
||||
"Error creating NSEC3 hash\n");
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
ldns_rdf_print(stdout, hashed_dname);
|
||||
printf("\n");
|
||||
ldns_rdf_deep_free(dname);
|
||||
ldns_rdf_deep_free(hashed_dname);
|
||||
}
|
||||
|
||||
if (nsec3_salt) {
|
||||
free(nsec3_salt);
|
||||
}
|
||||
|
||||
free(prog);
|
||||
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
113
zonemaster-ldns/ldns/examples/ldns-read-zone.1
Normal file
113
zonemaster-ldns/ldns/examples/ldns-read-zone.1
Normal file
@@ -0,0 +1,113 @@
|
||||
.TH ldns-read-zone 1 "30 May 2005"
|
||||
.SH NAME
|
||||
ldns-read-zone \- read a zonefile and print it
|
||||
.SH SYNOPSIS
|
||||
.B ldns-read-zone
|
||||
.IR ZONEFILE
|
||||
|
||||
.SH DESCRIPTION
|
||||
|
||||
\fBldns-read-zone\fR reads a DNS zone file and prints it. The output has 1
|
||||
resource record per line, and no pretty-printing makeup.
|
||||
|
||||
.SH OPTIONS
|
||||
.TP
|
||||
\fB-0\fR
|
||||
Print a (null) for the RRSIG inception, expiry and key data. This option
|
||||
can be used when comparing different signing systems that use the same
|
||||
DNSKEYs for signing but would have a slightly different timings/jitter.
|
||||
|
||||
.TP
|
||||
\fB-b\fR
|
||||
Include Bubble Babble encoding of DS's.
|
||||
|
||||
.TP
|
||||
\fB-c\fR
|
||||
Canonicalize all resource records in the zone before printing
|
||||
|
||||
.TP
|
||||
\fB-d\fR
|
||||
Only print DNSSEC data from the zone. This option skips every record
|
||||
that is not of type NSEC, NSEC3 or RRSIG. DNSKEY and DS records are not
|
||||
printed.
|
||||
|
||||
.TP
|
||||
\fB-e\fR \fIRR type\fR
|
||||
Do not print RRs of the given \fIrr type\fR.
|
||||
This option may be given multiple times.
|
||||
\fB-e\fR is not meant to be used together with \fB-E\fR.
|
||||
|
||||
.TP
|
||||
\fB-E\fR \fIRR type\fR
|
||||
Print only RRs of the given \fIrr type\fR.
|
||||
This option may be given multiple times.
|
||||
\fB-E\fR is not meant to be used together with \fB-e\fR.
|
||||
|
||||
.TP
|
||||
\fB-h\fR
|
||||
Show usage and exit
|
||||
|
||||
.TP
|
||||
\fB-n\fR
|
||||
Do not print the SOA record
|
||||
|
||||
.TP
|
||||
\fB-p\fR
|
||||
Pad the SOA serial number with spaces so the number and the spaces together
|
||||
take ten characters. This is useful for in file serial number increments.
|
||||
|
||||
.TP
|
||||
\fB-s\fR
|
||||
Strip DNSSEC data from the zone. This option skips every record
|
||||
that is of type NSEC, NSEC3 or RRSIG. DNSKEY and DS records are still
|
||||
printed.
|
||||
|
||||
.TP
|
||||
\fB-S\fR \fI[[+|0]number | YYYYMMDDxx | unixtime ]\fR
|
||||
Set serial number to the given \fInumber\fR, or when preceded by a sign,
|
||||
offset the existing number with it. When giving the literal strings
|
||||
\fIYYYYMMDDxx\fR or \fIunixtime\fR, the serial number is tried to be reset
|
||||
in datecounter or in unixtime format respectively. Though is the updated serial
|
||||
number is smaller than the original one, the original one is simply
|
||||
increased by one.
|
||||
|
||||
When updating a serial number, records of type NSEC, NSEC3, RRSIG and DNSKEY
|
||||
will be skipped when printing the zone.
|
||||
|
||||
.TP
|
||||
\fB-u\fR \fIRR type\fR
|
||||
Mark \fIRR type\fR for printing in unknown type format.
|
||||
|
||||
\fB-u\fR is not meant to be used together with \fB-U\fR.
|
||||
|
||||
.TP
|
||||
\fB-U\fR \fIRR type\fR
|
||||
Mark \fIRR type\fR for \fBnot\fR printing in unknown type format.
|
||||
|
||||
The first occurrence of the \fB-U\fR option marks all RR types for printing
|
||||
in unknown type format except for the given \fIRR type\fR.
|
||||
Subsequent \fB-U\fR options will clear the mark for those \fIRR type\fRs too,
|
||||
so that only the given \fIRR type\fRs will be printed in the presentation
|
||||
format specific for those \fIRR type\fRs.
|
||||
|
||||
\fB-U\fR is not meant to be used together with \fB-u\fR.
|
||||
|
||||
.TP
|
||||
\fB-v\fR
|
||||
Show the version and exit
|
||||
|
||||
.TP
|
||||
\fB-z\fR
|
||||
Sort the zone before printing (this implies \-c)
|
||||
|
||||
|
||||
.SH AUTHOR
|
||||
Written by the ldns team as an example for ldns usage.
|
||||
|
||||
.SH REPORTING BUGS
|
||||
Report bugs to <dns-team@nlnetlabs.nl>.
|
||||
|
||||
.SH COPYRIGHT
|
||||
Copyright (C) 2005 NLnet Labs. This is free software. There is NO
|
||||
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR
|
||||
PURPOSE.
|
||||
307
zonemaster-ldns/ldns/examples/ldns-read-zone.c
Normal file
307
zonemaster-ldns/ldns/examples/ldns-read-zone.c
Normal file
@@ -0,0 +1,307 @@
|
||||
/*
|
||||
* read a zone file from disk and prints it, one RR per line
|
||||
*
|
||||
* (c) NLnetLabs 2005-2008
|
||||
*
|
||||
* See the file LICENSE for the license
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
#include <unistd.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include <ldns/ldns.h>
|
||||
#include <ldns/host2str.h>
|
||||
|
||||
#include <errno.h>
|
||||
|
||||
static void print_usage(const char* progname)
|
||||
{
|
||||
printf("Usage: %s [OPTIONS] <zonefile>\n", progname);
|
||||
printf("\tReads the zonefile and prints it.\n");
|
||||
printf("\tThe RR count of the zone is printed to stderr.\n");
|
||||
printf("\t-0 zeroize timestamps and signature in RRSIG records.\n");
|
||||
printf("\t-b include Bubble Babble encoding of DS's.\n");
|
||||
printf("\t-c canonicalize all rrs in the zone.\n");
|
||||
printf("\t-d only show DNSSEC data from the zone\n");
|
||||
printf("\t-e <rr type>\n");
|
||||
printf("\t\tDo not print RRs of the given <rr type>.\n");
|
||||
printf("\t\tThis option may be given multiple times.\n");
|
||||
printf("\t\t-e is not meant to be used together with -E.\n");
|
||||
printf("\t-E <rr type>\n");
|
||||
printf("\t\tPrint only RRs of the given <rr type>.\n");
|
||||
printf("\t\tThis option may be given multiple times.\n");
|
||||
printf("\t\t-E is not meant to be used together with -e.\n");
|
||||
printf("\t-h show this text\n");
|
||||
printf("\t-n do not print the SOA record\n");
|
||||
printf("\t-p prepend SOA serial with spaces so"
|
||||
" it takes exactly ten characters.\n");
|
||||
printf("\t-s strip DNSSEC data from the zone\n");
|
||||
printf("\t-S [[+|-]<number> | YYYYMMDDxx | "
|
||||
" unixtime ]\n"
|
||||
"\t\tSet serial number to <number> or,"
|
||||
" when preceded by a sign,\n"
|
||||
"\t\toffset the existing number with "
|
||||
"<number>. With YYYYMMDDxx\n"
|
||||
"\t\tthe serial is formatted as a datecounter"
|
||||
", and with unixtime as\n"
|
||||
"\t\tthe number of seconds since 1-1-1970."
|
||||
" However, on serial\n"
|
||||
"\t\tnumber decrease, +1 is used in stead"
|
||||
". (implies -s)\n");
|
||||
printf("\t-u <rr type>\n");
|
||||
printf("\t\tMark <rr type> for printing in unknown type format.\n");
|
||||
printf("\t\tThis option may be given multiple times.\n");
|
||||
printf("\t\t-u is not meant to be used together with -U.\n");
|
||||
printf("\t-U <rr type>\n");
|
||||
printf("\t\tMark <rr type> for not printing in unknown type format.\n");
|
||||
printf("\t\tThis option may be given multiple times.\n");
|
||||
printf(
|
||||
"\t\tThe first occurrence of the -U option marks all RR types for"
|
||||
"\n\t\tprinting in unknown type format except for the given <rr type>."
|
||||
"\n\t\tSubsequent -U options will clear the mark for those <rr type>s"
|
||||
"\n\t\ttoo, so that only the given <rr type>s will be printed in the"
|
||||
"\n\t\tpresentation format specific for those <rr type>s.\n");
|
||||
printf("\t\t-U is not meant to be used together with -u.\n");
|
||||
printf("\t-v shows the version and exits\n");
|
||||
printf("\t-z sort the zone (implies -c).\n");
|
||||
printf("\nif no file is given standard input is read\n");
|
||||
exit(EXIT_SUCCESS);
|
||||
}
|
||||
|
||||
static void exclude_type(ldns_rdf **show_types, ldns_rr_type t)
|
||||
{
|
||||
ldns_status s;
|
||||
|
||||
assert(show_types != NULL);
|
||||
|
||||
if (! *show_types && LDNS_STATUS_OK !=
|
||||
(s = ldns_rdf_bitmap_known_rr_types(show_types)))
|
||||
goto fail;
|
||||
|
||||
s = ldns_nsec_bitmap_clear_type(*show_types, t);
|
||||
if (s == LDNS_STATUS_OK)
|
||||
return;
|
||||
fail:
|
||||
fprintf(stderr, "Cannot exclude rr type %s: %s\n"
|
||||
, ldns_rr_descript(t)->_name
|
||||
, ldns_get_errorstr_by_id(s));
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
static void include_type(ldns_rdf **show_types, ldns_rr_type t)
|
||||
{
|
||||
ldns_status s;
|
||||
|
||||
assert(show_types != NULL);
|
||||
|
||||
if (! *show_types && LDNS_STATUS_OK !=
|
||||
(s = ldns_rdf_bitmap_known_rr_types_space(show_types)))
|
||||
goto fail;
|
||||
|
||||
s = ldns_nsec_bitmap_set_type(*show_types, t);
|
||||
if (s == LDNS_STATUS_OK)
|
||||
return;
|
||||
fail:
|
||||
fprintf(stderr, "Cannot exclude all rr types except %s: %s\n"
|
||||
, ldns_rr_descript(t)->_name
|
||||
, ldns_get_errorstr_by_id(s));
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
int
|
||||
main(int argc, char **argv)
|
||||
{
|
||||
char *filename;
|
||||
FILE *fp;
|
||||
ldns_zone *z;
|
||||
int line_nr = 0;
|
||||
int c;
|
||||
bool canonicalize = false;
|
||||
bool sort = false;
|
||||
bool print_soa = true;
|
||||
ldns_status s;
|
||||
size_t i;
|
||||
ldns_rr_list *stripped_list;
|
||||
ldns_rr *cur_rr;
|
||||
ldns_output_format_storage fmt_storage;
|
||||
ldns_output_format* fmt = ldns_output_format_init(&fmt_storage);
|
||||
ldns_rdf *show_types = NULL;
|
||||
|
||||
ldns_soa_serial_increment_func_t soa_serial_increment_func = NULL;
|
||||
int soa_serial_increment_func_data = 0;
|
||||
|
||||
while ((c = getopt(argc, argv, "0bcde:E:hnpsS:u:U:vz")) != -1) {
|
||||
switch(c) {
|
||||
case '0':
|
||||
fmt->flags |= LDNS_FMT_ZEROIZE_RRSIGS;
|
||||
break;
|
||||
case 'b':
|
||||
fmt->flags |=
|
||||
( LDNS_COMMENT_BUBBLEBABBLE |
|
||||
LDNS_COMMENT_FLAGS );
|
||||
break;
|
||||
case 'c':
|
||||
canonicalize = true;
|
||||
break;
|
||||
case 'd':
|
||||
include_type(&show_types, LDNS_RR_TYPE_RRSIG);
|
||||
include_type(&show_types, LDNS_RR_TYPE_NSEC);
|
||||
include_type(&show_types, LDNS_RR_TYPE_NSEC3);
|
||||
break;
|
||||
case 'e':
|
||||
exclude_type(&show_types,
|
||||
ldns_get_rr_type_by_name(optarg));
|
||||
break;
|
||||
case 'E':
|
||||
include_type(&show_types,
|
||||
ldns_get_rr_type_by_name(optarg));
|
||||
break;
|
||||
case 'h':
|
||||
print_usage("ldns-read-zone");
|
||||
break;
|
||||
case 'n':
|
||||
print_soa = false;
|
||||
break;
|
||||
case 'p':
|
||||
fmt->flags |= LDNS_FMT_PAD_SOA_SERIAL;
|
||||
break;
|
||||
case 's':
|
||||
case 'S':
|
||||
exclude_type(&show_types, LDNS_RR_TYPE_RRSIG);
|
||||
exclude_type(&show_types, LDNS_RR_TYPE_NSEC);
|
||||
exclude_type(&show_types, LDNS_RR_TYPE_NSEC3);
|
||||
if (c == 's') break;
|
||||
if (*optarg == '+' || *optarg == '-') {
|
||||
soa_serial_increment_func_data =
|
||||
atoi(optarg);
|
||||
soa_serial_increment_func =
|
||||
ldns_soa_serial_increment_by;
|
||||
} else if (! strtok(optarg, "0123456789")) {
|
||||
soa_serial_increment_func_data =
|
||||
atoi(optarg);
|
||||
soa_serial_increment_func =
|
||||
ldns_soa_serial_identity;
|
||||
} else if (!strcasecmp(optarg, "YYYYMMDDxx")){
|
||||
soa_serial_increment_func =
|
||||
ldns_soa_serial_datecounter;
|
||||
} else if (!strcasecmp(optarg, "unixtime")){
|
||||
soa_serial_increment_func =
|
||||
ldns_soa_serial_unixtime;
|
||||
} else {
|
||||
fprintf(stderr, "-S expects a number "
|
||||
"optionally preceded by a "
|
||||
"+ or - sign to indicate an "
|
||||
"offset, or the text YYYYMM"
|
||||
"DDxx or unixtime\n");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
break;
|
||||
case 'u':
|
||||
s = ldns_output_format_set_type(fmt,
|
||||
ldns_get_rr_type_by_name(optarg));
|
||||
if (s != LDNS_STATUS_OK) {
|
||||
fprintf( stderr
|
||||
, "Cannot set rr type %s "
|
||||
"in output format to "
|
||||
"print as unknown type: %s\n"
|
||||
, ldns_rr_descript(
|
||||
ldns_get_rr_type_by_name(optarg)
|
||||
)->_name
|
||||
, ldns_get_errorstr_by_id(s)
|
||||
);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
break;
|
||||
case 'U':
|
||||
s = ldns_output_format_clear_type(fmt,
|
||||
ldns_get_rr_type_by_name(optarg));
|
||||
if (s != LDNS_STATUS_OK) {
|
||||
fprintf( stderr
|
||||
, "Cannot set rr type %s "
|
||||
"in output format to not "
|
||||
"print as unknown type: %s\n"
|
||||
, ldns_rr_descript(
|
||||
ldns_get_rr_type_by_name(optarg)
|
||||
)->_name
|
||||
, ldns_get_errorstr_by_id(s)
|
||||
);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
break;
|
||||
case 'v':
|
||||
printf("read zone version %s (ldns version %s)\n", LDNS_VERSION, ldns_version());
|
||||
exit(EXIT_SUCCESS);
|
||||
break;
|
||||
case 'z':
|
||||
canonicalize = true;
|
||||
sort = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
argc -= optind;
|
||||
argv += optind;
|
||||
|
||||
if (argc == 0) {
|
||||
fp = stdin;
|
||||
} else {
|
||||
filename = argv[0];
|
||||
|
||||
fp = fopen(filename, "r");
|
||||
if (!fp) {
|
||||
fprintf(stderr, "Unable to open %s: %s\n", filename, strerror(errno));
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
}
|
||||
|
||||
s = ldns_zone_new_frm_fp_l(&z, fp, NULL, 0, LDNS_RR_CLASS_IN, &line_nr);
|
||||
|
||||
fclose(fp);
|
||||
if (s != LDNS_STATUS_OK) {
|
||||
fprintf(stderr, "%s at line %d\n",
|
||||
ldns_get_errorstr_by_id(s),
|
||||
line_nr);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
if (show_types) {
|
||||
if (print_soa)
|
||||
print_soa = ldns_nsec_bitmap_covers_type(show_types,
|
||||
LDNS_RR_TYPE_SOA);
|
||||
stripped_list = ldns_rr_list_new();
|
||||
while ((cur_rr = ldns_rr_list_pop_rr(ldns_zone_rrs(z))))
|
||||
if (ldns_nsec_bitmap_covers_type(show_types,
|
||||
ldns_rr_get_type(cur_rr)))
|
||||
ldns_rr_list_push_rr(stripped_list, cur_rr);
|
||||
else
|
||||
ldns_rr_free(cur_rr);
|
||||
ldns_rr_list_free(ldns_zone_rrs(z));
|
||||
ldns_zone_set_rrs(z, stripped_list);
|
||||
}
|
||||
|
||||
if (canonicalize) {
|
||||
ldns_rr2canonical(ldns_zone_soa(z));
|
||||
for (i = 0; i < ldns_rr_list_rr_count(ldns_zone_rrs(z)); i++) {
|
||||
ldns_rr2canonical(ldns_rr_list_rr(ldns_zone_rrs(z), i));
|
||||
}
|
||||
}
|
||||
if (sort) {
|
||||
ldns_zone_sort(z);
|
||||
}
|
||||
|
||||
if (print_soa && ldns_zone_soa(z)) {
|
||||
if (soa_serial_increment_func) {
|
||||
ldns_rr_soa_increment_func_int(
|
||||
ldns_zone_soa(z)
|
||||
, soa_serial_increment_func
|
||||
, soa_serial_increment_func_data
|
||||
);
|
||||
}
|
||||
ldns_rr_print_fmt(stdout, fmt, ldns_zone_soa(z));
|
||||
}
|
||||
ldns_rr_list_print_fmt(stdout, fmt, ldns_zone_rrs(z));
|
||||
|
||||
ldns_zone_deep_free(z);
|
||||
|
||||
exit(EXIT_SUCCESS);
|
||||
}
|
||||
26
zonemaster-ldns/ldns/examples/ldns-resolver.1
Normal file
26
zonemaster-ldns/ldns/examples/ldns-resolver.1
Normal file
@@ -0,0 +1,26 @@
|
||||
.TH ldns-resolver 1 "27 Apr 2005"
|
||||
.SH NAME
|
||||
ldns-resolver \- tries to create a resolver from a resolv.conf file.
|
||||
.SH SYNOPSIS
|
||||
.B ldns-resolver
|
||||
.IR file
|
||||
|
||||
.SH DESCRIPTION
|
||||
\fBldns-resolver\fR tries to create a resolver from a resolv.conf file.
|
||||
This is only useful to test the library for robustness with input data.
|
||||
|
||||
.SH OPTIONS
|
||||
\fBldns-resolver\fR takes a filename of the resolv.conf file as input.
|
||||
For example \fIldns-resolver /etc/resolv.conf\fR will show if the file can
|
||||
be parsed successfully.
|
||||
|
||||
.SH AUTHOR
|
||||
Written by the ldns team as an example for ldns usage.
|
||||
|
||||
.SH REPORTING BUGS
|
||||
Report bugs to <dns-team@nlnetlabs.nl>.
|
||||
|
||||
.SH COPYRIGHT
|
||||
Copyright (C) 2005 NLnet Labs. This is free software. There is NO
|
||||
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR
|
||||
PURPOSE.
|
||||
47
zonemaster-ldns/ldns/examples/ldns-resolver.c
Normal file
47
zonemaster-ldns/ldns/examples/ldns-resolver.c
Normal file
@@ -0,0 +1,47 @@
|
||||
/*
|
||||
* ldns-resolver tries to create a resolver structure from /dev/urandom
|
||||
* this is only useful to test the library for robustness with input data
|
||||
*
|
||||
* (c) NLnet Labs 2006 - 2008
|
||||
* See the file LICENSE for the license
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
#include "errno.h"
|
||||
|
||||
#include <ldns/ldns.h>
|
||||
|
||||
int
|
||||
main(int argc, char **argv) {
|
||||
|
||||
ldns_resolver *r;
|
||||
int line = 1;
|
||||
FILE *rand;
|
||||
ldns_status s;
|
||||
|
||||
if (argc != 2 || strncmp(argv[1], "-h", 3) == 0) {
|
||||
printf("Usage: ldns-resolver <file>\n");
|
||||
printf("Tries to create a stub resolver structure from the given file.\n");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
if (!(rand = fopen(argv[1], "r"))) {
|
||||
printf("Error opening %s: %s\n", argv[1], strerror(errno));
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
printf("Trying to read from %s\n", argv[1]);
|
||||
s = ldns_resolver_new_frm_fp_l(&r, rand, &line);
|
||||
if (s != LDNS_STATUS_OK) {
|
||||
printf("Failed: %s at line %d\n", ldns_get_errorstr_by_id(s), line);
|
||||
exit(EXIT_FAILURE);
|
||||
} else {
|
||||
printf("Success\n");
|
||||
ldns_resolver_print(stdout, r);
|
||||
ldns_resolver_deep_free(r);
|
||||
}
|
||||
|
||||
fclose(rand);
|
||||
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
27
zonemaster-ldns/ldns/examples/ldns-revoke.1
Normal file
27
zonemaster-ldns/ldns/examples/ldns-revoke.1
Normal file
@@ -0,0 +1,27 @@
|
||||
.TH ldns-revoke 1 "23 Jul 2008"
|
||||
.SH NAME
|
||||
ldns-revoke \- sets the revoke bit of a DNSKEY
|
||||
.SH SYNOPSIS
|
||||
.B ldns-revoke
|
||||
.IR file
|
||||
|
||||
.SH DESCRIPTION
|
||||
\fBldns-revoke\fR is used to revoke a public DNSKEY RR.
|
||||
When run it will read \fIfile\fR with a DNSKEY RR in it,
|
||||
sets the revoke bit and write back the output to \fIfile\fR .
|
||||
|
||||
.SH OPTIONS
|
||||
.TP
|
||||
\fB-n\fR
|
||||
Write the result to stdout instead of a file
|
||||
|
||||
.SH AUTHOR
|
||||
Written by the ldns team as an example for ldns usage.
|
||||
|
||||
.SH REPORTING BUGS
|
||||
Report bugs to <dns-team@nlnetlabs.nl>.
|
||||
|
||||
.SH COPYRIGHT
|
||||
Copyright (C) 2008 NLnet Labs. This is free software. There is NO
|
||||
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR
|
||||
PURPOSE.
|
||||
104
zonemaster-ldns/ldns/examples/ldns-revoke.c
Normal file
104
zonemaster-ldns/ldns/examples/ldns-revoke.c
Normal file
@@ -0,0 +1,104 @@
|
||||
/*
|
||||
* revoke sets the revoke bit of a public key.
|
||||
*
|
||||
* (c) NLnet Labs, 2005 - 2008
|
||||
* See the file LICENSE for the license
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include <ldns/ldns.h>
|
||||
#ifdef HAVE_SSL
|
||||
#include <openssl/ssl.h>
|
||||
#endif /* HAVE_SSL */
|
||||
|
||||
#include <errno.h>
|
||||
|
||||
static void
|
||||
usage(FILE *fp, char *prog) {
|
||||
fprintf(fp, "%s [-n] keyfile\n", prog);
|
||||
fprintf(fp, " Revokes a key\n");
|
||||
fprintf(fp, "Options:\n");
|
||||
fprintf(fp, " -n: do not write to file but to stdout\n");
|
||||
}
|
||||
|
||||
int
|
||||
main(int argc, char *argv[])
|
||||
{
|
||||
FILE *keyfp;
|
||||
char *keyname;
|
||||
ldns_rr *k;
|
||||
uint16_t flags;
|
||||
char *program = argv[0];
|
||||
int nofile = 0;
|
||||
ldns_rdf *origin = NULL;
|
||||
ldns_status result;
|
||||
|
||||
argv++, argc--;
|
||||
while (argc && argv[0][0] == '-') {
|
||||
if (strcmp(argv[0], "-n") == 0) {
|
||||
nofile=1;
|
||||
}
|
||||
else {
|
||||
usage(stderr, program);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
argv++, argc--;
|
||||
}
|
||||
|
||||
if (argc != 1) {
|
||||
usage(stderr, program);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
keyname = strdup(argv[0]);
|
||||
|
||||
keyfp = fopen(keyname, "r");
|
||||
if (!keyfp) {
|
||||
fprintf(stderr, "Failed to open public key file %s: %s\n", keyname,
|
||||
strerror(errno));
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
result = ldns_rr_new_frm_fp(&k, keyfp, 0, &origin, NULL);
|
||||
/* what does this while loop do? */
|
||||
while (result == LDNS_STATUS_SYNTAX_ORIGIN) {
|
||||
result = ldns_rr_new_frm_fp(&k, keyfp, 0, &origin, NULL);
|
||||
}
|
||||
if (result != LDNS_STATUS_OK) {
|
||||
fprintf(stderr, "Could not read public key from file %s: %s\n", keyname, ldns_get_errorstr_by_id(result));
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
fclose(keyfp);
|
||||
|
||||
flags = ldns_read_uint16(ldns_rdf_data(ldns_rr_dnskey_flags(k)));
|
||||
flags |= LDNS_KEY_REVOKE_KEY;
|
||||
|
||||
if (!ldns_rr_dnskey_set_flags(k,
|
||||
ldns_native2rdf_int16(LDNS_RDF_TYPE_INT16, flags)))
|
||||
{
|
||||
fprintf(stderr, "Revocation failed\n");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
/* print the public key RR to .key */
|
||||
|
||||
if (nofile)
|
||||
ldns_rr_print(stdout,k);
|
||||
else {
|
||||
keyfp = fopen(keyname, "w");
|
||||
if (!keyfp) {
|
||||
fprintf(stderr, "Unable to open %s: %s\n", keyname,
|
||||
strerror(errno));
|
||||
exit(EXIT_FAILURE);
|
||||
} else {
|
||||
ldns_rr_print(keyfp, k);
|
||||
fclose(keyfp);
|
||||
fprintf(stdout, "DNSKEY revoked\n");
|
||||
}
|
||||
}
|
||||
|
||||
free(keyname);
|
||||
ldns_rr_free(k);
|
||||
|
||||
exit(EXIT_SUCCESS);
|
||||
}
|
||||
30
zonemaster-ldns/ldns/examples/ldns-rrsig.1
Normal file
30
zonemaster-ldns/ldns/examples/ldns-rrsig.1
Normal file
@@ -0,0 +1,30 @@
|
||||
.TH ldns-rrsig 1 "27 Apr 2005"
|
||||
.SH NAME
|
||||
ldns-rrsig \- print out the inception and expiration dates in human
|
||||
readable form
|
||||
.SH SYNOPSIS
|
||||
.B ldns-rrsig
|
||||
.IR domain
|
||||
[
|
||||
.IR type
|
||||
]
|
||||
|
||||
.SH DESCRIPTION
|
||||
\fBldns-rrsig\fR is used to print the expiration and inception date of
|
||||
a RRSIG. The first argument is a domain name. \fBldns-rrsig\fR will
|
||||
query the authoritative servers for that domain to get a list of RRSIGs.
|
||||
It will then print out the inception and expiration dates for the RRSIG
|
||||
covering the SOA record.
|
||||
.PP
|
||||
If the second argument \fBtype\fR is given the RRSIG covering that type will be shown.
|
||||
|
||||
.SH AUTHOR
|
||||
Written by the ldns team as an example for ldns usage.
|
||||
|
||||
.SH REPORTING BUGS
|
||||
Report bugs to <dns-team@nlnetlabs.nl>.
|
||||
|
||||
.SH COPYRIGHT
|
||||
Copyright (C) 2005 NLnet Labs. This is free software. There is NO
|
||||
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR
|
||||
PURPOSE.
|
||||
219
zonemaster-ldns/ldns/examples/ldns-rrsig.c
Normal file
219
zonemaster-ldns/ldns/examples/ldns-rrsig.c
Normal file
@@ -0,0 +1,219 @@
|
||||
/*
|
||||
* ldns-rrsig prints out the inception and expiration dates in a more readable
|
||||
* way than the normal RRSIG presentation format
|
||||
*
|
||||
* for a particularly domain
|
||||
* (c) NLnet Labs, 2005 - 2008
|
||||
* See the file LICENSE for the license
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include <ldns/ldns.h>
|
||||
|
||||
static int
|
||||
usage(FILE *fp, char *prog) {
|
||||
fprintf(fp, "%s domain [type]\n", prog);
|
||||
fprintf(fp, " print out the inception and expiration dates\n");
|
||||
fprintf(fp, " in a more human readable form\n");
|
||||
fprintf(fp, " <type>\tquery for RRSIG(<type>), defaults to SOA\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
main(int argc, char *argv[])
|
||||
{
|
||||
ldns_resolver *res;
|
||||
ldns_resolver *localres;
|
||||
ldns_rdf *domain;
|
||||
ldns_pkt *p;
|
||||
ldns_rr_list *rrsig;
|
||||
ldns_rr_list *rrsig_type;
|
||||
ldns_rr_list *ns;
|
||||
ldns_rr_list *ns_ip;
|
||||
uint8_t i, j;
|
||||
ldns_rr_type t;
|
||||
const char * type_name;
|
||||
struct tm incep, expir;
|
||||
char incep_buf[26];
|
||||
char expir_buf[26];
|
||||
ldns_status s;
|
||||
time_t now = time(NULL);
|
||||
|
||||
p = NULL;
|
||||
rrsig = NULL;
|
||||
rrsig_type = NULL;
|
||||
domain = NULL;
|
||||
|
||||
/* option parsing */
|
||||
|
||||
if (argc < 2) {
|
||||
usage(stdout, argv[0]);
|
||||
exit(EXIT_FAILURE);
|
||||
} else {
|
||||
/* create a rdf from the command line arg */
|
||||
domain = ldns_dname_new_frm_str(argv[1]);
|
||||
if (!domain) {
|
||||
usage(stdout, argv[0]);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
}
|
||||
|
||||
if (argc == 3) {
|
||||
/* optional type arg */
|
||||
type_name = argv[2];
|
||||
t = ldns_rdf2rr_type(
|
||||
ldns_rdf_new_frm_str(LDNS_RDF_TYPE_TYPE, type_name));
|
||||
if (t == 0) {
|
||||
fprintf(stderr, " *** %s is not a valid RR type\n", type_name);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
} else {
|
||||
t = LDNS_RR_TYPE_SOA;
|
||||
type_name = "SOA";
|
||||
}
|
||||
|
||||
/* create a new resolver from /etc/resolv.conf */
|
||||
s = ldns_resolver_new_frm_file(&localres, NULL);
|
||||
if (s != LDNS_STATUS_OK) {
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
/* first get the nameserver of the domain in question */
|
||||
p = ldns_resolver_query(localres, domain, LDNS_RR_TYPE_NS,
|
||||
LDNS_RR_CLASS_IN, LDNS_RD);
|
||||
if (!p) {
|
||||
fprintf(stderr," *** Could not find any nameserver for %s", argv[1]);
|
||||
ldns_resolver_deep_free(localres);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
ns = ldns_pkt_rr_list_by_type(p, LDNS_RR_TYPE_NS, LDNS_SECTION_ANSWER);
|
||||
|
||||
if (!ns) {
|
||||
fprintf(stderr," *** Could not find any nameserver for %s", argv[1]);
|
||||
ldns_pkt_free(p);
|
||||
ldns_resolver_deep_free(localres);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
/* use our local resolver to resolv the names in the for usage in our
|
||||
* new resolver */
|
||||
res = ldns_resolver_new();
|
||||
if (!res) {
|
||||
ldns_pkt_free(p);
|
||||
ldns_resolver_deep_free(localres);
|
||||
ldns_rr_list_deep_free(ns);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
for(i = 0; i < ldns_rr_list_rr_count(ns); i++) {
|
||||
ns_ip = ldns_get_rr_list_addr_by_name(localres,
|
||||
ldns_rr_ns_nsdname(ldns_rr_list_rr(ns, i)),
|
||||
LDNS_RR_CLASS_IN, LDNS_RD);
|
||||
/* add these to new resolver */
|
||||
for(j = 0; j < ldns_rr_list_rr_count(ns_ip); j++) {
|
||||
if (ldns_resolver_push_nameserver(res,
|
||||
ldns_rr_a_address(ldns_rr_list_rr(ns_ip, j))) != LDNS_STATUS_OK) {
|
||||
printf("Error adding nameserver to resolver\n");
|
||||
ldns_pkt_free(p);
|
||||
ldns_resolver_deep_free(res);
|
||||
ldns_resolver_deep_free(localres);
|
||||
ldns_rr_list_deep_free(ns);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
}
|
||||
ldns_rr_list_deep_free(ns_ip);
|
||||
|
||||
}
|
||||
|
||||
/* enable DNSSEC */
|
||||
ldns_resolver_set_dnssec(res, true);
|
||||
/* also set CD, we want EVERYTHING! */
|
||||
ldns_resolver_set_dnssec_cd(res, true);
|
||||
|
||||
/* use the resolver to send it a query for the soa
|
||||
* records of the domain given on the command line
|
||||
*/
|
||||
ldns_pkt_free(p);
|
||||
p = ldns_resolver_query(res, domain, LDNS_RR_TYPE_RRSIG, LDNS_RR_CLASS_IN, LDNS_RD);
|
||||
|
||||
ldns_rdf_deep_free(domain);
|
||||
|
||||
if (!p) {
|
||||
ldns_resolver_deep_free(localres);
|
||||
ldns_rr_list_deep_free(ns);
|
||||
exit(EXIT_FAILURE);
|
||||
} else {
|
||||
/* retrieve the RRSIG records from the answer section of that
|
||||
* packet
|
||||
*/
|
||||
rrsig = ldns_pkt_rr_list_by_type(p, LDNS_RR_TYPE_RRSIG, LDNS_SECTION_ANSWER);
|
||||
if (!rrsig) {
|
||||
fprintf(stderr,
|
||||
" *** invalid answer name %s after RRSIG query for %s\n",
|
||||
argv[1], argv[1]);
|
||||
ldns_pkt_free(p);
|
||||
ldns_resolver_deep_free(res);
|
||||
ldns_rr_list_deep_free(ns);
|
||||
exit(EXIT_FAILURE);
|
||||
} else {
|
||||
rrsig_type = ldns_rr_list_new();
|
||||
|
||||
for(i = 0; i < ldns_rr_list_rr_count(rrsig); i++) {
|
||||
if (ldns_rdf2rr_type(
|
||||
ldns_rr_rrsig_typecovered(
|
||||
ldns_rr_list_rr(rrsig, i))) == t) {
|
||||
ldns_rr_list_push_rr(rrsig_type,
|
||||
ldns_rr_list_rr(rrsig, i));
|
||||
}
|
||||
}
|
||||
if (ldns_rr_list_rr_count(rrsig_type) == 0) {
|
||||
fprintf(stderr, " *** No RRSIG(%s) type found\n",
|
||||
type_name);
|
||||
ldns_resolver_deep_free(localres);
|
||||
ldns_resolver_deep_free(res);
|
||||
ldns_pkt_free(p);
|
||||
ldns_rr_list_deep_free(ns);
|
||||
ldns_rr_list_free(rrsig);
|
||||
ldns_rr_list_deep_free(rrsig_type);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
for(i = 0; i < ldns_rr_list_rr_count(rrsig_type); i++) {
|
||||
memset(&incep, 0, sizeof(incep));
|
||||
if (ldns_serial_arithmetics_gmtime_r(
|
||||
ldns_rdf2native_time_t(
|
||||
ldns_rr_rrsig_inception(
|
||||
ldns_rr_list_rr(rrsig_type, i))),
|
||||
now, &incep
|
||||
)
|
||||
&& asctime_r(&incep, incep_buf)) {
|
||||
incep_buf[24] = '\0';
|
||||
} else {
|
||||
incep_buf[0] = '\0';
|
||||
}
|
||||
memset(&expir, 0, sizeof(expir));
|
||||
if (ldns_serial_arithmetics_gmtime_r(
|
||||
ldns_rdf2native_time_t(
|
||||
ldns_rr_rrsig_expiration(
|
||||
ldns_rr_list_rr(rrsig_type, i))),
|
||||
now, &expir
|
||||
)
|
||||
&& asctime_r(&expir, expir_buf)) {
|
||||
expir_buf[24] = '\0';
|
||||
} else {
|
||||
expir_buf[0] = '\0';
|
||||
}
|
||||
|
||||
fprintf(stdout, "%s RRSIG(%s): %s - %s\n",
|
||||
argv[1], type_name, incep_buf, expir_buf);
|
||||
}
|
||||
ldns_rr_list_free(rrsig);
|
||||
ldns_rr_list_deep_free(rrsig_type);
|
||||
}
|
||||
}
|
||||
ldns_pkt_free(p);
|
||||
ldns_resolver_deep_free(localres);
|
||||
ldns_resolver_deep_free(res);
|
||||
ldns_rr_list_deep_free(ns);
|
||||
return 0;
|
||||
}
|
||||
194
zonemaster-ldns/ldns/examples/ldns-signzone.1
Normal file
194
zonemaster-ldns/ldns/examples/ldns-signzone.1
Normal file
@@ -0,0 +1,194 @@
|
||||
.TH ldns-signzone 1 "13 March 2018"
|
||||
.SH NAME
|
||||
ldns-signzone \- sign a zonefile with DNSSEC data
|
||||
.SH SYNOPSIS
|
||||
.B ldns-signzone
|
||||
[
|
||||
.IR OPTIONS
|
||||
]
|
||||
.IR ZONEFILE
|
||||
.IR
|
||||
KEY
|
||||
[KEY
|
||||
[KEY] ...
|
||||
]
|
||||
|
||||
.SH DESCRIPTION
|
||||
|
||||
\fBldns-signzone\fR is used to generate a DNSSEC signed zone. When run it
|
||||
will create a new zonefile that contains RRSIG and NSEC resource records, as
|
||||
specified in RFC 4033, RFC 4034 and RFC 4035.
|
||||
|
||||
Keys must be specified by their base name (i.e. without .private). If
|
||||
the DNSKEY that belongs to the key in the .private file is not present
|
||||
in the zone, it will be read from the file <base name>.key. If that
|
||||
file does not exist, the DNSKEY value will be generated from the
|
||||
private key.
|
||||
|
||||
Multiple keys can be specified, Key Signing Keys are used as such when
|
||||
they are either already present in the zone, or specified in a .key
|
||||
file, and have the KSK bit set.
|
||||
|
||||
.SH OPTIONS
|
||||
.TP
|
||||
\fB-b\fR
|
||||
Augments the zone and the RR's with extra comment texts for a more readable
|
||||
layout, easier to debug. DS records will have a bubblebabble version of
|
||||
the data in the comment text, NSEC3 records will have the unhashed owner names
|
||||
in the comment text.
|
||||
|
||||
Without this option, only DNSKEY RR's will have their Key Tag annotated in
|
||||
the comment text.
|
||||
|
||||
.TP
|
||||
\fB-d\fR
|
||||
Normally, if the DNSKEY RR for a key that is used to sign the zone is
|
||||
not found in the zone file, it will be read from .key, or derived from
|
||||
the private key (in that order). This option turns that feature off,
|
||||
so that only the signatures are added to the zone.
|
||||
|
||||
.TP
|
||||
\fB-e\fR \fIdate\fR
|
||||
Set expiration date of the signatures to this date, the format can be
|
||||
YYYYMMDD[hhmmss], or a timestamp.
|
||||
|
||||
.TP
|
||||
\fB-f\fR \fIfile\fR
|
||||
Use this file to store the signed zone in (default <originalfile>.signed)
|
||||
|
||||
.TP
|
||||
\fB-i\fR \fIdate\fR
|
||||
Set inception date of the signatures to this date, the format can be
|
||||
YYYYMMDD[hhmmss], or a timestamp.
|
||||
|
||||
.TP
|
||||
\fB-o\fR \fIorigin\fR
|
||||
Use this as the origin of the zone
|
||||
|
||||
.TP
|
||||
\fB-u\fR
|
||||
set SOA serial to the number of seconds since 1-1-1970
|
||||
|
||||
.TP
|
||||
\fB-v\fR
|
||||
Print the version and exit
|
||||
|
||||
.TP
|
||||
\fB-z\fR \fI[scheme:]hash\fR
|
||||
Calculate the zone's digest and add those as ZONEMD RRs. The (optional)
|
||||
`scheme' must be `simple` (or 1) and `hash' should be `sha384' (or 1) or
|
||||
`sha512' (or 2). This option can be given more than once.
|
||||
|
||||
.TP
|
||||
\fB-Z\fR
|
||||
Allow ZONEMDs to be added without signing
|
||||
|
||||
.TP
|
||||
\fB-A\fR
|
||||
Sign the DNSKEY record with all keys. By default it is signed with a
|
||||
minimal number of keys, to keep the response size for the DNSKEY query
|
||||
small, and only the SEP keys that are passed are used. If there are no
|
||||
SEP keys, the DNSKEY RRset is signed with the non\-SEP keys. This option
|
||||
turns off the default and all keys are used to sign the DNSKEY RRset.
|
||||
|
||||
.TP
|
||||
\fB-U\fR
|
||||
Sign with every unique algorithm in the provided keys. The DNSKEY set
|
||||
is signed with all the SEP keys, plus all the non\-SEP keys that have an
|
||||
algorithm that was not presen in the SEP key set.
|
||||
|
||||
.TP
|
||||
\fB-E\fR \fIname\fR
|
||||
Use the EVP cryptographic engine with the given name for signing. This
|
||||
can have some extra options; see ENGINE OPTIONS for more information.
|
||||
|
||||
.TP
|
||||
\fB-K\fR \fIalgorithm-id,key-id\fR
|
||||
|
||||
Use the key `key-id' as the signing key for algorithm `algorithm-id' as
|
||||
a Key Signing Key (KSK). This option is used when you use an OpenSSL engine,
|
||||
see ENGINE OPTIONS for more information.
|
||||
|
||||
.TP
|
||||
\fB-k\fR \fIalgorithm-id,key-id\fR
|
||||
Use the key `key-id' as the signing key for algorithm `algorithm-id' as
|
||||
a Zone Signing Key (ZSK). This option is used when you use an OpenSSL
|
||||
engine, see ENGINE OPTIONS for more information.
|
||||
|
||||
.TP
|
||||
\fB-n\fR
|
||||
Use NSEC3 instead of NSEC.
|
||||
|
||||
.TP
|
||||
If you use NSEC3, you can specify the following extra options:
|
||||
|
||||
.TP
|
||||
\fB-a\fR \fIalgorithm\fR
|
||||
Algorithm used to create the hashed NSEC3 owner names
|
||||
|
||||
.TP
|
||||
\fB-p\fR
|
||||
Opt-out. All NSEC3 records in the zone will have the Opt-out flag set. After signing, you can add insecure delegations to the signed zone.
|
||||
|
||||
.TP
|
||||
\fB-s\fR \fIstring\fR
|
||||
Salt
|
||||
|
||||
.TP
|
||||
\fB-t\fR \fInumber\fR
|
||||
Number of hash iterations
|
||||
|
||||
.SH ENGINE OPTIONS
|
||||
You can modify the possible engines, if supported, by setting an
|
||||
OpenSSL configuration file. This is done through the environment
|
||||
variable OPENSSL_CONF.
|
||||
|
||||
The key options (\-k and \-K) work as follows: you specify a DNSSEC
|
||||
algorithm (using its symbolic name, for instance, RSASHA256
|
||||
or its numeric identifier, for instance, 8), followed by a comma
|
||||
and a key identifier (white space is not allowed between the
|
||||
algorithm and the comma and between the comma and the key identifier).
|
||||
|
||||
The key identifier can be any of the following:
|
||||
|
||||
<id>
|
||||
<slot>:<id>
|
||||
id_<id>
|
||||
slot_<slot>-id_<id>
|
||||
label_<label>
|
||||
slot_<slot>-label_<label>
|
||||
|
||||
Where '<id>' is the PKCS #11 key identifier in hexadecimal
|
||||
notation, '<label>' is the PKCS #11 human-readable label, and '<slot>'
|
||||
is the slot number where the token is present.
|
||||
|
||||
More recent versions of OpenSSL engines may support
|
||||
the PKCS #11 URI scheme (RFC 7512),
|
||||
please consult your engine's documentation.
|
||||
|
||||
If not already present, a DNSKEY RR is generated from the key
|
||||
data, and added to the zone.
|
||||
|
||||
.SH EXAMPLES
|
||||
|
||||
.TP
|
||||
ldns-signzone nlnetlabs.nl Knlnetlabs.nl.+005+12273
|
||||
Sign the zone in the file 'nlnetlabs.nl' with the key in the
|
||||
files 'Knlnetlabs.nl.+005+12273.private'. If the DNSKEY is not present
|
||||
in the zone, use the key in the
|
||||
file 'Knlnetlabs.nl.+005+12273.key'. If that is not present, generate
|
||||
one with default values from 'Knlnetlabs.nl.+005+12273.private'.
|
||||
|
||||
|
||||
.SH AUTHORS
|
||||
Written by the ldns team as an example for ldns usage.
|
||||
.br
|
||||
Portions of engine support by Vadim Penzin <vadim@penzin.net>.
|
||||
|
||||
.SH REPORTING BUGS
|
||||
Report bugs to <dns-team@nlnetlabs.nl>.
|
||||
|
||||
.SH COPYRIGHT
|
||||
Copyright (C) 2005-2008 NLnet Labs. This is free software. There is NO
|
||||
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR
|
||||
PURPOSE.
|
||||
1150
zonemaster-ldns/ldns/examples/ldns-signzone.c
Normal file
1150
zonemaster-ldns/ldns/examples/ldns-signzone.c
Normal file
File diff suppressed because it is too large
Load Diff
41
zonemaster-ldns/ldns/examples/ldns-test-edns.1
Normal file
41
zonemaster-ldns/ldns/examples/ldns-test-edns.1
Normal file
@@ -0,0 +1,41 @@
|
||||
.TH ldns-test-edns 1 "14 Dec 2010"
|
||||
.SH NAME
|
||||
ldns-test-edns \- test if dns cache supports EDNS and DNSSEC.
|
||||
.SH SYNOPSIS
|
||||
.B ldns-test-edns
|
||||
[
|
||||
.IR -i
|
||||
]
|
||||
{
|
||||
.IR ip
|
||||
}
|
||||
.SH DESCRIPTION
|
||||
\fBldns-test-edns\fR tests a DNS cache and checks if it supports EDNS0 and
|
||||
DNSSEC types so that it can be used as a dnssec-enabled DNS cache. It sends
|
||||
two queries to the cache, one for the root key and one for a DS record.
|
||||
These must succeed, the answer must have EDNS, that type and signatures.
|
||||
.PP
|
||||
If the IP address is good for DNSSEC, it is printed with 'OK'. Otherwise
|
||||
short description is given of the failure.
|
||||
If OK is given, the cache should be good to use as a cache for a local
|
||||
configured DNSSEC validator.
|
||||
.PP
|
||||
The tool assumes the root is signed and Sweden is signed.
|
||||
Also, the queries are sent with the CD flag, the tool does not check that the
|
||||
results are validated, but that they \fBcan\fR be validated.
|
||||
.SH OPTIONS
|
||||
\fB-i\fR option enables a mode where the working IP addresses are printed
|
||||
after another, with no other explanations, and if none work or no IP addresses
|
||||
are on the input, 'off' is printed.
|
||||
.PP
|
||||
\fBldns-test-edns\fR takes one or more IP addresses, it checks them in turn.
|
||||
IPv4 and IPv6 addresses can be given. The exit value is for the last checked
|
||||
IP address: 0 is OK, 1 is failure, 2 is some sort of network failure.
|
||||
.SH AUTHOR
|
||||
Written by the ldns team as an example for ldns usage.
|
||||
.SH REPORTING BUGS
|
||||
Report bugs to <dns-team@nlnetlabs.nl>.
|
||||
.SH COPYRIGHT
|
||||
Copyright (C) 2010 NLnet Labs. This is free software. There is NO
|
||||
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR
|
||||
PURPOSE.
|
||||
264
zonemaster-ldns/ldns/examples/ldns-test-edns.c
Normal file
264
zonemaster-ldns/ldns/examples/ldns-test-edns.c
Normal file
@@ -0,0 +1,264 @@
|
||||
/*
|
||||
* ldns-test-edns tries to get DNSKEY and RRSIG from an IP address.
|
||||
* This can be used to test if a DNS cache supports DNSSEC (caching RRSIGs),
|
||||
* i.e. for automatic configuration utilities or when you get a new DNS cache
|
||||
* from DHCP and wonder if your local validator could use that as a cache.
|
||||
*
|
||||
* (c) NLnet Labs 2010
|
||||
* See the file LICENSE for the license
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
#include "errno.h"
|
||||
#include <ldns/ldns.h>
|
||||
|
||||
/** print error details */
|
||||
static int verb = 1;
|
||||
|
||||
static struct sockaddr_in6* cast_sockaddr_storage2sockaddr_in6(
|
||||
struct sockaddr_storage* s)
|
||||
{
|
||||
return (struct sockaddr_in6*)s;
|
||||
}
|
||||
|
||||
static struct sockaddr_in* cast_sockaddr_storage2sockaddr_in(
|
||||
struct sockaddr_storage* s)
|
||||
{
|
||||
return (struct sockaddr_in*)s;
|
||||
}
|
||||
|
||||
/** parse IP address */
|
||||
static int
|
||||
convert_addr(char* str, int p, struct sockaddr_storage* addr, socklen_t* len)
|
||||
{
|
||||
#ifdef AF_INET6
|
||||
if(strchr(str, ':')) {
|
||||
*len = (socklen_t)sizeof(struct sockaddr_in6);
|
||||
cast_sockaddr_storage2sockaddr_in6(addr)->sin6_family =
|
||||
AF_INET6;
|
||||
cast_sockaddr_storage2sockaddr_in6(addr)->sin6_port =
|
||||
htons((uint16_t)p);
|
||||
if(inet_pton(AF_INET6, str,
|
||||
&((struct sockaddr_in6*)addr)->sin6_addr) == 1)
|
||||
return 1;
|
||||
} else {
|
||||
#endif
|
||||
*len = (socklen_t)sizeof(struct sockaddr_in);
|
||||
#ifndef S_SPLINT_S
|
||||
cast_sockaddr_storage2sockaddr_in(addr)->sin_family =
|
||||
AF_INET;
|
||||
#endif
|
||||
cast_sockaddr_storage2sockaddr_in(addr)->sin_port =
|
||||
htons((uint16_t)p);
|
||||
if(inet_pton(AF_INET, str,
|
||||
&((struct sockaddr_in*)addr)->sin_addr) == 1)
|
||||
return 1;
|
||||
#ifdef AF_INET6
|
||||
}
|
||||
#endif
|
||||
if(verb) printf("error: cannot parse IP address %s\n", str);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/** create a query to test */
|
||||
static ldns_buffer*
|
||||
make_query(const char* nm, int tp)
|
||||
{
|
||||
/* with EDNS DO and CDFLAG */
|
||||
ldns_buffer* b = ldns_buffer_new(512);
|
||||
ldns_pkt* p;
|
||||
ldns_status s;
|
||||
if(!b) {
|
||||
if(verb) printf("error: out of memory\n");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
s = ldns_pkt_query_new_frm_str(&p, nm, tp, LDNS_RR_CLASS_IN,
|
||||
(uint16_t)(LDNS_RD|LDNS_CD));
|
||||
if(s != LDNS_STATUS_OK) {
|
||||
if(verb) printf("error: %s\n", ldns_get_errorstr_by_id(s));
|
||||
ldns_buffer_free(b);
|
||||
return NULL;
|
||||
}
|
||||
if(!p) {
|
||||
if(verb) printf("error: out of memory\n");
|
||||
ldns_buffer_free(b);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
ldns_pkt_set_edns_do(p, 1);
|
||||
ldns_pkt_set_edns_udp_size(p, 4096);
|
||||
ldns_pkt_set_id(p, ldns_get_random());
|
||||
if( (s=ldns_pkt2buffer_wire(b, p)) != LDNS_STATUS_OK) {
|
||||
if(verb) printf("error: %s\n", ldns_get_errorstr_by_id(s));
|
||||
ldns_pkt_free(p);
|
||||
ldns_buffer_free(b);
|
||||
return NULL;
|
||||
}
|
||||
ldns_pkt_free(p);
|
||||
|
||||
return b;
|
||||
}
|
||||
|
||||
/** try 3 times to get an EDNS reply from the server, exponential backoff */
|
||||
static int
|
||||
get_packet(struct sockaddr_storage* addr, socklen_t len, const char* nm,
|
||||
int tp, uint8_t **wire, size_t* wlen)
|
||||
{
|
||||
struct timeval t;
|
||||
ldns_buffer* qbin;
|
||||
ldns_status s;
|
||||
int tries = 0;
|
||||
|
||||
memset(&t, 0, sizeof(t));
|
||||
t.tv_usec = 100 * 1000; /* 100 milliseconds (then 200, 400, 800) */
|
||||
|
||||
qbin = make_query(nm, tp);
|
||||
if(!qbin)
|
||||
return 0;
|
||||
while(tries < 4) {
|
||||
tries ++;
|
||||
s = ldns_udp_send(wire, qbin, addr, len, t, wlen);
|
||||
if(s != LDNS_STATUS_NETWORK_ERR) {
|
||||
break;
|
||||
}
|
||||
t.tv_usec *= 2;
|
||||
if(t.tv_usec > 1000*1000) {
|
||||
t.tv_usec -= 1000*1000;
|
||||
t.tv_sec += 1;
|
||||
}
|
||||
}
|
||||
ldns_buffer_free(qbin);
|
||||
if(tries == 4) {
|
||||
if(verb) printf("timeout\n");
|
||||
return 0;
|
||||
}
|
||||
if(s != LDNS_STATUS_OK) {
|
||||
if(verb) printf("error: %s\n", ldns_get_errorstr_by_id(s));
|
||||
return 0;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
/** test if type is present in returned packet */
|
||||
static int
|
||||
check_type_in_answer(ldns_pkt* p, int t)
|
||||
{
|
||||
ldns_rr_list *l = ldns_pkt_rr_list_by_type(p, t, LDNS_SECTION_ANSWER);
|
||||
if(!l) {
|
||||
char* s = ldns_rr_type2str(t);
|
||||
if(verb) printf("no DNSSEC %s\n", s?s:"(out of memory)");
|
||||
LDNS_FREE(s);
|
||||
return 0;
|
||||
}
|
||||
ldns_rr_list_deep_free(l);
|
||||
return 1;
|
||||
}
|
||||
|
||||
/** check the packet and make sure that EDNS and DO and the type and RRSIG */
|
||||
static int
|
||||
check_packet(uint8_t* wire, size_t len, int tp)
|
||||
{
|
||||
ldns_pkt *p = NULL;
|
||||
ldns_status s;
|
||||
if( (s=ldns_wire2pkt(&p, wire, len)) != LDNS_STATUS_OK) {
|
||||
if(verb) printf("error: %s\n", ldns_get_errorstr_by_id(s));
|
||||
goto failed;
|
||||
}
|
||||
if(!p) {
|
||||
if(verb) printf("error: out of memory\n");
|
||||
goto failed;
|
||||
}
|
||||
|
||||
/* does DNS work? */
|
||||
if(ldns_pkt_get_rcode(p) != LDNS_RCODE_NOERROR) {
|
||||
char* r = ldns_pkt_rcode2str(ldns_pkt_get_rcode(p));
|
||||
if(verb) printf("no answer, %s\n", r?r:"(out of memory)");
|
||||
LDNS_FREE(r);
|
||||
goto failed;
|
||||
}
|
||||
|
||||
/* test EDNS0 presence, of OPT record */
|
||||
/* LDNS forgets during pkt parse, but we test the ARCOUNT;
|
||||
* 0 additional means no EDNS(on the wire), and after parsing the
|
||||
* same additional RRs as before means no EDNS OPT */
|
||||
if(LDNS_ARCOUNT(wire) == 0 ||
|
||||
ldns_pkt_arcount(p) == LDNS_ARCOUNT(wire)) {
|
||||
if(verb) printf("no EDNS\n");
|
||||
goto failed;
|
||||
}
|
||||
|
||||
/* test if the type, RRSIG present */
|
||||
if(!check_type_in_answer(p, tp) ||
|
||||
!check_type_in_answer(p, LDNS_RR_TYPE_RRSIG)) {
|
||||
goto failed;
|
||||
}
|
||||
|
||||
LDNS_FREE(wire);
|
||||
ldns_pkt_free(p);
|
||||
return 1;
|
||||
failed:
|
||||
LDNS_FREE(wire);
|
||||
ldns_pkt_free(p);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/** check EDNS at this IP and port */
|
||||
static int
|
||||
check_edns_ip(char* ip, int port, int info)
|
||||
{
|
||||
struct sockaddr_storage addr;
|
||||
socklen_t len = 0;
|
||||
uint8_t* wire;
|
||||
size_t wlen;
|
||||
memset(&addr, 0, sizeof(addr));
|
||||
if(verb) printf("%s ", ip);
|
||||
if(!convert_addr(ip, port, &addr, &len))
|
||||
return 2;
|
||||
/* try to send 3 times to the IP address, test root key */
|
||||
if(!get_packet(&addr, len, ".", LDNS_RR_TYPE_DNSKEY, &wire, &wlen))
|
||||
return 2;
|
||||
if(!check_packet(wire, wlen, LDNS_RR_TYPE_DNSKEY))
|
||||
return 1;
|
||||
/* check support for caching type DS for chains of trust */
|
||||
if(!get_packet(&addr, len, "se.", LDNS_RR_TYPE_DS, &wire, &wlen))
|
||||
return 2;
|
||||
if(!check_packet(wire, wlen, LDNS_RR_TYPE_DS))
|
||||
return 1;
|
||||
if(verb) printf("OK\n");
|
||||
if(info) printf(" %s", ip);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
main(int argc, char **argv)
|
||||
{
|
||||
int i, r=0, info=0, ok=0;
|
||||
#ifdef USE_WINSOCK
|
||||
WSADATA wsa_data;
|
||||
if(WSAStartup(MAKEWORD(2,2), &wsa_data) != 0) {
|
||||
printf("WSAStartup failed\n"); exit(1);
|
||||
}
|
||||
#endif
|
||||
if (argc < 2 || strncmp(argv[1], "-h", 3) == 0) {
|
||||
printf("Usage: ldns-test-edns [-i] {ip address}\n");
|
||||
printf("Tests if the DNS cache at IP address supports EDNS.\n");
|
||||
printf("if it works, print IP address OK.\n");
|
||||
printf("-i: print IPs that are OK or print 'off'.\n");
|
||||
printf("exit value, last IP is 0:OK, 1:fail, 2:net error.\n");
|
||||
exit(1);
|
||||
}
|
||||
if(strcmp(argv[1], "-i") == 0) {
|
||||
info = 1;
|
||||
verb = 0;
|
||||
}
|
||||
|
||||
for(i=1+info; i<argc; i++) {
|
||||
r = check_edns_ip(argv[i], LDNS_PORT, info);
|
||||
if(r == 0)
|
||||
ok++;
|
||||
}
|
||||
if(info && !ok)
|
||||
printf("off\n");
|
||||
return r;
|
||||
}
|
||||
135
zonemaster-ldns/ldns/examples/ldns-testns.1
Normal file
135
zonemaster-ldns/ldns/examples/ldns-testns.1
Normal file
@@ -0,0 +1,135 @@
|
||||
.TH ldns-testns 1 "14 Dec 2006"
|
||||
.SH NAME
|
||||
ldns-testns \- simple fake nameserver tool
|
||||
.SH SYNOPSIS
|
||||
.B ldns-testns
|
||||
[
|
||||
.IR OPTION
|
||||
]
|
||||
.IR datafile
|
||||
|
||||
.SH DESCRIPTION
|
||||
\fBldns-testns\fR can be used to provide answers to DNS queries for
|
||||
testing. The answers are premade, and can be tailored to testing
|
||||
needs. The answers can be wildly invalid or unparsable.
|
||||
|
||||
This program is a debugging aid. It is not efficient, especially
|
||||
with a long config file, but it can give any reply to any query.
|
||||
This can help the developer pre-script replies for queries.
|
||||
|
||||
It listens to IP4 UDP and TCP by default.
|
||||
You can specify a packet RR by RR with header flags to return.
|
||||
|
||||
ldns-testns is not meant for production use.
|
||||
|
||||
.SH OPTIONS
|
||||
.TP
|
||||
\fB-r\fR
|
||||
Listens to a random port. The port number is printed to stdout.
|
||||
|
||||
.TP
|
||||
\fB-p\fR \fIport\fR
|
||||
Listens to the specified port.
|
||||
|
||||
.TP
|
||||
\fB-f\fR \fInum\fR
|
||||
Forks this number of additional instances that serve the same ports and
|
||||
same datafile. They do not exit; printed is 'forked pid: <num>' and you
|
||||
have to kill them yourself.
|
||||
|
||||
.TP
|
||||
\fB-v\fR
|
||||
Outputs more debug information. It is possible to give this option multiple
|
||||
times to increase verbosity level.
|
||||
|
||||
.TP
|
||||
\fB-6\fR
|
||||
Bind to IP6 address instead of IP4. Use together with -p.
|
||||
|
||||
.TP
|
||||
\fBdatafile\fR
|
||||
The data file is read on start up. It contains queries and the packets
|
||||
that should be sent in answer to those queries. The data file format is
|
||||
explained below.
|
||||
|
||||
.SH DATA FILE FORMAT
|
||||
The data file format has ';' to denote comment. A number of entries
|
||||
are processed first to last. The first matching entry is used to answer
|
||||
the query with. This is a line based format. DNS resource records
|
||||
are entered in zone-file format.
|
||||
|
||||
You can use $ORIGIN and $TTL directives. Zone file '(' and ')' to span
|
||||
multiple lines are not allowed.
|
||||
|
||||
$ORIGIN origin
|
||||
$TTL default_ttl
|
||||
|
||||
ENTRY_BEGIN
|
||||
|
||||
; first give MATCH lines, that say what queries are matched
|
||||
; by this entry.
|
||||
; 'opcode' makes the query match the opcode from the reply
|
||||
; if you leave it out, any opcode matches this entry.
|
||||
; 'qtype' makes the query match the qtype from the reply
|
||||
; 'qname' makes the query match the qname from the reply
|
||||
; 'serial=1023' makes the query match if ixfr serial is 1023.
|
||||
|
||||
MATCH [opcode] [qtype] [qname] [serial=<value>]
|
||||
MATCH [UDP|TCP]
|
||||
MATCH ...
|
||||
|
||||
; Then the REPLY header is specified.
|
||||
|
||||
REPLY opcode, rcode or flags.
|
||||
(opcode) QUERY IQUERY STATUS NOTIFY UPDATE
|
||||
(rcode) NOERROR FORMERR SERVFAIL NXDOMAIN NOTIMPL YXDOMAIN
|
||||
YXRRSET NXRRSET NOTAUTH NOTZONE
|
||||
(flags) QR AA TC RD CD RA AD
|
||||
|
||||
REPLY ...
|
||||
|
||||
; any additional actions to do.
|
||||
|
||||
ADJUST copy_id ; 'copy_id' copies the ID from the query to the answer.
|
||||
|
||||
; 'sleep=10' sleeps for 10 seconds before giving the answer (TCP is open)
|
||||
|
||||
ADJUST [sleep=<num>] ; sleep before giving any reply
|
||||
ADJUST [packet_sleep=<num>] ; sleep before this packet in sequence
|
||||
|
||||
SECTION QUESTION
|
||||
<RRs, one per line> ; the RRcount is determined automatically.
|
||||
|
||||
SECTION ANSWER
|
||||
<RRs, one per line>
|
||||
|
||||
SECTION AUTHORITY
|
||||
<RRs, one per line>
|
||||
|
||||
SECTION ADDITIONAL
|
||||
<RRs, one per line>
|
||||
|
||||
HEX_EDNSDATA_BEGIN
|
||||
<Hex data of an EDNS option>
|
||||
HEX_EDNSDATA_END
|
||||
|
||||
EXTRA_PACKET ; follow with SECTION, REPLY for more packets.
|
||||
HEX_ANSWER_BEGIN ; follow with hex data
|
||||
; this replaces any answer packet constructed
|
||||
; with the SECTION keywords (only SECTION QUERY
|
||||
; is used to match queries). If the data cannot
|
||||
; be parsed, ADJUST rules for the answer packet
|
||||
; are ignored
|
||||
|
||||
HEX_ANSWER_END
|
||||
|
||||
ENTRY_END
|
||||
|
||||
.SH AUTHOR
|
||||
Written by the ldns team as an example for ldns usage, and for testing purposes.
|
||||
.SH REPORTING BUGS
|
||||
Report bugs to <dns-team@nlnetlabs.nl>.
|
||||
.SH COPYRIGHT
|
||||
Copyright (C) 2006-2008 NLnet Labs. This is free software. There is NO
|
||||
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR
|
||||
PURPOSE.
|
||||
638
zonemaster-ldns/ldns/examples/ldns-testns.c
Normal file
638
zonemaster-ldns/ldns/examples/ldns-testns.c
Normal file
@@ -0,0 +1,638 @@
|
||||
/*
|
||||
* ldns-testns. Light-weight DNS daemon, gives canned replies.
|
||||
*
|
||||
* Tiny dns server, that responds with specially crafted replies
|
||||
* to requests. For testing dns software.
|
||||
*
|
||||
* (c) NLnet Labs, 2005 - 2008
|
||||
* See the file LICENSE for the license
|
||||
*/
|
||||
|
||||
/*
|
||||
* This program is a debugging aid. It can is not efficient, especially
|
||||
* with a long config file, but it can give any reply to any query.
|
||||
* This can help the developer pre-script replies for queries.
|
||||
*
|
||||
* It listens to IP4 UDP and TCP by default.
|
||||
* You can specify a packet RR by RR with header flags to return.
|
||||
*
|
||||
* Missing features:
|
||||
* - matching content different from reply content.
|
||||
* - find way to adjust mangled packets?
|
||||
*/
|
||||
|
||||
/*
|
||||
The data file format is as follows:
|
||||
|
||||
; comment.
|
||||
; a number of entries, these are processed first to last.
|
||||
; a line based format.
|
||||
|
||||
$ORIGIN origin
|
||||
$TTL default_ttl
|
||||
|
||||
ENTRY_BEGIN
|
||||
; first give MATCH lines, that say what queries are matched
|
||||
; by this entry.
|
||||
; 'opcode' makes the query match the opcode from the reply
|
||||
; if you leave it out, any opcode matches this entry.
|
||||
; 'qtype' makes the query match the qtype from the reply
|
||||
; 'qname' makes the query match the qname from the reply
|
||||
; 'serial=1023' makes the query match if ixfr serial is 1023.
|
||||
MATCH [opcode] [qtype] [qname] [serial=<value>]
|
||||
MATCH [UDP|TCP]
|
||||
MATCH ...
|
||||
; Then the REPLY header is specified.
|
||||
REPLY opcode, rcode or flags.
|
||||
(opcode) QUERY IQUERY STATUS NOTIFY UPDATE
|
||||
(rcode) NOERROR FORMERR SERVFAIL NXDOMAIN NOTIMPL YXDOMAIN
|
||||
YXRRSET NXRRSET NOTAUTH NOTZONE
|
||||
(flags) QR AA TC RD CD RA AD
|
||||
REPLY ...
|
||||
; any additional actions to do.
|
||||
; 'copy_id' copies the ID from the query to the answer.
|
||||
ADJUST copy_id
|
||||
; 'sleep=10' sleeps for 10 seconds before giving the answer (TCP is open)
|
||||
ADJUST [sleep=<num>] ; sleep before giving any reply
|
||||
ADJUST [packet_sleep=<num>] ; sleep before this packet in sequence
|
||||
SECTION QUESTION
|
||||
<RRs, one per line> ; the RRcount is determined automatically.
|
||||
SECTION ANSWER
|
||||
<RRs, one per line>
|
||||
SECTION AUTHORITY
|
||||
<RRs, one per line>
|
||||
SECTION ADDITIONAL
|
||||
<RRs, one per line>
|
||||
HEX_EDNSDATA_BEGIN
|
||||
<Hex data of an EDNS option>
|
||||
HEX_EDNSDATA_END
|
||||
EXTRA_PACKET ; follow with SECTION, REPLY for more packets.
|
||||
HEX_ANSWER_BEGIN ; follow with hex data
|
||||
; this replaces any answer packet constructed
|
||||
; with the SECTION keywords (only SECTION QUERY
|
||||
; is used to match queries). If the data cannot
|
||||
; be parsed, ADJUST rules for the answer packet
|
||||
; are ignored
|
||||
HEX_ANSWER_END
|
||||
ENTRY_END
|
||||
*/
|
||||
|
||||
/* Example data file:
|
||||
$ORIGIN nlnetlabs.nl
|
||||
$TTL 3600
|
||||
|
||||
ENTRY_BEGIN
|
||||
MATCH qname
|
||||
REPLY NOERROR
|
||||
ADJUST copy_id
|
||||
SECTION QUESTION
|
||||
www.nlnetlabs.nl. IN A
|
||||
SECTION ANSWER
|
||||
www.nlnetlabs.nl. IN A 195.169.215.155
|
||||
SECTION AUTHORITY
|
||||
nlnetlabs.nl. IN NS www.nlnetlabs.nl.
|
||||
HEX_EDNSDATA_BEGIN
|
||||
00 03 ; NSID
|
||||
00 04 ; LENGTH
|
||||
4E 53 ; NS
|
||||
49 44 ; ID
|
||||
HEX_EDNSDATA_END
|
||||
ENTRY_END
|
||||
|
||||
ENTRY_BEGIN
|
||||
MATCH qname
|
||||
REPLY NOERROR
|
||||
ADJUST copy_id
|
||||
SECTION QUESTION
|
||||
www2.nlnetlabs.nl. IN A
|
||||
HEX_ANSWER_BEGIN
|
||||
; 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
|
||||
;-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
|
||||
00 bf 81 80 00 01 00 01 00 02 00 02 03 77 77 77 0b 6b 61 6e ; 1- 20
|
||||
61 72 69 65 70 69 65 74 03 63 6f 6d 00 00 01 00 01 03 77 77 ; 21- 40
|
||||
77 0b 6b 61 6e 61 72 69 65 70 69 65 74 03 63 6f 6d 00 00 01 ; 41- 60
|
||||
00 01 00 01 50 8b 00 04 52 5e ed 32 0b 6b 61 6e 61 72 69 65 ; 61- 80
|
||||
70 69 65 74 03 63 6f 6d 00 00 02 00 01 00 01 50 8b 00 11 03 ; 81- 100
|
||||
6e 73 31 08 68 65 78 6f 6e 2d 69 73 02 6e 6c 00 0b 6b 61 6e ; 101- 120
|
||||
61 72 69 65 70 69 65 74 03 63 6f 6d 00 00 02 00 01 00 01 50 ; 121- 140
|
||||
8b 00 11 03 6e 73 32 08 68 65 78 6f 6e 2d 69 73 02 6e 6c 00 ; 141- 160
|
||||
03 6e 73 31 08 68 65 78 6f 6e 2d 69 73 02 6e 6c 00 00 01 00 ; 161- 180
|
||||
01 00 00 46 53 00 04 52 5e ed 02 03 6e 73 32 08 68 65 78 6f ; 181- 200
|
||||
6e 2d 69 73 02 6e 6c 00 00 01 00 01 00 00 46 53 00 04 d4 cc ; 201- 220
|
||||
db 5b
|
||||
HEX_ANSWER_END
|
||||
ENTRY_END
|
||||
|
||||
|
||||
*/
|
||||
|
||||
struct sockaddr_storage;
|
||||
#include "config.h"
|
||||
#include <ldns/ldns.h>
|
||||
#include "ldns-testpkts.h"
|
||||
|
||||
#ifdef HAVE_SYS_SOCKET_H
|
||||
#include <sys/socket.h>
|
||||
#endif
|
||||
#ifdef HAVE_TIME_H
|
||||
#include <time.h>
|
||||
#endif
|
||||
#ifdef HAVE_SYS_TIME_H
|
||||
#include <sys/time.h>
|
||||
#endif
|
||||
#ifdef HAVE_SYS_SELECT_H
|
||||
#include <sys/select.h>
|
||||
#endif
|
||||
#ifdef HAVE_ARPA_INET_H
|
||||
#include <arpa/inet.h>
|
||||
#endif
|
||||
#ifdef HAVE_NETINET_IN_H
|
||||
#include <netinet/in.h>
|
||||
#endif
|
||||
#ifdef HAVE_NETINET_UDP_H
|
||||
#include <netinet/udp.h>
|
||||
#endif
|
||||
#ifdef HAVE_NETINET_IGMP_H
|
||||
#include <netinet/igmp.h>
|
||||
#endif
|
||||
#include <errno.h>
|
||||
#include <signal.h>
|
||||
|
||||
#ifdef HAVE_TARGETCONDITIONALS_H
|
||||
#include <TargetConditionals.h>
|
||||
#endif
|
||||
|
||||
#if defined(TARGET_OS_TV) || defined(TARGET_OS_WATCH)
|
||||
#undef HAVE_FORK
|
||||
#endif
|
||||
|
||||
#define INBUF_SIZE 4096 /* max size for incoming queries */
|
||||
#define DEFAULT_PORT 53 /* default if no -p port is specified */
|
||||
#define CONN_BACKLOG 256 /* connections queued up for tcp */
|
||||
static const char* prog_name = "ldns-testns";
|
||||
static FILE* logfile = 0;
|
||||
static int do_verbose = 0;
|
||||
|
||||
static void usage(void)
|
||||
{
|
||||
printf("Usage: %s [options] <datafile>\n", prog_name);
|
||||
printf(" -r listens on random port. Port number is printed.\n");
|
||||
printf(" -p listens on the specified port, default %d.\n", DEFAULT_PORT);
|
||||
printf(" -f forks given number extra instances, default none.\n");
|
||||
printf(" -v more verbose, prints queries, answers and matching.\n");
|
||||
printf(" -6 listen on IP6 any address, instead of IP4 any address.\n");
|
||||
printf("The program answers queries with canned replies from the datafile.\n");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
static void log_msg(const char* msg, ...)
|
||||
{
|
||||
va_list args;
|
||||
va_start(args, msg);
|
||||
vfprintf(logfile, msg, args);
|
||||
fflush(logfile);
|
||||
va_end(args);
|
||||
}
|
||||
|
||||
static void error(const char* msg, ...)
|
||||
{
|
||||
va_list args;
|
||||
va_start(args, msg);
|
||||
fprintf(logfile, "%s error: ", prog_name);
|
||||
vfprintf(logfile, msg, args);
|
||||
fprintf(logfile, "\n");
|
||||
fflush(logfile);
|
||||
va_end(args);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
void verbose(int lvl, const char* msg, ...) ATTR_FORMAT(printf, 2, 3);
|
||||
void verbose(int ATTR_UNUSED(lvl), const char* msg, ...)
|
||||
{
|
||||
va_list args;
|
||||
va_start(args, msg);
|
||||
if(do_verbose)
|
||||
vfprintf(logfile, msg, args);
|
||||
fflush(logfile);
|
||||
va_end(args);
|
||||
}
|
||||
|
||||
static int bind_port(int sock, int port, int fam)
|
||||
{
|
||||
struct sockaddr_in addr;
|
||||
#if defined(AF_INET6) && defined(HAVE_GETADDRINFO)
|
||||
if(fam == AF_INET6) {
|
||||
struct sockaddr_in6 addr6;
|
||||
memset(&addr6, 0, sizeof(addr6));
|
||||
addr6.sin6_family = AF_INET6;
|
||||
addr6.sin6_port = (in_port_t)htons((uint16_t)port);
|
||||
# if HAVE_DECL_IN6ADDR_ANY
|
||||
addr6.sin6_addr = in6addr_any;
|
||||
# else
|
||||
memset(&addr6.sin6_addr, 0, sizeof(addr6.sin6_addr));
|
||||
# endif
|
||||
return bind(sock, (struct sockaddr *)&addr6, (socklen_t) sizeof(addr6));
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifndef S_SPLINT_S
|
||||
addr.sin_family = AF_INET;
|
||||
#endif
|
||||
addr.sin_port = (in_port_t)htons((uint16_t)port);
|
||||
addr.sin_addr.s_addr = INADDR_ANY;
|
||||
return bind(sock, (struct sockaddr *)&addr, (socklen_t) sizeof(addr));
|
||||
}
|
||||
|
||||
struct handle_udp_userdata {
|
||||
int udp_sock;
|
||||
struct sockaddr_storage addr_him;
|
||||
socklen_t hislen;
|
||||
};
|
||||
static void
|
||||
send_udp(uint8_t* buf, size_t len, void* data)
|
||||
{
|
||||
struct handle_udp_userdata *userdata = (struct handle_udp_userdata*)data;
|
||||
/* udp send reply */
|
||||
ssize_t nb;
|
||||
nb = sendto(userdata->udp_sock, (void*)buf, len, 0,
|
||||
(struct sockaddr*)&userdata->addr_him, userdata->hislen);
|
||||
if(nb == -1)
|
||||
log_msg("sendto(): %s\n", strerror(errno));
|
||||
else if((size_t)nb != len)
|
||||
log_msg("sendto(): only sent %d of %d octets.\n",
|
||||
(int)nb, (int)len);
|
||||
}
|
||||
|
||||
static void
|
||||
handle_udp(int udp_sock, struct entry* entries, int *count)
|
||||
{
|
||||
ssize_t nb;
|
||||
uint8_t inbuf[INBUF_SIZE];
|
||||
struct handle_udp_userdata userdata;
|
||||
userdata.udp_sock = udp_sock;
|
||||
|
||||
userdata.hislen = (socklen_t)sizeof(userdata.addr_him);
|
||||
/* udp recv */
|
||||
nb = recvfrom(udp_sock, (void*)inbuf, INBUF_SIZE, 0,
|
||||
(struct sockaddr*)&userdata.addr_him, &userdata.hislen);
|
||||
if (nb < 1) {
|
||||
#ifndef USE_WINSOCK
|
||||
log_msg("recvfrom(): %s\n", strerror(errno));
|
||||
#else
|
||||
if(WSAGetLastError() != WSAEINPROGRESS &&
|
||||
WSAGetLastError() != WSAECONNRESET &&
|
||||
WSAGetLastError()!= WSAEWOULDBLOCK)
|
||||
log_msg("recvfrom(): %d\n", WSAGetLastError());
|
||||
#endif
|
||||
return;
|
||||
}
|
||||
handle_query(inbuf, nb, entries, count, transport_udp, send_udp,
|
||||
&userdata, do_verbose?logfile:0);
|
||||
}
|
||||
|
||||
static int
|
||||
read_n_bytes(int sock, uint8_t* buf, size_t sz)
|
||||
{
|
||||
size_t count = 0;
|
||||
while(count < sz) {
|
||||
ssize_t nb = recv(sock, (void*)(buf+count), sz-count, 0);
|
||||
if(nb < 0) {
|
||||
log_msg("recv(): %s\n", strerror(errno));
|
||||
return -1;
|
||||
} else if(nb == 0) {
|
||||
log_msg("recv: remote end closed the channel\n");
|
||||
return sz-count;
|
||||
}
|
||||
count += nb;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void
|
||||
write_n_bytes(int sock, uint8_t* buf, size_t sz)
|
||||
{
|
||||
size_t count = 0;
|
||||
while(count < sz) {
|
||||
ssize_t nb = send(sock, (void*)(buf+count), sz-count, 0);
|
||||
if(nb < 0) {
|
||||
log_msg("send(): %s\n", strerror(errno));
|
||||
return;
|
||||
}
|
||||
count += nb;
|
||||
}
|
||||
}
|
||||
|
||||
struct handle_tcp_userdata {
|
||||
int s;
|
||||
};
|
||||
static void
|
||||
send_tcp(uint8_t* buf, size_t len, void* data)
|
||||
{
|
||||
struct handle_tcp_userdata *userdata = (struct handle_tcp_userdata*)data;
|
||||
uint16_t tcplen;
|
||||
/* tcp send reply */
|
||||
tcplen = htons(len);
|
||||
write_n_bytes(userdata->s, (uint8_t*)&tcplen, sizeof(tcplen));
|
||||
write_n_bytes(userdata->s, buf, len);
|
||||
}
|
||||
|
||||
static void
|
||||
handle_tcp(int tcp_sock, struct entry* entries, int *count)
|
||||
{
|
||||
int s;
|
||||
struct sockaddr_storage addr_him;
|
||||
socklen_t hislen;
|
||||
uint8_t inbuf[INBUF_SIZE];
|
||||
uint16_t tcplen = 0;
|
||||
struct handle_tcp_userdata userdata;
|
||||
|
||||
/* accept */
|
||||
hislen = (socklen_t)sizeof(addr_him);
|
||||
if((s = accept(tcp_sock, (struct sockaddr*)&addr_him, &hislen)) < 0) {
|
||||
log_msg("accept(): %s\n", strerror(errno));
|
||||
return;
|
||||
}
|
||||
userdata.s = s;
|
||||
|
||||
while(1) {
|
||||
/* tcp recv */
|
||||
if (read_n_bytes(s, (uint8_t*)&tcplen, sizeof(tcplen))) {
|
||||
#ifndef USE_WINSOCK
|
||||
close(s);
|
||||
#else
|
||||
closesocket(s);
|
||||
#endif
|
||||
return;
|
||||
}
|
||||
tcplen = ntohs(tcplen);
|
||||
if(tcplen >= INBUF_SIZE) {
|
||||
log_msg("query %d bytes too large, buffer %d bytes.\n",
|
||||
tcplen, INBUF_SIZE);
|
||||
#ifndef USE_WINSOCK
|
||||
close(s);
|
||||
#else
|
||||
closesocket(s);
|
||||
#endif
|
||||
return;
|
||||
}
|
||||
if (read_n_bytes(s, inbuf, tcplen)) {
|
||||
#ifndef USE_WINSOCK
|
||||
close(s);
|
||||
#else
|
||||
closesocket(s);
|
||||
#endif
|
||||
return;
|
||||
}
|
||||
|
||||
handle_query(inbuf, (ssize_t) tcplen, entries, count, transport_tcp,
|
||||
send_tcp, &userdata, do_verbose?logfile:0);
|
||||
|
||||
/* another query straight away? */
|
||||
if(1) {
|
||||
fd_set rset;
|
||||
struct timeval tv;
|
||||
int ret;
|
||||
FD_ZERO(&rset);
|
||||
FD_SET(s, &rset);
|
||||
tv.tv_sec = 0;
|
||||
tv.tv_usec = 100*1000;
|
||||
ret = select(s+1, &rset, NULL, NULL, &tv);
|
||||
if(ret < 0) {
|
||||
error("select(): %s\n", strerror(errno));
|
||||
}
|
||||
if(ret == 0) {
|
||||
/* timeout */
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
#ifndef USE_WINSOCK
|
||||
close(s);
|
||||
#else
|
||||
closesocket(s);
|
||||
#endif
|
||||
|
||||
}
|
||||
|
||||
/** shared by the service and main routine (forked and threaded) */
|
||||
static int udp_sock, tcp_sock;
|
||||
static struct entry* entries;
|
||||
|
||||
/**
|
||||
* Test DNS server service, uses global udpsock, tcpsock, reply entries
|
||||
* The signature is kept void so the function can be used as a thread function.
|
||||
*/
|
||||
static void
|
||||
service(void)
|
||||
{
|
||||
fd_set rset, wset, eset;
|
||||
int count;
|
||||
int maxfd;
|
||||
|
||||
/* service */
|
||||
count = 0;
|
||||
while (1) {
|
||||
#ifndef S_SPLINT_S
|
||||
FD_ZERO(&rset);
|
||||
FD_ZERO(&wset);
|
||||
FD_ZERO(&eset);
|
||||
FD_SET(udp_sock, &rset);
|
||||
FD_SET(tcp_sock, &rset);
|
||||
#endif
|
||||
maxfd = udp_sock;
|
||||
if(tcp_sock > maxfd)
|
||||
maxfd = tcp_sock;
|
||||
if(select(maxfd+1, &rset, &wset, &eset, NULL) < 0) {
|
||||
error("select(): %s\n", strerror(errno));
|
||||
}
|
||||
if(FD_ISSET(udp_sock, &rset)) {
|
||||
handle_udp(udp_sock, entries, &count);
|
||||
}
|
||||
if(FD_ISSET(tcp_sock, &rset)) {
|
||||
handle_tcp(tcp_sock, entries, &count);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
forkit(int number)
|
||||
{
|
||||
int i;
|
||||
for(i=0; i<number; i++)
|
||||
{
|
||||
#if !defined(HAVE_FORK) || !defined(HAVE_FORK_AVAILABLE)
|
||||
#ifndef USE_WINSOCK
|
||||
log_msg("fork() not available.\n");
|
||||
exit(1);
|
||||
#else /* USE_WINSOCK */
|
||||
DWORD tid;
|
||||
HANDLE id = CreateThread(NULL, 0,
|
||||
(LPTHREAD_START_ROUTINE)service, NULL,
|
||||
0, &tid);
|
||||
if(id == NULL) {
|
||||
log_msg("error CreateThread: %d\n", GetLastError());
|
||||
return;
|
||||
}
|
||||
log_msg("thread id: %d\n", (int)tid);
|
||||
#endif /* USE_WINSOCK */
|
||||
#else /* HAVE_FORK */
|
||||
pid_t pid = fork();
|
||||
if(pid == (pid_t) -1) {
|
||||
log_msg("error forking: %s\n", strerror(errno));
|
||||
return;
|
||||
}
|
||||
if(pid == 0)
|
||||
return; /* child starts serving */
|
||||
log_msg("forked pid: %d\n", (int)pid);
|
||||
#endif /* HAVE_FORK */
|
||||
}
|
||||
}
|
||||
|
||||
int
|
||||
main(int argc, char **argv)
|
||||
{
|
||||
/* arguments */
|
||||
int c;
|
||||
int port = DEFAULT_PORT;
|
||||
const char* datafile;
|
||||
int forknum = 0;
|
||||
|
||||
/* network */
|
||||
int fam = AF_INET;
|
||||
bool random_port_success;
|
||||
|
||||
#ifdef USE_WINSOCK
|
||||
WSADATA wsa_data;
|
||||
#endif
|
||||
|
||||
/* parse arguments */
|
||||
srandom(time(NULL) ^ getpid());
|
||||
logfile = stdout;
|
||||
prog_name = argv[0];
|
||||
log_msg("%s: start\n", prog_name);
|
||||
while((c = getopt(argc, argv, "6f:p:rv")) != -1) {
|
||||
switch(c) {
|
||||
case '6':
|
||||
#ifdef AF_INET6
|
||||
fam = AF_INET6;
|
||||
#else
|
||||
log_msg("cannot -6: no IP6 available\n");
|
||||
exit(1);
|
||||
#endif
|
||||
break;
|
||||
case 'r':
|
||||
port = 0;
|
||||
break;
|
||||
case 'f':
|
||||
forknum = atoi(optarg);
|
||||
if(forknum < 1)
|
||||
error("invalid forkno %s, give number", optarg);
|
||||
break;
|
||||
case 'p':
|
||||
port = atoi(optarg);
|
||||
if (port < 1) {
|
||||
error("Invalid port %s, use a number.", optarg);
|
||||
}
|
||||
break;
|
||||
case 'v':
|
||||
do_verbose++;
|
||||
break;
|
||||
default:
|
||||
usage();
|
||||
break;
|
||||
}
|
||||
}
|
||||
argc -= optind;
|
||||
argv += optind;
|
||||
|
||||
if(argc == 0 || argc > 1)
|
||||
usage();
|
||||
|
||||
datafile = argv[0];
|
||||
log_msg("Reading datafile %s\n", datafile);
|
||||
entries = read_datafile(datafile, 0);
|
||||
|
||||
#ifdef SIGPIPE
|
||||
(void)signal(SIGPIPE, SIG_IGN);
|
||||
#endif
|
||||
#ifdef USE_WINSOCK
|
||||
if(WSAStartup(MAKEWORD(2,2), &wsa_data) != 0)
|
||||
error("WSAStartup failed\n");
|
||||
#endif
|
||||
|
||||
if((udp_sock = socket(fam, SOCK_DGRAM, 0)) < 0) {
|
||||
error("udp socket(): %s\n", strerror(errno));
|
||||
}
|
||||
if((tcp_sock = socket(fam, SOCK_STREAM, 0)) < 0) {
|
||||
error("tcp socket(): %s\n", strerror(errno));
|
||||
}
|
||||
c = 1;
|
||||
if(setsockopt(tcp_sock, SOL_SOCKET, SO_REUSEADDR, (void*)&c, (socklen_t) sizeof(int)) < 0) {
|
||||
error("setsockopt(SO_REUSEADDR): %s\n", strerror(errno));
|
||||
}
|
||||
|
||||
/* bind ip4 */
|
||||
if (port > 0) {
|
||||
if (bind_port(udp_sock, port, fam)) {
|
||||
error("cannot bind(): %s\n", strerror(errno));
|
||||
}
|
||||
if (bind_port(tcp_sock, port, fam)) {
|
||||
error("cannot bind(): %s\n", strerror(errno));
|
||||
}
|
||||
if (listen(tcp_sock, CONN_BACKLOG) < 0) {
|
||||
error("listen(): %s\n", strerror(errno));
|
||||
}
|
||||
} else {
|
||||
random_port_success = false;
|
||||
while (!random_port_success) {
|
||||
port = (random() % 64510) + 1025;
|
||||
log_msg("trying to bind to port %d\n", port);
|
||||
random_port_success = true;
|
||||
if (bind_port(udp_sock, port, fam)) {
|
||||
#ifdef EADDRINUSE
|
||||
if (errno != EADDRINUSE) {
|
||||
#elif defined(USE_WINSOCK)
|
||||
if (WSAGetLastError() != WSAEADDRINUSE) {
|
||||
#else
|
||||
if (1) {
|
||||
#endif
|
||||
perror("bind()");
|
||||
return -1;
|
||||
} else {
|
||||
random_port_success = false;
|
||||
}
|
||||
}
|
||||
if (random_port_success) {
|
||||
if (bind_port(tcp_sock, port, fam)) {
|
||||
#ifdef EADDRINUSE
|
||||
if (errno != EADDRINUSE) {
|
||||
#elif defined(USE_WINSOCK)
|
||||
if (WSAGetLastError()!=WSAEADDRINUSE){
|
||||
#else
|
||||
if (1) {
|
||||
#endif
|
||||
perror("bind()");
|
||||
return -1;
|
||||
} else {
|
||||
random_port_success = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (random_port_success) {
|
||||
if (listen(tcp_sock, CONN_BACKLOG) < 0) {
|
||||
error("listen(): %s\n", strerror(errno));
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
log_msg("Listening on port %d\n", port);
|
||||
|
||||
/* forky! */
|
||||
if(forknum > 0)
|
||||
forkit(forknum);
|
||||
|
||||
service();
|
||||
|
||||
return 0;
|
||||
}
|
||||
983
zonemaster-ldns/ldns/examples/ldns-testpkts.c
Normal file
983
zonemaster-ldns/ldns/examples/ldns-testpkts.c
Normal file
@@ -0,0 +1,983 @@
|
||||
/*
|
||||
* ldns-testpkts. Data file parse for test packets, and query matching.
|
||||
*
|
||||
* Data storage for specially crafted replies for testing purposes.
|
||||
*
|
||||
* (c) NLnet Labs, 2005, 2006, 2007, 2008
|
||||
* See the file LICENSE for the license
|
||||
*/
|
||||
|
||||
/**
|
||||
* \file
|
||||
* This is a debugging aid. It is not efficient, especially
|
||||
* with a long config file, but it can give any reply to any query.
|
||||
* This can help the developer pre-script replies for queries.
|
||||
*
|
||||
* You can specify a packet RR by RR with header flags to return.
|
||||
*
|
||||
* Missing features:
|
||||
* - matching content different from reply content.
|
||||
* - find way to adjust mangled packets?
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
struct sockaddr_storage;
|
||||
#include <ldns/ldns.h>
|
||||
#include <errno.h>
|
||||
#include "ldns-testpkts.h"
|
||||
|
||||
/** max line length */
|
||||
#define MAX_LINE 10240
|
||||
/** string to show in warnings and errors */
|
||||
static const char* prog_name = "ldns-testpkts";
|
||||
|
||||
/** logging routine, provided by caller */
|
||||
void verbose(int lvl, const char* msg, ...) ATTR_FORMAT(printf, 2, 3);
|
||||
|
||||
/** print error and exit */
|
||||
static void error(const char* msg, ...) __attribute__((noreturn));
|
||||
static void error(const char* msg, ...)
|
||||
{
|
||||
va_list args;
|
||||
va_start(args, msg);
|
||||
fprintf(stderr, "%s error: ", prog_name);
|
||||
vfprintf(stderr, msg, args);
|
||||
fprintf(stderr, "\n");
|
||||
fflush(stderr);
|
||||
va_end(args);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
/** return if string is empty or comment */
|
||||
static bool isendline(char c)
|
||||
{
|
||||
if(c == ';' || c == '#'
|
||||
|| c == '\n' || c == 0)
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
/** true if the string starts with the keyword given. Moves the str ahead.
|
||||
* @param str: before keyword, afterwards after keyword and spaces.
|
||||
* @param keyword: the keyword to match
|
||||
* @return: true if keyword present. False otherwise, and str unchanged.
|
||||
*/
|
||||
static bool str_keyword(char** str, const char* keyword)
|
||||
{
|
||||
size_t len = strlen(keyword);
|
||||
assert(str && keyword);
|
||||
if(strncmp(*str, keyword, len) != 0)
|
||||
return false;
|
||||
*str += len;
|
||||
while(isspace((int)**str))
|
||||
(*str)++;
|
||||
return true;
|
||||
}
|
||||
|
||||
/** Add reply packet to entry */
|
||||
static struct reply_packet*
|
||||
entry_add_reply(struct entry* entry)
|
||||
{
|
||||
struct reply_packet* pkt = (struct reply_packet*)malloc(
|
||||
sizeof(struct reply_packet));
|
||||
struct reply_packet ** p = &entry->reply_list;
|
||||
pkt->next = NULL;
|
||||
pkt->packet_sleep = 0;
|
||||
pkt->reply = ldns_pkt_new();
|
||||
pkt->reply_from_hex = NULL;
|
||||
pkt->raw_ednsdata = NULL;
|
||||
/* link at end */
|
||||
while(*p)
|
||||
p = &((*p)->next);
|
||||
*p = pkt;
|
||||
return pkt;
|
||||
}
|
||||
|
||||
/** parse MATCH line */
|
||||
static void matchline(char* line, struct entry* e)
|
||||
{
|
||||
char* parse = line;
|
||||
while(*parse) {
|
||||
if(isendline(*parse))
|
||||
return;
|
||||
if(str_keyword(&parse, "opcode")) {
|
||||
e->match_opcode = true;
|
||||
} else if(str_keyword(&parse, "qtype")) {
|
||||
e->match_qtype = true;
|
||||
} else if(str_keyword(&parse, "qname")) {
|
||||
e->match_qname = true;
|
||||
} else if(str_keyword(&parse, "subdomain")) {
|
||||
e->match_subdomain = true;
|
||||
} else if(str_keyword(&parse, "all")) {
|
||||
e->match_all = true;
|
||||
} else if(str_keyword(&parse, "ttl")) {
|
||||
e->match_ttl = true;
|
||||
} else if(str_keyword(&parse, "DO")) {
|
||||
e->match_do = true;
|
||||
} else if(str_keyword(&parse, "noedns")) {
|
||||
e->match_noedns = true;
|
||||
} else if(str_keyword(&parse, "ednsdata")) {
|
||||
e->match_ednsdata_raw = true;
|
||||
} else if(str_keyword(&parse, "UDP")) {
|
||||
e->match_transport = transport_udp;
|
||||
} else if(str_keyword(&parse, "TCP")) {
|
||||
e->match_transport = transport_tcp;
|
||||
} else if(str_keyword(&parse, "serial")) {
|
||||
e->match_serial = true;
|
||||
if(*parse != '=' && *parse != ':')
|
||||
error("expected = or : in MATCH: %s", line);
|
||||
parse++;
|
||||
e->ixfr_soa_serial = (uint32_t)strtol(parse, (char**)&parse, 10);
|
||||
while(isspace((int)*parse))
|
||||
parse++;
|
||||
} else if(str_keyword(&parse, "udp_size")) {
|
||||
if(*parse != '=' && *parse != ':')
|
||||
error("expected = or : in MATCH: %s", line);
|
||||
parse++;
|
||||
e->match_udp_size = (uint32_t)strtol(parse, (char**)&parse, 10);
|
||||
while(isspace((int)*parse))
|
||||
parse++;
|
||||
} else {
|
||||
error("could not parse MATCH: '%s'", parse);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/** parse REPLY line */
|
||||
static void replyline(char* line, ldns_pkt *reply)
|
||||
{
|
||||
char* parse = line;
|
||||
while(*parse) {
|
||||
if(isendline(*parse))
|
||||
return;
|
||||
/* opcodes */
|
||||
if(str_keyword(&parse, "QUERY")) {
|
||||
ldns_pkt_set_opcode(reply, LDNS_PACKET_QUERY);
|
||||
} else if(str_keyword(&parse, "IQUERY")) {
|
||||
ldns_pkt_set_opcode(reply, LDNS_PACKET_IQUERY);
|
||||
} else if(str_keyword(&parse, "STATUS")) {
|
||||
ldns_pkt_set_opcode(reply, LDNS_PACKET_STATUS);
|
||||
} else if(str_keyword(&parse, "NOTIFY")) {
|
||||
ldns_pkt_set_opcode(reply, LDNS_PACKET_NOTIFY);
|
||||
} else if(str_keyword(&parse, "UPDATE")) {
|
||||
ldns_pkt_set_opcode(reply, LDNS_PACKET_UPDATE);
|
||||
/* rcodes */
|
||||
} else if(str_keyword(&parse, "NOERROR")) {
|
||||
ldns_pkt_set_rcode(reply, LDNS_RCODE_NOERROR);
|
||||
} else if(str_keyword(&parse, "FORMERR")) {
|
||||
ldns_pkt_set_rcode(reply, LDNS_RCODE_FORMERR);
|
||||
} else if(str_keyword(&parse, "SERVFAIL")) {
|
||||
ldns_pkt_set_rcode(reply, LDNS_RCODE_SERVFAIL);
|
||||
} else if(str_keyword(&parse, "NXDOMAIN")) {
|
||||
ldns_pkt_set_rcode(reply, LDNS_RCODE_NXDOMAIN);
|
||||
} else if(str_keyword(&parse, "NOTIMPL")) {
|
||||
ldns_pkt_set_rcode(reply, LDNS_RCODE_NOTIMPL);
|
||||
} else if(str_keyword(&parse, "REFUSED")) {
|
||||
ldns_pkt_set_rcode(reply, LDNS_RCODE_REFUSED);
|
||||
} else if(str_keyword(&parse, "YXDOMAIN")) {
|
||||
ldns_pkt_set_rcode(reply, LDNS_RCODE_YXDOMAIN);
|
||||
} else if(str_keyword(&parse, "YXRRSET")) {
|
||||
ldns_pkt_set_rcode(reply, LDNS_RCODE_YXRRSET);
|
||||
} else if(str_keyword(&parse, "NXRRSET")) {
|
||||
ldns_pkt_set_rcode(reply, LDNS_RCODE_NXRRSET);
|
||||
} else if(str_keyword(&parse, "NOTAUTH")) {
|
||||
ldns_pkt_set_rcode(reply, LDNS_RCODE_NOTAUTH);
|
||||
} else if(str_keyword(&parse, "NOTZONE")) {
|
||||
ldns_pkt_set_rcode(reply, LDNS_RCODE_NOTZONE);
|
||||
/* flags */
|
||||
} else if(str_keyword(&parse, "QR")) {
|
||||
ldns_pkt_set_qr(reply, true);
|
||||
} else if(str_keyword(&parse, "AA")) {
|
||||
ldns_pkt_set_aa(reply, true);
|
||||
} else if(str_keyword(&parse, "TC")) {
|
||||
ldns_pkt_set_tc(reply, true);
|
||||
} else if(str_keyword(&parse, "RD")) {
|
||||
ldns_pkt_set_rd(reply, true);
|
||||
} else if(str_keyword(&parse, "CD")) {
|
||||
ldns_pkt_set_cd(reply, true);
|
||||
} else if(str_keyword(&parse, "RA")) {
|
||||
ldns_pkt_set_ra(reply, true);
|
||||
} else if(str_keyword(&parse, "AD")) {
|
||||
ldns_pkt_set_ad(reply, true);
|
||||
} else if(str_keyword(&parse, "DO")) {
|
||||
ldns_pkt_set_edns_udp_size(reply, 4096);
|
||||
ldns_pkt_set_edns_do(reply, true);
|
||||
} else {
|
||||
error("could not parse REPLY: '%s'", parse);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/** parse ADJUST line */
|
||||
static void adjustline(char* line, struct entry* e,
|
||||
struct reply_packet* pkt)
|
||||
{
|
||||
char* parse = line;
|
||||
while(*parse) {
|
||||
if(isendline(*parse))
|
||||
return;
|
||||
if(str_keyword(&parse, "copy_id")) {
|
||||
e->copy_id = true;
|
||||
} else if(str_keyword(&parse, "copy_query")) {
|
||||
e->copy_query = true;
|
||||
} else if(str_keyword(&parse, "sleep=")) {
|
||||
e->sleeptime = (unsigned int) strtol(parse, (char**)&parse, 10);
|
||||
while(isspace((int)*parse))
|
||||
parse++;
|
||||
} else if(str_keyword(&parse, "packet_sleep=")) {
|
||||
pkt->packet_sleep = (unsigned int) strtol(parse, (char**)&parse, 10);
|
||||
while(isspace((int)*parse))
|
||||
parse++;
|
||||
} else {
|
||||
error("could not parse ADJUST: '%s'", parse);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/** create new entry */
|
||||
static struct entry* new_entry(void)
|
||||
{
|
||||
struct entry* e = LDNS_MALLOC(struct entry);
|
||||
memset(e, 0, sizeof(*e));
|
||||
e->match_opcode = false;
|
||||
e->match_qtype = false;
|
||||
e->match_qname = false;
|
||||
e->match_subdomain = false;
|
||||
e->match_all = false;
|
||||
e->match_ttl = false;
|
||||
e->match_do = false;
|
||||
e->match_noedns = false;
|
||||
e->match_serial = false;
|
||||
e->ixfr_soa_serial = 0;
|
||||
e->match_transport = transport_any;
|
||||
e->match_udp_size = 0;
|
||||
e->reply_list = NULL;
|
||||
e->copy_id = false;
|
||||
e->copy_query = false;
|
||||
e->sleeptime = 0;
|
||||
e->next = NULL;
|
||||
return e;
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts a hex string to binary data
|
||||
* @param hexstr: string of hex.
|
||||
* @param len: is the length of the string
|
||||
* @param buf: is the buffer to store the result in
|
||||
* @param offset: is the starting position in the result buffer
|
||||
* @param buf_len: is the length of buf.
|
||||
* @return This function returns the length of the result
|
||||
*/
|
||||
static size_t
|
||||
hexstr2bin(char *hexstr, int len, uint8_t *buf, size_t offset, size_t buf_len)
|
||||
{
|
||||
char c;
|
||||
int i;
|
||||
uint8_t int8 = 0;
|
||||
int sec = 0;
|
||||
size_t bufpos = 0;
|
||||
|
||||
if (len % 2 != 0) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
for (i=0; i<len; i++) {
|
||||
c = hexstr[i];
|
||||
|
||||
/* case insensitive, skip spaces */
|
||||
if (c != ' ') {
|
||||
if (c >= '0' && c <= '9') {
|
||||
int8 += c & 0x0f;
|
||||
} else if (c >= 'a' && c <= 'z') {
|
||||
int8 += (c & 0x0f) + 9;
|
||||
} else if (c >= 'A' && c <= 'Z') {
|
||||
int8 += (c & 0x0f) + 9;
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (sec == 0) {
|
||||
int8 = int8 << 4;
|
||||
sec = 1;
|
||||
} else {
|
||||
if (bufpos + offset + 1 <= buf_len) {
|
||||
buf[bufpos+offset] = int8;
|
||||
int8 = 0;
|
||||
sec = 0;
|
||||
bufpos++;
|
||||
} else {
|
||||
fprintf(stderr, "Buffer too small in hexstr2bin");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return bufpos;
|
||||
}
|
||||
|
||||
/** convert hex buffer to binary buffer */
|
||||
static ldns_buffer *
|
||||
data_buffer2wire(ldns_buffer *data_buffer)
|
||||
{
|
||||
ldns_buffer *wire_buffer = NULL;
|
||||
int c;
|
||||
|
||||
/* stat hack
|
||||
* 0 = normal
|
||||
* 1 = comment (skip to end of line)
|
||||
* 2 = unprintable character found, read binary data directly
|
||||
*/
|
||||
size_t data_buf_pos = 0;
|
||||
int state = 0;
|
||||
uint8_t *hexbuf;
|
||||
int hexbufpos = 0;
|
||||
size_t wirelen;
|
||||
uint8_t *data_wire = (uint8_t *) ldns_buffer_begin(data_buffer);
|
||||
uint8_t *wire = LDNS_XMALLOC(uint8_t, LDNS_MAX_PACKETLEN);
|
||||
|
||||
hexbuf = LDNS_XMALLOC(uint8_t, LDNS_MAX_PACKETLEN);
|
||||
for (data_buf_pos = 0; data_buf_pos < ldns_buffer_position(data_buffer); data_buf_pos++) {
|
||||
c = (int) data_wire[data_buf_pos];
|
||||
|
||||
if (state < 2 && !isascii(c)) {
|
||||
/*verbose("non ascii character found in file: (%d) switching to raw mode\n", c);*/
|
||||
state = 2;
|
||||
}
|
||||
switch (state) {
|
||||
case 0:
|
||||
if ( (c >= '0' && c <= '9') ||
|
||||
(c >= 'a' && c <= 'f') ||
|
||||
(c >= 'A' && c <= 'F') )
|
||||
{
|
||||
if (hexbufpos >= LDNS_MAX_PACKETLEN) {
|
||||
error("buffer overflow");
|
||||
LDNS_FREE(hexbuf);
|
||||
return 0;
|
||||
|
||||
}
|
||||
hexbuf[hexbufpos] = (uint8_t) c;
|
||||
hexbufpos++;
|
||||
} else if (c == ';') {
|
||||
state = 1;
|
||||
} else if (c == ' ' || c == '\t' || c == '\n') {
|
||||
/* skip whitespace */
|
||||
}
|
||||
break;
|
||||
case 1:
|
||||
if (c == '\n' || c == EOF) {
|
||||
state = 0;
|
||||
}
|
||||
break;
|
||||
case 2:
|
||||
if (hexbufpos >= LDNS_MAX_PACKETLEN) {
|
||||
error("buffer overflow");
|
||||
LDNS_FREE(hexbuf);
|
||||
return 0;
|
||||
}
|
||||
hexbuf[hexbufpos] = (uint8_t) c;
|
||||
hexbufpos++;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (hexbufpos >= LDNS_MAX_PACKETLEN) {
|
||||
/*verbose("packet size reached\n");*/
|
||||
}
|
||||
|
||||
/* lenient mode: length must be multiple of 2 */
|
||||
if (hexbufpos % 2 != 0) {
|
||||
if (hexbufpos >= LDNS_MAX_PACKETLEN) {
|
||||
error("buffer overflow");
|
||||
LDNS_FREE(hexbuf);
|
||||
return 0;
|
||||
}
|
||||
hexbuf[hexbufpos] = (uint8_t) '0';
|
||||
hexbufpos++;
|
||||
}
|
||||
|
||||
if (state < 2) {
|
||||
wirelen = hexstr2bin((char *) hexbuf, hexbufpos, wire, 0, LDNS_MAX_PACKETLEN);
|
||||
wire_buffer = ldns_buffer_new(wirelen);
|
||||
ldns_buffer_new_frm_data(wire_buffer, wire, wirelen);
|
||||
} else {
|
||||
error("Incomplete hex data, not at byte boundary\n");
|
||||
}
|
||||
LDNS_FREE(wire);
|
||||
LDNS_FREE(hexbuf);
|
||||
return wire_buffer;
|
||||
}
|
||||
|
||||
/** parse ORIGIN */
|
||||
static void
|
||||
get_origin(const char* name, int lineno, ldns_rdf** origin, char* parse)
|
||||
{
|
||||
/* snip off rest of the text so as to make the parse work in ldns */
|
||||
char* end;
|
||||
char store;
|
||||
ldns_status status;
|
||||
|
||||
ldns_rdf_free(*origin);
|
||||
*origin = NULL;
|
||||
|
||||
end=parse;
|
||||
while(!isspace((int)*end) && !isendline(*end))
|
||||
end++;
|
||||
store = *end;
|
||||
*end = 0;
|
||||
verbose(3, "parsing '%s'\n", parse);
|
||||
status = ldns_str2rdf_dname(origin, parse);
|
||||
*end = store;
|
||||
if (status != LDNS_STATUS_OK)
|
||||
error("%s line %d:\n\t%s: %s", name, lineno,
|
||||
ldns_get_errorstr_by_id(status), parse);
|
||||
}
|
||||
|
||||
/* Reads one entry from file. Returns entry or NULL on error. */
|
||||
struct entry*
|
||||
read_entry(FILE* in, const char* name, int *lineno, uint32_t* default_ttl,
|
||||
ldns_rdf** origin, ldns_rdf** prev_rr, int skip_whitespace)
|
||||
{
|
||||
struct entry* current = NULL;
|
||||
char line[MAX_LINE];
|
||||
char* parse;
|
||||
ldns_pkt_section add_section = LDNS_SECTION_QUESTION;
|
||||
struct reply_packet *cur_reply = NULL;
|
||||
bool reading_hex = false;
|
||||
bool reading_hex_ednsdata = false;
|
||||
ldns_buffer* hex_data_buffer = NULL;
|
||||
ldns_buffer* hex_ednsdata_buffer = NULL;
|
||||
|
||||
while(fgets(line, (int)sizeof(line), in) != NULL) {
|
||||
line[MAX_LINE-1] = 0;
|
||||
parse = line;
|
||||
(*lineno) ++;
|
||||
|
||||
while(isspace((int)*parse))
|
||||
parse++;
|
||||
/* test for keywords */
|
||||
if(isendline(*parse))
|
||||
continue; /* skip comment and empty lines */
|
||||
if(str_keyword(&parse, "ENTRY_BEGIN")) {
|
||||
if(current) {
|
||||
error("%s line %d: previous entry does not ENTRY_END",
|
||||
name, *lineno);
|
||||
}
|
||||
current = new_entry();
|
||||
current->lineno = *lineno;
|
||||
cur_reply = entry_add_reply(current);
|
||||
continue;
|
||||
} else if(str_keyword(&parse, "$ORIGIN")) {
|
||||
get_origin(name, *lineno, origin, parse);
|
||||
continue;
|
||||
} else if(str_keyword(&parse, "$TTL")) {
|
||||
*default_ttl = (uint32_t)atoi(parse);
|
||||
continue;
|
||||
}
|
||||
|
||||
/* working inside an entry */
|
||||
if(!current) {
|
||||
error("%s line %d: expected ENTRY_BEGIN but got %s",
|
||||
name, *lineno, line);
|
||||
}
|
||||
if(str_keyword(&parse, "MATCH")) {
|
||||
matchline(parse, current);
|
||||
} else if(str_keyword(&parse, "REPLY")) {
|
||||
replyline(parse, cur_reply->reply);
|
||||
} else if(str_keyword(&parse, "ADJUST")) {
|
||||
adjustline(parse, current, cur_reply);
|
||||
} else if(str_keyword(&parse, "EXTRA_PACKET")) {
|
||||
cur_reply = entry_add_reply(current);
|
||||
} else if(str_keyword(&parse, "SECTION")) {
|
||||
if(str_keyword(&parse, "QUESTION"))
|
||||
add_section = LDNS_SECTION_QUESTION;
|
||||
else if(str_keyword(&parse, "ANSWER"))
|
||||
add_section = LDNS_SECTION_ANSWER;
|
||||
else if(str_keyword(&parse, "AUTHORITY"))
|
||||
add_section = LDNS_SECTION_AUTHORITY;
|
||||
else if(str_keyword(&parse, "ADDITIONAL"))
|
||||
add_section = LDNS_SECTION_ADDITIONAL;
|
||||
else error("%s line %d: bad section %s", name, *lineno, parse);
|
||||
} else if(str_keyword(&parse, "HEX_ANSWER_BEGIN")) {
|
||||
hex_data_buffer = ldns_buffer_new(LDNS_MAX_PACKETLEN);
|
||||
reading_hex = true;
|
||||
} else if(str_keyword(&parse, "HEX_ANSWER_END")) {
|
||||
if (!reading_hex) {
|
||||
error("%s line %d: HEX_ANSWER_END read but no HEX_ANSWER_BEGIN keyword seen", name, *lineno);
|
||||
}
|
||||
reading_hex = false;
|
||||
cur_reply->reply_from_hex = data_buffer2wire(hex_data_buffer);
|
||||
ldns_buffer_free(hex_data_buffer);
|
||||
hex_data_buffer = NULL;
|
||||
} else if(reading_hex) {
|
||||
ldns_buffer_printf(hex_data_buffer, line);
|
||||
} else if(str_keyword(&parse, "HEX_EDNSDATA_BEGIN")) {
|
||||
hex_ednsdata_buffer = ldns_buffer_new(LDNS_MAX_PACKETLEN);
|
||||
|
||||
reading_hex_ednsdata = true;
|
||||
} else if(str_keyword(&parse, "HEX_EDNSDATA_END")) {
|
||||
ldns_buffer* edns = NULL;
|
||||
if (!reading_hex_ednsdata) {
|
||||
error("%s line %d: HEX_EDNSDATA_END read but no"
|
||||
"HEX_EDNSDATA_BEGIN keyword seen", name, *lineno);
|
||||
}
|
||||
reading_hex_ednsdata = false;
|
||||
|
||||
edns = data_buffer2wire(hex_ednsdata_buffer);
|
||||
|
||||
/* add read-in EDNS directly to the reply */
|
||||
ldns_pkt_set_edns_data(cur_reply->reply,
|
||||
ldns_rdf_new_frm_data(LDNS_RDF_TYPE_UNKNOWN,
|
||||
ldns_buffer_limit(edns),
|
||||
ldns_buffer_begin(edns)));
|
||||
|
||||
/* store raw EDNS for matching */
|
||||
cur_reply->raw_ednsdata = data_buffer2wire(hex_ednsdata_buffer);
|
||||
|
||||
ldns_buffer_free(edns);
|
||||
ldns_buffer_free(hex_ednsdata_buffer);
|
||||
hex_ednsdata_buffer = NULL;
|
||||
} else if(reading_hex_ednsdata) {
|
||||
ldns_buffer_printf(hex_ednsdata_buffer, line);
|
||||
} else if(str_keyword(&parse, "ENTRY_END")) {
|
||||
if (hex_data_buffer)
|
||||
ldns_buffer_free(hex_data_buffer);
|
||||
return current;
|
||||
} else {
|
||||
/* it must be a RR, parse and add to packet. */
|
||||
ldns_rr* n = NULL;
|
||||
ldns_status status;
|
||||
char* rrstr = line;
|
||||
if (skip_whitespace)
|
||||
rrstr = parse;
|
||||
if(add_section == LDNS_SECTION_QUESTION)
|
||||
status = ldns_rr_new_question_frm_str(
|
||||
&n, rrstr, *origin, prev_rr);
|
||||
else status = ldns_rr_new_frm_str(&n, rrstr,
|
||||
*default_ttl, *origin, prev_rr);
|
||||
if(status != LDNS_STATUS_OK)
|
||||
error("%s line %d:\n\t%s: %s", name, *lineno,
|
||||
ldns_get_errorstr_by_id(status), rrstr);
|
||||
ldns_pkt_push_rr(cur_reply->reply, add_section, n);
|
||||
}
|
||||
|
||||
}
|
||||
if (reading_hex) {
|
||||
error("%s: End of file reached while still reading hex, "
|
||||
"missing HEX_ANSWER_END\n", name);
|
||||
}
|
||||
if(current) {
|
||||
error("%s: End of file reached while reading entry. "
|
||||
"missing ENTRY_END\n", name);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* reads the canned reply file and returns a list of structs */
|
||||
struct entry*
|
||||
read_datafile(const char* name, int skip_whitespace)
|
||||
{
|
||||
struct entry* list = NULL;
|
||||
struct entry* last = NULL;
|
||||
struct entry* current = NULL;
|
||||
FILE *in;
|
||||
int lineno = 0;
|
||||
uint32_t default_ttl = 0;
|
||||
ldns_rdf* origin = NULL;
|
||||
ldns_rdf* prev_rr = NULL;
|
||||
int entry_num = 0;
|
||||
|
||||
if((in=fopen(name, "r")) == NULL) {
|
||||
error("could not open file %s: %s", name, strerror(errno));
|
||||
}
|
||||
|
||||
while((current = read_entry(in, name, &lineno, &default_ttl,
|
||||
&origin, &prev_rr, skip_whitespace)))
|
||||
{
|
||||
if(last)
|
||||
last->next = current;
|
||||
else list = current;
|
||||
last = current;
|
||||
entry_num ++;
|
||||
}
|
||||
verbose(1, "%s: Read %d entries\n", prog_name, entry_num);
|
||||
|
||||
fclose(in);
|
||||
ldns_rdf_deep_free(origin);
|
||||
ldns_rdf_deep_free(prev_rr);
|
||||
return list;
|
||||
}
|
||||
|
||||
/** get qtype from rr */
|
||||
static ldns_rr_type get_qtype(ldns_pkt* p)
|
||||
{
|
||||
if(!ldns_rr_list_rr(ldns_pkt_question(p), 0))
|
||||
return 0;
|
||||
return ldns_rr_get_type(ldns_rr_list_rr(ldns_pkt_question(p), 0));
|
||||
}
|
||||
|
||||
/** returns owner from rr */
|
||||
static ldns_rdf* get_owner(ldns_pkt* p)
|
||||
{
|
||||
if(!ldns_rr_list_rr(ldns_pkt_question(p), 0))
|
||||
return NULL;
|
||||
return ldns_rr_owner(ldns_rr_list_rr(ldns_pkt_question(p), 0));
|
||||
}
|
||||
|
||||
/** get authority section SOA serial value */
|
||||
static uint32_t get_serial(ldns_pkt* p)
|
||||
{
|
||||
ldns_rr *rr = ldns_rr_list_rr(ldns_pkt_authority(p), 0);
|
||||
ldns_rdf *rdf;
|
||||
uint32_t val;
|
||||
if(!rr) return 0;
|
||||
rdf = ldns_rr_rdf(rr, 2);
|
||||
if(!rdf) return 0;
|
||||
val = ldns_rdf2native_int32(rdf);
|
||||
verbose(3, "found serial %u in msg. ", (int)val);
|
||||
return val;
|
||||
}
|
||||
|
||||
/** match two rr lists */
|
||||
static int
|
||||
match_list(ldns_rr_list* q, ldns_rr_list *p, bool mttl)
|
||||
{
|
||||
size_t i;
|
||||
if(ldns_rr_list_rr_count(q) != ldns_rr_list_rr_count(p))
|
||||
return 0;
|
||||
for(i=0; i<ldns_rr_list_rr_count(q); i++)
|
||||
{
|
||||
if(ldns_rr_compare(ldns_rr_list_rr(q, i),
|
||||
ldns_rr_list_rr(p, i)) != 0) {
|
||||
verbose(3, "rr %d different", (int)i);
|
||||
return 0;
|
||||
}
|
||||
if(mttl && ldns_rr_ttl(ldns_rr_list_rr(q, i)) !=
|
||||
ldns_rr_ttl(ldns_rr_list_rr(p, i))) {
|
||||
verbose(3, "rr %d ttl different", (int)i);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
/** compare two booleans */
|
||||
static int
|
||||
cmp_bool(int x, int y)
|
||||
{
|
||||
if(!x && !y) return 0;
|
||||
if(x && y) return 0;
|
||||
if(!x) return -1;
|
||||
return 1;
|
||||
}
|
||||
|
||||
/** match all of the packet */
|
||||
static int
|
||||
match_all(ldns_pkt* q, ldns_pkt* p, bool mttl)
|
||||
{
|
||||
if(ldns_pkt_get_opcode(q) != ldns_pkt_get_opcode(p))
|
||||
{ verbose(3, "allmatch: opcode different"); return 0;}
|
||||
if(ldns_pkt_get_rcode(q) != ldns_pkt_get_rcode(p))
|
||||
{ verbose(3, "allmatch: rcode different"); return 0;}
|
||||
if(ldns_pkt_id(q) != ldns_pkt_id(p))
|
||||
{ verbose(3, "allmatch: id different"); return 0;}
|
||||
if(cmp_bool(ldns_pkt_qr(q), ldns_pkt_qr(p)) != 0)
|
||||
{ verbose(3, "allmatch: qr different"); return 0;}
|
||||
if(cmp_bool(ldns_pkt_aa(q), ldns_pkt_aa(p)) != 0)
|
||||
{ verbose(3, "allmatch: aa different"); return 0;}
|
||||
if(cmp_bool(ldns_pkt_tc(q), ldns_pkt_tc(p)) != 0)
|
||||
{ verbose(3, "allmatch: tc different"); return 0;}
|
||||
if(cmp_bool(ldns_pkt_rd(q), ldns_pkt_rd(p)) != 0)
|
||||
{ verbose(3, "allmatch: rd different"); return 0;}
|
||||
if(cmp_bool(ldns_pkt_cd(q), ldns_pkt_cd(p)) != 0)
|
||||
{ verbose(3, "allmatch: cd different"); return 0;}
|
||||
if(cmp_bool(ldns_pkt_ra(q), ldns_pkt_ra(p)) != 0)
|
||||
{ verbose(3, "allmatch: ra different"); return 0;}
|
||||
if(cmp_bool(ldns_pkt_ad(q), ldns_pkt_ad(p)) != 0)
|
||||
{ verbose(3, "allmatch: ad different"); return 0;}
|
||||
if(ldns_pkt_qdcount(q) != ldns_pkt_qdcount(p))
|
||||
{ verbose(3, "allmatch: qdcount different"); return 0;}
|
||||
if(ldns_pkt_ancount(q) != ldns_pkt_ancount(p))
|
||||
{ verbose(3, "allmatch: ancount different"); return 0;}
|
||||
if(ldns_pkt_nscount(q) != ldns_pkt_nscount(p))
|
||||
{ verbose(3, "allmatch: nscount different"); return 0;}
|
||||
if(ldns_pkt_arcount(q) != ldns_pkt_arcount(p))
|
||||
{ verbose(3, "allmatch: arcount different"); return 0;}
|
||||
if(!match_list(ldns_pkt_question(q), ldns_pkt_question(p), 0))
|
||||
{ verbose(3, "allmatch: qd section different"); return 0;}
|
||||
if(!match_list(ldns_pkt_answer(q), ldns_pkt_answer(p), mttl))
|
||||
{ verbose(3, "allmatch: an section different"); return 0;}
|
||||
if(!match_list(ldns_pkt_authority(q), ldns_pkt_authority(p), mttl))
|
||||
{ verbose(3, "allmatch: ar section different"); return 0;}
|
||||
if(!match_list(ldns_pkt_additional(q), ldns_pkt_additional(p), mttl))
|
||||
{ verbose(3, "allmatch: ns section different"); return 0;}
|
||||
return 1;
|
||||
}
|
||||
|
||||
/** Convert to hexstring and call verbose(), prepend with header */
|
||||
static void
|
||||
verbose_hex(int lvl, uint8_t *data, size_t datalen, const char *header)
|
||||
{
|
||||
verbose(lvl, "%s", header);
|
||||
while (datalen-- > 0) {
|
||||
verbose(lvl, " %02x", (unsigned int)*data++);
|
||||
}
|
||||
verbose(lvl, "\n");
|
||||
}
|
||||
|
||||
/** Match q edns data to p raw edns data */
|
||||
static int
|
||||
match_ednsdata(ldns_pkt* q, struct reply_packet* p)
|
||||
{
|
||||
size_t qdlen, pdlen;
|
||||
uint8_t *qd, *pd;
|
||||
if(!ldns_pkt_edns(q) || !ldns_pkt_edns_data(q)) {
|
||||
verbose(3, "No EDNS data\n");
|
||||
return 0;
|
||||
}
|
||||
qdlen = ldns_rdf_size(ldns_pkt_edns_data(q));
|
||||
pdlen = ldns_buffer_limit(p->raw_ednsdata);
|
||||
qd = ldns_rdf_data(ldns_pkt_edns_data(q));
|
||||
pd = ldns_buffer_begin(p->raw_ednsdata);
|
||||
if( qdlen == pdlen && 0 == memcmp(qd, pd, qdlen) ) return 1;
|
||||
verbose(3, "EDNS data does not match.\n");
|
||||
verbose_hex(3, qd, qdlen, "q:");
|
||||
verbose_hex(3, pd, pdlen, "p:");
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* finds entry in list, or returns NULL */
|
||||
struct entry*
|
||||
find_match(struct entry* entries, ldns_pkt* query_pkt,
|
||||
enum transport_type transport)
|
||||
{
|
||||
struct entry* p = entries;
|
||||
ldns_pkt* reply = NULL;
|
||||
for(p=entries; p; p=p->next) {
|
||||
verbose(3, "comparepkt: ");
|
||||
reply = p->reply_list->reply;
|
||||
if(p->match_opcode && ldns_pkt_get_opcode(query_pkt) !=
|
||||
ldns_pkt_get_opcode(reply)) {
|
||||
verbose(3, "bad opcode\n");
|
||||
continue;
|
||||
}
|
||||
if(p->match_qtype && get_qtype(query_pkt) != get_qtype(reply)) {
|
||||
verbose(3, "bad qtype\n");
|
||||
continue;
|
||||
}
|
||||
if(p->match_qname) {
|
||||
if (!get_owner(query_pkt) || !get_owner(reply)
|
||||
|| ( !p->copy_query
|
||||
&& ldns_dname_compare( get_owner(query_pkt)
|
||||
, get_owner(reply)))
|
||||
|| ( p->copy_query
|
||||
&& !ldns_dname_match_wildcard( get_owner(query_pkt)
|
||||
, get_owner(reply)))) {
|
||||
verbose(3, "bad qname\n");
|
||||
continue;
|
||||
}
|
||||
}
|
||||
if(p->match_subdomain) {
|
||||
if(!get_owner(query_pkt) || !get_owner(reply) ||
|
||||
(ldns_dname_compare(get_owner(query_pkt),
|
||||
get_owner(reply)) != 0 &&
|
||||
!ldns_dname_is_subdomain(
|
||||
get_owner(query_pkt), get_owner(reply))))
|
||||
{
|
||||
verbose(3, "bad subdomain\n");
|
||||
continue;
|
||||
}
|
||||
}
|
||||
if(p->match_serial && get_serial(query_pkt) != p->ixfr_soa_serial) {
|
||||
verbose(3, "bad serial\n");
|
||||
continue;
|
||||
}
|
||||
if(p->match_do && !ldns_pkt_edns_do(query_pkt)) {
|
||||
verbose(3, "no DO bit set\n");
|
||||
continue;
|
||||
}
|
||||
if(p->match_noedns && ldns_pkt_edns(query_pkt)) {
|
||||
verbose(3, "bad; EDNS OPT present\n");
|
||||
continue;
|
||||
}
|
||||
if(p->match_ednsdata_raw &&
|
||||
!match_ednsdata(query_pkt, p->reply_list)) {
|
||||
verbose(3, "bad EDNS data match.\n");
|
||||
continue;
|
||||
}
|
||||
if(p->match_transport != transport_any && p->match_transport != transport) {
|
||||
verbose(3, "bad transport\n");
|
||||
continue;
|
||||
}
|
||||
if(p->match_udp_size > 0 && transport == transport_udp && (
|
||||
!ldns_pkt_edns(query_pkt) ||
|
||||
ldns_pkt_edns_udp_size(query_pkt) < p->match_udp_size)) {
|
||||
verbose(3, "bad udp_size\n");
|
||||
continue;
|
||||
}
|
||||
if(p->match_all && !match_all(query_pkt, reply, p->match_ttl)) {
|
||||
verbose(3, "bad allmatch\n");
|
||||
continue;
|
||||
}
|
||||
verbose(3, "match!\n");
|
||||
return p;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void
|
||||
adjust_packet(struct entry* match, ldns_pkt* answer_pkt, ldns_pkt* query_pkt)
|
||||
{
|
||||
/* copy & adjust packet */
|
||||
if(match->copy_id)
|
||||
ldns_pkt_set_id(answer_pkt, ldns_pkt_id(query_pkt));
|
||||
if(match->copy_query) {
|
||||
ldns_rr_list* list = ldns_pkt_get_section_clone(query_pkt,
|
||||
LDNS_SECTION_QUESTION);
|
||||
ldns_rr_list_deep_free(ldns_pkt_question(answer_pkt));
|
||||
ldns_pkt_set_question(answer_pkt, list);
|
||||
}
|
||||
if(match->sleeptime > 0) {
|
||||
verbose(3, "sleeping for %d seconds\n", match->sleeptime);
|
||||
#ifdef HAVE_SLEEP
|
||||
sleep(match->sleeptime);
|
||||
#else
|
||||
Sleep(match->sleeptime * 1000);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Parses data buffer to a query, finds the correct answer
|
||||
* and calls the given function for every packet to send.
|
||||
*/
|
||||
void
|
||||
handle_query(uint8_t* inbuf, ssize_t inlen, struct entry* entries, int* count,
|
||||
enum transport_type transport, void (*sendfunc)(uint8_t*, size_t, void*),
|
||||
void* userdata, FILE* verbose_out)
|
||||
{
|
||||
ldns_status status;
|
||||
ldns_pkt *query_pkt = NULL;
|
||||
ldns_pkt *answer_pkt = NULL;
|
||||
struct reply_packet *p;
|
||||
ldns_rr *query_rr = NULL;
|
||||
uint8_t *outbuf = NULL;
|
||||
size_t answer_size = 0;
|
||||
struct entry* entry = NULL;
|
||||
ldns_rdf *stop_command = ldns_dname_new_frm_str("server.stop.");
|
||||
|
||||
status = ldns_wire2pkt(&query_pkt, inbuf, (size_t)inlen);
|
||||
if (status != LDNS_STATUS_OK) {
|
||||
verbose(1, "Got bad packet: %s\n", ldns_get_errorstr_by_id(status));
|
||||
ldns_rdf_deep_free(stop_command);
|
||||
return;
|
||||
}
|
||||
|
||||
query_rr = ldns_rr_list_rr(ldns_pkt_question(query_pkt), 0);
|
||||
verbose(1, "query %d: id %d: %s %d bytes: ", ++(*count), (int)ldns_pkt_id(query_pkt),
|
||||
(transport==transport_tcp)?"TCP":"UDP", (int)inlen);
|
||||
if(verbose_out) ldns_rr_print(verbose_out, query_rr);
|
||||
if(verbose_out) ldns_pkt_print(verbose_out, query_pkt);
|
||||
|
||||
if (ldns_rr_get_type(query_rr) == LDNS_RR_TYPE_TXT &&
|
||||
ldns_rr_get_class(query_rr) == LDNS_RR_CLASS_CH &&
|
||||
ldns_dname_compare(ldns_rr_owner(query_rr), stop_command) == 0) {
|
||||
exit(0);
|
||||
}
|
||||
|
||||
/* fill up answer packet */
|
||||
entry = find_match(entries, query_pkt, transport);
|
||||
if(!entry || !entry->reply_list) {
|
||||
verbose(1, "no answer packet for this query, no reply.\n");
|
||||
ldns_pkt_free(query_pkt);
|
||||
ldns_rdf_deep_free(stop_command);
|
||||
return;
|
||||
}
|
||||
for(p = entry->reply_list; p; p = p->next)
|
||||
{
|
||||
verbose(3, "Answer pkt:\n");
|
||||
if (p->reply_from_hex) {
|
||||
/* try to parse the hex packet, if it can be
|
||||
* parsed, we can use adjust rules. if not,
|
||||
* send packet literally */
|
||||
status = ldns_buffer2pkt_wire(&answer_pkt, p->reply_from_hex);
|
||||
if (status == LDNS_STATUS_OK) {
|
||||
adjust_packet(entry, answer_pkt, query_pkt);
|
||||
if(verbose_out) ldns_pkt_print(verbose_out, answer_pkt);
|
||||
status = ldns_pkt2wire(&outbuf, answer_pkt, &answer_size);
|
||||
verbose(2, "Answer packet size: %u bytes.\n", (unsigned int)answer_size);
|
||||
if (status != LDNS_STATUS_OK) {
|
||||
verbose(1, "Error creating answer: %s\n", ldns_get_errorstr_by_id(status));
|
||||
ldns_pkt_free(query_pkt);
|
||||
ldns_rdf_deep_free(stop_command);
|
||||
return;
|
||||
}
|
||||
ldns_pkt_free(answer_pkt);
|
||||
answer_pkt = NULL;
|
||||
} else {
|
||||
verbose(3, "Could not parse hex data (%s), sending hex data directly.\n", ldns_get_errorstr_by_id(status));
|
||||
/* still try to adjust ID */
|
||||
answer_size = ldns_buffer_capacity(p->reply_from_hex);
|
||||
outbuf = LDNS_XMALLOC(uint8_t, answer_size);
|
||||
memcpy(outbuf, ldns_buffer_begin(p->reply_from_hex), answer_size);
|
||||
if(entry->copy_id) {
|
||||
ldns_write_uint16(outbuf,
|
||||
ldns_pkt_id(query_pkt));
|
||||
}
|
||||
}
|
||||
} else {
|
||||
answer_pkt = ldns_pkt_clone(p->reply);
|
||||
adjust_packet(entry, answer_pkt, query_pkt);
|
||||
if(verbose_out) ldns_pkt_print(verbose_out, answer_pkt);
|
||||
status = ldns_pkt2wire(&outbuf, answer_pkt, &answer_size);
|
||||
verbose(1, "Answer packet size: %u bytes.\n", (unsigned int)answer_size);
|
||||
if (status != LDNS_STATUS_OK) {
|
||||
verbose(1, "Error creating answer: %s\n", ldns_get_errorstr_by_id(status));
|
||||
ldns_pkt_free(query_pkt);
|
||||
ldns_rdf_deep_free(stop_command);
|
||||
return;
|
||||
}
|
||||
ldns_pkt_free(answer_pkt);
|
||||
answer_pkt = NULL;
|
||||
}
|
||||
if(p->packet_sleep) {
|
||||
verbose(3, "sleeping for next packet %d secs\n",
|
||||
p->packet_sleep);
|
||||
#ifdef HAVE_SLEEP
|
||||
sleep(p->packet_sleep);
|
||||
#else
|
||||
Sleep(p->packet_sleep * 1000);
|
||||
#endif
|
||||
verbose(3, "wakeup for next packet "
|
||||
"(slept %d secs)\n", p->packet_sleep);
|
||||
}
|
||||
sendfunc(outbuf, answer_size, userdata);
|
||||
LDNS_FREE(outbuf);
|
||||
outbuf = NULL;
|
||||
answer_size = 0;
|
||||
}
|
||||
ldns_pkt_free(query_pkt);
|
||||
ldns_rdf_deep_free(stop_command);
|
||||
}
|
||||
|
||||
/** delete the list of reply packets */
|
||||
static void delete_replylist(struct reply_packet* replist)
|
||||
{
|
||||
struct reply_packet *p=replist, *np;
|
||||
while(p) {
|
||||
np = p->next;
|
||||
ldns_pkt_free(p->reply);
|
||||
ldns_buffer_free(p->reply_from_hex);
|
||||
free(p);
|
||||
p=np;
|
||||
}
|
||||
}
|
||||
|
||||
void delete_entry(struct entry* list)
|
||||
{
|
||||
struct entry *p=list, *np;
|
||||
while(p) {
|
||||
np = p->next;
|
||||
delete_replylist(p->reply_list);
|
||||
free(p);
|
||||
p = np;
|
||||
}
|
||||
}
|
||||
274
zonemaster-ldns/ldns/examples/ldns-testpkts.h
Normal file
274
zonemaster-ldns/ldns/examples/ldns-testpkts.h
Normal file
@@ -0,0 +1,274 @@
|
||||
/*
|
||||
* ldns-testpkts. Data file parse for test packets, and query matching.
|
||||
*
|
||||
* Data storage for specially crafted replies for testing purposes.
|
||||
*
|
||||
* (c) NLnet Labs, 2005, 2006, 2007
|
||||
* See the file LICENSE for the license
|
||||
*/
|
||||
|
||||
#ifndef LDNS_TESTPKTS_H
|
||||
#define LDNS_TESTPKTS_H
|
||||
|
||||
/**
|
||||
* \file
|
||||
*
|
||||
* This is a debugging aid. It is not efficient, especially
|
||||
* with a long config file, but it can give any reply to any query.
|
||||
* This can help the developer pre-script replies for queries.
|
||||
*
|
||||
* You can specify a packet RR by RR with header flags to return.
|
||||
*
|
||||
* Missing features:
|
||||
* - matching content different from reply content.
|
||||
* - find way to adjust mangled packets?
|
||||
*
|
||||
*/
|
||||
|
||||
/*
|
||||
The data file format is as follows:
|
||||
|
||||
; comment.
|
||||
; a number of entries, these are processed first to last.
|
||||
; a line based format.
|
||||
|
||||
$ORIGIN origin
|
||||
$TTL default_ttl
|
||||
|
||||
ENTRY_BEGIN
|
||||
; first give MATCH lines, that say what queries are matched
|
||||
; by this entry.
|
||||
; 'opcode' makes the query match the opcode from the reply
|
||||
; if you leave it out, any opcode matches this entry.
|
||||
; 'qtype' makes the query match the qtype from the reply
|
||||
; 'qname' makes the query match the qname from the reply
|
||||
; 'subdomain' makes the query match subdomains of qname from the reply
|
||||
; 'serial=1023' makes the query match if ixfr serial is 1023.
|
||||
; 'all' has to match header byte for byte and all rrs in packet.
|
||||
; 'ttl' used with all, rrs in packet must also have matching TTLs.
|
||||
; 'DO' will match only queries with DO bit set.
|
||||
; 'noedns' matches queries without EDNS OPT records.
|
||||
; 'ednsdata' matches queries to HEX_EDNS section.
|
||||
; 'udp_size=1232' makes the query match if:
|
||||
; udp_size in query edns0 field >= 1232,
|
||||
; or the query came over TCP.
|
||||
MATCH [opcode] [qtype] [qname] [serial=<value>] [all] [ttl]
|
||||
MATCH [UDP|TCP] DO
|
||||
MATCH ...
|
||||
; Then the REPLY header is specified.
|
||||
REPLY opcode, rcode or flags.
|
||||
(opcode) QUERY IQUERY STATUS NOTIFY UPDATE
|
||||
(rcode) NOERROR FORMERR SERVFAIL NXDOMAIN NOTIMPL YXDOMAIN
|
||||
YXRRSET NXRRSET NOTAUTH NOTZONE
|
||||
(flags) QR AA TC RD CD RA AD DO
|
||||
REPLY ...
|
||||
; any additional actions to do.
|
||||
; 'copy_id' copies the ID from the query to the answer.
|
||||
ADJUST copy_id
|
||||
; 'copy_query' copies the query name, type and class to the answer.
|
||||
ADJUST copy_query
|
||||
; 'sleep=10' sleeps for 10 seconds before giving the answer (TCP is open)
|
||||
ADJUST [sleep=<num>] ; sleep before giving any reply
|
||||
ADJUST [packet_sleep=<num>] ; sleep before this packet in sequence
|
||||
SECTION QUESTION
|
||||
<RRs, one per line> ; the RRcount is determined automatically.
|
||||
SECTION ANSWER
|
||||
<RRs, one per line>
|
||||
SECTION AUTHORITY
|
||||
<RRs, one per line>
|
||||
SECTION ADDITIONAL
|
||||
<RRs, one per line>
|
||||
EXTRA_PACKET ; follow with SECTION, REPLY for more packets.
|
||||
HEX_ANSWER_BEGIN ; follow with hex data
|
||||
; this replaces any answer packet constructed
|
||||
; with the SECTION keywords (only SECTION QUERY
|
||||
; is used to match queries). If the data cannot
|
||||
; be parsed, ADJUST rules for the answer packet
|
||||
; are ignored. Only copy_id is done.
|
||||
HEX_ANSWER_END
|
||||
HEX_EDNS_BEGIN ; follow with hex data.
|
||||
; Raw EDNS data to match against. It must be an
|
||||
; exact match (all options are matched) and will be
|
||||
; evaluated only when 'MATCH ednsdata' given.
|
||||
HEX_EDNS_END
|
||||
ENTRY_END
|
||||
|
||||
|
||||
Example data file:
|
||||
$ORIGIN nlnetlabs.nl
|
||||
$TTL 3600
|
||||
|
||||
ENTRY_BEGIN
|
||||
MATCH qname
|
||||
REPLY NOERROR
|
||||
ADJUST copy_id
|
||||
SECTION QUESTION
|
||||
www.nlnetlabs.nl. IN A
|
||||
SECTION ANSWER
|
||||
www.nlnetlabs.nl. IN A 195.169.215.155
|
||||
SECTION AUTHORITY
|
||||
nlnetlabs.nl. IN NS www.nlnetlabs.nl.
|
||||
ENTRY_END
|
||||
|
||||
ENTRY_BEGIN
|
||||
MATCH qname
|
||||
REPLY NOERROR
|
||||
ADJUST copy_id
|
||||
SECTION QUESTION
|
||||
www2.nlnetlabs.nl. IN A
|
||||
HEX_ANSWER_BEGIN
|
||||
; 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
|
||||
;-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
|
||||
00 bf 81 80 00 01 00 01 00 02 00 02 03 77 77 77 0b 6b 61 6e ; 1- 20
|
||||
61 72 69 65 70 69 65 74 03 63 6f 6d 00 00 01 00 01 03 77 77 ; 21- 40
|
||||
77 0b 6b 61 6e 61 72 69 65 70 69 65 74 03 63 6f 6d 00 00 01 ; 41- 60
|
||||
00 01 00 01 50 8b 00 04 52 5e ed 32 0b 6b 61 6e 61 72 69 65 ; 61- 80
|
||||
70 69 65 74 03 63 6f 6d 00 00 02 00 01 00 01 50 8b 00 11 03 ; 81- 100
|
||||
6e 73 31 08 68 65 78 6f 6e 2d 69 73 02 6e 6c 00 0b 6b 61 6e ; 101- 120
|
||||
61 72 69 65 70 69 65 74 03 63 6f 6d 00 00 02 00 01 00 01 50 ; 121- 140
|
||||
8b 00 11 03 6e 73 32 08 68 65 78 6f 6e 2d 69 73 02 6e 6c 00 ; 141- 160
|
||||
03 6e 73 31 08 68 65 78 6f 6e 2d 69 73 02 6e 6c 00 00 01 00 ; 161- 180
|
||||
01 00 00 46 53 00 04 52 5e ed 02 03 6e 73 32 08 68 65 78 6f ; 181- 200
|
||||
6e 2d 69 73 02 6e 6c 00 00 01 00 01 00 00 46 53 00 04 d4 cc ; 201- 220
|
||||
db 5b
|
||||
HEX_ANSWER_END
|
||||
ENTRY_END
|
||||
|
||||
|
||||
|
||||
note that this file will link with your
|
||||
void verbose(int level, char* format, ...); output function.
|
||||
*/
|
||||
|
||||
#include <ldns/ldns.h>
|
||||
|
||||
/** Type of transport, since some entries match based on UDP or TCP of query */
|
||||
enum transport_type {transport_any = 0, transport_udp, transport_tcp };
|
||||
|
||||
/** struct to keep a linked list of reply packets for a query */
|
||||
struct reply_packet {
|
||||
/** next in list of reply packets, for TCP multiple pkts on wire */
|
||||
struct reply_packet* next;
|
||||
/** the reply pkt */
|
||||
ldns_pkt* reply;
|
||||
/** Additional EDNS data for matching queries. */
|
||||
ldns_buffer* raw_ednsdata;
|
||||
/** or reply pkt in hex if not parsable */
|
||||
ldns_buffer* reply_from_hex;
|
||||
/** seconds to sleep before giving packet */
|
||||
unsigned int packet_sleep;
|
||||
};
|
||||
|
||||
/** data structure to keep the canned queries in.
|
||||
format is the 'matching query' and the 'canned answer' */
|
||||
struct entry {
|
||||
/* match */
|
||||
/* How to match an incoming query with this canned reply */
|
||||
/** match query opcode with answer opcode */
|
||||
bool match_opcode;
|
||||
/** match qtype with answer qtype */
|
||||
bool match_qtype;
|
||||
/** match qname with answer qname */
|
||||
bool match_qname;
|
||||
/** match qname as subdomain of answer qname */
|
||||
bool match_subdomain;
|
||||
/** match SOA serial number, from auth section */
|
||||
bool match_serial;
|
||||
/** match all of the packet */
|
||||
bool match_all;
|
||||
/** match ttls in the packet */
|
||||
bool match_ttl;
|
||||
/** match DO bit */
|
||||
bool match_do;
|
||||
/** match absence of EDNS OPT record in query */
|
||||
bool match_noedns;
|
||||
/** match edns data field given in hex */
|
||||
bool match_ednsdata_raw;
|
||||
/** match query serial with this value. */
|
||||
uint32_t ixfr_soa_serial;
|
||||
/** match on UDP/TCP */
|
||||
enum transport_type match_transport;
|
||||
/** match on edns udp size (larger or equal) */
|
||||
uint16_t match_udp_size;
|
||||
|
||||
/** pre canned reply */
|
||||
struct reply_packet *reply_list;
|
||||
|
||||
/** how to adjust the reply packet */
|
||||
/** copy over the ID from the query into the answer */
|
||||
bool copy_id;
|
||||
/** copy the query nametypeclass from query into the answer */
|
||||
bool copy_query;
|
||||
/** in seconds */
|
||||
unsigned int sleeptime;
|
||||
|
||||
/** some number that names this entry, line number in file or so */
|
||||
int lineno;
|
||||
|
||||
/** next in list */
|
||||
struct entry* next;
|
||||
};
|
||||
|
||||
/**
|
||||
* reads the canned reply file and returns a list of structs
|
||||
* does an exit on error.
|
||||
* @param name: name of the file to read.
|
||||
* @param skip_whitespace: skip leftside whitespace.
|
||||
*/
|
||||
struct entry* read_datafile(const char* name, int skip_whitespace);
|
||||
|
||||
/**
|
||||
* Delete linked list of entries.
|
||||
*/
|
||||
void delete_entry(struct entry* list);
|
||||
|
||||
/**
|
||||
* Read one entry from the data file.
|
||||
* @param in: file to read from. Filepos must be at the start of a new line.
|
||||
* @param name: name of the file for prettier errors.
|
||||
* @param lineno: line number in file, incremented as lines are read.
|
||||
* for prettier errors.
|
||||
* @param default_ttl: on first call set to default TTL for entries,
|
||||
* later it stores the $TTL value last seen. Try 3600 first call.
|
||||
* @param origin: domain name for origin appending. Can be &NULL on first call.
|
||||
* later it stores the $ORIGIN value last seen. Often &NULL or the zone
|
||||
* name on first call.
|
||||
* @param prev_rr: previous rr name for correcter parsing. &NULL on first call.
|
||||
* @param skip_whitespace: skip leftside whitespace.
|
||||
* @return: The entry read (malloced) or NULL if no entry could be read.
|
||||
*/
|
||||
struct entry* read_entry(FILE* in, const char* name, int *lineno,
|
||||
uint32_t* default_ttl, ldns_rdf** origin, ldns_rdf** prev_rr,
|
||||
int skip_whitespace);
|
||||
|
||||
/**
|
||||
* finds entry in list, or returns NULL.
|
||||
*/
|
||||
struct entry* find_match(struct entry* entries, ldns_pkt* query_pkt,
|
||||
enum transport_type transport);
|
||||
|
||||
/**
|
||||
* copy & adjust packet
|
||||
*/
|
||||
void adjust_packet(struct entry* match, ldns_pkt* answer_pkt,
|
||||
ldns_pkt* query_pkt);
|
||||
|
||||
/**
|
||||
* Parses data buffer to a query, finds the correct answer
|
||||
* and calls the given function for every packet to send.
|
||||
* if verbose_out filename is given, packets are dumped there.
|
||||
* @param inbuf: the packet that came in
|
||||
* @param inlen: length of packet.
|
||||
* @param entries: entries read in from datafile.
|
||||
* @param count: is increased to count number of queries answered.
|
||||
* @param transport: set to UDP or TCP to match some types of entries.
|
||||
* @param sendfunc: called to send answer (buffer, size, userarg).
|
||||
* @param userdata: userarg to give to sendfunc.
|
||||
* @param verbose_out: if not NULL, verbose messages are printed there.
|
||||
*/
|
||||
void handle_query(uint8_t* inbuf, ssize_t inlen, struct entry* entries,
|
||||
int* count, enum transport_type transport,
|
||||
void (*sendfunc)(uint8_t*, size_t, void*), void* userdata,
|
||||
FILE* verbose_out);
|
||||
|
||||
#endif /* LDNS_TESTPKTS_H */
|
||||
52
zonemaster-ldns/ldns/examples/ldns-update.1
Normal file
52
zonemaster-ldns/ldns/examples/ldns-update.1
Normal file
@@ -0,0 +1,52 @@
|
||||
.TH ldns-update 1 "30 May 2005"
|
||||
.SH NAME
|
||||
ldns-update \- send a dynamic update packet
|
||||
.SH SYNOPSIS
|
||||
.B ldns-update
|
||||
.IR name
|
||||
[
|
||||
.IR zone
|
||||
]
|
||||
[
|
||||
.IR ip
|
||||
]
|
||||
[
|
||||
.IR tsig_name
|
||||
.IR tsig_alg
|
||||
.IR tsig_hmac
|
||||
]
|
||||
|
||||
.SH DESCRIPTION
|
||||
\fBldns-update\fR is used to send a dynamic update packet.
|
||||
|
||||
.SH OPTIONS
|
||||
.TP
|
||||
\fBname\fR
|
||||
The domainname to associate with the given \fBip\fR address.
|
||||
|
||||
.TP
|
||||
\fBzone\fR
|
||||
When given uses this \fBzone\fR instead of trying to find and process \fBdomain\fR's SOA record.
|
||||
|
||||
.TP
|
||||
\fBip\fR
|
||||
Send the update to this IP address.
|
||||
Or, when the literal text \fBnone\fR is given, remove any previous addresses.
|
||||
|
||||
.TP
|
||||
\fBtsig_name tsig_alg tsig_hmac\fR
|
||||
Use TSIG (rfc2845) to authenticate.
|
||||
|
||||
.SH EXAMPLE
|
||||
ldns-update my.example.org 1.2.3.4
|
||||
|
||||
.SH AUTHOR
|
||||
Written by Jakob Schlyter and Håkan Olsson, as an addition to the ldns library from NLnet Labs.
|
||||
|
||||
.SH REPORTING BUGS
|
||||
Report bugs to <dns-team@nlnetlabs.nl>.
|
||||
|
||||
.SH COPYRIGHT
|
||||
Copyright (C) 2005 NLnet Labs. This is free software. There is NO
|
||||
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR
|
||||
PURPOSE.
|
||||
320
zonemaster-ldns/ldns/examples/ldns-update.c
Normal file
320
zonemaster-ldns/ldns/examples/ldns-update.c
Normal file
@@ -0,0 +1,320 @@
|
||||
/* $Id: ldns-update.c,v 1.1 2005/09/13 09:37:05 ho Exp $ */
|
||||
/*
|
||||
* Example of the update functionality
|
||||
*
|
||||
* See the file LICENSE for the license
|
||||
*/
|
||||
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include <strings.h>
|
||||
#include <ldns/ldns.h>
|
||||
|
||||
/* dynamic update stuff */
|
||||
static ldns_resolver *
|
||||
ldns_update_resolver_new(const char *fqdn, const char *zone,
|
||||
ldns_rr_class class, uint16_t port, ldns_tsig_credentials *tsig_cred, ldns_rdf **zone_rdf)
|
||||
{
|
||||
ldns_resolver *r1, *r2;
|
||||
ldns_pkt *query = NULL, *resp = NULL;
|
||||
ldns_rr_list *nslist, *iplist;
|
||||
ldns_rdf *soa_zone, *soa_mname = NULL, *ns_name;
|
||||
size_t i;
|
||||
ldns_status s;
|
||||
|
||||
if (class == 0) {
|
||||
class = LDNS_RR_CLASS_IN;
|
||||
}
|
||||
|
||||
if (port == 0) {
|
||||
port = LDNS_PORT;
|
||||
}
|
||||
|
||||
/* First, get data from /etc/resolv.conf */
|
||||
s = ldns_resolver_new_frm_file(&r1, NULL);
|
||||
if (s != LDNS_STATUS_OK) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
r2 = ldns_resolver_new();
|
||||
if (!r2) {
|
||||
goto bad;
|
||||
}
|
||||
ldns_resolver_set_port(r2, port);
|
||||
|
||||
/* TSIG key data available? Copy into the resolver. */
|
||||
if (tsig_cred) {
|
||||
ldns_resolver_set_tsig_algorithm(r2, ldns_tsig_algorithm(tsig_cred));
|
||||
ldns_resolver_set_tsig_keyname(r2, ldns_tsig_keyname(tsig_cred));
|
||||
ldns_resolver_set_tsig_keydata(r2, ldns_tsig_keydata(tsig_cred));
|
||||
}
|
||||
|
||||
/* Now get SOA zone, mname, NS, and construct r2. [RFC2136 4.3] */
|
||||
|
||||
/* Explicit 'zone' or no? */
|
||||
if (zone) {
|
||||
soa_zone = ldns_dname_new_frm_str(zone);
|
||||
if (ldns_update_soa_mname(soa_zone, r1, class, &soa_mname)
|
||||
!= LDNS_STATUS_OK) {
|
||||
goto bad;
|
||||
}
|
||||
} else {
|
||||
if (ldns_update_soa_zone_mname(fqdn, r1, class, &soa_zone,
|
||||
&soa_mname) != LDNS_STATUS_OK) {
|
||||
goto bad;
|
||||
}
|
||||
}
|
||||
|
||||
/* Pass zone_rdf on upwards. */
|
||||
*zone_rdf = ldns_rdf_clone(soa_zone);
|
||||
|
||||
/* NS */
|
||||
query = ldns_pkt_query_new(soa_zone, LDNS_RR_TYPE_NS, class, LDNS_RD);
|
||||
if (!query) {
|
||||
goto bad;
|
||||
}
|
||||
soa_zone = NULL;
|
||||
|
||||
ldns_pkt_set_random_id(query);
|
||||
|
||||
if (ldns_resolver_send_pkt(&resp, r1, query) != LDNS_STATUS_OK) {
|
||||
dprintf("%s", "NS query failed!\n");
|
||||
goto bad;
|
||||
}
|
||||
ldns_pkt_free(query);
|
||||
if (!resp) {
|
||||
goto bad;
|
||||
}
|
||||
/* Match SOA MNAME to NS list, adding it first */
|
||||
nslist = ldns_pkt_answer(resp);
|
||||
for (i = 0; i < ldns_rr_list_rr_count(nslist); i++) {
|
||||
ns_name = ldns_rr_rdf(ldns_rr_list_rr(nslist, i), 0);
|
||||
if (!ns_name)
|
||||
continue;
|
||||
if (ldns_rdf_compare(soa_mname, ns_name) == 0) {
|
||||
/* Match */
|
||||
iplist = ldns_get_rr_list_addr_by_name(r1, ns_name, class, 0);
|
||||
(void) ldns_resolver_push_nameserver_rr_list(r2, iplist);
|
||||
ldns_rr_list_deep_free(iplist);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* Then all the other NSs. XXX Randomize? */
|
||||
for (i = 0; i < ldns_rr_list_rr_count(nslist); i++) {
|
||||
ns_name = ldns_rr_rdf(ldns_rr_list_rr(nslist, i), 0);
|
||||
if (!ns_name)
|
||||
continue;
|
||||
if (ldns_rdf_compare(soa_mname, ns_name) != 0) {
|
||||
/* No match, add it now. */
|
||||
iplist = ldns_get_rr_list_addr_by_name(r1, ns_name, class, 0);
|
||||
(void) ldns_resolver_push_nameserver_rr_list(r2, iplist);
|
||||
ldns_rr_list_deep_free(iplist);
|
||||
}
|
||||
}
|
||||
|
||||
ldns_resolver_set_random(r2, false);
|
||||
ldns_pkt_free(resp);
|
||||
ldns_resolver_deep_free(r1);
|
||||
if (soa_mname)
|
||||
ldns_rdf_deep_free(soa_mname);
|
||||
return r2;
|
||||
|
||||
bad:
|
||||
if (r1)
|
||||
ldns_resolver_deep_free(r1);
|
||||
if (r2)
|
||||
ldns_resolver_deep_free(r2);
|
||||
if (query)
|
||||
ldns_pkt_free(query);
|
||||
if (resp)
|
||||
ldns_pkt_free(resp);
|
||||
if (soa_mname)
|
||||
ldns_rdf_deep_free(soa_mname);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
static ldns_status
|
||||
ldns_update_send_simple_addr(const char *fqdn, const char *zone,
|
||||
const char *ipaddr, uint16_t p, uint32_t ttl, ldns_tsig_credentials *tsig_cred)
|
||||
{
|
||||
ldns_resolver *res;
|
||||
ldns_pkt *u_pkt = NULL, *r_pkt;
|
||||
ldns_rr_list *up_rrlist;
|
||||
ldns_rr *up_rr;
|
||||
ldns_rdf *zone_rdf = NULL;
|
||||
char *rrstr;
|
||||
uint32_t rrstrlen, status = LDNS_STATUS_OK;
|
||||
|
||||
if (!fqdn || strlen(fqdn) == 0)
|
||||
return LDNS_STATUS_ERR;
|
||||
|
||||
/* Create resolver */
|
||||
res = ldns_update_resolver_new(fqdn, zone, 0, p, tsig_cred, &zone_rdf);
|
||||
if (!res || !zone_rdf) {
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
/* Set up the update section. */
|
||||
up_rrlist = ldns_rr_list_new();
|
||||
if (!up_rrlist) {
|
||||
goto cleanup;
|
||||
}
|
||||
/* Create input for ldns_rr_new_frm_str() */
|
||||
if (ipaddr) {
|
||||
/* We're adding A or AAAA */
|
||||
rrstrlen = strlen(fqdn) + sizeof (" IN AAAA ") + strlen(ipaddr) + 1;
|
||||
rrstr = (char *)malloc(rrstrlen);
|
||||
if (!rrstr) {
|
||||
ldns_rr_list_deep_free(up_rrlist);
|
||||
goto cleanup;
|
||||
}
|
||||
snprintf(rrstr, rrstrlen, "%s IN %s %s", fqdn,
|
||||
strchr(ipaddr, ':') ? "AAAA" : "A", ipaddr);
|
||||
|
||||
if (ldns_rr_new_frm_str(&up_rr, rrstr, ttl, NULL, NULL) !=
|
||||
LDNS_STATUS_OK) {
|
||||
ldns_rr_list_deep_free(up_rrlist);
|
||||
free(rrstr);
|
||||
goto cleanup;
|
||||
}
|
||||
free(rrstr);
|
||||
ldns_rr_list_push_rr(up_rrlist, up_rr);
|
||||
} else {
|
||||
/* We're removing A and/or AAAA from 'fqdn'. [RFC2136 2.5.2] */
|
||||
up_rr = ldns_rr_new();
|
||||
ldns_rr_set_owner(up_rr, ldns_dname_new_frm_str(fqdn));
|
||||
ldns_rr_set_ttl(up_rr, 0);
|
||||
ldns_rr_set_class(up_rr, LDNS_RR_CLASS_ANY);
|
||||
|
||||
ldns_rr_set_type(up_rr, LDNS_RR_TYPE_A);
|
||||
ldns_rr_list_push_rr(up_rrlist, ldns_rr_clone(up_rr));
|
||||
|
||||
ldns_rr_set_type(up_rr, LDNS_RR_TYPE_AAAA);
|
||||
ldns_rr_list_push_rr(up_rrlist, up_rr);
|
||||
}
|
||||
|
||||
/* Create update packet. */
|
||||
u_pkt = ldns_update_pkt_new(zone_rdf, LDNS_RR_CLASS_IN, NULL, up_rrlist, NULL);
|
||||
zone_rdf = NULL;
|
||||
if (!u_pkt) {
|
||||
ldns_rr_list_deep_free(up_rrlist);
|
||||
goto cleanup;
|
||||
}
|
||||
ldns_pkt_set_random_id(u_pkt);
|
||||
|
||||
/* Add TSIG */
|
||||
if (tsig_cred)
|
||||
if (ldns_update_pkt_tsig_add(u_pkt, res) != LDNS_STATUS_OK) {
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
if (ldns_resolver_send_pkt(&r_pkt, res, u_pkt) != LDNS_STATUS_OK) {
|
||||
goto cleanup;
|
||||
}
|
||||
ldns_pkt_free(u_pkt);
|
||||
if (!r_pkt) {
|
||||
goto cleanup;
|
||||
}
|
||||
if (ldns_pkt_get_rcode(r_pkt) != LDNS_RCODE_NOERROR) {
|
||||
ldns_lookup_table *t = ldns_lookup_by_id(ldns_rcodes,
|
||||
(int)ldns_pkt_get_rcode(r_pkt));
|
||||
if (t) {
|
||||
dprintf(";; UPDATE response was %s\n", t->name);
|
||||
} else {
|
||||
dprintf(";; UPDATE response was (%d)\n", ldns_pkt_get_rcode(r_pkt));
|
||||
}
|
||||
status = LDNS_STATUS_ERR;
|
||||
}
|
||||
ldns_pkt_free(r_pkt);
|
||||
ldns_resolver_deep_free(res);
|
||||
return status;
|
||||
|
||||
cleanup:
|
||||
if (res)
|
||||
ldns_resolver_deep_free(res);
|
||||
if (u_pkt)
|
||||
ldns_pkt_free(u_pkt);
|
||||
if (zone_rdf)
|
||||
ldns_rdf_deep_free(zone_rdf);
|
||||
return LDNS_STATUS_ERR;
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
usage(FILE *fp, char *prog)
|
||||
{
|
||||
fprintf(fp, "%s domain [zone] ip tsig_name tsig_alg tsig_hmac\n", prog);
|
||||
fprintf(fp, " send a dynamic update packet to <ip>\n\n");
|
||||
fprintf(fp, " Use 'none' instead of ip to remove any previous address\n");
|
||||
fprintf(fp, " If 'zone' is not specified, try to figure it out from the zone's SOA\n");
|
||||
fprintf(fp, " Example: %s my.example.org 1.2.3.4\n", prog);
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
main(int argc, char **argv)
|
||||
{
|
||||
char *fqdn, *ipaddr, *zone, *prog;
|
||||
ldns_status ret;
|
||||
ldns_tsig_credentials tsig_cr, *tsig_cred;
|
||||
int c = 2;
|
||||
uint32_t defttl = 300;
|
||||
uint32_t port = 53;
|
||||
|
||||
prog = strdup(argv[0]);
|
||||
|
||||
switch (argc) {
|
||||
case 3:
|
||||
case 4:
|
||||
case 6:
|
||||
case 7:
|
||||
break;
|
||||
default:
|
||||
usage(stderr, prog);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
fqdn = argv[1];
|
||||
c = 2;
|
||||
if (argc == 4 || argc == 7) {
|
||||
zone = argv[c++];
|
||||
} else {
|
||||
zone = NULL;
|
||||
}
|
||||
|
||||
if (strcmp(argv[c], "none") == 0) {
|
||||
ipaddr = NULL;
|
||||
} else {
|
||||
ipaddr = argv[c];
|
||||
}
|
||||
c++;
|
||||
if (argc == 6 || argc == 7) {
|
||||
tsig_cr.keyname = argv[c++];
|
||||
if (strncasecmp(argv[c], "hmac-sha1", 9) == 0) {
|
||||
tsig_cr.algorithm = (char*)"hmac-sha1.";
|
||||
} else if (strncasecmp(argv[c], "hmac-md5", 8) == 0) {
|
||||
tsig_cr.algorithm = (char*)"hmac-md5.sig-alg.reg.int.";
|
||||
} else {
|
||||
fprintf(stderr, "Unknown algorithm, try \"hmac-md5\" "
|
||||
"or \"hmac-sha1\".\n");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
tsig_cr.keydata = argv[++c];
|
||||
tsig_cred = &tsig_cr;
|
||||
} else {
|
||||
tsig_cred = NULL;
|
||||
}
|
||||
|
||||
printf(";; trying UPDATE with FQDN \"%s\" and IP \"%s\"\n",
|
||||
fqdn, ipaddr ? ipaddr : "<none>");
|
||||
if (argc == 6 || argc == 7) {
|
||||
printf(";; tsig: \"%s\" \"%s\" \"%s\"\n", tsig_cr.keyname,
|
||||
tsig_cr.algorithm, tsig_cr.keydata);
|
||||
}
|
||||
|
||||
ret = ldns_update_send_simple_addr(fqdn, zone, ipaddr, port, defttl, tsig_cred);
|
||||
exit(ret);
|
||||
}
|
||||
115
zonemaster-ldns/ldns/examples/ldns-verify-zone.1.in
Normal file
115
zonemaster-ldns/ldns/examples/ldns-verify-zone.1.in
Normal file
@@ -0,0 +1,115 @@
|
||||
.TH ldns-verifyzone 1 "27 May 2008"
|
||||
.SH NAME
|
||||
ldns-verify-zone \- read a DNSSEC signed zone and verify it.
|
||||
.SH SYNOPSIS
|
||||
.B ldns-verify-zone
|
||||
.IR ZONEFILE
|
||||
|
||||
.SH DESCRIPTION
|
||||
|
||||
\fBldns-verify-zone\fR reads a DNS zone file and verifies it.
|
||||
|
||||
RRSIG resource records are checked against the DNSKEY set at the zone apex.
|
||||
|
||||
Each name is checked for an NSEC(3), if appropriate.
|
||||
|
||||
If ZONEMD resource records are present, one of them needs to match the zone content.
|
||||
|
||||
.SH OPTIONS
|
||||
.TP
|
||||
\fB-h\fR
|
||||
Show usage and exit
|
||||
|
||||
.TP
|
||||
\fB-a\fR
|
||||
Apex only, check only the zone apex
|
||||
|
||||
.TP
|
||||
\fB-e\fR \fIperiod\fR
|
||||
Signatures may not expire within this period.
|
||||
Default no period is used.
|
||||
|
||||
.TP
|
||||
\fB-i\fR \fIperiod\fR
|
||||
Signatures must have been valid at least this long.
|
||||
Default signatures should just be valid now.
|
||||
|
||||
.TP
|
||||
\fB-k\fR \fIfile\fR
|
||||
A file that contains a trusted DNSKEY or DS rr.
|
||||
This option may be given more than once.
|
||||
|
||||
Alternatively, if \fB-k\fR is not specified, and a default trust anchor
|
||||
(@LDNS_TRUST_ANCHOR_FILE@) exists and contains a valid DNSKEY or DS record,
|
||||
it will be used as the trust anchor.
|
||||
.TP
|
||||
\fB-p\fR \fI[0-100]\fR
|
||||
Only check this percentage of the zone.
|
||||
Which names to check is determined randomly.
|
||||
Defaults to 100.
|
||||
|
||||
.TP
|
||||
\fB-S\fR
|
||||
Chase signature(s) to a known key.
|
||||
The network may be accessed to validate the zone's DNSKEYs. (implies \-k)
|
||||
|
||||
.TP
|
||||
\fB-t\fR \fIYYYYMMDDhhmmss | [+|-]offset\fR
|
||||
Set the validation time either by an absolute time value or as an offset in seconds from the current time.
|
||||
|
||||
.TP
|
||||
\fB-v\fR
|
||||
Show the version and exit
|
||||
|
||||
.TP
|
||||
\fB-V\fR \fInumber\fR
|
||||
Set the verbosity level (default 3):
|
||||
|
||||
0: Be silent
|
||||
1: Print result, and any errors
|
||||
2: Same as 1 for now
|
||||
3: Print result, any errors, and the names that are
|
||||
being checked
|
||||
4: Same as 3 for now
|
||||
5: Print the zone after it has been read, the result,
|
||||
any errors, and the names that are being checked
|
||||
|
||||
.TP
|
||||
\fB-Z\fR
|
||||
Requires a valid ZONEMD RR to be present. When given once, this option will
|
||||
permit verifying only the ZONEMD RR of an unsigned zone. When given more than
|
||||
once, the zone needs to be validly DNSSEC signed as well.
|
||||
|
||||
.TP
|
||||
\fB-ZZZ\fR
|
||||
When three times a \fB-Z\fR option is given, the ZONEMD RR to be verified is
|
||||
considered "detached" and does not need to have valid signatures.
|
||||
|
||||
.LP
|
||||
\fIperiod\fRs are given in ISO 8601 duration format:
|
||||
.RS
|
||||
P[n]Y[n]M[n]DT[n]H[n]M[n]S
|
||||
.RE
|
||||
.LP
|
||||
If no file is given standard input is read.
|
||||
|
||||
.SH "FILES"
|
||||
.TP
|
||||
@LDNS_TRUST_ANCHOR_FILE@
|
||||
The file from which trusted keys are loaded for signature chasing,
|
||||
when no \fB-k\fR option is given.
|
||||
|
||||
.SH "SEE ALSO"
|
||||
.LP
|
||||
unbound-anchor(8)
|
||||
|
||||
.SH AUTHOR
|
||||
Written by the ldns team as an example for ldns usage.
|
||||
|
||||
.SH REPORTING BUGS
|
||||
Report bugs to <dns-team@nlnetlabs.nl>.
|
||||
|
||||
.SH COPYRIGHT
|
||||
Copyright (C) 2008 NLnet Labs. This is free software. There is NO
|
||||
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR
|
||||
PURPOSE.
|
||||
977
zonemaster-ldns/ldns/examples/ldns-verify-zone.c
Normal file
977
zonemaster-ldns/ldns/examples/ldns-verify-zone.c
Normal file
@@ -0,0 +1,977 @@
|
||||
/*
|
||||
* read a zone file from disk and prints it, one RR per line
|
||||
*
|
||||
* (c) NLnetLabs 2008
|
||||
*
|
||||
* See the file LICENSE for the license
|
||||
*
|
||||
* Missing from the checks: empty non-terminals
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
#include <unistd.h>
|
||||
#include <stdlib.h>
|
||||
#include <sys/time.h>
|
||||
|
||||
#include <ldns/ldns.h>
|
||||
|
||||
#include <errno.h>
|
||||
|
||||
#ifdef HAVE_SSL
|
||||
#include <openssl/err.h>
|
||||
|
||||
static int verbosity = 3;
|
||||
static time_t check_time = 0;
|
||||
static int32_t inception_offset = 0;
|
||||
static int32_t expiration_offset = 0;
|
||||
static bool do_sigchase = false;
|
||||
static bool no_nomatch_msg = false;
|
||||
|
||||
static FILE* myout;
|
||||
static FILE* myerr;
|
||||
|
||||
static void
|
||||
update_error(ldns_status* result, ldns_status status)
|
||||
{
|
||||
if (status != LDNS_STATUS_OK) {
|
||||
if (*result == LDNS_STATUS_OK || *result == LDNS_STATUS_ERR ||
|
||||
( *result == LDNS_STATUS_CRYPTO_NO_MATCHING_KEYTAG_DNSKEY
|
||||
&& status != LDNS_STATUS_ERR
|
||||
)) {
|
||||
*result = status;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
print_type(FILE* stream, ldns_rr_type type)
|
||||
{
|
||||
const ldns_rr_descriptor *descriptor = ldns_rr_descript(type);
|
||||
|
||||
if (descriptor && descriptor->_name) {
|
||||
fprintf(stream, "%s", descriptor->_name);
|
||||
} else {
|
||||
fprintf(stream, "TYPE%u", type);
|
||||
}
|
||||
}
|
||||
|
||||
static ldns_status
|
||||
read_key_file(const char *filename, ldns_rr_list *keys)
|
||||
{
|
||||
ldns_status status = LDNS_STATUS_ERR;
|
||||
ldns_rr *rr;
|
||||
FILE *fp;
|
||||
uint32_t my_ttl = 0;
|
||||
ldns_rdf *my_origin = NULL;
|
||||
ldns_rdf *my_prev = NULL;
|
||||
int line_nr;
|
||||
|
||||
if (!(fp = fopen(filename, "r"))) {
|
||||
return LDNS_STATUS_FILE_ERR;
|
||||
}
|
||||
while (!feof(fp)) {
|
||||
status = ldns_rr_new_frm_fp_l(&rr, fp, &my_ttl, &my_origin,
|
||||
&my_prev, &line_nr);
|
||||
|
||||
if (status == LDNS_STATUS_OK) {
|
||||
|
||||
if ( ldns_rr_get_type(rr) == LDNS_RR_TYPE_DS
|
||||
|| ldns_rr_get_type(rr) == LDNS_RR_TYPE_DNSKEY)
|
||||
|
||||
ldns_rr_list_push_rr(keys, rr);
|
||||
|
||||
} else if ( status == LDNS_STATUS_SYNTAX_EMPTY
|
||||
|| status == LDNS_STATUS_SYNTAX_TTL
|
||||
|| status == LDNS_STATUS_SYNTAX_ORIGIN
|
||||
|| status == LDNS_STATUS_SYNTAX_INCLUDE)
|
||||
|
||||
status = LDNS_STATUS_OK;
|
||||
else
|
||||
break;
|
||||
}
|
||||
fclose(fp);
|
||||
return status;
|
||||
}
|
||||
|
||||
|
||||
|
||||
static void
|
||||
print_rr_error(FILE* stream, ldns_rr* rr, const char* msg)
|
||||
{
|
||||
if (verbosity > 0) {
|
||||
fprintf(stream, "Error: %s for ", msg);
|
||||
ldns_rdf_print(stream, ldns_rr_owner(rr));
|
||||
fprintf(stream, "\t");
|
||||
print_type(stream, ldns_rr_get_type(rr));
|
||||
fprintf(stream, "\n");
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
print_rr_status_error(FILE* stream, ldns_rr* rr, ldns_status status)
|
||||
{
|
||||
if (status != LDNS_STATUS_OK) {
|
||||
print_rr_error(stream, rr, ldns_get_errorstr_by_id(status));
|
||||
if (verbosity > 0 && status == LDNS_STATUS_SSL_ERR) {
|
||||
#if OPENSSL_VERSION_NUMBER < 0x10100000 || defined(HAVE_LIBRESSL)
|
||||
ERR_load_crypto_strings();
|
||||
#endif
|
||||
ERR_print_errors_fp(stream);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
print_rrs_status_error(FILE* stream, ldns_rr_list* rrs, ldns_status status,
|
||||
ldns_dnssec_rrs* cur_sig)
|
||||
{
|
||||
if (status != LDNS_STATUS_OK) {
|
||||
if (ldns_rr_list_rr_count(rrs) > 0) {
|
||||
print_rr_status_error(stream, ldns_rr_list_rr(rrs, 0),
|
||||
status);
|
||||
} else if (verbosity > 0) {
|
||||
fprintf(stream, "Error: %s for <unknown>\n",
|
||||
ldns_get_errorstr_by_id(status));
|
||||
}
|
||||
if (verbosity >= 4) {
|
||||
fprintf(stream, "RRSet:\n");
|
||||
ldns_rr_list_print(stream, rrs);
|
||||
fprintf(stream, "Signature:\n");
|
||||
ldns_rr_print(stream, cur_sig->rr);
|
||||
fprintf(stream, "\n");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static ldns_status
|
||||
rrsig_check_time_margins(ldns_rr* rrsig
|
||||
#if 0 /* Passing those as arguments becomes sensible when
|
||||
* rrsig_check_time_margins will be added to the library.
|
||||
*/
|
||||
,time_t check_time, int32_t inception_offset, int32_t expiration_offset
|
||||
#endif
|
||||
)
|
||||
{
|
||||
int32_t inception, expiration;
|
||||
|
||||
inception = ldns_rdf2native_int32(ldns_rr_rrsig_inception (rrsig));
|
||||
expiration = ldns_rdf2native_int32(ldns_rr_rrsig_expiration(rrsig));
|
||||
|
||||
if (((int32_t) (check_time - inception_offset)) - inception < 0) {
|
||||
return LDNS_STATUS_CRYPTO_SIG_NOT_INCEPTED_WITHIN_MARGIN;
|
||||
}
|
||||
if (expiration - ((int32_t) (check_time + expiration_offset)) < 0) {
|
||||
return LDNS_STATUS_CRYPTO_SIG_EXPIRED_WITHIN_MARGIN;
|
||||
}
|
||||
return LDNS_STATUS_OK;
|
||||
}
|
||||
|
||||
static ldns_status
|
||||
verify_rrs(ldns_rr_list* rrset_rrs, ldns_dnssec_rrs* cur_sig,
|
||||
ldns_rr_list* keys)
|
||||
{
|
||||
ldns_status status, result = LDNS_STATUS_OK;
|
||||
ldns_dnssec_rrs *cur_sig_bak = cur_sig;
|
||||
|
||||
/* A single valid signature validates the RRset */
|
||||
while (cur_sig) {
|
||||
if (ldns_verify_rrsig_keylist_time( rrset_rrs, cur_sig->rr
|
||||
, keys, check_time, NULL)
|
||||
|| rrsig_check_time_margins(cur_sig->rr))
|
||||
cur_sig = cur_sig->next;
|
||||
else
|
||||
return LDNS_STATUS_OK;
|
||||
}
|
||||
/* Without any valid signature, do print all errors. */
|
||||
for (cur_sig = cur_sig_bak; cur_sig; cur_sig = cur_sig->next) {
|
||||
status = ldns_verify_rrsig_keylist_time(rrset_rrs,
|
||||
cur_sig->rr, keys, check_time, NULL);
|
||||
status = status ? status
|
||||
: rrsig_check_time_margins(cur_sig->rr);
|
||||
if (!status)
|
||||
; /* pass */
|
||||
else if (!no_nomatch_msg || status !=
|
||||
LDNS_STATUS_CRYPTO_NO_MATCHING_KEYTAG_DNSKEY)
|
||||
print_rrs_status_error(
|
||||
myerr, rrset_rrs, status, cur_sig);
|
||||
update_error(&result, status);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
static ldns_status
|
||||
verify_dnssec_rrset(ldns_rdf *zone_name, ldns_rdf *name,
|
||||
ldns_dnssec_rrsets *rrset, ldns_rr_list *keys)
|
||||
{
|
||||
ldns_rr_list *rrset_rrs;
|
||||
ldns_dnssec_rrs *cur_rr, *cur_sig;
|
||||
ldns_status status;
|
||||
|
||||
if (!rrset->rrs) return LDNS_STATUS_OK;
|
||||
|
||||
rrset_rrs = ldns_rr_list_new();
|
||||
cur_rr = rrset->rrs;
|
||||
while(cur_rr && cur_rr->rr) {
|
||||
ldns_rr_list_push_rr(rrset_rrs, cur_rr->rr);
|
||||
cur_rr = cur_rr->next;
|
||||
}
|
||||
cur_sig = rrset->signatures;
|
||||
if (cur_sig) {
|
||||
status = verify_rrs(rrset_rrs, cur_sig, keys);
|
||||
|
||||
} else /* delegations may be unsigned (on opt out...) */
|
||||
if (rrset->type != LDNS_RR_TYPE_NS ||
|
||||
ldns_dname_compare(name, zone_name) == 0) {
|
||||
|
||||
print_rr_error(myerr, rrset->rrs->rr, "no signatures");
|
||||
status = LDNS_STATUS_CRYPTO_NO_RRSIG;
|
||||
} else {
|
||||
status = LDNS_STATUS_OK;
|
||||
}
|
||||
ldns_rr_list_free(rrset_rrs);
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
static ldns_status
|
||||
verify_single_rr(ldns_rr *rr, ldns_dnssec_rrs *signature_rrs,
|
||||
ldns_rr_list *keys)
|
||||
{
|
||||
ldns_rr_list *rrset_rrs;
|
||||
ldns_status status;
|
||||
|
||||
rrset_rrs = ldns_rr_list_new();
|
||||
ldns_rr_list_push_rr(rrset_rrs, rr);
|
||||
|
||||
status = verify_rrs(rrset_rrs, signature_rrs, keys);
|
||||
|
||||
ldns_rr_list_free(rrset_rrs);
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
static ldns_status
|
||||
verify_next_hashed_name(ldns_dnssec_zone* zone, ldns_dnssec_name *name)
|
||||
{
|
||||
ldns_rbnode_t *next_node;
|
||||
ldns_dnssec_name *next_name;
|
||||
int cmp;
|
||||
char *next_owner_str;
|
||||
ldns_rdf *next_owner_dname;
|
||||
|
||||
assert(name->hashed_name != NULL);
|
||||
|
||||
next_node = ldns_rbtree_search(zone->hashed_names, name->hashed_name);
|
||||
assert(next_node != NULL);
|
||||
do {
|
||||
next_node = ldns_rbtree_next(next_node);
|
||||
if (next_node == LDNS_RBTREE_NULL) {
|
||||
next_node = ldns_rbtree_first(zone->hashed_names);
|
||||
}
|
||||
next_name = (ldns_dnssec_name *) next_node->data;
|
||||
} while (! next_name->nsec);
|
||||
|
||||
next_owner_str = ldns_rdf2str(ldns_nsec3_next_owner(name->nsec));
|
||||
next_owner_dname = ldns_dname_new_frm_str(next_owner_str);
|
||||
cmp = ldns_dname_compare(next_owner_dname, next_name->hashed_name);
|
||||
ldns_rdf_deep_free(next_owner_dname);
|
||||
LDNS_FREE(next_owner_str);
|
||||
if (cmp != 0) {
|
||||
if (verbosity > 0) {
|
||||
fprintf(myerr, "Error: The NSEC3 record for ");
|
||||
ldns_rdf_print(stdout, name->name);
|
||||
fprintf(myerr, " points to the wrong next hashed owner"
|
||||
" name\n\tshould point to ");
|
||||
ldns_rdf_print(myerr, next_name->name);
|
||||
fprintf(myerr, ", whose hashed name is ");
|
||||
ldns_rdf_print(myerr, next_name->hashed_name);
|
||||
fprintf(myerr, "\n");
|
||||
}
|
||||
return LDNS_STATUS_ERR;
|
||||
} else {
|
||||
return LDNS_STATUS_OK;
|
||||
}
|
||||
}
|
||||
|
||||
static bool zone_is_nsec3_optout(ldns_dnssec_zone* zone)
|
||||
{
|
||||
static int remember = -1;
|
||||
|
||||
if (remember == -1) {
|
||||
remember = ldns_dnssec_zone_is_nsec3_optout(zone) ? 1 : 0;
|
||||
}
|
||||
return remember == 1;
|
||||
}
|
||||
|
||||
static ldns_status
|
||||
verify_nsec(ldns_dnssec_zone* zone, ldns_rbnode_t *cur_node,
|
||||
ldns_rr_list *keys)
|
||||
{
|
||||
ldns_rbnode_t *next_node;
|
||||
ldns_dnssec_name *name, *next_name;
|
||||
ldns_status status, result;
|
||||
result = LDNS_STATUS_OK;
|
||||
|
||||
name = (ldns_dnssec_name *) cur_node->data;
|
||||
if (name->nsec) {
|
||||
if (name->nsec_signatures) {
|
||||
status = verify_single_rr(name->nsec,
|
||||
name->nsec_signatures, keys);
|
||||
|
||||
update_error(&result, status);
|
||||
} else {
|
||||
if (verbosity > 0) {
|
||||
fprintf(myerr,
|
||||
"Error: the NSEC(3) record of ");
|
||||
ldns_rdf_print(myerr, name->name);
|
||||
fprintf(myerr, " has no signatures\n");
|
||||
}
|
||||
update_error(&result, LDNS_STATUS_ERR);
|
||||
}
|
||||
/* check whether the NSEC record points to the right name */
|
||||
switch (ldns_rr_get_type(name->nsec)) {
|
||||
case LDNS_RR_TYPE_NSEC:
|
||||
/* simply try next name */
|
||||
next_node = ldns_rbtree_next(cur_node);
|
||||
if (next_node == LDNS_RBTREE_NULL) {
|
||||
next_node = ldns_rbtree_first(
|
||||
zone->names);
|
||||
}
|
||||
next_node = ldns_dnssec_name_node_next_nonglue(
|
||||
next_node);
|
||||
if (!next_node) {
|
||||
next_node =
|
||||
ldns_dnssec_name_node_next_nonglue(
|
||||
ldns_rbtree_first(zone->names));
|
||||
}
|
||||
next_name = (ldns_dnssec_name*)next_node->data;
|
||||
if (ldns_dname_compare(next_name->name,
|
||||
ldns_rr_rdf(name->nsec,
|
||||
0)) != 0) {
|
||||
if (verbosity > 0) {
|
||||
fprintf(myerr, "Error: the "
|
||||
"NSEC record for ");
|
||||
ldns_rdf_print(myerr,
|
||||
name->name);
|
||||
fprintf(myerr, " points to "
|
||||
"the wrong "
|
||||
"next owner name\n");
|
||||
}
|
||||
if (verbosity >= 4) {
|
||||
fprintf(myerr, "\t: ");
|
||||
ldns_rdf_print(myerr,
|
||||
ldns_rr_rdf(
|
||||
name->nsec,
|
||||
0));
|
||||
fprintf(myerr, " i.s.o. ");
|
||||
ldns_rdf_print(myerr,
|
||||
next_name->name);
|
||||
fprintf(myerr, ".\n");
|
||||
}
|
||||
update_error(&result,
|
||||
LDNS_STATUS_ERR);
|
||||
}
|
||||
break;
|
||||
case LDNS_RR_TYPE_NSEC3:
|
||||
/* find the hashed next name in the tree */
|
||||
/* this is expensive, do we need to add
|
||||
* support for this in the structs?
|
||||
* (ie. pointer to next hashed name?)
|
||||
*/
|
||||
status = verify_next_hashed_name(zone, name);
|
||||
update_error(&result, status);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
if (zone_is_nsec3_optout(zone) &&
|
||||
(ldns_dnssec_name_is_glue(name) ||
|
||||
( ldns_dnssec_rrsets_contains_type(name->rrsets,
|
||||
LDNS_RR_TYPE_NS)
|
||||
&& !ldns_dnssec_rrsets_contains_type(name->rrsets,
|
||||
LDNS_RR_TYPE_DS)))) {
|
||||
/* ok, no problem, but we need to remember to check
|
||||
* whether the chain does not actually point to this
|
||||
* name later */
|
||||
} else {
|
||||
if (verbosity > 0) {
|
||||
fprintf(myerr,
|
||||
"Error: there is no NSEC(3) for ");
|
||||
ldns_rdf_print(myerr, name->name);
|
||||
fprintf(myerr, "\n");
|
||||
}
|
||||
update_error(&result, LDNS_STATUS_ERR);
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
static ldns_status
|
||||
verify_dnssec_name(ldns_rdf *zone_name, ldns_dnssec_zone* zone,
|
||||
ldns_rbnode_t *cur_node, ldns_rr_list *keys,
|
||||
bool detached_zonemd)
|
||||
{
|
||||
ldns_status result = LDNS_STATUS_OK;
|
||||
ldns_status status;
|
||||
ldns_dnssec_rrsets *cur_rrset;
|
||||
ldns_dnssec_name *name;
|
||||
int on_delegation_point;
|
||||
/* for NSEC chain checks */
|
||||
|
||||
name = (ldns_dnssec_name *) cur_node->data;
|
||||
if (verbosity >= 5) {
|
||||
fprintf(myout, "Checking: ");
|
||||
ldns_rdf_print(myout, name->name);
|
||||
fprintf(myout, "\n");
|
||||
}
|
||||
|
||||
if (ldns_dnssec_name_is_glue(name)) {
|
||||
/* glue */
|
||||
cur_rrset = name->rrsets;
|
||||
while (cur_rrset) {
|
||||
if (cur_rrset->signatures) {
|
||||
if (verbosity > 0) {
|
||||
fprintf(myerr, "Error: ");
|
||||
ldns_rdf_print(myerr, name->name);
|
||||
fprintf(myerr, "\t");
|
||||
print_type(myerr, cur_rrset->type);
|
||||
fprintf(myerr, " has signature(s),"
|
||||
" but is occluded"
|
||||
" (or glue)\n");
|
||||
}
|
||||
result = LDNS_STATUS_ERR;
|
||||
}
|
||||
cur_rrset = cur_rrset->next;
|
||||
}
|
||||
if (name->nsec) {
|
||||
if (verbosity > 0) {
|
||||
fprintf(myerr, "Error: ");
|
||||
ldns_rdf_print(myerr, name->name);
|
||||
fprintf(myerr, " has an NSEC(3),"
|
||||
" but is occluded"
|
||||
" (or glue)\n");
|
||||
}
|
||||
result = LDNS_STATUS_ERR;
|
||||
}
|
||||
} else {
|
||||
/* not glue, do real verify */
|
||||
|
||||
on_delegation_point =
|
||||
ldns_dnssec_rrsets_contains_type(name->rrsets,
|
||||
LDNS_RR_TYPE_NS)
|
||||
&& !ldns_dnssec_rrsets_contains_type(name->rrsets,
|
||||
LDNS_RR_TYPE_SOA);
|
||||
cur_rrset = name->rrsets;
|
||||
while(cur_rrset) {
|
||||
|
||||
/* Do not check occluded rrsets
|
||||
* on the delegation point
|
||||
*/
|
||||
if ((on_delegation_point &&
|
||||
(cur_rrset->type == LDNS_RR_TYPE_NS ||
|
||||
cur_rrset->type == LDNS_RR_TYPE_DS)) ||
|
||||
(!on_delegation_point &&
|
||||
cur_rrset->type != LDNS_RR_TYPE_RRSIG &&
|
||||
cur_rrset->type != LDNS_RR_TYPE_NSEC &&
|
||||
|
||||
( cur_rrset->type != LDNS_RR_TYPE_ZONEMD
|
||||
|| !detached_zonemd || cur_rrset->signatures))) {
|
||||
|
||||
status = verify_dnssec_rrset(zone_name,
|
||||
name->name, cur_rrset, keys);
|
||||
update_error(&result, status);
|
||||
}
|
||||
cur_rrset = cur_rrset->next;
|
||||
}
|
||||
status = verify_nsec(zone, cur_node, keys);
|
||||
update_error(&result, status);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
static void
|
||||
add_keys_with_matching_ds(ldns_dnssec_rrsets* from_keys, ldns_rr_list *dss,
|
||||
ldns_rr_list *to_keys)
|
||||
{
|
||||
size_t i;
|
||||
ldns_rr* ds_rr;
|
||||
ldns_dnssec_rrs *cur_key;
|
||||
|
||||
for (i = 0; i < ldns_rr_list_rr_count(dss); i++) {
|
||||
|
||||
if (ldns_rr_get_type(ds_rr = ldns_rr_list_rr(dss, i))
|
||||
== LDNS_RR_TYPE_DS) {
|
||||
|
||||
for (cur_key = from_keys->rrs; cur_key;
|
||||
cur_key = cur_key->next ) {
|
||||
|
||||
if (ldns_rr_compare_ds(cur_key->rr, ds_rr)) {
|
||||
ldns_rr_list_push_rr(to_keys,
|
||||
cur_key->rr);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static ldns_resolver *p_ldns_new_res(ldns_resolver** new_res, ldns_status *s)
|
||||
{
|
||||
assert(new_res && s);
|
||||
if (!(*s = ldns_resolver_new_frm_file(new_res, NULL))) {
|
||||
ldns_resolver_set_dnssec(*new_res, 1);
|
||||
ldns_resolver_set_dnssec_cd(*new_res, 1);
|
||||
return *new_res;
|
||||
}
|
||||
ldns_resolver_free(*new_res);
|
||||
return (*new_res = NULL);
|
||||
}
|
||||
|
||||
static ldns_status
|
||||
sigchase(ldns_resolver* res, ldns_rdf *zone_name, ldns_dnssec_rrsets *zonekeys,
|
||||
ldns_rr_list *keys)
|
||||
{
|
||||
ldns_dnssec_rrs* cur_key;
|
||||
ldns_status status;
|
||||
ldns_resolver* new_res = NULL;
|
||||
ldns_rdf* parent_name = NULL;
|
||||
ldns_rr_list* parent_keys = NULL;
|
||||
ldns_rr_list* ds_keys = NULL;
|
||||
|
||||
add_keys_with_matching_ds(zonekeys, keys, keys);
|
||||
|
||||
/* First try to authenticate the keys offline.
|
||||
* When do_sigchase is given validation may continue lookup up
|
||||
* keys online. Reporting the failure of the offline validation
|
||||
* should then be suppressed.
|
||||
*/
|
||||
no_nomatch_msg = do_sigchase;
|
||||
status = verify_dnssec_rrset(zone_name, zone_name, zonekeys, keys);
|
||||
no_nomatch_msg = false;
|
||||
|
||||
/* Continue online on validation failure when the -S option was given.
|
||||
*/
|
||||
if ( !do_sigchase
|
||||
|| status != LDNS_STATUS_CRYPTO_NO_MATCHING_KEYTAG_DNSKEY
|
||||
|| ldns_dname_label_count(zone_name) == 0 ) {
|
||||
if (verbosity > 0) {
|
||||
fprintf(myerr, "Cannot chase the root: %s\n"
|
||||
, ldns_get_errorstr_by_id(status));
|
||||
}
|
||||
|
||||
} else if (!res && !(res = p_ldns_new_res(&new_res, &status))) {
|
||||
if (verbosity > 0) {
|
||||
fprintf(myerr, "Could not create resolver: %s\n"
|
||||
, ldns_get_errorstr_by_id(status));
|
||||
}
|
||||
} else if (!(parent_name = ldns_dname_left_chop(zone_name))) {
|
||||
status = LDNS_STATUS_MEM_ERR;
|
||||
|
||||
/*
|
||||
* Use the (authenticated) keys of the parent zone ...
|
||||
*/
|
||||
} else if (!(parent_keys = ldns_fetch_valid_domain_keys(res,
|
||||
parent_name, keys, &status))) {
|
||||
if (verbosity > 0) {
|
||||
fprintf(myerr,
|
||||
"Could not get valid DNSKEY RRset to "
|
||||
"validate domain's DS: %s\n",
|
||||
ldns_get_errorstr_by_id(status)
|
||||
);
|
||||
}
|
||||
/*
|
||||
* ... to validate the DS for the zone ...
|
||||
*/
|
||||
} else if (!(ds_keys = ldns_validate_domain_ds(res, zone_name,
|
||||
parent_keys))) {
|
||||
status = LDNS_STATUS_CRYPTO_NO_TRUSTED_DS;
|
||||
if (verbosity > 0) {
|
||||
fprintf(myerr,
|
||||
"Could not get valid DS RRset for domain: %s\n",
|
||||
ldns_get_errorstr_by_id(status)
|
||||
);
|
||||
}
|
||||
} else {
|
||||
/*
|
||||
* ... to use it to add the KSK to the trusted keys ...
|
||||
*/
|
||||
add_keys_with_matching_ds(zonekeys, ds_keys, keys);
|
||||
|
||||
/*
|
||||
* ... to validate all zonekeys ...
|
||||
*/
|
||||
status = verify_dnssec_rrset(zone_name, zone_name,
|
||||
zonekeys, keys);
|
||||
}
|
||||
/*
|
||||
* ... so they can all be added to our list of trusted keys.
|
||||
*/
|
||||
ldns_resolver_deep_free(new_res);
|
||||
ldns_rdf_deep_free(parent_name);
|
||||
ldns_rr_list_free(parent_keys);
|
||||
ldns_rr_list_free(ds_keys);
|
||||
|
||||
if (status == LDNS_STATUS_OK)
|
||||
for (cur_key = zonekeys->rrs; cur_key; cur_key = cur_key->next)
|
||||
ldns_rr_list_push_rr(keys, cur_key->rr);
|
||||
return status;
|
||||
}
|
||||
|
||||
static ldns_status
|
||||
verify_dnssec_zone(ldns_dnssec_zone *dnssec_zone, ldns_rdf *zone_name,
|
||||
ldns_rr_list *keys, bool apexonly, int percentage,
|
||||
bool detached_zonemd)
|
||||
{
|
||||
ldns_rbnode_t *cur_node;
|
||||
ldns_dnssec_rrsets *cur_key_rrset;
|
||||
ldns_dnssec_rrs *cur_key;
|
||||
ldns_status status;
|
||||
ldns_status result = LDNS_STATUS_OK;
|
||||
|
||||
cur_key_rrset = ldns_dnssec_zone_find_rrset(dnssec_zone, zone_name,
|
||||
LDNS_RR_TYPE_DNSKEY);
|
||||
if (!cur_key_rrset || !cur_key_rrset->rrs) {
|
||||
if (verbosity > 0) {
|
||||
fprintf(myerr,
|
||||
"Error: No DNSKEY records at zone apex\n");
|
||||
}
|
||||
result = LDNS_STATUS_ERR;
|
||||
} else {
|
||||
/* are keys given with -k to use for validation? */
|
||||
if (ldns_rr_list_rr_count(keys) > 0) {
|
||||
if ((result = sigchase(NULL, zone_name, cur_key_rrset,
|
||||
keys)))
|
||||
goto error;
|
||||
} else
|
||||
for (cur_key = cur_key_rrset->rrs; cur_key;
|
||||
cur_key = cur_key->next)
|
||||
ldns_rr_list_push_rr(keys, cur_key->rr);
|
||||
|
||||
cur_node = ldns_rbtree_first(dnssec_zone->names);
|
||||
if (cur_node == LDNS_RBTREE_NULL) {
|
||||
if (verbosity > 0) {
|
||||
fprintf(myerr, "Error: Empty zone?\n");
|
||||
}
|
||||
result = LDNS_STATUS_ERR;
|
||||
}
|
||||
if (apexonly) {
|
||||
/*
|
||||
* In this case, only the first node in the treewalk
|
||||
* below should be checked.
|
||||
*/
|
||||
assert( cur_node->data == dnssec_zone->soa );
|
||||
/*
|
||||
* Although the percentage option doesn't make sense
|
||||
* here, we set it to 100 to force the first node to
|
||||
* be checked.
|
||||
*/
|
||||
percentage = 100;
|
||||
}
|
||||
while (cur_node != LDNS_RBTREE_NULL) {
|
||||
/* should we check this one? saves calls to random. */
|
||||
if (percentage == 100
|
||||
|| ((random() % 100) >= 100 - percentage)) {
|
||||
status = verify_dnssec_name(zone_name,
|
||||
dnssec_zone, cur_node, keys,
|
||||
detached_zonemd);
|
||||
update_error(&result, status);
|
||||
if (apexonly)
|
||||
break;
|
||||
}
|
||||
cur_node = ldns_rbtree_next(cur_node);
|
||||
}
|
||||
}
|
||||
error:
|
||||
ldns_rr_list_free(keys);
|
||||
return result;
|
||||
}
|
||||
|
||||
static void print_usage(FILE *out, const char *progname)
|
||||
{
|
||||
fprintf(out, "Usage: %s [OPTIONS] <zonefile>\n", progname);
|
||||
fprintf(out, "\tReads the zonefile and checks for DNSSEC errors.\n");
|
||||
fprintf(out, "\nIt checks whether NSEC(3)s are present, "
|
||||
"and verifies all signatures\n");
|
||||
fprintf(out, "It also checks the NSEC(3) chain, but it "
|
||||
"will error on opted-out delegations\n");
|
||||
fprintf(out, "It also checks whether ZONEMDs are present, and if so, "
|
||||
"needs one of them to match the zone's data.\n");
|
||||
fprintf(out, "\nOPTIONS:\n");
|
||||
fprintf(out, "\t-h\t\tshow this text\n");
|
||||
fprintf(out, "\t-a\t\tapex only, check only the zone apex\n");
|
||||
fprintf(out, "\t-e <period>\tsignatures may not expire "
|
||||
"within this period.\n\t\t\t"
|
||||
"(default no period is used)\n");
|
||||
fprintf(out, "\t-i <period>\tsignatures must have been "
|
||||
"valid at least this long.\n\t\t\t"
|
||||
"(default signatures should just be valid now)\n");
|
||||
fprintf(out, "\t-k <file>\tspecify a file that contains a "
|
||||
"trusted DNSKEY or DS rr.\n\t\t\t"
|
||||
"This option may be given more than once.\n"
|
||||
"\t\t\tDefault is %s\n", LDNS_TRUST_ANCHOR_FILE);
|
||||
fprintf(out, "\t-p [0-100]\tonly checks this percentage of "
|
||||
"the zone.\n\t\t\tDefaults to 100\n");
|
||||
fprintf(out, "\t-S\t\tchase signature(s) to a known key. "
|
||||
"The network may be\n\t\t\taccessed to "
|
||||
"validate the zone's DNSKEYs. (implies -k)\n");
|
||||
fprintf(out, "\t-t YYYYMMDDhhmmss | [+|-]offset\n\t\t\t"
|
||||
"set the validation time either by an "
|
||||
"absolute time\n\t\t\tvalue or as an "
|
||||
"offset in seconds from <now>.\n\t\t\t"
|
||||
"For data that came from the network (while "
|
||||
"chasing),\n\t\t\tsystem time will be used "
|
||||
"for validating it regardless.\n");
|
||||
fprintf(out, "\t-v\t\tshows the version and exits\n");
|
||||
fprintf(out, "\t-V [0-5]\tset verbosity level (default 3)\n");
|
||||
fprintf(out, "\t-Z\t\tRequires a valid ZONEMD RR to be present.\n");
|
||||
fprintf(out, "\t\t\tWhen given once, this option will permit verifying"
|
||||
"\n\t\t\tjust the ZONEMD RR of an unsigned zone. When given "
|
||||
"\n\t\t\tmore than once, the zone needs to be validly DNSSEC"
|
||||
"\n\t\t\tsigned as well. With three times a -Z option (-ZZZ)"
|
||||
"\n\t\t\ta ZONEMD RR without signatures is allowed.");
|
||||
fprintf(out, "\n<period>s are given in ISO 8601 duration format: "
|
||||
"P[n]Y[n]M[n]DT[n]H[n]M[n]S\n");
|
||||
fprintf(out, "\nif no file is given standard input is read\n");
|
||||
}
|
||||
|
||||
int
|
||||
main(int argc, char **argv)
|
||||
{
|
||||
char *filename;
|
||||
FILE *fp;
|
||||
int line_nr = 0;
|
||||
int c;
|
||||
ldns_status s;
|
||||
ldns_dnssec_zone *dnssec_zone = NULL;
|
||||
ldns_status result = LDNS_STATUS_ERR;
|
||||
bool apexonly = false;
|
||||
int percentage = 100;
|
||||
struct tm tm;
|
||||
ldns_duration_type *duration;
|
||||
ldns_rr_list *keys = ldns_rr_list_new();
|
||||
size_t nkeys = 0;
|
||||
const char *progname = argv[0];
|
||||
int zonemd_required = 0;
|
||||
ldns_dnssec_rrsets *zonemd_rrset;
|
||||
|
||||
check_time = ldns_time(NULL);
|
||||
myout = stdout;
|
||||
myerr = stderr;
|
||||
|
||||
while ((c = getopt(argc, argv, "ae:hi:k:vV:p:St:Z")) != -1) {
|
||||
switch(c) {
|
||||
case 'a':
|
||||
apexonly = true;
|
||||
break;
|
||||
case 'h':
|
||||
print_usage(stdout, progname);
|
||||
exit(EXIT_SUCCESS);
|
||||
break;
|
||||
case 'e':
|
||||
case 'i':
|
||||
duration = ldns_duration_create_from_string(optarg);
|
||||
if (!duration) {
|
||||
if (verbosity > 0) {
|
||||
fprintf(myerr,
|
||||
"<period> should be in ISO "
|
||||
"8601 duration format: "
|
||||
"P[n]Y[n]M[n]DT[n]H[n]M[n]S\n"
|
||||
);
|
||||
}
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
if (c == 'e')
|
||||
expiration_offset =
|
||||
ldns_duration2time(duration);
|
||||
else
|
||||
inception_offset =
|
||||
ldns_duration2time(duration);
|
||||
break;
|
||||
case 'k':
|
||||
s = read_key_file(optarg, keys);
|
||||
if (s == LDNS_STATUS_FILE_ERR) {
|
||||
if (verbosity > 0) {
|
||||
fprintf(myerr,
|
||||
"Error opening %s: %s\n",
|
||||
optarg, strerror(errno));
|
||||
}
|
||||
}
|
||||
if (s != LDNS_STATUS_OK) {
|
||||
if (verbosity > 0) {
|
||||
fprintf(myerr,
|
||||
"Could not parse key file "
|
||||
"%s: %s\n",optarg,
|
||||
ldns_get_errorstr_by_id(s));
|
||||
}
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
if (ldns_rr_list_rr_count(keys) == nkeys) {
|
||||
if (verbosity > 0) {
|
||||
fprintf(myerr,
|
||||
"No keys found in file %s\n",
|
||||
optarg);
|
||||
}
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
nkeys = ldns_rr_list_rr_count(keys);
|
||||
break;
|
||||
case 'p':
|
||||
percentage = atoi(optarg);
|
||||
if (percentage < 0 || percentage > 100) {
|
||||
if (verbosity > 0) {
|
||||
fprintf(myerr,
|
||||
"percentage needs to fall "
|
||||
"between 0..100\n");
|
||||
}
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
srandom(time(NULL) ^ getpid());
|
||||
break;
|
||||
case 'S':
|
||||
do_sigchase = true;
|
||||
/* may chase */
|
||||
break;
|
||||
case 't':
|
||||
if (strlen(optarg) == 14 &&
|
||||
sscanf(optarg, "%4d%2d%2d%2d%2d%2d",
|
||||
&tm.tm_year, &tm.tm_mon,
|
||||
&tm.tm_mday, &tm.tm_hour,
|
||||
&tm.tm_min , &tm.tm_sec ) == 6) {
|
||||
|
||||
tm.tm_year -= 1900;
|
||||
tm.tm_mon--;
|
||||
check_time = ldns_mktime_from_utc(&tm);
|
||||
}
|
||||
else {
|
||||
check_time += atoi(optarg);
|
||||
}
|
||||
break;
|
||||
case 'v':
|
||||
printf("verify-zone version %s (ldns version %s)\n",
|
||||
LDNS_VERSION, ldns_version());
|
||||
exit(EXIT_SUCCESS);
|
||||
break;
|
||||
case 'V':
|
||||
verbosity = atoi(optarg);
|
||||
break;
|
||||
case 'Z':
|
||||
zonemd_required += 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (do_sigchase && nkeys == 0) {
|
||||
(void) read_key_file(LDNS_TRUST_ANCHOR_FILE, keys);
|
||||
nkeys = ldns_rr_list_rr_count(keys);
|
||||
|
||||
if (nkeys == 0) {
|
||||
if (verbosity > 0) {
|
||||
fprintf(myerr, "Unable to chase "
|
||||
"signature without keys.\n");
|
||||
}
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
}
|
||||
|
||||
argc -= optind;
|
||||
argv += optind;
|
||||
|
||||
if (argc == 0) {
|
||||
fp = stdin;
|
||||
} else if (argc == 1) {
|
||||
filename = argv[0];
|
||||
|
||||
fp = fopen(filename, "r");
|
||||
if (!fp) {
|
||||
if (verbosity > 0) {
|
||||
fprintf(myerr, "Unable to open %s: %s\n",
|
||||
filename, strerror(errno));
|
||||
}
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
} else {
|
||||
print_usage(stderr, progname);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
s = ldns_dnssec_zone_new_frm_fp_l(&dnssec_zone, fp, NULL, 0,
|
||||
LDNS_RR_CLASS_IN, &line_nr);
|
||||
if (s != LDNS_STATUS_OK) {
|
||||
if (verbosity > 0) {
|
||||
fprintf(myerr, "%s at line %d\n",
|
||||
ldns_get_errorstr_by_id(s), line_nr);
|
||||
}
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
if (!dnssec_zone->soa) {
|
||||
if (verbosity > 0) {
|
||||
fprintf(myerr,
|
||||
"; Error: no SOA in the zone\n");
|
||||
}
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
result = ldns_dnssec_zone_mark_glue(dnssec_zone);
|
||||
if (result != LDNS_STATUS_OK) {
|
||||
if (verbosity > 0) {
|
||||
fprintf(myerr,
|
||||
"There were errors identifying the "
|
||||
"glue in the zone\n");
|
||||
}
|
||||
}
|
||||
if (verbosity >= 5) {
|
||||
ldns_dnssec_zone_print(myout, dnssec_zone);
|
||||
}
|
||||
zonemd_rrset = ldns_dnssec_zone_find_rrset(dnssec_zone,
|
||||
dnssec_zone->soa->name, LDNS_RR_TYPE_ZONEMD);
|
||||
|
||||
if (zonemd_required == 1
|
||||
&& !ldns_dnssec_zone_find_rrset(dnssec_zone,
|
||||
dnssec_zone->soa->name, LDNS_RR_TYPE_DNSKEY))
|
||||
result = LDNS_STATUS_OK;
|
||||
else
|
||||
result = verify_dnssec_zone(dnssec_zone,
|
||||
dnssec_zone->soa->name, keys, apexonly,
|
||||
percentage, zonemd_required > 2);
|
||||
|
||||
if (zonemd_rrset) {
|
||||
ldns_status zonemd_result
|
||||
= ldns_dnssec_zone_verify_zonemd(dnssec_zone);
|
||||
|
||||
if (zonemd_result)
|
||||
fprintf( myerr, "Could not validate zone digest: %s\n"
|
||||
, ldns_get_errorstr_by_id(zonemd_result));
|
||||
|
||||
else if (verbosity > 3)
|
||||
fprintf( myout
|
||||
, "Zone digest matched the zone content\n");
|
||||
|
||||
if (zonemd_result)
|
||||
result = zonemd_result;
|
||||
|
||||
} else if (zonemd_required)
|
||||
result = LDNS_STATUS_NO_ZONEMD;
|
||||
|
||||
if (result == LDNS_STATUS_OK) {
|
||||
if (verbosity >= 3) {
|
||||
fprintf(myout, "Zone is verified and complete\n");
|
||||
}
|
||||
} else if (verbosity > 0)
|
||||
fprintf(myerr, "There were errors in the zone\n");
|
||||
|
||||
ldns_dnssec_zone_deep_free(dnssec_zone);
|
||||
fclose(fp);
|
||||
exit(result);
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
int
|
||||
main(int argc, char **argv)
|
||||
{
|
||||
fprintf(stderr, "ldns-verify-zone needs OpenSSL support, "
|
||||
"which has not been compiled in\n");
|
||||
return 1;
|
||||
}
|
||||
#endif /* HAVE_SSL */
|
||||
|
||||
22
zonemaster-ldns/ldns/examples/ldns-version.1
Normal file
22
zonemaster-ldns/ldns/examples/ldns-version.1
Normal file
@@ -0,0 +1,22 @@
|
||||
.TH ldns-version 1 "27 Apr 2005"
|
||||
.SH NAME
|
||||
ldns-version \- print out the version of the ldns-library and tools on this system
|
||||
.SH SYNOPSIS
|
||||
.B ldns-version
|
||||
|
||||
.SH DESCRIPTION
|
||||
\fBldns-version\fR is used to print out version information of the ldns library and tools
|
||||
|
||||
.SH OPTIONS
|
||||
\fBldns-version\fR has no options.
|
||||
|
||||
.SH AUTHOR
|
||||
Written by the ldns team as an example for ldns usage.
|
||||
|
||||
.SH REPORTING BUGS
|
||||
Report bugs to <dns-team@nlnetlabs.nl>.
|
||||
|
||||
.SH COPYRIGHT
|
||||
Copyright (C) 2005 NLnet Labs. This is free software. There is NO
|
||||
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR
|
||||
PURPOSE.
|
||||
16
zonemaster-ldns/ldns/examples/ldns-version.c
Normal file
16
zonemaster-ldns/ldns/examples/ldns-version.c
Normal file
@@ -0,0 +1,16 @@
|
||||
/*
|
||||
* ldns-version shows ldns's version
|
||||
*
|
||||
* (c) NLnet Labs, 2005 - 2008
|
||||
* See the file LICENSE for the license
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
#include <ldns/ldns.h>
|
||||
|
||||
int
|
||||
main(void)
|
||||
{
|
||||
printf("%s\n", ldns_version());
|
||||
return 0;
|
||||
}
|
||||
61
zonemaster-ldns/ldns/examples/ldns-walk.1
Normal file
61
zonemaster-ldns/ldns/examples/ldns-walk.1
Normal file
@@ -0,0 +1,61 @@
|
||||
.TH ldns-walk 1 "21 Nov 2005"
|
||||
.SH NAME
|
||||
ldns-walk \- Retrieve the contents of a DNSSEC signed zone
|
||||
.SH SYNOPSIS
|
||||
.B ldns-walk
|
||||
[
|
||||
.IR OPTION
|
||||
]
|
||||
.IR ZONE
|
||||
|
||||
.SH DESCRIPTION
|
||||
|
||||
\fBldns-walk\fR is used to retrieve the contents of a DNSSEC signed zone.
|
||||
It does this through NSEC-walking (following the chain of NSEC records)
|
||||
and 'guessing' the next non-existent owner name for each NSEC.
|
||||
|
||||
Note that it might get stuck on some wildcard records when used through a
|
||||
caching forwarder. This problem can be circumvented by querying the
|
||||
authoritative nameserver directly (with the @ argument).
|
||||
|
||||
Of course the nameserver that is used must be DNSSEC-aware.
|
||||
|
||||
.SH OPTIONS
|
||||
.TP
|
||||
\fB-4\fR
|
||||
Use only IPv4.
|
||||
|
||||
.TP
|
||||
\fB-6\fR
|
||||
Use only IPv6.
|
||||
|
||||
.TP
|
||||
\fB-f\fR
|
||||
Do a 'full' zone walk; by default, ldns-walk will only show the names, and types present at those names. If this option is given, all resource records will be printed.
|
||||
|
||||
.TP
|
||||
\fB-s\fR \fIname\fR
|
||||
Start the walk with this owner name. Useful when continuing the walk for a
|
||||
large zone.
|
||||
|
||||
.TP
|
||||
\fB-v\fR \fIverbosity\fR
|
||||
Verbosity level [1-5].
|
||||
|
||||
.TP
|
||||
\fB@\fR \fInameserver\fR
|
||||
Send the queries to this nameserver.
|
||||
|
||||
.SH BUGS
|
||||
The full zone walk function is not complete yet, it does not correctly print delegation records
|
||||
|
||||
.SH AUTHOR
|
||||
Written by Jelte Jansen as an example for ldns usage.
|
||||
|
||||
.SH REPORTING BUGS
|
||||
Report bugs to <dns-team@nlnetlabs.nl>.
|
||||
|
||||
.SH COPYRIGHT
|
||||
Copyright (C) 2005 NLnet Labs. This is free software. There is NO
|
||||
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR
|
||||
PURPOSE.
|
||||
667
zonemaster-ldns/ldns/examples/ldns-walk.c
Normal file
667
zonemaster-ldns/ldns/examples/ldns-walk.c
Normal file
@@ -0,0 +1,667 @@
|
||||
/*
|
||||
* ldns-walk uses educated guesses and NSEC data to retrieve the
|
||||
* contents of a dnssec signed zone
|
||||
*
|
||||
* (c) NLnet Labs, 2005 - 2008
|
||||
* See the file LICENSE for the license
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include <ldns/ldns.h>
|
||||
|
||||
int verbosity = 0;
|
||||
|
||||
static int
|
||||
usage(FILE *fp, char *prog) {
|
||||
fprintf(fp, "%s [options] domain\n", prog);
|
||||
fprintf(fp, " print out the owner names for domain and the record types for those names\n");
|
||||
fprintf(fp, "OPTIONS:\n");
|
||||
fprintf(fp, "-4\t\tonly use IPv4\n");
|
||||
fprintf(fp, "-6\t\tonly use IPv6\n");
|
||||
fprintf(fp, "-f\t\tfull; get all rrsets instead of only a list of names and types\n");
|
||||
fprintf(fp, "-s <name>\t\tStart from this name\n");
|
||||
fprintf(fp, "-v <verbosity>\t\tVerbosity level [1-5]\n");
|
||||
fprintf(fp, "-version\tShow version and exit\n");
|
||||
fprintf(fp, "@<nameserver>\t\tUse this nameserver\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
static ldns_rdf *
|
||||
create_dname_plus_1(ldns_rdf *dname)
|
||||
{
|
||||
uint8_t *wire;
|
||||
ldns_rdf *newdname;
|
||||
uint8_t labellen;
|
||||
size_t pos;
|
||||
ldns_status status;
|
||||
size_t i;
|
||||
|
||||
ldns_dname2canonical(dname);
|
||||
if (verbosity >= 3) {
|
||||
printf("Create +e for ");
|
||||
ldns_rdf_print(stdout, dname);
|
||||
printf("\n");
|
||||
}
|
||||
if (ldns_rdf_size(dname) < LDNS_MAX_DOMAINLEN) {
|
||||
wire = malloc(ldns_rdf_size(dname) + 2);
|
||||
if (!wire) {
|
||||
fprintf(stderr, "Malloc error: out of memory?\n");
|
||||
exit(127);
|
||||
}
|
||||
wire[0] = (uint8_t) 1;
|
||||
wire[1] = (uint8_t) '\000';
|
||||
memcpy(&wire[2], ldns_rdf_data(dname), ldns_rdf_size(dname));
|
||||
pos = 0;
|
||||
status = ldns_wire2dname(&newdname, wire, ldns_rdf_size(dname) + 2, &pos);
|
||||
free(wire);
|
||||
} else {
|
||||
wire = malloc(ldns_rdf_size(dname));
|
||||
if (!wire) {
|
||||
fprintf(stderr, "Malloc error: out of memory?\n");
|
||||
exit(127);
|
||||
}
|
||||
labellen = ldns_rdf_data(dname)[0];
|
||||
wire[0] = labellen;
|
||||
memcpy(&wire[1], ldns_rdf_data(dname) + 1, labellen);
|
||||
memcpy(&wire[labellen], ldns_rdf_data(dname) + labellen, ldns_rdf_size(dname) - labellen);
|
||||
i = labellen;
|
||||
while (wire[i] == 255) {
|
||||
if (i == 0) {
|
||||
printf("Error, don't know how to add 1 to a label with maximum length and all values on 255\n");
|
||||
exit(9);
|
||||
} else {
|
||||
i--;
|
||||
}
|
||||
}
|
||||
wire[i] = wire[i] + 1;
|
||||
pos = 0;
|
||||
status = ldns_wire2dname(&newdname, wire, ldns_rdf_size(dname) + 1, &pos);
|
||||
free(wire);
|
||||
}
|
||||
if (verbosity >= 3) {
|
||||
printf("result: ");
|
||||
ldns_rdf_print(stdout, newdname);
|
||||
printf("\n");
|
||||
}
|
||||
|
||||
if (status != LDNS_STATUS_OK) {
|
||||
printf("Error: %s\n", ldns_get_errorstr_by_id(status));
|
||||
exit(10);
|
||||
}
|
||||
|
||||
return newdname;
|
||||
}
|
||||
|
||||
static ldns_rdf *
|
||||
create_plus_1_dname(ldns_rdf *dname)
|
||||
{
|
||||
ldns_rdf *label;
|
||||
ldns_status status;
|
||||
|
||||
if (verbosity >= 3) {
|
||||
printf("Creating n+e for: ");
|
||||
ldns_rdf_print(stdout, dname);
|
||||
printf("\n");
|
||||
}
|
||||
|
||||
ldns_dname2canonical(dname);
|
||||
status = ldns_str2rdf_dname(&label, "\\000");
|
||||
if (status != LDNS_STATUS_OK) {
|
||||
printf("error creating \\000 dname: %s\n\n", ldns_get_errorstr_by_id(status));
|
||||
exit(2);
|
||||
}
|
||||
status = ldns_dname_cat(label, dname);
|
||||
if (status != LDNS_STATUS_OK) {
|
||||
printf("error catting \\000 dname: %s\n\n", ldns_get_errorstr_by_id(status));
|
||||
exit(3);
|
||||
}
|
||||
return label;
|
||||
}
|
||||
|
||||
static void
|
||||
query_type_bitmaps(ldns_resolver *res,
|
||||
uint16_t res_flags,
|
||||
const ldns_rdf *name,
|
||||
const ldns_rdf *rdf)
|
||||
{
|
||||
/* Note: this code is duplicated in higher.c in
|
||||
* ldns_nsec_type_check() function
|
||||
*/
|
||||
uint8_t window_block_nr;
|
||||
uint8_t bitmap_length;
|
||||
uint16_t type;
|
||||
uint16_t pos = 0;
|
||||
uint16_t bit_pos;
|
||||
uint8_t *data = ldns_rdf_data(rdf);
|
||||
|
||||
ldns_pkt *answer_pkt;
|
||||
char *errstr;
|
||||
|
||||
if (verbosity >= 3) {
|
||||
printf("Getting Resource Records covered by NSEC at ");
|
||||
ldns_rdf_print(stdout, name);
|
||||
printf("\n");
|
||||
}
|
||||
|
||||
while(pos < ldns_rdf_size(rdf)) {
|
||||
window_block_nr = data[pos];
|
||||
bitmap_length = data[pos + 1];
|
||||
pos += 2;
|
||||
|
||||
for (bit_pos = 0; bit_pos < (bitmap_length) * 8; bit_pos++) {
|
||||
if (ldns_get_bit(&data[pos], bit_pos)) {
|
||||
type = 256 * (uint16_t) window_block_nr + bit_pos;
|
||||
/* skip nsec and rrsig */
|
||||
if (type != LDNS_RR_TYPE_NSEC &&
|
||||
type != LDNS_RR_TYPE_RRSIG) {
|
||||
if (verbosity >= 3) {
|
||||
printf("querying for:\n");
|
||||
ldns_rdf_print(stdout, name);
|
||||
printf(" type %u\n", (unsigned int) type);
|
||||
}
|
||||
answer_pkt = ldns_resolver_query(res, name, type,
|
||||
LDNS_RR_CLASS_IN,
|
||||
res_flags);
|
||||
if (answer_pkt) {
|
||||
if (verbosity >= 5) {
|
||||
ldns_pkt_print(stdout, answer_pkt);
|
||||
}
|
||||
/* hmm, this does not give us the right records
|
||||
* when asking for type NS above the delegation
|
||||
* (or, in fact, when the delegated zone is
|
||||
* served by this server either)
|
||||
* do we need to special case NS like NSEC?
|
||||
* or can we fix the query or the answer reading?
|
||||
* ...
|
||||
*/
|
||||
ldns_rr_list_print(stdout,
|
||||
ldns_pkt_answer(answer_pkt));
|
||||
ldns_pkt_free(answer_pkt);
|
||||
} else {
|
||||
printf("Query error, bailing out\n");
|
||||
printf("Failed at ");
|
||||
ldns_rdf_print(stdout, name);
|
||||
errstr = ldns_rr_type2str(type);
|
||||
printf(" %s\n", errstr);
|
||||
free(errstr);
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
pos += (uint16_t) bitmap_length;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
main(int argc, char *argv[])
|
||||
{
|
||||
ldns_status status;
|
||||
|
||||
ldns_resolver *res;
|
||||
ldns_rdf *domain = NULL;
|
||||
ldns_pkt *p;
|
||||
ldns_rr *soa;
|
||||
ldns_rr_list *rrlist;
|
||||
ldns_rr_list *rrlist2;
|
||||
ldns_rr_list *nsec_sigs = NULL;
|
||||
ldns_rdf *soa_p1;
|
||||
ldns_rdf *next_dname;
|
||||
ldns_rdf *last_dname;
|
||||
ldns_rdf *last_dname_p;
|
||||
ldns_rdf *startpoint = NULL;
|
||||
ldns_rr *nsec_rr = NULL;
|
||||
const char* arg_domain = NULL;
|
||||
int full = 0;
|
||||
|
||||
char *serv = NULL;
|
||||
ldns_rdf *serv_rdf;
|
||||
ldns_resolver *cmdline_res;
|
||||
ldns_rr_list *cmdline_rr_list;
|
||||
ldns_rdf *cmdline_dname;
|
||||
|
||||
uint8_t fam = LDNS_RESOLV_INETANY;
|
||||
int result = 0;
|
||||
int i;
|
||||
char *arg_end_ptr = NULL;
|
||||
size_t j;
|
||||
|
||||
p = NULL;
|
||||
rrlist = NULL;
|
||||
rrlist2 = NULL;
|
||||
soa = NULL;
|
||||
domain = NULL;
|
||||
|
||||
if (argc < 2) {
|
||||
usage(stdout, argv[0]);
|
||||
exit(EXIT_FAILURE);
|
||||
} else {
|
||||
for (i = 1; i < argc; i++) {
|
||||
if (strncmp(argv[i], "-4", 3) == 0) {
|
||||
if (fam != LDNS_RESOLV_INETANY) {
|
||||
fprintf(stderr, "You can only specify one of -4 or -6\n");
|
||||
exit(1);
|
||||
}
|
||||
fam = LDNS_RESOLV_INET;
|
||||
} else if (strncmp(argv[i], "-6", 3) == 0) {
|
||||
if (fam != LDNS_RESOLV_INETANY) {
|
||||
fprintf(stderr, "You can only specify one of -4 or -6\n");
|
||||
exit(1);
|
||||
}
|
||||
fam = LDNS_RESOLV_INET6;
|
||||
} else if (strncmp(argv[i], "-f", 3) == 0) {
|
||||
full = true;
|
||||
} else if (strncmp(argv[i], "-s", 3) == 0) {
|
||||
if (i + 1 < argc) {
|
||||
if (ldns_str2rdf_dname(&startpoint, argv[i + 1]) != LDNS_STATUS_OK) {
|
||||
printf("Bad start point name: %s\n", argv[i + 1]);
|
||||
exit(1);
|
||||
}
|
||||
} else {
|
||||
printf("Missing argument for -s\n");
|
||||
exit(1);
|
||||
}
|
||||
i++;
|
||||
} else if (strncmp(argv[i], "-v", 3) == 0) {
|
||||
if (i + 1 < argc) {
|
||||
verbosity = strtol(argv[i+1], &arg_end_ptr, 10);
|
||||
if (*arg_end_ptr != '\0') {
|
||||
printf("Bad argument for -v: %s\n", argv[i+1]);
|
||||
exit(1);
|
||||
}
|
||||
} else {
|
||||
printf("Missing argument for -v\n");
|
||||
exit(1);
|
||||
}
|
||||
i++;
|
||||
} else if (strcmp("-version", argv[i]) == 0) {
|
||||
printf("dns zone walker, version %s (ldns version %s)\n", LDNS_VERSION, ldns_version());
|
||||
goto exit;
|
||||
} else {
|
||||
if (argv[i][0] == '@') {
|
||||
if (strlen(argv[i]) == 1) {
|
||||
if (i + 1 < argc) {
|
||||
serv = argv[i + 1];
|
||||
i++;
|
||||
} else {
|
||||
printf("Missing argument for -s\n");
|
||||
exit(1);
|
||||
}
|
||||
} else {
|
||||
serv = argv[i] + 1;
|
||||
}
|
||||
} else {
|
||||
if (i < argc) {
|
||||
if (!domain) {
|
||||
/* create a rdf from the command line arg */
|
||||
arg_domain = argv[i];
|
||||
domain = ldns_dname_new_frm_str(arg_domain);
|
||||
if (!domain) {
|
||||
usage(stdout, argv[0]);
|
||||
exit(1);
|
||||
}
|
||||
} else {
|
||||
printf("One domain at a time please\n");
|
||||
exit(1);
|
||||
}
|
||||
} else {
|
||||
printf("No domain given to walk\n");
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!domain) {
|
||||
printf("Missing argument\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
|
||||
/* create a new resolver from /etc/resolv.conf */
|
||||
if(!serv) {
|
||||
if (ldns_resolver_new_frm_file(&res, NULL) != LDNS_STATUS_OK) {
|
||||
fprintf(stderr, "%s", "Could not create resolver obj");
|
||||
result = EXIT_FAILURE;
|
||||
goto exit;
|
||||
}
|
||||
} else {
|
||||
res = ldns_resolver_new();
|
||||
if (!res || strlen(serv) <= 0) {
|
||||
result = EXIT_FAILURE;
|
||||
goto exit;
|
||||
}
|
||||
/* add the nameserver */
|
||||
serv_rdf = ldns_rdf_new_frm_str(LDNS_RDF_TYPE_A, serv);
|
||||
if (!serv_rdf) {
|
||||
/* maybe ip6 */
|
||||
serv_rdf = ldns_rdf_new_frm_str(LDNS_RDF_TYPE_AAAA, serv);
|
||||
}
|
||||
if (!serv_rdf) {
|
||||
/* try to resolv the name if possible */
|
||||
status = ldns_resolver_new_frm_file(&cmdline_res, NULL);
|
||||
|
||||
if (status != LDNS_STATUS_OK) {
|
||||
fprintf(stderr, "%s", "@server ip could not be converted");
|
||||
result = EXIT_FAILURE;
|
||||
goto exit;
|
||||
}
|
||||
|
||||
cmdline_dname = ldns_dname_new_frm_str(serv);
|
||||
cmdline_rr_list = ldns_get_rr_list_addr_by_name(
|
||||
cmdline_res,
|
||||
cmdline_dname,
|
||||
LDNS_RR_CLASS_IN,
|
||||
0);
|
||||
ldns_rdf_deep_free(cmdline_dname);
|
||||
ldns_resolver_deep_free(cmdline_res);
|
||||
if (!cmdline_rr_list) {
|
||||
fprintf(stderr, "%s %s", "could not find any address for the name: ", serv);
|
||||
result = EXIT_FAILURE;
|
||||
goto exit;
|
||||
} else {
|
||||
if (ldns_resolver_push_nameserver_rr_list(
|
||||
res,
|
||||
cmdline_rr_list
|
||||
) != LDNS_STATUS_OK) {
|
||||
fprintf(stderr, "%s", "pushing nameserver");
|
||||
result = EXIT_FAILURE;
|
||||
ldns_rr_list_deep_free(cmdline_rr_list);
|
||||
goto exit;
|
||||
}
|
||||
ldns_rr_list_deep_free(cmdline_rr_list);
|
||||
}
|
||||
} else {
|
||||
if (ldns_resolver_push_nameserver(res, serv_rdf) != LDNS_STATUS_OK) {
|
||||
fprintf(stderr, "%s", "pushing nameserver");
|
||||
result = EXIT_FAILURE;
|
||||
goto exit;
|
||||
} else {
|
||||
ldns_rdf_deep_free(serv_rdf);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
ldns_resolver_set_dnssec(res, true);
|
||||
ldns_resolver_set_dnssec_cd(res, true);
|
||||
ldns_resolver_set_ip6(res, fam);
|
||||
|
||||
if (!res) {
|
||||
exit(2);
|
||||
}
|
||||
|
||||
/* use the resolver to send it a query for the soa
|
||||
* records of the domain given on the command line
|
||||
*/
|
||||
if (verbosity >= 3) {
|
||||
printf("\nQuerying for: ");
|
||||
ldns_rdf_print(stdout, domain);
|
||||
printf("\n");
|
||||
}
|
||||
p = ldns_resolver_query(res, domain, LDNS_RR_TYPE_SOA, LDNS_RR_CLASS_IN, LDNS_RD);
|
||||
soa = NULL;
|
||||
if (verbosity >= 5) {
|
||||
if (p) {
|
||||
ldns_pkt_print(stdout, p);
|
||||
} else {
|
||||
fprintf(stdout, "No Packet Received from ldns_resolver_query()\n");
|
||||
}
|
||||
}
|
||||
|
||||
if (!p) {
|
||||
exit(3);
|
||||
} else {
|
||||
/* retrieve the MX records from the answer section of that
|
||||
* packet
|
||||
*/
|
||||
rrlist = ldns_pkt_rr_list_by_type(p, LDNS_RR_TYPE_SOA, LDNS_SECTION_ANSWER);
|
||||
if (!rrlist || ldns_rr_list_rr_count(rrlist) != 1) {
|
||||
if (rrlist) {
|
||||
printf(" *** > 1 SOA: %u\n", (unsigned int) ldns_rr_list_rr_count(rrlist));
|
||||
} else {
|
||||
printf(" *** No rrlist...\b");
|
||||
}
|
||||
/* TODO: conversion memory */
|
||||
fprintf(stderr,
|
||||
" *** invalid answer name after SOA query for %s\n",
|
||||
arg_domain);
|
||||
ldns_pkt_print(stdout, p);
|
||||
ldns_pkt_free(p);
|
||||
ldns_resolver_deep_free(res);
|
||||
exit(4);
|
||||
} else {
|
||||
soa = ldns_rr_clone(ldns_rr_list_rr(rrlist, 0));
|
||||
ldns_rr_list_deep_free(rrlist);
|
||||
rrlist = NULL;
|
||||
/* check if zone contains DNSSEC data */
|
||||
rrlist = ldns_pkt_rr_list_by_type(p, LDNS_RR_TYPE_RRSIG, LDNS_SECTION_ANSWER);
|
||||
if (!rrlist) {
|
||||
printf("No DNSSEC data received; either the zone is not secured or you should query it directly (with @nameserver)\n");
|
||||
ldns_pkt_free(p);
|
||||
ldns_resolver_deep_free(res);
|
||||
exit(5);
|
||||
}
|
||||
ldns_rr_list_deep_free(rrlist);
|
||||
}
|
||||
}
|
||||
|
||||
/* add \001 to soa */
|
||||
status = ldns_str2rdf_dname(&soa_p1, "\\000");
|
||||
if (status != LDNS_STATUS_OK) {
|
||||
printf("error: %s\n", ldns_get_errorstr_by_id(status));
|
||||
}
|
||||
if (!soa) {
|
||||
printf("Error getting SOA\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
if (startpoint) {
|
||||
last_dname = startpoint;
|
||||
last_dname_p = create_dname_plus_1(last_dname);
|
||||
} else {
|
||||
last_dname = ldns_rdf_clone(domain);
|
||||
if (ldns_dname_cat(soa_p1, last_dname) != LDNS_STATUS_OK) {
|
||||
printf("Error concatenating dnames\n");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
last_dname_p = ldns_rdf_clone(soa_p1);
|
||||
}
|
||||
|
||||
if (!full) {
|
||||
ldns_rdf_print(stdout, ldns_rr_owner(soa));
|
||||
printf("\t");
|
||||
}
|
||||
|
||||
next_dname = NULL;
|
||||
while (!next_dname || ldns_rdf_compare(next_dname, domain) != 0) {
|
||||
if (p) {
|
||||
ldns_pkt_free(p);
|
||||
p = NULL;
|
||||
}
|
||||
if (verbosity >= 4) {
|
||||
printf("Querying for: ");
|
||||
ldns_rdf_print(stdout, last_dname_p);
|
||||
printf("\n");
|
||||
}
|
||||
p = ldns_resolver_query(res, last_dname_p, LDNS_RR_TYPE_DS, LDNS_RR_CLASS_IN, LDNS_RD);
|
||||
if (verbosity >= 5) {
|
||||
if (p) {
|
||||
ldns_pkt_print(stdout, p);
|
||||
} else {
|
||||
fprintf(stdout, "No Packet Received from ldns_resolver_query()\n");
|
||||
}
|
||||
}
|
||||
|
||||
if (next_dname) {
|
||||
ldns_rdf_deep_free(next_dname);
|
||||
ldns_rr_free(nsec_rr);
|
||||
next_dname = NULL;
|
||||
nsec_rr = NULL;
|
||||
}
|
||||
|
||||
if (!p) {
|
||||
fprintf(stderr, "Error trying to resolve: ");
|
||||
ldns_rdf_print(stderr, last_dname_p);
|
||||
fprintf(stderr, "\n");
|
||||
while (!p) {
|
||||
if (verbosity >= 3) {
|
||||
printf("Querying for: ");
|
||||
ldns_rdf_print(stdout, last_dname_p);
|
||||
printf("\n");
|
||||
}
|
||||
p = ldns_resolver_query(res, last_dname_p, LDNS_RR_TYPE_DS, LDNS_RR_CLASS_IN, LDNS_RD);
|
||||
/* TODO: make a general option for this (something like ignore_rtt)? */
|
||||
for (j = 0; j < ldns_resolver_nameserver_count(res); j++) {
|
||||
if (ldns_resolver_nameserver_rtt(res, j) != 0) {
|
||||
ldns_resolver_set_nameserver_rtt(res, j, LDNS_RESOLV_RTT_MIN);
|
||||
}
|
||||
}
|
||||
if (verbosity >= 5) {
|
||||
if (p) {
|
||||
ldns_pkt_print(stdout, p);
|
||||
} else {
|
||||
fprintf(stdout, "No Packet Received from ldns_resolver_query()\n");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* if the current name is an empty non-terminal, bind returns
|
||||
* SERVFAIL on the plus1-query...
|
||||
* so requery with only the last dname
|
||||
*/
|
||||
if (ldns_pkt_get_rcode(p) == LDNS_RCODE_SERVFAIL) {
|
||||
ldns_pkt_free(p);
|
||||
p = NULL;
|
||||
if (verbosity >= 3) {
|
||||
printf("Querying for: ");
|
||||
ldns_rdf_print(stdout, last_dname);
|
||||
printf("\n");
|
||||
}
|
||||
p = ldns_resolver_query(res, last_dname, LDNS_RR_TYPE_DS, LDNS_RR_CLASS_IN, LDNS_RD);
|
||||
if (verbosity >= 5) {
|
||||
if (p) {
|
||||
ldns_pkt_print(stdout, p);
|
||||
} else {
|
||||
fprintf(stdout, "No Packet Received from ldns_resolver_query()\n");
|
||||
}
|
||||
}
|
||||
|
||||
if (!p) {
|
||||
exit(51);
|
||||
}
|
||||
rrlist = ldns_pkt_rr_list_by_type(p, LDNS_RR_TYPE_NSEC, LDNS_SECTION_AUTHORITY);
|
||||
rrlist2 = ldns_pkt_rr_list_by_type(p, LDNS_RR_TYPE_NSEC, LDNS_SECTION_ANSWER);
|
||||
} else {
|
||||
rrlist = ldns_pkt_rr_list_by_type(p, LDNS_RR_TYPE_NSEC, LDNS_SECTION_AUTHORITY);
|
||||
rrlist2 = ldns_pkt_rr_list_by_type(p, LDNS_RR_TYPE_NSEC, LDNS_SECTION_ANSWER);
|
||||
}
|
||||
if (rrlist && rrlist2) {
|
||||
ldns_rr_list_cat(rrlist, rrlist2);
|
||||
} else if (rrlist2) {
|
||||
rrlist = rrlist2;
|
||||
}
|
||||
|
||||
if (!rrlist || ldns_rr_list_rr_count(rrlist) < 1) {
|
||||
if (!rrlist) {
|
||||
fflush(stdout);
|
||||
fprintf(stderr, "Zone does not seem to be DNSSEC secured,"
|
||||
"or it uses NSEC3.\n");
|
||||
fflush(stderr);
|
||||
goto exit;
|
||||
}
|
||||
} else {
|
||||
/* find correct nsec */
|
||||
next_dname = NULL;
|
||||
for (j = 0; j < ldns_rr_list_rr_count(rrlist); j++) {
|
||||
if (ldns_nsec_covers_name(ldns_rr_list_rr(rrlist, j), last_dname_p)) {
|
||||
if (verbosity >= 3) {
|
||||
printf("The domain name: ");
|
||||
ldns_rdf_print(stdout, last_dname_p);
|
||||
printf("\nis covered by NSEC: ");
|
||||
ldns_rr_print(stdout, ldns_rr_list_rr(rrlist, j));
|
||||
}
|
||||
next_dname = ldns_rdf_clone(ldns_rr_rdf(ldns_rr_list_rr(rrlist, j), 0));
|
||||
nsec_rr = ldns_rr_clone(ldns_rr_list_rr(rrlist, j));
|
||||
nsec_sigs = ldns_dnssec_pkt_get_rrsigs_for_name_and_type(p, ldns_rr_owner(nsec_rr), LDNS_RR_TYPE_NSEC);
|
||||
} else {
|
||||
if (verbosity >= 4) {
|
||||
printf("\n");
|
||||
ldns_rdf_print(stdout, last_dname_p);
|
||||
printf("\nNOT covered by NSEC: ");
|
||||
ldns_rr_print(stdout, ldns_rr_list_rr(rrlist, j));
|
||||
printf("\n");
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!next_dname) {
|
||||
printf("Error no nsec for ");
|
||||
ldns_rdf_print(stdout, last_dname);
|
||||
printf("\n");
|
||||
exit(1);
|
||||
}
|
||||
ldns_rr_list_deep_free(rrlist);
|
||||
}
|
||||
if (!next_dname) {
|
||||
/* apparently the zone also has prepended data (i.e. a.example and www.a.example,
|
||||
* The www comes after the a but before a\\000, so we need to make another name (\\000.a)
|
||||
*/
|
||||
if (last_dname_p) {
|
||||
ldns_rdf_deep_free(last_dname_p);
|
||||
}
|
||||
last_dname_p = create_plus_1_dname(last_dname);
|
||||
} else {
|
||||
if (last_dname) {
|
||||
if (ldns_rdf_compare(last_dname, next_dname) == 0) {
|
||||
printf("\n\nNext dname is the same as current, this would loop forever. This is a problem that usually occurs when walking through a caching forwarder. Try using the authoritative nameserver to walk (with @nameserver).\n");
|
||||
exit(2);
|
||||
}
|
||||
ldns_rdf_deep_free(last_dname);
|
||||
}
|
||||
last_dname = ldns_rdf_clone(next_dname);
|
||||
if (last_dname_p) {
|
||||
ldns_rdf_deep_free(last_dname_p);
|
||||
}
|
||||
last_dname_p = create_dname_plus_1(last_dname);
|
||||
if (!full) {
|
||||
ldns_rdf_print(stdout, ldns_rr_owner(nsec_rr));
|
||||
printf(" ");
|
||||
ldns_rdf_print(stdout, ldns_rr_rdf(nsec_rr, 1));
|
||||
printf("\n");
|
||||
} else {
|
||||
/* ok, so now we know all the types present at this name,
|
||||
* query for those one by one (...)
|
||||
*/
|
||||
query_type_bitmaps(res, LDNS_RD, ldns_rr_owner(nsec_rr),
|
||||
ldns_rr_rdf(nsec_rr, 1));
|
||||
/* print this nsec and its signatures too */
|
||||
ldns_rr_print(stdout, nsec_rr);
|
||||
if (nsec_sigs) {
|
||||
ldns_rr_list_print(stdout, nsec_sigs);
|
||||
ldns_rr_list_free(nsec_sigs);
|
||||
nsec_sigs = NULL;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
ldns_rdf_deep_free(domain);
|
||||
ldns_rdf_deep_free(soa_p1);
|
||||
ldns_rdf_deep_free(last_dname_p);
|
||||
ldns_rdf_deep_free(last_dname);
|
||||
ldns_rdf_deep_free(next_dname);
|
||||
ldns_rr_free(nsec_rr);
|
||||
ldns_pkt_free(p);
|
||||
|
||||
ldns_rr_free(soa);
|
||||
|
||||
printf("\n\n");
|
||||
ldns_resolver_deep_free(res);
|
||||
|
||||
exit:
|
||||
return result;
|
||||
}
|
||||
34
zonemaster-ldns/ldns/examples/ldns-zcat.1
Normal file
34
zonemaster-ldns/ldns/examples/ldns-zcat.1
Normal file
@@ -0,0 +1,34 @@
|
||||
.TH ldns-zcat 1 "15 Dec 2005"
|
||||
.SH NAME
|
||||
ldns-zcat \- reunite (z)split up a zone files
|
||||
.SH SYNOPSIS
|
||||
.B ldns-zcat
|
||||
.IR zonefiles
|
||||
|
||||
.SH DESCRIPTION
|
||||
.B ldns-zcat
|
||||
will read in a bunch of (z)split up zonefiles and creates a new larger
|
||||
zone file. The SOA record in the first part is used as the SOA record
|
||||
in the generated zone.
|
||||
.PP
|
||||
The resulted zone file is printed to standard output.
|
||||
|
||||
.SH OPTIONS
|
||||
.TP
|
||||
.B -o ORIGIN
|
||||
use ORIGIN when reading in the zone
|
||||
|
||||
.TP
|
||||
.B -v
|
||||
show the version number and exit
|
||||
|
||||
.SH AUTHOR
|
||||
Written by the ldns team as an example for ldns usage.
|
||||
|
||||
.SH REPORTING BUGS
|
||||
Report bugs to <dns-team@nlnetlabs.nl>.
|
||||
|
||||
.SH COPYRIGHT
|
||||
Copyright (C) 2005, 2006 NLnet Labs. This is free software. There is NO
|
||||
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR
|
||||
PURPOSE.
|
||||
171
zonemaster-ldns/ldns/examples/ldns-zcat.c
Normal file
171
zonemaster-ldns/ldns/examples/ldns-zcat.c
Normal file
@@ -0,0 +1,171 @@
|
||||
/*
|
||||
* read a zone that is split up with ldns-zsplit and re-create
|
||||
* the original zone
|
||||
*
|
||||
* From:
|
||||
* zone1: SOA a b c d e f
|
||||
* zone2: SOA f g h i k l
|
||||
*
|
||||
* Go back to:
|
||||
* zone: SOA a b c d e f g h i j k l
|
||||
*
|
||||
* This is useful in combination with ldns-zsplit
|
||||
*
|
||||
* See the file LICENSE for the license
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
#include <errno.h>
|
||||
#include <ldns/ldns.h>
|
||||
|
||||
#define FIRST_ZONE 0
|
||||
#define MIDDLE_ZONE 1
|
||||
#define LAST_ZONE 2
|
||||
|
||||
static void
|
||||
usage(FILE *f, char *progname)
|
||||
{
|
||||
fprintf(f, "Usage: %s [OPTIONS] <zonefiles>\n", progname);
|
||||
fprintf(f, " Concatenate signed zone snippets created with ldns-zsplit\n");
|
||||
fprintf(f, " back together. The generate zone file is printed to stdout\n");
|
||||
fprintf(f, " The new zone should be equal to the original zone (before splitting)\n");
|
||||
fprintf(f, "OPTIONS:\n");
|
||||
fprintf(f, "-o ORIGIN\tUse this as initial origin, for zones starting with @\n");
|
||||
fprintf(f, "-v\t\tShow the version number and exit\n");
|
||||
}
|
||||
|
||||
int
|
||||
main(int argc, char **argv)
|
||||
{
|
||||
char *progname;
|
||||
FILE *fp;
|
||||
int c;
|
||||
ldns_rdf *origin;
|
||||
size_t i, j;
|
||||
int where;
|
||||
ldns_zone *z;
|
||||
ldns_rr_list *zrr;
|
||||
ldns_rr *current_rr;
|
||||
ldns_rr *soa;
|
||||
ldns_rdf *last_owner;
|
||||
ldns_rr *last_rr;
|
||||
ldns_rr *pop_rr;
|
||||
|
||||
progname = strdup(argv[0]);
|
||||
origin = NULL;
|
||||
|
||||
while ((c = getopt(argc, argv, "o:v")) != -1) {
|
||||
switch(c) {
|
||||
case 'o':
|
||||
origin = ldns_dname_new_frm_str(strdup(optarg));
|
||||
if (!origin) {
|
||||
fprintf(stderr, "Cannot convert the origin %s to a domainname\n", optarg);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
break;
|
||||
case 'v':
|
||||
printf("zone file concatenator version %s (ldns version %s)\n", LDNS_VERSION, ldns_version());
|
||||
exit(EXIT_SUCCESS);
|
||||
break;
|
||||
default:
|
||||
fprintf(stderr, "Unrecognized option\n");
|
||||
usage(stdout, progname);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
}
|
||||
|
||||
argc -= optind;
|
||||
argv += optind;
|
||||
|
||||
if (argc < 1) {
|
||||
usage(stdout, progname);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
for (i = 0; i < (size_t)argc; i++) {
|
||||
|
||||
if (!(fp = fopen(argv[i], "r"))) {
|
||||
fprintf(stderr, "Error opening key file %s: %s\n", argv[i], strerror(errno));
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
if (ldns_zone_new_frm_fp(&z, fp, origin, 0, 0) != LDNS_STATUS_OK) {
|
||||
fprintf(stderr, "Zone file %s could not be parsed correctly\n", argv[i]);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
zrr = ldns_zone_rrs(z);
|
||||
soa = ldns_zone_soa(z); /* SOA is stored separately */
|
||||
|
||||
fprintf(stderr, "%s\n", argv[i]);
|
||||
|
||||
if (0 == i) {
|
||||
where = FIRST_ZONE;
|
||||
|
||||
/* remove the last equal named RRs */
|
||||
last_rr = ldns_rr_list_pop_rr(zrr);
|
||||
last_owner = ldns_rr_owner(last_rr);
|
||||
/* remove until no match */
|
||||
do {
|
||||
pop_rr = ldns_rr_list_pop_rr(zrr);
|
||||
} while(ldns_rdf_compare(last_owner, ldns_rr_owner(pop_rr)) == 0) ;
|
||||
/* we popped one to many, put it back */
|
||||
ldns_rr_list_push_rr(zrr, pop_rr);
|
||||
} else if ((size_t)(argc - 1) == i) {
|
||||
where = LAST_ZONE;
|
||||
} else {
|
||||
where = MIDDLE_ZONE;
|
||||
|
||||
/* remove the last equal named RRs */
|
||||
last_rr = ldns_rr_list_pop_rr(zrr);
|
||||
last_owner = ldns_rr_owner(last_rr);
|
||||
/* remove until no match */
|
||||
do {
|
||||
pop_rr = ldns_rr_list_pop_rr(zrr);
|
||||
} while(ldns_rdf_compare(last_owner, ldns_rr_owner(pop_rr)) == 0) ;
|
||||
/* we popped one to many, put it back */
|
||||
ldns_rr_list_push_rr(zrr, pop_rr);
|
||||
}
|
||||
|
||||
/* printing the RRs */
|
||||
for (j = 0; j < ldns_rr_list_rr_count(zrr); j++) {
|
||||
|
||||
current_rr = ldns_rr_list_rr(zrr, j);
|
||||
|
||||
switch(where) {
|
||||
case FIRST_ZONE:
|
||||
if (soa) {
|
||||
ldns_rr_print(stdout, soa);
|
||||
soa = NULL;
|
||||
}
|
||||
break;
|
||||
case MIDDLE_ZONE:
|
||||
/* rm SOA */
|
||||
/* SOA isn't printed by default */
|
||||
|
||||
/* rm SOA aux records
|
||||
* this also takes care of the DNSKEYs + RRSIGS
|
||||
*/
|
||||
if (ldns_rdf_compare(ldns_rr_owner(current_rr),
|
||||
ldns_rr_owner(soa)) == 0) {
|
||||
continue;
|
||||
}
|
||||
break;
|
||||
case LAST_ZONE:
|
||||
/* rm SOA */
|
||||
/* SOA isn't printed by default */
|
||||
|
||||
/* rm SOA aux records
|
||||
* this also takes care of the DNSKEYs + RRSIGS
|
||||
*/
|
||||
if (ldns_rdf_compare(ldns_rr_owner(current_rr),
|
||||
ldns_rr_owner(soa)) == 0) {
|
||||
continue;
|
||||
}
|
||||
break;
|
||||
}
|
||||
ldns_rr_print(stdout, current_rr);
|
||||
}
|
||||
}
|
||||
exit(EXIT_SUCCESS);
|
||||
}
|
||||
43
zonemaster-ldns/ldns/examples/ldns-zsplit.1
Normal file
43
zonemaster-ldns/ldns/examples/ldns-zsplit.1
Normal file
@@ -0,0 +1,43 @@
|
||||
.TH ldns-zsplit 1 "15 Dec 2005"
|
||||
.SH NAME
|
||||
ldns-zsplit \- split up a zone file
|
||||
.SH SYNOPSIS
|
||||
.B ldns-zsplit
|
||||
[
|
||||
.IR OPTIONS
|
||||
]
|
||||
.IR zonefile
|
||||
|
||||
.SH DESCRIPTION
|
||||
|
||||
.SH OPTIONS
|
||||
.TP
|
||||
.B -n NUMBER
|
||||
Split after NUMBER RRs, \fBldns-zsplit\fR will not split in
|
||||
the middle of an RRs.
|
||||
.PP
|
||||
Each part is saved with a numerical suffix, starting with .000. The
|
||||
largest suffix is thus .999.
|
||||
|
||||
.TP
|
||||
.B -o ORIGIN
|
||||
use ORIGIN as origin when reading the zonefile.
|
||||
|
||||
.TP
|
||||
.B -z
|
||||
Sort the zone before splitting.
|
||||
|
||||
.TP
|
||||
.B -v
|
||||
Show version number and exit.
|
||||
|
||||
.SH AUTHOR
|
||||
Written by the ldns team as an example for ldns usage.
|
||||
|
||||
.SH REPORTING BUGS
|
||||
Report bugs to <dns-team@nlnetlabs.nl>.
|
||||
|
||||
.SH COPYRIGHT
|
||||
Copyright (C) 2005, 2006 NLnet Labs. This is free software. There is NO
|
||||
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR
|
||||
PURPOSE.
|
||||
273
zonemaster-ldns/ldns/examples/ldns-zsplit.c
Normal file
273
zonemaster-ldns/ldns/examples/ldns-zsplit.c
Normal file
@@ -0,0 +1,273 @@
|
||||
/*
|
||||
* read a zone from disk and split it up:
|
||||
*
|
||||
* zone: SOA a b c d e f g h i j k l
|
||||
* becomes:
|
||||
* zone1: SOA a b c d e f
|
||||
* zone2: SOA f g h i k l
|
||||
*
|
||||
* ldns-catzone removes the last name and put
|
||||
* the zone back together.
|
||||
*
|
||||
* This way you can incremental sign a zone
|
||||
*
|
||||
* See the file LICENSE for the license
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
#include <errno.h>
|
||||
#include <ldns/ldns.h>
|
||||
|
||||
#define DEFAULT_SPLIT 1000
|
||||
#define FILE_SIZE 255
|
||||
#define SPLIT_MAX 999
|
||||
#define NO_SPLIT 0
|
||||
#define INTENT_TO_SPLIT 1
|
||||
#define SPLIT_NOW 2
|
||||
|
||||
static void
|
||||
usage(FILE *f, char *progname)
|
||||
{
|
||||
fprintf(f, "Usage: %s [OPTIONS] <zonefile> [keys]\n", progname);
|
||||
fprintf(f, " Cut a zone file into pieces, each part is put in a file\n");
|
||||
fprintf(f, " named: '<zonefile>.NNN'. Where NNN is a integer ranging 000 to 999.\n");
|
||||
fprintf(f, " If key files are given they are inserted in each part.\n");
|
||||
fprintf(f, " The original SOA is also included in each part, making them correct DNS\n");
|
||||
fprintf(f, " (mini) zones.\n");
|
||||
fprintf(f, " This utility can be used to parallel sign a large zone.\n");
|
||||
fprintf(f, " To make it work the original zone needs to be canonical ordered.\n");
|
||||
fprintf(f, "\nOPTIONS:\n");
|
||||
fprintf(f, " -n NUMBER\tsplit after this many RRs\n");
|
||||
fprintf(f, " -o ORIGIN\tuse this as initial origin, for zones starting with @\n");
|
||||
fprintf(f, " -z\t\tsort the zone prior to splitting. The current ldns zone\n");
|
||||
fprintf(f, " \t\timplementation makes this unusable for large zones.\n");
|
||||
fprintf(f, " -v\t\tshow version number and exit\n");
|
||||
}
|
||||
|
||||
|
||||
/* key the keys from the cmd line */
|
||||
static ldns_rr_list *
|
||||
open_keyfiles(char **files, uint16_t filec)
|
||||
{
|
||||
uint16_t i;
|
||||
ldns_rr_list *pubkeys;
|
||||
ldns_rr *k;
|
||||
FILE *kfp;
|
||||
|
||||
pubkeys = ldns_rr_list_new();
|
||||
|
||||
for (i = 0; i < filec; i++) {
|
||||
if (!(kfp = fopen(files[i], "r"))) {
|
||||
fprintf(stderr, "Error opening key file %s: %s\n", files[i], strerror(errno));
|
||||
return NULL;
|
||||
}
|
||||
if (ldns_rr_new_frm_fp(&k, kfp, NULL, NULL, NULL) != LDNS_STATUS_OK) {
|
||||
fprintf(stderr, "Error parsing the key file %s: %s\n", files[i], strerror(errno));
|
||||
ldns_rr_list_deep_free(pubkeys);
|
||||
return NULL;
|
||||
}
|
||||
fclose(kfp);
|
||||
ldns_rr_list_push_rr(pubkeys, k);
|
||||
}
|
||||
return pubkeys;
|
||||
}
|
||||
|
||||
/* open a new zone file with the correct suffix */
|
||||
static FILE *
|
||||
open_newfile(char *basename, ldns_zone *z, size_t counter, ldns_rr_list *keys)
|
||||
{
|
||||
char filename[FILE_SIZE];
|
||||
FILE *fp;
|
||||
|
||||
if (counter > SPLIT_MAX) {
|
||||
fprintf(stderr, "Maximum split count reached %u\n", (unsigned int) counter);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
snprintf(filename, FILE_SIZE, "%s.%03u", basename, (unsigned int) counter);
|
||||
|
||||
if (!(fp = fopen(filename, "w"))) {
|
||||
fprintf(stderr, "Cannot open zone %s: %s\n", filename, strerror(errno));
|
||||
return NULL;
|
||||
} else {
|
||||
fprintf(stderr, "%s\n", filename);
|
||||
}
|
||||
ldns_rr_print(fp, ldns_zone_soa(z));
|
||||
if (keys) {
|
||||
ldns_rr_list_print(fp, keys);
|
||||
|
||||
}
|
||||
return fp;
|
||||
}
|
||||
|
||||
int
|
||||
main(int argc, char **argv)
|
||||
{
|
||||
char *progname;
|
||||
FILE *fp;
|
||||
ldns_zone *z;
|
||||
ldns_rr_list *zrrs;
|
||||
ldns_rdf *lastname;
|
||||
int c;
|
||||
int line_nr;
|
||||
size_t split;
|
||||
size_t i;
|
||||
int splitting;
|
||||
int compare;
|
||||
size_t file_counter;
|
||||
ldns_rdf *origin;
|
||||
ldns_rdf *current_rdf;
|
||||
ldns_rr *current_rr;
|
||||
ldns_rr_list *last_rrset;
|
||||
ldns_rr_list *pubkeys;
|
||||
bool sort;
|
||||
ldns_status s;
|
||||
|
||||
progname = strdup(argv[0]);
|
||||
split = 0;
|
||||
splitting = NO_SPLIT;
|
||||
file_counter = 0;
|
||||
lastname = NULL;
|
||||
origin = NULL;
|
||||
last_rrset = ldns_rr_list_new();
|
||||
sort = false;
|
||||
|
||||
while ((c = getopt(argc, argv, "n:o:zv")) != -1) {
|
||||
switch(c) {
|
||||
case 'n':
|
||||
split = (size_t)atoi(optarg);
|
||||
if (split == 0) {
|
||||
fprintf(stderr, "-n want a integer\n");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
break;
|
||||
case 'o':
|
||||
origin = ldns_dname_new_frm_str(strdup(optarg));
|
||||
if (!origin) {
|
||||
fprintf(stderr, "Cannot convert the origin %s to a domainname\n", optarg);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
break;
|
||||
case 'v':
|
||||
printf("zone file splitter version %s (ldns version %s)\n", LDNS_VERSION, ldns_version());
|
||||
exit(EXIT_SUCCESS);
|
||||
break;
|
||||
case 'z':
|
||||
sort = true;
|
||||
break;
|
||||
default:
|
||||
fprintf(stderr, "Unrecognized option\n");
|
||||
usage(stdout, progname);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
}
|
||||
if (split == 0) {
|
||||
split = DEFAULT_SPLIT;
|
||||
}
|
||||
|
||||
argc -= optind;
|
||||
argv += optind;
|
||||
|
||||
if (argc < 1) {
|
||||
usage(stdout, progname);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
if (!(fp = fopen(argv[0], "r"))) {
|
||||
fprintf(stderr, "Unable to open %s: %s\n", argv[0], strerror(errno));
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
/* get the keys */
|
||||
pubkeys = open_keyfiles(argv + 1, (uint16_t) argc - 1);
|
||||
|
||||
/* suck in the entire zone ... */
|
||||
if (!origin) {
|
||||
origin = ldns_dname_new_frm_str(".");
|
||||
}
|
||||
|
||||
s = ldns_zone_new_frm_fp_l(&z, fp, origin, 0, LDNS_RR_CLASS_IN, &line_nr);
|
||||
fclose(fp);
|
||||
|
||||
if (s != LDNS_STATUS_OK) {
|
||||
fprintf(stderr, "Zone file %s could not be parsed correctly: %s at line %d\n",
|
||||
argv[0],
|
||||
ldns_get_errorstr_by_id(s),
|
||||
line_nr);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
/* these kind of things can kill you... */
|
||||
if (sort) {
|
||||
ldns_zone_sort(z);
|
||||
}
|
||||
|
||||
zrrs = ldns_zone_rrs(z);
|
||||
if (ldns_rr_list_rr_count(zrrs) / split > SPLIT_MAX) {
|
||||
fprintf(stderr, "The zone is too large for the used -n value: %u\n", (unsigned int) split);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
|
||||
/* Setup */
|
||||
if (!(fp = open_newfile(argv[0], z, file_counter, pubkeys))) {
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
for(i = 0; i < ldns_rr_list_rr_count(zrrs); i++) {
|
||||
|
||||
current_rr = ldns_rr_list_rr(zrrs, i);
|
||||
current_rdf = ldns_rr_owner(current_rr);
|
||||
|
||||
compare = ldns_dname_compare(current_rdf, lastname);
|
||||
|
||||
if (compare == 0) {
|
||||
ldns_rr_list_push_rr(last_rrset, current_rr);
|
||||
}
|
||||
|
||||
if (i > 0 && (i % split) == 0) {
|
||||
splitting = INTENT_TO_SPLIT;
|
||||
}
|
||||
|
||||
if (splitting == INTENT_TO_SPLIT) {
|
||||
if (compare != 0) {
|
||||
splitting = SPLIT_NOW;
|
||||
}
|
||||
}
|
||||
|
||||
if (splitting == SPLIT_NOW) {
|
||||
fclose(fp);
|
||||
|
||||
lastname = NULL;
|
||||
splitting = NO_SPLIT;
|
||||
file_counter++;
|
||||
if (!(fp = open_newfile(argv[0], z, file_counter, pubkeys))) {
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
/* insert the last RRset in the new file */
|
||||
ldns_rr_list_print(fp, last_rrset);
|
||||
|
||||
/* print the current rr */
|
||||
ldns_rr_print(fp, current_rr);
|
||||
|
||||
/* remove them */
|
||||
ldns_rr_list_free(last_rrset);
|
||||
last_rrset = ldns_rr_list_new();
|
||||
/* add the current RR */
|
||||
ldns_rr_list_push_rr(last_rrset, current_rr);
|
||||
continue;
|
||||
}
|
||||
if (splitting == NO_SPLIT || splitting == INTENT_TO_SPLIT) {
|
||||
ldns_rr_print(fp, current_rr);
|
||||
}
|
||||
if (compare != 0) {
|
||||
/* remove them and then add the current one */
|
||||
ldns_rr_list_free(last_rrset);
|
||||
last_rrset = ldns_rr_list_new();
|
||||
ldns_rr_list_push_rr(last_rrset, current_rr);
|
||||
}
|
||||
lastname = current_rdf;
|
||||
}
|
||||
fclose(fp);
|
||||
exit(EXIT_SUCCESS);
|
||||
}
|
||||
26
zonemaster-ldns/ldns/examples/ldnsd.1
Normal file
26
zonemaster-ldns/ldns/examples/ldnsd.1
Normal file
@@ -0,0 +1,26 @@
|
||||
.TH ldnsd 1 "27 Apr 2005"
|
||||
.SH NAME
|
||||
ldnsd \- simple daemon example code
|
||||
.SH SYNOPSIS
|
||||
.B ldnsd
|
||||
.IR port
|
||||
.IR zone
|
||||
.IR zonefile
|
||||
|
||||
.SH DESCRIPTION
|
||||
\fBldnsd\fR is a simple daemon that answers queries for a zone.
|
||||
This is NOT a full-fledged authoritative nameserver!
|
||||
|
||||
.SH OPTIONS
|
||||
\fBldnsd\fR takes a port, zone and zonefile as arguments.
|
||||
|
||||
.SH AUTHOR
|
||||
Written by the ldns team as an example for ldns usage.
|
||||
|
||||
.SH REPORTING BUGS
|
||||
Report bugs to <dns-team@nlnetlabs.nl>.
|
||||
|
||||
.SH COPYRIGHT
|
||||
Copyright (C) 2005 NLnet Labs. This is free software. There is NO
|
||||
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR
|
||||
PURPOSE.
|
||||
245
zonemaster-ldns/ldns/examples/ldnsd.c
Normal file
245
zonemaster-ldns/ldns/examples/ldnsd.c
Normal file
@@ -0,0 +1,245 @@
|
||||
/*
|
||||
* ldnsd. Light-weight DNS daemon
|
||||
*
|
||||
* Tiny dns server to show how a real one could be built.
|
||||
*
|
||||
* (c) NLnet Labs, 2005
|
||||
* See the file LICENSE for the license
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
#include <ldns/ldns.h>
|
||||
|
||||
#ifdef HAVE_SYS_SOCKET_H
|
||||
# include <sys/socket.h>
|
||||
#endif
|
||||
#ifdef HAVE_ARPA_INET_H
|
||||
# include <arpa/inet.h>
|
||||
#endif
|
||||
#ifdef HAVE_NETINET_IN_H
|
||||
# include <netinet/in.h>
|
||||
#endif
|
||||
#ifdef HAVE_NETINET_UDP_H
|
||||
# include <netinet/udp.h>
|
||||
#endif
|
||||
#ifdef HAVE_NETINET_IGMP_H
|
||||
# include <netinet/igmp.h>
|
||||
#endif
|
||||
|
||||
#include <errno.h>
|
||||
|
||||
#define INBUF_SIZE 4096
|
||||
|
||||
static void usage(FILE *output)
|
||||
{
|
||||
fprintf(output, "Usage: ldnsd <address> <port> <zone> <zonefile>\n");
|
||||
fprintf(output, "Listens on the specified port and answers queries for the given zone\n");
|
||||
fprintf(output, "This is NOT a full-fledged authoritative nameserver!\n");
|
||||
}
|
||||
|
||||
static int udp_bind(int sock, int port, const char *my_address)
|
||||
{
|
||||
struct sockaddr_in addr;
|
||||
in_addr_t maddr = INADDR_ANY;
|
||||
|
||||
if (my_address) {
|
||||
#ifdef AF_INET6
|
||||
if (inet_pton(AF_INET6, my_address, &maddr) < 1) {
|
||||
#else
|
||||
if (0) {
|
||||
#endif
|
||||
if (inet_pton(AF_INET, my_address, &maddr) < 1) {
|
||||
return -2;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#ifndef S_SPLINT_S
|
||||
addr.sin_family = AF_INET;
|
||||
#endif
|
||||
addr.sin_port = (in_port_t) htons((uint16_t)port);
|
||||
addr.sin_addr.s_addr = maddr;
|
||||
return bind(sock, (struct sockaddr *)&addr, (socklen_t) sizeof(addr));
|
||||
}
|
||||
|
||||
/* this will probably be moved to a better place in the library itself */
|
||||
static ldns_rr_list *
|
||||
get_rrset(const ldns_zone *zone, const ldns_rdf *owner_name, const ldns_rr_type qtype, const ldns_rr_class qclass)
|
||||
{
|
||||
uint16_t i;
|
||||
ldns_rr_list *rrlist = ldns_rr_list_new();
|
||||
ldns_rr *cur_rr;
|
||||
if (!zone || !owner_name) {
|
||||
fprintf(stderr, "Warning: get_rrset called with NULL zone or owner name\n");
|
||||
return rrlist;
|
||||
}
|
||||
|
||||
for (i = 0; i < ldns_zone_rr_count(zone); i++) {
|
||||
cur_rr = ldns_rr_list_rr(ldns_zone_rrs(zone), i);
|
||||
if (ldns_dname_compare(ldns_rr_owner(cur_rr), owner_name) == 0 &&
|
||||
ldns_rr_get_class(cur_rr) == qclass &&
|
||||
ldns_rr_get_type(cur_rr) == qtype
|
||||
) {
|
||||
ldns_rr_list_push_rr(rrlist, ldns_rr_clone(cur_rr));
|
||||
}
|
||||
}
|
||||
|
||||
printf("Found rrset of %u rrs\n", (unsigned int) ldns_rr_list_rr_count(rrlist));
|
||||
|
||||
return rrlist;
|
||||
}
|
||||
|
||||
int
|
||||
main(int argc, char **argv)
|
||||
{
|
||||
/* arguments */
|
||||
int port;
|
||||
const char *zone_file;
|
||||
|
||||
/* network */
|
||||
int sock;
|
||||
ssize_t nb;
|
||||
struct sockaddr addr_me;
|
||||
struct sockaddr addr_him;
|
||||
socklen_t hislen = (socklen_t) sizeof(addr_him);
|
||||
uint8_t inbuf[INBUF_SIZE];
|
||||
uint8_t *outbuf;
|
||||
|
||||
/* dns */
|
||||
ldns_status status;
|
||||
ldns_pkt *query_pkt;
|
||||
ldns_pkt *answer_pkt;
|
||||
size_t answer_size;
|
||||
ldns_rr *query_rr;
|
||||
ldns_rr_list *answer_qr;
|
||||
ldns_rr_list *answer_an;
|
||||
ldns_rr_list *answer_ns;
|
||||
ldns_rr_list *answer_ad;
|
||||
ldns_rdf *origin = NULL;
|
||||
|
||||
/* zone */
|
||||
ldns_zone *zone;
|
||||
int line_nr;
|
||||
FILE *zone_fp;
|
||||
|
||||
/* use this to listen on specified interfaces later? */
|
||||
char *my_address = NULL;
|
||||
|
||||
if (argc < 5) {
|
||||
usage(stderr);
|
||||
exit(EXIT_FAILURE);
|
||||
} else {
|
||||
my_address = argv[1];
|
||||
port = atoi(argv[2]);
|
||||
if (port < 1) {
|
||||
usage(stderr);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
if (ldns_str2rdf_dname(&origin, argv[3]) != LDNS_STATUS_OK) {
|
||||
fprintf(stderr, "Bad origin, not a correct domain name\n");
|
||||
usage(stderr);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
zone_file = argv[4];
|
||||
}
|
||||
|
||||
printf("Reading zone file %s\n", zone_file);
|
||||
zone_fp = fopen(zone_file, "r");
|
||||
if (!zone_fp) {
|
||||
fprintf(stderr, "Unable to open %s: %s\n", zone_file, strerror(errno));
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
line_nr = 0;
|
||||
status = ldns_zone_new_frm_fp_l(&zone, zone_fp, origin, 0, LDNS_RR_CLASS_IN, &line_nr);
|
||||
|
||||
if (status != LDNS_STATUS_OK) {
|
||||
printf("Zone reader failed, aborting\n");
|
||||
exit(EXIT_FAILURE);
|
||||
} else {
|
||||
printf("Read %u resource records in zone file\n", (unsigned int) ldns_zone_rr_count(zone));
|
||||
}
|
||||
fclose(zone_fp);
|
||||
|
||||
printf("Listening on port %d\n", port);
|
||||
sock = socket(AF_INET, SOCK_DGRAM, 0);
|
||||
if (sock < 0) {
|
||||
fprintf(stderr, "%s: socket(): %s\n", argv[0], strerror(errno));
|
||||
exit(1);
|
||||
}
|
||||
memset(&addr_me, 0, sizeof(addr_me));
|
||||
|
||||
/* bind: try all ports in that range */
|
||||
if (udp_bind(sock, port, my_address)) {
|
||||
fprintf(stderr, "%s: cannot bind(): %s\n", argv[0], strerror(errno));
|
||||
exit(errno);
|
||||
}
|
||||
|
||||
/* Done. Now receive */
|
||||
while (1) {
|
||||
nb = recvfrom(sock, (void*)inbuf, INBUF_SIZE, 0,
|
||||
&addr_him, &hislen);
|
||||
if (nb < 1) {
|
||||
fprintf(stderr, "%s: recvfrom(): %s\n",
|
||||
argv[0], strerror(errno));
|
||||
exit(1);
|
||||
}
|
||||
|
||||
/*
|
||||
show(inbuf, nb, nn, hp, sp, ip, bp);
|
||||
*/
|
||||
printf("Got query of %u bytes\n", (unsigned int) nb);
|
||||
status = ldns_wire2pkt(&query_pkt, inbuf, (size_t) nb);
|
||||
if (status != LDNS_STATUS_OK) {
|
||||
printf("Got bad packet: %s\n", ldns_get_errorstr_by_id(status));
|
||||
} else {
|
||||
ldns_pkt_print(stdout, query_pkt);
|
||||
}
|
||||
|
||||
query_rr = ldns_rr_list_rr(ldns_pkt_question(query_pkt), 0);
|
||||
printf("QUERY RR: \n");
|
||||
ldns_rr_print(stdout, query_rr);
|
||||
|
||||
answer_qr = ldns_rr_list_new();
|
||||
ldns_rr_list_push_rr(answer_qr, ldns_rr_clone(query_rr));
|
||||
|
||||
answer_an = get_rrset(zone, ldns_rr_owner(query_rr), ldns_rr_get_type(query_rr), ldns_rr_get_class(query_rr));
|
||||
answer_pkt = ldns_pkt_new();
|
||||
answer_ns = ldns_rr_list_new();
|
||||
answer_ad = ldns_rr_list_new();
|
||||
|
||||
ldns_pkt_set_qr(answer_pkt, 1);
|
||||
ldns_pkt_set_aa(answer_pkt, 1);
|
||||
ldns_pkt_set_id(answer_pkt, ldns_pkt_id(query_pkt));
|
||||
|
||||
ldns_pkt_push_rr_list(answer_pkt, LDNS_SECTION_QUESTION, answer_qr);
|
||||
ldns_pkt_push_rr_list(answer_pkt, LDNS_SECTION_ANSWER, answer_an);
|
||||
ldns_pkt_push_rr_list(answer_pkt, LDNS_SECTION_AUTHORITY, answer_ns);
|
||||
ldns_pkt_push_rr_list(answer_pkt, LDNS_SECTION_ADDITIONAL, answer_ad);
|
||||
|
||||
status = ldns_pkt2wire(&outbuf, answer_pkt, &answer_size);
|
||||
|
||||
printf("Answer packet size: %u bytes.\n", (unsigned int) answer_size);
|
||||
if (status != LDNS_STATUS_OK) {
|
||||
printf("Error creating answer: %s\n", ldns_get_errorstr_by_id(status));
|
||||
} else {
|
||||
(void) sendto(sock, (void*)outbuf, answer_size, 0,
|
||||
&addr_him, hislen);
|
||||
}
|
||||
|
||||
ldns_pkt_free(query_pkt);
|
||||
ldns_pkt_free(answer_pkt);
|
||||
LDNS_FREE(outbuf);
|
||||
ldns_rr_list_free(answer_qr);
|
||||
ldns_rr_list_free(answer_an);
|
||||
ldns_rr_list_free(answer_ns);
|
||||
ldns_rr_list_free(answer_ad);
|
||||
}
|
||||
|
||||
/* No cleanup because of the infinite loop
|
||||
*
|
||||
* ldns_rdf_deep_free(origin);
|
||||
* ldns_zone_deep_free(zone);
|
||||
* return 0;
|
||||
*/
|
||||
}
|
||||
61
zonemaster-ldns/ldns/examples/nsd-test/Makefile.in
Normal file
61
zonemaster-ldns/ldns/examples/nsd-test/Makefile.in
Normal file
@@ -0,0 +1,61 @@
|
||||
# Standard installation pathnames
|
||||
# See the file LICENSE for the license
|
||||
SHELL = @SHELL@
|
||||
VERSION = @PACKAGE_VERSION@
|
||||
basesrcdir = $(shell basename `pwd`)
|
||||
srcdir = @srcdir@
|
||||
prefix = @prefix@
|
||||
exec_prefix = @exec_prefix@
|
||||
bindir = @bindir@
|
||||
mandir = @mandir@
|
||||
|
||||
CC = @CC@
|
||||
CFLAGS = @CFLAGS@ -Wall -I.
|
||||
CPPFLAGS = @CPPFLAGS@
|
||||
LDFLAGS = @LDFLAGS@
|
||||
LIBS = @LIBS@
|
||||
LDNSDIR = @LDNSDIR@
|
||||
|
||||
COMPILE = $(CC) $(CPPFLAGS) $(CFLAGS) $(LDFLAGS) $(LIBS)
|
||||
|
||||
LINT = splint
|
||||
LINTFLAGS = +quiet -weak -warnposix -unrecog -Din_addr_t=uint32_t -Du_int=unsigned -Du_char=uint8_t -preproc
|
||||
|
||||
HEADER = config.h
|
||||
SOURCES = ldns-testns.c nsd-ldnsd.c
|
||||
|
||||
PROGRAMS=$(SOURCES:.c=)
|
||||
|
||||
.PHONY: all clean realclean
|
||||
|
||||
all: $(PROGRAMS)
|
||||
|
||||
all-static: $(PROGRAMS:=-stc)
|
||||
|
||||
%: $(srcdir)/%.c
|
||||
$(COMPILE) -o $@ $(srcdir)/$@.c
|
||||
|
||||
%-stc:
|
||||
@# can't mix implicit and static rules
|
||||
@if [ $(srcdir)/$(@:-stc=).c -nt $(@:-stc=) ] ; then \
|
||||
echo "$(CC) $(CPPFLAGS) $(CFLAGS) -lpcap -lcrypto -o $(@:-stc=) $(srcdir)/$(@:-stc=).c $(LDNSDIR)/lib/libldns.a" ; \
|
||||
$(CC) $(CPPFLAGS) $(CFLAGS) -lpcap -lcrypto -o $(@:-stc=) $(srcdir)/$(@:-stc=).c $(LDNSDIR)/lib/libldns.a ; \
|
||||
fi ;
|
||||
|
||||
lint:
|
||||
for i in $(SOURCES); do \
|
||||
$(LINT) $(LINTFLAGS) -I. -I$(srcdir) $(srcdir)/$$i $(CPPFLAGS); \
|
||||
if [ $$? -ne 0 ] ; then exit 1 ; fi ; \
|
||||
done
|
||||
|
||||
clean:
|
||||
rm -f *.o
|
||||
rm -f $(PROGRAMS)
|
||||
|
||||
realclean: clean
|
||||
rm -rf autom4te.cache/
|
||||
rm -f config.log config.status aclocal.m4 config.h.in configure Makefile
|
||||
rm -f config.h
|
||||
|
||||
confclean: clean
|
||||
rm -rf config.log config.status config.h Makefile
|
||||
181
zonemaster-ldns/ldns/examples/nsd-test/configure.ac
Normal file
181
zonemaster-ldns/ldns/examples/nsd-test/configure.ac
Normal file
@@ -0,0 +1,181 @@
|
||||
# -*- Autoconf -*-
|
||||
# Process this file with autoconf to produce a configure script.
|
||||
|
||||
AC_PREREQ(2.57)
|
||||
AC_INIT(ldns, 1.7.0, dns-team@nlnetlabs.nl,libdns)
|
||||
AC_CONFIG_SRCDIR([nsd-ldnsd.c])
|
||||
|
||||
OURCPPFLAGS='-D_POSIX_C_SOURCE=200112 -D_XOPEN_SOURCE=600 -D__EXTENSIONS__ -D__BSD_VISIBLE'
|
||||
CPPFLAGS=${CPPFLAGS:-${OURCPPFLAGS}}
|
||||
OURCFLAGS='-g'
|
||||
CFLAGS=${CFLAGS:-${OURCFLAGS}}
|
||||
|
||||
AC_AIX
|
||||
# Checks for programs.
|
||||
AC_PROG_CC
|
||||
AC_PROG_MAKE_SET
|
||||
|
||||
dnl routine to help check for compiler flags.
|
||||
AC_DEFUN([CHECK_COMPILER_FLAG],
|
||||
[
|
||||
AC_REQUIRE([AC_PROG_CC])
|
||||
AC_MSG_CHECKING(whether $CC supports -$1)
|
||||
cache=`echo $1 | sed 'y%.=/+-%___p_%'`
|
||||
AC_CACHE_VAL(cv_prog_cc_flag_$cache,
|
||||
[
|
||||
echo 'void f(){}' >conftest.c
|
||||
if test -z "`$CC -$1 -c conftest.c 2>&1`"; then
|
||||
eval "cv_prog_cc_flag_$cache=yes"
|
||||
else
|
||||
eval "cv_prog_cc_flag_$cache=no"
|
||||
fi
|
||||
rm -f conftest*
|
||||
])
|
||||
if eval "test \"`echo '$cv_prog_cc_flag_'$cache`\" = yes"; then
|
||||
AC_MSG_RESULT(yes)
|
||||
:
|
||||
$2
|
||||
else
|
||||
AC_MSG_RESULT(no)
|
||||
:
|
||||
$3
|
||||
fi
|
||||
])
|
||||
CHECK_COMPILER_FLAG(O2, [CFLAGS="$CFLAGS -O2"])
|
||||
CHECK_COMPILER_FLAG(std=c99, [CFLAGS="$CFLAGS -std=c99"], [CFLAGS="$CFLAGS -ansi"])
|
||||
|
||||
AC_CHECK_HEADERS([sys/types.h getopt.h stdlib.h stdio.h assert.h netinet/in.h ctype.h time.h pcap.h arpa/inet.h sys/time.h sys/socket.h],,, [AC_INCLUDES_DEFAULT])
|
||||
AC_CHECK_HEADERS([netinet/in_systm.h net/if.h netinet/ip.h netinet/udp.h netinet/if_ether.h],,, [
|
||||
AC_INCLUDES_DEFAULT
|
||||
#ifdef HAVE_NETINET_IN_SYSTM_H
|
||||
#include <netinet/in_systm.h>
|
||||
#endif
|
||||
#ifdef HAVE_NETINET_IN_H
|
||||
#include <netinet/in.h>
|
||||
#endif
|
||||
#ifdef HAVE_SYS_SOCKET_H
|
||||
#include <sys/socket.h>
|
||||
#endif
|
||||
#ifdef HAVE_NET_IF_H
|
||||
#include <net/if.h>
|
||||
#endif])
|
||||
|
||||
AC_CHECK_HEADERS([sys/param.h sys/mount.h],,,
|
||||
[AC_INCLUDES_DEFAULT]
|
||||
[
|
||||
[
|
||||
#if HAVE_SYS_PARAM_H
|
||||
# include <sys/param.h>
|
||||
#endif
|
||||
]
|
||||
])
|
||||
|
||||
AC_CHECK_LIB(socket, socket)
|
||||
AC_CHECK_LIB(nsl, inet_ntop)
|
||||
|
||||
# check for ldns
|
||||
AC_ARG_WITH(ldns,
|
||||
AC_HELP_STRING([--with-ldns=PATH specify prefix of path of ldns library to use])
|
||||
,
|
||||
[
|
||||
specialldnsdir="$withval"
|
||||
CPPFLAGS="$CPPFLAGS -I$withval/include"
|
||||
LDFLAGS="$LDFLAGS -L$withval/lib"
|
||||
LDNSDIR="$withval"
|
||||
]
|
||||
)
|
||||
|
||||
# check for ldns development source tree
|
||||
AC_MSG_CHECKING([for ldns devel source])
|
||||
ldns_dev_dir=../..
|
||||
if test -f $ldns_dev_dir/ldns/util.h && \
|
||||
grep LDNS_VERSION $ldns_dev_dir/ldns/util.h >/dev/null; then
|
||||
ldns_version=`grep LDNS_VERSION $ldns_dev_dir/ldns/util.h | sed -e 's/^.*"\(.*\)".*$/\1/'`
|
||||
AC_MSG_RESULT([using $ldns_dev_dir with $ldns_version])
|
||||
CPPFLAGS="$CPPFLAGS -I$ldns_dev_dir/include"
|
||||
LDFLAGS="$LDFLAGS -L$ldns_dev_dir/lib"
|
||||
LIBS="$LIBS -lldns"
|
||||
AC_DEFINE(HAVE_LIBLDNS, 1, [If the ldns library is available.])
|
||||
LDNSDIR="$ldns_dev_dir"
|
||||
else
|
||||
AC_MSG_RESULT([no])
|
||||
AC_CHECK_LIB(ldns, ldns_rr_new,, [
|
||||
AC_MSG_ERROR([Can't find ldns library])
|
||||
]
|
||||
)
|
||||
fi
|
||||
|
||||
AC_SUBST(LDNSDIR)
|
||||
|
||||
AC_CHECK_HEADER(ldns/ldns.h,, [
|
||||
AC_MSG_ERROR([Can't find ldns headers])
|
||||
], [AC_INCLUDES_DEFAULT]
|
||||
)
|
||||
|
||||
AC_CHECK_LIB(pcap, pcap_open_offline,, [
|
||||
AC_MSG_WARN([Can't find pcap library (needed for ldns-dpa, will not build dpa now.)])
|
||||
]
|
||||
)
|
||||
|
||||
AC_CHECK_FUNCS(isblank)
|
||||
|
||||
AH_BOTTOM([
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
#include <assert.h>
|
||||
|
||||
#if STDC_HEADERS
|
||||
#include <stdlib.h>
|
||||
#include <stddef.h>
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_STDINT_H
|
||||
#include <stdint.h>
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_SYS_SOCKET_H
|
||||
#include <sys/socket.h>
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_NETINET_IN_H
|
||||
#include <netinet/in.h>
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_ARPA_INET_H
|
||||
#include <arpa/inet.h>
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_NETINET_UDP_H
|
||||
#include <netinet/udp.h>
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_TIME_H
|
||||
#include <time.h>
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_PCAP_H
|
||||
#include <pcap.h>
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_NETINET_IN_SYSTM_H
|
||||
#include <netinet/in_systm.h>
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_NETINET_IP_H
|
||||
#include <netinet/ip.h>
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_NET_IF_H
|
||||
#include <net/if.h>
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_NETINET_IF_ETHER_H
|
||||
#include <netinet/if_ether.h>
|
||||
#endif
|
||||
])
|
||||
|
||||
AC_CONFIG_FILES([Makefile])
|
||||
AC_CONFIG_HEADER([config.h])
|
||||
AC_OUTPUT
|
||||
806
zonemaster-ldns/ldns/examples/nsd-test/ldns-testns.c
Normal file
806
zonemaster-ldns/ldns/examples/nsd-test/ldns-testns.c
Normal file
@@ -0,0 +1,806 @@
|
||||
/*
|
||||
* ldns-testns. Light-weight DNS daemon, gives canned replies.
|
||||
*
|
||||
* Tiny dns server, that responds with specially crafted replies
|
||||
* to requests. For testing dns software.
|
||||
*
|
||||
* (c) NLnet Labs, 2005, 2006
|
||||
* See the file LICENSE for the license
|
||||
*/
|
||||
|
||||
/*
|
||||
* This program is a debugging aid. It can is not efficient, especially
|
||||
* with a long config file, but it can give any reply to any query.
|
||||
* This can help the developer pre-script replies for queries.
|
||||
*
|
||||
* It listens to IP4 UDP and TCP by default.
|
||||
* You can specify a packet RR by RR with header flags to return.
|
||||
*
|
||||
* Missing features:
|
||||
* - hexdump support, for 'formerr' packets.
|
||||
* - cannot mess up the header at present.
|
||||
* - matching content different from reply content.
|
||||
*/
|
||||
|
||||
/*
|
||||
The data file format is as follows:
|
||||
|
||||
; comment.
|
||||
; a number of entries, these are processed first to last.
|
||||
; a line based format.
|
||||
|
||||
$ORIGIN origin
|
||||
$TTL default_ttl
|
||||
|
||||
ENTRY_BEGIN
|
||||
; first give MATCH lines, that say what queries are matched
|
||||
; by this entry.
|
||||
; 'opcode' makes the query match the opcode from the reply
|
||||
; if you leave it out, any opcode matches this entry.
|
||||
; 'qtype' makes the query match the qtype from the reply
|
||||
; 'qname' makes the query match the qname from the reply
|
||||
; 'serial=1023' makes the query match if ixfr serial is 1023.
|
||||
MATCH [opcode] [qtype] [qname] [serial=<value>]
|
||||
MATCH [UDP|TCP]
|
||||
MATCH ...
|
||||
; Then the REPLY header is specified.
|
||||
REPLY opcode, rcode or flags.
|
||||
(opcode) QUERY IQUERY STATUS NOTIFY UPDATE
|
||||
(rcode) NOERROR FORMERR SERVFAIL NXDOMAIN NOTIMPL YXDOMAIN
|
||||
YXRRSET NXRRSET NOTAUTH NOTZONE
|
||||
(flags) QR AA TC RD CD RA AD
|
||||
REPLY ...
|
||||
; any additional actions to do.
|
||||
; 'copy_id' copies the ID from the query to the answer.
|
||||
ADJUST copy_id
|
||||
; 'sleep=10' sleeps for 10 seconds before giving the answer (TCP is open)
|
||||
ADJUST [sleep=<num>] ; sleep before giving any reply
|
||||
ADJUST [packet_sleep=<num>] ; sleep before this packet in sequence
|
||||
SECTION QUESTION
|
||||
<RRs, one per line> ; the RRcount is determined automatically.
|
||||
SECTION ANSWER
|
||||
<RRs, one per line>
|
||||
SECTION AUTHORITY
|
||||
<RRs, one per line>
|
||||
SECTION ADDITIONAL
|
||||
<RRs, one per line>
|
||||
EXTRA_PACKET ; follow with SECTION, REPLY for more packets.
|
||||
ENTRY_END
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
#include <ldns/ldns.h>
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/select.h>
|
||||
|
||||
#include <arpa/inet.h>
|
||||
#include <netinet/in.h>
|
||||
#include <netinet/udp.h>
|
||||
#include <netinet/igmp.h>
|
||||
#include <errno.h>
|
||||
|
||||
#define INBUF_SIZE 4096 /* max size for incoming queries */
|
||||
#define MAX_LINE 10240 /* max line length */
|
||||
#define DEFAULT_PORT 53 /* default if no -p port is specified */
|
||||
#define CONN_BACKLOG 5 /* 5 connections queued up for tcp */
|
||||
static const char* prog_name = "ldns-testns";
|
||||
static FILE* logfile = 0;
|
||||
static int verbose = 0;
|
||||
|
||||
enum transport_type {transport_any = 0, transport_udp, transport_tcp };
|
||||
|
||||
/* struct to keep a linked list of reply packets for a query */
|
||||
struct reply_packet {
|
||||
struct reply_packet* next;
|
||||
ldns_pkt* reply;
|
||||
int packet_sleep; /* seconds to sleep before giving packet */
|
||||
};
|
||||
|
||||
/* data structure to keep the canned queries in */
|
||||
/* format is the 'matching query' and the 'canned answer' */
|
||||
struct entry {
|
||||
/* match */
|
||||
/* How to match an incoming query with this canned reply */
|
||||
bool match_opcode; /* match query opcode with answer opcode */
|
||||
bool match_qtype; /* match qtype with answer qtype */
|
||||
bool match_qname; /* match qname with answer qname */
|
||||
bool match_serial; /* match SOA serial number, from auth section */
|
||||
uint32_t ixfr_soa_serial; /* match query serial with this value. */
|
||||
enum transport_type match_transport; /* match on UDP/TCP */
|
||||
|
||||
/* pre canned reply */
|
||||
struct reply_packet *reply_list;
|
||||
|
||||
/* how to adjust the reply packet */
|
||||
bool copy_id; /* copy over the ID from the query into the answer */
|
||||
int sleeptime; /* in seconds */
|
||||
|
||||
/* next in list */
|
||||
struct entry* next;
|
||||
};
|
||||
|
||||
static void usage()
|
||||
{
|
||||
printf("Usage: %s [options] <datafile>\n", prog_name);
|
||||
printf(" -p listens on the specified port, default %d.\n", DEFAULT_PORT);
|
||||
printf(" -v more verbose, prints queries, answers and matching.\n");
|
||||
printf("The program answers queries with canned replies from the datafile.\n");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
static void log_msg(const char* msg, ...)
|
||||
{
|
||||
va_list args;
|
||||
va_start(args, msg);
|
||||
vfprintf(logfile, msg, args);
|
||||
fflush(logfile);
|
||||
va_end(args);
|
||||
}
|
||||
|
||||
static void error(const char* msg, ...)
|
||||
{
|
||||
va_list args;
|
||||
va_start(args, msg);
|
||||
fprintf(logfile, "%s error: ", prog_name);
|
||||
vfprintf(logfile, msg, args);
|
||||
fprintf(logfile, "\n");
|
||||
fflush(stdout);
|
||||
va_end(args);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
static int bind_port(int sock, int port)
|
||||
{
|
||||
struct sockaddr_in addr;
|
||||
|
||||
addr.sin_family = AF_INET;
|
||||
addr.sin_port = (in_port_t)htons((uint16_t)port);
|
||||
addr.sin_addr.s_addr = INADDR_ANY;
|
||||
return bind(sock, (struct sockaddr *)&addr, (socklen_t) sizeof(addr));
|
||||
}
|
||||
|
||||
static bool isendline(char c)
|
||||
{
|
||||
if(c == ';' || c == '#'
|
||||
|| c == '\n' || c == 0)
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
/* true if the string starts with the keyword given. Moves the str ahead. */
|
||||
static bool str_keyword(const char** str, const char* keyword)
|
||||
{
|
||||
size_t len = strlen(keyword);
|
||||
assert(str && keyword);
|
||||
if(strncmp(*str, keyword, len) != 0)
|
||||
return false;
|
||||
*str += len;
|
||||
while(isspace((unsigned char)**str))
|
||||
(*str)++;
|
||||
return true;
|
||||
}
|
||||
|
||||
static struct reply_packet*
|
||||
entry_add_reply(struct entry* entry)
|
||||
{
|
||||
struct reply_packet* pkt = (struct reply_packet*)malloc(
|
||||
sizeof(struct reply_packet));
|
||||
struct reply_packet ** p = &entry->reply_list;
|
||||
pkt->next = NULL;
|
||||
pkt->packet_sleep = 0;
|
||||
pkt->reply = ldns_pkt_new();
|
||||
/* link at end */
|
||||
while(*p)
|
||||
p = &((*p)->next);
|
||||
*p = pkt;
|
||||
return pkt;
|
||||
}
|
||||
|
||||
static void matchline(const char* line, struct entry* e)
|
||||
{
|
||||
const char* parse = line;
|
||||
while(*parse) {
|
||||
if(isendline(*parse))
|
||||
return;
|
||||
if(str_keyword(&parse, "opcode")) {
|
||||
e->match_opcode = true;
|
||||
} else if(str_keyword(&parse, "qtype")) {
|
||||
e->match_qtype = true;
|
||||
} else if(str_keyword(&parse, "qname")) {
|
||||
e->match_qname = true;
|
||||
} else if(str_keyword(&parse, "UDP")) {
|
||||
e->match_transport = transport_udp;
|
||||
} else if(str_keyword(&parse, "TCP")) {
|
||||
e->match_transport = transport_tcp;
|
||||
} else if(str_keyword(&parse, "serial")) {
|
||||
e->match_serial = true;
|
||||
if(*parse != '=' && *parse != ':')
|
||||
error("expected = or : in MATCH: %s", line);
|
||||
parse++;
|
||||
e->ixfr_soa_serial = (uint32_t)strtol(parse, (char**)&parse, 10);
|
||||
while(isspace((unsigned char)*parse))
|
||||
parse++;
|
||||
} else {
|
||||
error("could not parse MATCH: '%s'", parse);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void replyline(const char* line, ldns_pkt *reply)
|
||||
{
|
||||
const char* parse = line;
|
||||
while(*parse) {
|
||||
if(isendline(*parse))
|
||||
return;
|
||||
/* opcodes */
|
||||
if(str_keyword(&parse, "QUERY")) {
|
||||
ldns_pkt_set_opcode(reply, LDNS_PACKET_QUERY);
|
||||
} else if(str_keyword(&parse, "IQUERY")) {
|
||||
ldns_pkt_set_opcode(reply, LDNS_PACKET_IQUERY);
|
||||
} else if(str_keyword(&parse, "STATUS")) {
|
||||
ldns_pkt_set_opcode(reply, LDNS_PACKET_STATUS);
|
||||
} else if(str_keyword(&parse, "NOTIFY")) {
|
||||
ldns_pkt_set_opcode(reply, LDNS_PACKET_NOTIFY);
|
||||
} else if(str_keyword(&parse, "UPDATE")) {
|
||||
ldns_pkt_set_opcode(reply, LDNS_PACKET_UPDATE);
|
||||
/* rcodes */
|
||||
} else if(str_keyword(&parse, "NOERROR")) {
|
||||
ldns_pkt_set_rcode(reply, LDNS_RCODE_NOERROR);
|
||||
} else if(str_keyword(&parse, "FORMERR")) {
|
||||
ldns_pkt_set_rcode(reply, LDNS_RCODE_FORMERR);
|
||||
} else if(str_keyword(&parse, "SERVFAIL")) {
|
||||
ldns_pkt_set_rcode(reply, LDNS_RCODE_SERVFAIL);
|
||||
} else if(str_keyword(&parse, "NXDOMAIN")) {
|
||||
ldns_pkt_set_rcode(reply, LDNS_RCODE_NXDOMAIN);
|
||||
} else if(str_keyword(&parse, "NOTIMPL")) {
|
||||
ldns_pkt_set_rcode(reply, LDNS_RCODE_NOTIMPL);
|
||||
} else if(str_keyword(&parse, "YXDOMAIN")) {
|
||||
ldns_pkt_set_rcode(reply, LDNS_RCODE_YXDOMAIN);
|
||||
} else if(str_keyword(&parse, "YXRRSET")) {
|
||||
ldns_pkt_set_rcode(reply, LDNS_RCODE_YXRRSET);
|
||||
} else if(str_keyword(&parse, "NXRRSET")) {
|
||||
ldns_pkt_set_rcode(reply, LDNS_RCODE_NXRRSET);
|
||||
} else if(str_keyword(&parse, "NOTAUTH")) {
|
||||
ldns_pkt_set_rcode(reply, LDNS_RCODE_NOTAUTH);
|
||||
} else if(str_keyword(&parse, "NOTZONE")) {
|
||||
ldns_pkt_set_rcode(reply, LDNS_RCODE_NOTZONE);
|
||||
/* flags */
|
||||
} else if(str_keyword(&parse, "QR")) {
|
||||
ldns_pkt_set_qr(reply, true);
|
||||
} else if(str_keyword(&parse, "AA")) {
|
||||
ldns_pkt_set_aa(reply, true);
|
||||
} else if(str_keyword(&parse, "TC")) {
|
||||
ldns_pkt_set_tc(reply, true);
|
||||
} else if(str_keyword(&parse, "RD")) {
|
||||
ldns_pkt_set_rd(reply, true);
|
||||
} else if(str_keyword(&parse, "CD")) {
|
||||
ldns_pkt_set_cd(reply, true);
|
||||
} else if(str_keyword(&parse, "RA")) {
|
||||
ldns_pkt_set_ra(reply, true);
|
||||
} else if(str_keyword(&parse, "AD")) {
|
||||
ldns_pkt_set_ad(reply, true);
|
||||
} else {
|
||||
error("could not parse REPLY: '%s'", parse);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void adjustline(const char* line, struct entry* e,
|
||||
struct reply_packet* pkt)
|
||||
{
|
||||
const char* parse = line;
|
||||
while(*parse) {
|
||||
if(isendline(*parse))
|
||||
return;
|
||||
if(str_keyword(&parse, "copy_id")) {
|
||||
e->copy_id = true;
|
||||
} else if(str_keyword(&parse, "sleep=")) {
|
||||
e->sleeptime = strtol(parse, (char**)&parse, 10);
|
||||
while(isspace((unsigned char)*parse))
|
||||
parse++;
|
||||
} else if(str_keyword(&parse, "packet_sleep=")) {
|
||||
pkt->packet_sleep = strtol(parse, (char**)&parse, 10);
|
||||
while(isspace((unsigned char)*parse))
|
||||
parse++;
|
||||
} else {
|
||||
error("could not parse ADJUST: '%s'", parse);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static struct entry* new_entry()
|
||||
{
|
||||
struct entry* e = LDNS_MALLOC(struct entry);
|
||||
memset(e, 0, sizeof(e));
|
||||
e->match_opcode = false;
|
||||
e->match_qtype = false;
|
||||
e->match_qname = false;
|
||||
e->match_serial = false;
|
||||
e->ixfr_soa_serial = 0;
|
||||
e->match_transport = transport_any;
|
||||
e->reply_list = NULL;
|
||||
e->copy_id = false;
|
||||
e->sleeptime = 0;
|
||||
e->next = NULL;
|
||||
return e;
|
||||
}
|
||||
|
||||
static void get_origin(const char* name, int lineno, ldns_rdf** origin, char* parse)
|
||||
{
|
||||
/* snip off rest of the text so as to make the parse work in ldns */
|
||||
char* end;
|
||||
char store;
|
||||
ldns_status status;
|
||||
|
||||
ldns_rdf_free(*origin);
|
||||
*origin = NULL;
|
||||
|
||||
end=parse;
|
||||
while(!isspace((unsigned char)*end) && !isendline(*end))
|
||||
end++;
|
||||
store = *end;
|
||||
*end = 0;
|
||||
log_msg("parsing '%s'\n", parse);
|
||||
status = ldns_str2rdf_dname(origin, parse);
|
||||
*end = store;
|
||||
if (status != LDNS_STATUS_OK)
|
||||
error("%s line %d:\n\t%s: %s", name, lineno,
|
||||
ldns_get_errorstr_by_id(status), parse);
|
||||
}
|
||||
|
||||
/* reads the canned reply file and returns a list of structs */
|
||||
static struct entry* read_datafile(const char* name)
|
||||
{
|
||||
struct entry* list = NULL;
|
||||
struct entry* last = NULL;
|
||||
struct entry* current = NULL;
|
||||
FILE *in;
|
||||
int lineno = 0;
|
||||
char line[MAX_LINE];
|
||||
const char* parse;
|
||||
ldns_pkt_section add_section = LDNS_SECTION_QUESTION;
|
||||
uint16_t default_ttl = 0;
|
||||
ldns_rdf* origin = NULL;
|
||||
ldns_rdf* prev_rr = NULL;
|
||||
int entry_num = 0;
|
||||
struct reply_packet *cur_reply = NULL;
|
||||
|
||||
if((in=fopen(name, "r")) == NULL) {
|
||||
error("could not open file %s: %s", name, strerror(errno));
|
||||
}
|
||||
|
||||
while(fgets(line, (int)sizeof(line), in) != NULL) {
|
||||
line[MAX_LINE-1] = 0;
|
||||
parse = line;
|
||||
lineno ++;
|
||||
|
||||
while(isspace((unsigned char)*parse))
|
||||
parse++;
|
||||
/* test for keywords */
|
||||
if(isendline(*parse))
|
||||
continue; /* skip comment and empty lines */
|
||||
if(str_keyword(&parse, "ENTRY_BEGIN")) {
|
||||
if(current) {
|
||||
error("%s line %d: previous entry does not ENTRY_END",
|
||||
name, lineno);
|
||||
}
|
||||
current = new_entry();
|
||||
cur_reply = entry_add_reply(current);
|
||||
if(last)
|
||||
last->next = current;
|
||||
else list = current;
|
||||
last = current;
|
||||
continue;
|
||||
} else if(str_keyword(&parse, "$ORIGIN")) {
|
||||
get_origin(name, lineno, &origin, (char*)parse);
|
||||
continue;
|
||||
} else if(str_keyword(&parse, "$TTL")) {
|
||||
default_ttl = (uint16_t)atoi(parse);
|
||||
continue;
|
||||
}
|
||||
|
||||
/* working inside an entry */
|
||||
if(!current) {
|
||||
error("%s line %d: expected ENTRY_BEGIN but got %s",
|
||||
name, lineno, line);
|
||||
}
|
||||
if(str_keyword(&parse, "MATCH")) {
|
||||
matchline(parse, current);
|
||||
} else if(str_keyword(&parse, "REPLY")) {
|
||||
replyline(parse, cur_reply->reply);
|
||||
} else if(str_keyword(&parse, "ADJUST")) {
|
||||
adjustline(parse, current, cur_reply);
|
||||
} else if(str_keyword(&parse, "EXTRA_PACKET")) {
|
||||
cur_reply = entry_add_reply(current);
|
||||
} else if(str_keyword(&parse, "SECTION")) {
|
||||
if(str_keyword(&parse, "QUESTION"))
|
||||
add_section = LDNS_SECTION_QUESTION;
|
||||
else if(str_keyword(&parse, "ANSWER"))
|
||||
add_section = LDNS_SECTION_ANSWER;
|
||||
else if(str_keyword(&parse, "AUTHORITY"))
|
||||
add_section = LDNS_SECTION_AUTHORITY;
|
||||
else if(str_keyword(&parse, "ADDITIONAL"))
|
||||
add_section = LDNS_SECTION_ADDITIONAL;
|
||||
else error("%s line %d: bad section %s", name, lineno, parse);
|
||||
} else if(str_keyword(&parse, "ENTRY_END")) {
|
||||
current = 0;
|
||||
entry_num ++;
|
||||
} else {
|
||||
/* it must be a RR, parse and add to packet. */
|
||||
ldns_rr* n = NULL;
|
||||
ldns_status status;
|
||||
status = ldns_rr_new_frm_str(&n, parse, default_ttl, origin, &prev_rr);
|
||||
if (status != LDNS_STATUS_OK)
|
||||
error("%s line %d:\n\t%s: %s", name, lineno,
|
||||
ldns_get_errorstr_by_id(status), parse);
|
||||
ldns_pkt_push_rr(cur_reply->reply, add_section, n);
|
||||
}
|
||||
|
||||
}
|
||||
log_msg("Read %d entries\n", entry_num);
|
||||
|
||||
fclose(in);
|
||||
return list;
|
||||
}
|
||||
|
||||
static ldns_rr_type get_qtype(ldns_pkt* p)
|
||||
{
|
||||
if(!ldns_rr_list_rr(ldns_pkt_question(p), 0))
|
||||
return 0;
|
||||
return ldns_rr_get_type(ldns_rr_list_rr(ldns_pkt_question(p), 0));
|
||||
}
|
||||
|
||||
static ldns_rdf* get_owner(ldns_pkt* p)
|
||||
{
|
||||
if(!ldns_rr_list_rr(ldns_pkt_question(p), 0))
|
||||
return NULL;
|
||||
return ldns_rr_owner(ldns_rr_list_rr(ldns_pkt_question(p), 0));
|
||||
}
|
||||
|
||||
static uint32_t get_serial(ldns_pkt* p)
|
||||
{
|
||||
/* get authority section SOA serial value */
|
||||
ldns_rr *rr = ldns_rr_list_rr(ldns_pkt_authority(p), 0);
|
||||
ldns_rdf *rdf;
|
||||
uint32_t val;
|
||||
if(!rr) return 0;
|
||||
rdf = ldns_rr_rdf(rr, 2);
|
||||
if(!rdf) return 0;
|
||||
val = ldns_rdf2native_int32(rdf);
|
||||
if(verbose) log_msg("found serial %u in msg. ", (int)val);
|
||||
return val;
|
||||
}
|
||||
|
||||
/* finds entry in list, or returns NULL */
|
||||
static struct entry* find_match(struct entry* entries, ldns_pkt* query_pkt,
|
||||
enum transport_type transport)
|
||||
{
|
||||
struct entry* p = entries;
|
||||
ldns_pkt* reply = NULL;
|
||||
for(p=entries; p; p=p->next) {
|
||||
if(verbose) log_msg("comparepkt: ");
|
||||
reply = p->reply_list->reply;
|
||||
if(p->match_opcode && ldns_pkt_get_opcode(query_pkt) !=
|
||||
ldns_pkt_get_opcode(reply)) {
|
||||
if(verbose) log_msg("bad opcode\n");
|
||||
continue;
|
||||
}
|
||||
if(p->match_qtype && get_qtype(query_pkt) != get_qtype(reply)) {
|
||||
if(verbose) log_msg("bad qtype\n");
|
||||
continue;
|
||||
}
|
||||
if(p->match_qname) {
|
||||
if(!get_owner(query_pkt) || !get_owner(reply) ||
|
||||
ldns_dname_compare(
|
||||
get_owner(query_pkt), get_owner(reply)) != 0) {
|
||||
if(verbose) log_msg("bad qname\n");
|
||||
continue;
|
||||
}
|
||||
}
|
||||
if(p->match_serial && get_serial(query_pkt) != p->ixfr_soa_serial) {
|
||||
if(verbose) log_msg("bad serial\n");
|
||||
continue;
|
||||
}
|
||||
if(p->match_transport != transport_any && p->match_transport != transport) {
|
||||
if(verbose) log_msg("bad transport\n");
|
||||
continue;
|
||||
}
|
||||
if(verbose) log_msg("match!\n");
|
||||
return p;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void
|
||||
adjust_packet(struct entry* match, ldns_pkt* answer_pkt, ldns_pkt* query_pkt)
|
||||
{
|
||||
/* copy & adjust packet */
|
||||
if(match->copy_id)
|
||||
ldns_pkt_set_id(answer_pkt, ldns_pkt_id(query_pkt));
|
||||
if(match->sleeptime > 0) {
|
||||
if(verbose) log_msg("sleeping for %d seconds\n", match->sleeptime);
|
||||
sleep(match->sleeptime);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Parses data buffer to a query, finds the correct answer
|
||||
* and calls the given function for every packet to send.
|
||||
*/
|
||||
static void
|
||||
handle_query(uint8_t* inbuf, ssize_t inlen, struct entry* entries, int* count,
|
||||
enum transport_type transport, void (*sendfunc)(uint8_t*, size_t, void*),
|
||||
void* userdata)
|
||||
{
|
||||
ldns_status status;
|
||||
ldns_pkt *query_pkt = NULL;
|
||||
ldns_pkt *answer_pkt = NULL;
|
||||
struct reply_packet *p;
|
||||
ldns_rr *query_rr = NULL;
|
||||
uint8_t *outbuf = NULL;
|
||||
size_t answer_size = 0;
|
||||
struct entry* entry = NULL;
|
||||
|
||||
status = ldns_wire2pkt(&query_pkt, inbuf, (size_t)inlen);
|
||||
if (status != LDNS_STATUS_OK) {
|
||||
log_msg("Got bad packet: %s\n", ldns_get_errorstr_by_id(status));
|
||||
return;
|
||||
}
|
||||
|
||||
query_rr = ldns_rr_list_rr(ldns_pkt_question(query_pkt), 0);
|
||||
log_msg("query %d: id %d: %s %d bytes: ", ++(*count), (int)ldns_pkt_id(query_pkt),
|
||||
(transport==transport_tcp)?"TCP":"UDP", inlen);
|
||||
ldns_rr_print(logfile, query_rr);
|
||||
if(verbose) ldns_pkt_print(logfile, query_pkt);
|
||||
|
||||
/* fill up answer packet */
|
||||
entry = find_match(entries, query_pkt, transport);
|
||||
if(!entry || !entry->reply_list) {
|
||||
log_msg("no answer packet for this query, no reply.\n");
|
||||
ldns_pkt_free(query_pkt);
|
||||
return;
|
||||
}
|
||||
for(p = entry->reply_list; p; p = p->next)
|
||||
{
|
||||
if(verbose) log_msg("Answer pkt:\n");
|
||||
answer_pkt = ldns_pkt_clone(p->reply);
|
||||
adjust_packet(entry, answer_pkt, query_pkt);
|
||||
if(verbose) ldns_pkt_print(logfile, answer_pkt);
|
||||
status = ldns_pkt2wire(&outbuf, answer_pkt, &answer_size);
|
||||
log_msg("Answer packet size: %u bytes.\n", (unsigned int)answer_size);
|
||||
if (status != LDNS_STATUS_OK) {
|
||||
log_msg("Error creating answer: %s\n", ldns_get_errorstr_by_id(status));
|
||||
ldns_pkt_free(query_pkt);
|
||||
return;
|
||||
}
|
||||
ldns_pkt_free(answer_pkt);
|
||||
answer_pkt = NULL;
|
||||
|
||||
if(p->packet_sleep) {
|
||||
if(verbose) log_msg("sleeping for next packet"
|
||||
" %d secs\n", p->packet_sleep);
|
||||
sleep(p->packet_sleep);
|
||||
if(verbose) log_msg("wakeup for next packet "
|
||||
"(slept %d secs)\n", p->packet_sleep);
|
||||
}
|
||||
sendfunc(outbuf, answer_size, userdata);
|
||||
LDNS_FREE(outbuf);
|
||||
outbuf = NULL;
|
||||
answer_size = 0;
|
||||
}
|
||||
ldns_pkt_free(query_pkt);
|
||||
}
|
||||
|
||||
struct handle_udp_userdata {
|
||||
int udp_sock;
|
||||
struct sockaddr_storage addr_him;
|
||||
socklen_t hislen;
|
||||
};
|
||||
static void
|
||||
send_udp(uint8_t* buf, size_t len, void* data)
|
||||
{
|
||||
struct handle_udp_userdata *userdata = (struct handle_udp_userdata*)data;
|
||||
/* udp send reply */
|
||||
ssize_t nb;
|
||||
nb = sendto(userdata->udp_sock, buf, len, 0,
|
||||
(struct sockaddr*)&userdata->addr_him, userdata->hislen);
|
||||
if(nb == -1)
|
||||
log_msg("sendto(): %s\n", strerror(errno));
|
||||
else if((size_t)nb != len)
|
||||
log_msg("sendto(): only sent %d of %d octets.\n",
|
||||
(int)nb, (int)len);
|
||||
}
|
||||
|
||||
static void
|
||||
handle_udp(int udp_sock, struct entry* entries, int *count)
|
||||
{
|
||||
ssize_t nb;
|
||||
uint8_t inbuf[INBUF_SIZE];
|
||||
struct handle_udp_userdata userdata;
|
||||
userdata.udp_sock = udp_sock;
|
||||
|
||||
userdata.hislen = (socklen_t)sizeof(userdata.addr_him);
|
||||
/* udp recv */
|
||||
nb = recvfrom(udp_sock, inbuf, INBUF_SIZE, 0,
|
||||
(struct sockaddr*)&userdata.addr_him, &userdata.hislen);
|
||||
if (nb < 1) {
|
||||
log_msg("recvfrom(): %s\n", strerror(errno));
|
||||
return;
|
||||
}
|
||||
handle_query(inbuf, nb, entries, count, transport_udp, send_udp, &userdata);
|
||||
}
|
||||
|
||||
static void
|
||||
read_n_bytes(int sock, uint8_t* buf, size_t sz)
|
||||
{
|
||||
size_t count = 0;
|
||||
while(count < sz) {
|
||||
ssize_t nb = read(sock, buf+count, sz-count);
|
||||
if(nb < 0) {
|
||||
log_msg("read(): %s\n", strerror(errno));
|
||||
return;
|
||||
}
|
||||
count += nb;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
write_n_bytes(int sock, uint8_t* buf, size_t sz)
|
||||
{
|
||||
size_t count = 0;
|
||||
while(count < sz) {
|
||||
ssize_t nb = write(sock, buf+count, sz-count);
|
||||
if(nb < 0) {
|
||||
log_msg("write(): %s\n", strerror(errno));
|
||||
return;
|
||||
}
|
||||
count += nb;
|
||||
}
|
||||
}
|
||||
|
||||
struct handle_tcp_userdata {
|
||||
int s;
|
||||
};
|
||||
static void
|
||||
send_tcp(uint8_t* buf, size_t len, void* data)
|
||||
{
|
||||
struct handle_tcp_userdata *userdata = (struct handle_tcp_userdata*)data;
|
||||
uint16_t tcplen;
|
||||
/* tcp send reply */
|
||||
tcplen = htons(len);
|
||||
write_n_bytes(userdata->s, (uint8_t*)&tcplen, sizeof(tcplen));
|
||||
write_n_bytes(userdata->s, buf, len);
|
||||
}
|
||||
|
||||
static void
|
||||
handle_tcp(int tcp_sock, struct entry* entries, int *count)
|
||||
{
|
||||
int s;
|
||||
struct sockaddr_storage addr_him;
|
||||
socklen_t hislen;
|
||||
uint8_t inbuf[INBUF_SIZE];
|
||||
uint16_t tcplen;
|
||||
struct handle_tcp_userdata userdata;
|
||||
|
||||
/* accept */
|
||||
hislen = (socklen_t)sizeof(addr_him);
|
||||
if((s = accept(tcp_sock, (struct sockaddr*)&addr_him, &hislen)) < 0) {
|
||||
log_msg("accept(): %s\n", strerror(errno));
|
||||
return;
|
||||
}
|
||||
userdata.s = s;
|
||||
|
||||
/* tcp recv */
|
||||
read_n_bytes(s, (uint8_t*)&tcplen, sizeof(tcplen));
|
||||
tcplen = ntohs(tcplen);
|
||||
if(tcplen >= INBUF_SIZE) {
|
||||
log_msg("query %d bytes too large, buffer %d bytes.\n",
|
||||
tcplen, INBUF_SIZE);
|
||||
close(s);
|
||||
return;
|
||||
}
|
||||
read_n_bytes(s, inbuf, tcplen);
|
||||
|
||||
handle_query(inbuf, tcplen, entries, count, transport_tcp, send_tcp, &userdata);
|
||||
close(s);
|
||||
|
||||
}
|
||||
|
||||
int
|
||||
main(int argc, char **argv)
|
||||
{
|
||||
/* arguments */
|
||||
int c;
|
||||
int port = DEFAULT_PORT;
|
||||
const char* datafile;
|
||||
int count;
|
||||
|
||||
/* network */
|
||||
int udp_sock, tcp_sock;
|
||||
fd_set rset, wset, eset;
|
||||
struct timeval timeout;
|
||||
int maxfd;
|
||||
|
||||
/* dns */
|
||||
struct entry* entries;
|
||||
|
||||
/* parse arguments */
|
||||
logfile = stdout;
|
||||
prog_name = argv[0];
|
||||
log_msg("%s: start\n", prog_name);
|
||||
while((c = getopt(argc, argv, "p:v")) != -1) {
|
||||
switch(c) {
|
||||
case 'p':
|
||||
port = atoi(optarg);
|
||||
if (port < 1) {
|
||||
error("Invalid port %s, use a number.", optarg);
|
||||
}
|
||||
break;
|
||||
case 'v':
|
||||
verbose++;
|
||||
break;
|
||||
default:
|
||||
usage();
|
||||
break;
|
||||
}
|
||||
}
|
||||
argc -= optind;
|
||||
argv += optind;
|
||||
|
||||
if(argc == 0 || argc > 1)
|
||||
usage();
|
||||
|
||||
datafile = argv[0];
|
||||
log_msg("Reading datafile %s\n", datafile);
|
||||
entries = read_datafile(datafile);
|
||||
|
||||
log_msg("Listening on port %d\n", port);
|
||||
if((udp_sock = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
|
||||
error("udp socket(): %s\n", strerror(errno));
|
||||
}
|
||||
if((tcp_sock = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
|
||||
error("tcp socket(): %s\n", strerror(errno));
|
||||
}
|
||||
c = 1;
|
||||
if(setsockopt(tcp_sock, SOL_SOCKET, SO_REUSEADDR, &c, sizeof(int)) < 0) {
|
||||
error("setsockopt(SO_REUSEADDR): %s\n", strerror(errno));
|
||||
}
|
||||
|
||||
/* bind ip4 */
|
||||
if (bind_port(udp_sock, port)) {
|
||||
error("cannot bind(): %s\n", strerror(errno));
|
||||
}
|
||||
if (bind_port(tcp_sock, port)) {
|
||||
error("cannot bind(): %s\n", strerror(errno));
|
||||
}
|
||||
if (listen(tcp_sock, CONN_BACKLOG) < 0) {
|
||||
error("listen(): %s\n", strerror(errno));
|
||||
}
|
||||
|
||||
/* service */
|
||||
count = 0;
|
||||
timeout.tv_sec = 0;
|
||||
timeout.tv_usec = 0;
|
||||
while (1) {
|
||||
FD_ZERO(&rset);
|
||||
FD_ZERO(&wset);
|
||||
FD_ZERO(&eset);
|
||||
FD_SET(udp_sock, &rset);
|
||||
FD_SET(tcp_sock, &rset);
|
||||
maxfd = udp_sock;
|
||||
if(tcp_sock > maxfd)
|
||||
maxfd = tcp_sock;
|
||||
if(select(maxfd+1, &rset, &wset, &eset, NULL) < 0) {
|
||||
error("select(): %s\n", strerror(errno));
|
||||
}
|
||||
if(FD_ISSET(udp_sock, &rset)) {
|
||||
handle_udp(udp_sock, entries, &count);
|
||||
}
|
||||
if(FD_ISSET(tcp_sock, &rset)) {
|
||||
handle_tcp(tcp_sock, entries, &count);
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
196
zonemaster-ldns/ldns/examples/nsd-test/nsd-ldnsd.c
Normal file
196
zonemaster-ldns/ldns/examples/nsd-test/nsd-ldnsd.c
Normal file
@@ -0,0 +1,196 @@
|
||||
/*
|
||||
* nsd-ldnsd. Light-weight DNS daemon, which sends IXFRs
|
||||
*
|
||||
* Tiny dns server to show how a real one could be built.
|
||||
* This version is used for NSD test, send out IXFR's only.
|
||||
*
|
||||
* (c) NLnet Labs, 2005, 2006
|
||||
* See the file LICENSE for the license
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
#include <ldns/ldns.h>
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <sys/socket.h>
|
||||
|
||||
#include <arpa/inet.h>
|
||||
#include <netinet/in.h>
|
||||
#include <netinet/udp.h>
|
||||
#include <netinet/igmp.h>
|
||||
#include <errno.h>
|
||||
|
||||
#define INBUF_SIZE 4096
|
||||
#define MAX_LEN 1024
|
||||
|
||||
void usage(FILE *output)
|
||||
{
|
||||
fprintf(output, "Usage: nsd-ldnsd -# <port> <zone> <soa-serial>\n");
|
||||
fprintf(output, "Listens on the specified port and answer every query with an IXFR\n");
|
||||
fprintf(output, "This is NOT a full-fledged authoritative nameserver! It is NOTHING.\n");
|
||||
fprintf(output, "-# quit after this many queries.\n");
|
||||
}
|
||||
|
||||
static int udp_bind(int sock, int port, const char *my_address)
|
||||
{
|
||||
struct sockaddr_in addr;
|
||||
|
||||
addr.sin_family = AF_INET;
|
||||
addr.sin_port = (in_port_t)htons((uint16_t)port);
|
||||
addr.sin_addr.s_addr = INADDR_ANY;
|
||||
return bind(sock, (struct sockaddr *)&addr, (socklen_t) sizeof(addr));
|
||||
}
|
||||
|
||||
int
|
||||
main(int argc, char **argv)
|
||||
{
|
||||
/* arguments */
|
||||
int port;
|
||||
int soa;
|
||||
ldns_rdf *zone_name;
|
||||
size_t count;
|
||||
size_t maxcount;
|
||||
|
||||
/* network */
|
||||
int sock;
|
||||
ssize_t nb;
|
||||
struct sockaddr addr_me;
|
||||
struct sockaddr addr_him;
|
||||
socklen_t hislen = sizeof(addr_him);
|
||||
const char *my_address;
|
||||
uint8_t inbuf[INBUF_SIZE];
|
||||
uint8_t *outbuf;
|
||||
|
||||
/* dns */
|
||||
ldns_status status;
|
||||
ldns_pkt *query_pkt;
|
||||
ldns_pkt *answer_pkt;
|
||||
size_t answer_size;
|
||||
ldns_rr *query_rr;
|
||||
ldns_rr *rr;
|
||||
char rr_string[MAX_LEN + 1];
|
||||
ldns_rr *soa_rr;
|
||||
char soa_string[MAX_LEN + 1];
|
||||
|
||||
/* use this to listen on specified interfaces later? */
|
||||
my_address = NULL;
|
||||
|
||||
if(argc == 5) {
|
||||
/* -# num given */
|
||||
if (argv[1][0] == '-') {
|
||||
maxcount = atoi(argv[1] + 1);
|
||||
if (maxcount == 0) {
|
||||
usage(stdout);
|
||||
exit(EXIT_FAILURE);
|
||||
} else {
|
||||
fprintf(stderr, "quitting after %d qs\n", (int)maxcount);
|
||||
}
|
||||
} else {
|
||||
fprintf(stderr, "Use -Number for max count\n");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
argc--;
|
||||
argv++;
|
||||
} else {
|
||||
maxcount = 0;
|
||||
}
|
||||
|
||||
if (argc != 4) {
|
||||
usage(stdout);
|
||||
exit(EXIT_FAILURE);
|
||||
} else {
|
||||
port = atoi(argv[1]);
|
||||
if (port < 1) {
|
||||
fprintf(stderr, "Use a number for the port\n");
|
||||
usage(stdout);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
zone_name = ldns_dname_new_frm_str(argv[2]);
|
||||
if (!zone_name) {
|
||||
fprintf(stderr, "Illegal domain name: %s\n", argv[2]);
|
||||
usage(stdout);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
soa = atoi(argv[3]);
|
||||
if (soa < 1) {
|
||||
fprintf(stderr, "Illegal soa number\n");
|
||||
usage(stdout);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
printf("Listening on port %d\n", port);
|
||||
sock = socket(AF_INET, SOCK_DGRAM, 0);
|
||||
if (sock < 0) {
|
||||
fprintf(stderr, "%s: socket(): %s\n", argv[0], strerror(errno));
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
memset(&addr_me, 0, sizeof(addr_me));
|
||||
|
||||
/* bind: try all ports in that range */
|
||||
if (udp_bind(sock, port, my_address)) {
|
||||
fprintf(stderr, "%s: cannot bind(): %s\n", argv[0], strerror(errno));
|
||||
}
|
||||
|
||||
/* create our ixfr answer */
|
||||
answer_pkt = ldns_pkt_new();
|
||||
|
||||
snprintf(rr_string, MAX_LEN, "%s IN IXFR", argv[2]);
|
||||
(void)ldns_rr_new_frm_str(&rr, rr_string , 0, NULL, NULL);
|
||||
(void)ldns_pkt_push_rr(answer_pkt, LDNS_SECTION_QUESTION, rr);
|
||||
|
||||
/* next add some rrs, with SOA stuff so that we mimic or ixfr reply */
|
||||
snprintf(soa_string, MAX_LEN, "%s IN SOA miek.miek.nl elektron.atoom.net %d 1 2 3000 4",
|
||||
argv[2], soa);
|
||||
|
||||
(void)ldns_rr_new_frm_str(&soa_rr, soa_string, 0, NULL, NULL);
|
||||
snprintf(rr_string, MAX_LEN, "%s IN A 127.0.0.1", argv[2]);
|
||||
(void)ldns_rr_new_frm_str(&rr, rr_string , 0, NULL, NULL);
|
||||
|
||||
/* compose the ixfr pkt */
|
||||
(void)ldns_pkt_push_rr(answer_pkt, LDNS_SECTION_ANSWER, soa_rr);
|
||||
(void)ldns_pkt_push_rr(answer_pkt, LDNS_SECTION_ANSWER, rr);
|
||||
(void)ldns_pkt_push_rr(answer_pkt, LDNS_SECTION_ANSWER, soa_rr);
|
||||
|
||||
/* Done. Now receive */
|
||||
count = 0;
|
||||
while (1) {
|
||||
nb = recvfrom(sock, inbuf, INBUF_SIZE, 0, &addr_him, &hislen);
|
||||
if (nb < 1) {
|
||||
fprintf(stderr, "%s: recvfrom(): %s\n",
|
||||
argv[0], strerror(errno));
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
printf("Got query of %d bytes\n", (int)nb);
|
||||
status = ldns_wire2pkt(&query_pkt, inbuf, nb);
|
||||
if (status != LDNS_STATUS_OK) {
|
||||
printf("Got bad packet: %s\n", ldns_get_errorstr_by_id(status));
|
||||
continue;
|
||||
}
|
||||
|
||||
query_rr = ldns_rr_list_rr(ldns_pkt_question(query_pkt), 0);
|
||||
printf("%d QUERY RR +%d: \n", (int)++count, ldns_pkt_id(query_pkt));
|
||||
ldns_rr_print(stdout, query_rr);
|
||||
|
||||
ldns_pkt_set_id(answer_pkt, ldns_pkt_id(query_pkt));
|
||||
|
||||
status = ldns_pkt2wire(&outbuf, answer_pkt, &answer_size);
|
||||
|
||||
printf("Answer packet size: %u bytes.\n", (unsigned int) answer_size);
|
||||
if (status != LDNS_STATUS_OK) {
|
||||
printf("Error creating answer: %s\n", ldns_get_errorstr_by_id(status));
|
||||
} else {
|
||||
nb = (size_t) sendto(sock, outbuf, answer_size, 0, &addr_him, hislen);
|
||||
}
|
||||
|
||||
if (maxcount > 0 && count >= maxcount) {
|
||||
fprintf(stderr, "%d queries seen... goodbye\n", (int)count);
|
||||
exit(EXIT_SUCCESS);
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
188
zonemaster-ldns/ldns/examples/nsd-test/nsec3-covers.c
Normal file
188
zonemaster-ldns/ldns/examples/nsd-test/nsec3-covers.c
Normal file
@@ -0,0 +1,188 @@
|
||||
/*
|
||||
* nsec3-covers. Parses NSEC3s from drill and shows what is covered.
|
||||
*
|
||||
* Pipe the output of the dig/drill query with NSEC3s to the tool.
|
||||
* It will print which domain names are covered by NSEC3s.
|
||||
*
|
||||
* (c) NLnet Labs, 2005, 2006
|
||||
* See the file LICENSE for the license
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
#include <ldns/ldns.h>
|
||||
#include <errno.h>
|
||||
|
||||
void usage(FILE *output)
|
||||
{
|
||||
fprintf(output, "Usage: dig +dnssec <query> | nsec3-covers or\n"
|
||||
"drill -D <query> | nsec3-covers\n");
|
||||
}
|
||||
|
||||
void abort_ldns_error(const char* str, ldns_status err)
|
||||
{
|
||||
fprintf(stderr, "error: %s: %s\n", str, ldns_get_errorstr_by_id(err));
|
||||
exit(1);
|
||||
}
|
||||
|
||||
char*
|
||||
skip_comments_and_query(FILE* in, ldns_rdf ** qname)
|
||||
{
|
||||
static char buf[10240];
|
||||
/* read comment lines */
|
||||
while(1) {
|
||||
if(!fgets(buf, sizeof(buf), in))
|
||||
return 0; /* EOF */
|
||||
printf("%s", buf); /* echo */
|
||||
if(strcmp(buf, "") == 0 || strcmp(buf, "\n") == 0)
|
||||
continue;
|
||||
if(buf[0] != ';')
|
||||
break;
|
||||
if(strncmp(buf, ";; QUESTION SECTION:", 20) == 0)
|
||||
{
|
||||
char *q_rr = buf;
|
||||
/* read question on next line, ;;s before */
|
||||
if(!fgets(buf, sizeof(buf), in)) return 0;
|
||||
while(*q_rr == ';' || *q_rr == ' ' || *q_rr == '\t')
|
||||
++q_rr;
|
||||
printf("Question: %s", q_rr);
|
||||
*strchr(q_rr, '\t') = 0;
|
||||
*qname = ldns_dname_new_frm_str(q_rr);
|
||||
}
|
||||
}
|
||||
return buf;
|
||||
}
|
||||
|
||||
void
|
||||
read_in(ldns_rr_list* list, ldns_rdf** qname, FILE *in)
|
||||
{
|
||||
char* buf;
|
||||
while((buf=skip_comments_and_query(in, qname)))
|
||||
{
|
||||
/* add rr */
|
||||
ldns_rr *rr=0;
|
||||
ldns_rdf *origin=0, *prev=0;
|
||||
ldns_status err;
|
||||
uint16_t ttl = 3600;
|
||||
if((err=ldns_rr_new_frm_str(&rr, buf, ttl, origin, &prev)) !=
|
||||
LDNS_STATUS_OK)
|
||||
abort_ldns_error("read rr", err);
|
||||
ldns_rr_list_push_rr(list, rr);
|
||||
}
|
||||
printf("nsec3-covers: read %d rrs\n", (int)ldns_rr_list_rr_count(list));
|
||||
if(!qname) {
|
||||
printf("Could not read question name\n");
|
||||
exit(1);
|
||||
}
|
||||
printf("nsec3-covers: qname is ");
|
||||
ldns_rdf_print(stdout, *qname);
|
||||
printf("\n");
|
||||
}
|
||||
|
||||
struct donelist {
|
||||
ldns_rdf* name;
|
||||
struct donelist* next;
|
||||
};
|
||||
static struct donelist *done = 0;
|
||||
|
||||
/* this is a linear speed test (slow for large numbers).
|
||||
but the dig response will be small anyway. */
|
||||
int check_done(ldns_rdf *qname)
|
||||
{
|
||||
struct donelist* p = done;
|
||||
while(p) {
|
||||
if(ldns_dname_compare(qname, p->name)==0)
|
||||
return 1;
|
||||
p = p->next;
|
||||
}
|
||||
/* not done yet add to list */
|
||||
p = (struct donelist*)malloc(sizeof(struct donelist));
|
||||
p->name = qname;
|
||||
p->next = done;
|
||||
done = p;
|
||||
return 0;
|
||||
}
|
||||
|
||||
void
|
||||
check_cover(ldns_rr_list *list, ldns_rdf *qname)
|
||||
{
|
||||
ldns_status status;
|
||||
size_t i;
|
||||
if(check_done(qname))
|
||||
return;
|
||||
for(i=0; i<ldns_rr_list_rr_count(list); ++i)
|
||||
{
|
||||
ldns_rr* nsec3 = ldns_rr_list_rr(list, i);
|
||||
if(ldns_rr_get_type(nsec3) != LDNS_RR_TYPE_NSEC3) {
|
||||
/* skip non nsec3 */
|
||||
continue;
|
||||
}
|
||||
ldns_rdf* hashed = ldns_nsec3_hash_name_frm_nsec3(
|
||||
nsec3, qname);
|
||||
status = ldns_dname_cat(hashed, ldns_dname_left_chop(
|
||||
ldns_rr_owner(nsec3)));
|
||||
if(status != LDNS_STATUS_OK)
|
||||
abort_ldns_error("ldns_dname_cat", status);
|
||||
|
||||
if(ldns_dname_compare(hashed, ldns_rr_owner(nsec3)) == 0) {
|
||||
ldns_rdf_print(stdout, ldns_rr_owner(nsec3));
|
||||
printf(" proves ");
|
||||
ldns_rdf_print(stdout, qname);
|
||||
printf(" exists.\n");
|
||||
}
|
||||
else if(ldns_nsec_covers_name(nsec3, hashed)) {
|
||||
ldns_rdf_print(stdout, ldns_rr_owner(nsec3));
|
||||
printf(" proves ");
|
||||
ldns_rdf_print(stdout, qname);
|
||||
printf(" does not exist.\n");
|
||||
}
|
||||
ldns_rdf_free(hashed);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
covertests(ldns_rr_list *list, ldns_rdf *qname)
|
||||
{
|
||||
size_t i;
|
||||
ldns_rdf *smaller = qname;
|
||||
ldns_rdf *wcard = ldns_dname_new_frm_str("*");
|
||||
for(i=0; i<ldns_dname_label_count(qname)+1; ++i)
|
||||
{
|
||||
check_cover(list, smaller);
|
||||
ldns_rdf* wcardchild = ldns_dname_cat_clone(wcard, smaller);
|
||||
check_cover(list, wcardchild);
|
||||
smaller = ldns_dname_left_chop(smaller);
|
||||
}
|
||||
/* check covers by weird names */
|
||||
if(0) {
|
||||
check_cover(list, ldns_dname_new_frm_str("x.bar.example."));
|
||||
check_cover(list, ldns_dname_new_frm_str("bar.example."));
|
||||
}
|
||||
}
|
||||
|
||||
int
|
||||
main(int argc, char **argv)
|
||||
{
|
||||
size_t i;
|
||||
if(argc != 1) {
|
||||
usage(stderr);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* read in */
|
||||
ldns_rr_list *list = ldns_rr_list_new();
|
||||
ldns_rdf *qname = 0;
|
||||
read_in(list, &qname, stdin);
|
||||
|
||||
/* check covers */
|
||||
covertests(list, qname);
|
||||
for(i=0; i<ldns_rr_list_rr_count(list); ++i)
|
||||
{
|
||||
ldns_rr* rr = ldns_rr_list_rr(list, i);
|
||||
if(!ldns_dname_is_subdomain(qname, ldns_rr_owner(rr))) {
|
||||
covertests(list, ldns_rr_owner(rr));
|
||||
}
|
||||
}
|
||||
|
||||
ldns_rr_list_deep_free(list);
|
||||
return 0;
|
||||
}
|
||||
77
zonemaster-ldns/ldns/examples/nsd-test/test.queries
Normal file
77
zonemaster-ldns/ldns/examples/nsd-test/test.queries
Normal file
@@ -0,0 +1,77 @@
|
||||
# comment at start.
|
||||
; Test queries for ldns-testns.
|
||||
; This is a line based format config file.
|
||||
|
||||
$ORIGIN example.com
|
||||
$TTL 3600
|
||||
|
||||
# Below are the entries, they are tested for a match one by one.
|
||||
# enclose each in ENTRY_BEGIN and ENTRY_END.
|
||||
ENTRY_BEGIN
|
||||
# MATCH makes sure the query and answer match on:
|
||||
MATCH opcode qtype qname ; for default queries
|
||||
# or you can match on a specific value.
|
||||
; MATCH serial=1024 ; for this query also match SOA serial.
|
||||
; MATCH UDP ; query must be by udp.
|
||||
#
|
||||
# REPLY lines give header info for the reply:
|
||||
# (opcode) QUERY IQUERY STATUS NOTIFY UPDATE
|
||||
# (rcode) NOERROR FORMERR SERVFAIL NXDOMAIN NOTIMPL YXDOMAIN
|
||||
# YXRRSET NXRRSET NOTAUTH NOTZONE
|
||||
# (flags) QR AA TC RD CD RA AD
|
||||
REPLY QR ; this is a query reply.
|
||||
# ADJUST: runtime modifications to the reply. usually copy_id.
|
||||
ADJUST copy_id
|
||||
# add RRs to a section, QUESTION ANSWER AUTHORITY ADDITIONAL
|
||||
SECTION QUESTION
|
||||
# RRs, (an RR must be on a single line).
|
||||
@ IN A
|
||||
SECTION ANSWER
|
||||
@ A 192.168.0.123
|
||||
@ TXT "This record is unexpected."
|
||||
SECTION ADDITIONAL
|
||||
@ A 192.1.2.3
|
||||
ENTRY_END
|
||||
|
||||
ENTRY_BEGIN
|
||||
MATCH TCP opcode qname
|
||||
ADJUST copy_id
|
||||
SECTION QUESTION
|
||||
axfr.example.com. IN AXFR
|
||||
SECTION ANSWER
|
||||
axfr.example.com. IN SOA a. b. 10 60 60 60 60 60
|
||||
bla.axfr.example.com. IN TXT "bla"
|
||||
EXTRA_PACKET
|
||||
ADJUST packet_sleep=4
|
||||
SECTION ANSWER
|
||||
bla.axfr.example.com. IN TXT "bla2"
|
||||
axfr.example.com. IN SOA a. b. 10 60 60 60 60 60
|
||||
ENTRY_END
|
||||
|
||||
ENTRY_BEGIN
|
||||
MATCH TCP
|
||||
REPLY SERVFAIL
|
||||
ADJUST copy_id
|
||||
ldns.testns.example. TXT "The ldnstestns server handled your TCP request"
|
||||
ENTRY_END
|
||||
|
||||
ENTRY_BEGIN
|
||||
MATCH opcode qtype qname
|
||||
MATCH serial=102
|
||||
ADJUST copy_id
|
||||
REPLY QR AA
|
||||
SECTION QUESTION
|
||||
example.net. IXFR
|
||||
SECTION ANSWER
|
||||
example.net. SOA ns1.example.net. . 0 103 0 0 0
|
||||
ENTRY_END
|
||||
|
||||
ENTRY_BEGIN
|
||||
; Keep this as the last entry.
|
||||
; matches anything and returns this packet.
|
||||
; so you will get an answer for every query.
|
||||
REPLY SERVFAIL
|
||||
ADJUST copy_id
|
||||
ldns.testns.example. TXT "The ldnstestns server did not find a match for your query"
|
||||
ENTRY_END
|
||||
|
||||
Reference in New Issue
Block a user