From 12d0ee83711079f1c16b63b3a3f826f240da93a3 Mon Sep 17 00:00:00 2001 From: Emran Billah Date: Fri, 16 Aug 2024 13:14:54 -0300 Subject: [PATCH] Working ok with a single xbnet, file structure and code encapsulation looking good, iptable updating ok, need to figure out issues with bridge network --- .env | 15 +-- Dockerfile | 28 ++++-- docker-compose-run-multiple.yml | 4 + docker-compose.yml | 24 ++--- entrypoint.sh | 142 ++++++++++++++++++++++++++++- scripts/get_connected_wifi_info.sh | 12 +++ scripts/health_check.sh | 15 +++ supervisord.conf | 8 ++ 8 files changed, 221 insertions(+), 27 deletions(-) mode change 100644 => 100755 .env create mode 100644 scripts/health_check.sh create mode 100644 supervisord.conf diff --git a/.env b/.env old mode 100644 new mode 100755 index 8c11247..f9a08d8 --- a/.env +++ b/.env @@ -1,11 +1,14 @@ # Configuration for xbnet0 XBEE0_PORT=/dev/ttyUSB0 -XBEE0_BAUDRATE=/dev/ttyUSB0 -XBEE0_NET_SRC_IP=192.168.8.1 -XBEE0_NET_DST_IP=192.168.8.2 +XBEE0_BAUDRATE=230400 +XBEE0_NET_SRC_IP=192.168.1.10 # Note: This requires the subnet 192.168.1... (to match with the default gateway, or use Masquerade if changing the subnet) +XBEE0_NET_DST_IP=192.168.1.11 # Note: This requires the subnet 192.168.1... (to match with the default gateway, or use Masquerade if changing the subnet) +XBEE0_NET_IFACE_NAME=xbnet0 # Configuration for xbnet1 XBEE1_PORT=/dev/ttyUSB1 -XBEE1_BAUDRATE=/dev/ttyUSB1 -XBEE1_NET_SRC_IP=192.168.8.2 -XBEE1_NET_DST_IP=192.168.8.1 +XBEE1_BAUDRATE=230400 +XBEE1_NET_SRC_IP=192.168.1.11 # Note: This requires the subnet 192.168.1... (to match with the default gateway, or use Masquerade if changing the subnet) +XBEE1_NET_DST_IP=192.168.1.10 # Note: This requires the subnet 192.168.1... (to match with the default gateway, or use Masquerade if changing the subnet) +XBEE1_NET_IFACE_NAME=xbnet1 + diff --git a/Dockerfile b/Dockerfile index c20f392..a84526d 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,11 +1,15 @@ # Use an official Rust image as the base FROM rust:latest -# Install dependencies +# Install necessary packages RUN apt-get update && apt-get install -y \ libudev-dev \ iproute2 \ iputils-ping \ + net-tools \ + bridge-utils \ + iptables \ + supervisor \ && rm -rf /var/lib/apt/lists/* # Clone the xbnet repository @@ -13,14 +17,24 @@ RUN git clone https://github.com/jgoerzen/xbnet.git /usr/src/xbnet # Build xbnet WORKDIR /usr/src/xbnet -RUN cargo build && cargo build --release +RUN cargo build --release -# Copy the built binary to /usr/local/bin +# Copy the built binary to /usr/local/bin (makes it accessible from anywhere in the OS) RUN cp target/release/xbnet /usr/local/bin/xbnet -# Create and copy the entrypoint script to root location "/" -COPY ./entrypoint.sh / +# Copy the entrypoint script +COPY entrypoint.sh /entrypoint.sh RUN chmod +x /entrypoint.sh -ENTRYPOINT ["/entrypoint.sh"] -CMD ["bash"] +# Copy the supervisor config file +COPY supervisord.conf /etc/supervisor/conf.d/supervisord.conf + +# Copy the health check script from local ./scripts/ to container root / +COPY ./scripts/health_check.sh /health_check.sh +RUN chmod +x /health_check.sh + +# Add the health check +HEALTHCHECK CMD /health_check.sh || exit 1 + +# Start supervisord as the main command +CMD ["/usr/bin/supervisord", "-c", "/etc/supervisor/conf.d/supervisord.conf"] diff --git a/docker-compose-run-multiple.yml b/docker-compose-run-multiple.yml index d3959c8..a0264fa 100644 --- a/docker-compose-run-multiple.yml +++ b/docker-compose-run-multiple.yml @@ -1,3 +1,7 @@ +# TODO: This will not work with current configuration +# Use a bash script to either dynamicall generate this file or append to services +# based on how many xbnets you want to create + version: '3.8' services: diff --git a/docker-compose.yml b/docker-compose.yml index da625cc..0eb72b0 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -5,15 +5,15 @@ services: build: . container_name: xbee_node privileged: true - env_file: - - .env - devices: - - "${XBEE0_PORT}:${XBEE0_PORT}" - command: > - bash -c " - xbnet -d --serial-speed ${XBEE0_BAUDRATE} ${XBEE0_PORT} tun; - ip addr add ${XBEE1_NET_SRC_IP}/24 dev xbnet0; - ip link set dev xbnet0 up; - ping -c 4 ${XBEE1_NET_DST_IP}; - sleep infinity - " + env_file: .env + restart: always + networks: + default: + ipv4_address: ${XBEE0_NET_SRC_IP} + +networks: + default: + driver: bridge + ipam: + config: + - subnet: 192.168.1.0/24 # Note: the xbnet assigned IPs must be on this subnet (if Masquerade is not used) diff --git a/entrypoint.sh b/entrypoint.sh index 1a91860..d3d2aaf 100644 --- a/entrypoint.sh +++ b/entrypoint.sh @@ -1,4 +1,142 @@ #!/bin/bash -set -e -exec "$@" \ No newline at end of file +# Source the get_connected_wifi_info.sh script +source ./scripts/get_connected_wifi_info.sh + +# Check if the script is running with root privileges +check_root() { + if [ "$(id -u)" -ne 0 ]; then + echo "This script must be run as root. Exiting..." + exit 1 + fi +} + +# Clean up resources +# - Kill the background process used to create the xbnet interface +# - Cleanup any resources created or copied over. This includes: +# - Bridge interface +# - xbnet interface +cleanup() { + echo "Cleaning up resources..." + pkill -f "xbnet -d --serial-speed $XBEE0_BAUDRATE $XBEE0_PORT tap" + + if ip link show br0 > /dev/null 2>&1; then + ip link set br0 down + brctl delbr br0 + fi + + if ip link show $XBEE0_NET_IFACE_NAME > /dev/null 2>&1; then + ip link set $XBEE0_NET_IFACE_NAME down + ip link delete $XBEE0_NET_IFACE_NAME + fi +} + +# Function to check if the XBee device is connected +check_xbee_device() { + if [ -e "$XBEE0_PORT" ]; then + echo "XBee device found at $XBEE0_PORT. Proceeding with setup..." + return 0 + else + echo "Error: No XBee device found at $XBEE0_PORT. Please connect the device." + return 1 + fi +} + +# Start the xbnet interface +# - Also check if the starting the xbnet interface was successful +# - And return appropriate status codes +start_xbnet_interface() { + echo "Starting XBee network interface..." + xbnet -d --serial-speed $XBEE0_BAUDRATE $XBEE0_PORT tap & + + while [ ! -d "/sys/class/net/$XBEE0_NET_IFACE_NAME" ]; do + echo "Waiting for interface $XBEE0_NET_IFACE_NAME to be created..." + sleep 1 + done + + XBEE0_NET_IFACE_NAME=$(ls /sys/class/net | grep 'xbnet') + + if [ -z "$XBEE0_NET_IFACE_NAME" ]; then + echo "Error: No XBee network interface found." + return 1 + else + echo "XBee network interface $XBEE0_NET_IFACE_NAME created successfully." + return 0 + fi +} + +# Configure the network interface and bridge +# - Create interface with name specified by XBEE0_NET_IFACE_NAME in .env file +# - Create bridge interface (this bridge will be used to connect xbnet to host wifi) +# - Attach xbnet to bridge +# - Start the bridge interface +configure_network_and_bridge() { + ip addr add $XBEE0_NET_SRC_IP/24 dev $XBEE0_NET_IFACE_NAME + ip link set dev $XBEE0_NET_IFACE_NAME up + + brctl addbr br0 + brctl addif br0 $XBEE0_NET_IFACE_NAME + ip link set dev br0 up +} + +# Monitor and bridge Wi-Fi +# - If a connected wifi interface is found +# - Add it to the bridge interface with xbnet +# - Else +# - keep looking for a newly established connection with a wifi interface +monitor_and_bridge_wifi() { + while true; do + HOST_WIFI_IFACE=$(get_connected_wifi_device) + + if [ -n "$HOST_WIFI_IFACE" ]; then + echo "Wi-Fi interface found: $HOST_WIFI_IFACE. Bridging with $XBEE0_NET_IFACE_NAME..." + brctl addif br0 $HOST_WIFI_IFACE + + iptables -t nat -A POSTROUTING -o $HOST_WIFI_IFACE -j MASQUERADE + iptables -A FORWARD -i br0 -o $HOST_WIFI_IFACE -j ACCEPT + iptables -A FORWARD -i $HOST_WIFI_IFACE -o br0 -j ACCEPT + + echo "Bridge configured. Monitoring for changes..." + break + else + echo "No Wi-Fi interface found. Rechecking in 5 seconds..." + sleep 5 + fi + done +} + +# Function to monitor the XBee device and restart setup if disconnected +monitor_xbee_device() { + while [ -e "$XBEE0_PORT" ]; do + sleep 5 + done + + echo "XBee device at $XBEE0_PORT was removed. Cleaning up..." + cleanup +} + +# Main function to set up the XBee network +setup_xbee_network() { + while true; do + check_xbee_device + if [ $? -ne 0 ]; then + sleep 5 + continue + fi + + start_xbnet_interface + if [ $? -ne 0 ]; then + cleanup + sleep 5 + continue + fi + + configure_network_and_bridge + monitor_and_bridge_wifi + monitor_xbee_device + done +} + +# Run the setup only if the script is executed as root +check_root +setup_xbee_network diff --git a/scripts/get_connected_wifi_info.sh b/scripts/get_connected_wifi_info.sh index 757fd70..d4c7d34 100755 --- a/scripts/get_connected_wifi_info.sh +++ b/scripts/get_connected_wifi_info.sh @@ -1,5 +1,15 @@ +# get_connected_wifi_info.sh +# +# Usage: eg. +# source ./get_connected_wifi_info.sh +# wifi_device=$(get_connected_wifi_device) +# wifi_name=$(get_connected_wifi_name) +# + #!/bin/bash +# get_connected_wifi_device() +# - Returns wifi device id, eg. wlp0s20f3 get_connected_wifi_device() { # Get the active Wi-Fi connections connections=$(nmcli -t -f DEVICE,TYPE,STATE device | grep -E '^.*:wifi:connected$' | cut -d: -f1) @@ -13,6 +23,8 @@ get_connected_wifi_device() { fi } +# get_connected_wifi_device() +# - Returns wifi device name, eg. spiri-field get_connected_wifi_name() { # Get the device name of the first connected Wi-Fi device device=$(get_connected_wifi_device) diff --git a/scripts/health_check.sh b/scripts/health_check.sh new file mode 100644 index 0000000..7e15855 --- /dev/null +++ b/scripts/health_check.sh @@ -0,0 +1,15 @@ +#!/bin/bash + +# Ensure the environment variables are loaded +source /etc/environment + +# Perform the health check by pinging the xbnet interface +# - If the xbnet0 interface is successfully created, we should be able to ping the assigned IP +ping -c 1 "$XBEE0_NET_SRC_IP" > /dev/null 2>&1 + +# Return the appropriate status based on ping success +if [ $? -eq 0 ]; then + exit 0 +else + exit 1 +fi diff --git a/supervisord.conf b/supervisord.conf new file mode 100644 index 0000000..b853cc3 --- /dev/null +++ b/supervisord.conf @@ -0,0 +1,8 @@ +[supervisord] +nodaemon=true + +[program:xbnet] +command=/entrypoint.sh +autorestart=true +stderr_logfile=/var/log/xbnet.err.log +stdout_logfile=/var/log/xbnet.out.log