barefoot   Frontpage - Barefoot - Download - Usage - Status - Support - Modules - Docs - Links - Survey - GDPR
 

HOSTID operations

This page describes how to perform access control based on out-of-band hostid client information.

NOTE: This functionality currently depends on proprietary extensions similar to those described in draft-abdo-hostid-tcpopt-implementation-02.

A hostid as used here is a client identifier. When a client connects directly to a Barefoot server, the IP-address of the client can be obtained via the getpeername() system call, but with the standard TCP/IP and SOCKS protocols the identity of the client will not be available to the next hop (the address the Barefoot server connects to on behalf of the client).

Whether the proxy server forwards connections directly to a target destination or via server chaining to another proxy server, the first proxy will appear as the client for the next server if getpeername() is used. This makes it difficult to perform access control, logging or similar operations based on the original client IP-address in other locations than in the proxy server that communicates directly with the client. An approach, such as those described in the above hostid-tcpopt draft makes use of a TCP option to transmit the identity of the original client in forwarded connections. Any IP-address transmitted in this way is here referred to as a hostid.

The Barefoot hostid support is designed so that multiple hostids (or IP-addresses) can be transmitted, allowing the identity of multiple layers of caches to be encoded.

Barefoot hostid configuration

A possible hostid usage scenario would include a client, a Barefoot proxy and a target server. The client connects to the Barefoot proxy which then initiates a connection to the target server. The connection to the target server would be done by the Barefoot server, but the identity of the client would be available to the target server via the hostid information provided via a TCP socket option.

A second scenario would have a private company network with two layers of proxies. The first layer at the border of the private and public network, and the second layer inside the private network. The border proxy would receive connections directly from external clients and set the IP-address of these clients in the hostid field on connections forwarded to the internal proxy. The internal proxy would retrieve the hostid value and add the IP-address of the border proxy on connections to the target server. The target server would then have available the IP-address of the original client (as HOSTID), the border proxy (as HOSTID2), and the external address of the internal proxy (via a direct TCP connection).

Logging of hostid values

On platforms supporting the hostid socket option, any available hostid information on a TCP connection Barefoot receives will be automatically logged by Barefoot. The hostid information is merged with the information normally logged by Barefoot in the format shown below.

HOSTID corresponds to the first hostid TCP option value. The logged HOSTID values are enclosed in a set of [] characters to emphasize that this information is obtained out-of-band and cannot be verified by Barefoot.

info: pass(1): tcp/hostid [: [HOSTID] CLIENT PROXY-INT -> ALLZEROES TARGET
info: pass(1): tcp/connect [: [HOSTID] CLIENT PROXY-INT -> PROXY-EXT TARGET
info: pass(1): tcp/connect -: TARGET PROXY-EXT -> PROXY-INT CLIENT [HOSTID] (RLEN)
info: pass(1): tcp/connect -: [HOSTID] CLIENT PROXY-INT -> PROXY-EXT TARGET (WLEN)
info: pass(1): tcp/connect ]: RLEN -> [HOSTID] CLIENT PROXY-INT -> WLEN, WLEN -> PROXY-EXT TARGET -> RLEN: DESC. Session duration: SESSTIMEs
info: pass(1): tcp/hostid ]: RLEN -> [HOSTID] CLIENT PROXY-INT -> WLEN, WLEN -> ALLZEROES TARGET -> RLEN: DESC. Session duration: SESSTIMEs

The following information is reported on the connection when SIGINFO/SIGUSR1 is received:

debug: tcp: [HOSTID] CLIENT PROXY-INT <-> PROXY-EXT TARGET: age: SESSTIMEs, idle: IDLETIMEs, bytes transferred: WLEN (+ 0 buffered (0 + 0 + 0)) <-> RLEN (+ 0 buffered (0 + 0 + 0))

When two hostid addresses are set on a connection, the output will appear as follows. The second hostid address will be shown in the HOSTID2 field:

info: pass(1): tcp/hostid [: [HOSTID] [HOSTID2] CLIENT PROXY-INT -> ALLZEROES TARGET
info: pass(1): tcp/connect [: [HOSTID] [HOSTID2] CLIENT PROXY-INT -> PROXY-EXT TARGET
info: pass(1): tcp/connect -: TARGET PROXY-EXT -> PROXY-INT CLIENT [HOSTID2] [HOSTID] (RLEN)
info: pass(1): tcp/connect -: [HOSTID] [HOSTID2] CLIENT PROXY-INT -> PROXY-EXT TARGET (WLEN)
info: pass(1): tcp/connect ]: RLEN -> [HOSTID] [HOSTID2] CLIENT PROXY-INT -> WLEN, WLEN -> PROXY-EXT TARGET -> RLEN: DESC. Session duration: SESSTIMEs
info: pass(1): tcp/hostid ]: RLEN -> [HOSTID] [HOSTID2] CLIENT PROXY-INT -> WLEN, WLEN -> ALLZEROES TARGET -> RLEN: DESC. Session duration: SESSTIMEs

The SIGINFO/SIGUSR1 format for two hostid values is as follows:

debug: tcp: [HOSTID] [HOSTID2] CLIENT PROXY-INT <-> PROXY-EXT TARGET: age: SESSTIMEs, idle: IDLETIMEs, bytes transferred: WLEN (+ 0 buffered (0 + 0 + 0)) <-> RLEN (+ 0 buffered (0 + 0 + 0))

When server chaining is used, the proxy that forwards the request to a SOCKS server and uses the following extended log format, which also includes information about the next and last SOCKS proxies (as the contacted SOCKS server might forward the request to another SOCKS server, and so on). Note that when server chaining is used, the LASTPROXY-EXT value is also put inside a set of [] characters to indicate it cannot be directly verified.

info: pass(1): tcp/hostid [: [HOSTID] CLIENT PROXY-INT -> ALLZEROES TARGET
info: pass(1): tcp/connect [: [HOSTID] CLIENT PROXY-INT -> PROXY-EXT NEXTPROXY-INT [LASTPROXY-EXT] TARGET
info: pass(1): tcp/connect -: TARGET [LASTPROXY-EXT] NEXTPROXY-INT PROXY-EXT -> PROXY-INT CLIENT [HOSTID] (RLEN)
info: pass(1): tcp/connect -: [HOSTID] CLIENT PROXY-INT -> PROXY-EXT NEXTPROXY-INT [LASTPROXY-EXT] TARGET (WLEN)
info: pass(1): tcp/connect ]: RLEN -> [HOSTID] CLIENT PROXY-INT -> WLEN, WLEN -> PROXY-EXT NEXTPROXY-INT [LASTPROXY-EXT] TARGET -> RLEN: DESC. Session duration: SESSTIMEs
info: pass(1): tcp/hostid ]: RLEN -> [HOSTID] CLIENT PROXY-INT -> WLEN, WLEN -> ALLZEROES TARGET -> RLEN: DESC. Session duration: SESSTIMEs

SIGINFO/SIGUSR1 format:

debug: tcp: [HOSTID] CLIENT PROXY-INT <-> PROXY-EXT NEXTPROXY-INT [LASTPROXY-EXT] TARGET: age: SESSTIMEs, idle: IDLETIMEs, bytes transferred: WLEN (+ 0 buffered (0 + 0 + 0)) <-> RLEN (+ 0 buffered (0 + 0 + 0))

Manipulation of hostid values

TCP connections received by a Barefoot server can have zero or more hostid values set. By default the server will log these values but not forward them onto the outgoing connection. To explicitly specify how the hostid values should be handled, the following alternatives are available:

  • none - No hostid values will be set on the outgoing connection. This is the default behavior.
  • pass - This causes Barefoot to simply forward/duplicate any existing hostid values from the client connection, without adding or removing anything.
  • set-client - Any existing values are discarded and only the source address of the client connecting to Barefoot will be set in the hostid field on the outgoing connection.
  • add-client - This causes any existing values to be duplicated (unless all entries are used) and the client source address to be added.

    It should be noted that the hostid TCP option field is not of infinite size, and might be limited by both a given kernel implementation and the TCP header size. Care should be be taken to ensure that a chain of proxies will not attempt to set a larger number of hostid entries than there is room for as this will result in loss of information.

    Assuming a maximum of two hostid values are supported, the following behavior is implemented by Barefoot when adding addresses to the hostid fields on an outgoing connection:

    • If no hostid values are set on the incoming connection, the source address of the client connecting to Barefoot will be set in the first hostid position on the outgoing connection. The second position will remain empty.
    • If a single hostid value is set on the incoming connection, it will be copied to the first hostid position on the outgoing connection. The source address of the client connecting to Barefoot will be set in the second hostid position.
    • If two hostid values are set on the incoming connection, the first hostid value from the incoming connection will be copied to the first hostid position on the outgoing connection. The second hostid value from the incoming connection will be discarded, and instead the source address of the client connecting to Barefoot will be set in the second hostid position on the outgoing connection.

      This means that with this approach any address lost will be those off intermediate proxies or routers, rather than the first value added, which is expected to contain the address of the initial client.

      A warning will be logged by Barefoot when this occurs:

      warning: setconfsockoption(): connection from 127.0.0.1.57839 has already reached the maximum number of hostids (2), so can not add one more. Removing the last hostid (172.16.100.2) before adding the new one

Because any IP-address can be set in the hostid TCP option, values set by untrusted clients should be treated with care. A Barefoot proxy that communicates directly with an untrusted client should use either the none or the set-client keywords to discard any hostid TCP option values set by the untrusted client. The pass or add-client values should only be used for connections from trusted hosts (such as another proxy).

The hostid keywords can be set both globally, as defaults, and in socks rules, meaning that different approaches can be used for different clients and SOCKS requests. The syntax is as follows:

 external.tcp.hostid: pass|add-client|set-client|none

The example below shows a configuration that specifies that by default, hostid values should not be set for outgoing connections (keyword none), with two exceptions:

  • For any other connections from a machine with the IP-address 10.0.0.1, any hostid values should be passed on unchanged (keyword pass).
  • For any connections to the target server www.example.org, the address of the client should be added to any existing hostid values (keyword add-client).
#default, discard any hostid
external.tcp.hostid: none

#duplicate any hostid values from the host 10.0.0.1
client pass {
     from: 10.0.0.1/32 to: eth0 port = www
     bounce to: www.example.org port = www

     external.tcp.hostid: pass
}

#add client source address to hostid values.
client pass {
     from: 0.0.0.0/0 to: eth0 port = www
     bounce to: www.example.org port = www

     external.tcp.hostid: add-client
}

#use the default; not setting any hostids.
client pass {
     from: 0.0.0.0/0 to: eth0 port = ssh
     bounce to: www.example.org port = ssh
}

Access control based on hostid values

A new access control layer has been added in this release that can be used to either grant or deny access to the proxy based on hostid information.

Access control is now done in these steps:

  1. First the client pass/block rules are applied.
  2. Then the new hostid pass/block rules are applied for any TCP connections that have hostid values set. These rules are ignored for TCP connections without hostid values.

The first step is basically unchanged, but a new keyword (hostid)) has been added that can be used to ensure that connections that should have hostid values set are blocked if no hostid values have been set. The following example shows how this can be done:

#matches connections from 10.0.0.1 *only* if they have hostid values set,
#regardless of what the hostid value is.
#if there are no other client pass rules matching connections from 10.0.0.1,
#connections from 10.0.0.1 will always be blocked unless they have at
#least one hostid value set.
client pass {
	from: 10.0.0.1/32 to: eth0 port = www
	bounce to: www.example.org port = www
	hostid: 0.0.0.0/0
}

#require hostid values to be set on connections from 10.0.0.2,
#but also require the hostid values to be in the 172.16 network.
client pass {
	from: 10.0.0.2/32 to: eth0 port = www
	bounce to: www.example.org port = www
        hostid: 172.16.0.0/12
}

#allow connections from 10.0.0.3 regardless of whether hostid values
#are set or not.
client pass {
	from: 10.0.0.2/32 to: eth0 port = www
	bounce to: www.example.org port = www
}

As with the from and to keywords, the hostid keyword can contain an address or hostname to match against. All the specified parameters (from, to, hostid, etc. must match for a rule to pass.

The hostid rules are applied before the Barefoot client pass/block rules. The contents of the from keyword is matched against the hostid values and the to keyword against the internal address of the Barefoot server.

Since the hostid field can contain more than one address, it is necessary to be able to control which hostid address the from address should be matched against.

This is controlled with the hostindex keyword, which can have the values any, 1, or 2. The any keyword causes a rule to match if any of the hostid values matches. A value of 1 will only match if it matches the first first hostid value (the initial client), and 2 will only match if it matched the second value. By default, the value of this hostindex parameter is 1.

If there is at least one hostid rule configured in the Barefoot configuration file, the default behavior is to block connections with hostid information set unless there is a matching hostid pass rule, while if no hostid rules exists, or no hostid value is set on the incoming connection, the default behaviour is to ignore hostid values as far as access control is concerned. Note that this is different from the other ACL-levels, which block by default and always require a matching pass rule.

The following example shows a simple example with a single hostid rule:

#pass connections where the first hostid value is 10.0.0.1
hostid pass {
       from: 10.0.0.1/32 to: 0.0.0.0/0
       hostindex: 1
}

This example has two rules to allow different matching for each of the two hostid values:

#pass connections where the first hostid value is from the 10.0.0.0 network
hostid pass {
       from: 10.0.0.0/8 to: 0.0.0.0/0
       hostindex: 1
}

#also pass connections where the second hostid value is 172.16.0.20
hostid  {
       from: 172.16.0.20/32 to: 0.0.0.0/0
       hostindex: 2
}

Usage example A

This section shows how the different keywords can be combined in a typical usage scenario.

This example is based on a usage scenario where there is a Barefoot server running on the border between an internal and an external network. The Barefoot server receives traffic from untrusted clients and forwards it to any specified internal target servers.

The Barefoot server ignores any hostid values set on connections from the clients connecting to it and sets the source address of the clients in the first hostid field of the connections going to the internal servers.

The following Barefoot configuration is used to achieve this behavior:

#always set client IP on outgoing connections, ignoring any existing values
external.tcp.hostid: set-client

#pass ssh traffic for client connections from the 192.168-net.
client pass {
	from: 192.168.0.0/16 to: eth0 port = ssh
	bounce to: www.example.org port = ssh
}

The configuration above would give the following behavior for a client with the address 192.168.1.10 connecting to the ssh port on the Barefoot proxy.

  1. The client pass rule would match, causing the Barefoot server to establish a connection to the ssh port on www.example.org on behalf of the client from 192.168.1.10.
  2. The connection received by the target server would see the external IP-address of the Barefoot proxy as the source IP-address, and have the IP-address of the client (192.168.1.10) set as a hostid value in the TCP connection from Barefoot (assuming the server supports this extension and is able to extract the value from the kernel). No other hostid values would be set.

Usage example B

The example is based on a usage scenario where there is a Barefoot server running on the border between an internal and an external network, like in the previous example. In this case the Barefoot configuration is more restrictive and only accepts connections from, a presumably trusted, server with the address 192.168.1.1. All connections need to have at least one hostid value set. This example also uses the hostid addresses for access control, allowing only specific address ranges to connect through Barefoot.

The following Barefoot configuration is used to achieve this:

#always add client IP on outgoing connections, keeping the existing value.
external.tcp.hostid: add-client

#pass client connections from the trusted server 192.168.1.1, but require
#them to have a hostid set. 
client pass {
        from: 192.168.1.1/32 to: eth0 port = ssh
	bounce to: www.example.org port = ssh
        hostid: 0.0.0.0/0
        log: connect disconnect error

}

#only clients with a hostid from the 172.16-net are accepted.
hostid pass {
        from: 172.16.0.0/12 to: 0.0.0.0/0
        log: connect disconnect error
}

The configuration above would give the following behavior for a client with the address 172.16.0.1 connecting via the trusted server at 192.168.1.1 to the ssh port on the Barefoot proxy.

  1. The client pass and hostid pass rules would all match, causing the Barefoot server to establish a connection to the ssh port of www.example.org on behalf of the client from 192.168.1.1. The connection to the target server would have both the client address 172.16.0.1 and the proxy address 192.168.1.1 set in the hostid header.
  2. A TCP connection would be received by the 10.1.1.1 server. The hostid values on this connection would contain the addresses 172.16.0.1 and 192.168.1.1. The source IP-address of the connection would be that of the external Barefoot interface.

Copyright © 1998-2018 Inferno Nettverk A/S