mirror of https://github.com/portainer/portainer
137 lines
3.8 KiB
Go
137 lines
3.8 KiB
Go
package networking
|
|
|
|
import (
|
|
"crypto/tls"
|
|
"fmt"
|
|
"net"
|
|
"net/http"
|
|
"net/url"
|
|
"strings"
|
|
"time"
|
|
|
|
"github.com/segmentio/encoding/json"
|
|
)
|
|
|
|
// ProbeDNSConnection probes a DNS connection and returns a JSON string with the DNS lookup status and IP addresses.
|
|
// ignores errors for the dns lookup since we want to know if the host is reachable
|
|
func ProbeDNSConnection(url string) string {
|
|
_, host, _ := parseURL(url)
|
|
result := map[string]interface{}{
|
|
"operation": "dns lookup",
|
|
"remote_address": host,
|
|
"connected_at": time.Now().Format(time.RFC3339),
|
|
"status": "dns lookup successful",
|
|
"resolved_ips": []net.IP{},
|
|
}
|
|
|
|
ipAddresses, err := net.LookupIP(host)
|
|
if err != nil {
|
|
result["status"] = fmt.Sprintf("dns lookup failed: %s", err)
|
|
} else {
|
|
result["resolved_ips"] = ipAddresses
|
|
}
|
|
|
|
jsonData, _ := json.Marshal(result)
|
|
return string(jsonData)
|
|
}
|
|
|
|
// ProbeTelnetConnection probes a telnet connection and returns a JSON string with the telnet connection status, local and remote addresses.
|
|
// ignores errors for the telnet connection since we want to know if the host is reachable
|
|
func ProbeTelnetConnection(url string) string {
|
|
network, host, port := parseURL(url)
|
|
if network == "https" || network == "http" {
|
|
network = "tcp"
|
|
}
|
|
|
|
address := fmt.Sprintf("%s:%s", host, port)
|
|
result := map[string]string{
|
|
"operation": "telnet connection",
|
|
"local_address": "unknown",
|
|
"remote_address": "unknown",
|
|
"network": network,
|
|
"status": "connected to " + address,
|
|
"connected_at": time.Now().Format(time.RFC3339),
|
|
}
|
|
|
|
connection, err := net.DialTimeout(network, address, 5*time.Second)
|
|
if err != nil {
|
|
result["status"] = fmt.Sprintf("failed to connect to %s: %s", address, err)
|
|
} else {
|
|
defer connection.Close()
|
|
result["local_address"] = connection.LocalAddr().String()
|
|
result["remote_address"] = connection.RemoteAddr().String()
|
|
}
|
|
|
|
jsonData, _ := json.Marshal(result)
|
|
return string(jsonData)
|
|
}
|
|
|
|
// DetectProxy probes a target URL and returns a JSON string with the proxy detection status, local and remote addresses.
|
|
// ignores errors for the http request since we want to know if the host is reachable
|
|
func DetectProxy(url string) string {
|
|
client := &http.Client{
|
|
Transport: &http.Transport{
|
|
TLSClientConfig: &tls.Config{
|
|
InsecureSkipVerify: true,
|
|
},
|
|
},
|
|
Timeout: 10 * time.Second,
|
|
}
|
|
|
|
result := map[string]string{
|
|
"operation": "proxy detection",
|
|
"local_address": "unknown",
|
|
"remote_address": "unknown",
|
|
"network": "https",
|
|
"status": "no proxy detected",
|
|
"connected_at": time.Now().Format(time.RFC3339),
|
|
}
|
|
|
|
resp, err := client.Get(url)
|
|
if err != nil {
|
|
result["status"] = fmt.Sprintf("failed to make request: %s", err)
|
|
} else {
|
|
defer resp.Body.Close()
|
|
|
|
if resp.Request != nil {
|
|
result["local_address"] = resp.Request.Host
|
|
result["remote_address"] = resp.Request.RemoteAddr
|
|
}
|
|
|
|
if resp.Header.Get("Via") != "" || resp.Header.Get("X-Forwarded-For") != "" || resp.Header.Get("Proxy-Connection") != "" {
|
|
result["status"] = "proxy detected via headers"
|
|
} else if resp.TLS != nil && len(resp.TLS.PeerCertificates) > 0 {
|
|
cert := resp.TLS.PeerCertificates[0]
|
|
if cert.IsCA || strings.Contains(strings.ToLower(cert.Issuer.CommonName), "proxy") {
|
|
result["status"] = "proxy detected via certificate"
|
|
}
|
|
}
|
|
}
|
|
|
|
jsonData, _ := json.Marshal(result)
|
|
return string(jsonData)
|
|
}
|
|
|
|
// parseURL parses a raw URL and returns the network, host and port
|
|
// it also ensures the network is tcp and the port is set to the default for the network
|
|
func parseURL(rawURL string) (network, host, port string) {
|
|
u, err := url.Parse(rawURL)
|
|
if err != nil {
|
|
return "", "", ""
|
|
}
|
|
|
|
network = u.Scheme
|
|
host = u.Hostname()
|
|
port = u.Port()
|
|
|
|
if port == "" {
|
|
if network == "https" {
|
|
port = "443"
|
|
} else if network == "http" {
|
|
port = "80"
|
|
}
|
|
}
|
|
|
|
return network, host, port
|
|
}
|