📄 dns_client_packet.c
字号:
/* ############################################################################ (c) Copyright Virata Limited 2001 ## Virata Limited Confidential and Proprietary## The following software source code ("Software") is strictly confidential and# is proprietary to Virata Limited ("Virata"). It may only be read, used,# copied, adapted, modified or otherwise dealt with by you if you have# entered into a confidentiality agreement with Virata and then subject to the# terms of that confidentiality agreement and any other applicable agreement# between you and Virata. If you are in any doubt as to whether you are # entitled to access, read, use, copy, adapt, modify or otherwise deal with# the Software or whether you are entitled to disclose the Software to any# other person you should contact Virata. If you have not entered into a# confidentiality agreement with Virata granting access to this Software you# should forthwith return all media, copies and printed listings containing# the Software to Virata. ## Virata reserves the right to take legal action against you should you breach# the above provisions.## If you are unsure, or to report violations, please contact # support@virata.com# ##########################################################################*//* * file: dns_client_packet.c * * description: this file contains routines used in the parsing and construction * of the DNS packet. * */#include <stdio.h>#include <string.h>#include "dns_client.h"#include "dns_client_resource.h"static int parse_dns_question(U8 *dnsmsg, U8 *data, DnsQuestion *dq, int bremain);static int parse_dns_record(U8 *dnsmsg, U8 *data, DnsRRec *drr, int bremain);static int parse_soa_data(SOArec *srec, U8 *dnsmsg, U8 *data);static int get_dname(U8 *dnsmsg, U8 *data, U8 *dname);static int get_label(U8 *data, U8 *label);static int install_dns_question(U8 *cptr, DnsQuestion *dquest);static int install_dns_rrecord(U8 *cptr, DnsRRec *drrec);static int create_dname(char *domain, char *buffer);#ifdef DNS_DEBUGvoid print_resource_record(DnsRRec *);void print_question(DnsQuestion *);void dns_string(DnsRRec *);void dns_ipaddr(DnsRRec *);void dns_default(DnsRRec *);void dns_soa(DnsRRec *);#endif/* * create_dns_message() * * this routine takes a pointer to a completed DnsMsg structure and a * pointer to a buffer to place the completed DNS message. note we're * assuming the buffer points to enough space. note that this is * important, we do not attempt to do the DNS message compression scheme. * so if you've got a lot of resource records you could overflow even * though you may not if the compression was used and we're not checking. * * return: number of bytes for the message or * -1 to indicate an error condition. */intcreate_dns_message(U8 *dnsbuffer, DnsMsg *dmsg){ int nused, i, nbytes = 0; DnsQuestion *dq = NULL; DnsRRec *rrec = NULL; U16 *sptr = (U16 *)dnsbuffer; U8 *cptr = NULL; /* * assign the values for the DNS header, this part is word aligned * but the rest of the message is not. */ *sptr = htons(dmsg->m_dnshdr.id); sptr++; *sptr = htons(dmsg->m_dnshdr.flags); sptr++; *sptr = htons(dmsg->m_dnshdr.nquest); sptr++; *sptr = htons(dmsg->m_dnshdr.nansrr); sptr++; *sptr = htons(dmsg->m_dnshdr.nauthrr); sptr++; *sptr = htons(dmsg->m_dnshdr.naddrr); sptr++; cptr = (U8 *)sptr; nbytes = sizeof(DnsHdr); /* install the questions */ i = 0; dq = dmsg->m_questions; while ( dq != NULL && i++ < dmsg->m_dnshdr.nquest ) { if ((nused = install_dns_question(cptr, dq)) < 0) { dprintf("%C error installing question\n"); return -1; } cptr += nused; nbytes += nused; dq = dq->q_next; } /* install the answers */ i = 0; rrec = dmsg->m_answers; while ( rrec != NULL && i++ < dmsg->m_dnshdr.nansrr ) { if ((nused = install_dns_rrecord(cptr, rrec)) < 0) { dprintf("%C error installing answers\n"); return -1; } cptr += nused; nbytes += nused; rrec = rrec->r_next; } /* install the authority records */ i = 0; rrec = dmsg->m_authoritys; while ( rrec != NULL && i++ < dmsg->m_dnshdr.nauthrr ) { if ((nused = install_dns_rrecord(cptr, rrec)) < 0) { dprintf("%C error installing authoritys\n"); return -1; } cptr += nused; nbytes += nused; rrec = rrec->r_next; } /* install additional records */ i = 0; rrec = dmsg->m_additionals; while ( rrec != NULL && i++ < dmsg->m_dnshdr.naddrr ) { if ((nused = install_dns_rrecord(cptr, rrec)) < 0) { dprintf("%C error installing additionals\n"); return -1; } cptr += nused; nbytes += nused; rrec = rrec->r_next; } return nbytes;} /* end create_dns_message() *//* * parse_dns_message() * * this routine will parse the DNS message. keep in mind that currently * we only handle a few resource record types. we take the DNS message * and retrieve the header information, including the flags. we parse * out the questions and all the resource records. * * dnsmsg - is the DNS message * dsize - is the number of bytes in the DNS message * dmsg - is the parsed message, we allocate the needed space for the * lists. * * return: number of bytes used during the parsing, or * -1 to indicate an error condition */intparse_dns_message(U8 *dnsmsg, int dsize, DnsMsg *dmsg){ DnsQuestion *dq = NULL; DnsRRec *rrec = NULL; int i, nread, tread, bcnt = dsize; U8 *cptr; U16 *sptr; UNUSED(dsize); /* * first get the header stuff. note we can assume the header part * is aligned so the casts are okay. can't make this assumption * elsewhere though. */ if ( dsize < (int )sizeof(DnsHdr) ) { dprintf("%C DNS message size less than DNS header\n"); dprintf("header size %d, packet size %d\n", sizeof(DnsHdr), dsize); return -1; } memset(dmsg, 0, sizeof(DnsMsg)); sptr = (U16 *)dnsmsg; dmsg->m_dnshdr.id = ntohs(*sptr); sptr++; dmsg->m_dnshdr.flags = ntohs(*sptr); sptr++; dmsg->m_dnshdr.nquest = ntohs(*sptr); sptr++; dmsg->m_dnshdr.nansrr = ntohs(*sptr); sptr++; dmsg->m_dnshdr.nauthrr = ntohs(*sptr); sptr++; dmsg->m_dnshdr.naddrr = ntohs(*sptr); sptr++; cptr = (U8 *)sptr; bcnt -= sizeof(DnsHdr); tread = sizeof(DnsHdr); /* allocate and parse the DNS questions and the resource records */ if ( dmsg->m_dnshdr.nquest > 0 ) { if ((dmsg->m_questions = dns_get_question()) == NULL) { dprintf("%C allocation failure for DnsQuestions\n");#ifdef DNS_DEBUG print_resource_pool();#endif return -1; } dq = dmsg->m_questions; if ((nread = parse_dns_question(dnsmsg, cptr, dq, bcnt)) < 0) { dprintf("%C error parsing DNS question\n"); dnsmsg_cleanup(dmsg); return -1; } cptr += nread; bcnt -= nread; tread += nread; if ( tread > dsize ) { dprintf("%C parse error on DNS packet not enough space left\n"); dnsmsg_cleanup(dmsg); return -1; } for ( i = 1; i < dmsg->m_dnshdr.nquest; i++ ) { if ((dq->q_next = dns_get_question()) == NULL) { dprintf("%C allocation failure for DnsQuestion\n");#ifdef DNS_DEBUG print_resource_pool();#endif dnsmsg_cleanup(dmsg); return -1; } if ((nread = parse_dns_question(dnsmsg, cptr, dq->q_next, bcnt)) < 0) { dprintf("%C error parsing DNS question\n"); dnsmsg_cleanup(dmsg); return -1; } cptr += nread; bcnt -= nread; tread += nread; if ( tread > dsize ) { dprintf("%C parse error on DNS packet out of space parsing questions\n"); dnsmsg_cleanup(dmsg); return -1; } dq = dq->q_next; } } /* answer RRs */ if ( dmsg->m_dnshdr.nansrr > 0 ) { if ((dmsg->m_answers = dns_get_RR()) == NULL) { dprintf("%C error allocating new answer resource record\n");#ifdef DNS_DEBUG print_resource_pool();#endif dnsmsg_cleanup(dmsg); return -1; } rrec = dmsg->m_answers; if ((nread = parse_dns_record(dnsmsg, cptr, rrec, bcnt)) < 0) { dprintf("%C error parsing answer record\n"); dnsmsg_cleanup(dmsg); return -1; } cptr += nread; bcnt -= nread; tread += nread; if ( tread > dsize ) { dprintf("%C parse error on DNS packet, not enough space for RR\n"); dnsmsg_cleanup(dmsg); return -1; } for ( i = 1; i < dmsg->m_dnshdr.nansrr; i++ ) { if ((rrec->r_next = dns_get_RR()) == NULL) { dprintf("%C could not allocate space for next answer RR\n");#ifdef DNS_DEBUG print_resource_pool();#endif dnsmsg_cleanup(dmsg); return -1; } if ((nread = parse_dns_record(dnsmsg, cptr, rrec->r_next, bcnt)) < 0) { dprintf("%C error parsing answer record\n"); dnsmsg_cleanup(dmsg); return -1; } cptr += nread; bcnt -= nread; tread += nread; if ( tread > dsize ) { dprintf("%C parse error on DNS packet, not enough space for answer RR\n"); dnsmsg_cleanup(dmsg); return -1; } rrec = rrec->r_next; } } /* authority or NS records */ if ( dmsg->m_dnshdr.nauthrr > 0 ) { if ((dmsg->m_authoritys = dns_get_RR()) == NULL) { dprintf("%C error allocating NS record\n");#ifdef DNS_DEBUG print_resource_pool();#endif dnsmsg_cleanup(dmsg); return -1; } rrec = dmsg->m_authoritys; if ((nread = parse_dns_record(dnsmsg, cptr, rrec, bcnt)) < 0) { dprintf("%C error parsing NS record\n"); dnsmsg_cleanup(dmsg); return -1; } cptr += nread; bcnt -= nread; tread += nread; if ( tread > dsize ) { dprintf("%C parse error on DNS packet, not enough space for NS RR\n"); dnsmsg_cleanup(dmsg); return -1; } for ( i = 1; i < dmsg->m_dnshdr.nauthrr; i++ ) { if ((rrec->r_next = dns_get_RR()) == NULL) { dprintf("%C error allocating next NS record\n");#ifdef DNS_DEBUG print_resource_pool();#endif dnsmsg_cleanup(dmsg); return -1; } if ((nread = parse_dns_record(dnsmsg, cptr, rrec->r_next, bcnt)) < 0) { dprintf("%C error parsing NS record\n"); dnsmsg_cleanup(dmsg); return -1; } cptr += nread; bcnt -= nread; tread += nread; if ( tread > dsize ) { dprintf("%C parse error on DNS packet, not enough space fo next NS RR\n"); dnsmsg_cleanup(dmsg); return -1; } rrec = rrec->r_next; } } /* get any additional records */ if ( dmsg->m_dnshdr.naddrr > 0 ) { if ((dmsg->m_additionals = dns_get_RR()) == NULL) { dprintf("%C error allocating additional record\n");#ifdef DNS_DEBUG print_resource_pool();#endif dnsmsg_cleanup(dmsg); return -1; } rrec = dmsg->m_additionals; if ((nread = parse_dns_record(dnsmsg, cptr, rrec, bcnt)) < 0) { dprintf("%C error parsing additional record\n"); dnsmsg_cleanup(dmsg); return -1; } cptr += nread; bcnt -= nread; tread += nread; if ( tread > dsize ) { dprintf("%C parse error on DNS packet, no space for additional RR\n"); dnsmsg_cleanup(dmsg); return -1; } for ( i = 1; i < dmsg->m_dnshdr.naddrr; i++ ) { if ((rrec->r_next = dns_get_RR()) == NULL) { dprintf("%C error allocating next additional record\n");#ifdef DNS_DEBUG print_resource_pool();#endif dnsmsg_cleanup(dmsg); return -1; } if ((nread = parse_dns_record(dnsmsg, cptr, rrec->r_next, bcnt)) < 0) { dprintf("%C error parsing next additional record\n"); dnsmsg_cleanup(dmsg); return -1; } cptr += nread; bcnt -= nread; tread += nread; if ( tread > dsize ) { dprintf("%C parse error on DNS packet, no space for next additional RR\n"); dnsmsg_cleanup(dmsg); return -1; } rrec = rrec->r_next; } } return tread;} /* end parse_dns_message() *//* * install_dns_question() * * this routine will take a pointer to the current location in the * DNS message and a pointer to the DnsQuestion structure to fill in. * * return: number of bytes used, or * -1 will indicate an error. */static intinstall_dns_question(U8 *cptr, DnsQuestion *dquest){ int nbytes; U8 nbuf[NAMEMAX+1]; U16 sval; /* short value, used for 2 byte conversion */ /* copy the domain name in. the name comes in as a string, need to * convert it to proper format. */ if ((nbytes = create_dname(dquest->q_name, nbuf)) < 0) { dprintf("%C: domain name %s not within DNS limits\n", dquest->q_name); return -1; } memcpy(cptr, nbuf, nbytes); cptr += nbytes; /* * now copy in the type and class values. note that we can't * assume stuff is word aligned so we do a memcpy here */ sval = htons(dquest->q_type); memcpy(cptr, &sval, sizeof(sval)); cptr += sizeof(sval); nbytes += sizeof(sval); sval = htons(dquest->q_class); memcpy(cptr, &sval, sizeof(sval)); nbytes += sizeof(sval); return nbytes;} /* end install_dns_question() *//* * parse_dns_question() * * this routine will parse a question from the DNS message. it will * parse out the domain name and the query type and class. the * information is returned in the DnsQuestion structure. * * return: number of bytes used to parse the question, or * -1 to indicate an error. */static intparse_dns_question(U8 *dnsmsg, U8 *data, DnsQuestion *dq, int bremain){ int nread, bcnt = bremain; /* byte count, the remaining bytes in the packet */ U16 sval; /* 2 byte value used for conversion */ /* the first thing in the question is the domain name */ memset(dq->q_name, 0, NAMEMAX+1); if ((nread = get_dname(dnsmsg, data, dq->q_name)) < 0) { dprintf("error retrieving domain name\n"); return -1; } data += nread; bcnt -= nread; if ( bcnt < (int )(2 * sizeof(sval)) ) { dprintf("%C DNS question parsing error\n"); return -1; } /* next are two two byte values, the query type and query class */ memcpy(&sval, data, sizeof(sval)); dq->q_type = ntohs(sval); data += sizeof(sval); memcpy(&sval, data, sizeof(sval)); dq->q_class = ntohs(sval);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -