Skip to content

Commit

Permalink
Fix multiple IPv4/IPv6 parsing bugs. Fixes #41.
Browse files Browse the repository at this point in the history
  • Loading branch information
smola committed Aug 18, 2014
1 parent a92e839 commit 1b3f7be
Show file tree
Hide file tree
Showing 4 changed files with 75 additions and 32 deletions.
49 changes: 34 additions & 15 deletions src/main/java/io/mola/galimatias/IPv4Address.java
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,8 @@
import java.net.Inet4Address;
import java.net.UnknownHostException;

import static io.mola.galimatias.URLUtils.isASCIIDigit;

public class IPv4Address extends Host {

private static final long serialVersionUID = 1L;
Expand All @@ -47,31 +49,48 @@ public static IPv4Address parseIPv4Address(final String input) throws Galimatias
if (input.isEmpty()) {
throw new GalimatiasParseException("empty input");
}
if (input.charAt(input.length() - 1) == '.') { //XXX: This case is not covered by the IPv6-mapped IPv4 case in the spec
throw new GalimatiasParseException("IPv4 address has trailing dot");
}
byte[] addr = new byte[4];
int dotsSeen = 0;
int addrIdx = 0;
int i = 0;
while (i < input.length()) {
char c = input.charAt(i);
int value = 0;
while (URLUtils.isASCIIDigit(c)) {
value = value * 10 + (c - 0x30);
i++;
c = (i >= input.length())? 0x00 : input.charAt(i);
int idx = 0;
boolean isEOF = false;
while (!isEOF) {
char c = input.charAt(idx);
Integer value = null;
if (!isASCIIDigit(c)) {
throw new GalimatiasParseException("Non-digit character in IPv4 address");
}
if (value > 255) {
throw new GalimatiasParseException("Malformed IPv4 address, bad value: " + value);
while (isASCIIDigit(c)) {
final int number = c - 0x30; // 10.3.1
if (value == null) { // 10.3.2
value = number;
} else if (value == 0) {
throw new GalimatiasParseException("IPv4 address contains a leading zero");
} else {
value = value * 10 + number;
}
idx++; // 10.3.3
isEOF = idx >= input.length();
c = (isEOF)? 0x00 : input.charAt(idx);
if (value > 255) { // 10.3.4
throw new GalimatiasParseException("Invalid value for IPv4 address");
}
}
if (dotsSeen < 3 && c != '.') {
throw new GalimatiasParseException("Malformed IPv4 address", i);
throw new GalimatiasParseException("Illegal character in IPv4 address", idx);
}
if (dotsSeen == 3 && i < input.length()) {
throw new GalimatiasParseException("IPv4 address is too long", i);
idx++;
isEOF = idx >= input.length();
c = (isEOF)? 0x00 : input.charAt(idx);
if (dotsSeen == 3 && idx < input.length()) {
throw new GalimatiasParseException("IPv4 address is too long", idx);
}
addr[addrIdx] = (byte) value;
addr[addrIdx] = (byte) (int) value;
addrIdx++;
dotsSeen++;
i++;
}
if (dotsSeen != 4) {
throw new GalimatiasParseException("Malformed IPv4 address");
Expand Down
38 changes: 21 additions & 17 deletions src/main/java/io/mola/galimatias/IPv6Address.java
Original file line number Diff line number Diff line change
Expand Up @@ -147,7 +147,7 @@ public static IPv6Address parseIPv6Address(final String ipString) throws Galimat
// Step 10: IPv4-mapped address.
while (!isEOF) {
// Step 10.1
int value = 0;
Integer value = null;

// Step 10.2
if (!isASCIIDigit(c)) {
Expand All @@ -156,41 +156,46 @@ public static IPv6Address parseIPv6Address(final String ipString) throws Galimat

// Step 10.3
while (isASCIIDigit(c)) {
value = value * 10 + (c - 0x30);
idx++;
final int number = c - 0x30; // 10.3.1
if (value == null) { // 10.3.2
value = number;
} else if (value == 0) {
throw new GalimatiasParseException("IPv4 mapped address contains a leading zero");
} else {
value = value * 10 + number;
}
idx++; // 10.3.3
isEOF = idx >= input.length;
c = (isEOF)? 0x00 : input[idx];
if (value > 255) { // 10.3.4
throw new GalimatiasParseException("Invalid value for IPv4-mapped address");
}
}

// Step 10.4
if (value > 255) {
throw new GalimatiasParseException("Invalid value for IPv4-mapped address");
}

// Step 10.5
if (dotsSeen < 3 && c != '.') {
throw new GalimatiasParseException("Illegal character in IPv4-mapped address");
}

// Step 10.6
// Step 10.5
address[piecePointer] = (short) ((address[piecePointer] << 8) + value);

// Step 10.7
if (dotsSeen == 1 || dotsSeen == 3) { //FIXME: This was 0 and 2 in the spec?
// Step 10.6
if (dotsSeen == 1 || dotsSeen == 3) {
piecePointer++;
}

// Step 10.8
// Step 10.7
idx++;
isEOF = idx >= input.length;
c = (isEOF)? 0x00 : input[idx];

// Step 10.9
// Step 10.8
if (dotsSeen == 3 && !isEOF) {
throw new GalimatiasParseException("Too long IPv4-mapped address");
}

// Step 10.10
// Step 10.9
dotsSeen++;
}
}
Expand All @@ -202,8 +207,7 @@ public static IPv6Address parseIPv6Address(final String ipString) throws Galimat
// Step 11.2
piecePointer = 7;
// Step 11.3
while (swaps != 0) { //FIXME: Spec states that piecePointer should be checked for
// != 0, but it is always non-zero if 'swaps' is non-zero.
while (piecePointer != 0 && swaps > 0) {
short swappedPiece = address[piecePointer];
address[piecePointer] = address[compressPointer + swaps - 1];
address[compressPointer + swaps - 1] = swappedPiece;
Expand All @@ -212,7 +216,7 @@ public static IPv6Address parseIPv6Address(final String ipString) throws Galimat
}
}
// Step 12
else if (piecePointer != 8) {
else if (compressPointer == null && piecePointer != 8) {
throw new GalimatiasParseException("Address too short");
}

Expand Down
10 changes: 10 additions & 0 deletions src/test/java/io/mola/galimatias/IPv4AddressTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,16 @@ public void parseAddressWithFinalDot() throws GalimatiasParseException {
IPv4Address.parseIPv4Address("1.1.1.1.");
}

@Test(expected = GalimatiasParseException.class)
public void parseWithLeadingZero1() throws GalimatiasParseException {
IPv6Address.parseIPv6Address("192.168.1.1.05");
}

@Test(expected = GalimatiasParseException.class)
public void parseWithLeadingZero2() throws GalimatiasParseException {
IPv6Address.parseIPv6Address("192.168.1.1.00");
}

@Test(expected = GalimatiasParseException.class)
public void parseTooShortAddress() throws GalimatiasParseException {
IPv4Address.parseIPv4Address("1.1.1");
Expand Down
10 changes: 10 additions & 0 deletions src/test/java/io/mola/galimatias/IPv6AddressTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -136,6 +136,16 @@ public void parseTooLongIPv4Mapped() throws GalimatiasParseException {
IPv6Address.parseIPv6Address("::192.168.1.1.5");
}

@Test(expected = GalimatiasParseException.class)
public void parseIPv4MappedWithLeadingZero1() throws GalimatiasParseException {
IPv6Address.parseIPv6Address("::192.168.1.1.05");
}

@Test(expected = GalimatiasParseException.class)
public void parseIPv4MappedWithLeadingZero2() throws GalimatiasParseException {
IPv6Address.parseIPv6Address("::192.168.1.1.00");
}

@Test(expected = GalimatiasParseException.class)
public void parseMalformedIPv4Mapped() throws GalimatiasParseException {
IPv6Address.parseIPv6Address("::192.168.1a.1");
Expand Down

0 comments on commit 1b3f7be

Please sign in to comment.