func getTunnelClient(driverEndpoint string, tunnelEndpoint string, maxRetries int) (client.API, error) { log.Printf("Using Fleet Tunnel connection for requests") getSSHClient := func() (interface{}, error) { return ssh.NewSSHClient("core", driverEndpoint, nil, false, defaultTimeout) } result, err := retry(getSSHClient, maxRetries) if err != nil { return nil, err } sshClient := result.(*ssh.SSHForwardingClient) dial := func(string, string) (net.Conn, error) { cmd := fmt.Sprintf("fleetctl fd-forward %s", tunnelEndpoint) return ssh.DialCommand(sshClient, cmd) } // This is needed to fake out the client - it isn't used // since we're overloading the dial method on the transport // but the client complains if it isn't set fakeHTTPEndpoint, err := url.Parse("http://domain-sock") if err != nil { return nil, err } trans := pkg.LoggingHTTPTransport{ Transport: http.Transport{ Dial: dial, }, } httpClient := http.Client{ Transport: &trans, } return client.NewHTTPClient(&httpClient, *fakeHTTPEndpoint) }
// getAPI returns an API to Fleet. func getAPI(hostAddr string, maxRetries int) (client.API, error) { if hostAddr == "" { return nullAPI{}, nil } getSSHClient := func() (interface{}, error) { return ssh.NewSSHClient("core", hostAddr, nil, false, time.Second*10) } result, err := retry(getSSHClient, maxRetries) if err != nil { return nil, err } sshClient := result.(*ssh.SSHForwardingClient) dial := func(string, string) (net.Conn, error) { cmd := "fleetctl fd-forward /var/run/fleet.sock" return ssh.DialCommand(sshClient, cmd) } trans := pkg.LoggingHTTPTransport{ Transport: http.Transport{ Dial: dial, }, } httpClient := http.Client{ Transport: &trans, } // since dial() ignores the endpoint, we just need something here that // won't make the HTTP client complain. endpoint, err := url.Parse("http://domain-sock") return client.NewHTTPClient(&httpClient, *endpoint) }
func getHTTPClient() (client.API, error) { endpoints := strings.Split(globalFlags.Endpoint, ",") if len(endpoints) > 1 { log.Warningf("multiple endpoints provided but only the first (%s) is used", endpoints[0]) } ep, err := url.Parse(endpoints[0]) if err != nil { return nil, err } if len(ep.Scheme) == 0 { return nil, errors.New("URL scheme undefined") } tun := getTunnelFlag() tunneling := tun != "" dialUnix := ep.Scheme == "unix" || ep.Scheme == "file" tunnelFunc := net.Dial if tunneling { sshClient, err := ssh.NewSSHClient(globalFlags.SSHUserName, tun, getChecker(), true, getSSHTimeoutFlag()) if err != nil { return nil, fmt.Errorf("failed initializing SSH client: %v", err) } if dialUnix { tgt := ep.Path tunnelFunc = func(string, string) (net.Conn, error) { log.Debugf("Establishing remote fleetctl proxy to %s", tgt) cmd := fmt.Sprintf(`fleetctl fd-forward %s`, tgt) return ssh.DialCommand(sshClient, cmd) } } else { tunnelFunc = sshClient.Dial } } dialFunc := tunnelFunc if dialUnix { // This commonly happens if the user misses the leading slash after the scheme. // For example, "unix://var/run/fleet.sock" would be parsed as host "var". if len(ep.Host) > 0 { return nil, fmt.Errorf("unable to connect to host %q with scheme %q", ep.Host, ep.Scheme) } // The Path field is only used for dialing and should not be used when // building any further HTTP requests. sockPath := ep.Path ep.Path = "" // If not tunneling to the unix socket, http.Client will dial it directly. // http.Client does not natively support dialing a unix domain socket, so the // dial function must be overridden. if !tunneling { dialFunc = func(string, string) (net.Conn, error) { return net.Dial("unix", sockPath) } } // http.Client doesn't support the schemes "unix" or "file", but it // is safe to use "http" as dialFunc ignores it anyway. ep.Scheme = "http" // The Host field is not used for dialing, but will be exposed in debug logs. ep.Host = "domain-sock" } tlsConfig, err := pkg.ReadTLSConfigFiles(globalFlags.CAFile, globalFlags.CertFile, globalFlags.KeyFile) if err != nil { return nil, err } trans := pkg.LoggingHTTPTransport{ Transport: http.Transport{ Dial: dialFunc, TLSClientConfig: tlsConfig, }, } hc := http.Client{ Transport: &trans, } return client.NewHTTPClient(&hc, *ep) }