/* * Implements a simple, synchroneous DNS SRV query. * * climm Copyright (C) © 2001-2010 Rüdiger Kuhlmann * * climm is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by * the Free Software Foundation; version 2 dated June, 1991. * * climm is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public * License for more details. * * In addition, as a special exception permission is granted to link the * code of this release of climm with the OpenSSL project's "OpenSSL" * library, and distribute the linked executables. You must obey the GNU * General Public License in all respects for all of the code used other * than "OpenSSL". If you modify this file, you may extend this exception * to your version of the file, but you are not obligated to do so. If you * do not wish to do so, delete this exception statement from your version * of this file. * * You should have received a copy of the GNU General Public License * along with this package; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA * 02111-1307, USA. * * $Id$ */ #include "climm.h" #include "io/io_dns.h" /* OS X needs a compatibility flag for the resolver */ #define BIND_8_COMPAT 1 #if HAVE_NETINET_IN_H #include #endif #if HAVE_ARPA_NAMESER_H #include #endif #if HAVE_RESOLV_H #include #endif #ifndef T_SRV #define T_SRV 33 #endif typedef struct rrdns_s { char *hostname; UWORD port; UWORD pref; UWORD weight; } rrdns_t; const char *io_dns_resolve (const char *query) { union { unsigned char buf[1024]; HEADER h; } response; unsigned char *end, *pos; static str_s str; char name[256]; rrdns_t rrdns[32]; int count = 0, i, size, qdcount, ancount; UWORD type, len, pref, weight, port; size = res_query (query, C_IN, T_SRV, response.buf, sizeof (response)); if (size <= sizeof (HEADER)) return NULL; qdcount = ntohs (response.h.qdcount); ancount = ntohs (response.h.ancount); pos = response.buf + sizeof (HEADER); end = response.buf + size; /* skip over query */ while (pos < end && qdcount-- > 0) { size = dn_expand (response.buf, end, pos, name, 256); if (size < 0) return NULL; pos += size; pos += QFIXEDSZ; } while (pos < end && ancount-- > 0 && count < 32) { size = dn_expand (response.buf, end, pos, name, 256); if (size < 0) break; pos += size; GETSHORT (type, pos); pos += 6; GETSHORT (len, pos); if (type != T_SRV) { pos += len; continue; } GETSHORT (pref, pos); GETSHORT (weight, pos); GETSHORT (port, pos); size = dn_expand (response.buf, end, pos, name, 256); if (size < 0) return NULL; pos += size; rrdns[count].hostname = strdup (name); rrdns[count].port = port; rrdns[count].pref = pref; rrdns[count].weight = weight; count++; } if (!count) return NULL; for (i = 0; i < count - 1; i++) if (rrdns[i].pref > rrdns[i+1].pref || (rrdns[i].pref == rrdns[i+1].pref && rrdns[i].weight < rrdns[i+1].weight)) { rrdns_t tmp = rrdns[i]; rrdns[i] = rrdns[i+1]; rrdns[i+1] = tmp; } s_init (&str, "", 50); // s_catf (&str, ";example.org:1"); for (i = 0; i < count; i++) { s_catf (&str, ";%s:%u", rrdns[i].hostname, rrdns[i].port); free (rrdns[i].hostname); } return str.txt + 1; }