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