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