Browse Source

initial commit

felics 1 year ago
commit
fd5b34f7e3
2 changed files with 1177 additions and 0 deletions
  1. 12
    0
      README.md
  2. 1165
    0
      adhocspot.sh

+ 12
- 0
README.md View File

@@ -0,0 +1,12 @@
1
+Bash script to easily configure your interface to share your internet connection and configure a DHCP and DNS and TFTP boot server to listen on it. IP, DHCP, DNS can be configured, and for WiFi interfaces also wireless mode and encryption.
2
+
3
+For full functionality, the following executables are beeing expected to be found (and doing the expected stuff):
4
+* `bash`,
5
+* `dnsmasq`,
6
+* `iptables`,
7
+* `ifconfig` (in Arch Linux, part of the package `net-tools`),
8
+* `iwconfig` (in Arch Linux, part of the package `wireless_tools`),
9
+* `wpa_supplicant`,
10
+* ... and standard tools like `grep`, `sed`, `awk` ….
11
+
12
+* Arch Linux: [AUR Package](http://aur.archlinux.org/packages/adhocspot-script/).

+ 1165
- 0
adhocspot.sh View File

@@ -0,0 +1,1165 @@
1
+#!/bin/bash
2
+
3
+_version=20190514.1
4
+
5
+##### Dependencies. #####
6
+#
7
+# On Arch Linux, this script depends on the following packages (in brackets the bare commands it uses):
8
+#   * bash: For running this script. ('bash')
9
+#   * dnsmasq: For DHCP and DNS. ('dnsmasq')
10
+#   * iptables: For configuring NAT/ masquerading. ('iptables')
11
+#   * net-tools: For configuring IP information of the network interface. ('ifconfig')
12
+#   * wireless_tools: For configuration of wireless network interface. ('iwconfig')
13
+#   * wpa_supplicant: For WPA-encryption. ('wpa_supplicant', 'wpa_passphrase')
14
+#   * ... and standard tools like grep, sed, awk ...
15
+#
16
+##### #####
17
+
18
+
19
+# set -e
20
+
21
+_datetime="$(date +%Y-%m-%d_%H-%M-%S)"
22
+
23
+# Default values. Can be overridden by commandline options.
24
+_iface_default="wlan0"
25
+_ip_default="192.168.101.3"
26
+_netmask_default="255.255.255.0"
27
+_out_iface_all_default="true"
28
+_out_iface_default="<all>"
29
+_dhcprange_lower_suffix_default="121"
30
+_dhcprange_upper_suffix_default="199"
31
+_macaddress_change_default="false"
32
+_macaddress_default='<not change>'
33
+_essid_default="adhoc_network"
34
+_channel_default="8"
35
+_encryption_default="off"
36
+_enckey_default="please_specify_a_non_default_key"
37
+_wifimode_default="ad-hoc"
38
+_no_wifi_default="false"
39
+_no_ipconfig_default="false"
40
+_no_nat_default="false"
41
+_tftp_root_default="/tftpboot"
42
+_no_tftp_default="false"
43
+_verbose_default="false"
44
+_debug_default="false"
45
+_rundir_base_default="/var/run/adhocspot"
46
+
47
+
48
+
49
+stdout()
50
+# To write to stdout.
51
+# Options: '-n': Without trailing newline.
52
+{
53
+  if [ "$1" == "-n" ]; then
54
+    _fmt='%s'
55
+    shift
56
+  else
57
+    _fmt='%s\n'
58
+  fi
59
+
60
+  if [ $# -gt 1 ]; then
61
+    errmsg "BUG: Too many arguments passed to internal function 'stdout()'".
62
+    return 12
63
+  else
64
+    printf "${_fmt}" "$1"
65
+  fi
66
+}
67
+
68
+stderr()
69
+# To write to stderr.
70
+{
71
+  stdout "$@" > /dev/stderr
72
+}
73
+
74
+msg()
75
+# To print messages for the user.
76
+{
77
+  stdout "$@"
78
+}
79
+
80
+stdout_prefix()
81
+{
82
+  prefix="$1"
83
+  while read line; do
84
+    stdout "${prefix}${line}"
85
+  done
86
+}
87
+
88
+verbose() {
89
+  if "${_verbose}"; then
90
+    msg "$@"
91
+  fi
92
+}
93
+
94
+debug() {
95
+  if "${_debug}"; then
96
+    msg "$@"
97
+  fi
98
+}
99
+
100
+errmsg() {
101
+  stderr "$@"
102
+}
103
+
104
+exiterror() {
105
+  if [ $# -ge 2 ]; then
106
+    _exitcode="$2"
107
+  else
108
+    _exitcode=1
109
+  fi
110
+  if [ $# -ge 1 ]; then
111
+    _msg="$1"
112
+  else
113
+    _msg="$0: Unspecified Error. Aborting."
114
+  fi
115
+  errmsg "${_msg}"
116
+  exit "${_exitcode}"
117
+}
118
+
119
+make_newip_from_suffix() {
120
+  # Takes as $1 an IPv4-address, as $2 a last part of an IPv4-address, and replaces the last part of $1 with $2.
121
+  if [ $# -lt 2 ]; then
122
+    exiterror "$0: In function 'make_newip_from_suffix': Error: Need IP-address and a suffix as options."
123
+  fi
124
+
125
+  _ip="$1"
126
+  _sfx="$2"
127
+
128
+  stdout "$(stdout "${_ip}" | awk -F. '{print $1"."$2"."$3}').${_sfx}"
129
+}
130
+
131
+get_macaddress() {
132
+  # Returns the MAC-address of the interface specified in $1.
133
+  if [ $# -lt 1 ]; then
134
+    exiterror "$0: In function 'get_macaddress': Error: Need to specify a network interface as option."
135
+  fi
136
+  
137
+  ifconfig "$1" | grep -E '\<ether\>' | sed 's|^.*ether[[:space:]]*\([0-9a-f:]*\)[[:space:]].*$|\1|g'
138
+}
139
+
140
+is_interface_up() {
141
+  # Returns 0 if interface $1 is up, otherwise 1.
142
+  if [ $# -lt 1 ]; then
143
+    exiterror "$0: In function 'is_interface_up': Error: Need to specify a network interface as option."
144
+  fi
145
+  
146
+  ifconfig "$1" | tr '[[:space:]]' '\n' | grep 'flags=' | grep -q UP
147
+}
148
+
149
+set_macaddress() {
150
+  # Sets the MAC-address of the network interface $1 to $2.
151
+  if [ $# -lt 2 ]; then
152
+    exiterror "$0: In function 'set_macaddress': Error: Need interface and MAC-address as options."
153
+  fi
154
+  
155
+  verbose "Setting MAC address of $1 to $2."
156
+  
157
+  if is_interface_up "$1"; then
158
+    _isup=true
159
+  else
160
+    _isup=false
161
+  fi
162
+  
163
+  # debug "DEBUG: Interface is up, need to be temporarily down to change MAC address."
164
+  if "${_isup}"; then
165
+    ifconfig "$1" down
166
+  fi
167
+  # debug "DEBUG: Interface was brought down. Now changing MAC address."
168
+  ifconfig "$1" hw ether "$2"
169
+  # debug "DEBUG: Bringing interface up again."
170
+  if "${_isup}"; then
171
+    ifconfig "$1" up
172
+  fi
173
+  # debug "DEBUG: Interface brought up."
174
+}
175
+
176
+get_netmask() {
177
+  # Returns the netmask of network interface $1.
178
+  if [ $# -lt 1 ]; then
179
+    exiterror "$0: In function 'get_netmask': Error: Need to specify a network interface as option."
180
+  fi
181
+
182
+  _nmask="$(ifconfig "$1" | grep -E '\<netmask\>' | sed 's|^.*netmask[[:space:]]*\([0-9a-f\.]*\)[[:space:]].*$|\1|g')"
183
+  stdout "${_nmask}"
184
+}
185
+
186
+get_ipaddress() {
187
+  # Returns the IP address of network interface $1.
188
+  if [ $# -lt 1 ]; then
189
+    exiterror "$0: In function 'get_ipaddress': Error: Need to specify a network interface as option."
190
+  fi
191
+  
192
+  _ipaddr="$(ifconfig "$1" | grep -E '\<inet\>' | sed 's|^.*inet[[:space:]]*\([0-9a-f\.]*\)[[:space:]].*$|\1|g')"
193
+  if [ -z "${_ipaddr}" ]; then
194
+    _ipaddr='0.0.0.0'
195
+  fi
196
+  
197
+  stdout "${_ipaddr}"
198
+}
199
+
200
+get_ipconfig() {
201
+  # Outputs the ip config state of network interface $1. Output format: 'inet <ip> netmask <netmask> [up/down]' (so we could direktly feed back into ifconfig).
202
+  if [ $# -lt 1 ]; then
203
+    exiterror "$0: In function 'get_ipconfig': Error: Need to specify a network interface as option."
204
+  fi
205
+  
206
+  if is_interface_up "$1"; then
207
+    _updown='up'
208
+  else
209
+    _updown='down'
210
+  fi
211
+  
212
+  _ipaddr="$(get_ipaddress "$1")"
213
+  _nmask="$(get_netmask "$1")"
214
+  
215
+  if [ -z "${_ipaddr}" ]; then
216
+    _ipaddr='0.0.0.0'
217
+  fi
218
+  if [ -n "${_nmask}" ]; then
219
+    _nmtext="netmask ${_nmask} "
220
+  else
221
+    _nmtext=""
222
+  fi
223
+  
224
+  stdout "inet ${_ipaddr} ${_nmtext}${_updown}"
225
+}
226
+
227
+get_nat_interfaces() {
228
+  # Returns a newline-separated list of interfaces to add masquerading to their postrouting queue. Examines $_out_iface_all: If $_out_iface_all is true, returns all available interfaces whose name does not start with 'lo'. Otherwise, returns ${_out_iface}.
229
+  _nat_ifaces=""
230
+  if "${_out_iface_all}"; then
231
+    _nat_ifaces="$(ifconfig -a | grep -E '^[^[[:space:]]]*' | awk '{print $1}' | sed 's|\:$||g' | grep -vE '^lo')"
232
+  else
233
+    _nat_ifaces="${_out_iface}"
234
+  fi
235
+  stdout "${_nat_ifaces}"
236
+}
237
+
238
+get_rp_filter_status() {
239
+  # Arguments: $1: Space-, tab- or newline-separated list of interfaces to check rp_filter value.
240
+  if [ $# -lt 1 ]; then
241
+    exiterror "$0: In function 'get_nat_status': Error: Need list of interfaces as option."
242
+  fi
243
+  for _nat_iface in $1; do
244
+    stdout "${_nat_iface} $(cat "/proc/sys/net/ipv4/conf/${_nat_iface}/rp_filter")"
245
+  done
246
+}
247
+
248
+get_ipv4_forward_status() {
249
+  cat "/proc/sys/net/ipv4/ip_forward"
250
+} 
251
+
252
+configure_nat() {
253
+  # Arguments:
254
+  # $1: Space-, tab- or newline-separated list of interfaces to add masquerading to their postrouting queue.
255
+  if [ $# -lt 1 ]; then
256
+    exiterror "$0: In function 'configure_nat': Error: Need list of interfaces as option."
257
+  fi
258
+  get_rp_filter_status "$1" > "${_rp_filter_statusfile}"
259
+  get_ipv4_forward_status > "${_ipv4_forward_statusfile}"
260
+  verbose "Configuring IPv4 forwarding"
261
+  stdout 1 > /proc/sys/net/ipv4/ip_forward
262
+  for _nat_iface in $1; do
263
+    verbose "Configuring masquerading and disabling rp_filter on ${_nat_iface}."
264
+    iptables -t nat -A POSTROUTING -j MASQUERADE -o "${_nat_iface}"
265
+    stdout 0 > "/proc/sys/net/ipv4/conf/${_nat_iface}/rp_filter"
266
+  done
267
+}
268
+
269
+deconfigure_nat() {
270
+  if [ -e "${_rp_filter_statusfile}" ]; then
271
+    cat "${_rp_filter_statusfile}" | while read _line; do
272
+      _nat_iface="$(stdout "${_line}" | awk '{print $1}')"
273
+      _rp_value="$(stdout "${_line}" | awk '{print $2}')"
274
+      verbose "Setting rp_filter to ${_rp_value} on ${_nat_iface}."
275
+      stdout "${_rp_value}" > "/proc/sys/net/ipv4/conf/${_nat_iface}/rp_filter"
276
+    done
277
+    rm -f "${_rp_filter_statusfile}"
278
+  fi
279
+  if [ -e "${_ipv4_forward_statusfile}" ]; then
280
+    _fwd="$(cat "${_ipv4_forward_statusfile}")"
281
+    verbose "Setting IPv4 forwarding to ${_fwd}."
282
+    stdout "${_fwd}" > /proc/sys/net/ipv4/ip_forward
283
+    rm -f "${_ipv4_forward_statusfile}"
284
+  fi
285
+  verbose "Removing all entries from the 'nat' firewall table."
286
+  iptables -t nat -F
287
+}
288
+
289
+configure_ip() {
290
+  # Configures the network interface $1. Expects as argument $2 a string acceptible to ifconfig (e.g. of the format 'inet <IP> netmask <netmask> [up/down]').
291
+  if [ $# -lt 2 ]; then
292
+    exiterror "$0: In function 'configure_ip': Error: Need interface, and configuration as options."
293
+  fi
294
+  
295
+  verbose "Setting network interface $1 to $2."
296
+  ifconfig "$1" $2
297
+}
298
+
299
+configure_wifi_basics() {
300
+  # Configures the WiFi interface $1 for mode $2, ESSID $3, channel $4.
301
+  if [ $# -lt 4 ]; then
302
+    exiterror "$0: In function 'configure_wifi_basics': Error: Need interface, mode, ESSID and channel as options."
303
+  fi
304
+
305
+  verbose "Configuring $1 for WiFi mode $2, ESSID $3 and channel $4."
306
+  iwconfig "$1" mode "$2" essid "$3" channel "$4"
307
+}
308
+
309
+configure_wifi_wep() {
310
+  # Configures the WiFi interface $1 for WEP-encryption with password $2.
311
+  if [ $# -lt 2 ]; then
312
+    exiterror "$0: In function 'configure_wifi_wep': Error: Need interface and WEP-password as options."
313
+  fi
314
+  
315
+  verbose "Setting encryption of $1 to WEP restricted, with password $2."
316
+  iwconfig "$1" key restricted s:"$2"
317
+}
318
+
319
+configure_wifi_wpa() {
320
+  # Configures the WiFi interface $1 for WPA-encryption with ESSID $2 and password $3. $4 specifies the WiFi-Mode we operate (e.g. ad-hoc or master).
321
+  if [ $# -lt 4 ]; then
322
+    exiterror "$0: In function 'configure_wifi_wpa': Error: Need interface, ESSID, WEP-password and WiFi-mode as options."
323
+  fi
324
+  
325
+  _wpaiface="$1"
326
+  _wpaessid="$2"
327
+  _wpapasswd="$3"
328
+  _wpawifimode="$4"
329
+  
330
+  _wpadriver="wext"
331
+  _wpapsk="$(wpa_passphrase "${_wpaessid}" "${_wpapasswd}" | grep -Ev '^[[:space:]]*\#' | grep '^[[:space:]]psk\=' | cut -d'=' -f2)"
332
+  _wpa_group="$(id -gn)"
333
+  
334
+  case "${_wpawifimode}" in
335
+    "ad-hoc")
336
+      _mode=1
337
+      _ap_scan=2
338
+      _key_mgmt='WPA-NONE'
339
+      _pairwise='NONE'
340
+    ;;
341
+    "master")
342
+      exiterror "$0: Error: WPA encryption together with mode 'master' is not implemented yet. Aborting." 99
343
+      _mode=1
344
+      _ap_scan=1
345
+      _key_mgmt='WPA-NONE'
346
+      _pairwise='NONE'
347
+    ;;
348
+    "managed")
349
+      _mode=0
350
+      _ap_scan=1
351
+      _key_mgmt='WPA-PSK'
352
+      _pairwise='NONE'
353
+    ;;
354
+    *)
355
+      exiterror "$0: In function 'configure_wifi_wpa': Error: Not supported WiFi-mode "${_wpawifimode}" specified."
356
+    ;;
357
+  
358
+  esac
359
+  
360
+  _wpaconf="
361
+    ctrl_interface=DIR=${_wpa_ctrl} GROUP=${_wpa_group}
362
+    ap_scan=${_ap_scan}
363
+    network={
364
+      ssid=\"${_wpaessid}\"
365
+      mode="${_mode}"
366
+      proto=WPA
367
+      key_mgmt=${_key_mgmt}
368
+      pairwise=${_pairwise}
369
+      group=TKIP
370
+      psk=${_wpapsk}
371
+    }
372
+"
373
+
374
+  if "${_debug}"; then
375
+    _wpadebug="-dd"
376
+  elif "${_verbose}"; then
377
+    _wpadebug="-d"
378
+  else
379
+    _wpadebug=""
380
+  fi
381
+  
382
+  verbose "Starting wpa_supplicant for interface ${_wpaiface}."
383
+  debug ""
384
+  debug "=== Using the following configuration file for wpa_supplicant: ==="
385
+  debug ""
386
+  debug "${_wpaconf}"
387
+  debug ""
388
+  debug "=== End of wpa_supplicant's config file. ==="
389
+  debug ""
390
+  stdout "${_wpaconf}" | wpa_supplicant ${_wpadebug} -P "${_wpa_pidfile}" -t -f "${_wpa_logfile}" -B -c"/dev/stdin" -i "${_wpaiface}" -D "${_wpadriver}" || {
391
+    _wpa_error="$?"
392
+    exiterror "$0: Error: wpa_supplicant failed to start with exitcode ${_wpa_error}. Aborting." "${_wpa_error}"
393
+  }
394
+}
395
+
396
+configure_wifi() {
397
+  # Configures the WiFi interface. Arguments:
398
+  # $1: Interface
399
+  # $2: Mode
400
+  # $3: ESSID
401
+  # $4: Channel
402
+  # $5: Encryption type
403
+  # $6: Encryption password
404
+  
405
+  if [ $# -lt 6 ]; then
406
+    exiterror "$0: In function 'configure_wifi': Error: Need interface, mode, ESSID, channel, encryption type and encryption password as options."
407
+  fi
408
+  
409
+  _wifi_iface="$1"
410
+  _wifi_mode="$2"
411
+  _wifi_essid="$3"
412
+  _wifi_channel="$4"
413
+  _wifi_enctype="$5"
414
+  _wifi_encpasswd="$6"
415
+  
416
+  configure_wifi_basics "${_wifi_iface}" "${_wifi_mode}" "${_wifi_essid}" "${_wifi_channel}"
417
+  
418
+  case "${_wifi_enctype}" in
419
+    "wep")
420
+      configure_wifi_wep "${_wifi_iface}" "${_wifi_encpasswd}"
421
+    ;;
422
+    "wpa")
423
+      configure_wifi_wpa "${_wifi_iface}" "${_wifi_essid}" "${_wifi_encpasswd}" "${_wifi_mode}"
424
+    ;;
425
+    "off")
426
+      true # Do not configure encryption.
427
+    ;;
428
+    *)
429
+      exiterror "$0: In function 'configure_wifi': Selected unsupported encryption type '${_wifi_enctype}'. Aborting."
430
+    ;;
431
+  esac
432
+}
433
+
434
+start_dnsmasq() {
435
+
436
+  _dnsmasq_iface="${_iface}"
437
+
438
+  _dnsmasq_tftproot="${_tftp_root}"
439
+  
440
+  
441
+  if [ "$(grep dnsmasq /etc/passwd | cut -d':' -f1 )" == dnsmasq ]; then
442
+    _dnsmasq_user=dnsmasq
443
+  else
444
+    _dnsmasq_user=nobody
445
+  fi
446
+
447
+  if [ "$(grep dnsmasq /etc/group | cut -d':' -f1 )" == dnsmasq ]; then
448
+    _dnsmasq_group=dnsmasq
449
+  else
450
+    _dnsmasq_group=nobody
451
+  fi
452
+
453
+  if "${_debug}"; then
454
+    _dnsmasq_debug_options=(
455
+      "--log-queries=extra"
456
+      "--log-dhcp"
457
+    )
458
+  elif "${_verbose}"; then
459
+    _dnsmasq_debug_options=(
460
+      "--log-dhcp"
461
+    )
462
+  else
463
+    _dnsmasq_debug_options=()
464
+  fi
465
+  
466
+  _dnsmasq_general_options=(
467
+    "--no-hosts"
468
+    "--log-facility=${_dnsmasq_logfile}"
469
+    "--pid-file=${_dnsmasq_pidfile}"
470
+    "--user=${_dnsmasq_user}"
471
+    "--group=${_dnsmasq_group}"
472
+    "--interface=${_dnsmasq_iface}"
473
+    "--bind-dynamic"
474
+    # "--bind-interfaces"
475
+    "--dhcp-range=${_dhcprange_lower},${_dhcprange_upper},24h"
476
+    "--read-ethers"
477
+    "--conf-file=/dev/null"
478
+  )
479
+  if "${_no_tftp}"; then
480
+    _dnsmasq_tftp_options=(
481
+    )
482
+  else
483
+    _dnsmasq_tftp_options=(
484
+      "--enable-tftp"
485
+      "--tftp-root=${_dnsmasq_tftproot}"
486
+      "--tftp-no-fail"
487
+    )
488
+  fi
489
+  
490
+  verbose "Starting dnsmasq."
491
+  dnsmasq "${_dnsmasq_debug_options[@]}" "${_dnsmasq_general_options[@]}" "${_dnsmasq_tftp_options[@]}" || {
492
+    _dnsmasq_error="$?"
493
+    exiterror "$0: Error: dnsmasq failed to start with exitcode ${_dnsmasq_error}. Aborting." "${_dnsmasq_error}"
494
+  }
495
+  
496
+}
497
+
498
+kill_by_pidfile() {
499
+  # Kills a process by the PID within the file $1. Optional argument $2: A 'fancy name' of the process to use in error messages.
500
+  if [ $# -lt 1 ]; then
501
+    exiterror "$0: In function 'kill_by_pidfile': Error: Need a PID-file as option."
502
+  fi
503
+  
504
+  if [ $# -ge 2 ]; then
505
+    _fancyname="$2"
506
+  else
507
+    _fancyname="process"
508
+  fi
509
+
510
+  _pid="$(cat "$1")"
511
+  
512
+  verbose "Killing ${_fancyname} (PID ${_pid})."
513
+  
514
+  if [ -d "/proc/${_pid}" ]; then
515
+    kill "${_pid}" || {
516
+      kill -9 "${_pid}" || {
517
+        errmsg "$0: Failed to kill ${_fancyname} (PID "${_pid}")".
518
+      }
519
+    }
520
+  else
521
+    errmsg "$0: ${_fancyname}'s PID-file $1 is present, but no process under that PID (${_pid}) is running."
522
+  fi
523
+
524
+}
525
+
526
+string_whitelist() {
527
+  # Checks the string $1 against a whitelist: Returns one if the string passes, zero if it contains any character not in the whitelist.
528
+  # As optional argument $2 a whitelist to be fed to tr can be used, if not specified a default is used.
529
+  if [ $# -lt 1 ]; then
530
+    exiterror "$0: In function 'string_whitelist': Error: Need a string to test as option."
531
+  fi
532
+
533
+  if [ $# -ge 2 ]; then
534
+    _whitelist="$2"
535
+  else
536
+    _whitelist='[a-zA-Z0-9\._\-]'
537
+  fi
538
+
539
+  if [ -z "$(stdout "$1" | tr -d "${_whitelist}")" ]; then
540
+    return 0
541
+  else
542
+    return 1
543
+  fi
544
+}
545
+
546
+
547
+_iface="${_iface_default}"
548
+_ip="${_ip_default}"
549
+_netmask="${_netmask_default}"
550
+_out_iface_all="${_out_iface_all_default}"
551
+_out_iface="${_out_iface_default}"
552
+# _dhcprange_lower is set after parsing the options.
553
+# _dhcprange_upper is set after parsing the options.
554
+_macaddress_change="${_macaddress_change_default}"
555
+_macaddress="${_macaddress_default}"
556
+_essid="${_essid_default}"
557
+_channel="${_channel_default}"
558
+_encryption="${_encryption_default}"
559
+_enckey="${_enckey_default}"
560
+_wifimode="${_wifimode_default}"
561
+_no_wifi="${_no_wifi_default}"
562
+_no_ipconfig="${_no_ipconfig_default}"
563
+_no_nat="${_no_nat_default}"
564
+_tftp_root="${_tftp_root_default}"
565
+_no_tftp="${_no_tftp_default}"
566
+_verbose="${_verbose_default}"
567
+_debug="${_debug_default}"
568
+_rundir_base="${_rundir_base_default}"
569
+
570
+
571
+printusage() {
572
+  stdout "Usage:"
573
+  stdout "  $0 action [arguments ...]"
574
+  stdout ""
575
+  stdout "Actions (exactly one required):"
576
+  stdout "  up   | start                      Start the thing."
577
+  stdout "  down | stop                       Stop the thing."
578
+  stdout "  stat | status | state | show      Show the status of the thing."
579
+  stdout "  -h   | --help | help              Print this message and exit."
580
+  stdout "  -V   | --version                  Print version number and exit. (Version is: '${_version}'.)"
581
+  stdout ""
582
+  stdout "Arguments (all optional):"
583
+  stdout "  -h   | --help | help              Print this message and exit."
584
+  stdout "  -V   | --version                  Print version number and exit. (Version is: '${_version}'.)"
585
+  stdout "  -v   | --verbose                  Print information as we go on/ start daemons verbosely."
586
+  stdout "  -d   | --debug                    Print debug output/ start daemons with debug output."
587
+  stdout "                                    Implies verbose."
588
+  stdout "  -i   | --iface <iface>            Interface on which the connection should be made available"
589
+  stdout "                                    (default: ${_iface_default})."
590
+  stdout "                                    Only characters out of the set [a-zA-Z0-9\._\-] are allowed."
591
+  stdout "  -ip  | --ip <ip>                  IPv4-address to configure this interface to (default: ${_ip_default})."
592
+  stdout "  -nm  | --netmask <netmask>        Netmask to use on this interface (default: ${_netmask_default})."
593
+  stdout "  -m   | --mac <MAC-address>        Set the MAC-address of this interface (defaults to the"
594
+  stdout "                                    interface's native MAC-address)."
595
+  stdout "  -ni  | --no-ipconfig              If specified, do not configure IP information for this"
596
+  stdout "                                    interface. Useful e.g. if already configured."
597
+  stdout "                                    Specifying this option, the following won't be configured:" 
598
+  stdout "                                    IP-address, netmask, MAC-address."
599
+  stdout "  -o   | --out-iface <iface>        If specified, configure masquerading ('NAT') only for"
600
+  stdout "                                    packages leaving on this interface (usually this is your"
601
+  stdout "                                    interface which connects to the internet, not the one"
602
+  stdout "                                    specified by the option '-i' / '--iface')."
603
+  stdout "                                    Only characters out of the set [a-zA-Z0-9\._\-] are allowed."
604
+  stdout "                                    If not specified, NAT will be configured on all available non-"
605
+  stdout "                                    local interfaces (determined by name starting with 'lo')."
606
+  stdout "  -nn  | --no-nat                   If specified, do not configure and deconfigure network address"
607
+  stdout "                                    translation, forwarding and masquerading."
608
+  stdout "  -dl  | --dhcp-lower <dhcp-ip>     Lower end of the range of IP-addresses to assign to"
609
+  stdout "                                    clients. The default is the first three numbers of our"
610
+  stdout "                                    IP-address, and then ${_dhcprange_lower_suffix_default}, e.g. $(make_newip_from_suffix "${_ip_default}" ${_dhcprange_lower_suffix_default})"
611
+  stdout "  -du  | --dhcp-upper <dhcp-ip>     Upper end of the range of IP-addresses to assign to"
612
+  stdout "                                    clients. The default is the first three numbers of our"
613
+  stdout "                                    IP-address, and then ${_dhcprange_upper_suffix_default}, e.g. $(make_newip_from_suffix "${_ip_default}" ${_dhcprange_upper_suffix_default})"
614
+  stdout "  -wm  | --wifi-mode <mode>         The WiFi-mode to set the interface to. Allowed modes:"
615
+  stdout "                                    'ad-hoc', 'master', 'managed'. (Default: ${_wifimode_default}.)"
616
+  stdout "  -e   | --essid <ESSID>            Set the WiFi ESSID to use (default: ${_essid_default})."
617
+  stdout "  -c   | --channel <wifi-channel>   Set the WiFi channel to use (default: ${_channel_default})."
618
+  stdout "  -enc | --enc <encryption-type>    Set the type of WiFi encryption to use. Possible values:"
619
+  stdout "                                    'off', 'wep', 'wpa'. (Default: ${_encryption_default})."
620
+  stdout "  -key | --key <enc-password>       Set the password to use for the WiFi encryption key"
621
+  stdout "                                    (default: ${_enckey_default})."
622
+  stdout "                                    NOTE: For WEP, the password has to be 5 or 13 characters long."
623
+  stdout "                                          For WPA, it has to be between 8 ans 63 characters long."
624
+  stdout "  -nw  | --no-wifi                  If specified, do not wifi-configure the interface. Useful"
625
+  stdout "                                    e.g. if already configured or it's not a WiFi interface."
626
+  stdout "                                    Specifying this option, the following won't be configured:" 
627
+  stdout "                                    WiFi-mode, ESSID, channel, encryption type, encryption key."
628
+  stdout "  -tf  | --tftp-root <dir>          Directory where to serve files for TFTP network boot from"
629
+  stdout "                                    (default: ${_tftp_root_default})"
630
+  stdout "  -nt  | --no-tftp                  If specified, do not provide a TFTP server."
631
+  stdout "  -r   | --rundir <directory>       Where to store and look for runtime information"
632
+  stdout "                                    (default: ${_rundir_base_default}). It get's created if nonextisting."
633
+  stdout ""
634
+  stdout "(Info: We were started at ${_datetime}.)"
635
+}
636
+
637
+_dhcp_lower_explicitly_set=false
638
+_dhcp_upper_explicitly_set=false
639
+
640
+if [ $# -lt 1 ]; then
641
+  errmsg "$0: Error: Need at least one action specified."
642
+  errmsg ""
643
+  errmsg "Try option '-h' for a help."
644
+  errmsg ""
645
+  exiterror "Aborting." 10
646
+fi
647
+
648
+_action="$1"
649
+case "${_action}" in
650
+  "up"|"start")
651
+    _action="up"
652
+  ;;
653
+  "down"|"stop")
654
+    _action="down"
655
+  ;;
656
+  "stat"|"status"|"state"|"show")
657
+    _action="status"
658
+  ;;
659
+  "-h"|"--help"|"help")
660
+    printusage
661
+    exit 0
662
+  ;;
663
+  "-V"|"--version")
664
+    msg "${_version}"
665
+    exit 0
666
+  ;;
667
+  *)
668
+    errmsg "$0: Error: Invalid action '${_action}' specified."
669
+    errmsg ""
670
+    errmsg "$(printusage)"
671
+    errmsg ""
672
+    exiterror "Aborting." 10
673
+  ;;
674
+esac
675
+shift
676
+
677
+while [ $# -ge 1 ]; do
678
+  
679
+  case "$1" in
680
+  
681
+    "-h"|"--help"|"help")
682
+      shift
683
+      printusage
684
+      exit 0
685
+    ;;
686
+    
687
+    "-V"|"--version")
688
+      shift
689
+      msg "${_version}"
690
+      exit 0
691
+    ;;
692
+    
693
+    "-i"|"--iface")
694
+      shift
695
+      if [ $# -ge 1 ]; then
696
+        _iface="$1"
697
+      else
698
+        errmsg "$0: Error: Too few arguments for option '-i' or '--iface': Need to specify an interface."
699
+        errmsg ""
700
+        errmsg "$(printusage)"
701
+        errmsg ""
702
+        exiterror "Aborting." 11
703
+      fi
704
+      shift
705
+    ;;
706
+    
707
+    "-ip"|"--ip")
708
+      shift
709
+      if [ $# -ge 1 ]; then
710
+        _ip="$1"
711
+      else
712
+        errmsg "$0: Error: Too few arguments for option '-ip' or '--ip': Need to specify an IPv4-address."
713
+        errmsg ""
714
+        errmsg "$(printusage)"
715
+        errmsg ""
716
+        exiterror "Aborting." 12
717
+      fi
718
+      shift
719
+    ;;
720
+    
721
+    "-nm"|"--netmask")
722
+      shift
723
+      if [ $# -ge 1 ]; then
724
+        _netmask="$1"
725
+      else
726
+        errmsg "$0: Error: Too few arguments for option '-nm' or '--netmask': Need to specify a netmask."
727
+        errmsg ""
728
+        errmsg "$(printusage)"
729
+        errmsg ""
730
+        exiterror "Aborting." 13
731
+      fi
732
+      shift
733
+    ;;
734
+    
735
+    "-ni"|"--no-ipconfig")
736
+      shift
737
+      _no_ipconfig='true'
738
+    ;;
739
+    
740
+    "-o"|"--out-iface")
741
+      shift
742
+      if [ $# -ge 1 ]; then
743
+        _out_iface_all="false"
744
+        _out_iface="$1"
745
+      else
746
+        errmsg "$0: Error: Too few arguments for option '-o' or '--out-iface': Need to specify an interface."
747
+        errmsg ""
748
+        errmsg "$(printusage)"
749
+        errmsg ""
750
+        exiterror "Aborting." 16
751
+      fi
752
+      shift
753
+    ;;
754
+    
755
+    "-nn"|"--no-nat")
756
+      shift
757
+      _no_nat='true'
758
+    ;;
759
+    
760
+    "-dl"|"--dhcp-lower")
761
+      shift
762
+      if [ $# -ge 1 ]; then
763
+        _dhcprange_lower="$1"
764
+        _dhcp_lower_explicitly_set=true
765
+      else
766
+        errmsg "$0: Error: Too few arguments for option '-dl' or '--dhcp-lower': Need to specify an IPv4-address."
767
+        errmsg ""
768
+        errmsg "$(printusage)"
769
+        errmsg ""
770
+        exiterror "Aborting." 14
771
+      fi
772
+      shift
773
+    ;;
774
+
775
+    "-du"|"--dhcp-upper")
776
+      shift
777
+      if [ $# -ge 1 ]; then
778
+        _dhcprange_upper="$1"
779
+        _dhcp_upper_explicitly_set=true
780
+      else
781
+        errmsg "$0: Error: Too few arguments for option '-du' or '--dhcp-upper': Need to specify an IPv4-address."
782
+        errmsg ""
783
+        errmsg "$(printusage)"
784
+        errmsg ""
785
+        exiterror "Aborting." 15
786
+      fi
787
+      shift
788
+    ;;
789
+
790
+    "-m"|"--mac")
791
+      shift
792
+      if [ $# -ge 1 ]; then
793
+        _macaddress_change='true'
794
+        _macaddress="$1"
795
+      else
796
+        errmsg "$0: Error: Too few arguments for option '-m' or '--mac': Need to specify a MAC-address."
797
+        errmsg ""
798
+        errmsg "$(printusage)"
799
+        errmsg ""
800
+        exiterror "Aborting." 17
801
+      fi
802
+      shift
803
+    ;;
804
+
805
+    "-wm"|"--wifi-mode")
806
+      shift
807
+      if [ $# -ge 1 ]; then
808
+        _wifimode="$1"
809
+      else
810
+        errmsg "$0: Error: Too few arguments for option '-wm' or '--wifi-mode': Need to specify a WiFi mode."
811
+        errmsg ""
812
+        errmsg "$(printusage)"
813
+        errmsg ""
814
+        exiterror "Aborting." 18
815
+      fi
816
+      case "${_wifimode}" in
817
+        "ad-hoc"|"master"|"managed")
818
+          true # Everything is fine.
819
+        ;;
820
+        *)
821
+          errmsg "$0: Not allowed WiFi-mode '${_wifimode}' specified for the '-wm' or '--wifi-mode'-option."
822
+          errmsg ""
823
+          errmsg "$(printusage)"
824
+          errmsg ""
825
+          exiterror "Aborting." 2
826
+        ;;
827
+      esac
828
+      shift
829
+    ;;
830
+
831
+    "-e"|"--essid")
832
+      shift
833
+      if [ $# -ge 1 ]; then
834
+        _essid="$1"
835
+      else
836
+        errmsg "$0: Error: Too few arguments for option '-e' or '--essid': Need to specify a WiFi ESSID."
837
+        errmsg ""
838
+        errmsg "$(printusage)"
839
+        errmsg ""
840
+        exiterror "Aborting." 19
841
+      fi
842
+      shift
843
+    ;;
844
+
845
+    "-c"|"--channel")
846
+      shift
847
+      if [ $# -ge 1 ]; then
848
+        _channel="$1"
849
+      else
850
+        errmsg "$0: Error: Too few arguments for option '-c' or '--channel': Need to specify a WiFi channel."
851
+        errmsg ""
852
+        errmsg "$(printusage)"
853
+        errmsg ""
854
+        exiterror "Aborting." 20
855
+      fi
856
+      shift
857
+    ;;
858
+
859
+    "-enc"|"--enc")
860
+      shift
861
+      if [ $# -ge 1 ]; then
862
+        _encryption="$1"
863
+      else
864
+        errmsg "$0: Error: Too few arguments for option '-enc' or '--enc': Need to specify a WiFi encryption type."
865
+        errmsg ""
866
+        errmsg "$(printusage)"
867
+        errmsg ""
868
+        exiterror "Aborting." 21
869
+      fi
870
+      case "${_encryption}" in
871
+        "off"|"wep"|"wpa")
872
+          true # Everything is fine.
873
+        ;;
874
+        *)
875
+          errmsg "$0: Not allowed WiFi encryption type '${_encryption}' specified for the '-enc' or '--enc'-option."
876
+          errmsg ""
877
+          errmsg "$(printusage)"
878
+          errmsg ""
879
+          exiterror "Aborting." 2
880
+        ;;
881
+      esac
882
+
883
+      shift
884
+    ;;
885
+
886
+    "-key"|"--key")
887
+      shift
888
+      if [ $# -ge 1 ]; then
889
+        _enckey="$1"
890
+      else
891
+        errmsg "$0: Error: Too few arguments for option '-key' or '--key': Need to specify a WiFi encryption password."
892
+        errmsg ""
893
+        errmsg "$(printusage)"
894
+        errmsg ""
895
+        exiterror "Aborting." 22
896
+      fi
897
+      _enckeylength="$(stdout -n "${_enckey}" | wc -c)"
898
+      case "${_encryption}" in
899
+        "wep")
900
+          if [ ${_enckeylength} -ne 5 ] && [ ${_enckeylength} -ne 13 ]; then
901
+            errmsg "$0: Error: For WEP-encryption, the length of the password has to be 5 or 13 characters. Yours was ${_enckeylength}."
902
+            errmsg ""
903
+            exiterror "Aborting." 2
904
+          fi
905
+        ;;
906
+        "wpa")
907
+          if [ ${_enckeylength} -lt 8 ] || [ ${_enckeylength} -gt 63 ]; then
908
+            errmsg "$0: Error: For WPA-encryption, the length of the password has to be between 8 and 63 characters. Yours was ${_enckeylength}."
909
+            errmsg ""
910
+            exiterror "Aborting." 2
911
+          fi
912
+        ;;
913
+        *)
914
+          true # Everything is fine since there is no encryption, so the password does not matter.
915
+        ;;
916
+      esac
917
+      shift
918
+    ;;
919
+
920
+    "-nw"|"--no-wifi")
921
+      shift
922
+      _no_wifi='true'
923
+    ;;
924
+    
925
+    "-v"|"--verbose")
926
+      shift
927
+      _verbose='true'
928
+    ;;
929
+    
930
+    "-d"|"--debug")
931
+      shift
932
+      _verbose='true'
933
+      _debug='true'
934
+    ;;
935
+    
936
+    "-tf"|"--tftp-root")
937
+      shift
938
+      if [ $# -ge 1 ]; then
939
+        _tftp_root="$1"
940
+      else
941
+        errmsg "$0: Error: Too few arguments for option '-tf' or '--tftp-root': Need to specify a directory."
942
+        errmsg ""
943
+        errmsg "$(printusage)"
944
+        errmsg ""
945
+        exiterror "Aborting." 23
946
+      fi
947
+      shift
948
+    ;;
949
+    
950
+    "-nt"|"--no-tftp")
951
+      shift
952
+      _no_tftp='true'
953
+    ;;
954
+    
955
+    "-r"|"--rundir")
956
+      shift
957
+      if [ $# -ge 1 ]; then
958
+        _rundir_base="$1"
959
+      else
960
+        errmsg "$0: Error: Too few arguments for option '-r' or '--rundir': Need to specify a directory."
961
+        errmsg ""
962
+        errmsg "$(printusage)"
963
+        errmsg ""
964
+        exiterror "Aborting." 24
965
+      fi
966
+      shift
967
+    ;;
968
+
969
+    *)
970
+      _unknownarg="$1"
971
+      shift
972
+      errmsg "$0: Error: Unrecognised argument '${_unknownarg}'."
973
+      errmsg ""
974
+      errmsg "$(printusage)"
975
+      errmsg ""
976
+      exiterror "Aborting." 1
977
+    ;;
978
+  
979
+  esac
980
+  
981
+done
982
+
983
+if ! "${_dhcp_lower_explicitly_set}"; then
984
+  _dhcprange_lower="$(make_newip_from_suffix "${_ip}" ${_dhcprange_lower_suffix_default})"
985
+fi
986
+
987
+if ! "${_dhcp_upper_explicitly_set}"; then
988
+  _dhcprange_upper="$(make_newip_from_suffix "${_ip}" ${_dhcprange_upper_suffix_default})"
989
+fi
990
+
991
+string_whitelist "${_iface}" || {
992
+  errmsg "$0: Error: Interface name '${_iface}' (specified via the '-i' or '--iface'-option or set as a default) contains invalid characters."
993
+  errmsg "See help."
994
+  exiterror "Aborting."
995
+}
996
+
997
+_instance="${_iface}"
998
+_rundir="${_rundir_base}/${_instance}"
999
+
1000
+_wpa_logfilebase='wpa_supplicant.log'
1001
+_wpa_ctrlfilebase='wpa_supplicant.ctrl'
1002
+_wpa_pidfilebase='wpa_supplicant.pid'
1003
+_dnsmasq_logfilebase='dnsmasq.log'
1004
+_dnsmasq_pidfilebase='dnsmasq.pid'
1005
+_origmacfilebase='macaddress.orig'
1006
+_origifconfigfilebase='ifconfig.orig'
1007
+_wificonfiguredfilebase='wifi.orig'
1008
+_startedatfilebase='datetime.txt'
1009
+_rp_filter_statusfilebase='rp_filter.orig'
1010
+_ipv4_forward_statusfilebase='ipv4_forward.orig'
1011
+_nat_configuredfilebase='nat_configured'
1012
+
1013
+_wpa_ctrl="${_rundir}/${_wpa_ctrlfilebase}"
1014
+_wpa_pidfile="${_rundir}/${_wpa_pidfilebase}"
1015
+_wpa_logfile="${_rundir}/${_wpa_logfilebase}"
1016
+_dnsmasq_logfile="${_rundir}/${_dnsmasq_logfilebase}"
1017
+_dnsmasq_pidfile="${_rundir}/${_dnsmasq_pidfilebase}"
1018
+_origmacfile="${_rundir}/${_origmacfilebase}"
1019
+_origifconfigfile="${_rundir}/${_origifconfigfilebase}"
1020
+_wificonfiguredfile="${_rundir}/${_wificonfiguredfilebase}"
1021
+_startedatfile="${_rundir}/${_startedatfilebase}"
1022
+_rp_filter_statusfile="${_rundir}/${_rp_filter_statusfilebase}"
1023
+_ipv4_forward_statusfile="${_rundir}/${_ipv4_forward_statusfilebase}"
1024
+_nat_configuredfile="${_rundir}/${_nat_configuredfilebase}"
1025
+
1026
+
1027
+if "${_verbose}"; then
1028
+  _mkdirverbose="-v"
1029
+  _rmverbose="-v"
1030
+fi
1031
+
1032
+verbose "Started at ${_datetime}."
1033
+
1034
+case "${_action}" in
1035
+
1036
+  "up")
1037
+  
1038
+    mkdir ${_mkdirverbose} -p "${_rundir}"
1039
+    cd "${_rundir}"
1040
+    
1041
+    stdout "${_datetime}" > "${_startedatfile}"
1042
+    
1043
+    if "${_macaddress_change}"; then
1044
+      get_macaddress "${_iface}" > "${_origmacfile}"
1045
+      set_macaddress "${_iface}" "${_macaddress}"
1046
+    fi
1047
+
1048
+    if ! "${_no_wifi}"; then
1049
+      stdout "We configured WiFi, so we take it down afterwards. (In fact, only the existence of this file matters, not it's content.)" > "${_wificonfiguredfile}"
1050
+      configure_wifi "${_iface}" "${_wifimode}" "${_essid}" "${_channel}" "${_encryption}" "${_enckey}"
1051
+    fi
1052
+
1053
+    if ! "${_no_ipconfig}"; then
1054
+      get_ipconfig "${_iface}" > "${_origifconfigfile}"
1055
+      configure_ip "${_iface}" "inet ${_ip} netmask ${_netmask} up"
1056
+    fi
1057
+    
1058
+    if ! "${_no_nat}"; then
1059
+      _nat_interfaces="$(get_nat_interfaces | tr '\n' ' ')"
1060
+      configure_nat "${_nat_interfaces}"
1061
+      stdout "${_nat_interfaces}" > "${_nat_configuredfile}"
1062
+    fi
1063
+    
1064
+    start_dnsmasq
1065
+    
1066
+  ;;
1067
+
1068
+  "down")
1069
+    
1070
+    if [ -d "${_rundir}" ]; then
1071
+      cd "${_rundir}"
1072
+    else
1073
+      errmsg "$0: Cannot bring down, since specified runtime information directory ${_rundir} does not exist."
1074
+    fi
1075
+    
1076
+    if [ -e "${_nat_configuredfile}" ]; then
1077
+      deconfigure_nat
1078
+      rm -f "${_nat_configuredfile}"
1079
+    fi
1080
+    
1081
+    if [ -e "${_wpa_pidfile}" ]; then
1082
+      kill_by_pidfile "${_wpa_pidfile}" "wpa_supplicant"
1083
+      rm -f "${_wpa_pidfile}"
1084
+    fi
1085
+    
1086
+    if [ -e "${_dnsmasq_pidfile}" ]; then
1087
+      kill_by_pidfile "${_dnsmasq_pidfile}" "dnsmasq"
1088
+      rm -f "${_dnsmasq_pidfile}"
1089
+    fi
1090
+    
1091
+    if [ -e "${_origifconfigfile}" ]; then
1092
+      configure_ip "${_iface}" "$(cat "${_origifconfigfile}")"
1093
+      rm -f "${_origifconfigfile}"
1094
+    fi
1095
+
1096
+    if [ -e "${_wificonfiguredfile}" ]; then
1097
+      configure_wifi "${_iface}" managed any 0 off "${_enckey_default}"
1098
+      rm -f "${_wificonfiguredfile}"
1099
+    fi
1100
+    
1101
+    if [ -e "${_origmacfile}" ]; then
1102
+      set_macaddress "${_iface}" "$(cat "${_origmacfile}")"
1103
+      rm -f "${_origmacfile}"
1104
+    fi
1105
+    
1106
+    rm -f "${_startedatfile}"
1107
+    rm -Rf "${_rundir}"/*
1108
+    rmdir ${_rmverbose} "${_rundir}"
1109
+  ;;
1110
+
1111
+  "status")
1112
+    _instances="$(find "${_rundir_base}" -mindepth 1 -maxdepth 1 -type d)"
1113
+    if [ -z "${_instances}" ]; then
1114
+      stdout "No runtime information present at '${_rundir_base}/'. Probably nothing running."
1115
+    else
1116
+      cd "${_rundir_base}"
1117
+      for _inst in ${_instances}; do
1118
+        _inst="$(basename "${_inst}")"
1119
+        _instdir="${_rundir_base}/${_inst}"
1120
+        stdout "${_inst}:"
1121
+        {
1122
+          [ -e "${_instdir}/${_startedatfilebase}" ] && stdout "Started: $(cat "${_instdir}/${_startedatfilebase}")" || true
1123
+          stdout -n "$(get_ipconfig "${_inst}")"; [ -e "${_instdir}/${_origifconfigfilebase}" ] && {
1124
+            stdout -n " (Old: $(cat "${_instdir}/${_origifconfigfilebase}")),"
1125
+          } || true
1126
+          stdout -n " "
1127
+          stdout -n "ether $(get_macaddress "${_inst}")"; [ -e "${_instdir}/${_origmacfilebase}" ] && {
1128
+            stdout -n " (Old: $(cat "${_instdir}/${_origmacfilebase}"))"
1129
+          } || true
1130
+          stdout ""
1131
+          
1132
+          [ -e "${_instdir}/${_nat_configuredfilebase}" ] && {
1133
+            stdout -n "NAT: Configured by us for interfaces $(cat "${_instdir}/${_nat_configuredfilebase}")."
1134
+          } || {
1135
+            stdout -n "NAT: Not configured by us."
1136
+          }
1137
+          stdout ""
1138
+          
1139
+          [ -e "${_instdir}/${_wpa_pidfilebase}" ] && {
1140
+            stdout -n "wpa_supplicant: PID: $(cat "${_instdir}/${_wpa_pidfilebase}"), "; [ -d "/proc/$(cat "${_instdir}/${_wpa_pidfilebase}")" ] && stdout -n "Running." || stdout -n "Not running."
1141
+          } || {
1142
+            stdout -n "wpa_supplicant: Could not determine PID."
1143
+          }
1144
+          [ -e "${_instdir}/${_wpa_logfilebase}" ] && stdout -n " Logfile: '${_instdir}/${_wpa_logfilebase}'." || true
1145
+          stdout ""
1146
+          
1147
+          stdout -n "dnsmasq: "; [ -e "${_instdir}/${_dnsmasq_pidfilebase}" ] && {
1148
+            stdout -n "PID: $(cat "${_instdir}/${_dnsmasq_pidfilebase}"), "; [ -d "/proc/$(cat "${_instdir}/${_dnsmasq_pidfilebase}")" ] && stdout -n "Running." || stdout -n "Not running."
1149
+          } || {
1150
+            stdout -n "Could not determine PID."
1151
+          }
1152
+          [ -e "${_instdir}/${_dnsmasq_logfilebase}" ] && stdout -n " Logfile: '${_instdir}/${_dnsmasq_logfilebase}'." || true
1153
+          stdout ""
1154
+
1155
+        } | stdout_prefix "        "
1156
+        stdout ""
1157
+      done
1158
+    fi
1159
+  ;;
1160
+
1161
+  *)
1162
+    exiterror "$0: Error: Unknown action '${_action}'. Aborting."
1163
+  ;;
1164
+
1165
+esac