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
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
|
#!/bin/bash
# Needs bash for printf -v VARNAME
# -----------------------------------------------------------------------------
#
# Copyright (c) 2011..2018 bwLehrpool-Projektteam
#
# This program/file is free software distributed under the GPL version 2.
# See https://www.gnu.org/licenses/old-licenses/gpl-2.0-standalone.html
#
# If you have any feedback please consult https://bwlehrpool.de and
# send your feedback to support@bwlehrpool.de.
#
# General information about bwLehrpool can be found at https://bwlehrpool.de
#
# -----------------------------------------------------------------------------
#
# Mini-Linux Toolkit
#
# -----------------------------------------------------------------------------
# DO NOT RENAME/MOVE THIS FILE!
# The slx-network dracut module checks for its existence
. /opt/openslx/config
declare -rg primary="${SLX_BRIDGE:-br0}"
declare -rg RESOLV_CONF="/opt/openslx/resolv.conf"
declare -rg THIS_RESOLV="/run/network/${interface}.resolv"
declare -rg flag="/run/network/primary-dhcp.flag"
if [ "$1" = "--lock-hostname-updates" ]; then
# If we change the hostname while Xorg is running, this might
# cause issues, depending on how it's set up. So we run this
# script with the lock argument to touch the flag file right
# before we try to launch lightdm/Xorg. In case the DHCP request
# is too slow, this means we'll run with the wrong hostname
# (potentially), but that's better than delaying the bootup
# unnecessarily.
# So also note that if you ever change this script's name/location
# (JUST DON'T), you'd need to update all call sites, i.e. the
# udhcpc startup script, and the lightdm service drop-in.
mkdir -p /run/network
touch "$flag"
exit 0
fi
shopt -s extglob
rebuild_resolv_conf () {
# Don't do anything if the active resolv.conf is not ours
# Also this will not run resolvconf update.d... No idea if we should still do so...
[ -L "/etc/resolv.conf" ] || return 0
[ "$(readlink -f "/etc/resolv.conf")" = "${RESOLV_CONF}" ] || return 0
# Fake file to merge in search domains from /opt/openslx/config
echo "search $SLX_NET_SEARCH" > "/run/network/zzzzz-openslx.resolv"
# Use extglob trickery to make sure br0/$primary stuff comes first
# Then print them in a first-come-first-served manner.
# Print nameserver entries one per line, print only first domain value,
# group everything else together into one line.
# Skip domain entirely if any search lines are found.
cat "/run/network/$primary.resolv" /run/network/!("$primary").resolv \
| gawk '{
if ( $1 ~ /^[a-z]+$/ ) {
for (i = 2; i <= NF; ++i) {
if (done[$1][$i])
continue
done[$1][$i] = 1
output[$1][++idx] = $i
}
} else {
print $0
}
}
END {
for (s in output) {
if (s == "nameserver") {
for (t in output[s]) {
print s " " output[s][t]
}
} else if (s == "domain" && isarray(output["search"])) {
} else {
printf "%s", s
for (t in output[s]) {
printf " %s", output[s][t]
if (s == "domain")
break
}
print ""
}
}
}' \
> "$RESOLV_CONF" 2> /dev/null
# add support for resolv.conf update scripts // see man(8) resolvconf
for s in /etc/resolvconf/update.d/*.sh; do
[ -f "$s" ] && [ -x "$s" ] && "$s"
done
}
escape_search() {
sed -e 's/[]\/()$*.^|[]/\\&/g' <<<"$@"
}
escape_replace() {
sed -e 's/[\/&]/\\&/g' <<<"$@"
}
check_env() {
if [ -z "$ip" ] || [ -z "$subnet" ] || [ -z "$interface" ]; then
echo "$1 event with missing data" >&2
echo "ip = '$ip'" >&2
echo "subnet = '$subnet'" >&2
echo "interface = '$interface'" >&2
exit 1
fi
}
ipc() {
# Use the busybox ipcalc explicity as it's incompatible with the perl-one
busybox ipcalc -s "$@"
}
mkdir -p "/run/network"
case "$1" in
bound|renew)
check_env "$1"
mkdir -p "/run/dhcpc"
if [ "$interface" != "$primary" ]; then
echo 1 > /proc/sys/net/ipv4/conf/all/arp_filter
echo 1 > /proc/sys/net/ipv4/conf/all/arp_ignore
fi
# Set address on interface
alt_table= # Use separate routing table?
if [ "$interface" != "$primary" ]; then
pri_net="$( ip addr show dev "${primary}" | awk '$1 == "inet" {print $2; exit}' )"
[[ "$pri_net" == */* ]] || pri_net="${pri_net}/32"
pri_net="$( ipc -n "$pri_net" | sed 's/^.*=//' )/${pri_net#*/}"
this_net="$( ipc -n "$ip" "$subnet" | sed 's/^.*=//' )/$( ipc -p "$ip" "$subnet" | sed 's/^.*=//' )"
[ "$pri_net" = "$this_net" ] && alt_table=yes
fi
if [ -z "$alt_table" ]; then
# default table
ip addr add "$ip/$( ipc -p "$ip" "$subnet" | sed 's/^.*=//' )" dev "$interface"
# Set default route, if given
if [ -n "$router" ]; then
# Only replace route if it's the same interface as the current default route, or we don't have any
current="$( ip route show | awk '{ if ($1 == "default") {print $5; exit 0}}' )"
if [ -z "$current" ] || [ "$interface" = "$current" ]; then
ip route replace default via "$router"
fi
fi
else
# alt table - determine which one
mkdir -p /etc/iproute2
touch /etc/iproute2/rt_tables
alt_table="$( awk -v "iface=$interface" \
'$1 ~ /^[0-9]+$/ && $2 == iface {print $1; exit}' \
/etc/iproute2/rt_tables )"
if [ -z "$alt_table" ]; then
alt_table="$( awk '$1 ~ /^[0-9]+$/ { a[$1] = 1 }
END {
for (i = 1; i < 255; ++i) {
if (!a[i]) { print i; exit }
}
print 1
}' /etc/iproute2/rt_tables )"
echo "$alt_table $interface" >> /etc/iproute2/rt_tables
fi
ip addr add "$ip/$( ipc -p "$ip" "$subnet" | sed 's/.*=//' )" dev "$interface" noprefixroute
ip route add "$this_net" dev "$interface" scope link src "$ip" table "$interface"
ip rule add from "$ip" table "$interface"
# Set default route, if given
if [ -n "$router" ]; then
ip route replace default via "$router" table "$interface"
fi
fi
# get domain, hostname and thus fqdn from DNS
dns_fqdn=$(busybox timeout 3 rdns "$ip")
dns_short="${dns_fqdn%%.*}"
# check if it is fqdn
if [ "$dns_fqdn" == "$dns_short" ]; then
unset dns_fqdn dns_short
fi
# Update resolver configuration file
conf_file="$(mktemp)"
# Own domain suffix
if [ -n "$domain" ]; then
:
elif [ -n "$dns_fqdn" ]; then
domain="${dns_fqdn#*.}"
elif [ -n "$SLX_NET_DOMAIN" ]; then
domain="$SLX_NET_DOMAIN"
fi
if [ -n "$domain" ]; then
echo "domain ${domain%% *}" >> "${conf_file}"
fi
# Add domain to list of search domains if not in there yet
if [ -n "$domain" ] && [ -n "$search" ]; then
FOUND=no
for sd in $search; do
[ "x$sd" = "x$domain" ] && FOUND=yes
done
[ "$FOUND" = "no" ] && search="$domain $search"
elif [ -n "$domain" ]; then
search="$domain"
fi
# Search domains
if [ -n "$search" ]; then
echo "search $search" >> "${conf_file}"
elif [ -n "$SLX_NET_SEARCH" ]; then
echo "search $SLX_NET_SEARCH" >> "${conf_file}"
elif [ -n "$SLX_NET_DOMAIN" ]; then
echo "search $SLX_NET_DOMAIN" >> "${conf_file}"
fi
for i in $dns; do
echo "$0: Adding DNS $i"
echo "nameserver $i" >> "${conf_file}"
done
# Manual handling required :-(
mv -f "$conf_file" "$THIS_RESOLV"
rebuild_resolv_conf
# Things that should only happen for the main interface that was used for booting
if [ "$interface" = "$primary" ]; then
# Update IP
sed -i "s/^\(SLX_PXE_CLIENT_IP=\).*$/\1'$ip'/" /opt/openslx/config
# Write DOMAIN and SEARCH to /opt/openslx/config if empty
if [ -z "$SLX_NET_DOMAIN" ] && [ -n "$domain" ]; then
echo "SLX_NET_DOMAIN='$domain'" >> /opt/openslx/config
fi
if [ -z "$SLX_NET_SEARCH" ] && [ -n "$search" ]; then
echo "SLX_NET_SEARCH='$search'" >> /opt/openslx/config
fi
# Same for WINS servers
if [ -z "$SLX_NET_WINS" ] && [ -n "$wins" ]; then
echo "SLX_NET_WINS='$wins'" >> /opt/openslx/config
fi
# Only update hostname if network is not ready yet
# later on this might cause issues
if ! [ -e "$flag" ]; then
# Fallback for hostname
if [ -z "$dns_fqdn" ] && [ -n "$domain" ] && [ -n "$hostname" ]; then
# fallback to what the dhcp told us
dns_fqdn="${hostname}.${domain}"
fi
if [ -z "$dns_fqdn" ]; then
# Try currently set fqdn
dns_fqdn="$( hostname -f )"
fi
if [ -z "$dns_fqdn" ]; then
if [ -s "/etc/hostname" ]; then
dns_fqdn="$( head -n 1 /etc/hostname )"
else
# Final fallback, nothing valid found
dns_fqdn="noname-${ip//./-}.invalid"
fi
fi
# finally, if dns_fqdn was set to anything, apply it
if [ -n "$dns_fqdn" ]; then
dns_short="${dns_fqdn%%.*}"
echo "$dns_short" > "/proc/sys/kernel/hostname"
echo "$dns_short" > "/etc/hostname"
if [ -z "$SLX_HOSTNAME" ]; then
echo "# Config written by openslx-dhcp-script (1)" >> /opt/openslx/config
echo "SLX_HOSTNAME='$dns_short'" >> /opt/openslx/config
elif [ "$SLX_HOSTNAME" != "$dns_short" ]; then
sed -i "s/^\(SLX_HOSTNAME=\).*$/\1'$dns_short'/" /opt/openslx/config
fi
fi
# Update /etc/issue for proper spacing
/opt/openslx/scripts/openslx-create_issue
touch "$flag"
# end "network not ready yet"
else
# Network already going, make sure we don't change the primary hostname in /etc/hosts
hostname=
domain=
dns_fqdn=
fi
# Remove any stray addresses; we expect the primary interface to only have one
# address supplied via DHCP. We do this after adding the new one, obviously.
rem_list=$( ip -o addr show "$interface" | awk '{ for (i=1;i<NF;++i) if ($i == "inet") print $(i+1) }' | grep -v "^${ip}/" )
if [ -n "$rem_list" ]; then
echo "PRIMARY: Removing $rem_list since we just got assigned $ip"
echo 1 > "/proc/sys/net/ipv4/conf/$interface/promote_secondaries"
for addr in $rem_list; do
ip addr del "$addr" dev "$interface"
sed -i "/^$(escape_search "${addr%/*}")(\s|$)/d" /etc/hosts
done
fi
fi # end "primary only"
# Hostname in /etc/hosts
touch "/etc/hosts"
hostlist=""
[ -n "$dns_fqdn" ] && hostlist="$dns_fqdn"
[ -n "$hostname" ] && [ -n "$domain" ] && [ "x${hostname}.${domain}" != "x$dns_fqdn" ] && hostlist="$hostlist ${hostname}.${domain}"
if [ -n "$hostlist" ]; then
for host in $hostlist; do
host_short="${host%%.*}"
[ "x$host_short" = "x$host" ] && host_short=""
sed -i -r "s/\s$(escape_search "$host")(\s|$)/ /g" /etc/hosts
[ -n "$host_short" ] && sed -i -r "s/\s$(escape_search "$host_short")(\s|$)/ /g" /etc/hosts
if grep -q -E "^$ip\s" /etc/hosts; then
sed -i "s/^$(escape_search "$ip")\s.*/$(escape_replace "$ip $host $host_short")/g" /etc/hosts
else
echo "$ip $host $host_short" >> /etc/hosts
fi
done
fi
# Get rid of orphaned lines in /etc/hosts
sed -i -r '/^[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+\s*$/d' /etc/hosts
if [ -n "$dns" ] && [ -z "$SLX_DNS" ]; then
# Write to openslx-config
echo "# Config written by openslx-dhcp-script (2)" >> /opt/openslx/config
echo "SLX_DNS='$dns'" >> /opt/openslx/config
fi
# Rewrite nat1 dhcpd config for VMs, and restart dnsmasq if it changed
/opt/openslx/scripts/runvirt-start_dhcpd
;;
deconfig)
check_env "$1"
if [ "$interface" = "$primary" ]; then
echo "Ignoring deconfig for primary interface"
else
echo 1 > "/proc/sys/net/ipv4/conf/$interface/promote_secondaries"
clientip=${ip%%:*}
ip addr del "$clientip/$(ipc -p "$clientip" "$subnet" | sed s/.*=//)" dev "$interface"
ip route flush table "$interface"
sed -i "/^$(escape_search "$ip")(\s|$)/d" /etc/hosts
fi
# Manual handling required :-(
rm -f -- "$THIS_RESOLV"
rebuild_resolv_conf
;;
leasefail)
echo "$0: Lease failed: $message" >&2
;;
nak)
echo "$0: Received a NAK: $message" >&2
;;
*)
echo "$0: Unknown udhcpc command: $1" >&2
exit 1
;;
esac
exit 0
|