Commit 723e71a0 authored by Karsten Loesing's avatar Karsten Loesing
Browse files

Don't require searches by IPv6 address to start with [.

Implements #16552.
parent 6b674fe7
# Changes in version 4.0-x.x.x - 2017-xx-xx
* Medium changes
- Accept searches by IPv6 addresses even without leading or
enclosing square brackets.
# Changes in version 3.2-1.1.0 - 2017-01-27
* Major changes
......
......@@ -261,7 +261,8 @@ public class RequestHandler {
} else {
List<String> addresses = entry.getAddresses();
for (String address : addresses) {
if (address.startsWith(searchTerm.toLowerCase())) {
if (address.startsWith(searchTerm.toLowerCase())
|| address.startsWith("[" + searchTerm.toLowerCase())) {
/* Address matches. */
lineMatches = true;
break;
......
......@@ -75,6 +75,12 @@ public class ResourceServlet extends HttpServlet {
new HashSet<>(Arrays.asList(("search,fingerprint,order,limit,"
+ "offset,fields").split(",")));
private static String ipv6AddressPatternString =
"^\\[?[0-9a-fA-F:\\.]{1,39}\\]?$";
private static Pattern ipv6AddressPattern =
Pattern.compile(ipv6AddressPatternString);
/** Handles the HTTP GET request in the wrapped <code>request</code> by
* writing an HTTP GET response to the likewise <code>response</code>,
* both of which are wrapped to facilitate testing. */
......@@ -150,13 +156,17 @@ public class ResourceServlet extends HttpServlet {
}
List<String> unqualifiedSearchTerms = new ArrayList<>();
for (String searchTerm : searchTerms) {
if (searchTerm.contains(":") && !searchTerm.startsWith("[")) {
if (searchTerm.contains(":")) {
String[] parts = searchTerm.split(":", 2);
String parameterKey = parts[0];
if (!knownParameters.contains(parameterKey)
|| illegalSearchQualifiers.contains(parameterKey)) {
response.sendError(HttpServletResponse.SC_BAD_REQUEST);
return;
if (ipv6AddressPattern.matcher(parameterKey).matches()) {
unqualifiedSearchTerms.add(searchTerm);
} else {
response.sendError(HttpServletResponse.SC_BAD_REQUEST);
return;
}
}
if (!parameterMap.containsKey(parameterKey)) {
String parameterValue = parts[1];
......@@ -369,7 +379,7 @@ public class ResourceServlet extends HttpServlet {
Pattern.compile("^\\$?[0-9a-fA-F]{1,40}$|" /* Hex fingerprint. */
+ "^[0-9a-zA-Z+/]{1,27}$|" /* Base64 fingerprint. */
+ "^[0-9a-zA-Z\\.]{1,19}$|" /* Nickname or IPv4 address. */
+ "^\\[[0-9a-fA-F:\\.]{1,39}\\]?$|" /* IPv6 address. */
+ ipv6AddressPatternString + "|" /* IPv6 address. */
+ "^[a-zA-Z_]+:\\p{Graph}+$" /* Qualified search term. */);
protected static String[] parseSearchParameters(String queryString) {
......
......@@ -102,9 +102,9 @@ public class ResponseBuilder {
return this.charsWritten;
}
private static final String PROTOCOL_VERSION = "3.2";
private static final String PROTOCOL_VERSION = "4.0";
private static final String NEXT_MAJOR_VERSION_SCHEDULED = "2017-02-27";
private static final String NEXT_MAJOR_VERSION_SCHEDULED = null;
private void writeRelays(List<SummaryDocument> relays, PrintWriter pw) {
this.write(pw, "{\"version\":\"%s\",\n", PROTOCOL_VERSION);
......
......@@ -346,10 +346,9 @@ characters of a space-separated fingerprint on November 15, 2015.</li>
<li><strong>3.2</strong>: Extended order parameter to "first_seen" and
added response meta data fields "relays_skipped", "relays_truncated",
"bridges_skipped", and "bridges_truncated" on January 27, 2017.</li>
<li><strong>4.0</strong>: (scheduled, but not deployed yet!): Extend
search parameter to not require leading or enclosing square brackets
around IPv6 addresses anymore, to be deployed by February 27,
2017.</li>
<li><strong>4.0</strong>: Extended search parameter to not require
leading or enclosing square brackets around IPv6 addresses anymore on
February 28, 2017.</li>
</ul>
......@@ -456,7 +455,8 @@ Return only (1) relays with the parameter value matching (part of a)
nickname, (possibly $-prefixed) beginning of a hex-encoded fingerprint,
any 4 hex characters of a space-separated fingerprint, beginning of a
base64-encoded fingerprint without trailing equal signs, or beginning of
an IP address, (2) bridges with (part of a) nickname or (possibly
an IP address (possibly enclosed in square brackets in case of IPv6),
(2) bridges with (part of a) nickname or (possibly
$-prefixed) beginning of a hashed hex-encoded fingerprint, and (3) relays
and/or bridges matching a given qualified search term.
Searches by relay IP address include all known addresses used for onion
......
......@@ -706,6 +706,34 @@ public class ResourceServletTest {
"/summary?search=[2001:4f8:3:2e::]", 0, null, 0, null);
}
@Test()
public void testSearchIpv6Slash64NoBrackets() {
this.assertSummaryDocument(
"/summary?search=2001:4f8:3:2e::", 1,
new String[] { "Ferrari458" }, 0, null);
}
@Test()
public void testSearchIpv6Slash8Colon() {
this.assertSummaryDocument(
"/summary?search=[2001:", 1,
new String[] { "Ferrari458" }, 0, null);
}
@Test()
public void testSearchIpv6Slash8NoColon() {
this.assertSummaryDocument(
"/summary?search=[2001", 1,
new String[] { "Ferrari458" }, 0, null);
}
@Test()
public void testSearchIpv6Slash8NoColonNoBrackets() {
this.assertSummaryDocument(
"/summary?search=2001", 1,
new String[] { "Ferrari458" }, 0, null);
}
@Test()
public void testSearchIpv6Uncompressed() {
this.assertSummaryDocument(
......@@ -887,6 +915,13 @@ public class ResourceServletTest {
this.assertErrorStatusCode("/summary?search=limit:1", 400);
}
@Test()
public void testSearchDeadBeef() {
/* This does not return 400 Bad Request, even though "dead" is not a valid
* search term qualifier, because this could be the start of an IPv6 address
* without leading bracket. */
this.assertSummaryDocument("/summary?search=dead:beef", 0, null, 0, null);
}
@Test()
public void testSearchEmailAddress() {
......
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment