Wordfence Security – Firewall & Malware Scan - Version 6.0.1

Version Description

  • Feature: IPv6 fully supported. This includes whois, range blocking, IPv6 city lookup in live traffic, country blocking and all other security functions. See www.wordfence.com/blog/ for more info.
  • Feature: New scanning routine examines the wp_options table for executable code based on a new infection we are seeing that is well hidden.
  • Improvement: Prevent Googlebot from being blocked if user has configured a banned URL and Google tries to crawl it.
  • Improvement: Improved detection for additional Google crawlers especially if an IP PTR resolves to a .googlebot.com domain.
  • Fix: Fixed bug with https:// URLs not allowed in country blocking.
  • Fix: Fixed typos.
Download this release

Release Info

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

Code changes from version 5.3.12 to 6.0.1

css/main.css CHANGED
@@ -144,17 +144,17 @@ table.wfSummaryParent { font-family: sans-serif; font-size: 14px; color: #000; z
144
table.wfSummaryParent td { vertical-align: top; padding: 0; margin: 0; }
145
table.wfSummaryParent table.wfSummaryChild th { font-weight: bold; text-align: right; font-family: Georgia, serif; color: #000; padding: 5px 10px 5px 0; border-top: 1px solid #CCC; }
146
table.wfSummaryParent table.wfSummaryChild td { font-weight: normal; text-align: left; padding: 5px 0 5px 0; border-top: 1px solid #CCC; }
147
- table.wfSummaryParent table.wfSC1 td { width: 300px; padding: 0px 25px 10px 0; }
148
table.wfSummaryParent table.wfSC2 th { width: 80px; }
149
table.wfSummaryParent table.wfSC2 td { width: 100px; }
150
table.wfSummaryParent table.wfSC3 th { width: 80px; }
151
table.wfSummaryParent table.wfSC3 td { width: 250px; }
152
- table.wfSummaryParent th.wfHead { font-size: 22px; font-family: Georgia, serif; font-style: italic; color: #555; font-weight: bold; text-align: left; padding: 20px 0 20px 0px; -webkit-font-smoothing: antialiased; }
153
154
- div.wfIssue table.wfIssue td { padding: 2px; margin: 0; border-width: 0px; text-align: left; }
155
div.wfIssue table.wfIssue th { padding: 2px; margin: 0; font-weight: bold; text-align: left; color: #777; }
156
- div.wfIssue h2 { margin: 0px 0 5px 0; padding: 0; }
157
- div.wfIssue table.wfIssueLinks td { border-width: 0px; text-align: left; padding-right: 10px; }
158
.wfIssueOptions {
159
border-top: 1px solid #CCC;
160
padding: 10px;
@@ -210,7 +210,7 @@ table th.wfSubheading { font-weight: bold; padding-top: 10px; }
210
padding: 0 0 0 18px;
211
margin: 0;
212
right: 10px;
213
- top: 0px;
214
background-repeat: no-repeat;
215
font-weight: normal;
216
}
@@ -338,7 +338,7 @@ input.wfStartScanButton { width: 160px; text-align: left; padding-left: 20px; }
338
.wfFalcon {
339
width: 63px;
340
height: 63px;
341
- border-width: 0px;
342
background-color: transparent;
343
background-image: url(../images/wordfenceFalcon.png);
344
background-position: 0 0;
@@ -350,7 +350,7 @@ input.wfStartScanButton { width: 160px; text-align: left; padding-left: 20px; }
350
.wfFalconImage {
351
width: 63px;
352
height: 63px;
353
- border-width: 0px;
354
background-color: transparent;
355
background-image: url(../images/wordfenceFalcon.png);
356
background-position: 0 0;
@@ -360,13 +360,13 @@ input.wfStartScanButton { width: 160px; text-align: left; padding-left: 20px; }
360
.wfSmallFalcon {
361
width: 33px;
362
height: 16px;
363
- border-width: 0px;
364
background-color: transparent;
365
background-image: url(../images/wordfenceFalconSmall.png);
366
background-position: 0 0;
367
background-repeat: no-repeat;
368
- margin: 0px;
369
- padding: 0px;
370
display: inline;
371
float: right;
372
}
@@ -394,7 +394,7 @@ input.wfStartScanButton { width: 160px; text-align: left; padding-left: 20px; }
394
font-size: 14px !important ; color: white !important ; font-family: Trebuchet, Arial, sans-serif !important ; font-weight: bold !important ;
395
-moz-box-sizing: border-box !important ; -webkit-box-sizing: border-box !important ; box-sizing: border-box !important ;
396
border-radius: 19px !important ;
397
- box-shadow: 0px 9.5px 0px rgba(0,0,0,0.08) inset !important ;
398
}
399
.wfOnOffSwitch-inner:before {
400
content: "ON" !important ;
@@ -410,7 +410,7 @@ input.wfStartScanButton { width: 160px; text-align: left; padding-left: 20px; }
410
border-radius: 0 19px 19px 0 !important ;
411
}
412
.wfOnOffSwitch-switch {
413
- width: 19px !important ; margin: 0px !important ;
414
background: #FFFFFF !important ;
415
border: 2px solid #999999 !important ; border-radius: 19px !important ;
416
position: absolute !important ; top: 0 !important ; bottom: 0 !important ; right: 46px !important ;
@@ -426,7 +426,7 @@ input.wfStartScanButton { width: 160px; text-align: left; padding-left: 20px; }
426
margin-left: 0 !important ;
427
}
428
.wfOnOffSwitch-checkbox:checked + .wfOnOffSwitch-label .wfOnOffSwitch-switch {
429
- right: 0px !important ;
430
}
431
#wordfenceConfigWarning {
432
clear: left;
@@ -461,3 +461,13 @@ table.wf-table tbody tr:nth-child(2n) td {
461
table.wf-table tbody tr:hover td {
462
background-color: #fffbd8;
463
}
144
table.wfSummaryParent td { vertical-align: top; padding: 0; margin: 0; }
145
table.wfSummaryParent table.wfSummaryChild th { font-weight: bold; text-align: right; font-family: Georgia, serif; color: #000; padding: 5px 10px 5px 0; border-top: 1px solid #CCC; }
146
table.wfSummaryParent table.wfSummaryChild td { font-weight: normal; text-align: left; padding: 5px 0 5px 0; border-top: 1px solid #CCC; }
147
+ table.wfSummaryParent table.wfSC1 td { width: 300px; padding: 0 25px 10px 0; }
148
table.wfSummaryParent table.wfSC2 th { width: 80px; }
149
table.wfSummaryParent table.wfSC2 td { width: 100px; }
150
table.wfSummaryParent table.wfSC3 th { width: 80px; }
151
table.wfSummaryParent table.wfSC3 td { width: 250px; }
152
+ table.wfSummaryParent th.wfHead { font-size: 22px; font-family: Georgia, serif; font-style: italic; color: #555; font-weight: bold; text-align: left; padding: 20px 0 20px 0; -webkit-font-smoothing: antialiased; }
153
154
+ div.wfIssue table.wfIssue td { padding: 2px; margin: 0; border-width: 0; text-align: left; }
155
div.wfIssue table.wfIssue th { padding: 2px; margin: 0; font-weight: bold; text-align: left; color: #777; }
156
+ div.wfIssue h2 { margin: 0 0 5px 0; padding: 0; }
157
+ div.wfIssue table.wfIssueLinks td { border-width: 0; text-align: left; padding-right: 10px; }
158
.wfIssueOptions {
159
border-top: 1px solid #CCC;
160
padding: 10px;
210
padding: 0 0 0 18px;
211
margin: 0;
212
right: 10px;
213
+ top: 0;
214
background-repeat: no-repeat;
215
font-weight: normal;
216
}
338
.wfFalcon {
339
width: 63px;
340
height: 63px;
341
+ border-width: 0;
342
background-color: transparent;
343
background-image: url(../images/wordfenceFalcon.png);
344
background-position: 0 0;
350
.wfFalconImage {
351
width: 63px;
352
height: 63px;
353
+ border-width: 0;
354
background-color: transparent;
355
background-image: url(../images/wordfenceFalcon.png);
356
background-position: 0 0;
360
.wfSmallFalcon {
361
width: 33px;
362
height: 16px;
363
+ border-width: 0;
364
background-color: transparent;
365
background-image: url(../images/wordfenceFalconSmall.png);
366
background-position: 0 0;
367
background-repeat: no-repeat;
368
+ margin: 0;
369
+ padding: 0;
370
display: inline;
371
float: right;
372
}
394
font-size: 14px !important ; color: white !important ; font-family: Trebuchet, Arial, sans-serif !important ; font-weight: bold !important ;
395
-moz-box-sizing: border-box !important ; -webkit-box-sizing: border-box !important ; box-sizing: border-box !important ;
396
border-radius: 19px !important ;
397
+ box-shadow: 0 9.5px 0 rgba(0,0,0,0.08) inset !important ;
398
}
399
.wfOnOffSwitch-inner:before {
400
content: "ON" !important ;
410
border-radius: 0 19px 19px 0 !important ;
411
}
412
.wfOnOffSwitch-switch {
413
+ width: 19px !important ; margin: 0 !important ;
414
background: #FFFFFF !important ;
415
border: 2px solid #999999 !important ; border-radius: 19px !important ;
416
position: absolute !important ; top: 0 !important ; bottom: 0 !important ; right: 46px !important ;
426
margin-left: 0 !important ;
427
}
428
.wfOnOffSwitch-checkbox:checked + .wfOnOffSwitch-label .wfOnOffSwitch-switch {
429
+ right: 0 !important ;
430
}
431
#wordfenceConfigWarning {
432
clear: left;
461
table.wf-table tbody tr:hover td {
462
background-color: #fffbd8;
463
}
464
+
465
+ table.block-ranges-table {
466
+ border-collapse: collapse;
467
+ margin: 10px 0 0;
468
+ }
469
+ table.block-ranges-table tr td {
470
+ border: 1px solid #CCC;
471
+ border-width: 1px 0;
472
+ padding: 10px 0 12px 0;
473
+ }
js/admin.js CHANGED
@@ -938,6 +938,27 @@
938
});
939
}
940
},
941
restoreFile: function(issueID) {
942
var self = this;
943
this.ajax('wordfence_restoreFile', {
@@ -1240,6 +1261,9 @@
1240
makeViewFileLink: function(file) {
1241
return WordfenceAdminVars.siteBaseURL + '?_wfsf=view&nonce=' + this.nonce + '&file=' + encodeURIComponent(file);
1242
},
1243
makeTimeAgo: function(t) {
1244
var months = Math.floor(t / (86400 * 30));
1245
var days = Math.floor(t / 86400);
@@ -1341,13 +1365,16 @@
1341
1342
function wfm21(str, ipRange, offset, totalStr) {
1343
var ips = ipRange.split(/\s*\-\s*/);
1344
- var ip1num = self.inet_aton(ips[0]);
1345
- var ip2num = self.inet_aton(ips[1]);
1346
- var totalIPs = ip2num - ip1num + 1;
1347
- return "<a href=\"admin.php?page=WordfenceRangeBlocking&wfBlockRange=" + ipRange + "\"" + redStyle + ">" + ipRange + " [<strong>" + totalIPs + "</strong> addresses in this network. Click to block this network]<\/a>";
1348
}
1349
1350
- res.result.rawdata[i] = res.result.rawdata[i].replace(/(\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3} - \d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3})/, wfm21);
1351
rawhtml += res.result.rawdata[i] + "<br />";
1352
}
1353
jQuery('#wfrawhtml').html(rawhtml);
@@ -1360,9 +1387,16 @@
1360
this.colorbox('300px', "Please specify a reason", "You forgot to include a reason you're blocking this IP range. We ask you to include this for your own record keeping.");
1361
return;
1362
}
1363
- ipRange = ipRange.replace(/ /g, '');
1364
if (ipRange) {
1365
- if (!/^\d+\.\d+\.\d+\.\d+\-\d+\.\d+\.\d+\.\d+#x2F;.test(ipRange)) {
1366
this.colorbox('300px', 'Specify a valid IP range', "Please specify a valid IP address range in the form of \"1.2.3.4 - 1.2.3.5\" without quotes. Make sure the dash between the IP addresses in a normal dash (a minus sign on your keyboard) and not another character that looks like a dash.");
1367
return;
1368
}
@@ -1845,6 +1879,84 @@
1845
}
1846
return d;
1847
},
1848
removeCacheExclusion: function(id) {
1849
this.ajax('wordfence_removeCacheExclusion', {id: id}, function(res) {
1850
window.location.reload(true);
938
});
939
}
940
},
941
+ deleteDatabaseOption: function(issueID) {
942
+ var self = this;
943
+ this.ajax('wordfence_deleteDatabaseOption', {
944
+ issueID: issueID
945
+ }, function(res) {
946
+ self.doneDeleteDatabaseOption(res);
947
+ });
948
+ },
949
+ doneDeleteDatabaseOption: function(res) {
950
+ var cb = false;
951
+ var self = this;
952
+ if (res.ok) {
953
+ this.loadIssues(function() {
954
+ self.colorbox('400px', "Success removing option", "The option " + res.option_name + " was successfully removed.");
955
+ });
956
+ } else if (res.cerrorMsg) {
957
+ this.loadIssues(function() {
958
+ self.colorbox('400px', 'An error occurred', res.cerrorMsg);
959
+ });
960
+ }
961
+ },
962
restoreFile: function(issueID) {
963
var self = this;
964
this.ajax('wordfence_restoreFile', {
1261
makeViewFileLink: function(file) {
1262
return WordfenceAdminVars.siteBaseURL + '?_wfsf=view&nonce=' + this.nonce + '&file=' + encodeURIComponent(file);
1263
},
1264
+ makeViewOptionLink: function(option, siteID) {
1265
+ return WordfenceAdminVars.siteBaseURL + '?_wfsf=viewOption&nonce=' + this.nonce + '&option=' + encodeURIComponent(option) + '&site_id=' + encodeURIComponent(siteID);
1266
+ },
1267
makeTimeAgo: function(t) {
1268
var months = Math.floor(t / (86400 * 30));
1269
var days = Math.floor(t / 86400);
1365
1366
function wfm21(str, ipRange, offset, totalStr) {
1367
var ips = ipRange.split(/\s*\-\s*/);
1368
+ var totalIPs = NaN;
1369
+ if (ips[0].indexOf(':') < 0) {
1370
+ var ip1num = self.inet_aton(ips[0]);
1371
+ var ip2num = self.inet_aton(ips[1]);
1372
+ totalIPs = ip2num - ip1num + 1;
1373
+ }
1374
+ return "<a href=\"admin.php?page=WordfenceRangeBlocking&wfBlockRange=" + ipRange + "\"" + redStyle + ">" + ipRange + " [" + (!isNaN(totalIPs) ? "<strong>" + totalIPs + "</strong> addresses in this network." : "") + "Click to block this network]<\/a>";
1375
}
1376
1377
+ res.result.rawdata[i] = res.result.rawdata[i].replace(/(\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3} - \d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}|[a-f0-9:.]{3,} - [a-f0-9:.]{3,})/i, wfm21);
1378
rawhtml += res.result.rawdata[i] + "<br />";
1379
}
1380
jQuery('#wfrawhtml').html(rawhtml);
1387
this.colorbox('300px', "Please specify a reason", "You forgot to include a reason you're blocking this IP range. We ask you to include this for your own record keeping.");
1388
return;
1389
}
1390
+ ipRange = ipRange.replace(/ /g, '').toLowerCase();
1391
if (ipRange) {
1392
+ var range = ipRange.split('-'),
1393
+ validRange = false;
1394
+ if (range[0].match(':')) {
1395
+ validRange = this.inet_pton(range[0]) !== false && this.inet_pton(range[1]) !== false;
1396
+ } else if (range[0].match('.')) {
1397
+ validRange = this.inet_aton(range[0]) !== false && this.inet_aton(range[1]) !== false;
1398
+ }
1399
+ if (!validRange) {
1400
this.colorbox('300px', 'Specify a valid IP range', "Please specify a valid IP address range in the form of \"1.2.3.4 - 1.2.3.5\" without quotes. Make sure the dash between the IP addresses in a normal dash (a minus sign on your keyboard) and not another character that looks like a dash.");
1401
return;
1402
}
1879
}
1880
return d;
1881
},
1882
+
1883
+ inet_pton: function(a) {
1884
+ // discuss at: http://phpjs.org/functions/inet_pton/
1885
+ // original by: Theriault
1886
+ // example 1: inet_pton('::');
1887
+ // returns 1: '\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0'
1888
+ // example 2: inet_pton('127.0.0.1');
1889
+ // returns 2: '\x7F\x00\x00\x01'
1890
+
1891
+ var r, m, x, i, j, f = String.fromCharCode;
1892
+ m = a.match(/^(?:\d{1,3}(?:\.|$)){4}/); // IPv4
1893
+ if (m) {
1894
+ m = m[0].split('.');
1895
+ m = f(m[0]) + f(m[1]) + f(m[2]) + f(m[3]);
1896
+ // Return if 4 bytes, otherwise false.
1897
+ return m.length === 4 ? m : false;
1898
+ }
1899
+ r = /^((?:[\da-f]{1,4}(?::|)){0,8})(::)?((?:[\da-f]{1,4}(?::|)){0,8})#x2F;;
1900
+ m = a.match(r); // IPv6
1901
+ if (m) {
1902
+ // Translate each hexadecimal value.
1903
+ for (j = 1; j < 4; j++) {
1904
+ // Indice 2 is :: and if no length, continue.
1905
+ if (j === 2 || m[j].length === 0) {
1906
+ continue;
1907
+ }
1908
+ m[j] = m[j].split(':');
1909
+ for (i = 0; i < m[j].length; i++) {
1910
+ m[j][i] = parseInt(m[j][i], 16);
1911
+ // Would be NaN if it was blank, return false.
1912
+ if (isNaN(m[j][i])) {
1913
+ return false; // Invalid IP.
1914
+ }
1915
+ m[j][i] = f(m[j][i] >> 8) + f(m[j][i] & 0xFF);
1916
+ }
1917
+ m[j] = m[j].join('');
1918
+ }
1919
+ x = m[1].length + m[3].length;
1920
+ if (x === 16) {
1921
+ return m[1] + m[3];
1922
+ } else if (x < 16 && m[2].length > 0) {
1923
+ return m[1] + (new Array(16 - x + 1))
1924
+ .join('\x00') + m[3];
1925
+ }
1926
+ }
1927
+ return false; // Invalid IP.
1928
+ },
1929
+ inet_ntop: function(a) {
1930
+ // discuss at: http://phpjs.org/functions/inet_ntop/
1931
+ // original by: Theriault
1932
+ // example 1: inet_ntop('\x7F\x00\x00\x01');
1933
+ // returns 1: '127.0.0.1'
1934
+ // example 2: inet_ntop('\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\1');
1935
+ // returns 2: '::1'
1936
+
1937
+ var i = 0,
1938
+ m = '',
1939
+ c = [];
1940
+ a += '';
1941
+ if (a.length === 4) { // IPv4
1942
+ return [
1943
+ a.charCodeAt(0), a.charCodeAt(1), a.charCodeAt(2), a.charCodeAt(3)].join('.');
1944
+ } else if (a.length === 16) { // IPv6
1945
+ for (i = 0; i < 16; i++) {
1946
+ c.push(((a.charCodeAt(i++) << 8) + a.charCodeAt(i))
1947
+ .toString(16));
1948
+ }
1949
+ return c.join(':')
1950
+ .replace(/((^|:)0(?=:|$))+:?/g, function(t) {
1951
+ m = (t.length > m.length) ? t : m;
1952
+ return t;
1953
+ })
1954
+ .replace(m || ' ', '::');
1955
+ } else { // Invalid length
1956
+ return false;
1957
+ }
1958
+ },
1959
+
1960
removeCacheExclusion: function(id) {
1961
this.ajax('wordfence_removeCacheExclusion', {id: id}, function(res) {
1962
window.location.reload(true);
lib/GeoIP.dat CHANGED
Binary file
lib/dashboard.php CHANGED
@@ -32,6 +32,7 @@
32
<?php if(wfConfig::get('scansEnabled_themes')){ ?><tr><td style="padding-right: 20px;">Scan Themes:</td><td style="color: #0F0;">&#10004;</td></tr> <?php } ?>
33
<?php if(wfConfig::get('scansEnabled_plugins')){ ?><tr><td style="padding-right: 20px;">Scan Plugins:</td><td style="color: #0F0;">&#10004;</td></tr> <?php } ?>
34
<?php if(wfConfig::get('scansEnabled_fileContents')){ ?><tr><td style="padding-right: 20px;">Scan Other Files:</td><td style="color: #0F0;">&#10004;</td></tr> <?php } ?>
35
<?php if(wfConfig::get('scansEnabled_posts')){ ?><tr><td style="padding-right: 20px;">Scan Posts:</td><td style="color: #0F0;">&#10004;</td></tr> <?php } ?>
36
<?php if(wfConfig::get('scansEnabled_comments')){ ?><tr><td style="padding-right: 20px;">Scan Comments:</td><td style="color: #0F0;">&#10004;</td></tr> <?php } ?>
37
<?php if(wfConfig::get('scansEnabled_oldVersions')){ ?><tr><td style="padding-right: 20px;">Scan for Old Software:</td><td style="color: #0F0;">&#10004;</td></tr> <?php } ?>
32
<?php if(wfConfig::get('scansEnabled_themes')){ ?><tr><td style="padding-right: 20px;">Scan Themes:</td><td style="color: #0F0;">&#10004;</td></tr> <?php } ?>
33
<?php if(wfConfig::get('scansEnabled_plugins')){ ?><tr><td style="padding-right: 20px;">Scan Plugins:</td><td style="color: #0F0;">&#10004;</td></tr> <?php } ?>
34
<?php if(wfConfig::get('scansEnabled_fileContents')){ ?><tr><td style="padding-right: 20px;">Scan Other Files:</td><td style="color: #0F0;">&#10004;</td></tr> <?php } ?>
35
+ <?php if(wfConfig::get('scansEnabled_database')){ ?><tr><td style="padding-right: 20px;">Scan Database:</td><td style="color: #0F0;">&#10004;</td></tr> <?php } ?>
36
<?php if(wfConfig::get('scansEnabled_posts')){ ?><tr><td style="padding-right: 20px;">Scan Posts:</td><td style="color: #0F0;">&#10004;</td></tr> <?php } ?>
37
<?php if(wfConfig::get('scansEnabled_comments')){ ?><tr><td style="padding-right: 20px;">Scan Comments:</td><td style="color: #0F0;">&#10004;</td></tr> <?php } ?>
38
<?php if(wfConfig::get('scansEnabled_oldVersions')){ ?><tr><td style="padding-right: 20px;">Scan for Old Software:</td><td style="color: #0F0;">&#10004;</td></tr> <?php } ?>
lib/menu_options.php CHANGED
@@ -462,6 +462,14 @@ $w = new wfConfig();
462
name="scansEnabled_fileContents"
463
value="1" <?php $w->cb( 'scansEnabled_fileContents' ); ?>/></td>
464
</tr>
465
<tr>
466
<th>Scan posts for known dangerous URLs and suspicious content<a
467
href="http://docs.wordfence.com/en/Wordfence_options#Scan_posts_for_known_dangerous_URLs_and_suspicious_content"
462
name="scansEnabled_fileContents"
463
value="1" <?php $w->cb( 'scansEnabled_fileContents' ); ?>/></td>
464
</tr>
465
+ <tr>
466
+ <th>Scan database for backdoors, trojans and suspicious code<a
467
+ href="http://docs.wordfence.com/en/Wordfence_options#Scan_database_for_backdoors.2C_trojans_and_suspicious_code"
468
+ target="_blank" class="wfhelp"></a></th>
469
+ <td><input type="checkbox" id="scansEnabled_database" class="wfConfigElem"
470
+ name="scansEnabled_database"
471
+ value="1" <?php $w->cb( 'scansEnabled_database' ); ?>/></td>
472
+ </tr>
473
<tr>
474
<th>Scan posts for known dangerous URLs and suspicious content<a
475
href="http://docs.wordfence.com/en/Wordfence_options#Scan_posts_for_known_dangerous_URLs_and_suspicious_content"
lib/menu_rangeBlocking.php CHANGED
@@ -7,7 +7,7 @@
7
<?php if(! wfConfig::get('firewallEnabled')){ ?><div style="color: #F00; font-weight: bold;">Firewall is disabled. You can enable it on the <a href="admin.php?page=WordfenceSecOpt">Wordfence Options page</a> at the top.</div><br /><?php } ?>
8
<table class="wfConfigForm">
9
<tr><th>IP address range:</th><td><input id="ipRange" type="text" size="30" maxlength="255" value="<?php
10
- if( isset( $_GET['wfBlockRange'] ) && preg_match('/^[\d\.\s\t\-]+#x2F;', $_GET['wfBlockRange']) ){ echo wp_kses($_GET['wfBlockRange'], array()); }
11
?>" onkeyup="WFAD.calcRangeTotal();">&nbsp;<span id="wfShowRangeTotal"></span></td></tr>
12
<tr><td></td><td style="padding-bottom: 15px;"><strong>Examples:</strong> 192.168.200.200 - 192.168.200.220</td></tr>
13
<tr><th>User-Agent (browser) that matches:</th><td><input id="uaRange" type="text" size="30" maxlength="255" >&nbsp;(Case insensitive)</td></tr>
@@ -29,8 +29,8 @@
29
</div>
30
<script type="text/x-jquery-template" id="wfBlockedRangesTmpl">
31
<div>
32
- <div style="border-bottom: 1px solid #CCC; padding-bottom: 10px; margin-bottom: 10px;">
33
- <table border="0" style="width: 100%">
34
{{each(idx, elem) results}}
35
<tr><td>
36
{{if patternDisabled}}
7
<?php if(! wfConfig::get('firewallEnabled')){ ?><div style="color: #F00; font-weight: bold;">Firewall is disabled. You can enable it on the <a href="admin.php?page=WordfenceSecOpt">Wordfence Options page</a> at the top.</div><br /><?php } ?>
8
<table class="wfConfigForm">
9
<tr><th>IP address range:</th><td><input id="ipRange" type="text" size="30" maxlength="255" value="<?php
10
+ if( isset( $_GET['wfBlockRange'] ) && preg_match('/^[\da-f\.\s\t\-:]+#x2F;i', $_GET['wfBlockRange']) ){ echo wp_kses($_GET['wfBlockRange'], array()); }
11
?>" onkeyup="WFAD.calcRangeTotal();">&nbsp;<span id="wfShowRangeTotal"></span></td></tr>
12
<tr><td></td><td style="padding-bottom: 15px;"><strong>Examples:</strong> 192.168.200.200 - 192.168.200.220</td></tr>
13
<tr><th>User-Agent (browser) that matches:</th><td><input id="uaRange" type="text" size="30" maxlength="255" >&nbsp;(Case insensitive)</td></tr>
29
</div>
30
<script type="text/x-jquery-template" id="wfBlockedRangesTmpl">
31
<div>
32
+ <div style="padding-bottom: 10px; margin-bottom: 10px;">
33
+ <table border="0" style="width: 100%" class="block-ranges-table">
34
{{each(idx, elem) results}}
35
<tr><td>
36
{{if patternDisabled}}
lib/menu_scan.php CHANGED
@@ -556,6 +556,57 @@
556
</div>
557
</div>
558
</script>
559
<script type="text/x-jquery-template" id="issueTmpl_pubBadURLs">
560
<div>
561
<div class="wfIssue">
556
</div>
557
</div>
558
</script>
559
+ <script type="text/x-jquery-template" id="issueTmpl_database">
560
+ <div>
561
+ <div class="wfIssue">
562
+ <h2>${shortMsg}</h2>
563
+ <p>
564
+ <table border="0" class="wfIssue" cellspacing="0" cellpadding="0">
565
+ <tr><th>Option Name:</th><td>${data.option_name}</td></tr>
566
+ {{if ((typeof data.badURL !== 'undefined') && data.badURL)}}
567
+ <tr><th>Bad URL:</th><td><strong class="wfWarn">${data.badURL}</strong></td></tr>
568
+ {{/if}}
569
+ <tr><th>Issue first detected:</th><td>${timeAgo} ago.</td></tr>
570
+ <tr><th>Severity:</th><td>{{if severity == '1'}}Critical{{else}}Warning{{/if}}</td></tr>
571
+ <tr><th>Status</th><td>
572
+ {{if status == 'new' }}New{{/if}}
573
+ {{if status == 'ignoreP' }}Permanently ignoring this option{{/if}}
574
+ {{if status == 'ignoreC' }}Ignoring this option until it changes{{/if}}
575
+ </td></tr>
576
+ </table>
577
+ </p>
578
+ <p>
579
+ {{html longMsg}}
580
+ </p>
581
+ <div class="wfIssueOptions">
582
+ <strong>Tools:</strong>
583
+ {{if data.optionExists}}
584
+ <a target="_blank" href="${WFAD.makeViewOptionLink(data.option_name, data.site_id)}">View this option.</a>
585
+ {{/if}}
586
+ {{if data.canDelete}}
587
+ <a href="#" onclick="WFAD.deleteDatabaseOption('${id}'); return false;">Delete this option from the database (can't be undone).</a>
588
+ <br />&nbsp;<input type="checkbox" class="wfdelCheckbox" value="${id}" />&nbsp;Select for bulk delete
589
+ {{/if}}
590
+ </div>
591
+ <div class="wfIssueOptions">
592
+ {{if status == 'new'}}
593
+ <strong>Resolve:</strong>
594
+ <a href="#" onclick="WFAD.updateIssueStatus('${id}', 'delete'); return false;">I have fixed this issue</a>
595
+ {{if data.optionExists}}
596
+ <a href="#" onclick="WFAD.updateIssueStatus('${id}', 'ignoreC'); return false;">Ignore until the option changes.</a>
597
+ <a href="#" onclick="WFAD.updateIssueStatus('${id}', 'ignoreP'); return false;">Always ignore this option.</a>
598
+ {{else}}
599
+ <a href="#" onclick="WFAD.updateIssueStatus('${id}', 'ignoreC'); return false;">Ignore missing option.</a>
600
+ {{/if}}
601
+
602
+ {{/if}}
603
+ {{if status == 'ignoreC' || status == 'ignoreP'}}
604
+ <a href="#" onclick="WFAD.updateIssueStatus('${id}', 'delete'); return false;">Stop ignoring this issue.</a>
605
+ {{/if}}
606
+ </div>
607
+ </div>
608
+ </div>
609
+ </script>
610
<script type="text/x-jquery-template" id="issueTmpl_pubBadURLs">
611
<div>
612
<div class="wfIssue">
lib/wfActivityReport.php CHANGED
@@ -339,13 +339,15 @@ SQL
339
340
/**
341
* @param mixed $ip_address
342
- * @param null $unixday
343
*/
344
public static function logBlockedIP($ip_address, $unixday = null) {
345
global $wpdb;
346
347
- if (is_string($ip_address) && !is_numeric($ip_address)) {
348
- $ip_address = wfUtils::inet_aton($ip_address);
349
}
350
351
$blocked_table = "{$wpdb->base_prefix}wfBlockedIPLog";
@@ -355,7 +357,7 @@ SQL
355
$unixday_insert = absint($unixday);
356
}
357
358
- $country = wfUtils::IP2Country(is_numeric($ip_address) ? wfUtils::inet_ntoa($ip_address) : $ip_address);
359
360
$wpdb->query($wpdb->prepare(<<<SQL
361
INSERT INTO $blocked_table (IP, countryCode, blockCount, unixday)
339
340
/**
341
* @param mixed $ip_address
342
+ * @param int|null $unixday
343
*/
344
public static function logBlockedIP($ip_address, $unixday = null) {
345
+ /** @var wpdb $wpdb */
346
global $wpdb;
347
348
+ $is_bin_ip = !wfUtils::isValidIP($ip_address);
349
+ if (!$is_bin_ip) {
350
+ $ip_address = wfUtils::inet_pton($ip_address);
351
}
352
353
$blocked_table = "{$wpdb->base_prefix}wfBlockedIPLog";
357
$unixday_insert = absint($unixday);
358
}
359
360
+ $country = wfUtils::IP2Country($is_bin_ip ? wfUtils::inet_ntop($ip_address) : $ip_address);
361
362
$wpdb->query($wpdb->prepare(<<<SQL
363
INSERT INTO $blocked_table (IP, countryCode, blockCount, unixday)
lib/wfCache.php CHANGED
@@ -578,6 +578,11 @@ EOT;
578
self::updateBlockedIPs('add'); //Fail silently if .htaccess is not readable. Will fall back to old blocking via WP
579
wp_schedule_single_event(time() + 300, 'wordfence_update_blocked_IPs');
580
}
581
public static function updateBlockedIPs($action){ //'add' or 'remove'
582
if(wfConfig::get('cacheType') != 'falcon'){ return; }
583
@@ -635,9 +640,19 @@ EOT;
635
636
if($range){
637
if($browser || $referer){ continue; } //We don't allow combos in falcon
638
- $ips = explode('-', $range);
639
- $cidrs = wfUtils::rangeToCIDRs($ips[0], $ips[1]);
640
- $hIPs = wfUtils::inet_ntoa($ips[0]) . ' - ' . wfUtils::inet_ntoa($ips[1]);
641
if(sizeof($cidrs) > 0){
642
$lines[] = '#Start of blocking code for IP range: ' . $hIPs . "\n";
643
foreach($cidrs as $c){
578
self::updateBlockedIPs('add'); //Fail silently if .htaccess is not readable. Will fall back to old blocking via WP
579
wp_schedule_single_event(time() + 300, 'wordfence_update_blocked_IPs');
580
}
581
+
582
+ /**
583
+ * @param $action
584
+ * @return bool|string|void
585
+ */
586
public static function updateBlockedIPs($action){ //'add' or 'remove'
587
if(wfConfig::get('cacheType') != 'falcon'){ return; }
588
640
641
if($range){
642
if($browser || $referer){ continue; } //We don't allow combos in falcon
643
+
644
+ list($start_range, $end_range) = explode('-', $range);
645
+ if (preg_match('/[\.:]/', $start_range)) {
646
+ $start_range = wfUtils::inet_pton($start_range);
647
+ $end_range = wfUtils::inet_pton($end_range);
648
+ } else {
649
+ $start_range = wfUtils::inet_pton(long2ip($start_range));
650
+ $end_range = wfUtils::inet_pton(long2ip($end_range));
651
+ }
652
+
653
+ $cidrs = wfUtils::rangeToCIDRs($start_range, $end_range);
654
+
655
+ $hIPs = wfUtils::inet_ntop($start_range) . ' - ' . wfUtils::inet_ntop($end_range);
656
if(sizeof($cidrs) > 0){
657
$lines[] = '#Start of blocking code for IP range: ' . $hIPs . "\n";
658
foreach($cidrs as $c){
lib/wfConfig.php CHANGED
@@ -34,6 +34,7 @@ class wfConfig {
34
"scansEnabled_plugins" => false,
35
"scansEnabled_malware" => false,
36
"scansEnabled_fileContents" => false,
37
"scansEnabled_posts" => false,
38
"scansEnabled_comments" => false,
39
"scansEnabled_passwds" => false,
@@ -121,6 +122,7 @@ class wfConfig {
121
"scansEnabled_plugins" => false,
122
"scansEnabled_malware" => true,
123
"scansEnabled_fileContents" => true,
124
"scansEnabled_posts" => true,
125
"scansEnabled_comments" => true,
126
"scansEnabled_passwds" => true,
@@ -208,6 +210,7 @@ class wfConfig {
208
"scansEnabled_plugins" => false,
209
"scansEnabled_malware" => true,
210
"scansEnabled_fileContents" => true,
211
"scansEnabled_posts" => true,
212
"scansEnabled_comments" => true,
213
"scansEnabled_passwds" => true,
@@ -295,6 +298,7 @@ class wfConfig {
295
"scansEnabled_plugins" => false,
296
"scansEnabled_malware" => true,
297
"scansEnabled_fileContents" => true,
298
"scansEnabled_posts" => true,
299
"scansEnabled_comments" => true,
300
"scansEnabled_passwds" => true,
@@ -382,6 +386,7 @@ class wfConfig {
382
"scansEnabled_plugins" => false,
383
"scansEnabled_malware" => true,
384
"scansEnabled_fileContents" => true,
385
"scansEnabled_posts" => true,
386
"scansEnabled_comments" => true,
387
"scansEnabled_passwds" => true,
34
"scansEnabled_plugins" => false,
35
"scansEnabled_malware" => false,
36
"scansEnabled_fileContents" => false,
37
+ "scansEnabled_database" => false,
38
"scansEnabled_posts" => false,
39
"scansEnabled_comments" => false,
40
"scansEnabled_passwds" => false,
122
"scansEnabled_plugins" => false,
123
"scansEnabled_malware" => true,
124
"scansEnabled_fileContents" => true,
125
+ "scansEnabled_database" => true,
126
"scansEnabled_posts" => true,
127
"scansEnabled_comments" => true,
128
"scansEnabled_passwds" => true,
210
"scansEnabled_plugins" => false,
211
"scansEnabled_malware" => true,
212
"scansEnabled_fileContents" => true,
213
+ "scansEnabled_database" => true,
214
"scansEnabled_posts" => true,
215
"scansEnabled_comments" => true,
216
"scansEnabled_passwds" => true,
298
"scansEnabled_plugins" => false,
299
"scansEnabled_malware" => true,
300
"scansEnabled_fileContents" => true,
301
+ "scansEnabled_database" => true,
302
"scansEnabled_posts" => true,
303
"scansEnabled_comments" => true,
304
"scansEnabled_passwds" => true,
386
"scansEnabled_plugins" => false,
387
"scansEnabled_malware" => true,
388
"scansEnabled_fileContents" => true,
389
+ "scansEnabled_database" => true,
390
"scansEnabled_posts" => true,
391
"scansEnabled_comments" => true,
392
"scansEnabled_passwds" => true,
lib/wfCrawl.php CHANGED
@@ -12,7 +12,7 @@ class wfCrawl {
12
public static function verifyCrawlerPTR($hostPattern, $IP){
13
global $wpdb; $table = $wpdb->base_prefix . 'wfCrawlers';
14
$db = new wfDB();
15
- $IPn = wfUtils::inet_aton($IP);
16
$status = $db->querySingle("select status from $table where IP=%s and patternSig=UNHEX(MD5('%s')) and lastUpdate > unix_timestamp() - %d", $IPn, $hostPattern, WORDFENCE_CRAWLER_VERIFY_CACHE_TIME);
17
if($status){
18
if($status == 'verified'){
@@ -27,7 +27,7 @@ class wfCrawl {
27
return false;
28
}
29
if(preg_match($hostPattern, $host)){
30
- $resultIPs = gethostbynamel($host);
31
$addrsMatch = false;
32
foreach($resultIPs as $resultIP){
33
if($resultIP == $IP){
@@ -89,5 +89,14 @@ class wfCrawl {
89
'@^Google$@'
90
);
91
92
}
93
?>
12
public static function verifyCrawlerPTR($hostPattern, $IP){
13
global $wpdb; $table = $wpdb->base_prefix . 'wfCrawlers';
14
$db = new wfDB();
15
+ $IPn = wfUtils::inet_pton($IP);
16
$status = $db->querySingle("select status from $table where IP=%s and patternSig=UNHEX(MD5('%s')) and lastUpdate > unix_timestamp() - %d", $IPn, $hostPattern, WORDFENCE_CRAWLER_VERIFY_CACHE_TIME);
17
if($status){
18
if($status == 'verified'){
27
return false;
28
}
29
if(preg_match($hostPattern, $host)){
30
+ $resultIPs = wfUtils::resolveDomainName($host);
31
$addrsMatch = false;
32
foreach($resultIPs as $resultIP){
33
if($resultIP == $IP){
89
'@^Google$@'
90
);
91
92
+
93
+ /**
94
+ * Has correct user agent and PTR record points to .googlebot.com domain.
95
+ *
96
+ * @return bool
97
+ */
98
+ public static function isVerifiedGoogleCrawler() {
99
+ return self::isGoogleCrawler() && self::verifyCrawlerPTR(wordfence::getLog()->getGooglePattern(), wfUtils::getIP());
100
+ }
101
}
102
?>
lib/wfHelperBin.php ADDED
@@ -0,0 +1,78 @@
1
+ <?php
2
+
3
+ class wfHelperBin {
4
+
5
+ /**
6
+ * @param string $bin1
7
+ * @param string $bin2
8
+ * @return mixed
9
+ */
10
+ public static function addbin2bin($bin1, $bin2) {
11
+ if (strlen($bin1) % 4 != 0) {
12
+ $bin1 = str_repeat("\0", 4 - (strlen($bin1) % 4)) . $bin1;
13
+ }
14
+ if (strlen($bin2) % 4 != 0) {
15
+ $bin2 = str_repeat("\0", 4 - (strlen($bin2) % 4)) . $bin2;
16
+ }
17
+
18
+ $bin1_ints = array_reverse(array_values(unpack('N*', $bin1)));
19
+ $bin2_ints = array_reverse(array_values(unpack('N*', $bin2)));
20
+ $return = array();
21
+ $carries = 0;
22
+ for ($i=0; $i < max(count($bin1_ints), count($bin2_ints)); $i++) {
23
+ $int1 = array_key_exists($i, $bin1_ints) ? $bin1_ints[$i] : 0;
24
+ $int2 = array_key_exists($i, $bin2_ints) ? $bin2_ints[$i] : 0;
25
+ $val = $int1 + $int2 + $carries;
26
+ if ($carries > 0) {
27
+ $carries = 0;
28
+ }
29
+ if ($val >= 0x100000000) {
30
+ $val -= 0x100000000;
31
+ $carries++;
32
+ }
33
+ $return[] = $val;
34
+ }
35
+ if ($carries) {
36
+ $return[] += $carries;
37
+ }
38
+ $return = array_reverse($return);
39
+ array_unshift($return, 'N*');
40
+ $return = call_user_func_array('pack', $return);
41
+ $return = ltrim($return, "\x00");
42
+ return strlen($return) == 0 ? "\x00" : $return;
43
+ }
44
+
45
+ /**
46
+ * Convert binary string to the 10101's representation.
47
+ *
48
+ * @param string $string
49
+ * @return string
50
+ */
51
+ public static function bin2str($string) {
52
+ $return = '';
53
+ for ($i = 0; $i < strlen($string); $i++) {
54
+ $return .= str_pad(decbin(ord($string[$i])), 8, '0', STR_PAD_LEFT);
55
+ }
56
+ $return = ltrim($return, '0');
57
+ return strlen($return) == 0 ? '0' : $return;
58
+ }
59
+
60
+ /**
61
+ * Convert 10101's representation back to the binary data.
62
+ *
63
+ * @param string $string
64
+ * @return string
65
+ */
66
+ public static function str2bin($string) {
67
+ if (strlen($string) % 32 > 0) {
68
+ $string = str_repeat('0', 32 - (strlen($string) % 32)) . $string;
69
+ }
70
+ $ints = str_split($string, 32);
71
+ $return = '';
72
+ foreach ($ints as $int) {
73
+ $return .= pack('N', bindec($int));
74
+ }
75
+ $return = ltrim($return, "\0");
76
+ return strlen($return) == 0 ? "\0" : $return;
77
+ }
78
+ }
lib/wfIssues.php CHANGED
@@ -26,14 +26,14 @@ class wfIssues {
26
$ignoreC, /* some piece of data used for md5 for ignoring until something changes */
27
$shortMsg, $longMsg, $templateData
28
){
29
-
30
31
$ignoreP = md5($ignoreP);
32
$ignoreC = md5($ignoreC);
33
$rec = $this->getDB()->querySingleRec("select status, ignoreP, ignoreC from " . $this->issuesTable . " where (ignoreP='%s' OR ignoreC='%s')", $ignoreP, $ignoreC);
34
if($rec){
35
if($rec['status'] == 'new' && ($rec['ignoreC'] == $ignoreC || $rec['ignoreP'] == $ignoreP)){
36
- if($type != 'file'){ //Filter out duplicate new issues but not infected files because we want to see all infections even if file contents are identical
37
return false;
38
}
39
}
@@ -172,7 +172,9 @@ class wfIssues {
172
$rec['data'] = unserialize($rec['data']);
173
return $rec;
174
}
175
- public function getIssues(){
176
$ret = array(
177
'new' => array(),
178
'ignored' => array()
@@ -200,6 +202,10 @@ class wfIssues {
200
$issueList[$i]['data']['fileExists'] = '';
201
}
202
}
203
$issueList[$i]['issueIDX'] = $i;
204
}
205
}
26
$ignoreC, /* some piece of data used for md5 for ignoring until something changes */
27
$shortMsg, $longMsg, $templateData
28
){
29
+
30
31
$ignoreP = md5($ignoreP);
32
$ignoreC = md5($ignoreC);
33
$rec = $this->getDB()->querySingleRec("select status, ignoreP, ignoreC from " . $this->issuesTable . " where (ignoreP='%s' OR ignoreC='%s')", $ignoreP, $ignoreC);
34
if($rec){
35
if($rec['status'] == 'new' && ($rec['ignoreC'] == $ignoreC || $rec['ignoreP'] == $ignoreP)){
36
+ if($type != 'file' && $type != 'database'){ //Filter out duplicate new issues but not infected files because we want to see all infections even if file contents are identical
37
return false;
38
}
39
}
172
$rec['data'] = unserialize($rec['data']);
173
return $rec;
174
}
175
+ public function getIssues(){
176
+ /** @var wpdb $wpdb */
177
+ global $wpdb;
178
$ret = array(
179
'new' => array(),
180
'ignored' => array()
202
$issueList[$i]['data']['fileExists'] = '';
203
}
204
}
205
+ if ($issueList[$i]['type'] == 'database') {
206
+ $prefix = $wpdb->get_blog_prefix($issueList[$i]['data']['site_id']);
207
+ $issueList[$i]['data']['optionExists'] = $wpdb->get_var($wpdb->prepare("SELECT count(*) FROM {$prefix}options WHERE option_name = %s", $issueList[$i]['data']['option_name'])) > 0;
208
+ }
209
$issueList[$i]['issueIDX'] = $i;
210
}
211
}
lib/wfLog.php CHANGED
@@ -26,7 +26,7 @@ class wfLog {
26
$this->perfTable = $wpdb->base_prefix . 'wfPerfLog';
27
}
28
public function logPerf($IP, $UA, $URL, $data){
29
- $IP = wfUtils::inet_aton($IP);
30
$this->getDB()->queryWrite("insert into " . $this->perfTable . " (IP, userID, UA, URL, ctime, fetchStart, domainLookupStart, domainLookupEnd, connectStart, connectEnd, requestStart, responseStart, responseEnd, domReady, loaded) values (%s, %d, '%s', '%s', unix_timestamp(), %d, %d, %d, %d, %d, %d, %d, %d, %d, %d)",
31
$IP,
32
$this->getCurrentUserID(),
@@ -67,7 +67,7 @@ class wfLog {
67
$action,
68
$username,
69
$userID,
70
- wfUtils::inet_aton(wfUtils::getIP()),
71
(isset($_SERVER['HTTP_USER_AGENT']) ? $_SERVER['HTTP_USER_AGENT'] : '')
72
);
73
}
@@ -79,10 +79,17 @@ class wfLog {
79
if(wfConfig::get('firewallEnabled')){
80
//Moved the following block into the "is fw enabled section" for optimization.
81
$IP = wfUtils::getIP();
82
- $IPnum = wfUtils::inet_aton($IP);
83
if($this->isWhitelisted($IP)){
84
return;
85
}
86
if($type == '404'){
87
$table = $this->scanTable;
88
} else if($type == 'hit'){
@@ -91,7 +98,7 @@ class wfLog {
91
wordfence::status(1, 'error', "Invalid type to logLeechAndBlock(): $type");
92
return;
93
}
94
- $this->getDB()->queryWrite("insert into $table (eMin, IP, hits) values (floor(unix_timestamp() / 60), %s, 1) ON DUPLICATE KEY update hits = IF(@wfcurrenthits := hits + 1, hits + 1, hits + 1)", wfUtils::inet_aton($IP));
95
$hitsPerMinute = $this->getDB()->querySingle("select @wfcurrenthits");
96
//end block moved into "is fw enabled" section
97
@@ -126,7 +133,7 @@ class wfLog {
126
if($pat){
127
$URL = wfUtils::getRequestedURL();
128
if(preg_match($pat, $URL)){
129
- $this->getDB()->queryWrite("insert IGNORE into $p"."wfVulnScanners (IP, ctime, hits) values (INET_ATON('%s'), unix_timestamp(), 1) ON DUPLICATE KEY UPDATE ctime = unix_timestamp(), hits = hits + 1", $IP);
130
if(wfConfig::get('maxScanHits') != 'DISABLED'){
131
if( empty($_SERVER['HTTP_REFERER'] )){
132
$this->getDB()->queryWrite("insert into " . $this->badLeechersTable . " (eMin, IP, hits) values (floor(unix_timestamp() / 60), %s, 1) ON DUPLICATE KEY update hits = IF(@wfblcurrenthits := hits + 1, hits + 1, hits + 1)", $IPnum);
@@ -159,42 +166,36 @@ class wfLog {
159
}
160
}
161
}
162
- public function isWhitelisted($IP){
163
- $IPnum = wfUtils::inet_aton($IP);
164
- if($IPnum > 1160651777 && $IPnum < 1160651808){ //IP is in Wordfence's IP block which would prevent our scanning server manually kicking off scans that are stuck
165
return true;
166
}
167
//We now whitelist all private addrs
168
- if(wfUtils::isPrivateAddress($IP)){
169
return true;
170
}
171
//These belong to sucuri's scanning servers which will get blocked by Wordfence as a false positive if you try a scan. So we whitelisted them.
172
- $externalWhite = array('97.74.127.171','69.164.203.172','173.230.128.135','66.228.34.49','66.228.40.185','50.116.36.92','50.116.36.93','50.116.3.171','198.58.96.212','50.116.63.221','192.155.92.112','192.81.128.31','198.58.106.244','192.155.95.139','23.239.9.227','198.58.112.103','192.155.94.43','162.216.16.33','173.255.233.124','173.255.233.124','192.155.90.179','50.116.41.217','192.81.129.227','198.58.111.80');
173
- if(in_array($IP, $externalWhite)){
174
return true;
175
}
176
$list = wfConfig::get('whitelisted');
177
- if(! $list){ return false; }
178
$list = explode(',', $list);
179
- if(sizeof($list) < 1){ return false; }
180
- foreach($list as $whiteIP){
181
- if(preg_match('/\[\d+\-\d+\]/', $whiteIP)){
182
- $IPparts = explode('.', $IP);
183
- $whiteParts = explode('.', $whiteIP);
184
- $mismatch = false;
185
- for($i = 0; $i <= 3; $i++){
186
- if(preg_match('/^\[(\d+)\-(\d+)\]#x2F;', $whiteParts[$i], $m)){
187
- if($IPparts[$i] < $m[1] || $IPparts[$i] > $m[2]){
188
- $mismatch = true;
189
- }
190
- } else if($whiteParts[$i] != $IPparts[$i]){
191
- $mismatch = true;
192
- }
193
- }
194
- if($mismatch === false){
195
- return true; //Is whitelisted because we did not get a mismatch
196
- }
197
- } else if($whiteIP == $IP){
198
return true;
199
}
200
}
@@ -221,7 +222,7 @@ class wfLog {
221
}
222
223
// These belong to sucuri's scanning servers which will get blocked by Wordfence as a false positive if you try a scan. So we whitelisted them.
224
- $white_listed_ips = array_merge($white_listed_ips, array_map(array('wfUtils', 'inet_aton'), array('97.74.127.171', '69.164.203.172', '173.230.128.135', '66.228.34.49', '66.228.40.185', '50.116.36.92', '50.116.36.93', '50.116.3.171', '198.58.96.212', '50.116.63.221', '192.155.92.112', '192.81.128.31', '198.58.106.244', '192.155.95.139', '23.239.9.227', '198.58.112.103', '192.155.94.43', '162.216.16.33', '173.255.233.124', '173.255.233.124', '192.155.90.179', '50.116.41.217', '192.81.129.227', '198.58.111.80')));
225
226
if ($user_whitelisted === null) {
227
$user_whitelisted = wfConfig::get('whitelisted');
@@ -245,13 +246,21 @@ class wfLog {
245
$this->getDB()->queryWrite("delete from " . $this->lockOutTable);
246
}
247
public function unblockIP($IP){
248
- $this->getDB()->queryWrite("delete from " . $this->blocksTable . " where IP=%s", wfUtils::inet_aton($IP));
249
wfCache::updateBlockedIPs('add');
250
}
251
public function unblockRange($id){
252
$this->getDB()->queryWrite("delete from " . $this->ipRangesTable . " where id=%d", $id);
253
wfCache::updateBlockedIPs('add');
254
}
255
public function blockRange($blockType, $range, $reason){
256
$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);
257
wfCache::updateBlockedIPs('add');
@@ -284,8 +293,12 @@ class wfLog {
284
$numBlockElements = 0;
285
if($blockDat[0]){
286
$numBlockElements++;
287
- $ipDat = explode('-', $blockDat[0]);
288
- $elem['ipPattern'] = "Block visitors with IP addresses in the range: " . wfUtils::inet_ntoa($ipDat[0]) . ' - ' . wfUtils::inet_ntoa($ipDat[1]);
289
} else {
290
$elem['ipPattern'] = 'Allow all IP addresses';
291
}
@@ -316,7 +329,7 @@ class wfLog {
316
if($permanent){
317
//Insert permanent=1 or update existing perm or non-per block to be permanent
318
$this->getDB()->queryWrite("insert into " . $this->blocksTable . " (IP, blockedTime, reason, wfsn, permanent) values (%s, %d, '%s', %d, %d) ON DUPLICATE KEY update blockedTime=%d, reason='%s', wfsn=%d, permanent=%d",
319
- wfUtils::inet_aton($IP),
320
$timeBlockOccurred,
321
$reason,
322
$wfsn,
@@ -329,7 +342,7 @@ class wfLog {
329
} else {
330
//insert perm=0 but don't update and make perm blocks non-perm.
331
$this->getDB()->queryWrite("insert into " . $this->blocksTable . " (IP, blockedTime, reason, wfsn, permanent) values (%s, %d, '%s', %d, %d) ON DUPLICATE KEY update blockedTime=%d, reason='%s', wfsn=%d",
332
- wfUtils::inet_aton($IP),
333
$timeBlockOccurred,
334
$reason,
335
$wfsn,
@@ -349,7 +362,7 @@ class wfLog {
349
public function lockOutIP($IP, $reason){
350
if($this->isWhitelisted($IP)){ return false; }
351
$this->getDB()->queryWrite("insert into " . $this->lockOutTable . " (IP, blockedTime, reason) values (%s, unix_timestamp(), '%s') ON DUPLICATE KEY update blockedTime=unix_timestamp(), reason='%s'",
352
- wfUtils::inet_aton($IP),
353
$reason,
354
$reason
355
);
@@ -360,11 +373,11 @@ class wfLog {
360
return true;
361
}
362
public function unlockOutIP($IP){
363
- $this->getDB()->queryWrite("delete from " . $this->lockOutTable . " where IP=%s", wfUtils::inet_aton($IP));
364
}
365
public function isIPLockedOut($IP){
366
- if($this->getDB()->querySingle("select IP from " . $this->lockOutTable . " where IP=%s and blockedTime + %s > unix_timestamp()", wfUtils::inet_aton($IP), wfConfig::get('loginSec_lockoutMins') * 60)){
367
- $this->getDB()->queryWrite("update " . $this->lockOutTable . " set blockedHits = blockedHits + 1, lastAttempt = unix_timestamp() where IP=%s", wfUtils::inet_aton($IP));
368
return true;
369
} else {
370
return false;
@@ -378,7 +391,7 @@ class wfLog {
378
}
379
$this->resolveIPs($results);
380
foreach($results as &$elem){
381
- $elem['IP'] = wfUtils::inet_ntoa($elem['IP']);
382
}
383
return $results;
384
}
@@ -391,15 +404,15 @@ class wfLog {
391
}
392
$this->resolveIPs($results);
393
foreach($results as &$elem){
394
- $elem['IP'] = wfUtils::inet_ntoa($elem['IP']);
395
}
396
return $results;
397
}
398
public function getBlockedIPsAddrOnly(){
399
- $results = $this->getDB()->querySelect("select INET_NTOA(IP) as IP from " . $this->blocksTable . " where (permanent=1 OR (blockedTime + %s > unix_timestamp()))", wfConfig::get('blockedTime'), wfConfig::get('blockedTime'));
400
$ret = array();
401
foreach($results as $elem){
402
- $ret[] = $elem['IP'];
403
}
404
return $ret;
405
}
@@ -431,7 +444,7 @@ class wfLog {
431
$this->resolveIPs($results);
432
foreach($results as &$elem){
433
$elem['blocked'] = 1;
434
- $elem['IP'] = wfUtils::inet_ntoa($elem['IP']);
435
}
436
return $results;
437
}
@@ -450,7 +463,7 @@ class wfLog {
450
$elem['timeAgo'] = wfUtils::makeTimeAgo($this->getDB()->querySingle("select unix_timestamp() - (eMin * 60) from $table where IP=%s", $elem['IP']));
451
$elem['blocked'] = $this->getDB()->querySingle("select blockedTime from " . $this->blocksTable . " where IP=%s and ((blockedTime + %s > unix_timestamp()) OR permanent = 1)", $elem['IP'], wfConfig::get('blockedTime'));
452
//take action
453
- $elem['IP'] = wfUtils::inet_ntoa($elem['IP']);
454
}
455
return $results;
456
}
@@ -466,7 +479,7 @@ class wfLog {
466
sprintf('%.6f', microtime(true)),
467
(is_404() ? 1 : 0),
468
(wfCrawl::isGoogleCrawler() ? 1 : 0),
469
- wfUtils::inet_aton(wfUtils::getIP()),
470
$this->getCurrentUserID(),
471
(wordfence::$newVisit ? 1 : 0),
472
wfUtils::getRequestedURL(),
@@ -482,7 +495,7 @@ class wfLog {
482
$browscap = new wfBrowscap();
483
foreach($results as &$res){
484
$res['timeAgo'] = wfUtils::makeTimeAgo($serverTime - $res['ctime']);
485
- $res['IP'] = wfUtils::inet_ntoa($res['IP']);
486
$res['browser'] = false;
487
if($res['UA']){
488
$b = $browscap->getBrowser($res['UA']);
@@ -516,8 +529,8 @@ class wfLog {
516
$serverTime = $this->getDB()->querySingle("select unix_timestamp()");
517
$IPSQL = "";
518
if($IP){
519
- $IPSQL = " and IP=INET_ATON(%s) ";
520
- $sqlArgs = array($afterTime, $IP, $limit);
521
} else {
522
$sqlArgs = array($afterTime, $limit);
523
}
@@ -559,7 +572,7 @@ class wfLog {
559
$res['type'] = $type;
560
$res['timeAgo'] = wfUtils::makeTimeAgo($serverTime - $res['ctime']);
561
$res['blocked'] = $this->getDB()->querySingle("select blockedTime from " . $this->blocksTable . " where IP=%s and (permanent = 1 OR (blockedTime + %s > unix_timestamp()))", $res['IP'], wfConfig::get('blockedTime'));
562
- $res['IP'] = wfUtils::inet_ntoa($res['IP']);
563
$res['extReferer'] = false;
564
if(isset( $res['referer'] ) && $res['referer']){
565
if(wfUtils::hasXSS($res['referer'] )){ //filtering out XSS
@@ -642,8 +655,9 @@ class wfLog {
642
$IPLocs = wfUtils::getIPsGeo($IPs); //Creates an array with IP as key and data as value
643
644
foreach($results as &$res){
645
- if(isset($IPLocs[$res['IP']])){
646
- $res['loc'] = $IPLocs[$res['IP']];
647
} else {
648
$res['loc'] = false;
649
}
@@ -696,7 +710,7 @@ class wfLog {
696
if($this->isWhitelisted($IP)){
697
return;
698
}
699
- $IPnum = wfUtils::inet_aton($IP);
700
701
//New range and UA pattern blocking:
702
$r1 = $this->getDB()->querySelect("select id, blockType, blockString from " . $this->ipRangesTable);
@@ -711,8 +725,16 @@ class wfLog {
711
$uaPattern = $bDat[1];
712
$refPattern = isset($bDat[2]) ? $bDat[2] : '';
713
if($ipRange){
714
- $ips = explode('-', $ipRange);
715
- if($IPnum >= $ips[0] && $IPnum <= $ips[1]){
716
$ipRangeBlocked = true;
717
}
718
}
@@ -872,7 +894,7 @@ class wfLog {
872
wordfence::status(2, 'info', "Blocking IP $IP. $reason");
873
} else if($action == 'throttle'){
874
$IP = wfUtils::getIP();
875
- $this->getDB()->queryWrite("insert into " . $this->throttleTable . " (IP, startTime, endTime, timesThrottled, lastReason) values (%s, unix_timestamp(), unix_timestamp(), 1, '%s') ON DUPLICATE KEY UPDATE endTime=unix_timestamp(), timesThrottled = timesThrottled + 1, lastReason='%s'", wfUtils::inet_aton($IP), $reason, $reason);
876
wordfence::status(2, 'info', "Throttling IP $IP. $reason");
877
wfConfig::inc('totalIPsThrottled');
878
$secsToGo = 60;
@@ -907,16 +929,11 @@ class wfLog {
907
} else if($nb == 'neverBlockUA' || $nb == 'neverBlockVerified'){
908
if(wfCrawl::isGoogleCrawler()){ //Check the UA using regex
909
if($nb == 'neverBlockVerified'){
910
- if(wfCrawl::isGooglebot()){ //UA is the one, the only, the original Googlebot
911
- if(wfCrawl::verifyCrawlerPTR($this->googlePattern, wfUtils::getIP())){ //UA check passed, now verify using PTR if configured to
912
- self::$gbSafeCache[$cacheKey] = false; //This is a verified Google crawler, so no we can't block it
913
- } else {
914
- self::$gbSafeCache[$cacheKey] = true; //This is a crawler claiming to be Google but it did not verify
915
- }
916
- } else { //UA isGoogleCrawler, but is not Googlebot itself. E.g. feedreader, google-site-verification, etc.
917
- self::$gbSafeCache[$cacheKey] = false; //This is a crawler with a google UA, but it's not Googlebot, so we don't block for safety. We can't verify these because they don't have a PTR record. e.g. Feedreader.
918
}
919
-
920
} else { //neverBlockUA
921
self::$gbSafeCache[$cacheKey] = false; //User configured us to only do a UA check and this claims to be google so don't block
922
}
@@ -966,12 +983,17 @@ class wfLog {
966
return array_reverse($results);
967
}
968
969
}
970
971
/**
972
- * @todo Add IPv6 support
973
*
974
- * Class wfUserIPRange
975
*/
976
class wfUserIPRange {
977
@@ -990,30 +1012,62 @@ class wfUserIPRange {
990
/**
991
* Check if the supplied IP address is within the user supplied range.
992
*
993
- * @param $ip
994
* @return bool
995
*/
996
public function isIPInRange($ip) {
997
$ip_string = $this->getIPString();
998
- if (preg_match('/\[\d+\-\d+\]/', $ip_string)) {
999
- $IPparts = explode('.', $ip);
1000
- $whiteParts = explode('.', $ip_string);
1001
- $mismatch = false;
1002
- for ($i = 0; $i <= 3; $i++) {
1003
- if (preg_match('/^\[(\d+)\-(\d+)\]#x2F;', $whiteParts[$i], $m)) {
1004
- if ($IPparts[$i] < $m[1] || $IPparts[$i] > $m[2]) {
1005
$mismatch = true;
1006
}
1007
- } else if ($whiteParts[$i] != $IPparts[$i]) {
1008
- $mismatch = true;
1009
}
1010
}
1011
- if ($mismatch === false) {
1012
- return true; // Is whitelisted because we did not get a mismatch
1013
}
1014
- } else if ($ip_string == $ip) {
1015
- return true;
1016
}
1017
return false;
1018
}
1019
@@ -1027,23 +1081,123 @@ class wfUserIPRange {
1027
/** @var wpdb $wpdb */
1028
global $wpdb;
1029
$ip_string = $this->getIPString();
1030
- if (preg_match('/\[\d+\-\d+\]/', $ip_string)) {
1031
- $sql = '(';
1032
$whiteParts = explode('.', $ip_string);
1033
for ($i = 0, $j = 24; $i <= 3; $i++, $j -= 8) {
1034
if (preg_match('/^\[(\d+)\-(\d+)\]#x2F;', $whiteParts[$i], $m)) {
1035
- $sql .= $wpdb->prepare("$column >> $j & 0xFF BETWEEN %d AND %d", $m[1], $m[2]);
1036
} else {
1037
- $sql .= $wpdb->prepare("$column >> $j & 0xFF = %d", $whiteParts[$i]);
1038
}
1039
$sql .= ' AND ';
1040
}
1041
$sql = substr($sql, 0, -5) . ')';
1042
return $sql;
1043
}
1044
- return $wpdb->prepare("($column = %s)", is_numeric($ip_string) ? $ip_string : wfUtils::inet_aton($ip_string));
1045
}
1046
1047
/**
1048
* @return string|null
1049
*/
26
$this->perfTable = $wpdb->base_prefix . 'wfPerfLog';
27
}
28
public function logPerf($IP, $UA, $URL, $data){
29
+ $IP = wfUtils::inet_pton($IP);
30
$this->getDB()->queryWrite("insert into " . $this->perfTable . " (IP, userID, UA, URL, ctime, fetchStart, domainLookupStart, domainLookupEnd, connectStart, connectEnd, requestStart, responseStart, responseEnd, domReady, loaded) values (%s, %d, '%s', '%s', unix_timestamp(), %d, %d, %d, %d, %d, %d, %d, %d, %d, %d)",
31
$IP,
32
$this->getCurrentUserID(),
67
$action,
68
$username,
69
$userID,
70
+ wfUtils::inet_pton(wfUtils::getIP()),
71
(isset($_SERVER['HTTP_USER_AGENT']) ? $_SERVER['HTTP_USER_AGENT'] : '')
72
);
73
}
79
if(wfConfig::get('firewallEnabled')){
80
//Moved the following block into the "is fw enabled section" for optimization.
81
$IP = wfUtils::getIP();
82
+ $IPnum = wfUtils::inet_pton($IP);
83
if($this->isWhitelisted($IP)){
84
return;
85
}
86
+ if (wfConfig::get('neverBlockBG') == 'neverBlockUA' && wfCrawl::isGoogleCrawler()) {
87
+ return;
88
+ }
89
+ if (wfConfig::get('neverBlockBG') == 'neverBlockVerified' && wfCrawl::isVerifiedGoogleCrawler()) {
90
+ return;
91
+ }
92
+
93
if($type == '404'){
94
$table = $this->scanTable;
95
} else if($type == 'hit'){
98
wordfence::status(1, 'error', "Invalid type to logLeechAndBlock(): $type");
99
return;
100
}
101
+ $this->getDB()->queryWrite("insert into $table (eMin, IP, hits) values (floor(unix_timestamp() / 60), %s, 1) ON DUPLICATE KEY update hits = IF(@wfcurrenthits := hits + 1, hits + 1, hits + 1)", wfUtils::inet_pton($IP));
102
$hitsPerMinute = $this->getDB()->querySingle("select @wfcurrenthits");
103
//end block moved into "is fw enabled" section
104
133
if($pat){
134
$URL = wfUtils::getRequestedURL();
135
if(preg_match($pat, $URL)){
136
+ $this->getDB()->queryWrite("insert IGNORE into $p"."wfVulnScanners (IP, ctime, hits) values (%s, unix_timestamp(), 1) ON DUPLICATE KEY UPDATE ctime = unix_timestamp(), hits = hits + 1", wfUtils::inet_pton($IP));
137
if(wfConfig::get('maxScanHits') != 'DISABLED'){
138
if( empty($_SERVER['HTTP_REFERER'] )){
139
$this->getDB()->queryWrite("insert into " . $this->badLeechersTable . " (eMin, IP, hits) values (floor(unix_timestamp() / 60), %s, 1) ON DUPLICATE KEY update hits = IF(@wfblcurrenthits := hits + 1, hits + 1, hits + 1)", $IPnum);
166
}
167
}
168
}
169
+
170
+ /**
171
+ * @param string $IP Should be in dot or colon notation (127.0.0.1 or ::1)
172
+ * @return bool
173
+ */
174
+ public function isWhitelisted($IP) {
175
+ $wfIPBlock = new wfUserIPRange('69.46.36.[1-32]');
176
+ if ($wfIPBlock->isIPInRange($IP)) { //IP is in Wordfence's IP block which would prevent our scanning server manually kicking off scans that are stuck
177
return true;
178
}
179
//We now whitelist all private addrs
180
+ if (wfUtils::isPrivateAddress($IP)) {
181
return true;
182
}
183
//These belong to sucuri's scanning servers which will get blocked by Wordfence as a false positive if you try a scan. So we whitelisted them.
184
+ $externalWhite = array('97.74.127.171', '69.164.203.172', '173.230.128.135', '66.228.34.49', '66.228.40.185', '50.116.36.92', '50.116.36.93', '50.116.3.171', '198.58.96.212', '50.116.63.221', '192.155.92.112', '192.81.128.31', '198.58.106.244', '192.155.95.139', '23.239.9.227', '198.58.112.103', '192.155.94.43', '162.216.16.33', '173.255.233.124', '173.255.233.124', '192.155.90.179', '50.116.41.217', '192.81.129.227', '198.58.111.80');
185
+ if (in_array($IP, $externalWhite)) {
186
return true;
187
}
188
$list = wfConfig::get('whitelisted');
189
+ if (!$list) {
190
+ return false;
191
+ }
192
$list = explode(',', $list);
193
+ if (sizeof($list) < 1) {
194
+ return false;
195
+ }
196
+ foreach ($list as $whiteIP) {
197
+ $white_ip_block = new wfUserIPRange($whiteIP);
198
+ if ($white_ip_block->isIPInRange($IP)) {
199
return true;
200
}
201
}
222
}
223
224
// These belong to sucuri's scanning servers which will get blocked by Wordfence as a false positive if you try a scan. So we whitelisted them.
225
+ $white_listed_ips = array_merge($white_listed_ips, array_map(array('wfUtils', 'inet_pton'), array('97.74.127.171', '69.164.203.172', '173.230.128.135', '66.228.34.49', '66.228.40.185', '50.116.36.92', '50.116.36.93', '50.116.3.171', '198.58.96.212', '50.116.63.221', '192.155.92.112', '192.81.128.31', '198.58.106.244', '192.155.95.139', '23.239.9.227', '198.58.112.103', '192.155.94.43', '162.216.16.33', '173.255.233.124', '173.255.233.124', '192.155.90.179', '50.116.41.217', '192.81.129.227', '198.58.111.80')));
226
227
if ($user_whitelisted === null) {
228
$user_whitelisted = wfConfig::get('whitelisted');
246
$this->getDB()->queryWrite("delete from " . $this->lockOutTable);
247
}
248
public function unblockIP($IP){
249
+ $this->getDB()->queryWrite("delete from " . $this->blocksTable . " where IP=%s", wfUtils::inet_pton($IP));
250
wfCache::updateBlockedIPs('add');
251
}
252
public function unblockRange($id){
253
$this->getDB()->queryWrite("delete from " . $this->ipRangesTable . " where id=%d", $id);
254
wfCache::updateBlockedIPs('add');
255
}
256
+
257
+ /**
258
+ *
259
+ * @param string $blockType
260
+ * @param string $range
261
+ * @param string $reason
262
+ * @return bool
263
+ */
264
public function blockRange($blockType, $range, $reason){
265
$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);
266
wfCache::updateBlockedIPs('add');
293
$numBlockElements = 0;
294
if($blockDat[0]){
295
$numBlockElements++;
296
+ list($start_range, $end_range) = explode('-', $blockDat[0]);
297
+ if (!preg_match('/[\.:]/', $start_range)) {
298
+ $start_range = long2ip($start_range);
299
+ $end_range = long2ip($end_range);
300
+ }
301
+ $elem['ipPattern'] = "Block visitors with IP addresses in the range: " . $start_range . ' - ' . $end_range;
302
} else {
303
$elem['ipPattern'] = 'Allow all IP addresses';
304
}
329
if($permanent){
330
//Insert permanent=1 or update existing perm or non-per block to be permanent
331
$this->getDB()->queryWrite("insert into " . $this->blocksTable . " (IP, blockedTime, reason, wfsn, permanent) values (%s, %d, '%s', %d, %d) ON DUPLICATE KEY update blockedTime=%d, reason='%s', wfsn=%d, permanent=%d",
332
+ wfUtils::inet_pton($IP),
333
$timeBlockOccurred,
334
$reason,
335
$wfsn,
342
} else {
343
//insert perm=0 but don't update and make perm blocks non-perm.
344
$this->getDB()->queryWrite("insert into " . $this->blocksTable . " (IP, blockedTime, reason, wfsn, permanent) values (%s, %d, '%s', %d, %d) ON DUPLICATE KEY update blockedTime=%d, reason='%s', wfsn=%d",
345
+ wfUtils::inet_pton($IP),
346
$timeBlockOccurred,
347
$reason,
348
$wfsn,
362
public function lockOutIP($IP, $reason){
363
if($this->isWhitelisted($IP)){ return false; }
364
$this->getDB()->queryWrite("insert into " . $this->lockOutTable . " (IP, blockedTime, reason) values (%s, unix_timestamp(), '%s') ON DUPLICATE KEY update blockedTime=unix_timestamp(), reason='%s'",
365
+ wfUtils::inet_pton($IP),
366
$reason,
367
$reason
368
);
373
return true;
374
}
375
public function unlockOutIP($IP){
376
+ $this->getDB()->queryWrite("delete from " . $this->lockOutTable . " where IP=%s", wfUtils::inet_pton($IP));
377
}
378
public function isIPLockedOut($IP){
379
+ 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)){
380
+ $this->getDB()->queryWrite("update " . $this->lockOutTable . " set blockedHits = blockedHits + 1, lastAttempt = unix_timestamp() where IP=%s", wfUtils::inet_pton($IP));
381
return true;
382
} else {
383
return false;
391
}
392
$this->resolveIPs($results);
393
foreach($results as &$elem){
394
+ $elem['IP'] = wfUtils::inet_ntop($elem['IP']);
395
}
396
return $results;
397
}
404
}
405
$this->resolveIPs($results);
406
foreach($results as &$elem){
407
+ $elem['IP'] = wfUtils::inet_ntop($elem['IP']);
408
}
409
return $results;
410
}
411
public function getBlockedIPsAddrOnly(){
412
+ $results = $this->getDB()->querySelect("select IP from " . $this->blocksTable . " where (permanent=1 OR (blockedTime + %s > unix_timestamp()))", wfConfig::get('blockedTime'), wfConfig::get('blockedTime'));
413
$ret = array();
414
foreach($results as $elem){
415
+ $ret[] = wfUtils::inet_ntop($elem['IP']);
416
}
417
return $ret;
418
}
444
$this->resolveIPs($results);
445
foreach($results as &$elem){
446
$elem['blocked'] = 1;
447
+ $elem['IP'] = wfUtils::inet_ntop($elem['IP']);
448
}
449
return $results;
450
}
463
$elem['timeAgo'] = wfUtils::makeTimeAgo($this->getDB()->querySingle("select unix_timestamp() - (eMin * 60) from $table where IP=%s", $elem['IP']));
464
$elem['blocked'] = $this->getDB()->querySingle("select blockedTime from " . $this->blocksTable . " where IP=%s and ((blockedTime + %s > unix_timestamp()) OR permanent = 1)", $elem['IP'], wfConfig::get('blockedTime'));
465
//take action
466
+ $elem['IP'] = wfUtils::inet_ntop($elem['IP']);
467
}
468
return $results;
469
}
479
sprintf('%.6f', microtime(true)),
480
(is_404() ? 1 : 0),
481
(wfCrawl::isGoogleCrawler() ? 1 : 0),
482
+ wfUtils::inet_pton(wfUtils::getIP()),
483
$this->getCurrentUserID(),
484
(wordfence::$newVisit ? 1 : 0),
485
wfUtils::getRequestedURL(),
495
$browscap = new wfBrowscap();
496
foreach($results as &$res){
497
$res['timeAgo'] = wfUtils::makeTimeAgo($serverTime - $res['ctime']);
498
+ $res['IP'] = wfUtils::inet_ntop($res['IP']);
499
$res['browser'] = false;
500
if($res['UA']){
501
$b = $browscap->getBrowser($res['UA']);
529
$serverTime = $this->getDB()->querySingle("select unix_timestamp()");
530
$IPSQL = "";
531
if($IP){
532
+ $IPSQL = " and IP=%s ";
533
+ $sqlArgs = array($afterTime, wfUtils::inet_pton($IP), $limit);
534
} else {
535
$sqlArgs = array($afterTime, $limit);
536
}
572
$res['type'] = $type;
573
$res['timeAgo'] = wfUtils::makeTimeAgo($serverTime - $res['ctime']);
574
$res['blocked'] = $this->getDB()->querySingle("select blockedTime from " . $this->blocksTable . " where IP=%s and (permanent = 1 OR (blockedTime + %s > unix_timestamp()))", $res['IP'], wfConfig::get('blockedTime'));
575
+ $res['IP'] = wfUtils::inet_ntop($res['IP']);
576
$res['extReferer'] = false;
577
if(isset( $res['referer'] ) && $res['referer']){
578
if(wfUtils::hasXSS($res['referer'] )){ //filtering out XSS
655
$IPLocs = wfUtils::getIPsGeo($IPs); //Creates an array with IP as key and data as value
656
657
foreach($results as &$res){
658
+ $ip_printable = wfUtils::inet_ntop($res['IP']);
659
+ if(isset($IPLocs[$ip_printable])){
660
+ $res['loc'] = $IPLocs[$ip_printable];
661
} else {
662
$res['loc'] = false;
663
}
710
if($this->isWhitelisted($IP)){
711
return;
712
}
713
+ $IPnum = wfUtils::inet_pton($IP);
714
715
//New range and UA pattern blocking:
716
$r1 = $this->getDB()->querySelect("select id, blockType, blockString from " . $this->ipRangesTable);
725
$uaPattern = $bDat[1];
726
$refPattern = isset($bDat[2]) ? $bDat[2] : '';
727
if($ipRange){
728
+ list($start_range, $end_range) = explode('-', $ipRange);
729
+ if (preg_match('/[\.:]/', $start_range)) {
730
+ $start_range = wfUtils::inet_pton($start_range);
731
+ $end_range = wfUtils::inet_pton($end_range);
732
+ } else {
733
+ $start_range = wfUtils::inet_pton(long2ip($start_range));
734
+ $end_range = wfUtils::inet_pton(long2ip($end_range));
735
+ }
736
+
737
+ if (strcmp($IPnum, $start_range) >= 0 && strcmp($IPnum, $end_range) <= 0) {
738
$ipRangeBlocked = true;
739
}
740
}
894
wordfence::status(2, 'info', "Blocking IP $IP. $reason");
895
} else if($action == 'throttle'){
896
$IP = wfUtils::getIP();
897
+ $this->getDB()->queryWrite("insert into " . $this->throttleTable . " (IP, startTime, endTime, timesThrottled, lastReason) values (%s, unix_timestamp(), unix_timestamp(), 1, '%s') ON DUPLICATE KEY UPDATE endTime=unix_timestamp(), timesThrottled = timesThrottled + 1, lastReason='%s'", wfUtils::inet_pton($IP), $reason, $reason);
898
wordfence::status(2, 'info', "Throttling IP $IP. $reason");
899
wfConfig::inc('totalIPsThrottled');
900
$secsToGo = 60;
929
} else if($nb == 'neverBlockUA' || $nb == 'neverBlockVerified'){
930
if(wfCrawl::isGoogleCrawler()){ //Check the UA using regex
931
if($nb == 'neverBlockVerified'){
932
+ if(wfCrawl::verifyCrawlerPTR($this->googlePattern, wfUtils::getIP())){ //UA check passed, now verify using PTR if configured to
933
+ self::$gbSafeCache[$cacheKey] = false; //This is a verified Google crawler, so no we can't block it
934
+ } else {
935
+ self::$gbSafeCache[$cacheKey] = true; //This is a crawler claiming to be Google but it did not verify
936
}
937
} else { //neverBlockUA
938
self::$gbSafeCache[$cacheKey] = false; //User configured us to only do a UA check and this claims to be google so don't block
939
}
983
return array_reverse($results);
984
}
985
986
+ /**
987
+ * @return string
988
+ */
989
+ public function getGooglePattern() {
990
+ return $this->googlePattern;
991
+ }
992
+
993
}
994
995
/**
996
*
997
*/
998
class wfUserIPRange {
999
1012
/**
1013
* Check if the supplied IP address is within the user supplied range.
1014
*
1015
+ * @param string $ip
1016
* @return bool
1017
*/
1018
public function isIPInRange($ip) {
1019
$ip_string = $this->getIPString();
1020
+
1021
+ // IPv4 range
1022
+ if (strpos($ip_string, '.') !== false && strpos($ip, '.') !== false) {
1023
+ if (preg_match('/\[\d+\-\d+\]/', $ip_string)) {
1024
+ $IPparts = explode('.', $ip);
1025
+ $whiteParts = explode('.', $ip_string);
1026
+ $mismatch = false;
1027
+ for ($i = 0; $i <= 3; $i++) {
1028
+ if (preg_match('/^\[(\d+)\-(\d+)\]#x2F;', $whiteParts[$i], $m)) {
1029
+ if ($IPparts[$i] < $m[1] || $IPparts[$i] > $m[2]) {
1030
+ $mismatch = true;
1031
+ }
1032
+ } else if ($whiteParts[$i] != $IPparts[$i]) {
1033
$mismatch = true;
1034
}
1035
}
1036
+ if ($mismatch === false) {
1037
+ return true; // Is whitelisted because we did not get a mismatch
1038
+ }
1039
+ } else if ($ip_string == $ip) {
1040
+ return true;
1041
}
1042
+
1043
+ // IPv6 range
1044
+ } else if (strpos($ip_string, ':') !== false && strpos($ip, ':') !== false) {
1045
+ if (preg_match('/\[[a-f0-9]+\-[a-f0-9]+\]/', $ip_string)) {
1046
+ $IPparts = explode(':', strtolower(wfUtils::expandIPv6Address($ip)));
1047
+ $whiteParts = explode(':', strtolower(self::expandIPv6Range($ip_string)));
1048
+ $mismatch = false;
1049
+ for ($i = 0; $i <= 7; $i++) {
1050
+ if (preg_match('/^\[([a-f0-9]+)\-([a-f0-9]+)\]#x2F;i', $whiteParts[$i], $m)) {
1051
+ $ip_group = hexdec($IPparts[$i]);
1052
+ $range_group_from = hexdec($m[1]);
1053
+ $range_group_to = hexdec($m[2]);
1054
+ if ($ip_group < $range_group_from || $ip_group > $range_group_to) {
1055
+ $mismatch = true;
1056
+ break;
1057
+ }
1058
+ } else if ($whiteParts[$i] != $IPparts[$i]) {
1059
+ $mismatch = true;
1060
+ break;
1061
+ }
1062
+ }
1063
+ if ($mismatch === false) {
1064
+ return true; // Is whitelisted because we did not get a mismatch
1065
+ }
1066
+ } else if ($ip_string == $ip) {
1067
+ return true;
1068
}
1069
}
1070
+
1071
return false;
1072
}
1073
1081
/** @var wpdb $wpdb */
1082
global $wpdb;
1083
$ip_string = $this->getIPString();
1084
+
1085
+ if (strpos($ip_string, '.') !== false && preg_match('/\[\d+\-\d+\]/', $ip_string)) {
1086
$whiteParts = explode('.', $ip_string);
1087
+ $sql = "(SUBSTR($column, 1, 12) = LPAD(CHAR(0xff, 0xff), 12, CHAR(0)) AND ";
1088
+
1089
for ($i = 0, $j = 24; $i <= 3; $i++, $j -= 8) {
1090
+ // MySQL can only perform bitwise operations on integers
1091
+ $conv = sprintf('CAST(CONV(HEX(SUBSTR(%s, 13, 8)), 16, 10) as UNSIGNED INTEGER)', $column);
1092
if (preg_match('/^\[(\d+)\-(\d+)\]#x2F;', $whiteParts[$i], $m)) {
1093
+ $sql .= $wpdb->prepare("$conv >> $j & 0xFF BETWEEN %d AND %d", $m[1], $m[2]);
1094
} else {
1095
+ $sql .= $wpdb->prepare("$conv >> $j & 0xFF = %d", $whiteParts[$i]);
1096
}
1097
$sql .= ' AND ';
1098
}
1099
$sql = substr($sql, 0, -5) . ')';
1100
return $sql;
1101
+
1102
+ } else if (strpos($ip_string, ':') !== false && preg_match('/\[[a-f0-9]+\-[a-f0-9]+\]/', $ip_string)) {
1103
+ $whiteParts = explode(':', strtolower(self::expandIPv6Range($ip_string)));
1104
+ $sql = '(';
1105
+
1106
+ for ($i = 0; $i <= 7; $i++) {
1107
+ // MySQL can only perform bitwise operations on integers
1108
+ $conv = sprintf('CAST(CONV(HEX(SUBSTR(%s, %d, 8)), 16, 10) as UNSIGNED INTEGER)', $column, $i < 4 ? 1 : 9);
1109
+ $j = 16 * (3 - ($i % 4));
1110
+ if (preg_match('/^\[([a-f0-9]+)\-([a-f0-9]+)\]#x2F;', $whiteParts[$i], $m)) {
1111
+ $sql .= $wpdb->prepare("$conv >> $j & 0xFFFF BETWEEN 0x%x AND 0x%x", hexdec($m[1]), hexdec($m[2]));
1112
+ } else {
1113
+ $sql .= $wpdb->prepare("$conv >> $j & 0xFFFF = 0x%x", hexdec($whiteParts[$i]));
1114
+ }
1115
+ $sql .= ' AND ';
1116
+ }
1117
+ $sql = substr($sql, 0, -5) . ')';
1118
+ return $sql;
1119
+ }
1120
+ return $wpdb->prepare("($column = %s)", wfUtils::inet_pton($ip_string));
1121
+ }
1122
+
1123
+ /**
1124
+ * Expand a compressed printable range representation of an IPv6 address.
1125
+ *
1126
+ * @todo Hook up exceptions for better error handling.
1127
+ * @todo Allow IPv4 mapped IPv6 addresses (::ffff:192.168.1.1).
1128
+ * @param string $ip_range
1129
+ * @return string
1130
+ */
1131
+ public static function expandIPv6Range($ip_range) {
1132
+ $colon_count = substr_count($ip_range, ':');
1133
+ $dbl_colon_count = substr_count($ip_range, '::');
1134
+ if ($dbl_colon_count > 1) {
1135
+ return false;
1136
+ }
1137
+ $dbl_colon_pos = strpos($ip_range, '::');
1138
+ if ($dbl_colon_pos !== false) {
1139
+ $ip_range = str_replace('::', str_repeat(':0000',
1140
+ (($dbl_colon_pos === 0 || $dbl_colon_pos === strlen($ip_range) - 2) ? 9 : 8) - $colon_count) . ':', $ip_range);
1141
+ $ip_range = trim($ip_range, ':');
1142
+ }
1143
+ $colon_count = substr_count($ip_range, ':');
1144
+ if ($colon_count != 7) {
1145
+ return false;
1146
+ }
1147
+
1148
+ $groups = explode(':', $ip_range);
1149
+ $expanded = '';
1150
+ foreach ($groups as $group) {
1151
+ if (preg_match('/\[([a-f0-9]{1,4})\-([a-f0-9]{1,4})\]/i', $group, $matches)) {
1152
+ $expanded .= sprintf('[%s-%s]', str_pad(strtolower($matches[1]), 4, '0', STR_PAD_LEFT), str_pad(strtolower($matches[2]), 4, '0', STR_PAD_LEFT)) . ':';
1153
+ } else if (preg_match('/[a-f0-9]{1,4}/i', $group)) {
1154
+ $expanded .= str_pad(strtolower($group), 4, '0', STR_PAD_LEFT) . ':';
1155
+ } else {
1156
+ return false;
1157
+ }
1158
+ }
1159
+ return trim($expanded, ':');
1160
+ }
1161
+
1162
+ /**
1163
+ * @return bool
1164
+ */
1165
+ public function isValidRange() {
1166
+ return $this->isValidIPv4Range() || $this->isValidIPv6Range();
1167
+ }
1168
+
1169
+ /**
1170
+ * @return bool
1171
+ */
1172
+ public function isValidIPv4Range() {
1173
+ $ip_string = $this->getIPString();
1174
+ preg_match('(\d)', $ip_string, $matches);
1175
+ foreach ($matches as $match) {
1176
+ if ($match[1] > 255 || $match[1] < 0) {
1177
+ return false;
1178
+ }
1179
}
1180
+ $group_regex = '([0-9]{1,3}|\[[0-9]{1,3}\-[0-9]{1,3}\])';
1181
+ return preg_match('/^' . str_repeat("$group_regex.", 3) . $group_regex . '#x2F;i', $ip_string) > 0;
1182
}
1183
1184
+ /**
1185
+ * @return bool
1186
+ */
1187
+ public function isValidIPv6Range() {
1188
+ $ip_string = $this->getIPString();
1189
+ if (strpos($ip_string, '::') !== false) {
1190
+ $ip_string = self::expandIPv6Range($ip_string);
1191
+ }
1192
+ if (!$ip_string) {
1193
+ return false;
1194
+ }
1195
+ $group_regex = '([a-f0-9]{1,4}|\[[a-f0-9]{1,4}\-[a-f0-9]{1,4}\])';
1196
+ return preg_match('/^' . str_repeat("$group_regex:", 7) . $group_regex . '#x2F;i', $ip_string) > 0;
1197
+ }
1198
+
1199
+
1200
+
1201
/**
1202
* @return string|null
1203
*/
lib/wfScanEngine.php CHANGED
@@ -21,6 +21,9 @@ class wfScanEngine {
21
public $maxExecTime = false; //If more than $maxExecTime has elapsed since last check, fork a new scan process and continue
22
private $publicScanEnabled = false;
23
private $fileContentsResults = false;
24
private $scanner = false;
25
private $scanQueue = array();
26
private $hoover = false;
@@ -33,6 +36,17 @@ class wfScanEngine {
33
);
34
private $userPasswdQueue = "";
35
private $passwdHasIssues = false;
36
public function __sleep(){ //Same order here as above for properties that are included in serialization
37
return array('hasher', 'jobList', 'i', 'wp_version', 'apiKey', 'startTime', 'maxExecTime', 'publicScanEnabled', 'fileContentsResults', 'scanner', 'scanQueue', 'hoover', 'scanData', 'statusIDX', 'userPasswdQueue', 'passwdHasIssues');
38
}
@@ -53,7 +67,7 @@ class wfScanEngine {
53
$this->jobList[] = 'knownFiles_init';
54
$this->jobList[] = 'knownFiles_main';
55
$this->jobList[] = 'knownFiles_finish';
56
- foreach(array('knownFiles', 'fileContents', 'posts', 'comments', 'passwds', 'options', 'dns', 'diskSpace', 'oldVersions') as $scanType){
57
if(wfConfig::get('scansEnabled_' . $scanType)){
58
if(method_exists($this, 'scan_' . $scanType . '_init')){
59
foreach(array('init', 'main', 'finish') as $op){ $this->jobList[] = $scanType . '_' . $op; };
@@ -331,9 +345,40 @@ class wfScanEngine {
331
wordfence::statusEnd($this->statusIDX['infect'], $haveIssues);
332
wordfence::statusEnd($this->statusIDX['GSB'], $haveIssuesGSB);
333
}
334
private function scan_posts_init(){
335
$this->statusIDX['posts'] = wordfence::statusStart('Scanning posts for URL\'s in Google\'s Safe Browsing List');
336
- $blogsToScan = $this->getBlogsToScan('posts');
337
$wfdb = new wfDB();
338
$this->hoover = new wordfenceURLHoover($this->apiKey, $this->wp_version);
339
foreach($blogsToScan as $blog){
@@ -443,7 +488,7 @@ class wfScanEngine {
443
$this->scanData = array();
444
$this->scanQueue = array();
445
$this->hoover = new wordfenceURLHoover($this->apiKey, $this->wp_version);
446
- $blogsToScan = $this->getBlogsToScan('comments');
447
$wfdb = new wfDB();
448
foreach($blogsToScan as $blog){
449
$q1 = $wfdb->querySelect("select comment_ID from " . $blog['table'] . " where comment_approved=1");
@@ -565,7 +610,7 @@ class wfScanEngine {
565
$this->status(2, 'info', "Scanned comment with $cDesc");
566
return false;
567
}
568
- public function getBlogsToScan($table){
569
$wfdb = new wfDB();
570
global $wpdb;
571
$prefix = $wpdb->base_prefix;
@@ -739,7 +784,7 @@ class wfScanEngine {
739
}
740
}
741
private function scan_options(){
742
- $blogsToScan = $this->getBlogsToScan('options');
743
$wfdb = new wfDB();
744
foreach($blogsToScan as $blog){
745
$charset = $wfdb->querySingle("select option_value from " . $blog['table'] . " where option_name='blog_charset'");
21
public $maxExecTime = false; //If more than $maxExecTime has elapsed since last check, fork a new scan process and continue
22
private $publicScanEnabled = false;
23
private $fileContentsResults = false;
24
+ /**
25
+ * @var bool|wordfenceScanner
26
+ */
27
private $scanner = false;
28
private $scanQueue = array();
29
private $hoover = false;
36
);
37
private $userPasswdQueue = "";
38
private $passwdHasIssues = false;
39
+
40
+ /**
41
+ * @var array
42
+ */
43
+ private $databaseResults;
44
+
45
+ /**
46
+ * @var wordfenceDBScanner
47
+ */
48
+ private $dbScanner;
49
+
50
public function __sleep(){ //Same order here as above for properties that are included in serialization
51
return array('hasher', 'jobList', 'i', 'wp_version', 'apiKey', 'startTime', 'maxExecTime', 'publicScanEnabled', 'fileContentsResults', 'scanner', 'scanQueue', 'hoover', 'scanData', 'statusIDX', 'userPasswdQueue', 'passwdHasIssues');
52
}
67
$this->jobList[] = 'knownFiles_init';
68
$this->jobList[] = 'knownFiles_main';
69
$this->jobList[] = 'knownFiles_finish';
70
+ foreach(array('knownFiles', 'fileContents', 'database', 'posts', 'comments', 'passwds', 'options', 'dns', 'diskSpace', 'oldVersions') as $scanType){
71
if(wfConfig::get('scansEnabled_' . $scanType)){
72
if(method_exists($this, 'scan_' . $scanType . '_init')){
73
foreach(array('init', 'main', 'finish') as $op){ $this->jobList[] = $scanType . '_' . $op; };
345
wordfence::statusEnd($this->statusIDX['infect'], $haveIssues);
346
wordfence::statusEnd($this->statusIDX['GSB'], $haveIssuesGSB);
347
}
348
+
349
+ private function scan_database_init() {
350
+ $this->statusIDX['db_infect'] = wordfence::statusStart('Scanning database for infections and vulnerabilities');
351
+ $this->dbScanner = new wordfenceDBScanner($this->apiKey, $this->wp_version, ABSPATH);
352
+ $this->status(2, 'info', "Starting scan of database");
353
+ }
354
+
355
+ private function scan_database_main() {
356
+ if (!$this->dbScanner) {
357
+ $this->dbScanner = new wordfenceDBScanner($this->apiKey, $this->wp_version, ABSPATH);
358
+ }
359
+ $this->databaseResults = $this->dbScanner->scan($this);
360
+ }
361
+
362
+ private function scan_database_finish() {
363
+ $this->status(2, 'info', "Done database scan");
364
+ if ($this->dbScanner->errorMsg) {
365
+ throw new Exception($this->dbScanner->errorMsg);
366
+ }
367
+ $this->dbScanner = null;
368
+ $haveIssues = false;
369
+ foreach ($this->databaseResults as $issue) {
370
+ $this->status(2, 'info', "Adding issue: " . $issue['shortMsg']);
371
+ $issue_success = $this->addIssue($issue['type'], $issue['severity'], $issue['ignoreP'], $issue['ignoreC'], $issue['shortMsg'], $issue['longMsg'], $issue['data']);
372
+ if ($issue_success) {
373
+ $haveIssues = true;
374
+ }
375
+ }
376
+ $this->databaseResults = null;
377
+ wordfence::statusEnd($this->statusIDX['db_infect'], $haveIssues);
378
+ }
379
private function scan_posts_init(){
380
$this->statusIDX['posts'] = wordfence::statusStart('Scanning posts for URL\'s in Google\'s Safe Browsing List');
381
+ $blogsToScan = self::getBlogsToScan('posts');
382
$wfdb = new wfDB();
383
$this->hoover = new wordfenceURLHoover($this->apiKey, $this->wp_version);
384
foreach($blogsToScan as $blog){
488
$this->scanData = array();
489
$this->scanQueue = array();
490
$this->hoover = new wordfenceURLHoover($this->apiKey, $this->wp_version);
491
+ $blogsToScan = self::getBlogsToScan('comments');
492
$wfdb = new wfDB();
493
foreach($blogsToScan as $blog){
494
$q1 = $wfdb->querySelect("select comment_ID from " . $blog['table'] . " where comment_approved=1");
610
$this->status(2, 'info', "Scanned comment with $cDesc");
611
return false;
612
}
613
+ public static function getBlogsToScan($table){
614
$wfdb = new wfDB();
615
global $wpdb;
616
$prefix = $wpdb->base_prefix;
784
}
785
}
786
private function scan_options(){
787
+ $blogsToScan = self::getBlogsToScan('options');
788
$wfdb = new wfDB();
789
foreach($blogsToScan as $blog){
790
$charset = $wfdb->querySingle("select option_value from " . $blog['table'] . " where option_name='blog_charset'");
lib/wfUtils.php CHANGED
@@ -65,27 +65,68 @@ class wfUtils {
65
return "$m1 $t1";
66
}
67
}
68
- public static function formatBytes($bytes, $precision = 2) {
69
- $units = array('B', 'KB', 'MB', 'GB', 'TB');
70
71
- $bytes = max($bytes, 0);
72
- $pow = floor(($bytes ? log($bytes) : 0) / log(1024));
73
- $pow = min($pow, count($units) - 1);
74
75
// Uncomment one of the following alternatives
76
$bytes /= pow(1024, $pow);
77
// $bytes /= (1 << (10 * $pow));
78
79
- return round($bytes, $precision) . ' ' . $units[$pow];
80
- }
81
- public static function inet_ntoa($ip){
82
$long = 4294967295 - ($ip - 1);
83
return long2ip(-$long);
84
}
85
- public static function inet_aton($ip){
86
$ip = preg_replace('/(?<=^|\.)0+([1-9])/', '$1', $ip);
87
return sprintf("%u", ip2long($ip));
88
}
89
public static function hasLoginCookie(){
90
if(isset($_COOKIE)){
91
if(is_array($_COOKIE)){
@@ -117,25 +158,45 @@ class wfUtils {
117
public static function makeRandomIP(){
118
return rand(11,230) . '.' . rand(0,255) . '.' . rand(0,255) . '.' . rand(0,255);
119
}
120
- public static function isPrivateAddress($addr){
121
- $num = self::inet_aton($addr);
122
- foreach(self::$privateAddrs as $a){
123
- if($num >= $a[1] && $num <= $a[2]){
124
- return true;
125
}
126
}
127
- return false;
128
}
129
- private static function getCleanIP($arr){ //Expects an array of items. The items are either IP's or IP's separated by comma, space or tab. Or an array of IP's.
130
- // We then examine all IP's looking for a public IP and storing private IP's in an array. If we find no public IPs we return the first private addr we found.
131
- $privates = array(); //Store private addrs until end as last resort.
132
- for($i = 0; $i < count($arr); $i++){
133
$item = $arr[$i];
134
- if(is_array($item)){
135
foreach($item as $j){
136
- $j = preg_replace('/:\d+#x2F;', '', $j); //Strip off port
137
- if(self::isValidIP($j)){
138
- if(self::isPrivateAddress($j)){
139
$privates[] = $j;
140
} else {
141
return $j;
@@ -146,10 +207,12 @@ class wfUtils {
146
}
147
$skipToNext = false;
148
foreach(array(',', ' ', "\t") as $char){
149
- if(strpos($item, $char) !== false){
150
$sp = explode($char, $item);
151
foreach($sp as $j){
152
- $j = preg_replace('/:\d+#x2F;', '', $j); //Strip off port
153
if(self::isValidIP($j)){
154
if(self::isPrivateAddress($j)){
155
$privates[] = $j;
@@ -164,7 +227,9 @@ class wfUtils {
164
}
165
if($skipToNext){ continue; } //Skip to next item because this one had a comma, space or tab so was delimited and we didn't find anything.
166
167
- $item = preg_replace('/:\d+#x2F;', '', $item); //Strip off port
168
if(self::isValidIP($item)){
169
if(self::isPrivateAddress($item)){
170
$privates[] = $item;
@@ -198,25 +263,16 @@ class wfUtils {
198
$IP = self::getCleanIP(array($_SERVER[$howGet], $_SERVER['REMOTE_ADDR']));
199
}
200
} else {
201
- $IPs = array($_SERVER['REMOTE_ADDR']);
202
if(isset($_SERVER['HTTP_X_FORWARDED_FOR'])){ $IPs[] = $_SERVER['HTTP_X_FORWARDED_FOR']; }
203
if(isset($_SERVER['HTTP_X_REAL_IP'])){ $IPs[] = $_SERVER['HTTP_X_REAL_IP']; }
204
- $IP = self::getCleanIP($IPs);
205
}
206
return $IP; //Returns a valid IP or false.
207
}
208
public static function isValidIP($IP){
209
- if(preg_match('/^(\d+)\.(\d+)\.(\d+)\.(\d+)#x2F;', $IP, $m)){
210
- if(
211
- $m[1] >= 0 && $m[1] <= 255 &&
212
- $m[2] >= 0 && $m[2] <= 255 &&
213
- $m[3] >= 0 && $m[3] <= 255 &&
214
- $m[4] >= 0 && $m[4] <= 255
215
- ){
216
- return true;
217
- }
218
- }
219
- return false;
220
}
221
public static function getRequestedURL(){
222
if(isset($_SERVER['HTTP_HOST']) && $_SERVER['HTTP_HOST']){
@@ -262,14 +318,14 @@ class wfUtils {
262
return $db->querySingle("select AES_DECRYPT(UNHEX('%s'), '%s') as val", $str, $key);
263
}
264
public static function lcmem(){
265
- $trace=debug_backtrace();
266
- $caller=array_shift($trace);
267
$mem = memory_get_usage(true);
268
error_log("$mem at " . $caller['file'] . " line " . $caller['line']);
269
}
270
public static function logCaller(){
271
- $trace=debug_backtrace();
272
- $caller=array_shift($trace);
273
$c2 = array_shift($trace);
274
error_log("Caller for " . $caller['file'] . " line " . $caller['line'] . " is " . $c2['file'] . ' line ' . $c2['line']);
275
}
@@ -282,8 +338,8 @@ class wfUtils {
282
}
283
}
284
public static function isAdminPageMU(){
285
- if(preg_match('/^[\/a-zA-Z0-9\-\_\s\+\~\!\^\.]*\/wp-admin\/network\//', $_SERVER['REQUEST_URI'])){
286
- return true;
287
}
288
return false;
289
}
@@ -357,7 +413,7 @@ class wfUtils {
357
return self::$isWindows == 'yes' ? true : false;
358
}
359
public static function getScanLock(){
360
- //Windows does not support non-blocking flock, so we use time.
361
$scanRunning = wfConfig::get('wf_scanRunning');
362
if($scanRunning && time() - $scanRunning < WORDFENCE_MAX_SCAN_TIME){
363
return false;
@@ -377,7 +433,7 @@ class wfUtils {
377
}
378
}
379
public static function getIPGeo($IP){ //Works with int or dotted
380
-
381
$locs = self::getIPsGeo(array($IP));
382
if(isset($locs[$IP])){
383
return $locs[$IP];
@@ -387,53 +443,57 @@ class wfUtils {
387
}
388
public static function getIPsGeo($IPs){ //works with int or dotted. Outputs same format it receives.
389
$IPs = array_unique($IPs);
390
- $isInt = false;
391
- if(strpos($IPs[0], '.') === false){
392
- $isInt = true;
393
- }
394
$toResolve = array();
395
$db = new wfDB();
396
global $wpdb;
397
$locsTable = $wpdb->base_prefix . 'wfLocs';
398
$IPLocs = array();
399
foreach($IPs as $IP){
400
- $row = $db->querySingleRec("select IP, ctime, failed, city, region, countryName, countryCode, lat, lon, unix_timestamp() - ctime as age from " . $locsTable . " where IP=%s", ($isInt ? $IP : self::inet_aton($IP)) );
401
if($row){
402
if($row['age'] > WORDFENCE_MAX_IPLOC_AGE){
403
$db->queryWrite("delete from " . $locsTable . " where IP=%s", $row['IP']);
404
} else {
405
if($row['failed'] == 1){
406
- $IPLocs[$IP] = false;
407
} else {
408
- if(! $isInt){
409
- $row['IP'] = self::inet_ntoa($row['IP']);
410
- }
411
- $IPLocs[$IP] = $row;
412
}
413
}
414
}
415
- if(! isset($IPLocs[$IP])){
416
- $toResolve[] = $IP;
417
}
418
}
419
if(sizeof($toResolve) > 0){
420
- $api = new wfAPI(wfConfig::get('apiKey'), wfUtils::getWPVersion());
421
try {
422
$freshIPs = $api->call('resolve_ips', array(), array(
423
'ips' => implode(',', $toResolve)
424
));
425
if(is_array($freshIPs)){
426
foreach($freshIPs as $IP => $value){
427
if($value == 'failed'){
428
- $db->queryWrite("insert IGNORE into " . $locsTable . " (IP, ctime, failed) values (%s, unix_timestamp(), 1)", ($isInt ? $IP : self::inet_aton($IP)) );
429
$IPLocs[$IP] = false;
430
} else if(is_array($value)){
431
for($i = 0; $i <= 5; $i++){
432
//Prevent warnings in debug mode about uninitialized values
433
if(! isset($value[$i])){ $value[$i] = ''; }
434
}
435
- $db->queryWrite("insert IGNORE into " . $locsTable . " (IP, ctime, failed, city, region, countryName, countryCode, lat, lon) values (%s, unix_timestamp(), 0, '%s', '%s', '%s', '%s', %s, %s)",
436
- ($isInt ? $IP : self::inet_aton($IP)),
437
$value[3], //city
438
$value[2], //region
439
$value[1], //countryName
@@ -460,25 +520,39 @@ class wfUtils {
460
}
461
return $IPLocs;
462
}
463
- public static function reverseLookup($IP){
464
$db = new wfDB();
465
global $wpdb;
466
$reverseTable = $wpdb->base_prefix . 'wfReverseCache';
467
- $IPn = wfUtils::inet_aton($IP);
468
$host = $db->querySingle("select host from " . $reverseTable . " where IP=%s and unix_timestamp() - lastUpdate < %d", $IPn, WORDFENCE_REVERSE_LOOKUP_CACHE_TIME);
469
- if(! $host){
470
- $ptr = implode(".", array_reverse(explode(".",$IP))) . ".in-addr.arpa";
471
- if (function_exists('dns_get_record')) {
472
- $host = @dns_get_record($ptr, DNS_PTR);
473
}
474
- if($host == null){
475
$host = 'NONE';
476
- } else {
477
- $host = $host[0]['target'];
478
}
479
$db->queryWrite("insert into " . $reverseTable . " (IP, host, lastUpdate) values (%s, '%s', unix_timestamp()) ON DUPLICATE KEY UPDATE host='%s', lastUpdate=unix_timestamp()", $IPn, $host, $host);
480
}
481
- if($host == 'NONE'){
482
return '';
483
} else {
484
return $host;
@@ -502,7 +576,7 @@ class wfUtils {
502
$fh = @fopen($file, 'r');
503
wfUtils::errorsOn();
504
if(! $fh){ return false; }
505
- $offset = WORDFENCE_MAX_FILE_SIZE_TO_PROCESS + 1;
506
$tooBig = false;
507
try {
508
if(@fseek($fh, $offset, SEEK_SET) === 0){
@@ -517,7 +591,7 @@ class wfUtils {
517
public static function fileOver2Gigs($file){ //Surround calls to this func with try/catch because fseek may throw error.
518
$fh = @fopen($file, 'r');
519
if(! $fh){ return false; }
520
- $offset = 2147483647;
521
$tooBig = false;
522
//My throw an error so surround calls to this func with try/catch
523
if(@fseek($fh, $offset, SEEK_SET) === 0){
@@ -542,11 +616,15 @@ class wfUtils {
542
return $URL;
543
}
544
public static function IP2Country($IP){
545
- if(! (function_exists('geoip_open') && function_exists('geoip_country_code_by_addr'))){
546
require_once('wfGeoIP.php');
547
}
548
$gi = geoip_open(dirname(__FILE__) . "/GeoIP.dat",GEOIP_STANDARD);
549
- $country = geoip_country_code_by_addr($gi, $IP);
550
geoip_close($gi);
551
return $country ? $country : '';
552
}
@@ -594,7 +672,35 @@ class wfUtils {
594
public static function isRefererBlocked($refPattern){
595
return fnmatch($refPattern, $_SERVER['HTTP_REFERER'], FNM_CASEFOLD);
596
}
597
public static function rangeToCIDRs($startIP, $endIP){
598
$startIPBin = sprintf('%032b', $startIP);
599
$endIPBin = sprintf('%032b', $endIP);
600
$IPIncBin = $startIPBin;
@@ -611,6 +717,7 @@ class wfUtils {
611
}
612
return $CIDRs;
613
}
614
public static function setcookie($name, $value, $expire, $path, $domain, $secure, $httpOnly){
615
if(version_compare(PHP_VERSION, '5.2.0') >= 0){
616
@setcookie($name, $value, $expire, $path, $domain, $secure, $httpOnly);
@@ -661,6 +768,42 @@ class wfUtils {
661
public static function getPrivateAddrs() {
662
return self::$privateAddrs;
663
}
664
}
665
666
65
return "$m1 $t1";
66
}
67
}
68
+ public static function formatBytes($bytes, $precision = 2) {
69
+ $units = array('B', 'KB', 'MB', 'GB', 'TB');
70
71
+ $bytes = max($bytes, 0);
72
+ $pow = floor(($bytes ? log($bytes) : 0) / log(1024));
73
+ $pow = min($pow, count($units) - 1);
74
75
// Uncomment one of the following alternatives
76
$bytes /= pow(1024, $pow);
77
// $bytes /= (1 << (10 * $pow));
78
79
+ return round($bytes, $precision) . ' ' . $units[$pow];
80
+ }
81
+
82
+ /**
83
+ * Return dot or colon notation of IPv4 or IPv6 address.
84
+ *
85
+ * @param string $ip
86
+ * @return string|bool
87
+ */
88
+ public static function inet_ntop($ip) {
89
+ // trim this to the IPv4 equiv if it's in the mapped range
90
+ if (strlen($ip) == 16 && substr($ip, 0, 12) == pack("H*", '00000000000000000000ffff')) {
91
+ $ip = substr($ip, 12, 4);
92
+ }
93
+ return inet_ntop($ip);
94
+ }
95
+
96
+ /**
97
+ * Return dot notation of IPv4 address.
98
+ *
99
+ * @param int $ip
100
+ * @return string|bool
101
+ */
102
+ public static function inet_ntoa($ip) {
103
$long = 4294967295 - ($ip - 1);
104
return long2ip(-$long);
105
}
106
+
107
+ /**
108
+ * Return the packed binary string of an IPv4 or IPv6 address.
109
+ *
110
+ * @param string $ip
111
+ * @return string
112
+ */
113
+ public static function inet_pton($ip) {
114
+ // convert the 4 char IPv4 to IPv6 mapped version.
115
+ $pton = str_pad(inet_pton($ip), 16, pack("H*", '00000000000000000000ffff00000000'), STR_PAD_LEFT);
116
+ return $pton;
117
+ }
118
+
119
+ /**
120
+ * Return string representation of 32 bit int of the IP address.
121
+ *
122
+ * @param string $ip
123
+ * @return string
124
+ */
125
+ public static function inet_aton($ip) {
126
$ip = preg_replace('/(?<=^|\.)0+([1-9])/', '$1', $ip);
127
return sprintf("%u", ip2long($ip));
128
}
129
+
130
public static function hasLoginCookie(){
131
if(isset($_COOKIE)){
132
if(is_array($_COOKIE)){
158
public static function makeRandomIP(){
159
return rand(11,230) . '.' . rand(0,255) . '.' . rand(0,255) . '.' . rand(0,255);
160
}
161
+
162
+ /**
163
+ * @param string $addr Should be in dot or colon notation (127.0.0.1 or ::1)
164
+ * @return bool
165
+ */
166
+ public static function isPrivateAddress($addr) {
167
+ // Run this through the preset list for IPv4 addresses.
168
+ if (filter_var($addr, FILTER_VALIDATE_IP, FILTER_FLAG_IPV4) !== false) {
169
+ $num = self::inet_aton($addr);
170
+ foreach (self::$privateAddrs as $a) {
171
+ if ($num >= $a[1] && $num <= $a[2]) {
172
+ return true;
173
+ }
174
}
175
}
176
+
177
+ return filter_var($addr, FILTER_VALIDATE_IP, FILTER_FLAG_IPV4 | FILTER_FLAG_IPV6) !== false
178
+ && filter_var($addr, FILTER_VALIDATE_IP, FILTER_FLAG_IPV4 | FILTER_FLAG_IPV6 | FILTER_FLAG_NO_PRIV_RANGE | FILTER_FLAG_NO_RES_RANGE) === false;
179
}
180
+
181
+ /**
182
+ * Expects an array of items. The items are either IP's or IP's separated by comma, space or tab. Or an array of IP's.
183
+ * We then examine all IP's looking for a public IP and storing private IP's in an array. If we find no public IPs we return the first private addr we found.
184
+ *
185
+ * @param array $arr
186
+ * @return bool|mixed
187
+ */
188
+ private static function getCleanIP($arr){
189
+ $privates = array(); //Store private addrs until end as last resort.
190
+ for($i = 0; $i < count($arr); $i++){
191
$item = $arr[$i];
192
+ if(is_array($item)){
193
foreach($item as $j){
194
+ // try verifying the IP is valid before stripping the port off
195
+ if (!self::isValidIP($j)) {
196
+ $j = preg_replace('/:\d+#x2F;', '', $j); //Strip off port
197
+ }
198
+ if (self::isValidIP($j)) {
199
+ if (self::isPrivateAddress($j)) {
200
$privates[] = $j;
201
} else {
202
return $j;
207
}
208
$skipToNext = false;
209
foreach(array(',', ' ', "\t") as $char){
210
+ if(strpos($item, $char) !== false){
211
$sp = explode($char, $item);
212
foreach($sp as $j){
213
+ if (!self::isValidIP($j)) {
214
+ $j = preg_replace('/:\d+#x2F;', '', $j); //Strip off port
215
+ }
216
if(self::isValidIP($j)){
217
if(self::isPrivateAddress($j)){
218
$privates[] = $j;
227
}
228
if($skipToNext){ continue; } //Skip to next item because this one had a comma, space or tab so was delimited and we didn't find anything.
229
230
+ if (!self::isValidIP($item)) {
231
+ $item = preg_replace('/:\d+#x2F;', '', $item); //Strip off port
232
+ }
233
if(self::isValidIP($item)){
234
if(self::isPrivateAddress($item)){
235
$privates[] = $item;
263
$IP = self::getCleanIP(array($_SERVER[$howGet], $_SERVER['REMOTE_ADDR']));
264
}
265
} else {
266
+ // if no REMOTE_ADDR, it's probably running from the command line
267
+ $IPs = array(isset($_SERVER['REMOTE_ADDR']) ? $_SERVER['REMOTE_ADDR'] : '127.0.0.1');
268
if(isset($_SERVER['HTTP_X_FORWARDED_FOR'])){ $IPs[] = $_SERVER['HTTP_X_FORWARDED_FOR']; }
269
if(isset($_SERVER['HTTP_X_REAL_IP'])){ $IPs[] = $_SERVER['HTTP_X_REAL_IP']; }
270
+ $IP = self::getCleanIP($IPs);
271
}
272
return $IP; //Returns a valid IP or false.
273
}
274
public static function isValidIP($IP){
275
+ return filter_var($IP, FILTER_VALIDATE_IP) !== false;
276
}
277
public static function getRequestedURL(){
278
if(isset($_SERVER['HTTP_HOST']) && $_SERVER['HTTP_HOST']){
318
return $db->querySingle("select AES_DECRYPT(UNHEX('%s'), '%s') as val", $str, $key);
319
}
320
public static function lcmem(){
321
+ $trace=debug_backtrace();
322
+ $caller=array_shift($trace);
323
$mem = memory_get_usage(true);
324
error_log("$mem at " . $caller['file'] . " line " . $caller['line']);
325
}
326
public static function logCaller(){
327
+ $trace=debug_backtrace();
328
+ $caller=array_shift($trace);
329
$c2 = array_shift($trace);
330
error_log("Caller for " . $caller['file'] . " line " . $caller['line'] . " is " . $c2['file'] . ' line ' . $c2['line']);
331
}
338
}
339
}
340
public static function isAdminPageMU(){
341
+ if(preg_match('/^[\/a-zA-Z0-9\-\_\s\+\~\!\^\.]*\/wp-admin\/network\//', $_SERVER['REQUEST_URI'])){
342
+ return true;
343
}
344
return false;
345
}
413
return self::$isWindows == 'yes' ? true : false;
414
}
415
public static function getScanLock(){
416
+ //Windows does not support non-blocking flock, so we use time.
417
$scanRunning = wfConfig::get('wf_scanRunning');
418
if($scanRunning && time() - $scanRunning < WORDFENCE_MAX_SCAN_TIME){
419
return false;
433
}
434
}
435
public static function getIPGeo($IP){ //Works with int or dotted
436
+
437
$locs = self::getIPsGeo(array($IP));
438
if(isset($locs[$IP])){
439
return $locs[$IP];
443
}
444
public static function getIPsGeo($IPs){ //works with int or dotted. Outputs same format it receives.
445
$IPs = array_unique($IPs);
446
$toResolve = array();
447
$db = new wfDB();
448
global $wpdb;
449
$locsTable = $wpdb->base_prefix . 'wfLocs';
450
$IPLocs = array();
451
foreach($IPs as $IP){
452
+ $isBinaryIP = !self::isValidIP($IP);
453
+ if ($isBinaryIP) {
454
+ $ip_printable = wfUtils::inet_ntop($IP);
455
+ $ip_bin = $IP;
456
+ } else {
457
+ $ip_printable = $IP;
458
+ $ip_bin = wfUtils::inet_pton($IP);
459
+ }
460
+
461
+ $row = $db->querySingleRec("select IP, ctime, failed, city, region, countryName, countryCode, lat, lon, unix_timestamp() - ctime as age from " . $locsTable . " where IP=%s", $ip_bin);
462
if($row){
463
if($row['age'] > WORDFENCE_MAX_IPLOC_AGE){
464
$db->queryWrite("delete from " . $locsTable . " where IP=%s", $row['IP']);
465
} else {
466
if($row['failed'] == 1){
467
+ $IPLocs[$ip_printable] = false;
468
} else {
469
+ $row['IP'] = self::inet_ntop($row['IP']);
470
+ $IPLocs[$ip_printable] = $row;
471
}
472
}
473
}
474
+ if(! isset($IPLocs[$ip_printable])){
475
+ $toResolve[] = $ip_printable;
476
}
477
}
478
if(sizeof($toResolve) > 0){
479
+ $api = new wfAPI(wfConfig::get('apiKey'), wfUtils::getWPVersion());
480
try {
481
$freshIPs = $api->call('resolve_ips', array(), array(
482
'ips' => implode(',', $toResolve)
483
));
484
if(is_array($freshIPs)){
485
foreach($freshIPs as $IP => $value){
486
+ $IP_bin = wfUtils::inet_pton($IP);
487
if($value == 'failed'){
488
+ $db->queryWrite("insert IGNORE into " . $locsTable . " (IP, ctime, failed) values (%s, unix_timestamp(), 1)", $IP_bin);
489
$IPLocs[$IP] = false;
490
} else if(is_array($value)){
491
for($i = 0; $i <= 5; $i++){
492
//Prevent warnings in debug mode about uninitialized values
493
if(! isset($value[$i])){ $value[$i] = ''; }
494
}
495
+ $db->queryWrite("insert IGNORE into " . $locsTable . " (IP, ctime, failed, city, region, countryName, countryCode, lat, lon) values (%s, unix_timestamp(), 0, '%s', '%s', '%s', '%s', %s, %s)",
496
+ $IP_bin,
497
$value[3], //city
498
$value[2], //region
499
$value[1], //countryName
520
}
521
return $IPLocs;
522
}
523
+
524
+ public static function reverseLookup($IP) {
525
$db = new wfDB();
526
global $wpdb;
527
$reverseTable = $wpdb->base_prefix . 'wfReverseCache';
528
+ $IPn = wfUtils::inet_pton($IP);
529
$host = $db->querySingle("select host from " . $reverseTable . " where IP=%s and unix_timestamp() - lastUpdate < %d", $IPn, WORDFENCE_REVERSE_LOOKUP_CACHE_TIME);
530
+ if (!$host) {
531
+ // This function works for IPv4 or IPv6
532
+ if (function_exists('gethostbyaddr')) {
533
+ $host = gethostbyaddr($IP);
534
}
535
+ if (!$host) {
536
+ $ptr = false;
537
+ if (filter_var($IP, FILTER_VALIDATE_IP, FILTER_FLAG_IPV4) !== false) {
538
+ $ptr = implode(".", array_reverse(explode(".", $IP))) . ".in-addr.arpa";
539
+ } else if (filter_var($IP, FILTER_VALIDATE_IP, FILTER_FLAG_IPV6) !== false) {
540
+ $ptr = implode(".", array_reverse(str_split(bin2hex($IPn)))) . ".ip6.arpa";
541
+ }
542
+
543
+ if ($ptr && function_exists('dns_get_record')) {
544
+ $host = @dns_get_record($ptr, DNS_PTR);
545
+ if ($host) {
546
+ $host = $host[0]['target'];
547
+ }
548
+ }
549
+ }
550
+ if (!$host) {
551
$host = 'NONE';
552
}
553
$db->queryWrite("insert into " . $reverseTable . " (IP, host, lastUpdate) values (%s, '%s', unix_timestamp()) ON DUPLICATE KEY UPDATE host='%s', lastUpdate=unix_timestamp()", $IPn, $host, $host);
554
}
555
+ if ($host == 'NONE') {
556
return '';
557
} else {
558
return $host;
576
$fh = @fopen($file, 'r');
577
wfUtils::errorsOn();
578
if(! $fh){ return false; }
579
+ $offset = WORDFENCE_MAX_FILE_SIZE_TO_PROCESS + 1;
580
$tooBig = false;
581
try {
582
if(@fseek($fh, $offset, SEEK_SET) === 0){
591
public static function fileOver2Gigs($file){ //Surround calls to this func with try/catch because fseek may throw error.
592
$fh = @fopen($file, 'r');
593
if(! $fh){ return false; }
594
+ $offset = 2147483647;
595
$tooBig = false;
596
//My throw an error so surround calls to this func with try/catch
597
if(@fseek($fh, $offset, SEEK_SET) === 0){
616
return $URL;
617
}
618
public static function IP2Country($IP){
619
+ if(! (function_exists('geoip_open') && function_exists('geoip_country_code_by_addr') && function_exists('geoip_country_code_by_addr_v6'))){
620
require_once('wfGeoIP.php');
621
}
622
$gi = geoip_open(dirname(__FILE__) . "/GeoIP.dat",GEOIP_STANDARD);
623
+ if (filter_var($IP, FILTER_VALIDATE_IP, FILTER_FLAG_IPV6) !== false) {
624
+ $country = geoip_country_code_by_addr_v6($gi, $IP);
625
+ } else {
626
+ $country = geoip_country_code_by_addr($gi, $IP);
627
+ }
628
geoip_close($gi);
629
return $country ? $country : '';
630
}
672
public static function isRefererBlocked($refPattern){
673
return fnmatch($refPattern, $_SERVER['HTTP_REFERER'], FNM_CASEFOLD);
674
}
675
+
676
+ /**
677
+ * @param $startIP
678
+ * @param $endIP
679
+ * @return array
680
+ */
681
public static function rangeToCIDRs($startIP, $endIP){
682
+ $start_ip_printable = wfUtils::inet_ntop($startIP);
683
+ if (filter_var($start_ip_printable, FILTER_VALIDATE_IP, FILTER_FLAG_IPV4)) {
684
+ return self::rangeToCIDRsIPv4(current(unpack('N', substr($startIP, 12, 4))), current(unpack('N', substr($endIP, 12, 4))));
685
+ }
686
+ $startIPBin = str_pad(wfHelperBin::bin2str($startIP), 128, '0', STR_PAD_LEFT);
687
+ $endIPBin = str_pad(wfHelperBin::bin2str($endIP), 128, '0', STR_PAD_LEFT);
688
+ $IPIncBin = $startIPBin;
689
+ $CIDRs = array();
690
+ while (strcmp($IPIncBin, $endIPBin) <= 0) {
691
+ $longNetwork = 128;
692
+ $IPNetBin = $IPIncBin;
693
+ while (($IPIncBin[$longNetwork - 1] == '0') && (strcmp(substr_replace($IPNetBin, '1', $longNetwork - 1, 1), $endIPBin) <= 0)) {
694
+ $IPNetBin[$longNetwork - 1] = '1';
695
+ $longNetwork--;
696
+ }
697
+ $CIDRs[] = self::inet_ntop(str_pad(wfHelperBin::str2bin($IPIncBin), 16, "\x00", STR_PAD_LEFT)) . ($longNetwork < 128 ? '/' . $longNetwork : '');
698
+ $IPIncBin = str_pad(wfHelperBin::bin2str(wfHelperBin::addbin2bin(chr(1), wfHelperBin::str2bin($IPNetBin))), 128, '0', STR_PAD_LEFT);
699
+ }
700
+ return $CIDRs;
701
+ }