View | Details | Raw Unified | Return to bug 3055 | Differences between
and this patch

Collapse All | Expand All

(-)misc.c (+29 lines)
Lines 517-522 convtime(const char *s) Link Here
517
}
517
}
518
518
519
/*
519
/*
520
 * format a time interval (in seconds) for human readability, e.g.
521
 * 600 => "10m", 87300 => "1d15m".
522
 * Returns NULL on error. Caller must free result.
523
 */
524
char *
525
fmt_interval(u_int seconds)
526
{
527
	char *ret = NULL;
528
529
	if (seconds == 0)
530
		return strdup("0s");
531
532
#define FMT_UNIT(unit, letter) \
533
	do { \
534
		if (seconds >= unit) { \
535
			xextendf(&ret, "", "%u%c", seconds / unit, letter); \
536
			seconds %= unit; \
537
		} \
538
	} while(0)
539
	FMT_UNIT(WEEKS, 'w');
540
	FMT_UNIT(DAYS, 'd');
541
	FMT_UNIT(HOURS, 'h');
542
	FMT_UNIT(MINUTES, 'm');
543
	FMT_UNIT(1, 's');
544
#undef FMT_UNIT
545
	return ret;
546
}
547
548
/*
520
 * Returns a standardized host+port identifier string.
549
 * Returns a standardized host+port identifier string.
521
 * Caller must free returned string.
550
 * Caller must free returned string.
522
 */
551
 */
(-)misc.h (+1 lines)
Lines 66-71 int parse_user_host_path(const char *, Link Here
66
int	 parse_user_host_port(const char *, char **, char **, int *);
66
int	 parse_user_host_port(const char *, char **, char **, int *);
67
int	 parse_uri(const char *, const char *, char **, char **, int *, char **);
67
int	 parse_uri(const char *, const char *, char **, char **, int *, char **);
68
long	 convtime(const char *);
68
long	 convtime(const char *);
69
char	*fmt_interval(u_int);
69
char	*tilde_expand_filename(const char *, uid_t);
70
char	*tilde_expand_filename(const char *, uid_t);
70
char	*percent_expand(const char *, ...) __attribute__((__sentinel__));
71
char	*percent_expand(const char *, ...) __attribute__((__sentinel__));
71
char	*tohex(const void *, size_t);
72
char	*tohex(const void *, size_t);
(-)sshd.c (-23 / +63 lines)
Lines 788-794 notify_hostkeys(struct ssh *ssh) Link Here
788
 * all connections are dropped for startups > max_startups
788
 * all connections are dropped for startups > max_startups
789
 */
789
 */
790
static int
790
static int
791
drop_connection(int startups)
791
should_drop_connection(int startups)
792
{
792
{
793
	int p, r;
793
	int p, r;
794
794
Lines 805-814 drop_connection(int startups) Link Here
805
	p += options.max_startups_rate;
805
	p += options.max_startups_rate;
806
	r = arc4random_uniform(100);
806
	r = arc4random_uniform(100);
807
807
808
	debug("drop_connection: p %d, r %d", p, r);
808
	debug("%s: p %d, r %d", __func__, p, r);
809
	return (r < p) ? 1 : 0;
809
	return (r < p) ? 1 : 0;
810
}
810
}
811
811
812
/*
813
 * Check whether connection should be accepted by MaxStartups.
814
 * Returns 0 if the connection is accepted. If the connection is refused,
815
 * returns 1 and attempts to send notification to client.
816
 * Logs when the MaxStartups condition is entered or exited, and periodically
817
 * while in that state.
818
 */
819
static int
820
drop_connection(int sock, int startups)
821
{
822
	char *laddr, *raddr;
823
	const char msg[] = "Exceeded MaxStartups\r\n";
824
	static time_t last_drop, first_drop;
825
	static u_int ndropped;
826
	LogLevel drop_level = SYSLOG_LEVEL_VERBOSE;
827
	time_t now;
828
829
	now = monotime();
830
	if (!should_drop_connection(startups)) {
831
		if (last_drop != 0 &&
832
		    startups < options.max_startups_begin - 1) {
833
			/* XXX maybe need better hysteresis here */
834
			logit("exited MaxStartups throttling after %s, "
835
			    "%u connections dropped",
836
			    fmt_interval((u_int)(now - first_drop)), ndropped);
837
			last_drop = 0;
838
		}
839
		return 0;
840
	}
841
842
#define SSHD_MAXSTARTUPS_LOG_INTERVAL	(5 * 60)
843
	if (last_drop == 0) {
844
		error("beginning MaxStartups throttling");
845
		drop_level = SYSLOG_LEVEL_INFO;
846
		first_drop = now;
847
		ndropped = 0;
848
	} else if (last_drop + SSHD_MAXSTARTUPS_LOG_INTERVAL < now) {
849
		/* Periodic logs */
850
		error("in MaxStartups throttling for %s, "
851
		    "%u connections dropped",
852
		    fmt_interval((u_int)(now - first_drop)), ndropped + 1);
853
		drop_level = SYSLOG_LEVEL_INFO;
854
	}
855
	last_drop = now;
856
	ndropped++;
857
858
	laddr = get_local_ipaddr(sock);
859
	raddr = get_peer_ipaddr(sock);
860
	do_log2(drop_level, "drop connection #%d from [%s]:%d on [%s]:%d "
861
	    "past MaxStartups", startups, raddr, get_peer_port(sock),
862
	    laddr, get_local_port(sock));
863
	free(laddr);
864
	free(raddr);
865
	/* best-effort notification to client */
866
	(void)write(sock, msg, sizeof(msg) - 1);
867
	return 1;
868
}
869
812
static void
870
static void
813
usage(void)
871
usage(void)
814
{
872
{
Lines 1152-1178 server_accept_loop(int *sock_in, int *so Link Here
1152
					usleep(100 * 1000);
1210
					usleep(100 * 1000);
1153
				continue;
1211
				continue;
1154
			}
1212
			}
1155
			if (unset_nonblock(*newsock) == -1) {
1213
			if (unset_nonblock(*newsock) == -1 ||
1156
				close(*newsock);
1214
			    drop_connection(*newsock, startups) ||
1157
				continue;
1215
			    pipe(startup_p) == -1) {
1158
			}
1159
			if (drop_connection(startups) == 1) {
1160
				char *laddr = get_local_ipaddr(*newsock);
1161
				char *raddr = get_peer_ipaddr(*newsock);
1162
				char msg[] = "Exceeded MaxStartups\r\n";
1163
1164
				verbose("drop connection #%d from [%s]:%d "
1165
				    "on [%s]:%d past MaxStartups", startups,
1166
				    raddr, get_peer_port(*newsock),
1167
				    laddr, get_local_port(*newsock));
1168
				free(laddr);
1169
				free(raddr);
1170
				/* best-effort notification to client */
1171
				(void)write(*newsock, msg, strlen(msg));
1172
				close(*newsock);
1173
				continue;
1174
			}
1175
			if (pipe(startup_p) == -1) {
1176
				close(*newsock);
1216
				close(*newsock);
1177
				continue;
1217
				continue;
1178
			}
1218
			}

Return to bug 3055