1
0
mirror of https://github.com/moparisthebest/sslh synced 2024-11-11 11:45:07 -05:00
sslh/sslh-fork.c
Yves Rutschle 80f76c6fc5 v1.8:
Changed log format to make it possible to link
	connections to subsequent logs from other services.

	Updated CentOS init.d script (Andre Krajnik).

	Fixed zombie issue with OpenBSD (The SA_NOCLDWAIT flag is not
	propagated to the child process, so we set up signals after
	the fork.) (François FRITZ)

	Added -o "OpenVPN" and OpenVPN probing and support.

	Added single-threaded, select(2)-based version.

	Added support for "Bold" SSH clients (clients that speak first)
	Thanks to Guillaume Ricaud for spotting a regression
	bug.

	Added -f "foreground" option.

	Added test suite. (only tests connexions. No test for libwrap,
	setsid, setuid and so on) and corresponding 'make
	test' target.

	Added README.MacOSX (thanks Aaron Madlon-Kay)

	Documented use with proxytunnel and corkscrew in
	README.
2013-07-10 23:12:42 +02:00

152 lines
3.4 KiB
C

/*
Reimplementation of sslh in C
# Copyright (C) 2007-2008 Yves Rutschle
#
# This program is free software; you can redistribute it
# and/or modify it under the terms of the GNU General Public
# License as published by the Free Software Foundation; either
# version 2 of the License, or (at your option) any later
# version.
#
# This program is distributed in the hope that it will be
# useful, but WITHOUT ANY WARRANTY; without even the implied
# warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
# PURPOSE. See the GNU General Public License for more
# details.
#
# The full text for the General Public License is here:
# http://www.gnu.org/licenses/gpl.html
*/
#include "common.h"
const char* server_type = "sslh-fork";
#define MAX(a, b) (((a) > (b)) ? (a) : (b))
/* shovels data from one fd to the other and vice-versa
returns after one socket closed
*/
int shovel(struct connection *cnx)
{
fd_set fds;
int res, i;
int max_fd = MAX(cnx->q[0].fd, cnx->q[1].fd) + 1;
FD_ZERO(&fds);
while (1) {
FD_SET(cnx->q[0].fd, &fds);
FD_SET(cnx->q[1].fd, &fds);
res = select(
max_fd,
&fds,
NULL,
NULL,
NULL
);
CHECK_RES_DIE(res, "select");
for (i = 0; i < 2; i++) {
if (FD_ISSET(cnx->q[i].fd, &fds)) {
res = fd2fd(&cnx->q[1-i], &cnx->q[i]);
if (!res) {
if (verbose)
fprintf(stderr, "%s %s", i ? "client" : "server", "socket closed\n");
return res;
}
}
}
}
}
/* Child process that finds out what to connect to and proxies
*/
void start_shoveler(int in_socket)
{
fd_set fds;
struct timeval tv;
struct sockaddr *saddr;
int res;
int out_socket;
char *target;
struct connection cnx;
T_PROTO_ID prot;
init_cnx(&cnx);
FD_ZERO(&fds);
FD_SET(in_socket, &fds);
memset(&tv, 0, sizeof(tv));
tv.tv_sec = probing_timeout;
res = select(in_socket + 1, &fds, NULL, NULL, &tv);
if (res == -1)
perror("select");
cnx.q[0].fd = in_socket;
if (FD_ISSET(in_socket, &fds)) {
/* Received data: figure out what protocol it is */
prot = probe_client_protocol(&cnx);
} else {
/* Timed out: it's necessarily SSH */
prot = PROT_SSH;
}
saddr = &protocols[prot].saddr;
target = protocols[prot].description;
if (protocols[prot].service &&
check_access_rights(in_socket, protocols[prot].service)) {
exit(0);
}
/* Connect the target socket */
out_socket = socket(AF_INET, SOCK_STREAM, 0);
res = connect(out_socket, saddr, sizeof(addr_ssl));
CHECK_RES_DIE(res, "connect");
if (verbose)
fprintf(stderr, "connected to something\n");
cnx.q[1].fd = out_socket;
log_connection(&cnx);
flush_defered(&cnx.q[1]);
shovel(&cnx);
close(in_socket);
close(out_socket);
if (verbose)
fprintf(stderr, "connection closed down\n");
exit(0);
}
void main_loop(int listen_socket)
{
int in_socket;
while (1)
{
in_socket = accept(listen_socket, 0, 0);
if (verbose) fprintf(stderr, "accepted fd %d\n", in_socket);
if (!fork())
{
close(listen_socket);
start_shoveler(in_socket);
exit(0);
}
close(in_socket);
}
}
/* The actual main is in common.c: it's the same for both version of
* the server
*/