ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/gvpe/src/vpn_dns.C
Revision: 1.4
Committed: Wed Mar 2 05:49:31 2005 UTC (19 years, 2 months ago) by pcg
Content type: text/plain
Branch: MAIN
Changes since 1.3: +349 -93 lines
Log Message:
*** empty log message ***

File Contents

# User Rev Content
1 pcg 1.1 /*
2     vpn_dns.C -- handle the dns tunnel part of the protocol.
3     Copyright (C) 2003-2004 Marc Lehmann <pcg@goof.com>
4    
5     This program is free software; you can redistribute it and/or modify
6     it under the terms of the GNU General Public License as published by
7     the Free Software Foundation; either version 2 of the License, or
8     (at your option) any later version.
9    
10     This program is distributed in the hope that it will be useful,
11     but WITHOUT ANY WARRANTY; without even the implied warranty of
12     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13     GNU General Public License for more details.
14    
15     You should have received a copy of the GNU General Public License
16     along with this program; if not, write to the Free Software
17     Foundation, Inc. 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
18     */
19    
20     #include "config.h"
21    
22     #if ENABLE_DNS
23    
24     // dns processing is EXTREMELY ugly. For obvious(?) reasons.
25     // it's a hack, use only in emergency situations please.
26    
27     #include <cstring>
28    
29     #include <sys/types.h>
30     #include <sys/socket.h>
31     #include <sys/wait.h>
32     #include <sys/uio.h>
33     #include <errno.h>
34     #include <time.h>
35     #include <unistd.h>
36     #include <fcntl.h>
37    
38     #include <map>
39    
40     #include "netcompat.h"
41    
42     #include "vpn.h"
43    
44     #define MIN_RETRY 1.
45     #define MAX_RETRY 60.
46    
47 pcg 1.3 #define MAX_OUTSTANDING 10 // max. outstanding requests
48 pcg 1.4 #define MAX_WINDOW 100 // max. for MAX_OUTSTANDING
49     #define MAX_RATE 1 // requests/s
50     #define MAX_BACKLOG (10*1024) // size of protocol backlog
51 pcg 1.1
52     /*
53    
54     protocol, in shorthand :)
55    
56 pcg 1.2 client -> server <req> ANY?
57     server -> client <req> TXT <rep>
58 pcg 1.1
59 pcg 1.2 <req> is dns64-encoded <client-id:12><recv-seqno:10>[<send-seqno:10><data>]
60     <rep> is dns64-encoded <0:12><recv-seqno:10>[<send-seqno:10><data>]
61    
62     if <client-id> is zero, the connection will be configured:
63    
64     <0:12><0:4>client-id:12><default-ttl:8><max-size:16><flags:16>
65 pcg 1.1
66     */
67    
68 pcg 1.2 #define MAX_LBL_SIZE 63
69     #define MAX_PKT_SIZE 512
70    
71     #define RR_TYPE_TXT 16
72     #define RR_TYPE_ANY 255
73     #define RR_CLASS_IN 1
74    
75     // the "_" is not valid but widely accepted (all octets should be supported, but let's be conservative)
76     struct dns64
77     {
78     static const char encode_chars[64 + 1];
79     static s8 decode_chars[256];
80    
81     static int encode_len (int bytes) { return (bytes * 8 + 5) / 6; }
82     static int decode_len (int bytes) { return (bytes * 6) / 8; }
83 pcg 1.4 static int encode (char *dst, u8 *src, int len);
84     static int decode (u8 *dst, char *src, int len);
85 pcg 1.2
86     dns64 ();
87     } dns64;
88    
89 pcg 1.4 const char dns64::encode_chars[64 + 1] = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ_-";
90 pcg 1.2 s8 dns64::decode_chars[256];
91    
92     dns64::dns64 ()
93     {
94     for (int i = 0; i < 64; i++)
95     decode_chars [encode_chars [i]] = i + 1;
96     }
97    
98 pcg 1.4 int dns64::encode (char *dst, u8 *src, int len)
99 pcg 1.2 {
100     // slow, but easy to debug
101 pcg 1.4 char *beg = dst;
102 pcg 1.2 unsigned int accum, bits = 0;
103    
104     while (len--)
105     {
106     accum <<= 8;
107     accum |= *src++;
108     bits += 8;
109    
110     while (bits >= 6)
111     {
112     *dst++ = encode_chars [(accum >> (bits - 6)) & 63];
113     bits -= 6;
114     }
115     }
116    
117     if (bits)
118     *dst++ = encode_chars [(accum << (6 - bits)) & 63];
119 pcg 1.4
120     return dst - beg;
121 pcg 1.2 }
122    
123 pcg 1.4 int dns64::decode (u8 *dst, char *src, int len)
124 pcg 1.2 {
125     // slow, but easy to debug
126 pcg 1.4 u8 *beg = dst;
127 pcg 1.2 unsigned int accum, bits = 0;
128    
129     while (len--)
130     {
131     s8 chr = decode_chars [(u8)*src++];
132    
133     if (!chr)
134     break;
135    
136     accum <<= 6;
137     accum |= chr - 1;
138     bits += 6;
139    
140     while (bits >= 8)
141     {
142     *dst++ = accum >> (bits - 8);
143     bits -= 8;
144     }
145     }
146 pcg 1.4
147     return dst - beg;
148     }
149    
150     /////////////////////////////////////////////////////////////////////////////
151    
152     struct byte_stream
153     {
154     u8 *data;
155     int maxsize;
156     int fill;
157    
158     byte_stream (int maxsize);
159     ~byte_stream ();
160    
161     bool empty () { return !fill; }
162     int size () { return fill; }
163    
164     bool put (vpn_packet *pkt);
165     vpn_packet *get ();
166    
167     u8 *begin () { return data; }
168     void remove (int count);
169     };
170    
171     byte_stream::byte_stream (int maxsize)
172     : maxsize (maxsize), fill (0)
173     {
174     data = new u8 [maxsize];
175     }
176    
177     byte_stream::~byte_stream ()
178     {
179     delete data;
180     }
181    
182     void byte_stream::remove (int count)
183     {
184     if (count > fill)
185     abort ();
186    
187     memmove (data, data + count, fill -= count);
188     }
189    
190     bool byte_stream::put (vpn_packet *pkt)
191     {
192     if (maxsize - fill < pkt->len + 2)
193     return false;
194    
195     data [fill++] = pkt->len >> 8;
196     data [fill++] = pkt->len;
197    
198     memcpy (data + fill, &((*pkt)[0]), pkt->len); fill += pkt->len;
199    
200     return true;
201     }
202    
203     vpn_packet *byte_stream::get ()
204     {
205     int len = (data [0] << 8) | data [1];
206    
207     if (fill < len + 2)
208     return 0;
209    
210     vpn_packet *pkt = new vpn_packet;
211     memcpy (&((*pkt)[0]), data + 2, len);
212     remove (len + 2);
213    
214     return pkt;
215 pcg 1.2 }
216    
217 pcg 1.3 /////////////////////////////////////////////////////////////////////////////
218    
219 pcg 1.2 #define FLAG_QUERY ( 0 << 15)
220     #define FLAG_RESPONSE ( 1 << 15)
221     #define FLAG_OP_MASK (15 << 14)
222     #define FLAG_OP_QUERY ( 0 << 11)
223     #define FLAG_AA ( 1 << 10)
224     #define FLAG_TC ( 1 << 9)
225     #define FLAG_RD ( 1 << 8)
226     #define FLAG_RA ( 1 << 7)
227     #define FLAG_RCODE_MASK (15 << 0)
228     #define FLAG_RCODE_OK ( 0 << 0)
229     #define FLAG_RCODE_FORMERR ( 1 << 0)
230     #define FLAG_RCODE_SERVFAIL ( 2 << 0)
231     #define FLAG_RCODE_NXDOMAIN ( 3 << 0)
232     #define FLAG_RCODE_REFUSED ( 5 << 0)
233    
234     #define DEFAULT_CLIENT_FLAGS (FLAG_QUERY | FLAG_OP_QUERY | FLAG_RD)
235     #define DEFAULT_SERVER_FLAGS (FLAG_RESPONSE | FLAG_OP_QUERY | FLAG_AA | FLAG_RD)
236    
237     struct dns_packet : net_packet
238     {
239     u16 id;
240     u16 flags; // QR:1 Opcode:4 AA:1 TC:1 RD:1 RA:1 Z:3 RCODE:4
241     u16 qdcount, ancount, nscount, arcount;
242    
243     u8 data[MAXSIZE - 6 * 2];
244    
245     int decode_label (char *data, int size, int &offs);
246     };
247    
248     int dns_packet::decode_label (char *data, int size, int &offs)
249     {
250     char *orig = data;
251    
252     memset (data, 0, size);
253    
254     while (offs < size - 1)
255     {
256     u8 len = (*this)[offs++];
257    
258     if (!len)
259     break;
260     else if (len < 64)
261     {
262     if (size < len + 1 || offs + len >= MAXSIZE - 1)
263     break;
264    
265     memcpy (data, &((*this)[offs]), len);
266    
267     data += len; size -= len; offs += len;
268     *data++ = '.'; size--;
269     }
270     else
271     {
272     int offs2 = ((len & 63) << 8) + (*this)[offs++];
273    
274     data += decode_label (data, size, offs2);
275     break;
276     }
277     }
278    
279     return data - orig;
280     }
281    
282 pcg 1.3 /////////////////////////////////////////////////////////////////////////////
283    
284     struct dns_req
285     {
286     dns_packet *pkt;
287     tstamp next;
288     int retry;
289 pcg 1.4 connection *conn;
290 pcg 1.3
291 pcg 1.4 dns_req (connection *c, int seqno, byte_stream *stream);
292 pcg 1.3 };
293    
294     struct dns_rep
295     {
296     };
297    
298     static u16 dns_id; // TODO: should be per-vpn
299    
300 pcg 1.4 dns_req::dns_req (connection *c, int seqno, byte_stream *stream)
301     : conn (c)
302 pcg 1.3 {
303     next = 0;
304     retry = 0;
305    
306     pkt = new dns_packet;
307    
308     pkt->id = dns_id++;
309     pkt->flags = DEFAULT_CLIENT_FLAGS;
310 pcg 1.4 pkt->qdcount = htons (1);
311 pcg 1.3 pkt->ancount = 0;
312     pkt->nscount = 0;
313     pkt->arcount = 0;
314    
315 pcg 1.4 int offs = 6*2;
316     int dlen = 255 - strlen (THISNODE->domain) - 1; // here we always have room for the max. label length
317    
318     u8 lbl[64]; //D
319     char enc[65];
320     int lbllen = 3;
321     lbl[0] = c->conf->id; //D
322     lbl[1] = seqno >> 8; //D
323     lbl[2] = seqno; //D
324    
325     while (dlen > 0)
326     {
327     int sndlen = dlen;
328    
329     if (sndlen + lbllen > dns64::decode_len (MAX_LBL_SIZE))
330     sndlen = dns64::decode_len (MAX_LBL_SIZE) - lbllen;
331    
332     if (sndlen > stream->size ())
333     sndlen = stream->size ();
334    
335     if (sndlen + lbllen == 0)
336     break;
337    
338     memcpy (lbl + lbllen, stream->begin (), sndlen);
339     stream->remove (sndlen);
340     lbllen += sndlen;
341    
342     dns64::encode (enc, lbl, lbllen);
343    
344     int elen = dns64::encode_len (lbllen);
345     (*pkt)[offs++] = elen;
346     memcpy (&((*pkt)[offs]), enc, elen);
347     offs += elen;
348     dlen -= elen + 1;
349    
350     lbllen = 0;
351     }
352    
353     const char *suffix = THISNODE->domain;
354 pcg 1.3
355 pcg 1.4 // add tunnel domain
356     for (;;)
357     {
358     const char *end = strchr (suffix, '.');
359    
360     if (!end)
361     end = suffix + strlen (suffix);
362    
363     int len = end - suffix;
364    
365     (*pkt)[offs++] = len;
366     memcpy (&((*pkt)[offs]), suffix, len);
367     offs += len;
368    
369     if (!*end)
370     break;
371    
372     suffix = end + 1;
373     }
374    
375     (*pkt)[offs++] = 0;
376     (*pkt)[offs++] = RR_TYPE_ANY >> 8; (*pkt)[offs++] = RR_TYPE_ANY;
377     (*pkt)[offs++] = RR_CLASS_IN >> 8; (*pkt)[offs++] = RR_CLASS_IN;
378    
379     pkt->len = offs;
380    
381     c->vpn->dns_sndpq.push_back (this);
382 pcg 1.3 }
383    
384     /////////////////////////////////////////////////////////////////////////////
385    
386 pcg 1.2 struct dns_cfg
387     {
388     u8 id1, id2, id3;
389     u8 def_ttl;
390     u8 unused1;
391     u16 max_size;
392     u8 flags1, flags2;
393     };
394    
395 pcg 1.4 dns_packet *
396     vpn::dnsv4_server (dns_packet *pkt)
397 pcg 1.2 {
398 pcg 1.4 u16 flags = ntohs (pkt->flags);
399 pcg 1.2
400 pcg 1.4 //memcpy (&((*rep)[0]), &((*pkt)[0]), pkt->len);
401     int offs = 6 * 2; // skip header
402 pcg 1.2
403 pcg 1.4 pkt->flags = htons (DEFAULT_SERVER_FLAGS | FLAG_RCODE_FORMERR);
404 pcg 1.2
405 pcg 1.4 if (!(flags & (FLAG_RESPONSE | FLAG_OP_MASK | FLAG_TC))
406     && pkt->qdcount == htons (1))
407     {
408     char qname[MAXSIZE];
409     int qlen = pkt->decode_label ((char *)qname, MAXSIZE - offs, offs);
410    
411     printf ("rcvd packet len %d, id%04x flags%04x q%04x a%04x n%04x a%04x <%s>\n", pkt->len,
412     pkt->id, flags, pkt->qdcount, pkt->ancount, pkt->nscount, pkt->arcount, qname);//D
413    
414     u16 qtype = (*pkt) [offs++] << 8; qtype |= (*pkt) [offs++];
415     u16 qclass = (*pkt) [offs++] << 8; qclass |= (*pkt) [offs++];
416 pcg 1.2
417 pcg 1.4 pkt->qdcount = htons (1);
418     pkt->ancount = 0;
419     pkt->nscount = 0; // should be self, as other nameservers reply like this
420     pkt->arcount = 0; // a record for self, as other nameservers reply like this
421 pcg 1.2
422 pcg 1.4 pkt->flags = htons (DEFAULT_SERVER_FLAGS | FLAG_RCODE_NXDOMAIN);
423 pcg 1.2
424 pcg 1.4 int dlen = strlen (THISNODE->domain);
425 pcg 1.2
426 pcg 1.4 if (qclass == RR_CLASS_IN
427     && (qtype == RR_TYPE_ANY || qtype == RR_TYPE_TXT)
428     && qlen > dlen + 1
429     && !memcmp (qname + qlen - dlen - 1, THISNODE->domain, dlen))
430 pcg 1.2 {
431 pcg 1.4 // correct class, domain, parse
432     u8 data[MAXSIZE];
433     int datalen = dns64::decode (data, qname, qlen - dlen - 1);
434 pcg 1.2
435 pcg 1.4 for (int i = 0; i < datalen; i++)
436     printf ("%02x ", data[i]);
437     printf ("\n");
438 pcg 1.2
439 pcg 1.4
440    
441    
442     #if 0
443     // now generate reply
444     rep->ancount = htons (1); // one answer RR
445     rep->flags = htons (DEFAULT_SERVER_FLAGS | FLAG_RCODE_OK);
446    
447     (*rep) [offs++] = 0xc0;
448     (*rep) [offs++] = 6 * 2; // same as in query section
449    
450     (*rep) [offs++] = RR_TYPE_TXT >> 8; (*rep) [offs++] = RR_TYPE_TXT;
451     (*rep) [offs++] = RR_CLASS_IN >> 8; (*rep) [offs++] = RR_CLASS_IN;
452    
453     (*rep) [offs++] = 0; (*rep) [offs++] = 0;
454     (*rep) [offs++] = 0; (*rep) [offs++] = 0; // TTL
455 pcg 1.2
456 pcg 1.4 int dlen = MAX_PKT_SIZE - offs - 2;
457 pcg 1.2
458 pcg 1.4 printf ("we have room for %d bytes\n", dlen);
459 pcg 1.2
460 pcg 1.4 int rdlen_offs = offs += 2;
461 pcg 1.2
462 pcg 1.4 u8 txt[255];
463     txt[0] = 0;
464     txt[1] = 0;
465 pcg 1.2
466 pcg 1.4 int txtlen = 2;
467 pcg 1.2
468 pcg 1.4 while (dlen > 1)
469     {
470     int sndlen = --dlen;
471 pcg 1.2
472 pcg 1.4 if (sndlen + txtlen > 255)
473     sndlen = 255 - txtlen;
474 pcg 1.2
475 pcg 1.4 sndlen = 0;
476 pcg 1.2
477 pcg 1.4 (*rep)[offs++] = sndlen + txtlen;
478     memcpy (&((*rep)[offs]), txt, txtlen);
479     offs += txtlen;
480 pcg 1.2
481 pcg 1.4 //if (sndlen + txtlen > dns_snddq.
482 pcg 1.2 }
483    
484 pcg 1.4 int rdlen = offs - rdlen_offs;
485    
486     (*rep) [rdlen_offs - 2] = rdlen >> 8;
487     (*rep) [rdlen_offs - 1] = rdlen;
488     #endif
489 pcg 1.2 }
490 pcg 1.4 }
491    
492     pkt->len = offs;
493     return pkt;
494     }
495    
496     void
497     vpn::dnsv4_client (dns_packet *pkt)
498     {
499     u16 flags = ntohs (pkt->flags);
500     int offs = 6 * 2; // skip header
501    
502     pkt->qdcount = ntohs (pkt->qdcount);
503     pkt->ancount = ntohs (pkt->ancount);
504    
505     for (vector<dns_req *>::iterator i = dns_sndpq.begin ();
506     i != dns_sndpq.end ();
507     ++i)
508     if ((*i)->pkt->id == pkt->id)
509     {
510     connection *c = (*i)->conn;
511     printf ("GOT RESPONSE id %x %p\n", pkt->id, c);//D
512     delete *i;
513     dns_sndpq.erase (i);
514    
515     if (flags & (FLAG_RESPONSE | FLAG_OP_MASK | FLAG_TC))
516     {
517     char qname[MAXSIZE];
518    
519     while (pkt->qdcount-- && offs < MAXSIZE - 4)
520     {
521     int qlen = pkt->decode_label ((char *)qname, MAXSIZE - offs, offs);
522     offs += 4; // skip qtype, qclass
523     }
524    
525     while (pkt->ancount-- && offs < MAXSIZE - 10)
526     {
527     pkt->decode_label ((char *)qname, MAXSIZE - offs, offs);
528    
529     u16 qtype = (*pkt) [offs++] << 8; qtype |= (*pkt) [offs++];
530     u16 qclass = (*pkt) [offs++] << 8; qclass |= (*pkt) [offs++];
531     u32 ttl = (*pkt) [offs++] << 24;
532     ttl |= (*pkt) [offs++] << 16;
533     ttl |= (*pkt) [offs++] << 8;
534     ttl |= (*pkt) [offs++];
535    
536     u16 rdlen = (*pkt) [offs++] << 8; rdlen |= (*pkt) [offs++];
537    
538     printf ("REPLY %d:%d TTL %d RD %d\n", qtype, qclass, ttl, rdlen);
539    
540     offs += rdlen;
541    
542     if (MAXSIZE - offs < rdlen)
543     {
544     // decode bytes, finally
545     }
546     }
547     }
548    
549     break;
550     }
551     }
552    
553     void
554     vpn::dnsv4_ev (io_watcher &w, short revents)
555     {
556     if (revents & EVENT_READ)
557     {
558     dns_packet *pkt = new dns_packet;
559     struct sockaddr_in sa;
560     socklen_t sa_len = sizeof (sa);
561    
562     pkt->len = recvfrom (w.fd, &((*pkt)[0]), MAXSIZE, 0, (sockaddr *)&sa, &sa_len);
563    
564     if (pkt->len > 0)
565     if (THISNODE->dns_port)
566     {
567     pkt = dnsv4_server (pkt);
568     sendto (w.fd, &((*pkt)[0]), pkt->len, 0, (sockaddr *)&sa, sa_len);
569     }
570     else
571     dnsv4_client (pkt);
572 pcg 1.1 }
573     }
574    
575     bool
576 pcg 1.3 connection::send_dnsv4_packet (vpn_packet *pkt, const sockinfo &si, int tos)
577     {
578 pcg 1.4 // never initialized
579     if (!dns_snddq && !dns_rcvdq)
580     {
581     dns_rcvdq = new byte_stream (MAX_BACKLOG * 2);
582     dns_snddq = new byte_stream (MAX_BACKLOG);
583    
584     dns_rcvseq = dns_sndseq = 0;
585    
586     dns_si.set (::conf.dns_forw_host, ::conf.dns_forw_port, PROT_DNSv4);
587     }
588    
589     if (!dns_snddq->put (pkt))
590 pcg 1.3 return false;
591    
592 pcg 1.4 // start timer if neccessary
593     if (!dnsv4_tw.active)
594     dnsv4_cb (dnsv4_tw);
595 pcg 1.3
596     return true;
597     }
598    
599     void
600     connection::dnsv4_cb (time_watcher &w)
601 pcg 1.1 {
602 pcg 1.3 // check for timeouts and (re)transmit
603     tstamp next = NOW + 60;
604 pcg 1.4 dns_req *send = 0;
605 pcg 1.3
606 pcg 1.4 slog (L_NOISE, _("dnsv4, %d packets in send queue\n"), vpn->dns_sndpq.size ());
607 pcg 1.3
608 pcg 1.4 for (vector<dns_req *>::iterator i = vpn->dns_sndpq.begin ();
609     i != vpn->dns_sndpq.end ();
610 pcg 1.3 ++i)
611     {
612     dns_req *r = *i;
613    
614     if (r->next <= NOW)
615     {
616 pcg 1.4 if (!send)
617     {
618     send = r;
619    
620     slog (L_NOISE, _("dnsv4, send req %d\n"), r->pkt->id);
621     r->retry++;
622     r->next = NOW + r->retry;
623     }
624 pcg 1.3 }
625    
626     if (r->next < next)
627     next = r->next;
628     }
629    
630 pcg 1.4 if (!send
631     && vpn->dns_sndpq.size () < MAX_OUTSTANDING)
632     send = new dns_req (this, dns_sndseq++, dns_snddq);
633    
634     tstamp min_next = NOW + (1. / (tstamp)MAX_RATE);
635    
636     if (send)
637     {
638     dns_packet *pkt = send->pkt;
639    
640     next = min_next;
641    
642     sendto (vpn->dnsv4_fd, &((*pkt)[0]), pkt->len, 0, dns_si.sav4 (), dns_si.salenv4 ());
643     }
644     else if (next < min_next)
645     next = min_next;
646    
647 pcg 1.3 w.start (next);
648 pcg 1.1 }
649    
650     #endif
651