1 2 /* Copyright 1998 by the Massachusetts Institute of Technology. 3 * 4 * Permission to use, copy, modify, and distribute this 5 * software and its documentation for any purpose and without 6 * fee is hereby granted, provided that the above copyright 7 * notice appear in all copies and that both that copyright 8 * notice and this permission notice appear in supporting 9 * documentation, and that the name of M.I.T. not be used in 10 * advertising or publicity pertaining to distribution of the 11 * software without specific, written prior permission. 12 * M.I.T. makes no representations about the suitability of 13 * this software for any purpose. It is provided "as is" 14 * without express or implied warranty. 15 */ 16 17 #include "ares_setup.h" 18 19 #ifdef HAVE_SYS_SOCKET_H 20 # include <sys/socket.h> 21 #endif 22 #ifdef HAVE_NETINET_IN_H 23 # include <netinet/in.h> 24 #endif 25 #ifdef HAVE_ARPA_NAMESER_H 26 # include <arpa/nameser.h> 27 #else 28 # include "nameser.h" 29 #endif 30 #ifdef HAVE_ARPA_NAMESER_COMPAT_H 31 # include <arpa/nameser_compat.h> 32 #endif 33 34 #include <stdlib.h> 35 #include <string.h> 36 #include "ares.h" 37 #include "ares_dns.h" 38 #include "ares_private.h" 39 40 /* Header format, from RFC 1035: 41 * 1 1 1 1 1 1 42 * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 43 * +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ 44 * | ID | 45 * +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ 46 * |QR| Opcode |AA|TC|RD|RA| Z | RCODE | 47 * +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ 48 * | QDCOUNT | 49 * +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ 50 * | ANCOUNT | 51 * +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ 52 * | NSCOUNT | 53 * +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ 54 * | ARCOUNT | 55 * +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ 56 * 57 * AA, TC, RA, and RCODE are only set in responses. Brief description 58 * of the remaining fields: 59 * ID Identifier to match responses with queries 60 * QR Query (0) or response (1) 61 * Opcode For our purposes, always QUERY 62 * RD Recursion desired 63 * Z Reserved (zero) 64 * QDCOUNT Number of queries 65 * ANCOUNT Number of answers 66 * NSCOUNT Number of name server records 67 * ARCOUNT Number of additional records 68 * 69 * Question format, from RFC 1035: 70 * 1 1 1 1 1 1 71 * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 72 * +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ 73 * | | 74 * / QNAME / 75 * / / 76 * +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ 77 * | QTYPE | 78 * +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ 79 * | QCLASS | 80 * +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ 81 * 82 * The query name is encoded as a series of labels, each represented 83 * as a one-byte length (maximum 63) followed by the text of the 84 * label. The list is terminated by a label of length zero (which can 85 * be thought of as the root domain). 86 */ 87 88 int ares_mkquery(const char *name, int dnsclass, int type, unsigned short id, 89 int rd, unsigned char **bufp, int *buflenp) 90 { 91 size_t len; 92 unsigned char *q; 93 const char *p; 94 size_t buflen; 95 unsigned char *buf; 96 97 /* Set our results early, in case we bail out early with an error. */ 98 *buflenp = 0; 99 *bufp = NULL; 100 101 /* Allocate a memory area for the maximum size this packet might need. +2 102 * is for the length byte and zero termination if no dots or ecscaping is 103 * used. 104 */ 105 len = strlen(name) + 2 + HFIXEDSZ + QFIXEDSZ; 106 buf = malloc(len); 107 if (!buf) 108 return ARES_ENOMEM; 109 110 /* Set up the header. */ 111 q = buf; 112 memset(q, 0, HFIXEDSZ); 113 DNS_HEADER_SET_QID(q, id); 114 DNS_HEADER_SET_OPCODE(q, QUERY); 115 if (rd) { 116 DNS_HEADER_SET_RD(q, 1); 117 } 118 else { 119 DNS_HEADER_SET_RD(q, 0); 120 } 121 DNS_HEADER_SET_QDCOUNT(q, 1); 122 123 /* A name of "." is a screw case for the loop below, so adjust it. */ 124 if (strcmp(name, ".") == 0) 125 name++; 126 127 /* Start writing out the name after the header. */ 128 q += HFIXEDSZ; 129 while (*name) 130 { 131 if (*name == '.') { 132 free(buf); 133 return ARES_EBADNAME; 134 } 135 136 /* Count the number of bytes in this label. */ 137 len = 0; 138 for (p = name; *p && *p != '.'; p++) 139 { 140 if (*p == '\\' && *(p + 1) != 0) 141 p++; 142 len++; 143 } 144 if (len > MAXLABEL) { 145 free(buf); 146 return ARES_EBADNAME; 147 } 148 149 /* Encode the length and copy the data. */ 150 *q++ = (unsigned char)len; 151 for (p = name; *p && *p != '.'; p++) 152 { 153 if (*p == '\\' && *(p + 1) != 0) 154 p++; 155 *q++ = *p; 156 } 157 158 /* Go to the next label and repeat, unless we hit the end. */ 159 if (!*p) 160 break; 161 name = p + 1; 162 } 163 164 /* Add the zero-length label at the end. */ 165 *q++ = 0; 166 167 /* Finish off the question with the type and class. */ 168 DNS_QUESTION_SET_TYPE(q, type); 169 DNS_QUESTION_SET_CLASS(q, dnsclass); 170 171 q += QFIXEDSZ; 172 173 buflen = (q - buf); 174 175 /* Reject names that are longer than the maximum of 255 bytes that's 176 * specified in RFC 1035 ("To simplify implementations, the total length of 177 * a domain name (i.e., label octets and label length octets) is restricted 178 * to 255 octets or less."). */ 179 if (buflen > (MAXCDNAME + HFIXEDSZ + QFIXEDSZ)) { 180 free(buf); 181 return ARES_EBADNAME; 182 } 183 184 /* we know this fits in an int at this point */ 185 *buflenp = (int) buflen; 186 *bufp = buf; 187 188 return ARES_SUCCESS; 189 } 190