├── README.md ├── boot └── hotspot.txt.example ├── etc ├── default │ └── hostapd ├── dnsmasq.d │ └── rpi-access-point.conf ├── hostapd │ └── hostapd.conf ├── network │ └── interfaces └── systemd │ └── system │ └── rpi-access-point.service ├── install.sh └── usr └── bin └── rpi-access-point /README.md: -------------------------------------------------------------------------------- 1 | # rpi3-hotspot 2 | 3 | Turns a Raspberry Pi 3 into a configurable access point. 4 | 5 | ## How this works 6 | 7 | An access point is created if `/boot/hotspot.txt` file is present. If there is no such file, no access point will be set up and the `/etc/wpa_supplicant/wpa_supplicant.conf` will be used. 8 | 9 | Defaults are `ssid=Rpi Access Point (%hostname%)` and `passphrase=rpi_ap_pass` but can be changed by tweaking the `/boot/hotspot.txt` file. One or both parameters can be modified. 10 | See `boot/hotspot.txt.example` for a documented example. 11 | 12 | The Raspberry Pi IP address will be `10.99.99.1`. 13 | 14 | ``` 15 | # /boot/hotspot.txt 16 | ssid=Rodrigo The Robot 17 | passphrase=your_secret_passphrase 18 | ``` 19 | 20 | ## Installation 21 | 22 | 1. Clone this repo or download the archive. 23 | 2. `cd` into the directory 24 | 3. Uninstall previously installed version 25 | 4. `sudo ./install.sh` 26 | 5. Profit. 27 | 28 | ## Uninstalling previous version 29 | 30 | ```bash 31 | sudo systemctl stop rpi-access-point 32 | sudo systemctl disable rpi-access-point 33 | sudo rm /etc/systemd/system/rpi-access-point.service /usr/bin/rpi-access-point 34 | sudo systemctl daemon-reload 35 | ``` 36 | -------------------------------------------------------------------------------- /boot/hotspot.txt.example: -------------------------------------------------------------------------------- 1 | # This file is an example of what /boot/hotspot.txt can be. 2 | # 3 | # If an option is not provided in the file, its default value will 4 | # be used. 5 | 6 | # `ssid` is the network name that will be detected. 7 | # Its length should be between 1 and 32 characters. 8 | # 9 | # Default value is ssid=Rpi Access Point 10 | ssid=ExampleAccessPoint 11 | 12 | # `passphrase` is the password required to connect to the network. 13 | # Its length should be between 8 and 63 characters (WPA-PSK). 14 | # 15 | # Default value is passphrase=rpi_ap_pass 16 | passphrase=example_secret_passphrase 17 | 18 | # hostname will be appendded to the SSID by default. The `hide_hostname` option 19 | # is used to prevent this behavior. This is convenient to differenciate hosts 20 | # configured with the same SSID. 21 | # 22 | # Default value is not specified, hostname will be appendded. 23 | # To disable this behavior, `hide_hostname=1`. Any other value will be ignored. 24 | hide_hostname=1 25 | -------------------------------------------------------------------------------- /etc/default/hostapd: -------------------------------------------------------------------------------- 1 | DAEMON_CONF="/etc/hostapd/hostapd.conf" 2 | -------------------------------------------------------------------------------- /etc/dnsmasq.d/rpi-access-point.conf: -------------------------------------------------------------------------------- 1 | bogus-priv 2 | filterwin2k 3 | domain-needed 4 | bind-interfaces 5 | expand-hosts 6 | no-resolv 7 | no-poll 8 | 9 | interface=wlan0 10 | listen-address=127.0.0.1 11 | listen-address=10.99.99.1 12 | 13 | server=8.8.8.8 14 | server=8.8.4.4 15 | server=208.67.222.222 16 | server=208.67.220.220 17 | 18 | dhcp-option=19,1 19 | domain=local 20 | local=/local/ 21 | server=/local/10.99.99.1 22 | 23 | dhcp-range=10.99.99.2,10.99.99.51,255.255.255.0,12h 24 | dhcp-option=6,10.99.99.1 25 | dhcp-option=3,10.99.99.1 26 | -------------------------------------------------------------------------------- /etc/hostapd/hostapd.conf: -------------------------------------------------------------------------------- 1 | interface=wlan0 2 | ssid=RpiAccessPoint 3 | hw_mode=g 4 | channel=6 5 | ieee80211n=1 6 | wmm_enabled=1 7 | macaddr_acl=0 8 | auth_algs=1 9 | wpa=2 10 | wpa_passphrase=rpi_ap_pass 11 | wpa_key_mgmt=WPA-PSK 12 | wpa_pairwise=TKIP 13 | rsn_pairwise=CCMP 14 | ctrl_interface=/var/run/hostapd 15 | ctrl_interface_group=0 16 | -------------------------------------------------------------------------------- /etc/network/interfaces: -------------------------------------------------------------------------------- 1 | # interfaces(5) file used by ifup(8) and ifdown(8) 2 | 3 | # Please note that this file is written to be used with dhcpcd 4 | # For static IP, consult /etc/dhcpcd.conf and 'man dhcpcd.conf' 5 | 6 | # Include files from /etc/network/interfaces.d: 7 | source-directory /etc/network/interfaces.d 8 | 9 | auto lo 10 | iface lo inet loopback 11 | 12 | iface eth0 inet manual 13 | 14 | allow-hotplug wlan0 15 | iface wlan0 inet manual 16 | -------------------------------------------------------------------------------- /etc/systemd/system/rpi-access-point.service: -------------------------------------------------------------------------------- 1 | [Unit] 2 | Description=Generates a wireless access point 3 | After=network-online.target 4 | 5 | [Service] 6 | Type=oneshot 7 | RemainAfterExit=yes 8 | ExecStart=/usr/bin/rpi-access-point 9 | 10 | [Install] 11 | WantedBy=multi-user.target 12 | -------------------------------------------------------------------------------- /install.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # 3 | 4 | set -e 5 | 6 | apt-get update 7 | apt-get install --yes network-manager hostapd dnsmasq 8 | systemctl disable hostapd 9 | systemctl disable dnsmasq 10 | 11 | if [ -f /etc/network/interfaces ]; then 12 | mv /etc/network/interfaces /etc/network/interfaces.old 13 | fi 14 | cp etc/network/interfaces /etc/network/interfaces 15 | 16 | if [ -f /etc/default/hostapd ]; then 17 | mv /etc/default/hostapd /etc/default/hostapd.old 18 | fi 19 | cp etc/default/hostapd /etc/default/hostapd 20 | 21 | if [ -f /etc/hostapd/hostapd.conf ]; then 22 | mv /etc/hostapd/hostapd.conf /etc/hostapd/hostapd.conf.old 23 | fi 24 | cp etc/hostapd/hostapd.conf /etc/hostapd/hostapd.conf 25 | 26 | cp etc/dnsmasq.d/rpi-access-point.conf /etc/dnsmasq.d/rpi-access-point.conf 27 | 28 | cp etc/systemd/system/rpi-access-point.service /etc/systemd/system/rpi-access-point.service 29 | cp usr/bin/rpi-access-point /usr/bin/rpi-access-point 30 | 31 | systemctl enable rpi-access-point.service 32 | -------------------------------------------------------------------------------- /usr/bin/rpi-access-point: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # 3 | 4 | set -e 5 | 6 | log() { 7 | echo "$1" 8 | } 9 | 10 | config_path="/boot/hotspot.txt" 11 | 12 | if [ -f $config_path ]; then 13 | 14 | log "Config file found at $config_path, activating access point" 15 | 16 | hotspot_ssid=$(sed -n -e 's/^ssid=\(.\+\)$/\1/p' /boot/hotspot.txt) 17 | 18 | # 802.11i specs: 19 | # The length of the SSID information field is between 0 and 32 octets. 20 | # A 0 length information field is used within Probe Request management frames 21 | # to indicate the wildcard SSID. 22 | if [ ${#hotspot_ssid} -lt 1 ] || [ ${#hotspot_ssid} -gt 32 ]; then 23 | log "Using default access point SSID" 24 | hotspot_ssid="Rpi Access Point" 25 | fi 26 | 27 | hide_hostname=$(sed -n -e 's/^hide_hostname=\(.\+\)$/\1/p' /boot/hotspot.txt) 28 | 29 | if [ "$hide_hostname" != "1" ]; then 30 | # append the hostname to avoid ssid collision 31 | hotspot_ssid="$hotspot_ssid ($(hostname))" 32 | fi 33 | 34 | log "SSID will be '$hotspot_ssid'" 35 | 36 | hotspot_passphrase=$(sed -n -e 's/^passphrase=\(.\+\)$/\1/p' /boot/hotspot.txt) 37 | 38 | # 802.11i specs: 39 | # A pass-phrase is a sequence of between 8 and 63 ASCII-encoded characters. 40 | # The limit of 63 comes from the desire to distinguish between a pass-phrase 41 | # and a PSK displayed as 64 hexadecimal characters. 42 | if [ ${#hotspot_passphrase} -lt 8 ] || [ ${#hotspot_passphrase} -gt 63 ]; then 43 | log "Using default passphrase" 44 | hotspot_passphrase="rpi_ap_pass" 45 | fi 46 | 47 | log "Updating hostapd configuration" 48 | 49 | sed -i "s/^ssid=.*/ssid=$hotspot_ssid/g" /etc/hostapd/hostapd.conf 50 | sed -i "s/^wpa_passphrase=.*/wpa_passphrase=$hotspot_passphrase/g" /etc/hostapd/hostapd.conf 51 | 52 | if ! grep "^denyinterfaces wlan0$" /etc/dhcpcd.conf; then 53 | log "dhcpcd will ignore wlan0" 54 | echo "denyinterfaces wlan0" | tee -a /etc/dhcpcd.conf 55 | systemctl restart dhcpcd 56 | fi 57 | 58 | if pgrep wpa_supplicant; then 59 | log "Stopping wpa_supplicant" 60 | wpa_pid=$(pgrep wpa_supplicant) 61 | kill "$wpa_pid" 62 | fi 63 | 64 | if [ "$(sysctl -n net.ipv4.ip_forward 2>/dev/null)" = "0" ]; then 65 | log "Update ip forwarding" 66 | sysctl -q -w net.ipv4.ip_forward=1 67 | sysctl -p 68 | fi 69 | 70 | log "Updating iptables" 71 | 72 | if ! iptables -t nat -C POSTROUTING -o eth0 -j MASQUERADE > /dev/null 2>&1; then 73 | iptables -t nat -A POSTROUTING -o eth0 -j MASQUERADE 74 | fi 75 | 76 | if ! iptables -C FORWARD -i eth0 -o wlan0 -m state --state RELATED,ESTABLISHED -j ACCEPT > /dev/null 2>&1; then 77 | iptables -A FORWARD -i eth0 -o wlan0 -m state --state RELATED,ESTABLISHED -j ACCEPT 78 | fi 79 | 80 | if ! iptables -C FORWARD -i wlan0 -o eth0 -j ACCEPT > /dev/null 2>&1; then 81 | iptables -A FORWARD -i wlan0 -o eth0 -j ACCEPT 82 | fi 83 | 84 | log "Updating interfaces" 85 | 86 | ifdown wlan0 &>/dev/null 87 | ifconfig wlan0 10.99.99.1 88 | ifup wlan0 89 | 90 | log "Restarting services" 91 | 92 | systemctl daemon-reload 93 | systemctl restart networking 94 | systemctl restart dnsmasq 95 | systemctl stop hostapd 96 | 97 | # hostapd won't use new config if it has been changed. 98 | # `sleep` seems to make it work 99 | sleep 5 100 | systemctl start hostapd 101 | 102 | log "Access point UP" 103 | else 104 | log "Deactivating access point" 105 | 106 | if grep "^denyinterfaces wlan0$" /etc/dhcpcd.conf; then 107 | sed -i "/denyinterfaces wlan0/d" /etc/dhcpcd.conf 108 | systemctl restart dhcpcd 109 | fi 110 | 111 | if iptables -t nat -C POSTROUTING -o eth0 -j MASQUERADE > /dev/null 2>&1; then 112 | iptables -t nat -D POSTROUTING -o eth0 -j MASQUERADE 113 | fi 114 | 115 | if iptables -C FORWARD -i eth0 -o wlan0 -m state --state RELATED,ESTABLISHED -j ACCEPT > /dev/null 2>&1; then 116 | iptables -D FORWARD -i eth0 -o wlan0 -m state --state RELATED,ESTABLISHED -j ACCEPT 117 | fi 118 | 119 | if iptables -C FORWARD -i wlan0 -o eth0 -j ACCEPT > /dev/null 2>&1; then 120 | iptables -D FORWARD -i wlan0 -o eth0 -j ACCEPT 121 | fi 122 | 123 | if [ "$(sysctl -n net.ipv4.ip_forward 2>/dev/null)" = "1" ]; then 124 | sysctl -q -w net.ipv4.ip_forward=0 125 | sysctl -p 126 | fi 127 | 128 | systemctl stop dnsmasq 129 | systemctl stop hostapd 130 | 131 | ifdown wlan0 &>/dev/null 132 | ifconfig wlan0 0.0.0.0 133 | ifup wlan0 134 | 135 | systemctl restart networking 136 | 137 | wpa_pid=$(pgrep wpa_supplicant) 138 | if [ -n "$wpa_pid" ]; then 139 | log "Stopping wpa_supplicant" 140 | kill "$wpa_pid" 141 | fi 142 | 143 | log "Starting wpa_supplicant with config: /etc/wpa_supplicant/wpa_supplicant.conf" 144 | wpa_supplicant -B -i wlan0 -c /etc/wpa_supplicant/wpa_supplicant.conf > /dev/null 145 | 146 | log "Access point DOWN" 147 | fi 148 | 149 | exit 0 150 | --------------------------------------------------------------------------------