-
Notifications
You must be signed in to change notification settings - Fork 29
/
Copy pathcheckuplink
executable file
·152 lines (126 loc) · 5.26 KB
/
checkuplink
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
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
#!/bin/busybox sh
# shellcheck shell=dash
# fail fast and abort early
set -eu
# set -o pipefail # TODO: pipefail needs more rework in the script
if { set -C; true 2>/dev/null >/var/lock/checkuplink.lock; }; then
trap "rm -f /var/lock/checkuplink.lock" EXIT
else
echo "Lock file exists... exiting"
exit
fi
interface_linklocal() {
# We generate a predictable v6 address
local macaddr oldIFS
macaddr="$(uci get wireguard.mesh_vpn.privatekey | wg pubkey | md5sum | sed 's/^\(..\)\(..\)\(..\)\(..\)\(..\).*$/02:\1:\2:\3:\4:\5/')"
oldIFS="$IFS"
IFS=':'
# shellcheck disable=SC2086 # we need to split macaddr here using IFS
set -- $macaddr
IFS="$oldIFS"
echo "fe80::${1}${2}:${3}ff:fe${4}:${5}${6}"
}
clean_port() {
echo "$1" | sed -r 's/:[0-9]+$|\[|\]//g'
}
check_address_family() {
local peer_endpoint="$2"
local gateway
gateway="$(clean_port "$peer_endpoint")"
# Check if we have a default route for v6 if not fallback to v4
if ip -6 route show table 1 | grep -q 'default via'
then
local ipv6
ipv6="$(gluon-wan nslookup "$gateway" | grep 'Address:\? [0-9]' | grep -E -o '([a-f0-9:]+:+)+[a-f0-9]+')"
echo "[$ipv6]$(echo "$peer_endpoint" | grep -E -oe ":[0-9]+$")"
else
local ipv4
ipv4="$(gluon-wan nslookup "$gateway" | grep 'Address:\? [0-9]' | grep -oE "\b([0-9]{1,3}\.){3}[0-9]{1,3}\b")"
echo "$ipv4$(echo "$peer_endpoint" | grep -E -oe ":[0-9]+$")"
fi
}
# Do we already have a private-key? If not generate one
if ! uci -q get wireguard.mesh_vpn.privatekey > /dev/null
then
uci set wireguard.mesh_vpn.privatekey="$(wg genkey)"
uci commit wireguard
fi
# Is wireguard enabled?
if [ "$(uci get wireguard.mesh_vpn.enabled)" = "true" ] || [ "$(uci get wireguard.mesh_vpn.enabled)" = "1" ]; then
#We assume we are not connected by default
CONNECTED=0
MESH_VPN_IFACE=$(uci get wireguard.mesh_vpn.iface)
# Check connectivity to supernode
if wget "http://[$(wg | grep fe80 | awk '{split($3,A,"/")};{print A[1]}')%$MESH_VPN_IFACE]/" --timeout=5 -O/dev/null -q
then
GWMAC=$(batctl gwl | awk '/[*]/{print $2}')
if batctl ping -c 5 "$GWMAC" > /dev/null 2>&1
then
CONNECTED=1
fi
fi
# If we don't have a connection we try to connect
if [ "$CONNECTED" -ne "1" ]; then
logger -t checkuplink "Reconnecting ..."
NTP_SERVERS=$(uci get system.ntp.server)
# shellcheck disable=SC3060 # busybox sh supports string replacement
NTP_SERVERS="${NTP_SERVERS// / -p }" # each separate NTP server needs to be behind a "-p"
# shellcheck disable=SC2086 # we need to expand the list of NTP_SERVERS here
gluon-wan /usr/sbin/ntpd -n -N -S /usr/sbin/ntpd-hotplug -p ${NTP_SERVERS} -q
# Get the number of configured peers and randomly select one
NUMBER_OF_PEERS=$(uci -q show wireguard | grep -E -ce "peer_[0-9]+.endpoint")
PEER="$(awk -v min=1 -v max="$NUMBER_OF_PEERS" 'BEGIN{srand(); print int(min+rand()*(max-min+1))}')"
PEER_PUBLICKEY="$(uci get wireguard.peer_"$PEER".publickey)"
logger -t checkuplink "Selected peer $PEER"
endpoint="$(check_address_family "$PEER_PUBLICKEY" "$(uci get wireguard.peer_"$PEER".endpoint)")"
logger -t checkuplink "Connecting to $endpoint"
# Delete Interfaces
{
ip link set nomaster dev mesh-vpn >/dev/null 2>&1
ip link delete dev mesh-vpn >/dev/null 2>&1
} || true
ip link delete dev "${MESH_VPN_IFACE}" >/dev/null 2>&1 || true
PUBLICKEY=$(uci get wireguard.mesh_vpn.privatekey | wg pubkey)
SEGMENT=$(uci get gluon.core.domain)
# Push public key to broker, test for https and use if supported
ret=0
wget -q "https://[::1]" || ret=$?
# returns Network Failure =4 if https exists
# and Generic Error =1 if no ssl lib available
if [ "$ret" -eq 1 ]; then
PROTO=http
else
PROTO=https
fi
gluon-wan wget -q -O- --post-data='{"domain": "'"$SEGMENT"'","public_key": "'"$PUBLICKEY"'"}' "$PROTO://$(uci get wireguard.mesh_vpn.broker)"
# Bring up the wireguard interface
ip link add dev "$MESH_VPN_IFACE" type wireguard
wg set "$MESH_VPN_IFACE" fwmark 1
uci get wireguard.mesh_vpn.privatekey | wg set "$MESH_VPN_IFACE" private-key /proc/self/fd/0
ip link set up dev "$MESH_VPN_IFACE"
# Add link-address and Peer
ip address add "$(interface_linklocal "$MESH_VPN_IFACE")"/64 dev "$MESH_VPN_IFACE"
if [ "$endpoint" = "" ]; then
endpoint=$(uci get wireguard.peer_"$PEER".endpoint)
fi
gluon-wan wg set "$MESH_VPN_IFACE" peer "$(uci get wireguard.peer_"$PEER".publickey)" persistent-keepalive 25 allowed-ips "$(uci get wireguard.peer_"$PEER".link_address)/128" endpoint "$endpoint"
# We need to allow incoming vxlan traffic on mesh iface
sleep 10
RULE="-i $MESH_VPN_IFACE -m udp -p udp --dport 8472 -j ACCEPT"
# shellcheck disable=SC2086 # we need to split RULE here twice
if ! ip6tables -C INPUT $RULE
then
ip6tables -I INPUT 1 $RULE
fi
# Bring up VXLAN
if ! ip link add mesh-vpn type vxlan id "$(lua -e 'print(tonumber(require("gluon.util").domain_seed_bytes("gluon-mesh-vpn-vxlan", 3), 16))')" local "$(interface_linklocal "$MESH_VPN_IFACE")" remote "$(uci get wireguard.peer_"$PEER".link_address)" dstport 8472 dev "$MESH_VPN_IFACE"
then
logger -p err -t checkuplink "Unable to create mesh-vpn interface"
exit 2
fi
ip link set up dev mesh-vpn
sleep 5
# If we have a BATMAN_V env we need to correct the throughput value now
batctl hardif mesh-vpn throughput_override 1000mbit;
fi
fi