comparison tcpfwd-direct.c @ 9:7f77962de998

- Reworked non-channel fd handling to listener.c - More channel cleaning up
author Matt Johnston <matt@ucc.asn.au>
date Thu, 03 Jun 2004 16:45:53 +0000
parents
children f76c9389e9e0
comparison
equal deleted inserted replaced
7:425ed5c20157 9:7f77962de998
1 #include "includes.h"
2 #include "session.h"
3 #include "dbutil.h"
4 #include "channel.h"
5 #include "tcpfwd-direct.h"
6
7 #ifndef DISABLE_TCPFWD_DIRECT
8 static int newtcpdirect(struct Channel * channel);
9 static int newtcp(const char * host, int port);
10
11 const struct ChanType chan_tcpdirect = {
12 0, /* sepfds */
13 "direct-tcpip",
14 newtcpdirect, /* init */
15 NULL, /* checkclose */
16 NULL, /* reqhandler */
17 NULL /* closehandler */
18 };
19
20
21 /* Called upon creating a new direct tcp channel (ie we connect out to an
22 * address */
23 static int newtcpdirect(struct Channel * channel) {
24
25 unsigned char* desthost = NULL;
26 unsigned int destport;
27 unsigned char* orighost = NULL;
28 unsigned int origport;
29 int sock;
30 int len;
31 int ret = DROPBEAR_FAILURE;
32
33 if (ses.opts->nolocaltcp) {
34 TRACE(("leave newtcpdirect: local tcp forwarding disabled"));
35 goto out;
36 }
37
38 desthost = buf_getstring(ses.payload, &len);
39 if (len > MAX_HOST_LEN) {
40 TRACE(("leave newtcpdirect: desthost too long"));
41 goto out;
42 }
43
44 destport = buf_getint(ses.payload);
45
46 orighost = buf_getstring(ses.payload, &len);
47 if (len > MAX_HOST_LEN) {
48 TRACE(("leave newtcpdirect: orighost too long"));
49 goto out;
50 }
51
52 origport = buf_getint(ses.payload);
53
54 /* best be sure */
55 if (origport > 65535 || destport > 65535) {
56 TRACE(("leave newtcpdirect: port > 65535"));
57 goto out;
58 }
59
60 sock = newtcp(desthost, destport);
61 if (sock < 0) {
62 TRACE(("leave newtcpdirect: sock failed"));
63 goto out;
64 }
65
66 ses.maxfd = MAX(ses.maxfd, sock);
67
68 /* Note that infd is actually the "outgoing" direction on the
69 * tcp connection, vice versa for outfd.
70 * We don't set outfd, that will get set after the connection's
71 * progress succeeds */
72 channel->infd = sock;
73 channel->initconn = 1;
74
75 ret = DROPBEAR_SUCCESS;
76
77 out:
78 m_free(desthost);
79 m_free(orighost);
80 TRACE(("leave newtcpdirect: ret %d", ret));
81 return ret;
82 }
83
84 /* Initiate a new TCP connection - this is non-blocking, so the socket
85 * returned will need to be checked for success when it is first written.
86 * Similarities with OpenSSH's connect_to() are not coincidental.
87 * Returns -1 on failure */
88 static int newtcp(const char * host, int port) {
89
90 int sock = -1;
91 char portstring[6];
92 struct addrinfo *res = NULL, *ai;
93 int val;
94
95 struct addrinfo hints;
96
97 TRACE(("enter newtcp"));
98
99 memset(&hints, 0, sizeof(hints));
100 /* TCP, either ip4 or ip6 */
101 hints.ai_socktype = SOCK_STREAM;
102 hints.ai_family = PF_UNSPEC;
103
104 snprintf(portstring, sizeof(portstring), "%d", port);
105 if (getaddrinfo(host, portstring, &hints, &res) != 0) {
106 if (res) {
107 freeaddrinfo(res);
108 }
109 TRACE(("leave newtcp: failed getaddrinfo"));
110 return -1;
111 }
112
113 /* Use the first socket that works */
114 for (ai = res; ai != NULL; ai = ai->ai_next) {
115
116 if (ai->ai_family != PF_INET && ai->ai_family != PF_INET6) {
117 continue;
118 }
119
120 sock = socket(ai->ai_family, SOCK_STREAM, 0);
121 if (sock < 0) {
122 TRACE(("TCP socket() failed"));
123 continue;
124 }
125
126 if (fcntl(sock, F_SETFL, O_NONBLOCK) < 0) {
127 close(sock);
128 TRACE(("TCP non-blocking failed"));
129 continue;
130 }
131
132 /* non-blocking, so it might return without success (EINPROGRESS) */
133 if (connect(sock, ai->ai_addr, ai->ai_addrlen) < 0) {
134 if (errno == EINPROGRESS) {
135 TRACE(("connect in progress"));
136 } else {
137 close(sock);
138 TRACE(("TCP connect failed"));
139 continue;
140 }
141 }
142 break;
143 }
144
145 freeaddrinfo(res);
146
147 if (ai == NULL) {
148 return -1;
149 }
150
151 setsockopt(sock, IPPROTO_TCP, TCP_NODELAY, (void*)&val, sizeof(val));
152 return sock;
153 }
154 #endif /* DISABLE_TCPFWD_DIRECT */