arp proxy: add hotplug

This commit is contained in:
Cyberes 2023-06-27 11:05:04 -06:00
parent 9ad732c123
commit a7396a23e4
7 changed files with 140 additions and 20 deletions

View File

@ -6,7 +6,7 @@ After=basic.target network.target
[Service]
SyslogIdentifier=wlan2eth
ExecStart=/bin/bash /opt/wlan2eth/bridge/nat/wlan2eth.sh
ExecStart=/bin/bash /opt/wlan2eth/bridge/nat/run-bridge-nat.sh
Restart=always
RestartSec=2

View File

@ -2,6 +2,6 @@
This bridge is a lot simpler than the NAT version. Just plug your client(s) into the bridge and it should just work.
Make sure to use a hub (NOT a switch) if you have more than one bridged client. A switch doesn't let the bridge see all the traffic from the clients.
I've heard people say that a hub (NOT a switch) is required when bridging more than one client (likely due to the fact that a switch doesn't let the bridge see all the traffic from the clients). But I don't think this matters.
Also, `parprouted` has a bug where it prints its error messages as raw Ethernet frames over the network. If something isn't working, open Wireshark and restart `parprouted`. Look for white "Ethernet II" frames.
Also, `parprouted` has a bug where it prints its log messages as raw Ethernet frames over the network. If something isn't working, open Wireshark and restart `parprouted`. Look for white "Ethernet II" frames.

View File

@ -157,38 +157,47 @@ grep '^enable-reflector=yes$' /etc/avahi/avahi-daemon.conf || {
cat > /etc/systemd/system/parprouted.service <<EOF
[Unit]
Description=proxy arp routing service
Description=Parprouted ARP Routing
Documentation=https://raspberrypi.stackexchange.com/q/88954/79866
#Requires=sys-subsystem-net-devices-$WLAN_IFACE.device dhcpcd.service
#After=sys-subsystem-net-devices-$WLAN_IFACE.device dhcpcd.service
After=network.target
[Service]
Type=forking
# Restart until $WLAN_IFACE gained carrier
Type=simple
# Restart the service until $WLAN_IFACE gained carrier
Restart=on-failure
RestartSec=5
TimeoutStartSec=30
# clone the dhcp-allocated IP to $ETH_IFACE so dhcp-helper will relay for the correct subnet
ExecStartPre=/bin/bash -c '/sbin/ip addr add \$(/sbin/ip -4 -br addr show $WLAN_IFACE | /bin/grep -Po "\\\d+\\\.\\\d+\\\.\\\d+\\\.\\\d+")/32 dev $ETH_IFACE'
ExecStartPre=/sbin/ip link set dev $ETH_IFACE down
ExecStartPre=/sbin/ip link set dev $ETH_IFACE up
ExecStartPre=/sbin/ip link set $WLAN_IFACE promisc on
ExecStart=-/usr/sbin/parprouted $ETH_IFACE $WLAN_IFACE
ExecStopPost=/sbin/ip link set $WLAN_IFACE promisc off
ExecStopPost=/sbin/ip link set dev $ETH_IFACE down
ExecStopPost=/sbin/ip link set dev $ETH_IFACE up
ExecStopPost=/bin/bash -c '/sbin/ip addr del \$(/sbin/ip -4 -br addr show $WLAN_IFACE | /bin/grep -Po "\\\d+\\\.\\\d+\\\.\\\d+\\\.\\\d+")/32 dev $ETH_IFACE'
ExecStart="$DIR/parprouted.sh"
RemainAfterExit=yes
[Install]
WantedBy=wpa_supplicant.service
EOF
cat > /etc/systemd/system/parprouted-monitor.service <<EOF
[Unit]
Description=Parprouted ARP Routing Hotplug
[Service]
ExecStart="$DIR/parprouted-monitor.sh"
Restart=always
[Install]
WantedBy=multi-user.target
EOF
ip link set dev $ETH_IFACE down
ip link set dev $ETH_IFACE up
systemctl daemon-reload
systemctl enable --now parprouted dhcp-helper
systemctl restart parprouted dhcp-helper
systemctl enable --now parprouted dhcp-helper parprouted-monitor
systemctl restart parprouted dhcp-helper parprouted-monitor
systemctl status --no-pager dhcp-helper
systemctl status --no-pager parprouted
systemctl status --no-pager parprouted-monitor
systemctl status --no-pager parprouted.service
echo -e "\n==============\nDone!\nNow reboot!"

View File

@ -0,0 +1,39 @@
#!/usr/bin/env bash
SOURCE=${BASH_SOURCE[0]}
while [ -L "$SOURCE" ]; do
DIR=$(cd -P "$(dirname "$SOURCE")" >/dev/null 2>&1 && pwd)
SOURCE=$(readlink "$SOURCE")
[[ $SOURCE != /* ]] && SOURCE=$DIR/$SOURCE
done
DIR=$(cd -P "$(dirname "$SOURCE")" >/dev/null 2>&1 && pwd)
if [[ -f "$DIR/../../config/arp-config.sh" ]]; then
. "$DIR/../../config/arp-config.sh"
else
echo "$DIR/../../config/arp-config.sh missing!"
exit 1
fi
if [ "$(id -u)" -ne 0 ]; then
echo 'This script must be run as root.' >&2
exit 1
fi
if [ ! -f "/sys/class/net/$ETH_IFACE/operstate" ]; then
echo "ERROR: $ETH_IFACE does not exist?"
echo "File does not exist: /sys/class/net/$ETH_IFACE/operstate"
exit 1
fi
# ==============================================================================
while true; do
if ethtool $ETH_IFACE | grep -q "Link detected: yes"; then
systemctl --quiet is-active parprouted || systemctl --quiet start parprouted
else
systemctl --quiet is-active parprouted && systemctl --quiet stop parprouted
fi
sleep 1
done

68
bridge/proxyarp/parprouted.sh Executable file
View File

@ -0,0 +1,68 @@
#!/usr/bin/env bash
SOURCE=${BASH_SOURCE[0]}
while [ -L "$SOURCE" ]; do
DIR=$(cd -P "$(dirname "$SOURCE")" >/dev/null 2>&1 && pwd)
SOURCE=$(readlink "$SOURCE")
[[ $SOURCE != /* ]] && SOURCE=$DIR/$SOURCE
done
DIR=$(cd -P "$(dirname "$SOURCE")" >/dev/null 2>&1 && pwd)
if [[ -f "$DIR/../../config/arp-config.sh" ]]; then
. "$DIR/../../config/arp-config.sh"
else
echo "$DIR/../../config/arp-config.sh missing!"
exit 1
fi
if [ "$(id -u)" -ne 0 ]; then
echo 'This script must be run as root.' >&2
exit 1
fi
if [ ! -f "/sys/class/net/$ETH_IFACE/operstate" ]; then
echo "ERROR: $ETH_IFACE does not exist?"
echo "File does not exist: /sys/class/net/$ETH_IFACE/operstate"
exit 1
fi
EXITING=0
function ctrl_c() {
# Reset the interfaces
if [ $EXITING -eq 0 ]; then # prevent running this multiple times
EXITING=1
echo "Cleaning up..."
ip link set $WLAN_IFACE promisc off
ip link set dev $ETH_IFACE down
ip link set dev $ETH_IFACE up
ip addr del $(/sbin/ip -4 -br addr show $WLAN_IFACE | /bin/grep -Po "\\d+\\.\\d+\\.\\d+\\.\\d+")/32 dev $ETH_IFACE
exit
fi
}
# ==============================================================================
while ! ethtool $ETH_IFACE | grep -q "Link detected: yes"; do
echo "Waiting for wired interface $ETH_IFACE to come up..."
sleep 10s
done
# Clone our DCHP-allocated IP from wlan0 to eth0 so dhcp-helper will relay for the correct subnet
echo "Initializing..."
trap ctrl_c SIGINT
trap ctrl_c SIGTERM
ip addr add $(/sbin/ip -4 -br addr show $WLAN_IFACE | /bin/grep -Po "\\d+\\.\\d+\\.\\d+\\.\\d+")/32 dev $ETH_IFACE
ip link set $WLAN_IFACE promisc on
while true; do
WLAN_IFACE_IP=$(ip -4 -br addr show $WLAN_IFACE | grep -Po "\\d+\\.\\d+\\.\\d+\\.\\d+")
if [ -n "${WLAN_IFACE_IP}" ]; then
break
fi
echo "Waiting for wireless interface $WLAN_IFACE to get an IP..."
sleep 10s
done
parprouted -d $ETH_IFACE $WLAN_IFACE

View File

@ -22,7 +22,7 @@ func (c ClientInfo) StringMAC() string {
var bridgedClients = make(map[string]ClientInfo)
var bridgedClientsLock sync.Mutex
func AddBridgedClient(ip net.IP, mac net.HardwareAddr, eth0MAC, wlan0MAC net.HardwareAddr, eth0 string) {
func AddBridgedClient(ip net.IP, mac, eth0MAC, wlan0MAC net.HardwareAddr, eth0 string) {
log := logger.GetLogger()
// Ignore the wlan0 MAC address
@ -30,18 +30,22 @@ func AddBridgedClient(ip net.IP, mac net.HardwareAddr, eth0MAC, wlan0MAC net.Har
log.Debugf("Not adding client IP (wlan0): %s", ip)
return
}
// Ignore the eth0 MAC address
if bytes.Equal(mac, eth0MAC) {
log.Debugf("Not adding client IP (eth0): %s", ip)
return
}
// Sometimes this IP shows up
if ip.String() == "0.0.0.0" {
log.Debug("Not adding client IP: 0.0.0.0")
return
}
// Windows clients will self-assign an IP
if isAPIPA(ip) {
log.Debugf("Not adding client IP (APIPA): %s", ip)
return
}
// Exclude other wierdness
if isExcluded(ip) {
log.Debugf("Not adding client IP (excluded): %s", ip)
return