{"id":206,"date":"2023-03-11T21:57:56","date_gmt":"2023-03-12T03:57:56","guid":{"rendered":"https:\/\/drkeithjones.com\/?p=206"},"modified":"2023-03-27T08:49:46","modified_gmt":"2023-03-27T12:49:46","slug":"how-to-connect-zeek-to-python","status":"publish","type":"post","link":"https:\/\/drkeithjones.com\/index.php\/2023\/03\/11\/how-to-connect-zeek-to-python\/","title":{"rendered":"How To Connect Zeek To Python"},"content":{"rendered":"\n<p>I was recently asked how to send data from Zeek to Python.  After <a href=\"https:\/\/docs.zeek.org\/en\/master\/frameworks\/broker.html#broker-framework-examples\" target=\"_blank\" rel=\"noopener\" title=\"\">flipping through the Zeek Broker documentation<\/a> I couldn&#8217;t find a good example to reference, so here is my example.<\/p>\n\n\n\n<p>The code for this demo is available here: <\/p>\n\n\n\n<p><a href=\"https:\/\/github.com\/keithjjones\/zeek-python-broker-demo\" target=\"_blank\" rel=\"noopener\" title=\"\">https:\/\/github.com\/keithjjones\/zeek-python-broker-demo<\/a><\/p>\n\n\n\n<p>The first piece of our source code is the Python program here:<\/p>\n\n\n\n<p><a href=\"https:\/\/github.com\/keithjjones\/zeek-python-broker-demo\/blob\/master\/broker-test.py\" target=\"_blank\" rel=\"noopener\" title=\"\">https:\/\/github.com\/keithjjones\/zeek-python-broker-demo\/blob\/master\/broker-test.py<\/a><\/p>\n\n\n\n<p>There is a prerequisite for this Python script, the Zeek Python Broker bindings must be downloaded and installed.  You can find the installation instructions here: <\/p>\n\n\n\n<p><a href=\"https:\/\/docs.zeek.org\/projects\/broker\/en\/master\/python.html#installation-in-a-virtual-environment\" target=\"_blank\" rel=\"noopener\" title=\"\">https:\/\/docs.zeek.org\/projects\/broker\/en\/master\/python.html#installation-in-a-virtual-environment<\/a><\/p>\n\n\n\n<p><em>The trick is you must install the version of broker that corresponds to your Zeek&#8217;s version.<\/em>  Be sure to read that last sentence again.  I figured this out the hard way.<\/p>\n\n\n\n<p>Your version of Broker can be looked up by visiting the Zeek repository and selecting your Zeek version in the branch dropdown, such as v5.0.4.  Then, go into the &#8220;auxil&#8221; directory to find Broker:<\/p>\n\n\n\n<p><a href=\"https:\/\/github.com\/zeek\/zeek\/tree\/v5.0.4\/auxil\" target=\"_blank\" rel=\"noopener\" title=\"\">https:\/\/github.com\/zeek\/zeek\/tree\/v5.0.4\/auxil<\/a><\/p>\n\n\n\n<p>If you click into the Broker directory you will enter its repository at the version used in Zeek v5.0.4.  If you click on &#8220;VERSION&#8221;, you will find version 2.3.5 of Broker is used in Zeek v5.0.4:  <\/p>\n\n\n\n<p><a href=\"https:\/\/github.com\/zeek\/broker\/blob\/a7d55f8da2c47bf8b3de2524b24e1d8bfec1c2ce\/VERSION\" target=\"_blank\" rel=\"noopener\" title=\"\">https:\/\/github.com\/zeek\/broker\/blob\/a7d55f8da2c47bf8b3de2524b24e1d8bfec1c2ce\/VERSION<\/a><\/p>\n\n\n\n<p>You can download Broker v2.3.5 here:<\/p>\n\n\n\n<p><a href=\"https:\/\/github.com\/zeek\/broker\/releases\" target=\"_blank\" rel=\"noopener\" title=\"\">https:\/\/github.com\/zeek\/broker\/releases<\/a><\/p>\n\n\n\n<p>Once you download Broker and install the Python bindings using the instructions linked above, you can finally execute the Python script.  Here is the script&#8217;s content:  <\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>import sys\nimport broker\n\n# Setup endpoint and connect to Zeek.\nwith broker.Endpoint() as ep, \\\n    ep.make_subscriber(\"\/topic\/test\") as sub:\n\n    ep.listen(\"127.0.0.1\", 60000)\n\n    while True:\n        (t, d) = sub.get()\n        pong = broker.zeek.Event(d)\n        print(\"received {}  --   {}\".format(pong.name(), pong.args()))\n\n        python_results = broker.zeek.Event(\"python_results\", pong.args()&#91;0]);\n        ep.publish(\"\/topic\/test\", python_results);<\/code><\/pre>\n\n\n\n<p>The script is relatively simple.  The following lines set up a Zeek Broker listener on 127.0.0.1:60000 via Python: <\/p>\n\n\n\n<p><a href=\"https:\/\/github.com\/keithjjones\/zeek-python-broker-demo\/blob\/master\/broker-test.py#L5-L8\" target=\"_blank\" rel=\"noopener\" title=\"\">https:\/\/github.com\/keithjjones\/zeek-python-broker-demo\/blob\/master\/broker-test.py#L5-L8<\/a>  <\/p>\n\n\n\n<p>Then, the Python script runs in an infinite loop pulling messages from Broker via the &#8220;get&#8221; function:<\/p>\n\n\n\n<p><a href=\"https:\/\/github.com\/keithjjones\/zeek-python-broker-demo\/blob\/master\/broker-test.py#L11\" target=\"_blank\" rel=\"noopener\" title=\"\">https:\/\/github.com\/keithjjones\/zeek-python-broker-demo\/blob\/master\/broker-test.py#L11<\/a><\/p>\n\n\n\n<p>Here &#8220;t&#8221; is the message&#8217;s topic, and &#8220;d&#8221; is the message&#8217;s raw data.  Line 12 then translates the data pulled from Broker into a Python event object called &#8220;pong&#8221;.  The name &#8220;pong&#8221; is not important, I wanted to show that this object could be named anything because the &#8220;.name()&#8221; function will tell you the true event name.  <\/p>\n\n\n\n<p>The last two lines in the script then create an event object and publishes it through Broker so that the &#8220;python_results&#8221; event will fire back in Zeek.  The event will have the same argument that was originally passed to the Python process from Zeek (&#8220;pong.args()[0]&#8221;).  Here is example output from the Python script:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>received some_test_event  --   &#91;(IPv4Address('172.20.32.121'), 47808\/udp, IPv4Address('172.20.32.255'), 47808\/udp)]\nreceived some_test_event  --   &#91;(IPv4Address('172.20.32.109'), 47808\/udp, IPv4Address('172.20.32.255'), 47808\/udp)]\nreceived some_test_event  --   &#91;(IPv4Address('172.20.32.200'), 47808\/udp, IPv4Address('172.20.32.115'), 47808\/udp)]\nreceived some_test_event  --   &#91;(IPv4Address('172.20.32.200'), 47808\/udp, IPv4Address('172.20.32.112'), 47808\/udp)]\nreceived some_test_event  --   &#91;(IPv4Address('172.20.32.200'), 47808\/udp, IPv4Address('172.20.32.110'), 47808\/udp)]\nreceived some_test_event  --   &#91;(IPv4Address('172.20.32.200'), 47808\/udp, IPv4Address('172.20.32.121'), 47808\/udp)]\nreceived some_test_event  --   &#91;(IPv4Address('172.20.32.200'), 47808\/udp, IPv4Address('172.20.32.109'), 47808\/udp)]<\/code><\/pre>\n\n\n\n<p>In the Zeek script content below you will find the event &#8220;python_results&#8221; is handled here:<\/p>\n\n\n\n<p><a href=\"https:\/\/github.com\/keithjjones\/zeek-python-broker-demo\/blob\/master\/broker-test.zeek#L6\" target=\"_blank\" rel=\"noopener\" title=\"\">https:\/\/github.com\/keithjjones\/zeek-python-broker-demo\/blob\/master\/broker-test.zeek#L6<\/a><\/p>\n\n\n\n<p>It just prints the arguments to the event.  In &#8220;connection_state_remove&#8221; the script sends the &#8220;c$id&#8221; conn_id record to Python:  <\/p>\n\n\n\n<p><a href=\"https:\/\/github.com\/keithjjones\/zeek-python-broker-demo\/blob\/master\/broker-test.zeek#L11-L14\" target=\"_blank\" rel=\"noopener\" title=\"\">https:\/\/github.com\/keithjjones\/zeek-python-broker-demo\/blob\/master\/broker-test.zeek#L11-L14<\/a>  <\/p>\n\n\n\n<p>Therefore, this is the same data that will be printed when it is returned via &#8220;python_results&#8221;.<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>global test_topic = \"\/topic\/test\";\n\nglobal some_test_event: event(c_id: conn_id);\n\nevent python_results(c_id: conn_id)\n{\n\tprint(cat(\"Got Python Results: \", c_id));\n}\n\nevent connection_state_remove(c: connection)\n{\n    Broker::publish(test_topic, some_test_event, c$id);\n}\n\nevent zeek_init()\n{\n\tBroker::peer(addr_to_uri(127.0.0.1), 60000\/tcp);\n\tBroker::subscribe(test_topic);\n}<\/code><\/pre>\n\n\n\n<p>The two lines in &#8220;zeek_init&#8221; take care of connecting to the Python process before publishing the results to the &#8220;\/topic\/test&#8221; topic in Zeek&#8217;s Broker.<\/p>\n\n\n\n<p>When running the Zeek script on a PCAP while the Python script is executing in another window, you will see the connection ID records printed from the Zeek and the Python processes in their respective windows as they are processed.  This will prove that the data was transferred from your PCAP through Zeek, into Python over Zeek&#8217;s Broker, and back to Zeek again over Broker. This is example output from the Zeek script:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>Got Python Results: &#91;orig_h=172.20.32.200, orig_p=47808\/udp, resp_h=172.20.32.115, resp_p=47808\/udp]\nGot Python Results: &#91;orig_h=172.20.32.200, orig_p=47808\/udp, resp_h=172.20.32.112, resp_p=47808\/udp]\nGot Python Results: &#91;orig_h=172.20.32.200, orig_p=47808\/udp, resp_h=172.20.32.110, resp_p=47808\/udp]\nGot Python Results: &#91;orig_h=172.20.32.200, orig_p=47808\/udp, resp_h=172.20.32.121, resp_p=47808\/udp]\nGot Python Results: &#91;orig_h=172.20.32.200, orig_p=47808\/udp, resp_h=172.20.32.109, resp_p=47808\/udp]<\/code><\/pre>\n\n\n\n<p>Now imagine all the new types of processing you can do in Python that may have been more difficult with Zeek alone!<\/p>\n","protected":false},"excerpt":{"rendered":"<p>I was recently asked how to send data from Zeek to Python. After flipping through the Zeek Broker documentation I couldn&#8217;t find a good example to reference, so here is my example. The code for this demo is available here: https:\/\/github.com\/keithjjones\/zeek-python-broker-demo The first piece of our source code is the Python program here: https:\/\/github.com\/keithjjones\/zeek-python-broker-demo\/blob\/master\/broker-test.py There [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"_jetpack_memberships_contains_paid_content":false,"footnotes":""},"categories":[74,91,45,61,4],"tags":[42,44,43,27],"class_list":["post-206","post","type-post","status-publish","format-standard","hentry","category-how-to","category-open-source","category-python","category-tools","category-zeek","tag-broker","tag-howto","tag-python","tag-zeek"],"aioseo_notices":[],"jetpack_featured_media_url":"","jetpack-related-posts":[],"jetpack_sharing_enabled":true,"_links":{"self":[{"href":"https:\/\/drkeithjones.com\/index.php\/wp-json\/wp\/v2\/posts\/206","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/drkeithjones.com\/index.php\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/drkeithjones.com\/index.php\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/drkeithjones.com\/index.php\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/drkeithjones.com\/index.php\/wp-json\/wp\/v2\/comments?post=206"}],"version-history":[{"count":0,"href":"https:\/\/drkeithjones.com\/index.php\/wp-json\/wp\/v2\/posts\/206\/revisions"}],"wp:attachment":[{"href":"https:\/\/drkeithjones.com\/index.php\/wp-json\/wp\/v2\/media?parent=206"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/drkeithjones.com\/index.php\/wp-json\/wp\/v2\/categories?post=206"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/drkeithjones.com\/index.php\/wp-json\/wp\/v2\/tags?post=206"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}