Tool to sniff data contents before encrypted with OpenSSL

Add tool as talked in iovisor-dev 'BCC: bpf_probe_read read function arguments'
diff --git a/tools/sslsniff.py b/tools/sslsniff.py
new file mode 100755
index 0000000..a89c6ef
--- /dev/null
+++ b/tools/sslsniff.py
@@ -0,0 +1,150 @@
+#!/usr/bin/python
+#
+# sslsniff  Captures data on SSL_READ or SSL_WRITE functions of OpenSSL
+#           For Linux, uses BCC, eBPF.
+#
+# Licensed under the Apache License, Version 2.0 (the "License")
+#
+# 12-Aug-2016    Adrian Lopez   Created this.
+# 13-Aug-2016    Mark Drayton   Fix SSL_Read
+
+from __future__ import print_function
+import ctypes as ct
+from bcc import BPF
+
+prog = """
+#include <linux/ptrace.h>
+#include <linux/sched.h>        /* For TASK_COMM_LEN */
+
+struct probe_SSL_data_t {
+        u64 timestamp_ns;
+        u32 pid;
+        char comm[TASK_COMM_LEN];
+        char v0[472];
+        u32 len;
+};
+
+BPF_PERF_OUTPUT(perf_SSL_write);
+
+int probe_SSL_write(struct pt_regs *ctx, void *ssl, void *buf, int num) {
+        struct probe_SSL_data_t __data = {0};
+        __data.timestamp_ns = bpf_ktime_get_ns();
+        __data.pid = bpf_get_current_pid_tgid();
+        __data.len = num;
+
+        bpf_get_current_comm(&__data.comm, sizeof(__data.comm));
+
+        if ( buf != 0) {
+                bpf_probe_read(&__data.v0, sizeof(__data.v0), buf);
+        }
+
+        perf_SSL_write.perf_submit(ctx, &__data, sizeof(__data));
+        return 0;
+}
+
+BPF_PERF_OUTPUT(perf_SSL_read);
+
+BPF_HASH(bufs, u32, u64);
+
+int probe_SSL_read_enter(struct pt_regs *ctx, void *ssl, void *buf, int num) {
+        u32 pid = bpf_get_current_pid_tgid();
+        bufs.update(&pid, (u64*)&buf);
+        return 0;
+}
+
+int probe_SSL_read_exit(struct pt_regs *ctx, void *ssl, void *buf, int num) {
+        u32 pid = bpf_get_current_pid_tgid();
+        u64 *bufp = bufs.lookup(&pid);
+        if (bufp == 0) {
+                return 0;
+        }
+
+        struct probe_SSL_data_t __data = {0};
+        __data.timestamp_ns = bpf_ktime_get_ns();
+        __data.pid = pid;
+        __data.len = PT_REGS_RC(ctx);
+
+        bpf_get_current_comm(&__data.comm, sizeof(__data.comm));
+
+        if (bufp != 0) {
+                bpf_probe_read(&__data.v0, sizeof(__data.v0), (char *)*bufp);
+        }
+
+        bufs.delete(&pid);
+
+        perf_SSL_read.perf_submit(ctx, &__data, sizeof(__data));
+        return 0;
+}
+"""
+
+b = BPF(text=prog)
+
+# Join to ssl_write
+b.attach_uprobe(name="ssl", sym="SSL_write", fn_name="probe_SSL_write")
+
+# Join to ssl_read
+# It looks like SSL_read's arguments aren't available in a return probe so you
+# need to stash the buffer address in a map on the function entry and read it
+# on its exit (Mark Drayton)
+b.attach_uprobe(name="ssl", sym="SSL_read", fn_name="probe_SSL_read_enter")
+b.attach_uretprobe(name="ssl", sym="SSL_read", fn_name="probe_SSL_read_exit")
+
+# define output data structure in Python
+TASK_COMM_LEN = 16  # linux/sched.h
+MAX_BUF_SIZE = 472  # Limited by the BPF stack
+
+
+# Max size of the whole struct: 512 bytes
+class Data(ct.Structure):
+    _fields_ = [
+            ("timestamp_ns", ct.c_ulonglong),
+            ("pid", ct.c_uint),
+            ("comm", ct.c_char * TASK_COMM_LEN),
+            ("v0", ct.c_char * MAX_BUF_SIZE),
+            ("len", ct.c_uint)
+    ]
+
+
+# header
+print("%-12s %-18s %-16s %-6s %-6s" % ("FUNC", "TIME(s)", "COMM", "PID",
+                                       "LEN"))
+
+# process event
+start = 0
+
+
+def print_event_write(cpu, data, size):
+    print_event(cpu, data, size, "SSL_WRITE")
+
+
+def print_event_read(cpu, data, size):
+    print_event(cpu, data, size, "SSL_READ")
+
+
+def print_event(cpu, data, size, rw):
+    global start
+    event = ct.cast(data, ct.POINTER(Data)).contents
+    if start == 0:
+        start = event.timestamp_ns
+    time_s = (float(event.timestamp_ns - start)) / 1000000000
+
+    s_mark = "-" * 5 + " DATA " + "-" * 5
+
+    e_mark = "-" * 5 + " END DATA " + "-" * 5
+
+    truncated_bytes = event.len - MAX_BUF_SIZE
+    if truncated_bytes > 0 :
+        e_mark = "-" * 5 + " END DATA (TRUNCATED, " + str(truncated_bytes) + \
+                " bytes lost) " + "-" * 5
+
+    print("%-12s %-18.9f %-16s %-6d %-6d\n%s\n%s\n%s\n" % (rw, time_s,
+                                                           event.comm,
+                                                           event.pid,
+                                                           event.len,
+                                                           s_mark, event.v0,
+                                                           e_mark))
+
+b["perf_SSL_write"].open_perf_buffer(print_event_write)
+b["perf_SSL_read"].open_perf_buffer(print_event_read)
+while 1:
+    b.kprobe_poll()
diff --git a/tools/sslsniff_example.txt b/tools/sslsniff_example.txt
new file mode 100644
index 0000000..596b01c
--- /dev/null
+++ b/tools/sslsniff_example.txt
@@ -0,0 +1,61 @@
+Demonstrations of sslsniff.py
+
+
+This tool traces the OpenSSL functions SSL_READ and SSL_WRITE.
+Data passed to this functions is printed as plain text.
+Useful, for example, to sniff HTTP before encrypted with SSL.
+
+
+Output of tool executing in other shell "curl https://example.com"
+
+% sudo python sslsniff.py
+FUNC         TIME(s)            COMM             PID    LEN   
+SSL_WRITE    0.000000000        curl             12915  75    
+----- DATA -----
+GET / HTTP/1.1
+Host: example.com
+User-Agent: curl/7.50.1
+Accept: */*
+
+
+----- END DATA -----
+
+SSL_READ     0.127144585        curl             12915  333   
+----- DATA -----
+HTTP/1.1 200 OK
+Cache-Control: max-age=604800
+Content-Type: text/html
+Date: Tue, 16 Aug 2016 15:42:12 GMT
+Etag: "359670651+gzip+ident"
+Expires: Tue, 23 Aug 2016 15:42:12 GMT
+Last-Modified: Fri, 09 Aug 2013 23:54:35 GMT
+Server: ECS (iad/18CB)
+Vary: Accept-Encoding
+X-Cache: HIT
+x-ec-custom-error: 1
+Content-Length: 1270
+
+
+----- END DATA -----
+
+SSL_READ     0.129967972        curl             12915  1270  
+----- DATA -----
+<!doctype html>
+<html>
+<head>
+    <title>Example Domain</title>
+
+    <meta charset="utf-8" />
+    <meta http-equiv="Content-type" content="text/html; charset=utf-8" />
+    <meta name="viewport" content="width=device-width, initial-scale=1" />
+    <style type="text/css">
+    body {
+        background-color: #f0f0f2;
+        margin: 0;
+        padding: 0;
+        font-family: "Open Sans", "Helvetica Neue", Helvetica, Arial, sans-serif;
+        
+    }
+    div {
+        w
+----- END DATA (TRUNCATED, 798 bytes lost) -----