Skip to content

Commit

Permalink
be more forgiving of IPv4-mapped addresses in json (#1404)
Browse files Browse the repository at this point in the history
Currently Zipkin checks that all IPv6 addresses are 16 bytes long.
However, if an IPv4-mapped addresses such as `::ffff:192.168.1.128` is
given then InetAddress.getByName will return an Inet4Address and the
assertion will fail.

Instead accept the address, but store it as ipv4 to maintain all
existing assertions.  This absolves clients of reconciling the nuances
of IPv4-mapped addresses in their environments (for example, in node
`net.isIPv6('::ffff:192.168.1.128')` is true) with Java's.
  • Loading branch information
cburroughs authored and adriancole committed Nov 15, 2016
1 parent 5905ba5 commit 43a0396
Show file tree
Hide file tree
Showing 2 changed files with 45 additions and 7 deletions.
26 changes: 19 additions & 7 deletions zipkin/src/main/java/zipkin/internal/JsonCodec.java
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.InetAddress;
import java.net.Inet6Address;
import java.nio.ByteBuffer;
import java.util.Collections;
Expand Down Expand Up @@ -73,16 +74,18 @@ public Endpoint fromJson(JsonReader reader) throws IOException {
if (nextName.equals("serviceName")) {
result.serviceName(reader.nextString());
} else if (nextName.equals("ipv4")) {
String[] ipv4String = reader.nextString().split("\\.", 5);
int ipv4 = 0;
for (String part : ipv4String) {
ipv4 = ipv4 << 8 | (Integer.parseInt(part) & 0xff);
}
result.ipv4(ipv4);
result.ipv4(parseIPv4Address(reader.nextString()));
} else if (nextName.equals("ipv6")) {
String input = reader.nextString();
// Shouldn't hit DNS, because it's an IP string literal.
result.ipv6(Inet6Address.getByName(input).getAddress());
InetAddress addr = Inet6Address.getByName(input);
// InetAddress.getByName returns an Inet4Address for
// IPv4-mapped IPv6 addresses such as ::ffff:192.0.2.128
if (addr instanceof Inet6Address) {
result.ipv6(addr.getAddress());
} else {
result.ipv4(parseIPv4Address(addr.getHostAddress()));
}
} else if (nextName.equals("port")) {
result.port(reader.nextInt());
} else {
Expand All @@ -93,6 +96,15 @@ public Endpoint fromJson(JsonReader reader) throws IOException {
return result.build();
}

private int parseIPv4Address(String input) {
String[] ipv4String = input.split("\\.", 5);
int ipv4 = 0;
for (String part : ipv4String) {
ipv4 = ipv4 << 8 | (Integer.parseInt(part) & 0xff);
}
return ipv4;
}

@Override public int sizeInBytes(Endpoint value) {
int sizeInBytes = 0;
sizeInBytes += asciiSizeInBytes("{\"serviceName\":\"");
Expand Down
26 changes: 26 additions & 0 deletions zipkin/src/test/java/zipkin/internal/JsonCodecTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -292,6 +292,32 @@ public void endpointHighPort() {
.isEqualTo(span);
}

@Test
public void mappedIPv6toIPv4() {
String json = "{\n"
+ " \"traceId\": \"6b221d5bc9e6496c\",\n"
+ " \"name\": \"get-traces\",\n"
+ " \"id\": \"6b221d5bc9e6496c\",\n"
+ " \"binaryAnnotations\": [\n"
+ " {\n"
+ " \"key\": \"foo\",\n"
+ " \"value\": \"bar\",\n"
+ " \"endpoint\": {\n"
+ " \"serviceName\": \"service\",\n"
+ " \"port\": 65535,\n"
+ " \"ipv6\": \"::ffff:192.0.2.128\"\n"
+ " }\n"
+ " }\n"
+ " ]\n"
+ "}";

Span span = Codec.JSON.readSpan(json.getBytes(UTF_8));
assertThat(span.binaryAnnotations.get(0).endpoint.ipv6)
.isNull();
assertThat(span.binaryAnnotations.get(0).endpoint.ipv4)
.isEqualTo((192 << 24) | (0 << 16) | (2 << 8) | 128); // 192.0.2.128
}

@Test
public void sizeInBytes_span() throws IOException {
Span span = TestObjects.LOTS_OF_SPANS[0];
Expand Down

0 comments on commit 43a0396

Please sign in to comment.