Overview
Access Server doesn't currently have a built-in feature for domain-based routing. However, you can configure domain routing using dnsmasq and manual NAT rules as a workaround. This method works for both full tunnel and split tunnel configurations.
Prerequisites
- An installed Access Server.
- Console access and the ability to get root access.
-
dnsmasq
installed on the Access Server host.
Step 1: Install dnsmasq
Ubuntu/Debian:
apt update && apt -y install dnsmasq
RHEL:
dnf update && dnf -y install dnsmasq
Step 2: Configure dnsmasq
- Find the IP of the
as0t0
interface:
ip -4 addr show as0t0 | grep -o 'inet [0-9.]*' | cut -d' ' -f2
- Example output:
root@openvpnas# ip -4 addr show as0t0 | grep -o 'inet [0-9.]*' | cut -d' ' -f2
172.27.224.1
- Example output:
- Edit the dnsmasq configuration:
nano /etc/dnsmasq.conf
- Add the following lines:
# Disable AAAA (IPv6) replies if you don't use IPv6 filter-AAAA # Listen only on the VPN interface interface=as0t0 # Explicitly bind to the correct IP listen-address=172.27.224.1 #Google's nameservers server=8.8.8.8 server=4.4.4.4 # Prevent conflicts with systemd-resolved bind-dynamic except-interface=lo # Use separate hosts file for mapping domains to fake IP addresses addn-hosts=/etc/domain_routing_hosts
-
Important: dnsmasq must start after Access Server. If
dnsmasq
is set to bind to theas0t0
interface or a specific IP (like 172.27.224.1), it must start after Access Server brings up that interface. Refer to the documentation for init system of your Linux distributive.
Ifdnsmasq
starts before the Access Server service and you can't change the order, use a delay, for example, with anExecStartPost=
systems hook.
-
Important: dnsmasq must start after Access Server. If
- Save and exit (Ctrl+X, then Y).
- Now, you can move on to the domain routing configuration and choose the full tunnel or split tunnel.
Domain routing configuration
Option 1: Full tunnel
Step 1: Enable full tunnel and set custom DNS
The goal here is to send the traffic to app1.example.net
to the VPN tunnel.
- Sign in to the Access Server console and get root privileges.
- Switch to the scripts directory:
cd /usr/local/openvpn_as/scripts/
- Run the below command to configure full tunnel in your Access Server:
./sacli --key "vpn.client.routing.reroute_gw" --value "true" ConfigPut
- Push a custom DNS server and configure the IP address from
as0t0
as the custom DNS server:./sacli --key "vpn.client.routing.reroute_dns" --value "custom" ConfigPut ./sacli --key "vpn.server.dhcp_option.dns.0" --value "172.27.224.1" ConfigPut
- Replace 172.27.224.1 with the IP address of the
as0t0
interface on your Access Server.
If you don't know what that IP address, you can run this command:
ip -4 addr show as0t0 | grep -o 'inet [0-9.]*' | cut -d' ' -f2
- Replace 172.27.224.1 with the IP address of the
- Refresh the Access Server configuration:
./sacli start
Step 2: Define the domain and assign a fake IP
In this step, we'll create a DNS entry with a fake IP address with the domain you want to redirect to the Access Server under /etc/domain_routing_hosts
.
For example, the domain app1.example.net
resolves to 203.0.113.15:
root@openvpnas# nslookup app1.openvpn.net Server: 127.0.0.53 Address: 127.0.0.53#53
Name: app1.example.net Address: 203.0.113.15
The idea is to create a manual DNS entry for app1.example.net
, by replacing 203.0.113.15 with another IP (fake IP). You can choose an IP from a subnet that isn't used by any settings in your Access Server.
In this case:
- 192.168.100.0/24 = the fake subnet.
-
192.168.100.15 = the fake IP for
app1.example.net
.
From the VPN client perspective, we will see 192.168.100.15, but in reality, the traffic will be directed to 203.0.113.15.
When you have your IP address and domain, follow these steps:
- Edit the
/etc/domain_routing_hosts
file:
nano /etc/domain_routing_hosts
- Configure the fake IP you selected (192.168.100.15) from the fake subnet (192.168.100.0/24) and attach it to your desired domain (
app1.example.net
) that you want to send through the VPN tunnel. For this, add the below line:
192.168.100.15 app1.example.net
- Save and exit by pressing Ctrl+X, then Y.
- Restart dnsmasq:
systemctl restart dnsmasq
Step 3: Configure a DNAT IPTABLE
Important Note: When you configure custom IPTABLES like the one mentioned above, whenever you restart the services on the Access Server side or save changes, that custom IPTABLES is deleted. The Access Server prepends its IPTABLES, so your custom IPTABLES will be appended. Follow this step to correct this.
- Change rule-prepending behavior to make Access Server append rules after existing ones (instead of prepending):
./sacli --key "iptables.append" --value "true" ConfigPut service openvpnas restart
- Now, even after restarting Access Server or saving changes, your custom IPTABLE remains the same. This doesn't affect any of the rules created by Access Server. For more info, refer to Tutorial: Managing iptables Settings in Access Server.
- The custom IPTABLES won't be persistent when rebooting the Access Server host.
- Configure a DNAT that will translate the destination IP (192.168.100.15) to the real destination IP (203.0.113.15):
iptables -t nat -A PREROUTING -d 192.168.100.15 -j DNAT --to-destination 203.0.113.15
- You should now be able to connect to the VPN, and when you try to resolve DNS or PING
app1.example.net
, you'll see 192.168.100.15, but in reality, it's getting traffic for 203.0.113.15.
- You should now be able to connect to the VPN, and when you try to resolve DNS or PING
Testing
Here's an example expected outcome, using the app1.example.net
domain:
PS C:\Users\Brandon> Resolve-DnsName app1.example.net
Name Type TTL Section IPAddress
---- ---- --- ------- ---------
app1.example.net A 0 Answer 192.168.100.15
Pinging from the VPN client works:
Pinging app1.example.net [app1.example.net] with 32 bytes of data:
Reply from 192.168.100.15: bytes=32 time=161ms TTL=110
Reply from 192.168.100.15: bytes=32 time=161ms TTL=110
Reply from 192.168.100.15: bytes=32 time=161ms TTL=110
Reply from 192.168.100.15: bytes=32 time=161ms TTL=110
A TCPDUMP on the Access Server shows the reality:
23:51:45.555053 as0t0 In ifindex 28 ethertype IPv4 (0x0800), length 80: 172.27.224.8 > 192.168.100.15: ICMP echo request, id 1, seq 2416, length 40
23:51:45.555077 eth0 Out ifindex 2 2e:79:fe:e6:00:ac ethertype IPv4 (0x0800), length 80: 64.227.7.197 > 203.0.113.15: ICMP echo request, id 1, seq 2416, length 40
23:51:45.557127 eth0 In ifindex 2 fe:00:00:00:01:01 ethertype IPv4 (0x0800), length 80: 203.0.113.15 > 64.227.7.197: ICMP echo reply, id 1, seq 2416, length 40
23:51:45.557162 as0t0 Out ifindex 28 ethertype IPv4 (0x0800), length 80: 192.168.100.15 > 172.27.224.8: ICMP echo reply, id 1, seq 2416, length 40
Access Server translates the destination IP from 192.168.100.15 to 203.0.113.15.
Option 2: Split tunnel
Step 1: Enable split tunnel for a specific user
The goal here is to send the traffic to app1.example.net
through the VPN tunnel.
- Sign in to the Access Server console and get root privileges.
- Switch to the scripts directory:
cd /usr/local/openvpn_as/scripts/
- Run the below command to configure full tunnel in your Access Server:
./sacli --key "vpn.client.routing.reroute_gw" --value "true" ConfigPut
- Run the below command to configure split tunnel for your desired VPN user:
./sacli --user 'brandon' --key "prop_reroute_gw_override" --value "dns_only" UserPropPut
- Push a custom DNS server and configure the IP address from
as0t0
as the custom DNS server:./sacli --key "vpn.client.routing.reroute_dns" --value "custom" ConfigPut ./sacli --key "vpn.server.dhcp_option.dns.0" --value "172.27.224.1" ConfigPut
- Replace 172.27.224.1 with the IP address of the
as0t0
interface on your Access Server.
If you don't know what that IP address, you can run this command:
ip -4 addr show as0t0 | grep -o 'inet [0-9.]*' | cut -d' ' -f2
- Replace 172.27.224.1 with the IP address of the
- Refresh the Access Server configuration:
./sacli start
Step 2: Define the domain and assign a fake IP
In this step, we'll create a DNS entry with a fake IP address with the domain you want to redirect to the Access Server under /etc/domain_routing_hosts
.
For example, the domain app1.example.net
resolves to 203.0.113.15:
root@openvpnas# nslookup app1.example.net Server: 127.0.0.53 Address: 127.0.0.53#53
Name: app1.example.net Address: 203.0.113.15
The idea is to create a manual DNS entry for app1.example.net
, by replacing 203.0.113.15 with another IP (fake IP). You can choose an IP from a subnet that isn't used by any settings in your Access Server.
In this case:
- 192.168.100.0/24 = the fake subnet.
-
192.168.100.15 = the fake IP for
app1.example.net
.
From the VPN client perspective, we will see 192.168.100.15, but in reality, the traffic will be directed to 203.0.113.15.
When you have your IP address and domain, follow these steps:
- Edit the
/etc/domain_routing_hosts
file:
nano /etc/domain_routing_hosts
- Configure the fake IP you selected (192.168.100.15) from the fake subnet (192.168.100.0/24) and attach it to your desired domain (
app1.example.net
) that you want to send through the VPN tunnel. For this, add the below line:
192.168.100.15 app1.example.net
- Save and exit by pressing Ctrl+X, then Y.
- Restart dnsmasq:
systemctl restart dnsmasq
Step 3: Configure a global access control rule for the fake IP
- Run the below command:
./sacli --key "vpn.server.routing.private_network.999" --value "192.168.100.15/32" ConfigPut
- We use index 999 to place this rule at the end of ACL.
- Refresh the Access Server configuration:
./sacli start
Step 4: Configure a DNAT IPTABLE
Important Note: When you configure custom IPTABLES like the one mentioned above, whenever you restart the services on the Access Server side or save changes, that custom IPTABLES is deleted. The Access Server prepends its IPTABLES, so your custom IPTABLES will be appended. Follow this step to correct this.
- Change rule-prepending behavior to make Access Server append rules after existing ones (instead of prepending):
./sacli --key "iptables.append" --value "true" ConfigPut service openvpnas restart
- Now, even after restarting Access Server or saving changes, your custom IPTABLE remains the same. This doesn't affect any of the rules created by Access Server. For more info, refer to Tutorial: Managing iptables Settings in Access Server.
- The custom IPTABLES won't be persistent when rebooting the Access Server host.
- Configure a DNAT that will translate the destination IP (192.168.100.15) to the real destination IP (203.0.113.15):
iptables -t nat -A PREROUTING -d 192.168.100.15 -j DNAT --to-destination 203.0.113.15
- You should now be able to connect to the VPN, and when you try to resolve DNS or PING
app1.example.net
, you'll see 192.168.100.15, but in reality, it's getting traffic for 203.0.113.15.
- You should now be able to connect to the VPN, and when you try to resolve DNS or PING
Testing
An expected outcome from the VPN client while resolving DNS for app1.example.net
should look like this:
PS C:\Users\Brandon> Resolve-DnsName app1.example.net
Name Type TTL Section IPAddress
---- ---- --- ------- ---------
app1.example.net A 0 Answer 192.168.100.15
Pinging from the VPN client works:
Pinging app1.example.net [app1.example.net] with 32 bytes of data:
Reply from 192.168.100.15: bytes=32 time=161ms TTL=110
Reply from 192.168.100.15: bytes=32 time=161ms TTL=110
Reply from 192.168.100.15: bytes=32 time=161ms TTL=110
Reply from 192.168.100.15: bytes=32 time=161ms TTL=110
A TCPDUMP on the Access Server shows the reality:
23:51:45.555053 as0t0 In ifindex 28 ethertype IPv4 (0x0800), length 80: 172.27.224.8 > 192.168.100.15: ICMP echo request, id 1, seq 2416, length 40
23:51:45.555077 eth0 Out ifindex 2 2e:79:fe:e6:00:ac ethertype IPv4 (0x0800), length 80: 64.227.7.197 > 203.0.113.15: ICMP echo request, id 1, seq 2416, length 40
23:51:45.557127 eth0 In ifindex 2 fe:00:00:00:01:01 ethertype IPv4 (0x0800), length 80: 203.0.113.15 > 64.227.7.197: ICMP echo reply, id 1, seq 2416, length 40
23:51:45.557162 as0t0 Out ifindex 28 ethertype IPv4 (0x0800), length 80: 192.168.100.15 > 172.27.224.8: ICMP echo reply, id 1, seq 2416, length 40
Access Server translates the destination IP from 192.168.100.15 to 203.0.113.15.
Option: Domain routing for multiple destination IPs
If a domain resolves to multiple IPs, you can configure a round-robin DNAT rule.
Step 1: Configure full tunnel global, split tunnel for the desired VPN user and the custom DNS server pushed by Access Server
For this use case, we are using split tunnel, and our domain app2.example.net
resolves to two IPs: 203.0.113.20 and 203.0.113.21.
- Sign in to the Access Server console and get root privileges.
- Switch to the scripts directory:
cd /usr/local/openvpn_as/scripts/
- Run the below command to configure full tunnel in your Access Server:
./sacli --key "vpn.client.routing.reroute_gw" --value "true" ConfigPut
- Run the below command to configure split tunnel for your desired VPN user:
./sacli --user 'brandon' --key "prop_reroute_gw_override" --value "dns_only" UserPropPut
- Push a custom DNS server and configure the IP address from
as0t0
as the custom DNS server:./sacli --key "vpn.client.routing.reroute_dns" --value "custom" ConfigPut ./sacli --key "vpn.server.dhcp_option.dns.0" --value "172.27.224.1" ConfigPut
- Replace 172.27.224.1 with the IP address of the
as0t0
interface on your Access Server.
If you don't know what that IP address, you can run this command:
ip -4 addr show as0t0 | grep -o 'inet [0-9.]*' | cut -d' ' -f2
- Replace 172.27.224.1 with the IP address of the
- Refresh the Access Server configuration:
./sacli start
Step 2: Configure the domain and assign a fake IP
In this step, we'll create a DNS entry with a fake IP address with the domain you want to redirect to the Access Server under /etc/domain_routing_hosts
.
For example, the domain app2.example.net
resolves to 203.0.113.20 and 203.0.113.21:
root@openvpnas# nslookup app2.example.net Server: 127.0.0.53 Address: 127.0.0.53#53
Non-authoritative answer:
Name: app2.example.net
Address: 203.0.113.20
Name: app2.example.net
Address: 203.0.113.21
The idea is to create a manual DNS entry for app2.example.net
, by replacing 203.0.113.20 and 203.0.113.21 with another IP (fake IP). You can choose an IP from a subnet that isn't used by any settings in your Access Server.
In this case:
- 192.168.100.0/24 = the fake subnet.
-
192.168.100.20 and 192.168.100.21 = the fake IPs for
app2.example.net
.
From the VPN client perspective, we will see 192.168.100.20 and 192.168.100.21, but in reality, the traffic will be reaching either 203.0.113.20 or 203.0.113.21.
When you have your IP addresses and domain, follow these steps:
- Edit the
/etc/domain_routing_hosts
file:
nano /etc/domain_routing_hosts
- Configure the fake IP you selected (192.168.100.20) from the fake subnet (192.168.100.0/24) and attach it to your desired domain (
app2.example.net
) that you want to send through the VPN tunnel. For this, add the below line:
192.168.100.20 app2.example.net
192.168.100.21 app2.example.net - Save and exit by pressing Ctrl+X, then Y.
- Restart dnsmasq:
systemctl restart dnsmasq
Step 3: Configure a global access control rule for the fake IP
- Run the below command:
./sacli --key "vpn.server.routing.private_network.998" --value "192.168.100.20/32" ConfigPut
./sacli --key "vpn.server.routing.private_network.999" --value "192.168.100.21/32" ConfigPut - Refresh the Access Server configuration:
./sacli start
Step 4: Configure a DNAT IPTABLE
Important Note: When you configure custom IPTABLES like the one mentioned above, whenever you restart the services on the Access Server side or save changes, that custom IPTABLES is deleted. The Access Server prepends its IPTABLES, so your custom IPTABLES will be appended. Follow this step to correct this.
- Change rule-prepending behavior to make Access Server append rules after existing ones (instead of prepending):
./sacli --key "iptables.append" --value "true" ConfigPut service openvpnas restart
- Now, even after restarting Access Server or saving changes, your custom IPTABLE remains the same. This doesn't affect any of the rules created by Access Server. For more info, refer to Tutorial: Managing iptables Settings in Access Server.
- The custom IPTABLES won't be persistent when rebooting the Access Server host.
- Configure a DNAT that will translate the destination IP (192.168.100.20) to the real destination IPs (203.0.113.20 and 203.0.113.21):
iptables -t nat -A PREROUTING -d 192.168.100.20 -j DNAT --to-destination 203.0.113.20
iptables -t nat -A PREROUTING -d 192.168.100.21 -j DNAT --to-destination 203.0.113.21- You should now be able to connect to the VPN, and when you try to resolve DNS, PING, or TCP Traffic
app2.example.net
, you'll see 192.168.100.20 or 192.168.100.21, but in reality, it's getting traffic for 203.0.113.20 or 203.0.113.21.
- You should now be able to connect to the VPN, and when you try to resolve DNS, PING, or TCP Traffic
Testing
An expected outcome from the VPN client while resolving DNS for app2.example.net
should look like this:
PS C:\Users\Brandon> Resolve-DnsName app2.example.net
Name Type TTL Section IPAddress
---- ---- --- ------- ---------
app2.example.net A 0 Answer 192.168.100.20
app2.example.net A 0 Answer 192.168.100.21
If I try a TCP connection from my VPN client, that works:
PS C:\Users\Brandon> tnc app2.example.net -port 943
ComputerName : app2.example.net
RemoteAddress : 192.168.100.20
RemotePort : 943
InterfaceAlias : Conexión de área local
SourceAddress : 172.27.228.8
TcpTestSucceeded : True
A TCPDUMP on the Access Server shows the reality:
00:38:49.262335 as0t1 In ifindex 29 ethertype IPv4 (0x0800), length 72: 172.27.228.8.63540 > 192.168.100.20.943: Flags [S], seq 902766971, win 65520, options [mss 1260,nop,wscale 8,nop,nop,sackOK], length 0
00:38:49.262381 eth0 Out ifindex 2 2e:79:fe:e6:00:ac ethertype IPv4 (0x0800), length 72: 64.227.7.197.63540 > 203.0.113.20.943: Flags [S], seq 902766971, win 65520, options [mss 1260,nop,wscale 8,nop,nop,sackOK], length 0
00:38:49.265338 eth0 In ifindex 2 fe:00:00:00:01:01 ethertype IPv4 (0x0800), length 72: 203.0.113.20.943 > 64.227.7.197.63540: Flags [S.], seq 2034942689, ack 902766972, win 64240, options [mss 1460,nop,nop,sackOK,nop,wscale 7], length 0
00:38:49.265383 as0t1 Out ifindex 29 ethertype IPv4 (0x0800), length 72: 192.168.100.20.943 > 172.27.228.8.63540: Flags [S.], seq 2034942689, ack 902766972, win 64240, options [mss 1460,nop,nop,sackOK,nop,wscale 7], length 0
00:38:49.342489 as0t1 In ifindex 29 ethertype IPv4 (0x0800), length 60: 172.27.228.8.63540 > 192.168.100.20.943: Flags [.], ack 1, win 1028, length 0
Access Server translates the destination IP from 192.168.100.20 to 203.0.113.20.
If I try a TCP connection from my VPN client again, that works:
PS C:\Users\Brandon> tnc app2.example.net -port 943
ComputerName : app2.example.net
RemoteAddress : 192.168.100.21
RemotePort : 943
InterfaceAlias : Conexión de área local
SourceAddress : 172.27.228.8
TcpTestSucceeded : True
A TCPDUMP on the Access Server shows the reality:
00:38:56.385484 as0t1 In ifindex 29 ethertype IPv4 (0x0800), length 72: 172.27.228.8.63543 > 192.168.100.21.943: Flags [S], seq 2960643544, win 65520, options [mss 1260,nop,wscale 8,nop,nop,sackOK], length 0
00:38:56.385528 eth0 Out ifindex 2 2e:79:fe:e6:00:ac ethertype IPv4 (0x0800), length 72: 64.227.7.197.63543 > 203.0.113.21.943: Flags [S], seq 2960643544, win 65520, options [mss 1260,nop,wscale 8,nop,nop,sackOK], length 0
00:38:56.387731 eth0 In ifindex 2 fe:00:00:00:01:01 ethertype IPv4 (0x0800), length 72: 203.0.113.21.943 > 64.227.7.197.63543: Flags [S.], seq 1155514875, ack 2960643545, win 64240, options [mss 1460,nop,nop,sackOK,nop,wscale 7], length 0
00:38:56.387762 as0t1 Out ifindex 29 ethertype IPv4 (0x0800), length 72: 192.168.100.21.943 > 172.27.228.8.63543: Flags [S.], seq 1155514875, ack 2960643545, win 64240, options [mss 1460,nop,nop,sackOK,nop,wscale 7], length 0
00:38:56.461460 as0t1 In ifindex 29 ethertype IPv4 (0x0800), length 60: 172.27.228.8.63543 > 192.168.100.20.943: Flags [.], ack 1, win 1028, length 0
Access Server translates the destination IP from 192.168.100.21 to 203.0.113.21.
Limitations: Automating DNAT updates for dynamic domains
Important Note: The domain routing approach here isn't geo-location aware and doesn't automatically update the DNAT IPTABLES when the target domain changes IP.
If a domain's IP changes frequently, automate updates with a script.
Some key points for our example:
- For this example, we will use domain routing with the split tunnel approach explained above.
- We will use
app1.example.net
in our example. - This domain
app1.example.net
resolves to 203.0.113.15, but this changes to 203.0.113.16. - We will use a bash script called
update_dnat.sh
. You can name it as you wish. - We will configure the bash script to run every five minutes. You can configure it to depending on domain records TTL and your needs. Ensure the interval is enough to allow the script to update all records.
Step 1: Create a bash script
- Create and edit the
update_dns.sh
nano /usr/local/bin/update_dnat.sh
- Add the following:
#!/bin/bash # Define the CSV file path DOMAIN_FILE='/etc/domain_routing_hosts' # Define the iptables parameters TABLE="nat" CHAIN="PREROUTING" # Check if the DOMAIN_FILE file exists if [[ ! -f "$DOMAIN_FILE" ]]; then logger -t DNAT_UPDATE "DOMAIN_FILE file not found!" exit 1 fi # Read the DOMAIN_FILE file line by line while IFS=$'\t' read -r LOCAL_IP DOMAIN; do # Check if the domain and IP are not empty if [[ -n "$DOMAIN" && -n "$LOCAL_IP" ]]; then # Resolve the domain to an IP NEW_IP=$(dig @1.1.1.1 +short $DOMAIN | head -n 1) # Check if dig returned an IP if [[ -z "$NEW_IP" ]]; then logger -t DNAT_UPDATE "Failed to resolve $DOMAIN" #exit 1 fi # Get the current DNAT rule for LOCAL_IP CURRENT_IP=$(iptables -t "$TABLE" -S "$CHAIN" | grep -- "-d $LOCAL_IP" | grep "DNAT" | awk -F'--to-destination ' '{print $2}') # If there's no rule or the IP has changed, update the rule if [[ "$NEW_IP" != "$CURRENT_IP" ]]; then logger -t DNAT_UPDATE "Updating DNAT rule... New IP for $DOMAIN: $NEW_IP" # Delete old DNAT rule (if exists) if [[ -n "$CURRENT_IP" ]]; then iptables -t "$TABLE" -D "$CHAIN" -d "$LOCAL_IP" -j DNAT --to-destination "$CURRENT_IP" fi # Add new DNAT rule iptables -t "$TABLE" -A "$CHAIN" -d "$LOCAL_IP" -j DNAT --to-destination "$NEW_IP" fi fi done < $DOMAIN_FILE
- The script reads domain names from the
/etc/domain_routing_hosts
file. - If you're using an internal domain with DNS entries in an internal DNS server behind Access Server, replace 1.1.1.1 with your internal DNS server.
- The script reads domain names from the
- Save and exit.
Step 2: Make the script executable
- Make the bash script executive:
chmod +x /usr/local/bin/update_dnat.sh
Step 3: Automate execution via cron job
- Open the crontab file for the account you're signed in as:
crontab -e
- You may be prompted to select an editor (nano).
- Add the following lines at the bottom of the crontab file:
SHELL=/bin/bash */5 * * * * /usr/local/bin/update_dnat.sh
- This runs the script every five minutes.
- Save and exit by pressing Ctrl+X, then Y.
Testing
An expected outcome from the VPN client while resolving DNS for app1.example.net
should look like this:
PS C:\Users\Brandon> Resolve-DnsName app1.example.net
Name Type TTL Section IPAddress
---- ---- --- ------- ---------
app1.example.net A 0 Answer 192.168.100.15
Pinging from the VPN client works:
Pinging app1.example.net [app1.example.net] with 32 bytes of data:
Reply from 192.168.100.15: bytes=32 time=161ms TTL=110
Reply from 192.168.100.15: bytes=32 time=161ms TTL=110
Reply from 192.168.100.15: bytes=32 time=161ms TTL=110
Reply from 192.168.100.15: bytes=32 time=161ms TTL=110
A TCPDUMP on the Access Server shows the reality:
23:51:45.555053 as0t0 In ifindex 28 ethertype IPv4 (0x0800), length 80: 172.27.224.8 > 192.168.100.15: ICMP echo request, id 1, seq 2416, length 40
23:51:45.555077 eth0 Out ifindex 2 2e:79:fe:e6:00:ac ethertype IPv4 (0x0800), length 80: 64.227.7.197 > 203.0.113.15: ICMP echo request, id 1, seq 2416, length 40
23:51:45.557127 eth0 In ifindex 2 fe:00:00:00:01:01 ethertype IPv4 (0x0800), length 80: 203.0.113.15 > 64.227.7.197: ICMP echo reply, id 1, seq 2416, length 40
23:51:45.557162 as0t0 Out ifindex 28 ethertype IPv4 (0x0800), length 80: 192.168.100.15 > 172.27.224.8: ICMP echo reply, id 1, seq 2416, length 40
Access Server translates the destination IP from 192.168.100.15 to 203.0.113.15.
Suppose the IP from app1.example.net
changes from 203.0.113.15 to 203.0.113.16.
Check if the bash script updates the IP by checking the syslog log:
root@openvpnas:~# cat /var/log/syslog
2025-03-09T20:42:01.101271+00:00 openvpnas CRON[72398]: (root) CMD (/usr/local/bin/update_dnat.sh)
2025-03-09T20:42:01.159530+00:00 openvpnas DNAT_UPDATE: Updating DNAT rule... New IP for app1.example.net: 203.0.113.16
You can also see this change by checking the IPTABLES:
root@openvpnas:~# iptables-save -c
[0:0] -A PREROUTING -d 192.168.100.15/32 -j DNAT --to-destination 203.0.113.16
Pinging from the VPN client works again:
Pinging app1.example.net [app1.example.net] with 32 bytes of data: Reply from 192.168.100.15: bytes=32 time=161ms TTL=110 Reply from 192.168.100.15: bytes=32 time=161ms TTL=110 Reply from 192.168.100.15: bytes=32 time=161ms TTL=110 Reply from 192.168.100.15: bytes=32 time=161ms TTL=110
A TCPDUMP on the Access Server shows the reality:
20:51:25.799349 as0t0 In ifindex 36 ethertype IPv4 (0x0800), length 80: 172.27.224.2 > 192.168.100.15: ICMP echo request, id 1, seq 2609, length 40
20:51:25.799388 eth0 Out ifindex 2 2e:79:fe:e6:00:ac ethertype IPv4 (0x0800), length 80: 64.227.7.197 > 203.0.113.16: ICMP echo request, id 1, seq 2609, length 40
20:51:25.801421 eth0 In ifindex 2 fe:00:00:00:01:01 ethertype IPv4 (0x0800), length 80: 203.0.113.16 > 64.227.7.197: ICMP echo reply, id 1, seq 2609, length 40
20:51:25.801484 as0t0 Out ifindex 36 ethertype IPv4 (0x0800), length 80: 192.168.100.15 > 172.27.224.2: ICMP echo reply, id 1, seq 2609, length 40
Access Server translates the destination IP from 192.168.100.15 to 203.0.113.16.
Conclusion
Using dnsmasq
and manual iptables
DNAT rules, you can configure domain-based routing for Access Server, even though it doesn't support this natively. If your domain's IP changes frequently, use a script to automate updates.
Comments
0 comments
Please sign in to leave a comment.