Project

General

Profile

Download (38.8 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("radius.inc");
47
require_once("voucher.inc");
48

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

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

    
96
	if ($cpactive == true) {
97

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

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

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

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

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

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

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

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

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

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

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

    
176

    
177

    
178
EOD;
179
		}
180

    
181
		$fd = @fopen("{$g['varetc_path']}/captiveportal.html", "w");
182
		if ($fd) {
183
			fwrite($fd, $htmltext);
184
			fclose($fd);
185
		}
186

    
187
		/* write error page */
188
		if ($config['captiveportal']['page']['errtext'])
189
			$errtext = base64_decode($config['captiveportal']['page']['errtext']);
190
		else {
191
			/* example page */
192
			$errtext = <<<EOD
193
<html>
194
<head>
195
<title>Authentication error</title>
196
</head>
197
<body>
198
<font color="#cc0000"><h2>Authentication error</h2></font>
199
<b>
200
Username and/or password invalid.
201
<br><br>
202
<a href="javascript:history.back(); ">Go back</a>
203
</b>
204
</body>
205
</html>
206

    
207
EOD;
208
		}
209

    
210
		$fd = @fopen("{$g['varetc_path']}/captiveportal-error.html", "w");
211
		if ($fd) {
212
			fwrite($fd, $errtext);
213
			fclose($fd);
214
		}
215

    
216
		/* write elements */
217
		captiveportal_write_elements();
218

    
219
		/* load rules */
220
		mwexec("/sbin/ipfw -q flush");
221

    
222
		/* ipfw cannot accept rules directly on stdin,
223
		   so we have to write them to a temporary file first */
224
		$fd = @fopen("{$g['tmp_path']}/ipfw.cp.rules", "w");
225
		if (!$fd) {
226
			printf("Cannot open ipfw.cp.rules in captiveportal_configure()\n");
227
			return 1;
228
		}
229

    
230
		fwrite($fd, $cprules);
231
		fclose($fd);
232

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

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

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

    
240
		chdir($g['captiveportal_path']);
241

    
242
		if ($config['captiveportal']['maxproc'])
243
			$maxproc = $config['captiveportal']['maxproc'];
244
		else
245
			$maxproc = 16;
246

    
247
		$use_fastcgi = true;
248

    
249
		if(isset($config['captiveportal']['httpslogin'])) {
250
			$cert = base64_decode($config['captiveportal']['certificate']);
251
			if (isset($config['captiveportal']['cacertificate']))
252
				$cacert = base64_decode($config['captiveportal']['cacertificate']);
253
			else
254
				$cacert = "";
255
			$key = base64_decode($config['captiveportal']['private-key']);
256
			/* generate lighttpd configuration */
257
			system_generate_lighty_config("{$g['varetc_path']}/lighty-CaptivePortal-SSL.conf",
258
				$cert, $key, $cacert, "lighty-CaptivePortal-ssl.pid", "8001", "/usr/local/captiveportal/",
259
					"cert-portal.pem", "ca-portal.pem", "1", $maxproc, $use_fastcgi, true);
260
		}
261

    
262
		/* generate lighttpd configuration */
263
		system_generate_lighty_config("{$g['varetc_path']}/lighty-CaptivePortal.conf",
264
			"", "", "", "lighty-CaptivePortal.pid", "8000", "/usr/local/captiveportal/",
265
				"cert-portal.pem", "ca-portal.pem", "1", $maxproc, $use_fastcgi, true);
266

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

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

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

    
278
		/* generate radius server database */
279
		if ($config['captiveportal']['radiusip'] && (!isset($config['captiveportal']['auth_method']) ||
280
				($config['captiveportal']['auth_method'] == "radius"))) {
281
			$radiusip = $config['captiveportal']['radiusip'];
282
			$radiusip2 = ($config['captiveportal']['radiusip2']) ? $config['captiveportal']['radiusip2'] : null;
283

    
284
			if ($config['captiveportal']['radiusport'])
285
				$radiusport = $config['captiveportal']['radiusport'];
286
			else
287
				$radiusport = 1812;
288

    
289
			if ($config['captiveportal']['radiusacctport'])
290
				$radiusacctport = $config['captiveportal']['radiusacctport'];
291
			else
292
				$radiusacctport = 1813;
293

    
294
			if ($config['captiveportal']['radiusport2'])
295
				$radiusport2 = $config['captiveportal']['radiusport2'];
296
			else
297
				$radiusport2 = 1812;
298

    
299
			$radiuskey = $config['captiveportal']['radiuskey'];
300
			$radiuskey2 = ($config['captiveportal']['radiuskey2']) ? $config['captiveportal']['radiuskey2'] : null;
301

    
302
			$fd = @fopen("{$g['vardb_path']}/captiveportal_radius.db", "w");
303
			if (!$fd) {
304
				printf("Error: cannot open radius DB file in captiveportal_configure().\n");
305
				return 1;
306
			} else if (isset($radiusip2, $radiuskey2)) {
307
				fwrite($fd,$radiusip . "," . $radiusport . "," . $radiusacctport . "," . $radiuskey . "\n"
308
					 . $radiusip2 . "," . $radiusport2 . "," . $radiusacctport . "," . $radiuskey2);
309
			} else {
310
				fwrite($fd,$radiusip . "," . $radiusport . "," . $radiusacctport . "," . $radiuskey);
311
			}
312
			fclose($fd);
313
		}
314

    
315
		if ($g['booting'])
316
			echo "done\n";
317

    
318
	} else {
319
		killbypid("{$g['varrun_path']}/lighty-CaptivePortal.pid");
320
		killbypid("{$g['varrun_path']}/minicron.pid");
321

    
322
		captiveportal_radius_stop_all(true);
323

    
324
		mwexec("/sbin/sysctl net.link.ether.ipfw=0");
325

    
326
		/* unload ipfw */
327
		if (is_module_loaded("ipfw.ko"))		
328
			mwexec("/sbin/kldunload ipfw.ko");
329
		$listifs = get_configured_interface_list_by_realif();
330
		foreach ($listifs as $listrealif => $listif) {
331
			if (!empty($listrealif)) {
332
				mwexec("/sbin/ifconfig {$listrealif} -ipfwfilter");
333
				$carpif = link_ip_to_carp_interface(find_interface_ip($listrealif));
334
                        	if (!empty($carpif)) {
335
					$carpsif = explode(" ", $carpif);
336
					foreach ($carpsif as $cpcarp)
337
						mwexec("/sbin/ifconfig {$cpcarp} -ipfwfilter");
338
				}
339
			}
340
		}
341
	}
342

    
343
	unlock($captiveportallck);
344
	
345
	return 0;
346
}
347

    
348
function captiveportal_rules_generate($cpif, &$cpiparray) {
349
	global $config, $g;
350

    
351
	$cprules =  "add 65291 set 1 allow pfsync from any to any\n";
352
	$cprules .= "add 65292 set 1 allow carp from any to any\n";
353

    
354
	$cprules .= <<<EOD
355
# add 65300 set 1 skipto 65534 all from any to any not layer2
356
# layer 2: pass ARP
357
add 65301 set 1 pass layer2 mac-type arp
358
# pfsense requires for WPA
359
add 65302 set 1 pass layer2 mac-type 0x888e
360
add 65303 set 1 pass layer2 mac-type 0x88c7
361

    
362
# PPP Over Ethernet Discovery Stage
363
add 65304 set 1 pass layer2 mac-type 0x8863
364
# PPP Over Ethernet Session Stage
365
add 65305 set 1 pass layer2 mac-type 0x8864
366
# Allow WPA
367
add 65306 set 1 pass layer2 mac-type 0x888e
368

    
369
# layer 2: block anything else non-IP
370
add 65307 set 1 deny layer2 not mac-type ip
371

    
372
EOD;
373

    
374
	$rulenum = 65310;
375
	$ips = "255.255.255.255 ";
376
	foreach ($cpiparray as $cpip)
377
		$ips .= "or {$cpip} ";
378
	$ips = "{ {$ips} }";
379
	//# allow access to our DHCP server (which needs to be able to ping clients as well)
380
	$cprules .= "add {$rulenum} set 1 pass udp from any 68 to {$ips} 67 in \n";
381
	$rulenum++;
382
	$cprules .= "add {$rulenum} set 1 pass udp from any 68 to {$ips} 67 in \n";
383
	$rulenum++;
384
	$cprules .= "add {$rulenum} set 1 pass udp from {$ips} 67 to any 68 out \n";
385
	$rulenum++;
386
	$cprules .= "add {$rulenum} set 1 pass icmp from {$ips} to any out icmptype 0\n";
387
	$rulenum++;
388
	$cprules .= "add {$rulenum} set 1 pass icmp from any to {$ips} in icmptype 8 \n";
389
	$rulenum++;
390
	//# allow access to our DNS forwarder
391
	$cprules .= "add {$rulenum} set 1 pass udp from any to {$ips} 53 in \n";
392
	$rulenum++;
393
	$cprules .= "add {$rulenum} set 1 pass udp from {$ips} 53 to any out \n";
394
	$rulenum++;
395
	# allow access to our web server
396
	$cprules .= "add {$rulenum} set 1 pass tcp from any to {$ips} 8000 in \n";
397
	$rulenum++;
398
	$cprules .= "add {$rulenum} set 1 pass tcp from {$ips} 8000 to any out \n";
399

    
400
	if (isset($config['captiveportal']['httpslogin'])) {
401
		$rulenum++;
402
		$cprules .= "add {$rulenum} set 1 pass tcp from any to {$ips} 8001 in \n";
403
		$rulenum++;
404
		$cprules .= "add {$rulenum} set 1 pass tcp from {$ips} 8001 to any out \n";
405
	}
406
	if (!empty($config['system']['webgui']['port']))
407
		$port = $config['system']['webgui']['port'];
408
	else if ($config['system']['webgui']['proto'] == "https")
409
		$port = 443;
410
	else
411
		$port = 80;
412
	$rulenum++;
413
	$cprules .= "add {$rulenum} set 1 pass tcp from any to {$ips} {$port} in \n";
414
	$rulenum++;
415
	$cprules .= "add {$rulenum} set 1 pass tcp from {$ips} {$port} to any out \n";
416
	$rulenum++;
417

    
418
	/* Allowed ips */
419
	$cprules .= "add {$rulenum} allow ip from table(3) to any in\n";
420
	$rulenum++;
421
	$cprules .= "add {$rulenum} allow ip from any to table(4) out\n";
422
	$rulenum++;
423
	$cprules .= "add {$rulenum} pipe tablearg ip from table(5) to any in\n";
424
	$rulenum++;
425
	$cprules .= "add {$rulenum} pipe tablearg ip from any to table(6) out\n";
426
	$rulenum++;
427
	$cprules .= "add {$rulenum} allow ip from any to table(7) in\n";
428
	$rulenum++;
429
	$cprules .= "add {$rulenum} allow ip from table(8) to any out\n";
430
	$rulenum++;
431
	$cprules .= "add {$rulenum} pipe tablearg ip from any to table(9) in\n";
432
	$rulenum++;
433
	$cprules .= "add {$rulenum} pipe tablearg ip from table(10) to any out\n";
434
	$rulenum++;
435

    
436
	/* Authenticated users rules. */
437
	if (isset($config['captiveportal']['peruserbw'])) {
438
		$cprules .= "add {$rulenum} set 1 pipe tablearg ip from table(1) to any in\n";
439
		$rulenum++;
440
		$cprules .= "add {$rulenum} set 1 pipe tablearg ip from any to table(2) out\n";
441
		$rulenum++;
442
	} else {
443
		$cprules .= "add {$rulenum} set 1 allow ip from table(1) to any in\n";
444
                $rulenum++;
445
                $cprules .= "add {$rulenum} set 1 allow ip from any to table(2) out\n";
446
                $rulenum++;
447
	}
448
	
449
       $cprules .= <<<EOD
450

    
451
# redirect non-authenticated clients to captive portal
452
add 65531 set 1 fwd 127.0.0.1,8000 tcp from any to any in
453
# let the responses from the captive portal web server back out
454
add 65532 set 1 pass tcp from any to any out
455
# block everything else
456
add 65533 set 1 deny all from any to any
457
# pass everything else on layer2
458
add 65534 set 1 pass all from any to any layer2
459

    
460
EOD;
461

    
462
    return $cprules;
463
}
464

    
465
/* remove clients that have been around for longer than the specified amount of time */
466
/* db file structure:
467
timestamp,ipfw_rule_no,clientip,clientmac,username,sessionid,password,session_timeout,idle_timeout,session_terminate_time */
468

    
469
/* (password is in Base64 and only saved when reauthentication is enabled) */
470
function captiveportal_prune_old() {
471

    
472
    global $g, $config;
473

    
474
    /* check for expired entries */
475
    if ($config['captiveportal']['timeout'])
476
        $timeout = $config['captiveportal']['timeout'] * 60;
477
    else
478
        $timeout = 0;
479

    
480
    if ($config['captiveportal']['idletimeout'])
481
        $idletimeout = $config['captiveportal']['idletimeout'] * 60;
482
    else
483
        $idletimeout = 0;
484

    
485
    if (!$timeout && !$idletimeout && !isset($config['captiveportal']['reauthenticate']) && 
486
		!isset($config['captiveportal']['radiussession_timeout']) && !isset($config['voucher']['enable']))
487
        return;
488

    
489
    $captiveportallck = lock('captiveportal');
490

    
491
    /* read database */
492
    $cpdb = captiveportal_read_db();
493

    
494
    $radiusservers = captiveportal_get_radius_servers();
495

    
496
    /*  To make sure we iterate over ALL accounts on every run the count($cpdb) is moved
497
     *  outside of the loop. Otherwise the loop would evaluate count() on every iteration
498
     *  and since $i would increase and count() would decrement they would meet before we
499
     *  had a chance to iterate over all accounts.
500
     */
501
    $unsetindexes = array();
502
    $no_users = count($cpdb);
503
    for ($i = 0; $i < $no_users; $i++) {
504

    
505
        $timedout = false;
506
        $term_cause = 1;
507

    
508
        /* hard timeout? */
509
        if ($timeout) {
510
            if ((time() - $cpdb[$i][0]) >= $timeout) {
511
                $timedout = true;
512
                $term_cause = 5; // Session-Timeout
513
            }
514
        }
515

    
516
        /* Session-Terminate-Time */
517
        if (!$timedout && !empty($cpdb[$i][9])) {
518
            if (time() >= $cpdb[$i][9]) {
519
                $timedout = true;
520
                $term_cause = 5; // Session-Timeout
521
            }
522
        }
523

    
524
        /* check if the radius idle_timeout attribute has been set and if its set change the idletimeout to this value */
525
        $idletimeout = (is_numeric($cpdb[$i][8])) ? $cpdb[$i][8] : $idletimeout;
526
        /* if an idle timeout is specified, get last activity timestamp from ipfw */
527
        if (!$timedout && $idletimeout) {
528
            $lastact = captiveportal_get_last_activity($cpdb[$i][2]);
529
			/*  If the user has logged on but not sent any traffic they will never be logged out.
530
			 *  We "fix" this by setting lastact to the login timestamp. 
531
			 */
532
			$lastact = $lastact ? $lastact : $cpdb[$i][0];
533
            if ($lastact && ((time() - $lastact) >= $idletimeout)) {
534
                $timedout = true;
535
                $term_cause = 4; // Idle-Timeout
536
                $stop_time = $lastact; // Entry added to comply with WISPr
537
            }
538
        }
539

    
540
	/* if vouchers are configured, activate session timeouts */
541
	if (!$timedout && isset($config['voucher']['enable']) && !empty($cpdb[$i][7])) {
542
		if (time() >= ($cpdb[$i][0] + $cpdb[$i][7])) {
543
			$timedout = true;
544
			$term_cause = 5; // Session-Timeout
545
		}
546
	}
547

    
548
        /* if radius session_timeout is enabled and the session_timeout is not null, then check if the user should be logged out */
549
        if (!$timedout && isset($config['captiveportal']['radiussession_timeout']) && !empty($cpdb[$i][7])) {
550
            if (time() >= ($cpdb[$i][0] + $cpdb[$i][7])) {
551
                $timedout = true;
552
                $term_cause = 5; // Session-Timeout
553
            }
554
        }
555

    
556
        if ($timedout) {
557
            captiveportal_disconnect($cpdb[$i], $radiusservers,$term_cause,$stop_time);
558
            captiveportal_logportalauth($cpdb[$i][4], $cpdb[$i][3], $cpdb[$i][2], "TIMEOUT");
559
	    $unsetindexes[$i] = $i;
560
        }
561

    
562
        /* do periodic RADIUS reauthentication? */
563
        if (!$timedout && isset($config['captiveportal']['reauthenticate']) &&
564
            !empty($radiusservers)) {
565

    
566
            if (isset($config['captiveportal']['radacct_enable'])) {
567
                if ($config['captiveportal']['reauthenticateacct'] == "stopstart") {
568
                    /* stop and restart accounting */
569
                    RADIUS_ACCOUNTING_STOP($cpdb[$i][1], // ruleno
570
                                           $cpdb[$i][4], // username
571
                                           $cpdb[$i][5], // sessionid
572
                                           $cpdb[$i][0], // start time
573
                                           $radiusservers,
574
                                           $cpdb[$i][2], // clientip
575
                                           $cpdb[$i][3], // clientmac
576
                                           10); // NAS Request
577
                    exec("/sbin/ipfw table 1 entryzerostats {$cpdb[$i][2]}");
578
                    exec("/sbin/ipfw table 2 entryzerostats {$cpdb[$i][2]}");
579
                    RADIUS_ACCOUNTING_START($cpdb[$i][1], // ruleno
580
                                            $cpdb[$i][4], // username
581
                                            $cpdb[$i][5], // sessionid
582
                                            $radiusservers,
583
                                            $cpdb[$i][2], // clientip
584
                                            $cpdb[$i][3]); // clientmac
585
                } else if ($config['captiveportal']['reauthenticateacct'] == "interimupdate") {
586
                    RADIUS_ACCOUNTING_STOP($cpdb[$i][1], // ruleno
587
                                           $cpdb[$i][4], // username
588
                                           $cpdb[$i][5], // sessionid
589
                                           $cpdb[$i][0], // start time
590
                                           $radiusservers,
591
                                           $cpdb[$i][2], // clientip
592
                                           $cpdb[$i][3], // clientmac
593
                                           10, // NAS Request
594
                                           true); // Interim Updates
595
                }
596
            }
597

    
598
            /* check this user against RADIUS again */
599
            $auth_list = RADIUS_AUTHENTICATION($cpdb[$i][4], // username
600
                                          base64_decode($cpdb[$i][6]), // password
601
                                            $radiusservers,
602
                                          $cpdb[$i][2], // clientip
603
                                          $cpdb[$i][3], // clientmac
604
                                          $cpdb[$i][1]); // ruleno
605

    
606
            if ($auth_list['auth_val'] == 3) {
607
                captiveportal_disconnect($cpdb[$i], $radiusservers, 17);
608
                captiveportal_logportalauth($cpdb[$i][4], $cpdb[$i][3], $cpdb[$i][2], "RADIUS_DISCONNECT", $auth_list['reply_message']);
609
	        $unsetindexes[$i] = $i;
610
            }
611
        }
612
    }
613
    /* This is a kludge to overcome some php weirdness */
614
    foreach($unsetindexes as $unsetindex)
615
	unset($cpdb[$unsetindex]);
616

    
617
    /* write database */
618
    captiveportal_write_db($cpdb);
619

    
620
    unlock($captiveportallck);
621
}
622

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

    
626
	global $g, $config;
627

    
628
	$stop_time = (empty($stop_time)) ? time() : $stop_time;
629

    
630
	/* this client needs to be deleted - remove ipfw rules */
631
	if (isset($config['captiveportal']['radacct_enable']) && !empty($radiusservers)) {
632
		RADIUS_ACCOUNTING_STOP($dbent[1], // ruleno
633
							   $dbent[4], // username
634
							   $dbent[5], // sessionid
635
							   $dbent[0], // start time
636
							   $radiusservers,
637
							   $dbent[2], // clientip
638
							   $dbent[3], // clientmac
639
							   $term_cause, // Acct-Terminate-Cause
640
							   false,
641
							   $stop_time);
642
	}
643
	/* Delete client's ip entry from tables 3 and 4. */
644
	mwexec("/sbin/ipfw table 1 delete {$dbent[2]}");
645
	mwexec("/sbin/ipfw table 2 delete {$dbent[2]}");
646

    
647
	/* Release the ruleno so it can be reallocated to new clients. */
648
	captiveportal_free_ipfw_ruleno($dbent[1]);
649

    
650
	/* 
651
	* These are the pipe numbers we use to control traffic shaping for each logged in user via captive portal
652
	* We could get an error if the pipe doesn't exist but everything should still be fine
653
	*/
654
	if (isset($config['captiveportal']['peruserbw'])) {
655
		mwexec("/sbin/ipfw pipe " . ($dbent[1]+20000) . " delete");
656
		mwexec("/sbin/ipfw pipe " . ($dbent[1]+20001) . " delete");
657
	}
658

    
659
	/* XXX: Redundant?! Ensure all pf(4) states are killed. */
660
	mwexec("pfctl -k {$dbent[2]}");
661
	mwexec("pfctl -K {$dbent[2]}");
662

    
663
}
664

    
665
/* remove a single client by ipfw rule number */
666
function captiveportal_disconnect_client($id,$term_cause = 1) {
667

    
668
	global $g, $config;
669

    
670
	$captiveportallck = lock('captiveportal');
671

    
672
	/* read database */
673
	$cpdb = captiveportal_read_db();
674
	$radiusservers = captiveportal_get_radius_servers();
675

    
676
	/* find entry */
677
	$tmpindex = 0;
678
	$cpdbcount = count($cpdb);
679
	for ($i = 0; $i < $cpdbcount; $i++) {
680
		if ($cpdb[$i][1] == $id) {
681
			captiveportal_disconnect($cpdb[$i], $radiusservers, $term_cause);
682
			captiveportal_logportalauth($cpdb[$i][4], $cpdb[$i][3], $cpdb[$i][2], "DISCONNECT");
683
			unset($cpdb[$i]);
684
			break;
685
		}
686
	}		
687

    
688
	/* write database */
689
	captiveportal_write_db($cpdb);
690

    
691
	unlock($captiveportallck);
692
}
693

    
694
/* send RADIUS acct stop for all current clients */
695
function captiveportal_radius_stop_all($lock = false) {
696
	global $g, $config;
697

    
698
	if (!isset($config['captiveportal']['radacct_enable']))
699
		return;
700

    
701
	if (!$lock)
702
		$captiveportallck = lock('captiveportal');
703

    
704
	$cpdb = captiveportal_read_db();
705

    
706
	$radiusservers = captiveportal_get_radius_servers();
707
	if (!empty($radiusservers)) {
708
		for ($i = 0; $i < count($cpdb); $i++) {
709
			RADIUS_ACCOUNTING_STOP($cpdb[$i][1], // ruleno
710
								   $cpdb[$i][4], // username
711
								   $cpdb[$i][5], // sessionid
712
								   $cpdb[$i][0], // start time
713
								   $radiusservers,
714
								   $cpdb[$i][2], // clientip
715
								   $cpdb[$i][3], // clientmac
716
								   7); // Admin Reboot
717
		}
718
	}
719
	if (!$lock)
720
		unlock($captiveportallck);
721
}
722

    
723
function captiveportal_passthrumac_configure_entry($macent) {
724
	$rules = "";
725
        $enBwup = isset($macent['bw_up']);
726
        $enBwdown = isset($macent['bw_down']);
727
	$actionup = "allow";
728
	$actiondown = "allow";
729

    
730
        if ($enBwup && $enBwdown)
731
                $ruleno = captiveportal_get_next_ipfw_ruleno(2000, 49899, true);
732
        else
733
                $ruleno = captiveportal_get_next_ipfw_ruleno(2000, 49899, false);
734

    
735
	if ($enBwup) {
736
                $bw_up = $ruleno + 20000;
737
                $rules .= "pipe {$bw_up} config bw {$macent['bw_up']}Kbit/s queue 100\n";
738
		$actionup = "pipe {$bw_up}";
739
        }
740
        if ($enBwdown) {
741
		$bw_down = $ruleno + 20001;
742
		$rules .= "pipe {$bw_down} config bw {$macent['bw_down']}Kbit/s queue 100\n";
743
		$actiondown = "pipe {$bw_down}";
744
        }
745
	$rules .= "add {$ruleno} {$actionup} ip from any to any MAC {$macent['mac']} any\n";
746
	$ruleno++;
747
	$rules .= "add {$ruleno} {$actiondown} ip from any to any MAC any {$macent['mac']}\n";
748

    
749
	return $rules;
750
}
751

    
752
function captiveportal_passthrumac_configure($lock = false) {
753
	global $config, $g;
754

    
755
	$rules = "";
756

    
757
	if (is_array($config['captiveportal']['passthrumac'])) {
758
		$macdb = array();
759
		foreach ($config['captiveportal']['passthrumac'] as $macent) {
760
			$rules .= captiveportal_passthrumac_configure_entry($macent);
761
			$macdb[$macent['mac']]['active']  = true;
762

    
763
		}
764
	}
765

    
766
	return $rules;
767
}
768

    
769
/* 
770
 * table (3=IN)/(4=OUT) hold allowed ip's without bw limits
771
 * table (5=IN)/(6=OUT) hold allowed ip's with bw limit.
772
 */
773
function captiveportal_allowedip_configure_entry($ipent) {
774

    
775
	$rules = "";
776
	$enBwup = isset($ipent['bw_up']);
777
	$enBwdown = isset($ipent['bw_down']);
778
	$bw_up = "";
779
        $bw_down = "";
780
        $tablein = array();
781
        $tableout = array();
782

    
783
	if ($enBwup && $enBwdown)
784
		$ruleno = captiveportal_get_next_ipfw_ruleno(2000, 49899, true);
785
	else
786
		$ruleno = captiveportal_get_next_ipfw_ruleno(2000, 49899, false);
787

    
788
        if ($ipent['dir'] == "from") {
789
        	if ($enBwup)
790
                	$tablein[] = 5;
791
                else
792
                	$tablein[] = 3;
793
                if ($enBwdown)
794
                        $tableout[] = 6;
795
                else
796
                        $tableout[] = 4;
797
        } else if ($ipent['dir'] == "to") {
798
                if ($enBwup)
799
                	$tablein[] = 9;
800
                else
801
                        $tablein[] = 7;
802
                if ($enBwdown)
803
                        $tableout[] = 10;
804
                else
805
                        $tableout[] = 8;
806
        } else if ($ipent['dir'] == "both") {
807
                if ($enBwup) {
808
                        $tablein[] = 5;
809
                        $tablein[] = 9;
810
                } else {
811
                        $tablein[] = 3;
812
                        $tablein[] = 7;
813
                }
814
        	if ($enBwdown) {
815
                        $tableout[] = 6;
816
                        $tableout[] = 10;
817
                } else {
818
                        $tableout[] = 4;
819
                	$tableout[] = 8;
820
                }
821
        }
822
        if ($enBwup) {
823
                $bw_up = $ruleno + 20000;
824
        	$rules .= "pipe {$bw_up} config bw {$ipent['bw_up']}Kbit/s queue 100\n";
825
        }
826
	foreach ($tablein as $table)
827
               $rules .= "table {$table} add {$ipent['ip']} {$bw_up}\n";
828
        if ($enBwdown) {
829
               $bw_down = $ruleno + 20001;
830
               $rules .= "pipe {$bw_down} config bw {$ipent['bw_down']}Kbit/s queue 100\n";
831
        }
832
        foreach ($tableout as $table)
833
        	$rules .= "table {$table} add {$ipent['ip']} {$bw_down}\n";
834

    
835
	return $rules;
836
}
837

    
838
function captiveportal_allowedip_configure() {
839
	global $config, $g;
840

    
841
	$rules = "";
842
	if (is_array($config['captiveportal']['allowedip'])) {
843
		foreach ($config['captiveportal']['allowedip'] as $ipent) {
844
			$rules .= captiveportal_allowedip_configure_entry($ipent);
845
		}
846
	}
847

    
848
	return $rules;
849
}
850

    
851
/* get last activity timestamp given client IP address */
852
function captiveportal_get_last_activity($ip) {
853

    
854
	$ipfwoutput = "";
855

    
856
	exec("/sbin/ipfw table 1 entrystats {$ip} 2>/dev/null", $ipfwoutput);
857
	/* Reading only from one of the tables is enough of approximation. */
858
	if ($ipfwoutput[0]) {
859
		$ri = explode(" ", $ipfwoutput[0]);
860
		if ($ri[4])
861
			return $ri[4];
862
	}
863

    
864
	return 0;
865
}
866

    
867
/* read RADIUS servers into array */
868
function captiveportal_get_radius_servers() {
869

    
870
        global $g;
871

    
872
        if (file_exists("{$g['vardb_path']}/captiveportal_radius.db")) {
873
                $radiusservers = array();
874
		$cpradiusdb = file("{$g['vardb_path']}/captiveportal_radius.db", 
875
			FILE_IGNORE_NEW_LINES | FILE_SKIP_EMPTY_LINES);
876
		if ($cpradiusdb)
877
		foreach($cpradiusdb as $cpradiusentry) {
878
                	$line = trim($cpradiusentry);
879
                        if ($line) {
880
                        	$radsrv = array();
881
                                list($radsrv['ipaddr'],$radsrv['port'],$radsrv['acctport'],$radsrv['key']) = explode(",",$line);
882
                        	$radiusservers[] = $radsrv;
883
                        }
884
		}
885

    
886
		return $radiusservers;
887
        }
888

    
889
        return false;
890
}
891

    
892
/* log successful captive portal authentication to syslog */
893
/* part of this code from php.net */
894
function captiveportal_logportalauth($user,$mac,$ip,$status, $message = null) {
895
	$message = trim($message);
896
	// Log it
897
	if (!$message)
898
		$message = "$status: $user, $mac, $ip";
899
	else
900
		$message = "$status: $user, $mac, $ip, $message";
901
	captiveportal_syslog($message);
902
	closelog();
903
}
904

    
905
/* log simple messages to syslog */
906
function captiveportal_syslog($message) {
907
	define_syslog_variables();
908
	$message = trim($message);
909
	openlog("logportalauth", LOG_PID, LOG_LOCAL4);
910
	// Log it
911
	syslog(LOG_INFO, $message);
912
	closelog();
913
}
914

    
915
function radius($username,$password,$clientip,$clientmac,$type) {
916
    global $g, $config;
917

    
918
    /* Start locking from the beginning of an authentication session */
919
    $captiveportallck = lock('captiveportal');
920

    
921
    $ruleno = captiveportal_get_next_ipfw_ruleno();
922

    
923
    /* If the pool is empty, return appropriate message and fail authentication */
924
    if (is_null($ruleno)) {
925
        $auth_list = array();
926
        $auth_list['auth_val'] = 1;
927
        $auth_list['error'] = "System reached maximum login capacity";
928
        unlock($captiveportallck);
929
        return $auth_list;
930
    }
931

    
932
    /*
933
     * Drop the lock since radius takes some time to finish.
934
     * The implementation is reentrant so we gain speed with this.
935
     */
936
    unlock($captiveportallck);
937

    
938
    $radiusservers = captiveportal_get_radius_servers();
939

    
940
    $auth_list = RADIUS_AUTHENTICATION($username,
941
                    $password,
942
                    $radiusservers,
943
                    $clientip,
944
                    $clientmac,
945
                    $ruleno);
946

    
947
    $captiveportallck = lock('captiveportal');
948

    
949
    if ($auth_list['auth_val'] == 2) {
950
        captiveportal_logportalauth($username,$clientmac,$clientip,$type);
951
        $sessionid = portal_allow($clientip,
952
                    $clientmac,
953
                    $username,
954
                    $password,
955
                    $auth_list,
956
                    $ruleno);
957
    }
958

    
959
    unlock($captiveportallck);
960

    
961
    return $auth_list;
962

    
963
}
964

    
965
/* read captive portal DB into array */
966
function captiveportal_read_db() {
967

    
968
        global $g;
969

    
970
        $cpdb = array();
971
        $fd = @fopen("{$g['vardb_path']}/captiveportal.db", "r");
972
        if ($fd) {
973
                while (!feof($fd)) {
974
                        $line = trim(fgets($fd));
975
                        if ($line) {
976
                                $cpdb[] = explode(",", $line);
977
                        }
978
                }
979
                fclose($fd);
980
        }
981
        return $cpdb;
982
}
983

    
984
/* write captive portal DB */
985
function captiveportal_write_db($cpdb) {
986
                 
987
        global $g;
988
                
989
        $fd = @fopen("{$g['vardb_path']}/captiveportal.db", "w");
990
        if ($fd) { 
991
                foreach ($cpdb as $cpent) {
992
                        fwrite($fd, join(",", $cpent) . "\n");
993
                }       
994
                fclose($fd);
995
        }       
996
}
997

    
998
function captiveportal_write_elements() {
999
    global $g, $config;
1000
    
1001
    /* delete any existing elements */
1002
    if (is_dir($g['captiveportal_element_path'])) {
1003
        $dh = opendir($g['captiveportal_element_path']);
1004
        while (($file = readdir($dh)) !== false) {
1005
            if ($file != "." && $file != "..")
1006
                unlink($g['captiveportal_element_path'] . "/" . $file);
1007
        }
1008
        closedir($dh);
1009
    } else {
1010
        @mkdir($g['captiveportal_element_path']);
1011
    }
1012
    
1013
	if (is_array($config['captiveportal']['element'])) {
1014
		conf_mount_rw();
1015
		foreach ($config['captiveportal']['element'] as $data) {
1016
			$fd = @fopen($g['captiveportal_element_path'] . '/' . $data['name'], "wb");
1017
			if (!$fd) {
1018
				printf("Error: cannot open '{$data['name']}' in captiveportal_write_elements().\n");
1019
				return 1;
1020
			}
1021
			$decoded = base64_decode($data['content']);
1022
			fwrite($fd,$decoded);
1023
			fclose($fd);
1024
			unlink_if_exists("{$g['captiveportal_path']}/{$data['name']}");
1025
			unlink_if_exists("{$g['captiveportal_path']}/{$data['name']}");
1026
			mwexec("cd {$g['captiveportal_path']}/ && ln -s {$g['captiveportal_element_path']}/{$data['name']} {$data['name']}");
1027
		}
1028
		conf_mount_ro();
1029
	}
1030
    
1031
    return 0;
1032
}
1033

    
1034
function captiveportal_init_ipfw_ruleno($rulenos_start = 2000, $rulenos_range_max = 49899) {
1035
	global $g;
1036

    
1037
	@unlink("{$g['vardb_path']}/captiveportal.rules");
1038
	$rules = array_pad(array(), $rulenos_range_max - $rulenos_start, false);
1039
	file_put_contents("{$g['vardb_path']}/captiveportal.rules", serialize($rules));
1040
}
1041

    
1042
/*
1043
 * This function will calculate the lowest free firewall ruleno
1044
 * within the range specified based on the actual logged on users
1045
 *
1046
 */
1047
function captiveportal_get_next_ipfw_ruleno($rulenos_start = 2000, $rulenos_range_max = 49899, $usebw = false) {
1048
	global $config, $g;
1049

    
1050
	if(!isset($config['captiveportal']['enable']))
1051
		return NULL;
1052

    
1053
	$ruleno = 0;
1054
	if (file_exists("{$g['vardb_path']}/captiveportal.rules")) {
1055
		$rules = unserialize(file_get_contents("{$g['vardb_path']}/captiveportal.rules"));
1056
		for ($ridx = 2; $ridx < ($rulenos_range_max - $rulenos_start); $ridx++) {
1057
			if ($rules[$ridx]) {
1058
				/* 
1059
	 			 * This allows our traffic shaping pipes to be the in pipe the same as ruleno 
1060
	 			 * and the out pipe ruleno + 1. This removes limitation that where present in 
1061
	 			 * previous version of the peruserbw.
1062
	 			 */
1063
				if (isset($config['captiveportal']['peruserbw']))
1064
					$ridx++;
1065
				continue;
1066
			}
1067
			$ruleno = $ridx;
1068
			$rules[$ridx] = "used";
1069
			if (isset($config['captiveportal']['peruserbw']) || $usebw == true)
1070
				$rules[++$ridx] = "used";
1071
			break;
1072
		}
1073
	} else {
1074
		$rules = array_pad(array(), $rulenos_range_max - $rulenos_start, false);
1075
		$rules[2] = "used";
1076
		$ruleno = 2;
1077
	}
1078
	file_put_contents("{$g['vardb_path']}/captiveportal.rules", serialize($rules));
1079
	return $ruleno;
1080
}
1081

    
1082
function captiveportal_free_ipfw_ruleno($ruleno, $usedbw = false) {
1083
	global $config, $g;
1084

    
1085
	if(!isset($config['captiveportal']['enable']))
1086
		return NULL;
1087

    
1088
	if (file_exists("{$g['vardb_path']}/captiveportal.rules")) {
1089
		$rules = unserialize(file_get_contents("{$g['vardb_path']}/captiveportal.rules"));
1090
		$rules[$ruleno] = false;
1091
		if (isset($config['captiveportal']['peruserbw']) || $usedbw == true)
1092
			$rules[++$ruleno] = false;
1093
		file_put_contents("{$g['vardb_path']}/captiveportal.rules", serialize($rules));
1094
	}
1095
}
1096

    
1097
function captiveportal_get_ipfw_passthru_ruleno($value) {
1098
	global $config, $g;
1099

    
1100
	if(!isset($config['captiveportal']['enable']))
1101
                return NULL;
1102

    
1103
        if (file_exists("{$g['vardb_path']}/captiveportal.rules")) {
1104
                $rules = unserialize(file_get_contents("{$g['vardb_path']}/captiveportal.rules"));
1105
		$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`);
1106
		if ($rules[$ruleno])
1107
			return $ruleno;
1108
        }
1109

    
1110
	return NULL;
1111
}
1112

    
1113
/**
1114
 * This function will calculate the traffic produced by a client
1115
 * based on its firewall rule
1116
 *
1117
 * Point of view: NAS
1118
 *
1119
 * Input means: from the client
1120
 * Output means: to the client
1121
 *
1122
 */
1123

    
1124
function getVolume($ip) {
1125

    
1126
    $volume = array();
1127

    
1128
    // Initialize vars properly, since we don't want NULL vars
1129
    $volume['input_pkts'] = $volume['input_bytes'] = $volume['output_pkts'] = $volume['output_bytes'] = 0 ;
1130

    
1131
    // Ingress
1132
    $ipfwin = "";
1133
    $ipfwout = "";
1134
    $matchesin = "";
1135
    $matchesout = "";
1136
    exec("/sbin/ipfw table 1 entrystats {$ip}", $ipfwin);
1137
    if ($ipfwin[0]) {
1138
		$ipfwin = split(" ", $ipfwin[0]);
1139
		$volume['input_pkts'] = $ipfwin[2];
1140
		$volume['input_bytes'] = $ipfwin[3];
1141
    }
1142

    
1143
    exec("/sbin/ipfw table 2 entrystats {$ip}", $ipfwout);
1144
    if ($ipfwout[0]) {
1145
        $ipfwout = split(" ", $ipfwout[0]);
1146
        $volume['output_pkts'] = $ipfwout[2];
1147
        $volume['output_bytes'] = $ipfwout[3];
1148
    }
1149

    
1150
    return $volume;
1151
}
1152

    
1153
/**
1154
 * Get the NAS-Identifier
1155
 *
1156
 * We will use our local hostname to make up the nas_id
1157
 */
1158
function getNasID()
1159
{
1160
    $nasId = "";
1161
    exec("/bin/hostname", $nasId);
1162
    if(!$nasId[0])
1163
        $nasId[0] = "{$g['product_name']}";
1164
    return $nasId[0];
1165
}
1166

    
1167
/**
1168
 * Get the NAS-IP-Address based on the current wan address
1169
 *
1170
 * Use functions in interfaces.inc to find this out
1171
 *
1172
 */
1173

    
1174
function getNasIP()
1175
{
1176
    $nasIp = get_interface_ip();
1177
    if(!$nasIp)
1178
        $nasIp = "0.0.0.0";
1179
    return $nasIp;
1180
}
1181

    
1182
function portal_ip_from_client_ip($cliip) {
1183
	global $config;
1184

    
1185
	$interfaces = explode(",", $config['captiveportal']['interface']);
1186
	foreach ($interfaces as $cpif) {
1187
		$ip = get_interface_ip($cpif);
1188
		$sn = get_interface_subnet($cpif);
1189
		if (ip_in_subnet($cliip, "{$ip}/{$sn}"))
1190
			return $ip;
1191
	}
1192

    
1193
	// doesn't match up to any particular interface
1194
	// so let's set the portal IP to what PHP says 
1195
	// the server IP issuing the request is. 
1196
	// allows same behavior as 1.2.x where IP isn't 
1197
	// in the subnet of any CP interface (static routes, etc.)
1198
	// rather than forcing to DNS hostname resolution
1199
	$ip = $_SERVER['SERVER_ADDR'];
1200
	if (is_ipaddr($ip))
1201
		return $ip;
1202

    
1203
	return false;
1204
}
1205

    
1206
?>
(6-6/50)