From bed12803fa9663d7aa2c2346b0c634ad2dcd43b7 Mon Sep 17 00:00:00 2001 From: Heschi Kreinick Date: Wed, 1 Feb 2017 15:15:17 -0500 Subject: [PATCH] ssh: Support multiple source-addresses, don't require IPv4 in tests. The ssh tests currently require 127.0.0.1 to work which isn't necessarily available everywhere. To fix the source-address tests, support comma-separated source-address values per the PROTOCOL.certkeys file: Comma-separated list of source addresses from which this certificate is accepted for authentication. Addresses are specified in CIDR format (nn.nn.nn.nn/nn or hhhh::hhhh/nn). If this option is not present then certificates may be presented from any source address. Change-Id: I87536ff81ffa005c073da103021ebc0dfb12b620 Reviewed-on: https://go-review.googlesource.com/36110 Reviewed-by: Han-Wen Nienhuys Run-TryBot: Heschi Kreinick --- ssh/client_auth_test.go | 4 ++-- ssh/handshake_test.go | 2 +- ssh/server.go | 27 +++++++++++++++------------ 3 files changed, 18 insertions(+), 15 deletions(-) diff --git a/ssh/client_auth_test.go b/ssh/client_auth_test.go index 1d9681a06c..e384c796b7 100644 --- a/ssh/client_auth_test.go +++ b/ssh/client_auth_test.go @@ -333,14 +333,14 @@ func TestClientLoginCert(t *testing.T) { } // allowed source address - cert.CriticalOptions = map[string]string{"source-address": "127.0.0.42/24"} + cert.CriticalOptions = map[string]string{"source-address": "127.0.0.42/24,::42/120"} cert.SignCert(rand.Reader, testSigners["ecdsa"]) if err := tryAuth(t, clientConfig); err != nil { t.Errorf("cert login with source-address failed: %v", err) } // disallowed source address - cert.CriticalOptions = map[string]string{"source-address": "127.0.0.42"} + cert.CriticalOptions = map[string]string{"source-address": "127.0.0.42,::42"} cert.SignCert(rand.Reader, testSigners["ecdsa"]) if err := tryAuth(t, clientConfig); err == nil { t.Errorf("cert login with source-address succeeded") diff --git a/ssh/handshake_test.go b/ssh/handshake_test.go index 4d643768a6..1b831127e8 100644 --- a/ssh/handshake_test.go +++ b/ssh/handshake_test.go @@ -40,7 +40,7 @@ func (t *testChecker) Check(dialAddr string, addr net.Addr, key PublicKey) error // therefore is buffered (net.Pipe deadlocks if both sides start with // a write.) func netPipe() (net.Conn, net.Conn, error) { - listener, err := net.Listen("tcp", "127.0.0.1:0") + listener, err := net.Listen("tcp", ":0") if err != nil { return nil, nil, err } diff --git a/ssh/server.go b/ssh/server.go index 28b109a9c0..77c84d165c 100644 --- a/ssh/server.go +++ b/ssh/server.go @@ -10,6 +10,7 @@ import ( "fmt" "io" "net" + "strings" ) // The Permissions type holds fine-grained permissions that are @@ -231,7 +232,7 @@ func isAcceptableAlgo(algo string) bool { return false } -func checkSourceAddress(addr net.Addr, sourceAddr string) error { +func checkSourceAddress(addr net.Addr, sourceAddrs string) error { if addr == nil { return errors.New("ssh: no address known for client, but source-address match required") } @@ -241,18 +242,20 @@ func checkSourceAddress(addr net.Addr, sourceAddr string) error { return fmt.Errorf("ssh: remote address %v is not an TCP address when checking source-address match", addr) } - if allowedIP := net.ParseIP(sourceAddr); allowedIP != nil { - if allowedIP.Equal(tcpAddr.IP) { - return nil - } - } else { - _, ipNet, err := net.ParseCIDR(sourceAddr) - if err != nil { - return fmt.Errorf("ssh: error parsing source-address restriction %q: %v", sourceAddr, err) - } + for _, sourceAddr := range strings.Split(sourceAddrs, ",") { + if allowedIP := net.ParseIP(sourceAddr); allowedIP != nil { + if allowedIP.Equal(tcpAddr.IP) { + return nil + } + } else { + _, ipNet, err := net.ParseCIDR(sourceAddr) + if err != nil { + return fmt.Errorf("ssh: error parsing source-address restriction %q: %v", sourceAddr, err) + } - if ipNet.Contains(tcpAddr.IP) { - return nil + if ipNet.Contains(tcpAddr.IP) { + return nil + } } }