Captive Portal not working on iOS devices only (DHCP 114)
-
I went through all your notes and advice, I have no problem getting a new/dedicated domain from Cloudflare, but I feel I'm very close to achieving what I want using the existing domain. Let Cloudflare be the last resort.
Out of curiosity, I went to a hotel nearby today where my laptop and Android device always get a secure connection and checked their Captive Portal certificate details, then applied what you guys suggested and compared it to this hotel's Captive Portal certificate that uses 2 SANs. One is the domain and one is the wildcard domain. Their URL also resolves to an internal IP. Here is a screenshot.
And here is mine
Anyway, I started from scratch, but when I was doing the Acme Certificate options, I didn't know what to put in the Server, Key, Key Name, and Algorithm. I appreciate your advice.
By the way. I used the LE's Production ACME V2 to register the ACME account key.Also, I got an error when I tried to issue/renew the certificate. Is there anything I need to do from the domain/registrar's side?
I also used afamiahotelresort.com for the Certificate's Common Name.
-
@basharsaba
You saw the difference ?
and
Btw :
update fail.
If you want more details : see the "more details".As you can see, the "CA" is also available. and afaik 'acme' would have stored it in the CA list if it is missing.
You know where it is, you could place it in there manually, if needed. -
Yes I saw the difference, Their Certification Hierarchy starts with a Certificate Authority which I'm missing.
In my particular situation, where am I supposed to create the Certificate Authority? Under System/Certificate/Authorities? If yes, Internal, intermediate, or import?
Or under ACME Certificates? What about the Key fields?
Here is the acme_issuecert.log.txt It's tooooooooo long and confusing. I couldn't spot the exact issue.
-
@basharsaba
I saw the log.
is wrong.
(stopped looking for more)The NS server here is the master domain name server.
Not optional or something.
The 'nsupdate' has to have an IP - this one :as that IP is my 'master domain name server' where the zone of the domain resides.
Your could be
[24.03-RELEASE][root@pfSense.bhf.tld]/root: dig afamiahotelresort.com NS +short ns203.canadianwebhosting.com. ns204.canadianwebhosting.com. [24.03-RELEASE][root@pfSense.bhf.tld]/root: dig ns204.canadianwebhosting.com A +short 104.36.151.152 [24.03-RELEASE][root@pfSense.bhf.tld]/root: dig ns203.canadianwebhosting.com A +short 104.36.151.151
This IP, the secret key and the algorithm type are made available to you be the domain registrar.
edit :
On the domain name server side, during the certificate renewal I showed above, I found this in the 'bind' logs :
07-Aug-2024 07:53:10.411 update: client @0x7ff5325d5070 82.127.26.108#55966/key update: updating zone '#####-hotel-fumel.net/IN': adding an RR at '_acme-challenge.#####-hotel-fumel.net' TXT "JLJQnIUFDoiQKHfN6iyFvHIuMMhF_-h7I5-mWcaZGX4" 07-Aug-2024 07:53:10.719 update-security: client @0x7ff5325d5070 82.127.26.108#65112/key update: signer "update" approved 07-Aug-2024 07:53:10.719 update: client @0x7ff5325d5070 82.127.26.108#65112/key update: updating zone '#####-hotel-fumel.net/IN': adding an RR at '_acme-challenge.#####-hotel-fumel.net' TXT "Rmcf8iJ7-R7joIpa_hEMgfYBm9jpt_YuSP3eyBjSfq4" 07-Aug-2024 07:55:17.432 update-security: client @0x7ff5325d5070 82.127.26.108#57576/key update: signer "update" approved 07-Aug-2024 07:55:17.432 update: client @0x7ff5325d5070 82.127.26.108#57576/key update: updating zone '#####-hotel-fumel.net/IN': deleting rrset at '_acme-challenge.#####-hotel-fumel.net' TXT 07-Aug-2024 07:55:17.596 update-security: client @0x7ff528513520 82.127.26.108#55196/key update: signer "update" approved 07-Aug-2024 07:55:17.596 update: client @0x7ff528513520 82.127.26.108#55196/key update: updating zone '#####-hotel-fumel.net/IN': deleting rrset at '_acme-challenge.#####-hotel-fumel.net' TXT 07-Aug-2024 07:55:38.455 update-security: client @0x7ff532233980 2a01:cb19:907:a600:92ec:77ff:fe29:392a#52512/key update: signer "update" approved
You can see that at 07h53:10 the two TXT fields are added under the sub domain "_acme-challenge".
Then there was the DNSsleep of two minutes.
The the two TXT fields are deleted / cleaned up.What also happens : as soon as the master zone is updated, the master DNS domain names servers signals the DNS slaves. As shown above, you have a master, and a slave.
These slave(s), when they see fit ( !! ) will contact the master and ask for a zone sync.
Only when is this done, Letsencrypt should start validating your domain, which is nothing more as checking if under _acme-challenge.afamiahotelresort.com exists, if there is a TXT field and if it contains the 'secret random' text string value that Letenscrypt gave to acme when it started.
Because I asked for a wild card cert, there are two TXT fields.
That's all that is needed to proof that YOU 'own' your domain.
As no one else could do this.I can see this log info as from the other side as I'm doing my own DNS stuff for my own domains ;: I run my own DNS servers (advise : don't do what I do).
-
A few questions:
-
In your SAN Table, you created 2 domain names. One is the main domain and one is the wildcard one. Does the zone need to match the domain name? I mean one zone is the main domain and the other one is the wildcard one?
-
Is the key for the SAN table the same SSL/TLS Certificate's Private Key that I have imported to Certificates, or am I supposed to look for another key?
-
I saw that you entered a Key Name. It's optional, shall I leave it blank or enter the domain name?
-
I couldn't find the Algorithm from the Registrar, so I chose the most common one SHA256
-
-
@basharsaba & @Gertjan
I am not replying to the questions asked but rather clarifying a few points and making observations:First, Let's Encrypt certificates through ACME support wildcard subdomains for the SAN list. I was not actually aware of that until now. It does not change anything, it just makes subdomain setup in the DNS easier and somewhat less secure if others have access to the DNS server setup. Specifying subdomains individually works just fine and you have control over which work. Your call when setting up your Let's Encrypt certificate in ACME.
Next, @Gertjan pointed out the certificate authorities associated with ACME, there appear to be 3 ACME related authorities. Of note is that the "external" one is NOT the one used for the certificate managed by the ACME package. The bottom one in Gertjan's screen capture is:
You can see that there is "1" certificate associated with it. This certificate is the one you will use for the Captive Portal https setup. The certificate is associated with the domain name, no subdomain is in play at all in the System, Certificates setup.
Now we look at @basharsaba 's original Certificate.
The two things of note here are- As stated previously, the Certificate includes the subdomain name which it should NOT include. It simply won't work as this is the security certificate which already includes the ability to handle wildcard subdomains in this case. It will force a second level domain resolution that is not supported.
- The issuer is listed as "external". This is wrong, it should be the Certificate Authority that is listed last as shown in @Gertjan 's image above but the exact syntax, in particular the CN=R?? part may change. In my opinion, this is why the original configuration was not working, the Certificate authority was wrong and thus failing for Captive Portal. This is why the Certificate Hierarchy is not correct, it simply doesn't exist. In the example below, the red should say "afamiahotelresort.com". The yellow will likely be different.
Lastly, the DNS setup points to the address of the captive portal, but it matters not how it came to do so, DNS server, Dynamic DNS or DNS Resolver Host Override. It is simply important that it resolve to the correct address pool that matches the DHCP associated with the Captive Portal. It has nothing to do with the certificate other than enabling that field in the SSL/TLS verification process to match on subdomain and Captive Portal to match on IP address.
Once the above configuration is achieved, I believe you will be operational.
-
@Gertjan @basharsaba
Sorry, I forgot one more suggestion. If you go to Services, ACME, General Settings, you can turn on the saving of all of your certificates to /conf/acme, including the authority. That way you can check the authority in System, Certificates, for both Authorities and Certificates:
I used the Authority certificate to create an authority for a second pfSense server on our network (I wanted https for webconfig on the second pfSense unit) and then pasted in the certificate using that authority, associating it with webconfig. I update it manually every time ACME renews the certificate itself which is a pain but of importance here, I re-created the configuration without configuring ACME itself and successfully enabled https. Thus Authority + Certificate is all that is needed to make https work on a subdomain.
-
Hello @EDaleH and @Gertjan, I have 50% good news.
So after numerous attempts of playing with the settings and troubleshooting the errors I was never able to get ACME to issue a certificate. I believe this is because we are not using the DNS from NameSilo (Registrar) but instead, we are using the DNS from the Canadian Web Hosting company. There wasn't enough room to play with the DNS settings or let's say the required parameters for the Domain SAN list in pfSense (Key, Token, Account, or Zone ID) were not available.
Long story short, I took your advice and purchased a brand new domain on Cloudflare (www.afamiahotelresort.net). As pfSesne already has DNS-CloudFlare listed, I was able to fill in the required fields and get the certificate issued.
I also enabled the 2 options (Cron Entry and Write Certificates).
The Certificate Authority and the Certificate were created automatically for the Wildcard domain.
You previously said I should have a subdomain.domain.tld that will be used for the Captive Portal. So I went to CloudFlare and created A record for pfsense.afamiahotelresort.net that is resolving to 192.168.1.1
I got an error when the Proxied option was enabled, so I had to disable it and the record was created as DNS only. Is this ok?
I went after that and changed all the other settings according to the new URL (Domain, DNS Server Settings (IP and Hostname), Captive Portal HTTPS Options, DHCP 114, DNS Resolver Host Overrides...etc but unfortunately, the connection to the Captive Portal page was still not secure.
Is it because I used the ACME Staging, not Production? I have to wait about a week to be able to re-issue a new Production Certificate because I have had a lot of failing ones.
Here are the new settings screenshots. Let me know why you think it's still not working.
DHCP 114 String is now "https://pfsense.afamiahotelresort.net:8003/rfc8910.php?zone=cpzone" -
@basharsaba said in Captive Portal not working on iOS devices only (DHCP 114):
Here are the new settings screenshots. Let me know why you think it's still not working.
DHCP 114 String is now "https://pfsense.afamiahotelresort.net:8003/rfc8910.php?zone=cpzone"As far as the general settings are concerned, there is no need for them to align with the domain you register. I don't think there is an issue though, it just might be a source of confusion when your pfSense firewall has the same name as your captive portal.
The DHCP114 string looks fine based on your previous setup info.
You need to move on from staging to the production environment for your certificate to work.
On Cloudflare you should have at least two records, afamiahotelresort.net pointed at your pfSense webconfigurator, and pfsense.afamiahotelresort.net pointed at the subnet of your captive portal. Yes, the proxy has to be off. Your SANs suggest you have that. For a "normal" setup using vlans, they would not be on the same subnet but it appears from prior communication from you that your captive portal is also on the default 192.168.1.1 subnet. That means the same DHCP server gives out addresses for your captive portal as for your LAN. It also means that all your visitors can launch the pfsense webconfigurator and only need to guess the user/pwrd to get in but as long as you are OK with that.....
For the DNS Resolver, I would put both SANs in there.
I would enable production at this stage and only then test it. It looks good from here.
-
@basharsaba said in Captive Portal not working on iOS devices only (DHCP 114):
You previously said I should have a subdomain.domain.tld that will be used for the Captive Portal. So I went to CloudFlare and created A record for pfsense.afamiahotelresort.net that is resolving to 192.168.1.1
I got an error when the Proxied option was enabled, so I had to disable it and the record was created as DNS only. Is this ok?
Perfectly ok.
You already asked and got a wild card certificate.
So "pfsense.afamiahotelresort.net" or "portal.afamiahotelresort.net" or "whatever.afamiahotelresort.net" is already accounted for.Um' not sure what you are doing here :
Where is this ?
On pfSense, there where "192.168.1.1" has a meaning (192.168.1.1 = RFC1918 = only locally and never 'on the Internet').
You should have :and your good.
@basharsaba said in Captive Portal not working on iOS devices only (DHCP 114):
Is it because I used the ACME Staging, not Production?
"Staging" is for testing. Useful as you can test the DNS API as long as you want.
Maybe it's time to actually read the Letsencrypt manuals, guidelines etc ??The "production" isn't good for testing, as you can only fail a couple of time, and then you have to wait for days to get a new cert.
-
I had to wait all this time until LE finally allowed me to issue a Production Certificate.
I want to update you that all the devices of all kinds are finally working without issues and getting a secure connection with a valid certificate. Having a dedicated domain on Cloudflare was a very wise idea.
I wouldn't be able to achieve that without your advice and assistance. You guys rock.
One last question. I have enabled Cron Entry. From your experience, will it really renew the certificate automatically after 90 days? Or am I still supposed to click the blue Issue/Renew button?
Apparently, the "Certificate renewal after" field doesn't matter at all because regardless of how many days I set, it's still 90 days as per LE.
-
@basharsaba
ACME will renew every 60 days and it works well with the default settings.
Congrats on your success.
-
@basharsaba said in Captive Portal not working on iOS devices only (DHCP 114):
From your experience, will it really renew the certificate automatically after 90 days? Or am I still supposed to click the blue Issue/Renew button?
Check the cron entry :
To see it, install; the pfSense Cron package first.
The need-to-renew-test runs every day, mine at : 03h16.
Now check the system log : to no surprise :Don't use '90' as a certificate renewal, but something between 30 and 60.
That leaves you with 60 to 30 days to resolve an issue IF something went wrong.
"90" will leave you with no spare time to resolve the issue.Btw : I'm using acme for years now, and it never failed. if it did, it was because the admin (me) was messing up again.
That said, free services or even when you pay for them : don't auto trust them, think about putting in place automated checks like this (very old munin based monitoring system). You can see that I check 2 domains there, and they are renewed after 30 days, and the other 60 days. Is like clock work. -
I've noticed something.
The scenario :
My PORTAL network :
192.168.2.1/24 - DHCP pool 192.168.6 -> 192.168.2.254
192.168.2.2, 3, 4, 5 = 4 APs with a static IP setup, DNS and gateway set to 192.168.2.1Normally, when I connect with my iPhone, I always get the same IPv4 : 192.168.1.6 because I created a DHCP MAC lease for my iPhone.
Now, when I add my IPv4 192.168.2.6 to the "allowed IP address" list :
I killed all Portal sessions, relaoded the Portal on pfSEnse, and then reconnected my iPhone.
I still got the login page ....It took me the better half of this morning that .... this is totally 'ok' as my iPhone, as soon as it receives a DHCP lease, it knows right away it has to go to
= "https://portal.xxx.net:8003/rfc8910.php?zone=cpzone1"
Before, when an IP was white listed like this, the portal became transparent for the device using that IP.
So, not really an issue, I was actually looking for a 'problem' that didn't exist.
Just : keep in mind that "rfc8910" method will not allow the bypass "allowed IP address" method.
edit : MAC list : probably same thing, didn't test yet.
-
Did you "forget" the iPhone "My Network"? I have noticed when testing RFC8910, DHCP 114 that it is/can be "sticky". As I switched between Kea and ISC, I had to remember to forget the old network on the iPhone, otherwise it appeared to be working under Kea when it actually had saved the login info from when it connected under ISC and received a 114 option, even though it got a different IP address. You can also switch "auto login" off and see if it has internet connectivity as that will prevent the captive portal page from loading, even if received via DHCP 114.
-
@EDaleH said in Captive Portal not working on iOS devices only (DHCP 114):
Did you "forget" the iPhone "My Network"?
Yep, did that, as part of the 'clean slate' approach.
@EDaleH said in Captive Portal not working on iOS devices only (DHCP 114):
I have noticed when testing RFC8910, DHCP 114 that it is/can be "sticky"
I have that impression also. Probably some iPhone side coding doing 'its' thing.
@EDaleH said in Captive Portal not working on iOS devices only (DHCP 114):
As I switched between Kea and ISC
I saw your discussion with marcos on Github about the upcoming kea implementation.
Progress is looking fine.@EDaleH said in Captive Portal not working on iOS devices only (DHCP 114):
You can also switch "auto login"
I'll experiment with that one
-
For the "rfc8910.php" file :
if (is_array($cpcfg['allowedip'])) { foreach ($cpcfg['allowedip'] as $ipent) { if ($ipent['ip'] == $clientip) { if ($ipent['dir'] != 'to') { // Bail out, 'clientip' is part of the 'allowedip' list ob_flush(); return; } } } }
If there is an array with "allowedips"
For each IP in the array,
If the IP of the portal c;lient matches an IP in the list,
And if the direction in not 'to' (thus 'both' or 'from'),
Then flush and return.This will take of he devices that are on the "allowed IP" list, they won't get login page anymore.
Take note : this works for 'English' portals. Afaik, the text 'from' 'to' and 'both' might be different for another languages.
-
@Gertjan said in Captive Portal not working on iOS devices only (DHCP 114):
This will take of he devices that are on the "allowed IP" list, they won't get login page anymore.
I confirmed that the same symptoms are present for "allowed IP" in Kea as I assume you were using ISC. I also confirmed that the fix works in Kea.
It is important to note that in order to have DHCP allocate a Static IP to a Mac address, that address must be outside the dynamic allocation pool for that portal's DHCP server.
It is also important to note that many devices change the MAC address every time you connect so you must turn off the "Private Wi-Fi Address" option on the iPhone for example. When you forget and add it again, it will reset to a dynamic Wi-Fi Address so the MAC will change and your static mapping will no longer be used.
The fix to RFC8910.php suggested simply prevents the device from intercepting the "capture" from the captive portal and it goes directly to the captive portal where it is allowed through, exactly as desired. There are negative consequences to this, first amongst them for me is that the "Open Captive Portal Page" option is not available on the iPhone for example. We use this to inform the client as to time, data quota, number of simultaneous users, time to automatic reset of account and potentially other important information (like logout) about their status. This is possible because DHCP 114 is sending the login URL to the captive portal every time you either log onto the Wi-Fi or click that option under the circled i on the iPhone for example. Captive portal will load the logout page if the device is already logged into the Captive Portal. Thus, we use the logout URL to provide this info. Once you bypass DHCP 114 through RFC8910.php this information will no longer be available. Loading the login URL manually will simply load the login page because, of course, a passed through IP is not logged in.
For this reason, thermostats, other IOT devices may use/need this feature but it is defeating the purpose of RFC8910 and must be applied for that reason, not to bypass the captive portal login screen. Once you are logged into the Captive Portal, you stay logged in until conditions are met to log you out automatically, time, data, etc. That is a preferred method of solving the problem of simply avoiding the login screen itself. Even for thermostats and other devices, they typically ignore RFC8910, DHCP 114 anyway and simply work by passing through their MAC address or an allowed IP in Captive Portal thus we never even noticed this issue to date. You preserve the login over a reboot by checking: Preserve users database ->Preserve connected users across reboot. If enabled, connected users won't be disconnected during a pfSense reboot.
-
Your last to phrases :
The fix to RFC8910.php suggested ...
and
For this reason, thermostats, ....
That's what I had in mind : 'thermostats', APs, smart switches and whatever other devices hosted on the portal network, these devices are typically white listed by using "Allowed IP" (and/or MAC probably) are mostly automates that don't know sh#t about portal login and/or don't use DHCP 114 (RFC8910) anyway - as you said already.
These devices won't consult the the portal's "venue-info-url" neither.The same type of filtering against the two "Allowed IP" and "MAC" lists isn't needed in the original portal's index.php
That said, devices have their MAC listed as "blocked" do inform the connected user with a message that his MAC is blocked (inviting him to change his MAC address ^^).Updated : I've also added MAC listed handling :
if (is_array($cpcfg['allowedip'])) { foreach ($cpcfg['allowedip'] as $ipent) { if ($ipent['ip'] == $clientip) { if ($ipent['dir'] != 'to') { // 'clientip' is part of the 'allowedip' list ob_flush(); return; } } } } $clientmac = pfSense_ip_to_mac($clientip); if (!is_array($clientmac)) { if (!isset($cpcfg['nomacfilter']) || isset($cpcfg['passthrumacadd'])) { /* unable to find MAC address - shouldn't happen! - bail out */ captiveportal_logportalauth("unauthenticated", "noclientmac", $clientip, "ERROR"); echo "An error occurred. Please check the system logs for more information."; log_error("Zone: {$cpzone} - Captive portal could not determine client's MAC address. Disable MAC address filtering in captive portal if you do not need this functionality."); ob_flush(); return; } } else if (is_array($cpcfg['passthrumac'])) { foreach ($cpcfg['passthrumac'] as $macent) { if ($macent['mac'] == $clientmac['macaddr']) { if ($macent['action'] == 'pass') { // 'clientmac' is part of the 'allowed MAC' list ob_flush(); return; } } } }
I took the initial MAC testing directly from the portal's 'index.php' file : if no MAC was found, but MAC usage isn't' disabled, then messages are logged/shown.
-
@Gertjan
Good Work, I tested the fix(es) under Kea/Plus 24.08 Dev (0925) and they work as advertised. I suggest you publish the full updated RFC8910.php here so others can quickly get the current result of this project to date.