Skip to content

Instantly share code, notes, and snippets.

@adonistseriotis
Created April 28, 2023 12:15
Show Gist options
  • Save adonistseriotis/798a14557fd38399bfb26ffffff907ef to your computer and use it in GitHub Desktop.
Save adonistseriotis/798a14557fd38399bfb26ffffff907ef to your computer and use it in GitHub Desktop.
Setup your Raspberry Pi as a Wi-Fi access point
#!/bin/bash
# Helper log function
log () {
local COLOR='\033[0;32m' # Blue color code
case "${2}" in
error) COLOR='\033[0;31m';;
warning) COLOR='\033[1;33m';;
esac
local NC='\033[0m' # No color code
echo -e "${COLOR}[$(date +'%Y-%m-%d %H:%M:%S')] $1${NC}"
}
if ! [ $(cat /etc/os-release 2>/dev/null | grep "Raspbian") ]; then
log "Your device is not running Raspbian :(" error
exit 1
fi
if ! [ $(iw list 2>/dev/null | grep "Supported interface modes" -A 8 | grep AP) ]; then
log "Your device does not support being used as an access point :(" error
exit 1
fi
# Check if the script is being run as root
if [ $(id -u) -ne 0 ]; then
echo "This script must be run as root. Use sudo."
exit 1
fi
if [ "$1" = "" ]; then
echo "Invalid arguments."
echo "Give SSID as 1st parameter"
exit 1
fi
if [ "$2" = "" ]; then
echo "Invalid arguments."
echo "Give password as 2nd parameter"
exit 1
fi
# Install required apt packages
installRequiredPackages() {
log "Installing required packages..."
# Allow non interactive installation of iptables-persistent
echo iptables-persistent iptables-persistent/autosave_v4 boolean true | sudo debconf-set-selections
echo iptables-persistent iptables-persistent/autosave_v6 boolean true | sudo debconf-set-selections
# Install required packages
apt install -y dnsmasq hostapd netfilter-persistent iptables-persistent
log "Installed!"
}
uninstallRequiredPackages() {
log "Uninstalling required packages..."
# Install required packages
apt purge -y dnsmasq hostapd netfilter-persistent iptables-persistent
log "Uninstalled!"
}
# hostapd configuration
configureHostapd() {
log "Configuring hostapd..."
test -f /etc/hostapd/hostapd.conf || (touch /etc/hostapd/hostapd.conf && log "Touched /etc/hostapd/hostapd.conf")
# tee /etc/hostapd/hostapd.conf > /etc/hostapd/hostapd.conf <<\EOF
echo "ctrl_interface=/var/run/hostapd" | tee /etc/hostapd/hostapd.conf > /dev/null
echo "driver=nl80211" | tee -a /etc/hostapd/hostapd.conf > /dev/null
echo "country_code=IT # Use your country code" | tee -a /etc/hostapd/hostapd.conf > /dev/null
echo "ssid=$1" | tee -a /etc/hostapd/hostapd.conf > /dev/null
echo "hw_mode=g" | tee -a /etc/hostapd/hostapd.conf > /dev/null
echo "channel=7" | tee -a /etc/hostapd/hostapd.conf > /dev/null
echo "auth_algs=1" | tee -a /etc/hostapd/hostapd.conf > /dev/null
echo "wpa=2" | tee -a /etc/hostapd/hostapd.conf > /dev/null
echo "wpa_passphrase=$2" | tee -a /etc/hostapd/hostapd.conf > /dev/null
echo "wpa_key_mgmt=WPA-PSK" | tee -a /etc/hostapd/hostapd.conf > /dev/null
echo "wpa_pairwise=TKIP" | tee -a /etc/hostapd/hostapd.conf > /dev/null
echo "rsn_pairwise=CCMP" | tee -a /etc/hostapd/hostapd.conf > /dev/null
echo "ignore_broadcast_ssid=1" | tee -a /etc/hostapd/hostapd.conf > /dev/null
# Change conf file permissions
chmod 600 /etc/hostapd/hostapd.conf
log "Configured hostapd!"
}
deconfigureHostapd() {
log "Deleting conf file /etc/hostapd/hostapd.conf..."
test -f /etc/hostapd/hostapd.conf && rm /etc/hostapd/hostapd.conf
log "Configured hostapd!"
}
# Creates the uap service required to host the access point
createUAPService() {
log "Creating uap service..."
test -f /etc/systemd/system/uap@.service || (touch /etc/systemd/system/uap@.service && log "Touched /etc/systemd/system/uap@.service file")
# tee /etc/systemd/system/uap@.service > /dev/null <<\EOF
echo "[Unit]" | tee /etc/systemd/system/uap@.service > /dev/null
echo "Description=IEEE 802.11 %p%i AP on wlan%i with hostapd" | tee -a /etc/systemd/system/uap@.service > /dev/null
echo "After=network.target" | tee -a /etc/systemd/system/uap@.service > /dev/null
echo $'\n' | tee -a /etc/systemd/system/uap@.service > /dev/null
echo "[Service]" | tee -a /etc/systemd/system/uap@.service > /dev/null
echo "Type=forking" | tee -a /etc/systemd/system/uap@.service > /dev/null
echo "PIDFile=/run/hostapd.pid" | tee -a /etc/systemd/system/uap@.service > /dev/null
echo "Restart=on-failure" | tee -a /etc/systemd/system/uap@.service > /dev/null
echo "RestartSec=2" | tee -a /etc/systemd/system/uap@.service > /dev/null
echo "Environment=DAEMON_CONF=/etc/hostapd/hostapd.conf" | tee -a /etc/systemd/system/uap@.service > /dev/null
echo "EnvironmentFile=-/etc/default/hostapd" | tee -a /etc/systemd/system/uap@.service > /dev/null
echo "ExecStartPre=/sbin/iw dev wlan%i interface add %p%i type __ap" | tee -a /etc/systemd/system/uap@.service > /dev/null
echo "ExecStart=/usr/sbin/hostapd -i %p%i -P /run/hostapd.pid -B \$DAEMON_OPTS \${DAEMON_CONF}" | tee -a /etc/systemd/system/uap@.service > /dev/null
echo "ExecStopPost=-/sbin/iw dev %p0 del" | tee -a /etc/systemd/system/uap@.service > /dev/null
echo $'\n' | tee -a /etc/systemd/system/uap@.service > /dev/null
echo "[Install]" | tee -a /etc/systemd/system/uap@.service > /dev/null
echo "WantedBy=multi-user.target" | tee -a /etc/systemd/system/uap@.service > /dev/null
log "Stopping hostapd..."
systemctl stop hostapd # if the default hostapd service was active before
log "Disabling hostapd..."
systemctl disable hostapd # if the default hostapd service was enabled before
log "Enabling uap@0.service..."
systemctl enable uap@0.service
log "Unblocking wlan..."
rfkill unblock wlan
log "Created!"
}
removeUAPService() {
log "Stopping uap@0.service..."
systemctl stop uap@0.service
log "Disabling uap@0.service..."
systemctl disable uap@0.service
log "Removing files..."
test -f /etc/systemd/system/uap@.service && rm /etc/systemd/system/uap@.service && log $'\t/etc/systemd/system/uap@.service'
test -f /usr/lib/systemd/system/uap@.service && rm /usr/lib/systemd/system/uap@.service && log $'\t/usr/lib/systemd/system/uap@.service'
log "Daemon-reloading..."
systemctl daemon-reload
}
setupDhcpcd() {
log "Setting up DHCPCD..."
# tee -a /etc/dhcpcd.conf > /dev/null <<\EOF
# these two lines are not strictly needed, as wlan0 uses the default configuration
echo "interface wlan0" | tee -a /etc/dhcpcd.conf > /dev/null
echo " dhcp" | tee -a /etc/dhcpcd.conf > /dev/null
echo $'\n' | tee -a /etc/dhcpcd.conf > /dev/null
# this defines static addressing to uap0 and disables wpa_supplicant for this interface
echo "interface uap0 " | tee -a /etc/dhcpcd.conf > /dev/null
echo " static ip_address=192.168.50.1/24" | tee -a /etc/dhcpcd.conf > /dev/null
echo " ipv4only" | tee -a /etc/dhcpcd.conf > /dev/null
echo " nohook wpa_supplicant" | tee -a /etc/dhcpcd.conf > /dev/null
log "Set up DHCPCD successful!"
}
removeDhcpcd() {
log "Removing conf lines from /etc/dhcpcd.conf..."
test -f /etc/dhcpcd.conf && sed -i '/interface wlan0/,+2d; /interface uap0/,+4d' /etc/dhcpcd.conf
log "Removed DHCPCD!"
}
setupRouting() {
log "Setting up routing..."
test -f /etc/sysctl.d/routed-ap.conf || (touch /etc/sysctl.d/routed-ap.conf && log "Touched /etc/sysctl.d/routed-ap.conf")
# tee /etc/sysctl.d/routed-ap.conf > /dev/null <<\EOF
echo "# https://www.raspberrypi.org/documentation/configuration/wireless/access-point-routed.md" | tee /etc/sysctl.d/routed-ap.conf > /dev/null
echo "# Enable IPv4 routing" | tee -a /etc/sysctl.d/routed-ap.conf > /dev/null
echo "net.ipv4.ip_forward=1" | tee -a /etc/sysctl.d/routed-ap.conf > /dev/null
log "Updating firewall rules..."
sudo iptables -t nat -A POSTROUTING -o eth0 -j MASQUERADE
sudo iptables -t nat -A POSTROUTING -o wlan0 -j MASQUERADE
sudo iptables -A FORWARD -i wlan0 -o uap0 -m state --state RELATED,ESTABLISHED -j ACCEPT
sudo iptables -A FORWARD -i uap0 -o wlan0 -j ACCEPT
sudo netfilter-persistent save
log "Updated and persisted!"
log "Appending to dnsmasq configuration..."
# tee -a /etc/dnsmasq.conf >/dev/null <<\EOF
echo "# disables dnsmasq reading any other files like /etc/resolv.conf for nameservers" | tee -a /etc/dnsmasq.conf > /dev/null
echo "no-resolv" | tee -a /etc/dnsmasq.conf > /dev/null
echo $'\n' | tee -a /etc/dnsmasq.conf > /dev/null
echo "interface=uap0" | tee -a /etc/dnsmasq.conf > /dev/null
echo "no-dhcp-interface=lo,wlan0" | tee -a /etc/dnsmasq.conf > /dev/null
echo "domain-needed" | tee -a /etc/dnsmasq.conf > /dev/null
echo "bogus-priv" | tee -a /etc/dnsmasq.conf > /dev/null
echo "server=8.8.8.8" | tee -a /etc/dnsmasq.conf > /dev/null
echo "dhcp-range=192.168.50.50,192.168.50.199,12h" | tee -a /etc/dnsmasq.conf > /dev/null
echo "dhcp-option=3,192.168.50.1" | tee -a /etc/dnsmasq.conf > /dev/null
log "Set up routing successful!"
}
removeRouting() {
log "Deleting /etc/sysctl.d/routed-ap.conf..."
test -f /etc/sysctl.d/routed-ap.conf || rm /etc/sysctl.d/routed-ap.conf
log "Deleting forwarding rules..."
sudo iptables -D FORWARD -i wlan0 -o uap0 -m state --state RELATED,ESTABLISHED -j ACCEPT || log "Rule 1 non-existent"
sudo iptables -D FORWARD -i uap0 -o wlan0 -j ACCEPT || log "Rule 2 non-existent"
sudo iptables -t nat -D POSTROUTING -o wlan0 -j MASQUERADE || log "Rule 3 non-existent"
sudo iptables -t nat -D POSTROUTING -o eth0 -j MASQUERADE || log "Rule 4 non-existent"
log "Removing lines added on /etc/dnsmasq.conf..."
sed -i '/no-resolv\|interface=uap0\|no-dhcp-interface=lo,wlan0\|domain-needed\|bogus-priv\|server=8.8.8.8\|dhcp-range=192.168.50.50,192.168.50.199,12h\|dhcp-option=3,192.168.50.1/d' /etc/dnsmasq.conf
log "Removed routing!"
}
set -e # Exit if an error occurs
while getopts u flag
do
case "${flag}" in
u) uninstall=1;;
esac
done
if [ -z $uninstall ]; then
installRequiredPackages
configureHostapd
createUAPService
setupDhcpcd
setupRouting
else
removeRouting
removeDhcpcd
removeUAPService
deconfigureHostapd
uninstallRequiredPackages
fi
log "WARNING:: YOU HAVE TO REBOOT TO SEE THESE ACTIONS TAKE EFFECT" warning
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment