⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 dns_client_packet.c

📁 DNS 的实现代码
💻 C
📖 第 1 页 / 共 3 页
字号:
    return nread + (2 * sizeof(sval));}   /* end parse_dns_question() *//* * install_dns_rrecord() * * this routine will install a resource record into the DNS message at the * location specificed by the current pointer, cptr. * * return:  number of bytes used for the RR, or *         -1 to indicate an error. */static intinstall_dns_rrecord(U8 *cptr, DnsRRec *drrec){    int   i, nbytes;    U8    nbuf[NAMEMAX+1];    U16   sval;    U32   lval;#ifdef DNS_RELAY_ANSWER_SOA_NS    SOArec  *soadata;    int      nbytes1;#endif    /*     * copy the domain name into place. the name     * we get is a string, must convert it to the label     * format.     */    if ((nbytes = create_dname(drrec->r_dname, nbuf)) < 0) {        dprintf("%C: name %s not within DNS limits\n", drrec->r_dname);	return -1;    }    memcpy(cptr, nbuf, nbytes);    cptr += nbytes;    /*      * install the type, class, time to live and resource data length.      * can't assume anything is word aligned so we need to do the     * memcpy()s     */    sval = htons(drrec->r_type);    memcpy(cptr, &sval, sizeof(sval));    cptr += sizeof(sval);    sval = htons(drrec->r_class);    memcpy(cptr, &sval, sizeof(sval));    cptr += sizeof(sval);    lval = htonl(drrec->r_ttl);    memcpy(cptr, &lval, sizeof(lval));    cptr += sizeof(lval);    sval = htons(drrec->r_datalen);    memcpy(cptr, &sval, sizeof(sval));    cptr += sizeof(sval);    nbytes += (3 * sizeof(sval)) + sizeof(lval);    /* install the resource data */    switch(drrec->r_type) {    case QT_A:        for ( i = 0; i < drrec->r_datalen; i++ )            *cptr++ = drrec->r_data[i];        break;    case QT_PTR:     case QT_NS:    case QT_CNAME:        if ( create_dname(drrec->r_data, cptr) < 0 ) {	    dprintf("%C: name value %s invalid\n", drrec->r_data);	    return -1;	}        break;#ifdef DNS_RELAY_ANSWER_SOA_NS    case QT_SOA:        soadata = (SOArec *)drrec->r_data;        if ((nbytes1 = create_dname(soadata->s_mname, cptr)) < 0)        {            dprintf("NS name in SOA RR invalid: %s\n", soadata->s_mname);            return -1;        }        cptr += nbytes1;        if ((nbytes1 = create_dname(soadata->s_rname, cptr)) < 0)        {            dprintf("e-mail in SOA RR invalid: %s\n", soadata->s_rname);            return -1;        }        cptr += nbytes1;        *cptr = soadata->s_serial;        cptr++;        *cptr = soadata->s_refresh;        cptr++;        *cptr = soadata->s_retry;        cptr++;        *cptr = soadata->s_expire;        cptr++;        *cptr = soadata->s_minimum;        cptr++;        break;#endif    default:        /* something we're not ready to handle, quess, just copy data over */        for ( i = 0; i < drrec->r_datalen; i++ )            *cptr++ = drrec->r_data[i];        break;    }    return nbytes + drrec->r_datalen;}   /* end install_dns_rrecord() */    /* * parse_dns_record() * * this routine will parse a DNS resource record. first the domain name is  * parsed, then comes the type and class.  next is the time to live, 4 bytes. * then is the resource data length and the resource data.  for us the data * will be either IP addresses or domain names.  we're only going to be asking * for the IP address for a host name or asking for the host name given the * IP address.  if we get a type we don't know how to handle we just copy the * datalen number of bytes to the record structure. this condition is not  * considered an error, we return the bytes used for parsing and the next * record, if there is one, can be parsed. * * return:  number of bytes used to parse the record or, *         -1 to indicate an error. */static int parse_dns_record(U8 *dnsmsg, U8 *data, DnsRRec *drr, int bremain){    int  nread, dnread;    int  bcnt = bremain;  /* byte count, the remain bytes in the packet */    U16  sval;            /* used for 2 byte conversions */    U32  lval;            /* used for 4 byte conversions */    memset(drr->r_dname, 0, NAMEMAX+1);    if ((nread = get_dname(dnsmsg, data, drr->r_dname)) < 0) {        dprintf("%C error getting domain name\n");	return -1;    }    data += nread;    bcnt -= nread;    if ( bcnt < (int )((3 * sizeof(sval)) + sizeof(lval)) ) {        dprintf("%C parse error on DNS resource record\n");        return -1;    }    /*      * next get the type, class, time-to-live and resource data length.     * note we do memcpy()s because the data is not likely to be word     * aligned.     */    memcpy(&sval, data, sizeof(sval));    drr->r_type = ntohs(sval);    data += sizeof(sval);    nread += sizeof(sval);    memcpy(&sval, data, sizeof(sval));    drr->r_class = ntohs(sval);    data += sizeof(sval);    nread += sizeof(sval);    memcpy(&lval, data, sizeof(lval));    drr->r_ttl = ntohl(lval);    data += sizeof(lval);    nread += sizeof(lval);    memcpy(&sval, data, sizeof(sval));    drr->r_datalen = ntohs(sval);    data += sizeof(sval);    nread += sizeof(sval);    bcnt -= (3 * sizeof(sval)) + sizeof(lval);        if (drr->r_datalen > bcnt)        return -1;    /*      * get the information from the data.  currently we only handle a      * couple of different types.  if we don't recognize the type we     * just copy the data over.     */    switch(drr->r_type) {    case QT_AAAA:        /* 	 * AAAA records are returning the IPv6 address, we check that we got the	 * right length and then copy the 16 bytes over.	 */        if (drr->r_datalen != sizeof(struct in6_addr))	    return -1;            	if ((drr->r_data = dns_ip6_alloc()) == NULL) {            dprintf("%C allocation failure for r_data\n");#ifdef DNS_DEBUG	    print_resource_pool();#endif            return -1;	}	memcpy(drr->r_data, data, drr->r_datalen);	nread += drr->r_datalen;	break;            case QT_A6:        /*          * Current version supports A6 records with 0 prefix only         */        if (drr->r_datalen == sizeof(struct in6_addr) + 1 || data[0] == 0 )        {  	        if ((drr->r_data = dns_ip6_alloc()) == NULL)             {                dprintf("%C allocation failure for r_data\n");#ifdef DNS_DEBUG  	            print_resource_pool();#endif                return -1;    	    }            memcpy(drr->r_data, data + 1, sizeof(struct in6_addr));            nread += drr->r_datalen;            /* We need not take in account byte with prefix length */            drr->r_datalen--;        }        break;    case QT_A:        /* 	 * A records are returning the IP address, we check that we got the	 * right length and then copy the 4 bytes over.	 */        if (drr->r_datalen != sizeof(U32)) {	    dprintf("IP address bad length %d\n", drr->r_datalen);	    return -1;	}	if ((drr->r_data = dns_ip_alloc()) == NULL) {            dprintf("%C allocation failure for r_data\n");#ifdef DNS_DEBUG	    print_resource_pool();#endif            return -1;	}	memcpy(drr->r_data, data, drr->r_datalen);	nread += drr->r_datalen;	break;    case QT_PTR:        /* 	 * a PTR record is returning us the domain name associated with an	 * IP address.  get the name as a string.	 */	if ((drr->r_data = dns_name_alloc()) == NULL) {            dprintf("%C allocation failed for r_data\n");#ifdef DNS_DEBUG	    print_resource_pool();#endif            return -1;	}	memset(drr->r_data, 0, drr->r_datalen);        if ((dnread = get_dname(dnsmsg, data, drr->r_data)) < 0) {	    dprintf("%C could not get ptr domain name\n");	    return -1;	}	nread += drr->r_datalen;	break;    case QT_NS:        /* 	 * a NS, (name server) RR.  this contains a name formated the same as	 * as the PTR RR above.	 */	if ((drr->r_data = dns_name_alloc()) == NULL) {            dprintf("%C allocation failed for r_data\n");#ifdef DNS_DEBUG	    print_resource_pool();#endif            return -1;	}        memset(drr->r_data, 0, drr->r_datalen);	if ((dnread = get_dname(dnsmsg, data, drr->r_data)) < 0) {	    dprintf("%C could not retrieve NS name\n");	    return -1;	}	nread += drr->r_datalen;	break;    case QT_CNAME:        /* cname type.  this has the domain name we asked for in the domain	 * section of the record and the canonical name in the data section.	 */	if ((drr->r_data = dns_name_alloc()) == NULL) {            dprintf("%C allocation failed for r_data\n");#ifdef DNS_DEBUG	    print_resource_pool();#endif            return -1;	}	memset(drr->r_data, 0, drr->r_datalen);        if ((dnread = get_dname(dnsmsg, data, drr->r_data)) < 0) {	    dprintf("%C could not get CNAME data\n");	    return -1;	}	nread += drr->r_datalen;	break;    case QT_SOA:         /*          * SOA, this is used for negative caching, see RFC 2181.  we attempt to         * allocate a structure used to hold the SOA information and then call  	 * parse_soa_data() to actually handle the parsing.	 */	if ((drr->r_data = (U8 *)dns_get_SOA()) == NULL) {	    dprintf("%C allocation for SOA data failed\n");#ifdef DNS_DEBUG	    print_resource_pool();#endif            return -1;	}	if ( parse_soa_data((SOArec *)drr->r_data, dnsmsg, data) < 0 ) {	    dprintf("%C attempt to parse SOA data failed\n");	    return -1;	}	nread += drr->r_datalen;	break;    default:        /*	 * something we didn't expect?  probably we should verify the type is	 * valid.  for right now we just copy the raw data over maybe the upper	 * level will understand it.	 */        dprintf("%C unrecognized RR type %d\n", drr->r_type);	if ( drr->r_datalen < NAMEMAX ) {	    if ((drr->r_data = dns_name_alloc()) == NULL) {		dprintf("%C allocation failed for r_data\n");#ifdef DNS_DEBUG		print_resource_pool();#endif		return -1;	    }	    memcpy(drr->r_data, data, drr->r_datalen);	    nread += drr->r_datalen;	}	else {	    dprintf("%C cannot parse size too large %d\n", drr->r_datalen);	    return -1;	}	break;    }    return nread;}   /* end parse_dns_record() *//* * parse_soa_data() * * this routine will parse the SOA data and install the information in the * SOArec structure passed in.  see RFC 1035 section 3.3.13 for a description * of the format of the rdata. * * return:  number of bytes used, or *         -1 to indicate an error condition. */static intparse_soa_data(SOArec *srec, U8 *dnsmsg, U8 *data){    U32   lval;    int   nread, bcnt = 0;    memset(srec->s_mname, 0, NAMEMAX+1);    memset(srec->s_rname, 0, NAMEMAX+1);    if ((nread = get_dname(dnsmsg, data, srec->s_mname)) < 0) {        dprintf("%C error retrieving mname for SOA data\n");	return -1;    }    data += nread;    bcnt += nread;    if ((nread = get_dname(dnsmsg, data, srec->s_rname)) < 0) {        dprintf("%C error retrieving rname for SOA data\n");	return -1;    }    data += nread;    bcnt += nread;    /*     * parse the rest of the data. all the rest of the information are 4 byte     * values.  we don't know if the data is word aligned so we memcpy() it     * first.     */    memcpy(&lval, data, sizeof(lval));    srec->s_serial = ntohl(lval);    data += sizeof(lval);    nread += sizeof(lval);    memcpy(&lval, data, sizeof(lval));    srec->s_refresh = ntohl(lval);    data += sizeof(lval);    nread += sizeof(lval);    memcpy(&lval, data, sizeof(lval));    srec->s_retry = ntohl(lval);    data += sizeof(lval);    nread += sizeof(lval);        memcpy(&lval, data, sizeof(lval));    srec->s_expire = ntohl(lval);    data += sizeof(lval);    nread += sizeof(lval);    memcpy(&lval, data, sizeof(lval));    srec->s_minimum = ntohl(lval);    data += sizeof(lval);    nread += sizeof(lval);    return nread;}   /* end parse_soa_data() *//* * get_dname() * * this routine will get the domain name from the DNS message.  the domain * name in a DNS message has the following format: * * -------------------------------- * |8|hostname|9|someplace|3|com|0| * -------------------------------- * * the numbers indicate how many characters for the following label and the * zero indicates the end of the domain name.  note that the DNS messages * employ a compression scheme (RFC 1035 sec 4.1.4) which this routine takes  * into account.  see "TCP/IP Illustrated Vol 1, R. Stevens Chap 14" for a  * discussion.  * * return:  number of bytes used in parsing, or *         -1 to indicate an error. */static intget_dname(U8 *dnsmsg, U8 *data, U8 *dname){    int   noadd, nread;    U8    ccnt;    short offset;    U8    *cptr;     char  label[LABELMAX + 1];    nread = noadd = 0;    cptr = data;    ccnt = *cptr;    while ( ccnt > 0 ) {        if ( CMPBITSET(ccnt) ) {	    offset = get_offset(cptr);	    cptr = dnsmsg + offset;	    if ( !noadd )	        nread += 2;	    noadd++;	}	ccnt = get_label(cptr, label);	if ( (S8 )ccnt < 0 )            /* the cast is okay because max = 63 */	    return -1;                  /* so a valid value can't be -1 */	strcat(dname, label);	if ( !noadd )	    nread += ccnt;	cptr += ccnt;	ccnt = *cptr;    }    if ( !noadd )        nread++;    return nread;}   /* end get_dname() *//* * get_label() * * this routine will copy out a label from the DNS message.  the parameter,

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -