1/*
2 * util.c
3 * some handy function needed in drill and not implemented
4 * in ldns
5 * (c) 2005 NLnet Labs
6 *
7 * See the file LICENSE for the license
8 *
9 */
10
11#include "drill.h"
12#include <ldns/ldns.h>
13
14#include <errno.h>
15
16static int
17read_line(FILE *input, char *line, size_t len)
18{
19	int i;
20	int c;
21
22	for (i = 0; i < (int)len-1; i++) {
23		c = getc(input);
24		if (c == EOF) {
25			return -1;
26		} else if (c != '\n') {
27			line[i] = c;
28		} else {
29			break;
30		}
31	}
32	line[i] = '\0';
33	return i;
34}
35
36/* key_list must be initialized with ldns_rr_list_new() */
37ldns_status
38read_key_file(const char *filename, ldns_rr_list *key_list, bool silently)
39{
40	int line_len = 0;
41	int line_nr = 0;
42	int key_count = 0;
43	char line[LDNS_MAX_LINELEN];
44	ldns_status status;
45	FILE *input_file;
46	ldns_rr *rr;
47
48	input_file = fopen(filename, "r");
49	if (!input_file) {
50		if (! silently) {
51			fprintf(stderr, "Error opening %s: %s\n",
52				filename, strerror(errno));
53		}
54		return LDNS_STATUS_ERR;
55	}
56	while (line_len >= 0) {
57		line_len = (int) read_line(input_file, line, sizeof(line));
58		line_nr++;
59		if (line_len > 0 && line[0] != ';') {
60			status = ldns_rr_new_frm_str(&rr, line, 0, NULL, NULL);
61			if (status != LDNS_STATUS_OK) {
62				if (! silently) {
63					fprintf(stderr,
64						"Error parsing DNSKEY RR "
65						"in line %d: %s\n", line_nr,
66						ldns_get_errorstr_by_id(status)
67						);
68				}
69			} else if (ldns_rr_get_type(rr) == LDNS_RR_TYPE_DNSKEY ||
70					   ldns_rr_get_type(rr) == LDNS_RR_TYPE_DS) {
71				ldns_rr_list_push_rr(key_list, rr);
72				key_count++;
73			} else {
74				ldns_rr_free(rr);
75			}
76		}
77	}
78	fclose(input_file);
79	if (key_count > 0) {
80		return LDNS_STATUS_OK;
81	} else {
82		/*fprintf(stderr, "No keys read\n");*/
83		return LDNS_STATUS_ERR;
84	}
85}
86
87ldns_rdf *
88ldns_rdf_new_addr_frm_str(char *str)
89{
90	ldns_rdf *a;
91
92	a = ldns_rdf_new_frm_str(LDNS_RDF_TYPE_A, str);
93	if (!a) {
94		/* maybe ip6 */
95		a = ldns_rdf_new_frm_str(LDNS_RDF_TYPE_AAAA, str);
96		if (!a) {
97			return NULL;
98		}
99	}
100	return a;
101}
102
103static inline void
104local_print_ds(FILE* out, const char* pre, ldns_rr* ds)
105{
106	if (out && ds) {
107		fprintf(out, "%s", pre);
108		ldns_rr_print(out, ds);
109		ldns_rr_free(ds);
110	}
111}
112
113/*
114 * For all keys in a packet print the DS
115 */
116void
117print_ds_of_keys(ldns_pkt *p)
118{
119	ldns_rr_list *keys;
120	uint16_t i;
121	ldns_rr *ds;
122
123	/* TODO fix the section stuff, here or in ldns */
124	keys = ldns_pkt_rr_list_by_type(p, LDNS_RR_TYPE_DNSKEY,
125			LDNS_SECTION_ANSWER);
126
127	/* this also returns the question section rr, which does not
128	 * have any data.... and this inturn crashes everything */
129
130	if (keys) {
131		for (i = 0; i < ldns_rr_list_rr_count(keys); i++) {
132			fprintf(stdout, ";\n; equivalent DS records for key %u:\n",
133				(unsigned int)ldns_calc_keytag(ldns_rr_list_rr(keys, i)));
134
135			ds = ldns_key_rr2ds(ldns_rr_list_rr(keys, i), LDNS_SHA1);
136			local_print_ds(stdout, "; sha1: ", ds);
137			ds = ldns_key_rr2ds(ldns_rr_list_rr(keys, i), LDNS_SHA256);
138			local_print_ds(stdout, "; sha256: ", ds);
139		}
140		ldns_rr_list_deep_free(keys);
141	}
142}
143
144static void
145print_class_type(FILE *fp, ldns_rr *r)
146{
147	ldns_lookup_table *lt;
148        lt = ldns_lookup_by_id(ldns_rr_classes, ldns_rr_get_class(r));
149        if (lt) {
150               	fprintf(fp, " %s", lt->name);
151        } else {
152        	fprintf(fp, " CLASS%d", ldns_rr_get_class(r));
153        }
154	/* okay not THE way - but the quickest */
155	switch (ldns_rr_get_type(r)) {
156		case LDNS_RR_TYPE_RRSIG:
157			fprintf(fp, " RRSIG ");
158			break;
159		case LDNS_RR_TYPE_DNSKEY:
160			fprintf(fp, " DNSKEY ");
161			break;
162		case LDNS_RR_TYPE_DS:
163			fprintf(fp, " DS ");
164			break;
165		default:
166			break;
167	}
168}
169
170
171void
172print_ds_abbr(FILE *fp, ldns_rr *ds)
173{
174	if (!ds || (ldns_rr_get_type(ds) != LDNS_RR_TYPE_DS)) {
175		return;
176	}
177
178	ldns_rdf_print(fp, ldns_rr_owner(ds));
179	fprintf(fp, " %d", (int)ldns_rr_ttl(ds));
180	print_class_type(fp, ds);
181	ldns_rdf_print(fp, ldns_rr_rdf(ds, 0)); fprintf(fp, " ");
182	ldns_rdf_print(fp, ldns_rr_rdf(ds, 1)); fprintf(fp, " ");
183	ldns_rdf_print(fp, ldns_rr_rdf(ds, 2)); fprintf(fp, " ");
184	ldns_rdf_print(fp, ldns_rr_rdf(ds, 3)); fprintf(fp, " ");
185}
186
187/* print some of the elements of a signature */
188void
189print_rrsig_abbr(FILE *fp, ldns_rr *sig) {
190	if (!sig || (ldns_rr_get_type(sig) != LDNS_RR_TYPE_RRSIG)) {
191		return;
192	}
193
194	ldns_rdf_print(fp, ldns_rr_owner(sig));
195	fprintf(fp, " %d", (int)ldns_rr_ttl(sig));
196	print_class_type(fp, sig);
197
198	/* print a number of rdf's */
199	/* typecovered */
200	ldns_rdf_print(fp, ldns_rr_rdf(sig, 0)); fprintf(fp, " ");
201	/* algo */
202	ldns_rdf_print(fp, ldns_rr_rdf(sig, 1)); fprintf(fp, " ");
203	/* labels */
204	ldns_rdf_print(fp, ldns_rr_rdf(sig, 2)); fprintf(fp, " (\n\t\t\t");
205	/* expir */
206	ldns_rdf_print(fp, ldns_rr_rdf(sig, 4)); fprintf(fp, " ");
207	/* incep */
208	ldns_rdf_print(fp, ldns_rr_rdf(sig, 5)); fprintf(fp, " ");
209	/* key-id */
210	ldns_rdf_print(fp, ldns_rr_rdf(sig, 6)); fprintf(fp, " ");
211	/* key owner */
212	ldns_rdf_print(fp, ldns_rr_rdf(sig, 7)); fprintf(fp, ")");
213}
214
215void
216print_dnskey_abbr(FILE *fp, ldns_rr *key)
217{
218        if (!key || (ldns_rr_get_type(key) != LDNS_RR_TYPE_DNSKEY)) {
219                return;
220        }
221
222        ldns_rdf_print(fp, ldns_rr_owner(key));
223        fprintf(fp, " %d", (int)ldns_rr_ttl(key));
224	print_class_type(fp, key);
225
226        /* print a number of rdf's */
227        /* flags */
228        ldns_rdf_print(fp, ldns_rr_rdf(key, 0)); fprintf(fp, " ");
229        /* proto */
230        ldns_rdf_print(fp, ldns_rr_rdf(key, 1)); fprintf(fp, " ");
231        /* algo */
232        ldns_rdf_print(fp, ldns_rr_rdf(key, 2));
233
234	if (ldns_rdf2native_int16(ldns_rr_rdf(key, 0)) == 256) {
235		fprintf(fp, " ;{id = %u (zsk), size = %db}", (unsigned int)ldns_calc_keytag(key),
236				(int)ldns_rr_dnskey_key_size(key));
237		return;
238	}
239	if (ldns_rdf2native_int16(ldns_rr_rdf(key, 0)) == 257) {
240		fprintf(fp, " ;{id = %u (ksk), size = %db}", (unsigned int)ldns_calc_keytag(key),
241				(int)ldns_rr_dnskey_key_size(key));
242		return;
243	}
244	fprintf(fp, " ;{id = %u, size = %db}", (unsigned int)ldns_calc_keytag(key),
245			(int)ldns_rr_dnskey_key_size(key));
246}
247
248void
249print_rr_list_abbr(FILE *fp, ldns_rr_list *rrlist, const char *usr)
250{
251	size_t i;
252	ldns_rr_type tp;
253
254	for(i = 0; i < ldns_rr_list_rr_count(rrlist); i++) {
255		tp = ldns_rr_get_type(ldns_rr_list_rr(rrlist, i));
256		if (i == 0 && tp != LDNS_RR_TYPE_RRSIG) {
257			if (usr) {
258				fprintf(fp, "%s ", usr);
259			}
260		}
261		switch(tp) {
262		case LDNS_RR_TYPE_DNSKEY:
263			print_dnskey_abbr(fp, ldns_rr_list_rr(rrlist, i));
264			break;
265		case LDNS_RR_TYPE_RRSIG:
266			print_rrsig_abbr(fp, ldns_rr_list_rr(rrlist, i));
267			break;
268		case LDNS_RR_TYPE_DS:
269			print_ds_abbr(fp, ldns_rr_list_rr(rrlist, i));
270			break;
271		default:
272			/* not handled */
273			break;
274		}
275		fputs("\n", fp);
276	}
277}
278
279void *
280xmalloc(size_t s)
281{
282	void *p;
283
284	p = malloc(s);
285	if (!p) {
286		printf("Mem failure\n");
287		exit(EXIT_FAILURE);
288	}
289	return p;
290}
291
292void *
293xrealloc(void *p, size_t size)
294{
295	void *q;
296
297	q = realloc(p, size);
298	if (!q) {
299		printf("Mem failure\n");
300		exit(EXIT_FAILURE);
301	}
302	return q;
303}
304
305void
306xfree(void *p)
307{
308	if (p) {
309	        free(p);
310	}
311}
312