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

# Content
1 /*
2 vpn_tcp.C -- handle the tcp part of the protocol.
3 Copyright (C) 2003-2008 Marc Lehmann <gvpe@schmorp.de>
4
5 This file is part of GVPE.
6
7 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 */
31
32 #include "config.h"
33
34 #if ENABLE_TCP
35
36 // tcp processing is extremely ugly, since the gvpe protocol is simply
37 // designed for unreliable datagram networks. tcp is implemented by
38 // multiplexing packets over tcp. errors are completely ignored, as we
39 // rely on the higher level layers to time out and reconnect.
40
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 #include <fcntl.h>
51
52 #include <map>
53
54 #include "netcompat.h"
55
56 #include "vpn.h"
57
58 #if ENABLE_HTTP_PROXY
59 # include "conf.h"
60 #endif
61
62 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 struct tcp_si_map : public map<const sockinfo *, tcp_connection *, lt_sockinfo>
73 {
74 inline void cleaner_cb (ev::timer &w, int revents); ev::timer cleaner;
75
76 tcp_si_map ()
77 {
78 ev_default_loop (0);
79 cleaner.set<tcp_si_map, &tcp_si_map::cleaner_cb> (this);
80 cleaner.start (::conf.keepalive / 2, ::conf.keepalive / 2);
81 }
82 };
83
84 static tcp_si_map tcp_si;
85
86 struct tcp_connection : ev::io
87 {
88 int tos;
89 tstamp last_activity;
90 const sockinfo si;
91 vpn &v;
92 bool active; // this connection has been actively established
93 enum { ERROR, IDLE, CONNECTING, CONNECTING_PROXY, ESTABLISHED } state;
94
95 vpn_packet *r_pkt;
96 u32 r_len, r_ofs;
97
98 vpn_packet *w_pkt;
99 u32 w_len, w_ofs;
100
101 #if ENABLE_HTTP_PROXY
102 char *proxy_req;
103 int proxy_req_len;
104 #endif
105
106 inline void tcpv4_ev (ev::io &w, int revents);
107
108 bool send_packet (vpn_packet *pkt, int tos);
109 bool write_packet ();
110
111 void error (); // abort conenction && cleanup
112
113 operator tcp_si_map::value_type()
114 {
115 return tcp_si_map::value_type (&si, this);
116 }
117
118 tcp_connection (int fd_, const sockinfo &si_, vpn &v_);
119 ~tcp_connection ();
120 };
121
122 void
123 tcp_si_map::cleaner_cb (ev::timer &w, int revents)
124 {
125 tstamp to = ev_now () - ::conf.keepalive - 30 - 60;
126
127 for (iterator i = begin (); i != end(); )
128 if (i->second->last_activity >= to)
129 ++i;
130 else
131 {
132 delete i->second;
133 erase (i);
134 i = begin ();
135 }
136 }
137
138 void
139 vpn::tcpv4_ev (ev::io &w, int revents)
140 {
141 if (revents & EV_READ)
142 {
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 fcntl (fd, F_SETFL, O_NONBLOCK);
152 fcntl (fd, F_SETFD, FD_CLOEXEC);
153
154 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 bool
165 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 return i->send_packet (pkt, tos);
180 }
181
182 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 //TODO: char* is the right type? hardly...
193 vec[0].iov_base = (char *)((u8 *)&plen) + w_ofs;
194 vec[0].iov_len = 2 - w_ofs;
195 vec[1].iov_base = (char *)&((*w_pkt)[0]);
196 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 void
220 tcp_connection::tcpv4_ev (ev::io &w, int revents)
221 {
222 last_activity = ev_now ();
223
224 if (revents & EV_WRITE)
225 {
226 if (state == CONNECTING)
227 {
228 state = ESTABLISHED;
229 set (EV_READ);
230 #if ENABLE_HTTP_PROXY
231 if (::conf.proxy_host && ::conf.proxy_port)
232 {
233 state = CONNECTING_PROXY;
234
235 if (write (fd, proxy_req, proxy_req_len) == 0)
236 {
237 error ();
238 return;
239 }
240
241 free (proxy_req); proxy_req = 0;
242 }
243 #endif
244 }
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 set (EV_READ);
254 }
255 }
256 else
257 set (EV_READ);
258 }
259 else
260 set (EV_READ);
261 }
262
263 if (revents & EV_READ)
264 {
265 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 // len == 0 <-> EOF
308 error ();
309 break;
310 }
311 #if ENABLE_HTTP_PROXY
312 else if (state == CONNECTING_PROXY)
313 {
314 fcntl (fd, F_SETFL, 0);
315 char r[1024];
316 int i;
317 bool emptyline = false;
318
319 // we do a blocking read of the response, to hell with it
320 for (i = 0; i < 1023; i++)
321 {
322 int l = read (fd, &r[i], 1);
323
324 if (l <= 0)
325 {
326 error ();
327 return;
328 }
329
330 if (r[i] == '\012')
331 {
332 if (emptyline)
333 break;
334 else
335 emptyline = true;
336 }
337 else if (r[i] != '\015')
338 emptyline = false;
339 }
340
341 fcntl (fd, F_SETFL, O_NONBLOCK);
342
343 if (i < 12)
344 {
345 slog (L_ERR, _("(%s): unable to do proxy-forwarding, short response"),
346 (const char *)si);
347 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 slog (L_ERR, _("(%s): malformed or unexpected proxy response (%.12s)"),
354 (const char *)si, r);
355 error ();
356 }
357 else
358 state = ESTABLISHED;
359 }
360 #endif
361 }
362 }
363
364 bool
365 tcp_connection::send_packet (vpn_packet *pkt, int tos)
366 {
367 last_activity = ev_now ();
368
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 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 fcntl (fd, F_SETFL, O_NONBLOCK);
407
408 if (connect (fd, csi->sav4 (), csi->salenv4 ()) >= 0
409 || errno == EINPROGRESS)
410 {
411 fcntl (fd, F_SETFL, O_NONBLOCK);
412 fcntl (fd, F_SETFD, FD_CLOEXEC);
413
414 state = CONNECTING;
415 start (fd, EV_WRITE);
416 }
417 else
418 close (fd);
419 }
420 }
421 else if (state == ESTABLISHED)
422 {
423 // 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 #if defined(SOL_IP) && defined(IP_TOS)
430 if (tos != this->tos)
431 {
432 this->tos = tos;
433 setsockopt (fd, SOL_IP, IP_TOS, &tos, sizeof tos);
434 }
435 #endif
436
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
448 set (EV_READ | EV_WRITE);
449 }
450 }
451 }
452
453 return state != ERROR;
454 }
455
456 void
457 tcp_connection::error ()
458 {
459 stop ();
460
461 if (fd >= 0)
462 {
463 close (fd);
464 tos = -1;
465 fd = -1;
466 }
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 tcp_connection::tcp_connection (int fd_, const sockinfo &si_, vpn &v_)
478 : v(v_), si(si_)
479 {
480 set<tcp_connection, &tcp_connection::tcpv4_ev> (this);
481
482 last_activity = ev_now ();
483 r_pkt = 0;
484 w_pkt = 0;
485 tos = -1;
486 fd = fd_;
487 #if ENABLE_HTTP_PROXY
488 proxy_req = 0;
489 #endif
490
491 if (fd < 0)
492 {
493 active = true;
494 state = IDLE;
495 }
496 else
497 {
498 active = false;
499 state = ESTABLISHED;
500 start (fd, EV_READ);
501 }
502 }
503
504 tcp_connection::~tcp_connection ()
505 {
506 error ();
507 }
508
509 #endif
510