Skip to content

Commit

Permalink
Basic support for extra IPv6 validation
Browse files Browse the repository at this point in the history
  • Loading branch information
medo64 committed Jul 28, 2020
1 parent 4f1232a commit f715f35
Show file tree
Hide file tree
Showing 3 changed files with 108 additions and 12 deletions.
8 changes: 8 additions & 0 deletions README.md
Expand Up @@ -17,12 +17,17 @@ This extension contributes the following settings:
* `highlight-ip.cidr`: Determines if subnet length (e.g. /24) will be
highlighted in addition to the address.

* `highlight-ip.strict`: Extra validation for proper formatting of IPv6 address
(RFC5952 rules). If set to true, IP address will be
recognized and highlighted as error.


### Default Configuration

"highlight-ip.v4": true,
"highlight-ip.v6": true,
"highlight-ip.cidr": true,
"highlight-ip.strict": false,


## Extension Colors
Expand All @@ -33,12 +38,15 @@ This extension contributes the following colors:

* `ipaddress.subnet`: Color for IP subnet length.

* `ipaddress.networkIssue`: Color for the IP address breaking the rule.


### Default Colors

"workbench.colorCustomizations": {
"ipaddress.network": "textLink.foreground",
"ipaddress.subnet": "textLink.foreground",
"ipaddress.networkIssue": "errorForeground",
}


Expand Down
98 changes: 86 additions & 12 deletions out/extension.js
Expand Up @@ -7,11 +7,14 @@ function activate(context) {
const defaultIPv4Highlight = true
const defaultIPv6Highlight = true
const defaultCidrHighlight = true
const defaultStrictMode = false
var ipv4Highlight
var ipv6Highlight
var cidrHighlight
var strictMode

const ipNetworkDecorationType = vscode.window.createTextEditorDecorationType({ color: new vscode.ThemeColor('ipaddress.network') })
const ipNetworkIssueDecorationType = vscode.window.createTextEditorDecorationType({ color: new vscode.ThemeColor('ipaddress.networkIssue') })
const ipSubnetDecorationType = vscode.window.createTextEditorDecorationType({ color: new vscode.ThemeColor('ipaddress.subnet') })

const ipv4CidrPattern = /(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)(\/((3[0-2])|(2[0-9])|(1[0-9])|[0-9]))?/g
Expand All @@ -28,6 +31,7 @@ function activate(context) {
const shouldRender = ipv4Highlight | ipv6Highlight

var ipNetworkDecorations = []
var ipNetworkIssueDecorations = []
var ipSubnetDecorations = []
if (shouldRender) {
//determine what is exactly visible
Expand Down Expand Up @@ -60,9 +64,9 @@ function activate(context) {
const endsAt = match.index + match[0].length
if ((startsAt > 0) && ipv4BreakPattern.exec(lineText.charAt(startsAt - 1))) { continue } //skip if character before match
if ((endsAt < lineLength) && ipv4BreakPattern.exec(lineText.charAt(endsAt))) { continue } //skip if character after match
const address = match[0]
const slashIndex = address.indexOf('/')
const cidrLength = (slashIndex == -1) ? 0 : (address.length - slashIndex)
const addressMatch = match[0]
const slashIndex = addressMatch.indexOf('/')
const cidrLength = (slashIndex == -1) ? 0 : (addressMatch.length - slashIndex)
ipNetworkDecorations.push({
range: new vscode.Range(
new vscode.Position(i, startsAt),
Expand All @@ -87,15 +91,79 @@ function activate(context) {
const endsAt = match.index + match[0].length
if ((startsAt > 0) && ipv6BreakPattern.exec(lineText.charAt(startsAt - 1))) { continue } //skip if character before match
if ((endsAt < lineLength) && ipv6BreakPattern.exec(lineText.charAt(endsAt))) { continue } //skip if character after match
const address = match[0]
const slashIndex = address.indexOf('/')
const cidrLength = (slashIndex == -1) ? 0 : (address.length - slashIndex)
ipNetworkDecorations.push({
range: new vscode.Range(
new vscode.Position(i, startsAt),
new vscode.Position(i, endsAt - cidrLength)
)
})

const addressMatch = match[0]
const slashIndex = addressMatch.indexOf('/')
const cidrLength = (slashIndex == -1) ? 0 : (addressMatch.length - slashIndex)

let validStrictNetwork = true
if (strictMode) {
const address = (slashIndex == -1) ? addressMatch : addressMatch.substr(0, slashIndex)
let addressPartsRaw = address.split(':');
const addressParts = addressPartsRaw.filter(function (item) { return item !== '' })

//expand IP - brute force
let longAddress = address.replace('::', ':' + '0:'.repeat(8 - addressParts.length))
if (longAddress.startsWith(':')) { longAddress = longAddress.substring(1) }
if (longAddress.endsWith(':')) { longAddress = longAddress.substring(0, longAddress.length - 1) }

//shorten the longest run (RFC5952: shorten as much as possible -or- the first sequence of zero bits must be shortened)
const longAddressParts = longAddress.split(':')
let wasZero = false
let currRunIndex = 0
let currRunLength = 0
let longRunIndex = 0
let longRunLength = 0
for (let i = 0; i < longAddressParts.length; i++) {
if (longAddressParts[i] === '0') {
if (wasZero) {
currRunLength += 1
if (currRunLength > longRunLength) {
longRunIndex = currRunIndex
longRunLength = currRunLength
}
} else {
currRunIndex = i
currRunLength = 1
wasZero = true
}
} else {
wasZero = false
}
}

let skipColon = true
let formattedAddress = ''
for (let i = 0; i < longAddressParts.length; i++) {
if ((longRunLength > 0) && (longRunIndex == i)) {
formattedAddress += '::'
skipColon = true
} else if ((longRunLength == 0) || (i < longRunIndex) || (i >= (longRunIndex + longRunLength))) {
if (!skipColon) { formattedAddress += ':' }
formattedAddress += parseInt(longAddressParts[i], 16).toString(16); ////RFC5952: leading zeros must be suppressed -and- The characters must be lowercase
skipColon = false
}
}

validStrictNetwork = (address === formattedAddress);
}

if (validStrictNetwork) {
ipNetworkDecorations.push({
range: new vscode.Range(
new vscode.Position(i, startsAt),
new vscode.Position(i, endsAt - cidrLength)
)
})
} else {
ipNetworkIssueDecorations.push({
range: new vscode.Range(
new vscode.Position(i, startsAt),
new vscode.Position(i, endsAt - cidrLength)
)
})
}

if (cidrHighlight && (cidrLength > 0)) {
ipSubnetDecorations.push({
range: new vscode.Range(
Expand All @@ -110,6 +178,7 @@ function activate(context) {
}

if (editor.setDecorations) { editor.setDecorations(ipNetworkDecorationType, ipNetworkDecorations) }
if (editor.setDecorations) { editor.setDecorations(ipNetworkIssueDecorationType, ipNetworkIssueDecorations) }
if (editor.setDecorations) { editor.setDecorations(ipSubnetDecorationType, ipSubnetDecorations) }
}

Expand All @@ -120,6 +189,7 @@ function activate(context) {
let newIPv4Highlight = customConfiguration.get('v4', defaultIPv4Highlight)
let newIPv6Highlight = customConfiguration.get('v6', defaultIPv6Highlight)
let newCidrHighlight = customConfiguration.get('cidr', defaultCidrHighlight)
let newStrictMode = customConfiguration.get('strict', defaultStrictMode)

if (ipv4Highlight !== newIPv4Highlight) {
ipv4Highlight = newIPv4Highlight
Expand All @@ -133,6 +203,10 @@ function activate(context) {
cidrHighlight = newCidrHighlight
anyChanges = true
}
if (strictMode !== newStrictMode) {
strictMode = newStrictMode
anyChanges = true
}

return anyChanges
}
Expand Down
14 changes: 14 additions & 0 deletions package.json
Expand Up @@ -52,6 +52,11 @@
"description": "Determines if IPv6 addresses in CIDR (e.g. 192.168.0.0/24 or 2001:db8::/32) will be highlighted.",
"type": "boolean",
"default": true
},
"highlight-ip.strict": {
"description": "Determines if IPv6 addresses will be checked for RFC5952 issues.",
"type": "boolean",
"default": false
}
}
}
Expand All @@ -74,6 +79,15 @@
"light": "textLink.foreground",
"highContrast": "textLink.foreground"
}
},
{
"id": "ipaddress.networkIssue",
"description": "Color for IP address when its IPv6 format is not in strict RFC5952 compliance.",
"defaults": {
"dark": "errorForeground",
"light": "errorForeground",
"highContrast": "errorForeground"
}
}
]
},
Expand Down

0 comments on commit f715f35

Please sign in to comment.