package com.netifera.platform.net.packets.decoders; import java.nio.ByteBuffer; import com.netifera.platform.net.packets.AbstractPacket; import com.netifera.platform.net.packets.IPacketDecoder; import com.netifera.platform.net.packets.IPacketHeader; import com.netifera.platform.net.packets.PacketPayload; import com.netifera.platform.net.packets.link.ARP; import com.netifera.platform.util.NetworkConstants; /** * A decoder implementation which can interpret various link types without fully parsing the * link headers. Only the information which is needed to find the higher level protocols is * examined and only the higher level protocols are fully parsed. * * The following link layer types are currently supported: * * <ul> * <li> DLT_IEEE802 </li> * <li> DLT_IEEE802_11 </li> * <li> DLT_IEEE802_11_RADIO </li> * <li> DLT_LINUX_SLL </li> * <li> DLT_PRISM_HEADER </li> * </ul> * */ public class GenericDecoder implements IPacketDecoder { private final static IPDecoder ipDecoder = new IPDecoder(); // FIXME use pcap package? ; Datalink.DLT_IEEE802_11, ... private final static int DLT_IEEE802 = 6; private final static int DLT_IEEE802_11 = 105; private final static int DLT_LINUX_SLL = 113; private final static int DLT_PRISM_HEADER = 119; private final static int DLT_IEEE802_11_RADIO = 127; private final static int DATA_FRAME = 2; private final static int FLAG_TO_DS = 0x01; private final static int FLAG_FROM_DS = 0x02; private final static int WIFI_DATA_MINSIZE = 52; private final static int LLC_DATA_MINSIZE = 28; private final static int LINUX_COOKED_DATA_MINSIZE = 16; private final static int PRISM_DATA_MINSIZE = 0x90; private final int datalink; public static GenericDecoder createForDatalink(int dlt) { switch(dlt) { case DLT_IEEE802: case DLT_IEEE802_11: case DLT_IEEE802_11_RADIO: case DLT_LINUX_SLL: case DLT_PRISM_HEADER: return new GenericDecoder(dlt); default: return null; } } private GenericDecoder(int datalink) { this.datalink = datalink; } public IPacketHeader decode(ByteBuffer buffer) { switch(datalink) { case DLT_IEEE802: case DLT_IEEE802_11: return decodeWifi(buffer.slice()); case DLT_IEEE802_11_RADIO: return decodeRadiotap(buffer.slice()); case DLT_LINUX_SLL: return decodeLinuxCooked(buffer.slice()); case DLT_PRISM_HEADER: return decodePrism(buffer.slice()); default: throw new IllegalStateException("Illegal datalink in GenericDecoder"); } } private IPacketHeader decodeWifi(ByteBuffer buffer) { if(buffer.remaining() < WIFI_DATA_MINSIZE) { return new PacketPayload(buffer); } int x = buffer.get(0) & 0xff; int mainType = (x & 0x0c) >> 2; // If it's not a data frame just return it all in a payload if(mainType != DATA_FRAME) { return new PacketPayload(buffer); } x = buffer.get(1) & 0xff; int offset = 24; if( ((x & FLAG_FROM_DS) != 0) && ((x & FLAG_TO_DS) != 0) ) { offset += 6; } buffer.position( buffer.position() + offset); return decodeLLC(buffer.slice()); } private IPacketHeader decodeRadiotap(ByteBuffer buffer) { // TODO check size buffer.getShort(); // skip version, pad int len = AbstractPacket.swap16(buffer.getShort() & 0xFFFF); if(len < 8 || len > buffer.remaining()) { buffer.rewind(); return new PacketPayload(buffer); } buffer.position( buffer.position() + len ); return decodeWifi(buffer.slice()); } private IPacketHeader decodePrism(ByteBuffer buffer) { if(buffer.remaining() < PRISM_DATA_MINSIZE) { return new PacketPayload(buffer); } buffer.position( buffer.position() + PRISM_DATA_MINSIZE ); return decodeWifi(buffer.slice()); } private IPacketHeader decodeLinuxCooked(ByteBuffer buffer) { if(buffer.remaining() < LINUX_COOKED_DATA_MINSIZE) { return new PacketPayload(buffer); } buffer.position( buffer.position() + 14); return decodeProto(buffer, buffer.getShort() & 0xFFFF); } private IPacketHeader decodeLLC(ByteBuffer buffer) { if(buffer.remaining() < LLC_DATA_MINSIZE) { return new PacketPayload(buffer); } buffer.position( buffer.position() + 6); final int protocol = buffer.getShort() & 0xFFFF; return decodeProto(buffer, protocol); } private IPacketHeader decodeProto(ByteBuffer buffer, int protocol) { switch(protocol) { case NetworkConstants.ETHERTYPE_ARP: final IPacketHeader arp = new ARP(); if(arp.unpack(buffer.slice())) { return arp; } return new PacketPayload(buffer.slice()); case NetworkConstants.ETHERTYPE_IPv4: return ipDecoder.getIPv4Decoder().decode(buffer.slice()); case NetworkConstants.ETHERTYPE_IPv6: return ipDecoder.getIPv6Decoder().decode(buffer.slice()); default: return new PacketPayload(buffer.slice()); } } }