Skip to content

Commit 5ac7a4b

Browse files
committed
Fix IPv4-mapped address support
1 parent b6637aa commit 5ac7a4b

File tree

4 files changed

+40
-3
lines changed

4 files changed

+40
-3
lines changed
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
import * as t from "tap";
2+
import mapIPv4ToIPv6 from "./mapIPv4ToIPv6";
3+
4+
t.test("it works", async (t) => {
5+
t.equal(mapIPv4ToIPv6("127.0.0.0"), "::ffff:127.0.0.0/128");
6+
t.equal(mapIPv4ToIPv6("127.0.0.0/8"), "::ffff:127.0.0.0/104");
7+
t.equal(mapIPv4ToIPv6("10.0.0.0"), "::ffff:10.0.0.0/128");
8+
t.equal(mapIPv4ToIPv6("10.0.0.0/8"), "::ffff:10.0.0.0/104");
9+
t.equal(mapIPv4ToIPv6("10.0.0.1"), "::ffff:10.0.0.1/128");
10+
t.equal(mapIPv4ToIPv6("10.0.0.1/8"), "::ffff:10.0.0.1/104");
11+
t.equal(mapIPv4ToIPv6("192.168.0.0/16"), "::ffff:192.168.0.0/112");
12+
t.equal(mapIPv4ToIPv6("172.16.0.0/12"), "::ffff:172.16.0.0/108");
13+
});

library/helpers/mapIPv4ToIPv6.ts

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
/**
2+
* Maps an IPv4 address to an IPv6 address.
3+
* e.g. 127.0.0.1/8 -> ::ffff:127
4+
*/
5+
export default function mapIPv4ToIPv6(ip: string): string {
6+
if (!ip.includes("/")) {
7+
// No CIDR suffix, assume /32
8+
return `::ffff:${ip}/128`;
9+
}
10+
11+
const parts = ip.split("/");
12+
const suffix = Number.parseInt(parts[1], 10);
13+
return `::ffff:${parts[0]}/${suffix + 96}`;
14+
}

library/vulnerabilities/ssrf/containsPrivateIPAddress.test.ts

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,9 @@ const publicIPs = [
3131
"fb00::",
3232
"fbff:ffff:ffff:ffff:ffff:ffff:ffff:ffff",
3333
"fec0::",
34+
"::ffff:1.2.3.4",
35+
"::ffff:172.1.2.3",
36+
"::ffff:192.145.0.0",
3437
];
3538

3639
const privateIPs = [
@@ -139,6 +142,10 @@ const privateIPs = [
139142
"::1",
140143
"::ffff:0.0.0.0",
141144
"::ffff:127.0.0.1",
145+
"::ffff:127.0.0.2",
146+
"::ffff:10.0.0.1",
147+
"::ffff:172.16.1.2",
148+
"::ffff:192.168.2.2",
142149
"fe80::",
143150
"fe80::1",
144151
"fe80::abc:1",

library/vulnerabilities/ssrf/isPrivateIP.ts

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import { IPMatcher } from "../../helpers/ip-matcher/IPMatcher";
2+
import mapIPv4ToIPv6 from "../../helpers/mapIPv4ToIPv6";
23

34
const PRIVATE_IP_RANGES = [
45
"0.0.0.0/8", // "This" network (RFC 1122)
@@ -27,12 +28,14 @@ const PRIVATE_IPV6_RANGES = [
2728
"::1/128", // Loopback address (RFC 4291)
2829
"fc00::/7", // Unique local address (ULA) (RFC 4193)
2930
"fe80::/10", // Link-local address (LLA) (RFC 4291)
30-
"::ffff:127.0.0.1/128", // IPv4-mapped address (RFC 4291)
31-
"::ffff:0:0",
3231
"100::/64", // Discard prefix (RFC 6666)
3332
"2001:db8::/32", // Documentation prefix (RFC 3849)
3433
"3fff::/20", // Documentation prefix (RFC 9637)
35-
];
34+
"::ffff:0:0",
35+
].concat(
36+
// Add the IPv4-mapped IPv6 addresses
37+
PRIVATE_IP_RANGES.map(mapIPv4ToIPv6)
38+
);
3639

3740
const privateIp = new IPMatcher();
3841

0 commit comments

Comments
 (0)