// getConn dials and creates a new persistConn to the target as // specified in the connectMethod. This includes doing a proxy CONNECT // and/or setting up TLS. If this doesn't return an error, the persistConn // is ready to write requests to. func (t *Transport) getConn(cm *connectMethod) (*persistConn, error) { if pc := t.getIdleConn(cm); pc != nil { return pc, nil } conn, err := t.dial("tcp", cm.addr()) if err != nil { if cm.proxyURL != nil { err = fmt.Errorf("http: error connecting to proxy %s: %v", cm.proxyURL, err) } return nil, err } pa := cm.proxyAuth() pconn := &persistConn{ t: t, cacheKey: cm.String(), conn: conn, reqch: make(chan requestAndChan, 50), } switch { case cm.proxyURL == nil: // Do nothing. case cm.targetScheme == "http": pconn.isProxy = true if pa != "" { pconn.mutateHeaderFunc = func(h Header) { h.Set("Proxy-Authorization", pa) } } case cm.targetScheme == "https": connectReq := &Request{ Method: "CONNECT", URL: &url.URL{Opaque: cm.targetAddr}, Host: cm.targetAddr, Headers: make(Header), } if pa != "" { connectReq.Headers.Set("Proxy-Authorization", pa) } connectReq.Write(conn) // Read response. // Okay to use and discard buffered reader here, because // TLS server will not speak until spoken to. br := bufio.NewReader(conn) resp, err := ReadResponse(br, connectReq) if err != nil { conn.Close() return nil, err } if resp.StatusCode != 200 { f := strings.SplitN(resp.Status, " ", 2) conn.Close() return nil, errors.New(f[1]) } } if cm.targetScheme == "https" { // Initiate TLS and check remote host name against certificate. conn = ztls.Client(conn, t.TLSClientConfig) if err = conn.(*ztls.Conn).Handshake(); err != nil { return nil, err } if t.TLSClientConfig == nil || !t.TLSClientConfig.InsecureSkipVerify { if err = conn.(*ztls.Conn).VerifyHostname(cm.tlsHost()); err != nil { return nil, err } } pconn.conn = conn } pconn.br = bufio.NewReader(pconn.conn) pconn.bw = bufio.NewWriter(pconn.conn) go pconn.readLoop() return pconn, nil }
// Extra method - Do a TLS Handshake and record progress func (c *Conn) TLSHandshake() error { if c.isTls { return fmt.Errorf( "Attempted repeat handshake with remote host %s", c.RemoteAddr().String()) } tlsConfig := new(ztls.Config) tlsConfig.InsecureSkipVerify = true tlsConfig.MinVersion = ztls.VersionSSL30 tlsConfig.MaxVersion = c.maxTlsVersion tlsConfig.RootCAs = c.caPool tlsConfig.HeartbeatEnabled = true tlsConfig.ClientDSAEnabled = true if !c.noSNI && c.domain != "" { tlsConfig.ServerName = c.domain } if c.onlyDHE { tlsConfig.CipherSuites = ztls.DHECiphers } if c.onlyExports { tlsConfig.CipherSuites = ztls.RSA512ExportCiphers } if c.onlyExportsDH { tlsConfig.CipherSuites = ztls.DHEExportCiphers } if c.chromeCiphers { tlsConfig.CipherSuites = ztls.ChromeCiphers } if c.chromeNoDHE { tlsConfig.CipherSuites = ztls.ChromeNoDHECiphers } if c.firefoxCiphers { tlsConfig.CipherSuites = ztls.FirefoxCiphers } if c.firefoxNoDHECiphers { tlsConfig.CipherSuites = ztls.FirefoxNoDHECiphers } if c.safariCiphers { tlsConfig.CipherSuites = ztls.SafariCiphers tlsConfig.ForceSuites = true } if c.safariNoDHECiphers { tlsConfig.CipherSuites = ztls.SafariNoDHECiphers tlsConfig.ForceSuites = true } if c.extendedRandom { tlsConfig.ExtendedRandom = true } if c.gatherSessionTicket { tlsConfig.ForceSessionTicketExt = true } if c.offerExtendedMasterSecret { tlsConfig.ExtendedMasterSecret = true } c.tlsConn = ztls.Client(c.conn, tlsConfig) c.tlsConn.SetReadDeadline(c.readDeadline) c.tlsConn.SetWriteDeadline(c.writeDeadline) c.isTls = true err := c.tlsConn.Handshake() if tlsConfig.ForceSuites && err == ztls.ErrUnimplementedCipher { err = nil } hl := c.tlsConn.GetHandshakeLog() if !c.tlsVerbose { hl.KeyMaterial = nil hl.ClientHello = nil hl.ClientFinished = nil hl.ClientKeyExchange = nil } c.grabData.TLSHandshake = hl return err }