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