6
6
7
7
use DateTime ;
8
8
use IPLib \Address \AddressInterface ;
9
+ use IPLib \Address \Type ;
9
10
use IPLib \Factory ;
10
11
use IPLib \Range \Subnet ;
11
12
use Psr \Log \LoggerInterface ;
@@ -245,14 +246,49 @@ private function defferUpdateCacheConfig(array $config): void
245
246
$ this ->adapter ->saveDeferred ($ cacheConfigItem );
246
247
}
247
248
249
+ /**
250
+ * Update the cached remediation of the specified IP from these new decisions.
251
+ */
252
+ private function saveRemediationsForIp (array $ decisions , string $ ip ): string
253
+ {
254
+ $ remediationResult = Constants::REMEDIATION_BYPASS ;
255
+ if (\count ($ decisions )) {
256
+ foreach ($ decisions as $ decision ) {
257
+ if (!\in_array ($ decision ['type ' ], Constants::ORDERED_REMEDIATIONS )) {
258
+ $ this ->logger ->warning ('' , ['type ' => 'UNKNOWN_REMEDIATION ' , 'unknown ' => $ decision ['type ' ], 'fallback ' => $ this ->fallbackRemediation ]);
259
+ $ decision ['type ' ] = $ this ->fallbackRemediation ;
260
+ }
261
+ $ remediation = $ this ->formatRemediationFromDecision ($ decision );
262
+ $ type = $ remediation [0 ];
263
+ $ exp = $ remediation [1 ];
264
+ $ id = $ remediation [2 ];
265
+ $ remediationResult = $ this ->addRemediationToCacheItem ($ ip , $ type , $ exp , $ id );
266
+ }
267
+ } else {
268
+ $ remediation = $ this ->formatRemediationFromDecision (null );
269
+ $ type = $ remediation [0 ];
270
+ $ exp = $ remediation [1 ];
271
+ $ id = $ remediation [2 ];
272
+ $ remediationResult = $ this ->addRemediationToCacheItem ($ ip , $ type , $ exp , $ id );
273
+ }
274
+ $ this ->commit ();
275
+
276
+ return $ remediationResult ;
277
+ }
278
+
248
279
/**
249
280
* Update the cached remediations from these new decisions.
250
281
*/
251
- private function saveRemediations (array $ decisions ): bool
282
+ private function saveRemediations (array $ decisions ): array
252
283
{
284
+ $ errors = [];
253
285
foreach ($ decisions as $ decision ) {
254
286
$ remediation = $ this ->formatRemediationFromDecision ($ decision );
255
287
$ type = $ remediation [0 ];
288
+ if (!\in_array ($ remediation [0 ], Constants::ORDERED_REMEDIATIONS )) {
289
+ $ this ->logger ->warning ('' , ['type ' => 'UNKNOWN_REMEDIATION ' , 'unknown ' => $ remediation [0 ], 'fallback ' => $ this ->fallbackRemediation ]);
290
+ $ remediation [0 ] = $ this ->fallbackRemediation ;
291
+ }
256
292
$ exp = $ remediation [1 ];
257
293
$ id = $ remediation [2 ];
258
294
@@ -262,7 +298,17 @@ private function saveRemediations(array $decisions): bool
262
298
} elseif ('Range ' === $ decision ['scope ' ]) {
263
299
$ range = Subnet::fromString ($ decision ['value ' ]);
264
300
301
+ $ addressType = $ range ->getAddressType ();
302
+ $ isIpv6 = (Type::T_IPv6 === $ addressType );
303
+ if ($ isIpv6 || ($ range ->getNetworkPrefix () < 24 )) {
304
+ $ error = ['type ' => 'DECISION_RANGE_TO_ADD_IS_TOO_LARGE ' , 'decision ' => $ decision ['id ' ], 'range ' => $ decision ['value ' ], 'remediation ' => $ type , 'expiration ' => $ exp ];
305
+ $ errors [] = $ error ;
306
+ $ this ->logger ->warning ('' , $ error );
307
+ continue ;
308
+ }
265
309
$ comparableEndAddress = $ range ->getEndAddress ()->getComparableString ();
310
+
311
+ $ comparableEndAddress = $ range ->getComparableEndString ();
266
312
$ address = $ range ->getStartAddress ();
267
313
$ this ->addRemediationToCacheItem (Bouncer::formatIpAsCacheKey ($ address ), $ type , $ exp , $ id );
268
314
$ ipCount = 1 ;
@@ -277,11 +323,12 @@ private function saveRemediations(array $decisions): bool
277
323
}
278
324
}
279
325
280
- return $ this ->commit ();
326
+ return [ ' success ' => $ this ->commit (), ' errors ' => $ errors ] ;
281
327
}
282
328
283
- private function removeRemediations (array $ decisions ): int
329
+ private function removeRemediations (array $ decisions ): array
284
330
{
331
+ $ errors = [];
285
332
$ count = 0 ;
286
333
foreach ($ decisions as $ decision ) {
287
334
if ('Ip ' === $ decision ['scope ' ]) {
@@ -298,7 +345,16 @@ private function removeRemediations(array $decisions): int
298
345
} elseif ('Range ' === $ decision ['scope ' ]) {
299
346
$ range = Subnet::fromString ($ decision ['value ' ]);
300
347
301
- $ comparableEndAddress = $ range ->getEndAddress ()->getComparableString ();
348
+ $ addressType = $ range ->getAddressType ();
349
+ $ isIpv6 = (Type::T_IPv6 === $ addressType );
350
+ if ($ isIpv6 || ($ range ->getNetworkPrefix () < 24 )) {
351
+ $ error = ['type ' => 'DECISION_RANGE_TO_REMOVE_IS_TOO_LARGE ' , 'decision ' => $ decision ['id ' ], 'range ' => $ decision ['value ' ]];
352
+ $ errors [] = $ error ;
353
+ $ this ->logger ->warning ('' , $ error );
354
+ continue ;
355
+ }
356
+
357
+ $ comparableEndAddress = $ range ->getComparableEndString ();
302
358
$ address = $ range ->getStartAddress ();
303
359
if (!$ this ->removeDecisionFromRemediationItem (Bouncer::formatIpAsCacheKey ($ address ), $ decision ['id ' ])) {
304
360
$ this ->logger ->debug ('' , ['type ' => 'DECISION_TO_REMOVE_NOT_FOUND_IN_CACHE ' , 'decision ' => $ decision ['id ' ]]);
@@ -333,37 +389,7 @@ private function removeRemediations(array $decisions): int
333
389
334
390
$ this ->commit ();
335
391
336
- return $ count ;
337
- }
338
-
339
- /**
340
- * Update the cached remediation of the specified IP from these new decisions.
341
- */
342
- private function saveRemediationsForIp (array $ decisions , string $ ip ): string
343
- {
344
- $ remediationResult = Constants::REMEDIATION_BYPASS ;
345
- if (\count ($ decisions )) {
346
- foreach ($ decisions as $ decision ) {
347
- if (!\in_array ($ decision ['type ' ], Constants::ORDERED_REMEDIATIONS )) {
348
- $ this ->logger ->warning ('' , ['type ' => 'UNKNOWN_REMEDIATION ' , 'unknown ' => $ decision ['type ' ], 'fallback ' => $ this ->fallbackRemediation ]);
349
- $ decision ['type ' ] = $ this ->fallbackRemediation ;
350
- }
351
- $ remediation = $ this ->formatRemediationFromDecision ($ decision );
352
- $ type = $ remediation [0 ];
353
- $ exp = $ remediation [1 ];
354
- $ id = $ remediation [2 ];
355
- $ remediationResult = $ this ->addRemediationToCacheItem ($ ip , $ type , $ exp , $ id );
356
- }
357
- } else {
358
- $ remediation = $ this ->formatRemediationFromDecision (null );
359
- $ type = $ remediation [0 ];
360
- $ exp = $ remediation [1 ];
361
- $ id = $ remediation [2 ];
362
- $ remediationResult = $ this ->addRemediationToCacheItem ($ ip , $ type , $ exp , $ id );
363
- }
364
- $ this ->commit ();
365
-
366
- return $ remediationResult ;
392
+ return ['count ' => $ count , 'errors ' => $ errors ];
367
393
}
368
394
369
395
public function clear (): bool
@@ -387,10 +413,12 @@ public function clear(): bool
387
413
* Warm the cache up.
388
414
* Used when the stream mode has just been activated.
389
415
*
390
- * @return int number of decisions added
416
+ * @return array "count": number of decisions added, "errors": decisions not added
391
417
*/
392
- public function warmUp (): int
418
+ public function warmUp (): array
393
419
{
420
+ $ addErrors = [];
421
+
394
422
if ($ this ->warmedUp ) {
395
423
$ this ->clear ();
396
424
}
@@ -401,7 +429,9 @@ public function warmUp(): int
401
429
402
430
$ nbNew = 0 ;
403
431
if ($ newDecisions ) {
404
- $ this ->warmedUp = $ this ->saveRemediations ($ newDecisions );
432
+ $ saveResult = $ this ->saveRemediations ($ newDecisions );
433
+ $ addErrors = $ saveResult ['errors ' ];
434
+ $ this ->warmedUp = $ saveResult ['success ' ];
405
435
$ this ->defferUpdateCacheConfig (['warmed_up ' => $ this ->warmedUp ]);
406
436
$ this ->commit ();
407
437
if (!$ this ->warmedUp ) {
@@ -416,20 +446,25 @@ public function warmUp(): int
416
446
$ this ->commit ();
417
447
$ this ->logger ->info ('' , ['type ' => 'CACHE_WARMED_UP ' , 'added_decisions ' => $ nbNew ]);
418
448
419
- return $ nbNew ;
449
+ return [ ' count ' => $ nbNew, ' errors ' => $ addErrors ] ;
420
450
}
421
451
422
452
/**
423
453
* Used in stream mode only.
424
454
* Pull decisions updates from the API and update the cached remediations.
425
455
* Used for the stream mode when we have to update the remediations list.
426
456
*
427
- * @return array number of deleted and new decisions
457
+ * @return array number of deleted and new decisions, and errors when processing decisions
428
458
*/
429
459
public function pullUpdates (): array
430
460
{
461
+ $ deletionErrors = [];
462
+ $ addErrors = [];
431
463
if (!$ this ->warmedUp ) {
432
- return ['deleted ' => 0 , 'new ' => $ this ->warmUp ()];
464
+ $ warmUpResult = $ this ->warmUp ();
465
+ $ addErrors = $ warmUpResult ['errors ' ];
466
+
467
+ return ['deleted ' => 0 , 'new ' => $ warmUpResult ['count ' ], 'deletionErrors ' => $ deletionErrors , 'addErrors ' => $ addErrors ];
433
468
}
434
469
435
470
$ this ->logger ->debug ('' , ['type ' => 'START_CACHE_UPDATE ' ]);
@@ -439,18 +474,21 @@ public function pullUpdates(): array
439
474
440
475
$ nbDeleted = 0 ;
441
476
if ($ deletedDecisions ) {
442
- $ nbDeleted = $ this ->removeRemediations ($ deletedDecisions );
477
+ $ removingResult = $ this ->removeRemediations ($ deletedDecisions );
478
+ $ deletionErrors = $ removingResult ['errors ' ];
479
+ $ nbDeleted = $ removingResult ['count ' ];
443
480
}
444
481
445
482
$ nbNew = 0 ;
446
483
if ($ newDecisions ) {
447
- $ this ->saveRemediations ($ newDecisions );
484
+ $ saveResult = $ this ->saveRemediations ($ newDecisions );
485
+ $ addErrors = $ saveResult ['errors ' ];
448
486
$ nbNew = \count ($ newDecisions );
449
487
}
450
488
451
489
$ this ->logger ->debug ('' , ['type ' => 'CACHE_UPDATED ' , 'deleted ' => $ nbDeleted , 'new ' => $ nbNew ]);
452
490
453
- return ['deleted ' => $ nbDeleted , 'new ' => $ nbNew ];
491
+ return ['deleted ' => $ nbDeleted , 'new ' => $ nbNew, ' deletionErrors ' => $ deletionErrors , ' addErrors ' => $ addErrors ];
454
492
}
455
493
456
494
/**
@@ -468,7 +506,6 @@ private function miss(string $ipToQuery, string $cacheKey): string
468
506
$ decisions = $ this ->apiClient ->getFilteredDecisions (['ip ' => $ ipToQuery ]);
469
507
}
470
508
471
-
472
509
return $ this ->saveRemediationsForIp ($ decisions , $ cacheKey );
473
510
}
474
511
0 commit comments