OpenBSD IPsec Tunnel Guide

This guide will explain how to setup a site-to-site IPsec tunnel (i.e., tunnel mode IPsec) between two OpenBSD gateways. Throughout this document there are example configs shown, some of which contain secret key data. DO NOT use these example keys! Create your own (as shown) and keep them private.

Table of Contents

The Tools

OpenBSD ships with all the tools needed to begin using IPsec. OpenBSD does not require a kernel recompile, software installtion, 3rd-party modules or anything else to get IPsec up and running.

The following is a list of OpenBSD’s IPsec tool set.

The Internet Security Association and Key Management Protocol (ISAKMP) Daemon. This daemon is responsible for exchanging cryptographic keys and setting up security associations (SAs) with IPsec peers.
The ipsecctl(8) utility is used to create and delete the flows that determine which traffic is protected using IPsec. It’s also used as the primary method of configuring IPsec. It does this by reading its configuration file and then passing various commands to isakmpd(8) in order to establish the IPsec connection.
The /etc/ipsec.conf file is the configuration file for the ipsecctl(8) utility. The flows and security associations that make up an IPsec connection are defined in this file using an easy-to-read syntax.
The security association synchronization daemon. This daemon synchronizes IPsec SAs and flows between redundant gateways.
The /etc/sasyncd.conf file is the configuration file for sasyncd(8).


Some of the terms and acronyms used when talking about IPsec are listed below.

Authentication Header (AH)
AH provides data integrity and origin authenticity of the payload. AH computes a hash using certain parts of the payload and sends the hash along with the packet payload. The receiver recomputes the hash and verifies it against the hash that it received in the packet to ensure that they match.
Encapsulating Security Payload (ESP)
ESP provides origin authenticity, integrity and confidentiality for the encapsulated IP packet. With ESP the payload of the IP packet is encrypted.
Internet Key Exchange (IKE)
IKE is the protocol that isakmpd(8) uses to setup Security Associations with IPsec peers.
Main Mode
When isakmpd(8) is negotiating with an IPsec peer using IKE, the first phase of the negotiation is called main mode. During main mode the two peers establish a secure channel which they then use to exchange the data needed to setup the security associations.
Quick Mode
When isakmpd(8) is negotiating with an IPsec peer using IKE, and after main mode has been completed, the two peers exchange the data necessary to setup the security associations. This exchange is called quick mode. Once the quick mode exchange is complete, data can flow across the IPsec connection.
Pre-Shared Key (PSK)
A secret key/password that is exchanged between two parties using some secure method. For example, generating a secret key and using SSH to upload they key to the IPsec gateways.
Security Association (SA)
A grouping of the security parameters that are used to protect the data sent over the IPsec connection. The parameters in the SA include key data and the encryption and hash algorithms. An SA controls traffic in one direction only. Two SAs are required on each gateway in order to achieve bidirectional IPsec traffic flow. SAs are established automatically by isakmpd(8) or can be created manually using ipsecctl(8).
Transport Mode
When an IPsec connection is run in transport mode only the payload of the original IP packet is encrypted. The packet header is left intact meaning the original destination address is used when routing the encrypted packet to its destination. Transport mode is used for host-to-host communication.
Tunnel Mode
When an IPsec connection is run in tunnel mode the entire original packet is encrypted. This encrypted packet is then encapsulated into a new IP packet. This new IP packet is routed to the remote IPsec peer. Tunnel mode is used for site-to-site (network-to-network) communication. Since the internal/site IP addresses are hidden inside the encrypted packet, these packets can be routed across public networks such as the Internet.

Building a Site-to-Site Tunnel

This scenario will describe building a site-to-site tunnel that’s used to connect two physically separate networks together over the public Internet. At each site is an OpenBSD gateway that will act as the endpoints for the IPsec connection. The end goal of this scenario is to enable full communication between the two networks.

Our sample topology:     .1        
  (Network 1) --- em0[OpenBSD gateway 1]em1 -----+
  (Network 2) --- em0[OpenBSD gateway 2]em1 -----+   .1        

Gather Information

Before anything can be configured we need to gather some basic information. We already have the necessary IP address information from the topology diagram above. We now need to define the IPsec parameters that will be used to build the connection.

Right off the bat we know that since we’re connecting two networks together using IPsec that we need to use tunnel mode. We also know that since we want to keep the transported data private (i.e., encrypted) that we need to use ESP as the transport protocol. Now we need to decide on the encryption and authentication types to use for main mode and quick mode. The easiest thing to do here is to not specify any encryption or authentication types and insead allow the default types to be used. Since both endpoints of the IPsec tunnel are OpenBSD and they both support the same set of encryption/authentication types, they will not have any difficulty negotiating with each other. For this exercise, a set of non-default types will be chosen in order to demonstrate how to configure them. The complete list of support enc/auth types is listed in the ipsec.conf(5) manpage in the “CRYPTO TRANSFORMS” section. For main mode we will use hmac-sha2-256 for authentication and blowfish for encryption. For quick mode we will use hmac-sha2-384 and blowfish.

Next we need to decide what method of authentication should be used between the gateways. To keep things simple, this example will use a pre-shared key (PSK). In order to ensure a strong PSK is used, we will use the openssl(1) utility to generate the key. We could just as easily pick our own PSK to use, however using OpenSSL ensures that 1) the PSK is random and not predictable and 2) that it’s sufficiently long enough that things like a brute-force attack are not feasible.

% openssl rand 20 | hexdump -e '20/1 "%02x"'

This command has generated a random 20 byte (160 bit) string and formatted it in hexadecimal. This key should be treated with care and kept secret at all times. A secure method of transport should be used when uploading the key to the gateways such as using SSH or entering the key from the console.

Here is a summary of the information we’ve decided upon:

Gateway 1 IP
Gateway 2 IP
Network 1
Network 2
Tunnel/Transport Mode
Tunnel Mode
Transport Protocol
Main Mode enc/auth
hmac-sha2-256, blowfish
Quick Mode enc/auth
hmac-sha2-384, blowfish
Authentication method
Pre-shared key
Pre-shared key

Creating the ipsec.conf(5) File

Now that we’ve defined all the configuration parameters we can begin configuring the tools. We’ll start with the /etc/ipsec.conf file. OpenBSD ships with a default ipsec.conf file that can be used as a starting point. We’re going to start with an empty file and configure everything from the ground up.

Since our intent is to have isakmpd(8) configure the flows and SAs automatically, we will define the IKE parameters in ipsec.conf. When ipsecctl(8) loads the config, it will instruct isakmpd to configure itself appropriately. The basic IKE configuration syntax is:

ike [mode] [encap] [tmode] \
 from src to dst \
 local localip peer remoteip \
 main auth algorithm enc algorithm \
 quick auth algorithm enc algorithm \
 psk key

These options are explained below.

Defines whether isakmpd will attempt to initiate the IPsec connection or whether it will wait for a connection request from the remote peer. Possible values are:

  • active – Tells isakmpd to initiate the IPsec connection. This is the default.
  • passive – Tells isakmpd to wait for a connection request.
  • dynamic – Tells isakmpd to initiate the IPsec connection and to enable Dead Peer Detection. This mode should be used when the remote peer has a dynamic IP address.
The transport protocol to use, either “esp” or “ah“.
Either “tunnel” or “transport” and indicates whether to enable tunnel mode or transport mode. The default is “tunnel“.
The IP address or subnet where the traffic to be protected is coming from. For a transport mode connection this will be the IP address of the local host. For a tunnel mode connection this will be the subnet and mask of the local network that should have its traffic sent through the IPsec tunnel.
The IP address or subnet where the protected traffic is being sent to. For a transport mode connection this will be the IP address of the remote host. For a tunnel mode connection this will be the subnet and mask of the remote network that will be reachable through the IPsec tunnel.
The IP address on the local machine where isakmpd should source the connection from. This option is generally not needed since isakmpd will choose the correct IP address automatically.
The IP address of the remote IPsec gateway.
The authentication or encryption algorithm to use during main mode and quick mode. The possible algorithms are documented in the ipsec.conf(5) man page under the “CRYPTO TRANSFORMS” section.
The pre-shared key.

Now that we have the syntax for creating the config file we can substitute our IPsec parameters from the table above into the file.

The ipsec.conf file on gateway 1:

ike esp from to \
 peer \
 main auth hmac-sha2-256 enc blowfish \
 quick auth hmac-sha2-384 enc blowfish \
 psk 204931646879ae1265a7d0437a51cc08fe8d7484

The ipsec.conf file on gateway 2:

ike esp from to \
 peer \
 main auth hmac-sha2-256 enc blowfish \
 quick auth hmac-sha2-384 enc blowfish \
 psk 204931646879ae1265a7d0437a51cc08fe8d7484

Note that even though we don’t specify the “active” or “tunnel” options they are the defaults and will be automatically applied by ipsecctl.

Starting isakmpd

Now that the ipsec.conf file is written we can tell ipsecctl(8) to load this config. When it does, it will instruct isakmpd to setup the IPsec connection based on the parameters we’ve specified. It’s then isakmpd’s job to create the SAs, setup the flows, and authenticate the peer.

To have isakmpd start when the system boots, edit the /etc/rc.conf.local file and add the following on a new line:


The -K option to isakmpd tells it not to load a keynote(4) policy. This option is necessary when using ipsecctl to control isakmpd.

You can start isakmpd from the shell by passing it the same flag:

# isakmpd -K

Now load the ipsec.conf file using ipsecctl:

# ipsecctl -f /etc/ipsec.conf

At this point ipsecctl will have communicated with isakmpd to tell it to establish the IPsec connection. To have ipsecctl run at system boot, add the following to /etc/rc.conf.local:


At this point isakmpd should be running and the ipsec.conf file should be loaded on both gateways.

After a short time the IPsec connection will be established. You can view the flows and SAs using ipsecctl.

gw1# ipsecctl -s all
flow esp in from to peer \
  srcid dstid type use
flow esp out from to peer \
  srcid dstid type use

esp tunnel from to spi 0x... \ 
  auth hmac-sha2-384 enc blowfish \
  authkey 0x... \
  enckey 0x...
esp tunnel from to spi 0x... \
  auth hmac-sha2-384 enc blowfish \
  authkey 0x... \
  enckey 0x...

We can see here on gateway #1 two flows have been established, one in each direction. Underneath that are the entries in the security association database (SAD). Like the flows, there is an SA in each direction. The “0x…” indicates values that will be unique for each SA. If the IPsec connection is not established then the output above will only show the flows and not the SAs.

Assuming you can see the flows and SAs then the connection is ready to pass traffic.

Allowing IPsec Traffic Through pf(4)

Since most OpenBSD gateways will be running pf(4), it’s necessary to add some explicit rules to allow IPsec traffic to and from the remote gateway. Two types of traffic need to be permitted between gateways:

  1. UDP traffic on ports 500 and 4500. These are the ports that isakmpd uses to communicate.
  2. ESP or AH packets (depending which one the IPsec connection is using).

These rules can be used on gateway #1 to achieve this.

ipsec_peer = ""
ext_if = "em1"

pass in on $ext_if proto udp from $ipsec_peer \
 to ($ext_if) port { 500 4500 }
pass out on $ext_if proto udp from $ext_if \
 to $ipsec_peer port { 500 4500 }

pass in on $ext_if proto esp from $ipsec_peer to ($ext_if)
pass out on $ext_if proto esp from $ext_if to $ipsec_peer

These rules would need to be integrated into the existing rules on gateway #1 and a similar set of rules would need to be integrated on gateway #2.

Filtering Traffic on the Tunnel

The previous section talked about filtering IPsec traffic to and from the gateway. Now we’ll look at how to filter user traffic that crosses the IPsec tunnel.

Filtering on enc0

Each OpenBSD gateway has a virtual enc(4) interface. This interface receives an unencrypted copy of all traffic sent and received on all IPsec connections. By using pf(4) to filter traffic on this interface we can control the types of traffic permitted on the tunnel.

The simplest filter is of course to allow all traffic inbound and outbound. This can be achieved using the “set skip” option.

set skip on enc0

Of course much more fine-grained control can be applied as well. Let’s assume in our sample topology that we only want to allow users on network #1 to be able to access a specific web server located on network #2. Users on network #2 should not be able to access any resources on network #1. By applying some filter rules to the enc0 interface on gateway #1 we can achieve this policy:

ext_if = "em1"
int_if = "em0"
ipsec_peer = ""
www_server = ""
www_ports = "{ 80 443 }"

block on enc0

pass in on enc0 proto ipencap from $ipsec_peer to ($ext_if) \
 keep state (if-bound)

pass out on enc0 proto tcp from $int_if:network to $www_server \
 port $www_ports keep state (if-bound)

Two items need special attention here.

  • Passing ipencap traffic: Because of how the OpenBSD IP stack works, incoming tunnel mode traffic must be explicity permitted by passing packets of protocol type “ipencap”. A corresponding outbound rule is not necessary because the stack handles outbound tunnel mode packets slightly differently. Care should be taken to only allow ipencap traffic from the specific hosts that we have IPsec connections with. If the remote IPsec peer has a dynamic IP address this obviously won’t be possible and the above filter rule would have to be modified to not filter on source IP address. If the IPsec connection is using transport mode then this rule is not needed.
  • Interface-bound state entries: Filter rules that permit user traffic over the tunnel should specify the “if-bound” state option. Without this option, if the IPsec connection is down (for example, if the remote gateway is offline) then users’ traffic will be routed using the normal routing table which would result in this traffic being sent over the public Internet. Using “if-bound” ensures that this traffic will only be permitted across the enc0 interface and therefore only across the IPsec tunnel. Care should also be taken when writing filter rules that permit regular user traffic to and from the Internet. Ensure that these rules do not inadvertantly allow private traffic to leak to the Internet when the IPsec connection is down.

Filtering using pf Tags

A pf tag is an internal identifier that can be attached to a packet as it enters an OpenBSD host. The tag can then be used as filter criteria by pf. See the Packet Tagging section of the PF User’s Guide for more details on tagging. The isakmpd daemon is capable of applying pf tags to incoming IPsec packets.

In order to apply a tag to an IPsec connection it must specified in the ipsec.conf file using the “tag” keyword. Taking our existing ipsec.conf file from gateway #2, we simply add the tag to the end:

ike esp from to \
 peer \
 main auth hmac-sha2-256 enc blowfish \
 quick auth hmac-sha2-384 enc blowfish \
 psk 204931646879ae1265a7d0437a51cc08fe8d7484 \
 tag net1-to-net2

In this case the arbitrary string “net1-to-net2” was chosen as the tag. All incoming IPsec packets belonging to this connection will be tagged with “net1-to-net2”. We can now incorporate this tag into the pf filter rules on gateway #2. Since we know from the previous section that we only want to allow users on network #1 to access a specific web server on network #2, we can apply this policy on gateway #2 by using the pf tag:

ext_if = "em1"
int_if = "em0"
ipsec_peer = ""
www_server = ""
www_ports = "{ 80 443 }"

block on enc0

pass in on enc0 proto ipencap from $ipsec_peer to ($ext_if) \
 keep state (if-bound)

pass in on enc0 keep state (if-bound) tagged net1-to-net2

pass out on $int_if proto tcp to $www_server port $www_ports \
 keep state (if-bound) tagged net1-to-net2

This example ruleset allows users on network #1 to access the web server on network #2 by matching on the pf tag that’s being applied to packets by isakmpd. An additional rule is added on $int_if to demonstrate how filtering on the tag and on IP address and port can be combined.

Filtering Traffic Using IKE Policy

The last way of filtering traffic is by using the IKE policy to limit what kind of traffic will be encapsulated and sent across the tunnel. Within the ipsec.conf file it’s possible to define the IP protocol and TCP/UDP ports to allow traffic to and from. Continuing with our example of only allowing network #1 to reach a web server on network #2, we could adjust the ipsec.conf file on gateway #1 to read:

ike esp proto tcp from to port 80 \
 peer \
 main auth hmac-sha2-256 enc blowfish \
 quick auth hmac-sha2-384 enc blowfish \
 psk 204931646879ae1265a7d0437a51cc08fe8d7484

When this ipsec.conf is loaded by ipsecctl, it will setup a flow between and for TCP port 80 only. Similar changes should be made on gateway #2.

There’s one thing we’re missing now though. In the previous filtering methods we allowed port 443 traffic to reach the web server in addition to port 80. How do we allow more than one port (or protocol) using this method? The answer is create a second IKE policy that specifes port 443:

ike esp proto tcp from to port 443 \
 peer \
 main auth hmac-sha2-256 enc blowfish \
 quick auth hmac-sha2-384 enc blowfish \
 psk 204931646879ae1265a7d0437a51cc08fe8d7484

A matching policy needs to be created on gateway #2.

Adding Redundancy

OpenBSD has built-in support for deploying redundant IPsec gateways. Synchronization of SAs and flows is handled by the sasyncd(8) daemon. This daemon is most often used in conjunction with carp(4). By enabling CARP on the redundant gateways they able to share a common external IP address. Configuring all IPsec connections to use this shared IP address allows the connections to failover between the redundant gateways.

We’ll modify our example topology to include a set of two redundant gateways connected to network #1.     .2  
  (Network 1) --- em0[OpenBSD gateway 1a]em1 --------+
           |    .1 carp1          carp2  |
           +----- em0[OpenBSD gateway 1b]em1 -+      |
                   .3    |      |
                                              |      |
  (Network 2) --- em0[OpenBSD gateway 2]em1 -----+   .1        

Network #1 now has two gateways: gateway #1a and #1b. These gateways are running CARP on their internal and external interfaces.

  • Internal: carp1,
  • External: carp2,

The general operation and configuration of CARP is covered in FAQ6: The Common Address Redundancy Protocol and in the PF User’s Guide Firewall Redundancy with CARP and pfsync.

The ipsec.conf file used on gateway #1a and #1b is mostly the same as in the earlier sections. The only thing that needs changing is to add the “local” keyword which tells isakmpd which IP address to bind to. Without this option, isakmpd would automatically use the IP address assigned to the physical em0 interface.

ike esp from to \
 local peer \
 main auth hmac-sha2-256 enc blowfish \
 quick auth hmac-sha2-384 enc blowfish \
 psk 204931646879ae1265a7d0437a51cc08fe8d7484

By telling isakmpd to use the shared CARP IP address we ensure that traffic will continue to flow when the gateways failover. Likewise on gateway #2, the ipsec.conf file should be changed so that the “peer” IP is set to the external CARP IP,

The next bit of redundancy needed is for the IPsec SAs and flows. This is handled by sasyncd(8). We’ll use a very basic sasyncd.conf file with these options:

The name of the CARP interface to track. When this interface is in “master” state then sasyncd will know the gateway is the current master.
The IP address of the other gateway. This is the address that synchronization messages will be sent to.
A pre-shared key used for encrypting updates sent between gateways.

The sasyncd.conf file on gateway #1a looks like:

# track the external carp interface
interface carp2
# address of gateway #1b
# 256 bit shared key
sharedkey da23169c9f49bb1fcdfab7d5565889754331b3f831b3723d273a06e9d780f2cc

To start sasyncd on system boot, add a line to /etc/rc.conf.local:


Check your pf.conf ruleset to ensure that traffic between the internal interfaces of gateway #1a and #1b on TCP port 500 is permitted. This is the port that sasyncd will use.

One last thing to do and that is, if isakmpd is already running on gateway #1a or #1b, kill it and restart it by adding the -S flag to its startup options. This option tells isakmpd not to delete SAs when it’s killed. The system startup scripts will automatically add the -S option when sasyncd is enabled.

At this point the tunnel should be up between the active gateway and gateway #2. Traffic should be flowing as before. On gateway #1b (the standby gateway), you should be able to see the IPsec SAs and flows which are being synchronized from gateway #1a using the ipsecctl -s all command.

Once the SAs are synchronized it should be possible to fail over between gateway #1a and #1b without disruption to the IPsec connection.


Some troubleshooting steps in case things aren’t working correctly.

Startup Order is Important

When OpenBSD boots, the rc(8) startup script runs the various IPsec tools in the correct order to ensure that everything works as it should (assuming of course that all the correct tools are enabled in /etc/rc.conf.local). If you’re starting the tools by hand from the command line, do so in this order:

  1. Run isakmpd with the -K and -S flags
  2. Load the /etc/ipsec.conf file with ipsecctl
  3. Run sasyncd

32 thoughts on “OpenBSD IPsec Tunnel Guide”

  1. joel im a openbsd fan and i have a question do u have configured openbsd as a vpn server in order to recive coneccionts from Cisco SRST 881

    1. Hi,

      I haven’t configured an 881 specifically, but have configured OpenBSD to terminate tunnels from other IOS devices and ASA. As long as you stick with configuration options that are common to both endpoints you should be fine.

  2. joel cg here again i have just try u example it seem im not getting the idea despite i have read all the ipsec man pages but i have question:
    1.- it is necesary that i set up routes to the protected networks?
    2.- i have this configuration
    ————– same
    any idea how to drive the dinamic ip client connection?

    1. Hi cg, you do not need routes to the protected networks. When the SAs are established, they will direct traffic through the tunnel without relying on explicit routes in the FIB. Dynamic IPs are an issue only because you generally need at least one side of the connection to be fixed. If you have dynamic IPs at your headend site you’re in for some hardship when your IP changes. However for testing, you should be able to bring up the tunnels and get everything going just fine.

      1. ok joel im having a hard time to configure this i have done tunnels but if i dont use the route commands it just does not ping between hosts over the private networks i have tried several configurations and your example too but nothing i will post u the info if u want to help me out this is the one that im using with pubkeys

        SITE A
        ike esp from $local_network to $remote_network peer $remote_ip
        ike esp from $local_ip to $remote_ip

        SITE B

        ike passive esp from $local_network to $remote_network peer \
        ike passive esp from $local_ip to $remote_ip
        the two sites need the route command to ping each other

        1. Hi cg, when you add the routes, are you certain the traffic is flowing over the tunnel and not being routed normally by the gateways? Could you use and paste your pf.conf, the route commands you’re using and output of ipsecctl -vvsa

          1. joel solved i think that the problem was either that the vpn hosts ware on the same lan and the same switch or i just fail in some configuration any way that was just a test bed so when i put the configuration over the VPN server and configure a client tunnel over adsl connection all work ok no need to add route commands as u say here is my configuration 4 my road warriors
            ike passive esp from any to $local_network peer any psk silent
            ike passive esp from $local_net to any psk silent
            ike passive esp from any to $local_ip psk silent
            ike passive esp from $local_ip to any psk silent

            thanks a lot 4 ur interest i hope some day i can help u the cisco will no be handed by me well thats what i think have a nice day dude

              1. Joel hi cg here again dude im now with the problem that i cant connect a peer cisco 800 series i have already ask u about this im not configuring the cisco peer the guy that its configuring the cisco peer but he says that the phase 1 works ok but the phase 2 no he send me all the configurations an erro messages can u help ?
                best regards!

                1. Hi,

                  If you have the configuration from his end then it shouldn’t be too hard to pick out where the differences are between his config and yours. If that fails, why don’t you turn on verbose debugging (isakmpd -v) and have him turn on the same with “debug crypto isakmp”. Carefully review the logs and look for whatever is causing the connection to fail. Good luck.

                    1. joel sorry to ask you so many things but they are asking me to set up the tunnel and reach 3 networks i have never done that don t know if i have to do the configuration on flows over the ipsec or if i have to do it on the routes

  3. Hi CG,

    I’ve helped you all I can at this point. You’ll have to do your best to understand the theory and work on the configuration yourself. Good luck!

  4. Great article! Have you ever setup OpenBSD as a road warrior VPN gateway? I would like to do this but have the ability to assign each road warrior a unique pre-shared key. That way if we have to let someone go, we don’t have to change the key for everyone. I know it cannot be done with ipsec.conf but it looks possible to do it with isakmpd.conf. An example with 2 or more road warriors would be great. Thank you in advance.

    1. Hi Matt, thanks for the comments.

      You’d be interested in this snippit from the isakmpd.conf(5) man page:

      “During phase 1 negotiation isakmpd(8) looks for a pre-shared key in the section. If no Authentication data is specified in that section, and isakmpd(8) is not the initiator, it looks for Authentication data in a section named after the initiator’s phase 1 ID. This allows mobile users with dynamic IP addresses to have different shared secrets.”

      So if your remote endpoints configure their phase 1 ID as “”, in your isakmpd.conf you’d have something like:


      (… and so on for each user)

      Also check out the “Passive-connections” options for the [Phase 2] section which is necessary in a road warrior setup.

  5. Well this certainly helped me quite a bit. Got one tunnel running 100% but with a second tunnel, I get the tunnel up(SAs are up and running) but I can’t route traffic through.

    set skip on enc0
    match out on enc0 from to {,} nat-to source-hash
    pass in on enc0 from {,} to keep state (if-bound) tagged VPN2
    pass out on enc0 from to {,} keep state (if-bound) tagged VPN2


    ike esp from ( to {,} \
    local $ts_local_ip peer $ts_remote_ip \
    main auth $ts_auth_algo enc $ts_enc_algo group $ts_grp \
    quick auth $ts_auth_algo enc $ts_enc_algo group $ts_grp \
    psk “key” \
    tag “VPN2”

    route -n show:
    192.168.27/24 0 10.10.0/24 0 0 remote_peer/esp/use/in
    10.10.0/24 0 192.168.27/24 0 0 remote_peer/esp/require/out
    192.168.28/24 0 10.10.0/24 0 0 remote_peer/esp/use/in
    10.10.0/24 0 192.168.28/24 0 0 remote_peer/esp/require/out

    A tcp dump of me trying to reach a host on the other end:
    78:ac:c0:b4:dc:0a 00:22:4d:7b:b2:a9 0800 74: > S 1039626623:1039626623(0) win 14600 (DF)
    78:ac:c0:b4:dc:0a 00:22:4d:7b:b2:a9 0800 74: > S 1039626623:1039626623(0) win 14600 (DF)

    I just don’t get what’s wrong. The other end of the tunnel I was told isn’t getting any of my traffic at all.

  6. Any suggestions on situations where this is up and running (I’m using the Shrewsoft VPN client), but am not able to communicate with the internal network? I’m able to communicate only with the VPN server / firewall (OpenBSD 5.1), and do so using the internal address (192.168.1.x), but am unable to get to anything else on the 192.168.1.x/24 network.

    I watch the internal interface in tcpdump for a while, and saw lots of name server queries going through to my nameserver, but no responses.

    I use ‘set skip on enc0’ in my pf.conf file to get it working so I can fine tune it later (and know which rules break things and which don’t).

    1. Hi Scott. To me that sounds like your pf policy is not permitting traffic from your remote IP space to the local LAN at the head end.

      1. Thanks Joel. I am thinking the same thing, but (I’m admitted no PF expert), was under the impression using the entry ‘set skip on enc0’ would essentially make PF pass anything (although I could be wrong).

        1. Ah, ok. The enc0 interface allows for filtering/visibility into the traffic inside the IPsec tunnel. That same traffic will still cross your inside interface on the firewall and requires its own set of filter rules. Don’t forget to also allow traffic “in” on that interface so it can cross the firewall into the tunnel and reach the far end.

  7. Have you ever bonded two X509 full PKI OpenVPN connections together? Example, mobile users have vpn to connect to enterprise openbsd box which then forwards all outgoing traffic through another vpn, essentially a double hop vpn. I suspect this can be accomplished with the routing table

    1. Hi. I have not but it sounds plausible. What’s the use case? Could the end host not connect directly to the second VPN hop?

  8. Hello and thanks for the great article! If you have a moment, I would appreciate some help. I have a local OpenBSD machine that I am trying to connect to a free VPN service. I don’t use my machine as a router for now. Actually, it sits behind the standard ISP home NAT-router/firewall setup. My configurations are as follows:

    ext_if = “re0”
    local_ip = “”
    local_network = “”
    remote_gw = “”
    remote_network = “”

    ike esp from $ext_if to $remote_gw1
    ike passive esp from $ext_if to $remote_network peer $remote_gw1
    ike esp from $local_network to $remote_network peer $remote_gw1
    psk vpn # username is vpn, password is vpn, and pre-shared key is vpn

    I cannot progress beyond the following:
    ipsecctl -f /etc/ipsec.conf
    ipsecctl: /etc/ipsec.conf: group writable or world read/writable
    ipsecctl: Syntax error in config file: ipsec rules not loaded

    Please, could you share some insight?

    Many thanks in advance!

    1. Hi Jemo, and thank you.

      You’re getting two error messages when you run ipsecctl. Let’s look at them individually.

      ipsecctl: /etc/ipsec.conf: group writable or world read/writable

      This one indicates a problem with the permissions on the file. It’s saying that the file should not be group writable and should not be world (“other’) readable or writable. If you correct the file’s permissions, this error will go away.

      ipsecctl: Syntax error in config file: ipsec rules not loaded

      This one indicates there’s a syntax error in your file. Something is wrong with the configuration lines you’ve entered. I notice that you entered your macros in one file (macros.conf) and your rules in another (ipsec.conf). How are you linking those files together? You’re telling ipsecctl to load ipsec.conf but how does it know to also look at macros.conf? Hint: there’s a line missing in your ipsec.conf which links the two together.

  9. Hi Jeol

    I need your help establishing the ipsec tunnel between two osbd servers. Here is the ipsec and iked.conf files


    I can also share the PF from both end, WIll you be able to help me getting the tunnel up or just suggest how can I run this in debug mode to reach route cause? If I run ISAKMPD in vervose mode then it says something like this

    “virtual_init: could not bind the ISAKMP port(s) on all interfaces: Address already in use”
    ” isakmpd[1434]: policy_init: open (“/etc/isakmpd/isakmpd.policy”, O_RDONLY) failed: No such file or directory”

    Thanks in advance for help.

    1. Hi Ashok,

      I edited your comment so that it doesn’t include your configuration. You included your public IP addresses and PSKs. Don’t ever do this. You gotta keep your keys private at all times. If the keys are shared with anyone, the security of your VPN is compromised.

      Ok, with that out of the way :)… This error: “isakmpd[1434]: policy_init: open (“/etc/isakmpd/isakmpd.policy”, O_RDONLY) failed: No such file or directory” indicates you have not created the isakmpd.policy file. How are you starting isakmpd? Are you passing the -K argument? -K tells isakmpd to _not_ load the policy file and this is usually what you want.

      This error: “virtual_init: could not bind the ISAKMP port(s) on all interfaces: Address already in use” indicates perhaps isakmpd is already running. Or, if isakmpd isn’t running, some other daemon is listening on UDP/500 and/or UDP/4500. Most likely isakmpd is probably running (possibly from your startup scripts?)

      1. Thanks for the reply Joel, WHat else can I check, while following is happening.

        1. I am able to ping both end public ips from each other.
        2 Pf.conf configured at both ends
        3. Ipsec.conf configured at both ends
        4. Iked.conf configured at both ends.
        5. One end is working with sasyncd hence there is no entry in /etc/isakmpd/isakmpd.conf while other end working as standalone server has entry for its public facing interface. (Please correct me if there should be an entry on server with sasyncd)
        6. Sysctl parameters are ok when compared with any online resource of Open BSD.

        What else can I check to make sure tunnel are established. M I missing something? I think I should make a simple step by step guide for Ipsec S-2-S tunnel once it is working fine.

        1. Well…. what did you find when you checked for other instances of isakmpd and for how you were starting isakmpd? Did you fix those issues? What happens now?

          Why are you configuring both ipsec.conf and iked.conf? And why are you editing isakmpd.conf and ipsec.conf?

          You might need to go find a basic instruction guide and start your configs from the basics and then build it up.

Leave a Reply

Your email address will not be published. Required fields are marked *

Would you like to subscribe to email notification of new comments? You can also subscribe without commenting.

Networking. Unix. Cyber Security. Code. Protocols. System Design. My Blog.