mirror of
https://github.com/iiab/iiab.git
synced 2025-03-09 15:40:17 +00:00
Merge pull request #870 from jvonau/cap1
tweaking iptables for captive portal
This commit is contained in:
commit
dae24949d8
9 changed files with 179 additions and 6 deletions
|
@ -71,3 +71,10 @@ named_enabled: True
|
||||||
dnsmasq_enabled: False
|
dnsmasq_enabled: False
|
||||||
dnsmasq_install: False
|
dnsmasq_install: False
|
||||||
captive_portal_enabled: False
|
captive_portal_enabled: False
|
||||||
|
|
||||||
|
# for simple python captive portal
|
||||||
|
py_captive_portal_install: True
|
||||||
|
py_captive_portal_enabled: True
|
||||||
|
py_captive_portal_port: "9090"
|
||||||
|
py_captive_portal_username: "Admin"
|
||||||
|
py_captive_portal_password: "changeme"
|
||||||
|
|
37
roles/network/tasks/captive_portal.yml
Normal file
37
roles/network/tasks/captive_portal.yml
Normal file
|
@ -0,0 +1,37 @@
|
||||||
|
- name: Create directory for captive portal script
|
||||||
|
file: path=/opt/iiab/captive-portal state=directory
|
||||||
|
when: py_captive_portal_install
|
||||||
|
|
||||||
|
- name: Copy captive portal script
|
||||||
|
template:
|
||||||
|
src: roles/network/templates/captive_portal/captive_portal.py.j2
|
||||||
|
dest: /opt/iiab/captive-portal/captive_portal.py
|
||||||
|
owner: root
|
||||||
|
group: root
|
||||||
|
mode: 0740
|
||||||
|
when: py_captive_portal_install
|
||||||
|
|
||||||
|
- name: Copy captive portal service file
|
||||||
|
template:
|
||||||
|
src: roles/network/templates/captive_portal/captive_portal.service.j2
|
||||||
|
dest: /etc/systemd/system/captive_portal.service
|
||||||
|
owner: root
|
||||||
|
group: root
|
||||||
|
mode: 0644
|
||||||
|
when: py_captive_portal_install
|
||||||
|
|
||||||
|
- name: Enable captive_portal after copying files
|
||||||
|
service: name=captive_portal.service enabled=yes
|
||||||
|
when: py_captive_portal_install and py_captive_portal_enabled
|
||||||
|
|
||||||
|
- name: Start captive_portal after copying files
|
||||||
|
service: name=captive_portal.service state=started
|
||||||
|
when: py_captive_portal_install and py_captive_portal_enabled
|
||||||
|
|
||||||
|
- name: Disable captive_portal after copying files
|
||||||
|
service: name=captive_portal.service enabled=no
|
||||||
|
when: py_captive_portal_install and py_captive_portal_enabled
|
||||||
|
|
||||||
|
- name: Stop captive_portal after copying files
|
||||||
|
service: name=captive_portal.service state=started
|
||||||
|
when: py_captive_portal_install and py_captive_portal_enabled
|
|
@ -27,6 +27,7 @@
|
||||||
group=root
|
group=root
|
||||||
mode={{ item.mode }}
|
mode={{ item.mode }}
|
||||||
with_items:
|
with_items:
|
||||||
|
- { src: 'named/named-iiab.conf.j2' , dest: '/etc/named-iiab.conf' , mode: '0644' }
|
||||||
- { src: 'named/school.local.zone.db' , dest: '/var/named-iiab/' , mode: '0644' }
|
- { src: 'named/school.local.zone.db' , dest: '/var/named-iiab/' , mode: '0644' }
|
||||||
- { src: 'named/school.internal.zone.db' , dest: '/var/named-iiab/' , mode: '0644' }
|
- { src: 'named/school.internal.zone.db' , dest: '/var/named-iiab/' , mode: '0644' }
|
||||||
|
|
||||||
|
|
|
@ -74,6 +74,14 @@
|
||||||
include_tasks: squid.yml
|
include_tasks: squid.yml
|
||||||
when: FQDN_changed and squid_install and iiab_stage|int == 9
|
when: FQDN_changed and squid_install and iiab_stage|int == 9
|
||||||
|
|
||||||
|
#- name: FOREFULLY ENABLE CAPTIVE PORTAL
|
||||||
|
# set_fact:
|
||||||
|
# py_captive_portal_install: True
|
||||||
|
|
||||||
|
- name: (Re)Installing captive portal
|
||||||
|
include_tasks: captive_portal.yml
|
||||||
|
when: py_captive_portal_install
|
||||||
|
|
||||||
#### start services
|
#### start services
|
||||||
- include_tasks: avahi.yml
|
- include_tasks: avahi.yml
|
||||||
tags:
|
tags:
|
||||||
|
|
97
roles/network/templates/captive_portal/captive_portal.py.j2
Executable file
97
roles/network/templates/captive_portal/captive_portal.py.j2
Executable file
|
@ -0,0 +1,97 @@
|
||||||
|
#!/usr/bin/python
|
||||||
|
|
||||||
|
# Captive portal script adapted from https://github.com/nikosft/captive-portal
|
||||||
|
|
||||||
|
import subprocess
|
||||||
|
import BaseHTTPServer
|
||||||
|
import cgi
|
||||||
|
|
||||||
|
# These variables are used as settings
|
||||||
|
PORT = int("{{ py_captive_portal_port }}") # the port in which the captive portal web server listens
|
||||||
|
IFACE = "{{ iiab_lan_iface }}" # the interface that captive portal protects
|
||||||
|
IP_ADDRESS = "{{ lan_ip }}" # the ip address of the captive portal (it can be the IP of IFACE)
|
||||||
|
|
||||||
|
'''
|
||||||
|
This it the http server used by the the captive portal
|
||||||
|
'''
|
||||||
|
class CaptivePortal(BaseHTTPServer.BaseHTTPRequestHandler):
|
||||||
|
#this is the index of the captive portal
|
||||||
|
#it simply redirects the user to the to login page
|
||||||
|
html_redirect = """
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<meta http-equiv="refresh" content="0; url=http://%s:%s/login" />
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<b>Redirecting to login page</b>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
|
"""%(IP_ADDRESS, PORT)
|
||||||
|
#the login page
|
||||||
|
html_login = """
|
||||||
|
<html>
|
||||||
|
<body>
|
||||||
|
<b>Login Form</b>
|
||||||
|
<form method="POST" action="do_login">
|
||||||
|
Username: <input type="text" name="username"><br>
|
||||||
|
Password: <input type="password" name="password"><br>
|
||||||
|
<input type="submit" value="Submit">
|
||||||
|
</form>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
|
"""
|
||||||
|
|
||||||
|
'''
|
||||||
|
if the user requests the login page show it, else
|
||||||
|
use the redirect page
|
||||||
|
'''
|
||||||
|
def do_GET(self):
|
||||||
|
path = self.path
|
||||||
|
self.send_response(200)
|
||||||
|
self.send_header("Content-type", "text/html")
|
||||||
|
self.end_headers()
|
||||||
|
if path == "/login":
|
||||||
|
self.wfile.write(self.html_login)
|
||||||
|
else:
|
||||||
|
self.wfile.write(self.html_redirect)
|
||||||
|
'''
|
||||||
|
this is called when the user submits the login form
|
||||||
|
'''
|
||||||
|
def do_POST(self):
|
||||||
|
self.send_response(200)
|
||||||
|
self.send_header("Content-type", "text/html")
|
||||||
|
self.end_headers()
|
||||||
|
form = cgi.FieldStorage(
|
||||||
|
fp=self.rfile,
|
||||||
|
headers=self.headers,
|
||||||
|
environ={'REQUEST_METHOD':'POST',
|
||||||
|
'CONTENT_TYPE':self.headers['Content-Type'],
|
||||||
|
})
|
||||||
|
username = form.getvalue("username")
|
||||||
|
password = form.getvalue("password")
|
||||||
|
#dummy security check
|
||||||
|
if username == '{{ py_captive_portal_username }}' and password == '{{ py_captive_portal_password }}':
|
||||||
|
#authorized user
|
||||||
|
remote_IP = self.client_address[0]
|
||||||
|
print 'New authorization from '+ remote_IP
|
||||||
|
print 'Updating IP tables'
|
||||||
|
subprocess.call(["iptables","-t", "nat", "-I", "PREROUTING","1", "-s", remote_IP, "-j" ,"ACCEPT"])
|
||||||
|
subprocess.call(["iptables", "-I", "FORWARD", "-s", remote_IP, "-j" ,"ACCEPT"])
|
||||||
|
self.wfile.write("You are now authorized. Navigate to any URL")
|
||||||
|
else:
|
||||||
|
#show the login form
|
||||||
|
self.wfile.write(self.html_login)
|
||||||
|
|
||||||
|
#the following function makes server produce no output
|
||||||
|
#comment it out if you want to print diagnostic messages
|
||||||
|
#def log_message(self, format, *args):
|
||||||
|
# return
|
||||||
|
|
||||||
|
print "Starting captive portal web server"
|
||||||
|
httpd = BaseHTTPServer.HTTPServer(('', PORT), CaptivePortal)
|
||||||
|
|
||||||
|
try:
|
||||||
|
httpd.serve_forever()
|
||||||
|
except KeyboardInterrupt:
|
||||||
|
pass
|
||||||
|
httpd.server_close()
|
|
@ -0,0 +1,15 @@
|
||||||
|
[Unit]
|
||||||
|
Description=Captive portal
|
||||||
|
After=syslog.target
|
||||||
|
|
||||||
|
[Service]
|
||||||
|
Type=simple
|
||||||
|
User=root
|
||||||
|
Group=root
|
||||||
|
WorkingDirectory=/opt/iiab/captive-portal
|
||||||
|
ExecStart=/opt/iiab/captive-portal/captive_portal.py
|
||||||
|
StandardOutput=syslog
|
||||||
|
StandardError=syslog
|
||||||
|
|
||||||
|
[Install]
|
||||||
|
WantedBy=multi-user.target
|
|
@ -60,6 +60,7 @@ kalite_server_port={{ kalite_server_port }}
|
||||||
sugarizer_port={{ sugarizer_port }}
|
sugarizer_port={{ sugarizer_port }}
|
||||||
block_DNS={{ block_DNS }}
|
block_DNS={{ block_DNS }}
|
||||||
captive_portal_enabled={{ captive_portal_enabled }}
|
captive_portal_enabled={{ captive_portal_enabled }}
|
||||||
|
py_captive_portal_enabled={{ py_captive_portal_enabled }}
|
||||||
|
|
||||||
echo "Lan is $lan and WAN is $wan"
|
echo "Lan is $lan and WAN is $wan"
|
||||||
#
|
#
|
||||||
|
@ -101,12 +102,13 @@ $IPTABLES -A FORWARD -i $wan -o $lan -m state --state ESTABLISHED,RELATED -j ACC
|
||||||
|
|
||||||
#Block https traffic except if directed at server
|
#Block https traffic except if directed at server
|
||||||
if [ "$gw_block_https" == "True" ]; then
|
if [ "$gw_block_https" == "True" ]; then
|
||||||
$IPTABLES -A FORWARD -p tcp ! -d 172.18.96.1 --dport 443 -j DROP
|
$IPTABLES -A FORWARD -p tcp ! -d {{ lan_ip }} --dport 443 -j DROP
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# Allow outgoing connections from the LAN side.
|
# Allow outgoing connections from the LAN side.
|
||||||
$IPTABLES -A FORWARD -i $lan -o $wan -j ACCEPT
|
if ! [ "$py_captive_portal_enabled" == "True" ];then
|
||||||
|
$IPTABLES -A FORWARD -i $lan -o $wan -j ACCEPT
|
||||||
|
fi
|
||||||
# Don't forward from the outside to the inside.
|
# Don't forward from the outside to the inside.
|
||||||
$IPTABLES -A FORWARD -i $wan -o $lan -j DROP
|
$IPTABLES -A FORWARD -i $wan -o $lan -j DROP
|
||||||
$IPTABLES -A INPUT -i $wan -j DROP
|
$IPTABLES -A INPUT -i $wan -j DROP
|
||||||
|
@ -122,8 +124,11 @@ if [ "$captive_portal_enabled" == "True" ];then
|
||||||
$IPTABLES -t mangle -A internet -j MARK --set-mark 99
|
$IPTABLES -t mangle -A internet -j MARK --set-mark 99
|
||||||
$IPTABLES -t nat -A PREROUTING -i {{ iiab_lan_iface }} -p tcp -m mark --mark 99 -m tcp --dport 80 -j DNAT --to-destination {{ lan_ip }}
|
$IPTABLES -t nat -A PREROUTING -i {{ iiab_lan_iface }} -p tcp -m mark --mark 99 -m tcp --dport 80 -j DNAT --to-destination {{ lan_ip }}
|
||||||
|
|
||||||
|
elif [ "py_$captive_portal_enabled" == "True" ];then
|
||||||
|
$IPTABLES -t nat -A PREROUTING -i $lan -p tcp --dport 80 ! -d {{ lan_ip }} -j DNAT --to {{ lan_ip }}:{{ py_captive_portal_port }}
|
||||||
|
|
||||||
elif [ "$HTTPCACHE_ON" == "True" ]; then
|
elif [ "$HTTPCACHE_ON" == "True" ]; then
|
||||||
$IPTABLES -t nat -A PREROUTING -i $lan -p tcp --dport 80 ! -d 172.18.96.1 -j DNAT --to 172.18.96.1:3128
|
$IPTABLES -t nat -A PREROUTING -i $lan -p tcp --dport 80 ! -d {{ lan_ip }} -j DNAT --to {{ lan_ip }}:3128
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# Enable routing.
|
# Enable routing.
|
||||||
|
|
|
@ -4,7 +4,7 @@ bogus-priv
|
||||||
#server=/{{ iiab_domain }}/{{ iiab_hostname }}
|
#server=/{{ iiab_domain }}/{{ iiab_hostname }}
|
||||||
# Add local-only domains here, queries in these domains are answered from /etc/hosts or DHCP only.
|
# Add local-only domains here, queries in these domains are answered from /etc/hosts or DHCP only.
|
||||||
local=/{{ iiab_domain }}/
|
local=/{{ iiab_domain }}/
|
||||||
{% if captive_portal_enabled == "True" %}
|
{% if dns_jail_enabled %}
|
||||||
# Make all host names resolve to the Raspberry Pi's IP address
|
# Make all host names resolve to the Raspberry Pi's IP address
|
||||||
address=/#/{{ lan_ip }}
|
address=/#/{{ lan_ip }}
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
|
|
@ -103,9 +103,12 @@ dhcpd_enabled: False
|
||||||
named_install: True
|
named_install: True
|
||||||
named_enabled: True
|
named_enabled: True
|
||||||
block_DNS: False
|
block_DNS: False
|
||||||
|
# Captive Portal highly experimental as of July 2018: https://github.com/iiab/iiab/pull/870
|
||||||
|
py_captive_portal_install: True
|
||||||
|
py_captive_portal_enabled: False
|
||||||
|
|
||||||
# dnsmasq
|
# dnsmasq
|
||||||
dnsmasq_install: False
|
dnsmasq_install: True
|
||||||
dnsmasq_enabled: False
|
dnsmasq_enabled: False
|
||||||
|
|
||||||
# Captive Portal highly experimental as of June 2018: https://github.com/iiab/iiab/issues/608
|
# Captive Portal highly experimental as of June 2018: https://github.com/iiab/iiab/issues/608
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue