1/*
2 * Copyright (C) 2009  Internet Systems Consortium, Inc. ("ISC")
3 *
4 * Permission to use, copy, modify, and/or distribute this software for any
5 * purpose with or without fee is hereby granted, provided that the above
6 * copyright notice and this permission notice appear in all copies.
7 *
8 * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
9 * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
10 * AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
11 * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
12 * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
13 * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
14 * PERFORMANCE OF THIS SOFTWARE.
15 */
16
17/* $Id: sample-request.c,v 1.5 2009/09/29 15:06:07 fdupont Exp $ */
18
19#include <config.h>
20
21#include <sys/types.h>
22#include <sys/socket.h>
23
24#include <netinet/in.h>
25
26#include <arpa/inet.h>
27
28#include <unistd.h>
29#include <stdio.h>
30#include <stdlib.h>
31#include <string.h>
32#include <netdb.h>
33
34#include <isc/base64.h>
35#include <isc/buffer.h>
36#include <isc/lib.h>
37#include <isc/mem.h>
38#include <isc/sockaddr.h>
39#include <isc/util.h>
40
41#include <dns/client.h>
42#include <dns/fixedname.h>
43#include <dns/keyvalues.h>
44#include <dns/lib.h>
45#include <dns/masterdump.h>
46#include <dns/message.h>
47#include <dns/name.h>
48#include <dns/rdata.h>
49#include <dns/rdataset.h>
50#include <dns/rdatastruct.h>
51#include <dns/rdatatype.h>
52#include <dns/result.h>
53#include <dns/secalg.h>
54
55#include <dst/dst.h>
56
57static isc_mem_t *mctx;
58static dns_fixedname_t fixedqname;
59
60ISC_PLATFORM_NORETURN_PRE static void
61usage(void) ISC_PLATFORM_NORETURN_POST;
62
63static void
64usage(void) {
65	fprintf(stderr, "sample-request [-t RRtype] server_address hostname\n");
66
67	exit(1);
68}
69
70static isc_result_t
71make_querymessage(dns_message_t *message, const char *namestr,
72		  dns_rdatatype_t rdtype)
73{
74	dns_name_t *qname = NULL, *qname0;
75	dns_rdataset_t *qrdataset = NULL;
76	isc_result_t result;
77	isc_buffer_t b;
78	size_t namelen;
79
80	/* Construct qname */
81	namelen = strlen(namestr);
82	isc_buffer_init(&b, namestr, namelen);
83	isc_buffer_add(&b, namelen);
84	dns_fixedname_init(&fixedqname);
85	qname0 = dns_fixedname_name(&fixedqname);
86	result = dns_name_fromtext(qname0, &b, dns_rootname, 0, NULL);
87	if (result != ISC_R_SUCCESS) {
88		fprintf(stderr, "failed to convert qname: %d\n", result);
89		return (result);
90	}
91
92	/* Construct query message */
93	message->opcode = dns_opcode_query;
94	message->rdclass = dns_rdataclass_in;
95
96	result = dns_message_gettempname(message, &qname);
97	if (result != ISC_R_SUCCESS)
98		goto cleanup;
99
100	result = dns_message_gettemprdataset(message, &qrdataset);
101	if (result != ISC_R_SUCCESS)
102		goto cleanup;
103
104	dns_name_init(qname, NULL);
105	dns_name_clone(qname0, qname);
106	dns_rdataset_init(qrdataset);
107	dns_rdataset_makequestion(qrdataset, message->rdclass, rdtype);
108	ISC_LIST_APPEND(qname->list, qrdataset, link);
109	dns_message_addname(message, qname, DNS_SECTION_QUESTION);
110
111	return (ISC_R_SUCCESS);
112
113 cleanup:
114	if (qname != NULL)
115		dns_message_puttempname(message, &qname);
116	if (qrdataset != NULL)
117		dns_message_puttemprdataset(message, &qrdataset);
118	if (message != NULL)
119		dns_message_destroy(&message);
120	return (result);
121}
122
123static void
124print_section(dns_message_t *message, int section, isc_buffer_t *buf) {
125	isc_result_t result;
126	isc_region_t r;
127
128	result = dns_message_sectiontotext(message, section,
129					   &dns_master_style_full, 0, buf);
130	if (result != ISC_R_SUCCESS)
131		goto fail;
132
133	isc_buffer_usedregion(buf, &r);
134	printf("%.*s", (int)r.length, (char *)r.base);
135
136	return;
137
138 fail:
139	fprintf(stderr, "failed to convert a section\n");
140}
141
142int
143main(int argc, char *argv[]) {
144	int ch, i, gai_error;
145	struct addrinfo hints, *res;
146	isc_textregion_t tr;
147	dns_client_t *client = NULL;
148	isc_result_t result;
149	isc_sockaddr_t sa;
150	dns_message_t *qmessage, *rmessage;
151	dns_rdatatype_t type = dns_rdatatype_a;
152	isc_buffer_t *outputbuf;
153
154	while ((ch = getopt(argc, argv, "t:")) != -1) {
155		switch (ch) {
156		case 't':
157			tr.base = optarg;
158			tr.length = strlen(optarg);
159			result = dns_rdatatype_fromtext(&type, &tr);
160			if (result != ISC_R_SUCCESS) {
161				fprintf(stderr,
162					"invalid RRtype: %s\n", optarg);
163				exit(1);
164			}
165			break;
166		default:
167			usage();
168		}
169	}
170
171	argc -= optind;
172	argv += optind;
173	if (argc < 2)
174		usage();
175
176	isc_lib_register();
177	result = dns_lib_init();
178	if (result != ISC_R_SUCCESS) {
179		fprintf(stderr, "dns_lib_init failed: %d\n", result);
180		exit(1);
181	}
182
183	result = dns_client_create(&client, 0);
184	if (result != ISC_R_SUCCESS) {
185		fprintf(stderr, "dns_client_create failed: %d\n", result);
186		exit(1);
187	}
188
189	/* Prepare message structures */
190	mctx = NULL;
191	qmessage = NULL;
192	rmessage = NULL;
193
194	result = isc_mem_create(0, 0, &mctx);
195	if (result != ISC_R_SUCCESS) {
196		fprintf(stderr, "failed to create a memory context\n");
197		exit(1);
198	}
199	result = dns_message_create(mctx, DNS_MESSAGE_INTENTRENDER, &qmessage);
200	if (result == ISC_R_SUCCESS) {
201		result = dns_message_create(mctx, DNS_MESSAGE_INTENTPARSE,
202					    &rmessage);
203	}
204	if (result != ISC_R_SUCCESS) {
205		fprintf(stderr, "failed to create messages\n");
206		exit(1);
207	}
208
209	/* Initialize the nameserver address */
210	memset(&hints, 0, sizeof(hints));
211	hints.ai_family = AF_UNSPEC;
212	hints.ai_socktype = SOCK_DGRAM;
213	hints.ai_protocol = IPPROTO_UDP;
214	hints.ai_flags = AI_NUMERICHOST;
215	gai_error = getaddrinfo(argv[0], "53", &hints, &res);
216	if (gai_error != 0) {
217		fprintf(stderr, "getaddrinfo failed: %s\n",
218			gai_strerror(gai_error));
219		exit(1);
220	}
221	INSIST(res->ai_addrlen <= sizeof(sa.type));
222	memcpy(&sa.type, res->ai_addr, res->ai_addrlen);
223	freeaddrinfo(res);
224	sa.length = res->ai_addrlen;
225	ISC_LINK_INIT(&sa, link);
226
227	/* Construct qname */
228	result = make_querymessage(qmessage, argv[1], type);
229	if (result != ISC_R_SUCCESS) {
230		fprintf(stderr, "failed to create a query\n");
231		exit(1);
232	}
233
234	/* Send request and wait for a response */
235	result = dns_client_request(client, qmessage, rmessage, &sa, 0, 0,
236				    NULL, 60, 0, 3);
237	if (result != ISC_R_SUCCESS) {
238		fprintf(stderr, "failed to get a response: %s\n",
239			dns_result_totext(result));
240	}
241
242	/* Dump the response */
243	outputbuf = NULL;
244	result = isc_buffer_allocate(mctx, &outputbuf, 65535);
245	if (result != ISC_R_SUCCESS) {
246		fprintf(stderr, "failed to allocate a result buffer\n");
247		exit(1);
248	}
249	for (i = 0; i < DNS_SECTION_MAX; i++) {
250		print_section(rmessage, i, outputbuf);
251		isc_buffer_clear(outputbuf);
252	}
253	isc_buffer_free(&outputbuf);
254
255	/* Cleanup */
256	dns_message_destroy(&qmessage);
257	dns_message_destroy(&rmessage);
258	isc_mem_destroy(&mctx);
259	dns_client_destroy(&client);
260	dns_lib_shutdown();
261
262	exit(0);
263}
264