diff --git a/ca/ca.go b/ca/ca.go
diff --git a/cert/print.go b/cert/print.go
diff --git a/cmd/root.go b/cmd/root.go
@@ -55,8 +55,8 @@ func getParser(opts *MicCliOptions) *cobra.Command {
defaults := GetDefaultOptions()
rootCmd.Flags().StringVarP(&opts.Addr, "addr", "a", defaults.Addr, "address to listen to")
- rootCmd.Flags().StringVarP(&opts.CaPath, "ca-cert-path", "c", defaults.CaPath, "custom CA certificate path (optional)")
rootCmd.Flags().IntVarP(&opts.Port, "port", "p", defaults.Port, "port to listen to")
+ rootCmd.Flags().IntVarP(&opts.ForwardTo, "forward-to", "t", defaults.ForwardTo, "local port to forward to")
rootCmd.Flags().BoolVarP(&opts.Verbose, "verbose", "v", defaults.Verbose, "enable verbose mode")
return rootCmd
diff --git a/cmd/types.go b/cmd/types.go
@@ -8,8 +8,8 @@ type MicCliOptions struct {
/// Addr: address to listen to
Addr string
- /// CaPath: custom CA certificate path (optional)
- CaPath string
+ /// ForwardTo: local port to forward call to
+ ForwardTo int
/// Verbose: enable verbose mode
Verbose bool
@@ -17,10 +17,10 @@ type MicCliOptions struct {
func GetDefaultOptions() MicCliOptions {
opts := MicCliOptions{
- Port: 8080,
- Addr: "127.0.0.1",
- CaPath: "",
- Verbose: false,
+ Port: 8080,
+ Addr: "127.0.0.1",
+ ForwardTo: 1337,
+ Verbose: false,
}
return opts
diff --git a/go.mod b/go.mod
@@ -2,14 +2,15 @@ module github.com/djnnvx/mic
go 1.24.4
-require github.com/spf13/cobra v1.9.1
+require (
+ github.com/refraction-networking/utls v1.8.0
+ github.com/spf13/cobra v1.9.1
+)
require (
github.com/andybalholm/brotli v1.0.6 // indirect
- github.com/cloudflare/circl v1.5.0 // indirect
github.com/inconshreveable/mousetrap v1.1.0 // indirect
github.com/klauspost/compress v1.17.4 // indirect
- github.com/refraction-networking/utls v1.7.3 // indirect
github.com/spf13/pflag v1.0.6 // indirect
golang.org/x/crypto v0.36.0 // indirect
golang.org/x/sys v0.31.0 // indirect
diff --git a/go.sum b/go.sum
@@ -1,14 +1,12 @@
github.com/andybalholm/brotli v1.0.6 h1:Yf9fFpf49Zrxb9NlQaluyE92/+X7UVHlhMNJN2sxfOI=
github.com/andybalholm/brotli v1.0.6/go.mod h1:fO7iG3H7G2nSZ7m0zPUDn85XEX2GTukHGRSepvi9Eig=
-github.com/cloudflare/circl v1.5.0 h1:hxIWksrX6XN5a1L2TI/h53AGPhNHoUBo+TD1ms9+pys=
-github.com/cloudflare/circl v1.5.0/go.mod h1:uddAzsPgqdMAYatqJ0lsjX1oECcQLIlRpzZh3pJrofs=
github.com/cpuguy83/go-md2man/v2 v2.0.6/go.mod h1:oOW0eioCTA6cOiMLiUPZOpcVxMig6NIQQ7OS05n1F4g=
github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8=
github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw=
github.com/klauspost/compress v1.17.4 h1:Ej5ixsIri7BrIjBkRZLTo6ghwrEtHFk7ijlczPW4fZ4=
github.com/klauspost/compress v1.17.4/go.mod h1:/dCuZOvVtNoHsyb+cuJD3itjs3NbnF6KH9zAO4BDxPM=
-github.com/refraction-networking/utls v1.7.3 h1:L0WRhHY7Oq1T0zkdzVZMR6zWZv+sXbHB9zcuvsAEqCo=
-github.com/refraction-networking/utls v1.7.3/go.mod h1:TUhh27RHMGtQvjQq+RyO11P6ZNQNBb3N0v7wsEjKAIQ=
+github.com/refraction-networking/utls v1.8.0 h1:L38krhiTAyj9EeiQQa2sg+hYb4qwLCqdMcpZrRfbONE=
+github.com/refraction-networking/utls v1.8.0/go.mod h1:jkSOEkLqn+S/jtpEHPOsVv/4V4EVnelwbMQl4vCWXAM=
github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
github.com/spf13/cobra v1.9.1 h1:CXSaggrXdbHK9CF+8ywj8Amf7PBRmPCOJugH954Nnlo=
github.com/spf13/cobra v1.9.1/go.mod h1:nDyEzZ8ogv936Cinf6g1RU9MRY64Ir93oCnqb9wxYW0=
diff --git a/proxy/backend.go b/proxy/backend.go
@@ -1,27 +0,0 @@
-package proxy
-
-import (
- "bufio"
- "log"
- "net"
-)
-
-func backendHandler(conn net.Conn, p *Proxy) {
- defer conn.Close()
- reader := bufio.NewReader(conn)
-
- /* peek to determine protocol */
- peek, err := reader.Peek(1)
- if err != nil {
- log.Printf("[-] peek failed: %s\n", err.Error())
- return
- }
-
- if isSocks5(peek) {
-
- }
-}
-
-func init() {
- RegisterHandler(backendHandler)
-}
diff --git a/proxy/httpconnect.go b/proxy/httpconnect.go
@@ -1,22 +0,0 @@
-package proxy
-
-import (
- "bufio"
- "net"
- "strings"
-)
-
-func httpConnectHandler(conn net.Conn, p *Proxy) {
- reader := bufio.NewReader(conn)
- line, err := reader.Peek(7)
-
- if err != nil || !strings.HasPrefix(string(line), "CONNECT") {
- return /* not HTTP, let next handler deal with it */
- }
-
- conn.Close()
-}
-
-func init() {
- RegisterHandler(httpConnectHandler)
-}
diff --git a/proxy/https.go b/proxy/https.go
@@ -0,0 +1,98 @@
+package proxy
+
+import (
+ "bufio"
+ "fmt"
+ "io"
+ "log"
+ "math/rand"
+ "net"
+ "net/http"
+ "strings"
+ "sync"
+
+ utls "github.com/refraction-networking/utls"
+)
+
+func httpsHandler(clientConn net.Conn, p *Proxy) {
+ defer clientConn.Close()
+
+ // List of different browser fingerprints to cycle through.
+ var helloIDs = []utls.HelloID{
+ utls.HelloChrome_116,
+ utls.HelloFirefox_105,
+ utls.HelloSafari_16_0,
+ utls.HelloEdge_106,
+ }
+
+ // Read the first line of the request to check for the CONNECT method.
+ reader := bufio.NewReader(clientConn)
+ req, err := http.ReadRequest(reader)
+ if err != nil {
+ log.Printf("Failed to read client request: %v", err)
+ return
+ }
+
+ // An HTTPS proxy relies on the HTTP CONNECT method.
+ if req.Method != http.MethodConnect {
+ log.Printf("Received non-CONNECT request: %s %s", req.Method, req.Host)
+ return
+ }
+
+ // The Host field contains the destination host and port.
+ host := req.URL.Host
+ if !strings.Contains(host, ":") {
+ // If no port is specified by the client, use the `ForwardTo` port from our Proxy struct.
+ host = fmt.Sprintf("%s:%d", host, p.ForwardTo)
+ }
+
+ log.Printf("Connecting to target: %s", host)
+
+ // Establish a TCP connection to the target server.
+ targetConn, err := net.Dial("tcp", host)
+ if err != nil {
+ log.Printf("Failed to dial target %s: %v", host, err)
+ return
+ }
+ defer targetConn.Close()
+
+ randomIndex := rand.Intn(len(helloIDs))
+ randomHelloID := helloIDs[randomIndex]
+ log.Printf("Using uTLS fingerprint: %s", randomHelloID.String())
+
+ // Create a uTLS client with the randomly selected fingerprint & perform handshake
+ utlsConfig := &utls.Config{
+ ServerName: strings.Split(host, ":")[0],
+ }
+ uclient := utls.UClient(targetConn, utlsConfig, randomHelloID)
+
+ if err := uclient.Handshake(); err != nil {
+ log.Printf("uTLS handshake failed with %s: %v", host, err)
+ return
+ }
+ defer uclient.Close()
+
+ clientConn.Write([]byte("HTTP/1.1 200 Connection established\r\n\r\n"))
+ var wg sync.WaitGroup
+ wg.Add(2)
+
+ // Pipe data from the client to the target server.
+ go func() {
+ defer wg.Done()
+ _, err := io.Copy(uclient, reader)
+ if err != nil && err != io.EOF {
+ log.Printf("Error copying from client to target: %v", err)
+ }
+ }()
+
+ // Pipe data from the target server back to the client.
+ go func() {
+ defer wg.Done()
+ _, err := io.Copy(clientConn, uclient)
+ if err != nil && err != io.EOF {
+ log.Printf("Error copying from target to client: %v", err)
+ }
+ }()
+
+ wg.Wait()
+}
diff --git a/proxy/proxy.go b/proxy/proxy.go
@@ -1,13 +1,13 @@
package proxy
import (
- "crypto/x509"
+ "log"
"net"
)
type Proxy struct {
ListenAddr string
- CAPool *x509.CertPool
+ ForwardTo int
}
// function is a function that processes an incoming client connection
@@ -27,16 +27,21 @@ func (p *Proxy) Run() error {
if err != nil {
return err
}
+ defer ln.Close()
+
+ log.Printf("[+] Starting proxy on %s, forwarding to port %d", p.ListenAddr, p.ForwardTo)
for {
c, err := ln.Accept()
if err != nil {
- return err
+ log.Printf("Failed to accept connection: %v", err)
+ continue
}
conn := c
go func() {
for _, h := range handlers {
+ // Each handler processes the incoming connection.
h(conn, p)
}
}()
diff --git a/proxy/socks5.go b/proxy/socks5.go
@@ -1,25 +0,0 @@
-package proxy
-
-import (
- "bufio"
- "net"
-)
-
-func isSocks5(peek []byte) bool {
- return peek != nil || peek[0] == 0x05
-}
-
-func socks5Handler(conn net.Conn, p *Proxy) {
- reader := bufio.NewReader(conn)
- peek, err := reader.Peek(1)
-
- if err != nil || peek[0] != 0x05 {
- return /* not SOCKS5, let next handler deal with it */
- }
-
- conn.Close()
-}
-
-func init() {
- RegisterHandler(socks5Handler)
-}
| | | | | | | | | | |