Project

General

Profile

Download (32 KB) Statistics
| Branch: | Tag: | Revision:
1 5b237745 Scott Ullrich
<?php
2
/*
3
	captiveportal.inc
4 3db19cf1 Scott Ullrich
	part of m0n0wall (http://m0n0.ch/wall)
5 36254e4a Scott Ullrich
6 0bd34ed6 Scott Ullrich
	Copyright (C) 2003-2006 Manuel Kasper <mk@neon1.net>.
7 5b237745 Scott Ullrich
	All rights reserved.
8 36254e4a Scott Ullrich
9 5b237745 Scott Ullrich
	Redistribution and use in source and binary forms, with or without
10
	modification, are permitted provided that the following conditions are met:
11 36254e4a Scott Ullrich
12 5b237745 Scott Ullrich
	1. Redistributions of source code must retain the above copyright notice,
13
	   this list of conditions and the following disclaimer.
14 36254e4a Scott Ullrich
15 5b237745 Scott Ullrich
	2. Redistributions in binary form must reproduce the above copyright
16
	   notice, this list of conditions and the following disclaimer in the
17
	   documentation and/or other materials provided with the distribution.
18 36254e4a Scott Ullrich
19 5b237745 Scott Ullrich
	THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
20
	INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
21
	AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
22
	AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
23
	OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
24
	SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
25
	INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
26
	CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
27
	ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
28
	POSSIBILITY OF SUCH DAMAGE.
29 ca83c6ea Scott Ullrich
30 9699028a Scott Ullrich
	This version of captiveportal.inc has been modified by Rob Parker
31
	<rob.parker@keycom.co.uk> to include changes for per-user bandwidth management
32
	via returned RADIUS attributes. This page has been modified to delete any
33
	added rules which may have been created by other per-user code (index.php, etc).
34
	These changes are (c) 2004 Keycom PLC.
35
*/
36 36254e4a Scott Ullrich
37 5b237745 Scott Ullrich
/* include all configuration functions */
38
require_once("functions.inc");
39 3db19cf1 Scott Ullrich
require_once("radius_authentication.inc");
40 0bd34ed6 Scott Ullrich
require_once("radius_accounting.inc");
41 856e58a6 Scott Ullrich
require_once("radius.inc");
42 0bd34ed6 Scott Ullrich
43
$lockfile = "{$g['varrun_path']}/captiveportal.lock";
44 5b237745 Scott Ullrich
45
function captiveportal_configure() {
46
	global $config, $g;
47 36254e4a Scott Ullrich
48 3db19cf1 Scott Ullrich
	if (isset($config['captiveportal']['enable']) &&
49
		(($config['captiveportal']['interface'] == "lan") ||
50
			isset($config['interfaces'][$config['captiveportal']['interface']]['enable']))) {
51 36254e4a Scott Ullrich
52 3db19cf1 Scott Ullrich
		if ($g['booting'])
53
			echo "Starting captive portal... ";
54 36254e4a Scott Ullrich
55 5b237745 Scott Ullrich
		/* kill any running mini_httpd */
56 23a0c341 Scott Ullrich
		killbypid("{$g['varrun_path']}/lighty-CaptivePortal.pid");
57 63fff79b Scott Ullrich
		killbypid("{$g['varrun_path']}/lighty-CaptivePortal-SSL.pid");
58 36254e4a Scott Ullrich
59 c6c92abf Scott Ullrich
		/* kill any running minicron */
60
		killbypid("{$g['varrun_path']}/minicron.pid");
61 36254e4a Scott Ullrich
62 3db19cf1 Scott Ullrich
		/* generate ipfw rules */
63
		$cprules = captiveportal_rules_generate();
64 36254e4a Scott Ullrich
65 3db19cf1 Scott Ullrich
		/* make sure ipfw is loaded */
66
		mwexec("/sbin/kldload ipfw");
67 36254e4a Scott Ullrich
68 5b237745 Scott Ullrich
		/* stop accounting on all clients */
69 3db19cf1 Scott Ullrich
		captiveportal_radius_stop_all();
70 5b237745 Scott Ullrich
71 0bd34ed6 Scott Ullrich
		/* initialize minicron interval value */
72
		$croninterval = $config['captiveportal']['croninterval'] ? $config['captiveportal']['croninterval'] : 60;
73
74
		/* double check if the $croninterval is numeric and at least 10 seconds. If not we set it to 60 to avoid problems */
75
		if ((!is_numeric($croninterval)) || ($croninterval < 10)) { $croninterval = 60; }
76
77 5b237745 Scott Ullrich
		/* remove old information */
78 d99f7864 Scott Ullrich
		unlink_if_exists("{$g['vardb_path']}/captiveportal.nextrule");
79
		unlink_if_exists("{$g['vardb_path']}/captiveportal.db");
80
		unlink_if_exists("{$g['vardb_path']}/captiveportal_mac.db");
81
		unlink_if_exists("{$g['vardb_path']}/captiveportal_ip.db");
82
		unlink_if_exists("{$g['vardb_path']}/captiveportal_radius.db");
83 36254e4a Scott Ullrich
84 5b237745 Scott Ullrich
		/* write portal page */
85
		if ($config['captiveportal']['page']['htmltext'])
86
			$htmltext = base64_decode($config['captiveportal']['page']['htmltext']);
87
		else {
88
			/* example/template page */
89
			$htmltext = <<<EOD
90
<html>
91
<head>
92 61b040ce Scott Ullrich
<title>pfSense captive portal</title>
93 5b237745 Scott Ullrich
</head>
94 3db19cf1 Scott Ullrich
<body>
95 a515d275 Scott Ullrich
<center>
96 61b040ce Scott Ullrich
<h2>pfSense captive portal</h2>
97 407a29ca Scott Ullrich
Welcome to the pfSense Captive Portal!  This is the default page since a custom page has not been defined.
98 14d2d21b Scott Ullrich
<p>
99 a515d275 Scott Ullrich
<form method="post" action="\$PORTAL_ACTION\$">
100
<input name="redirurl" type="hidden" value="\$PORTAL_REDIRURL\$">
101 407a29ca Scott Ullrich
<table>
102
   <tr><td>Username:</td><td><input name="auth_user" type="text"></td></tr>
103
   <tr><td>Password:</td><td><input name="auth_pass" type="password"></td></tr>
104 a515d275 Scott Ullrich
   <tr><td>&nbsp;</td></tr>
105 14d2d21b Scott Ullrich
   <tr>
106
     <td colspan="2">
107 0bd34ed6 Scott Ullrich
	<center><input name="accept" type="submit" value="Continue"></center>
108 14d2d21b Scott Ullrich
     </td>
109
   </tr>
110 407a29ca Scott Ullrich
</table>
111 a515d275 Scott Ullrich
</center>
112 407a29ca Scott Ullrich
</form>
113 5b237745 Scott Ullrich
</body>
114
</html>
115
116 0bd34ed6 Scott Ullrich
117
118 5b237745 Scott Ullrich
EOD;
119
		}
120
121
		$fd = @fopen("{$g['varetc_path']}/captiveportal.html", "w");
122
		if ($fd) {
123
			fwrite($fd, $htmltext);
124 36254e4a Scott Ullrich
			fclose($fd);
125 5b237745 Scott Ullrich
		}
126 36254e4a Scott Ullrich
127 5b237745 Scott Ullrich
		/* write error page */
128
		if ($config['captiveportal']['page']['errtext'])
129
			$errtext = base64_decode($config['captiveportal']['page']['errtext']);
130
		else {
131
			/* example page */
132
			$errtext = <<<EOD
133
<html>
134
<head>
135
<title>Authentication error</title>
136
</head>
137
<body>
138
<font color="#cc0000"><h2>Authentication error</h2></font>
139
<b>
140
Username and/or password invalid.
141
<br><br>
142
<a href="javascript:history.back()">Go back</a>
143
</b>
144
</body>
145
</html>
146
147
EOD;
148
		}
149
150
		$fd = @fopen("{$g['varetc_path']}/captiveportal-error.html", "w");
151
		if ($fd) {
152
			fwrite($fd, $errtext);
153 36254e4a Scott Ullrich
			fclose($fd);
154 5b237745 Scott Ullrich
		}
155 36254e4a Scott Ullrich
156 0bd34ed6 Scott Ullrich
		/* write elements */
157
		captiveportal_write_elements();
158 5b237745 Scott Ullrich
159 3db19cf1 Scott Ullrich
		/* load rules */
160
		mwexec("/sbin/ipfw -f delete set 1");
161
		mwexec("/sbin/ipfw -f delete set 2");
162
		mwexec("/sbin/ipfw -f delete set 3");
163 36254e4a Scott Ullrich
164 63fff79b Scott Ullrich
		/* ipfw cannot accept rules directly on stdin,
165 3db19cf1 Scott Ullrich
		   so we have to write them to a temporary file first */
166
		$fd = @fopen("{$g['tmp_path']}/ipfw.cp.rules", "w");
167
		if (!$fd) {
168
			printf("Cannot open ipfw.cp.rules in captiveportal_configure()\n");
169
			return 1;
170
		}
171 36254e4a Scott Ullrich
172 3db19cf1 Scott Ullrich
		fwrite($fd, $cprules);
173
		fclose($fd);
174 36254e4a Scott Ullrich
175 3db19cf1 Scott Ullrich
		mwexec("/sbin/ipfw {$g['tmp_path']}/ipfw.cp.rules");
176 36254e4a Scott Ullrich
177 3db19cf1 Scott Ullrich
		unlink("{$g['tmp_path']}/ipfw.cp.rules");
178 36254e4a Scott Ullrich
179 3db19cf1 Scott Ullrich
		/* filter on layer2 as well so we can check MAC addresses */
180
		mwexec("/sbin/sysctl net.link.ether.ipfw=1");
181 36254e4a Scott Ullrich
182 5b237745 Scott Ullrich
		chdir($g['captiveportal_path']);
183 36254e4a Scott Ullrich
184 877ac35d Scott Ullrich
		/* TEMPORARY!  FAST_CGI reports _FALSE_ client ip
185
		 * 	       addresses.
186
		 */
187
		$use_fastcgi = false;
188 9b5a1292 Scott Ullrich
189
		if ($config['captiveportal']['maxproc'])
190
			$maxproc = $config['captiveportal']['maxproc'];
191
		else
192
			$maxproc = 16;
193 36254e4a Scott Ullrich
194 40b9f8c0 Scott Ullrich
		if(isset($config['captiveportal']['httpslogin'])) {
195
			$cert = base64_decode($config['captiveportal']['certificate']);
196
			$key = base64_decode($config['captiveportal']['private-key']);
197 63fff79b Scott Ullrich
			/* generate lighttpd configuration */
198
			system_generate_lighty_config("{$g['varetc_path']}/lighty-CaptivePortal-SSL.conf",
199
				$cert, $key, "lighty-CaptivePortal-ssl.pid", "8001", "/usr/local/captiveportal/",
200
					"cert-portal.pem", "1", $maxproc, $use_fastcgi, true);
201 40b9f8c0 Scott Ullrich
		}
202 36254e4a Scott Ullrich
203 877ac35d Scott Ullrich
		/* generate lighttpd configuration */
204
		system_generate_lighty_config("{$g['varetc_path']}/lighty-CaptivePortal.conf",
205 63fff79b Scott Ullrich
			"", "", "lighty-CaptivePortal.pid", "8000", "/usr/local/captiveportal/",
206 556d59be Scott Ullrich
				"cert-portal.pem", "1", $maxproc, $use_fastcgi, true);
207 36254e4a Scott Ullrich
208 877ac35d Scott Ullrich
		/* attempt to start lighttpd */
209
		$res = mwexec("/usr/local/sbin/lighttpd -f {$g['varetc_path']}/lighty-CaptivePortal.conf");
210 36254e4a Scott Ullrich
211 63fff79b Scott Ullrich
		/* fire up https instance */
212
		if(isset($config['captiveportal']['httpslogin']))
213
			$res = mwexec("/usr/local/sbin/lighttpd -f {$g['varetc_path']}/lighty-CaptivePortal-SSL.conf");
214 36254e4a Scott Ullrich
215 0bd34ed6 Scott Ullrich
		/* start pruning process (interval defaults to 60 seconds) */
216
		mwexec("/usr/local/bin/minicron $croninterval {$g['varrun_path']}/minicron.pid " .
217 c6c92abf Scott Ullrich
			"/etc/rc.prunecaptiveportal");
218 36254e4a Scott Ullrich
219 5b237745 Scott Ullrich
		/* generate passthru mac database */
220 3db19cf1 Scott Ullrich
		captiveportal_passthrumac_configure();
221
		/* create allowed ip database and insert ipfw rules to make it so */
222
		captiveportal_allowedip_configure();
223 5b237745 Scott Ullrich
224 d99f7864 Scott Ullrich
		/* generate radius server database */
225
		if ($config['captiveportal']['radiusip'] && (!isset($config['captiveportal']['auth_method']) ||
226
				($config['captiveportal']['auth_method'] == "radius"))) {
227
			$radiusip = $config['captiveportal']['radiusip'];
228
			$radiusip2 = ($config['captiveportal']['radiusip2']) ? $config['captiveportal']['radiusip2'] : null;
229
230
			if ($config['captiveportal']['radiusport'])
231
				$radiusport = $config['captiveportal']['radiusport'];
232
			else
233
				$radiusport = 1812;
234
235
			if ($config['captiveportal']['radiusacctport'])
236
				$radiusacctport = $config['captiveportal']['radiusacctport'];
237
			else
238
				$radiusacctport = 1813;
239
240
			if ($config['captiveportal']['radiusport2'])
241
				$radiusport2 = $config['captiveportal']['radiusport2'];
242
			else
243
				$radiusport2 = 1812;
244
245
			$radiuskey = $config['captiveportal']['radiuskey'];
246
			$radiuskey2 = ($config['captiveportal']['radiuskey2']) ? $config['captiveportal']['radiuskey2'] : null;
247
248
			$fd = @fopen("{$g['vardb_path']}/captiveportal_radius.db", "w");
249
			if (!$fd) {
250
				printf("Error: cannot open radius DB file in captiveportal_configure().\n");
251
				return 1;
252
			} else if (isset($radiusip2, $radiuskey2)) {
253
				fwrite($fd,$radiusip . "," . $radiusport . "," . $radiusacctport . "," . $radiuskey . "\n"
254
					 . $radiusip2 . "," . $radiusport2 . "," . $radiusacctport . "," . $radiuskey2);
255
			} else {
256
				fwrite($fd,$radiusip . "," . $radiusport . "," . $radiusacctport . "," . $radiuskey);
257
			}
258
			fclose($fd);
259
		}
260 36254e4a Scott Ullrich
261 d99f7864 Scott Ullrich
		if ($g['booting'])
262
			echo "done\n";
263 36254e4a Scott Ullrich
264 5b237745 Scott Ullrich
	} else {
265 23a0c341 Scott Ullrich
		killbypid("{$g['varrun_path']}/lighty-CaptivePortal.pid");
266 c6c92abf Scott Ullrich
		killbypid("{$g['varrun_path']}/minicron.pid");
267 12ee8fe4 Scott Ullrich
268 3db19cf1 Scott Ullrich
		captiveportal_radius_stop_all();
269
270
		mwexec("/sbin/sysctl net.link.ether.ipfw=0");
271
272
		if (!isset($config['shaper']['enable'])) {
273
			/* unload ipfw */
274
			mwexec("/sbin/kldunload ipfw");
275
		} else {
276
			/* shaper is on - just remove our rules */
277
			mwexec("/sbin/ipfw -f delete set 1");
278
			mwexec("/sbin/ipfw -f delete set 2");
279
			mwexec("/sbin/ipfw -f delete set 3");
280
		}
281
	}
282 36254e4a Scott Ullrich
283 5b237745 Scott Ullrich
	return 0;
284
}
285
286 3db19cf1 Scott Ullrich
function captiveportal_rules_generate() {
287
	global $config, $g;
288 36254e4a Scott Ullrich
289 3db19cf1 Scott Ullrich
	$cpifn = $config['captiveportal']['interface'];
290
	$cpif = $config['interfaces'][$cpifn]['if'];
291
	$cpip = $config['interfaces'][$cpifn]['ipaddr'];
292
293
	/* note: the captive portal daemon inserts all pass rules for authenticated
294
	   clients as skipto 50000 rules to make traffic shaping work */
295
296
	$cprules = "";
297 181a843c Scott Ullrich
298
	/*   allow nat redirects to work  see
299
	     http://cvstrac.pfsense.com/tktview?tn=651
300
	 */
301
	$iflist = array("lan" => "LAN", "wan" => "WAN");
302 c54d236c Scott Ullrich
	$captive_portal_interface = strtoupper($cpifn);
303 36254e4a Scott Ullrich
	for ($i = 1; isset($config['interfaces']['opt' . $i]); $i++)
304
		$iflist['opt' . $i] = "OPT{$i}";
305 181a843c Scott Ullrich
	foreach ($iflist as $ifent => $ifname) {
306 d66bb68a Scott Ullrich
		if($captive_portal_interface == strtoupper($ifname))
307 181a843c Scott Ullrich
			continue;
308
		$int = convert_friendly_interface_to_real_interface_name($ifname);
309 657f3f15 Scott Ullrich
		$cprules .= "add 30 set 1 skipto 50000 all from any to any in via {$int} keep-state\n";
310 181a843c Scott Ullrich
	}
311 36254e4a Scott Ullrich
312 3db19cf1 Scott Ullrich
	/* captive portal on LAN interface? */
313
	if ($cpifn == "lan") {
314
		/* add anti-lockout rules */
315
		$cprules .= <<<EOD
316 0bd34ed6 Scott Ullrich
add 500 set 1 pass all from $cpip to any out via $cpif
317 3db19cf1 Scott Ullrich
add 501 set 1 pass all from any to $cpip in via $cpif
318
319
EOD;
320
	}
321
322
	$cprules .= <<<EOD
323
# skip to traffic shaper if not on captive portal interface
324
add 1000 set 1 skipto 50000 all from any to any not layer2 not via $cpif
325
# pass all layer2 traffic on other interfaces
326
add 1001 set 1 pass layer2 not via $cpif
327
328
# layer 2: pass ARP
329
add 1100 set 1 pass layer2 mac-type arp
330 b9d1d810 Scott Ullrich
# pfsense requires for WPA
331
add 1100 set 1 pass layer2 mac-type 0x888e
332 684c787e Scott Ullrich
333 36254e4a Scott Ullrich
# PPP Over Ethernet Discovery Stage
334 684c787e Scott Ullrich
add 1100 set 1 pass layer2 mac-type 0x8863
335
# PPP Over Ethernet Session Stage
336
add 1100 set 1 pass layer2 mac-type 0x8864
337
338 3db19cf1 Scott Ullrich
# layer 2: block anything else non-IP
339
add 1101 set 1 deny layer2 not mac-type ip
340
# layer 2: check if MAC addresses of authenticated clients are correct
341
add 1102 set 1 skipto 20000 layer2
342
343
# allow access to our DHCP server (which needs to be able to ping clients as well)
344
add 1200 set 1 pass udp from any 68 to 255.255.255.255 67 in
345
add 1201 set 1 pass udp from any 68 to $cpip 67 in
346
add 1202 set 1 pass udp from $cpip 67 to any 68 out
347
add 1203 set 1 pass icmp from $cpip to any out icmptype 8
348
add 1204 set 1 pass icmp from any to $cpip in icmptype 0
349
350
# allow access to our DNS forwarder
351
add 1300 set 1 pass udp from any to $cpip 53 in
352
add 1301 set 1 pass udp from $cpip 53 to any out
353
354
# allow access to our web server
355
add 1302 set 1 pass tcp from any to $cpip 8000 in
356
add 1303 set 1 pass tcp from $cpip 8000 to any out
357
358
EOD;
359
360
	if (isset($config['captiveportal']['httpslogin'])) {
361
		$cprules .= <<<EOD
362
add 1304 set 1 pass tcp from any to $cpip 8001 in
363
add 1305 set 1 pass tcp from $cpip 8001 to any out
364
365
EOD;
366
	}
367 36254e4a Scott Ullrich
368 3db19cf1 Scott Ullrich
	$cprules .= <<<EOD
369
370
# ... 10000-19899: rules per authenticated client go here...
371
372
# redirect non-authenticated clients to captive portal
373
add 19900 set 1 fwd 127.0.0.1,8000 tcp from any to any 80 in
374 5480497a Scott Ullrich
375
# --- for redir ssl
376
# redirect non-authenticated clients to captive portal on ssl
377
add 19901 set 1 fwd 127.0.0.1,8001 tcp from any to any 443 in
378
379
# let the responses from the captive portal web server back out
380
add 19902 set 1 pass tcp from any 443 to any out
381
382
# --- End redir ssl
383
384 3db19cf1 Scott Ullrich
# let the responses from the captive portal web server back out
385 5480497a Scott Ullrich
add 19903 set 1 pass tcp from any 80 to any out
386 3db19cf1 Scott Ullrich
# block everything else
387 5480497a Scott Ullrich
add 19904 set 1 deny all from any to any
388 3db19cf1 Scott Ullrich
389
# ... 20000-29899: layer2 block rules per authenticated client go here...
390
391
# pass everything else on layer2
392
add 29900 set 1 pass all from any to any layer2
393
394
EOD;
395
396
	return $cprules;
397
}
398
399 5b237745 Scott Ullrich
/* remove clients that have been around for longer than the specified amount of time */
400 36254e4a Scott Ullrich
/* db file structure:
401 0bd34ed6 Scott Ullrich
timestamp,ipfw_rule_no,clientip,clientmac,username,sessionid,password,session_timeout,idle_timeout,session_terminate_time */
402
403 3db19cf1 Scott Ullrich
/* (password is in Base64 and only saved when reauthentication is enabled) */
404 5b237745 Scott Ullrich
function captiveportal_prune_old() {
405 0bd34ed6 Scott Ullrich
406 d99f7864 Scott Ullrich
	global $g, $config;
407 0bd34ed6 Scott Ullrich
408 d99f7864 Scott Ullrich
	/* check for expired entries */
409
	if ($config['captiveportal']['timeout'])
410
		$timeout = $config['captiveportal']['timeout'] * 60;
411
	else
412
		$timeout = 0;
413 36254e4a Scott Ullrich
414 d99f7864 Scott Ullrich
	if ($config['captiveportal']['idletimeout'])
415
		$idletimeout = $config['captiveportal']['idletimeout'] * 60;
416
	else
417
		$idletimeout = 0;
418 36254e4a Scott Ullrich
419 d99f7864 Scott Ullrich
	if (!$timeout && !$idletimeout && !isset($config['captiveportal']['reauthenticate']))
420
		return;
421 36254e4a Scott Ullrich
422 d99f7864 Scott Ullrich
	captiveportal_lock();
423 36254e4a Scott Ullrich
424 d99f7864 Scott Ullrich
	/* read database */
425
	$cpdb = captiveportal_read_db();
426 36254e4a Scott Ullrich
427 d99f7864 Scott Ullrich
	$radiusservers = captiveportal_get_radius_servers();
428 36254e4a Scott Ullrich
429 d99f7864 Scott Ullrich
	for ($i = 0; $i < count($cpdb); $i++) {
430 36254e4a Scott Ullrich
431 d99f7864 Scott Ullrich
		$timedout = false;
432
		$term_cause = 1;
433 36254e4a Scott Ullrich
434 d99f7864 Scott Ullrich
		/* hard timeout? */
435
		if ($timeout) {
436
			if ((time() - $cpdb[$i][0]) >= $timeout) {
437
				$timedout = true;
438
				$term_cause = 5; // Session-Timeout
439
			}
440
		}
441 36254e4a Scott Ullrich
442 d99f7864 Scott Ullrich
		/* Session-Terminate-Time */
443
		if (!$timedout && !empty($cpdb[$i][9])) {
444
			if (time() >= $cpdb[$i][9]) {
445
				$timedout = true;
446
				$term_cause = 5; // Session-Timeout
447
			}
448
		}
449 36254e4a Scott Ullrich
450 d99f7864 Scott Ullrich
		/* check if the radius idle_timeout attribute has been set and if its set change the idletimeout to this value */
451
		$idletimeout = (is_numeric($cpdb[$i][8])) ? $cpdb[$i][8] : $idletimeout;
452
		/* if an idle timeout is specified, get last activity timestamp from ipfw */
453
		if (!$timedout && $idletimeout) {
454
			$lastact = captiveportal_get_last_activity($cpdb[$i][1]);
455
			if ($lastact && ((time() - $lastact) >= $idletimeout)) {
456
				$timedout = true;
457
				$term_cause = 4; // Idle-Timeout
458
				$stop_time = $lastact; // Entry added to comply with WISPr
459
			}
460
		}
461 36254e4a Scott Ullrich
462 d99f7864 Scott Ullrich
		/* if radius session_timeout is enabled and the session_timeout is not null, then check if the user should be logged out */
463
		if (!$timedout && isset($config['captiveportal']['radiussession_timeout']) && !empty($cpdb[$i][7])) {
464
			if (time() >= ($cpdb[$i][0] + $cpdb[$i][7])) {
465
				$timedout = true;
466
				$term_cause = 5; // Session-Timeout
467
			}
468
		}
469 36254e4a Scott Ullrich
470 d99f7864 Scott Ullrich
		if ($timedout) {
471
			captiveportal_disconnect($cpdb[$i], $radiusservers,$term_cause,$stop_time);
472
			captiveportal_logportalauth($cpdb[$i][4], $cpdb[$i][3], $cpdb[$i][2], "TIMEOUT");
473
			unset($cpdb[$i]);
474
		}
475 36254e4a Scott Ullrich
476 d99f7864 Scott Ullrich
		/* do periodic RADIUS reauthentication? */
477
		if (!$timedout && isset($config['captiveportal']['reauthenticate']) &&
478
			($radiusservers !== false)) {
479
480
			if (isset($config['captiveportal']['radacct_enable'])) {
481
				if ($config['captiveportal']['reauthenticateacct'] == "stopstart") {
482
					/* stop and restart accounting */
483
					RADIUS_ACCOUNTING_STOP($cpdb[$i][1], // ruleno
484
										   $cpdb[$i][4], // username
485
										   $cpdb[$i][5], // sessionid
486
										   $cpdb[$i][0], // start time
487
										   $radiusservers[0]['ipaddr'],
488
										   $radiusservers[0]['acctport'],
489
										   $radiusservers[0]['key'],
490
										   $cpdb[$i][2], // clientip
491
										   $cpdb[$i][3], // clientmac
492
										   10); // NAS Request
493
					exec("/sbin/ipfw zero {$cpdb[$i][1]}");
494
					RADIUS_ACCOUNTING_START($cpdb[$i][1], // ruleno
495
											$cpdb[$i][4], // username
496
											$cpdb[$i][5], // sessionid
497
											$radiusservers[0]['ipaddr'],
498
											$radiusservers[0]['acctport'],
499
											$radiusservers[0]['key'],
500
											$cpdb[$i][2], // clientip
501
											$cpdb[$i][3]); // clientmac
502
				} else if ($config['captiveportal']['reauthenticateacct'] == "interimupdate") {
503
					RADIUS_ACCOUNTING_STOP($cpdb[$i][1], // ruleno
504
										   $cpdb[$i][4], // username
505
										   $cpdb[$i][5], // sessionid
506
										   $cpdb[$i][0], // start time
507
										   $radiusservers[0]['ipaddr'],
508
										   $radiusservers[0]['acctport'],
509
										   $radiusservers[0]['key'],
510
										   $cpdb[$i][2], // clientip
511
										   $cpdb[$i][3], // clientmac
512
										   10, // NAS Request
513
										   true); // Interim Updates
514
				}
515
			}
516 36254e4a Scott Ullrich
517 d99f7864 Scott Ullrich
			/* check this user against RADIUS again */
518
			$auth_list = RADIUS_AUTHENTICATION($cpdb[$i][4], // username
519
										  base64_decode($cpdb[$i][6]), // password
520
							  			  $radiusservers,
521
										  $cpdb[$i][2], // clientip
522
										  $cpdb[$i][3], // clientmac
523
										  $cpdb[$i][1]); // ruleno
524
525
			if ($auth_list['auth_val'] == 3) {
526
				captiveportal_disconnect($cpdb[$i], $radiusservers, 17);
527
				captiveportal_logportalauth($cpdb[$i][4], $cpdb[$i][3], $cpdb[$i][2], "RADIUS_DISCONNECT", $auth_list['reply_message']);
528
				unset($cpdb[$i]);
529
			}
530
		}
531
	}
532 36254e4a Scott Ullrich
533 d99f7864 Scott Ullrich
	/* write database */
534
	captiveportal_write_db($cpdb);
535
536
	captiveportal_unlock();
537 5b237745 Scott Ullrich
}
538
539 3db19cf1 Scott Ullrich
/* remove a single client according to the DB entry */
540 0bd34ed6 Scott Ullrich
function captiveportal_disconnect($dbent, $radiusservers,$term_cause = 1,$stop_time = null) {
541 36254e4a Scott Ullrich
542 d99f7864 Scott Ullrich
	global $g, $config;
543
544
	$stop_time = (empty($stop_time)) ? time() : $stop_time;
545
546
	/* this client needs to be deleted - remove ipfw rules */
547
	if (isset($config['captiveportal']['radacct_enable']) && isset($radiusservers[0])) {
548
		RADIUS_ACCOUNTING_STOP($dbent[1], // ruleno
549
							   $dbent[4], // username
550
							   $dbent[5], // sessionid
551
							   $dbent[0], // start time
552
							   $radiusservers[0]['ipaddr'],
553
							   $radiusservers[0]['acctport'],
554
							   $radiusservers[0]['key'],
555
							   $dbent[2], // clientip
556
							   $dbent[3], // clientmac
557
							   $term_cause, // Acct-Terminate-Cause
558
							   false,
559
							   $stop_time);
560
	}
561
562
	mwexec("/sbin/ipfw delete " . $dbent[1] . " " . ($dbent[1]+10000));
563
564
	//KEYCOM: we need to delete +40500 and +45500 as well...
565
	//these are the rule numbers we use to control traffic shaping for each logged in user via captive portal
566
	//we only need to remove our rules if peruserbw is turned on.
567
	if (isset($config['captiveportal']['peruserbw'])) {
568
		mwexec("/sbin/ipfw delete " . ($dbent[1]+40500));
569
		mwexec("/sbin/ipfw delete " . ($dbent[1]+45500));
570
	}
571 7a7abeba Scott Ullrich
572
	/* ensure all pf states are killed (pfSense) */
573
	mwexec("pfctl -k {$dbent[2]}");
574
575 3db19cf1 Scott Ullrich
}
576 12ee8fe4 Scott Ullrich
577 3db19cf1 Scott Ullrich
/* remove a single client by ipfw rule number */
578 0bd34ed6 Scott Ullrich
function captiveportal_disconnect_client($id,$term_cause = 1) {
579 36254e4a Scott Ullrich
580 d99f7864 Scott Ullrich
	global $g, $config;
581 36254e4a Scott Ullrich
582 d99f7864 Scott Ullrich
	captiveportal_lock();
583 36254e4a Scott Ullrich
584 d99f7864 Scott Ullrich
	/* read database */
585
	$cpdb = captiveportal_read_db();
586
	$radiusservers = captiveportal_get_radius_servers();
587
588
	/* find entry */
589
	for ($i = 0; $i < count($cpdb); $i++) {
590
		if ($cpdb[$i][1] == $id) {
591
			captiveportal_disconnect($cpdb[$i], $radiusservers, $term_cause);
592
			captiveportal_logportalauth($cpdb[$i][4], $cpdb[$i][3], $cpdb[$i][2], "DISCONNECT");
593
			unset($cpdb[$i]);
594
			break;
595
		}
596
	}
597 36254e4a Scott Ullrich
598 d99f7864 Scott Ullrich
	/* write database */
599
	captiveportal_write_db($cpdb);
600 36254e4a Scott Ullrich
601 d99f7864 Scott Ullrich
	captiveportal_unlock();
602 5b237745 Scott Ullrich
}
603
604
/* send RADIUS acct stop for all current clients */
605
function captiveportal_radius_stop_all() {
606 d99f7864 Scott Ullrich
	global $g, $config;
607
608
	if (!isset($config['captiveportal']['radacct_enable']))
609
		return;
610
611
	captiveportal_lock();
612
	$cpdb = captiveportal_read_db();
613
614
	$radiusservers = captiveportal_get_radius_servers();
615
616
	if (isset($radiusservers[0])) {
617
		for ($i = 0; $i < count($cpdb); $i++) {
618
			RADIUS_ACCOUNTING_STOP($cpdb[$i][1], // ruleno
619
								   $cpdb[$i][4], // username
620
								   $cpdb[$i][5], // sessionid
621
								   $cpdb[$i][0], // start time
622
								   $radiusservers[0]['ipaddr'],
623
								   $radiusservers[0]['acctport'],
624
								   $radiusservers[0]['key'],
625
								   $cpdb[$i][2], // clientip
626
								   $cpdb[$i][3], // clientmac
627
								   7); // Admin Reboot
628
		}
629
	}
630
	captiveportal_unlock();
631 5b237745 Scott Ullrich
}
632
633
function captiveportal_passthrumac_configure() {
634
	global $config, $g;
635 36254e4a Scott Ullrich
636 3db19cf1 Scott Ullrich
	captiveportal_lock();
637 36254e4a Scott Ullrich
638 5b237745 Scott Ullrich
	/* clear out passthru macs, if necessary */
639 3db19cf1 Scott Ullrich
	unlink_if_exists("{$g['vardb_path']}/captiveportal_mac.db");
640 36254e4a Scott Ullrich
641 5b237745 Scott Ullrich
	if (is_array($config['captiveportal']['passthrumac'])) {
642 36254e4a Scott Ullrich
643 5b237745 Scott Ullrich
		$fd = @fopen("{$g['vardb_path']}/captiveportal_mac.db", "w");
644
		if (!$fd) {
645
			printf("Error: cannot open passthru mac DB file in captiveportal_passthrumac_configure().\n");
646 3db19cf1 Scott Ullrich
			captiveportal_unlock();
647 36254e4a Scott Ullrich
			return 1;
648 5b237745 Scott Ullrich
		}
649 36254e4a Scott Ullrich
650 5b237745 Scott Ullrich
		foreach ($config['captiveportal']['passthrumac'] as $macent) {
651
			/* record passthru mac so it can be recognized and let thru */
652
			fwrite($fd, $macent['mac'] . "\n");
653
		}
654 36254e4a Scott Ullrich
655
		fclose($fd);
656 5b237745 Scott Ullrich
	}
657 0bd34ed6 Scott Ullrich
658 1de584c9 Scott Ullrich
	/*    pass through mac entries should always exist.  the reason
659
	 *    for this is because we do not have native mac address filtering
660
         *    mechanisms.  this allows us to filter by mac address easily
661
	 *    and get around this limitation.   I consider this a bug in
662 36254e4a Scott Ullrich
         *    m0n0wall and pfSense as m0n0wall does not have native mac
663 1de584c9 Scott Ullrich
         *    filtering mechanisms as well. -Scott Ullrich
664
         */
665
	if (is_array($config['captiveportal']['passthrumac'])) {
666
		mwexec("/sbin/ipfw delete 50");
667
		foreach($config['captiveportal']['passthrumac'] as $ptm) {
668
			/* create the pass through mac entry */
669 12249cad Scott Ullrich
			//system("echo /sbin/ipfw add 50 skipto 65535 ip from any to any MAC {$ptm['mac']} any > /tmp/cp");
670 5d61b44e Scott Ullrich
			mwexec("/sbin/ipfw add 50 skipto 29900 ip from any to any MAC {$ptm['mac']} any keep-state");
671
			mwexec("/sbin/ipfw add 50 skipto 29900 ip from any to any MAC any {$ptm['mac']} keep-state");
672 1de584c9 Scott Ullrich
		}
673
	}
674 0bd34ed6 Scott Ullrich
675 3db19cf1 Scott Ullrich
	captiveportal_unlock();
676 36254e4a Scott Ullrich
677 5b237745 Scott Ullrich
	return 0;
678
}
679
680
function captiveportal_allowedip_configure() {
681
	global $config, $g;
682 36254e4a Scott Ullrich
683 3db19cf1 Scott Ullrich
	captiveportal_lock();
684 5b237745 Scott Ullrich
685
	/* clear out existing allowed ips, if necessary */
686
	if (file_exists("{$g['vardb_path']}/captiveportal_ip.db")) {
687
		$fd = @fopen("{$g['vardb_path']}/captiveportal_ip.db", "r");
688
		if ($fd) {
689
			while (!feof($fd)) {
690
				$line = trim(fgets($fd));
691 3db19cf1 Scott Ullrich
				if ($line) {
692 5b237745 Scott Ullrich
					list($ip,$rule) = explode(",",$line);
693 3db19cf1 Scott Ullrich
					mwexec("/sbin/ipfw delete $rule");
694 36254e4a Scott Ullrich
				}
695 5b237745 Scott Ullrich
			}
696
		}
697 3db19cf1 Scott Ullrich
		fclose($fd);
698 5b237745 Scott Ullrich
		unlink("{$g['vardb_path']}/captiveportal_ip.db");
699
	}
700
701 3db19cf1 Scott Ullrich
	/* get next ipfw rule number */
702
	if (file_exists("{$g['vardb_path']}/captiveportal.nextrule"))
703
		$ruleno = trim(file_get_contents("{$g['vardb_path']}/captiveportal.nextrule"));
704
	if (!$ruleno)
705
		$ruleno = 10000;	/* first rule number */
706 36254e4a Scott Ullrich
707 5b237745 Scott Ullrich
	if (is_array($config['captiveportal']['allowedip'])) {
708 36254e4a Scott Ullrich
709 5b237745 Scott Ullrich
		$fd = @fopen("{$g['vardb_path']}/captiveportal_ip.db", "w");
710
		if (!$fd) {
711
			printf("Error: cannot open allowed ip DB file in captiveportal_allowedip_configure().\n");
712 3db19cf1 Scott Ullrich
			captiveportal_unlock();
713 36254e4a Scott Ullrich
			return 1;
714 5b237745 Scott Ullrich
		}
715 36254e4a Scott Ullrich
716 5b237745 Scott Ullrich
		foreach ($config['captiveportal']['allowedip'] as $ipent) {
717 36254e4a Scott Ullrich
718 5b237745 Scott Ullrich
			/* record allowed ip so it can be recognized and removed later */
719 3db19cf1 Scott Ullrich
			fwrite($fd, $ipent['ip'] . "," . $ruleno ."\n");
720 36254e4a Scott Ullrich
721 3db19cf1 Scott Ullrich
			/* insert ipfw rule to allow ip thru */
722
			if ($ipent['dir'] == "from") {
723
				mwexec("/sbin/ipfw add $ruleno set 2 skipto 50000 ip from " . $ipent['ip'] . " to any in");
724
				mwexec("/sbin/ipfw add $ruleno set 2 skipto 50000 ip from any to " . $ipent['ip'] . " out");
725
			} else {
726
				mwexec("/sbin/ipfw add $ruleno set 2 skipto 50000 ip from any to " . $ipent['ip'] . " in");
727
				mwexec("/sbin/ipfw add $ruleno set 2 skipto 50000 ip from " . $ipent['ip'] . " to any out");
728
			}
729 36254e4a Scott Ullrich
730 3db19cf1 Scott Ullrich
			$ruleno++;
731
			if ($ruleno > 19899)
732
				$ruleno = 10000;
733 5b237745 Scott Ullrich
		}
734 36254e4a Scott Ullrich
735
		fclose($fd);
736 5b237745 Scott Ullrich
737
		/* write next rule number */
738
		$fd = @fopen("{$g['vardb_path']}/captiveportal.nextrule", "w");
739
		if ($fd) {
740
			fwrite($fd, $ruleno);
741
			fclose($fd);
742
		}
743
	}
744 36254e4a Scott Ullrich
745 3db19cf1 Scott Ullrich
	captiveportal_unlock();
746 5b237745 Scott Ullrich
	return 0;
747
}
748
749 3db19cf1 Scott Ullrich
/* get last activity timestamp given ipfw rule number */
750
function captiveportal_get_last_activity($ruleno) {
751 36254e4a Scott Ullrich
752 d99f7864 Scott Ullrich
	$ipfwoutput = "";
753 36254e4a Scott Ullrich
754 d99f7864 Scott Ullrich
	exec("/sbin/ipfw -T list {$ruleno} 2>/dev/null", $ipfwoutput);
755
756
	/* in */
757
	if ($ipfwoutput[0]) {
758
		$ri = explode(" ", $ipfwoutput[0]);
759
		if ($ri[1])
760
			return $ri[1];
761
	}
762 36254e4a Scott Ullrich
763 d99f7864 Scott Ullrich
	return 0;
764 5b237745 Scott Ullrich
}
765
766
/* read RADIUS servers into array */
767
function captiveportal_get_radius_servers() {
768 0bd34ed6 Scott Ullrich
769
        global $g;
770
771
        if (file_exists("{$g['vardb_path']}/captiveportal_radius.db")) {
772
                $fd = @fopen("{$g['vardb_path']}/captiveportal_radius.db","r");
773
                if ($fd) {
774
                        $radiusservers = array();
775
                        while (!feof($fd)) {
776
                                $line = trim(fgets($fd));
777
                                if ($line) {
778
                                        $radsrv = array();
779
                                        list($radsrv['ipaddr'],$radsrv['port'],$radsrv['acctport'],$radsrv['key']) = explode(",",$line);
780
                                        $radiusservers[] = $radsrv;
781
                                }
782
                        }
783
                        fclose($fd);
784
785
                        return $radiusservers;
786
                }
787
        }
788
789
        return false;
790 5b237745 Scott Ullrich
}
791
792
/* lock captive portal information, decide that the lock file is stale after
793
   10 seconds */
794
function captiveportal_lock() {
795 0bd34ed6 Scott Ullrich
796
        global $lockfile;
797
798
        $n = 0;
799
        while ($n < 10) {
800
                /* open the lock file in append mode to avoid race condition */
801
                if ($fd = @fopen($lockfile, "x")) {
802
                        /* succeeded */
803
                        fclose($fd);
804
                        return;
805
                } else {
806
                        /* file locked, wait and try again */
807
                        sleep(1);
808
                        $n++;
809
                }
810
        }
811 5b237745 Scott Ullrich
}
812
813 0bd34ed6 Scott Ullrich
/* unlock captive portal information file */
814 5b237745 Scott Ullrich
function captiveportal_unlock() {
815 0bd34ed6 Scott Ullrich
816
        global $lockfile;
817
818
        if (file_exists($lockfile))
819
                unlink($lockfile);
820 5b237745 Scott Ullrich
}
821
822 3db19cf1 Scott Ullrich
/* log successful captive portal authentication to syslog */
823
/* part of this code from php.net */
824 0bd34ed6 Scott Ullrich
function captiveportal_logportalauth($user,$mac,$ip,$status, $message = null) {
825 d99f7864 Scott Ullrich
	define_syslog_variables();
826
	$message = trim($message);
827
	openlog("logportalauth", LOG_PID, LOG_LOCAL4);
828
	// Log it
829
	if (!$message)
830
	syslog(LOG_INFO, "$status: $user, $mac, $ip");
831
	else
832
	syslog(LOG_INFO, "$status: $user, $mac, $ip, $message");
833
	closelog();
834 3db19cf1 Scott Ullrich
}
835
836 0bd34ed6 Scott Ullrich
function radius($username,$password,$clientip,$clientmac,$type) {
837 d99f7864 Scott Ullrich
	global $g, $config;
838
839
	$next_ruleno = get_next_ipfw_ruleno();
840
	$radiusservers = captiveportal_get_radius_servers();
841
	$radacct_enable = isset($config['captiveportal']['radacct_enable']);
842
843
	$auth_list = RADIUS_AUTHENTICATION($username,
844
					$password,
845
					$radiusservers,
846
					$clientip,
847
					$clientmac,
848
					$next_ruleno);
849
850
	if ($auth_list['auth_val'] == 2) {
851
		captiveportal_logportalauth($username,$clientmac,$clientip,$type);
852
		$sessionid = portal_allow($clientip,
853
					$clientmac,
854
					$username,
855
					$password,
856
					$auth_list['session_timeout'],
857
					$auth_list['idle_timeout'],
858
					$auth_list['url_redirection'],
859
					$auth_list['session_terminate_time']);
860
861
		if ($radacct_enable) {
862
			$auth_list['acct_val'] = RADIUS_ACCOUNTING_START($next_ruleno,
863
									$username,
864
									$sessionid,
865
									$radiusservers[0]['ipaddr'],
866
									$radiusservers[0]['acctport'],
867
									$radiusservers[0]['key'],
868
									$clientip,
869
									$clientmac);
870
			if ($auth_list['acct_val'] == 1)
871
				captiveportal_logportalauth($username,$clientmac,$clientip,$type,"RADIUS ACCOUNTING FAILED");
872
		}
873
	}
874 0bd34ed6 Scott Ullrich
875 d99f7864 Scott Ullrich
	return $auth_list;
876 0bd34ed6 Scott Ullrich
877
}
878
879
/* read captive portal DB into array */
880
function captiveportal_read_db() {
881
882
        global $g;
883
884
        $cpdb = array();
885
        $fd = @fopen("{$g['vardb_path']}/captiveportal.db", "r");
886
        if ($fd) {
887
                while (!feof($fd)) {
888
                        $line = trim(fgets($fd));
889
                        if ($line) {
890
                                $cpdb[] = explode(",", $line);
891
                        }
892
                }
893
                fclose($fd);
894
        }
895
        return $cpdb;
896
}
897
898
/* write captive portal DB */
899
function captiveportal_write_db($cpdb) {
900 36254e4a Scott Ullrich
901 0bd34ed6 Scott Ullrich
        global $g;
902 36254e4a Scott Ullrich
903 0bd34ed6 Scott Ullrich
        $fd = @fopen("{$g['vardb_path']}/captiveportal.db", "w");
904 36254e4a Scott Ullrich
        if ($fd) {
905 0bd34ed6 Scott Ullrich
                foreach ($cpdb as $cpent) {
906
                        fwrite($fd, join(",", $cpent) . "\n");
907 36254e4a Scott Ullrich
                }
908 0bd34ed6 Scott Ullrich
                fclose($fd);
909 36254e4a Scott Ullrich
        }
910 0bd34ed6 Scott Ullrich
}
911
912
function captiveportal_write_elements() {
913 d99f7864 Scott Ullrich
	global $g, $config;
914
915
	/* delete any existing elements */
916
	if (is_dir($g['captiveportal_element_path'])) {
917
		$dh = opendir($g['captiveportal_element_path']);
918
		while (($file = readdir($dh)) !== false) {
919
			if ($file != "." && $file != "..")
920
				unlink($g['captiveportal_element_path'] . "/" . $file);
921
		}
922
		closedir($dh);
923
	} else {
924
		mkdir($g['captiveportal_element_path']);
925
	}
926 36254e4a Scott Ullrich
927 d99f7864 Scott Ullrich
	if (is_array($config['captiveportal']['element'])) {
928
		conf_mount_rw();
929
		foreach ($config['captiveportal']['element'] as $data) {
930
			$fd = @fopen($g['captiveportal_element_path'] . '/' . $data['name'], "wb");
931
			if (!$fd) {
932
				printf("Error: cannot open '{$data['name']}' in captiveportal_write_elements().\n");
933
				return 1;
934
			}
935
			$decoded = base64_decode($data['content']);
936
			fwrite($fd,$decoded);
937
			fclose($fd);
938
			unlink_if_exists("{$g['captiveportal_path']}/{$data['name']}");
939
			unlink_if_exists("{$g['captiveportal_path']}/{$data['name']}");
940
			mwexec("cd {$g['captiveportal_path']}/ && ln -s {$g['captiveportal_element_path']}/{$data['name']} {$data['name']}");
941
		}
942
		conf_mount_ro();
943
	}
944 36254e4a Scott Ullrich
945 d99f7864 Scott Ullrich
	return 0;
946 0bd34ed6 Scott Ullrich
}
947
948 6d8f4f75 Scott Ullrich
/*
949
 * This function will calculate the lowest free firewall ruleno
950
 * within the range specified based on the actual installed rules
951
 *
952
 */
953
954
function get_next_ipfw_ruleno($rulenos_start = 10000, $rulenos_range_max = 9899) {
955
956 84e5047d Scott Ullrich
	$fwrules = "";
957
	$matches = "";
958 6d8f4f75 Scott Ullrich
	exec("/sbin/ipfw show", $fwrules);
959
	foreach ($fwrules as $fwrule) {
960
		preg_match("/^(\d+)\s+/", $fwrule, $matches);
961
		$rulenos_used[] = $matches[1];
962
	}
963
	$rulenos_used = array_unique($rulenos_used);
964
	$rulenos_range = count($rulenos_used);
965
	if ($rulenos_range > $rulenos_range_max) {
966
		return NULL;
967
	}
968
	$rulenos_pool = range($rulenos_start, ($rulenos_start + $rulenos_range));
969
	$rulenos_free = array_diff($rulenos_pool, $rulenos_used);
970
	$ruleno = array_shift($rulenos_free);
971
972
	return $ruleno;
973
}
974
975 920cafaf Scott Ullrich
/*
976
 * This function will calculate the lowest free firewall ruleno
977
 * within the range specified based on the actual installed rules
978
 *
979
 */
980
981
function captiveportal_get_next_ipfw_ruleno($rulenos_start = 10000, $rulenos_range_max = 9899) {
982
983 84e5047d Scott Ullrich
	$fwrules = "";
984
	$matches = "";
985 920cafaf Scott Ullrich
	exec("/sbin/ipfw show", $fwrules);
986
	foreach ($fwrules as $fwrule) {
987
		preg_match("/^(\d+)\s+/", $fwrule, $matches);
988
		$rulenos_used[] = $matches[1];
989
	}
990
	$rulenos_used = array_unique($rulenos_used);
991
	$rulenos_range = count($rulenos_used);
992
	if ($rulenos_range > $rulenos_range_max) {
993
		return NULL;
994
	}
995
	$rulenos_pool = range($rulenos_start, ($rulenos_start + $rulenos_range));
996
	$rulenos_free = array_diff($rulenos_pool, $rulenos_used);
997
	$ruleno = array_shift($rulenos_free);
998
999
	return $ruleno;
1000
}
1001
1002 360d815d Scott Ullrich
/**
1003
 * This function will calculate the traffic produced by a client
1004
 * based on its firewall rule
1005
 *
1006
 * Point of view: NAS
1007
 *
1008
 * Input means: from the client
1009
 * Output means: to the client
1010
 *
1011
 */
1012
1013
function getVolume($ruleno) {
1014
1015
    $volume = array();
1016
1017
    // Initialize vars properly, since we don't want NULL vars
1018
    $volume['input_pkts'] = $volume['input_bytes'] = $volume['output_pkts'] = $volume['output_bytes'] = 0 ;
1019
1020
    // Ingress
1021 84e5047d Scott Ullrich
    $ipfw = "";
1022
    $matches = "";
1023 360d815d Scott Ullrich
    exec("/sbin/ipfw show {$ruleno}", $ipfw);
1024
    preg_match("/(\d+)\s+(\d+)\s+(\d+)\s+.*/", $ipfw[0], $matches);
1025
    $volume['input_pkts'] = $matches[2];
1026
    $volume['input_bytes'] = $matches[3];
1027
1028
    // Flush internal buffer
1029
    unset($matches);
1030
1031
    // Outgress
1032
    preg_match("/(\d+)\s+(\d+)\s+(\d+)\s+.*/", $ipfw[1], $matches);
1033
    $volume['output_pkts'] = $matches[2];
1034
    $volume['output_bytes'] = $matches[3];
1035
1036
    return $volume;
1037
}
1038
1039 856e58a6 Scott Ullrich
/**
1040
 * Get the NAS-Identifier
1041
 *
1042
 * We will use our local hostname to make up the nas_id
1043
 */
1044
function getNasID()
1045
{
1046 84e5047d Scott Ullrich
    $nasId = "";
1047 856e58a6 Scott Ullrich
    exec("/bin/hostname", $nasId);
1048
    if(!$nasId[0])
1049
        $nasId[0] = "pfSense";
1050
    return $nasId[0];
1051
}
1052
1053
/**
1054
 * Get the NAS-IP-Address based on the current wan address
1055
 *
1056
 * Use functions in interfaces.inc to find this out
1057
 *
1058
 */
1059
1060
function getNasIP()
1061
{
1062
    $nasIp = get_current_wan_address();
1063
    if(!$nasIp)
1064
        $nasIp = "0.0.0.0";
1065
    return $nasIp;
1066
}
1067
1068 36254e4a Scott Ullrich
?>