1 /*
2 * Copyright (c) 2002-2006 Tomas Svensson <ts@codepix.com>
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 * 3. The name of the author may not be used to endorse or promote products
14 * derived from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
17 * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
18 * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
19 * THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
20 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
21 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
22 * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
23 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
24 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
25 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27
28 #include "conf.h"
29
30 #define _POSIX_PII_SOCKET /* for Tru64 UNIX 5.1 */
31
32 #include <sys/types.h>
33 #ifdef WIN32
34 #include <Winsock2.h>
35 #include <process.h>
36 #define snprintf _snprintf
37 #define strcasecmp _stricmp
38 #define strncasecmp _strnicmp
39 typedef __int32 ssize_t;
40 typedef int socklen_t;
41 #define ECONNREFUSED WSAECONNREFUSED
42 #define EINPROGRESS WSAEWOULDBLOCK
43 #else
44 #include <sys/socket.h>
45 #include <netdb.h>
46 #include <sys/uio.h>
47 #include <unistd.h>
48 #include <netinet/in.h>
49 #include <arpa/inet.h>
50 #include <netinet/in_systm.h>
51 #include <netinet/ip.h>
52 #endif
53 #include <fcntl.h>
54 #include <sys/types.h>
55
56
57 #include <string.h>
58 #include <stdio.h>
59 #include <stdlib.h>
60 #include <errno.h>
61
62 extern int debug;
63
64 #include "tlswrap.h"
65 #include "network.h"
66 #include "misc.h"
67
68 #ifdef WIN32
69
write(SOCKET s,void * buf,int len)70 int write(SOCKET s, void *buf, int len) {
71 return send(s, (char*)buf, len, 0);
72 }
73
read(SOCKET s,void * buf,int len)74 int read(SOCKET s, void *buf, int len) {
75 return recv(s, (char*)buf, len, 0);
76 }
77
78 #endif
79
setup_connect_1(struct user_data * ud,int index,char * serv,char * port,int write_pipe)80 void setup_connect_1(struct user_data *ud, int index, char *serv,
81 char *port, int write_pipe) {
82 struct dns_msg dns;
83
84 dns.ud = index;
85 strlcpy(dns.port, port, sizeof(dns.port));
86 strlcpy(dns.hostname, serv, sizeof(dns.hostname));
87 if (write(write_pipe, &dns, sizeof(dns)) != sizeof(dns)) {
88 fprintf(stderr, "Error: Too many hostname lookups\n");
89 return;
90 }
91 ud->connected = CONN_DNS;
92 if (debug)
93 printf("Resolving %s on %d...\n",serv, index);
94 }
95
96 void
setup_connect_2(struct user_data * ud,struct dns_msg * dns,int data)97 setup_connect_2(struct user_data *ud, struct dns_msg *dns, int data)
98 {
99 char *ep;
100 int result, tos = 0;
101
102 if (strlen(dns->hostname) == 0) {
103 if (debug)
104 printf("Error: Could not resolve hostname\n");
105 if (!(data)) {
106 ud->connected = CONN_NO;
107 print_to_ud(ud, "530 Could not resolve hostname.\r\n");
108 }
109 return;
110 }
111 ud->ssl_data = NULL; /* Could be data left from other session, which would crash dataclose */
112 ud->rport = strtol(dns->port, &ep, 10);
113 if (debug)
114 printf("Connecting to %s on port %s, please wait...\n", dns->hostname, dns->port);
115
116 if (data) {
117 ud->serv_data_fd = setup_connect(dns->hostname, dns->port, &ud->lport, &result);
118 #ifndef WIN32
119 tos = IPTOS_THROUGHPUT;
120 if ((setsockopt(ud->serv_data_fd, IPPROTO_IP, IP_TOS, &tos, sizeof(tos)) == -1) && debug)
121 printf("Unable to set TOS=Throughput for data channel.\n");
122 #endif
123 } else {
124 ud->serv_fd = setup_connect(dns->hostname, dns->port,
125 &ud->lport, &result);
126 #ifndef WIN32
127 tos = IPTOS_THROUGHPUT;
128 if ((setsockopt(ud->serv_fd, IPPROTO_IP, IP_TOS, &tos, sizeof(tos)) == -1) && debug)
129 printf("Unable to set TOS=Lowdelay for control channel.\n");
130 #endif
131 }
132
133 if (result == 0) {
134 if (data) {
135 if (debug)
136 printf("data connected\n");
137 ud->data_connected = CONN_YES;
138 } else {
139 ud->connected = CONN_YES;
140 ud->serv_status = SERV_CONN;
141 }
142 } else if (result == 2) {
143 print_to_ud(ud, "Can't find hostname, should not happen!");
144 ud->connected = CONN_CMD;
145 } else if (result == 3) {
146 print_to_ud(ud,"421 Connection refused by server.\r\n");
147 user_close(ud);
148 } else if (result == 4) {
149 print_to_ud(ud,"421 Software caused connection abort.\r\n");
150 user_close(ud);
151 } else {
152 if (debug)
153 printf("connection in progress\n");
154 if (!data)
155 ud->connected = CONN_IN_PROG;
156 else
157 ud->data_connected = CONN_IN_PROG;
158 }
159 }
160
161 #ifdef WIN32
162 SOCKET
163 #else
164 int
165 #endif
setup_connect(const char * host,const char * port,unsigned int * lport,int * result)166 setup_connect(const char *host, const char *port,
167 unsigned int *lport, int *result)
168 {
169
170 int flags, sockopt;
171 char *ep;
172
173 struct sockaddr_in sin, *sin2;
174 unsigned short nport;
175 struct sockaddr sa;
176 socklen_t sa_len;
177 #ifdef WIN32
178 SOCKET conn_fd;
179 unsigned long nonblockopt = 1;
180 #else
181 int conn_fd;
182 #endif
183
184 conn_fd = socket(PF_INET, SOCK_STREAM, 0);
185
186 #ifdef WIN32
187 if (conn_fd == INVALID_SOCKET)
188 #else
189 if (conn_fd < 0)
190 #endif
191 sys_err("setup_connect_socket");
192
193 #ifdef WIN32
194 ioctlsocket(conn_fd, FIONBIO, &nonblockopt);
195 #else
196 flags = fcntl(conn_fd,F_GETFL);
197 fcntl(conn_fd, F_SETFL, flags | O_NONBLOCK);
198 #endif
199
200 sockopt = 1;
201 #ifdef WIN32
202 if (setsockopt(conn_fd, SOL_SOCKET, SO_KEEPALIVE, (char*)&sockopt, sizeof(sockopt)))
203 sys_err("setsockopt-keepalive");
204 #else
205 if (setsockopt(conn_fd, SOL_SOCKET, SO_KEEPALIVE, &sockopt, sizeof(sockopt)))
206 sys_err("setsockopt-keepalive");
207 #endif
208
209 memset(&sa,0,sizeof(sa));
210 sa.sa_family = PF_INET;
211 if (bind(conn_fd, &sa, sizeof(sa)) < 0)
212 perror("bind");
213
214 sa_len = sizeof(sa);
215 if (getsockname(conn_fd, &sa, &sa_len))
216 sys_err("getsockname");
217
218
219 memset(&sin, 0, sizeof(sin));
220 sin2 = (struct sockaddr_in *)&sa;
221 if (debug)
222 printf("host = %s, port = %s\n", host, port);
223 #if defined(HAVE_INET_ATON) || defined(HAVE_LIBRESOLV)
224 if (inet_aton(host, &sin.sin_addr) != 1)
225 sys_err(host);
226 #else
227 if ( (sin.sin_addr.s_addr = inet_addr(host)) == INADDR_NONE)
228 sys_err("inet_addr");
229 #endif
230 *lport = ntohs(sin2->sin_port);
231 nport = (unsigned short)strtol(port, &ep, 10);
232 sin.sin_port = htons(nport);
233 sin.sin_family = PF_INET;
234 if (connect(conn_fd, (struct sockaddr *)&sin, sizeof(sin)) != 0) {
235 #ifdef WIN32
236 errno = WSAGetLastError();
237 #endif
238 if (errno == ECONNREFUSED) {
239 *result = 3;
240 #ifdef WIN32
241 } else if (errno == WSAECONNABORTED) { // i.e. blocked by firewall or such
242 *result = 4;
243 #endif
244 } else {
245 if (errno != EINPROGRESS) {
246 if (debug) printf("socket error is %d", errno);
247 sys_err("connect");
248 }
249 *result = 1; /* Nonblocking operation */
250 }
251 } else
252 *result = 0; /* Connected */
253
254 return conn_fd;
255 }
256
257 #ifdef WIN32
258
259 extern int in_service;
260
dns_helper(void * arg)261 void dns_helper(void *arg) { // __cdecl
262 SOCKET *sarg = (SOCKET*)arg;
263 SOCKET read_fd = sarg[0];
264 SOCKET write_fd = sarg[1];
265 #else
266 void dns_helper(int read_fd, int write_fd) {
267 #endif
268 struct dns_msg dns;
269 ssize_t bytes;
270
271 struct sockaddr_in saddr;
272 struct hostent *hptr;
273
274 #ifdef HAVE_SETPROCTITLE
275 char sp[40];
276 unsigned int serv = 0;
277 #endif
278 for(;;) {
279 #ifdef HAVE_SETPROCTITLE
280 snprintf(sp, sizeof(sp), "tlswrap-dns (serviced %u reqs)",
281 serv++);
282 setproctitle(sp);
283 #endif
284 bytes = read(read_fd, &dns, sizeof(dns));
285 if (bytes == 0) {
286 if (debug)
287 printf("Parent died, exiting...\n");
288 #ifdef WIN32
289 // if (in_service)
290 // closesocket(pipe01[1]);
291 //x closesocket(pipe01[0]);
292 //x closesocket(pipe02[0]);
293 //x closesocket(pipe02[1]);
294 closesocket(write_fd);
295 _endthread();
296 // else
297 #endif
298 exit(0);
299 }
300
301 memset(&saddr, 0, sizeof(saddr));
302 if ((hptr = gethostbyname(dns.hostname)) == NULL)
303 dns.hostname[0] = '\0';
304 else {
305 memcpy(&saddr.sin_addr, hptr->h_addr,
306 sizeof(saddr.sin_addr));
307 strlcpy(dns.hostname, inet_ntoa(saddr.sin_addr),
308 sizeof(dns.hostname));
309 }
310 bytes = write(write_fd, &dns, sizeof(dns));
311 }
312
313 }
314
315 #ifdef WIN32
316 SOCKET
317 #else
318 int
319 #endif
320 setup_listen(int max_users, const char *host, char *port, int portlen)
321 {
322 /* IP V4 only version */
323
324 /* Returns a non-blocking listening socket on the specified port.
325 Listen backlog is set to max_users. if portlen != 0 then blah */
326
327 int flags, sockopt;
328 unsigned short rport;
329 socklen_t slen;
330
331 struct sockaddr_in sin;
332 char *ep;
333 struct hostent *hptr;
334 #ifdef WIN32
335 unsigned long nonblockopt = 1;
336 SOCKET listen_socket;
337 #else
338 int listen_socket;
339 #endif
340
341
342 rport = (unsigned short)strtol(port, &ep, 10);
343
344 memset(&sin, 0, sizeof(sin));
345 sin.sin_family = PF_INET;
346 sin.sin_port = htons(rport);
347
348 if (host == NULL)
349 sin.sin_addr.s_addr = htonl(INADDR_ANY);
350 else {
351 if ((hptr = gethostbyname(host)) == NULL) {
352 printf("hostname = %s\n", host);
353 sys_err("can't resolve specified local hostname");
354 } else
355 memcpy(&sin.sin_addr, hptr->h_addr, sizeof(sin.sin_addr));
356 }
357 listen_socket = socket(PF_INET, SOCK_STREAM, 0);
358
359 #ifdef WIN32
360 if (listen_socket == INVALID_SOCKET)
361 #else
362 if (listen_socket < 0)
363 #endif
364 sys_err("socket_listen_ipv4");
365
366 sockopt = 1;
367 #ifdef WIN32
368 if (setsockopt(listen_socket, SOL_SOCKET, SO_REUSEADDR, (char*)&sockopt,
369 sizeof(sockopt)))
370 sys_err("setsockopt-reuseaddr");
371 #else
372 if (setsockopt(listen_socket, SOL_SOCKET, SO_REUSEADDR, &sockopt,
373 sizeof(sockopt)))
374 sys_err("setsockopt-reuseaddr");
375 #endif
376
377 if (bind(listen_socket, (struct sockaddr *)&sin, sizeof(sin)))
378 sys_err("bind");
379
380 slen = sizeof(struct sockaddr_in);
381 if (getsockname(listen_socket, (struct sockaddr*)&sin, &slen) < 0)
382 sys_err("getsockname");
383
384 if (listen(listen_socket, max_users))
385 sys_err("listen");
386
387
388 #ifdef WIN32
389 ioctlsocket(listen_socket, FIONBIO, &nonblockopt);
390 #else
391 flags = fcntl(listen_socket, F_GETFL);
392 fcntl(listen_socket, F_SETFL, flags | O_NONBLOCK);
393 #endif
394 if (portlen > 0)
395 snprintf(port, portlen, "%u", ntohs(sin.sin_port));
396
397 return listen_socket;
398 }
399
400
401 int get_local_ip(int fd, char *ip, int iplen)
402 {
403 socklen_t slen;
404 struct sockaddr_in sin;
405
406 slen = sizeof(struct sockaddr_in);
407 if (getsockname(fd, (struct sockaddr*)&sin, &slen) < 0)
408 sys_err("getsockname");
409
410 strlcpy(ip, inet_ntoa(sin.sin_addr), iplen);
411 return 0;
412 }
413
414 int get_remote_ip(int fd, char *ip, int iplen)
415 {
416 socklen_t slen;
417 struct sockaddr_in sin;
418
419 slen = sizeof(struct sockaddr_in);
420 if (getpeername(fd, (struct sockaddr*)&sin, &slen) < 0)
421 sys_err("getsockname");
422
423 strlcpy(ip, inet_ntoa(sin.sin_addr), iplen);
424 return 0;
425 }
426