diff options
Diffstat (limited to 'sshd.c')
-rw-r--r-- | sshd.c | 88 |
1 files changed, 64 insertions, 24 deletions
@@ -1,4 +1,4 @@ | |||
1 | /* $OpenBSD: sshd.c,v 1.554 2020/05/15 08:34:03 markus Exp $ */ | 1 | /* $OpenBSD: sshd.c,v 1.555 2020/05/26 01:09:05 djm Exp $ */ |
2 | /* | 2 | /* |
3 | * Author: Tatu Ylonen <ylo@cs.hut.fi> | 3 | * Author: Tatu Ylonen <ylo@cs.hut.fi> |
4 | * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland | 4 | * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland |
@@ -829,7 +829,7 @@ notify_hostkeys(struct ssh *ssh) | |||
829 | * all connections are dropped for startups > max_startups | 829 | * all connections are dropped for startups > max_startups |
830 | */ | 830 | */ |
831 | static int | 831 | static int |
832 | drop_connection(int startups) | 832 | should_drop_connection(int startups) |
833 | { | 833 | { |
834 | int p, r; | 834 | int p, r; |
835 | 835 | ||
@@ -846,10 +846,68 @@ drop_connection(int startups) | |||
846 | p += options.max_startups_rate; | 846 | p += options.max_startups_rate; |
847 | r = arc4random_uniform(100); | 847 | r = arc4random_uniform(100); |
848 | 848 | ||
849 | debug("drop_connection: p %d, r %d", p, r); | 849 | debug("%s: p %d, r %d", __func__, p, r); |
850 | return (r < p) ? 1 : 0; | 850 | return (r < p) ? 1 : 0; |
851 | } | 851 | } |
852 | 852 | ||
853 | /* | ||
854 | * Check whether connection should be accepted by MaxStartups. | ||
855 | * Returns 0 if the connection is accepted. If the connection is refused, | ||
856 | * returns 1 and attempts to send notification to client. | ||
857 | * Logs when the MaxStartups condition is entered or exited, and periodically | ||
858 | * while in that state. | ||
859 | */ | ||
860 | static int | ||
861 | drop_connection(int sock, int startups) | ||
862 | { | ||
863 | char *laddr, *raddr; | ||
864 | const char msg[] = "Exceeded MaxStartups\r\n"; | ||
865 | static time_t last_drop, first_drop; | ||
866 | static u_int ndropped; | ||
867 | LogLevel drop_level = SYSLOG_LEVEL_VERBOSE; | ||
868 | time_t now; | ||
869 | |||
870 | now = monotime(); | ||
871 | if (!should_drop_connection(startups)) { | ||
872 | if (last_drop != 0 && | ||
873 | startups < options.max_startups_begin - 1) { | ||
874 | /* XXX maybe need better hysteresis here */ | ||
875 | logit("exited MaxStartups throttling after %s, " | ||
876 | "%u connections dropped", | ||
877 | fmt_timeframe(now - first_drop), ndropped); | ||
878 | last_drop = 0; | ||
879 | } | ||
880 | return 0; | ||
881 | } | ||
882 | |||
883 | #define SSHD_MAXSTARTUPS_LOG_INTERVAL (5 * 60) | ||
884 | if (last_drop == 0) { | ||
885 | error("beginning MaxStartups throttling"); | ||
886 | drop_level = SYSLOG_LEVEL_INFO; | ||
887 | first_drop = now; | ||
888 | ndropped = 0; | ||
889 | } else if (last_drop + SSHD_MAXSTARTUPS_LOG_INTERVAL < now) { | ||
890 | /* Periodic logs */ | ||
891 | error("in MaxStartups throttling for %s, " | ||
892 | "%u connections dropped", | ||
893 | fmt_timeframe(now - first_drop), ndropped + 1); | ||
894 | drop_level = SYSLOG_LEVEL_INFO; | ||
895 | } | ||
896 | last_drop = now; | ||
897 | ndropped++; | ||
898 | |||
899 | laddr = get_local_ipaddr(sock); | ||
900 | raddr = get_peer_ipaddr(sock); | ||
901 | do_log2(drop_level, "drop connection #%d from [%s]:%d on [%s]:%d " | ||
902 | "past MaxStartups", startups, raddr, get_peer_port(sock), | ||
903 | laddr, get_local_port(sock)); | ||
904 | free(laddr); | ||
905 | free(raddr); | ||
906 | /* best-effort notification to client */ | ||
907 | (void)write(sock, msg, sizeof(msg) - 1); | ||
908 | return 1; | ||
909 | } | ||
910 | |||
853 | static void | 911 | static void |
854 | usage(void) | 912 | usage(void) |
855 | { | 913 | { |
@@ -1206,27 +1264,9 @@ server_accept_loop(int *sock_in, int *sock_out, int *newsock, int *config_s) | |||
1206 | usleep(100 * 1000); | 1264 | usleep(100 * 1000); |
1207 | continue; | 1265 | continue; |
1208 | } | 1266 | } |
1209 | if (unset_nonblock(*newsock) == -1) { | 1267 | if (unset_nonblock(*newsock) == -1 || |
1210 | close(*newsock); | 1268 | drop_connection(*newsock, startups) || |
1211 | continue; | 1269 | pipe(startup_p) == -1) { |
1212 | } | ||
1213 | if (drop_connection(startups) == 1) { | ||
1214 | char *laddr = get_local_ipaddr(*newsock); | ||
1215 | char *raddr = get_peer_ipaddr(*newsock); | ||
1216 | char msg[] = "Exceeded MaxStartups\r\n"; | ||
1217 | |||
1218 | verbose("drop connection #%d from [%s]:%d " | ||
1219 | "on [%s]:%d past MaxStartups", startups, | ||
1220 | raddr, get_peer_port(*newsock), | ||
1221 | laddr, get_local_port(*newsock)); | ||
1222 | free(laddr); | ||
1223 | free(raddr); | ||
1224 | /* best-effort notification to client */ | ||
1225 | (void)write(*newsock, msg, strlen(msg)); | ||
1226 | close(*newsock); | ||
1227 | continue; | ||
1228 | } | ||
1229 | if (pipe(startup_p) == -1) { | ||
1230 | close(*newsock); | 1270 | close(*newsock); |
1231 | continue; | 1271 | continue; |
1232 | } | 1272 | } |