{"id":504,"date":"2015-03-09T09:51:19","date_gmt":"2015-03-09T14:51:19","guid":{"rendered":"http:\/\/3gfp.com\/wp\/?p=504"},"modified":"2015-03-09T09:57:05","modified_gmt":"2015-03-09T14:57:05","slug":"sniffing-tcp-packets-with-python","status":"publish","type":"post","link":"https:\/\/3gfp.com\/wp\/2015\/03\/sniffing-tcp-packets-with-python\/","title":{"rendered":"Sniffing TCP Packets With Python"},"content":{"rendered":"<p>Inspired by this StackOverflow question, [&#8220;How do I sniff on a port for log messages using python?&#8221;][so_question], I decided to figure out how to capture and process packets in Python. It turns out to be quite easy once you work out the kinks. Except the kinks were a pain to determine.<\/p>\n<p>[so_question]: http:\/\/stackoverflow.com\/q\/28870666\/47078<\/p>\n<p>Sample output:<\/p>\n<pre class=\"lang:default highlight:0 decode:true \" >$ sudo python capture.py\r\n10:27:44.016601    hello ('127.0.0.1', 61129)\r\n10:27:44.016614    hello ('127.0.0.1', 61129)\r\n10:27:54.019731    hello ('127.0.0.1', 61137)\r\n10:27:54.019741    hello ('127.0.0.1', 61137)<\/pre>\n<p><!--more--><\/p>\n<p>Note<br \/>\n:   _It may appear that the same packets are printed twice here, but what you&#8217;re really seeing is the same packet going out and then coming back in. The timestamps give it away. Also, if you have an OSX version of tcpdump, the  <span class=\"lang:default decode:true  crayon-inline \" >-k ID<\/span>  option will print something like this:  <span class=\"lang:default decode:true  crayon-inline \" >(lo0, out)<\/span> ._<\/p>\n<p>Basic, high-level usage:<\/p>\n<pre class=\"lang:python range:118-125 decode:true \" data-url=\"https:\/\/raw.githubusercontent.com\/sr105\/pypcap_example\/master\/capture.py\" ><\/pre>\n<p>And then the actual generator:<\/p>\n<pre class=\"lang:python range:85-110 decode:true \" data-url=\"https:\/\/raw.githubusercontent.com\/sr105\/pypcap_example\/master\/capture.py\" ><\/pre>\n<p>Depending on the interface you capture from, you may receive Ethernet, Loopback, or IP packets. This means that a little deduction must be done to determine how to decode them. We figure this out once, and save the decoding function for all future packets. Although, if you never need to enter promiscuous mode[^1], you use the &#8220;iptap&#8221; interface and you will only ever receive IP packets.<\/p>\n<p>[^1]: Ethernet interfaces normally filter out any network traffic not destined for the current machine. Setting the interface to be promiscuous, tells it to pass through all packets it receives.<\/p>\n<pre class=\"lang:python range:67-75 decode:true \" data-url=\"https:\/\/raw.githubusercontent.com\/sr105\/pypcap_example\/master\/capture.py\" ><\/pre>\n<p>All of the decode functions return either data or None if a parsing error occurs. Here&#8217;s the one for Ethernet packets:<\/p>\n<pre class=\"lang:python range:49-53 decode:true \" data-url=\"https:\/\/raw.githubusercontent.com\/sr105\/pypcap_example\/master\/capture.py\" ><\/pre>\n<p>As a bonus, here&#8217;s a couple of methods that print out binary data similar to the  <span class=\"lang:default decode:true  crayon-inline \" >hexdump -C<\/span>  command, but without the trailing ASCII.<\/p>\n<pre class=\"lang:python range:30-45 decode:true \" data-url=\"https:\/\/raw.githubusercontent.com\/sr105\/pypcap_example\/master\/capture.py\" ><\/pre>\n<p>With debugging turned on, the output is much more verbose:<\/p>\n<pre class=\"lang:default highlight:0 decode:true \" >Capturing on interface(s): iptap\r\n00000000: 4500 004e 0f7a 4000 4006 0000 7f00 0001\r\n00000010: 7f00 0001 2704 f1ab 5a99 b667 c79a 4159\r\n00000020: 8018 31d7 fe42 0000 0101 080a 4969 b251\r\n00000030: 4969 b251 6865 6c6c 6f20 2827 3132 372e\r\n00000040: 302e 302e 3127 2c20 3631 3836 3729\r\n\r\nPacket type: ip\r\n10:45:44.428427    hello ('127.0.0.1', 61867)\r\n00000000: 4500 004e 0f7a 4000 4006 2d2e 7f00 0001\r\n00000010: 7f00 0001 2704 f1ab 5a99 b667 c79a 4159\r\n00000020: 8018 31d7 fe42 0000 0101 080a 4969 b251\r\n00000030: 4969 b251 6865 6c6c 6f20 2827 3132 372e\r\n00000040: 302e 302e 3127 2c20 3631 3836 3729\r\n\r\n10:45:44.428447    hello ('127.0.0.1', 61867)<\/pre>\n","protected":false},"excerpt":{"rendered":"<p>Inspired by this StackOverflow question, [&#8220;How do I sniff on a port for log messages using python?&#8221;][so_question], I decided to figure out how to capture and process packets in Python. It turns out to be quite easy once you work out the kinks. Except the kinks were a pain to determine. [so_question]: http:\/\/stackoverflow.com\/q\/28870666\/47078 Sample output: [&hellip;]<\/p>\n","protected":false},"author":14,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[1],"tags":[],"class_list":["post-504","post","type-post","status-publish","format-standard","hentry","category-uncategorized"],"_links":{"self":[{"href":"https:\/\/3gfp.com\/wp\/wp-json\/wp\/v2\/posts\/504","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/3gfp.com\/wp\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/3gfp.com\/wp\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/3gfp.com\/wp\/wp-json\/wp\/v2\/users\/14"}],"replies":[{"embeddable":true,"href":"https:\/\/3gfp.com\/wp\/wp-json\/wp\/v2\/comments?post=504"}],"version-history":[{"count":16,"href":"https:\/\/3gfp.com\/wp\/wp-json\/wp\/v2\/posts\/504\/revisions"}],"predecessor-version":[{"id":520,"href":"https:\/\/3gfp.com\/wp\/wp-json\/wp\/v2\/posts\/504\/revisions\/520"}],"wp:attachment":[{"href":"https:\/\/3gfp.com\/wp\/wp-json\/wp\/v2\/media?parent=504"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/3gfp.com\/wp\/wp-json\/wp\/v2\/categories?post=504"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/3gfp.com\/wp\/wp-json\/wp\/v2\/tags?post=504"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}