1 /*
2  * udp.c - handle upd connections
3  *
4  * Copyright (C) 1999 Brad M. Garcia <garsh@home.com>
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 #ifdef HAVE_CONFIG_H
22 #include <config.h>
23 #endif
24 #include <errno.h>
25 #include <sys/types.h>
26 #include <sys/socket.h>
27 #include <netinet/in.h>
28 #include <arpa/inet.h>
29 #include <syslog.h>
30 #include <string.h>
31 #include <time.h>
32 #include <assert.h>
33 #include "common.h"
34 #include "relay.h"
35 #include "cache.h"
36 #include "query.h"
37 #include "domnode.h"
38 #include "check.h"
39 #include "dns.h"
40 
41 #ifndef EXCLUDE_MASTER
42 #include "master.h"
43 #endif
44 
45 /*
46  * dnssend()						22OCT99wzk
47  *
48  * Abstract: A small wrapper for send()/sendto().  If an error occurs a
49  *           message is written to syslog.
50  *
51  * Returns:  The return code from sendto().
52  */
udp_send(int sock,srvnode_t * srv,void * msg,int len)53 static int udp_send(int sock, srvnode_t *srv, void *msg, int len)
54 {
55     int	rc;
56     time_t now = time(NULL);
57     rc = sendto(sock, msg, len, 0,
58 		(const struct sockaddr *) &srv->addr,
59 		sizeof(struct sockaddr_in));
60 
61     if (rc != len) {
62 	log_msg(LOG_ERR, "sendto error: %s: ",
63 		inet_ntoa(srv->addr.sin_addr), strerror(errno));
64 	return (rc);
65     }
66     if ((srv->send_time == 0)) srv->send_time = now;
67     srv->send_count++;
68     return (rc);
69 }
70 
send2current(query_t * q,void * msg,const int len)71 int send2current(query_t *q, void *msg, const int len) {
72     /* If we have domains associated with our servers, send it to the
73        appropriate server as determined by srvr */
74   domnode_t *d;
75   assert(q != NULL);
76   assert(q->domain != NULL);
77 
78   d = q->domain;
79   while ((d->current != NULL) && (udp_send(q->sock, d->current, msg, len) != len)) {
80     if (reactivate_interval) deactivate_current(d);
81   }
82   if (d->current != NULL) {
83     return len;
84   } else return 0;
85 }
86 
87 
88 /*
89  * handle_udprequest()
90  *
91  * This function handles udp DNS requests by either replying to them (if we
92  * know the correct reply via master, caching, etc.), or forwarding them to
93  * an appropriate DNS server.
94  */
udp_handle_request()95 query_t *udp_handle_request()
96 {
97     unsigned           addr_len;
98     int                len;
99     const int          maxsize = UDP_MAXSIZE;
100     static char        msg[UDP_MAXSIZE+4];
101     struct sockaddr_in from_addr;
102     int                fwd;
103     domnode_t          *dptr;
104     query_t *q, *prev;
105 
106     /* Read in the message */
107     addr_len = sizeof(struct sockaddr_in);
108     len = recvfrom(isock, msg, maxsize, 0,
109 		   (struct sockaddr *)&from_addr, &addr_len);
110     if (len < 0) {
111 	log_debug(1, "recvfrom error %s", strerror(errno));
112 	return NULL;
113     }
114 
115     /* do some basic checking */
116     if (check_query(msg, len) < 0) return NULL;
117 
118     /* Determine how query should be handled */
119     if ((fwd = handle_query(&from_addr, msg, &len, &dptr)) < 0)
120       return NULL; /* if its bogus, just ignore it */
121 
122     /* If we already know the answer, send it and we're done */
123     if (fwd == 0) {
124 	if (sendto(isock, msg, len, 0, (const struct sockaddr *)&from_addr,
125 		   addr_len) != len) {
126 	    log_debug(1, "sendto error %s", strerror(errno));
127 	}
128 	return NULL;
129     }
130 
131 
132     /* dptr->current should never be NULL it is checked in handle_query */
133 
134     //    dnsquery_add(&from_addr, msg, len);
135     // if (!send2current(dptr, msg, len)) {
136 
137     /* rewrite msg, get id and add to list*/
138 
139     if ((prev=query_add(dptr, dptr->current, &from_addr, msg, len)) == NULL){
140       /* of some reason we could not get any new queries. we have to
141 	 drop this packet */
142       return NULL;
143     }
144     q = prev->next;
145 
146 
147     if (send2current(q, msg, len) > 0) {
148       /* add to query list etc etc */
149       return q;
150     } else {
151 
152       /* we couldn't send the query */
153 #ifndef EXCLUDE_MASTER
154       int	packetlen;
155       char	packet[maxsize+4];
156 
157       /*
158        * If we couldn't send the packet to our DNS servers,
159        * perhaps the `network is unreachable', we tell the
160        * client that we are unable to process his request
161        * now.  This will show a `No address (etc.) records
162        * available for host' in nslookup.  With this the
163        * client won't wait hang around till he gets his
164        * timeout.
165        * For this feature dnrd has to run on the gateway
166        * machine.
167        */
168 
169       if ((packetlen = master_dontknow(msg, len, packet)) > 0) {
170 	query_delete_next(prev);
171 	return NULL;
172 	if (sendto(isock, msg, len, 0, (const struct sockaddr *)&from_addr,
173 		   addr_len) != len) {
174 	  log_debug(1, "sendto error %s", strerror(errno));
175 	  return NULL;
176 	}
177       }
178 #endif
179     }
180     return q;
181 }
182 
183 /*
184  * dnsrecv()							22OCT99wzk
185  *
186  * Abstract: A small wrapper for recv()/recvfrom() with output of an
187  *           error message if needed.
188  *
189  * Returns:  A positove number indicating of the bytes received, -1 on a
190  *           recvfrom error and 0 if the received message is too large.
191  */
reply_recv(query_t * q,void * msg,int len)192 static int reply_recv(query_t *q, void *msg, int len)
193 {
194     int	rc, fromlen;
195     struct sockaddr_in from;
196 
197     fromlen = sizeof(struct sockaddr_in);
198     rc = recvfrom(q->sock, msg, len, 0,
199 		  (struct sockaddr *) &from, &fromlen);
200 
201     if (rc == -1) {
202 	log_msg(LOG_ERR, "recvfrom error: %s",
203 		inet_ntoa(q->srv->addr.sin_addr));
204 	return (-1);
205     }
206     else if (rc > len) {
207 	log_msg(LOG_NOTICE, "packet too large: %s",
208 		inet_ntoa(q->srv->addr.sin_addr));
209 	return (0);
210     }
211     else if (memcmp(&from.sin_addr, &q->srv->addr.sin_addr,
212 		    sizeof(from.sin_addr)) != 0) {
213 	log_msg(LOG_WARNING, "unexpected server: %s",
214 		inet_ntoa(from.sin_addr));
215 	return (0);
216     }
217 
218     return (rc);
219 }
220 
221 /*
222  * handle_udpreply()
223  *
224  * This function handles udp DNS requests by either replying to them (if we
225  * know the correct reply via master, caching, etc.), or forwarding them to
226  * an appropriate DNS server.
227  *
228  * Note that the mached query is prev->next and not prev.
229  */
udp_handle_reply(query_t * prev)230 void udp_handle_reply(query_t *prev)
231 {
232   //    const int          maxsize = 512; /* According to RFC 1035 */
233     static char        msg[UDP_MAXSIZE+4];
234     int                len;
235     unsigned           addr_len;
236     query_t *q = prev->next;
237 
238     log_debug(3, "handling socket %i", q->sock);
239     if ((len = reply_recv(q, msg, UDP_MAXSIZE)) < 0)
240       {
241 	log_debug(1, "dnsrecv failed: %i", len);
242 	query_delete_next(prev);
243 	return; /* recv error */
244       }
245 
246     /* do basic checking */
247     if (check_reply(q->srv, msg, len) < 0) {
248       log_debug(1, "check_reply failed");
249       query_delete_next(prev);
250       return;
251     }
252 
253     if (opt_debug) {
254 	char buf[256];
255 	snprintf_cname(msg, len, 12, buf, sizeof(buf));
256 	log_debug(3, "Received DNS reply for \"%s\"", buf);
257     }
258 
259     dump_dnspacket("reply", msg, len);
260     addr_len = sizeof(struct sockaddr_in);
261 
262     /* was this a dummy reactivate query? */
263     if (q->domain != NULL) {
264       /* no, lets cache the reply and send to client */
265       cache_dnspacket(msg, len, q->srv);
266 
267       /* set the client qid */
268       *((unsigned short *)msg) = q->client_qid;
269       log_debug(3, "Forwarding the reply to the host %s",
270 		inet_ntoa(q->client.sin_addr));
271       if (sendto(isock, msg, len, 0,
272 		 (const struct sockaddr *)&q->client,
273 		 addr_len) != len) {
274 	log_debug(1, "sendto error %s", strerror(errno));
275       }
276     } else {
277       log_debug(2, "We got a reactivation dummy reply. Cool!");
278     }
279 
280     /* this server is obviously alive, we reset the counters */
281     q->srv->send_time = 0;
282     if (q->srv->inactive) log_debug(1, "Reactivating server %s",
283 				 inet_ntoa(q->srv->addr.sin_addr));
284     q->srv->inactive = 0;
285     /* remove query from list and destroy it */
286     query_delete_next(prev);
287 }
288 
289 
290 /* send a dummy packet to a deactivated server to check if its back*/
udp_send_dummy(srvnode_t * s)291 int udp_send_dummy(srvnode_t *s) {
292   static unsigned char dnsbuf[] = {
293   /* HEADER */
294     /* we send a lookup for localhost */
295     /* will this work on a big endian system? */
296     0x00, 0x00, /* ID */
297     0x01, 0x00, /* QR|OC|AA|TC|RD -  RA|Z|RCODE  */
298     0x00, 0x01, /* QDCOUNT */
299     0x00, 0x00, /* ANCOUNT */
300     0x00, 0x00, /* NSCOUNT */
301     0x00, 0x00, /* ARCOUNT */
302 
303     9, 'l','o','c','a','l','h','o','s','t',0,  /* QNAME */
304     0x00,0x01,   /* QTYPE A record */
305     0x00,0x01   /* QCLASS: IN */
306 
307     /* in case you want to lookup root servers instead, use this: */
308     /*    0x00,       */ /* QNAME:  empty */
309     /*    0x00, 0x02, */ /* QTYPE:  a authorative name server */
310     /*    0x00, 0x01  */ /* QCLASS: IN */
311   };
312   query_t *q;
313   struct sockaddr_in srcaddr;
314 
315   /* should not happen */
316   assert(s != NULL);
317 
318   if ((q=query_add(NULL, s, &srcaddr, dnsbuf, sizeof(dnsbuf))) != NULL) {
319     int rc;
320     q = q->next; /* query add returned the query 1 before in list */
321     /* don't let those queries live too long */
322     q->ttl = reactivate_interval;
323     memset(&srcaddr, 0, sizeof(srcaddr));
324     log_debug(2, "Sending dummy id=%i to %s", ((unsigned short *)dnsbuf)[0],
325 	      inet_ntoa(s->addr.sin_addr));
326     /*  return dnssend(s, &dnsbuf, sizeof(dnsbuf)); */
327     rc=udp_send(q->sock, s, dnsbuf, sizeof(dnsbuf));
328     ((unsigned short *)dnsbuf)[0]++;
329     return rc;
330   }
331   return -1;
332 }
333