Files
layer4-proxy/README.md
Jacob Kiers 590740f40e
Some checks failed
ci/woodpecker/push/build/1 Pipeline was canceled
ci/woodpecker/push/build/3 Pipeline was canceled
ci/woodpecker/push/build/2 Pipeline was canceled
ci/woodpecker/tag/build/2 Pipeline is pending
ci/woodpecker/tag/build/3 Pipeline is pending
ci/woodpecker/tag/build/1 Pipeline was canceled
Add wildcard SNI matching
2026-04-09 22:12:55 +02:00

2.5 KiB

l4p

Hey, now we are on level 4!

CI

l4p is a layer 4 proxy implemented by Rust to listen on specific ports and transfer TCP data to remote addresses (only TCP) according to the configuration.

Features

  • Listen on specific port and proxy to local or remote port
  • SNI-based rule without terminating TLS connection
  • DNS-based backend with periodic resolution

Installation

To gain best performance on your computer's architecture, please consider build the source code. First, you may need Rust tool chain.

$ cd l4p
$ cargo build --release

Binary file will be generated at target/release/l4p, or you can use cargo install --path . to install.

Or you can use Cargo to install l4p:

$ cargo install l4p

Or you can download binary file form the Release page.

Features

  • Listen on specific port and proxy to local or remote port
  • SNI-based rule without terminating TLS connection
  • Wildcard SNI matching with DNS-style longest-suffix-match
  • DNS-based backend with periodic resolution

Configuration

l4p will read yaml format configuration file from /etc/l4p/l4p.yaml, and you can set custom path to environment variable L4P_CONFIG, here is an minimal viable example:

version: 1
log: info

servers:
  proxy_server:
    listen:
      - "127.0.0.1:8081"
    default: remote

upstream:
  remote: "tcp://www.remote.example.com:8082" # proxy to remote address

There are two upstreams built in:

  • Ban, which terminates the connection immediately
  • Echo, which reflects back with the input

For detailed configuration, check this example.

SNI Matching

The proxy supports both exact and wildcard SNI patterns in the sni config. Wildcards use DNS-style longest-suffix-match: more specific patterns take precedence. For example, with *.example.com and *.api.example.com, request api.example.com matches the first, while v2.api.example.com matches the second.

Wildcards are validated against the Public Suffix List (PSL). Known suffixes (.com, .org) require at least one label below the suffix (*.example.com OK, *.com rejected). Unknown suffixes (.local, .lan) are allowed without restriction.

Invalid wildcard patterns are rejected at config load time with clear error messages.

Thanks

  • fourth, of which this is a heavily modified fork.

License

l4p is available under terms of Apache-2.0.