/******************************************************************************* * gMix open source project - https://svs.informatik.uni-hamburg.de/gmix/ * Copyright (C) 2014 SVS * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. *******************************************************************************/ package staticContent.evaluation.traceParser.engine.protocolHeaderParser; import java.net.InetAddress; import java.net.UnknownHostException; import java.util.Arrays; import java.util.Vector; import staticContent.evaluation.traceParser.engine.protocolHeaderParser.IPpacket.IPprotocol; import staticContent.framework.util.Util; public class IPv6Packet { public static int getVersion(byte[] packet) { return (packet[0] & (0xf0)) >> 4; } public static int getTrafficClass(byte[] packet) { int result = Util.unsignedShortToInt(Arrays.copyOfRange(packet, 0, 2)); return (result >> 4) & 0xffff; } public static int getPayloadLengthIncludingExtensionHeaders(byte[] packet) { return Util.unsignedShortToInt(Arrays.copyOfRange(packet, 4, 6)); } public static IPprotocol getProtocol(byte[] packet) { // TODO: skip extension headers if present return IPpacket.getIPprotocolNumberByByte(packet[6]); } public static int getProtocolAsInt(byte[] packet) { return Util.unsignedByteToShort(packet[6]); } public static String getProtocolAsHex(byte[] packet) { return "0x" +String.format("%02X", packet[6]); } public static int getNextHeader(byte[] packet) { return getProtocolAsInt(packet); } public static int getHopLimit(byte[] packet) { return Util.unsignedByteToShort(packet[7]); } public static InetAddress getSrcIP(byte[] packet) { try { return InetAddress.getByAddress(Arrays.copyOfRange(packet, 8, 24)); } catch (UnknownHostException e) { e.printStackTrace(); return null; } } public static String getSrcIPasString(byte[] packet) { try { return InetAddress.getByAddress(Arrays.copyOfRange(packet, 8, 24)).getHostAddress(); } catch (UnknownHostException e) { e.printStackTrace(); return null; } } public static InetAddress getDstIP(byte[] packet) { try { return InetAddress.getByAddress(Arrays.copyOfRange(packet, 24, 40)); } catch (UnknownHostException e) { e.printStackTrace(); return null; } } public static String getDstIPasString(byte[] packet) { try { return InetAddress.getByAddress(Arrays.copyOfRange(packet, 24, 40)).getHostAddress(); } catch (UnknownHostException e) { e.printStackTrace(); return null; } } public static int getHeaderLengthStat(byte[] packet) { if (!IPpacket.isIPv6ExtensionHeader(getProtocolAsInt(packet))) // no extension headers -> return basic length (= 40 bytes) return 40; int headerOffset = 40; while (true) { int type = Util.unsignedByteToShort(packet[headerOffset]); if (IPpacket.isIPv6ExtensionHeader(type)) headerOffset += (8 + Util.unsignedByteToShort(packet[headerOffset+1])); else break; } return headerOffset; } public static boolean containsExtensionHeader(byte[] packet) { return IPpacket.isIPv6ExtensionHeader(getProtocolAsInt(packet)); } public static byte[][] getExtensionHeaders(byte[] packet) { if (!containsExtensionHeader(packet)) return null; Vector<byte[]> extensionHeaders = new Vector<byte[]>(); int headerOffset = 40; while (true) { int type = Util.unsignedByteToShort(packet[headerOffset]); if (IPpacket.isIPv6ExtensionHeader(type)) { int len = 8 + Util.unsignedByteToShort(packet[headerOffset+1]); extensionHeaders.add(Arrays.copyOfRange(packet, headerOffset, headerOffset + len)); headerOffset += len; } else break; } byte[][] result = new byte[extensionHeaders.size()][]; for (int i=0; i<result.length; i++) { result[i] = extensionHeaders.get(i); } return result; } /** * does not count extension headers as payload * @param packet * @return */ public static boolean containsPayload(byte[] packet) { return packet.length > getHeaderLengthStat(packet); } public static byte[] getPayloadStat(byte[] packet) { int totalHeaderLength = getHeaderLengthStat(packet); // including extension headers if (packet.length <= totalHeaderLength) { // truncated packet; no payload return null; } else { int expectedActualPayloadLength = getPayloadLengthWithoutExtensionHeaders(packet); int availableData = packet.length - totalHeaderLength; // might include padding (!) if (availableData == expectedActualPayloadLength) // no padding included return Arrays.copyOfRange(packet, totalHeaderLength, packet.length); else if (availableData < expectedActualPayloadLength) // truncated packet -> return available data only (yes we could exchange "==" with "<=" above, but than the code is less intuitive...) return Arrays.copyOfRange(packet, totalHeaderLength, packet.length); else // availableData < expectedActualPayloadLength -> padding included return Arrays.copyOfRange(packet, totalHeaderLength, totalHeaderLength + expectedActualPayloadLength); } } public static int getPayloadLengthWithoutExtensionHeaders(byte[] packet) { return IPv6Packet.getPayloadLengthIncludingExtensionHeaders(packet) - (getHeaderLengthStat(packet) - 40); // payload length WITHOUT extension headers (40 is the basic header length) as indicated by the payload length field } public static String toString(byte[] packet) { StringBuffer sb = new StringBuffer(); sb.append("IPv6 header: \n"); sb.append(" version: " +IPv6Packet.getVersion(packet) +"\n"); sb.append(" traffic class: " +IPv6Packet.getTrafficClass(packet) +"\n"); sb.append(" payload length (incl. ext. headers): " +IPv6Packet.getPayloadLengthIncludingExtensionHeaders(packet) +"\n"); sb.append(" next header: " +IPv6Packet.getProtocol(packet) +"\n"); sb.append(" hop limit: " +IPv6Packet.getHopLimit(packet) +"\n"); sb.append(" source ip: " +IPv6Packet.getSrcIPasString(packet) +"\n"); sb.append(" destinatin ip: " +IPv6Packet.getDstIPasString(packet) +"\n"); boolean containsExtensionHeaders = IPv6Packet.containsExtensionHeader(packet); sb.append(" contains extension headers: " +containsExtensionHeaders +"\n"); if (containsExtensionHeaders) { byte[][] extensionHeaders = IPv6Packet.getExtensionHeaders(packet); for (int i=0; i<extensionHeaders.length; i++) { sb.append(" header " +i +": " +Util.toHex(extensionHeaders[i]) +"\n"); } } byte[] payload = IPv6Packet.getPayloadStat(packet); if (payload == null) sb.append(" payload: none"); else sb.append(" payload (" +payload.length +" bytes): " +Util.toHex(payload)); return sb.toString(); } }