git ssb

0+

cel / sslh



Tree: f4d2a8d2adb32056e656a73ce3d1d1d155f81046

Files: f4d2a8d2adb32056e656a73ce3d1d1d155f81046 / sslh-fork.c

4738 bytesRaw
1/*
2 sslh-fork: forking server
3
4# Copyright (C) 2007-2012 Yves Rutschle
5#
6# This program is free software; you can redistribute it
7# and/or modify it under the terms of the GNU General Public
8# License as published by the Free Software Foundation; either
9# version 2 of the License, or (at your option) any later
10# version.
11#
12# This program is distributed in the hope that it will be
13# useful, but WITHOUT ANY WARRANTY; without even the implied
14# warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
15# PURPOSE. See the GNU General Public License for more
16# details.
17#
18# The full text for the General Public License is here:
19# http://www.gnu.org/licenses/gpl.html
20
21*/
22
23#include "common.h"
24#include "probe.h"
25
26const char* server_type = "sslh-fork";
27
28#define MAX(a, b) (((a) > (b)) ? (a) : (b))
29
30/* shovels data from one fd to the other and vice-versa
31 returns after one socket closed
32 */
33int shovel(struct connection *cnx)
34{
35 fd_set fds;
36 int res, i;
37 int max_fd = MAX(cnx->q[0].fd, cnx->q[1].fd) + 1;
38
39 FD_ZERO(&fds);
40 while (1) {
41 FD_SET(cnx->q[0].fd, &fds);
42 FD_SET(cnx->q[1].fd, &fds);
43
44 res = select(
45 max_fd,
46 &fds,
47 NULL,
48 NULL,
49 NULL
50 );
51 CHECK_RES_DIE(res, "select");
52
53 for (i = 0; i < 2; i++) {
54 if (FD_ISSET(cnx->q[i].fd, &fds)) {
55 res = fd2fd(&cnx->q[1-i], &cnx->q[i]);
56 if (!res) {
57 if (verbose)
58 fprintf(stderr, "%s %s", i ? "client" : "server", "socket closed\n");
59 return res;
60 }
61 }
62 }
63 }
64}
65
66/* Child process that finds out what to connect to and proxies
67 */
68void start_shoveler(int in_socket)
69{
70 fd_set fds;
71 struct timeval tv;
72 int res = PROBE_AGAIN;
73 int out_socket;
74 struct connection cnx;
75
76 init_cnx(&cnx);
77 cnx.q[0].fd = in_socket;
78
79 FD_ZERO(&fds);
80 FD_SET(in_socket, &fds);
81 memset(&tv, 0, sizeof(tv));
82 tv.tv_sec = probing_timeout;
83
84 while (res == PROBE_AGAIN) {
85 /* POSIX does not guarantee that tv will be updated, but the client can
86 * only postpone the inevitable for so long */
87 res = select(in_socket + 1, &fds, NULL, NULL, &tv);
88 if (res == -1)
89 perror("select");
90
91 if (FD_ISSET(in_socket, &fds)) {
92 /* Received data: figure out what protocol it is */
93 res = probe_client_protocol(&cnx);
94 } else {
95 /* Timed out: it's necessarily SSH */
96 cnx.proto = timeout_protocol();
97 break;
98 }
99 }
100
101 if (cnx.proto->service &&
102 check_access_rights(in_socket, cnx.proto->service)) {
103 exit(0);
104 }
105
106 /* Connect the target socket */
107 out_socket = connect_addr(&cnx, in_socket);
108 CHECK_RES_DIE(out_socket, "connect");
109
110 cnx.q[1].fd = out_socket;
111
112 log_connection(&cnx);
113
114 flush_deferred(&cnx.q[1]);
115
116 shovel(&cnx);
117
118 close(in_socket);
119 close(out_socket);
120
121 if (verbose)
122 fprintf(stderr, "connection closed down\n");
123
124 exit(0);
125}
126
127static int *listener_pid;
128static int listener_pid_number = 0;
129
130void stop_listeners(int sig)
131{
132 int i;
133
134 for (i = 0; i < listener_pid_number; i++) {
135 kill(listener_pid[i], sig);
136 }
137}
138
139void main_loop(int listen_sockets[], int num_addr_listen)
140{
141 int in_socket, i, res;
142 struct sigaction action;
143
144 listener_pid_number = num_addr_listen;
145 listener_pid = malloc(listener_pid_number * sizeof(listener_pid[0]));
146
147 /* Start one process for each listening address */
148 for (i = 0; i < num_addr_listen; i++) {
149 if (!(listener_pid[i] = fork())) {
150
151 /* Listening process just accepts a connection, forks, and goes
152 * back to listening */
153 while (1)
154 {
155 in_socket = accept(listen_sockets[i], 0, 0);
156 if (verbose) fprintf(stderr, "accepted fd %d\n", in_socket);
157
158 if (!fork())
159 {
160 for (i = 0; i < num_addr_listen; ++i)
161 close(listen_sockets[i]);
162 start_shoveler(in_socket);
163 exit(0);
164 }
165 close(in_socket);
166 }
167 }
168 }
169
170 /* Set SIGTERM to "stop_listeners" which further kills all listener
171 * processes. Note this won't kill processes that listeners forked, which
172 * means active connections remain active. */
173 memset(&action, 0, sizeof(action));
174 action.sa_handler = stop_listeners;
175 res = sigaction(SIGTERM, &action, NULL);
176 CHECK_RES_DIE(res, "sigaction");
177
178 wait(NULL);
179}
180
181/* The actual main is in common.c: it's the same for both version of
182 * the server
183 */
184
185

Built with git-ssb-web