Project

General

Profile

Download (47.6 KB) Statistics
| Branch: | Tag: | Revision:
1 5b237745 Scott Ullrich
<?php
2
/*
3
	captiveportal.inc
4 b260c8e0 Scott Ullrich
	part of pfSense (http://www.pfSense.org)
5 36254e4a Scott Ullrich
6 b260c8e0 Scott Ullrich
	originally part of m0n0wall (http://m0n0.ch/wall)
7
8
	Copyright (C) 2010 Scott Ullrich <sullrich@gmail.com>
9
	Copyright (C) 2009 Ermal Lu?i <ermal.luci@gmail.com>
10 0bd34ed6 Scott Ullrich
	Copyright (C) 2003-2006 Manuel Kasper <mk@neon1.net>.
11 5b237745 Scott Ullrich
	All rights reserved.
12 36254e4a Scott Ullrich
13 5b237745 Scott Ullrich
	Redistribution and use in source and binary forms, with or without
14
	modification, are permitted provided that the following conditions are met:
15 36254e4a Scott Ullrich
16 5b237745 Scott Ullrich
	1. Redistributions of source code must retain the above copyright notice,
17
	   this list of conditions and the following disclaimer.
18 36254e4a Scott Ullrich
19 5b237745 Scott Ullrich
	2. Redistributions in binary form must reproduce the above copyright
20
	   notice, this list of conditions and the following disclaimer in the
21
	   documentation and/or other materials provided with the distribution.
22 36254e4a Scott Ullrich
23 5b237745 Scott Ullrich
	THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
24
	INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
25
	AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
26
	AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
27
	OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
28
	SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
29
	INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
30
	CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
31
	ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
32
	POSSIBILITY OF SUCH DAMAGE.
33 ca83c6ea Scott Ullrich
34 9699028a Scott Ullrich
	This version of captiveportal.inc has been modified by Rob Parker
35
	<rob.parker@keycom.co.uk> to include changes for per-user bandwidth management
36
	via returned RADIUS attributes. This page has been modified to delete any
37
	added rules which may have been created by other per-user code (index.php, etc).
38
	These changes are (c) 2004 Keycom PLC.
39 523855b0 Scott Ullrich
	
40 bf444c34 Ermal
	pfSense_BUILDER_BINARIES:	/sbin/ipfw	/sbin/sysctl	/sbin/kldunload
41 523855b0 Scott Ullrich
	pfSense_BUILDER_BINARIES:	/usr/local/sbin/lighttpd	/usr/local/bin/minicron	/sbin/pfctl
42
	pfSense_BUILDER_BINARIES:	/bin/hostname	/bin/cp	
43
	pfSense_MODULE:	captiveportal
44 9699028a Scott Ullrich
*/
45 36254e4a Scott Ullrich
46 5b237745 Scott Ullrich
/* include all configuration functions */
47 a55cdcc0 Ermal Lu?i
require_once("config.inc");
48
require_once("functions.inc");
49 71fdaecd Ermal
require_once("filter.inc");
50 856e58a6 Scott Ullrich
require_once("radius.inc");
51 156487ed Ermal Lu?i
require_once("voucher.inc");
52 0bd34ed6 Scott Ullrich
53 023aa1f2 Scott Ullrich
function get_default_captive_portal_html() {
54 5b237745 Scott Ullrich
	global $config, $g;
55 023aa1f2 Scott Ullrich
	// Detect if vouchers are being used and default to the voucher page
56 10370262 Scott Ullrich
	if(isset($config['voucher']['enable'])) {
57 023aa1f2 Scott Ullrich
			$htmltext = <<<EOD
58
<html> 
59
	<body> 
60
		<form method="post" action="\$PORTAL_ACTION\$"> 
61
			<center>
62
				<table cellpadding="6" cellspacing="0" width="550" height="380" style="border:1px solid #000000">
63
					<tr height="10" bgcolor="#990000">
64
						<td style="border-bottom:1px solid #000000">
65
							<font color='white'>
66
								<b>
67
									Guest Voucher code required to continue
68
								</b>
69
							</font>
70
						</td>
71
					</tr>
72
					<tr>
73
						<td>
74
							<div id="mainlevel">
75
								<center>
76
									<table width="100%" border="0" cellpadding="5" cellspacing="0">
77
								 		<tr>
78
								    		<td>
79
												<center>
80
													<div id="mainarea">
81
														<center>
82
															<table width="100%" border="0" cellpadding="5" cellspacing="5">
83
																<tr>
84
																	<td>
85
																		<div id="maindivarea">
86
																			<center>
87
																				<div id='statusbox'>
88
																					<font color='red' face='arial' size='+1'>
89
																						<b>
90
																							\$PORTAL_MESSAGE\$
91
																						</b>
92
																					</font>
93
																				</div>
94
																				<p/>
95
																				<div id='loginbox'>
96
																					Enter Voucher Code: 
97
																					<input name="auth_voucher" type="text" style="border:1px dashed;" size="22"> 
98
																					<input name="redirurl" type="hidden" value="\$PORTAL_REDIRURL\$"> 
99
																					<input name="accept" type="submit" value="Continue"> 
100
																				</div>
101
																			</center>
102
																		</div>
103
										     						</td>
104
																</tr>
105
															</table>
106
														</center>
107
													</div>
108
												</center>
109
											</td>
110
										</tr>
111
									</table>
112
								</center>
113
							</div>
114
						</td>
115
					</tr>
116
				</table>
117
			</center>
118
		</form>
119
	</body> 
120
</html>
121 36254e4a Scott Ullrich
122 023aa1f2 Scott Ullrich
EOD;
123 c2056357 Scott Ullrich
		return $htmltext;
124
	}
125 0bd34ed6 Scott Ullrich
126 023aa1f2 Scott Ullrich
	// Vouchers are not found, return the normal user/pass auth page
127
	$htmltext = <<<EOD
128 b260c8e0 Scott Ullrich
<html> 
129
	<body> 
130 ce7c3bb5 Scott Ullrich
		<form method="post" action="\$PORTAL_ACTION\$"> 
131
		<input name="redirurl" type="hidden" value="\$PORTAL_REDIRURL\$">
132 b260c8e0 Scott Ullrich
			<center>
133
				<table cellpadding="6" cellspacing="0" width="550" height="380" style="border:1px solid #000000">
134
					<tr height="10" bgcolor="#990000">
135
						<td style="border-bottom:1px solid #000000">
136
							<font color='white'>
137
								<b>
138
									{$g['product_name']} captive portal
139
								</b>
140
							</font>
141
						</td>
142
					</tr>
143
					<tr>
144
						<td>
145
							<div id="mainlevel">
146
								<center>
147
									<table width="100%" border="0" cellpadding="5" cellspacing="0">
148
								 		<tr>
149
								    		<td>
150
												<center>
151
													<div id="mainarea">
152
														<center>
153
															<table width="100%" border="0" cellpadding="5" cellspacing="5">
154
																<tr>
155
										     						<td>
156
																		<div id="maindivarea">
157
																			<center>
158
																				<div id='statusbox'>
159
																					<font color='red' face='arial' size='+1'>
160
																						<b>
161 ce7c3bb5 Scott Ullrich
																							\$PORTAL_MESSAGE\$
162 b260c8e0 Scott Ullrich
																						</b>
163
																					</font>
164
																				</div>
165
																				<br/>
166
																				<div id='loginbox'>
167
																					<table>
168
																					   <tr><td colspan="2"><center>Welcome to the {$g['product_name']} Captive Portal!</td></tr>
169
																					   <tr><td>&nbsp;</td></tr>
170
																					   <tr><td align="right">Username:</td><td><input name="auth_user" type="text" style="border: 1px dashed;"></td></tr>
171
																					   <tr><td align="right">Password:</td><td><input name="auth_pass" type="password" style="border: 1px dashed;"></td></tr>
172
																					   <tr><td>&nbsp;</td></tr>
173
																					   <tr>
174
																					     <td colspan="2">
175
																							<center><input name="accept" type="submit" value="Continue"></center>
176
																					     </td>
177
																					   </tr>
178
																					</table>
179
																				</div>
180
																			</center>
181
																		</div>
182
										     						</td>
183
																</tr>
184
															</table>
185
														</center>
186
													</div>
187
												</center>
188
											</td>
189
										</tr>
190
									</table>
191
								</center>
192
							</div>
193
						</td>
194
					</tr>
195
				</table>
196
			</center>
197
		</form>
198
	</body> 
199 5b237745 Scott Ullrich
</html>
200
201 023aa1f2 Scott Ullrich
EOD;
202 0bd34ed6 Scott Ullrich
203 023aa1f2 Scott Ullrich
	return $htmltext;
204
}
205 0bd34ed6 Scott Ullrich
206 023aa1f2 Scott Ullrich
function captiveportal_configure() {
207
	global $config, $g;
208
209
	$captiveportallck = lock('captiveportal');
210
	
211
	if (isset($config['captiveportal']['enable'])) {
212
213
		if ($g['booting'])
214
			echo "Starting captive portal... ";
215
216
		/* kill any running mini_httpd */
217
		killbypid("{$g['varrun_path']}/lighty-CaptivePortal.pid");
218
		killbypid("{$g['varrun_path']}/lighty-CaptivePortal-SSL.pid");
219
220
		/* remove old information */
221
		unlink_if_exists("{$g['vardb_path']}/captiveportal.db");
222
		unlink_if_exists("{$g['vardb_path']}/captiveportal_mac.db");
223
		unlink_if_exists("{$g['vardb_path']}/captiveportal_ip.db");
224
		unlink_if_exists("{$g['vardb_path']}/captiveportal_radius.db");
225
226
		/* setup new database in case someone tries to access the status -> captive portal page */
227
		touch("{$g['vardb_path']}/captiveportal.db");
228
229
		/* kill any running minicron */
230
		killbypid("{$g['varrun_path']}/minicron.pid");
231
232
		/* init ipfw rules */
233
		captiveportal_init_rules(true);
234
235
		/* stop accounting on all clients */
236
		captiveportal_radius_stop_all(true);
237
238
		/* initialize minicron interval value */
239
		$croninterval = $config['captiveportal']['croninterval'] ? $config['captiveportal']['croninterval'] : 60;
240
241
		/* double check if the $croninterval is numeric and at least 10 seconds. If not we set it to 60 to avoid problems */
242
		if ((!is_numeric($croninterval)) || ($croninterval < 10)) { $croninterval = 60; }
243
244
		/* write portal page */
245
		if ($config['captiveportal']['page']['htmltext'])
246
			$htmltext = base64_decode($config['captiveportal']['page']['htmltext']);
247
		else {
248
			/* example/template page */
249
			$htmltext = get_default_captive_portal_html();
250 5b237745 Scott Ullrich
		}
251
252
		$fd = @fopen("{$g['varetc_path']}/captiveportal.html", "w");
253
		if ($fd) {
254 7a7e94a7 Scott Ullrich
			// Special case handling.  Convert so that we can pass this page
255
			// through the PHP interpreter later without clobbering the vars.
256
			$htmltext = str_replace("\$PORTAL_REDIRURL\$", "#PORTAL_REDIRURL#", $htmltext);
257
			$htmltext = str_replace("\$PORTAL_MESSAGE\$", "#PORTAL_MESSAGE#", $htmltext);
258
			$htmltext = str_replace("\$CLIENT_MAC\$", "#CLIENT_MAC#", $htmltext);
259
			$htmltext = str_replace("\$CLIENT_IP\$", "#CLIENT_IP#", $htmltext);
260
			$htmltext = str_replace("\$ORIGINAL_PORTAL_IP\$", "#ORIGINAL_PORTAL_IP#", $htmltext);
261
			$htmltext = str_replace("\$PORTAL_ACTION\$", "#PORTAL_ACTION#", $htmltext);
262 5b237745 Scott Ullrich
			fwrite($fd, $htmltext);
263 36254e4a Scott Ullrich
			fclose($fd);
264 5b237745 Scott Ullrich
		}
265 36254e4a Scott Ullrich
266 5b237745 Scott Ullrich
		/* write error page */
267
		if ($config['captiveportal']['page']['errtext'])
268
			$errtext = base64_decode($config['captiveportal']['page']['errtext']);
269
		else {
270
			/* example page */
271
			$errtext = <<<EOD
272 b260c8e0 Scott Ullrich
<html> 
273
	<body> 
274 ce7c3bb5 Scott Ullrich
		<form method="post" action="\$PORTAL_ACTION\$"> 
275
		<input name="redirurl" type="hidden" value="\$PORTAL_REDIRURL\$">
276 b260c8e0 Scott Ullrich
			<center>
277
				<table cellpadding="6" cellspacing="0" width="550" height="380" style="border:1px solid #000000">
278
					<tr height="10" bgcolor="#990000">
279
						<td style="border-bottom:1px solid #000000">
280
							<font color='white'>
281
								<b>
282
									{$g['product_name']} captive portal
283
								</b>
284
							</font>
285
						</td>
286
					</tr>
287
					<tr>
288
						<td>
289
							<div id="mainlevel">
290
								<center>
291
									<table width="100%" border="0" cellpadding="5" cellspacing="0">
292
								 		<tr>
293
								    		<td>
294
												<center>
295
													<div id="mainarea">
296
														<center>
297
															<table width="100%" border="0" cellpadding="5" cellspacing="5">
298
																<tr>
299
										     						<td>
300
																		<div id="maindivarea">
301
																			<center>
302
																				<div id='statusbox'>
303
																					<font color='red' face='arial' size='+1'>
304
																						<b>
305 ce7c3bb5 Scott Ullrich
																							\$PORTAL_MESSAGE\$
306 b260c8e0 Scott Ullrich
																						</b>
307
																					</font>
308
																				</div>
309
																				<br/>
310
																				<div id='loginbox'>
311
																					<table>
312
																					   <tr><td colspan="2"><center>Welcome to the {$g['product_name']} Captive Portal!</td></tr>
313
																					   <tr><td>&nbsp;</td></tr>
314
																					   <tr><td align="right">Username:</td><td><input name="auth_user" type="text" style="border: 1px dashed;"></td></tr>
315
																					   <tr><td align="right">Password:</td><td><input name="auth_pass" type="password" style="border: 1px dashed;"></td></tr>
316
																					   <tr><td>&nbsp;</td></tr>
317
																					   <tr>
318
																					     <td colspan="2">
319
																							<center><input name="accept" type="submit" value="Continue"></center>
320
																					     </td>
321
																					   </tr>
322
																					</table>
323
																				</div>
324
																			</center>
325
																		</div>
326
										     						</td>
327
																</tr>
328
															</table>
329
														</center>
330
													</div>
331
												</center>
332
											</td>
333
										</tr>
334
									</table>
335
								</center>
336
							</div>
337
						</td>
338
					</tr>
339
				</table>
340
			</center>
341
		</form>
342
	</body> 
343 5b237745 Scott Ullrich
</html>
344
345
EOD;
346
		}
347
348
		$fd = @fopen("{$g['varetc_path']}/captiveportal-error.html", "w");
349
		if ($fd) {
350 7a7e94a7 Scott Ullrich
			// Special case handling.  Convert so that we can pass this page
351
			// through the PHP interpreter later without clobbering the vars.
352
			$errtext = str_replace("\$PORTAL_REDIRURL\$", "#PORTAL_REDIRURL#", $errtext);
353
			$errtext = str_replace("\$PORTAL_MESSAGE\$", "#PORTAL_MESSAGE#", $errtext);
354
			$errtext = str_replace("\$CLIENT_MAC\$", "#CLIENT_MAC#", $errtext);
355
			$errtext = str_replace("\$CLIENT_IP\$", "#CLIENT_IP#", $errtext);
356
			$errtext = str_replace("\$ORIGINAL_PORTAL_IP\$", "#ORIGINAL_PORTAL_IP#", $errtext);
357
			$errtext = str_replace("\$PORTAL_ACTION\$", "#PORTAL_ACTION#", $errtext);
358 5b237745 Scott Ullrich
			fwrite($fd, $errtext);
359 36254e4a Scott Ullrich
			fclose($fd);
360 5b237745 Scott Ullrich
		}
361 36254e4a Scott Ullrich
362 5b87b24e Ermal
		/* write error page */
363
		if ($config['captiveportal']['page']['logouttext'])
364
			$logouttext = base64_decode($config['captiveportal']['page']['logouttext']);
365
		else {
366
			/* example page */
367
			$logouttext = <<<EOD
368
<HTML>
369
<HEAD><TITLE>Redirecting...</TITLE></HEAD>
370
<BODY>
371
<SPAN STYLE="font-family: Tahoma, Verdana, Arial, Helvetica, sans-serif; font-size: 11px;">
372 6991e1a6 Erik Fonnesbeck
<B>Redirecting to <A HREF="<?=\$my_redirurl;?>"><?=\$my_redirurl;?></A>...</B>
373 5b87b24e Ermal
</SPAN>
374
<SCRIPT LANGUAGE="JavaScript">
375
<!--
376
LogoutWin = window.open('', 'Logout', 'toolbar=0,scrollbars=0,location=0,statusbar=0,menubar=0,resizable=0,width=256,height=64');
377
if (LogoutWin) {
378
    LogoutWin.document.write('<HTML>');
379
    LogoutWin.document.write('<HEAD><TITLE>Logout</TITLE></HEAD>') ;
380
    LogoutWin.document.write('<BODY BGCOLOR="#435370">');
381
    LogoutWin.document.write('<DIV ALIGN="center" STYLE="color: #ffffff; font-family: Tahoma, Verdana, Arial, Helvetica, sans-serif; font-size: 11px;">') ;
382
    LogoutWin.document.write('<B>Click the button below to disconnect</B><P>');
383 6991e1a6 Erik Fonnesbeck
    LogoutWin.document.write('<FORM METHOD="POST" ACTION="<?=\$logouturl;?>">');
384
    LogoutWin.document.write('<INPUT NAME="logout_id" TYPE="hidden" VALUE="<?=\$sessionid;?>">');
385 5b87b24e Ermal
    LogoutWin.document.write('<INPUT NAME="logout" TYPE="submit" VALUE="Logout">');
386
    LogoutWin.document.write('</FORM>');
387
    LogoutWin.document.write('</DIV></BODY>');
388
    LogoutWin.document.write('</HTML>');
389
    LogoutWin.document.close();
390
}
391
392 6991e1a6 Erik Fonnesbeck
document.location.href="<?=\$my_redirurl;?>";
393 5b87b24e Ermal
-->
394
</SCRIPT>
395
</BODY>
396
</HTML>
397
398
EOD;
399
		}
400
401
		$fd = @fopen("{$g['varetc_path']}/captiveportal-logout.html", "w");
402
		if ($fd) {
403
			fwrite($fd, $logouttext);
404
			fclose($fd);
405
		}
406 0bd34ed6 Scott Ullrich
		/* write elements */
407
		captiveportal_write_elements();
408 5b237745 Scott Ullrich
409 769e254e Ermal
		/* start up the webserving daemon */
410
		captiveportal_init_webgui();
411 36254e4a Scott Ullrich
412 0bd34ed6 Scott Ullrich
		/* start pruning process (interval defaults to 60 seconds) */
413
		mwexec("/usr/local/bin/minicron $croninterval {$g['varrun_path']}/minicron.pid " .
414 c6c92abf Scott Ullrich
			"/etc/rc.prunecaptiveportal");
415 36254e4a Scott Ullrich
416 d99f7864 Scott Ullrich
		/* generate radius server database */
417
		if ($config['captiveportal']['radiusip'] && (!isset($config['captiveportal']['auth_method']) ||
418
				($config['captiveportal']['auth_method'] == "radius"))) {
419
			$radiusip = $config['captiveportal']['radiusip'];
420
			$radiusip2 = ($config['captiveportal']['radiusip2']) ? $config['captiveportal']['radiusip2'] : null;
421
422
			if ($config['captiveportal']['radiusport'])
423
				$radiusport = $config['captiveportal']['radiusport'];
424
			else
425
				$radiusport = 1812;
426
427
			if ($config['captiveportal']['radiusacctport'])
428
				$radiusacctport = $config['captiveportal']['radiusacctport'];
429
			else
430
				$radiusacctport = 1813;
431
432
			if ($config['captiveportal']['radiusport2'])
433
				$radiusport2 = $config['captiveportal']['radiusport2'];
434
			else
435
				$radiusport2 = 1812;
436
437
			$radiuskey = $config['captiveportal']['radiuskey'];
438
			$radiuskey2 = ($config['captiveportal']['radiuskey2']) ? $config['captiveportal']['radiuskey2'] : null;
439
440
			$fd = @fopen("{$g['vardb_path']}/captiveportal_radius.db", "w");
441
			if (!$fd) {
442
				printf("Error: cannot open radius DB file in captiveportal_configure().\n");
443
				return 1;
444
			} else if (isset($radiusip2, $radiuskey2)) {
445
				fwrite($fd,$radiusip . "," . $radiusport . "," . $radiusacctport . "," . $radiuskey . "\n"
446
					 . $radiusip2 . "," . $radiusport2 . "," . $radiusacctport . "," . $radiuskey2);
447
			} else {
448
				fwrite($fd,$radiusip . "," . $radiusport . "," . $radiusacctport . "," . $radiuskey);
449
			}
450
			fclose($fd);
451
		}
452 36254e4a Scott Ullrich
453 d99f7864 Scott Ullrich
		if ($g['booting'])
454
			echo "done\n";
455 36254e4a Scott Ullrich
456 5b237745 Scott Ullrich
	} else {
457 23a0c341 Scott Ullrich
		killbypid("{$g['varrun_path']}/lighty-CaptivePortal.pid");
458 c6c92abf Scott Ullrich
		killbypid("{$g['varrun_path']}/minicron.pid");
459 12ee8fe4 Scott Ullrich
460 dedf51a2 Ermal Lu?i
		captiveportal_radius_stop_all(true);
461 3db19cf1 Scott Ullrich
462
		mwexec("/sbin/sysctl net.link.ether.ipfw=0");
463
464 5209079f Ermal Luçi
		/* unload ipfw */
465 faebbab3 Scott Ullrich
		if (is_module_loaded("ipfw.ko"))		
466
			mwexec("/sbin/kldunload ipfw.ko");
467 85250056 Ermal Lu?i
		$listifs = get_configured_interface_list_by_realif();
468 bbc6768b Ermal Lu?i
		foreach ($listifs as $listrealif => $listif) {
469 7c587b9f Ermal Lu?i
			if (!empty($listrealif)) {
470 da9d6701 Ermal
				if (does_interface_exist($listrealif)) {
471 bf444c34 Ermal
					pfSense_interface_flags($listrealif, -IFF_IPFW_FILTER);
472 da9d6701 Ermal
					$carpif = link_ip_to_carp_interface(find_interface_ip($listrealif));
473
                        		if (!empty($carpif)) {
474
						$carpsif = explode(" ", $carpif);
475
						foreach ($carpsif as $cpcarp)
476 bf444c34 Ermal
							pfSense_interface_flags($cpcarp, -IFF_IPFW_FILTER);
477 da9d6701 Ermal
					}
478 2ee45728 Ermal Lu?i
				}
479 bbc6768b Ermal Lu?i
			}
480
		}
481 3db19cf1 Scott Ullrich
	}
482 36254e4a Scott Ullrich
483 f8b11310 Ermal Lu?i
	unlock($captiveportallck);
484 c3214b80 Scott Ullrich
	
485 5b237745 Scott Ullrich
	return 0;
486
}
487
488 769e254e Ermal
function captiveportal_init_webgui() {
489
	global $g, $config;
490
491
	 if (!isset($config['captiveportal']['enable']))
492
                return;
493
494
	if ($config['captiveportal']['maxproc'])
495
		$maxproc = $config['captiveportal']['maxproc'];
496
	else
497
		$maxproc = 16;
498
499
	$use_fastcgi = true;
500
501
	if (isset($config['captiveportal']['httpslogin'])) {
502
		$cert = base64_decode($config['captiveportal']['certificate']);
503
		if (isset($config['captiveportal']['cacertificate']))
504
			$cacert = base64_decode($config['captiveportal']['cacertificate']);
505
		else
506
			$cacert = "";
507
		$key = base64_decode($config['captiveportal']['private-key']);
508
		/* generate lighttpd configuration */
509
		system_generate_lighty_config("{$g['varetc_path']}/lighty-CaptivePortal-SSL.conf",
510
			$cert, $key, $cacert, "lighty-CaptivePortal-ssl.pid", "8001", "/usr/local/captiveportal/",
511
			"cert-portal.pem", "ca-portal.pem", "1", $maxproc, $use_fastcgi, true);
512
	}
513
514
	/* generate lighttpd configuration */
515
	system_generate_lighty_config("{$g['varetc_path']}/lighty-CaptivePortal.conf",
516
		"", "", "", "lighty-CaptivePortal.pid", "8000", "/usr/local/captiveportal/",
517
		"cert-portal.pem", "ca-portal.pem", "1", $maxproc, $use_fastcgi, true);
518
519
	/* attempt to start lighttpd */
520
	$res = mwexec("/usr/local/sbin/lighttpd -f {$g['varetc_path']}/lighty-CaptivePortal.conf");
521
522
	/* fire up https instance */
523
	if (isset($config['captiveportal']['httpslogin']))
524
		$res = mwexec("/usr/local/sbin/lighttpd -f {$g['varetc_path']}/lighty-CaptivePortal-SSL.conf");
525
}
526
527 1d9e9cca Ermal
function captiveportal_init_rules($reinit = false) {
528 3db19cf1 Scott Ullrich
	global $config, $g;
529 36254e4a Scott Ullrich
530 769e254e Ermal
	if (!isset($config['captiveportal']['enable']))
531
		return;
532
533
	$cpips = array();
534
	$ifaces = get_configured_interface_list();
535
	foreach ($ifaces as $kiface => $kiface2) {
536
		$tmpif = get_real_interface($kiface);
537
		pfSense_interface_flags($tmpif, -IFF_IPFW_FILTER);
538
	}
539
	$cpinterfaces = explode(",", $config['captiveportal']['interface']);
540
	$firsttime = 0;
541
	foreach ($cpinterfaces as $cpifgrp) {
542
		if (!isset($ifaces[$cpifgrp]))
543
			continue;
544
		$tmpif = get_real_interface($cpifgrp);
545
		if (!empty($tmpif)) {
546
			if ($firsttime > 0)
547
				$cpinterface .= " or ";
548
			$cpinterface .= "via {$tmpif}";
549
			$firsttime = 1;
550
			$cpipm = get_interface_ip($cpifgrp);
551
			if (is_ipaddr($cpipm)) {
552
				$carpif = link_ip_to_carp_interface($cpipm);
553
				if (!empty($carpif)) {
554
					$carpsif = explode(" ", $carpif);
555
					foreach ($carpsif as $cpcarp) {
556
						pfSense_interface_flags($cpcarp, IFF_IPFW_FILTER);
557
						$carpip = find_interface_ip($cpcarp);
558
						if (is_ipaddr($carpip))
559
							$cpips[] = $carpip;
560
					}
561
				}
562
				$cpips[] = $cpipm;
563
				pfSense_interface_flags($tmpif, IFF_IPFW_FILTER);
564
			}
565
		}
566
	}
567
	if (count($cpips) > 0) {
568
		$cpactive = true;
569
		$cpinterface = "{ {$cpinterface} } ";
570
        } else
571
		return false;
572
573 eade409a Ermal
	if ($reinit == false)
574
		$captiveportallck = lock('captiveportal');
575
576 1d9e9cca Ermal
	/* init dummynet/ipfw rules number database */
577
	captiveportal_init_ipfw_ruleno();
578
579 769e254e Ermal
	/* make sure ipfw is loaded */
580
	if (!is_module_loaded("ipfw.ko"))
581
		filter_load_ipfw();
582
	/* Always load dummynet now that even allowed ip and mac passthrough use it. */
583
	if (!is_module_loaded("dummynet.ko"))
584
		mwexec("/sbin/kldload dummynet");
585
586 b01792a0 Ermal
	$cprules =  "add 65291 set 1 allow pfsync from any to any\n";
587
	$cprules .= "add 65292 set 1 allow carp from any to any\n";
588 181a843c Scott Ullrich
589 3db19cf1 Scott Ullrich
	$cprules .= <<<EOD
590 b01792a0 Ermal
# add 65300 set 1 skipto 65534 all from any to any not layer2
591 3db19cf1 Scott Ullrich
# layer 2: pass ARP
592 b01792a0 Ermal
add 65301 set 1 pass layer2 mac-type arp
593 b9d1d810 Scott Ullrich
# pfsense requires for WPA
594 b01792a0 Ermal
add 65302 set 1 pass layer2 mac-type 0x888e
595
add 65303 set 1 pass layer2 mac-type 0x88c7
596 684c787e Scott Ullrich
597 36254e4a Scott Ullrich
# PPP Over Ethernet Discovery Stage
598 b01792a0 Ermal
add 65304 set 1 pass layer2 mac-type 0x8863
599 684c787e Scott Ullrich
# PPP Over Ethernet Session Stage
600 b01792a0 Ermal
add 65305 set 1 pass layer2 mac-type 0x8864
601 55f5c311 Ermal Lu?i
# Allow WPA
602 b01792a0 Ermal
add 65306 set 1 pass layer2 mac-type 0x888e
603 684c787e Scott Ullrich
604 3db19cf1 Scott Ullrich
# layer 2: block anything else non-IP
605 b01792a0 Ermal
add 65307 set 1 deny layer2 not mac-type ip
606 3db19cf1 Scott Ullrich
607
EOD;
608
609 b01792a0 Ermal
	$rulenum = 65310;
610 fb516dda Chris Buechler
	$ipcount = 0;
611 0ba17c67 Ermal
	$ips = "";
612 fb516dda Chris Buechler
	foreach ($cpips as $cpip) {
613
		if($ipcount == 0) {
614
			$ips = "{$cpip} ";
615
		} else {
616
			$ips .= "or {$cpip} ";
617
		}
618
		$ipcount++;
619
	}
620 0ba17c67 Ermal
	$ips = "{ 255.255.255.255 or {$ips} }";
621 746e60c9 Ermal
	$cprules .= "add {$rulenum} set 1 pass ip from any to {$ips} in\n";
622 2f27dffd Ermal
	$rulenum++;
623 746e60c9 Ermal
	$cprules .= "add {$rulenum} set 1 pass ip from {$ips} to any out\n";
624 2f27dffd Ermal
	$rulenum++;
625
	$cprules .= "add {$rulenum} set 1 pass icmp from {$ips} to any out icmptype 0\n";
626
	$rulenum++;
627
	$cprules .= "add {$rulenum} set 1 pass icmp from any to {$ips} in icmptype 8 \n";
628
	$rulenum++;
629 b01792a0 Ermal
	/* Allowed ips */
630
	$cprules .= "add {$rulenum} allow ip from table(3) to any in\n";
631
	$rulenum++;
632
	$cprules .= "add {$rulenum} allow ip from any to table(4) out\n";
633
	$rulenum++;
634
	$cprules .= "add {$rulenum} pipe tablearg ip from table(5) to any in\n";
635
	$rulenum++;
636
	$cprules .= "add {$rulenum} pipe tablearg ip from any to table(6) out\n";
637
	$rulenum++;
638
	$cprules .= "add {$rulenum} allow ip from any to table(7) in\n";
639
	$rulenum++;
640
	$cprules .= "add {$rulenum} allow ip from table(8) to any out\n";
641
	$rulenum++;
642
	$cprules .= "add {$rulenum} pipe tablearg ip from any to table(9) in\n";
643
	$rulenum++;
644
	$cprules .= "add {$rulenum} pipe tablearg ip from table(10) to any out\n";
645
	$rulenum++;
646
647
	/* Authenticated users rules. */
648 f9f71ad3 Ermal Lu?i
	if (isset($config['captiveportal']['peruserbw'])) {
649 6ce61a8f Ermal
		$cprules .= "add {$rulenum} set 1 pipe tablearg ip from table(1) to any in\n";
650 f9f71ad3 Ermal Lu?i
		$rulenum++;
651 6ce61a8f Ermal
		$cprules .= "add {$rulenum} set 1 pipe tablearg ip from any to table(2) out\n";
652 f9f71ad3 Ermal Lu?i
		$rulenum++;
653
	} else {
654 6ce61a8f Ermal
		$cprules .= "add {$rulenum} set 1 allow ip from table(1) to any in\n";
655 f9f71ad3 Ermal Lu?i
                $rulenum++;
656 6ce61a8f Ermal
                $cprules .= "add {$rulenum} set 1 allow ip from any to table(2) out\n";
657 f9f71ad3 Ermal Lu?i
                $rulenum++;
658
	}
659
	
660
       $cprules .= <<<EOD
661 5480497a Scott Ullrich
662 d44bccc7 Scott Ullrich
# redirect non-authenticated clients to captive portal
663 6ce61a8f Ermal
add 65531 set 1 fwd 127.0.0.1,8000 tcp from any to any in
664 3db19cf1 Scott Ullrich
# let the responses from the captive portal web server back out
665 6ce61a8f Ermal
add 65532 set 1 pass tcp from any to any out
666 3db19cf1 Scott Ullrich
# block everything else
667 6ce61a8f Ermal
add 65533 set 1 deny all from any to any
668 3db19cf1 Scott Ullrich
# pass everything else on layer2
669 6ce61a8f Ermal
add 65534 set 1 pass all from any to any layer2
670 3db19cf1 Scott Ullrich
671
EOD;
672
673 769e254e Ermal
	/* generate passthru mac database */
674
	$cprules .= captiveportal_passthrumac_configure(true);
675
	$cprules .= "\n";
676
	/* allowed ipfw rules to make allowed ip work */
677
	$cprules .= captiveportal_allowedip_configure();
678
679
	/* load rules */
680 1d9e9cca Ermal
	if ($reinit == true)
681
		$cprules = "table all flush\nflush\n{$cprules}";
682
	else {
683
		$tmprules = "table 3 flush\n";
684
		$tmprules .= "table 4 flush\n";
685
		$tmprules .= "table 5 flush\n";
686
		$tmprules .= "table 6 flush\n";
687
		$tmprules .= "table 7 flush\n";
688
		$tmprules .= "table 8 flush\n";
689
		$tmprules .= "table 9 flush\n";
690
		$tmprules .= "table 10 flush\n";
691
		$tmprules .= "flush\n";
692
		$cprules = "{$tmprules}\n{$cprules}";
693
	}
694 eade409a Ermal
695
	file_put_contents("{$g['tmp_path']}/ipfw.cp.rules", $cprules);
696
	mwexec("/sbin/ipfw -q {$g['tmp_path']}/ipfw.cp.rules", true);
697
	@unlink("{$g['tmp_path']}/ipfw.cp.rules");
698
699
	if ($reinit == false)
700
		unlock($captiveportallck);
701
702 769e254e Ermal
703
	/* filter on layer2 as well so we can check MAC addresses */
704
	mwexec("/sbin/sysctl net.link.ether.ipfw=1");
705
706
	return $cprules;
707 3db19cf1 Scott Ullrich
}
708
709 5b237745 Scott Ullrich
/* remove clients that have been around for longer than the specified amount of time */
710 36254e4a Scott Ullrich
/* db file structure:
711 0bd34ed6 Scott Ullrich
timestamp,ipfw_rule_no,clientip,clientmac,username,sessionid,password,session_timeout,idle_timeout,session_terminate_time */
712
713 3db19cf1 Scott Ullrich
/* (password is in Base64 and only saved when reauthentication is enabled) */
714 5b237745 Scott Ullrich
function captiveportal_prune_old() {
715 0bd34ed6 Scott Ullrich
716 23c4f978 Scott Ullrich
    global $g, $config;
717
718
    /* check for expired entries */
719
    if ($config['captiveportal']['timeout'])
720
        $timeout = $config['captiveportal']['timeout'] * 60;
721
    else
722
        $timeout = 0;
723
724
    if ($config['captiveportal']['idletimeout'])
725
        $idletimeout = $config['captiveportal']['idletimeout'] * 60;
726
    else
727
        $idletimeout = 0;
728
729 336e3c1c Charlie
    if (!$timeout && !$idletimeout && !isset($config['captiveportal']['reauthenticate']) && 
730
		!isset($config['captiveportal']['radiussession_timeout']) && !isset($config['voucher']['enable']))
731 23c4f978 Scott Ullrich
        return;
732
733 dedf51a2 Ermal Lu?i
    $captiveportallck = lock('captiveportal');
734 23c4f978 Scott Ullrich
735
    /* read database */
736
    $cpdb = captiveportal_read_db();
737
738
    $radiusservers = captiveportal_get_radius_servers();
739
740 2d53158f stompro
    /*  To make sure we iterate over ALL accounts on every run the count($cpdb) is moved
741
     *  outside of the loop. Otherwise the loop would evaluate count() on every iteration
742
     *  and since $i would increase and count() would decrement they would meet before we
743
     *  had a chance to iterate over all accounts.
744 f56a73f1 Scott Ullrich
     */
745 8e51cc6a Ermal Lu?i
    $unsetindexes = array();
746 f56a73f1 Scott Ullrich
    $no_users = count($cpdb);
747
    for ($i = 0; $i < $no_users; $i++) {
748 23c4f978 Scott Ullrich
749
        $timedout = false;
750
        $term_cause = 1;
751
752
        /* hard timeout? */
753
        if ($timeout) {
754
            if ((time() - $cpdb[$i][0]) >= $timeout) {
755
                $timedout = true;
756
                $term_cause = 5; // Session-Timeout
757
            }
758
        }
759
760
        /* Session-Terminate-Time */
761
        if (!$timedout && !empty($cpdb[$i][9])) {
762
            if (time() >= $cpdb[$i][9]) {
763
                $timedout = true;
764
                $term_cause = 5; // Session-Timeout
765
            }
766
        }
767
768
        /* check if the radius idle_timeout attribute has been set and if its set change the idletimeout to this value */
769
        $idletimeout = (is_numeric($cpdb[$i][8])) ? $cpdb[$i][8] : $idletimeout;
770
        /* if an idle timeout is specified, get last activity timestamp from ipfw */
771
        if (!$timedout && $idletimeout) {
772 f9f71ad3 Ermal Lu?i
            $lastact = captiveportal_get_last_activity($cpdb[$i][2]);
773 2d53158f stompro
			/*  If the user has logged on but not sent any traffic they will never be logged out.
774
			 *  We "fix" this by setting lastact to the login timestamp. 
775 f56a73f1 Scott Ullrich
			 */
776
			$lastact = $lastact ? $lastact : $cpdb[$i][0];
777 23c4f978 Scott Ullrich
            if ($lastact && ((time() - $lastact) >= $idletimeout)) {
778
                $timedout = true;
779
                $term_cause = 4; // Idle-Timeout
780
                $stop_time = $lastact; // Entry added to comply with WISPr
781
            }
782
        }
783
784 336e3c1c Charlie
	/* if vouchers are configured, activate session timeouts */
785
	if (!$timedout && isset($config['voucher']['enable']) && !empty($cpdb[$i][7])) {
786
		if (time() >= ($cpdb[$i][0] + $cpdb[$i][7])) {
787
			$timedout = true;
788
			$term_cause = 5; // Session-Timeout
789
		}
790
	}
791
792 23c4f978 Scott Ullrich
        /* if radius session_timeout is enabled and the session_timeout is not null, then check if the user should be logged out */
793
        if (!$timedout && isset($config['captiveportal']['radiussession_timeout']) && !empty($cpdb[$i][7])) {
794
            if (time() >= ($cpdb[$i][0] + $cpdb[$i][7])) {
795
                $timedout = true;
796
                $term_cause = 5; // Session-Timeout
797
            }
798
        }
799
800
        if ($timedout) {
801
            captiveportal_disconnect($cpdb[$i], $radiusservers,$term_cause,$stop_time);
802
            captiveportal_logportalauth($cpdb[$i][4], $cpdb[$i][3], $cpdb[$i][2], "TIMEOUT");
803 8e51cc6a Ermal Lu?i
	    $unsetindexes[$i] = $i;
804 23c4f978 Scott Ullrich
        }
805
806
        /* do periodic RADIUS reauthentication? */
807
        if (!$timedout && isset($config['captiveportal']['reauthenticate']) &&
808 40b48c6c Ermal Lu?i
            !empty($radiusservers)) {
809 23c4f978 Scott Ullrich
810
            if (isset($config['captiveportal']['radacct_enable'])) {
811
                if ($config['captiveportal']['reauthenticateacct'] == "stopstart") {
812
                    /* stop and restart accounting */
813
                    RADIUS_ACCOUNTING_STOP($cpdb[$i][1], // ruleno
814
                                           $cpdb[$i][4], // username
815
                                           $cpdb[$i][5], // sessionid
816
                                           $cpdb[$i][0], // start time
817 40b48c6c Ermal Lu?i
                                           $radiusservers,
818 23c4f978 Scott Ullrich
                                           $cpdb[$i][2], // clientip
819
                                           $cpdb[$i][3], // clientmac
820
                                           10); // NAS Request
821 6ce61a8f Ermal
                    exec("/sbin/ipfw table 1 entryzerostats {$cpdb[$i][2]}");
822
                    exec("/sbin/ipfw table 2 entryzerostats {$cpdb[$i][2]}");
823 23c4f978 Scott Ullrich
                    RADIUS_ACCOUNTING_START($cpdb[$i][1], // ruleno
824
                                            $cpdb[$i][4], // username
825
                                            $cpdb[$i][5], // sessionid
826 40b48c6c Ermal Lu?i
                                            $radiusservers,
827 23c4f978 Scott Ullrich
                                            $cpdb[$i][2], // clientip
828
                                            $cpdb[$i][3]); // clientmac
829
                } else if ($config['captiveportal']['reauthenticateacct'] == "interimupdate") {
830
                    RADIUS_ACCOUNTING_STOP($cpdb[$i][1], // ruleno
831
                                           $cpdb[$i][4], // username
832
                                           $cpdb[$i][5], // sessionid
833
                                           $cpdb[$i][0], // start time
834 40b48c6c Ermal Lu?i
                                           $radiusservers,
835 23c4f978 Scott Ullrich
                                           $cpdb[$i][2], // clientip
836
                                           $cpdb[$i][3], // clientmac
837
                                           10, // NAS Request
838
                                           true); // Interim Updates
839
                }
840
            }
841
842
            /* check this user against RADIUS again */
843
            $auth_list = RADIUS_AUTHENTICATION($cpdb[$i][4], // username
844
                                          base64_decode($cpdb[$i][6]), // password
845
                                            $radiusservers,
846
                                          $cpdb[$i][2], // clientip
847
                                          $cpdb[$i][3], // clientmac
848
                                          $cpdb[$i][1]); // ruleno
849
850
            if ($auth_list['auth_val'] == 3) {
851
                captiveportal_disconnect($cpdb[$i], $radiusservers, 17);
852
                captiveportal_logportalauth($cpdb[$i][4], $cpdb[$i][3], $cpdb[$i][2], "RADIUS_DISCONNECT", $auth_list['reply_message']);
853 8e51cc6a Ermal Lu?i
	        $unsetindexes[$i] = $i;
854 23c4f978 Scott Ullrich
            }
855
        }
856
    }
857 8e51cc6a Ermal Lu?i
    /* This is a kludge to overcome some php weirdness */
858
    foreach($unsetindexes as $unsetindex)
859
	unset($cpdb[$unsetindex]);
860 23c4f978 Scott Ullrich
861
    /* write database */
862
    captiveportal_write_db($cpdb);
863
864 dedf51a2 Ermal Lu?i
    unlock($captiveportallck);
865 5b237745 Scott Ullrich
}
866
867 3db19cf1 Scott Ullrich
/* remove a single client according to the DB entry */
868 0bd34ed6 Scott Ullrich
function captiveportal_disconnect($dbent, $radiusservers,$term_cause = 1,$stop_time = null) {
869 36254e4a Scott Ullrich
870 d99f7864 Scott Ullrich
	global $g, $config;
871
872
	$stop_time = (empty($stop_time)) ? time() : $stop_time;
873
874
	/* this client needs to be deleted - remove ipfw rules */
875 40b48c6c Ermal Lu?i
	if (isset($config['captiveportal']['radacct_enable']) && !empty($radiusservers)) {
876 d99f7864 Scott Ullrich
		RADIUS_ACCOUNTING_STOP($dbent[1], // ruleno
877
							   $dbent[4], // username
878
							   $dbent[5], // sessionid
879
							   $dbent[0], // start time
880 40b48c6c Ermal Lu?i
							   $radiusservers,
881 d99f7864 Scott Ullrich
							   $dbent[2], // clientip
882
							   $dbent[3], // clientmac
883
							   $term_cause, // Acct-Terminate-Cause
884
							   false,
885
							   $stop_time);
886
	}
887 2d53158f stompro
	/* Delete client's ip entry from tables 3 and 4. */
888 6ce61a8f Ermal
	mwexec("/sbin/ipfw table 1 delete {$dbent[2]}");
889
	mwexec("/sbin/ipfw table 2 delete {$dbent[2]}");
890 1dbe445a Ermal
891 6ce61a8f Ermal
	/* Release the ruleno so it can be reallocated to new clients. */
892
	captiveportal_free_ipfw_ruleno($dbent[1]);
893 f9f71ad3 Ermal Lu?i
894
	/* 
895
	* These are the pipe numbers we use to control traffic shaping for each logged in user via captive portal
896
	* We could get an error if the pipe doesn't exist but everything should still be fine
897
	*/
898
	if (isset($config['captiveportal']['peruserbw'])) {
899
		mwexec("/sbin/ipfw pipe " . ($dbent[1]+20000) . " delete");
900
		mwexec("/sbin/ipfw pipe " . ($dbent[1]+20001) . " delete");
901
	}
902 7a7abeba Scott Ullrich
903 6ce61a8f Ermal
	/* XXX: Redundant?! Ensure all pf(4) states are killed. */
904 7a7abeba Scott Ullrich
	mwexec("pfctl -k {$dbent[2]}");
905 b1cc2eb2 Ermal Luçi
	mwexec("pfctl -K {$dbent[2]}");
906 7a7abeba Scott Ullrich
907 3db19cf1 Scott Ullrich
}
908 12ee8fe4 Scott Ullrich
909 3db19cf1 Scott Ullrich
/* remove a single client by ipfw rule number */
910 0bd34ed6 Scott Ullrich
function captiveportal_disconnect_client($id,$term_cause = 1) {
911 36254e4a Scott Ullrich
912 d99f7864 Scott Ullrich
	global $g, $config;
913 36254e4a Scott Ullrich
914 dedf51a2 Ermal Lu?i
	$captiveportallck = lock('captiveportal');
915 36254e4a Scott Ullrich
916 d99f7864 Scott Ullrich
	/* read database */
917
	$cpdb = captiveportal_read_db();
918
	$radiusservers = captiveportal_get_radius_servers();
919
920
	/* find entry */
921 889b0934 Ermal Lu?i
	$tmpindex = 0;
922 6ce61a8f Ermal
	$cpdbcount = count($cpdb);
923
	for ($i = 0; $i < $cpdbcount; $i++) {
924 d99f7864 Scott Ullrich
		if ($cpdb[$i][1] == $id) {
925
			captiveportal_disconnect($cpdb[$i], $radiusservers, $term_cause);
926
			captiveportal_logportalauth($cpdb[$i][4], $cpdb[$i][3], $cpdb[$i][2], "DISCONNECT");
927 dd35bb5a Chris Buechler
			unset($cpdb[$i]);
928 d99f7864 Scott Ullrich
			break;
929
		}
930 dd35bb5a Chris Buechler
	}		
931 36254e4a Scott Ullrich
932 d99f7864 Scott Ullrich
	/* write database */
933
	captiveportal_write_db($cpdb);
934 36254e4a Scott Ullrich
935 dedf51a2 Ermal Lu?i
	unlock($captiveportallck);
936 5b237745 Scott Ullrich
}
937
938
/* send RADIUS acct stop for all current clients */
939 dedf51a2 Ermal Lu?i
function captiveportal_radius_stop_all($lock = false) {
940 d99f7864 Scott Ullrich
	global $g, $config;
941
942
	if (!isset($config['captiveportal']['radacct_enable']))
943
		return;
944
945 90455aeb Ermal Lu?i
	if (!$lock)
946 dedf51a2 Ermal Lu?i
		$captiveportallck = lock('captiveportal');
947
948 d99f7864 Scott Ullrich
	$cpdb = captiveportal_read_db();
949
950
	$radiusservers = captiveportal_get_radius_servers();
951 40b48c6c Ermal Lu?i
	if (!empty($radiusservers)) {
952 d99f7864 Scott Ullrich
		for ($i = 0; $i < count($cpdb); $i++) {
953
			RADIUS_ACCOUNTING_STOP($cpdb[$i][1], // ruleno
954
								   $cpdb[$i][4], // username
955
								   $cpdb[$i][5], // sessionid
956
								   $cpdb[$i][0], // start time
957 40b48c6c Ermal Lu?i
								   $radiusservers,
958 d99f7864 Scott Ullrich
								   $cpdb[$i][2], // clientip
959
								   $cpdb[$i][3], // clientmac
960
								   7); // Admin Reboot
961
		}
962
	}
963 90455aeb Ermal Lu?i
	if (!$lock)
964 dedf51a2 Ermal Lu?i
		unlock($captiveportallck);
965 5b237745 Scott Ullrich
}
966
967 d5ae560d Ermal
function captiveportal_passthrumac_configure_entry($macent) {
968
	$rules = "";
969
        $enBwup = isset($macent['bw_up']);
970
        $enBwdown = isset($macent['bw_down']);
971
	$actionup = "allow";
972
	$actiondown = "allow";
973
974
        if ($enBwup && $enBwdown)
975
                $ruleno = captiveportal_get_next_ipfw_ruleno(2000, 49899, true);
976
        else
977
                $ruleno = captiveportal_get_next_ipfw_ruleno(2000, 49899, false);
978
979
	if ($enBwup) {
980
                $bw_up = $ruleno + 20000;
981
                $rules .= "pipe {$bw_up} config bw {$macent['bw_up']}Kbit/s queue 100\n";
982
		$actionup = "pipe {$bw_up}";
983
        }
984
        if ($enBwdown) {
985
		$bw_down = $ruleno + 20001;
986
		$rules .= "pipe {$bw_down} config bw {$macent['bw_down']}Kbit/s queue 100\n";
987
		$actiondown = "pipe {$bw_down}";
988
        }
989 ffcf81bb Chris Buechler
	$rules .= "add {$ruleno} {$actiondown} ip from any to any MAC {$macent['mac']} any\n";
990 d5ae560d Ermal
	$ruleno++;
991 ffcf81bb Chris Buechler
	$rules .= "add {$ruleno} {$actionup} ip from any to any MAC any {$macent['mac']}\n";
992 d5ae560d Ermal
993
	return $rules;
994
}
995
996 dedf51a2 Ermal Lu?i
function captiveportal_passthrumac_configure($lock = false) {
997 5b237745 Scott Ullrich
	global $config, $g;
998 36254e4a Scott Ullrich
999 d5ae560d Ermal
	$rules = "";
1000 36254e4a Scott Ullrich
1001 5b237745 Scott Ullrich
	if (is_array($config['captiveportal']['passthrumac'])) {
1002 1dbe445a Ermal
		$macdb = array();
1003 5b237745 Scott Ullrich
		foreach ($config['captiveportal']['passthrumac'] as $macent) {
1004 d5ae560d Ermal
			$rules .= captiveportal_passthrumac_configure_entry($macent);
1005 1dbe445a Ermal
			$macdb[$macent['mac']]['active']  = true;
1006
1007 5b237745 Scott Ullrich
		}
1008
	}
1009 0bd34ed6 Scott Ullrich
1010 d5ae560d Ermal
	return $rules;
1011 5b237745 Scott Ullrich
}
1012
1013 fac13a5e Ermal
function captiveportal_passthrumac_findbyname($username) {
1014
	global $config;
1015
1016
	if (is_array($config['captiveportal']['passthrumac'])) {
1017
		foreach ($config['captiveportal']['passthrumac'] as $macent) {
1018
			if ($macent['username'] == $username)
1019
				return $macent;
1020
		}
1021
	}
1022
	return NULL;
1023
}
1024
1025 b01792a0 Ermal
/* 
1026
 * table (3=IN)/(4=OUT) hold allowed ip's without bw limits
1027
 * table (5=IN)/(6=OUT) hold allowed ip's with bw limit.
1028
 */
1029
function captiveportal_allowedip_configure_entry($ipent) {
1030
1031
	$rules = "";
1032
	$enBwup = isset($ipent['bw_up']);
1033
	$enBwdown = isset($ipent['bw_down']);
1034
	$bw_up = "";
1035
        $bw_down = "";
1036
        $tablein = array();
1037
        $tableout = array();
1038
1039
	if ($enBwup && $enBwdown)
1040
		$ruleno = captiveportal_get_next_ipfw_ruleno(2000, 49899, true);
1041
	else
1042
		$ruleno = captiveportal_get_next_ipfw_ruleno(2000, 49899, false);
1043
1044
        if ($ipent['dir'] == "from") {
1045
        	if ($enBwup)
1046
                	$tablein[] = 5;
1047
                else
1048
                	$tablein[] = 3;
1049
                if ($enBwdown)
1050
                        $tableout[] = 6;
1051
                else
1052
                        $tableout[] = 4;
1053
        } else if ($ipent['dir'] == "to") {
1054
                if ($enBwup)
1055
                	$tablein[] = 9;
1056
                else
1057
                        $tablein[] = 7;
1058
                if ($enBwdown)
1059
                        $tableout[] = 10;
1060
                else
1061
                        $tableout[] = 8;
1062
        } else if ($ipent['dir'] == "both") {
1063
                if ($enBwup) {
1064
                        $tablein[] = 5;
1065
                        $tablein[] = 9;
1066
                } else {
1067
                        $tablein[] = 3;
1068
                        $tablein[] = 7;
1069
                }
1070
        	if ($enBwdown) {
1071
                        $tableout[] = 6;
1072
                        $tableout[] = 10;
1073
                } else {
1074
                        $tableout[] = 4;
1075
                	$tableout[] = 8;
1076
                }
1077
        }
1078
        if ($enBwup) {
1079
                $bw_up = $ruleno + 20000;
1080
        	$rules .= "pipe {$bw_up} config bw {$ipent['bw_up']}Kbit/s queue 100\n";
1081
        }
1082 d6a0379d Ermal
	$subnet = "";
1083
	if (!empty($ipent['sn']))
1084
		$subnet = "/{$ipent['sn']}";
1085 b01792a0 Ermal
	foreach ($tablein as $table)
1086 d6a0379d Ermal
               $rules .= "table {$table} add {$ipent['ip']}{$subnet} {$bw_up}\n";
1087 b01792a0 Ermal
        if ($enBwdown) {
1088
               $bw_down = $ruleno + 20001;
1089
               $rules .= "pipe {$bw_down} config bw {$ipent['bw_down']}Kbit/s queue 100\n";
1090
        }
1091
        foreach ($tableout as $table)
1092 d6a0379d Ermal
        	$rules .= "table {$table} add {$ipent['ip']}{$subnet} {$bw_down}\n";
1093 b01792a0 Ermal
1094
	return $rules;
1095
}
1096
1097 cb0a2913 Ermal Lu?i
function captiveportal_allowedip_configure() {
1098 5b237745 Scott Ullrich
	global $config, $g;
1099 36254e4a Scott Ullrich
1100 6ce61a8f Ermal
	$rules = "";
1101 5b237745 Scott Ullrich
	if (is_array($config['captiveportal']['allowedip'])) {
1102 cb0a2913 Ermal Lu?i
		foreach ($config['captiveportal']['allowedip'] as $ipent) {
1103 b01792a0 Ermal
			$rules .= captiveportal_allowedip_configure_entry($ipent);
1104 cb0a2913 Ermal Lu?i
		}
1105
	}
1106 36254e4a Scott Ullrich
1107 6ce61a8f Ermal
	return $rules;
1108 5b237745 Scott Ullrich
}
1109
1110 2d53158f stompro
/* get last activity timestamp given client IP address */
1111 f9f71ad3 Ermal Lu?i
function captiveportal_get_last_activity($ip) {
1112 36254e4a Scott Ullrich
1113 d99f7864 Scott Ullrich
	$ipfwoutput = "";
1114 36254e4a Scott Ullrich
1115 6ce61a8f Ermal
	exec("/sbin/ipfw table 1 entrystats {$ip} 2>/dev/null", $ipfwoutput);
1116 f9f71ad3 Ermal Lu?i
	/* Reading only from one of the tables is enough of approximation. */
1117 d99f7864 Scott Ullrich
	if ($ipfwoutput[0]) {
1118
		$ri = explode(" ", $ipfwoutput[0]);
1119 f9f71ad3 Ermal Lu?i
		if ($ri[4])
1120
			return $ri[4];
1121 d99f7864 Scott Ullrich
	}
1122 36254e4a Scott Ullrich
1123 d99f7864 Scott Ullrich
	return 0;
1124 5b237745 Scott Ullrich
}
1125
1126
/* read RADIUS servers into array */
1127
function captiveportal_get_radius_servers() {
1128 0bd34ed6 Scott Ullrich
1129
        global $g;
1130
1131
        if (file_exists("{$g['vardb_path']}/captiveportal_radius.db")) {
1132 2f70eac7 Ermal Lu?i
                $radiusservers = array();
1133 a48acf9a Ermal Lu?i
		$cpradiusdb = file("{$g['vardb_path']}/captiveportal_radius.db", 
1134
			FILE_IGNORE_NEW_LINES | FILE_SKIP_EMPTY_LINES);
1135
		if ($cpradiusdb)
1136 2f70eac7 Ermal Lu?i
		foreach($cpradiusdb as $cpradiusentry) {
1137
                	$line = trim($cpradiusentry);
1138
                        if ($line) {
1139
                        	$radsrv = array();
1140
                                list($radsrv['ipaddr'],$radsrv['port'],$radsrv['acctport'],$radsrv['key']) = explode(",",$line);
1141
                        	$radiusservers[] = $radsrv;
1142 0bd34ed6 Scott Ullrich
                        }
1143 2f70eac7 Ermal Lu?i
		}
1144 0bd34ed6 Scott Ullrich
1145 2f70eac7 Ermal Lu?i
		return $radiusservers;
1146 0bd34ed6 Scott Ullrich
        }
1147
1148
        return false;
1149 5b237745 Scott Ullrich
}
1150
1151 3db19cf1 Scott Ullrich
/* log successful captive portal authentication to syslog */
1152
/* part of this code from php.net */
1153 0bd34ed6 Scott Ullrich
function captiveportal_logportalauth($user,$mac,$ip,$status, $message = null) {
1154 d99f7864 Scott Ullrich
	$message = trim($message);
1155
	// Log it
1156
	if (!$message)
1157 f56a73f1 Scott Ullrich
		$message = "$status: $user, $mac, $ip";
1158 d99f7864 Scott Ullrich
	else
1159 f56a73f1 Scott Ullrich
		$message = "$status: $user, $mac, $ip, $message";
1160
	captiveportal_syslog($message);
1161
	closelog();
1162
}
1163
1164
/* log simple messages to syslog */
1165
function captiveportal_syslog($message) {
1166
	define_syslog_variables();
1167
	$message = trim($message);
1168
	openlog("logportalauth", LOG_PID, LOG_LOCAL4);
1169
	// Log it
1170
	syslog(LOG_INFO, $message);
1171 d99f7864 Scott Ullrich
	closelog();
1172 3db19cf1 Scott Ullrich
}
1173
1174 0bd34ed6 Scott Ullrich
function radius($username,$password,$clientip,$clientmac,$type) {
1175 d44bccc7 Scott Ullrich
    global $g, $config;
1176 d99f7864 Scott Ullrich
1177 d44bccc7 Scott Ullrich
    /* Start locking from the beginning of an authentication session */
1178 dedf51a2 Ermal Lu?i
    $captiveportallck = lock('captiveportal');
1179 0bd34ed6 Scott Ullrich
1180 d44bccc7 Scott Ullrich
    $ruleno = captiveportal_get_next_ipfw_ruleno();
1181
1182 2d53158f stompro
    /* If the pool is empty, return appropriate message and fail authentication */
1183 d44bccc7 Scott Ullrich
    if (is_null($ruleno)) {
1184
        $auth_list = array();
1185
        $auth_list['auth_val'] = 1;
1186
        $auth_list['error'] = "System reached maximum login capacity";
1187 dedf51a2 Ermal Lu?i
        unlock($captiveportallck);
1188 d44bccc7 Scott Ullrich
        return $auth_list;
1189
    }
1190
1191 2f70eac7 Ermal Lu?i
    /*
1192
     * Drop the lock since radius takes some time to finish.
1193
     * The implementation is reentrant so we gain speed with this.
1194
     */
1195
    unlock($captiveportallck);
1196
1197 d44bccc7 Scott Ullrich
    $radiusservers = captiveportal_get_radius_servers();
1198
1199
    $auth_list = RADIUS_AUTHENTICATION($username,
1200
                    $password,
1201
                    $radiusservers,
1202
                    $clientip,
1203
                    $clientmac,
1204
                    $ruleno);
1205
1206 2f70eac7 Ermal Lu?i
    $captiveportallck = lock('captiveportal');
1207
1208 d44bccc7 Scott Ullrich
    if ($auth_list['auth_val'] == 2) {
1209
        captiveportal_logportalauth($username,$clientmac,$clientip,$type);
1210
        $sessionid = portal_allow($clientip,
1211
                    $clientmac,
1212
                    $username,
1213
                    $password,
1214
                    $auth_list,
1215
                    $ruleno);
1216
    }
1217 9befcca7 Ermal Lu?i
1218 dedf51a2 Ermal Lu?i
    unlock($captiveportallck);
1219 d44bccc7 Scott Ullrich
1220
    return $auth_list;
1221 0bd34ed6 Scott Ullrich
1222
}
1223
1224
/* read captive portal DB into array */
1225
function captiveportal_read_db() {
1226
1227
        global $g;
1228
1229
        $cpdb = array();
1230
        $fd = @fopen("{$g['vardb_path']}/captiveportal.db", "r");
1231
        if ($fd) {
1232
                while (!feof($fd)) {
1233
                        $line = trim(fgets($fd));
1234
                        if ($line) {
1235
                                $cpdb[] = explode(",", $line);
1236
                        }
1237
                }
1238
                fclose($fd);
1239
        }
1240
        return $cpdb;
1241
}
1242
1243
/* write captive portal DB */
1244
function captiveportal_write_db($cpdb) {
1245 d44bccc7 Scott Ullrich
                 
1246 0bd34ed6 Scott Ullrich
        global $g;
1247 d44bccc7 Scott Ullrich
                
1248 0bd34ed6 Scott Ullrich
        $fd = @fopen("{$g['vardb_path']}/captiveportal.db", "w");
1249 d44bccc7 Scott Ullrich
        if ($fd) { 
1250 0bd34ed6 Scott Ullrich
                foreach ($cpdb as $cpent) {
1251
                        fwrite($fd, join(",", $cpent) . "\n");
1252 d44bccc7 Scott Ullrich
                }       
1253 0bd34ed6 Scott Ullrich
                fclose($fd);
1254 d44bccc7 Scott Ullrich
        }       
1255 0bd34ed6 Scott Ullrich
}
1256
1257
function captiveportal_write_elements() {
1258 769e254e Ermal
	global $g, $config;
1259 d44bccc7 Scott Ullrich
    
1260 769e254e Ermal
	/* delete any existing elements */
1261
	if (is_dir($g['captiveportal_element_path'])) {
1262
		$dh = opendir($g['captiveportal_element_path']);
1263
		while (($file = readdir($dh)) !== false) {
1264
			if ($file != "." && $file != "..")
1265
				unlink($g['captiveportal_element_path'] . "/" . $file);
1266
		}
1267
		closedir($dh);
1268
	} else
1269
		@mkdir($g['captiveportal_element_path']);
1270
1271 1fadb31d Scott Ullrich
	if (is_array($config['captiveportal']['element'])) {
1272
		conf_mount_rw();
1273
		foreach ($config['captiveportal']['element'] as $data) {
1274
			$fd = @fopen($g['captiveportal_element_path'] . '/' . $data['name'], "wb");
1275
			if (!$fd) {
1276
				printf("Error: cannot open '{$data['name']}' in captiveportal_write_elements().\n");
1277
				return 1;
1278
			}
1279
			$decoded = base64_decode($data['content']);
1280
			fwrite($fd,$decoded);
1281
			fclose($fd);
1282
			unlink_if_exists("{$g['captiveportal_path']}/{$data['name']}");
1283
			unlink_if_exists("{$g['captiveportal_path']}/{$data['name']}");
1284
			mwexec("cd {$g['captiveportal_path']}/ && ln -s {$g['captiveportal_element_path']}/{$data['name']} {$data['name']}");
1285
		}
1286
		conf_mount_ro();
1287
	}
1288 d44bccc7 Scott Ullrich
    
1289 769e254e Ermal
	return 0;
1290 0bd34ed6 Scott Ullrich
}
1291
1292 6ce61a8f Ermal
function captiveportal_init_ipfw_ruleno($rulenos_start = 2000, $rulenos_range_max = 49899) {
1293
	global $g;
1294
1295
	@unlink("{$g['vardb_path']}/captiveportal.rules");
1296
	$rules = array_pad(array(), $rulenos_range_max - $rulenos_start, false);
1297
	file_put_contents("{$g['vardb_path']}/captiveportal.rules", serialize($rules));
1298
}
1299
1300 920cafaf Scott Ullrich
/*
1301
 * This function will calculate the lowest free firewall ruleno
1302 f9f71ad3 Ermal Lu?i
 * within the range specified based on the actual logged on users
1303 920cafaf Scott Ullrich
 *
1304
 */
1305 b01792a0 Ermal
function captiveportal_get_next_ipfw_ruleno($rulenos_start = 2000, $rulenos_range_max = 49899, $usebw = false) {
1306 f9f71ad3 Ermal Lu?i
	global $config, $g;
1307 6ce61a8f Ermal
1308 de752609 Scott Ullrich
	if(!isset($config['captiveportal']['enable']))
1309 01d57b8c Scott Ullrich
		return NULL;
1310 6ce61a8f Ermal
1311 f9f71ad3 Ermal Lu?i
	$ruleno = 0;
1312 6ce61a8f Ermal
	if (file_exists("{$g['vardb_path']}/captiveportal.rules")) {
1313
		$rules = unserialize(file_get_contents("{$g['vardb_path']}/captiveportal.rules"));
1314
		for ($ridx = 2; $ridx < ($rulenos_range_max - $rulenos_start); $ridx++) {
1315
			if ($rules[$ridx]) {
1316
				/* 
1317
	 			 * This allows our traffic shaping pipes to be the in pipe the same as ruleno 
1318
	 			 * and the out pipe ruleno + 1. This removes limitation that where present in 
1319
	 			 * previous version of the peruserbw.
1320
	 			 */
1321
				if (isset($config['captiveportal']['peruserbw']))
1322
					$ridx++;
1323
				continue;
1324
			}
1325
			$ruleno = $ridx;
1326
			$rules[$ridx] = "used";
1327 b01792a0 Ermal
			if (isset($config['captiveportal']['peruserbw']) || $usebw == true)
1328 6ce61a8f Ermal
				$rules[++$ridx] = "used";
1329
			break;
1330
		}
1331
	} else {
1332
		$rules = array_pad(array(), $rulenos_range_max - $rulenos_start, false);
1333
		$rules[2] = "used";
1334
		$ruleno = 2;
1335
	}
1336
	file_put_contents("{$g['vardb_path']}/captiveportal.rules", serialize($rules));
1337
	return $ruleno;
1338
}
1339
1340 b01792a0 Ermal
function captiveportal_free_ipfw_ruleno($ruleno, $usedbw = false) {
1341 6ce61a8f Ermal
	global $config, $g;
1342
1343
	if(!isset($config['captiveportal']['enable']))
1344
		return NULL;
1345
1346
	if (file_exists("{$g['vardb_path']}/captiveportal.rules")) {
1347
		$rules = unserialize(file_get_contents("{$g['vardb_path']}/captiveportal.rules"));
1348
		$rules[$ruleno] = false;
1349 b01792a0 Ermal
		if (isset($config['captiveportal']['peruserbw']) || $usedbw == true)
1350 6ce61a8f Ermal
			$rules[++$ruleno] = false;
1351
		file_put_contents("{$g['vardb_path']}/captiveportal.rules", serialize($rules));
1352 f9f71ad3 Ermal Lu?i
	}
1353 6ce61a8f Ermal
}
1354
1355 d5ae560d Ermal
function captiveportal_get_ipfw_passthru_ruleno($value) {
1356 6ce61a8f Ermal
	global $config, $g;
1357
1358
	if(!isset($config['captiveportal']['enable']))
1359
                return NULL;
1360
1361
        if (file_exists("{$g['vardb_path']}/captiveportal.rules")) {
1362
                $rules = unserialize(file_get_contents("{$g['vardb_path']}/captiveportal.rules"));
1363 d5ae560d Ermal
		$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`);
1364 6ce61a8f Ermal
		if ($rules[$ruleno])
1365
			return $ruleno;
1366
        }
1367
1368 f9f71ad3 Ermal Lu?i
	return NULL;
1369 920cafaf Scott Ullrich
}
1370
1371 360d815d Scott Ullrich
/**
1372
 * This function will calculate the traffic produced by a client
1373
 * based on its firewall rule
1374
 *
1375
 * Point of view: NAS
1376
 *
1377
 * Input means: from the client
1378
 * Output means: to the client
1379
 *
1380
 */
1381
1382 f9f71ad3 Ermal Lu?i
function getVolume($ip) {
1383 360d815d Scott Ullrich
1384
    $volume = array();
1385
1386
    // Initialize vars properly, since we don't want NULL vars
1387
    $volume['input_pkts'] = $volume['input_bytes'] = $volume['output_pkts'] = $volume['output_bytes'] = 0 ;
1388
1389
    // Ingress
1390 f9f71ad3 Ermal Lu?i
    $ipfwin = "";
1391
    $ipfwout = "";
1392
    $matchesin = "";
1393
    $matchesout = "";
1394 6ce61a8f Ermal
    exec("/sbin/ipfw table 1 entrystats {$ip}", $ipfwin);
1395 f9f71ad3 Ermal Lu?i
    if ($ipfwin[0]) {
1396 523855b0 Scott Ullrich
		$ipfwin = split(" ", $ipfwin[0]);
1397
		$volume['input_pkts'] = $ipfwin[2];
1398
		$volume['input_bytes'] = $ipfwin[3];
1399 f9f71ad3 Ermal Lu?i
    }
1400
1401 6ce61a8f Ermal
    exec("/sbin/ipfw table 2 entrystats {$ip}", $ipfwout);
1402 f9f71ad3 Ermal Lu?i
    if ($ipfwout[0]) {
1403
        $ipfwout = split(" ", $ipfwout[0]);
1404
        $volume['output_pkts'] = $ipfwout[2];
1405
        $volume['output_bytes'] = $ipfwout[3];
1406
    }
1407 360d815d Scott Ullrich
1408
    return $volume;
1409
}
1410
1411 856e58a6 Scott Ullrich
/**
1412
 * Get the NAS-Identifier
1413
 *
1414
 * We will use our local hostname to make up the nas_id
1415
 */
1416
function getNasID()
1417
{
1418 84e5047d Scott Ullrich
    $nasId = "";
1419 856e58a6 Scott Ullrich
    exec("/bin/hostname", $nasId);
1420
    if(!$nasId[0])
1421 36d0358b Scott Ullrich
        $nasId[0] = "{$g['product_name']}";
1422 856e58a6 Scott Ullrich
    return $nasId[0];
1423
}
1424
1425
/**
1426
 * Get the NAS-IP-Address based on the current wan address
1427
 *
1428
 * Use functions in interfaces.inc to find this out
1429
 *
1430
 */
1431
1432
function getNasIP()
1433
{
1434 64c0462b Ermal
	global $config;
1435
1436 36ff7f81 Ermal
	if (empty($config['captiveportal']['radiussrcip_attribute']))
1437
    		$nasIp = get_interface_ip();
1438
	else {
1439 4a756e9b Ermal
		if (is_ipaddr($config['captiveportal']['radiussrcip_attribute']))
1440
                        $nasIp = $config['captiveportal']['radiussrcip_attribute'];
1441
                else
1442
                        $nasIp = get_interface_ip($config['captiveportal']['radiussrcip_attribute']);
1443 36ff7f81 Ermal
	}
1444 64c0462b Ermal
		
1445
    	if(!is_ipaddr($nasIp))
1446
        	$nasIp = "0.0.0.0";
1447
1448
	return $nasIp;
1449 856e58a6 Scott Ullrich
}
1450
1451 f8b11310 Ermal Lu?i
function portal_ip_from_client_ip($cliip) {
1452
	global $config;
1453
1454
	$interfaces = explode(",", $config['captiveportal']['interface']);
1455
	foreach ($interfaces as $cpif) {
1456
		$ip = get_interface_ip($cpif);
1457
		$sn = get_interface_subnet($cpif);
1458
		if (ip_in_subnet($cliip, "{$ip}/{$sn}"))
1459
			return $ip;
1460
	}
1461
1462 cc125e13 Chris Buechler
	// doesn't match up to any particular interface
1463
	// so let's set the portal IP to what PHP says 
1464
	// the server IP issuing the request is. 
1465
	// allows same behavior as 1.2.x where IP isn't 
1466
	// in the subnet of any CP interface (static routes, etc.)
1467
	// rather than forcing to DNS hostname resolution
1468
	$ip = $_SERVER['SERVER_ADDR'];
1469
	if (is_ipaddr($ip))
1470
		return $ip;
1471
1472 f8b11310 Ermal Lu?i
	return false;
1473
}
1474
1475 cfa62e06 Ermal
?>