Project

General

Profile

« Previous | Next » 

Revision d31bc32a

Added by Ermal LUÇI over 14 years ago

Make the CP locking more granular and make use correctly of exclusive/shared locks where appripriate. This speeds up CP login process.

View differences:

etc/inc/captiveportal.inc
206 206
function captiveportal_configure() {
207 207
	global $config, $g;
208 208

  
209
	$captiveportallck = lock('captiveportal');
209
	$captiveportallck = lock('captiveportal', LOCK_EX);
210 210
	
211 211
	if (isset($config['captiveportal']['enable'])) {
212 212

  
......
233 233
		captiveportal_init_rules(true);
234 234

  
235 235
		/* stop accounting on all clients */
236
		captiveportal_radius_stop_all(true);
236
		captiveportal_radius_stop_all();
237 237

  
238 238
		/* initialize minicron interval value */
239 239
		$croninterval = $config['captiveportal']['croninterval'] ? $config['captiveportal']['croninterval'] : 60;
......
415 415
			"/etc/rc.prunecaptiveportal");
416 416

  
417 417
		/* generate radius server database */
418
		if ($config['captiveportal']['radiusip'] && (!isset($config['captiveportal']['auth_method']) ||
419
				($config['captiveportal']['auth_method'] == "radius"))) {
420
			$radiusip = $config['captiveportal']['radiusip'];
421
			$radiusip2 = ($config['captiveportal']['radiusip2']) ? $config['captiveportal']['radiusip2'] : null;
422

  
423
			if ($config['captiveportal']['radiusport'])
424
				$radiusport = $config['captiveportal']['radiusport'];
425
			else
426
				$radiusport = 1812;
427

  
428
			if ($config['captiveportal']['radiusacctport'])
429
				$radiusacctport = $config['captiveportal']['radiusacctport'];
430
			else
431
				$radiusacctport = 1813;
432

  
433
			if ($config['captiveportal']['radiusport2'])
434
				$radiusport2 = $config['captiveportal']['radiusport2'];
435
			else
436
				$radiusport2 = 1812;
437

  
438
			$radiuskey = $config['captiveportal']['radiuskey'];
439
			$radiuskey2 = ($config['captiveportal']['radiuskey2']) ? $config['captiveportal']['radiuskey2'] : null;
440

  
441
			$fd = @fopen("{$g['vardb_path']}/captiveportal_radius.db", "w");
442
			if (!$fd) {
443
				printf("Error: cannot open radius DB file in captiveportal_configure().\n");
444
				return 1;
445
			} else if (isset($radiusip2, $radiuskey2)) {
446
				fwrite($fd,$radiusip . "," . $radiusport . "," . $radiusacctport . "," . $radiuskey . "\n"
447
					 . $radiusip2 . "," . $radiusport2 . "," . $radiusacctport . "," . $radiuskey2);
448
			} else {
449
				fwrite($fd,$radiusip . "," . $radiusport . "," . $radiusacctport . "," . $radiuskey);
450
			}
451
			fclose($fd);
452
		}
418
		captiveportal_init_radius_servers();
453 419

  
454 420
		if ($g['booting'])
455 421
			echo "done\n";
......
458 424
		killbypid("{$g['varrun_path']}/lighty-CaptivePortal.pid");
459 425
		killbypid("{$g['varrun_path']}/minicron.pid");
460 426

  
461
		captiveportal_radius_stop_all(true);
427
		captiveportal_radius_stop_all();
462 428

  
463 429
		mwexec("/sbin/sysctl net.link.ether.ipfw=0");
464 430

  
......
732 698
	!isset($config['captiveportal']['radiussession_timeout']) && !isset($config['voucher']['enable']))
733 699
        return;
734 700

  
735
    $captiveportallck = lock('captiveportal', LOCK_EX);
736

  
737 701
    /* read database */
738 702
    $cpdb = captiveportal_read_db();
739 703

  
......
862 826

  
863 827
    /* write database */
864 828
    captiveportal_write_db($cpdb);
865

  
866
    unlock($captiveportallck);
867 829
}
868 830

  
869 831
/* remove a single client according to the DB entry */
870 832
function captiveportal_disconnect($dbent, $radiusservers,$term_cause = 1,$stop_time = null) {
871

  
872 833
	global $g, $config;
873 834

  
874 835
	$stop_time = (empty($stop_time)) ? time() : $stop_time;
......
876 837
	/* this client needs to be deleted - remove ipfw rules */
877 838
	if (isset($config['captiveportal']['radacct_enable']) && !empty($radiusservers)) {
878 839
		RADIUS_ACCOUNTING_STOP($dbent[1], // ruleno
879
							   $dbent[4], // username
880
							   $dbent[5], // sessionid
881
							   $dbent[0], // start time
882
							   $radiusservers,
883
							   $dbent[2], // clientip
884
							   $dbent[3], // clientmac
885
							   $term_cause, // Acct-Terminate-Cause
886
							   false,
887
							   $stop_time);
840
				   $dbent[4], // username
841
				   $dbent[5], // sessionid
842
				   $dbent[0], // start time
843
				   $radiusservers,
844
				   $dbent[2], // clientip
845
				   $dbent[3], // clientmac
846
				   $term_cause, // Acct-Terminate-Cause
847
				   false,
848
				   $stop_time);
888 849
	}
889 850
	/* Delete client's ip entry from tables 3 and 4. */
890 851
	mwexec("/sbin/ipfw table 1 delete {$dbent[2]}");
......
910 871

  
911 872
/* remove a single client by ipfw rule number */
912 873
function captiveportal_disconnect_client($id,$term_cause = 1) {
913

  
914 874
	global $g, $config;
915 875

  
916
	$captiveportallck = lock('captiveportal', LOCK_EX);
917

  
918 876
	/* read database */
919 877
	$cpdb = captiveportal_read_db();
920 878
	$radiusservers = captiveportal_get_radius_servers();
921 879

  
922 880
	/* find entry */
923
	$tmpindex = 0;
924
	$cpdbcount = count($cpdb);
925
	for ($i = 0; $i < $cpdbcount; $i++) {
926
		if ($cpdb[$i][1] == $id) {
927
			captiveportal_disconnect($cpdb[$i], $radiusservers, $term_cause);
928
			captiveportal_logportalauth($cpdb[$i][4], $cpdb[$i][3], $cpdb[$i][2], "DISCONNECT");
881
	foreach ($cpdb as $i => $cpentry) {
882
		if ($cpentry[1] == $id) {
883
			captiveportal_disconnect($cpentry, $radiusservers, $term_cause);
884
			captiveportal_logportalauth($cpentry[4], $cpentry[3], $cpentry[2], "DISCONNECT");
929 885
			unset($cpdb[$i]);
930 886
			break;
931 887
		}
......
933 889

  
934 890
	/* write database */
935 891
	captiveportal_write_db($cpdb);
936

  
937
	unlock($captiveportallck);
938 892
}
939 893

  
940 894
/* send RADIUS acct stop for all current clients */
941
function captiveportal_radius_stop_all($lock = false) {
942
	global $g, $config;
895
function captiveportal_radius_stop_all() {
896
	global $config;
943 897

  
944 898
	if (!isset($config['captiveportal']['radacct_enable']))
945 899
		return;
946 900

  
947
	if (!$lock)
948
		$captiveportallck = lock('captiveportal');
949

  
950
	$cpdb = captiveportal_read_db();
951

  
952 901
	$radiusservers = captiveportal_get_radius_servers();
953 902
	if (!empty($radiusservers)) {
954
		for ($i = 0; $i < count($cpdb); $i++) {
955
			RADIUS_ACCOUNTING_STOP($cpdb[$i][1], // ruleno
956
								   $cpdb[$i][4], // username
957
								   $cpdb[$i][5], // sessionid
958
								   $cpdb[$i][0], // start time
959
								   $radiusservers,
960
								   $cpdb[$i][2], // clientip
961
								   $cpdb[$i][3], // clientmac
962
								   7); // Admin Reboot
903
		$cpdb = captiveportal_read_db();
904
		foreach ($cpdb as $cpentry) {
905
			RADIUS_ACCOUNTING_STOP($cpentry[1], // ruleno
906
					   $cpentry[4], // username
907
					   $cpentry[5], // sessionid
908
					   $cpentry[0], // start time
909
					   $radiusservers,
910
					   $cpentry[2], // clientip
911
					   $cpentry[3], // clientmac
912
					   7); // Admin Reboot
963 913
		}
964 914
	}
965
	if (!$lock)
966
		unlock($captiveportallck);
967 915
}
968 916

  
969 917
function captiveportal_passthrumac_configure_entry($macent) {
......
1125 1073
	return 0;
1126 1074
}
1127 1075

  
1076
function captiveportal_init_radius_servers() {
1077
	global $config, $g;
1078

  
1079
	/* generate radius server database */
1080
	if ($config['captiveportal']['radiusip'] && (!isset($config['captiveportal']['auth_method']) ||
1081
	    ($config['captiveportal']['auth_method'] == "radius"))) {
1082
		$radiusip = $config['captiveportal']['radiusip'];
1083
		$radiusip2 = ($config['captiveportal']['radiusip2']) ? $config['captiveportal']['radiusip2'] : null;
1084

  
1085
		if ($config['captiveportal']['radiusport'])
1086
			$radiusport = $config['captiveportal']['radiusport'];
1087
		else
1088
			$radiusport = 1812;
1089
		if ($config['captiveportal']['radiusacctport'])
1090
			$radiusacctport = $config['captiveportal']['radiusacctport'];
1091
		else
1092
			$radiusacctport = 1813;
1093
		if ($config['captiveportal']['radiusport2'])
1094
			$radiusport2 = $config['captiveportal']['radiusport2'];
1095
		else
1096
			$radiusport2 = 1812;
1097
		$radiuskey = $config['captiveportal']['radiuskey'];
1098
		$radiuskey2 = ($config['captiveportal']['radiuskey2']) ? $config['captiveportal']['radiuskey2'] : null;
1099

  
1100
		$cprdsrvlck = lock('captiveportalradius', LOCK_EX);
1101
		$fd = @fopen("{$g['vardb_path']}/captiveportal_radius.db", "w");
1102
		if (!$fd) {
1103
			captiveportal_syslog("Error: cannot open radius DB file in captiveportal_configure().\n");
1104
			unlock($cprdsrvlck);
1105
			return 1;
1106
		} else if (isset($radiusip2, $radiuskey2))
1107
			fwrite($fd,$radiusip . "," . $radiusport . "," . $radiusacctport . "," . $radiuskey . "\n"
1108
			. $radiusip2 . "," . $radiusport2 . "," . $radiusacctport . "," . $radiuskey2);
1109
		else
1110
			fwrite($fd,$radiusip . "," . $radiusport . "," . $radiusacctport . "," . $radiuskey);
1111
		fclose($fd);
1112
		unlock($cprdsrvlck);
1113
	}
1114
}
1115

  
1128 1116
/* read RADIUS servers into array */
1129 1117
function captiveportal_get_radius_servers() {
1130

  
1131 1118
        global $g;
1132 1119

  
1120
	$cprdsrvlck = lock('captiveportalradius');
1133 1121
        if (file_exists("{$g['vardb_path']}/captiveportal_radius.db")) {
1134 1122
                $radiusservers = array();
1135 1123
		$cpradiusdb = file("{$g['vardb_path']}/captiveportal_radius.db", 
......
1144 1132
                        }
1145 1133
		}
1146 1134

  
1135
		unlock('captiveportalradius');
1147 1136
		return $radiusservers;
1148 1137
        }
1149 1138

  
1139
	unlock('captiveportalradius');
1150 1140
        return false;
1151 1141
}
1152 1142

  
1153 1143
/* log successful captive portal authentication to syslog */
1154 1144
/* part of this code from php.net */
1155 1145
function captiveportal_logportalauth($user,$mac,$ip,$status, $message = null) {
1156
	$message = trim($message);
1157 1146
	// Log it
1158 1147
	if (!$message)
1159 1148
		$message = "$status: $user, $mac, $ip";
1160
	else
1149
	else {
1150
		$message = trim($message);
1161 1151
		$message = "$status: $user, $mac, $ip, $message";
1152
	}
1162 1153
	captiveportal_syslog($message);
1163
	closelog();
1164 1154
}
1165 1155

  
1166 1156
/* log simple messages to syslog */
......
1176 1166
function radius($username,$password,$clientip,$clientmac,$type) {
1177 1167
    global $g, $config;
1178 1168

  
1179
    /* Start locking from the beginning of an authentication session */
1180
    $captiveportallck = lock('captiveportal');
1181

  
1182 1169
    $ruleno = captiveportal_get_next_ipfw_ruleno();
1183 1170

  
1184 1171
    /* If the pool is empty, return appropriate message and fail authentication */
......
1186 1173
        $auth_list = array();
1187 1174
        $auth_list['auth_val'] = 1;
1188 1175
        $auth_list['error'] = "System reached maximum login capacity";
1189
        unlock($captiveportallck);
1190 1176
        return $auth_list;
1191 1177
    }
1192 1178

  
1193
    /*
1194
     * Drop the lock since radius takes some time to finish.
1195
     * The implementation is reentrant so we gain speed with this.
1196
     */
1197
    unlock($captiveportallck);
1198

  
1199 1179
    $radiusservers = captiveportal_get_radius_servers();
1200 1180

  
1201 1181
    $auth_list = RADIUS_AUTHENTICATION($username,
......
1205 1185
                    $clientmac,
1206 1186
                    $ruleno);
1207 1187

  
1208
    $captiveportallck = lock('captiveportal');
1209

  
1210 1188
    if ($auth_list['auth_val'] == 2) {
1211 1189
        captiveportal_logportalauth($username,$clientmac,$clientip,$type);
1212 1190
        $sessionid = portal_allow($clientip,
......
1217 1195
                    $ruleno);
1218 1196
    }
1219 1197

  
1220
    unlock($captiveportallck);
1221

  
1222 1198
    return $auth_list;
1223

  
1224 1199
}
1225 1200

  
1226 1201
/* read captive portal DB into array */
1227 1202
function captiveportal_read_db() {
1228

  
1229 1203
        global $g;
1230 1204

  
1231 1205
        $cpdb = array();
1206

  
1207
	$cpdblck = lock('captiveportaldb');
1232 1208
        $fd = @fopen("{$g['vardb_path']}/captiveportal.db", "r");
1233 1209
        if ($fd) {
1234 1210
                while (!feof($fd)) {
......
1239 1215
                }
1240 1216
                fclose($fd);
1241 1217
        }
1218
	unlock($cpdblck);
1242 1219
        return $cpdb;
1243 1220
}
1244 1221

  
1245 1222
/* write captive portal DB */
1246 1223
function captiveportal_write_db($cpdb) {
1247
                 
1248 1224
        global $g;
1249
                
1225

  
1226
	$cpdblck = lock('captiveportaldb', LOCK_EX);
1250 1227
        $fd = @fopen("{$g['vardb_path']}/captiveportal.db", "w");
1251
        if ($fd) { 
1228
        if ($fd) {
1252 1229
                foreach ($cpdb as $cpent) {
1253 1230
                        fwrite($fd, join(",", $cpent) . "\n");
1254
                }       
1231
                }
1255 1232
                fclose($fd);
1256
        }       
1233
        }
1234
	unlock($cpdblck);
1257 1235
}
1258 1236

  
1259 1237
function captiveportal_write_elements() {
......
1310 1288
	if(!isset($config['captiveportal']['enable']))
1311 1289
		return NULL;
1312 1290

  
1291
	$cpruleslck = lock('captiveportalrules', LOCK_EX);
1313 1292
	$ruleno = 0;
1314 1293
	if (file_exists("{$g['vardb_path']}/captiveportal.rules")) {
1315 1294
		$rules = unserialize(file_get_contents("{$g['vardb_path']}/captiveportal.rules"));
......
1336 1315
		$ruleno = 2;
1337 1316
	}
1338 1317
	file_put_contents("{$g['vardb_path']}/captiveportal.rules", serialize($rules));
1318
	unlock($cpruleslck);
1339 1319
	return $ruleno;
1340 1320
}
1341 1321

  
......
1345 1325
	if(!isset($config['captiveportal']['enable']))
1346 1326
		return NULL;
1347 1327

  
1328
	$cpruleslck = lock('captiveportalrules', LOCK_EX);
1348 1329
	if (file_exists("{$g['vardb_path']}/captiveportal.rules")) {
1349 1330
		$rules = unserialize(file_get_contents("{$g['vardb_path']}/captiveportal.rules"));
1350 1331
		$rules[$ruleno] = false;
......
1352 1333
			$rules[++$ruleno] = false;
1353 1334
		file_put_contents("{$g['vardb_path']}/captiveportal.rules", serialize($rules));
1354 1335
	}
1336
	unlock($cpruleslck);
1355 1337
}
1356 1338

  
1357 1339
function captiveportal_get_ipfw_passthru_ruleno($value) {
......
1360 1342
	if(!isset($config['captiveportal']['enable']))
1361 1343
                return NULL;
1362 1344

  
1345
	$cpruleslck = lock('captiveportalrules', LOCK_EX);
1363 1346
        if (file_exists("{$g['vardb_path']}/captiveportal.rules")) {
1364 1347
                $rules = unserialize(file_get_contents("{$g['vardb_path']}/captiveportal.rules"));
1365 1348
		$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`);
1366
		if ($rules[$ruleno])
1349
		if ($rules[$ruleno]) {
1350
			unlock($cpruleslck);
1367 1351
			return $ruleno;
1352
		}
1368 1353
        }
1369 1354

  
1355
	unlock($cpruleslck);
1370 1356
	return NULL;
1371 1357
}
1372 1358

  
etc/inc/system.inc
1477 1477
	return file_get_contents("{$g['varlog_path']}/dmesg.boot");
1478 1478
}
1479 1479

  
1480
?>
1480
?>
usr/local/captiveportal/index.php
268 268

  
269 269
	global $redirurl, $g, $config, $type, $passthrumac, $_POST;
270 270

  
271
	/* See if a ruleno is passed, if not start locking the sessions because this means there isn't one atm */
272
	$captiveshouldunlock = false;
273
	if ($ruleno == null) {
274
		$cplock = lock('captiveportal');
275
		$captiveshouldunlock = true;
271
	/* See if a ruleno is passed, if not start sessions because this means there isn't one atm */
272
	if ($ruleno == null)
276 273
		$ruleno = captiveportal_get_next_ipfw_ruleno();
277
	}
278 274

  
279 275
	/* if the pool is empty, return appropriate message and exit */
280 276
	if (is_null($ruleno)) {
281 277
		portal_reply_page($redirurl, "error", "System reached maximum login capacity");
282 278
		log_error("WARNING!  Captive portal has reached maximum login capacity");
283
		if ($captiveshouldunlock == true)
284
		unlock($cplock);
285 279
		exit;
286 280
	}
287 281

  
......
367 361
		}
368 362
	}
369 363

  
370
	if ($attributes['voucher'] && $remaining_time <= 0) {
371
		unlock($cplock);
364
	if ($attributes['voucher'] && $remaining_time <= 0)
372 365
		return 0;       // voucher already used and no time left
373
	}
374 366

  
375 367
	if (!isset($sessionid)) {
376

  
377 368
		/* generate unique session ID */
378 369
		$tod = gettimeofday();
379 370
		$sessionid = substr(md5(mt_rand() . $tod['sec'] . $tod['usec'] . $clientip . $clientmac), 0, 16);
......
405 396
			mwexec("/sbin/ipfw -q {$g['tmp_path']}/macentry.rules.tmp");
406 397
			$writecfg = true;
407 398
		} else {
408

  
409 399
			if ($peruserbw && !empty($bw_up) && is_numeric($bw_up)) {
410 400
				$bw_up_pipeno = $ruleno + 20000;
411 401
				//$bw_up /= 1000; // Scale to Kbit/s
......
448 438
			if (isset($config['captiveportal']['radacct_enable']) && !empty($radiusservers)) {
449 439
				$acct_val = RADIUS_ACCOUNTING_START($ruleno,
450 440
                                		$username, $sessionid, $radiusservers, $clientip, $clientmac);
451

  
452 441
				if ($acct_val == 1)
453 442
					captiveportal_logportalauth($username,$clientmac,$clientip,$type,"RADIUS ACCOUNTING FAILED");
454 443
			}
......
458 447
		}
459 448
	}
460 449

  
461
	if ($captiveshouldunlock == true)
462
		unlock($cplock);
463

  
464 450
	if ($writecfg == true)
465 451
		write_config();
466 452

  
......
502 488

  
503 489

  
504 490
/* remove a single client by session ID
505
   by Dinesh Nair
491
 *  by Dinesh Nair
506 492
 */
507 493
function disconnect_client($sessionid, $logoutReason = "LOGOUT", $term_cause = 1) {
508

  
509 494
    global $g, $config;
510 495

  
511
    $cplock = lock('captiveportal');
512 496
    /* read database */
513 497
    $cpdb = captiveportal_read_db();
514 498

  
......
527 511

  
528 512
    /* write database */
529 513
    captiveportal_write_db($cpdb);
530

  
531
    unlock($cplock);
532 514
}
533 515

  
534 516
/*
......
555 537

  
556 538
	$updatetimeouts = isset($config['captiveportal']['freelogins_updatetimeouts']);
557 539

  
558
	$cplock = lock('captiveportal');
559

  
560 540
	/*
561 541
	 * Read database of used MACs.  Lines are a comma-separated list
562 542
	 * of the time, MAC, then the count of pass-through credits remaining.
......
578 558
						captiveportal_write_usedmacs_db($usedmacs);
579 559
					}
580 560

  
581
					unlock($cplock);
582 561
					return false;
583 562
				} else {
584 563
					$usedmac[2] -= 1;
......
600 579
	}
601 580

  
602 581
	captiveportal_write_usedmacs_db($usedmacs);
603
	unlock($cplock);
604 582
	return true;
605 583
}
606 584

  
607 585
function captiveportal_read_usedmacs_db() {
608 586
	global $g;
609 587

  
588
	$cpumaclck = lock('captiveusedmacs');
610 589
	if (file_exists("{$g['vardb_path']}/captiveportal_usedmacs.db")) {
611 590
		$usedmacs = file("{$g['vardb_path']}/captiveportal_usedmacs.db", FILE_IGNORE_NEW_LINES | FILE_SKIP_EMPTY_LINES);
612 591
		if (!usedmacs)
......
614 593
	} else
615 594
		$usedmacs = array();
616 595

  
596
	unlock($cpumaclck);
617 597
	return $usedmacs;
618 598
}
619 599

  
620 600
function captiveportal_write_usedmacs_db($usedmacs) {
621 601
	global $g;
622 602

  
623
	file_put_contents("{$g['vardb_path']}/captiveportal_usedmacs.db", implode("\n", $usedmacs));
603
	$cpumaclck = lock('captiveusedmacs', LOCK_EX);
604
	@file_put_contents("{$g['vardb_path']}/captiveportal_usedmacs.db", implode("\n", $usedmacs));
605
	unlock($cpumaclck);
624 606
}
625 607

  
626 608
?>

Also available in: Unified diff