{"id":13582352,"url":"https://github.com/assafmo/joincap","last_synced_at":"2025-10-06T07:18:13.872Z","repository":{"id":57497008,"uuid":"135612140","full_name":"assafmo/joincap","owner":"assafmo","description":"Merge multiple pcap files together, gracefully.","archived":false,"fork":false,"pushed_at":"2024-11-14T14:51:17.000Z","size":2615,"stargazers_count":215,"open_issues_count":3,"forks_count":22,"subscribers_count":10,"default_branch":"master","last_synced_at":"2025-03-28T06:10:25.437Z","etag":null,"topics":["command-line","commandline","concat","forensics","join","merge","network","network-analysis","packet","packet-processing","pcap","pcap-files","pcap-processor","sysadmin","sysadmin-tool","tcpdump","tcpdump-capture"],"latest_commit_sha":null,"homepage":"","language":"Go","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/assafmo.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2018-05-31T16:57:22.000Z","updated_at":"2025-03-02T01:41:37.000Z","dependencies_parsed_at":"2024-06-20T04:44:35.165Z","dependency_job_id":"fa0d0d11-15a1-4c8c-a7f4-32df8286de4b","html_url":"https://github.com/assafmo/joincap","commit_stats":{"total_commits":292,"total_committers":3,"mean_commits":97.33333333333333,"dds":"0.017123287671232834","last_synced_commit":"9ee7aaebd8e3c8586461a48181cd9dad31d1c7a1"},"previous_names":[],"tags_count":30,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/assafmo%2Fjoincap","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/assafmo%2Fjoincap/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/assafmo%2Fjoincap/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/assafmo%2Fjoincap/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/assafmo","download_url":"https://codeload.github.com/assafmo/joincap/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":247135144,"owners_count":20889421,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","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":["command-line","commandline","concat","forensics","join","merge","network","network-analysis","packet","packet-processing","pcap","pcap-files","pcap-processor","sysadmin","sysadmin-tool","tcpdump","tcpdump-capture"],"created_at":"2024-08-01T15:02:37.769Z","updated_at":"2025-10-06T07:18:13.866Z","avatar_url":"https://github.com/assafmo.png","language":"Go","funding_links":[],"categories":["Software Packages","Go","软件包","Other Software","Go Tools","Go 工具"],"sub_categories":["Other Software","其他软件库和软件包","其他软件"],"readme":"# joincap\n\nMerge multiple pcap files together, gracefully.\n\n[![CircleCI](https://circleci.com/gh/assafmo/joincap.svg?style=shield\u0026circle-token=cd4f46d248b7601530558ae6559a20ff75a897ad)](https://circleci.com/gh/assafmo/joincap)\n[![Coverage Status](https://coveralls.io/repos/github/assafmo/joincap/badge.svg?branch=master)](https://coveralls.io/github/assafmo/joincap?branch=master)\n[![Go Report Card](https://goreportcard.com/badge/github.com/assafmo/joincap)](https://goreportcard.com/report/github.com/assafmo/joincap)\n[![GoDoc](https://godoc.org/github.com/assafmo/joincap?status.svg)](https://godoc.org/github.com/assafmo/joincap)\n[![Ask DeepWiki](https://deepwiki.com/badge.svg)](https://deepwiki.com/assafmo/joincap)\n\n## Installation\n\n- Download a precompiled binary from https://github.com/assafmo/joincap/releases\n- Or... Use `go get`:\n\n  ```bash\n  go get -u github.com/assafmo/joincap\n  ```\n\n- Or use Ubuntu PPA:\n\n  ```bash\n  curl -SsL https://assafmo.github.io/ppa/ubuntu/KEY.gpg | sudo apt-key add -\n  sudo curl -SsL -o /etc/apt/sources.list.d/assafmo.list https://assafmo.github.io/ppa/ubuntu/assafmo.list\n  sudo apt update\n  sudo apt install joincap\n  ```\n\n## Basic Usage\n\n```bash\nUsage:\n  joincap [OPTIONS] InFiles...\n\nApplication Options:\n  -v, --verbose        Explain when skipping packets or entire input files\n  -V, --version        Print the version and exit\n  -w=                  Sets the output filename. If the name is '-', stdout will be used (default: -)\n  -c=                  An integer argument for limiting the pcap size (default: 9223372036854775807)\n  -p=[micros|nanos]    Sets timestamp precision (default: micros)\n\nHelp Options:\n  -h, --help            Show this help message\n```\n\n## Why?\n\nI believe skipping corrupt packets is better than failing the entire merge job.  \nWhen using `tcpslice` or `mergecap` sometimes `pcapfix` is needed to fix bad input pcap files.\n\n1.  One option is to try and run merge (`mergecap`/`tcpslice`), if we get errors then run `pcapfix` on the bad pcaps and then run merge again.\n    - Adds complexity (run -\u003e check errors -\u003e fix -\u003e rerun)\n    - (If errors) Demands more resources (`pcapfix` processes)\n    - (If errors) Extends the total run time\n2.  Another option is to run `pcapfix` on the input pcap files and then merge.\n    - Extends the total run time by a lot (read and write each pcap twice instead of once)\n    - Demands more storage (for the fixed pcaps)\n    - Demands more resources (`pcapfix` processes)\n3.  We can use `pcapfix` \"in memory\" with process substitution: `mergecap -w out.pcap \u003c(pcapfix -o /dev/stdout 1.pcap) \u003c(pcapfix -o /dev/stdout 2.pcap)`.\n    - Adds complexity (build a complex command line)\n    - Demands more resources (`pcapfix` processes)\n    - Harder for us to use pathname expansion (e.g. `tcpslice -w out.pcap *.pcap`)\n    - We have to mind the command line character limit (in case of long pathnames)\n    - Doesn't work for `tcpslice` (seeks the last packets to calculate time ranges - cannot do this with pipes)\n\n## Error handling: `joincap` vs `mergecap` vs `tcpslice`\n\n### Results\n\n| Use case                                                                                              | joincap            | mergecap v2.4.5    | tcpslice v1.2a3    |\n| ----------------------------------------------------------------------------------------------------- | ------------------ | ------------------ | ------------------ |\n| Corrupt input global header                                                                           | :heavy_check_mark: | :x:                | :x:                |\n| Corrupt input packet header                                                                           | :heavy_check_mark: | :x:                | :x:                |\n| Unexpectd EOF\u003cbr\u003e(last packet data is truncated)                                                      | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: |\n| Input pcap has no packets\u003cbr\u003e(global header is ok, no first packet header)                            | :heavy_check_mark: | :heavy_check_mark: | :x:                |\n| Input file size is smaller than 24 bytes\u003cbr\u003e(global header is truncated)                              | :heavy_check_mark: | :heavy_check_mark: | :x:                |\n| Input file size is between 24 and 40 bytes\u003cbr\u003e(global header is ok, first packet header is truncated) | :heavy_check_mark: | :x:                | :x:                |\n| Input file doesn't exists                                                                             | :heavy_check_mark: | :x:                | :x:                |\n| Input file is a directory                                                                             | :heavy_check_mark: | :x:                | :x:                |\n| Input file end is garbage                                                                             | :heavy_check_mark: | :heavy_check_mark: | :x:                |\n| Input file is gzipped (.pcap.gz)                                                                      | :heavy_check_mark: | :heavy_check_mark: | :x:                |\n\n### Error outputs\n\n| Use case                                                                                              | Error outputs                                                                                                                                                                                                                                                                                       |\n| ----------------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |\n| Corrupt input global header                                                                           | \u003cul\u003e\u003cli\u003e`tcpslice: bad tcpdump file test_pcaps/bad_global.pcap: archaic pcap savefile format`\u003c/li\u003e\u003cli\u003e`mergecap: The file \"test_pcaps/bad_global.pcap\" contains record data that mergecap doesn't support. (pcap: major version 0 unsupported)`\u003c/li\u003e\u003c/ul\u003e                                           |\n| Corrupt input packet header                                                                           | \u003cul\u003e\u003cli\u003etcpslice: Infinite loop?\u003c/li\u003e\u003cli\u003e`mergecap: The file \"test_pcaps/bad_first_header.pcap\" appears to be damaged or corrupt. (pcap: File has 2368110654-byte packet, bigger than maximum of 262144)`\u003c/li\u003e\u003c/ul\u003e                                                                                 |\n| Unexpectd EOF\u003cbr\u003e(last packet data is truncated)                                                      |                                                                                                                                                                                                                                                                                                     |\n| Input pcap has no packets\u003cbr\u003e(global header is ok, no first packet header)                            | \u003cul\u003e\u003cli\u003etcpslice: Outputs empty pcap (Only global header)\u003c/li\u003e\u003c/ul\u003e                                                                                                                                                                                                                                 |\n| Input file size is smaller than 24 bytes\u003cbr\u003e(global header is truncated)                              | \u003cul\u003e\u003cli\u003e`tcpslice: bad tcpdump file test_pcaps/empty: truncated dump file; tried to read 4 file header bytes, only got 0`\u003c/li\u003e\u003c/ul\u003e                                                                                                                                                                 |\n| Input file size is between 24 and 40 bytes\u003cbr\u003e(global header is ok, first packet header is truncated) | \u003cul\u003e\u003cli\u003e`tcpslice: bad status reading first packet in test_pcaps/partial_first_header.pcap: truncated dump file; tried to read 16 header bytes, only got 11`\u003c/li\u003e\u003cli\u003e`mergecap: The file \"test_pcaps/partial_first_header.pcap\" appears to have been cut short in the middle of a paket.`\u003c/li\u003e\u003c/ul\u003e |\n| Input file doesn't exists                                                                             | \u003cul\u003e\u003cli\u003e`tcpslice: bad tcpdump file ./not_here: ./not_here: No such file or directory`\u003c/li\u003e\u003cli\u003e`mergecap: The file \"./not_here\" doesn't exist.`\u003c/li\u003e\u003c/ul\u003e                                                                                                                                           |\n| Input file is a directory                                                                             | \u003cul\u003e\u003cli\u003e`tcpslice: bad tcpdump file examples: error reading dump file: Is a directory`\u003c/li\u003e\u003cli\u003e`mergecap: \"examples\" is a directory (folder), not a file.`\u003c/li\u003e\u003c/ul\u003e                                                                                                                                |\n| Input file end is garbage                                                                             | \u003cul\u003e\u003cli\u003e`tcpslice: problems finding end packet of file test_pcaps/bad_end.pcap`\u003c/li\u003e\u003c/ul\u003e                                                                                                                                                                                                           |\n| Input file is gzipped (.pcap.gz)                                                                      | \u003cul\u003e\u003cli\u003e`tcpslice: bad tcpdump file test_pcaps/ok.pcap.gz: unknown file format`\u003c/li\u003e\u003c/ul\u003e                                                                                                                                                                                                           |\n\n### How to reproduce\n\n| Use case                                                                                              | How to reproduce                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                         |\n| ----------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |\n| Corrupt input global header                                                                           | \u003cul\u003e\u003cli\u003e`joincap -w out_joincap.pcap test_pcaps/bad_global.pcap`\u003c/li\u003e\u003cli\u003e`mergecap -w out_mergecap.pcap test_pcaps/bad_global.pcap`\u003c/li\u003e\u003cli\u003e`tcpslice -D -w out_tcpslice.pcap test_pcaps/bad_global.pcap`\u003c/li\u003e\u003c/ul\u003e                                                                                                                                                                                                                                                                                                                                      |\n| Corrupt input packet header                                                                           | \u003cul\u003e\u003cli\u003e`joincap -w out_joincap.pcap test_pcaps/bad_first_header.pcap`\u003c/li\u003e\u003cli\u003e`mergecap -w out_mergecap.pcap test_pcaps/bad_first_header.pcap`\u003c/li\u003e\u003cli\u003e`tcpslice -D -w out_tcpslice.pcap test_pcaps/bad_first_header.pcap`\u003c/li\u003e\u003c/ul\u003e                                                                                                                                                                                                                                                                                                                    |\n| Unexpectd EOF\u003cbr\u003e(last packet data is truncated)                                                      | \u003cul\u003e\u003cli\u003e`joincap -w out_joincap.pcap test_pcaps/unexpected_eof_on_first_packet.pcap`\u003c/li\u003e\u003cli\u003e`mergecap -w out_mergecap.pcap test_pcaps/unexpected_eof_on_first_packet.pcap`\u003c/li\u003e\u003cli\u003e`tcpslice -D -w out_tcpslice.pcap test_pcaps/unexpected_eof_on_first_packet.pcap`\u003c/li\u003e\u003cli\u003e`joincap -w out_joincap.pcap test_pcaps/unexpected_eof_on_second_packet.pcap`\u003c/li\u003e\u003cli\u003e`mergecap -w out_mergecap.pcap test_pcaps/unexpected_eof_on_second_packet.pcap`\u003c/li\u003e\u003cli\u003e`tcpslice -D -w out_tcpslice.pcap test_pcaps/unexpected_eof_on_second_packet.pcap`\u003c/li\u003e\u003c/ul\u003e |\n| Input pcap has no packets\u003cbr\u003e(global header is ok, no first packet header)                            | \u003cul\u003e\u003cli\u003e`joincap -w out_joincap.pcap test_pcaps/ok.pcap test_pcaps/no_packets.pcap`\u003c/li\u003e\u003cli\u003e`mergecap -w out_mergecap.pcap test_pcaps/ok.pcap test_pcaps/no_packets.pcap`\u003c/li\u003e\u003cli\u003e`tcpslice -D -w out_tcpslice.pcap test_pcaps/ok.pcap test_pcaps/no_packets.pcap`\u003c/li\u003e\u003c/ul\u003e                                                                                                                                                                                                                                                                             |\n| Input file size is smaller than 24 bytes\u003cbr\u003e(global header is truncated)                              | \u003cul\u003e\u003cli\u003e`joincap -w out_joincap.pcap test_pcaps/ok.pcap test_pcaps/empty`\u003c/li\u003e\u003cli\u003e`mergecap -w out_mergecap.pcap test_pcaps/ok.pcap test_pcaps/empty`\u003c/li\u003e\u003cli\u003e`tcpslice -D -w out_tcpslice.pcap test_pcaps/ok.pcap test_pcaps/empty`\u003c/li\u003e\u003cli\u003e`joincap -w out_joincap.pcap test_pcaps/ok.pcap test_pcaps/partial_global_header.pcap`\u003c/li\u003e\u003cli\u003e`mergecap -w out_mergecap.pcap test_pcaps/ok.pcap test_pcaps/partial_global_header.pcap`\u003c/li\u003e\u003cli\u003e`tcpslic -De -w out_tcpslice.pcap test_pcaps/ok.pcap test_pcaps/partial_global_header.pcap`\u003c/li\u003e\u003c/ul\u003e       |\n| Input file size is between 24 and 40 bytes\u003cbr\u003e(global header is ok, first packet header is truncated) | \u003cul\u003e\u003cli\u003e`joincap -w out_joincap.pcap test_pcaps/ok.pcap test_pcaps/partial_first_header.pcap`\u003c/li\u003e\u003cli\u003e`mergecap -w out_mergecap.pcap test_pcaps/ok.pcap test_pcaps/partial_first_header.pcap`\u003c/li\u003e\u003cli\u003e`tcpslic -De -w out_tcpslice.pcap test_pcaps/ok.pcap test_pcaps/partial_first_header.pcap`\u003c/li\u003e\u003c/ul\u003e                                                                                                                                                                                                                                               |\n| Input file doesn't exists                                                                             | \u003cul\u003e\u003cli\u003e`joincap -w out_joincap.pcap test_pcaps/ok.pcap ./not_here`\u003c/li\u003e\u003cli\u003e`mergecap -w out_mergecap.pcap test_pcaps/ok.pcap ./not_here`\u003c/li\u003e\u003cli\u003e`tcpslice -D -w out_tcpslice.pcap test_pcaps/ok.pcap ./not_here`\u003c/li\u003e\u003c/ul\u003e                                                                                                                                                                                                                                                                                                                             |\n| Input file is a directory                                                                             | \u003cul\u003e\u003cli\u003e`joincap -w out_joincap.pcap test_pcaps/ok.pcap test_pcaps/`\u003c/li\u003e\u003cli\u003e`mergecap -w out_mergecap.pcap test_pcaps/ok.pcap test_pcaps/`\u003c/li\u003e\u003cli\u003e`tcpslice -D -w out_tcpslice.pcap test_pcaps/ok.pcap test_pcaps/`\u003c/li\u003e\u003c/ul\u003e                                                                                                                                                                                                                                                                                                                          |\n| Input file end is garbage                                                                             | \u003cul\u003e\u003cli\u003e`joincap -w out_joincap.pcap test_pcaps/ok.pcap test_pcaps/bad_end.pcap`\u003c/li\u003e\u003cli\u003e`mergecap -w out_mergecap.pcap test_pcaps/ok.pcap test_pcaps/bad_end.pcap`\u003c/li\u003e\u003cli\u003e`tcpslice -D -w out_tcpslice.pcap test_pcaps/ok.pcap test_pcaps/bad_end.pcap`\u003c/li\u003e\u003c/ul\u003e                                                                                                                                                                                                                                                                                      |\n| Input file is gzipped (.pcap.gz)                                                                      | \u003cul\u003e\u003cli\u003e`joincap -w out_joincap.pcap test_pcaps/ok.pcap.gz`\u003c/li\u003e\u003cli\u003e`mergecap -w out_mergecap.pcap test_pcaps/ok.pcap.gz`\u003c/li\u003e\u003cli\u003e`tcpslice -D -w out_tcpslice.pcap test_pcaps/ok.pcap.gz`\u003c/li\u003e\u003c/ul\u003e                                                                                                                                                                                                                                                                                                                                                     |\n\n## Benchmarks\n\n|              | Version | Speed    | Time     |\n| ------------ | ------- | -------- | -------- |\n| **mergecap** | 3.2.2   | 590MiB/s | 0m5.632s |\n| **tcpslice** | 1.2a3   | 838MiB/s | 0m3.666s |\n| **joincap**  | 0.10.2  | 562MiB/s | 0m5.462s |\n\n- Merging 3 files with total size of 2.99994GiB.\n- Running on Linux 5.4.0-21-generic, with Intel(R) Core(TM) i7-9750H CPU @ 2.60GHz (with SSE4.2), with 31765 MB of physical memory, with locale C, with zlib 1.2.11.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fassafmo%2Fjoincap","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fassafmo%2Fjoincap","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fassafmo%2Fjoincap/lists"}