Project

General

Profile

Download (40.3 KB) Statistics
| Branch: | Tag: | Revision:
1
<?php
2
/*
3
	captiveportal.inc
4
	part of m0n0wall (http://m0n0.ch/wall)
5

    
6
	Copyright (C) 2009 Ermal Lu?i
7
	Copyright (C) 2003-2006 Manuel Kasper <mk@neon1.net>.
8
	All rights reserved.
9

    
10
	Redistribution and use in source and binary forms, with or without
11
	modification, are permitted provided that the following conditions are met:
12

    
13
	1. Redistributions of source code must retain the above copyright notice,
14
	   this list of conditions and the following disclaimer.
15

    
16
	2. Redistributions in binary form must reproduce the above copyright
17
	   notice, this list of conditions and the following disclaimer in the
18
	   documentation and/or other materials provided with the distribution.
19

    
20
	THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
21
	INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
22
	AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
23
	AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
24
	OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25
	SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26
	INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27
	CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28
	ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29
	POSSIBILITY OF SUCH DAMAGE.
30

    
31
	This version of captiveportal.inc has been modified by Rob Parker
32
	<rob.parker@keycom.co.uk> to include changes for per-user bandwidth management
33
	via returned RADIUS attributes. This page has been modified to delete any
34
	added rules which may have been created by other per-user code (index.php, etc).
35
	These changes are (c) 2004 Keycom PLC.
36
	
37
	pfSense_BUILDER_BINARIES:	/sbin/ifconfig	/sbin/ipfw	/sbin/sysctl	/sbin/kldunload
38
	pfSense_BUILDER_BINARIES:	/usr/local/sbin/lighttpd	/usr/local/bin/minicron	/sbin/pfctl
39
	pfSense_BUILDER_BINARIES:	/bin/hostname	/bin/cp	
40
	pfSense_MODULE:	captiveportal
41
*/
42

    
43
/* include all configuration functions */
44
require_once("config.inc");
45
require_once("functions.inc");
46
require_once("filter.inc");
47
require_once("radius.inc");
48
require_once("voucher.inc");
49

    
50
function captiveportal_configure() {
51
	global $config, $g;
52

    
53
	$captiveportallck = lock('captiveportal');
54
	
55
	$cpactive = false;
56
	if (isset($config['captiveportal']['enable'])) {
57
		$cpips = array();
58
		$ifaces = get_configured_interface_list();
59
		foreach ($ifaces as $kiface => $kiface2) {
60
			$tmpif = get_real_interface($kiface);
61
			mwexec("/sbin/ifconfig {$tmpif} -ipfwfilter");
62
		}
63
		$cpinterfaces = explode(",", $config['captiveportal']['interface']);
64
		$firsttime = 0;
65
		foreach ($cpinterfaces as $cpifgrp) {
66
			if (!isset($ifaces[$cpifgrp]))
67
				continue;
68
			$tmpif = get_real_interface($cpifgrp);
69
			if (!empty($tmpif)) {
70
				if ($firsttime > 0)
71
					$cpinterface .= " or ";
72
				$cpinterface .= "via {$tmpif}"; 
73
				$firsttime = 1;
74
				$cpipm = get_interface_ip($cpifgrp);
75
				if (is_ipaddr($cpipm)) {
76
					$carpif = link_ip_to_carp_interface($cpipm);
77
					if (!empty($carpif)) {
78
						$carpsif = explode(" ", $carpif);
79
						foreach ($carpsif as $cpcarp) {
80
							mwexec("/sbin/ifconfig {$cpcarp} ipfwfilter");
81
							$carpip = find_interface_ip($cpcarp);
82
							if (is_ipaddr($carpip))
83
								$cpips[] = $carpip;
84
						}
85
					}
86
					$cpips[] = $cpipm;
87
					mwexec("/sbin/ifconfig {$tmpif} ipfwfilter");
88
				}
89
			}
90
		}
91
		if (count($cpips) > 0) {
92
			$cpactive = true;
93
			$cpinterface = "{ {$cpinterface} } ";
94
		}
95
	}
96

    
97
	if ($cpactive == true) {
98

    
99
		if ($g['booting'])
100
			echo "Starting captive portal... ";
101

    
102
		/* kill any running mini_httpd */
103
		killbypid("{$g['varrun_path']}/lighty-CaptivePortal.pid");
104
		killbypid("{$g['varrun_path']}/lighty-CaptivePortal-SSL.pid");
105

    
106
		/* remove old information */
107
		unlink_if_exists("{$g['vardb_path']}/captiveportal.db");
108
		unlink_if_exists("{$g['vardb_path']}/captiveportal_mac.db");
109
		unlink_if_exists("{$g['vardb_path']}/captiveportal_ip.db");
110
		unlink_if_exists("{$g['vardb_path']}/captiveportal_radius.db");
111
		mwexec("/sbin/ipfw -q table all flush");
112

    
113
		/* setup new database in case someone tries to access the status -> captive portal page */
114
		touch("{$g['vardb_path']}/captiveportal.db");
115

    
116
		/* kill any running minicron */
117
		killbypid("{$g['varrun_path']}/minicron.pid");
118

    
119
		/* make sure ipfw is loaded */
120
		if (!is_module_loaded("ipfw.ko"))
121
			filter_load_ipfw();
122
		/* Always load dummynet now that even allowed ip and mac passthrough use it. */
123
		if (!is_module_loaded("dummynet.ko"))
124
                        mwexec("/sbin/kldload dummynet");
125

    
126
		/* generate ipfw rules */
127
		captiveportal_init_ipfw_ruleno();
128
		$cprules = captiveportal_rules_generate($cpinterface, $cpips);
129
		$cprules .= "\n";
130
		/* generate passthru mac database */
131
		$cprules .= captiveportal_passthrumac_configure(true);
132
		$cprules .= "\n";
133
		/* allowed ipfw rules to make allowed ip work */
134
		$cprules .= captiveportal_allowedip_configure();
135

    
136
		/* stop accounting on all clients */
137
		captiveportal_radius_stop_all(true);
138

    
139
		/* initialize minicron interval value */
140
		$croninterval = $config['captiveportal']['croninterval'] ? $config['captiveportal']['croninterval'] : 60;
141

    
142
		/* double check if the $croninterval is numeric and at least 10 seconds. If not we set it to 60 to avoid problems */
143
		if ((!is_numeric($croninterval)) || ($croninterval < 10)) { $croninterval = 60; }
144

    
145
		/* write portal page */
146
		if ($config['captiveportal']['page']['htmltext'])
147
			$htmltext = base64_decode($config['captiveportal']['page']['htmltext']);
148
		else {
149
			/* example/template page */
150
			$htmltext = <<<EOD
151
<html>
152
<head>
153
<title>{$g['product_name']} captive portal</title>
154
</head>
155
<body>
156
<center>
157
<h2>{$g['product_name']} captive portal</h2>
158
Welcome to the {$g['product_name']} Captive Portal!
159
<p>
160
<form method="post" action="\$PORTAL_ACTION\$">
161
<input name="redirurl" type="hidden" value="\$PORTAL_REDIRURL\$">
162
<table>
163
   <tr><td>Username:</td><td><input name="auth_user" type="text"></td></tr>
164
   <tr><td>Password:</td><td><input name="auth_pass" type="password"></td></tr>
165
   <tr><td>&nbsp;</td></tr>
166
   <tr>
167
     <td colspan="2">
168
	<center><input name="accept" type="submit" value="Continue"></center>
169
     </td>
170
   </tr>
171
</table>
172
</center>
173
</form>
174
</body>
175
</html>
176

    
177

    
178

    
179
EOD;
180
		}
181

    
182
		$fd = @fopen("{$g['varetc_path']}/captiveportal.html", "w");
183
		if ($fd) {
184
			// Special case handling.  Convert so that we can pass this page
185
			// through the PHP interpreter later without clobbering the vars.
186
			$htmltext = str_replace("\$PORTAL_REDIRURL\$", "#PORTAL_REDIRURL#", $htmltext);
187
			$htmltext = str_replace("\$PORTAL_MESSAGE\$", "#PORTAL_MESSAGE#", $htmltext);
188
			$htmltext = str_replace("\$CLIENT_MAC\$", "#CLIENT_MAC#", $htmltext);
189
			$htmltext = str_replace("\$CLIENT_IP\$", "#CLIENT_IP#", $htmltext);
190
			$htmltext = str_replace("\$ORIGINAL_PORTAL_IP\$", "#ORIGINAL_PORTAL_IP#", $htmltext);
191
			$htmltext = str_replace("\$PORTAL_ACTION\$", "#PORTAL_ACTION#", $htmltext);
192
			fwrite($fd, $htmltext);
193
			fclose($fd);
194
		}
195

    
196
		/* write error page */
197
		if ($config['captiveportal']['page']['errtext'])
198
			$errtext = base64_decode($config['captiveportal']['page']['errtext']);
199
		else {
200
			/* example page */
201
			$errtext = <<<EOD
202
<html>
203
<head>
204
<title>Authentication error</title>
205
</head>
206
<body>
207
<font color="#cc0000"><h2>Authentication error</h2></font>
208
<b>
209
Username and/or password invalid.
210
<br><br>
211
<a href="javascript:history.back(); ">Go back</a>
212
</b>
213
</body>
214
</html>
215

    
216
EOD;
217
		}
218

    
219
		$fd = @fopen("{$g['varetc_path']}/captiveportal-error.html", "w");
220
		if ($fd) {
221
			// Special case handling.  Convert so that we can pass this page
222
			// through the PHP interpreter later without clobbering the vars.
223
			$errtext = str_replace("\$PORTAL_REDIRURL\$", "#PORTAL_REDIRURL#", $errtext);
224
			$errtext = str_replace("\$PORTAL_MESSAGE\$", "#PORTAL_MESSAGE#", $errtext);
225
			$errtext = str_replace("\$CLIENT_MAC\$", "#CLIENT_MAC#", $errtext);
226
			$errtext = str_replace("\$CLIENT_IP\$", "#CLIENT_IP#", $errtext);
227
			$errtext = str_replace("\$ORIGINAL_PORTAL_IP\$", "#ORIGINAL_PORTAL_IP#", $errtext);
228
			$errtext = str_replace("\$PORTAL_ACTION\$", "#PORTAL_ACTION#", $errtext);
229
			fwrite($fd, $errtext);
230
			fclose($fd);
231
		}
232

    
233
		/* write elements */
234
		captiveportal_write_elements();
235

    
236
		/* load rules */
237
		mwexec("/sbin/ipfw -q flush");
238

    
239
		/* ipfw cannot accept rules directly on stdin,
240
		   so we have to write them to a temporary file first */
241
		$fd = @fopen("{$g['tmp_path']}/ipfw.cp.rules", "w");
242
		if (!$fd) {
243
			printf("Cannot open ipfw.cp.rules in captiveportal_configure()\n");
244
			return 1;
245
		}
246

    
247
		fwrite($fd, $cprules);
248
		fclose($fd);
249

    
250
		mwexec("/sbin/ipfw -q {$g['tmp_path']}/ipfw.cp.rules");
251

    
252
		@unlink("{$g['tmp_path']}/ipfw.cp.rules");
253

    
254
		/* filter on layer2 as well so we can check MAC addresses */
255
		mwexec("/sbin/sysctl net.link.ether.ipfw=1");
256

    
257
		chdir($g['captiveportal_path']);
258

    
259
		if ($config['captiveportal']['maxproc'])
260
			$maxproc = $config['captiveportal']['maxproc'];
261
		else
262
			$maxproc = 16;
263

    
264
		$use_fastcgi = true;
265

    
266
		if(isset($config['captiveportal']['httpslogin'])) {
267
			$cert = base64_decode($config['captiveportal']['certificate']);
268
			if (isset($config['captiveportal']['cacertificate']))
269
				$cacert = base64_decode($config['captiveportal']['cacertificate']);
270
			else
271
				$cacert = "";
272
			$key = base64_decode($config['captiveportal']['private-key']);
273
			/* generate lighttpd configuration */
274
			system_generate_lighty_config("{$g['varetc_path']}/lighty-CaptivePortal-SSL.conf",
275
				$cert, $key, $cacert, "lighty-CaptivePortal-ssl.pid", "8001", "/usr/local/captiveportal/",
276
					"cert-portal.pem", "ca-portal.pem", "1", $maxproc, $use_fastcgi, true);
277
		}
278

    
279
		/* generate lighttpd configuration */
280
		system_generate_lighty_config("{$g['varetc_path']}/lighty-CaptivePortal.conf",
281
			"", "", "", "lighty-CaptivePortal.pid", "8000", "/usr/local/captiveportal/",
282
				"cert-portal.pem", "ca-portal.pem", "1", $maxproc, $use_fastcgi, true);
283

    
284
		/* attempt to start lighttpd */
285
		$res = mwexec("/usr/local/sbin/lighttpd -f {$g['varetc_path']}/lighty-CaptivePortal.conf");
286

    
287
		/* fire up https instance */
288
		if(isset($config['captiveportal']['httpslogin']))
289
			$res = mwexec("/usr/local/sbin/lighttpd -f {$g['varetc_path']}/lighty-CaptivePortal-SSL.conf");
290

    
291
		/* start pruning process (interval defaults to 60 seconds) */
292
		mwexec("/usr/local/bin/minicron $croninterval {$g['varrun_path']}/minicron.pid " .
293
			"/etc/rc.prunecaptiveportal");
294

    
295
		/* generate radius server database */
296
		if ($config['captiveportal']['radiusip'] && (!isset($config['captiveportal']['auth_method']) ||
297
				($config['captiveportal']['auth_method'] == "radius"))) {
298
			$radiusip = $config['captiveportal']['radiusip'];
299
			$radiusip2 = ($config['captiveportal']['radiusip2']) ? $config['captiveportal']['radiusip2'] : null;
300

    
301
			if ($config['captiveportal']['radiusport'])
302
				$radiusport = $config['captiveportal']['radiusport'];
303
			else
304
				$radiusport = 1812;
305

    
306
			if ($config['captiveportal']['radiusacctport'])
307
				$radiusacctport = $config['captiveportal']['radiusacctport'];
308
			else
309
				$radiusacctport = 1813;
310

    
311
			if ($config['captiveportal']['radiusport2'])
312
				$radiusport2 = $config['captiveportal']['radiusport2'];
313
			else
314
				$radiusport2 = 1812;
315

    
316
			$radiuskey = $config['captiveportal']['radiuskey'];
317
			$radiuskey2 = ($config['captiveportal']['radiuskey2']) ? $config['captiveportal']['radiuskey2'] : null;
318

    
319
			$fd = @fopen("{$g['vardb_path']}/captiveportal_radius.db", "w");
320
			if (!$fd) {
321
				printf("Error: cannot open radius DB file in captiveportal_configure().\n");
322
				return 1;
323
			} else if (isset($radiusip2, $radiuskey2)) {
324
				fwrite($fd,$radiusip . "," . $radiusport . "," . $radiusacctport . "," . $radiuskey . "\n"
325
					 . $radiusip2 . "," . $radiusport2 . "," . $radiusacctport . "," . $radiuskey2);
326
			} else {
327
				fwrite($fd,$radiusip . "," . $radiusport . "," . $radiusacctport . "," . $radiuskey);
328
			}
329
			fclose($fd);
330
		}
331

    
332
		if ($g['booting'])
333
			echo "done\n";
334

    
335
	} else {
336
		killbypid("{$g['varrun_path']}/lighty-CaptivePortal.pid");
337
		killbypid("{$g['varrun_path']}/minicron.pid");
338

    
339
		captiveportal_radius_stop_all(true);
340

    
341
		mwexec("/sbin/sysctl net.link.ether.ipfw=0");
342

    
343
		/* unload ipfw */
344
		if (is_module_loaded("ipfw.ko"))		
345
			mwexec("/sbin/kldunload ipfw.ko");
346
		$listifs = get_configured_interface_list_by_realif();
347
		foreach ($listifs as $listrealif => $listif) {
348
			if (!empty($listrealif)) {
349
				if (does_interface_exist($listrealif)) {
350
					mwexec("/sbin/ifconfig {$listrealif} -ipfwfilter");
351
					$carpif = link_ip_to_carp_interface(find_interface_ip($listrealif));
352
                        		if (!empty($carpif)) {
353
						$carpsif = explode(" ", $carpif);
354
						foreach ($carpsif as $cpcarp)
355
							mwexec("/sbin/ifconfig {$cpcarp} -ipfwfilter");
356
					}
357
				}
358
			}
359
		}
360
	}
361

    
362
	unlock($captiveportallck);
363
	
364
	return 0;
365
}
366

    
367
function captiveportal_rules_generate($cpif, &$cpiparray) {
368
	global $config, $g;
369

    
370
	$cprules =  "add 65291 set 1 allow pfsync from any to any\n";
371
	$cprules .= "add 65292 set 1 allow carp from any to any\n";
372

    
373
	$cprules .= <<<EOD
374
# add 65300 set 1 skipto 65534 all from any to any not layer2
375
# layer 2: pass ARP
376
add 65301 set 1 pass layer2 mac-type arp
377
# pfsense requires for WPA
378
add 65302 set 1 pass layer2 mac-type 0x888e
379
add 65303 set 1 pass layer2 mac-type 0x88c7
380

    
381
# PPP Over Ethernet Discovery Stage
382
add 65304 set 1 pass layer2 mac-type 0x8863
383
# PPP Over Ethernet Session Stage
384
add 65305 set 1 pass layer2 mac-type 0x8864
385
# Allow WPA
386
add 65306 set 1 pass layer2 mac-type 0x888e
387

    
388
# layer 2: block anything else non-IP
389
add 65307 set 1 deny layer2 not mac-type ip
390

    
391
EOD;
392

    
393
	$rulenum = 65310;
394
	$ips = "255.255.255.255 ";
395
	foreach ($cpiparray as $cpip)
396
		$ips .= "or {$cpip} ";
397
	$ips = "{ {$ips} }";
398
	//# allow access to our DHCP server (which needs to be able to ping clients as well)
399
	$cprules .= "add {$rulenum} set 1 pass udp from any 68 to {$ips} 67 in \n";
400
	$rulenum++;
401
	$cprules .= "add {$rulenum} set 1 pass udp from any 68 to {$ips} 67 in \n";
402
	$rulenum++;
403
	$cprules .= "add {$rulenum} set 1 pass udp from {$ips} 67 to any 68 out \n";
404
	$rulenum++;
405
	$cprules .= "add {$rulenum} set 1 pass icmp from {$ips} to any out icmptype 0\n";
406
	$rulenum++;
407
	$cprules .= "add {$rulenum} set 1 pass icmp from any to {$ips} in icmptype 8 \n";
408
	$rulenum++;
409
	//# allow access to our DNS forwarder
410
	$cprules .= "add {$rulenum} set 1 pass udp from any to {$ips} 53 in \n";
411
	$rulenum++;
412
	$cprules .= "add {$rulenum} set 1 pass udp from {$ips} 53 to any out \n";
413
	$rulenum++;
414
	# allow access to our web server
415
	$cprules .= "add {$rulenum} set 1 pass tcp from any to {$ips} 8000 in \n";
416
	$rulenum++;
417
	$cprules .= "add {$rulenum} set 1 pass tcp from {$ips} 8000 to any out \n";
418

    
419
	if (isset($config['captiveportal']['httpslogin'])) {
420
		$rulenum++;
421
		$cprules .= "add {$rulenum} set 1 pass tcp from any to {$ips} 8001 in \n";
422
		$rulenum++;
423
		$cprules .= "add {$rulenum} set 1 pass tcp from {$ips} 8001 to any out \n";
424
	}
425
	if (!empty($config['system']['webgui']['port']))
426
		$port = $config['system']['webgui']['port'];
427
	else if ($config['system']['webgui']['proto'] == "http")
428
		$port = 80;
429
	else
430
		$port = 443;
431
	$rulenum++;
432
	$cprules .= "add {$rulenum} set 1 pass tcp from any to {$ips} {$port} in \n";
433
	$rulenum++;
434
	$cprules .= "add {$rulenum} set 1 pass tcp from {$ips} {$port} to any out \n";
435
	$rulenum++;
436

    
437
	/* Allowed ips */
438
	$cprules .= "add {$rulenum} allow ip from table(3) to any in\n";
439
	$rulenum++;
440
	$cprules .= "add {$rulenum} allow ip from any to table(4) out\n";
441
	$rulenum++;
442
	$cprules .= "add {$rulenum} pipe tablearg ip from table(5) to any in\n";
443
	$rulenum++;
444
	$cprules .= "add {$rulenum} pipe tablearg ip from any to table(6) out\n";
445
	$rulenum++;
446
	$cprules .= "add {$rulenum} allow ip from any to table(7) in\n";
447
	$rulenum++;
448
	$cprules .= "add {$rulenum} allow ip from table(8) to any out\n";
449
	$rulenum++;
450
	$cprules .= "add {$rulenum} pipe tablearg ip from any to table(9) in\n";
451
	$rulenum++;
452
	$cprules .= "add {$rulenum} pipe tablearg ip from table(10) to any out\n";
453
	$rulenum++;
454

    
455
	/* Authenticated users rules. */
456
	if (isset($config['captiveportal']['peruserbw'])) {
457
		$cprules .= "add {$rulenum} set 1 pipe tablearg ip from table(1) to any in\n";
458
		$rulenum++;
459
		$cprules .= "add {$rulenum} set 1 pipe tablearg ip from any to table(2) out\n";
460
		$rulenum++;
461
	} else {
462
		$cprules .= "add {$rulenum} set 1 allow ip from table(1) to any in\n";
463
                $rulenum++;
464
                $cprules .= "add {$rulenum} set 1 allow ip from any to table(2) out\n";
465
                $rulenum++;
466
	}
467
	
468
       $cprules .= <<<EOD
469

    
470
# redirect non-authenticated clients to captive portal
471
add 65531 set 1 fwd 127.0.0.1,8000 tcp from any to any in
472
# let the responses from the captive portal web server back out
473
add 65532 set 1 pass tcp from any to any out
474
# block everything else
475
add 65533 set 1 deny all from any to any
476
# pass everything else on layer2
477
add 65534 set 1 pass all from any to any layer2
478

    
479
EOD;
480

    
481
    return $cprules;
482
}
483

    
484
/* remove clients that have been around for longer than the specified amount of time */
485
/* db file structure:
486
timestamp,ipfw_rule_no,clientip,clientmac,username,sessionid,password,session_timeout,idle_timeout,session_terminate_time */
487

    
488
/* (password is in Base64 and only saved when reauthentication is enabled) */
489
function captiveportal_prune_old() {
490

    
491
    global $g, $config;
492

    
493
    /* check for expired entries */
494
    if ($config['captiveportal']['timeout'])
495
        $timeout = $config['captiveportal']['timeout'] * 60;
496
    else
497
        $timeout = 0;
498

    
499
    if ($config['captiveportal']['idletimeout'])
500
        $idletimeout = $config['captiveportal']['idletimeout'] * 60;
501
    else
502
        $idletimeout = 0;
503

    
504
    if (!$timeout && !$idletimeout && !isset($config['captiveportal']['reauthenticate']) && 
505
		!isset($config['captiveportal']['radiussession_timeout']) && !isset($config['voucher']['enable']))
506
        return;
507

    
508
    $captiveportallck = lock('captiveportal');
509

    
510
    /* read database */
511
    $cpdb = captiveportal_read_db();
512

    
513
    $radiusservers = captiveportal_get_radius_servers();
514

    
515
    /*  To make sure we iterate over ALL accounts on every run the count($cpdb) is moved
516
     *  outside of the loop. Otherwise the loop would evaluate count() on every iteration
517
     *  and since $i would increase and count() would decrement they would meet before we
518
     *  had a chance to iterate over all accounts.
519
     */
520
    $unsetindexes = array();
521
    $no_users = count($cpdb);
522
    for ($i = 0; $i < $no_users; $i++) {
523

    
524
        $timedout = false;
525
        $term_cause = 1;
526

    
527
        /* hard timeout? */
528
        if ($timeout) {
529
            if ((time() - $cpdb[$i][0]) >= $timeout) {
530
                $timedout = true;
531
                $term_cause = 5; // Session-Timeout
532
            }
533
        }
534

    
535
        /* Session-Terminate-Time */
536
        if (!$timedout && !empty($cpdb[$i][9])) {
537
            if (time() >= $cpdb[$i][9]) {
538
                $timedout = true;
539
                $term_cause = 5; // Session-Timeout
540
            }
541
        }
542

    
543
        /* check if the radius idle_timeout attribute has been set and if its set change the idletimeout to this value */
544
        $idletimeout = (is_numeric($cpdb[$i][8])) ? $cpdb[$i][8] : $idletimeout;
545
        /* if an idle timeout is specified, get last activity timestamp from ipfw */
546
        if (!$timedout && $idletimeout) {
547
            $lastact = captiveportal_get_last_activity($cpdb[$i][2]);
548
			/*  If the user has logged on but not sent any traffic they will never be logged out.
549
			 *  We "fix" this by setting lastact to the login timestamp. 
550
			 */
551
			$lastact = $lastact ? $lastact : $cpdb[$i][0];
552
            if ($lastact && ((time() - $lastact) >= $idletimeout)) {
553
                $timedout = true;
554
                $term_cause = 4; // Idle-Timeout
555
                $stop_time = $lastact; // Entry added to comply with WISPr
556
            }
557
        }
558

    
559
	/* if vouchers are configured, activate session timeouts */
560
	if (!$timedout && isset($config['voucher']['enable']) && !empty($cpdb[$i][7])) {
561
		if (time() >= ($cpdb[$i][0] + $cpdb[$i][7])) {
562
			$timedout = true;
563
			$term_cause = 5; // Session-Timeout
564
		}
565
	}
566

    
567
        /* if radius session_timeout is enabled and the session_timeout is not null, then check if the user should be logged out */
568
        if (!$timedout && isset($config['captiveportal']['radiussession_timeout']) && !empty($cpdb[$i][7])) {
569
            if (time() >= ($cpdb[$i][0] + $cpdb[$i][7])) {
570
                $timedout = true;
571
                $term_cause = 5; // Session-Timeout
572
            }
573
        }
574

    
575
        if ($timedout) {
576
            captiveportal_disconnect($cpdb[$i], $radiusservers,$term_cause,$stop_time);
577
            captiveportal_logportalauth($cpdb[$i][4], $cpdb[$i][3], $cpdb[$i][2], "TIMEOUT");
578
	    $unsetindexes[$i] = $i;
579
        }
580

    
581
        /* do periodic RADIUS reauthentication? */
582
        if (!$timedout && isset($config['captiveportal']['reauthenticate']) &&
583
            !empty($radiusservers)) {
584

    
585
            if (isset($config['captiveportal']['radacct_enable'])) {
586
                if ($config['captiveportal']['reauthenticateacct'] == "stopstart") {
587
                    /* stop and restart accounting */
588
                    RADIUS_ACCOUNTING_STOP($cpdb[$i][1], // ruleno
589
                                           $cpdb[$i][4], // username
590
                                           $cpdb[$i][5], // sessionid
591
                                           $cpdb[$i][0], // start time
592
                                           $radiusservers,
593
                                           $cpdb[$i][2], // clientip
594
                                           $cpdb[$i][3], // clientmac
595
                                           10); // NAS Request
596
                    exec("/sbin/ipfw table 1 entryzerostats {$cpdb[$i][2]}");
597
                    exec("/sbin/ipfw table 2 entryzerostats {$cpdb[$i][2]}");
598
                    RADIUS_ACCOUNTING_START($cpdb[$i][1], // ruleno
599
                                            $cpdb[$i][4], // username
600
                                            $cpdb[$i][5], // sessionid
601
                                            $radiusservers,
602
                                            $cpdb[$i][2], // clientip
603
                                            $cpdb[$i][3]); // clientmac
604
                } else if ($config['captiveportal']['reauthenticateacct'] == "interimupdate") {
605
                    RADIUS_ACCOUNTING_STOP($cpdb[$i][1], // ruleno
606
                                           $cpdb[$i][4], // username
607
                                           $cpdb[$i][5], // sessionid
608
                                           $cpdb[$i][0], // start time
609
                                           $radiusservers,
610
                                           $cpdb[$i][2], // clientip
611
                                           $cpdb[$i][3], // clientmac
612
                                           10, // NAS Request
613
                                           true); // Interim Updates
614
                }
615
            }
616

    
617
            /* check this user against RADIUS again */
618
            $auth_list = RADIUS_AUTHENTICATION($cpdb[$i][4], // username
619
                                          base64_decode($cpdb[$i][6]), // password
620
                                            $radiusservers,
621
                                          $cpdb[$i][2], // clientip
622
                                          $cpdb[$i][3], // clientmac
623
                                          $cpdb[$i][1]); // ruleno
624

    
625
            if ($auth_list['auth_val'] == 3) {
626
                captiveportal_disconnect($cpdb[$i], $radiusservers, 17);
627
                captiveportal_logportalauth($cpdb[$i][4], $cpdb[$i][3], $cpdb[$i][2], "RADIUS_DISCONNECT", $auth_list['reply_message']);
628
	        $unsetindexes[$i] = $i;
629
            }
630
        }
631
    }
632
    /* This is a kludge to overcome some php weirdness */
633
    foreach($unsetindexes as $unsetindex)
634
	unset($cpdb[$unsetindex]);
635

    
636
    /* write database */
637
    captiveportal_write_db($cpdb);
638

    
639
    unlock($captiveportallck);
640
}
641

    
642
/* remove a single client according to the DB entry */
643
function captiveportal_disconnect($dbent, $radiusservers,$term_cause = 1,$stop_time = null) {
644

    
645
	global $g, $config;
646

    
647
	$stop_time = (empty($stop_time)) ? time() : $stop_time;
648

    
649
	/* this client needs to be deleted - remove ipfw rules */
650
	if (isset($config['captiveportal']['radacct_enable']) && !empty($radiusservers)) {
651
		RADIUS_ACCOUNTING_STOP($dbent[1], // ruleno
652
							   $dbent[4], // username
653
							   $dbent[5], // sessionid
654
							   $dbent[0], // start time
655
							   $radiusservers,
656
							   $dbent[2], // clientip
657
							   $dbent[3], // clientmac
658
							   $term_cause, // Acct-Terminate-Cause
659
							   false,
660
							   $stop_time);
661
	}
662
	/* Delete client's ip entry from tables 3 and 4. */
663
	mwexec("/sbin/ipfw table 1 delete {$dbent[2]}");
664
	mwexec("/sbin/ipfw table 2 delete {$dbent[2]}");
665

    
666
	/* Release the ruleno so it can be reallocated to new clients. */
667
	captiveportal_free_ipfw_ruleno($dbent[1]);
668

    
669
	/* 
670
	* These are the pipe numbers we use to control traffic shaping for each logged in user via captive portal
671
	* We could get an error if the pipe doesn't exist but everything should still be fine
672
	*/
673
	if (isset($config['captiveportal']['peruserbw'])) {
674
		mwexec("/sbin/ipfw pipe " . ($dbent[1]+20000) . " delete");
675
		mwexec("/sbin/ipfw pipe " . ($dbent[1]+20001) . " delete");
676
	}
677

    
678
	/* XXX: Redundant?! Ensure all pf(4) states are killed. */
679
	mwexec("pfctl -k {$dbent[2]}");
680
	mwexec("pfctl -K {$dbent[2]}");
681

    
682
}
683

    
684
/* remove a single client by ipfw rule number */
685
function captiveportal_disconnect_client($id,$term_cause = 1) {
686

    
687
	global $g, $config;
688

    
689
	$captiveportallck = lock('captiveportal');
690

    
691
	/* read database */
692
	$cpdb = captiveportal_read_db();
693
	$radiusservers = captiveportal_get_radius_servers();
694

    
695
	/* find entry */
696
	$tmpindex = 0;
697
	$cpdbcount = count($cpdb);
698
	for ($i = 0; $i < $cpdbcount; $i++) {
699
		if ($cpdb[$i][1] == $id) {
700
			captiveportal_disconnect($cpdb[$i], $radiusservers, $term_cause);
701
			captiveportal_logportalauth($cpdb[$i][4], $cpdb[$i][3], $cpdb[$i][2], "DISCONNECT");
702
			unset($cpdb[$i]);
703
			break;
704
		}
705
	}		
706

    
707
	/* write database */
708
	captiveportal_write_db($cpdb);
709

    
710
	unlock($captiveportallck);
711
}
712

    
713
/* send RADIUS acct stop for all current clients */
714
function captiveportal_radius_stop_all($lock = false) {
715
	global $g, $config;
716

    
717
	if (!isset($config['captiveportal']['radacct_enable']))
718
		return;
719

    
720
	if (!$lock)
721
		$captiveportallck = lock('captiveportal');
722

    
723
	$cpdb = captiveportal_read_db();
724

    
725
	$radiusservers = captiveportal_get_radius_servers();
726
	if (!empty($radiusservers)) {
727
		for ($i = 0; $i < count($cpdb); $i++) {
728
			RADIUS_ACCOUNTING_STOP($cpdb[$i][1], // ruleno
729
								   $cpdb[$i][4], // username
730
								   $cpdb[$i][5], // sessionid
731
								   $cpdb[$i][0], // start time
732
								   $radiusservers,
733
								   $cpdb[$i][2], // clientip
734
								   $cpdb[$i][3], // clientmac
735
								   7); // Admin Reboot
736
		}
737
	}
738
	if (!$lock)
739
		unlock($captiveportallck);
740
}
741

    
742
function captiveportal_passthrumac_configure_entry($macent) {
743
	$rules = "";
744
        $enBwup = isset($macent['bw_up']);
745
        $enBwdown = isset($macent['bw_down']);
746
	$actionup = "allow";
747
	$actiondown = "allow";
748

    
749
        if ($enBwup && $enBwdown)
750
                $ruleno = captiveportal_get_next_ipfw_ruleno(2000, 49899, true);
751
        else
752
                $ruleno = captiveportal_get_next_ipfw_ruleno(2000, 49899, false);
753

    
754
	if ($enBwup) {
755
                $bw_up = $ruleno + 20000;
756
                $rules .= "pipe {$bw_up} config bw {$macent['bw_up']}Kbit/s queue 100\n";
757
		$actionup = "pipe {$bw_up}";
758
        }
759
        if ($enBwdown) {
760
		$bw_down = $ruleno + 20001;
761
		$rules .= "pipe {$bw_down} config bw {$macent['bw_down']}Kbit/s queue 100\n";
762
		$actiondown = "pipe {$bw_down}";
763
        }
764
	$rules .= "add {$ruleno} {$actionup} ip from any to any MAC {$macent['mac']} any\n";
765
	$ruleno++;
766
	$rules .= "add {$ruleno} {$actiondown} ip from any to any MAC any {$macent['mac']}\n";
767

    
768
	return $rules;
769
}
770

    
771
function captiveportal_passthrumac_configure($lock = false) {
772
	global $config, $g;
773

    
774
	$rules = "";
775

    
776
	if (is_array($config['captiveportal']['passthrumac'])) {
777
		$macdb = array();
778
		foreach ($config['captiveportal']['passthrumac'] as $macent) {
779
			$rules .= captiveportal_passthrumac_configure_entry($macent);
780
			$macdb[$macent['mac']]['active']  = true;
781

    
782
		}
783
	}
784

    
785
	return $rules;
786
}
787

    
788
function captiveportal_passthrumac_findbyname($username) {
789
	global $config;
790

    
791
	if (is_array($config['captiveportal']['passthrumac'])) {
792
		foreach ($config['captiveportal']['passthrumac'] as $macent) {
793
			if ($macent['username'] == $username)
794
				return $macent;
795
		}
796
	}
797
	return NULL;
798
}
799

    
800
/* 
801
 * table (3=IN)/(4=OUT) hold allowed ip's without bw limits
802
 * table (5=IN)/(6=OUT) hold allowed ip's with bw limit.
803
 */
804
function captiveportal_allowedip_configure_entry($ipent) {
805

    
806
	$rules = "";
807
	$enBwup = isset($ipent['bw_up']);
808
	$enBwdown = isset($ipent['bw_down']);
809
	$bw_up = "";
810
        $bw_down = "";
811
        $tablein = array();
812
        $tableout = array();
813

    
814
	if ($enBwup && $enBwdown)
815
		$ruleno = captiveportal_get_next_ipfw_ruleno(2000, 49899, true);
816
	else
817
		$ruleno = captiveportal_get_next_ipfw_ruleno(2000, 49899, false);
818

    
819
        if ($ipent['dir'] == "from") {
820
        	if ($enBwup)
821
                	$tablein[] = 5;
822
                else
823
                	$tablein[] = 3;
824
                if ($enBwdown)
825
                        $tableout[] = 6;
826
                else
827
                        $tableout[] = 4;
828
        } else if ($ipent['dir'] == "to") {
829
                if ($enBwup)
830
                	$tablein[] = 9;
831
                else
832
                        $tablein[] = 7;
833
                if ($enBwdown)
834
                        $tableout[] = 10;
835
                else
836
                        $tableout[] = 8;
837
        } else if ($ipent['dir'] == "both") {
838
                if ($enBwup) {
839
                        $tablein[] = 5;
840
                        $tablein[] = 9;
841
                } else {
842
                        $tablein[] = 3;
843
                        $tablein[] = 7;
844
                }
845
        	if ($enBwdown) {
846
                        $tableout[] = 6;
847
                        $tableout[] = 10;
848
                } else {
849
                        $tableout[] = 4;
850
                	$tableout[] = 8;
851
                }
852
        }
853
        if ($enBwup) {
854
                $bw_up = $ruleno + 20000;
855
        	$rules .= "pipe {$bw_up} config bw {$ipent['bw_up']}Kbit/s queue 100\n";
856
        }
857
	foreach ($tablein as $table)
858
               $rules .= "table {$table} add {$ipent['ip']} {$bw_up}\n";
859
        if ($enBwdown) {
860
               $bw_down = $ruleno + 20001;
861
               $rules .= "pipe {$bw_down} config bw {$ipent['bw_down']}Kbit/s queue 100\n";
862
        }
863
        foreach ($tableout as $table)
864
        	$rules .= "table {$table} add {$ipent['ip']} {$bw_down}\n";
865

    
866
	return $rules;
867
}
868

    
869
function captiveportal_allowedip_configure() {
870
	global $config, $g;
871

    
872
	$rules = "";
873
	if (is_array($config['captiveportal']['allowedip'])) {
874
		foreach ($config['captiveportal']['allowedip'] as $ipent) {
875
			$rules .= captiveportal_allowedip_configure_entry($ipent);
876
		}
877
	}
878

    
879
	return $rules;
880
}
881

    
882
/* get last activity timestamp given client IP address */
883
function captiveportal_get_last_activity($ip) {
884

    
885
	$ipfwoutput = "";
886

    
887
	exec("/sbin/ipfw table 1 entrystats {$ip} 2>/dev/null", $ipfwoutput);
888
	/* Reading only from one of the tables is enough of approximation. */
889
	if ($ipfwoutput[0]) {
890
		$ri = explode(" ", $ipfwoutput[0]);
891
		if ($ri[4])
892
			return $ri[4];
893
	}
894

    
895
	return 0;
896
}
897

    
898
/* read RADIUS servers into array */
899
function captiveportal_get_radius_servers() {
900

    
901
        global $g;
902

    
903
        if (file_exists("{$g['vardb_path']}/captiveportal_radius.db")) {
904
                $radiusservers = array();
905
		$cpradiusdb = file("{$g['vardb_path']}/captiveportal_radius.db", 
906
			FILE_IGNORE_NEW_LINES | FILE_SKIP_EMPTY_LINES);
907
		if ($cpradiusdb)
908
		foreach($cpradiusdb as $cpradiusentry) {
909
                	$line = trim($cpradiusentry);
910
                        if ($line) {
911
                        	$radsrv = array();
912
                                list($radsrv['ipaddr'],$radsrv['port'],$radsrv['acctport'],$radsrv['key']) = explode(",",$line);
913
                        	$radiusservers[] = $radsrv;
914
                        }
915
		}
916

    
917
		return $radiusservers;
918
        }
919

    
920
        return false;
921
}
922

    
923
/* log successful captive portal authentication to syslog */
924
/* part of this code from php.net */
925
function captiveportal_logportalauth($user,$mac,$ip,$status, $message = null) {
926
	$message = trim($message);
927
	// Log it
928
	if (!$message)
929
		$message = "$status: $user, $mac, $ip";
930
	else
931
		$message = "$status: $user, $mac, $ip, $message";
932
	captiveportal_syslog($message);
933
	closelog();
934
}
935

    
936
/* log simple messages to syslog */
937
function captiveportal_syslog($message) {
938
	define_syslog_variables();
939
	$message = trim($message);
940
	openlog("logportalauth", LOG_PID, LOG_LOCAL4);
941
	// Log it
942
	syslog(LOG_INFO, $message);
943
	closelog();
944
}
945

    
946
function radius($username,$password,$clientip,$clientmac,$type) {
947
    global $g, $config;
948

    
949
    /* Start locking from the beginning of an authentication session */
950
    $captiveportallck = lock('captiveportal');
951

    
952
    $ruleno = captiveportal_get_next_ipfw_ruleno();
953

    
954
    /* If the pool is empty, return appropriate message and fail authentication */
955
    if (is_null($ruleno)) {
956
        $auth_list = array();
957
        $auth_list['auth_val'] = 1;
958
        $auth_list['error'] = "System reached maximum login capacity";
959
        unlock($captiveportallck);
960
        return $auth_list;
961
    }
962

    
963
    /*
964
     * Drop the lock since radius takes some time to finish.
965
     * The implementation is reentrant so we gain speed with this.
966
     */
967
    unlock($captiveportallck);
968

    
969
    $radiusservers = captiveportal_get_radius_servers();
970

    
971
    $auth_list = RADIUS_AUTHENTICATION($username,
972
                    $password,
973
                    $radiusservers,
974
                    $clientip,
975
                    $clientmac,
976
                    $ruleno);
977

    
978
    $captiveportallck = lock('captiveportal');
979

    
980
    if ($auth_list['auth_val'] == 2) {
981
        captiveportal_logportalauth($username,$clientmac,$clientip,$type);
982
        $sessionid = portal_allow($clientip,
983
                    $clientmac,
984
                    $username,
985
                    $password,
986
                    $auth_list,
987
                    $ruleno);
988
    }
989

    
990
    unlock($captiveportallck);
991

    
992
    return $auth_list;
993

    
994
}
995

    
996
/* read captive portal DB into array */
997
function captiveportal_read_db() {
998

    
999
        global $g;
1000

    
1001
        $cpdb = array();
1002
        $fd = @fopen("{$g['vardb_path']}/captiveportal.db", "r");
1003
        if ($fd) {
1004
                while (!feof($fd)) {
1005
                        $line = trim(fgets($fd));
1006
                        if ($line) {
1007
                                $cpdb[] = explode(",", $line);
1008
                        }
1009
                }
1010
                fclose($fd);
1011
        }
1012
        return $cpdb;
1013
}
1014

    
1015
/* write captive portal DB */
1016
function captiveportal_write_db($cpdb) {
1017
                 
1018
        global $g;
1019
                
1020
        $fd = @fopen("{$g['vardb_path']}/captiveportal.db", "w");
1021
        if ($fd) { 
1022
                foreach ($cpdb as $cpent) {
1023
                        fwrite($fd, join(",", $cpent) . "\n");
1024
                }       
1025
                fclose($fd);
1026
        }       
1027
}
1028

    
1029
function captiveportal_write_elements() {
1030
    global $g, $config;
1031
    
1032
    /* delete any existing elements */
1033
    if (is_dir($g['captiveportal_element_path'])) {
1034
        $dh = opendir($g['captiveportal_element_path']);
1035
        while (($file = readdir($dh)) !== false) {
1036
            if ($file != "." && $file != "..")
1037
                unlink($g['captiveportal_element_path'] . "/" . $file);
1038
        }
1039
        closedir($dh);
1040
    } else {
1041
        @mkdir($g['captiveportal_element_path']);
1042
    }
1043
    
1044
	if (is_array($config['captiveportal']['element'])) {
1045
		conf_mount_rw();
1046
		foreach ($config['captiveportal']['element'] as $data) {
1047
			$fd = @fopen($g['captiveportal_element_path'] . '/' . $data['name'], "wb");
1048
			if (!$fd) {
1049
				printf("Error: cannot open '{$data['name']}' in captiveportal_write_elements().\n");
1050
				return 1;
1051
			}
1052
			$decoded = base64_decode($data['content']);
1053
			fwrite($fd,$decoded);
1054
			fclose($fd);
1055
			unlink_if_exists("{$g['captiveportal_path']}/{$data['name']}");
1056
			unlink_if_exists("{$g['captiveportal_path']}/{$data['name']}");
1057
			mwexec("cd {$g['captiveportal_path']}/ && ln -s {$g['captiveportal_element_path']}/{$data['name']} {$data['name']}");
1058
		}
1059
		conf_mount_ro();
1060
	}
1061
    
1062
    return 0;
1063
}
1064

    
1065
function captiveportal_init_ipfw_ruleno($rulenos_start = 2000, $rulenos_range_max = 49899) {
1066
	global $g;
1067

    
1068
	@unlink("{$g['vardb_path']}/captiveportal.rules");
1069
	$rules = array_pad(array(), $rulenos_range_max - $rulenos_start, false);
1070
	file_put_contents("{$g['vardb_path']}/captiveportal.rules", serialize($rules));
1071
}
1072

    
1073
/*
1074
 * This function will calculate the lowest free firewall ruleno
1075
 * within the range specified based on the actual logged on users
1076
 *
1077
 */
1078
function captiveportal_get_next_ipfw_ruleno($rulenos_start = 2000, $rulenos_range_max = 49899, $usebw = false) {
1079
	global $config, $g;
1080

    
1081
	if(!isset($config['captiveportal']['enable']))
1082
		return NULL;
1083

    
1084
	$ruleno = 0;
1085
	if (file_exists("{$g['vardb_path']}/captiveportal.rules")) {
1086
		$rules = unserialize(file_get_contents("{$g['vardb_path']}/captiveportal.rules"));
1087
		for ($ridx = 2; $ridx < ($rulenos_range_max - $rulenos_start); $ridx++) {
1088
			if ($rules[$ridx]) {
1089
				/* 
1090
	 			 * This allows our traffic shaping pipes to be the in pipe the same as ruleno 
1091
	 			 * and the out pipe ruleno + 1. This removes limitation that where present in 
1092
	 			 * previous version of the peruserbw.
1093
	 			 */
1094
				if (isset($config['captiveportal']['peruserbw']))
1095
					$ridx++;
1096
				continue;
1097
			}
1098
			$ruleno = $ridx;
1099
			$rules[$ridx] = "used";
1100
			if (isset($config['captiveportal']['peruserbw']) || $usebw == true)
1101
				$rules[++$ridx] = "used";
1102
			break;
1103
		}
1104
	} else {
1105
		$rules = array_pad(array(), $rulenos_range_max - $rulenos_start, false);
1106
		$rules[2] = "used";
1107
		$ruleno = 2;
1108
	}
1109
	file_put_contents("{$g['vardb_path']}/captiveportal.rules", serialize($rules));
1110
	return $ruleno;
1111
}
1112

    
1113
function captiveportal_free_ipfw_ruleno($ruleno, $usedbw = false) {
1114
	global $config, $g;
1115

    
1116
	if(!isset($config['captiveportal']['enable']))
1117
		return NULL;
1118

    
1119
	if (file_exists("{$g['vardb_path']}/captiveportal.rules")) {
1120
		$rules = unserialize(file_get_contents("{$g['vardb_path']}/captiveportal.rules"));
1121
		$rules[$ruleno] = false;
1122
		if (isset($config['captiveportal']['peruserbw']) || $usedbw == true)
1123
			$rules[++$ruleno] = false;
1124
		file_put_contents("{$g['vardb_path']}/captiveportal.rules", serialize($rules));
1125
	}
1126
}
1127

    
1128
function captiveportal_get_ipfw_passthru_ruleno($value) {
1129
	global $config, $g;
1130

    
1131
	if(!isset($config['captiveportal']['enable']))
1132
                return NULL;
1133

    
1134
        if (file_exists("{$g['vardb_path']}/captiveportal.rules")) {
1135
                $rules = unserialize(file_get_contents("{$g['vardb_path']}/captiveportal.rules"));
1136
		$ruleno = intval(`/sbin/ipfw show | /usr/bin/grep {$value} |  /usr/bin/grep -v grep | /usr/bin/cut -d " " -f 1 | /usr/bin/head -n 1`);
1137
		if ($rules[$ruleno])
1138
			return $ruleno;
1139
        }
1140

    
1141
	return NULL;
1142
}
1143

    
1144
/**
1145
 * This function will calculate the traffic produced by a client
1146
 * based on its firewall rule
1147
 *
1148
 * Point of view: NAS
1149
 *
1150
 * Input means: from the client
1151
 * Output means: to the client
1152
 *
1153
 */
1154

    
1155
function getVolume($ip) {
1156

    
1157
    $volume = array();
1158

    
1159
    // Initialize vars properly, since we don't want NULL vars
1160
    $volume['input_pkts'] = $volume['input_bytes'] = $volume['output_pkts'] = $volume['output_bytes'] = 0 ;
1161

    
1162
    // Ingress
1163
    $ipfwin = "";
1164
    $ipfwout = "";
1165
    $matchesin = "";
1166
    $matchesout = "";
1167
    exec("/sbin/ipfw table 1 entrystats {$ip}", $ipfwin);
1168
    if ($ipfwin[0]) {
1169
		$ipfwin = split(" ", $ipfwin[0]);
1170
		$volume['input_pkts'] = $ipfwin[2];
1171
		$volume['input_bytes'] = $ipfwin[3];
1172
    }
1173

    
1174
    exec("/sbin/ipfw table 2 entrystats {$ip}", $ipfwout);
1175
    if ($ipfwout[0]) {
1176
        $ipfwout = split(" ", $ipfwout[0]);
1177
        $volume['output_pkts'] = $ipfwout[2];
1178
        $volume['output_bytes'] = $ipfwout[3];
1179
    }
1180

    
1181
    return $volume;
1182
}
1183

    
1184
/**
1185
 * Get the NAS-Identifier
1186
 *
1187
 * We will use our local hostname to make up the nas_id
1188
 */
1189
function getNasID()
1190
{
1191
    $nasId = "";
1192
    exec("/bin/hostname", $nasId);
1193
    if(!$nasId[0])
1194
        $nasId[0] = "{$g['product_name']}";
1195
    return $nasId[0];
1196
}
1197

    
1198
/**
1199
 * Get the NAS-IP-Address based on the current wan address
1200
 *
1201
 * Use functions in interfaces.inc to find this out
1202
 *
1203
 */
1204

    
1205
function getNasIP()
1206
{
1207
    $nasIp = get_interface_ip();
1208
    if(!$nasIp)
1209
        $nasIp = "0.0.0.0";
1210
    return $nasIp;
1211
}
1212

    
1213
function portal_ip_from_client_ip($cliip) {
1214
	global $config;
1215

    
1216
	$interfaces = explode(",", $config['captiveportal']['interface']);
1217
	foreach ($interfaces as $cpif) {
1218
		$ip = get_interface_ip($cpif);
1219
		$sn = get_interface_subnet($cpif);
1220
		if (ip_in_subnet($cliip, "{$ip}/{$sn}"))
1221
			return $ip;
1222
	}
1223

    
1224
	// doesn't match up to any particular interface
1225
	// so let's set the portal IP to what PHP says 
1226
	// the server IP issuing the request is. 
1227
	// allows same behavior as 1.2.x where IP isn't 
1228
	// in the subnet of any CP interface (static routes, etc.)
1229
	// rather than forcing to DNS hostname resolution
1230
	$ip = $_SERVER['SERVER_ADDR'];
1231
	if (is_ipaddr($ip))
1232
		return $ip;
1233

    
1234
	return false;
1235
}
1236

    
1237
?>
(6-6/50)