Skip to content

Commit fcae00a

Browse files
authored
Merge pull request #44 from tls-attacker/fix-ipv6-parsing-issue-10
Fix IPv6 parsing in ScanTarget (#10)
2 parents 1ec8f34 + 30d954f commit fcae00a

File tree

2 files changed

+200
-7
lines changed

2 files changed

+200
-7
lines changed

src/main/java/de/rub/nds/crawler/data/ScanTarget.java

Lines changed: 38 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -53,13 +53,44 @@ public static Pair<ScanTarget, JobStatus> fromTargetString(
5353
System.out.println(targetString);
5454
}
5555

56-
// check if targetString contains port (e.g. "www.example.com:8080")
57-
// FIXME I guess this breaks any IPv6 parsing
58-
if (targetString.contains(":")) {
59-
int port = Integer.parseInt(targetString.split(":")[1]);
60-
targetString = targetString.split(":")[0];
61-
if (port > 1 && port < 65535) {
62-
target.setPort(port);
56+
// check if targetString contains port (e.g. "www.example.com:8080" or "[2001:db8::1]:8080")
57+
// Handle IPv6 addresses with ports (enclosed in brackets)
58+
if (targetString.startsWith("[") && targetString.contains("]:")) {
59+
int bracketEnd = targetString.indexOf("]:");
60+
String ipv6Address = targetString.substring(1, bracketEnd);
61+
String portString = targetString.substring(bracketEnd + 2);
62+
try {
63+
int port = Integer.parseInt(portString);
64+
if (port > 1 && port < 65535) {
65+
target.setPort(port);
66+
} else {
67+
target.setPort(defaultPort);
68+
}
69+
} catch (NumberFormatException e) {
70+
LOGGER.warn("Invalid port number: {}", portString);
71+
target.setPort(defaultPort);
72+
}
73+
targetString = ipv6Address; // Always extract the IPv6 address
74+
} else if (targetString.contains(":")) {
75+
// Check if it's an IPv6 address without port or IPv4/hostname with port
76+
String[] parts = targetString.split(":");
77+
if (parts.length == 2 && !targetString.contains("::")) {
78+
// Likely IPv4 or hostname with port
79+
try {
80+
int port = Integer.parseInt(parts[1]);
81+
if (port > 1 && port < 65535) {
82+
target.setPort(port);
83+
} else {
84+
target.setPort(defaultPort);
85+
}
86+
targetString = parts[0]; // Always extract the address part
87+
} catch (NumberFormatException e) {
88+
// Not a valid port, treat the whole string as address
89+
target.setPort(defaultPort);
90+
}
91+
} else {
92+
// Multiple colons or "::" - likely an IPv6 address without port
93+
target.setPort(defaultPort);
6394
}
6495
} else {
6596
target.setPort(defaultPort);
Lines changed: 162 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,162 @@
1+
/*
2+
* TLS-Crawler - A TLS scanning tool to perform large scale scans with the TLS-Scanner
3+
*
4+
* Copyright 2018-2022 Ruhr University Bochum, Paderborn University, and Hackmanit GmbH
5+
*
6+
* Licensed under Apache License, Version 2.0
7+
* http://www.apache.org/licenses/LICENSE-2.0.txt
8+
*/
9+
package de.rub.nds.crawler.data;
10+
11+
import static org.junit.jupiter.api.Assertions.*;
12+
13+
import de.rub.nds.crawler.constant.JobStatus;
14+
import org.apache.commons.lang3.tuple.Pair;
15+
import org.junit.jupiter.api.Test;
16+
17+
public class ScanTargetTest {
18+
19+
@Test
20+
public void testIPv4WithPort() {
21+
Pair<ScanTarget, JobStatus> result =
22+
ScanTarget.fromTargetString("192.168.1.1:8080", 443, null);
23+
assertEquals(JobStatus.TO_BE_EXECUTED, result.getRight());
24+
assertEquals("192.168.1.1", result.getLeft().getIp());
25+
assertEquals(8080, result.getLeft().getPort());
26+
assertNull(result.getLeft().getHostname());
27+
}
28+
29+
@Test
30+
public void testIPv4WithoutPort() {
31+
Pair<ScanTarget, JobStatus> result = ScanTarget.fromTargetString("192.168.1.1", 443, null);
32+
assertEquals(JobStatus.TO_BE_EXECUTED, result.getRight());
33+
assertEquals("192.168.1.1", result.getLeft().getIp());
34+
assertEquals(443, result.getLeft().getPort());
35+
assertNull(result.getLeft().getHostname());
36+
}
37+
38+
@Test
39+
public void testIPv6WithPort() {
40+
Pair<ScanTarget, JobStatus> result =
41+
ScanTarget.fromTargetString("[2001:db8::1]:8080", 443, null);
42+
assertEquals(JobStatus.TO_BE_EXECUTED, result.getRight());
43+
assertEquals("2001:db8::1", result.getLeft().getIp());
44+
assertEquals(8080, result.getLeft().getPort());
45+
assertNull(result.getLeft().getHostname());
46+
}
47+
48+
@Test
49+
public void testIPv6WithoutPort() {
50+
Pair<ScanTarget, JobStatus> result = ScanTarget.fromTargetString("2001:db8::1", 443, null);
51+
assertEquals(JobStatus.TO_BE_EXECUTED, result.getRight());
52+
assertEquals("2001:db8::1", result.getLeft().getIp());
53+
assertEquals(443, result.getLeft().getPort());
54+
assertNull(result.getLeft().getHostname());
55+
}
56+
57+
@Test
58+
public void testIPv6FullAddressWithPort() {
59+
Pair<ScanTarget, JobStatus> result =
60+
ScanTarget.fromTargetString(
61+
"[2001:0db8:85a3:0000:0000:8a2e:0370:7334]:8443", 443, null);
62+
assertEquals(JobStatus.TO_BE_EXECUTED, result.getRight());
63+
assertEquals("2001:0db8:85a3:0000:0000:8a2e:0370:7334", result.getLeft().getIp());
64+
assertEquals(8443, result.getLeft().getPort());
65+
assertNull(result.getLeft().getHostname());
66+
}
67+
68+
@Test
69+
public void testIPv6CompressedAddress() {
70+
Pair<ScanTarget, JobStatus> result = ScanTarget.fromTargetString("::1", 443, null);
71+
assertEquals(JobStatus.TO_BE_EXECUTED, result.getRight());
72+
assertEquals("::1", result.getLeft().getIp());
73+
assertEquals(443, result.getLeft().getPort());
74+
assertNull(result.getLeft().getHostname());
75+
}
76+
77+
@Test
78+
public void testHostnameWithPort() {
79+
Pair<ScanTarget, JobStatus> result =
80+
ScanTarget.fromTargetString("example.com:8080", 443, null);
81+
assertEquals(JobStatus.TO_BE_EXECUTED, result.getRight());
82+
assertEquals("example.com", result.getLeft().getHostname());
83+
assertEquals(8080, result.getLeft().getPort());
84+
// IP will be resolved by DNS lookup, so we can't test the exact value
85+
assertNotNull(result.getLeft().getIp());
86+
}
87+
88+
@Test
89+
public void testHostnameWithoutPort() {
90+
Pair<ScanTarget, JobStatus> result = ScanTarget.fromTargetString("example.com", 443, null);
91+
assertEquals(JobStatus.TO_BE_EXECUTED, result.getRight());
92+
assertEquals("example.com", result.getLeft().getHostname());
93+
assertEquals(443, result.getLeft().getPort());
94+
assertNotNull(result.getLeft().getIp());
95+
}
96+
97+
@Test
98+
public void testInvalidPortRangeHigh() {
99+
Pair<ScanTarget, JobStatus> result =
100+
ScanTarget.fromTargetString("192.168.1.1:70000", 443, null);
101+
assertEquals(JobStatus.TO_BE_EXECUTED, result.getRight());
102+
assertEquals("192.168.1.1", result.getLeft().getIp());
103+
assertEquals(443, result.getLeft().getPort()); // Should use default port
104+
}
105+
106+
@Test
107+
public void testInvalidPortRangeLow() {
108+
Pair<ScanTarget, JobStatus> result =
109+
ScanTarget.fromTargetString("192.168.1.1:0", 443, null);
110+
assertEquals(JobStatus.TO_BE_EXECUTED, result.getRight());
111+
assertEquals("192.168.1.1", result.getLeft().getIp());
112+
assertEquals(443, result.getLeft().getPort()); // Should use default port
113+
}
114+
115+
@Test
116+
public void testInvalidPortFormat() {
117+
Pair<ScanTarget, JobStatus> result =
118+
ScanTarget.fromTargetString("[2001:db8::1]:abc", 443, null);
119+
assertEquals(JobStatus.TO_BE_EXECUTED, result.getRight());
120+
assertEquals("2001:db8::1", result.getLeft().getIp());
121+
assertEquals(443, result.getLeft().getPort()); // Should use default port
122+
}
123+
124+
@Test
125+
public void testTrancoRankWithIPv4() {
126+
Pair<ScanTarget, JobStatus> result =
127+
ScanTarget.fromTargetString("100,192.168.1.1:8080", 443, null);
128+
assertEquals(JobStatus.TO_BE_EXECUTED, result.getRight());
129+
assertEquals("192.168.1.1", result.getLeft().getIp());
130+
assertEquals(8080, result.getLeft().getPort());
131+
assertEquals(100, result.getLeft().getTrancoRank());
132+
}
133+
134+
@Test
135+
public void testTrancoRankWithIPv6() {
136+
Pair<ScanTarget, JobStatus> result =
137+
ScanTarget.fromTargetString("200,[2001:db8::1]:8080", 443, null);
138+
assertEquals(JobStatus.TO_BE_EXECUTED, result.getRight());
139+
assertEquals("2001:db8::1", result.getLeft().getIp());
140+
assertEquals(8080, result.getLeft().getPort());
141+
assertEquals(200, result.getLeft().getTrancoRank());
142+
}
143+
144+
@Test
145+
public void testUnknownHost() {
146+
Pair<ScanTarget, JobStatus> result =
147+
ScanTarget.fromTargetString("this-host-should-not-exist-12345.com", 443, null);
148+
assertEquals(JobStatus.UNRESOLVABLE, result.getRight());
149+
assertEquals("this-host-should-not-exist-12345.com", result.getLeft().getHostname());
150+
assertNull(result.getLeft().getIp());
151+
}
152+
153+
@Test
154+
public void testMalformedIPv6Bracket() {
155+
// Missing closing bracket - should result in UNRESOLVABLE
156+
Pair<ScanTarget, JobStatus> result =
157+
ScanTarget.fromTargetString("[2001:db8::1:8080", 443, null);
158+
assertEquals(JobStatus.UNRESOLVABLE, result.getRight());
159+
// Should use default port
160+
assertEquals(443, result.getLeft().getPort());
161+
}
162+
}

0 commit comments

Comments
 (0)