Skip to main content

Build a NTP Timeserver Client in Go

Shenzhen, China

I used Docker to build a Go-based NTS Timeserver Server by @hacklunch and deployed the service using Hashicorp Nomad. Now I need to compile the binary for an ARM environment so that it can be used on an IoT device.

Related

Test Build the Binary

build.sh

#!/usr/bin/bash
archs=(amd64 arm64 arm)

for arch in ${archs[@]}
do
        env GOOS=linux GOARCH=${arch} go build -ldflags "-s -w" -o build/ntsclient_${arch}
        upx --ultra-brute -obuild/ntsclient_upx_${arch} build/ntsclient_${arch}
done
./build.sh

                       Ultimate Packer for eXecutables
                          Copyright (C) 1996 - 2020
UPX git-d7ba31+ Markus Oberhumer, Laszlo Molnar & John Reiser   Jan 23rd 2020

        File size         Ratio      Format      Name
   --------------------   ------   -----------   -----------
   5554176 ->   1734704   31.23%   linux/amd64   ntsclient_upx_amd64           

Packed 1 file.

        File size         Ratio      Format      Name
   --------------------   ------   -----------   -----------
   5242880 ->   1494584   28.51%   linux/arm64   ntsclient_upx_arm64           

Packed 1 file.

        File size         Ratio      Format      Name
   --------------------   ------   -----------   -----------
   5373952 ->   1443108   26.85%    linux/arm    ntsclient_upx_arm 

Run the Binary

ntsclient does not output anything when querying and setting the time, unless something goes wrong (or debug output is turned on). An example configuration file looks like:

ntsclient.toml

# NTS Server
server="time.cloudflare.com"
# Interval in seconds between queries
interval=1000

# Alternative NTS Server

# https://netnod.se
#server="nts.ntp.se"

# https://nts.time.nl/
#server="nts.time.nl"

# Test servers listed on https://docs.ntpsec.org/latest/NTS-QuickStart.html
#server="ntp1.glypnod.com"
#server="ntp2.glypnod.com"
./ntsclient --config ./ntsclient.toml
Could not set system time: operation not permitted

sudo ./ntsclient --config ./ntsclient.toml

To switch on the debug mode:

sudo ./ntsclient --config ./ntsclient.toml --debug

Use Gitlab CI to Build the Binary

The following CI file generates the ARM version of the ntsclient and stores it as an artifact to be used in a firmware build pipeline:

.gitlab-ci.yml

image: golang:latest

variables:
  REPO: my.gitlab.com
  GROUP: firmware
  PROJECT: ntsclient
  ARCH: arm

stages:
 - build

before_script:
  # Something strange to make Gitlab like Go
  - mkdir -p $GOPATH/src/$REPO/$GROUP $GOPATH/src/_/builds
  - cp -r $CI_PROJECT_DIR $GOPATH/src/$REPO/$GROUP/$PROJECT
  - ln -s $GOPATH/src/$REPO/$GROUP $GOPATH/src/_/builds/$GROUP
  # Use UPX to compress the binary after build
  # I downloaded/un-tar'ed the latest release into the repo root dir
  - cp ./upx-4.0.0-amd64_linux/upx /usr/bin/npx
  - chmod +x /usr/bin/npx
  # Make sure all Go build dependencies are available
  - go get -v -d ./...

build:
  stage: build
  script:
    - env GOOS=linux GOARCH=$ARCH go build -ldflags "-s -w" -o ntsclient_src
    - /usr/bin/npx --ultra-brute -ontsclient ntsclient_src
  only:
    - main
  artifacts:
    paths:
      # Push the binary into your repo's build artifacts
      - /builds/firmware/ntsclient/ntsclient
    expire_in: 1 day