diff --git a/README.md b/README.md index ad7da88..1f6b7fa 100644 --- a/README.md +++ b/README.md @@ -85,7 +85,7 @@ Add your new proxy hostname into a free Cloudflare account. Setup your origin rules to send that host to the origin server (darkflare-server) via the proxy port you choose. -I used 8080. +I used 8080 with a Cloudflare proxy via HTTP for the firs test. Less overhead. ## āœØ Features @@ -95,9 +95,6 @@ I used 8080. - **Session Management**: Keeps your connections organized like a Type A personality - **TLS Security**: Because we're sneaky, not reckless -## ā˜ ļø Pending Features -- **Include Spoofed Headers for Files**: Add real headers to the jpegs and php files to appear to be exactly and they are to be. Add more support for PDF, MOV, and MP4 files to make the traffic looks more realistic. - ## šŸš€ Quick Start ### Installation @@ -116,18 +113,35 @@ chmod +x darkflare-client darkflare-server Add `-debug` flag for debug mode ### Notes -Make the host.domain.net you use is configured in Cloudflare to point to the darkflare-server. If you want to debug and go directly to the psudo server you can use the `-o` flag. +Make the host.domain.net you use is configured in Cloudflare to point to the darkflare-server. If you want to debug and go directly to the psudo server you can use the `-allow-direct` flag on the server. ### Running the Server + ```bash -./darkflare-server -d localhost:22 -p 8080 -debug +# HTTPS Server (recommended for production) +./darkflare-server -o https://0.0.0.0:443 -d localhost:22 -c /path/to/cert.pem -k /path/to/key.pem + +# HTTP Server (for testing) +./darkflare-server -o http://0.0.0.0:8080 -d localhost:22 ``` -Add `-debug` for server debug messages ### Notes -- You must specify either `-d` (destination) or `-a` (application) mode, but not both -- The `-o` flag (open) allows direct connections without Cloudflare headers (not recommended for production). Good for debugging so you can go from the client directly to the server. +- You must specify either `-d` (network destination) or `-a` (application) mode, but not both +- The `-allow-direct` flag allows direct connections without Cloudflare headers (not recommended for production) - Debug mode (`-debug`) provides verbose logging of connections and data transfers +- Under SSL/TLS configuration in Cloudflare you need to set ssl encryption mode to Full. + +### SSL/TLS Certificates + +For HTTPS mode, you'll need to obtain origin certificates from Cloudflare: + +1. Log into your Cloudflare dashboard +2. Go to SSL/TLS > Origin Server +3. Create a new certificate (or use an existing one) +4. Download both the certificate and private key +5. When starting the server in HTTPS mode, provide both certificate files: + +Note: Keep your private key secure and never share it. The certificate provided by Cloudflare is specifically for securing the connection between Cloudflare and your origin server. ### Testing the Connection ```bash diff --git a/bin/checksums.txt b/bin/checksums.txt index d1fb51b..5e06b9e 100644 --- a/bin/checksums.txt +++ b/bin/checksums.txt @@ -1,12 +1,12 @@ # DarkFlare Binary Checksums -# Generated: Wed Nov 27 17:17:28 UTC 2024 +# Generated: Wed Nov 27 18:28:12 UTC 2024 -c71a5cf86a1280d00dd460046718ccfeee7a8aabbac3241b344bb87705bc7933 checksums.txt -55acba659aa2e0fe1b6d1926c32988d7e33e53ad87582a0e547922fdcccfcedd darkflare-client-darwin-amd64 -de1ef97574fe9a6310dd76df938ae0436d1b321f16218b6a142a4915f6ffc144 darkflare-client-darwin-arm64 -bf887e178d20dc7f97e0984032afefefad41568a4a0c7a68f2fd67a5df1e314e darkflare-client-linux-amd64 -5ba3cf40b182968195e7df419ffe3a5d02567256b529badd6bd9dd32f2ed49ea darkflare-client-windows-amd64.exe -635e6593ac287be49cded64674a24a262fc1ae77047ec7beb0e2732a58d8fb52 darkflare-server-darwin-amd64 -af68cf706364049dad8848d6f0bd1a24daae5d5e60db343057482622533df28b darkflare-server-darwin-arm64 -57a529665b1a3ca0c7ef633afff3ec6a04020918f05e77203c91cb97ae6313ad darkflare-server-linux-amd64 -62477e5d843ee7c33e2a99f42dcc7c7f34fb369fdced4d90570623accdb8f381 darkflare-server-windows-amd64.exe +bef55901802edf53cfbf3bdd2db0e50202c67ee14c77f46fa2242c154617d3bc checksums.txt +58c1df4743072ec1691378b65eac7e66beaaec60572f724e62eaf5be104dfea3 darkflare-client-darwin-amd64 +17cf1c0b0c7e4bfba8602499e760b25ed37833f88c2e8afa68122408be3a881b darkflare-client-darwin-arm64 +1a4a0539b645e6a9fef5eb3a633c4fabe9952bf1655ee402ca8f870f6c8655c3 darkflare-client-linux-amd64 +260fcf233f40628347f8c6c7197d6549e2fc2b9079866e9cc25cb9d676b42eb6 darkflare-client-windows-amd64.exe +df474dd2277f2fe4668c9c3d569a8cf8c2b6761f04a5c7a4212ac50dfb195c16 darkflare-server-darwin-amd64 +b9b9e4475ba6055a33a9ce1c6ed605725afbd1a997b1508b1b0cbfb78fff3b13 darkflare-server-darwin-arm64 +ada672ccb9ad4cb78499d640d233fcc3d052d7eb1a05c149a0485f74dd0ed1eb darkflare-server-linux-amd64 +feedeb09aa65c81c1024122a25dd408bbe7e7ad4f1bfe42476af7a64665b4202 darkflare-server-windows-amd64.exe diff --git a/bin/darkflare-client-darwin-amd64 b/bin/darkflare-client-darwin-amd64 index c317f10..38ff832 100755 Binary files a/bin/darkflare-client-darwin-amd64 and b/bin/darkflare-client-darwin-amd64 differ diff --git a/bin/darkflare-client-darwin-arm64 b/bin/darkflare-client-darwin-arm64 index 07ffef9..ef890b3 100755 Binary files a/bin/darkflare-client-darwin-arm64 and b/bin/darkflare-client-darwin-arm64 differ diff --git a/bin/darkflare-client-linux-amd64 b/bin/darkflare-client-linux-amd64 index 7d96b4e..04843be 100755 Binary files a/bin/darkflare-client-linux-amd64 and b/bin/darkflare-client-linux-amd64 differ diff --git a/bin/darkflare-client-windows-amd64.exe b/bin/darkflare-client-windows-amd64.exe index 6c9375b..226eb15 100755 Binary files a/bin/darkflare-client-windows-amd64.exe and b/bin/darkflare-client-windows-amd64.exe differ diff --git a/bin/darkflare-server-darwin-amd64 b/bin/darkflare-server-darwin-amd64 index a6d871b..21e73b6 100755 Binary files a/bin/darkflare-server-darwin-amd64 and b/bin/darkflare-server-darwin-amd64 differ diff --git a/bin/darkflare-server-darwin-arm64 b/bin/darkflare-server-darwin-arm64 index d779278..de14a60 100755 Binary files a/bin/darkflare-server-darwin-arm64 and b/bin/darkflare-server-darwin-arm64 differ diff --git a/bin/darkflare-server-linux-amd64 b/bin/darkflare-server-linux-amd64 index d223dd2..b61857c 100755 Binary files a/bin/darkflare-server-linux-amd64 and b/bin/darkflare-server-linux-amd64 differ diff --git a/bin/darkflare-server-windows-amd64.exe b/bin/darkflare-server-windows-amd64.exe index cdad026..c90748a 100755 Binary files a/bin/darkflare-server-windows-amd64.exe and b/bin/darkflare-server-windows-amd64.exe differ diff --git a/cert/cert.go b/cert/cert.go new file mode 100644 index 0000000..434df58 --- /dev/null +++ b/cert/cert.go @@ -0,0 +1,62 @@ +package cert + +import ( + "crypto/ecdsa" + "crypto/elliptic" + "crypto/rand" + "crypto/x509" + "crypto/x509/pkix" + "encoding/pem" + "math/big" + "net" + "time" +) + +func GenerateSelfSignedCert() (certPEM []byte, keyPEM []byte, err error) { + // Generate private key + privateKey, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader) + if err != nil { + return nil, nil, err + } + + // Create certificate template + template := x509.Certificate{ + SerialNumber: big.NewInt(1), + Subject: pkix.Name{ + Organization: []string{"DarkFlare Server"}, + }, + NotBefore: time.Now(), + NotAfter: time.Now().Add(365 * 24 * time.Hour), + + KeyUsage: x509.KeyUsageKeyEncipherment | x509.KeyUsageDigitalSignature, + ExtKeyUsage: []x509.ExtKeyUsage{x509.ExtKeyUsageServerAuth}, + BasicConstraintsValid: true, + DNSNames: []string{"localhost"}, + IPAddresses: []net.IP{net.ParseIP("127.0.0.1")}, + } + + // Create certificate + derBytes, err := x509.CreateCertificate(rand.Reader, &template, &template, &privateKey.PublicKey, privateKey) + if err != nil { + return nil, nil, err + } + + // Encode certificate + certPEM = pem.EncodeToMemory(&pem.Block{ + Type: "CERTIFICATE", + Bytes: derBytes, + }) + + // Encode private key + privBytes, err := x509.MarshalPKCS8PrivateKey(privateKey) + if err != nil { + return nil, nil, err + } + + keyPEM = pem.EncodeToMemory(&pem.Block{ + Type: "PRIVATE KEY", + Bytes: privBytes, + }) + + return certPEM, keyPEM, nil +} diff --git a/client/main.go b/client/main.go index 8a38f7d..3f4e129 100644 --- a/client/main.go +++ b/client/main.go @@ -310,37 +310,7 @@ func (c *Client) handleConnection(conn net.Conn) { if resp.StatusCode != http.StatusOK { body, _ := io.ReadAll(io.LimitReader(resp.Body, c.maxBodySize)) - errorMsg := fmt.Sprintf("CDN returned status %d (%s)", resp.StatusCode, resp.Status) - - // Try to extract more detailed error information - if len(body) > 0 { - // Check if it's HTML (common for CDN error pages) - if bytes.Contains(body, []byte("")) || bytes.Contains(body, []byte("")) { - errorMsg += " - CDN returned an HTML error page" - } else { - // Add the response body if it's not too long - if len(body) > 200 { - errorMsg += fmt.Sprintf("\nResponse: %s...", string(body[:200])) - } else { - errorMsg += fmt.Sprintf("\nResponse: %s", string(body)) - } - } - } - - // Add common CDN error code explanations - switch resp.StatusCode { - case http.StatusBadGateway: - errorMsg += "\nPossible cause: Origin server (darkflare-server) is unreachable" - case http.StatusForbidden: - errorMsg += "\nPossible cause: Request blocked by CDN security rules" - case http.StatusServiceUnavailable: - errorMsg += "\nPossible cause: CDN temporary error or rate limiting" - case http.StatusGatewayTimeout: - errorMsg += "\nPossible cause: Origin server (darkflare-server) timed out" - } - - c.debugLog("CDN Error: %s", errorMsg) - resp.Body.Close() + c.handleResponse(resp, body) time.Sleep(time.Second) continue } @@ -354,9 +324,24 @@ func (c *Client) handleConnection(conn net.Conn) { } if len(data) > 0 { - if bytes.HasPrefix(data, []byte("<")) { - c.debugLog("Received HTML response instead of hex data") - time.Sleep(time.Second) + // Check for Cloudflare directory listing or error pages + if bytes.Contains(data, []byte("")) || bytes.Contains(data, []byte("")) { + // Check for common indicators + switch { + case bytes.Contains(data, []byte("Index of /")): + c.debugLog("Error: Origin server returned a directory listing - Server may be misconfigured") + case bytes.Contains(data, []byte("Error 521")): + c.debugLog("Error: Origin server is down or not responding (Cloudflare Error 521)") + case bytes.Contains(data, []byte("Error 522")): + c.debugLog("Error: Connection timed out to origin server (Cloudflare Error 522)") + case bytes.Contains(data, []byte("Error 523")): + c.debugLog("Error: Origin server is unreachable (Cloudflare Error 523)") + case bytes.Contains(data, []byte("Error 524")): + c.debugLog("Error: Connection timed out waiting for origin server (Cloudflare Error 524)") + default: + c.debugLog("Error: Received HTML response instead of tunnel data - Origin server may be down or misconfigured") + } + time.Sleep(time.Second * 5) // Increased backoff for server errors continue } @@ -387,6 +372,56 @@ func (c *Client) handleConnection(conn net.Conn) { } } +func (c *Client) handleResponse(resp *http.Response, body []byte) { + if resp.StatusCode != http.StatusOK { + // Format error message + errorMsg := fmt.Sprintf("\nā•­ā”€ CDN Error ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€\n") + errorMsg += fmt.Sprintf("ā”‚ Status: %d (%s)\n", resp.StatusCode, resp.Status) + + // Add common CDN error explanations + switch resp.StatusCode { + case http.StatusBadGateway: + errorMsg += "ā”‚ Cause: Origin server (darkflare-server) is unreachable\n" + case http.StatusForbidden: + errorMsg += "ā”‚ Cause: Request blocked by CDN security rules\n" + case http.StatusServiceUnavailable: + errorMsg += "ā”‚ Cause: CDN temporary error or rate limiting\n" + case http.StatusGatewayTimeout: + errorMsg += "ā”‚ Cause: Origin server (darkflare-server) timed out\n" + case http.StatusNotFound: + errorMsg += "ā”‚ Cause: Origin server not responding or incorrect path\n" + } + + // If we got HTML content, parse it for specific errors + if bytes.Contains(body, []byte("")) || bytes.Contains(body, []byte("")) { + switch { + case bytes.Contains(body, []byte("Index of /")): + errorMsg += "ā”‚ Detail: Origin server returned directory listing\n" + errorMsg += "ā”‚ Server is misconfigured or not running darkflare\n" + case bytes.Contains(body, []byte("Error 521")): + errorMsg += "ā”‚ Detail: Origin server is down (Cloudflare Error 521)\n" + case bytes.Contains(body, []byte("Error 522")): + errorMsg += "ā”‚ Detail: Connection timed out (Cloudflare Error 522)\n" + case bytes.Contains(body, []byte("Error 523")): + errorMsg += "ā”‚ Detail: Origin unreachable (Cloudflare Error 523)\n" + case bytes.Contains(body, []byte("Error 524")): + errorMsg += "ā”‚ Detail: Origin timeout (Cloudflare Error 524)\n" + default: + errorMsg += "ā”‚ Detail: Received HTML instead of tunnel data\n" + errorMsg += "ā”‚ Server may be down or misconfigured\n" + } + } else if len(body) > 0 { + // If we got binary data, just indicate it + errorMsg += "ā”‚ Detail: Received unexpected binary response\n" + } + + errorMsg += "ā•°ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€\n" + c.debugLog(errorMsg) + return + } + // ... handle successful response ... +} + func main() { var localPort int var targetURL string diff --git a/server/main.go b/server/main.go index 0e7ef1a..80a48d9 100644 --- a/server/main.go +++ b/server/main.go @@ -23,6 +23,7 @@ package main import ( "bufio" + "crypto/tls" "encoding/hex" "flag" "fmt" @@ -30,6 +31,7 @@ import ( "log" "net" "net/http" + "net/url" "os" "os/exec" "strings" @@ -197,7 +199,17 @@ func (s *Server) handleRequest(w http.ResponseWriter, r *http.Request) { w.Header().Set("Expires", "0") w.Header().Set("Content-Type", "application/octet-stream") + // Try to get session ID from various possible headers sessionID := r.Header.Get("X-Ephemeral") + if sessionID == "" { + // Try Cloudflare-specific headers + sessionID = r.Header.Get("Cf-Ray") + if sessionID == "" { + // Could also try other headers or generate a session ID based on IP + sessionID = r.Header.Get("Cf-Connecting-Ip") + } + } + if sessionID == "" { if s.debug { log.Printf("Error: Missing session ID from %s", r.Header.Get("Cf-Connecting-Ip")) @@ -309,11 +321,13 @@ func (s *Server) handleRequest(w http.ResponseWriter, r *http.Request) { } func main() { - var port int + var origin string var dest string + var certFile string + var keyFile string var debug bool - var appCommand string var allowDirect bool + var appCommand string flag.Usage = func() { fmt.Fprintf(os.Stderr, "DarkFlare Server - TCP-over-CDN tunnel server component\n") @@ -321,70 +335,172 @@ func main() { fmt.Fprintf(os.Stderr, "Usage:\n") fmt.Fprintf(os.Stderr, " %s [options]\n\n", os.Args[0]) fmt.Fprintf(os.Stderr, "Options:\n") - fmt.Fprintf(os.Stderr, " -p Port to listen on (default: 8080)\n") + fmt.Fprintf(os.Stderr, " -o Origin address in format: http(s)://ip:port\n") + fmt.Fprintf(os.Stderr, " Example: https://0.0.0.0:443\n") + fmt.Fprintf(os.Stderr, " -c Path to certificate file (required for HTTPS)\n") + fmt.Fprintf(os.Stderr, " -k Path to private key file (required for HTTPS)\n") fmt.Fprintf(os.Stderr, " -d Destination address in host:port format\n") fmt.Fprintf(os.Stderr, " Example: localhost:22 for SSH forwarding\n\n") fmt.Fprintf(os.Stderr, " -a Application mode: launches a command instead of forwarding\n") fmt.Fprintf(os.Stderr, " Example: 'sshd -i' or 'pppd noauth'\n") fmt.Fprintf(os.Stderr, " Note: Cannot be used with -d flag\n\n") fmt.Fprintf(os.Stderr, " -debug Enable debug logging\n") - fmt.Fprintf(os.Stderr, " -o Allow direct connections without Cloudflare headers\n") + fmt.Fprintf(os.Stderr, " -allow-direct Allow direct connections without Cloudflare headers\n") fmt.Fprintf(os.Stderr, " Warning: Not recommended for production use\n\n") fmt.Fprintf(os.Stderr, "Examples:\n") - fmt.Fprintf(os.Stderr, " SSH forwarding:\n") - fmt.Fprintf(os.Stderr, " %s -d localhost:22 -p 8080\n\n", os.Args[0]) - fmt.Fprintf(os.Stderr, " Run SSH daemon directly:\n") - fmt.Fprintf(os.Stderr, " %s -a \"sshd -i\" -p 8080\n\n", os.Args[0]) - fmt.Fprintf(os.Stderr, " Debug mode with direct access:\n") - fmt.Fprintf(os.Stderr, " %s -d localhost:22 -p 8080 -debug -o\n\n", os.Args[0]) + fmt.Fprintf(os.Stderr, " HTTPS Server:\n") + fmt.Fprintf(os.Stderr, " %s -o https://0.0.0.0:443 -d localhost:22 -c /path/to/cert.pem -k /path/to/key.pem\n\n", os.Args[0]) + fmt.Fprintf(os.Stderr, " HTTP Server:\n") + fmt.Fprintf(os.Stderr, " %s -o http://0.0.0.0:80 -d localhost:22\n\n", os.Args[0]) fmt.Fprintf(os.Stderr, "For more information: https://github.com/blyon/darkflare\n") } - flag.IntVar(&port, "p", 8080, "") + flag.StringVar(&origin, "o", "http://0.0.0.0:8080", "") flag.StringVar(&dest, "d", "", "") + flag.StringVar(&certFile, "c", "", "") + flag.StringVar(&keyFile, "k", "", "") flag.StringVar(&appCommand, "a", "", "") flag.BoolVar(&debug, "debug", false, "") - flag.BoolVar(&allowDirect, "o", false, "") + flag.BoolVar(&allowDirect, "allow-direct", false, "") flag.Parse() - if len(os.Args) == 1 { - flag.Usage() - os.Exit(1) + // Parse origin URL + originURL, err := url.Parse(origin) + if err != nil { + log.Fatalf("Invalid origin URL: %v", err) } - if dest != "" && appCommand != "" { - fmt.Fprintf(os.Stderr, "Error: Cannot specify both -d and -a options\n\n") - flag.Usage() - os.Exit(1) + // Validate scheme + if originURL.Scheme != "http" && originURL.Scheme != "https" { + log.Fatal("Origin scheme must be either 'http' or 'https'") } - if dest == "" && appCommand == "" { - fmt.Fprintf(os.Stderr, "Error: Must specify either destination (-d) or application (-a)\n\n") - flag.Usage() - os.Exit(1) + // Validate and extract host/port + originHost, originPort, err := net.SplitHostPort(originURL.Host) + if err != nil { + log.Fatalf("Invalid origin address: %v", err) } + // Parse destination var destHost, destPort string if dest != "" { - var err error destHost, destPort, err = net.SplitHostPort(dest) if err != nil { log.Fatalf("Invalid destination address: %v", err) } } + // Validate IP is local + if !isLocalIP(originHost) { + log.Fatal("Origin host must be a local IP address") + } + server := NewServer(destHost, destPort, appCommand, debug, allowDirect) - log.Printf("DarkFlare server running on port %d", port) + log.Printf("DarkFlare server running on %s://%s:%s", originURL.Scheme, originHost, originPort) if allowDirect { log.Printf("Warning: Direct connections allowed (no Cloudflare required)") } - if appCommand != "" { - log.Printf("Running in application mode with command: %s", appCommand) + + // Start server with appropriate protocol + if originURL.Scheme == "https" { + if certFile == "" || keyFile == "" { + log.Fatal("HTTPS requires both certificate (-c) and key (-k) files") + } + + // Load and verify certificates + cert, err := tls.LoadX509KeyPair(certFile, keyFile) + if err != nil { + log.Fatalf("Failed to load certificate and key: %v", err) + } + + if debug { + log.Printf("Successfully loaded certificate from %s and key from %s", certFile, keyFile) + } + + server := &http.Server{ + Addr: fmt.Sprintf("%s:%s", originHost, originPort), + Handler: http.HandlerFunc(server.handleRequest), + TLSConfig: &tls.Config{ + Certificates: []tls.Certificate{cert}, + MinVersion: tls.VersionTLS12, + MaxVersion: tls.VersionTLS13, + // Allow any cipher suites + CipherSuites: nil, + // Don't verify client certs + ClientAuth: tls.NoClientCert, + // Handle SNI + GetCertificate: func(info *tls.ClientHelloInfo) (*tls.Certificate, error) { + if debug { + log.Printf("Client requesting certificate for server name: %s", info.ServerName) + } + return &cert, nil + }, + GetConfigForClient: func(hello *tls.ClientHelloInfo) (*tls.Config, error) { + if debug { + log.Printf("TLS Handshake Details:") + log.Printf(" Client Address: %s", hello.Conn.RemoteAddr()) + log.Printf(" Server Name: %s", hello.ServerName) + log.Printf(" Supported Versions: %v", hello.SupportedVersions) + log.Printf(" Supported Ciphers: %v", hello.CipherSuites) + log.Printf(" Supported Curves: %v", hello.SupportedCurves) + log.Printf(" Supported Points: %v", hello.SupportedPoints) + log.Printf(" ALPN Protocols: %v", hello.SupportedProtos) + } + return nil, nil + }, + VerifyConnection: func(cs tls.ConnectionState) error { + if debug { + log.Printf("TLS Connection State:") + log.Printf(" Version: 0x%x", cs.Version) + log.Printf(" HandshakeComplete: %v", cs.HandshakeComplete) + log.Printf(" CipherSuite: 0x%x", cs.CipherSuite) + log.Printf(" NegotiatedProtocol: %s", cs.NegotiatedProtocol) + log.Printf(" ServerName: %s", cs.ServerName) + } + return nil + }, + // Enable HTTP/2 support + NextProtos: []string{"h2", "http/1.1"}, + }, + ErrorLog: log.New(os.Stderr, "[HTTPS] ", log.LstdFlags), + ConnState: func(conn net.Conn, state http.ConnState) { + if debug { + log.Printf("Connection state changed to %s from %s", + state, conn.RemoteAddr().String()) + } + }, + } + + log.Printf("Starting HTTPS server on %s:%s", originHost, originPort) + if debug { + log.Printf("TLS Configuration:") + log.Printf(" Minimum Version: %x", server.TLSConfig.MinVersion) + log.Printf(" Maximum Version: %x", server.TLSConfig.MaxVersion) + log.Printf(" Certificates Loaded: %d", len(server.TLSConfig.Certificates)) + log.Printf(" Listening Address: %s", server.Addr) + log.Printf(" Supported Protocols: %v", server.TLSConfig.NextProtos) + } + + log.Fatal(server.ListenAndServeTLS(certFile, keyFile)) } else { - log.Printf("Running in proxy mode, forwarding to %s:%s", destHost, destPort) + server := &http.Server{ + Addr: fmt.Sprintf("%s:%s", originHost, originPort), + Handler: http.HandlerFunc(server.handleRequest), + } + log.Fatal(server.ListenAndServe()) + } +} + +func isLocalIP(ip string) bool { + if ip == "0.0.0.0" || ip == "127.0.0.1" || ip == "::1" { + return true + } + + ipAddr := net.ParseIP(ip) + if ipAddr == nil { + return false } - http.HandleFunc("/", server.handleRequest) - log.Fatal(http.ListenAndServe(fmt.Sprintf(":%d", port), nil)) + return ipAddr.IsLoopback() || ipAddr.IsPrivate() }