00001 /* Copyright 1998 by the Massachusetts Institute of Technology. 00002 * 00003 * Permission to use, copy, modify, and distribute this 00004 * software and its documentation for any purpose and without 00005 * fee is hereby granted, provided that the above copyright 00006 * notice appear in all copies and that both that copyright 00007 * notice and this permission notice appear in supporting 00008 * documentation, and that the name of M.I.T. not be used in 00009 * advertising or publicity pertaining to distribution of the 00010 * software without specific, written prior permission. 00011 * M.I.T. makes no representations about the suitability of 00012 * this software for any purpose. It is provided "as is" 00013 * without express or implied warranty. 00014 * 00015 * CHANGELOG: this file has been modified by Sergio Perez Alcañiz <serpeal@disca.upv.es> 00016 * Departamento de Informática de Sistemas y Computadores 00017 * Universidad Politécnica de Valencia 00018 * Valencia (Spain) 00019 * Date: April 2003 00020 * 00021 */ 00022 00023 #include "ares_private.h" 00024 #include "ares_dns.h" 00025 00026 /* Header format, from RFC 1035: 00027 * 1 1 1 1 1 1 00028 * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 00029 * +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ 00030 * | ID | 00031 * +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ 00032 * |QR| Opcode |AA|TC|RD|RA| Z | RCODE | 00033 * +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ 00034 * | QDCOUNT | 00035 * +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ 00036 * | ANCOUNT | 00037 * +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ 00038 * | NSCOUNT | 00039 * +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ 00040 * | ARCOUNT | 00041 * +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ 00042 * 00043 * AA, TC, RA, and RCODE are only set in responses. Brief description 00044 * of the remaining fields: 00045 * ID Identifier to match responses with queries 00046 * QR Query (0) or response (1) 00047 * Opcode For our purposes, always QUERY 00048 * RD Recursion desired 00049 * Z Reserved (zero) 00050 * QDCOUNT Number of queries 00051 * ANCOUNT Number of answers 00052 * NSCOUNT Number of name server records 00053 * ARCOUNT Number of additional records 00054 * 00055 * Question format, from RFC 1035: 00056 * 1 1 1 1 1 1 00057 * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 00058 * +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ 00059 * | | 00060 * / QNAME / 00061 * / / 00062 * +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ 00063 * | QTYPE | 00064 * +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ 00065 * | QCLASS | 00066 * +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ 00067 * 00068 * The query name is encoded as a series of labels, each represented 00069 * as a one-byte length (maximum 63) followed by the text of the 00070 * label. The list is terminated by a label of length zero (which can 00071 * be thought of as the root domain). 00072 */ 00073 00074 int ares_mkquery(const char *name, int dnsclass, int type, unsigned short id, 00075 int rd, unsigned char **buf, int *buflen) 00076 { 00077 int len; 00078 unsigned char *q; 00079 const char *p; 00080 00081 /* Compute the length of the encoded name so we can check buflen. 00082 * Start counting at 1 for the zero-length label at the end. */ 00083 len = 1; 00084 for (p = name; *p; p++) 00085 { 00086 if (*p == '\\' && *(p + 1) != 0) 00087 p++; 00088 len++; 00089 } 00090 /* If there are n periods in the name, there are n + 1 labels, and 00091 * thus n + 1 length fields, unless the name is empty or ends with a 00092 * period. So add 1 unless name is empty or ends with a period. 00093 */ 00094 if (*name && *(p - 1) != '.') 00095 len++; 00096 00097 *buflen = len + HFIXEDSZ + QFIXEDSZ; 00098 *buf = malloc(*buflen); 00099 if (!*buf) 00100 return ARES_ENOMEM; 00101 00102 /* Set up the header. */ 00103 q = *buf; 00104 memset(q, 0, HFIXEDSZ); 00105 DNS_HEADER_SET_QID(q, id); 00106 DNS_HEADER_SET_OPCODE(q, QUERY); 00107 DNS_HEADER_SET_RD(q, (rd) ? 1 : 0); 00108 DNS_HEADER_SET_QDCOUNT(q, 1); 00109 00110 /* A name of "." is a screw case for the loop below, so adjust it. */ 00111 if (strcmp(name, ".") == 0) 00112 name++; 00113 00114 /* Start writing out the name after the header. */ 00115 q += HFIXEDSZ; 00116 while (*name) 00117 { 00118 if (*name == '.') 00119 return ARES_EBADNAME; 00120 00121 /* Count the number of bytes in this label. */ 00122 len = 0; 00123 for (p = name; *p && *p != '.'; p++) 00124 { 00125 if (*p == '\\' && *(p + 1) != 0) 00126 p++; 00127 len++; 00128 } 00129 if (len > MAXLABEL) 00130 return ARES_EBADNAME; 00131 00132 /* Encode the length and copy the data. */ 00133 *q++ = len; 00134 for (p = name; *p && *p != '.'; p++) 00135 { 00136 if (*p == '\\' && *(p + 1) != 0) 00137 p++; 00138 *q++ = *p; 00139 } 00140 00141 /* Go to the next label and repeat, unless we hit the end. */ 00142 if (!*p) 00143 break; 00144 name = p + 1; 00145 } 00146 00147 /* Add the zero-length label at the end. */ 00148 *q++ = 0; 00149 00150 /* Finish off the question with the type and class. */ 00151 DNS_QUESTION_SET_TYPE(q, type); 00152 DNS_QUESTION_SET_CLASS(q, dnsclass); 00153 00154 return ARES_SUCCESS; 00155 }