Wireguard connection not established due to clock out of sync

Hi,

My use-case: Running a Freebsd 12.2 server on a Pi3 as a Wireguard client to my PFSense Wireguard server.

If the wireguard service in the Pi3 is disabled in rc.conf, the server boots up and the ntpd sync works fine, and system time is accurate.

But if the wireguard service in the Pi3 is enabled in rc.conf, the ntpd sync does not finish before wireguard is started. This causes two issues:
- System clock is like an hour offtrack
- Wireguard handshake between client and server failed due to the time gap being too large

I used rcorder to check the actual script execution order. Initially wireguard service ran before ntpd. Modified the rc script for wireguard to require ntpd. This solved the execution order and ntpd runs just before wireguard. But for some reason ntpd does not sync before winguard starts its handshake.

Despite my best search efforts, I have not found anyone running in to this particular issue. Probably because my HW and OS combo is not that common for wireguard users.

Any advise on how to resolve this would be much appreciated.

Best Regards

//Jimmy
 
I would try this:
  • change the script order for wireguard to require ntpdate; and
  • add ntpdate_enable="YES" to /etc/rc.conf.
 
When you don't have a RTC you have to get the ntpd to sync quickly, bridging any big gap right at the start. Normally the ntpd closes in on the actual time not blazingly fast: that is good. When synchronised time is needed immediately at the start of ntpd, the normal ntp algorithms do not suffice. Personally, I prefer the use of ntpd(8) over ntpdate(8)*

As for /etc/rc.conf:
  1. Check that there is no reference or use of ntpdate(8) anymore
  2. add:
    ntpd_enable="YES"
    ntpd_sync_on_start="YES"
Also, as extra checks: verify that ntpd is running after boot:
ps -auxww | grep ntpd
this should give you the same pid and status confirmation as:
service ntpd status

rc.conf(5):
ntpd_sync_on_start
(bool) If set to "YES", ntpd(8) is run with the -g flag,
which syncs the system's clock on startup. See ntpd(8) for
more information regarding the -g option. This is a pre-
ferred alternative to using ntpdate(8) or specifying the
ntpdate_enable variable.

ntpd(8)**:
USAGE
How NTP Operates
[...]
Finally, in the past many startup scripts would run ntpdate(8) or sntp(8)
to get the system clock close to correct before starting ntpd(8), but
this was never more than a mediocre hack and is no longer needed. If you
are following the instructions in Starting NTP (Best Current Practice)
and you still need to set the system time before starting ntpd, please
open a bug report and document what is going on, and then look at using
sntp(8) if you really need to set the clock before starting ntpd.

There is a way to start ntpd(8) that often addresses all of the problems
mentioned above.

Starting NTP (Best Current Practice)
First, use the iburst option on your server entries.

If you can also keep a good ntp.drift file then ntpd(8) will effectively
"warm-start" and your system's clock will be stable in under 11 seconds'
time.

As soon as possible in the startup sequence, start ntpd(8) with at least
the -g and perhaps the -N options.
ntpd(8):
-g, --panicgate
Allow the first adjustment to be Big. This option may appear an
unlimited number of times.

Normally, ntpd exits with a message to the system log if the off-
set exceeds the panic threshold, which is 1000 s by default. This
option allows the time to be set to any value without restric-
tion; however, this can happen only once. If the threshold is ex-
ceeded after that, ntpd will exit with a message to the system
log. This option can be used with the -q and -x options. See the
tinker configuration file directive for other options.

___
* ntpdate(8):
DESCRIPTION
Note: The functionality of this program is now available in the ntpd(8)
program. See the -q command line option in the ntpd(8) page. After a
suitable period of mourning, the ntpdate utility is to be retired from
this distribution.
and What is the difference between the Director ntp and ntpdate commands?

Also, ntpdate - set the date and time via NTP:
Disclaimer: This program has known bugs and deficiencies and nobody has volunteered to fix them in a long time <more> [...]

Edit: FreeBSD 12.2-RELEASE is EoL (End of Life), see Prior Releases Which Have Reached End-Of-Life and the support matrix at Supported FreeBSD releases. You should upgrade to 12.3-RELEASE, if you want to stay with major version 12.

** Edit: added quote from ntpd(8) about combo use of ntpdate(8) and ntpd(8) at start up ("mediocre hack"); including "Starting NTP (Best Current Practice)"
 
Last edited:
Thanks for your suggestions.

Further testing shows that over time (about an hour), the ntpd time sync brings down the time gap enough to allow the windguard client-server handshake to succeed. So a revised problem statement would be "After reboot, Wireguard client-server handshake fails due to client system clock being out of sync. Handshake eventually succeeds, but results in a too long window of inactive connectivity."

gpw928 :
Regarding the rc.d service execution order, adding condition 'REQUIRE: NETWORKING ntpd' to file '/usr/local/etc/rc.d/wireguard' makes ntpd start before wireguard.

Code:
rcorder /etc/rc.d/* /usr/local/etc/rc.d/
...
/etc/rc.d/DAEMON
/etc/rc.d/ntpd
/usr/local/etc/rc.d/wireguard
...

Erichans :
I took you advise and reviewed any trace of using ntpdate(8). Found none in rc.conf, service is not enabled, and a ps -aux shows no evidence of it running. Using 'ntpd_sync_on_start="YES" ' is the same as the ntpd(8) '--panicgate' switch AFAIK.
Here is my /etc/rc.conf for reference:
Code:
hostname="wireguard"
keymap="se"
ifconfig_DEFAULT="DHCP"

# ntpd - adjusts time gradually during operation
ntpd_enable="YES"
ntpd_sync_on_start="YES"

# Wifi
wlans_rtwn0="wlan0"
ifconfig_wlan0="WPA SYNCDHCP"

sshd_enable="YES"
sendmail_enable="NONE"
sendmail_submit_enable="NO"
sendmail_outbound_enable="NO"
sendmail_msp_queue_enable="NO"
growfs_enable="YES"

# Wireguard
wireguard_interfaces="wg0"
wireguard_enable="YES"
defaultrouter="10.0.70.1"


Wireguard package:
Code:
wireguard-2,1
Name           : wireguard
Version        : 2,1
Installed on   : Sun Apr 10 12:12:34 2022 CEST
Origin         : net/wireguard
Architecture   : FreeBSD:12:*

Wireguard interface:
Code:
ifconfig wg0
wg0: flags=80c1<UP,RUNNING,NOARP,MULTICAST> metric 0 mtu 1420
    options=80000<LINKSTATE>
    inet 10.0.70.2 netmask 0xffffff00
    groups: wg
    nd6 options=109<PERFORMNUD,IFDISABLED,NO_DAD>
Code:
wg
interface: wg0
  public key: <public key redacted>
  listening port: 20924

peer: <public key redacted>
  endpoint: <public ip address redacted>
  allowed ips: 0.0.0.0/0
  latest handshake: 1 minute, 31 seconds ago (*)
  transfer: 1.13 MiB received, 443.61 KiB sent
  persistent keepalive: every 15 seconds
* This line is omitted from command output if the handshake has never succeeded.
Code:
netstat -rn
Routing tables

Internet:
Destination        Gateway            Flags     Netif Expire
0.0.0.0/1          wg0                US          wg0
default            192.168.0.1        UGS         ue0
10.0.70.0/24       link#4             U           wg0
10.0.70.2          link#4             UHS         lo0
<wireguard server's public ip address redacted>       192.168.0.1        UGHS        ue0
127.0.0.1          link#1             UH          lo0
128.0.0.0/1        wg0                US          wg0
192.168.0.0/24     link#2             U           ue0
192.168.0.100      link#2             UHS         lo0
192.168.0.101      link#3             UHS         lo0

For future reference for anyone who wants to determine the root cause to this condition:

Detecting the handshake issue:
  • 'wg' command output does not include a line starting with 'latest handshake'
  • Remote wireguard server's IP address cannot be pinged from client side
Confirming unsynched system clock as root cause:
  • 'date' command comparision between client- and server hosts shows misalignment
Accelerating the ntpd sync window would definitely help. The effects of the issue could also be reduced if there was a way of postponing the wireguard script start relative to the ntpd script start in the rc.d framework. But to the best of my knowledge the framework does not support that, or?
 
Yes, it would seem that ntpdate_enable is in planned obsolescence, and definitely the wrong way to sync time at boot.

I see that setting ntpd_sync_on_start="YES" in /etc/rc.conf invokes ntpd with the "-g" option, which allows a radical clock slew just once (at startup).

Setting "tinker panic 0" in /etc/ntp.conf allows a radical clock slew at any time.

All virtual machines should set "tinker panic 0" because they need to allow a radical clock slewing any time, most especially after a VMotion (or equivalent).

VMs should thus not need ntpd_sync_on_start="YES". However they definitely need to be configured with enough up-steam time servers to be able to readily identify (and out-vote) "false tickers", because a radical slew to the wrong time is highly undesirable.
 
gpw928 :
Regarding the rc.d service execution order, adding condition 'REQUIRE: NETWORKING ntpd' to file '/usr/local/etc/rc.d/wireguard' makes ntpd start before wireguard.
I appreciate that. I also see that /etc/rc.d/ntpd REQUIREs ntpdate, so if you have ntpdate_enable="YES" in /etc/rc.conf, you should get a one-time execution of ntpdate(8) prior to ntpd(8) starting.

That might just be exactly what you need to expedite the synchronisation... and ntpdate is just deprecated, not obsolete...

Also, please consider how time servers are chosen at either end of the VPN.

Do you have control of both hosts? Is so, you can choose the time servers they use. You could even let them serve time to each other (as peers).

If you don't have control at both ends, you can still choose a quality time source at the end you do control. Think tier 1.

ntpdate requires an NTP server to sync from. You can specify it explicitly in /etc/rc.conf with ntpdate_hosts="ntp-tier1-host ...".

You can also temporarily add a bunch of public tier 1 hosts with "server" directives (before any "pool" directives) in /etc/ntp.conf, and use ntpq -pn | grep "^*" to see which ones get chosen as best for your situation. Then pick that one for ntpdate to use.
 
Back
Top