nneonneo / iOS-SOCKS-Server

iOS HTTP/SOCKS proxy server for fake-tethering
250 stars 30 forks source link

Tethering Still Shows #18

Open jjbear11 opened 11 months ago

jjbear11 commented 11 months ago

Hello! I have been using this program for the last three months without issue. Now, when I try to use it, my data usage shows as Hotspot on my plan (and thus is throttled once I've gone over my cap). I'm on iOS 16.5.1 (c) and recently downloaded the most up-to-date code from the repo to see if any recent changes would fix my issue. Is there something in that version of iOS which could be causing issues here? Thanks for a great little script!

philrosenthal commented 11 months ago

Are you certain that you are using the socks proxy and not the tethering? ie: if you close the pythonista app, does the browser just show an error that it is unable to connect to the proxy?

Also, check what IPv4 and IPv6 addresses you are getting from both your phone in Safari and also on your computer that is connecting through the iOS-SOCKS-Server by checking: http://ip6only.me http://ip4.me

You should be seeing the same address on both your phone and your computer.

If not, check what address a browser using 'normal' tethering is, and see if that's the same as what you are getting through the iOS-SOCKS-Server script.

jjbear11 commented 11 months ago

I have confirmed that my traffic is indeed going through the Pythonista script; if I shut down Pythonista, my browser hangs as it is unable to connect to the proxy.

I am getting the same public IP address whether going through the 'normal' tethering or the iOS-SOCKS-Server script. I did notice however that when I do the 'normal' tethering route, my public IP is not the same on my connected device as it is on the host device. I would think that the aspect of tethering would inherently imply that the public host IP would be shared with the client (ie, I would see the same public IP on my client as I'm seeing on the host).

To note, I have another method of bypassing my tethering speed restrictions (although that method is limited to a single device at a time) -- and I have confirmed that it still works there. So it's not like my provider has caught on and has limited me in some way...

philrosenthal commented 11 months ago

The phone essentially has two cellular interfaces, one for on-device usage, and one for tethering usage. Unfortunately, there's not a clear way of selecting which one is the cellular interface, so we have to make an informed guess.

Each of those interfaces may have both an IPv4 and IPv6 address, or just an IPv4 or just an IPv6 address.

If you are trying to have it bill as if it is usage from the phone, it needs to have the same ipv4 / ipv6 address as the normal on-device usage on the phone.

There were some major changes in the past few months in order to add IPv6 support, and it would be helpful if you could try it at these particular commits to see if any of them pick the 'right' ip address.

https://github.com/nneonneo/iOS-SOCKS-Server/tree/330c97dd050ba5de142b17695407bcceadf32018 https://github.com/nneonneo/iOS-SOCKS-Server/tree/653bdc54b27c91711917657cb8376a4eba06ffae https://github.com/nneonneo/iOS-SOCKS-Server/tree/46a8ec61b7bce66c5e206b6294a2581f8acb5822 https://github.com/nneonneo/iOS-SOCKS-Server/tree/47f7ce1ef3a14d4deabe053d08f5816943646c79

jjbear11 commented 11 months ago

I used the following commit since it was the most-recent one. It appears that IPv6 support isn't working for me. I am receiving an error: Failed to connect to 2606:4700:4700::1111 over IPv6 due to: [Errno 65] No route to host. Any suggestions on what I can try?

philrosenthal commented 11 months ago

The failure of IPv6 isn't necessarily a problem. If your Cellular carrier doesn't have working IPv6 but does have an IPv6 address configured for some reason, this test takes place to make sure not to attempt to use IPv6 for the rest of the session.

As long as you aren't seeing an IPv6 address show up when you load ip6only.me in a browser, it's safe to ignore this. If you are seeing it show up in your tethering usage, though, the bigger question is figuring out why the IPv4 address is not the IPv4 address that your phone normally uses, but rather the tethering interface's address.

On Jul 27, 2023, at 3:24 PM, jjbear11 @.***> wrote:

I used the following commit https://github.com/nneonneo/iOS-SOCKS-Server/tree/653bdc54b27c91711917657cb8376a4eba06ffae since it was the most-recent one. It appears that IPv6 support isn't working for me. I am receiving an error: Failed to connect to 2606:4700:4700::1111 over IPv6 due to: [Errno 65] No route to host. Any suggestions on what I can try?

— Reply to this email directly, view it on GitHub https://github.com/nneonneo/iOS-SOCKS-Server/issues/18#issuecomment-1654397099, or unsubscribe https://github.com/notifications/unsubscribe-auth/AA5WPLMMOX4UFX33TGMYC2DXSK6AVANCNFSM6AAAAAA22HBHRU. You are receiving this because you commented.

jjbear11 commented 11 months ago

After some digging, it appears that my mobile provide (AT&T) -- with regards to their hotspot, incorporates double-NAT, or CGNAT technology. Not sure how to work around that... My work mobile is VZW, and I get the same public address on both host hotspot as well as client connected to hotspot. AT&T seems to be the culprit here.

nneonneo commented 11 months ago

One option would be to try disabling tethering and use an ad-hoc network instead: create an ad-hoc network on your computer and have your phone join it. iOS-SOCKS-Server has been tested to work in this configuration.

philrosenthal commented 11 months ago

After some digging, it appears that my mobile provide (AT&T) -- with regards to their hotspot, incorporates double-NAT, or CGNAT technology. Not sure how to work around that... My work mobile is VZW, and I get the same public address on both host hotspot as well as client connected to hotspot. AT&T seems to be the culprit here.

CGNAT is the normal way for IPv4 on cellular.

philrosenthal commented 11 months ago

@jjbear11 I've just re-read your comment again ... are you saying that the IPv4 address shown on ip4.me is the same on your computer using a hotspot as it is when you run it on your phone in Safari on AT&T?

jjbear11 commented 11 months ago

Actually it's the other way around. For example:

Work Phone

Personal Phone

I will look into the Ad-Hoc network idea suggested by @nneonneo earlier. I'm still stumped though as to why this worked a few months ago for me though, and now it isn't. I can only deduce that (perhaps) AT&T had previously not had CGNAT enabled on my device or something.

jjbear11 commented 10 months ago

So I think I may have stumbled upon something regarding my issue this morning; if I recall correctly, the python script had prior picked pdp_ip0 as the IPv4 interface. However, now the script picks something besides pdp_ip0 for the IPv4 interface (for instance, pdp_ip2 or pdp_ip3). That appears to cause my tethered traffic to not appear correctly. Is there a way to "force" pdp_ip0 (at least for me to test to see if this is indeed the issue)? Thanks!

philrosenthal commented 10 months ago

Try this out and see if it helps.

Look for this section of code (lines 94-100):

XXX implement better classification of interfaces

    if iface.name.startswith("en"):
        iftypes["en"].append(iface)
    elif iface.name.startswith("bridge"):
        iftypes["bridge"].append(iface)
    else:
        iftypes["cell"].append(iface)

Change it as follows:

    # XXX implement better classification of interfaces
    if iface.name.startswith("en"):
        iftypes["en"].append(iface)
    elif iface.name.startswith("bridge"):
        iftypes["bridge"].append(iface)
    elif iface.name == 'pdp_ip0':
        iftypes["cell"].append(iface)

On Aug 7, 2023, at 9:54 AM, jjbear11 @.***> wrote:

So I think I may have stumbled upon something regarding my issue this morning; if I recall correctly, the python script had prior picked pdp_ip0 as the IPv4 interface. However, now the script picks something besides pdp_ip0 for the IPv4 interface. That appears to cause my tethered traffic to not appear correctly. Is there a way to "force" pdp_ip0 (at least for me to test to see if this is indeed the issue)? Thanks!

— Reply to this email directly, view it on GitHub https://github.com/nneonneo/iOS-SOCKS-Server/issues/18#issuecomment-1667903706, or unsubscribe https://github.com/notifications/unsubscribe-auth/AA5WPLLZ62GVU44G2BLVTWTXUDXQFANCNFSM6AAAAAA22HBHRU. You are receiving this because you commented.

jjbear11 commented 10 months ago

Yep that did it! Hard-coding the pdp_ip0 as my cell interface has me back up and running now. I wonder why the automatic detection of the interface had previously picked pdp_ip0 but now won't pick that interface. Either way, thank you so much for the help!

philrosenthal commented 10 months ago

Can you confirm that this solved the issue with data being tracked as tethering rather than phone usage?

jjbear11 commented 10 months ago

Can you confirm that this solved the issue with data being tracked as tethering rather than phone usage?

Yes, I do confirm that hardcoding pdp_ip0 for the interface name fixed my issue. My data usage properly shows as phone usage now instead of tethering and I am no longer throttled in my speed when using this script. Thanks!

philrosenthal commented 10 months ago

@nneonneo I'm not sure your thoughts on making changes here -- this is related to my own experience (and was in my pull request), and as jjbear has noted, the current code is in fact broken for some users (apparently, AT&T), and forcing it to pdp_ip0 does resolve it in that case.

Perhaps there's a way we can look at the routing table to get an idea of what the default route is ... but barring that, I'd be inclined to just hard set it to pdp_ip0 for myself given the clear example shown with this reported issue.

nneonneo commented 10 months ago

I'm fine with, say, prioritizing pdp_ip0 over all other options if present. I just don't know if it's possible to guarantee that that will always be the cell connection, but I agree that the current implementation is deficient.

philrosenthal commented 10 months ago

I'll see if I can find some good solutions to analyze the routing table, and if not, will select pdp_ip0 as long as it is present and if not, go back to the current algorithm.

Once I've got that completed, I will post a pull request.

On Aug 30, 2023, at 10:39 PM, Robert Xiao @.***> wrote:

I'm fine with, say, prioritizing pdp_ip0 over all other options if present. I just don't know if it's possible to guarantee that that will always be the cell connection, but I agree that the current implementation is deficient.

— Reply to this email directly, view it on GitHub https://github.com/nneonneo/iOS-SOCKS-Server/issues/18#issuecomment-1700288351, or unsubscribe https://github.com/notifications/unsubscribe-auth/AA5WPLKTOMI32WAZMINAU4DXX72OPANCNFSM6AAAAAA22HBHRU. You are receiving this because you commented.

philrosenthal commented 10 months ago

It looks like there's no straightforward way of accessing the routing table under Pythonista ...

Perhaps this code could be used as an example on building something to access system libraries directly to see the routing table under Pythonista:

https://github.com/jianpx/ios-cabin/tree/master/RouteTableManager

I'm not sure how difficult it would be to port if it's even possible.

If we could port it, we'd be able to see all the various default routes, and the interfaces they are using, which would provide a list of potential interfaces to use ... which would likely give us a list of enX, ipsecX, and pdp_ipX ... we could then most likely use the lowest number for pdp_ipX to have a default route, which would probably reliably be the main network interface.

nneonneo commented 8 months ago

@philrosenthal I can confirm that it's possible to obtain the route table on iOS, with this proof of concept:

import ctypes

CTL_NET = 4
PF_ROUTE = 17
NET_RT_DUMP2 = 7

mib = (ctypes.c_int * 6)()
mib[0] = CTL_NET
mib[1] = PF_ROUTE
mib[2] = 0  # protocol number, currently always 0
mib[3] = 0  # address family, 0 for all address families
mib[4] = NET_RT_DUMP2
mib[5] = 0

libc = ctypes.CDLL("libSystem.dylib")
sz = ctypes.c_int()
res = libc.sysctl(mib, 6, 0, ctypes.byref(sz), 0, 0)
print(res, sz)

buf = ctypes.create_string_buffer(sz.value)
res = libc.sysctl(mib, 6, buf, ctypes.byref(sz), 0, 0)
print(res, buf.raw, sz)

What we need to do now is parse the buf according to the binary format into a useful form.