mirror of
https://github.com/vincentmli/bpfire.git
synced 2026-04-09 18:45:54 +02:00
wireguard: Add wireguard initscript
commit b78ba3624f0a11c060ad06dbd65741b82684d93e Author: Michael Tremer <michael.tremer@ipfire.org> Date: Tue Apr 16 16:17:59 2024 +0200 wireguard: Add initscript Signed-off-by: Michael Tremer <michael.tremer@ipfire.org> Signed-off-by: Vincent Li <vincent.mc.li@gmail.com>
This commit is contained in:
@@ -92,6 +92,7 @@ etc/rc.d/init.d/udev_retry
|
|||||||
etc/rc.d/init.d/unbound
|
etc/rc.d/init.d/unbound
|
||||||
etc/rc.d/init.d/vnstat
|
etc/rc.d/init.d/vnstat
|
||||||
etc/rc.d/init.d/waitdrives
|
etc/rc.d/init.d/waitdrives
|
||||||
|
etc/rc.d/init.d/wireguard
|
||||||
etc/rc.d/init.d/wlanclient
|
etc/rc.d/init.d/wlanclient
|
||||||
etc/rc.d/init.d/xdptailcall
|
etc/rc.d/init.d/xdptailcall
|
||||||
etc/rc.d/init.d/ddos
|
etc/rc.d/init.d/ddos
|
||||||
@@ -107,6 +108,7 @@ etc/rc.d/rc0.d/K30sshd
|
|||||||
etc/rc.d/rc0.d/K47setclock
|
etc/rc.d/rc0.d/K47setclock
|
||||||
etc/rc.d/rc0.d/K49cyrus-sasl
|
etc/rc.d/rc0.d/K49cyrus-sasl
|
||||||
etc/rc.d/rc0.d/K51vnstat
|
etc/rc.d/rc0.d/K51vnstat
|
||||||
|
etc/rc.d/rc0.d/K70wireguard
|
||||||
etc/rc.d/rc0.d/K77conntrackd
|
etc/rc.d/rc0.d/K77conntrackd
|
||||||
etc/rc.d/rc0.d/K78suricata
|
etc/rc.d/rc0.d/K78suricata
|
||||||
etc/rc.d/rc0.d/K79leds
|
etc/rc.d/rc0.d/K79leds
|
||||||
@@ -138,6 +140,7 @@ etc/rc.d/rc3.d/S24cyrus-sasl
|
|||||||
etc/rc.d/rc3.d/S30sshd
|
etc/rc.d/rc3.d/S30sshd
|
||||||
etc/rc.d/rc3.d/S32apache
|
etc/rc.d/rc3.d/S32apache
|
||||||
etc/rc.d/rc3.d/S40fcron
|
etc/rc.d/rc3.d/S40fcron
|
||||||
|
etc/rc.d/rc3.d/S50wireguard
|
||||||
etc/rc.d/rc3.d/S98rc.local
|
etc/rc.d/rc3.d/S98rc.local
|
||||||
etc/rc.d/rc3.d/S99grub-btrfsd
|
etc/rc.d/rc3.d/S99grub-btrfsd
|
||||||
#etc/rc.d/rc3.d/S99imspetor
|
#etc/rc.d/rc3.d/S99imspetor
|
||||||
@@ -156,6 +159,7 @@ etc/rc.d/rc6.d/K30sshd
|
|||||||
etc/rc.d/rc6.d/K47setclock
|
etc/rc.d/rc6.d/K47setclock
|
||||||
etc/rc.d/rc6.d/K49cyrus-sasl
|
etc/rc.d/rc6.d/K49cyrus-sasl
|
||||||
etc/rc.d/rc6.d/K51vnstat
|
etc/rc.d/rc6.d/K51vnstat
|
||||||
|
etc/rc.d/rc6.d/K70wireguard
|
||||||
etc/rc.d/rc6.d/K77conntrackd
|
etc/rc.d/rc6.d/K77conntrackd
|
||||||
etc/rc.d/rc6.d/K78suricata
|
etc/rc.d/rc6.d/K78suricata
|
||||||
etc/rc.d/rc6.d/K79leds
|
etc/rc.d/rc6.d/K79leds
|
||||||
|
|||||||
@@ -101,6 +101,7 @@ $(TARGET) :
|
|||||||
ln -sf ../init.d/setclock /etc/rc.d/rc0.d/K47setclock
|
ln -sf ../init.d/setclock /etc/rc.d/rc0.d/K47setclock
|
||||||
ln -sf ../init.d/cyrus-sasl /etc/rc.d/rc0.d/K49cyrus-sasl
|
ln -sf ../init.d/cyrus-sasl /etc/rc.d/rc0.d/K49cyrus-sasl
|
||||||
ln -sf ../init.d/vnstat /etc/rc.d/rc0.d/K51vnstat
|
ln -sf ../init.d/vnstat /etc/rc.d/rc0.d/K51vnstat
|
||||||
|
ln -sf ../init.d/wireguard /etc/rc.d/rc0.d/K70wireguard
|
||||||
ln -sf ../init.d/conntrackd /etc/rc.d/rc0.d/K77conntrackd
|
ln -sf ../init.d/conntrackd /etc/rc.d/rc0.d/K77conntrackd
|
||||||
ln -sf ../init.d/suricata /etc/rc.d/rc0.d/K78suricata
|
ln -sf ../init.d/suricata /etc/rc.d/rc0.d/K78suricata
|
||||||
ln -sf ../init.d/leds /etc/rc.d/rc0.d/K79leds
|
ln -sf ../init.d/leds /etc/rc.d/rc0.d/K79leds
|
||||||
@@ -131,6 +132,7 @@ $(TARGET) :
|
|||||||
ln -sf ../init.d/apache /etc/rc.d/rc3.d/S32apache
|
ln -sf ../init.d/apache /etc/rc.d/rc3.d/S32apache
|
||||||
ln -sf ../init.d/haproxy /etc/rc.d/rc3.d/S35haproxy
|
ln -sf ../init.d/haproxy /etc/rc.d/rc3.d/S35haproxy
|
||||||
ln -sf ../init.d/fcron /etc/rc.d/rc3.d/S40fcron
|
ln -sf ../init.d/fcron /etc/rc.d/rc3.d/S40fcron
|
||||||
|
ln -sf ../init.d/wireguard /etc/rc.d/rc3.d/S50wireguard
|
||||||
ln -sf ../../sysconfig/rc.local /etc/rc.d/rc3.d/S98rc.local
|
ln -sf ../../sysconfig/rc.local /etc/rc.d/rc3.d/S98rc.local
|
||||||
ln -sf ../init.d/grub-btrfsd /etc/rc.d/rc3.d/S99grub-btrfsd
|
ln -sf ../init.d/grub-btrfsd /etc/rc.d/rc3.d/S99grub-btrfsd
|
||||||
ln -sf ../init.d/imspetor /etc/rc.d/rc3.d/S99imspetor
|
ln -sf ../init.d/imspetor /etc/rc.d/rc3.d/S99imspetor
|
||||||
@@ -147,6 +149,7 @@ $(TARGET) :
|
|||||||
ln -sf ../init.d/setclock /etc/rc.d/rc6.d/K47setclock
|
ln -sf ../init.d/setclock /etc/rc.d/rc6.d/K47setclock
|
||||||
ln -sf ../init.d/cyrus-sasl /etc/rc.d/rc6.d/K49cyrus-sasl
|
ln -sf ../init.d/cyrus-sasl /etc/rc.d/rc6.d/K49cyrus-sasl
|
||||||
ln -sf ../init.d/vnstat /etc/rc.d/rc6.d/K51vnstat
|
ln -sf ../init.d/vnstat /etc/rc.d/rc6.d/K51vnstat
|
||||||
|
ln -sf ../init.d/wireguard /etc/rc.d/rc6.d/K70wireguard
|
||||||
ln -sf ../init.d/conntrackd /etc/rc.d/rc6.d/K77conntrackd
|
ln -sf ../init.d/conntrackd /etc/rc.d/rc6.d/K77conntrackd
|
||||||
ln -sf ../init.d/suricata /etc/rc.d/rc6.d/K78suricata
|
ln -sf ../init.d/suricata /etc/rc.d/rc6.d/K78suricata
|
||||||
ln -sf ../init.d/leds /etc/rc.d/rc6.d/K79leds
|
ln -sf ../init.d/leds /etc/rc.d/rc6.d/K79leds
|
||||||
|
|||||||
391
src/initscripts/system/wireguard
Normal file
391
src/initscripts/system/wireguard
Normal file
@@ -0,0 +1,391 @@
|
|||||||
|
#!/bin/sh
|
||||||
|
###############################################################################
|
||||||
|
# #
|
||||||
|
# IPFire.org - A linux based firewall #
|
||||||
|
# Copyright (C) 2024 Michael Tremer <michael.tremer@ipfire.org> #
|
||||||
|
# #
|
||||||
|
# This program is free software: you can redistribute it and/or modify #
|
||||||
|
# it under the terms of the GNU General Public License as published by #
|
||||||
|
# the Free Software Foundation, either version 3 of the License, or #
|
||||||
|
# (at your option) any later version. #
|
||||||
|
# #
|
||||||
|
# This program is distributed in the hope that it will be useful, #
|
||||||
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of #
|
||||||
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the #
|
||||||
|
# GNU General Public License for more details. #
|
||||||
|
# #
|
||||||
|
# You should have received a copy of the GNU General Public License #
|
||||||
|
# along with this program. If not, see <http://www.gnu.org/licenses/>. #
|
||||||
|
# #
|
||||||
|
###############################################################################
|
||||||
|
|
||||||
|
shopt -s nullglob
|
||||||
|
|
||||||
|
. /etc/sysconfig/rc
|
||||||
|
. ${rc_functions}
|
||||||
|
. /etc/rc.d/init.d/networking/functions.network
|
||||||
|
|
||||||
|
eval $(/usr/local/bin/readhash /var/ipfire/wireguard/settings)
|
||||||
|
|
||||||
|
interfaces() {
|
||||||
|
local id
|
||||||
|
local enabled
|
||||||
|
local type
|
||||||
|
local _rest
|
||||||
|
|
||||||
|
local IFS=','
|
||||||
|
|
||||||
|
# wg0 will always be created for roadwarrior
|
||||||
|
echo "wg0"
|
||||||
|
|
||||||
|
while read -r id enabled type _rest; do
|
||||||
|
# Skip peers that are not enabled
|
||||||
|
[ "${enabled}" = "on" ] || continue
|
||||||
|
|
||||||
|
# Skip anything that isn't a net-to-net connection
|
||||||
|
[ "${type}" = "net" ] || continue
|
||||||
|
|
||||||
|
echo "wg${id}"
|
||||||
|
done < /var/ipfire/wireguard/peers
|
||||||
|
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
interface_is_rw() {
|
||||||
|
local intf="${1}"
|
||||||
|
|
||||||
|
[ "${intf}" = "wg0" ]
|
||||||
|
}
|
||||||
|
|
||||||
|
setup_interface() {
|
||||||
|
local intf="${1}"
|
||||||
|
|
||||||
|
# Create the interface if it does not exist
|
||||||
|
if [ ! -d "/sys/class/net/${intf}" ]; then
|
||||||
|
ip link add "${intf}" type wireguard || return $?
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Set up the interface
|
||||||
|
ip link set "${intf}" up
|
||||||
|
|
||||||
|
# Set the MTU
|
||||||
|
if [ -n "${MTU}" ]; then
|
||||||
|
ip link set "${intf}" mtu "${MTU}" || return $?
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Load the configuration into the kernel
|
||||||
|
wg syncconf "${intf}" <(generate_config "${intf}") || return $?
|
||||||
|
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
cleanup_interfaces() {
|
||||||
|
local interfaces=( "$(interfaces)" )
|
||||||
|
|
||||||
|
local intf
|
||||||
|
for intf in /sys/class/net/wg[0-9]*; do
|
||||||
|
[ -d "${intf}" ] || continue
|
||||||
|
|
||||||
|
# Remove the path
|
||||||
|
intf="${intf##*/}"
|
||||||
|
|
||||||
|
local found=0
|
||||||
|
local i
|
||||||
|
|
||||||
|
for i in ${interfaces[@]}; do
|
||||||
|
if [ "${intf}" = "${i}" ]; then
|
||||||
|
found=1
|
||||||
|
break
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
|
||||||
|
if [ "${found}" -eq 0 ]; then
|
||||||
|
ip link del "${intf}"
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
# Replaces 0.0.0.0/0 with 0.0.0.0/1 and 128.0.0.0/1 so that we can route all traffic
|
||||||
|
# through a WireGuard tunnel.
|
||||||
|
expand_subnets() {
|
||||||
|
local subnet
|
||||||
|
|
||||||
|
for subnet in $@; do
|
||||||
|
case "${subnet}" in
|
||||||
|
0.0.0.0/0|0.0.0.0/0.0.0.0)
|
||||||
|
echo -n "0.0.0.0/1,"
|
||||||
|
echo -n "128.0.0.0/1,"
|
||||||
|
;;
|
||||||
|
|
||||||
|
*)
|
||||||
|
echo -n "${subnet},"
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
done
|
||||||
|
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
generate_config() {
|
||||||
|
local intf="${1}"
|
||||||
|
|
||||||
|
# Flush all previously set routes
|
||||||
|
ip route flush dev "${intf}"
|
||||||
|
|
||||||
|
local IFS=','
|
||||||
|
|
||||||
|
local id
|
||||||
|
local enabled
|
||||||
|
local type
|
||||||
|
local name
|
||||||
|
local pubkey
|
||||||
|
local privkey
|
||||||
|
local port
|
||||||
|
local endpoint_addr
|
||||||
|
local endpoint_port
|
||||||
|
local remote_subnets
|
||||||
|
local remarks
|
||||||
|
local local_subnets
|
||||||
|
local psk
|
||||||
|
local keepalive
|
||||||
|
local local_address
|
||||||
|
local _rest
|
||||||
|
|
||||||
|
# Handles the special case of the RW interface
|
||||||
|
if interface_is_rw "${intf}"; then
|
||||||
|
echo "[Interface]"
|
||||||
|
echo "PrivateKey = ${PRIVATE_KEY}"
|
||||||
|
|
||||||
|
# Optionally set the port
|
||||||
|
if [ -n "${PORT}" ]; then
|
||||||
|
echo "ListenPort = ${PORT}"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Add the client pool
|
||||||
|
if [ -n "${CLIENT_POOL}" ]; then
|
||||||
|
ip route add "${CLIENT_POOL}" dev "${intf}"
|
||||||
|
fi
|
||||||
|
|
||||||
|
while read -r id enabled type name pubkey privkey port endpoint_addr endpoint_port \
|
||||||
|
remote_subnets remarks local_subnets psk keepalive local_address _rest; do
|
||||||
|
# Skip peers that are not hosts or not enabled
|
||||||
|
[ "${type}" = "host" ] || continue
|
||||||
|
[ "${enabled}" = "on" ] || continue
|
||||||
|
|
||||||
|
echo "[Peer]"
|
||||||
|
echo "PublicKey = ${pubkey}"
|
||||||
|
|
||||||
|
# Set PSK (if set)
|
||||||
|
if [ -n "${psk}" ]; then
|
||||||
|
echo "PresharedKey = ${psk}"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Set routes
|
||||||
|
if [ -n "${remote_subnets}" ]; then
|
||||||
|
echo "AllowedIPs = ${remote_subnets//|/, }"
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo # newline
|
||||||
|
done < /var/ipfire/wireguard/peers
|
||||||
|
|
||||||
|
return 0
|
||||||
|
fi
|
||||||
|
|
||||||
|
local local_subnet
|
||||||
|
local remote_subnet
|
||||||
|
|
||||||
|
while read -r id enabled type name pubkey privkey port endpoint_addr endpoint_port \
|
||||||
|
remote_subnets remarks local_subnets psk keepalive local_address _rest; do
|
||||||
|
# Check for the matching connection
|
||||||
|
[ "${type}" = "net" ] || continue
|
||||||
|
[ "${intf}" = "wg${id}" ] || continue
|
||||||
|
|
||||||
|
# Skip peers that are not enabled
|
||||||
|
[ "${enabled}" = "on" ] || continue
|
||||||
|
|
||||||
|
# Update the interface alias
|
||||||
|
ip link set "${intf}" alias "${name}"
|
||||||
|
|
||||||
|
# Flush any addresses
|
||||||
|
ip addr flush dev "${intf}"
|
||||||
|
|
||||||
|
# Assign the local address
|
||||||
|
if [ -n "${local_address}" ]; then
|
||||||
|
ip addr add "${local_address}" dev "${intf}"
|
||||||
|
|
||||||
|
# Apply MASQUERADE
|
||||||
|
iptables -t nat -A WGNAT -o "${intf}" -j MASQUERADE
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo "[Interface]"
|
||||||
|
|
||||||
|
if [ -n "${privkey}" ]; then
|
||||||
|
echo "PrivateKey = ${privkey}"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Optionally set the port
|
||||||
|
if [ -n "${port}" ]; then
|
||||||
|
echo "ListenPort = ${port}"
|
||||||
|
|
||||||
|
# Open the port
|
||||||
|
iptables -A WGINPUT -p udp --dport "${port}" -j ACCEPT
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo "[Peer]"
|
||||||
|
echo "PublicKey = ${pubkey}"
|
||||||
|
|
||||||
|
# Set PSK (if set)
|
||||||
|
if [ -n "${psk}" ]; then
|
||||||
|
echo "PresharedKey = ${psk}"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Set endpoint
|
||||||
|
if [ -n "${endpoint_addr}" ]; then
|
||||||
|
echo "Endpoint = ${endpoint_addr}${endpoint_port:+:}${endpoint_port}"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Set routes
|
||||||
|
if [ -n "${remote_subnets}" ]; then
|
||||||
|
echo "AllowedIPs = ${remote_subnets//|/, }"
|
||||||
|
|
||||||
|
# Apply the routes
|
||||||
|
local_subnets=( "${local_subnets//|/,}" )
|
||||||
|
remote_subnets=( "${remote_subnets//|/,}" )
|
||||||
|
|
||||||
|
# Find an IP address of the firewall that is inside the routed subnet
|
||||||
|
local src="$(ipfire_address_in_networks "${local_subnets[@]}")"
|
||||||
|
|
||||||
|
for remote_subnet in $(expand_subnets "${remote_subnets[@]}"); do
|
||||||
|
local args=(
|
||||||
|
"${remote_subnet}" "dev" "${intf}"
|
||||||
|
)
|
||||||
|
|
||||||
|
# Add the preferred source if we found one
|
||||||
|
if [ -n "${src}" ]; then
|
||||||
|
args+=( "src" "${src}" )
|
||||||
|
fi
|
||||||
|
|
||||||
|
ip route add "${args[@]}"
|
||||||
|
done
|
||||||
|
|
||||||
|
# Add a direct host route to the endpoint
|
||||||
|
if [ -s "/var/ipfire/red/remote-ipaddress" ]; then
|
||||||
|
ip route add table wg \
|
||||||
|
"${endpoint_addr}" via "$(</var/ipfire/red/remote-ipaddress)"
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Set keepalive
|
||||||
|
if [ -n "${keepalive}" ]; then
|
||||||
|
echo "PersistentKeepalive = ${keepalive}"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Set blocking rules
|
||||||
|
for local_subnet in ${local_subnets//|/ }; do
|
||||||
|
for remote_subnet in ${remote_subnets//|/ }; do
|
||||||
|
iptables -I WGBLOCK \
|
||||||
|
-s "${remote_subnet}" -d "${local_subnet}" -j RETURN
|
||||||
|
done
|
||||||
|
done
|
||||||
|
|
||||||
|
# There will only be one match, so we can break as soon we get here
|
||||||
|
break
|
||||||
|
done < /var/ipfire/wireguard/peers
|
||||||
|
}
|
||||||
|
|
||||||
|
reload_firewall() {
|
||||||
|
# Flush all previous rules
|
||||||
|
iptables -F WGINPUT
|
||||||
|
iptables -t nat -F WGNAT
|
||||||
|
|
||||||
|
if [ "${ENABLED}" = "on" ]; then
|
||||||
|
iptables -A WGINPUT -p udp --dport "${PORT}" -j ACCEPT
|
||||||
|
fi
|
||||||
|
|
||||||
|
iptables -F WGBLOCK
|
||||||
|
|
||||||
|
# Don't block any traffic from Roadwarrior peers
|
||||||
|
if [ -n "${CLIENT_POOL}" ]; then
|
||||||
|
iptables -A WGBLOCK -s "${CLIENT_POOL}" -i wg0 -j RETURN
|
||||||
|
iptables -A WGBLOCK -d "${CLIENT_POOL}" -o wg0 -j RETURN
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Block all other traffic
|
||||||
|
iptables -A WGBLOCK -j REJECT --reject-with icmp-admin-prohibited
|
||||||
|
|
||||||
|
# Flush any custom routes
|
||||||
|
ip route flush table wg 2>/dev/null
|
||||||
|
|
||||||
|
# Ensure that the table is being looked up
|
||||||
|
if ! ip rule | grep -q "lookup wg"; then
|
||||||
|
ip rule add table wg
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
wg_start() {
|
||||||
|
local failed=0
|
||||||
|
local intf
|
||||||
|
|
||||||
|
# Find all interfaces
|
||||||
|
local interfaces=( "$(interfaces)" )
|
||||||
|
|
||||||
|
# Shut down any unwanted interfaces
|
||||||
|
cleanup_interfaces
|
||||||
|
|
||||||
|
# Reload the firewall
|
||||||
|
reload_firewall
|
||||||
|
|
||||||
|
# Setup all interfaces
|
||||||
|
for intf in ${interfaces[@]}; do
|
||||||
|
setup_interface "${intf}" || failed=1
|
||||||
|
done
|
||||||
|
|
||||||
|
return ${failed}
|
||||||
|
}
|
||||||
|
|
||||||
|
wg_stop() {
|
||||||
|
local intf
|
||||||
|
|
||||||
|
# Reload the firewall
|
||||||
|
ENABLED=off reload_firewall
|
||||||
|
|
||||||
|
for intf in /sys/class/net/wg[0-9]*; do
|
||||||
|
ip link del "${intf##*/}"
|
||||||
|
done
|
||||||
|
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
case "${1}" in
|
||||||
|
start)
|
||||||
|
if [ "${ENABLED}" != "on" ]; then
|
||||||
|
exit 0
|
||||||
|
fi
|
||||||
|
|
||||||
|
boot_mesg "Starting WireGuard VPN..."
|
||||||
|
wg_start; evaluate_retval
|
||||||
|
;;
|
||||||
|
|
||||||
|
stop)
|
||||||
|
boot_mesg "Stopping WireGuard VPN..."
|
||||||
|
wg_stop; evaluate_retval
|
||||||
|
;;
|
||||||
|
|
||||||
|
reload)
|
||||||
|
boot_mesg "Reloading WireGuard VPN..."
|
||||||
|
wg_start; evaluate_retval
|
||||||
|
;;
|
||||||
|
|
||||||
|
restart)
|
||||||
|
${0} stop
|
||||||
|
sleep 1
|
||||||
|
${0} start
|
||||||
|
;;
|
||||||
|
|
||||||
|
*)
|
||||||
|
echo "Usage: ${0} {start|stop|reload|restart}"
|
||||||
|
exit 1
|
||||||
|
;;
|
||||||
|
esac
|
||||||
Reference in New Issue
Block a user