caddy-l4

repository·master·Indexed 23 days ago

https://github.com/mholt/caddy-l4

An experimental Layer 4 application for Caddy that enables composable handling of raw TCP, UDP, and Unix socket connections. It allows users to route, proxy, or manipulate traffic based on connection properties such as IP addresses, TLS SNI, or protocol sniffing. Key features include TLS termination for non-HTTP protocols, load balancing, and port-based routing. It uses a modular architecture consisting of servers, routes, matchers, and handlers, and can be configured via Caddyfile or JSON.

Tokens
75.7K
Snippets
113
Records
173
Agent score
83%

What's inside caddy-l4

  1. What is Caddy Layer 4?

    master

    Caddy-L4 (formerly Project Conncept) is a Layer 4 app for Caddy designed to handle low-level, non-HTTP network traffic at the transport layer (OSI Layer 4). It supports TCP, UDP, and Unix sockets.

    Key use cases include:

    • Proxying Raw TCP/UDP Traffic: Forwarding protocols like SSH, databases (MySQL, PostgreSQL), or gaming servers.
    • Port-Based Routing: Directing traffic based on ports without HTTP logic.
    • TLS Termination: Offloading encryption/decryption for non-HTTP protocols.
    • Load Balancing: Distributing Layer 4 traffic across backends.
    • Protocol Agnosticism: Supporting any protocol that operates over TCP/UDP.
  2. Understand how Routes work in Caddy-L4

    master

    Routes define how incoming TCP/UDP traffic is processed by combining Matchers and Handlers.

    • Matchers: Criteria used to filter connections (e.g., IP address, TLS SNI).
    • Handlers: Actions taken on matched traffic (e.g., proxy, echo, tls).

    Matching Logic

    • AND Logic (Matcher Sets): A single matcher set (a collection of matchers) requires ALL its matchers to return true for a connection to be accepted.
    • OR Logic (Multiple Matcher Sets): If a route contains multiple matcher sets, a connection is accepted if ANY matcher set returns true.
    • Catch-all: A route with no matcher sets handles all traffic and prevents any subsequent routes from being evaluated.

    Execution Order

    • Matchers: The order of matchers within a set, or the order of matcher sets within a route, does not affect matching results.
    • Handlers: Handlers execute sequentially in a chain. The order in which you list handlers inside a route is critical.
  3. How caddy-l4 works: Servers, Routes, Matchers, and Handlers

    master

    The caddy-l4 app operates using a hierarchical structure similar to Caddy's http app:

    1. Servers: The top-level definition where you listen on specific sockets or ports.
    2. Routes: Each server contains one or more routes.
    3. Matchers: A route defines a set of conditions (matchers) that a connection must meet to trigger the route.
    4. Handlers: If the matchers are satisfied, the associated handlers are invoked to process the connection (e.g., proxying, echoing, or terminating TLS).

    This composable model allows you to perform complex logic like inspecting TLS SNI, checking HTTP Host headers, or routing based on IP ranges at the Layer 4 level.

  4. Use the SOCKS5 Matcher

    master

    The SOCKS5 matcher identifies connections that follow the SOCKSv5 protocol. It performs raw packet parsing to detect SOCKSv5 traffic.

    Because the SOCKSv5 header is very short, using a bare socks5 matcher may result in false positives. To increase accuracy, you should use the auth_methods field to specify the exact authentication methods you expect from your clients.

  5. Configure the DNS Matcher

    master

    The DNS matcher filters DNS traffic by inspecting the question section of DNS request messages. You can use allow and deny rules to match against the domain name, the record type (e.g., A, MX, NS), and the class (e.g., IN, CH).

    Filtering Modes

    • Exact Matching: Use name, type, and class for string matching. Domain names must be lowercase and end with a dot (e.g., example.com.).
    • Regular Expression Matching: Use name_regexp, type_regexp, and class_regexp for pattern matching.
    • Wildcards: Use an asterisk * to skip filtering a specific field.

    Restrictiveness Controls

    • default_deny: If set to true, any DNS request that does not match an allow or deny rule is denied. The default behavior is to allow unmatched traffic.
    • prefer_allow: If set to true, requests that match both an allow rule and a deny rule are allowed. The default behavior is to deny such requests.
  6. Use the Vars Regexp matcher to match connections

    master

    The vars_regexp matcher allows you to match connections based on regular expressions applied to variables in the connection context or placeholder values.

    Key Behaviors

    • Placeholders vs Variables: If the key is surrounded by { } (e.g., {l4.tls.cipher_suite}), it is treated as a placeholder. Otherwise, it is treated as a variable name.
    • Capture Groups: Upon a successful match, the matcher adds new placeholders to the connection context. These follow the pattern {l4.regexp.<name>.<capture_group}} where <name> is the optional name provided to the matcher. If no name is provided, the pattern is {l4.regexp.<capture_group}}.
    • No Expansion: Placeholders in the keys or values of variables are not expanded during provision or matching.

    Caddyfile Syntax

    vars_regexp [<name>] <variable> <regexp>

    Note: The Caddyfile syntax only supports one variable per matcher. To implement OR logic, use multiple matcher sets.

    vars_regexp aes_gcm {l4.tls.cipher_suite} ^TLS_([_A-Z]?)AES_(?<key>\d+)_GCM_SHA(?<hash>\d+)$
  7. Use the Close handler to terminate connections

    master

    The close handler immediately closes incoming connections.

    Behavior by Protocol Type:

    • Connection-oriented (e.g., TCP): The handler closes the actual net.Conn connection.
    • Connectionless (e.g., UDP): The handler closes the 'virtual connection' created when the first packet is received from a specific address:port combination. The sender is unaware the connection was closed. If the same sender sends more traffic, a new virtual connection is created, and routing/matching logic repeats. This is useful for filtering specific packets.
  8. Use the Vars matcher to match connections

    master

    The vars matcher allows you to match connections based on variables in the context or placeholder values. It functions similarly to the vars matcher in the Caddy HTTP app.

    Logic and Syntax

    • Implementation: It uses a map of strings to a slice of strings. The key is the placeholder or variable name, and the values are the possible values that will trigger a match (using logical OR logic).
    • Placeholders vs. Variables:
      • If the key is surrounded by { } (e.g., {l4.tls.cipher_suite}), it is treated as a placeholder.
      • Otherwise, it is treated as a variable name.
    • Expansion:
      • Placeholders used in the keys or the variable values are not expanded.
      • However, placeholders used within the possible values are resolved at the time of matching.
  9. How Caddy Layer 4 architecture works

    master

    The Layer 4 app uses a modular architecture consisting of four primary components that work together to process connections:

    1. Servers: The entry point that applies routes to raw socket connections (TCP, UDP, or Unix sockets).
    2. Routes: Sets of matchers and handlers. If a connection satisfies a route's matchers, its associated handlers are invoked.
    3. Matchers: Components that perform protocol inspection (e.g., detecting SSH, RDP, or OpenVPN) or filtering (e.g., by client IP or time).
    4. Handlers: A chain of processors that act on each incoming connection (e.g., proxying traffic to a backend or terminating TLS).
  10. Use placeholders in Caddy Layer 4

    master

    Placeholders allow for dynamic configuration values. There are two types:

    1. Environment Variables

    • Caddyfile only: Use {$VAR} syntax. These are evaluated once at launch before the Caddyfile is parsed.
    • Both Caddyfile and JSON: Use {env.VAR} syntax. These are runtime placeholders.

    2. Runtime Placeholders

    Runtime placeholders use the {...} syntax. Support varies by data type and option:

    TypePlaceholder Support
    Numeric (int, float, duration, etc.)No support
    Strings (IPs/CIDRs, Regex, Special values)Supported, but evaluated once at provision (e.g., remote_ip matcher, socks5 handler commands/credentials).
    Special Case: proxy handler dial and local_addressEvaluated twice: once at handler provision (for {env.*}) and once at dial/per-connection (for {l4.*}).
    Other Strings (e.g., alpn)Supported and evaluated each time at match or handle.

    Important Exceptions:

    • tls_* options inside the upstream of a proxy handler do not support runtime placeholders.
    • All options inside the connection_policy of a tls handler do not support runtime placeholders.
  11. Use the OpenVPN Matcher to multiplex OpenVPN traffic

    master

    The OpenVPN matcher identifies connections that follow the OpenVPN protocol by performing independent raw packet parsing. It allows Caddy to multiplex multiple, diversely configured OpenVPN server instances on a single port by matching based on security modes, digest algorithms, and keys.

    Supported capabilities include:

    • Matching all control channel security modes: plain, auth, crypt, and crypt2.
    • Matching based on a digest algorithm (in auth mode).
    • Matching based on a group key (in auth and crypt modes).
    • Matching based on a server key (in crypt2 mode).
    • Matching based on client keys (in crypt2 mode).
    • Support for both TCP and UDP connections.
  12. How the Not matcher works

    master

    The not matcher negates matching conditions, allowing you to match connections that do not satisfy the inner matching sets.

    Logic Rules:

    • A not matcher takes one or more matcher sets.
    • The matcher sets are OR'ed: if any matcher set returns true, the final result of the not matcher is false.
    • Individual matchers within a single set are AND'ed (standard matching behavior).

    Implementation Differences:

    • Caddyfile: Supports only a single matcher set. To achieve OR logic (negating multiple different conditions), you must use multiple not matchers.
    • JSON: Supports multiple matcher sets within a single not block, allowing for complex OR logic.