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