1473355f96b91a1fbeb6f8f8f0bcd3c887da12f40Erik Kline/* 2473355f96b91a1fbeb6f8f8f0bcd3c887da12f40Erik Kline * Copyright (C) 2016 The Android Open Source Project 3473355f96b91a1fbeb6f8f8f0bcd3c887da12f40Erik Kline * 4473355f96b91a1fbeb6f8f8f0bcd3c887da12f40Erik Kline * Licensed under the Apache License, Version 2.0 (the "License"); 5473355f96b91a1fbeb6f8f8f0bcd3c887da12f40Erik Kline * you may not use this file except in compliance with the License. 6473355f96b91a1fbeb6f8f8f0bcd3c887da12f40Erik Kline * You may obtain a copy of the License at 7473355f96b91a1fbeb6f8f8f0bcd3c887da12f40Erik Kline * 8473355f96b91a1fbeb6f8f8f0bcd3c887da12f40Erik Kline * http://www.apache.org/licenses/LICENSE-2.0 9473355f96b91a1fbeb6f8f8f0bcd3c887da12f40Erik Kline * 10473355f96b91a1fbeb6f8f8f0bcd3c887da12f40Erik Kline * Unless required by applicable law or agreed to in writing, software 11473355f96b91a1fbeb6f8f8f0bcd3c887da12f40Erik Kline * distributed under the License is distributed on an "AS IS" BASIS, 12473355f96b91a1fbeb6f8f8f0bcd3c887da12f40Erik Kline * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13473355f96b91a1fbeb6f8f8f0bcd3c887da12f40Erik Kline * See the License for the specific language governing permissions and 14473355f96b91a1fbeb6f8f8f0bcd3c887da12f40Erik Kline * limitations under the License. 15473355f96b91a1fbeb6f8f8f0bcd3c887da12f40Erik Kline */ 16473355f96b91a1fbeb6f8f8f0bcd3c887da12f40Erik Kline 17473355f96b91a1fbeb6f8f8f0bcd3c887da12f40Erik Klinepackage android.net.util; 18473355f96b91a1fbeb6f8f8f0bcd3c887da12f40Erik Kline 19473355f96b91a1fbeb6f8f8f0bcd3c887da12f40Erik Klineimport android.net.dhcp.DhcpPacket; 20473355f96b91a1fbeb6f8f8f0bcd3c887da12f40Erik Kline 21473355f96b91a1fbeb6f8f8f0bcd3c887da12f40Erik Klineimport java.net.InetAddress; 22473355f96b91a1fbeb6f8f8f0bcd3c887da12f40Erik Klineimport java.net.UnknownHostException; 23473355f96b91a1fbeb6f8f8f0bcd3c887da12f40Erik Klineimport java.nio.ByteBuffer; 24473355f96b91a1fbeb6f8f8f0bcd3c887da12f40Erik Klineimport java.nio.ByteOrder; 25473355f96b91a1fbeb6f8f8f0bcd3c887da12f40Erik Klineimport java.util.Arrays; 26473355f96b91a1fbeb6f8f8f0bcd3c887da12f40Erik Klineimport java.util.StringJoiner; 27473355f96b91a1fbeb6f8f8f0bcd3c887da12f40Erik Kline 28473355f96b91a1fbeb6f8f8f0bcd3c887da12f40Erik Klineimport static android.system.OsConstants.*; 29473355f96b91a1fbeb6f8f8f0bcd3c887da12f40Erik Klineimport static android.net.util.NetworkConstants.*; 30473355f96b91a1fbeb6f8f8f0bcd3c887da12f40Erik Kline 31473355f96b91a1fbeb6f8f8f0bcd3c887da12f40Erik Kline 32473355f96b91a1fbeb6f8f8f0bcd3c887da12f40Erik Kline/** 33473355f96b91a1fbeb6f8f8f0bcd3c887da12f40Erik Kline * Critical connectivity packet summarizing class. 34473355f96b91a1fbeb6f8f8f0bcd3c887da12f40Erik Kline * 35473355f96b91a1fbeb6f8f8f0bcd3c887da12f40Erik Kline * Outputs short descriptions of ARP, DHCPv4, and IPv6 RS/RA/NS/NA packets. 36473355f96b91a1fbeb6f8f8f0bcd3c887da12f40Erik Kline * 37473355f96b91a1fbeb6f8f8f0bcd3c887da12f40Erik Kline * @hide 38473355f96b91a1fbeb6f8f8f0bcd3c887da12f40Erik Kline */ 39473355f96b91a1fbeb6f8f8f0bcd3c887da12f40Erik Klinepublic class ConnectivityPacketSummary { 40473355f96b91a1fbeb6f8f8f0bcd3c887da12f40Erik Kline private static final String TAG = ConnectivityPacketSummary.class.getSimpleName(); 41473355f96b91a1fbeb6f8f8f0bcd3c887da12f40Erik Kline 42473355f96b91a1fbeb6f8f8f0bcd3c887da12f40Erik Kline private final byte[] mHwAddr; 43473355f96b91a1fbeb6f8f8f0bcd3c887da12f40Erik Kline private final byte[] mBytes; 44473355f96b91a1fbeb6f8f8f0bcd3c887da12f40Erik Kline private final int mLength; 45473355f96b91a1fbeb6f8f8f0bcd3c887da12f40Erik Kline private final ByteBuffer mPacket; 46473355f96b91a1fbeb6f8f8f0bcd3c887da12f40Erik Kline private final String mSummary; 47473355f96b91a1fbeb6f8f8f0bcd3c887da12f40Erik Kline 48473355f96b91a1fbeb6f8f8f0bcd3c887da12f40Erik Kline public static String summarize(byte[] hwaddr, byte[] buffer) { 49473355f96b91a1fbeb6f8f8f0bcd3c887da12f40Erik Kline return summarize(hwaddr, buffer, buffer.length); 50473355f96b91a1fbeb6f8f8f0bcd3c887da12f40Erik Kline } 51473355f96b91a1fbeb6f8f8f0bcd3c887da12f40Erik Kline 52473355f96b91a1fbeb6f8f8f0bcd3c887da12f40Erik Kline // Methods called herein perform some but by no means all error checking. 53473355f96b91a1fbeb6f8f8f0bcd3c887da12f40Erik Kline // They may throw runtime exceptions on malformed packets. 54473355f96b91a1fbeb6f8f8f0bcd3c887da12f40Erik Kline public static String summarize(byte[] hwaddr, byte[] buffer, int length) { 55473355f96b91a1fbeb6f8f8f0bcd3c887da12f40Erik Kline if ((hwaddr == null) || (hwaddr.length != ETHER_ADDR_LEN)) return null; 56473355f96b91a1fbeb6f8f8f0bcd3c887da12f40Erik Kline if (buffer == null) return null; 57473355f96b91a1fbeb6f8f8f0bcd3c887da12f40Erik Kline length = Math.min(length, buffer.length); 58473355f96b91a1fbeb6f8f8f0bcd3c887da12f40Erik Kline return (new ConnectivityPacketSummary(hwaddr, buffer, length)).toString(); 59473355f96b91a1fbeb6f8f8f0bcd3c887da12f40Erik Kline } 60473355f96b91a1fbeb6f8f8f0bcd3c887da12f40Erik Kline 61473355f96b91a1fbeb6f8f8f0bcd3c887da12f40Erik Kline private ConnectivityPacketSummary(byte[] hwaddr, byte[] buffer, int length) { 62473355f96b91a1fbeb6f8f8f0bcd3c887da12f40Erik Kline mHwAddr = hwaddr; 63473355f96b91a1fbeb6f8f8f0bcd3c887da12f40Erik Kline mBytes = buffer; 64473355f96b91a1fbeb6f8f8f0bcd3c887da12f40Erik Kline mLength = Math.min(length, mBytes.length); 65473355f96b91a1fbeb6f8f8f0bcd3c887da12f40Erik Kline mPacket = ByteBuffer.wrap(mBytes, 0, mLength); 66473355f96b91a1fbeb6f8f8f0bcd3c887da12f40Erik Kline mPacket.order(ByteOrder.BIG_ENDIAN); 67473355f96b91a1fbeb6f8f8f0bcd3c887da12f40Erik Kline 68473355f96b91a1fbeb6f8f8f0bcd3c887da12f40Erik Kline final StringJoiner sj = new StringJoiner(" "); 69473355f96b91a1fbeb6f8f8f0bcd3c887da12f40Erik Kline // TODO: support other link-layers, or even no link-layer header. 70473355f96b91a1fbeb6f8f8f0bcd3c887da12f40Erik Kline parseEther(sj); 71473355f96b91a1fbeb6f8f8f0bcd3c887da12f40Erik Kline mSummary = sj.toString(); 72473355f96b91a1fbeb6f8f8f0bcd3c887da12f40Erik Kline } 73473355f96b91a1fbeb6f8f8f0bcd3c887da12f40Erik Kline 74473355f96b91a1fbeb6f8f8f0bcd3c887da12f40Erik Kline public String toString() { 75473355f96b91a1fbeb6f8f8f0bcd3c887da12f40Erik Kline return mSummary; 76473355f96b91a1fbeb6f8f8f0bcd3c887da12f40Erik Kline } 77473355f96b91a1fbeb6f8f8f0bcd3c887da12f40Erik Kline 78473355f96b91a1fbeb6f8f8f0bcd3c887da12f40Erik Kline private void parseEther(StringJoiner sj) { 79473355f96b91a1fbeb6f8f8f0bcd3c887da12f40Erik Kline if (mPacket.remaining() < ETHER_HEADER_LEN) { 80473355f96b91a1fbeb6f8f8f0bcd3c887da12f40Erik Kline sj.add("runt:").add(asString(mPacket.remaining())); 81473355f96b91a1fbeb6f8f8f0bcd3c887da12f40Erik Kline return; 82473355f96b91a1fbeb6f8f8f0bcd3c887da12f40Erik Kline } 83473355f96b91a1fbeb6f8f8f0bcd3c887da12f40Erik Kline 84473355f96b91a1fbeb6f8f8f0bcd3c887da12f40Erik Kline mPacket.position(ETHER_SRC_ADDR_OFFSET); 85473355f96b91a1fbeb6f8f8f0bcd3c887da12f40Erik Kline final ByteBuffer srcMac = (ByteBuffer) mPacket.slice().limit(ETHER_ADDR_LEN); 86473355f96b91a1fbeb6f8f8f0bcd3c887da12f40Erik Kline sj.add(ByteBuffer.wrap(mHwAddr).equals(srcMac) ? "TX" : "RX"); 87473355f96b91a1fbeb6f8f8f0bcd3c887da12f40Erik Kline sj.add(getMacAddressString(srcMac)); 88473355f96b91a1fbeb6f8f8f0bcd3c887da12f40Erik Kline 89473355f96b91a1fbeb6f8f8f0bcd3c887da12f40Erik Kline mPacket.position(ETHER_DST_ADDR_OFFSET); 90473355f96b91a1fbeb6f8f8f0bcd3c887da12f40Erik Kline final ByteBuffer dstMac = (ByteBuffer) mPacket.slice().limit(ETHER_ADDR_LEN); 91473355f96b91a1fbeb6f8f8f0bcd3c887da12f40Erik Kline sj.add(">").add(getMacAddressString(dstMac)); 92473355f96b91a1fbeb6f8f8f0bcd3c887da12f40Erik Kline 93473355f96b91a1fbeb6f8f8f0bcd3c887da12f40Erik Kline mPacket.position(ETHER_TYPE_OFFSET); 94473355f96b91a1fbeb6f8f8f0bcd3c887da12f40Erik Kline final int etherType = asUint(mPacket.getShort()); 95473355f96b91a1fbeb6f8f8f0bcd3c887da12f40Erik Kline switch (etherType) { 96473355f96b91a1fbeb6f8f8f0bcd3c887da12f40Erik Kline case ETHER_TYPE_ARP: 97473355f96b91a1fbeb6f8f8f0bcd3c887da12f40Erik Kline sj.add("arp"); 98473355f96b91a1fbeb6f8f8f0bcd3c887da12f40Erik Kline parseARP(sj); 99473355f96b91a1fbeb6f8f8f0bcd3c887da12f40Erik Kline break; 100473355f96b91a1fbeb6f8f8f0bcd3c887da12f40Erik Kline case ETHER_TYPE_IPV4: 101473355f96b91a1fbeb6f8f8f0bcd3c887da12f40Erik Kline sj.add("ipv4"); 102473355f96b91a1fbeb6f8f8f0bcd3c887da12f40Erik Kline parseIPv4(sj); 103473355f96b91a1fbeb6f8f8f0bcd3c887da12f40Erik Kline break; 104473355f96b91a1fbeb6f8f8f0bcd3c887da12f40Erik Kline case ETHER_TYPE_IPV6: 105473355f96b91a1fbeb6f8f8f0bcd3c887da12f40Erik Kline sj.add("ipv6"); 106473355f96b91a1fbeb6f8f8f0bcd3c887da12f40Erik Kline parseIPv6(sj); 107473355f96b91a1fbeb6f8f8f0bcd3c887da12f40Erik Kline break; 108473355f96b91a1fbeb6f8f8f0bcd3c887da12f40Erik Kline default: 109473355f96b91a1fbeb6f8f8f0bcd3c887da12f40Erik Kline // Unknown ether type. 110473355f96b91a1fbeb6f8f8f0bcd3c887da12f40Erik Kline sj.add("ethtype").add(asString(etherType)); 111473355f96b91a1fbeb6f8f8f0bcd3c887da12f40Erik Kline break; 112473355f96b91a1fbeb6f8f8f0bcd3c887da12f40Erik Kline } 113473355f96b91a1fbeb6f8f8f0bcd3c887da12f40Erik Kline } 114473355f96b91a1fbeb6f8f8f0bcd3c887da12f40Erik Kline 115473355f96b91a1fbeb6f8f8f0bcd3c887da12f40Erik Kline private void parseARP(StringJoiner sj) { 116473355f96b91a1fbeb6f8f8f0bcd3c887da12f40Erik Kline if (mPacket.remaining() < ARP_PAYLOAD_LEN) { 117473355f96b91a1fbeb6f8f8f0bcd3c887da12f40Erik Kline sj.add("runt:").add(asString(mPacket.remaining())); 118473355f96b91a1fbeb6f8f8f0bcd3c887da12f40Erik Kline return; 119473355f96b91a1fbeb6f8f8f0bcd3c887da12f40Erik Kline } 120473355f96b91a1fbeb6f8f8f0bcd3c887da12f40Erik Kline 121473355f96b91a1fbeb6f8f8f0bcd3c887da12f40Erik Kline if (asUint(mPacket.getShort()) != ARP_HWTYPE_ETHER || 122473355f96b91a1fbeb6f8f8f0bcd3c887da12f40Erik Kline asUint(mPacket.getShort()) != ETHER_TYPE_IPV4 || 123473355f96b91a1fbeb6f8f8f0bcd3c887da12f40Erik Kline asUint(mPacket.get()) != ETHER_ADDR_LEN || 124473355f96b91a1fbeb6f8f8f0bcd3c887da12f40Erik Kline asUint(mPacket.get()) != IPV4_ADDR_LEN) { 125473355f96b91a1fbeb6f8f8f0bcd3c887da12f40Erik Kline sj.add("unexpected header"); 126473355f96b91a1fbeb6f8f8f0bcd3c887da12f40Erik Kline return; 127473355f96b91a1fbeb6f8f8f0bcd3c887da12f40Erik Kline } 128473355f96b91a1fbeb6f8f8f0bcd3c887da12f40Erik Kline 129473355f96b91a1fbeb6f8f8f0bcd3c887da12f40Erik Kline final int opCode = asUint(mPacket.getShort()); 130473355f96b91a1fbeb6f8f8f0bcd3c887da12f40Erik Kline 131473355f96b91a1fbeb6f8f8f0bcd3c887da12f40Erik Kline final String senderHwAddr = getMacAddressString(mPacket); 132473355f96b91a1fbeb6f8f8f0bcd3c887da12f40Erik Kline final String senderIPv4 = getIPv4AddressString(mPacket); 133473355f96b91a1fbeb6f8f8f0bcd3c887da12f40Erik Kline getMacAddressString(mPacket); // target hardware address, unused 134473355f96b91a1fbeb6f8f8f0bcd3c887da12f40Erik Kline final String targetIPv4 = getIPv4AddressString(mPacket); 135473355f96b91a1fbeb6f8f8f0bcd3c887da12f40Erik Kline 136473355f96b91a1fbeb6f8f8f0bcd3c887da12f40Erik Kline if (opCode == ARP_REQUEST) { 137473355f96b91a1fbeb6f8f8f0bcd3c887da12f40Erik Kline sj.add("who-has").add(targetIPv4); 138473355f96b91a1fbeb6f8f8f0bcd3c887da12f40Erik Kline } else if (opCode == ARP_REPLY) { 139473355f96b91a1fbeb6f8f8f0bcd3c887da12f40Erik Kline sj.add("reply").add(senderIPv4).add(senderHwAddr); 140473355f96b91a1fbeb6f8f8f0bcd3c887da12f40Erik Kline } else { 141473355f96b91a1fbeb6f8f8f0bcd3c887da12f40Erik Kline sj.add("unknown opcode").add(asString(opCode)); 142473355f96b91a1fbeb6f8f8f0bcd3c887da12f40Erik Kline } 143473355f96b91a1fbeb6f8f8f0bcd3c887da12f40Erik Kline } 144473355f96b91a1fbeb6f8f8f0bcd3c887da12f40Erik Kline 145473355f96b91a1fbeb6f8f8f0bcd3c887da12f40Erik Kline private void parseIPv4(StringJoiner sj) { 146473355f96b91a1fbeb6f8f8f0bcd3c887da12f40Erik Kline if (!mPacket.hasRemaining()) { 147473355f96b91a1fbeb6f8f8f0bcd3c887da12f40Erik Kline sj.add("runt"); 148473355f96b91a1fbeb6f8f8f0bcd3c887da12f40Erik Kline return; 149473355f96b91a1fbeb6f8f8f0bcd3c887da12f40Erik Kline } 150473355f96b91a1fbeb6f8f8f0bcd3c887da12f40Erik Kline 151473355f96b91a1fbeb6f8f8f0bcd3c887da12f40Erik Kline final int startOfIpLayer = mPacket.position(); 152473355f96b91a1fbeb6f8f8f0bcd3c887da12f40Erik Kline final int ipv4HeaderLength = (mPacket.get(startOfIpLayer) & IPV4_IHL_MASK) * 4; 153473355f96b91a1fbeb6f8f8f0bcd3c887da12f40Erik Kline if (mPacket.remaining() < ipv4HeaderLength || 154473355f96b91a1fbeb6f8f8f0bcd3c887da12f40Erik Kline mPacket.remaining() < IPV4_HEADER_MIN_LEN) { 155473355f96b91a1fbeb6f8f8f0bcd3c887da12f40Erik Kline sj.add("runt:").add(asString(mPacket.remaining())); 156473355f96b91a1fbeb6f8f8f0bcd3c887da12f40Erik Kline return; 157473355f96b91a1fbeb6f8f8f0bcd3c887da12f40Erik Kline } 158473355f96b91a1fbeb6f8f8f0bcd3c887da12f40Erik Kline final int startOfTransportLayer = startOfIpLayer + ipv4HeaderLength; 159473355f96b91a1fbeb6f8f8f0bcd3c887da12f40Erik Kline 160473355f96b91a1fbeb6f8f8f0bcd3c887da12f40Erik Kline mPacket.position(startOfIpLayer + IPV4_FLAGS_OFFSET); 161473355f96b91a1fbeb6f8f8f0bcd3c887da12f40Erik Kline final int flagsAndFragment = asUint(mPacket.getShort()); 162473355f96b91a1fbeb6f8f8f0bcd3c887da12f40Erik Kline final boolean isFragment = (flagsAndFragment & IPV4_FRAGMENT_MASK) != 0; 163473355f96b91a1fbeb6f8f8f0bcd3c887da12f40Erik Kline 164473355f96b91a1fbeb6f8f8f0bcd3c887da12f40Erik Kline mPacket.position(startOfIpLayer + IPV4_PROTOCOL_OFFSET); 165473355f96b91a1fbeb6f8f8f0bcd3c887da12f40Erik Kline final int protocol = asUint(mPacket.get()); 166473355f96b91a1fbeb6f8f8f0bcd3c887da12f40Erik Kline 167473355f96b91a1fbeb6f8f8f0bcd3c887da12f40Erik Kline mPacket.position(startOfIpLayer + IPV4_SRC_ADDR_OFFSET); 168473355f96b91a1fbeb6f8f8f0bcd3c887da12f40Erik Kline final String srcAddr = getIPv4AddressString(mPacket); 169473355f96b91a1fbeb6f8f8f0bcd3c887da12f40Erik Kline 170473355f96b91a1fbeb6f8f8f0bcd3c887da12f40Erik Kline mPacket.position(startOfIpLayer + IPV4_DST_ADDR_OFFSET); 171473355f96b91a1fbeb6f8f8f0bcd3c887da12f40Erik Kline final String dstAddr = getIPv4AddressString(mPacket); 172473355f96b91a1fbeb6f8f8f0bcd3c887da12f40Erik Kline 173473355f96b91a1fbeb6f8f8f0bcd3c887da12f40Erik Kline sj.add(srcAddr).add(">").add(dstAddr); 174473355f96b91a1fbeb6f8f8f0bcd3c887da12f40Erik Kline 175473355f96b91a1fbeb6f8f8f0bcd3c887da12f40Erik Kline mPacket.position(startOfTransportLayer); 176473355f96b91a1fbeb6f8f8f0bcd3c887da12f40Erik Kline if (protocol == IPPROTO_UDP) { 177473355f96b91a1fbeb6f8f8f0bcd3c887da12f40Erik Kline sj.add("udp"); 178473355f96b91a1fbeb6f8f8f0bcd3c887da12f40Erik Kline if (isFragment) sj.add("fragment"); 179473355f96b91a1fbeb6f8f8f0bcd3c887da12f40Erik Kline else parseUDP(sj); 180473355f96b91a1fbeb6f8f8f0bcd3c887da12f40Erik Kline } else { 181473355f96b91a1fbeb6f8f8f0bcd3c887da12f40Erik Kline sj.add("proto").add(asString(protocol)); 182473355f96b91a1fbeb6f8f8f0bcd3c887da12f40Erik Kline if (isFragment) sj.add("fragment"); 183473355f96b91a1fbeb6f8f8f0bcd3c887da12f40Erik Kline } 184473355f96b91a1fbeb6f8f8f0bcd3c887da12f40Erik Kline } 185473355f96b91a1fbeb6f8f8f0bcd3c887da12f40Erik Kline 186473355f96b91a1fbeb6f8f8f0bcd3c887da12f40Erik Kline private void parseIPv6(StringJoiner sj) { 187473355f96b91a1fbeb6f8f8f0bcd3c887da12f40Erik Kline if (mPacket.remaining() < IPV6_HEADER_LEN) { 188473355f96b91a1fbeb6f8f8f0bcd3c887da12f40Erik Kline sj.add("runt:").add(asString(mPacket.remaining())); 189473355f96b91a1fbeb6f8f8f0bcd3c887da12f40Erik Kline return; 190473355f96b91a1fbeb6f8f8f0bcd3c887da12f40Erik Kline } 191473355f96b91a1fbeb6f8f8f0bcd3c887da12f40Erik Kline 192473355f96b91a1fbeb6f8f8f0bcd3c887da12f40Erik Kline final int startOfIpLayer = mPacket.position(); 193473355f96b91a1fbeb6f8f8f0bcd3c887da12f40Erik Kline 194473355f96b91a1fbeb6f8f8f0bcd3c887da12f40Erik Kline mPacket.position(startOfIpLayer + IPV6_PROTOCOL_OFFSET); 195473355f96b91a1fbeb6f8f8f0bcd3c887da12f40Erik Kline final int protocol = asUint(mPacket.get()); 196473355f96b91a1fbeb6f8f8f0bcd3c887da12f40Erik Kline 197473355f96b91a1fbeb6f8f8f0bcd3c887da12f40Erik Kline mPacket.position(startOfIpLayer + IPV6_SRC_ADDR_OFFSET); 198473355f96b91a1fbeb6f8f8f0bcd3c887da12f40Erik Kline final String srcAddr = getIPv6AddressString(mPacket); 199473355f96b91a1fbeb6f8f8f0bcd3c887da12f40Erik Kline final String dstAddr = getIPv6AddressString(mPacket); 200473355f96b91a1fbeb6f8f8f0bcd3c887da12f40Erik Kline 201473355f96b91a1fbeb6f8f8f0bcd3c887da12f40Erik Kline sj.add(srcAddr).add(">").add(dstAddr); 202473355f96b91a1fbeb6f8f8f0bcd3c887da12f40Erik Kline 203473355f96b91a1fbeb6f8f8f0bcd3c887da12f40Erik Kline mPacket.position(startOfIpLayer + IPV6_HEADER_LEN); 204473355f96b91a1fbeb6f8f8f0bcd3c887da12f40Erik Kline if (protocol == IPPROTO_ICMPV6) { 205473355f96b91a1fbeb6f8f8f0bcd3c887da12f40Erik Kline sj.add("icmp6"); 206473355f96b91a1fbeb6f8f8f0bcd3c887da12f40Erik Kline parseICMPv6(sj); 207473355f96b91a1fbeb6f8f8f0bcd3c887da12f40Erik Kline } else { 208473355f96b91a1fbeb6f8f8f0bcd3c887da12f40Erik Kline sj.add("proto").add(asString(protocol)); 209473355f96b91a1fbeb6f8f8f0bcd3c887da12f40Erik Kline } 210473355f96b91a1fbeb6f8f8f0bcd3c887da12f40Erik Kline } 211473355f96b91a1fbeb6f8f8f0bcd3c887da12f40Erik Kline 212473355f96b91a1fbeb6f8f8f0bcd3c887da12f40Erik Kline private void parseICMPv6(StringJoiner sj) { 213473355f96b91a1fbeb6f8f8f0bcd3c887da12f40Erik Kline if (mPacket.remaining() < ICMPV6_HEADER_MIN_LEN) { 214473355f96b91a1fbeb6f8f8f0bcd3c887da12f40Erik Kline sj.add("runt:").add(asString(mPacket.remaining())); 215473355f96b91a1fbeb6f8f8f0bcd3c887da12f40Erik Kline return; 216473355f96b91a1fbeb6f8f8f0bcd3c887da12f40Erik Kline } 217473355f96b91a1fbeb6f8f8f0bcd3c887da12f40Erik Kline 218473355f96b91a1fbeb6f8f8f0bcd3c887da12f40Erik Kline final int icmp6Type = asUint(mPacket.get()); 219473355f96b91a1fbeb6f8f8f0bcd3c887da12f40Erik Kline final int icmp6Code = asUint(mPacket.get()); 220473355f96b91a1fbeb6f8f8f0bcd3c887da12f40Erik Kline mPacket.getShort(); // checksum, unused 221473355f96b91a1fbeb6f8f8f0bcd3c887da12f40Erik Kline 222473355f96b91a1fbeb6f8f8f0bcd3c887da12f40Erik Kline switch (icmp6Type) { 223473355f96b91a1fbeb6f8f8f0bcd3c887da12f40Erik Kline case ICMPV6_ROUTER_SOLICITATION: 224473355f96b91a1fbeb6f8f8f0bcd3c887da12f40Erik Kline sj.add("rs"); 225473355f96b91a1fbeb6f8f8f0bcd3c887da12f40Erik Kline parseICMPv6RouterSolicitation(sj); 226473355f96b91a1fbeb6f8f8f0bcd3c887da12f40Erik Kline break; 227473355f96b91a1fbeb6f8f8f0bcd3c887da12f40Erik Kline case ICMPV6_ROUTER_ADVERTISEMENT: 228473355f96b91a1fbeb6f8f8f0bcd3c887da12f40Erik Kline sj.add("ra"); 229473355f96b91a1fbeb6f8f8f0bcd3c887da12f40Erik Kline parseICMPv6RouterAdvertisement(sj); 230473355f96b91a1fbeb6f8f8f0bcd3c887da12f40Erik Kline break; 231473355f96b91a1fbeb6f8f8f0bcd3c887da12f40Erik Kline case ICMPV6_NEIGHBOR_SOLICITATION: 232473355f96b91a1fbeb6f8f8f0bcd3c887da12f40Erik Kline sj.add("ns"); 233473355f96b91a1fbeb6f8f8f0bcd3c887da12f40Erik Kline parseICMPv6NeighborMessage(sj); 234473355f96b91a1fbeb6f8f8f0bcd3c887da12f40Erik Kline break; 235473355f96b91a1fbeb6f8f8f0bcd3c887da12f40Erik Kline case ICMPV6_NEIGHBOR_ADVERTISEMENT: 236473355f96b91a1fbeb6f8f8f0bcd3c887da12f40Erik Kline sj.add("na"); 237473355f96b91a1fbeb6f8f8f0bcd3c887da12f40Erik Kline parseICMPv6NeighborMessage(sj); 238473355f96b91a1fbeb6f8f8f0bcd3c887da12f40Erik Kline break; 239473355f96b91a1fbeb6f8f8f0bcd3c887da12f40Erik Kline default: 240473355f96b91a1fbeb6f8f8f0bcd3c887da12f40Erik Kline sj.add("type").add(asString(icmp6Type)); 241473355f96b91a1fbeb6f8f8f0bcd3c887da12f40Erik Kline sj.add("code").add(asString(icmp6Code)); 242473355f96b91a1fbeb6f8f8f0bcd3c887da12f40Erik Kline break; 243473355f96b91a1fbeb6f8f8f0bcd3c887da12f40Erik Kline } 244473355f96b91a1fbeb6f8f8f0bcd3c887da12f40Erik Kline } 245473355f96b91a1fbeb6f8f8f0bcd3c887da12f40Erik Kline 246473355f96b91a1fbeb6f8f8f0bcd3c887da12f40Erik Kline private void parseICMPv6RouterSolicitation(StringJoiner sj) { 247473355f96b91a1fbeb6f8f8f0bcd3c887da12f40Erik Kline final int RESERVED = 4; 248473355f96b91a1fbeb6f8f8f0bcd3c887da12f40Erik Kline if (mPacket.remaining() < RESERVED) { 249473355f96b91a1fbeb6f8f8f0bcd3c887da12f40Erik Kline sj.add("runt:").add(asString(mPacket.remaining())); 250473355f96b91a1fbeb6f8f8f0bcd3c887da12f40Erik Kline return; 251473355f96b91a1fbeb6f8f8f0bcd3c887da12f40Erik Kline } 252473355f96b91a1fbeb6f8f8f0bcd3c887da12f40Erik Kline 253473355f96b91a1fbeb6f8f8f0bcd3c887da12f40Erik Kline mPacket.position(mPacket.position() + RESERVED); 254473355f96b91a1fbeb6f8f8f0bcd3c887da12f40Erik Kline parseICMPv6NeighborDiscoveryOptions(sj); 255473355f96b91a1fbeb6f8f8f0bcd3c887da12f40Erik Kline } 256473355f96b91a1fbeb6f8f8f0bcd3c887da12f40Erik Kline 257473355f96b91a1fbeb6f8f8f0bcd3c887da12f40Erik Kline private void parseICMPv6RouterAdvertisement(StringJoiner sj) { 258473355f96b91a1fbeb6f8f8f0bcd3c887da12f40Erik Kline final int FLAGS_AND_TIMERS = 3 * 4; 259473355f96b91a1fbeb6f8f8f0bcd3c887da12f40Erik Kline if (mPacket.remaining() < FLAGS_AND_TIMERS) { 260473355f96b91a1fbeb6f8f8f0bcd3c887da12f40Erik Kline sj.add("runt:").add(asString(mPacket.remaining())); 261473355f96b91a1fbeb6f8f8f0bcd3c887da12f40Erik Kline return; 262473355f96b91a1fbeb6f8f8f0bcd3c887da12f40Erik Kline } 263473355f96b91a1fbeb6f8f8f0bcd3c887da12f40Erik Kline 264473355f96b91a1fbeb6f8f8f0bcd3c887da12f40Erik Kline mPacket.position(mPacket.position() + FLAGS_AND_TIMERS); 265473355f96b91a1fbeb6f8f8f0bcd3c887da12f40Erik Kline parseICMPv6NeighborDiscoveryOptions(sj); 266473355f96b91a1fbeb6f8f8f0bcd3c887da12f40Erik Kline } 267473355f96b91a1fbeb6f8f8f0bcd3c887da12f40Erik Kline 268473355f96b91a1fbeb6f8f8f0bcd3c887da12f40Erik Kline private void parseICMPv6NeighborMessage(StringJoiner sj) { 269473355f96b91a1fbeb6f8f8f0bcd3c887da12f40Erik Kline final int RESERVED = 4; 270473355f96b91a1fbeb6f8f8f0bcd3c887da12f40Erik Kline final int minReq = RESERVED + IPV6_ADDR_LEN; 271473355f96b91a1fbeb6f8f8f0bcd3c887da12f40Erik Kline if (mPacket.remaining() < minReq) { 272473355f96b91a1fbeb6f8f8f0bcd3c887da12f40Erik Kline sj.add("runt:").add(asString(mPacket.remaining())); 273473355f96b91a1fbeb6f8f8f0bcd3c887da12f40Erik Kline return; 274473355f96b91a1fbeb6f8f8f0bcd3c887da12f40Erik Kline } 275473355f96b91a1fbeb6f8f8f0bcd3c887da12f40Erik Kline 276473355f96b91a1fbeb6f8f8f0bcd3c887da12f40Erik Kline mPacket.position(mPacket.position() + RESERVED); 277473355f96b91a1fbeb6f8f8f0bcd3c887da12f40Erik Kline sj.add(getIPv6AddressString(mPacket)); 278473355f96b91a1fbeb6f8f8f0bcd3c887da12f40Erik Kline parseICMPv6NeighborDiscoveryOptions(sj); 279473355f96b91a1fbeb6f8f8f0bcd3c887da12f40Erik Kline } 280473355f96b91a1fbeb6f8f8f0bcd3c887da12f40Erik Kline 281473355f96b91a1fbeb6f8f8f0bcd3c887da12f40Erik Kline private void parseICMPv6NeighborDiscoveryOptions(StringJoiner sj) { 282473355f96b91a1fbeb6f8f8f0bcd3c887da12f40Erik Kline // All ND options are TLV, where T is one byte and L is one byte equal 283473355f96b91a1fbeb6f8f8f0bcd3c887da12f40Erik Kline // to the length of T + L + V in units of 8 octets. 284473355f96b91a1fbeb6f8f8f0bcd3c887da12f40Erik Kline while (mPacket.remaining() >= ICMPV6_ND_OPTION_MIN_LENGTH) { 285473355f96b91a1fbeb6f8f8f0bcd3c887da12f40Erik Kline final int ndType = asUint(mPacket.get()); 286473355f96b91a1fbeb6f8f8f0bcd3c887da12f40Erik Kline final int ndLength = asUint(mPacket.get()); 287473355f96b91a1fbeb6f8f8f0bcd3c887da12f40Erik Kline final int ndBytes = ndLength * ICMPV6_ND_OPTION_LENGTH_SCALING_FACTOR - 2; 2882f157c421a9fa15660b8f1bc0c64b1ebb45fa64aLorenzo Colitti if (ndBytes < 0 || ndBytes > mPacket.remaining()) { 2892f157c421a9fa15660b8f1bc0c64b1ebb45fa64aLorenzo Colitti sj.add("<malformed>"); 2902f157c421a9fa15660b8f1bc0c64b1ebb45fa64aLorenzo Colitti break; 2912f157c421a9fa15660b8f1bc0c64b1ebb45fa64aLorenzo Colitti } 292473355f96b91a1fbeb6f8f8f0bcd3c887da12f40Erik Kline final int position = mPacket.position(); 293473355f96b91a1fbeb6f8f8f0bcd3c887da12f40Erik Kline 294473355f96b91a1fbeb6f8f8f0bcd3c887da12f40Erik Kline switch (ndType) { 295473355f96b91a1fbeb6f8f8f0bcd3c887da12f40Erik Kline case ICMPV6_ND_OPTION_SLLA: 296473355f96b91a1fbeb6f8f8f0bcd3c887da12f40Erik Kline sj.add("slla"); 297473355f96b91a1fbeb6f8f8f0bcd3c887da12f40Erik Kline sj.add(getMacAddressString(mPacket)); 298473355f96b91a1fbeb6f8f8f0bcd3c887da12f40Erik Kline break; 299473355f96b91a1fbeb6f8f8f0bcd3c887da12f40Erik Kline case ICMPV6_ND_OPTION_TLLA: 300473355f96b91a1fbeb6f8f8f0bcd3c887da12f40Erik Kline sj.add("tlla"); 301473355f96b91a1fbeb6f8f8f0bcd3c887da12f40Erik Kline sj.add(getMacAddressString(mPacket)); 302473355f96b91a1fbeb6f8f8f0bcd3c887da12f40Erik Kline break; 303473355f96b91a1fbeb6f8f8f0bcd3c887da12f40Erik Kline case ICMPV6_ND_OPTION_MTU: 304473355f96b91a1fbeb6f8f8f0bcd3c887da12f40Erik Kline sj.add("mtu"); 305473355f96b91a1fbeb6f8f8f0bcd3c887da12f40Erik Kline final short reserved = mPacket.getShort(); 306473355f96b91a1fbeb6f8f8f0bcd3c887da12f40Erik Kline sj.add(asString(mPacket.getInt())); 307473355f96b91a1fbeb6f8f8f0bcd3c887da12f40Erik Kline break; 308473355f96b91a1fbeb6f8f8f0bcd3c887da12f40Erik Kline default: 309473355f96b91a1fbeb6f8f8f0bcd3c887da12f40Erik Kline // Skip. 310473355f96b91a1fbeb6f8f8f0bcd3c887da12f40Erik Kline break; 311473355f96b91a1fbeb6f8f8f0bcd3c887da12f40Erik Kline } 312473355f96b91a1fbeb6f8f8f0bcd3c887da12f40Erik Kline 313473355f96b91a1fbeb6f8f8f0bcd3c887da12f40Erik Kline mPacket.position(position + ndBytes); 314473355f96b91a1fbeb6f8f8f0bcd3c887da12f40Erik Kline } 315473355f96b91a1fbeb6f8f8f0bcd3c887da12f40Erik Kline } 316473355f96b91a1fbeb6f8f8f0bcd3c887da12f40Erik Kline 317473355f96b91a1fbeb6f8f8f0bcd3c887da12f40Erik Kline private void parseUDP(StringJoiner sj) { 318473355f96b91a1fbeb6f8f8f0bcd3c887da12f40Erik Kline if (mPacket.remaining() < UDP_HEADER_LEN) { 319473355f96b91a1fbeb6f8f8f0bcd3c887da12f40Erik Kline sj.add("runt:").add(asString(mPacket.remaining())); 320473355f96b91a1fbeb6f8f8f0bcd3c887da12f40Erik Kline return; 321473355f96b91a1fbeb6f8f8f0bcd3c887da12f40Erik Kline } 322473355f96b91a1fbeb6f8f8f0bcd3c887da12f40Erik Kline 323473355f96b91a1fbeb6f8f8f0bcd3c887da12f40Erik Kline final int previous = mPacket.position(); 324473355f96b91a1fbeb6f8f8f0bcd3c887da12f40Erik Kline final int srcPort = asUint(mPacket.getShort()); 325473355f96b91a1fbeb6f8f8f0bcd3c887da12f40Erik Kline final int dstPort = asUint(mPacket.getShort()); 326473355f96b91a1fbeb6f8f8f0bcd3c887da12f40Erik Kline sj.add(asString(srcPort)).add(">").add(asString(dstPort)); 327473355f96b91a1fbeb6f8f8f0bcd3c887da12f40Erik Kline 328473355f96b91a1fbeb6f8f8f0bcd3c887da12f40Erik Kline mPacket.position(previous + UDP_HEADER_LEN); 329473355f96b91a1fbeb6f8f8f0bcd3c887da12f40Erik Kline if (srcPort == DHCP4_CLIENT_PORT || dstPort == DHCP4_CLIENT_PORT) { 330473355f96b91a1fbeb6f8f8f0bcd3c887da12f40Erik Kline sj.add("dhcp4"); 331473355f96b91a1fbeb6f8f8f0bcd3c887da12f40Erik Kline parseDHCPv4(sj); 332473355f96b91a1fbeb6f8f8f0bcd3c887da12f40Erik Kline } 333473355f96b91a1fbeb6f8f8f0bcd3c887da12f40Erik Kline } 334473355f96b91a1fbeb6f8f8f0bcd3c887da12f40Erik Kline 335473355f96b91a1fbeb6f8f8f0bcd3c887da12f40Erik Kline private void parseDHCPv4(StringJoiner sj) { 336473355f96b91a1fbeb6f8f8f0bcd3c887da12f40Erik Kline final DhcpPacket dhcpPacket; 337473355f96b91a1fbeb6f8f8f0bcd3c887da12f40Erik Kline try { 338473355f96b91a1fbeb6f8f8f0bcd3c887da12f40Erik Kline dhcpPacket = DhcpPacket.decodeFullPacket(mBytes, mLength, DhcpPacket.ENCAP_L2); 339473355f96b91a1fbeb6f8f8f0bcd3c887da12f40Erik Kline sj.add(dhcpPacket.toString()); 340473355f96b91a1fbeb6f8f8f0bcd3c887da12f40Erik Kline } catch (DhcpPacket.ParseException e) { 341473355f96b91a1fbeb6f8f8f0bcd3c887da12f40Erik Kline sj.add("parse error: " + e); 342473355f96b91a1fbeb6f8f8f0bcd3c887da12f40Erik Kline } 343473355f96b91a1fbeb6f8f8f0bcd3c887da12f40Erik Kline } 344473355f96b91a1fbeb6f8f8f0bcd3c887da12f40Erik Kline 345473355f96b91a1fbeb6f8f8f0bcd3c887da12f40Erik Kline private static String getIPv4AddressString(ByteBuffer ipv4) { 346473355f96b91a1fbeb6f8f8f0bcd3c887da12f40Erik Kline return getIpAddressString(ipv4, IPV4_ADDR_LEN); 347473355f96b91a1fbeb6f8f8f0bcd3c887da12f40Erik Kline } 348473355f96b91a1fbeb6f8f8f0bcd3c887da12f40Erik Kline 349473355f96b91a1fbeb6f8f8f0bcd3c887da12f40Erik Kline private static String getIPv6AddressString(ByteBuffer ipv6) { 350473355f96b91a1fbeb6f8f8f0bcd3c887da12f40Erik Kline return getIpAddressString(ipv6, IPV6_ADDR_LEN); 351473355f96b91a1fbeb6f8f8f0bcd3c887da12f40Erik Kline } 352473355f96b91a1fbeb6f8f8f0bcd3c887da12f40Erik Kline 353473355f96b91a1fbeb6f8f8f0bcd3c887da12f40Erik Kline private static String getIpAddressString(ByteBuffer ip, int byteLength) { 354473355f96b91a1fbeb6f8f8f0bcd3c887da12f40Erik Kline if (ip == null || ip.remaining() < byteLength) return "invalid"; 355473355f96b91a1fbeb6f8f8f0bcd3c887da12f40Erik Kline 356473355f96b91a1fbeb6f8f8f0bcd3c887da12f40Erik Kline byte[] bytes = new byte[byteLength]; 357473355f96b91a1fbeb6f8f8f0bcd3c887da12f40Erik Kline ip.get(bytes, 0, byteLength); 358473355f96b91a1fbeb6f8f8f0bcd3c887da12f40Erik Kline try { 359473355f96b91a1fbeb6f8f8f0bcd3c887da12f40Erik Kline InetAddress addr = InetAddress.getByAddress(bytes); 360473355f96b91a1fbeb6f8f8f0bcd3c887da12f40Erik Kline return addr.getHostAddress(); 361473355f96b91a1fbeb6f8f8f0bcd3c887da12f40Erik Kline } catch (UnknownHostException uhe) { 362473355f96b91a1fbeb6f8f8f0bcd3c887da12f40Erik Kline return "unknown"; 363473355f96b91a1fbeb6f8f8f0bcd3c887da12f40Erik Kline } 364473355f96b91a1fbeb6f8f8f0bcd3c887da12f40Erik Kline } 365473355f96b91a1fbeb6f8f8f0bcd3c887da12f40Erik Kline 366473355f96b91a1fbeb6f8f8f0bcd3c887da12f40Erik Kline private static String getMacAddressString(ByteBuffer mac) { 367473355f96b91a1fbeb6f8f8f0bcd3c887da12f40Erik Kline if (mac == null || mac.remaining() < ETHER_ADDR_LEN) return "invalid"; 368473355f96b91a1fbeb6f8f8f0bcd3c887da12f40Erik Kline 369473355f96b91a1fbeb6f8f8f0bcd3c887da12f40Erik Kline byte[] bytes = new byte[ETHER_ADDR_LEN]; 370473355f96b91a1fbeb6f8f8f0bcd3c887da12f40Erik Kline mac.get(bytes, 0, bytes.length); 3711a4f618812880c2fa4156576da1b7c3c773b52aaErik Kline Object[] printableBytes = new Object[bytes.length]; 372473355f96b91a1fbeb6f8f8f0bcd3c887da12f40Erik Kline int i = 0; 3731a4f618812880c2fa4156576da1b7c3c773b52aaErik Kline for (byte b : bytes) printableBytes[i++] = new Byte(b); 374473355f96b91a1fbeb6f8f8f0bcd3c887da12f40Erik Kline 375473355f96b91a1fbeb6f8f8f0bcd3c887da12f40Erik Kline final String MAC48_FORMAT = "%02x:%02x:%02x:%02x:%02x:%02x"; 376473355f96b91a1fbeb6f8f8f0bcd3c887da12f40Erik Kline return String.format(MAC48_FORMAT, printableBytes); 377473355f96b91a1fbeb6f8f8f0bcd3c887da12f40Erik Kline } 378473355f96b91a1fbeb6f8f8f0bcd3c887da12f40Erik Kline} 379