static void
do_section(ns_msg *handle, ns_sect section, int pflag, FILE *file) {
	int n, sflag, rrnum;
	char buf[2048];	/* XXX need to malloc */
	ns_opcode opcode;
	ns_rr rr;

	/*
	 * Print answer records.
	 */
	sflag = (_res.pfcode & pflag);
	if (_res.pfcode && !sflag)
		return;

	opcode = ns_msg_getflag(*handle, ns_f_opcode);
	rrnum = 0;
	for (;;) {
		if (ns_parserr(handle, section, rrnum, &rr)) {
			if (errno != ENODEV)
				fprintf(file, ";; ns_parserr: %s\n",
					strerror(errno));
			else if (rrnum > 0 && sflag != 0 &&
				 (_res.pfcode & RES_PRF_HEAD1))
				putc('\n', file);
			return;
		}
		if (rrnum == 0 && sflag != 0 && (_res.pfcode & RES_PRF_HEAD1))
			fprintf(file, ";; %s SECTION:\n",
				p_section(section, opcode));
		if (section == ns_s_qd)
			fprintf(file, ";;\t%s, type = %s, class = %s\n",
				ns_rr_name(rr),
				p_type(ns_rr_type(rr)),
				p_class(ns_rr_class(rr)));
		else {
			n = ns_sprintrr(handle, &rr, NULL, NULL,
					buf, sizeof buf);
			if (n < 0) {
				fprintf(file, ";; ns_sprintrr: %s\n",
					strerror(errno));
				return;
			}
			fputs(buf, file);
			fputc('\n', file);
		}
		rrnum++;
	}
}
Example #2
0
/*
 * krb5int_dns_nextans - get next matching answer record
 *
 * Sets pp to NULL if no more records.  Returns -1 on error, 0 on
 * success.
 */
int
krb5int_dns_nextans(struct krb5int_dns_state *ds,
                    const unsigned char **pp, int *lenp)
{
    int len;
    ns_rr rr;

    *pp = NULL;
    *lenp = 0;
    while (ds->cur_ans < ns_msg_count(ds->msg, ns_s_an)) {
        len = ns_parserr(&ds->msg, ns_s_an, ds->cur_ans, &rr);
        if (len < 0)
            return -1;
        ds->cur_ans++;
        if (ds->nclass == (int)ns_rr_class(rr)
            && ds->ntype == (int)ns_rr_type(rr)) {
            *pp = ns_rr_rdata(rr);
            *lenp = ns_rr_rdlen(rr);
            return 0;
        }
    }
    return 0;
}
Example #3
0
void txtout_output(const char* descr, iaddr from, iaddr to, uint8_t proto, unsigned flags,
    unsigned sport, unsigned dport, my_bpftimeval ts,
    const u_char* pkt_copy, unsigned olen,
    const u_char* payload, unsigned payloadlen)
{
    /*
     * Short output, only print QTYPE and QNAME for IN records
     */
    if (opt_s) {
        if (flags & DNSCAP_OUTPUT_ISDNS) {
            ns_msg msg;
            int    qdcount, err = 0;
            ns_rr  rr;
            if (ns_initparse(payload, payloadlen, &msg) < 0) {
                if (tcpstate_getcurr && tcpstate_reset)
                    tcpstate_reset(tcpstate_getcurr(), "");
                return;
            }
            qdcount = ns_msg_count(msg, ns_s_qd);

            if (qdcount > 0 && 0 == (err = ns_parserr(&msg, ns_s_qd, 0, &rr)) && ns_rr_class(rr) == 1) {
                fprintf(out, "%s %s\n",
                    p_type(ns_rr_type(rr)),
                    ns_rr_name(rr));
            }
            if (err < 0) {
                if (tcpstate_getcurr && tcpstate_reset)
                    tcpstate_reset(tcpstate_getcurr(), "");
            }
        }
        return;
    }

    /*
     * IP Stuff
     */
    fprintf(out, "%10ld.%06ld", (long)ts.tv_sec, (long)ts.tv_usec);
    fprintf(out, " %s %u", ia_str(from), sport);
    fprintf(out, " %s %u", ia_str(to), dport);
    fprintf(out, " %hhu", proto);

    if (flags & DNSCAP_OUTPUT_ISDNS) {
        ns_msg msg;
        int    qdcount, err = 0;
        ns_rr  rr;
        if (ns_initparse(payload, payloadlen, &msg) < 0) {
            if (tcpstate_getcurr && tcpstate_reset)
                tcpstate_reset(tcpstate_getcurr(), "");
            fprintf(out, "\n");
            return;
        }

        /*
         * DNS Header
         */
        fprintf(out, " %u", ns_msg_id(msg));
        fprintf(out, " %u", ns_msg_getflag(msg, ns_f_opcode));
        fprintf(out, " %u", ns_msg_getflag(msg, ns_f_rcode));
        fprintf(out, " |");
        if (ns_msg_getflag(msg, ns_f_qr))
            fprintf(out, "QR|");
        if (ns_msg_getflag(msg, ns_f_aa))
            fprintf(out, "AA|");
        if (ns_msg_getflag(msg, ns_f_tc))
            fprintf(out, "TC|");
        if (ns_msg_getflag(msg, ns_f_rd))
            fprintf(out, "RD|");
        if (ns_msg_getflag(msg, ns_f_ra))
            fprintf(out, "RA|");
        if (ns_msg_getflag(msg, ns_f_ad))
            fprintf(out, "AD|");
        if (ns_msg_getflag(msg, ns_f_cd))
            fprintf(out, "CD|");

        qdcount = ns_msg_count(msg, ns_s_qd);
        if (qdcount > 0 && 0 == (err = ns_parserr(&msg, ns_s_qd, 0, &rr))) {
            fprintf(out, " %s %s %s",
                p_class(ns_rr_class(rr)),
                p_type(ns_rr_type(rr)),
                ns_rr_name(rr));
        }
        if (err < 0) {
            if (tcpstate_getcurr && tcpstate_reset)
                tcpstate_reset(tcpstate_getcurr(), "");
        }
    }
    /*
     * Done
     */
    fprintf(out, "\n");
}
Example #4
0
static void
do_section(const res_state statp,
	   ns_msg *handle, ns_sect section,
	   int pflag, FILE *file)
{
	int n, sflag, rrnum;
	static int buflen = 2048;
	char *buf;
	ns_opcode opcode;
	ns_rr rr;

	/*
	 * Print answer records.
	 */
	sflag = (statp->pfcode & pflag);
	if (statp->pfcode && !sflag)
		return;

	buf = malloc(buflen);
	if (buf == NULL) {
		fprintf(file, ";; memory allocation failure\n");
		return;
	}

	opcode = (ns_opcode) ns_msg_getflag(*handle, ns_f_opcode);
	rrnum = 0;
	for (;;) {
		if (ns_parserr(handle, section, rrnum, &rr)) {
			if (errno != ENODEV)
				fprintf(file, ";; ns_parserr: %s\n",
					strerror(errno));
			else if (rrnum > 0 && sflag != 0 &&
				 (statp->pfcode & RES_PRF_HEAD1))
				putc('\n', file);
			goto cleanup;
		}
		if (rrnum == 0 && sflag != 0 && (statp->pfcode & RES_PRF_HEAD1))
			fprintf(file, ";; %s SECTION:\n",
				p_section(section, opcode));
		if (section == ns_s_qd)
			fprintf(file, ";;\t%s, type = %s, class = %s\n",
				ns_rr_name(rr),
				p_type(ns_rr_type(rr)),
				p_class(ns_rr_class(rr)));
		else if (section == ns_s_ar && ns_rr_type(rr) == ns_t_opt) {
			u_int16_t optcode, optlen, rdatalen = ns_rr_rdlen(rr);
			u_int32_t ttl = ns_rr_ttl(rr);

			fprintf(file,
				"; EDNS: version: %u, udp=%u, flags=%04x\n",
				(ttl>>16)&0xff, ns_rr_class(rr), ttl&0xffff);

			while (rdatalen >= 4) {
				const u_char *cp = ns_rr_rdata(rr);
				int i;

				GETSHORT(optcode, cp);
				GETSHORT(optlen, cp);

				if (optcode == NS_OPT_NSID) {
					fputs("; NSID: ", file);
					if (optlen == 0) {
						fputs("; NSID\n", file);
					} else {
						fputs("; NSID: ", file);
						for (i = 0; i < optlen; i++)
							fprintf(file, "%02x ",
								cp[i]);
						fputs(" (",file);
						for (i = 0; i < optlen; i++)
							fprintf(file, "%c",
								isprint(cp[i])?
								cp[i] : '.');
						fputs(")\n", file);
					}
				} else {
					if (optlen == 0) {
						fprintf(file, "; OPT=%u\n",
							optcode);
					} else {
						fprintf(file, "; OPT=%u: ",
							optcode);
						for (i = 0; i < optlen; i++)
							fprintf(file, "%02x ",
								cp[i]);
						fputs(" (",file);
						for (i = 0; i < optlen; i++)
							fprintf(file, "%c",
								isprint(cp[i]) ?
									cp[i] : '.');
						fputs(")\n", file);
					}
				}
				rdatalen -= 4 + optlen;
			}
		} else {
Example #5
0
static void
do_section (int pfcode, ns_msg *handle, ns_sect section, int pflag, FILE *file)
{
	int n, sflag, rrnum;
	static int buflen = 2048;
	char *buf;
	ns_opcode opcode;
	ns_rr rr;

	/*
	 * Print answer records.
	 */
	sflag = (pfcode & pflag);
	if (pfcode && !sflag)
		return;

	buf = malloc(buflen);
	if (buf == NULL) {
		fprintf(file, ";; memory allocation failure\n");
		return;
	}

	opcode = (ns_opcode) ns_msg_getflag(*handle, ns_f_opcode);
	rrnum = 0;
	for (;;) {
		if (ns_parserr(handle, section, rrnum, &rr)) {
			if (errno != ENODEV)
				fprintf(file, ";; ns_parserr: %s\n",
					strerror(errno));
			else if (rrnum > 0 && sflag != 0 &&
				 (pfcode & RES_PRF_HEAD1))
				putc('\n', file);
			goto cleanup;
		}
		if (rrnum == 0 && sflag != 0 && (pfcode & RES_PRF_HEAD1))
			fprintf(file, ";; %s SECTION:\n",
				p_section(section, opcode));
		if (section == ns_s_qd)
			fprintf(file, ";;\t%s, type = %s, class = %s\n",
				ns_rr_name(rr),
				p_type(ns_rr_type(rr)),
				p_class(ns_rr_class(rr)));
		else {
			n = ns_sprintrr(handle, &rr, NULL, NULL,
					buf, buflen);
			if (n < 0) {
				if (errno == ENOSPC) {
					free(buf);
					buf = NULL;
					if (buflen < 131072)
						buf = malloc(buflen += 1024);
					if (buf == NULL) {
						fprintf(file,
					      ";; memory allocation failure\n");
					      return;
					}
					continue;
				}
				fprintf(file, ";; ns_sprintrr: %s\n",
					strerror(errno));
				goto cleanup;
			}
			fputs(buf, file);
			fputc('\n', file);
		}
		rrnum++;
	}
 cleanup:
	free(buf);
}
Example #6
0
static int 
app_follow_ptr(radiodns_app_t *app, unsigned char *abuf, ns_msg phandle, ns_rr prr)
{
	char dnbuf[MAXDNAME + 1], dbuf[4];
	char *d, *p, *endp;
	ns_msg handle;
	ns_rr rr;
	int c, len, r;
	
	dn_expand(ns_msg_base(phandle), ns_msg_base(phandle) + ns_msg_size(phandle), ns_rr_rdata(prr), dnbuf, sizeof(dnbuf));	
	if(!(app->name = (char *) calloc(1, strlen(dnbuf))))
	{
		return -2;
	}
	d = app->name;
	p = dnbuf;
	while(*p && *p != '.')
	{
		if(*p == '\\' && isdigit(p[1]) && isdigit(p[2]) && isdigit(p[3]))
		{
			dbuf[0] = p[1];
			dbuf[1] = p[2];
			dbuf[2] = p[3];
			dbuf[3] = 0;
			c = strtol(dbuf, NULL, 10);
			*d = c;
			d++;
			p += 4;
			continue;
		}
		else if(*p == '\\' && p[1])
		{
			/* Skip the backslash, allowing it to escape the '.' */
			p++;
		}
		*d = *p;
		d++;
		p++;
	}
	*d = 0;
	if(0 >= (len = res_query(dnbuf, ns_c_in, ns_t_any, abuf, RDNS_ANSWERBUFLEN)))
	{
		return -1;
	}
	if(0 > ns_initparse(abuf, len, &handle))
	{
		return -1;
	}
	if(0 > (len = ns_msg_count(handle, ns_s_an)))
	{
		return -1;
	}
	if(!(app->srv = (radiodns_srv_t *) calloc(len, sizeof(radiodns_srv_t))))
	{
		return -2;
	}
	for(c = 0; c < len; c++)
	{
		if(ns_parserr(&handle, ns_s_an, c, &rr))
		{
			continue;
		}
		if(ns_rr_class(rr) != ns_c_in)
		{
			continue;
		}
		if(ns_rr_type(rr) == ns_t_txt)
		{
			app_parse_txt(app, handle, rr, dnbuf);
		}
		if(ns_rr_type(rr) == ns_t_srv)
		{
			r = app_parse_srv(app, handle, rr, dnbuf, &(app->srv[app->nsrv]));
			if(r == 0)
			{
				app->nsrv++;
			}
			else
			{
				return r;
			}
		}
				
	}
	if(app->nsrv)
	{
		return 0;
	}
	return -1;
}
Example #7
0
/* Attempt to resolve the target FQDN for a context */
const char *
radiodns_resolve_target(radiodns_t *context)
{
	int len, c;
	ns_msg handle;
	ns_rr rr;
	char domain[MAXDNAME + 1], dnbuf[MAXDNAME + 1];

	/* reset these to help with error handling in callers */
	h_errno = NETDB_INTERNAL;
	errno = 0;
	if(!context->answer)
	{
		if(NULL == (context->answer = (unsigned char *) malloc(RDNS_ANSWERBUFLEN)))
		{
			return NULL;
		}
	}
	free(context->target);
	context->target = NULL;
	strcpy(domain, context->domain);
	for(;;)
	{
		h_errno = 0;
		if(0 >= (len = res_query(domain, ns_c_in, ns_t_any, context->answer, RDNS_ANSWERBUFLEN)))
		{
			if(NETDB_INTERNAL == h_errno)
			{
				return NULL;
			}
			break;
		}
		if(0 > ns_initparse(context->answer, len, &handle))
		{
			break;
		}
		if(0 > (len = ns_msg_count(handle, ns_s_an)))
		{
			break;
		}
		/* Resolvers tend towards the sane: the last result in a set of
		 * DNAME and CNAME replies will be the one we care about. If
		 * you're building against a resolver which for some reason
		 * behaves differently, you'll need a workaround here.
		 */
		dnbuf[0] = 0;
		for(c = 0; c < len; c++)
		{
			if(ns_parserr(&handle, ns_s_an, c, &rr))
			{
				/* Parse failed? Hmm. */
				continue;
			}
			if(ns_rr_class(rr) != ns_c_in)
			{
				continue;
			}
			if(ns_rr_type(rr) == ns_t_dname || ns_rr_type(rr) == ns_t_cname)
			{
				dn_expand(ns_msg_base(handle), ns_msg_base(handle) + ns_msg_size(handle), ns_rr_rdata(rr), dnbuf, sizeof(dnbuf));
			}
		}      
		if(dnbuf[0])
		{
			if(0 == strcmp(domain, dnbuf))
			{
				break;
			}
			strcpy(domain, dnbuf);
			continue;
		}
		break;
	}
	/* Whatever we found last is the target, unless we found nothing at all,
	 * in which case the target is the same as the original domain.
	 */
	if(NULL == (context->target = strdup(domain)))
	{
		return NULL;
	}    
	return context->target;
}
Example #8
0
/* Find all of the records for _<name>._<protocol>.<target> */
radiodns_app_t *
radiodns_resolve_app(radiodns_t *context, const char *name, const char *protocol)
{
	char fqdn[MAXDNAME+1], dnbuf[MAXDNAME+1];
	radiodns_app_t *defapp, *namedapps, *app;
	ns_msg handle;
	ns_rr rr;
	int len, c, r;
	unsigned char *abuf;

	if(!context->target)
	{
		if(NULL == radiodns_resolve_target(context))
		{
			return NULL;
		}
	}
	if(!protocol)
	{
		protocol = "tcp";
	}
	if(strlen(name) + strlen(protocol) + strlen(context->target) + 4 > MAXDNAME)
	{
		errno = ENAMETOOLONG;
		return NULL;
	}
	sprintf(fqdn, "_%s._%s.%s", name, protocol, context->target);
	if(0 >= (len = res_query(fqdn, ns_c_in, ns_t_any, context->answer, RDNS_ANSWERBUFLEN)))
	{
		return NULL;
	}	
	if(0 > ns_initparse(context->answer, len, &handle))
	{
		return NULL;
	}
	if(0 > (len = ns_msg_count(handle, ns_s_an)))
	{
		return NULL;
	}
	defapp = NULL;
	namedapps = NULL;
	abuf = NULL;
	r = 0; /* -1 == some catchable error, -2 == catastrophic error */
	for(c = 0; c < len; c++)
	{
		if(ns_parserr(&handle, ns_s_an, c, &rr))
		{
			/* Parse failed? Hmm. */
			continue;
		}
		if(ns_rr_class(rr) != ns_c_in)
		{
			continue;
		}
		if(ns_rr_type(rr) == ns_t_ptr)
		{
			if(!abuf)
			{
				if(!(abuf = (unsigned char *) malloc(RDNS_ANSWERBUFLEN)))
				{
					r = -2;
					break;
				}
			}
			if(!(app = app_create()))
			{
				r = -2;
				break;
			}
			r = app_follow_ptr(app, abuf, handle, rr);
			if(r == 0)
			{
				app->next = namedapps;
				namedapps = app;
			}
			else if(r == -1)
			{
				radiodns_destroy_app(app);
				continue;
			}
			else
			{
				radiodns_destroy_app(app);
				break;
			}	
		}
		else if(ns_rr_type(rr) == ns_t_txt)
		{
			if(!defapp)
			{
				if(!(defapp = app_create()))
				{
					r = -2;
					break;
				}
			}
			if(-2 == (r = app_parse_txt(defapp, handle, rr, dnbuf)))
			{
				break;
			}
		}
		else if(ns_rr_type(rr) == ns_t_srv)
		{
			if(!defapp)
			{
				if(!(defapp = app_create()))
				{
					r = -2;
					break;
				}
			}
			if(!defapp->srv)
			{
				if(!(defapp->srv = (radiodns_srv_t *) calloc(len, sizeof(radiodns_srv_t))))
				{
					r = -2;
					break;
				}
			}
			r = app_parse_srv(defapp, handle, rr, dnbuf, &(defapp->srv[defapp->nsrv]));
			if(r == 0)
			{
				defapp->nsrv++;
			}
			else if(r == -2)
			{
				break;
			}
		}
	}
	free(abuf);
	if(r == -2)
	{
		radiodns_destroy_app(defapp);
		radiodns_destroy_app(namedapps);
		return NULL;
	}
	if(defapp)
	{
		if(defapp->nsrv)
		{
			defapp->next = namedapps;
			return defapp;
		}
		radiodns_destroy_app(defapp);
	}
	/* In the event that there actually wasn't anything worth returning,
	 * don't confuse matters by leaving errno set to something random.
	 */
	errno = 0;
	return namedapps;
}
Example #9
0
/* This function expects the bep034_lock to be held by caller,
   releases it while working and returns with the lock held
*/
static bep034_status bep034_fill_hostrecord( const char * hostname, bep034_hostrecord ** hostrecord, uintptr_t dns_handle ) {
  uint8_t answer[NS_PACKETSZ];
  bep034_hostrecord * hr = 0;
  int answer_len, num_msgs, max_entries, i;
  ns_msg msg;
  ns_rr rr;

  /* Reset hostrecord pointer */
  * hostrecord = 0;

  /* If we find a record in cache, return it */
  hr = bep034_find_hostrecord( hostname, &i /* dummy */ );
  if( hr ) {
    *hostrecord = hr;
    return BEP_034_INPROGRESS;
  }

  /* Return mutex, we'll be blocking now and do not
     hold any resources in need of guarding  */
  bep034_dounlock();

  /* Query resolver for TXT records for the trackers domain */
#ifdef __MACH__
  {
    struct sockaddr tmp;
    uint32_t tmplen;
    answer_len = dns_search( (dns_handle_t)dns_handle, hostname, ns_c_in, ns_t_txt, answer, sizeof(answer), &tmp, &tmplen );
  }
#else
  (void)dns_handle;
  answer_len = res_search(hostname, ns_c_in, ns_t_txt, answer, sizeof(answer));
#endif
  if( answer_len < 0 ) {
    /* Here we enter race condition land */
    switch( h_errno ) {
    case NO_RECOVERY: case HOST_NOT_FOUND: return BEP_034_NXDOMAIN;
    case NO_DATA: return BEP_034_NORECORD;
    case NETDB_INTERNAL: case TRY_AGAIN: default: return BEP_034_TIMEOUT;
    }
  }

  ns_initparse (answer, answer_len, &msg);
  num_msgs = ns_msg_count (msg, ns_s_an);
  for( i=0; i<num_msgs; ++i) {
    ns_parserr (&msg, ns_s_an, i, &rr);
    if (ns_rr_class(rr) == ns_c_in && ns_rr_type(rr) == ns_t_txt ) {
      uint32_t record_ttl = ns_rr_ttl(rr);
      uint16_t record_len = ns_rr_rdlen(rr);
      const uint8_t *record_ptr = ns_rr_rdata(rr);
      const char * string_ptr, * string_end;

      /* First octet is length of (first) string in the txt record.
         Since BEP034 does not say anything about multiple strings,
         we ignore all but the first string in each TXT record. */
      uint8_t string_len = *record_ptr;

      /* If we would read beyond buffer end, ignore record */
      if( record_ptr + 1 + string_len > answer + answer_len )
        continue;

      /* Sanitize string length against record length */
      if( string_len + 1 > record_len )
        string_len = record_len - 1;

      /* Test if we are interested in the record */
      if( string_len < 10 /* strlen( "BITTORRENT" ) */ )
        continue;

      /* Although the BEP is not very specific, we interpret the wording
         "This should always be the first word in the record" as a requirment
         to not start the record with a space */
      if( memcmp( record_ptr + 1, "BITTORRENT", 10 ) )
        continue;

      /* We found a BITTORRENT TXT record. Now start parsing:
         Given entries of the form "UDP:\d+\s" i.e. 6 bytes,
         in a record of length N we have an upper bound of
         ( N - 11 ) / 6 records.
      */
      max_entries = 1 + ( string_len - 11 ) / 6;

      /* Allocate memory for host record */
      hr = (bep034_hostrecord*)
        malloc( sizeof(bep034_hostrecord) + sizeof( uint32_t ) * max_entries );
      if( !hr )
        return BEP_034_TIMEOUT;

      /* Init host record */
      hr->hostname = strdup( hostname );
      hr->entries = 0;
      hr->expiry = NOW() + record_ttl;

      /* Look for "\s(TCP|UDP):\d+" */
      string_ptr = record_ptr + 1;
      string_end = string_ptr + string_len;
      string_ptr += 10 /* strlen( "BITTORRENT" ) */;

      while( string_ptr + 6 < string_end ) { /* We need at least 6 bytes for a word */
        int found;
        uint32_t port = 0;

        ++string_ptr;
        if( string_ptr[-1] != ' ' || string_ptr[2] != 'P' || string_ptr[3] != ':' )
          continue;
        if( string_ptr[0] == 'T' && string_ptr[1] == 'C' )
          found = 0;
        else if( string_ptr[0] == 'U' && string_ptr[1] == 'D' )
          found = 1;
        else
          continue;

        /* Now we're sure, we've found UDP: or TCP: and assume, from string_ptr + 4 there's
           a port number*/
        string_ptr += 4;
        while( string_ptr < string_end && (*string_ptr >= '0' && *string_ptr <= '9' ) )
          port = port * 10 + *(string_ptr++) - '0';

        /* If no digit was found, word is invalid */
        if( string_ptr[-1] == ':' ) continue;

        /* If number did not terminate on end of string or with a space, word is invalid */
        if( string_ptr != string_end && *string_ptr != ' ' ) continue;

        /* If we have an invalid port number, word is invalid */
        if( port > 65335 ) continue;

        /* Valid word found, add it to tracker list */
        hr->trackers[ hr->entries++ ] = port | ( found ? 0x10000 : 0 );
      }

      /* Ensure exclusive access to the host record list, lock will be held
         on return so that the caller can work with hr */
      bep034_dolock();

      /* Hand over record to cache, from now the cache has to release memory */
      if( bep034_save_record( &hr ) )
        return BEP_034_TIMEOUT;

      /* Dump what we found */
      bep034_dump_record( hr );

      /* Once the first line in the first record has been parsed, return host record */
      *hostrecord = hr;
      return BEP_034_INPROGRESS;
    }
  }
}
Example #10
0
int srv_getaddrinfo(const char *node, const char *service,
		    const struct addrinfo *hints,
		    struct addrinfo **res)
{
    char *srv_name;
    size_t srv_name_size;
    char tgt_port[6];
#ifdef WIN32
    PDNS_RECORD resp, entry;
    char *tgt_name;
#else
    char tgt_name[BINKD_FQDNLEN + 1];
    unsigned char resp[SRVGAI_DNSRESPLEN];
    ns_msg nsb;
    ns_rr rrb;
    int rlen, i, rrlen;
    const unsigned char *p;
    struct in_addr dummy_addr;
#endif
    int rc;
    struct addrinfo *ai, **ai_last = res;

    /* we need sensible information for all parameters */
    if (!node || (node && !*node) || !service || (service && !*service) ||
	    !hints || !res)
	return getaddrinfo(node, service, hints, res);

    /* only domain names are supported */
    if (hints->ai_flags & AI_NUMERICHOST)
	return getaddrinfo(node, service, hints, res);

    /* detect IP addresses */
    if ((hints->ai_family == AF_INET || hints->ai_family == AF_UNSPEC) && 
#ifdef WIN32
	    inet_addr(node) != INADDR_NONE
#else
	    inet_aton(node, &dummy_addr) != 0
#endif
	    )
	return getaddrinfo(node, service, hints, res);
#ifdef AF_INET6
    if ((hints->ai_family == AF_INET6 || hints->ai_family == AF_UNSPEC) && 
	    strchr(node, ':'))
	return getaddrinfo(node, service, hints, res);
#endif

    /* only named services are supported */
    if ((hints->ai_flags & AI_NUMERICSERV) || *service == '0' ||
	    atoi(service) > 0)
	return getaddrinfo(node, service, hints, res);

    /* only TCP and UDP are supported */
    if (hints->ai_socktype != SOCK_STREAM && hints->ai_socktype != SOCK_DGRAM)
	return getaddrinfo(node, service, hints, res);

    /*              _ <service>           ._  tcp . <node>           \0 */
    srv_name_size = 1 + strlen(service) + 2 + 3 + 1 + strlen(node) + 1;
    srv_name = malloc(srv_name_size);
    if (!srv_name)
	return EAI_MEMORY;

    /* construct domain name for SRV query */
    snprintf(srv_name, srv_name_size, "_%s._%s.%s", service,
	    hints->ai_socktype == SOCK_STREAM ? "tcp" : "udp", node);

#ifdef WIN32
    rc = DnsQuery(srv_name, DNS_TYPE_SRV, DNS_QUERY_STANDARD, NULL, &resp, NULL);
#else
    rlen = res_search(srv_name, ns_c_in, ns_t_srv, resp, sizeof(resp));
#endif
    free(srv_name);

    /* fallback if DNS query does not return a single entry */
#ifdef WIN32
    if (rc != ERROR_SUCCESS)
#else
    if (rlen < 1)
#endif
	return getaddrinfo(node, service, hints, res);

#ifndef WIN32
    /* fallback in case we cannot parse the response */
    if (ns_initparse(resp, rlen, &nsb) < 0)
	return getaddrinfo(node, service, hints, res);
#endif

    /* iterate through result set -- might be incomplete */
#ifdef WIN32
    for (entry = resp; entry != NULL; entry = entry->pNext) {
	switch (entry->wType) {
	case DNS_TYPE_SRV:
	    snprintf(tgt_port, sizeof(tgt_port), "%d", entry->Data.SRV.wPort);
	    tgt_name = entry->Data.SRV.pNameTarget;
#else
    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;

	switch (ns_rr_type(rrb)) {
	case ns_t_srv:
	    rrlen = ns_rr_rdlen(rrb);
	    if (rrlen < 8)	/* 2+2+2 and at least 2 for host */
		break;

	    /* extract host and port */
	    p = ns_rr_rdata(rrb);
	    rc = dn_expand(resp, resp+rlen, p+6, tgt_name, sizeof(tgt_name));
	    if (rc < 2)
		break;
	    snprintf(tgt_port, sizeof(tgt_port), "%u", 
		    (unsigned int)p[4] << 8 | (unsigned int)p[5]);
#endif

	    /* resolve and add to end of list */
	    if (getaddrinfo(tgt_name, tgt_port, hints, ai_last) != 0)
		break;

	    /* get end of list */
	    for (ai=*ai_last; ai != NULL; ai = ai->ai_next)
		ai_last = &(ai->ai_next);

	    break;
	default:    /* someone stupid might use CNAME */
	    break;
	}
    }

#ifdef WIN32
    /* free result set */
    DnsRecordListFree(resp, DnsFreeRecordList);
#endif

    /* fallback in case no resolution via SRV is possible */
    if (ai_last == res)
	return getaddrinfo(node, service, hints, res);

    return 0;
}
Example #11
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;
}