Project

General

Profile

Route-based VPNs » History » Version 2

Noel Kuntze, 16.03.2017 00:49
Problem with connmark

1 1 Tobias Brunner
h1. Route-based VPNs
2 1 Tobias Brunner
3 1 Tobias Brunner
{{>toc}}
4 1 Tobias Brunner
5 1 Tobias Brunner
Generally IPsec processing is based on policies. After regular route lookups are done the OS kernel consults its SPD(Security Policy Database) for a matching policy and if one is found that is associated with an IPsec SA(Security Association) the packet is processed (e.g. encrypted and sent as ESP packet). Refer to [[IPsecDocumentation]] for details.
6 1 Tobias Brunner
7 1 Tobias Brunner
Depending on the operating system it is also possible to configure route-based VPNs. Here IPsec processing does not (only) depend on negotiated policies but may e.g. be controlled by routing packets to a specific interface.
8 1 Tobias Brunner
9 1 Tobias Brunner
Most of these approaches also allow easy capture of plaintext traffic, which, depending on the operating system, might not be that straight-forward with policy-based VPNs (see [[CorrectTrafficDump]]). Another advantage this approach could have is that the MTU can be specified for the tunneling devices allowing to fragment packets before tunneling them in case PMTUD does not work properly.
10 1 Tobias Brunner
11 1 Tobias Brunner
h2. VTI Devices on Linux
12 1 Tobias Brunner
13 1 Tobias Brunner
_*Disclaimer:* VTI devices are supported since the Linux 3.6 kernel, but some important changes were added later (3.15+). The information below might not be accurate for older kernel versions._
14 1 Tobias Brunner
15 1 Tobias Brunner
VTI devices act like a wrapper around existing IPsec policies. This means you can't just route arbitrary packets to a VTI device to get them tunneled, the established IPsec policies have to match too. However, you can negotiate _0.0.0.0/0_ traffic selectors on both ends to allow tunneling anything that's routed via VTI device.
16 1 Tobias Brunner
17 1 Tobias Brunner
To make this work, that is, to prevent packets not routed via VTI device from matching the policies (if _0.0.0.0/0_ is used every packet would match) marks are used. Only packets that are marked accordingly will match the policies and get tunneled, for other packets the policies are ignored. Whenever a packet is routed to a VTI device it automatically gets the configured mark applied so it will match the policy and get tunneled.
18 1 Tobias Brunner
19 1 Tobias Brunner
It's important to note that VTI tunnel devices are a local feature, no additional encapsulation (like with GRE, see below) is added, so the other end does not have to be aware that VTI devices are used in addition to regular IPsec policies.
20 1 Tobias Brunner
21 1 Tobias Brunner
A VTI device may be created with the following command:
22 1 Tobias Brunner
23 1 Tobias Brunner
<pre>
24 1 Tobias Brunner
ip tunnel add <name> local <local IP> remote <remote IP> mode vti key <number equaling the mark>
25 1 Tobias Brunner
</pre>
26 1 Tobias Brunner
27 1 Tobias Brunner
_<name>_ can be any valid device name (e.g. _ipsec0_, _vti0_ etc.). But note that the @ip@ command treats names starting with _vti_ special in some instances (e.g. when retrieving device statistics). The IPs are the endpoints of the IPsec tunnel. The number at the end has to match the mark configured for the connection. It is also possible to configure different marks for in- and outbound traffic using _ikey/okey <mark>_, but that is usually not required.
28 1 Tobias Brunner
29 1 Tobias Brunner
After creating the device it has to be enabled (@ip link set <name> up@) and then routes may be installed (routing protocols may also be used).  To avoid duplicate policy lookups it is also recommended to set @sysctl -w net.ipv4.conf.<name>.disable_policy=1@. All of this also works for IPv6.
30 1 Tobias Brunner
31 1 Tobias Brunner
{{collapse(Examples)
32 1 Tobias Brunner
<pre>
33 1 Tobias Brunner
ip tunnel add vti0   local 192.168.0.1 remote 192.168.0.2 mode vti key 42
34 1 Tobias Brunner
ip tunnel add ipsec0 local 192.168.0.1 remote 192.168.0.2 mode vti key 0x01000201
35 1 Tobias Brunner
sysctl -w net.ipv4.conf.vti0.disable_policy=1
36 1 Tobias Brunner
ip link set vti0 up
37 1 Tobias Brunner
ip route add 10.1.0.0/16 dev vti0
38 1 Tobias Brunner
sysctl -w net.ipv4.conf.ipsec0.disable_policy=1
39 1 Tobias Brunner
ip link set ipsec0 up
40 1 Tobias Brunner
ip route add 10.2.0.0/16 dev ipsec0
41 1 Tobias Brunner
ip route add 10.3.0.0/16 dev ipsec0
42 1 Tobias Brunner
</pre>
43 1 Tobias Brunner
}}
44 1 Tobias Brunner
45 1 Tobias Brunner
Statistics on VTI devices may be displayed with @ip -s tunnel show [<name>]@. Note that specifying a name will not show any statistics if the device name starts with _vti_.
46 1 Tobias Brunner
47 1 Tobias Brunner
A VTI device may be removed again with @ip tunnel del <name>@.
48 1 Tobias Brunner
49 1 Tobias Brunner
h3. Configuration
50 1 Tobias Brunner
51 1 Tobias Brunner
To avoid that routes installed by the IKE daemon cause conflicts disable route installation with _charon.install_routes=0_ in [[strongswan.conf]].
52 1 Tobias Brunner
53 1 Tobias Brunner
Then configure a regular site-to-site connection either with the traffic selectors set to _0.0.0.0/0_ on both ends (_local|remote_ts=0.0.0.0.0/0_ in [[swanctl.conf]] or _left|rightsubnet=0.0.0.0/0_ in [[ipsec.conf]]) or set to specific subnets. As mentioned above, only traffic that matches these traffic selectors will then actually be forwarded, other packets will be rejected with an ICMP error message (_destination unreachable/destination host unreachable_).
54 1 Tobias Brunner
55 1 Tobias Brunner
The most important configuration option is the mark (_mark_in|out_ in [[swanctl.conf]], _mark_ in [[ipsec.conf]]). After applying the optional mask (default is _0xffffffff_) to the mark set on the VTI device, and applied by it to the routed packets, the value has to match the configured mark.
56 1 Tobias Brunner
So referring to the example above, to match the mark on _vti0_ configure _mark_in_ = _mark_out_ = _42_ and to match the mark on _ipsec0_ set the value to _0x01000201_ (but something like _0x00000001/0x0000000f_ would also work).
57 1 Tobias Brunner
58 1 Tobias Brunner
h3. Sharing VTI Devices
59 1 Tobias Brunner
60 1 Tobias Brunner
VTI devices may be shared by multiple IPsec SAs (e.g. in roadwarrior scenarios, to capture traffic or lower the MTU) by setting the remote endpoint of the VTI device to 0.0.0.0. For instance:
61 1 Tobias Brunner
62 1 Tobias Brunner
<pre>
63 1 Tobias Brunner
ip tunnel add ipsec0 local 192.168.0.1 remote 0.0.0.0 mode vti key 42
64 1 Tobias Brunner
</pre>
65 1 Tobias Brunner
66 1 Tobias Brunner
Then assuming [[VirtualIP|virtual IPs]] for roadwarriors are assigned from the _10.0.1.0/24_ subnet a matching route may be installed with @ip route add 10.0.1.0/24 dev ipsec0@.
67 1 Tobias Brunner
68 1 Tobias Brunner
h3. Connection-specific VTI Devices
69 1 Tobias Brunner
70 1 Tobias Brunner
With a custom [[updown]] script it is also possible to setup connection-specific VTI devices.
71 1 Tobias Brunner
72 1 Tobias Brunner
For instance, to create a VTI device on a roadwarrrior client that receives a [[VirtualIP|dynamic virtual IP]] (courtesy of Endre Szab├│):
73 1 Tobias Brunner
74 1 Tobias Brunner
{{collapse(Example Script)
75 1 Tobias Brunner
<pre>
76 1 Tobias Brunner
#!/bin/bash
77 1 Tobias Brunner
78 1 Tobias Brunner
# set charon.install_virtual_ip = no to prevent the daemon from also installing the VIP
79 1 Tobias Brunner
80 1 Tobias Brunner
set -o nounset
81 1 Tobias Brunner
set -o errexit
82 1 Tobias Brunner
83 1 Tobias Brunner
VTI_IF="vti${PLUTO_UNIQUEID}"
84 1 Tobias Brunner
85 1 Tobias Brunner
case "${PLUTO_VERB}" in
86 1 Tobias Brunner
    up-client)
87 1 Tobias Brunner
        ip tunnel add "${VTI_IF}" local "${PLUTO_ME}" remote "${PLUTO_PEER}" mode vti \
88 1 Tobias Brunner
            okey "${PLUTO_MARK_OUT%%/*}" ikey "${PLUTO_MARK_IN%%/*}"
89 1 Tobias Brunner
        ip link set "${VTI_IF}" up
90 1 Tobias Brunner
        ip addr add "${PLUTO_MY_SOURCEIP}" dev "${VTI_IF}"
91 1 Tobias Brunner
        ip route add "${PLUTO_PEER_CLIENT}" dev "${VTI_IF}"
92 1 Tobias Brunner
        sysctl -w "net.ipv4.conf.${VTI_IF}.disable_policy=1"
93 1 Tobias Brunner
        ;;
94 1 Tobias Brunner
    down-client)
95 1 Tobias Brunner
        ip tunnel del "${VTI_IF}"
96 1 Tobias Brunner
        ;;
97 1 Tobias Brunner
esac
98 1 Tobias Brunner
</pre>
99 1 Tobias Brunner
}}
100 1 Tobias Brunner
101 1 Tobias Brunner
If there is more than one subnet in the remote traffic selector this might cause conflicts as the _updown_ script will be called for each combination of local and remote subnet.
102 1 Tobias Brunner
103 1 Tobias Brunner
h2. Marks on Linux
104 1 Tobias Brunner
105 1 Tobias Brunner
One of the core features of VTI devices, dynamically specifying which traffic to tunnel, can actually be replicated directly with marks and firewall rules. By configuring connections with marks and then selectively marking packets directly with Netfilter rules via @MARK@ target in the @PREROUTING@ or @FORWARD@ only specific traffic will get tunneled.
106 1 Tobias Brunner
107 1 Tobias Brunner
This may also be used to create multiple identical tunnels for which firewall rules  dynamically decide which traffic is tunneled though which IPsec SA (e.g. for {{tc(ikev2/net2net-psk-dscp, QoS/DiffServ)}}).
108 1 Tobias Brunner
109 1 Tobias Brunner
h2. GRE
110 1 Tobias Brunner
111 1 Tobias Brunner
An alternative to VTI devices is using GRE(Generic Routing Encapsulation), which is a generic point-to-point tunneling protocol that adds an additional encapsulation layer (at least 4 bytes).  But it provides a portable way of creating route-based VPNs (running a routing protocol on-top is also easy).
112 1 Tobias Brunner
113 1 Tobias Brunner
While VTI devices depend on site-to-site IPsec connections in tunnel mode, GRE uses a host-to-host connection that can also be run in transport mode (avoiding additional overhead). But while VTI devices may be used by only one of the hosts, GRE must be used by both of them.
114 1 Tobias Brunner
115 1 Tobias Brunner
Creating a GRE tunnel on Linux can be done as follows:
116 1 Tobias Brunner
117 1 Tobias Brunner
<pre>
118 1 Tobias Brunner
ip tunnel add <name> local <local IP> remote <remote IP> mode gre
119 1 Tobias Brunner
</pre>
120 1 Tobias Brunner
121 1 Tobias Brunner
<name> can be any valid interface name (e.g. _ipsec0_, _gre0_ etc.). But note that the @ip@ command treats names starting with _gre_ special in some instances (e.g. when retrieving device statistics). The IPs are the endpoints of the IPsec tunnel.
122 1 Tobias Brunner
123 1 Tobias Brunner
After creating the device it has to be enabled (@ip link set <name> up@) and then routes may be installed.
124 1 Tobias Brunner
125 1 Tobias Brunner
{{collapse(Example)
126 1 Tobias Brunner
<pre>
127 1 Tobias Brunner
ip tunnel add ipsec0 local 192.168.0.1 remote 192.168.0.2 mode gre
128 1 Tobias Brunner
ip link set ipsec0 up
129 1 Tobias Brunner
ip route add 10.1.0.0/16 dev ipsec0
130 1 Tobias Brunner
ip route add 10.2.0.0/16 dev ipsec0
131 1 Tobias Brunner
</pre>
132 1 Tobias Brunner
}}
133 1 Tobias Brunner
134 1 Tobias Brunner
Statistics on GRE devices may be displayed with @ip -s tunnel show [<name>]@. Note that specifying a name will not show any statistics if the device name starts with _gre_.
135 1 Tobias Brunner
136 1 Tobias Brunner
A GRE device may be removed again with @ip tunnel del <name>@.
137 1 Tobias Brunner
138 1 Tobias Brunner
h3. Configuration
139 1 Tobias Brunner
140 1 Tobias Brunner
As mentioned above, a host-to-host IPsec connection in transport mode can be used. The traffic selectors may even be limited to just the GRE protocol (_local|remote_ts=dynamic[gre]_ in [[swanctl.conf]] or _left|rightsubnet=%dynamic[gre]_ in [[ipsec.conf]]).
141 1 Tobias Brunner
142 1 Tobias Brunner
h2. libipsec And TUN Devices
143 1 Tobias Brunner
144 1 Tobias Brunner
Based on our own userland IPsec implementation and the [[kernel-libipsec]] plugin it is possible to create route-based VPNs with TUN devices. Similar to VTI devices the negotiated IPsec policies have to match the traffic routed via TUN device.
145 1 Tobias Brunner
In particular because packets have to be copied between kernel and userland it is not as efficient as the solutions above (also read the notes on [[kernel-libipsec]]).
146 2 Noel Kuntze
147 2 Noel Kuntze
h2. Problems
148 2 Noel Kuntze
149 2 Noel Kuntze
Make sure to disable the [[connmark]] plugin when running the VTI. Otherwise, it will insert iptables rules into the @*mangle@ table that prevent the VTI from working.