Managed to pick and parse DNS packets; but, still need to get the detailed informatio...
authorrtrimana <rtrimana@uci.edu>
Thu, 26 Apr 2018 17:52:01 +0000 (10:52 -0700)
committerrtrimana <rtrimana@uci.edu>
Thu, 26 Apr 2018 17:52:01 +0000 (10:52 -0700)
Code/Projects/SmartPlugDetector/src/main/java/edu/uci/iotproject/DnsPacket.java [new file with mode: 0644]
Code/Projects/SmartPlugDetector/src/main/java/edu/uci/iotproject/Main.java

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 (file)
index 0000000..f15d0d7
--- /dev/null
@@ -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; }
+}
index 44085c3..4892c24 100644 (file)
 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;
-    }
 }