├── .buildconfig ├── global-query.yaml └── goprobe.yaml ├── .devcontainer ├── Dockerfile └── devcontainer.json ├── .github └── workflows │ ├── build-packages.yml │ ├── ci-pr.yml │ ├── ci-push.yml │ ├── codeql.yml │ └── pr-naming-rules.yml ├── .gitignore ├── LICENCE ├── README.md ├── cmd ├── global-query │ ├── .gitignore │ ├── README.md │ ├── cmd │ │ ├── help.go │ │ ├── init_querier.go │ │ ├── root.go │ │ └── server.go │ ├── main.go │ └── pkg │ │ ├── conf │ │ └── conf.go │ │ ├── distributed │ │ ├── querier.go │ │ └── query.go │ │ └── hosts │ │ └── resolve.go ├── goConvert │ ├── .gitignore │ ├── README.md │ ├── data.csv │ ├── goConvert.go │ └── goConvert_test.go ├── goProbe │ ├── README.md │ ├── config │ │ ├── config.go │ │ ├── config_test.go │ │ └── monitor.go │ ├── default.pgo │ ├── flags │ │ └── root.go │ └── goProbe.go ├── goQuery │ ├── .gitignore │ ├── README.md │ ├── cmd │ │ ├── doc.go │ │ ├── examples.go │ │ ├── help.go │ │ ├── help_test.go │ │ ├── list.go │ │ ├── profiling.go │ │ ├── root.go │ │ └── version.go │ ├── default.pgo │ ├── doc.go │ ├── main.go │ └── pkg │ │ └── conf │ │ └── conf.go ├── goquery_completion │ ├── cmd.go │ ├── cmd_test.go │ ├── common.go │ ├── conditional.go │ ├── conditional_test.go │ ├── default_database_path_public.go │ ├── flag.go │ ├── ifaces.go │ └── query_type.go └── gpctl │ ├── README.md │ ├── cmd │ ├── config.go │ ├── root.go │ ├── status.go │ └── version.go │ ├── main.go │ └── pkg │ └── conf │ └── conf.go ├── doc.go ├── examples ├── README.md ├── analyze-meta │ ├── .gitignore │ └── main.go └── config │ ├── dummy-querier.yaml │ ├── global-query-api-client-querier-example-config-devcontainer.yaml │ ├── global-query-api-client-querier-example-config.yaml │ ├── global-query-example-config-devcontainer.yaml │ ├── global-query-example-config.yaml │ ├── goprobe-example-config-devcontainer.yaml │ ├── goprobe-example-config.yaml │ ├── goprobe-example.service │ ├── goquery-example-config.yaml │ ├── gpctl-example-config-devcontainer.yaml │ └── gpctl-example-config.yaml ├── go.mod ├── go.sum ├── go.work ├── go.work.sum ├── img ├── goprobe_system_overview.png └── goprobe_system_overview_dark.png ├── pkg ├── api │ ├── api.go │ ├── client │ │ └── client.go │ ├── globalquery │ │ ├── client │ │ │ ├── client.go │ │ │ ├── stream.go │ │ │ └── stream_test.go │ │ └── server │ │ │ ├── server.go │ │ │ └── server_test.go │ ├── goprobe │ │ ├── api.go │ │ ├── client │ │ │ ├── client-config.go │ │ │ ├── client.go │ │ │ ├── config.go │ │ │ ├── query.go │ │ │ └── status.go │ │ └── server │ │ │ ├── config.go │ │ │ ├── config_api_ops.go │ │ │ ├── server.go │ │ │ ├── status.go │ │ │ └── status_api_ops.go │ ├── info_api_ops.go │ ├── middleware.go │ ├── query.go │ ├── query_api_ops.go │ ├── server │ │ ├── server.go │ │ ├── server_test.go │ │ └── spec.go │ └── util.go ├── capture │ ├── buffer.go │ ├── buffer_test.go │ ├── capture.go │ ├── capture_manager.go │ ├── capture_mock.go │ ├── capture_nomock.go │ ├── capture_test.go │ ├── captures.go │ ├── capturetypes │ │ ├── classify.go │ │ ├── config.go │ │ ├── packet.go │ │ ├── parsing_error.go │ │ ├── parsing_error_test.go │ │ └── status.go │ ├── doc.go │ ├── flow.go │ ├── metrics.go │ ├── packet_test.go │ └── rungroup.go ├── defaults │ └── defaults.go ├── e2etest │ ├── e2e_bench_test.go │ ├── e2e_test.go │ ├── extdata │ │ └── udpflows.pcap.gz │ ├── testdata │ │ ├── c04-wap-r1.pcap.gz │ │ ├── default.pcap.gz │ │ ├── fragmented.pcap.gz │ │ └── truncated.pcap.gz │ └── types.go ├── formatting │ ├── format.go │ └── format_test.go ├── goDB │ ├── .gitignore │ ├── DBWorkManager.go │ ├── Query.go │ ├── StringParser.go │ ├── SyslogConsts_public.go │ ├── SyslogDBWriter.go │ ├── conditions │ │ ├── node │ │ │ ├── desugar.go │ │ │ ├── desugar_test.go │ │ │ ├── filter_direction.go │ │ │ ├── filter_direction_test.go │ │ │ ├── instrument.go │ │ │ ├── instrument_test.go │ │ │ ├── node.go │ │ │ ├── node_test.go │ │ │ ├── parse.go │ │ │ ├── parse_test.go │ │ │ ├── resolve.go │ │ │ └── resolve_test.go │ │ ├── tokenize.go │ │ └── tokenize_test.go │ ├── database_format.md │ ├── db_writer.go │ ├── db_writer_test.go │ ├── doc.go │ ├── encoder │ │ ├── encoder.go │ │ ├── encoder_test.go │ │ ├── encoders │ │ │ └── encoders.go │ │ ├── lz4 │ │ │ ├── lz4.go │ │ │ ├── lz4_cgo.go │ │ │ ├── lz4_native.go │ │ │ └── lz4_test.go │ │ ├── lz4cust │ │ │ └── lz4cust.go │ │ ├── null │ │ │ └── null.go │ │ └── zstd │ │ │ ├── zstd.go │ │ │ ├── zstd_cgo.go │ │ │ ├── zstd_native.go │ │ │ └── zstd_test.go │ ├── engine │ │ ├── aggregate.go │ │ ├── bench_gen.sh │ │ ├── benchgen │ │ │ └── main.go │ │ ├── benchmarks_test.go │ │ ├── flush_darwin.go │ │ ├── flush_linux.go │ │ ├── gen.go │ │ ├── query.go │ │ ├── query_test.go │ │ └── testdb │ │ │ ├── eth0 │ │ │ └── 2016 │ │ │ │ └── 02 │ │ │ │ ├── 1456358400 │ │ │ │ ├── .blockmeta │ │ │ │ ├── bytes_rcvd.gpf │ │ │ │ ├── bytes_sent.gpf │ │ │ │ ├── dip.gpf │ │ │ │ ├── dport.gpf │ │ │ │ ├── pkts_rcvd.gpf │ │ │ │ ├── pkts_sent.gpf │ │ │ │ ├── proto.gpf │ │ │ │ └── sip.gpf │ │ │ │ └── 1456444800_mm1-0-eE3-SvUZv-SF9Du1-CFM4-Ppa6 │ │ │ │ ├── .blockmeta │ │ │ │ ├── bytes_rcvd.gpf │ │ │ │ ├── bytes_sent.gpf │ │ │ │ ├── dip.gpf │ │ │ │ ├── dport.gpf │ │ │ │ ├── pkts_rcvd.gpf │ │ │ │ ├── pkts_sent.gpf │ │ │ │ ├── proto.gpf │ │ │ │ └── sip.gpf │ │ │ ├── eth1 │ │ │ └── 2016 │ │ │ │ └── 02 │ │ │ │ ├── 1456358400 │ │ │ │ ├── .blockmeta │ │ │ │ ├── bytes_rcvd.gpf │ │ │ │ ├── bytes_sent.gpf │ │ │ │ ├── dip.gpf │ │ │ │ ├── dport.gpf │ │ │ │ ├── pkts_rcvd.gpf │ │ │ │ ├── pkts_sent.gpf │ │ │ │ ├── proto.gpf │ │ │ │ └── sip.gpf │ │ │ │ └── 1456444800_oX-1-aVB1-8PILs4-AK9rM2-0Gt8-05he │ │ │ │ ├── .blockmeta │ │ │ │ ├── bytes_rcvd.gpf │ │ │ │ ├── bytes_sent.gpf │ │ │ │ ├── dip.gpf │ │ │ │ ├── dport.gpf │ │ │ │ ├── pkts_rcvd.gpf │ │ │ │ ├── pkts_sent.gpf │ │ │ │ ├── proto.gpf │ │ │ │ └── sip.gpf │ │ │ ├── eth2 │ │ │ └── 2016 │ │ │ │ └── 02 │ │ │ │ ├── 1456358400 │ │ │ │ ├── .blockmeta │ │ │ │ ├── bytes_rcvd.gpf │ │ │ │ ├── bytes_sent.gpf │ │ │ │ ├── dip.gpf │ │ │ │ ├── dport.gpf │ │ │ │ ├── pkts_rcvd.gpf │ │ │ │ ├── pkts_sent.gpf │ │ │ │ ├── proto.gpf │ │ │ │ └── sip.gpf │ │ │ │ └── 1456444800_w3-0-0-2mW1-KQ81-DA-Xo │ │ │ │ ├── .blockmeta │ │ │ │ ├── bytes_rcvd.gpf │ │ │ │ ├── bytes_sent.gpf │ │ │ │ ├── dip.gpf │ │ │ │ ├── dport.gpf │ │ │ │ ├── pkts_rcvd.gpf │ │ │ │ ├── pkts_sent.gpf │ │ │ │ ├── proto.gpf │ │ │ │ └── sip.gpf │ │ │ ├── t_c1_fwde │ │ │ └── 2016 │ │ │ │ └── 02 │ │ │ │ ├── 1456358400 │ │ │ │ ├── .blockmeta │ │ │ │ ├── bytes_rcvd.gpf │ │ │ │ ├── bytes_sent.gpf │ │ │ │ ├── dip.gpf │ │ │ │ ├── dport.gpf │ │ │ │ ├── pkts_rcvd.gpf │ │ │ │ ├── pkts_sent.gpf │ │ │ │ ├── proto.gpf │ │ │ │ └── sip.gpf │ │ │ │ └── 1456444800_Ns-0-0-fXANh-hb5ap-Eum1-o3w1 │ │ │ │ ├── .blockmeta │ │ │ │ ├── bytes_rcvd.gpf │ │ │ │ ├── bytes_sent.gpf │ │ │ │ ├── dip.gpf │ │ │ │ ├── dport.gpf │ │ │ │ ├── pkts_rcvd.gpf │ │ │ │ ├── pkts_sent.gpf │ │ │ │ ├── proto.gpf │ │ │ │ └── sip.gpf │ │ │ ├── t_c1_fwde1 │ │ │ └── 2016 │ │ │ │ └── 02 │ │ │ │ ├── 1456358400 │ │ │ │ ├── .blockmeta │ │ │ │ ├── bytes_rcvd.gpf │ │ │ │ ├── bytes_sent.gpf │ │ │ │ ├── dip.gpf │ │ │ │ ├── dport.gpf │ │ │ │ ├── pkts_rcvd.gpf │ │ │ │ ├── pkts_sent.gpf │ │ │ │ ├── proto.gpf │ │ │ │ └── sip.gpf │ │ │ │ └── 1456444800_a6-0-0-I6k54-JwjJ-Ltg-nij │ │ │ │ ├── .blockmeta │ │ │ │ ├── bytes_rcvd.gpf │ │ │ │ ├── bytes_sent.gpf │ │ │ │ ├── dip.gpf │ │ │ │ ├── dport.gpf │ │ │ │ ├── pkts_rcvd.gpf │ │ │ │ ├── pkts_sent.gpf │ │ │ │ ├── proto.gpf │ │ │ │ └── sip.gpf │ │ │ ├── tun_3g_c1_fw1 │ │ │ └── 2016 │ │ │ │ └── 02 │ │ │ │ ├── 1456358400 │ │ │ │ ├── .blockmeta │ │ │ │ ├── bytes_rcvd.gpf │ │ │ │ ├── bytes_sent.gpf │ │ │ │ ├── dip.gpf │ │ │ │ ├── dport.gpf │ │ │ │ ├── pkts_rcvd.gpf │ │ │ │ ├── pkts_sent.gpf │ │ │ │ ├── proto.gpf │ │ │ │ └── sip.gpf │ │ │ │ └── 1456444800_v1-0-0-yr7-j86-g9-P5 │ │ │ │ ├── .blockmeta │ │ │ │ ├── bytes_rcvd.gpf │ │ │ │ ├── bytes_sent.gpf │ │ │ │ ├── dip.gpf │ │ │ │ ├── dport.gpf │ │ │ │ ├── pkts_rcvd.gpf │ │ │ │ ├── pkts_sent.gpf │ │ │ │ ├── proto.gpf │ │ │ │ └── sip.gpf │ │ │ └── tun_3g_c1_fwde │ │ │ └── 2016 │ │ │ └── 02 │ │ │ ├── 1456358400 │ │ │ ├── .blockmeta │ │ │ ├── bytes_rcvd.gpf │ │ │ ├── bytes_sent.gpf │ │ │ ├── dip.gpf │ │ │ ├── dport.gpf │ │ │ ├── pkts_rcvd.gpf │ │ │ ├── pkts_sent.gpf │ │ │ ├── proto.gpf │ │ │ └── sip.gpf │ │ │ └── 1456444800_v1-0-0-cg6-bg5-18-T4 │ │ │ ├── .blockmeta │ │ │ ├── bytes_rcvd.gpf │ │ │ ├── bytes_sent.gpf │ │ │ ├── dip.gpf │ │ │ ├── dport.gpf │ │ │ ├── pkts_rcvd.gpf │ │ │ ├── pkts_sent.gpf │ │ │ ├── proto.gpf │ │ │ └── sip.gpf │ ├── filter.go │ ├── godb_test.go │ ├── info │ │ ├── hostid.go │ │ ├── hostid_default.go │ │ ├── hostid_linux.go │ │ ├── info.go │ │ ├── info_test.go │ │ └── interfaces.go │ ├── metadata.go │ ├── protocols │ │ ├── protocols.go │ │ ├── protocols_darwin.go │ │ ├── protocols_generator.go │ │ └── protocols_linux.go │ └── storage │ │ ├── gpfile │ │ ├── gpdir.go │ │ ├── gpfile.go │ │ ├── gpfile_test.go │ │ ├── metadata.go │ │ └── options.go │ │ └── storage.go ├── goprobe │ └── writeout │ │ ├── godb.go │ │ ├── handler.go │ │ └── metrics.go ├── query │ ├── README.md │ ├── args.go │ ├── args_test.go │ ├── defaults.go │ ├── defaults_darwin.go │ ├── defaults_linux.go │ ├── defaults_linux_arm.go │ ├── dns │ │ ├── dns.go │ │ ├── dns_public.go │ │ └── dns_test.go │ ├── doc.go │ ├── heap │ │ ├── heap.go │ │ ├── meminfo_darwin.go │ │ └── meminfo_linux.go │ ├── options.go │ ├── query.go │ ├── runner.go │ ├── statement.go │ ├── time.go │ └── time_test.go ├── results │ ├── TablePrinter.go │ ├── print.go │ ├── result.go │ ├── result_test.go │ └── sort.go ├── types │ ├── columns.go │ ├── columns_test.go │ ├── direction.go │ ├── errors.go │ ├── hashmap │ │ ├── LICENSE │ │ ├── PATENTS │ │ ├── aggregate.go │ │ ├── hashmap.go │ │ ├── hashmap_test.go │ │ ├── iterator.go │ │ └── list.go │ ├── iface.go │ ├── iface_test.go │ ├── interface_lister.go │ ├── keyval.go │ ├── shellformat │ │ ├── shellformat.go │ │ └── shellformat_test.go │ ├── types.go │ ├── types_test.go │ └── workload │ │ └── stats.go ├── util │ ├── tunnel_info.go │ └── tunnel_info_public.go └── version │ ├── .gitignore │ ├── make_version.go │ └── version.go ├── plugins ├── contrib │ ├── .gitignore │ ├── README.md │ ├── contrib.go │ ├── contrib_gen.go │ ├── gen.go │ ├── go.mod │ └── go.sum ├── plugin.go └── querier │ ├── apiclient │ └── querier.go │ └── init.go └── presentations └── 2025 └── goprobe_bern_meetup ├── .gitignore ├── .npmrc ├── Makefile ├── global-network-observability-with-goprobe.pdf ├── package.json ├── pictures ├── bg-initial.png ├── els0r-gh.png ├── fako1024-gh.png ├── goprobe_system_overview.png ├── goprobe_system_overview_gq_focus.png ├── goprobe_system_overview_host.png ├── hosts.png ├── ntm-global-analysis │ ├── ntm-global-analysis.001.png │ ├── ntm-global-analysis.002.png │ ├── ntm-global-analysis.003.png │ ├── ntm-global-analysis.004.png │ ├── ntm-global-analysis.005.png │ └── ntm-global-analysis.006.png ├── os.png ├── packet_detail.png ├── packets.png ├── packets_hosts.png ├── packets_os_hosts.png ├── packets_single.png └── slimcap │ ├── capture_flow_1.png │ ├── capture_flow_2.png │ ├── fine.jpg │ ├── layers.png │ ├── mock.png │ ├── ringbuf.png │ ├── ringbuf_1.png │ ├── ringbuf_2.png │ └── ringbuf_3.png ├── slides.md └── theme ├── CHANGELOG.md ├── LICENSE ├── README.md ├── example.md ├── layoutHelper.ts ├── layouts ├── 3-images.vue ├── bullets.vue ├── fact.vue ├── image-right.vue ├── intro-image-right.vue ├── intro-image.vue ├── intro.vue ├── quote.vue ├── section.vue └── statement.vue ├── package.json └── styles ├── index.ts ├── layout.css └── prism.css /.buildconfig/global-query.yaml: -------------------------------------------------------------------------------- 1 | logging: 2 | level: debug 3 | encoding: logfmt 4 | 5 | -------------------------------------------------------------------------------- /.buildconfig/goprobe.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | interfaces: 3 | lo: 4 | promisc: false 5 | ring_buffer: 6 | num_blocks: 4 7 | block_size: 1048576 8 | logging: 9 | level: debug 10 | encoding: logfmt 11 | -------------------------------------------------------------------------------- /.devcontainer/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM mcr.microsoft.com/devcontainers/go:1.23-bullseye 2 | 3 | RUN apt-get update && export DEBIAN_FRONTEND=noninteractive \ 4 | && apt-get -y install git \ 5 | build-essential \ 6 | curl 7 | 8 | # compression libs 9 | RUN apt install liblz4-dev libzstd-dev 10 | 11 | # convenience tools 12 | RUN apt install -y vim inetutils-ping 13 | 14 | # for goProbe's info tests 15 | RUN mkdir -p /var/lib/dbus/ && echo "da314207b73d8b1bdeb86e5adfa0d6cb" > /var/lib/dbus/machine-id 16 | 17 | # go 18 | USER vscode 19 | RUN go install golang.org/x/tools/gopls@latest 20 | RUN curl -sSfL https://raw.githubusercontent.com/golangci/golangci-lint/master/install.sh | sh -s -- -b $(go env GOPATH)/bin v1.54.2 21 | -------------------------------------------------------------------------------- /.devcontainer/devcontainer.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "goprobe-dev", 3 | "build": { 4 | "dockerfile": "Dockerfile", 5 | "args": { 6 | "HTTP_PROXY": "${localEnv:HTTP_PROXY}", 7 | "HTTPS_PROXY": "${localEnv:HTTP_PROXY}", 8 | "http_proxy": "${localEnv:HTTP_PROXY}", 9 | "https_proxy": "${localEnv:HTTP_PROXY}" 10 | } 11 | }, 12 | "containerEnv": { 13 | "GOWORK": "/workspaces/goProbe/go.work" 14 | }, 15 | "customizations": { 16 | "vscode": { 17 | "extensions": [ 18 | "golang.go", 19 | "eamodio.gitlens", 20 | "davidanson.vscode-markdownlint", 21 | "ms-azuretools.vscode-docker", 22 | "shardulm94.trailing-spaces", 23 | "Gruntfuggly.todo-tree", 24 | "bierner.emojisense", 25 | "stkb.rewrap", 26 | "vscode-icons-team.vscode-icons", 27 | "github.vscode-pull-request-github", 28 | "redhat.vscode-yaml", 29 | "IBM.output-colorizer", 30 | "github.copilot" 31 | ], 32 | "settings": { 33 | "files.eol": "\n", 34 | "editor.formatOnSave": true, 35 | "go.buildTags": "", 36 | "go.toolsEnvVars": { 37 | "CGO_ENABLED": "0" 38 | }, 39 | "go.useLanguageServer": true, 40 | "go.testEnvVars": { 41 | "CGO_ENABLED": "1" 42 | }, 43 | "go.testFlags": [ 44 | "-v", 45 | "-race" 46 | ], 47 | "go.testTimeout": "10s", 48 | "go.coverOnSingleTest": true, 49 | "go.coverOnSingleTestFile": true, 50 | "go.coverOnTestPackage": true, 51 | "go.lintTool": "golangci-lint", 52 | "go.lintOnSave": "package", 53 | "[go]": { 54 | "editor.codeActionsOnSave": { 55 | "source.organizeImports": "always" 56 | } 57 | }, 58 | "gopls": { 59 | "usePlaceholders": false, 60 | "staticcheck": true 61 | }, 62 | "remote.extensionKind": { 63 | "ms-azuretools.vscode-docker": "workspace" 64 | } 65 | } 66 | } 67 | }, 68 | "forwardPorts": [ 69 | 8145 70 | ] 71 | } 72 | -------------------------------------------------------------------------------- /.github/workflows/ci-pr.yml: -------------------------------------------------------------------------------- 1 | name: CI Build / Test (Pull Request) 2 | 3 | on: 4 | - pull_request 5 | 6 | jobs: 7 | 8 | build-linux: 9 | name: Build / Test on Linux 10 | runs-on: ubuntu-latest 11 | steps: 12 | - name: Set up Go 13 | uses: actions/setup-go@v5 14 | with: 15 | go-version: ^1.23 16 | id: go 17 | 18 | - name: Check out code into the Go module directory 19 | uses: actions/checkout@v4 20 | 21 | - name: Build for AMD64 22 | run: GOOS=linux GOARCH=amd64 go build -tags jsoniter -v ./... 23 | 24 | - name: Build for AMD64 (Production Mode) 25 | run: GOOS=linux GOARCH=amd64 go build -tags jsoniter,slimcap_nomock -v ./... 26 | 27 | - name: Build for AMD64 (No-GCO Mode) 28 | run: GOOS=linux GOARCH=amd64 CGO_ENABLED=0 go build -tags jsoniter -v ./... 29 | 30 | - name: Test 31 | run: | 32 | go test -tags jsoniter -v ./... -covermode=atomic -coverprofile=coverage.out 33 | go tool cover -func=coverage.out -o=coverage.out 34 | 35 | - name: Test (No-CGO Mode) 36 | run: | 37 | CGO_ENABLED=0 go test -tags jsoniter -v ./... 38 | 39 | - name: Test (Production Mode) 40 | run: | 41 | go test -tags jsoniter,slimcap_nomock -v ./... 42 | 43 | - name: Race Detector 44 | run: | 45 | go test -tags jsoniter -race -v ./... 46 | 47 | 48 | -------------------------------------------------------------------------------- /.github/workflows/ci-push.yml: -------------------------------------------------------------------------------- 1 | name: CI Build / Test (Push) 2 | 3 | on: 4 | - push 5 | 6 | jobs: 7 | 8 | build-linux: 9 | name: Build / Test on Linux 10 | runs-on: ubuntu-latest 11 | steps: 12 | - name: Set up Go 13 | uses: actions/setup-go@v5 14 | with: 15 | go-version: ^1.23 16 | id: go 17 | 18 | - name: Check out code into the Go module directory 19 | uses: actions/checkout@v4 20 | 21 | - name: Build for AMD64 22 | run: GOOS=linux GOARCH=amd64 go build -tags jsoniter -v ./... 23 | 24 | - name: Test 25 | run: | 26 | go test -tags jsoniter -v ./... -covermode=atomic -coverprofile=coverage.out 27 | go tool cover -func=coverage.out -o=coverage.out 28 | -------------------------------------------------------------------------------- /.github/workflows/pr-naming-rules.yml: -------------------------------------------------------------------------------- 1 | # Adopted from an action that is no longer maintained 2 | # https://github.com/deepakputhraya/action-pr-title 3 | name: Pull Request Validation 4 | on: 5 | pull_request: 6 | types: [opened, synchronize, edited, reopened] 7 | jobs: 8 | title-rules: 9 | runs-on: ubuntu-latest 10 | steps: 11 | - uses: actions/github-script@v7 12 | with: 13 | script: | 14 | const REGEX = new RegExp('^(\\[(feature|bugfix|doc|security|trivial)\\])+ [A-Z].+'); // Title must match this regex 15 | const MIN_LENGTH = 32; // Min length of the title 16 | const MAX_LENGTH = 256; // Max length of the title (-1 is no max) 17 | 18 | const { title } = context.payload.pull_request; 19 | if (!REGEX.test(title)) { 20 | core.setFailed( 21 | `Pull Request title "${title}" failed to match regex - ${REGEX}` 22 | ); 23 | return; 24 | } 25 | if (title.length < MIN_LENGTH) { 26 | core.setFailed( 27 | `Pull Request title "${title}" is smaller than the minimum length - ${MIN_LENGTH}` 28 | ); 29 | return; 30 | } 31 | if (MAX_LENGTH > 0 && title.length > MAX_LENGTH) { 32 | core.setFailed( 33 | `Pull Request title "${title}" is greater than the maximum length - ${MAX_LENGTH}` 34 | ); 35 | return; 36 | } 37 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | *.bz2 2 | *.deb 3 | *.test 4 | absolute 5 | cmd/global-query/global-query 6 | cmd/goConvert/goConvert 7 | cmd/goProbe/goProbe 8 | cmd/goQuery/goQuery 9 | cmd/gpctl/gpctl 10 | .vscode/ 11 | _build/ 12 | go.work.sum 13 | .db/ 14 | tmp/ 15 | bin/ 16 | 17 | .codegpt -------------------------------------------------------------------------------- /cmd/global-query/.gitignore: -------------------------------------------------------------------------------- 1 | global-query 2 | -------------------------------------------------------------------------------- /cmd/global-query/cmd/help.go: -------------------------------------------------------------------------------- 1 | package cmd 2 | 3 | var supportedCmds = "{server}" 4 | 5 | var helpBase = ` 6 | global-query ` + supportedCmds + ` 7 | 8 | Query server for running distributed goQuery queries and aggregating the results. 9 | ` 10 | 11 | var helpBaseLong = helpBase + ` 12 | Meant to run in server mode via the "server" command. 13 | ` 14 | -------------------------------------------------------------------------------- /cmd/global-query/cmd/init_querier.go: -------------------------------------------------------------------------------- 1 | package cmd 2 | 3 | import ( 4 | "context" 5 | 6 | "github.com/spf13/viper" 7 | 8 | "github.com/els0r/goProbe/v4/cmd/global-query/pkg/conf" 9 | "github.com/els0r/goProbe/v4/cmd/global-query/pkg/distributed" 10 | "github.com/els0r/goProbe/v4/plugins" 11 | 12 | // internal plugin support 13 | _ "github.com/els0r/goProbe/v4/plugins/querier" 14 | ) 15 | 16 | func initQuerier(ctx context.Context) (querier distributed.Querier, err error) { 17 | return plugins.InitQuerier(ctx, 18 | viper.GetString(conf.QuerierType), 19 | viper.GetString(conf.QuerierConfig), 20 | ) 21 | } 22 | -------------------------------------------------------------------------------- /cmd/global-query/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import "github.com/els0r/goProbe/v4/cmd/global-query/cmd" 4 | 5 | func main() { 6 | cmd.Execute() 7 | } 8 | -------------------------------------------------------------------------------- /cmd/global-query/pkg/conf/conf.go: -------------------------------------------------------------------------------- 1 | package conf 2 | 3 | import "time" 4 | 5 | const ( 6 | // ServiceName is the name of the service as it will show up in telemetry such as metrics, logs, traces, etc. 7 | ServiceName = "global_query" 8 | ) 9 | 10 | // Definnitions for command line parameters / arguments 11 | const ( 12 | loggingKey = "logging" 13 | LogLevel = loggingKey + ".level" 14 | LogEncoding = loggingKey + ".encoding" 15 | 16 | profilingKey = "profiling" 17 | ProfilingEnabled = profilingKey + ".enabled" 18 | 19 | hostsKey = "hosts" 20 | hostsResolverKey = hostsKey + ".resolver" 21 | 22 | HostsResolverType = hostsResolverKey + ".type" 23 | 24 | querierKey = "querier" 25 | 26 | QuerierType = querierKey + ".type" 27 | QuerierConfig = querierKey + ".config" 28 | QuerierMaxConcurrent = querierKey + ".max_concurrent" 29 | 30 | serverKey = "server" 31 | ServerAddr = serverKey + ".addr" 32 | ServerShutdownGracePeriod = serverKey + ".shutdowngraceperiod" 33 | 34 | openapiKey = "openapi" 35 | OpenAPISpecOutfile = openapiKey + ".spec-outfile" 36 | ) 37 | 38 | // Global defaults for command line parameters / arguments 39 | const ( 40 | DefaultLogLevel = "info" 41 | DefaultLogEncoding = "logfmt" 42 | 43 | DefaultHostsResolver = "string" 44 | 45 | DefaultHostsQuerierType = "api" 46 | 47 | DefaultServerAddr = "localhost:8145" 48 | DefaultServerShutdownGracePeriod = 30 * time.Second 49 | ) 50 | -------------------------------------------------------------------------------- /cmd/global-query/pkg/distributed/querier.go: -------------------------------------------------------------------------------- 1 | package distributed 2 | 3 | import ( 4 | "context" 5 | 6 | "github.com/els0r/goProbe/v4/cmd/global-query/pkg/hosts" 7 | "github.com/els0r/goProbe/v4/pkg/query" 8 | "github.com/els0r/goProbe/v4/pkg/results" 9 | ) 10 | 11 | // Querier provides a general interface for all query executors 12 | type Querier interface { 13 | // Query runs the distributed query on the provided hosts and returns a channel from 14 | // which the results can be read. In addition, keepalives are sent via a second channel. 15 | // It is the responsibility of the implementing type to close the channels. 16 | // This may become a requirement through the interface definitions in future versions. 17 | Query(ctx context.Context, hosts hosts.Hosts, args *query.Args) (<-chan *results.Result, <-chan struct{}) 18 | } 19 | 20 | // QuerierAnyable extends a "common" Querier with the support to retrieve a list of all hosts / targets 21 | // available to the Querier 22 | type QuerierAnyable interface { 23 | // AllHosts returns a list of all hosts / targets available to the Querier 24 | AllHosts() (hosts.Hosts, error) 25 | } 26 | 27 | // ErrorRunner is used to propagate an error all the way to the aggregation routine 28 | type ErrorRunner struct { 29 | err error 30 | } 31 | 32 | // NewErrorRunner creates a new error runner 33 | func NewErrorRunner(err error) *ErrorRunner { 34 | return &ErrorRunner{err: err} 35 | } 36 | 37 | // Run doesn't execute anything but returns the error that was passed to the constructor 38 | func (e *ErrorRunner) Run(_ context.Context, _ *query.Args) (*results.Result, error) { 39 | return nil, e.err 40 | } 41 | -------------------------------------------------------------------------------- /cmd/global-query/pkg/hosts/resolve.go: -------------------------------------------------------------------------------- 1 | package hosts 2 | 3 | import ( 4 | "context" 5 | "sort" 6 | "strings" 7 | ) 8 | 9 | // Hosts stores a list of host strings 10 | type Hosts []string 11 | 12 | // ResolverType enumerates the supported host resolvers 13 | type ResolverType string 14 | 15 | const ( 16 | // StringResolverType denotes a simple string resolver type 17 | StringResolverType ResolverType = "string" 18 | ) 19 | 20 | // Resolver returns a list of hosts based on the query string 21 | type Resolver interface { 22 | Resolve(ctx context.Context, query string) (Hosts, error) 23 | } 24 | 25 | // StringResolver transforms a comma-separated list of hosts into an array. Sorting is 26 | // enabled by default 27 | type StringResolver struct { 28 | sorted bool 29 | } 30 | 31 | // NewStringResolver creates a new string-based hosts resolver 32 | func NewStringResolver(sorted bool) *StringResolver { 33 | return &StringResolver{sorted: sorted} 34 | } 35 | 36 | // Resolve accepts a comma-separated list of hosts and returns them sorted and deduplicated in a Hosts array 37 | func (s *StringResolver) Resolve(_ context.Context, query string) (hostList Hosts, err error) { 38 | var hostMap = make(map[string]struct{}) 39 | for _, h := range strings.Split(strings.TrimSpace(query), ",") { 40 | _, exists := hostMap[h] 41 | if h != "" && !exists { 42 | hostMap[h] = struct{}{} 43 | } 44 | } 45 | hostList = make(Hosts, len(hostMap)) 46 | i := 0 47 | for k := range hostMap { 48 | hostList[i] = k 49 | i++ 50 | } 51 | sort.Slice(hostList, func(i, j int) bool { 52 | return hostList[i] < hostList[j] 53 | }) 54 | return hostList, nil 55 | } 56 | -------------------------------------------------------------------------------- /cmd/goConvert/.gitignore: -------------------------------------------------------------------------------- 1 | csvtestdb 2 | -------------------------------------------------------------------------------- /cmd/goConvert/README.md: -------------------------------------------------------------------------------- 1 | # goConvert 2 | 3 | > Ingest flow data from CSV files and convert it to GPFiles for goDBv 4 | 5 | ## Quick Start 6 | 7 | How to run 8 | 9 | ```sh 10 | go run goConvert.go --help 11 | ``` 12 | 13 | ## Ingesting Flow Data 14 | 15 | You need to make sure that the data which you are importing is _ordered by time_ and provides a column which stores UNIX timestamps. An example `csv` file may look as follows: 16 | 17 | ```sh 18 | # HEADER: bytes_rcvd,bytes_sent,dip,dport,packets_rcvd,packets_sent,proto,sip,tstamp 19 | ... 20 | 40,72,172.23.34.171,8080,1,1,6,10.11.72.28,1392997558 21 | 40,72,172.23.34.171,49362,1,1,6,10.11.72.28,1392999058 22 | ... 23 | ``` 24 | 25 | You _must_ abide by this structure, otherwise the conversion will fail. 26 | -------------------------------------------------------------------------------- /cmd/goProbe/default.pgo: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/els0r/goProbe/7eed90f04ea0ba38aeaaa9e22ae8a6b7aac7d6f9/cmd/goProbe/default.pgo -------------------------------------------------------------------------------- /cmd/goProbe/flags/root.go: -------------------------------------------------------------------------------- 1 | // Package flags is for parsing goProbe's command line parameters. 2 | package flags 3 | 4 | import ( 5 | "errors" 6 | "flag" 7 | ) 8 | 9 | // Flags stores goProbe's command line parameters 10 | type Flags struct { 11 | Config string 12 | Version bool 13 | OpenAPISpecOutfile string 14 | } 15 | 16 | // CmdLine globally exposes the parsed flags 17 | var CmdLine = &Flags{} 18 | 19 | // Read reads in the command line parameters 20 | func Read() error { 21 | flag.StringVar(&CmdLine.Config, "config", "", "path to goProbe's configuration file (required)") 22 | flag.BoolVar(&CmdLine.Version, "version", false, "print goProbe's version and exit") 23 | flag.StringVar(&CmdLine.OpenAPISpecOutfile, "openapi.spec-outfile", "", "write OpenAPI 3.0.3 spec to output file and exit") 24 | 25 | flag.Parse() 26 | 27 | if CmdLine.Config == "" && !CmdLine.Version { 28 | flag.PrintDefaults() 29 | return errors.New("no configuration file provided") 30 | } 31 | return nil 32 | } 33 | -------------------------------------------------------------------------------- /cmd/goQuery/.gitignore: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/els0r/goProbe/7eed90f04ea0ba38aeaaa9e22ae8a6b7aac7d6f9/cmd/goQuery/.gitignore -------------------------------------------------------------------------------- /cmd/goQuery/cmd/doc.go: -------------------------------------------------------------------------------- 1 | // Package cmd parses goQuery's supported flags and runs its CLI commands 2 | package cmd 3 | -------------------------------------------------------------------------------- /cmd/goQuery/cmd/examples.go: -------------------------------------------------------------------------------- 1 | package cmd 2 | 3 | import ( 4 | "fmt" 5 | 6 | "github.com/spf13/cobra" 7 | ) 8 | 9 | var exampleCmd = &cobra.Command{ 10 | Use: "examples", 11 | Short: "Print examples invocations of goquery", 12 | Run: printExample, 13 | } 14 | 15 | func init() { 16 | rootCmd.AddCommand(exampleCmd) 17 | } 18 | 19 | var examples = ` 20 | EXAMPLES 21 | 22 | * Show the top 5 (-n) IP pairs (talk_conv) over the default data presentation period 23 | (30 days) on a specific interface (-i): 24 | 25 | goquery -i eth0 -n 5 talk_conv 26 | 27 | equivalently you could also write 28 | 29 | goquery -i eth0 -n 5 sip,dip 30 | 31 | * Show the top 10 (-n) dport-protocol pairs over collected data from two days ago (-f, -l) 32 | ordered by the number of packets (-s packets) in ascending order (-a): 33 | 34 | goquery -i eth0 -n 10 -s packets -a -f "-2d" -l "-1d" apps_port 35 | 36 | * Get the total traffic volume over eth0 and t4_1234 in the last 24 hours (-f) 37 | between source network 213.156.236.0/24 (-c snet) and destination network 38 | 213.156.237.0/25 (-c dnet): 39 | 40 | goquery -i eth0,t4_1234 -f "-1d" -c "snet=213.156.236.0/24 AND dnet=213.156.237.0/25" \ 41 | talk_conv 42 | 43 | * Get the top 10 (-n) source-ip/destination-ip triples from all time (-f "-9999d") whose 44 | source or destination was in 172.27.0.0/16: 45 | 46 | goquery -i eth0 -f "-9999d" -c "snet = 172.27.0.0/16 | dnet = 172.27.0.0/16" -n 10 \ 47 | "sip,dip" 48 | ` 49 | 50 | func printExample(_ *cobra.Command, _ []string) { 51 | fmt.Println(examples) 52 | } 53 | -------------------------------------------------------------------------------- /cmd/goQuery/cmd/help_test.go: -------------------------------------------------------------------------------- 1 | package cmd 2 | 3 | import ( 4 | "testing" 5 | 6 | "github.com/els0r/goProbe/v4/pkg/query" 7 | "github.com/stretchr/testify/require" 8 | ) 9 | 10 | func TestTimestampHelp(t *testing.T) { 11 | require.NotPanics(t, func() { 12 | _ = buildTimestampHelpList( 13 | query.TimeFormatsDefault(), 14 | query.TimeFormatsCustom(), 15 | query.TimeFormatsRelative(), 16 | ) 17 | }) 18 | } 19 | -------------------------------------------------------------------------------- /cmd/goQuery/cmd/profiling.go: -------------------------------------------------------------------------------- 1 | package cmd 2 | 3 | import ( 4 | "fmt" 5 | "os" 6 | "path/filepath" 7 | "runtime/pprof" 8 | 9 | "github.com/els0r/goProbe/v4/cmd/goQuery/pkg/conf" 10 | "github.com/els0r/telemetry/logging" 11 | "github.com/spf13/cobra" 12 | "github.com/spf13/viper" 13 | ) 14 | 15 | func initProfiling(_ *cobra.Command, _ []string) error { 16 | // Setup profiling (if enabled) 17 | profilingOutputDir := viper.GetString(conf.ProfilingOutputDir) 18 | if profilingOutputDir != "" { 19 | logging.Logger().With(conf.ProfilingOutputDir, profilingOutputDir).Debug("setting up profiling") 20 | if err := startProfiling(profilingOutputDir); err != nil { 21 | return fmt.Errorf("failed to initialize profiling: %w", err) 22 | } 23 | } 24 | return nil 25 | } 26 | 27 | func finishProfiling(_ *cobra.Command, _ []string) error { 28 | profilingOutputDir := viper.GetString(conf.ProfilingOutputDir) 29 | if profilingOutputDir != "" { 30 | if err := stopProfiling(profilingOutputDir); err != nil { 31 | return fmt.Errorf("failed to finalize profiling: %w", err) 32 | } 33 | } 34 | return nil 35 | } 36 | 37 | func startProfiling(dirPath string) error { 38 | err := os.MkdirAll(dirPath, 0750) 39 | if err != nil { 40 | return fmt.Errorf("failed to create pprof directory: %w", err) 41 | } 42 | 43 | f, err := os.Create(filepath.Join(filepath.Clean(dirPath), "goquery_cpu_profile.pprof")) 44 | if err != nil { 45 | return fmt.Errorf("failed to create CPU profile file: %w", err) 46 | } 47 | if err := pprof.StartCPUProfile(f); err != nil { 48 | return fmt.Errorf("failed to start CPU profiling: %w", err) 49 | } 50 | 51 | return nil 52 | } 53 | 54 | func stopProfiling(dirPath string) error { 55 | 56 | pprof.StopCPUProfile() 57 | 58 | f, err := os.Create(filepath.Join(filepath.Clean(dirPath), "goquery_mem_profile.pprof")) 59 | if err != nil { 60 | return fmt.Errorf("failed to create memory profile file: %w", err) 61 | } 62 | if err := pprof.Lookup("allocs").WriteTo(f, 0); err != nil { 63 | return fmt.Errorf("failed to start memory profiling: %w", err) 64 | } 65 | 66 | return nil 67 | } 68 | -------------------------------------------------------------------------------- /cmd/goQuery/cmd/version.go: -------------------------------------------------------------------------------- 1 | package cmd 2 | 3 | import ( 4 | "fmt" 5 | 6 | "github.com/els0r/goProbe/v4/pkg/version" 7 | "github.com/spf13/cobra" 8 | ) 9 | 10 | var versionCmd = &cobra.Command{ 11 | Use: "version", 12 | Short: "Print version", 13 | Run: func(cmd *cobra.Command, args []string) { 14 | printVersion() 15 | }, 16 | } 17 | 18 | func init() { 19 | rootCmd.AddCommand(versionCmd) 20 | } 21 | 22 | func printVersion() { 23 | fmt.Printf("%s", version.Version()) 24 | } 25 | -------------------------------------------------------------------------------- /cmd/goQuery/default.pgo: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/els0r/goProbe/7eed90f04ea0ba38aeaaa9e22ae8a6b7aac7d6f9/cmd/goQuery/default.pgo -------------------------------------------------------------------------------- /cmd/goQuery/doc.go: -------------------------------------------------------------------------------- 1 | // Binary to query flows stored in goDB. This is the main entry point for network traffic analysis with the goProbe suite. 2 | // 3 | // For usage examples consult 4 | // goQuery --help 5 | // 6 | // or run 7 | // goQuery examples 8 | package main 9 | -------------------------------------------------------------------------------- /cmd/goQuery/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import "github.com/els0r/goProbe/v4/cmd/goQuery/cmd" 4 | 5 | func main() { 6 | cmd.Execute() 7 | } 8 | -------------------------------------------------------------------------------- /cmd/goQuery/pkg/conf/conf.go: -------------------------------------------------------------------------------- 1 | package conf 2 | 3 | // Definitions for command line parameters / arguments 4 | const ( 5 | queryKey = "query" 6 | 7 | serverKey = queryKey + ".server" 8 | QueryServerAddr = serverKey + ".addr" 9 | QueryTimeout = queryKey + ".timeout" 10 | QueryHostsResolution = queryKey + ".hosts-resolution" 11 | QueryLog = queryKey + ".log" 12 | QueryKeepAlive = queryKey + ".keepalive" 13 | QueryStats = queryKey + ".stats" 14 | QueryStreaming = queryKey + ".streaming" 15 | 16 | dbKey = "db" 17 | QueryDBPath = dbKey + ".path" 18 | 19 | StoredQuery = "stored-query" 20 | 21 | // logging 22 | loggingKey = "logging" 23 | LogLevel = loggingKey + ".level" 24 | 25 | // DNS settings 26 | dnsKey = "dns-resolution" 27 | DNSResolutionEnabled = dnsKey + ".enabled" 28 | DNSResolutionMaxRows = dnsKey + ".max-rows" 29 | DNSResolutionTimeout = dnsKey + ".timeout" 30 | 31 | // Sorting 32 | sortKey = "sort" 33 | SortBy = sortKey + ".by" 34 | SortAscending = sortKey + ".ascending" 35 | 36 | // Results 37 | resultsKey = "results" 38 | ResultsFormat = resultsKey + ".format" 39 | ResultsLimit = resultsKey + ".limit" 40 | 41 | // Memory 42 | memoryKey = "memory" 43 | MemoryMaxPct = memoryKey + ".max-pct" 44 | MemoryLowMode = memoryKey + ".low-mode" 45 | 46 | // Time 47 | First = "first" 48 | Last = "last" 49 | 50 | // Profiling 51 | profilingKey = "profiling" 52 | ProfilingOutputDir = profilingKey + ".output-dir" 53 | 54 | // Tracing propagation 55 | Traceparent = "traceparent" 56 | ) 57 | -------------------------------------------------------------------------------- /cmd/goquery_completion/cmd_test.go: -------------------------------------------------------------------------------- 1 | ///////////////////////////////////////////////////////////////////////////////// 2 | // 3 | // cmd_test.go 4 | // 5 | // Written by Lorenz Breidenbach lob@open.ch, February 2016 6 | // Copyright (c) 2016 Open Systems AG, Switzerland 7 | // All Rights Reserved. 8 | // 9 | ///////////////////////////////////////////////////////////////////////////////// 10 | 11 | package main 12 | 13 | import ( 14 | "reflect" 15 | "testing" 16 | ) 17 | 18 | var unescapeTests = []struct { 19 | in string 20 | out []string 21 | weird bool 22 | }{ 23 | {"", []string{""}, false}, 24 | {" ", []string{""}, false}, 25 | {" ", []string{""}, false}, 26 | {"a", []string{"a"}, false}, 27 | {"a ", []string{"a", ""}, false}, 28 | {" a ", []string{"a", ""}, false}, 29 | {" 'a' ", []string{"a", ""}, false}, 30 | {`\ "a" `, []string{" ", "a", ""}, false}, 31 | {`\ "\ \\\"\n"`, []string{" ", `\ \"\n`, ""}, true}, 32 | {` "a" \ `, []string{"a", " ", ""}, false}, 33 | {` "a"\ `, []string{"a", " "}, false}, 34 | {`\ 'a' `, []string{" ", "a", ""}, false}, 35 | {` 'a' \ `, []string{"a", " ", ""}, false}, 36 | {` 'a'\ `, []string{"a", " "}, false}, 37 | {`"hello""world`, []string{"hello", "world"}, false}, 38 | {`"hello""world"`, []string{"hello", "world", ""}, true}, 39 | {`"hello"'world'`, []string{"hello", "world", ""}, true}, 40 | {`"hello"'world"`, []string{"hello", "world\""}, false}, 41 | {`"world'`, []string{"world'"}, false}, 42 | {`''`, []string{"", ""}, true}, 43 | } 44 | 45 | func TestBashUnescape(t *testing.T) { 46 | for _, test := range unescapeTests { 47 | out, weird := bashUnescape(test.in) 48 | if !reflect.DeepEqual(test.out, out) || test.weird != weird { 49 | t.Fatalf("Expected (%#v, %v), got (%#v, %v)", test.out, test.weird, out, weird) 50 | } 51 | } 52 | 53 | } 54 | -------------------------------------------------------------------------------- /cmd/goquery_completion/default_database_path_public.go: -------------------------------------------------------------------------------- 1 | ///////////////////////////////////////////////////////////////////////////////// 2 | // 3 | // default_database_path_public.go 4 | // 5 | // Written by Lorenz Breidenbach lob@open.ch, February 2016 6 | // Copyright (c) 2016 Open Systems AG, Switzerland 7 | // All Rights Reserved. 8 | // 9 | ///////////////////////////////////////////////////////////////////////////////// 10 | 11 | // +build !OSAG 12 | 13 | package main 14 | 15 | const defaultDBPath = "" 16 | -------------------------------------------------------------------------------- /cmd/goquery_completion/query_type.go: -------------------------------------------------------------------------------- 1 | ///////////////////////////////////////////////////////////////////////////////// 2 | // 3 | // query_type.go 4 | // 5 | // Written by Lorenz Breidenbach lob@open.ch, February 2016 6 | // Copyright (c) 2016 Open Systems AG, Switzerland 7 | // All Rights Reserved. 8 | // 9 | ///////////////////////////////////////////////////////////////////////////////// 10 | 11 | package main 12 | 13 | import ( 14 | "strings" 15 | 16 | "github.com/els0r/goProbe/v4/pkg/types" 17 | ) 18 | 19 | func queryType(args []string) []string { 20 | tokenize := func(qt string) []string { 21 | return strings.Split(qt, ",") 22 | } 23 | 24 | join := func(attribs []string) string { 25 | return strings.Join(attribs, ",") 26 | } 27 | 28 | unusedAttribs := func(attribs []string) []string { 29 | attribUnused := map[string]bool{ 30 | "time": true, 31 | "iface": true, 32 | types.SIPName: true, 33 | types.DIPName: true, 34 | types.DportName: true, 35 | types.ProtoName: true, 36 | } 37 | 38 | for _, attrib := range attribs { 39 | switch attrib { 40 | case "talk_conv", "talk_src", "talk_dst", "apps_port", "agg_talk_port", "raw": 41 | return nil 42 | case "src": 43 | attrib = types.SIPName 44 | case "dst": 45 | attrib = types.DIPName 46 | } 47 | attribUnused[attrib] = false 48 | } 49 | 50 | var result []string 51 | for attrib, unused := range attribUnused { 52 | if unused { 53 | result = append(result, attrib) 54 | } 55 | } 56 | return result 57 | } 58 | 59 | next := func(attribs []string) suggestions { 60 | var suggs []suggestion 61 | if len(attribs) == 1 { 62 | for _, qt := range []string{"talk_conv", "talk_src", "talk_dst", "apps_port", "agg_talk_port", "raw"} { 63 | if strings.HasPrefix(qt, attribs[0]) { 64 | suggs = append(suggs, suggestion{qt, qt, true}) 65 | } 66 | } 67 | } 68 | for _, ua := range unusedAttribs(attribs[:len(attribs)-1]) { 69 | if strings.HasPrefix(ua, last(attribs)) { 70 | suggs = append(suggs, suggestion{ua, ua, true}) 71 | } 72 | } 73 | return knownSuggestions{suggs} 74 | } 75 | 76 | unknown := func(_ string) []string { 77 | panic("There are no unknown suggestions for the query type.") 78 | } 79 | 80 | return complete(tokenize, join, next, unknown, last(args)) 81 | } 82 | -------------------------------------------------------------------------------- /cmd/gpctl/README.md: -------------------------------------------------------------------------------- 1 | # gpctl 2 | 3 | > CLI tool to query and modify goProbe's internal state 4 | 5 | ## Invocation 6 | 7 | ```sh 8 | ./gpctl -s unix:/var/run/goprobe status eth0 eth1 9 | ``` 10 | 11 | This will produce the capture statistics (processed packets, drops, active capture, etc.) for interfaces eth0 and eth1. 12 | 13 | ### Reloading goProbe's Configuration 14 | 15 | To force a configuration reload of goProbe's interface configuration, point to its configuration file and run 16 | 17 | ```sh 18 | ./gpctl -s unix:/var/run/goprobe config -f /path/to/goprobe.yaml 19 | ``` 20 | 21 | ## Configuration 22 | 23 | To avoid having to specify goProbe's API server address with every call, it is recommended to provide a minimal configuration 24 | file guiding API query behavior and creating an alias: 25 | 26 | ```sh 27 | alias gpctl="./gpctl --config /path/to/gpctl.yaml" 28 | ``` 29 | 30 | Refer to [gpctl-example-config.yaml](../../examples/config/gpctl-example-config.yaml) for configuration options. 31 | -------------------------------------------------------------------------------- /cmd/gpctl/cmd/version.go: -------------------------------------------------------------------------------- 1 | package cmd 2 | 3 | import ( 4 | "fmt" 5 | 6 | "github.com/els0r/goProbe/v4/pkg/version" 7 | "github.com/spf13/cobra" 8 | ) 9 | 10 | var versionCmd = &cobra.Command{ 11 | Use: "version", 12 | Short: "Print version", 13 | Run: func(cmd *cobra.Command, args []string) { 14 | printVersion() 15 | }, 16 | SilenceErrors: true, 17 | } 18 | 19 | func init() { 20 | rootCmd.AddCommand(versionCmd) 21 | } 22 | 23 | func printVersion() { 24 | fmt.Printf("%s", version.Version()) 25 | } 26 | -------------------------------------------------------------------------------- /cmd/gpctl/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import "github.com/els0r/goProbe/v4/cmd/gpctl/cmd" 4 | 5 | func main() { 6 | cmd.Execute() 7 | } 8 | -------------------------------------------------------------------------------- /cmd/gpctl/pkg/conf/conf.go: -------------------------------------------------------------------------------- 1 | package conf 2 | 3 | const ( 4 | serverKey = "server" 5 | 6 | GoProbeServerAddr = serverKey + ".addr" // GoProbeServerAddr : The server endpoint / address of form : 7 | RequestTimeout = "timeout" // RequestTimeout : The request timeout 8 | ) 9 | -------------------------------------------------------------------------------- /doc.go: -------------------------------------------------------------------------------- 1 | /* 2 | Package goprobe supplies utilities and libraries for lightweight network packet aggregation and efficient storage and querying of flows 3 | */ 4 | package goprobe 5 | -------------------------------------------------------------------------------- /examples/README.md: -------------------------------------------------------------------------------- 1 | # Examples 2 | 3 | > small, standalone programs and snippets that showcase functionalities of the goProbe suite 4 | 5 | ## Contents 6 | 7 | ### Tools 8 | 9 | * [analyze-meta](./analyze-meta/) - helper tool to inspect a GPF file's meta information 10 | 11 | ### Configuration 12 | 13 | * [config](./config/) - example configurations for the binaries provided by this repository -------------------------------------------------------------------------------- /examples/analyze-meta/.gitignore: -------------------------------------------------------------------------------- 1 | analyze-meta 2 | -------------------------------------------------------------------------------- /examples/config/dummy-querier.yaml: -------------------------------------------------------------------------------- 1 | num_results: 2 2 | -------------------------------------------------------------------------------- /examples/config/global-query-api-client-querier-example-config-devcontainer.yaml: -------------------------------------------------------------------------------- 1 | hostA: 2 | addr: "localhost:8145" 3 | timeout: 15s 4 | log: true 5 | -------------------------------------------------------------------------------- /examples/config/global-query-api-client-querier-example-config.yaml: -------------------------------------------------------------------------------- 1 | hostA: 2 | addr: "unix:/var/run/goprobe" 3 | timeout: 5s 4 | log: true 5 | hostB: 6 | addr: "192.168.1.1:8145" 7 | timeout: 15s 8 | log: true 9 | -------------------------------------------------------------------------------- /examples/config/global-query-example-config-devcontainer.yaml: -------------------------------------------------------------------------------- 1 | logging: 2 | level: debug 3 | encoding: logfmt 4 | hosts: 5 | resolver: 6 | type: string 7 | querier: 8 | type: api 9 | max_concurrent: 64 10 | config: ./examples/config/global-query-api-client-querier-example-config-devcontainer.yaml 11 | server: 12 | addr: localhost:8146 13 | -------------------------------------------------------------------------------- /examples/config/global-query-example-config.yaml: -------------------------------------------------------------------------------- 1 | logging: 2 | level: debug 3 | encoding: logfmt 4 | hosts: 5 | resolver: 6 | type: string 7 | querier: 8 | type: api 9 | max_concurrent: 64 10 | config: ./examples/config/global-query-api-client-querier-example-config.yaml 11 | server: 12 | addr: localhost:8146 13 | -------------------------------------------------------------------------------- /examples/config/goprobe-example-config-devcontainer.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | db: 3 | path: /usr/local/goProbe/db 4 | local_buffers: 5 | size_limit: 67108864 6 | num_buffers: 1 7 | interfaces: 8 | eth0: 9 | promisc: false 10 | ring_buffer: 11 | num_blocks: 4 12 | block_size: 1048576 13 | api: 14 | addr: 0.0.0.0:8145 15 | profiling: true 16 | metrics: true 17 | query_rate_limit: 18 | max_req_per_sec: 2 19 | max_burst: 2 20 | logging: 21 | level: debug 22 | encoding: logfmt 23 | -------------------------------------------------------------------------------- /examples/config/goprobe-example.service: -------------------------------------------------------------------------------- 1 | [Unit] 2 | Description=Network Traffic Monitoring 3 | After=network-online.target 4 | 5 | [Service] 6 | Type=simple 7 | ExecStart=/usr/local/bin/goProbe -config /etc/goprobe.conf 8 | Restart=on-failure 9 | RestartSec=10 10 | TimeoutStopSec=30 11 | 12 | [Install] 13 | WantedBy=multi-user.target 14 | Alias=goprobe.service 15 | -------------------------------------------------------------------------------- /examples/config/goquery-example-config.yaml: -------------------------------------------------------------------------------- 1 | # db configures where goquery can find the flow database. It enables querying the local DB 2 | db: 3 | # path of the goDB database written by goprobe and read by goquery 4 | path: /usr/local/goprobe/db 5 | query: 6 | # server enables querying the global-query API 7 | server: 8 | # addr defines under which address the global-query API server is reachable. For unix sockets, 9 | # the prefix unix: is required 10 | addr: "http://global-query.example.com:8146" 11 | # timeout specifies the timeout for queries. The parameter is used for both query modes 12 | timeout: 30s 13 | # log defines the query log file to which queries are logged. Not their results, just the stages of query preparation, 14 | # execution, and completion. The output of the query results is written to stdout 15 | # 16 | # It is also not be confused with the logging configuration, which will guide how internal errors/warning/debug statements 17 | # are presented to the caller 18 | # 19 | # query logging is disabled if the path is empty, meaning that queries are not logged by default 20 | log: /var/log/goquery.log 21 | # logging guides the logging of internal errors/warning/debug statements 22 | logging: 23 | # level defines the log level. It can be one of: debug, info, warn, error, fatal, panic. By default, goquery will log warnings 24 | # and errors to stderr. All other log levels are logged to stdout. It is recommended to only increase the log level for debugging 25 | level: warn 26 | -------------------------------------------------------------------------------- /examples/config/gpctl-example-config-devcontainer.yaml: -------------------------------------------------------------------------------- 1 | server: 2 | # addr defines under which address goProbe's API server is reachable. For unix sockets, 3 | # the prefix unix: is required 4 | addr: "localhost:8145" 5 | # timeout specifies the timeout for calls to goProbe's API server. This is used for all requests 6 | timeout: 30s 7 | -------------------------------------------------------------------------------- /examples/config/gpctl-example-config.yaml: -------------------------------------------------------------------------------- 1 | server: 2 | # addr defines under which address goProbe's API server is reachable. For unix sockets, 3 | # the prefix unix: is required 4 | addr: "unix:/var/run/goprobe" 5 | # timeout specifies the timeout for calls to goProbe's API server. This is used for all requests 6 | timeout: 30s 7 | -------------------------------------------------------------------------------- /go.work: -------------------------------------------------------------------------------- 1 | go 1.23.1 2 | 3 | use ( 4 | . 5 | ./plugins/contrib 6 | ) 7 | -------------------------------------------------------------------------------- /img/goprobe_system_overview.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/els0r/goProbe/7eed90f04ea0ba38aeaaa9e22ae8a6b7aac7d6f9/img/goprobe_system_overview.png -------------------------------------------------------------------------------- /img/goprobe_system_overview_dark.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/els0r/goProbe/7eed90f04ea0ba38aeaaa9e22ae8a6b7aac7d6f9/img/goprobe_system_overview_dark.png -------------------------------------------------------------------------------- /pkg/api/api.go: -------------------------------------------------------------------------------- 1 | package api 2 | 3 | const ( 4 | infoPrefix = "/-" 5 | 6 | // HealthRoute denotes the route / URI path to the health endpoint 7 | HealthRoute = infoPrefix + "/health" 8 | // InfoRoute denotes the route / URI path to the info endpoint 9 | InfoRoute = infoPrefix + "/info" 10 | // ReadyRoute denotes the route / URI path to the ready endpoint 11 | ReadyRoute = infoPrefix + "/ready" 12 | ) 13 | 14 | const ( 15 | // QueryRoute is the route to run a goquery query 16 | QueryRoute = "/_query" 17 | 18 | // ValidationRoute is the route to validate a goquery query 19 | ValidationRoute = QueryRoute + "/validate" 20 | 21 | // SSEQueryRoute runs a goquery query with a return channel for partial results 22 | SSEQueryRoute = QueryRoute + "/sse" 23 | ) 24 | -------------------------------------------------------------------------------- /pkg/api/globalquery/client/client.go: -------------------------------------------------------------------------------- 1 | package client 2 | 3 | import ( 4 | "context" 5 | "net/http" 6 | 7 | "github.com/els0r/goProbe/v4/pkg/api" 8 | "github.com/els0r/goProbe/v4/pkg/api/client" 9 | "github.com/els0r/goProbe/v4/pkg/query" 10 | "github.com/els0r/goProbe/v4/pkg/results" 11 | "github.com/els0r/goProbe/v4/pkg/types" 12 | "github.com/fako1024/httpc" 13 | ) 14 | 15 | const ( 16 | clientName = "global-query-client" 17 | ) 18 | 19 | // Client denotes a global query client 20 | type Client struct { 21 | *client.DefaultClient 22 | } 23 | 24 | // New creates a new client for the global-query API 25 | func New(addr string, opts ...client.Option) *Client { 26 | opts = append(opts, client.WithName(clientName)) 27 | return &Client{ 28 | DefaultClient: client.NewDefault(addr, opts...), 29 | } 30 | } 31 | 32 | // Run implements the query.Runner interface 33 | func (c *Client) Run(ctx context.Context, args *query.Args) (*results.Result, error) { 34 | return c.Query(ctx, args) 35 | } 36 | 37 | // Query performs the global query and returns its result 38 | func (c *Client) Query(ctx context.Context, args *query.Args) (*results.Result, error) { 39 | // use a copy of the arguments, since some fields are modified by the client 40 | queryArgs := *args 41 | 42 | // whatever happens, the results are expected to be returned in json 43 | queryArgs.Format = types.FormatJSON 44 | 45 | if queryArgs.Caller == "" { 46 | queryArgs.Caller = clientName 47 | } 48 | 49 | var res = new(results.Result) 50 | 51 | req := c.Modify(ctx, 52 | httpc.NewWithClient(http.MethodPost, c.NewURL(api.QueryRoute), c.Client()). 53 | EncodeJSON(queryArgs). 54 | ParseJSON(res), 55 | ) 56 | 57 | err := req.RunWithContext(ctx) 58 | if err != nil { 59 | return nil, err 60 | } 61 | 62 | return res, nil 63 | } 64 | -------------------------------------------------------------------------------- /pkg/api/globalquery/client/stream_test.go: -------------------------------------------------------------------------------- 1 | package client 2 | 3 | import ( 4 | "bufio" 5 | "fmt" 6 | "io" 7 | "strings" 8 | "testing" 9 | 10 | "github.com/els0r/goProbe/v4/pkg/api" 11 | "github.com/stretchr/testify/require" 12 | ) 13 | 14 | func TestEventStream(t *testing.T) { 15 | var tests = []struct { 16 | body io.Reader 17 | line []byte 18 | expectedEvent *event 19 | }{ 20 | { 21 | body: strings.NewReader(` 22 | event: partialResult 23 | data: hello 24 | `), 25 | expectedEvent: &event{ 26 | streamType: api.StreamEventPartialResult, 27 | data: []byte("hello"), 28 | }, 29 | }, 30 | { 31 | body: strings.NewReader(` 32 | 33 | 34 | event: finalResult 35 | data: hello 36 | `), 37 | expectedEvent: &event{ 38 | streamType: api.StreamEventFinalResult, 39 | data: []byte("hello"), 40 | }, 41 | }, 42 | { 43 | body: strings.NewReader(` 44 | 45 | 46 | event: queryError 47 | data: there was an error 48 | `), 49 | expectedEvent: &event{ 50 | streamType: api.StreamEventQueryError, 51 | data: []byte("there was an error"), 52 | }, 53 | }, 54 | } 55 | 56 | for i, test := range tests { 57 | t.Run(fmt.Sprint(i), func(t *testing.T) { 58 | r := bufio.NewReader(test.body) 59 | actual, err := readEvent(r) 60 | require.Nil(t, err) 61 | require.Equal(t, test.expectedEvent, actual) 62 | }) 63 | } 64 | } 65 | -------------------------------------------------------------------------------- /pkg/api/globalquery/server/server.go: -------------------------------------------------------------------------------- 1 | package server 2 | 3 | import ( 4 | "fmt" 5 | 6 | "github.com/danielgtaylor/huma/v2" 7 | "github.com/els0r/goProbe/v4/cmd/global-query/pkg/conf" 8 | "github.com/els0r/goProbe/v4/cmd/global-query/pkg/distributed" 9 | "github.com/els0r/goProbe/v4/cmd/global-query/pkg/hosts" 10 | "github.com/els0r/goProbe/v4/pkg/api" 11 | "github.com/els0r/goProbe/v4/pkg/api/server" 12 | "github.com/els0r/goProbe/v4/pkg/version" 13 | ) 14 | 15 | // Server runs a global-query API server 16 | type Server struct { 17 | hostListResolver hosts.Resolver 18 | querier distributed.Querier 19 | 20 | *server.DefaultServer 21 | } 22 | 23 | // New creates a new global-query API server 24 | func New(addr string, resolver hosts.Resolver, querier distributed.Querier, opts ...server.Option) *Server { 25 | server := &Server{ 26 | hostListResolver: resolver, 27 | querier: querier, 28 | DefaultServer: server.NewDefault(conf.ServiceName, addr, opts...), 29 | } 30 | 31 | server.registerRoutes() 32 | 33 | return server 34 | } 35 | 36 | func (server *Server) registerRoutes() { 37 | var middlewares huma.Middlewares 38 | 39 | maxConcurrentQueries, rateLimiter, enabled := server.QueryRateLimiter() 40 | if enabled { 41 | middlewares = append(middlewares, api.RateLimitMiddleware(rateLimiter)) 42 | } 43 | 44 | opts := []distributed.QueryOption{} 45 | if maxConcurrentQueries > 0 { 46 | sem := make(chan struct{}, maxConcurrentQueries) 47 | opts = append(opts, distributed.WithMaxConcurrent(sem)) 48 | } 49 | api.RegisterQueryAPI(server.API(), 50 | fmt.Sprintf("global-query/%s", version.Short()), 51 | distributed.NewQueryRunner(server.hostListResolver, server.querier, opts...), 52 | middlewares, 53 | ) 54 | } 55 | -------------------------------------------------------------------------------- /pkg/api/globalquery/server/server_test.go: -------------------------------------------------------------------------------- 1 | package server 2 | 3 | import ( 4 | "bytes" 5 | "testing" 6 | 7 | "github.com/stretchr/testify/require" 8 | ) 9 | 10 | func TestGenerateOpenAPISpec(t *testing.T) { 11 | buf := &bytes.Buffer{} 12 | s := New("localhost:8146", nil, nil) 13 | 14 | err := s.WriteOpenAPISpec(buf) 15 | require.Nil(t, err) 16 | } 17 | -------------------------------------------------------------------------------- /pkg/api/goprobe/client/client-config.go: -------------------------------------------------------------------------------- 1 | package client 2 | 3 | import ( 4 | "errors" 5 | "time" 6 | ) 7 | 8 | // Config specifies the configurable parts of the client 9 | type Config struct { 10 | Scheme string `json:"scheme" yaml:"scheme"` 11 | Addr string `json:"addr" yaml:"addr"` 12 | Key string `json:"key,omitempty" yaml:"key,omitempty"` 13 | 14 | RequestTimeout time.Duration `json:"timeout,omitempty" yaml:"timeout,omitempty"` 15 | 16 | Log bool `json:"log" yaml:"log"` 17 | } 18 | 19 | var ( 20 | ErrorEmptyAddress = errors.New("no endpoint address (host:port) provided") // ErrorEmptyAddress : Denotes that an empty config has been provided 21 | ) 22 | 23 | // Validate validates the configuration 24 | func (cfg *Config) Validate() error { 25 | if cfg.Addr == "" { 26 | return ErrorEmptyAddress 27 | } 28 | return nil 29 | } 30 | -------------------------------------------------------------------------------- /pkg/api/goprobe/client/client.go: -------------------------------------------------------------------------------- 1 | package client 2 | 3 | import ( 4 | "io" 5 | "os" 6 | "path/filepath" 7 | 8 | "github.com/els0r/goProbe/v4/pkg/api/client" 9 | gpapi "github.com/els0r/goProbe/v4/pkg/api/goprobe" 10 | "gopkg.in/yaml.v3" 11 | ) 12 | 13 | // Client provides a client that calls goProbe's API functions 14 | type Client struct { 15 | *client.DefaultClient 16 | } 17 | 18 | const ( 19 | clientName = "goprobe-client" 20 | ) 21 | 22 | // NewFromReader creates the client based on configuration read from an io.Reader 23 | func NewFromReader(r io.Reader) (*Client, error) { 24 | var cfg = new(Config) 25 | err := yaml.NewDecoder(r).Decode(cfg) 26 | if err != nil { 27 | return nil, err 28 | } 29 | err = cfg.Validate() 30 | if err != nil { 31 | return nil, err 32 | } 33 | return NewFromConfig(cfg), nil 34 | } 35 | 36 | // New creates a new client instance 37 | func New(addr string, opts ...client.Option) *Client { 38 | opts = append(opts, client.WithName(clientName)) 39 | return &Client{ 40 | DefaultClient: client.NewDefault(addr, opts...), 41 | } 42 | } 43 | 44 | // NewFromConfig creates the client based on cfg 45 | func NewFromConfig(cfg *Config) *Client { 46 | if cfg == nil { 47 | return New(gpapi.DefaultServerAddress) 48 | } 49 | 50 | c := New(cfg.Addr, 51 | client.WithRequestLogging(cfg.Log), 52 | client.WithRequestTimeout(cfg.RequestTimeout), 53 | client.WithScheme(cfg.Scheme), 54 | client.WithAPIKey(cfg.Key), 55 | ) 56 | 57 | return c 58 | } 59 | 60 | // NewFromConfigFile creates the client based on configuration from a file 61 | func NewFromConfigFile(path string) (*Client, error) { 62 | f, err := os.Open(filepath.Clean(path)) 63 | if err != nil { 64 | return nil, err 65 | } 66 | defer func() { 67 | if cerr := f.Close(); cerr != nil && err == nil { 68 | err = cerr 69 | } 70 | }() 71 | 72 | return NewFromReader(f) 73 | } 74 | 75 | func addIfaceToPath(path string, ifaces ...string) string { 76 | if len(ifaces) == 1 { 77 | path = filepath.Join(path, ifaces[0]) 78 | } 79 | return path 80 | } 81 | -------------------------------------------------------------------------------- /pkg/api/goprobe/client/query.go: -------------------------------------------------------------------------------- 1 | package client 2 | 3 | import ( 4 | "context" 5 | 6 | "github.com/els0r/goProbe/v4/pkg/api" 7 | "github.com/els0r/goProbe/v4/pkg/query" 8 | "github.com/els0r/goProbe/v4/pkg/results" 9 | "github.com/els0r/goProbe/v4/pkg/types" 10 | "github.com/fako1024/httpc" 11 | ) 12 | 13 | // Run implements the query.Runner interface 14 | func (c *Client) Run(ctx context.Context, args *query.Args) (*results.Result, error) { 15 | return c.Query(ctx, args) 16 | } 17 | 18 | // Query runs a query on the API endpoint 19 | func (c *Client) Query(ctx context.Context, args *query.Args) (*results.Result, error) { 20 | // use a copy of the arguments, since some fields are modified by the client 21 | queryArgs := *args 22 | // whatever happens, the results are expected to be returned in json 23 | queryArgs.Format = types.FormatJSON 24 | 25 | if queryArgs.Caller == "" { 26 | queryArgs.Caller = clientName 27 | } 28 | 29 | // we need more results before truncating 30 | if queryArgs.NumResults < query.DefaultNumResults { 31 | queryArgs.NumResults = query.DefaultNumResults 32 | } 33 | 34 | var res = new(results.Result) 35 | 36 | req := c.Modify(ctx, 37 | httpc.NewWithClient("POST", c.NewURL(api.QueryRoute), c.Client()). 38 | EncodeJSON(queryArgs). 39 | ParseJSON(res), 40 | ) 41 | err := req.RunWithContext(ctx) 42 | if err != nil { 43 | return nil, err 44 | } 45 | 46 | return res, nil 47 | } 48 | 49 | // Query runs a query on the API endpoint 50 | func (c *Client) Validate(ctx context.Context, args *query.Args) (*results.Result, error) { 51 | var res = new(results.Result) 52 | 53 | req := c.Modify(ctx, 54 | httpc.NewWithClient("POST", c.NewURL(api.ValidationRoute), c.Client()). 55 | EncodeJSON(args). 56 | ParseJSON(res), 57 | ) 58 | err := req.RunWithContext(ctx) 59 | if err != nil { 60 | return nil, err 61 | } 62 | 63 | return res, nil 64 | } 65 | -------------------------------------------------------------------------------- /pkg/api/goprobe/client/status.go: -------------------------------------------------------------------------------- 1 | package client 2 | 3 | import ( 4 | "context" 5 | "fmt" 6 | "strings" 7 | "time" 8 | 9 | gpapi "github.com/els0r/goProbe/v4/pkg/api/goprobe" 10 | "github.com/els0r/goProbe/v4/pkg/capture/capturetypes" 11 | "github.com/fako1024/httpc" 12 | ) 13 | 14 | // GetInterfaceStatus returns the interface capture stats from the running goProbe instance 15 | func (c *Client) GetInterfaceStatus(ctx context.Context, ifaces ...string) (statuses map[string]capturetypes.CaptureStats, lastWriteout time.Time, startedAt time.Time, err error) { 16 | var res = new(gpapi.StatusResponse) 17 | 18 | url := c.NewURL(addIfaceToPath(gpapi.StatusRoute, ifaces...)) 19 | 20 | req := c.Modify(ctx, 21 | httpc.NewWithClient("GET", url, c.Client()). 22 | ParseJSON(res), 23 | ) 24 | if len(ifaces) > 1 { 25 | req = req.QueryParams(httpc.Params{ 26 | gpapi.IfacesQueryParam: strings.Join(ifaces, ","), 27 | }) 28 | } 29 | err = req.RunWithContext(ctx) 30 | if err != nil { 31 | if res.Error != "" { 32 | err = fmt.Errorf("%d: %s", res.StatusCode, res.Error) 33 | } 34 | return nil, lastWriteout, startedAt, err 35 | } 36 | 37 | return res.Statuses, res.LastWriteout, res.StartedAt, nil 38 | } 39 | -------------------------------------------------------------------------------- /pkg/api/goprobe/server/server.go: -------------------------------------------------------------------------------- 1 | package server 2 | 3 | import ( 4 | "fmt" 5 | 6 | "github.com/danielgtaylor/huma/v2" 7 | "github.com/els0r/goProbe/v4/cmd/goProbe/config" 8 | "github.com/els0r/goProbe/v4/pkg/api" 9 | "github.com/els0r/goProbe/v4/pkg/api/server" 10 | "github.com/els0r/goProbe/v4/pkg/capture" 11 | "github.com/els0r/goProbe/v4/pkg/goDB/engine" 12 | "github.com/els0r/goProbe/v4/pkg/version" 13 | ) 14 | 15 | // Server runs a goprobe API server 16 | type Server struct { 17 | 18 | // goprobe specific variables 19 | dbPath string 20 | captureManager *capture.Manager 21 | configMonitor *config.Monitor 22 | 23 | *server.DefaultServer 24 | } 25 | 26 | // New creates a new goprobe API server 27 | func New(addr, dbPath string, captureManager *capture.Manager, configMonitor *config.Monitor, opts ...server.Option) *Server { 28 | server := &Server{ 29 | dbPath: dbPath, 30 | captureManager: captureManager, 31 | configMonitor: configMonitor, 32 | DefaultServer: server.NewDefault(config.ServiceName, addr, opts...), 33 | } 34 | 35 | server.registerRoutes() 36 | 37 | return server 38 | } 39 | 40 | const ifaceKey = "interface" 41 | 42 | func (server *Server) registerRoutes() { 43 | var middlewares huma.Middlewares 44 | maxConcurrentQueries, rateLimiter, enabled := server.QueryRateLimiter() 45 | if enabled { 46 | middlewares = append(middlewares, api.RateLimitMiddleware(rateLimiter)) 47 | } 48 | 49 | // query 50 | opts := []engine.RunnerOption{ 51 | engine.WithLiveData(server.captureManager), 52 | } 53 | if maxConcurrentQueries > 0 { 54 | sem := make(chan struct{}, maxConcurrentQueries) 55 | opts = append(opts, engine.WithMaxConcurrent(sem)) 56 | } 57 | api.RegisterQueryAPI(server.API(), 58 | fmt.Sprintf("goProbe/%s", version.Short()), 59 | engine.NewQueryRunner(server.dbPath, opts...), 60 | middlewares, 61 | ) 62 | 63 | // stats 64 | server.registerStatusAPI() 65 | 66 | // config 67 | server.registerConfigAPI() 68 | } 69 | -------------------------------------------------------------------------------- /pkg/api/goprobe/server/status.go: -------------------------------------------------------------------------------- 1 | package server 2 | 3 | import ( 4 | "context" 5 | "net/http" 6 | 7 | gpapi "github.com/els0r/goProbe/v4/pkg/api/goprobe" 8 | ) 9 | 10 | func (server *Server) getIfaceStatusHandler() func(ctx context.Context, input *GetIfaceStatusInput) (*GetStatusOutput, error) { 11 | return func(ctx context.Context, input *GetIfaceStatusInput) (*GetStatusOutput, error) { 12 | output := &GetStatusOutput{} 13 | resp := &gpapi.StatusResponse{} 14 | output.Body = resp 15 | 16 | resp.StatusCode = http.StatusOK 17 | resp.StartedAt, resp.LastWriteout = server.captureManager.GetTimestamps() 18 | 19 | // query single interface if path parameter was supplied 20 | if input.Iface != "" { 21 | resp.Statuses = server.captureManager.Status(ctx, input.Iface) 22 | } 23 | if len(resp.Statuses) == 0 { 24 | resp.StatusCode = http.StatusNoContent 25 | } 26 | 27 | output.Status = resp.StatusCode 28 | 29 | return output, nil 30 | } 31 | } 32 | 33 | func (server *Server) getIfacesStatusHandler() func(ctx context.Context, input *GetIfacesStatusInput) (*GetStatusOutput, error) { 34 | return func(ctx context.Context, input *GetIfacesStatusInput) (*GetStatusOutput, error) { 35 | output := &GetStatusOutput{} 36 | resp := &gpapi.StatusResponse{} 37 | output.Body = resp 38 | 39 | resp.StatusCode = http.StatusOK 40 | resp.StartedAt, resp.LastWriteout = server.captureManager.GetTimestamps() 41 | 42 | // query multiple if supplied in query parameters 43 | if len(input.Ifaces) > 0 { 44 | resp.Statuses = server.captureManager.Status(ctx, input.Ifaces...) 45 | } else { 46 | // fetch all 47 | resp.Statuses = server.captureManager.Status(ctx) 48 | } 49 | if len(resp.Statuses) == 0 { 50 | resp.StatusCode = http.StatusNoContent 51 | } 52 | 53 | output.Status = resp.StatusCode 54 | 55 | return output, nil 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /pkg/api/goprobe/server/status_api_ops.go: -------------------------------------------------------------------------------- 1 | package server 2 | 3 | import ( 4 | "net/http" 5 | 6 | "github.com/danielgtaylor/huma/v2" 7 | gpapi "github.com/els0r/goProbe/v4/pkg/api/goprobe" 8 | ) 9 | 10 | var statusTags = []string{"Status"} 11 | 12 | const ( 13 | getStatusOpName = "get-status" 14 | 15 | getStatusSingle = getStatusOpName + "-single" 16 | getStatusMultiple = getStatusOpName + "-multiple" 17 | ) 18 | 19 | func (server *Server) registerStatusAPI() { 20 | huma.Register(server.API(), 21 | huma.Operation{ 22 | OperationID: getStatusSingle, 23 | Method: http.MethodGet, 24 | Path: gpapi.StatusRoute + "/{iface}", 25 | Summary: "Get capture status (single)", 26 | Description: "Gets capture status of a single interface", 27 | Tags: statusTags, 28 | }, 29 | server.getIfaceStatusHandler(), 30 | ) 31 | huma.Register(server.API(), 32 | huma.Operation{ 33 | OperationID: getStatusMultiple, 34 | Method: http.MethodGet, 35 | Path: gpapi.StatusRoute, 36 | Summary: "Get capture status (many)", 37 | Description: "Gets capture status of one or more (or all) interfaces", 38 | Tags: statusTags, 39 | }, 40 | server.getIfacesStatusHandler(), 41 | ) 42 | } 43 | 44 | // GetIfaceStatusInput describes the input to a status request for a single interface 45 | type GetIfaceStatusInput struct { 46 | Iface string `path:"iface" doc:"Interface to get status from" minLength:"2"` 47 | } 48 | 49 | // GetIfacesStatusInput describes the input to a status request 50 | type GetIfacesStatusInput struct { 51 | Ifaces []string `query:"ifaces" doc:"Interfaces to get status from" required:"false" minItems:"1"` 52 | } 53 | 54 | // GetStatusOutput returns the status fetched during a status request 55 | type GetStatusOutput struct { 56 | Status int 57 | Body *gpapi.StatusResponse 58 | } 59 | -------------------------------------------------------------------------------- /pkg/api/server/server_test.go: -------------------------------------------------------------------------------- 1 | package server 2 | 3 | import ( 4 | "bytes" 5 | "testing" 6 | 7 | "github.com/stretchr/testify/require" 8 | ) 9 | 10 | func TestGenerateOpenAPISpec(t *testing.T) { 11 | buf := &bytes.Buffer{} 12 | s := NewDefault("test", "localhost:8146") 13 | 14 | err := s.WriteOpenAPISpec(buf) 15 | require.Nil(t, err) 16 | } 17 | -------------------------------------------------------------------------------- /pkg/api/server/spec.go: -------------------------------------------------------------------------------- 1 | package server 2 | 3 | import ( 4 | "context" 5 | "fmt" 6 | "io" 7 | "os" 8 | 9 | "github.com/els0r/telemetry/logging" 10 | ) 11 | 12 | // OpenAPISpecWriter can be implemented by any server able to produce an OpenAPI spec 13 | // from its registered routes 14 | type OpenAPISpecWriter interface { 15 | WriteOpenAPISpec(w io.Writer) error 16 | } 17 | 18 | // GenerateSpec writes the OpenAPI spec to a file 19 | func GenerateSpec(ctx context.Context, path string, ow OpenAPISpecWriter) error { 20 | if path == "" { 21 | return nil 22 | } 23 | logger := logging.FromContext(ctx).With("path", path) 24 | 25 | logger.Info("writing OpenAPI spec only") 26 | f, err := os.OpenFile(path, os.O_CREATE|os.O_WRONLY|os.O_TRUNC, 0755) 27 | if err != nil { 28 | return err 29 | } 30 | 31 | err = ow.WriteOpenAPISpec(f) 32 | if err != nil { 33 | return fmt.Errorf("failed to write OpenAPI spec to %s: %w", path, err) 34 | } 35 | return nil 36 | } 37 | -------------------------------------------------------------------------------- /pkg/api/util.go: -------------------------------------------------------------------------------- 1 | package api 2 | 3 | import ( 4 | "path/filepath" 5 | "strings" 6 | ) 7 | 8 | const ( 9 | unixPrefix = "unix:" 10 | httpPrefix = "http://" 11 | httpsPrefix = "https://" 12 | ) 13 | 14 | // ExtractUnixSocket determines whether the provided address contains a unix: 15 | // prefix. If so, it will treat the remainder as the path to the socket 16 | func ExtractUnixSocket(addr string) (socketFile string) { 17 | if strings.HasPrefix(addr, unixPrefix) { 18 | socketFile = filepath.Clean(strings.TrimPrefix(addr, unixPrefix)) 19 | } 20 | return 21 | } 22 | 23 | // ExtractSchemeAddr extracts the scheme from the address if it is present and returns 24 | // the trimmed address with it. If not scheme match is found, scheme is empty and the 25 | // input to the function will be returned in address 26 | func ExtractSchemeAddr(addr string) (scheme string, address string) { 27 | switch { 28 | case strings.HasPrefix(addr, unixPrefix): 29 | return "", filepath.Clean(strings.TrimPrefix(addr, unixPrefix)) 30 | case strings.HasPrefix(addr, httpPrefix): 31 | return httpPrefix, filepath.Clean(strings.TrimPrefix(addr, httpPrefix)) 32 | case strings.HasPrefix(addr, httpsPrefix): 33 | return httpsPrefix, filepath.Clean(strings.TrimPrefix(addr, httpsPrefix)) 34 | } 35 | return "", addr 36 | } 37 | -------------------------------------------------------------------------------- /pkg/capture/capture_mock.go: -------------------------------------------------------------------------------- 1 | //go:build !slimcap_nomock 2 | // +build !slimcap_nomock 3 | 4 | package capture 5 | 6 | import "github.com/fako1024/slimcap/capture" 7 | 8 | // Source redefines any slimcap zero copy source interface type 9 | type Source = capture.SourceZeroCopy 10 | -------------------------------------------------------------------------------- /pkg/capture/capture_nomock.go: -------------------------------------------------------------------------------- 1 | //go:build slimcap_nomock 2 | // +build slimcap_nomock 3 | 4 | package capture 5 | 6 | import "github.com/fako1024/slimcap/capture/afpacket/afring" 7 | 8 | // Source redefines an afring source 9 | type Source = *afring.Source 10 | -------------------------------------------------------------------------------- /pkg/capture/captures.go: -------------------------------------------------------------------------------- 1 | package capture 2 | 3 | import "sync" 4 | 5 | // Captures denotes a named set of Capture instances, wrapping a map and the 6 | // required synchronization of all its actions 7 | type captures struct { 8 | Map map[string]*Capture 9 | sync.RWMutex 10 | } 11 | 12 | // newCaptures instantiates a new, empty set of Captures 13 | func newCaptures() *captures { 14 | return &captures{ 15 | Map: make(map[string]*Capture), 16 | RWMutex: sync.RWMutex{}, 17 | } 18 | } 19 | 20 | // Ifaces return the list of names of all interfaces in the set 21 | func (c *captures) Ifaces(ifaces ...string) []string { 22 | if len(ifaces) == 0 { 23 | c.RLock() 24 | ifaces = make([]string, 0, len(c.Map)) 25 | for iface := range c.Map { 26 | ifaces = append(ifaces, iface) 27 | } 28 | c.RUnlock() 29 | } 30 | 31 | return ifaces 32 | } 33 | 34 | // Get safely returns a Capture by name (and an indicator if it exists) 35 | func (c *captures) Get(iface string) (capture *Capture, exists bool) { 36 | c.RLock() 37 | capture, exists = c.GetNoLock(iface) 38 | c.RUnlock() 39 | return 40 | } 41 | 42 | // GetNoLock returns a Capture by name (and an indicator if it exists) without locking 43 | func (c *captures) GetNoLock(iface string) (capture *Capture, exists bool) { 44 | capture, exists = c.Map[iface] 45 | return 46 | } 47 | 48 | // Set safely adds / overwrites a Capture by name 49 | func (c *captures) Set(iface string, capture *Capture) { 50 | c.Lock() 51 | c.SetNoLock(iface, capture) 52 | c.Unlock() 53 | } 54 | 55 | // SetNoLock adds / overwrites a Capture by name without locking 56 | func (c *captures) SetNoLock(iface string, capture *Capture) { 57 | c.Map[iface] = capture 58 | } 59 | 60 | // Delete safely removes a Capture from the set by name 61 | func (c *captures) Delete(iface string) { 62 | c.Lock() 63 | c.DeleteNoLock(iface) 64 | c.Unlock() 65 | } 66 | 67 | // Delete removes a Capture from the set by name without locking 68 | func (c *captures) DeleteNoLock(iface string) { 69 | delete(c.Map, iface) 70 | } 71 | -------------------------------------------------------------------------------- /pkg/capture/capturetypes/config.go: -------------------------------------------------------------------------------- 1 | package capturetypes 2 | 3 | import "log/slog" 4 | 5 | // IfaceChange denotes the result from a config update / reload of an interface 6 | type IfaceChange struct { 7 | // Name: the name of the interface 8 | Name string `json:"name" doc:"Name of the interface" example:"eth0"` 9 | // Success: the config update / reload operation(s) succeeded 10 | Success bool `json:"success" doc:"The config update / reload operation(s) suceeded" example:"true"` 11 | } 12 | 13 | // LogValue implements the LogValuer interface 14 | func (ic IfaceChange) LogValue() slog.Value { 15 | return slog.GroupValue( 16 | slog.String("name", ic.Name), 17 | slog.Bool("success", ic.Success), 18 | ) 19 | } 20 | 21 | // IfaceChanges denotes a list of IfaceChange instances 22 | type IfaceChanges []IfaceChange 23 | 24 | // Names return a simple string slice containing all interface names 25 | func (c IfaceChanges) Names() []string { 26 | names := make([]string, len(c)) 27 | for i := 0; i < len(c); i++ { 28 | names[i] = c[i].Name 29 | } 30 | return names 31 | } 32 | 33 | // Results return both successful and failed results in a slice, respectively 34 | func (c IfaceChanges) Results() (ok []string, failed []string) { 35 | for _, change := range c { 36 | if change.Success { 37 | ok = append(ok, change.Name) 38 | } else { 39 | failed = append(failed, change.Name) 40 | } 41 | } 42 | 43 | return 44 | } 45 | 46 | // Len returns the length (read: number) of interface changes (implementation of sorting interface) 47 | func (c IfaceChanges) Len() int { 48 | return len(c) 49 | } 50 | 51 | // Less returns if a named change is to be ordered before a second one (implementation of sorting interface) 52 | func (c IfaceChanges) Less(i, j int) bool { 53 | return c[i].Name < c[j].Name 54 | } 55 | 56 | // Swap swaps two interface changes in the list (implementation of sorting interface) 57 | func (c IfaceChanges) Swap(i, j int) { 58 | c[i], c[j] = c[j], c[i] 59 | } 60 | 61 | // FromIfaceNames generates a list of IfaceChange instances from a list of interface names 62 | func FromIfaceNames(names []string) IfaceChanges { 63 | res := make(IfaceChanges, len(names)) 64 | for i := 0; i < len(names); i++ { 65 | res[i].Name = names[i] 66 | } 67 | return res 68 | } 69 | -------------------------------------------------------------------------------- /pkg/capture/capturetypes/parsing_error.go: -------------------------------------------------------------------------------- 1 | package capturetypes 2 | 3 | // ParsingErrno denotes a non-critical packet parsing error / failure 4 | type ParsingErrno int8 5 | 6 | const ( 7 | // ErrnoOK : No Error 8 | ErrnoOK ParsingErrno = iota - 1 9 | 10 | // ErrnoPacketFragmentIgnore : packet fragment does not carry relevant information 11 | // (will be skipped as non-error) 12 | ErrnoPacketFragmentIgnore 13 | 14 | // ErrnoInvalidIPHeader : received neither IPv4 nor IPv6 IP header 15 | ErrnoInvalidIPHeader 16 | 17 | // ErrnoPacketTruncated : packet too short / truncated 18 | ErrnoPacketTruncated 19 | 20 | // NumParsingErrors : Number of tracked parsing errors 21 | NumParsingErrors 22 | ) 23 | 24 | // ParsingErrnoNames maps a ParsingErrno to a string 25 | var ParsingErrnoNames = [NumParsingErrors]string{ 26 | "packet fragmented", 27 | "invalid IP header", 28 | "packet truncated", 29 | } 30 | 31 | // String returns a string representation of the underlying ParsingErrno 32 | func (e ParsingErrno) String() string { 33 | return ParsingErrnoNames[e] 34 | } 35 | 36 | // ParsingFailed denotes if a ParsingErrno actually signifies that packet parsing failed 37 | func (e ParsingErrno) ParsingFailed() bool { 38 | return e >= ErrnoInvalidIPHeader 39 | } 40 | 41 | // ParsingErrTracker denotes a simple table-based parsing error structure for counting 42 | // all available parsing error (errno) types 43 | type ParsingErrTracker [NumParsingErrors]int 44 | 45 | // Sum returns the sum of all errors (inclunding non-critical ones) currently tracked 46 | // in the error table 47 | func (e *ParsingErrTracker) Sum() (res int) { 48 | for i := ErrnoPacketFragmentIgnore; i < NumParsingErrors; i++ { 49 | res += e[i] 50 | } 51 | return 52 | } 53 | 54 | // SumFailed returns the sum of all errors (that prevent packet processing) currently tracked 55 | // in the error table 56 | func (e *ParsingErrTracker) SumFailed() (res int) { 57 | for i := ErrnoInvalidIPHeader; i < NumParsingErrors; i++ { 58 | res += e[i] 59 | } 60 | return 61 | } 62 | 63 | // Reset resets all error counters in the error table (for reuse) 64 | func (e *ParsingErrTracker) Reset() { 65 | for i := ErrnoPacketFragmentIgnore; i < NumParsingErrors; i++ { 66 | e[i] = 0 67 | } 68 | } 69 | -------------------------------------------------------------------------------- /pkg/capture/capturetypes/parsing_error_test.go: -------------------------------------------------------------------------------- 1 | package capturetypes 2 | 3 | import ( 4 | "testing" 5 | 6 | "github.com/stretchr/testify/require" 7 | ) 8 | 9 | func TestResetParsingError(t *testing.T) { 10 | 11 | errs := ParsingErrTracker{} 12 | 13 | errs[ErrnoInvalidIPHeader] = 1 14 | errs[ErrnoPacketTruncated] = 2 15 | errs[ErrnoPacketFragmentIgnore] = 3 16 | 17 | require.Equal(t, 1, errs[ErrnoInvalidIPHeader]) 18 | require.Equal(t, 2, errs[ErrnoPacketTruncated]) 19 | require.Equal(t, 3, errs[ErrnoPacketFragmentIgnore]) 20 | require.Equal(t, errs.Sum(), 6) 21 | require.Equal(t, errs.SumFailed(), 3) 22 | 23 | // Create a copy of the tracker 24 | errCopy := errs 25 | 26 | // Reset the tracker 27 | errs.Reset() 28 | 29 | // Validate that the initial tracker is reset 30 | require.Equal(t, 0, errs[ErrnoInvalidIPHeader]) 31 | require.Equal(t, 0, errs[ErrnoPacketTruncated]) 32 | require.Equal(t, 0, errs[ErrnoPacketFragmentIgnore]) 33 | require.Equal(t, errs.SumFailed(), 0) 34 | 35 | // Validate that the copy is not affected by the reset 36 | require.Equal(t, 1, errCopy[ErrnoInvalidIPHeader]) 37 | require.Equal(t, 2, errCopy[ErrnoPacketTruncated]) 38 | require.Equal(t, 3, errCopy[ErrnoPacketFragmentIgnore]) 39 | require.Equal(t, errCopy.SumFailed(), 3) 40 | } 41 | -------------------------------------------------------------------------------- /pkg/capture/doc.go: -------------------------------------------------------------------------------- 1 | // Package capture is used to set up packet capturing and specifies the flow format. The API to interact with the capture manager is specified in a sub-package. 2 | package capture 3 | -------------------------------------------------------------------------------- /pkg/capture/rungroup.go: -------------------------------------------------------------------------------- 1 | ///////////////////////////////////////////////////////////////////////////////// 2 | // 3 | // rungroup.go 4 | // 5 | // Written by Lorenz Breidenbach lob@open.ch, December 2015 6 | // Copyright (c) 2015 Open Systems AG, Switzerland 7 | // All Rights Reserved. 8 | // 9 | ///////////////////////////////////////////////////////////////////////////////// 10 | 11 | package capture 12 | 13 | import "sync" 14 | 15 | // RunGroup wraps the common waitgroup setup for go routines that need to finish before 16 | // continuing with instruction execution. 17 | type RunGroup struct { 18 | wg sync.WaitGroup 19 | } 20 | 21 | // Run executes any function inside a go routine and waits for it 22 | func (rg *RunGroup) Run(f func()) { 23 | rg.wg.Add(1) 24 | go func() { 25 | f() 26 | rg.wg.Done() 27 | }() 28 | } 29 | 30 | // Wait wraps the sync.Wait method 31 | func (rg *RunGroup) Wait() { 32 | rg.wg.Wait() 33 | } 34 | -------------------------------------------------------------------------------- /pkg/defaults/defaults.go: -------------------------------------------------------------------------------- 1 | package defaults 2 | 3 | import "time" 4 | 5 | const ( 6 | 7 | // DBPath denotes the default path on disk where the DB resides 8 | DBPath = "/usr/local/goProbe/db" 9 | 10 | // QueryTimeout denotes the default query timeout 11 | QueryTimeout = 0 * time.Second 12 | ) 13 | -------------------------------------------------------------------------------- /pkg/e2etest/extdata/udpflows.pcap.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/els0r/goProbe/7eed90f04ea0ba38aeaaa9e22ae8a6b7aac7d6f9/pkg/e2etest/extdata/udpflows.pcap.gz -------------------------------------------------------------------------------- /pkg/e2etest/testdata/c04-wap-r1.pcap.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/els0r/goProbe/7eed90f04ea0ba38aeaaa9e22ae8a6b7aac7d6f9/pkg/e2etest/testdata/c04-wap-r1.pcap.gz -------------------------------------------------------------------------------- /pkg/e2etest/testdata/default.pcap.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/els0r/goProbe/7eed90f04ea0ba38aeaaa9e22ae8a6b7aac7d6f9/pkg/e2etest/testdata/default.pcap.gz -------------------------------------------------------------------------------- /pkg/e2etest/testdata/fragmented.pcap.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/els0r/goProbe/7eed90f04ea0ba38aeaaa9e22ae8a6b7aac7d6f9/pkg/e2etest/testdata/fragmented.pcap.gz -------------------------------------------------------------------------------- /pkg/e2etest/testdata/truncated.pcap.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/els0r/goProbe/7eed90f04ea0ba38aeaaa9e22ae8a6b7aac7d6f9/pkg/e2etest/testdata/truncated.pcap.gz -------------------------------------------------------------------------------- /pkg/formatting/format_test.go: -------------------------------------------------------------------------------- 1 | package formatting 2 | 3 | import ( 4 | "testing" 5 | "time" 6 | 7 | "github.com/stretchr/testify/require" 8 | ) 9 | 10 | func TestCountHumanized(t *testing.T) { 11 | var tests = []struct { 12 | input uint64 13 | expected string 14 | }{ 15 | {0, "0.00 "}, 16 | {1, "1.00 "}, 17 | {100000, "100.00 k"}, 18 | {238327428, "238.33 M"}, 19 | } 20 | 21 | for _, test := range tests { 22 | test := test 23 | t.Run(test.expected, func(t *testing.T) { 24 | actual := Count(test.input) 25 | require.Equal(t, test.expected, actual) 26 | }) 27 | } 28 | } 29 | 30 | func TestSize(t *testing.T) { 31 | var tests = []struct { 32 | input uint64 33 | expected string 34 | }{ 35 | {0, "0.00 B"}, 36 | {231, "231.00 B"}, 37 | {2338231, "2.23 MB"}, 38 | {28319384728, "26.37 GB"}, 39 | {2832828383338231, "2.52 PB"}, 40 | {2832828383338238231, "2.46 EB"}, 41 | } 42 | 43 | for _, test := range tests { 44 | test := test 45 | t.Run(test.expected, func(t *testing.T) { 46 | actual := Size(test.input) 47 | require.Equal(t, test.expected, actual) 48 | }) 49 | } 50 | } 51 | 52 | func TestDuration(t *testing.T) { 53 | var tests = []struct { 54 | input time.Duration 55 | expected string 56 | }{ 57 | {0, "0s"}, 58 | {1 * time.Millisecond, "1ms"}, 59 | {1 * time.Second, "1s"}, 60 | {1*time.Second + 232*time.Millisecond, "1.232s"}, 61 | {1*time.Minute + 3*time.Second, "1m3s"}, 62 | {1*time.Hour + 3*time.Minute + 3*time.Second, "1h3m3s"}, 63 | {25*time.Hour + 3*time.Minute + 3*time.Second, "1d1h3m3s"}, 64 | } 65 | 66 | for _, test := range tests { 67 | test := test 68 | t.Run(test.expected, func(t *testing.T) { 69 | actual := Duration(test.input) 70 | require.Equal(t, test.expected, actual) 71 | }) 72 | } 73 | } 74 | -------------------------------------------------------------------------------- /pkg/goDB/.gitignore: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/els0r/goProbe/7eed90f04ea0ba38aeaaa9e22ae8a6b7aac7d6f9/pkg/goDB/.gitignore -------------------------------------------------------------------------------- /pkg/goDB/SyslogConsts_public.go: -------------------------------------------------------------------------------- 1 | ///////////////////////////////////////////////////////////////////////////////// 2 | // 3 | // syslogConsts_public.go 4 | // 5 | // Constants for location of syslog socket file 6 | // 7 | // Written by Lennart Elsen lel@open.ch, June 2016 8 | // Copyright (c) 2016 Open Systems AG, Switzerland 9 | // All Rights Reserved. 10 | // 11 | ///////////////////////////////////////////////////////////////////////////////// 12 | 13 | // +build !OSAG 14 | 15 | package goDB 16 | 17 | const ( 18 | socketPath = "/var/run/goprobe.sock" 19 | ) 20 | -------------------------------------------------------------------------------- /pkg/goDB/SyslogDBWriter.go: -------------------------------------------------------------------------------- 1 | ///////////////////////////////////////////////////////////////////////////////// 2 | // 3 | // SyslogDBWriter.go 4 | // 5 | // Logging facility for dumping the raw flow information to syslog. 6 | // 7 | // Written by Lennart Elsen lel@open.ch, June 2016 8 | // Copyright (c) 2016 Open Systems AG, Switzerland 9 | // All Rights Reserved. 10 | // 11 | ///////////////////////////////////////////////////////////////////////////////// 12 | 13 | package goDB 14 | 15 | import ( 16 | "fmt" 17 | "log/syslog" 18 | 19 | "github.com/els0r/goProbe/v4/pkg/types/hashmap" 20 | ) 21 | 22 | // SyslogDBWriter can write goProbe's flow map to a syslog destination 23 | type SyslogDBWriter struct { 24 | logger *syslog.Writer 25 | } 26 | 27 | // NewSyslogDBWriter establishes a syslog connection and returns the flow writer 28 | func NewSyslogDBWriter() (*SyslogDBWriter, error) { 29 | s := &SyslogDBWriter{} 30 | 31 | var err error 32 | if s.logger, err = syslog.Dial("unix", socketPath, syslog.LOG_NOTICE, "ntm"); err != nil { 33 | return nil, err 34 | } 35 | return s, nil 36 | } 37 | 38 | // Write writes the aggregated flows to the syslog writer 39 | func (s *SyslogDBWriter) Write(flowmap *hashmap.AggFlowMap, iface string, timestamp int64) { 40 | for i := flowmap.Iter(); i.Next(); { 41 | _ = s.logger.Info( 42 | fmt.Sprintf("%d,%s,%s,%s", 43 | timestamp, 44 | iface, 45 | i.Key(), 46 | i.Val().String(), 47 | ), 48 | ) 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /pkg/goDB/conditions/node/desugar.go: -------------------------------------------------------------------------------- 1 | ///////////////////////////////////////////////////////////////////////////////// 2 | // 3 | // DesugarConditional.go 4 | // 5 | // Written by Lennart Elsen lel@open.ch and 6 | // Lorenz Breidenbach lob@open.ch, January 2016 7 | // Copyright (c) 2016 Open Systems AG, Switzerland 8 | // All Rights Reserved. 9 | // 10 | ///////////////////////////////////////////////////////////////////////////////// 11 | 12 | package node 13 | 14 | import ( 15 | "fmt" 16 | 17 | "github.com/els0r/goProbe/v4/pkg/types" 18 | ) 19 | 20 | // Returns a desugared version of the receiver. 21 | func desugar(node Node) (Node, error) { 22 | return node.transform(desugarConditionNode) 23 | } 24 | 25 | func desugarConditionNode(node conditionNode) (Node, error) { 26 | helper := func(name, src, dst, comparator, value string) (Node, error) { 27 | var result Node 28 | if comparator != "=" && comparator != "!=" { 29 | return result, fmt.Errorf("invalid comparison operator in %s condition: %s", name, comparator) 30 | } 31 | 32 | result = orNode{ 33 | left: conditionNode{ 34 | attribute: src, 35 | comparator: "=", 36 | value: value, 37 | }, 38 | right: conditionNode{ 39 | attribute: dst, 40 | comparator: "=", 41 | value: value, 42 | }, 43 | } 44 | 45 | if comparator == "!=" { 46 | result = notNode{ 47 | node: result, 48 | } 49 | } 50 | 51 | return result, nil 52 | } 53 | 54 | // map aliases to proper attribute names 55 | switch node.attribute { 56 | case "src": 57 | node.attribute = types.SIPName 58 | case "dst": 59 | node.attribute = types.DIPName 60 | case "port": 61 | node.attribute = types.DportName 62 | case "ipproto", "protocol": 63 | node.attribute = types.ProtoName 64 | case "host": 65 | return helper("host", types.SIPName, types.DIPName, node.comparator, node.value) 66 | case "net": 67 | return helper("net", "snet", "dnet", node.comparator, node.value) 68 | default: 69 | // nothing to do 70 | } 71 | 72 | return node, nil 73 | } 74 | -------------------------------------------------------------------------------- /pkg/goDB/conditions/node/desugar_test.go: -------------------------------------------------------------------------------- 1 | ///////////////////////////////////////////////////////////////////////////////// 2 | // 3 | // desugar_test.go 4 | // 5 | // Written by Lorenz Breidenbach lob@open.ch, January 2016 6 | // Copyright (c) 2015 Open Systems AG, Switzerland 7 | // All Rights Reserved. 8 | // 9 | ///////////////////////////////////////////////////////////////////////////////// 10 | 11 | package node 12 | 13 | import ( 14 | "errors" 15 | "testing" 16 | ) 17 | 18 | var desugarTests = []struct { 19 | inTokens []string 20 | output string // desugared ouput 21 | success bool 22 | }{ 23 | { 24 | []string{"host", "!=", "192.168.178.1", "|", "(", "host", "=", "192.168.178.1", ")"}, 25 | "(!((sip = 192.168.178.1 | dip = 192.168.178.1)) | (sip = 192.168.178.1 | dip = 192.168.178.1))", 26 | true, 27 | }, 28 | { 29 | []string{"net", "!=", "192.168.178.1/24", "|", "(", "net", "=", "192.168.178.1/16", ")"}, 30 | "(!((snet = 192.168.178.1/24 | dnet = 192.168.178.1/24)) | (snet = 192.168.178.1/16 | dnet = 192.168.178.1/16))", 31 | true, 32 | }, 33 | { 34 | []string{"!", "(", "src", "=", "192.168.178.1", "&", "dst", "!=", "1.2.3.4", ")"}, 35 | "!((sip = 192.168.178.1 & dip != 1.2.3.4))", 36 | true, 37 | }, 38 | { 39 | []string{"host", "<", "192.168.178.1/24"}, 40 | "", 41 | false, 42 | }, 43 | { 44 | []string{"net", ">=", "192.168.178.1/24", "|", "(", "net", "=", "192.168.178.1/16", ")"}, 45 | "", 46 | false, 47 | }, 48 | } 49 | 50 | func TestDesugar(t *testing.T) { 51 | for _, test := range desugarTests { 52 | node, err := parseConditional(test.inTokens) 53 | if err != nil && !errors.Is(err, errEmptyConditional) { 54 | t.Fatalf("Parsing %v unexpectly failed. Error:\n%v", test.inTokens, err) 55 | } 56 | 57 | desugaredNode, err := desugar(node) 58 | if !test.success { 59 | if err == nil { 60 | t.Fatalf("Expected to fail on input %v but didn't.", 61 | test.inTokens) 62 | } 63 | } else { 64 | if err != nil { 65 | t.Fatalf("Unexpectedly failed on input %v. The error is: %s", 66 | test.inTokens, err) 67 | } 68 | if desugaredNode.String() != test.output { 69 | t.Fatalf("Expected output: %s. Actual output: %s", 70 | test.output, desugaredNode) 71 | } 72 | } 73 | } 74 | } 75 | -------------------------------------------------------------------------------- /pkg/goDB/db_writer_test.go: -------------------------------------------------------------------------------- 1 | package goDB 2 | 3 | import ( 4 | "fmt" 5 | "os" 6 | "path/filepath" 7 | "strconv" 8 | "testing" 9 | "time" 10 | 11 | "github.com/els0r/goProbe/v4/pkg/capture/capturetypes" 12 | "github.com/els0r/goProbe/v4/pkg/goDB/encoder/encoders" 13 | "github.com/els0r/goProbe/v4/pkg/goDB/storage/gpfile" 14 | "github.com/els0r/goProbe/v4/pkg/types/hashmap" 15 | "github.com/stretchr/testify/require" 16 | ) 17 | 18 | func TestPanicDuringWrite(t *testing.T) { 19 | 20 | // Setup a temporary directory for the test DB 21 | tempDir, err := os.MkdirTemp(os.TempDir(), "dbwrite_test") 22 | require.Nil(t, err) 23 | defer require.Nil(t, os.RemoveAll(tempDir)) 24 | 25 | timestamp := time.Now().Unix() 26 | dayTimestamp := gpfile.DirTimestamp(timestamp) 27 | dayUnix := time.Unix(dayTimestamp, 0) 28 | dirPath := filepath.Join(filepath.Join(tempDir, "test"), strconv.Itoa(dayUnix.Year()), fmt.Sprintf("%02d", dayUnix.Month()), strconv.FormatInt(dayTimestamp, 10)) 29 | 30 | w := NewDBWriter(tempDir, "test", encoders.EncoderTypeNull).Permissions(0600) 31 | 32 | // Add a single item that will trigger a panic later 33 | testMap := hashmap.NewAggFlowMap() 34 | testMap.PrimaryMap.Set([]byte{0x0}, hashmap.Val{}) 35 | 36 | t.Run("Write", func(t *testing.T) { 37 | require.Panics(t, func() { 38 | err := w.Write(testMap, capturetypes.CaptureStats{}, timestamp) 39 | _ = err 40 | }) 41 | dirs, err := os.ReadDir(dirPath) 42 | require.Nil(t, err) 43 | require.Empty(t, dirs) 44 | }) 45 | 46 | t.Run("WriteBulk", func(t *testing.T) { 47 | require.Panics(t, func() { 48 | err := w.WriteBulk([]BulkWorkload{ 49 | { 50 | FlowMap: testMap, 51 | CaptureStats: capturetypes.CaptureStats{}, 52 | Timestamp: timestamp, 53 | }, 54 | }, timestamp) 55 | _ = err 56 | }) 57 | dirs, err := os.ReadDir(dirPath) 58 | require.Nil(t, err) 59 | require.Empty(t, dirs) 60 | }) 61 | 62 | } 63 | -------------------------------------------------------------------------------- /pkg/goDB/doc.go: -------------------------------------------------------------------------------- 1 | // Package goDB defines the columnar database format for persistently writing goProbe flows and querying the stored data. 2 | package goDB 3 | -------------------------------------------------------------------------------- /pkg/goDB/encoder/encoder.go: -------------------------------------------------------------------------------- 1 | package encoder 2 | 3 | import ( 4 | "errors" 5 | "fmt" 6 | "io" 7 | 8 | "github.com/els0r/goProbe/v4/pkg/goDB/encoder/encoders" 9 | "github.com/els0r/goProbe/v4/pkg/goDB/encoder/lz4" 10 | "github.com/els0r/goProbe/v4/pkg/goDB/encoder/null" 11 | "github.com/els0r/goProbe/v4/pkg/goDB/encoder/zstd" 12 | ) 13 | 14 | var ( 15 | 16 | // ErrDeprecatedLZ4Cust is used to signify the obsoletion of the lz4cust encoding 17 | ErrDeprecatedLZ4Cust = errors.New("the LZ4 custom implementation has been deprecated, please check out the v4.0.0 README") 18 | ) 19 | 20 | // Encoder provides the GP File with a means to compress and decompress its raw data 21 | type Encoder interface { 22 | 23 | // Type will return the type of encoder 24 | Type() encoders.Type 25 | 26 | // Close will close the encoder and release potentially allocated resources 27 | Close() error 28 | 29 | // Compress will take the input data slice and write it to dst. The number of written compressed bytes is returned with n 30 | Compress(data, buf []byte, dst io.Writer) (n int, err error) 31 | 32 | // Decompress reads compressed bytes from src into in, decompresses it into out and returns the number of bytes decompressed. 33 | // It is the responsibility of the caller to ensure that in and out are properly sized 34 | Decompress(in, out []byte, src io.Reader) (n int, err error) 35 | 36 | // SetLevel sets / changes the compression level (if supported) 37 | SetLevel(level int) 38 | } 39 | 40 | // New creates a new encoder based on an encoder type 41 | func New(t encoders.Type) (Encoder, error) { 42 | switch t { 43 | case encoders.EncoderTypeNull: 44 | return null.New(), nil 45 | case encoders.EncoderTypeLZ4: 46 | return lz4.New(), nil 47 | case encoders.EncoderTypeLZ4CustomDeprecated: 48 | return nil, ErrDeprecatedLZ4Cust 49 | case encoders.EncoderTypeZSTD: 50 | return zstd.New(), nil 51 | default: 52 | return nil, fmt.Errorf("unsupported encoder: %v", t) 53 | } 54 | } 55 | 56 | // NewByString is a convenience method for encoder selection by string 57 | // rather than enumeration code 58 | func NewByString(t string) (Encoder, error) { 59 | et, err := encoders.GetTypeByString(t) 60 | if err != nil { 61 | return nil, err 62 | } 63 | return New(et) 64 | } 65 | -------------------------------------------------------------------------------- /pkg/goDB/encoder/encoders/encoders.go: -------------------------------------------------------------------------------- 1 | package encoders 2 | 3 | import ( 4 | "fmt" 5 | "strings" 6 | ) 7 | 8 | // Type denotes the type of encoder 9 | type Type uint8 10 | 11 | // IMPORTANT: 12 | // When implementing new encoders, make sure to add the type above MaxEncoderType. Otherwise, compatibility 13 | // with existing databases is broken 14 | const ( 15 | EncoderTypeLZ4CustomDeprecated Type = iota // EncoderTypeLZ4Custom : LZ4 encoder / compressor with custom checksum stripping (default, hence allocated the value 0) 16 | EncoderTypeNull // EncoderTypeNull : Null encoder 17 | EncoderTypeZSTD // EncoderTypeZSTD : ZSTD encoder / compressor 18 | EncoderTypeLZ4 // EncoderTypeLZ4 ; LZ4 encoder / compressor based on available lz4 system library (1.9.4 recommended for performance) 19 | 20 | // MaxEncoderType should always be the last entry 21 | MaxEncoderType = EncoderTypeLZ4 22 | ) 23 | 24 | var encoderNames = map[Type]string{ 25 | EncoderTypeLZ4: "lz4", 26 | EncoderTypeLZ4CustomDeprecated: "lz4cust", 27 | EncoderTypeNull: "null", 28 | EncoderTypeZSTD: "zstd", 29 | } 30 | 31 | // String returns a string representation of the encoding type 32 | func (t Type) String() string { 33 | return encoderNames[t] 34 | } 35 | 36 | // GetTypeByString returns the encoder type based on a named string 37 | func GetTypeByString(t string) (Type, error) { 38 | switch strings.ToLower(t) { 39 | case "null", "": 40 | return EncoderTypeNull, nil 41 | case "lz4": 42 | return EncoderTypeLZ4, nil 43 | case "lz4cust": 44 | return EncoderTypeLZ4CustomDeprecated, nil 45 | case "zstd": 46 | return EncoderTypeZSTD, nil 47 | default: 48 | return EncoderTypeNull, fmt.Errorf("unsupported encoder: %v", t) 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /pkg/goDB/encoder/lz4/lz4.go: -------------------------------------------------------------------------------- 1 | // Package lz4 implements goDB's Encoder interface for lz4 (de-)compression of flow data 2 | package lz4 3 | 4 | import ( 5 | "errors" 6 | 7 | "github.com/els0r/goProbe/v4/pkg/goDB/encoder/encoders" 8 | ) 9 | 10 | const ( 11 | MaxCompressionLevel = 12 // MaxCompressionLevel denotes the maximum useful compression level 12 | defaultCompressionLevel = 6 13 | ) 14 | 15 | var ( 16 | 17 | // ErrBufferSizeMismatch denotes that the allocated buffer is insufficient in size 18 | ErrBufferSizeMismatch = errors.New("buffer size mismatch for compressed data") 19 | 20 | // ErrIncorrectNumBytesRead denotes that the number of bytes read during decompression 21 | // does not match the expected size 22 | ErrIncorrectNumBytesRead = errors.New("incorrect number of bytes read from data source during decompression") 23 | ) 24 | 25 | // Encoder compresses data with the LZ4 algorithm (omitting certain bounds-checks for performance reasons) 26 | type Encoder struct { 27 | 28 | // compression level 29 | level int 30 | } 31 | 32 | // Option sets additional parameters on the Encoder 33 | type Option func(*Encoder) 34 | 35 | // New creates a new LZ4 Encoder that can be used to compress/decompress data 36 | func New(opts ...Option) *Encoder { 37 | // compression level of 4 is used by default as it offers higher compression speeds than maximum compression, 38 | // while retaining an agreeable compression ratio 39 | l := &Encoder{level: defaultCompressionLevel} 40 | 41 | // apply options 42 | for _, opt := range opts { 43 | opt(l) 44 | } 45 | return l 46 | } 47 | 48 | // WithCompressionLevel allows the level to be set to something other than the default 512 49 | func WithCompressionLevel(level int) Option { 50 | return func(e *Encoder) { 51 | e.SetLevel(level) 52 | } 53 | } 54 | 55 | // SetLevel sets / changes the compression level (if supported) 56 | func (e *Encoder) SetLevel(level int) { 57 | e.level = level 58 | } 59 | 60 | // Type will return the type of encoder 61 | func (e *Encoder) Type() encoders.Type { 62 | return encoders.EncoderTypeLZ4 63 | } 64 | -------------------------------------------------------------------------------- /pkg/goDB/encoder/lz4/lz4_native.go: -------------------------------------------------------------------------------- 1 | //go:build !cgo || goprobe_noliblz4 2 | // +build !cgo goprobe_noliblz4 3 | 4 | package lz4 5 | 6 | import ( 7 | "fmt" 8 | "io" 9 | 10 | "github.com/pierrec/lz4/v4" 11 | ) 12 | 13 | // Close will close the encoder and release potentially allocated resources 14 | func (e *Encoder) Close() error { 15 | return nil 16 | } 17 | 18 | // Compress compresses the input data and writes it to dst 19 | func (e *Encoder) Compress(data, buf []byte, dst io.Writer) (n int, err error) { 20 | 21 | // Handle output slice size 22 | dstCapacity := lz4.CompressBlockBound(len(data)) 23 | if cap(buf) < dstCapacity { 24 | buf = make([]byte, 0, 2*dstCapacity) 25 | } 26 | buf = buf[:dstCapacity] 27 | 28 | // Compress data 29 | compLen, err := lz4.CompressBlockHC(data, buf, lz4.CompressionLevel(e.level), nil, nil) 30 | if err != nil { 31 | return n, fmt.Errorf("compression failed: %w", err) 32 | } 33 | 34 | // Perform sanity check whether the computed worst case has been exceeded 35 | if len(buf) < compLen { 36 | return n, ErrBufferSizeMismatch 37 | } 38 | 39 | // If provided, write output to the writer 40 | if dst != nil { 41 | if n, err = dst.Write(buf[:compLen]); err != nil { 42 | return n, err 43 | } 44 | } 45 | 46 | return n, nil 47 | } 48 | 49 | // Decompress runs LZ4 decompression on "in" read from "src" and writes it to "out" 50 | func (e *Encoder) Decompress(in, out []byte, src io.Reader) (int, error) { 51 | var nBytesConsumed int 52 | 53 | // Read compressed source data 54 | nBytesConsumed, err := src.Read(in) 55 | if err != nil { 56 | return 0, err 57 | } 58 | if nBytesConsumed != len(in) { 59 | return 0, ErrIncorrectNumBytesRead 60 | } 61 | 62 | // Decompress data 63 | decompLen, err := lz4.UncompressBlock(in, out) 64 | if err != nil { 65 | return 0, fmt.Errorf("decompression failed: %w", err) 66 | } 67 | 68 | return decompLen, nil 69 | } 70 | -------------------------------------------------------------------------------- /pkg/goDB/encoder/lz4cust/lz4cust.go: -------------------------------------------------------------------------------- 1 | // Package lz4cust implements goDB's Encoder interface for lz4 (de-)compression of flow data 2 | package lz4cust 3 | 4 | import ( 5 | "github.com/els0r/goProbe/v4/pkg/goDB/encoder/encoders" 6 | ) 7 | 8 | // Encoder compresses data with the LZ4 algorithm (omitting certain bounds-checks for performance reasons) 9 | type Encoder struct { 10 | // compression level 11 | level int 12 | } 13 | 14 | // Option sets additional parameters on the Encoder 15 | type Option func(*Encoder) 16 | 17 | // SetLevel sets / changes the compression level (if supported) 18 | func (e *Encoder) SetLevel(level int) { 19 | e.level = level 20 | } 21 | 22 | // Type will return the type of encoder 23 | func (e *Encoder) Type() encoders.Type { 24 | return encoders.EncoderTypeLZ4CustomDeprecated 25 | } 26 | 27 | // Close will close the encoder and release potentially allocated resources 28 | func (e *Encoder) Close() error { 29 | return nil 30 | } 31 | -------------------------------------------------------------------------------- /pkg/goDB/encoder/null/null.go: -------------------------------------------------------------------------------- 1 | package null 2 | 3 | import ( 4 | "errors" 5 | "io" 6 | 7 | "github.com/els0r/goProbe/v4/pkg/goDB/encoder/encoders" 8 | ) 9 | 10 | // DefaultEncoder proivdes a globally usable null encoder / DefaultEncoder 11 | // Since all null compression / decompression actions are stateless it is safe 12 | var DefaultEncoder = New() 13 | 14 | // Encoder compresses data without any algorithm 15 | type Encoder struct{} 16 | 17 | // New creates a new Null encoder which does not manipulate the original data 18 | // in any way. It's meant to be used where no compression is desired 19 | func New() *Encoder { 20 | return &Encoder{} 21 | } 22 | 23 | // Type will return the type of encoder 24 | func (e *Encoder) Type() encoders.Type { 25 | return encoders.EncoderTypeNull 26 | } 27 | 28 | // Close will close the encoder and release potentially allocated resources 29 | func (e *Encoder) Close() error { 30 | return nil 31 | } 32 | 33 | // Compress directly writes "data" to "dst" without any further manipulation 34 | func (e *Encoder) Compress(data, _ []byte, dst io.Writer) (n int, err error) { 35 | return dst.Write(data) 36 | } 37 | 38 | // Decompress runs no decompression on the data read from src. It's directly written 39 | // to "out" 40 | func (e *Encoder) Decompress(_, out []byte, src io.Reader) (n int, err error) { 41 | n, err = src.Read(out) 42 | if err != nil { 43 | return 0, err 44 | } 45 | if n != len(out) { 46 | return 0, errors.New("incorrect number of bytes read from data source") 47 | } 48 | 49 | return n, nil 50 | } 51 | 52 | // SetLevel sets / changes the compression level (if supported) 53 | func (e *Encoder) SetLevel(_ int) {} 54 | -------------------------------------------------------------------------------- /pkg/goDB/encoder/zstd/zstd.go: -------------------------------------------------------------------------------- 1 | // Package zstd implements goDB's Encoder interface for ZStandard (de-)compression of flow data 2 | package zstd 3 | 4 | import ( 5 | "errors" 6 | 7 | "github.com/els0r/goProbe/v4/pkg/goDB/encoder/encoders" 8 | ) 9 | 10 | const ( 11 | MaxCompressionLevel = 19 // MaxCompressionLevel denotes the maximum useful compression level 12 | defaultCompressionLevel = 6 13 | ) 14 | 15 | var ( 16 | 17 | // ErrBufferSizeMismatch denotes that the allocated buffer is insufficient in size 18 | ErrBufferSizeMismatch = errors.New("buffer size mismatch for compressed data") 19 | 20 | // ErrIncorrectNumBytesRead denotes that the number of bytes read during decompression 21 | // does not match the expected size 22 | ErrIncorrectNumBytesRead = errors.New("incorrect number of bytes read from data source during decompression") 23 | 24 | // ErrContextCreationFailed denotes that instantiation of a ZSTD (de)compression context failed 25 | ErrContextCreationFailed = errors.New("context creation failed") 26 | ) 27 | 28 | // Option sets additional parameters on the Encoder 29 | type Option func(*Encoder) 30 | 31 | // New creates a new ZStandard Encoder that can be used to compress/decompress data 32 | func New(opts ...Option) *Encoder { 33 | // compression level of 6 is used by default as it offers higher compression speeds than maximum compression, 34 | // while retaining an agreeable compression ratio 35 | l := &Encoder{level: defaultCompressionLevel} 36 | 37 | // apply options 38 | for _, opt := range opts { 39 | opt(l) 40 | } 41 | return l 42 | } 43 | 44 | // WithCompressionLevel allows the level to be set to something other than the default (6) 45 | func WithCompressionLevel(level int) Option { 46 | return func(e *Encoder) { 47 | e.SetLevel(level) 48 | } 49 | } 50 | 51 | // SetLevel sets / changes the compression level (if supported) 52 | func (e *Encoder) SetLevel(level int) { 53 | e.level = level 54 | } 55 | 56 | // Type will return the type of encoder 57 | func (e *Encoder) Type() encoders.Type { 58 | return encoders.EncoderTypeZSTD 59 | } 60 | -------------------------------------------------------------------------------- /pkg/goDB/engine/bench_gen.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | benchfile="./benchmarks_test.go" 4 | 5 | if ! [ -e $benchfile ]; then 6 | echo "--- Generating query benchmarks file ---" 7 | go run ./benchgen/main.go && goimports -w $benchfile 8 | chmod a+r $benchfile 9 | else 10 | echo "--- Benchmarks already generated ---" 11 | fi 12 | exit 0 13 | -------------------------------------------------------------------------------- /pkg/goDB/engine/flush_darwin.go: -------------------------------------------------------------------------------- 1 | //go:build darwin 2 | // +build darwin 3 | 4 | package engine 5 | 6 | var syncCmd = []string{"sudo", "purge"} 7 | -------------------------------------------------------------------------------- /pkg/goDB/engine/flush_linux.go: -------------------------------------------------------------------------------- 1 | //go:build linux 2 | // +build linux 3 | 4 | package engine 5 | 6 | var syncCmd = []string{"sync", "&&", "echo", "3", ">", "/proc/sys/vm/drop_caches"} 7 | -------------------------------------------------------------------------------- /pkg/goDB/engine/gen.go: -------------------------------------------------------------------------------- 1 | package engine 2 | 3 | // This file is only used for code generation statements 4 | 5 | // Benchmark generation 6 | //go:generate ./bench_gen.sh 7 | -------------------------------------------------------------------------------- /pkg/goDB/engine/testdb/eth0/2016/02/1456358400/.blockmeta: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/els0r/goProbe/7eed90f04ea0ba38aeaaa9e22ae8a6b7aac7d6f9/pkg/goDB/engine/testdb/eth0/2016/02/1456358400/.blockmeta -------------------------------------------------------------------------------- /pkg/goDB/engine/testdb/eth0/2016/02/1456358400/bytes_rcvd.gpf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/els0r/goProbe/7eed90f04ea0ba38aeaaa9e22ae8a6b7aac7d6f9/pkg/goDB/engine/testdb/eth0/2016/02/1456358400/bytes_rcvd.gpf -------------------------------------------------------------------------------- /pkg/goDB/engine/testdb/eth0/2016/02/1456358400/bytes_sent.gpf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/els0r/goProbe/7eed90f04ea0ba38aeaaa9e22ae8a6b7aac7d6f9/pkg/goDB/engine/testdb/eth0/2016/02/1456358400/bytes_sent.gpf -------------------------------------------------------------------------------- /pkg/goDB/engine/testdb/eth0/2016/02/1456358400/dip.gpf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/els0r/goProbe/7eed90f04ea0ba38aeaaa9e22ae8a6b7aac7d6f9/pkg/goDB/engine/testdb/eth0/2016/02/1456358400/dip.gpf -------------------------------------------------------------------------------- /pkg/goDB/engine/testdb/eth0/2016/02/1456358400/dport.gpf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/els0r/goProbe/7eed90f04ea0ba38aeaaa9e22ae8a6b7aac7d6f9/pkg/goDB/engine/testdb/eth0/2016/02/1456358400/dport.gpf -------------------------------------------------------------------------------- /pkg/goDB/engine/testdb/eth0/2016/02/1456358400/pkts_rcvd.gpf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/els0r/goProbe/7eed90f04ea0ba38aeaaa9e22ae8a6b7aac7d6f9/pkg/goDB/engine/testdb/eth0/2016/02/1456358400/pkts_rcvd.gpf -------------------------------------------------------------------------------- /pkg/goDB/engine/testdb/eth0/2016/02/1456358400/pkts_sent.gpf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/els0r/goProbe/7eed90f04ea0ba38aeaaa9e22ae8a6b7aac7d6f9/pkg/goDB/engine/testdb/eth0/2016/02/1456358400/pkts_sent.gpf -------------------------------------------------------------------------------- /pkg/goDB/engine/testdb/eth0/2016/02/1456358400/proto.gpf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/els0r/goProbe/7eed90f04ea0ba38aeaaa9e22ae8a6b7aac7d6f9/pkg/goDB/engine/testdb/eth0/2016/02/1456358400/proto.gpf -------------------------------------------------------------------------------- /pkg/goDB/engine/testdb/eth0/2016/02/1456358400/sip.gpf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/els0r/goProbe/7eed90f04ea0ba38aeaaa9e22ae8a6b7aac7d6f9/pkg/goDB/engine/testdb/eth0/2016/02/1456358400/sip.gpf -------------------------------------------------------------------------------- /pkg/goDB/engine/testdb/eth0/2016/02/1456444800_mm1-0-eE3-SvUZv-SF9Du1-CFM4-Ppa6/.blockmeta: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/els0r/goProbe/7eed90f04ea0ba38aeaaa9e22ae8a6b7aac7d6f9/pkg/goDB/engine/testdb/eth0/2016/02/1456444800_mm1-0-eE3-SvUZv-SF9Du1-CFM4-Ppa6/.blockmeta -------------------------------------------------------------------------------- /pkg/goDB/engine/testdb/eth0/2016/02/1456444800_mm1-0-eE3-SvUZv-SF9Du1-CFM4-Ppa6/bytes_rcvd.gpf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/els0r/goProbe/7eed90f04ea0ba38aeaaa9e22ae8a6b7aac7d6f9/pkg/goDB/engine/testdb/eth0/2016/02/1456444800_mm1-0-eE3-SvUZv-SF9Du1-CFM4-Ppa6/bytes_rcvd.gpf -------------------------------------------------------------------------------- /pkg/goDB/engine/testdb/eth0/2016/02/1456444800_mm1-0-eE3-SvUZv-SF9Du1-CFM4-Ppa6/bytes_sent.gpf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/els0r/goProbe/7eed90f04ea0ba38aeaaa9e22ae8a6b7aac7d6f9/pkg/goDB/engine/testdb/eth0/2016/02/1456444800_mm1-0-eE3-SvUZv-SF9Du1-CFM4-Ppa6/bytes_sent.gpf -------------------------------------------------------------------------------- /pkg/goDB/engine/testdb/eth0/2016/02/1456444800_mm1-0-eE3-SvUZv-SF9Du1-CFM4-Ppa6/dip.gpf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/els0r/goProbe/7eed90f04ea0ba38aeaaa9e22ae8a6b7aac7d6f9/pkg/goDB/engine/testdb/eth0/2016/02/1456444800_mm1-0-eE3-SvUZv-SF9Du1-CFM4-Ppa6/dip.gpf -------------------------------------------------------------------------------- /pkg/goDB/engine/testdb/eth0/2016/02/1456444800_mm1-0-eE3-SvUZv-SF9Du1-CFM4-Ppa6/dport.gpf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/els0r/goProbe/7eed90f04ea0ba38aeaaa9e22ae8a6b7aac7d6f9/pkg/goDB/engine/testdb/eth0/2016/02/1456444800_mm1-0-eE3-SvUZv-SF9Du1-CFM4-Ppa6/dport.gpf -------------------------------------------------------------------------------- /pkg/goDB/engine/testdb/eth0/2016/02/1456444800_mm1-0-eE3-SvUZv-SF9Du1-CFM4-Ppa6/pkts_rcvd.gpf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/els0r/goProbe/7eed90f04ea0ba38aeaaa9e22ae8a6b7aac7d6f9/pkg/goDB/engine/testdb/eth0/2016/02/1456444800_mm1-0-eE3-SvUZv-SF9Du1-CFM4-Ppa6/pkts_rcvd.gpf -------------------------------------------------------------------------------- /pkg/goDB/engine/testdb/eth0/2016/02/1456444800_mm1-0-eE3-SvUZv-SF9Du1-CFM4-Ppa6/pkts_sent.gpf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/els0r/goProbe/7eed90f04ea0ba38aeaaa9e22ae8a6b7aac7d6f9/pkg/goDB/engine/testdb/eth0/2016/02/1456444800_mm1-0-eE3-SvUZv-SF9Du1-CFM4-Ppa6/pkts_sent.gpf -------------------------------------------------------------------------------- /pkg/goDB/engine/testdb/eth0/2016/02/1456444800_mm1-0-eE3-SvUZv-SF9Du1-CFM4-Ppa6/proto.gpf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/els0r/goProbe/7eed90f04ea0ba38aeaaa9e22ae8a6b7aac7d6f9/pkg/goDB/engine/testdb/eth0/2016/02/1456444800_mm1-0-eE3-SvUZv-SF9Du1-CFM4-Ppa6/proto.gpf -------------------------------------------------------------------------------- /pkg/goDB/engine/testdb/eth0/2016/02/1456444800_mm1-0-eE3-SvUZv-SF9Du1-CFM4-Ppa6/sip.gpf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/els0r/goProbe/7eed90f04ea0ba38aeaaa9e22ae8a6b7aac7d6f9/pkg/goDB/engine/testdb/eth0/2016/02/1456444800_mm1-0-eE3-SvUZv-SF9Du1-CFM4-Ppa6/sip.gpf -------------------------------------------------------------------------------- /pkg/goDB/engine/testdb/eth1/2016/02/1456358400/.blockmeta: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/els0r/goProbe/7eed90f04ea0ba38aeaaa9e22ae8a6b7aac7d6f9/pkg/goDB/engine/testdb/eth1/2016/02/1456358400/.blockmeta -------------------------------------------------------------------------------- /pkg/goDB/engine/testdb/eth1/2016/02/1456358400/bytes_rcvd.gpf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/els0r/goProbe/7eed90f04ea0ba38aeaaa9e22ae8a6b7aac7d6f9/pkg/goDB/engine/testdb/eth1/2016/02/1456358400/bytes_rcvd.gpf -------------------------------------------------------------------------------- /pkg/goDB/engine/testdb/eth1/2016/02/1456358400/bytes_sent.gpf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/els0r/goProbe/7eed90f04ea0ba38aeaaa9e22ae8a6b7aac7d6f9/pkg/goDB/engine/testdb/eth1/2016/02/1456358400/bytes_sent.gpf -------------------------------------------------------------------------------- /pkg/goDB/engine/testdb/eth1/2016/02/1456358400/dip.gpf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/els0r/goProbe/7eed90f04ea0ba38aeaaa9e22ae8a6b7aac7d6f9/pkg/goDB/engine/testdb/eth1/2016/02/1456358400/dip.gpf -------------------------------------------------------------------------------- /pkg/goDB/engine/testdb/eth1/2016/02/1456358400/dport.gpf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/els0r/goProbe/7eed90f04ea0ba38aeaaa9e22ae8a6b7aac7d6f9/pkg/goDB/engine/testdb/eth1/2016/02/1456358400/dport.gpf -------------------------------------------------------------------------------- /pkg/goDB/engine/testdb/eth1/2016/02/1456358400/pkts_rcvd.gpf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/els0r/goProbe/7eed90f04ea0ba38aeaaa9e22ae8a6b7aac7d6f9/pkg/goDB/engine/testdb/eth1/2016/02/1456358400/pkts_rcvd.gpf -------------------------------------------------------------------------------- /pkg/goDB/engine/testdb/eth1/2016/02/1456358400/pkts_sent.gpf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/els0r/goProbe/7eed90f04ea0ba38aeaaa9e22ae8a6b7aac7d6f9/pkg/goDB/engine/testdb/eth1/2016/02/1456358400/pkts_sent.gpf -------------------------------------------------------------------------------- /pkg/goDB/engine/testdb/eth1/2016/02/1456358400/proto.gpf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/els0r/goProbe/7eed90f04ea0ba38aeaaa9e22ae8a6b7aac7d6f9/pkg/goDB/engine/testdb/eth1/2016/02/1456358400/proto.gpf -------------------------------------------------------------------------------- /pkg/goDB/engine/testdb/eth1/2016/02/1456358400/sip.gpf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/els0r/goProbe/7eed90f04ea0ba38aeaaa9e22ae8a6b7aac7d6f9/pkg/goDB/engine/testdb/eth1/2016/02/1456358400/sip.gpf -------------------------------------------------------------------------------- /pkg/goDB/engine/testdb/eth1/2016/02/1456444800_oX-1-aVB1-8PILs4-AK9rM2-0Gt8-05he/.blockmeta: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/els0r/goProbe/7eed90f04ea0ba38aeaaa9e22ae8a6b7aac7d6f9/pkg/goDB/engine/testdb/eth1/2016/02/1456444800_oX-1-aVB1-8PILs4-AK9rM2-0Gt8-05he/.blockmeta -------------------------------------------------------------------------------- /pkg/goDB/engine/testdb/eth1/2016/02/1456444800_oX-1-aVB1-8PILs4-AK9rM2-0Gt8-05he/bytes_rcvd.gpf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/els0r/goProbe/7eed90f04ea0ba38aeaaa9e22ae8a6b7aac7d6f9/pkg/goDB/engine/testdb/eth1/2016/02/1456444800_oX-1-aVB1-8PILs4-AK9rM2-0Gt8-05he/bytes_rcvd.gpf -------------------------------------------------------------------------------- /pkg/goDB/engine/testdb/eth1/2016/02/1456444800_oX-1-aVB1-8PILs4-AK9rM2-0Gt8-05he/bytes_sent.gpf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/els0r/goProbe/7eed90f04ea0ba38aeaaa9e22ae8a6b7aac7d6f9/pkg/goDB/engine/testdb/eth1/2016/02/1456444800_oX-1-aVB1-8PILs4-AK9rM2-0Gt8-05he/bytes_sent.gpf -------------------------------------------------------------------------------- /pkg/goDB/engine/testdb/eth1/2016/02/1456444800_oX-1-aVB1-8PILs4-AK9rM2-0Gt8-05he/dip.gpf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/els0r/goProbe/7eed90f04ea0ba38aeaaa9e22ae8a6b7aac7d6f9/pkg/goDB/engine/testdb/eth1/2016/02/1456444800_oX-1-aVB1-8PILs4-AK9rM2-0Gt8-05he/dip.gpf -------------------------------------------------------------------------------- /pkg/goDB/engine/testdb/eth1/2016/02/1456444800_oX-1-aVB1-8PILs4-AK9rM2-0Gt8-05he/dport.gpf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/els0r/goProbe/7eed90f04ea0ba38aeaaa9e22ae8a6b7aac7d6f9/pkg/goDB/engine/testdb/eth1/2016/02/1456444800_oX-1-aVB1-8PILs4-AK9rM2-0Gt8-05he/dport.gpf -------------------------------------------------------------------------------- /pkg/goDB/engine/testdb/eth1/2016/02/1456444800_oX-1-aVB1-8PILs4-AK9rM2-0Gt8-05he/pkts_rcvd.gpf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/els0r/goProbe/7eed90f04ea0ba38aeaaa9e22ae8a6b7aac7d6f9/pkg/goDB/engine/testdb/eth1/2016/02/1456444800_oX-1-aVB1-8PILs4-AK9rM2-0Gt8-05he/pkts_rcvd.gpf -------------------------------------------------------------------------------- /pkg/goDB/engine/testdb/eth1/2016/02/1456444800_oX-1-aVB1-8PILs4-AK9rM2-0Gt8-05he/pkts_sent.gpf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/els0r/goProbe/7eed90f04ea0ba38aeaaa9e22ae8a6b7aac7d6f9/pkg/goDB/engine/testdb/eth1/2016/02/1456444800_oX-1-aVB1-8PILs4-AK9rM2-0Gt8-05he/pkts_sent.gpf -------------------------------------------------------------------------------- /pkg/goDB/engine/testdb/eth1/2016/02/1456444800_oX-1-aVB1-8PILs4-AK9rM2-0Gt8-05he/proto.gpf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/els0r/goProbe/7eed90f04ea0ba38aeaaa9e22ae8a6b7aac7d6f9/pkg/goDB/engine/testdb/eth1/2016/02/1456444800_oX-1-aVB1-8PILs4-AK9rM2-0Gt8-05he/proto.gpf -------------------------------------------------------------------------------- /pkg/goDB/engine/testdb/eth1/2016/02/1456444800_oX-1-aVB1-8PILs4-AK9rM2-0Gt8-05he/sip.gpf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/els0r/goProbe/7eed90f04ea0ba38aeaaa9e22ae8a6b7aac7d6f9/pkg/goDB/engine/testdb/eth1/2016/02/1456444800_oX-1-aVB1-8PILs4-AK9rM2-0Gt8-05he/sip.gpf -------------------------------------------------------------------------------- /pkg/goDB/engine/testdb/eth2/2016/02/1456358400/.blockmeta: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/els0r/goProbe/7eed90f04ea0ba38aeaaa9e22ae8a6b7aac7d6f9/pkg/goDB/engine/testdb/eth2/2016/02/1456358400/.blockmeta -------------------------------------------------------------------------------- /pkg/goDB/engine/testdb/eth2/2016/02/1456358400/bytes_rcvd.gpf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/els0r/goProbe/7eed90f04ea0ba38aeaaa9e22ae8a6b7aac7d6f9/pkg/goDB/engine/testdb/eth2/2016/02/1456358400/bytes_rcvd.gpf -------------------------------------------------------------------------------- /pkg/goDB/engine/testdb/eth2/2016/02/1456358400/bytes_sent.gpf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/els0r/goProbe/7eed90f04ea0ba38aeaaa9e22ae8a6b7aac7d6f9/pkg/goDB/engine/testdb/eth2/2016/02/1456358400/bytes_sent.gpf -------------------------------------------------------------------------------- /pkg/goDB/engine/testdb/eth2/2016/02/1456358400/dip.gpf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/els0r/goProbe/7eed90f04ea0ba38aeaaa9e22ae8a6b7aac7d6f9/pkg/goDB/engine/testdb/eth2/2016/02/1456358400/dip.gpf -------------------------------------------------------------------------------- /pkg/goDB/engine/testdb/eth2/2016/02/1456358400/dport.gpf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/els0r/goProbe/7eed90f04ea0ba38aeaaa9e22ae8a6b7aac7d6f9/pkg/goDB/engine/testdb/eth2/2016/02/1456358400/dport.gpf -------------------------------------------------------------------------------- /pkg/goDB/engine/testdb/eth2/2016/02/1456358400/pkts_rcvd.gpf: -------------------------------------------------------------------------------- 1 |   2 | 3 | 4 |  5 |  6 |  7 | 8 |  9 | 10 |   11 |  12 |  13 | 14 |  15 | 16 |  17 | 18 |  19 |  20 | 21 | 22 |  23 |  24 | 25 |  26 |  27 | 28 |  29 |  30 | 31 |  32 |  33 | 34 |  35 |  36 | 37 |  38 | 39 | 40 |   41 |  42 | 43 |   44 |  45 | 46 |    47 | 48 |  49 |  50 |  51 |  52 |  53 |  54 | 55 |  56 |  57 |  58 | 59 |  60 | 61 |   62 | 63 | 64 |  65 |  66 | 67 |  68 | 69 |  70 |  71 | 72 |  73 | 74 |   75 | 76 | -------------------------------------------------------------------------------- /pkg/goDB/engine/testdb/eth2/2016/02/1456358400/pkts_sent.gpf: -------------------------------------------------------------------------------- 1 |                    2 |              3 |    -------------------------------------------------------------------------------- /pkg/goDB/engine/testdb/eth2/2016/02/1456358400/proto.gpf: -------------------------------------------------------------------------------- 1 |  -------------------------------------------------------------------------------- /pkg/goDB/engine/testdb/eth2/2016/02/1456358400/sip.gpf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/els0r/goProbe/7eed90f04ea0ba38aeaaa9e22ae8a6b7aac7d6f9/pkg/goDB/engine/testdb/eth2/2016/02/1456358400/sip.gpf -------------------------------------------------------------------------------- /pkg/goDB/engine/testdb/eth2/2016/02/1456444800_w3-0-0-2mW1-KQ81-DA-Xo/.blockmeta: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/els0r/goProbe/7eed90f04ea0ba38aeaaa9e22ae8a6b7aac7d6f9/pkg/goDB/engine/testdb/eth2/2016/02/1456444800_w3-0-0-2mW1-KQ81-DA-Xo/.blockmeta -------------------------------------------------------------------------------- /pkg/goDB/engine/testdb/eth2/2016/02/1456444800_w3-0-0-2mW1-KQ81-DA-Xo/bytes_rcvd.gpf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/els0r/goProbe/7eed90f04ea0ba38aeaaa9e22ae8a6b7aac7d6f9/pkg/goDB/engine/testdb/eth2/2016/02/1456444800_w3-0-0-2mW1-KQ81-DA-Xo/bytes_rcvd.gpf -------------------------------------------------------------------------------- /pkg/goDB/engine/testdb/eth2/2016/02/1456444800_w3-0-0-2mW1-KQ81-DA-Xo/bytes_sent.gpf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/els0r/goProbe/7eed90f04ea0ba38aeaaa9e22ae8a6b7aac7d6f9/pkg/goDB/engine/testdb/eth2/2016/02/1456444800_w3-0-0-2mW1-KQ81-DA-Xo/bytes_sent.gpf -------------------------------------------------------------------------------- /pkg/goDB/engine/testdb/eth2/2016/02/1456444800_w3-0-0-2mW1-KQ81-DA-Xo/dip.gpf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/els0r/goProbe/7eed90f04ea0ba38aeaaa9e22ae8a6b7aac7d6f9/pkg/goDB/engine/testdb/eth2/2016/02/1456444800_w3-0-0-2mW1-KQ81-DA-Xo/dip.gpf -------------------------------------------------------------------------------- /pkg/goDB/engine/testdb/eth2/2016/02/1456444800_w3-0-0-2mW1-KQ81-DA-Xo/dport.gpf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/els0r/goProbe/7eed90f04ea0ba38aeaaa9e22ae8a6b7aac7d6f9/pkg/goDB/engine/testdb/eth2/2016/02/1456444800_w3-0-0-2mW1-KQ81-DA-Xo/dport.gpf -------------------------------------------------------------------------------- /pkg/goDB/engine/testdb/eth2/2016/02/1456444800_w3-0-0-2mW1-KQ81-DA-Xo/pkts_rcvd.gpf: -------------------------------------------------------------------------------- 1 |  2 |  3 | 4 |  5 |  6 | 7 |  8 |  9 | 10 | 11 |  12 |  13 |  14 | 15 |  16 | 17 |  18 |  19 | 20 | 21 |  22 |  23 |  24 | 25 |  26 |  27 |  28 | 29 |  30 |  31 | 32 |  33 |  34 |  35 |  36 | 37 |  38 |  39 | 40 | 41 |  42 |  43 |  44 | 45 |  46 | 47 |  48 |  49 | 50 | 51 |  52 |  53 |  54 |  55 |   56 | 57 | 58 |  59 |  60 |  61 |  62 | 63 |  64 |  65 | 66 | 67 |  68 |  69 |  70 | 71 |  72 | 73 |  74 |  75 | 76 |  77 |  78 | 79 |  80 | 81 |  82 |  83 | 84 |  85 | 86 |   87 | 88 |  89 |  90 |  91 | 92 |  93 |   94 | 95 |   96 | 97 |  98 | 99 |  100 |  101 |  102 | 103 | 104 |  105 |  106 |  107 | 108 |  109 |   110 | 111 | 112 |  113 |  114 |  115 | 116 |  117 | 118 |  119 |  120 | 121 | 122 |  123 |  124 | 125 | 126 |   127 |  128 |  129 | 130 |  131 |  132 | 133 |   134 |  135 | 136 | -------------------------------------------------------------------------------- /pkg/goDB/engine/testdb/eth2/2016/02/1456444800_w3-0-0-2mW1-KQ81-DA-Xo/pkts_sent.gpf: -------------------------------------------------------------------------------- 1 |                                                         -------------------------------------------------------------------------------- /pkg/goDB/engine/testdb/eth2/2016/02/1456444800_w3-0-0-2mW1-KQ81-DA-Xo/proto.gpf: -------------------------------------------------------------------------------- 1 |  -------------------------------------------------------------------------------- /pkg/goDB/engine/testdb/eth2/2016/02/1456444800_w3-0-0-2mW1-KQ81-DA-Xo/sip.gpf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/els0r/goProbe/7eed90f04ea0ba38aeaaa9e22ae8a6b7aac7d6f9/pkg/goDB/engine/testdb/eth2/2016/02/1456444800_w3-0-0-2mW1-KQ81-DA-Xo/sip.gpf -------------------------------------------------------------------------------- /pkg/goDB/engine/testdb/t_c1_fwde/2016/02/1456358400/.blockmeta: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/els0r/goProbe/7eed90f04ea0ba38aeaaa9e22ae8a6b7aac7d6f9/pkg/goDB/engine/testdb/t_c1_fwde/2016/02/1456358400/.blockmeta -------------------------------------------------------------------------------- /pkg/goDB/engine/testdb/t_c1_fwde/2016/02/1456358400/bytes_rcvd.gpf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/els0r/goProbe/7eed90f04ea0ba38aeaaa9e22ae8a6b7aac7d6f9/pkg/goDB/engine/testdb/t_c1_fwde/2016/02/1456358400/bytes_rcvd.gpf -------------------------------------------------------------------------------- /pkg/goDB/engine/testdb/t_c1_fwde/2016/02/1456358400/bytes_sent.gpf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/els0r/goProbe/7eed90f04ea0ba38aeaaa9e22ae8a6b7aac7d6f9/pkg/goDB/engine/testdb/t_c1_fwde/2016/02/1456358400/bytes_sent.gpf -------------------------------------------------------------------------------- /pkg/goDB/engine/testdb/t_c1_fwde/2016/02/1456358400/dip.gpf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/els0r/goProbe/7eed90f04ea0ba38aeaaa9e22ae8a6b7aac7d6f9/pkg/goDB/engine/testdb/t_c1_fwde/2016/02/1456358400/dip.gpf -------------------------------------------------------------------------------- /pkg/goDB/engine/testdb/t_c1_fwde/2016/02/1456358400/dport.gpf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/els0r/goProbe/7eed90f04ea0ba38aeaaa9e22ae8a6b7aac7d6f9/pkg/goDB/engine/testdb/t_c1_fwde/2016/02/1456358400/dport.gpf -------------------------------------------------------------------------------- /pkg/goDB/engine/testdb/t_c1_fwde/2016/02/1456358400/pkts_rcvd.gpf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/els0r/goProbe/7eed90f04ea0ba38aeaaa9e22ae8a6b7aac7d6f9/pkg/goDB/engine/testdb/t_c1_fwde/2016/02/1456358400/pkts_rcvd.gpf -------------------------------------------------------------------------------- /pkg/goDB/engine/testdb/t_c1_fwde/2016/02/1456358400/pkts_sent.gpf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/els0r/goProbe/7eed90f04ea0ba38aeaaa9e22ae8a6b7aac7d6f9/pkg/goDB/engine/testdb/t_c1_fwde/2016/02/1456358400/pkts_sent.gpf -------------------------------------------------------------------------------- /pkg/goDB/engine/testdb/t_c1_fwde/2016/02/1456358400/proto.gpf: -------------------------------------------------------------------------------- 1 | PPPPPP*P,P+PPPP<PPPPPPPPPPPPP+PPP-P?pPPPPPPPPPPPPPPPPPPPPPPPP -------------------------------------------------------------------------------- /pkg/goDB/engine/testdb/t_c1_fwde/2016/02/1456358400/sip.gpf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/els0r/goProbe/7eed90f04ea0ba38aeaaa9e22ae8a6b7aac7d6f9/pkg/goDB/engine/testdb/t_c1_fwde/2016/02/1456358400/sip.gpf -------------------------------------------------------------------------------- /pkg/goDB/engine/testdb/t_c1_fwde/2016/02/1456444800_Ns-0-0-fXANh-hb5ap-Eum1-o3w1/.blockmeta: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/els0r/goProbe/7eed90f04ea0ba38aeaaa9e22ae8a6b7aac7d6f9/pkg/goDB/engine/testdb/t_c1_fwde/2016/02/1456444800_Ns-0-0-fXANh-hb5ap-Eum1-o3w1/.blockmeta -------------------------------------------------------------------------------- /pkg/goDB/engine/testdb/t_c1_fwde/2016/02/1456444800_Ns-0-0-fXANh-hb5ap-Eum1-o3w1/bytes_rcvd.gpf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/els0r/goProbe/7eed90f04ea0ba38aeaaa9e22ae8a6b7aac7d6f9/pkg/goDB/engine/testdb/t_c1_fwde/2016/02/1456444800_Ns-0-0-fXANh-hb5ap-Eum1-o3w1/bytes_rcvd.gpf -------------------------------------------------------------------------------- /pkg/goDB/engine/testdb/t_c1_fwde/2016/02/1456444800_Ns-0-0-fXANh-hb5ap-Eum1-o3w1/bytes_sent.gpf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/els0r/goProbe/7eed90f04ea0ba38aeaaa9e22ae8a6b7aac7d6f9/pkg/goDB/engine/testdb/t_c1_fwde/2016/02/1456444800_Ns-0-0-fXANh-hb5ap-Eum1-o3w1/bytes_sent.gpf -------------------------------------------------------------------------------- /pkg/goDB/engine/testdb/t_c1_fwde/2016/02/1456444800_Ns-0-0-fXANh-hb5ap-Eum1-o3w1/dip.gpf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/els0r/goProbe/7eed90f04ea0ba38aeaaa9e22ae8a6b7aac7d6f9/pkg/goDB/engine/testdb/t_c1_fwde/2016/02/1456444800_Ns-0-0-fXANh-hb5ap-Eum1-o3w1/dip.gpf -------------------------------------------------------------------------------- /pkg/goDB/engine/testdb/t_c1_fwde/2016/02/1456444800_Ns-0-0-fXANh-hb5ap-Eum1-o3w1/dport.gpf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/els0r/goProbe/7eed90f04ea0ba38aeaaa9e22ae8a6b7aac7d6f9/pkg/goDB/engine/testdb/t_c1_fwde/2016/02/1456444800_Ns-0-0-fXANh-hb5ap-Eum1-o3w1/dport.gpf -------------------------------------------------------------------------------- /pkg/goDB/engine/testdb/t_c1_fwde/2016/02/1456444800_Ns-0-0-fXANh-hb5ap-Eum1-o3w1/pkts_rcvd.gpf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/els0r/goProbe/7eed90f04ea0ba38aeaaa9e22ae8a6b7aac7d6f9/pkg/goDB/engine/testdb/t_c1_fwde/2016/02/1456444800_Ns-0-0-fXANh-hb5ap-Eum1-o3w1/pkts_rcvd.gpf -------------------------------------------------------------------------------- /pkg/goDB/engine/testdb/t_c1_fwde/2016/02/1456444800_Ns-0-0-fXANh-hb5ap-Eum1-o3w1/pkts_sent.gpf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/els0r/goProbe/7eed90f04ea0ba38aeaaa9e22ae8a6b7aac7d6f9/pkg/goDB/engine/testdb/t_c1_fwde/2016/02/1456444800_Ns-0-0-fXANh-hb5ap-Eum1-o3w1/pkts_sent.gpf -------------------------------------------------------------------------------- /pkg/goDB/engine/testdb/t_c1_fwde/2016/02/1456444800_Ns-0-0-fXANh-hb5ap-Eum1-o3w1/proto.gpf: -------------------------------------------------------------------------------- 1 | PPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPP -------------------------------------------------------------------------------- /pkg/goDB/engine/testdb/t_c1_fwde/2016/02/1456444800_Ns-0-0-fXANh-hb5ap-Eum1-o3w1/sip.gpf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/els0r/goProbe/7eed90f04ea0ba38aeaaa9e22ae8a6b7aac7d6f9/pkg/goDB/engine/testdb/t_c1_fwde/2016/02/1456444800_Ns-0-0-fXANh-hb5ap-Eum1-o3w1/sip.gpf -------------------------------------------------------------------------------- /pkg/goDB/engine/testdb/t_c1_fwde1/2016/02/1456358400/.blockmeta: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/els0r/goProbe/7eed90f04ea0ba38aeaaa9e22ae8a6b7aac7d6f9/pkg/goDB/engine/testdb/t_c1_fwde1/2016/02/1456358400/.blockmeta -------------------------------------------------------------------------------- /pkg/goDB/engine/testdb/t_c1_fwde1/2016/02/1456358400/bytes_rcvd.gpf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/els0r/goProbe/7eed90f04ea0ba38aeaaa9e22ae8a6b7aac7d6f9/pkg/goDB/engine/testdb/t_c1_fwde1/2016/02/1456358400/bytes_rcvd.gpf -------------------------------------------------------------------------------- /pkg/goDB/engine/testdb/t_c1_fwde1/2016/02/1456358400/bytes_sent.gpf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/els0r/goProbe/7eed90f04ea0ba38aeaaa9e22ae8a6b7aac7d6f9/pkg/goDB/engine/testdb/t_c1_fwde1/2016/02/1456358400/bytes_sent.gpf -------------------------------------------------------------------------------- /pkg/goDB/engine/testdb/t_c1_fwde1/2016/02/1456358400/dip.gpf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/els0r/goProbe/7eed90f04ea0ba38aeaaa9e22ae8a6b7aac7d6f9/pkg/goDB/engine/testdb/t_c1_fwde1/2016/02/1456358400/dip.gpf -------------------------------------------------------------------------------- /pkg/goDB/engine/testdb/t_c1_fwde1/2016/02/1456358400/dport.gpf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/els0r/goProbe/7eed90f04ea0ba38aeaaa9e22ae8a6b7aac7d6f9/pkg/goDB/engine/testdb/t_c1_fwde1/2016/02/1456358400/dport.gpf -------------------------------------------------------------------------------- /pkg/goDB/engine/testdb/t_c1_fwde1/2016/02/1456358400/pkts_rcvd.gpf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/els0r/goProbe/7eed90f04ea0ba38aeaaa9e22ae8a6b7aac7d6f9/pkg/goDB/engine/testdb/t_c1_fwde1/2016/02/1456358400/pkts_rcvd.gpf -------------------------------------------------------------------------------- /pkg/goDB/engine/testdb/t_c1_fwde1/2016/02/1456358400/pkts_sent.gpf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/els0r/goProbe/7eed90f04ea0ba38aeaaa9e22ae8a6b7aac7d6f9/pkg/goDB/engine/testdb/t_c1_fwde1/2016/02/1456358400/pkts_sent.gpf -------------------------------------------------------------------------------- /pkg/goDB/engine/testdb/t_c1_fwde1/2016/02/1456358400/proto.gpf: -------------------------------------------------------------------------------- 1 |  -------------------------------------------------------------------------------- /pkg/goDB/engine/testdb/t_c1_fwde1/2016/02/1456358400/sip.gpf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/els0r/goProbe/7eed90f04ea0ba38aeaaa9e22ae8a6b7aac7d6f9/pkg/goDB/engine/testdb/t_c1_fwde1/2016/02/1456358400/sip.gpf -------------------------------------------------------------------------------- /pkg/goDB/engine/testdb/t_c1_fwde1/2016/02/1456444800_a6-0-0-I6k54-JwjJ-Ltg-nij/.blockmeta: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/els0r/goProbe/7eed90f04ea0ba38aeaaa9e22ae8a6b7aac7d6f9/pkg/goDB/engine/testdb/t_c1_fwde1/2016/02/1456444800_a6-0-0-I6k54-JwjJ-Ltg-nij/.blockmeta -------------------------------------------------------------------------------- /pkg/goDB/engine/testdb/t_c1_fwde1/2016/02/1456444800_a6-0-0-I6k54-JwjJ-Ltg-nij/bytes_rcvd.gpf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/els0r/goProbe/7eed90f04ea0ba38aeaaa9e22ae8a6b7aac7d6f9/pkg/goDB/engine/testdb/t_c1_fwde1/2016/02/1456444800_a6-0-0-I6k54-JwjJ-Ltg-nij/bytes_rcvd.gpf -------------------------------------------------------------------------------- /pkg/goDB/engine/testdb/t_c1_fwde1/2016/02/1456444800_a6-0-0-I6k54-JwjJ-Ltg-nij/bytes_sent.gpf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/els0r/goProbe/7eed90f04ea0ba38aeaaa9e22ae8a6b7aac7d6f9/pkg/goDB/engine/testdb/t_c1_fwde1/2016/02/1456444800_a6-0-0-I6k54-JwjJ-Ltg-nij/bytes_sent.gpf -------------------------------------------------------------------------------- /pkg/goDB/engine/testdb/t_c1_fwde1/2016/02/1456444800_a6-0-0-I6k54-JwjJ-Ltg-nij/dip.gpf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/els0r/goProbe/7eed90f04ea0ba38aeaaa9e22ae8a6b7aac7d6f9/pkg/goDB/engine/testdb/t_c1_fwde1/2016/02/1456444800_a6-0-0-I6k54-JwjJ-Ltg-nij/dip.gpf -------------------------------------------------------------------------------- /pkg/goDB/engine/testdb/t_c1_fwde1/2016/02/1456444800_a6-0-0-I6k54-JwjJ-Ltg-nij/dport.gpf: -------------------------------------------------------------------------------- 1 | U"U"5U"U"U"U"U"U"U"U"U"U"U"U"U"U"U"U"U"U"U"U"U"U"U"U"U"U"U"U"5U"U"U"U"U"U"U"U"U"U"U"U"U"U"U"U"U"U"U"U"U"U"U"U"U"U"5U"U"U"U"U"U"U"U"U"U"U"U"U"U"U"U"U"U"U"U"U"U"U"U"U"U"U"U"5U"U"U"U"U"U"U"U"U"U"U"U"U"U"U"U"U"U"U"U"U"U"U"U"U"U"U"U"5U"U"U"U"U"U"U"U"U"U"U"U"U"U"U"U"U"U"U"U"U"U"U"U"U"U"5U"U"U"U"U"U"U"U"U"U"U"U"U"U"U"U"U"U"U"U"U"U"U"U"U"U"U"U"U"U"U"U"5U"U"U"U"U"U"U"U"U"U"U"U"U"U"U"U" -------------------------------------------------------------------------------- /pkg/goDB/engine/testdb/t_c1_fwde1/2016/02/1456444800_a6-0-0-I6k54-JwjJ-Ltg-nij/pkts_rcvd.gpf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/els0r/goProbe/7eed90f04ea0ba38aeaaa9e22ae8a6b7aac7d6f9/pkg/goDB/engine/testdb/t_c1_fwde1/2016/02/1456444800_a6-0-0-I6k54-JwjJ-Ltg-nij/pkts_rcvd.gpf -------------------------------------------------------------------------------- /pkg/goDB/engine/testdb/t_c1_fwde1/2016/02/1456444800_a6-0-0-I6k54-JwjJ-Ltg-nij/pkts_sent.gpf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/els0r/goProbe/7eed90f04ea0ba38aeaaa9e22ae8a6b7aac7d6f9/pkg/goDB/engine/testdb/t_c1_fwde1/2016/02/1456444800_a6-0-0-I6k54-JwjJ-Ltg-nij/pkts_sent.gpf -------------------------------------------------------------------------------- /pkg/goDB/engine/testdb/t_c1_fwde1/2016/02/1456444800_a6-0-0-I6k54-JwjJ-Ltg-nij/proto.gpf: -------------------------------------------------------------------------------- 1 |  -------------------------------------------------------------------------------- /pkg/goDB/engine/testdb/t_c1_fwde1/2016/02/1456444800_a6-0-0-I6k54-JwjJ-Ltg-nij/sip.gpf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/els0r/goProbe/7eed90f04ea0ba38aeaaa9e22ae8a6b7aac7d6f9/pkg/goDB/engine/testdb/t_c1_fwde1/2016/02/1456444800_a6-0-0-I6k54-JwjJ-Ltg-nij/sip.gpf -------------------------------------------------------------------------------- /pkg/goDB/engine/testdb/tun_3g_c1_fw1/2016/02/1456358400/.blockmeta: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/els0r/goProbe/7eed90f04ea0ba38aeaaa9e22ae8a6b7aac7d6f9/pkg/goDB/engine/testdb/tun_3g_c1_fw1/2016/02/1456358400/.blockmeta -------------------------------------------------------------------------------- /pkg/goDB/engine/testdb/tun_3g_c1_fw1/2016/02/1456358400/bytes_rcvd.gpf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/els0r/goProbe/7eed90f04ea0ba38aeaaa9e22ae8a6b7aac7d6f9/pkg/goDB/engine/testdb/tun_3g_c1_fw1/2016/02/1456358400/bytes_rcvd.gpf -------------------------------------------------------------------------------- /pkg/goDB/engine/testdb/tun_3g_c1_fw1/2016/02/1456358400/bytes_sent.gpf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/els0r/goProbe/7eed90f04ea0ba38aeaaa9e22ae8a6b7aac7d6f9/pkg/goDB/engine/testdb/tun_3g_c1_fw1/2016/02/1456358400/bytes_sent.gpf -------------------------------------------------------------------------------- /pkg/goDB/engine/testdb/tun_3g_c1_fw1/2016/02/1456358400/dip.gpf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/els0r/goProbe/7eed90f04ea0ba38aeaaa9e22ae8a6b7aac7d6f9/pkg/goDB/engine/testdb/tun_3g_c1_fw1/2016/02/1456358400/dip.gpf -------------------------------------------------------------------------------- /pkg/goDB/engine/testdb/tun_3g_c1_fw1/2016/02/1456358400/dport.gpf: -------------------------------------------------------------------------------- 1 |  -------------------------------------------------------------------------------- /pkg/goDB/engine/testdb/tun_3g_c1_fw1/2016/02/1456358400/pkts_rcvd.gpf: -------------------------------------------------------------------------------- 1 |  -------------------------------------------------------------------------------- /pkg/goDB/engine/testdb/tun_3g_c1_fw1/2016/02/1456358400/pkts_sent.gpf: -------------------------------------------------------------------------------- 1 |  -------------------------------------------------------------------------------- /pkg/goDB/engine/testdb/tun_3g_c1_fw1/2016/02/1456358400/proto.gpf: -------------------------------------------------------------------------------- 1 |  -------------------------------------------------------------------------------- /pkg/goDB/engine/testdb/tun_3g_c1_fw1/2016/02/1456358400/sip.gpf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/els0r/goProbe/7eed90f04ea0ba38aeaaa9e22ae8a6b7aac7d6f9/pkg/goDB/engine/testdb/tun_3g_c1_fw1/2016/02/1456358400/sip.gpf -------------------------------------------------------------------------------- /pkg/goDB/engine/testdb/tun_3g_c1_fw1/2016/02/1456444800_v1-0-0-yr7-j86-g9-P5/.blockmeta: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/els0r/goProbe/7eed90f04ea0ba38aeaaa9e22ae8a6b7aac7d6f9/pkg/goDB/engine/testdb/tun_3g_c1_fw1/2016/02/1456444800_v1-0-0-yr7-j86-g9-P5/.blockmeta -------------------------------------------------------------------------------- /pkg/goDB/engine/testdb/tun_3g_c1_fw1/2016/02/1456444800_v1-0-0-yr7-j86-g9-P5/bytes_rcvd.gpf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/els0r/goProbe/7eed90f04ea0ba38aeaaa9e22ae8a6b7aac7d6f9/pkg/goDB/engine/testdb/tun_3g_c1_fw1/2016/02/1456444800_v1-0-0-yr7-j86-g9-P5/bytes_rcvd.gpf -------------------------------------------------------------------------------- /pkg/goDB/engine/testdb/tun_3g_c1_fw1/2016/02/1456444800_v1-0-0-yr7-j86-g9-P5/bytes_sent.gpf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/els0r/goProbe/7eed90f04ea0ba38aeaaa9e22ae8a6b7aac7d6f9/pkg/goDB/engine/testdb/tun_3g_c1_fw1/2016/02/1456444800_v1-0-0-yr7-j86-g9-P5/bytes_sent.gpf -------------------------------------------------------------------------------- /pkg/goDB/engine/testdb/tun_3g_c1_fw1/2016/02/1456444800_v1-0-0-yr7-j86-g9-P5/dip.gpf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/els0r/goProbe/7eed90f04ea0ba38aeaaa9e22ae8a6b7aac7d6f9/pkg/goDB/engine/testdb/tun_3g_c1_fw1/2016/02/1456444800_v1-0-0-yr7-j86-g9-P5/dip.gpf -------------------------------------------------------------------------------- /pkg/goDB/engine/testdb/tun_3g_c1_fw1/2016/02/1456444800_v1-0-0-yr7-j86-g9-P5/dport.gpf: -------------------------------------------------------------------------------- 1 |  -------------------------------------------------------------------------------- /pkg/goDB/engine/testdb/tun_3g_c1_fw1/2016/02/1456444800_v1-0-0-yr7-j86-g9-P5/pkts_rcvd.gpf: -------------------------------------------------------------------------------- 1 |  -------------------------------------------------------------------------------- /pkg/goDB/engine/testdb/tun_3g_c1_fw1/2016/02/1456444800_v1-0-0-yr7-j86-g9-P5/pkts_sent.gpf: -------------------------------------------------------------------------------- 1 |  -------------------------------------------------------------------------------- /pkg/goDB/engine/testdb/tun_3g_c1_fw1/2016/02/1456444800_v1-0-0-yr7-j86-g9-P5/proto.gpf: -------------------------------------------------------------------------------- 1 |  -------------------------------------------------------------------------------- /pkg/goDB/engine/testdb/tun_3g_c1_fw1/2016/02/1456444800_v1-0-0-yr7-j86-g9-P5/sip.gpf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/els0r/goProbe/7eed90f04ea0ba38aeaaa9e22ae8a6b7aac7d6f9/pkg/goDB/engine/testdb/tun_3g_c1_fw1/2016/02/1456444800_v1-0-0-yr7-j86-g9-P5/sip.gpf -------------------------------------------------------------------------------- /pkg/goDB/engine/testdb/tun_3g_c1_fwde/2016/02/1456358400/.blockmeta: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/els0r/goProbe/7eed90f04ea0ba38aeaaa9e22ae8a6b7aac7d6f9/pkg/goDB/engine/testdb/tun_3g_c1_fwde/2016/02/1456358400/.blockmeta -------------------------------------------------------------------------------- /pkg/goDB/engine/testdb/tun_3g_c1_fwde/2016/02/1456358400/bytes_rcvd.gpf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/els0r/goProbe/7eed90f04ea0ba38aeaaa9e22ae8a6b7aac7d6f9/pkg/goDB/engine/testdb/tun_3g_c1_fwde/2016/02/1456358400/bytes_rcvd.gpf -------------------------------------------------------------------------------- /pkg/goDB/engine/testdb/tun_3g_c1_fwde/2016/02/1456358400/bytes_sent.gpf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/els0r/goProbe/7eed90f04ea0ba38aeaaa9e22ae8a6b7aac7d6f9/pkg/goDB/engine/testdb/tun_3g_c1_fwde/2016/02/1456358400/bytes_sent.gpf -------------------------------------------------------------------------------- /pkg/goDB/engine/testdb/tun_3g_c1_fwde/2016/02/1456358400/dip.gpf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/els0r/goProbe/7eed90f04ea0ba38aeaaa9e22ae8a6b7aac7d6f9/pkg/goDB/engine/testdb/tun_3g_c1_fwde/2016/02/1456358400/dip.gpf -------------------------------------------------------------------------------- /pkg/goDB/engine/testdb/tun_3g_c1_fwde/2016/02/1456358400/dport.gpf: -------------------------------------------------------------------------------- 1 |  -------------------------------------------------------------------------------- /pkg/goDB/engine/testdb/tun_3g_c1_fwde/2016/02/1456358400/pkts_rcvd.gpf: -------------------------------------------------------------------------------- 1 |  -------------------------------------------------------------------------------- /pkg/goDB/engine/testdb/tun_3g_c1_fwde/2016/02/1456358400/pkts_sent.gpf: -------------------------------------------------------------------------------- 1 |  -------------------------------------------------------------------------------- /pkg/goDB/engine/testdb/tun_3g_c1_fwde/2016/02/1456358400/proto.gpf: -------------------------------------------------------------------------------- 1 |  -------------------------------------------------------------------------------- /pkg/goDB/engine/testdb/tun_3g_c1_fwde/2016/02/1456358400/sip.gpf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/els0r/goProbe/7eed90f04ea0ba38aeaaa9e22ae8a6b7aac7d6f9/pkg/goDB/engine/testdb/tun_3g_c1_fwde/2016/02/1456358400/sip.gpf -------------------------------------------------------------------------------- /pkg/goDB/engine/testdb/tun_3g_c1_fwde/2016/02/1456444800_v1-0-0-cg6-bg5-18-T4/.blockmeta: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/els0r/goProbe/7eed90f04ea0ba38aeaaa9e22ae8a6b7aac7d6f9/pkg/goDB/engine/testdb/tun_3g_c1_fwde/2016/02/1456444800_v1-0-0-cg6-bg5-18-T4/.blockmeta -------------------------------------------------------------------------------- /pkg/goDB/engine/testdb/tun_3g_c1_fwde/2016/02/1456444800_v1-0-0-cg6-bg5-18-T4/bytes_rcvd.gpf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/els0r/goProbe/7eed90f04ea0ba38aeaaa9e22ae8a6b7aac7d6f9/pkg/goDB/engine/testdb/tun_3g_c1_fwde/2016/02/1456444800_v1-0-0-cg6-bg5-18-T4/bytes_rcvd.gpf -------------------------------------------------------------------------------- /pkg/goDB/engine/testdb/tun_3g_c1_fwde/2016/02/1456444800_v1-0-0-cg6-bg5-18-T4/bytes_sent.gpf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/els0r/goProbe/7eed90f04ea0ba38aeaaa9e22ae8a6b7aac7d6f9/pkg/goDB/engine/testdb/tun_3g_c1_fwde/2016/02/1456444800_v1-0-0-cg6-bg5-18-T4/bytes_sent.gpf -------------------------------------------------------------------------------- /pkg/goDB/engine/testdb/tun_3g_c1_fwde/2016/02/1456444800_v1-0-0-cg6-bg5-18-T4/dip.gpf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/els0r/goProbe/7eed90f04ea0ba38aeaaa9e22ae8a6b7aac7d6f9/pkg/goDB/engine/testdb/tun_3g_c1_fwde/2016/02/1456444800_v1-0-0-cg6-bg5-18-T4/dip.gpf -------------------------------------------------------------------------------- /pkg/goDB/engine/testdb/tun_3g_c1_fwde/2016/02/1456444800_v1-0-0-cg6-bg5-18-T4/dport.gpf: -------------------------------------------------------------------------------- 1 |  -------------------------------------------------------------------------------- /pkg/goDB/engine/testdb/tun_3g_c1_fwde/2016/02/1456444800_v1-0-0-cg6-bg5-18-T4/pkts_rcvd.gpf: -------------------------------------------------------------------------------- 1 |  -------------------------------------------------------------------------------- /pkg/goDB/engine/testdb/tun_3g_c1_fwde/2016/02/1456444800_v1-0-0-cg6-bg5-18-T4/pkts_sent.gpf: -------------------------------------------------------------------------------- 1 |  -------------------------------------------------------------------------------- /pkg/goDB/engine/testdb/tun_3g_c1_fwde/2016/02/1456444800_v1-0-0-cg6-bg5-18-T4/proto.gpf: -------------------------------------------------------------------------------- 1 |  -------------------------------------------------------------------------------- /pkg/goDB/engine/testdb/tun_3g_c1_fwde/2016/02/1456444800_v1-0-0-cg6-bg5-18-T4/sip.gpf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/els0r/goProbe/7eed90f04ea0ba38aeaaa9e22ae8a6b7aac7d6f9/pkg/goDB/engine/testdb/tun_3g_c1_fwde/2016/02/1456444800_v1-0-0-cg6-bg5-18-T4/sip.gpf -------------------------------------------------------------------------------- /pkg/goDB/filter.go: -------------------------------------------------------------------------------- 1 | package goDB 2 | 3 | import ( 4 | "github.com/els0r/goProbe/v4/pkg/types/hashmap" 5 | ) 6 | 7 | // FilterFn denotes a function that filters an exisiting AggFlowMap and returns a new one 8 | // Note: In case of a null-op, the output map may be the same as the input map 9 | type FilterFn func(*hashmap.AggFlowMap) *hashmap.AggFlowMap 10 | 11 | // QueryFilter returns a FilterFn that applies a query condition to an existing AggFlowMap 12 | func QueryFilter(query *Query) FilterFn { 13 | return func(input *hashmap.AggFlowMap) (result *hashmap.AggFlowMap) { 14 | 15 | // If there is no condition, return the input map as is 16 | if query.Conditional == nil { 17 | return input 18 | } 19 | 20 | result = hashmap.NewAggFlowMap() 21 | 22 | // Loop over primary (IPv4) entries 23 | for it := input.PrimaryMap.Iter(); it.Next(); { 24 | if conditionalSatisfied := query.Conditional.Evaluate(it.Key()); conditionalSatisfied { 25 | result.PrimaryMap.SetOrUpdate(it.Key(), 26 | it.Val().BytesRcvd, 27 | it.Val().BytesSent, 28 | it.Val().PacketsRcvd, 29 | it.Val().PacketsSent, 30 | ) 31 | } 32 | } 33 | 34 | // Loop over primary (IPv6) entries 35 | for it := input.SecondaryMap.Iter(); it.Next(); { 36 | if conditionalSatisfied := query.Conditional.Evaluate(it.Key()); conditionalSatisfied { 37 | result.SecondaryMap.SetOrUpdate(it.Key(), 38 | it.Val().BytesRcvd, 39 | it.Val().BytesSent, 40 | it.Val().PacketsRcvd, 41 | it.Val().PacketsSent, 42 | ) 43 | } 44 | } 45 | 46 | return 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /pkg/goDB/info/hostid_default.go: -------------------------------------------------------------------------------- 1 | //go:build !linux 2 | // +build !linux 3 | 4 | package info 5 | 6 | import "errors" 7 | 8 | func hostID() (string, error) { 9 | return UnknownID, errors.New("not implemented") 10 | } 11 | -------------------------------------------------------------------------------- /pkg/goDB/info/hostid_linux.go: -------------------------------------------------------------------------------- 1 | //go:build linux 2 | // +build linux 3 | 4 | package info 5 | 6 | import ( 7 | "os" 8 | ) 9 | 10 | const ( 11 | machineIDPath = "/etc/machine-id" 12 | machineIDDBusPath = "/var/lib/dbus/machine-id" 13 | ) 14 | 15 | func hostID() (string, error) { 16 | 17 | // Attempt to read the machine ID from the main file 18 | idData, err := os.ReadFile(machineIDPath) 19 | if err != nil { 20 | 21 | // Fallback to DBus based file 22 | idData, err = os.ReadFile(machineIDDBusPath) 23 | if err != nil { 24 | return UnknownID, err 25 | } 26 | } 27 | 28 | return sanitizeHostID(idData), nil 29 | } 30 | -------------------------------------------------------------------------------- /pkg/goDB/info/info.go: -------------------------------------------------------------------------------- 1 | package info 2 | 3 | import ( 4 | "errors" 5 | "fmt" 6 | "io/fs" 7 | "os" 8 | ) 9 | 10 | // CheckDBExists will return nil if a DB at path exists and otherwise the error encountered 11 | func CheckDBExists(path string) error { 12 | if path == "" { 13 | return fmt.Errorf("empty DB path provided") 14 | } 15 | stat, err := os.Stat(path) 16 | if err != nil { 17 | if errors.Is(err, fs.ErrNotExist) { 18 | return fmt.Errorf("database directory does not exist: %w", err) 19 | } 20 | 21 | return fmt.Errorf("failed to check DB directory: %w", err) 22 | } 23 | 24 | if !stat.IsDir() { 25 | return fmt.Errorf("path %s is not a directory", path) 26 | } 27 | 28 | return nil 29 | } 30 | -------------------------------------------------------------------------------- /pkg/goDB/info/interfaces.go: -------------------------------------------------------------------------------- 1 | package info 2 | 3 | import ( 4 | "os" 5 | "sort" 6 | ) 7 | 8 | // GetInterfaces returns a list of interfaces covered by this goDB 9 | func GetInterfaces(dbPath string) ([]string, error) { 10 | dirents, err := os.ReadDir(dbPath) 11 | if err != nil { 12 | return nil, err 13 | } 14 | 15 | var ifaces []string 16 | for _, dirent := range dirents { 17 | if dirent.IsDir() { 18 | ifaces = append(ifaces, dirent.Name()) 19 | } 20 | } 21 | sort.SliceStable(ifaces, func(i, j int) bool { 22 | return ifaces[i] < ifaces[j] 23 | }) 24 | 25 | return ifaces, nil 26 | } 27 | -------------------------------------------------------------------------------- /pkg/goDB/metadata.go: -------------------------------------------------------------------------------- 1 | package goDB 2 | 3 | import ( 4 | "github.com/els0r/goProbe/v4/pkg/formatting" 5 | "github.com/els0r/goProbe/v4/pkg/goDB/storage/gpfile" 6 | "github.com/els0r/goProbe/v4/pkg/results" 7 | "github.com/els0r/goProbe/v4/pkg/types" 8 | ) 9 | 10 | // InterfaceMetadata describes the time range for which data is available, how many flows 11 | // were recorded and how much traffic was captured 12 | type InterfaceMetadata struct { 13 | Iface string `json:"iface"` 14 | results.TimeRange 15 | 16 | gpfile.Stats 17 | } 18 | 19 | // TableHeader constructs the table header for pretty printing metadata 20 | func (i *InterfaceMetadata) TableHeader(detailed bool) (headerRows [][]string) { 21 | r1 := []string{"iface"} 22 | fromTo := []string{"from", "to"} 23 | 24 | if detailed { 25 | r0 := []string{"", "packets", "packets", "bytes", "bytes", "# of", "# of", "", "", ""} 26 | r1 = append(r1, "in", "out", "in", "out", "IPv4 flows", "IPv6 flows", "drops") 27 | 28 | headerRows = append(headerRows, r0) 29 | } else { 30 | r1 = append(r1, "packets", "traffic", "flows") 31 | } 32 | 33 | r1 = append(r1, fromTo...) 34 | 35 | headerRows = append(headerRows, r1) 36 | return headerRows 37 | } 38 | 39 | // TableRow puts all attributes of the metadata into a row that can be used for table printing. 40 | // If detailed is false, the counts and metadata is summarized to their sum (e.g. IPv4 + IPv6 flows = NumFlows). 41 | // Drops are only printed in detail mode 42 | func (i *InterfaceMetadata) TableRow(detailed bool) []string { 43 | str := []string{i.Iface} 44 | fromTo := []string{i.First.Format(types.DefaultTimeOutputFormat), i.Last.Format(types.DefaultTimeOutputFormat)} 45 | if detailed { 46 | str = append(str, 47 | formatting.Count(i.Counts.PacketsRcvd), formatting.Count(i.Counts.PacketsSent), 48 | formatting.Size(i.Counts.BytesRcvd), formatting.Size(i.Counts.BytesSent), 49 | formatting.Count(i.Traffic.NumV4Entries), formatting.Count(i.Traffic.NumV6Entries), 50 | formatting.Count(i.Traffic.NumDrops), 51 | ) 52 | } else { 53 | str = append(str, 54 | formatting.Count(i.Counts.PacketsRcvd+i.Counts.PacketsSent), 55 | formatting.Size(i.Counts.BytesRcvd+i.Counts.BytesSent), 56 | formatting.Count(i.Traffic.NumFlows()), 57 | ) 58 | 59 | } 60 | str = append(str, fromTo...) 61 | return str 62 | } 63 | -------------------------------------------------------------------------------- /pkg/goDB/protocols/protocols.go: -------------------------------------------------------------------------------- 1 | /* 2 | Package protocols provides lookup functionality for IP protocol IDs and their names (which are 3 | in some cases OS specific) 4 | */ 5 | package protocols 6 | 7 | //go:generate go run protocols_generator.go 8 | 9 | // GetIPProto returns the friendly name for a given protocol id 10 | func GetIPProto(id int) string { 11 | return IPProtocols[id] 12 | } 13 | 14 | // GetIPProtoID returns the numeric value for a given IP protocol 15 | func GetIPProtoID(name string) (uint64, bool) { 16 | ret, ok := IPProtocolIDs[name] 17 | return uint64(ret), ok 18 | } 19 | -------------------------------------------------------------------------------- /pkg/goDB/storage/gpfile/options.go: -------------------------------------------------------------------------------- 1 | package gpfile 2 | 3 | import ( 4 | "io/fs" 5 | 6 | "github.com/els0r/goProbe/v4/pkg/goDB/encoder" 7 | "github.com/els0r/goProbe/v4/pkg/goDB/encoder/encoders" 8 | "github.com/fako1024/gotools/concurrency" 9 | ) 10 | 11 | // Option defines optional arguments to gpfile 12 | type Option func(any) 13 | 14 | // optionSetterCommon denotes options that apply to both GPDir and GPFile 15 | type optionSetterCommon interface { 16 | setPermissions(fs.FileMode) 17 | } 18 | 19 | // optionSetterFile denotes options that apply to GPFile only 20 | type optionSetterFile interface { 21 | optionSetterCommon 22 | setMemPool(concurrency.MemPoolGCable) 23 | setEncoder(encoder.Encoder) 24 | setEncoderTypeLevel(encoders.Type, int) 25 | } 26 | 27 | // WithEncoder allows to set the compression implementation 28 | func WithEncoder(e encoder.Encoder) Option { 29 | return func(o any) { 30 | if obj, ok := o.(optionSetterFile); ok { 31 | obj.setEncoder(e) 32 | } 33 | } 34 | } 35 | 36 | // WithEncoderTypeLevel allows to set the compression type and level 37 | func WithEncoderTypeLevel(t encoders.Type, l int) Option { 38 | return func(o any) { 39 | if obj, ok := o.(optionSetterFile); ok { 40 | obj.setEncoderTypeLevel(t, l) 41 | } 42 | } 43 | } 44 | 45 | // WithReadAll triggers a full read of the underlying file from disk 46 | // upon first read access to minimize I/O load. 47 | // Seeking is handled by replacing the underlying file with a seekable 48 | // in-memory structure (c.f. readWriteSeekCloser interface) 49 | func WithReadAll(pool concurrency.MemPoolGCable) Option { 50 | return func(o any) { 51 | if obj, ok := o.(optionSetterFile); ok { 52 | obj.setMemPool(pool) 53 | } 54 | } 55 | } 56 | 57 | // WithPermissions sets a non-default set of permissions / file mode for 58 | // the file 59 | func WithPermissions(permissions fs.FileMode) Option { 60 | return func(o any) { 61 | if obj, ok := o.(optionSetterCommon); ok { 62 | obj.setPermissions(permissions) 63 | } 64 | } 65 | } 66 | -------------------------------------------------------------------------------- /pkg/goprobe/writeout/handler.go: -------------------------------------------------------------------------------- 1 | package writeout 2 | 3 | import ( 4 | "context" 5 | "time" 6 | 7 | "github.com/els0r/goProbe/v4/pkg/capture/capturetypes" 8 | ) 9 | 10 | // WriteoutsChanDepth defines a default depth for sending writeouts over the writeout channel 11 | const WriteoutsChanDepth = 100 12 | 13 | // Handler defines a generic interface for handling writeouts 14 | type Handler interface { 15 | 16 | // HandleWriteout provides access to writeouts via a channel 17 | HandleWriteout(ctx context.Context, timestamp time.Time, writeoutChan <-chan capturetypes.TaggedAggFlowMap) <-chan struct{} 18 | } 19 | -------------------------------------------------------------------------------- /pkg/goprobe/writeout/metrics.go: -------------------------------------------------------------------------------- 1 | package writeout 2 | 3 | import ( 4 | "github.com/els0r/goProbe/v4/cmd/goProbe/config" 5 | "github.com/prometheus/client_golang/prometheus" 6 | ) 7 | 8 | const ( 9 | writeoutSubsystem = "godb_handler" 10 | ) 11 | 12 | var writeoutDuration = prometheus.NewHistogram(prometheus.HistogramOpts{ 13 | Namespace: config.ServiceName, 14 | Subsystem: writeoutSubsystem, 15 | Name: "writeout_duration_seconds", 16 | Help: "Total flow data writeout time, aggregated across all interfaces written to DB", 17 | // these buckets should capture disks of various speed and setups with many interfaces 18 | Buckets: []float64{0.025, 0.05, 0.1, 0.25, 0.5, 1, 5, 10, 30, 60}, 19 | }) 20 | 21 | func init() { 22 | prometheus.MustRegister( 23 | writeoutDuration, 24 | ) 25 | } 26 | -------------------------------------------------------------------------------- /pkg/query/README.md: -------------------------------------------------------------------------------- 1 | # goDB Query API 2 | 3 | This package exposes methods to query the data stored in goDB. 4 | 5 | ## Example 6 | 7 | To access the data captured by goProbe (stored at the default location) from your own application, you can use the following to get started: 8 | 9 | ```golang 10 | func main() { 11 | // set query output(s) redirection (default is os.Stdout). You can use multiple io.Writers here 12 | ctx := context.Background() 13 | outputs := os.Stderr 14 | 15 | args := query.NewArgs("sip,dip", "eth0", 16 | query.WithSortAscending(), 17 | query.WithCondition("dport eq 443"), 18 | ) 19 | 20 | // prepare the statement (e.g. parse args and setup query parameters). 21 | // This example assumes that you are querying against goDB 22 | stmt, err := args.Prepare(output) 23 | if err != nil { 24 | fmt.Fprintf(os.Stderr, "couldn't prepare statement: %s\n", err) 25 | os.Exit(1) 26 | } 27 | 28 | // execute statement 29 | err = engine.NewQueryRunner().Run(ctx, stmt) 30 | if err != nil { 31 | fmt.Fprintf(os.Stderr, "query failed: %s\n", err) 32 | os.Exit(1) 33 | } 34 | } 35 | ``` 36 | 37 | For a more complete overview, please consult the documentation. 38 | -------------------------------------------------------------------------------- /pkg/query/defaults.go: -------------------------------------------------------------------------------- 1 | package query 2 | 3 | import ( 4 | "sort" 5 | "time" 6 | 7 | "github.com/els0r/goProbe/v4/pkg/defaults" 8 | "github.com/els0r/goProbe/v4/pkg/results" 9 | "github.com/els0r/goProbe/v4/pkg/types" 10 | ) 11 | 12 | // Defaults for query arguments 13 | var ( 14 | DefaultDBPath = defaults.DBPath 15 | DefaultFormat = types.FormatTXT 16 | DefaultMaxMemPct = 60 17 | DefaultNumResults = uint64(1000) 18 | DefaultResolveRows = 25 19 | DefaultResolveTimeout = 1 * time.Second 20 | DefaultQueryTimeout = defaults.QueryTimeout 21 | DefaultSortBy = "bytes" 22 | ) 23 | 24 | // PermittedFormats stores all supported output formats 25 | var permittedFormats = map[string]struct{}{ 26 | types.FormatTXT: {}, 27 | types.FormatJSON: {}, 28 | types.FormatCSV: {}, 29 | } 30 | 31 | var ( 32 | permittedFormatsSlice = []string{} 33 | permittedSortBySlice = []string{} 34 | ) 35 | 36 | func init() { 37 | for format := range permittedFormats { 38 | permittedFormatsSlice = append(permittedFormatsSlice, format) 39 | } 40 | sort.StringSlice(permittedFormatsSlice).Sort() 41 | 42 | for sortBy := range permittedSortBy { 43 | permittedSortBySlice = append(permittedSortBySlice, sortBy) 44 | } 45 | sort.StringSlice(permittedSortBySlice).Sort() 46 | } 47 | 48 | // PermittedFormats list which formats are supported 49 | func PermittedFormats() []string { 50 | return permittedFormatsSlice 51 | } 52 | 53 | // PermittedSortBy sorts all permitted sorting orders 54 | var permittedSortBy = map[string]results.SortOrder{ 55 | "bytes": results.SortTraffic, 56 | "packets": results.SortPackets, 57 | "time": results.SortTime, 58 | } 59 | 60 | // PermittedSortBy lists which sort by methods are supported 61 | func PermittedSortBy() []string { 62 | return permittedSortBySlice 63 | } 64 | -------------------------------------------------------------------------------- /pkg/query/defaults_darwin.go: -------------------------------------------------------------------------------- 1 | //go:build darwin 2 | // +build darwin 3 | 4 | package query 5 | 6 | // MaxResults stores the maximum number of rows a query will return. This limit is more or less 7 | // theoretical, since a DB will unlikley feature such an amount of entries 8 | const MaxResults = 9999999999999999 9 | -------------------------------------------------------------------------------- /pkg/query/defaults_linux.go: -------------------------------------------------------------------------------- 1 | // +build !arm 2 | 3 | package query 4 | 5 | // MaxResults stores the maximum number of rows a query will return. This limit is more or less 6 | // theoretical, since a DB will unlikley feature such an amount of entries 7 | const MaxResults = 9999999999999999 8 | -------------------------------------------------------------------------------- /pkg/query/defaults_linux_arm.go: -------------------------------------------------------------------------------- 1 | // +build arm 2 | 3 | package query 4 | 5 | // MaxResults stores the maximum number of rows a query will return. This limit is more or less 6 | // theoretical, since a DB will unlikley feature such an amount of entries 7 | const MaxResults = 1000000 8 | -------------------------------------------------------------------------------- /pkg/query/dns/dns_public.go: -------------------------------------------------------------------------------- 1 | ///////////////////////////////////////////////////////////////////////////////// 2 | // 3 | // dns_public.go 4 | // 5 | // Written by Lorenz Breidenbach lob@open.ch, October 2015 6 | // Copyright (c) 2015 Open Systems AG, Switzerland 7 | // All Rights Reserved. 8 | // 9 | ///////////////////////////////////////////////////////////////////////////////// 10 | 11 | // +build !OSAG 12 | 13 | package dns 14 | 15 | // CheckDNS is a no-op to check if a DNS resolver is present (deployment enviornment specific) 16 | func CheckDNS() error { 17 | return nil 18 | } 19 | -------------------------------------------------------------------------------- /pkg/query/dns/dns_test.go: -------------------------------------------------------------------------------- 1 | ///////////////////////////////////////////////////////////////////////////////// 2 | // 3 | // dns_test.go 4 | // 5 | // Written by Lorenz Breidenbach lob@open.ch, August 2015 6 | // Copyright (c) 2015 Open Systems AG, Switzerland 7 | // All Rights Reserved. 8 | // 9 | ///////////////////////////////////////////////////////////////////////////////// 10 | 11 | package dns 12 | 13 | import ( 14 | "context" 15 | "os" 16 | "testing" 17 | "time" 18 | ) 19 | 20 | func skipInCI(t *testing.T) { 21 | if os.Getenv("CI") == "true" { 22 | t.Skipf("skipping DNS tests in CI/CD mode") 23 | } 24 | } 25 | 26 | func TestLookup(t *testing.T) { 27 | skipInCI(t) 28 | t.Parallel() 29 | 30 | // 8.8.8.8 is google's DNS server. This lookup should yield the same 31 | // result for many years. 32 | ips2domains := TimedReverseLookup(context.Background(), []string{"8.8.8.8", "0.0.0.0"}, 2*time.Second) 33 | if domain, ok := ips2domains["8.8.8.8"]; ok && domain != "dns.google." { 34 | t.Fatalf("RDNS lookup yielded wrong result: %s", domain) 35 | } else if !ok { 36 | t.Log("RDNS lookup yielded no result. Perhaps your internet is down?") 37 | t.Skip() 38 | } 39 | 40 | if _, ok := ips2domains["0.0.0.0"]; ok { 41 | t.Fatalf("RDNS unexpectedly succeeded on 0.0.0.0.") 42 | } 43 | } 44 | 45 | func TestTimeout(t *testing.T) { 46 | skipInCI(t) 47 | t.Parallel() 48 | 49 | t0 := time.Now() 50 | _ = TimedReverseLookup(context.Background(), []string{"8.8.8.8", "8.8.4.4", "192.168.0.1", "10.0.0.1", "129.3.4.5"}, 1*time.Millisecond) 51 | t1 := time.Now() 52 | if t1.Sub(t0) > 10*time.Millisecond { 53 | t.Fatal("Timeout failed") 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /pkg/query/doc.go: -------------------------------------------------------------------------------- 1 | // Package query supplies the API for running queries on a goDB database 2 | package query 3 | -------------------------------------------------------------------------------- /pkg/query/heap/heap.go: -------------------------------------------------------------------------------- 1 | package heap 2 | 3 | import ( 4 | "context" 5 | "errors" 6 | "fmt" 7 | "runtime" 8 | "runtime/debug" 9 | "time" 10 | ) 11 | 12 | // Parameters for checking memory consumption of query 13 | const ( 14 | 15 | // MemCheckInterval denotes the frequency at which the memory consumption is checked 16 | MemCheckInterval = 1 * time.Second 17 | 18 | // Variables for manual garbage collection calls 19 | goGCInterval = 5 * time.Second 20 | goGCLimit = 6291456 // Limit for GC call, in bytes 21 | ) 22 | 23 | var ( 24 | 25 | // ErrorMemoryBreach denotes that the provided / requested maximum memory usage has been exceeded 26 | ErrorMemoryBreach = errors.New("maximum memory breach") 27 | ) 28 | 29 | // Watch makes sure to alert on too high memory consumption 30 | func Watch(ctx context.Context, maxAllowedMemPct int) (errors chan error) { 31 | errors = make(chan error) 32 | go func() { 33 | // obtain physical memory of this host 34 | var ( 35 | physMem float64 36 | err error 37 | ) 38 | 39 | physMem, err = getPhysMem() 40 | if err != nil { 41 | errors <- err 42 | return 43 | } 44 | 45 | // Create global MemStats object for tracking of memory consumption 46 | memTicker := time.NewTicker(MemCheckInterval) 47 | m := runtime.MemStats{} 48 | lastGC := time.Now() 49 | 50 | for { 51 | select { 52 | case <-memTicker.C: 53 | runtime.ReadMemStats(&m) 54 | 55 | usedMem := m.Sys - m.HeapReleased 56 | maxAllowedMem := uint64(float64(maxAllowedMemPct) * physMem / 100) 57 | 58 | // Check if current memory consumption is higher than maximum allowed percentage of the available 59 | // physical memory 60 | if usedMem/1024 > maxAllowedMem { 61 | memTicker.Stop() 62 | errors <- fmt.Errorf("%w: %v%% of physical memory", ErrorMemoryBreach, maxAllowedMemPct) 63 | return 64 | } 65 | 66 | // Conditionally call a manual garbage collection and memory release if the current heap allocation 67 | // is above goGCLimit and more than goGCInterval seconds have passed 68 | if usedMem > goGCLimit && time.Since(lastGC) > goGCInterval { 69 | runtime.GC() 70 | debug.FreeOSMemory() 71 | lastGC = time.Now() 72 | } 73 | case <-ctx.Done(): 74 | memTicker.Stop() 75 | return 76 | } 77 | } 78 | }() 79 | return errors 80 | } 81 | -------------------------------------------------------------------------------- /pkg/query/heap/meminfo_darwin.go: -------------------------------------------------------------------------------- 1 | //go:build darwin 2 | // +build darwin 3 | 4 | package heap 5 | 6 | const gb = 1204 * 1024 * 1024 7 | 8 | func getPhysMem() (float64, error) { 9 | // TODO: proper way to extract the available physical memory 10 | // Defaulting to 4 GB to say on the safe side 11 | var physMem = float64(4 * gb) 12 | 13 | return physMem, nil 14 | } 15 | -------------------------------------------------------------------------------- /pkg/query/heap/meminfo_linux.go: -------------------------------------------------------------------------------- 1 | //go:build linux 2 | // +build linux 3 | 4 | package heap 5 | 6 | import ( 7 | "bufio" 8 | "fmt" 9 | "os" 10 | "strconv" 11 | "strings" 12 | ) 13 | 14 | const memFilePath = "/proc/meminfo" 15 | 16 | func getPhysMem() (float64, error) { 17 | var memFile *os.File 18 | var ferr error 19 | if memFile, ferr = os.OpenFile(memFilePath, os.O_RDONLY, 0600); ferr != nil { 20 | return 0.0, fmt.Errorf("unable to open %s: %w", memFilePath, ferr) 21 | } 22 | 23 | physMem := 0.0 24 | memInfoScanner := bufio.NewScanner(memFile) 25 | for memInfoScanner.Scan() { 26 | if strings.Contains(memInfoScanner.Text(), "MemTotal") { 27 | memTokens := strings.Split(memInfoScanner.Text(), " ") 28 | physMem, _ = strconv.ParseFloat(memTokens[len(memTokens)-2], 64) 29 | } 30 | } 31 | 32 | if physMem < 0.1 { 33 | return 0.0, fmt.Errorf("unable to obtain amount of physical memory from %s", memFilePath) 34 | } 35 | 36 | if ferr = memFile.Close(); ferr != nil { 37 | return 0.0, fmt.Errorf("unable to close %s after reading: %w", memFilePath, ferr) 38 | } 39 | 40 | return physMem, nil 41 | } 42 | -------------------------------------------------------------------------------- /pkg/query/runner.go: -------------------------------------------------------------------------------- 1 | package query 2 | 3 | import ( 4 | "context" 5 | 6 | "github.com/els0r/goProbe/v4/pkg/results" 7 | ) 8 | 9 | // Runner specifies the functionality a query runner must provide 10 | type Runner interface { 11 | 12 | // Run takes a query statement, executes the underlying query and returns the result(s) 13 | Run(ctx context.Context, args *Args) (*results.Result, error) 14 | } 15 | -------------------------------------------------------------------------------- /pkg/query/time_test.go: -------------------------------------------------------------------------------- 1 | package query 2 | 3 | import ( 4 | "fmt" 5 | "testing" 6 | 7 | "github.com/els0r/goProbe/v4/pkg/types" 8 | "github.com/stretchr/testify/assert" 9 | ) 10 | 11 | func TestParseTimestamp(t *testing.T) { 12 | var tests = []TimeFormat{ 13 | // special cases 14 | {"", "-100000d"}, 15 | {"", "-100000h"}, 16 | {"", "-100000m"}, 17 | {"", "-100000s"}, 18 | {"", "-23d:4h:3m"}, 19 | {"", "-23d:4h:8m:3s"}, 20 | {"", "-23d4h8m3s"}, 21 | {"", "1674492267"}, 22 | {"", "2006-01-02T15:04:05-07:00"}, // RFC3339 test 23 | {"", "Mon Jan 23 11:31:04 2023"}, // ANSIC test 24 | {"", fmt.Sprintf("%d", types.MaxTime.Unix())}, // Maximum supported time 25 | } 26 | tests = append(tests, append(timeFormatsDefault, timeFormatsCustom...)[2:]...) 27 | 28 | for _, tFormat := range tests { 29 | t.Run(tFormat.Format, func(t *testing.T) { 30 | tstamp, err := ParseTimeArgument(tFormat.Format) 31 | 32 | assert.Nil(t, err, "unexpected error: %v", err) 33 | assert.NotEqual(t, tstamp, 0, "expected non-zero timestamp") 34 | }) 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /pkg/results/print.go: -------------------------------------------------------------------------------- 1 | package results 2 | 3 | import ( 4 | "fmt" 5 | "io" 6 | "text/tabwriter" 7 | "time" 8 | 9 | "github.com/els0r/goProbe/v4/pkg/formatting" 10 | "github.com/els0r/goProbe/v4/pkg/types" 11 | ) 12 | 13 | // FooterTabwriter is a specific tabwriter for the results footer 14 | type FooterTabwriter struct { 15 | *tabwriter.Writer 16 | } 17 | 18 | // NewFooterTabwriter returns a new FooterTabwriter 19 | func NewFooterTabwriter(w io.Writer) *FooterTabwriter { 20 | return &FooterTabwriter{ 21 | tabwriter.NewWriter(w, 0, 4, 1, ' ', 0), 22 | } 23 | } 24 | 25 | // WriteEntry writes a new entry to the footer 26 | func (fw *FooterTabwriter) WriteEntry(key, msg string, args ...any) error { 27 | _, err := fmt.Fprintf(fw.Writer, key+"\t: "+msg+"\n", args...) 28 | return err 29 | } 30 | 31 | // Flush flushes the footer writer 32 | func (fw *FooterTabwriter) Flush() error { 33 | return fw.Writer.Flush() 34 | } 35 | 36 | // FooterPrinter allows a type to print to the Footer 37 | type FooterPrinter interface { 38 | PrintFooter(fw *FooterTabwriter) error 39 | } 40 | 41 | /// FooterPrinter implementations 42 | 43 | // PrintFooter prints the timespan and duration covered 44 | func (tr TimeRange) PrintFooter(fw *FooterTabwriter) error { 45 | return fw.WriteEntry("Timespan", "[%s, %s] (%s)", 46 | tr.First.Format(types.DefaultTimeOutputFormat), 47 | tr.Last.Format(types.DefaultTimeOutputFormat), 48 | formatting.Durationable(tr.Last.Sub(tr.First).Round(time.Minute)), 49 | ) 50 | } 51 | 52 | // PrintFooter prints the conditions of the query in case they are available 53 | func (q Query) PrintFooter(fw *FooterTabwriter) error { 54 | if q.Condition == "" { 55 | return nil 56 | } 57 | return fw.WriteEntry("Conditions", q.Condition) 58 | } 59 | 60 | // PrintFooter prints the queried hosts summary (total, ok, empty, error) 61 | func (hs HostsStatuses) PrintFooter(fw *FooterTabwriter) error { 62 | return fw.WriteEntry("Hosts", hs.Summary()) 63 | } 64 | -------------------------------------------------------------------------------- /pkg/results/result_test.go: -------------------------------------------------------------------------------- 1 | package results 2 | 3 | import ( 4 | "fmt" 5 | "testing" 6 | 7 | "github.com/els0r/goProbe/v4/pkg/types" 8 | jsoniter "github.com/json-iterator/go" 9 | "github.com/stretchr/testify/assert" 10 | ) 11 | 12 | func TestMerge(t *testing.T) { 13 | 14 | // t0 := time.Now() 15 | 16 | var tests = []struct { 17 | inMap RowsMap 18 | input Rows 19 | expected Rows 20 | }{} 21 | 22 | for i, test := range tests { 23 | t.Run(fmt.Sprint(i), func(t *testing.T) { 24 | test.inMap.MergeRows(test.input) 25 | 26 | out := test.inMap.ToRowsSorted(By(SortTime, types.DirectionBoth, true)) 27 | 28 | assert.Equal(t, test.expected, out) 29 | 30 | b, _ := jsoniter.MarshalIndent(out, "", " ") 31 | fmt.Println(string(b)) 32 | }) 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /pkg/types/direction.go: -------------------------------------------------------------------------------- 1 | package types 2 | 3 | import jsoniter "github.com/json-iterator/go" 4 | 5 | // Direction indicates the counters of which flow direction we should print. 6 | type Direction int 7 | 8 | // Enumeration of directions to be considered 9 | const ( 10 | DirectionUnknown Direction = iota 11 | DirectionSum // sum of inbound and outbound counters 12 | DirectionIn // inbound counters 13 | DirectionOut // outbound counters 14 | DirectionBoth // inbound and outbound counters 15 | ) 16 | 17 | // String implement human-readable printing of the direction 18 | func (d Direction) String() string { 19 | switch d { 20 | case DirectionSum: 21 | return "sum" 22 | case DirectionIn: 23 | return "in" 24 | case DirectionOut: 25 | return "out" 26 | case DirectionBoth: 27 | return "bi-directional" 28 | } 29 | return "unknown" 30 | } 31 | 32 | // DirectionFromString maps a string to a Direction 33 | func DirectionFromString(s string) Direction { 34 | switch s { 35 | case "sum": 36 | return DirectionSum 37 | case "in": 38 | return DirectionIn 39 | case "out": 40 | return DirectionOut 41 | case "bi-directional": 42 | return DirectionOut 43 | } 44 | return DirectionUnknown 45 | } 46 | 47 | // MarshalJSON implements the Marshaler interface for sort order 48 | func (d *Direction) MarshalJSON() ([]byte, error) { 49 | return jsoniter.Marshal(d.String()) 50 | } 51 | 52 | // UnmarshalJSON implements the Unmarshaler interface 53 | func (d *Direction) UnmarshalJSON(b []byte) error { 54 | var str string 55 | err := jsoniter.Unmarshal(b, &str) 56 | if err != nil { 57 | return err 58 | } 59 | *d = DirectionFromString(str) 60 | return nil 61 | } 62 | -------------------------------------------------------------------------------- /pkg/types/hashmap/LICENSE: -------------------------------------------------------------------------------- 1 | Original from https://github.com/golang/go/blob/master/LICENSE 2 | 3 | Copyright (c) 2009 The Go Authors. All rights reserved. 4 | 5 | Redistribution and use in source and binary forms, with or without 6 | modification, are permitted provided that the following conditions are 7 | met: 8 | 9 | * Redistributions of source code must retain the above copyright 10 | notice, this list of conditions and the following disclaimer. 11 | * Redistributions in binary form must reproduce the above 12 | copyright notice, this list of conditions and the following disclaimer 13 | in the documentation and/or other materials provided with the 14 | distribution. 15 | * Neither the name of Google Inc. nor the names of its 16 | contributors may be used to endorse or promote products derived from 17 | this software without specific prior written permission. 18 | 19 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 20 | "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 21 | LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 22 | A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 23 | OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 24 | SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 25 | LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 26 | DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 27 | THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 28 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 29 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -------------------------------------------------------------------------------- /pkg/types/hashmap/PATENTS: -------------------------------------------------------------------------------- 1 | Original from https://github.com/golang/go/blob/master/PATENTS: 2 | 3 | Additional IP Rights Grant (Patents) 4 | 5 | "This implementation" means the copyrightable works distributed by 6 | Google as part of the Go project. 7 | 8 | Google hereby grants to You a perpetual, worldwide, non-exclusive, 9 | no-charge, royalty-free, irrevocable (except as stated in this section) 10 | patent license to make, have made, use, offer to sell, sell, import, 11 | transfer and otherwise run, modify and propagate the contents of this 12 | implementation of Go, where such license applies only to those patent 13 | claims, both currently owned or controlled by Google and acquired in 14 | the future, licensable by Google that are necessarily infringed by this 15 | implementation of Go. This grant does not include claims that would be 16 | infringed only as a consequence of further modification of this 17 | implementation. If you or your agent or exclusive licensee institute or 18 | order or agree to the institution of patent litigation against any 19 | entity (including a cross-claim or counterclaim in a lawsuit) alleging 20 | that this implementation of Go or any code incorporated within this 21 | implementation of Go constitutes direct or contributory patent 22 | infringement, or inducement of patent infringement, then any patent 23 | rights granted to you under this License for this implementation of Go 24 | shall terminate as of the date such litigation is filed. -------------------------------------------------------------------------------- /pkg/types/hashmap/list.go: -------------------------------------------------------------------------------- 1 | package hashmap 2 | 3 | import ( 4 | "bytes" 5 | "sort" 6 | 7 | "github.com/els0r/goProbe/v4/pkg/types" 8 | ) 9 | 10 | // Item denotes a flat key / value pair 11 | type Item struct { 12 | types.Key 13 | Val 14 | } 15 | 16 | // List denotes a list of key / value pairs 17 | type List []Item 18 | 19 | // Flatten converts a flow map to a flat table / list 20 | func (a *AggFlowMap) Flatten() (primaryList List, secondaryList List) { 21 | if a == nil { 22 | return 23 | } 24 | 25 | primaryList, secondaryList = make(List, a.PrimaryMap.Len()), make(List, a.SecondaryMap.Len()) 26 | 27 | for j, it := 0, a.PrimaryMap.Iter(); it.Next(); j++ { 28 | primaryList[j] = Item{it.Key(), it.Val()} 29 | } 30 | for j, it := 0, a.SecondaryMap.Iter(); it.Next(); j++ { 31 | secondaryList[j] = Item{it.Key(), it.Val()} 32 | } 33 | 34 | return 35 | } 36 | 37 | // Sort orders relevant flow columns so that they become more compressible 38 | func (l List) Sort() List { 39 | sort.Slice(l, func(i, j int) bool { 40 | 41 | iv, jv := l[i], l[j] 42 | 43 | if comp := bytes.Compare(iv.GetSIP(), jv.GetSIP()); comp != 0 { 44 | return comp < 0 45 | } 46 | if comp := bytes.Compare(iv.GetDIP(), jv.GetDIP()); comp != 0 { 47 | return comp < 0 48 | } 49 | if comp := bytes.Compare(iv.GetDport(), jv.GetDport()); comp != 0 { 50 | return comp < 0 51 | } 52 | if iv.GetProto() != jv.GetProto() { 53 | return iv.GetProto() < jv.GetProto() 54 | } 55 | 56 | return false 57 | }) 58 | 59 | return l 60 | } 61 | -------------------------------------------------------------------------------- /pkg/types/iface.go: -------------------------------------------------------------------------------- 1 | package types 2 | 3 | import ( 4 | "errors" 5 | "fmt" 6 | "regexp" 7 | "strings" 8 | ) 9 | 10 | var ifaceNameRegexp = regexp.MustCompile(`^!?[a-zA-Z0-9\.:_-]{1,15}$`) 11 | 12 | const ifaceListDelimiter = "," 13 | 14 | func ValidateIfaceName(iface string) error { 15 | if iface == "" { 16 | return errors.New("interface list contains empty interface name") 17 | } 18 | 19 | if !ifaceNameRegexp.MatchString(iface) { 20 | return fmt.Errorf("interface name `%s` is invalid", iface) 21 | } 22 | 23 | return nil 24 | } 25 | 26 | // This function is used to validate the input and to jugde if interfaces should 27 | // be displayed in output table 28 | func ValidateIfaceArgument(ifaceArgument string) ([]string, error) { 29 | if IsIfaceArgumentRegExp(ifaceArgument) { 30 | _, err := ValidateRegExp(ifaceArgument) 31 | return []string{ifaceArgument}, err 32 | } 33 | ifaces := strings.Split(ifaceArgument, ifaceListDelimiter) 34 | for _, iface := range ifaces { 35 | if err := ValidateIfaceName(iface); err != nil { 36 | return ifaces, err 37 | } 38 | } 39 | return ifaces, nil 40 | } 41 | 42 | const regExpSeparator = "/" 43 | 44 | func IsIfaceArgumentRegExp(iface string) bool { 45 | return strings.HasPrefix(iface, regExpSeparator) && strings.HasSuffix(iface, regExpSeparator) && len(iface) > 2 46 | } 47 | 48 | func ValidateAndSeparateFilters(ifaceList string) ([]string, []string, error) { 49 | ifaces := strings.Split(ifaceList, ifaceListDelimiter) 50 | var positive, negative []string 51 | for _, iface := range ifaces { 52 | if err := ValidateIfaceName(iface); err != nil { 53 | return nil, nil, err 54 | } 55 | if strings.HasPrefix(iface, "!") { 56 | negative = append(negative, iface[1:]) 57 | } else { 58 | positive = append(positive, iface) 59 | } 60 | } 61 | return positive, negative, nil 62 | } 63 | 64 | func ValidateRegExp(regExp string) (*regexp.Regexp, error) { 65 | if regExp == "" { 66 | return nil, errors.New("interface regexp is empty") 67 | } 68 | return regexp.Compile(regExp) 69 | } 70 | 71 | func ValidateAndExtractRegExp(regExp string) (*regexp.Regexp, error) { 72 | if regExp == "" { 73 | return nil, errors.New("interface regexp is empty") 74 | } 75 | // regexp to extract regular expression between the forward slashes 76 | re := regexp.MustCompile(`^/(.*?)/$`) 77 | 78 | // Find the match 79 | match := re.FindStringSubmatch(regExp) 80 | 81 | if len(match) > 1 { 82 | return regexp.Compile(match[1]) 83 | } 84 | return nil, fmt.Errorf("unexpected match count on regexp %s", regExp) 85 | } 86 | -------------------------------------------------------------------------------- /pkg/types/interface_lister.go: -------------------------------------------------------------------------------- 1 | package types 2 | 3 | type InterfaceLister interface { 4 | ListInterfaces() ([]string, error) 5 | } 6 | -------------------------------------------------------------------------------- /pkg/types/shellformat/shellformat.go: -------------------------------------------------------------------------------- 1 | package shellformat 2 | 3 | import ( 4 | "fmt" 5 | "os" 6 | 7 | "golang.org/x/sys/unix" 8 | ) 9 | 10 | // EscapeSeq denotes a simple formatting modifier / escape sequence for shell output 11 | type EscapeSeq = string 12 | 13 | var isNoColorTerm = os.Getenv("TERM") == "dumb" || !isTerminal(os.Stdout.Fd()) 14 | 15 | // Some standard modifiers 16 | var ( 17 | EscapeSeqReset EscapeSeq = "\033[0m" 18 | EscapeSeqBold EscapeSeq = "\033[1m" 19 | EscapeSeqBlack EscapeSeq = "\033[30m" 20 | EscapeSeqRed EscapeSeq = "\033[31m" 21 | EscapeSeqGreen EscapeSeq = "\033[32m" 22 | EscapeSeqYellow EscapeSeq = "\033[33m" 23 | EscapeSeqBlue EscapeSeq = "\033[34m" 24 | EscapeSeqPurple EscapeSeq = "\033[35m" 25 | EscapeSeqCyan EscapeSeq = "\033[36m" 26 | EscapeSeqGray EscapeSeq = "\033[37m" 27 | EscapeSeqWhite EscapeSeq = "\033[97m" 28 | ) 29 | 30 | // Format denotes an abstract format for shell output 31 | type Format uint64 32 | 33 | // Formatting codes suitable for logical combination via '|' 34 | const ( 35 | Bold Format = 1 << 1 36 | Black Format = 1 << 2 37 | Red Format = 1 << 3 38 | Green Format = 1 << 4 39 | Yellow Format = 1 << 5 40 | Blue Format = 1 << 6 41 | Purple Format = 1 << 7 42 | Cyan Format = 1 << 8 43 | Gray Format = 1 << 9 44 | White Format = 1 << 10 45 | 46 | maxFormat = White 47 | ) 48 | 49 | var allFormats = []EscapeSeq{ 50 | "", 51 | EscapeSeqBold, 52 | EscapeSeqBlack, 53 | EscapeSeqRed, 54 | EscapeSeqGreen, 55 | EscapeSeqYellow, 56 | EscapeSeqBlue, 57 | EscapeSeqPurple, 58 | EscapeSeqCyan, 59 | EscapeSeqGray, 60 | EscapeSeqWhite, 61 | } 62 | 63 | // Fmt modifies the provided string using the list of modifiers 64 | // and resets the output formatting to default at the end 65 | func Fmt(format Format, input string, a ...any) string { 66 | 67 | if isNoColorTerm { 68 | return fmt.Sprintf(input, a...) 69 | } 70 | 71 | seq := format.genEscapeSeq() 72 | if seq == "" { 73 | return fmt.Sprintf(input, a...) 74 | } 75 | 76 | return fmt.Sprintf(seq+input+EscapeSeqReset, a...) 77 | } 78 | 79 | func (f Format) genEscapeSeq() (seq string) { 80 | for i := 1; i <= int(maxFormat); i++ { 81 | if f&(1< Third-party contributions for the goProbe software suite 4 | 5 | See [github.com/els0r/goProbe-contrib](https://github.com/els0r/goProbe-contrib) for how to contribute. 6 | -------------------------------------------------------------------------------- /plugins/contrib/contrib.go: -------------------------------------------------------------------------------- 1 | package contrib 2 | -------------------------------------------------------------------------------- /plugins/contrib/contrib_gen.go: -------------------------------------------------------------------------------- 1 | //go:build goprobe_contrib 2 | 3 | package contrib 4 | 5 | //go:generate go run gen.go 6 | -------------------------------------------------------------------------------- /plugins/contrib/gen.go: -------------------------------------------------------------------------------- 1 | //go:build ignore && goprobe_contrib 2 | 3 | package main 4 | 5 | import ( 6 | "os" 7 | ) 8 | 9 | const contribImport = `//go:build goprobe_contrib 10 | 11 | // Code generated by gen.go - DO NOT EDIT. 12 | package contrib 13 | 14 | // enumerates the plugin list 15 | import _ "github.com/els0r/goProbe-contrib" 16 | ` 17 | 18 | func main() { 19 | os.WriteFile("contrib_generated.go", []byte(contribImport), 0644) 20 | } 21 | -------------------------------------------------------------------------------- /plugins/contrib/go.mod: -------------------------------------------------------------------------------- 1 | module github.com/els0r/goProbe/plugins/contrib/v4 2 | 3 | go 1.23.1 4 | -------------------------------------------------------------------------------- /plugins/contrib/go.sum: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/els0r/goProbe/7eed90f04ea0ba38aeaaa9e22ae8a6b7aac7d6f9/plugins/contrib/go.sum -------------------------------------------------------------------------------- /plugins/querier/init.go: -------------------------------------------------------------------------------- 1 | package querier 2 | 3 | // enumerates the default querier plugin list 4 | import ( 5 | _ "github.com/els0r/goProbe/v4/plugins/querier/apiclient" 6 | ) 7 | -------------------------------------------------------------------------------- /presentations/2025/goprobe_bern_meetup/.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | dist 3 | .site 4 | .vercel 5 | 6 | # misc 7 | .idea 8 | .DS_Store 9 | npm-debug.log* 10 | yarn-error.log 11 | 12 | # use pnpm-lock 13 | yarn.lock 14 | package-lock.json 15 | 16 | coverage 17 | 18 | *.log 19 | 20 | *.local 21 | 22 | index.html 23 | .vite-inspect 24 | .remote-assets 25 | components.d.ts 26 | -------------------------------------------------------------------------------- /presentations/2025/goprobe_bern_meetup/.npmrc: -------------------------------------------------------------------------------- 1 | registry=https://registry.npmjs.org/ 2 | 3 | # https://pnpm.io/npmrc#auto-install-peers 4 | auto-install-peers=true 5 | strict-peer-dependencies=false 6 | 7 | # https://pnpm.io/npmrc#shamefully-hoist 8 | shamefully-hoist=true 9 | -------------------------------------------------------------------------------- /presentations/2025/goprobe_bern_meetup/Makefile: -------------------------------------------------------------------------------- 1 | deps: 2 | npm install 3 | 4 | run: 5 | npm exec -c 'slidev "slides.md" --port 3031' 6 | 7 | export: 8 | npm exec -c 'slidev export --with-clicks' 9 | -------------------------------------------------------------------------------- /presentations/2025/goprobe_bern_meetup/global-network-observability-with-goprobe.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/els0r/goProbe/7eed90f04ea0ba38aeaaa9e22ae8a6b7aac7d6f9/presentations/2025/goprobe_bern_meetup/global-network-observability-with-goprobe.pdf -------------------------------------------------------------------------------- /presentations/2025/goprobe_bern_meetup/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "slidev-theme-eloc", 3 | "version": "1.1.0", 4 | "description": "Focus on writing, present in a concise style.", 5 | "keywords": [ 6 | "slidev-theme", 7 | "slidev" 8 | ], 9 | "license": "MIT", 10 | "repository": "https://github.com/zthxxx/slides/blob/master/packages/slidev-theme-eloc", 11 | "homepage": "https://eloc-slidev.vercel.app", 12 | "type": "module", 13 | "scripts": { 14 | "dev": "slidev example.md --open", 15 | "clean": "rimraf dist", 16 | "build:example": "npm run clean && slidev build example.md", 17 | "export": "slidev export screenshot.md --output export", 18 | "screenshot": "slidev export screenshot.md --output screenshot --format png", 19 | "deploy": "npm run build:example && vercel --cwd dist" 20 | }, 21 | "files": [ 22 | "README.md", 23 | "CHANGELOG.md", 24 | "example.md", 25 | "components", 26 | "layouts", 27 | "public", 28 | "setup", 29 | "styles", 30 | "vite.config.ts", 31 | "*.vue" 32 | ], 33 | "dependencies": { 34 | "@shikijs/monaco": "^3.2.0", 35 | "@slidev/theme-apple-basic": "^0.25.1", 36 | "@slidev/theme-default": "^0.25.0", 37 | "@slidev/types": "^51.1.1", 38 | "@vueuse/core": "^12.7.0", 39 | "@vueuse/math": "^12.7.0", 40 | "codemirror-theme-vars": "^0.1.2", 41 | "defu": "^6.1.4", 42 | "prism-theme-vars": "^0.2.5", 43 | "slidev-theme-eloc": "^1.1.0" 44 | }, 45 | "devDependencies": { 46 | "@slidev/cli": "51.1.1", 47 | "playwright-chromium": "1.50.1", 48 | "postcss": "8.5.2", 49 | "rimraf": "6.0.1" 50 | }, 51 | "engines": { 52 | "node": ">=20.0.0", 53 | "slidev": ">=51.0.0" 54 | }, 55 | "//": "Learn more: https://sli.dev/guide/write-theme.html", 56 | "// slidev theme meta": "https://github.com/slidevjs/slidev/blob/v51.1.1/packages/types/src/types.ts#L73", 57 | "slidev": { 58 | "colorSchema": "both", 59 | "highlighter": "shiki", 60 | "// slidev config": "https://github.com/slidevjs/slidev/blob/v51.1.1/packages/parser/src/config.ts#L5", 61 | "defaults": { 62 | "routerMode": "history", 63 | "canvasWidth": 1580, 64 | "selectable": true, 65 | "fonts": { 66 | "mono": "Fira Code" 67 | } 68 | } 69 | } 70 | } 71 | -------------------------------------------------------------------------------- /presentations/2025/goprobe_bern_meetup/pictures/bg-initial.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/els0r/goProbe/7eed90f04ea0ba38aeaaa9e22ae8a6b7aac7d6f9/presentations/2025/goprobe_bern_meetup/pictures/bg-initial.png -------------------------------------------------------------------------------- /presentations/2025/goprobe_bern_meetup/pictures/els0r-gh.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/els0r/goProbe/7eed90f04ea0ba38aeaaa9e22ae8a6b7aac7d6f9/presentations/2025/goprobe_bern_meetup/pictures/els0r-gh.png -------------------------------------------------------------------------------- /presentations/2025/goprobe_bern_meetup/pictures/fako1024-gh.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/els0r/goProbe/7eed90f04ea0ba38aeaaa9e22ae8a6b7aac7d6f9/presentations/2025/goprobe_bern_meetup/pictures/fako1024-gh.png -------------------------------------------------------------------------------- /presentations/2025/goprobe_bern_meetup/pictures/goprobe_system_overview.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/els0r/goProbe/7eed90f04ea0ba38aeaaa9e22ae8a6b7aac7d6f9/presentations/2025/goprobe_bern_meetup/pictures/goprobe_system_overview.png -------------------------------------------------------------------------------- /presentations/2025/goprobe_bern_meetup/pictures/goprobe_system_overview_gq_focus.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/els0r/goProbe/7eed90f04ea0ba38aeaaa9e22ae8a6b7aac7d6f9/presentations/2025/goprobe_bern_meetup/pictures/goprobe_system_overview_gq_focus.png -------------------------------------------------------------------------------- /presentations/2025/goprobe_bern_meetup/pictures/goprobe_system_overview_host.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/els0r/goProbe/7eed90f04ea0ba38aeaaa9e22ae8a6b7aac7d6f9/presentations/2025/goprobe_bern_meetup/pictures/goprobe_system_overview_host.png -------------------------------------------------------------------------------- /presentations/2025/goprobe_bern_meetup/pictures/hosts.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/els0r/goProbe/7eed90f04ea0ba38aeaaa9e22ae8a6b7aac7d6f9/presentations/2025/goprobe_bern_meetup/pictures/hosts.png -------------------------------------------------------------------------------- /presentations/2025/goprobe_bern_meetup/pictures/ntm-global-analysis/ntm-global-analysis.001.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/els0r/goProbe/7eed90f04ea0ba38aeaaa9e22ae8a6b7aac7d6f9/presentations/2025/goprobe_bern_meetup/pictures/ntm-global-analysis/ntm-global-analysis.001.png -------------------------------------------------------------------------------- /presentations/2025/goprobe_bern_meetup/pictures/ntm-global-analysis/ntm-global-analysis.002.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/els0r/goProbe/7eed90f04ea0ba38aeaaa9e22ae8a6b7aac7d6f9/presentations/2025/goprobe_bern_meetup/pictures/ntm-global-analysis/ntm-global-analysis.002.png -------------------------------------------------------------------------------- /presentations/2025/goprobe_bern_meetup/pictures/ntm-global-analysis/ntm-global-analysis.003.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/els0r/goProbe/7eed90f04ea0ba38aeaaa9e22ae8a6b7aac7d6f9/presentations/2025/goprobe_bern_meetup/pictures/ntm-global-analysis/ntm-global-analysis.003.png -------------------------------------------------------------------------------- /presentations/2025/goprobe_bern_meetup/pictures/ntm-global-analysis/ntm-global-analysis.004.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/els0r/goProbe/7eed90f04ea0ba38aeaaa9e22ae8a6b7aac7d6f9/presentations/2025/goprobe_bern_meetup/pictures/ntm-global-analysis/ntm-global-analysis.004.png -------------------------------------------------------------------------------- /presentations/2025/goprobe_bern_meetup/pictures/ntm-global-analysis/ntm-global-analysis.005.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/els0r/goProbe/7eed90f04ea0ba38aeaaa9e22ae8a6b7aac7d6f9/presentations/2025/goprobe_bern_meetup/pictures/ntm-global-analysis/ntm-global-analysis.005.png -------------------------------------------------------------------------------- /presentations/2025/goprobe_bern_meetup/pictures/ntm-global-analysis/ntm-global-analysis.006.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/els0r/goProbe/7eed90f04ea0ba38aeaaa9e22ae8a6b7aac7d6f9/presentations/2025/goprobe_bern_meetup/pictures/ntm-global-analysis/ntm-global-analysis.006.png -------------------------------------------------------------------------------- /presentations/2025/goprobe_bern_meetup/pictures/os.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/els0r/goProbe/7eed90f04ea0ba38aeaaa9e22ae8a6b7aac7d6f9/presentations/2025/goprobe_bern_meetup/pictures/os.png -------------------------------------------------------------------------------- /presentations/2025/goprobe_bern_meetup/pictures/packet_detail.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/els0r/goProbe/7eed90f04ea0ba38aeaaa9e22ae8a6b7aac7d6f9/presentations/2025/goprobe_bern_meetup/pictures/packet_detail.png -------------------------------------------------------------------------------- /presentations/2025/goprobe_bern_meetup/pictures/packets.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/els0r/goProbe/7eed90f04ea0ba38aeaaa9e22ae8a6b7aac7d6f9/presentations/2025/goprobe_bern_meetup/pictures/packets.png -------------------------------------------------------------------------------- /presentations/2025/goprobe_bern_meetup/pictures/packets_hosts.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/els0r/goProbe/7eed90f04ea0ba38aeaaa9e22ae8a6b7aac7d6f9/presentations/2025/goprobe_bern_meetup/pictures/packets_hosts.png -------------------------------------------------------------------------------- /presentations/2025/goprobe_bern_meetup/pictures/packets_os_hosts.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/els0r/goProbe/7eed90f04ea0ba38aeaaa9e22ae8a6b7aac7d6f9/presentations/2025/goprobe_bern_meetup/pictures/packets_os_hosts.png -------------------------------------------------------------------------------- /presentations/2025/goprobe_bern_meetup/pictures/packets_single.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/els0r/goProbe/7eed90f04ea0ba38aeaaa9e22ae8a6b7aac7d6f9/presentations/2025/goprobe_bern_meetup/pictures/packets_single.png -------------------------------------------------------------------------------- /presentations/2025/goprobe_bern_meetup/pictures/slimcap/capture_flow_1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/els0r/goProbe/7eed90f04ea0ba38aeaaa9e22ae8a6b7aac7d6f9/presentations/2025/goprobe_bern_meetup/pictures/slimcap/capture_flow_1.png -------------------------------------------------------------------------------- /presentations/2025/goprobe_bern_meetup/pictures/slimcap/capture_flow_2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/els0r/goProbe/7eed90f04ea0ba38aeaaa9e22ae8a6b7aac7d6f9/presentations/2025/goprobe_bern_meetup/pictures/slimcap/capture_flow_2.png -------------------------------------------------------------------------------- /presentations/2025/goprobe_bern_meetup/pictures/slimcap/fine.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/els0r/goProbe/7eed90f04ea0ba38aeaaa9e22ae8a6b7aac7d6f9/presentations/2025/goprobe_bern_meetup/pictures/slimcap/fine.jpg -------------------------------------------------------------------------------- /presentations/2025/goprobe_bern_meetup/pictures/slimcap/layers.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/els0r/goProbe/7eed90f04ea0ba38aeaaa9e22ae8a6b7aac7d6f9/presentations/2025/goprobe_bern_meetup/pictures/slimcap/layers.png -------------------------------------------------------------------------------- /presentations/2025/goprobe_bern_meetup/pictures/slimcap/mock.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/els0r/goProbe/7eed90f04ea0ba38aeaaa9e22ae8a6b7aac7d6f9/presentations/2025/goprobe_bern_meetup/pictures/slimcap/mock.png -------------------------------------------------------------------------------- /presentations/2025/goprobe_bern_meetup/pictures/slimcap/ringbuf.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/els0r/goProbe/7eed90f04ea0ba38aeaaa9e22ae8a6b7aac7d6f9/presentations/2025/goprobe_bern_meetup/pictures/slimcap/ringbuf.png -------------------------------------------------------------------------------- /presentations/2025/goprobe_bern_meetup/pictures/slimcap/ringbuf_1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/els0r/goProbe/7eed90f04ea0ba38aeaaa9e22ae8a6b7aac7d6f9/presentations/2025/goprobe_bern_meetup/pictures/slimcap/ringbuf_1.png -------------------------------------------------------------------------------- /presentations/2025/goprobe_bern_meetup/pictures/slimcap/ringbuf_2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/els0r/goProbe/7eed90f04ea0ba38aeaaa9e22ae8a6b7aac7d6f9/presentations/2025/goprobe_bern_meetup/pictures/slimcap/ringbuf_2.png -------------------------------------------------------------------------------- /presentations/2025/goprobe_bern_meetup/pictures/slimcap/ringbuf_3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/els0r/goProbe/7eed90f04ea0ba38aeaaa9e22ae8a6b7aac7d6f9/presentations/2025/goprobe_bern_meetup/pictures/slimcap/ringbuf_3.png -------------------------------------------------------------------------------- /presentations/2025/goprobe_bern_meetup/theme/LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2021 Slidev.js Team 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /presentations/2025/goprobe_bern_meetup/theme/example.md: -------------------------------------------------------------------------------- 1 | --- 2 | theme: ./ 3 | layout: intro 4 | --- 5 | 6 | # Presentation title 7 | 8 | Presentation subtitle 9 | 10 |
11 | 12 | Author and Date 13 | 14 |
15 | 16 | --- 17 | layout: intro-image 18 | image: 'https://source.unsplash.com/collection/4966472/1920x1080' 19 | --- 20 | 21 |
22 | 23 | Author and Date 24 | 25 |
26 | 27 |
28 |

Presentation title

29 |

Presentation subtitle

30 |
31 | 32 | --- 33 | layout: intro-image-right 34 | image: 'https://source.unsplash.com/collection/4966472/1920x1080' 35 | --- 36 | 37 | # Slide Title 38 | ## Slide Subtitle 39 | 40 | --- 41 | layout: image-right 42 | image: 'https://source.unsplash.com/collection/4966472/1920x1080' 43 | --- 44 | 45 | # Slide Title 46 | ## Slide Subtitle 47 | 48 | * Slide bullet text 49 | 50 | --- 51 | 52 | # Slide Title 53 | ## Slide Subtitle 54 | 55 | * Slide bullet text 56 | 57 | --- 58 | layout: bullets 59 | --- 60 | 61 | * Slide bullet text 62 | 63 | --- 64 | layout: section 65 | --- 66 | 67 | # Section Title 68 | 69 | --- 70 | layout: statement 71 | --- 72 | 73 | # Statement 74 | 75 | --- 76 | layout: fact 77 | --- 78 | 79 | # 100% 80 | Fact information 81 | 82 | --- 83 | layout: quote 84 | --- 85 | 86 | # "Notable quote" 87 | Attribution 88 | 89 | --- 90 | layout: 3-images 91 | imageLeft: 'https://source.unsplash.com/collection/4966472/1920x1080' 92 | imageTopRight: 'https://source.unsplash.com/collection/4966472/1920x1080' 93 | imageBottomRight: 'https://source.unsplash.com/collection/4966472/1920x1080' 94 | --- 95 | 96 | --- 97 | layout: image 98 | image: 'https://source.unsplash.com/collection/4966472/1920x1080' 99 | --- 100 | 101 | --- 102 | layout: center 103 | class: "text-center" 104 | --- 105 | 106 | # Learn More 107 | 108 | [Documentations](https://sli.dev) / [GitHub Repo](https://github.com/slidevjs/slidev) 109 | -------------------------------------------------------------------------------- /presentations/2025/goprobe_bern_meetup/theme/layoutHelper.ts: -------------------------------------------------------------------------------- 1 | import type { CSSProperties } from 'vue' 2 | 3 | /** 4 | * Resolve urls from frontmatter and append with the base url 5 | */ 6 | export function resolveAssetUrl(url: string) { 7 | if (url.startsWith('/')) 8 | return import.meta.env.BASE_URL + url.slice(1) 9 | return url 10 | } 11 | 12 | export function handleBackground(background?: string, dim = false): CSSProperties { 13 | const isColor = background && ['#', 'rgb', 'hsl'].some(v => background.indexOf(v) === 0) 14 | 15 | const style = { 16 | background: isColor 17 | ? background 18 | : undefined, 19 | color: (background && !isColor) 20 | ? 'white' 21 | : undefined, 22 | backgroundImage: isColor 23 | ? undefined 24 | : background 25 | ? dim 26 | ? `linear-gradient(#0005, #0008), url(${resolveAssetUrl(background)})` 27 | : `url("${resolveAssetUrl(background)}")` 28 | : undefined, 29 | backgroundRepeat: 'no-repeat', 30 | backgroundPosition: 'center', 31 | backgroundSize: 'cover', 32 | } 33 | 34 | if (!style.background) 35 | delete style.background 36 | 37 | return style 38 | } 39 | -------------------------------------------------------------------------------- /presentations/2025/goprobe_bern_meetup/theme/layouts/3-images.vue: -------------------------------------------------------------------------------- 1 | 20 | 21 | 30 | -------------------------------------------------------------------------------- /presentations/2025/goprobe_bern_meetup/theme/layouts/bullets.vue: -------------------------------------------------------------------------------- 1 | 8 | -------------------------------------------------------------------------------- /presentations/2025/goprobe_bern_meetup/theme/layouts/fact.vue: -------------------------------------------------------------------------------- 1 | 8 | -------------------------------------------------------------------------------- /presentations/2025/goprobe_bern_meetup/theme/layouts/image-right.vue: -------------------------------------------------------------------------------- 1 | 15 | 16 | 24 | -------------------------------------------------------------------------------- /presentations/2025/goprobe_bern_meetup/theme/layouts/intro-image-right.vue: -------------------------------------------------------------------------------- 1 | 15 | 16 | 24 | -------------------------------------------------------------------------------- /presentations/2025/goprobe_bern_meetup/theme/layouts/intro-image.vue: -------------------------------------------------------------------------------- 1 | 12 | 13 | 18 | -------------------------------------------------------------------------------- /presentations/2025/goprobe_bern_meetup/theme/layouts/intro.vue: -------------------------------------------------------------------------------- 1 | 8 | -------------------------------------------------------------------------------- /presentations/2025/goprobe_bern_meetup/theme/layouts/quote.vue: -------------------------------------------------------------------------------- 1 | 8 | -------------------------------------------------------------------------------- /presentations/2025/goprobe_bern_meetup/theme/layouts/section.vue: -------------------------------------------------------------------------------- 1 | 8 | -------------------------------------------------------------------------------- /presentations/2025/goprobe_bern_meetup/theme/layouts/statement.vue: -------------------------------------------------------------------------------- 1 | 8 | -------------------------------------------------------------------------------- /presentations/2025/goprobe_bern_meetup/theme/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@slidev/theme-apple-basic", 3 | "version": "0.25.1", 4 | "description": "Apple like theme for Slidev", 5 | "author": "Jeremy Meissner ", 6 | "license": "MIT", 7 | "homepage": "https://sli.dev", 8 | "repository": { 9 | "type": "git", 10 | "url": "https://github.com/slidevjs/themes" 11 | }, 12 | "bugs": "https://github.com/slidevjs/themes/issues", 13 | "keywords": [ 14 | "slidev-theme", 15 | "slidev" 16 | ], 17 | "engines": { 18 | "node": ">=14.0.0", 19 | "slidev": ">=v0.47.0" 20 | }, 21 | "slidev": { 22 | "defaults": { 23 | "fonts": { 24 | "sans": "Helvetica Neue", 25 | "local": "Helvetica Neue" 26 | } 27 | } 28 | }, 29 | "dependencies": { 30 | "@slidev/types": "^0.47.0", 31 | "codemirror-theme-vars": "^0.1.2", 32 | "prism-theme-vars": "^0.2.4" 33 | }, 34 | "scripts": { 35 | "dev": "slidev example.md --open", 36 | "build": "slidev build example.md", 37 | "export": "slidev export example.md", 38 | "screenshot": "slidev export example.md --format png" 39 | } 40 | } -------------------------------------------------------------------------------- /presentations/2025/goprobe_bern_meetup/theme/styles/index.ts: -------------------------------------------------------------------------------- 1 | import './layout.css' 2 | import './prism.css' 3 | -------------------------------------------------------------------------------- /presentations/2025/goprobe_bern_meetup/theme/styles/prism.css: -------------------------------------------------------------------------------- 1 | @import 'prism-theme-vars/base.css'; 2 | @import 'codemirror-theme-vars/base.css'; 3 | @import 'prism-theme-vars/to-codemirror.css'; 4 | 5 | :root { 6 | --prism-font-family: var(--slidev-code-font-family); 7 | --prism-background: var(--slidev-code-background); 8 | } 9 | 10 | html:not(.dark) { 11 | --prism-foreground: #393a34; 12 | --prism-comment: #a0ada0; 13 | --prism-string: #b56959; 14 | --prism-literal: #2f8a89; 15 | --prism-number: #296aa3; 16 | --prism-keyword: #1c6b48; 17 | --prism-function: #6c7834; 18 | --prism-boolean: #1c6b48; 19 | --prism-constant: #a65e2b; 20 | --prism-deleted: #a14f55; 21 | --prism-class: #2993a3; 22 | --prism-builtin: #ab5959; 23 | --prism-property: #b58451; 24 | --prism-namespace: #b05a78; 25 | --prism-punctuation: #8e8f8b; 26 | --prism-decorator: #bd8f8f; 27 | --prism-regex: #ab5e3f; 28 | --prism-json-property: #698c96; 29 | } 30 | 31 | html.dark { 32 | --prism-foreground: #d4cfbf; 33 | --prism-comment: #758575; 34 | --prism-string: #d48372; 35 | --prism-literal: #429988; 36 | --prism-keyword: #4d9375; 37 | --prism-boolean: #1c6b48; 38 | --prism-number: #6394bf; 39 | --prism-variable: #c2b36e; 40 | --prism-function: #a1b567; 41 | --prism-deleted: #a14f55; 42 | --prism-class: #54b1bf; 43 | --prism-builtin: #e0a569; 44 | --prism-property: #dd8e6e; 45 | --prism-namespace: #db889a; 46 | --prism-punctuation: #858585; 47 | --prism-decorator: #bd8f8f; 48 | --prism-regex: #ab5e3f; 49 | --prism-json-property: #6b8b9e; 50 | --prism-line-number: #888888; 51 | --prism-line-number-gutter: #eeeeee; 52 | --prism-line-highlight-background: #444444; 53 | --prism-selection-background: #444444; 54 | } 55 | --------------------------------------------------------------------------------