git ssb

0+

cel / sslh



Tree: ae008179f033c8409c69b13787a539351bace626

Files: ae008179f033c8409c69b13787a539351bace626 / sslh-fork.c

4508 bytesRaw
1/*
2 Reimplementation of sslh in C
3
4# Copyright (C) 2007-2011 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
25const char* server_type = "sslh-fork";
26
27#define MAX(a, b) (((a) > (b)) ? (a) : (b))
28
29/* shovels data from one fd to the other and vice-versa
30 returns after one socket closed
31 */
32int shovel(struct connection *cnx)
33{
34 fd_set fds;
35 int res, i;
36 int max_fd = MAX(cnx->q[0].fd, cnx->q[1].fd) + 1;
37
38 FD_ZERO(&fds);
39 while (1) {
40 FD_SET(cnx->q[0].fd, &fds);
41 FD_SET(cnx->q[1].fd, &fds);
42
43 res = select(
44 max_fd,
45 &fds,
46 NULL,
47 NULL,
48 NULL
49 );
50 CHECK_RES_DIE(res, "select");
51
52 for (i = 0; i < 2; i++) {
53 if (FD_ISSET(cnx->q[i].fd, &fds)) {
54 res = fd2fd(&cnx->q[1-i], &cnx->q[i]);
55 if (!res) {
56 if (verbose)
57 fprintf(stderr, "%s %s", i ? "client" : "server", "socket closed\n");
58 return res;
59 }
60 }
61 }
62 }
63}
64
65/* Child process that finds out what to connect to and proxies
66 */
67void start_shoveler(int in_socket)
68{
69 fd_set fds;
70 struct timeval tv;
71 struct addrinfo *saddr;
72 int res;
73 int out_socket;
74 struct connection cnx;
75 T_PROTO_ID prot;
76
77 init_cnx(&cnx);
78
79 FD_ZERO(&fds);
80 FD_SET(in_socket, &fds);
81 memset(&tv, 0, sizeof(tv));
82 tv.tv_sec = probing_timeout;
83 res = select(in_socket + 1, &fds, NULL, NULL, &tv);
84 if (res == -1)
85 perror("select");
86
87 cnx.q[0].fd = in_socket;
88
89 if (FD_ISSET(in_socket, &fds)) {
90 /* Received data: figure out what protocol it is */
91 prot = probe_client_protocol(&cnx);
92 } else {
93 /* Timed out: it's necessarily SSH */
94 prot = 0;
95 }
96
97 saddr = &protocols[prot].saddr;
98 if (protocols[prot].service &&
99 check_access_rights(in_socket, protocols[prot].service)) {
100 exit(0);
101 }
102
103 /* Connect the target socket */
104 out_socket = connect_addr(saddr, protocols[prot].description);
105 CHECK_RES_DIE(out_socket, "connect");
106
107 cnx.q[1].fd = out_socket;
108
109 log_connection(&cnx);
110
111 flush_defered(&cnx.q[1]);
112
113 shovel(&cnx);
114
115 close(in_socket);
116 close(out_socket);
117
118 if (verbose)
119 fprintf(stderr, "connection closed down\n");
120
121 exit(0);
122}
123
124static int *listener_pid;
125static int listener_pid_number = 0;
126
127void stop_listeners(int sig)
128{
129 int i;
130
131 for (i = 0; i < listener_pid_number; i++) {
132 kill(listener_pid[i], sig);
133 }
134}
135
136void main_loop(int listen_sockets[], int num_addr_listen)
137{
138 int in_socket, i, res;
139 struct sigaction action;
140
141 listener_pid = malloc(listener_pid_number * sizeof(listener_pid[0]));
142
143 /* Start one process for each listening address */
144 for (i = 0; i < num_addr_listen; i++) {
145 if (!(listener_pid[i] = fork())) {
146
147 /* Listening process just accepts a connection, forks, and goes
148 * back to listening */
149 while (1)
150 {
151 in_socket = accept(listen_sockets[i], 0, 0);
152 if (verbose) fprintf(stderr, "accepted fd %d\n", in_socket);
153
154 if (!fork())
155 {
156 close(listen_sockets[i]);
157 start_shoveler(in_socket);
158 exit(0);
159 }
160 close(in_socket);
161 }
162 }
163 }
164
165 /* Set SIGTERM to "stop_listeners" which further kills all listener
166 * processes. Note this won't kill processes that listeners forked, which
167 * means active connections remain active. */
168 memset(&action, 0, sizeof(action));
169 action.sa_handler = stop_listeners;
170 res = sigaction(SIGTERM, &action, NULL);
171 CHECK_RES_DIE(res, "sigaction");
172
173 listener_pid_number = num_addr_listen;
174 wait(NULL);
175}
176
177/* The actual main is in common.c: it's the same for both version of
178 * the server
179 */
180
181

Built with git-ssb-web