package net.tomp2p.peers; import java.net.Inet4Address; import java.net.Inet6Address; import java.net.InetAddress; import java.net.UnknownHostException; public abstract class IP { public static class IPv4 extends IP { private final int bits; private IPv4(final int bits) { this.bits = bits; } /** * 192.168.1.2 with netmask /24 results in 192.168.1.0 */ public IPv4 maskWithNetworkMask(final int networkMask) { if (networkMask == 32) { return this; } else if(networkMask == 0) { return new IPv4(0); } else { final int mask = (0xFFFFFFFF << (32 - networkMask)); return new IPv4(bits & mask); } } /** * 192.168.1.2 with netmask /24 results in 0.0.0.2 */ public IPv4 maskWithNetworkMaskInv(final int networkMask) { if (networkMask == 0) { return this; } else { return new IPv4(bits & (0xFFFFFFFF >>> networkMask)); } } public IPv4 set(final IPv4 maskedAddress) { final int newBits = bits | maskedAddress.bits; return new IPv4(newBits); } public InetAddress toInetAddress() { final byte[] ip = new byte[4]; ip[0] = (byte) (bits >>> 24); ip[1] = (byte) (bits >>> 16); ip[2] = (byte) (bits >>> 8); ip[3] = (byte) (bits); try { return Inet4Address.getByAddress(ip); } catch (UnknownHostException e) { //we know the size, so this should not throw an exception e.printStackTrace(); return null; } } public int toInt() { return bits; } @Override public boolean equals(Object obj) { if (this == obj) { return true; } if (!(obj instanceof IPv4)) { return false; } final IPv4 o = (IPv4) obj; return bits == o.bits; } @Override public int hashCode() { return bits; } @Override public String toString() { final StringBuilder sb = new StringBuilder("/"); sb.append((bits >>> 24) & 0xff); sb.append('.'); sb.append((bits >>> 16) & 0xff); sb.append('.'); sb.append((bits >>> 8) & 0xff ); sb.append('.'); sb.append(bits & 0xff); return sb.toString(); } } public static class IPv6 extends IP { private final long highBits; private final long lowBits; private IPv6(final long highBits, final long lowBits) { this.highBits = highBits; this.lowBits = lowBits; } public IPv6 maskWithNetworkMask(final int networkMask) { if (networkMask == 128) { return this; } else if (networkMask == 64) { return new IPv6(highBits, 0); } else if (networkMask > 64) { final int remainingPrefixLength = networkMask - 64; return new IPv6(highBits, lowBits & (0xFFFFFFFFFFFFFFFFL << (64 - remainingPrefixLength))); } else { return new IPv6(highBits & (0xFFFFFFFFFFFFFFFFL << (64 - networkMask)), 0); } } public InetAddress toInetAddress() { final byte[] ip = new byte[16]; ip[0] = (byte) (highBits >>> 56); ip[1] = (byte) (highBits >>> 48); ip[2] = (byte) (highBits >>> 40); ip[3] = (byte) (highBits >>> 32); ip[4] = (byte) (highBits >>> 24); ip[5] = (byte) (highBits >>> 16); ip[6] = (byte) (highBits >>> 8); ip[7] = (byte) (highBits); ip[8] = (byte) (lowBits >>> 56); ip[9] = (byte) (lowBits >>> 48); ip[10] = (byte) (lowBits >>> 40); ip[11] = (byte) (lowBits >>> 32); ip[12] = (byte) (lowBits >>> 24); ip[13] = (byte) (lowBits >>> 16); ip[14] = (byte) (lowBits >>> 8); ip[15] = (byte) (lowBits); try { return Inet6Address.getByAddress(ip); } catch (UnknownHostException e) { //we know the size, so this should not throw an exception e.printStackTrace(); return null; } } public long toLongHi() { return highBits; } public long toLongLo() { return lowBits; } @Override public boolean equals(Object obj) { if (this == obj) { return true; } if (!(obj instanceof IPv6)) { return false; } final IPv6 o = (IPv6) obj; return highBits == o.highBits && lowBits == o.lowBits; } @Override public int hashCode() { return (int)((highBits^(highBits>>>32)) ^ (lowBits^(lowBits>>>32))); } @Override public String toString() { final StringBuilder sb = new StringBuilder("/"); sb.append(String.format("%04X ", (short) (highBits >>> 48))); sb.append(':'); sb.append(String.format("%04X ", (short) (highBits >>> 32))); sb.append(':'); sb.append(String.format("%04X ", (short) (highBits >>> 16))); sb.append(':'); sb.append(String.format("%04X ", (short) highBits)); sb.append(':'); sb.append(String.format("%04X ", (short) (lowBits >>> 48))); sb.append(':'); sb.append(String.format("%04X ", (short) (lowBits >>> 32))); sb.append(':'); sb.append(String.format("%04X ", (short) (lowBits >>> 16))); sb.append(':'); sb.append(String.format("%04X ", (short) lowBits)); return sb.toString(); } } public abstract InetAddress toInetAddress(); public static IPv4 fromInt(final int bits) { return new IPv4(bits); } public static IPv4 fromInet4Address(final InetAddress inetAddress) { if (inetAddress == null) { throw new IllegalArgumentException("Cannot construct from null."); } else if (!(inetAddress instanceof Inet4Address)) { throw new IllegalArgumentException("Must be IPv4."); } final byte[] buf = ((Inet4Address) inetAddress).getAddress(); final int ip = ((buf[0] & 0xFF) << 24) | ((buf[1] & 0xFF) << 16) | ((buf[2] & 0xFF) << 8) | ((buf[3] & 0xFF)); return new IPv4(ip); } public static IPv6 fromLong(long highBits, long lowBits) { return new IPv6(highBits, lowBits); } public static IPv6 fromInet6Address(final InetAddress inetAddress) { if (inetAddress == null) { throw new IllegalArgumentException("Cannot construct from null."); } else if (!(inetAddress instanceof Inet6Address)) { throw new IllegalArgumentException("Must be IPv6."); } final byte[] buf = ((Inet6Address) inetAddress).getAddress(); final long highBits = ((buf[0] & 0xFFL) << 56) | ((buf[1] & 0xFFL) << 48) | ((buf[2] & 0xFFL) << 40) | ((buf[3] & 0xFFL) << 32) | ((buf[4] & 0xFFL) << 24) | ((buf[5] & 0xFFL) << 16) | ((buf[6] & 0xFFL) << 8) | ((buf[7] & 0xFFL)); final long lowBits = ((buf[8] & 0xFFL) << 56) | ((buf[9] & 0xFFL) << 48) | ((buf[10] & 0xFFL) << 40) | ((buf[11] & 0xFFL) << 32) | ((buf[12] & 0xFFL) << 24) | ((buf[13] & 0xFFL) << 16) | ((buf[14] & 0xFFL) << 8) | ((buf[15] & 0xFFL)); return new IPv6(highBits, lowBits); } }