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