Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Set static IP addresses (Android 11+) #193

Closed
knuxyl opened this issue Nov 12, 2020 · 39 comments
Closed

Set static IP addresses (Android 11+) #193

knuxyl opened this issue Nov 12, 2020 · 39 comments

Comments

@knuxyl
Copy link

knuxyl commented Nov 12, 2020

I don't know if it's the Pixel 5 Android 11, but before on my Moto X4 Android 10 the IPs given to clients was always 192.168.43.XXX. With my Pixel 5, it is now completely random every time I turn the hotspot on. I do not know if this is Android 11, Pixel 5, or a bug in VPN Hotspot. I need my IPs to be static.
What it did on Moto X4
Desktop - 192.168.43.125
Server - 192.168.43.100
What its doing now on Pixel 5
Desktop 192.168.170.125
Server - 192.168.170.100
The bold is random everytime, but it does keep the last digits the same.

If this isn't a ug, could this be a feature request to allow control over this?

@Mygod
Copy link
Owner

Mygod commented Nov 12, 2020

This is an intended feature of Android 11. You should complain to Google instead.

@Mygod Mygod added the vendor-specific Definitely not my fault label Nov 12, 2020
@Mygod Mygod closed this as completed Nov 12, 2020
@Mygod Mygod changed the title Possible bug : Randomized IP subnet Set static IP addresses (Android 11+) May 31, 2021
@Mygod
Copy link
Owner

Mygod commented May 31, 2021

Reopening since technically setStaticIpv4Addresses API addresses this, but it seems it will restrict the tethering to only one device.

@Mygod Mygod reopened this May 31, 2021
@seandepagnier
Copy link

This "feature" is really useless. Why did they do this?

@Mygod
Copy link
Owner

Mygod commented Feb 22, 2022

In principle, it is possible to hijack the DNS so that a fixed domain will point to the gateway. However, this requires root and I do not see a useful use case for now.

@worstperson
Copy link

worstperson commented Mar 17, 2022

This is an example of redirecting DHCP requests to your own instance of Dnsmasq serving on a non-standard port, in this case for usb tethering. This lets you set any local network, dns servers, static leases.

Clear and set addresses and add the route

ndc interface clearaddrs rndis0
ndc interface setcfg rndis0 192.168.42.1 24 up
ndc network route add 99 rndis0 192.168.42.0/24

Take broadcast udp traffic on port 67 and redirect it to 1067.

iptables -t nat -I PREROUTING -i rndis0 -s 0.0.0.0 -d 255.255.255.255 -p udp -m udp --dport 67 -j DNAT --to-destination 255.255.255.255:1067

Start a new Dnsmasq instance with the dhcp-alternate-port option to receive requests on our alternative port.

killall dnsmasq
dnsmasq --keep-in-foreground --no-resolv --no-poll --dhcp-authoritative --dhcp-range=192.168.42.10,192.168.42.99,1h --dhcp-option=6,8.8.8.8,8.8.4.4 --dhcp-leasefile=/sdcard/dnsmasq.leases --dhcp-alternate-port=1067,68 --dhcp-option-force=43,ANDROID_METERED --pid-file=/sdcard/dnsmasq.pid --listen-mark 0xf0063

Edit:
Dnsmasq still seems to be used for dns. Specifying the port gets around having to kill it.

dnsmasq --keep-in-foreground --no-resolv --no-poll --dhcp-authoritative --dhcp-range=192.168.42.10,192.168.42.99,1h --server=8.8.8.8 --server=8.8.4.4 --dhcp-leasefile=/sdcard/dnsmasq.leases --dhcp-alternate-port=1067,68 --port=1053 --dhcp-option-force=43,ANDROID_METERED --pid-file=/sdcard/dnsmasq.pid --listen-mark 0xf0063

And we can then redirect to the new dns server.

iptables -t nat -I PREROUTING -i rndis0 -s 192.168.42.0/24 -d 192.168.42.1 -p udp -m udp --dport 53 -j DNAT --to-destination 192.168.42.1:1053

@Mygod
Copy link
Owner

Mygod commented Mar 17, 2022

@worstperson Thanks for looking into this! However, I prefer to not kill dnsmasq since that may not work properly. (If I remember correctly, there are some interfacing between the Android netd services and dnsmasq.)

@worstperson
Copy link

Below "Edit:", I had fixed it by setting the DNS port to avoid conflicting and added a rule to point traffic to it.

@worstperson
Copy link

Sorry that wasn't very clear. I quickly realized that you wouldn't accept the original PoC shortly after posting, so I hurriedly fixed the dns server conflict and added it at the bottom of the post with inadequate description. Android seems to still use Dnsmasq as a dns cache, so I used the --port option to change the dns listening port and added an iptables rule to intercept dns requests from clients and redirect them to the port we're listening on. I also changed the dnsmasq command to direct clients to it's dns server, rather than sending them the remote servers to query directly.

ndc interface clearaddrs rndis0
ndc interface setcfg rndis0 192.168.42.1 24 up
ndc network route add 99 rndis0 192.168.42.0/24
# Redirect DHCP requests
iptables -t nat -I PREROUTING -i rndis0 -s 0.0.0.0 -d 255.255.255.255 -p udp -m udp --dport 67 -j DNAT --to-destination 255.255.255.255:1067
# Redirect DNS requests
iptables -t nat -I PREROUTING -i rndis0 -s 192.168.42.0/24 -d 192.168.42.1 -p udp -m udp --dport 53 -j DNAT --to-destination 192.168.42.1:1053
dnsmasq --keep-in-foreground --no-resolv --no-poll --dhcp-authoritative --dhcp-range=192.168.42.10,192.168.42.99,1h --server=8.8.8.8 --server=8.8.4.4 --dhcp-leasefile=/sdcard/dnsmasq.leases --dhcp-alternate-port=1067,68 --port=1053 --dhcp-option-force=43,ANDROID_METERED --pid-file=/sdcard/dnsmasq.pid --listen-mark 0xf0063

An example of how to reverse the changes made. The variable $NETWORK should be set to the ip that was originally assigned to the interface.

# Stop your Dnsmasq instance first
iptables -t nat -D PREROUTING -i rndis0 -s 192.168.42.0/24 -d 192.168.42.1 -p udp -m udp --dport 53 -j DNAT --to-destination 192.168.42.1:1053
iptables -t nat -D PREROUTING -i rndis0 -s 0.0.0.0 -d 255.255.255.255 -p udp -m udp --dport 67 -j DNAT --to-destination 255.255.255.255:1067
ndc network route remove 99 rndis0 192.168.42.0/24
ndc interface clearaddrs rndis0
ndc interface setcfg rndis0 $NETWORK 24 up

@Mygod
Copy link
Owner

Mygod commented Mar 25, 2022

Thanks for the POC. Still not sure if I want to implement all of that though. 🤣

@copystring
Copy link

For days I'm looking for a way to have a fixed DHCP range for my pixel 5.
In my very specific use case my car connects to my phones hotspot. Then Torque Pro installed on my car is supposed to connect to the app "Torque OBD2 Repeater". This would only ever work if the IP range is static otherwise every restart of my phone I'd have to enter the IP manually on my car.
But to make it useable for me this would also need the tasker implementation to turn on the hotspot when connect to my car via Bluetooth so yeah ... 🤷‍♂️

@Unnamed3
Copy link

It would be very nice if you implement this feature to reverse these annoying changes that Google made to Android.
I have a case too where I need to update the ip addresses everytime. Before Android 10 and 11, the android Wi-Fi tethering IP address was 192.168.43.0/24, and 192.168.42.0/24 for USB tehrering.
Even the gateway address is now random instead of 192.168.x.1.
Furthermore, this problem wouldn't be as annoying as it is now if the phone would have used its own DNS. But thats not the case, as I already tried. See this thread : https://android.stackexchange.com/questions/230983/the-phone-as-hotspot-doesnt-use-its-own-dns

@seandepagnier
Copy link

It does not add any meaningful security to my local network that is WPA encrypted anyway. I am not going to hijack my own dns. This is an annoying change that makes using android hot spot less convenient.

@Unnamed3
Copy link

Any news on this ? Really want this feature added, thanks

@GhettiGuru
Copy link

GhettiGuru commented Oct 19, 2023

Yes I had a similar issue, I was unable to set a IP address and I had to statically for ethernet for my USBC hub and I've never had the problem before I usually used kali Linux, on my phone as chroot o program routers and stuff before but I hadn't tried it on this device yet. There is no option for setting a static IP address for programming a router or something like I could not manually assign it at all plug up the USBC hub it gets what it gets like I couldn't figure it out for anything I finally gave up and went home and got my PC when I've done this before but not on this device Motorola generally was what I roll though outside of a few htcs the HTC One M8 and U11 other than that I've never had this problem before it's confusing wasn't an option anywhere for ethernet for that, there's a tether by (or hotspot)by ethernet in settings that was the only one I found. I was on Android 12 at the time but since I've taken a 13 update I would have to look, I doubt anything has changed. If there wasn't much trouble implementing a feature where you can assign your own IP ranges and addresses they would be helpful because I needed to give myself, on the host/server device an IP address and I was unable to.

@Mygod
Copy link
Owner

Mygod commented Oct 23, 2023

I think the best way to do this at the moment is to write an Xposed module to hook up relevant methods in IpServer.

@cleanerspam
Copy link

Can we please get this feature , I have read on here and stackexchange that it can be done by some hacky method .
Maybe some way to Permanently set the gateway as 192.168.1.xyz in VPN hotspot app

@worstperson
Copy link

Mygod is right, making a simple Xposed module or framework patcher is for sure the best approach, it's not VPN Hotspot's fault Android does this.

I spent some time to make a patch if you want to try. It's missing GUI options, ideally you'd set an IP per interface, but here it is hardcoded so you can only safely apply to one interface at a time. DNSMasq's pid file should also go into getFilesDir().getPath() rather than /sdcard/.

In be.mygod.vpnhotspot.net.Routing
Near the top I add variables to define the new IP/prefix and redefine hostAddress and hostSubnet so they can be reassigned later on

    val ipv4Addr = "192.168.1.129"
    val ipv4Prefix = ipv4Addr.substring(0, ipv4Addr.lastIndexOf("."))

    //private val hostAddress = try {
    private var hostAddress = try {
        val iface = NetworkInterface.getByName(downstream) ?: error("iface not found")
        val addresses = iface.interfaceAddresses!!.filter { it.address is Inet4Address && it.networkPrefixLength <= 32 }
        if (addresses.size > 1) error("More than one addresses was found: $addresses")
        addresses.first()
    } catch (e: Exception) {
        throw InterfaceNotFoundException(e)
    }
    //private val hostSubnet = "${hostAddress.address.hostAddress}/${hostAddress.networkPrefixLength}"
    private var hostSubnet = "${hostAddress.address.hostAddress}/${hostAddress.networkPrefixLength}"

And create a function to do the override, I placed it right under the function "masquerade"

    fun addressOveride() {
        // Collect the nfmark for the downstream interface
        val markCmd = transaction.execQuiet("iptables-save | grep '\\-i " + downstream + " \\-j MARK \\-\\-set\\-xmark'").out
        val mark = markCmd.substring(markCmd.indexOf("0x300") + 5, markCmd.indexOf("/"));

        // Add a new address to the interface
        transaction.exec("ip address add local " + ipv4Addr + "/24 broadcast " + ipv4Prefix + ".255 scope global dev " + downstream, "ip address del local " + ipv4Addr + "/24 broadcast " + ipv4Prefix + ".255 scope global dev " + downstream)

        // Add route for our address
        transaction.exec("ip route add " + ipv4Prefix + ".0/24 dev " + downstream + " table local_network proto static scope link", "ip route del " + ipv4Prefix + ".0/24 dev " + downstream + " table local_network proto static scope link")

        // Redirect DHCP to our own DNSMasq instance
        transaction.exec("iptables -t nat -A PREROUTING -i " + downstream + " -s 0.0.0.0 -d 255.255.255.255 -p udp --dport 67 -j DNAT --to-destination 255.255.255.255:6767", "iptables -t nat -D PREROUTING -i " + downstream + " -s 0.0.0.0 -d 255.255.255.255 -p udp --dport 67 -j DNAT --to-destination 255.255.255.255:6767")

        // Launch DNSMasq to serve DHCP only, VPN Hotspot does it's own DNS redirect
        transaction.exec("dnsmasq --keep-in-foreground --no-resolv --no-poll --dhcp-authoritative --dhcp-range=" + ipv4Prefix + ".10," + ipv4Prefix + ".99,1h --dhcp-alternate-port=6767,68 --port=0 --dhcp-option-force=43,ANDROID_METERED --listen-mark 0xf00" + mark + " --pid-file=/sdcard/dnsmasq-" + downstream + ".pid >&- 2>&- &", "kill -s 9 \$(cat /sdcard/dnsmasq-" + downstream + ".pid)")
        
        hostAddress = try {
            val iface = NetworkInterface.getByName(downstream) ?: error("iface not found")
            val addresses = iface.interfaceAddresses!!.filter { it.address is Inet4Address && ipv4Addr == it.address.hostAddress!!.toString() }
            if (addresses.size > 1) error("More than one addresses was found: $addresses")
            addresses.first()
        } catch (e: Exception) {
            throw InterfaceNotFoundException(e)
        }
        hostSubnet = "${hostAddress.address.hostAddress}/${hostAddress.networkPrefixLength}"
    }

In be.mygod.vpnhotspot.TetheringService
Add the call to do the override when the Downstream is configured

    private class Downstream(caller: Any, downstream: String, var monitor: Boolean = false) :
            RoutingManager(caller, downstream) {
        override fun Routing.configure() {
            addressOveride()
            forward()
            masquerade(masqueradeMode)
            if (app.pref.getBoolean("service.disableIpv6", true)) disableIpv6()
        }
    }

@Mygod
Copy link
Owner

Mygod commented Feb 18, 2024

Thanks a lot @worstperson! Unfortunately that patch seems to hacky to be merged (and having a way to configure this for multiple tethering interfaces is probably also needed). :)

@Mygod
Copy link
Owner

Mygod commented Feb 20, 2024

@worstperson What do you think of @poqdavid's script in #537? It seems to me that that seems like a better solution than hacking around dnsmasq if it works.

@poqdavid
Copy link

@worstperson What do you think of @poqdavid's script in #537? It seems to me that that seems like a better solution than hacking around dnsmasq if it works.

I have a suggestion maybe we could have both as an option like how IP Masquerade Mode works in the app for more compatibility

@Mygod
Copy link
Owner

Mygod commented Feb 20, 2024

I think it would be ideal to avoid keeping a separate instance of dnsmasq alive.

@worstperson
Copy link

@Mygod
It only supports static configurations, clients that have DHCP enabled will be served addresses from the original range.
It is not reversible(must disable and enable tethering) since it removes the original address from the interface which breaks DNSMasq's port 53 binding.
The 'ndc network route' command is unnecessary since the correct policy routing rules are already in place.

I think it might be better to just add the new address and route to the interface. Clients can use static addresses if they want to operate in that specific range and clients connecting with DHCP will still get a working connection and ip from the original range. Basically just my patch above without the lines to collect the nfmark, redirect DHCP, and spawn DNSMasq.

@Mygod
Copy link
Owner

Mygod commented Feb 21, 2024

Right. If all we want is a stable IP address for the clients to connect to, why not just create a new interface with a static IP (can make it /32 even)? This way we should break virtually zero things.

@Mygod Mygod closed this as completed in 044206f Feb 21, 2024
@Mygod
Copy link
Owner

Mygod commented Feb 21, 2024

Added static IP support via a staticip dummy interface in 044206f. It seems to work fine from my testing. If anyone has a use case that is not covered by this, they may start a new issue.

@Mygod Mygod removed the vendor-specific Definitely not my fault label Feb 21, 2024
@worstperson
Copy link

worstperson commented Feb 21, 2024

No luck here, though I could be just dumb. The interface gets created and assigned, seems to be a single address assignment though.

staticip Link encap:Ethernet HWaddr ae:0c:ad:fb:72:98
inet addr:10.78.2.173 Bcast:0.0.0.0 Mask:255.255.255.255
inet6 addr: fe80::ac0c:adff:fefb:7298/64 Scope: Link
UP BROADCAST RUNNING NOARP MTU:1500 Metric:1
RX packets:0 errors:0 dropped:0 overruns:0 frame:0
TX packets:6 errors:0 dropped:0 overruns:0 carrier:0
collisions:0 txqueuelen:1000
RX bytes:0 TX bytes:420

No route is created afaict, but also I don't know how a dummy interface can be used like this without bridging to the tether interface (which we can't do ofc). Is it supposed to be a virtual sub-interface or something like that?

@worstperson
Copy link

worstperson commented Feb 21, 2024

Ok, scratch that. Added a cidr to the default address and it sets up the address and route correctly now. Still not getting any traffic to pass between the client and phone in either direction though.

@Mygod
Copy link
Owner

Mygod commented Feb 21, 2024

What do you mean? It works fine for me. What do you get if you run ip route get 10.78.2.173 from <client ip> iif <tethering iface>?

EDIT: Also check that ip route show table local displays the correct entry for staticip? Tested again on my phones and seemed fine.

@poqdavid
Copy link

btw with my script DHCP still sends the randomly generated IP is there a way to change or prevent that?

@Mygod
Copy link
Owner

Mygod commented Feb 21, 2024

@poqdavid I did not plan to support that. What is your use case?

@poqdavid
Copy link

@poqdavid I did not plan to support that. What is your use case?

Well, I use my phone's hotspot a lot to connect a lot to the internet and I run things like DNSCrypt, VBAN and it gets really difficult when the IP keeps changing so that's why I been using that script

@Mygod
Copy link
Owner

Mygod commented Feb 21, 2024

Okay but I don't see why you need all the clients to have static IPs?

@poqdavid
Copy link

Okay but I don't see why you need all the clients to have static IPs?

Well, I host things using Termux and every time IP changes, I got to change settings on both my phone and PC

@Mygod
Copy link
Owner

Mygod commented Feb 21, 2024

Just point your clients to the static IP instead and you'll be fine.

@worstperson
Copy link

Sorry for the late reply, was at work. I switched from rndis to wlan for testing today to see if it changes anything. I set Static IP to 10.0.0.1 to make things easier and assigned my computer to 10.0.0.2. Appending a cidr doesn't seem to effect the test results. The tests through wlan have no upstream, ethernet adapter is not available rn and I don't want to setup a reverse tether. Shouldn't matter though.

ocean:/ # ip route get 10.0.0.1 from 10.0.0.2 iif wlan0
local 10.0.0.1 from 10.0.0.2 dev lo table local
cache iif wlan0

ocean:/ # ip route show table local
local 10.0.0.1 dev staticip proto kernel scope host src 10.0.0.1
(truncated)

But no route to my computer

ocean:/ # ip r g 10.0.0.2 f 10.0.0.1 i wlan0
RTNETLINK answers: Network is unreachable

ocean:/ # ip r g 10.0.0.2
RTNETLINK answers: Network is unreachable

ocean:/ # ping -W 3 -c 1 10.0.0.2
connect: Network is unreachable

If I specify the interface it works?!

ocean:/ # ping -W 3 -c 1 -I wlan0 10.0.0.2
PING 10.0.0.2 (10.0.0.2) from 192.168.145.106 wlan0: 56(84) bytes of data.
64 bytes from 10.0.0.2: icmp_seq=1 ttl=64 time=268 ms

--- 10.0.0.2 ping statistics ---
1 packets transmitted, 1 received, 0% packet loss, time 0ms
rtt min/avg/max/mdev = 268.658/268.658/268.658/0.000 ms

Now checking from my computer, I have a route to the phone

[user@SFF-PC ~]$ ip r g 10.0.0.1
10.0.0.1 dev wlp0s20f0u10 src 10.0.0.2 uid 1000
cache

But packets never get a response

[user@SFF-PC ~]$ ping -W 3 -c 1 10.0.0.1
PING 10.0.0.1 (10.0.0.1) 56(84) bytes of data.

--- 10.0.0.1 ping statistics ---
1 packets transmitted, 0 received, 100% packet loss, time 0ms


Testing with another device, this time with rndis0 as the downstream and wlan0 as an upstream

kiev:/ # ping -W 3 -c 1 10.0.0.2
PING 10.0.0.2 (10.0.0.2) 56(84) bytes of data.
From 192.168.42.129: icmp_seq=1 Destination Net Unreachable

--- 10.0.0.2 ping statistics ---
1 packets transmitted, 0 received, +1 errors, 100% packet loss, time 0ms
You can see packets are getting routed to the upstream instead of downstream

Specifying the interface still works

kiev:/ # ping -W 3 -c 1 -I rndis0 10.0.0.2
PING 10.0.0.2 (10.0.0.2) from 192.168.115.73 rndis0: 56(84) bytes of data.
64 bytes from 10.0.0.2: icmp_seq=1 ttl=64 time=1.64 ms

--- 10.0.0.2 ping statistics ---
1 packets transmitted, 1 received, 0% packet loss, time 0ms
rtt min/avg/max/mdev = 1.646/1.646/1.646/0.000 ms

And still no response from the phone

[user@SFF-PC ~]$ ping -W 3 -c 1 10.0.0.1
PING 10.0.0.1 (10.0.0.1) 56(84) bytes of data.

--- 10.0.0.1 ping statistics ---
1 packets transmitted, 0 received, 100% packet loss, time 0ms

@Mygod
Copy link
Owner

Mygod commented Feb 21, 2024

@worstperson You don't assign your computer a static IP. Just use DHCP and connect to the new static IP, for example 10.0.0.1.

@worstperson
Copy link

That works, I see what you were doing now. I didn't realize this was only for running services on the phone lol. Was thinking custom local ranges so I could (for example) block DHCP requests from reaching the phone and serve it on the client that forwards the tether to other devices, but fair enough. This is still a useful feature as-is.

@Mygod
Copy link
Owner

Mygod commented Feb 22, 2024

@worstperson Yes. Not sure why you would want to do that. If there is a reasonable use case, I can consider supporting it.

@worstperson
Copy link

worstperson commented Feb 22, 2024

The idea is to let me run servers with known fixed addresses from any arbitrary device(could be nfs or a webserver or a webclient for a torrent client, or any number of things) on my local network. DHCP was my example because I could use it to assign static addresses to devices on my network without having to set their network configuration. DoH/DoT servers and network wide adblocking are other great applications. If you additionally gave the option to drop DHCP requests from the static subnet in the app, it'd make it easy to just bridge the tether interface to ethernet in Windows and let any old router on the network provide that service.

But me personally, I'd just patch the framework and be done with it. It's not a big ask to just diy it from my point of view. What you've already implemented is great and I'm perfectly happy leaving it there.

@cleanerspam
Copy link

But me personally, I'd just patch the framework and be done with it. It's not a big ask to just diy it from my point of view. What you've already implemented is great and I'm perfectly happy leaving it there.

Please post the link of Lsposed(xposed) module if you build it to bypass this silly restriction of Android

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

9 participants