mic.git


mic

~ proxy for JA4-TLS fingerprinting evasion
git clone https://github.com/djnnvx/mic.git
log | files | refs | archive | README | LICENSE

commit 9695b1e40189a62a01dcb87d0bdccc2da6915955
parent 90c475b670f7eb8d9a6a55758d5ff87932fe2c36
Author: djnn <[email protected]>
Date: Sun, 17 May 2026 18:47:19 +0900

chore(meta): use proper error-handling instead of panics

Diffstat:
Mcmd/client.go | 7++++---
Mcmd/server.go | 17++++++++++++-----
Mproxy/integration_test.go | 6+++++-
Mproxy/ja4_integration_test.go | 6+++++-
Mproxy/serverfront.go | 7++++---

5 files changed, 30 insertions(+), 13 deletions(-)

diff --git a/cmd/client.go b/cmd/client.go
@@ -2,6 +2,7 @@ package cmd
 
 import (
 	"crypto/x509"
+	"fmt"
 	"log"
 	"os"
 
@@ -28,7 +29,7 @@ func newClientCmd() *cobra.Command {
 			if caPath != "" {
 				caCert, err := os.ReadFile(caPath)
 				if err != nil {
-					log.Fatalf("[!] Failed to read CA certificate: %v", err)
+					return fmt.Errorf("reading CA certificate: %w", err)
 				}
 				pool := x509.NewCertPool()
 				pool.AppendCertsFromPEM(caCert)
@@ -38,7 +39,7 @@ func newClientCmd() *cobra.Command {
 			if fpName != "" {
 				fp, err := fingerprint.ByName(fpName)
 				if err != nil {
-					log.Fatalf("[!] Failed to load fingerprint: %v", err)
+					return fmt.Errorf("loading fingerprint: %w", err)
 				}
 				p.Fingerprint = fp
 				log.Printf("[+] Using TLS fingerprint: %s", fp.Name())
@@ -47,7 +48,7 @@ func newClientCmd() *cobra.Command {
 			if interceptCert != "" || interceptKey != "" {
 				ca, err := proxy.LoadOrGenerateCA(interceptCert, interceptKey)
 				if err != nil {
-					log.Fatalf("[!] Failed to load/generate intercept CA: %v", err)
+					return fmt.Errorf("loading/generating intercept CA: %w", err)
 				}
 				p.LocalCA = ca
 				log.Printf("[+] MitM CA ready — import %s, then: curl --cacert %s -x http://localhost%s https://<target>",
diff --git a/cmd/server.go b/cmd/server.go
@@ -2,6 +2,8 @@ package cmd
 
 import (
 	"crypto/x509"
+	"errors"
+	"fmt"
 	"log"
 	"os"
 
@@ -25,10 +27,10 @@ func newServerCmd() *cobra.Command {
 		Short: "TLS termination proxy with upstream fingerprinting",
 		RunE: func(cmd *cobra.Command, args []string) error {
 			if backend == "" {
-				log.Fatal("[!] --backend is required for server mode")
+				return errors.New("--backend is required for server mode")
 			}
 			if cert == "" || key == "" {
-				log.Fatal("[!] --cert and --key are required for server mode")
+				return errors.New("--cert and --key are required for server mode")
 			}
 
 			p := &proxy.Proxy{
@@ -39,7 +41,7 @@ func newServerCmd() *cobra.Command {
 			if caPath != "" {
 				caCert, err := os.ReadFile(caPath)
 				if err != nil {
-					log.Fatalf("[!] Failed to read CA certificate: %v", err)
+					return fmt.Errorf("reading CA certificate: %w", err)
 				}
 				pool := x509.NewCertPool()
 				pool.AppendCertsFromPEM(caCert)
@@ -49,14 +51,19 @@ func newServerCmd() *cobra.Command {
 			if fpName != "" {
 				fp, err := fingerprint.ByName(fpName)
 				if err != nil {
-					log.Fatalf("[!] Failed to load fingerprint: %v", err)
+					return fmt.Errorf("loading fingerprint: %w", err)
 				}
 				p.Fingerprint = fp
 				log.Printf("[+] Using TLS fingerprint: %s", fp.Name())
 			}
 
+			handler, err := proxy.ServerFrontHandler(cert, key)
+			if err != nil {
+				return err
+			}
+			p.Handler = handler
+
 			log.Printf("[+] Mode: server (TLS termination → backend %s)", backend)
-			p.Handler = proxy.ServerFrontHandler(cert, key)
 			return p.Run()
 		},
 	}
diff --git a/proxy/integration_test.go b/proxy/integration_test.go
@@ -157,7 +157,11 @@ func TestServerFront_Integration(t *testing.T) {
 		CAPool:      backendCAPool,
 		Fingerprint: fp,
 	}
-	proxyAddr := serveHandler(t, p, ServerFrontHandler(certFile, keyFile))
+	handler, err := ServerFrontHandler(certFile, keyFile)
+	if err != nil {
+		t.Fatalf("ServerFrontHandler: %v", err)
+	}
+	proxyAddr := serveHandler(t, p, handler)
 
 	tlsConn, err := tls.DialWithDialer(
 		&net.Dialer{Timeout: testTimeout},
diff --git a/proxy/ja4_integration_test.go b/proxy/ja4_integration_test.go
@@ -85,7 +85,11 @@ func TestServerFront_JA4(t *testing.T) {
 			}
 
 			p := &Proxy{BackendAddr: captureAddr, CAPool: capturePool, Fingerprint: fp}
-			proxyAddr := serveHandler(t, p, ServerFrontHandler(proxyCertFile, proxyKeyFile))
+			handler, err := ServerFrontHandler(proxyCertFile, proxyKeyFile)
+			if err != nil {
+				t.Fatalf("ServerFrontHandler: %v", err)
+			}
+			proxyAddr := serveHandler(t, p, handler)
 
 			tlsConn, err := tls.DialWithDialer(
 				&net.Dialer{Timeout: testTimeout},
diff --git a/proxy/serverfront.go b/proxy/serverfront.go
@@ -3,16 +3,17 @@ package proxy
 import (
 	"bufio"
 	"crypto/tls"
+	"fmt"
 	"log"
 	"net"
 )
 
 // ServerFrontHandler returns a Handler that terminates incoming TLS using certFile/keyFile,
 // then forwards to p.BackendAddr using the configured fingerprint.
-func ServerFrontHandler(certFile, keyFile string) Handler {
+func ServerFrontHandler(certFile, keyFile string) (Handler, error) {
 	cert, err := tls.LoadX509KeyPair(certFile, keyFile)
 	if err != nil {
-		log.Fatalf("ServerFrontHandler: loading certificate: %v", err)
+		return nil, fmt.Errorf("ServerFrontHandler: loading certificate: %w", err)
 	}
 
 	tlsCfg := &tls.Config{
@@ -38,5 +39,5 @@ func ServerFrontHandler(certFile, keyFile string) Handler {
 		defer targetConn.Close()
 
 		pipe(tlsConn, bufio.NewReader(tlsConn), targetConn)
-	}
+	}, nil
 }