7

I've looked around but found nothing on this subject.

I have an Android phone with a public IP given by sprint. Tethering on Android uses NAT, so if I want to access any of the devices behind the phone I have to use port forwarding (Which I'd really rather not do). Is it possible to set tethering to bridged (Disable NAT), so the device behind the phone will be given the public IP?

3
  • What sort of devices do you want to access and what would you be using to access devices behind the Android phone?
    – Tim Kist
    Commented May 5, 2018 at 9:21
  • 1
    Your question already contains the answer: with a public IP given by sprint. You get exactly one IP address not multiple. A mobile network is AFAIK not like a LAN where you can simply get as many IP addresses via DHCP as you need. Only with IPv6, bridging may be possible if you get a subnet instead of one address.
    – Robert
    Commented May 5, 2018 at 18:45
  • I am trying to give a mikrotik router my phone's static IP so I can log directly into it remotely. The FWD app works, but it has it's limitations. As for the issue with a mobile network handing out multiple IP addresses, I only want to connect one device behind the phone, and I want the phones public IP to be given to it. So no additional IP addresses needed.
    – Zock77
    Commented May 7, 2018 at 14:57

2 Answers 2

6

Let's say rmnet_data1 is your Mobile Data interface (on Qualcomm devices) and wlan0 is WiFi interface. When you switch on Mobile Data, your ISP assigns rmnet_data1 an IP address, possibly dynamic and not necessarily a public IP (see details in this answer), but let's assume it is a static public IP - say 1.2.3.10. When you switch on tethering, wlan0 is turned into AP mode and a static IP is assigned (used to be 192.168.43.1 but is randomized since Pie). A DHCP/DNS server (dnsmasq) is listening on this interface to assign dynamic IP addresses to any hosts which join the local network.

Now phone is essentially a router connecting two networks (different subnets) at gateways (rmnet_data1 for external/public network i.e. WAN and wlan0 for local/private network i.e. WLAN). Since only one IP is assigned by the ISP to your phone, phone is doing NAT (at OSI layer 3) to make internet accessible for all local clients. As in your case the only connected host (router) is assigned address, let's say, 192.168.43.10. You'll have to do specific Port Forwarding or DMZ to access the router from internet.

BRIDGING ON LINUX / ANDROID:

What you want to do is assign address 1.2.3.10 to the router using Ethernet bridge as you stated in comment:

I only want to connect one device behind the phone, and I want the phones public IP to be given to it.

If you want to retain current network configuration on device, Ethernet bridging - which is an alternative to NAT for internet sharing - doesn't seem to be an option at all, unless you get a whole subnet (e.g. /30) from ISP instead of a single IP address. See Appendix A for reasons.

BRIDGING ON MODEM / ROUTER:

That said, what you are looking for is called Half Bridge Mode; a feature provided in many modem/router combo devices to avoid the problem of double NAT. It's also called IP Pass-through, IP Extension, DHCP Spoofing or True DMZ by different manufacturers. Other operation modes on ISP provided combo devices are NAT and Full Bridge.

We can use some workaround to expose the public IP to connected host. It involves changing IP configurations and kernel routing policy/tables, so it breaks internet connectivity on Android device. That's not a problem on modems/routers, but on Android it is. So we have to use NAT for Android's internal traffic (see Appendix B).

HOW TO TURN ANDROID INTO HALF-BRIDGED MODEM / ROUTER?

ISPs doing CGNAT usually create small subnets for connected clients, in case of public IP it could be even /8. In our case, let's say, the network ID is 1.2.3.8/30, so 1.2.3.9 will be the ISP's gateway address. There are different approaches we can go with, see Appendix C.

Rest of the details are given in the following script which can be executed followed by dhcp, static, arp or stop argument:

#!/system/bin/sh
set -e

[ "$(id -u)" = 0 ] || { echo 'Not running as root!' >&2; exit 1; }

# internal filed separator
IFS=$' \t\n'

##########################
# define / get variables #
##########################
SSID=MyAP                           # set this to your desired string (avoid spaces and non-ascii characters)
PASSCODE=foobarfoobar               # set this to your desired string (8 to 63 characters)
PUB_IFACE=rmnet_data                # set this according to your device (Qualcomm SoCs use 'rmne_data[N]')
WIFI_IFACE=wlan0                    # set this according to your device (check with 'lshw' or 'ip link show')
AP_IFACE=${WIFI_IFACE}-AP           # we'll create new WiFi interface for hotspot
DIR=/data/local/tmp/$AP_IFACE       # where to put config files
LOCAL_SUBNET=192.168.1              # for public interface
PST_RT_CHN=my_chain                 # to define source NAT for local packets
DNS1=1.1.1.1
DNS2=1.0.0.1

# read public interface name, IP and mask
read -r PUB_IFACE PUB_IP MASK <<< \
    $(ip -4 -o a | tr -s ' ' | awk -F'[ /]' '/'"$PUB_IFACE"'/ {print $2,$4,$5}')

# read ISP's default gateway
GW=$(ip r s t all | awk '/^default/ && /'"$PUB_IFACE"'/ {print $3}')

# ip for WiFi hotspot interface in public subnet
AP_IP=$GW/$MASK

############################
# start / stop bridge mode #
############################
STOP()
(
    echo 'Cleaning up...'

    # ignore errors
    set +e

    # don't print error messages
    exec >/dev/null 2>&1

    # hope there are no other instances of same daemons
        pkill -15 hostapd
        pkill -15 dnsmasq
    # remove local IP from public interface
        ip address del ${LOCAL_SUBNET}.1 dev $PUB_IFACE
    # remove rule and clear RPDB cache
        ip rule del lookup main
        ip route flush cache
    # flush main table
        ip route flush table main
    # disable forwarding
        printf 0 >/proc/sys/net/ipv4/ip_forward
        iptables -D FORWARD -i $AP_IFACE -o $PUB_IFACE -j ACCEPT
        iptables -D FORWARD -o $AP_IFACE -i $PUB_IFACE -j ACCEPT
    # stop listening on DHCP port
        iptables -D INPUT -i $AP_IFACE -p udp -m udp --dport 67 -j ACCEPT
    # stop local NAT
        iptables -t nat -D POSTROUTING -j $PST_RT_CHN
        iptables -t nat -F $PST_RT_CHN
        iptables -t nat -X $PST_RT_CHN
    # delete AP interface
        iw $AP_IFACE del
    # delete config directory
        rm -rf $DIR
)

if [ "$1" = stop ]
then
    STOP
    exit

elif [ "$1" != dhcp -a "$1" != static -a "$1" != arp ]
then
    echo 'Usage:' >&2
    printf '\t%s\n' "$(basename "$0") dhcp|static|arp|stop" >&2
    exit 1
fi

################
# basic checks #
################
if [ -z $PUB_IP ]
then
    echo 'Turn on Mobile Data first.' >&2
    exit 1
fi

if ! iw phy | grep -A10 'Supported interface modes:' | grep -q '\*[ ]*AP'
then
    echo 'AP mode not supported.' >&2
    exit 1
fi

if ! iw dev $WIFI_IFACE link | grep -q '^Not connected'
then
    echo 'First disconnect form Wi-Fi.' >&2
    exit 1
fi

##########################
# clear previous configs #
##########################
STOP

# clean up if error occurs
trap '[ $? = 0 ] || STOP' EXIT

#####################################
# create virtual wireless interface #
#####################################
if ! iw dev $WIFI_IFACE interface add $AP_IFACE type __ap
then
    echo "Couldn't create AP interface." >&2
    exit 1
fi

####################################
# configure interfaces and routing #
####################################
echo 'Configuring network...'

# add local IP to public interface and delete public IP
ip address add ${LOCAL_SUBNET}.1/30 dev $PUB_IFACE
ip address del $PUB_IP/$MASK dev $PUB_IFACE

# activate the WLAN interface
ip link set dev $AP_IFACE up

if [ "$1" = dhcp ]
then
    # assign ip in public subnet to WiFi hotspot interface
    ip address add $AP_IP dev $AP_IFACE

elif [ "$1" = static ]
then
    # assign ip in local subnet to WiFi hostspot interface
    ip address add ${LOCAL_SUBNET}.2/30 dev $AP_IFACE

else
    # start proxying ARP queries both ways
    printf 1 >/proc/sys/net/ipv4/conf/$AP_IFACE/proxy_arp
fi

# clear auto added routes and add new
ip route flush table main
ip route add $PUB_IP dev $AP_IFACE
ip route add default via $GW dev $PUB_IFACE
ip route flush cache

# Android doesn't look up into main table by default
ip rule add lookup main

# let packets be forwarded
printf 1 >/proc/sys/net/ipv4/ip_forward
iptables -I FORWARD -i $AP_IFACE -o $PUB_IFACE -j ACCEPT
iptables -I FORWARD -o $AP_IFACE -i $PUB_IFACE -j ACCEPT

# apply source NAT on internally generated packets
iptables -t nat -N $PST_RT_CHN
iptables -t nat -I POSTROUTING -j $PST_RT_CHN
iptables -t nat -I $PST_RT_CHN -o $PUB_IFACE ! -s $PUB_IP -j SNAT --to-source $PUB_IP

#######################
# access point daemon #
#######################
# create configuration file
mkdir -p $DIR
cat <<-HOSTAPD >$DIR/hostapd.conf
    # network name
    ssid=$SSID
    # passphrase to use for protected access
    wpa_passphrase=$PASSCODE

    # maximum STA clients allowed to connect
    max_num_sta=1

    # network interface to listen on
    interface=$AP_IFACE
    # wi-fi driver
    driver=nl80211

    # set operation mode, 'g' for 2.4GHz band
    hw_mode=g
    # WLAN frequency channel to use
    channel=1

    # key management protocol; use pre-share key
    wpa_key_mgmt=WPA-PSK
    # enforce WPA2
    wpa=2
HOSTAPD

echo 'Starting hostapd...'
hostapd -B $DIR/hostapd.conf

##########################################
# IP assignment; manually or dynamically #
##########################################
if [ "$1" = dhcp ]
then
    # create configuration file
    cat <<-DNSMASQ >$DIR/dnsmasq.conf
        # we dont want DNS server, only DHCP
        port=0

        # network interface to listen on
        interface=$AP_IFACE
        bind-interfaces

        # nameservers to be sent to clients
        dhcp-option=6,$DNS1,$DNS2

        # range of IPs to make available to wlan devices and when to renew IP
        dhcp-range=$PUB_IP,$PUB_IP,24h
        # where to save leases
        dhcp-leasefile=$DIR/dnsmasq.leases

        # respond to requests from a different IP broadcast subnet
        dhcp-authoritative

        # log extra information about DHCP handshakes
        log-dhcp
    DNSMASQ

    # open listening port for dnsmasq
    iptables -I INPUT -i $AP_IFACE -p udp -m udp --dport 67 -j ACCEPT

    echo 'Starting DHCP server...'
    dnsmasq -C $DIR/dnsmasq.conf </dev/null

else
    echo
    echo 'On connected host disable DHCP, set DNS and do:'
    echo 'ip a f dev <wifi>'
    echo "ip a a $PUB_IP dev <wifi>"
    echo 'ip r f t main'

    if [ "$1" = static ]
    then
        echo "ip r a ${LOCAL_SUBNET}.2 dev <wifi>"
        echo "ip r a default via ${LOCAL_SUBNET}.2 dev <wifi>"

    else
        echo 'ip r a default dev <wifi>'
        echo 'ip n f dev <wifi>'
    fi

    echo
fi

echo Done.

NOTE:

  • All of the required binaries (iw,ip, iptables, hostapd, dnsmasq) are available on Android but hostapd doesn't work on command-line. I used a static built binary, tested on Pie.
  • Based on the factors discussed here, your ISP may figure out (and mind) that your traffic is not originating from Android device.
  • After stopping half bridge mode, you need to turn Mobile Data OFF and ON to resume normal working because routes are cleared. Also on device boot you may need to switch on WiFi once so that wlan0 interface is created.
  • ISP's nameservers - if needed - (and default gateway) can also be obtained by:

    ~$ dumpsys connectivity | grep CONNECTED | grep -o 'Routes: .* DnsAddresses: [^ ]*'
    Routes: [0.0.0.0/0 -> 1.2.3.9 rmnet_data1,1.2.3.8/30 -> 0.0.0.0 rmnet_data1,] DnsAddresses: [1.1.1.1,8.8.8.8,]
    

VERIFICATION:

Your configuration should look like this:

1. Routing
==========
~$ ip rule show
0:  from all lookup local
9999:   from all lookup main

~$ ip route show table main
default via 1.2.3.9 dev rmnet_data1
1.2.3.10 dev wlan0-AP

2. Forwarding
=============
~$ cat /proc/sys/net/ipv4/ip_forward
1

~# iptables -S
-A FORWARD -i rmnet_data1 -o wlan0-AP -j ACCEPT
-A FORWARD -i wlan0-AP -o rmnet_data1 -j ACCEPT

3. Source NAT
=============
~$ ip -4 -o address
rmnet_data1    inet 192.168.1.1/30

~# iptables -t nat -S
-A POSTROUTING -j my_chain
-A my_chain ! -s 1.2.3.10/32 -o rmnet_data1 -j SNAT --to-source 1.2.3.10

4. Access Point Daemon
======================
~# iw dev
        Interface wlan0-AP
                ssid MyAP
                type AP

5 (a). DHCP Server
==================
~$ ip -4 -o address
wlan0-AP    inet 1.2.3.9/30

~# netstat -lup
Proto    Local Address   Foreign Address  PID/Program name
udp      1.2.3.9:67      0.0.0.0:*        23693/dnsmasq

~# iptables -S
-A INPUT -i wlan0-AP -p udp -m udp --dport 67 -j ACCEPT

5 (b). Static IP
================
~$ ip -4 -o address
wlan0-AP    inet 192.168.1.2/30

5 (c). Proxy ARP
================
~$ cat /proc/sys/net/ipv4/conf/wlan0-AP/proxy_arp
1

APPENDIX A:

Why Ethernet bridging isn't a straightforward option on Android:

  • There are at least two hosts on your local network; phone and router, but only one IP address is received from ISP. Two hosts on same network can't have same IP address.
  • If you transparently bridge rmnet_data1 and wlan0, both can have same IP address i.e. 1.2.3.10 but router still needs to be assigned another IP address, either statically or by DHCP server from ISP side. If you don't assign full bridge an IP, internet connectivity will break on Android which can't work (see Appendix B).
  • Ethernet bridging (which operates at OSI L2) doesn't work for WiFi interfaces in STA mode without WDS / 4addr support (on both sides of WiFi) which isn't supported by all physical interfaces. In AP mode, however, WiFi interface supports bridging, but 3G/4G interfaces don't. A recent patch to rmnet adds bridging support only for interfaces which can send MAP data.
  • An alternative to Ethernet bridging is proxy ARP (at OSI L3) or something like wlan_kabel which can be applied to both interfaces. But again you need three or at least two IP addresses; one for phone and one for router.

APPENDIX B:

Why NAT is required on device?

Modems have their own processors - called baseband or communication processor (BP or CP) on Android devices - and they run their own minimal RTOS. On small devices like phones they are integrated in SoCs. Communication with modem is done using a set of standard control protocol. AT commands is the traditional one used with PPP (1, 2), but manufacturers have developed new methods (e.g. QMI (3, 4, 5) / RmNet (6, 7) on Qualcomm devices).

The closed source vendor specific control/data modem protocols used on Android devices are not (or at least well) documented. Vendors provide native RIL Daemon as a binary blob which communicates with modem through RILJ and telephony framework in Java stack. When we turn on Mobile Data, these components work together to authenticate with MNO (by reading SIM data, APN settings etc.) and then configure the network stack (IP, DNS, route etc.) to make internet connectivity possible. So the modem is available to Android OS as in full bridge mode (no NAT involved on device).

Using methods explained above we assign public IP to connected host, so Android device itself loses internet connection. As soon as we make a change to the IP configuration, Android's telephony stack detects disconnections and sends a reset command to modem (through RILD) and whole network stack is refreshed with new (or same) IP settings received from MNO.

So to set Android device in Half Bridge mode, a more reliable approach is to take full control of communication with modem by altering the telephony framework (which isn't a simple task). As a workaround we do source NATing for internally generated packets on Android device so that it's not disconnected from internet. While the public IP is routed without any NAT to the only host connected to wlan0 interface, so that it's accessible from internet.

APPENDIX C:

Routing Methods for Half Bridge Mode on Android:

  • DHCP:
    Assign 1.2.3.10 to your router using DHCP server, 1.2.3.9 to wlan0 and 192.168.1.1/30 (or any other private IP) to rmnet_data1. It's also possible to create a hypothetical 1.2.3.0/X network and assign random IP from that hypothetical network to wlan0. But public IP address must not conflict with subnet ID or broadcast address in the faked subnet. It becomes difficult to achieve if IP is assigned dynamically, particularly if IP class and subnet mask keep on changing from ISP.
    In this way AP interface and router appear on same local network, and wlan0 IP is set as default gateway (next hop) for router. Here we are faking an IP address (at OSI L3).
  • Static Route:
    Setting IP/DNS on router manually allows you to assign local IP address to AP interface instead of using pseudo IP address. Add AP's IP address as default gateway on router. However router might have problem using default gateway on different subnet.
  • ProxyARP:
    Another option when not using DHCP is ProxyARP (8, 9, 10). If wlan0 has no IP address, we need to add a static route without IP address as default gateway. So router can't query gateway's MAC address and thus keeps asking wlan0 (in global broadcasts) where an internet address (next hop) is. It's because target of ARP queries is always the IP address, either of a local host or of default gateway (if destination IP is on another network).

    Due to ProxyARP, wlan0 provides its own MAC address for every ARP query received from connected host. ARP queries from rmnet_data1 (for 1.2.3.10's MAC address) are forwarded/received by wlan0 to/from connected host. rmnet_data1 itself doesn't have a MAC address (like PPP). A side effect of this approach is that the connected router will pollute its ARP cache by associating every visited internet address to AP's MAC address. Here we are faking a MAC address (at OSI L2).


CREDITS:

2

Have a look at this thread about using open VPN. Here you can give public IPs to devices using Open VPN, I think.

Or you could find another tethering app which supports this such as PdaNet+ which may have more control.

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .