mirror of https://github.com/gorhill/uBlock.git
Code review for `ipaddress=` filter option
If an IP address can be extracted from the hostname portion of a URL, the IP address matching will be performed at onBeforeRequest() time. Regardless, IP address matching will subsequently always be performed at onHeadersReceived() time as the request details at that point contain a reliable IP address value on supported platforms (Firefox- only as of now). The `cap_ipaddress` now evaluates to `true` in Chromium-based browsers. Even though these browsers are unable to provide reliable IP address value at onHeadersReceived() time, they can still perform IP address matching for IP address extracted from hostname portion of a URL.
This commit is contained in:
parent
c19497db33
commit
099b9852cd
|
@ -163,6 +163,7 @@ vAPI.webextFlavor = {
|
|||
|
||||
// This is always true.
|
||||
soup.add('ublock').add('webext');
|
||||
soup.add('ipaddress');
|
||||
|
||||
// Whether this is a dev build.
|
||||
if ( /^\d+\.\d+\.\d+\D/.test(browser.runtime.getManifest().version) ) {
|
||||
|
@ -181,8 +182,7 @@ vAPI.webextFlavor = {
|
|||
if ( browser.runtime.getURL('').startsWith('moz-extension://') ) {
|
||||
soup.add('firefox')
|
||||
.add('user_stylesheet')
|
||||
.add('html_filtering')
|
||||
.add('ipaddress');
|
||||
.add('html_filtering');
|
||||
const match = /Firefox\/(\d+)/.exec(ua);
|
||||
flavor.major = match && parseInt(match[1], 10) || 115;
|
||||
} else {
|
||||
|
|
|
@ -305,8 +305,8 @@ const µBlock = { // jshint ignore:line
|
|||
this.realm = '';
|
||||
this.setMethod(details.method);
|
||||
this.setURL(details.url);
|
||||
this.setIPAddress(details.ip);
|
||||
this.aliasURL = details.aliasURL || undefined;
|
||||
this.ipaddress = details.ip || undefined;
|
||||
this.redirectURL = undefined;
|
||||
this.filter = undefined;
|
||||
if ( this.itype !== this.SUB_FRAME ) {
|
||||
|
|
|
@ -122,6 +122,8 @@ const methodBitToStrMap = new Map([
|
|||
[ METHOD_PUT, 'put' ],
|
||||
]);
|
||||
|
||||
const reIPv4 = /^\d+\.\d+\.\d+\.\d+$/;
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
export const FilteringContext = class {
|
||||
|
@ -136,9 +138,9 @@ export const FilteringContext = class {
|
|||
this.stype = undefined;
|
||||
this.url = undefined;
|
||||
this.aliasURL = undefined;
|
||||
this.ipaddress = undefined;
|
||||
this.hostname = undefined;
|
||||
this.domain = undefined;
|
||||
this.ipaddress = undefined;
|
||||
this.docId = -1;
|
||||
this.frameId = -1;
|
||||
this.docOrigin = undefined;
|
||||
|
@ -176,6 +178,7 @@ export const FilteringContext = class {
|
|||
this.url = other.url;
|
||||
this.hostname = other.hostname;
|
||||
this.domain = other.domain;
|
||||
this.ipaddress = other.ipaddress;
|
||||
this.docId = other.docId;
|
||||
this.frameId = other.frameId;
|
||||
this.docOrigin = other.docOrigin;
|
||||
|
@ -213,7 +216,7 @@ export const FilteringContext = class {
|
|||
|
||||
setURL(a) {
|
||||
if ( a !== this.url ) {
|
||||
this.hostname = this.domain = undefined;
|
||||
this.hostname = this.domain = this.ipaddress = undefined;
|
||||
this.url = a;
|
||||
}
|
||||
return this;
|
||||
|
@ -246,6 +249,28 @@ export const FilteringContext = class {
|
|||
return this;
|
||||
}
|
||||
|
||||
getIPAddress() {
|
||||
if ( this.ipaddress !== undefined ) {
|
||||
return this.ipaddress;
|
||||
}
|
||||
const ipaddr = this.getHostname();
|
||||
const c0 = ipaddr.charCodeAt(0);
|
||||
if ( c0 === 0x5B /* [ */ ) {
|
||||
return (this.ipaddress = ipaddr.slice(1, -1));
|
||||
} else if ( c0 >= 0x30 && c0 <= 0x39 ) {
|
||||
if ( reIPv4.test(ipaddr) ) {
|
||||
return (this.ipaddress = ipaddr);
|
||||
}
|
||||
}
|
||||
return (this.ipaddress = '');
|
||||
}
|
||||
|
||||
// Must always be called *after* setURL()
|
||||
setIPAddress(ipaddr) {
|
||||
this.ipaddress = ipaddr || undefined;
|
||||
return this;
|
||||
}
|
||||
|
||||
getDocOrigin() {
|
||||
if ( this.docOrigin === undefined ) {
|
||||
this.docOrigin = this.tabOrigin;
|
||||
|
|
|
@ -578,6 +578,7 @@ export const preparserIfTokens = new Set([
|
|||
'env_mv3',
|
||||
'env_safari',
|
||||
'cap_html_filtering',
|
||||
'cap_ipaddress',
|
||||
'cap_user_stylesheet',
|
||||
'false',
|
||||
'ext_abp',
|
||||
|
|
|
@ -2973,6 +2973,9 @@ registerFilterClass(FilterOnHeaders);
|
|||
/******************************************************************************/
|
||||
|
||||
class FilterIPAddress {
|
||||
static reIPv6IPv4lan = /^::ffff:(7f\w{2}|a\w{2}|a9fe|c0a8):\w+$/;
|
||||
static reIPv6local = /^f[cd]\w{2}:/;
|
||||
|
||||
static match(idata) {
|
||||
const ipaddr = $requestAddress;
|
||||
const details = filterRefs[filterData[idata+1]];
|
||||
|
@ -3011,26 +3014,26 @@ class FilterIPAddress {
|
|||
}
|
||||
return ipaddr.startsWith('192.168.');
|
||||
}
|
||||
if ( c0 !== 0x5B /* [ */ ) { return false; }
|
||||
// ipv6
|
||||
const c1 = ipaddr.charCodeAt(1);
|
||||
if ( c1 === 0x3A /* : */ ) {
|
||||
if ( ipaddr.startsWith('[::') === false ) { return false; }
|
||||
if ( ipaddr === '[::]' || ipaddr === '[::1]' ) { return true; }
|
||||
if ( ipaddr.startsWith('[::ffff:') === false ) { return false; }
|
||||
return /^\[::ffff:(7f\w{2}|a\w{2}|a9fe|c0a8):\w+\]$/.test(ipaddr);
|
||||
if ( c0 === 0x3A /* : */ ) {
|
||||
if ( ipaddr.startsWith('::') === false ) { return false; }
|
||||
if ( ipaddr === '::' || ipaddr === '::1' ) { return true; }
|
||||
if ( ipaddr.startsWith('::ffff:') === false ) { return false; }
|
||||
return this.reIPv6IPv4lan.test(ipaddr);
|
||||
}
|
||||
if ( c1 === 0x36 /* 6 */ ) {
|
||||
return ipaddr.startsWith('[64:ff9b:');
|
||||
}
|
||||
if ( c1 === 0x66 /* f */ ) {
|
||||
return /^\[f[cd]\w{2}:/.test(ipaddr);
|
||||
if ( ipaddr.includes(':') ) {
|
||||
if ( c0 === 0x36 /* 6 */ ) {
|
||||
return ipaddr.startsWith('64:ff9b:');
|
||||
}
|
||||
if ( c0 === 0x66 /* f */ ) {
|
||||
return this.reIPv6local.test(ipaddr);
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
static isLoopback(ipaddr) {
|
||||
return ipaddr === '127.0.0.1' || ipaddr === '[::1]';
|
||||
return ipaddr === '127.0.0.1' || ipaddr === '::1';
|
||||
}
|
||||
|
||||
static compile(details) {
|
||||
|
@ -3412,7 +3415,6 @@ class FilterCompiler {
|
|||
this.notTypeBits = 0;
|
||||
this.methodBits = 0;
|
||||
this.notMethodBits = 0;
|
||||
this.responseHeadersRealm = false;
|
||||
return this;
|
||||
}
|
||||
|
||||
|
@ -3532,13 +3534,11 @@ class FilterCompiler {
|
|||
case sfp.NODE_TYPE_NET_OPTION_NAME_HEADER: {
|
||||
this.optionValues.set('header', parser.getNetOptionValue(id) || '');
|
||||
this.optionUnitBits |= HEADER_BIT;
|
||||
this.responseHeadersRealm = true;
|
||||
break;
|
||||
}
|
||||
case sfp.NODE_TYPE_NET_OPTION_NAME_IPADDRESS:
|
||||
this.optionValues.set('ipaddress', parser.getNetOptionValue(id) || '');
|
||||
this.optionUnitBits |= IPADDRESS_BIT;
|
||||
this.responseHeadersRealm = true;
|
||||
break;
|
||||
case sfp.NODE_TYPE_NET_OPTION_NAME_METHOD:
|
||||
this.processMethodOption(parser.getNetOptionValue(id));
|
||||
|
@ -4008,7 +4008,7 @@ class FilterCompiler {
|
|||
}
|
||||
|
||||
// Origin
|
||||
if ( this.optionValues.has('from') ) {
|
||||
if ( (this.optionUnitBits & FROM_BIT) !== 0 ) {
|
||||
compileFromDomainOpt(
|
||||
this.optionValues.get('fromList'),
|
||||
units.length !== 0 && patternClass.isSlow === true,
|
||||
|
@ -4017,7 +4017,7 @@ class FilterCompiler {
|
|||
}
|
||||
|
||||
// Destination
|
||||
if ( this.optionValues.has('to') ) {
|
||||
if ( (this.optionUnitBits & TO_BIT) !== 0 ) {
|
||||
compileToDomainOpt(
|
||||
this.optionValues.get('toList'),
|
||||
units.length !== 0 && patternClass.isSlow === true,
|
||||
|
@ -4026,18 +4026,18 @@ class FilterCompiler {
|
|||
}
|
||||
|
||||
// Deny-allow
|
||||
if ( this.optionValues.has('denyallow') ) {
|
||||
if ( (this.optionUnitBits & DENYALLOW_BIT) !== 0 ) {
|
||||
units.push(FilterDenyAllow.compile(this));
|
||||
}
|
||||
|
||||
// IP address
|
||||
if ( (this.optionUnitBits & IPADDRESS_BIT) !== 0 ) {
|
||||
units.push(FilterIPAddress.compile(this));
|
||||
}
|
||||
|
||||
// Header
|
||||
if ( this.responseHeadersRealm ) {
|
||||
if ( this.optionValues.has('ipaddress') ) {
|
||||
units.push(FilterIPAddress.compile(this));
|
||||
}
|
||||
if ( this.optionValues.has('header') ) {
|
||||
units.push(FilterOnHeaders.compile(this));
|
||||
}
|
||||
if ( (this.optionUnitBits & HEADER_BIT) !== 0 ) {
|
||||
units.push(FilterOnHeaders.compile(this));
|
||||
this.action |= HEADERS_REALM;
|
||||
}
|
||||
|
||||
|
@ -4058,12 +4058,17 @@ class FilterCompiler {
|
|||
modifierBitsFromType.get(this.modifyType);
|
||||
}
|
||||
|
||||
this.compileToAtomicFilter(
|
||||
units.length === 1
|
||||
? units[0]
|
||||
: FilterCompositeAll.compile(units),
|
||||
writer
|
||||
);
|
||||
const fdata = units.length === 1
|
||||
? units[0]
|
||||
: FilterCompositeAll.compile(units);
|
||||
|
||||
this.compileToAtomicFilter(fdata, writer);
|
||||
|
||||
if ( (this.optionUnitBits & IPADDRESS_BIT) !== 0 ) {
|
||||
if ( (this.action & HEADERS_REALM) !== 0 ) { return; }
|
||||
this.action |= HEADERS_REALM;
|
||||
this.compileToAtomicFilter(fdata, writer);
|
||||
}
|
||||
}
|
||||
|
||||
compilePattern(units) {
|
||||
|
@ -4856,7 +4861,7 @@ StaticNetFilteringEngine.prototype.matchAndFetchModifiers = function(
|
|||
$requestHostname = fctxt.getHostname();
|
||||
$requestMethodBit = fctxt.method || 0;
|
||||
$requestTypeValue = (typeBits & TypeBitsMask) >>> TypeBitsOffset;
|
||||
$requestAddress = fctxt.ipaddress || '';
|
||||
$requestAddress = fctxt.getIPAddress();
|
||||
|
||||
const modifierType = modifierTypeFromName.get(modifierName);
|
||||
const modifierBits = modifierBitsFromType.get(modifierType);
|
||||
|
@ -5223,7 +5228,7 @@ StaticNetFilteringEngine.prototype.matchRequest = function(fctxt, modifiers = 0)
|
|||
$requestHostname = fctxt.getHostname();
|
||||
$requestMethodBit = fctxt.method || 0;
|
||||
$requestTypeValue = (typeBits & TypeBitsMask) >>> TypeBitsOffset;
|
||||
$requestAddress = fctxt.ipaddress || '';
|
||||
$requestAddress = fctxt.getIPAddress();
|
||||
$isBlockImportant = false;
|
||||
|
||||
// Evaluate block realm before allow realm, and allow realm before
|
||||
|
@ -5259,7 +5264,7 @@ StaticNetFilteringEngine.prototype.matchHeaders = function(fctxt, headers) {
|
|||
$requestHostname = fctxt.getHostname();
|
||||
$requestMethodBit = fctxt.method || 0;
|
||||
$requestTypeValue = (typeBits & TypeBitsMask) >>> TypeBitsOffset;
|
||||
$requestAddress = fctxt.ipaddress || '';
|
||||
$requestAddress = fctxt.getIPAddress();
|
||||
$httpHeaders.init(headers);
|
||||
|
||||
let r = 0;
|
||||
|
|
Loading…
Reference in New Issue