ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/gvpe/src/vpn_tcp.C
Revision: 1.21
Committed: Sun Dec 2 00:39:06 2007 UTC (16 years, 5 months ago) by pcg
Content type: text/plain
Branch: MAIN
Changes since 1.20: +9 -2 lines
Log Message:
cache tos

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