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.
|
// This is always true.
|
||||||
soup.add('ublock').add('webext');
|
soup.add('ublock').add('webext');
|
||||||
|
soup.add('ipaddress');
|
||||||
|
|
||||||
// Whether this is a dev build.
|
// Whether this is a dev build.
|
||||||
if ( /^\d+\.\d+\.\d+\D/.test(browser.runtime.getManifest().version) ) {
|
if ( /^\d+\.\d+\.\d+\D/.test(browser.runtime.getManifest().version) ) {
|
||||||
|
@ -181,8 +182,7 @@ vAPI.webextFlavor = {
|
||||||
if ( browser.runtime.getURL('').startsWith('moz-extension://') ) {
|
if ( browser.runtime.getURL('').startsWith('moz-extension://') ) {
|
||||||
soup.add('firefox')
|
soup.add('firefox')
|
||||||
.add('user_stylesheet')
|
.add('user_stylesheet')
|
||||||
.add('html_filtering')
|
.add('html_filtering');
|
||||||
.add('ipaddress');
|
|
||||||
const match = /Firefox\/(\d+)/.exec(ua);
|
const match = /Firefox\/(\d+)/.exec(ua);
|
||||||
flavor.major = match && parseInt(match[1], 10) || 115;
|
flavor.major = match && parseInt(match[1], 10) || 115;
|
||||||
} else {
|
} else {
|
||||||
|
|
|
@ -305,8 +305,8 @@ const µBlock = { // jshint ignore:line
|
||||||
this.realm = '';
|
this.realm = '';
|
||||||
this.setMethod(details.method);
|
this.setMethod(details.method);
|
||||||
this.setURL(details.url);
|
this.setURL(details.url);
|
||||||
|
this.setIPAddress(details.ip);
|
||||||
this.aliasURL = details.aliasURL || undefined;
|
this.aliasURL = details.aliasURL || undefined;
|
||||||
this.ipaddress = details.ip || undefined;
|
|
||||||
this.redirectURL = undefined;
|
this.redirectURL = undefined;
|
||||||
this.filter = undefined;
|
this.filter = undefined;
|
||||||
if ( this.itype !== this.SUB_FRAME ) {
|
if ( this.itype !== this.SUB_FRAME ) {
|
||||||
|
|
|
@ -122,6 +122,8 @@ const methodBitToStrMap = new Map([
|
||||||
[ METHOD_PUT, 'put' ],
|
[ METHOD_PUT, 'put' ],
|
||||||
]);
|
]);
|
||||||
|
|
||||||
|
const reIPv4 = /^\d+\.\d+\.\d+\.\d+$/;
|
||||||
|
|
||||||
/******************************************************************************/
|
/******************************************************************************/
|
||||||
|
|
||||||
export const FilteringContext = class {
|
export const FilteringContext = class {
|
||||||
|
@ -136,9 +138,9 @@ export const FilteringContext = class {
|
||||||
this.stype = undefined;
|
this.stype = undefined;
|
||||||
this.url = undefined;
|
this.url = undefined;
|
||||||
this.aliasURL = undefined;
|
this.aliasURL = undefined;
|
||||||
this.ipaddress = undefined;
|
|
||||||
this.hostname = undefined;
|
this.hostname = undefined;
|
||||||
this.domain = undefined;
|
this.domain = undefined;
|
||||||
|
this.ipaddress = undefined;
|
||||||
this.docId = -1;
|
this.docId = -1;
|
||||||
this.frameId = -1;
|
this.frameId = -1;
|
||||||
this.docOrigin = undefined;
|
this.docOrigin = undefined;
|
||||||
|
@ -176,6 +178,7 @@ export const FilteringContext = class {
|
||||||
this.url = other.url;
|
this.url = other.url;
|
||||||
this.hostname = other.hostname;
|
this.hostname = other.hostname;
|
||||||
this.domain = other.domain;
|
this.domain = other.domain;
|
||||||
|
this.ipaddress = other.ipaddress;
|
||||||
this.docId = other.docId;
|
this.docId = other.docId;
|
||||||
this.frameId = other.frameId;
|
this.frameId = other.frameId;
|
||||||
this.docOrigin = other.docOrigin;
|
this.docOrigin = other.docOrigin;
|
||||||
|
@ -213,7 +216,7 @@ export const FilteringContext = class {
|
||||||
|
|
||||||
setURL(a) {
|
setURL(a) {
|
||||||
if ( a !== this.url ) {
|
if ( a !== this.url ) {
|
||||||
this.hostname = this.domain = undefined;
|
this.hostname = this.domain = this.ipaddress = undefined;
|
||||||
this.url = a;
|
this.url = a;
|
||||||
}
|
}
|
||||||
return this;
|
return this;
|
||||||
|
@ -246,6 +249,28 @@ export const FilteringContext = class {
|
||||||
return this;
|
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() {
|
getDocOrigin() {
|
||||||
if ( this.docOrigin === undefined ) {
|
if ( this.docOrigin === undefined ) {
|
||||||
this.docOrigin = this.tabOrigin;
|
this.docOrigin = this.tabOrigin;
|
||||||
|
|
|
@ -578,6 +578,7 @@ export const preparserIfTokens = new Set([
|
||||||
'env_mv3',
|
'env_mv3',
|
||||||
'env_safari',
|
'env_safari',
|
||||||
'cap_html_filtering',
|
'cap_html_filtering',
|
||||||
|
'cap_ipaddress',
|
||||||
'cap_user_stylesheet',
|
'cap_user_stylesheet',
|
||||||
'false',
|
'false',
|
||||||
'ext_abp',
|
'ext_abp',
|
||||||
|
|
|
@ -2973,6 +2973,9 @@ registerFilterClass(FilterOnHeaders);
|
||||||
/******************************************************************************/
|
/******************************************************************************/
|
||||||
|
|
||||||
class FilterIPAddress {
|
class FilterIPAddress {
|
||||||
|
static reIPv6IPv4lan = /^::ffff:(7f\w{2}|a\w{2}|a9fe|c0a8):\w+$/;
|
||||||
|
static reIPv6local = /^f[cd]\w{2}:/;
|
||||||
|
|
||||||
static match(idata) {
|
static match(idata) {
|
||||||
const ipaddr = $requestAddress;
|
const ipaddr = $requestAddress;
|
||||||
const details = filterRefs[filterData[idata+1]];
|
const details = filterRefs[filterData[idata+1]];
|
||||||
|
@ -3011,26 +3014,26 @@ class FilterIPAddress {
|
||||||
}
|
}
|
||||||
return ipaddr.startsWith('192.168.');
|
return ipaddr.startsWith('192.168.');
|
||||||
}
|
}
|
||||||
if ( c0 !== 0x5B /* [ */ ) { return false; }
|
|
||||||
// ipv6
|
// ipv6
|
||||||
const c1 = ipaddr.charCodeAt(1);
|
if ( c0 === 0x3A /* : */ ) {
|
||||||
if ( c1 === 0x3A /* : */ ) {
|
if ( ipaddr.startsWith('::') === false ) { return false; }
|
||||||
if ( ipaddr.startsWith('[::') === false ) { return false; }
|
if ( ipaddr === '::' || ipaddr === '::1' ) { return true; }
|
||||||
if ( ipaddr === '[::]' || ipaddr === '[::1]' ) { return true; }
|
if ( ipaddr.startsWith('::ffff:') === false ) { return false; }
|
||||||
if ( ipaddr.startsWith('[::ffff:') === false ) { return false; }
|
return this.reIPv6IPv4lan.test(ipaddr);
|
||||||
return /^\[::ffff:(7f\w{2}|a\w{2}|a9fe|c0a8):\w+\]$/.test(ipaddr);
|
|
||||||
}
|
}
|
||||||
if ( c1 === 0x36 /* 6 */ ) {
|
if ( ipaddr.includes(':') ) {
|
||||||
return ipaddr.startsWith('[64:ff9b:');
|
if ( c0 === 0x36 /* 6 */ ) {
|
||||||
|
return ipaddr.startsWith('64:ff9b:');
|
||||||
|
}
|
||||||
|
if ( c0 === 0x66 /* f */ ) {
|
||||||
|
return this.reIPv6local.test(ipaddr);
|
||||||
}
|
}
|
||||||
if ( c1 === 0x66 /* f */ ) {
|
|
||||||
return /^\[f[cd]\w{2}:/.test(ipaddr);
|
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
static isLoopback(ipaddr) {
|
static isLoopback(ipaddr) {
|
||||||
return ipaddr === '127.0.0.1' || ipaddr === '[::1]';
|
return ipaddr === '127.0.0.1' || ipaddr === '::1';
|
||||||
}
|
}
|
||||||
|
|
||||||
static compile(details) {
|
static compile(details) {
|
||||||
|
@ -3412,7 +3415,6 @@ class FilterCompiler {
|
||||||
this.notTypeBits = 0;
|
this.notTypeBits = 0;
|
||||||
this.methodBits = 0;
|
this.methodBits = 0;
|
||||||
this.notMethodBits = 0;
|
this.notMethodBits = 0;
|
||||||
this.responseHeadersRealm = false;
|
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -3532,13 +3534,11 @@ class FilterCompiler {
|
||||||
case sfp.NODE_TYPE_NET_OPTION_NAME_HEADER: {
|
case sfp.NODE_TYPE_NET_OPTION_NAME_HEADER: {
|
||||||
this.optionValues.set('header', parser.getNetOptionValue(id) || '');
|
this.optionValues.set('header', parser.getNetOptionValue(id) || '');
|
||||||
this.optionUnitBits |= HEADER_BIT;
|
this.optionUnitBits |= HEADER_BIT;
|
||||||
this.responseHeadersRealm = true;
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case sfp.NODE_TYPE_NET_OPTION_NAME_IPADDRESS:
|
case sfp.NODE_TYPE_NET_OPTION_NAME_IPADDRESS:
|
||||||
this.optionValues.set('ipaddress', parser.getNetOptionValue(id) || '');
|
this.optionValues.set('ipaddress', parser.getNetOptionValue(id) || '');
|
||||||
this.optionUnitBits |= IPADDRESS_BIT;
|
this.optionUnitBits |= IPADDRESS_BIT;
|
||||||
this.responseHeadersRealm = true;
|
|
||||||
break;
|
break;
|
||||||
case sfp.NODE_TYPE_NET_OPTION_NAME_METHOD:
|
case sfp.NODE_TYPE_NET_OPTION_NAME_METHOD:
|
||||||
this.processMethodOption(parser.getNetOptionValue(id));
|
this.processMethodOption(parser.getNetOptionValue(id));
|
||||||
|
@ -4008,7 +4008,7 @@ class FilterCompiler {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Origin
|
// Origin
|
||||||
if ( this.optionValues.has('from') ) {
|
if ( (this.optionUnitBits & FROM_BIT) !== 0 ) {
|
||||||
compileFromDomainOpt(
|
compileFromDomainOpt(
|
||||||
this.optionValues.get('fromList'),
|
this.optionValues.get('fromList'),
|
||||||
units.length !== 0 && patternClass.isSlow === true,
|
units.length !== 0 && patternClass.isSlow === true,
|
||||||
|
@ -4017,7 +4017,7 @@ class FilterCompiler {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Destination
|
// Destination
|
||||||
if ( this.optionValues.has('to') ) {
|
if ( (this.optionUnitBits & TO_BIT) !== 0 ) {
|
||||||
compileToDomainOpt(
|
compileToDomainOpt(
|
||||||
this.optionValues.get('toList'),
|
this.optionValues.get('toList'),
|
||||||
units.length !== 0 && patternClass.isSlow === true,
|
units.length !== 0 && patternClass.isSlow === true,
|
||||||
|
@ -4026,18 +4026,18 @@ class FilterCompiler {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Deny-allow
|
// Deny-allow
|
||||||
if ( this.optionValues.has('denyallow') ) {
|
if ( (this.optionUnitBits & DENYALLOW_BIT) !== 0 ) {
|
||||||
units.push(FilterDenyAllow.compile(this));
|
units.push(FilterDenyAllow.compile(this));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Header
|
// IP address
|
||||||
if ( this.responseHeadersRealm ) {
|
if ( (this.optionUnitBits & IPADDRESS_BIT) !== 0 ) {
|
||||||
if ( this.optionValues.has('ipaddress') ) {
|
|
||||||
units.push(FilterIPAddress.compile(this));
|
units.push(FilterIPAddress.compile(this));
|
||||||
}
|
}
|
||||||
if ( this.optionValues.has('header') ) {
|
|
||||||
|
// Header
|
||||||
|
if ( (this.optionUnitBits & HEADER_BIT) !== 0 ) {
|
||||||
units.push(FilterOnHeaders.compile(this));
|
units.push(FilterOnHeaders.compile(this));
|
||||||
}
|
|
||||||
this.action |= HEADERS_REALM;
|
this.action |= HEADERS_REALM;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -4058,12 +4058,17 @@ class FilterCompiler {
|
||||||
modifierBitsFromType.get(this.modifyType);
|
modifierBitsFromType.get(this.modifyType);
|
||||||
}
|
}
|
||||||
|
|
||||||
this.compileToAtomicFilter(
|
const fdata = units.length === 1
|
||||||
units.length === 1
|
|
||||||
? units[0]
|
? units[0]
|
||||||
: FilterCompositeAll.compile(units),
|
: FilterCompositeAll.compile(units);
|
||||||
writer
|
|
||||||
);
|
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) {
|
compilePattern(units) {
|
||||||
|
@ -4856,7 +4861,7 @@ StaticNetFilteringEngine.prototype.matchAndFetchModifiers = function(
|
||||||
$requestHostname = fctxt.getHostname();
|
$requestHostname = fctxt.getHostname();
|
||||||
$requestMethodBit = fctxt.method || 0;
|
$requestMethodBit = fctxt.method || 0;
|
||||||
$requestTypeValue = (typeBits & TypeBitsMask) >>> TypeBitsOffset;
|
$requestTypeValue = (typeBits & TypeBitsMask) >>> TypeBitsOffset;
|
||||||
$requestAddress = fctxt.ipaddress || '';
|
$requestAddress = fctxt.getIPAddress();
|
||||||
|
|
||||||
const modifierType = modifierTypeFromName.get(modifierName);
|
const modifierType = modifierTypeFromName.get(modifierName);
|
||||||
const modifierBits = modifierBitsFromType.get(modifierType);
|
const modifierBits = modifierBitsFromType.get(modifierType);
|
||||||
|
@ -5223,7 +5228,7 @@ StaticNetFilteringEngine.prototype.matchRequest = function(fctxt, modifiers = 0)
|
||||||
$requestHostname = fctxt.getHostname();
|
$requestHostname = fctxt.getHostname();
|
||||||
$requestMethodBit = fctxt.method || 0;
|
$requestMethodBit = fctxt.method || 0;
|
||||||
$requestTypeValue = (typeBits & TypeBitsMask) >>> TypeBitsOffset;
|
$requestTypeValue = (typeBits & TypeBitsMask) >>> TypeBitsOffset;
|
||||||
$requestAddress = fctxt.ipaddress || '';
|
$requestAddress = fctxt.getIPAddress();
|
||||||
$isBlockImportant = false;
|
$isBlockImportant = false;
|
||||||
|
|
||||||
// Evaluate block realm before allow realm, and allow realm before
|
// Evaluate block realm before allow realm, and allow realm before
|
||||||
|
@ -5259,7 +5264,7 @@ StaticNetFilteringEngine.prototype.matchHeaders = function(fctxt, headers) {
|
||||||
$requestHostname = fctxt.getHostname();
|
$requestHostname = fctxt.getHostname();
|
||||||
$requestMethodBit = fctxt.method || 0;
|
$requestMethodBit = fctxt.method || 0;
|
||||||
$requestTypeValue = (typeBits & TypeBitsMask) >>> TypeBitsOffset;
|
$requestTypeValue = (typeBits & TypeBitsMask) >>> TypeBitsOffset;
|
||||||
$requestAddress = fctxt.ipaddress || '';
|
$requestAddress = fctxt.getIPAddress();
|
||||||
$httpHeaders.init(headers);
|
$httpHeaders.init(headers);
|
||||||
|
|
||||||
let r = 0;
|
let r = 0;
|
||||||
|
|
Loading…
Reference in New Issue