├── .github
└── workflows
│ └── build.yml
├── Dockerfile
├── LICENSE
├── Makefile
├── README.md
├── assets
├── doc.go
└── ebpf_probe.go
├── bin
└── rtcagent
├── builder
├── Makefile.release
├── gen_android_nocore.sh
├── init_env.sh
└── rpmBuild.spec
├── cli
├── cmd
│ ├── freeswitch.go
│ ├── global.go
│ ├── kamailio.go
│ ├── monitor.go
│ ├── opensips.go
│ ├── root.go
│ └── tcprtt.go
├── cobrautl
│ └── help.go
└── main.go
├── dump.pcap
├── examples
└── Dockerfile.kamailio
├── go.mod
├── go.sum
├── hepclient
├── hepclient.go
└── hepsender
│ └── hepsender.go
├── kern
├── bpf.old
│ ├── arm64
│ │ ├── vmlinux.h
│ │ └── vmlinux_510.h
│ ├── bpf_core_read.h
│ ├── bpf_endian.h
│ ├── bpf_helper_defs.h
│ ├── bpf_helpers.h
│ ├── bpf_tracing.h
│ └── x86
│ │ ├── .gitkeep
│ │ └── vmlinux.h
├── bpf
│ ├── arm64
│ │ ├── vmlinux.h
│ │ └── vmlinux_510.h
│ ├── bpf_core_read.h
│ ├── bpf_endian.h
│ ├── bpf_helper_defs.h
│ ├── bpf_helpers.h
│ ├── bpf_tracing.h
│ └── x86
│ │ ├── .gitkeep
│ │ └── vmlinux.h
├── common.h
├── common2.h
├── freeswitch.h
├── freeswitch_kern.c
├── kamailio.h
├── kamailio_kern.c
├── monitor_kern.c
├── opensips.h
├── opensips_kern.c
├── rtcagent.h
└── tcprtt_kern.c
├── main.go
├── metric
├── definition.go
├── metric.go
├── prometheus.go
└── reload.go
├── model
└── metric.go
├── outdata
└── hep
│ ├── hep.pb.go
│ ├── hep.proto
│ └── marshal.go
├── pkg
├── event_processor
│ ├── base_event.go
│ ├── iparser.go
│ ├── iworker.go
│ └── processor.go
├── proc
│ ├── go_elf
│ │ ├── eprint.go
│ │ └── gccgo.go
│ ├── proc.go
│ └── proc_test.go
└── util
│ ├── ebpf
│ ├── bpf.go
│ ├── bpf_androidgki.go
│ ├── bpf_linux.go
│ ├── config.gz
│ └── parse.go
│ ├── hkdf
│ ├── hkdf.go
│ └── hkdf_test.go
│ └── kernel
│ ├── kernel_version.go
│ ├── kernel_version_unsupport.go
│ └── version.go
├── rtcagent.service
├── rtcagent.yml
├── runagent.sh
└── user
├── bytecode
├── .gitkeep
├── freeswitch_kern.d
├── freeswitch_kern.o
├── freeswitch_kern_less52.d
├── freeswitch_kern_less52.o
├── kamailio_kern.d
├── kamailio_kern.o
├── kamailio_kern_less52.d
├── kamailio_kern_less52.o
├── monitor_kern.d
├── monitor_kern.o
├── monitor_kern_less52.d
├── monitor_kern_less52.o
├── opensips_kern.d
├── opensips_kern.o
├── opensips_kern_less52.d
├── opensips_kern_less52.o
├── tcprtt_kern.d
├── tcprtt_kern.o
├── tcprtt_kern_less52.d
└── tcprtt_kern_less52.o
├── config
├── common.go
├── common_androidgki.go
├── common_linux.go
├── config_freeswitch.go
├── config_kamailio.go
├── config_monitor.go
├── config_opensips.go
├── config_tcprtt.go
├── const.go
└── iconfig.go
├── event
├── event_freeswitch.go
├── event_kamailio.go
├── event_monitor.go
├── event_opensips.go
├── event_tcprtt.go
├── ievent.go
└── misc.go
├── module
├── const.go
├── iclose.go
├── imodule.go
├── probe_freeswitch.go
├── probe_kamailio.go
├── probe_monitor.go
├── probe_opensips.go
├── probe_tcpdrop.go
└── register.go
└── time
└── monotonic.go
/.github/workflows/build.yml:
--------------------------------------------------------------------------------
1 | name: RTCAgent Builder
2 |
3 | on:
4 | workflow_dispatch:
5 | release:
6 | types: [created]
7 |
8 |
9 | env:
10 | REGISTRY: ghcr.io
11 | IMAGE_NAME: ${{ github.repository }}
12 |
13 | jobs:
14 |
15 | build:
16 | runs-on: ubuntu-latest
17 | steps:
18 | - uses: actions/checkout@v4
19 | - name: Set up Go
20 | uses: actions/setup-go@v5.0.2
21 | with:
22 | go-version: 1.21
23 | - name: Setup Build Env
24 | run: /bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com//sipcapture/rtcagent/master/builder/init_env.sh)"
25 | - name: Build RTCAgent
26 | run: make
27 | - name: Compress
28 | run: |
29 | strip bin/rtcagent
30 | upx bin/rtcagent
31 | - name: Check & Run
32 | run: |
33 | ls -alFh bin/rtcagent
34 | ./bin/rtcagent --help
35 |
36 | - name: Patch NFPM Version
37 | run: |
38 | sudo sed -i "s/0.0.0/${{ github.ref_name }}/g" rtcagent.yml
39 | - name: Create deb package
40 | id: nfpm-deb
41 | uses: burningalchemist/nfpm-action@v1
42 | env:
43 | VERSION: ${{ github.event.release.tag_name }}
44 | with:
45 | packager: deb
46 | config: rtcagent.yml
47 | target: rtcagent_${{ github.ref_name }}_all.deb
48 | - name: Create rpm package
49 | id: nfpm-rpm
50 | uses: burningalchemist/nfpm-action@v1
51 | env:
52 | VERSION: ${{ github.event.release.tag_name }}
53 | with:
54 | packager: rpm
55 | config: rtcagent.yml
56 | target: rtcagent_${{ github.ref_name }}.amd64.rpm
57 |
58 | - name: Upload Release
59 | if: github.event_name != 'pull_request'
60 | uses: boxpositron/upload-multiple-releases@1.0.7
61 | env:
62 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
63 | with:
64 | release_config: |
65 | ./bin/rtcagent
66 | ./rtcagent_${{ github.ref_name }}_all.deb
67 | ./rtcagent_${{ github.ref_name }}.amd64.rpm
68 | tag_name: ${{ github.ref_name }}
69 | release_name: rtcagent_${{ github.ref_name }}
70 | draft: false
71 | prerelease: false
72 | overwrite: true
73 |
74 | - name: Log in to the Container registry
75 | uses: docker/login-action@v2.0.0
76 | with:
77 | registry: ${{ env.REGISTRY }}
78 | username: ${{ github.actor }}
79 | password: ${{ secrets.GITHUB_TOKEN }}
80 |
81 | - name: Docker Build and push
82 | uses: docker/build-push-action@v3.0.0
83 | with:
84 | context: .
85 | push: true
86 | tags: |
87 | ghcr.io/sipcapture/rtcagent:latest
88 | ghcr.io/sipcapture/rtcagent:${{ github.ref_name }}
89 |
--------------------------------------------------------------------------------
/Dockerfile:
--------------------------------------------------------------------------------
1 | FROM alpine as builder
2 | RUN apk add --allow-untrusted --update --no-cache curl ca-certificates
3 | WORKDIR /
4 | RUN curl -fsSL github.com/sipcapture/rtcagent/releases/latest/download/rtcagent -O && chmod +x rtcagent
5 |
6 | FROM scratch
7 | COPY --from=builder /etc/ssl/certs/ca-certificates.crt /etc/ssl/certs/
8 | COPY --from=builder /rtcagent /rtcagent
9 | CMD ["/rtcagent"]
10 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | > RTCagent is an HEP/eBPF powered observability tool for VoIP/WebRTC Applications.
6 |
7 |
8 |
9 | ### About
10 |
11 | **RTCAgent** is a _next-generation **HEP Agent**_ developed using the latest **[eBPF](https://ebpf.io)** technologies.
12 |
13 | RTCAgent greatly differs from any other previous HEP Agent in several ways:
14 |
15 | - Unlike _native agents_, it does not require any code modifications or patches
16 | - Unlike _passive agents_, it does not require access to network interfaces and packets
17 | - Unlike _any other agent_, it traces functions used for _sending/receiving_ data
18 |
19 | _The result is a new, lightweight and portable HEP Agent able to mirror SIP packets through eBPF hooks
20 | from the core of supported applications bypassing manual code integrations, network encryption and complexity._
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 | ### Download
30 | Download an `amd64/x86` static build of `rtcagent` and use it immediately on modern kernels.
31 | ```bash
32 | curl -fsSL github.com/sipcapture/rtcagent/releases/latest/download/rtcagent -O && chmod +x rtcagent
33 | ```
34 |
35 | Prefer using packages? Get the latest [deb and rpm](https://github.com/sipcapture/rtcagent/releases) releases for `amd64/x86`
36 |
37 | ### Usage
38 |
39 | ```
40 |
41 | NAME: rtcagent - Capture and debug RTC Projects.
42 | USAGE: rtcagent [flags]
43 |
44 | COMMANDS:
45 |
46 | help Help about any command
47 | freeswitch capture SIP messages from freeswitch (libsofia): t_port, su_recv
48 | kamailio capture SIP messages from kamailio: recv_msg, udp_send, tcp_send.
49 | opensips capture SIP messages from v: recv_msg, udp_send, tcp_send.
50 | tcprtt show tcp rtt stats
51 | monitor show advanced monitor statistics
52 |
53 |
54 | DESCRIPTION:
55 |
56 | RTCAgent is a tool that can capture and trace SIP packets using eBPF hooks and HEP
57 |
58 | Usage:
59 | rtcagent -h
60 |
61 | OPTIONS:
62 | -d, --debug[=false] enable debug logging
63 | -h, --help[=false] help for rtcagent
64 | -P, --hep-port="9060" hep port - default 9060
65 | -S, --hep-server="" hep server to duplicate: i.e. 10.0.0.1
66 | -T, --hep-transport="udp" hep transport default udp. Can be udp, tcp, tls
67 | --hex[=false] print byte strings as hex encoded strings
68 | -l, --log-file="" -l save the packets to file
69 | --nosearch[=false] no lib search
70 | -p, --pid=0 if pid is 0 then we target all pids
71 | -u, --uid=0 if uid is 0 then we target all users
72 | -v, --version[=false] version for rtcagent
73 |
74 | ```
75 |
76 |
77 |
78 | ### Build
79 |
80 | > Compatible with Linux/Android kernel versions >= **x86_64 5.x**, >= **aarch64 5.5**.
81 | > Linux only. Does not support Windows and macOS.
82 |
83 | #### Requirements
84 | * golang 1.18 or newer
85 | * clang 9.0 or newer
86 | * cmake 3.18.4 or newer
87 | * clang backend: llvm 9.0 or newer
88 | * kernel config:CONFIG_DEBUG_INFO_BTF=y
89 |
90 | #### Instructions
91 |
92 | ##### Ubuntu
93 | If you are using Ubuntu 20.04 or later versions, you can use a single command to complete the initialization of the compilation environment.
94 | ```shell
95 | /bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com//sipcapture/rtcagent/master/builder/init_env.sh)"
96 | ```
97 | ##### Any Linux
98 | In addition to the software listed in the 'Toolchain Version' section above, the following software is also required for the compilation environment. Please install before proceeding.
99 |
100 | * linux-tools-common
101 | * linux-tools-generic
102 | * pkgconf
103 | * libelf-dev
104 |
105 | **Clone the repository code and compile**
106 | ```shell
107 | git clone git@github.com:/sipcapture/rtcagent.git
108 | cd rtcagent
109 | make
110 | bin/rtcagent
111 | ```
112 | #### compile without BTF
113 | RTCAgent support BTF disabled with command `make nocore` to compile at 2022/04/17 and can run on Linux systems that do not support BTF.
114 | ```shell
115 | make nocore
116 | bin/rtcagent --help
117 | ```
118 |
119 |
120 |
121 | ### Usage
122 | Run `rtcagent` on a native host attaching to a local binary target
123 | ##### Kamailio
124 | ```
125 | ./rtcagent kamailio -T udp -P 9060 -S $HOMER -m /usr/sbin/kamailio
126 | ```
127 | ##### OpenSIPS
128 | ```
129 | ./rtcagent opensips -T tcp -P 9061 -S $HOMER -m /usr/sbin/opensips
130 | ```
131 | ##### FreeSwitch
132 | ```
133 | ./rtcagent freeswitch -T udp -P 9060 -S $HOMER -m /usr/sbin/freeswitch
134 | ```
135 |
136 | ### Docker
137 | #### Hypervisor Mode
138 | Run `rtcagent` as a priviledged container on your host attaching to a local binary target
139 | ```
140 | rtcagent:
141 | privileged: true
142 | pid: host
143 | image: ghcr.io/sipcapture/rtcagent
144 | container_name: rtcagent
145 | restart: unless-stopped
146 | volumes:
147 | - /sys/fs/cgroup:/host/sys/fs/cgroup:ro
148 | - /sys/kernel/debug:/sys/kernel/debug:rw
149 | command: --cgroupfs-root=/host/sys/fs/cgroup
150 | ```
151 |
152 | #### Cross-Container Mode
153 | Run `rtcagent` as a priviledged container attached to a target container via docker volume mounts
154 | ##### Kamailio
155 | ```
156 | rtcagent:
157 | privileged: true
158 | image: ghcr.io/sipcapture/rtcagent
159 | container_name: rtcagent
160 | restart: unless-stopped
161 | volumes:
162 | - $(docker inspect --format="{{.GraphDriver.Data.MergedDir}}" kamailio)/usr/sbin/kamailio:/kamailio:ro
163 | command: /rtcagent kamailio -m /kamailio
164 | depends_on:
165 | - kamailio
166 | ```
167 | ##### OpenSIPS
168 | ```
169 | rtcagent:
170 | privileged: true
171 | image: ghcr.io/sipcapture/rtcagent
172 | container_name: rtcagent
173 | restart: unless-stopped
174 | volumes:
175 | - $(docker inspect --format="{{.GraphDriver.Data.MergedDir}}" opensips)/usr/sbin/opensips:/opensips:ro
176 | command: /rtcagent opensips -m /opensips
177 | depends_on:
178 | - opensips
179 | ```
180 |
181 |
182 | ### Credits
183 |
184 | RTCAgent is inspired by Cilum, Odigos, eCapture and the many eBPF guides, libraries and implementations.
185 |
--------------------------------------------------------------------------------
/assets/doc.go:
--------------------------------------------------------------------------------
1 | package assets
2 |
--------------------------------------------------------------------------------
/bin/rtcagent:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sipcapture/rtcagent/6e4bba460ef57079552fcd03e4b790b6a712d4c3/bin/rtcagent
--------------------------------------------------------------------------------
/builder/Makefile.release:
--------------------------------------------------------------------------------
1 | #
2 | # Responsible for creating rtcagent snapshots for testing and releasing
3 | #
4 |
5 | .PHONY: all
6 | all: help
7 | release: snapshot snapshot_android publish
8 |
9 | #
10 | # make
11 | #
12 |
13 | .ONESHELL:
14 | SHELL = /bin/sh
15 |
16 | MAKEFLAGS += --no-print-directory
17 |
18 | #
19 | # tools
20 | #
21 |
22 | CMD_CHECKSUM ?= sha256sum
23 | CMD_GITHUB ?= gh
24 | CMD_TAR ?= tar
25 | CMD_GIT ?= git
26 | CMD_RM ?= rm
27 | CMD_TOUCH ?= touch
28 | CMD_MKDIR ?= mkdir
29 | CMD_MV ?= mv
30 | CMD_CP ?= cp
31 |
32 | UNAME_M := $(shell uname -m)
33 | SNAPSHOT_VERSION ?= $(shell git rev-parse HEAD)
34 |
35 | .ONESHELL:
36 | .check_%:
37 | #
38 | @command -v $* >/dev/null
39 | if [ $$? -ne 0 ]; then
40 | echo "missing required tool $*"
41 | exit 1
42 | else
43 | touch $@ # avoid target rebuilds due to inexistent file
44 | fi
45 |
46 | #
47 | # environment
48 | #
49 |
50 | .PHONY: env
51 | env:
52 | @echo ---------------------------------------
53 | @echo "CMD_CHECKSUM $(CMD_CHECKSUM)"
54 | @echo "CMD_GIT $(CMD_GIT)"
55 | @echo "CMD_GITHUB $(CMD_GITHUB)"
56 | @echo "CMD_TAR $(CMD_TAR)"
57 | @echo "CMD_TOUCH $(CMD_TOUCH)"
58 | @echo "CMD_RM $(CMD_RM)"
59 | @echo "CMD_MKDIR $(CMD_MKDIR)"
60 | @echo ---------------------------------------
61 | @echo "SNAPSHOT_VERSION $(SNAPSHOT_VERSION)"
62 | @echo ---------------------------------------
63 |
64 | #
65 | # usage
66 | #
67 |
68 | .PHONY: help
69 | help:
70 | @echo ""
71 | @echo "Create rtcagent snapshots for testing and releasing"
72 | @echo ""
73 | @echo "To generate a release snapshot:"
74 | @echo ""
75 | @echo " $$ make -f builder/Makefile.release snapshot"
76 | @echo ""
77 | @echo " - Compiles rtcagent"
78 | @echo " - Creates an archive of build artifacts along with license"
79 | @echo " - Takes a checksum of the archive"
80 | @echo ""
81 | @echo " Example:"
82 | @echo ""
83 | @echo " To create build artifacts versioned by latest git SHA:"
84 | @echo ""
85 | @echo " $$ make -f builder/Makefile.release snapshot"
86 | @echo ""
87 | @echo " To create build artifacts with version v0.1.6:"
88 | @echo ""
89 | @echo " $$ SNAPSHOT_VERSION=v0.1.6 \ "
90 | @echo " make -f builder/Makefile.release snapshot"
91 | @echo ""
92 | @echo "To publish a release:"
93 | @echo ""
94 | @echo " $$ SNAPSHOT_VERSION=v0.1.6 \ "
95 | @echo " make -f builder/Makefile.release publish"
96 | @echo ""
97 | @echo ""
98 | @echo "Clean leftovers:"
99 | @echo ""
100 | @echo " $$ make -f builder/Makefile.release clean"
101 | @echo ""
102 |
103 | #
104 | # requirements
105 | #
106 |
107 | .PHONY: .check_tree
108 | .check_tree:
109 | #
110 | @if [ ! -d ./builder ]; then
111 | echo "you must be in the root directory"
112 | exit 1
113 | fi
114 |
115 | #
116 | # output dir
117 | #
118 |
119 | OUTPUT_DIR = ./bin
120 | TAR_DIR = rtcagent-$(SNAPSHOT_VERSION)-linux-$(UNAME_M)
121 | TAR_DIR_ANDROID = rtcagent-$(SNAPSHOT_VERSION)-android-$(UNAME_M)
122 |
123 | # from CLI args.
124 | RELEASE_NOTES ?= $(OUTPUT_DIR)/release_notes.txt
125 |
126 | $(OUTPUT_DIR):
127 | #
128 | $(CMD_MKDIR) -p $@
129 | # $(CMD_TOUCH) $(RELEASE_NOTES)
130 |
131 | #
132 | # Create a release snapshot
133 | #
134 |
135 | OUT_ARCHIVE := $(OUTPUT_DIR)/$(TAR_DIR).tar.gz
136 | OUT_ARCHIVE_ANDROID := $(OUTPUT_DIR)/$(TAR_DIR_ANDROID).tar.gz
137 | OUT_CHECKSUMS := $(OUTPUT_DIR)/checksum-$(SNAPSHOT_VERSION).txt
138 |
139 | .PHONY: snapshot
140 | snapshot: \
141 | $(OUTPUT_DIR) \
142 | | .check_tree \
143 | .check_$(CMD_TAR) \
144 | .check_$(CMD_CHECKSUM) \
145 | .check_$(CMD_GITHUB)
146 |
147 | # build binaries
148 | $(MAKE) clean
149 | $(MAKE) nocore
150 | # create the tar ball and checksum files
151 | $(CMD_MKDIR) -p $(TAR_DIR)
152 | $(CMD_CP) LICENSE $(TAR_DIR)/LICENSE
153 | $(CMD_CP) CHANGELOG.md $(TAR_DIR)/CHANGELOG.md
154 | $(CMD_CP) README.md $(TAR_DIR)/README.md
155 | $(CMD_CP) README_CN.md $(TAR_DIR)/README_CN.md
156 | $(CMD_MV) $(OUTPUT_DIR)/rtcagent $(TAR_DIR)/rtcagent
157 | $(CMD_CP) $(RELEASE_NOTES) $(OUTPUT_DIR)/release_notes.txt
158 | $(CMD_TAR) -czf $(OUT_ARCHIVE) $(TAR_DIR)
159 | cd $(OUTPUT_DIR)
160 | $(CMD_CHECKSUM) $(TAR_DIR).tar.gz > ./../$(OUT_CHECKSUMS)
161 | cd ../
162 |
163 | .PHONY: snapshot_android
164 | snapshot_android: \
165 | $(OUTPUT_DIR) \
166 | | .check_tree \
167 | .check_$(CMD_TAR) \
168 | .check_$(CMD_CHECKSUM) \
169 | .check_$(CMD_GITHUB)
170 |
171 | # build binaries
172 | $(MAKE) clean
173 | ANDROID=1 $(MAKE) nocore
174 | # create the tar ball and checksum files
175 | $(CMD_MKDIR) -p $(TAR_DIR_ANDROID)
176 | $(CMD_CP) LICENSE $(TAR_DIR_ANDROID)/LICENSE
177 | $(CMD_CP) CHANGELOG.md $(TAR_DIR_ANDROID)/CHANGELOG.md
178 | $(CMD_CP) README.md $(TAR_DIR_ANDROID)/README.md
179 | $(CMD_CP) README_CN.md $(TAR_DIR_ANDROID)/README_CN.md
180 | $(CMD_MV) $(OUTPUT_DIR)/rtcagent $(TAR_DIR_ANDROID)/rtcagent
181 | $(CMD_CP) $(RELEASE_NOTES) $(TAR_DIR_ANDROID)/release_notes.txt
182 | $(CMD_TAR) -czf $(OUT_ARCHIVE_ANDROID) $(TAR_DIR_ANDROID)
183 | cd $(OUTPUT_DIR)
184 | $(CMD_CHECKSUM) $(TAR_DIR_ANDROID).tar.gz >> ./../$(OUT_CHECKSUMS)
185 | cd ../
186 |
187 | .PHONY: publish
188 | publish: \
189 | $(OUTPUT_DIR) \
190 | $(OUT_ARCHIVE) \
191 | $(OUT_ARCHIVE_ANDROID) \
192 | $(OUT_CHECKSUMS) \
193 | | .check_tree \
194 | .check_$(CMD_GITHUB)
195 | #
196 | # release it!
197 | $(CMD_GITHUB) release create $(SNAPSHOT_VERSION) $(OUT_ARCHIVE) $(OUT_ARCHIVE_ANDROID) $(OUT_CHECKSUMS) --title "RtcAgent $(SNAPSHOT_VERSION)" --notes-file $(RELEASE_NOTES)
198 |
199 | .PHONY: clean
200 | clean:
201 | #
202 | $(MAKE) clean
203 |
--------------------------------------------------------------------------------
/builder/gen_android_nocore.sh:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env bash
2 | # bash builder/gen_android_nocore.sh 1.0.0
3 | SHELL_GH=gh
4 |
5 | # Android nocore ubnutu 20.04 ARM
6 | UNAME_M=`uname -m`
7 | OUTPUT_DIR="./bin"
8 | SNAPSHOT_VERSION=v${1}
9 | export PATH=/usr/local/go/bin:$PATH
10 | ANDROID=1 make nocore
11 | TAR_DIR=rtcagent-android-${UNAME_M}_nocore-${SNAPSHOT_VERSION}
12 |
13 | # rtcagent-v0.4.8-android-x86_64.tar.gz
14 | OUT_ARCHIVE=${OUTPUT_DIR}/rtcagent-${SNAPSHOT_VERSION}-android-${UNAME_M}-nocore.tar.gz
15 |
16 | # add gobin into $PATH
17 | mkdir -p ${TAR_DIR}
18 | cp LICENSE ${TAR_DIR}/LICENSE
19 | cp CHANGELOG.md ${TAR_DIR}/CHANGELOG.md
20 | cp README.md ${TAR_DIR}/README.md
21 | cp README_CN.md ${TAR_DIR}/README_CN.md
22 | cp ${OUTPUT_DIR}/rtcagent ${TAR_DIR}/rtcagent
23 | tar -czf ${OUT_ARCHIVE} ${TAR_DIR}
24 |
25 |
26 | # upload to github
27 | ${SHELL_GH} release download ${SNAPSHOT_VERSION} -p "checksum-${SNAPSHOT_VERSION}.txt"
28 | sha256sum rtcagent-*.tar.gz >> checksum-${SNAPSHOT_VERSION}.txt
29 | files=($(ls rtcagent-*.tar.gz checksum-${SNAPSHOT_VERSION}.txt))
30 | # shellcheck disable=SC2145
31 | echo "-------------------upload files: ${files[@]} -------------------"
32 | ${SHELL_GH} release upload ${SNAPSHOT_VERSION} "${files[@]}" --clobber
33 |
--------------------------------------------------------------------------------
/builder/init_env.sh:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env bash
2 |
3 | # /bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com//sipcapture/rtcagent/master/builder/init_env.sh)"
4 |
5 | # check env
6 | release_num=$(lsb_release -r --short)
7 | if [ $? -ne 0 ]; then
8 | echo "command not found, supported ubuntu only."
9 | exit
10 | fi
11 |
12 | CLANG_NUM=12
13 | # shellcheck disable=SC2209
14 | MAKE_RTCAGENT=make
15 | if [ ${release_num} == "20.04" ]; then
16 | CLANG_NUM=9
17 | MAKE_RTCAGENT="make nocore"
18 | elif [ ${release_num} == "20.10" ]; then
19 | CLANG_NUM=10
20 | MAKE_RTCAGENT="make nocore"
21 | elif [ ${release_num} == "21.04" ]; then
22 | CLANG_NUM=11
23 | elif [ ${release_num} == "21.10" ]; then
24 | CLANG_NUM=12
25 | elif [ ${release_num} == "22.04" ]; then
26 | CLANG_NUM=12
27 | elif [ ${release_num} == "22.10" ]; then
28 | CLANG_NUM=12
29 | else
30 | echo "unsupported release version ${release_num}" && exit
31 | fi
32 |
33 | echo "CLANG_NUM=${CLANG_NUM}"
34 |
35 | UNAME_M=`uname -m`
36 | ARCH="amd64"
37 | if [[ ${UNAME_M} =~ "x86_64" ]];then
38 | ARCH="amd64"
39 | elif [[ ${UNAME_M} =~ "aarch64" ]]; then
40 | ARCH="arm64"
41 | else
42 | echo "unsupported arch ${UNAME_M}";
43 | fi
44 |
45 | GOBIN_ZIP="go1.21.12.linux-${ARCH}.tar.gz"
46 | echo "GOBIN_ZIP:${GOBIN_ZIP}"
47 |
48 | cd ~
49 |
50 | uname -a
51 | sudo apt-get update
52 |
53 | # install packages
54 | sudo apt-get install --yes build-essential pkgconf libelf-dev llvm-${CLANG_NUM} clang-${CLANG_NUM} linux-tools-common linux-tools-generic
55 | for tool in "clang" "llc" "llvm-strip"
56 | do
57 | sudo rm -f /usr/bin/$tool
58 | sudo ln -s /usr/bin/$tool-${CLANG_NUM} /usr/bin/$tool
59 | done
60 |
61 | clang --version
62 |
63 |
64 | if ! command -v go /dev/null
65 | then
66 | # install golang
67 | wget https://go.dev/dl/${GOBIN_ZIP}
68 | sudo rm -rf /usr/local/go && sudo tar -C /usr/local -xzf ${GOBIN_ZIP}
69 | export PATH=/usr/local/go/bin:$PATH
70 | fi
71 |
72 | # clone repo
73 | git clone https://github.com//sipcapture/rtcagent.git
74 | cd ./rtcagent || exit
75 | go mod tidy
76 | ${MAKE_RTCAGENT}
77 |
--------------------------------------------------------------------------------
/builder/rpmBuild.spec:
--------------------------------------------------------------------------------
1 | Name: rtcagent
2 | Version:
3 | Release:
4 | Summary: capture SIP traffic include TLS without certificate
5 | License: AGPL-3.0
6 | URL: https://www.qxip.net
7 | Source0: %{name}-%{version}.tar.gz
8 |
9 | %global _missing_build_ids_terminate_build 0
10 | %define debug_package %{nil}
11 |
12 | BuildRequires: make
13 | BuildRequires: clang
14 |
15 | %description
16 | SIP/TLS plaintext capture,
17 |
18 | supports kamailio, freeswitch, opensips
19 |
20 | %prep
21 | %setup -c
22 |
23 | %build
24 | make
25 |
26 | %install
27 | rm -rf %{buildroot}
28 | mkdir -p %{buildroot}/usr/local/bin/
29 | install -m 755 bin/rtcagent %{buildroot}/usr/local/bin/rtcagent
30 |
31 | %files
32 | /usr/local/bin/rtcagent
33 |
34 | %changelog
35 |
--------------------------------------------------------------------------------
/cli/cmd/freeswitch.go:
--------------------------------------------------------------------------------
1 | //go:build !androidgki
2 | // +build !androidgki
3 |
4 | /*
5 | LINK - http://github.com/sipcapture/rtcagent
6 |
7 | Copyright (C) 2023 QXIP B.V.
8 |
9 | This program is free software: you can redistribute it and/or modify
10 | it under the terms of the GNU Affero General Public License as published by
11 | the Free Software Foundation, either version 3 of the License, or
12 | (at your option) any later version.
13 |
14 | This program is distributed in the hope that it will be useful,
15 | but WITHOUT ANY WARRANTY; without even the implied warranty of
16 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 | GNU Affero General Public License for more details.
18 |
19 | You should have received a copy of the GNU Affero General Public License
20 | along with this program. If not, see .
21 | */
22 |
23 | package cmd
24 |
25 | import (
26 | "context"
27 | "log"
28 | "os"
29 | "os/signal"
30 | "rtcagent/hepclient"
31 | "rtcagent/hepclient/hepsender"
32 | "rtcagent/user/config"
33 | "rtcagent/user/module"
34 | "strings"
35 | "syscall"
36 |
37 | "github.com/spf13/cobra"
38 | )
39 |
40 | var freeswitchConfig = config.NewFreeSwitchConfig()
41 |
42 | // freeswitchCmd represents the freeswitch command
43 | var freeswitchCmd = &cobra.Command{
44 | Use: "freeswitch",
45 | Short: "capture SIP messages from freeswitch (libsofia): t_port, su_recv.",
46 | Long: ` Tested on freeswitch 1.x`,
47 | Run: freeswitchCommandFunc,
48 | }
49 |
50 | func init() {
51 | freeswitchCmd.PersistentFlags().StringVarP(&freeswitchConfig.FreeSwitchpath, "lib-sofia", "m", "/usr/local/lib/libsofia-sip-ua.so.0", "libsofia file path, use to hook")
52 | rootCmd.AddCommand(freeswitchCmd)
53 | }
54 |
55 | // freeswitchCommandFunc executes the "freeswitch" command.
56 | func freeswitchCommandFunc(command *cobra.Command, args []string) {
57 | stopper := make(chan os.Signal, 1)
58 | signal.Notify(stopper, os.Interrupt, syscall.SIGTERM)
59 | ctx, cancelFun := context.WithCancel(context.TODO())
60 |
61 | mod := module.GetModuleByName(module.ModuleNameFreeSwitch)
62 |
63 | logger := log.New(os.Stdout, "freeswitch_", log.LstdFlags)
64 | logger.Printf("RTCAGENT :: version :%s", GitVersion)
65 | logger.Printf("RTCAGENT :: start to run %s module", mod.Name())
66 |
67 | // save global config
68 | gConf, e := getGlobalConf(command)
69 | if e != nil {
70 | logger.Fatal(e)
71 | os.Exit(1)
72 | }
73 | freeswitchConfig.Pid = gConf.Pid
74 | freeswitchConfig.Debug = gConf.Debug
75 | freeswitchConfig.IsHex = gConf.IsHex
76 |
77 | if (gConf.HepServer != "" || len(strings.TrimSpace(gConf.HepServer)) > 0) && hepsender.Hepsender == nil {
78 |
79 | log.Println("HEP client will be started")
80 |
81 | var err error
82 | hepsender.Hepsender, err = hepclient.NewHepClient(gConf.HepServer, gConf.HepPort, gConf.HepTransport)
83 | if err != nil {
84 | log.Fatalf("HEP client couldn't be init: addr:%s, port: %s, transport: %s. Error: %s", gConf.HepServer, gConf.HepPort, gConf.HepTransport, err.Error())
85 | os.Exit(1)
86 | } else {
87 | log.Println("HEP client started")
88 | }
89 | }
90 |
91 | log.Printf("RTCAGENT :: pid info :%d -%s", os.Getpid(), gConf.HepServer)
92 | //bc.Pid = globalFlags.Pid
93 | if e := freeswitchConfig.Check(); e != nil {
94 | logger.Fatal(e)
95 | os.Exit(1)
96 | }
97 |
98 | err := mod.Init(ctx, logger, freeswitchConfig)
99 | if err != nil {
100 | logger.Fatal(err)
101 | os.Exit(1)
102 | }
103 |
104 | go func(module module.IModule) {
105 | err := module.Run()
106 | if err != nil {
107 | logger.Fatalf("%v", err)
108 | }
109 | }(mod)
110 | <-stopper
111 | cancelFun()
112 | os.Exit(0)
113 | }
114 |
--------------------------------------------------------------------------------
/cli/cmd/global.go:
--------------------------------------------------------------------------------
1 | /*
2 | LINK - http://github.com/sipcapture/rtcagent
3 |
4 | Copyright (C) 2023 QXIP B.V.
5 |
6 | This program is free software: you can redistribute it and/or modify
7 | it under the terms of the GNU Affero General Public License as published by
8 | the Free Software Foundation, either version 3 of the License, or
9 | (at your option) any later version.
10 |
11 | This program is distributed in the hope that it will be useful,
12 | but WITHOUT ANY WARRANTY; without even the implied warranty of
13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 | GNU Affero General Public License for more details.
15 |
16 | You should have received a copy of the GNU Affero General Public License
17 | along with this program. If not, see .
18 | */
19 | package cmd
20 |
21 | import (
22 | "github.com/spf13/cobra"
23 | )
24 |
25 | // GlobalFlags are flags that defined globally
26 | // and are inherited to all sub-commands.
27 | type GlobalFlags struct {
28 | IsHex bool
29 | Debug bool
30 | Pid uint64 // PID
31 | Uid uint64 // UID
32 | NoSearch bool // No lib search
33 | loggerFile string // save file
34 | HepServer string
35 | HepPort string
36 | HepTransport string
37 | HepEnable bool
38 | }
39 |
40 | func getGlobalConf(command *cobra.Command) (conf GlobalFlags, err error) {
41 | conf.Pid, err = command.Flags().GetUint64("pid")
42 | if err != nil {
43 | return
44 | }
45 |
46 | conf.Uid, err = command.Flags().GetUint64("uid")
47 | if err != nil {
48 | return
49 | }
50 |
51 | conf.Debug, err = command.Flags().GetBool("debug")
52 | if err != nil {
53 | return
54 | }
55 |
56 | conf.IsHex, err = command.Flags().GetBool("hex")
57 | if err != nil {
58 | return
59 | }
60 |
61 | conf.NoSearch, err = command.Flags().GetBool("nosearch")
62 | if err != nil {
63 | return
64 | }
65 |
66 | conf.loggerFile, err = command.Flags().GetString("log-file")
67 | if err != nil {
68 | return
69 | }
70 |
71 | conf.HepServer, err = command.Flags().GetString("hep-server")
72 | if err != nil {
73 | return
74 | }
75 |
76 | conf.HepPort, err = command.Flags().GetString("hep-port")
77 | if err != nil {
78 | return
79 | }
80 |
81 | conf.HepTransport, err = command.Flags().GetString("hep-transport")
82 | if err != nil {
83 | return
84 | }
85 |
86 | return
87 | }
88 |
--------------------------------------------------------------------------------
/cli/cmd/kamailio.go:
--------------------------------------------------------------------------------
1 | //go:build !androidgki
2 | // +build !androidgki
3 |
4 | /*
5 | LINK - http://github.com/sipcapture/rtcagent
6 |
7 | Copyright (C) 2023 QXIP B.V.
8 |
9 | This program is free software: you can redistribute it and/or modify
10 | it under the terms of the GNU Affero General Public License as published by
11 | the Free Software Foundation, either version 3 of the License, or
12 | (at your option) any later version.
13 |
14 | This program is distributed in the hope that it will be useful,
15 | but WITHOUT ANY WARRANTY; without even the implied warranty of
16 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 | GNU Affero General Public License for more details.
18 |
19 | You should have received a copy of the GNU Affero General Public License
20 | along with this program. If not, see .
21 | */
22 |
23 | package cmd
24 |
25 | import (
26 | "context"
27 | "log"
28 | "os"
29 | "os/signal"
30 | "rtcagent/hepclient"
31 | "rtcagent/hepclient/hepsender"
32 | "rtcagent/user/config"
33 | "rtcagent/user/module"
34 | "strings"
35 | "syscall"
36 |
37 | "github.com/spf13/cobra"
38 | )
39 |
40 | var kamailioConfig = config.NewKamailioConfig()
41 |
42 | // kamailioCmd represents the kamailio command
43 | var kamailioCmd = &cobra.Command{
44 | Use: "kamailio",
45 | Short: "capture SIP messages from kamailio: recv_msg, udp_send, tcp_send.",
46 | Long: ` Tested on kamailio 5.x`,
47 | Run: kamailioCommandFunc,
48 | }
49 |
50 | func init() {
51 | kamailioCmd.PersistentFlags().StringVarP(&kamailioConfig.Kamailiopath, "kamailio", "m", "/usr/sbin/kamailio", "kamailio binary file path, use to hook")
52 | rootCmd.AddCommand(kamailioCmd)
53 | }
54 |
55 | // kamailioCommandFunc executes the "kamailio" command.
56 | func kamailioCommandFunc(command *cobra.Command, args []string) {
57 | stopper := make(chan os.Signal, 1)
58 | signal.Notify(stopper, os.Interrupt, syscall.SIGTERM)
59 | ctx, cancelFun := context.WithCancel(context.TODO())
60 |
61 | mod := module.GetModuleByName(module.ModuleNameKamailio)
62 |
63 | logger := log.New(os.Stdout, "kamailio_", log.LstdFlags)
64 | logger.Printf("RTCAGENT :: version :%s", GitVersion)
65 | logger.Printf("RTCAGENT :: start to run %s module", mod.Name())
66 |
67 | // save global config
68 | gConf, e := getGlobalConf(command)
69 | if e != nil {
70 | logger.Fatal(e)
71 | os.Exit(1)
72 | }
73 | kamailioConfig.Pid = gConf.Pid
74 | kamailioConfig.Debug = gConf.Debug
75 | kamailioConfig.IsHex = gConf.IsHex
76 | kamailioConfig.NoSearch = gConf.NoSearch
77 |
78 | logger.Printf("RTCAGENT :: kamailio - nosearch: %v", kamailioConfig.NoSearch)
79 |
80 | if (gConf.HepServer != "" || len(strings.TrimSpace(gConf.HepServer)) > 0) && hepsender.Hepsender == nil {
81 |
82 | log.Println("HEP client will be started")
83 |
84 | var err error
85 | hepsender.Hepsender, err = hepclient.NewHepClient(gConf.HepServer, gConf.HepPort, gConf.HepTransport)
86 | if err != nil {
87 | log.Fatalf("HEP client couldn't be init: addr:%s, port: %s, transport: %s. Error: %s", gConf.HepServer, gConf.HepPort, gConf.HepTransport, err.Error())
88 | os.Exit(1)
89 | } else {
90 | log.Println("HEP client started")
91 | }
92 | }
93 |
94 | log.Printf("RTCAGENT :: pid info :%d -%s", os.Getpid(), gConf.HepServer)
95 | //bc.Pid = globalFlags.Pid
96 | if e := kamailioConfig.Check(); e != nil {
97 | logger.Fatal(e)
98 | os.Exit(1)
99 | }
100 |
101 | err := mod.Init(ctx, logger, kamailioConfig)
102 | if err != nil {
103 | logger.Fatal(err)
104 | os.Exit(1)
105 | }
106 |
107 | go func(module module.IModule) {
108 | err := module.Run()
109 | if err != nil {
110 | logger.Fatalf("%v", err)
111 | }
112 | }(mod)
113 | <-stopper
114 | cancelFun()
115 | os.Exit(0)
116 | }
117 |
--------------------------------------------------------------------------------
/cli/cmd/monitor.go:
--------------------------------------------------------------------------------
1 | //go:build !androidgki
2 | // +build !androidgki
3 |
4 | /*
5 | LINK - http://github.com/sipcapture/rtcagent
6 |
7 | Copyright (C) 2023 QXIP B.V.
8 |
9 | This program is free software: you can redistribute it and/or modify
10 | it under the terms of the GNU Affero General Public License as published by
11 | the Free Software Foundation, either version 3 of the License, or
12 | (at your option) any later version.
13 |
14 | This program is distributed in the hope that it will be useful,
15 | but WITHOUT ANY WARRANTY; without even the implied warranty of
16 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 | GNU Affero General Public License for more details.
18 |
19 | You should have received a copy of the GNU Affero General Public License
20 | along with this program. If not, see .
21 | */
22 |
23 | package cmd
24 |
25 | import (
26 | "context"
27 | "log"
28 | "os"
29 | "os/signal"
30 | "rtcagent/hepclient"
31 | "rtcagent/hepclient/hepsender"
32 | "rtcagent/metric"
33 | "rtcagent/user/config"
34 | "rtcagent/user/module"
35 | "strings"
36 | "syscall"
37 |
38 | "github.com/spf13/cobra"
39 | )
40 |
41 | var monitorConfig = config.NewMonitorConfig()
42 |
43 | // monitorCmd represents the monitor command
44 | var monitorCmd = &cobra.Command{
45 | Use: "monitor",
46 | Short: "show stats",
47 | Long: ` Tested on linux`,
48 | Run: monitorCommandFunc,
49 | }
50 |
51 | func init() {
52 | monitorCmd.PersistentFlags().StringVarP(&monitorConfig.Monitorpath, "binary", "b", "", "monitor binary file path, use to hook")
53 | monitorCmd.PersistentFlags().BoolVarP(&monitorConfig.SysCall, "syscall", "", false, "monitor syscall")
54 | monitorCmd.PersistentFlags().BoolVarP(&monitorConfig.UserCall, "usercall", "", false, "monitor usercall")
55 | monitorCmd.PersistentFlags().BoolVarP(&monitorConfig.NetworkCall, "networkcall", "", false, "monitor networkcall")
56 | monitorCmd.PersistentFlags().StringSliceVarP(&monitorConfig.UserFunctions, "functions", "f", nil, "monitor user functions")
57 | monitorCmd.PersistentFlags().BoolVarP(&monitorConfig.ShowUserFunction, "show-user-functions", "", false, "show user functions")
58 |
59 | rootCmd.AddCommand(monitorCmd)
60 | }
61 |
62 | // monitorCommandFunc executes the "monitor" command.
63 | func monitorCommandFunc(command *cobra.Command, args []string) {
64 | stopper := make(chan os.Signal, 1)
65 | signal.Notify(stopper, os.Interrupt, syscall.SIGTERM)
66 | ctx, cancelFun := context.WithCancel(context.TODO())
67 |
68 | mod := module.GetModuleByName(module.ModuleNameMonitor)
69 |
70 | logger := log.New(os.Stdout, "monitor_", log.LstdFlags)
71 | logger.Printf("RTCAGENT :: version :%s", GitVersion)
72 | logger.Printf("RTCAGENT :: start to run %s module", mod.Name())
73 |
74 | // save global config
75 | gConf, e := getGlobalConf(command)
76 | if e != nil {
77 | logger.Fatal(e)
78 | os.Exit(1)
79 | }
80 | monitorConfig.Pid = gConf.Pid
81 | monitorConfig.Debug = gConf.Debug
82 | monitorConfig.IsHex = gConf.IsHex
83 |
84 | if (gConf.HepServer != "" || len(strings.TrimSpace(gConf.HepServer)) > 0) && hepsender.Hepsender == nil {
85 |
86 | log.Println("HEP client will be started")
87 |
88 | var err error
89 | hepsender.Hepsender, err = hepclient.NewHepClient(gConf.HepServer, gConf.HepPort, gConf.HepTransport)
90 | if err != nil {
91 | log.Fatalf("HEP client couldn't be init: addr:%s, port: %s, transport: %s. Error: %s", gConf.HepServer, gConf.HepPort, gConf.HepTransport, err.Error())
92 | os.Exit(1)
93 | } else {
94 | log.Println("HEP client started")
95 | }
96 | }
97 |
98 | log.Printf("RTCAGENT :: pid info :%d -%s", os.Getpid(), gConf.HepServer)
99 | if e := monitorConfig.Check(); e != nil {
100 | logger.Fatal(e)
101 | os.Exit(1)
102 | }
103 |
104 | err := mod.Init(ctx, logger, monitorConfig)
105 | if err != nil {
106 | logger.Fatal(err)
107 | os.Exit(1)
108 | }
109 |
110 | m := metric.New("prometheus")
111 | m.Chan = monitorConfig.PromCh
112 |
113 | if err := m.Run(); err != nil {
114 | log.Printf("Error: %v", err)
115 | }
116 | defer m.End()
117 |
118 | go func(module module.IModule) {
119 | err := module.Run()
120 | if err != nil {
121 | logger.Fatalf("%v", err)
122 | }
123 | }(mod)
124 | <-stopper
125 |
126 | cancelFun()
127 | os.Exit(0)
128 | }
129 |
--------------------------------------------------------------------------------
/cli/cmd/opensips.go:
--------------------------------------------------------------------------------
1 | //go:build !androidgki
2 | // +build !androidgki
3 |
4 | /*
5 | LINK - http://github.com/sipcapture/rtcagent
6 |
7 | Copyright (C) 2023 QXIP B.V.
8 |
9 | This program is free software: you can redistribute it and/or modify
10 | it under the terms of the GNU Affero General Public License as published by
11 | the Free Software Foundation, either version 3 of the License, or
12 | (at your option) any later version.
13 |
14 | This program is distributed in the hope that it will be useful,
15 | but WITHOUT ANY WARRANTY; without even the implied warranty of
16 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 | GNU Affero General Public License for more details.
18 |
19 | You should have received a copy of the GNU Affero General Public License
20 | along with this program. If not, see .
21 | */
22 |
23 | package cmd
24 |
25 | import (
26 | "context"
27 | "log"
28 | "os"
29 | "os/signal"
30 | "rtcagent/hepclient"
31 | "rtcagent/hepclient/hepsender"
32 | "rtcagent/user/config"
33 | "rtcagent/user/module"
34 | "strings"
35 | "syscall"
36 |
37 | "github.com/spf13/cobra"
38 | )
39 |
40 | var opensipsConfig = config.NewOpensipsConfig()
41 |
42 | // opensipsCmd represents the opensips command
43 | var opensipsCmd = &cobra.Command{
44 | Use: "opensips",
45 | Short: "capture SIP messages from opensips: recv_msg, udp_send, tcp_send.",
46 | Long: ` Tested on opensips 3.x`,
47 | Run: opensipsCommandFunc,
48 | }
49 |
50 | func init() {
51 | opensipsCmd.PersistentFlags().StringVarP(&opensipsConfig.Opensipspath, "opensips", "m", "/usr/sbin/opensips", "opensips binary file path, use to hook")
52 | rootCmd.AddCommand(opensipsCmd)
53 | }
54 |
55 | // opensipsCommandFunc executes the "opensips" command.
56 | func opensipsCommandFunc(command *cobra.Command, args []string) {
57 | stopper := make(chan os.Signal, 1)
58 | signal.Notify(stopper, os.Interrupt, syscall.SIGTERM)
59 | ctx, cancelFun := context.WithCancel(context.TODO())
60 |
61 | mod := module.GetModuleByName(module.ModuleNameOpensips)
62 |
63 | logger := log.New(os.Stdout, "opensips_", log.LstdFlags)
64 | logger.Printf("RTCAGENT :: version :%s", GitVersion)
65 | logger.Printf("RTCAGENT :: start to run %s module", mod.Name())
66 |
67 | // save global config
68 | gConf, e := getGlobalConf(command)
69 | if e != nil {
70 | logger.Fatal(e)
71 | os.Exit(1)
72 | }
73 | opensipsConfig.Pid = gConf.Pid
74 | opensipsConfig.Debug = gConf.Debug
75 | opensipsConfig.IsHex = gConf.IsHex
76 | opensipsConfig.NoSearch = gConf.NoSearch
77 |
78 | logger.Printf("RTCAGENT :: opensips - nosearch: %v", opensipsConfig.NoSearch)
79 |
80 | if (gConf.HepServer != "" || len(strings.TrimSpace(gConf.HepServer)) > 0) && hepsender.Hepsender == nil {
81 |
82 | log.Println("HEP client will be started")
83 |
84 | var err error
85 | hepsender.Hepsender, err = hepclient.NewHepClient(gConf.HepServer, gConf.HepPort, gConf.HepTransport)
86 | if err != nil {
87 | log.Fatalf("HEP client couldn't be init: addr:%s, port: %s, transport: %s. Error: %s", gConf.HepServer, gConf.HepPort, gConf.HepTransport, err.Error())
88 | os.Exit(1)
89 | } else {
90 | log.Println("HEP client started")
91 | }
92 | }
93 |
94 | log.Printf("RTCAGENT :: pid info :%d -%s", os.Getpid(), gConf.HepServer)
95 | //bc.Pid = globalFlags.Pid
96 | if e := opensipsConfig.Check(); e != nil {
97 | logger.Fatal(e)
98 | os.Exit(1)
99 | }
100 |
101 | err := mod.Init(ctx, logger, opensipsConfig)
102 | if err != nil {
103 | logger.Fatal(err)
104 | os.Exit(1)
105 | }
106 |
107 | go func(module module.IModule) {
108 | err := module.Run()
109 | if err != nil {
110 | logger.Fatalf("%v", err)
111 | }
112 | }(mod)
113 | <-stopper
114 | cancelFun()
115 | os.Exit(0)
116 | }
117 |
--------------------------------------------------------------------------------
/cli/cmd/root.go:
--------------------------------------------------------------------------------
1 | /*
2 | LINK - http://github.com/sipcapture/rtcagent
3 |
4 | Copyright (C) 2023 QXIP B.V.
5 |
6 | This program is free software: you can redistribute it and/or modify
7 | it under the terms of the GNU Affero General Public License as published by
8 | the Free Software Foundation, either version 3 of the License, or
9 | (at your option) any later version.
10 |
11 | This program is distributed in the hope that it will be useful,
12 | but WITHOUT ANY WARRANTY; without even the implied warranty of
13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 | GNU Affero General Public License for more details.
15 |
16 | You should have received a copy of the GNU Affero General Public License
17 | along with this program. If not, see .
18 | */
19 |
20 | package cmd
21 |
22 | import (
23 | "os"
24 | "rtcagent/cli/cobrautl"
25 |
26 | "github.com/spf13/cobra"
27 | )
28 |
29 | const (
30 | cliName = "rtcagent"
31 | cliDescription = "Capture and debug RTC Projects."
32 | )
33 |
34 | var (
35 | GitVersion = "v0.0.2"
36 | //ReleaseDate = "2022-03-16"
37 | )
38 |
39 | const (
40 | defaultPid uint64 = 0
41 | defaultUid uint64 = 0
42 | )
43 |
44 | // rootCmd represents the base command when called without any subcommands
45 | var rootCmd = &cobra.Command{
46 | Use: cliName,
47 | Short: cliDescription,
48 | SuggestFor: []string{"rtcagent"},
49 |
50 | Long: `RTCAgent is a tool that can capture and trace SIP packets by hijacking application's function like kamailio, freeswitch, opensips, monitor
51 | it can also make tcprtt statics on the server.
52 |
53 | Repository: https://github.com//sipcapture/rtcagent
54 | HomePage: https://www.qxip.net
55 |
56 | Usage:
57 | rtcagent kamailio -h
58 | rtcagent freeswitch -h
59 | rtcagent opensips -h
60 | `,
61 | }
62 |
63 | func usageFunc(c *cobra.Command) error {
64 | return cobrautl.UsageFunc(c, GitVersion)
65 | }
66 |
67 | // Execute adds all child commands to the root command and sets flags appropriately.
68 | // This is called by main.main(). It only needs to happen once to the rootCmd.
69 | func Execute() {
70 | rootCmd.SetUsageFunc(usageFunc)
71 | rootCmd.SetHelpTemplate(`{{.UsageString}}`)
72 | rootCmd.CompletionOptions.DisableDefaultCmd = true
73 | rootCmd.Version = GitVersion
74 | rootCmd.SetVersionTemplate(`{{with .Name}}{{printf "%s " .}}{{end}}{{printf "version:\t%s" .Version}}
75 | `)
76 |
77 | err := rootCmd.Execute()
78 | if err != nil {
79 | os.Exit(1)
80 | }
81 |
82 | }
83 |
84 | func init() {
85 | cobra.EnablePrefixMatching = true
86 | var globalFlags = GlobalFlags{}
87 |
88 | //rootCmd.Flags().BoolP("toggle", "t", false, "Help message for toggle")
89 | rootCmd.PersistentFlags().BoolVarP(&globalFlags.Debug, "debug", "d", false, "enable debug logging")
90 | rootCmd.PersistentFlags().BoolVar(&globalFlags.IsHex, "hex", false, "print byte strings as hex encoded strings")
91 | rootCmd.PersistentFlags().BoolVar(&globalFlags.NoSearch, "nosearch", false, "no lib search")
92 | rootCmd.PersistentFlags().Uint64VarP(&globalFlags.Pid, "pid", "p", defaultPid, "if pid is 0 then we target all pids")
93 | rootCmd.PersistentFlags().Uint64VarP(&globalFlags.Uid, "uid", "u", defaultUid, "if uid is 0 then we target all users")
94 | rootCmd.PersistentFlags().StringVarP(&globalFlags.loggerFile, "log-file", "l", "", "-l save the packets to file")
95 | rootCmd.PersistentFlags().StringVarP(&globalFlags.HepServer, "hep-server", "S", "", "hep server to duplicate: i.e. 10.0.0.1")
96 | rootCmd.PersistentFlags().StringVarP(&globalFlags.HepPort, "hep-port", "P", "9060", "hep port - default 9060")
97 | rootCmd.PersistentFlags().StringVarP(&globalFlags.HepTransport, "hep-transport", "T", "udp", "hep transport default udp. Can be udp, tcp, tls")
98 |
99 | }
100 |
--------------------------------------------------------------------------------
/cli/cmd/tcprtt.go:
--------------------------------------------------------------------------------
1 | //go:build !androidgki
2 | // +build !androidgki
3 |
4 | /*
5 | LINK - http://github.com/sipcapture/rtcagent
6 |
7 | Copyright (C) 2023 QXIP B.V.
8 |
9 | This program is free software: you can redistribute it and/or modify
10 | it under the terms of the GNU Affero General Public License as published by
11 | the Free Software Foundation, either version 3 of the License, or
12 | (at your option) any later version.
13 |
14 | This program is distributed in the hope that it will be useful,
15 | but WITHOUT ANY WARRANTY; without even the implied warranty of
16 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 | GNU Affero General Public License for more details.
18 |
19 | You should have received a copy of the GNU Affero General Public License
20 | along with this program. If not, see .
21 | */
22 |
23 | package cmd
24 |
25 | import (
26 | "context"
27 | "log"
28 | "os"
29 | "os/signal"
30 | "rtcagent/hepclient"
31 | "rtcagent/hepclient/hepsender"
32 | "rtcagent/user/config"
33 | "rtcagent/user/module"
34 | "strings"
35 | "syscall"
36 |
37 | "github.com/spf13/cobra"
38 | )
39 |
40 | var tcprttConfig = config.NewTcprttConfig()
41 |
42 | // tcprttCmd represents the tcprtt command
43 | var tcprttCmd = &cobra.Command{
44 | Use: "tcprtt",
45 | Short: "show tcp rtt",
46 | Long: ` Tested on linux`,
47 | Run: tcprttCommandFunc,
48 | }
49 |
50 | func init() {
51 | tcprttCmd.PersistentFlags().StringVarP(&tcprttConfig.Tcprttpath, "tcprtt", "m", "", "tcprtt binary file path, use to hook")
52 | rootCmd.AddCommand(tcprttCmd)
53 | }
54 |
55 | // tcprttCommandFunc executes the "tcprtt" command.
56 | func tcprttCommandFunc(command *cobra.Command, args []string) {
57 | stopper := make(chan os.Signal, 1)
58 | signal.Notify(stopper, os.Interrupt, syscall.SIGTERM)
59 | ctx, cancelFun := context.WithCancel(context.TODO())
60 |
61 | mod := module.GetModuleByName(module.ModuleNameTcprtt)
62 |
63 | logger := log.New(os.Stdout, "tcprtt_", log.LstdFlags)
64 | logger.Printf("RTCAGENT :: version :%s", GitVersion)
65 | logger.Printf("RTCAGENT :: start to run %s module", mod.Name())
66 |
67 | // save global config
68 | gConf, e := getGlobalConf(command)
69 | if e != nil {
70 | logger.Fatal(e)
71 | os.Exit(1)
72 | }
73 | tcprttConfig.Pid = gConf.Pid
74 | tcprttConfig.Debug = gConf.Debug
75 | tcprttConfig.IsHex = gConf.IsHex
76 |
77 | if (gConf.HepServer != "" || len(strings.TrimSpace(gConf.HepServer)) > 0) && hepsender.Hepsender == nil {
78 |
79 | log.Println("HEP client will be started")
80 |
81 | var err error
82 | hepsender.Hepsender, err = hepclient.NewHepClient(gConf.HepServer, gConf.HepPort, gConf.HepTransport)
83 | if err != nil {
84 | log.Fatalf("HEP client couldn't be init: addr:%s, port: %s, transport: %s. Error: %s", gConf.HepServer, gConf.HepPort, gConf.HepTransport, err.Error())
85 | os.Exit(1)
86 | } else {
87 | log.Println("HEP client started")
88 | }
89 | }
90 |
91 | log.Printf("RTCAGENT :: pid info :%d -%s", os.Getpid(), gConf.HepServer)
92 | //bc.Pid = globalFlags.Pid
93 | if e := tcprttConfig.Check(); e != nil {
94 | logger.Fatal(e)
95 | os.Exit(1)
96 | }
97 |
98 | err := mod.Init(ctx, logger, tcprttConfig)
99 | if err != nil {
100 | logger.Fatal(err)
101 | os.Exit(1)
102 | }
103 |
104 | go func(module module.IModule) {
105 | err := module.Run()
106 | if err != nil {
107 | logger.Fatalf("%v", err)
108 | }
109 | }(mod)
110 | <-stopper
111 | cancelFun()
112 | os.Exit(0)
113 | }
114 |
--------------------------------------------------------------------------------
/cli/cobrautl/help.go:
--------------------------------------------------------------------------------
1 | /*
2 |
3 | LINK - http://github.com/sipcapture/rtcagent
4 |
5 | Copyright (C) 2023 QXIP B.V.
6 |
7 | This program is free software: you can redistribute it and/or modify
8 | it under the terms of the GNU Affero General Public License as published by
9 | the Free Software Foundation, either version 3 of the License, or
10 | (at your option) any later version.
11 |
12 | This program is distributed in the hope that it will be useful,
13 | but WITHOUT ANY WARRANTY; without even the implied warranty of
14 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 | GNU Affero General Public License for more details.
16 |
17 | You should have received a copy of the GNU Affero General Public License
18 | along with this program. If not, see .
19 |
20 | */
21 |
22 | package cobrautl
23 |
24 | import (
25 | "bytes"
26 | "fmt"
27 | "io"
28 | "os"
29 | "strings"
30 | "text/tabwriter"
31 | "text/template"
32 |
33 | "github.com/spf13/cobra"
34 | "github.com/spf13/pflag"
35 | )
36 |
37 | var (
38 | commandUsageTemplate *template.Template
39 | templFuncs = template.FuncMap{
40 | "descToLines": func(s string) []string {
41 | // trim leading/trailing whitespace and split into slice of lines
42 | return strings.Split(strings.Trim(s, "\n\t "), "\n")
43 | },
44 | "cmdName": func(cmd *cobra.Command, startCmd *cobra.Command) string {
45 | parts := []string{cmd.Name()}
46 | for cmd.HasParent() && cmd.Parent().Name() != startCmd.Name() {
47 | cmd = cmd.Parent()
48 | parts = append([]string{cmd.Name()}, parts...)
49 | }
50 | return strings.Join(parts, " ")
51 | },
52 | }
53 | )
54 |
55 | func init() {
56 | commandUsage := `
57 | {{ $cmd := .Cmd }}\
58 | {{ $cmdname := cmdName .Cmd .Cmd.Root }}\
59 | NAME:
60 | {{ if not .Cmd.HasParent }}\
61 | {{printf "\t%s - %s" .Cmd.Name .Cmd.Short}}
62 | {{else}}\
63 | {{printf "\t%s - %s" $cmdname .Cmd.Short}}
64 | {{end}}\
65 |
66 | USAGE:
67 | {{printf "\t%s" .Cmd.UseLine}}
68 | {{ if not .Cmd.HasParent }}\
69 |
70 | VERSION:
71 | {{printf "\t%s" .Version}}
72 | {{end}}\
73 | {{if .Cmd.HasSubCommands}}\
74 |
75 | COMMANDS:
76 | {{range .SubCommands}}\
77 | {{ $cmdname := cmdName . $cmd }}\
78 | {{ if .Runnable }}\
79 | {{printf "\t%s\t%s" $cmdname .Short}}
80 | {{end}}\
81 | {{end}}\
82 | {{end}}\
83 | {{ if .Cmd.Long }}\
84 |
85 | DESCRIPTION:
86 | {{range $line := descToLines .Cmd.Long}}{{printf "\t%s" $line}}
87 | {{end}}\
88 | {{end}}\
89 | {{if .Cmd.HasLocalFlags}}\
90 |
91 | OPTIONS:
92 | {{.LocalFlags}}\
93 | {{end}}\
94 | {{if .Cmd.HasInheritedFlags}}\
95 |
96 | GLOBAL OPTIONS:
97 | {{.GlobalFlags}}\
98 | {{end}}
99 | `[1:]
100 |
101 | commandUsageTemplate = template.Must(template.New("command_usage").Funcs(templFuncs).Parse(strings.Replace(commandUsage, "\\\n", "", -1)))
102 | }
103 |
104 | func rtcagentFlagUsages(flagSet *pflag.FlagSet) string {
105 | x := new(bytes.Buffer)
106 |
107 | flagSet.VisitAll(func(flag *pflag.Flag) {
108 | if len(flag.Deprecated) > 0 {
109 | return
110 | }
111 | var format string
112 | if len(flag.Shorthand) > 0 {
113 | format = " -%s, --%s"
114 | } else {
115 | format = " %s --%s"
116 | }
117 | if len(flag.NoOptDefVal) > 0 {
118 | format = format + "["
119 | }
120 | if flag.Value.Type() == "string" {
121 | // put quotes on the value
122 | format = format + "=%q"
123 | } else {
124 | format = format + "=%s"
125 | }
126 | if len(flag.NoOptDefVal) > 0 {
127 | format = format + "]"
128 | }
129 | format = format + "\t%s\n"
130 | shorthand := flag.Shorthand
131 | fmt.Fprintf(x, format, shorthand, flag.Name, flag.DefValue, flag.Usage)
132 | })
133 |
134 | return x.String()
135 | }
136 |
137 | func getSubCommands(cmd *cobra.Command) []*cobra.Command {
138 | var subCommands []*cobra.Command
139 | for _, subCmd := range cmd.Commands() {
140 | subCommands = append(subCommands, subCmd)
141 | subCommands = append(subCommands, getSubCommands(subCmd)...)
142 | }
143 | return subCommands
144 | }
145 |
146 | func UsageFunc(cmd *cobra.Command, version string) error {
147 | subCommands := getSubCommands(cmd)
148 | tabOut := getTabOutWithWriter(os.Stdout)
149 | err := commandUsageTemplate.Execute(tabOut, struct {
150 | Cmd *cobra.Command
151 | LocalFlags string
152 | GlobalFlags string
153 | SubCommands []*cobra.Command
154 | Version string
155 | }{
156 | cmd,
157 | rtcagentFlagUsages(cmd.LocalFlags()),
158 | rtcagentFlagUsages(cmd.InheritedFlags()),
159 | subCommands,
160 | version,
161 | })
162 | if err != nil {
163 | return err
164 | }
165 | err = tabOut.Flush()
166 | return err
167 | }
168 |
169 | func getTabOutWithWriter(writer io.Writer) *tabwriter.Writer {
170 | aTabOut := new(tabwriter.Writer)
171 | aTabOut.Init(writer, 0, 8, 1, '\t', 0)
172 | return aTabOut
173 | }
174 |
--------------------------------------------------------------------------------
/cli/main.go:
--------------------------------------------------------------------------------
1 | /*
2 |
3 | LINK - http://github.com/sipcapture/rtcagent
4 |
5 | Copyright (C) 2023 QXIP B.V.
6 |
7 | This program is free software: you can redistribute it and/or modify
8 | it under the terms of the GNU Affero General Public License as published by
9 | the Free Software Foundation, either version 3 of the License, or
10 | (at your option) any later version.
11 |
12 | This program is distributed in the hope that it will be useful,
13 | but WITHOUT ANY WARRANTY; without even the implied warranty of
14 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 | GNU Affero General Public License for more details.
16 |
17 | You should have received a copy of the GNU Affero General Public License
18 | along with this program. If not, see .
19 |
20 | */
21 |
22 | package cli
23 |
24 | import (
25 | "rtcagent/cli/cmd"
26 | )
27 |
28 | func Start() {
29 | cmd.Execute()
30 | }
31 |
--------------------------------------------------------------------------------
/dump.pcap:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sipcapture/rtcagent/6e4bba460ef57079552fcd03e4b790b6a712d4c3/dump.pcap
--------------------------------------------------------------------------------
/examples/Dockerfile.kamailio:
--------------------------------------------------------------------------------
1 | FROM ghcr.io/kamailio/kamailio:5.8.0-bookworm
2 | ENV SHM_MEMORY=${SHM_MEMORY:-64}
3 | ENV PKG_MEMORY=${PKG_MEMORY:-8}
4 | RUN apt update && apt install wget \
5 | && wget https://github.com/sipcapture/rtcagent/releases/latest/download/rtcagent \
6 | && chmod +x /rtcagent \
7 | && apt-get clean && rm -rf /var/lib/apt/lists/*
8 |
9 | ENTRYPOINT kamailio -DD -E -m ${SHM_MEMORY} -M ${PKG_MEMORY} & /rtcagent kamailio -m /usr/sbin/kamailio
10 |
--------------------------------------------------------------------------------
/go.mod:
--------------------------------------------------------------------------------
1 | module rtcagent
2 |
3 | go 1.21
4 |
5 | toolchain go1.22.1
6 |
7 | require (
8 | github.com/VictoriaMetrics/fastcache v1.12.2
9 | github.com/adubovikov/ebpfmanager v0.4.7
10 | github.com/buger/goterm v1.0.4
11 | github.com/cilium/ebpf v0.12.3
12 | github.com/gogo/protobuf v1.3.2
13 | github.com/prometheus/client_golang v1.19.0
14 | github.com/shuLhan/go-bindata v4.0.0+incompatible
15 | github.com/spf13/cobra v1.4.0
16 | github.com/spf13/pflag v1.0.5
17 | golang.org/x/crypto v0.21.0
18 | golang.org/x/sys v0.18.0
19 | )
20 |
21 | require (
22 | github.com/avast/retry-go v3.0.0+incompatible // indirect
23 | github.com/beorn7/perks v1.0.1 // indirect
24 | github.com/cespare/xxhash/v2 v2.2.0 // indirect
25 | github.com/florianl/go-tc v0.4.0 // indirect
26 | github.com/golang/snappy v0.0.4 // indirect
27 | github.com/google/go-cmp v0.6.0 // indirect
28 | github.com/hashicorp/errwrap v1.0.0 // indirect
29 | github.com/hashicorp/go-multierror v1.1.1 // indirect
30 | github.com/inconshreveable/mousetrap v1.0.0 // indirect
31 | github.com/josharian/native v1.0.0 // indirect
32 | github.com/mdlayher/netlink v1.7.1 // indirect
33 | github.com/mdlayher/socket v0.4.0 // indirect
34 | github.com/prometheus/client_model v0.5.0 // indirect
35 | github.com/prometheus/common v0.48.0 // indirect
36 | github.com/prometheus/procfs v0.12.0 // indirect
37 | github.com/stretchr/testify v1.7.0 // indirect
38 | github.com/vishvananda/netlink v1.1.0 // indirect
39 | github.com/vishvananda/netns v0.0.0-20210104183010-2eb08e3e575f // indirect
40 | golang.org/x/exp v0.0.0-20230224173230-c95f2b4c22f2 // indirect
41 | golang.org/x/net v0.23.0 // indirect
42 | golang.org/x/sync v0.3.0 // indirect
43 | google.golang.org/protobuf v1.33.0 // indirect
44 | )
45 |
46 | replace github.com/google/gopacket v1.1.19 => github.com/cfc4n/gopacket v1.1.20
47 |
--------------------------------------------------------------------------------
/hepclient/hepclient.go:
--------------------------------------------------------------------------------
1 | package hepclient
2 |
3 | import (
4 | "bufio"
5 | "crypto/tls"
6 | "fmt"
7 | "log"
8 | "net"
9 | "strings"
10 | "unicode"
11 | )
12 |
13 | type HEPConn struct {
14 | conn net.Conn
15 | writer *bufio.Writer
16 | errCnt uint
17 | }
18 | type HepClient struct {
19 | hepQueue chan []byte
20 | addr string
21 | transport string
22 | client HEPConn
23 | }
24 |
25 | func NewHepClient(addr, port, trans string) (*HepClient, error) {
26 |
27 | h := &HepClient{
28 | addr: strings.ToLower(cutSpace(addr + ":" + port)),
29 | client: HEPConn{},
30 | transport: trans,
31 | hepQueue: make(chan []byte, 20000),
32 | }
33 |
34 | if err := h.ConnectServer(); err != nil {
35 | log.Fatalf("Error: %s", err.Error())
36 | return nil, fmt.Errorf("cannot establish a connection")
37 | }
38 |
39 | go h.Start()
40 | return h, nil
41 | }
42 |
43 | func (h *HepClient) Close() {
44 | if err := h.client.conn.Close(); err != nil {
45 | log.Fatalf("cannnot close connection to %s: %v", h.addr, err)
46 | }
47 | }
48 |
49 | func (h *HepClient) ReConnect() (err error) {
50 | if err = h.ConnectServer(); err != nil {
51 | return err
52 | }
53 | h.client.writer.Reset(h.client.conn)
54 | return err
55 | }
56 |
57 | func (h *HepClient) ConnectServer() (err error) {
58 | if h.transport == "udp" {
59 |
60 | if h.client.conn, err = net.Dial("udp", h.addr); err != nil {
61 | return fmt.Errorf("dial transport failed: %s", err.Error())
62 | }
63 | } else if h.transport == "tcp" {
64 |
65 | if h.client.conn, err = net.Dial("tcp", h.addr); err != nil {
66 | return fmt.Errorf("dial transport failed: %s", err.Error())
67 | }
68 | } else if h.transport == "tls" {
69 | if h.client.conn, err = tls.Dial("tcp", h.addr, &tls.Config{InsecureSkipVerify: true}); err != nil {
70 | return fmt.Errorf("dial transport failed: %s", err.Error())
71 | }
72 | } else {
73 | return fmt.Errorf("unsupported transport: %s", h.transport)
74 | }
75 |
76 | h.client.writer = bufio.NewWriterSize(h.client.conn, 8192)
77 | return err
78 | }
79 |
80 | func (h *HepClient) Output(msg []byte) {
81 | h.hepQueue <- msg
82 | }
83 |
84 | func (h *HepClient) Send(msg []byte) {
85 | h.client.writer.Write(msg)
86 | err := h.client.writer.Flush()
87 | if err != nil {
88 | log.Fatal("%v", err)
89 | h.client.errCnt++
90 | retry := true
91 | if retry {
92 | h.client.errCnt = 0
93 | if err = h.ReConnect(); err != nil {
94 | log.Fatalf("reconnect error: %v", err)
95 | return
96 | }
97 | }
98 | }
99 | }
100 |
101 | func (h *HepClient) Start() {
102 | for msg := range h.hepQueue {
103 | h.Send(msg)
104 | }
105 | }
106 |
107 | func cutSpace(str string) string {
108 | return strings.Map(func(r rune) rune {
109 | if unicode.IsSpace(r) {
110 | return -1
111 | }
112 | return r
113 | }, str)
114 | }
115 |
--------------------------------------------------------------------------------
/hepclient/hepsender/hepsender.go:
--------------------------------------------------------------------------------
1 | package hepsender
2 |
3 | import "rtcagent/hepclient"
4 |
5 | var Hepsender *hepclient.HepClient
6 |
--------------------------------------------------------------------------------
/kern/bpf.old/arm64/vmlinux.h:
--------------------------------------------------------------------------------
1 | vmlinux_510.h
--------------------------------------------------------------------------------
/kern/bpf.old/bpf_endian.h:
--------------------------------------------------------------------------------
1 | /* SPDX-License-Identifier: (LGPL-2.1 OR BSD-2-Clause) */
2 | #ifndef __BPF_ENDIAN__
3 | #define __BPF_ENDIAN__
4 |
5 | /*
6 | * Isolate byte #n and put it into byte #m, for __u##b type.
7 | * E.g., moving byte #6 (nnnnnnnn) into byte #1 (mmmmmmmm) for __u64:
8 | * 1) xxxxxxxx nnnnnnnn xxxxxxxx xxxxxxxx xxxxxxxx xxxxxxxx mmmmmmmm xxxxxxxx
9 | * 2) nnnnnnnn xxxxxxxx xxxxxxxx xxxxxxxx xxxxxxxx mmmmmmmm xxxxxxxx 00000000
10 | * 3) 00000000 00000000 00000000 00000000 00000000 00000000 00000000 nnnnnnnn
11 | * 4) 00000000 00000000 00000000 00000000 00000000 00000000 nnnnnnnn 00000000
12 | */
13 | #define ___bpf_mvb(x, b, n, m) ((__u##b)(x) << (b-(n+1)*8) >> (b-8) << (m*8))
14 |
15 | #define ___bpf_swab16(x) ((__u16)( \
16 | ___bpf_mvb(x, 16, 0, 1) | \
17 | ___bpf_mvb(x, 16, 1, 0)))
18 |
19 | #define ___bpf_swab32(x) ((__u32)( \
20 | ___bpf_mvb(x, 32, 0, 3) | \
21 | ___bpf_mvb(x, 32, 1, 2) | \
22 | ___bpf_mvb(x, 32, 2, 1) | \
23 | ___bpf_mvb(x, 32, 3, 0)))
24 |
25 | #define ___bpf_swab64(x) ((__u64)( \
26 | ___bpf_mvb(x, 64, 0, 7) | \
27 | ___bpf_mvb(x, 64, 1, 6) | \
28 | ___bpf_mvb(x, 64, 2, 5) | \
29 | ___bpf_mvb(x, 64, 3, 4) | \
30 | ___bpf_mvb(x, 64, 4, 3) | \
31 | ___bpf_mvb(x, 64, 5, 2) | \
32 | ___bpf_mvb(x, 64, 6, 1) | \
33 | ___bpf_mvb(x, 64, 7, 0)))
34 |
35 | /* LLVM's BPF target selects the endianness of the CPU
36 | * it compiles on, or the user specifies (bpfel/bpfeb),
37 | * respectively. The used __BYTE_ORDER__ is defined by
38 | * the compiler, we cannot rely on __BYTE_ORDER from
39 | * libc headers, since it doesn't reflect the actual
40 | * requested byte order.
41 | *
42 | * Note, LLVM's BPF target has different __builtin_bswapX()
43 | * semantics. It does map to BPF_ALU | BPF_END | BPF_TO_BE
44 | * in bpfel and bpfeb case, which means below, that we map
45 | * to cpu_to_be16(). We could use it unconditionally in BPF
46 | * case, but better not rely on it, so that this header here
47 | * can be used from application and BPF program side, which
48 | * use different targets.
49 | */
50 | #if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
51 | # define __bpf_ntohs(x) __builtin_bswap16(x)
52 | # define __bpf_htons(x) __builtin_bswap16(x)
53 | # define __bpf_constant_ntohs(x) ___bpf_swab16(x)
54 | # define __bpf_constant_htons(x) ___bpf_swab16(x)
55 | # define __bpf_ntohl(x) __builtin_bswap32(x)
56 | # define __bpf_htonl(x) __builtin_bswap32(x)
57 | # define __bpf_constant_ntohl(x) ___bpf_swab32(x)
58 | # define __bpf_constant_htonl(x) ___bpf_swab32(x)
59 | # define __bpf_be64_to_cpu(x) __builtin_bswap64(x)
60 | # define __bpf_cpu_to_be64(x) __builtin_bswap64(x)
61 | # define __bpf_constant_be64_to_cpu(x) ___bpf_swab64(x)
62 | # define __bpf_constant_cpu_to_be64(x) ___bpf_swab64(x)
63 | #elif __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__
64 | # define __bpf_ntohs(x) (x)
65 | # define __bpf_htons(x) (x)
66 | # define __bpf_constant_ntohs(x) (x)
67 | # define __bpf_constant_htons(x) (x)
68 | # define __bpf_ntohl(x) (x)
69 | # define __bpf_htonl(x) (x)
70 | # define __bpf_constant_ntohl(x) (x)
71 | # define __bpf_constant_htonl(x) (x)
72 | # define __bpf_be64_to_cpu(x) (x)
73 | # define __bpf_cpu_to_be64(x) (x)
74 | # define __bpf_constant_be64_to_cpu(x) (x)
75 | # define __bpf_constant_cpu_to_be64(x) (x)
76 | #else
77 | # error "Fix your compiler's __BYTE_ORDER__?!"
78 | #endif
79 |
80 | #define bpf_htons(x) \
81 | (__builtin_constant_p(x) ? \
82 | __bpf_constant_htons(x) : __bpf_htons(x))
83 | #define bpf_ntohs(x) \
84 | (__builtin_constant_p(x) ? \
85 | __bpf_constant_ntohs(x) : __bpf_ntohs(x))
86 | #define bpf_htonl(x) \
87 | (__builtin_constant_p(x) ? \
88 | __bpf_constant_htonl(x) : __bpf_htonl(x))
89 | #define bpf_ntohl(x) \
90 | (__builtin_constant_p(x) ? \
91 | __bpf_constant_ntohl(x) : __bpf_ntohl(x))
92 | #define bpf_cpu_to_be64(x) \
93 | (__builtin_constant_p(x) ? \
94 | __bpf_constant_cpu_to_be64(x) : __bpf_cpu_to_be64(x))
95 | #define bpf_be64_to_cpu(x) \
96 | (__builtin_constant_p(x) ? \
97 | __bpf_constant_be64_to_cpu(x) : __bpf_be64_to_cpu(x))
98 |
99 | #endif /* __BPF_ENDIAN__ */
100 |
--------------------------------------------------------------------------------
/kern/bpf.old/bpf_helpers.h:
--------------------------------------------------------------------------------
1 | /* SPDX-License-Identifier: (LGPL-2.1 OR BSD-2-Clause) */
2 | #ifndef __BPF_HELPERS__
3 | #define __BPF_HELPERS__
4 |
5 | /*
6 | * Note that bpf programs need to include either
7 | * vmlinux.h (auto-generated from BTF) or linux/types.h
8 | * in advance since bpf_helper_defs.h uses such types
9 | * as __u64.
10 | */
11 | #include "bpf_helper_defs.h"
12 |
13 | #define __uint(name, val) int (*name)[val]
14 | #define __type(name, val) typeof(val) *name
15 | #define __array(name, val) typeof(val) *name[]
16 |
17 | /* Helper macro to print out debug messages */
18 | #define bpf_printk(fmt, ...) \
19 | ({ \
20 | char ____fmt[] = fmt; \
21 | bpf_trace_printk(____fmt, sizeof(____fmt), \
22 | ##__VA_ARGS__); \
23 | })
24 |
25 | /*
26 | * Helper macro to place programs, maps, license in
27 | * different sections in elf_bpf file. Section names
28 | * are interpreted by libbpf depending on the context (BPF programs, BPF maps,
29 | * extern variables, etc).
30 | * To allow use of SEC() with externs (e.g., for extern .maps declarations),
31 | * make sure __attribute__((unused)) doesn't trigger compilation warning.
32 | */
33 | #define SEC(name) \
34 | _Pragma("GCC diagnostic push") \
35 | _Pragma("GCC diagnostic ignored \"-Wignored-attributes\"") \
36 | __attribute__((section(name), used)) \
37 | _Pragma("GCC diagnostic pop") \
38 |
39 | /* Avoid 'linux/stddef.h' definition of '__always_inline'. */
40 | #undef __always_inline
41 | #define __always_inline inline __attribute__((always_inline))
42 |
43 | #ifndef __noinline
44 | #define __noinline __attribute__((noinline))
45 | #endif
46 | #ifndef __weak
47 | #define __weak __attribute__((weak))
48 | #endif
49 |
50 | /*
51 | * Use __hidden attribute to mark a non-static BPF subprogram effectively
52 | * static for BPF verifier's verification algorithm purposes, allowing more
53 | * extensive and permissive BPF verification process, taking into account
54 | * subprogram's caller context.
55 | */
56 | #define __hidden __attribute__((visibility("hidden")))
57 |
58 | /* When utilizing vmlinux.h with BPF CO-RE, user BPF programs can't include
59 | * any system-level headers (such as stddef.h, linux/version.h, etc), and
60 | * commonly-used macros like NULL and KERNEL_VERSION aren't available through
61 | * vmlinux.h. This just adds unnecessary hurdles and forces users to re-define
62 | * them on their own. So as a convenience, provide such definitions here.
63 | */
64 | #ifndef NULL
65 | #define NULL ((void *)0)
66 | #endif
67 |
68 | #ifndef KERNEL_VERSION
69 | #define KERNEL_VERSION(a, b, c) (((a) << 16) + ((b) << 8) + ((c) > 255 ? 255 : (c)))
70 | #endif
71 |
72 | /*
73 | * Helper macros to manipulate data structures
74 | */
75 | #ifndef offsetof
76 | #define offsetof(TYPE, MEMBER) ((unsigned long)&((TYPE *)0)->MEMBER)
77 | #endif
78 | #ifndef container_of
79 | #define container_of(ptr, type, member) \
80 | ({ \
81 | void *__mptr = (void *)(ptr); \
82 | ((type *)(__mptr - offsetof(type, member))); \
83 | })
84 | #endif
85 |
86 | /*
87 | * Helper macro to throw a compilation error if __bpf_unreachable() gets
88 | * built into the resulting code. This works given BPF back end does not
89 | * implement __builtin_trap(). This is useful to assert that certain paths
90 | * of the program code are never used and hence eliminated by the compiler.
91 | *
92 | * For example, consider a switch statement that covers known cases used by
93 | * the program. __bpf_unreachable() can then reside in the default case. If
94 | * the program gets extended such that a case is not covered in the switch
95 | * statement, then it will throw a build error due to the default case not
96 | * being compiled out.
97 | */
98 | #ifndef __bpf_unreachable
99 | # define __bpf_unreachable() __builtin_trap()
100 | #endif
101 |
102 | /*
103 | * Helper function to perform a tail call with a constant/immediate map slot.
104 | */
105 | #if __clang_major__ >= 8 && defined(__bpf__)
106 | static __always_inline void
107 | bpf_tail_call_static(void *ctx, const void *map, const __u32 slot)
108 | {
109 | if (!__builtin_constant_p(slot))
110 | __bpf_unreachable();
111 |
112 | /*
113 | * Provide a hard guarantee that LLVM won't optimize setting r2 (map
114 | * pointer) and r3 (constant map index) from _different paths_ ending
115 | * up at the _same_ call insn as otherwise we won't be able to use the
116 | * jmpq/nopl retpoline-free patching by the x86-64 JIT in the kernel
117 | * given they mismatch. See also d2e4c1e6c294 ("bpf: Constant map key
118 | * tracking for prog array pokes") for details on verifier tracking.
119 | *
120 | * Note on clobber list: we need to stay in-line with BPF calling
121 | * convention, so even if we don't end up using r0, r4, r5, we need
122 | * to mark them as clobber so that LLVM doesn't end up using them
123 | * before / after the call.
124 | */
125 | asm volatile("r1 = %[ctx]\n\t"
126 | "r2 = %[map]\n\t"
127 | "r3 = %[slot]\n\t"
128 | "call 12"
129 | :: [ctx]"r"(ctx), [map]"r"(map), [slot]"i"(slot)
130 | : "r0", "r1", "r2", "r3", "r4", "r5");
131 | }
132 | #endif
133 |
134 | /*
135 | * Helper structure used by eBPF C program
136 | * to describe BPF map attributes to libbpf loader
137 | */
138 | struct bpf_map_def {
139 | unsigned int type;
140 | unsigned int key_size;
141 | unsigned int value_size;
142 | unsigned int max_entries;
143 | unsigned int map_flags;
144 | };
145 |
146 | enum libbpf_pin_type {
147 | LIBBPF_PIN_NONE,
148 | /* PIN_BY_NAME: pin maps by name (in /sys/fs/bpf by default) */
149 | LIBBPF_PIN_BY_NAME,
150 | };
151 |
152 | enum libbpf_tristate {
153 | TRI_NO = 0,
154 | TRI_YES = 1,
155 | TRI_MODULE = 2,
156 | };
157 |
158 | #define __kconfig __attribute__((section(".kconfig")))
159 | #define __ksym __attribute__((section(".ksyms")))
160 |
161 | #endif
162 |
--------------------------------------------------------------------------------
/kern/bpf.old/x86/.gitkeep:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sipcapture/rtcagent/6e4bba460ef57079552fcd03e4b790b6a712d4c3/kern/bpf.old/x86/.gitkeep
--------------------------------------------------------------------------------
/kern/bpf/arm64/vmlinux.h:
--------------------------------------------------------------------------------
1 | vmlinux_510.h
--------------------------------------------------------------------------------
/kern/bpf/bpf_endian.h:
--------------------------------------------------------------------------------
1 | /* SPDX-License-Identifier: (LGPL-2.1 OR BSD-2-Clause) */
2 | #ifndef __BPF_ENDIAN__
3 | #define __BPF_ENDIAN__
4 |
5 | /*
6 | * Isolate byte #n and put it into byte #m, for __u##b type.
7 | * E.g., moving byte #6 (nnnnnnnn) into byte #1 (mmmmmmmm) for __u64:
8 | * 1) xxxxxxxx nnnnnnnn xxxxxxxx xxxxxxxx xxxxxxxx xxxxxxxx mmmmmmmm xxxxxxxx
9 | * 2) nnnnnnnn xxxxxxxx xxxxxxxx xxxxxxxx xxxxxxxx mmmmmmmm xxxxxxxx 00000000
10 | * 3) 00000000 00000000 00000000 00000000 00000000 00000000 00000000 nnnnnnnn
11 | * 4) 00000000 00000000 00000000 00000000 00000000 00000000 nnnnnnnn 00000000
12 | */
13 | #define ___bpf_mvb(x, b, n, m) ((__u##b)(x) << (b-(n+1)*8) >> (b-8) << (m*8))
14 |
15 | #define ___bpf_swab16(x) ((__u16)( \
16 | ___bpf_mvb(x, 16, 0, 1) | \
17 | ___bpf_mvb(x, 16, 1, 0)))
18 |
19 | #define ___bpf_swab32(x) ((__u32)( \
20 | ___bpf_mvb(x, 32, 0, 3) | \
21 | ___bpf_mvb(x, 32, 1, 2) | \
22 | ___bpf_mvb(x, 32, 2, 1) | \
23 | ___bpf_mvb(x, 32, 3, 0)))
24 |
25 | #define ___bpf_swab64(x) ((__u64)( \
26 | ___bpf_mvb(x, 64, 0, 7) | \
27 | ___bpf_mvb(x, 64, 1, 6) | \
28 | ___bpf_mvb(x, 64, 2, 5) | \
29 | ___bpf_mvb(x, 64, 3, 4) | \
30 | ___bpf_mvb(x, 64, 4, 3) | \
31 | ___bpf_mvb(x, 64, 5, 2) | \
32 | ___bpf_mvb(x, 64, 6, 1) | \
33 | ___bpf_mvb(x, 64, 7, 0)))
34 |
35 | /* LLVM's BPF target selects the endianness of the CPU
36 | * it compiles on, or the user specifies (bpfel/bpfeb),
37 | * respectively. The used __BYTE_ORDER__ is defined by
38 | * the compiler, we cannot rely on __BYTE_ORDER from
39 | * libc headers, since it doesn't reflect the actual
40 | * requested byte order.
41 | *
42 | * Note, LLVM's BPF target has different __builtin_bswapX()
43 | * semantics. It does map to BPF_ALU | BPF_END | BPF_TO_BE
44 | * in bpfel and bpfeb case, which means below, that we map
45 | * to cpu_to_be16(). We could use it unconditionally in BPF
46 | * case, but better not rely on it, so that this header here
47 | * can be used from application and BPF program side, which
48 | * use different targets.
49 | */
50 | #if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
51 | # define __bpf_ntohs(x) __builtin_bswap16(x)
52 | # define __bpf_htons(x) __builtin_bswap16(x)
53 | # define __bpf_constant_ntohs(x) ___bpf_swab16(x)
54 | # define __bpf_constant_htons(x) ___bpf_swab16(x)
55 | # define __bpf_ntohl(x) __builtin_bswap32(x)
56 | # define __bpf_htonl(x) __builtin_bswap32(x)
57 | # define __bpf_constant_ntohl(x) ___bpf_swab32(x)
58 | # define __bpf_constant_htonl(x) ___bpf_swab32(x)
59 | # define __bpf_be64_to_cpu(x) __builtin_bswap64(x)
60 | # define __bpf_cpu_to_be64(x) __builtin_bswap64(x)
61 | # define __bpf_constant_be64_to_cpu(x) ___bpf_swab64(x)
62 | # define __bpf_constant_cpu_to_be64(x) ___bpf_swab64(x)
63 | #elif __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__
64 | # define __bpf_ntohs(x) (x)
65 | # define __bpf_htons(x) (x)
66 | # define __bpf_constant_ntohs(x) (x)
67 | # define __bpf_constant_htons(x) (x)
68 | # define __bpf_ntohl(x) (x)
69 | # define __bpf_htonl(x) (x)
70 | # define __bpf_constant_ntohl(x) (x)
71 | # define __bpf_constant_htonl(x) (x)
72 | # define __bpf_be64_to_cpu(x) (x)
73 | # define __bpf_cpu_to_be64(x) (x)
74 | # define __bpf_constant_be64_to_cpu(x) (x)
75 | # define __bpf_constant_cpu_to_be64(x) (x)
76 | #else
77 | # error "Fix your compiler's __BYTE_ORDER__?!"
78 | #endif
79 |
80 | #define bpf_htons(x) \
81 | (__builtin_constant_p(x) ? \
82 | __bpf_constant_htons(x) : __bpf_htons(x))
83 | #define bpf_ntohs(x) \
84 | (__builtin_constant_p(x) ? \
85 | __bpf_constant_ntohs(x) : __bpf_ntohs(x))
86 | #define bpf_htonl(x) \
87 | (__builtin_constant_p(x) ? \
88 | __bpf_constant_htonl(x) : __bpf_htonl(x))
89 | #define bpf_ntohl(x) \
90 | (__builtin_constant_p(x) ? \
91 | __bpf_constant_ntohl(x) : __bpf_ntohl(x))
92 | #define bpf_cpu_to_be64(x) \
93 | (__builtin_constant_p(x) ? \
94 | __bpf_constant_cpu_to_be64(x) : __bpf_cpu_to_be64(x))
95 | #define bpf_be64_to_cpu(x) \
96 | (__builtin_constant_p(x) ? \
97 | __bpf_constant_be64_to_cpu(x) : __bpf_be64_to_cpu(x))
98 |
99 | #endif /* __BPF_ENDIAN__ */
100 |
--------------------------------------------------------------------------------
/kern/bpf/x86/.gitkeep:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sipcapture/rtcagent/6e4bba460ef57079552fcd03e4b790b6a712d4c3/kern/bpf/x86/.gitkeep
--------------------------------------------------------------------------------
/kern/common.h:
--------------------------------------------------------------------------------
1 | /*
2 |
3 | LINK - http://github.com/sipcapture/rtcagent
4 |
5 | Copyright (C) 2023 QXIP B.V.
6 |
7 | This program is free software: you can redistribute it and/or modify
8 | it under the terms of the GNU Affero General Public License as published by
9 | the Free Software Foundation, either version 3 of the License, or
10 | (at your option) any later version.
11 |
12 | This program is distributed in the hope that it will be useful,
13 | but WITHOUT ANY WARRANTY; without even the implied warranty of
14 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 | GNU Affero General Public License for more details.
16 |
17 | You should have received a copy of the GNU Affero General Public License
18 | along with this program. If not, see .
19 |
20 | */
21 |
22 | #ifndef RTCAGENT_COMMON_H
23 | #define RTCAGENT_COMMON_H
24 |
25 | #ifdef DEBUG_PRINT
26 | #define debug_bpf_printk(fmt, ...) \
27 | do { \
28 | char s[] = fmt; \
29 | bpf_trace_printk(s, sizeof(s), ##__VA_ARGS__); \
30 | } while (0)
31 | #else
32 | #define debug_bpf_printk(fmt, ...)
33 | #endif
34 |
35 | #define TASK_COMM_LEN 16
36 | #define MAX_DATA_SIZE_OPENSSL 1024 * 4
37 | #define MAX_DATA_SIZE_MYSQL 256
38 | #define MAX_DATA_SIZE_POSTGRES 256
39 | #define MAX_DATA_SIZE_BASH 256
40 |
41 | // enum_server_command, via
42 | #define COM_QUERY 3
43 |
44 | #define AF_INET 2
45 | #define AF_INET6 10
46 | #define SA_DATA_LEN 14
47 | #define BASH_ERRNO_DEFAULT 128
48 |
49 | ///////// for TC & XDP ebpf programs in tc.h
50 | #define TC_ACT_OK 0
51 | #define ETH_P_IP 0x0800 /* Internet Protocol packet */
52 | #define SKB_MAX_DATA_SIZE 2048
53 |
54 | #ifndef KERNEL_LESS_5_2
55 | // alawyse, we used it in tc.h
56 | const volatile u64 target_port = 443;
57 |
58 | // Optional Target PID and UID
59 | const volatile u64 target_pid = 0;
60 | const volatile u64 target_uid = 0;
61 | const volatile u64 target_errno = BASH_ERRNO_DEFAULT;
62 | #else
63 | #endif
64 |
65 | char __license[] SEC("license") = "Dual MIT/GPL";
66 | __u32 _version SEC("version") = 0xFFFFFFFE;
67 |
68 | #endif
69 |
--------------------------------------------------------------------------------
/kern/common2.h:
--------------------------------------------------------------------------------
1 | // This is a compact version of `vmlinux.h` to be used in the examples using C code.
2 |
3 | #pragma once
4 |
5 | typedef unsigned char __u8;
6 | typedef short int __s16;
7 | typedef short unsigned int __u16;
8 | typedef int __s32;
9 | typedef unsigned int __u32;
10 | typedef long long int __s64;
11 | typedef long long unsigned int __u64;
12 | typedef __u8 u8;
13 | typedef __s16 s16;
14 | typedef __u16 u16;
15 | typedef __s32 s32;
16 | typedef __u32 u32;
17 | typedef __s64 s64;
18 | typedef __u64 u64;
19 | typedef __u16 __le16;
20 | typedef __u16 __be16;
21 | typedef __u32 __be32;
22 | typedef __u64 __be64;
23 | typedef __u32 __wsum;
24 |
25 | #include "bpf/bpf_helpers.h"
26 |
27 | enum bpf_map_type {
28 | BPF_MAP_TYPE_UNSPEC = 0,
29 | BPF_MAP_TYPE_HASH = 1,
30 | BPF_MAP_TYPE_ARRAY = 2,
31 | BPF_MAP_TYPE_PROG_ARRAY = 3,
32 | BPF_MAP_TYPE_PERF_EVENT_ARRAY = 4,
33 | BPF_MAP_TYPE_PERCPU_HASH = 5,
34 | BPF_MAP_TYPE_PERCPU_ARRAY = 6,
35 | BPF_MAP_TYPE_STACK_TRACE = 7,
36 | BPF_MAP_TYPE_CGROUP_ARRAY = 8,
37 | BPF_MAP_TYPE_LRU_HASH = 9,
38 | BPF_MAP_TYPE_LRU_PERCPU_HASH = 10,
39 | BPF_MAP_TYPE_LPM_TRIE = 11,
40 | BPF_MAP_TYPE_ARRAY_OF_MAPS = 12,
41 | BPF_MAP_TYPE_HASH_OF_MAPS = 13,
42 | BPF_MAP_TYPE_DEVMAP = 14,
43 | BPF_MAP_TYPE_SOCKMAP = 15,
44 | BPF_MAP_TYPE_CPUMAP = 16,
45 | BPF_MAP_TYPE_XSKMAP = 17,
46 | BPF_MAP_TYPE_SOCKHASH = 18,
47 | BPF_MAP_TYPE_CGROUP_STORAGE = 19,
48 | BPF_MAP_TYPE_REUSEPORT_SOCKARRAY = 20,
49 | BPF_MAP_TYPE_PERCPU_CGROUP_STORAGE = 21,
50 | BPF_MAP_TYPE_QUEUE = 22,
51 | BPF_MAP_TYPE_STACK = 23,
52 | BPF_MAP_TYPE_SK_STORAGE = 24,
53 | BPF_MAP_TYPE_DEVMAP_HASH = 25,
54 | BPF_MAP_TYPE_STRUCT_OPS = 26,
55 | BPF_MAP_TYPE_RINGBUF = 27,
56 | BPF_MAP_TYPE_INODE_STORAGE = 28,
57 | };
58 |
59 | enum xdp_action {
60 | XDP_ABORTED = 0,
61 | XDP_DROP = 1,
62 | XDP_PASS = 2,
63 | XDP_TX = 3,
64 | XDP_REDIRECT = 4,
65 | };
66 |
67 | struct xdp_md {
68 | __u32 data;
69 | __u32 data_end;
70 | __u32 data_meta;
71 | __u32 ingress_ifindex;
72 | __u32 rx_queue_index;
73 | __u32 egress_ifindex;
74 | };
75 |
76 | typedef __u16 __sum16;
77 |
78 | #define ETH_P_IP 0x0800
79 |
80 | struct ethhdr {
81 | unsigned char h_dest[6];
82 | unsigned char h_source[6];
83 | __be16 h_proto;
84 | };
85 |
86 | struct iphdr {
87 | __u8 ihl: 4;
88 | __u8 version: 4;
89 | __u8 tos;
90 | __be16 tot_len;
91 | __be16 id;
92 | __be16 frag_off;
93 | __u8 ttl;
94 | __u8 protocol;
95 | __sum16 check;
96 | __be32 saddr;
97 | __be32 daddr;
98 | };
99 |
100 | enum {
101 | BPF_ANY = 0,
102 | BPF_NOEXIST = 1,
103 | BPF_EXIST = 2,
104 | BPF_F_LOCK = 4,
105 | };
106 |
107 | /* BPF_FUNC_perf_event_output, BPF_FUNC_perf_event_read and
108 | * BPF_FUNC_perf_event_read_value flags.
109 | */
110 | #define BPF_F_INDEX_MASK 0xffffffffULL
111 | #define BPF_F_CURRENT_CPU BPF_F_INDEX_MASK
112 |
113 | #if defined(__TARGET_ARCH_x86)
114 | struct pt_regs {
115 | /*
116 | * C ABI says these regs are callee-preserved. They aren't saved on kernel entry
117 | * unless syscall needs a complete, fully filled "struct pt_regs".
118 | */
119 | unsigned long r15;
120 | unsigned long r14;
121 | unsigned long r13;
122 | unsigned long r12;
123 | unsigned long rbp;
124 | unsigned long rbx;
125 | /* These regs are callee-clobbered. Always saved on kernel entry. */
126 | unsigned long r11;
127 | unsigned long r10;
128 | unsigned long r9;
129 | unsigned long r8;
130 | unsigned long rax;
131 | unsigned long rcx;
132 | unsigned long rdx;
133 | unsigned long rsi;
134 | unsigned long rdi;
135 | /*
136 | * On syscall entry, this is syscall#. On CPU exception, this is error code.
137 | * On hw interrupt, it's IRQ number:
138 | */
139 | unsigned long orig_rax;
140 | /* Return frame for iretq */
141 | unsigned long rip;
142 | unsigned long cs;
143 | unsigned long eflags;
144 | unsigned long rsp;
145 | unsigned long ss;
146 | /* top of stack page */
147 | };
148 | #endif /* __TARGET_ARCH_x86 */
149 |
--------------------------------------------------------------------------------
/kern/kamailio.h:
--------------------------------------------------------------------------------
1 | /*
2 |
3 | LINK - http://github.com/sipcapture/rtcagent
4 |
5 | Copyright (C) 2023 QXIP B.V.
6 |
7 | This program is free software: you can redistribute it and/or modify
8 | it under the terms of the GNU Affero General Public License as published by
9 | the Free Software Foundation, either version 3 of the License, or
10 | (at your option) any later version.
11 |
12 | This program is distributed in the hope that it will be useful,
13 | but WITHOUT ANY WARRANTY; without even the implied warranty of
14 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 | GNU Affero General Public License for more details.
16 |
17 | You should have received a copy of the GNU Affero General Public License
18 | along with this program. If not, see .
19 |
20 | */
21 |
22 |
23 | #include "rtcagent.h"
24 |
25 | #define _SYS_SOCKET_H 1
26 | #define IP4_MAX_STR_SIZE 15
27 | #define IP6_MAX_STR_SIZE 45
28 | #define IP_ADDR_MAX_STR_SIZE 6 /* ip62ascii + \0*/
29 | #define SS_MAXSIZE 128 /* Implementation specific max size */
30 | #define MAX_DATA_SIZE_SIP 1024*4
31 |
32 | typedef unsigned short sa_family_t;
33 |
34 | typedef struct _str
35 | {
36 | char *s;
37 | int len;
38 | } str;
39 |
40 | struct sockaddr_storage
41 | {
42 | union
43 | {
44 | struct
45 | {
46 | sa_family_t ss_family; /* address family */
47 | /* Following field(s) are implementation specific */
48 | char __data[SS_MAXSIZE - sizeof(unsigned short)];
49 | /* space to achieve desired size, */
50 | /* _SS_MAXSIZE value minus size of ss_family */
51 | };
52 | void *__align; /* implementation specific desired alignment */
53 | };
54 | };
55 |
56 | typedef struct ip_addr
57 | {
58 | unsigned int af; /* address family: AF_INET6 or AF_INET */
59 | unsigned int len; /* address len, 16 or 4 */
60 |
61 | /* 64 bits aligned address */
62 | union
63 | {
64 | unsigned long addrl[16 / sizeof(long)]; /* long format*/
65 | unsigned int addr32[4];
66 | unsigned short addr16[8];
67 | unsigned char addr[16];
68 | } u;
69 | } ip_addr_t;
70 |
71 | typedef struct advertise_info
72 | {
73 | str name; /* name - eg.: foo.bar or 10.0.0.1 */
74 | unsigned short port_no; /* port number */
75 | short port_pad; /* padding field */
76 | str port_no_str; /* port number converted to string -- optimization*/
77 | str address_str; /*ip address converted to string -- optimization*/
78 | struct ip_addr address; /* ip address */
79 | str sock_str; /* Socket proto, ip, and port as string */
80 | } advertise_info_t;
81 |
82 | typedef struct snd_flags
83 | {
84 | unsigned short f; /* snd flags */
85 | unsigned short blst_imask; /* blocklist ignore mask */
86 | } snd_flags_t;
87 |
88 | typedef enum si_flags
89 | {
90 | SI_NONE = 0,
91 | SI_IS_IP = (1 << 0),
92 | SI_IS_LO = (1 << 1),
93 | SI_IS_MCAST = (1 << 2),
94 | SI_IS_ANY = (1 << 3),
95 | SI_IS_MHOMED = (1 << 4),
96 | SI_IS_VIRTUAL = (1 << 5),
97 | } si_flags_t;
98 |
99 | typedef union sockaddr_union
100 | {
101 | struct sockaddr s;
102 | struct sockaddr_in sin;
103 | struct sockaddr_in6 sin6;
104 | struct sockaddr_storage sas;
105 | } sr_sockaddr_union_t;
106 |
107 | typedef struct socket_info
108 | {
109 | int socket;
110 | int gindex; /* global index in the lists of all sockets */
111 | str name; /* name - eg.: foo.bar or 10.0.0.1 */
112 | struct ip_addr address; /* ip address */
113 | str address_str; /*ip address converted to string -- optimization*/
114 | str port_no_str; /* port number converted to string -- optimization*/
115 | enum si_flags flags; /* SI_IS_IP | SI_IS_LO | SI_IS_MCAST */
116 | union sockaddr_union su;
117 | struct socket_info *next;
118 | struct socket_info *prev;
119 | unsigned short port_no; /* port number */
120 | char proto; /* tcp or udp*/
121 | char proto_pad0; /* padding field */
122 | short proto_pad1; /* padding field */
123 | str sock_str; /* Socket proto, ip, and port as string */
124 | struct addr_info *addr_info_lst; /* extra addresses (e.g. SCTP mh) */
125 | int workers; /* number of worker processes for this socket */
126 | int workers_tcpidx; /* index of workers in tcp children array */
127 | str sockname; /* socket name given in config listen value */
128 | struct advertise_info useinfo; /* details to be used in SIP msg */
129 | #ifdef USE_MCAST
130 | str mcast; /* name of interface that should join multicast group*/
131 | #endif /* USE_MCAST */
132 | } socket_info_t;
133 |
134 | typedef struct dest_info
135 | {
136 | struct socket_info *send_sock;
137 | union sockaddr_union to;
138 | int id; /* tcp stores the connection id here */
139 | snd_flags_t send_flags;
140 | char proto;
141 | #ifdef USE_COMP
142 | char proto_pad0; /* padding field */
143 | short comp;
144 | #else
145 | char proto_pad0; /* padding field */
146 | short proto_pad1; /* padding field */
147 | #endif
148 | } dest_info_t;
149 |
150 | /* inits an ip_addr pointer from a sockaddr_union ip address */
151 | static inline void su2ip_addr(struct ip_addr *ip, const union sockaddr_union *su)
152 | {
153 | switch (su->s.sa_family)
154 | {
155 | case AF_INET:
156 | ip->af = AF_INET;
157 | ip->len = 4;
158 | __builtin_memcpy(ip->u.addr, &su->sin.sin_addr, 4);
159 | break;
160 | case AF_INET6:
161 | ip->af = AF_INET6;
162 | ip->len = 16;
163 | __builtin_memcpy(ip->u.addr, &su->sin6.sin6_addr, 16);
164 | break;
165 | default:
166 | __builtin_memset(ip, 0, sizeof(ip_addr_t));
167 | }
168 | }
169 |
--------------------------------------------------------------------------------
/kern/opensips.h:
--------------------------------------------------------------------------------
1 | /*
2 |
3 | LINK - http://github.com/sipcapture/rtcagent
4 |
5 | Copyright (C) 2023 QXIP B.V.
6 |
7 | This program is free software: you can redistribute it and/or modify
8 | it under the terms of the GNU Affero General Public License as published by
9 | the Free Software Foundation, either version 3 of the License, or
10 | (at your option) any later version.
11 |
12 | This program is distributed in the hope that it will be useful,
13 | but WITHOUT ANY WARRANTY; without even the implied warranty of
14 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 | GNU Affero General Public License for more details.
16 |
17 | You should have received a copy of the GNU Affero General Public License
18 | along with this program. If not, see .
19 |
20 | */
21 |
22 | #include "rtcagent.h"
23 |
24 | #define _SYS_SOCKET_H 1
25 | #define IP4_MAX_STR_SIZE 15
26 | #define IP6_MAX_STR_SIZE 45
27 | #define IP_ADDR_MAX_STR_SIZE 6 /* ip62ascii + \0*/
28 | #define SS_MAXSIZE 128 /* Implementation specific max size */
29 | #define MAX_DATA_SIZE_SIP 1024 * 4
30 |
31 | typedef unsigned short sa_family_t;
32 |
33 | typedef struct _str
34 | {
35 | char *s;
36 | int len;
37 | } str;
38 |
39 | struct sockaddr_storage
40 | {
41 | union
42 | {
43 | struct
44 | {
45 | sa_family_t ss_family; /* address family */
46 | /* Following field(s) are implementation specific */
47 | char __data[SS_MAXSIZE - sizeof(unsigned short)];
48 | /* space to achieve desired size, */
49 | /* _SS_MAXSIZE value minus size of ss_family */
50 | };
51 | void *__align; /* implementation specific desired alignment */
52 | };
53 | };
54 |
55 | typedef struct ip_addr
56 | {
57 | unsigned int af; /* address family: AF_INET6 or AF_INET */
58 | unsigned int len; /* address len, 16 or 4 */
59 |
60 | /* 64 bits aligned address */
61 | union
62 | {
63 | unsigned long addrl[16 / sizeof(long)]; /* long format*/
64 | unsigned int addr32[4];
65 | unsigned short addr16[8];
66 | unsigned char addr[16];
67 | } u;
68 | } ip_addr_t;
69 |
70 | typedef struct advertise_info
71 | {
72 | str name; /* name - eg.: foo.bar or 10.0.0.1 */
73 | unsigned short port_no; /* port number */
74 | short port_pad; /* padding field */
75 | str port_no_str; /* port number converted to string -- optimization*/
76 | str address_str; /*ip address converted to string -- optimization*/
77 | struct ip_addr address; /* ip address */
78 | str sock_str; /* Socket proto, ip, and port as string */
79 | } advertise_info_t;
80 |
81 | typedef struct snd_flags
82 | {
83 | unsigned short f; /* snd flags */
84 | unsigned short blst_imask; /* blocklist ignore mask */
85 | } snd_flags_t;
86 |
87 | typedef enum si_flags
88 | {
89 | SI_NONE = 0,
90 | SI_IS_IP = (1 << 0),
91 | SI_IS_LO = (1 << 1),
92 | SI_IS_MCAST = (1 << 2),
93 | SI_IS_ANY = (1 << 3),
94 | SI_IS_MHOMED = (1 << 4),
95 | SI_IS_VIRTUAL = (1 << 5),
96 | } si_flags_t;
97 |
98 | typedef union sockaddr_union
99 | {
100 | struct sockaddr s;
101 | struct sockaddr_in sin;
102 | struct sockaddr_in6 sin6;
103 | struct sockaddr_storage sas;
104 | } sr_sockaddr_union_t;
105 |
106 | typedef struct socket_info
107 | {
108 | int socket;
109 | str name; /*!< name - eg.: foo.bar or 10.0.0.1 */
110 | str tag; /* the tag of the interface, use only in OpenSIPS ecosystem */
111 | struct ip_addr address; /*!< ip address */
112 | str address_str; /*!< ip address converted to string -- optimization*/
113 | unsigned short port_no; /*!< port number */
114 | str port_no_str; /*!< port number converted to string -- optimization*/
115 | enum si_flags flags; /*!< SI_IS_IP | SI_IS_LO | SI_IS_MCAST | SI_IS_ANYCAST */
116 | union sockaddr_union su;
117 | int proto; /*!< tcp or udp*/
118 | str sock_str;
119 | str adv_sock_str;
120 | str tag_sock_str;
121 | str adv_name_str; /* Advertised name of this interface */
122 | str adv_port_str; /* Advertised port of this interface */
123 | struct ip_addr adv_address; /* Advertised address in ip_addr form (for find_si) */
124 | unsigned short adv_port; /* optimization for grep_sock_info() */
125 | unsigned short workers;
126 | } socket_info_t;
127 |
128 | /*
129 | typedef struct socket_info
130 | {
131 | int socket;
132 | int gindex;
133 | str name;
134 | struct ip_addr address;
135 | str address_str;
136 | str port_no_str;
137 | enum si_flags flags;
138 | union sockaddr_union su;
139 | struct socket_info *next;
140 | struct socket_info *prev;
141 | unsigned short port_no;
142 | char proto;
143 | char proto_pad0;
144 | short proto_pad1;
145 | str sock_str;
146 | struct addr_info *addr_info_lst;
147 | int workers;
148 | int workers_tcpidx;
149 | str sockname;
150 | struct advertise_info useinfo;
151 | } socket_info_t;
152 | */
153 |
154 | typedef struct dest_info
155 | {
156 | struct socket_info *send_sock;
157 | union sockaddr_union to;
158 | int id; /* tcp stores the connection id here */
159 | snd_flags_t send_flags;
160 | char proto;
161 | #ifdef USE_COMP
162 | char proto_pad0; /* padding field */
163 | short comp;
164 | #else
165 | char proto_pad0; /* padding field */
166 | short proto_pad1; /* padding field */
167 | #endif
168 | } dest_info_t;
169 |
170 | /* inits an ip_addr pointer from a sockaddr_union ip address */
171 | static inline void su2ip_addr(struct ip_addr *ip, const union sockaddr_union *su)
172 | {
173 | switch (su->s.sa_family)
174 | {
175 | case AF_INET:
176 | ip->af = AF_INET;
177 | ip->len = 4;
178 | __builtin_memcpy(ip->u.addr, &su->sin.sin_addr, 4);
179 | break;
180 | case AF_INET6:
181 | ip->af = AF_INET6;
182 | ip->len = 16;
183 | __builtin_memcpy(ip->u.addr, &su->sin6.sin6_addr, 16);
184 | break;
185 | default:
186 | __builtin_memset(ip, 0, sizeof(ip_addr_t));
187 | }
188 | }
189 |
--------------------------------------------------------------------------------
/kern/rtcagent.h:
--------------------------------------------------------------------------------
1 | // Copyright 2022 CFC4N . All Rights Reserved.
2 | //
3 | // Licensed under the Apache License, Version 2.0 (the "License");
4 | // you may not use this file except in compliance with the License.
5 | // You may obtain a copy of the License at
6 | //
7 | // http://www.apache.org/licenses/LICENSE-2.0
8 | //
9 | // Unless required by applicable law or agreed to in writing, software
10 | // distributed under the License is distributed on an "AS IS" BASIS,
11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | // See the License for the specific language governing permissions and
13 | // limitations under the License.
14 |
15 | #ifndef RTCAGENT_H
16 | #define RTCAGENT_H
17 |
18 | #ifndef NOCORE
19 | //CO:RE is enabled
20 | #include "vmlinux.h"
21 | #include "bpf/bpf_core_read.h"
22 | #include "bpf/bpf_helpers.h"
23 | #include "bpf/bpf_tracing.h"
24 | #include "bpf/bpf_endian.h"
25 |
26 |
27 | #else
28 | //CO:RE is disabled
29 | #include
30 |
31 | // see https://github.com//sipcapture/rtcagent/issues/256 for more detail.
32 | /*
33 | * This will bring in asm_volatile_goto and asm_inline macro definitions
34 | * if enabled by compiler and config options.
35 | */
36 | #include
37 |
38 | /*
39 | * asm_inline is defined as asm __inline in "include/linux/compiler_types.h"
40 | * if supported by the kernel's CC (i.e CONFIG_CC_HAS_ASM_INLINE) which is not
41 | * supported by CLANG.
42 | */
43 | #ifdef asm_inline
44 | #undef asm_inline
45 | #define asm_inline asm
46 | #endif
47 |
48 | #include
49 | #include
50 | #include
51 | #include
52 | #include
53 | #include
54 | #include
55 | #include
56 | #include
57 | #include
58 | #include
59 |
60 | struct tcphdr {
61 | __be16 source;
62 | __be16 dest;
63 | };
64 |
65 | #endif
66 |
67 | #include "common.h"
68 |
69 | #endif
70 |
--------------------------------------------------------------------------------
/kern/tcprtt_kern.c:
--------------------------------------------------------------------------------
1 | /*
2 |
3 | LINK - http://github.com/sipcapture/rtcagent
4 |
5 | Copyright (C) 2023 QXIP B.V.
6 |
7 | This program is free software: you can redistribute it and/or modify
8 | it under the terms of the GNU Affero General Public License as published by
9 | the Free Software Foundation, either version 3 of the License, or
10 | (at your option) any later version.
11 |
12 | This program is distributed in the hope that it will be useful,
13 | but WITHOUT ANY WARRANTY; without even the implied warranty of
14 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 | GNU Affero General Public License for more details.
16 |
17 | You should have received a copy of the GNU Affero General Public License
18 | along with this program. If not, see .
19 |
20 | */
21 |
22 | #include "common2.h"
23 | #include "bpf/bpf_endian.h"
24 | #include "bpf/bpf_tracing.h"
25 |
26 |
27 | #define AF_INET 2
28 |
29 | char __license[] SEC("license") = "Dual MIT/GPL";
30 |
31 | /**
32 | * For CO-RE relocatable eBPF programs, __attribute__((preserve_access_index))
33 | * preserves the offset of the specified fields in the original kernel struct.
34 | * So here we don't need to include "vmlinux.h". Instead we only need to define
35 | * the kernel struct and their fields the eBPF program actually requires.
36 | *
37 | * Also note that BTF-enabled programs like fentry, fexit, fmod_ret, tp_btf,
38 | * lsm, etc. declared using the BPF_PROG macro can read kernel memory without
39 | * needing to call bpf_probe_read*().
40 | */
41 |
42 | struct sock_common {
43 | union {
44 | struct {
45 | // skc_daddr is destination IP address
46 | __be32 skc_daddr;
47 | // skc_rcv_saddr is the source IP address
48 | __be32 skc_rcv_saddr;
49 | };
50 | };
51 | union {
52 | struct {
53 | // skc_dport is the destination TCP/UDP port
54 | __be16 skc_dport;
55 | // skc_num is the source TCP/UDP port
56 | __u16 skc_num;
57 | };
58 | };
59 | // skc_family is the network address family (2 for IPV4)
60 | short unsigned int skc_family;
61 | } __attribute__((preserve_access_index));
62 |
63 | /**
64 | * struct sock is the network layer representation of sockets.
65 | * This is a simplified copy of the kernel's struct sock.
66 | * This copy is needed only to access struct sock_common.
67 | */
68 | struct sock {
69 | struct sock_common __sk_common;
70 | } __attribute__((preserve_access_index));
71 |
72 | /**
73 | * struct tcp_sock is the Linux representation of a TCP socket.
74 | * This is a simplified copy of the kernel's struct tcp_sock.
75 | * For this example we only need srtt_us to read the smoothed RTT.
76 | */
77 | struct tcp_sock {
78 | u32 srtt_us;
79 | } __attribute__((preserve_access_index));
80 |
81 | struct {
82 | __uint(type, BPF_MAP_TYPE_RINGBUF);
83 | __uint(max_entries, 1 << 24);
84 | } events SEC(".maps");
85 |
86 | /**
87 | * The sample submitted to userspace over a ring buffer.
88 | * Emit struct event's type info into the ELF's BTF so bpf2go
89 | * can generate a Go type from it.
90 | */
91 | struct event {
92 | u16 sport;
93 | u16 dport;
94 | u32 saddr;
95 | u32 daddr;
96 | u32 srtt;
97 | };
98 | struct event *unused_event __attribute__((unused));
99 |
100 | SEC("fentry/tcp_close")
101 | int BPF_PROG(tcp_close, struct sock *sk)
102 | {
103 |
104 | //char fmt2[] = "TIMESTAMP: %d\n";
105 | //bpf_trace_printk(fmt2, sizeof(fmt2), 1);
106 |
107 | if (sk->__sk_common.skc_family != AF_INET)
108 | {
109 | return 0;
110 | }
111 |
112 | // The input struct sock is actually a tcp_sock, so we can type-cast
113 | struct tcp_sock *ts = bpf_skc_to_tcp_sock(sk);
114 | if (!ts)
115 | {
116 | return 0;
117 | }
118 |
119 | struct event *tcp_info;
120 | tcp_info = bpf_ringbuf_reserve(&events, sizeof(struct event), 0);
121 | if (!tcp_info)
122 | {
123 | return 0;
124 | }
125 |
126 | tcp_info->saddr = sk->__sk_common.skc_rcv_saddr;
127 | tcp_info->daddr = sk->__sk_common.skc_daddr;
128 | tcp_info->dport = bpf_ntohs(sk->__sk_common.skc_dport);
129 | tcp_info->sport = sk->__sk_common.skc_num;
130 |
131 | tcp_info->srtt = ts->srtt_us >> 3;
132 | tcp_info->srtt /= 1000;
133 |
134 | bpf_ringbuf_submit(tcp_info, 0);
135 |
136 | return 0;
137 | }
138 |
--------------------------------------------------------------------------------
/main.go:
--------------------------------------------------------------------------------
1 | package main
2 |
3 | import (
4 | "log"
5 | "rtcagent/cli"
6 | "rtcagent/pkg/util/ebpf"
7 | "rtcagent/pkg/util/kernel"
8 | "runtime"
9 |
10 | _ "github.com/shuLhan/go-bindata" // add for bindata in Makefile
11 | )
12 |
13 | const (
14 | BtfNotSupport = "You can compile a no BTF version by yourself with command `make nocore`,Please read Makefile for more info."
15 | )
16 |
17 | var (
18 | enableCORE = "true"
19 | )
20 |
21 | func main() {
22 |
23 | kv, err := kernel.HostVersion()
24 | if err != nil {
25 | log.Fatal(err)
26 | }
27 | switch runtime.GOARCH {
28 | case "amd64":
29 | if kv < kernel.VersionCode(4, 18, 0) {
30 | log.Fatalf("Linux/Android Kernel (x86_64) version %v is not supported. Need > 4.18 .", kv)
31 | }
32 | case "arm64":
33 | if kv < kernel.VersionCode(5, 5, 0) {
34 | log.Fatalf("Linux/Android Kernel (aarch64) version %v is not supported. Need > 5.5 .", kv)
35 | }
36 | default:
37 | log.Fatalf("unsupported CPU arch:%v. ", runtime.GOARCH)
38 | }
39 |
40 | isContainer, err := ebpf.IsContainer()
41 | if err != nil {
42 | log.Fatal("Check container error:", err)
43 | }
44 |
45 | if isContainer {
46 | log.Printf("Your environment is a container. We will not detect the BTF config.")
47 | } else {
48 | enable, e := ebpf.IsEnableBPF()
49 | if e != nil {
50 | log.Fatalf("Kernel config read failed, error:%v", e)
51 | }
52 |
53 | if !enable {
54 | log.Fatalf("Kernel not support, error:%v", e)
55 | }
56 |
57 | if enableCORE == "true" {
58 | enable, e := ebpf.IsEnableBTF()
59 | if e != nil {
60 | log.Fatalf("Can't found BTF config with error:%v.\n"+BtfNotSupport, e)
61 | }
62 | if !enable {
63 | log.Fatal("BTF not support, please check it. shell: cat /boot/config-`uname -r` | grep CONFIG_DEBUG_INFO_BTF \n " +
64 | BtfNotSupport)
65 | }
66 | }
67 | }
68 |
69 | cli.Start()
70 | }
71 |
--------------------------------------------------------------------------------
/metric/definition.go:
--------------------------------------------------------------------------------
1 | package metric
2 |
3 | import (
4 | "github.com/prometheus/client_golang/prometheus"
5 | "github.com/prometheus/client_golang/prometheus/promauto"
6 | )
7 |
8 | var (
9 | // TCP Latency
10 | latencyTCP = promauto.NewGaugeVec(prometheus.GaugeOpts{
11 | Name: "tcp_latency",
12 | Help: "latency of tcp connection"},
13 | []string{"node_id", "src_ip", "dst_ip", "src_port", "dst_port"})
14 | )
15 |
--------------------------------------------------------------------------------
/metric/metric.go:
--------------------------------------------------------------------------------
1 | package metric
2 |
3 | import (
4 | "log"
5 | "os"
6 | "os/signal"
7 | "rtcagent/model"
8 | "runtime"
9 | "syscall"
10 | )
11 |
12 | type Metric struct {
13 | H MetricHandler
14 | Chan chan model.AggregatedMetricValue
15 | quit chan bool
16 | }
17 |
18 | type MetricHandler interface {
19 | setup() error
20 | reload()
21 | expose(chan model.AggregatedMetricValue)
22 | }
23 |
24 | func New(name string) *Metric {
25 | var register = map[string]MetricHandler{
26 | "prometheus": new(Prometheus),
27 | }
28 |
29 | return &Metric{
30 | H: register[name],
31 | quit: make(chan bool),
32 | }
33 | }
34 |
35 | func (m *Metric) Run() error {
36 | err := m.H.setup()
37 | if err != nil {
38 | return err
39 | }
40 |
41 | for i := 0; i < runtime.NumCPU(); i++ {
42 | go func() {
43 | m.H.expose(m.Chan)
44 | }()
45 | }
46 |
47 | s := make(chan os.Signal, 1)
48 | signal.Notify(s, syscall.SIGHUP)
49 | go func() {
50 | for {
51 | select {
52 | case <-s:
53 | m.H.reload()
54 | case <-m.quit:
55 | m.quit <- true
56 | return
57 | }
58 | }
59 | }()
60 |
61 | return nil
62 | }
63 |
64 | func (m *Metric) End() {
65 | m.quit <- true
66 | <-m.quit
67 | close(m.Chan)
68 | log.Printf("close metric channel")
69 | }
70 |
--------------------------------------------------------------------------------
/metric/prometheus.go:
--------------------------------------------------------------------------------
1 | package metric
2 |
3 | import (
4 | "log"
5 | "net"
6 | "net/http"
7 | "rtcagent/model"
8 | "strings"
9 | "sync"
10 | "time"
11 |
12 | "github.com/VictoriaMetrics/fastcache"
13 | "github.com/prometheus/client_golang/prometheus/promhttp"
14 | )
15 |
16 | const (
17 | invite = "INVITE"
18 | register = "REGISTER"
19 | cacheSize = 60 * 1024 * 1024
20 | )
21 |
22 | type Prometheus struct {
23 | TargetEmpty bool
24 | TargetIP []string
25 | TargetName []string
26 | TargetMap map[string]string
27 | TargetConf *sync.RWMutex
28 | cache *fastcache.Cache
29 | s *http.Server
30 | }
31 |
32 | func (p *Prometheus) setup() (err error) {
33 | p.TargetConf = new(sync.RWMutex)
34 | p.TargetIP = strings.Split("10.0.0.1", ",")
35 | p.TargetName = strings.Split("test", ",")
36 | p.cache = fastcache.New(cacheSize)
37 |
38 | /*
39 | err = prometheus.Register(version_collector.NewCollector("rtcagent"))
40 | if err != nil {
41 | log.Fatalf("Error registering version collector: %s", err)
42 | }
43 |
44 | p.exporter, err = NewExporter()
45 | if err != nil {
46 | log.Fatalf("Error creating exporter: %s", err)
47 | }
48 |
49 | err = prometheus.Register(p.exporter)
50 | if err != nil {
51 | log.Fatalf("Error registering exporter: %s", err)
52 | }
53 | */
54 |
55 | metricsPath := "/metrics"
56 | listenAddress := ":9435"
57 |
58 | mux := http.NewServeMux()
59 | mux.Handle("/metrics", promhttp.Handler())
60 |
61 | mux.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
62 | _, err = w.Write([]byte(`
63 | eBPF Exporter
64 |
65 | eBPF Exporter
66 | Metrics
67 |
68 | `))
69 | if err != nil {
70 | log.Fatalf("Error sending response body: %s", err)
71 | }
72 | })
73 |
74 | p.s = &http.Server{
75 | Addr: listenAddress,
76 | Handler: mux,
77 | ReadTimeout: 0, // 1 * time.Minute,
78 | WriteTimeout: 30 * time.Minute,
79 | MaxHeaderBytes: 1 << 20,
80 | }
81 |
82 | go func() {
83 |
84 | l, err := net.Listen("tcp", listenAddress)
85 |
86 | if err != nil {
87 | log.Fatal(err)
88 | }
89 |
90 | //fmt.Println(`{"server_state":"listening"}`)
91 | log.Fatal(p.s.Serve(l))
92 | }()
93 |
94 | return err
95 | }
96 |
97 | func (p *Prometheus) expose(hCh chan model.AggregatedMetricValue) {
98 | for pkt := range hCh {
99 |
100 | //fmt.Println(pkt.Name)
101 | if pkt.IntType == 2 {
102 | latencyTCP.WithLabelValues(pkt.Labels...).Set(pkt.Value)
103 | }
104 | }
105 | }
106 |
--------------------------------------------------------------------------------
/metric/reload.go:
--------------------------------------------------------------------------------
1 | package metric
2 |
3 | import (
4 | "log"
5 | "os"
6 | "strings"
7 | "unicode"
8 | )
9 |
10 | func cutSpace(str string) string {
11 | return strings.Map(func(r rune) rune {
12 | if unicode.IsSpace(r) {
13 | return -1
14 | }
15 | return r
16 | }, str)
17 | }
18 |
19 | func (p *Prometheus) reload() {
20 | var fsTargetIP []string
21 | var fsTargetName []string
22 |
23 | fb, err := os.ReadFile("prometheus.conf")
24 | if err != nil {
25 | log.Printf("%v", err)
26 | return
27 | }
28 |
29 | fs := cutSpace(string(fb))
30 |
31 | if si := strings.Index(fs, "PromTargetIP=\""); si > -1 {
32 | s := si + len("PromTargetIP=\"")
33 | e := strings.Index(fs[s:], "\"")
34 | if e >= 7 {
35 | fsTargetIP = strings.Split(fs[s:s+e], ",")
36 | }
37 | }
38 | if si := strings.Index(fs, "PromTargetName=\""); si > -1 {
39 | s := si + len("PromTargetName=\"")
40 | e := strings.Index(fs[s:], "\"")
41 | if e > 0 {
42 | fsTargetName = strings.Split(fs[s:s+e], ",")
43 | }
44 | }
45 |
46 | if fsTargetIP != nil && fsTargetName != nil && len(fsTargetIP) == len(fsTargetName) {
47 | p.TargetConf.Lock()
48 | p.TargetIP = fsTargetIP
49 | p.TargetName = fsTargetName
50 | p.TargetEmpty = false
51 | p.TargetMap = make(map[string]string)
52 | for i := 0; i < len(p.TargetName); i++ {
53 | p.TargetMap[p.TargetIP[i]] = p.TargetName[i]
54 | }
55 | p.TargetConf.Unlock()
56 | log.Printf("successfully reloaded PromTargetIP: %#v", fsTargetIP)
57 | log.Printf("successfully reloaded PromTargetName: %#v", fsTargetName)
58 | } else {
59 | log.Printf("failed to reload PromTargetIP: %#v", fsTargetIP)
60 | log.Printf("failed to reload PromTargetName: %#v", fsTargetName)
61 | log.Printf("please give every PromTargetIP a unique IP and PromTargetName a unique name")
62 | }
63 | }
64 |
--------------------------------------------------------------------------------
/model/metric.go:
--------------------------------------------------------------------------------
1 | package model
2 |
3 | import (
4 | "github.com/prometheus/client_golang/prometheus"
5 | )
6 |
7 | // aggregatedMetricValue is a value after aggregation of equal label sets
8 | type AggregatedMetricValue struct {
9 | // labels are decoded from the raw key
10 | Labels []string
11 | // value is the kernel map value
12 | Value float64
13 | //Internal type
14 | IntType int
15 | //
16 | Type prometheus.ValueType
17 | //name
18 | Name string
19 | }
20 |
21 | // aggregatedMetricValue is a value after aggregation of equal label sets
22 | type AggregatedTimeMetricValue struct {
23 | // labels are decoded from the raw key
24 | MapLabelsString map[string]string
25 | MapLabelsInt map[string]int
26 | // value is the kernel map value
27 | Value float64
28 | //
29 | Type prometheus.ValueType
30 | //name
31 | Name string
32 | //
33 | IntType int
34 | //time
35 | Time int64
36 | }
37 |
38 | type Label struct {
39 | Name string `yaml:"name"`
40 | Size uint `yaml:"size"`
41 | }
42 |
--------------------------------------------------------------------------------
/outdata/hep/hep.proto:
--------------------------------------------------------------------------------
1 | syntax = "proto2";
2 | package publish;
3 |
4 |
5 | import "github.com/gogo/protobuf/gogoproto/gogo.proto";
6 |
7 | option (gogoproto.gostring_all) = true;
8 | option (gogoproto.goproto_stringer_all) = false;
9 | option (gogoproto.stringer_all) = true;
10 | option (gogoproto.marshaler_all) = true;
11 | option (gogoproto.sizer_all) = true;
12 | option (gogoproto.unmarshaler_all) = true;
13 |
14 | // For tests
15 | option (gogoproto.testgen_all) = true;
16 | option (gogoproto.benchgen_all) = true;
17 | option (gogoproto.equal_all) = true;
18 | option (gogoproto.populate_all) = true;
19 |
20 | // HEP represents HEP packet
21 | message HEP {
22 | required uint32 Version = 1 [(gogoproto.nullable) = false];
23 | required uint32 Protocol = 2 [(gogoproto.nullable) = false];
24 | required string SrcIP = 3 [(gogoproto.nullable) = false];
25 | required string DstIP = 4 [(gogoproto.nullable) = false];
26 | required uint32 SrcPort = 5 [(gogoproto.nullable) = false];
27 | required uint32 DstPort = 6 [(gogoproto.nullable) = false];
28 | required uint32 Tsec = 7 [(gogoproto.nullable) = false];
29 | required uint32 Tmsec = 8 [(gogoproto.nullable) = false];
30 | required uint32 ProtoType = 9 [(gogoproto.nullable) = false];
31 | required uint32 NodeID = 10 [(gogoproto.nullable) = false];
32 | required string NodePW = 11 [(gogoproto.nullable) = false];
33 | required string Payload = 12 [(gogoproto.nullable) = false];
34 | required string CID = 13 [(gogoproto.nullable) = false];
35 | required uint32 Vlan = 14 [(gogoproto.nullable) = false];
36 | }
37 |
--------------------------------------------------------------------------------
/pkg/event_processor/iparser.go:
--------------------------------------------------------------------------------
1 | /*
2 |
3 | LINK - http://github.com/sipcapture/rtcagent
4 |
5 | Copyright (C) 2023 QXIP B.V.
6 |
7 | This program is free software: you can redistribute it and/or modify
8 | it under the terms of the GNU Affero General Public License as published by
9 | the Free Software Foundation, either version 3 of the License, or
10 | (at your option) any later version.
11 |
12 | This program is distributed in the hope that it will be useful,
13 | but WITHOUT ANY WARRANTY; without even the implied warranty of
14 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 | GNU Affero General Public License for more details.
16 |
17 | You should have received a copy of the GNU Affero General Public License
18 | along with this program. If not, see .
19 |
20 | */
21 |
22 | package event_processor
23 |
24 | import (
25 | "bytes"
26 | "encoding/hex"
27 | "fmt"
28 | )
29 |
30 | type ProcessStatus uint8
31 | type PacketType uint8
32 | type ParserType uint8
33 |
34 | const (
35 | ProcessStateInit ProcessStatus = iota
36 | ProcessStateProcessing
37 | ProcessStateDone
38 | )
39 |
40 | const (
41 | PacketTypeNull PacketType = iota
42 | PacketTypeUnknow
43 | PacketTypeGzip
44 | PacketTypeWebSocket
45 | )
46 |
47 | const (
48 | ParserTypeNull ParserType = iota
49 | ParserTypeHttpRequest
50 | ParserTypeHttp2Request
51 | ParserTypeHttpResponse
52 | ParserTypeHttp2Response
53 | ParserTypeWebSocket
54 | )
55 |
56 | type IParser interface {
57 | detect(b []byte) error
58 | Write(b []byte) (int, error)
59 | ParserType() ParserType
60 | PacketType() PacketType
61 | //Body() []byte
62 | Name() string
63 | IsDone() bool
64 | Init()
65 | Display() []byte
66 | Reset()
67 | }
68 |
69 | var parsers = make(map[string]IParser)
70 |
71 | func Register(p IParser) {
72 | if p == nil {
73 | panic("Register Parser is nil")
74 | }
75 | name := p.Name()
76 | if _, dup := parsers[name]; dup {
77 | panic(fmt.Sprintf("Register called twice for Parser %s", name))
78 | }
79 | parsers[name] = p
80 | }
81 |
82 | func GetAllModules() map[string]IParser {
83 | return parsers
84 | }
85 |
86 | func GetModuleByName(name string) IParser {
87 | return parsers[name]
88 | }
89 |
90 | func NewParser(payload []byte) IParser {
91 | if len(payload) > 0 {
92 | var newParser IParser
93 | for _, parser := range GetAllModules() {
94 | err := parser.detect(payload)
95 | if err == nil {
96 | break
97 | }
98 | }
99 | if newParser == nil {
100 | newParser = new(DefaultParser)
101 | }
102 | newParser.Init()
103 | return newParser
104 | }
105 | var np = &DefaultParser{}
106 | np.Init()
107 | return np
108 | }
109 |
110 | type DefaultParser struct {
111 | reader *bytes.Buffer
112 | isdone bool
113 | }
114 |
115 | func (dp *DefaultParser) ParserType() ParserType {
116 | return ParserTypeNull
117 | }
118 |
119 | func (dp *DefaultParser) PacketType() PacketType {
120 | return PacketTypeNull
121 | }
122 |
123 | func (dp *DefaultParser) Write(b []byte) (int, error) {
124 | dp.isdone = true
125 | return dp.reader.Write(b)
126 | }
127 |
128 | func (dp *DefaultParser) detect(b []byte) error {
129 | return nil
130 | }
131 |
132 | func (dp *DefaultParser) Name() string {
133 | return "DefaultParser"
134 | }
135 |
136 | func (dp *DefaultParser) IsDone() bool {
137 | return dp.isdone
138 | }
139 |
140 | func (dp *DefaultParser) Init() {
141 | dp.reader = bytes.NewBuffer(nil)
142 | }
143 |
144 | func (dp *DefaultParser) Display() []byte {
145 | b := dp.reader.Bytes()
146 | if len(b) <= 0 {
147 | return []byte{}
148 | }
149 | if b[0] < 32 || b[0] > 126 {
150 | return []byte(hex.Dump(b))
151 | }
152 | return []byte(CToGoString(dp.reader.Bytes()))
153 | }
154 |
155 | func (dp *DefaultParser) Reset() {
156 | dp.isdone = false
157 | dp.reader.Reset()
158 | }
159 |
--------------------------------------------------------------------------------
/pkg/event_processor/iworker.go:
--------------------------------------------------------------------------------
1 | /*
2 |
3 | LINK - http://github.com/sipcapture/rtcagent
4 |
5 | Copyright (C) 2023 QXIP B.V.
6 |
7 | This program is free software: you can redistribute it and/or modify
8 | it under the terms of the GNU Affero General Public License as published by
9 | the Free Software Foundation, either version 3 of the License, or
10 | (at your option) any later version.
11 |
12 | This program is distributed in the hope that it will be useful,
13 | but WITHOUT ANY WARRANTY; without even the implied warranty of
14 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 | GNU Affero General Public License for more details.
16 |
17 | You should have received a copy of the GNU Affero General Public License
18 | along with this program. If not, see .
19 |
20 | */
21 |
22 | package event_processor
23 |
24 | import (
25 | "encoding/hex"
26 | "rtcagent/user/event"
27 | "time"
28 | )
29 |
30 | type IWorker interface {
31 | Write(event.IEventStruct) error
32 | GetUUID() string
33 | }
34 |
35 | const (
36 | MaxTickerCount = 10 // 1 Sencond/(eventWorker.ticker.C) = 10
37 | MaxChanLen = 16
38 | )
39 |
40 | type eventWorker struct {
41 | incoming chan event.IEventStruct
42 | //events []user.IEventStruct
43 | status ProcessStatus
44 | packetType PacketType
45 | ticker *time.Ticker
46 | tickerCount uint8
47 | UUID string
48 | processor *EventProcessor
49 | parser IParser
50 | }
51 |
52 | func NewEventWorker(uuid string, processor *EventProcessor) IWorker {
53 | eWorker := &eventWorker{}
54 | eWorker.init(uuid, processor)
55 | go func() {
56 | eWorker.Run()
57 | }()
58 | return eWorker
59 | }
60 |
61 | func (ew *eventWorker) init(uuid string, processor *EventProcessor) {
62 | ew.ticker = time.NewTicker(time.Millisecond * 100)
63 | ew.incoming = make(chan event.IEventStruct, MaxChanLen)
64 | ew.status = ProcessStateInit
65 | ew.UUID = uuid
66 | ew.processor = processor
67 | }
68 |
69 | func (ew *eventWorker) GetUUID() string {
70 | return ew.UUID
71 | }
72 |
73 | func (ew *eventWorker) Write(e event.IEventStruct) error {
74 | ew.incoming <- e
75 | return nil
76 | }
77 |
78 | func (ew *eventWorker) Display() {
79 |
80 | //if ew.parser.ParserType() != ParserTypeHttpResponse {
81 | // return
82 | //}
83 |
84 | b := ew.parser.Display()
85 |
86 | if len(b) <= 0 {
87 | return
88 | }
89 |
90 | if ew.processor.isHex {
91 | b = []byte(hex.Dump(b))
92 | }
93 |
94 | //ew.processor.GetLogger().Printf("UUID:%s, Name:%s, Type:%d, Length:%d", ew.UUID, ew.parser.Name(), ew.parser.ParserType(), len(b))
95 | ew.processor.GetLogger().Println("\n===================================================" + string(b))
96 | ew.parser.Reset()
97 | ew.status = ProcessStateDone
98 | ew.packetType = PacketTypeNull
99 | }
100 |
101 | func (ew *eventWorker) parserEvent(e event.IEventStruct) {
102 |
103 | if ew.status == ProcessStateInit {
104 | parser := NewParser(e.Payload())
105 | ew.parser = parser
106 | }
107 |
108 | ew.status = ProcessStateProcessing
109 |
110 | _, err := ew.parser.Write(e.Payload()[:e.PayloadLen()])
111 | if err != nil {
112 | ew.processor.GetLogger().Fatalf("eventWorker: detect packet type error, UUID:%s, error:%v", ew.UUID, err)
113 | }
114 |
115 | if ew.parser.IsDone() {
116 |
117 | ew.Display()
118 | }
119 |
120 | }
121 |
122 | func (ew *eventWorker) Run() {
123 | for {
124 | select {
125 | case _ = <-ew.ticker.C:
126 | //
127 | if ew.tickerCount > MaxTickerCount {
128 | ew.processor.GetLogger().Printf("eventWorker TickerCount > %d, event closed.", MaxTickerCount)
129 | ew.Close()
130 | return
131 | }
132 | ew.tickerCount++
133 | case e := <-ew.incoming:
134 | // reset tickerCount
135 | ew.tickerCount = 0
136 | ew.parserEvent(e)
137 | }
138 | }
139 |
140 | }
141 |
142 | func (ew *eventWorker) Close() {
143 | ew.ticker.Stop()
144 | ew.Display()
145 | ew.tickerCount = 0
146 | ew.processor.delWorkerByUUID(ew)
147 | }
148 |
--------------------------------------------------------------------------------
/pkg/event_processor/processor.go:
--------------------------------------------------------------------------------
1 | /*
2 |
3 | LINK - http://github.com/sipcapture/rtcagent
4 |
5 | Copyright (C) 2023 QXIP B.V.
6 |
7 | This program is free software: you can redistribute it and/or modify
8 | it under the terms of the GNU Affero General Public License as published by
9 | the Free Software Foundation, either version 3 of the License, or
10 | (at your option) any later version.
11 |
12 | This program is distributed in the hope that it will be useful,
13 | but WITHOUT ANY WARRANTY; without even the implied warranty of
14 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 | GNU Affero General Public License for more details.
16 |
17 | You should have received a copy of the GNU Affero General Public License
18 | along with this program. If not, see .
19 |
20 | */
21 |
22 | package event_processor
23 |
24 | import (
25 | "fmt"
26 | "log"
27 | "rtcagent/hepclient/hepsender"
28 | "rtcagent/user/event"
29 | "sync"
30 | )
31 |
32 | const (
33 | MaxIncomingChanLen = 1024
34 | MaxParserQueueLen = 1024
35 | )
36 |
37 | type EventProcessor struct {
38 | sync.Mutex
39 | incoming chan event.IEventStruct
40 |
41 | workerQueue map[string]IWorker
42 |
43 | logger *log.Logger
44 |
45 | // output model
46 | isHex bool
47 | }
48 |
49 | func (ep *EventProcessor) GetLogger() *log.Logger {
50 | return ep.logger
51 | }
52 |
53 | func (ep *EventProcessor) init() {
54 | ep.incoming = make(chan event.IEventStruct, MaxIncomingChanLen)
55 | ep.workerQueue = make(map[string]IWorker, MaxParserQueueLen)
56 | }
57 |
58 | // Write event
59 | func (ep *EventProcessor) Serve() {
60 | for {
61 | select {
62 | case e := <-ep.incoming:
63 | ep.dispatch(e)
64 | }
65 | }
66 | }
67 |
68 | func (ep *EventProcessor) dispatch(e event.IEventStruct) {
69 | ep.logger.Printf("event ==== ID:%s", e.String())
70 |
71 | //fmt.Printf("event ==== ID:%s\n", e.String())
72 |
73 | if e.SendHep() {
74 | ep.logger.Printf("LETS SEND HEP\n")
75 | data, err := e.GenerateHEP()
76 | if err == nil {
77 | if hepsender.Hepsender != nil {
78 | hepsender.Hepsender.Output(data)
79 | }
80 |
81 | }
82 | }
83 |
84 | //ep.
85 | //Worker will be reimplement later!
86 | /*
87 | var uuid string = e.GetUUID()
88 | found, eWorker := ep.getWorkerByUUID(uuid)
89 | if !found {
90 | // ADD a new eventWorker into queue
91 | eWorker = NewEventWorker(e.GetUUID(), ep)
92 | ep.addWorkerByUUID(eWorker)
93 | }
94 |
95 | err := eWorker.Write(e)
96 | if err != nil {
97 | //...
98 | ep.GetLogger().Fatalf("write event failed , error:%v", err)
99 | }
100 | */
101 | }
102 |
103 | //func (ep *EventProcessor) Incoming() chan user.IEventStruct {
104 | // return ep.incoming
105 | //}
106 |
107 | func (ep *EventProcessor) getWorkerByUUID(uuid string) (bool, IWorker) {
108 | ep.Lock()
109 | defer ep.Unlock()
110 | var eWorker IWorker
111 | var found bool
112 | eWorker, found = ep.workerQueue[uuid]
113 | if !found {
114 | return false, eWorker
115 | }
116 | return true, eWorker
117 | }
118 |
119 | func (ep *EventProcessor) addWorkerByUUID(worker IWorker) {
120 | ep.Lock()
121 | defer ep.Unlock()
122 | ep.workerQueue[worker.GetUUID()] = worker
123 | }
124 |
125 | func (ep *EventProcessor) delWorkerByUUID(worker IWorker) {
126 | ep.Lock()
127 | defer ep.Unlock()
128 | delete(ep.workerQueue, worker.GetUUID())
129 | }
130 |
131 | // Write event
132 | func (ep *EventProcessor) Write(e event.IEventStruct) {
133 | select {
134 | case ep.incoming <- e:
135 | return
136 | }
137 | }
138 |
139 | func (ep *EventProcessor) Close() error {
140 | if len(ep.workerQueue) > 0 {
141 | return fmt.Errorf("EventProcessor.Close(): workerQueue is not empty:%d", len(ep.workerQueue))
142 | }
143 | return nil
144 | }
145 |
146 | func NewEventProcessor(logger *log.Logger, isHex bool) *EventProcessor {
147 | var ep *EventProcessor
148 | ep = &EventProcessor{}
149 | ep.logger = logger
150 | ep.isHex = isHex
151 | ep.init()
152 | return ep
153 | }
154 |
--------------------------------------------------------------------------------
/pkg/proc/go_elf/eprint.go:
--------------------------------------------------------------------------------
1 | package main
2 |
3 | import "C"
4 | import "fmt"
5 |
6 | //export eprint
7 | func eprint(i C.int) {
8 | fmt.Printf("RtcAgent unit testing : i = %d\n", uint32(i))
9 | }
10 |
--------------------------------------------------------------------------------
/pkg/proc/go_elf/gccgo.go:
--------------------------------------------------------------------------------
1 | package main
2 |
3 | /*
4 | extern void eprint(int i);
5 |
6 | void foo(void) {
7 | int i;
8 | for (i=0;i<10;i++) {
9 | eprint(i);
10 | }
11 | }
12 | */
13 | import "C"
14 |
15 | func Foo() {
16 | C.foo()
17 | }
18 |
19 | func main() {
20 | Foo()
21 | }
22 |
--------------------------------------------------------------------------------
/pkg/proc/proc.go:
--------------------------------------------------------------------------------
1 | package proc
2 |
3 | import (
4 | "debug/buildinfo"
5 | "errors"
6 | "strconv"
7 | "strings"
8 | )
9 |
10 | const (
11 | goVersionPrefix = "Go cmd/compile "
12 | )
13 |
14 | // ErrVersionNotFound is returned when we can't find Go version info from a binary
15 | var ErrVersionNotFound = errors.New("version info not found")
16 |
17 | // GoVersion represents Go toolchain version that a binary is built with.
18 | type GoVersion struct {
19 | major int
20 | minor int
21 | }
22 |
23 | // After returns true if it is greater than major.minor
24 | func (v *GoVersion) After(major, minor int) bool {
25 | if v.major > minor {
26 | return true
27 | }
28 | if v.major == major && v.minor > minor {
29 | return true
30 | }
31 | return false
32 | }
33 |
34 | // ExtraceGoVersion extracts Go version info from a binary that is built with Go toolchain
35 | func ExtraceGoVersion(path string) (*GoVersion, error) {
36 | bi, e := buildinfo.ReadFile(path)
37 | if e != nil {
38 | return nil, ErrVersionNotFound
39 | }
40 | gv, err := parseGoVersion(bi.GoVersion)
41 | if err != nil {
42 | return nil, err
43 | }
44 | return gv, nil
45 | }
46 |
47 | func parseGoVersion(r string) (*GoVersion, error) {
48 | ver := strings.TrimPrefix(r, goVersionPrefix)
49 |
50 | if strings.HasPrefix(ver, "go") {
51 | v := strings.SplitN(ver[2:], ".", 3)
52 | var major, minor int
53 | var err error
54 |
55 | major, err = strconv.Atoi(v[0])
56 | if err != nil {
57 | return nil, err
58 | }
59 |
60 | if len(v) >= 2 {
61 | minor, err = strconv.Atoi(v[1])
62 | if err != nil {
63 | return nil, err
64 | }
65 | }
66 |
67 | return &GoVersion{
68 | major: major,
69 | minor: minor,
70 | }, nil
71 | }
72 | return nil, ErrVersionNotFound
73 | }
74 |
--------------------------------------------------------------------------------
/pkg/proc/proc_test.go:
--------------------------------------------------------------------------------
1 | package proc
2 |
3 | import (
4 | "bytes"
5 | "fmt"
6 | "os"
7 | "os/exec"
8 | "path/filepath"
9 | "testing"
10 | )
11 |
12 | const ELF_BUILD_BY_CGO = "go_elf"
13 |
14 | func TestExtraceGoVersion(t *testing.T) {
15 | path := fmt.Sprintf("/proc/%d/exe", os.Getppid())
16 | ver, err := ExtraceGoVersion(path)
17 | if err != nil {
18 | t.Log(err)
19 | return
20 | }
21 | t.Log(ver)
22 | }
23 |
24 | // cd go_elf
25 | // CGO_ENABLED=1 go build .
26 | func TestExtraceGoVersionGccgo(t *testing.T) {
27 | e := os.Chdir("go_elf")
28 | if e != nil {
29 | t.Fatalf("chdir error:%v\n", e)
30 | }
31 |
32 | p, e := os.Getwd()
33 | if e != nil {
34 | t.Fatalf("Getwd error:%v", e)
35 | }
36 | t.Logf("pwd:%s", p)
37 |
38 | // go build go_elf
39 | pathEnv := os.Getenv("PATH")
40 | t.Logf("env $PATH:%s", pathEnv)
41 |
42 | // mkdir directories
43 | goBuildPath := filepath.Join(os.TempDir(), "go-build")
44 | goEnvPath := filepath.Join(os.TempDir(), "go-env")
45 | e = os.MkdirAll(goBuildPath, os.ModePerm)
46 | if e != nil {
47 | t.Fatal(e)
48 | }
49 | e = os.MkdirAll(goEnvPath, os.ModePerm)
50 | if e != nil {
51 | t.Fatal(e)
52 | }
53 |
54 | c := exec.Command("go", "build", "-v", ".")
55 |
56 | var outb, errb bytes.Buffer
57 | c.Stdout = &outb
58 | c.Stderr = &errb
59 | e = c.Run()
60 | t.Logf("output:%s, errput:%s", outb.String(), errb.String())
61 | if e != nil {
62 | c.Stderr = os.Stderr
63 | t.Fatalf("go build failed:%v", e)
64 | }
65 |
66 | p1 := filepath.Join(p, ELF_BUILD_BY_CGO)
67 | ver, err := ExtraceGoVersion(p1)
68 | t.Logf("Extrace GoVersion from CGO ELF :%s", p1)
69 | if err != nil {
70 | t.Fatal(err)
71 | }
72 | t.Logf("version found :%v", ver)
73 | }
74 |
--------------------------------------------------------------------------------
/pkg/util/ebpf/bpf.go:
--------------------------------------------------------------------------------
1 | package ebpf
2 |
3 | import (
4 | "fmt"
5 | "os"
6 |
7 | "golang.org/x/sys/unix"
8 | )
9 |
10 | // CONFIG CHECK ITEMS
11 | var (
12 | configCheckItems = []string{
13 | "CONFIG_BPF",
14 | "CONFIG_UPROBES",
15 | "CONFIG_ARCH_SUPPORTS_UPROBES",
16 | }
17 | )
18 |
19 | type UnameInfo struct {
20 | SysName string
21 | Nodename string
22 | Release string
23 | Version string
24 | Machine string
25 | Domainname string
26 | }
27 |
28 | func getOSUnamer() (*UnameInfo, error) {
29 | u := unix.Utsname{}
30 | e := unix.Uname(&u)
31 | if e != nil {
32 | return nil, e
33 | }
34 | ui := UnameInfo{}
35 | ui.SysName = charsToString(u.Sysname)
36 | ui.Nodename = charsToString(u.Nodename)
37 | ui.Release = charsToString(u.Release)
38 | ui.Version = charsToString(u.Version)
39 | ui.Machine = charsToString(u.Machine)
40 | ui.Domainname = charsToString(u.Domainname)
41 |
42 | return &ui, nil
43 | }
44 |
45 | func charsToString(ca [65]byte) string {
46 | s := make([]byte, len(ca))
47 | var lens int
48 | for ; lens < len(ca); lens++ {
49 | if ca[lens] == 0 {
50 | break
51 | }
52 | s[lens] = uint8(ca[lens])
53 | }
54 | return string(s[0:lens])
55 | }
56 |
57 | // from internal/btf/bpf.go
58 | // checkKernelBTF attempts to load the raw vmlinux BTF blob at
59 | // /sys/kernel/btf/vmlinux and falls back to scanning the file system
60 | // for vmlinux ELFs.
61 |
62 | func checkKernelBTF() (bool, error) {
63 | _, err := os.Stat(SysKernelBtfVmlinux)
64 |
65 | // if exist ,return true
66 | if err == nil {
67 | return true, nil
68 | }
69 |
70 | return findVMLinux()
71 | }
72 |
73 | // findVMLinux scans multiple well-known paths for vmlinux kernel images.
74 | func findVMLinux() (bool, error) {
75 | kv, err := getOSUnamer()
76 | if err != nil {
77 | return false, err
78 | }
79 | release := kv.Release
80 |
81 | for _, loc := range locations {
82 | _, err := os.Stat(fmt.Sprintf(loc, release))
83 | if err != nil {
84 | continue
85 | }
86 | return true, nil
87 | }
88 | return false, err
89 | }
90 |
91 | func IsEnableBTF() (bool, error) {
92 | found, e := checkKernelBTF()
93 | if e == nil && found {
94 | return true, nil
95 | }
96 |
97 | var KernelConfig = make(map[string]string)
98 |
99 | KernelConfig, e = GetSystemConfig()
100 | if e != nil {
101 | return false, e
102 | }
103 |
104 | bc, found := KernelConfig[ConfigDebugInfoBtf]
105 | if !found {
106 | return false, nil
107 | }
108 |
109 | if bc != "y" {
110 | return false, nil
111 | }
112 | return true, nil
113 | }
114 |
115 | // check BPF CONFIG
116 | func IsEnableBPF() (bool, error) {
117 | var e error
118 | var KernelConfig = make(map[string]string)
119 |
120 | KernelConfig, e = GetSystemConfig()
121 | if e != nil {
122 | return false, e
123 | }
124 |
125 | for _, item := range configCheckItems {
126 | bc, found := KernelConfig[item]
127 | if !found {
128 | return false, fmt.Errorf("Config not found, item:%s.", item)
129 | }
130 |
131 | if bc != "y" {
132 | return false, fmt.Errorf("Config disabled, item :%s.", item)
133 | }
134 | }
135 |
136 | return true, nil
137 | }
138 |
--------------------------------------------------------------------------------
/pkg/util/ebpf/bpf_androidgki.go:
--------------------------------------------------------------------------------
1 | //go:build androidgki
2 | // +build androidgki
3 |
4 | package ebpf
5 |
6 | import (
7 | "bufio"
8 | "compress/gzip"
9 | "fmt"
10 | "os"
11 | )
12 |
13 | const (
14 | BootConfigPath = "/proc/config.gz"
15 | ConfigDebugInfoBtf = "CONFIG_DEBUG_INFO_BTF"
16 | SysKernelBtfVmlinux = "/sys/kernel/btf/vmlinux"
17 | )
18 |
19 | var (
20 | // use same list of locations as libbpf
21 | // https://android.googlesource.com/platform/external/libbpf/
22 |
23 | locations = []string{
24 | "/sys/kernel/btf/vmlinux",
25 | }
26 | )
27 |
28 | func GetSystemConfig() (map[string]string, error) {
29 | return getAndroidConfig(BootConfigPath)
30 | }
31 |
32 | func getAndroidConfig(filename string) (map[string]string, error) {
33 | var KernelConfig = make(map[string]string)
34 | // Open file bootConf.
35 | f, err := os.Open(filename)
36 | if err != nil {
37 | return KernelConfig, err
38 | }
39 | defer f.Close()
40 |
41 | // check if the file is gzipped
42 | var magic []byte
43 | var i int
44 | magic = make([]byte, 2)
45 | i, err = f.Read(magic)
46 | if err != nil {
47 | return KernelConfig, err
48 | }
49 | if i != 2 {
50 | return KernelConfig, fmt.Errorf("read %d bytes, expected 2", i)
51 | }
52 |
53 | var s *bufio.Scanner
54 | _, err = f.Seek(0, 0)
55 | if err != nil {
56 | return KernelConfig, err
57 | }
58 |
59 | var reader *gzip.Reader
60 | //magic number for gzip is 0x1f8b
61 | if magic[0] == 0x1f && magic[1] == 0x8b {
62 | // gzip file
63 | reader, err = gzip.NewReader(f)
64 | if err != nil {
65 | return KernelConfig, err
66 | }
67 | s = bufio.NewScanner(reader)
68 | } else {
69 | // not gzip file
70 | s = bufio.NewScanner(f)
71 | }
72 |
73 | if err = parse(s, KernelConfig); err != nil {
74 | return KernelConfig, err
75 | }
76 | return KernelConfig, nil
77 | }
78 |
79 | // IsContainedInCgroup returns true if the process is running in a container.
80 | func IsContainer() (bool, error) {
81 | return false, nil
82 | }
83 |
--------------------------------------------------------------------------------
/pkg/util/ebpf/bpf_linux.go:
--------------------------------------------------------------------------------
1 | //go:build !androidgki
2 | // +build !androidgki
3 |
4 | package ebpf
5 |
6 | import (
7 | "bufio"
8 | "compress/gzip"
9 | "fmt"
10 | "os"
11 | "strings"
12 | )
13 |
14 | const (
15 | SysKernelBtfVmlinux = "/sys/kernel/btf/vmlinux"
16 | ConfigDebugInfoBtf = "CONFIG_DEBUG_INFO_BTF"
17 | ProcContainerCgroupPath = "/proc/1/cgroup"
18 | ProcContainerSchedPath = "/proc/1/sched"
19 | )
20 |
21 | var (
22 | // use same list of locations as libbpf
23 | // https://github.com/libbpf/libbpf/blob/9a3a42608dbe3731256a5682a125ac1e23bced8f/src/btf.c#L3114-L3122
24 |
25 | locations = []string{
26 | "/boot/vmlinux-%s",
27 | "/lib/modules/%s/vmlinux-%[1]s",
28 | "/lib/modules/%s/build/vmlinux",
29 | "/usr/lib/modules/%s/kernel/vmlinux",
30 | "/usr/lib/debug/boot/vmlinux-%s",
31 | "/usr/lib/debug/boot/vmlinux-%s.debug",
32 | "/usr/lib/debug/lib/modules/%s/vmlinux",
33 | }
34 |
35 | configPaths = []string{
36 | "/proc/config.gz",
37 | "/boot/config",
38 | "/boot/config-%s",
39 | }
40 | )
41 |
42 | func GetSystemConfig() (map[string]string, error) {
43 | var KernelConfig = make(map[string]string)
44 | var found bool
45 | i, e := getOSUnamer()
46 | if e != nil {
47 | return KernelConfig, e
48 | }
49 |
50 | var err error
51 | for _, system_config_path := range configPaths {
52 | var bootConf = system_config_path
53 | if strings.Index(system_config_path, "%s") != -1 {
54 | bootConf = fmt.Sprintf(system_config_path, i.Release)
55 | }
56 |
57 | KernelConfig, e = getLinuxConfig(bootConf)
58 | if e != nil {
59 | err = e
60 | continue
61 | }
62 |
63 | if len(KernelConfig) > 0 {
64 | found = true
65 | break
66 | }
67 | }
68 |
69 | if !found {
70 | return nil, fmt.Errorf("KernelConfig not found. with error: %v", err)
71 | }
72 | return KernelConfig, nil
73 | }
74 |
75 | func getLinuxConfig(filename string) (map[string]string, error) {
76 | var KernelConfig = make(map[string]string)
77 |
78 | // Open file bootConf.
79 | f, err := os.Open(filename)
80 | if err != nil {
81 | return KernelConfig, err
82 | }
83 | defer f.Close()
84 |
85 | // check if the file is gzipped
86 | var magic []byte
87 | var i int
88 | magic = make([]byte, 2)
89 | i, err = f.Read(magic)
90 | if err != nil {
91 | return KernelConfig, err
92 | }
93 | if i != 2 {
94 | return KernelConfig, fmt.Errorf("read %d bytes, expected 2", i)
95 | }
96 |
97 | var s *bufio.Scanner
98 | _, err = f.Seek(0, 0)
99 | if err != nil {
100 | return KernelConfig, err
101 | }
102 |
103 | var reader *gzip.Reader
104 | //magic number for gzip is 0x1f8b
105 | if magic[0] == 0x1f && magic[1] == 0x8b {
106 | // gzip file
107 | reader, err = gzip.NewReader(f)
108 | if err != nil {
109 | return KernelConfig, err
110 | }
111 | s = bufio.NewScanner(reader)
112 | } else {
113 | // not gzip file
114 | s = bufio.NewScanner(f)
115 | }
116 |
117 | if err = parse(s, KernelConfig); err != nil {
118 | return KernelConfig, err
119 | }
120 | return KernelConfig, nil
121 | }
122 |
123 | // IsContainer returns true if the process is running in a container.
124 | func IsContainer() (bool, error) {
125 | b, e := isCOntainerCgroup()
126 | if e != nil {
127 | return false, e
128 | }
129 |
130 | // if b is true, it's a container
131 | if b {
132 | return true, nil
133 | }
134 |
135 | // if b is false, continue to check sched
136 | b, e = isCOntainerSched()
137 | if e != nil {
138 | return false, e
139 | }
140 |
141 | return b, nil
142 | }
143 |
144 | // isCOntainerCgroup returns true if the process is running in a container.
145 | // https://www.baeldung.com/linux/is-process-running-inside-container
146 |
147 | func isCOntainerCgroup() (bool, error) {
148 | var f *os.File
149 | var err error
150 | var i int
151 | f, err = os.Open(ProcContainerCgroupPath)
152 | if err != nil {
153 | return false, err
154 | }
155 | defer f.Close()
156 | b := make([]byte, 1024)
157 | i, err = f.Read(b)
158 | if err != nil {
159 | return false, err
160 | }
161 | switch {
162 | case strings.Contains(string(b[:i]), "cpuset:/docker"):
163 | // CGROUP V1 docker container
164 | return true, nil
165 | case strings.Contains(string(b[:i]), "cpuset:/kubepods"):
166 | // k8s container
167 | return true, nil
168 | case strings.Contains(string(b[:i]), "0::/\n"):
169 | // CGROUP V2 docker container
170 | return true, nil
171 | }
172 |
173 | return false, nil
174 | }
175 |
176 | // isCOntainerSched returns true if the process is running in a container.
177 | // https://man7.org/linux/man-pages/man7/sched.7.html
178 | func isCOntainerSched() (bool, error) {
179 | var f *os.File
180 | var err error
181 | var i int
182 | f, err = os.Open(ProcContainerSchedPath)
183 | if err != nil {
184 | return false, err
185 | }
186 | defer f.Close()
187 | b := make([]byte, 1024)
188 | i, err = f.Read(b)
189 | if err != nil {
190 | return false, err
191 | }
192 | switch {
193 | case strings.Contains(string(b[:i]), "bash (1, #threads"):
194 | return true, nil
195 | case strings.Contains(string(b[:i]), "run-on-arch-com (1, #threads"):
196 | return true, nil
197 | case strings.Contains(string(b[:i]), "init (1, #threads:"):
198 | return false, nil
199 | case strings.Contains(string(b[:i]), "systemd (1, #threads"):
200 | return false, nil
201 | }
202 |
203 | return false, nil
204 | }
205 |
--------------------------------------------------------------------------------
/pkg/util/ebpf/config.gz:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sipcapture/rtcagent/6e4bba460ef57079552fcd03e4b790b6a712d4c3/pkg/util/ebpf/config.gz
--------------------------------------------------------------------------------
/pkg/util/ebpf/parse.go:
--------------------------------------------------------------------------------
1 | package ebpf
2 |
3 | import (
4 | "bufio"
5 | "fmt"
6 | "regexp"
7 | "strings"
8 | )
9 |
10 | func parse(s *bufio.Scanner, p map[string]string) error {
11 | r, _ := regexp.Compile("^(?:# *)?(CONFIG_\\w*)(?:=| )(y|n|m|is not set|\\d+|0x.+|\".*\")$")
12 |
13 | for s.Scan() {
14 |
15 | t := s.Text()
16 |
17 | // Skip line if empty.
18 | if t == "" {
19 | continue
20 | }
21 |
22 | // 0 is the match of the entire expression,
23 | // 1 is the key, 2 is the value.
24 | m := r.FindStringSubmatch(t)
25 | if m == nil {
26 | continue
27 | }
28 |
29 | if len(m) != 3 {
30 | return fmt.Errorf("match is not 3 chars long: %v", m)
31 | }
32 | // Remove all leading and trailing double quotes from the value.
33 | if len(m[2]) > 1 {
34 | m[2] = strings.Trim(m[2], "\"")
35 | }
36 |
37 | // Insert entry into map.
38 | p[m[1]] = m[2]
39 | }
40 |
41 | if err := s.Err(); err != nil {
42 | return err
43 | }
44 |
45 | return nil
46 | }
47 |
--------------------------------------------------------------------------------
/pkg/util/hkdf/hkdf.go:
--------------------------------------------------------------------------------
1 | // Copyright 2022 CFC4N . All Rights Reserved.
2 | //
3 | // Licensed under the Apache License, Version 2.0 (the "License");
4 | // you may not use this file except in compliance with the License.
5 | // You may obtain a copy of the License at
6 | //
7 | // http://www.apache.org/licenses/LICENSE-2.0
8 | //
9 | // Unless required by applicable law or agreed to in writing, software
10 | // distributed under the License is distributed on an "AS IS" BASIS,
11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | // See the License for the specific language governing permissions and
13 | // limitations under the License.
14 |
15 | package hkdf
16 |
17 | // Copyright 2014 The Go Authors. All rights reserved.
18 | // Use of this source code is governed by a BSD-style
19 | // license that can be found in the LICENSE file.
20 |
21 | // Mostly derived from golang.org/x/crypto/hkdf, but with an exposed
22 | // Extract API.
23 | //
24 | // HKDF is a cryptographic key derivation function (KDF) with the goal of
25 | // expanding limited input keying material into one or more cryptographically
26 | // strong secret keys.
27 | //
28 | // RFC 5869: https://tools.ietf.org/html/rfc5869
29 |
30 | import (
31 | "crypto"
32 |
33 | "golang.org/x/crypto/cryptobyte"
34 | "golang.org/x/crypto/hkdf"
35 | )
36 |
37 | const (
38 | ResumptionBinderLabel = "res binder"
39 | ClientHandshakeTrafficLabel = "c hs traffic"
40 | ServerHandshakeTrafficLabel = "s hs traffic"
41 | ClientApplicationTrafficLabel = "c ap traffic"
42 | ServerApplicationTrafficLabel = "s ap traffic"
43 | ExporterLabel = "exp master"
44 | ResumptionLabel = "res master"
45 | TrafficUpdateLabel = "traffic upd"
46 | )
47 |
48 | const (
49 | KeyLogLabelTLS12 = "CLIENT_RANDOM"
50 | KeyLogLabelClientHandshake = "CLIENT_HANDSHAKE_TRAFFIC_SECRET"
51 | KeyLogLabelServerHandshake = "SERVER_HANDSHAKE_TRAFFIC_SECRET"
52 | KeyLogLabelClientTraffic = "CLIENT_TRAFFIC_SECRET_0"
53 | KeyLogLabelServerTraffic = "SERVER_TRAFFIC_SECRET_0"
54 | KeyLogLabelExporterSecret = "EXPORTER_SECRET"
55 | KeyLogLabelClientEarlyTafficSecret = "CLIENT_EARLY_TRAFFIC_SECRET"
56 | )
57 |
58 | // crypto/tls/cipher_suites.go line 678
59 | // TLS 1.3 cipher suites.
60 | const (
61 | TlsAes128GcmSha256 uint16 = 0x1301
62 | TlsAes256GcmSha384 uint16 = 0x1302
63 | TlsChacha20Poly1305Sha256 uint16 = 0x1303
64 | )
65 |
66 | // ExpandLabel implements HKDF-Expand-Label from RFC 8446, Section 7.1.
67 | func ExpandLabel(secret []byte, label string, context []byte, length int, transcript crypto.Hash) []byte {
68 | var hkdfLabel cryptobyte.Builder
69 | hkdfLabel.AddUint16(uint16(length))
70 | hkdfLabel.AddUint8LengthPrefixed(func(b *cryptobyte.Builder) {
71 | b.AddBytes([]byte("tls13 "))
72 | b.AddBytes([]byte(label))
73 | })
74 | hkdfLabel.AddUint8LengthPrefixed(func(b *cryptobyte.Builder) {
75 | b.AddBytes(context[:length])
76 | })
77 | out := make([]byte, length)
78 |
79 | n, err := hkdf.Expand(transcript.New, secret[:length], hkdfLabel.BytesOrPanic()).Read(out)
80 | if err != nil || n != length {
81 | panic("tls: HKDF-Expand-Label invocation failed unexpectedly")
82 | }
83 | return out
84 | }
85 |
--------------------------------------------------------------------------------
/pkg/util/hkdf/hkdf_test.go:
--------------------------------------------------------------------------------
1 | package hkdf
2 |
3 | import (
4 | "crypto"
5 | _ "crypto/sha256"
6 | _ "crypto/sha512"
7 | "testing"
8 | )
9 |
10 | func TestHkdf(t *testing.T) {
11 | t.Log("TestHkdf")
12 | //TODO
13 | var length int
14 | var transcript crypto.Hash
15 | var cipherId uint32 = 50336513
16 | // test with different cipherID
17 | switch uint16(cipherId & 0x0000FFFF) {
18 | case TlsAes128GcmSha256, TlsChacha20Poly1305Sha256:
19 | length = 32
20 | transcript = crypto.SHA256
21 | case TlsAes256GcmSha384:
22 | length = 48
23 | transcript = crypto.SHA384
24 | default:
25 | t.Log("Unknown cipher")
26 | }
27 |
28 | // HandshakeSecret
29 | handshakeSecret := []byte{0x33, 0xad, 0x0a, 0x1c, 0x60, 0x7e, 0xc0, 0x3b, 0x09, 0xe6, 0xcd, 0x98, 0x93, 0x68, 0x0c, 0xe2, 0x10, 0xad, 0xf3, 0x00, 0xaa, 0x1f, 0x26, 0x60, 0xe1, 0xb2, 0x2e, 0x10, 0xf1, 0x70, 0xf9, 0x2a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}
30 | // MasterSecret
31 | masterSecret := []byte{0x95, 0x8a, 0x8a, 0xfc, 0xa1, 0x12, 0x34, 0xac, 0x64, 0xf5, 0x9b, 0x09, 0xb3, 0xd2, 0xaf, 0xbb, 0xd3, 0xe8, 0x46, 0x4d, 0xce, 0xa5, 0x27, 0x6d, 0x30, 0xd4, 0x26, 0x85, 0x5a, 0x7a, 0xde, 0x77, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}
32 | // HandshakeTrafficHash
33 | handshakeTrafficHash := []byte{0x89, 0xf6, 0x4d, 0x87, 0xef, 0xf1, 0x30, 0x91, 0xfb, 0xa9, 0x9f, 0x20, 0x20, 0xb5, 0x16, 0xf9, 0x3a, 0x4a, 0xc4, 0x51, 0x6a, 0xd2, 0x6a, 0x94, 0x62, 0x04, 0x27, 0xe4, 0xe9, 0xa1, 0xd5, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}
34 | // ServerFinishedHash
35 | serverFinishedHash := []byte{0x75, 0x28, 0xcb, 0x64, 0x54, 0xfb, 0x4c, 0xab, 0xbc, 0x00, 0x6a, 0x64, 0x01, 0xaa, 0xc6, 0xf3, 0x7f, 0x7d, 0xa0, 0x82, 0x72, 0x66, 0xc0, 0x6c, 0x5b, 0xbd, 0x96, 0x91, 0x02, 0xac, 0xf6, 0xfc, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}
36 | // ExporterMasterSecret
37 | exporterMasterSecret := []byte{0x7d, 0x43, 0x64, 0x4b, 0xfa, 0x10, 0x38, 0x66, 0x18, 0x54, 0xac, 0x12, 0xff, 0x72, 0x6c, 0xcf, 0x26, 0xbe, 0x8d, 0x80, 0x8c, 0xf2, 0x0b, 0x16, 0x05, 0x71, 0xb1, 0xd4, 0xd4, 0xab, 0x5e, 0x0a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}
38 |
39 | clientHandshakeSecret := ExpandLabel(handshakeSecret[:length],
40 | ClientHandshakeTrafficLabel, handshakeTrafficHash[:length], length, transcript)
41 | t.Logf("%s: %x", KeyLogLabelClientHandshake, clientHandshakeSecret)
42 |
43 | serverHandshakeSecret := ExpandLabel(handshakeSecret[:length],
44 | ServerHandshakeTrafficLabel, handshakeTrafficHash[:length], length, transcript)
45 | t.Logf("%s: %x", KeyLogLabelServerHandshake, serverHandshakeSecret)
46 |
47 | clientTrafficSecret := ExpandLabel(masterSecret[:length],
48 | ClientApplicationTrafficLabel, serverFinishedHash[:length], length, transcript)
49 | t.Logf("%s: %x", KeyLogLabelClientTraffic, clientTrafficSecret)
50 |
51 | serverTrafficSecret := ExpandLabel(masterSecret[:length],
52 | ServerApplicationTrafficLabel, serverFinishedHash[:length], length, transcript)
53 | t.Logf("%s: %x", KeyLogLabelServerTraffic, serverTrafficSecret)
54 |
55 | t.Logf("%s: %x", KeyLogLabelExporterSecret, exporterMasterSecret[:length])
56 | }
57 |
--------------------------------------------------------------------------------
/pkg/util/kernel/kernel_version.go:
--------------------------------------------------------------------------------
1 | //go:build linux
2 | // +build linux
3 |
4 | // Copyright 2016-2017 Kinvolk
5 | //
6 | // Licensed under the Apache License, Version 2.0 (the "License");
7 | // you may not use this file except in compliance with the License.
8 | // You may obtain a copy of the License at
9 | //
10 | // http://www.apache.org/licenses/LICENSE-2.0
11 | //
12 | // Unless required by applicable law or agreed to in writing, software
13 | // distributed under the License is distributed on an "AS IS" BASIS,
14 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 | // See the License for the specific language governing permissions and
16 | // limitations under the License.
17 |
18 | package kernel
19 |
20 | import (
21 | "fmt"
22 | "io/ioutil"
23 | "regexp"
24 | "strconv"
25 | "strings"
26 | "syscall"
27 | )
28 |
29 | var versionRegex = regexp.MustCompile(`^(\d+)\.(\d+)(?:.(\d+))?.*$`)
30 |
31 | // KernelVersionFromReleaseString converts a release string with format
32 | // 4.4.2[-1] to a kernel version number in LINUX_VERSION_CODE format.
33 | // That is, for kernel "a.b.c", the version number will be (a<<16 + b<<8 + c)
34 | func KernelVersionFromReleaseString(releaseString string) (uint32, error) {
35 | versionParts := versionRegex.FindStringSubmatch(releaseString)
36 | if len(versionParts) < 3 {
37 | return 0, fmt.Errorf("got invalid release version %q (expected format '4.3.2-1')", releaseString)
38 | }
39 | var major, minor, patch uint64
40 | var err error
41 | major, err = strconv.ParseUint(versionParts[1], 10, 8)
42 | if err != nil {
43 | return 0, err
44 | }
45 |
46 | minor, err = strconv.ParseUint(versionParts[2], 10, 8)
47 | if err != nil {
48 | return 0, err
49 | }
50 |
51 | // patch is optional
52 | if len(versionParts) >= 4 {
53 | patch, _ = strconv.ParseUint(versionParts[3], 10, 8)
54 | }
55 |
56 | // clamp patch/sublevel to 255 EARLY in 4.14.252 because they merged this too early:
57 | // https://github.com/torvalds/linux/commit/e131e0e880f942f138c4b5e6af944c7ddcd7ec96
58 | if major == 4 && minor == 14 && patch >= 252 {
59 | patch = 255
60 | }
61 |
62 | out := major*256*256 + minor*256 + patch
63 | return uint32(out), nil
64 | }
65 |
66 | func currentVersionUname() (uint32, error) {
67 | var buf syscall.Utsname
68 | if err := syscall.Uname(&buf); err != nil {
69 | return 0, err
70 | }
71 | releaseString := strings.Trim(utsnameStr(buf.Release[:]), "\x00")
72 | return KernelVersionFromReleaseString(releaseString)
73 | }
74 |
75 | func currentVersionUbuntu() (uint32, error) {
76 | procVersion, err := ioutil.ReadFile("/proc/version_signature")
77 | if err != nil {
78 | return 0, err
79 | }
80 | return parseUbuntuVersion(string(procVersion))
81 | }
82 |
83 | func parseUbuntuVersion(procVersion string) (uint32, error) {
84 | var u1, u2, releaseString string
85 | _, err := fmt.Sscanf(procVersion, "%s %s %s", &u1, &u2, &releaseString)
86 | if err != nil {
87 | return 0, err
88 | }
89 | return KernelVersionFromReleaseString(releaseString)
90 | }
91 |
92 | var debianVersionRegex = regexp.MustCompile(`.* SMP Debian (\d+\.\d+.\d+-\d+)(?:\+[[:alnum:]]*)?.*`)
93 |
94 | func parseDebianVersion(str string) (uint32, error) {
95 | match := debianVersionRegex.FindStringSubmatch(str)
96 | if len(match) != 2 {
97 | return 0, fmt.Errorf("failed to parse kernel version from /proc/version: %s", str)
98 | }
99 | return KernelVersionFromReleaseString(match[1])
100 | }
101 |
102 | func currentVersionDebian() (uint32, error) {
103 | procVersion, err := ioutil.ReadFile("/proc/version")
104 | if err != nil {
105 | return 0, fmt.Errorf("error reading /proc/version: %s", err)
106 | }
107 |
108 | return parseDebianVersion(string(procVersion))
109 | }
110 |
111 | // CurrentKernelVersion returns the current kernel version in
112 | // LINUX_VERSION_CODE format (see KernelVersionFromReleaseString())
113 | func CurrentKernelVersion() (uint32, error) {
114 | // We need extra checks for Debian and Ubuntu as they modify
115 | // the kernel version patch number for compatibility with
116 | // out-of-tree modules. Linux perf tools do the same for Ubuntu
117 | // systems: https://github.com/torvalds/linux/commit/d18acd15c
118 | //
119 | // See also:
120 | // https://kernel-handbook.alioth.debian.org/ch-versions.html
121 | // https://wiki.ubuntu.com/Kernel/FAQ
122 | version, err := currentVersionUbuntu()
123 | if err == nil {
124 | return version, nil
125 | }
126 | version, err = currentVersionDebian()
127 | if err == nil {
128 | return version, nil
129 | }
130 | return currentVersionUname()
131 | }
132 |
133 | func utsnameStr(in []int8) string {
134 | out := make([]byte, len(in))
135 | for i := 0; i < len(in); i++ {
136 | if in[i] == 0 {
137 | break
138 | }
139 | out = append(out, byte(in[i]))
140 | }
141 | return string(out)
142 | }
143 |
--------------------------------------------------------------------------------
/pkg/util/kernel/kernel_version_unsupport.go:
--------------------------------------------------------------------------------
1 | //go:build !linux
2 | // +build !linux
3 |
4 | package kernel
5 |
6 | import (
7 | "fmt"
8 |
9 | "runtime"
10 | )
11 |
12 | var ErrNonLinux = fmt.Errorf("unsupported platform %s/%s", runtime.GOOS, runtime.GOARCH)
13 |
14 | func KernelVersionFromReleaseString(releaseString string) (uint32, error) {
15 | return 0, ErrNonLinux
16 | }
17 |
18 | func CurrentKernelVersion() (uint32, error) {
19 | return 0, ErrNonLinux
20 | }
21 |
--------------------------------------------------------------------------------
/pkg/util/kernel/version.go:
--------------------------------------------------------------------------------
1 | //go:build linux
2 | // +build linux
3 |
4 | package kernel
5 |
6 | import (
7 | "fmt"
8 | )
9 |
10 | // Version is a numerical representation of a kernel version
11 | type Version uint32
12 |
13 | var hostVersion Version
14 |
15 | // String returns a string representing the version in x.x.x format
16 | func (v Version) String() string {
17 | a, b, c := v>>16, v>>8&0xff, v&0xff
18 | return fmt.Sprintf("%d.%d.%d", a, b, c)
19 | }
20 |
21 | // HostVersion returns the running kernel version of the host
22 | func HostVersion() (Version, error) {
23 | if hostVersion != 0 {
24 | return hostVersion, nil
25 | }
26 | kv, err := CurrentKernelVersion()
27 | if err != nil {
28 | return 0, err
29 | }
30 | hostVersion = Version(kv)
31 | return hostVersion, nil
32 | }
33 |
34 | // ParseVersion parses a string in the format of x.x.x to a Version
35 | func ParseVersion(s string) Version {
36 | var a, b, c byte
37 | fmt.Sscanf(s, "%d.%d.%d", &a, &b, &c)
38 | return VersionCode(a, b, c)
39 | }
40 |
41 | // VersionCode returns a Version computed from the individual parts of a x.x.x version
42 | func VersionCode(major, minor, patch byte) Version {
43 | // KERNEL_VERSION(a,b,c) = (a << 16) + (b << 8) + (c)
44 | // Per https://github.com/torvalds/linux/blob/db7c953555388571a96ed8783ff6c5745ba18ab9/Makefile#L1250
45 | return Version((uint32(major) << 16) + (uint32(minor) << 8) + uint32(patch))
46 | }
47 |
--------------------------------------------------------------------------------
/rtcagent.service:
--------------------------------------------------------------------------------
1 | [Unit]
2 | Description=Captures packets with eBPF Filter and sends them to Homer
3 | Wants=network.target
4 | After=network.target
5 |
6 | [Service]
7 | #this service file uses Kamailio binary for FreeSWITCH change the command accordingly
8 | ExecStart=/usr/bin/rtcagent kamailio -m /opt/kamailio/sbin/kamailio --hep-server="127.0.0.1" --hep-port="9060" --hep-transport="tcp" --debug=false
9 | ExecStop=/bin/kill ${MAINPID}
10 | Restart=on-failure
11 | RestartSec=10s
12 | Type=simple
13 |
14 | [Install]
15 | WantedBy=multi-user.target
16 |
--------------------------------------------------------------------------------
/rtcagent.yml:
--------------------------------------------------------------------------------
1 | name: rtcagent
2 | arch: amd64
3 | platform: linux
4 | version: 0.0.0
5 | release: 1
6 | section: default
7 | priority: extra
8 | replaces:
9 | - rtcagent
10 | provides:
11 | - rtcagent
12 | maintainer: Alexandr Dubovikob
13 | description: RTCagent is a HEP/eBPF sniffer for VoiP/RTC Applications
14 | vendor: sipcapture.org
15 | homepage: http://sipcapture.org
16 | license: AGPLv3
17 | contents:
18 | - src: ./bin/rtcagent
19 | dst: /usr/bin/rtcagent
20 |
--------------------------------------------------------------------------------
/runagent.sh:
--------------------------------------------------------------------------------
1 | ./bin/rtcagent kamailio --hep-port=9060 --hep-server=homer.null.qxip.net
2 | #./bin/rtcagent opensips --hep-port=9060 --hep-server=homer.null.qxip.net
3 |
--------------------------------------------------------------------------------
/user/bytecode/.gitkeep:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sipcapture/rtcagent/6e4bba460ef57079552fcd03e4b790b6a712d4c3/user/bytecode/.gitkeep
--------------------------------------------------------------------------------
/user/bytecode/freeswitch_kern.d:
--------------------------------------------------------------------------------
1 | user/bytecode/freeswitch_kern.o: kern/freeswitch_kern.c kern/freeswitch.h \
2 | kern/rtcagent.h kern/bpf/x86/vmlinux.h kern/bpf/bpf_core_read.h \
3 | kern/bpf/bpf_helpers.h kern/bpf/bpf_helper_defs.h \
4 | kern/bpf/bpf_tracing.h kern/bpf/bpf_endian.h kern/common.h
5 |
6 | kern/freeswitch.h:
7 |
8 | kern/rtcagent.h:
9 |
10 | kern/bpf/x86/vmlinux.h:
11 |
12 | kern/bpf/bpf_core_read.h:
13 |
14 | kern/bpf/bpf_helpers.h:
15 |
16 | kern/bpf/bpf_helper_defs.h:
17 |
18 | kern/bpf/bpf_tracing.h:
19 |
20 | kern/bpf/bpf_endian.h:
21 |
22 | kern/common.h:
23 |
--------------------------------------------------------------------------------
/user/bytecode/freeswitch_kern.o:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sipcapture/rtcagent/6e4bba460ef57079552fcd03e4b790b6a712d4c3/user/bytecode/freeswitch_kern.o
--------------------------------------------------------------------------------
/user/bytecode/freeswitch_kern_less52.d:
--------------------------------------------------------------------------------
1 | user/bytecode/freeswitch_kern_less52.o: kern/freeswitch_kern.c \
2 | kern/freeswitch.h kern/rtcagent.h kern/bpf/x86/vmlinux.h \
3 | kern/bpf/bpf_core_read.h kern/bpf/bpf_helpers.h \
4 | kern/bpf/bpf_helper_defs.h kern/bpf/bpf_tracing.h \
5 | kern/bpf/bpf_endian.h kern/common.h
6 |
7 | kern/freeswitch.h:
8 |
9 | kern/rtcagent.h:
10 |
11 | kern/bpf/x86/vmlinux.h:
12 |
13 | kern/bpf/bpf_core_read.h:
14 |
15 | kern/bpf/bpf_helpers.h:
16 |
17 | kern/bpf/bpf_helper_defs.h:
18 |
19 | kern/bpf/bpf_tracing.h:
20 |
21 | kern/bpf/bpf_endian.h:
22 |
23 | kern/common.h:
24 |
--------------------------------------------------------------------------------
/user/bytecode/freeswitch_kern_less52.o:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sipcapture/rtcagent/6e4bba460ef57079552fcd03e4b790b6a712d4c3/user/bytecode/freeswitch_kern_less52.o
--------------------------------------------------------------------------------
/user/bytecode/kamailio_kern.d:
--------------------------------------------------------------------------------
1 | user/bytecode/kamailio_kern.o: kern/kamailio_kern.c kern/kamailio.h \
2 | kern/rtcagent.h kern/bpf/x86/vmlinux.h kern/bpf/bpf_core_read.h \
3 | kern/bpf/bpf_helpers.h kern/bpf/bpf_helper_defs.h \
4 | kern/bpf/bpf_tracing.h kern/bpf/bpf_endian.h kern/common.h
5 |
6 | kern/kamailio.h:
7 |
8 | kern/rtcagent.h:
9 |
10 | kern/bpf/x86/vmlinux.h:
11 |
12 | kern/bpf/bpf_core_read.h:
13 |
14 | kern/bpf/bpf_helpers.h:
15 |
16 | kern/bpf/bpf_helper_defs.h:
17 |
18 | kern/bpf/bpf_tracing.h:
19 |
20 | kern/bpf/bpf_endian.h:
21 |
22 | kern/common.h:
23 |
--------------------------------------------------------------------------------
/user/bytecode/kamailio_kern.o:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sipcapture/rtcagent/6e4bba460ef57079552fcd03e4b790b6a712d4c3/user/bytecode/kamailio_kern.o
--------------------------------------------------------------------------------
/user/bytecode/kamailio_kern_less52.d:
--------------------------------------------------------------------------------
1 | user/bytecode/kamailio_kern_less52.o: kern/kamailio_kern.c \
2 | kern/kamailio.h kern/rtcagent.h kern/bpf/x86/vmlinux.h \
3 | kern/bpf/bpf_core_read.h kern/bpf/bpf_helpers.h \
4 | kern/bpf/bpf_helper_defs.h kern/bpf/bpf_tracing.h \
5 | kern/bpf/bpf_endian.h kern/common.h
6 |
7 | kern/kamailio.h:
8 |
9 | kern/rtcagent.h:
10 |
11 | kern/bpf/x86/vmlinux.h:
12 |
13 | kern/bpf/bpf_core_read.h:
14 |
15 | kern/bpf/bpf_helpers.h:
16 |
17 | kern/bpf/bpf_helper_defs.h:
18 |
19 | kern/bpf/bpf_tracing.h:
20 |
21 | kern/bpf/bpf_endian.h:
22 |
23 | kern/common.h:
24 |
--------------------------------------------------------------------------------
/user/bytecode/kamailio_kern_less52.o:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sipcapture/rtcagent/6e4bba460ef57079552fcd03e4b790b6a712d4c3/user/bytecode/kamailio_kern_less52.o
--------------------------------------------------------------------------------
/user/bytecode/monitor_kern.d:
--------------------------------------------------------------------------------
1 | user/bytecode/monitor_kern.o: kern/monitor_kern.c kern/bpf/x86/vmlinux.h \
2 | kern/bpf/bpf_helpers.h kern/bpf/bpf_helper_defs.h \
3 | kern/bpf/bpf_endian.h kern/bpf/bpf_tracing.h kern/bpf/bpf_core_read.h
4 |
5 | kern/bpf/x86/vmlinux.h:
6 |
7 | kern/bpf/bpf_helpers.h:
8 |
9 | kern/bpf/bpf_helper_defs.h:
10 |
11 | kern/bpf/bpf_endian.h:
12 |
13 | kern/bpf/bpf_tracing.h:
14 |
15 | kern/bpf/bpf_core_read.h:
16 |
--------------------------------------------------------------------------------
/user/bytecode/monitor_kern.o:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sipcapture/rtcagent/6e4bba460ef57079552fcd03e4b790b6a712d4c3/user/bytecode/monitor_kern.o
--------------------------------------------------------------------------------
/user/bytecode/monitor_kern_less52.d:
--------------------------------------------------------------------------------
1 | user/bytecode/monitor_kern_less52.o: kern/monitor_kern.c \
2 | kern/bpf/x86/vmlinux.h kern/bpf/bpf_helpers.h \
3 | kern/bpf/bpf_helper_defs.h kern/bpf/bpf_endian.h \
4 | kern/bpf/bpf_tracing.h kern/bpf/bpf_core_read.h
5 |
6 | kern/bpf/x86/vmlinux.h:
7 |
8 | kern/bpf/bpf_helpers.h:
9 |
10 | kern/bpf/bpf_helper_defs.h:
11 |
12 | kern/bpf/bpf_endian.h:
13 |
14 | kern/bpf/bpf_tracing.h:
15 |
16 | kern/bpf/bpf_core_read.h:
17 |
--------------------------------------------------------------------------------
/user/bytecode/monitor_kern_less52.o:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sipcapture/rtcagent/6e4bba460ef57079552fcd03e4b790b6a712d4c3/user/bytecode/monitor_kern_less52.o
--------------------------------------------------------------------------------
/user/bytecode/opensips_kern.d:
--------------------------------------------------------------------------------
1 | user/bytecode/opensips_kern.o: kern/opensips_kern.c kern/opensips.h \
2 | kern/rtcagent.h kern/bpf/x86/vmlinux.h kern/bpf/bpf_core_read.h \
3 | kern/bpf/bpf_helpers.h kern/bpf/bpf_helper_defs.h \
4 | kern/bpf/bpf_tracing.h kern/bpf/bpf_endian.h kern/common.h
5 |
6 | kern/opensips.h:
7 |
8 | kern/rtcagent.h:
9 |
10 | kern/bpf/x86/vmlinux.h:
11 |
12 | kern/bpf/bpf_core_read.h:
13 |
14 | kern/bpf/bpf_helpers.h:
15 |
16 | kern/bpf/bpf_helper_defs.h:
17 |
18 | kern/bpf/bpf_tracing.h:
19 |
20 | kern/bpf/bpf_endian.h:
21 |
22 | kern/common.h:
23 |
--------------------------------------------------------------------------------
/user/bytecode/opensips_kern.o:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sipcapture/rtcagent/6e4bba460ef57079552fcd03e4b790b6a712d4c3/user/bytecode/opensips_kern.o
--------------------------------------------------------------------------------
/user/bytecode/opensips_kern_less52.d:
--------------------------------------------------------------------------------
1 | user/bytecode/opensips_kern_less52.o: kern/opensips_kern.c \
2 | kern/opensips.h kern/rtcagent.h kern/bpf/x86/vmlinux.h \
3 | kern/bpf/bpf_core_read.h kern/bpf/bpf_helpers.h \
4 | kern/bpf/bpf_helper_defs.h kern/bpf/bpf_tracing.h \
5 | kern/bpf/bpf_endian.h kern/common.h
6 |
7 | kern/opensips.h:
8 |
9 | kern/rtcagent.h:
10 |
11 | kern/bpf/x86/vmlinux.h:
12 |
13 | kern/bpf/bpf_core_read.h:
14 |
15 | kern/bpf/bpf_helpers.h:
16 |
17 | kern/bpf/bpf_helper_defs.h:
18 |
19 | kern/bpf/bpf_tracing.h:
20 |
21 | kern/bpf/bpf_endian.h:
22 |
23 | kern/common.h:
24 |
--------------------------------------------------------------------------------
/user/bytecode/opensips_kern_less52.o:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sipcapture/rtcagent/6e4bba460ef57079552fcd03e4b790b6a712d4c3/user/bytecode/opensips_kern_less52.o
--------------------------------------------------------------------------------
/user/bytecode/tcprtt_kern.d:
--------------------------------------------------------------------------------
1 | user/bytecode/tcprtt_kern.o: kern/tcprtt_kern.c kern/common2.h \
2 | kern/bpf/bpf_helpers.h kern/bpf/bpf_helper_defs.h \
3 | kern/bpf/bpf_endian.h kern/bpf/bpf_tracing.h
4 |
5 | kern/common2.h:
6 |
7 | kern/bpf/bpf_helpers.h:
8 |
9 | kern/bpf/bpf_helper_defs.h:
10 |
11 | kern/bpf/bpf_endian.h:
12 |
13 | kern/bpf/bpf_tracing.h:
14 |
--------------------------------------------------------------------------------
/user/bytecode/tcprtt_kern.o:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sipcapture/rtcagent/6e4bba460ef57079552fcd03e4b790b6a712d4c3/user/bytecode/tcprtt_kern.o
--------------------------------------------------------------------------------
/user/bytecode/tcprtt_kern_less52.d:
--------------------------------------------------------------------------------
1 | user/bytecode/tcprtt_kern_less52.o: kern/tcprtt_kern.c kern/common2.h \
2 | kern/bpf/bpf_helpers.h kern/bpf/bpf_helper_defs.h \
3 | kern/bpf/bpf_endian.h kern/bpf/bpf_tracing.h
4 |
5 | kern/common2.h:
6 |
7 | kern/bpf/bpf_helpers.h:
8 |
9 | kern/bpf/bpf_helper_defs.h:
10 |
11 | kern/bpf/bpf_endian.h:
12 |
13 | kern/bpf/bpf_tracing.h:
14 |
--------------------------------------------------------------------------------
/user/bytecode/tcprtt_kern_less52.o:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sipcapture/rtcagent/6e4bba460ef57079552fcd03e4b790b6a712d4c3/user/bytecode/tcprtt_kern_less52.o
--------------------------------------------------------------------------------
/user/config/common.go:
--------------------------------------------------------------------------------
1 | /*
2 |
3 | LINK - http://github.com/sipcapture/rtcagent
4 |
5 | Copyright (C) 2023 QXIP B.V.
6 |
7 | This program is free software: you can redistribute it and/or modify
8 | it under the terms of the GNU Affero General Public License as published by
9 | the Free Software Foundation, either version 3 of the License, or
10 | (at your option) any later version.
11 |
12 | This program is distributed in the hope that it will be useful,
13 | but WITHOUT ANY WARRANTY; without even the implied warranty of
14 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 | GNU Affero General Public License for more details.
16 |
17 | You should have received a copy of the GNU Affero General Public License
18 | along with this program. If not, see .
19 |
20 | */
21 |
22 | package config
23 |
24 | import (
25 | "bufio"
26 | "debug/elf"
27 | "fmt"
28 | "log"
29 | "os"
30 | "path/filepath"
31 | "strings"
32 |
33 | "errors"
34 | )
35 |
36 | func GlobMany(targets []string, onErr func(string, error)) []string {
37 | rv := make([]string, 0, 20)
38 | addFile := func(path string, fi os.FileInfo, err error) error {
39 | if err != nil {
40 | log.Println(err.Error())
41 | return err
42 | }
43 | rv = append(rv, path)
44 | return err
45 | }
46 |
47 | for _, p := range targets {
48 | // "p" is a wildcard pattern? expand it:
49 | if strings.Contains(p, "*") {
50 | matches, err := filepath.Glob(p)
51 | if err == nil {
52 | // walk each match:
53 | for _, p := range matches {
54 | e := filepath.Walk(p, addFile)
55 | if e != nil {
56 | continue
57 | }
58 | }
59 | }
60 | // path is not a wildcard, walk it:
61 | } else {
62 | e := filepath.Walk(p, addFile)
63 | if e != nil {
64 | return []string{}
65 | }
66 | }
67 | }
68 | return rv
69 | }
70 |
71 | // ParseDynLibConf reads/parses DL config files defined as a pattern
72 | // and returns a list of directories found in there (or an error).
73 | func ParseDynLibConf(pattern string) (dirs []string, err error) {
74 | files := GlobMany([]string{pattern}, nil)
75 |
76 | for _, configFile := range files {
77 | if strings.Contains(configFile, "lib32") {
78 | continue
79 | }
80 | fd, err := os.Open(configFile)
81 | if err != nil {
82 | return dirs, err
83 | }
84 | defer fd.Close()
85 |
86 | sc := bufio.NewScanner(fd)
87 | for sc.Scan() {
88 | line := strings.TrimSpace(sc.Text())
89 | // ignore comments and empty lines
90 | if len(line) == 0 || line[0] == '#' || line[0] == ';' {
91 | continue
92 | }
93 | // found "include" directive?
94 | words := strings.Fields(line)
95 | if strings.ToLower(words[0]) == "include" {
96 | subdirs, err := ParseDynLibConf(words[1])
97 | if err != nil && !os.IsNotExist(err) {
98 | return dirs, err
99 | }
100 | dirs = append(dirs, subdirs...)
101 | } else {
102 | dirs = append(dirs, line)
103 | }
104 | }
105 | }
106 | if len(dirs) <= 0 {
107 | err = errors.New(fmt.Sprintf("read keylogger :%s error .", pattern))
108 | }
109 | return dirs, err
110 | }
111 |
112 | // getDynsFromElf get shared objects from ELF keylogger
113 | func getDynsFromElf(file string) ([]string, error) {
114 | f, e := elf.Open(file)
115 | if e != nil {
116 | return nil, e
117 | }
118 | neededs, err := f.DynString(elf.DT_NEEDED)
119 | return neededs, err
120 | }
121 |
122 | // getDynPathByElf found soPath by soName from elfName
123 | func getDynPathByElf(elfName, soName string) (string, error) {
124 |
125 | sos, e := getDynsFromElf(elfName)
126 | if e != nil {
127 | return "", e
128 | }
129 |
130 | // search dynamic library form ld.so.conf
131 | var searchPath = GetDynLibDirs()
132 | realSoName := recurseDynStrings(sos, searchPath, soName)
133 |
134 | // if not found soName from elfName
135 | if len(realSoName) == 0 {
136 | return "", errors.New(fmt.Sprintf("cant found so lib from %s", elfName))
137 | }
138 | return realSoName, nil
139 | }
140 |
141 | func recurseDynStrings(dynSym []string, searchPath []string, soName string) string {
142 | var realSoName string
143 | for _, el := range dynSym {
144 | // check keylogger path here for library if it doesnot exists panic
145 | var fd *os.File
146 | for _, entry := range searchPath {
147 | path := filepath.Join(entry, el)
148 | if _, err := os.Stat(path); !os.IsNotExist(err) {
149 | fd, err = os.OpenFile(path, os.O_RDONLY, 0644)
150 | if err != nil {
151 | //log.Fatal(err)
152 | fmt.Printf("open keylogger:%s error:%v\n", path, err)
153 | continue
154 | } else {
155 | // found
156 | if strings.HasPrefix(filepath.Base(path), soName) {
157 | realSoName = path
158 | break
159 | }
160 |
161 | // not match ,will open it, and recurse it
162 | }
163 | }
164 | }
165 |
166 | if len(realSoName) > 0 {
167 | return realSoName
168 | }
169 |
170 | if fd == nil {
171 | log.Fatal(fmt.Sprintf("cant found lib so:%s in dirs:%v", el, searchPath))
172 | }
173 |
174 | bint, err := elf.NewFile(fd)
175 | if err != nil {
176 | log.Fatal(err)
177 | }
178 |
179 | bDynSym, err := bint.DynString(elf.DT_NEEDED)
180 | if err != nil {
181 | log.Fatal(err)
182 | }
183 |
184 | realSoName = recurseDynStrings(bDynSym, searchPath, soName)
185 | if len(realSoName) > 0 {
186 | return realSoName
187 | }
188 | }
189 | // not found
190 | return ""
191 | }
192 |
--------------------------------------------------------------------------------
/user/config/common_androidgki.go:
--------------------------------------------------------------------------------
1 | //go:build androidgki
2 | // +build androidgki
3 |
4 | /*
5 |
6 | LINK - http://github.com/sipcapture/rtcagent
7 |
8 | Copyright (C) 2023 QXIP B.V.
9 |
10 | This program is free software: you can redistribute it and/or modify
11 | it under the terms of the GNU Affero General Public License as published by
12 | the Free Software Foundation, either version 3 of the License, or
13 | (at your option) any later version.
14 |
15 | This program is distributed in the hope that it will be useful,
16 | but WITHOUT ANY WARRANTY; without even the implied warranty of
17 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 | GNU Affero General Public License for more details.
19 |
20 | You should have received a copy of the GNU Affero General Public License
21 | along with this program. If not, see .
22 |
23 | */
24 |
25 | package config
26 |
27 | // https://source.android.com/devices/architecture/vndk/linker-namespace
28 | var (
29 | default_so_paths = []string{
30 | "/data/asan/system/lib64",
31 | "/apex/com.android.conscrypt/lib64",
32 | "/apex/com.android.runtime/lib64/bionic",
33 | }
34 | )
35 |
36 | const ElfArchIsandroid = true
37 |
38 | func GetDynLibDirs() []string {
39 | return default_so_paths
40 | }
41 |
--------------------------------------------------------------------------------
/user/config/common_linux.go:
--------------------------------------------------------------------------------
1 | //go:build !androidgki
2 | // +build !androidgki
3 |
4 | /*
5 |
6 | LINK - http://github.com/sipcapture/rtcagent
7 |
8 | Copyright (C) 2023 QXIP B.V.
9 |
10 | This program is free software: you can redistribute it and/or modify
11 | it under the terms of the GNU Affero General Public License as published by
12 | the Free Software Foundation, either version 3 of the License, or
13 | (at your option) any later version.
14 |
15 | This program is distributed in the hope that it will be useful,
16 | but WITHOUT ANY WARRANTY; without even the implied warranty of
17 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 | GNU Affero General Public License for more details.
19 |
20 | You should have received a copy of the GNU Affero General Public License
21 | along with this program. If not, see .
22 |
23 | */
24 |
25 | package config
26 |
27 | import "log"
28 |
29 | const (
30 | LdLoadPath = "/etc/ld.so.conf"
31 | ElfArchIsandroid = false
32 | )
33 |
34 | /*
35 | 1, the RPATH binary header (set at build-time) of the library causing the lookup (if any)
36 | 2, the RPATH binary header (set at build-time) of the executable
37 | 3, the LD_LIBRARY_PATH environment variable (set at run-time)
38 | 4, the RUNPATH binary header (set at build-time) of the executable
39 | 5, /etc/ld.so.cache
40 | 6, base library directories (/lib and /usr/lib)
41 | ref: http://blog.tremily.us/posts/rpath/
42 | */
43 | var (
44 | default_so_paths = []string{
45 | "/lib",
46 | "/usr/lib",
47 | "/usr/lib64",
48 | "/lib64",
49 | }
50 | )
51 |
52 | func GetDynLibDirs() []string {
53 | dirs, err := ParseDynLibConf(LdLoadPath)
54 | if err != nil {
55 | log.Println(err.Error())
56 | return default_so_paths
57 | }
58 | return append(dirs, "/lib64", "/usr/lib64")
59 | }
60 |
--------------------------------------------------------------------------------
/user/config/config_freeswitch.go:
--------------------------------------------------------------------------------
1 | //go:build !androidgki
2 | // +build !androidgki
3 |
4 | /*
5 |
6 | LINK - http://github.com/sipcapture/rtcagent
7 |
8 | Copyright (C) 2023 QXIP B.V.
9 |
10 | This program is free software: you can redistribute it and/or modify
11 | it under the terms of the GNU Affero General Public License as published by
12 | the Free Software Foundation, either version 3 of the License, or
13 | (at your option) any later version.
14 |
15 | This program is distributed in the hope that it will be useful,
16 | but WITHOUT ANY WARRANTY; without even the implied warranty of
17 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 | GNU Affero General Public License for more details.
19 |
20 | You should have received a copy of the GNU Affero General Public License
21 | along with this program. If not, see .
22 |
23 | */
24 |
25 | package config
26 |
27 | import (
28 | "bytes"
29 | "debug/elf"
30 | "errors"
31 | "os"
32 | "strings"
33 | )
34 |
35 | type FreeSwitchType uint8
36 |
37 | const (
38 | FreeSwitchTypeUnknow FreeSwitchType = iota
39 | FreeSwitchType5
40 | FreeSwitchType4
41 | FreeSwitchType3
42 | FreeSwitchType2
43 | )
44 |
45 | // freeswitch
46 | type FreeSwitchConfig struct {
47 | eConfig
48 | FreeSwitchpath string `json:"freeswitchPath"`
49 | ElfType uint8 //
50 | Version FreeSwitchType //
51 | VersionInfo string // info
52 | }
53 |
54 | func NewFreeSwitchConfig() *FreeSwitchConfig {
55 | config := &FreeSwitchConfig{}
56 | return config
57 | }
58 |
59 | func (this *FreeSwitchConfig) Check() error {
60 |
61 | if this.FreeSwitchpath == "" || len(strings.TrimSpace(this.FreeSwitchpath)) <= 0 {
62 | return errors.New("FreeSwitch path cant be null.")
63 | }
64 |
65 | _, e := os.Stat(this.FreeSwitchpath)
66 | if e != nil {
67 | return e
68 | }
69 | this.ElfType = ElfTypeBin
70 |
71 | _elf, e := elf.Open(this.FreeSwitchpath)
72 | if e != nil {
73 | return e
74 | }
75 |
76 | //if funcName == "" {
77 | // return errors.New(fmt.Sprintf("cant match freeswitch 'receive_msg'function to hook with freeswitch file::%s", this.FreeSwitchpath))
78 | //}
79 |
80 | this.Version = FreeSwitchType5
81 | this.VersionInfo = "freeswitch"
82 |
83 | found := strings.Contains("receive_msg", "COM_DATA")
84 | if found {
85 | roSection := _elf.Section(".rodata")
86 | var buf []byte
87 | buf, e = roSection.Data()
88 | var ver FreeSwitchType
89 | var verInfo string
90 | if e == nil {
91 | ver, verInfo = getFreeSwitchVer(buf)
92 | }
93 | this.Version = ver
94 | this.VersionInfo = verInfo
95 | }
96 |
97 | return nil
98 | }
99 |
100 | func getFreeSwitchVer(buf []byte) (FreeSwitchType, string) {
101 |
102 | var slice [][]byte
103 |
104 | if slice = bytes.Split(buf, []byte("\x00")); slice == nil {
105 | return FreeSwitchTypeUnknow, ""
106 | }
107 |
108 | length := len(slice)
109 | var offset int
110 |
111 | for i := 0; i < length; i++ {
112 | if len(slice[i]) == 0 {
113 | continue
114 | }
115 |
116 | l := len(slice[i])
117 | if l > 15 || l < 8 {
118 | continue
119 | }
120 |
121 | freeswitchVer := string(slice[i])
122 | if strings.Contains(freeswitchVer, "freeswitch 5.") {
123 | //fmt.Println(fmt.Sprintf("offset:%d, body:%s", offset, slice[i]))
124 | return FreeSwitchType5, freeswitchVer
125 | } else if strings.Contains(freeswitchVer, "freeswitch 4.") {
126 | return FreeSwitchType4, freeswitchVer
127 | } else if strings.Contains(freeswitchVer, "freeswitch 3.") {
128 | return FreeSwitchType3, freeswitchVer
129 | }
130 | offset += len(slice[i]) + 1
131 | }
132 | return FreeSwitchTypeUnknow, ""
133 | }
134 |
--------------------------------------------------------------------------------
/user/config/config_kamailio.go:
--------------------------------------------------------------------------------
1 | //go:build !androidgki
2 | // +build !androidgki
3 |
4 | /*
5 |
6 | LINK - http://github.com/sipcapture/rtcagent
7 |
8 | Copyright (C) 2023 QXIP B.V.
9 |
10 | This program is free software: you can redistribute it and/or modify
11 | it under the terms of the GNU Affero General Public License as published by
12 | the Free Software Foundation, either version 3 of the License, or
13 | (at your option) any later version.
14 |
15 | This program is distributed in the hope that it will be useful,
16 | but WITHOUT ANY WARRANTY; without even the implied warranty of
17 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 | GNU Affero General Public License for more details.
19 |
20 | You should have received a copy of the GNU Affero General Public License
21 | along with this program. If not, see .
22 |
23 | */
24 |
25 | package config
26 |
27 | import (
28 | "bytes"
29 | "debug/elf"
30 | "errors"
31 | "log"
32 | "os"
33 | "strings"
34 | )
35 |
36 | type KamailioType uint8
37 |
38 | const (
39 | KamailioTypeUnknow KamailioType = iota
40 | KamailioType5
41 | KamailioType4
42 | KamailioType3
43 | KamailioType2
44 | )
45 |
46 | // kamailio
47 | type KamailioConfig struct {
48 | eConfig
49 | Kamailiopath string `json:"kamailioPath"`
50 | ElfType uint8 //
51 | Version KamailioType //
52 | VersionInfo string // info
53 | }
54 |
55 | func NewKamailioConfig() *KamailioConfig {
56 | config := &KamailioConfig{}
57 | return config
58 | }
59 |
60 | func (this *KamailioConfig) Check() error {
61 |
62 | if this.Kamailiopath == "" || len(strings.TrimSpace(this.Kamailiopath)) <= 0 {
63 | return errors.New("Kamailio path cant be null.")
64 | }
65 |
66 | if this.GetNoSearch() {
67 | log.Printf("RTCAGENT :: kamailio. No search")
68 | return nil
69 | }
70 |
71 | _, e := os.Stat(this.Kamailiopath)
72 | if e != nil {
73 | return e
74 | }
75 | this.ElfType = ElfTypeBin
76 |
77 | _elf, e := elf.Open(this.Kamailiopath)
78 | if e != nil {
79 | return e
80 | }
81 |
82 | //if funcName == "" {
83 | // return errors.New(fmt.Sprintf("cant match kamailio 'receive_msg'function to hook with kamailio file::%s", this.Kamailiopath))
84 | //}
85 |
86 | this.Version = KamailioType5
87 | this.VersionInfo = "kamailio"
88 |
89 | found := strings.Contains("receive_msg", "COM_DATA")
90 | if found {
91 | roSection := _elf.Section(".rodata")
92 | var buf []byte
93 | buf, e = roSection.Data()
94 | var ver KamailioType
95 | var verInfo string
96 | if e == nil {
97 | ver, verInfo = getKamailioVer(buf)
98 | }
99 | this.Version = ver
100 | this.VersionInfo = verInfo
101 | }
102 |
103 | return nil
104 | }
105 |
106 | func getKamailioVer(buf []byte) (KamailioType, string) {
107 |
108 | var slice [][]byte
109 |
110 | if slice = bytes.Split(buf, []byte("\x00")); slice == nil {
111 | return KamailioTypeUnknow, ""
112 | }
113 |
114 | length := len(slice)
115 | var offset int
116 |
117 | for i := 0; i < length; i++ {
118 | if len(slice[i]) == 0 {
119 | continue
120 | }
121 |
122 | l := len(slice[i])
123 | if l > 15 || l < 8 {
124 | continue
125 | }
126 |
127 | kamailioVer := string(slice[i])
128 | if strings.Contains(kamailioVer, "kamailio 5.") {
129 | //fmt.Println(fmt.Sprintf("offset:%d, body:%s", offset, slice[i]))
130 | return KamailioType5, kamailioVer
131 | } else if strings.Contains(kamailioVer, "kamailio 4.") {
132 | return KamailioType4, kamailioVer
133 | } else if strings.Contains(kamailioVer, "kamailio 3.") {
134 | return KamailioType3, kamailioVer
135 | }
136 | offset += len(slice[i]) + 1
137 | }
138 | return KamailioTypeUnknow, ""
139 | }
140 |
--------------------------------------------------------------------------------
/user/config/config_monitor.go:
--------------------------------------------------------------------------------
1 | //go:build !androidgki
2 | // +build !androidgki
3 |
4 | /*
5 |
6 | LINK - http://github.com/sipcapture/rtcagent
7 |
8 | Copyright (C) 2023 QXIP B.V.
9 |
10 | This program is free software: you can redistribute it and/or modify
11 | it under the terms of the GNU Affero General Public License as published by
12 | the Free Software Foundation, either version 3 of the License, or
13 | (at your option) any later version.
14 |
15 | This program is distributed in the hope that it will be useful,
16 | but WITHOUT ANY WARRANTY; without even the implied warranty of
17 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 | GNU Affero General Public License for more details.
19 |
20 | You should have received a copy of the GNU Affero General Public License
21 | along with this program. If not, see .
22 |
23 | */
24 |
25 | package config
26 |
27 | import (
28 | "errors"
29 | "log"
30 | "os"
31 | "rtcagent/model"
32 | "strings"
33 | )
34 |
35 | type MonitorType uint8
36 |
37 | const (
38 | MonitorTypeUnknow MonitorType = iota
39 | MonitorType5
40 | MonitorType4
41 | MonitorType3
42 | MonitorType2
43 | )
44 |
45 | // tcprtt
46 | type MonitorConfig struct {
47 | eConfig
48 | Monitorpath string `json:"monitPath"`
49 | SysCall bool //
50 | UserCall bool //
51 | NetworkCall bool //
52 | ShowUserFunction bool //
53 | NetworkLatency bool //
54 | ElfType uint8 //
55 | Version MonitorType //
56 | VersionInfo string // info
57 | UserFunctions []string // user functions
58 | PromCh chan model.AggregatedMetricValue
59 | UiCh chan model.AggregatedTimeMetricValue
60 | }
61 |
62 | func NewMonitorConfig() *MonitorConfig {
63 | config := &MonitorConfig{}
64 | config.PromCh = make(chan model.AggregatedMetricValue, 500)
65 | config.UiCh = make(chan model.AggregatedTimeMetricValue, 500)
66 |
67 | return config
68 | }
69 |
70 | func (this *MonitorConfig) Check() error {
71 |
72 | if this.Monitorpath == "" || len(strings.TrimSpace(this.Monitorpath)) <= 0 {
73 | return errors.New("binary path cant be null.")
74 | }
75 |
76 | if this.GetNoSearch() {
77 | log.Printf("RTCAGENT :: binary. No search")
78 | return nil
79 | }
80 |
81 | _, e := os.Stat(this.Monitorpath)
82 | if e != nil {
83 | return e
84 | }
85 | this.ElfType = ElfTypeBin
86 |
87 | return nil
88 | }
89 |
--------------------------------------------------------------------------------
/user/config/config_opensips.go:
--------------------------------------------------------------------------------
1 | //go:build !androidgki
2 | // +build !androidgki
3 |
4 | /*
5 |
6 | LINK - http://github.com/sipcapture/rtcagent
7 |
8 | Copyright (C) 2023 QXIP B.V.
9 |
10 | This program is free software: you can redistribute it and/or modify
11 | it under the terms of the GNU Affero General Public License as published by
12 | the Free Software Foundation, either version 3 of the License, or
13 | (at your option) any later version.
14 |
15 | This program is distributed in the hope that it will be useful,
16 | but WITHOUT ANY WARRANTY; without even the implied warranty of
17 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 | GNU Affero General Public License for more details.
19 |
20 | You should have received a copy of the GNU Affero General Public License
21 | along with this program. If not, see .
22 |
23 | */
24 |
25 | package config
26 |
27 | import (
28 | "bytes"
29 | "debug/elf"
30 | "errors"
31 | "log"
32 | "os"
33 | "strings"
34 | )
35 |
36 | type OpensipsType uint8
37 |
38 | const (
39 | OpensipsTypeUnknow OpensipsType = iota
40 | OpensipsType3
41 | OpensipsType2
42 | OpensipsType1
43 | )
44 |
45 | // opensips
46 | type OpensipsConfig struct {
47 | eConfig
48 | Opensipspath string `json:"opensipsPath"`
49 | ElfType uint8 //
50 | Version OpensipsType //
51 | VersionInfo string // info
52 | }
53 |
54 | func NewOpensipsConfig() *OpensipsConfig {
55 | config := &OpensipsConfig{}
56 | return config
57 | }
58 |
59 | func (this *OpensipsConfig) Check() error {
60 |
61 | if this.Opensipspath == "" || len(strings.TrimSpace(this.Opensipspath)) <= 0 {
62 | return errors.New("Opensips path cant be null.")
63 | }
64 |
65 | if this.GetNoSearch() {
66 | log.Printf("RTCAGENT :: opensips. No search")
67 | return nil
68 | }
69 |
70 | _, e := os.Stat(this.Opensipspath)
71 | if e != nil {
72 | return e
73 | }
74 | this.ElfType = ElfTypeBin
75 |
76 | _elf, e := elf.Open(this.Opensipspath)
77 | if e != nil {
78 | return e
79 | }
80 |
81 | //if funcName == "" {
82 | // return errors.New(fmt.Sprintf("cant match opensips 'receive_msg'function to hook with opensips file::%s", this.Opensipspath))
83 | //}
84 |
85 | this.Version = OpensipsType3
86 | this.VersionInfo = "opensips"
87 |
88 | found := strings.Contains("receive_msg", "COM_DATA")
89 | if found {
90 | roSection := _elf.Section(".rodata")
91 | var buf []byte
92 | buf, e = roSection.Data()
93 | var ver OpensipsType
94 | var verInfo string
95 | if e == nil {
96 | ver, verInfo = getOpensipsVer(buf)
97 | }
98 | this.Version = ver
99 | this.VersionInfo = verInfo
100 | }
101 |
102 | return nil
103 | }
104 |
105 | func getOpensipsVer(buf []byte) (OpensipsType, string) {
106 |
107 | var slice [][]byte
108 |
109 | if slice = bytes.Split(buf, []byte("\x00")); slice == nil {
110 | return OpensipsTypeUnknow, ""
111 | }
112 |
113 | length := len(slice)
114 | var offset int
115 |
116 | for i := 0; i < length; i++ {
117 | if len(slice[i]) == 0 {
118 | continue
119 | }
120 |
121 | l := len(slice[i])
122 | if l > 15 || l < 8 {
123 | continue
124 | }
125 |
126 | opensipsVer := string(slice[i])
127 | if strings.Contains(opensipsVer, "opensips 3.") {
128 | //fmt.Println(fmt.Sprintf("offset:%d, body:%s", offset, slice[i]))
129 | return OpensipsType3, opensipsVer
130 | } else if strings.Contains(opensipsVer, "opensips 2.") {
131 | return OpensipsType2, opensipsVer
132 | } else if strings.Contains(opensipsVer, "opensips 1.") {
133 | return OpensipsType1, opensipsVer
134 | }
135 | offset += len(slice[i]) + 1
136 | }
137 | return OpensipsTypeUnknow, ""
138 | }
139 |
--------------------------------------------------------------------------------
/user/config/config_tcprtt.go:
--------------------------------------------------------------------------------
1 | //go:build !androidgki
2 | // +build !androidgki
3 |
4 | /*
5 |
6 | LINK - http://github.com/sipcapture/rtcagent
7 |
8 | Copyright (C) 2023 QXIP B.V.
9 |
10 | This program is free software: you can redistribute it and/or modify
11 | it under the terms of the GNU Affero General Public License as published by
12 | the Free Software Foundation, either version 3 of the License, or
13 | (at your option) any later version.
14 |
15 | This program is distributed in the hope that it will be useful,
16 | but WITHOUT ANY WARRANTY; without even the implied warranty of
17 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 | GNU Affero General Public License for more details.
19 |
20 | You should have received a copy of the GNU Affero General Public License
21 | along with this program. If not, see .
22 |
23 | */
24 |
25 | package config
26 |
27 | type TcprttType uint8
28 |
29 | const (
30 | TcprttTypeUnknow TcprttType = iota
31 | TcprttType5
32 | TcprttType4
33 | TcprttType3
34 | TcprttType2
35 | )
36 |
37 | // tcprtt
38 | type TcprttConfig struct {
39 | eConfig
40 | Tcprttpath string `json:"tcprttPath"`
41 | ElfType uint8 //
42 | Version TcprttType //
43 | VersionInfo string // info
44 | }
45 |
46 | func NewTcprttConfig() *TcprttConfig {
47 | config := &TcprttConfig{}
48 | return config
49 | }
50 |
51 | func (this *TcprttConfig) Check() error {
52 |
53 | //if funcName == "" {
54 | // return errors.New(fmt.Sprintf("cant match tcprtt 'receive_msg'function to hook with tcprtt file::%s", this.Tcprttpath))
55 | //}
56 |
57 | return nil
58 | }
59 |
--------------------------------------------------------------------------------
/user/config/const.go:
--------------------------------------------------------------------------------
1 | /*
2 |
3 | LINK - http://github.com/sipcapture/rtcagent
4 |
5 | Copyright (C) 2023 QXIP B.V.
6 |
7 | This program is free software: you can redistribute it and/or modify
8 | it under the terms of the GNU Affero General Public License as published by
9 | the Free Software Foundation, either version 3 of the License, or
10 | (at your option) any later version.
11 |
12 | This program is distributed in the hope that it will be useful,
13 | but WITHOUT ANY WARRANTY; without even the implied warranty of
14 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 | GNU Affero General Public License for more details.
16 |
17 | You should have received a copy of the GNU Affero General Public License
18 | along with this program. If not, see .
19 |
20 | */
21 |
22 | package config
23 |
24 | const (
25 | ElfTypeBin uint8 = 1
26 | ElfTypeSo uint8 = 2
27 | )
28 |
29 | const (
30 | X86BinaryPrefix = "/lib/x86_64-linux-gnu"
31 | OthersBinaryPrefix = "/usr/lib"
32 | )
33 |
--------------------------------------------------------------------------------
/user/config/iconfig.go:
--------------------------------------------------------------------------------
1 | /*
2 |
3 | LINK - http://github.com/sipcapture/rtcagent
4 |
5 | Copyright (C) 2023 QXIP B.V.
6 |
7 | This program is free software: you can redistribute it and/or modify
8 | it under the terms of the GNU Affero General Public License as published by
9 | the Free Software Foundation, either version 3 of the License, or
10 | (at your option) any later version.
11 |
12 | This program is distributed in the hope that it will be useful,
13 | but WITHOUT ANY WARRANTY; without even the implied warranty of
14 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 | GNU Affero General Public License for more details.
16 |
17 | You should have received a copy of the GNU Affero General Public License
18 | along with this program. If not, see .
19 |
20 | */
21 |
22 | package config
23 |
24 | import "rtcagent/pkg/util/kernel"
25 |
26 | type IConfig interface {
27 | Check() error //
28 | GetPid() uint64
29 | GetUid() uint64
30 | GetHex() bool
31 | GetDebug() bool
32 | GetNoSearch() bool
33 | SetPid(uint64)
34 | SetUid(uint64)
35 | SetHex(bool)
36 | SetDebug(bool)
37 | SetNoSearch(bool)
38 | EnableGlobalVar() bool //
39 | }
40 |
41 | type eConfig struct {
42 | Pid uint64
43 | Uid uint64
44 | IsHex bool
45 | Debug bool
46 | NoSearch bool
47 | }
48 |
49 | func (this *eConfig) GetPid() uint64 {
50 | return this.Pid
51 | }
52 |
53 | func (this *eConfig) GetUid() uint64 {
54 | return this.Uid
55 | }
56 |
57 | func (this *eConfig) GetDebug() bool {
58 | return this.Debug
59 | }
60 |
61 | func (this *eConfig) GetHex() bool {
62 | return this.IsHex
63 | }
64 |
65 | func (this *eConfig) GetNoSearch() bool {
66 | return this.NoSearch
67 | }
68 |
69 | func (this *eConfig) SetPid(pid uint64) {
70 | this.Pid = pid
71 | }
72 |
73 | func (this *eConfig) SetUid(uid uint64) {
74 | this.Uid = uid
75 | }
76 |
77 | func (this *eConfig) SetDebug(b bool) {
78 | this.Debug = b
79 | }
80 |
81 | func (this *eConfig) SetHex(isHex bool) {
82 | this.IsHex = isHex
83 | }
84 |
85 | func (this *eConfig) SetNoSearch(noSearch bool) {
86 | this.NoSearch = noSearch
87 | }
88 |
89 | func (this *eConfig) EnableGlobalVar() bool {
90 | kv, err := kernel.HostVersion()
91 | if err != nil {
92 | //log.Fatal(err)
93 | return true
94 | }
95 | if kv < kernel.VersionCode(5, 2, 0) {
96 | return false
97 | }
98 | return true
99 | }
100 |
--------------------------------------------------------------------------------
/user/event/event_tcprtt.go:
--------------------------------------------------------------------------------
1 | //go:build !androidgki
2 | // +build !androidgki
3 |
4 | /*
5 | LINK - http://github.com/sipcapture/rtcagent
6 |
7 | Copyright (C) 2023 QXIP B.V.
8 |
9 | This program is free software: you can redistribute it and/or modify
10 | it under the terms of the GNU Affero General Public License as published by
11 | the Free Software Foundation, either version 3 of the License, or
12 | (at your option) any later version.
13 |
14 | This program is distributed in the hope that it will be useful,
15 | but WITHOUT ANY WARRANTY; without even the implied warranty of
16 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 | GNU Affero General Public License for more details.
18 |
19 | You should have received a copy of the GNU Affero General Public License
20 | along with this program. If not, see .
21 | */
22 |
23 | package event
24 |
25 | import (
26 | "bytes"
27 | "encoding/binary"
28 | "fmt"
29 | "net"
30 | "rtcagent/model"
31 | )
32 |
33 | type TcprttEvent struct {
34 | Sport uint16 `json:"sport"`
35 | Dport uint16 `json:"dport"`
36 | Saddr uint32 `json:"saddr"`
37 | Daddr uint32 `json:"daddr"`
38 | SRTT uint32 `json:"srtt"`
39 | }
40 |
41 | func (tcpev *TcprttEvent) Decode(payload []byte) (err error) {
42 |
43 | buf := bytes.NewBuffer(payload)
44 |
45 | if err = binary.Read(buf, binary.LittleEndian, &tcpev.Sport); err != nil {
46 | return
47 | }
48 |
49 | if err = binary.Read(buf, binary.LittleEndian, &tcpev.Dport); err != nil {
50 | return
51 | }
52 | if err = binary.Read(buf, binary.LittleEndian, &tcpev.Saddr); err != nil {
53 | return
54 | }
55 | if err = binary.Read(buf, binary.LittleEndian, &tcpev.Daddr); err != nil {
56 | return
57 | }
58 | if err = binary.Read(buf, binary.LittleEndian, &tcpev.SRTT); err != nil {
59 | return
60 | }
61 |
62 | return nil
63 | }
64 |
65 | func (tcpev *TcprttEvent) GetUUID() string {
66 | return fmt.Sprintf("%d_%d", tcpev.Sport, tcpev.Dport)
67 | }
68 |
69 | func (tcpev *TcprttEvent) Payload() []byte {
70 | da := []byte{}
71 | return da
72 | }
73 |
74 | func (tcpev *TcprttEvent) PayloadLen() int {
75 | return 0
76 | }
77 |
78 | func (tcpev *TcprttEvent) StringHex() string {
79 | //var connInfo string
80 | //perfix = COLORGREEN
81 | //s := fmt.Sprintf("PID:%d, Comm:%s, TID:%d, %s, Version:%s, Mask: %d, Payload:\n%s", tcpev.Pid, CToGoString(tcpev.Comm[:]),
82 | // tcpev.Tid, connInfo, v, 1, b.String())
83 | //s := fmt.Sprintf("PID:%d, Comm:%s, TID:%d, %s, Version:%s, SrcPort: %d, DstPort:%d, SrcIPv6: %d, DstIPv6: %d, Payload:\n%s", tcpev.Pid, CToGoString(tcpev.Comm[:]),
84 | // tcpev.Tid, connInfo, v.String(), tcpev.RcInfo.SrcPort, tcpev.RcInfo.DstPort, 1, 1, b.String())
85 | return "a"
86 | }
87 |
88 | // intToIP converts IPv4 number to net.IP
89 |
90 | func intToIP(ipNum uint32) net.IP {
91 | ip := make(net.IP, 4)
92 | binary.LittleEndian.PutUint32(ip, ipNum)
93 | return ip
94 | }
95 |
96 | func (tcpev *TcprttEvent) String() string {
97 | //addr := tcpev.module.(*module.MOpenSSLProbe).GetConn(tcpev.Pid, tcpev.Fd)
98 |
99 | srcIP := intToIP(tcpev.Saddr)
100 | dstIP := intToIP(tcpev.Daddr)
101 |
102 | prefix := COLORGREEN
103 |
104 | s := fmt.Sprintf("%s%-15s %-6d -> %-15s %-6d %-6d%s", prefix, srcIP, tcpev.Sport, dstIP, tcpev.Dport, tcpev.SRTT, COLORRESET)
105 | return s
106 | }
107 |
108 | func (tcpev *TcprttEvent) SendHep() bool {
109 | //Lets allow to send HEP
110 | return false
111 | }
112 |
113 | func (tcpev *TcprttEvent) GenerateHEP() ([]byte, error) {
114 |
115 | return nil, fmt.Errorf("no data")
116 |
117 | }
118 |
119 | func (tcpev *TcprttEvent) Clone() IEventStruct {
120 | event := new(TcprttEvent)
121 | return event
122 | }
123 |
124 | func (tcpev *TcprttEvent) EventType() EventType {
125 | return 0
126 | }
127 |
128 | func (tcpev *TcprttEvent) DoCorrelation(userFunctionArray []string) bool {
129 |
130 | return false
131 | }
132 |
133 | func (tcpev *TcprttEvent) GenerateMetric() model.AggregatedMetricValue {
134 | //Lets allow to send HEP
135 |
136 | return model.AggregatedMetricValue{}
137 | }
138 |
139 | func (tcpev *TcprttEvent) GenerateTimeMetric() model.AggregatedTimeMetricValue {
140 |
141 | return model.AggregatedTimeMetricValue{}
142 | }
143 |
--------------------------------------------------------------------------------
/user/event/ievent.go:
--------------------------------------------------------------------------------
1 | /*
2 | LINK - http://github.com/sipcapture/rtcagent
3 |
4 | Copyright (C) 2023 QXIP B.V.
5 |
6 | This program is free software: you can redistribute it and/or modify
7 | it under the terms of the GNU Affero General Public License as published by
8 | the Free Software Foundation, either version 3 of the License, or
9 | (at your option) any later version.
10 |
11 | This program is distributed in the hope that it will be useful,
12 | but WITHOUT ANY WARRANTY; without even the implied warranty of
13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 | GNU Affero General Public License for more details.
15 |
16 | You should have received a copy of the GNU Affero General Public License
17 | along with this program. If not, see .
18 | */
19 |
20 | package event
21 |
22 | import (
23 | "rtcagent/model"
24 | )
25 |
26 | type EventType uint8
27 |
28 | const (
29 | // EventTypeOutput upload to server or write to logfile.
30 | EventTypeOutput EventType = iota
31 |
32 | // EventTypeModuleData set as module cache data
33 | EventTypeModuleData
34 |
35 | // EventTypeEventProcessor display by event_processor.
36 | EventTypeEventProcessor
37 | )
38 |
39 | type IEventStruct interface {
40 | Decode(payload []byte) (err error)
41 | Payload() []byte
42 | PayloadLen() int
43 | GenerateHEP() ([]byte, error)
44 | String() string
45 | DoCorrelation(userFunctionArray []string) bool
46 | SendHep() bool
47 | StringHex() string
48 | Clone() IEventStruct
49 | EventType() EventType
50 | GetUUID() string
51 | GenerateMetric() model.AggregatedMetricValue
52 | GenerateTimeMetric() model.AggregatedTimeMetricValue
53 | }
54 |
--------------------------------------------------------------------------------
/user/event/misc.go:
--------------------------------------------------------------------------------
1 | /*
2 | LINK - http://github.com/sipcapture/rtcagent
3 |
4 | Copyright (C) 2023 QXIP B.V.
5 |
6 | This program is free software: you can redistribute it and/or modify
7 | it under the terms of the GNU Affero General Public License as published by
8 | the Free Software Foundation, either version 3 of the License, or
9 | (at your option) any later version.
10 |
11 | This program is distributed in the hope that it will be useful,
12 | but WITHOUT ANY WARRANTY; without even the implied warranty of
13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 | GNU Affero General Public License for more details.
15 |
16 | You should have received a copy of the GNU Affero General Public License
17 | along with this program. If not, see .
18 | */
19 |
20 | package event
21 |
22 | import (
23 | "bytes"
24 | "fmt"
25 | )
26 |
27 | const ChunkSize = 16
28 | const ChunkSizeHalf = ChunkSize / 2
29 |
30 | const (
31 | COLORRESET = "\033[0m"
32 | COLORRED = "\033[31m"
33 | COLORGREEN = "\033[32m"
34 | COLORYELLOW = "\033[33m"
35 | COLORBLUE = "\033[34m"
36 | COLORPURPLE = "\033[35m"
37 | COLORCYAN = "\033[36m"
38 | COLORWHITE = "\033[37m"
39 | )
40 |
41 | func dumpByteSlice(b []byte, perfix string) *bytes.Buffer {
42 | var a [ChunkSize]byte
43 | bb := new(bytes.Buffer)
44 | n := (len(b) + (ChunkSize - 1)) &^ (ChunkSize - 1)
45 |
46 | for i := 0; i < n; i++ {
47 |
48 | //
49 | if i%ChunkSize == 0 {
50 | bb.WriteString(perfix)
51 | bb.WriteString(fmt.Sprintf("%04d", i))
52 | }
53 |
54 | if i%ChunkSizeHalf == 0 {
55 | bb.WriteString(" ")
56 | } else if i%(ChunkSizeHalf/2) == 0 {
57 | bb.WriteString(" ")
58 | }
59 |
60 | if i < len(b) {
61 | bb.WriteString(fmt.Sprintf(" %02X", b[i]))
62 | } else {
63 | bb.WriteString(" ")
64 | }
65 |
66 | if i >= len(b) {
67 | a[i%ChunkSize] = ' '
68 | } else if b[i] < 32 || b[i] > 126 {
69 | a[i%ChunkSize] = '.'
70 | } else {
71 | a[i%ChunkSize] = b[i]
72 | }
73 |
74 | if i%ChunkSize == (ChunkSize - 1) {
75 | bb.WriteString(fmt.Sprintf(" %s\n", string(a[:])))
76 | }
77 | }
78 | return bb
79 | }
80 |
81 | func CToGoString(c []byte) string {
82 | n := -1
83 | for i, b := range c {
84 | if b == 0 {
85 | break
86 | }
87 | n = i
88 | }
89 | return string(c[:n+1])
90 | }
91 |
--------------------------------------------------------------------------------
/user/module/const.go:
--------------------------------------------------------------------------------
1 | /*
2 |
3 | LINK - http://github.com/sipcapture/rtcagent
4 |
5 | Copyright (C) 2023 QXIP B.V.
6 |
7 | This program is free software: you can redistribute it and/or modify
8 | it under the terms of the GNU Affero General Public License as published by
9 | the Free Software Foundation, either version 3 of the License, or
10 | (at your option) any later version.
11 |
12 | This program is distributed in the hope that it will be useful,
13 | but WITHOUT ANY WARRANTY; without even the implied warranty of
14 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 | GNU Affero General Public License for more details.
16 |
17 | You should have received a copy of the GNU Affero General Public License
18 | along with this program. If not, see .
19 |
20 | */
21 |
22 | package module
23 |
24 | const (
25 | ProbeTypeUprobe = "uprobe"
26 | ProbeTypeKprobe = "kprobe"
27 | ProbeTypeTC = "TC"
28 | ProbeTypeTP = "tracepoint"
29 | ProbeTypeFentry = "fentry"
30 | ProbeTypeXDP = "XDP"
31 | )
32 |
33 | const (
34 | ModuleNameKamailio = "EBPFProbeKamailio"
35 | ModuleNameFreeSwitch = "EBPFProbeFreeSwitch"
36 | ModuleNameTcprtt = "EBPFProbeTcprtt"
37 | ModuleNameOpensips = "EBPFProbeOpensips"
38 | ModuleNameMonitor = "EBPFProbeMonitor"
39 | )
40 |
41 | const (
42 | BashErrnoDefault int = 128
43 | )
44 |
45 | // buffer size times of ebpf perf map
46 | // buffer size = BufferSizeOfEbpfMap * os.pagesize
47 | const BufferSizeOfEbpfMap = 1024
48 |
--------------------------------------------------------------------------------
/user/module/iclose.go:
--------------------------------------------------------------------------------
1 | /*
2 |
3 | LINK - http://github.com/sipcapture/rtcagent
4 |
5 | Copyright (C) 2023 QXIP B.V.
6 |
7 | This program is free software: you can redistribute it and/or modify
8 | it under the terms of the GNU Affero General Public License as published by
9 | the Free Software Foundation, either version 3 of the License, or
10 | (at your option) any later version.
11 |
12 | This program is distributed in the hope that it will be useful,
13 | but WITHOUT ANY WARRANTY; without even the implied warranty of
14 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 | GNU Affero General Public License for more details.
16 |
17 | You should have received a copy of the GNU Affero General Public License
18 | along with this program. If not, see .
19 |
20 | */
21 |
22 | package module
23 |
24 | type IClose interface {
25 | Close() error
26 | }
27 |
--------------------------------------------------------------------------------
/user/module/probe_freeswitch.go:
--------------------------------------------------------------------------------
1 | //go:build !androidgki
2 | // +build !androidgki
3 |
4 | /*
5 |
6 | LINK - http://github.com/sipcapture/rtcagent
7 |
8 | Copyright (C) 2023 QXIP B.V.
9 |
10 | This program is free software: you can redistribute it and/or modify
11 | it under the terms of the GNU Affero General Public License as published by
12 | the Free Software Foundation, either version 3 of the License, or
13 | (at your option) any later version.
14 |
15 | This program is distributed in the hope that it will be useful,
16 | but WITHOUT ANY WARRANTY; without even the implied warranty of
17 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 | GNU Affero General Public License for more details.
19 |
20 | You should have received a copy of the GNU Affero General Public License
21 | along with this program. If not, see .
22 |
23 | */
24 |
25 | package module
26 |
27 | import (
28 | "bytes"
29 | "context"
30 | "errors"
31 | "fmt"
32 | "log"
33 | "math"
34 | "os"
35 | "rtcagent/assets"
36 | "rtcagent/user/config"
37 | "rtcagent/user/event"
38 |
39 | manager "github.com/adubovikov/ebpfmanager"
40 | "github.com/cilium/ebpf"
41 | "golang.org/x/sys/unix"
42 | )
43 |
44 | type MFreeSwitchProbe struct {
45 | Module
46 | bpfManager *manager.Manager
47 | bpfManagerOptions manager.Options
48 | eventFuncMaps map[*ebpf.Map]event.IEventStruct
49 | eventMaps []*ebpf.Map
50 | }
51 |
52 | func (this *MFreeSwitchProbe) Init(ctx context.Context, logger *log.Logger, conf config.IConfig) error {
53 | this.Module.Init(ctx, logger, conf)
54 | this.conf = conf
55 | this.Module.SetChild(this)
56 | this.eventMaps = make([]*ebpf.Map, 0, 2)
57 | this.eventFuncMaps = make(map[*ebpf.Map]event.IEventStruct)
58 | return nil
59 | }
60 |
61 | func (this *MFreeSwitchProbe) Start() error {
62 | if err := this.start(); err != nil {
63 | return err
64 | }
65 | return nil
66 | }
67 |
68 | func (this *MFreeSwitchProbe) MakeUI() error {
69 |
70 | return nil
71 | }
72 |
73 | func (this *MFreeSwitchProbe) start() error {
74 |
75 | // fetch ebpf assets
76 | var bpfFileName = this.geteBPFName("user/bytecode/freeswitch_kern.o")
77 | this.logger.Printf("%s\tBPF bytecode filename: [%s]\n", this.Name(), bpfFileName)
78 |
79 | byteBuf, err := assets.Asset(bpfFileName)
80 | if err != nil {
81 | return fmt.Errorf("couldn't find asset %v.", err)
82 | }
83 |
84 | // setup the managers
85 | err = this.setupManagers()
86 | if err != nil {
87 | return fmt.Errorf("freeswitch module couldn't find binPath %v.", err)
88 | }
89 |
90 | // initialize the bootstrap manager
91 | if err = this.bpfManager.InitWithOptions(bytes.NewReader(byteBuf), this.bpfManagerOptions); err != nil {
92 | return fmt.Errorf("couldn't init manager %v", err)
93 | }
94 |
95 | // start the bootstrap manager
96 | if err = this.bpfManager.Start(); err != nil {
97 | return fmt.Errorf("couldn't start bootstrap manager %v", err)
98 | }
99 |
100 | err = this.initDecodeFun()
101 | if err != nil {
102 | return err
103 | }
104 |
105 | return nil
106 | }
107 |
108 | func (this *MFreeSwitchProbe) Close() error {
109 | if err := this.bpfManager.Stop(manager.CleanAll); err != nil {
110 | return fmt.Errorf("couldn't stop manager %v", err)
111 | }
112 | return this.Module.Close()
113 | }
114 |
115 | func (this *MFreeSwitchProbe) setupManagers() error {
116 | var binaryPath string
117 | switch this.conf.(*config.FreeSwitchConfig).ElfType {
118 | case config.ElfTypeBin:
119 | binaryPath = this.conf.(*config.FreeSwitchConfig).FreeSwitchpath
120 | default:
121 | binaryPath = "/usr/local/lib/libsofia-sip-ua.so.0"
122 | }
123 |
124 | _, err := os.Stat(binaryPath)
125 | if err != nil {
126 | return err
127 | }
128 |
129 | version := this.conf.(*config.FreeSwitchConfig).Version
130 | versionInfo := this.conf.(*config.FreeSwitchConfig).VersionInfo
131 |
132 | //objdump -T /usr/local/lib/libsofia-sip-ua.so.0 |grep receive_msg
133 | //0000000000174c30 g DF .text 000000000000541f Base receive_msg
134 |
135 | var probes = []*manager.Probe{
136 | {
137 | Section: "uprobe/receive_msg",
138 | EbpfFuncName: "freeswitch_receive_msg",
139 | AttachToFuncName: "su_vrecv",
140 | BinaryPath: binaryPath,
141 | },
142 | {
143 | Section: "uretprobe/receive_msg",
144 | EbpfFuncName: "freeswitch_ret_receive_msg",
145 | AttachToFuncName: "su_vrecv",
146 | BinaryPath: binaryPath,
147 | },
148 | {
149 | Section: "uprobe/msg_send",
150 | EbpfFuncName: "msg_send",
151 | AttachToFuncName: "tport_vsend",
152 | BinaryPath: binaryPath,
153 | },
154 | {
155 | Section: "uretprobe/msg_send",
156 | EbpfFuncName: "msg_ret_send",
157 | AttachToFuncName: "tport_vsend",
158 | BinaryPath: binaryPath,
159 | },
160 | }
161 |
162 | this.bpfManager = &manager.Manager{
163 | Probes: probes,
164 | Maps: []*manager.Map{
165 | {
166 | Name: "events",
167 | },
168 | },
169 | }
170 |
171 | this.logger.Printf("%s\tFreeSwitch: %d, Version:%s, binrayPath:%s\n", this.Name(), version, versionInfo, binaryPath)
172 |
173 | this.bpfManagerOptions = manager.Options{
174 | DefaultKProbeMaxActive: 512,
175 |
176 | VerifierOptions: ebpf.CollectionOptions{
177 | Programs: ebpf.ProgramOptions{
178 | LogSize: 2097152,
179 | },
180 | },
181 |
182 | RLimit: &unix.Rlimit{
183 | Cur: math.MaxUint64,
184 | Max: math.MaxUint64,
185 | },
186 | }
187 | return nil
188 | }
189 |
190 | func (this *MFreeSwitchProbe) DecodeFun(em *ebpf.Map) (event.IEventStruct, bool) {
191 | fun, found := this.eventFuncMaps[em]
192 | return fun, found
193 | }
194 |
195 | func (this *MFreeSwitchProbe) initDecodeFun() error {
196 | // freeswitchEventsMap
197 | freeswitchEventsMap, found, err := this.bpfManager.GetMap("events")
198 |
199 | this.logger.Printf("====> BPF bytecode filename: [%v]\n", found)
200 |
201 | if err != nil {
202 | this.logger.Printf("====> ERRROR BPF bytecode filename: [%]\n", err.Error())
203 | return err
204 | }
205 | if !found {
206 | return errors.New("cant found map:events")
207 | }
208 | this.eventMaps = append(this.eventMaps, freeswitchEventsMap)
209 | this.eventFuncMaps[freeswitchEventsMap] = &event.FreeSwitchEvent{}
210 |
211 | ///Packet{payload: payload[:len(hep)], length: len(hep)}
212 |
213 | return nil
214 | }
215 |
216 | func (this *MFreeSwitchProbe) Events() []*ebpf.Map {
217 | return this.eventMaps
218 | }
219 |
220 | func init() {
221 | mod := &MFreeSwitchProbe{}
222 | mod.name = ModuleNameFreeSwitch
223 | mod.mType = ProbeTypeUprobe
224 | Register(mod)
225 | }
226 |
--------------------------------------------------------------------------------
/user/module/probe_kamailio.go:
--------------------------------------------------------------------------------
1 | //go:build !androidgki
2 | // +build !androidgki
3 |
4 | /*
5 |
6 | LINK - http://github.com/sipcapture/rtcagent
7 |
8 | Copyright (C) 2023 QXIP B.V.
9 |
10 | This program is free software: you can redistribute it and/or modify
11 | it under the terms of the GNU Affero General Public License as published by
12 | the Free Software Foundation, either version 3 of the License, or
13 | (at your option) any later version.
14 |
15 | This program is distributed in the hope that it will be useful,
16 | but WITHOUT ANY WARRANTY; without even the implied warranty of
17 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 | GNU Affero General Public License for more details.
19 |
20 | You should have received a copy of the GNU Affero General Public License
21 | along with this program. If not, see .
22 |
23 | */
24 |
25 | package module
26 |
27 | import (
28 | "bytes"
29 | "context"
30 | "errors"
31 | "fmt"
32 | "log"
33 | "math"
34 | "os"
35 | "rtcagent/assets"
36 | "rtcagent/user/config"
37 | "rtcagent/user/event"
38 |
39 | manager "github.com/adubovikov/ebpfmanager"
40 | "github.com/cilium/ebpf"
41 | "golang.org/x/sys/unix"
42 | )
43 |
44 | type MKamailioProbe struct {
45 | Module
46 | bpfManager *manager.Manager
47 | bpfManagerOptions manager.Options
48 | eventFuncMaps map[*ebpf.Map]event.IEventStruct
49 | eventMaps []*ebpf.Map
50 | }
51 |
52 | func (this *MKamailioProbe) Init(ctx context.Context, logger *log.Logger, conf config.IConfig) error {
53 | this.Module.Init(ctx, logger, conf)
54 | this.conf = conf
55 | this.Module.SetChild(this)
56 | this.eventMaps = make([]*ebpf.Map, 0, 2)
57 | this.eventFuncMaps = make(map[*ebpf.Map]event.IEventStruct)
58 | return nil
59 | }
60 |
61 | func (this *MKamailioProbe) Start() error {
62 | if err := this.start(); err != nil {
63 | return err
64 | }
65 | return nil
66 | }
67 |
68 | func (this *MKamailioProbe) MakeUI() error {
69 |
70 | return nil
71 | }
72 |
73 | func (this *MKamailioProbe) start() error {
74 |
75 | // fetch ebpf assets
76 | var bpfFileName = this.geteBPFName("user/bytecode/kamailio_kern.o")
77 | this.logger.Printf("%s\tBPF bytecode filename: [%s]\n", this.Name(), bpfFileName)
78 |
79 | byteBuf, err := assets.Asset(bpfFileName)
80 | if err != nil {
81 | return fmt.Errorf("couldn't find asset %v.", err)
82 | }
83 |
84 | // setup the managers
85 | err = this.setupManagers()
86 | if err != nil {
87 | return fmt.Errorf("kamailio module couldn't find binPath %v.", err)
88 | }
89 |
90 | // initialize the bootstrap manager
91 | if err = this.bpfManager.InitWithOptions(bytes.NewReader(byteBuf), this.bpfManagerOptions); err != nil {
92 | return fmt.Errorf("couldn't init manager %v", err)
93 | }
94 |
95 | // start the bootstrap manager
96 | if err = this.bpfManager.Start(); err != nil {
97 | return fmt.Errorf("couldn't start bootstrap manager %v", err)
98 | }
99 |
100 | err = this.initDecodeFun()
101 | if err != nil {
102 | return err
103 | }
104 |
105 | return nil
106 | }
107 |
108 | func (this *MKamailioProbe) Close() error {
109 | if err := this.bpfManager.Stop(manager.CleanAll); err != nil {
110 | return fmt.Errorf("couldn't stop manager %v", err)
111 | }
112 | return this.Module.Close()
113 | }
114 |
115 | func (this *MKamailioProbe) setupManagers() error {
116 | var binaryPath string
117 | switch this.conf.(*config.KamailioConfig).ElfType {
118 | case config.ElfTypeBin:
119 | binaryPath = this.conf.(*config.KamailioConfig).Kamailiopath
120 | default:
121 | binaryPath = "/usr/sbin/kamailio"
122 | }
123 |
124 | if !this.conf.(*config.KamailioConfig).GetNoSearch() {
125 | _, err := os.Stat(binaryPath)
126 | if err != nil {
127 | return err
128 | }
129 | }
130 |
131 | version := this.conf.(*config.KamailioConfig).Version
132 | versionInfo := this.conf.(*config.KamailioConfig).VersionInfo
133 |
134 | //objdump -T /usr/sbin/kamailio |grep receive_msg
135 | //0000000000174c30 g DF .text 000000000000541f Base receive_msg
136 |
137 | var probes = []*manager.Probe{
138 | {
139 | Section: "uprobe/receive_msg",
140 | EbpfFuncName: "kamailio_receive_msg",
141 | AttachToFuncName: "receive_msg",
142 | BinaryPath: binaryPath,
143 | },
144 | {
145 | Section: "uretprobe/receive_msg",
146 | EbpfFuncName: "kamailio_ret_receive_msg",
147 | AttachToFuncName: "receive_msg",
148 | BinaryPath: binaryPath,
149 | },
150 | {
151 | Section: "uprobe/msg_send_udp",
152 | EbpfFuncName: "msg_send_udp",
153 | AttachToFuncName: "udp_send",
154 | BinaryPath: binaryPath,
155 | },
156 | {
157 | Section: "uretprobe/msg_send_udp",
158 | EbpfFuncName: "msg_ret_send_udp",
159 | AttachToFuncName: "udp_send",
160 | BinaryPath: binaryPath,
161 | },
162 | {
163 | Section: "uprobe/msg_send_tcp",
164 | EbpfFuncName: "msg_send_tcp",
165 | AttachToFuncName: "tcp_send",
166 | BinaryPath: binaryPath,
167 | },
168 | {
169 | Section: "uretprobe/msg_send_tcp",
170 | EbpfFuncName: "msg_ret_send_tcp",
171 | AttachToFuncName: "tcp_send",
172 | BinaryPath: binaryPath,
173 | },
174 | }
175 |
176 | this.bpfManager = &manager.Manager{
177 | Probes: probes,
178 | Maps: []*manager.Map{
179 | {
180 | Name: "events",
181 | },
182 | },
183 | }
184 |
185 | this.logger.Printf("%s\tKamailio: %d, Version:%s, binrayPath:%s\n", this.Name(), version, versionInfo, binaryPath)
186 |
187 | this.bpfManagerOptions = manager.Options{
188 | DefaultKProbeMaxActive: 512,
189 |
190 | VerifierOptions: ebpf.CollectionOptions{
191 | Programs: ebpf.ProgramOptions{
192 | LogSize: 2097152,
193 | },
194 | },
195 |
196 | RLimit: &unix.Rlimit{
197 | Cur: math.MaxUint64,
198 | Max: math.MaxUint64,
199 | },
200 | }
201 | return nil
202 | }
203 |
204 | func (this *MKamailioProbe) DecodeFun(em *ebpf.Map) (event.IEventStruct, bool) {
205 | fun, found := this.eventFuncMaps[em]
206 | return fun, found
207 | }
208 |
209 | func (this *MKamailioProbe) initDecodeFun() error {
210 | // kamailioEventsMap
211 | kamailioEventsMap, found, err := this.bpfManager.GetMap("events")
212 |
213 | this.logger.Printf("====> BPF bytecode filename: [%v]\n", found)
214 |
215 | if err != nil {
216 | this.logger.Printf("====> ERRROR BPF bytecode filename: [%]\n", err.Error())
217 | return err
218 | }
219 | if !found {
220 | return errors.New("cant found map:events")
221 | }
222 | this.eventMaps = append(this.eventMaps, kamailioEventsMap)
223 | this.eventFuncMaps[kamailioEventsMap] = &event.KamailioEvent{}
224 |
225 | ///Packet{payload: payload[:len(hep)], length: len(hep)}
226 |
227 | return nil
228 | }
229 |
230 | func (this *MKamailioProbe) Events() []*ebpf.Map {
231 | return this.eventMaps
232 | }
233 |
234 | func init() {
235 | mod := &MKamailioProbe{}
236 | mod.name = ModuleNameKamailio
237 | mod.mType = ProbeTypeUprobe
238 | Register(mod)
239 | }
240 |
--------------------------------------------------------------------------------
/user/module/probe_tcpdrop.go:
--------------------------------------------------------------------------------
1 | //go:build !androidgki
2 | // +build !androidgki
3 |
4 | /*
5 |
6 | LINK - http://github.com/sipcapture/rtcagent
7 |
8 | Copyright (C) 2023 QXIP B.V.
9 |
10 | This program is free software: you can redistribute it and/or modify
11 | it under the terms of the GNU Affero General Public License as published by
12 | the Free Software Foundation, either version 3 of the License, or
13 | (at your option) any later version.
14 |
15 | This program is distributed in the hope that it will be useful,
16 | but WITHOUT ANY WARRANTY; without even the implied warranty of
17 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 | GNU Affero General Public License for more details.
19 |
20 | You should have received a copy of the GNU Affero General Public License
21 | along with this program. If not, see .
22 |
23 | */
24 |
25 | package module
26 |
27 | import (
28 | "bytes"
29 | "context"
30 | "fmt"
31 | "log"
32 | "math"
33 | "rtcagent/assets"
34 | "rtcagent/user/config"
35 | "rtcagent/user/event"
36 |
37 | manager "github.com/adubovikov/ebpfmanager"
38 | "github.com/cilium/ebpf"
39 | "github.com/cilium/ebpf/link"
40 | "github.com/cilium/ebpf/rlimit"
41 | "golang.org/x/sys/unix"
42 | )
43 |
44 | type MTcprttProbe struct {
45 | Module
46 | bpfManager *manager.Manager
47 | bpfManagerOptions manager.Options
48 | eventFuncMaps map[*ebpf.Map]event.IEventStruct
49 | eventMaps []*ebpf.Map
50 | linkData link.Link
51 | }
52 |
53 | func (this *MTcprttProbe) Init(ctx context.Context, logger *log.Logger, conf config.IConfig) error {
54 | this.Module.Init(ctx, logger, conf)
55 | this.conf = conf
56 | this.Module.SetChild(this)
57 | this.eventMaps = make([]*ebpf.Map, 0, 2)
58 | this.eventFuncMaps = make(map[*ebpf.Map]event.IEventStruct)
59 | return nil
60 | }
61 |
62 | func (this *MTcprttProbe) Start() error {
63 | if err := this.start(); err != nil {
64 | return err
65 | }
66 | return nil
67 | }
68 |
69 | type bpfPrograms struct {
70 | TcpClose *ebpf.Program `ebpf:"tcp_close"`
71 | }
72 |
73 | type bpfMaps struct {
74 | Events *ebpf.Map `ebpf:"events"`
75 | }
76 | type bpfObjects struct {
77 | bpfPrograms
78 | bpfMaps
79 | }
80 |
81 | func (this *MTcprttProbe) start() error {
82 |
83 | // Allow the current process to lock memory for eBPF resources.
84 | if err := rlimit.RemoveMemlock(); err != nil {
85 | log.Fatal(err)
86 | }
87 |
88 | var bpfFileName = this.geteBPFName("user/bytecode/tcprtt_kern.o")
89 | this.logger.Printf("%s\tBPF bytecode filename: [%s]\n", this.Name(), bpfFileName)
90 |
91 | byteBuf, err := assets.Asset(bpfFileName)
92 | if err != nil {
93 | return fmt.Errorf("couldn't find asset %v.", err)
94 | }
95 |
96 | objs := bpfObjects{}
97 |
98 | reader := bytes.NewReader(byteBuf)
99 | spec, err := ebpf.LoadCollectionSpecFromReader(reader)
100 | if err != nil {
101 | return fmt.Errorf("can't load bpf: %w", err)
102 | }
103 |
104 | err = spec.LoadAndAssign(&objs, nil)
105 | if err != nil {
106 | return fmt.Errorf("couldn't find asset %v.", err)
107 | }
108 |
109 | this.linkData, err = link.AttachTracing(link.TracingOptions{
110 | Program: objs.bpfPrograms.TcpClose,
111 | })
112 | if err != nil {
113 | this.logger.Printf("%s\tBPF bytecode filename FATAL: [%s]\n", this.Name(), bpfFileName)
114 | log.Fatal(err)
115 | }
116 |
117 | this.eventMaps = append(this.eventMaps, objs.bpfMaps.Events)
118 | this.eventFuncMaps[objs.bpfMaps.Events] = &event.TcprttEvent{}
119 |
120 | err = this.initDecodeFun()
121 | if err != nil {
122 | return err
123 | }
124 |
125 | return nil
126 | }
127 |
128 | func (this *MTcprttProbe) MakeUI() error {
129 |
130 | return nil
131 | }
132 |
133 | func (this *MTcprttProbe) Close() error {
134 |
135 | this.linkData.Close()
136 | if err := this.bpfManager.Stop(manager.CleanAll); err != nil {
137 | return fmt.Errorf("couldn't stop manager %v", err)
138 | }
139 | return this.Module.Close()
140 | }
141 |
142 | func (this *MTcprttProbe) setupManagers() error {
143 | var binaryPath string
144 |
145 | version := this.conf.(*config.TcprttConfig).Version
146 | versionInfo := this.conf.(*config.TcprttConfig).VersionInfo
147 |
148 | var probes = []*manager.Probe{
149 | {
150 | Section: "fentry/tcp_close",
151 | EbpfFuncName: `ebpf:"tcp_close"`,
152 | AttachToFuncName: `ebpf:"tcp_close"`,
153 | },
154 | }
155 |
156 | this.bpfManager = &manager.Manager{
157 | Probes: probes,
158 | Maps: []*manager.Map{
159 | {
160 | Name: "events",
161 | },
162 | },
163 | }
164 |
165 | this.logger.Printf("%s\tTcprtt: %d, Version:%s, binrayPath:%s\n", this.Name(), version, versionInfo, binaryPath)
166 |
167 | this.bpfManagerOptions = manager.Options{
168 | DefaultKProbeMaxActive: 512,
169 |
170 | VerifierOptions: ebpf.CollectionOptions{
171 | Programs: ebpf.ProgramOptions{
172 | LogSize: 2097152,
173 | },
174 | },
175 |
176 | RLimit: &unix.Rlimit{
177 | Cur: math.MaxUint64,
178 | Max: math.MaxUint64,
179 | },
180 | }
181 | return nil
182 | }
183 |
184 | func (this *MTcprttProbe) DecodeFun(em *ebpf.Map) (event.IEventStruct, bool) {
185 | fun, found := this.eventFuncMaps[em]
186 | return fun, found
187 | }
188 |
189 | func (this *MTcprttProbe) initDecodeFun() error {
190 |
191 | prefix := event.COLORCYAN
192 |
193 | this.logger.Printf("%s%-15s %-6s -> %-15s %-6s %-6s%s", prefix, "Src addr", "Port", "Dest addr", "Port", "RTT", event.COLORRESET)
194 |
195 | return nil
196 | }
197 |
198 | func (this *MTcprttProbe) Events() []*ebpf.Map {
199 | return this.eventMaps
200 | }
201 |
202 | func init() {
203 | mod := &MTcprttProbe{}
204 | mod.name = ModuleNameTcprtt
205 | mod.mType = ProbeTypeFentry
206 | Register(mod)
207 | }
208 |
--------------------------------------------------------------------------------
/user/module/register.go:
--------------------------------------------------------------------------------
1 | /*
2 |
3 | LINK - http://github.com/sipcapture/rtcagent
4 |
5 | Copyright (C) 2023 QXIP B.V.
6 |
7 | This program is free software: you can redistribute it and/or modify
8 | it under the terms of the GNU Affero General Public License as published by
9 | the Free Software Foundation, either version 3 of the License, or
10 | (at your option) any later version.
11 |
12 | This program is distributed in the hope that it will be useful,
13 | but WITHOUT ANY WARRANTY; without even the implied warranty of
14 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 | GNU Affero General Public License for more details.
16 |
17 | You should have received a copy of the GNU Affero General Public License
18 | along with this program. If not, see .
19 |
20 | */
21 |
22 | package module
23 |
24 | import (
25 | "fmt"
26 | )
27 |
28 | var modules = make(map[string]IModule)
29 |
30 | func Register(p IModule) {
31 | if p == nil {
32 | panic("Register probe is nil")
33 | }
34 | name := p.Name()
35 | if _, dup := modules[name]; dup {
36 | panic(fmt.Sprintf("Register called twice for probe %s", name))
37 | }
38 | modules[name] = p
39 | }
40 |
41 | func GetAllModules() map[string]IModule {
42 | return modules
43 | }
44 |
45 | func GetModuleByName(modName string) IModule {
46 | m, f := modules[modName]
47 | if f {
48 | return m
49 | }
50 | return nil
51 | }
52 |
--------------------------------------------------------------------------------
/user/time/monotonic.go:
--------------------------------------------------------------------------------
1 | package monotonic
2 |
3 | import (
4 | "time"
5 | )
6 |
7 | /*
8 | #include
9 | static unsigned long long get_nsecs(void)
10 | {
11 | struct timespec ts;
12 | clock_gettime(CLOCK_MONOTONIC, &ts);
13 | return (unsigned long long)ts.tv_sec * 1000000000UL + ts.tv_nsec;
14 | }
15 | */
16 | import "C"
17 |
18 | func GetTime() (uint64, int64) {
19 | monotonic := uint64(C.get_nsecs())
20 | timestamp := time.Now().UTC().UnixNano()
21 | return monotonic, timestamp
22 | }
23 |
24 | func GetRealTime(capTime uint64) time.Time {
25 | monotonic := uint64(C.get_nsecs())
26 | timestamp := time.Now().UTC().UnixNano()
27 | return time.Unix(0, (timestamp - (int64(monotonic-capTime) * 1000)))
28 | }
29 |
--------------------------------------------------------------------------------