pkg/client: set ServerName before DialTLS handshake for android

Otherwise, the android app fails to connect with a server that uses
Let's Encrypt (because it relies on SNI, which requires the ServerName
to be set).

Change-Id: I9f25486bea68e83c68584a83817c98bfc84f62b9
This commit is contained in:
mpl 2017-05-31 17:30:36 +02:00
parent 32fbc99a66
commit 8b2e541731
2 changed files with 55 additions and 1 deletions

View File

@ -333,6 +333,12 @@ func (o optionSameOrigin) modifyClient(c *Client) {
c.sameOrigin = bool(o)
}
type optionParamsOnly bool
func (o optionParamsOnly) modifyClient(c *Client) {
c.paramsOnly = bool(o)
}
// noop is for use with syncutil.Onces.
func noop() error { return nil }
@ -1149,6 +1155,10 @@ func (c *Client) DialTLSFunc() func(network, addr string) (net.Conn, error) {
} else {
tlsConfig = &tls.Config{InsecureSkipVerify: true}
}
// Since we're doing the TLS handshake ourselves, we need to set the ServerName,
// in case the server uses SNI (as is the case if it's relying on Let's Encrypt,
// for example).
tlsConfig.ServerName = c.serverNameOfAddr(addr)
conn = tls.Client(ac, tlsConfig)
if err := conn.Handshake(); err != nil {
return nil, err
@ -1176,6 +1186,21 @@ func (c *Client) DialTLSFunc() func(network, addr string) (net.Conn, error) {
}
}
// serverNameOfAddr returns the host part of addr, or the empty string if addr
// is not a valid address (see net.Dial). Additionally, if host is an IP literal,
// serverNameOfAddr returns the empty string.
func (c *Client) serverNameOfAddr(addr string) string {
serverName, _, err := net.SplitHostPort(addr)
if err != nil {
c.printf("could not get server name from address %q: %v", addr, err)
return ""
}
if ip := net.ParseIP(serverName); ip != nil {
return ""
}
return serverName
}
func (c *Client) Signer() (*schema.Signer, error) {
c.signerOnce.Do(c.signerInit)
return c.signer, c.signerErr
@ -1299,8 +1324,11 @@ func (c *Client) Close() error {
// and auth but does not use any on-disk config files or environment variables
// for its configuration. It may still use the disk for caches.
func NewFromParams(server string, mode auth.AuthMode, opts ...ClientOption) *Client {
// paramsOnly = true needs to be passed as soon as an argument, because
// there are code paths in newClient (c.transportForConfig) that can lead
// to parsing the config file.
opts = append(opts[:len(opts):len(opts)], optionParamsOnly(true))
cl := newClient(server, mode, opts...)
cl.paramsOnly = true
return cl
}

View File

@ -61,3 +61,29 @@ func TestAliasFromConfig(t *testing.T) {
}
}
}
func TestServerOfName(t *testing.T) {
addrs := []struct {
input string
want string
}{
{
input: "foo.com:80",
want: "foo.com",
},
{
input: "192.168.0.9:80",
want: "",
},
{
input: "foo.com",
want: "",
},
}
c := NewFromParams("whatever", nil)
for _, v := range addrs {
if got := c.serverNameOfAddr(v.input); got != v.want {
t.Errorf("wanted %v, got %q", v.want, got)
}
}
}