📄 dns_client_packet.c
字号:
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 + -