create_ap

create a nat-ed wifi ap
git clone git://git.2f30.org/create_ap.git
Log | Files | Refs | LICENSE

commit 81d861cb46e9eef96ec161e8ceb252beaadea3ec
parent 14ec50f379a418383e2aa0203e01ef45b5cbd789
Author: oblique <psyberbits@gmail.com>
Date:   Fri Sep  5 01:53:42 +0300

Reimplementation of 6a3e1d98 commit

With the 6a3e1d98 commit NetworkManager was throwing an assertion so
we take a different approach when we create the bridge interface.
Also if the <interface-with-internet> is already a bridge interface
we skip creation.

The new approach is:

   1) Save the IPs and route table of INTERNET_IFACE
   2) If NetworkManager is running set INTERNET_IFACE as unmanaged
   3) Create BRIDGE_IFACE and add INTERNET_IFACE to it
   4) Set the previously saved IPs and route table to BRIDGE_IFACE

Better fix #19

Diffstat:
README.md | 3+++
create_ap | 166+++++++++++++++++++++++++++++++++++++++++++++++++++----------------------------
2 files changed, 111 insertions(+), 58 deletions(-)
diff --git a/README.md b/README.md @@ -54,6 +54,9 @@ ### Bridged Internet sharing: create_ap -m bridge wlan0 eth0 MyAccessPoint MyPassPhrase +### Bridged Internet sharing (pre-configured bridge interface): + create_ap -m bridge wlan0 br0 MyAccessPoint MyPassPhrase + ### Internet sharing from the same WiFi interface: create_ap wlan0 wlan0 MyAccessPoint MyPassPhrase diff --git a/create_ap b/create_ap @@ -43,6 +43,8 @@ usage() { echo " * If you're not using the --no-virt option, then you can create an AP with the same" echo " interface you are getting your Internet connection." echo " * You can pass your SSID and password through pipe or through arguments (see examples)." + echo " * On bridge method if the <interface-with-internet> is not a bridge interface, then" + echo " a bridge interface is created automatically." echo echo "Examples:" echo " $(basename $0) wlan0 eth0 MyAccessPoint MyPassPhrase" @@ -52,6 +54,7 @@ usage() { echo " $(basename $0) wlan0 wlan0 MyAccessPoint MyPassPhrase" echo " $(basename $0) -n wlan0 MyAccessPoint MyPassPhrase" echo " $(basename $0) -m bridge wlan0 eth0 MyAccessPoint MyPassPhrase" + echo " $(basename $0) -m bridge wlan0 br0 MyAccessPoint MyPassPhrase" echo " $(basename $0) --driver rtl871xdrv wlan0 eth0 MyAccessPoint MyPassPhrase" } @@ -88,6 +91,10 @@ is_wifi_interface() { return 1 } +is_bridge_interface() { + brctl show | cut -f1 | grep -E "^$1\$" > /dev/null 2>&1 +} + get_phy_device() { for x in /sys/class/ieee80211/*; do [[ ! -d "$x" ]] && continue @@ -160,9 +167,8 @@ get_macaddr() { get_avail_bridge() { for i in {0..100}; do - curr_bridge=$(brctl show | grep "br$i" | cut -s -f1) - if [[ -z $curr_bridge ]]; then - echo "br$i" + if ! is_bridge_interface "br${i}"; then + echo "br${i}" return fi done @@ -177,7 +183,6 @@ get_new_macaddr() { echo $NEWMAC } -ADDED_UNMANAGED=0 NETWORKMANAGER_CONF=/etc/NetworkManager/NetworkManager.conf NM_OLDER_VERSION=1 @@ -323,6 +328,8 @@ BRIDGE_IFACE= OLD_IP_FORWARD= OLD_BRIDGE_IPTABLES= OLD_MACADDR= +IP_ADDRS= +ROUTE_ADDRS= cleanup() { trap "" SIGINT @@ -345,19 +352,39 @@ cleanup() { iptables -D FORWARD -i ${INTERNET_IFACE} -d ${GATEWAY%.*}.0/24 -j ACCEPT > /dev/null 2>&1 [[ -n $OLD_IP_FORWARD ]] && echo $OLD_IP_FORWARD > /proc/sys/net/ipv4/ip_forward elif [[ "$SHARE_METHOD" == "bridge" ]]; then - ip route show dev $BRIDGE_IFACE | grep -v -E '^default' | while read x; do - ip route del $x dev $BRIDGE_IFACE - ip route add $x dev $INTERNET_IFACE - done - - ip route show dev $BRIDGE_IFACE | grep -E '^default' | while read x; do - ip route del $x dev $BRIDGE_IFACE - ip route add $x dev $INTERNET_IFACE - done + if [[ -n $OLD_BRIDGE_IPTABLES ]]; then + echo $OLD_BRIDGE_IPTABLES > /proc/sys/net/bridge/bridge-nf-call-iptables + fi - ip link set down $BRIDGE_IFACE - brctl delbr $BRIDGE_IFACE - [[ -n $OLD_BRIDGE_IPTABLES ]] && echo $OLD_BRIDGE_IPTABLES > /proc/sys/net/bridge/bridge-nf-call-iptables + if ! is_bridge_interface $INTERNET_IFACE; then + ip link set down $BRIDGE_IFACE + brctl delbr $BRIDGE_IFACE + ip addr flush $INTERNET_IFACE + ip link set dev $INTERNET_IFACE up + + for x in "${IP_ADDRS[@]}"; do + x="${x/inet/}" + x="${x/secondary/}" + x="${x/dynamic/}" + x=$(echo $x | sed 's/\([0-9]\)sec/\1/g') + x="${x/${INTERNET_IFACE}/}" + ip addr add $x dev $INTERNET_IFACE + done + + ip route flush dev $INTERNET_IFACE + + for x in "${ROUTE_ADDRS[@]}"; do + [[ "$x" == default* ]] && continue + ip route add $x dev $INTERNET_IFACE + done + + for x in "${ROUTE_ADDRS[@]}"; do + [[ "$x" != default* ]] && continue + ip route add $x dev $INTERNET_IFACE + done + + networkmanager_rm_unmanaged_if_needed $INTERNET_IFACE + fi fi fi @@ -501,17 +528,6 @@ if [[ "$SHARE_METHOD" != "nat" && "$SHARE_METHOD" != "bridge" && "$SHARE_METHOD" exit 1 fi -if [[ "$SHARE_METHOD" == "bridge" ]]; then - OLD_BRIDGE_IPTABLES=$(cat /proc/sys/net/bridge/bridge-nf-call-iptables) - BRIDGE_IFACE=$(get_avail_bridge) - if [[ -z $BRIDGE_IFACE ]]; then - echo "ERROR: No availabe bridges < br100" >&2 - exit 1 - fi -elif [[ "$SHARE_METHOD" == "nat" ]]; then - OLD_IP_FORWARD=$(cat /proc/sys/net/ipv4/ip_forward) -fi - if [[ "$SHARE_METHOD" != "none" ]]; then MIN_REQUIRED_ARGS=2 else @@ -562,6 +578,23 @@ else fi fi +if [[ "$SHARE_METHOD" == "bridge" ]]; then + OLD_BRIDGE_IPTABLES=$(cat /proc/sys/net/bridge/bridge-nf-call-iptables) + + if is_bridge_interface $INTERNET_IFACE; then + BRIDGE_IFACE=$INTERNET_IFACE + else + BRIDGE_IFACE=$(get_avail_bridge) + fi + + if [[ -z $BRIDGE_IFACE ]]; then + echo "ERROR: No availabe bridges < br100" >&2 + exit 1 + fi +elif [[ "$SHARE_METHOD" == "nat" ]]; then + OLD_IP_FORWARD=$(cat /proc/sys/net/ipv4/ip_forward) +fi + if [[ $NO_VIRT -eq 1 && "$WIFI_IFACE" == "$INTERNET_IFACE" ]]; then echo -n "ERROR: You can not share your connection from the same" >&2 echo " interface if you are using --no-virt option." >&2 @@ -693,48 +726,65 @@ if [[ "$SHARE_METHOD" != "none" ]]; then elif [[ "$SHARE_METHOD" == "bridge" ]]; then # disable iptables rules for bridged interfaces echo 0 > /proc/sys/net/bridge/bridge-nf-call-iptables || die - # create and initialize bridged interface - brctl addbr ${BRIDGE_IFACE} || die - brctl addif ${BRIDGE_IFACE} ${INTERNET_IFACE} || die # to initialize the bridge interface correctly we need to do the following: # - # 1) duplicate the IPs of INTERNET_IFACE to BRIDGE_IFACE - # 2) duplicate routing table of INTERNET_IFACE to BRIDGE_IFACE - # 3) delete routing table of INTERNET_IFACE - # NOTE: we don't need to delete the IPs of INTERNET_IFACE + # 1) save the IPs and route table of INTERNET_IFACE + # 2) if NetworkManager is running set INTERNET_IFACE as unmanaged + # 3) create BRIDGE_IFACE and add INTERNET_IFACE to it + # 4) set the previously saved IPs and route table to BRIDGE_IFACE # # we need the above because BRIDGE_IFACE is the master interface from now on # and it must know where is connected, otherwise connection is lost. - ip link set dev ${BRIDGE_IFACE} up || die + if ! is_bridge_interface $INTERNET_IFACE; then + echo -n "Create a bridge interface... " + OLD_IFS="$IFS" + IFS=$'\n' - ip addr show $INTERNET_IFACE | grep -E '[[:blank:]]+inet ' | while read x; do - IPADDR=$(echo $x | sed 's/inet \([^ ]*\).*/\1/') - BRDADDR= - if [[ $x == *\ brd\ * ]]; then - BRDADDR=$(echo $x | sed 's/.* brd \([^ ]*\).*/\1/') - fi - if [[ -n "$BRDADDR" ]]; then - ip addr add $IPADDR broadcast $BRDADDR dev $BRIDGE_IFACE || die - else - ip addr add $IPADDR dev $BRIDGE_IFACE || die + IP_ADDRS=( $(ip addr show $INTERNET_IFACE | grep -A 1 -E 'inet[[:blank:]]' | paste - -) ) + ROUTE_ADDRS=( $(ip route show dev $INTERNET_IFACE) ) + + IFS="$OLD_IFS" + + if networkmanager_is_running; then + networkmanager_add_unmanaged $INTERNET_IFACE + networkmanager_wait_until_unmanaged $INTERNET_IFACE fi - done - # remove any existing entries that were added from 'ip addr add' - ip route flush dev $BRIDGE_IFACE || die + brctl addbr $BRIDGE_IFACE || die + brctl setfd $BRIDGE_IFACE 0 + brctl addif $BRIDGE_IFACE $INTERNET_IFACE || die + ip link set dev $BRIDGE_IFACE up || die + ip link set dev $INTERNET_IFACE up || die + + ip addr flush $INTERNET_IFACE + for x in "${IP_ADDRS[@]}"; do + x="${x/inet/}" + x="${x/secondary/}" + x="${x/dynamic/}" + x=$(echo $x | sed 's/\([0-9]\)sec/\1/g') + x="${x/${INTERNET_IFACE}/}" + ip addr add $x dev $BRIDGE_IFACE || die + done - # we must first add the entries that specify the subnets and then the - # gateway entry, otherwise 'ip addr add' will return an error - ip route show dev $INTERNET_IFACE | grep -v -E '^default' | while read x; do - ip route del $x dev $INTERNET_IFACE || die - ip route add $x dev $BRIDGE_IFACE || die - done + # remove any existing entries that were added from 'ip addr add' + ip route flush dev $INTERNET_IFACE + ip route flush dev $BRIDGE_IFACE - ip route show dev $INTERNET_IFACE | grep -E '^default' | while read x; do - ip route del $x dev $INTERNET_IFACE || die - ip route add $x dev $BRIDGE_IFACE || die - done + # we must first add the entries that specify the subnets and then the + # gateway entry, otherwise 'ip addr add' will return an error + for x in "${ROUTE_ADDRS[@]}"; do + [[ "$x" == default* ]] && continue + ip route add $x dev $BRIDGE_IFACE || die + done + + for x in "${ROUTE_ADDRS[@]}"; do + [[ "$x" != default* ]] && continue + ip route add $x dev $BRIDGE_IFACE || die + done + + echo "$BRIDGE_IFACE created." + fi fi else echo "No Internet sharing"