1 /*
2 ** Copyright (C) 2006 Olivier DEMBOUR
3 ** $Id: rr.c,v 1.6.4.3 2010/01/20 16:09:07 collignon Exp $
4 **
5 **
6 ** This program is free software; you can redistribute it and/or modify
7 ** it under the terms of the GNU General Public License as published by
8 ** the Free Software Foundation; either version 2 of the License, or
9 ** (at your option) any later version.
10 **
11 ** This program is distributed in the hope that it will be useful,
12 ** but WITHOUT ANY WARRANTY; without even the implied warranty of
13 ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14 ** GNU General Public License for more details.
15 **
16 ** You should have received a copy of the GNU General Public License
17 ** along with This program; if not, write to the Free Software
18 ** Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
19 */
20 
21 #include "list.h"
22 #include "dns.h"
23 #include "server.h"
24 #include "rr.h"
25 #include "requests.h"
26 #include "dns.h"
27 #include "debug.h"
28 
29 #include <string.h>
30 
31 static const t_rr_functions rr_function[] = {
32   { TYPE_TXT,	TYPE_TXT,	&rr_add_reply_encode,	0,	&rr_get_reply_length_encode},
33   { TYPE_KEY,	TYPE_KEY,	&rr_add_reply_raw,	0,	&rr_get_reply_length_raw},
34   //  { TYPE_A,	TYPE_CNAME,	&rr_add_reply_cname,	0,	&rr_get_reply_length_cname},
35   //  { TYPE_NS,	TYPE_NS,	0,			0,	0},
36   //  {TYPE_SIG, TYPE_SIG,	&rr_add_reply_raw,	0,	&rr_get_reply_length_raw},
37   {0,0,0,0}
38 };
39 
40 
41 /**
42  * @brief get functions pointer for decoding data
43  * @param[in] request type
44  * @retval functions pointer
45  **/
46 
get_rr_function_by_type(uint16_t type)47 const t_rr_functions		*get_rr_function_by_type(uint16_t type)
48 {
49   int			i = 0;
50 
51   while (rr_function[i].type
52 	 && (rr_function[i].type != type))
53     i++;
54   return (rr_function[i].type ? &rr_function[i] : 0);
55 }
56 
57 /**
58  * @brief add a answer in the DNS request
59  * @param[in] hdr DNS header
60  * @param[in] where memory to write
61  * @param[in] type type of request (TXT, KEY ...)
62  * @param[in] encoded_data data to put
63  * @param[in] what compress pointer to the subdomain or 0
64  * @retval rr header
65  **/
66 
rr_add_data(struct dns_hdr * hdr,void * where,uint16_t type,char * encoded_data,uint16_t what)67 void                    *rr_add_data(struct dns_hdr *hdr, void *where, uint16_t type, char *encoded_data, uint16_t what)
68 {
69   struct rr_hdr         *rr;
70 
71   PUT_16(&hdr->ancount, GET_16(&hdr->ancount)+1);
72   hdr->arcount = 0;
73   if (!what) /* std compression */
74     PUT_16(where, sizeof(struct dns_hdr) | COMPRESS_FLAG);
75   else
76     PUT_16(where, what | COMPRESS_FLAG);
77   rr = where + sizeof(uint16_t);
78   PUT_16(&rr->type, type);
79   PUT_16(&rr->klass, CLASS_IN);
80   PUT_32(&rr->ttl, 3);
81   if (encoded_data)
82     {
83       JUMP_RR_HDR(rr)[0] = 'A' +  GET_16(&hdr->ancount)-1;
84       strcpy(JUMP_RR_HDR(rr)+1, encoded_data);
85     }
86   else /* fake IP adress */
87     {
88       PUT_16(&rr->rdlength,4);
89       strcpy(JUMP_RR_HDR(rr), "AAAA");
90     }
91   return (rr);
92 }
93 /**
94  * @brief add data as a CNAME no available
95  **/
96 
rr_add_reply_cname(t_conf * conf,t_request * req,struct dns_hdr * hdr,void * where,char * encoded_data)97 void                    *rr_add_reply_cname(t_conf *conf, t_request *req, struct dns_hdr *hdr, void *where, char *encoded_data)
98 {
99   struct rr_hdr         *rr;
100   int                   len;
101   char			domain[MAX_EDNS_LEN];
102   char			*my_domain;
103 
104   /* TODO : should avoid the strcpy each time */
105   strncpy(domain, req->domain, sizeof(domain));
106   dns_encode(domain);
107 
108   my_domain = strstr((char *) (hdr+1), domain);
109   rr = rr_add_data(hdr, where, req->reply_functions->reply_type , encoded_data, 0);
110 
111   where = JUMP_RR_HDR(rr);
112   dns_encode(where);
113   len = strlen(where);
114 
115   ((char *)where)[len] = COMPRESS_FLAG_CHAR; /* add domain name */
116   ((char *)where)[len+1] = (uint16_t) (my_domain - (char *)hdr);
117   PUT_16(&rr->rdlength,len + 2);
118   /* Add fake entry  CNAME is at x.x.x.x */
119   rr = rr_add_data(hdr, where+len+2, TYPE_A, 0, JUMP_RR_HDR(rr) - (char *)hdr);
120   where = JUMP_RR_HDR(rr);
121   //  PUT_16(&rr->type, TYPE_A);
122   len = strlen(where);
123   return (where + len);
124 }
125 
126 /**
127  * @brief add data and dns_encode it
128  * @param[in] conf configuration
129  * @param[in] req request received
130  * @param[in] hdr DNS header
131  * @param[in] where memory address
132  * @param[in] encoded_data data encoded in base64
133  **/
134 
rr_add_reply_encode(t_conf * conf,t_request * req,struct dns_hdr * hdr,void * where,char * encoded_data)135 void                    *rr_add_reply_encode(t_conf *conf, t_request *req, struct dns_hdr *hdr, void *where, char *encoded_data)
136 {
137   struct rr_hdr         *rr;
138   int                   len;
139 
140   rr = rr_add_data(hdr, where, req->reply_functions->reply_type, encoded_data, 0);
141   where = JUMP_RR_HDR(rr);
142   dns_encode(where);
143   len = strlen(where) + 1; /* len + byte 0 (label data) */
144   PUT_16(&rr->rdlength,len);
145   return (where + len);
146 }
147 
148 /**
149  * @brief add data but don't dns_encode it
150  * @param[in] conf configuration
151  * @param[in] req request received
152  * @param[in] hdr DNS header
153  * @param[in] where memory address
154  * @param[in] encoded_data data encoded in base64
155  **/
156 
rr_add_reply_raw(t_conf * conf,t_request * req,struct dns_hdr * hdr,void * where,char * encoded_data)157 void                    *rr_add_reply_raw(t_conf *conf,  t_request *req, struct dns_hdr *hdr,
158 					  void *where,  char *encoded_data)
159 {
160   struct rr_hdr         *rr;
161   int                   len;
162 
163   rr = rr_add_data(hdr, where, req->reply_functions->reply_type, encoded_data, 0);
164   where =JUMP_RR_HDR(rr);
165   len = strlen(where);
166   PUT_16(&rr->rdlength,len);
167   return (where + len);
168 }
169 
rr_get_reply_length_cname(struct dns_hdr * hdr,t_simple_list * client,int query_len)170 int			rr_get_reply_length_cname(struct dns_hdr *hdr, t_simple_list *client, int query_len)
171 {
172 
173   /*
174    */
175   return (0);
176 }
177 
178 /**
179  * @brief check available length left before being encoded
180  * @param[in] client client
181  * @param[in] query_len query len
182  * @retval len available
183  **/
184 
rr_get_reply_length_encode(struct dns_hdr * hdr,t_simple_list * client,int query_len)185 int			rr_get_reply_length_encode(struct dns_hdr *hdr, t_simple_list *client, int query_len)
186 {
187   void			*end_query;
188   int			len;
189   int			total_query_len;
190 
191   if (!(end_query = jump_end_answer(hdr, query_len)))
192     return (0);
193   total_query_len = (int) (end_query - (void *)hdr);
194   len = (ENCODE_DATA_AVAILABLE(total_query_len,
195 			       strlen(JUMP_DNS_HDR(hdr)), MAX_DNS_LEN));
196 
197   if ((len > 0) && (len > PACKET_LEN + 2))
198     /* IDX + EOL = 2 bytes  */
199     len -=  (PACKET_LEN + 2);
200   else
201     len = 0;
202   if (client && client->control.mtu_size)
203     len = MIN(DECODED_LEN(client->control.mtu_size), len);
204   DPRINTF(3, "%s return %d\n", __FUNCTION__, len);
205   return (len);
206 }
207 
208 /**
209  * @brief check available length left for raw data
210  * @param[in] client client
211  * @param[in] query_len query len
212  * @retval len available
213  **/
214 
rr_get_reply_length_raw(struct dns_hdr * hdr,t_simple_list * client,int query_len)215 int			rr_get_reply_length_raw(struct dns_hdr *hdr, t_simple_list *client, int query_len)
216 {
217   char			*end_query;
218   int			len;
219   int			total_query_len;
220 
221   if (!(end_query = jump_end_answer(hdr, query_len)))
222     return (0);
223   total_query_len = (int) (end_query - (char *)hdr);
224   len = (RAW_DATA_AVAILABLE(total_query_len,
225 			    strlen(JUMP_DNS_HDR(hdr)), MAX_DNS_LEN));
226 
227   if ((len > 0) && (len > PACKET_LEN + 2))
228     /* IDX + EOL = 2 bytes  */
229     len -=  (PACKET_LEN + 2);
230   else
231     len = 0;
232   /* max mtu ? */
233   if (client && client->control.mtu_size)
234     len = MIN(client->control.mtu_size, len);
235   DPRINTF(3, "%s return %d\n", __FUNCTION__, len);
236   return (len);
237 }
238