1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166
|
/*
* Copyright (C) 2019 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package android.net.shared;
import java.net.Inet4Address;
import java.net.InetAddress;
import java.net.UnknownHostException;
/**
* Collection of utilities to work with IPv4 addresses.
* @hide
*/
public class Inet4AddressUtils {
/**
* Convert a IPv4 address from an integer to an InetAddress (0x04030201 -> 1.2.3.4)
*
* <p>This method uses the higher-order int bytes as the lower-order IPv4 address bytes,
* which is an unusual convention. Consider {@link #intToInet4AddressHTH(int)} instead.
* @param hostAddress an int coding for an IPv4 address, where higher-order int byte is
* lower-order IPv4 address byte
*/
public static Inet4Address intToInet4AddressHTL(int hostAddress) {
return intToInet4AddressHTH(Integer.reverseBytes(hostAddress));
}
/**
* Convert a IPv4 address from an integer to an InetAddress (0x01020304 -> 1.2.3.4)
* @param hostAddress an int coding for an IPv4 address
*/
public static Inet4Address intToInet4AddressHTH(int hostAddress) {
byte[] addressBytes = { (byte) (0xff & (hostAddress >> 24)),
(byte) (0xff & (hostAddress >> 16)),
(byte) (0xff & (hostAddress >> 8)),
(byte) (0xff & hostAddress) };
try {
return (Inet4Address) InetAddress.getByAddress(addressBytes);
} catch (UnknownHostException e) {
throw new AssertionError();
}
}
/**
* Convert an IPv4 address from an InetAddress to an integer (1.2.3.4 -> 0x01020304)
*
* <p>This conversion can help order IP addresses: considering the ordering
* 192.0.2.1 < 192.0.2.2 < ..., resulting ints will follow that ordering if read as unsigned
* integers with {@link Integer#toUnsignedLong}.
* @param inetAddr is an InetAddress corresponding to the IPv4 address
* @return the IP address as integer
*/
public static int inet4AddressToIntHTH(Inet4Address inetAddr)
throws IllegalArgumentException {
byte [] addr = inetAddr.getAddress();
return ((addr[0] & 0xff) << 24) | ((addr[1] & 0xff) << 16)
| ((addr[2] & 0xff) << 8) | (addr[3] & 0xff);
}
/**
* Convert a IPv4 address from an InetAddress to an integer (1.2.3.4 -> 0x04030201)
*
* <p>This method stores the higher-order IPv4 address bytes in the lower-order int bytes,
* which is an unusual convention. Consider {@link #inet4AddressToIntHTH(Inet4Address)} instead.
* @param inetAddr is an InetAddress corresponding to the IPv4 address
* @return the IP address as integer
*/
public static int inet4AddressToIntHTL(Inet4Address inetAddr) {
return Integer.reverseBytes(inet4AddressToIntHTH(inetAddr));
}
/**
* Convert a network prefix length to an IPv4 netmask integer (prefixLength 17 -> 0xffff8000)
* @return the IPv4 netmask as an integer
*/
public static int prefixLengthToV4NetmaskIntHTH(int prefixLength)
throws IllegalArgumentException {
if (prefixLength < 0 || prefixLength > 32) {
throw new IllegalArgumentException("Invalid prefix length (0 <= prefix <= 32)");
}
// (int)a << b is equivalent to a << (b & 0x1f): can't shift by 32 (-1 << 32 == -1)
return prefixLength == 0 ? 0 : 0xffffffff << (32 - prefixLength);
}
/**
* Convert a network prefix length to an IPv4 netmask integer (prefixLength 17 -> 0x0080ffff).
*
* <p>This method stores the higher-order IPv4 address bytes in the lower-order int bytes,
* which is an unusual convention. Consider {@link #prefixLengthToV4NetmaskIntHTH(int)} instead.
* @return the IPv4 netmask as an integer
*/
public static int prefixLengthToV4NetmaskIntHTL(int prefixLength)
throws IllegalArgumentException {
return Integer.reverseBytes(prefixLengthToV4NetmaskIntHTH(prefixLength));
}
/**
* Convert an IPv4 netmask to a prefix length, checking that the netmask is contiguous.
* @param netmask as a {@code Inet4Address}.
* @return the network prefix length
* @throws IllegalArgumentException the specified netmask was not contiguous.
* @hide
*/
public static int netmaskToPrefixLength(Inet4Address netmask) {
// inetAddressToInt returns an int in *network* byte order.
int i = inet4AddressToIntHTH(netmask);
int prefixLength = Integer.bitCount(i);
int trailingZeros = Integer.numberOfTrailingZeros(i);
if (trailingZeros != 32 - prefixLength) {
throw new IllegalArgumentException("Non-contiguous netmask: " + Integer.toHexString(i));
}
return prefixLength;
}
/**
* Returns the implicit netmask of an IPv4 address, as was the custom before 1993.
*/
public static int getImplicitNetmask(Inet4Address address) {
int firstByte = address.getAddress()[0] & 0xff; // Convert to an unsigned value.
if (firstByte < 128) {
return 8;
} else if (firstByte < 192) {
return 16;
} else if (firstByte < 224) {
return 24;
} else {
return 32; // Will likely not end well for other reasons.
}
}
/**
* Get the broadcast address for a given prefix.
*
* <p>For example 192.168.0.1/24 -> 192.168.0.255
*/
public static Inet4Address getBroadcastAddress(Inet4Address addr, int prefixLength)
throws IllegalArgumentException {
final int intBroadcastAddr = inet4AddressToIntHTH(addr)
| ~prefixLengthToV4NetmaskIntHTH(prefixLength);
return intToInet4AddressHTH(intBroadcastAddr);
}
/**
* Get a prefix mask as Inet4Address for a given prefix length.
*
* <p>For example 20 -> 255.255.240.0
*/
public static Inet4Address getPrefixMaskAsInet4Address(int prefixLength)
throws IllegalArgumentException {
return intToInet4AddressHTH(prefixLengthToV4NetmaskIntHTH(prefixLength));
}
}
|