From: rtrimana <rtrimana@uci.edu> Date: Thu, 26 Apr 2018 17:52:01 +0000 (-0700) Subject: Managed to pick and parse DNS packets; but, still need to get the detailed informatio... X-Git-Url: http://demsky.eecs.uci.edu/git/?a=commitdiff_plain;h=c9c106d26eae359e98d162488a6d667d741a551c;p=pingpong.git Managed to pick and parse DNS packets; but, still need to get the detailed information from inside the packet. --- diff --git a/Code/Projects/SmartPlugDetector/src/main/java/edu/uci/iotproject/DnsPacket.java b/Code/Projects/SmartPlugDetector/src/main/java/edu/uci/iotproject/DnsPacket.java new file mode 100644 index 0000000..f15d0d7 --- /dev/null +++ b/Code/Projects/SmartPlugDetector/src/main/java/edu/uci/iotproject/DnsPacket.java @@ -0,0 +1,522 @@ +// This is a generated file! Please edit source .ksy file and use kaitai-struct-compiler to rebuild +package edu.uci.iotproject; + +import io.kaitai.struct.ByteBufferKaitaiStream; +import io.kaitai.struct.KaitaiStruct; +import io.kaitai.struct.KaitaiStream; +import java.io.IOException; +import java.util.Map; +import java.util.HashMap; +import java.util.ArrayList; +import java.nio.charset.Charset; + +import java.nio.BufferUnderflowException; + + +/** + * (No support for Auth-Name + Add-Name for simplicity) + */ +public class DnsPacket extends KaitaiStruct { + public static DnsPacket fromFile(String fileName) throws IOException { + return new DnsPacket(new ByteBufferKaitaiStream(fileName)); + } + + public enum ClassType { + IN_CLASS(1), + CS(2), + CH(3), + HS(4); + + private final long id; + ClassType(long id) { this.id = id; } + public long id() { return id; } + private static final Map<Long, ClassType> byId = new HashMap<Long, ClassType>(4); + static { + for (ClassType e : ClassType.values()) + byId.put(e.id(), e); + } + public static ClassType byId(long id) { return byId.get(id); } + } + + public enum TypeType { + A(1), + NS(2), + MD(3), + MF(4), + CNAME(5), + SOE(6), + MB(7), + MG(8), + MR(9), + NULL(10), + WKS(11), + PTR(12), + HINFO(13), + MINFO(14), + MX(15), + TXT(16); + + private final long id; + TypeType(long id) { this.id = id; } + public long id() { return id; } + private static final Map<Long, TypeType> byId = new HashMap<Long, TypeType>(16); + static { + for (TypeType e : TypeType.values()) + byId.put(e.id(), e); + } + public static TypeType byId(long id) { return byId.get(id); } + } + + public DnsPacket(KaitaiStream _io) { + this(_io, null, null); + } + + public DnsPacket(KaitaiStream _io, KaitaiStruct _parent) { + this(_io, _parent, null); + } + + public DnsPacket(KaitaiStream _io, KaitaiStruct _parent, DnsPacket _root) { + super(_io); + this._parent = _parent; + this._root = _root == null ? this : _root; + _read(); + } + private void _read() { + this.transactionId = this._io.readU2be(); + this.flags = new PacketFlags(this._io, this, _root); + this.qdcount = this._io.readU2be(); + this.ancount = this._io.readU2be(); + this.nscount = this._io.readU2be(); + this.arcount = this._io.readU2be(); + queries = new ArrayList<Query>((int) (qdcount())); + for (int i = 0; i < qdcount(); i++) { + this.queries.add(new Query(this._io, this, _root)); + } + answers = new ArrayList<Answer>((int) (ancount())); + for (int i = 0; i < ancount(); i++) { + this.answers.add(new Answer(this._io, this, _root)); + } + } + public static class PointerStruct extends KaitaiStruct { + public static PointerStruct fromFile(String fileName) throws IOException { + return new PointerStruct(new ByteBufferKaitaiStream(fileName)); + } + + public PointerStruct(KaitaiStream _io) { + this(_io, null, null); + } + + public PointerStruct(KaitaiStream _io, DnsPacket.Label _parent) { + this(_io, _parent, null); + } + + public PointerStruct(KaitaiStream _io, DnsPacket.Label _parent, DnsPacket _root) { + super(_io); + this._parent = _parent; + this._root = _root; + _read(); + } + private void _read() { + this.value = this._io.readU1(); + } + private DomainName contents; + public DomainName contents() { + if (this.contents != null) + return this.contents; + KaitaiStream io = _root._io(); + long _pos = io.pos(); + io.seek(value()); + this.contents = new DomainName(io, this, _root); + io.seek(_pos); + return this.contents; + } + private int value; + private DnsPacket _root; + private DnsPacket.Label _parent; + + /** + * Read one byte, then offset to that position, read one domain-name and return + */ + public int value() { return value; } + public DnsPacket _root() { return _root; } + public DnsPacket.Label _parent() { return _parent; } + } + public static class Label extends KaitaiStruct { + public static Label fromFile(String fileName) throws IOException { + return new Label(new ByteBufferKaitaiStream(fileName)); + } + + public Label(KaitaiStream _io) { + this(_io, null, null); + } + + public Label(KaitaiStream _io, DnsPacket.DomainName _parent) { + this(_io, _parent, null); + } + + public Label(KaitaiStream _io, DnsPacket.DomainName _parent, DnsPacket _root) { + super(_io); + this._parent = _parent; + this._root = _root; + _read(); + } + private void _read() { + this.length = this._io.readU1(); + if (isPointer()) { + this.pointer = new PointerStruct(this._io, this, _root); + } + // TODO: This part causes BufferUnderflowException + if (!(isPointer())) { + try { + this.name = new String(this._io.readBytes(length()), Charset.forName("ASCII")); + } catch (BufferUnderflowException ex) { + //ex.printStackTrace(); + this.name = null; + } + } + } + private Boolean isPointer; + public Boolean isPointer() { + if (this.isPointer != null) + return this.isPointer; + boolean _tmp = (boolean) (length() == 192); + this.isPointer = _tmp; + return this.isPointer; + } + private int length; + private PointerStruct pointer; + private String name; + private DnsPacket _root; + private DnsPacket.DomainName _parent; + + /** + * RFC1035 4.1.4: If the first two bits are raised it's a pointer-offset to a previously defined name + */ + public int length() { return length; } + public PointerStruct pointer() { return pointer; } + + /** + * Otherwise its a string the length of the length value + */ + public String name() { return name; } + public DnsPacket _root() { return _root; } + public DnsPacket.DomainName _parent() { return _parent; } + } + public static class Query extends KaitaiStruct { + public static Query fromFile(String fileName) throws IOException { + return new Query(new ByteBufferKaitaiStream(fileName)); + } + + public Query(KaitaiStream _io) { + this(_io, null, null); + } + + public Query(KaitaiStream _io, DnsPacket _parent) { + this(_io, _parent, null); + } + + public Query(KaitaiStream _io, DnsPacket _parent, DnsPacket _root) { + super(_io); + this._parent = _parent; + this._root = _root; + _read(); + } + private void _read() { + this.name = new DomainName(this._io, this, _root); + this.type = DnsPacket.TypeType.byId(this._io.readU2be()); + this.queryClass = DnsPacket.ClassType.byId(this._io.readU2be()); + } + private DomainName name; + private TypeType type; + private ClassType queryClass; + private DnsPacket _root; + private DnsPacket _parent; + public DomainName name() { return name; } + public TypeType type() { return type; } + public ClassType queryClass() { return queryClass; } + public DnsPacket _root() { return _root; } + public DnsPacket _parent() { return _parent; } + } + public static class DomainName extends KaitaiStruct { + public static DomainName fromFile(String fileName) throws IOException { + return new DomainName(new ByteBufferKaitaiStream(fileName)); + } + + public DomainName(KaitaiStream _io) { + this(_io, null, null); + } + + public DomainName(KaitaiStream _io, KaitaiStruct _parent) { + this(_io, _parent, null); + } + + public DomainName(KaitaiStream _io, KaitaiStruct _parent, DnsPacket _root) { + super(_io); + this._parent = _parent; + this._root = _root; + _read(); + } + private void _read() { + this.name = new ArrayList<Label>(); + { + Label _it; + int i = 0; + do { + _it = new Label(this._io, this, _root); + this.name.add(_it); + i++; + } while (!( ((_it.length() == 0) || (_it.length() == 192)) )); + } + } + private ArrayList<Label> name; + private DnsPacket _root; + private KaitaiStruct _parent; + + /** + * Repeat until the length is 0 or it is a pointer (bit-hack to get around lack of OR operator) + */ + public ArrayList<Label> name() { return name; } + public DnsPacket _root() { return _root; } + public KaitaiStruct _parent() { return _parent; } + } + public static class Address extends KaitaiStruct { + public static Address fromFile(String fileName) throws IOException { + return new Address(new ByteBufferKaitaiStream(fileName)); + } + + public Address(KaitaiStream _io) { + this(_io, null, null); + } + + public Address(KaitaiStream _io, DnsPacket.Answer _parent) { + this(_io, _parent, null); + } + + public Address(KaitaiStream _io, DnsPacket.Answer _parent, DnsPacket _root) { + super(_io); + this._parent = _parent; + this._root = _root; + _read(); + } + private void _read() { + ip = new ArrayList<Integer>((int) (4)); + for (int i = 0; i < 4; i++) { + this.ip.add(this._io.readU1()); + } + } + private ArrayList<Integer> ip; + private DnsPacket _root; + private DnsPacket.Answer _parent; + public ArrayList<Integer> ip() { return ip; } + public DnsPacket _root() { return _root; } + public DnsPacket.Answer _parent() { return _parent; } + } + public static class Answer extends KaitaiStruct { + public static Answer fromFile(String fileName) throws IOException { + return new Answer(new ByteBufferKaitaiStream(fileName)); + } + + public Answer(KaitaiStream _io) { + this(_io, null, null); + } + + public Answer(KaitaiStream _io, DnsPacket _parent) { + this(_io, _parent, null); + } + + public Answer(KaitaiStream _io, DnsPacket _parent, DnsPacket _root) { + super(_io); + this._parent = _parent; + this._root = _root; + _read(); + } + private void _read() { + this.name = new DomainName(this._io, this, _root); + this.type = DnsPacket.TypeType.byId(this._io.readU2be()); + this.answerClass = DnsPacket.ClassType.byId(this._io.readU2be()); + this.ttl = this._io.readS4be(); + this.rdlength = this._io.readU2be(); + if (type() == DnsPacket.TypeType.PTR) { + this.ptrdname = new DomainName(this._io, this, _root); + } + if (type() == DnsPacket.TypeType.A) { + this.address = new Address(this._io, this, _root); + } + } + private DomainName name; + private TypeType type; + private ClassType answerClass; + private int ttl; + private int rdlength; + private DomainName ptrdname; + private Address address; + private DnsPacket _root; + private DnsPacket _parent; + public DomainName name() { return name; } + public TypeType type() { return type; } + public ClassType answerClass() { return answerClass; } + + /** + * Time to live (in seconds) + */ + public int ttl() { return ttl; } + + /** + * Length in octets of the following payload + */ + public int rdlength() { return rdlength; } + public DomainName ptrdname() { return ptrdname; } + public Address address() { return address; } + public DnsPacket _root() { return _root; } + public DnsPacket _parent() { return _parent; } + } + public static class PacketFlags extends KaitaiStruct { + public static PacketFlags fromFile(String fileName) throws IOException { + return new PacketFlags(new ByteBufferKaitaiStream(fileName)); + } + + public PacketFlags(KaitaiStream _io) { + this(_io, null, null); + } + + public PacketFlags(KaitaiStream _io, DnsPacket _parent) { + this(_io, _parent, null); + } + + public PacketFlags(KaitaiStream _io, DnsPacket _parent, DnsPacket _root) { + super(_io); + this._parent = _parent; + this._root = _root; + _read(); + } + private void _read() { + this.flag = this._io.readU2be(); + } + private Integer qr; + public Integer qr() { + if (this.qr != null) + return this.qr; + int _tmp = (int) (((flag() & 32768) >> 15)); + this.qr = _tmp; + return this.qr; + } + private Integer ra; + public Integer ra() { + if (this.ra != null) + return this.ra; + int _tmp = (int) (((flag() & 128) >> 7)); + this.ra = _tmp; + return this.ra; + } + private Integer tc; + public Integer tc() { + if (this.tc != null) + return this.tc; + int _tmp = (int) (((flag() & 512) >> 9)); + this.tc = _tmp; + return this.tc; + } + private Integer rcode; + public Integer rcode() { + if (this.rcode != null) + return this.rcode; + int _tmp = (int) (((flag() & 15) >> 0)); + this.rcode = _tmp; + return this.rcode; + } + private Integer opcode; + public Integer opcode() { + if (this.opcode != null) + return this.opcode; + int _tmp = (int) (((flag() & 30720) >> 11)); + this.opcode = _tmp; + return this.opcode; + } + private Integer aa; + public Integer aa() { + if (this.aa != null) + return this.aa; + int _tmp = (int) (((flag() & 1024) >> 10)); + this.aa = _tmp; + return this.aa; + } + private Integer z; + public Integer z() { + if (this.z != null) + return this.z; + int _tmp = (int) (((flag() & 64) >> 6)); + this.z = _tmp; + return this.z; + } + private Integer rd; + public Integer rd() { + if (this.rd != null) + return this.rd; + int _tmp = (int) (((flag() & 256) >> 8)); + this.rd = _tmp; + return this.rd; + } + private Integer cd; + public Integer cd() { + if (this.cd != null) + return this.cd; + int _tmp = (int) (((flag() & 16) >> 4)); + this.cd = _tmp; + return this.cd; + } + private Integer ad; + public Integer ad() { + if (this.ad != null) + return this.ad; + int _tmp = (int) (((flag() & 32) >> 5)); + this.ad = _tmp; + return this.ad; + } + private int flag; + private DnsPacket _root; + private DnsPacket _parent; + public int flag() { return flag; } + public DnsPacket _root() { return _root; } + public DnsPacket _parent() { return _parent; } + } + private int transactionId; + private PacketFlags flags; + private int qdcount; + private int ancount; + private int nscount; + private int arcount; + private ArrayList<Query> queries; + private ArrayList<Answer> answers; + private DnsPacket _root; + private KaitaiStruct _parent; + + /** + * ID to keep track of request/responces + */ + public int transactionId() { return transactionId; } + public PacketFlags flags() { return flags; } + + /** + * How many questions are there + */ + public int qdcount() { return qdcount; } + + /** + * Number of resource records answering the question + */ + public int ancount() { return ancount; } + + /** + * Number of resource records pointing toward an authority + */ + public int nscount() { return nscount; } + + /** + * Number of resource records holding additional information + */ + public int arcount() { return arcount; } + public ArrayList<Query> queries() { return queries; } + public ArrayList<Answer> answers() { return answers; } + public DnsPacket _root() { return _root; } + public KaitaiStruct _parent() { return _parent; } +} diff --git a/Code/Projects/SmartPlugDetector/src/main/java/edu/uci/iotproject/Main.java b/Code/Projects/SmartPlugDetector/src/main/java/edu/uci/iotproject/Main.java index 44085c3..4892c24 100644 --- a/Code/Projects/SmartPlugDetector/src/main/java/edu/uci/iotproject/Main.java +++ b/Code/Projects/SmartPlugDetector/src/main/java/edu/uci/iotproject/Main.java @@ -1,30 +1,121 @@ package edu.uci.iotproject; +import io.kaitai.struct.ByteBufferKaitaiStream; +import io.kaitai.struct.KaitaiStruct; +import io.kaitai.struct.KaitaiStream; +import java.io.IOException; import java.util.ArrayList; import java.util.List; +import java.util.HashMap; import java.util.Map; /** - * Entry point of the application. + * This is a system that reads PCAP files to compare + * patterns of DNS hostnames, packet sequences, and packet + * lengths with training data to determine certain events + * or actions for smart home devices. * * @author Janus Varmarken + * @author Rahmadi Trimananda (rtrimana@uci.edu) + * @version 0.1 */ public class Main { - private static int counter = 0; - public static void main(String[] args) throws Exception { + + /** + * Private class properties + */ + private Pcap pcap; + private List<Pcap.Packet> listPacket; + private Map<String, List<byte[]>> mapHostnamesToIPAddresses; + + /** + * Private class constants + */ + private static final int DNS_PORT = 53; + + /** + * Constructor + * + * @param file name of the analyzed PCAP file + */ + public Main(String file) throws IOException { + + pcap = Pcap.fromFile(file); + listPacket = pcap.packets(); + mapHostnamesToIPAddresses = new HashMap<String, List<byte[]>>(); + } + + + /** + * Private method that maps DNS hostnames to their + * respected IP addresses. This method iterates + * through the List<Pcap.Packet>, gets DNS packets, + * and gets the IP addresses associated with them. + */ + private void mapHostnamesToIPAddresses() { + + int counter = 1; + for(Pcap.Packet packet : listPacket) { + System.out.print("# " + counter++); + // Check the packet type + if (packet._root().hdr().network() == Pcap.Linktype.ETHERNET) { + EthernetFrame ethFrame = (EthernetFrame) packet.body(); + if (ethFrame.etherType() == EthernetFrame.EtherTypeEnum.IPV4) { + Ipv4Packet ip4Packet = (Ipv4Packet) ethFrame.body(); + + System.out.print(" - Protocol: " + ip4Packet.protocol()); + + if (ip4Packet.protocol() == Ipv4Packet.ProtocolEnum.UDP) { + // DNS is UDP port 53 + UdpDatagram udpData = (UdpDatagram) ip4Packet.body(); + System.out.print(" - Source Port: " + udpData.srcPort()); + System.out.print(" - Dest Port: " + udpData.dstPort()); + + // Source port 53 means this is DNS response + if (udpData.srcPort() == DNS_PORT) { + KaitaiStream dnsStream = new ByteBufferKaitaiStream(udpData.body()); + DnsPacket dnsPacket = new DnsPacket(dnsStream); + ArrayList<DnsPacket.Answer> answers = dnsPacket.answers(); + System.out.print(" - this DNS packet has " + answers.size() + " answers."); + } + } + } + } + System.out.println(); + } + } + + /*private String cloudIPAddress(String hostName) { + if (hostName.equals("events.tplinkra.com")) + return "205.251.203.26"; + else + return null; + }*/ + + // TODO move to separate class + // Add parameter that is the trace to be analyzed (most like the pcap library's representation of a flow) + public String findPattern(Map<String, List<Integer>> hostnameToPacketLengths, String smartPlugIp) { + + // No difference, output "Complete match" + // If difference, output <Packet no, deviation from expected> for each packet + return null; + } + + public static void main(String[] args) { System.out.println("it works"); //String file = "/scratch/traffic_measurements/Switches-Feb2018/wemo/wlan1/wlan1.setup.pcap"; String file = "/home/rtrimana/pcap_processing/smart_home_traffic/Code/Projects/SmartPlugDetector/pcap/wlan1.local.dns.pcap"; try { - Pcap data = Pcap.fromFile(file); - //data.hdr(); + Main main = new Main(file); + main.mapHostnamesToIPAddresses(); + + /*Pcap data = Pcap.fromFile(file); List<Pcap.Packet> listPacket = data.packets(); System.out.println("Number of packets: " + listPacket.size()); System.out.println("==================="); for(Pcap.Packet packet : listPacket) { - System.out.print("#" + counter++ + "\n"); if (packet._root().hdr().network() == Pcap.Linktype.ETHERNET) { EthernetFrame eFrame = (EthernetFrame) packet.body(); if (eFrame.etherType() == EthernetFrame.EtherTypeEnum.IPV4) { @@ -48,26 +139,10 @@ public class Main { } } } - } + }*/ } catch (Exception e) { e.printStackTrace(); } } - - private String cloudIPAddress(String hostName) { - if (hostName.equals("events.tplinkra.com")) - return "205.251.203.26"; - else - return null; - } - - // TODO move to separate class - // Add parameter that is the trace to be analyzed (most like the pcap library's representation of a flow) - public String findPattern(Map<String, List<Integer>> hostnameToPacketLengths, String smartPlugIp) { - - // No difference, output "Complete match" - // If difference, output <Packet no, deviation from expected> for each packet - return null; - } }