diff --git a/python-inet_diag/diag_filter.h b/python-inet_diag/diag_filter.h
new file mode 100644
index 0000000..c7fd725
--- /dev/null
+++ b/python-inet_diag/diag_filter.h
@@ -0,0 +1,26 @@
+#ifndef _DIAG_FILTER_H_
+#define _DIAG_FILTER_H_ 1
+
+#define DIAG_FILTER_OR	1
+#define DIAG_FILTER_AND	2
+#define DIAG_FILTER_NOT	3
+#define DIAG_BC_NOP 4
+#define DIAG_BC_JMP 5
+#define DIAG_BC_S_GE 6
+#define DIAG_BC_S_LE 7
+#define DIAG_BC_D_GE 8
+#define DIAG_BC_D_LE 9
+#define DIAG_BC_AUTO 10
+#define DIAG_BC_S_COND 11
+#define DIAG_BC_D_COND 12
+
+#include <linux/types.h>
+
+/* Simple filter using the INET_DIAG_BC_* types */
+struct diag_filter {
+	int type;
+	int value;
+	struct diag_filter *post;
+	struct diag_filter *pred;
+};
+#endif /* _DIAG_FILTER_H_ */
diff --git a/python-inet_diag/inet_diag.c b/python-inet_diag/inet_diag.c
index b7bc32d..26b92ae 100644
--- a/python-inet_diag/inet_diag.c
+++ b/python-inet_diag/inet_diag.c
@@ -25,8 +25,8 @@
 #include <linux/rtnetlink.h>
 #include <arpa/inet.h>
 #include <netinet/tcp.h>
-#include "inet_diag_copy.h"
-
+#include <linux/inet_diag.h>
+#include "diag_filter.h"
 #ifndef __unused
 #define __unused __attribute__ ((unused))
 #endif
@@ -529,23 +529,184 @@ static PyTypeObject inet_diag_type = {
 	.tp_getattr	= (getattrfunc)inet_diag__getattr,
 };
 
+struct aafilter
+{
+    int family;
+	int	mask;
+	unsigned long int prefix;
+    int port;
+    struct aafilter *next;
+};
+
+static void filter_patch(char *a, int len, int reloc)
+{
+    while (len > 0) {
+        struct inet_diag_bc_op *op = (struct inet_diag_bc_op*)a;
+        if (op->no == len+4)
+            op->no += reloc;
+        len -= op->yes;
+        a += op->yes;
+    }
+    if (len < 0)
+        abort();
+}
+
+static int filter_bytecompile(struct diag_filter *f, char **bytecode)
+{
+	switch (f->type) {
+		case DIAG_BC_AUTO:
+	{
+		if (!(*bytecode=malloc(4))) abort();
+		((struct inet_diag_bc_op*)*bytecode)[0] = (struct inet_diag_bc_op){ INET_DIAG_BC_AUTO, 4, 8 };
+		return 4;
+	}
+		case DIAG_BC_D_COND:
+		case DIAG_BC_S_COND:
+	{
+		struct aafilter *a = (void*)f->pred;
+		struct aafilter *b;
+		char *ptr;
+		int  code = (f->type == DIAG_BC_D_COND ? INET_DIAG_BC_D_COND : INET_DIAG_BC_S_COND);
+		int len = 0;
+
+		for (b=a; b; b=b->next) {
+			len += 4 + sizeof(struct inet_diag_hostcond);
+			if (a->family == AF_INET6)
+				len += 16;
+			else
+				len += 4;
+			if (b->next)
+				len += 4;
+		}
+		if (!(ptr = malloc(len))) abort();
+		*bytecode = ptr;
+		for (b=a; b; b=b->next) {
+			struct inet_diag_bc_op *op = (struct inet_diag_bc_op *)ptr;
+			int alen = (a->family == AF_INET6 ? 16 : 4);
+			int oplen = alen + 4 + sizeof(struct inet_diag_hostcond);
+			struct inet_diag_hostcond *cond = (struct inet_diag_hostcond*)(ptr+4);
+
+			*op = (struct inet_diag_bc_op){ code, oplen, oplen+4 };
+			cond->family = a->family;
+			cond->port = a->port;
+			cond->prefix_len = a->mask;
+			memcpy(cond->addr, &a->prefix, alen);
+			ptr += oplen;
+			if (b->next) {
+				op = (struct inet_diag_bc_op *)ptr;
+				*op = (struct inet_diag_bc_op){ INET_DIAG_BC_JMP, 4, len - (ptr-*bytecode)};
+				ptr += 4;
+			}
+		}
+		return ptr - *bytecode;
+	}
+		case DIAG_BC_D_GE:
+	{
+		struct aafilter *x = (void*)f->pred;
+		if (!(*bytecode=malloc(8))) abort();
+		((struct inet_diag_bc_op*)*bytecode)[0] = (struct inet_diag_bc_op){ INET_DIAG_BC_D_GE, 8, 12 };
+		((struct inet_diag_bc_op*)*bytecode)[1] = (struct inet_diag_bc_op){ 0, 0, x->port };
+		return 8;
+	}
+		case DIAG_BC_D_LE:
+	{
+		struct aafilter *x = (void*)f->pred;
+		if (!(*bytecode=malloc(8))) abort();
+		((struct inet_diag_bc_op*)*bytecode)[0] = (struct inet_diag_bc_op){ INET_DIAG_BC_D_LE, 8, 12 };
+		((struct inet_diag_bc_op*)*bytecode)[1] = (struct inet_diag_bc_op){ 0, 0, x->port };
+		return 8;
+	}
+		case DIAG_BC_S_GE:
+	{
+		struct aafilter *x = (void*)f->pred;
+		if (!(*bytecode=malloc(8))) abort();
+		((struct inet_diag_bc_op*)*bytecode)[0] = (struct inet_diag_bc_op){ INET_DIAG_BC_S_GE, 8, 12 };
+		((struct inet_diag_bc_op*)*bytecode)[1] = (struct inet_diag_bc_op){ 0, 0, x->port };
+		return 8;
+	}
+		case DIAG_BC_S_LE:
+	{
+		struct aafilter *x = (void*)f->pred;
+		if (!(*bytecode=malloc(8))) abort();
+		((struct inet_diag_bc_op*)*bytecode)[0] = (struct inet_diag_bc_op){ INET_DIAG_BC_S_LE, 8, 12 };
+		((struct inet_diag_bc_op*)*bytecode)[1] = (struct inet_diag_bc_op){ 0, 0, x->port };
+		return 8;
+	}
+
+		case DIAG_FILTER_AND:
+	{
+		char *a1, *a2, *a, l1, l2;
+		l1 = filter_bytecompile(f->pred, &a1);
+		l2 = filter_bytecompile(f->post, &a2);
+		if (!(a = malloc(l1+l2))) abort();
+		memcpy(a, a1, l1);
+		memcpy(a+l1, a2, l2);
+		free(a1); free(a2);
+		filter_patch(a, l1, l2);
+		*bytecode = a;
+		return l1+l2;
+	}
+		case DIAG_FILTER_OR:
+	{
+		char *a1, *a2, *a, l1, l2;
+		l1 = filter_bytecompile(f->pred, &a1);
+		l2 = filter_bytecompile(f->post, &a2);
+		if (!(a = malloc(l1+l2+4))) abort();
+		memcpy(a, a1, l1);
+		memcpy(a+l1+4, a2, l2);
+		free(a1); free(a2);
+		*(struct inet_diag_bc_op*)(a+l1) = (struct inet_diag_bc_op){ INET_DIAG_BC_JMP, 4, l2+4 };
+		*bytecode = a;
+		return l1+l2+4;
+	}
+		case DIAG_FILTER_NOT:
+	{
+		char *a1, *a, l1;
+		l1 = filter_bytecompile(f->pred, &a1);
+		if (!(a = malloc(l1+4))) abort();
+		memcpy(a, a1, l1);
+		free(a1);
+		*(struct inet_diag_bc_op*)(a+l1) = (struct inet_diag_bc_op){ INET_DIAG_BC_JMP, 4, 8 };
+		*bytecode = a;
+		return l1+4;
+	}
+		default:
+		abort();
+	}
+}
+
 /* constructor */
 static char inet_diag_create__doc__[] =
-"create() -- creates a new inet_diag socket.";
+"create([states, extensions, socktype, src, sport, dst, dport, le_spt, le_dpt, ge_spt, ge_dpt, join=DIAG_FILTER_AND])\n\n\
+Creates a new inet_diag socket object. Filters include:\n\
+- socket states (SENT, RECV, etc.)\n\
+- source addr and source port (must be used together)\n\
+- dest addr and dest port (must be used together)\n\
+- <=, >= source and dest port\n\n\
+All specified source and dest filters can either be joined with DIAG_FILTER_AND or DIAG_FILTER_OR.";
 static PyObject *inet_diag__create(PyObject *mself __unused, PyObject *args,
 				   PyObject *keywds)
 {
 	int states = default_states;
 	int extensions = INET_DIAG_NONE;
 	int socktype = TCPDIAG_GETSOCK;
-	static char *kwlist[] = { "states", "extensions", "socktype" };
+	const char *src;
+	const char *dst;
+	int sport  = -1;
+	int dport  = -1;
+	int le_spt = -1;
+	int le_dpt = -1;
+	int ge_spt = -1;
+	int ge_dpt = -1;
+	int join   = DIAG_FILTER_AND;
+	static char *kwlist[] = { "states", "extensions", "socktype", "src", "dst", "sport", "dport", "le_spt", "le_dpt", "ge_spt", "ge_dpt", "join" };
 	struct inet_diag *self = PyObject_NEW(struct inet_diag,
 					      &inet_diag_type);
 	if (self == NULL)
 		return NULL;
 
-	if (!PyArg_ParseTupleAndKeywords(args, keywds, "|iii", kwlist,
-					 &states, &extensions, &socktype))
+	if (!PyArg_ParseTupleAndKeywords(args, keywds, "|iiissiiiiiii", kwlist,
+					 &states, &extensions, &socktype, &src, &dst, &sport, &dport, &le_spt, &le_dpt, &ge_spt, &ge_dpt, &join))
 		goto out_err;
 
 	self->socket = socket(AF_NETLINK, SOCK_RAW, NETLINK_INET_DIAG);
@@ -555,6 +716,7 @@ static PyObject *inet_diag__create(PyObject *mself __unused, PyObject *args,
 	struct sockaddr_nl nladdr = {
 		.nl_family = AF_NETLINK,
 	};
+
 	struct {
 		struct nlmsghdr nlh;
 		struct inet_diag_req r;
@@ -571,19 +733,165 @@ static PyObject *inet_diag__create(PyObject *mself __unused, PyObject *args,
 			.idiag_ext    = extensions,
 		},
 	};
-	struct iovec iov[1] = {
-		[0] = {
-			.iov_base = &req,
-			.iov_len  = sizeof(req),
-		},
-	};
+
+	// filter preparation
+	struct diag_filter *filter;
+	int f_exists = 0;
+	if ( src != NULL && sport != -1 ) {
+		struct in_addr in_src = {};
+		inet_aton(src, &in_src);
+
+		filter = &(struct diag_filter){
+			.type   = DIAG_BC_S_COND,
+			.pred   = (void*)&(struct aafilter){
+				.family = AF_INET,
+				.mask   = 32,
+				.prefix = in_src.s_addr,
+				.port   = sport,
+				.next   = NULL,
+			}
+		};
+		f_exists = 1;
+	}
+
+	if ( dst != NULL && dport != -1 ) {
+		struct in_addr in_dst = {};
+		inet_aton(dst, &in_dst);
+
+		struct diag_filter tmp_dst = (struct diag_filter){
+			.type   = DIAG_BC_D_COND,
+			.pred   = (void*)&(struct aafilter){
+				.family = AF_INET,
+				.mask   = 32,
+				.prefix = in_dst.s_addr,
+				.port   = dport,
+				.next   = NULL,
+			}
+		};
+
+		if ( f_exists != 0 ) {
+			filter = &(struct diag_filter){
+				.type = join,
+				.pred = filter,
+				.post = &tmp_dst,
+			};
+		} else {
+			filter   = &tmp_dst;
+			f_exists = 1;
+		}
+	}
+
+	if ( le_spt != -1 ) {
+		struct diag_filter tmp_le_spt = {
+			.type  = DIAG_BC_S_LE,
+			.pred  = (void*)&(struct aafilter){
+				.port = le_spt,
+				.next = NULL,
+			}
+		};
+
+		if ( f_exists != 0 ) {
+			filter = &(struct diag_filter){
+				.type = join,
+				.pred = filter,
+				.post = &tmp_le_spt,
+			};
+		} else {
+			filter   = &tmp_le_spt;
+			f_exists = 1;
+		}
+	}
+
+	if ( le_dpt != -1 ) {
+		struct diag_filter tmp_le_dpt = {
+			.type   = DIAG_BC_D_LE,
+			.pred   = (void*)&(struct aafilter){
+				.port   = le_dpt,
+				.next   = NULL,
+			}
+		};
+
+		if ( f_exists != 0 ) {
+			filter = &(struct diag_filter){
+				.type = join,
+				.pred = filter,
+				.post = &tmp_le_dpt,
+			};
+		} else {
+			filter   = &tmp_le_dpt;
+			f_exists = 1;
+		}
+	}
+
+	if ( ge_spt != -1 ) {
+		struct diag_filter tmp_ge_spt = {
+			.type   = DIAG_BC_S_GE,
+			.pred   = (void*)&(struct aafilter){
+				.port   = ge_spt,
+				.next   = NULL,
+			}
+		};
+
+		if ( f_exists != 0 ) {
+			filter = &(struct diag_filter){
+				.type = join,
+				.pred = filter,
+				.post = &tmp_ge_spt,
+			};
+		} else {
+			filter   = &tmp_ge_spt;
+			f_exists = 1;
+		}
+	}
+
+	if ( ge_dpt != -1 ) {
+		struct diag_filter tmp_ge_dpt = {
+			.type   = DIAG_BC_D_GE,
+			.pred   = (void*)&(struct aafilter){
+				.port   = ge_dpt,
+				.next   = NULL,
+			}
+		};
+
+		if ( f_exists != 0 ) {
+			filter = &(struct diag_filter){
+				.type = join,
+				.pred = filter,
+				.post = &tmp_ge_dpt,
+			};
+		} else {
+			filter   = &tmp_ge_dpt;
+			f_exists = 1;
+		}
+	}
+
+	struct iovec iov[3];
+	iov[0] = (struct iovec){
+            .iov_base = &req,
+            .iov_len  = sizeof(req),
+    };
+
+	// append the filter	
+    struct rtattr rta; 
+	char *filter_mem = NULL;
+    int filter_len = 0;
+	if ( f_exists != 0 ) {
+		filter_len   = filter_bytecompile(filter, &filter_mem);
+    	rta.rta_type = INET_DIAG_REQ_BYTECODE;
+    	rta.rta_len  = RTA_LENGTH(filter_len);
+
+    	iov[1] = (struct iovec){ &rta, sizeof(rta) };
+    	iov[2] = (struct iovec){ filter_mem, filter_len };
+
+    	req.nlh.nlmsg_len += RTA_LENGTH(filter_len);
+	}
+
 	struct msghdr msg = {
 		.msg_name    = &nladdr,
 		.msg_namelen = sizeof(nladdr),
 		.msg_iov     = iov,
-		.msg_iovlen  = 1,
+		.msg_iovlen  = ( f_exists != 0 ? 3 : 1 ),
 	};
-
 	if (sendmsg(self->socket, &msg, 0) < 0)
 		goto out_err;
 
@@ -608,7 +916,15 @@ static struct PyMethodDef python_inet_diag__methods[] = {
 PyMODINIT_FUNC initinet_diag(void)
 {
 	PyObject *m;
-	m = Py_InitModule("inet_diag", python_inet_diag__methods);
+	m = Py_InitModule3("inet_diag", python_inet_diag__methods, "Example:\n\n\
+	> import inet_diag\n\
+	> idiag = inet_diag.create(states = inet_diag.default_states, extensions = inet_diag.EXT_MEMORY, socktype = inet_diag.TCPDIAG_GETSOCK, le_dpt = 500)\n\
+	> while True:\n\
+	>     try:\n\
+	>         s = idiag.get()\n\
+	>     except:\n\
+	>         break\n\
+	>     print s");
 	PyModule_AddIntConstant(m, "SS_ESTABLISHED", SS_ESTABLISHED);
 	PyModule_AddIntConstant(m, "SS_SYN_SENT",    SS_SYN_SENT);
 	PyModule_AddIntConstant(m, "SS_SYN_RECV",    SS_SYN_RECV);
@@ -632,4 +948,6 @@ PyMODINIT_FUNC initinet_diag(void)
 	PyModule_AddIntConstant(m, "PROTO_OPT_ECN", TCPI_OPT_ECN);
 	PyModule_AddIntConstant(m, "TCPDIAG_GETSOCK", TCPDIAG_GETSOCK);
 	PyModule_AddIntConstant(m, "DCCPDIAG_GETSOCK", DCCPDIAG_GETSOCK);
+	PyModule_AddIntConstant(m, "DIAG_FILTER_AND", DIAG_FILTER_AND);
+	PyModule_AddIntConstant(m, "DIAG_FILTER_OR", DIAG_FILTER_OR);
 }
