IPsec is a standard VPN technology that is supported by all major systems and does not require a separate client installation. However, IPsec has a lot of concepts and is very complicated to configure. After a lot of tossing and turning, I finally figured out an easy configuration method based on strongSwan, which supports iOS and macOS dial-in.

The server is ubuntu 22.04, first install strongSwan related components.

1
sudo aptitude install strongswan strongswan-swanctl

The command to start the strongSwan service is as follows.

1
sudo systemctl start strongswan-starter.service

The service name is strongswan-starter, which is different from the old system.

Then you need to add the configuration. Unlike other sources on the web, this time we use the latest swanctl configuration for strongSwan, which is configured in /etc/swanctl/.

First create /etc/swanctl/conf.d/foo.conf with the following structure.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
connections {
  foo {
    local_addrs = X.X.X.X
    local {}
    remote {}
    children {}
    version = 2
  }
}
secrets {}
pools {}

Multiple configurations can be added under connections, each specifying a name. For each connection, we need to specify the following configuration.

  • local_addrs is the public IP address of the server
  • local is the authentication information of the server
  • remote is the authentication information of the client
  • children configures the network information of the client and server
  • version specifies the IKE version number

Most of the information found on the Internet uses certificates to authenticate the dual-ended identity, which is the most secure way, but also the most cumbersome in terms of configuration and usage. We can use PSK mode to simplify the configuration.

So PSK is Pre-Share Key, where both ends share a key in advance. Compared to the certificate method, PSK is simpler, but less secure. So don’t use a simple PSK key. It is recommended to use openssl to generate random keys automatically.

1
2
$ openssl rand -hex 32
9817df17e110d120b7470026cfdb700b91b375cc33cbee66260125f23f3cbe8b

In addition to generating a shared key, the PSK must also specify an ID for each key, so the local and remote configurations are as follows.

1
2
3
4
5
6
7
local {
  auth = psk
  id = bob
}
remote {
  auth = psk
}

Here the server PSK identifier is specified as bob, which can be chosen at random. The client also specifies to use PSK authentication, but the user information needs to be added in secrets as follows.

1
2
3
4
5
6
secrets {
  ike-tom {
    id = tom
    secret = "..."
  }
}

The secret in the configuration is also available in various formats. The one with double quotes means no processing is needed, “foo” means foo, and the one without double quotes has two types: one with 0x means a hexadecimal string, and one with 0l means a base64 string. But I tested and found that iOS/macOS does not support the latter two.

The above completes the authentication part of the configuration, and the following configures the network part.

First, we need to automatically assign IP addresses to the clients. To do this, first add the client network segment to the pools.

1
2
3
4
5
pools {
  rw_pool {
    addrs = 10.9.8.0/24
  }
}

rw_pool is the configuration name, which can be arbitrary. Once you have a network segment, you need to specify which segment you want to use in the connection configuration.

1
2
3
4
5
6
connections {
  foo {
    pools = rw_pool
    # ...
  }
}

The last thing is to allow incoming client traffic, which requires configuring the children parameter.

1
2
3
4
5
6
children {
  bar {
    local_ts = 0.0.0.0/0
    remote_ts = 10.9.8.0/24
  }
}

We can think of children as simply routing tables or firewall rules. From the client’s point of view, local_ts represents the target segment and remote_ts represents the source segment. bar This configuration means that devices in the 10.9.8.0/24 network segment are allowed to access any network address. This means that the VPN server is relaying all network traffic for the client. We can also set local_ts to limit the resources that the client can access according to the actual situation.

Here all the configurations are finished 😄 Isn’t it easy. The complete configuration is as follows.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
connections {
  foo {
    version = 2
    local_addrs = X.X.X.X
    local {
      auth = psk
      id = bob
    }
    remote {
      auth = psk
    }
    children {
      bar {
        local_ts = 0.0.0.0/0
        remote_ts = 10.9.8.0/24
      }
    }
    pools = rw_pool
  }
}
secrets {
  ike-tom {
    id = tom
    secret = "..."
  }
}
pools {
  rw_pool {
    addrs = 10.9.8.0/24
  }
}

We need to load the configuration using swanctl.

1
swanctl --load-all

Add VPN configuration on iOS, select IKEv4 as the type. fill in the server IP address. Select none for user, no certificate, and fill in the secret in secrets.

This will allow you to access the VPN remotely. After dialing in successfully, you will find that you cannot access the network normally. After debugging, I found two problems.

The first is that the server is not pushing the DNS configuration.

iOS does not support specifying DNS, and macOS does not work, although you can specify it. The easiest way to do this is to have strongSwan automatically drop it. This requires modifying /etc/strongswan.conf.

1
2
3
4
charon {
  dns1 = 8.8.8.8
  # ...
}

After modifying the configuration, you need to restart strongswan-starter and then call swanctl to load the configuration.

Second, the server needs to be NAT enabled.

1
iptables -t nat -A POSTROUTING -o eth0 -j MASQUERADE

Here eth0 is the name of the NIC that the server can access to the external network, please adjust it as needed.

After solving these two problems, the client can access the external network through server-side forwarding 🎉 This is all in this article.

The advantage of IPsec VPN is that it is standardized and supported by all mainstream systems. But the disadvantage is also obvious, in addition to the complexity of configuration, because the application is too widespread, but also easy to be network censorship system interference. However, there is no problem at all to use in China domestic.