1#include <sys/socket.h> 2#include <netinet/in.h> 3#include <arpa/inet.h> 4#include <string.h> 5 6#include "dns_decode.h" 7 8/* 9 * The following macros set num to the host version of the number pointed to 10 * by buf and increment the buff (usually a pointer) and count (usually and 11 * int counter) 12 */ 13#if 0 //CMC for alignment 8/3/2001 14#define SET_UINT16( num, buff) num = htons(*(uint16*)*buff); *buff += 2 15#define SET_UINT32( num, buff) num = htonl(*(uint32*)*buff); *buff += 4 16#else 17#define SET_UINT16( num, buff) \ 18{ unsigned char tmp[2], i; \ 19 for ( i = 0; i < 2; i++ ) \ 20 tmp[i] = *(((unsigned char*)*buff)+i); \ 21 num = htons(*(uint16*)&tmp); \ 22 *buff += 2; \ 23} 24#define SET_UINT32( num, buff) \ 25{ unsigned char tmp[4], i; \ 26 for ( i = 0; i < 4; i++ ) \ 27 tmp[i] = *(((unsigned char*)*buff)+i); \ 28 num = htons(*(uint32*)&tmp); \ 29 *buff += 4; \ 30} 31#endif 32/*****************************************************************************/ 33/* reverse lookups encode the IP in reverse, so we need to turn it around 34 * example 2.0.168.192.in-addr.arpa => 192.168.0.2 35 * this function only returns the first four numbers in the IP 36 * NOTE: it assumes that name points to a buffer BUF_SIZE long 37 */ 38void dns_decode_reverse_name(char *name) 39{ 40 char temp[NAME_SIZE]; 41 int i,j,k; 42 43 k = 0; 44 45 //modified by CMC to protect data 8/9/2001 46 for( j = 0, i = 0; j<3 && i < NAME_SIZE-2; i++){ 47 if( name[i] == '.' )j++; 48 } 49 for( ; name[i] != '.' && i < NAME_SIZE-1; i++){ 50 temp[k++] = name[i]; 51 } 52 if ( k == 0 ) 53 return; 54 55 temp[k++] = '.'; 56 57 name[i] = 0; 58 59 for( j = 0, i = 0; j<2; i++) if( name[i] == '.' )j++; 60 for( ; name[i] != '.'; i++) temp[k++] = name[i]; 61 temp[k++] = '.'; 62 63 for( j = 0, i = 0; j<1; i++) if( name[i] == '.' )j++; 64 for( ; name[i] != '.'; i++) temp[k++] = name[i]; 65 temp[k++] = '.'; 66 67 for( i = 0; name[i] != '.'; i++) temp[k++] = name[i]; 68 69 temp[k] = 0; 70 71 strcpy( name, temp ); 72} 73/*****************************************************************************/ 74/* Queries are encoded such that there is and integer specifying how long 75 * the next block of text will be before the actuall text. For eaxmple: 76 * www.linux.com => \03www\05linux\03com\0 77 * This function assumes that buf points to an encoded name. 78 * The name is decoded into name. Name should be at least 255 bytes long. 79 */ 80void dns_decode_name(char *name, char **buf) 81{ 82 int k, len, j; 83 84 k = 0; 85 while( **buf ){ 86 len = *(*buf)++; 87 if ( k + len >= NAME_SIZE ) //added by CMC to protect name[] 8/9/2001 88 break; 89 for( j = 0; j<len; j++) 90 name[k++] = *(*buf)++; 91 name[k++] = '.'; 92 } 93 if ( k == 0 ) k = 1; //added by CMC to protect name[] 8/9/2001 94 name[k-1] = *(*buf)++; 95} 96/*****************************************************************************/ 97/* Decodes the raw packet in buf to create a rr. Assumes buf points to the 98 * start of a rr. 99 * Note: Question rrs dont have rdatalen or rdata. Set is_question when 100 * decoding question rrs, else clear is_question 101 */ 102void dns_decode_rr(struct dns_rr *rr, char **buf, int is_question,char *header) 103{ 104 /* if the first two bits the of the name are set, then the message has been 105 compressed and so the next byte is an offset from the start of the message 106 pointing to the start of the name */ 107 if( **buf & 0xC0 ){ 108 (*buf)++; 109 header += *(*buf)++; 110 dns_decode_name( rr->name, &header ); 111 }else{ 112 /* ordinary decode name */ 113 dns_decode_name( rr->name, buf ); 114 } 115 116 SET_UINT16( rr->type, buf ); 117 SET_UINT16( rr->class, buf); 118 119 if( is_question != 1 ){ 120 SET_UINT32( rr->ttl, buf ); 121 SET_UINT16( rr->rdatalen, buf ); 122 123 if ( rr->rdatalen > NAME_SIZE ) //added by CMC for segment fault 8/3/2001 124 rr->rdatalen = NAME_SIZE; 125 memcpy( rr->data, *buf, rr->rdatalen ); 126 *buf += rr->rdatalen; 127 128 /* 129 for(i = 0; i < rr->rdatalen; i+=4 ) 130 SET_UINT32( (uint32)rr->data[i], buf ); 131 */ 132 } 133 134 if( rr->type == PTR ){ /* reverse lookup */ 135 dns_decode_reverse_name( rr->name ); 136 } 137 138} 139/*****************************************************************************/ 140/* A raw packet pointed to by buf is decoded in the assumed to be alloced 141 * dns_message structure. 142 * RETURNS: 0 143 */ 144int dns_decode_message(struct dns_message *m, char **buf) 145{ 146 int i; 147 char *header_start = *buf; 148 149 SET_UINT16( m->header.id, buf ); 150 SET_UINT16( m->header.flags.flags, buf ); 151 SET_UINT16( m->header.qdcount, buf ); 152 SET_UINT16( m->header.ancount, buf ); 153 SET_UINT16( m->header.nscount, buf ); 154 SET_UINT16( m->header.arcount, buf ); 155 156 if( m->header.ancount > 1 ){ 157 //printf("Lotsa answers\n"); 158 debug("Lotsa answers\n"); //modified by CMC 8/6/2001 159 } 160 161 /* decode all the question rrs */ 162 for( i = 0; i < m->header.qdcount && i < NUM_RRS; i++){ 163 dns_decode_rr( &m->question[i], buf, 1, header_start ); 164 } 165 /* decode all the answer rrs */ 166 for( i = 0; i < m->header.ancount && i < NUM_RRS; i++){ 167 dns_decode_rr( &m->answer[i], buf, 0, header_start ); 168 } 169 170 return 0; 171} 172/*****************************************************************************/ 173void dns_decode_request(dns_request_t *m) 174{ 175// struct in_addr *addr; 176 struct in_addr addr; 177 char *ptr; 178 int i; 179 180 m->here = m->original_buf; 181 182 dns_decode_message( &m->message, &m->here ); 183 184 185 if( m->message.question[0].type == PTR ){ 186 strncpy( m->ip, m->message.question[0].name, 20 ); 187 }else if ( m->message.question[0].type == A || 188 m->message.question[0].type == AAA){ 189 strncpy( m->cname, m->message.question[0].name, NAME_SIZE ); 190 } 191 192 /* set according to the answer */ 193 for( i = 0; i < m->message.header.ancount && i < NUM_RRS; i++){ 194 195 /* make sure we ge the same type as the query incase there are multiple 196 and unrelated answers */ 197 if( m->message.question[0].type == m->message.answer[i].type ){ 198 199 if( m->message.answer[i].type == A 200 || m->message.answer[i].type == AAA ){ 201 /* Standard lookup so convert data to an IP */ 202 #if 0 //CMC for alignment 8/3/2001 203 addr = (struct in_addr *)m->message.answer[i].data; 204 strncpy( m->ip, inet_ntoa( addr[0] ), 20 ); 205 #else 206 memcpy( &addr.s_addr, m->message.answer[i].data, 4 ); 207 strncpy( m->ip, inet_ntoa( addr ), 20 ); 208 #endif 209 break; 210 211 }else if( m->message.answer[i].type == PTR ){ 212 /* Reverse lookup so convert data to a nume */ 213 ptr = m->message.answer[i].data; 214 dns_decode_name( m->cname, &ptr ); 215 strncpy( m->ip, m->message.answer[i].name, 20 ); 216 break; 217 } 218 219 } /* if( question == answer ) */ 220 } /* for */ 221} 222 223 224 225 226 227