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

# Content
1 /*
2 vpn_tcp.C -- handle the tcp part of the protocol.
3 Copyright (C) 2003-2007 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
8 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 along with gvpe; if not, write to the Free Software
19 Foundation, Inc. 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
20 */
21
22 #include "config.h"
23
24 #if ENABLE_TCP
25
26 // tcp processing is extremely ugly, since the gvpe protocol is simply
27 // designed for unreliable datagram networks. tcp is implemented by
28 // multiplexing packets over tcp. errors are completely ignored, as we
29 // rely on the higher level layers to time out and reconnect.
30
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 #include <fcntl.h>
41
42 #include <map>
43
44 #include "netcompat.h"
45
46 #include "vpn.h"
47
48 #if ENABLE_HTTP_PROXY
49 # include "conf.h"
50 #endif
51
52 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 void cleaner_cb (ev::timer &w, int revents); ev::timer cleaner;
64
65 tcp_si_map ()
66 : cleaner(this, &tcp_si_map::cleaner_cb)
67 {
68 cleaner.start (::conf.keepalive / 2, ::conf.keepalive / 2);
69 }
70
71 } tcp_si;
72
73 struct tcp_connection : ev::io {
74 int tos;
75 tstamp last_activity;
76 const sockinfo si;
77 vpn &v;
78 bool active; // this connection has been actively established
79 enum { ERROR, IDLE, CONNECTING, CONNECTING_PROXY, ESTABLISHED } state;
80
81 vpn_packet *r_pkt;
82 u32 r_len, r_ofs;
83
84 vpn_packet *w_pkt;
85 u32 w_len, w_ofs;
86
87 #if ENABLE_HTTP_PROXY
88 char *proxy_req;
89 int proxy_req_len;
90 #endif
91
92 void tcpv4_ev (ev::io &w, int revents);
93
94 bool send_packet (vpn_packet *pkt, int tos);
95 bool write_packet ();
96
97 void error (); // abort conenction && cleanup
98
99 operator tcp_si_map::value_type()
100 {
101 return tcp_si_map::value_type (&si, this);
102 }
103
104 tcp_connection (int fd_, const sockinfo &si_, vpn &v_);
105 ~tcp_connection ();
106 };
107
108 void tcp_si_map::cleaner_cb (ev::timer &w, int revents)
109 {
110 tstamp to = ev_now () - ::conf.keepalive - 30 - 60;
111
112 for (iterator i = begin (); i != end(); )
113 if (i->second->last_activity >= to)
114 ++i;
115 else
116 {
117 delete i->second;
118 erase (i);
119 i = begin ();
120 }
121 }
122
123 void
124 vpn::tcpv4_ev (ev::io &w, int revents)
125 {
126 if (revents & EV_READ)
127 {
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 fcntl (fd, F_SETFL, O_NONBLOCK);
137 fcntl (fd, F_SETFD, FD_CLOEXEC);
138
139 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 bool
150 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 return i->send_packet (pkt, tos);
165 }
166
167 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 //TODO: char* is the right type? hardly...
178 vec[0].iov_base = (char *)((u8 *)&plen) + w_ofs;
179 vec[0].iov_len = 2 - w_ofs;
180 vec[1].iov_base = (char *)&((*w_pkt)[0]);
181 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 void
205 tcp_connection::tcpv4_ev (ev::io &w, int revents)
206 {
207 last_activity = ev_now ();
208
209 if (revents & EV_WRITE)
210 {
211 if (state == CONNECTING)
212 {
213 state = ESTABLISHED;
214 set (EV_READ);
215 #if ENABLE_HTTP_PROXY
216 if (::conf.proxy_host && ::conf.proxy_port)
217 {
218 state = CONNECTING_PROXY;
219
220 if (write (fd, proxy_req, proxy_req_len) == 0)
221 {
222 error ();
223 return;
224 }
225
226 free (proxy_req); proxy_req = 0;
227 }
228 #endif
229 }
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 set (EV_READ);
239 }
240 }
241 else
242 set (EV_READ);
243 }
244 else
245 set (EV_READ);
246 }
247
248 if (revents & EV_READ)
249 {
250 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 // len == 0 <-> EOF
293 error ();
294 break;
295 }
296 #if ENABLE_HTTP_PROXY
297 else if (state == CONNECTING_PROXY)
298 {
299 fcntl (fd, F_SETFL, 0);
300 char r[1024];
301 int i;
302 bool emptyline = false;
303
304 // we do a blocking read of the response, to hell with it
305 for (i = 0; i < 1023; i++)
306 {
307 int l = read (fd, &r[i], 1);
308
309 if (l <= 0)
310 {
311 error ();
312 return;
313 }
314
315 if (r[i] == '\012')
316 {
317 if (emptyline)
318 break;
319 else
320 emptyline = true;
321 }
322 else if (r[i] != '\015')
323 emptyline = false;
324 }
325
326 fcntl (fd, F_SETFL, O_NONBLOCK);
327
328 if (i < 12)
329 {
330 slog (L_ERR, _("(%s): unable to do proxy-forwarding, short response"),
331 (const char *)si);
332 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 slog (L_ERR, _("(%s): malformed or unexpected proxy response (%.12s)"),
339 (const char *)si, r);
340 error ();
341 }
342 else
343 state = ESTABLISHED;
344 }
345 #endif
346 }
347 }
348
349 bool
350 tcp_connection::send_packet (vpn_packet *pkt, int tos)
351 {
352 last_activity = ev_now ();
353
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 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 fcntl (fd, F_SETFL, O_NONBLOCK);
392
393 if (connect (fd, csi->sav4 (), csi->salenv4 ()) >= 0
394 || errno == EINPROGRESS)
395 {
396 fcntl (fd, F_SETFL, O_NONBLOCK);
397 fcntl (fd, F_SETFD, FD_CLOEXEC);
398
399 state = CONNECTING;
400 start (fd, EV_WRITE);
401 }
402 else
403 close (fd);
404 }
405 }
406 else if (state == ESTABLISHED)
407 {
408 // 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 #if defined(SOL_IP) && defined(IP_TOS)
415 if (tos != this->tos)
416 {
417 this->tos = tos;
418 setsockopt (fd, SOL_IP, IP_TOS, &tos, sizeof tos);
419 }
420 #endif
421
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
433 set (EV_READ | EV_WRITE);
434 }
435 }
436 }
437
438 return state != ERROR;
439 }
440
441 void tcp_connection::error ()
442 {
443 stop ();
444
445 if (fd >= 0)
446 {
447 close (fd);
448 tos = -1;
449 fd = -1;
450 }
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 tcp_connection::tcp_connection (int fd_, const sockinfo &si_, vpn &v_)
462 : v(v_), si(si_), ev::io(this, &tcp_connection::tcpv4_ev)
463 {
464 last_activity = ev_now ();
465 r_pkt = 0;
466 w_pkt = 0;
467 tos = -1;
468 fd = fd_;
469 #if ENABLE_HTTP_PROXY
470 proxy_req = 0;
471 #endif
472
473 if (fd < 0)
474 {
475 active = true;
476 state = IDLE;
477 }
478 else
479 {
480 active = false;
481 state = ESTABLISHED;
482 start (fd, EV_READ);
483 }
484 }
485
486 tcp_connection::~tcp_connection ()
487 {
488 error ();
489 }
490
491 #endif
492