Captive portal. Configuring ncsi redirect

I will give an example of setting up forwarding clients without money to the captive portal when connecting to the network.

Let’s say Nginx is installed, for example, as I described in the article Installing and Configuring Nginx. In practice, nginx uses less system resources and is faster than Apache2.

Let’s create a configuration file for customers who run out of money:

nano /etc/nginx/sites-enabled/page_credit

Add the following to the new file:

server {
        allow 10.0.0.0/8;
        allow 172.16.0.0/12;
        deny all;
        server_tokens off;

        listen 81;
        access_log off;

        root /var/www/81;
	index index.php;
        server_name _;

        location / {
            if ( $http_user_agent ~ ^uTorrent ) {
                            return 404;
            }
            if ( $http_user_agent ~ Windows-Update-Agent ) {
                            return 404;
            }
            if ( $http_user_agent ~ "Microsoft NCSI" ) {
                            return 302 https://captive.ixnfo.com;
            }
            if ( $http_user_agent ~ "ESS Update" ) {
                            return 404;
            }
            if ( $http_user_agent ~ "Google Update" ) {
                            return 404;
            }
            if ( $http_user_agent ~ "Microsoft-CryptoAPI" ) {
                            return 404;
            }
            if ( $http_user_agent ~ "Microsoft BITS" ) {
                            return 404;
            }
            if ( $http_user_agent ~ MSDW ) {
                            return 404;
            }
            if ( $http_user_agent ~ ^SeaPort ) {
                            return 404;
            }
            if ( $http_user_agent ~ ^Windows-Media-Player ) {
                            return 404;
            }
            if ( $http_user_agent ~ "Google Update" ) {
                            return 404;
            }
            if ( $http_user_agent ~ ^GoogleEarth ) {
                            return 404;
            }
            if ( $http_user_agent ~ ^Skype ) {
                            return 404;
            }
            if ( $http_user_agent = "MailRuSputnik" ) {
                            return 404;
            }
            if ( $http_user_agent ~ ^Ya\.Online ) {
                            return 404;
            }
            if ( $http_user_agent ~ ^MRA ) {
                            return 404;
            }
            if ( $http_user_agent ~* ^MediaGet ) {
                            return 404;
            }
            if ( $http_user_agent ~ ^BTWebClient ) {
                            return 404;
            }
            if ( $http_user_agent ~ ^Syncer ) {
                            return 404;
            }
            if ( $http_user_agent = "TMUFE" ) {
                            return 404;
            }
            if ( $http_user_agent ~ ^Akamai\ NetSession\ Interface ) {
                            return 404;
            }
            if ( $http_user_agent ~ ^VKSaver ) {
                            return 404;
            }
            if ( $http_user_agent ~ DrWebUpdate ) {
                            return 404;
            }
            if ( $http_user_agent = "" ) {
                            return 404;
            }
            if ( $host ~ geo\.kaspersky\.com ) {
                            return 404;
            }
            if ( $host ~ (su|download|webrep).*\.avast\.com ) {
                            return 404;
            }
            if ( $host = wi2geo.mobile.yandex.net ) {
                            return 404;
            }
            if ( $host ~ bar.*\.yandex\.ru ) {
                            return 404;
            }
            if ( $host ~ (ping|master)\d*\.(dyngate|teamviewer)\.com ) {
                            return 404;
            }
            if ( $host ~ sitecheck\d*\.opera\.com ) {
                            return 404;
            }
            if ( $host ~ (xml\.my|mailsputnik|maps)\.mail\.ru ) {
                            return 404;
            }
            if ( $host = onlineconfigservice.ubi.com ) {
                            return 404;
            }
            if ( $host = com-services.pandonetworks.com ) {
                            return 404;
            }
            if ( $host ~ ticno\.com ) {
                            return 404;
            }
            if ( $host ~ conduit ) {
                            return 404;
            }
            if ( $host ~ cbox\.ws ) {
                            return 404;
            }
            if ( $host ~ (pricelist|metrics)\.skype\.com ) {
                            return 404;
            }
            if ( $host = weather.service.msn.com ) {
                            return 404;
            }
            if ( $host = advstat.letitbit.net ) {
                            return 404;
            }
            if ( $host = skymonk.net ) {
                            return 404;
            }
            if ( $host ~ counter ) {
                            return 404;
            }
            if ( $host ~ pluraserver ) {
                            return 404;
            }
            if ( $host ~ apps.bittorrent.com ) {
                            return 404;
            }
            if ( $host ~ tracker ) {
                            return 404;
            }
            if ( $request_uri ~* (update|feed|announce|rss|xml|json|oauth) ) {
                            return 404;
            }
            if ( $request_uri ~* (toolbar|suggest) ) {
                            return 404;
            }
            if ( $request_filename ~ \.(ico|gif|jpg|png) ) {
                            return 404;
            }
            if ( $request_filename ~ \.(css|xml|js|swf|flv) ) {
                            return 404;
            }
            if ( $request_filename ~ \.(crl|txt|cab|msi|jar) ) {
                            return 404;
            }
            if ( $host ~ norton ) {
                            return 404;
            }
            rewrite ^ https://captive.ixnfo.com/ redirect;
        }
location ~ \.php$ {
                try_files $uri =404;
                include /etc/nginx/fastcgi_params;
                fastcgi_pass unix:/var/run/php5-fpm.sock;
        }
    }

I created a page with text on another server, and I added the contents to the /var/www/81/index.php file:

<?php
    header('Content-Type: text/html; charset=cp1251');
    http_response_code(511);
?>
<html>
<head>
<meta http-equiv="pragma" content="no-cache">
<meta http-equiv="cache-control" content="no-cache">
<meta http-equiv="Refresh" content="1;URL=https://captive.ixnfo.com">
</head>
No payment
</html>

Let’s create a configuration file for unknown clients:

nano /etc/nginx/sites-enabled/unknown_clients

Add to it:

server {
        allow 10.0.0.0/8;
        allow 10.55.56.0/24;
        deny all;
        server_tokens off;

        listen 82;
        access_log off;
        #access_log /var/log/nginx/unknown.access.log;
        root /var/www/82/;
        index index.php;
        server_name test_ixnfo;
        add_header Cache-Control no-cache;
        #expires 0;

        location / {
            if ( $http_user_agent ~ ^uTorrent ) {
                            return 404;
            }
            if ( $http_user_agent ~ Windows-Update-Agent ) {
                            return 404;
            }
            if ( $http_user_agent ~ "Microsoft NCSI" ) {
                            return 302 http://192.168.2.2:82/index.php;
            }
            if ( $http_user_agent ~ "ESS Update" ) {
                            return 404;
            }
            if ( $http_user_agent ~ "Google Update" ) {
                            return 404;
            }
            if ( $http_user_agent ~ "Microsoft-CryptoAPI" ) {
                            return 404;
            }
            if ( $http_user_agent ~ "Microsoft BITS" ) {
                            return 404;
            }
            if ( $http_user_agent ~ MSDW ) {
                            return 404;
            }
            if ( $http_user_agent ~ ^SeaPort ) {
                            return 404;
            }
            if ( $http_user_agent ~ ^Windows-Media-Player ) {
                            return 404;
            }
            if ( $http_user_agent ~ "Google Update" ) {
                            return 404;
            }
            if ( $http_user_agent ~ ^GoogleEarth ) {
                            return 404;
            }
            if ( $http_user_agent ~ ^Skype ) {
                            return 404;
            }
            if ( $http_user_agent = "MailRuSputnik" ) {
                            return 404;
            }
            if ( $http_user_agent ~ ^Ya\.Online ) {
                            return 404;
            }
            if ( $http_user_agent ~ ^MRA ) {
                            return 404;
            }
            if ( $http_user_agent ~* ^MediaGet ) {
                            return 404;
            }
            if ( $http_user_agent ~ ^BTWebClient ) {
                            return 404;
            }
            if ( $http_user_agent ~ ^Syncer ) {
                            return 404;
            }
            if ( $http_user_agent = "TMUFE" ) {
                            return 404;
            }
            if ( $http_user_agent ~ ^Akamai\ NetSession\ Interface ) {
                            return 404;
            }
            if ( $http_user_agent ~ ^VKSaver ) {
                            return 404;
            }
            if ( $http_user_agent ~ DrWebUpdate ) {
                            return 404;
            }
            if ( $http_user_agent = "" ) {
                            return 404;
            }
            if ( $host ~ geo\.kaspersky\.com ) {
                            return 404;
            }
            if ( $host ~ (su|download|webrep).*\.avast\.com ) {
                            return 404;
            }
            if ( $host = wi2geo.mobile.yandex.net ) {
                            return 404;
            }
            if ( $host ~ bar.*\.yandex\.ru ) {
                            return 404;
            }
            if ( $host ~ (ping|master)\d*\.(dyngate|teamviewer)\.com ) {
                            return 404;
            }
            if ( $host ~ sitecheck\d*\.opera\.com ) {
                            return 404;
            }
            if ( $host ~ (xml\.my|mailsputnik|maps)\.mail\.ru ) {
                            return 404;
            }
            if ( $host = onlineconfigservice.ubi.com ) {
                            return 404;
            }
            if ( $host = com-services.pandonetworks.com ) {
                            return 404;
            }
            if ( $host ~ ticno\.com ) {
                            return 404;
            }
            if ( $host ~ conduit ) {
                            return 404;
            }
            if ( $host ~ cbox\.ws ) {
                            return 404;
            }
            if ( $host ~ (pricelist|metrics)\.skype\.com ) {
                            return 404;
            }
            if ( $host = weather.service.msn.com ) {
                            return 404;
            }
            if ( $host = advstat.letitbit.net ) {
                            return 404;
            }
            if ( $host = skymonk.net ) {
                            return 404;
            }
            if ( $host ~ counter ) {
                            return 404;
            }
            if ( $host ~ pluraserver ) {
                            return 404;
            }
            if ( $host ~ apps.bittorrent.com ) {
                            return 404;
            }
            if ( $host ~ tracker ) {
                            return 404;
            }
            if ( $request_uri ~* (update|feed|announce|rss|xml|json|oauth) ) {
                            return 404;
            }
            if ( $request_uri ~* (toolbar|suggest) ) {
                            return 404;
            }
            if ( $request_filename ~ \.(ico|gif|jpg|png) ) {
                            return 404;
            }
            if ( $request_filename ~ \.(css|xml|js|swf|flv) ) {
                            return 404;
            }
            if ( $request_filename ~ \.(crl|txt|cab|msi|jar) ) {
                            return 404;
            }
            if ( $host ~ norton ) {
                            return 404;
            }
            rewrite ^ http://192.168.2.2:82/index.php redirect;
        }

location ~ \.php$ {
                try_files $uri =404;
                include /etc/nginx/fastcgi_params;
                fastcgi_pass unix:/var/run/php5-fpm.sock;
        }

}

The file /var/www/82/index.php I created this type:

<html>
<head>
...
<p class='alert-text' style='color:red;'>
Your device is not registered in the system<br>
and received a temporary ip address, if necessary, inform its operator</p><br>
<b><p class='alert-text' style='color:red; font-size:140%;'><?php echo $_SERVER["REMOTE_ADDR"]; ?></b></p><br>
<a href='https://test.ixnfo.com/'>LINK</a><br>
<p class='alert-text'><b>Support:</b><br>
XX-XX-XX, ... <br>
<b>Administration ...</b><br><br></p>
...

Since I used ipset for debtors on the access server, for this ipset we redirect http requests via iptables, allow access to the server with nginx, billing and dns server, and everything else is forbidden:

/sbin/ipset create denyip iphash
/sbin/iptables -t nat -A PREROUTING -p tcp -m multiport --dport 80 -m set --match-set denyip src -j DNAT --to-destination 192.168.5.5:81
/sbin/iptables -A FORWARD -m set --match-set denyip src -d 192.168.5.5 -p tcp --dport 81 -j ACCEPT
/sbin/iptables -A FORWARD -m set --match-set denyip src -d 192.168.5.5 -p tcp --dport 443 -j ACCEPT
/sbin/iptables -A FORWARD -m set --match-set denyip src -d 192.168.2.2 -p tcp --dport 9443 -j ACCEPT
/sbin/iptables -A FORWARD -m set --match-set denyip src -d 192.168.2.2 -p tcp --dport 53 -j ACCEPT
/sbin/iptables -A FORWARD -m set --match-set denyip src -d 192.168.2.2 -p udp --dport 53 -j ACCEPT
/sbin/iptables -A FORWARD -m set --match-set denyip src -j DROP

Or if guest clients are given separate IP addresses, then instead of ipset we will indicate the network:

iptables -t nat -A PREROUTING -s 10.0.56.0/24 -p tcp -m tcp --dport 80 -j DNAT --to-destination 192.168.5.5:81

I will briefly describe the process:

Windows when connecting to the network under “http_user_agent=Microsoft NCSI” tries to open the page http://www.msftncsi.com/ncsi.txt which contains the text Microsoft NCSI and receives the status 200 OK, and also checks the DNS server – determines the IP address for dns.msftncsi.com, which should be 131.107.255.255.
If the link opened and DNS answered correctly, then the system considers that there is an Internet connection, if the link is not available, and DNS answered correctly – the system considers that it is necessary to log in and opens our captive portal in the browser.
All these parameters are stored in the registry HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\NlaSvc\Parameters\Internet, and you can also disable this check by specifying 0 for EnableActiveProbing.

Apple, when connected to the network, tries to open http://captive.apple.com/hotspot-detect.html twice, expects to receive the text “Success” in the caption and body of the page. The first time trying under “http_user_agent=CaptiveNetworkSupport…”.

In nginx logs you can see the following entries:

“GET /connecttest.txt HTTP/1.1” 301 178 “-” “Microsoft NCSI”
“GET /ncsi.txt HTTP/1.1” 301 178 “-” “Microsoft NCSI”
“GET /hotspot-detect.html HTTP/1.0” 302 154 “-” “CaptiveNetworkSupport-355.260.2 wispr”
“GET /generate_204 HTTP/1.1” 301 178 “-” “Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/52.0.2743.82 Safari/537.36”

Similarly on Apache2 using .htaccess you can do so:

RewriteEngine on
ErrorDocument 404 http://192.168.5.5:81/index.php

Also, so that search engines do not index the page, you can create a robots.txt file with the contents:

User-agent: *
Disallow: /

Sometimes I saw errors in the logs that there is no favicon.ico file, so you can also add it.

And also I recommend using iptables to restrict access to the page only for local networks.

See also my article:
IPTables rules for the web server
Ubuntu IP Masquerading (NAT)

Leave a comment

Leave a Reply