/******************************************************************************* * 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 staticContent.evaluation.traceParser.engine.protocolHeaderParser.IPpacket.IPprotocol; import staticContent.framework.util.Util; public class IPv4Packet { public static int getVersion(byte[] packet) { return (packet[0] & (0xf0)) >> 4; } public static int getHeaderLengthStat(byte[] packet) { return (packet[0] & (0x0f)) * 4; } public static int getDifferentiatedServicesCodePoint(byte[] packet) { return packet[1] & (0x0f); } public static boolean getECN_CT(byte[] packet) { return Util.getBitAt(1, packet[1]); } public static boolean getECN_CE(byte[] packet) { return Util.getBitAt(0, packet[1]); } /** * header length + payload length in byte */ public static int getTotalLength(byte[] packet) { return Util.unsignedShortToInt(Arrays.copyOfRange(packet, 2, 4)); } public static int getIdentification(byte[] packet) { return Util.unsignedShortToInt(Arrays.copyOfRange(packet, 4, 6)); } public static boolean getFlagsReservedBit(byte[] packet) { return Util.getBitAt(5, packet[6]); } public static boolean getFlagsDontFragment(byte[] packet) { return Util.getBitAt(6, packet[6]); } public static boolean getFlagsMoreFragments(byte[] packet) { return Util.getBitAt(7, packet[6]); } /** * returns thy byte index (not bit index) */ public static int getFragmentOffset(byte[] packet) { return Util.unsignedShortToInt(Arrays.copyOfRange(packet, 6, 8)) & 0x1fff; } public static int getTTL(byte[] packet) { return Util.unsignedByteToShort(packet[8]); } public static IPprotocol getProtocol(byte[] packet) { return IPpacket.getIPprotocolNumberByByte(packet[9]); } public static int getProtocolAsInt(byte[] packet) { return Util.unsignedByteToShort(packet[9]); } public static String getProtocolAsHex(byte[] packet) { return "0x" +String.format("%02X", packet[9]); } public static byte[] getHeaderCheckSum(byte[] packet) { return Arrays.copyOfRange(packet, 10, 12); } public static byte[] calculateHeaderCheckSum(byte[] packet) { int headerLength = getHeaderLengthStat(packet); byte[] header = Arrays.copyOf(packet, headerLength); int result = 0; for (int i=0; i<header.length; i+=2) if (i != 10 && i != 11 ) { // ignore checksum field int pt1 = header[i] & 0xff; int pt2 = (i+1 < header.length) ? (header[i+1] & 0xff) : 0; result += (pt1 << 8) + pt2; } result = (result >> 16) + (result & 0xffff); result = result + (result >> 16); result = ~result & 0xffff; return Arrays.copyOfRange(Util.intToByteArray(result), 2, 4); } public static boolean isHeaderChecksumCorrect(byte[] packet) { return Arrays.equals(getHeaderCheckSum(packet), calculateHeaderCheckSum(packet)); } public static String getSrcIPasString(byte[] packet) { try { return InetAddress.getByAddress(Arrays.copyOfRange(packet, 12, 16)).getHostAddress(); } catch (UnknownHostException e) { e.printStackTrace(); return null; } } public static InetAddress getSrcIP(byte[] packet) { try { return InetAddress.getByAddress(Arrays.copyOfRange(packet, 12, 16)); } catch (UnknownHostException e) { e.printStackTrace(); return null; } } public static String getDstIPasString(byte[] packet) { try { return InetAddress.getByAddress(Arrays.copyOfRange(packet, 16, 20)).getHostAddress(); } catch (UnknownHostException e) { e.printStackTrace(); return null; } } public static InetAddress getDstIP(byte[] packet) { try { return InetAddress.getByAddress(Arrays.copyOfRange(packet, 16, 20)); } catch (UnknownHostException e) { e.printStackTrace(); return null; } } public static boolean hasOptionsSet(byte[] packet) { return getHeaderLengthStat(packet) != 20; } public static byte[] getOptions(byte[] packet) { int optionsLength = getHeaderLengthStat(packet) - 20; if (optionsLength == 0) return null; else return Arrays.copyOfRange(packet, 20, 20+optionsLength); } public static boolean containsPayload(byte[] packet) { return packet.length > getHeaderLengthStat(packet); } public static byte[] getPayloadStat(byte[] packet) { int headerLength = getHeaderLengthStat(packet); if (packet.length - headerLength <= 0) { // truncated packet; no payload return null; } else { // payload or fraction of payload available int expectedPayloadLength = getTotalLength(packet) - headerLength; // length according to header int availableData = packet.length - headerLength; // might include padding (!) if (availableData == expectedPayloadLength) // no padding included return Arrays.copyOfRange(packet, headerLength, packet.length); else if (availableData < expectedPayloadLength) // truncated packet -> return available data only (yes we could exchange "==" with "<=" above, but than the code is less intuitive...) return Arrays.copyOfRange(packet, headerLength, packet.length); else // availableData < expectedPayloadLength -> padding included return Arrays.copyOfRange(packet, headerLength, headerLength + expectedPayloadLength); } } public static int getPayloadLengthStat(byte[] packet) { int headerLength = getHeaderLengthStat(packet); return getTotalLength(packet) - headerLength; // length according to header } public static String toString(byte[] packet) { StringBuffer sb = new StringBuffer(); sb.append("IPv4 header: \n"); sb.append(" version: " +IPv4Packet.getVersion(packet) +"\n"); sb.append(" header length: " +IPv4Packet.getHeaderLengthStat(packet) +" bytes\n"); sb.append(" DSF: " +IPv4Packet.getDifferentiatedServicesCodePoint(packet) +"\n"); sb.append(" total length: " +IPv4Packet.getTotalLength(packet) +"\n"); sb.append(" identification: " +IPv4Packet.getIdentification(packet) +"\n"); sb.append(" don't fragment: " +IPv4Packet.getFlagsDontFragment(packet) +"\n"); sb.append(" more fragments: " +IPv4Packet.getFlagsMoreFragments(packet) +"\n"); sb.append(" fragment offst: " +IPv4Packet.getFragmentOffset(packet) +"\n"); sb.append(" TTL: " +IPv4Packet.getTTL(packet) +"\n"); sb.append(" protocol: " +IPv4Packet.getProtocol(packet) +"\n"); sb.append(" header checksum correct: " +IPv4Packet.isHeaderChecksumCorrect(packet) +"\n"); sb.append(" source ip: " +IPv4Packet.getSrcIPasString(packet) +"\n"); sb.append(" destinatin ip: " +IPv4Packet.getDstIPasString(packet) +"\n"); boolean hasOptions = IPv4Packet.hasOptionsSet(packet); sb.append(" has options set: " +hasOptions +"\n"); if (hasOptions) sb.append("\n options: " +Util.toHex(IPv4Packet.getOptions(packet)) +"\n"); byte[] payload = IPv4Packet.getPayloadStat(packet); if (payload == null) sb.append(" payload: none"); else sb.append(" payload (" +payload.length +" bytes): " +Util.toHex(payload)); return sb.toString(); } }