|
1
|
|
|
<?php |
|
2
|
|
|
|
|
3
|
|
|
/* |
|
4
|
|
|
* ****************************************************************************** |
|
5
|
|
|
* Copyright 2011-2017 DANTE Ltd. and GÉANT on behalf of the GN3, GN3+, GN4-1 |
|
6
|
|
|
* and GN4-2 consortia |
|
7
|
|
|
* |
|
8
|
|
|
* License: see the web/copyright.php file in the file structure |
|
9
|
|
|
* ****************************************************************************** |
|
10
|
|
|
*/ |
|
11
|
|
|
|
|
12
|
|
|
namespace core\diag; |
|
13
|
|
|
|
|
14
|
|
|
use \Exception; |
|
15
|
|
|
|
|
16
|
|
|
require_once(dirname(dirname(__DIR__)) . "/config/_config.php"); |
|
17
|
|
|
|
|
18
|
|
|
/** |
|
19
|
|
|
* The overall coordination class that runs all kinds of tests to find out where |
|
20
|
|
|
* and what is wrong. Operates on the realm of a user. Can do more magic if it |
|
21
|
|
|
* also knows which federation the user is currently positioned in, or even |
|
22
|
|
|
* which exact hotspot to analyse. |
|
23
|
|
|
*/ |
|
24
|
|
|
class Telepath { |
|
25
|
|
|
|
|
26
|
|
|
// list of elements of the infrastructure which could be broken |
|
27
|
|
|
// along with their occurence probability (guesswork!) |
|
28
|
|
|
const INFRA_ETLR = "INFRA_ETLR"; |
|
29
|
|
|
const INFRA_LINK_ETLR_NRO_IDP = "INFRA_LINK_ETLR_NRO_IdP"; |
|
30
|
|
|
const INFRA_LINK_ETLR_NRO_SP = "INFRA_LINK_ETLR_NRO_SP"; |
|
31
|
|
|
const INFRA_NRO_SP = "INFRA_NRO_SP"; |
|
32
|
|
|
const INFRA_NRO_IDP = "INFRA_NRO_IdP"; |
|
33
|
|
|
const INFRA_SP_RADIUS = "INFRA_SP_RADIUS"; |
|
34
|
|
|
const INFRA_IDP_RADIUS = "INFRA_IdP_RADIUS"; |
|
35
|
|
|
const INFRA_IDP_AUTHBACKEND = "INFRA_IdP_AUTHBACKEND"; |
|
36
|
|
|
const INFRA_SP_80211 = "INFRA_SP_80211"; |
|
37
|
|
|
const INFRA_SP_LAN = "INFRA_SP_LAN"; |
|
38
|
|
|
const INFRA_DEVICE = "INFRA_DEVICE"; |
|
39
|
|
|
const INFRA_NONEXISTENTREALM = "INFRA_NONEXISTENTREALM"; |
|
40
|
|
|
|
|
41
|
|
|
private $probabilities; |
|
42
|
|
|
private $possibleFailureReasons; |
|
43
|
|
|
private $additionalFindings; |
|
44
|
|
|
private $realm; |
|
45
|
|
|
private $visitedFlr; |
|
46
|
|
|
private $visitedHotspot; |
|
47
|
|
|
private $catIdP; |
|
48
|
|
|
private $dbIdP; |
|
49
|
|
|
private $idPFederation; |
|
50
|
|
|
private $logHandle; |
|
51
|
|
|
|
|
52
|
|
|
public function __construct(string $realm, $visitedFlr = NULL, $visitedHotspot = NULL) { |
|
53
|
|
|
// everyone could be guilty |
|
54
|
|
|
$this->possibleFailureReasons = [ |
|
55
|
|
|
Telepath::INFRA_ETLR, |
|
56
|
|
|
Telepath::INFRA_LINK_ETLR_NRO_IDP, |
|
57
|
|
|
Telepath::INFRA_LINK_ETLR_NRO_SP, |
|
58
|
|
|
Telepath::INFRA_NRO_SP, |
|
59
|
|
|
Telepath::INFRA_NRO_IDP, |
|
60
|
|
|
Telepath::INFRA_SP_RADIUS, |
|
61
|
|
|
Telepath::INFRA_IDP_RADIUS, |
|
62
|
|
|
Telepath::INFRA_IDP_AUTHBACKEND, |
|
63
|
|
|
Telepath::INFRA_SP_80211, |
|
64
|
|
|
Telepath::INFRA_SP_LAN, |
|
65
|
|
|
Telepath::INFRA_DEVICE, |
|
66
|
|
|
Telepath::INFRA_NONEXISTENTREALM, |
|
67
|
|
|
]; |
|
68
|
|
|
|
|
69
|
|
|
// these are NOT constant - in the course of checks, we may find a "smoking gun" and elevate the probability |
|
70
|
|
|
// in the end, use the numbers of those elements which were not deterministically excluded and normalise to 1 |
|
71
|
|
|
// to get a percentage to report on. |
|
72
|
|
|
$this->probabilities = [ |
|
73
|
|
|
Telepath::INFRA_ETLR => 0.01, |
|
74
|
|
|
Telepath::INFRA_LINK_ETLR_NRO_IDP => 0.01, |
|
75
|
|
|
Telepath::INFRA_LINK_ETLR_NRO_SP => 0.01, |
|
76
|
|
|
Telepath::INFRA_NRO_SP => 0.02, |
|
77
|
|
|
Telepath::INFRA_NRO_IDP => 0.02, |
|
78
|
|
|
Telepath::INFRA_SP_RADIUS => 0.04, |
|
79
|
|
|
Telepath::INFRA_IDP_RADIUS => 0.04, |
|
80
|
|
|
Telepath::INFRA_SP_80211 => 0.05, |
|
81
|
|
|
Telepath::INFRA_SP_LAN => 0.05, |
|
82
|
|
|
Telepath::INFRA_IDP_AUTHBACKEND => 0.02, |
|
83
|
|
|
Telepath::INFRA_DEVICE => 0.3, |
|
84
|
|
|
Telepath::INFRA_NONEXISTENTREALM => 0.7, /* if the eduroam DB were fully and consistently populated, this would have 1.0 - if we don't know anything about the realm, then this is not a valid eduroam realm. But reality says we don't have complete info in the DBs. */ |
|
85
|
|
|
]; |
|
86
|
|
|
$this->additionalFindings = []; |
|
87
|
|
|
$this->realm = $realm; |
|
88
|
|
|
$this->visitedFlr = $visitedFlr; |
|
89
|
|
|
$this->visitedHotspot = $visitedHotspot; |
|
90
|
|
|
$links = \core\Federation::determineIdPIdByRealm($realm); |
|
91
|
|
|
$this->catIdP = $links["CAT"]; |
|
92
|
|
|
$this->dbIdP = $links["EXTERNAL"]; |
|
93
|
|
|
$this->idPFederation = $links["FEDERATION"]; |
|
94
|
|
|
// this is NULL if the realm is not known in either DB |
|
95
|
|
|
// if so, let's try a regex to extract the ccTLD if any |
|
96
|
|
|
$matches = []; |
|
97
|
|
|
if ($this->idPFederation === NULL && preg_match("/\.(..)$/", $realm, $matches)) { |
|
98
|
|
|
$this->idPFederation = strtoupper($matches[1]); |
|
99
|
|
|
} |
|
100
|
|
|
$this->logHandle = new \core\common\Logging(); |
|
101
|
|
|
$this->logHandle->debug(4, "XYZ: IdP-side NRO is " . $this->idPFederation . "\n"); |
|
102
|
|
|
} |
|
103
|
|
|
|
|
104
|
|
|
const STATUS_GOOD = 0; |
|
105
|
|
|
const STATUS_PARTIAL = -1; |
|
106
|
|
|
const STATUS_DOWN = -2; |
|
107
|
|
|
const STATUS_MONITORINGFAIL = -3; |
|
108
|
|
|
|
|
109
|
|
|
/* The eduroam OT monitoring has the following return codes: |
|
110
|
|
|
* |
|
111
|
|
|
|
|
112
|
|
|
Status codes |
|
113
|
|
|
|
|
114
|
|
|
0 - O.K. |
|
115
|
|
|
-1 - Accept O.K. Reject No |
|
116
|
|
|
-2 - Reject O.K. Accept No |
|
117
|
|
|
-3 - Accept No Reject No |
|
118
|
|
|
-9 - system error |
|
119
|
|
|
-10 - Accept O.K. Reject timeou |
|
120
|
|
|
-11 - Accept O.K. Reject no EAP |
|
121
|
|
|
-20 - Reject O.K. Accept timeou |
|
122
|
|
|
-21 - Reject O.K. Accept no EAP |
|
123
|
|
|
-31 - Accept No Reject timeou |
|
124
|
|
|
-32 - Accept Timeout Reject no |
|
125
|
|
|
-33 - Accept Timeout Reject timeou |
|
126
|
|
|
-35 - Accept No Reject no EAP |
|
127
|
|
|
-36 - Reject No Accept no EAP |
|
128
|
|
|
-37 - Reject No EAP Accept no EAP |
|
129
|
|
|
-40 - UDP test error |
|
130
|
|
|
|
|
131
|
|
|
*/ |
|
132
|
|
|
|
|
133
|
|
|
private function checkEtlrStatus() { |
|
134
|
|
|
// TODO: we always check the European TLRs even though the connection in question might go via others and/or this one |
|
135
|
|
|
// needs a table to determine what goes where :-( |
|
136
|
|
|
$jsonResult = \core\common\OutsideComm::downloadFile("https://monitor.eduroam.org/mapi/index.php?type=tlr_test&tlr=TLR_EU"); |
|
137
|
|
|
$decoded = json_decode($jsonResult, TRUE); |
|
138
|
|
|
$retval["RAW"] = $decoded; |
|
|
|
|
|
|
139
|
|
|
$atLeastOneFunctional = FALSE; |
|
140
|
|
|
$allFunctional = TRUE; |
|
141
|
|
|
if (!isset($decoded['tlr_test']) || isset($decoded['ERROR'])) { |
|
142
|
|
|
$retval["STATUS"] = Telepath::STATUS_MONITORINGFAIL; |
|
143
|
|
|
return $retval; |
|
144
|
|
|
} |
|
145
|
|
|
foreach ($decoded['tlr_test'] as $instance => $resultset) { |
|
146
|
|
|
if ($instance == "tlr") { |
|
147
|
|
|
// don't care |
|
148
|
|
|
continue; |
|
149
|
|
|
} |
|
150
|
|
|
switch ($resultset['status_code']) { |
|
151
|
|
|
case 0: |
|
152
|
|
|
$atLeastOneFunctional = TRUE; |
|
153
|
|
|
break; |
|
154
|
|
|
case 9: |
|
155
|
|
|
break; |
|
156
|
|
|
default: |
|
157
|
|
|
$allFunctional = FALSE; |
|
158
|
|
|
} |
|
159
|
|
|
} |
|
160
|
|
|
if ($allFunctional) { |
|
161
|
|
|
$retval["STATUS"] = Telepath::STATUS_GOOD; |
|
162
|
|
|
return $retval; |
|
163
|
|
|
} |
|
164
|
|
|
if ($atLeastOneFunctional) { |
|
165
|
|
|
$retval["STATUS"] = Telepath::STATUS_PARTIAL; |
|
166
|
|
|
return $retval; |
|
167
|
|
|
} |
|
168
|
|
|
$retval["STATUS"] = Telepath::STATUS_DOWN; |
|
169
|
|
|
return $retval; |
|
170
|
|
|
} |
|
171
|
|
|
|
|
172
|
|
|
private function checkFedEtlrUplink($flr) { |
|
|
|
|
|
|
173
|
|
|
// TODO: this is a stub, need eduroam OT API to query the current server status |
|
174
|
|
|
// APIQueryNROviaETLR($flr); |
|
|
|
|
|
|
175
|
|
|
return Telepath::STATUS_GOOD; |
|
176
|
|
|
} |
|
177
|
|
|
|
|
178
|
|
|
private function checkFlrServerStatus($flr) { |
|
|
|
|
|
|
179
|
|
|
// TODO: this is a stub, need eduroam OT API to query the current server status |
|
180
|
|
|
// APIQueryNRODirect($flr); |
|
|
|
|
|
|
181
|
|
|
return Telepath::STATUS_GOOD; |
|
182
|
|
|
} |
|
183
|
|
|
|
|
184
|
|
|
private function checkNROFlow($visitedFlr, $homeFlr) { |
|
|
|
|
|
|
185
|
|
|
// TODO: this is a stub, need eduroam OT API to query the current server status |
|
186
|
|
|
// APIQueryNRODirect($visitedFlr, $homeFlr); |
|
|
|
|
|
|
187
|
|
|
return Telepath::STATUS_GOOD; |
|
188
|
|
|
} |
|
189
|
|
|
|
|
190
|
|
|
public function magic() { |
|
191
|
|
|
|
|
192
|
|
|
// simple things first: do we know anything about the realm, either |
|
193
|
|
|
// because it's a CAT participant or because it's in the eduroam DB? |
|
194
|
|
|
// if so, we can exclude the INFRA_NONEXISTENTREALM cause |
|
195
|
|
|
|
|
196
|
|
|
$this->additionalFindings[Telepath::INFRA_NONEXISTENTREALM][] = ["ID1" => $this->catIdP, "ID2" => $this->dbIdP]; |
|
197
|
|
|
|
|
198
|
|
|
if ($this->catIdP != \core\Federation::UNKNOWN_IDP || $this->dbIdP != \core\Federation::UNKNOWN_IDP) { |
|
199
|
|
|
$this->possibleFailureReasons = array_diff($this->possibleFailureReasons, [Telepath::INFRA_NONEXISTENTREALM]); |
|
200
|
|
|
} |
|
201
|
|
|
|
|
202
|
|
|
// let's do the least amount of testing needed: |
|
203
|
|
|
// - The CAT reachability test already covers ELTRs, IdP NRO level and the IdP itself. |
|
204
|
|
|
// if the realm maps to a CAT IdP, we can run the more thorough tests; otherwise just |
|
205
|
|
|
// the normal shallow ones |
|
206
|
|
|
|
|
207
|
|
|
if ($this->catIdP > 0) { |
|
208
|
|
|
$idpObject = new \core\IdP($this->catIdP); |
|
209
|
|
|
$profileObjects = $idpObject->listProfiles(); |
|
210
|
|
|
|
|
211
|
|
|
$bestProfile = FALSE; |
|
212
|
|
|
|
|
213
|
|
|
|
|
214
|
|
|
foreach ($profileObjects as $profileObject) { |
|
215
|
|
|
$mangledRealm = substr($profileObject->realm, strpos($profileObject->realm, "@") + 1); |
|
216
|
|
|
$readinessLevel = $profileObject->readinessLevel(); |
|
217
|
|
|
if ($readinessLevel == \core\AbstractProfile::READINESS_LEVEL_SHOWTIME && $mangledRealm == $this->realm) { |
|
218
|
|
|
$bestProfile = $profileObject; |
|
219
|
|
|
break; |
|
220
|
|
|
} |
|
221
|
|
|
if ($readinessLevel == \core\AbstractProfile::READINESS_LEVEL_SUFFICIENTCONFIG && $profileObject->realm == $this->realm) { |
|
222
|
|
|
$bestProfile = $profileObject; |
|
223
|
|
|
} |
|
224
|
|
|
} |
|
225
|
|
|
if ($bestProfile == FALSE) { // huh? no match on the realm. Then let's take the next-best with SUFFICIENTCONFIG |
|
226
|
|
|
foreach ($profileObjects as $profileObject) { |
|
227
|
|
|
$readinessLevel = $profileObject->readinessLevel(); |
|
228
|
|
|
if ($readinessLevel == \core\AbstractProfile::READINESS_LEVEL_SUFFICIENTCONFIG) { |
|
229
|
|
|
$bestProfile = $profileObject; |
|
230
|
|
|
break; |
|
231
|
|
|
} |
|
232
|
|
|
} |
|
233
|
|
|
} |
|
234
|
|
|
if ($bestProfile != FALSE) { // still nothing? then there's only a very incomplete profile definition, and we can't work with that. Fall back to shallow |
|
235
|
|
|
$this->additionalFindings[Telepath::INFRA_IDP_RADIUS][] = ["Profile" => $bestProfile->identifier]; |
|
236
|
|
|
$testsuite = new RADIUSTests($this->realm, $bestProfile->getRealmCheckOuterUsername(), $bestProfile->getEapMethodsinOrderOfPreference(1), $bestProfile->getCollapsedAttributes()['eap:server_name'], $bestProfile->getCollapsedAttributes()["eap:ca_file"]); |
|
237
|
|
|
} else { |
|
238
|
|
|
$this->additionalFindings[Telepath::INFRA_IDP_RADIUS][] = ["Profile" => "UNCONCLUSIVE"]; |
|
239
|
|
|
$testsuite = new RADIUSTests($this->realm, "anonymous@" . $this->realm); |
|
240
|
|
|
} |
|
241
|
|
|
} else { |
|
242
|
|
|
$testsuite = new RADIUSTests($this->realm, "anonymous@" . $this->realm); |
|
243
|
|
|
} |
|
244
|
|
|
|
|
245
|
|
|
// we are expecting to get a REJECT from all runs, because that means the packet got through to the IdP. |
|
246
|
|
|
// (the ETLR sometimes does a "Reject instead of Ignore" but that is filtered out and changed into a timeout |
|
247
|
|
|
// by the test suite automatically, so it does not disturb the measurement) |
|
248
|
|
|
// If that's true, we can exclude two sources of problems (both proxy levels). Hooray! |
|
249
|
|
|
$allAreConversationReject = TRUE; |
|
250
|
|
|
$atLeastOneConversationReject = FALSE; |
|
251
|
|
|
|
|
252
|
|
|
foreach (CONFIG_DIAGNOSTICS['RADIUSTESTS']['UDP-hosts'] as $probeindex => $probe) { |
|
253
|
|
|
$reachCheck = $testsuite->udpReachability($probeindex); |
|
254
|
|
|
if ($reachCheck != RADIUSTests::RETVAL_CONVERSATION_REJECT) { |
|
255
|
|
|
$allAreConversationReject = FALSE; |
|
256
|
|
|
} else { |
|
257
|
|
|
$atLeastOneConversationReject = TRUE; |
|
258
|
|
|
} |
|
259
|
|
|
|
|
260
|
|
|
$this->additionalFindings[Telepath::INFRA_ETLR][] = ["DETAIL" => $testsuite->consolidateUdpResult($probeindex)]; |
|
261
|
|
|
$this->additionalFindings[Telepath::INFRA_NRO_IDP][] = ["DETAIL" => $testsuite->consolidateUdpResult($probeindex)]; |
|
262
|
|
|
$this->additionalFindings[Telepath::INFRA_IDP_RADIUS][] = ["DETAIL" => $testsuite->consolidateUdpResult($probeindex)]; |
|
263
|
|
|
} |
|
264
|
|
|
|
|
265
|
|
|
if ($allAreConversationReject) { |
|
266
|
|
|
$this->additionalFindings[Telepath::INFRA_ETLR][] = ["CONNCHECK" => RADIUSTests::RETVAL_CONVERSATION_REJECT]; |
|
267
|
|
|
$this->additionalFindings[Telepath::INFRA_NRO_IDP][] = ["CONNCHECK" => RADIUSTests::RETVAL_CONVERSATION_REJECT]; |
|
268
|
|
|
$this->additionalFindings[Telepath::INFRA_IDP_RADIUS][] = ["CONNCHECK" => RADIUSTests::RETVAL_CONVERSATION_REJECT]; |
|
269
|
|
|
$this->additionalFindings[Telepath::INFRA_LINK_ETLR_NRO_IDP][] = ["LINKCHECK" => RADIUSTests::L_OK]; |
|
270
|
|
|
// we have actually reached an IdP, so all links are good, and the |
|
271
|
|
|
// realm is routable in eduroam. So even if it exists in neither DB |
|
272
|
|
|
// we can exclude the NONEXISTENTREALM case |
|
273
|
|
|
$this->possibleFailureReasons = array_diff($this->possibleFailureReasons, [Telepath::INFRA_ETLR, Telepath::INFRA_NRO_IDP, Telepath::INFRA_LINK_ETLR_NRO_IDP, Telepath::INFRA_NONEXISTENTREALM]); |
|
274
|
|
|
}; |
|
275
|
|
|
|
|
276
|
|
|
if ($atLeastOneConversationReject) { |
|
277
|
|
|
// at least we can be sure it exists |
|
278
|
|
|
$this->possibleFailureReasons = array_diff($this->possibleFailureReasons, [Telepath::INFRA_NONEXISTENTREALM]); |
|
279
|
|
|
// It could still be an IdP RADIUS problem in that some cert oddities |
|
280
|
|
|
// in combination with the device lead to a broken auth |
|
281
|
|
|
// if there is nothing beyond the "REMARK" level, then it's not an IdP problem |
|
282
|
|
|
// otherwise, add the corresponding warnings and errors to $additionalFindings |
|
283
|
|
|
switch ($this->additionalFindings[Telepath::INFRA_IDP_RADIUS][0]['DETAIL']['level']) { |
|
284
|
|
|
case RADIUSTests::L_OK: |
|
285
|
|
|
case RADIUSTests::L_REMARK: |
|
286
|
|
|
// both are fine - the IdP is working and the user problem |
|
287
|
|
|
// is not on the IdP RADIUS level |
|
288
|
|
|
$this->additionalFindings[Telepath::INFRA_IDP_RADIUS][] = ["ODDITYLEVEL" => $this->additionalFindings[Telepath::INFRA_IDP_RADIUS][0]['DETAIL']['level']]; |
|
289
|
|
|
$this->possibleFailureReasons = array_diff($this->possibleFailureReasons, [Telepath::INFRA_IDP_RADIUS]); |
|
290
|
|
|
break; |
|
291
|
|
|
case RADIUSTests::L_WARN: |
|
292
|
|
|
$this->additionalFindings[Telepath::INFRA_IDP_RADIUS][] = ["ODDITYLEVEL" => RADIUSTests::L_WARN]; |
|
293
|
|
|
$this->probabilities[Telepath::INFRA_IDP_RADIUS] = 0.3; // possibly we found the culprit - if RADIUS server is misconfigured AND user is on a device which reacts picky about exactly this oddity. |
|
294
|
|
|
break; |
|
295
|
|
|
case RADIUSTests::L_ERROR: |
|
296
|
|
|
$this->additionalFindings[Telepath::INFRA_IDP_RADIUS][] = ["ODDITYLEVEL" => RADIUSTests::L_ERROR]; |
|
297
|
|
|
$this->probabilities[Telepath::INFRA_IDP_RADIUS] = 0.8; // errors are never good, so we can be reasonably sure we've hit the spot! |
|
298
|
|
|
} |
|
299
|
|
|
} |
|
300
|
|
|
|
|
301
|
|
|
// - if the test does NOT go through, we need to find out which of the three is guilty |
|
302
|
|
|
// - then, the international "via ETLR" check can be used to find out if the IdP alone |
|
303
|
|
|
// is guilty. If that one fails, the direct monitoring of servers and ETLRs themselves |
|
304
|
|
|
// closes the loop. |
|
305
|
|
|
// let's see if the ETLRs are up |
|
306
|
|
|
|
|
307
|
|
|
$etlrStatus = $this->checkEtlrStatus(); |
|
308
|
|
|
$this->additionalFindings[Telepath::INFRA_ETLR][] = $etlrStatus; |
|
309
|
|
|
switch ($etlrStatus["STATUS"]) { |
|
310
|
|
|
case Telepath::STATUS_GOOD: |
|
311
|
|
|
$this->possibleFailureReasons = array_diff($this->possibleFailureReasons, [Telepath::INFRA_ETLR]); |
|
312
|
|
|
break; |
|
313
|
|
|
case Telepath::STATUS_PARTIAL: |
|
314
|
|
|
case Telepath::STATUS_MONITORINGFAIL: |
|
315
|
|
|
// one of the ETLRs is down, or there is a failure in the monitoring system? |
|
316
|
|
|
// This probably doesn't impact the user unless he's unlucky and has his session fall into failover. |
|
317
|
|
|
// keep ETLR as a possible problem with original probability |
|
318
|
|
|
break; |
|
319
|
|
|
case Telepath::STATUS_DOWN: |
|
320
|
|
|
// Oh! Well if it is not international roaming, that still doesn't have an effect /in this case/. |
|
321
|
|
|
if ($this->idPFederation == $this->visitedFlr) { |
|
322
|
|
|
$this->possibleFailureReasons = array_diff($this->possibleFailureReasons, [Telepath::INFRA_ETLR]); |
|
323
|
|
|
break; |
|
324
|
|
|
} |
|
325
|
|
|
// But it is about int'l roaming, and we are spot on here. |
|
326
|
|
|
// Raise probability by much (even monitoring is sometimes wrong, or a few minutes behind reality) |
|
327
|
|
|
$this->probabilities[Telepath::INFRA_ETLR] = 0.95; |
|
328
|
|
|
} |
|
329
|
|
|
// next up: if the ETLR was okay, check the the FLR and its ETLR |
|
330
|
|
|
// uplink (if we know which federation we are talking about) |
|
331
|
|
|
|
|
332
|
|
|
if (!in_array(Telepath::INFRA_ETLR, $this->possibleFailureReasons) && $this->idPFederation != NULL) { |
|
333
|
|
|
// first the direct connectivity to the server |
|
334
|
|
|
$flrServerStatus = $this->checkFlrServerStatus($this->idPFederation); |
|
335
|
|
View Code Duplication |
switch ($flrServerStatus) { |
|
|
|
|
|
|
336
|
|
|
case Telepath::STATUS_GOOD: |
|
337
|
|
|
$this->additionalFindings[Telepath::INFRA_NRO_IDP][] = ["STATUS" => Telepath::STATUS_GOOD]; |
|
338
|
|
|
$this->possibleFailureReasons = array_diff($this->possibleFailureReasons, [Telepath::INFRA_NRO_IDP]); |
|
339
|
|
|
break; |
|
340
|
|
|
case Telepath::STATUS_PARTIAL: |
|
341
|
|
|
// a subset of the FLRs is down? This probably doesn't impact the user unless he's unlucky and has his session fall into failover. |
|
342
|
|
|
// keep FLR as a possible problem with original probability |
|
343
|
|
|
$this->additionalFindings[Telepath::INFRA_NRO_IDP][] = ["STATUS" => Telepath::STATUS_PARTIAL]; |
|
344
|
|
|
break; |
|
345
|
|
|
case Telepath::STATUS_DOWN: |
|
346
|
|
|
$this->additionalFindings[Telepath::INFRA_NRO_IDP][] = ["STATUS" => Telepath::STATUS_DOWN]; |
|
347
|
|
|
// Raise probability by much (even monitoring is sometimes wrong, or a few minutes behind reality) |
|
348
|
|
|
$this->probabilities[Telepath::INFRA_NRO_IDP] = 0.95; |
|
349
|
|
|
} |
|
350
|
|
|
// then its uplink |
|
351
|
|
|
$flrUplinkStatus = $this->checkFedEtlrUplink($this->idPFederation); |
|
352
|
|
View Code Duplication |
switch ($flrUplinkStatus) { |
|
|
|
|
|
|
353
|
|
|
case Telepath::STATUS_GOOD: |
|
354
|
|
|
$this->additionalFindings[Telepath::INFRA_NRO_IDP][] = ["STATUS" => Telepath::STATUS_GOOD]; |
|
355
|
|
|
$this->possibleFailureReasons = array_diff($this->possibleFailureReasons, [Telepath::INFRA_NRO_IDP, Telepath::INFRA_LINK_ETLR_NRO_IDP]); |
|
356
|
|
|
break; |
|
357
|
|
|
case Telepath::STATUS_PARTIAL: |
|
358
|
|
|
// a subset of the FLRs is down? This probably doesn't impact the user unless he's unlucky and has his session fall into failover. |
|
359
|
|
|
// keep FLR as a possible problem with original probability |
|
360
|
|
|
$this->additionalFindings[Telepath::INFRA_NRO_IDP][] = ["STATUS" => Telepath::STATUS_PARTIAL]; |
|
361
|
|
|
break; |
|
362
|
|
|
case Telepath::STATUS_DOWN: |
|
363
|
|
|
$this->additionalFindings[Telepath::INFRA_NRO_IDP][] = ["STATUS" => Telepath::STATUS_DOWN]; |
|
364
|
|
|
// Raise probability by much (even monitoring is sometimes wrong, or a few minutes behind reality) |
|
365
|
|
|
// if earlier test found the server itself to be the problem, keep it, otherwise put the blame on the link |
|
366
|
|
|
if ($this->probabilities[Telepath::INFRA_NRO_IDP] != 0.95) { |
|
367
|
|
|
$this->probabilities[Telepath::INFRA_LINK_ETLR_NRO_IDP] = 0.95; |
|
368
|
|
|
} |
|
369
|
|
|
} |
|
370
|
|
|
} |
|
371
|
|
|
|
|
372
|
|
|
// now, if we know the country the user is currently in, let's see |
|
373
|
|
|
// if the NRO SP-side is up |
|
374
|
|
|
if ($this->visitedFlr !== NULL) { |
|
375
|
|
|
$visitedFlrStatus = $this->checkFlrServerStatus($this->visitedFlr); |
|
376
|
|
|
// direct query to server |
|
377
|
|
View Code Duplication |
switch ($visitedFlrStatus) { |
|
|
|
|
|
|
378
|
|
|
case Telepath::STATUS_GOOD: |
|
379
|
|
|
$this->additionalFindings[Telepath::INFRA_NRO_SP][] = ["STATUS" => Telepath::STATUS_GOOD]; |
|
380
|
|
|
$this->possibleFailureReasons = array_diff($this->possibleFailureReasons, [Telepath::INFRA_NRO_SP]); |
|
381
|
|
|
break; |
|
382
|
|
|
case Telepath::STATUS_PARTIAL: |
|
383
|
|
|
// a subset of the FLRs is down? This probably doesn't impact the user unless he's unlucky and has his session fall into failover. |
|
384
|
|
|
// keep FLR as a possible problem with original probability |
|
385
|
|
|
$this->additionalFindings[Telepath::INFRA_NRO_SP][] = ["STATUS" => Telepath::STATUS_PARTIAL]; |
|
386
|
|
|
break; |
|
387
|
|
|
case Telepath::STATUS_DOWN: |
|
388
|
|
|
$this->additionalFindings[Telepath::INFRA_NRO_SP][] = ["STATUS" => Telepath::STATUS_DOWN]; |
|
389
|
|
|
// Raise probability by much (even monitoring is sometimes wrong, or a few minutes behind reality) |
|
390
|
|
|
$this->probabilities[Telepath::INFRA_NRO_SP] = 0.95; |
|
391
|
|
|
} |
|
392
|
|
|
// and again its uplink to the ETLR |
|
393
|
|
|
$visitedFlrUplinkStatus = $this->checkFedEtlrUplink($this->visitedFlr); |
|
394
|
|
View Code Duplication |
switch ($visitedFlrUplinkStatus) { |
|
|
|
|
|
|
395
|
|
|
case Telepath::STATUS_GOOD: |
|
396
|
|
|
$this->additionalFindings[Telepath::INFRA_NRO_SP][] = ["STATUS" => Telepath::STATUS_GOOD]; |
|
397
|
|
|
$this->possibleFailureReasons = array_diff($this->possibleFailureReasons, [Telepath::INFRA_NRO_SP, Telepath::INFRA_LINK_ETLR_NRO_SP]); |
|
398
|
|
|
break; |
|
399
|
|
|
case Telepath::STATUS_PARTIAL: |
|
400
|
|
|
// a subset of the FLRs is down? This probably doesn't impact the user unless he's unlucky and has his session fall into failover. |
|
401
|
|
|
// keep FLR as a possible problem with original probability |
|
402
|
|
|
$this->additionalFindings[Telepath::INFRA_NRO_SP][] = ["STATUS" => Telepath::STATUS_PARTIAL]; |
|
403
|
|
|
break; |
|
404
|
|
|
case Telepath::STATUS_DOWN: |
|
405
|
|
|
$this->additionalFindings[Telepath::INFRA_NRO_SP][] = ["STATUS" => Telepath::STATUS_DOWN]; |
|
406
|
|
|
// Raise probability by much (even monitoring is sometimes wrong, or a few minutes behind reality) |
|
407
|
|
|
// if earlier test found the server itself to be the problem, keep it, otherwise put the blame on the link |
|
408
|
|
|
if ($this->probabilities[Telepath::INFRA_NRO_SP] != 0.95) { |
|
409
|
|
|
$this->probabilities[Telepath::INFRA_LINK_ETLR_NRO_SP] = 0.95; |
|
410
|
|
|
} |
|
411
|
|
|
} |
|
412
|
|
|
// the last thing we can do (but it's a bit redundant): check the country-to-country link |
|
413
|
|
|
// it's only needed if all three and their links are up, but we want to exclude funny routing blacklists |
|
414
|
|
|
// which occur only in the *combination* of source and dest |
|
415
|
|
|
// if there is an issue at that point, blame the SP: once a request would have reached the ETLRs, things would be all good. So they apparently didn't. |
|
416
|
|
|
if (!in_array(Telepath::INFRA_ETLR, $this->possibleFailureReasons) && |
|
417
|
|
|
!in_array(Telepath::INFRA_LINK_ETLR_NRO_IDP, $this->possibleFailureReasons) && |
|
418
|
|
|
!in_array(Telepath::INFRA_NRO_IDP, $this->possibleFailureReasons) && |
|
419
|
|
|
!in_array(Telepath::INFRA_LINK_ETLR_NRO_SP, $this->possibleFailureReasons) && |
|
420
|
|
|
!in_array(Telepath::INFRA_NRO_SP, $this->possibleFailureReasons) |
|
421
|
|
|
) { |
|
422
|
|
|
$countryToCountryStatus = $this->checkNROFlow($this->visitedFlr, $this->idPFederation); |
|
423
|
|
|
switch ($countryToCountryStatus) { |
|
424
|
|
|
case Telepath::STATUS_GOOD: |
|
425
|
|
|
// all routes work |
|
426
|
|
|
break; |
|
427
|
|
|
case Telepath::STATUS_PARTIAL: |
|
428
|
|
|
// at least one, or even all have a routing problem |
|
429
|
|
|
case Telepath::STATUS_DOWN: |
|
430
|
|
|
// that's rather telling. |
|
431
|
|
|
$this->additionalFindings[Telepath::INFRA_NRO_SP][] = ["C2CLINK" => Telepath::STATUS_DOWN]; |
|
432
|
|
|
$this->probabilities[Telepath::INFRA_NRO_SP] = 0.95; |
|
433
|
|
|
} |
|
434
|
|
|
} |
|
435
|
|
|
} |
|
436
|
|
|
|
|
437
|
|
|
// done. return both the list of possible problem sources with their probabilities, and the additional findings we collected along the way. |
|
438
|
|
|
$totalScores = 0.; |
|
439
|
|
|
foreach ($this->possibleFailureReasons as $oneReason) { |
|
440
|
|
|
$totalScores += $this->probabilities[$oneReason]; |
|
441
|
|
|
} |
|
442
|
|
|
$probArray = []; |
|
443
|
|
|
foreach ($this->possibleFailureReasons as $oneReason) { |
|
444
|
|
|
$probArray[$oneReason] = $this->probabilities[$oneReason] / $totalScores; |
|
445
|
|
|
} |
|
446
|
|
|
array_multisort($probArray, SORT_DESC, SORT_NUMERIC, $this->possibleFailureReasons); |
|
447
|
|
|
|
|
448
|
|
|
return ["SUSPECTS" => $this->possibleFailureReasons, "PROBABILITIES" => $probArray, "EVIDENCE" => $this->additionalFindings]; |
|
449
|
|
|
} |
|
450
|
|
|
|
|
451
|
|
|
} |
|
452
|
|
|
|
Adding an explicit array definition is generally preferable to implicit array definition as it guarantees a stable state of the code.
Let’s take a look at an example:
As you can see in this example, the array
$myArrayis initialized the first time when the foreach loop is entered. You can also see that the value of thebarkey is only written conditionally; thus, its value might result from a previous iteration.This might or might not be intended. To make your intention clear, your code more readible and to avoid accidental bugs, we recommend to add an explicit initialization $myArray = array() either outside or inside the foreach loop.