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
This commit is contained in:
oblique 2014-09-05 01:53:42 +03:00
parent 14ec50f379
commit 81d861cb46
2 changed files with 110 additions and 57 deletions

View File

@ -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

164
create_ap
View File

@ -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
if [[ -n $OLD_BRIDGE_IPTABLES ]]; then
echo $OLD_BRIDGE_IPTABLES > /proc/sys/net/bridge/bridge-nf-call-iptables
fi
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 ! 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
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
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/')
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
if [[ -n "$BRDADDR" ]]; then
ip addr add $IPADDR broadcast $BRDADDR dev $BRIDGE_IFACE || die
else
ip addr add $IPADDR dev $BRIDGE_IFACE || die
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
# 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
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
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
# remove any existing entries that were added from 'ip addr add'
ip route flush dev $INTERNET_IFACE
ip route flush dev $BRIDGE_IFACE
# 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"