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

Android Captive Portal Helper isn't triggered. #2

Open
idolpx opened this Issue Jul 9, 2016 · 79 comments

Comments

Projects
None yet
@idolpx
Copy link
Owner

idolpx commented Jul 9, 2016

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.

@ratmandu

This comment has been minimized.

Copy link

ratmandu commented Aug 12, 2016

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?

@idolpx

This comment has been minimized.

Copy link
Owner Author

idolpx commented Aug 15, 2016

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.

@Starbix

This comment has been minimized.

Copy link

Starbix commented Aug 19, 2016

The captive portal also doesn't work for me although I'm on iOS. Is it possible that it's broken on iOS 10?
Edit: It seems to work with dev beta 7 / public beta 6

@idolpx

This comment has been minimized.

Copy link
Owner Author

idolpx commented Aug 20, 2016

I don't have an iOS 10 device but will see what I can come up with to test with.

@Starbix

This comment has been minimized.

Copy link

Starbix commented Aug 20, 2016

It just worked once for iOS 10, while it works again if I renew my release in iOS 9

@Noki

This comment has been minimized.

Copy link
Contributor

Noki commented Aug 20, 2016

Please check if my pull request fixes it: #10

@idolpx

This comment has been minimized.

Copy link
Owner Author

idolpx commented Aug 21, 2016

Hmmm... still the same for me on my Android device but if it fixed it for you I'll merge it.
Thanks.

@Starbix

This comment has been minimized.

Copy link

Starbix commented Aug 21, 2016

This doesn't fix it for iOS 10

@Noki

This comment has been minimized.

Copy link
Contributor

Noki commented Aug 21, 2016

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:

dnsd.setTTL(0);

And the caching directives could be set using something like this:

AsyncWebServerResponse *response = request->beginResponse(302);
response->addHeader("Cache-Control","no-cache");
response->addHeader("Pragma","no-cache");
response->addHeader ("Location", "http://10.10.10.1/" );
request->send(response);

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.

@idolpx

This comment has been minimized.

Copy link
Owner Author

idolpx commented Aug 27, 2016

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.

@Starbix

This comment has been minimized.

Copy link

Starbix commented Aug 27, 2016

It looks like it works on iOS 10 (dev beta 8/ public beta 7) now.

@idolpx

This comment has been minimized.

Copy link
Owner Author

idolpx commented Aug 27, 2016

Oh great! Thanks for the feedback.

@tpmodding

This comment has been minimized.

Copy link

tpmodding commented Oct 11, 2016

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]
platform = espressif8266
board = nodemcuv2
framework = arduino
build_flags = -ULWIP_OPEN_SRC -Wl,-Tesp8266.flash.4m.ld

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 :/

@treii28

This comment has been minimized.

Copy link

treii28 commented Sep 19, 2017

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.
/ core / java / android / net / CaptivePortalTracker.java

@treii28

This comment has been minimized.

Copy link

treii28 commented Sep 23, 2017

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 see they have an lwip implementation in the esp8266 code and some of the libraries (including ESPAsyncTCP) use it for some of their protocol handling. Maybe there's some way in there (it's a tad beyond my skill level at the moment, but I'm trying to find resources to learn as much as I can about it) that could help?

@idolpx

This comment has been minimized.

Copy link
Owner Author

idolpx commented Jan 5, 2018

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.
https://socifi-doc.atlassian.net/wiki/spaces/SC/pages/94371841/DNS+Workaround+to+keep+Android+Splash+Page+and+the+Captive+Portal+Notification+active

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.

@drzony

This comment has been minimized.

Copy link

drzony commented Feb 8, 2018

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).
The problem seems to be limited to Samsung devices. I have S7 edge and have no luck with pop-up (only "Internet may not be available" shows). On my Tab Pro with Cyanogen installed it works as intended.
It seems that my phone does not request /generate204 from web server (nor does it make any other requests). I've looked into AOSP code and it should visit those URLs, so it seems that Samsung has changed the way that CP detection works.
Still I was not able to determine what triggers the pop-up on my phone. Maybe there is some IP whitelist and/or some special DNS answer required.

@idolpx

This comment has been minimized.

Copy link
Owner Author

idolpx commented Feb 17, 2018

Did you try to implement DNS Option 160 in your custom DNS code? I'm curious if that would activate the CP Helper.

@drzony

This comment has been minimized.

Copy link

drzony commented Feb 17, 2018

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.

@idolpx

This comment has been minimized.

Copy link
Owner Author

idolpx commented Feb 18, 2018

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.

http://community.arubanetworks.com/t5/Technology-Blog/RFC-7710-Captive-Portal-Identification-Using-DHCP-or-Router/ba-p/255737

@drzony

This comment has been minimized.

Copy link

drzony commented Feb 18, 2018

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
Captive portal is only a small part of my project, so checking this out will take some time (and I wonder if it's worth the effort)

@ChrisSteinbach

This comment has been minimized.

Copy link

ChrisSteinbach commented Apr 17, 2018

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.

@idolpx

This comment has been minimized.

Copy link
Owner Author

idolpx commented May 10, 2018

Oh shoot... ok. Thanks for trying it out and letting us know.
This bugs me every time I think about it. It has been a while.
Getting this working consistently across all devices would be the icing on the cake for the project.

@vidharv

This comment has been minimized.

Copy link

vidharv commented Aug 16, 2018

Did you guys manage to get it working!??

@idolpx

This comment has been minimized.

Copy link
Owner Author

idolpx commented Aug 25, 2018

I have not looked at it again in a long time. Still an open issue until we find a solution.

@Marfjeh

This comment has been minimized.

Copy link
Contributor

Marfjeh commented Oct 9, 2018

I got it working!

there are some commeted out lines on mobile-rr.ino line 576 ish..

remove the comments and adding

                if ( strstr(domain, "connectivitycheck.gstatic.com") )
                    dnsd.overrideIP =  IPAddress(74, 125, 21, 113);
                // connectivitycheck.android.com -> 74.125.21.113
                if ( strstr(domain, "connectivitycheck.android.com") )
                    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);

It works! it seems my phone (s7 edge) was sending the request to connectivitycheck.gstatic.com not to connectivitycheck.android.com

I also enabled dnsd.setTTL(0);

@Noki

This comment has been minimized.

Copy link
Contributor

Noki commented Oct 10, 2018

@Marfjeh Good job! Do you send in a pull request for all the lazy people? ;-)

@Marfjeh

This comment has been minimized.

Copy link
Contributor

Marfjeh commented Oct 10, 2018

Sure. i'll fork the project

@drzony

This comment has been minimized.

Copy link

drzony commented Feb 25, 2019

I finally managed to make it work, it turns out that DNS redirects for:

  • clients3.google.com
  • clients.l.google.com
  • connectivitycheck.android.com
  • connectivitycheck.gstatic.com
  • play.googleapis.com

need to be answered with invalid address e.g. 192.168.4.11 (if softAPIP is 192.168.4.1)
I've just verified that this works, but it needs custom DNS server, because the one that is included in ESP Arduino lib always answers with single IP.

@idolpx

This comment has been minimized.

Copy link
Owner Author

idolpx commented Feb 25, 2019

I put in a callback so you can override the IP address being returned from DNS. But from what I was finding it has to be a non-local IP address and you also have to override all connections to port 80 on any IP and direct them to the softAPIP to get it to work correctly.

I will try this though and see if it works for me too. :) Thanks for the feedback.
This one has been bugging me for a long time.

@drzony

This comment has been minimized.

Copy link

drzony commented Feb 26, 2019

You do not need IP redirection. Here is my exact setup that works:

  1. DNS server answering with:
IPAddress dest_address = WiFi.softAPIP();

if (strcmp(label, "clients3.google.com") == 0 || strcmp(label, "clients.l.google.com") == 0 ||
    strcmp(label, "connectivitycheck.android.com") == 0 ||
    strcmp(label, "connectivitycheck.gstatic.com") == 0 ||
    strcmp(label, "play.googleapis.com") == 0) {
    dest_address[3] += 10;
}
  1. HTTP server redirecting "notFound" and everything that is not meant for "myhost.manager.net" to "http://myhost.manager.net", with the following redirect:
if (request->host() != "myhost.manager.net" && request->host() != WiFi.softAPIP().toString()) {
    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", "http://myhost.manager.net");
    request->send(response);
}

And that's all that is needed.

@treii28

This comment has been minimized.

Copy link

treii28 commented Mar 6, 2019

Let me know as soon as there is something final to try out. I would love to get that project down off the 'waiting for resolution' shelf.
In the meantime I'll play with the recent suggestions. Maybe I'll get lucky.

@treii28

This comment has been minimized.

Copy link

treii28 commented Mar 6, 2019

@drzony is your dnsserver code posted anywhere?

@drzony

This comment has been minimized.

Copy link

drzony commented Mar 6, 2019

Not yet, it's part of a bigger project and it will take a while to release, you can modify included DNSServer in line

( _domainName == "*" || getDomainName() == _domainName )

Just add comparisons with addresses from my comment and then add replyWithFakeIp()

@treii28

This comment has been minimized.

Copy link

treii28 commented Mar 7, 2019

but isn't _domainName in that instance the one specified when the server instance is created? It appears to me the UDP _buffer is what is going to contain the incoming request but it's going to be in the raw UDP packet format (with the domain name started at I believe position 13 -- thus the +12 offset in the code)

Edit: OH wait, duh - ok, your custom dns server isn't removing the prefix. Gotcha - ok, thanks. I'll take a look at that later. I had the regular one open in another window which was why I was confused.

@treii28

This comment has been minimized.

Copy link

treii28 commented Mar 7, 2019

btw, if you control your own code and always plan to use low 4th digit ips, you should be fine, but I'd probably do something like this:

if(dest_address[3] < 244)
dest_address[3] += 10;
else
dest_address[3] -= 10;

(255 is broadcast so you want to fall on 254 or below)

@drzony

This comment has been minimized.

Copy link

drzony commented Mar 8, 2019

@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.
As for you code, if you are using DNSServer from this repo you can provide callback to onOverride and change the address there (sorry for the confusion, I did not notice earlier that the callback option was already added)

@treii28

This comment has been minimized.

Copy link

treii28 commented Mar 8, 2019

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.

@treii28

This comment has been minimized.

Copy link

treii28 commented Mar 8, 2019

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.

@treii28

This comment has been minimized.

Copy link

treii28 commented Mar 8, 2019

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?

@drzony

This comment has been minimized.

Copy link

drzony commented Mar 8, 2019

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
     {
@drzony

This comment has been minimized.

Copy link

drzony commented Mar 8, 2019

@treii28 Here is how it works:

  1. DNS responds with invalid IP for "check" hosts
  2. The phone tries to connect and when it fails it looks for sign-in page via HTTP
  3. DNS redirects all other addresses to APIP
  4. If the request is for 10.10.10.1 or wifi.manager.net - WebServer serves RR
  5. All other HTTP requests are redirected to wifi.manager.net
@idolpx

This comment has been minimized.

Copy link
Owner Author

idolpx commented Mar 13, 2019

What devices are you testing on? It still doesn't work properly on my Samsung Galaxy S5.
A lot of devices work with just responding to all DNS requests with the AP IP Address.

From my digging a modified lwip with port redirection is what is going to solve this issue for these older devices.
I just haven't figured out how to use a different lwip with the napt feature in this project yet.

@treii28

This comment has been minimized.

Copy link

treii28 commented Mar 13, 2019

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

@treii28

This comment has been minimized.

Copy link

treii28 commented Mar 13, 2019

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')

@drzony

This comment has been minimized.

Copy link

drzony commented Mar 13, 2019

@treii28
I'm using Note 9 and only after changing the responses it started to work (it's on my own code, so I'm not sure that my patch above is enough, my DNS server sticks to spec better). I'll have esp8266 setup on the weekend, so maybe I'll have time to make a PoC on it and send you some example for testing. The whole idea here is that on pure Android it's enough to return 404 on generate_204 (I have verified this on my tablet) on Samsung phones the connectivity addresses have to be unreachable, that is what my patch does on DNS. The other part is HTTP redirection, which allows the sign-in page to work.

@idolpx

This comment has been minimized.

Copy link
Owner Author

idolpx commented Mar 13, 2019

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.

https://unix.stackexchange.com/questions/432190/why-isnt-androids-captive-portal-detection-triggering-a-browser-window

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.

@idolpx

This comment has been minimized.

Copy link
Owner Author

idolpx commented Mar 13, 2019

Just updated with some minor changes so it builds on the latest platform update and some tweaks.

@drzony

This comment has been minimized.

Copy link

drzony commented Mar 14, 2019

@idolpx
I don't think port redirection is required. I'll make a separate "Hello world" project on the weekend, since your code has a lot of other functionality that may interfere. I think I'll be able to do this on original DNS server code with only slight modifications

@treii28

This comment has been minimized.

Copy link

treii28 commented Mar 14, 2019

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.

@treii28

This comment has been minimized.

Copy link

treii28 commented Mar 14, 2019

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.

@29G

This comment has been minimized.

Copy link

29G commented Mar 14, 2019

Hello,
I've noticed that when using the old repo files from 2018 before the latest commits (https://github.com/idolpx/mobile-rr/tree/41841a67682127afd9d283569e4a7065b8143178) the captive portal does work on my Oreo Samsung. A few seconds after connecting a page opens and i get "sign-in to network" prompt. But i couldn't flash the SPIFFS on the old version for some reason so i couldn't test the rickroll.

With the latest commits, there is no captive portal "sign in to network" anymore. Neither on iOS or Android. The SPIFFS flash does work and the rickroll works when i manually go to 192.168.4.1

@drzony

This comment has been minimized.

Copy link

drzony commented Mar 14, 2019

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:

diff --git a/src/mobile-rr.ino b/src/mobile-rr.ino
index 1fb4e70..127e603 100644
--- a/src/mobile-rr.ino
+++ b/src/mobile-rr.ino
@@ -573,17 +573,26 @@ void setupDNSServer()
     {
         dbg_printf ( "DNS Query [%d]: %s -> %s", remoteIP[3], domain, ipToString ( resolvedIP ).c_str() );
 
-        // connectivitycheck.android.com -> 74.125.21.113, 172.217.21.67
-        //if ( strstr( "clients1.google.com|clients2.google.com|clients3.google.com|clients4.google.com|clients.l.google.com|connectivitycheck.android.com|connectivitycheck.gstatic.com|android.clients.google.com|play.googleapis.com", domain ) )
-        //    dnsd.overrideIP =  IPAddress(172, 217, 21, 67);
-
-        // 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|clients.l.google.com|connectivitycheck.android.com|connectivitycheck.gstatic.com|android.clients.google.com|play.googleapis.com", domain ) )
-        //    dnsd.overrideIP =  IPAddress(ip[0], ip[1], ip[2], ip[3]+10);
-
+        const char *domains[] = {
+            "msftncsi.com",
+            "clients1.google.com",
+            "clients2.google.com",
+            "clients3.google.com",
+            "clients4.google.com",
+            "connectivitycheck.android.com",
+            "connectivitycheck.gstatic.com",
+            "clients.l.google.com",
+            "play.googleapis.com",
+            NULL
+        };
+        size_t i = 0;
+        bool fake = false;
+        while (domains[i]) {
+            if (strcmp(domain, domains[i]) == 0) {
+                dnsd.overrideIP = WiFi.softAPIP();
+                dnsd.overrideIP[3] += 10;
+            }
+        }
     } );
     dnsd.onOverride ( [] ( const IPAddress & remoteIP, const char *domain, const IPAddress & overrideIP )
     {
@idolpx

This comment has been minimized.

Copy link
Owner Author

idolpx commented Mar 14, 2019

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.

@drzony

This comment has been minimized.

Copy link

drzony commented Mar 15, 2019

I've made a simple example at: https://github.com/drzony/captive_portal
I've tested it on ESP32, but it should work on ESP8266.
@idolpx Could you verify it on your setup?

@treii28

This comment has been minimized.

Copy link

treii28 commented Mar 15, 2019

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).
He made a suggestion that is so braindead stupid, I'm kicking myself for not thinking of it myself. It may not work for all applications, but if you do not intend to connect your device to the internet anyway, just set your ap's address to the google primary dns address (8.8.8.8).

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.

@idolpx

This comment has been minimized.

Copy link
Owner Author

idolpx commented Mar 15, 2019

IT WORKS!!!
.....
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.

@idolpx

This comment has been minimized.

Copy link
Owner Author

idolpx commented Mar 15, 2019

@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.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
You can’t perform that action at this time.