summaryrefslogtreecommitdiffhomepage
path: root/release
diff options
context:
space:
mode:
authorNick Khyl <nickk@tailscale.com>2024-12-05 13:16:48 -0600
committerNick Khyl <nickk@tailscale.com>2024-12-05 13:16:48 -0600
commit0267fe83b200f1702a2fa0a395442c02a053fadb (patch)
tree63654c55225eeb834de59a5a0bc8d19033c6145b /release
parent87546a5edf6b6503a87eeb2d666baba57398a066 (diff)
downloadtailscale-1.78.0.tar.xz
tailscale-1.78.0.zip
VERSION.txt: this is v1.78.0v1.78.0
Signed-off-by: Nick Khyl <nickk@tailscale.com>
Diffstat (limited to 'release')
-rwxr-xr-xrelease/deb/debian.postrm.sh34
-rwxr-xr-xrelease/deb/debian.prerm.sh14
-rw-r--r--release/dist/memoize.go172
-rw-r--r--release/dist/synology/files/Tailscale.sc10
-rw-r--r--release/dist/synology/files/config22
-rwxr-xr-xrelease/dist/synology/files/index.cgi4
-rw-r--r--release/dist/synology/files/logrotate-dsm616
-rw-r--r--release/dist/synology/files/logrotate-dsm716
-rw-r--r--release/dist/synology/files/privilege-dsm614
-rw-r--r--release/dist/synology/files/privilege-dsm714
-rw-r--r--release/dist/synology/files/privilege-dsm7.for-package-center26
-rw-r--r--release/dist/synology/files/resource20
-rw-r--r--release/dist/synology/files/scripts/postupgrade4
-rw-r--r--release/dist/synology/files/scripts/preupgrade4
-rwxr-xr-xrelease/dist/synology/files/scripts/start-stop-status258
-rw-r--r--release/dist/unixpkgs/pkgs.go944
-rw-r--r--release/dist/unixpkgs/targets.go254
-rw-r--r--release/release.go30
-rwxr-xr-xrelease/rpm/rpm.postinst.sh82
-rwxr-xr-xrelease/rpm/rpm.postrm.sh16
-rwxr-xr-xrelease/rpm/rpm.prerm.sh16
21 files changed, 985 insertions, 985 deletions
diff --git a/release/deb/debian.postrm.sh b/release/deb/debian.postrm.sh
index f4dd4ed9c..93d90b0ea 100755
--- a/release/deb/debian.postrm.sh
+++ b/release/deb/debian.postrm.sh
@@ -1,17 +1,17 @@
-#!/bin/sh
-set -e
-if [ -d /run/systemd/system ] ; then
- systemctl --system daemon-reload >/dev/null || true
-fi
-
-if [ -x "/usr/bin/deb-systemd-helper" ]; then
- if [ "$1" = "remove" ]; then
- deb-systemd-helper mask 'tailscaled.service' >/dev/null || true
- fi
-
- if [ "$1" = "purge" ]; then
- deb-systemd-helper purge 'tailscaled.service' >/dev/null || true
- deb-systemd-helper unmask 'tailscaled.service' >/dev/null || true
- rm -rf /var/lib/tailscale
- fi
-fi
+#!/bin/sh
+set -e
+if [ -d /run/systemd/system ] ; then
+ systemctl --system daemon-reload >/dev/null || true
+fi
+
+if [ -x "/usr/bin/deb-systemd-helper" ]; then
+ if [ "$1" = "remove" ]; then
+ deb-systemd-helper mask 'tailscaled.service' >/dev/null || true
+ fi
+
+ if [ "$1" = "purge" ]; then
+ deb-systemd-helper purge 'tailscaled.service' >/dev/null || true
+ deb-systemd-helper unmask 'tailscaled.service' >/dev/null || true
+ rm -rf /var/lib/tailscale
+ fi
+fi
diff --git a/release/deb/debian.prerm.sh b/release/deb/debian.prerm.sh
index 9be58ede4..a712a08c8 100755
--- a/release/deb/debian.prerm.sh
+++ b/release/deb/debian.prerm.sh
@@ -1,7 +1,7 @@
-#!/bin/sh
-set -e
-if [ "$1" = "remove" ]; then
- if [ -d /run/systemd/system ]; then
- deb-systemd-invoke stop 'tailscaled.service' >/dev/null || true
- fi
-fi
+#!/bin/sh
+set -e
+if [ "$1" = "remove" ]; then
+ if [ -d /run/systemd/system ]; then
+ deb-systemd-invoke stop 'tailscaled.service' >/dev/null || true
+ fi
+fi
diff --git a/release/dist/memoize.go b/release/dist/memoize.go
index 0927ac0a8..f148cd2b7 100644
--- a/release/dist/memoize.go
+++ b/release/dist/memoize.go
@@ -1,86 +1,86 @@
-// Copyright (c) Tailscale Inc & AUTHORS
-// SPDX-License-Identifier: BSD-3-Clause
-
-package dist
-
-import (
- "sync"
-
- "tailscale.com/util/deephash"
-)
-
-// MemoizedFn is a function that memoize.Do can call.
-type MemoizedFn[T any] func() (T, error)
-
-// Memoize runs MemoizedFns and remembers their results.
-type Memoize[O any] struct {
- mu sync.Mutex
- cond *sync.Cond
- outs map[deephash.Sum]O
- errs map[deephash.Sum]error
- inflight map[deephash.Sum]bool
-}
-
-// Do runs fn and returns its result.
-// fn is only run once per unique key. Subsequent Do calls with the same key
-// return the memoized result of the first call, even if fn is a different
-// function.
-func (m *Memoize[O]) Do(key any, fn MemoizedFn[O]) (ret O, err error) {
- m.mu.Lock()
- defer m.mu.Unlock()
- if m.cond == nil {
- m.cond = sync.NewCond(&m.mu)
- m.outs = map[deephash.Sum]O{}
- m.errs = map[deephash.Sum]error{}
- m.inflight = map[deephash.Sum]bool{}
- }
-
- k := deephash.Hash(&key)
-
- for m.inflight[k] {
- m.cond.Wait()
- }
- if err := m.errs[k]; err != nil {
- var ret O
- return ret, err
- }
- if ret, ok := m.outs[k]; ok {
- return ret, nil
- }
-
- m.inflight[k] = true
- m.mu.Unlock()
- defer func() {
- m.mu.Lock()
- delete(m.inflight, k)
- if err != nil {
- m.errs[k] = err
- } else {
- m.outs[k] = ret
- }
- m.cond.Broadcast()
- }()
-
- ret, err = fn()
- if err != nil {
- var ret O
- return ret, err
- }
- return ret, nil
-}
-
-// once is like memoize, but for functions that don't return non-error values.
-type once struct {
- m Memoize[any]
-}
-
-// Do runs fn.
-// fn is only run once per unique key. Subsequent Do calls with the same key
-// return the memoized result of the first call, even if fn is a different
-// function.
-func (o *once) Do(key any, fn func() error) error {
- _, err := o.m.Do(key, func() (any, error) {
- return nil, fn()
- })
- return err
-}
+// Copyright (c) Tailscale Inc & AUTHORS
+// SPDX-License-Identifier: BSD-3-Clause
+
+package dist
+
+import (
+ "sync"
+
+ "tailscale.com/util/deephash"
+)
+
+// MemoizedFn is a function that memoize.Do can call.
+type MemoizedFn[T any] func() (T, error)
+
+// Memoize runs MemoizedFns and remembers their results.
+type Memoize[O any] struct {
+ mu sync.Mutex
+ cond *sync.Cond
+ outs map[deephash.Sum]O
+ errs map[deephash.Sum]error
+ inflight map[deephash.Sum]bool
+}
+
+// Do runs fn and returns its result.
+// fn is only run once per unique key. Subsequent Do calls with the same key
+// return the memoized result of the first call, even if fn is a different
+// function.
+func (m *Memoize[O]) Do(key any, fn MemoizedFn[O]) (ret O, err error) {
+ m.mu.Lock()
+ defer m.mu.Unlock()
+ if m.cond == nil {
+ m.cond = sync.NewCond(&m.mu)
+ m.outs = map[deephash.Sum]O{}
+ m.errs = map[deephash.Sum]error{}
+ m.inflight = map[deephash.Sum]bool{}
+ }
+
+ k := deephash.Hash(&key)
+
+ for m.inflight[k] {
+ m.cond.Wait()
+ }
+ if err := m.errs[k]; err != nil {
+ var ret O
+ return ret, err
+ }
+ if ret, ok := m.outs[k]; ok {
+ return ret, nil
+ }
+
+ m.inflight[k] = true
+ m.mu.Unlock()
+ defer func() {
+ m.mu.Lock()
+ delete(m.inflight, k)
+ if err != nil {
+ m.errs[k] = err
+ } else {
+ m.outs[k] = ret
+ }
+ m.cond.Broadcast()
+ }()
+
+ ret, err = fn()
+ if err != nil {
+ var ret O
+ return ret, err
+ }
+ return ret, nil
+}
+
+// once is like memoize, but for functions that don't return non-error values.
+type once struct {
+ m Memoize[any]
+}
+
+// Do runs fn.
+// fn is only run once per unique key. Subsequent Do calls with the same key
+// return the memoized result of the first call, even if fn is a different
+// function.
+func (o *once) Do(key any, fn func() error) error {
+ _, err := o.m.Do(key, func() (any, error) {
+ return nil, fn()
+ })
+ return err
+}
diff --git a/release/dist/synology/files/Tailscale.sc b/release/dist/synology/files/Tailscale.sc
index 707ac6bb0..f3bb1f0bd 100644
--- a/release/dist/synology/files/Tailscale.sc
+++ b/release/dist/synology/files/Tailscale.sc
@@ -1,6 +1,6 @@
-[Tailscale]
-title="Tailscale"
-desc="Tailscale VPN"
-port_forward="no"
-src.ports="41641/udp"
+[Tailscale]
+title="Tailscale"
+desc="Tailscale VPN"
+port_forward="no"
+src.ports="41641/udp"
dst.ports="41641/udp" \ No newline at end of file
diff --git a/release/dist/synology/files/config b/release/dist/synology/files/config
index 4dbc48dfb..1cf1a6cfa 100644
--- a/release/dist/synology/files/config
+++ b/release/dist/synology/files/config
@@ -1,11 +1,11 @@
-{
- ".url": {
- "SYNO.SDS.Tailscale": {
- "type": "url",
- "title": "Tailscale",
- "icon": "PACKAGE_ICON_256.PNG",
- "url": "webman/3rdparty/Tailscale/index.cgi/",
- "urlTarget": "_syno_tailscale"
- }
- }
-}
+{
+ ".url": {
+ "SYNO.SDS.Tailscale": {
+ "type": "url",
+ "title": "Tailscale",
+ "icon": "PACKAGE_ICON_256.PNG",
+ "url": "webman/3rdparty/Tailscale/index.cgi/",
+ "urlTarget": "_syno_tailscale"
+ }
+ }
+}
diff --git a/release/dist/synology/files/index.cgi b/release/dist/synology/files/index.cgi
index 2c1990cfd..996160d1d 100755
--- a/release/dist/synology/files/index.cgi
+++ b/release/dist/synology/files/index.cgi
@@ -1,2 +1,2 @@
-#! /bin/sh
-exec /var/packages/Tailscale/target/bin/tailscale web -cgi -prefix="/webman/3rdparty/Tailscale/index.cgi/"
+#! /bin/sh
+exec /var/packages/Tailscale/target/bin/tailscale web -cgi -prefix="/webman/3rdparty/Tailscale/index.cgi/"
diff --git a/release/dist/synology/files/logrotate-dsm6 b/release/dist/synology/files/logrotate-dsm6
index 2df64283a..a52a6ba24 100644
--- a/release/dist/synology/files/logrotate-dsm6
+++ b/release/dist/synology/files/logrotate-dsm6
@@ -1,8 +1,8 @@
-/var/packages/Tailscale/etc/tailscaled.stdout.log {
- size 10M
- rotate 3
- missingok
- copytruncate
- compress
- notifempty
-}
+/var/packages/Tailscale/etc/tailscaled.stdout.log {
+ size 10M
+ rotate 3
+ missingok
+ copytruncate
+ compress
+ notifempty
+}
diff --git a/release/dist/synology/files/logrotate-dsm7 b/release/dist/synology/files/logrotate-dsm7
index 7020dc925..3fe677510 100644
--- a/release/dist/synology/files/logrotate-dsm7
+++ b/release/dist/synology/files/logrotate-dsm7
@@ -1,8 +1,8 @@
-/var/packages/Tailscale/var/tailscaled.stdout.log {
- size 10M
- rotate 3
- missingok
- copytruncate
- compress
- notifempty
-}
+/var/packages/Tailscale/var/tailscaled.stdout.log {
+ size 10M
+ rotate 3
+ missingok
+ copytruncate
+ compress
+ notifempty
+}
diff --git a/release/dist/synology/files/privilege-dsm6 b/release/dist/synology/files/privilege-dsm6
index 4b6fe093a..c638528d1 100644
--- a/release/dist/synology/files/privilege-dsm6
+++ b/release/dist/synology/files/privilege-dsm6
@@ -1,7 +1,7 @@
-{
- "defaults":{
- "run-as": "root"
- },
- "username": "tailscale",
- "groupname": "tailscale"
-}
+{
+ "defaults":{
+ "run-as": "root"
+ },
+ "username": "tailscale",
+ "groupname": "tailscale"
+}
diff --git a/release/dist/synology/files/privilege-dsm7 b/release/dist/synology/files/privilege-dsm7
index 93a9c4f7d..4eca66cff 100644
--- a/release/dist/synology/files/privilege-dsm7
+++ b/release/dist/synology/files/privilege-dsm7
@@ -1,7 +1,7 @@
-{
- "defaults":{
- "run-as": "package"
- },
- "username": "tailscale",
- "groupname": "tailscale"
-}
+{
+ "defaults":{
+ "run-as": "package"
+ },
+ "username": "tailscale",
+ "groupname": "tailscale"
+}
diff --git a/release/dist/synology/files/privilege-dsm7.for-package-center b/release/dist/synology/files/privilege-dsm7.for-package-center
index db1468346..b2f93cee1 100644
--- a/release/dist/synology/files/privilege-dsm7.for-package-center
+++ b/release/dist/synology/files/privilege-dsm7.for-package-center
@@ -1,13 +1,13 @@
-{
- "defaults":{
- "run-as": "package"
- },
- "username": "tailscale",
- "groupname": "tailscale",
- "tool": [{
- "relpath": "bin/tailscaled",
- "user": "package",
- "group": "package",
- "capabilities": "cap_net_admin,cap_chown,cap_net_raw"
- }]
-}
+{
+ "defaults":{
+ "run-as": "package"
+ },
+ "username": "tailscale",
+ "groupname": "tailscale",
+ "tool": [{
+ "relpath": "bin/tailscaled",
+ "user": "package",
+ "group": "package",
+ "capabilities": "cap_net_admin,cap_chown,cap_net_raw"
+ }]
+}
diff --git a/release/dist/synology/files/resource b/release/dist/synology/files/resource
index 0da0002ef..706c97671 100644
--- a/release/dist/synology/files/resource
+++ b/release/dist/synology/files/resource
@@ -1,11 +1,11 @@
-{
- "port-config": {
- "protocol-file": "conf/Tailscale.sc"
- },
- "usr-local-linker": {
- "bin": ["bin/tailscale"]
- },
- "syslog-config": {
- "logrotate-relpath": "conf/logrotate.conf"
- }
+{
+ "port-config": {
+ "protocol-file": "conf/Tailscale.sc"
+ },
+ "usr-local-linker": {
+ "bin": ["bin/tailscale"]
+ },
+ "syslog-config": {
+ "logrotate-relpath": "conf/logrotate.conf"
+ }
} \ No newline at end of file
diff --git a/release/dist/synology/files/scripts/postupgrade b/release/dist/synology/files/scripts/postupgrade
index 92b94c40c..2a7fba5b6 100644
--- a/release/dist/synology/files/scripts/postupgrade
+++ b/release/dist/synology/files/scripts/postupgrade
@@ -1,3 +1,3 @@
-#!/bin/sh
-
+#!/bin/sh
+
exit 0 \ No newline at end of file
diff --git a/release/dist/synology/files/scripts/preupgrade b/release/dist/synology/files/scripts/preupgrade
index 92b94c40c..2a7fba5b6 100644
--- a/release/dist/synology/files/scripts/preupgrade
+++ b/release/dist/synology/files/scripts/preupgrade
@@ -1,3 +1,3 @@
-#!/bin/sh
-
+#!/bin/sh
+
exit 0 \ No newline at end of file
diff --git a/release/dist/synology/files/scripts/start-stop-status b/release/dist/synology/files/scripts/start-stop-status
index e6ece04e3..311f9293b 100755
--- a/release/dist/synology/files/scripts/start-stop-status
+++ b/release/dist/synology/files/scripts/start-stop-status
@@ -1,129 +1,129 @@
-#!/bin/bash
-
-SERVICE_NAME="tailscale"
-
-if [ "${SYNOPKG_DSM_VERSION_MAJOR}" -eq "6" ]; then
- PKGVAR="/var/packages/Tailscale/etc"
-else
- PKGVAR="${SYNOPKG_PKGVAR}"
-fi
-
-PID_FILE="${PKGVAR}/tailscaled.pid"
-LOG_FILE="${PKGVAR}/tailscaled.stdout.log"
-STATE_FILE="${PKGVAR}/tailscaled.state"
-SOCKET_FILE="${PKGVAR}/tailscaled.sock"
-PORT="41641"
-
-SERVICE_COMMAND="${SYNOPKG_PKGDEST}/bin/tailscaled \
---state=${STATE_FILE} \
---socket=${SOCKET_FILE} \
---port=$PORT"
-
-if [ "${SYNOPKG_DSM_VERSION_MAJOR}" -eq "7" -a ! -e "/dev/net/tun" ]; then
- # TODO(maisem/crawshaw): Disable the tun device in DSM7 for now.
- SERVICE_COMMAND="${SERVICE_COMMAND} --tun=userspace-networking"
-fi
-
-if [ "${SYNOPKG_DSM_VERSION_MAJOR}" -eq "6" ]; then
- chown -R tailscale:tailscale "${PKGVAR}/"
-fi
-
-start_daemon() {
- local ts=$(date --iso-8601=second)
- echo "${ts} Starting ${SERVICE_NAME} with: ${SERVICE_COMMAND}" >${LOG_FILE}
- STATE_DIRECTORY=${PKGVAR} ${SERVICE_COMMAND} 2>&1 | sed -u '1,200p;201s,.*,[further tailscaled logs suppressed],p;d' >>${LOG_FILE} &
- # We pipe tailscaled's output to sed, so "$!" retrieves the PID of sed not tailscaled.
- # Use jobs -p to retrieve the PID of the most recent process group leader.
- jobs -p >"${PID_FILE}"
-}
-
-stop_daemon() {
- if [ -r "${PID_FILE}" ]; then
- local PID=$(cat "${PID_FILE}")
- local ts=$(date --iso-8601=second)
- echo "${ts} Stopping ${SERVICE_NAME} service PID=${PID}" >>${LOG_FILE}
- kill -TERM $PID >>${LOG_FILE} 2>&1
- wait_for_status 1 || kill -KILL $PID >>${LOG_FILE} 2>&1
- rm -f "${PID_FILE}" >/dev/null
- fi
-}
-
-daemon_status() {
- if [ -r "${PID_FILE}" ]; then
- local PID=$(cat "${PID_FILE}")
- if ps -o pid -p ${PID} > /dev/null; then
- return
- fi
- rm -f "${PID_FILE}" >/dev/null
- fi
- return 1
-}
-
-wait_for_status() {
- # 20 tries
- # sleeps for 1 second after each try
- local counter=20
- while [ ${counter} -gt 0 ]; do
- daemon_status
- [ $? -eq $1 ] && return
- counter=$((counter - 1))
- sleep 1
- done
- return 1
-}
-
-ensure_tun_created() {
- if [ "${SYNOPKG_DSM_VERSION_MAJOR}" -eq "7" ]; then
- # TODO(maisem/crawshaw): Disable the tun device in DSM7 for now.
- return
- fi
- # Create the necessary file structure for /dev/net/tun
- if ([ ! -c /dev/net/tun ]); then
- if ([ ! -d /dev/net ]); then
- mkdir -m 755 /dev/net
- fi
- mknod /dev/net/tun c 10 200
- chmod 0755 /dev/net/tun
- fi
-
- # Load the tun module if not already loaded
- if (!(lsmod | grep -q "^tun\s")); then
- insmod /lib/modules/tun.ko
- fi
-}
-
-case $1 in
-start)
- if daemon_status; then
- exit 0
- else
- ensure_tun_created
- start_daemon
- exit $?
- fi
- ;;
-stop)
- if daemon_status; then
- stop_daemon
- exit $?
- else
- exit 0
- fi
- ;;
-status)
- if daemon_status; then
- echo "${SERVICE_NAME} is running"
- exit 0
- else
- echo "${SERVICE_NAME} is not running"
- exit 3
- fi
- ;;
-log)
- exit 0
- ;;
-*)
- echo "command $1 is not implemented"
- exit 0
- ;;
-esac
+#!/bin/bash
+
+SERVICE_NAME="tailscale"
+
+if [ "${SYNOPKG_DSM_VERSION_MAJOR}" -eq "6" ]; then
+ PKGVAR="/var/packages/Tailscale/etc"
+else
+ PKGVAR="${SYNOPKG_PKGVAR}"
+fi
+
+PID_FILE="${PKGVAR}/tailscaled.pid"
+LOG_FILE="${PKGVAR}/tailscaled.stdout.log"
+STATE_FILE="${PKGVAR}/tailscaled.state"
+SOCKET_FILE="${PKGVAR}/tailscaled.sock"
+PORT="41641"
+
+SERVICE_COMMAND="${SYNOPKG_PKGDEST}/bin/tailscaled \
+--state=${STATE_FILE} \
+--socket=${SOCKET_FILE} \
+--port=$PORT"
+
+if [ "${SYNOPKG_DSM_VERSION_MAJOR}" -eq "7" -a ! -e "/dev/net/tun" ]; then
+ # TODO(maisem/crawshaw): Disable the tun device in DSM7 for now.
+ SERVICE_COMMAND="${SERVICE_COMMAND} --tun=userspace-networking"
+fi
+
+if [ "${SYNOPKG_DSM_VERSION_MAJOR}" -eq "6" ]; then
+ chown -R tailscale:tailscale "${PKGVAR}/"
+fi
+
+start_daemon() {
+ local ts=$(date --iso-8601=second)
+ echo "${ts} Starting ${SERVICE_NAME} with: ${SERVICE_COMMAND}" >${LOG_FILE}
+ STATE_DIRECTORY=${PKGVAR} ${SERVICE_COMMAND} 2>&1 | sed -u '1,200p;201s,.*,[further tailscaled logs suppressed],p;d' >>${LOG_FILE} &
+ # We pipe tailscaled's output to sed, so "$!" retrieves the PID of sed not tailscaled.
+ # Use jobs -p to retrieve the PID of the most recent process group leader.
+ jobs -p >"${PID_FILE}"
+}
+
+stop_daemon() {
+ if [ -r "${PID_FILE}" ]; then
+ local PID=$(cat "${PID_FILE}")
+ local ts=$(date --iso-8601=second)
+ echo "${ts} Stopping ${SERVICE_NAME} service PID=${PID}" >>${LOG_FILE}
+ kill -TERM $PID >>${LOG_FILE} 2>&1
+ wait_for_status 1 || kill -KILL $PID >>${LOG_FILE} 2>&1
+ rm -f "${PID_FILE}" >/dev/null
+ fi
+}
+
+daemon_status() {
+ if [ -r "${PID_FILE}" ]; then
+ local PID=$(cat "${PID_FILE}")
+ if ps -o pid -p ${PID} > /dev/null; then
+ return
+ fi
+ rm -f "${PID_FILE}" >/dev/null
+ fi
+ return 1
+}
+
+wait_for_status() {
+ # 20 tries
+ # sleeps for 1 second after each try
+ local counter=20
+ while [ ${counter} -gt 0 ]; do
+ daemon_status
+ [ $? -eq $1 ] && return
+ counter=$((counter - 1))
+ sleep 1
+ done
+ return 1
+}
+
+ensure_tun_created() {
+ if [ "${SYNOPKG_DSM_VERSION_MAJOR}" -eq "7" ]; then
+ # TODO(maisem/crawshaw): Disable the tun device in DSM7 for now.
+ return
+ fi
+ # Create the necessary file structure for /dev/net/tun
+ if ([ ! -c /dev/net/tun ]); then
+ if ([ ! -d /dev/net ]); then
+ mkdir -m 755 /dev/net
+ fi
+ mknod /dev/net/tun c 10 200
+ chmod 0755 /dev/net/tun
+ fi
+
+ # Load the tun module if not already loaded
+ if (!(lsmod | grep -q "^tun\s")); then
+ insmod /lib/modules/tun.ko
+ fi
+}
+
+case $1 in
+start)
+ if daemon_status; then
+ exit 0
+ else
+ ensure_tun_created
+ start_daemon
+ exit $?
+ fi
+ ;;
+stop)
+ if daemon_status; then
+ stop_daemon
+ exit $?
+ else
+ exit 0
+ fi
+ ;;
+status)
+ if daemon_status; then
+ echo "${SERVICE_NAME} is running"
+ exit 0
+ else
+ echo "${SERVICE_NAME} is not running"
+ exit 3
+ fi
+ ;;
+log)
+ exit 0
+ ;;
+*)
+ echo "command $1 is not implemented"
+ exit 0
+ ;;
+esac
diff --git a/release/dist/unixpkgs/pkgs.go b/release/dist/unixpkgs/pkgs.go
index bad6ce572..60a038eb4 100644
--- a/release/dist/unixpkgs/pkgs.go
+++ b/release/dist/unixpkgs/pkgs.go
@@ -1,472 +1,472 @@
-// Copyright (c) Tailscale Inc & AUTHORS
-// SPDX-License-Identifier: BSD-3-Clause
-
-// Package unixpkgs contains dist Targets for building unix Tailscale packages.
-package unixpkgs
-
-import (
- "archive/tar"
- "compress/gzip"
- "errors"
- "fmt"
- "io"
- "log"
- "os"
- "path/filepath"
- "strings"
-
- "github.com/goreleaser/nfpm/v2"
- "github.com/goreleaser/nfpm/v2/files"
- "tailscale.com/release/dist"
-)
-
-type tgzTarget struct {
- filenameArch string // arch to use in filename instead of deriving from goEnv["GOARCH"]
- goEnv map[string]string
- signer dist.Signer
-}
-
-func (t *tgzTarget) arch() string {
- if t.filenameArch != "" {
- return t.filenameArch
- }
- return t.goEnv["GOARCH"]
-}
-
-func (t *tgzTarget) os() string {
- return t.goEnv["GOOS"]
-}
-
-func (t *tgzTarget) String() string {
- return fmt.Sprintf("%s/%s/tgz", t.os(), t.arch())
-}
-
-func (t *tgzTarget) Build(b *dist.Build) ([]string, error) {
- var filename string
- if t.goEnv["GOOS"] == "linux" {
- // Linux used to be the only tgz architecture, so we didn't put the OS
- // name in the filename.
- filename = fmt.Sprintf("tailscale_%s_%s.tgz", b.Version.Short, t.arch())
- } else {
- filename = fmt.Sprintf("tailscale_%s_%s_%s.tgz", b.Version.Short, t.os(), t.arch())
- }
- if err := b.BuildWebClientAssets(); err != nil {
- return nil, err
- }
- ts, err := b.BuildGoBinary("tailscale.com/cmd/tailscale", t.goEnv)
- if err != nil {
- return nil, err
- }
- tsd, err := b.BuildGoBinary("tailscale.com/cmd/tailscaled", t.goEnv)
- if err != nil {
- return nil, err
- }
-
- log.Printf("Building %s", filename)
-
- out := filepath.Join(b.Out, filename)
- f, err := os.Create(out)
- if err != nil {
- return nil, err
- }
- defer f.Close()
- gw := gzip.NewWriter(f)
- defer gw.Close()
- tw := tar.NewWriter(gw)
- defer tw.Close()
-
- addFile := func(src, dst string, mode int64) error {
- f, err := os.Open(src)
- if err != nil {
- return err
- }
- defer f.Close()
- fi, err := f.Stat()
- if err != nil {
- return err
- }
- hdr := &tar.Header{
- Name: dst,
- Size: fi.Size(),
- Mode: mode,
- ModTime: b.Time,
- Uid: 0,
- Gid: 0,
- Uname: "root",
- Gname: "root",
- }
- if err := tw.WriteHeader(hdr); err != nil {
- return err
- }
- if _, err = io.Copy(tw, f); err != nil {
- return err
- }
- return nil
- }
- addDir := func(name string) error {
- hdr := &tar.Header{
- Name: name + "/",
- Mode: 0755,
- ModTime: b.Time,
- Uid: 0,
- Gid: 0,
- Uname: "root",
- Gname: "root",
- }
- return tw.WriteHeader(hdr)
- }
- dir := strings.TrimSuffix(filename, ".tgz")
- if err := addDir(dir); err != nil {
- return nil, err
- }
- if err := addFile(tsd, filepath.Join(dir, "tailscaled"), 0755); err != nil {
- return nil, err
- }
- if err := addFile(ts, filepath.Join(dir, "tailscale"), 0755); err != nil {
- return nil, err
- }
- if t.os() == "linux" {
- dir = filepath.Join(dir, "systemd")
- if err := addDir(dir); err != nil {
- return nil, err
- }
- tailscaledDir, err := b.GoPkg("tailscale.com/cmd/tailscaled")
- if err != nil {
- return nil, err
- }
- if err := addFile(filepath.Join(tailscaledDir, "tailscaled.service"), filepath.Join(dir, "tailscaled.service"), 0644); err != nil {
- return nil, err
- }
- if err := addFile(filepath.Join(tailscaledDir, "tailscaled.defaults"), filepath.Join(dir, "tailscaled.defaults"), 0644); err != nil {
- return nil, err
- }
- }
- if err := tw.Close(); err != nil {
- return nil, err
- }
- if err := gw.Close(); err != nil {
- return nil, err
- }
- if err := f.Close(); err != nil {
- return nil, err
- }
-
- files := []string{filename}
-
- if t.signer != nil {
- outSig := out + ".sig"
- if err := t.signer.SignFile(out, outSig); err != nil {
- return nil, err
- }
- files = append(files, filepath.Base(outSig))
- }
-
- return files, nil
-}
-
-type debTarget struct {
- goEnv map[string]string
-}
-
-func (t *debTarget) os() string {
- return t.goEnv["GOOS"]
-}
-
-func (t *debTarget) arch() string {
- return t.goEnv["GOARCH"]
-}
-
-func (t *debTarget) String() string {
- return fmt.Sprintf("linux/%s/deb", t.goEnv["GOARCH"])
-}
-
-func (t *debTarget) Build(b *dist.Build) ([]string, error) {
- if t.os() != "linux" {
- return nil, errors.New("deb only supported on linux")
- }
-
- if err := b.BuildWebClientAssets(); err != nil {
- return nil, err
- }
- ts, err := b.BuildGoBinary("tailscale.com/cmd/tailscale", t.goEnv)
- if err != nil {
- return nil, err
- }
- tsd, err := b.BuildGoBinary("tailscale.com/cmd/tailscaled", t.goEnv)
- if err != nil {
- return nil, err
- }
-
- tailscaledDir, err := b.GoPkg("tailscale.com/cmd/tailscaled")
- if err != nil {
- return nil, err
- }
- repoDir, err := b.GoPkg("tailscale.com")
- if err != nil {
- return nil, err
- }
-
- arch := debArch(t.arch())
- contents, err := files.PrepareForPackager(files.Contents{
- &files.Content{
- Type: files.TypeFile,
- Source: ts,
- Destination: "/usr/bin/tailscale",
- },
- &files.Content{
- Type: files.TypeFile,
- Source: tsd,
- Destination: "/usr/sbin/tailscaled",
- },
- &files.Content{
- Type: files.TypeFile,
- Source: filepath.Join(tailscaledDir, "tailscaled.service"),
- Destination: "/lib/systemd/system/tailscaled.service",
- },
- &files.Content{
- Type: files.TypeConfigNoReplace,
- Source: filepath.Join(tailscaledDir, "tailscaled.defaults"),
- Destination: "/etc/default/tailscaled",
- },
- }, 0, "deb", false)
- if err != nil {
- return nil, err
- }
- info := nfpm.WithDefaults(&nfpm.Info{
- Name: "tailscale",
- Arch: arch,
- Platform: "linux",
- Version: b.Version.Short,
- Maintainer: "Tailscale Inc <info@tailscale.com>",
- Description: "The easiest, most secure, cross platform way to use WireGuard + oauth2 + 2FA/SSO",
- Homepage: "https://www.tailscale.com",
- License: "MIT",
- Section: "net",
- Priority: "extra",
- Overridables: nfpm.Overridables{
- Contents: contents,
- Scripts: nfpm.Scripts{
- PostInstall: filepath.Join(repoDir, "release/deb/debian.postinst.sh"),
- PreRemove: filepath.Join(repoDir, "release/deb/debian.prerm.sh"),
- PostRemove: filepath.Join(repoDir, "release/deb/debian.postrm.sh"),
- },
- Depends: []string{
- // iptables is almost always required but not strictly needed.
- // Even if you can technically run Tailscale without it (by
- // manually configuring nftables or userspace mode), we still
- // mark this as "Depends" because our previous experiment in
- // https://github.com/tailscale/tailscale/issues/9236 of making
- // it only Recommends caused too many problems. Until our
- // nftables table is more mature, we'd rather err on the side of
- // wasting a little disk by including iptables for people who
- // might not need it rather than handle reports of it being
- // missing.
- "iptables",
- },
- Recommends: []string{
- "tailscale-archive-keyring (>= 1.35.181)",
- // The "ip" command isn't needed since 2021-11-01 in
- // 408b0923a61972ed but kept as an option as of
- // 2021-11-18 in d24ed3f68e35e802d531371. See
- // https://github.com/tailscale/tailscale/issues/391.
- // We keep it recommended because it's usually
- // installed anyway and it's useful for debugging. But
- // we can live without it, so it's not Depends.
- "iproute2",
- },
- Replaces: []string{"tailscale-relay"},
- Conflicts: []string{"tailscale-relay"},
- },
- })
- pkg, err := nfpm.Get("deb")
- if err != nil {
- return nil, err
- }
-
- filename := fmt.Sprintf("tailscale_%s_%s.deb", b.Version.Short, arch)
- log.Printf("Building %s", filename)
- f, err := os.Create(filepath.Join(b.Out, filename))
- if err != nil {
- return nil, err
- }
- defer f.Close()
- if err := pkg.Package(info, f); err != nil {
- return nil, err
- }
- if err := f.Close(); err != nil {
- return nil, err
- }
-
- return []string{filename}, nil
-}
-
-type rpmTarget struct {
- goEnv map[string]string
- signer dist.Signer
-}
-
-func (t *rpmTarget) os() string {
- return t.goEnv["GOOS"]
-}
-
-func (t *rpmTarget) arch() string {
- return t.goEnv["GOARCH"]
-}
-
-func (t *rpmTarget) String() string {
- return fmt.Sprintf("linux/%s/rpm", t.arch())
-}
-
-func (t *rpmTarget) Build(b *dist.Build) ([]string, error) {
- if t.os() != "linux" {
- return nil, errors.New("rpm only supported on linux")
- }
-
- if err := b.BuildWebClientAssets(); err != nil {
- return nil, err
- }
- ts, err := b.BuildGoBinary("tailscale.com/cmd/tailscale", t.goEnv)
- if err != nil {
- return nil, err
- }
- tsd, err := b.BuildGoBinary("tailscale.com/cmd/tailscaled", t.goEnv)
- if err != nil {
- return nil, err
- }
-
- tailscaledDir, err := b.GoPkg("tailscale.com/cmd/tailscaled")
- if err != nil {
- return nil, err
- }
- repoDir, err := b.GoPkg("tailscale.com")
- if err != nil {
- return nil, err
- }
-
- arch := rpmArch(t.arch())
- contents, err := files.PrepareForPackager(files.Contents{
- &files.Content{
- Type: files.TypeFile,
- Source: ts,
- Destination: "/usr/bin/tailscale",
- },
- &files.Content{
- Type: files.TypeFile,
- Source: tsd,
- Destination: "/usr/sbin/tailscaled",
- },
- &files.Content{
- Type: files.TypeFile,
- Source: filepath.Join(tailscaledDir, "tailscaled.service"),
- Destination: "/lib/systemd/system/tailscaled.service",
- },
- &files.Content{
- Type: files.TypeConfigNoReplace,
- Source: filepath.Join(tailscaledDir, "tailscaled.defaults"),
- Destination: "/etc/default/tailscaled",
- },
- // SELinux policy on e.g. CentOS 8 forbids writing to /var/cache.
- // Creating an empty directory at install time resolves this issue.
- &files.Content{
- Type: files.TypeDir,
- Destination: "/var/cache/tailscale",
- },
- }, 0, "rpm", false)
- if err != nil {
- return nil, err
- }
- info := nfpm.WithDefaults(&nfpm.Info{
- Name: "tailscale",
- Arch: arch,
- Platform: "linux",
- Version: b.Version.Short,
- Maintainer: "Tailscale Inc <info@tailscale.com>",
- Description: "The easiest, most secure, cross platform way to use WireGuard + oauth2 + 2FA/SSO",
- Homepage: "https://www.tailscale.com",
- License: "MIT",
- Overridables: nfpm.Overridables{
- Contents: contents,
- Scripts: nfpm.Scripts{
- PostInstall: filepath.Join(repoDir, "release/rpm/rpm.postinst.sh"),
- PreRemove: filepath.Join(repoDir, "release/rpm/rpm.prerm.sh"),
- PostRemove: filepath.Join(repoDir, "release/rpm/rpm.postrm.sh"),
- },
- Depends: []string{"iptables", "iproute"},
- Replaces: []string{"tailscale-relay"},
- Conflicts: []string{"tailscale-relay"},
- RPM: nfpm.RPM{
- Group: "Network",
- Signature: nfpm.RPMSignature{
- PackageSignature: nfpm.PackageSignature{
- SignFn: t.signer,
- },
- },
- },
- },
- })
- pkg, err := nfpm.Get("rpm")
- if err != nil {
- return nil, err
- }
-
- filename := fmt.Sprintf("tailscale_%s_%s.rpm", b.Version.Short, arch)
- log.Printf("Building %s", filename)
-
- f, err := os.Create(filepath.Join(b.Out, filename))
- if err != nil {
- return nil, err
- }
- defer f.Close()
- if err := pkg.Package(info, f); err != nil {
- return nil, err
- }
- if err := f.Close(); err != nil {
- return nil, err
- }
-
- return []string{filename}, nil
-}
-
-// debArch returns the debian arch name for the given Go arch name.
-// nfpm also does this translation internally, but we need to do it outside nfpm
-// because we also need the filename to be correct.
-func debArch(arch string) string {
- switch arch {
- case "386":
- return "i386"
- case "arm":
- // TODO: this is supposed to be "armel" for GOARM=5, and "armhf" for
- // GOARM=6 and 7. But we have some tech debt to pay off here before we
- // can ship more than 1 ARM deb, so for now match redo's behavior of
- // shipping armv5 binaries in an armv7 trenchcoat.
- return "armhf"
- case "mipsle":
- return "mipsel"
- case "mips64le":
- return "mips64el"
- default:
- return arch
- }
-}
-
-// rpmArch returns the RPM arch name for the given Go arch name.
-// nfpm also does this translation internally, but we need to do it outside nfpm
-// because we also need the filename to be correct.
-func rpmArch(arch string) string {
- switch arch {
- case "amd64":
- return "x86_64"
- case "386":
- return "i386"
- case "arm":
- return "armv7hl"
- case "arm64":
- return "aarch64"
- case "mipsle":
- return "mipsel"
- case "mips64le":
- return "mips64el"
- default:
- return arch
- }
-}
+// Copyright (c) Tailscale Inc & AUTHORS
+// SPDX-License-Identifier: BSD-3-Clause
+
+// Package unixpkgs contains dist Targets for building unix Tailscale packages.
+package unixpkgs
+
+import (
+ "archive/tar"
+ "compress/gzip"
+ "errors"
+ "fmt"
+ "io"
+ "log"
+ "os"
+ "path/filepath"
+ "strings"
+
+ "github.com/goreleaser/nfpm/v2"
+ "github.com/goreleaser/nfpm/v2/files"
+ "tailscale.com/release/dist"
+)
+
+type tgzTarget struct {
+ filenameArch string // arch to use in filename instead of deriving from goEnv["GOARCH"]
+ goEnv map[string]string
+ signer dist.Signer
+}
+
+func (t *tgzTarget) arch() string {
+ if t.filenameArch != "" {
+ return t.filenameArch
+ }
+ return t.goEnv["GOARCH"]
+}
+
+func (t *tgzTarget) os() string {
+ return t.goEnv["GOOS"]
+}
+
+func (t *tgzTarget) String() string {
+ return fmt.Sprintf("%s/%s/tgz", t.os(), t.arch())
+}
+
+func (t *tgzTarget) Build(b *dist.Build) ([]string, error) {
+ var filename string
+ if t.goEnv["GOOS"] == "linux" {
+ // Linux used to be the only tgz architecture, so we didn't put the OS
+ // name in the filename.
+ filename = fmt.Sprintf("tailscale_%s_%s.tgz", b.Version.Short, t.arch())
+ } else {
+ filename = fmt.Sprintf("tailscale_%s_%s_%s.tgz", b.Version.Short, t.os(), t.arch())
+ }
+ if err := b.BuildWebClientAssets(); err != nil {
+ return nil, err
+ }
+ ts, err := b.BuildGoBinary("tailscale.com/cmd/tailscale", t.goEnv)
+ if err != nil {
+ return nil, err
+ }
+ tsd, err := b.BuildGoBinary("tailscale.com/cmd/tailscaled", t.goEnv)
+ if err != nil {
+ return nil, err
+ }
+
+ log.Printf("Building %s", filename)
+
+ out := filepath.Join(b.Out, filename)
+ f, err := os.Create(out)
+ if err != nil {
+ return nil, err
+ }
+ defer f.Close()
+ gw := gzip.NewWriter(f)
+ defer gw.Close()
+ tw := tar.NewWriter(gw)
+ defer tw.Close()
+
+ addFile := func(src, dst string, mode int64) error {
+ f, err := os.Open(src)
+ if err != nil {
+ return err
+ }
+ defer f.Close()
+ fi, err := f.Stat()
+ if err != nil {
+ return err
+ }
+ hdr := &tar.Header{
+ Name: dst,
+ Size: fi.Size(),
+ Mode: mode,
+ ModTime: b.Time,
+ Uid: 0,
+ Gid: 0,
+ Uname: "root",
+ Gname: "root",
+ }
+ if err := tw.WriteHeader(hdr); err != nil {
+ return err
+ }
+ if _, err = io.Copy(tw, f); err != nil {
+ return err
+ }
+ return nil
+ }
+ addDir := func(name string) error {
+ hdr := &tar.Header{
+ Name: name + "/",
+ Mode: 0755,
+ ModTime: b.Time,
+ Uid: 0,
+ Gid: 0,
+ Uname: "root",
+ Gname: "root",
+ }
+ return tw.WriteHeader(hdr)
+ }
+ dir := strings.TrimSuffix(filename, ".tgz")
+ if err := addDir(dir); err != nil {
+ return nil, err
+ }
+ if err := addFile(tsd, filepath.Join(dir, "tailscaled"), 0755); err != nil {
+ return nil, err
+ }
+ if err := addFile(ts, filepath.Join(dir, "tailscale"), 0755); err != nil {
+ return nil, err
+ }
+ if t.os() == "linux" {
+ dir = filepath.Join(dir, "systemd")
+ if err := addDir(dir); err != nil {
+ return nil, err
+ }
+ tailscaledDir, err := b.GoPkg("tailscale.com/cmd/tailscaled")
+ if err != nil {
+ return nil, err
+ }
+ if err := addFile(filepath.Join(tailscaledDir, "tailscaled.service"), filepath.Join(dir, "tailscaled.service"), 0644); err != nil {
+ return nil, err
+ }
+ if err := addFile(filepath.Join(tailscaledDir, "tailscaled.defaults"), filepath.Join(dir, "tailscaled.defaults"), 0644); err != nil {
+ return nil, err
+ }
+ }
+ if err := tw.Close(); err != nil {
+ return nil, err
+ }
+ if err := gw.Close(); err != nil {
+ return nil, err
+ }
+ if err := f.Close(); err != nil {
+ return nil, err
+ }
+
+ files := []string{filename}
+
+ if t.signer != nil {
+ outSig := out + ".sig"
+ if err := t.signer.SignFile(out, outSig); err != nil {
+ return nil, err
+ }
+ files = append(files, filepath.Base(outSig))
+ }
+
+ return files, nil
+}
+
+type debTarget struct {
+ goEnv map[string]string
+}
+
+func (t *debTarget) os() string {
+ return t.goEnv["GOOS"]
+}
+
+func (t *debTarget) arch() string {
+ return t.goEnv["GOARCH"]
+}
+
+func (t *debTarget) String() string {
+ return fmt.Sprintf("linux/%s/deb", t.goEnv["GOARCH"])
+}
+
+func (t *debTarget) Build(b *dist.Build) ([]string, error) {
+ if t.os() != "linux" {
+ return nil, errors.New("deb only supported on linux")
+ }
+
+ if err := b.BuildWebClientAssets(); err != nil {
+ return nil, err
+ }
+ ts, err := b.BuildGoBinary("tailscale.com/cmd/tailscale", t.goEnv)
+ if err != nil {
+ return nil, err
+ }
+ tsd, err := b.BuildGoBinary("tailscale.com/cmd/tailscaled", t.goEnv)
+ if err != nil {
+ return nil, err
+ }
+
+ tailscaledDir, err := b.GoPkg("tailscale.com/cmd/tailscaled")
+ if err != nil {
+ return nil, err
+ }
+ repoDir, err := b.GoPkg("tailscale.com")
+ if err != nil {
+ return nil, err
+ }
+
+ arch := debArch(t.arch())
+ contents, err := files.PrepareForPackager(files.Contents{
+ &files.Content{
+ Type: files.TypeFile,
+ Source: ts,
+ Destination: "/usr/bin/tailscale",
+ },
+ &files.Content{
+ Type: files.TypeFile,
+ Source: tsd,
+ Destination: "/usr/sbin/tailscaled",
+ },
+ &files.Content{
+ Type: files.TypeFile,
+ Source: filepath.Join(tailscaledDir, "tailscaled.service"),
+ Destination: "/lib/systemd/system/tailscaled.service",
+ },
+ &files.Content{
+ Type: files.TypeConfigNoReplace,
+ Source: filepath.Join(tailscaledDir, "tailscaled.defaults"),
+ Destination: "/etc/default/tailscaled",
+ },
+ }, 0, "deb", false)
+ if err != nil {
+ return nil, err
+ }
+ info := nfpm.WithDefaults(&nfpm.Info{
+ Name: "tailscale",
+ Arch: arch,
+ Platform: "linux",
+ Version: b.Version.Short,
+ Maintainer: "Tailscale Inc <info@tailscale.com>",
+ Description: "The easiest, most secure, cross platform way to use WireGuard + oauth2 + 2FA/SSO",
+ Homepage: "https://www.tailscale.com",
+ License: "MIT",
+ Section: "net",
+ Priority: "extra",
+ Overridables: nfpm.Overridables{
+ Contents: contents,
+ Scripts: nfpm.Scripts{
+ PostInstall: filepath.Join(repoDir, "release/deb/debian.postinst.sh"),
+ PreRemove: filepath.Join(repoDir, "release/deb/debian.prerm.sh"),
+ PostRemove: filepath.Join(repoDir, "release/deb/debian.postrm.sh"),
+ },
+ Depends: []string{
+ // iptables is almost always required but not strictly needed.
+ // Even if you can technically run Tailscale without it (by
+ // manually configuring nftables or userspace mode), we still
+ // mark this as "Depends" because our previous experiment in
+ // https://github.com/tailscale/tailscale/issues/9236 of making
+ // it only Recommends caused too many problems. Until our
+ // nftables table is more mature, we'd rather err on the side of
+ // wasting a little disk by including iptables for people who
+ // might not need it rather than handle reports of it being
+ // missing.
+ "iptables",
+ },
+ Recommends: []string{
+ "tailscale-archive-keyring (>= 1.35.181)",
+ // The "ip" command isn't needed since 2021-11-01 in
+ // 408b0923a61972ed but kept as an option as of
+ // 2021-11-18 in d24ed3f68e35e802d531371. See
+ // https://github.com/tailscale/tailscale/issues/391.
+ // We keep it recommended because it's usually
+ // installed anyway and it's useful for debugging. But
+ // we can live without it, so it's not Depends.
+ "iproute2",
+ },
+ Replaces: []string{"tailscale-relay"},
+ Conflicts: []string{"tailscale-relay"},
+ },
+ })
+ pkg, err := nfpm.Get("deb")
+ if err != nil {
+ return nil, err
+ }
+
+ filename := fmt.Sprintf("tailscale_%s_%s.deb", b.Version.Short, arch)
+ log.Printf("Building %s", filename)
+ f, err := os.Create(filepath.Join(b.Out, filename))
+ if err != nil {
+ return nil, err
+ }
+ defer f.Close()
+ if err := pkg.Package(info, f); err != nil {
+ return nil, err
+ }
+ if err := f.Close(); err != nil {
+ return nil, err
+ }
+
+ return []string{filename}, nil
+}
+
+type rpmTarget struct {
+ goEnv map[string]string
+ signer dist.Signer
+}
+
+func (t *rpmTarget) os() string {
+ return t.goEnv["GOOS"]
+}
+
+func (t *rpmTarget) arch() string {
+ return t.goEnv["GOARCH"]
+}
+
+func (t *rpmTarget) String() string {
+ return fmt.Sprintf("linux/%s/rpm", t.arch())
+}
+
+func (t *rpmTarget) Build(b *dist.Build) ([]string, error) {
+ if t.os() != "linux" {
+ return nil, errors.New("rpm only supported on linux")
+ }
+
+ if err := b.BuildWebClientAssets(); err != nil {
+ return nil, err
+ }
+ ts, err := b.BuildGoBinary("tailscale.com/cmd/tailscale", t.goEnv)
+ if err != nil {
+ return nil, err
+ }
+ tsd, err := b.BuildGoBinary("tailscale.com/cmd/tailscaled", t.goEnv)
+ if err != nil {
+ return nil, err
+ }
+
+ tailscaledDir, err := b.GoPkg("tailscale.com/cmd/tailscaled")
+ if err != nil {
+ return nil, err
+ }
+ repoDir, err := b.GoPkg("tailscale.com")
+ if err != nil {
+ return nil, err
+ }
+
+ arch := rpmArch(t.arch())
+ contents, err := files.PrepareForPackager(files.Contents{
+ &files.Content{
+ Type: files.TypeFile,
+ Source: ts,
+ Destination: "/usr/bin/tailscale",
+ },
+ &files.Content{
+ Type: files.TypeFile,
+ Source: tsd,
+ Destination: "/usr/sbin/tailscaled",
+ },
+ &files.Content{
+ Type: files.TypeFile,
+ Source: filepath.Join(tailscaledDir, "tailscaled.service"),
+ Destination: "/lib/systemd/system/tailscaled.service",
+ },
+ &files.Content{
+ Type: files.TypeConfigNoReplace,
+ Source: filepath.Join(tailscaledDir, "tailscaled.defaults"),
+ Destination: "/etc/default/tailscaled",
+ },
+ // SELinux policy on e.g. CentOS 8 forbids writing to /var/cache.
+ // Creating an empty directory at install time resolves this issue.
+ &files.Content{
+ Type: files.TypeDir,
+ Destination: "/var/cache/tailscale",
+ },
+ }, 0, "rpm", false)
+ if err != nil {
+ return nil, err
+ }
+ info := nfpm.WithDefaults(&nfpm.Info{
+ Name: "tailscale",
+ Arch: arch,
+ Platform: "linux",
+ Version: b.Version.Short,
+ Maintainer: "Tailscale Inc <info@tailscale.com>",
+ Description: "The easiest, most secure, cross platform way to use WireGuard + oauth2 + 2FA/SSO",
+ Homepage: "https://www.tailscale.com",
+ License: "MIT",
+ Overridables: nfpm.Overridables{
+ Contents: contents,
+ Scripts: nfpm.Scripts{
+ PostInstall: filepath.Join(repoDir, "release/rpm/rpm.postinst.sh"),
+ PreRemove: filepath.Join(repoDir, "release/rpm/rpm.prerm.sh"),
+ PostRemove: filepath.Join(repoDir, "release/rpm/rpm.postrm.sh"),
+ },
+ Depends: []string{"iptables", "iproute"},
+ Replaces: []string{"tailscale-relay"},
+ Conflicts: []string{"tailscale-relay"},
+ RPM: nfpm.RPM{
+ Group: "Network",
+ Signature: nfpm.RPMSignature{
+ PackageSignature: nfpm.PackageSignature{
+ SignFn: t.signer,
+ },
+ },
+ },
+ },
+ })
+ pkg, err := nfpm.Get("rpm")
+ if err != nil {
+ return nil, err
+ }
+
+ filename := fmt.Sprintf("tailscale_%s_%s.rpm", b.Version.Short, arch)
+ log.Printf("Building %s", filename)
+
+ f, err := os.Create(filepath.Join(b.Out, filename))
+ if err != nil {
+ return nil, err
+ }
+ defer f.Close()
+ if err := pkg.Package(info, f); err != nil {
+ return nil, err
+ }
+ if err := f.Close(); err != nil {
+ return nil, err
+ }
+
+ return []string{filename}, nil
+}
+
+// debArch returns the debian arch name for the given Go arch name.
+// nfpm also does this translation internally, but we need to do it outside nfpm
+// because we also need the filename to be correct.
+func debArch(arch string) string {
+ switch arch {
+ case "386":
+ return "i386"
+ case "arm":
+ // TODO: this is supposed to be "armel" for GOARM=5, and "armhf" for
+ // GOARM=6 and 7. But we have some tech debt to pay off here before we
+ // can ship more than 1 ARM deb, so for now match redo's behavior of
+ // shipping armv5 binaries in an armv7 trenchcoat.
+ return "armhf"
+ case "mipsle":
+ return "mipsel"
+ case "mips64le":
+ return "mips64el"
+ default:
+ return arch
+ }
+}
+
+// rpmArch returns the RPM arch name for the given Go arch name.
+// nfpm also does this translation internally, but we need to do it outside nfpm
+// because we also need the filename to be correct.
+func rpmArch(arch string) string {
+ switch arch {
+ case "amd64":
+ return "x86_64"
+ case "386":
+ return "i386"
+ case "arm":
+ return "armv7hl"
+ case "arm64":
+ return "aarch64"
+ case "mipsle":
+ return "mipsel"
+ case "mips64le":
+ return "mips64el"
+ default:
+ return arch
+ }
+}
diff --git a/release/dist/unixpkgs/targets.go b/release/dist/unixpkgs/targets.go
index 42bab6d3b..f87c56d31 100644
--- a/release/dist/unixpkgs/targets.go
+++ b/release/dist/unixpkgs/targets.go
@@ -1,127 +1,127 @@
-// Copyright (c) Tailscale Inc & AUTHORS
-// SPDX-License-Identifier: BSD-3-Clause
-
-package unixpkgs
-
-import (
- "fmt"
- "sort"
- "strings"
-
- "tailscale.com/release/dist"
-
- _ "github.com/goreleaser/nfpm/v2/deb"
- _ "github.com/goreleaser/nfpm/v2/rpm"
-)
-
-type Signers struct {
- Tarball dist.Signer
- RPM dist.Signer
-}
-
-func Targets(signers Signers) []dist.Target {
- var ret []dist.Target
- for goosgoarch := range tarballs {
- goos, goarch := splitGoosGoarch(goosgoarch)
- ret = append(ret, &tgzTarget{
- goEnv: map[string]string{
- "GOOS": goos,
- "GOARCH": goarch,
- },
- signer: signers.Tarball,
- })
- }
- for goosgoarch := range debs {
- goos, goarch := splitGoosGoarch(goosgoarch)
- ret = append(ret, &debTarget{
- goEnv: map[string]string{
- "GOOS": goos,
- "GOARCH": goarch,
- },
- })
- }
- for goosgoarch := range rpms {
- goos, goarch := splitGoosGoarch(goosgoarch)
- ret = append(ret, &rpmTarget{
- goEnv: map[string]string{
- "GOOS": goos,
- "GOARCH": goarch,
- },
- signer: signers.RPM,
- })
- }
-
- // Special case: AMD Geode is 386 with softfloat. Tarballs only since it's
- // an ancient architecture.
- ret = append(ret, &tgzTarget{
- filenameArch: "geode",
- goEnv: map[string]string{
- "GOOS": "linux",
- "GOARCH": "386",
- "GO386": "softfloat",
- },
- signer: signers.Tarball,
- })
-
- sort.Slice(ret, func(i, j int) bool {
- return ret[i].String() < ret[j].String()
- })
-
- return ret
-}
-
-var (
- tarballs = map[string]bool{
- "linux/386": true,
- "linux/amd64": true,
- "linux/arm": true,
- "linux/arm64": true,
- "linux/mips64": true,
- "linux/mips64le": true,
- "linux/mips": true,
- "linux/mipsle": true,
- "linux/riscv64": true,
- // TODO: more tarballs we could distribute, but don't currently. Leaving
- // out for initial parity with redo.
- // "darwin/amd64": true,
- // "darwin/arm64": true,
- // "freebsd/amd64": true,
- // "openbsd/amd64": true,
- }
-
- debs = map[string]bool{
- "linux/386": true,
- "linux/amd64": true,
- "linux/arm": true,
- "linux/arm64": true,
- "linux/riscv64": true,
- "linux/mipsle": true,
- "linux/mips64le": true,
- "linux/mips": true,
- // Debian does not support big endian mips64. Leave that out until we know
- // we need it.
- // "linux/mips64": true,
- }
-
- rpms = map[string]bool{
- "linux/386": true,
- "linux/amd64": true,
- "linux/arm": true,
- "linux/arm64": true,
- "linux/riscv64": true,
- "linux/mipsle": true,
- "linux/mips64le": true,
- // Fedora only supports little endian mipses. Maybe some other distribution
- // supports big-endian? Leave them out for now.
- // "linux/mips": true,
- // "linux/mips64": true,
- }
-)
-
-func splitGoosGoarch(s string) (string, string) {
- goos, goarch, ok := strings.Cut(s, "/")
- if !ok {
- panic(fmt.Sprintf("invalid target %q", s))
- }
- return goos, goarch
-}
+// Copyright (c) Tailscale Inc & AUTHORS
+// SPDX-License-Identifier: BSD-3-Clause
+
+package unixpkgs
+
+import (
+ "fmt"
+ "sort"
+ "strings"
+
+ "tailscale.com/release/dist"
+
+ _ "github.com/goreleaser/nfpm/v2/deb"
+ _ "github.com/goreleaser/nfpm/v2/rpm"
+)
+
+type Signers struct {
+ Tarball dist.Signer
+ RPM dist.Signer
+}
+
+func Targets(signers Signers) []dist.Target {
+ var ret []dist.Target
+ for goosgoarch := range tarballs {
+ goos, goarch := splitGoosGoarch(goosgoarch)
+ ret = append(ret, &tgzTarget{
+ goEnv: map[string]string{
+ "GOOS": goos,
+ "GOARCH": goarch,
+ },
+ signer: signers.Tarball,
+ })
+ }
+ for goosgoarch := range debs {
+ goos, goarch := splitGoosGoarch(goosgoarch)
+ ret = append(ret, &debTarget{
+ goEnv: map[string]string{
+ "GOOS": goos,
+ "GOARCH": goarch,
+ },
+ })
+ }
+ for goosgoarch := range rpms {
+ goos, goarch := splitGoosGoarch(goosgoarch)
+ ret = append(ret, &rpmTarget{
+ goEnv: map[string]string{
+ "GOOS": goos,
+ "GOARCH": goarch,
+ },
+ signer: signers.RPM,
+ })
+ }
+
+ // Special case: AMD Geode is 386 with softfloat. Tarballs only since it's
+ // an ancient architecture.
+ ret = append(ret, &tgzTarget{
+ filenameArch: "geode",
+ goEnv: map[string]string{
+ "GOOS": "linux",
+ "GOARCH": "386",
+ "GO386": "softfloat",
+ },
+ signer: signers.Tarball,
+ })
+
+ sort.Slice(ret, func(i, j int) bool {
+ return ret[i].String() < ret[j].String()
+ })
+
+ return ret
+}
+
+var (
+ tarballs = map[string]bool{
+ "linux/386": true,
+ "linux/amd64": true,
+ "linux/arm": true,
+ "linux/arm64": true,
+ "linux/mips64": true,
+ "linux/mips64le": true,
+ "linux/mips": true,
+ "linux/mipsle": true,
+ "linux/riscv64": true,
+ // TODO: more tarballs we could distribute, but don't currently. Leaving
+ // out for initial parity with redo.
+ // "darwin/amd64": true,
+ // "darwin/arm64": true,
+ // "freebsd/amd64": true,
+ // "openbsd/amd64": true,
+ }
+
+ debs = map[string]bool{
+ "linux/386": true,
+ "linux/amd64": true,
+ "linux/arm": true,
+ "linux/arm64": true,
+ "linux/riscv64": true,
+ "linux/mipsle": true,
+ "linux/mips64le": true,
+ "linux/mips": true,
+ // Debian does not support big endian mips64. Leave that out until we know
+ // we need it.
+ // "linux/mips64": true,
+ }
+
+ rpms = map[string]bool{
+ "linux/386": true,
+ "linux/amd64": true,
+ "linux/arm": true,
+ "linux/arm64": true,
+ "linux/riscv64": true,
+ "linux/mipsle": true,
+ "linux/mips64le": true,
+ // Fedora only supports little endian mipses. Maybe some other distribution
+ // supports big-endian? Leave them out for now.
+ // "linux/mips": true,
+ // "linux/mips64": true,
+ }
+)
+
+func splitGoosGoarch(s string) (string, string) {
+ goos, goarch, ok := strings.Cut(s, "/")
+ if !ok {
+ panic(fmt.Sprintf("invalid target %q", s))
+ }
+ return goos, goarch
+}
diff --git a/release/release.go b/release/release.go
index a8d0e6b62..638635b6d 100644
--- a/release/release.go
+++ b/release/release.go
@@ -1,15 +1,15 @@
-// Copyright (c) Tailscale Inc & AUTHORS
-// SPDX-License-Identifier: BSD-3-Clause
-
-// Package release provides functionality for building client releases.
-package release
-
-import "embed"
-
-// This contains all files in the release directory,
-// notably the files needed for deb, rpm, and similar packages.
-// Because we assign this to the blank identifier, it does not actually embed the files.
-// However, this does cause `go mod vendor` to include the files when vendoring the package.
-//
-//go:embed *
-var _ embed.FS
+// Copyright (c) Tailscale Inc & AUTHORS
+// SPDX-License-Identifier: BSD-3-Clause
+
+// Package release provides functionality for building client releases.
+package release
+
+import "embed"
+
+// This contains all files in the release directory,
+// notably the files needed for deb, rpm, and similar packages.
+// Because we assign this to the blank identifier, it does not actually embed the files.
+// However, this does cause `go mod vendor` to include the files when vendoring the package.
+//
+//go:embed *
+var _ embed.FS
diff --git a/release/rpm/rpm.postinst.sh b/release/rpm/rpm.postinst.sh
index 3d264c5f6..f9c1fddfd 100755
--- a/release/rpm/rpm.postinst.sh
+++ b/release/rpm/rpm.postinst.sh
@@ -1,41 +1,41 @@
-# $1 == 1 for initial installation.
-# $1 == 2 for upgrades.
-
-if [ $1 -eq 1 ] ; then
- # Normally, the tailscale-relay package would request shutdown of
- # its service before uninstallation. Unfortunately, the
- # tailscale-relay package we distributed doesn't have those
- # scriptlets. We definitely want relaynode to be stopped when
- # installing tailscaled though, so we blindly try to turn off
- # relaynode here.
- #
- # However, we also want this package installation to look like an
- # upgrade from relaynode! Therefore, if relaynode is currently
- # enabled, we want to also enable tailscaled. If relaynode is
- # currently running, we also want to start tailscaled.
- #
- # If there doesn't seem to be an active or enabled relaynode on
- # the system, we follow the RPM convention for package installs,
- # which is to not enable or start the service.
- relaynode_enabled=0
- relaynode_running=0
- if systemctl is-enabled tailscale-relay.service >/dev/null 2>&1; then
- relaynode_enabled=1
- fi
- if systemctl is-active tailscale-relay.service >/dev/null 2>&1; then
- relaynode_running=1
- fi
-
- systemctl --no-reload disable tailscale-relay.service >/dev/null 2>&1 || :
- systemctl stop tailscale-relay.service >/dev/null 2>&1 || :
-
- if [ $relaynode_enabled -eq 1 ]; then
- systemctl enable tailscaled.service >/dev/null 2>&1 || :
- else
- systemctl preset tailscaled.service >/dev/null 2>&1 || :
- fi
-
- if [ $relaynode_running -eq 1 ]; then
- systemctl start tailscaled.service >/dev/null 2>&1 || :
- fi
-fi
+# $1 == 1 for initial installation.
+# $1 == 2 for upgrades.
+
+if [ $1 -eq 1 ] ; then
+ # Normally, the tailscale-relay package would request shutdown of
+ # its service before uninstallation. Unfortunately, the
+ # tailscale-relay package we distributed doesn't have those
+ # scriptlets. We definitely want relaynode to be stopped when
+ # installing tailscaled though, so we blindly try to turn off
+ # relaynode here.
+ #
+ # However, we also want this package installation to look like an
+ # upgrade from relaynode! Therefore, if relaynode is currently
+ # enabled, we want to also enable tailscaled. If relaynode is
+ # currently running, we also want to start tailscaled.
+ #
+ # If there doesn't seem to be an active or enabled relaynode on
+ # the system, we follow the RPM convention for package installs,
+ # which is to not enable or start the service.
+ relaynode_enabled=0
+ relaynode_running=0
+ if systemctl is-enabled tailscale-relay.service >/dev/null 2>&1; then
+ relaynode_enabled=1
+ fi
+ if systemctl is-active tailscale-relay.service >/dev/null 2>&1; then
+ relaynode_running=1
+ fi
+
+ systemctl --no-reload disable tailscale-relay.service >/dev/null 2>&1 || :
+ systemctl stop tailscale-relay.service >/dev/null 2>&1 || :
+
+ if [ $relaynode_enabled -eq 1 ]; then
+ systemctl enable tailscaled.service >/dev/null 2>&1 || :
+ else
+ systemctl preset tailscaled.service >/dev/null 2>&1 || :
+ fi
+
+ if [ $relaynode_running -eq 1 ]; then
+ systemctl start tailscaled.service >/dev/null 2>&1 || :
+ fi
+fi
diff --git a/release/rpm/rpm.postrm.sh b/release/rpm/rpm.postrm.sh
index d74f7e9de..e19a7305c 100755
--- a/release/rpm/rpm.postrm.sh
+++ b/release/rpm/rpm.postrm.sh
@@ -1,8 +1,8 @@
-# $1 == 0 for uninstallation.
-# $1 == 1 for removing old package during upgrade.
-
-systemctl daemon-reload >/dev/null 2>&1 || :
-if [ $1 -ge 1 ] ; then
- # Package upgrade, not uninstall
- systemctl try-restart tailscaled.service >/dev/null 2>&1 || :
-fi
+# $1 == 0 for uninstallation.
+# $1 == 1 for removing old package during upgrade.
+
+systemctl daemon-reload >/dev/null 2>&1 || :
+if [ $1 -ge 1 ] ; then
+ # Package upgrade, not uninstall
+ systemctl try-restart tailscaled.service >/dev/null 2>&1 || :
+fi
diff --git a/release/rpm/rpm.prerm.sh b/release/rpm/rpm.prerm.sh
index 682c01bd5..eeabf3b58 100755
--- a/release/rpm/rpm.prerm.sh
+++ b/release/rpm/rpm.prerm.sh
@@ -1,8 +1,8 @@
-# $1 == 0 for uninstallation.
-# $1 == 1 for removing old package during upgrade.
-
-if [ $1 -eq 0 ] ; then
- # Package removal, not upgrade
- systemctl --no-reload disable tailscaled.service > /dev/null 2>&1 || :
- systemctl stop tailscaled.service > /dev/null 2>&1 || :
-fi
+# $1 == 0 for uninstallation.
+# $1 == 1 for removing old package during upgrade.
+
+if [ $1 -eq 0 ] ; then
+ # Package removal, not upgrade
+ systemctl --no-reload disable tailscaled.service > /dev/null 2>&1 || :
+ systemctl stop tailscaled.service > /dev/null 2>&1 || :
+fi