transparency — network transparency and the related aspects
The Kernun firewall is able to transparently grab clients' connections and hand them over to its proxies, as well as to pretend to servers that connections come from clients' real IP addresses instead of the firewall's IP address. This ability is implemented in the transparency support that was added to the FreeBSD kernel.
Transparency for clients is realized using special sockets called transparent listening sockets. Unlike a regular listening socket, a transparent listening socket is able to accept transparent connections, i.e., it accepts a connection even if the client is not connecting explicitly to the firewall, but directly to some server's IP address.
A transparent listening connection can be configured
either to accept connections that arrive to any
interface, or it can be limited to a particular
interface. The former case is configured in the Kernun
configuration by specifying a special IP address,
latter one can be configured either by specifying the
name of the interface, or by specifying its IP address
(which is only used to
determine the particular interface). See listen-on(5) for the proper syntax.
Transparent listening sockets can be identified in a
running system by
sockstat(1). They are
distinguished from regular sockets by the special syntax
LOCAL ADDRESS field of the
If present, the
denotes the interface the transparent listening socket is
limited to. Otherwise (denoted by
the socket listens on all network interfaces.
In the TCP protocol, accepting connection by
accept(2) returns a new
socket that is used for communication with the client.
Packets sent via this socket are automatically assigned
the real destination (the server's) IP address as the
source address, and all packets sent within this
connection from the client to the server would come to
this socket. These sockets are indicated by syntax
>> in the
ADDRESS field of the
sockstat(1). Here, the
addr denotes the IP address of the
server (i.e., the IP address the client thinks to be
In the typical scenario there would be one transparent
listening socket for each interface the proxy listens on
FD 5 in the following example).
This socket is shared by the proxy's parent process and by
all of its child processes.
In addition, there would be two sockets for each
connection established via the proxy: one for the
connection from the client to the proxy
FD 11), and another for the connection
from the proxy to the server (
The situation is shown in the following example
stands for the client IP address,
10.3.3.3 stands for
the firewall external address and
10.4.4.4 stands for
the server IP address):
USER COMMAND PID FD PROTO LOCAL ADDRESS FOREIGN ADDRESS kernun tcp-proxy 26802 5 tcp4 vr0>>:22 *:* kernun tcp-proxy 26801 5 tcp4 vr0>>:22 *:* kernun tcp-proxy 26800 5 tcp4 vr0>>:22 *:* kernun tcp-proxy 26800 11 tcp4 >>10.4.4.4:22 10.1.1.1:36528 kernun tcp-proxy 26800 12 tcp4 10.3.3.3:62175 10.4.4.4:22 kernun tcp-proxy 26799 5 tcp4 vr0>>:22 *:* kernun tcp-proxy 26798 5 tcp4 vr0>>:22 *:* kernun tcp-proxy 26797 5 tcp4 vr0>>:22 *:*
Connections can be considered in ACLs according to their
transparency. This is done using a keyword to the
configuration item. If the key
transparent is present
in this item, only transparent connections get matched. Similarly,
non-transparent present, only
non-transparent connections get matched.
This feature allows servers to see real clients' addresses upon receiving connections instead of the firewall's address (which is the standard behavior for proxies). It can be specified in an ACL section using either of the following syntax constructions:
source-address client; source-address [18.104.22.168];
This feature can be regarded as transparency for servers.
source-address might be used either in
For example, if a client of
10.1.1.1 wants to
connect through proxy at
transparently or non-transparently) to server
the server sees normally the connection as coming from
firewall's external address, e.g.
the server sees the connection as if it were coming from
that case, the
the following output:
USER COMMAND PID FD PROTO LOCAL ADDRESS FOREIGN ADDRESS ... kernun tcp-proxy 23008 11 tcp4 >>10.4.4.4:22 10.1.1.1:36528 kernun tcp-proxy 23008 12 tcp4 10.1.1.1:62175 10.4.4.4:22 ...
Unlike in the first example,
the connection from the firewall to the server
FD=12) shows the
ADDRESS to be
10.1.1.1 (i.e., the
client's IP address).
For a given TCP/UDP port there can be more than one type of application listening side-by-side: transparent proxies, non-transparent proxies or system daemons (such as ssh daemon sshd). However, they must not be in mutual conflict.
Conflicts are detected by the /verify command of cml(8). Two applications that listen on the same port (or with their listen port ranges overlapping) are in conflict, if any of the following cases occurs:
Both listen in the non-transparent mode on the same IP address
Both listen in the non-transparent mode on the
wildcard IP address
Both listen transparently on the same interface (either if the interface name was given directly or if it was deduced from the IP address)
Both listen transparently without interface restriction
Note that the conflicts check is only performed for the components configured within the cml configuration file. It is not performed for the components that are configured out of it.
When a packet arrives, the most specific socket is chosen according to the following precedence order (from the most specific to the most generic):
Non transparent, single IP address, single port
Non transparent, wildcard
Transparent with interface restriction, single port
Transparent without interface restriction, single port
Non transparent, single IP address, port range
Non transparent, wildcard
Transparent with interface restriction, port range
Transparent without interface restriction, port range
It is therefore possible to provide several services for
the same port, as long as they do not collide. For
example, the SSH daemon might be available for an
administrative connection to the firewall on all
interfaces (SSH daemon only makes sense in the
non-transparent mode), while
might be configured in the transparent mode for proxying the
ssh traffic through the server for the internal
interface. In that case, packets with the destination
address equal to any of the firewall's IP addresses
would end up in the SSH daemon, while packets with the
destination in the external network would be processed by
the tcp-proxy. See the examples section.
When transparency is enabled (
net.inet.ip.transparency=1), every packet is
considered to be potentially local (i.e., destinated for
some firewall's process) and is therefore delivered
into the local IP stack. One of the consequences of this fact
is that the packet is not eventually ip-forwarded (even if
sysctl net.inet.ip.forwarding=1 and it
would have been forwarded, if the standard FreeBSD kernel
had been used).
Under certain circumstances it might be desirable to
bypass transparency. Kernun firewall uses the packet
packet-filter(5)) for this
purpose. When the packet has the pf tag
NOTRANSP set, the kernel handles it the same
way the regular FreeBSD kernel would. The actual tag that
is used for this purpose can be changed using sysctl
NOTRANSP is the default value.
The following rule can be used to tag all the
traffic from client of
pass in on vr0 from 10.1.1.1 to any tag NOTRANSP
Note that all the traffic that is
required not to undergo the transparency must be tagged
NOTRANSP. Especially, for bidirectional communication,
packets for both directions must be tagged so (see the
latter example in this manual page).
FreeBSD: ioctl(2), pf(4), pf.conf(5), pfctl(8)