Consulting djbware Publications

tcprules - compiles rules for tcpserver and sslserver

Purpose

TCP connections targeting tcpserver or sslserver can denied or allowed given several connection informations, like the client's IP address. tcprules allows to define rules for incoming TCP connections to decided whether they finally will result in an active TCP session. If accepted, several environment settings can be given; typically used by the invoked server application.

Compiling Rules

Rules are defined in text-format to be subject of tcprules which turnes the rule into a machine-independent cdb format.

tcprules reads rules from its standard input and writes them into cdb in a binary format suited for quick access. Their file names can be freely chosen. The resulting file rules.cdb needs to be provided to tcpserver or sslserver upon call.

Typical usage:

tcprules rules.cdb rules.tmp < rules.txt

tcprules can be modified while tcpserver or sslserver are running. Changes to the rule base are atomic and the result is read by tcpserver or sslserver upon their following invocation.

Rule syntax and Instructions

A rule is one line. A file containing rules may also contain comments: lines beginning with # are ignored. tcprules offers two distinct instruction rules:

Environment variables are typically expressed in upper case. Any number of environment variables can be given. The content of the enviroment variable should be given in single or doube quotes. Unlike DJB's original implementation, here ':' colons are allowed.

Addresses

tcpserver support three different types of addresses:

  1. IP addresses: IPv4 and compactified IPv6 addresses; potentially expressed in CIDR format.
  2. Domain names: which however require a DNS query/reply based on the incoming IP address.
  3. User names: In case the IDENT or TAP lookup was successful user@host or user@ip (not used anymore).
IPv4 Addresses

tcprules recognizes IPv4 addresses in four different ways:

  1. Host IPv4 addresses, while for instance blocking one singe IPv4 18.23.0.32:deny.
  2. IPv4 octett ranges. Here complete subnets can be accepted or blocked: 18.:deny.
  3. Contiguous IPv4 address ranges within subnets: 18.23.0.1-22:allow.
  4. IPv4 CIDR notation: 127.0/8:allow.
    The bit-length of the given IP address (after expansion) has at least to match number of net-prefix bits. Otherwise, a syntax error is displayed.
IPv6 Addresses

tcprules understands

  1. compactified IPv6 addresses: 2001:de01:2:3:4:a:b:c:deny, or
  2. IPv6 addresses in CIDR format: 2002::/48:deny.
    Since the IPv6 address on input is evaluated in it's compactified format, simply include the final '::' for convenience. The resulting address is truncated to the number of provided prefix bits.

Note: Always IPv4/IPv6 addresses with the longest matching address part or prefix are considered. Unlike the DNS information, IP addresses can not be faked for TCP connections. Therefore, within tcprules they have precedence over DNS responses.

Domain Names

tcprules is enabled to understand the hierarchical label-based DNS full-qualified domain name. In order to distinguish domain names from IPv4 addresses (following the same snytax), a prepending equal sign '=' is required for domain names. In case a DNS lookup is performed prior to evaluating the TCP connection by tcprules, the following DNS names can be used:

  1. Full FQDN for a single host: =host.example.com:allow.
  2. Domain names and TLDs: =example.net:deny or =.example.net:deny, or even =.com:allow,GREETDELAY="60".
  3. Resolvable IP addresses (indicated by the solitary '=' sign): =:allow; reversely, if not: :deny.

This covers the most practical cases.

Order of Execution

tcprules follows the idea, that more specific settings have precedence over less specific.

  1. $TCPREMOTEINFO@$TCPREMOTEIP, if $TCPREMOTEINFO is set;
  2. $TCPREMOTEINFO@=$TCPREMOTEHOST, if $TCPREMOTEINFO is set and $TCPREMOTEHOST is set;
  3. $TCPREMOTEIP;
  4. =$TCPREMOTEHOST, if $TCPREMOTEHOST is set;
  5. shorter and shorter prefixes of $TCPREMOTEIP ending with a dot;
  6. $TCPREMOTEIP/PREFIX where $TCPREMOTEIP considering in order the longest matching provided PREFIX;
  7. shorter and shorter suffixes of $TCPREMOTEHOST starting with a dot, preceded by =, if $TCPREMOTEHOST is set;
  8. =, if $TCPREMOTEHOST is set; and finally
  9. the empty string.

Testing Rules

Testing your current rules is easys using tcprulescheck:

  1. Whithin your shell, you can simply define tailored environment variables as given above (exported).
  2. Invoking now tcprulescheck while providing your cdb as argument will show which current rule is selected.

Sample:

127.0.0.1:allow,RELAYCLIENT="" =:allow :deny

After compilation of this ruleset by means of tcprules as testrules.cdb you can run your tests:

$ export TCPREMOTEIP=127.0.0.1 $ tcprulescheck testrules.cdb tcprulescheck: info: TCPREMOTEIP: 127.0.0.1 TCPREMOTEHOST: rule 127.0.0.1: set environment variable RELAYCLIENT= allow connection $ export TCPREMOTEIP=127.0.0.2 $ tcprulescheck testrules.cdb tcprulescheck: info: TCPREMOTEIP: 127.0.0.2 TCPREMOTEHOST: default: deny connection $ export TCPREMOTEHOST=host.example.com $ tcprulescheck testrules.cdb tcprulescheck: info: TCPREMOTEIP: 127.0.0.2 TCPREMOTEHOST: host.example.com TCPREMOTEINFO: rule =: allow connection