summaryrefslogtreecommitdiffstats
path: root/net/ripe-atlas/test.sh
blob: 57b6eba83e3df0e97d4374894a8beba9354a4d06 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
#!/bin/sh

MEAS_DIR=/usr/lib/ripe-atlas/measurement
SCRIPT_DIR=/usr/lib/ripe-atlas/scripts
SHARE_DIR=/usr/share/ripe-atlas
BUSYBOX="$MEAS_DIR/busybox"

# Atlas measurement applets. Standard busybox applets are deliberately not
# built in, so only these plus the patched telnetd are expected.
APPLETS="atlasinit buddyinfo condmv date dfrm eooqd eperd evhttpget evntp \
evping evsslgetcert evtdig evtraceroute httppost onlyuptime perd rchoose \
rptaddrs rptra6 rptuptime rxtxrpt telnetd"

check_applets() {
	for applet in $APPLETS; do
		path="$MEAS_DIR/$applet"
		[ -e "$path" ] || { echo "FAIL: missing applet: $applet"; exit 1; }
		if [ -L "$path" ]; then
			target=$(readlink "$path")
			case "$target" in
			busybox|./busybox|"$BUSYBOX") ;;
			*) echo "FAIL: applet $applet -> unexpected target: $target"; exit 1 ;;
			esac
		elif [ -f "$path" ]; then
			bb_inode=$(ls -i "$BUSYBOX" | awk '{print $1}')
			ap_inode=$(ls -i "$path" | awk '{print $1}')
			[ "$bb_inode" = "$ap_inode" ] || {
				echo "FAIL: applet $applet is not a busybox hardlink"; exit 1; }
		else
			echo "FAIL: applet $applet is neither symlink nor regular file"
			exit 1
		fi
	done

	applet_list=$("$BUSYBOX" --list 2>/dev/null) || {
		echo "FAIL: 'busybox --list' failed"; exit 1; }
	for applet in $APPLETS; do
		echo "$applet_list" | grep -qx "$applet" || {
			echo "FAIL: applet '$applet' missing from 'busybox --list'"; exit 1; }
	done
}

# Catch crash signals (132/134/137/139) and hangs. Output is not asserted
# because the applet CLIs vary across Atlas releases.
run_applet_smoke() {
	name="$1"; shift
	out=$(timeout 5 "$BUSYBOX" "$name" "$@" 2>&1); rc=$?
	case "$rc" in
	124) echo "FAIL: applet $name timed out"; exit 1 ;;
	132|134|137|139)
		echo "FAIL: applet $name crashed (rc=$rc)"; echo "$out"; exit 1 ;;
	esac
}

case "$1" in
ripe-atlas-common)
	[ -x "$BUSYBOX" ] || { echo "FAIL: $BUSYBOX not installed"; exit 1; }
	[ -s "$BUSYBOX" ] || { echo "FAIL: $BUSYBOX is empty"; exit 1; }
	check_applets

	# The probe drops to this user, so it must exist with a matching group.
	uid=$(awk -F: '$1=="ripe-atlas" {print $3}' /etc/passwd)
	[ -n "$uid" ] || { echo "FAIL: user 'ripe-atlas' missing from /etc/passwd"; exit 1; }
	gid=$(awk -F: '$1=="ripe-atlas" {print $3}' /etc/group)
	[ -n "$gid" ] || { echo "FAIL: group 'ripe-atlas' missing from /etc/group"; exit 1; }

	# Exercise the applets that need no network peer.
	run_applet_smoke rptuptime
	run_applet_smoke dfrm -A 9018 /tmp 1 /tmp /tmp
	run_applet_smoke condmv /tmp/atlas-no-such-src /tmp/atlas-no-such-dst
	[ -r /proc/uptime ] && run_applet_smoke onlyuptime
	[ -r /proc/buddyinfo ] && run_applet_smoke buddyinfo 1 /dev/null
	[ -r /proc/net/dev ] && run_applet_smoke rxtxrpt -A 9999

	# The shell libraries the init and reginit source at runtime.
	for f in common.sh config.sh paths.lib.sh json.lib.sh support.lib.sh \
		 linux-functions.sh reginit.sh; do
		[ -s "$SCRIPT_DIR/$f" ] || { echo "FAIL: $SCRIPT_DIR/$f missing or empty"; exit 1; }
	done
	for f in $(ls "$SCRIPT_DIR"/*.sh 2>/dev/null); do
		sh -n "$f" || { echo "FAIL: $f is not valid shell"; exit 1; }
	done

	[ -s "$SHARE_DIR/capabilities.json" ] || {
		echo "FAIL: $SHARE_DIR/capabilities.json missing or empty"; exit 1; }
	jsonfilter -i "$SHARE_DIR/capabilities.json" -e '@.effective' >/dev/null || {
		echo "FAIL: capabilities.json is not valid JSON"; exit 1; }
	jsonfilter -i "$SHARE_DIR/capabilities.json" -e '@.effective[*]' | grep -qx CAP_NET_RAW || {
		echo "FAIL: capabilities.json does not grant CAP_NET_RAW"; exit 1; }

	[ -x /etc/init.d/ripe-atlas ] || { echo "FAIL: /etc/init.d/ripe-atlas not installed"; exit 1; }
	sh -n /etc/init.d/ripe-atlas || { echo "FAIL: init script is not valid shell"; exit 1; }
	[ -s /etc/config/ripe-atlas ] || { echo "FAIL: /etc/config/ripe-atlas missing or empty"; exit 1; }
	uci -q show ripe-atlas >/dev/null || { echo "FAIL: uci cannot parse ripe-atlas config"; exit 1; }

	[ -x /usr/sbin/ripe-atlas ] || { echo "FAIL: /usr/sbin/ripe-atlas not installed"; exit 1; }
	;;

ripe-atlas-probe|ripe-atlas-anchor)
	# Each variant ships the registration servers and host keys for its own
	# environment; without them the probe cannot register.
	[ -s "$SCRIPT_DIR/reg_servers.sh.prod" ] || {
		echo "FAIL: $SCRIPT_DIR/reg_servers.sh.prod missing or empty"; exit 1; }
	sh -n "$SCRIPT_DIR/reg_servers.sh.prod" || {
		echo "FAIL: reg_servers.sh.prod is not valid shell"; exit 1; }
	grep -qE '^REG_[0-9]+_HOST=[^[:space:]]' "$SCRIPT_DIR/reg_servers.sh.prod" || {
		echo "FAIL: reg_servers.sh.prod defines no REG_*_HOST entries"; exit 1; }

	[ -s "$SHARE_DIR/known_hosts.reg" ] || {
		echo "FAIL: $SHARE_DIR/known_hosts.reg missing or empty"; exit 1; }
	grep -q 'ssh-\|ecdsa-' "$SHARE_DIR/known_hosts.reg" || {
		echo "FAIL: known_hosts.reg holds no host keys"; exit 1; }
	;;
esac

exit 0