git ssb

0+

cel / sslh



Tree: c02e2d7aeeba25cb53d8a81acad55318ce63a4c4

Files: c02e2d7aeeba25cb53d8a81acad55318ce63a4c4 / sslh-fork.c

4513 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 struct addrinfo *saddr;
73 int res;
74 int out_socket;
75 struct connection cnx;
76 struct proto *prot;
77
78 init_cnx(&cnx);
79
80 FD_ZERO(&fds);
81 FD_SET(in_socket, &fds);
82 memset(&tv, 0, sizeof(tv));
83 tv.tv_sec = probing_timeout;
84 res = select(in_socket + 1, &fds, NULL, NULL, &tv);
85 if (res == -1)
86 perror("select");
87
88 cnx.q[0].fd = in_socket;
89
90 if (FD_ISSET(in_socket, &fds)) {
91 /* Received data: figure out what protocol it is */
92 prot = probe_client_protocol(&cnx);
93 } else {
94 /* Timed out: it's necessarily SSH */
95 prot = timeout_protocol();
96 }
97
98 saddr = prot->saddr;
99 if (prot->service &&
100 check_access_rights(in_socket, prot->service)) {
101 exit(0);
102 }
103
104 /* Connect the target socket */
105 out_socket = connect_addr(saddr, in_socket, prot->description);
106 CHECK_RES_DIE(out_socket, "connect");
107
108 cnx.q[1].fd = out_socket;
109
110 log_connection(&cnx);
111
112 flush_defered(&cnx.q[1]);
113
114 shovel(&cnx);
115
116 close(in_socket);
117 close(out_socket);
118
119 if (verbose)
120 fprintf(stderr, "connection closed down\n");
121
122 exit(0);
123}
124
125static int *listener_pid;
126static int listener_pid_number = 0;
127
128void stop_listeners(int sig)
129{
130 int i;
131
132 for (i = 0; i < listener_pid_number; i++) {
133 kill(listener_pid[i], sig);
134 }
135}
136
137void main_loop(int listen_sockets[], int num_addr_listen)
138{
139 int in_socket, i, res;
140 struct sigaction action;
141
142 listener_pid_number = num_addr_listen;
143 listener_pid = malloc(listener_pid_number * sizeof(listener_pid[0]));
144
145 /* Start one process for each listening address */
146 for (i = 0; i < num_addr_listen; i++) {
147 if (!(listener_pid[i] = fork())) {
148
149 /* Listening process just accepts a connection, forks, and goes
150 * back to listening */
151 while (1)
152 {
153 in_socket = accept(listen_sockets[i], 0, 0);
154 if (verbose) fprintf(stderr, "accepted fd %d\n", in_socket);
155
156 if (!fork())
157 {
158 close(listen_sockets[i]);
159 start_shoveler(in_socket);
160 exit(0);
161 }
162 close(in_socket);
163 }
164 }
165 }
166
167 /* Set SIGTERM to "stop_listeners" which further kills all listener
168 * processes. Note this won't kill processes that listeners forked, which
169 * means active connections remain active. */
170 memset(&action, 0, sizeof(action));
171 action.sa_handler = stop_listeners;
172 res = sigaction(SIGTERM, &action, NULL);
173 CHECK_RES_DIE(res, "sigaction");
174
175 wait(NULL);
176}
177
178/* The actual main is in common.c: it's the same for both version of
179 * the server
180 */
181
182

Built with git-ssb-web