Skip to content

Commit 80d613a

Browse files
committed
feat: Add IPv6Converter new algorithm with Junit tests
1 parent 9b52ac9 commit 80d613a

File tree

2 files changed

+154
-0
lines changed

2 files changed

+154
-0
lines changed
Lines changed: 95 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,95 @@
1+
package com.thealgorithms.conversions;
2+
3+
import java.net.Inet6Address;
4+
import java.net.InetAddress;
5+
import java.net.UnknownHostException;
6+
import java.util.Arrays;
7+
8+
/**
9+
* A utility class for converting between IPv6 and IPv4 addresses.
10+
*
11+
* - Converts IPv4 to IPv6-mapped IPv6 address.
12+
* - Extracts IPv4 address from IPv6-mapped IPv6.
13+
* - Handles exceptions for invalid inputs.
14+
*
15+
* @author Hardvan
16+
*/
17+
public final class IPv6Converter {
18+
private IPv6Converter() {
19+
}
20+
21+
/**
22+
* Converts an IPv4 address (e.g., "192.0.2.128") to an IPv6-mapped IPv6 address.
23+
* Example: IPv4 "192.0.2.128" -> IPv6 "::ffff:192.0.2.128"
24+
*
25+
* @param ipv4Address The IPv4 address in string format.
26+
* @return The corresponding IPv6-mapped IPv6 address.
27+
* @throws UnknownHostException If the IPv4 address is invalid.
28+
* @throws IllegalArgumentException If the IPv6 address is not a mapped IPv4 address.
29+
*/
30+
public static String ipv4ToIpv6(String ipv4Address) throws UnknownHostException {
31+
if (ipv4Address == null || ipv4Address.isEmpty()) {
32+
throw new UnknownHostException("IPv4 address is empty.");
33+
}
34+
35+
InetAddress ipv4 = InetAddress.getByName(ipv4Address);
36+
byte[] ipv4Bytes = ipv4.getAddress();
37+
38+
// Create IPv6-mapped IPv6 address (starts with ::ffff:)
39+
byte[] ipv6Bytes = new byte[16];
40+
ipv6Bytes[10] = (byte) 0xff;
41+
ipv6Bytes[11] = (byte) 0xff;
42+
System.arraycopy(ipv4Bytes, 0, ipv6Bytes, 12, 4);
43+
44+
// Manually format to "::ffff:x.x.x.x" format
45+
StringBuilder ipv6String = new StringBuilder("::ffff:");
46+
for (int i = 12; i < 16; i++) {
47+
ipv6String.append(ipv6Bytes[i] & 0xFF);
48+
if (i < 15) {
49+
ipv6String.append('.');
50+
}
51+
}
52+
return ipv6String.toString();
53+
}
54+
55+
/**
56+
* Extracts the IPv4 address from an IPv6-mapped IPv6 address.
57+
* Example: IPv6 "::ffff:192.0.2.128" -> IPv4 "192.0.2.128"
58+
*
59+
* @param ipv6Address The IPv6 address in string format.
60+
* @return The extracted IPv4 address.
61+
* @throws UnknownHostException If the IPv6 address is invalid or not a mapped IPv4 address.
62+
*/
63+
public static String ipv6ToIpv4(String ipv6Address) throws UnknownHostException {
64+
InetAddress ipv6 = InetAddress.getByName(ipv6Address);
65+
byte[] ipv6Bytes = ipv6.getAddress();
66+
67+
// Check if the address is an IPv6-mapped IPv4 address
68+
if (isValidIpv6MappedIpv4(ipv6Bytes)) {
69+
byte[] ipv4Bytes = Arrays.copyOfRange(ipv6Bytes, 12, 16);
70+
InetAddress ipv4 = InetAddress.getByAddress(ipv4Bytes);
71+
return ipv4.getHostAddress();
72+
} else {
73+
throw new IllegalArgumentException("Not a valid IPv6-mapped IPv4 address.");
74+
}
75+
}
76+
77+
/**
78+
* Helper function to check if the given byte array represents
79+
* an IPv6-mapped IPv4 address (prefix 0:0:0:0:0:ffff).
80+
*
81+
* @param ipv6Bytes Byte array representation of the IPv6 address.
82+
* @return True if the address is IPv6-mapped IPv4, otherwise false.
83+
*/
84+
private static boolean isValidIpv6MappedIpv4(byte[] ipv6Bytes) {
85+
// IPv6-mapped IPv4 addresses are 16 bytes long, with the first 10 bytes set to 0,
86+
// followed by 0xff, 0xff, and the last 4 bytes representing the IPv4 address.
87+
if (ipv6Bytes.length != 16) return false;
88+
89+
for (int i = 0; i < 10; i++) {
90+
if (ipv6Bytes[i] != 0) return false;
91+
}
92+
93+
return ipv6Bytes[10] == (byte) 0xff && ipv6Bytes[11] == (byte) 0xff;
94+
}
95+
}
Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
package com.thealgorithms.conversions;
2+
3+
import static org.junit.jupiter.api.Assertions.assertEquals;
4+
import static org.junit.jupiter.api.Assertions.assertThrows;
5+
6+
import org.junit.jupiter.api.Test;
7+
8+
import java.net.UnknownHostException;
9+
10+
public class IPv6ConverterTest {
11+
12+
@Test
13+
public void testIpv4ToIpv6_ValidInput() throws UnknownHostException {
14+
String ipv4 = "192.0.2.128";
15+
String expectedIpv6 = "::ffff:192.0.2.128";
16+
String actualIpv6 = IPv6Converter.ipv4ToIpv6(ipv4);
17+
assertEquals(expectedIpv6, actualIpv6);
18+
}
19+
20+
@Test
21+
public void testIpv6ToIpv4_InvalidIPv6MappedAddress() {
22+
String invalidIpv6 = "2001:db8::1"; // Not an IPv6-mapped IPv4
23+
assertThrows(IllegalArgumentException.class, () -> {
24+
IPv6Converter.ipv6ToIpv4(invalidIpv6);
25+
});
26+
}
27+
28+
@Test
29+
public void testIpv4ToIpv6_InvalidIPv4Address() {
30+
String invalidIpv4 = "999.999.999.999"; // Invalid IPv4 address
31+
assertThrows(UnknownHostException.class, () -> {
32+
IPv6Converter.ipv4ToIpv6(invalidIpv4);
33+
});
34+
}
35+
36+
@Test
37+
public void testIpv6ToIpv4_InvalidFormat() {
38+
String invalidIpv6 = "invalid:ipv6::address";
39+
assertThrows(UnknownHostException.class, () -> {
40+
IPv6Converter.ipv6ToIpv4(invalidIpv6);
41+
});
42+
}
43+
44+
@Test
45+
public void testIpv4ToIpv6_EmptyString() {
46+
String emptyIpv4 = "";
47+
assertThrows(UnknownHostException.class, () -> {
48+
IPv6Converter.ipv4ToIpv6(emptyIpv4);
49+
});
50+
}
51+
52+
@Test
53+
public void testIpv6ToIpv4_EmptyString() {
54+
String emptyIpv6 = "";
55+
assertThrows(IllegalArgumentException.class, () -> {
56+
IPv6Converter.ipv6ToIpv4(emptyIpv6);
57+
});
58+
}
59+
}

0 commit comments

Comments
 (0)