-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathcaptive-portal.sh
executable file
·144 lines (119 loc) · 5.83 KB
/
captive-portal.sh
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
#!/bin/bash
# Project Byzantium: captive-portal.sh
# This script does the heavy lifting of IP tables manipulation under the
# captive portal's hood. It should only be used by the captive portal daemon.
# Written by Sitwon and The Doctor.
# Copyright (C) 2013 Project Byzantium
# This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or any later version.
IPTABLES=/usr/sbin/iptables
ARP=/sbin/arp
# Set up the choice tree of options that can be passed to this script.
case "$1" in
'initialize')
# $2: IP address of the client interface. Assumes final octet is .1.
# Initialize the IP tables ruleset by creating a new chain for captive
# portal users.
$IPTABLES -N internet -t mangle
# Convert the IP address of the client interface into a netblock.
CLIENTNET=`echo $2 | sed 's/1$/0\/24/'`
# Exempt traffic which does not originate from the client network.
$IPTABLES -t mangle -A PREROUTING -p all ! -s $CLIENTNET -j RETURN
# Traffic not exempted by the above rules gets kicked to the captive
# portal chain. When a use clicks through a rule is inserted above
# this one that matches them with a RETURN.
$IPTABLES -t mangle -A PREROUTING -j internet
# Traffic not coming from an accepted user gets marked 99.
$IPTABLES -t mangle -A internet -j MARK --set-mark 99
# $2 is actually the IP address of the client interface, so let's make
# it a bit more clear.
CLIENTIP=$2
# Traffic which has been marked 99 and is headed for 80/TCP or 443/TCP
# should be redirected to the captive portal web server.
$IPTABLES -t nat -A PREROUTING -m mark --mark 99 -p tcp --dport 80 \
-j DNAT --to-destination $CLIENTIP:31337
$IPTABLES -t nat -A PREROUTING -m mark --mark 99 -p tcp --dport 443 \
-j DNAT --to-destination $CLIENTIP:31338
$IPTABLES -t nat -A PREROUTING -m mark --mark 99 -p udp --dport 53 \
-j DNAT --to-destination $CLIENTIP:31339
# HTTP replies come from the same port the requests were received by.
# Rewrite the outbound packets to appear to come from the appropriate
# ports.
$IPTABLES -t nat -A POSTROUTING -d $CLIENTNET -p tcp --sport 31337 \
-j SNAT --to-source :80
$IPTABLES -t nat -A POSTROUTING -d $CLIENTNET -p tcp --sport 31338 \
-j SNAT --to-source :443
# Replies from fake_dns.py come from the same port because they're
# UDP. Rewrite the packet headers so it loos like it's from port
# 53/udp.
$IPTABLES -t nat -A POSTROUTING -d $CLIENTNET -p udp --sport 31339 \
-j SNAT --to-source :53
# All other traffic which is marked 99 is just dropped
$IPTABLES -t filter -A FORWARD -m mark --mark 99 -j DROP
# Allow incoming traffic that is headed for the local node.
$IPTABLES -t filter -A INPUT -p tcp --dport 53 -j ACCEPT
$IPTABLES -t filter -A INPUT -p tcp --dport 80 -j ACCEPT
$IPTABLES -t filter -A INPUT -p tcp --dport 443 -j ACCEPT
$IPTABLES -t filter -A INPUT -p tcp --dport 1248 -j ACCEPT
$IPTABLES -t filter -A INPUT -p tcp --dport 6667 -j ACCEPT
$IPTABLES -t filter -A INPUT -p tcp --dport 8089 -j ACCEPT
$IPTABLES -t filter -A INPUT -p tcp --dport 9001 -j ACCEPT
$IPTABLES -t filter -A INPUT -p tcp --dport 9005 -j ACCEPT
$IPTABLES -t filter -A INPUT -p tcp --dport 9006 -j ACCEPT
$IPTABLES -t filter -A INPUT -p tcp --dport 9090 -j ACCEPT
$IPTABLES -t filter -A INPUT -p tcp --dport 31337 -j ACCEPT
$IPTABLES -t filter -A INPUT -p tcp --dport 31338 -j ACCEPT
$IPTABLES -t filter -A INPUT -p udp --dport 53 -j ACCEPT
$IPTABLES -t filter -A INPUT -p udp --dport 67 -j ACCEPT
$IPTABLES -t filter -A INPUT -p udp --dport 698 -j ACCEPT
$IPTABLES -t filter -A INPUT -p udp --dport 5353 -j ACCEPT
$IPTABLES -t filter -A INPUT -p udp --dport 31339 -j ACCEPT
$IPTABLES -t filter -A INPUT -p icmp -j ACCEPT
# But reject anything else coming from unrecognized users.
$IPTABLES -t filter -A INPUT -m mark --mark 99 -j DROP
exit 0
;;
'add')
# $2: IP address of client.
CLIENT=$2
# Isolate the MAC address of the client in question.
CLIENTMAC=`$ARP -n | grep ':' | grep $CLIENT | awk '{print $3}'`
# Add the MAC address of the client to the whitelist, so it'll be able
# to access the mesh even if its IP address changes.
$IPTABLES -t mangle -I internet -m mac --mac-source \
$CLIENTMAC -j RETURN
exit 0
;;
'remove')
# $2: IP address of client.
CLIENT=$2
# Isolate the MAC address of the client in question.
CLIENTMAC=`$ARP -n | grep ':' | grep $CLIENT | awk '{print $3}'`
# Delete the MAC address of the client from the whitelist.
$IPTABLES -t mangle -D internet -m mac --mac-source \
$CLIENTMAC -j RETURN
exit 0
;;
'purge')
# Purge all of the IP tables rules.
$IPTABLES -F
$IPTABLES -X
$IPTABLES -t nat -F
$IPTABLES -t nat -X
$IPTABLES -t mangle -F
$IPTABLES -t mangle -X
$IPTABLES -t filter -F
$IPTABLES -t filter -X
exit 0
;;
'list')
# Display the currently running IP tables ruleset.
$IPTABLES --list -n
$IPTABLES --list -t nat -n
$IPTABLES --list -t mangle -n
$IPTABLES --list -t filter -n
exit 0
;;
*)
echo "USAGE: $0 {initialize <IP> <interface>|add <IP> <interface>|remove <IP> <interface>|purge|list}"
exit 0
esac