ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/gvpe/src/vpn_dns.C
Revision: 1.2
Committed: Tue Mar 1 04:38:21 2005 UTC (19 years, 2 months ago) by pcg
Content type: text/plain
Branch: MAIN
Changes since 1.1: +236 -7 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     #if ENABLE_HTTP_PROXY
45     # include "conf.h"
46     #endif
47    
48     #define MIN_RETRY 1.
49     #define MAX_RETRY 60.
50    
51     #define SERVER conf.dns_port
52    
53     /*
54    
55     protocol, in shorthand :)
56    
57 pcg 1.2 client -> server <req> ANY?
58     server -> client <req> TXT <rep>
59 pcg 1.1
60 pcg 1.2 <req> is dns64-encoded <client-id:12><recv-seqno:10>[<send-seqno:10><data>]
61     <rep> is dns64-encoded <0:12><recv-seqno:10>[<send-seqno:10><data>]
62    
63     if <client-id> is zero, the connection will be configured:
64    
65     <0:12><0:4>client-id:12><default-ttl:8><max-size:16><flags:16>
66 pcg 1.1
67     */
68    
69 pcg 1.2 #define MAX_LBL_SIZE 63
70     #define MAX_PKT_SIZE 512
71    
72     #define RR_TYPE_TXT 16
73     #define RR_TYPE_ANY 255
74     #define RR_CLASS_IN 1
75    
76     // the "_" is not valid but widely accepted (all octets should be supported, but let's be conservative)
77     struct dns64
78     {
79     static const char encode_chars[64 + 1];
80     static s8 decode_chars[256];
81    
82     static int encode_len (int bytes) { return (bytes * 8 + 5) / 6; }
83     static int decode_len (int bytes) { return (bytes * 6) / 8; }
84     static void encode (char *dst, u8 *src, int len);
85     static void decode (u8 *dst, char *src, int len);
86    
87     dns64 ();
88     } dns64;
89    
90     const char dns64::encode_chars[64 + 1] = "0123456789-abcdefghijklmnopqrstuvwxyz_ABCDEFGHIJKLMNOPQRSTUVWXYZ";
91     s8 dns64::decode_chars[256];
92    
93     dns64::dns64 ()
94     {
95     for (int i = 0; i < 64; i++)
96     decode_chars [encode_chars [i]] = i + 1;
97     }
98    
99     void dns64::encode (char *dst, u8 *src, int len)
100     {
101     // slow, but easy to debug
102     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     }
120    
121     void dns64::decode (u8 *dst, char *src, int len)
122     {
123     // slow, but easy to debug
124     unsigned int accum, bits = 0;
125    
126     while (len--)
127     {
128     s8 chr = decode_chars [(u8)*src++];
129    
130    
131     if (!chr)
132     break;
133    
134     accum <<= 6;
135     accum |= chr - 1;
136     bits += 6;
137    
138     while (bits >= 8)
139     {
140     *dst++ = accum >> (bits - 8);
141     bits -= 8;
142     }
143     }
144     }
145    
146     #define FLAG_QUERY ( 0 << 15)
147     #define FLAG_RESPONSE ( 1 << 15)
148     #define FLAG_OP_MASK (15 << 14)
149     #define FLAG_OP_QUERY ( 0 << 11)
150     #define FLAG_AA ( 1 << 10)
151     #define FLAG_TC ( 1 << 9)
152     #define FLAG_RD ( 1 << 8)
153     #define FLAG_RA ( 1 << 7)
154     #define FLAG_RCODE_MASK (15 << 0)
155     #define FLAG_RCODE_OK ( 0 << 0)
156     #define FLAG_RCODE_FORMERR ( 1 << 0)
157     #define FLAG_RCODE_SERVFAIL ( 2 << 0)
158     #define FLAG_RCODE_NXDOMAIN ( 3 << 0)
159     #define FLAG_RCODE_REFUSED ( 5 << 0)
160    
161     #define DEFAULT_CLIENT_FLAGS (FLAG_QUERY | FLAG_OP_QUERY | FLAG_RD)
162     #define DEFAULT_SERVER_FLAGS (FLAG_RESPONSE | FLAG_OP_QUERY | FLAG_AA | FLAG_RD)
163    
164     struct dns_packet : net_packet
165     {
166     u16 id;
167     u16 flags; // QR:1 Opcode:4 AA:1 TC:1 RD:1 RA:1 Z:3 RCODE:4
168     u16 qdcount, ancount, nscount, arcount;
169    
170     u8 data[MAXSIZE - 6 * 2];
171    
172     int decode_label (char *data, int size, int &offs);
173     };
174    
175     int dns_packet::decode_label (char *data, int size, int &offs)
176     {
177     char *orig = data;
178    
179     memset (data, 0, size);
180    
181     while (offs < size - 1)
182     {
183     u8 len = (*this)[offs++];
184    
185     if (!len)
186     break;
187     else if (len < 64)
188     {
189     if (size < len + 1 || offs + len >= MAXSIZE - 1)
190     break;
191    
192     memcpy (data, &((*this)[offs]), len);
193    
194     data += len; size -= len; offs += len;
195     *data++ = '.'; size--;
196     }
197     else
198     {
199     int offs2 = ((len & 63) << 8) + (*this)[offs++];
200    
201     data += decode_label (data, size, offs2);
202     break;
203     }
204     }
205    
206     return data - orig;
207     }
208    
209     struct dns_cfg
210     {
211     u8 id1, id2, id3;
212     u8 def_ttl;
213     u8 unused1;
214     u16 max_size;
215     u8 flags1, flags2;
216     };
217    
218     // reply to client-poll
219     void dnsv4_poll (dns_packet *pkt, int &offs)
220     {
221     int dlen = MAX_PKT_SIZE - offs - 2;
222    
223     (*pkt) [offs++] = 0;
224     (*pkt) [offs++] = 5;
225     memcpy (&((*pkt)[offs]), "\01H\02\xff\x00", 5);
226     offs += 5;
227    
228     pkt->ancount = htons (1);
229     pkt->flags = htons (DEFAULT_SERVER_FLAGS | FLAG_RCODE_OK);
230    
231     printf ("we have room for %d bytes\n", dlen);
232     }
233    
234 pcg 1.1 void
235     vpn::dnsv4_ev (io_watcher &w, short revents)
236     {
237     if (revents & EVENT_READ)
238     {
239 pcg 1.2 dns_packet *pkt = new dns_packet;
240 pcg 1.1 struct sockaddr_in sa;
241     socklen_t sa_len = sizeof (sa);
242 pcg 1.2
243     int len = recvfrom (w.fd, &((*pkt)[0]), MAXSIZE, 0, (sockaddr *)&sa, &sa_len);
244     pkt->len = len;
245    
246     u16 flags = ntohs (pkt->flags);
247    
248     if (THISNODE->dns_port)
249     {
250     // server
251     pkt->flags = htons (DEFAULT_SERVER_FLAGS | FLAG_RCODE_FORMERR);
252    
253     int offs = 6 * 2; // skip header
254    
255     if (!(flags & (FLAG_RESPONSE | FLAG_OP_MASK | FLAG_TC))
256     && pkt->qdcount == htons (1))
257     {
258     char qname[MAXSIZE];
259     int qlen = pkt->decode_label ((char *)qname, MAXSIZE, offs);
260    
261     printf ("rcvd packet len %d, id%04x flags%04x q%04x a%04x n%04x a%04x <%s>\n", len,
262     pkt->id, flags, pkt->qdcount, pkt->ancount, pkt->nscount, pkt->arcount, qname);//D
263    
264     u16 qtype = (*pkt) [offs++] << 8; qtype |= (*pkt) [offs++];
265     u16 qclass = (*pkt) [offs++] << 8; qclass |= (*pkt) [offs++];
266    
267     pkt->qdcount = htons (1);
268     pkt->ancount = 0;
269     pkt->nscount = 0; // should be self, as other nameservers reply like this
270     pkt->arcount = 0; // a record for self, as other nameservers reply like this
271    
272     pkt->flags = htons (DEFAULT_SERVER_FLAGS | FLAG_RCODE_NXDOMAIN);
273    
274     int dlen = strlen (THISNODE->domain);
275    
276     if (qclass == RR_CLASS_IN
277     && (qtype == RR_TYPE_ANY || qtype == RR_TYPE_TXT)
278     && qlen > dlen + 1
279     && !memcmp (qname + qlen - dlen - 1, THISNODE->domain, dlen))
280     {
281     // correct class, now generate reply
282     pkt->ancount = htons (1); // one answer RR
283    
284     (*pkt) [offs++] = 0xc0;
285     (*pkt) [offs++] = 6 * 2; // same as in query section
286    
287     (*pkt) [offs++] = RR_TYPE_TXT >> 8; (*pkt) [offs++] = RR_TYPE_TXT;
288     (*pkt) [offs++] = RR_CLASS_IN >> 8; (*pkt) [offs++] = RR_CLASS_IN;
289    
290     (*pkt) [offs++] = 0; (*pkt) [offs++] = 0;
291     (*pkt) [offs++] = 0; (*pkt) [offs++] = 0; // TTL
292    
293     dnsv4_poll (pkt, offs);
294     printf ("correct class\n");
295     }
296     }
297    
298     sendto (w.fd, &((*pkt)[0]), offs, 0, (sockaddr *)&sa, sa_len);
299     }
300     else
301     {
302     // client
303     }
304 pcg 1.1 }
305     }
306    
307     bool
308     vpn::send_dnsv4_packet (vpn_packet *pkt, const sockinfo &si, int tos)
309     {
310     //return i->send_packet (pkt, tos);
311     }
312    
313     #endif
314