{"id":13508712,"url":"https://github.com/cobenian/expcap","last_synced_at":"2026-02-24T04:01:35.653Z","repository":{"id":25229927,"uuid":"28654371","full_name":"Cobenian/expcap","owner":"Cobenian","description":"Elixir PCAP library","archived":false,"fork":false,"pushed_at":"2022-11-22T01:51:07.000Z","size":4585,"stargazers_count":33,"open_issues_count":3,"forks_count":13,"subscribers_count":3,"default_branch":"master","last_synced_at":"2025-11-22T05:20:30.782Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"Elixir","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/Cobenian.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2014-12-31T03:22:46.000Z","updated_at":"2025-03-04T03:02:30.000Z","dependencies_parsed_at":"2023-01-14T08:00:54.828Z","dependency_job_id":null,"html_url":"https://github.com/Cobenian/expcap","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/Cobenian/expcap","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Cobenian%2Fexpcap","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Cobenian%2Fexpcap/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Cobenian%2Fexpcap/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Cobenian%2Fexpcap/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/Cobenian","download_url":"https://codeload.github.com/Cobenian/expcap/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Cobenian%2Fexpcap/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":29771038,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-02-24T04:01:02.180Z","status":"ssl_error","status_checked_at":"2026-02-24T03:59:49.901Z","response_time":75,"last_error":"SSL_read: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2024-08-01T02:00:57.376Z","updated_at":"2026-02-24T04:01:35.618Z","avatar_url":"https://github.com/Cobenian.png","language":"Elixir","funding_links":[],"categories":["Networking"],"sub_categories":[],"readme":"ExPcap\n======\n\n[![hex.pm Custom](https://img.shields.io/badge/expcap-Elixir-brightgreen.svg)](https://hex.pm/packages/expcap)\n[![hex.pm Version](https://img.shields.io/hexpm/v/expcap.svg)](https://hex.pm/packages/expcap)\n[![hex.pm License](https://img.shields.io/hexpm/l/plug.svg)](https://hex.pm/packages/expcap)\n\nA PCAP library written in Elixir. This does not wrap a C or Erlang PCAP library,\nrather it attempts to be an idiomatic Elixir library.\n\nThis library parses pcap files, however it does not yet support most protocols\nthat can be contained within a pcap file. The only supported protocols at the\nmoment are:\n\n* Ethernet\n* IPv4\n* UDP\n* DNS\n\n## Add Dependency\n\nIn mix.exs add a dependency:\n\n    {:expcap, \"~\u003e 0.1.0\"}\n\n## Documentation\n\nDocumentation can be found at http://cobenian.github.io/expcap\n\n## Documentation\n\nYou must have run mix deps.get and mix deps.compile first.\n\n    mix docs\n\n## Build\n\nYou must have Elixir 1.0.0+ installed along with mix.\n\n    mix deps.get\n    mix deps.compile\n    mix compile\n    mix escript.build\n\n## Test\n\nYou must have run mix deps.get and mix deps.compile first.\n\n    mix test\n\n## Run via Escript\n\nOnce the project has been built, the following escript can be run:\n\n    ./expcap -f \u003cpath-file-pcap-file\u003e\n\nA sample DNS cap file can be found in test/data/dns.cap. This file is provided\nby Wireshark as a sample capture.\n\n    ./expcap -f test/data/dns.cap\n\n## Programmatic Use\n\nHere is a sample using mix:\n\n    iex -S mix\n    iex\u003e ExPcap.from_file \"test/data/dns.cap\"\n\nIf you want to print the string in a more user friendly format:\n\n    iex -S mix\n    iex\u003e \"test/data/dns.cap\" |\u003e ExPcap.from_file |\u003e String.Chars.to_string\n\n### Windows\n\nEscript does not run on Windows so the expcap escript will not work. However,\nthe code in this library should work on Windows if used as an Elixir library.\nThis has *not* been tested that we are aware of.\n\n## Adding Support For Additional Protocols\n\nAdding support for additional protocols is not difficult. Any protocol that\nmay contain your protocol in its body should be updated to indicate that your\nprotocol is supported.\n\n* Update encapsulating protocols to be aware of the new protocol\n\nFor example, if we are adding the UDP protocol and it can be encapsulated in\nIPv4 packets, we need to modify the IPv4 PayloadType protocol. In this case we\nwould add the following line:\n\n```elixir\n    \u003c\u003c17\u003e\u003e -\u003e Protocol.Udp\n```\n\nNote that each protocol is different in this regard. For example, in IPv4 the\nheader contains a 'protocol' field that indicates the content type of the body.\nThe new IPv4 PayloadType implementation would look like:\n\n```elixir\n    defimpl PayloadType, for: Protocol.Ipv4 do\n      @doc \"\"\"\n      Returns the parser that will parse the body of this IPv4 packet.\n      \"\"\"\n      @spec payload_parser(binary) :: PayloadParser.t\n      def payload_parser(data) do\n        case data.header.protocol do\n          \u003c\u003c06\u003e\u003e -\u003e Protocol.Tcp\n          \u003c\u003c17\u003e\u003e -\u003e Protocol.Udp\n        end\n      end\n    end\n```\n\nBare Bones:\n\n```elixir\n    defimpl PayloadType, for: Protocol.Ipv4 do\n      def payload_parser(data) do\n        case data.header.protocol do\n          \u003c\u003c06\u003e\u003e -\u003e Protocol.Tcp\n          \u003c\u003c17\u003e\u003e -\u003e Protocol.Udp\n        end\n      end\n    end\n```\n\n* Create a module and struct for your protocol\n\nFor many protocols this means having header and data sections only. You may\nwant to include a \"parsed data\" element as well.  Here is an example:\n\n```elixir\n    defmodule Protocol.Udp do\n      @moduledoc \"\"\"\n      A parsed UDP packet\n      \"\"\"\n\n      @bytes_in_header 8\n\n      defstruct header: %Protocol.Udp.Header{},\n                data: \u003c\u003c\u003e\u003e\n\n      @type t :: %Protocol.Udp{\n        header: Protocol.Udp.Header.t,\n        data: binary\n      }\n    end\n\n```\n\nBare Bones:\n\n```elixir\n    defmodule Protocol.Udp do\n      defstruct header: %Protocol.Udp.Header{},\n                data: \u003c\u003c\u003e\u003e\n    end\n```\n\n* Create a struct for your protocol's header (optional)\n\nThis is not strictly required, but is generally a good practice.\n\nHere is an example:\n\n```elixir\n    defmodule Protocol.Udp.Header do\n      @moduledoc \"\"\"\n      A parsed UDP packet header\n      \"\"\"\n      defstruct srcport:     \u003c\u003c\u003e\u003e,\n                destport:    \u003c\u003c\u003e\u003e,\n                length:      \u003c\u003c\u003e\u003e,\n                checksum:    \u003c\u003c\u003e\u003e\n\n      @type t :: %Protocol.Udp.Header{\n        srcport:  non_neg_integer,\n        destport: non_neg_integer,\n        length:   binary,\n        checksum: binary\n      }\n    end\n```\n\nBare Bones:\n\n```elixir\n    defmodule Protocol.Udp.Header do\n      defstruct srcport:     \u003c\u003c\u003e\u003e,\n                destport:    \u003c\u003c\u003e\u003e,\n                length:      \u003c\u003c\u003e\u003e,\n                checksum:    \u003c\u003c\u003e\u003e\n    end\n```\n\n* Implement the PayloadType protocol\n\nExample:\n\n```elixir\n    defimpl PayloadType, for: Protocol.Udp do\n      @doc \"\"\"\n      Returns the parser that will parse the body of the UDP packet\n      \"\"\"\n      @spec payload_parser(binary) :: Protocol.Udp.t\n      def payload_parser(_data) do\n        Protocol.Dns\n      end\n    end\n```\n\nBare Bones:\n\n```elixir\n    defimpl PayloadType, for: Protocol.Udp do\n      def payload_parser(_data) do\n        Protocol.Dns\n      end\n    end\n```\n\n* Implement the PayloadParser protocol\n\nExample:\n\n```elixir\n    defimpl PayloadParser, for: Protocol.Udp do\n      @doc \"\"\"\n      Returns the parsed body of the UDP packet\n      \"\"\"\n      @spec from_data(binary) :: any\n      def from_data(data) do\n        Protocol.Udp.from_data data\n      end\n    end\n```\n\nBare Bones:\n\n```elixir\n    defimpl PayloadParser, for: Protocol.Udp do\n      def from_data(data) do\n        Protocol.Udp.from_data data\n      end\n    end\n```\n\n* Add support for parsing your header (optional if you do not have a header)\n\nExample:\n\n```elixir\n    @doc \"\"\"\n    Parses the header of a UDP packet\n    \"\"\"\n    @spec header(binary) :: Protocol.Udp.Header.t\n    def header(data) do\n      \u003c\u003c\n      srcport       :: unsigned-integer-size(16),\n      destport      :: unsigned-integer-size(16),\n      length        :: bytes-size(2),\n      checksum      :: bytes-size(2),\n      _payload       :: binary\n      \u003e\u003e = data\n      %Protocol.Udp.Header{\n        srcport: srcport,\n        destport: destport,\n        length: length,\n        checksum: checksum\n      }\n    end\n```\n\nBare Bones:\n\n```elixir\n    def header(data) do\n      \u003c\u003c\n        srcport       :: unsigned-integer-size(16),\n        destport      :: unsigned-integer-size(16),\n        length        :: bytes-size(2),\n        checksum      :: bytes-size(2),\n        _payload       :: binary\n      \u003e\u003e = data\n      %Protocol.Udp.Header{\n        srcport: srcport,\n        destport: destport,\n        length: length,\n        checksum: checksum\n      }\n    end\n```\n\n* Add support for parsing your protocol\n\nExample:\n\n```elixir\n    @doc \"\"\"\n    Returns a parsed UDP packet\n    \"\"\"\n    @spec from_data(binary) :: Protocol.Udp.t\n    def from_data(data) do\n      \u003c\u003c _header :: bytes-size(@bytes_in_header), payload :: binary \u003e\u003e = data\n      %Protocol.Udp{\n        header: header(data),\n        data: payload\n      }\n    end\n```\n\nBare Bones:\n\n```elixir\n    def from_data(data) do\n      \u003c\u003c _header :: bytes-size(@bytes_in_header), payload :: binary \u003e\u003e = data\n      %Protocol.Udp{\n        header: header(data),\n        data: payload\n      }\n    end\n```\n\n* Add support for printing your header to string (optional if you do not have a header)\n\nExample:\n\n```elixir\n    defimpl String.Chars, for: Protocol.Udp.Header do\n      @doc \"\"\"\n      Prints a UDP packet header to a human readable string\n      \"\"\"\n      @spec to_string(Protocol.Udp.t) :: String.t\n      def to_string(udp) do\n        String.trim(\"\"\"\n        srcport:          #{udp.srcport}\n        srcport:          #{udp.destport}\n        length:           #{ExPcap.Binaries.to_uint16(udp.length)}\n        checksum:         #{ExPcap.Binaries.to_hex(udp.checksum)}\n        \"\"\")\n      end\n    end\n```\n\nBare Bones:\n\n```elixir\n    defimpl String.Chars, for: Protocol.Udp.Header do\n      def to_string(udp) do\n        String.trim(\"\"\"\n        srcport:          #{udp.srcport}\n        srcport:          #{udp.destport}\n        length:           #{ExPcap.Binaries.to_uint16(udp.length)}\n        checksum:         #{ExPcap.Binaries.to_hex(udp.checksum)}\n        \"\"\")\n      end\n    end\n```\n\n* Add support for printing your protocol to string\n\nExample:\n\n```elixir\n    defimpl String.Chars, for: Protocol.Udp do\n      @doc \"\"\"\n      Prints a UDP packet to a human readable string\n      \"\"\"\n      @spec to_string(Protocol.Udp.t) :: String.t\n      def to_string(udp) do\n        String.trim(\"\"\"\n        Udp:\n        #{udp.header}\n        Length:           #{byte_size(udp.data)}\n        Raw:              #{ExPcap.Binaries.to_raw(udp.data)}\n        \"\"\")\n      end\n    end\n```\n\nBare Bones:\n\n```elixir\n    defimpl String.Chars, for: Protocol.Udp do\n      def to_string(udp) do\n        String.trim(\"\"\"\n        Udp:\n        #{udp.header}\n        Length:           #{byte_size(udp.data)}\n        Raw:              #{ExPcap.Binaries.to_raw(udp.data)}\n        \"\"\")\n      end\n    end\n```\n\n## Limitations\n\n* Very few protocols are supported at this time.\n* Well formed pcap files can be parsed properly, however corrupted pcap files\nmay not have helpful error messages.\n* Escript will not run on Windows, but the code should.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fcobenian%2Fexpcap","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fcobenian%2Fexpcap","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fcobenian%2Fexpcap/lists"}