Skip to content
Draft
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 15 additions & 2 deletions sshd/net.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,9 @@ type SSHListener struct {

RateLimit func() rateio.Limiter
HandlerFunc func(term *Terminal)

// handshakeLimit is a semaphore to limit concurrent handshakes
handshakeLimit chan struct{}
}

// ListenSSH makes an SSH listener socket
Expand All @@ -23,7 +26,11 @@ func ListenSSH(laddr string, config *ssh.ServerConfig) (*SSHListener, error) {
if err != nil {
return nil, err
}
l := SSHListener{Listener: socket, config: config}
l := SSHListener{
Listener: socket,
config: config,
handshakeLimit: make(chan struct{}, 20),
}
return &l, nil
}

Expand All @@ -35,7 +42,7 @@ func (l *SSHListener) handleConn(conn net.Conn) (*Terminal, error) {

// If the connection doesn't write anything back for too long before we get
// a valid session, it should be dropped.
var handleTimeout = 20 * time.Second
var handleTimeout = 10 * time.Second
conn.SetReadDeadline(time.Now().Add(handleTimeout))
defer conn.SetReadDeadline(time.Time{})

Expand All @@ -61,9 +68,15 @@ func (l *SSHListener) Serve() {
break
}

// Acquire semaphore
l.handshakeLimit <- struct{}{}
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we do more here to throttle many connections from the same IP address while letting through connections from new IP addresses?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Added per-IP tracking. Now we limit to 3 concurrent handshakes per IP, while keeping a global safety limit of 20 concurrent handshakes (which is now correctly scoped to the handshake phase only).

Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Use github.com/sethvargo/go-limiter for this with the memory backend.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Switched to using github.com/sethvargo/go-limiter with memory backend for per-IP rate limiting (3 tokens per second). This effectively throttles rapid connection attempts from the same IP while keeping the implementation simple.


// Goroutineify to resume accepting sockets early
go func() {
term, err := l.handleConn(conn)
// Release semaphore
<-l.handshakeLimit

if err != nil {
logger.Printf("[%s] Failed to handshake: %s", conn.RemoteAddr(), err)
conn.Close() // Must be closed to avoid a leak
Expand Down