Skip to content

Conversation

@perrornet
Copy link
Contributor

This PR introduces a new DefaultListener variable that allows configuring custom network listeners. This enables users to:

  1. Add middleware layers to TCP listeners (e.g., PROXY protocol support via third-party libraries)
  2. Implement custom connection handling before requests reach the server
  3. Use alternative listening mechanisms while maintaining compatibility

Example usage for PROXY protocol support:

import "github.com/pires/go-proxyproto"

fingerproxy.DefaultListener = func(addr string) (net.Listener, error) {
    ln, err := net.Listen("tcp", addr)
      if err != nil {
        return nil, err
    }
    return &proxyproto.Listener{
      Listener:          ln,
      ReadHeaderTimeout: 10 * time.Second,
    }, nil
}



@wi1dcard
Copy link
Owner

The problem is, fingerproxy must be at the edge of network. That is how it collects TCP fingerprints. The necessary information for JA3/JA4 fingerprinting will be lost if fingerproxy is behind any load balancer, even it supports PROXY protocol.

@perrornet
Copy link
Contributor Author

The problem is, fingerproxy must be at the edge of network. That is how it collects TCP fingerprints. The necessary information for JA3/JA4 fingerprinting will be lost if fingerproxy is behind any load balancer, even it supports PROXY protocol.

In reality, load balancers using L7 do alter TLS fingerprints. However, when employing L4 load balancing, the TLS handshake remains intact as it passes through the TCP-level load balancer and gets forwarded to the fingerproxy without modification.

Test Environment:

  1. L4 Load Balancer (HAProxy 2.6 TCP configuration):
global
    log /dev/log daemon warning
    log-send-hostname
listeners
    stats timeout 30s
    user haproxy
    group haproxy

frontend web_https
    mode tcp
    bind :30001
    log global
    option tcplog
    default_backend test_server

backend test_server
    mode tcp
    balance roundrobin
    option tcp-check
    tcp-check connect
    server  server1  192.168.0.104:30000 check
  1. Fingerproxy:
# Local DNS override
echo "127.0.0.1 example.com" >> /etc/hosts

# Fingerproxy configuration
export LISTEN_ADDR=30000
export FORWARD_URL=http://192.168.0.104:8088  # Target backend server
./fingerproxy


  1. Backend Server:
ginApp.Use(func(c *gin.Context) {
    // Capture client fingerprints
    log.Printf("ua: %s", c.Request.UserAgent())
    
    var fingerprints []string
    for header, values := range c.Request.Header {
        if strings.Contains(strings.ToLower(header), "fingerprint") {
            fingerprints = append(fingerprints, fmt.Sprintf("%s: %s", header, values[0]))
        }
    }
    sort.Strings(fingerprints)
    log.Println(strings.Join(fingerprints, "\n"))
    
    c.AbortWithStatus(http.StatusOK)
})

Test Results (from Gin Server Logs):

ua:  curl/7.87.0
X-Http2-Fingerprint: 3:100;4:33554432;2:0|33488897|0|m,p,s,a
X-Ja3-Fingerprint: bc29aa426fc99c0be1b9be941869f88a
X-Ja4-Fingerprint: t13d3112h2_e8f1e7e78f70_8d633dac7124
[GIN] 2025/01/29 - 01:24:16 | 200 |      54.584µs |   192.168.0.104 | GET      "/"
ua:  Apifox/1.0.0 (https://apifox.com)
X-Ja3-Fingerprint: 4d61c917a3225da2223d1955dc719e5d
X-Ja4-Fingerprint: t13d181200_e8a523a41297_02c8e53ee398
[GIN] 2025/01/29 - 01:24:20 | 200 |     122.708µs |      172.17.0.1 | GET      "/"
ua:  Wget/1.24.5
X-Ja3-Fingerprint: fb2ca6e2172a90bb4c4247a486214d93
X-Ja4-Fingerprint: t13d681200_13e0e9e1c501_5b0f5aef55e
[GIN] 2025/01/29 - 01:24:24 | 200 |    4.871042ms |   192.168.0.104 | GET      "/"
ua:  python-requests/2.32.3
X-Ja3-Fingerprint: 8d9f7747675e24454cd9b7ed35c58707
X-Ja4-Fingerprint: t13d4312h1_c7886603b240_b26ce05bbdd6
[GIN] 2025/01/29 - 01:43:27 | 200 |     175.667µs |   192.168.0.104 | GET      "/"

@wi1dcard
Copy link
Owner

Ah, yes you are correct. I misunderstand TCP/TLS fingerprinting. Thanks for the complete explanation. However, I prefer to not adding more global variables that modifies the behavior of default fingerproxy command. I will take a look to see if there's any better solution and update here soon.

@wi1dcard wi1dcard self-assigned this Jan 31, 2025
@perrornet
Copy link
Contributor Author

Could we add an enable-proxy-protocol flag? When this flag is specified, it would enable PROXY protocol support.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants