I have a raspberry pi with three interfaces connected, eth0
, wlan0
and ppp0
, what i'm looking to achieve is having routes to the internet through all interfaces, but so far only eth0
and ppp0
gets a route.
here's outputs of route -n
and ip route show
(don't have a working ppp0 interface now but i know that one works)
Kernel IP routing table
Destination Gateway Genmask Flags Metric Ref Use Iface
0.0.0.0 192.168.1.1 0.0.0.0 UG 0 0 0 eth0
192.168.1.0 0.0.0.0 255.255.255.0 U 0 0 0 eth0
192.168.1.0 0.0.0.0 255.255.255.0 U 0 0 0 wlan0
default via 192.168.1.1 dev eth0
192.168.1.0/24 dev eth0 proto kernel scope link src 192.168.1.39
192.168.1.0/24 dev wlan0 proto kernel scope link src 192.168.1.243
I wrote a script that is triggered from /etc/dhcp/dhclient-exit-hooks.d/
so once the interface gets an offer from dhcp.
#!/bin/bash
calculateCIDR() {
nbits=0
IFS=.
for dec in $1 ; do
case $dec in
255) let nbits+=8;;
254) let nbits+=7;;
252) let nbits+=6;;
248) let nbits+=5;;
240) let nbits+=4;;
224) let nbits+=3;;
192) let nbits+=2;;
128) let nbits+=1;;
0);;
*)
echo "Error calulating CIDR exiting.";
exit 1
;;
esac
done
echo $nbits
}
calculateSubnet() {
IFS=. read -r i1 i2 i3 i4 <<< $1
IFS=. read -r m1 m2 m3 m4 <<< $2
echo "$((i1 & m1)).$((i2 & m2)).$((i3 & m3)).$((i4 & m4))"
}
# check if all parameters are there
# expected parameters
# $1 = iface
# $2 = ip
# $3 = mask
# $4 = gateway
if [ $# -ne 4 ]
then
echo "Illegal number of arguments"
exit 2
fi
# assign variables
IFACE=$1
IP=$2
MASK=$3
GATEWAY=$4
# extract inface number and calculate table number
case $IFACE in
eth*)
TABLEID=$(( 10 + `echo $IFACE | grep -o -E '[0-9]+'`))
METRIC=0
;;
wlan*)
TABLEID=$(( 30 + `echo $IFACE | grep -o -E '[0-9]+'`))
METRIC=$(( 50 + `echo $IFACE | grep -o -E '[0-9]+'`))
;;
ppp*)
TABLEID=$(( 90 + `echo $IFACE | grep -o -E '[0-9]+'`))
METRIC=$(( 100 + `echo $IFACE | grep -o -E '[0-9]+'`))
;;
*)
echo "Bad interface exiting"
exit 1
;;
esac
# create new table for interface only if not existing there already
grep -q -F "$TABLEID $IFACE" /etc/iproute2/rt_tables || echo "$TABLEID $IFACE" >> /etc/iproute2/rt_tables
# remove previous rules
while ip rule delete table $IFACE 2>/dev/null; do true; done
# flush previous table
ip route flush table $IFACE
# calculate CIDR from
CIDR=$(calculateCIDR $MASK)
# calculate subnet address
SUBNET=$(calculateSubnet $IP $MASK)
# create route for local network
ip route add $SUBNET/$CIDR dev $IFACE src $IP metric $METRIC table $IFACE
# create route for internet
ip route add default via $GATEWAY dev $IFACE metric $METRIC table $IFACE
# set rules for the interface
ip rule add from $IP/32 table $IFACE
ip rule add to $IP/32 table $IFACE
# done
exit 0
this same script is used for all interfaces provided with network setup, wlan0 never gets a route to internet meaning i can't use it to ping anything outside the local network. anyone knows why ? i'm running out of ideas.
iptables
'statistic --mode nth
+MARK
along withip rule
'sfwmark
does work). Anyway the solution proposed does indeed use this kind of setting: using additional routing tables