Project

General

Profile

Download (8.54 KB) Statistics
| Branch: | Tag: | Revision:
1
#!/usr/local/bin/php-cgi -f
2
<?php
3
/*
4
 * rc.carpmaster
5
 *
6
 * part of pfSense (https://www.pfsense.org)
7
 * Copyright (c) 2004-2013 BSD Perimeter
8
 * Copyright (c) 2013-2016 Electric Sheep Fencing
9
 * Copyright (c) 2014-2022 Rubicon Communications, LLC (Netgate)
10
 * All rights reserved.
11
 *
12
 * Licensed under the Apache License, Version 2.0 (the "License");
13
 * you may not use this file except in compliance with the License.
14
 * You may obtain a copy of the License at
15
 *
16
 * http://www.apache.org/licenses/LICENSE-2.0
17
 *
18
 * Unless required by applicable law or agreed to in writing, software
19
 * distributed under the License is distributed on an "AS IS" BASIS,
20
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
21
 * See the License for the specific language governing permissions and
22
 * limitations under the License.
23
 */
24

    
25
require_once("functions.inc");
26
require_once("config.inc");
27
require_once("notices.inc");
28
require_once("openvpn.inc");
29
require_once("ipsec.inc");
30
require_once("interfaces.inc");
31
require_once("captiveportal.inc");
32

    
33
if (isset($_GET['interface'])) {
34
	$argument = $_GET['interface'];
35
} else {
36
	$argument = str_replace("\n", "", $argv[1]);
37
}
38
$argument = ltrim($argument, '$');
39
if (!strstr($argument, "@")) {
40
	log_error("CARP master event triggered from wrong source {$argument}");
41
	exit;
42
}
43

    
44
list($vhid, $iface) = explode("@", $argument);
45

    
46
$friendly = convert_real_interface_to_friendly_interface_name($iface);
47
$friendly_descr = convert_friendly_interface_to_friendly_descr($friendly);
48
$vips = link_interface_to_vips($friendly, '', $vhid);
49
if (!is_array($vips)) {
50
	log_error("CARP master event triggered from wrong source {$argument} - no associated VIPs");
51
	exit;
52
}
53
foreach ($vips as $vip) {
54
	$notificationmsg = sprintf('HA cluster member "(%1$s@%2$s): (%3$s)" has resumed CARP state "MASTER" for vhid %4$s',
55
	    $vip['subnet'], $iface, $friendly_descr, $vhid);
56

    
57
	notify_all_remote($notificationmsg);
58
	log_error($notificationmsg);
59
}
60
restart_ppp_interfaces_using_interfaces($vips);
61

    
62
/* Start OpenVPN clients running on this VIP, since they should be in the stopped state while the VIP is CARP Backup. */
63
global $config;
64
$a_groups = return_gateway_groups_array(true);
65
if (is_array($config['openvpn']) && is_array($config['openvpn']['openvpn-client'])) {
66
	foreach ($config['openvpn']['openvpn-client'] as $settings) {
67
		if (substr($settings['interface'], 0, 4) == '_vip') {
68
			$openvpn_vip = $settings['interface'];
69
		} else if (is_array($a_groups[$settings['interface']])) {
70
			// interface is a gateway group, check CARP VIP
71
			if (substr($a_groups[$settings['interface']][0]['vip'], 0, 4) == '_vip') {
72
				$openvpn_vip = $a_groups[$settings['interface']][0]['vip'];
73
			}
74
		} else {
75
			// this OpenVPN instance not on a CARP IP
76
			continue;
77
		}
78
		foreach ($vips as $vip) {
79
			if ($openvpn_vip == "_vip{$vip['uniqid']}") {
80
				log_error("Starting OpenVPN client instance on {$friendly_descr} because of transition to CARP master.");
81
				openvpn_restart('client', $settings);
82
			}
83
		}
84
	}
85
}
86
if (is_array($config['openvpn']) && is_array($config['openvpn']['openvpn-server'])) {
87
	foreach ($config['openvpn']['openvpn-server'] as $settings) {
88
		if (substr($settings['interface'], 0, 4) == '_vip') {
89
			$openvpn_vip = $settings['interface'];
90
		} else if (is_array($a_groups[$settings['interface']])) {
91
			// interface is a gateway group, check CARP VIP
92
			if (substr($a_groups[$settings['interface']][0]['vip'], 0, 4) == '_vip') {
93
				$openvpn_vip = $a_groups[$settings['interface']][0]['vip'];
94
			}
95
		} else {
96
			// this OpenVPN instance not on a CARP IP
97
			continue;
98
		}
99
		foreach ($vips as $vip) {
100
			if ($openvpn_vip == "_vip{$vip['uniqid']}") {
101
				log_error("Starting OpenVPN server instance on {$friendly_descr} because of transition to CARP master.");
102
				openvpn_restart('server', $settings);
103
			}
104
		}
105
	}
106
}
107
if (is_array($config['ipsec']) && is_array($config['ipsec']['phase1'])) {
108
	foreach ($config['ipsec']['phase1'] as $ph1ent) {
109
		if ((substr($ph1ent['interface'], 0, 4) == '_vip') && (in_array($ph1ent['interface'], $vips))) {
110
			log_error("Reconfiguring IPsec because of transition to CARP master.");
111
			ipsec_configure();
112
			break;
113
		}
114
	}
115
}
116

    
117
/* Reconfigure radvd when necessary */
118
if (isset($config['dhcpdv6']) && is_array($config['dhcpdv6'])) {
119
	$rafound = false;
120
	foreach ($config['dhcpdv6'] as $dhcpv6if => $dhcpv6ifconf) {
121
		foreach ($vips as $vip) {
122
			if ($dhcpv6ifconf['rainterface'] == "_vip{$vip['uniqid']}") {
123
				log_error("Starting radvd instance on {$friendly_descr} because of transition to CARP master.");
124
				$rafound = true;
125
			}
126
		}
127
	}
128
	if ($rafound) {
129
		services_radvd_configure();
130
	}
131
}
132

    
133
/* Reconfigure DHCP Relay when necessary */
134
if (isset($config['dhcrelay']) && is_array($config['dhcrelay']) && isset($config['dhcrelay']['enable']) &&
135
    isset($config['dhcrelay']['carpstatusvip']) && ($config['dhcrelay']['carpstatusvip'] == "_vip{$vip['uniqid']}")) {
136
	log_error("Starting DHCP Relay service because of transition to CARP master.");
137
	services_dhcrelay_configure();
138
}
139

    
140
/* Reconfigure DHCPv6 Relay when necessary */
141
if (isset($config['dhcrelay6']) && is_array($config['dhcrelay6']) && isset($config['dhcrelay6']['enable']) &&
142
    isset($config['dhcrelay6']['carpstatusvip']) && ($config['dhcrelay6']['carpstatusvip'] == "_vip{$vip['uniqid']}")) {
143
	log_error("Starting DHCPv6 Relay service because of transition to CARP master.");
144
	services_dhcrelay6_configure();
145
}
146

    
147
/* Reconfigure captive portal when necessary :
148
   If we are the primary node, and we are switching back from backup to master : Get user list from the backup node */
149
if (!empty($config['captiveportal']) && is_array($config['hasync']) && !empty($config['hasync']['synchronizetoip']) &&
150
    $config['hasync']['synchronizecaptiveportal'] != "") {
151
	if (empty($config['hasync']['username'])) {
152
		$xmlrpc_username = "admin";
153
	} else {
154
		$xmlrpc_username = $config['hasync']['username'];
155
	}
156
	$xmlrpc_port = $config['system']['webgui']['port'];
157
	if (empty($xmlrpc_port)) {
158
		if ($config['system']['webgui']['protocol'] == "http") {
159
			$xmlrpc_port = "80";
160
		} else {
161
			$xmlrpc_port = "443";
162
		}
163
	}
164

    
165
	foreach ($config['captiveportal'] as $cpzone=>$cp) {
166
		$rpc_client = new pfsense_xmlrpc_client();
167
		$rpc_client->setConnectionData($config['hasync']['synchronizetoip'], $xmlrpc_port, $xmlrpc_username, $config['hasync']['password']);
168
		$resp = $rpc_client->xmlrpc_method('captive_portal_sync', array('op' => 'get_databases', 'zone' => $cpzone));
169

    
170
		if (is_array($resp)) { // $resp will be an array only if the communication was successful
171
			// Contains array of connected users (will be stored in SQLite DB)
172
			$connected_users = unserialize(base64_decode($resp['connected_users']));
173
			// Contains array of active vouchers (will be stored in active vouchers db)
174
			$active_vouchers = unserialize(base64_decode($resp['active_vouchers']));
175
			// Contain bitmask of both in use and expired vouchers (will be stored in "used vouchers" db)
176
			$expired_vouchers = unserialize(base64_decode($resp['expired_vouchers']));
177
			// Contains array of usedmacs (will be stored in usedmacs db)
178
			$usedmacs = unserialize(base64_decode($resp['usedmacs']));
179

    
180
			$cpdb = captiveportal_read_db();
181
			$unsetindexes = array_column($cpdb, 5);
182
			if (!empty($unsetindexes)) {
183
				captiveportal_remove_entries($unsetindexes, true); // true: prevent carp loop
184
			}
185
			captiveportal_free_dnrules();
186

    
187
			foreach ($connected_users as $id => $user) {
188
				$pipeno = captiveportal_get_next_dn_ruleno('auth');
189
				$attributes = array();
190
				$attributes['allow_time'] = $user['allow_time'];
191
				$attributes['session_timeout'] = $user['session_timeout'];
192
				$attributes['idle_timeout'] = $user['idle_timeout'];
193
				$attributes['session_terminate_time'] = $user['session_terminate_time'];
194
				$attributes['interim_interval'] = $user['interim_interval'];
195
				$attributes['maxbytes'] = $user['traffic_quota'];
196

    
197
				portal_allow($user['ip'], $user['mac'], $user['username'], base64_decode($user['bpassword']), null,
198
				    $attributes, $pipeno, $user['authmethod'], $user['context'], $user['sessionid'], true);
199
			}
200
			foreach ($expired_vouchers as $roll => $vdb) {
201
				voucher_write_used_db($roll, $vdb);
202
			}
203
			foreach ($active_vouchers as $roll => $vouchers) {
204
				voucher_write_active_db($roll, $vouchers);
205
			}
206
			captiveportal_write_usedmacs_db($usedmacs); 
207
		}
208
		captiveportal_syslog(sprintf(gettext('Connected users, used vouchers and used MACs have been synchronized from %1$s'), $config['hasync']['synchronizetoip']));
209
	}
210
}
211
openlog("", LOG_PID, LOG_LOCAL0);
212
$pluginparams = array();
213
$pluginparams['type'] = 'carp';
214
$pluginparams['event'] = 'rc.carpmaster';
215
$pluginparams['interface'] = $argument;
216
pkg_call_plugins('plugin_carp', $pluginparams);
217

    
218
?>
(25-25/85)