Beispiel #1
0
static off_t
grok_additional_for_opt_rr(const u_char *buf, int len, off_t offset, dns_message * m)
{
    int x;
    unsigned short sometype;
    unsigned short someclass;
    unsigned short us;
    char somename[MAX_QNAME_SZ];
    x = rfc1035NameUnpack(buf, len, &offset, somename, MAX_QNAME_SZ);
    if (0 != x)
	return 0;
    if (offset + 10 > len)
	return 0;
    sometype = nptohs(buf + offset);
    someclass = nptohs(buf + offset + 2);
    if (sometype == T_OPT) {
	m->edns.found = 1;
	m->edns.bufsiz = someclass;
	memcpy(&m->edns.version, buf + offset + 5, 1);
	us = nptohs(buf + offset + 6);
	m->edns.DO = (us >> 15) & 0x01;		/* RFC 3225 */
    }
Beispiel #2
0
/*
* rfc1035QueryUnpack()
* 
* Unpacks a RFC1035 Query Record into 'query' from a message buffer.
*
* Updates the new message buffer offset.
*
* Returns 0 (success) or 1 (error)
*/
static int rfc1035QueryUnpack(const char *buf, size_t sz, int *off,
				rfc1035_query * query)
{
	unsigned short s;

	if (rfc1035NameUnpack(buf, sz, off, NULL, query->name, RFC1035_MAXHOSTNAMESZ, 0)) {
		RFC1035_UNPACK_DEBUG;
		memset(query, '\0', sizeof(*query));
		return 1;
	}
	if (*off + 4 > (int) sz) {
		RFC1035_UNPACK_DEBUG;
		memset(query, '\0', sizeof(*query));
		return 1;
	}
	memcpy(&s, buf + *off, 2);
	*off += 2;
	query->qtype = ntohs(s);
	memcpy(&s, buf + *off, 2);
	*off += 2;
	query->qclass = ntohs(s);
	return 0;
}
Beispiel #3
0
static off_t
grok_question(const u_char *buf, int len, off_t offset, char *qname, unsigned short *qtype, unsigned short *qclass)
{
    char *t;
    int x;
    x = rfc1035NameUnpack(buf, len, &offset, qname, MAX_QNAME_SZ);
    if (0 != x)
	return 0;
    if ('\0' == *qname)
	strcpy(qname, ".");
    /* XXX remove special characters from QNAME */
    while ((t = strchr(qname, '\n')))
	*t = ' ';
    while ((t = strchr(qname, '\r')))
	*t = ' ';
    for (t = qname; *t; t++)
	*t = tolower(*t);
    if (offset + 4 > len)
	return 0;
    *qtype = nptohs(buf + offset);
    *qclass = nptohs(buf + offset + 2);
    offset += 4;
    return offset;
}
Beispiel #4
0
static int
rfc1035NameUnpack(const u_char *buf, size_t sz, off_t * off, char *name, int ns)
{
    off_t no = 0;
    unsigned char c;
    size_t len;
    static int loop_detect = 0;
    if (loop_detect > 2)
	return 4;		/* compression loop */
    if (ns <= 0)
	return 4;		/* probably compression loop */
    do {
	if ((*off) >= sz)
	    break;
	c = *(buf + (*off));
	if (c > 191) {
	    /* blasted compression */
	    int rc;
	    unsigned short s;
	    off_t ptr;
	    s = nptohs(buf + (*off));
	    (*off) += sizeof(s);
	    /* Sanity check */
	    if ((*off) >= sz)
		return 1;	/* message too short */
	    ptr = s & 0x3FFF;
	    /* Make sure the pointer is inside this message */
	    if (ptr >= sz)
		return 2;	/* bad compression ptr */
	    if (ptr < DNS_MSG_HDR_SZ)
		return 2;	/* bad compression ptr */
	    loop_detect++;
	    rc = rfc1035NameUnpack(buf, sz, &ptr, name + no, ns - no);
	    loop_detect--;
	    return rc;
	} else if (c > RFC1035_MAXLABELSZ) {
	    /*
	     * "(The 10 and 01 combinations are reserved for future use.)"
	     */
	    return 3;		/* reserved label/compression flags */
	    break;
	} else {
	    (*off)++;
	    len = (size_t) c;
	    if (len == 0)
		break;
	    if (len > (ns - 1))
		len = ns - 1;
	    if ((*off) + len > sz)
		return 4;	/* message is too short */
	    if (no + len + 1 > ns)
		return 5;	/* qname would overflow name buffer */
	    memcpy(name + no, buf + (*off), len);
	    (*off) += len;
	    no += len;
	    *(name + (no++)) = '.';
	}
    } while (c > 0);
    if (no > 0)
	*(name + no - 1) = '\0';
    /* make sure we didn't allow someone to overflow the name buffer */
    assert(no <= ns);
    return 0;
}
Beispiel #5
0
/*
* rfc1035RRUnpack()
* 
* Unpacks a RFC1035 Resource Record into 'RR' from a message buffer.
* The caller must free RR->rdata!
*
* Updates the new message buffer offset.
*
* Returns 0 (success) or 1 (error)
*/
static int rfc1035RRUnpack(const char *buf, size_t sz, int *off, rfc1035_rr * RR)
{
	const char *myname = "rfc1035RRUnpack";
	unsigned short s;
	unsigned int i;
	unsigned short rdlength;
	int rdata_off;

	if (rfc1035NameUnpack(buf, sz, off, NULL, RR->name, RFC1035_MAXHOSTNAMESZ, 0)) {
		RFC1035_UNPACK_DEBUG;
		memset(RR, '\0', sizeof(*RR));
		return 1;
	}
	/*
	* Make sure the remaining message has enough octets for the
	* rest of the RR fields.
	*/
	if ((*off) + 10 > (int) sz) {
		RFC1035_UNPACK_DEBUG;
		memset(RR, '\0', sizeof(*RR));
		return 1;
	}
	memcpy(&s, buf + (*off), sizeof(s));
	(*off) += sizeof(s);
	RR->type = ntohs(s);
	memcpy(&s, buf + (*off), sizeof(s));
	(*off) += sizeof(s);
	RR->tclass = ntohs(s);
	memcpy(&i, buf + (*off), sizeof(i));
	(*off) += sizeof(i);
	RR->ttl = ntohl(i);
	memcpy(&s, buf + (*off), sizeof(s));
	(*off) += sizeof(s);
	rdlength = ntohs(s);
	if ((*off) + rdlength > (int) sz) {
		/*
		* We got a truncated packet.  'dnscache' truncates UDP
		* replies at 512 octets, as per RFC 1035.
		*/
		RFC1035_UNPACK_DEBUG;
		memset(RR, '\0', sizeof(*RR));
		return 1;
	}
	RR->rdlength = rdlength;
	switch (RR->type) {
	case RFC1035_TYPE_PTR:
		RR->rdata = (char*) acl_mymalloc(RFC1035_MAXHOSTNAMESZ);
		rdata_off = *off;
		RR->rdlength = 0;	/* Filled in by rfc1035NameUnpack */
		if (rfc1035NameUnpack(buf, sz, &rdata_off, &RR->rdlength,
				RR->rdata, RFC1035_MAXHOSTNAMESZ, 0))
			return 1;
		if (rdata_off > ((*off) + rdlength)) {
			/*
			* This probably doesn't happen for valid packets, but
			* I want to make sure that NameUnpack doesn't go beyond
			* the RDATA area.
			*/
			RFC1035_UNPACK_DEBUG;
			acl_myfree(RR->rdata);
			memset(RR, '\0', sizeof(*RR));
			return 1;
		}
		break;
	case RFC1035_TYPE_A:
	default:
		RR->rdata = (char*) acl_mymalloc(rdlength);
		memcpy(RR->rdata, buf + (*off), rdlength);
		break;
	}
	(*off) += rdlength;
	if (*off > (int) sz)
		acl_msg_fatal("%s: *off(%d) > sz(%d)", myname, *off, sz);
	return 0;
}
Beispiel #6
0
/*
* rfc1035NameUnpack()
* 
* Unpacks a Name in a message buffer into a char*.
* Note 'buf' points to the beginning of the whole message,
* 'off' points to the spot where the Name begins, and 'sz'
* is the size of the whole message.  'name' must be allocated
* by the caller.
*
* Supports the RFC1035 message compression through recursion.
*
* Updates the new buffer offset.
*
* Returns 0 (success) or 1 (error)
*/
static int rfc1035NameUnpack(const char *buf, size_t sz, int *off,
				 unsigned short *rdlength, char *name, size_t ns, int rdepth)
{
	const char *myname = "rfc1035NameUnpack";
	int no = 0;
	unsigned char c;
	size_t len;

	if (ns <= 0)
		acl_msg_fatal("%s: ns(%d) <= 0", myname, ns);
	do {
		if (*off >= (int) sz)
			acl_msg_fatal("%s: *off(%d) >= sz(%d)", myname, *off, sz);
		c = *(buf + (*off));
		if (c > 191) {
			/* blasted compression */
			unsigned short s;
			int ptr;
			if (rdepth > 64)	/* infinite pointer loop */
				return 1;
			memcpy(&s, buf + (*off), sizeof(s));
			s = ntohs(s);
			(*off) += sizeof(s);
			/* Sanity check */
			if ((*off) >= (int) sz)
				return 1;
			ptr = s & 0x3FFF;
			/* Make sure the pointer is inside this message */
			if (ptr >= (int) sz)
				return 1;
			return rfc1035NameUnpack(buf, sz, &ptr, rdlength, name + no,
						ns - no, rdepth + 1);
		} else if (c > RFC1035_MAXLABELSZ) {
			/*
			* "(The 10 and 01 combinations are reserved for future use.)"
			*/
			return 1;
		} else {
			(*off)++;
			len = (size_t) c;
			if (len == 0)
				break;
			if (len > (ns - no - 1))	/* label won't fit */
				return 1;
			if ((*off) + len >= sz)	/* message is too short */
				return 1;
			memcpy(name + no, buf + (*off), len);
			(*off) += (int) len;
			no += (int) len;
			*(name + (no++)) = '.';
			if (rdlength)
				*rdlength += (unsigned short) len + 1;
		}
	} while (c > 0 && no < (int) ns);
	if (no)
		*(name + no - 1) = '\0';
	else
		*name = '\0';
	/* make sure we didn't allow someone to overflow the name buffer */
	if (no > (int) ns)
		acl_msg_fatal("%s: no(%d) > ns(%d)", myname, no, ns);
	return 0;
}