IPSec network DHCP problem, the reply routing through wrong path

Hi there,

What is my problem

DHCP reply routing path is not correct, see Tcpdump Section below, and the port forward rule can not work.

What have I done

I've setup an ipsec interface (ipsec0, it is a tun device), and give this interface a static ip:

# ip link show ipsec0
26: ipsec0: <POINTOPOINT,MULTICAST,NOARP,UP,LOWER_UP> mtu 1400 qdisc fq_codel state UNKNOWN mode DEFAULT group default qlen 500
    link/none
# ip addr show ipsec0
26: ipsec0: <POINTOPOINT,MULTICAST,NOARP,UP,LOWER_UP> mtu 1400 qdisc fq_codel state UNKNOWN group default qlen 500
    link/none
    inet 192.168.100.1/24 brd 192.168.100.255 scope global ipsec0
       valid_lft forever preferred_lft forever
    inet6 fd22:1389:8072:100::1/64 scope global
       valid_lft forever preferred_lft forever

DHCP server is also setup like this:

config dnsmasq
        ......
        list interface 'ipsec0'
        ......

config dhcp 'ipsec0'
        option interface 'ipsec0'
        option start '100'
        option limit '200'
        option leasetime '12h'
        option dhcpv4 'server'
        option ra 'server'
        option dhcpv6 'server'

Below is strongswan's dhcp config:

 # cat /etc/strongswan.d/charon/dhcp.conf
dhcp {

    # Always use the configured server address.
    force_server_address = yes

    # Derive user-defined MAC address from hash of IKE identity and send client
    # identity DHCP option.
    identity_lease = yes

    # Interface name the plugin uses for address allocation.
    interface = ipsec0

    # Interface name the plugin uses to bind its receive socket.
    # interface_receive = charon.plugins.dhcp.interface

    # Whether to load the plugin. Can also be an integer to increase the
    # priority of this plugin.
    load = yes

    # DHCP server unicast or broadcast IP address.
    server = 192.168.100.255

    # Use the DHCP server port (67) as source port when a unicast server address
    # is configured.
    use_server_port = no

}

Problem and logs

Now I am dailing into this vpn site and there are problems in ipsec's log, the dhcp request dont receive reply, but dnsmasq shows it is replied:

Sat Dec 27 14:45:38 2025 daemon.info ipsec: 14[CFG] sending DHCP DISCOVER for 7b:b7:bb:ca:ad:6f to 192.168.100.1
Sat Dec 27 14:45:38 2025 daemon.info dnsmasq-dhcp[1]: DHCPDISCOVER(ipsec0) 7b:b7:bb:ca:ad:6f
Sat Dec 27 14:45:38 2025 daemon.info dnsmasq-dhcp[1]: DHCPOFFER(ipsec0) 192.168.100.114 7b:b7:bb:ca:ad:6f
Sat Dec 27 14:45:40 2025 daemon.info ipsec: 06[MGR] ignoring request with ID 5, already processing
Sat Dec 27 14:45:41 2025 daemon.info ipsec: 14[CFG] sending DHCP DISCOVER for 7b:b7:bb:ca:ad:6f to 192.168.100.1

Tcpdump result and problem reasons

I've done some sniffer works, and now I understanding why this happend, BUT I DONT KNOW HOW TO RESOLVE IT:

14:03:16.004177 ipsec0 Out IP 192.168.100.1.68 > 192.168.100.255.67: BOOTP/DHCP, Request from 7b:b7:bb:ca:ad:6f, length 268
14:03:17.004601 ipsec0 Out IP 192.168.100.1.68 > 192.168.100.255.67: BOOTP/DHCP, Request from 7b:b7:bb:ca:ad:6f, length 268
14:03:19.005029 ipsec0 Out IP 192.168.100.1.68 > 192.168.100.255.67: BOOTP/DHCP, Request from 7b:b7:bb:ca:ad:6f, length 268
14:03:19.049906 lo    In  IP 192.168.100.1.67 > 192.168.100.1.67: BOOTP/DHCP, Reply, length 300
14:03:19.050842 lo    In  IP 192.168.100.1.67 > 192.168.100.1.67: BOOTP/DHCP, Reply, length 300
14:03:19.051684 lo    In  IP 192.168.100.1.67 > 192.168.100.1.67: BOOTP/DHCP, Reply, length 300
14:03:22.005457 ipsec0 Out IP 192.168.100.1.68 > 192.168.100.255.67: BOOTP/DHCP, Request from 7b:b7:bb:ca:ad:6f, length 268
14:03:22.006596 lo    In  IP 192.168.100.1.67 > 192.168.100.1.67: BOOTP/DHCP, Reply, length 300
14:03:26.005888 ipsec0 Out IP 192.168.100.1.68 > 192.168.100.255.67: BOOTP/DHCP, Request from 7b:b7:bb:ca:ad:6f, length 268
14:03:26.006872 lo    In  IP 192.168.100.1.67 > 192.168.100.1.67: BOOTP/DHCP, Reply, length 300

tcpdump shows the request (port 68 --> port 67) has sent to broadcast address (192.168.100.255), but the reply is routing to a wrong path, the traffic goes to the same ip and same port (???).

I tried port forward rules

I've setup a DNAT rule, but it seems useless:

# cat /etc/config/firewall

config redirect
        option target 'DNAT'
        option name 'VPN DHCP DNAT'
        list proto 'udp'
        option src 'ipsec0'
        option src_dport '67'
        option dest_port '68'
        option dest 'ipsec0'
        option src_port '67'
        option family 'any'
        option reflection '0'

The rule is a little confusing, but it said like below on openwrt's luci firewall web interface:

Match: incoming IPv6 and IPv6, protocol UDP, from ipsec0, port 67, to this device, port 67.
Action:  forward to ipsec0, port 68

Any suggestions ?

Need to see bigger picture
Please connect to your OpenWrt device using ssh and copy the output of the following commands and post it here using the "Preformatted text </> " button (red circle; this works best in the 'Markdown' composer view in the blue oval):

Screenshot 2025-10-20 at 8.14.14 PM

Remember to redact passwords, VPN keys, MAC addresses and any public IP addresses you may have:

ubus call system board
cat /etc/config/network
cat /etc/config/wireless
cat /etc/config/dhcp
cat /etc/config/firewall
cat /etc/sysctl.conf

(post deleted by author)

First try without offloads....

Disabling hardware offload & software offload, I mean ... no offload, do not resolve the prolbem :frowning:

I've found the solution. For safty reason, I've delete floor 3, the information on floor 3 is irrelevant to this problem.

This issue is likely related to strongSwan's DHCP plugin, and the solution can be found in its configuration file:

# cat /etc/strongswan.d/charon/dhcp.conf
dhcp {
    ......
    # Interface name the plugin uses to bind its receive socket.
    # interface_receive = charon.plugins.dhcp.interface
    ......
}

You can see there is a interface_receive configuration item, according to my sinffer result:

14:03:19.005029 ipsec0 Out IP 192.168.100.1.68 > 192.168.100.255.67: BOOTP/DHCP, Request from 7b:b7:bb:ca:ad:6f, length 268
14:03:19.049906 lo    In  IP 192.168.100.1.67 > 192.168.100.1.67: BOOTP/DHCP, Reply, length 300

The DHCP response appears on interface lo, so, just set interface_receive to lo, this solved my problem:

# cat /etc/strongswan.d/charon/dhcp.conf
dhcp {
    ......
    # Interface name the plugin uses to bind its receive socket.
    interface_receive = lo
    ......
}

NOTE: according to strongswan dhcp plugin's offical document, interface_receive is available since version 6.0.1, BUT according to my test, it is also available in version 5.9.14