ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/gvpe/src/vpn_tcp.C
Revision: 1.27
Committed: Tue Feb 8 23:11:36 2011 UTC (13 years, 3 months ago) by root
Content type: text/plain
Branch: MAIN
CVS Tags: rel-3_0, rel-2_25, HEAD
Changes since 1.26: +6 -3 lines
Log Message:
*** empty log message ***

File Contents

# User Rev Content
1 pcg 1.1 /*
2     vpn_tcp.C -- handle the tcp part of the protocol.
3 pcg 1.26 Copyright (C) 2003-2008 Marc Lehmann <gvpe@schmorp.de>
4 pcg 1.1
5 pcg 1.12 This file is part of GVPE.
6    
7 pcg 1.26 GVPE is free software; you can redistribute it and/or modify it
8     under the terms of the GNU General Public License as published by the
9     Free Software Foundation; either version 3 of the License, or (at your
10     option) any later version.
11    
12     This program is distributed in the hope that it will be useful, but
13     WITHOUT ANY WARRANTY; without even the implied warranty of
14     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
15     Public License for more details.
16    
17     You should have received a copy of the GNU General Public License along
18     with this program; if not, see <http://www.gnu.org/licenses/>.
19    
20     Additional permission under GNU GPL version 3 section 7
21    
22     If you modify this Program, or any covered work, by linking or
23     combining it with the OpenSSL project's OpenSSL library (or a modified
24     version of that library), containing parts covered by the terms of the
25     OpenSSL or SSLeay licenses, the licensors of this Program grant you
26     additional permission to convey the resulting work. Corresponding
27     Source for a non-source form of such a combination shall include the
28     source code for the parts of OpenSSL used as well as that of the
29     covered work.
30 pcg 1.1 */
31    
32     #include "config.h"
33    
34     #if ENABLE_TCP
35    
36 pcg 1.19 // tcp processing is extremely ugly, since the gvpe protocol is simply
37 pcg 1.1 // designed for unreliable datagram networks. tcp is implemented by
38     // multiplexing packets over tcp. errors are completely ignored, as we
39 pcg 1.19 // rely on the higher level layers to time out and reconnect.
40 pcg 1.1
41     #include <cstring>
42    
43     #include <sys/types.h>
44     #include <sys/socket.h>
45     #include <sys/wait.h>
46     #include <sys/uio.h>
47     #include <errno.h>
48     #include <time.h>
49     #include <unistd.h>
50 pcg 1.9 #include <fcntl.h>
51 pcg 1.1
52     #include <map>
53 pcg 1.8
54     #include "netcompat.h"
55 pcg 1.1
56     #include "vpn.h"
57    
58 pcg 1.4 #if ENABLE_HTTP_PROXY
59     # include "conf.h"
60     #endif
61    
62 pcg 1.1 struct tcp_connection;
63    
64     struct lt_sockinfo
65     {
66     bool operator()(const sockinfo *a, const sockinfo *b) const
67     {
68     return *a < *b;
69     }
70     };
71    
72 pcg 1.22 struct tcp_si_map : public map<const sockinfo *, tcp_connection *, lt_sockinfo>
73     {
74 pcg 1.24 inline void cleaner_cb (ev::timer &w, int revents); ev::timer cleaner;
75 pcg 1.1
76     tcp_si_map ()
77 pcg 1.17 {
78 pcg 1.25 ev_default_loop (0);
79 pcg 1.23 cleaner.set<tcp_si_map, &tcp_si_map::cleaner_cb> (this);
80 pcg 1.19 cleaner.start (::conf.keepalive / 2, ::conf.keepalive / 2);
81 pcg 1.17 }
82 root 1.27 };
83 pcg 1.13
84 root 1.27 static tcp_si_map tcp_si;
85 pcg 1.1
86 pcg 1.22 struct tcp_connection : ev::io
87     {
88 pcg 1.21 int tos;
89 pcg 1.1 tstamp last_activity;
90     const sockinfo si;
91     vpn &v;
92     bool active; // this connection has been actively established
93 pcg 1.4 enum { ERROR, IDLE, CONNECTING, CONNECTING_PROXY, ESTABLISHED } state;
94 pcg 1.1
95     vpn_packet *r_pkt;
96     u32 r_len, r_ofs;
97    
98 pcg 1.3 vpn_packet *w_pkt;
99     u32 w_len, w_ofs;
100    
101 pcg 1.4 #if ENABLE_HTTP_PROXY
102     char *proxy_req;
103     int proxy_req_len;
104     #endif
105    
106 pcg 1.24 inline void tcpv4_ev (ev::io &w, int revents);
107 pcg 1.1
108 pcg 1.2 bool send_packet (vpn_packet *pkt, int tos);
109 pcg 1.3 bool write_packet ();
110 pcg 1.1
111     void error (); // abort conenction && cleanup
112    
113     operator tcp_si_map::value_type()
114 pcg 1.13 {
115     return tcp_si_map::value_type (&si, this);
116     }
117 pcg 1.1
118     tcp_connection (int fd_, const sockinfo &si_, vpn &v_);
119     ~tcp_connection ();
120     };
121    
122 root 1.27 void
123     tcp_si_map::cleaner_cb (ev::timer &w, int revents)
124 pcg 1.1 {
125 pcg 1.20 tstamp to = ev_now () - ::conf.keepalive - 30 - 60;
126 pcg 1.1
127     for (iterator i = begin (); i != end(); )
128     if (i->second->last_activity >= to)
129     ++i;
130     else
131     {
132 pcg 1.19 delete i->second;
133 pcg 1.1 erase (i);
134     i = begin ();
135     }
136     }
137    
138     void
139 pcg 1.17 vpn::tcpv4_ev (ev::io &w, int revents)
140 pcg 1.1 {
141 pcg 1.17 if (revents & EV_READ)
142 pcg 1.1 {
143     struct sockaddr_in sa;
144     socklen_t sa_len = sizeof (sa);
145     int len;
146    
147     int fd = accept (w.fd, (sockaddr *)&sa, &sa_len);
148    
149     if (fd >= 0)
150     {
151 pcg 1.16 fcntl (fd, F_SETFL, O_NONBLOCK);
152     fcntl (fd, F_SETFD, FD_CLOEXEC);
153    
154 pcg 1.1 sockinfo si(sa, PROT_TCPv4);
155    
156     slog (L_DEBUG, _("%s: accepted tcp connection"), (const char *)si);//D
157    
158     tcp_connection *i = new tcp_connection (fd, si, *this);
159     tcp_si.insert (*i);
160     }
161     }
162     }
163    
164 pcg 1.2 bool
165 pcg 1.1 vpn::send_tcpv4_packet (vpn_packet *pkt, const sockinfo &si, int tos)
166     {
167     tcp_si_map::iterator info = tcp_si.find (&si);
168    
169     tcp_connection *i;
170    
171     if (info == tcp_si.end ())
172     {
173     i = new tcp_connection (-1, si, *this);
174     tcp_si.insert (*i);
175     }
176     else
177     i = info->second;
178    
179 pcg 1.2 return i->send_packet (pkt, tos);
180 pcg 1.1 }
181    
182 pcg 1.3 bool
183     tcp_connection::write_packet ()
184     {
185     ssize_t len;
186    
187     if (w_ofs < 2)
188     {
189     u16 plen = htons (w_pkt->len);
190    
191     iovec vec[2];
192 pcg 1.7 //TODO: char* is the right type? hardly...
193     vec[0].iov_base = (char *)((u8 *)&plen) + w_ofs;
194 pcg 1.3 vec[0].iov_len = 2 - w_ofs;
195 pcg 1.7 vec[1].iov_base = (char *)&((*w_pkt)[0]);
196 pcg 1.3 vec[1].iov_len = w_len - 2;
197    
198     len = writev (fd, vec, 2);
199     }
200     else
201     len = write (fd, &((*w_pkt)[w_ofs - 2]), w_len);
202    
203     if (len > 0)
204     {
205     w_ofs += len;
206     w_len -= len;
207    
208     return w_len == 0;
209     }
210     else if (len < 0 && (errno == EAGAIN || errno == EINTR))
211     return false;
212     else
213     {
214     error ();
215     return false;
216     }
217     }
218    
219 pcg 1.1 void
220 pcg 1.17 tcp_connection::tcpv4_ev (ev::io &w, int revents)
221 pcg 1.1 {
222 pcg 1.20 last_activity = ev_now ();
223 pcg 1.1
224 pcg 1.17 if (revents & EV_WRITE)
225 pcg 1.3 {
226     if (state == CONNECTING)
227     {
228     state = ESTABLISHED;
229 pcg 1.17 set (EV_READ);
230 pcg 1.4 #if ENABLE_HTTP_PROXY
231     if (::conf.proxy_host && ::conf.proxy_port)
232     {
233     state = CONNECTING_PROXY;
234 pcg 1.11
235     if (write (fd, proxy_req, proxy_req_len) == 0)
236     {
237     error ();
238     return;
239     }
240    
241 pcg 1.4 free (proxy_req); proxy_req = 0;
242     }
243     #endif
244 pcg 1.3 }
245     else if (state == ESTABLISHED)
246     {
247     if (w_pkt)
248     {
249     if (write_packet ())
250     {
251     delete w_pkt; w_pkt = 0;
252    
253 pcg 1.17 set (EV_READ);
254 pcg 1.3 }
255     }
256     else
257 pcg 1.17 set (EV_READ);
258 pcg 1.3 }
259     else
260 pcg 1.17 set (EV_READ);
261 pcg 1.3 }
262    
263 pcg 1.17 if (revents & EV_READ)
264 pcg 1.1 {
265 pcg 1.4 if (state == ESTABLISHED)
266     for (;;)
267     {
268     if (!r_pkt)
269     {
270     r_pkt = new vpn_packet;
271     r_ofs = 0;
272     r_len = 2; // header
273     }
274    
275     ssize_t len = read (fd, &((*r_pkt)[r_ofs < 2 ? r_ofs : r_ofs - 2]), r_len);
276    
277     if (len > 0)
278     {
279     r_len -= len;
280     r_ofs += len;
281    
282     if (r_len == 0)
283     {
284     if (r_ofs == 2)
285     {
286     r_len = ntohs (*(u16 *)&((*r_pkt)[0]));
287     r_pkt->len = r_len;
288    
289     if (r_len > 0 && r_len < MAXSIZE)
290     continue;
291     }
292     else
293     {
294     v.recv_vpn_packet (r_pkt, si);
295     delete r_pkt;
296     r_pkt = 0;
297    
298     continue;
299     }
300     }
301     else
302     break;
303     }
304     else if (len < 0 && (errno == EINTR || errno == EAGAIN))
305     break;
306    
307 pcg 1.11 // len == 0 <-> EOF
308 pcg 1.4 error ();
309     break;
310     }
311     #if ENABLE_HTTP_PROXY
312     else if (state == CONNECTING_PROXY)
313 pcg 1.1 {
314 pcg 1.4 fcntl (fd, F_SETFL, 0);
315     char r[1024];
316     int i;
317     bool emptyline = false;
318 pcg 1.1
319 pcg 1.4 // we do a blocking read of the response, to hell with it
320     for (i = 0; i < 1023; i++)
321 pcg 1.1 {
322 pcg 1.4 int l = read (fd, &r[i], 1);
323 pcg 1.1
324 pcg 1.4 if (l <= 0)
325 pcg 1.1 {
326 pcg 1.4 error ();
327     return;
328     }
329 pcg 1.1
330 pcg 1.4 if (r[i] == '\012')
331     {
332     if (emptyline)
333     break;
334 pcg 1.1 else
335 pcg 1.4 emptyline = true;
336 pcg 1.1 }
337 pcg 1.4 else if (r[i] != '\015')
338     emptyline = false;
339 pcg 1.1 }
340    
341 pcg 1.4 fcntl (fd, F_SETFL, O_NONBLOCK);
342    
343     if (i < 12)
344     {
345 pcg 1.6 slog (L_ERR, _("(%s): unable to do proxy-forwarding, short response"),
346 pcg 1.5 (const char *)si);
347 pcg 1.4 error ();
348     }
349     else if (r[0] != 'H' || r[1] != 'T' || r[2] != 'T' || r[3] != 'P' || r[4] != '/'
350     || r[5] != '1' // http-major
351     || r[9] != '2') // response
352     {
353 pcg 1.6 slog (L_ERR, _("(%s): malformed or unexpected proxy response (%.12s)"),
354 pcg 1.5 (const char *)si, r);
355 pcg 1.4 error ();
356     }
357     else
358     state = ESTABLISHED;
359 pcg 1.1 }
360 pcg 1.4 #endif
361 pcg 1.1 }
362     }
363    
364 pcg 1.2 bool
365 pcg 1.1 tcp_connection::send_packet (vpn_packet *pkt, int tos)
366     {
367 pcg 1.20 last_activity = ev_now ();
368 pcg 1.1
369     if (state == IDLE)
370     {
371     // woaw, the first lost packet ;)
372     fd = socket (PF_INET, SOCK_STREAM, IPPROTO_TCP);
373    
374     if (fd >= 0)
375     {
376 pcg 1.4 const sockinfo *csi = &si;
377    
378     #if ENABLE_HTTP_PROXY
379     sockinfo psi;
380    
381     if (::conf.proxy_host && ::conf.proxy_port)
382     {
383     psi.set (::conf.proxy_host, ::conf.proxy_port, PROT_TCPv4);
384    
385     if (psi.valid ())
386     {
387     csi = &psi;
388    
389     proxy_req_len = asprintf (&proxy_req,
390     "CONNECT %s:%d HTTP/1.0\015\012"
391     "%s%s%s" // optional proxy-auth
392     "\015\012",
393     si.ntoa (),
394     ntohs (si.port),
395     ::conf.proxy_auth ? "Proxy-Authorization: Basic " : "",
396     ::conf.proxy_auth ? ::conf.proxy_auth : "",
397     ::conf.proxy_auth ? "\015\012" : "");
398    
399     }
400     else
401     slog (L_ERR, _("unable to resolve http proxy hostname '%s', trying direct"),
402     ::conf.proxy_host);
403     }
404     #endif
405    
406 pcg 1.1 fcntl (fd, F_SETFL, O_NONBLOCK);
407 pcg 1.4
408     if (connect (fd, csi->sav4 (), csi->salenv4 ()) >= 0
409 pcg 1.1 || errno == EINPROGRESS)
410     {
411 pcg 1.16 fcntl (fd, F_SETFL, O_NONBLOCK);
412     fcntl (fd, F_SETFD, FD_CLOEXEC);
413    
414 pcg 1.1 state = CONNECTING;
415 pcg 1.17 start (fd, EV_WRITE);
416 pcg 1.1 }
417     else
418     close (fd);
419     }
420     }
421     else if (state == ESTABLISHED)
422     {
423 pcg 1.3 // drop packet if the tcp write buffer is full. this *is* the
424     // right thing to do, not using tcp *is* the right thing to do.
425     if (!w_pkt)
426     {
427     // how this maps to the underlying tcp packets we don't know
428     // and we don't care. at least we tried ;)
429 pcg 1.7 #if defined(SOL_IP) && defined(IP_TOS)
430 pcg 1.21 if (tos != this->tos)
431     {
432     this->tos = tos;
433     setsockopt (fd, SOL_IP, IP_TOS, &tos, sizeof tos);
434     }
435 pcg 1.7 #endif
436 pcg 1.3
437     w_pkt = pkt;
438     w_ofs = 0;
439     w_len = pkt->len + 2; // length + size header
440    
441     if (write_packet ())
442     w_pkt = 0;
443     else
444     {
445     w_pkt = new vpn_packet;
446     w_pkt->set (*pkt);
447 pcg 1.1
448 pcg 1.17 set (EV_READ | EV_WRITE);
449 pcg 1.3 }
450     }
451 pcg 1.1 }
452 pcg 1.2
453     return state != ERROR;
454 pcg 1.1 }
455    
456 root 1.27 void
457     tcp_connection::error ()
458 pcg 1.4 {
459 pcg 1.18 stop ();
460    
461 pcg 1.4 if (fd >= 0)
462     {
463     close (fd);
464 pcg 1.21 tos = -1;
465     fd = -1;
466 pcg 1.4 }
467    
468     delete r_pkt; r_pkt = 0;
469     delete w_pkt; w_pkt = 0;
470     #if ENABLE_HTTP_PROXY
471     free (proxy_req); proxy_req = 0;
472     #endif
473    
474     state = active ? IDLE : ERROR;
475     }
476    
477 pcg 1.1 tcp_connection::tcp_connection (int fd_, const sockinfo &si_, vpn &v_)
478 pcg 1.23 : v(v_), si(si_)
479 pcg 1.1 {
480 pcg 1.23 set<tcp_connection, &tcp_connection::tcpv4_ev> (this);
481    
482 pcg 1.20 last_activity = ev_now ();
483 pcg 1.1 r_pkt = 0;
484 pcg 1.3 w_pkt = 0;
485 pcg 1.21 tos = -1;
486 pcg 1.1 fd = fd_;
487 pcg 1.4 #if ENABLE_HTTP_PROXY
488     proxy_req = 0;
489     #endif
490 pcg 1.1
491     if (fd < 0)
492     {
493     active = true;
494     state = IDLE;
495     }
496     else
497     {
498     active = false;
499     state = ESTABLISHED;
500 pcg 1.17 start (fd, EV_READ);
501 pcg 1.1 }
502     }
503    
504     tcp_connection::~tcp_connection ()
505     {
506     error ();
507     }
508    
509     #endif
510