static int dblchk(str *domain, str *dbltxt)
{
	str dblstr;
	char *dbl = getenv("DBLLOOKUP");
	int l, i;
	unsigned char ansbuf[512];
	
	if(!dbl || domain->len == 0) return 0;
	if(session_getnum("sump",0)) return 0; /* no point */


	str_init(&dblstr);
	str_copy(&dblstr, domain);
	str_catc(&dblstr, '.');
	str_cats(&dblstr, dbl);
			
	l = res_query(dblstr.s, C_IN, T_TXT, ansbuf, sizeof(ansbuf));
	if(l > 0 && ((HEADER *)ansbuf)->ancount != 0) {  /* something in the answer */
		unsigned char *recbuf = ansbuf+NS_HFIXEDSZ;
		
		/* skip over questions, why am I still writing stuff
		 * like this? */
		for(i = ns_get16(ansbuf+4); i != 0; --i)
			recbuf += dn_skipname(recbuf, ansbuf+l)+4;

		for(i = ns_get16(ansbuf+6); i != 0; --i) {
			recbuf += dn_skipname(recbuf, ansbuf+l);

			if(ns_get16(recbuf) != T_TXT) { /* CNAME or something */
				recbuf += 10 + ns_get16(recbuf+8);
				continue;
			}
			/* it's a TXT record, wow */
			str_init(dbltxt);
			str_copyb(dbltxt, (char*)recbuf+11, recbuf[10]);
			str_free(&dblstr);
			return 1;
		}
	} /* didn't find anything */
	str_free(&dblstr);
	return 0;
	}
Example #2
0
static int
app_parse_srv(radiodns_app_t *app, ns_msg handle, ns_rr rr, char *dnbuf, radiodns_srv_t *srv)
{
	const unsigned char *rdata;
	
	(void) app;

	rdata = ns_rr_rdata(rr);
	srv->priority = ns_get16(rdata);
	rdata += NS_INT16SZ;

	srv->weight = ns_get16(rdata);
	rdata += NS_INT16SZ;
	
	srv->port = ns_get16(rdata);
	rdata += NS_INT16SZ;
	
	dn_expand(ns_msg_base(handle), ns_msg_base(handle) + ns_msg_size(handle), rdata, dnbuf, MAXDNAME);
	if(!(srv->target = strdup(dnbuf)))
	{
		return -2;
	}
	return 0;
}
Example #3
0
u_int16_t _getshort(const u_char *src) { return (ns_get16(src)); }
Example #4
0
static void afsdb_hosts_to_addrs(char *vllist[],
				 int *vlsnum,
				 ns_msg handle,
				 ns_sect section,
				 unsigned mask,
				 unsigned long *_ttl)
{
	int rrnum;
	ns_rr rr;
	int subtype, i, ret;
	unsigned int ttl = UINT_MAX, rr_ttl;

	debug("AFSDB RR count is %d", ns_msg_count(handle, section));

	/* Look at all the resource records in this section. */
	for (rrnum = 0; rrnum < ns_msg_count(handle, section); rrnum++) {
		/* Expand the resource record number rrnum into rr. */
		if (ns_parserr(&handle, section, rrnum, &rr)) {
			_error("ns_parserr failed : %m");
			continue;
		}

		/* We're only interested in AFSDB records */
		if (ns_rr_type(rr) == ns_t_afsdb) {
			vllist[*vlsnum] = malloc(MAXDNAME);
			if (!vllist[*vlsnum])
				error("Out of memory");

			subtype = ns_get16(ns_rr_rdata(rr));

			/* Expand the name server's domain name */
			if (ns_name_uncompress(ns_msg_base(handle),
					       ns_msg_end(handle),
					       ns_rr_rdata(rr) + 2,
					       vllist[*vlsnum],
					       MAXDNAME) < 0)
				error("ns_name_uncompress failed");

			rr_ttl = ns_rr_ttl(rr);
			if (ttl > rr_ttl)
				ttl = rr_ttl;

			/* Check the domain name we've just unpacked and add it to
			 * the list of VL servers if it is not a duplicate.
			 * If it is a duplicate, just ignore it.
			 */
			for (i = 0; i < *vlsnum; i++)
				if (strcasecmp(vllist[i], vllist[*vlsnum]) == 0)
					goto next_one;

			/* Turn the hostname into IP addresses */
			ret = dns_resolver(vllist[*vlsnum], mask);
			if (ret) {
				debug("AFSDB RR can't resolve."
				      "subtype:%d, server name:%s, netmask:%u",
				      subtype, vllist[*vlsnum], mask);
				goto next_one;
			}

			info("AFSDB RR subtype:%d, server name:%s, ip:%*.*s, ttl:%u",
			     subtype, vllist[*vlsnum],
			     (int)payload[payload_index - 1].iov_len,
			     (int)payload[payload_index - 1].iov_len,
			     (char *)payload[payload_index - 1].iov_base,
			     ttl);

			/* prepare for the next record */
			*vlsnum += 1;
			continue;

		next_one:
			free(vllist[*vlsnum]);
		}
	}

	*_ttl = ttl;
	info("ttl: %u", ttl);
}
Example #5
0
int
DnsResolver_lookupMx(DnsResolver *self, const char *domain, DnsMxResponse **resp)
{
    int query_stat = DnsResolver_query(self, domain, ns_t_mx);
    if (NETDB_SUCCESS != query_stat) {
        return query_stat;
    }   // end if
    size_t msg_count = ns_msg_count(self->msghanlde, ns_s_an);
    DnsMxResponse *respobj =
        (DnsMxResponse *) malloc(sizeof(DnsMxResponse) + msg_count * sizeof(struct mxentry *));
    if (NULL == respobj) {
        return DnsResolver_setError(self, NETDB_INTERNAL);
    }   // end if
    memset(respobj, 0, sizeof(DnsMxResponse) + msg_count * sizeof(struct mxentry *));
    respobj->num = 0;
    for (size_t n = 0; n < msg_count; ++n) {
        ns_rr rr;
        int parse_stat = ns_parserr(&self->msghanlde, ns_s_an, n, &rr);
        if (0 != parse_stat) {
            goto formerr;
        }   // end if
        if (ns_t_mx != ns_rr_type(rr)) {
            continue;
        }   // end if
        const unsigned char *rdata = ns_rr_rdata(rr);
        if (ns_rr_rdlen(rr) < NS_INT16SZ) {
            goto formerr;
        }   // end if

        int preference = ns_get16(rdata);
        rdata += NS_INT16SZ;

        // NOTE: NS_MAXDNAME で十分なのかイマイチ確証が持てないが, bind8 の dig コマンドの実装でもこの値を使っていたのでいいのではないか.
        char dnamebuf[NS_MAXDNAME];
        int dnamelen =
            ns_name_uncompress(self->msgbuf, self->msgbuf + self->msglen, rdata, dnamebuf,
                               sizeof(dnamebuf));
        if (NS_INT16SZ + dnamelen != ns_rr_rdlen(rr)) {
            goto formerr;
        }   // end if
        // TODO: dnamebuf は NULL 終端が保証されているのか?
        size_t domainlen = strlen(dnamebuf);
        respobj->exchange[respobj->num] =
            (struct mxentry *) malloc(sizeof(struct mxentry) + sizeof(char[domainlen + 1]));
        if (NULL == respobj->exchange[respobj->num]) {
            goto noresource;
        }   // end if
        respobj->exchange[respobj->num]->preference = preference;
        if (domainlen + 1 <=
            strlcpy(respobj->exchange[respobj->num]->domain, dnamebuf, domainlen + 1)) {
            abort();
        }   // end if
        ++(respobj->num);
    }   // end for
    if (0 == respobj->num) {
        goto formerr;
    }   // end if
    *resp = respobj;
    return NETDB_SUCCESS;

  formerr:
    DnsMxResponse_free(respobj);
    return DnsResolver_setError(self, NO_RECOVERY);

  noresource:
    DnsMxResponse_free(respobj);
    return DnsResolver_setError(self, NETDB_INTERNAL);
}   // end function : DnsResolver_lookupMx
Example #6
0
static int
printZone(ns_type xfr, const char *zone, const struct sockaddr_in *sin,
	  ns_tsig_key *key)
{
	static u_char *answer = NULL;
	static int answerLen = 0;

	querybuf buf;
	int msglen, amtToRead, numRead, result, sockFD, len;
	int count, type, rlen, done, n;
	int numAnswers, numRecords, soacnt;
	u_char *cp, tmp[NS_INT16SZ];
	char dname[2][NS_MAXDNAME];
	enum { NO_ERRORS, ERR_READING_LEN, ERR_READING_MSG, ERR_PRINTING }
		error;
	pid_t zpid = -1;
	u_char *newmsg;
	int newmsglen;
	ns_tcp_tsig_state tsig_state;
	int tsig_ret, tsig_required, tsig_present;

	switch (xfr) {
	case ns_t_axfr:
	case ns_t_zxfr:
		break;
	default:
		fprintf(stderr, ";; %s - transfer type not supported\n",
			p_type(xfr));
		return (ERROR);
	}

	/*
	 *  Create a query packet for the requested zone name.
	 */
	msglen = res_nmkquery(&res, ns_o_query, zone,
			      queryClass, ns_t_axfr, NULL,
			      0, 0, buf.qb2, sizeof buf);
	if (msglen < 0) {
		if (res.options & RES_DEBUG)
			fprintf(stderr, ";; res_nmkquery failed\n");
		return (ERROR);
	}

	/*
	 * Sign the message if a key was sent
	 */
	if (key == NULL) {
		newmsg = (u_char *)&buf;
		newmsglen = msglen;
	} else {
		DST_KEY *dstkey;
		int bufsize, siglen;
		u_char sig[64];
		int ret;
		
		/* ns_sign() also calls dst_init(), but there is no harm
		 * doing it twice
		 */
		dst_init();
		
		bufsize = msglen + 1024;
		newmsg = (u_char *) malloc(bufsize);
		if (newmsg == NULL) {
			errno = ENOMEM;
			return (-1);
		}
		memcpy(newmsg, (u_char *)&buf, msglen);
		newmsglen = msglen;
		
		if (strcmp(key->alg, NS_TSIG_ALG_HMAC_MD5) != 0)
			dstkey = NULL;
		else
			dstkey = dst_buffer_to_key(key->name, KEY_HMAC_MD5,
							NS_KEY_TYPE_AUTH_ONLY,
							NS_KEY_PROT_ANY,
							key->data, key->len);
		if (dstkey == NULL) {
			errno = EINVAL;
			if (key)
				free(newmsg);
			return (-1);
		}
		
		siglen = sizeof(sig);
/* newmsglen++; */
		ret = ns_sign(newmsg, &newmsglen, bufsize, NOERROR, dstkey, NULL, 0,
		      sig, &siglen, 0);
		if (ret < 0) {
			if (key)
				free (newmsg);
			if (ret == NS_TSIG_ERROR_NO_SPACE)
				errno  = EMSGSIZE;
			else if (ret == -1)
				errno  = EINVAL;
			return (ret);
		}
		ns_verify_tcp_init(dstkey, sig, siglen, &tsig_state);
	}

	/*
	 *  Set up a virtual circuit to the server.
	 */
	if ((sockFD = socket(sin->sin_family, SOCK_STREAM, 0)) < 0) {
		int e = errno;

		perror(";; socket");
		return (e);
	}
	
	switch (sin->sin_family) {
	case AF_INET:
		if (bind(sockFD, (struct sockaddr *)&myaddress,
			 sizeof myaddress) < 0){
			int e = errno;

			fprintf(stderr, ";; bind(%s port %u): %s\n",
				inet_ntoa(myaddress.sin_addr),
				ntohs(myaddress.sin_port),
				strerror(e));
			(void) close(sockFD);
			sockFD = -1;
			return (e);
		}
		if (connect(sockFD, (const struct sockaddr *)sin,
			    sizeof *sin) < 0) {
			int e = errno;

			perror(";; connect");
			(void) close(sockFD);
			sockFD = -1;
			return (e);
		}
		break;
	case AF_INET6:
		if (bind(sockFD, (struct sockaddr *)&myaddress6,
			 sizeof myaddress6) < 0){
			int e = errno;
			char buf[80];

			fprintf(stderr, ";; bind(%s port %u): %s\n",
				inet_ntop(AF_INET6, &myaddress6.sin6_addr,
					  buf, sizeof(buf)),
				ntohs(myaddress6.sin6_port),
				strerror(e));
			(void) close(sockFD);
			sockFD = -1;
			return (e);
		}
		if (connect(sockFD, (const struct sockaddr *)sin,
			    sizeof(struct sockaddr_in6)) < 0) {
			int e = errno;

			perror(";; connect");
			(void) close(sockFD);
			sockFD = -1;
			return (e);
		}
		break;
	}

	/*
	 * Send length & message for zone transfer
	 */

	ns_put16(newmsglen, tmp);
        if (write(sockFD, (char *)tmp, NS_INT16SZ) != NS_INT16SZ ||
            write(sockFD, (char *)newmsg, newmsglen) != newmsglen) {
		int e = errno;
		if (key)
			free (newmsg);
		perror(";; write");
		(void) close(sockFD);
		sockFD = -1;
		return (e);
	} else if (key)
		free (newmsg);

	/*
	 * If we're compressing, push a gzip into the pipeline.
	 */
	if (xfr == ns_t_zxfr) {
		enum { rd = 0, wr = 1 };
		int z[2];

		if (pipe(z) < 0) {
			int e = errno;

			perror(";; pipe");
			(void) close(sockFD);
			sockFD = -1;
			return (e);
		}
		zpid = vfork();
		if (zpid < 0) {
			int e = errno;

			perror(";; fork");
			(void) close(sockFD);
			sockFD = -1;
			return (e);
		} else if (zpid == 0) {
			/* Child. */
			(void) close(z[rd]);
			(void) dup2(sockFD, STDIN_FILENO);
			(void) close(sockFD);
			(void) dup2(z[wr], STDOUT_FILENO);
			(void) close(z[wr]);
			execlp("gzip", "gzip", "-d", "-v", NULL);
			perror(";; child: execlp(gunzip)");
			_exit(1);
		}
		/* Parent. */
		(void) close(z[wr]);
		(void) dup2(z[rd], sockFD);
		(void) close(z[rd]);
	}
	result = 0;
	numAnswers = 0;
	numRecords = 0;
	soacnt = 0;
	error = NO_ERRORS;
	numRead = 0;

	dname[0][0] = '\0';
	for (done = 0; !done; (void)NULL) {
		/*
		 * Read the length of the response.
		 */

		cp = tmp;
		amtToRead = INT16SZ;
		while (amtToRead > 0 &&
		   (numRead = read(sockFD, cp, amtToRead)) > 0) {
			cp += numRead;
			amtToRead -= numRead;
		}
		if (numRead <= 0) {
			error = ERR_READING_LEN;
			break;
		}

		len = ns_get16(tmp);
		if (len == 0)
			break;	/* nothing left to read */

		/*
		 * The server sent too much data to fit the existing buffer --
		 * allocate a new one.
		 */
		if (len > answerLen) {
			if (answerLen != 0)
				free(answer);
			answerLen = len;
			answer = (u_char *)malloc(answerLen);
		}

		/*
		 * Read the response.
		 */

		amtToRead = len;
		cp = answer;
		while (amtToRead > 0 &&
		       (numRead = read(sockFD, cp, amtToRead)) > 0) {
			cp += numRead;
			amtToRead -= numRead;
		}
		if (numRead <= 0) {
			error = ERR_READING_MSG;
			break;
		}

		result = print_axfr(stdout, answer, len);
		if (result != 0) {
			error = ERR_PRINTING;
			break;
		}
		numRecords += htons(((HEADER *)answer)->ancount);
		numAnswers++;

		/* Header. */
		cp = answer + HFIXEDSZ;
		/* Question. */
		for (count = ntohs(((HEADER *)answer)->qdcount);	
		     count > 0;
		     count--) {
			n = dn_skipname(cp, answer + len);
			if (n < 0) {
				error = ERR_PRINTING;
				done++;
				break;
			}
			cp += n + QFIXEDSZ;
			if (cp > answer + len) {
				error = ERR_PRINTING;
				done++;
				break;
			}
		}
		/* Answer. */
		for (count = ntohs(((HEADER *)answer)->ancount);
		     count > 0 && !done;
		     count--) {
			n = dn_expand(answer, answer + len, cp,
				      dname[soacnt], sizeof dname[0]);
			if (n < 0) {
				error = ERR_PRINTING;
				done++;
				break;
			}
			cp += n;
			if (cp + 3 * INT16SZ + INT32SZ > answer + len) {
				error = ERR_PRINTING;
				done++;
				break;
			}
			GETSHORT(type, cp);
			cp += INT16SZ;
			cp += INT32SZ;	/* ttl */
			GETSHORT(rlen, cp);
			cp += rlen;
			if (cp > answer + len) {
				error = ERR_PRINTING;
				done++;
				break;
			}
			if (type == T_SOA && soacnt++ &&
			    ns_samename(dname[0], dname[1]) == 1) {
				done++;
				break;
			}
		}

		/*
		 * Verify the TSIG
		 */

		if (key) {
			if (ns_find_tsig(answer, answer + len) != NULL)
				tsig_present = 1;
			else
				tsig_present = 0;
			if (numAnswers == 1 || soacnt > 1)
				tsig_required = 1;
			else
				tsig_required = 0;
			tsig_ret = ns_verify_tcp(answer, &len, &tsig_state,
						 tsig_required);
			if (tsig_ret == 0) {
				if (tsig_present)
					printf("; TSIG ok\n");
			}
			else
				printf("; TSIG invalid\n");
		}

	}

	printf(";; Received %d answer%s (%d record%s).\n",
	       numAnswers, (numAnswers != 1) ? "s" : "",
	       numRecords, (numRecords != 1) ? "s" : "");

	(void) close(sockFD);
	sockFD = -1;

	/*
	 * If we were uncompressing, reap the uncompressor.
	 */
	if (xfr == ns_t_zxfr) {
		pid_t pid;
		int status = 0;

		pid = wait(&status);
		if (pid < 0) {
			int e = errno;

			perror(";; wait");
			return (e);
		}
		if (pid != zpid) {
			fprintf(stderr, ";; wrong pid (%lu != %lu)\n",
				(u_long)pid, (u_long)zpid);
			return (ERROR);
		}
		printf(";; pid %lu: exit %d, signal %d, core %c\n",
		       (u_long)pid, WEXITSTATUS(status),
		       WIFSIGNALED(status) ? WTERMSIG(status) : 0,
		       WCOREDUMP(status) ? 't' : 'f');
	}

	switch (error) {
	case NO_ERRORS:
		return (0);

	case ERR_READING_LEN:
		return (EMSGSIZE);

	case ERR_PRINTING:
		return (result);

	case ERR_READING_MSG:
		return (EMSGSIZE);

	default:
		return (EFAULT);
	}
}
Example #7
0
  DNS::HostMap DNS::resolve( const std::string& service, const std::string& proto,
                             const std::string& domain, const LogSink& logInstance )
  {
    buffer srvbuf;
    bool error = false;

    const std::string dname = "_" +  service + "._" + proto;

    if( !domain.empty() )
      srvbuf.len = res_querydomain( dname.c_str(), const_cast<char*>( domain.c_str() ),
                                    C_IN, T_SRV, srvbuf.buf, NS_PACKETSZ );
    else
      srvbuf.len = res_query( dname.c_str(), C_IN, T_SRV, srvbuf.buf, NS_PACKETSZ );

    if( srvbuf.len < 0 )
      return defaultHostMap( domain, logInstance );

    HEADER* hdr = (HEADER*)srvbuf.buf;
    unsigned char* here = srvbuf.buf + NS_HFIXEDSZ;

    if( ( hdr->tc ) || ( srvbuf.len < NS_HFIXEDSZ ) )
      error = true;

    if( hdr->rcode >= 1 && hdr->rcode <= 5 )
      error = true;

    if( ntohs( hdr->ancount ) == 0 )
      error = true;

    if( ntohs( hdr->ancount ) > NS_PACKETSZ )
      error = true;

    int cnt;
    for( cnt = ntohs( hdr->qdcount ); cnt>0; --cnt )
    {
      int strlen = dn_skipname( here, srvbuf.buf + srvbuf.len );
      here += strlen + NS_QFIXEDSZ;
    }

    unsigned char* srv[NS_PACKETSZ];
    int srvnum = 0;
    for( cnt = ntohs( hdr->ancount ); cnt>0; --cnt )
    {
      int strlen = dn_skipname( here, srvbuf.buf + srvbuf.len );
      here += strlen;
      srv[srvnum++] = here;
      here += SRV_FIXEDSZ;
      here += dn_skipname( here, srvbuf.buf + srvbuf.len );
    }

    if( error )
    {
      return defaultHostMap( domain, logInstance );
    }

    // (q)sort here

    HostMap servers;
    for( cnt=0; cnt<srvnum; ++cnt )
    {
      name srvname;

      if( ns_name_ntop( srv[cnt] + SRV_SERVER, (char*)srvname, NS_MAXDNAME ) < 0 )
        printf( "handle this error!\n" );

      servers[(char*)srvname] = ns_get16( srv[cnt] + SRV_PORT );
    }

    return servers;
  }
Example #8
0
File: dns.c Project: bond/dma
int
dns_get_mx_list(const char *host, int port, struct mx_hostentry **he, int no_mx)
{
	char outname[MAXDNAME];
	ns_msg msg;
	ns_rr rr;
	const char *searchhost;
	const unsigned char *cp;
	unsigned char *ans;
	struct mx_hostentry *hosts = NULL;
	size_t nhosts = 0;
	size_t anssz;
	int pref;
	int cname_recurse;
	int err;
	int i;

	res_init();
	searchhost = host;
	cname_recurse = 0;

	anssz = 65536;
	ans = malloc(anssz);
	if (ans == NULL)
		return (1);

	if (no_mx)
		goto out;

repeat:
	err = res_search(searchhost, ns_c_in, ns_t_mx, ans, anssz);
	if (err < 0) {
		switch (h_errno) {
		case NO_DATA:
			/*
			 * Host exists, but no MX (or CNAME) entry.
			 * Not an error, use host name instead.
			 */
			goto out;
		case TRY_AGAIN:
			/* transient error */
			goto transerr;
		case NO_RECOVERY:
		case HOST_NOT_FOUND:
		default:
			errno = ENOENT;
			goto err;
		}
	}

	if (!ns_initparse(ans, anssz, &msg))
		goto transerr;

	switch (ns_msg_getflag(msg, ns_f_rcode)) {
	case ns_r_noerror:
		break;
	case ns_r_nxdomain:
		goto err;
	default:
		goto transerr;
	}

	for (i = 0; i < ns_msg_count(msg, ns_s_an); i++) {
		if (ns_parserr(&msg, ns_s_an, i, &rr))
			goto transerr;

		cp = ns_rr_rdata(rr);

		switch (ns_rr_type(rr)) {
		case ns_t_mx:
			pref = ns_get16(cp);
			cp += 2;
			err = ns_name_uncompress(ns_msg_base(msg), ns_msg_end(msg),
						 cp, outname, sizeof(outname));
			if (err < 0)
				goto transerr;

			add_host(pref, outname, port, &hosts, &nhosts);
			break;

		case ns_t_cname:
			err = ns_name_uncompress(ns_msg_base(msg), ns_msg_end(msg),
						 cp, outname, sizeof(outname));
			if (err < 0)
				goto transerr;

			/* Prevent a CNAME loop */
			if (cname_recurse++ > 10)
				goto err;

			searchhost = outname;
			goto repeat;

		default:
			break;
		}
	}

out:
	err = 0;
	if (0) {
transerr:
		if (nhosts == 0)
			err = 1;
	}
	if (0) {
err:
		err = -1;
	}

	free(ans);

	if (!err) {
		/*
		 * If we didn't find any MX, use the hostname instead.
		 */
		if (nhosts == 0)
			add_host(0, searchhost, port, &hosts, &nhosts);

		qsort(hosts, nhosts, sizeof(*hosts), sort_pref);
	}

	if (nhosts > 0) {
		/* terminate list */
		*hosts[nhosts].host = 0;
	} else {
		if (hosts != NULL)
			free(hosts);
		hosts = NULL;
	}

	*he = hosts;
	return (err);

	free(ans);
	if (hosts != NULL)
		free(hosts);
	return (err);
}
/**
 *  create_naptr_record()
 */
static NAPTR_record *create_naptr_record(const ns_msg *handle,
                                         const ns_rr *rr) {
   size_t rdchars;
   const u_char *rdata, *edata;
   const u_char *message = ns_msg_base(*handle);
   size_t message_len = ns_msg_size(*handle);
   char buf[NS_MAXDNAME]; /* defined in nameser.h */
   NAPTR_record *naptr_record = malloc(sizeof(NAPTR_record));
   memset(naptr_record,0,sizeof(NAPTR_record));

   /*
   ** Domain field
   */
   naptr_record->domain = strdup(ns_rr_name(*rr));

   /*
   ** TTL field
   */
   naptr_record->ttl = ns_rr_ttl(*rr);

   /*
   ** Copy from rdata
   ** (borrowed from BIND-8.2.2 ns_print.c)
   */
   rdata = ns_rr_rdata(*rr);
   edata = rdata+ns_rr_rdlen(*rr);

   /*
   ** Order & preference field
   */
   naptr_record->order = ns_get16(rdata);
   rdata += NS_INT16SZ;
   naptr_record->preference = ns_get16(rdata);
   rdata += NS_INT16SZ;

   /*
   ** Flags field
   */
   if((naptr_record->flags = get_rdata_str(rdata,edata,&rdchars))==NULL) {
      free_naptr_record(naptr_record);
      return NULL;
   }
   rdata += rdchars;

   /*
   ** Service field
   */
   if((naptr_record->service = get_rdata_str(rdata,edata,&rdchars))==NULL) {
      free_naptr_record(naptr_record);
      return NULL;
   }
   rdata += rdchars;

   /*
   ** RegExp field
   */
   if((naptr_record->regexp = get_rdata_str(rdata,edata,&rdchars))==NULL) {
      free_naptr_record(naptr_record);
      return NULL;
   }
   rdata += rdchars;

   /*
   ** Replacement field
   **  Note: dn_expand() sets the first character to '\0' for the root,
   **        we are going to set it back to '.'
   */
   if(dn_expand(message,message+message_len,rdata,buf,NS_MAXDNAME)==-1) {
      free_naptr_record(naptr_record);
      return NULL;
   }
   if(buf[0]=='\0') {
      buf[0]='.';
      buf[1]='\0';
   }
   naptr_record->replacement = strdup(buf);

   return naptr_record;
}
Example #10
0
/* Setup a client socket for the named service over the given protocol under
 * the given domain name.
 */
static int insrv_lookup (int (*mksox) (int,const struct sockaddr *,socklen_t),
			char *service, char *proto, char *domain,
			char *cnxhost, size_t cnxhlen, int *cnxport) {
	// 1. convert service/proto to svcnm
	// 2. construct SRV query for _service._proto.domain
	// 3. try connecting to all answers in turn
	// 4. if no SRV records exist, lookup A record to connect to on stdport
	// 5. return connection socket or error code

	iobuf query, names;
	name svcnm;
	int error=0;
	int ctr;
	int rnd;
	int sox=0;
	HEADER *nameshdr;
	unsigned char *here, *srv[MAXNUM_SRV], *ip;
	int num_srv=0;
	// Storage for fallback SRV list, constructed when DNS gives no SRV
	unsigned char fallbacksrv [2*(MAXCDNAME+SRV_FIXEDSZ+MAXCDNAME)];

	srv_flags &= ~SRV_GOT_MASK;
	srv_flags |=  SRV_GOT_SRV;

	strcpy (svcnm, "_");
	strcat (svcnm, service);
	strcat (svcnm, "._");
	strcat (svcnm, proto);

	// Note that SRV records are only defined for class IN
	if (domain) {
		names.len=res_querydomain (svcnm, domain,
				C_IN, T_SRV,
				names.buf, PACKETSZ);
	} else {
		names.len=res_query (svcnm,
				C_IN, T_SRV,
				names.buf, PACKETSZ);
	}
	if (names.len < 0) {
		error = -ENOENT;
		goto fallback;
	}
	nameshdr=(HEADER *) names.buf;
	here=names.buf + HFIXEDSZ;
	rnd=nameshdr->id; 	// Heck, gimme one reason why not!

	if ((names.len < HFIXEDSZ) || nameshdr->tc) {
		error = -EMSGSIZE;
	}
	switch (nameshdr->rcode) {
		case 1:
			error = -EFAULT;
			goto fallback;
		case 2:
			error = -EAGAIN;
			goto fallback;
		case 3:
			error = -ENOENT;
			goto fallback;
		case 4:
			error = -ENOSYS;
			goto fallback;
		case 5:
			error = -EPERM;
			goto fallback;
		default:
			break;
	}
	if (ntohs (nameshdr->ancount) == 0) {
		error = -ENOENT;
		goto fallback;
	}
	if (ntohs (nameshdr->ancount) > MAXNUM_SRV) {
		error = -ERANGE;
		goto fallback;
	}
	for (ctr=ntohs (nameshdr->qdcount); ctr>0; ctr--) {
		int strlen=dn_skipname (here, names.buf+names.len);
		here += strlen + QFIXEDSZ;
	}
	for (ctr=ntohs (nameshdr->ancount); ctr>0; ctr--) {
		int strlen=dn_skipname (here, names.buf+names.len);
		here += strlen;
		srv [num_srv++] = here;
		here += SRV_FIXEDSZ;
		here += dn_skipname (here, names.buf+names.len);
	}

	// In case an error occurred, there are no SRV records.
	// Fallback strategy now is: construct two. One with the domain name,
	// the other with the /standard/ service name prefixed.
	// Note: Assuming a domain without the service name prefixed!
fallback:
	if (error) {
		struct servent *servent = getservbyname (service, proto);

		srv_flags &= ~SRV_GOT_MASK;
		srv_flags |=  SRV_GOT_A;

		num_srv = 2;
		if (!servent) {
			return error; // First error returned
		}
		srv [0] = here = fallbacksrv;
		// Only few record fields are really needed:
		*(unsigned short *)(here + SRV_COST)   = htons (0);
		*(unsigned short *)(here + SRV_WEIGHT) = htons (0);
		*(unsigned short *)(here + SRV_PORT)   = servent->s_port;
		here += SRV_FIXEDSZ;
		if (domain) {
			here += dn_comp (domain, here, MAXCDNAME, NULL, NULL);
		}
		// Forget about the name whose SRV IN this is, no need for it
		srv [1] = here;
		// Only few record fields are really needed:
		*(unsigned short *)(here + SRV_COST)   = htons (1);
		*(unsigned short *)(here + SRV_WEIGHT) = htons (0);
		*(unsigned short *)(here + SRV_PORT)   = servent->s_port;
		here += SRV_FIXEDSZ;
		here += dn_comp (servent->s_name, here, MAXCDNAME, NULL, NULL);
		here--; // Go back to overwrite final zero byte
		if (domain) {
			here += dn_comp (domain, here, MAXCDNAME, NULL, NULL);
		}
		rnd = 1;
	}
	// End of fallback construction, making sure that variables are defined
	// srv[] points to the SRV RR, num_srv counts the number of entries.
	// Every SRV RR has at least cost, weight, port and servername set.
	
#ifdef DEBUG
	for (ctr=0; ctr<num_srv; ctr++) {
		name srvname;
		if (ns_name_ntop (srv [ctr]+SRV_SERVER, srvname, MAXDNAME) < 0) {
			return -errno;
		}
		printf ("Considering SRV server %d %d %d\t%s\n",
				ns_get16 (srv [ctr]+SRV_COST),
				ns_get16 (srv [ctr]+SRV_WEIGHT),
				ns_get16 (srv [ctr]+SRV_PORT),
				srvname
			);
	}
#endif

	// Overwrite weight with rnd-spread version to divide load over weights
	for (ctr=0; ctr<num_srv; ctr++) {
		*(unsigned short *)(srv [ctr]+SRV_WEIGHT)
			= rnd % (1+ns_get16 (srv [ctr]+SRV_WEIGHT));
	}
	qsort (srv, num_srv, sizeof (*srv), srvcmp);


	for (ctr=0; ctr<num_srv; ctr++) {
		name srvname;
		struct hostent *host;
		// Open a socket to connect with
		int sox = socket (PF_INET, (*proto!='u')? SOCK_STREAM: SOCK_DGRAM, 0);
		if (sox < 0) {
			return -errno;
		}
		if (ns_name_ntop (srv [ctr]+SRV_SERVER, srvname, MAXDNAME) < 0) {
			return -errno;
		}
#ifdef DEBUG
		printf ("Trying SRV server %d %d\t%s\n",
				ns_get16 (srv [ctr]+SRV_COST),
				*(unsigned short *)(srv [ctr]+SRV_WEIGHT),
				srvname
			);
#endif
		if ((host=gethostbyname (srvname))
				&& (host->h_addrtype == AF_INET)) {
			char **ip=host->h_addr_list;
			while (*ip) {
				char *ipnr=*ip;
				struct sockaddr_in sin;
				memset (&sin, 0, sizeof (sin));
				sin.sin_family = AF_INET;
				memcpy (&sin.sin_addr,
						ipnr,
						sizeof (sin.sin_addr));
				sin.sin_port = *(unsigned short *) (srv [ctr]+SRV_PORT);
#ifdef DEBUG
				fprintf (stderr, "\tbind_connect (%d, 0x%08lx, %d)\t",
					sox,
					ntohl(*(unsigned long *)ipnr),
					ntohs (sin.sin_port));
#endif
#ifdef DEBUG
				if (mksox == connect) {
					printf ("mksox == connect\n");
				}
				if (mksox == bind) {
					printf ("mksox == bind\n");
				}
				{ int i; printf ("SIN ="); for (i=0; i<sizeof (sin); i++) printf (" %02x", (int) (((unsigned char *) &sin) [i])); printf ("\n"); }
#endif
				if (mksox (sox, (struct sockaddr *) &sin, sizeof (sin)) == 0) {
#ifdef DEBUG
					fprintf (stderr, "Connected or bound to %s:%d\n", srvname, ntohs (sin.sin_port));
#endif
					if (cnxhost) {
						if (strlen (cnxhost) > cnxhlen-1) {
							*cnxhost = '\0';
						} else {
							strncpy (cnxhost,srvname,cnxhlen);
						}
					}
					if (cnxport) {
						*cnxport = ntohs (sin.sin_port);
					}
					return sox;
				} else {
					if (!error) {
						error = -errno;
					}
				}
				ip++;
			}
			
		}
#ifdef DEBUG
		printf ("Closing socket %d\n", sox);
#endif
		close (sox);
	}

	if (!error) {
		error = -ENOENT;
	}
	return error;

}
void PlatformDomainNameServiceQuery::runBlocking() {
	if (!serviceValid) {
		emitError();
		return;
	}

	SWIFT_LOG(debug) << "Querying " << service << std::endl;

	std::vector<DomainNameServiceQuery::Result> records;

#if defined(SWIFTEN_PLATFORM_WINDOWS)
	DNS_RECORD* responses;
	// FIXME: This conversion doesn't work if unicode is deffed above
	if (DnsQuery(service.c_str(), DNS_TYPE_SRV, DNS_QUERY_STANDARD, NULL, &responses, NULL) != ERROR_SUCCESS) {
		emitError();
		return;
	}

	DNS_RECORD* currentEntry = responses;
	while (currentEntry) {
		if (currentEntry->wType == DNS_TYPE_SRV) {
			DomainNameServiceQuery::Result record;
			record.priority = currentEntry->Data.SRV.wPriority;
			record.weight = currentEntry->Data.SRV.wWeight;
			record.port = currentEntry->Data.SRV.wPort;
				
			// The pNameTarget is actually a PCWSTR, so I would have expected this 
			// conversion to not work at all, but it does.
			// Actually, it doesn't. Fix this and remove explicit cast
			// Remove unicode undef above as well
			record.hostname = std::string((const char*) currentEntry->Data.SRV.pNameTarget);
			records.push_back(record);
		}
		currentEntry = currentEntry->pNext;
	}
	DnsRecordListFree(responses, DnsFreeRecordList);

#else
	// Make sure we reinitialize the domain list every time
	res_init();

	ByteArray response;
	response.resize(NS_PACKETSZ);
	int responseLength = res_query(const_cast<char*>(service.c_str()), ns_c_in, ns_t_srv, reinterpret_cast<u_char*>(vecptr(response)), response.size());
	if (responseLength == -1) {
		SWIFT_LOG(debug) << "Error" << std::endl;
		emitError();
		return;
	}

	// Parse header
	HEADER* header = reinterpret_cast<HEADER*>(vecptr(response));
	unsigned char* messageStart = vecptr(response);
	unsigned char* messageEnd = messageStart + responseLength;
	unsigned char* currentEntry = messageStart + NS_HFIXEDSZ;

	// Skip over the queries
	int queriesCount = ntohs(header->qdcount);
	while (queriesCount > 0) {
		int entryLength = dn_skipname(currentEntry, messageEnd);
		if (entryLength < 0) {
			emitError();
			return;
		}
		currentEntry += entryLength + NS_QFIXEDSZ;
		queriesCount--;
	}

	// Process the SRV answers
	int answersCount = ntohs(header->ancount);
	while (answersCount > 0) {
		DomainNameServiceQuery::Result record;

		int entryLength = dn_skipname(currentEntry, messageEnd);
		currentEntry += entryLength;
		currentEntry += NS_RRFIXEDSZ;

		// Priority
		if (currentEntry + 2 >= messageEnd) {
			emitError();
			return;
		}
		record.priority = boost::numeric_cast<int>(ns_get16(currentEntry));
		currentEntry += 2;

		// Weight
		if (currentEntry + 2 >= messageEnd) {
			emitError();
			return;
		}
		record.weight = boost::numeric_cast<int>(ns_get16(currentEntry));
		currentEntry += 2;

		// Port
		if (currentEntry + 2 >= messageEnd) {
			emitError();
			return;
		}
		record.port = boost::numeric_cast<int>(ns_get16(currentEntry));
		currentEntry += 2; 

		// Hostname
		if (currentEntry >= messageEnd) {
			emitError();
			return;
		}
		ByteArray entry;
		entry.resize(NS_MAXDNAME);
		entryLength = dn_expand(messageStart, messageEnd, currentEntry, reinterpret_cast<char*>(vecptr(entry)), entry.size());
		if (entryLength < 0) {
			emitError();
			return;
		}
		record.hostname = std::string(reinterpret_cast<const char*>(vecptr(entry)));
		records.push_back(record);
		currentEntry += entryLength;
		answersCount--;
	}
#endif

	BoostRandomGenerator generator;
	DomainNameServiceQuery::sortResults(records, generator);
	//std::cout << "Sending out " << records.size() << " SRV results " << std::endl;
	eventLoop->postEvent(boost::bind(boost::ref(onResult), records), shared_from_this());
}
Example #12
0
File: send.c Project: aosm/bind
int
SendRequest(union res_sockaddr_union *nsAddrPtr, const u_char *buf,
	    int buflen, u_char *answer, u_int anslen, int *trueLenPtr)
{
	int n, try, v_circuit, resplen;
	ISC_SOCKLEN_T salen;
	int gotsomewhere = 0, connected = 0;
	int connreset = 0;
	u_short id, len;
	u_char *cp;
	fd_set dsmask;
	struct timeval timeout;
	const HEADER *hp = (const HEADER *) buf;
	HEADER *anhp = (HEADER *) answer;
	struct iovec iov[2];
	int terrno = ETIMEDOUT;
	char junk[512];
	struct sockaddr_storage sa;
	int family = nsAddrPtr->sin.sin_family;
	int clen = (family == AF_INET) ? sizeof(struct sockaddr_in) :
				         sizeof(struct sockaddr_in6);

	if (res.options & RES_DEBUG2) {
	    printf("------------\nSendRequest(), len %d\n", buflen);
	    Print_query(buf, buf + buflen, 1);
	}
	v_circuit = (res.options & RES_USEVC) || buflen > PACKETSZ;
	id = hp->id;
	/*
	 * Send request, RETRY times, or until successful
	 */
	for (try = 0; try < res.retry; try++) {
	usevc:
		if (v_circuit) {
			int truncated = 0;

			/*
			 * Use virtual circuit;
			 * at most one attempt per server.
			 */
			try = res.retry;
			if (s < 0) {
				s = socket(family, SOCK_STREAM, 0);
				if (s < 0) {
					terrno = errno;
					if (res.options & RES_DEBUG)
					    perror("socket (vc) failed");
					continue;
				}
				if (connect(s, (struct sockaddr *)nsAddrPtr,
				    clen) < 0) {
					terrno = errno;
					if (res.options & RES_DEBUG)
					    perror("connect failed");
					(void) close(s);
					s = -1;
					continue;
				}
			}
			/*
			 * Send length & message
			 */
			__putshort(buflen, (u_char *)&len);
			iov[0].iov_base = (caddr_t)&len;
			iov[0].iov_len = INT16SZ;
			DE_CONST(buf, iov[1].iov_base);
			iov[1].iov_len = buflen;
			if (writev(s, iov, 2) != INT16SZ + buflen) {
				terrno = errno;
				if (res.options & RES_DEBUG)
					perror("write failed");
				(void) close(s);
				s = -1;
				continue;
			}
			/*
			 * Receive length & response
			 */
			cp = answer;
			len = INT16SZ;
			while ((n = read(s, (char *)cp, (int)len)) > 0) {
				cp += n;
				if ((len -= n) <= 0)
					break;
			}
			if (n <= 0) {
				terrno = errno;
				if (res.options & RES_DEBUG)
					perror("read failed");
				(void) close(s);
				s = -1;
				/*
				 * A long running process might get its TCP
				 * connection reset if the remote server was
				 * restarted.  Requery the server instead of
				 * trying a new one.  When there is only one
				 * server, this means that a query might work
				 * instead of failing.  We only allow one reset
				 * per query to prevent looping.
				 */
				if (terrno == ECONNRESET && !connreset) {
					connreset = 1;
				}
				continue;
			}
			cp = answer;
			if ((resplen = ns_get16((u_char*)cp)) > (int)anslen) {
				if (res.options & RES_DEBUG)
					fprintf(stderr, "response truncated\n");
				len = anslen;
				truncated = 1;
			} else
				len = resplen;
			while (len != 0 &&
			   (n = read(s, (char *)cp, (int)len)) > 0) {
				cp += n;
				len -= n;
			}
			if (n <= 0) {
				terrno = errno;
				if (res.options & RES_DEBUG)
					perror("read failed");
				(void) close(s);
				s = -1;
				continue;
			}
			if (truncated) {
				/*
				 * Flush rest of answer
				 * so connection stays in synch.
				 */
				anhp->tc = 1;
				len = resplen - anslen;
				while (len != 0) {
					n = (len > sizeof(junk) ?
					    sizeof(junk) : len);
					if ((n = read(s, junk, n)) > 0)
						len -= n;
					else
						break;
				}
			}
		} else {
			/*
			 * Use datagrams.
			 */
			if (s < 0) {
				s = socket(family, SOCK_DGRAM, 0);
				if (s < 0) {
					terrno = errno;
					if (res.options & RES_DEBUG)
					    perror("socket (dg) failed");
					continue;
				}
			}
#if BSD >= 43
			if (connected == 0) {
				if (connect(s, (struct sockaddr *)nsAddrPtr,
				    clen) < 0) {
					if (res.options & RES_DEBUG)
						perror("connect");
					continue;
				}
				connected = 1;
			}
			if (send(s, buf, buflen, 0) != buflen) {
				if (res.options & RES_DEBUG)
					perror("send");
				continue;
			}
#else /* BSD */
			if (sendto(s, (const char *)buf, buflen, 0,
				   (struct sockaddr *) nsAddrPtr,
				   clen) != buflen) {
				if (res.options & RES_DEBUG)
					perror("sendto");
				continue;
			}
#endif

			/*
			 * Wait for reply
			 */
			timeout.tv_sec = (res.retrans << try);
			if (timeout.tv_sec <= 0)
				timeout.tv_sec = 1;
			timeout.tv_usec = 0;
 wait:
			FD_ZERO(&dsmask);
			FD_SET(s, &dsmask);
			n = select(s+1, &dsmask, (fd_set *)NULL,
				(fd_set *)NULL, &timeout);
			if (n < 0) {
				if (res.options & RES_DEBUG)
					perror("select");
				continue;
			}
			if (n == 0) {
				/*
				 * timeout
				 */
				if (res.options & RES_DEBUG)
					printf("timeout\n");
#if BSD >= 43
				gotsomewhere = 1;
#endif
				continue;
			}

			salen = sizeof sa;
			resplen = recvfrom(s, (char *)answer, anslen, 0,
					   (struct sockaddr *)&sa, &salen);
			if (resplen <= 0) {
				if (res.options & RES_DEBUG)
					perror("recvfrom");
				continue;
			}
			gotsomewhere = 1;
			if (id != anhp->id) {
				/*
				 * response from old query, ignore it
				 */
				if (res.options & RES_DEBUG2) {
					printf("------------\nOld answer:\n");
					Print_query(answer, answer+resplen, 1);
				}
				goto wait;
			}
			if (!(res.options & RES_IGNTC) && anhp->tc) {
				/*
				 * get rest of answer;
				 * use TCP with same server.
				 */
				if (res.options & RES_DEBUG)
					printf("truncated answer\n");
				(void) close(s);
				s = -1;
				v_circuit = 1;
				goto usevc;
			}
		}
		if (res.options & RES_DEBUG) {
		    if (res.options & RES_DEBUG2)
			printf("------------\nGot answer (%d bytes):\n",
			    resplen);
		    else
			printf("------------\nGot answer:\n");
		    Print_query(answer, answer+resplen, 1);
		}
		(void) close(s);
		s = -1;
		*trueLenPtr = resplen;
		return (SUCCESS);
	}
	if (s >= 0) {
		(void) close(s);
		s = -1;
	}
	if (v_circuit == 0)
		if (gotsomewhere == 0)
			return NO_RESPONSE;	/* no nameservers found */
		else
			return TIME_OUT;	/* no answer obtained */
	else
		if (errno == ECONNREFUSED)
			return NO_RESPONSE;
		else
			return ERROR;
}
Example #13
0
/*
 * Fill out host list, based on DNS lookups.
 * This is not reentrant.  Better be called before any other threads
 * are started.
 */
int cldc_getaddr(GList **host_list, const char *thishost, struct hail_log *log)
{
	enum { hostsz = 64 };
	char cldb[hostsz];
	unsigned char resp[512];
	int rlen;
	ns_msg nsb;
	ns_rr rrb;
	int rrlen;
	char hostb[hostsz];
	int i;
	struct cldc_host hp;
	const unsigned char *p;
	int rc;
	int search_retries = 10;

	/*
	 * We must create FQDN or else the first thing the resolver does
	 * is a lookup in the DNS root (probably the standard-compliant
	 * dot between "_cld" and "_udp" hurts us here).
	 */
	if (cldc_make_fqdn(cldb, hostsz, "_cld._udp", thishost) != 0) {
		HAIL_INFO(log, "internal error in cldc_make_fqdn(%s)",
			  thishost);
		return -1;
	}

do_try_again:
	rc = res_search(cldb, ns_c_in, ns_t_srv, resp, 512);
	if (rc < 0) {
		switch (h_errno) {
		case HOST_NOT_FOUND:
			HAIL_INFO(log, "%s: No _cld._udp SRV record", __func__);
			return -1;
		case NO_DATA:
			HAIL_INFO(log, "%s: Cannot find _cld._udp"
				  " SRV record", __func__);
			return -1;
		case TRY_AGAIN:
			if (search_retries-- > 0)
				goto do_try_again;
			/* fall through */
		case NO_RECOVERY:
		default:
			HAIL_ERR(log, "%s: res_search error (%d): %s",
				 __func__, h_errno, hstrerror(h_errno));
			return -1;
		}
	}
	rlen = rc;

	if (rlen == 0) {
		HAIL_INFO(log, "%s: res_search returned empty reply", __func__);
		return -1;
	}

	if (ns_initparse(resp, rlen, &nsb) < 0) {
		HAIL_ERR(log, "%s: ns_initparse error", __func__);
		return -1;
	}

	for (i = 0; i < ns_msg_count(nsb, ns_s_an); i++) {
		rc = ns_parserr(&nsb, ns_s_an, i, &rrb);
		if (rc < 0)
			continue;

		if (ns_rr_class(rrb) != ns_c_in)
			continue;

		memset(&hp, 0, sizeof(hp));

		switch (ns_rr_type(rrb)) {
		case ns_t_srv:
			rrlen = ns_rr_rdlen(rrb);
			if (rrlen < 8) {	/* 2+2+2 and 2 for host */
				HAIL_DEBUG(log, "%s: SRV len %d",
					   __func__, rrlen);
				break;
			}
			p = ns_rr_rdata(rrb);
			rc = dn_expand(resp, resp+rlen, p+6, hostb, hostsz);
			if (rc < 0) {
				HAIL_DEBUG(log, "%s: dn_expand error %d",
					   __func__, rc);
				break;
			}
			if (rc < 2) {
				HAIL_DEBUG(log, "%s: dn_expand short %d",
					   __func__, rc);
				break;
			}

			if (cldc_saveaddr(&hp, ns_get16(p+0),
					  ns_get16(p+2), ns_get16(p+4),
					  rc, hostb, NULL))
				break;

			HAIL_DEBUG(log, "%s: found CLD host %s port %u"
				   " prio %d weight %d",
				   __func__, hp.host, hp.port,
				   hp.prio, hp.weight);

			push_host(host_list, &hp);
			break;
		case ns_t_cname:	/* impossible, but */
			HAIL_DEBUG(log, "%s: CNAME in SRV request, ignored",
				   __func__);
			break;
		default:
			;
		}
	}

	return 0;
}
Example #14
0
/* Setup a client socket for the named service over the given protocol under
 * the given domain name.
 */
int insrv_lookup (const char *service, const char *proto, const char *domain, 
	list<t_dns_result> &result) 
{
	// 1. convert service/proto to svcnm
	// 2. construct SRV query for _service._proto.domain

	iobuf names;
	name svcnm;
	int ctr;
	int rnd;
	HEADER *nameshdr;
	unsigned char *here, *srv[MAXNUM_SRV];
	int num_srv=0;
	// Storage for fallback SRV list, constructed when DNS gives no SRV
	//unsigned char fallbacksrv [2*(MAXCDNAME+SRV_FIXEDSZ+MAXCDNAME)];

	// srv_flags &= ~SRV_GOT_MASK;
	// srv_flags |=  SRV_GOT_SRV;

	strcpy (svcnm, "_");
	strcat (svcnm, service);
	strcat (svcnm, "._");
	strcat (svcnm, proto);

	// Note that SRV records are only defined for class IN
	if (domain) {
		names.len=res_querydomain (svcnm, domain,
				C_IN, T_SRV,
				names.buf, PACKETSZ);
	} else {
		names.len=res_query (svcnm,
				C_IN, T_SRV,
				names.buf, PACKETSZ);
	}
	if (names.len < 0) {
		return -ENOENT;
	}
	nameshdr=(HEADER *) names.buf;
	here=names.buf + HFIXEDSZ;
	rnd=nameshdr->id; 	// Heck, gimme one reason why not!

	if ((names.len < HFIXEDSZ) || nameshdr->tc) {
		return -EMSGSIZE;
	}
	switch (nameshdr->rcode) {
		case 1:
			return -EFAULT;
		case 2:
			return -EAGAIN;
		case 3:
			return -ENOENT;
		case 4:
			return -ENOSYS;
		case 5:
			return -EPERM;
		default:
			break;
	}
	if (ntohs (nameshdr->ancount) == 0) {
		return -ENOENT;
	}
	if (ntohs (nameshdr->ancount) > MAXNUM_SRV) {
		return -ERANGE;
	}
	for (ctr=ntohs (nameshdr->qdcount); ctr>0; ctr--) {
		int strlen=dn_skipname (here, names.buf+names.len);
		here += strlen + QFIXEDSZ;
	}
	for (ctr=ntohs (nameshdr->ancount); ctr>0; ctr--) {
		int strlen=dn_skipname (here, names.buf+names.len);
		here += strlen;
		srv [num_srv++] = here;
		here += SRV_FIXEDSZ;
		here += dn_skipname (here, names.buf+names.len);
	}
	
	// Overwrite weight with rnd-spread version to divide load over weights
	for (ctr=0; ctr<num_srv; ctr++) {
		*(unsigned short *) (srv [ctr]+SRV_WEIGHT)
			= htons(rnd % (1+ns_get16 (srv [ctr]+SRV_WEIGHT)));
	}
	qsort (srv, num_srv, sizeof (*srv), srvcmp);
	
	result.clear();
	for (ctr=0; ctr<num_srv; ctr++) {
		name srvname;
		if (ns_name_ntop (srv [ctr]+SRV_SERVER, srvname, MAXDNAME) < 0) {
			return -errno;
		}
		
		t_dns_result r;
		r.hostname = srvname;
		r.port = ns_get16(srv [ctr]+SRV_PORT);
		result.push_back(r);
	}
	
	return 0;
}