Fortinet black logo

Administration Guide

DTLS support

DTLS support

FortiOS Datagram Transport Layer Security (DTLS) allows SSL VPN to encrypt traffic using TLS and uses UDP as the transport layer instead of TCP. This avoids retransmission problems that can occur with TCP-in-TCP.

To establish a client SSL VPN connection with DTLS to the FortiGate:
  1. Enable the DTLS tunnel in the CLI:

    config vpn ssl setting
        set dtls-tunnel enable
    end
  2. Configure the SSL VPN settings (see SSL VPN full tunnel for remote user).

  3. Configure the firewall policy (see Firewall policy).

  4. In FortiClient, use the Preferred DTLS Tunnel option to connect to SSL VPN with DTLS:

    1. Go to Settings and expand the VPN Options section.

    2. Enable Preferred DTLS Tunnel.

      Note

      FortiClient 5.4.0 to 5.4.3 uses DTLS by default. FortiClient 5.4.4 and later uses normal TLS, regardless of the DTLS setting on the FortiGate.

    3. Click Save.

  5. In FortiOS, run diagnostics to ensure the SSL VPN connection is established with DTLS:

    # diagnose debug application sslvpn -1
    # diagnose debug enable
    

    The system displays a response like the following:

    [304:vdom1:7]DTLS established: DTLSv1 ECDHE-RSA-AES256-GCM-SHA384

Configuring the DTLS heartbeat parameters

The DTLS heartbeat parameters for SSL VPN can be adjusted. This improves the success rate of establishing a DTLS tunnel in networks with congestion or jitter.

config vpn ssl settings
    set dtls-heartbeat-idle-timeout <integer>
    set dtls-heartbeat-interval <integer>
    set dtls-heartbeat-fail-count <integer>
end

dtls-heartbeat-idle-timeout <integer>

Set the idle timeout before the DTLS heartbeat is sent, in seconds (3 - 10, default = 3).

dtls-heartbeat-interval <integer>

Set the interval between DTLS heartbeats, in seconds (3 - 10, default = 3).

dtls-heartbeat-fail-count <integer>

Set the number of missing heartbeats before the connection is considered dropped, in seconds (3 - 10, default = 3).

To configure the DTLS heartbeat parameters:
config vpn ssl settings
    set dtls-heartbeat-idle-timeout 3
    set dtls-heartbeat-interval 3
    set dtls-heartbeat-fail-count 3
end
To verify the configuration:
  1. Run diagnostics on the client side:

    # diagnose debug application sslvpn -1
    # diagnose debug enable
    00:00:03 S:058.000B(000.000B/s) R:000.000B(000.000B/s) Sd: 0 0.0000%DEBUG fsv_tun_send_clt_hb:812 send heartbeat.
    00:00:06 S:135.000B(000.000B/s) R:000.000B(000.000B/s) Sd: 0 0.0000%DEBUG fsv_client_on_read:575 got type heartbeat
    00:00:07 S:135.000B(000.000B/s) R:019.000B(019.000B/s) Sd: 0 0.0000%DEBUG fsv_tun_send_clt_hb:812 send heartbeat.
    00:00:09 S:154.000B(000.000B/s) R:019.000B(000.000B/s) Sd: 0 0.0000%DEBUG fsv_client_on_read:575 got type heartbeat
    00:00:10 S:154.000B(000.000B/s) R:038.000B(019.000B/s) Sd: 0 0.0000%DEBUG fsv_tun_send_clt_hb:812 send heartbeat.
    00:00:13 S:173.000B(000.000B/s) R:038.000B(000.000B/s) Sd: 0 0.0000%DEBUG fsv_tun_send_clt_hb:812 send heartbeat.

    The heartbeat starts being sent after the idle timeout, and the heartbeat is sent every three seconds.

  2. Run diagnostics on the server side:

    root@auto-pc147:/home/auto# ./sslvpn/perf_test/fsvc-0.90/build/fsvc -s 10.1.100.2 -n 1443 -u u1 -p 1 --dtls -d debug
    ...
    2023-04-26 12:01:40 [304:vdom1:5]sslvpn_send_ctrl_msg:987 0x7f1f2743e800 message: heartbeat  10.1.100.147
    2023-04-26 12:01:41 [304:vdom1:5]sslvpn_dtls_handle_client_data:758 0x7f1f2743e800 got heartbeat
    2023-04-26 12:01:44 [304:vdom1:5]sslvpn_dtls_handle_client_data:758 0x7f1f2743e800 got heartbeat
    2023-04-26 12:01:46 [304:vdom1:5]sslvpn_send_ctrl_msg:987 0x7f1f2743e800 message: heartbeat  10.1.100.147
    2023-04-26 12:01:50 [304:vdom1:5]sslvpn_send_ctrl_msg:987 0x7f1f2743e800 message: heartbeat  10.1.100.147
    2023-04-26 12:01:54 [304:vdom1:5]sslvpn_send_ctrl_msg:987 0x7f1f2743e800 message: heartbeat  10.1.100.147
    2023-04-26 12:01:54 [304:vdom1:5]sslvpn_dtls_timeout_check:358 no heartbeat received for 9 seconds.
    2023-04-26 12:01:54 [304:vdom1:5]fsv_disassociate_fd_to_ipaddr:2367 deassociate 10.11.12.1 from tun (ssl.vdom1:12)
    2023-04-26 12:01:54 [304:vdom1:5]dtls_tun_link_down:1884 tunnel device (12) closed
    2023-04-26 12:01:54 [304:vdom1:5]tunnel is down, wait for next connection.
    2023-04-26 12:01:54 [304:vdom1:5]sslvpn_release_dynip:1597 free app session, idx[0]
    2023-04-26 12:01:54 [304:vdom1:5]release dyip
    2023-04-26 12:01:54 [304:vdom1:5]Destroy sconn 0x7f1f2743e800, connSize=0. (vdom1)

    The tunnel is disconnected once the dtls-heartbeat-fail-count is reached.

  3. Use a Linux traffic control (tc) utility to introduce packet loss of 30% on the interface connected to the FortiGate (ens192):

    root@auto-pc147:~# tc qdisc add dev ens192 root netem loss 30%
    
  4. Run a ping test. The results show that the network has jitter/congestion as 33% of packets are being lost:

    root@auto-pc147:~# ping 10.1.100.2 -c 100
    PING 10.1.100.2 (10.1.100.2) 56(84) bytes of data.
    64 bytes from 10.1.100.2: icmp_seq=1 ttl=255 time=0.111 ms
    64 bytes from 10.1.100.2: icmp_seq=2 ttl=255 time=0.106 ms
    ...
    64 bytes from 10.1.100.2: icmp_seq=99 ttl=255 time=0.103 ms
    64 bytes from 10.1.100.2: icmp_seq=100 ttl=255 time=0.097 ms
    
    --- 10.1.100.2 ping statistics ---
    100 packets transmitted, 67 received, 33% packet loss, time 101382ms
    rtt min/avg/max/mdev = 0.088/0.104/0.141/0.009 ms
  5. Run diagnostics again on the server side to verify that the DTLS tunnel is established:

    # diagnose debug application sslvpn -1
    # diagnose debug enable
    [307:vdom1:9]form_ipv4_pol_split_tunnel_addr:113 Matched policy (id = 14) to add ipv4 split tunnel routing address
    [307:vdom1:9]SSL state:warning close notify (10.1.100.147)
    [307:vdom1:9]sslConnGotoNextState:311 error (last state: 1, closeOp: 0)
    [307:vdom1:9]Destroy sconn 0x7f1f27454800, connSize=0. (vdom1)
    [307:vdom1:9]SSL state:warning close notify (10.1.100.147)
    [304:vdom1:7]allocSSLConn:310 sconn 0x7f1f2743e800 (1:vdom1)
    [304:vdom1:7]DTLS established: DTLSv1 ECDHE-RSA-AES256-GCM-SHA384 from 10.1.100.147
    [304:vdom1:7]sslvpn_dtls_handle_client_data:693 got type clthello-tun
    [304:vdom1:7]sslvpn_dtls_handle_client_data:780 unrecognized key: id=565b74d7
    [304:vdom1:7]sslvpn_dtls_handle_client_data:703 got cookie: kKi9WXUQfKg4Mxld66IQDr3/8krPAAiA/SvxcoKfnSfDOXvKKPOgMikJZGtBaSUX1lgPK6ke73XKF43o7FYzM7MVVBY5CIRhLLnVtFP0DmqCqOz0uVtqQlUZWgtUtGz7hTl8O6VqPlnNgKX4PAY1Y+4GBqA2wG/giITeJ1Q1O7qmGzw0UwNao27C2AJBul+ugbN44C60H+XMBcd2ggXjjdFSQfQrt4Jhnbn3hhnvQImEVypv/0t1S6D0H+z5DmYZEf9nCPux0JICfGBhv6w1VXMhsasjSR3Jye049MM6xA9eCiqmUZW9DZfe
    [304:vdom1:7]deconstruct_session_id:716 decode session id ok, user=[u1], group=[all_groups],authserver=[],portal=[split_tunnel_portal],host[10.1.100.147],realm=[],csrf_token=[D840486CC92FEFC2B7F4EA46D8A455],idx=0,auth=1,sid=1db3f5f5,login=1682614961,access=1682614961,saml_logout_url=no,pip=no,grp_info=[uwiuNn],rmt_grp_info=[]
    [304:vdom1:7]tun dev (ssl.vdom1) opened (12)
    [304:vdom1:7]fsv_associate_fd_to_ipaddr:2333 associate 10.11.12.1 to tun (ssl.vdom1:12)
    [304:vdom1:7]proxy arp: scanning 26 interfaces for IP 10.11.12.1
    [304:vdom1:7]no ethernet address for proxy ARP
    [304:vdom1:7]sslvpn_user_match:1170 add user u1 in group all_groups
    [304:vdom1:7]Will add auth policy for policy 14
    [304:vdom1:7]Add auth logon for user u1:all_groups, matched group number 2
    [304:vdom1:7]sslvpn_send_ctrl_msg:987 0x7f1f2743e800 message: svrhello-tun ok 10.1.100.147
    [304:vdom1:7]sslvpn_dtls_handle_client_data:758 0x7f1f2743e800 got heartbeat
    [304:vdom1:7]sslvpn_send_ctrl_msg:987 0x7f1f2743e800 message: heartbeat  10.1.100.147
    [304:vdom1:7]sslvpn_dtls_handle_client_data:758 0x7f1f2743e800 got heartbeat
    [304:vdom1:7]sslvpn_dtls_handle_client_data:758 0x7f1f2743e800 got heartbeat
    [304:vdom1:7]sslvpn_send_ctrl_msg:987 0x7f1f2743e800 message: heartbeat  10.1.100.147

DTLS support

FortiOS Datagram Transport Layer Security (DTLS) allows SSL VPN to encrypt traffic using TLS and uses UDP as the transport layer instead of TCP. This avoids retransmission problems that can occur with TCP-in-TCP.

To establish a client SSL VPN connection with DTLS to the FortiGate:
  1. Enable the DTLS tunnel in the CLI:

    config vpn ssl setting
        set dtls-tunnel enable
    end
  2. Configure the SSL VPN settings (see SSL VPN full tunnel for remote user).

  3. Configure the firewall policy (see Firewall policy).

  4. In FortiClient, use the Preferred DTLS Tunnel option to connect to SSL VPN with DTLS:

    1. Go to Settings and expand the VPN Options section.

    2. Enable Preferred DTLS Tunnel.

      Note

      FortiClient 5.4.0 to 5.4.3 uses DTLS by default. FortiClient 5.4.4 and later uses normal TLS, regardless of the DTLS setting on the FortiGate.

    3. Click Save.

  5. In FortiOS, run diagnostics to ensure the SSL VPN connection is established with DTLS:

    # diagnose debug application sslvpn -1
    # diagnose debug enable
    

    The system displays a response like the following:

    [304:vdom1:7]DTLS established: DTLSv1 ECDHE-RSA-AES256-GCM-SHA384

Configuring the DTLS heartbeat parameters

The DTLS heartbeat parameters for SSL VPN can be adjusted. This improves the success rate of establishing a DTLS tunnel in networks with congestion or jitter.

config vpn ssl settings
    set dtls-heartbeat-idle-timeout <integer>
    set dtls-heartbeat-interval <integer>
    set dtls-heartbeat-fail-count <integer>
end

dtls-heartbeat-idle-timeout <integer>

Set the idle timeout before the DTLS heartbeat is sent, in seconds (3 - 10, default = 3).

dtls-heartbeat-interval <integer>

Set the interval between DTLS heartbeats, in seconds (3 - 10, default = 3).

dtls-heartbeat-fail-count <integer>

Set the number of missing heartbeats before the connection is considered dropped, in seconds (3 - 10, default = 3).

To configure the DTLS heartbeat parameters:
config vpn ssl settings
    set dtls-heartbeat-idle-timeout 3
    set dtls-heartbeat-interval 3
    set dtls-heartbeat-fail-count 3
end
To verify the configuration:
  1. Run diagnostics on the client side:

    # diagnose debug application sslvpn -1
    # diagnose debug enable
    00:00:03 S:058.000B(000.000B/s) R:000.000B(000.000B/s) Sd: 0 0.0000%DEBUG fsv_tun_send_clt_hb:812 send heartbeat.
    00:00:06 S:135.000B(000.000B/s) R:000.000B(000.000B/s) Sd: 0 0.0000%DEBUG fsv_client_on_read:575 got type heartbeat
    00:00:07 S:135.000B(000.000B/s) R:019.000B(019.000B/s) Sd: 0 0.0000%DEBUG fsv_tun_send_clt_hb:812 send heartbeat.
    00:00:09 S:154.000B(000.000B/s) R:019.000B(000.000B/s) Sd: 0 0.0000%DEBUG fsv_client_on_read:575 got type heartbeat
    00:00:10 S:154.000B(000.000B/s) R:038.000B(019.000B/s) Sd: 0 0.0000%DEBUG fsv_tun_send_clt_hb:812 send heartbeat.
    00:00:13 S:173.000B(000.000B/s) R:038.000B(000.000B/s) Sd: 0 0.0000%DEBUG fsv_tun_send_clt_hb:812 send heartbeat.

    The heartbeat starts being sent after the idle timeout, and the heartbeat is sent every three seconds.

  2. Run diagnostics on the server side:

    root@auto-pc147:/home/auto# ./sslvpn/perf_test/fsvc-0.90/build/fsvc -s 10.1.100.2 -n 1443 -u u1 -p 1 --dtls -d debug
    ...
    2023-04-26 12:01:40 [304:vdom1:5]sslvpn_send_ctrl_msg:987 0x7f1f2743e800 message: heartbeat  10.1.100.147
    2023-04-26 12:01:41 [304:vdom1:5]sslvpn_dtls_handle_client_data:758 0x7f1f2743e800 got heartbeat
    2023-04-26 12:01:44 [304:vdom1:5]sslvpn_dtls_handle_client_data:758 0x7f1f2743e800 got heartbeat
    2023-04-26 12:01:46 [304:vdom1:5]sslvpn_send_ctrl_msg:987 0x7f1f2743e800 message: heartbeat  10.1.100.147
    2023-04-26 12:01:50 [304:vdom1:5]sslvpn_send_ctrl_msg:987 0x7f1f2743e800 message: heartbeat  10.1.100.147
    2023-04-26 12:01:54 [304:vdom1:5]sslvpn_send_ctrl_msg:987 0x7f1f2743e800 message: heartbeat  10.1.100.147
    2023-04-26 12:01:54 [304:vdom1:5]sslvpn_dtls_timeout_check:358 no heartbeat received for 9 seconds.
    2023-04-26 12:01:54 [304:vdom1:5]fsv_disassociate_fd_to_ipaddr:2367 deassociate 10.11.12.1 from tun (ssl.vdom1:12)
    2023-04-26 12:01:54 [304:vdom1:5]dtls_tun_link_down:1884 tunnel device (12) closed
    2023-04-26 12:01:54 [304:vdom1:5]tunnel is down, wait for next connection.
    2023-04-26 12:01:54 [304:vdom1:5]sslvpn_release_dynip:1597 free app session, idx[0]
    2023-04-26 12:01:54 [304:vdom1:5]release dyip
    2023-04-26 12:01:54 [304:vdom1:5]Destroy sconn 0x7f1f2743e800, connSize=0. (vdom1)

    The tunnel is disconnected once the dtls-heartbeat-fail-count is reached.

  3. Use a Linux traffic control (tc) utility to introduce packet loss of 30% on the interface connected to the FortiGate (ens192):

    root@auto-pc147:~# tc qdisc add dev ens192 root netem loss 30%
    
  4. Run a ping test. The results show that the network has jitter/congestion as 33% of packets are being lost:

    root@auto-pc147:~# ping 10.1.100.2 -c 100
    PING 10.1.100.2 (10.1.100.2) 56(84) bytes of data.
    64 bytes from 10.1.100.2: icmp_seq=1 ttl=255 time=0.111 ms
    64 bytes from 10.1.100.2: icmp_seq=2 ttl=255 time=0.106 ms
    ...
    64 bytes from 10.1.100.2: icmp_seq=99 ttl=255 time=0.103 ms
    64 bytes from 10.1.100.2: icmp_seq=100 ttl=255 time=0.097 ms
    
    --- 10.1.100.2 ping statistics ---
    100 packets transmitted, 67 received, 33% packet loss, time 101382ms
    rtt min/avg/max/mdev = 0.088/0.104/0.141/0.009 ms
  5. Run diagnostics again on the server side to verify that the DTLS tunnel is established:

    # diagnose debug application sslvpn -1
    # diagnose debug enable
    [307:vdom1:9]form_ipv4_pol_split_tunnel_addr:113 Matched policy (id = 14) to add ipv4 split tunnel routing address
    [307:vdom1:9]SSL state:warning close notify (10.1.100.147)
    [307:vdom1:9]sslConnGotoNextState:311 error (last state: 1, closeOp: 0)
    [307:vdom1:9]Destroy sconn 0x7f1f27454800, connSize=0. (vdom1)
    [307:vdom1:9]SSL state:warning close notify (10.1.100.147)
    [304:vdom1:7]allocSSLConn:310 sconn 0x7f1f2743e800 (1:vdom1)
    [304:vdom1:7]DTLS established: DTLSv1 ECDHE-RSA-AES256-GCM-SHA384 from 10.1.100.147
    [304:vdom1:7]sslvpn_dtls_handle_client_data:693 got type clthello-tun
    [304:vdom1:7]sslvpn_dtls_handle_client_data:780 unrecognized key: id=565b74d7
    [304:vdom1:7]sslvpn_dtls_handle_client_data:703 got cookie: kKi9WXUQfKg4Mxld66IQDr3/8krPAAiA/SvxcoKfnSfDOXvKKPOgMikJZGtBaSUX1lgPK6ke73XKF43o7FYzM7MVVBY5CIRhLLnVtFP0DmqCqOz0uVtqQlUZWgtUtGz7hTl8O6VqPlnNgKX4PAY1Y+4GBqA2wG/giITeJ1Q1O7qmGzw0UwNao27C2AJBul+ugbN44C60H+XMBcd2ggXjjdFSQfQrt4Jhnbn3hhnvQImEVypv/0t1S6D0H+z5DmYZEf9nCPux0JICfGBhv6w1VXMhsasjSR3Jye049MM6xA9eCiqmUZW9DZfe
    [304:vdom1:7]deconstruct_session_id:716 decode session id ok, user=[u1], group=[all_groups],authserver=[],portal=[split_tunnel_portal],host[10.1.100.147],realm=[],csrf_token=[D840486CC92FEFC2B7F4EA46D8A455],idx=0,auth=1,sid=1db3f5f5,login=1682614961,access=1682614961,saml_logout_url=no,pip=no,grp_info=[uwiuNn],rmt_grp_info=[]
    [304:vdom1:7]tun dev (ssl.vdom1) opened (12)
    [304:vdom1:7]fsv_associate_fd_to_ipaddr:2333 associate 10.11.12.1 to tun (ssl.vdom1:12)
    [304:vdom1:7]proxy arp: scanning 26 interfaces for IP 10.11.12.1
    [304:vdom1:7]no ethernet address for proxy ARP
    [304:vdom1:7]sslvpn_user_match:1170 add user u1 in group all_groups
    [304:vdom1:7]Will add auth policy for policy 14
    [304:vdom1:7]Add auth logon for user u1:all_groups, matched group number 2
    [304:vdom1:7]sslvpn_send_ctrl_msg:987 0x7f1f2743e800 message: svrhello-tun ok 10.1.100.147
    [304:vdom1:7]sslvpn_dtls_handle_client_data:758 0x7f1f2743e800 got heartbeat
    [304:vdom1:7]sslvpn_send_ctrl_msg:987 0x7f1f2743e800 message: heartbeat  10.1.100.147
    [304:vdom1:7]sslvpn_dtls_handle_client_data:758 0x7f1f2743e800 got heartbeat
    [304:vdom1:7]sslvpn_dtls_handle_client_data:758 0x7f1f2743e800 got heartbeat
    [304:vdom1:7]sslvpn_send_ctrl_msg:987 0x7f1f2743e800 message: heartbeat  10.1.100.147