Wordfence Security – Firewall & Malware Scan - Version 6.2.3

Version Description

  • Improvement: Reworked blocking for IP ranges, country blocking, and direct IP blocking to minimize server impact when under attack.
  • Improvement: Live traffic better indicates the action taken by country blocking when it redirects a visitor.
  • Improvement: Added support for finding server logs to the Diagnostics page to help with troubleshooting.
  • Improvement: Whitelisted StatusCake IP addresses.
  • Improvement: Updated GeoIP database.
  • Improvement: Disabling Wordfence now sends an alert.
  • Improvement: Improved detection for uploaded PHP content in the firewall.
  • Fix: Eliminated memory-related errors resulting from the scan on sites with very large numbers of issues and low memory.
  • Fix: Fixed admin page layout for sites using RTL languages.
  • Fix: Reduced overhead of the dashboard widget.
  • Fix: Improved performance of checking for whitelisted IPs.
  • Fix: Changes to the default plugin hello.php are now detected correctly in scans.
  • Fix: Fixed IPv6 warning in the dashboard widget.
Download this release

Release Info

Developer wfryan
Plugin Icon 128x128 Wordfence Security – Firewall & Malware Scan
Version 6.2.3
Comparing to
See all releases

Code changes from version 6.2.2 to 6.2.3

js/admin.js CHANGED
@@ -63,6 +63,10 @@
63
  $($this.data('selector')).show();
64
  return false;
65
  });
 
 
 
 
66
 
67
  $('#doSendEmail').click(function() {
68
  var ticket = $('#_ticketnumber').val();
@@ -111,11 +115,39 @@
111
  jQuery('#consoleActivity').scrollTop(jQuery('#consoleActivity').prop('scrollHeight'));
112
  jQuery('#consoleScan').scrollTop(jQuery('#consoleScan').prop('scrollHeight'));
113
  this.noScanHTML = jQuery('#wfNoScanYetTmpl').tmpl().html();
114
- this.loadIssues();
 
 
 
 
 
 
115
  this.startActivityLogUpdates();
116
  if (this.needTour()) {
117
  this.scanTourStart();
118
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
119
  } else if (jQuery('#wordfenceMode_waf').length > 0) {
120
  if (this.needTour()) {
121
  this.tour('wfWAFTour', 'wfHeading', 'top', 'left', "Learn about Live Traffic", function() {
@@ -321,7 +353,9 @@
321
  },
322
  updateConfig: function(key, val, cb) {
323
  this.ajax('wordfence_updateConfig', {key: key, val: val}, function() {
324
- cb();
 
 
325
  });
326
  },
327
  tourFinish: function() {
@@ -790,15 +824,25 @@
790
  jQuery('#wfAuditJobs').empty().html("<p>You don't have any password auditing jobs in progress or completed yet.</p>");
791
  }
792
  },
793
- loadIssues: function(callback) {
794
  if (this.mode != 'scan') {
795
  return;
796
  }
 
 
797
  var self = this;
798
- this.ajax('wordfence_loadIssues', {}, function(res) {
799
  self.displayIssues(res, callback);
800
  });
801
  },
 
 
 
 
 
 
 
 
802
  sev2num: function(str) {
803
  if (/wfProbSev1/.test(str)) {
804
  return 1;
@@ -869,7 +913,7 @@
869
  "bPaginate": false,
870
  "bLengthChange": false,
871
  "bAutoWidth": false,
872
- "aaData": res.issuesLists[issueStatus],
873
  "aoColumns": [
874
  {
875
  "sTitle": '<div class="th_wrapp">Severity</div>',
@@ -895,6 +939,22 @@
895
  ]
896
  });
897
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
898
  if (callback) {
899
  jQuery('#wfIssues_' + this.visibleIssuesPanel).fadeIn(500, function() {
900
  callback();
@@ -902,7 +962,6 @@
902
  } else {
903
  jQuery('#wfIssues_' + this.visibleIssuesPanel).fadeIn(500);
904
  }
905
- return true;
906
  },
907
  ajax: function(action, data, cb, cbErr, noLoading) {
908
  if (typeof(data) == 'string') {
63
  $($this.data('selector')).show();
64
  return false;
65
  });
66
+
67
+ $('.downloadLogFile').each(function() {
68
+ $(this).attr('href', WordfenceAdminVars.ajaxURL + '?action=wordfence_downloadLogFile&nonce=' + WFAD.nonce + '&logfile=' + encodeURIComponent($(this).data('logfile')));
69
+ });
70
 
71
  $('#doSendEmail').click(function() {
72
  var ticket = $('#_ticketnumber').val();
115
  jQuery('#consoleActivity').scrollTop(jQuery('#consoleActivity').prop('scrollHeight'));
116
  jQuery('#consoleScan').scrollTop(jQuery('#consoleScan').prop('scrollHeight'));
117
  this.noScanHTML = jQuery('#wfNoScanYetTmpl').tmpl().html();
118
+
119
+
120
+ var loadingIssues = true;
121
+
122
+ this.loadIssues(function() {
123
+ loadingIssues = false;
124
+ });
125
  this.startActivityLogUpdates();
126
  if (this.needTour()) {
127
  this.scanTourStart();
128
  }
129
+
130
+ var issuesWrapper = $('#wfScanIssuesWrapper');
131
+ var hasScrolled = false;
132
+ $(window).on('scroll', function() {
133
+ var win = $(this);
134
+ // console.log(win.scrollTop() + window.innerHeight, liveTrafficWrapper.outerHeight() + liveTrafficWrapper.offset().top);
135
+ var currentScrollBottom = win.scrollTop() + window.innerHeight;
136
+ var scrollThreshold = issuesWrapper.outerHeight() + issuesWrapper.offset().top;
137
+ if (hasScrolled && !loadingIssues && currentScrollBottom >= scrollThreshold) {
138
+ // console.log('infinite scroll');
139
+
140
+ loadingIssues = true;
141
+ hasScrolled = false;
142
+ var offset = $('div.wfIssue').length;
143
+ WFAD.loadMoreIssues(function() {
144
+ loadingIssues = false;
145
+ }, offset);
146
+ } else if (currentScrollBottom < scrollThreshold) {
147
+ hasScrolled = true;
148
+ // console.log('no infinite scroll');
149
+ }
150
+ });
151
  } else if (jQuery('#wordfenceMode_waf').length > 0) {
152
  if (this.needTour()) {
153
  this.tour('wfWAFTour', 'wfHeading', 'top', 'left', "Learn about Live Traffic", function() {
353
  },
354
  updateConfig: function(key, val, cb) {
355
  this.ajax('wordfence_updateConfig', {key: key, val: val}, function() {
356
+ if (cb) {
357
+ cb();
358
+ }
359
  });
360
  },
361
  tourFinish: function() {
824
  jQuery('#wfAuditJobs').empty().html("<p>You don't have any password auditing jobs in progress or completed yet.</p>");
825
  }
826
  },
827
+ loadIssues: function(callback, offset, limit) {
828
  if (this.mode != 'scan') {
829
  return;
830
  }
831
+ offset = offset || 0;
832
+ limit = limit || WordfenceAdminVars.scanIssuesPerPage;
833
  var self = this;
834
+ this.ajax('wordfence_loadIssues', {offset: offset, limit: limit}, function(res) {
835
  self.displayIssues(res, callback);
836
  });
837
  },
838
+ loadMoreIssues: function(callback, offset, limit) {
839
+ offset = offset || 0;
840
+ limit = limit || WordfenceAdminVars.scanIssuesPerPage;
841
+ var self = this;
842
+ this.ajax('wordfence_loadIssues', {offset: offset, limit: limit}, function(res) {
843
+ self.appendIssues(res.issuesLists, callback);
844
+ });
845
+ },
846
  sev2num: function(str) {
847
  if (/wfProbSev1/.test(str)) {
848
  return 1;
913
  "bPaginate": false,
914
  "bLengthChange": false,
915
  "bAutoWidth": false,
916
+ //"aaData": res.issuesLists[issueStatus],
917
  "aoColumns": [
918
  {
919
  "sTitle": '<div class="th_wrapp">Severity</div>',
939
  ]
940
  });
941
  }
942
+
943
+ this.appendIssues(res.issuesLists, callback);
944
+
945
+ return true;
946
+ },
947
+ appendIssues: function(issuesLists, callback) {
948
+ for (var issueStatus in issuesLists) {
949
+ var tableID = 'wfIssuesTable_' + issueStatus;
950
+ if (jQuery('#' + tableID).length < 1) {
951
+ //Invalid issue status
952
+ continue;
953
+ }
954
+
955
+ jQuery('#' + tableID).dataTable().fnAddData(issuesLists[issueStatus]);
956
+ }
957
+
958
  if (callback) {
959
  jQuery('#wfIssues_' + this.visibleIssuesPanel).fadeIn(500, function() {
960
  callback();
962
  } else {
963
  jQuery('#wfIssues_' + this.visibleIssuesPanel).fadeIn(500);
964
  }
 
965
  },
966
  ajax: function(action, data, cb, cbErr, noLoading) {
967
  if (typeof(data) == 'string') {
js/admin.liveTraffic.js CHANGED
@@ -356,6 +356,7 @@
356
  case 'lockedOut':
357
  return 'locked out from logging in';
358
 
 
359
  case 'blocked:wordfence':
360
  case 'blocked:wfsnrepeat':
361
  desc = self.actionDescription();
356
  case 'lockedOut':
357
  return 'locked out from logging in';
358
 
359
+ case 'blocked:waf-always':
360
  case 'blocked:wordfence':
361
  case 'blocked:wfsnrepeat':
362
  desc = self.actionDescription();
lib/GeoIP.dat CHANGED
Binary file
lib/GeoIPv6.dat CHANGED
Binary file
lib/email_newIssues.php CHANGED
@@ -42,6 +42,10 @@
42
 
43
  <?php } } } ?>
44
 
 
 
 
 
45
 
46
  <?php if(! $isPaid){ ?>
47
  <p>NOTE: You are using the free version of Wordfence. Upgrade today:</p>
42
 
43
  <?php } } } ?>
44
 
45
+ <?php if ($issuesNotShown > 0) { ?>
46
+ <p><?php echo wfUtils::pluralize($issuesNotShown, 'issue'); ?> were omitted from this email. View every issue: <a href="<?php echo $adminURL; ?>admin.php?page=Wordfence"><?php echo $adminURL; ?>admin.php?page=Wordfence</a></p>
47
+ <?php } ?>
48
+
49
 
50
  <?php if(! $isPaid){ ?>
51
  <p>NOTE: You are using the free version of Wordfence. Upgrade today:</p>
lib/menu_blockedIPs.php CHANGED
@@ -1,5 +1,5 @@
1
  <div class="wordfenceModeElem" id="wordfenceMode_blockedIPs"></div>
2
- <div class="wrap">
3
  <?php require('menuHeader.php'); ?>
4
  <?php $helpLink="http://docs.wordfence.com/en/Blocked_IPs"; $helpLabel="Learn more about Blocked IPs"; $pageTitle = "Wordfence Blocked IPs"; include('pageTitle.php'); ?>
5
  <div class="wordfenceLive">
1
  <div class="wordfenceModeElem" id="wordfenceMode_blockedIPs"></div>
2
+ <div class="wrap wordfence">
3
  <?php require('menuHeader.php'); ?>
4
  <?php $helpLink="http://docs.wordfence.com/en/Blocked_IPs"; $helpLabel="Learn more about Blocked IPs"; $pageTitle = "Wordfence Blocked IPs"; include('pageTitle.php'); ?>
5
  <div class="wordfenceLive">
lib/menu_countryBlocking.php CHANGED
@@ -5,7 +5,7 @@ require('wfBulkCountries.php');
5
  WFAD.countryMap = <?php echo json_encode($wfBulkCountries); ?>;
6
  </script>
7
  <div class="wordfenceModeElem" id="wordfenceMode_countryBlocking"></div>
8
- <div class="wrap" id="paidWrap">
9
  <?php require('menuHeader.php'); ?>
10
  <?php $pageTitle = "Block Selected Countries from Accessing your Site"; $helpLink="http://docs.wordfence.com/en/Country_blocking"; $helpLabel="Learn more about Country Blocking"; include('pageTitle.php'); ?>
11
  <?php
5
  WFAD.countryMap = <?php echo json_encode($wfBulkCountries); ?>;
6
  </script>
7
  <div class="wordfenceModeElem" id="wordfenceMode_countryBlocking"></div>
8
+ <div class="wrap wordfence" id="paidWrap">
9
  <?php require('menuHeader.php'); ?>
10
  <?php $pageTitle = "Block Selected Countries from Accessing your Site"; $helpLink="http://docs.wordfence.com/en/Country_blocking"; $helpLabel="Learn more about Country Blocking"; include('pageTitle.php'); ?>
11
  <?php
lib/menu_diagnostic.php CHANGED
@@ -19,8 +19,11 @@ $w = new wfConfig();
19
  <br clear="both"/>
20
 
21
  <?php
22
- $rightRail = new wfView('marketing/rightrail', array('additionalClasses' => 'wordfenceRightRailDiagnostics'));
23
- echo $rightRail;
 
 
 
24
  ?>
25
 
26
  <form id="wfConfigForm">
@@ -346,6 +349,43 @@ $w = new wfConfig();
346
  </table>
347
  </div>
348
  <?php endif ?>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
349
  </form>
350
  </div>
351
 
19
  <br clear="both"/>
20
 
21
  <?php
22
+ if (!isset($sendingDiagnosticEmail)) { $sendingDiagnosticEmail = false; }
23
+ if (!$sendingDiagnosticEmail) {
24
+ $rightRail = new wfView('marketing/rightrail', array('additionalClasses' => 'wordfenceRightRailDiagnostics'));
25
+ echo $rightRail;
26
+ }
27
  ?>
28
 
29
  <form id="wfConfigForm">
349
  </table>
350
  </div>
351
  <?php endif ?>
352
+ <div style="max-width: 100%; overflow: auto; padding: 1px;">
353
+ <table class="wf-table"<?php echo !empty($inEmail) ? ' border=1' : '' ?>>
354
+ <tbody class="empty-row">
355
+ <tr>
356
+ <td colspan="2"></td>
357
+ </tr>
358
+ </tbody>
359
+ <tbody class="thead">
360
+ <tr>
361
+ <th colspan="2">Log Files (Error messages from WordPress core, plugins, and themes)</th>
362
+ </tr>
363
+ </tbody>
364
+ <tbody class="thead thead-subhead" style="font-size: 85%">
365
+ <tr>
366
+ <th>File</th>
367
+ <th>Download</th>
368
+ </tr>
369
+ </tbody>
370
+ <tbody style="font-size: 85%">
371
+ <?php
372
+ $errorLogs = wfErrorLogHandler::getErrorLogs();
373
+ if (count($errorLogs) < 1): ?>
374
+ <tr>
375
+ <td colspan="2"><em>No log files found.</em></td>
376
+ </tr>
377
+ <?php else:
378
+ foreach ($errorLogs as $log => $readable): ?>
379
+ <tr>
380
+ <td style="width: 100%"><?php echo esc_html($log) . ' (' . wfUtils::formatBytes(filesize($log)) . ')'; ?></td>
381
+ <td style="white-space: nowrap; text-align: right;"><?php echo ($readable ? '<a href="#" data-logfile="' . esc_html($log) . '" class="downloadLogFile" target="_blank">Download</a>' : '<em>Requires downloading from the server directly</em>'); ?></td>
382
+ </tr>
383
+ <?php endforeach;
384
+ endif; ?>
385
+ </tbody>
386
+
387
+ </table>
388
+ </div>
389
  </form>
390
  </div>
391
 
lib/menu_options.php CHANGED
@@ -2,7 +2,7 @@
2
  $w = new wfConfig();
3
  ?>
4
  <div class="wordfenceModeElem" id="wordfenceMode_options"></div>
5
- <div class="wrap">
6
  <?php require( 'menuHeader.php' ); ?>
7
  <?php $helpLink = "http://docs.wordfence.com/en/Wordfence_options";
8
  $helpLabel = "Learn more about Wordfence Options";
@@ -271,6 +271,12 @@ $w = new wfConfig();
271
  enabled (see above), you'll get an email when an update occurs.
272
  </td>
273
  </tr>
 
 
 
 
 
 
274
  <tr>
275
  <th>Alert on critical problems</th>
276
  <td><input type="checkbox" id="alertOn_critical" class="wfConfigElem" name="alertOn_critical"
@@ -618,6 +624,14 @@ $w = new wfConfig();
618
  name="scan_exclude"><?php echo wfUtils::cleanupOneEntryPerLine($w->getHTML( 'scan_exclude' )); ?></textarea>
619
  </td>
620
  </tr>
 
 
 
 
 
 
 
 
621
  <tr>
622
  <td colspan="2">
623
  <div class="wfMarker" id="wfMarkerFirewallRules"></div>
@@ -1031,6 +1045,18 @@ $w = new wfConfig();
1031
  name="disableCodeExecutionUploads"
1032
  value="1" <?php $w->cb( 'disableCodeExecutionUploads' ); ?> /></td>
1033
  </tr>
 
 
 
 
 
 
 
 
 
 
 
 
1034
 
1035
  <tr>
1036
  <td colspan="2">
2
  $w = new wfConfig();
3
  ?>
4
  <div class="wordfenceModeElem" id="wordfenceMode_options"></div>
5
+ <div class="wrap wordfence">
6
  <?php require( 'menuHeader.php' ); ?>
7
  <?php $helpLink = "http://docs.wordfence.com/en/Wordfence_options";
8
  $helpLabel = "Learn more about Wordfence Options";
271
  enabled (see above), you'll get an email when an update occurs.
272
  </td>
273
  </tr>
274
+ <tr>
275
+ <th>Email me if Wordfence is deactivated</th>
276
+ <td><input type="checkbox" id="alertOn_wordfenceDeactivated" class="wfConfigElem" name="alertOn_wordfenceDeactivated"
277
+ value="1" <?php $w->cb( 'alertOn_wordfenceDeactivated' ); ?>/>
278
+ </td>
279
+ </tr>
280
  <tr>
281
  <th>Alert on critical problems</th>
282
  <td><input type="checkbox" id="alertOn_critical" class="wfConfigElem" name="alertOn_critical"
624
  name="scan_exclude"><?php echo wfUtils::cleanupOneEntryPerLine($w->getHTML( 'scan_exclude' )); ?></textarea>
625
  </td>
626
  </tr>
627
+ <tr>
628
+ <th>Limit the number of issues sent in the scan results email.</th>
629
+ <td>
630
+ <input type="text" name="scan_maxIssues" id="scan_maxIssues"
631
+ value="<?php $w->f( 'scan_maxIssues' ); ?>"/> 0 or empty means unlimited
632
+ issues will be sent.
633
+ </td>
634
+ </tr>
635
  <tr>
636
  <td colspan="2">
637
  <div class="wfMarker" id="wfMarkerFirewallRules"></div>
1045
  name="disableCodeExecutionUploads"
1046
  value="1" <?php $w->cb( 'disableCodeExecutionUploads' ); ?> /></td>
1047
  </tr>
1048
+ <tr class="hidden">
1049
+ <th style="vertical-align: top;">Monitor Front-end Background Requests for False Positives</th>
1050
+ <td><input type="checkbox" name="ajaxWatcherDisabled_front" id="ajaxWatcherDisabled_front" value="1" <?php $w->cb( 'ajaxWatcherDisabled_front' ); ?>></td>
1051
+ </tr>
1052
+ <tr class="hidden">
1053
+ <th style="vertical-align: top;">Monitor Admin Panel Background Requests for False Positives</th>
1054
+ <td><input type="checkbox" name="ajaxWatcherDisabled_admin" id="ajaxWatcherDisabled_admin" value="1" <?php $w->cb( 'ajaxWatcherDisabled_admin' ); ?>></td>
1055
+ </tr>
1056
+ <tr class="hidden">
1057
+ <th style="vertical-align: top;">Delay IP and Country blocking until after WordPress and plugins have loaded (only process firewall rules early)</th>
1058
+ <td><input type="checkbox" name="disableWAFIPBlocking" id="disableWAFIPBlocking" value="1" <?php $w->cb( 'disableWAFIPBlocking' ); ?>></td>
1059
+ </tr>
1060
 
1061
  <tr>
1062
  <td colspan="2">
lib/menu_passwd.php CHANGED
@@ -1,5 +1,5 @@
1
  <div class="wordfenceModeElem" id="wordfenceMode_passwd"></div>
2
- <div class="wrap" id="paidWrap">
3
  <?php require('menuHeader.php'); ?>
4
  <?php $pageTitle = "Audit the Strength of your Passwords";
5
  $helpLink = "http://docs.wordfence.com/en/Wordfence_Password_Auditing";
1
  <div class="wordfenceModeElem" id="wordfenceMode_passwd"></div>
2
+ <div class="wrap wordfence" id="paidWrap">
3
  <?php require('menuHeader.php'); ?>
4
  <?php $pageTitle = "Audit the Strength of your Passwords";
5
  $helpLink = "http://docs.wordfence.com/en/Wordfence_Password_Auditing";
lib/menu_rangeBlocking.php CHANGED
@@ -1,5 +1,5 @@
1
  <div class="wordfenceModeElem" id="wordfenceMode_rangeBlocking"></div>
2
- <div class="wrap" id="paidWrap">
3
  <?php require('menuHeader.php'); ?>
4
  <?php $helpLink="http://docs.wordfence.com/en/Advanced_Blocking"; $helpLabel="Learn more about Advanced Blocking"; $pageTitle = "Advanced Blocking"; include('pageTitle.php'); ?>
5
  <?php
1
  <div class="wordfenceModeElem" id="wordfenceMode_rangeBlocking"></div>
2
+ <div class="wrap wordfence" id="paidWrap">
3
  <?php require('menuHeader.php'); ?>
4
  <?php $helpLink="http://docs.wordfence.com/en/Advanced_Blocking"; $helpLabel="Learn more about Advanced Blocking"; $pageTitle = "Advanced Blocking"; include('pageTitle.php'); ?>
5
  <?php
lib/menu_scan.php CHANGED
@@ -163,7 +163,7 @@ $sigUpdateTime = wfConfig::get('signatureUpdateTime');
163
 
164
 
165
  </div>
166
- <div style="margin-top: 20px;">
167
  <div id="wfTabs">
168
  <a href="#" id="wfNewIssuesTab" class="wfTab2 wfTabSwitch selected" onclick="wordfenceAdmin.switchIssuesTab(this, 'new'); return false;">New Issues</a>
169
  <a href="#" class="wfTab2 wfTabSwitch" onclick="wordfenceAdmin.switchIssuesTab(this, 'ignored'); return false;">Ignored Issues</a>
163
 
164
 
165
  </div>
166
+ <div id="wfScanIssuesWrapper" style="margin-top: 20px;">
167
  <div id="wfTabs">
168
  <a href="#" id="wfNewIssuesTab" class="wfTab2 wfTabSwitch selected" onclick="wordfenceAdmin.switchIssuesTab(this, 'new'); return false;">New Issues</a>
169
  <a href="#" class="wfTab2 wfTabSwitch" onclick="wordfenceAdmin.switchIssuesTab(this, 'ignored'); return false;">Ignored Issues</a>
lib/menu_scanSchedule.php CHANGED
@@ -1,5 +1,5 @@
1
  <div class="wordfenceModeElem" id="wordfenceMode_scanScheduling"></div>
2
- <div class="wrap" id="paidWrap">
3
  <?php require('menuHeader.php'); ?>
4
  <?php $pageTitle = "Schedule when Wordfence Scans Occur"; $helpLink="http://docs.wordfence.com/en/Wordfence_scan_scheduling"; $helpLabel="Learn more about Scheduling Wordfence Scans"; include('pageTitle.php'); ?>
5
  <?php
1
  <div class="wordfenceModeElem" id="wordfenceMode_scanScheduling"></div>
2
+ <div class="wrap wordfence" id="paidWrap">
3
  <?php require('menuHeader.php'); ?>
4
  <?php $pageTitle = "Schedule when Wordfence Scans Occur"; $helpLink="http://docs.wordfence.com/en/Wordfence_scan_scheduling"; $helpLabel="Learn more about Scheduling Wordfence Scans"; include('pageTitle.php'); ?>
5
  <?php
lib/menu_sitePerf.php CHANGED
@@ -2,7 +2,7 @@
2
  $w = new wfConfig();
3
  ?>
4
  <div class="wordfenceModeElem" id="wordfenceMode_caching"></div>
5
- <div class="wrap">
6
  <?php require('menuHeader.php'); ?>
7
  <?php $pageTitle = "Your Site Performance"; $helpLink="http://docs.wordfence.com/en/Falcon_Cache"; $helpLabel="Learn more about Wordfence Caching"; include('pageTitle.php'); ?>
8
  <?php
2
  $w = new wfConfig();
3
  ?>
4
  <div class="wordfenceModeElem" id="wordfenceMode_caching"></div>
5
+ <div class="wrap wordfence">
6
  <?php require('menuHeader.php'); ?>
7
  <?php $pageTitle = "Your Site Performance"; $helpLink="http://docs.wordfence.com/en/Falcon_Cache"; $helpLabel="Learn more about Wordfence Caching"; include('pageTitle.php'); ?>
8
  <?php
lib/menu_sitePerfStats.php CHANGED
@@ -44,7 +44,7 @@
44
  }
45
  </style>
46
 
47
- <div class="wrap">
48
  <?php require('menuHeader.php'); ?>
49
  <div class="wordfence-lock-icon wordfence-icon32"><br /></div>
50
  <h2 id="wfHeading">
44
  }
45
  </style>
46
 
47
+ <div class="wrap wordfence">
48
  <?php require('menuHeader.php'); ?>
49
  <div class="wordfence-lock-icon wordfence-icon32"><br /></div>
50
  <h2 id="wfHeading">
lib/menu_twoFactor.php CHANGED
@@ -1,5 +1,5 @@
1
  <div class="wordfenceModeElem" id="wordfenceMode_twoFactor"></div>
2
- <div class="wrap" id="paidWrap">
3
  <?php require('menuHeader.php'); ?>
4
  <?php $pageTitle = "Cellphone Sign-in"; $helpLink="http://docs.wordfence.com/en/Cellphone_sign-in"; $helpLabel="Learn more about Cellphone Sign-in"; include('pageTitle.php'); ?>
5
  <?php
1
  <div class="wordfenceModeElem" id="wordfenceMode_twoFactor"></div>
2
+ <div class="wrap wordfence" id="paidWrap">
3
  <?php require('menuHeader.php'); ?>
4
  <?php $pageTitle = "Cellphone Sign-in"; $helpLink="http://docs.wordfence.com/en/Cellphone_sign-in"; $helpLabel="Learn more about Cellphone Sign-in"; include('pageTitle.php'); ?>
5
  <?php
lib/menu_waf.php CHANGED
@@ -5,7 +5,7 @@ $wafConfigURL = network_admin_url('admin.php?page=WordfenceWAF&wafAction=configu
5
  $wafRemoveURL = network_admin_url('admin.php?page=WordfenceWAF&wafAction=removeAutoPrepend');
6
  /** @var array $wafData */
7
  ?>
8
- <div class="wrap" id="paidWrap">
9
  <?php require('menuHeader.php'); ?>
10
  <?php
11
  $pageTitle = "Wordfence Web Application Firewall";
@@ -269,12 +269,17 @@ $wafRemoveURL = network_admin_url('admin.php?page=WordfenceWAF&wafAction=removeA
269
  </p>
270
  <br>
271
 
272
- <?php if (WFWAF_AUTO_PREPEND) : ?>
273
  <h2>Advanced Configuration</h2>
 
 
 
 
 
274
 
275
- <p><strong>Remove Extended Protection<a href="https://docs.wordfence.com/en/Web_Application_Firewall_FAQ#How_can_I_remove_the_firewall_setup_manually.3F" target="_blank"
 
276
  class="wfhelp"></a></strong><br>
277
-
278
  <em>If you're moving to a new host or a new installation location, you may need to temporarily disable extended protection to avoid any file not found errors. Use this action to remove the configuration changes that enable extended protection mode or you can <a href="https://docs.wordfence.com/en/Web_Application_Firewall_FAQ#How_can_I_remove_the_firewall_setup_manually.3F" target="_blank">remove them manually</a>.</em></p>
279
 
280
  <p><a href="<?php echo $wafRemoveURL; ?>" class="button button-small" id="waf-remove-extended">Remove Extended Protection</a></p>
@@ -746,6 +751,11 @@ $wafRemoveURL = network_admin_url('admin.php?page=WordfenceWAF&wafAction=removeA
746
  var disabled = this.checked ? 0 : 1;
747
  WFAD.updateConfig('ajaxWatcherDisabled_admin', disabled);
748
  })
 
 
 
 
 
749
  })(jQuery);
750
  </script>
751
 
5
  $wafRemoveURL = network_admin_url('admin.php?page=WordfenceWAF&wafAction=removeAutoPrepend');
6
  /** @var array $wafData */
7
  ?>
8
+ <div class="wrap wordfence" id="paidWrap">
9
  <?php require('menuHeader.php'); ?>
10
  <?php
11
  $pageTitle = "Wordfence Web Application Firewall";
269
  </p>
270
  <br>
271
 
 
272
  <h2>Advanced Configuration</h2>
273
+
274
+ <p id="waf-advanced-options">
275
+ <strong>Other Options</strong><br>
276
+ <label><input type="checkbox" id="waf-disable-ip-blocking" name="waf-disable-ip-blocking" value="1"<?php echo $config->getConfig('disableWAFIPBlocking') ? ' checked' : ''; ?>>Delay IP and Country blocking until after WordPress and plugins have loaded (only process firewall rules early)</label>
277
+ </p>
278
 
279
+ <?php if (WFWAF_AUTO_PREPEND) : ?>
280
+ <p><strong>Remove Extended Protection<a href="https://docs.wordfence.com/en/Web_Application_Firewall_FAQ#How_can_I_remove_the_firewall_setup_manually.3F" target="_blank"
281
  class="wfhelp"></a></strong><br>
282
+
283
  <em>If you're moving to a new host or a new installation location, you may need to temporarily disable extended protection to avoid any file not found errors. Use this action to remove the configuration changes that enable extended protection mode or you can <a href="https://docs.wordfence.com/en/Web_Application_Firewall_FAQ#How_can_I_remove_the_firewall_setup_manually.3F" target="_blank">remove them manually</a>.</em></p>
284
 
285
  <p><a href="<?php echo $wafRemoveURL; ?>" class="button button-small" id="waf-remove-extended">Remove Extended Protection</a></p>
751
  var disabled = this.checked ? 0 : 1;
752
  WFAD.updateConfig('ajaxWatcherDisabled_admin', disabled);
753
  })
754
+
755
+ $('#waf-disable-ip-blocking').on('click', function() {
756
+ var disabled = this.checked ? 1 : 0;
757
+ WFAD.updateConfig('disableWAFIPBlocking', disabled);
758
+ })
759
  })(jQuery);
760
  </script>
761
 
lib/menu_whois.php CHANGED
@@ -1,5 +1,5 @@
1
  <div class="wordfenceModeElem" id="wordfenceMode_whois"></div>
2
- <div class="wrap" id="paidWrap">
3
  <?php require('menuHeader.php'); ?>
4
  <?php $pageTitle = "WHOIS Lookup"; $helpLink="http://docs.wordfence.com/en/Whois_Lookup"; $helpLabel="Learn more about Whois Lookups"; include('pageTitle.php'); ?>
5
  <?php
1
  <div class="wordfenceModeElem" id="wordfenceMode_whois"></div>
2
+ <div class="wrap wordfence" id="paidWrap">
3
  <?php require('menuHeader.php'); ?>
4
  <?php $pageTitle = "WHOIS Lookup"; $helpLink="http://docs.wordfence.com/en/Whois_Lookup"; $helpLabel="Learn more about Whois Lookups"; include('pageTitle.php'); ?>
5
  <?php
lib/wf503.php CHANGED
@@ -5,7 +5,7 @@
5
  <h1>Your access to this site has been limited</h1>
6
  <p>Your access to this service has been temporarily limited. Please try again in a few minutes. (HTTP response code 503)</p>
7
  <p>Reason: <span style="color: #F00;"><?php echo $reason; ?></span></p>
8
- <p style="width: 600px;"><b>Important note for site admins: </b>If you are the administrator of this website note that your access has been limited because you broke one of the Wordfence firewall rules.
9
  The reason your access was limited is: <b>"<?php echo $reason; ?>"</b>.
10
  <br /><br />
11
  If this is a false positive, meaning that your access to your own site has been limited incorrectly, then you
@@ -13,7 +13,7 @@ will need to regain access to your site, go to the Wordfence "options" page, go
13
  if you were blocked because it was detected that you are a fake Google crawler, then disable the rule that blocks fake google crawlers. Or if you were blocked because you
14
  were accessing your site too quickly, then increase the number of accesses allowed per minute.
15
  <br /><br />
16
- If you're still having trouble, then simply disable the Wordfence firewall and you will
17
  still benefit from the other security features that Wordfence provides.
18
 
19
  <br /><br />
5
  <h1>Your access to this site has been limited</h1>
6
  <p>Your access to this service has been temporarily limited. Please try again in a few minutes. (HTTP response code 503)</p>
7
  <p>Reason: <span style="color: #F00;"><?php echo $reason; ?></span></p>
8
+ <p style="width: 600px;"><b>Important note for site admins: </b>If you are the administrator of this website note that your access has been limited because you broke one of the Wordfence blocking rules.
9
  The reason your access was limited is: <b>"<?php echo $reason; ?>"</b>.
10
  <br /><br />
11
  If this is a false positive, meaning that your access to your own site has been limited incorrectly, then you
13
  if you were blocked because it was detected that you are a fake Google crawler, then disable the rule that blocks fake google crawlers. Or if you were blocked because you
14
  were accessing your site too quickly, then increase the number of accesses allowed per minute.
15
  <br /><br />
16
+ If you're still having trouble, then simply disable the Wordfence advanced blocking and you will
17
  still benefit from the other security features that Wordfence provides.
18
 
19
  <br /><br />
lib/wfActivityReport.php CHANGED
@@ -190,16 +190,10 @@ class wfActivityReport {
190
  * @return mixed
191
  */
192
  public function getTopIPsBlocked($limit = 10) {
193
- $where = $this->getBlockedIPWhitelistWhereClause();
194
- if ($where) {
195
- $where = 'WHERE NOT (' . $where . ')';
196
- }
197
-
198
  $results = $this->db->get_results($this->db->prepare(<<<SQL
199
  SELECT *,
200
  SUM(blockCount) as blockCount
201
  FROM {$this->db->prefix}wfBlockedIPLog
202
- $where
203
  GROUP BY IP
204
  ORDER BY blockCount DESC
205
  LIMIT %d
@@ -218,15 +212,9 @@ SQL
218
  * @return array
219
  */
220
  public function getTopCountriesBlocked($limit = 10) {
221
- $where = $this->getBlockedIPWhitelistWhereClause();
222
- if ($where) {
223
- $where = 'WHERE NOT (' . $where . ')';
224
- }
225
-
226
  $results = $this->db->get_results($this->db->prepare(<<<SQL
227
  SELECT *, COUNT(IP) as totalIPs, SUM(blockCount) as totalBlockCount
228
  FROM {$this->db->base_prefix}wfBlockedIPLog
229
- $where
230
  GROUP BY countryCode
231
  ORDER BY totalBlockCount DESC
232
  LIMIT %d
190
  * @return mixed
191
  */
192
  public function getTopIPsBlocked($limit = 10) {
 
 
 
 
 
193
  $results = $this->db->get_results($this->db->prepare(<<<SQL
194
  SELECT *,
195
  SUM(blockCount) as blockCount
196
  FROM {$this->db->prefix}wfBlockedIPLog
 
197
  GROUP BY IP
198
  ORDER BY blockCount DESC
199
  LIMIT %d
212
  * @return array
213
  */
214
  public function getTopCountriesBlocked($limit = 10) {
 
 
 
 
 
215
  $results = $this->db->get_results($this->db->prepare(<<<SQL
216
  SELECT *, COUNT(IP) as totalIPs, SUM(blockCount) as totalBlockCount
217
  FROM {$this->db->base_prefix}wfBlockedIPLog
 
218
  GROUP BY countryCode
219
  ORDER BY totalBlockCount DESC
220
  LIMIT %d
lib/wfConfig.php CHANGED
@@ -25,8 +25,8 @@ class wfConfig {
25
  "alertOn_firstAdminLoginOnly" => array('value' => false, 'autoload' => self::AUTOLOAD),
26
  "alertOn_nonAdminLogin" => array('value' => false, 'autoload' => self::AUTOLOAD),
27
  "alertOn_firstNonAdminLoginOnly" => array('value' => false, 'autoload' => self::AUTOLOAD),
 
28
  "liveTrafficEnabled" => array('value' => true, 'autoload' => self::AUTOLOAD),
29
- "scansEnabled_checkReadableConfig" => array('value' => true, 'autoload' => self::AUTOLOAD),
30
  "advancedCommentScanning" => array('value' => false, 'autoload' => self::AUTOLOAD),
31
  "checkSpamIP" => array('value' => false, 'autoload' => self::AUTOLOAD),
32
  "spamvertizeCheck" => array('value' => false, 'autoload' => self::AUTOLOAD),
@@ -42,6 +42,7 @@ class wfConfig {
42
  "scansEnabled_coreUnknown" => array('value' => true, 'autoload' => self::AUTOLOAD),
43
  "scansEnabled_malware" => array('value' => true, 'autoload' => self::AUTOLOAD),
44
  "scansEnabled_fileContents" => array('value' => true, 'autoload' => self::AUTOLOAD),
 
45
  "scansEnabled_suspectedFiles" => array('value' => true, 'autoload' => self::AUTOLOAD),
46
  "scansEnabled_posts" => array('value' => true, 'autoload' => self::AUTOLOAD),
47
  "scansEnabled_comments" => array('value' => true, 'autoload' => self::AUTOLOAD),
@@ -86,11 +87,12 @@ class wfConfig {
86
  'ajaxWatcherDisabled_front' => array('value' => false, 'autoload' => self::AUTOLOAD),
87
  'ajaxWatcherDisabled_admin' => array('value' => false, 'autoload' => self::AUTOLOAD),
88
  'wafAlertOnAttacks' => array('value' => true, 'autoload' => self::AUTOLOAD),
 
89
  ),
90
  "otherParams" => array(
91
  "scan_include_extra" => "",
92
  // 'securityLevel' => '2',
93
- "alertEmails" => "", "liveTraf_ignoreUsers" => "", "liveTraf_ignoreIPs" => "", "liveTraf_ignoreUA" => "", "apiKey" => "", "maxMem" => '256', 'scan_exclude' => '', 'whitelisted' => '', 'bannedURLs' => '', 'maxExecutionTime' => '', 'howGetIPs' => '', 'actUpdateInterval' => '', 'alert_maxHourly' => 0, 'loginSec_userBlacklist' => '',
94
  'liveTraf_maxRows' => 2000,
95
  "neverBlockBG" => "neverBlockVerified",
96
  "loginSec_countFailMins" => "240",
@@ -282,12 +284,16 @@ class wfConfig {
282
 
283
  if (!self::$tableExists) {
284
  return;
285
- }
286
 
 
287
  $table = self::table();
288
  if ($wpdb->query($wpdb->prepare("INSERT INTO {$table} (name, val, autoload) values (%s, %s, %s) ON DUPLICATE KEY UPDATE val = %s, autoload = %s", $key, $val, $autoload, $val, $autoload)) !== false && $autoload != self::DONT_AUTOLOAD) {
289
  self::updateCachedOption($key, $val);
290
  }
 
 
 
 
291
  }
292
  public static function get($key, $default = false) {
293
  global $wpdb;
25
  "alertOn_firstAdminLoginOnly" => array('value' => false, 'autoload' => self::AUTOLOAD),
26
  "alertOn_nonAdminLogin" => array('value' => false, 'autoload' => self::AUTOLOAD),
27
  "alertOn_firstNonAdminLoginOnly" => array('value' => false, 'autoload' => self::AUTOLOAD),
28
+ "alertOn_wordfenceDeactivated" => array('value' => true, 'autoload' => self::AUTOLOAD),
29
  "liveTrafficEnabled" => array('value' => true, 'autoload' => self::AUTOLOAD),
 
30
  "advancedCommentScanning" => array('value' => false, 'autoload' => self::AUTOLOAD),
31
  "checkSpamIP" => array('value' => false, 'autoload' => self::AUTOLOAD),
32
  "spamvertizeCheck" => array('value' => false, 'autoload' => self::AUTOLOAD),
42
  "scansEnabled_coreUnknown" => array('value' => true, 'autoload' => self::AUTOLOAD),
43
  "scansEnabled_malware" => array('value' => true, 'autoload' => self::AUTOLOAD),
44
  "scansEnabled_fileContents" => array('value' => true, 'autoload' => self::AUTOLOAD),
45
+ "scansEnabled_checkReadableConfig" => array('value' => true, 'autoload' => self::AUTOLOAD),
46
  "scansEnabled_suspectedFiles" => array('value' => true, 'autoload' => self::AUTOLOAD),
47
  "scansEnabled_posts" => array('value' => true, 'autoload' => self::AUTOLOAD),
48
  "scansEnabled_comments" => array('value' => true, 'autoload' => self::AUTOLOAD),
87
  'ajaxWatcherDisabled_front' => array('value' => false, 'autoload' => self::AUTOLOAD),
88
  'ajaxWatcherDisabled_admin' => array('value' => false, 'autoload' => self::AUTOLOAD),
89
  'wafAlertOnAttacks' => array('value' => true, 'autoload' => self::AUTOLOAD),
90
+ 'disableWAFIPBlocking' => array('value' => false, 'autoload' => self::AUTOLOAD),
91
  ),
92
  "otherParams" => array(
93
  "scan_include_extra" => "",
94
  // 'securityLevel' => '2',
95
+ "alertEmails" => "", "liveTraf_ignoreUsers" => "", "liveTraf_ignoreIPs" => "", "liveTraf_ignoreUA" => "", "apiKey" => "", "maxMem" => '256', 'scan_exclude' => '', 'scan_maxIssues' => 1000, 'whitelisted' => '', 'bannedURLs' => '', 'maxExecutionTime' => '', 'howGetIPs' => '', 'actUpdateInterval' => '', 'alert_maxHourly' => 0, 'loginSec_userBlacklist' => '',
96
  'liveTraf_maxRows' => 2000,
97
  "neverBlockBG" => "neverBlockVerified",
98
  "loginSec_countFailMins" => "240",
284
 
285
  if (!self::$tableExists) {
286
  return;
 
287
 
288
+ }
289
  $table = self::table();
290
  if ($wpdb->query($wpdb->prepare("INSERT INTO {$table} (name, val, autoload) values (%s, %s, %s) ON DUPLICATE KEY UPDATE val = %s, autoload = %s", $key, $val, $autoload, $val, $autoload)) !== false && $autoload != self::DONT_AUTOLOAD) {
291
  self::updateCachedOption($key, $val);
292
  }
293
+
294
+ if (!WFWAF_SUBDIRECTORY_INSTALL && class_exists('wfWAFIPBlocksController') && (substr($key, 0, 4) == 'cbl_' || $key == 'blockedTime' || $key == 'disableWAFIPBlocking')) {
295
+ wfWAFIPBlocksController::synchronizeConfigSettings();
296
+ }
297
  }
298
  public static function get($key, $default = false) {
299
  global $wpdb;
lib/wfIPWhitelist.php CHANGED
@@ -30,6 +30,7 @@ $wfIPWhitelist = array(
30
  '69.46.36.8/29',
31
  '69.46.36.16/28',
32
  '69.46.36.32/32',
 
33
  ),
34
  'sucuri' => array(
35
  '97.74.127.171',
@@ -221,4 +222,156 @@ $wfIPWhitelist = array(
221
  '69.162.124.224/28',
222
  '63.143.42.240/28',
223
  ),
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
224
  );
30
  '69.46.36.8/29',
31
  '69.46.36.16/28',
32
  '69.46.36.32/32',
33
+ '68.64.48.0/27',
34
  ),
35
  'sucuri' => array(
36
  '97.74.127.171',
222
  '69.162.124.224/28',
223
  '63.143.42.240/28',
224
  ),
225
+ 'statuscake' => array(
226
+ '103.194.112.70',
227
+ '104.131.247.151',
228
+ '104.131.248.65',
229
+ '104.131.248.78',
230
+ '104.156.229.24',
231
+ '104.156.255.184',
232
+ '104.206.168.26',
233
+ '104.238.164.105',
234
+ '107.150.1.135',
235
+ '107.155.104.182',
236
+ '107.155.108.234',
237
+ '107.155.125.29',
238
+ '107.161.28.219',
239
+ '107.170.197.248',
240
+ '107.170.219.46',
241
+ '107.170.227.23',
242
+ '107.170.227.24',
243
+ '107.170.240.141',
244
+ '107.170.53.191',
245
+ '107.191.47.131',
246
+ '107.191.57.237',
247
+ '108.61.119.153',
248
+ '108.61.162.214',
249
+ '108.61.205.201',
250
+ '108.61.212.141',
251
+ '108.61.215.179',
252
+ '125.63.48.239',
253
+ '128.199.222.65',
254
+ '138.197.130.232',
255
+ '138.197.130.235',
256
+ '138.197.140.243',
257
+ '138.204.171.136',
258
+ '138.68.24.115',
259
+ '138.68.24.136',
260
+ '138.68.24.207',
261
+ '138.68.24.60',
262
+ '138.68.80.10',
263
+ '138.68.80.173',
264
+ '139.59.15.79',
265
+ '139.59.155.26',
266
+ '139.59.190.241',
267
+ '139.59.22.109',
268
+ '139.59.26.85',
269
+ '139.59.29.167',
270
+ '149.154.157.61',
271
+ '149.255.59.100',
272
+ '151.236.10.238',
273
+ '151.236.18.80',
274
+ '151.80.175.223',
275
+ '151.80.175.226',
276
+ '154.127.60.23',
277
+ '154.127.60.59',
278
+ '158.255.208.76',
279
+ '159.203.182.22',
280
+ '159.203.182.60',
281
+ '159.203.186.225',
282
+ '159.203.31.18',
283
+ '162.243.247.163',
284
+ '162.243.71.56',
285
+ '162.248.97.72',
286
+ '162.253.64.104',
287
+ '162.253.64.87',
288
+ '176.56.230.110',
289
+ '178.62.101.57',
290
+ '178.62.104.137',
291
+ '178.62.106.84',
292
+ '178.62.109.7',
293
+ '178.62.40.233',
294
+ '178.62.41.44',
295
+ '178.62.41.49',
296
+ '178.62.41.52',
297
+ '178.62.65.162',
298
+ '178.62.71.227',
299
+ '178.62.78.199',
300
+ '178.62.80.93',
301
+ '178.62.86.69',
302
+ '178.73.210.99',
303
+ '181.41.201.117',
304
+ '181.41.214.137',
305
+ '185.112.157.185',
306
+ '185.12.45.70',
307
+ '185.47.129.168',
308
+ '185.60.135.86',
309
+ '188.166.158.224',
310
+ '188.166.253.148',
311
+ '188.226.139.158',
312
+ '188.226.158.160',
313
+ '188.226.169.228',
314
+ '188.226.171.58',
315
+ '188.226.184.152',
316
+ '188.226.185.106',
317
+ '188.226.186.199',
318
+ '188.226.203.84',
319
+ '188.226.247.184',
320
+ '188.68.238.79',
321
+ '192.241.221.11',
322
+ '193.124.178.54',
323
+ '193.124.178.61',
324
+ '193.182.144.105',
325
+ '193.182.144.147',
326
+ '199.167.128.80',
327
+ '209.222.30.242',
328
+ '213.183.56.107',
329
+ '217.148.43.188',
330
+ '217.148.43.202',
331
+ '31.220.7.237',
332
+ '37.157.246.146',
333
+ '37.235.48.42',
334
+ '37.235.52.25',
335
+ '37.235.53.240',
336
+ '37.235.55.205',
337
+ '37.97.188.103',
338
+ '45.32.128.80',
339
+ '45.32.145.79',
340
+ '45.32.151.21',
341
+ '45.32.160.172',
342
+ '45.32.166.195',
343
+ '45.32.171.24',
344
+ '45.32.192.198',
345
+ '45.32.195.186',
346
+ '45.32.195.93',
347
+ '45.32.212.56',
348
+ '45.32.36.158',
349
+ '45.32.7.22',
350
+ '45.63.121.159',
351
+ '45.63.26.78',
352
+ '45.63.51.63',
353
+ '45.63.61.213',
354
+ '45.63.76.68',
355
+ '45.63.78.84',
356
+ '45.63.86.120',
357
+ '45.63.88.213',
358
+ '45.76.1.44',
359
+ '45.76.192.50',
360
+ '45.76.3.112',
361
+ '46.101.0.24',
362
+ '46.101.110.32',
363
+ '46.101.110.43',
364
+ '46.101.110.45',
365
+ '46.101.20.96',
366
+ '46.101.238.182',
367
+ '46.101.238.189',
368
+ '46.101.240.208',
369
+ '46.101.27.186',
370
+ '46.101.61.83',
371
+ '46.101.74.251',
372
+ '5.45.179.103',
373
+ '50.2.139.16',
374
+ '82.221.95.161',
375
+ '91.236.116.163',
376
+ ),
377
  );
lib/wfIssues.php CHANGED
@@ -6,16 +6,18 @@ class wfIssues {
6
  //Properties that are serialized on sleep:
7
  private $updateCalled = false;
8
  private $issuesTable = '';
 
9
  private $newIssues = array();
10
  public $totalIssues = 0;
11
  public $totalCriticalIssues = 0;
12
  public $totalWarningIssues = 0;
13
  public function __sleep(){ //Same order here as vars above
14
- return array('updateCalled', 'issuesTable', 'newIssues', 'totalIssues', 'totalCriticalIssues', 'totalWarningIssues');
15
  }
16
  public function __construct(){
17
  global $wpdb;
18
  $this->issuesTable = $wpdb->base_prefix . 'wfIssues';
 
19
  }
20
  public function __wakeup(){
21
  $this->db = new wfDB();
@@ -48,15 +50,18 @@ class wfIssues {
48
  $this->totalWarningIssues++;
49
  }
50
  $this->totalIssues++;
51
- $this->newIssues[] = array(
52
- 'type' => $type,
53
- 'severity' => $severity,
54
- 'ignoreP' => $ignoreP,
55
- 'ignoreC' => $ignoreC,
56
- 'shortMsg' => $shortMsg,
57
- 'longMsg' => $longMsg,
58
- 'tmplData' => $templateData
59
- );
 
 
 
60
 
61
  $this->getDB()->queryWrite("insert into " . $this->issuesTable . " (time, status, type, severity, ignoreP, ignoreC, shortMsg, longMsg, data) values (unix_timestamp(), '%s', '%s', %d, '%s', '%s', '%s', '%s', '%s')",
62
  'new',
@@ -93,6 +98,7 @@ class wfIssues {
93
  if(! is_array($emailedIssues)){
94
  $emailedIssues = array();
95
  }
 
96
  $finalIssues = array();
97
  foreach($this->newIssues as $newIssue){
98
  $alreadyEmailed = false;
@@ -105,8 +111,14 @@ class wfIssues {
105
  if(! $alreadyEmailed){
106
  $finalIssues[] = $newIssue;
107
  }
 
 
 
108
  }
109
  if(sizeof($finalIssues) < 1){ return; }
 
 
 
110
 
111
  $totalWarningIssues = 0;
112
  $totalCriticalIssues = 0;
@@ -126,7 +138,9 @@ class wfIssues {
126
  'issues' => $finalIssues,
127
  'totalCriticalIssues' => $totalCriticalIssues,
128
  'totalWarningIssues' => $totalWarningIssues,
129
- 'level' => $level
 
 
130
  ));
131
 
132
  wp_mail(implode(',', $emails), $subject, $content, 'Content-type: text/html');
@@ -146,7 +160,7 @@ class wfIssues {
146
  $rec['data'] = unserialize($rec['data']);
147
  return $rec;
148
  }
149
- public function getIssues(){
150
  /** @var wpdb $wpdb */
151
  global $wpdb;
152
  $ret = array(
@@ -154,7 +168,7 @@ class wfIssues {
154
  'ignored' => array()
155
  );
156
  $userIni = ini_get('user_ini.filename');
157
- $q1 = $this->getDB()->querySelect("select * from " . $this->issuesTable . " order by time desc");
158
  foreach($q1 as $i){
159
  $i['data'] = unserialize($i['data']);
160
  $i['timeAgo'] = wfUtils::makeTimeAgo(time() - $i['time']);
6
  //Properties that are serialized on sleep:
7
  private $updateCalled = false;
8
  private $issuesTable = '';
9
+ private $maxIssues = 0;
10
  private $newIssues = array();
11
  public $totalIssues = 0;
12
  public $totalCriticalIssues = 0;
13
  public $totalWarningIssues = 0;
14
  public function __sleep(){ //Same order here as vars above
15
+ return array('updateCalled', 'issuesTable', 'maxIssues', 'newIssues', 'totalIssues', 'totalCriticalIssues', 'totalWarningIssues');
16
  }
17
  public function __construct(){
18
  global $wpdb;
19
  $this->issuesTable = $wpdb->base_prefix . 'wfIssues';
20
+ $this->maxIssues = wfConfig::get('scan_maxIssues', 0);
21
  }
22
  public function __wakeup(){
23
  $this->db = new wfDB();
50
  $this->totalWarningIssues++;
51
  }
52
  $this->totalIssues++;
53
+ if (empty($this->maxIssues) || $this->totalIssues <= $this->maxIssues)
54
+ {
55
+ $this->newIssues[] = array(
56
+ 'type' => $type,
57
+ 'severity' => $severity,
58
+ 'ignoreP' => $ignoreP,
59
+ 'ignoreC' => $ignoreC,
60
+ 'shortMsg' => $shortMsg,
61
+ 'longMsg' => $longMsg,
62
+ 'tmplData' => $templateData
63
+ );
64
+ }
65
 
66
  $this->getDB()->queryWrite("insert into " . $this->issuesTable . " (time, status, type, severity, ignoreP, ignoreC, shortMsg, longMsg, data) values (unix_timestamp(), '%s', '%s', %d, '%s', '%s', '%s', '%s', '%s')",
67
  'new',
98
  if(! is_array($emailedIssues)){
99
  $emailedIssues = array();
100
  }
101
+ $overflowCount = $this->totalIssues - count($this->newIssues);
102
  $finalIssues = array();
103
  foreach($this->newIssues as $newIssue){
104
  $alreadyEmailed = false;
111
  if(! $alreadyEmailed){
112
  $finalIssues[] = $newIssue;
113
  }
114
+ else {
115
+ $overflowCount--;
116
+ }
117
  }
118
  if(sizeof($finalIssues) < 1){ return; }
119
+
120
+ $this->newIssues = array();
121
+ $this->totalIssues = 0;
122
 
123
  $totalWarningIssues = 0;
124
  $totalCriticalIssues = 0;
138
  'issues' => $finalIssues,
139
  'totalCriticalIssues' => $totalCriticalIssues,
140
  'totalWarningIssues' => $totalWarningIssues,
141
+ 'level' => $level,
142
+ 'issuesNotShown' => $overflowCount,
143
+ 'adminURL' => get_admin_url(),
144
  ));
145
 
146
  wp_mail(implode(',', $emails), $subject, $content, 'Content-type: text/html');
160
  $rec['data'] = unserialize($rec['data']);
161
  return $rec;
162
  }
163
+ public function getIssues($offset = 0, $limit = 100){
164
  /** @var wpdb $wpdb */
165
  global $wpdb;
166
  $ret = array(
168
  'ignored' => array()
169
  );
170
  $userIni = ini_get('user_ini.filename');
171
+ $q1 = $this->getDB()->querySelect("select * from " . $this->issuesTable . " order by time desc LIMIT %d,%d", $offset, $limit);
172
  foreach($q1 as $i){
173
  $i['data'] = unserialize($i['data']);
174
  $i['timeAgo'] = wfUtils::makeTimeAgo(time() - $i['time']);
lib/wfLog.php CHANGED
@@ -304,17 +304,33 @@ class wfLog {
304
  public function unblockAllIPs(){
305
  $this->getDB()->queryWrite("delete from " . $this->blocksTable);
306
  wfCache::updateBlockedIPs('add');
 
 
 
 
307
  }
308
  public function unlockAllIPs(){
309
  $this->getDB()->queryWrite("delete from " . $this->lockOutTable);
 
 
 
 
310
  }
311
  public function unblockIP($IP){
312
  $this->getDB()->queryWrite("delete from " . $this->blocksTable . " where IP=%s", wfUtils::inet_pton($IP));
313
  wfCache::updateBlockedIPs('add');
 
 
 
 
314
  }
315
  public function unblockRange($id){
316
  $this->getDB()->queryWrite("delete from " . $this->ipRangesTable . " where id=%d", $id);
317
  wfCache::updateBlockedIPs('add');
 
 
 
 
318
  }
319
 
320
  /**
@@ -328,6 +344,11 @@ class wfLog {
328
  $reason = stripslashes($reason);
329
  $this->getDB()->queryWrite("insert IGNORE into " . $this->ipRangesTable . " (blockType, blockString, ctime, reason, totalBlocked, lastBlocked) values ('%s', '%s', unix_timestamp(), '%s', 0, 0)", $blockType, $range, $reason);
330
  wfCache::updateBlockedIPs('add');
 
 
 
 
 
331
  return true;
332
  }
333
  public function getRangesBasic(){
@@ -430,6 +451,11 @@ class wfLog {
430
 
431
  wfCache::updateBlockedIPs('add');
432
  wfConfig::inc('totalIPsBlocked');
 
 
 
 
 
433
  return true;
434
  }
435
  public function lockOutIP($IP, $reason){
@@ -450,10 +476,19 @@ class wfLog {
450
  }
451
 
452
  wfConfig::inc('totalIPsLocked');
 
 
 
 
 
453
  return true;
454
  }
455
  public function unlockOutIP($IP){
456
  $this->getDB()->queryWrite("delete from " . $this->lockOutTable . " where IP=%s", wfUtils::inet_pton($IP));
 
 
 
 
457
  }
458
  public function isIPLockedOut($IP){
459
  if($this->getDB()->querySingle("select IP from " . $this->lockOutTable . " where IP=%s and blockedTime + %s > unix_timestamp()", wfUtils::inet_pton($IP), wfConfig::get('loginSec_lockoutMins') * 60)){
@@ -1030,7 +1065,7 @@ class wfLog {
1030
  $hasRun = true;
1031
 
1032
  $blockedCountries = wfConfig::get('cbl_countries', false);
1033
- $bareRequestURI = wfUtils::extractBareURI($_SERVER['REQUEST_URI']);
1034
  $IP = wfUtils::getIP();
1035
  if($country = wfUtils::IP2Country($IP) ){
1036
  foreach(explode(',', $blockedCountries) as $blocked){
@@ -1042,7 +1077,7 @@ class wfLog {
1042
  if($eRedirHost && $eRedirHost != wfUtils::extractHostname(home_url())){ //It's an external redirect...
1043
  $isExternalRedir = true;
1044
  }
1045
- if( (! $isExternalRedir) && wfUtils::extractBareURI($redirURL) == $bareRequestURI){ //Is this the URI we want to redirect to, then don't block it
1046
  //Do nothing
1047
  /* Uncomment the following if page components aren't loading for the page we redirect to.
1048
  Uncommenting is not recommended because it means that anyone from a blocked country
@@ -1052,11 +1087,24 @@ class wfLog {
1052
  //Do nothing
1053
  */
1054
  } else {
 
 
 
 
 
 
 
 
 
 
 
 
1055
  $this->redirect(wfConfig::get('cbl_redirURL'));
1056
  }
1057
  } else {
1058
  $this->currentRequest->actionDescription = 'blocked access via country blocking';
1059
  wfConfig::inc('totalCountryBlocked');
 
1060
  $this->do503(3600, "Access from your area has been temporarily limited for security reasons");
1061
  }
1062
  }
@@ -1233,6 +1281,15 @@ class wfUserIPRange {
1233
 
1234
  // IPv4 range
1235
  if (strpos($ip_string, '.') !== false && strpos($ip, '.') !== false) {
 
 
 
 
 
 
 
 
 
1236
  if (preg_match('/\[\d+\-\d+\]/', $ip_string)) {
1237
  $IPparts = explode('.', $ip);
1238
  $whiteParts = explode('.', $ip_string);
@@ -1314,23 +1371,26 @@ class wfUserIPRange {
1314
  $sql = substr($sql, 0, -5) . ')';
1315
  return $sql;
1316
 
1317
- } else if (strpos($ip_string, ':') !== false && preg_match('/\[[a-f0-9]+\-[a-f0-9]+\]/', $ip_string)) {
1318
- $whiteParts = explode(':', strtolower(self::expandIPv6Range($ip_string)));
1319
- $sql = '(';
1320
-
1321
- for ($i = 0; $i <= 7; $i++) {
1322
- // MySQL can only perform bitwise operations on integers
1323
- $conv = sprintf('CAST(CONV(HEX(SUBSTR(%s, %d, 8)), 16, 10) as UNSIGNED INTEGER)', $column, $i < 4 ? 1 : 9);
1324
- $j = 16 * (3 - ($i % 4));
1325
- if (preg_match('/^\[([a-f0-9]+)\-([a-f0-9]+)\]$/', $whiteParts[$i], $m)) {
1326
- $sql .= $wpdb->prepare("$conv >> $j & 0xFFFF BETWEEN 0x%x AND 0x%x", hexdec($m[1]), hexdec($m[2]));
1327
- } else {
1328
- $sql .= $wpdb->prepare("$conv >> $j & 0xFFFF = 0x%x", hexdec($whiteParts[$i]));
 
 
 
 
1329
  }
1330
- $sql .= ' AND ';
 
1331
  }
1332
- $sql = substr($sql, 0, -5) . ')';
1333
- return $sql;
1334
  }
1335
  return $wpdb->prepare("($column = %s)", wfUtils::inet_pton($ip_string));
1336
  }
@@ -1427,7 +1487,7 @@ class wfUserIPRange {
1427
  * @param string|null $ip_string
1428
  */
1429
  public function setIPString($ip_string) {
1430
- $this->ip_string = preg_replace('/[\x{2013}-\x{2015}]/u', '-', $ip_string); //Replace em-dash, en-dash, and horizontal bar with a regular dash
1431
  }
1432
  }
1433
 
@@ -2264,3 +2324,100 @@ class wfLiveTrafficQueryGroupBy {
2264
  class wfLiveTrafficQueryException extends Exception {
2265
 
2266
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
304
  public function unblockAllIPs(){
305
  $this->getDB()->queryWrite("delete from " . $this->blocksTable);
306
  wfCache::updateBlockedIPs('add');
307
+
308
+ if (!WFWAF_SUBDIRECTORY_INSTALL && class_exists('wfWAFIPBlocksController')) {
309
+ wfWAFIPBlocksController::synchronizeConfigSettings();
310
+ }
311
  }
312
  public function unlockAllIPs(){
313
  $this->getDB()->queryWrite("delete from " . $this->lockOutTable);
314
+
315
+ if (!WFWAF_SUBDIRECTORY_INSTALL && class_exists('wfWAFIPBlocksController')) {
316
+ wfWAFIPBlocksController::synchronizeConfigSettings();
317
+ }
318
  }
319
  public function unblockIP($IP){
320
  $this->getDB()->queryWrite("delete from " . $this->blocksTable . " where IP=%s", wfUtils::inet_pton($IP));
321
  wfCache::updateBlockedIPs('add');
322
+
323
+ if (!WFWAF_SUBDIRECTORY_INSTALL && class_exists('wfWAFIPBlocksController')) {
324
+ wfWAFIPBlocksController::synchronizeConfigSettings();
325
+ }
326
  }
327
  public function unblockRange($id){
328
  $this->getDB()->queryWrite("delete from " . $this->ipRangesTable . " where id=%d", $id);
329
  wfCache::updateBlockedIPs('add');
330
+
331
+ if (!WFWAF_SUBDIRECTORY_INSTALL && class_exists('wfWAFIPBlocksController')) {
332
+ wfWAFIPBlocksController::synchronizeConfigSettings();
333
+ }
334
  }
335
 
336
  /**
344
  $reason = stripslashes($reason);
345
  $this->getDB()->queryWrite("insert IGNORE into " . $this->ipRangesTable . " (blockType, blockString, ctime, reason, totalBlocked, lastBlocked) values ('%s', '%s', unix_timestamp(), '%s', 0, 0)", $blockType, $range, $reason);
346
  wfCache::updateBlockedIPs('add');
347
+
348
+ if (!WFWAF_SUBDIRECTORY_INSTALL && class_exists('wfWAFIPBlocksController')) {
349
+ wfWAFIPBlocksController::synchronizeConfigSettings();
350
+ }
351
+
352
  return true;
353
  }
354
  public function getRangesBasic(){
451
 
452
  wfCache::updateBlockedIPs('add');
453
  wfConfig::inc('totalIPsBlocked');
454
+
455
+ if (!WFWAF_SUBDIRECTORY_INSTALL && class_exists('wfWAFIPBlocksController')) {
456
+ wfWAFIPBlocksController::synchronizeConfigSettings();
457
+ }
458
+
459
  return true;
460
  }
461
  public function lockOutIP($IP, $reason){
476
  }
477
 
478
  wfConfig::inc('totalIPsLocked');
479
+
480
+ if (!WFWAF_SUBDIRECTORY_INSTALL && class_exists('wfWAFIPBlocksController')) {
481
+ wfWAFIPBlocksController::synchronizeConfigSettings();
482
+ }
483
+
484
  return true;
485
  }
486
  public function unlockOutIP($IP){
487
  $this->getDB()->queryWrite("delete from " . $this->lockOutTable . " where IP=%s", wfUtils::inet_pton($IP));
488
+
489
+ if (!WFWAF_SUBDIRECTORY_INSTALL && class_exists('wfWAFIPBlocksController')) {
490
+ wfWAFIPBlocksController::synchronizeConfigSettings();
491
+ }
492
  }
493
  public function isIPLockedOut($IP){
494
  if($this->getDB()->querySingle("select IP from " . $this->lockOutTable . " where IP=%s and blockedTime + %s > unix_timestamp()", wfUtils::inet_pton($IP), wfConfig::get('loginSec_lockoutMins') * 60)){
1065
  $hasRun = true;
1066
 
1067
  $blockedCountries = wfConfig::get('cbl_countries', false);
1068
+ $bareRequestURI = untrailingslashit(wfUtils::extractBareURI($_SERVER['REQUEST_URI']));
1069
  $IP = wfUtils::getIP();
1070
  if($country = wfUtils::IP2Country($IP) ){
1071
  foreach(explode(',', $blockedCountries) as $blocked){
1077
  if($eRedirHost && $eRedirHost != wfUtils::extractHostname(home_url())){ //It's an external redirect...
1078
  $isExternalRedir = true;
1079
  }
1080
+ if( (! $isExternalRedir) && untrailingslashit(wfUtils::extractBareURI($redirURL)) == $bareRequestURI){ //Is this the URI we want to redirect to, then don't block it
1081
  //Do nothing
1082
  /* Uncomment the following if page components aren't loading for the page we redirect to.
1083
  Uncommenting is not recommended because it means that anyone from a blocked country
1087
  //Do nothing
1088
  */
1089
  } else {
1090
+ wfConfig::inc('totalCountryBlocked');
1091
+
1092
+ $this->initLogRequest();
1093
+ $this->currentRequest->actionDescription = 'blocked access via country blocking and redirected to URL (' . wfConfig::get('cbl_redirURL') . ')';
1094
+ $this->currentRequest->statusCode = 503;
1095
+ if (!$this->currentRequest->action) {
1096
+ $this->currentRequest->action = 'blocked:wordfence';
1097
+ }
1098
+ $this->logHit();
1099
+
1100
+ wfActivityReport::logBlockedIP($IP);
1101
+
1102
  $this->redirect(wfConfig::get('cbl_redirURL'));
1103
  }
1104
  } else {
1105
  $this->currentRequest->actionDescription = 'blocked access via country blocking';
1106
  wfConfig::inc('totalCountryBlocked');
1107
+ wfActivityReport::logBlockedIP($IP);
1108
  $this->do503(3600, "Access from your area has been temporarily limited for security reasons");
1109
  }
1110
  }
1281
 
1282
  // IPv4 range
1283
  if (strpos($ip_string, '.') !== false && strpos($ip, '.') !== false) {
1284
+ // IPv4-mapped-IPv6
1285
+ if (preg_match('/:ffff:([^:]+)$/i', $ip_string, $matches)) {
1286
+ $ip_string = $matches[1];
1287
+ }
1288
+ if (preg_match('/:ffff:([^:]+)$/i', $ip, $matches)) {
1289
+ $ip = $matches[1];
1290
+ }
1291
+
1292
+ // Range check
1293
  if (preg_match('/\[\d+\-\d+\]/', $ip_string)) {
1294
  $IPparts = explode('.', $ip);
1295
  $whiteParts = explode('.', $ip_string);
1371
  $sql = substr($sql, 0, -5) . ')';
1372
  return $sql;
1373
 
1374
+ } else if (strpos($ip_string, ':') !== false) {
1375
+ $ip_string = strtolower(self::expandIPv6Range($ip_string));
1376
+ if (preg_match('/\[[a-f0-9]+\-[a-f0-9]+\]/i', $ip_string)) {
1377
+ $whiteParts = explode(':', $ip_string);
1378
+ $sql = '(';
1379
+
1380
+ for ($i = 0; $i <= 7; $i++) {
1381
+ // MySQL can only perform bitwise operations on integers
1382
+ $conv = sprintf('CAST(CONV(HEX(SUBSTR(%s, %d, 8)), 16, 10) as UNSIGNED INTEGER)', $column, $i < 4 ? 1 : 9);
1383
+ $j = 16 * (3 - ($i % 4));
1384
+ if (preg_match('/^\[([a-f0-9]+)\-([a-f0-9]+)\]$/i', $whiteParts[$i], $m)) {
1385
+ $sql .= $wpdb->prepare("$conv >> $j & 0xFFFF BETWEEN 0x%x AND 0x%x", hexdec($m[1]), hexdec($m[2]));
1386
+ } else {
1387
+ $sql .= $wpdb->prepare("$conv >> $j & 0xFFFF = 0x%x", hexdec($whiteParts[$i]));
1388
+ }
1389
+ $sql .= ' AND ';
1390
  }
1391
+ $sql = substr($sql, 0, -5) . ')';
1392
+ return $sql;
1393
  }
 
 
1394
  }
1395
  return $wpdb->prepare("($column = %s)", wfUtils::inet_pton($ip_string));
1396
  }
1487
  * @param string|null $ip_string
1488
  */
1489
  public function setIPString($ip_string) {
1490
+ $this->ip_string = strtolower(preg_replace('/[\x{2013}-\x{2015}]/u', '-', $ip_string)); //Replace em-dash, en-dash, and horizontal bar with a regular dash
1491
  }
1492
  }
1493
 
2324
  class wfLiveTrafficQueryException extends Exception {
2325
 
2326
  }
2327
+
2328
+ class wfErrorLogHandler {
2329
+ public static function getErrorLogs($deepSearch = false) {
2330
+ static $errorLogs = null;
2331
+
2332
+ if ($errorLogs === null) {
2333
+ $searchPaths = array(ABSPATH, ABSPATH . 'wp-admin', ABSPATH . 'wp-content');
2334
+
2335
+ $homePath = get_home_path();
2336
+ if (!in_array($homePath, $searchPaths)) {
2337
+ $searchPaths[] = $homePath;
2338
+ }
2339
+
2340
+ $errorLogPath = ini_get('error_log');
2341
+ if (!empty($errorLogPath) && !in_array($errorLogPath, $searchPaths)) {
2342
+ $searchPaths[] = $errorLogPath;
2343
+ }
2344
+
2345
+ $errorLogs = array();
2346
+ foreach ($searchPaths as $s) {
2347
+ $errorLogs = array_merge($errorLogs, self::_scanForLogs($s, $deepSearch));
2348
+ }
2349
+ }
2350
+ return $errorLogs;
2351
+ }
2352
+
2353
+ private static function _scanForLogs($path, $deepSearch = false) {
2354
+ static $processedFolders = array(); //Protection for endless loops caused by symlinks
2355
+ if (is_file($path)) {
2356
+ $file = basename($path);
2357
+ if (preg_match('#(?:error_log(\-\d+)?$|\.log$)#i', $file)) {
2358
+ return array($path => is_readable($path));
2359
+ }
2360
+ return array();
2361
+ }
2362
+
2363
+ $path = untrailingslashit($path);
2364
+ $contents = @scandir($path);
2365
+ if (!is_array($contents)) {
2366
+ return array();
2367
+ }
2368
+
2369
+ $processedFolders[$path] = true;
2370
+ $errorLogs = array();
2371
+ foreach ($contents as $name) {
2372
+ if ($name == '.' || $name == '..') { continue; }
2373
+ $testPath = $path . DIRECTORY_SEPARATOR . $name;
2374
+ if (!array_key_exists($testPath, $processedFolders)) {
2375
+ if ((is_dir($testPath) && $deepSearch) || !is_dir($testPath)) {
2376
+ $errorLogs = array_merge($errorLogs, self::_scanForLogs($testPath, $deepSearch));
2377
+ }
2378
+ }
2379
+ }
2380
+ return $errorLogs;
2381
+ }
2382
+
2383
+ public static function outputErrorLog($path) {
2384
+ $errorLogs = self::getErrorLogs();
2385
+ if (!isset($errorLogs[$path])) { //Only allow error logs we've identified
2386
+ status_header(404);
2387
+ nocache_headers();
2388
+
2389
+ $template = get_404_template();
2390
+ if ($template && file_exists($template)) {
2391
+ include($template);
2392
+ }
2393
+ exit;
2394
+ }
2395
+
2396
+ $fh = @fopen($path, 'r');
2397
+ if (!$fh) {
2398
+ status_header(503);
2399
+ nocache_headers();
2400
+ echo "503 Service Unavailable";
2401
+ exit;
2402
+ }
2403
+
2404
+ $headersOutputted = false;
2405
+ while (!feof($fh)) {
2406
+ $data = fread($fh, 1 * 1024 * 1024); //read 1 megs max per chunk
2407
+ if ($data === false) { //Handle the error where the file was reported readable but we can't actually read it
2408
+ status_header(503);
2409
+ nocache_headers();
2410
+ echo "503 Service Unavailable";
2411
+ exit;
2412
+ }
2413
+
2414
+ if (!$headersOutputted) {
2415
+ header('Content-Type: text/plain');
2416
+ header('Content-Disposition: attachment; filename="' . basename($path));
2417
+ $headersOutputted = true;
2418
+ }
2419
+ echo $data;
2420
+ }
2421
+ exit;
2422
+ }
2423
+ }
lib/wfUtils.php CHANGED
@@ -134,13 +134,17 @@ class wfUtils {
134
  return false;
135
  }
136
  }
137
-
138
- // Convert human readable addresses to 128 bit (IPv6) binary strings
139
- // Note: self::inet_pton converts IPv4 addresses to IPv6 compatible versions
140
- $binary_network = str_pad(wfHelperBin::bin2str(self::inet_pton($network)), 128, '0', STR_PAD_LEFT);
141
- $binary_ip = str_pad(wfHelperBin::bin2str(self::inet_pton($ip)), 128, '0', STR_PAD_LEFT);
142
-
143
- return 0 === substr_compare($binary_ip, $binary_network, 0, $prefix);
 
 
 
 
144
  }
145
 
146
  /**
@@ -647,7 +651,7 @@ class wfUtils {
647
  return self::getCleanIPAndServerVar(array($connectionIP));
648
  } else {
649
  $ipsToCheck = array(
650
- array($_SERVER[$howGet], $howGet),
651
  $connectionIP,
652
  );
653
  return self::getCleanIPAndServerVar($ipsToCheck);
134
  return false;
135
  }
136
  }
137
+
138
+ $bin_network = substr(self::inet_pton($network), 0, ceil($prefix / 8));
139
+ $bin_ip = substr(self::inet_pton($ip), 0, ceil($prefix / 8));
140
+ if ($prefix % 8 != 0) { //Adjust the last relevant character to fit the mask length since the character's bits are split over it
141
+ $pos = intval($prefix / 8);
142
+ $adjustment = chr(((0xff << (8 - ($prefix % 8))) & 0xff));
143
+ $bin_network[$pos] = ($bin_network[$pos] & $adjustment);
144
+ $bin_ip[$pos] = ($bin_ip[$pos] & $adjustment);
145
+ }
146
+
147
+ return ($bin_network === $bin_ip);
148
  }
149
 
150
  /**
651
  return self::getCleanIPAndServerVar(array($connectionIP));
652
  } else {
653
  $ipsToCheck = array(
654
+ array((isset($_SERVER[$howGet]) ? $_SERVER[$howGet] : ''), $howGet),
655
  $connectionIP,
656
  );
657
  return self::getCleanIPAndServerVar($ipsToCheck);
lib/wordfenceClass.php CHANGED
@@ -48,6 +48,13 @@ class wordfence {
48
  update_option('wordfenceActivated', 1);
49
  }
50
  public static function uninstallPlugin(){
 
 
 
 
 
 
 
51
  //Check if caching is enabled and if it is, disable it and fix the .htaccess file.
52
  $cacheType = wfConfig::get('cacheType', false);
53
  if($cacheType == 'falcon'){
@@ -552,6 +559,11 @@ SQL
552
 
553
  wp_schedule_single_event(time(), 'wordfence_sendFalconDeprecationNotice');
554
  }
 
 
 
 
 
555
 
556
  //Must be the final line
557
  }
@@ -1018,7 +1030,11 @@ SQL
1018
 
1019
  $wfFunc = isset($_GET['_wfsf']) ? @$_GET['_wfsf'] : false;
1020
  if($wfFunc == 'unlockEmail'){
1021
- if(! wp_verify_nonce(@$_POST['nonce'], 'wf-form')){
 
 
 
 
1022
  die("Sorry but your browser sent an invalid security token when trying to use this form.");
1023
  }
1024
  $numTries = get_transient('wordfenceUnlockTries');
@@ -1029,9 +1045,10 @@ SQL
1029
  if(! $numTries){ $numTries = 1; } else { $numTries = $numTries + 1; }
1030
  set_transient('wordfenceUnlockTries', $numTries, 180);
1031
 
1032
- $email = trim($_POST['email']);
1033
  global $wpdb;
1034
  $ws = $wpdb->get_results($wpdb->prepare("SELECT ID, user_login FROM $wpdb->users WHERE user_email = %s", $email));
 
1035
  foreach($ws as $user){
1036
  $userDat = get_userdata($user->ID);
1037
  if(wfUtils::isAdmin($userDat)){
@@ -1116,10 +1133,15 @@ SQL
1116
  'whitelistedIPs' => (string) wfConfig::get('whitelisted'),
1117
  'howGetIPs' => (string) wfConfig::get('howGetIPs'),
1118
  'other_WFNet' => wfConfig::get('other_WFNet', true),
 
1119
  );
1120
  foreach ($configDefaults as $key => $value) {
1121
  $waf->getStorageEngine()->setConfig($key, $value);
1122
  }
 
 
 
 
1123
 
1124
  if (empty($_GET['wordfence_syncAttackData'])) {
1125
  $lastAttackMicroseconds = $wpdb->get_var("SELECT MAX(attackLogTime) FROM {$wpdb->base_prefix}wfHits");
@@ -2001,6 +2023,7 @@ SQL
2001
  public static function ajax_sendDiagnostic_callback(){
2002
  $inEmail = true;
2003
  $body = "This email is the diagnostic from " . site_url() . ".\nThe IP address that requested this was: " . wfUtils::getIP() . "\nTicket Number/Forum Username: " . $_POST['ticket'];
 
2004
  ob_start();
2005
  require 'menu_diagnostic.php';
2006
  $body = nl2br($body) . ob_get_clean();
@@ -2685,6 +2708,15 @@ SQL
2685
  readfile($file);
2686
  die();
2687
  }
 
 
 
 
 
 
 
 
 
2688
  public static function ajax_addCacheExclusion_callback(){
2689
  $ex = wfConfig::get('cacheExclusions', false);
2690
  if($ex){
@@ -3205,8 +3237,11 @@ HTACCESS;
3205
  );
3206
  }
3207
  public static function ajax_loadIssues_callback(){
 
 
 
3208
  $i = new wfIssues();
3209
- $iss = $i->getIssues();
3210
  return array(
3211
  'issuesLists' => $iss,
3212
  'summary' => $i->getSummaryItems(),
@@ -4253,7 +4288,7 @@ HTML;
4253
  'exportSettings', 'importSettings', 'bulkOperation', 'deleteFile', 'deleteDatabaseOption', 'removeExclusion',
4254
  'activityLogUpdate', 'ticker', 'loadIssues', 'updateIssueStatus', 'deleteIssue', 'updateAllIssues',
4255
  'reverseLookup', 'unlockOutIP', 'loadBlockRanges', 'unblockRange', 'blockIPUARange', 'whois', 'unblockIP',
4256
- 'blockIP', 'permBlockIP', 'loadStaticPanel', 'saveConfig', 'downloadHtaccess', 'checkFalconHtaccess',
4257
  'updateConfig', 'saveCacheConfig', 'removeFromCache', 'autoUpdateChoice', 'adminEmailChoice', 'suPHPWAFUpdateChoice', 'falconDeprecationChoice', 'saveCacheOptions', 'clearPageCache',
4258
  'getCacheStats', 'clearAllBlocked', 'killScan', 'saveCountryBlocking', 'saveScanSchedule', 'tourClosed',
4259
  'welcomeClosed', 'startTourAgain', 'downgradeLicense', 'addTwoFactor', 'twoFacActivate', 'twoFacDel',
@@ -4390,7 +4425,8 @@ HTML;
4390
  'tourClosed' => wfConfig::get('tourClosed', 0),
4391
  'welcomeClosed' => wfConfig::get('welcomeClosed', 0),
4392
  'cacheType' => wfConfig::get('cacheType'),
4393
- 'liveTrafficEnabled' => wfConfig::liveTrafficEnabled()
 
4394
  ));
4395
  }
4396
  public static function activation_warning(){
@@ -6287,7 +6323,7 @@ ALERTMSG;
6287
  $limit = 500;
6288
  $lastSendTime = wfConfig::get('lastAttackDataSendTime');
6289
  $attackData = $wpdb->get_results($wpdb->prepare("SELECT SQL_CALC_FOUND_ROWS * FROM {$wpdb->base_prefix}wfHits
6290
- WHERE action in ('blocked:waf', 'learned:waf', 'logged:waf')
6291
  AND attackLogTime > %.6f
6292
  LIMIT %d", $lastSendTime, $limit));
6293
  $totalRows = $wpdb->get_var('SELECT FOUND_ROWS()');
@@ -6330,6 +6366,7 @@ LIMIT %d", $lastSendTime, $limit));
6330
  'k' => $waf->getStorageEngine()->getConfig('apiKey'),
6331
  's' => $waf->getStorageEngine()->getConfig('siteURL') ? $waf->getStorageEngine()->getConfig('siteURL') :
6332
  sprintf('%s://%s/', $waf->getRequest()->getProtocol(), rawurlencode($waf->getRequest()->getHost())),
 
6333
  ), null, '&'),
6334
  array(
6335
  'body' => json_encode($dataToSend),
@@ -6382,11 +6419,11 @@ LIMIT %d", $lastSendTime, $limit));
6382
  $attackData = $waf->getStorageEngine()->getNewestAttackDataArray($lastAttackMicroseconds);
6383
  if ($attackData) {
6384
  foreach ($attackData as $request) {
6385
- if (count($request) !== 9) {
6386
  continue;
6387
  }
6388
 
6389
- list($logTimeMicroseconds, $requestTime, $ip, $learningMode, $paramKey, $paramValue, $failedRules, $ssl, $requestString) = $request;
6390
 
6391
  // Skip old entries and hits in learning mode, since they'll get picked up anyways.
6392
  if ($logTimeMicroseconds <= $lastAttackMicroseconds || $learningMode) {
@@ -6437,12 +6474,59 @@ LIMIT %d", $lastSendTime, $limit));
6437
  $path = $matches[1];
6438
  }
6439
  }
6440
-
6441
- if ($failedRules == 'logged') {
6442
- $hit->action = 'logged:waf';
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
6443
  }
6444
  else {
6445
- $hit->action = 'blocked:waf';
 
 
 
 
 
6446
  }
6447
 
6448
  /** @var wfWAFRule $rule */
@@ -6457,13 +6541,13 @@ LIMIT %d", $lastSendTime, $limit));
6457
  if ($ruleIDs && $ruleIDs[0]) {
6458
  $rule = $waf->getRule($ruleIDs[0]);
6459
  if ($rule) {
6460
- $hit->actionDescription = $rule->getDescription();
6461
  $actionData['category'] = $rule->getCategory();
6462
  $actionData['ssl'] = $ssl;
6463
  $actionData['fullRequest'] = base64_encode($requestString);
6464
  }
6465
  else if ($ruleIDs[0] == 'logged') {
6466
- $hit->actionDescription = 'Watched IP Traffic: ' . $ip;
6467
  $actionData['category'] = 'logged';
6468
  $actionData['ssl'] = $ssl;
6469
  $actionData['fullRequest'] = base64_encode($requestString);
48
  update_option('wordfenceActivated', 1);
49
  }
50
  public static function uninstallPlugin(){
51
+ //Send admin alert
52
+ if (wfConfig::get('alertOn_wordfenceDeactivated')) {
53
+ $currentUser = wp_get_current_user();
54
+ $username = $currentUser->user_login;
55
+ wordfence::alert("Wordfence Deactivated", "A user with username \"$username\" deactivated Wordfence on your WordPress site.", wfUtils::getIP());
56
+ }
57
+
58
  //Check if caching is enabled and if it is, disable it and fix the .htaccess file.
59
  $cacheType = wfConfig::get('cacheType', false);
60
  if($cacheType == 'falcon'){
559
 
560
  wp_schedule_single_event(time(), 'wordfence_sendFalconDeprecationNotice');
561
  }
562
+
563
+ //6.2.3
564
+ if (!WFWAF_SUBDIRECTORY_INSTALL && class_exists('wfWAFIPBlocksController')) {
565
+ wfWAFIPBlocksController::synchronizeConfigSettings();
566
+ }
567
 
568
  //Must be the final line
569
  }
1030
 
1031
  $wfFunc = isset($_GET['_wfsf']) ? @$_GET['_wfsf'] : false;
1032
  if($wfFunc == 'unlockEmail'){
1033
+ $nonceValid = wp_verify_nonce(@$_POST['nonce'], 'wf-form');
1034
+ if (!$nonceValid && method_exists(wfWAF::getInstance(), 'createNonce')) {
1035
+ $nonceValid = wfWAF::getInstance()->verifyNonce(@$_POST['nonce'], 'wf-form');
1036
+ }
1037
+ if(!$nonceValid){
1038
  die("Sorry but your browser sent an invalid security token when trying to use this form.");
1039
  }
1040
  $numTries = get_transient('wordfenceUnlockTries');
1045
  if(! $numTries){ $numTries = 1; } else { $numTries = $numTries + 1; }
1046
  set_transient('wordfenceUnlockTries', $numTries, 180);
1047
 
1048
+ $email = trim(@$_POST['email']);
1049
  global $wpdb;
1050
  $ws = $wpdb->get_results($wpdb->prepare("SELECT ID, user_login FROM $wpdb->users WHERE user_email = %s", $email));
1051
+ $found = false;
1052
  foreach($ws as $user){
1053
  $userDat = get_userdata($user->ID);
1054
  if(wfUtils::isAdmin($userDat)){
1133
  'whitelistedIPs' => (string) wfConfig::get('whitelisted'),
1134
  'howGetIPs' => (string) wfConfig::get('howGetIPs'),
1135
  'other_WFNet' => wfConfig::get('other_WFNet', true),
1136
+ 'pluginABSPATH' => ABSPATH,
1137
  );
1138
  foreach ($configDefaults as $key => $value) {
1139
  $waf->getStorageEngine()->setConfig($key, $value);
1140
  }
1141
+
1142
+ if (class_exists('wfWAFIPBlocksController')) {
1143
+ wfWAFIPBlocksController::synchronizeConfigSettings();
1144
+ }
1145
 
1146
  if (empty($_GET['wordfence_syncAttackData'])) {
1147
  $lastAttackMicroseconds = $wpdb->get_var("SELECT MAX(attackLogTime) FROM {$wpdb->base_prefix}wfHits");
2023
  public static function ajax_sendDiagnostic_callback(){
2024
  $inEmail = true;
2025
  $body = "This email is the diagnostic from " . site_url() . ".\nThe IP address that requested this was: " . wfUtils::getIP() . "\nTicket Number/Forum Username: " . $_POST['ticket'];
2026
+ $sendingDiagnosticEmail = true;
2027
  ob_start();
2028
  require 'menu_diagnostic.php';
2029
  $body = nl2br($body) . ob_get_clean();
2708
  readfile($file);
2709
  die();
2710
  }
2711
+ public static function ajax_downloadLogFile_callback() {
2712
+ if (!isset($_GET['logfile'])) {
2713
+ status_header(400);
2714
+ nocache_headers();
2715
+ exit;
2716
+ }
2717
+
2718
+ wfErrorLogHandler::outputErrorLog($_GET['logfile']); //exits
2719
+ }
2720
  public static function ajax_addCacheExclusion_callback(){
2721
  $ex = wfConfig::get('cacheExclusions', false);
2722
  if($ex){
3237
  );
3238
  }
3239
  public static function ajax_loadIssues_callback(){
3240
+ $offset = isset($_POST['offset']) ? intval($_POST['offset']) : 0;
3241
+ $limit = isset($_POST['limit']) ? intval($_POST['limit']) : WORDFENCE_SCAN_ISSUES_PER_PAGE;
3242
+
3243
  $i = new wfIssues();
3244
+ $iss = $i->getIssues($offset, $limit);
3245
  return array(
3246
  'issuesLists' => $iss,
3247
  'summary' => $i->getSummaryItems(),
4288
  'exportSettings', 'importSettings', 'bulkOperation', 'deleteFile', 'deleteDatabaseOption', 'removeExclusion',
4289
  'activityLogUpdate', 'ticker', 'loadIssues', 'updateIssueStatus', 'deleteIssue', 'updateAllIssues',
4290
  'reverseLookup', 'unlockOutIP', 'loadBlockRanges', 'unblockRange', 'blockIPUARange', 'whois', 'unblockIP',
4291
+ 'blockIP', 'permBlockIP', 'loadStaticPanel', 'saveConfig', 'downloadHtaccess', 'downloadLogFile', 'checkFalconHtaccess',
4292
  'updateConfig', 'saveCacheConfig', 'removeFromCache', 'autoUpdateChoice', 'adminEmailChoice', 'suPHPWAFUpdateChoice', 'falconDeprecationChoice', 'saveCacheOptions', 'clearPageCache',
4293
  'getCacheStats', 'clearAllBlocked', 'killScan', 'saveCountryBlocking', 'saveScanSchedule', 'tourClosed',
4294
  'welcomeClosed', 'startTourAgain', 'downgradeLicense', 'addTwoFactor', 'twoFacActivate', 'twoFacDel',
4425
  'tourClosed' => wfConfig::get('tourClosed', 0),
4426
  'welcomeClosed' => wfConfig::get('welcomeClosed', 0),
4427
  'cacheType' => wfConfig::get('cacheType'),
4428
+ 'liveTrafficEnabled' => wfConfig::liveTrafficEnabled(),
4429
+ 'scanIssuesPerPage' => WORDFENCE_SCAN_ISSUES_PER_PAGE,
4430
  ));
4431
  }
4432
  public static function activation_warning(){
6323
  $limit = 500;
6324
  $lastSendTime = wfConfig::get('lastAttackDataSendTime');
6325
  $attackData = $wpdb->get_results($wpdb->prepare("SELECT SQL_CALC_FOUND_ROWS * FROM {$wpdb->base_prefix}wfHits
6326
+ WHERE action in ('blocked:waf', 'learned:waf', 'logged:waf', 'blocked:waf-always')
6327
  AND attackLogTime > %.6f
6328
  LIMIT %d", $lastSendTime, $limit));
6329
  $totalRows = $wpdb->get_var('SELECT FOUND_ROWS()');
6366
  'k' => $waf->getStorageEngine()->getConfig('apiKey'),
6367
  's' => $waf->getStorageEngine()->getConfig('siteURL') ? $waf->getStorageEngine()->getConfig('siteURL') :
6368
  sprintf('%s://%s/', $waf->getRequest()->getProtocol(), rawurlencode($waf->getRequest()->getHost())),
6369
+ 't' => microtime(true),
6370
  ), null, '&'),
6371
  array(
6372
  'body' => json_encode($dataToSend),
6419
  $attackData = $waf->getStorageEngine()->getNewestAttackDataArray($lastAttackMicroseconds);
6420
  if ($attackData) {
6421
  foreach ($attackData as $request) {
6422
+ if (count($request) !== 9 && count($request) !== 10 /* with metadata */) {
6423
  continue;
6424
  }
6425
 
6426
+ list($logTimeMicroseconds, $requestTime, $ip, $learningMode, $paramKey, $paramValue, $failedRules, $ssl, $requestString, $metadata) = $request;
6427
 
6428
  // Skip old entries and hits in learning mode, since they'll get picked up anyways.
6429
  if ($logTimeMicroseconds <= $lastAttackMicroseconds || $learningMode) {
6474
  $path = $matches[1];
6475
  }
6476
  }
6477
+
6478
+ $metadata = ($metadata != null ? (array) $metadata : array());
6479
+ if (isset($metadata['finalAction']) && $metadata['finalAction']) { // The request was blocked/redirected because of its IP based on the plugin's blocking settings. WAF blocks should be reported but not shown in live traffic with that as a reason.
6480
+ $action = $metadata['finalAction']['action'];
6481
+ $actionDescription = $action;
6482
+ if (class_exists('wfWAFIPBlocksController')) {
6483
+ if ($action == wfWAFIPBlocksController::WFWAF_BLOCK_UAREFIPRANGE) {
6484
+ $id = $metadata['finalAction']['id'];
6485
+ $wpdb->query($wpdb->prepare("UPDATE {$wpdb->base_prefix}wfBlocksAdv SET totalBlocked = totalBlocked + 1, lastBlocked = %d WHERE id = %d", $requestTime, $id));
6486
+ wfActivityReport::logBlockedIP($ip);
6487
+ }
6488
+ else if ($action == wfWAFIPBlocksController::WFWAF_BLOCK_COUNTRY_REDIR) {
6489
+ $actionDescription .= ' (' . wfConfig::get('cbl_redirURL') . ')';
6490
+ wfConfig::inc('totalCountryBlocked');
6491
+ wfActivityReport::logBlockedIP($ip);
6492
+ }
6493
+ else if ($action == wfWAFIPBlocksController::WFWAF_BLOCK_COUNTRY) {
6494
+ wfConfig::inc('totalCountryBlocked');
6495
+ wfActivityReport::logBlockedIP($ip);
6496
+ }
6497
+ else if ($action == wfWAFIPBlocksController::WFWAF_BLOCK_WFSN) {
6498
+ wordfence::wfsnReportBlockedAttempt($ip, 'login');
6499
+ }
6500
+ }
6501
+
6502
+ if (strlen($actionDescription) == 0) {
6503
+ $actionDescription = 'Blocked by Wordfence';
6504
+ }
6505
+
6506
+ if (empty($failedRules)) { // Just a plugin block
6507
+ $hit->action = 'blocked:wordfence';
6508
+ if (class_exists('wfWAFIPBlocksController')) {
6509
+ if ($action == wfWAFIPBlocksController::WFWAF_BLOCK_WFSN) {
6510
+ $hit->action = 'blocked:wfsnrepeat';
6511
+ }
6512
+ }
6513
+ $hit->actionDescription = $actionDescription;
6514
+ }
6515
+ else if ($failedRules == 'logged') {
6516
+ $hit->action = 'logged:waf';
6517
+ }
6518
+ else { // Blocked by the WAF but would've been blocked anyway by the plugin settings so that message takes priority
6519
+ $hit->action = 'blocked:waf-always';
6520
+ $hit->actionDescription = $actionDescription;
6521
+ }
6522
  }
6523
  else {
6524
+ if ($failedRules == 'logged') {
6525
+ $hit->action = 'logged:waf';
6526
+ }
6527
+ else {
6528
+ $hit->action = 'blocked:waf';
6529
+ }
6530
  }
6531
 
6532
  /** @var wfWAFRule $rule */
6541
  if ($ruleIDs && $ruleIDs[0]) {
6542
  $rule = $waf->getRule($ruleIDs[0]);
6543
  if ($rule) {
6544
+ if ($hit->action == 'logged:waf' || $hit->action == 'blocked:waf') { $hit->actionDescription = $rule->getDescription(); }
6545
  $actionData['category'] = $rule->getCategory();
6546
  $actionData['ssl'] = $ssl;
6547
  $actionData['fullRequest'] = base64_encode($requestString);
6548
  }
6549
  else if ($ruleIDs[0] == 'logged') {
6550
+ if ($hit->action == 'logged:waf' || $hit->action == 'blocked:waf') { $hit->actionDescription = 'Watched IP Traffic: ' . $ip; }
6551
  $actionData['category'] = 'logged';
6552
  $actionData['ssl'] = $ssl;
6553
  $actionData['fullRequest'] = base64_encode($requestString);
lib/wordfenceConstants.php CHANGED
@@ -13,4 +13,5 @@ define('WORDFENCE_REVERSE_LOOKUP_CACHE_TIME', 86400);
13
  define('WORDFENCE_MAX_FILE_SIZE_TO_PROCESS', 52428800); //50 megs
14
  define('WORDFENCE_TWO_FACTOR_GRACE_TIME_AUTHENTICATOR', 90);
15
  define('WORDFENCE_TWO_FACTOR_GRACE_TIME_PHONE', 1800);
 
16
  ?>
13
  define('WORDFENCE_MAX_FILE_SIZE_TO_PROCESS', 52428800); //50 megs
14
  define('WORDFENCE_TWO_FACTOR_GRACE_TIME_AUTHENTICATOR', 90);
15
  define('WORDFENCE_TWO_FACTOR_GRACE_TIME_PHONE', 1800);
16
+ if (!defined('WORDFENCE_SCAN_ISSUES_PER_PAGE')) { define('WORDFENCE_SCAN_ISSUES_PER_PAGE', 100); }
17
  ?>
readme.txt CHANGED
@@ -3,7 +3,7 @@ Contributors: mmaunder
3
  Tags: security, secure, security plugin, wordpress security, login security, firewall, malware, antivirus, web application firewall, block hackers, country blocking
4
  Requires at least: 3.9
5
  Tested up to: 4.6.1
6
- Stable tag: 6.2.2
7
 
8
  Secure your website with the most comprehensive WordPress security plugin. Firewall, malware scan, blocking, live traffic, login security & more.
9
 
@@ -190,6 +190,21 @@ Secure your website with Wordfence.
190
 
191
  == Changelog ==
192
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
193
  = 6.2.2 =
194
  * Fix: Replaced a slow query in the dashboard widget that could affect sites with very large numbers of users.
195
 
3
  Tags: security, secure, security plugin, wordpress security, login security, firewall, malware, antivirus, web application firewall, block hackers, country blocking
4
  Requires at least: 3.9
5
  Tested up to: 4.6.1
6
+ Stable tag: 6.2.3
7
 
8
  Secure your website with the most comprehensive WordPress security plugin. Firewall, malware scan, blocking, live traffic, login security & more.
9
 
190
 
191
  == Changelog ==
192
 
193
+ = 6.2.3 =
194
+ * Improvement: Reworked blocking for IP ranges, country blocking, and direct IP blocking to minimize server impact when under attack.
195
+ * Improvement: Live traffic better indicates the action taken by country blocking when it redirects a visitor.
196
+ * Improvement: Added support for finding server logs to the Diagnostics page to help with troubleshooting.
197
+ * Improvement: Whitelisted StatusCake IP addresses.
198
+ * Improvement: Updated GeoIP database.
199
+ * Improvement: Disabling Wordfence now sends an alert.
200
+ * Improvement: Improved detection for uploaded PHP content in the firewall.
201
+ * Fix: Eliminated memory-related errors resulting from the scan on sites with very large numbers of issues and low memory.
202
+ * Fix: Fixed admin page layout for sites using RTL languages.
203
+ * Fix: Reduced overhead of the dashboard widget.
204
+ * Fix: Improved performance of checking for whitelisted IPs.
205
+ * Fix: Changes to the default plugin hello.php are now detected correctly in scans.
206
+ * Fix: Fixed IPv6 warning in the dashboard widget.
207
+
208
  = 6.2.2 =
209
  * Fix: Replaced a slow query in the dashboard widget that could affect sites with very large numbers of users.
210
 
vendor/wordfence/wf-waf/src/lib/request.php CHANGED
@@ -21,6 +21,9 @@ interface wfWAFRequestInterface {
21
  public function getHost();
22
 
23
  public function getURI();
 
 
 
24
 
25
  public function getPath();
26
 
@@ -73,6 +76,7 @@ class wfWAFRequest implements wfWAFRequestInterface {
73
  $request->setMd5QueryString(array());
74
  $request->setTimestamp('');
75
  $request->setURI('');
 
76
 
77
  list($headersString, $bodyString) = explode("\n\n", $requestString, 2);
78
  $headersString = trim($headersString);
@@ -241,6 +245,7 @@ class wfWAFRequest implements wfWAFRequestInterface {
241
  $request->setProtocol('');
242
  $request->setTimestamp('');
243
  $request->setURI('');
 
244
 
245
  $request->setBody(wfWAFUtils::stripMagicQuotes($_POST));
246
  $request->setQueryString(wfWAFUtils::stripMagicQuotes($_GET));
@@ -332,6 +337,7 @@ class wfWAFRequest implements wfWAFRequestInterface {
332
  private $md5QueryString;
333
  private $timestamp;
334
  private $uri;
 
335
 
336
  private $highlightParamFormat;
337
  private $highlightMatchFormat;
@@ -467,6 +473,14 @@ class wfWAFRequest implements wfWAFRequestInterface {
467
  public function getURI() {
468
  return $this->uri;
469
  }
 
 
 
 
 
 
 
 
470
 
471
  public function getPath() {
472
  return $this->path;
@@ -909,5 +923,12 @@ FORM;
909
  public function setUri($uri) {
910
  $this->uri = $uri;
911
  }
 
 
 
 
 
 
 
912
  }
913
 
21
  public function getHost();
22
 
23
  public function getURI();
24
+
25
+ public function setMetadata($metadata);
26
+ public function getMetadata();
27
 
28
  public function getPath();
29
 
76
  $request->setMd5QueryString(array());
77
  $request->setTimestamp('');
78
  $request->setURI('');
79
+ $request->setMetadata(array());
80
 
81
  list($headersString, $bodyString) = explode("\n\n", $requestString, 2);
82
  $headersString = trim($headersString);
245
  $request->setProtocol('');
246
  $request->setTimestamp('');
247
  $request->setURI('');
248
+ $request->setMetadata(array());
249
 
250
  $request->setBody(wfWAFUtils::stripMagicQuotes($_POST));
251
  $request->setQueryString(wfWAFUtils::stripMagicQuotes($_GET));
337
  private $md5QueryString;
338
  private $timestamp;
339
  private $uri;
340
+ private $metadata;
341
 
342
  private $highlightParamFormat;
343
  private $highlightMatchFormat;
473
  public function getURI() {
474
  return $this->uri;
475
  }
476
+
477
+ public function getMetadata() {
478
+ if (func_num_args() > 0) {
479
+ $args = func_get_args();
480
+ return $this->_arrayValueByKeys($this->metadata, $args);
481
+ }
482
+ return $this->metadata;
483
+ }
484
 
485
  public function getPath() {
486
  return $this->path;
923
  public function setUri($uri) {
924
  $this->uri = $uri;
925
  }
926
+
927
+ /**
928
+ * @param array $metadata
929
+ */
930
+ public function setMetadata($metadata) {
931
+ $this->metadata = $metadata;
932
+ }
933
  }
934
 
vendor/wordfence/wf-waf/src/lib/rules.php CHANGED
@@ -751,6 +751,7 @@ class wfWAFRuleComparison implements wfWAFRuleInterface {
751
  }
752
 
753
  $totalRead = 0;
 
754
  $hasExecutablePHP = false;
755
  $possiblyHasExecutablePHP = false;
756
  $hasOpenParen = false;
@@ -760,7 +761,7 @@ class wfWAFRuleComparison implements wfWAFRuleInterface {
760
  $maxTokenSize = 15; //__halt_compiler
761
  $possibleWrappedTokens = array('<?php', '<?=', '<?', '?>', 'exit', 'new', 'clone', 'echo', 'print', 'require', 'include', 'require_once', 'include_once', '__halt_compiler');
762
 
763
- $readsize = 512 * 1024; //512k at a time
764
  while (!feof($fh)) {
765
  $data = fread($fh, $readsize);
766
  $actualReadsize = strlen($data);
@@ -782,26 +783,81 @@ class wfWAFRuleComparison implements wfWAFRuleInterface {
782
  }
783
  }
784
 
 
 
 
 
 
 
 
 
 
 
785
  //Tokenize the data and check for PHP
 
786
  $tokens = @token_get_all($data);
 
 
 
 
 
 
 
 
 
 
787
  foreach ($tokens as $token) {
788
  if (is_array($token)) {
 
789
  switch ($token[0]) {
790
  case T_OPEN_TAG:
 
791
  $hasOpenParen = false;
792
  $hasCloseParen = false;
793
  $backtickCount = 0;
794
  $possiblyHasExecutablePHP = false;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
795
  break;
796
 
797
  case T_OPEN_TAG_WITH_ECHO:
 
798
  $hasOpenParen = false;
799
  $hasCloseParen = false;
800
  $backtickCount = 0;
801
  $possiblyHasExecutablePHP = true;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
802
  break;
803
 
804
  case T_CLOSE_TAG:
 
805
  if ($possiblyHasExecutablePHP) {
806
  $hasExecutablePHP = true; //Assume the echo short tag outputted something useful
807
  }
@@ -822,6 +878,7 @@ class wfWAFRuleComparison implements wfWAFRuleInterface {
822
  }
823
  }
824
  else {
 
825
  switch ($token) {
826
  case '(':
827
  $hasOpenParen = true;
@@ -841,16 +898,35 @@ class wfWAFRuleComparison implements wfWAFRuleInterface {
841
  }
842
 
843
  if ($hasExecutablePHP) {
 
844
  return true;
845
  }
846
 
847
  $wrappedTokenCheckBytes = substr($data, - min($maxTokenSize, $actualReadsize));
848
  }
 
 
849
  }
850
  }
851
 
852
  return false;
853
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
854
 
855
  /**
856
  * @return mixed
751
  }
752
 
753
  $totalRead = 0;
754
+ $insideOpenTag = false;
755
  $hasExecutablePHP = false;
756
  $possiblyHasExecutablePHP = false;
757
  $hasOpenParen = false;
761
  $maxTokenSize = 15; //__halt_compiler
762
  $possibleWrappedTokens = array('<?php', '<?=', '<?', '?>', 'exit', 'new', 'clone', 'echo', 'print', 'require', 'include', 'require_once', 'include_once', '__halt_compiler');
763
 
764
+ $readsize = 100 * 1024; //100k at a time
765
  while (!feof($fh)) {
766
  $data = fread($fh, $readsize);
767
  $actualReadsize = strlen($data);
783
  }
784
  }
785
 
786
+ //Make sure it tokenizes correctly if chunked
787
+ if ($insideOpenTag) {
788
+ if ($possiblyHasExecutablePHP) {
789
+ $data = '<?= ' . $data;
790
+ }
791
+ else {
792
+ $data = '<?php ' . $data;
793
+ }
794
+ }
795
+
796
  //Tokenize the data and check for PHP
797
+ $this->_resetErrors();
798
  $tokens = @token_get_all($data);
799
+ $error = error_get_last();
800
+ if ($error !== null && stripos($error['message'], 'Unexpected character in input') !== false) {
801
+ break;
802
+ }
803
+
804
+ if ($error !== null && feof($fh) && stripos($error['message'], 'Unterminated comment') !== false) {
805
+ break;
806
+ }
807
+
808
+ $offset = 0;
809
  foreach ($tokens as $token) {
810
  if (is_array($token)) {
811
+ $offset += strlen($token[1]);
812
  switch ($token[0]) {
813
  case T_OPEN_TAG:
814
+ $insideOpenTag = true;
815
  $hasOpenParen = false;
816
  $hasCloseParen = false;
817
  $backtickCount = 0;
818
  $possiblyHasExecutablePHP = false;
819
+
820
+ if ($error !== null && stripos($error['message'], 'Unterminated comment') !== false) {
821
+ $testOffset = $offset - strlen($token[1]);
822
+ $commentStart = strpos($data, '/*', $testOffset);
823
+ if ($commentStart !== false) {
824
+ $testBytes = substr($data, $testOffset, $commentStart - $testOffset);
825
+ $this->_resetErrors();
826
+ @token_get_all($testBytes);
827
+ $error = error_get_last();
828
+ if ($error !== null && stripos($error['message'], 'Unexpected character in input') !== false) {
829
+ break 3;
830
+ }
831
+ }
832
+ }
833
+
834
  break;
835
 
836
  case T_OPEN_TAG_WITH_ECHO:
837
+ $insideOpenTag = true;
838
  $hasOpenParen = false;
839
  $hasCloseParen = false;
840
  $backtickCount = 0;
841
  $possiblyHasExecutablePHP = true;
842
+
843
+ if ($error !== null && stripos($error['message'], 'Unterminated comment') !== false) {
844
+ $testOffset = $offset - strlen($token[1]);
845
+ $commentStart = strpos($data, '/*', $testOffset);
846
+ if ($commentStart !== false) {
847
+ $testBytes = substr($data, $testOffset, $commentStart - $testOffset);
848
+ $this->_resetErrors();
849
+ @token_get_all($testBytes);
850
+ $error = error_get_last();
851
+ if ($error !== null && stripos($error['message'], 'Unexpected character in input') !== false) {
852
+ break 3;
853
+ }
854
+ }
855
+ }
856
+
857
  break;
858
 
859
  case T_CLOSE_TAG:
860
+ $insideOpenTag = false;
861
  if ($possiblyHasExecutablePHP) {
862
  $hasExecutablePHP = true; //Assume the echo short tag outputted something useful
863
  }
878
  }
879
  }
880
  else {
881
+ $offset += strlen($token);
882
  switch ($token) {
883
  case '(':
884
  $hasOpenParen = true;
898
  }
899
 
900
  if ($hasExecutablePHP) {
901
+ fclose($fh);
902
  return true;
903
  }
904
 
905
  $wrappedTokenCheckBytes = substr($data, - min($maxTokenSize, $actualReadsize));
906
  }
907
+
908
+ fclose($fh);
909
  }
910
  }
911
 
912
  return false;
913
  }
914
+
915
+ private function _resetErrors() {
916
+ if (function_exists('error_clear_last')) {
917
+ error_clear_last();
918
+ }
919
+ else {
920
+ // set error_get_last() to defined state by forcing an undefined variable error
921
+ set_error_handler(array($this, '_resetErrorsHandler'), 0);
922
+ @$undefinedVariable;
923
+ restore_error_handler();
924
+ }
925
+ }
926
+
927
+ public function _resetErrorsHandler($errno, $errstr, $errfile, $errline) {
928
+ //Do nothing
929
+ }
930
 
931
  /**
932
  * @return mixed
vendor/wordfence/wf-waf/src/lib/utils.php CHANGED
@@ -544,4 +544,200 @@ class wfWAFUtils {
544
 
545
  return intval($val);
546
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
547
  }
544
 
545
  return intval($val);
546
  }
547
+
548
+ public static function reverseLookup($IP) {
549
+ $IPn = self::inet_pton($IP);
550
+ // This function works for IPv4 or IPv6
551
+ if (function_exists('gethostbyaddr')) {
552
+ $host = @gethostbyaddr($IP);
553
+ }
554
+ if (!$host) {
555
+ $ptr = false;
556
+ if (filter_var($IP, FILTER_VALIDATE_IP, FILTER_FLAG_IPV4) !== false) {
557
+ $ptr = implode(".", array_reverse(explode(".", $IP))) . ".in-addr.arpa";
558
+ } else if (filter_var($IP, FILTER_VALIDATE_IP, FILTER_FLAG_IPV6) !== false) {
559
+ $ptr = implode(".", array_reverse(str_split(bin2hex($IPn)))) . ".ip6.arpa";
560
+ }
561
+
562
+ if ($ptr && function_exists('dns_get_record')) {
563
+ $host = @dns_get_record($ptr, DNS_PTR);
564
+ if ($host) {
565
+ $host = $host[0]['target'];
566
+ }
567
+ }
568
+ }
569
+ if (!$host) {
570
+ return '';
571
+ }
572
+ return $host;
573
+ }
574
+
575
+ public static function patternToRegex($pattern, $mod = 'i', $sep = '/') {
576
+ $pattern = preg_quote(trim($pattern), $sep);
577
+ $pattern = str_replace(' ', '\s', $pattern);
578
+ return $sep . '^' . str_replace('\*', '.*', $pattern) . '$' . $sep . $mod;
579
+ }
580
+
581
+ public static function isUABlocked($uaPattern, $ua) { // takes a pattern using asterisks as wildcards, turns it into regex and checks it against the visitor UA returning true if blocked
582
+ return fnmatch($uaPattern, $ua, FNM_CASEFOLD);
583
+ }
584
+
585
+ public static function isRefererBlocked($refPattern, $referer) {
586
+ return fnmatch($refPattern, $referer, FNM_CASEFOLD);
587
+ }
588
+
589
+ public static function extractBareURI($URL) {
590
+ $URL = preg_replace('/^https?:\/\/[^\/]+/i', '', $URL); //strip of method and host
591
+ $URL = preg_replace('/\#.*$/', '', $URL); //strip off fragment
592
+ $URL = preg_replace('/\?.*$/', '', $URL); //strip off query string
593
+ return $URL;
594
+ }
595
+
596
+ public static function extractHostname($str) {
597
+ if (preg_match('/https?:\/\/([a-zA-Z0-9\.\-]+)(?:\/|$)/i', $str, $matches)) {
598
+ return strtolower($matches[1]);
599
+ }
600
+ else {
601
+ return false;
602
+ }
603
+ }
604
+
605
+ public static function redirect($location, $status = 302) {
606
+ $is_apache = (strpos($_SERVER['SERVER_SOFTWARE'], 'Apache') !== false || strpos($_SERVER['SERVER_SOFTWARE'], 'LiteSpeed') !== false);
607
+ $is_IIS = !$is_apache && (strpos($_SERVER['SERVER_SOFTWARE'], 'Microsoft-IIS') !== false || strpos($_SERVER['SERVER_SOFTWARE'], 'ExpressionDevServer') !== false);
608
+
609
+ if (!$is_IIS && PHP_SAPI != 'cgi-fcgi') {
610
+ self::statusHeader($status); // This causes problems on IIS and some FastCGI setups
611
+ }
612
+
613
+ header("Location: {$location}", true, $status);
614
+ exit;
615
+ }
616
+
617
+ public static function statusHeader($code) {
618
+ $code = abs(intval($code));
619
+
620
+ $statusCodes = array(
621
+ 100 => 'Continue',
622
+ 101 => 'Switching Protocols',
623
+ 102 => 'Processing',
624
+
625
+ 200 => 'OK',
626
+ 201 => 'Created',
627
+ 202 => 'Accepted',
628
+ 203 => 'Non-Authoritative Information',
629
+ 204 => 'No Content',
630
+ 205 => 'Reset Content',
631
+ 206 => 'Partial Content',
632
+ 207 => 'Multi-Status',
633
+ 226 => 'IM Used',
634
+
635
+ 300 => 'Multiple Choices',
636
+ 301 => 'Moved Permanently',
637
+ 302 => 'Found',
638
+ 303 => 'See Other',
639
+ 304 => 'Not Modified',
640
+ 305 => 'Use Proxy',
641
+ 306 => 'Reserved',
642
+ 307 => 'Temporary Redirect',
643
+ 308 => 'Permanent Redirect',
644
+
645
+ 400 => 'Bad Request',
646
+ 401 => 'Unauthorized',
647
+ 402 => 'Payment Required',
648
+ 403 => 'Forbidden',
649
+ 404 => 'Not Found',
650
+ 405 => 'Method Not Allowed',
651
+ 406 => 'Not Acceptable',
652
+ 407 => 'Proxy Authentication Required',
653
+ 408 => 'Request Timeout',
654
+ 409 => 'Conflict',
655
+ 410 => 'Gone',
656
+ 411 => 'Length Required',
657
+ 412 => 'Precondition Failed',
658
+ 413 => 'Request Entity Too Large',
659
+ 414 => 'Request-URI Too Long',
660
+ 415 => 'Unsupported Media Type',
661
+ 416 => 'Requested Range Not Satisfiable',
662
+ 417 => 'Expectation Failed',
663
+ 418 => 'I\'m a teapot',
664
+ 421 => 'Misdirected Request',
665
+ 422 => 'Unprocessable Entity',
666
+ 423 => 'Locked',
667
+ 424 => 'Failed Dependency',
668
+ 426 => 'Upgrade Required',
669
+ 428 => 'Precondition Required',
670
+ 429 => 'Too Many Requests',
671
+ 431 => 'Request Header Fields Too Large',
672
+ 451 => 'Unavailable For Legal Reasons',
673
+
674
+ 500 => 'Internal Server Error',
675
+ 501 => 'Not Implemented',
676
+ 502 => 'Bad Gateway',
677
+ 503 => 'Service Unavailable',
678
+ 504 => 'Gateway Timeout',
679
+ 505 => 'HTTP Version Not Supported',
680
+ 506 => 'Variant Also Negotiates',
681
+ 507 => 'Insufficient Storage',
682
+ 510 => 'Not Extended',
683
+ 511 => 'Network Authentication Required',
684
+ );
685
+
686
+ $description = (isset($statusCodes[$code]) ? $statusCodes[$code] : '');
687
+
688
+ $protocol = $_SERVER['SERVER_PROTOCOL'];
689
+ if (!in_array($protocol, array( 'HTTP/1.1', 'HTTP/2', 'HTTP/2.0'))) {
690
+ $protocol = 'HTTP/1.0';
691
+ }
692
+
693
+ $header = "{$protocol} {$code} {$description}";
694
+ @header($header, true, $code);
695
+ }
696
+
697
+ /**
698
+ * Check if an IP address is in a network block
699
+ *
700
+ * @param string $subnet Single IP or subnet in CIDR notation (e.g. '192.168.100.0' or '192.168.100.0/22')
701
+ * @param string $ip IPv4 or IPv6 address in dot or colon notation
702
+ * @return boolean
703
+ */
704
+ public static function subnetContainsIP($subnet, $ip) {
705
+ list($network, $prefix) = array_pad(explode('/', $subnet, 2), 2, null);
706
+
707
+ if (filter_var($network, FILTER_VALIDATE_IP, FILTER_FLAG_IPV4)) {
708
+ // If no prefix was supplied, 32 is implied for IPv4
709
+ if ($prefix === null) {
710
+ $prefix = 32;
711
+ }
712
+
713
+ // Validate the IPv4 network prefix
714
+ if ($prefix < 0 || $prefix > 32) {
715
+ return false;
716
+ }
717
+
718
+ // Increase the IPv4 network prefix to work in the IPv6 address space
719
+ $prefix += 96;
720
+ } else {
721
+ // If no prefix was supplied, 128 is implied for IPv6
722
+ if ($prefix === null) {
723
+ $prefix = 128;
724
+ }
725
+
726
+ // Validate the IPv6 network prefix
727
+ if ($prefix < 1 || $prefix > 128) {
728
+ return false;
729
+ }
730
+ }
731
+
732
+ $bin_network = substr(self::inet_pton($network), 0, ceil($prefix / 8));
733
+ $bin_ip = substr(self::inet_pton($ip), 0, ceil($prefix / 8));
734
+ if ($prefix % 8 != 0) { //Adjust the last relevant character to fit the mask length since the character's bits are split over it
735
+ $pos = intval($prefix / 8);
736
+ $adjustment = chr(((0xff << (8 - ($prefix % 8))) & 0xff));
737
+ $bin_network[$pos] = ($bin_network[$pos] & $adjustment);
738
+ $bin_ip[$pos] = ($bin_ip[$pos] & $adjustment);
739
+ }
740
+
741
+ return ($bin_network === $bin_ip);
742
+ }
743
  }
vendor/wordfence/wf-waf/src/lib/waf.php CHANGED
@@ -190,6 +190,7 @@ auEa+7b+FGTKs7dUo2BNGR7OVifK4GZ8w/ajS0TelhrSRi3BBQCGXLzUO/UURUAh
190
  $this->blockAction($e);
191
 
192
  } catch (wfWAFLogException $e) {
 
193
  $this->logAction($e);
194
  }
195
 
@@ -788,9 +789,22 @@ HTML
788
  * @param wfWAFBlockException $e
789
  * @param int $httpCode
790
  */
791
- public function blockAction($e, $httpCode = 403) {
792
- $this->getStorageEngine()->logAttack($e->getFailedRules(), $e->getParamKey(), $e->getParamValue(), $e->getRequest());
793
  $this->getStorageEngine()->blockIP($this->getRequest()->getTimestamp(), $this->getRequest()->getIP());
 
 
 
 
 
 
 
 
 
 
 
 
 
794
  header('HTTP/1.0 403 Forbidden');
795
  exit($this->getBlockedMessage());
796
  }
@@ -800,8 +814,21 @@ HTML
800
  * @param wfWAFBlockXSSException $e
801
  * @param int $httpCode
802
  */
803
- public function blockXSSAction($e, $httpCode = 403) {
804
- $this->getStorageEngine()->logAttack($e->getFailedRules(), $e->getParamKey(), $e->getParamValue(), $e->getRequest());
 
 
 
 
 
 
 
 
 
 
 
 
 
805
  header('HTTP/1.0 403 Forbidden');
806
  exit($this->getBlockedMessage());
807
  }
@@ -823,6 +850,24 @@ HTML
823
  'waf' => $this,
824
  ))->render();
825
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
826
 
827
  /**
828
  *
@@ -960,6 +1005,7 @@ HTML
960
  'k' => $this->getStorageEngine()->getConfig('apiKey'),
961
  's' => $this->getStorageEngine()->getConfig('siteURL') ? $this->getStorageEngine()->getConfig('siteURL') :
962
  sprintf('%s://%s/', $this->getRequest()->getProtocol(), rawurlencode($this->getRequest()->getHost())),
 
963
  ), null, '&'), $this->getStorageEngine()->getAttackData(), $request);
964
 
965
  if ($response instanceof wfWAFHTTPResponse && $response->getBody()) {
@@ -1083,6 +1129,33 @@ HTML
1083
  $algo = function_exists('hash') ? 'sha256' : 'sha1';
1084
  return wfWAFUtils::hash_hmac($algo, $userID . $role . floor(time() / 43200), $this->getStorageEngine()->getConfig('authKey'));
1085
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1086
 
1087
  /**
1088
  * @param string|null $host
@@ -1116,6 +1189,14 @@ HTML
1116
  public function isIPBlocked($ip) {
1117
  return $this->getStorageEngine()->isIPBlocked($ip);
1118
  }
 
 
 
 
 
 
 
 
1119
 
1120
  /**
1121
  * @return array
@@ -1455,7 +1536,8 @@ class wfWAFCronFetchIPListEvent extends wfWAFCronEvent {
1455
  $response = wfWAFHTTP::post(WFWAF_API_URL_SEC . "?" . http_build_query(array(
1456
  'action' => 'send_waf_attack_data',
1457
  'k' => $waf->getStorageEngine()->getConfig('apiKey'),
1458
- 's' => $waf->getStorageEngine()->getConfig('siteURL') ? $waf->getStorageEngine()->getConfig('siteURL') : $guessSiteURL,
 
1459
  ), null, '&'), '[]', $request);
1460
 
1461
  if ($response instanceof wfWAFHTTPResponse && $response->getBody()) {
@@ -1541,6 +1623,13 @@ class wfWAFEventBus implements wfWAFObserver {
1541
  $observer->blockSQLi($ip, $exception);
1542
  }
1543
  }
 
 
 
 
 
 
 
1544
 
1545
 
1546
  public function wafDisabled() {
@@ -1576,6 +1665,8 @@ interface wfWAFObserver {
1576
  public function blockXSS($ip, $exception);
1577
 
1578
  public function blockSQLi($ip, $exception);
 
 
1579
 
1580
  public function wafDisabled();
1581
 
@@ -1604,6 +1695,10 @@ class wfWAFBaseObserver implements wfWAFObserver {
1604
 
1605
  public function blockSQLi($ip, $exception) {
1606
 
 
 
 
 
1607
  }
1608
 
1609
  public function wafDisabled() {
190
  $this->blockAction($e);
191
 
192
  } catch (wfWAFLogException $e) {
193
+ $this->eventBus->log($ip, $e);
194
  $this->logAction($e);
195
  }
196
 
789
  * @param wfWAFBlockException $e
790
  * @param int $httpCode
791
  */
792
+ public function blockAction($e, $httpCode = 403, $redirect = false) {
793
+ $this->getStorageEngine()->logAttack($e->getFailedRules(), $e->getParamKey(), $e->getParamValue(), $e->getRequest(), $e->getRequest()->getMetadata());
794
  $this->getStorageEngine()->blockIP($this->getRequest()->getTimestamp(), $this->getRequest()->getIP());
795
+
796
+ if ($redirect) {
797
+ wfWAFUtils::redirect($redirect); // exits
798
+ }
799
+
800
+ if ($httpCode == 503) {
801
+ wfWAFUtils::statusHeader(503);
802
+ if ($secsToGo = $e->getRequest()->getMetadata('503Time')) {
803
+ header('Retry-After: ' . $secsToGo);
804
+ }
805
+ exit($this->getUnavailableMessage($e->getRequest()->getMetadata('503Reason')));
806
+ }
807
+
808
  header('HTTP/1.0 403 Forbidden');
809
  exit($this->getBlockedMessage());
810
  }
814
  * @param wfWAFBlockXSSException $e
815
  * @param int $httpCode
816
  */
817
+ public function blockXSSAction($e, $httpCode = 403, $redirect = false) {
818
+ $this->getStorageEngine()->logAttack($e->getFailedRules(), $e->getParamKey(), $e->getParamValue(), $e->getRequest(), $e->getRequest()->getMetadata());
819
+
820
+ if ($redirect) {
821
+ wfWAFUtils::redirect($redirect); // exits
822
+ }
823
+
824
+ if ($httpCode == 503) {
825
+ wfWAFUtils::statusHeader(503);
826
+ if ($secsToGo = $e->getRequest()->getMetadata('503Time')) {
827
+ header('Retry-After: ' . $secsToGo);
828
+ }
829
+ exit($this->getUnavailableMessage($e->getRequest()->getMetadata('503Reason')));
830
+ }
831
+
832
  header('HTTP/1.0 403 Forbidden');
833
  exit($this->getBlockedMessage());
834
  }
850
  'waf' => $this,
851
  ))->render();
852
  }
853
+
854
+ /**
855
+ * @return string
856
+ */
857
+ public function getUnavailableMessage($reason = '') {
858
+ try {
859
+ $homeURL = wfWAF::getInstance()->getStorageEngine()->getConfig('homeURL');
860
+ }
861
+ catch (Exception $e) {
862
+ //Do nothing
863
+ }
864
+
865
+ return wfWAFView::create('503', array(
866
+ 'waf' => $this,
867
+ 'reason' => $reason,
868
+ 'homeURL' => $homeURL,
869
+ ))->render();
870
+ }
871
 
872
  /**
873
  *
1005
  'k' => $this->getStorageEngine()->getConfig('apiKey'),
1006
  's' => $this->getStorageEngine()->getConfig('siteURL') ? $this->getStorageEngine()->getConfig('siteURL') :
1007
  sprintf('%s://%s/', $this->getRequest()->getProtocol(), rawurlencode($this->getRequest()->getHost())),
1008
+ 't' => microtime(true),
1009
  ), null, '&'), $this->getStorageEngine()->getAttackData(), $request);
1010
 
1011
  if ($response instanceof wfWAFHTTPResponse && $response->getBody()) {
1129
  $algo = function_exists('hash') ? 'sha256' : 'sha1';
1130
  return wfWAFUtils::hash_hmac($algo, $userID . $role . floor(time() / 43200), $this->getStorageEngine()->getConfig('authKey'));
1131
  }
1132
+
1133
+ /**
1134
+ * @param string $action
1135
+ * @return bool|string
1136
+ */
1137
+ public function createNonce($action) {
1138
+ $userInfo = $this->parseAuthCookie();
1139
+ if ($userInfo === false) {
1140
+ $userInfo = array('userID' => 0, 'role' => ''); // Use an empty user like WordPress would
1141
+ }
1142
+ $userID = $userInfo['userID'];
1143
+ $role = $userInfo['role'];
1144
+ $algo = function_exists('hash') ? 'sha256' : 'sha1';
1145
+ return wfWAFUtils::hash_hmac($algo, $action . $userID . $role . floor(time() / 43200), $this->getStorageEngine()->getConfig('authKey'));
1146
+ }
1147
+
1148
+ /**
1149
+ * @param string $nonce
1150
+ * @param string $action
1151
+ * @return bool
1152
+ */
1153
+ public function verifyNonce($nonce, $action) {
1154
+ if (empty($nonce)) {
1155
+ return false;
1156
+ }
1157
+ return wfWAFUtils::hash_equals($nonce, $this->createNonce($action));
1158
+ }
1159
 
1160
  /**
1161
  * @param string|null $host
1189
  public function isIPBlocked($ip) {
1190
  return $this->getStorageEngine()->isIPBlocked($ip);
1191
  }
1192
+
1193
+ /**
1194
+ * @param wfWAFRequest $request
1195
+ * @return bool|array false if it should not be blocked, otherwise an array defining the context for the final action
1196
+ */
1197
+ public function willPerformFinalAction($request) {
1198
+ return false;
1199
+ }
1200
 
1201
  /**
1202
  * @return array
1536
  $response = wfWAFHTTP::post(WFWAF_API_URL_SEC . "?" . http_build_query(array(
1537
  'action' => 'send_waf_attack_data',
1538
  'k' => $waf->getStorageEngine()->getConfig('apiKey'),
1539
+ 's' => $waf->getStorageEngine()->getConfig('siteURL') ? $waf->getStorageEngine()->getConfig('siteURL') : $guessSiteURL,
1540
+ 't' => microtime(true),
1541
  ), null, '&'), '[]', $request);
1542
 
1543
  if ($response instanceof wfWAFHTTPResponse && $response->getBody()) {
1623
  $observer->blockSQLi($ip, $exception);
1624
  }
1625
  }
1626
+
1627
+ public function log($ip, $exception) {
1628
+ /** @var wfWAFObserver $observer */
1629
+ foreach ($this->observers as $observer) {
1630
+ $observer->log($ip, $exception);
1631
+ }
1632
+ }
1633
 
1634
 
1635
  public function wafDisabled() {
1665
  public function blockXSS($ip, $exception);
1666
 
1667
  public function blockSQLi($ip, $exception);
1668
+
1669
+ public function log($ip, $exception);
1670
 
1671
  public function wafDisabled();
1672
 
1695
 
1696
  public function blockSQLi($ip, $exception) {
1697
 
1698
+ }
1699
+
1700
+ public function log($ip, $exception) {
1701
+
1702
  }
1703
 
1704
  public function wafDisabled() {
vendor/wordfence/wf-waf/src/views/503.php ADDED
@@ -0,0 +1,35 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML 2.0//EN">
2
+ <html><head>
3
+ <title>Your access to this site has been limited</title>
4
+ </head><body>
5
+ <h1>Your access to this site has been limited</h1>
6
+ <p>Your access to this service has been temporarily limited. Please try again in a few minutes. (HTTP response code 503)</p>
7
+ <p>Reason: <span style="color: #F00;"><?php echo $reason; ?></span></p>
8
+ <p style="width: 600px;"><b>Important note for site admins: </b>If you are the administrator of this website note that your access has been limited because you broke one of the Wordfence advanced blocking rules.
9
+ The reason your access was limited is: <b>"<?php echo $reason; ?>"</b>.
10
+ <br /><br />
11
+ If this is a false positive, meaning that your access to your own site has been limited incorrectly, then you
12
+ will need to regain access to your site, go to the Wordfence "options" page, go to the section for Rate Limiting Rules and disable the rule that caused you to be blocked. For example,
13
+ if you were blocked because it was detected that you are a fake Google crawler, then disable the rule that blocks fake google crawlers. Or if you were blocked because you
14
+ were accessing your site too quickly, then increase the number of accesses allowed per minute.
15
+ <br /><br />
16
+ If you're still having trouble, then simply disable the Wordfence advanced blocking and you will
17
+ still benefit from the other security features that Wordfence provides.
18
+ </p>
19
+
20
+ <?php
21
+ $nonce = $waf->createNonce('wf-form');
22
+ if (!empty($homeURL) && !empty($nonce)) : ?>
23
+ <br /><br />
24
+
25
+ If you are a site administrator and have been accidentally locked out, please enter your email in the box below and click "Send". If the email address you enter belongs to a known site administrator or someone set to receive Wordfence alerts, we will send you an email to help you regain access. <a href="https://docs.wordfence.com/en/Help!_I_locked_myself_out_and_can't_get_back_in._What_can_I_do%3F" target="_blank">Please read this FAQ entry if this does not work.</a>
26
+ <br /><br />
27
+ <form method="POST" action="<?php echo $homeURL; ?>?_wfsf=unlockEmail">
28
+ <input type="hidden" name="nonce" value="<?php echo $nonce; ?>" />
29
+ <input type="text" size="50" name="email" value="" maxlength="255" />&nbsp;<input type="submit" name="s" value="Send me an unlock email" />
30
+ </form>
31
+ <?php endif; ?>
32
+ <br /><br />
33
+
34
+ <address>This response was generated by Wordfence.</address>
35
+ </body></html>
waf/bootstrap.php CHANGED
@@ -9,10 +9,11 @@ if (!defined('WFWAF_AUTO_PREPEND')) {
9
  }
10
 
11
  require_once dirname(__FILE__) . '/wfWAFUserIPRange.php';
 
12
  require_once dirname(__FILE__) . '/../vendor/wordfence/wf-waf/src/init.php';
13
 
14
  class wfWAFWordPressRequest extends wfWAFRequest {
15
-
16
  /**
17
  * @param wfWAFRequest|null $request
18
  * @return wfWAFRequest
@@ -76,6 +77,12 @@ class wfWAFWordPressObserver extends wfWAFBaseObserver {
76
  }
77
  }
78
  }
 
 
 
 
 
 
79
  }
80
 
81
  public function afterRunRules()
@@ -93,6 +100,12 @@ class wfWAFWordPressObserver extends wfWAFBaseObserver {
93
  }
94
  }
95
  }
 
 
 
 
 
 
96
  }
97
  }
98
 
@@ -108,15 +121,41 @@ class wfWAFWordPress extends wfWAF {
108
  * @param wfWAFBlockException $e
109
  * @param int $httpCode
110
  */
111
- public function blockAction($e, $httpCode = 403) {
112
- if ($this->isInLearningMode()) {
113
  register_shutdown_function(array(
114
  $this, 'whitelistFailedRulesIfNot404',
115
  ));
116
  $this->getStorageEngine()->logAttack($e->getFailedRules(), $e->getParamKey(), $e->getParamValue(), $e->getRequest());
117
  $this->setLearningModeAttackException($e);
118
  } else {
119
- parent::blockAction($e, $httpCode);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
120
  }
121
  }
122
 
@@ -124,15 +163,41 @@ class wfWAFWordPress extends wfWAF {
124
  * @param wfWAFBlockXSSException $e
125
  * @param int $httpCode
126
  */
127
- public function blockXSSAction($e, $httpCode = 403) {
128
- if ($this->isInLearningMode()) {
129
  register_shutdown_function(array(
130
  $this, 'whitelistFailedRulesIfNot404',
131
  ));
132
  $this->getStorageEngine()->logAttack($e->getFailedRules(), $e->getParamKey(), $e->getParamValue(), $e->getRequest());
133
  $this->setLearningModeAttackException($e);
134
  } else {
135
- parent::blockXSSAction($e, $httpCode);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
136
  }
137
  }
138
 
@@ -185,6 +250,26 @@ class wfWAFWordPress extends wfWAF {
185
  return false;
186
  }
187
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
188
  public function uninstall() {
189
  parent::uninstall();
190
  @unlink(rtrim(WFWAF_LOG_PATH . '/') . '/.htaccess');
9
  }
10
 
11
  require_once dirname(__FILE__) . '/wfWAFUserIPRange.php';
12
+ require_once dirname(__FILE__) . '/wfWAFIPBlocksController.php';
13
  require_once dirname(__FILE__) . '/../vendor/wordfence/wf-waf/src/init.php';
14
 
15
  class wfWAFWordPressRequest extends wfWAFRequest {
16
+
17
  /**
18
  * @param wfWAFRequest|null $request
19
  * @return wfWAFRequest
77
  }
78
  }
79
  }
80
+
81
+ // Check plugin blocking
82
+ if ($result = wfWAF::getInstance()->willPerformFinalAction(wfWAF::getInstance()->getRequest())) {
83
+ if ($result === true) { $result = 'Not available'; } // Should not happen but can if the reason in the blocks table is empty
84
+ wfWAF::getInstance()->getRequest()->setMetadata(array_merge(wfWAF::getInstance()->getRequest()->getMetadata(), array('finalAction' => $result)));
85
+ }
86
  }
87
 
88
  public function afterRunRules()
100
  }
101
  }
102
  }
103
+
104
+ if ($reason = wfWAF::getInstance()->getRequest()->getMetadata('finalAction')) {
105
+ $e = new wfWAFBlockException($reason['action']);
106
+ $e->setRequest(wfWAF::getInstance()->getRequest());
107
+ throw $e;
108
+ }
109
  }
110
  }
111
 
121
  * @param wfWAFBlockException $e
122
  * @param int $httpCode
123
  */
124
+ public function blockAction($e, $httpCode = 403, $redirect = false) {
125
+ if ($this->isInLearningMode() && !$e->getRequest()->getMetadata('finalAction')) {
126
  register_shutdown_function(array(
127
  $this, 'whitelistFailedRulesIfNot404',
128
  ));
129
  $this->getStorageEngine()->logAttack($e->getFailedRules(), $e->getParamKey(), $e->getParamValue(), $e->getRequest());
130
  $this->setLearningModeAttackException($e);
131
  } else {
132
+ $failedRules = $e->getFailedRules();
133
+ if (empty($failedRules)) {
134
+ $finalAction = $e->getRequest()->getMetadata('finalAction');
135
+ if (is_array($finalAction)) {
136
+ $finalAction = $finalAction['action'];
137
+ if ($finalAction == wfWAFIPBlocksController::WFWAF_BLOCK_COUNTRY_REDIR) {
138
+ $redirect = wfWAFIPBlocksController::currentController()->countryRedirURL();
139
+ }
140
+ else if ($finalAction == wfWAFIPBlocksController::WFWAF_BLOCK_COUNTRY_BYPASS_REDIR) {
141
+ $redirect = wfWAFIPBlocksController::currentController()->countryBypassRedirURL();
142
+ }
143
+ else if ($finalAction == wfWAFIPBlocksController::WFWAF_BLOCK_UAREFIPRANGE) {
144
+ wfWAF::getInstance()->getRequest()->setMetadata(array_merge(wfWAF::getInstance()->getRequest()->getMetadata(), array('503Reason' => 'Advanced blocking in effect.', '503Time' => 3600)));
145
+ $httpCode = 503;
146
+ }
147
+ else if ($finalAction == wfWAFIPBlocksController::WFWAF_BLOCK_COUNTRY) {
148
+ wfWAF::getInstance()->getRequest()->setMetadata(array_merge(wfWAF::getInstance()->getRequest()->getMetadata(), array('503Reason' => 'Access from your area has been temporarily limited for security reasons.', '503Time' => 3600)));
149
+ $httpCode = 503;
150
+ }
151
+ else if (is_string($finalAction) && strlen($finalAction) > 0) {
152
+ wfWAF::getInstance()->getRequest()->setMetadata(array_merge(wfWAF::getInstance()->getRequest()->getMetadata(), array('503Reason' => $finalAction, '503Time' => 3600)));
153
+ $httpCode = 503;
154
+ }
155
+ }
156
+ }
157
+
158
+ parent::blockAction($e, $httpCode, $redirect);
159
  }
160
  }
161
 
163
  * @param wfWAFBlockXSSException $e
164
  * @param int $httpCode
165
  */
166
+ public function blockXSSAction($e, $httpCode = 403, $redirect = false) {
167
+ if ($this->isInLearningMode() && !$e->getRequest()->getMetadata('finalAction')) {
168
  register_shutdown_function(array(
169
  $this, 'whitelistFailedRulesIfNot404',
170
  ));
171
  $this->getStorageEngine()->logAttack($e->getFailedRules(), $e->getParamKey(), $e->getParamValue(), $e->getRequest());
172
  $this->setLearningModeAttackException($e);
173
  } else {
174
+ $failedRules = $e->getFailedRules();
175
+ if (empty($failedRules)) {
176
+ $finalAction = $e->getRequest()->getMetadata('finalAction');
177
+ if (is_array($finalAction)) {
178
+ $finalAction = $finalAction['action'];
179
+ if ($finalAction == wfWAFIPBlocksController::WFWAF_BLOCK_COUNTRY_REDIR) {
180
+ $redirect = wfWAFIPBlocksController::currentController()->countryRedirURL();
181
+ }
182
+ else if ($finalAction == wfWAFIPBlocksController::WFWAF_BLOCK_COUNTRY_BYPASS_REDIR) {
183
+ $redirect = wfWAFIPBlocksController::currentController()->countryBypassRedirURL();
184
+ }
185
+ else if ($finalAction == wfWAFIPBlocksController::WFWAF_BLOCK_UAREFIPRANGE) {
186
+ wfWAF::getInstance()->getRequest()->setMetadata(array_merge(wfWAF::getInstance()->getRequest()->getMetadata(), array('503Reason' => 'Advanced blocking in effect.', '503Time' => 3600)));
187
+ $httpCode = 503;
188
+ }
189
+ else if ($finalAction == wfWAFIPBlocksController::WFWAF_BLOCK_COUNTRY) {
190
+ wfWAF::getInstance()->getRequest()->setMetadata(array_merge(wfWAF::getInstance()->getRequest()->getMetadata(), array('503Reason' => 'Access from your area has been temporarily limited for security reasons.', '503Time' => 3600)));
191
+ $httpCode = 503;
192
+ }
193
+ else if (is_string($finalAction) && strlen($finalAction) > 0) {
194
+ wfWAF::getInstance()->getRequest()->setMetadata(array_merge(wfWAF::getInstance()->getRequest()->getMetadata(), array('503Reason' => $finalAction, '503Time' => 3600)));
195
+ $httpCode = 503;
196
+ }
197
+ }
198
+ }
199
+
200
+ parent::blockXSSAction($e, $httpCode, $redirect);
201
  }
202
  }
203
 
250
  return false;
251
  }
252
 
253
+ /**
254
+ * @param wfWAFRequest $request
255
+ * @return bool|string false if it should not be blocked, otherwise true or a reason for blocking
256
+ */
257
+ public function willPerformFinalAction($request) {
258
+ try {
259
+ $disableWAFIPBlocking = $this->getStorageEngine()->getConfig('disableWAFIPBlocking');
260
+ $advancedBlockingEnabled = $this->getStorageEngine()->getConfig('advancedBlockingEnabled');
261
+ }
262
+ catch (Exception $e) {
263
+ return false;
264
+ }
265
+
266
+ if ($disableWAFIPBlocking || !$advancedBlockingEnabled) {
267
+ return false;
268
+ }
269
+
270
+ return wfWAFIPBlocksController::currentController()->shouldBlockRequest($request);
271
+ }
272
+
273
  public function uninstall() {
274
  parent::uninstall();
275
  @unlink(rtrim(WFWAF_LOG_PATH . '/') . '/.htaccess');
waf/wfWAFGeoIP.php ADDED
@@ -0,0 +1,765 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 2; tab-width: 2 -*- */
4
+ /* geoip.inc
5
+ *
6
+ * Copyright (C) 2007 MaxMind LLC
7
+ *
8
+ * This library is free software; you can redistribute it and/or
9
+ * modify it under the terms of the GNU Lesser General Public
10
+ * License as published by the Free Software Foundation; either
11
+ * version 2.1 of the License, or (at your option) any later version.
12
+ *
13
+ * This library is distributed in the hope that it will be useful,
14
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
15
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16
+ * Lesser General Public License for more details.
17
+ *
18
+ * You should have received a copy of the GNU Lesser General Public
19
+ * License along with this library; if not, write to the Free Software
20
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
21
+ */
22
+ if(! class_exists('wfWAFGeoIP')){
23
+ define("GEOIP_COUNTRY_BEGIN", 16776960);
24
+ define("GEOIP_STATE_BEGIN_REV0", 16700000);
25
+ define("GEOIP_STATE_BEGIN_REV1", 16000000);
26
+ define("GEOIP_STANDARD", 0);
27
+ define("GEOIP_MEMORY_CACHE", 1);
28
+ define("GEOIP_SHARED_MEMORY", 2);
29
+ define("STRUCTURE_INFO_MAX_SIZE", 20);
30
+ define("DATABASE_INFO_MAX_SIZE", 100);
31
+ define("GEOIP_COUNTRY_EDITION", 106);
32
+ define("GEOIP_PROXY_EDITION", 8);
33
+ define("GEOIP_ASNUM_EDITION", 9);
34
+ define("GEOIP_NETSPEED_EDITION", 10);
35
+ define("GEOIP_REGION_EDITION_REV0", 112);
36
+ define("GEOIP_REGION_EDITION_REV1", 3);
37
+ define("GEOIP_CITY_EDITION_REV0", 111);
38
+ define("GEOIP_CITY_EDITION_REV1", 2);
39
+ define("GEOIP_ORG_EDITION", 110);
40
+ define("GEOIP_ISP_EDITION", 4);
41
+ define("SEGMENT_RECORD_LENGTH", 3);
42
+ define("STANDARD_RECORD_LENGTH", 3);
43
+ define("ORG_RECORD_LENGTH", 4);
44
+ define("MAX_RECORD_LENGTH", 4);
45
+ define("MAX_ORG_RECORD_LENGTH", 300);
46
+ define("GEOIP_SHM_KEY", 0x4f415401);
47
+ define("US_OFFSET", 1);
48
+ define("CANADA_OFFSET", 677);
49
+ define("WORLD_OFFSET", 1353);
50
+ define("FIPS_RANGE", 360);
51
+ define("GEOIP_UNKNOWN_SPEED", 0);
52
+ define("GEOIP_DIALUP_SPEED", 1);
53
+ define("GEOIP_CABLEDSL_SPEED", 2);
54
+ define("GEOIP_CORPORATE_SPEED", 3);
55
+ define("GEOIP_DOMAIN_EDITION", 11);
56
+ define("GEOIP_COUNTRY_EDITION_V6", 12);
57
+ define("GEOIP_LOCATIONA_EDITION", 13);
58
+ define("GEOIP_ACCURACYRADIUS_EDITION", 14);
59
+ define("GEOIP_CITYCOMBINED_EDITION", 15);
60
+ define("GEOIP_CITY_EDITION_REV1_V6", 30);
61
+ define("GEOIP_CITY_EDITION_REV0_V6",31);
62
+ define("GEOIP_NETSPEED_EDITION_REV1",32);
63
+ define("GEOIP_NETSPEED_EDITION_REV1_V6",33);
64
+ define("GEOIP_USERTYPE_EDITION",28);
65
+ define("GEOIP_USERTYPE_EDITION_V6",29);
66
+ define("GEOIP_ASNUM_EDITION_V6",21);
67
+ define("GEOIP_ISP_EDITION_V6",22);
68
+ define("GEOIP_ORG_EDITION_V6",23);
69
+ define("GEOIP_DOMAIN_EDITION_V6",24);
70
+
71
+ define("CITYCOMBINED_FIXED_RECORD", 7 );
72
+
73
+ class wfWAFGeoIP {
74
+ var $flags;
75
+ var $filehandle;
76
+ var $memory_buffer;
77
+ var $databaseType;
78
+ var $databaseSegments;
79
+ var $record_length;
80
+ var $shmid;
81
+ var $GEOIP_COUNTRY_CODE_TO_NUMBER = array(
82
+ "" => 0, "AP" => 1, "EU" => 2, "AD" => 3, "AE" => 4, "AF" => 5,
83
+ "AG" => 6, "AI" => 7, "AL" => 8, "AM" => 9, "CW" => 10, "AO" => 11,
84
+ "AQ" => 12, "AR" => 13, "AS" => 14, "AT" => 15, "AU" => 16, "AW" => 17,
85
+ "AZ" => 18, "BA" => 19, "BB" => 20, "BD" => 21, "BE" => 22, "BF" => 23,
86
+ "BG" => 24, "BH" => 25, "BI" => 26, "BJ" => 27, "BM" => 28, "BN" => 29,
87
+ "BO" => 30, "BR" => 31, "BS" => 32, "BT" => 33, "BV" => 34, "BW" => 35,
88
+ "BY" => 36, "BZ" => 37, "CA" => 38, "CC" => 39, "CD" => 40, "CF" => 41,
89
+ "CG" => 42, "CH" => 43, "CI" => 44, "CK" => 45, "CL" => 46, "CM" => 47,
90
+ "CN" => 48, "CO" => 49, "CR" => 50, "CU" => 51, "CV" => 52, "CX" => 53,
91
+ "CY" => 54, "CZ" => 55, "DE" => 56, "DJ" => 57, "DK" => 58, "DM" => 59,
92
+ "DO" => 60, "DZ" => 61, "EC" => 62, "EE" => 63, "EG" => 64, "EH" => 65,
93
+ "ER" => 66, "ES" => 67, "ET" => 68, "FI" => 69, "FJ" => 70, "FK" => 71,
94
+ "FM" => 72, "FO" => 73, "FR" => 74, "SX" => 75, "GA" => 76, "GB" => 77,
95
+ "GD" => 78, "GE" => 79, "GF" => 80, "GH" => 81, "GI" => 82, "GL" => 83,
96
+ "GM" => 84, "GN" => 85, "GP" => 86, "GQ" => 87, "GR" => 88, "GS" => 89,
97
+ "GT" => 90, "GU" => 91, "GW" => 92, "GY" => 93, "HK" => 94, "HM" => 95,
98
+ "HN" => 96, "HR" => 97, "HT" => 98, "HU" => 99, "ID" => 100, "IE" => 101,
99
+ "IL" => 102, "IN" => 103, "IO" => 104, "IQ" => 105, "IR" => 106, "IS" => 107,
100
+ "IT" => 108, "JM" => 109, "JO" => 110, "JP" => 111, "KE" => 112, "KG" => 113,
101
+ "KH" => 114, "KI" => 115, "KM" => 116, "KN" => 117, "KP" => 118, "KR" => 119,
102
+ "KW" => 120, "KY" => 121, "KZ" => 122, "LA" => 123, "LB" => 124, "LC" => 125,
103
+ "LI" => 126, "LK" => 127, "LR" => 128, "LS" => 129, "LT" => 130, "LU" => 131,
104
+ "LV" => 132, "LY" => 133, "MA" => 134, "MC" => 135, "MD" => 136, "MG" => 137,
105
+ "MH" => 138, "MK" => 139, "ML" => 140, "MM" => 141, "MN" => 142, "MO" => 143,
106
+ "MP" => 144, "MQ" => 145, "MR" => 146, "MS" => 147, "MT" => 148, "MU" => 149,
107
+ "MV" => 150, "MW" => 151, "MX" => 152, "MY" => 153, "MZ" => 154, "NA" => 155,
108
+ "NC" => 156, "NE" => 157, "NF" => 158, "NG" => 159, "NI" => 160, "NL" => 161,
109
+ "NO" => 162, "NP" => 163, "NR" => 164, "NU" => 165, "NZ" => 166, "OM" => 167,
110
+ "PA" => 168, "PE" => 169, "PF" => 170, "PG" => 171, "PH" => 172, "PK" => 173,
111
+ "PL" => 174, "PM" => 175, "PN" => 176, "PR" => 177, "PS" => 178, "PT" => 179,
112
+ "PW" => 180, "PY" => 181, "QA" => 182, "RE" => 183, "RO" => 184, "RU" => 185,
113
+ "RW" => 186, "SA" => 187, "SB" => 188, "SC" => 189, "SD" => 190, "SE" => 191,
114
+ "SG" => 192, "SH" => 193, "SI" => 194, "SJ" => 195, "SK" => 196, "SL" => 197,
115
+ "SM" => 198, "SN" => 199, "SO" => 200, "SR" => 201, "ST" => 202, "SV" => 203,
116
+ "SY" => 204, "SZ" => 205, "TC" => 206, "TD" => 207, "TF" => 208, "TG" => 209,
117
+ "TH" => 210, "TJ" => 211, "TK" => 212, "TM" => 213, "TN" => 214, "TO" => 215,
118
+ "TL" => 216, "TR" => 217, "TT" => 218, "TV" => 219, "TW" => 220, "TZ" => 221,
119
+ "UA" => 222, "UG" => 223, "UM" => 224, "US" => 225, "UY" => 226, "UZ" => 227,
120
+ "VA" => 228, "VC" => 229, "VE" => 230, "VG" => 231, "VI" => 232, "VN" => 233,
121
+ "VU" => 234, "WF" => 235, "WS" => 236, "YE" => 237, "YT" => 238, "RS" => 239,
122
+ "ZA" => 240, "ZM" => 241, "ME" => 242, "ZW" => 243, "A1" => 244, "A2" => 245,
123
+ "O1" => 246, "AX" => 247, "GG" => 248, "IM" => 249, "JE" => 250, "BL" => 251,
124
+ "MF" => 252, "BQ" => 253,
125
+ );
126
+ var $GEOIP_COUNTRY_CODES = array(
127
+ "","AP","EU","AD","AE","AF","AG","AI","AL","AM","CW",
128
+ "AO","AQ","AR","AS","AT","AU","AW","AZ","BA","BB",
129
+ "BD","BE","BF","BG","BH","BI","BJ","BM","BN","BO",
130
+ "BR","BS","BT","BV","BW","BY","BZ","CA","CC","CD",
131
+ "CF","CG","CH","CI","CK","CL","CM","CN","CO","CR",
132
+ "CU","CV","CX","CY","CZ","DE","DJ","DK","DM","DO",
133
+ "DZ","EC","EE","EG","EH","ER","ES","ET","FI","FJ",
134
+ "FK","FM","FO","FR","SX","GA","GB","GD","GE","GF",
135
+ "GH","GI","GL","GM","GN","GP","GQ","GR","GS","GT",
136
+ "GU","GW","GY","HK","HM","HN","HR","HT","HU","ID",
137
+ "IE","IL","IN","IO","IQ","IR","IS","IT","JM","JO",
138
+ "JP","KE","KG","KH","KI","KM","KN","KP","KR","KW",
139
+ "KY","KZ","LA","LB","LC","LI","LK","LR","LS","LT",
140
+ "LU","LV","LY","MA","MC","MD","MG","MH","MK","ML",
141
+ "MM","MN","MO","MP","MQ","MR","MS","MT","MU","MV",
142
+ "MW","MX","MY","MZ","NA","NC","NE","NF","NG","NI",
143
+ "NL","NO","NP","NR","NU","NZ","OM","PA","PE","PF",
144
+ "PG","PH","PK","PL","PM","PN","PR","PS","PT","PW",
145
+ "PY","QA","RE","RO","RU","RW","SA","SB","SC","SD",
146
+ "SE","SG","SH","SI","SJ","SK","SL","SM","SN","SO",
147
+ "SR","ST","SV","SY","SZ","TC","TD","TF","TG","TH",
148
+ "TJ","TK","TM","TN","TO","TL","TR","TT","TV","TW",
149
+ "TZ","UA","UG","UM","US","UY","UZ","VA","VC","VE",
150
+ "VG","VI","VN","VU","WF","WS","YE","YT","RS","ZA",
151
+ "ZM","ME","ZW","A1","A2","O1","AX","GG","IM","JE",
152
+ "BL","MF", "BQ");
153
+ var $GEOIP_COUNTRY_CODES3 = array(
154
+ "","AP","EU","AND","ARE","AFG","ATG","AIA","ALB","ARM","CUW",
155
+ "AGO","ATA","ARG","ASM","AUT","AUS","ABW","AZE","BIH","BRB",
156
+ "BGD","BEL","BFA","BGR","BHR","BDI","BEN","BMU","BRN","BOL",
157
+ "BRA","BHS","BTN","BVT","BWA","BLR","BLZ","CAN","CCK","COD",
158
+ "CAF","COG","CHE","CIV","COK","CHL","CMR","CHN","COL","CRI",
159
+ "CUB","CPV","CXR","CYP","CZE","DEU","DJI","DNK","DMA","DOM",
160
+ "DZA","ECU","EST","EGY","ESH","ERI","ESP","ETH","FIN","FJI",
161
+ "FLK","FSM","FRO","FRA","SXM","GAB","GBR","GRD","GEO","GUF",
162
+ "GHA","GIB","GRL","GMB","GIN","GLP","GNQ","GRC","SGS","GTM",
163
+ "GUM","GNB","GUY","HKG","HMD","HND","HRV","HTI","HUN","IDN",
164
+ "IRL","ISR","IND","IOT","IRQ","IRN","ISL","ITA","JAM","JOR",
165
+ "JPN","KEN","KGZ","KHM","KIR","COM","KNA","PRK","KOR","KWT",
166
+ "CYM","KAZ","LAO","LBN","LCA","LIE","LKA","LBR","LSO","LTU",
167
+ "LUX","LVA","LBY","MAR","MCO","MDA","MDG","MHL","MKD","MLI",
168
+ "MMR","MNG","MAC","MNP","MTQ","MRT","MSR","MLT","MUS","MDV",
169
+ "MWI","MEX","MYS","MOZ","NAM","NCL","NER","NFK","NGA","NIC",
170
+ "NLD","NOR","NPL","NRU","NIU","NZL","OMN","PAN","PER","PYF",
171
+ "PNG","PHL","PAK","POL","SPM","PCN","PRI","PSE","PRT","PLW",
172
+ "PRY","QAT","REU","ROU","RUS","RWA","SAU","SLB","SYC","SDN",
173
+ "SWE","SGP","SHN","SVN","SJM","SVK","SLE","SMR","SEN","SOM",
174
+ "SUR","STP","SLV","SYR","SWZ","TCA","TCD","ATF","TGO","THA",
175
+ "TJK","TKL","TKM","TUN","TON","TLS","TUR","TTO","TUV","TWN",
176
+ "TZA","UKR","UGA","UMI","USA","URY","UZB","VAT","VCT","VEN",
177
+ "VGB","VIR","VNM","VUT","WLF","WSM","YEM","MYT","SRB","ZAF",
178
+ "ZMB","MNE","ZWE","A1","A2","O1","ALA","GGY","IMN","JEY",
179
+ "BLM","MAF", "BES"
180
+ );
181
+ var $GEOIP_COUNTRY_NAMES = array(
182
+ "","Asia/Pacific Region","Europe","Andorra","United Arab Emirates","Afghanistan","Antigua and Barbuda","Anguilla","Albania","Armenia","Curacao",
183
+ "Angola","Antarctica","Argentina","American Samoa","Austria","Australia","Aruba","Azerbaijan","Bosnia and Herzegovina","Barbados",
184
+ "Bangladesh","Belgium","Burkina Faso","Bulgaria","Bahrain","Burundi","Benin","Bermuda","Brunei Darussalam","Bolivia",
185
+ "Brazil","Bahamas","Bhutan","Bouvet Island","Botswana","Belarus","Belize","Canada","Cocos (Keeling) Islands","Congo, The Democratic Republic of the",
186
+ "Central African Republic","Congo","Switzerland","Cote D'Ivoire","Cook Islands","Chile","Cameroon","China","Colombia","Costa Rica",
187
+ "Cuba","Cape Verde","Christmas Island","Cyprus","Czech Republic","Germany","Djibouti","Denmark","Dominica","Dominican Republic",
188
+ "Algeria","Ecuador","Estonia","Egypt","Western Sahara","Eritrea","Spain","Ethiopia","Finland","Fiji",
189
+ "Falkland Islands (Malvinas)","Micronesia, Federated States of","Faroe Islands","France","Sint Maarten (Dutch part)","Gabon","United Kingdom","Grenada","Georgia","French Guiana",
190
+ "Ghana","Gibraltar","Greenland","Gambia","Guinea","Guadeloupe","Equatorial Guinea","Greece","South Georgia and the South Sandwich Islands","Guatemala",
191
+ "Guam","Guinea-Bissau","Guyana","Hong Kong","Heard Island and McDonald Islands","Honduras","Croatia","Haiti","Hungary","Indonesia",
192
+ "Ireland","Israel","India","British Indian Ocean Territory","Iraq","Iran, Islamic Republic of","Iceland","Italy","Jamaica","Jordan",
193
+ "Japan","Kenya","Kyrgyzstan","Cambodia","Kiribati","Comoros","Saint Kitts and Nevis","Korea, Democratic People's Republic of","Korea, Republic of","Kuwait",
194
+ "Cayman Islands","Kazakhstan","Lao People's Democratic Republic","Lebanon","Saint Lucia","Liechtenstein","Sri Lanka","Liberia","Lesotho","Lithuania",
195
+ "Luxembourg","Latvia","Libya","Morocco","Monaco","Moldova, Republic of","Madagascar","Marshall Islands","Macedonia","Mali",
196
+ "Myanmar","Mongolia","Macau","Northern Mariana Islands","Martinique","Mauritania","Montserrat","Malta","Mauritius","Maldives",
197
+ "Malawi","Mexico","Malaysia","Mozambique","Namibia","New Caledonia","Niger","Norfolk Island","Nigeria","Nicaragua",
198
+ "Netherlands","Norway","Nepal","Nauru","Niue","New Zealand","Oman","Panama","Peru","French Polynesia",
199
+ "Papua New Guinea","Philippines","Pakistan","Poland","Saint Pierre and Miquelon","Pitcairn Islands","Puerto Rico","Palestinian Territory","Portugal","Palau",
200
+ "Paraguay","Qatar","Reunion","Romania","Russian Federation","Rwanda","Saudi Arabia","Solomon Islands","Seychelles","Sudan",
201
+ "Sweden","Singapore","Saint Helena","Slovenia","Svalbard and Jan Mayen","Slovakia","Sierra Leone","San Marino","Senegal","Somalia","Suriname",
202
+ "Sao Tome and Principe","El Salvador","Syrian Arab Republic","Swaziland","Turks and Caicos Islands","Chad","French Southern Territories","Togo","Thailand",
203
+ "Tajikistan","Tokelau","Turkmenistan","Tunisia","Tonga","Timor-Leste","Turkey","Trinidad and Tobago","Tuvalu","Taiwan",
204
+ "Tanzania, United Republic of","Ukraine","Uganda","United States Minor Outlying Islands","United States","Uruguay","Uzbekistan","Holy See (Vatican City State)","Saint Vincent and the Grenadines","Venezuela",
205
+ "Virgin Islands, British","Virgin Islands, U.S.","Vietnam","Vanuatu","Wallis and Futuna","Samoa","Yemen","Mayotte","Serbia","South Africa",
206
+ "Zambia","Montenegro","Zimbabwe","Anonymous Proxy","Satellite Provider","Other","Aland Islands","Guernsey","Isle of Man","Jersey",
207
+ "Saint Barthelemy","Saint Martin", "Bonaire, Saint Eustatius and Saba"
208
+ );
209
+
210
+ var $GEOIP_CONTINENT_CODES = array(
211
+ "--", "AS","EU","EU","AS","AS","NA","NA","EU","AS","NA",
212
+ "AF","AN","SA","OC","EU","OC","NA","AS","EU","NA",
213
+ "AS","EU","AF","EU","AS","AF","AF","NA","AS","SA",
214
+ "SA","NA","AS","AN","AF","EU","NA","NA","AS","AF",
215
+ "AF","AF","EU","AF","OC","SA","AF","AS","SA","NA",
216
+ "NA","AF","AS","AS","EU","EU","AF","EU","NA","NA",
217
+ "AF","SA","EU","AF","AF","AF","EU","AF","EU","OC",
218
+ "SA","OC","EU","EU","NA","AF","EU","NA","AS","SA",
219
+ "AF","EU","NA","AF","AF","NA","AF","EU","AN","NA",
220
+ "OC","AF","SA","AS","AN","NA","EU","NA","EU","AS",
221
+ "EU","AS","AS","AS","AS","AS","EU","EU","NA","AS",
222
+ "AS","AF","AS","AS","OC","AF","NA","AS","AS","AS",
223
+ "NA","AS","AS","AS","NA","EU","AS","AF","AF","EU",
224
+ "EU","EU","AF","AF","EU","EU","AF","OC","EU","AF",
225
+ "AS","AS","AS","OC","NA","AF","NA","EU","AF","AS",
226
+ "AF","NA","AS","AF","AF","OC","AF","OC","AF","NA",
227
+ "EU","EU","AS","OC","OC","OC","AS","NA","SA","OC",
228
+ "OC","AS","AS","EU","NA","OC","NA","AS","EU","OC",
229
+ "SA","AS","AF","EU","EU","AF","AS","OC","AF","AF",
230
+ "EU","AS","AF","EU","EU","EU","AF","EU","AF","AF",
231
+ "SA","AF","NA","AS","AF","NA","AF","AN","AF","AS",
232
+ "AS","OC","AS","AF","OC","AS","EU","NA","OC","AS",
233
+ "AF","EU","AF","OC","NA","SA","AS","EU","NA","SA",
234
+ "NA","NA","AS","OC","OC","OC","AS","AF","EU","AF",
235
+ "AF","EU","AF","--","--","--","EU","EU","EU","EU",
236
+ "NA","NA","NA"
237
+ );
238
+
239
+ }
240
+ if(! function_exists('geoip_load_shared_mem')){
241
+ function geoip_load_shared_mem ($file) {
242
+
243
+ $fp = fopen($file, "rb");
244
+ if (!$fp) {
245
+ print "error opening $file: $php_errormsg\n";
246
+ exit;
247
+ }
248
+ $s_array = fstat($fp);
249
+ $size = $s_array['size'];
250
+ if ($shmid = @shmop_open (GEOIP_SHM_KEY, "w", 0, 0)) {
251
+ shmop_delete ($shmid);
252
+ shmop_close ($shmid);
253
+ }
254
+ $shmid = shmop_open (GEOIP_SHM_KEY, "c", 0644, $size);
255
+ shmop_write ($shmid, fread($fp, $size), 0);
256
+ shmop_close ($shmid);
257
+ }
258
+ }
259
+
260
+ if(! function_exists('')){
261
+ function _setup_segments($gi){
262
+ $gi->databaseType = GEOIP_COUNTRY_EDITION;
263
+ $gi->record_length = STANDARD_RECORD_LENGTH;
264
+ if ($gi->flags & GEOIP_SHARED_MEMORY) {
265
+ $offset = @shmop_size ($gi->shmid) - 3;
266
+ for ($i = 0; $i < STRUCTURE_INFO_MAX_SIZE; $i++) {
267
+ $delim = @shmop_read ($gi->shmid, $offset, 3);
268
+ $offset += 3;
269
+ if ($delim == (chr(255).chr(255).chr(255))) {
270
+ $gi->databaseType = ord(@shmop_read ($gi->shmid, $offset, 1));
271
+ $offset++;
272
+
273
+ if ($gi->databaseType == GEOIP_REGION_EDITION_REV0){
274
+ $gi->databaseSegments = GEOIP_STATE_BEGIN_REV0;
275
+ } else if ($gi->databaseType == GEOIP_REGION_EDITION_REV1){
276
+ $gi->databaseSegments = GEOIP_STATE_BEGIN_REV1;
277
+ } else if (($gi->databaseType == GEOIP_CITY_EDITION_REV0)||
278
+ ($gi->databaseType == GEOIP_CITY_EDITION_REV1)
279
+ || ($gi->databaseType == GEOIP_ORG_EDITION)
280
+ || ($gi->databaseType == GEOIP_ORG_EDITION_V6)
281
+ || ($gi->databaseType == GEOIP_DOMAIN_EDITION)
282
+ || ($gi->databaseType == GEOIP_DOMAIN_EDITION_V6)
283
+ || ($gi->databaseType == GEOIP_ISP_EDITION)
284
+ || ($gi->databaseType == GEOIP_ISP_EDITION_V6)
285
+ || ($gi->databaseType == GEOIP_USERTYPE_EDITION)
286
+ || ($gi->databaseType == GEOIP_USERTYPE_EDITION_V6)
287
+ || ($gi->databaseType == GEOIP_LOCATIONA_EDITION)
288
+ || ($gi->databaseType == GEOIP_ACCURACYRADIUS_EDITION)
289
+ || ($gi->databaseType == GEOIP_CITY_EDITION_REV0_V6)
290
+ || ($gi->databaseType == GEOIP_CITY_EDITION_REV1_V6)
291
+ || ($gi->databaseType == GEOIP_NETSPEED_EDITION_REV1)
292
+ || ($gi->databaseType == GEOIP_NETSPEED_EDITION_REV1_V6)
293
+ || ($gi->databaseType == GEOIP_ASNUM_EDITION)
294
+ || ($gi->databaseType == GEOIP_ASNUM_EDITION_V6)){
295
+ $gi->databaseSegments = 0;
296
+ $buf = @shmop_read ($gi->shmid, $offset, SEGMENT_RECORD_LENGTH);
297
+ for ($j = 0;$j < SEGMENT_RECORD_LENGTH;$j++){
298
+ $gi->databaseSegments += (ord($buf[$j]) << ($j * 8));
299
+ }
300
+ if (($gi->databaseType == GEOIP_ORG_EDITION)
301
+ || ($gi->databaseType == GEOIP_ORG_EDITION_V6)
302
+ || ($gi->databaseType == GEOIP_DOMAIN_EDITION)
303
+ || ($gi->databaseType == GEOIP_DOMAIN_EDITION_V6)
304
+ || ($gi->databaseType == GEOIP_ISP_EDITION)
305
+ || ($gi->databaseType == GEOIP_ISP_EDITION_V6)) {
306
+ $gi->record_length = ORG_RECORD_LENGTH;
307
+ }
308
+ }
309
+ break;
310
+ } else {
311
+ $offset -= 4;
312
+ }
313
+ }
314
+ if (($gi->databaseType == GEOIP_COUNTRY_EDITION)||
315
+ ($gi->databaseType == GEOIP_COUNTRY_EDITION_V6)||
316
+ ($gi->databaseType == GEOIP_PROXY_EDITION)||
317
+ ($gi->databaseType == GEOIP_NETSPEED_EDITION)){
318
+ $gi->databaseSegments = GEOIP_COUNTRY_BEGIN;
319
+ }
320
+ } else {
321
+ $filepos = ftell($gi->filehandle);
322
+ fseek($gi->filehandle, -3, SEEK_END);
323
+ for ($i = 0; $i < STRUCTURE_INFO_MAX_SIZE; $i++) {
324
+ $delim = fread($gi->filehandle,3);
325
+ if ($delim == (chr(255).chr(255).chr(255))){
326
+ $gi->databaseType = ord(fread($gi->filehandle,1));
327
+ if ($gi->databaseType == GEOIP_REGION_EDITION_REV0){
328
+ $gi->databaseSegments = GEOIP_STATE_BEGIN_REV0;
329
+ }
330
+ else if ($gi->databaseType == GEOIP_REGION_EDITION_REV1){
331
+ $gi->databaseSegments = GEOIP_STATE_BEGIN_REV1;
332
+ } else if (($gi->databaseType == GEOIP_CITY_EDITION_REV0)
333
+ || ($gi->databaseType == GEOIP_CITY_EDITION_REV1)
334
+ || ($gi->databaseType == GEOIP_CITY_EDITION_REV0_V6)
335
+ || ($gi->databaseType == GEOIP_CITY_EDITION_REV1_V6)
336
+ || ($gi->databaseType == GEOIP_ORG_EDITION)
337
+ || ($gi->databaseType == GEOIP_DOMAIN_EDITION)
338
+ || ($gi->databaseType == GEOIP_ISP_EDITION)
339
+ || ($gi->databaseType == GEOIP_ORG_EDITION_V6)
340
+ || ($gi->databaseType == GEOIP_DOMAIN_EDITION_V6)
341
+ || ($gi->databaseType == GEOIP_ISP_EDITION_V6)
342
+ || ($gi->databaseType == GEOIP_LOCATIONA_EDITION)
343
+ || ($gi->databaseType == GEOIP_ACCURACYRADIUS_EDITION)
344
+ || ($gi->databaseType == GEOIP_CITY_EDITION_REV0_V6)
345
+ || ($gi->databaseType == GEOIP_CITY_EDITION_REV1_V6)
346
+ || ($gi->databaseType == GEOIP_NETSPEED_EDITION_REV1)
347
+ || ($gi->databaseType == GEOIP_NETSPEED_EDITION_REV1_V6)
348
+ || ($gi->databaseType == GEOIP_USERTYPE_EDITION)
349
+ || ($gi->databaseType == GEOIP_USERTYPE_EDITION_V6)
350
+ || ($gi->databaseType == GEOIP_ASNUM_EDITION)
351
+ || ($gi->databaseType == GEOIP_ASNUM_EDITION_V6)){
352
+ $gi->databaseSegments = 0;
353
+ $buf = fread($gi->filehandle,SEGMENT_RECORD_LENGTH);
354
+ for ($j = 0;$j < SEGMENT_RECORD_LENGTH;$j++){
355
+ $gi->databaseSegments += (ord($buf[$j]) << ($j * 8));
356
+ }
357
+ if ( ( $gi->databaseType == GEOIP_ORG_EDITION )
358
+ || ( $gi->databaseType == GEOIP_DOMAIN_EDITION )
359
+ || ( $gi->databaseType == GEOIP_ISP_EDITION )
360
+ || ( $gi->databaseType == GEOIP_ORG_EDITION_V6 )
361
+ || ( $gi->databaseType == GEOIP_DOMAIN_EDITION_V6 )
362
+ || ( $gi->databaseType == GEOIP_ISP_EDITION_V6 )) {
363
+ $gi->record_length = ORG_RECORD_LENGTH;
364
+ }
365
+ }
366
+ break;
367
+ } else {
368
+ fseek($gi->filehandle, -4, SEEK_CUR);
369
+ }
370
+ }
371
+ if (($gi->databaseType == GEOIP_COUNTRY_EDITION)||
372
+ ($gi->databaseType == GEOIP_COUNTRY_EDITION_V6)||
373
+ ($gi->databaseType == GEOIP_PROXY_EDITION)||
374
+ ($gi->databaseType == GEOIP_NETSPEED_EDITION)){
375
+ $gi->databaseSegments = GEOIP_COUNTRY_BEGIN;
376
+ }
377
+ fseek($gi->filehandle,$filepos,SEEK_SET);
378
+ }
379
+ return $gi;
380
+ }
381
+ }
382
+
383
+ if(! function_exists('geoip_open')){
384
+ function geoip_open($filename, $flags) {
385
+ $gi = new wfWAFGeoIP;
386
+ $gi->flags = $flags;
387
+ if ($gi->flags & GEOIP_SHARED_MEMORY) {
388
+ $gi->shmid = @shmop_open (GEOIP_SHM_KEY, "a", 0, 0);
389
+ } else {
390
+ $gi->filehandle = fopen($filename,"rb") or die( "Can not open $filename\n" );
391
+ if ($gi->flags & GEOIP_MEMORY_CACHE) {
392
+ $s_array = fstat($gi->filehandle);
393
+ $gi->memory_buffer = fread($gi->filehandle, $s_array['size']);
394
+ }
395
+ }
396
+
397
+ $gi = _setup_segments($gi);
398
+ return $gi;
399
+ }
400
+ }
401
+
402
+ if(! function_exists('geoip_close')){
403
+ function geoip_close($gi) {
404
+ if ($gi->flags & GEOIP_SHARED_MEMORY) {
405
+ return true;
406
+ }
407
+
408
+ return fclose($gi->filehandle);
409
+ }
410
+ }
411
+
412
+ if(! function_exists('geoip_country_id_by_name_v6')){
413
+ function geoip_country_id_by_name_v6($gi, $name) {
414
+ $rec = @dns_get_record($name, DNS_AAAA);
415
+ if ( !$rec ) {
416
+ return false;
417
+ }
418
+ $addr = $rec[0]["ipv6"];
419
+ if (!$addr || $addr == $name) {
420
+ return false;
421
+ }
422
+ return geoip_country_id_by_addr_v6($gi, $addr);
423
+ }
424
+ }
425
+
426
+ if(! function_exists('geoip_country_id_by_name')){
427
+ function geoip_country_id_by_name($gi, $name) {
428
+ $addr = gethostbyname($name);
429
+ if (!$addr || $addr == $name) {
430
+ return false;
431
+ }
432
+ return geoip_country_id_by_addr($gi, $addr);
433
+ }
434
+ }
435
+
436
+ if(! function_exists('geoip_country_id_by_name')){
437
+ function geoip_country_code_by_name_v6($gi, $name) {
438
+ $country_id = geoip_country_id_by_name_v6($gi,$name);
439
+ if ($country_id !== false) {
440
+ return $gi->GEOIP_COUNTRY_CODES[$country_id];
441
+ }
442
+ return false;
443
+ }
444
+ }
445
+
446
+ if(! function_exists('geoip_country_code_by_name')){
447
+ function geoip_country_code_by_name($gi, $name) {
448
+ $country_id = geoip_country_id_by_name($gi,$name);
449
+ if ($country_id !== false) {
450
+ return $gi->GEOIP_COUNTRY_CODES[$country_id];
451
+ }
452
+ return false;
453
+ }
454
+ }
455
+
456
+ if(! function_exists('geoip_country_name_by_name_v6')){
457
+ function geoip_country_name_by_name_v6($gi, $name) {
458
+ $country_id = geoip_country_id_by_name_v6($gi,$name);
459
+ if ($country_id !== false) {
460
+ return $gi->GEOIP_COUNTRY_NAMES[$country_id];
461
+ }
462
+ return false;
463
+ }
464
+ }
465
+
466
+ if(! function_exists('geoip_country_name_by_name')){
467
+ function geoip_country_name_by_name($gi, $name) {
468
+ $country_id = geoip_country_id_by_name($gi,$name);
469
+ if ($country_id !== false) {
470
+ return $gi->GEOIP_COUNTRY_NAMES[$country_id];
471
+ }
472
+ return false;
473
+ }
474
+ }
475
+
476
+ if(! function_exists('geoip_country_id_by_addr_v6')){
477
+ function geoip_country_id_by_addr_v6($gi, $addr) {
478
+ $ipnum = wfWAFUtils::inet_pton($addr);
479
+ return _geoip_seek_country_v6($gi, $ipnum) - GEOIP_COUNTRY_BEGIN;
480
+ }
481
+ }
482
+
483
+ if(! function_exists('geoip_country_id_by_addr')){
484
+ function geoip_country_id_by_addr($gi, $addr) {
485
+ $ipnum = ip2long($addr);
486
+ return _geoip_seek_country($gi, $ipnum) - GEOIP_COUNTRY_BEGIN;
487
+ }
488
+ }
489
+
490
+ if(! function_exists('geoip_country_code_by_addr_v6')){
491
+ function geoip_country_code_by_addr_v6($gi, $addr) {
492
+ $country_id = geoip_country_id_by_addr_v6($gi,$addr);
493
+ if ($country_id !== false) {
494
+ return $gi->GEOIP_COUNTRY_CODES[$country_id];
495
+ }
496
+ return false;
497
+ }
498
+ }
499
+
500
+ if(! function_exists('geoip_country_code_by_addr')){
501
+ function geoip_country_code_by_addr($gi, $addr) {
502
+ if ($gi->databaseType == GEOIP_CITY_EDITION_REV1) {
503
+ $record = geoip_record_by_addr($gi,$addr);
504
+ if ( $record !== false ) {
505
+ return $record->country_code;
506
+ }
507
+ } else {
508
+ $country_id = geoip_country_id_by_addr($gi,$addr);
509
+ if ($country_id !== false) {
510
+ return $gi->GEOIP_COUNTRY_CODES[$country_id];
511
+ }
512
+ }
513
+ return false;
514
+ }
515
+ }
516
+
517
+ if(! function_exists('geoip_country_name_by_addr_v6')){
518
+ function geoip_country_name_by_addr_v6($gi, $addr) {
519
+ $country_id = geoip_country_id_by_addr_v6($gi,$addr);
520
+ if ($country_id !== false) {
521
+ return $gi->GEOIP_COUNTRY_NAMES[$country_id];
522
+ }
523
+ return false;
524
+ }
525
+ }
526
+
527
+ if(! function_exists('geoip_country_name_by_addr')){
528
+ function geoip_country_name_by_addr($gi, $addr) {
529
+ if ($gi->databaseType == GEOIP_CITY_EDITION_REV1) {
530
+ $record = geoip_record_by_addr($gi,$addr);
531
+ return $record->country_name;
532
+ } else {
533
+ $country_id = geoip_country_id_by_addr($gi,$addr);
534
+ if ($country_id !== false) {
535
+ return $gi->GEOIP_COUNTRY_NAMES[$country_id];
536
+ }
537
+ }
538
+ return false;
539
+ }
540
+ }
541
+
542
+ if(! function_exists('_geoip_seek_country_v6')){
543
+ function _geoip_seek_country_v6($gi, $ipnum) {
544
+
545
+ # arrays from unpack start with offset 1
546
+ # yet another php mystery. array_merge work around
547
+ # this broken behaviour
548
+ $v6vec = array_merge(unpack( "C16", $ipnum));
549
+
550
+ $offset = 0;
551
+ for ($depth = 127; $depth >= 0; --$depth) {
552
+ if ($gi->flags & GEOIP_MEMORY_CACHE) {
553
+ // workaround php's broken substr, strpos, etc handling with
554
+ // mbstring.func_overload and mbstring.internal_encoding
555
+ $enc = mb_internal_encoding();
556
+ mb_internal_encoding('ISO-8859-1');
557
+
558
+ $buf = substr($gi->memory_buffer,
559
+ 2 * $gi->record_length * $offset,
560
+ 2 * $gi->record_length);
561
+
562
+ mb_internal_encoding($enc);
563
+ } elseif ($gi->flags & GEOIP_SHARED_MEMORY) {
564
+ $buf = @shmop_read ($gi->shmid,
565
+ 2 * $gi->record_length * $offset,
566
+ 2 * $gi->record_length );
567
+ } else {
568
+ fseek($gi->filehandle, 2 * $gi->record_length * $offset, SEEK_SET) == 0
569
+ or die("fseek failed");
570
+ $buf = fread($gi->filehandle, 2 * $gi->record_length);
571
+ }
572
+ $x = array(0,0);
573
+ for ($i = 0; $i < 2; ++$i) {
574
+ for ($j = 0; $j < $gi->record_length; ++$j) {
575
+ $x[$i] += ord($buf[$gi->record_length * $i + $j]) << ($j * 8);
576
+ }
577
+ }
578
+
579
+ $bnum = 127 - $depth;
580
+ $idx = $bnum >> 3;
581
+ $b_mask = 1 << ( $bnum & 7 ^ 7 );
582
+ if (($v6vec[$idx] & $b_mask) > 0) {
583
+ if ($x[1] >= $gi->databaseSegments) {
584
+ return $x[1];
585
+ }
586
+ $offset = $x[1];
587
+ } else {
588
+ if ($x[0] >= $gi->databaseSegments) {
589
+ return $x[0];
590
+ }
591
+ $offset = $x[0];
592
+ }
593
+ }
594
+ trigger_error("error traversing database - perhaps it is corrupt?", E_USER_ERROR);
595
+ return false;
596
+ }
597
+ }
598
+
599
+ if(! function_exists('_geoip_seek_country')){
600
+ function _geoip_seek_country($gi, $ipnum) {
601
+ $offset = 0;
602
+ for ($depth = 31; $depth >= 0; --$depth) {
603
+ if ($gi->flags & GEOIP_MEMORY_CACHE) {
604
+ // workaround php's broken substr, strpos, etc handling with
605
+ // mbstring.func_overload and mbstring.internal_encoding
606
+ $enc = mb_internal_encoding();
607
+ mb_internal_encoding('ISO-8859-1');
608
+
609
+ $buf = substr($gi->memory_buffer,
610
+ 2 * $gi->record_length * $offset,
611
+ 2 * $gi->record_length);
612
+
613
+ mb_internal_encoding($enc);
614
+ } elseif ($gi->flags & GEOIP_SHARED_MEMORY) {
615
+ $buf = @shmop_read ($gi->shmid,
616
+ 2 * $gi->record_length * $offset,
617
+ 2 * $gi->record_length );
618
+ } else {
619
+ fseek($gi->filehandle, 2 * $gi->record_length * $offset, SEEK_SET) == 0
620
+ or die("fseek failed");
621
+ $buf = fread($gi->filehandle, 2 * $gi->record_length);
622
+ }
623
+ $x = array(0,0);
624
+ for ($i = 0; $i < 2; ++$i) {
625
+ for ($j = 0; $j < $gi->record_length; ++$j) {
626
+ $x[$i] += ord($buf[$gi->record_length * $i + $j]) << ($j * 8);
627
+ }
628
+ }
629
+ if ($ipnum & (1 << $depth)) {
630
+ if ($x[1] >= $gi->databaseSegments) {
631
+ return $x[1];
632
+ }
633
+ $offset = $x[1];
634
+ } else {
635
+ if ($x[0] >= $gi->databaseSegments) {
636
+ return $x[0];
637
+ }
638
+ $offset = $x[0];
639
+ }
640
+ }
641
+ trigger_error("error traversing database - perhaps it is corrupt?", E_USER_ERROR);
642
+ return false;
643
+ }
644
+ }
645
+
646
+ if(! function_exists('_common_get_org')){
647
+ function _common_get_org($gi, $seek_org){
648
+ $record_pointer = $seek_org + (2 * $gi->record_length - 1) * $gi->databaseSegments;
649
+ if ($gi->flags & GEOIP_SHARED_MEMORY) {
650
+ $org_buf = @shmop_read ($gi->shmid, $record_pointer, MAX_ORG_RECORD_LENGTH);
651
+ } else {
652
+ fseek($gi->filehandle, $record_pointer, SEEK_SET);
653
+ $org_buf = fread($gi->filehandle,MAX_ORG_RECORD_LENGTH);
654
+ }
655
+ // workaround php's broken substr, strpos, etc handling with
656
+ // mbstring.func_overload and mbstring.internal_encoding
657
+ $enc = mb_internal_encoding();
658
+ mb_internal_encoding('ISO-8859-1');
659
+ $org_buf = substr($org_buf, 0, strpos($org_buf, "\0"));
660
+ mb_internal_encoding($enc);
661
+ return $org_buf;
662
+ }
663
+ }
664
+
665
+ if(! function_exists('_get_org_v6')){
666
+ function _get_org_v6($gi,$ipnum){
667
+ $seek_org = _geoip_seek_country_v6($gi,$ipnum);
668
+ if ($seek_org == $gi->databaseSegments) {
669
+ return NULL;
670
+ }
671
+ return _common_get_org($gi, $seek_org);
672
+ }
673
+ }
674
+
675
+ if(! function_exists('_get_org')){
676
+ function _get_org($gi,$ipnum){
677
+ $seek_org = _geoip_seek_country($gi,$ipnum);
678
+ if ($seek_org == $gi->databaseSegments) {
679
+ return NULL;
680
+ }
681
+ return _common_get_org($gi, $seek_org);
682
+ }
683
+ }
684
+
685
+ if(! function_exists('geoip_name_by_addr_v6')){
686
+ function geoip_name_by_addr_v6 ($gi,$addr) {
687
+ if ($addr == NULL) {
688
+ return 0;
689
+ }
690
+ $ipnum = wfWAFUtils::inet_pton($addr);
691
+ return _get_org_v6($gi, $ipnum);
692
+ }
693
+ }
694
+
695
+ if(! function_exists('geoip_name_by_addr')){
696
+ function geoip_name_by_addr ($gi,$addr) {
697
+ if ($addr == NULL) {
698
+ return 0;
699
+ }
700
+ $ipnum = ip2long($addr);
701
+ return _get_org($gi, $ipnum);
702
+ }
703
+ }
704
+
705
+ if(! function_exists('geoip_org_by_addr')){
706
+ function geoip_org_by_addr ($gi,$addr) {
707
+ return geoip_name_by_addr($gi, $addr);
708
+ }
709
+ }
710
+
711
+ if(! function_exists('_get_region')){
712
+ function _get_region($gi,$ipnum){
713
+ if ($gi->databaseType == GEOIP_REGION_EDITION_REV0){
714
+ $seek_region = _geoip_seek_country($gi,$ipnum) - GEOIP_STATE_BEGIN_REV0;
715
+ if ($seek_region >= 1000){
716
+ $country_code = "US";
717
+ $region = chr(($seek_region - 1000)/26 + 65) . chr(($seek_region - 1000)%26 + 65);
718
+ } else {
719
+ $country_code = $gi->GEOIP_COUNTRY_CODES[$seek_region];
720
+ $region = "";
721
+ }
722
+ return array ($country_code,$region);
723
+ } else if ($gi->databaseType == GEOIP_REGION_EDITION_REV1) {
724
+ $seek_region = _geoip_seek_country($gi,$ipnum) - GEOIP_STATE_BEGIN_REV1;
725
+ //print $seek_region;
726
+ if ($seek_region < US_OFFSET){
727
+ $country_code = "";
728
+ $region = "";
729
+ } else if ($seek_region < CANADA_OFFSET) {
730
+ $country_code = "US";
731
+ $region = chr(($seek_region - US_OFFSET)/26 + 65) . chr(($seek_region - US_OFFSET)%26 + 65);
732
+ } else if ($seek_region < WORLD_OFFSET) {
733
+ $country_code = "CA";
734
+ $region = chr(($seek_region - CANADA_OFFSET)/26 + 65) . chr(($seek_region - CANADA_OFFSET)%26 + 65);
735
+ } else {
736
+ $country_code = $gi->GEOIP_COUNTRY_CODES[($seek_region - WORLD_OFFSET) / FIPS_RANGE];
737
+ $region = "";
738
+ }
739
+ return array ($country_code,$region);
740
+ }
741
+ }
742
+ }
743
+
744
+ if(! function_exists('geoip_region_by_addr')){
745
+ function geoip_region_by_addr ($gi,$addr) {
746
+ if ($addr == NULL) {
747
+ return 0;
748
+ }
749
+ $ipnum = ip2long($addr);
750
+ return _get_region($gi, $ipnum);
751
+ }
752
+ }
753
+
754
+ if(! function_exists('getdnsattributes')){
755
+ function getdnsattributes ($l,$ip){
756
+ $r = new Net_DNS_Resolver();
757
+ $r->nameservers = array("ws1.maxmind.com");
758
+ $p = $r->search($l."." . $ip .".s.maxmind.com","TXT","IN");
759
+ $str = is_object($p->answer[0])?$p->answer[0]->string():'';
760
+ $str = substr( $str, 1, -1 );
761
+ return $str;
762
+ }
763
+ }
764
+ }
765
+ ?>
waf/wfWAFIPBlocksController.php ADDED
@@ -0,0 +1,394 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ class wfWAFIPBlocksController
3
+ {
4
+ const WFWAF_BLOCK_UAREFIPRANGE = 'UA/Referrer/IP Range not allowed';
5
+ const WFWAF_BLOCK_COUNTRY = 'blocked access via country blocking';
6
+ const WFWAF_BLOCK_COUNTRY_REDIR = 'blocked access via country blocking and redirected to URL';
7
+ const WFWAF_BLOCK_COUNTRY_BYPASS_REDIR = 'redirected to bypass URL';
8
+ const WFWAF_BLOCK_WFSN = 'Blocked by Wordfence Security Network';
9
+
10
+ protected static $_currentController = null;
11
+
12
+ public static function currentController() {
13
+ if (self::$_currentController === null) {
14
+ self::$_currentController = new wfWAFIPBlocksController();
15
+ }
16
+ return self::$_currentController;
17
+ }
18
+
19
+ public static function setCurrentController($currentController) {
20
+ self::$_currentController = $currentController;
21
+ }
22
+
23
+ public static function synchronizeConfigSettings() {
24
+ if (!class_exists('wfConfig')) { // Ensure this is only called when WordPress and the plugin are fully loaded
25
+ return;
26
+ }
27
+
28
+ static $isSynchronizing = false;
29
+ if ($isSynchronizing) {
30
+ return;
31
+ }
32
+ $isSynchronizing = true;
33
+
34
+ global $wpdb;
35
+ $db = new wfDB();
36
+
37
+ // Pattern Blocks
38
+ $r1 = $db->querySelect("SELECT id, blockType, blockString FROM {$wpdb->base_prefix}wfBlocksAdv");
39
+ $patternBlocks = array();
40
+ foreach ($r1 as $blockRec) {
41
+ if ($blockRec['blockType'] == 'IU') {
42
+ $bDat = explode('|', $blockRec['blockString']);
43
+ $ipRange = isset($bDat[0]) ? $bDat[0] : '';
44
+ $uaPattern = isset($bDat[1]) ? $bDat[1] : '';
45
+ $refPattern = isset($bDat[2]) ? $bDat[2] : '';
46
+ $hostnamePattern = isset($bDat[3]) ? $bDat[3] : '';
47
+
48
+ $patternBlocks[] = array('id' => $blockRec['id'], 'ipRange' => $ipRange, 'hostnamePattern' => $hostnamePattern, 'uaPattern' => $uaPattern, 'refPattern' => $refPattern);
49
+ }
50
+ }
51
+
52
+ // Country Blocks
53
+ $wfLog = new wfLog(wfConfig::get('apiKey'), wfUtils::getWPVersion());
54
+ $cblCookie = $wfLog->getCBLCookieVal(); //Ensure we have the bypass cookie option set
55
+
56
+ $countryBlocks = array();
57
+ $countryBlocks['action'] = wfConfig::get('cbl_action', false);
58
+ $countryBlocks['loggedInBlocked'] = wfConfig::get('cbl_loggedInBlocked', false);
59
+ $countryBlocks['loginFormBlocked'] = wfConfig::get('cbl_loginFormBlocked', false);
60
+ $countryBlocks['restOfSiteBlocked'] = wfConfig::get('cbl_restOfSiteBlocked', false);
61
+ $countryBlocks['bypassRedirURL'] = wfConfig::get('cbl_bypassRedirURL', '');
62
+ $countryBlocks['bypassRedirDest'] = wfConfig::get('cbl_bypassRedirDest', '');
63
+ $countryBlocks['bypassViewURL'] = wfConfig::get('cbl_bypassViewURL', '');
64
+ $countryBlocks['redirURL'] = wfConfig::get('cbl_redirURL', '');
65
+ $countryBlocks['countries'] = explode(',', wfConfig::get('cbl_countries', ''));
66
+ $countryBlocks['cookieVal'] = $cblCookie;
67
+
68
+ //Other Blocks
69
+ $otherBlocks = array('blockedTime' => wfConfig::get('blockedTime', 0));
70
+ $otherBlockEntries = $db->querySelect("SELECT IP, blockedTime, reason, permanent, wfsn FROM {$wpdb->base_prefix}wfBlocks WHERE permanent = 1 OR (blockedTime + %d > unix_timestamp())", $otherBlocks['blockedTime']);
71
+ $otherBlocks['blocks'] = (is_array($otherBlockEntries) ? $otherBlockEntries : array());
72
+ foreach ($otherBlocks['blocks'] as &$b) {
73
+ $b['IP'] = base64_encode($b['IP']);
74
+ }
75
+
76
+ // Save it
77
+ try {
78
+ $patternBlocksJSON = wfWAFUtils::json_encode($patternBlocks);
79
+ wfWAF::getInstance()->getStorageEngine()->setConfig('patternBlocks', $patternBlocksJSON);
80
+ $countryBlocksJSON = wfWAFUtils::json_encode($countryBlocks);
81
+ wfWAF::getInstance()->getStorageEngine()->setConfig('countryBlocks', $countryBlocksJSON);
82
+ $otherBlocksJSON = wfWAFUtils::json_encode($otherBlocks);
83
+ wfWAF::getInstance()->getStorageEngine()->setConfig('otherBlocks', $otherBlocksJSON);
84
+
85
+ wfWAF::getInstance()->getStorageEngine()->setConfig('advancedBlockingEnabled', wfConfig::get('firewallEnabled'));
86
+ wfWAF::getInstance()->getStorageEngine()->setConfig('disableWAFIPBlocking', wfConfig::get('disableWAFIPBlocking'));
87
+ }
88
+ catch (Exception $e) {
89
+ // Do nothing
90
+ }
91
+ $isSynchronizing = false;
92
+ }
93
+
94
+ /**
95
+ * @param wfWAFRequest $request
96
+ * @return bool|string If not blocked, returns false. Otherwise a string of the reason it was blocked or true.
97
+ */
98
+ public function shouldBlockRequest($request) {
99
+ // Checking the user whitelist is done before reaching this call
100
+
101
+ $ip = $request->getIP();
102
+
103
+ //Check the system whitelist
104
+ if ($this->checkForWhitelisted($ip)) {
105
+ return false;
106
+ }
107
+
108
+ //Let the plugin handle these
109
+ $wfFunc = $request->getQueryString('_wfsf');
110
+ if ($wfFunc == 'unlockEmail' || $wfFunc == 'unlockAccess') { // Can't check validity here, let it pass through to plugin level where it can
111
+ return false;
112
+ }
113
+
114
+ $logHuman = $request->getQueryString('wordfence_logHuman');
115
+ if ($logHuman !== null) {
116
+ return false;
117
+ }
118
+
119
+ //Start block checks
120
+ $ipNum = wfWAFUtils::inet_pton($ip);
121
+ $hostname = null;
122
+ $ua = $request->getHeaders('User-Agent'); if ($ua === null) { $ua = ''; }
123
+ $referer = $request->getHeaders('Referer'); if ($referer === null) { $referer = ''; }
124
+
125
+ $isPaid = false;
126
+ try {
127
+ $isPaid = wfWAF::getInstance()->getStorageEngine()->getConfig('isPaid');
128
+ $pluginABSPATH = wfWAF::getInstance()->getStorageEngine()->getConfig('pluginABSPATH');
129
+
130
+ $patternBlocksJSON = wfWAF::getInstance()->getStorageEngine()->getConfig('patternBlocks');
131
+ $countryBlocksJSON = wfWAF::getInstance()->getStorageEngine()->getConfig('countryBlocks');
132
+ $otherBlocksJSON = wfWAF::getInstance()->getStorageEngine()->getConfig('otherBlocks');
133
+ }
134
+ catch (Exception $e) {
135
+ // Do nothing
136
+ }
137
+
138
+ if (isset($_SERVER['SCRIPT_FILENAME']) && (strpos($_SERVER['SCRIPT_FILENAME'], $pluginABSPATH . "wp-admin/") === 0 || strpos($_SERVER['SCRIPT_FILENAME'], $pluginABSPATH . "wp-content/") === 0 || strpos($_SERVER['SCRIPT_FILENAME'], $pluginABSPATH . "wp-includes/") === 0)) {
139
+ return false; //Rely on WordPress's own access control and blocking at the plugin level
140
+ }
141
+
142
+ // Pattern Blocks from the Advanced Blocking page (IP Range, UA, Referer)
143
+ $patternBlocks = @wfWAFUtils::json_decode($patternBlocksJSON, true);
144
+ if (is_array($patternBlocks)) {
145
+ // Instead of a long block of if/else statements, using bitshifting to generate an expected value and a found value
146
+ $ipRangeOffset = 1;
147
+ $uaPatternOffset = 2;
148
+ $refPatternOffset = 3;
149
+
150
+ foreach ($patternBlocks as $b) {
151
+ $expectedBits = 0;
152
+ $foundBits = 0;
153
+
154
+ if (!empty($b['ipRange'])) {
155
+ $expectedBits |= (1 << $ipRangeOffset);
156
+ list($start_range, $end_range) = explode('-', $b['ipRange']);
157
+ if (preg_match('/[\.:]/', $start_range)) {
158
+ $start_range = wfWAFUtils::inet_pton($start_range);
159
+ $end_range = wfWAFUtils::inet_pton($end_range);
160
+ } else {
161
+ $start_range = wfWAFUtils::inet_pton(long2ip($start_range));
162
+ $end_range = wfWAFUtils::inet_pton(long2ip($end_range));
163
+ }
164
+
165
+ if (strcmp($ipNum, $start_range) >= 0 && strcmp($ipNum, $end_range) <= 0) {
166
+ $foundBits |= (1 << $ipRangeOffset);
167
+ }
168
+ }
169
+
170
+ if (!empty($b['hostnamePattern'])) {
171
+ $expectedBits |= (1 << $ipRangeOffset);
172
+ if ($hostname === null) {
173
+ $hostname = wfWAFUtils::reverseLookup($ip);
174
+ }
175
+ if (preg_match(wfWAFUtils::patternToRegex($b['hostnamePattern']), $hostname)) {
176
+ $foundBits |= (1 << $ipRangeOffset);
177
+ }
178
+ }
179
+
180
+ if (!empty($b['uaPattern'])) {
181
+ $expectedBits |= (1 << $uaPatternOffset);
182
+ if (wfWAFUtils::isUABlocked($b['uaPattern'], $ua)) {
183
+ $foundBits |= (1 << $uaPatternOffset);
184
+ }
185
+ }
186
+
187
+ if (!empty($b['refPattern'])) {
188
+ $expectedBits |= (1 << $refPatternOffset);
189
+ if (wfWAFUtils::isRefererBlocked($b['refPattern'], $referer)) {
190
+ $foundBits |= (1 << $refPatternOffset);
191
+ }
192
+ }
193
+
194
+ if ($foundBits === $expectedBits && $expectedBits > 0) {
195
+ return array('action' => self::WFWAF_BLOCK_UAREFIPRANGE, 'id' => $b['id']);
196
+ }
197
+ }
198
+ }
199
+ // End Pattern Blocks
200
+
201
+ // Country Blocking
202
+ if ($isPaid) {
203
+ $countryBlocks = @wfWAFUtils::json_decode($countryBlocksJSON, true);
204
+ if (is_array($countryBlocks)) {
205
+ $blockedCountries = $countryBlocks['countries'];
206
+ $bareRequestURI = wfWAFUtils::extractBareURI($request->getURI());
207
+ $bareBypassRedirURI = wfWAFUtils::extractBareURI($countryBlocks['bypassRedirURL']);
208
+ $skipCountryBlocking = false;
209
+
210
+ if ($bareBypassRedirURI && $bareRequestURI == $bareBypassRedirURI) { // Run this before country blocking because even if the user isn't blocked we need to set the bypass cookie so they can bypass future blocks.
211
+ if ($countryBlocks['bypassRedirDest']) {
212
+ setcookie('wfCBLBypass', $countryBlocks['cookieVal'], time() + (86400 * 365), '/', null, null, true);
213
+ return array('action' => self::WFWAF_BLOCK_COUNTRY_BYPASS_REDIR);
214
+ }
215
+ }
216
+
217
+ $bareBypassViewURI = wfWAFUtils::extractBareURI($countryBlocks['bypassViewURL']);
218
+ if ($bareBypassViewURI && $bareBypassViewURI == $bareRequestURI) {
219
+ setcookie('wfCBLBypass', $countryBlocks['cookieVal'], time() + (86400 * 365), '/', null, null, true);
220
+ $skipCountryBlocking = true;
221
+ }
222
+
223
+ $bypassCookieSet = false;
224
+ $bypassCookie = $request->getCookies('wfCBLBypass');
225
+ if (isset($bypassCookie) && $bypassCookie == $countryBlocks['cookieVal']) {
226
+ $bypassCookieSet = true;
227
+ }
228
+
229
+ if (!$skipCountryBlocking && $blockedCountries && !$bypassCookieSet) {
230
+ $isAuthRequest = (strpos($bareRequestURI, '/wp-login.php') !== false);
231
+ $isXMLRPC = (strpos($bareRequestURI, '/xmlrpc.php') !== false);
232
+ $isUserLoggedIn = wfWAF::getInstance()->parseAuthCookie() !== false;
233
+
234
+ // If everything is checked, make sure this always runs.
235
+ if ($countryBlocks['loggedInBlocked'] && $countryBlocks['loginFormBlocked'] && $countryBlocks['restOfSiteBlocked']) {
236
+ if ($blocked = $this->checkForBlockedCountry($countryBlocks, $ip, $bareRequestURI)) { return $blocked; }
237
+ }
238
+ // Block logged in users.
239
+ if ($countryBlocks['loggedInBlocked'] && $isUserLoggedIn) {
240
+ if ($blocked = $this->checkForBlockedCountry($countryBlocks, $ip, $bareRequestURI)) { return $blocked; }
241
+ }
242
+ // Block the login form itself and any attempt to authenticate.
243
+ if ($countryBlocks['loginFormBlocked'] && $isAuthRequest) {
244
+ if ($blocked = $this->checkForBlockedCountry($countryBlocks, $ip, $bareRequestURI)) { return $blocked; }
245
+ }
246
+ // Block requests that aren't to the login page, xmlrpc.php, or a user already logged in.
247
+ if ($countryBlocks['restOfSiteBlocked'] && !$isAuthRequest && !$isXMLRPC && !$isUserLoggedIn) {
248
+ if ($blocked = $this->checkForBlockedCountry($countryBlocks, $ip, $bareRequestURI)) { return $blocked; }
249
+ }
250
+ // XMLRPC is inaccesible when public portion of the site and auth is disabled.
251
+ if ($countryBlocks['loginFormBlocked'] && $countryBlocks['restOfSiteBlocked'] && $isXMLRPC) {
252
+ if ($blocked = $this->checkForBlockedCountry($countryBlocks, $ip, $bareRequestURI)) { return $blocked; }
253
+ }
254
+
255
+ // Any bypasses and other block possibilities will be checked at the plugin level once WordPress loads
256
+ }
257
+ }
258
+ }
259
+ // End Country Blocking
260
+
261
+ // Other Blocks
262
+ $otherBlocks = @wfWAFUtils::json_decode($otherBlocksJSON, true);
263
+ if (is_array($otherBlocks)) {
264
+ $blockedTime = $otherBlocks['blockedTime'];
265
+ $blocks = $otherBlocks['blocks'];
266
+ $bareRequestURI = wfWAFUtils::extractBareURI($request->getURI());
267
+ $isAuthRequest = (strpos($bareRequestURI, '/wp-login.php') !== false);
268
+ foreach ($blocks as $b) {
269
+ if (!$b['permanent'] && ($b['blockedTime'] + $blockedTime) < time()) {
270
+ continue;
271
+ }
272
+
273
+ if (base64_decode($b['IP']) != $ipNum) {
274
+ continue;
275
+ }
276
+
277
+ if ($isAuthRequest) {
278
+ return array('action' => self::WFWAF_BLOCK_WFSN);
279
+ }
280
+
281
+ return array('action' => (empty($b['reason']) ? '' : $b['reason']));
282
+ }
283
+ }
284
+ // End Other Blocks
285
+
286
+ return false;
287
+ }
288
+
289
+ public function countryRedirURL($countryBlocks = null) {
290
+ if (!isset($countryBlocks)) {
291
+ try {
292
+ $countryBlocksJSON = wfWAF::getInstance()->getStorageEngine()->getConfig('countryBlocks');
293
+ }
294
+ catch (Exception $e) {
295
+ return false;
296
+ }
297
+ }
298
+
299
+ $countryBlocks = @wfWAFUtils::json_decode($countryBlocksJSON, true);
300
+ if (is_array($countryBlocks)) {
301
+ if ($countryBlocks['action'] == 'redir') {
302
+ return $countryBlocks['redirURL'];
303
+ }
304
+ }
305
+ return false;
306
+ }
307
+
308
+ public function countryBypassRedirURL($countryBlocks = null) {
309
+ if (!isset($countryBlocks)) {
310
+ try {
311
+ $countryBlocksJSON = wfWAF::getInstance()->getStorageEngine()->getConfig('countryBlocks');
312
+ }
313
+ catch (Exception $e) {
314
+ return false;
315
+ }
316
+ }
317
+
318
+ $countryBlocks = @wfWAFUtils::json_decode($countryBlocksJSON, true);
319
+ if (is_array($countryBlocks)) {
320
+ return $countryBlocks['bypassRedirDest'];
321
+ }
322
+ return false;
323
+ }
324
+
325
+ protected function checkForBlockedCountry($countryBlock, $ip, $bareRequestURI) {
326
+ try {
327
+ $homeURL = wfWAF::getInstance()->getStorageEngine()->getConfig('homeURL');
328
+ }
329
+ catch (Exception $e) {
330
+ //Do nothing
331
+ }
332
+
333
+ $bareRequestURI = rtrim($bareRequestURI, '/\\');
334
+ if ($country = $this->ip2Country($ip)) {
335
+ foreach ($countryBlock['countries'] as $blocked) {
336
+ if (strtoupper($blocked) == strtoupper($country)) {
337
+ if ($countryBlock['action'] == 'redir') {
338
+ $redirURL = $countryBlock['redirURL'];
339
+ $eRedirHost = wfWAFUtils::extractHostname($redirURL);
340
+ $isExternalRedir = false;
341
+ if ($eRedirHost && $homeURL && $eRedirHost != wfWAFUtils::extractHostname($homeURL)) {
342
+ $isExternalRedir = true;
343
+ }
344
+
345
+ if ((!$isExternalRedir) && rtrim(wfWAFUtils::extractBareURI($redirURL), '/\\') == $bareRequestURI){ //Is this the URI we want to redirect to, then don't block it
346
+ //Do nothing
347
+ }
348
+ else {
349
+ return array('action' => self::WFWAF_BLOCK_COUNTRY_REDIR);
350
+ }
351
+ }
352
+ else {
353
+ return array('action' => self::WFWAF_BLOCK_COUNTRY);
354
+ }
355
+ }
356
+ }
357
+ }
358
+
359
+ return false;
360
+ }
361
+
362
+ protected function checkForWhitelisted($ip) {
363
+ $wordfenceLib = realpath(dirname(__FILE__) . '/../lib');
364
+ include($wordfenceLib . '/wfIPWhitelist.php'); // defines $wfIPWhitelist
365
+ foreach ($wfIPWhitelist as $group) {
366
+ foreach ($group as $subnet) {
367
+ if ($subnet instanceof wfWAFUserIPRange) { //Not currently reached
368
+ if ($subnet->isIPInRange($ip)) {
369
+ return true;
370
+ }
371
+ } elseif (wfWAFUtils::subnetContainsIP($subnet, $ip)) {
372
+ return true;
373
+ }
374
+ }
375
+ }
376
+ return false;
377
+ }
378
+
379
+ protected function ip2Country($ip){
380
+ $wordfenceLib = realpath(dirname(__FILE__) . '/../lib');
381
+ if (!(function_exists('geoip_open') && function_exists('geoip_country_code_by_addr') && function_exists('geoip_country_code_by_addr_v6'))) {
382
+ require_once(dirname(__FILE__) . '/wfWAFGeoIP.php');
383
+ }
384
+ if (filter_var($ip, FILTER_VALIDATE_IP, FILTER_FLAG_IPV6) !== false) {
385
+ $gi = geoip_open($wordfenceLib . "/GeoIPv6.dat", GEOIP_STANDARD);
386
+ $country = geoip_country_code_by_addr_v6($gi, $ip);
387
+ } else {
388
+ $gi = geoip_open($wordfenceLib . "/GeoIP.dat", GEOIP_STANDARD);
389
+ $country = geoip_country_code_by_addr($gi, $ip);
390
+ }
391
+ geoip_close($gi);
392
+ return $country ? $country : '';
393
+ }
394
+ }
waf/wfWAFUserIPRange.php CHANGED
@@ -28,6 +28,15 @@ class wfWAFUserIPRange {
28
 
29
  // IPv4 range
30
  if (strpos($ip_string, '.') !== false && strpos($ip, '.') !== false) {
 
 
 
 
 
 
 
 
 
31
  if (preg_match('/\[\d+\-\d+\]/', $ip_string)) {
32
  $IPparts = explode('.', $ip);
33
  $whiteParts = explode('.', $ip_string);
@@ -108,25 +117,29 @@ class wfWAFUserIPRange {
108
  }
109
  $sql = substr($sql, 0, -5) . ')';
110
  return $sql;
111
-
112
- } else if (strpos($ip_string, ':') !== false && preg_match('/\[[a-f0-9]+\-[a-f0-9]+\]/', $ip_string)) {
113
- $whiteParts = explode(':', strtolower(self::expandIPv6Range($ip_string)));
114
- $sql = '(';
115
-
116
- for ($i = 0; $i <= 7; $i++) {
117
- // MySQL can only perform bitwise operations on integers
118
- $conv = sprintf('CAST(CONV(HEX(SUBSTR(%s, %d, 8)), 16, 10) as UNSIGNED INTEGER)', $column, $i < 4 ? 1 : 9);
119
- $j = 16 * (3 - ($i % 4));
120
- if (preg_match('/^\[([a-f0-9]+)\-([a-f0-9]+)\]$/', $whiteParts[$i], $m)) {
121
- $sql .= $wpdb->prepare("$conv >> $j & 0xFFFF BETWEEN 0x%x AND 0x%x", hexdec($m[1]), hexdec($m[2]));
122
- } else {
123
- $sql .= $wpdb->prepare("$conv >> $j & 0xFFFF = 0x%x", hexdec($whiteParts[$i]));
 
 
 
 
124
  }
125
- $sql .= ' AND ';
 
126
  }
127
- $sql = substr($sql, 0, -5) . ')';
128
- return $sql;
129
  }
 
130
  return $wpdb->prepare("($column = %s)", wfWAFUtils::inet_pton($ip_string));
131
  }
132
 
@@ -221,6 +234,6 @@ class wfWAFUserIPRange {
221
  * @param string|null $ip_string
222
  */
223
  public function setIPString($ip_string) {
224
- $this->ip_string = preg_replace('/[\x{2013}-\x{2015}]/u', '-', $ip_string); //Replace em-dash, en-dash, and horizontal bar with a regular dash
225
  }
226
  }
28
 
29
  // IPv4 range
30
  if (strpos($ip_string, '.') !== false && strpos($ip, '.') !== false) {
31
+ // IPv4-mapped-IPv6
32
+ if (preg_match('/:ffff:([^:]+)$/i', $ip_string, $matches)) {
33
+ $ip_string = $matches[1];
34
+ }
35
+ if (preg_match('/:ffff:([^:]+)$/i', $ip, $matches)) {
36
+ $ip = $matches[1];
37
+ }
38
+
39
+ // Range check
40
  if (preg_match('/\[\d+\-\d+\]/', $ip_string)) {
41
  $IPparts = explode('.', $ip);
42
  $whiteParts = explode('.', $ip_string);
117
  }
118
  $sql = substr($sql, 0, -5) . ')';
119
  return $sql;
120
+
121
+ } else if (strpos($ip_string, ':') !== false) {
122
+ $ip_string = strtolower(self::expandIPv6Range($ip_string));
123
+ if (preg_match('/\[[a-f0-9]+\-[a-f0-9]+\]/i', $ip_string)) {
124
+ $whiteParts = explode(':', $ip_string);
125
+ $sql = '(';
126
+
127
+ for ($i = 0; $i <= 7; $i++) {
128
+ // MySQL can only perform bitwise operations on integers
129
+ $conv = sprintf('CAST(CONV(HEX(SUBSTR(%s, %d, 8)), 16, 10) as UNSIGNED INTEGER)', $column, $i < 4 ? 1 : 9);
130
+ $j = 16 * (3 - ($i % 4));
131
+ if (preg_match('/^\[([a-f0-9]+)\-([a-f0-9]+)\]$/i', $whiteParts[$i], $m)) {
132
+ $sql .= $wpdb->prepare("$conv >> $j & 0xFFFF BETWEEN 0x%x AND 0x%x", hexdec($m[1]), hexdec($m[2]));
133
+ } else {
134
+ $sql .= $wpdb->prepare("$conv >> $j & 0xFFFF = 0x%x", hexdec($whiteParts[$i]));
135
+ }
136
+ $sql .= ' AND ';
137
  }
138
+ $sql = substr($sql, 0, -5) . ')';
139
+ return $sql;
140
  }
 
 
141
  }
142
+
143
  return $wpdb->prepare("($column = %s)", wfWAFUtils::inet_pton($ip_string));
144
  }
145
 
234
  * @param string|null $ip_string
235
  */
236
  public function setIPString($ip_string) {
237
+ $this->ip_string = strtolower(preg_replace('/[\x{2013}-\x{2015}]/u', '-', $ip_string)); //Replace em-dash, en-dash, and horizontal bar with a regular dash
238
  }
239
  }
wordfence.php CHANGED
@@ -4,14 +4,14 @@ Plugin Name: Wordfence Security
4
  Plugin URI: http://www.wordfence.com/
5
  Description: Wordfence Security - Anti-virus, Firewall and Malware Scan
6
  Author: Wordfence
7
- Version: 6.2.2
8
  Author URI: http://www.wordfence.com/
9
  Network: true
10
  */
11
  if(defined('WP_INSTALLING') && WP_INSTALLING){
12
  return;
13
  }
14
- define('WORDFENCE_VERSION', '6.2.2');
15
  define('WORDFENCE_BASENAME', function_exists('plugin_basename') ? plugin_basename(__FILE__) :
16
  basename(dirname(__FILE__)) . '/' . basename(__FILE__));
17
 
4
  Plugin URI: http://www.wordfence.com/
5
  Description: Wordfence Security - Anti-virus, Firewall and Malware Scan
6
  Author: Wordfence
7
+ Version: 6.2.3
8
  Author URI: http://www.wordfence.com/
9
  Network: true
10
  */
11
  if(defined('WP_INSTALLING') && WP_INSTALLING){
12
  return;
13
  }
14
+ define('WORDFENCE_VERSION', '6.2.3');
15
  define('WORDFENCE_BASENAME', function_exists('plugin_basename') ? plugin_basename(__FILE__) :
16
  basename(dirname(__FILE__)) . '/' . basename(__FILE__));
17