ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/gvpe/src/vpn_tcp.C
Revision: 1.26
Committed: Thu Aug 7 17:54:27 2008 UTC (15 years, 9 months ago) by pcg
Content type: text/plain
Branch: MAIN
CVS Tags: rel-2_2, rel-2_21, rel-2_22
Changes since 1.25: +24 -14 lines
Log Message:
update to gplv3, finally

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 pcg 1.13
83 pcg 1.1 } tcp_si;
84    
85 pcg 1.22 struct tcp_connection : ev::io
86     {
87 pcg 1.21 int tos;
88 pcg 1.1 tstamp last_activity;
89     const sockinfo si;
90     vpn &v;
91     bool active; // this connection has been actively established
92 pcg 1.4 enum { ERROR, IDLE, CONNECTING, CONNECTING_PROXY, ESTABLISHED } state;
93 pcg 1.1
94     vpn_packet *r_pkt;
95     u32 r_len, r_ofs;
96    
97 pcg 1.3 vpn_packet *w_pkt;
98     u32 w_len, w_ofs;
99    
100 pcg 1.4 #if ENABLE_HTTP_PROXY
101     char *proxy_req;
102     int proxy_req_len;
103     #endif
104    
105 pcg 1.24 inline void tcpv4_ev (ev::io &w, int revents);
106 pcg 1.1
107 pcg 1.2 bool send_packet (vpn_packet *pkt, int tos);
108 pcg 1.3 bool write_packet ();
109 pcg 1.1
110     void error (); // abort conenction && cleanup
111    
112     operator tcp_si_map::value_type()
113 pcg 1.13 {
114     return tcp_si_map::value_type (&si, this);
115     }
116 pcg 1.1
117     tcp_connection (int fd_, const sockinfo &si_, vpn &v_);
118     ~tcp_connection ();
119     };
120    
121 pcg 1.17 void tcp_si_map::cleaner_cb (ev::timer &w, int revents)
122 pcg 1.1 {
123 pcg 1.20 tstamp to = ev_now () - ::conf.keepalive - 30 - 60;
124 pcg 1.1
125     for (iterator i = begin (); i != end(); )
126     if (i->second->last_activity >= to)
127     ++i;
128     else
129     {
130 pcg 1.19 delete i->second;
131 pcg 1.1 erase (i);
132     i = begin ();
133     }
134     }
135    
136     void
137 pcg 1.17 vpn::tcpv4_ev (ev::io &w, int revents)
138 pcg 1.1 {
139 pcg 1.17 if (revents & EV_READ)
140 pcg 1.1 {
141     struct sockaddr_in sa;
142     socklen_t sa_len = sizeof (sa);
143     int len;
144    
145     int fd = accept (w.fd, (sockaddr *)&sa, &sa_len);
146    
147     if (fd >= 0)
148     {
149 pcg 1.16 fcntl (fd, F_SETFL, O_NONBLOCK);
150     fcntl (fd, F_SETFD, FD_CLOEXEC);
151    
152 pcg 1.1 sockinfo si(sa, PROT_TCPv4);
153    
154     slog (L_DEBUG, _("%s: accepted tcp connection"), (const char *)si);//D
155    
156     tcp_connection *i = new tcp_connection (fd, si, *this);
157     tcp_si.insert (*i);
158     }
159     }
160     }
161    
162 pcg 1.2 bool
163 pcg 1.1 vpn::send_tcpv4_packet (vpn_packet *pkt, const sockinfo &si, int tos)
164     {
165     tcp_si_map::iterator info = tcp_si.find (&si);
166    
167     tcp_connection *i;
168    
169     if (info == tcp_si.end ())
170     {
171     i = new tcp_connection (-1, si, *this);
172     tcp_si.insert (*i);
173     }
174     else
175     i = info->second;
176    
177 pcg 1.2 return i->send_packet (pkt, tos);
178 pcg 1.1 }
179    
180 pcg 1.3 bool
181     tcp_connection::write_packet ()
182     {
183     ssize_t len;
184    
185     if (w_ofs < 2)
186     {
187     u16 plen = htons (w_pkt->len);
188    
189     iovec vec[2];
190 pcg 1.7 //TODO: char* is the right type? hardly...
191     vec[0].iov_base = (char *)((u8 *)&plen) + w_ofs;
192 pcg 1.3 vec[0].iov_len = 2 - w_ofs;
193 pcg 1.7 vec[1].iov_base = (char *)&((*w_pkt)[0]);
194 pcg 1.3 vec[1].iov_len = w_len - 2;
195    
196     len = writev (fd, vec, 2);
197     }
198     else
199     len = write (fd, &((*w_pkt)[w_ofs - 2]), w_len);
200    
201     if (len > 0)
202     {
203     w_ofs += len;
204     w_len -= len;
205    
206     return w_len == 0;
207     }
208     else if (len < 0 && (errno == EAGAIN || errno == EINTR))
209     return false;
210     else
211     {
212     error ();
213     return false;
214     }
215     }
216    
217 pcg 1.1 void
218 pcg 1.17 tcp_connection::tcpv4_ev (ev::io &w, int revents)
219 pcg 1.1 {
220 pcg 1.20 last_activity = ev_now ();
221 pcg 1.1
222 pcg 1.17 if (revents & EV_WRITE)
223 pcg 1.3 {
224     if (state == CONNECTING)
225     {
226     state = ESTABLISHED;
227 pcg 1.17 set (EV_READ);
228 pcg 1.4 #if ENABLE_HTTP_PROXY
229     if (::conf.proxy_host && ::conf.proxy_port)
230     {
231     state = CONNECTING_PROXY;
232 pcg 1.11
233     if (write (fd, proxy_req, proxy_req_len) == 0)
234     {
235     error ();
236     return;
237     }
238    
239 pcg 1.4 free (proxy_req); proxy_req = 0;
240     }
241     #endif
242 pcg 1.3 }
243     else if (state == ESTABLISHED)
244     {
245     if (w_pkt)
246     {
247     if (write_packet ())
248     {
249     delete w_pkt; w_pkt = 0;
250    
251 pcg 1.17 set (EV_READ);
252 pcg 1.3 }
253     }
254     else
255 pcg 1.17 set (EV_READ);
256 pcg 1.3 }
257     else
258 pcg 1.17 set (EV_READ);
259 pcg 1.3 }
260    
261 pcg 1.17 if (revents & EV_READ)
262 pcg 1.1 {
263 pcg 1.4 if (state == ESTABLISHED)
264     for (;;)
265     {
266     if (!r_pkt)
267     {
268     r_pkt = new vpn_packet;
269     r_ofs = 0;
270     r_len = 2; // header
271     }
272    
273     ssize_t len = read (fd, &((*r_pkt)[r_ofs < 2 ? r_ofs : r_ofs - 2]), r_len);
274    
275     if (len > 0)
276     {
277     r_len -= len;
278     r_ofs += len;
279    
280     if (r_len == 0)
281     {
282     if (r_ofs == 2)
283     {
284     r_len = ntohs (*(u16 *)&((*r_pkt)[0]));
285     r_pkt->len = r_len;
286    
287     if (r_len > 0 && r_len < MAXSIZE)
288     continue;
289     }
290     else
291     {
292     v.recv_vpn_packet (r_pkt, si);
293     delete r_pkt;
294     r_pkt = 0;
295    
296     continue;
297     }
298     }
299     else
300     break;
301     }
302     else if (len < 0 && (errno == EINTR || errno == EAGAIN))
303     break;
304    
305 pcg 1.11 // len == 0 <-> EOF
306 pcg 1.4 error ();
307     break;
308     }
309     #if ENABLE_HTTP_PROXY
310     else if (state == CONNECTING_PROXY)
311 pcg 1.1 {
312 pcg 1.4 fcntl (fd, F_SETFL, 0);
313     char r[1024];
314     int i;
315     bool emptyline = false;
316 pcg 1.1
317 pcg 1.4 // we do a blocking read of the response, to hell with it
318     for (i = 0; i < 1023; i++)
319 pcg 1.1 {
320 pcg 1.4 int l = read (fd, &r[i], 1);
321 pcg 1.1
322 pcg 1.4 if (l <= 0)
323 pcg 1.1 {
324 pcg 1.4 error ();
325     return;
326     }
327 pcg 1.1
328 pcg 1.4 if (r[i] == '\012')
329     {
330     if (emptyline)
331     break;
332 pcg 1.1 else
333 pcg 1.4 emptyline = true;
334 pcg 1.1 }
335 pcg 1.4 else if (r[i] != '\015')
336     emptyline = false;
337 pcg 1.1 }
338    
339 pcg 1.4 fcntl (fd, F_SETFL, O_NONBLOCK);
340    
341     if (i < 12)
342     {
343 pcg 1.6 slog (L_ERR, _("(%s): unable to do proxy-forwarding, short response"),
344 pcg 1.5 (const char *)si);
345 pcg 1.4 error ();
346     }
347     else if (r[0] != 'H' || r[1] != 'T' || r[2] != 'T' || r[3] != 'P' || r[4] != '/'
348     || r[5] != '1' // http-major
349     || r[9] != '2') // response
350     {
351 pcg 1.6 slog (L_ERR, _("(%s): malformed or unexpected proxy response (%.12s)"),
352 pcg 1.5 (const char *)si, r);
353 pcg 1.4 error ();
354     }
355     else
356     state = ESTABLISHED;
357 pcg 1.1 }
358 pcg 1.4 #endif
359 pcg 1.1 }
360     }
361    
362 pcg 1.2 bool
363 pcg 1.1 tcp_connection::send_packet (vpn_packet *pkt, int tos)
364     {
365 pcg 1.20 last_activity = ev_now ();
366 pcg 1.1
367     if (state == IDLE)
368     {
369     // woaw, the first lost packet ;)
370     fd = socket (PF_INET, SOCK_STREAM, IPPROTO_TCP);
371    
372     if (fd >= 0)
373     {
374 pcg 1.4 const sockinfo *csi = &si;
375    
376     #if ENABLE_HTTP_PROXY
377     sockinfo psi;
378    
379     if (::conf.proxy_host && ::conf.proxy_port)
380     {
381     psi.set (::conf.proxy_host, ::conf.proxy_port, PROT_TCPv4);
382    
383     if (psi.valid ())
384     {
385     csi = &psi;
386    
387     proxy_req_len = asprintf (&proxy_req,
388     "CONNECT %s:%d HTTP/1.0\015\012"
389     "%s%s%s" // optional proxy-auth
390     "\015\012",
391     si.ntoa (),
392     ntohs (si.port),
393     ::conf.proxy_auth ? "Proxy-Authorization: Basic " : "",
394     ::conf.proxy_auth ? ::conf.proxy_auth : "",
395     ::conf.proxy_auth ? "\015\012" : "");
396    
397     }
398     else
399     slog (L_ERR, _("unable to resolve http proxy hostname '%s', trying direct"),
400     ::conf.proxy_host);
401     }
402     #endif
403    
404 pcg 1.1 fcntl (fd, F_SETFL, O_NONBLOCK);
405 pcg 1.4
406     if (connect (fd, csi->sav4 (), csi->salenv4 ()) >= 0
407 pcg 1.1 || errno == EINPROGRESS)
408     {
409 pcg 1.16 fcntl (fd, F_SETFL, O_NONBLOCK);
410     fcntl (fd, F_SETFD, FD_CLOEXEC);
411    
412 pcg 1.1 state = CONNECTING;
413 pcg 1.17 start (fd, EV_WRITE);
414 pcg 1.1 }
415     else
416     close (fd);
417     }
418     }
419     else if (state == ESTABLISHED)
420     {
421 pcg 1.3 // drop packet if the tcp write buffer is full. this *is* the
422     // right thing to do, not using tcp *is* the right thing to do.
423     if (!w_pkt)
424     {
425     // how this maps to the underlying tcp packets we don't know
426     // and we don't care. at least we tried ;)
427 pcg 1.7 #if defined(SOL_IP) && defined(IP_TOS)
428 pcg 1.21 if (tos != this->tos)
429     {
430     this->tos = tos;
431     setsockopt (fd, SOL_IP, IP_TOS, &tos, sizeof tos);
432     }
433 pcg 1.7 #endif
434 pcg 1.3
435     w_pkt = pkt;
436     w_ofs = 0;
437     w_len = pkt->len + 2; // length + size header
438    
439     if (write_packet ())
440     w_pkt = 0;
441     else
442     {
443     w_pkt = new vpn_packet;
444     w_pkt->set (*pkt);
445 pcg 1.1
446 pcg 1.17 set (EV_READ | EV_WRITE);
447 pcg 1.3 }
448     }
449 pcg 1.1 }
450 pcg 1.2
451     return state != ERROR;
452 pcg 1.1 }
453    
454 pcg 1.4 void tcp_connection::error ()
455     {
456 pcg 1.18 stop ();
457    
458 pcg 1.4 if (fd >= 0)
459     {
460     close (fd);
461 pcg 1.21 tos = -1;
462     fd = -1;
463 pcg 1.4 }
464    
465     delete r_pkt; r_pkt = 0;
466     delete w_pkt; w_pkt = 0;
467     #if ENABLE_HTTP_PROXY
468     free (proxy_req); proxy_req = 0;
469     #endif
470    
471     state = active ? IDLE : ERROR;
472     }
473    
474 pcg 1.1 tcp_connection::tcp_connection (int fd_, const sockinfo &si_, vpn &v_)
475 pcg 1.23 : v(v_), si(si_)
476 pcg 1.1 {
477 pcg 1.23 set<tcp_connection, &tcp_connection::tcpv4_ev> (this);
478    
479 pcg 1.20 last_activity = ev_now ();
480 pcg 1.1 r_pkt = 0;
481 pcg 1.3 w_pkt = 0;
482 pcg 1.21 tos = -1;
483 pcg 1.1 fd = fd_;
484 pcg 1.4 #if ENABLE_HTTP_PROXY
485     proxy_req = 0;
486     #endif
487 pcg 1.1
488     if (fd < 0)
489     {
490     active = true;
491     state = IDLE;
492     }
493     else
494     {
495     active = false;
496     state = ESTABLISHED;
497 pcg 1.17 start (fd, EV_READ);
498 pcg 1.1 }
499     }
500    
501     tcp_connection::~tcp_connection ()
502     {
503     error ();
504     }
505    
506     #endif
507