Beispiel #1
0
static void cares_callback(void *arg, int status, unsigned char *abuf, int alen) {
	int i;
	unsigned int ancount, nscount, arcount;
	const unsigned char *aptr;

#ifdef DEBUG
	printf("cares_callback: status=%i, alen=%i\n", status, alen);
#endif
	if (status != ARES_SUCCESS) {
		if (verbose > 1)
			printf("ares failed: %s\n", ares_strerror(status));
		return;
	}

	ancount = DNS_HEADER_ANCOUNT(abuf);
	nscount = DNS_HEADER_NSCOUNT(abuf);
	arcount = DNS_HEADER_ARCOUNT(abuf);
	
#ifdef DEBUG
	printf("ancount: %i, nscount: %i, arcount: %i\n", ancount, nscount, arcount);
#endif

	/* safety check */
	if (alen < NS_HFIXEDSZ)
		return;
	aptr = abuf + NS_HFIXEDSZ;

	aptr = skip_query(aptr, abuf, alen);

	for (i = 0; i < ancount && caadr == 0; i++) {
		if (ca_tmpname == NULL)
			aptr = parse_rr(aptr, abuf, alen);
		else
			aptr = skip_rr(aptr, abuf, alen);
	}
	if (caadr == 0) {
		for (i = 0; i < nscount; i++) {
			aptr = skip_rr(aptr, abuf, alen);
		}
		for (i = 0; i < arcount && caadr == 0; i++) {
			aptr = parse_rr(aptr, abuf, alen);
		}
	}
}
Beispiel #2
0
static bool dns_mt(const struct sk_buff *skb, struct xt_action_param *par)
#endif
{
	const struct xt_dns_info *info = par->matchinfo;

	u8 *dns;
	size_t len, offset;
	bool is_match, invert;
	u16 counts[4]; /* qdcount, ancount, nscount, arcount */
	u16 udpsize;
	int i;

	/* skip fragments */
	if (par->fragoff)
		return false;

	NFDEBUG("skb->len: %d, skb->data_len: %d, par->thoff: %d\n", skb->len, skb->data_len, par->thoff);
	/* find UDP payload */
	offset = par->thoff + sizeof(struct udphdr);
	len = skb->len - offset;
	if (len > sizeof(pktbuf)) {
		pr_warn(KBUILD_MODNAME": Packet too big. Increase MAX_MTU (size %d)\n", skb->len);
		return false;
	}
	dns = skb_header_pointer(skb, offset, len, pktbuf);
	if (dns == NULL) {
		pr_warn(KBUILD_MODNAME": skb_header_pointer failed!\n");
		return false;
	}

	/* minimum DNS query payload is 17 bytes (for "." root zone) */
	if (len < 17)
		return false;

	NFDEBUG("skb->len: %d, skb->data_len: %d, len: %zu\n", skb->len, skb->data_len, len);
	debug_dump_buf(dns, len, 0, "ipt_dns");

	/* check if we are dealing with DNS query */
	if (info->flags & XT_DNS_QUERY) {
		invert = ((info->invert_flags & XT_DNS_QUERY) != 0);
		is_match = ((dns[2] & NS_QR) == NS_QR_QUERY);
		if (is_match == invert)
			return false;
	}

	/* check if we are dealing with DNS response */
	if (info->flags & XT_DNS_RESPONSE) {
		invert = ((info->invert_flags & XT_DNS_RESPONSE) != 0);
		is_match = ((dns[2] & NS_QR) == NS_QR_RESPONSE);
		if (is_match == invert)
			return false;
	}

	/* fill counts[] with data from dns header */
	for (i=0; i<4; i++) {
		counts[i] = ntohs(((u16*)dns)[i+2]);
	}

	/* query type test */
	if (info->flags & XT_DNS_QTYPE) {
		NFDEBUG("Entering qtype match\n");
		invert = ((info->invert_flags & XT_DNS_QTYPE) != 0);
		is_match = counts[0] > 0; /* qdcount at least 1 */

		if (!is_match)
			goto qtype_out;

		/* offset is set to the first question section */
		offset = 12;
		is_match = skip_name(dns, len, &offset);
		if (!is_match)
			goto qtype_out;

		NFDEBUG("Matching qtype: %x %x %x %x\n", dns[offset-4], dns[offset-3], dns[offset-2], dns[offset-1]);
		/* match if type=info->type, class IN */
		is_match = (dns[offset-4] == 0x00) && (dns[offset-3] == info->qtype)
			&& (dns[offset-2] == 0x00) && (dns[offset-1] == 0x01);
	
	qtype_out:
		if (is_match == invert)
			return false;
	}

	/* check for EDNS0 */
	if (info->flags & XT_DNS_EDNS0) {
		invert = ((info->invert_flags & XT_DNS_EDNS0) != 0);
		is_match = counts[3] > 0; /* arcount at least 1 */
		
		offset = 12;
		/* skip query sections */
		for (i=0; i<counts[0]; i++) {
			is_match &= skip_name(dns, len, &offset);
			if (!is_match)
				break;
		}
		if (!is_match)
			goto edns0_out;

		/* skip answer and authority sections */
		for (i=0; i<(counts[1]+counts[2]); i++) {
			is_match &= skip_rr(dns, len, &offset);
			if (!is_match)
				break;
		}
		if (!is_match)
			goto edns0_out;

		/* try to find EDNS0 pseudo-RR */
		for (i=0; i<counts[3]; i++) {
			if (dns[offset] == 0 && dns[offset+1] == 0 && dns[offset+2] == 41)
				break;
			is_match &= skip_rr(dns, len, &offset);
			if (!is_match)
				break;
		}
		if (!is_match || (i == counts[3])) {
			is_match = false;
			goto edns0_out;
		}
		/* EDNS0 found */
		if (info->flags & XT_DNS_BUFSIZE) {
			/* TODO: XT_DNS_BUFSIZE inversion not implemented */
			udpsize = dns[offset+3] << 8 | dns[offset+4];
			if (udpsize < info->bufsize[0] || udpsize > info->bufsize[1]) {
				is_match = false;
				goto edns0_out;
			}
		}
		debug_dump_buf(dns, len, offset, "ipt_dns_edns0");
	edns0_out:
		if (is_match == invert)
			return false;
		
	}

	/* Nothing stopped us so far, let's accept the packet */
	return true;
}