diff options
Diffstat (limited to 'serverloop.c')
-rw-r--r-- | serverloop.c | 64 |
1 files changed, 60 insertions, 4 deletions
diff --git a/serverloop.c b/serverloop.c index d6b360d9a..5a5b1e37f 100644 --- a/serverloop.c +++ b/serverloop.c | |||
@@ -35,7 +35,7 @@ | |||
35 | */ | 35 | */ |
36 | 36 | ||
37 | #include "includes.h" | 37 | #include "includes.h" |
38 | RCSID("$OpenBSD: serverloop.c,v 1.60 2001/04/05 23:39:20 markus Exp $"); | 38 | RCSID("$OpenBSD: serverloop.c,v 1.61 2001/04/13 22:46:54 beck Exp $"); |
39 | 39 | ||
40 | #include "xmalloc.h" | 40 | #include "xmalloc.h" |
41 | #include "packet.h" | 41 | #include "packet.h" |
@@ -91,6 +91,8 @@ static volatile int child_wait_status; /* Status from wait(). */ | |||
91 | 91 | ||
92 | void server_init_dispatch(void); | 92 | void server_init_dispatch(void); |
93 | 93 | ||
94 | int client_alive_timeouts = 0; | ||
95 | |||
94 | void | 96 | void |
95 | sigchld_handler(int sig) | 97 | sigchld_handler(int sig) |
96 | { | 98 | { |
@@ -190,6 +192,21 @@ wait_until_can_do_something(fd_set **readsetp, fd_set **writesetp, int *maxfdp, | |||
190 | { | 192 | { |
191 | struct timeval tv, *tvp; | 193 | struct timeval tv, *tvp; |
192 | int ret; | 194 | int ret; |
195 | int client_alive_scheduled = 0; | ||
196 | |||
197 | /* | ||
198 | * if using client_alive, set the max timeout accordingly, | ||
199 | * and indicate that this particular timeout was for client | ||
200 | * alive by setting the client_alive_scheduled flag. | ||
201 | * | ||
202 | * this could be randomized somewhat to make traffic | ||
203 | * analysis more difficult, but we're not doing it yet. | ||
204 | */ | ||
205 | if (max_time_milliseconds == 0 && options.client_alive_interval) { | ||
206 | client_alive_scheduled = 1; | ||
207 | max_time_milliseconds = options.client_alive_interval * 1000; | ||
208 | } else | ||
209 | client_alive_scheduled = 0; | ||
193 | 210 | ||
194 | /* When select fails we restart from here. */ | 211 | /* When select fails we restart from here. */ |
195 | retry_select: | 212 | retry_select: |
@@ -239,7 +256,7 @@ retry_select: | |||
239 | * from it, then read as much as is available and exit. | 256 | * from it, then read as much as is available and exit. |
240 | */ | 257 | */ |
241 | if (child_terminated && packet_not_very_much_data_to_write()) | 258 | if (child_terminated && packet_not_very_much_data_to_write()) |
242 | if (max_time_milliseconds == 0) | 259 | if (max_time_milliseconds == 0 || client_alive_scheduled) |
243 | max_time_milliseconds = 100; | 260 | max_time_milliseconds = 100; |
244 | 261 | ||
245 | if (max_time_milliseconds == 0) | 262 | if (max_time_milliseconds == 0) |
@@ -255,12 +272,36 @@ retry_select: | |||
255 | /* Wait for something to happen, or the timeout to expire. */ | 272 | /* Wait for something to happen, or the timeout to expire. */ |
256 | ret = select((*maxfdp)+1, *readsetp, *writesetp, NULL, tvp); | 273 | ret = select((*maxfdp)+1, *readsetp, *writesetp, NULL, tvp); |
257 | 274 | ||
258 | if (ret < 0) { | 275 | if (ret == -1) { |
259 | if (errno != EINTR) | 276 | if (errno != EINTR) |
260 | error("select: %.100s", strerror(errno)); | 277 | error("select: %.100s", strerror(errno)); |
261 | else | 278 | else |
262 | goto retry_select; | 279 | goto retry_select; |
263 | } | 280 | } |
281 | if (ret == 0 && client_alive_scheduled) { | ||
282 | /* timeout, check to see how many we have had */ | ||
283 | client_alive_timeouts++; | ||
284 | |||
285 | if (client_alive_timeouts > options.client_alive_count_max ) { | ||
286 | packet_disconnect( | ||
287 | "Timeout, your session not responding."); | ||
288 | } else { | ||
289 | /* | ||
290 | * send a bogus channel request with "wantreply" | ||
291 | * we should get back a failure | ||
292 | */ | ||
293 | int id; | ||
294 | |||
295 | id = channel_find_open(); | ||
296 | if (id != -1) { | ||
297 | channel_request_start(id, | ||
298 | "keepalive@openssh.com", 1); | ||
299 | packet_send(); | ||
300 | } else | ||
301 | packet_disconnect( | ||
302 | "No open channels after timeout!"); | ||
303 | } | ||
304 | } | ||
264 | } | 305 | } |
265 | 306 | ||
266 | /* | 307 | /* |
@@ -701,6 +742,19 @@ server_loop2(void) | |||
701 | } | 742 | } |
702 | 743 | ||
703 | void | 744 | void |
745 | server_input_channel_failure(int type, int plen, void *ctxt) | ||
746 | { | ||
747 | debug("Got CHANNEL_FAILURE for keepalive"); | ||
748 | /* | ||
749 | * reset timeout, since we got a sane answer from the client. | ||
750 | * even if this was generated by something other than | ||
751 | * the bogus CHANNEL_REQUEST we send for keepalives. | ||
752 | */ | ||
753 | client_alive_timeouts = 0; | ||
754 | } | ||
755 | |||
756 | |||
757 | void | ||
704 | server_input_stdin_data(int type, int plen, void *ctxt) | 758 | server_input_stdin_data(int type, int plen, void *ctxt) |
705 | { | 759 | { |
706 | char *data; | 760 | char *data; |
@@ -912,7 +966,8 @@ server_init_dispatch_20(void) | |||
912 | dispatch_set(SSH2_MSG_CHANNEL_REQUEST, &channel_input_channel_request); | 966 | dispatch_set(SSH2_MSG_CHANNEL_REQUEST, &channel_input_channel_request); |
913 | dispatch_set(SSH2_MSG_CHANNEL_WINDOW_ADJUST, &channel_input_window_adjust); | 967 | dispatch_set(SSH2_MSG_CHANNEL_WINDOW_ADJUST, &channel_input_window_adjust); |
914 | dispatch_set(SSH2_MSG_GLOBAL_REQUEST, &server_input_global_request); | 968 | dispatch_set(SSH2_MSG_GLOBAL_REQUEST, &server_input_global_request); |
915 | 969 | /* client_alive */ | |
970 | dispatch_set(SSH2_MSG_CHANNEL_FAILURE, &server_input_channel_failure); | ||
916 | /* rekeying */ | 971 | /* rekeying */ |
917 | dispatch_set(SSH2_MSG_KEXINIT, &kex_input_kexinit); | 972 | dispatch_set(SSH2_MSG_KEXINIT, &kex_input_kexinit); |
918 | } | 973 | } |
@@ -949,3 +1004,4 @@ server_init_dispatch(void) | |||
949 | else | 1004 | else |
950 | server_init_dispatch_15(); | 1005 | server_init_dispatch_15(); |
951 | } | 1006 | } |
1007 | |||