コード例 #1
0
ファイル: res_debug.c プロジェクト: DragonQuan/minix3
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((size_t)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 {
コード例 #2
0
ファイル: res_debug.c プロジェクト: AubrCool/glibc
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 {
			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);
}
コード例 #3
0
ファイル: srv_gai.c プロジェクト: besco/binkd
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;
}
コード例 #4
0
ファイル: dns.c プロジェクト: alexandermerritt/dragonfly
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 have_mx = 0;
	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:
			have_mx = 1;
			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;

			err = add_host(pref, outname, port, &hosts, &nhosts);
			if (err == -1)
				goto err;
			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 == 0) {
		if (!have_mx) {
			/*
			 * If we didn't find any MX, use the hostname instead.
			 */
			err = add_host(0, host, port, &hosts, &nhosts);
		} else if (nhosts == 0) {
			/*
			 * We did get MX, but couldn't resolve any of them
			 * due to transient errors.
			 */
			err = 1;
		}
	}

	if (nhosts > 0) {
		qsort(hosts, nhosts, sizeof(*hosts), sort_pref);
		/* 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);
}
コード例 #5
0
ファイル: dns.c プロジェクト: Brenhilt/libpki
/*! \brief Returns a MEM STACK with the requested DNS records */
PKI_MEM_STACK *URL_get_data_dns_url(URL *url, ssize_t size) {

	PKI_MEM_STACK *ret = NULL;

#ifdef HAVE_LIBRESOLV

	int type = T_A;
	PKI_MEM *obj = NULL;

	if( (!url) || (!url->addr)) {
		return NULL;
	}

	unsigned char response[NS_PACKETSZ];

	ns_msg dnsMessage;
	ns_rr dnsRecord;

	int dnsRecordSection = ns_s_an;
	int dns_msgCount = 0;
	int len = 0;

	// Check the Type of record
	if ((type = URL_get_dns_type(url->attrs)) == -1) return NULL;

	PKI_log_debug("DNS URI: Searching for %s (%s/%d)",
		url->addr, url->attrs, type);

	if ((len = res_search(url->addr, C_IN, type, response, sizeof(response))) < 0)
	{
		// An Error Occurred
		PKI_log_err("DNS URI: search failed\n");
		return NULL;
	}

	if (ns_initparse(response, len, &dnsMessage) < 0)
	{
		// This should not happen if the record is correct
		PKI_log_err("DNS URI: can not init DNS parsing of the dnsMessage\n");
		return NULL;
	}

	len = ns_msg_count(dnsMessage, dnsRecordSection);
	PKI_log_debug("DNS_URI: msg count ==> %d\n", len);

	if (len <= 0) return NULL;

	if((ret = PKI_STACK_MEM_new()) == NULL ) {
		PKI_log_debug ("DNS URI: Memory Failure");
		return NULL;
	}

	for (dns_msgCount = 0; dns_msgCount < len; dns_msgCount++)
	{
		PKI_log_debug("DNS URI: Retrieving DNS record #%d",dns_msgCount);

		if (ns_parserr(&dnsMessage, dnsRecordSection, dns_msgCount, &dnsRecord))
		{
			// ERROR: ns_parserr failed, let's continue to the next record
			PKI_log_err("DNS URI: Can not parse record %d of %d", dns_msgCount, len);
			continue;
		}

		PKI_log_debug("DNS URI: type = %d (req: %d)\n", ns_rr_type(dnsRecord), type);

		if (type == pki_ns_t_address)
		{
			switch (ns_rr_type(dnsRecord))
			{
				case T_A:
				case T_AAAA:
				case T_CNAME:
					break;
				default:
					continue;
			}
		}
		else if (type != ns_rr_type(dnsRecord))
		{
			PKI_log_debug("DNS URI: recived type %d is different from requested (%d)", 
				type, ns_rr_type(dnsRecord));
			// continue;
		}

		// int i = 0;
		int rv = 0;
		// int len = 0;
		int offset = 0;

		char dnsRecordName[MAXDNAME];

		memset(dnsRecordName, '\x0', MAXDNAME);
		// Parse the different types of DNS records
		if ((ns_rr_type(dnsRecord) == T_A) || (ns_rr_type(dnsRecord) == T_AAAA))
		{
			// These require Translation using IPv4/IPv6 functions
			int family = AF_INET;

			if (ns_rr_type(dnsRecord) == T_A) family = AF_INET;
			else family = AF_INET6;

			if(inet_ntop(family, ns_rr_rdata(dnsRecord), dnsRecordName, 
				sizeof(dnsRecordName)) == NULL)
			{
				// Can not convert
				continue;
			}
		}
		else if ((ns_rr_type(dnsRecord) == T_CNAME) || (ns_rr_type(dnsRecord) == T_MX) ||
			(ns_rr_type(dnsRecord) == T_NS))
		{
			if (ns_rr_type(dnsRecord) == T_MX) offset = NS_INT16SZ;

			rv = ns_name_uncompress(ns_msg_base(dnsMessage), ns_msg_end(dnsMessage),
				ns_rr_rdata(dnsRecord) + offset, dnsRecordName, MAXDNAME);

			// ERROR, can not uncompress the names
			if (rv < 0) continue;
		}
		else if (ns_rr_type(dnsRecord) == T_SRV)
		{
			// This requires special handling, the format is [SHORT][SHORT][SHORT][DATA]
			// unsigned short *pri = (unsigned short *) ns_rr_rdata(dnsRecord);
			// unsigned short *weight = (unsigned short *) &(ns_rr_rdata(dnsRecord)[2]);
			// unsigned short *port = (unsigned short *) &(ns_rr_rdata(dnsRecord)[4]);

			// Shall we return the additional data too ?
			// printf("PRI : %d\n", *pri);
			// printf("WEIGHT : %d\n", ntohs(*weight));
			// printf("PORT : %d\n", ntohs(*port));

			offset = 6;
			rv = ns_name_uncompress(ns_msg_base(dnsMessage), ns_msg_end(dnsMessage),
				ns_rr_rdata(dnsRecord) + offset, dnsRecordName, MAXDNAME);

			if (rv < 0) continue;
		}
		else if (ns_rr_type(dnsRecord) == T_TXT)
		{
			// Special handling required. Format is [BYTE][DATA]
			unsigned char *p = (unsigned char *)ns_rr_rdata(dnsRecord);

			snprintf(dnsRecordName, (size_t) *p+1, "%s", &ns_rr_rdata(dnsRecord)[1]);
		}
		else
		{
			PKI_log_debug("DNS URI: record type not supported [%d]", ns_rr_type(dnsRecord));
			continue;
		}

		if((obj = PKI_MEM_new_null()) == NULL ) {
			// Memory Allocation Error, we abort
			break;
		}

		if (strlen(dnsRecordName) > 0) {
			// If it is a printable value, we add the parsed version of the
			// record
			if(PKI_MEM_add(obj, (char *) dnsRecordName, strlen(dnsRecordName)) == PKI_ERR) {
				/* ERROR in memory growth */;
				PKI_log_err("DNS URI: Memory Allocation Error");
				break;
			}
		} else {
			// The value is not parsed/parsable, we return the raw data
			// the application should know what to do with the data!
			if(PKI_MEM_add(obj, (char *) ns_rr_rdata(dnsRecord), 
					ns_rr_rdlen(dnsRecord)) == PKI_ERR) {
				/* ERROR in memory growth */;
				PKI_log_err("DNS URI: Memory Allocation Error");
				break;
			}
		}

/*
		printf("MSG Data [%d]:\n", ns_rr_rdlen(dnsRecord));
		for (i=0; i < ns_rr_rdlen(dnsRecord); i++)
		{
			unsigned char *kk;

			kk = (unsigned char *) &ns_rr_rdata(dnsRecord)[i];
			printf("%x:", *kk);
		};
		printf("\n");

		fprintf(stderr, "DEBUG: RV => %d (err: %d, %s)\n", rv, h_errno, hstrerror(h_errno));
		fprintf(stderr, "DEBUG: name => %s (%s)\n", ns_rr_name(dnsRecord), url->addr);
		fprintf(stderr, "DEBUG: value => %s\n", dnsRecordName);
		fprintf(stderr, "DEBUG: type => %d\n", ns_rr_type(dnsRecord));
		fprintf(stderr, "DEBUG: class => %d\n", ns_rr_class(dnsRecord));
*/

		PKI_STACK_MEM_push(ret, obj);

		// PKI_log_debug("DNS URI: Added object #%d to stack", PKI_STACK_MEM_elements(ret));
	}

#endif

	return ret;
};
コード例 #6
0
ファイル: cldc-dns.c プロジェクト: henrich/hail
/*
 * 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;
}
コード例 #7
0
ファイル: dowse.c プロジェクト: cryptocurrent/dowse
void dowse_output(const char *descr, iaddr from, iaddr to, uint8_t proto, int isfrag,
              unsigned sport, unsigned dport, my_bpftimeval ts,
              const u_char *pkt_copy, unsigned olen,
              const u_char *dnspkt, unsigned dnslen) {
    /* dnspkt may be NULL if IP packet does not contain a valid DNS message */

    char output[MAX_OUTPUT];

    if (dnspkt) {

        ns_msg msg;
        int qdcount;
        ns_rr rr;

        int *val;
        char *sval;

        char *extracted;
        char *resolved;
        char *from;
        int res;
        char action = 'A';

        char from_color[16];

        ns_initparse(dnspkt, dnslen, &msg);
        if (!ns_msg_getflag(msg, ns_f_qr)) return;

        /*
         * -- flags --
         * 0    1                5    6    7    8           11               15
         * +----+----------------+----+----+----+-----------+----------------+
         * | QR | Operation Code | AA | TC | RA |   Zero    |    Recode      |
         * +----+----------------+----+----+----+-----------+----------------+
         *
         * Question/Response          : ns_f_qr
         * Operation code             : ns_f_opcode
         * Authoritative Answer       : ns_f_aa
         * Truncation occurred        : ns_f_tc
         * Recursion Desired          : ns_f_rd
         * Recursion Available        : ns_f_ra
         * MBZ                        : ns_f_z
         * Authentic Data (DNSSEC)    : ns_f_ad
         * Checking Disabled (DNSSEC) : ns_f_cd
         * Response code              : ns_f_rcode
         */
        // logerr("msg: %p",msg);
        qdcount = ns_msg_count(msg, ns_s_qd);
        if (qdcount > 0 && 0 == ns_parserr(&msg, ns_s_qd, 0, &rr)) {

            // where the query comes from
            from = ia_resolv(to);

            // if its from ourselves omit it
            if(strncmp(from,hostname,MAX_DOMAIN)==0) return;
            if(own_ipv4) if(strncmp(from,own_ipv4,MAX_DOMAIN)==0) return;
            // not reverse resolved means not known by Dowse, code RED
            if(is_ip(from)) strcpy(from_color,"#FF0000");


            resolved = ns_rr_name(rr);
            // what domain is being looked up
            extracted = extract_domain(resolved);

            res = hashmap_get(visited, extracted, (void**)(&val));
            switch(res) {

                // TODO: fix malloc and strdup here as they grow as a leak on long term
            case MAP_MISSING : // never visited

                /* ==13150== 992 bytes in 248 blocks are definitely lost in loss record 45 of 49 */
                /*     ==13150==    at 0x4C28C20: malloc (vg_replace_malloc.c:296) */
                /*     ==13150==    by 0x5C3D326: dowse_output (dowse.c:417) */
                /*     ==13150==    by 0x404CAB: output (dnscap.c:2201) */
                /*     ==13150==    by 0x406779: network_pkt (dnscap.c:2164) */
                /*     ==13150==    by 0x407065: dl_pkt (dnscap.c:1608) */
                /*     ==13150==    by 0x503F5E9: ??? (in /usr/lib/x86_64-linux-gnu/libpcap.so.1.6.2) */
                /*     ==13150==    by 0x5043783: ??? (in /usr/lib/x86_64-linux-gnu/libpcap.so.1.6.2) */
                /*     ==13150==    by 0x4037E0: poll_pcaps (dnscap.c:1344) */
                /*     ==13150==    by 0x4037E0: main (dnscap.c:406) */
                val = malloc(sizeof(int));
                *val = 1; // just a placeholder for now

                /* ==13150== 3,069 bytes in 248 blocks are definitely lost in loss record 47 of 49 */
                /*       ==13150==    at 0x4C28C20: malloc (vg_replace_malloc.c:296) */
                /*       ==13150==    by 0x5511A69: strdup (strdup.c:42) */
                /*       ==13150==    by 0x5C3D34D: dowse_output (dowse.c:419) */
                /*       ==13150==    by 0x404CAB: output (dnscap.c:2201) */
                /*       ==13150==    by 0x406779: network_pkt (dnscap.c:2164) */
                /*       ==13150==    by 0x407065: dl_pkt (dnscap.c:1608) */
                /*       ==13150==    by 0x503F5E9: ??? (in /usr/lib/x86_64-linux-gnu/libpcap.so.1.6.2) */
                /*       ==13150==    by 0x5043783: ??? (in /usr/lib/x86_64-linux-gnu/libpcap.so.1.6.2) */
                /*       ==13150==    by 0x4037E0: poll_pcaps (dnscap.c:1344) */
                /*       ==13150==    by 0x4037E0: main (dnscap.c:406) */
                res = hashmap_put(visited, strdup(extracted), val);
                break;

            case MAP_OK: // already visited
                action = 'M';
                break;

                // TODO error checks
            case MAP_FULL:
            case MAP_OMEM:
                break;
            }


            // compose the path of the detected query
            // add category if listed
            if(listpath) { // add known domain list information
                res = hashmap_get(domainlist, extracted, (void**)(&sval));
                switch(res) {

                case MAP_OK:
                    /* render with the category in front of domain */
                    snprintf(output,MAX_OUTPUT,"%lu|%s|%c|%s/%s/%s",
                             ts2epoch(&ts,NULL), // from our epoch.c
                             from, action, tld, sval, extracted);
                    break;
                default:
                    /* render only the domain in root category */
                    snprintf(output,MAX_OUTPUT,"%lu|%s|%c|%s/%s",
                             ts2epoch(&ts,NULL), // from our epoch.c
                             from, action, tld, extracted);
                    break;
                }
            } else
                /* render only the domain in root category */
                snprintf(output,MAX_OUTPUT,"%lu|%s|%c|%s/%s",
                         ts2epoch(&ts,NULL), // from our epoch.c
                         from, action, tld, extracted);



            /* write to file */
            if(fileout) {
                fputs(output, fileout);
                fputc('\n',fileout);
                if(fileout) fflush(fileout);
            }

            /* print fast on console for realtime */
            if(console) {
                puts(output);
                fflush(stdout);
            }

            if(redis) {
                rreply = redisCommand(redis, "PUBLISH dns-query-channel %s", output);
                logerr("PUBLISH dns-query-channel: %s\n", rreply->str);
                freeReplyObject(rreply);
            }

        }


    }

}
コード例 #8
0
ファイル: nb_dns.c プロジェクト: Acidburn0zzz/bro
/* Returns 1 with an answer, 0 when reply was old, -1 on fatal errors */
int
nb_dns_activity(struct nb_dns_info *nd, struct nb_dns_result *nr, char *errstr)
{
	register int msglen, qtype, atype, n, i;
	register struct nb_dns_entry *ne, *lastne;
	socklen_t fromlen;
	struct sockaddr from;
	u_long msg[MAXPACKET / sizeof(u_long)];
	register char *bp, *ep;
	register char **ap, **hap;
	register u_int16_t id;
	register const u_char *rdata;
	register u_int32_t rttl = 0;	// make compiler happy.
	register struct hostent *he;
	register size_t rdlen;
	ns_msg handle;
	ns_rr rr;

	/* This comes from the second half of do_query() */
	fromlen = sizeof(from);
	msglen = recvfrom(nd->s, (char *)msg, sizeof(msg), 0, &from, &fromlen);
	if (msglen <= 0) {
		snprintf(errstr, NB_DNS_ERRSIZE, "recvfrom(): %s",
		    my_strerror(errno));
		return (-1);
	}
	if (msglen < HFIXEDSZ) {
		snprintf(errstr, NB_DNS_ERRSIZE, "recvfrom(): undersized: %d",
		    msglen);
		return (-1);
	}
	if (ns_initparse((u_char *)msg, msglen, &handle) < 0) {
		snprintf(errstr, NB_DNS_ERRSIZE, "ns_initparse(): %s",
		    my_strerror(errno));
		nr->host_errno = NO_RECOVERY;
		return (-1);
	}

	/* RES_INSECURE1 style check */
	if (_nb_dns_cmpsockaddr((struct sockaddr *)&nd->server, &from,
	    errstr) < 0) {
		nr->host_errno = NO_RECOVERY;
		return (-1);
	}

	/* Search for this request */
	lastne = NULL;
	id = ns_msg_id(handle);
	for (ne = nd->list; ne != NULL; ne = ne->next) {
		if (ne->id == id)
			break;
		lastne = ne;
	}

	/* Not an answer to a question we care about anymore */
	if (ne == NULL)
		return (0);

	/* Unlink this entry */
	if (lastne == NULL)
		nd->list = ne->next;
	else
		lastne->next = ne->next;
	ne->next = NULL;

	/* RES_INSECURE2 style check */
	/* XXX not implemented */

	/* Initialize result struct */
	memset(nr, 0, sizeof(*nr));
	nr->cookie = ne->cookie;
	qtype = ne->qtype;

	/* Deal with various errors */
	switch (ns_msg_getflag(handle, ns_f_rcode)) {

	case ns_r_nxdomain:
		nr->host_errno = HOST_NOT_FOUND;
		free(ne);
		return (1);

	case ns_r_servfail:
		nr->host_errno = TRY_AGAIN;
		free(ne);
		return (1);

	case ns_r_noerror:
		break;

	case ns_r_formerr:
	case ns_r_notimpl:
	case ns_r_refused:
	default:
		nr->host_errno = NO_RECOVERY;
		free(ne);
		return (1);
	}

	/* Loop through records in packet */
	memset(&rr, 0, sizeof(rr));
	memset(&nd->dns_hostent, 0, sizeof(nd->dns_hostent));
	he = &nd->dns_hostent.hostent;
	/* XXX no support for aliases */
	he->h_aliases = nd->dns_hostent.host_aliases;
	he->h_addr_list = nd->dns_hostent.h_addr_ptrs;
	he->h_addrtype = ne->atype;
	he->h_length = ne->asize;
	free(ne);

	bp = nd->dns_hostent.hostbuf;
	ep = bp + sizeof(nd->dns_hostent.hostbuf);
	hap = he->h_addr_list;
	ap = he->h_aliases;

	for (i = 0; i < ns_msg_count(handle, ns_s_an); i++) {
		/* Parse next record */
		if (ns_parserr(&handle, ns_s_an, i, &rr) < 0) {
			if (errno != ENODEV) {
				nr->host_errno = NO_RECOVERY;
				return (1);
			}
			/* All done */
			break;
		}

		/* Ignore records that don't answer our query (e.g. CNAMEs) */
		atype = ns_rr_type(rr);
		if (atype != qtype)
			continue;

		rdata = ns_rr_rdata(rr);
		rdlen = ns_rr_rdlen(rr);
		rttl = ns_rr_ttl(rr);
		switch (atype) {

		case T_A:
		case T_AAAA:
			if (rdlen != (unsigned int) he->h_length) {
				snprintf(errstr, NB_DNS_ERRSIZE,
				    "nb_dns_activity(): bad rdlen %d",
				    (int) rdlen);
				nr->host_errno = NO_RECOVERY;
				return (-1);
			}

			if (bp + rdlen >= ep) {
				snprintf(errstr, NB_DNS_ERRSIZE,
				    "nb_dns_activity(): overflow 1");
				nr->host_errno = NO_RECOVERY;
				return (-1);
			}
			if (nd->dns_hostent.numaddrs + 1 >= MAXADDRS) {
				snprintf(errstr, NB_DNS_ERRSIZE,
				    "nb_dns_activity(): overflow 2");
				nr->host_errno = NO_RECOVERY;
				return (-1);
			}

			memcpy(bp, rdata, rdlen);
			*hap++ = bp;
			bp += rdlen;
			++nd->dns_hostent.numaddrs;

			/* Keep looking for more A records */
			break;

		case T_TXT:
			if (bp + rdlen >= ep) {
				snprintf(errstr, NB_DNS_ERRSIZE,
				    "nb_dns_activity(): overflow 1 for txt");
				nr->host_errno = NO_RECOVERY;
				return (-1);
			}

			memcpy(bp, rdata, rdlen);
			he->h_name = bp+1; /* First char is a control character. */
			nr->hostent = he;
			nr->ttl = rttl;
			return (1);

		case T_PTR:
			n = dn_expand((const u_char *)msg,
			    (const u_char *)msg + msglen, rdata, bp, ep - bp);
			if (n < 0) {
				/* XXX return -1 here ??? */
				nr->host_errno = NO_RECOVERY;
				return (1);
			}
			he->h_name = bp;
			/* XXX check for overflow */
			bp += n;		/* returned len includes EOS */

			/* "Find first satisfactory answer" */
			nr->hostent = he;
			nr->ttl = rttl;
			return (1);
		}
	}

	nr->hostent = he;
	nr->ttl = rttl;
	return (1);
}