xref: /freebsd/usr.sbin/pkg/dns_utils.c (revision 8ad6d9175cb2dee6592a20551a144c8a924dc515)
129aaa961SBaptiste Daroussin /*-
229aaa961SBaptiste Daroussin  * Copyright (c) 2012 Baptiste Daroussin <bapt@FreeBSD.org>
329aaa961SBaptiste Daroussin  * All rights reserved.
429aaa961SBaptiste Daroussin  *
529aaa961SBaptiste Daroussin  * Redistribution and use in source and binary forms, with or without
629aaa961SBaptiste Daroussin  * modification, are permitted provided that the following conditions
729aaa961SBaptiste Daroussin  * are met:
829aaa961SBaptiste Daroussin  * 1. Redistributions of source code must retain the above copyright
929aaa961SBaptiste Daroussin  *    notice, this list of conditions and the following disclaimer,
1029aaa961SBaptiste Daroussin  *    without modification, immediately at the beginning of the file.
1129aaa961SBaptiste Daroussin  * 2. Redistributions in binary form must reproduce the above copyright
1229aaa961SBaptiste Daroussin  *    notice, this list of conditions and the following disclaimer in the
1329aaa961SBaptiste Daroussin  *    documentation and/or other materials provided with the distribution.
1429aaa961SBaptiste Daroussin  *
1529aaa961SBaptiste Daroussin  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
1629aaa961SBaptiste Daroussin  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
1729aaa961SBaptiste Daroussin  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
1829aaa961SBaptiste Daroussin  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
1929aaa961SBaptiste Daroussin  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
2029aaa961SBaptiste Daroussin  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
2129aaa961SBaptiste Daroussin  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
2229aaa961SBaptiste Daroussin  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
2329aaa961SBaptiste Daroussin  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
2429aaa961SBaptiste Daroussin  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
2529aaa961SBaptiste Daroussin  */
2629aaa961SBaptiste Daroussin 
2729aaa961SBaptiste Daroussin #include <sys/cdefs.h>
2829aaa961SBaptiste Daroussin __FBSDID("$FreeBSD$");
2929aaa961SBaptiste Daroussin 
3029aaa961SBaptiste Daroussin #include <stdlib.h>
3129aaa961SBaptiste Daroussin #include <string.h>
3229aaa961SBaptiste Daroussin #include <netinet/in.h>
3329aaa961SBaptiste Daroussin #include <resolv.h>
3429aaa961SBaptiste Daroussin 
3529aaa961SBaptiste Daroussin #include "dns_utils.h"
3629aaa961SBaptiste Daroussin 
3729aaa961SBaptiste Daroussin typedef union {
3829aaa961SBaptiste Daroussin 	HEADER hdr;
3929aaa961SBaptiste Daroussin 	unsigned char buf[1024];
4029aaa961SBaptiste Daroussin } dns_query;
4129aaa961SBaptiste Daroussin 
4229aaa961SBaptiste Daroussin struct dns_srvinfo *
4329aaa961SBaptiste Daroussin dns_getsrvinfo(const char *zone)
4429aaa961SBaptiste Daroussin {
4529aaa961SBaptiste Daroussin 	struct dns_srvinfo **res, *first;
4629aaa961SBaptiste Daroussin 	unsigned char *end, *p;
4729aaa961SBaptiste Daroussin 	char host[MAXHOSTNAMELEN];
4829aaa961SBaptiste Daroussin 	dns_query q;
4929aaa961SBaptiste Daroussin 	int len, qdcount, ancount, n, i;
5029aaa961SBaptiste Daroussin 	unsigned int type, class, ttl, priority, weight, port;
5129aaa961SBaptiste Daroussin 
5229aaa961SBaptiste Daroussin 	if ((len = res_query(zone, C_IN, T_SRV, q.buf, sizeof(q.buf))) == -1 ||
5329aaa961SBaptiste Daroussin 	    len < (int)sizeof(HEADER))
5429aaa961SBaptiste Daroussin 		return (NULL);
5529aaa961SBaptiste Daroussin 
5629aaa961SBaptiste Daroussin 	qdcount = ntohs(q.hdr.qdcount);
5729aaa961SBaptiste Daroussin 	ancount = ntohs(q.hdr.ancount);
5829aaa961SBaptiste Daroussin 
5929aaa961SBaptiste Daroussin 	end = q.buf + len;
6029aaa961SBaptiste Daroussin 	p = q.buf + sizeof(HEADER);
6129aaa961SBaptiste Daroussin 
6229aaa961SBaptiste Daroussin 	while(qdcount > 0 && p < end) {
6329aaa961SBaptiste Daroussin 		qdcount--;
6429aaa961SBaptiste Daroussin 		if((len = dn_expand(q.buf, end, p, host, MAXHOSTNAMELEN)) < 0)
6529aaa961SBaptiste Daroussin 			return (NULL);
6629aaa961SBaptiste Daroussin 		p += len + NS_QFIXEDSZ;
6729aaa961SBaptiste Daroussin 	}
6829aaa961SBaptiste Daroussin 
69*8ad6d917SBaptiste Daroussin 	res = calloc(ancount, sizeof(struct dns_srvinfo *));
7029aaa961SBaptiste Daroussin 	if (res == NULL)
7129aaa961SBaptiste Daroussin 		return (NULL);
7229aaa961SBaptiste Daroussin 
7329aaa961SBaptiste Daroussin 	n = 0;
7429aaa961SBaptiste Daroussin 	while (ancount > 0 && p < end) {
7529aaa961SBaptiste Daroussin 		ancount--;
7629aaa961SBaptiste Daroussin 		len = dn_expand(q.buf, end, p, host, MAXHOSTNAMELEN);
7729aaa961SBaptiste Daroussin 		if (len < 0) {
7829aaa961SBaptiste Daroussin 			for (i = 0; i < n; i++)
7929aaa961SBaptiste Daroussin 				free(res[i]);
8029aaa961SBaptiste Daroussin 			free(res);
8129aaa961SBaptiste Daroussin 			return NULL;
8229aaa961SBaptiste Daroussin 		}
8329aaa961SBaptiste Daroussin 
8429aaa961SBaptiste Daroussin 		p += len;
8529aaa961SBaptiste Daroussin 
8629aaa961SBaptiste Daroussin 		NS_GET16(type, p);
8729aaa961SBaptiste Daroussin 		NS_GET16(class, p);
8829aaa961SBaptiste Daroussin 		NS_GET32(ttl, p);
8929aaa961SBaptiste Daroussin 		NS_GET16(len, p);
9029aaa961SBaptiste Daroussin 
9129aaa961SBaptiste Daroussin 		if (type != T_SRV) {
9229aaa961SBaptiste Daroussin 			p += len;
9329aaa961SBaptiste Daroussin 			continue;
9429aaa961SBaptiste Daroussin 		}
9529aaa961SBaptiste Daroussin 
9629aaa961SBaptiste Daroussin 		NS_GET16(priority, p);
9729aaa961SBaptiste Daroussin 		NS_GET16(weight, p);
9829aaa961SBaptiste Daroussin 		NS_GET16(port, p);
9929aaa961SBaptiste Daroussin 
10029aaa961SBaptiste Daroussin 		len = dn_expand(q.buf, end, p, host, MAXHOSTNAMELEN);
10129aaa961SBaptiste Daroussin 		if (len < 0) {
10229aaa961SBaptiste Daroussin 			for (i = 0; i < n; i++)
10329aaa961SBaptiste Daroussin 				free(res[i]);
10429aaa961SBaptiste Daroussin 			free(res);
10529aaa961SBaptiste Daroussin 			return (NULL);
10629aaa961SBaptiste Daroussin 		}
10729aaa961SBaptiste Daroussin 
10829aaa961SBaptiste Daroussin 		res[n] = malloc(sizeof(struct dns_srvinfo));
10929aaa961SBaptiste Daroussin 		if (res[n] == NULL) {
11029aaa961SBaptiste Daroussin 			for (i = 0; i < n; i++)
11129aaa961SBaptiste Daroussin 				free(res[i]);
11229aaa961SBaptiste Daroussin 			free(res);
11329aaa961SBaptiste Daroussin 			return (NULL);
11429aaa961SBaptiste Daroussin 		}
11529aaa961SBaptiste Daroussin 		res[n]->type = type;
11629aaa961SBaptiste Daroussin 		res[n]->class = class;
11729aaa961SBaptiste Daroussin 		res[n]->ttl = ttl;
11829aaa961SBaptiste Daroussin 		res[n]->priority = priority;
11929aaa961SBaptiste Daroussin 		res[n]->weight = weight;
12029aaa961SBaptiste Daroussin 		res[n]->port = port;
12129aaa961SBaptiste Daroussin 		res[n]->next = NULL;
12229aaa961SBaptiste Daroussin 		strlcpy(res[n]->host, host, MAXHOSTNAMELEN);
12329aaa961SBaptiste Daroussin 
12429aaa961SBaptiste Daroussin 		p += len;
12529aaa961SBaptiste Daroussin 		n++;
12629aaa961SBaptiste Daroussin 	}
12729aaa961SBaptiste Daroussin 
12829aaa961SBaptiste Daroussin 	for (i = 0; i < n - 1; i++)
12929aaa961SBaptiste Daroussin 		res[i]->next = res[i + 1];
13029aaa961SBaptiste Daroussin 
13129aaa961SBaptiste Daroussin 	first = res[0];
13229aaa961SBaptiste Daroussin 	free(res);
13329aaa961SBaptiste Daroussin 
13429aaa961SBaptiste Daroussin 	return (first);
13529aaa961SBaptiste Daroussin }
136