Skip to content

Commit d751117

Browse files
authored
Merge pull request #2041 from gchq/octal-ip-addresses
Addresses bug report #2008 Added explicit support for octal IP addresses. Changed approach to IPv4 regex to be string manipulation generated. Added some unit tests for IP address parsing - probably not full coverage. Added lookahead and lookbehind tricks to resolve warned issue that 1.2.3.256 would still be extracted as 1.2.3.25. Now only accepts valid IP addresses. Warning replaced with clause about infinite length dotted decimal forms.
2 parents a55075f + 288cd8f commit d751117

File tree

3 files changed

+150
-2
lines changed

3 files changed

+150
-2
lines changed

src/core/operations/ExtractIPAddresses.mjs

Lines changed: 16 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ class ExtractIPAddresses extends Operation {
2121

2222
this.name = "Extract IP addresses";
2323
this.module = "Regex";
24-
this.description = "Extracts all IPv4 and IPv6 addresses.<br><br>Warning: Given a string <code>710.65.0.456</code>, this will match <code>10.65.0.45</code> so always check the original input!";
24+
this.description = "Extracts all IPv4 and IPv6 addresses.<br><br>Warning: Given a string <code>1.2.3.4.5.6.7.8</code>, this will match <code>1.2.3.4 and 5.6.7.8</code> so always check the original input!";
2525
this.inputType = "string";
2626
this.outputType = "string";
2727
this.args = [
@@ -65,7 +65,21 @@ class ExtractIPAddresses extends Operation {
6565
*/
6666
run(input, args) {
6767
const [includeIpv4, includeIpv6, removeLocal, displayTotal, sort, unique] = args,
68-
ipv4 = "(?:(?:\\d|[01]?\\d\\d|2[0-4]\\d|25[0-5])\\.){3}(?:25[0-5]|2[0-4]\\d|[01]?\\d\\d|\\d)(?:\\/\\d{1,2})?",
68+
69+
// IPv4 decimal groups can have values 0 to 255. To construct a regex the following sub-regex is reused:
70+
ipv4DecimalByte = "(?:25[0-5]|2[0-4]\\d|1?[0-9]\\d|\\d)",
71+
ipv4OctalByte = "(?:0[1-3]?[0-7]{1,2})",
72+
73+
// Look behind and ahead will be used to exclude matches with additional decimal digits left and right of IP address
74+
lookBehind = "(?<!\\d)",
75+
lookAhead = "(?!\\d)",
76+
77+
// Each variant requires exactly 4 groups with literal . between.
78+
ipv4Decimal = "(?:" + lookBehind + ipv4DecimalByte + "\\.){3}" + "(?:" + ipv4DecimalByte + lookAhead + ")",
79+
ipv4Octal = "(?:" + lookBehind + ipv4OctalByte + "\\.){3}" + "(?:" + ipv4OctalByte + lookAhead + ")",
80+
81+
// Then we allow IPv4 addresses to be expressed either entirely in decimal or entirely in Octal
82+
ipv4 = "(?:" + ipv4Decimal + "|" + ipv4Octal + ")",
6983
ipv6 = "((?=.*::)(?!.*::.+::)(::)?([\\dA-F]{1,4}:(:|\\b)|){5}|([\\dA-F]{1,4}:){6})(([\\dA-F]{1,4}((?!\\3)::|:\\b|(?![\\dA-F])))|(?!\\2\\3)){2}";
7084
let ips = "";
7185

tests/operations/index.mjs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,7 @@ import "./tests/ELFInfo.mjs";
6565
import "./tests/Enigma.mjs";
6666
import "./tests/ExtractEmailAddresses.mjs";
6767
import "./tests/ExtractHashes.mjs";
68+
import "./tests/ExtractIPAddresses.mjs";
6869
import "./tests/Float.mjs";
6970
import "./tests/FileTree.mjs";
7071
import "./tests/FletcherChecksum.mjs";
Lines changed: 133 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,133 @@
1+
/**
2+
* ExtractIPAddresses tests.
3+
*
4+
* @author gchqdev365 [[email protected]]
5+
* @copyright Crown Copyright 2025
6+
* @license Apache-2.0
7+
*/
8+
import TestRegister from "../../lib/TestRegister.mjs";
9+
10+
TestRegister.addTests([
11+
{
12+
name: "ExtractIPAddress All Zeros",
13+
input: "0.0.0.0",
14+
expectedOutput: "0.0.0.0",
15+
recipeConfig: [
16+
{
17+
"op": "Extract IP addresses",
18+
"args": [true, true, false, false, false, false]
19+
},
20+
],
21+
},
22+
{
23+
name: "ExtractIPAddress All 10s",
24+
input: "10.10.10.10",
25+
expectedOutput: "10.10.10.10",
26+
recipeConfig: [
27+
{
28+
"op": "Extract IP addresses",
29+
"args": [true, true, false, false, false, false]
30+
},
31+
],
32+
},
33+
{
34+
name: "ExtractIPAddress All 10s",
35+
input: "100.100.100.100",
36+
expectedOutput: "100.100.100.100",
37+
recipeConfig: [
38+
{
39+
"op": "Extract IP addresses",
40+
"args": [true, true, false, false, false, false]
41+
},
42+
],
43+
},
44+
{
45+
name: "ExtractIPAddress 255s",
46+
input: "255.255.255.255",
47+
expectedOutput: "255.255.255.255",
48+
recipeConfig: [
49+
{
50+
"op": "Extract IP addresses",
51+
"args": [true, true, false, false, false, false]
52+
},
53+
],
54+
},
55+
{
56+
name: "ExtractIPAddress double digits",
57+
input: "10.10.10.10 25.25.25.25 99.99.99.99",
58+
expectedOutput: "10.10.10.10\n25.25.25.25\n99.99.99.99",
59+
recipeConfig: [
60+
{
61+
"op": "Extract IP addresses",
62+
"args": [true, true, false, false, false, false]
63+
},
64+
],
65+
},
66+
{
67+
name: "ExtractIPAddress 256 in middle",
68+
input: "255.256.255.255 255.255.256.255",
69+
expectedOutput: "",
70+
recipeConfig: [
71+
{
72+
"op": "Extract IP addresses",
73+
"args": [true, true, false, false, false, false]
74+
},
75+
],
76+
},
77+
{
78+
name: "ExtractIPAddress 256 at each end",
79+
input: "256.255.255.255 255.255.255.256",
80+
expectedOutput: "",
81+
recipeConfig: [
82+
{
83+
"op": "Extract IP addresses",
84+
"args": [true, true, false, false, false, false]
85+
},
86+
],
87+
},
88+
{
89+
name: "ExtractIPAddress silly example",
90+
input: "710.65.0.456",
91+
expectedOutput: "",
92+
recipeConfig: [
93+
{
94+
"op": "Extract IP addresses",
95+
"args": [true, true, false, false, false, false]
96+
},
97+
],
98+
},
99+
{
100+
name: "ExtractIPAddress longer dotted decimal",
101+
input: "1.2.3.4.5.6.7.8",
102+
expectedOutput: "1.2.3.4\n5.6.7.8",
103+
recipeConfig: [
104+
{
105+
"op": "Extract IP addresses",
106+
"args": [true, true, false, false, false, false]
107+
},
108+
],
109+
},
110+
{
111+
name: "ExtractIPAddress octal valid",
112+
input: "01.01.01.01 0123.0123.0123.0123 0377.0377.0377.0377",
113+
expectedOutput: "01.01.01.01\n0123.0123.0123.0123\n0377.0377.0377.0377",
114+
recipeConfig: [
115+
{
116+
"op": "Extract IP addresses",
117+
"args": [true, true, false, false, false, false]
118+
},
119+
],
120+
},
121+
{
122+
name: "ExtractIPAddress octal invalid",
123+
input: "0378.01.01.01 03.0377.2.3",
124+
expectedOutput: "",
125+
recipeConfig: [
126+
{
127+
"op": "Extract IP addresses",
128+
"args": [true, true, false, false, false, false]
129+
},
130+
],
131+
},
132+
]);
133+

0 commit comments

Comments
 (0)