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

# 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 } tcp_si;
84
85 struct tcp_connection : ev::io
86 {
87 int tos;
88 tstamp last_activity;
89 const sockinfo si;
90 vpn &v;
91 bool active; // this connection has been actively established
92 enum { ERROR, IDLE, CONNECTING, CONNECTING_PROXY, ESTABLISHED } state;
93
94 vpn_packet *r_pkt;
95 u32 r_len, r_ofs;
96
97 vpn_packet *w_pkt;
98 u32 w_len, w_ofs;
99
100 #if ENABLE_HTTP_PROXY
101 char *proxy_req;
102 int proxy_req_len;
103 #endif
104
105 inline void tcpv4_ev (ev::io &w, int revents);
106
107 bool send_packet (vpn_packet *pkt, int tos);
108 bool write_packet ();
109
110 void error (); // abort conenction && cleanup
111
112 operator tcp_si_map::value_type()
113 {
114 return tcp_si_map::value_type (&si, this);
115 }
116
117 tcp_connection (int fd_, const sockinfo &si_, vpn &v_);
118 ~tcp_connection ();
119 };
120
121 void tcp_si_map::cleaner_cb (ev::timer &w, int revents)
122 {
123 tstamp to = ev_now () - ::conf.keepalive - 30 - 60;
124
125 for (iterator i = begin (); i != end(); )
126 if (i->second->last_activity >= to)
127 ++i;
128 else
129 {
130 delete i->second;
131 erase (i);
132 i = begin ();
133 }
134 }
135
136 void
137 vpn::tcpv4_ev (ev::io &w, int revents)
138 {
139 if (revents & EV_READ)
140 {
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 fcntl (fd, F_SETFL, O_NONBLOCK);
150 fcntl (fd, F_SETFD, FD_CLOEXEC);
151
152 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 bool
163 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 return i->send_packet (pkt, tos);
178 }
179
180 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 //TODO: char* is the right type? hardly...
191 vec[0].iov_base = (char *)((u8 *)&plen) + w_ofs;
192 vec[0].iov_len = 2 - w_ofs;
193 vec[1].iov_base = (char *)&((*w_pkt)[0]);
194 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 void
218 tcp_connection::tcpv4_ev (ev::io &w, int revents)
219 {
220 last_activity = ev_now ();
221
222 if (revents & EV_WRITE)
223 {
224 if (state == CONNECTING)
225 {
226 state = ESTABLISHED;
227 set (EV_READ);
228 #if ENABLE_HTTP_PROXY
229 if (::conf.proxy_host && ::conf.proxy_port)
230 {
231 state = CONNECTING_PROXY;
232
233 if (write (fd, proxy_req, proxy_req_len) == 0)
234 {
235 error ();
236 return;
237 }
238
239 free (proxy_req); proxy_req = 0;
240 }
241 #endif
242 }
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 set (EV_READ);
252 }
253 }
254 else
255 set (EV_READ);
256 }
257 else
258 set (EV_READ);
259 }
260
261 if (revents & EV_READ)
262 {
263 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 // len == 0 <-> EOF
306 error ();
307 break;
308 }
309 #if ENABLE_HTTP_PROXY
310 else if (state == CONNECTING_PROXY)
311 {
312 fcntl (fd, F_SETFL, 0);
313 char r[1024];
314 int i;
315 bool emptyline = false;
316
317 // we do a blocking read of the response, to hell with it
318 for (i = 0; i < 1023; i++)
319 {
320 int l = read (fd, &r[i], 1);
321
322 if (l <= 0)
323 {
324 error ();
325 return;
326 }
327
328 if (r[i] == '\012')
329 {
330 if (emptyline)
331 break;
332 else
333 emptyline = true;
334 }
335 else if (r[i] != '\015')
336 emptyline = false;
337 }
338
339 fcntl (fd, F_SETFL, O_NONBLOCK);
340
341 if (i < 12)
342 {
343 slog (L_ERR, _("(%s): unable to do proxy-forwarding, short response"),
344 (const char *)si);
345 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 slog (L_ERR, _("(%s): malformed or unexpected proxy response (%.12s)"),
352 (const char *)si, r);
353 error ();
354 }
355 else
356 state = ESTABLISHED;
357 }
358 #endif
359 }
360 }
361
362 bool
363 tcp_connection::send_packet (vpn_packet *pkt, int tos)
364 {
365 last_activity = ev_now ();
366
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 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 fcntl (fd, F_SETFL, O_NONBLOCK);
405
406 if (connect (fd, csi->sav4 (), csi->salenv4 ()) >= 0
407 || errno == EINPROGRESS)
408 {
409 fcntl (fd, F_SETFL, O_NONBLOCK);
410 fcntl (fd, F_SETFD, FD_CLOEXEC);
411
412 state = CONNECTING;
413 start (fd, EV_WRITE);
414 }
415 else
416 close (fd);
417 }
418 }
419 else if (state == ESTABLISHED)
420 {
421 // 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 #if defined(SOL_IP) && defined(IP_TOS)
428 if (tos != this->tos)
429 {
430 this->tos = tos;
431 setsockopt (fd, SOL_IP, IP_TOS, &tos, sizeof tos);
432 }
433 #endif
434
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
446 set (EV_READ | EV_WRITE);
447 }
448 }
449 }
450
451 return state != ERROR;
452 }
453
454 void tcp_connection::error ()
455 {
456 stop ();
457
458 if (fd >= 0)
459 {
460 close (fd);
461 tos = -1;
462 fd = -1;
463 }
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 tcp_connection::tcp_connection (int fd_, const sockinfo &si_, vpn &v_)
475 : v(v_), si(si_)
476 {
477 set<tcp_connection, &tcp_connection::tcpv4_ev> (this);
478
479 last_activity = ev_now ();
480 r_pkt = 0;
481 w_pkt = 0;
482 tos = -1;
483 fd = fd_;
484 #if ENABLE_HTTP_PROXY
485 proxy_req = 0;
486 #endif
487
488 if (fd < 0)
489 {
490 active = true;
491 state = IDLE;
492 }
493 else
494 {
495 active = false;
496 state = ESTABLISHED;
497 start (fd, EV_READ);
498 }
499 }
500
501 tcp_connection::~tcp_connection ()
502 {
503 error ();
504 }
505
506 #endif
507