+"""
+Get details about packets blocked by ufw (uses journald)
+"""
+
+import datetime
+import re
+from systemd import journal
+
+from logparse import config
+from logparse.formatting import *
+from logparse.load_parsers import Parser
+from logparse.util import resolve
+
+PROTOCOLS = ["TCP", "UDP", "UDP-Lite", "ICMP", "ICMPv6", "AH", "SCTP", "MH"]
+
+class Packet():
+    """
+    Class to hold variables for each packet. Also parses incoming log messages
+    on object initialisation.
+    """
+
+    def __init__(self, msg):
+        """
+        Determine fields in log message. If any of the fields are missing the
+        log is considered malformed and is discarded. Also the protocol can be
+        specified as either an integer or a string - see `man ufw`.
+        """
+        try:
+            self.inif, self.outif, self.mac, self.src, self.dst, self.len, \
+                    self.proto, self.spt, self.dpt = \
+                    re.search(r"IN=(?P<inif>\w*).*OUT=(?P<outif>\w*).*"
+                        "MAC=(?P<mac>\S*).*SRC=(?P<src>\S*).*DST=(?P<dst>\S*)"
+                        ".*LEN=(?P<length>\d*).*PROTO=(?P<proto>\S*)"
+                        "(?:\sSPT=(?P<spt>\d*))?(?:\sDPT=(?P<dpt>\d*))?", msg
+                    ).groupdict().values()
+            if self.proto and self.proto.isdigit():
+                self.proto = PROTOCOLS[int(self.proto)-1]
+        except Exception as e:
+            logger.warning("Malformed packet log: {0}. Error message: {1}"
+                    .format(msg, str(e)))
+            return None
+
+class UfwJournald(Parser):
+
+    def __init__(self):
+        super().__init__()
+        self.name = "ufw"
+        self.info = "Get details about packets blocked by ufw"
+
+    def parse_log(self):
+
+        logger.debug("Starting ufw section")
+        section = Section("ufw")
+
+        # Find applicable log entries
+
+        j = journal.Reader()
+        j.this_machine()
+        j.add_match(_TRANSPORT='kernel')
+        j.add_match(PRIORITY=4)
+        j.seek_realtime(section.period.startdate)
+        
+        logger.debug("Searching for messages")
+
+        blocked_packets = [Packet(entry["MESSAGE"]) for entry in j
+                if "MESSAGE" in entry and "UFW BLOCK" in entry["MESSAGE"]]
+
+        # Parse messages
+
+        logger.debug("Parsing messages")
+
+        inbound_interfaces = []
+        outbound_interfaces = []
+        n_inbound = n_outbond = 0
+        src_ips = []
+        dst_ips = []
+        src_ports = []
+        dst_ports = []
+        protocols = {'UDP': 0, 'TCP': 0}
+        src_macs = []
+
+        for pkt in blocked_packets:
+            if pkt.inif:
+                inbound_interfaces.append(pkt.inif)
+            elif pkt.outif:
+                outbound_interfaces.append(pkt.outif)
+            if pkt.src: src_ips.append(resolve(pkt.src,
+                config.prefs.get("ufw", "ufw-resolve-domains")))
+            if pkt.dst: dst_ips.append(resolve(pkt.dst,
+                config.prefs.get("ufw", "ufw-resolve-domains")))
+            if pkt.spt: src_ports.append(pkt.spt)
+            if pkt.dpt: dst_ports.append(pkt.dpt)
+            if pkt.proto: protocols[pkt.proto] += 1
+
+        # Format data objects
+
+        section.append_data(Data(subtitle="{} blocked ({} UDP, {} TCP)".format(
+                plural("packet", len(blocked_packets)),
+                protocols['UDP'], protocols['TCP'])))
+
+        src_port_data = Data(items=src_ports)
+        src_port_data.orderbyfreq()
+        src_port_data.subtitle = plural("source port", len(src_port_data.items))
+        src_port_data.truncl(config.prefs.getint("logparse", "maxlist"))
+        section.append_data(src_port_data)
+
+        dst_port_data= Data(items=dst_ports)
+        dst_port_data.orderbyfreq()
+        dst_port_data.subtitle = plural("destination port",
+                len(dst_port_data.items))
+        dst_port_data.truncl(config.prefs.getint("logparse", "maxlist"))
+        section.append_data(dst_port_data)
+
+        src_ips_data= Data(items=src_ips)
+        src_ips_data.orderbyfreq()
+        src_ips_data.subtitle = plural("source IP", len(src_ips_data.items))
+        src_ips_data.truncl(config.prefs.getint("logparse", "maxlist"))
+        section.append_data(src_ips_data)
+
+        dst_ips_data= Data(items=dst_ips)
+        dst_ips_data.orderbyfreq()
+        dst_ips_data.subtitle = plural("destination IP",
+                len(dst_ips_data.items))
+        dst_ips_data.truncl(config.prefs.getint("logparse", "maxlist"))
+        section.append_data(dst_ips_data)
+
+        logger.info("Finished ufw section")
+        return section
+
+    def check_dependencies(self):
+        """
+        Basic dependency check to determine if there are any logs to parse
+        """
+
+        ufw_cmdline = "ufw --version"
+        if self._check_dependency_command(ufw_cmdline)[0] != 0:
+            return (False, ["ufw"])
+        else:
+            return (True, None)