-
Notifications
You must be signed in to change notification settings - Fork 52
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
Android Captive Portal Helper isn't triggered. #2
Comments
Just tested with Android 6.0.1 on a Nexus 5X, and a Nexus 6. Connecting to the hotspot brings up a "Sign in to wifi network" notification and toast. Clicking the notification loads the captive portal. What version of android are you running? |
I'm using a Galaxy S5 with Android 6.0.1. I'm not sure why my phone doesn't work the same. I'd like for it to open a browser page like it does on iOS. It does pop open a browser when I connect to some captive portals at restaurants and parks with free wifi though. I'd like for mobile-rr to work the same as those captive portals. I just need to do some packet sniffing to find out what the difference is. |
The captive portal also doesn't work for me although I'm on iOS. Is it possible that it's broken on iOS 10? |
I don't have an iOS 10 device but will see what I can come up with to test with. |
It just worked once for iOS 10, while it works again if I renew my release in iOS 9 |
Please check if my pull request fixes it: #10 |
Hmmm... still the same for me on my Android device but if it fixed it for you I'll merge it. |
This doesn't fix it for iOS 10 |
Hmm. Stopped working for me as well. Strange thing is that it works sometimes. It might be a caching issue. Probalby it is a good idea to send nocaching headers for the redirects and the captive portal index and set the TTL of DNS answers to 0 seconds. The DNS setting can be set using:
And the caching directives could be set using something like this:
However that also was not enough. But maybe because of the fact that things are still cached and I don't know how to reset the DNS cache and other caches on my phone. |
Thanks for the suggestions. I'm adding them now. I still have to do some WiFi sniffing to try and determine the difference between this captive portal and others. Is there a way to set DHCP option 160. I'm curious if that is what the difference is. |
It looks like it works on iOS 10 (dev beta 8/ public beta 7) now. |
Oh great! Thanks for the feedback. |
on my ios 10.0.1 iphone 6 doestn work anymore...i use a nodemcu and had to change the platformio.ini to this: [env:nodemcuv2] than compiling and uploading is no problem anymore...but as said the portal doesnt open...can only go to console if i type the url :/ |
Not working for me either, but I can't imagine it being a device dns-cache issue because places like McDonald's still cause a pop-up on my phone. Has anyone tried sniffing the wifi when connecting to a mcdoogles hotspot? Tell me a good program to grab wifi frames on connection and I'll try it myself. By the way, you can see what android does by looking at the source code. Among other things, I see a reference to not follow redirects when pulling the 204. (google CaptivePortalTracker.java for whatever version of android you are curious about) e.g. |
Further testing on my part with your dns server library, and I can see the dns requests are being answered, but I never see the requests combing back to the web server. My guess appears to be dns caching or otherwise not-trusting the response of the local-net address on the part of the mobile device. I'm wondering if there is any way to get the web server code to answer the /generate_204 and other urls regardless of the address they are being sent to. Something similar to IPTables redirects in linux or something. |
I added a callback to be able to override the IP of a DNS query to point the DNS to an IP that is inactive on the local network and that did not solve the issue either. This post suggested that method. I'm just now getting back to this to see if I can come up with a solution. My phone pops up the CP Helper every time at a McDonalds or Taco Bell and other CPs at restaurants but not from this little device. I will do some sniffing again soon to see if I can find any differences. Any feedback is greatly appreciated. I'd love to solve this issue. |
I'm working on a bit different project which uses Captive Portal. I have rewritten DNS code from scratch using AsyncUDP, extended it to handle most of DNS requests and it still did not help (manual browser navigation redirects correctly). |
Did you try to implement DNS Option 160 in your custom DNS code? I'm curious if that would activate the CP Helper. |
There is no such thing as DNS option 160, it's DHCP option 160 and it's implemented in DHCP server on ESP (I have verified that), if it was not implemented then the device would not receive address of DNS server (and it would not receive any DNS query packets). From inspection of packets coming to my DNS server I can see that the phone asks for the IPs for google servers and my ESP sends responses (I've verified that those responses are valid). But there are no HTTP requests made to web server, which is weird. If I open Chrome manually then if I type http://github.com then I'm properly redirected to my captive portal (which means that both DNS and web server are working), but there is no "Sign in to WiFi network" popup. As I've written in my post before on my Tab Pro with Cyanogen everything works as expected. |
Ooops sorry... Yes it is for DHCP but it is not for sending the DNS server address. It is for sending the url for a captive portal within the DHCP configuration. How would you set it in the ESP if it is already implemented? This article explains it's use a bit better. |
Unfortunately this would require change in ESP SDK, you can see DHCP options here https://github.com/esp8266/Arduino/blob/f9ac524b13348e18a1ceb00261d947d6c1e0f9b5/tools/sdk/lwip/src/app/dhcpserver.c#L134 |
I just tried with a change to lwip, adding DHCP option 160 to the offer. Unfortunately this didn't help for a Samsung S8; there was no automatic opening of the captive portal browser. I double checked the option looked correct using wireshark on a Linux machine (no captive portal browser opened there either). I guess option 160 is a dead-end, at least for now. |
Oh shoot... ok. Thanks for trying it out and letting us know. |
Did you guys manage to get it working!?? |
I have not looked at it again in a long time. Still an open issue until we find a solution. |
I got it working! there are some commeted out lines on remove the comments and adding
It works! it seems my phone (s7 edge) was sending the request to I also enabled |
@Marfjeh Good job! Do you send in a pull request for all the lazy people? ;-) |
Sure. i'll fork the project |
@treii28 concerning dest_address[3] += 10, it does not matter since it's uint8_t, so it will overflow to zero automatically. In terms of address clashes it should also work as the address I'm returning needs to be fake, any connection to broadcast will fail, so it should trigger the sign-in popup. |
ok, wasn't sure on the type - but overflow to zero could also equal zero for 246. And zero is a network address. Again, not good. |
And I'm not understanding how your step 2) is working if you are responding with a different dns address for the urls. The ESP won't try to answer it if the incoming request isn't sent to it's AP address. |
nope - no helper pop-up when returning a different address for the googles. Same ole 'Internet may not be available' with no redirect to a landing page. I inserted my offset in the wrong spot, but added debug stuffs to make sure it was detecting the google addresses and returning the non-ap address. No change in android behavior. (I also tried it with the sketch's override ip method) Or are you actually answering those with a second AP assigned to the address? |
Here is a diff that should work, I have not tested it: index 5acb53f..379ff13 100644
--- a/src/mobile-rr.ino
+++ b/src/mobile-rr.ino
@@ -573,13 +573,10 @@ void setupDNSServer()
dbg_printf ( "DNS Query [%d]: %s -> %s", remoteIP[3], domain, ipToString ( resolvedIP ).c_str() );
// connectivitycheck.android.com -> 74.125.21.113
- if ( strstr( "clients1.google.com|clients2.google.com|clients3.google.com|clients4.google.com|connectivitycheck.android.com|connectivitycheck.gstatic.com", domain ) )
- dnsd.overrideIP = IPAddress(74, 125, 21, 113);
-
- // dns.msftncsi.com -> 131.107.255.255
- if ( strstr(domain, "msftncsi.com") )
- dnsd.overrideIP = IPAddress(131, 107, 255, 255);
-
+ if ( strstr( "msftncsi.com|clients1.google.com|clients2.google.com|clients3.google.com|clients4.google.com|connectivitycheck.android.com|connectivitycheck.gstatic.com", domain ) ) {
+ dnsd.overrideIP = WiFi.softAPIP();
+ dnsd.overrideIP[3] += 10;
+ }
} );
dnsd.onOverride ( [] ( const IPAddress & remoteIP, const char *domain, const IPAddress & overrideIP )
{
@@ -596,7 +593,7 @@ void setupHTTPServer()
dbg_printf ( "Starting HTTP Captive Portal" );
// Handle requests
- httpd.on ( "/generate_204", onRequest ); //Android captive portal. Maybe not needed. Might be handled by notFound handler.
+ //httpd.on ( "/generate_204", onRequest ); //Android captive portal. Maybe not needed. Might be handled by notFound handler.
httpd.on ( "/fwlink", onRequest ); //Microsoft captive portal. Maybe not needed. Might be handled by notFound handler.
httpd.onNotFound ( onRequest );
@@ -1099,6 +1096,18 @@ void wifi_handle_event_cb ( System_Event_t *evt )
}
}
+void redirectRequest(AsyncWebServerRequest *request)
+{
+ String redirect_address = "http://wifi.manager.net";
+
+ AsyncWebServerResponse *response = request->beginResponse(307);
+ response->addHeader("X-Frame-Options", "deny");
+ response->addHeader("Cache-Control", "no-cache");
+ response->addHeader("Pragma", "no-cache");
+ response->addHeader("Location", redirect_address);
+ request->send(response);
+}
+
//***************************************************************************
// HTTPD onRequest *
//***************************************************************************
@@ -1116,26 +1125,9 @@ void onRequest ( AsyncWebServerRequest *request )
String path = request->url();
- if ( ( !SPIFFS.exists ( path ) && !SPIFFS.exists ( path + ".gz" ) ) || ( request->host() != "10.10.10.1" ) )
+ if ( ( !SPIFFS.exists ( path ) && !SPIFFS.exists ( path + ".gz" ) ) || ( request->host() != "10.10.10.1" && request->host() != "wifi.manager.net") )
{
- AsyncWebServerResponse *response = request->beginResponse ( 302, "text/plain", "" );
-// response->addHeader ( "Cache-Control", "no-cache, no-store, must-revalidate" );
-// response->addHeader ( "Pragma", "no-cache" );
-// response->addHeader ("Expires", "-1");
-// response->setContentLength (CONTENT_LENGTH_UNKNOWN);
- response->addHeader ( "Location", "http://10.10.10.1/index.htm" );
- request->send ( response );
-
- /* AsyncWebServerResponse *response = request->beginResponse(
- 511,
- "text/html",
- "<html><head><meta http-equiv='refresh' content='0; url=http://10.10.10.1/index.htm'></head></html>"
- );
- //response->addHeader("Cache-Control","no-cache");
- //response->addHeader("Pragma","no-cache");
- //response->addHeader ("Location", "http://10.10.10.1/index.htm" );
- request->send(response);
- */
+ redirectRequest(request);
}
else
{ |
@treii28 Here is how it works:
|
What devices are you testing on? It still doesn't work properly on my Samsung Galaxy S5. From my digging a modified lwip with port redirection is what is going to solve this issue for these older devices. |
I have a galaxy note 4. And I get what your code is trying to do. But if you are providing DNS responses for the generate_204 and other connect-check urls to ip addresses that your wifi isn't configured to answer, you can put as many redirect or other 'handle' methods in your webserver that you like. It's never going to receive the generate_204 request because the wifi isn't answering the requests for 74.125.21.13 or 131.107.255.255 |
As far as the code snippet above, it's doing little more than the original DNSServer was doing but adding extra conditionals that aren't really doing anything. (it's sending the softAP ip address whenever the generate_204 and other host urls are called which is what the original DNSServer code essentially did for 'everything') |
@treii28 |
From what I understand, those specific domains need to resolve via DNS to an IP address that is not on the local network and be unreachable. Then when the device tries to connect to that IP via port 80 or 443 the ESP8266 AP has to detect and redirect at that point to the localhost. If you look at the first answer on this post it describes what they did on a rPI to get it work correctly and consistently across a lot of different devices. I'm just trying to find a way to do the same. I think a modified lwip will give us the ability to do this kind of redirect. |
Just updated with some minor changes so it builds on the latest platform update and some tweaks. |
@idolpx |
Maybe I am not understanding the esp code then. Is it answering port 80 regardless of the target? I thought the AP configuration only grabbed traffic designated for it's configured IP so the webserver wouldn't ever even see the requests. EDIT: Lulz, i was going to post the link you had just posted above. I had it open in my browser yesterday before you posted it. |
BTW, if anyone can find any good resources on learning LWIP, I tried looking all over to get any kind of good doc on that library a few months back and couldn't find much. I struggle enough with C/C++. Trying to translate my limited knowledge of the TCP/IP stack into an undocumented library is probably beyond my skill/knowledge. But if I could find something that broke down the functionality, I might be able to duct tape something together. |
Ok, I found the issue with my previous patch, strstr was too greedy, it also returned fake for google.com, here is the new patch:
|
I noticed that too and just did a strcmp to see if the domain was "google.com" before checking for the override domains. It still didn't work on my test device. I'm working on a modified lwip now but not sure how to replace the one in the platformio framework for building the firmware. |
I've made a simple example at: https://github.com/drzony/captive_portal |
IT WORKS!!! For the first time in two years working on this issue on any android over v4.3 (kitkat) I got the pop-up redirect to finally work. I was asking in a facebook forum about the possibility of somehow configuring the esp8266 to answer additional addresses such as the overrides you are using or perhaps other DNS servers (such as the google default dns servers). Apparently the versions of Android from 4.3 through at least my version (v7) have either a behavior/feature or a bug where they will ask 8.8.8.8 for their generate_204 address by default. So you basically have to answer the DNS request on 8.8.8.8 or you won't be able to override it. I'll still keep asking around about configuring a second address, but for the time being this solution will work just fine for my geocaches and will probably work just fine for your mobile rick rolls. Configure your AP to use 8.8.8.8 and you'll get the pop-up helper with the redirect again. |
Holy hell... I got the popup when I tried this for the first time too on my Galaxy S5 but it tried to go to https://google.com by default and it doesn't get redirected to the portal page. @drzony I will try your project a when I get back this evening. Thanks for posting that. I'm almost done with the modified lwip but I don't know how to replace the one included with the framework in platformio yet. Still working on that. |
@drzony I had a few mins and went ahead and tried your project and I get the same results as mine. No popup helper on connect. But does redirect automatically when I browse manually like mine does. |
@idolpx I just noticed that you wrote https://google.com that means that it's trying to connect via https which is on port 443 not 80. If it's really SSL, then it will never work, since you won't be able to spoof the domain (you won't be able to get a signed server certificate for google.com, which is checked before redirect). I've seen this problem with several hotspots on older phones and the only thing to be done was manual visit to some http site. Maybe there is some weird way to redirect https to http without certificate, but it seems unlikely. |
This seems to be a major issue on Samsung devices. I wrote a captive portal library for Mongoose OS and have only had issues on Samsung Devices for some reason: Was reading through here hoping i could find some details as to why Samsung versions of android don't work with the standard 302 redirect -- even when I respond to all DNS requests with the AP IP address .. ugh. |
@tripflex |
Hey @ALL. On a Moto G XT1039 with Lineage-OS (14.1.20190207-NIGHTLY-peregrine) it works flawlessly with out modification of the code. |
[Sorry. Can not edit] And what OS doesn't work, too: Galaxy J5 SM-J500FN (Android 6.0.1 MMB29MJ500FNXXS1BQG1). |
...but: The captive portal advance from DNSServer examples works like a charm on my Galaxy J5 SM-J500FN (Android 6.0.1 MMB29MJ500FNXXS1BQG1). It calls the HTML output right after connecting the ESP8266 ap. 🤔 Is this a clue? |
@DE8MSH Could you try my example from https://github.com/drzony/captive_portal ? |
@drzony: Nope. But I don't use this platformio thingy dingy. I use Arduino IDE:
|
@29g The only difference is AP IP address (172.0.0.1), change 10.10.10.1 to 172.0.0.1 in line 142 and try to test it. I doubt it will work, but maybe something changed in Arduino for ESP. |
When connecting on an iOS or OSX device the captive portal is detected and a browser window pops up like it should to be able to accept the agreement and then get rick roll'd. It doesn't launch the browser window on Android though.
The text was updated successfully, but these errors were encountered: