18bf977d562b8f7261cf964bdf045b22bdbd92b7dLorenzo Colitti/* 28bf977d562b8f7261cf964bdf045b22bdbd92b7dLorenzo Colitti * Copyright (C) 2015 The Android Open Source Project 38bf977d562b8f7261cf964bdf045b22bdbd92b7dLorenzo Colitti * 48bf977d562b8f7261cf964bdf045b22bdbd92b7dLorenzo Colitti * Licensed under the Apache License, Version 2.0 (the "License"); 58bf977d562b8f7261cf964bdf045b22bdbd92b7dLorenzo Colitti * you may not use this file except in compliance with the License. 68bf977d562b8f7261cf964bdf045b22bdbd92b7dLorenzo Colitti * You may obtain a copy of the License at 78bf977d562b8f7261cf964bdf045b22bdbd92b7dLorenzo Colitti * 88bf977d562b8f7261cf964bdf045b22bdbd92b7dLorenzo Colitti * http://www.apache.org/licenses/LICENSE-2.0 98bf977d562b8f7261cf964bdf045b22bdbd92b7dLorenzo Colitti * 108bf977d562b8f7261cf964bdf045b22bdbd92b7dLorenzo Colitti * Unless required by applicable law or agreed to in writing, software 118bf977d562b8f7261cf964bdf045b22bdbd92b7dLorenzo Colitti * distributed under the License is distributed on an "AS IS" BASIS, 128bf977d562b8f7261cf964bdf045b22bdbd92b7dLorenzo Colitti * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 138bf977d562b8f7261cf964bdf045b22bdbd92b7dLorenzo Colitti * See the License for the specific language governing permissions and 148bf977d562b8f7261cf964bdf045b22bdbd92b7dLorenzo Colitti * limitations under the License. 158bf977d562b8f7261cf964bdf045b22bdbd92b7dLorenzo Colitti */ 168bf977d562b8f7261cf964bdf045b22bdbd92b7dLorenzo Colitti 178bf977d562b8f7261cf964bdf045b22bdbd92b7dLorenzo Colittipackage android.net.util; 188bf977d562b8f7261cf964bdf045b22bdbd92b7dLorenzo Colitti 198bf977d562b8f7261cf964bdf045b22bdbd92b7dLorenzo Colittiimport java.net.Inet6Address; 208bf977d562b8f7261cf964bdf045b22bdbd92b7dLorenzo Colittiimport java.net.InetAddress; 218bf977d562b8f7261cf964bdf045b22bdbd92b7dLorenzo Colittiimport java.nio.BufferOverflowException; 228bf977d562b8f7261cf964bdf045b22bdbd92b7dLorenzo Colittiimport java.nio.BufferUnderflowException; 238bf977d562b8f7261cf964bdf045b22bdbd92b7dLorenzo Colittiimport java.nio.ByteBuffer; 248bf977d562b8f7261cf964bdf045b22bdbd92b7dLorenzo Colittiimport java.nio.ShortBuffer; 258bf977d562b8f7261cf964bdf045b22bdbd92b7dLorenzo Colitti 268bf977d562b8f7261cf964bdf045b22bdbd92b7dLorenzo Colittiimport static android.system.OsConstants.IPPROTO_TCP; 278bf977d562b8f7261cf964bdf045b22bdbd92b7dLorenzo Colittiimport static android.system.OsConstants.IPPROTO_UDP; 288bf977d562b8f7261cf964bdf045b22bdbd92b7dLorenzo Colitti 298bf977d562b8f7261cf964bdf045b22bdbd92b7dLorenzo Colitti/** 308bf977d562b8f7261cf964bdf045b22bdbd92b7dLorenzo Colitti * @hide 318bf977d562b8f7261cf964bdf045b22bdbd92b7dLorenzo Colitti */ 328bf977d562b8f7261cf964bdf045b22bdbd92b7dLorenzo Colittipublic class IpUtils { 338bf977d562b8f7261cf964bdf045b22bdbd92b7dLorenzo Colitti /** 348bf977d562b8f7261cf964bdf045b22bdbd92b7dLorenzo Colitti * Converts a signed short value to an unsigned int value. Needed 358bf977d562b8f7261cf964bdf045b22bdbd92b7dLorenzo Colitti * because Java does not have unsigned types. 368bf977d562b8f7261cf964bdf045b22bdbd92b7dLorenzo Colitti */ 378bf977d562b8f7261cf964bdf045b22bdbd92b7dLorenzo Colitti private static int intAbs(short v) { 388bf977d562b8f7261cf964bdf045b22bdbd92b7dLorenzo Colitti return v & 0xFFFF; 398bf977d562b8f7261cf964bdf045b22bdbd92b7dLorenzo Colitti } 408bf977d562b8f7261cf964bdf045b22bdbd92b7dLorenzo Colitti 418bf977d562b8f7261cf964bdf045b22bdbd92b7dLorenzo Colitti /** 428bf977d562b8f7261cf964bdf045b22bdbd92b7dLorenzo Colitti * Performs an IP checksum (used in IP header and across UDP 438bf977d562b8f7261cf964bdf045b22bdbd92b7dLorenzo Colitti * payload) on the specified portion of a ByteBuffer. The seed 448bf977d562b8f7261cf964bdf045b22bdbd92b7dLorenzo Colitti * allows the checksum to commence with a specified value. 458bf977d562b8f7261cf964bdf045b22bdbd92b7dLorenzo Colitti */ 468bf977d562b8f7261cf964bdf045b22bdbd92b7dLorenzo Colitti private static int checksum(ByteBuffer buf, int seed, int start, int end) { 478bf977d562b8f7261cf964bdf045b22bdbd92b7dLorenzo Colitti int sum = seed; 488bf977d562b8f7261cf964bdf045b22bdbd92b7dLorenzo Colitti final int bufPosition = buf.position(); 498bf977d562b8f7261cf964bdf045b22bdbd92b7dLorenzo Colitti 508bf977d562b8f7261cf964bdf045b22bdbd92b7dLorenzo Colitti // set position of original ByteBuffer, so that the ShortBuffer 518bf977d562b8f7261cf964bdf045b22bdbd92b7dLorenzo Colitti // will be correctly initialized 528bf977d562b8f7261cf964bdf045b22bdbd92b7dLorenzo Colitti buf.position(start); 538bf977d562b8f7261cf964bdf045b22bdbd92b7dLorenzo Colitti ShortBuffer shortBuf = buf.asShortBuffer(); 548bf977d562b8f7261cf964bdf045b22bdbd92b7dLorenzo Colitti 558bf977d562b8f7261cf964bdf045b22bdbd92b7dLorenzo Colitti // re-set ByteBuffer position 568bf977d562b8f7261cf964bdf045b22bdbd92b7dLorenzo Colitti buf.position(bufPosition); 578bf977d562b8f7261cf964bdf045b22bdbd92b7dLorenzo Colitti 588bf977d562b8f7261cf964bdf045b22bdbd92b7dLorenzo Colitti final int numShorts = (end - start) / 2; 598bf977d562b8f7261cf964bdf045b22bdbd92b7dLorenzo Colitti for (int i = 0; i < numShorts; i++) { 608bf977d562b8f7261cf964bdf045b22bdbd92b7dLorenzo Colitti sum += intAbs(shortBuf.get(i)); 618bf977d562b8f7261cf964bdf045b22bdbd92b7dLorenzo Colitti } 628bf977d562b8f7261cf964bdf045b22bdbd92b7dLorenzo Colitti start += numShorts * 2; 638bf977d562b8f7261cf964bdf045b22bdbd92b7dLorenzo Colitti 648bf977d562b8f7261cf964bdf045b22bdbd92b7dLorenzo Colitti // see if a singleton byte remains 658bf977d562b8f7261cf964bdf045b22bdbd92b7dLorenzo Colitti if (end != start) { 668bf977d562b8f7261cf964bdf045b22bdbd92b7dLorenzo Colitti short b = buf.get(start); 678bf977d562b8f7261cf964bdf045b22bdbd92b7dLorenzo Colitti 688bf977d562b8f7261cf964bdf045b22bdbd92b7dLorenzo Colitti // make it unsigned 698bf977d562b8f7261cf964bdf045b22bdbd92b7dLorenzo Colitti if (b < 0) { 708bf977d562b8f7261cf964bdf045b22bdbd92b7dLorenzo Colitti b += 256; 718bf977d562b8f7261cf964bdf045b22bdbd92b7dLorenzo Colitti } 728bf977d562b8f7261cf964bdf045b22bdbd92b7dLorenzo Colitti 738bf977d562b8f7261cf964bdf045b22bdbd92b7dLorenzo Colitti sum += b * 256; 748bf977d562b8f7261cf964bdf045b22bdbd92b7dLorenzo Colitti } 758bf977d562b8f7261cf964bdf045b22bdbd92b7dLorenzo Colitti 768bf977d562b8f7261cf964bdf045b22bdbd92b7dLorenzo Colitti sum = ((sum >> 16) & 0xFFFF) + (sum & 0xFFFF); 778bf977d562b8f7261cf964bdf045b22bdbd92b7dLorenzo Colitti sum = ((sum + ((sum >> 16) & 0xFFFF)) & 0xFFFF); 788bf977d562b8f7261cf964bdf045b22bdbd92b7dLorenzo Colitti int negated = ~sum; 798bf977d562b8f7261cf964bdf045b22bdbd92b7dLorenzo Colitti return intAbs((short) negated); 808bf977d562b8f7261cf964bdf045b22bdbd92b7dLorenzo Colitti } 818bf977d562b8f7261cf964bdf045b22bdbd92b7dLorenzo Colitti 828bf977d562b8f7261cf964bdf045b22bdbd92b7dLorenzo Colitti private static int pseudoChecksumIPv4( 838bf977d562b8f7261cf964bdf045b22bdbd92b7dLorenzo Colitti ByteBuffer buf, int headerOffset, int protocol, int transportLen) { 848bf977d562b8f7261cf964bdf045b22bdbd92b7dLorenzo Colitti int partial = protocol + transportLen; 858bf977d562b8f7261cf964bdf045b22bdbd92b7dLorenzo Colitti partial += intAbs(buf.getShort(headerOffset + 12)); 868bf977d562b8f7261cf964bdf045b22bdbd92b7dLorenzo Colitti partial += intAbs(buf.getShort(headerOffset + 14)); 878bf977d562b8f7261cf964bdf045b22bdbd92b7dLorenzo Colitti partial += intAbs(buf.getShort(headerOffset + 16)); 888bf977d562b8f7261cf964bdf045b22bdbd92b7dLorenzo Colitti partial += intAbs(buf.getShort(headerOffset + 18)); 898bf977d562b8f7261cf964bdf045b22bdbd92b7dLorenzo Colitti return partial; 908bf977d562b8f7261cf964bdf045b22bdbd92b7dLorenzo Colitti } 918bf977d562b8f7261cf964bdf045b22bdbd92b7dLorenzo Colitti 928bf977d562b8f7261cf964bdf045b22bdbd92b7dLorenzo Colitti private static int pseudoChecksumIPv6( 938bf977d562b8f7261cf964bdf045b22bdbd92b7dLorenzo Colitti ByteBuffer buf, int headerOffset, int protocol, int transportLen) { 948bf977d562b8f7261cf964bdf045b22bdbd92b7dLorenzo Colitti int partial = protocol + transportLen; 958bf977d562b8f7261cf964bdf045b22bdbd92b7dLorenzo Colitti for (int offset = 8; offset < 40; offset += 2) { 968bf977d562b8f7261cf964bdf045b22bdbd92b7dLorenzo Colitti partial += intAbs(buf.getShort(headerOffset + offset)); 978bf977d562b8f7261cf964bdf045b22bdbd92b7dLorenzo Colitti } 988bf977d562b8f7261cf964bdf045b22bdbd92b7dLorenzo Colitti return partial; 998bf977d562b8f7261cf964bdf045b22bdbd92b7dLorenzo Colitti } 1008bf977d562b8f7261cf964bdf045b22bdbd92b7dLorenzo Colitti 1018bf977d562b8f7261cf964bdf045b22bdbd92b7dLorenzo Colitti private static byte ipversion(ByteBuffer buf, int headerOffset) { 1028bf977d562b8f7261cf964bdf045b22bdbd92b7dLorenzo Colitti return (byte) ((buf.get(headerOffset) & (byte) 0xf0) >> 4); 1038bf977d562b8f7261cf964bdf045b22bdbd92b7dLorenzo Colitti } 1048bf977d562b8f7261cf964bdf045b22bdbd92b7dLorenzo Colitti 1058bf977d562b8f7261cf964bdf045b22bdbd92b7dLorenzo Colitti public static short ipChecksum(ByteBuffer buf, int headerOffset) { 1068bf977d562b8f7261cf964bdf045b22bdbd92b7dLorenzo Colitti byte ihl = (byte) (buf.get(headerOffset) & 0x0f); 1078bf977d562b8f7261cf964bdf045b22bdbd92b7dLorenzo Colitti return (short) checksum(buf, 0, headerOffset, headerOffset + ihl * 4); 1088bf977d562b8f7261cf964bdf045b22bdbd92b7dLorenzo Colitti } 1098bf977d562b8f7261cf964bdf045b22bdbd92b7dLorenzo Colitti 1108bf977d562b8f7261cf964bdf045b22bdbd92b7dLorenzo Colitti private static short transportChecksum(ByteBuffer buf, int protocol, 1118bf977d562b8f7261cf964bdf045b22bdbd92b7dLorenzo Colitti int ipOffset, int transportOffset, int transportLen) { 1128bf977d562b8f7261cf964bdf045b22bdbd92b7dLorenzo Colitti if (transportLen < 0) { 1138bf977d562b8f7261cf964bdf045b22bdbd92b7dLorenzo Colitti throw new IllegalArgumentException("Transport length < 0: " + transportLen); 1148bf977d562b8f7261cf964bdf045b22bdbd92b7dLorenzo Colitti } 1158bf977d562b8f7261cf964bdf045b22bdbd92b7dLorenzo Colitti int sum; 1168bf977d562b8f7261cf964bdf045b22bdbd92b7dLorenzo Colitti byte ver = ipversion(buf, ipOffset); 1178bf977d562b8f7261cf964bdf045b22bdbd92b7dLorenzo Colitti if (ver == 4) { 1188bf977d562b8f7261cf964bdf045b22bdbd92b7dLorenzo Colitti sum = pseudoChecksumIPv4(buf, ipOffset, protocol, transportLen); 1198bf977d562b8f7261cf964bdf045b22bdbd92b7dLorenzo Colitti } else if (ver == 6) { 1208bf977d562b8f7261cf964bdf045b22bdbd92b7dLorenzo Colitti sum = pseudoChecksumIPv6(buf, ipOffset, protocol, transportLen); 1218bf977d562b8f7261cf964bdf045b22bdbd92b7dLorenzo Colitti } else { 1228bf977d562b8f7261cf964bdf045b22bdbd92b7dLorenzo Colitti throw new UnsupportedOperationException("Checksum must be IPv4 or IPv6"); 1238bf977d562b8f7261cf964bdf045b22bdbd92b7dLorenzo Colitti } 1248bf977d562b8f7261cf964bdf045b22bdbd92b7dLorenzo Colitti 1258bf977d562b8f7261cf964bdf045b22bdbd92b7dLorenzo Colitti sum = checksum(buf, sum, transportOffset, transportOffset + transportLen); 1268bf977d562b8f7261cf964bdf045b22bdbd92b7dLorenzo Colitti if (protocol == IPPROTO_UDP && sum == 0) { 1278bf977d562b8f7261cf964bdf045b22bdbd92b7dLorenzo Colitti sum = (short) 0xffff; 1288bf977d562b8f7261cf964bdf045b22bdbd92b7dLorenzo Colitti } 1298bf977d562b8f7261cf964bdf045b22bdbd92b7dLorenzo Colitti return (short) sum; 1308bf977d562b8f7261cf964bdf045b22bdbd92b7dLorenzo Colitti } 1318bf977d562b8f7261cf964bdf045b22bdbd92b7dLorenzo Colitti 1328bf977d562b8f7261cf964bdf045b22bdbd92b7dLorenzo Colitti public static short udpChecksum(ByteBuffer buf, int ipOffset, int transportOffset) { 1338bf977d562b8f7261cf964bdf045b22bdbd92b7dLorenzo Colitti int transportLen = intAbs(buf.getShort(transportOffset + 4)); 1348bf977d562b8f7261cf964bdf045b22bdbd92b7dLorenzo Colitti return transportChecksum(buf, IPPROTO_UDP, ipOffset, transportOffset, transportLen); 1358bf977d562b8f7261cf964bdf045b22bdbd92b7dLorenzo Colitti } 1368bf977d562b8f7261cf964bdf045b22bdbd92b7dLorenzo Colitti 1378bf977d562b8f7261cf964bdf045b22bdbd92b7dLorenzo Colitti public static short tcpChecksum(ByteBuffer buf, int ipOffset, int transportOffset, 1388bf977d562b8f7261cf964bdf045b22bdbd92b7dLorenzo Colitti int transportLen) { 1398bf977d562b8f7261cf964bdf045b22bdbd92b7dLorenzo Colitti return transportChecksum(buf, IPPROTO_TCP, ipOffset, transportOffset, transportLen); 1408bf977d562b8f7261cf964bdf045b22bdbd92b7dLorenzo Colitti } 1418bf977d562b8f7261cf964bdf045b22bdbd92b7dLorenzo Colitti 1428bf977d562b8f7261cf964bdf045b22bdbd92b7dLorenzo Colitti public static String addressAndPortToString(InetAddress address, int port) { 1438bf977d562b8f7261cf964bdf045b22bdbd92b7dLorenzo Colitti return String.format( 1448bf977d562b8f7261cf964bdf045b22bdbd92b7dLorenzo Colitti (address instanceof Inet6Address) ? "[%s]:%d" : "%s:%d", 1458bf977d562b8f7261cf964bdf045b22bdbd92b7dLorenzo Colitti address.getHostAddress(), port); 1468bf977d562b8f7261cf964bdf045b22bdbd92b7dLorenzo Colitti } 1478bf977d562b8f7261cf964bdf045b22bdbd92b7dLorenzo Colitti 1488bf977d562b8f7261cf964bdf045b22bdbd92b7dLorenzo Colitti public static boolean isValidUdpOrTcpPort(int port) { 1498bf977d562b8f7261cf964bdf045b22bdbd92b7dLorenzo Colitti return port > 0 && port < 65536; 1508bf977d562b8f7261cf964bdf045b22bdbd92b7dLorenzo Colitti } 1518bf977d562b8f7261cf964bdf045b22bdbd92b7dLorenzo Colitti} 152