Compare commits

...

201 Commits

Author SHA1 Message Date
Vadim Yanitskiy 9f47bedf37 build: include README.md into the release tarball
Change-Id: I1fcd14371dd2576f45c9c0798fd5c3628b631e13
2024-01-26 23:36:41 +07:00
Andreas Eversberg 13b41bc206 Use uniform log format for default config files
Related: OS#6272
Change-Id: I0754f45561a45557d0f9fb3218813a2c8e83559c
2023-12-01 12:48:59 +01:00
Pau Espin 88b5dc63a9 Bump version: 0.4.1.9-7f4d-dirty → 0.4.2
Change-Id: I26ebcdcad2e7913d6a76277917ce4210bff20e1f
2023-09-12 15:50:50 +02:00
Vadim Yanitskiy 7f4debf1b9 tests: $(BUILT_SOURCES) is not defined
Change-Id: I81dc30f6d6e3b25723f00d945c87b9c01c648cbf
2023-06-12 19:39:52 +07:00
Oliver Smith 2ec703f7c8 systemd: depend on networking-online.target
Related: SYS#6400
Change-Id: Ib6c78c76c5f13b9482428ce653a61b03b2aca1d3
2023-05-26 14:10:46 +02:00
Oliver Smith b8d16e4e44 debian: set compat level to 10
Related: OS#5958
Change-Id: I9776c48f4f913dd7f7cde3afc6fe32bd0e9ba1b0
2023-04-25 16:48:30 +02:00
Max 17da7b38b9 CI/CD: drop travis support
It hasn't been tried in years and has likely bit rot by now.

Change-Id: Ia3c725e94ecd544adb8899c05d66828387906625
2023-04-15 10:54:12 +00:00
Pau Espin 3092167e4e server: Call osmo_fd_unregister() before closing and changing bfd->fd
Change-Id: I44405687dae79a13db5617867c669ee4840485ba
2023-03-14 11:50:02 +01:00
Daniel Willmann fa47880575 cosmetic: Remove trailing whitespace
Change-Id: I33c8747f1f9c1020232e91d5559f0a06a31857d8
2023-02-28 11:39:05 +01:00
Daniel Willmann 4e934bb546 osmo_{client,server}_main: Remove is_config_node in vty_app_info
This member is deprcated/unused so simply remove it:

> 'is_config_node' is deprecated: Implicit parent node tracking has
> replaced the use of this callback. This callback is no longer called,
> ever, and can be left NULL.

Change-Id: I34295950557d9009b0d8d3378deb3b1263476f82
2023-02-28 11:39:05 +01:00
Daniel Willmann 50cc638ac7 osmo_{client,server}_main: Remove tall_ctr_ctx and tall_msgb_ctx
tall_ctr_ctx is only used by the obsolete osmo_counters which are not
used anymore.
tall_msgb_ctx is now set through msgb_tallox_ctx_init().

Fixes undefined reference errors since libosmocore.map was introduced in
I13169c00a59fb59513dfc598de5a71d094492422:

```
osmo-pcap/src/osmo_client_main.c:226: undefined reference to `tall_msgb_ctx'
/usr/bin/ld: osmo-pcap/src/osmo_client_main.c:226: undefined reference to `tall_msgb_ctx'
/usr/bin/ld: osmo-pcap/src/osmo_client_main.c:227: undefined reference to `tall_ctr_ctx'
/usr/bin/ld: osmo-pcap/src/osmo_client_main.c:227: undefined reference to `tall_ctr_ctx'
```

Change-Id: Idcbb96fd070f5ad20d3091ce886dc6130968538f
2023-02-28 11:07:59 +01:00
arehbein 9d7556a73e Transition to use of 'telnet_init_default'
Related: OS#5809
Change-Id: Icc57c68337d55c6594c1c36e9bf41624d11dab0a
2023-02-25 17:48:58 +01:00
Pau Espin 97c5c0c15c Bump version: 0.4.0.2-af54 → 0.4.1
Change-Id: I98918597c0e3823f14aacd9e84d8b9b10f68e71d
2023-02-07 17:11:46 +01:00
Vadim Yanitskiy af54579bd4 doc/manuals: update git URLs (git -> https; gitea)
Change-Id: I5d510f324f59303c79c3a0fb2c15f79e7cb3a8c4
2022-10-18 17:18:56 +07:00
Max 36061e0d37 Set working directory in systemd service file
By default systemd will execute service with root directory
(or home directory for user instance) which might result in
attempts to create files in unexpected place. Let's set it
to 'osmocom' subdir of state directory
(/var/lib for system instance) instead.

Related: OS#4821
Change-Id: I39c48167cbe74b599c8edc3659e787792cbcfdfd
2022-09-09 22:47:13 +07:00
Pau Espin bddebaecb2 Bump version: 0.3.0.5-5364-dirty → 0.4.0
Change-Id: Id9d5ef30ddbeb644cfbd98383a8764435576cbfe
2022-06-28 17:36:44 +02:00
Pau Espin 5364393417 .gitignore: blacklist configure~
Change-Id: Ic31044e997c1d2213a89e5c7c051814373c454bd
2022-06-28 17:36:02 +02:00
Harald Welte 57be1059bd update git URLs (git -> https; gitea)
Change-Id: I6e679bde473cebb98e9521b35dc3c5da3672e5a9
2022-06-18 12:29:01 +02:00
Pau Espin a55253f438 client: Add 'wqueue max-length <0-4294967295>' VTY command
This allows setting a suitable write-queue max length per client. The
desired value can be different based on a lot of variables, like memory
availabilty, network and CPU load, input/output link state, etc.

Related: SYS#5921
Change-Id: I4e9d5d836ddda215f9e7a075aa8e10d2d3854dd2
2022-04-14 18:32:23 +02:00
Pau Espin 50dcc15a2e client: Log wqueue capacity when failing to enqueue
Related: SYS#5921
Change-Id: Ie5f39fe679906a15f74490cd8554b18b9d1e0664
2022-04-14 18:30:33 +02:00
Pau Espin 6bbda89308 client: Increase wqueue transmit length
Having a length of 10 packets is too low, it can be filled easily under
high load or really bursty traffic, where the input path could be polled
multiple times while the output path (write socket poll) is not called.

Related: SYS#5921
Change-Id: I72babfcc31e12624f30c16450dafd988192148be
2022-04-14 17:57:14 +02:00
Pau Espin d72581492f Bump version: 0.2.1.4-b9be → 0.3.0
Change-Id: I7a4c45817dd3db7471b98b4db3b7bd2d4f3c240d
2022-01-13 10:06:14 +01:00
Pau Espin b9be6767ab server: Add vty command file-permission-mask
Related: SYS#5792
Change-Id: I78e0b56b38de438ee5fb679ae41c65b02ea2e722
2022-01-12 17:44:38 +01:00
Oliver Smith 235eba3e9b Revert "configure.ac: don't depend on libosmogb."
gprs header files from libosmogb are needed for osmo-pcap. This was the
reason why it was added as dependency to configure.ac in
I9a8fa03cef1efc9fdaea65ee63ca9b3379993989.

  $ git grep "osmocom/gprs"
  src/osmo_client_core.c:#include <osmocom/gprs/gprs_bssgp.h>
  src/osmo_client_core.c:#include <osmocom/gprs/protocol/gsm_08_16.h>
  src/osmo_client_core.c:#include <osmocom/gprs/protocol/gsm_08_18.h>

The package is only still building for debian, because in debian
libosmocore is not split up, and for centos, because the rpm spec file
still lists the dependency.

This reverts commit 2c2eadcadf.

Change-Id: Ic358956521230a2f6525533779c27417b2e86833
2021-12-13 12:39:13 +01:00
Harald Welte 2c2eadcadf configure.ac: don't depend on libosmogb.
There is nothing in osmo-pcap that relates to the Gb interface
(NS/BSSGP).

Change-Id: I079013b288c0585c32a3e3883a585460b4c3e616
2021-12-11 10:50:38 +01:00
Vadim Yanitskiy b9392bfde0 debian/control: minimum version for libzmq3-dev is 3.2.2
We require this version in 'contrib/osmo-pcap.spec.in', and should here too.

Change-Id: If76b4fcb8863ad5468a77113ad25142fe1145cda
2021-11-16 12:57:16 +00:00
Pau Espin 02d9d05143 Bump version: 0.2.0.4-30bc-dirty → 0.2.1
Change-Id: I345f288218a6459ffbadc5cae9feaf708c2188eb
2021-11-16 13:40:07 +01:00
Pau Espin 30bc1885e4 Explicitly depend on required libosmogb
the spec.in files already stated so expicitly, since some files include
osmocom/gprs/*.h. Only some data types from there are used, so there's
no need in linking the lib. Even more, doing so makes the build fail
because there soft-linking symbols required to be implemented by
libosmogb are not implemented here.

Related: OS#5311
Change-Id: I9a8fa03cef1efc9fdaea65ee63ca9b3379993989
2021-11-16 13:36:14 +01:00
Oliver Smith eedd83c113 Change default ports of client, server
Resolve conflict with other Osmocom software by moving ports:

osmo-pcap-client 4237 -> 4227
osmo-pcap-server 4238 -> 4228

Notably the defines OSMO_VTY_PORT_PCAP_CLIENT and _SERVER are currently
not provided by libosmocore, but will be added with the related commit.

Related: OS#5203
Related: libosmocore I098f211370bba61995ce424ab64029bdd4c49e2d
Change-Id: I3b18b1fbbca2799f868f28104e2f5d513f93d46c
2021-08-05 19:24:02 +02:00
Oliver Smith 22f3d95ac9 README.md: fix typo
Change-Id: I624e491dda95449b879f362ed98784adf604ba2b
2021-08-05 18:52:43 +02:00
Pau Espin ef92a539e8 Use new stat item/ctr getter APIs
Generated with spatch:
"""
@@
expression E1, E2;
@@
- &E2->ctr[E1]
+ rate_ctr_group_get_ctr(E2, E1)
"""

Change-Id: Ic860db04489e9ee7312edb008497186116f30bfc
2021-06-04 18:01:06 +02:00
Harald Welte 6e564a97b9 Bump version: 0.1.3 → 0.2.0
Change-Id: Ic36b541fa4000c352927e721397a081ccc709b73
2021-04-24 23:03:34 +02:00
Harald Welte 8b73a2a530 vty: call telnet_init_dynif() after config file is read
In case the config file specifies a vty bind address, we must read
it before we start the telnet server.

Change-Id: I44561754d4beaad5c74cb66994ca4ef38960ea78
2021-04-24 16:09:09 +02:00
Harald Welte dd1389c3d3 use telnet_init_dynif() to allow VTY bind to non-loopack address
Prior to this patch, you could configure 'bind 1.2.3.4' in the
config file, but the telnet interface still binds to 127.0.0.1.

Change-Id: I9b86b2cf6949917c55ea15277619cfa2b745185d
2021-04-24 13:00:41 +02:00
Harald Welte 9148d49841 client: Ensure the "file" header is sent on connect
A non-blocking STREAM socket connect() will mark the socket as
write-able once the connection succeeds.  However, as we first
call osmo_fd_setup() and then osmo_sock_init2_ofd(), the latter
will force the 'when' to OSMO_FD_READ and hence the write callback
will not be called.

Change-Id: I44c484b48966a985a9b85fb16122a17df5666bc1
2021-04-23 14:02:11 +02:00
Harald Welte 831494ed34 use osmo_wqueue_enqueue_quiet() as we log anyway
There's no need in both libosmocore and osmo-pcap-client logging
the same queue overflow twice.

Change-Id: I43881f2bd0b0870a51f9ca5dad2d8cba40d1e54b
2021-04-23 13:27:11 +02:00
Vadim Yanitskiy 69ce121c6c contrib/jenkins.sh: fix: pass '--enable-manuals' to configure
Currently `make publish` fails on Jenkins because there is nothing
to publish.  In [1] we simply forgot to pass '--enable-manuals'
if $WITH_MANUALS is set to 1, so no PDFs are built.  Fix this.

Change-Id: I85dfecf2025a0466fccfe5a1e63cda788f85992e
Fixes: [1] I28353f51de798535a3bb6efdc6c2da443d96ddfb
2021-04-18 21:14:21 +02:00
Harald Welte a663ed23b1 Add user manual for osmo-pcap
This adds one common user manual for both osmo-pcap-client
and osmo-pcap-server.

The manual is still basic in nature, but already contains useful
information regarding the setup of both clients and servers.

Change-Id: I66182fc55f1ee323eba45e7a7fc59db55bff520e
2021-04-18 15:25:01 +02:00
Harald Welte 8a119642ac update copyright statement; Holger worked on it until 2017
Change-Id: I7a39d4780d309f2dba99272c17bf1b9639760199
2021-04-18 14:26:07 +02:00
Harald Welte b0b2a2d542 add "--version" to osmo-pcap-client and -server
Change-Id: Ib82ee1a784a657f7274d78ba5f7a8afe6cfab395
2021-04-18 14:24:15 +02:00
Vadim Yanitskiy ff3f4b3bef vty_{client,server}_init(): remove unused argument
Change-Id: I65256c8602e91bcdbe5fe9e532b6ce7d347d3980
2021-04-16 20:30:18 +02:00
Vadim Yanitskiy d59783e601 vty: register commands for talloc context introspection
Change-Id: I3774cfd483102993340bd6e96f8512af61085679
2021-04-16 19:36:29 +02:00
Joachim Steiger 52f06fd54b manuals: generate VTY reference for osmo-pcap-{client,server}
Change-Id: I28353f51de798535a3bb6efdc6c2da443d96ddfb
Tweaked-By: Vadim Yanitskiy <vyanitskiy@sysmocom.de>
2021-04-16 19:29:31 +02:00
Harald Welte 611fd19fa3 vty: Add space after prompt, as customary
In all other programs, we have a space after the VTY prompt.

Change-Id: I7916c15cc34e41738a5716e4fefbb15e18f02fa7
2021-04-12 16:07:17 +02:00
Pau Espin Pedrol 06303a6dc5 Bump version: 0.1.2.9-288c-dirty → 0.1.3
Change-Id: I9287411a7c1f69ddc6211c2557d41dd533c84ff9
2021-02-23 13:19:37 +01:00
Oliver Smith 288c39be10 configure.ac: set -std=gnu11
Change-Id: I52c86f461edd96d810fb85a60c68be581caa1799
2021-01-27 17:52:22 +01:00
Harald Welte 72cc2a508d reformat debian/control for osmo-release.sh compatibility
If we have more than one dependency in the line, osmo-release.sh
fails with
ERROR: configure.ac <libosmocore, 0.11.0> does NOT match debian/control <Build-Depends:debhelper, 7.0.50~dh-autoreconfautotools-devlibpcap0.8-devpkg-configlibosmocore-devlibgnutls28-devlibzmq3-dev>!

Change-Id: I8ab9a24af6ac0e4610ecc0eca1d5f5b9e03ad445
2021-01-06 17:14:13 +01:00
Pau Espin 716a4db54c main: generate coredump and exit upon SIGABRT received
Previous code relied on abort() switching sigaction to SIG_FDL +
retriggering SIGABRT in case the signal handler returns, which would
then generate the coredump + terminate the process.
However, if a SIGABRT is received from somewhere else (kill -SIGABRT),
then the process would print the talloc report and continue running,
which is not desired.

Fixes: OS#4865
Change-Id: I39367aa480445fe961dcfa308789b3fc0cf759a1
2020-11-25 19:11:43 +01:00
Harald Welte 5899cb4fbf Use osmo_fd_*_{disable,enable}
Change-Id: I97e100b34e9d26cf5acaa57be12879787d4d2d2b
Depends: libosmocore.git Idb89ba7bc7c129a6304a76900d17f47daf54d17d
2020-10-19 13:07:06 +02:00
Harald Welte a9600141b8 Use osmo_fd_setup() whenever applicable
Change-Id: I02097760e7c6a5694290f4b877013aee9d92fd0e
2020-10-19 13:06:44 +02:00
Harald Welte 20c6ba5a9e Use OSMO_FD_* instead of deprecated BSC_FD_*
Change-Id: I7d57919877520710b5dc1f54de1de89cae78093e
2020-10-18 22:39:39 +02:00
Oliver Smith f93e3dc1f8 Makefile.am: EXTRA_DIST: debian, contrib/*.spec.in
Change-Id: I2cf6d26b71af23d85b3b9675f9e60c08397115c9
2020-05-22 13:42:48 +02:00
Oliver Smith fd387ecec3 contrib: integrate RPM spec
Remove OpenSUSE bug report link, set version to @VERSION@, make it build
with CentOS 8 etc.

Related: OS#4550
Change-Id: I7ac5f2c6bf11d88a3ebbc2f17d963d26f0b7de13
2020-05-19 15:37:24 +02:00
Oliver Smith 9d5fadcc79 contrib: import RPM spec
Copy the RPM spec file from:
https://build.opensuse.org/project/show/home:mnhauke:osmocom:nightly

Related: OS#4550
Change-Id: I5593db28b91a67a7f51abe086b83905066a1dfe7
2020-05-14 11:49:52 +02:00
Pau Espin d8368cebf8 Bump version: 0.1.1.4-7aa6 → 0.1.2
Change-Id: Ia47cff102c66902d17d92ecfe34018ebd86c5f55
2020-01-02 20:19:28 +01:00
Oliver Smith 7aa63021b6 osmoappdesc.py: switch to python 3
Make build and external tests work with python3, so we can drop
the python2 dependency.

Note that the external tests, which are using this file, are currently
not enabled in jenkins (OS#4317). However, I've manually verified that the
external tests work with this change.

Related: OS#2819
Depends: osmo-python-tests I3ffc3519bf6c22536a49dad7a966188ddad351a7
Change-Id: I19a996458745026cff60608710944e5ab76d8976
2019-12-11 09:38:21 +01:00
Oliver Smith 47ea18eb8e Cosmetic: README.md: document how to run tests
Mention the setcap command, that makes external tests work.

Related: OS#4317
Change-Id: Idc18925f0b71164b52248ca9312b997681d15241
2019-12-10 15:39:50 +01:00
Oliver Smith fdd62daa66 osmoappdesc.py: fix paths to configs
This makes external tests work again.

Related: OS#4317
Change-Id: I73ab32ea48ddfc1b017c8152ec4e95a9ed4f1d7b
2019-12-10 15:39:36 +01:00
Oliver Smith 380305ee09 Cosmetic: README.md: fix typo
Change-Id: I2df3235bade659d62cf179c680a958baabacaa51
2019-12-10 15:30:29 +01:00
Pau Espin 5e10f1db12 Bump version: 0.1.0.2-ce06 → 0.1.1
Change-Id: If517941429cc80419a80771f89f93a7a7ed2bc02
2019-08-07 13:12:48 +02:00
Pau Espin ce0660cfe1 Require libosmocore 0.11.0
Building against older versions fail for different reasons, newest one
being due to osmo_init_logging2 being added in 0.11.0.

Change-Id: Ic7f147c5a26b45b75931cfd8f662642f59a1d725
2019-08-07 13:11:03 +02:00
Pau Espin 210ed934bb Remove undefined param passed to {logging,osmo_stats}_vty_add_cmds
Since March 15th 2017, libosmocore API logging_vty_add_cmds() had its
parameter removed (c65c5b4ea075ef6cef11fff9442ae0b15c1d6af7). However,
definition in C file doesn't contain "(void)", which means number of
parameters is undefined and thus compiler doesn't complain. Let's remove
parameters from all callers before enforcing "(void)" on it.
API osmo_stats_vty_add_cmds never had a param list but has seem problem
(no "void"), so some users decided to pass a parameter to it.

Change-Id: I2e1ab7005514f1a06cac03e967aa5c8ea472e671
Related: OS#4138
2019-08-05 16:28:11 +02:00
Pau Espin 901543a788 Bump version: 0.0.11 → 0.1.0
Change-Id: I4f0d75163fcb7d8d9b5540f8970382ce873680d4
2019-07-16 19:01:16 +02:00
Pau Espin 300cb49540 debian/changelog: Mark 0.0.11 as released
Change-Id: I08a722be405f667797d180ec66e08ba0dc9f59d8
2019-07-16 04:07:09 +00:00
Oliver Smith d567571180 contrib/jenkins.sh: run "make maintainer-clean"
Related: OS#3047
Change-Id: Ieae88eec72801e143daa631e7d01a5e11e9befae
2019-07-10 12:30:53 +02:00
Oliver Smith e524725f9b gitignore: fix application names
Change-Id: I4ea6b6691a0e6cfb3de0c9d2b1a0c3ed68a18514
2019-07-04 15:35:05 +02:00
Pau Espin d68773c4dc tests/Makefile.am: Fix "./configure && make clean && make"
Without this patch, make check fails with following error:
No rule to make target 'atconfig', needed by 'check-local'

Changes needed to fix the issue were gathered by looking at differences
with libosmo-netif's Makefile.

Change-Id: Ie6698d1c1d36e2b8a5391bc2322c1632458751db
2019-07-04 12:21:33 +02:00
Harald Welte 407f7f9307 Fix compiler warning about deprecated _BSD_SOURCE
On (at least) Debian unstable I'm seeing the following compiler
warninig:

/usr/include/features.h:184:3: warning: #warning "_BSD_SOURCE and _SVID_SOURCE are deprecated, use _DEFAULT_SOURCE" [-Wcpp]
 # warning "_BSD_SOURCE and _SVID_SOURCE are deprecated, use _DEFAULT_SOURCE"

Apparently this was deprecated in glibc 2.20 released in 2014 (!)

Change-Id: I826189dec4107e7c3e8cf4c013316ef3014b7857
2019-01-26 17:39:19 +01:00
Harald Welte 066fc59ed0 change binary builds URL to network:osmocom as that's more maintained
Holgers' personal feed hasn't been updated for quite some time, and
we're building osmo-pcap as part of the normal latest and nightly builds
for quite some time now.

The only disadvantage compared to Holgers' personal feed is the lack of
support for RPM-based distributions (RHEL, CentOS, OpenSuSE).

Change-Id: Ic479c192ca259f01d422da3bd44443fe4160ccaa
2019-01-26 17:34:48 +01:00
Oliver Smith 5edc9b2382 contrib: fix makedistcheck with disabled systemd
EXTRA_DIST files need to be distributed, no matter if the systemd option
is configured or not.

Change-Id: I2fed90915f57bbb054a26bacecf8417d6f3ba5ce
2018-12-06 13:54:54 +01:00
Oliver Smith 14512ddae8 Fix DISTCHECK_CONFIGURE_FLAGS override
Set AM_DISTCHECK_CONFIGURE_FLAGS in Makefile.am instead of
DISTCHECK_CONFIGURE_FLAGS. This is the recommended way from the
automake manual, as otherwise the flag can't be changed by the user
anymore.

Related: OS#3718
Change-Id: Iaac6d41ef1cc2d5449edf870f635b28b045dc7db
2018-12-04 15:44:40 +01:00
Pau Espin 3ad56f0408 debian: Install osmo_pcap_clean_old in osmo-pcap-server pkg
Change-Id: Ia4b031fdf54cde3d00818df82e89733420a735ba
2018-11-01 12:52:30 +01:00
Pau Espin a3a6ceb5f7 gitignore: Add compile
Change-Id: Ie801d6929068d11fafd24a1370e60e984b0137c2
2018-11-01 12:52:30 +01:00
Pau Espin 45283d84e3 Install cfg files with autotools
Cfg files are moved to doc/examples like in other osmocom projects.
All the cfg files get installed into
$prefix/share/doc/osmo-pcap/examples/$subdir/, and 1 script per binary is
installed into /etc/osmocom.

Change-Id: If3f3a7d3867c0d4d2b1fe01f465532d1ce4bda66
2018-11-01 12:52:22 +01:00
Pau Espin b29f84ff6c Install systemd services with autotools
Change-Id: Id938f3dab4826ac748abb5e0b169d800c2a625a5
2018-11-01 12:51:39 +01:00
Pau Espin b96c957a22 debian: Clean up to look like other osmocom projects
Change-Id: Id71699642b799f5b2f8f3b794b9493ddaeb70cc0
2018-11-01 12:51:35 +01:00
Pau Espin 80d2b7b8dd contrib/jenkins.sh: Update to current osmocom infra
Otherwise builds end failing in osmocom jenkins/gerrit.

Change-Id: I955b99ce27df143f5d022619dd14e32b763e6c14
2018-11-01 12:42:54 +01:00
Pau Espin a82aaef507 server: Add pcap snaplen VTY cmd
Change-Id: I8fdcdc1a58926ec66a1dc5dc7a5e57ed4dceb4b4
2018-10-08 20:20:43 +02:00
Pau Espin 868a501213 server: Improve verification of messages from client
Take the chance to define SERVER_MAX_DATA_SIZE as pcap payload, which we
can later match to configurable snaplen parameter.

Change-Id: I45d4c59026faf1108c0976eb6ad8c270e3577dbf
2018-10-08 20:20:43 +02:00
Pau Espin b799344ecd client_send_link: snaplen not needed during allocation
We don't send any pkt data, so no need to allocate snaplen bytes extra.

Change-Id: I8d6385f6ff265564492121812a7a9f2bcfea3d5f
2018-10-08 20:20:43 +02:00
Pau Espin f946fa21ee client: Add pcap snaplen VTY cmd
Change-Id: I84fda9f27b725e031c218187ab679392dfa7ec3d
2018-10-08 20:20:43 +02:00
Pau Espin 168949e119 client: Set snaplen to MAXIMUM_SNAPLEN
Despite this value not being exported publicly, the truth is that
tcpdump and wireshark nowadays avoid processing any file with snaplen
bigger than this value:
"tcpdump: pcap_loop: invalid packet capture length 861244, bigger than
snaplen of 262144"
It also fails to set snaplen to values bigger than that:
"tcpdump -s 262145" --> "tcpdump: invalid snaplen 262145"

pcapfix also warns about wrong packet length if bigger than same value
(defined as PCAP_MAX_SNAPLEN there).

MAXIMUM_SPANPLEN is defined in tcpdump's netdissect.h and libpcap's
pcap-int.h. It is also defined as WTAP_MAX_PACKET_SIZE in
wireshark/wiretap/wtap.h (this one being the only publicly available).

Change-Id: Ib7449d5aba9da342c150704ebd0e1f09e7f7276c
2018-10-08 20:20:43 +02:00
Pau Espin db7be44632 Use enum for PKT_LINK_*
Makes it easier to understand different types and how they relate to
same field.

Change-Id: I1bec4d5d132a1476f9c418502ad808b7c778cee2
2018-10-08 20:20:43 +02:00
Pau Espin f10c57801a Replace '.' in counter names with ':'
The '.' is illegal character in counter names, as they are exported
via CTRL interface, where '.' has a special meaning that cannot be
used by strings comprising the variable name.

Change-Id: Icec5338d3242137980fa05d2c7ae2db940afb542
2018-10-08 20:20:43 +02:00
Pau Espin 78262bda57 jenkins.sh: enable werror and sanitize configure flags
Change-Id: Id8ad324ae9e1c57e1328bd1be04977e921125847
2018-10-08 13:41:47 +02:00
Pau Espin e241eada55 configure.ac: Add --enable-sanitize flag
Change-Id: I6a3bc49142b93a35988c8763f3125d7b5ffddaef
2018-10-08 13:39:51 +02:00
Pau Espin f59fabf9dc configure.ac: Add --enable-werror flag
Change-Id: I387a3365fb5b7340bf67fb945df434442924a4c7
2018-10-08 13:38:42 +02:00
Pau Espin d475673b69 osmo_client_send_data: Fix wrong log format
According to pcap.h, type bpf_u_int32 can be 32 bits on some systems,
so better cast explicitly to size_t to make sure always correct size is
used by log function.

Fixes warning:
osmo-pcap/src/osmo_client_network.c:175:4: warning: format ‘%zu’ expects argument of type ‘size_t’, but argument 7 has type ‘bpf_u_int32’ {aka ‘unsigned int’} [-Wformat=]
    "Capture len too big %zu\n", in_hdr->caplen);
    ^~~~~~~~~~~~~~~~~~~~~~~~~~~  ~~~~~~~~~~~~~~

Change-Id: I98654da143218d3e57da4e57781252eb3d3f3d5b
2018-10-08 13:33:50 +02:00
Pau Espin dc27ca85aa Drop osmo_init_logging and use osmo_init_logging2
Change-Id: Ib1c38f6134b3c1988477caa0f2c281b1ef01d5e0
2018-10-08 13:29:52 +02:00
Pau Espin 5f3c30c40c server: Properly name main talloc ctx
Change-Id: I810417d84c6a6ebcbc4b75a9bc41607bb0637228
2018-10-08 13:29:52 +02:00
Pau Espin 2828690633 client: Properly name main talloc ctx
Change-Id: Ibaa7f0e0add5f5e61cc0bb82341ee3b6b5c0cf07
2018-10-08 13:29:52 +02:00
Pau Espin 6e9bf9aa15 vty: skip installing cmds now always installed by default
Fixes following compilation warning:
osmo-pcap/src/osmo_client_vty.c:511:2: warning: ‘install_default’ is deprecated: Now happens implicitly with install_node() [-Wdeprecated-declarations]

Depends: libosmocore I5021c64a787b63314e0f2f1cba0b8fc7bff4f09b
Change-Id: I943f68dbafd7906313ad9e59f4adb289ae23cdec
2018-10-08 13:29:52 +02:00
Pau Espin 3dfdbc21dc cosmetic: client: rename forward_packet function
Function only checks if packet should be forwarded, it doesn't forward
any packet.

Change-Id: I87cd64290245db134b17bc0d6665c58f1cde17b6
2018-10-08 13:08:52 +02:00
Harald Welte e89231d8b0 debian/control: Fix URLs for homepage, git, gitweb
Change-Id: Iff74cf6b3e53a6786a96738b609a2e2d685b1300
2018-02-09 12:07:50 +01:00
Harald Welte f335e37ed5 Add support for generating IPIP to osmo-pcap-client
This allows the user to change the configuration between either using

a) the classic OsmoPCAP protocol (over TCP with or without TLS)
   which is used when you want to talk to an osmo-pcap-server

b) the (new) IPIP encapsulation, which will simply take the IP
   packet (without Ethernet or pcap header) and transmit it inside IPIP
   to the specified server IP address.  This is useful for gettin
   real-time streaming into wireshark.

Change-Id: I8056fc163ac2f15adcb964d867dd5e51df4e4710
2018-02-09 12:07:50 +01:00
Max 53044df9d5 Use release helper from libosmocore
See
https://osmocom.org/projects/cellular-infrastructure/wiki/Make_a_new_release
for details.

Change-Id: Iafe5905895a656b7055d58ca8f745fcfa4bd9886
Related: OS#1861
2017-08-28 10:57:19 +00:00
Max 93ac357b48 Add gitreview config
Change-Id: I35b3aaa3f8af4127d8a1b00c77ab02ae6a182714
2017-08-22 12:34:59 +02:00
Harald Welte 5f071cd2c6 client: Move to osmo_sock_init2_ofd()
We can simplify the code even further by using the osmo_fd version
of osmo_sock_init2() called osmo_sock_init2_ofd(), which takes care
of filling the osmo_fd.fd member and registering the socket in the
select loop.

Change-Id: Ibf1480e7dee287db77a19bb9f0254edddf7706ab
2017-07-21 18:25:15 +02:00
Harald Welte f266924bac Use libosmocore osmo_sock_init2() instead of local implementation
A related function for "create a socket, bind it locally and connect
remotely" has meanwhile been introduced in libosmocore, so the local
implementation can go.

Change-Id: Ieda77ad8b3f7b89faa09882c0037562ce4d0fc89
2017-07-21 18:20:36 +02:00
Harald Welte 2fe9cb937d Rename osmo_pcap_{client_server} executables to osmo-pcap-{client,server}
This naming is more in line with what all the other osmocom programs are
doing (e.g. osmo-pcu, osmo-bts-sysmo, osmo-bsc, ...).  We don't
generally use osmo_ anywhere else, so I suggest to change it for more
uniformity.

Change-Id: If1e3ce76f93266e0f01c801204769432b571fdb1
2017-07-21 15:21:01 +02:00
Harald Welte 2aea8704f3 Use TCP port numbers for VTY that don't overlap with other Osmocom Software
osmo-pcap for historical reasons uses the same port numbers as
OsmoPCU and OsmoBTS.  This leads to problems when wanting to run related
software together on one system.  Let's break the historical assumptions
and start with non-overlapping port numbers that are allocated/assigned
from https://osmocom.org/projects/cellular-infrastructure/wiki/Port_Numbers

Change-Id: I638ac0534517931d0987ce9f72f5db4f5b6c16b7
2017-07-21 15:18:02 +02:00
Harald Welte 604e071159 sock_src_init(): Don't freeaddrinfo() undefined src_result
src_result is only valid "if (src)", so we cannot unconditionally
free it:

(gdb) bt
    host=0x52 <error: Cannot access memory at address 0x52>, src=0x0)
    at /usr/src/debug/osmo-pcap/0.0.6+gitrAUTOINC+4776b2972e-r1d/git/src/osmo_client_network.c:165

Change-Id: I3b6778d9110583ecb1daec59ef2c86465d5818b9
2017-07-21 13:11:24 +02:00
Holger Hans Peter Freyther 4776b2972e debian: Add -dbg packages for the osmo-pcap-client and osmo-pcap-server
Currently looking at a weird issue. Make it possible to install the
-dbg packages.

Change-Id: I7d6c8e491be459151c1531b86f28bb1dc2ee8bb4
2017-03-07 23:17:41 +01:00
Holger Hans Peter Freyther 17f5b00506 debian: Make a new release with the new feature
Change-Id: Ibe86b761b494e0fb78bbbc78e3c1982e44185750
2017-01-17 09:13:36 +01:00
Holger Hans Peter Freyther 40c1e85499 client: Allow to bind to a specific source_ip
Modify the osmo_sock_init (code clone to be integrated upstream)
to allow binding to a specific source ip and source port. Allow
the source ip to be configured but allow the kernel to pick a
random port for us.

This is necessary for systems with multiple interfaces where the
default route is not necessarily the right one to connect to the
pcap server.

Change-Id: I84e728b0752213d28f970fcbbfd6565c441ccfeb
2017-01-17 09:06:42 +01:00
Holger Hans Peter Freyther fdebd88059 debian: Make a new release with the new features we gained
Change-Id: I85e210e6ed14aef085902a5af6407d51685aecba
2016-11-09 02:11:45 +01:00
Holger Hans Peter Freyther 36a183fd78 client: Tolerate an invalid pcap_handle
When not running as root the opening might fail and then we would
crash when sending the link information. Do not crash. This could
have crashed before the re-factoring but due the async connect it
seems more likely we hit it now.

Change-Id: I26a10c401a9a8998acc50a4bd4432d2ac7fceaeb
2016-11-09 01:46:35 +01:00
Holger Hans Peter Freyther 9294c40f14 client: disconnect before connecting the connection
With the VTY a user can write connect, connect, connect and this
would lead to leaking fds. Always close the connection.

Change-Id: Iab94dc2fd28496bf5fd8ceb5611f9e6505ccae1b
2016-11-09 01:04:04 +01:00
Holger Hans Peter Freyther 0a94e57b72 client: Allow to stop and remove a connection
Change-Id: I2118723345caf6a68f03de74a4182506e7bf105c
2016-11-09 01:04:04 +01:00
Holger Hans Peter Freyther d7ab53dc16 client: Do not connect default connection if no ip/port present
Ignore the default connection if no srv_port and has been specified.

Change-Id: I6a3a9a0af73a9183a6b233937af3357d15a07f25
2016-11-09 01:04:04 +01:00
Holger Hans Peter Freyther 1448f50db4 client: Allow to configure and connect multiple servers
Allow to configure multiple servers and connect. Introduce a new VTY
node to allow multiple servers. Add an explicit connect. Do not put
the main connection into the same list but assume it exists.

Change-Id: I9448ad4a005dd7c7eb1c615d03e57d6cb058ae4d
2016-11-09 01:04:04 +01:00
Holger Hans Peter Freyther 956c3facf1 client: Enable a non-blocking connect to the PCAP server
If we want to have multiple servers we should not block when trying to
connect to one of them. Enable non blocking mode and handle the fd
specially until it is connected. E.g. on failed connect the read will
become readable but fail, otherwise it becomes writable.

Clear the write queue to make sure that the link data is sent first.
We might be able to introduce a osmo_wqueue_prepend.

Change-Id: Iae2bc264d15aa8598beefc194e3b8c4ebe87320a
2016-11-09 01:03:59 +01:00
Holger Hans Peter Freyther e3d7c3e154 client: Prepare to work with a list of servers
There is no VTY code yet and no servers in the list but it looks
good client this.

Change-Id: Ic35748f1a95a880a9fa49dd18361592d8ac941ba
2016-11-09 00:20:29 +01:00
Holger Hans Peter Freyther bdda28b1f5 client: Finish renaming client to conn in other places of the code
Change-Id: I3c7c499c921b03752cbbcdda3eac8ca360323a22
2016-11-09 00:20:29 +01:00
Holger Hans Peter Freyther 13f397c68c client: Prepare to have multiple server connections
Take out various fields into a new connection class. We will have the
option to connect to multiple servers.

Change-Id: I820176d133fbdb0240a16eb4e1a6d505e5c080c6
2016-11-09 00:20:29 +01:00
Holger Hans Peter Freyther 0381276993 Merge branch 'feature/tls'
Add TLS support to the client and server. What is known working is
support of anonymous mode with generated DH params. Mildly tested
by hand over localhost.
2016-09-08 16:32:36 +02:00
Holger Hans Peter Freyther 22acd211f1 test: Add tls config file and enable tls a bit
Change-Id: Iba0008e3e0da276cc65c7501145b65294233febb
2016-09-08 16:24:04 +02:00
Holger Hans Peter Freyther 07b94157ec doc: Add initial documentation for the tls support
Change-Id: Ifc042e6755c223339fafbc3af9106073341f9b45
2016-09-08 16:17:02 +02:00
Holger Hans Peter Freyther cf29fd7069 server: Add vty interface for the TLS configuration
Make the priority configurable, load DH params, allow to specify
certificates or anonymous operations.

Change-Id: I8ec3c0f8e1ee2089e1b7dacd9de842260930032f
2016-09-08 16:17:02 +02:00
Holger Hans Peter Freyther ff3314e45c server: Allow to enable tls for the pcap server
Add simple vty command to enable tls per client or not. We still
need a lot more tls commands for the server.

Change-Id: I583b7d5c999ed01c135882895fb2a8f04739ad00
2016-09-08 16:17:01 +02:00
Holger Hans Peter Freyther 9ea4da4bbb server: Introduce tls mode for the server
Using tls priority of NORMAL:+ANON-ECDH:+ANON-DH already allows a
client to connect to a server and protect the data using tls.

Generate the dh params on load (and do that for the client right
now as well) but that will go away soon.

Change-Id: Ifa2ad24c0a631573c259a3bf94b91a946ad9ec9d
2016-09-08 16:17:01 +02:00
Holger Hans Peter Freyther 064d224288 server: Re-factor the read dispatch and connection close
In preparation of TLS let's not call close_connection from
within the dispatch but return an error and then close the
connection from the outside.

Change-Id: I607fed0191907cfbc8887d749c88f7f4ffb87166
2016-09-08 16:17:00 +02:00
Holger Hans Peter Freyther 1bec9d5d09 server: Add API function to close a connection
Change-Id: I4295854c749d86ca8c34a979c877363d9f48e176
2016-09-08 16:17:00 +02:00
Holger Hans Peter Freyther 098850d0a8 server: Move to a write_queue for the conn socket
We are only reading from the socket and never write but the osmo_tls
code is integrated with it. We will never write and the queue size is
set to 0. Simplify the read_cb.

Change-Id: I32335b1f7b7ed06b92c6222516c185301ce13781
2016-09-08 16:17:00 +02:00
Holger Hans Peter Freyther 6413e7669e server: Update copyright after zmq changes
Change-Id: I8861acaaec5465de620637b7fdf3341517133c4f
2016-09-08 16:16:59 +02:00
Holger Hans Peter Freyther c266796caa client: Initial support for TLS in the client
Use GNUtls because it is GPL compatible and instead of mbedTLS seems
to have a working non-blocking I/O integration. GNUtls has various
issues that could not be resolved easily:

* Pick spdy as sub protocol
* gmt_time not randomized
* private key loaded to RAM (but not verified)

This is the beginning and not the end. Client support might need more
work with actual tls verification. Maybe more manual x509 cert
verification is needed and maybe client certs don't work at all. I try
to ignore renegotiation as I threw away the key.

Reload x509 creds and keys as they might have changed from one
connection to another.

Change-Id: I9128e14084da1fc2705f858393f98b8133996172
2016-09-08 16:16:55 +02:00
Holger Hans Peter Freyther c1c194393b client: Add API function to close and re-connect network connection
Change-Id: Ib4e17948ffa84e73c1c81734e6002a73251d744b
2016-09-08 15:48:02 +02:00
Holger Hans Peter Freyther 3d439d0d08 tls: Add initial ideas about TLS in the client/server
Change-Id: I63a8cea776e57dce747a357c40f9caa0a9e2d3b5
2016-09-08 15:48:02 +02:00
Holger Hans Peter Freyther 0b4b824887 tests: Enable the vty tests for the osmo-pcap as well
Change-Id: I1704e0d58a04770a3aac1f70f3e01ee9ac585dbf
2016-09-08 15:21:29 +02:00
Holger Hans Peter Freyther fa5572e2af client: Use pcap_stats and export them as statistics
Attempt to write code that detects the wrap and is doing the
right thing when it happens.

Change-Id: I501ebc49d3e86b0605ec1fbe2f62aee3f362aa36
2016-08-19 20:28:21 +02:00
Holger Hans Peter Freyther 99526a6ad0 server: Add global and per client counters and begin to count
Add the basics for getting a picture what a client and the server
is doing. We need to create unique descriptions as the code is
working with names and not numbers for clients.

Change-Id: I4a9be5bdd815d280cccf0199efc2ca79fc77d393
2016-08-19 19:23:00 +02:00
Holger Hans Peter Freyther c3455dcb79 client: Additional counters for the statistics
Add more counters and start counting them when reading from the
PCAP library and when trying to write to the socket.

Change-Id: I52d3064a265b402ac849d8578a14f718156c0805
2016-08-19 17:31:01 +02:00
Holger Hans Peter Freyther f416463a3c client: First round of statistics in the pcap client
Count certain events that can help to understand what is going on.
This includes OOM, failure to queues.

Change-Id: I4a2dad32afb577822c7181d2813ea5a7e693c704
2016-08-18 18:39:53 +02:00
Holger Hans Peter Freyther 918be51338 server: Fail if the telnet interface can not be bound
Change-Id: Ibd14da3e7f62065f5d28d4a90d2b55eed609b64f
2016-08-18 18:37:13 +02:00
Holger Hans Peter Freyther 86282d65db client: Fail to start if it can't bind the telnet interface
Change-Id: Ic628dd348f8fce978691aaa331b0e67ee13f10c6
2016-08-18 18:34:27 +02:00
Holger Hans Peter Freyther 6e938eda1c stats: Initialize the stats(d) backend in the client/server
Initialize the stats backend allowing key performance indicators
to be pushed out of the system.

Change-Id: Id652b60d230f705b927e49d81cd3731432156c7e
2016-08-13 10:36:58 +02:00
Holger Hans Peter Freyther f8ff41e0f9 misc: Address compiler warning about deprecated header
In file included from osmo_client_main.c:27:0:
/home/ich/install/openbsc/include/osmocom/core/process.h:1:2: warning: #warning "Update from osmocom/core/process.h to osmocom/core/application.h" [-Wcpp]
 #warning "Update from osmocom/core/process.h to osmocom/core/application.h"

Change-Id: Id60cf90ebb7255d79f8e3bdb81f099f1362d538b
2016-08-13 10:31:02 +02:00
Holger Hans Peter Freyther df92652c95 vty: Fix compiler warning about type changes
osmo_client_main.c:57:2: warning: initialization from incompatible pointer type
  .go_parent_cb = osmopcap_go_parent,
  ^
osmo_client_main.c:57:2: warning: (near initialization for ‘vty_info.go_parent_cb’)
  CCLD     osmo_pcap_client
  CC       osmo_server_main.o
osmo_server_main.c:56:2: warning: initialization from incompatible pointer type
  .go_parent_cb = osmopcap_go_parent,
  ^
osmo_server_main.c:56:2: warning: (near initialization for ‘vty_info.go_parent_cb’)

Change-Id: If73c85a64789ef4bff63dcfe008e918e650b428f
2016-08-13 10:29:46 +02:00
Holger Hans Peter Freyther bdcbe0a679 misc: Update the todo with an obvious thing to do
Change-Id: I002e72776c6916ee331b4387b6d645d0c48c388c
2016-08-12 11:01:59 +02:00
Holger Hans Peter Freyther 2c503dd852 todo: With zeromq we can stream the data anywhere we want
Change-Id: I97c23cbf2d5f42b12e2fc8426633401c4edc1a62
2016-08-06 12:26:15 +02:00
Holger Hans Peter Freyther e024869a72 server: Add zmq based event and data interface to the server
To allow easily extracting or streaming the data to an external
analysis system, zeromq can be configured (and reconfigured). The
system works as fire and forget and no loss detection is present.

A simple go based client application is provided to subscribe to
the publisher.

Change-Id: I4f3e6d675023a81b7d2ee19bf1f44a2be0ca003c
2016-08-05 16:10:05 +02:00
Holger Hans Peter Freyther ad29ce6f06 server: Add zmq interface for publishing events
Change-Id: I383558bb9aad3cb149f35e13910a1d6aa79afc84
2016-08-04 18:02:57 +02:00
Holger Hans Peter Freyther 2899428be2 server: Add a config knob to not store the pcap stream
We might only want to centralize the data streams but handle the
data differently. This will be combined with an upcoming ZeroMQ
publisher feature to broadcast all events out.

Change-Id: I12c6bf16310820d882fa28c6930931650475e0bb
2016-08-04 16:14:38 +02:00
Holger Hans Peter Freyther 9646754e1f ci: Add travis.yml for the github account
Change-Id: I26de644a9cf4c6d6fb366c8a8fd701570005b9a8
2016-08-03 22:00:58 +02:00
Holger Hans Peter Freyther 26ba7b247e todo: Add another of my wishlist items
Change-Id: I5a6c473a97d04aecae8101a024edb734bbe24401
Reviewed-on: https://gerrit.osmocom.org/27
Tested-by: Jenkins Builder
Reviewed-by: Harald Welte <laforge@gnumonks.org>
2016-05-12 11:22:39 +00:00
Holger Hans Peter Freyther c2715e917f todo: Update with my long term goal to have TLS support
Change-Id: I566d48fe9831f384b93c3fad72a7dae9dd61b2d2
2016-05-08 11:24:04 +02:00
Holger Hans Peter Freyther ea4ad4680a jenkins: Attempt to fix FreeBSD distcheck
Change-Id: I758a5590f3d964039363852f07f0967170fd9a28
2016-05-03 14:37:34 +02:00
Holger Hans Peter Freyther ddc698fa92 freebsd: Another fix for the next file
Change-Id: I509e44c48d7983b305bc5fbcd9360ead74ef8d68
2016-05-03 14:37:31 +02:00
Holger Hans Peter Freyther 072b183cd8 freebsd: Include netinet/in.h and hopefully fix the build
Fixes:
/usr/include/netinet/ip.h:69:17: error: field has incomplete type 'struct in_addr'
        struct  in_addr ip_src,ip_dst;  /* source and dest address */

Change-Id: I446f67b85122363de66c86ddb25c8392ffa61a4f
2016-05-03 14:37:28 +02:00
Holger Hans Peter Freyther 7ab0c0b86c jenkins: Attempt to fix build on FreeBSD and not break Linux
pcap-config is not present as libpcap is part of the base system.
Use it as /bin/true and inject -lpcap as PCAP_LIBS.

Change-Id: I0c2b5222da0ee037d3a3156ac1fef89dfd849cad
2016-05-03 14:37:26 +02:00
Holger Hans Peter Freyther 157797317d distcheck: Need to package .version on Ubuntu as well
echo 0.0.6.14-5dff > ../../.version-t && mv ../../.version-t ../../.version
/bin/bash: ../../.version-t: Permission denied
Makefile:786: recipe for target '../../.version' failed
make[1]: *** [../../.version] Error 1

Change-Id: I726181f7af3e7582398738e0746982a5ea31d7e9
2016-05-03 14:37:22 +02:00
Holger Hans Peter Freyther 5dff9f9ef5 jenkins: Add the build script from jenkins here
This can be used to replicate a build issue more easily.
2016-04-13 19:04:44 -04:00
Holger Hans Peter Freyther 3fedbf8361 Mention the packages available 2016-01-18 14:25:19 +01:00
Holger Hans Peter Freyther e6bad63dc6 Point to a stand-a-lone repository with many many packages 2016-01-18 12:32:42 +01:00
Holger Hans Peter Freyther fd15a866db misc: Update the readme 2016-01-05 15:09:27 +01:00
Holger Hans Peter Freyther d2650854b6 misc: Add a readme to describe the project purpose a bit 2016-01-05 12:50:46 +01:00
Holger Hans Peter Freyther c016b5d382 Make a new release with 64bit client fixes 2015-12-03 22:17:26 +01:00
Holger Hans Peter Freyther 66b80cc8f5 client: Deal with external representation for pcap files
We need to convert the 64bit timeval on a 64bit userspace (or on
OpenBSD) into a 32bit truncated value for being able to write the
file. This means we have 2038 issue here?
2015-12-03 22:13:38 +01:00
Holger Hans Peter Freyther fbdcf593f8 debian: Make a new release 2015-12-03 20:41:28 +01:00
Holger Hans Peter Freyther 42421c4f7e client: Allow receiving jumbo frames on the client as well
Check the caplen and see if it is bigger than our assumed
maximum. Make sure we have enough space for data+hdr+hdr.
2015-12-03 20:28:04 +01:00
Holger Hans Peter Freyther ff1a5dc751 server: Deal with jumbo frames on the wire
The 2000 as a number is too small. Modern networks can have a
higher MTU (up to 9000). Take this number and assume there is
a big header in front of it.
2015-12-03 19:53:24 +01:00
Holger Hans Peter Freyther 26327bd0ce server: Fix the language and refer to the received data length 2015-12-03 19:29:38 +01:00
Holger Hans Peter Freyther a316c9394a debian: Make a new release of the code 2015-11-19 10:16:00 +00:00
Holger Hans Peter Freyther 74f89c6119 gprs: Do not collect BVC FLOW CONTROL / ACK messages
These generate a high amount of traffic. They are good to debug
ip.access nanoBTS GPRS crashes/service outage but in general cause
too much traffic.
2015-11-19 10:14:56 +00:00
Holger Hans Peter Freyther f42bbbc278 debian: Prepare a new release 2015-09-10 17:11:40 +02:00
Holger Hans Peter Freyther ae5ec91a40 gprs: Remove left over for counting llc frames
These variables were used to verify how many LLC frames were
seen.
2015-09-10 17:02:18 +02:00
Holger Hans Peter Freyther b7a834b4cb gprs: Add a custom GPRS filter
Allow to inspect UDP messages and check for GPRS, NS, BSSGP
and then filter LLC frames. Parsing the vL datastructure with
the libpcap syntax is a pain. It could be done using BPF but
we do not want to use bpf asm to specify the entire ruleset.

I looked into using libepan/libwireshark but this has memory
issues and is painful too. So let's parse UDP, NS, BSSGP using
the info we already have. I tried a bit of editcap to generate
a bit of broken data. The length check might still be bad.

I used my crash_20100602.pcap file to count the LLC frames we
detect and compare that to wireshark it ended with the right
number.

  pcap add-filter gprs

can be used to enable the new filtering option after the OS
has received the packet.

Fixes: ONW#1314
2015-09-10 16:55:33 +02:00
Sylvain Munaut 07d96eb654 build: Replace deprecated INCLUDES with AM_CPPFLAGS
Thanks to mnhauke

Signed-off-by: Sylvain Munaut <tnt@246tNt.com>
2014-12-22 22:33:31 +01:00
Holger Hans Peter Freyther 4edd6e6f1e debian: Add a osmo-pcap-client init script
* Ask start-stop-daemon to fork and create a PID file for us
* Kill based on the PID file and not the name
2013-04-10 18:38:12 +02:00
Holger Hans Peter Freyther b08783de7b debian: Add changelog entry for 0.0.4 2012-11-07 10:53:27 +01:00
Holger Hans Peter Freyther b7568c6897 contrib: Really add the config files, move them to contrib 2012-11-06 23:45:07 +01:00
Holger Hans Peter Freyther d7999f0557 debian: Update the package building 2012-11-06 23:42:04 +01:00
Holger Hans Peter Freyther 6d06bb1500 build: Allow to set the PCAP_CFLAGS and PCAP_LIBS externally
pcap-config might not be available, e.g. on Debian6.0 and CentOS5.x. Allow
the code to be built anyway.
2012-11-06 23:38:57 +01:00
Holger Hans Peter Freyther fc3a427fb1 build: Properly link and package the example configurations 2012-11-06 09:06:44 +01:00
Holger Hans Peter Freyther 557215fd56 misc: Fix the version determination of git-version-gen 2012-11-06 08:48:33 +01:00
Holger Hans Peter Freyther e8b9177706 dist: Attempt to fix the make distcheck 2012-01-06 00:46:38 +01:00
Holger Hans Peter Freyther 56d12cb505 dist: Attempt to fix the make distcheck 2012-01-06 00:45:14 +01:00
Daniel Willmann f8e6e1888a contrib: Use explicit globs and regexps 2011-12-26 23:59:09 +01:00
Holger Hans Peter Freyther 0741879e11 cron: Deal with '-' in the name of a client.
Do not stop when seeing the first '-'. E.g. if you have names like
tpe-system1, tpe-system2 they were treated as tpe and it was possible
that a currently opened file was deleted.
2011-09-24 16:51:32 +02:00
Daniel Willmann 53e1f38514 Clean by age as well as by amount of files in osmo_pcap_clean_old
The behaviour can be controlled by setting METHOD to "AGE" or "FILES".
2011-08-18 14:10:59 +02:00
Daniel Willmann 0e94548484 Fix bug where the cleanup script kept the oldest files
Fixes OW #21.
2011-07-26 12:36:00 +02:00
Holger Hans Peter Freyther b4fc89bfcf smatch: Check the client->device variable
This is fixing:
src/osmo_client_core.c +105 osmo_client_capture(8) warn: variable dereferenced before check 'client'
2011-07-19 17:59:00 +02:00
Holger Hans Peter Freyther cae1b7c960 misc: Remove process.h include, osmo_daemonize is in application.h now 2011-07-19 17:56:52 +02:00
Daniel Willmann 5d62ed0904 contrib: Add a script to clean up in regular intervals
This script should be run from cron. It compresses and deletes older
files.
2011-07-19 17:56:13 +02:00
Daniel Willmann b000368ad6 Catch up with API change in osmo_sock_init
The connect0_bind1 parameter has been replaced by a generic flag
parameter. With this patch osmo-pcap works (only) with versions of
libosmocore 0.3.2 or newer - configure.ac changed to reflects that.
2011-07-19 17:56:09 +02:00
Daniel Willmann c7401c6c23 server: Register signal handler to reopen logfiles on SIGHUP 2011-07-19 17:56:07 +02:00
Daniel Willmann de77386d84 server: Fix memory leak and error handling in restart_pcap 2011-07-19 17:56:03 +02:00
Holger Hans Peter Freyther f60990e3f4 server: Allow the group to read the files too 2011-06-10 15:29:46 +02:00
Holger Hans Peter Freyther dea9e8bbfe server: Make the maximum file size configurable 2011-06-10 15:23:04 +02:00
Holger Hans Peter Freyther de6262a97e TODO: Add a todo list... with bite size chunks 2011-06-03 20:25:56 +02:00
Holger Hans Peter Freyther 91eaae33ea osmo-pcap-server: Read the header in pieces too... 2011-06-02 17:58:46 +02:00
Holger Hans Peter Freyther 39d904f149 osmo-pcap-server: Try to read the the data with a simple state machine 2011-06-01 18:49:07 +02:00
Holger Hans Peter Freyther 9df7dc5f69 wireformat: Send the length in the network order..
this is a format change. but it is necessary now.
2011-06-01 17:34:09 +02:00
Holger Hans Peter Freyther 59bfb5854d osmo-server-network: Print the size of the packet.
Fix a typo, print the data we received and what we wanted.
2011-06-01 17:00:12 +02:00
Holger Hans Peter Freyther b1f5d5ebed osmo-client-core: Use the >= 0 handling. 2011-06-01 16:57:25 +02:00
Holger Hans Peter Freyther afcc2ae172 osmo-pcap-server: Indent the port properly 2011-06-01 16:33:55 +02:00
Holger Hans Peter Freyther 54ff0b1b86 osmo-pcap-server: Just check for >= 0 to find a valid fd 2011-06-01 16:33:11 +02:00
Holger Hans Peter Freyther dc3d1dcd59 osmo-pcap-server: Initialize local_fd with -1 otherwise 2011-06-01 16:32:29 +02:00
Holger Hans Peter Freyther e6acfea051 osmo-pcap-server: Deal with systems not providing these macros 2011-06-01 15:31:50 +02:00
Holger Hans Peter Freyther 0391b0a9c3 osmo-client-core: Work with older pcap libraries 2011-06-01 15:31:11 +02:00
Holger Hans Peter Freyther 821f4fad68 debian: Start packaging things 2011-06-01 15:00:55 +02:00
60 changed files with 4621 additions and 269 deletions

24
.gitignore vendored
View File

@ -5,6 +5,7 @@ Makefile
Makefile.in
*.*~
*.sw?
*.pyc
#configure
aclocal.m4
@ -16,6 +17,8 @@ depcomp
install-sh
missing
stamp-h1
compile
configure~
osmopcapconfig.h*
@ -25,5 +28,22 @@ osmopcapconfig.h*
# apps
src/osmo_pcap_client
src/osmo_pcap_server
src/osmo-pcap-client
src/osmo-pcap-server
# tests
tests/atconfig
tests/package.m4
tests/testsuite
tests/testsuite.log
contrib/osmo-pcap.spec
# manuals
doc/manuals/generated/
doc/manuals/vty/osmo-pcap-*-vty-reference.pdf
doc/manuals/vty/osmo-pcap-*-vty-reference.xml
doc/manuals/vty/osmo-pcap-*-vty-reference.xml.inc.gen
doc/manuals/vty/osmo-pcap-*-vty-reference.xml.inc.merged
doc/manuals/common
doc/manuals/build

3
.gitreview Normal file
View File

@ -0,0 +1,3 @@
[gerrit]
host=gerrit.osmocom.org
project=osmo-pcap

View File

@ -1,9 +1,22 @@
AUTOMAKE_OPTIONS = foreign dist-bzip2 1.6
SUBDIRS = include src
SUBDIRS = include src contrib doc tests
BUILT_SOURCES = $(top_srcdir)/.version
EXTRA_DIST = git-version-gen
EXTRA_DIST = \
.version \
README.md \
contrib/osmo-pcap.spec.in \
debian \
git-version-gen \
$(NULL)
AM_DISTCHECK_CONFIGURE_FLAGS = \
--with-systemdsystemunitdir=$$dc_install_base/$(systemdsystemunitdir)
@RELMAKE@
$(top_srcdir)/.version:
echo $(VERSION) > $@-t && mv $@-t $@
dist-hook:

60
README.md Normal file
View File

@ -0,0 +1,60 @@
# osmo-pcap distributed network capture
osmo-pcap has been created to collect network traces at different nodes
but store them centrally at a dedicated node for further analysis. This
might be needed for auditing, resolving conflicts, post processing or
debugging a distributed system.
The system consists out of the *osmo-pcap-client* to capture traffic at a
host and *osmo-pcap-server* to receive the traffic, store and rotate the
traffic at a centralized server. There is a shell script to compress
and expire old traces.
## osmo-pcap-client
The *osmo-pcap-client* is using libpcap and has a built-in detector for
the GPRS-NS/BSSGP protocol to exclude user traffic. The client is known
to work on 32/64 bit systems. It can be configured through the VTY and
the minimal config includes the interface to monitor, the pcap filter
to use and the server to send it to.
## osmo-pcap-server
The *osmo-pcap-server* will listen for new TCP connections and then will
receive the data from the client if it is coming from a known/good source
IPv4/port. The server is configured to write one file per client and to
change/rotate the file when the link encapsulation is changing. It can
be configured to rotate the file a given time interval and/or if the
filesize is over a threshold.
The osmo-pcap-server comes with a shell script to rotate and compress
old traces. Currently the configuration parameters (age or amount based)
need to be tuned in the script itself.
## Installation and Configuration
There are Debian, Ubuntu, Raspbian packages available via the excellent
[openSUSE Build Service](https://build.opensuse.org/package/show/network:osmocom:nightly/osmo-pcap).
Please see the *contrib/osmo-pcap-server.cfg* and *contrib/osmo-pcap-client.cfg*
file in the repository
## Running tests
In order to run all tests, do the following:
$ ./configure --enable-external-tests
$ make -j5
$ sudo setcap 'CAP_NET_RAW+eip CAP_NET_ADMIN+eip' src/osmo-pcap-client
$ make check
## Wishlist/TODO
- [ ] Add non-blocking TLS (probably GNUtls) support between client and server.
- [ ] Improve the clean-up script, maybe re-write in python with exteral configuration.
- [ ] Add hooks to the server to have an application receive all packages
## Author and License
osmo-pcap has been created by Holger Hans Peter Freyther (holger@freyther.de) and is licensed as AGPLv3+. The author appreciates failure or success reports of using the software.

16
TLS_TODO Normal file
View File

@ -0,0 +1,16 @@
= Goals
Secure communication between client and server. The captured
data might go through different interfaces than the one used
for capturing.
Instead of rolling a custom protocol the idea is to adopt TLS
1.2 to achieve client authentication and ciphering.
Neither the client nor the server should block during the key
exchange. Most TLS implementations do block and this is a problem
for a single threaded server. Ideally the same library is used
in the client and the server.
In practice libraries might block during the handshake and this
is a big deal for the server (other clients block).

23
TODO Normal file
View File

@ -0,0 +1,23 @@
== Todolist for the osmo-pcap system ==
* Have a shared secret between client/server, send the RAND
as part of the link type change... use it to decrypt on the
server.
* Integrate with logrotate, skip the daily rotate in the client,
handle SIGHUP by closing all files... this would be send as
a post rotate command.
* Add the end/quit macros to the configure code to the VTY
configure commands, this is in OpenBSC but deserve to move
to libosmocore or such...
* Add statistics to both the client and the server and make it
available through the VTY code.
* Transport pcaps using TLS and have a non-blocking server.
* Make the max size and rotate file configurable
* Collect BPF statistics and export them using StatsD, make the
StatsD support available in osmo-pcap.

View File

@ -4,23 +4,132 @@ AC_INIT([osmo-pcap],
[openbsc-devel@lists.openbsc.org])
AM_INIT_AUTOMAKE([dist-bzip2])
AC_CONFIG_TESTDIR(tests)
AC_ARG_ENABLE(manuals,
[AS_HELP_STRING(
[--enable-manuals],
[Generate manual PDFs [default=no]],
)],
[osmo_ac_build_manuals=$enableval], [osmo_ac_build_manuals="no"])
AM_CONDITIONAL([BUILD_MANUALS], [test x"$osmo_ac_build_manuals" = x"yes"])
AC_ARG_VAR(OSMO_GSM_MANUALS_DIR, [path to common osmo-gsm-manuals files, overriding pkg-config and "../osmo-gsm-manuals"
fallback])
if test x"$osmo_ac_build_manuals" = x"yes"
then
# Find OSMO_GSM_MANUALS_DIR (env, pkg-conf, fallback)
if test -n "$OSMO_GSM_MANUALS_DIR"; then
echo "checking for OSMO_GSM_MANUALS_DIR... $OSMO_GSM_MANUALS_DIR (from env)"
else
OSMO_GSM_MANUALS_DIR="$($PKG_CONFIG osmo-gsm-manuals --variable=osmogsmmanualsdir 2>/dev/null)"
if test -n "$OSMO_GSM_MANUALS_DIR"; then
echo "checking for OSMO_GSM_MANUALS_DIR... $OSMO_GSM_MANUALS_DIR (from pkg-conf)"
else
OSMO_GSM_MANUALS_DIR="../osmo-gsm-manuals"
echo "checking for OSMO_GSM_MANUALS_DIR... $OSMO_GSM_MANUALS_DIR (fallback)"
fi
fi
if ! test -d "$OSMO_GSM_MANUALS_DIR"; then
AC_MSG_ERROR("OSMO_GSM_MANUALS_DIR does not exist! Install osmo-gsm-manuals or set OSMO_GSM_MANUALS_DIR.")
fi
# Find and run check-depends
CHECK_DEPENDS="$OSMO_GSM_MANUALS_DIR/check-depends.sh"
if ! test -x "$CHECK_DEPENDS"; then
CHECK_DEPENDS="osmo-gsm-manuals-check-depends"
fi
if ! $CHECK_DEPENDS; then
AC_MSG_ERROR("missing dependencies for --enable-manuals")
fi
# Put in Makefile with absolute path
OSMO_GSM_MANUALS_DIR="$(realpath "$OSMO_GSM_MANUALS_DIR")"
AC_SUBST([OSMO_GSM_MANUALS_DIR])
fi
CFLAGS="$CFLAGS -std=gnu11"
dnl kernel style compile messages
m4_ifdef([AM_SILENT_RULES], [AM_SILENT_RULES([yes])])
dnl include release helper
RELMAKE='-include osmo-release.mk'
AC_SUBST([RELMAKE])
dnl checks for programs
AC_PROG_MAKE_SET
AC_PROG_CC
AC_PROG_INSTALL
AC_PROG_RANLIB
dnl checks for libraries
PKG_CHECK_MODULES(LIBOSMOCORE, libosmocore >= 0.3.0)
PKG_CHECK_MODULES(LIBOSMOVTY, libosmovty >= 0.3.0)
dnl check for pkg-config (explained in detail in libosmocore/configure.ac)
AC_PATH_PROG(PKG_CONFIG_INSTALLED, pkg-config, no)
if test "x$PKG_CONFIG_INSTALLED" = "xno"; then
AC_MSG_WARN([You need to install pkg-config])
fi
PKG_PROG_PKG_CONFIG([0.20])
dnl checks for header files
AC_HEADER_STDC
AC_ARG_ENABLE(sanitize,
[AS_HELP_STRING(
[--enable-sanitize],
[Compile with address sanitizer enabled],
)],
[sanitize=$enableval], [sanitize="no"])
if test x"$sanitize" = x"yes"
then
CFLAGS="$CFLAGS -fsanitize=address -fsanitize=undefined"
CPPFLAGS="$CPPFLAGS -fsanitize=address -fsanitize=undefined"
fi
AC_ARG_ENABLE(werror,
[AS_HELP_STRING(
[--enable-werror],
[Turn all compiler warnings into errors, with exceptions:
a) deprecation (allow upstream to mark deprecation without breaking builds);
b) "#warning" pragmas (allow to remind ourselves of errors without breaking builds)
]
)],
[werror=$enableval], [werror="no"])
if test x"$werror" = x"yes"
then
WERROR_FLAGS="-Werror"
WERROR_FLAGS+=" -Wno-error=deprecated -Wno-error=deprecated-declarations"
WERROR_FLAGS+=" -Wno-error=cpp" # "#warning"
CFLAGS="$CFLAGS $WERROR_FLAGS"
CPPFLAGS="$CPPFLAGS $WERROR_FLAGS"
fi
# https://www.freedesktop.org/software/systemd/man/daemon.html
AC_ARG_WITH([systemdsystemunitdir],
[AS_HELP_STRING([--with-systemdsystemunitdir=DIR], [Directory for systemd service files])],,
[with_systemdsystemunitdir=auto])
AS_IF([test "x$with_systemdsystemunitdir" = "xyes" -o "x$with_systemdsystemunitdir" = "xauto"], [
def_systemdsystemunitdir=$($PKG_CONFIG --variable=systemdsystemunitdir systemd)
AS_IF([test "x$def_systemdsystemunitdir" = "x"],
[AS_IF([test "x$with_systemdsystemunitdir" = "xyes"],
[AC_MSG_ERROR([systemd support requested but pkg-config unable to query systemd package])])
with_systemdsystemunitdir=no],
[with_systemdsystemunitdir="$def_systemdsystemunitdir"])])
AS_IF([test "x$with_systemdsystemunitdir" != "xno"],
[AC_SUBST([systemdsystemunitdir], [$with_systemdsystemunitdir])])
AM_CONDITIONAL([HAVE_SYSTEMD], [test "x$with_systemdsystemunitdir" != "xno"])
AC_ARG_ENABLE([external_tests],
AC_HELP_STRING([--enable-external-tests],
[Include the VTY tests in make check [default=no]]),
[enable_ext_tests="$enableval"],[enable_ext_tests="no"])
if test "x$enable_ext_tests" = "xyes" ; then
AM_PATH_PYTHON
AC_CHECK_PROG(OSMOTESTEXT_CHECK,osmotestvty.py,yes)
if test "x$OSMOTESTEXT_CHECK" != "xyes" ; then
AC_MSG_ERROR([Please install osmocom-python to run the VTY tests.])
fi
fi
AC_MSG_CHECKING([whether to enable VTY tests])
AC_MSG_RESULT([$enable_ext_tests])
AM_CONDITIONAL(ENABLE_EXT_TESTS, test "x$enable_ext_tests" = "xyes")
dnl Checks for typedefs, structures and compiler characteristics
AC_ARG_WITH([pcap-config],
@ -31,11 +140,32 @@ if test x$pcapcfg = "x"; then
AC_MSG_ERROR([pcap-config can not be found])
fi
PCAP_LIBS=`$pcapcfg --libs`
PCAP_CFLAGS=`$pcapcfg --cflags`
dnl CentOS 5 and Debian 6.0 do not ship with a pcap-config and we somehow
dnl need to support these versions. Once we drop support for these two distros
dnl the below can be simplified again.
AC_ARG_VAR([PCAP_LIBS], [PCAP library files])
AC_ARG_VAR([PCAP_CFLAGS], [PCAP C compiler flags])
if test "x$ac_cv_env_PCAP_LIBS_set" != "xset"; then
PCAP_LIBS=`$pcapcfg --libs`
fi
if test "x$ac_cv_env_PCAP_CFLAGS_set" != "xset"; then
PCAP_CFLAGS=`$pcapcfg --cflags`
fi
AC_SUBST([PCAP_LIBS])
AC_SUBST([PCAP_CFLAGS])
dnl checks for libraries
PKG_CHECK_MODULES(LIBOSMOCORE, libosmocore >= 1.9.0)
# libosmogb: needed for osmocom/gprs includes
PKG_CHECK_MODULES(LIBOSMOGB, libosmogb >= 1.9.0)
PKG_CHECK_MODULES(LIBOSMOGSM, libosmogsm >= 1.9.0)
PKG_CHECK_MODULES(LIBOSMOVTY, libosmovty >= 1.9.0)
PKG_CHECK_MODULES(LIBZMQ, libzmq >= 3.2.2)
PKG_CHECK_MODULES(LIBGNUTLS, gnutls)
# Coverage build taken from WebKit's configure.in
AC_MSG_CHECKING([whether to enable code coverage support])
AC_ARG_ENABLE(coverage,
@ -57,4 +187,11 @@ AC_OUTPUT(
include/Makefile
include/osmo-pcap/Makefile
src/Makefile
contrib/Makefile
contrib/systemd/Makefile
contrib/osmo-pcap.spec
doc/Makefile
doc/examples/Makefile
doc/manuals/Makefile
tests/Makefile
Makefile)

2
contrib/Makefile.am Normal file
View File

@ -0,0 +1,2 @@
SUBDIRS = systemd
dist_pkgdata_DATA = osmo_pcap_clean_old

62
contrib/jenkins.sh Executable file
View File

@ -0,0 +1,62 @@
#!/usr/bin/env bash
# jenkins build helper script for osmo-pcap. This is how we build on jenkins.osmocom.org
if ! [ -x "$(command -v osmo-build-dep.sh)" ]; then
echo "Error: We need to have scripts/osmo-deps.sh from http://git.osmocom.org/osmo-ci/ in PATH !"
exit 2
fi
set -ex
base="$PWD"
deps="$base/deps"
inst="$deps/install"
export deps inst
osmo-clean-workspace.sh
mkdir "$deps" || true
verify_value_string_arrays_are_terminated.py $(find . -name "*.[hc]")
export PKG_CONFIG_PATH="$inst/lib/pkgconfig:$PKG_CONFIG_PATH"
export LD_LIBRARY_PATH="$inst/lib"
osmo-build-dep.sh libosmocore "" '--disable-doxygen --enable-gnutls'
# Additional configure options and depends
CONFIG=""
if [ "$WITH_MANUALS" = "1" ]; then
osmo-build-dep.sh osmo-gsm-manuals
CONFIG="--enable-manuals"
fi
set +x
echo
echo
echo
echo " =============================== osmo-pcap ==============================="
echo
set -x
cd "$base"
autoreconf --install --force
PCAP_LIBS="-lpcap" PCAP_CFLAGS="" ./configure \
--with-pcap-config=/bin/true \
--enable-sanitize \
--enable-werror \
$CONFIG
$MAKE $PARALLEL_MAKE
$MAKE check || cat-testlogs.sh
DISTCHECK_CONFIGURE_FLAGS="--with-pcap-config=/bin/true $CONFIG" \
PCAP_LIBS="-lpcap" PCAP_CFLAGS="" \
$MAKE distcheck || cat-testlogs.sh
if [ "$WITH_MANUALS" = "1" ] && [ "$PUBLISH" = "1" ]; then
make -C "$base/doc/manuals" publish
fi
$MAKE maintainer-clean
osmo-clean-workspace.sh

88
contrib/osmo-pcap.spec.in Normal file
View File

@ -0,0 +1,88 @@
#
# spec file for package osmo-pcap
#
# Copyright (c) 2015, Martin Hauke <mardnh@gmx.de>
#
# All modifications and additions to the file contributed by third parties
# remain the property of their copyright owners, unless otherwise agreed
# upon. The license for this file, and modifications and additions to the
# file, is the same license as for the pristine package itself (unless the
# license for the pristine package is not an Open Source License, in which
# case the license is the MIT License). An "Open Source License" is a
# license that conforms to the Open Source Definition (Version 1.9)
# published by the Open Source Initiative.
Name: osmo-pcap
Version: @VERSION@
Release: 0
Summary: Osmocom's PCAP client and server
License: AGPL-3.0-or-later AND GPL-2.0-or-later
Group: Productivity/Telephony/Servers
URL: https://osmocom.org/projects/osmo-pcap
Source: %{name}-%{version}.tar.xz
BuildRequires: autoconf
BuildRequires: automake >= 1.6
BuildRequires: libpcap-devel
BuildRequires: libtool
%if 0%{?suse_version}
BuildRequires: systemd-rpm-macros
%endif
BuildRequires: pkgconfig
BuildRequires: pkgconfig(gnutls)
BuildRequires: pkgconfig(libosmocore) >= 1.9.0
BuildRequires: pkgconfig(libosmogb) >= 1.9.0
BuildRequires: pkgconfig(libosmogsm) >= 1.9.0
BuildRequires: pkgconfig(libosmovty) >= 1.9.0
BuildRequires: pkgconfig(libzmq) >= 3.2.2
%{?systemd_requires}
%description
Osmocom tools to help with pcap tracing.
Run osmo_pcap_client locally and send traces to a different system.
%prep
%setup -q
%build
echo "%{version}" >.tarball-version
autoreconf -fi
%configure \
--docdir=%{_docdir}/%{name} \
--with-systemdsystemunitdir=%{_unitdir}
make %{?_smp_mflags}
%install
%make_install
%if 0%{?suse_version}
%preun
%service_del_preun osmo-pcap-client.service osmo-pcap-server.service
%postun
%service_del_postun osmo-pcap-client.service osmo-pcap-server.service
%pre
%service_add_pre osmo-pcap-client.service osmo-pcap-server.service
%post
%service_add_post osmo-pcap-client.service osmo-pcap-server.service
%endif
%check
make %{?_smp_mflags} check || (find . -name testsuite.log -exec cat {} +)
%files
%license COPYING
%doc AUTHORS
%doc %{_docdir}/%{name}/examples
%dir %{_sysconfdir}/osmocom
%config(noreplace) %{_sysconfdir}/osmocom/osmo-pcap-client.cfg
%config(noreplace) %{_sysconfdir}/osmocom/osmo-pcap-server.cfg
%{_bindir}/osmo-pcap-client
%{_bindir}/osmo-pcap-server
%{_unitdir}/osmo-pcap-client.service
%{_unitdir}/osmo-pcap-server.service
%dir %{_datadir}/%{name}
%{_datadir}/%{name}/osmo_pcap_clean_old
%changelog

80
contrib/osmo_pcap_clean_old Executable file
View File

@ -0,0 +1,80 @@
#! /bin/sh
# Script designed to clean up (zip/delete) old files
# Adjust the variables below and then copy/symlink this script
# to /etc/cron/cron.{hourly,daily}
# We want to keep the filenames dated and that confuses logrotate,
# hence this script.
# Method used either AGE or FILES
METHOD="AGE"
# Maximum age of the logs
MAXAGE=120
# Maximum number of logs to keep
MAXFILES=30
# Zip all files after the first n files
ZIPAFTER=3
# Set to 1 for debug output
VERBOSE=0
# Path where the logfiles reside in
BASEPATH="/var/lib/osmo-pcap/"
# Find the client names present in basepath
# Delete files older than MAXAGE days
# Zip all but the first ZIPAFTER files
cd "$BASEPATH"
do_cleanup_age()
{
find . -ctime +$MAXAGE -name "trace-$1-*.pcap*" |sort -r | while read LOG; do
[ $VERBOSE -eq 1 ] && echo "Deleting file \"$LOG\""
rm -f "$LOG"
done
}
do_cleanup_files()
{
i=1
find . -name "trace-$1-*.pcap*" |sort -r | while read LOG; do
if [ $i -gt $MAXFILES ]; then
[ $VERBOSE -eq 1 ] && echo "Deleting file \"$LOG\""
rm -f "$LOG"
fi
i=$(($i+1))
done
}
do_zip()
{
i=1
find . -name "trace-$1-*.pcap*" |sort -r | while read LOG; do
if [ $i -gt $ZIPAFTER ]; then
if [ "${LOG##*.}" != "gz" ]; then
[ $VERBOSE -eq 1 ] && echo "Compressing file \"$LOG\""
gzip "$LOG"
fi
fi
i=$(($i+1))
done
}
# Use an explicit pattern here
find . -name "trace-*.pcap*" |sed -n -e "s/.*trace-\(.\+\)-[0-9]\{8\}_[0-9]\{6\}\.pcap\(\..\+\)\?/\1/p" |sort |uniq | while read CLIENT; do
[ $VERBOSE -eq 1 ] && echo "Cleaning logs for $CLIENT"
if [ "x$METHOD" == "xAGE" ]; then
do_cleanup_age "$CLIENT"
elif [ "x$METHOD" == "xFILES" ]; then
do_cleanup_files "$CLIENT"
else
echo "Error, set METHOD to AGE or FILES"
exit 1
fi
do_zip "$CLIENT"
done

View File

@ -0,0 +1,11 @@
EXTRA_DIST = \
osmo-pcap-client.service \
osmo-pcap-server.service
if HAVE_SYSTEMD
SYSTEMD_SERVICES = \
osmo-pcap-client.service \
osmo-pcap-server.service
systemdsystemunit_DATA = $(SYSTEMD_SERVICES)
endif

View File

@ -0,0 +1,16 @@
[Unit]
Description=PCAP Client for the PCAP aggregation
After=network-online.target
Wants=network-online.target
[Service]
Type=simple
Restart=always
StateDirectory=osmocom
WorkingDirectory=%S/osmocom
ExecStart=/usr/bin/osmo-pcap-client -c /etc/osmocom/osmo-pcap-client.cfg
RestartSec=2
[Install]
WantedBy=multi-user.target

View File

@ -0,0 +1,16 @@
[Unit]
Description=PCAP Server for the PCAP aggregation
After=network-online.target
Wants=network-online.target
[Service]
Type=simple
Restart=always
StateDirectory=osmocom
WorkingDirectory=%S/osmocom
ExecStart=/usr/bin/osmo-pcap-server -c /etc/osmocom/osmo-pcap-server.cfg
RestartSec=2
[Install]
WantedBy=multi-user.target

25
contrib/zmq_recv.go Normal file
View File

@ -0,0 +1,25 @@
package main
import (
"fmt";
"strings";
zmq "github.com/pebbe/zmq4"
)
func main() {
subscriber, _ := zmq.NewSocket(zmq.SUB)
defer subscriber.Close()
subscriber.Connect("tcp://localhost:6666")
subscriber.SetSubscribe("")
for {
msg, _ := subscriber.RecvMessage(0)
if (strings.HasPrefix(msg[0], "event.v1")) {
fmt.Println("Got event message.. %d", len(msg), msg)
} else if (strings.HasPrefix(msg[0], "data.v1")) {
fmt.Println("Got data message.. %d", len(msg), msg)
}
}
}

260
debian/changelog vendored Normal file
View File

@ -0,0 +1,260 @@
osmo-pcap (0.4.2) unstable; urgency=medium
[ arehbein ]
* Transition to use of 'telnet_init_default'
[ Daniel Willmann ]
* osmo_{client,server}_main: Remove tall_ctr_ctx and tall_msgb_ctx
* osmo_{client,server}_main: Remove is_config_node in vty_app_info
* cosmetic: Remove trailing whitespace
[ Pau Espin Pedrol ]
* server: Call osmo_fd_unregister() before closing and changing bfd->fd
[ Max ]
* CI/CD: drop travis support
[ Oliver Smith ]
* debian: set compat level to 10
* systemd: depend on networking-online.target
[ Vadim Yanitskiy ]
* tests: $(BUILT_SOURCES) is not defined
-- Pau Espin Pedrol <pespin@sysmocom.de> Tue, 12 Sep 2023 15:50:49 +0200
osmo-pcap (0.4.1) unstable; urgency=medium
[ Max ]
* Set working directory in systemd service file
[ Vadim Yanitskiy ]
* doc/manuals: update git URLs (git -> https; gitea)
-- Pau Espin Pedrol <pespin@sysmocom.de> Tue, 07 Feb 2023 17:11:46 +0100
osmo-pcap (0.4.0) unstable; urgency=medium
[ Pau Espin Pedrol ]
* client: Increase wqueue transmit length
* client: Log wqueue capacity when failing to enqueue
* client: Add 'wqueue max-length <0-4294967295>' VTY command
* .gitignore: blacklist configure~
[ Harald Welte ]
* update git URLs (git -> https; gitea)
-- Pau Espin Pedrol <pespin@sysmocom.de> Tue, 28 Jun 2022 17:36:44 +0200
osmo-pcap (0.3.0) unstable; urgency=medium
[ Vadim Yanitskiy ]
* debian/control: minimum version for libzmq3-dev is 3.2.2
[ Harald Welte ]
* configure.ac: don't depend on libosmogb.
[ Oliver Smith ]
* Revert "configure.ac: don't depend on libosmogb."
[ Pau Espin Pedrol ]
* server: Add vty command file-permission-mask
-- Pau Espin Pedrol <pespin@sysmocom.de> Thu, 13 Jan 2022 10:06:14 +0100
osmo-pcap (0.2.1) unstable; urgency=medium
[ Pau Espin Pedrol ]
* Use new stat item/ctr getter APIs
* Explicitly depend on required libosmogb
[ Oliver Smith ]
* README.md: fix typo
* Change default ports of client, server
-- Pau Espin Pedrol <pespin@sysmocom.de> Tue, 16 Nov 2021 13:40:07 +0100
osmo-pcap (0.2.0) unstable; urgency=medium
[ Harald Welte ]
* vty: Add space after prompt, as customary
* add "--version" to osmo-pcap-client and -server
* update copyright statement; Holger worked on it until 2017
* Add user manual for osmo-pcap
* use osmo_wqueue_enqueue_quiet() as we log anyway
* client: Ensure the "file" header is sent on connect
* use telnet_init_dynif() to allow VTY bind to non-loopack address
* vty: call telnet_init_dynif() after config file is read
[ Joachim Steiger ]
* manuals: generate VTY reference for osmo-pcap-{client,server}
[ Vadim Yanitskiy ]
* vty: register commands for talloc context introspection
* vty_{client,server}_init(): remove unused argument
* contrib/jenkins.sh: fix: pass '--enable-manuals' to configure
-- Harald Welte <laforge@osmocom.org> Sat, 24 Apr 2021 23:03:34 +0200
osmo-pcap (0.1.3) unstable; urgency=medium
[ Oliver Smith ]
* contrib: import RPM spec
* contrib: integrate RPM spec
* Makefile.am: EXTRA_DIST: debian, contrib/*.spec.in
* configure.ac: set -std=gnu11
[ Harald Welte ]
* Use OSMO_FD_* instead of deprecated BSC_FD_*
* Use osmo_fd_setup() whenever applicable
* Use osmo_fd_*_{disable,enable}
* reformat debian/control for osmo-release.sh compatibility
[ Pau Espin Pedrol ]
* main: generate coredump and exit upon SIGABRT received
-- Pau Espin Pedrol <pespin@espeweb.net> Tue, 23 Feb 2021 13:19:37 +0100
osmo-pcap (0.1.2) unstable; urgency=medium
[ Oliver Smith ]
* Cosmetic: README.md: fix typo
* osmoappdesc.py: fix paths to configs
* Cosmetic: README.md: document how to run tests
* osmoappdesc.py: switch to python 3
-- Pau Espin Pedrol <pespin@sysmocom.de> Thu, 02 Jan 2020 20:19:28 +0100
osmo-pcap (0.1.1) unstable; urgency=medium
* Remove undefined param passed to {logging,osmo_stats}_vty_add_cmds
* Require libosmocore 0.11.0
-- Pau Espin Pedrol <pespin@sysmocom.de> Wed, 07 Aug 2019 13:12:47 +0200
osmo-pcap (0.1.0) unstable; urgency=medium
[ Harald Welte ]
* sock_src_init(): Don't freeaddrinfo() undefined src_result
* Use TCP port numbers for VTY that don't overlap with other Osmocom Software
* Rename osmo_pcap_{client_server} executables to osmo-pcap-{client,server}
* Use libosmocore osmo_sock_init2() instead of local implementation
* client: Move to osmo_sock_init2_ofd()
* Add support for generating IPIP to osmo-pcap-client
* debian/control: Fix URLs for homepage, git, gitweb
* change binary builds URL to network:osmocom as that's more maintained
* Fix compiler warning about deprecated _BSD_SOURCE
[ Max ]
* Add gitreview config
* Use release helper from libosmocore
[ Pau Espin Pedrol ]
* cosmetic: client: rename forward_packet function
* vty: skip installing cmds now always installed by default
* client: Properly name main talloc ctx
* server: Properly name main talloc ctx
* Drop osmo_init_logging and use osmo_init_logging2
* osmo_client_send_data: Fix wrong log format
* configure.ac: Add --enable-werror flag
* configure.ac: Add --enable-sanitize flag
* jenkins.sh: enable werror and sanitize configure flags
* Replace '.' in counter names with ':'
* Use enum for PKT_LINK_*
* client: Set snaplen to MAXIMUM_SNAPLEN
* client: Add pcap snaplen VTY cmd
* client_send_link: snaplen not needed during allocation
* server: Improve verification of messages from client
* server: Add pcap snaplen VTY cmd
* contrib/jenkins.sh: Update to current osmocom infra
* debian: Clean up to look like other osmocom projects
* Install systemd services with autotools
* Install cfg files with autotools
* gitignore: Add compile
* debian: Install osmo_pcap_clean_old in osmo-pcap-server pkg
* tests/Makefile.am: Fix "./configure && make clean && make"
* debian/changelog: Mark 0.0.11 as released
[ Oliver Smith ]
* Fix DISTCHECK_CONFIGURE_FLAGS override
* contrib: fix makedistcheck with disabled systemd
* gitignore: fix application names
* contrib/jenkins.sh: run "make maintainer-clean"
-- Pau Espin Pedrol <pespin@sysmocom.de> Tue, 16 Jul 2019 19:01:15 +0200
osmo-pcap (0.0.11) unstable; urgency=medium
* Add "source ip A.B.C.D" option to use specific address.
* Add osmo-pcap-client-dbg/osmo-pcap-server-dbg package
-- Holger Hans Peter Freyther <holger@moiji-mobile.com> Tue, 17 Jan 2017 09:12:52 +0100
osmo-pcap (0.0.10) unstable; urgency=medium
* New release with new features
* Allow unauthenticated TLS between client and server
* Allow a client to connect to multiple servers at the
same time.
* Allow the server to forward data through ZeroMQ
-- Holger Hans Peter Freyther <holger@moiji-mobile.com> Wed, 09 Nov 2016 02:09:52 +0100
osmo-pcap (0.0.9) unstable; urgency=medium
* Fix pcap packet format for 64bit clients.
-- Holger Hans Peter Freyther <holger@moiji-mobile.com> Thu, 03 Dec 2015 22:17:19 +0100
osmo-pcap (0.0.8) unstable; urgency=medium
* Attempt to work with Jumbo frames up to 9000 bytes
* Fix wording in the server error message
* Install cron.daily job that can be changed by the user (e.g. max age of the files)
-- Holger Hans Peter Freyther <holger@moiji-mobile.com> Thu, 03 Dec 2015 20:41:24 +0100
osmo-pcap (0.0.7) unstable; urgency=medium
* gprs: Do not collect BVC FLOW CONTROL / ACK messages
-- Holger Hans Peter Freyther <holger@moiji-mobile.com> Thu, 19 Nov 2015 11:13:55 +0100
osmo-pcap (0.0.6) unstable; urgency=medium
[ Holger Hans Peter Freyther ]
* debian: Add changelog entry for 0.0.4
* debian: Add a osmo-pcap-client init script
[ Sylvain Munaut ]
* build: Replace deprecated INCLUDES with AM_CPPFLAGS
[ Holger Hans Peter Freyther ]
* gprs: Add a custom GPRS filter
* gprs: Remove left over for counting llc frames
-- Holger Hans Peter Freyther <holger@moiji-mobile.com> Thu, 10 Sep 2015 17:11:32 +0200
osmo-pcap (0.0.5) unstable; urgency=low
* Add init script for the osmo-pcap tool
-- Holger Hans Peter Freyther <holger@moiji-mobile.com> Thu, 10 Sep 2015 17:10:42 +0200
osmo-pcap (0.0.4) unstable; urgency=low
* New upstream version.
-- Holger Hans Peter Freyther <holger@freyther.de> Wed, 07 Nov 2012 10:11:21 +0100
osmo-pcap (0.0.3) unstable; urgency=low
* New upstream version.
-- Holger Hans Peter Freyther <holger@freyther.de> Tue, 06 Nov 2012 23:41:36 +0100
osmo-pcap (0.0.1) unstable; urgency=low
* Initial Release.
-- Holger Hans Peter Freyther <zecke@selfish.org> Wed, 01 Jun 2011 14:51:32 +0200

1
debian/compat vendored Normal file
View File

@ -0,0 +1 @@
10

36
debian/control vendored Normal file
View File

@ -0,0 +1,36 @@
Source: osmo-pcap
Section: net
Priority: extra
Maintainer: Osmocom team <openbsc@lists.osmocom.org>
Build-Depends: debhelper (>= 10),
dh-autoreconf,
autotools-dev,
libpcap0.8-dev,
pkg-config,
libosmocore-dev (>= 1.9.0),
libgnutls28-dev,
libzmq3-dev (>= 3.2.2)
Standards-Version: 3.9.1
Homepage: https://osmocom.org/projects/osmo-pcap
Vcs-Git: https://gitea.osmocom.org/osmocom/osmo-pcap
Vcs-Browser: https://gitea.osmocom.org/osmocom/osmo-pcap
Package: osmo-pcap-client
Architecture: any
Depends: ${shlibs:Depends}, ${misc:Depends}
Description: Run osmo-pcap-client locally and send traces to a different system.
Package: osmo-pcap-server
Architecture: any
Depends: ${shlibs:Depends}, ${misc:Depends}
Description: Collect traces from other systems.
Package: osmo-pcap-client-dbg
Architecture: any
Depends: osmo-pcap-client (= ${binary:Version})
Description: Debug symbols of osmo-pcap-client-dbg
Package: osmo-pcap-server-dbg
Architecture: any
Depends: osmo-pcap-server (= ${binary:Version})
Description: Debug symbols of osmo-pcap-server-dbg

22
debian/copyright vendored Normal file
View File

@ -0,0 +1,22 @@
Format: http://www.debian.org/doc/packaging-manuals/copyright-format/1.0/
Upstream-Name: OsmoPCAP
Source: https://gitea.osmocom.org/osmocom/osmo-pcap
Files: *
Copyright: 2011 Holger Freyther and On-Waves
2018 sysmocom s. f. m. c. GmbH <info@sysmocom.de>
License: AGPL-3+
License: AGPL-3+
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.

5
debian/osmo-pcap-client.install vendored Normal file
View File

@ -0,0 +1,5 @@
etc/osmocom/osmo-pcap-client.cfg
lib/systemd/system/osmo-pcap-client.service
usr/bin/osmo-pcap-client
usr/share/doc/osmo-pcap/examples/osmo-pcap-client/osmo-pcap-client.cfg
usr/share/doc/osmo-pcap/examples/osmo-pcap-client/osmo-pcap-client-tls.cfg

6
debian/osmo-pcap-server.install vendored Normal file
View File

@ -0,0 +1,6 @@
etc/osmocom/osmo-pcap-server.cfg
lib/systemd/system/osmo-pcap-server.service
usr/bin/osmo-pcap-server
usr/share/doc/osmo-pcap/examples/osmo-pcap-server/osmo-pcap-server.cfg
usr/share/doc/osmo-pcap/examples/osmo-pcap-server/osmo-pcap-server-tls.cfg
usr/share/osmo-pcap/osmo_pcap_clean_old

26
debian/rules vendored Executable file
View File

@ -0,0 +1,26 @@
#!/usr/bin/make -f
DEBIAN := $(shell dpkg-parsechangelog | grep ^Version: | cut -d' ' -f2)
DEBVERS := $(shell echo '$(DEBIAN)' | cut -d- -f1)
VERSION := $(shell echo '$(DEBVERS)' | sed -e 's/[+-].*//' -e 's/~//g')
#export DH_VERBOSE=1
export DEB_BUILD_MAINT_OPTIONS = hardening=+all
# Maybe we require some moreadvanced testing in the future
PCAP_CFLAGS="-I/usr/include"
PCAP_LIBS="-lpcap"
%:
dh $@ --with autoreconf --fail-missing
override_dh_auto_configure:
dh_auto_configure -- \
--with-systemdsystemunitdir=/lib/systemd/system \
--with-pcap-config=/bin/false \
PCAP_CFLAGS=$(PCAP_CFLAGS) \
PCAP_LIBS=$(PCAP_LIBS)
override_dh_strip:
dh_strip -posmo-pcap-client --dbg-package=osmo-pcap-client-dbg
dh_strip -posmo-pcap-server --dbg-package=osmo-pcap-server-dbg

1
debian/source/format vendored Normal file
View File

@ -0,0 +1 @@
3.0 (native)

4
doc/Makefile.am Normal file
View File

@ -0,0 +1,4 @@
SUBDIRS = \
examples \
manuals \
$(NULL)

30
doc/examples/Makefile.am Normal file
View File

@ -0,0 +1,30 @@
OSMOCONF_FILES = \
osmo-pcap-client/osmo-pcap-client.cfg \
osmo-pcap-server/osmo-pcap-server.cfg
osmoconfdir = $(sysconfdir)/osmocom
osmoconf_DATA = $(OSMOCONF_FILES)
EXTRA_DIST = $(OSMOCONF_FILES)
CFG_FILES = find $(srcdir) -type f -name '*.cfg*' | sed -e 's,^$(srcdir),,'
dist-hook:
for f in $$($(CFG_FILES)); do \
j="$(distdir)/$$f" && \
mkdir -p "$$(dirname $$j)" && \
$(INSTALL_DATA) $(srcdir)/$$f $$j; \
done
install-data-hook:
for f in $$($(CFG_FILES)); do \
j="$(DESTDIR)$(docdir)/examples/$$f" && \
mkdir -p "$$(dirname $$j)" && \
$(INSTALL_DATA) $(srcdir)/$$f $$j; \
done
uninstall-hook:
@$(PRE_UNINSTALL)
for f in $$($(CFG_FILES)); do \
j="$(DESTDIR)$(docdir)/examples/$$f" && \
$(RM) $$j; \
done

View File

@ -0,0 +1,24 @@
!
! OsmoPCAPClient (UNKNOWN-dirty) configuration saved from vty
!!
!
!
log stderr
logging color 1
logging print category-hex 0
logging print category 1
logging timestamp 0
logging print file basename last
logging print level 1
line vty
no login
!
client
pcap device any
pcap filter host www.google.com
pcap detect-loop 0
server ip 127.0.0.1
server port 6001
enable tls
tls priority NORMAL

View File

@ -0,0 +1,22 @@
!
! OsmoPCAPClient (UNKNOWN-dirty) configuration saved from vty
!!
!
!
log stderr
logging color 1
logging print category-hex 0
logging print category 1
logging timestamp 0
logging print file basename last
logging print level 1
line vty
no login
!
client
pcap device any
pcap filter host www.google.com
pcap detect-loop 0
server ip 127.0.0.1
server port 6001

View File

@ -0,0 +1,32 @@
!
! OsmoPCAPServer (UNKNOWN) configuration saved from vty
!!
!
log stderr
logging color 1
logging print category-hex 0
logging print category 1
logging timestamp 0
logging print file basename last
logging print level 1
logging level all everything
logging level pcap notice
logging level client notice
logging level server notice
logging level vty notice
!
line vty
no login
!
server
base-path /tmp
file-permission-mask 0440
server ip 127.0.0.1
server port 6001
max-file-size 262144000
client zecke1 127.0.0.1
client zecke2 127.0.0.1 store tls
client zecke3 127.0.0.2 no-store tls
client zecke4 127.0.0.3 no-store
enable tls
tls priority SECURE

View File

@ -0,0 +1,27 @@
!
! OsmoPCAPServer (UNKNOWN) configuration saved from vty
!!
!
log stderr
logging color 1
logging print category-hex 0
logging print category 1
logging timestamp 0
logging print file basename last
logging print level 1
logging level all everything
logging level pcap notice
logging level client notice
logging level server notice
logging level vty notice
!
line vty
no login
!
server
base-path /tmp
file-permission-mask 0440
server ip 127.0.0.1
server port 6001
max-file-size 262144000
client zecke 127.0.0.1

18
doc/manuals/Makefile.am Normal file
View File

@ -0,0 +1,18 @@
EXTRA_DIST = osmopcap-usermanual.adoc \
osmopcap-usermanual-docinfo.xml \
chapters \
vty
if BUILD_MANUALS
ASCIIDOC = osmopcap-usermanual.adoc
ASCIIDOC_DEPS = $(srcdir)/chapters/*.adoc
include $(OSMO_GSM_MANUALS_DIR)/build/Makefile.asciidoc.inc
# This is a significantly modified, multi-target adopted copy of
# $(OSMO_GSM_MANUALS_DIR)/build/Makefile.vty-reference.inc
VARIANTS = client server
include $(srcdir)/vty/Makefile.vty-reference.inc
OSMO_REPOSITORY = osmo-pcap
include $(OSMO_GSM_MANUALS_DIR)/build/Makefile.common.inc
endif

View File

@ -0,0 +1,132 @@
== osmo-pcap-client
The osmo-pcap-client program runs at a location of your network
where you would like to record some packets. It captures those
packets (with or without filter) and forwards them to one or multiple
remote servers.
=== Running osmo-pcap-client
==== SYNOPSIS
*osmo-pcap-client* [-D] [-c CFG_FILE] | -h | -V
==== OPTIONS
*-h, --help*::
Print a short help message about the supported options.
*-V, --version*::
Print the compile-time version number of the program.
*-D, --daemonize*::
Fork the process as a daemon into background.
*-c, --config-file 'CONFIGFILE'*::
Specify the file and path name of the configuration file to be
used. If none is specified, use `osmo-pcap-client.cfg` in the current
working directory.
Capturing network packets requires you to be superuser or have the CAP_NET_RAW capability.
There are several options to achieve this:
- start the program as root user (strongly discouraged)
- globally enable the CAP_NET_RAW capability for the program using e.g. the tool `setcap`
- asking `systemd` to start the program with the required capability
NOTE:: This potentially opens a privilege escalation, as `osmo-pcap-client` can be configured
via the VTY interface (telnet) which is by default accessible by any user on the local machine (access to the loopback device). Please make sure to protect access to the VTY interface accordingly.
=== Configuring the packet capture
The VTY configuration node of osmo-pcap-client contains a `client` node,
in which the packet capturing is configured
.osmo-pcap-client VTY configuration for packet capture
----
client
pcap device eth0 <1>
pcap filter udp port 23000 <2>
pcap detect-loop 1 <3>
----
<1> the network device from which to obtain a capture
<2> the libpcap filter string (`udp port 23000` in this example)
<3> instruct osmo-pcap-client to automatically add a filter that prevents capturing
the traffic between osmo-pcap-client and osmo-pcap-server, which would create a loop.
=== Configuring the primary server
.osmo-pcap-client configuration for the primary remote server
----
client
server ip 192.168.11.20 <1>
server port 54321 <2>
source ip 192.168.11.1 <3>
----
<1> IP address of the server to which to send the traces
<2> port number of the server to which to send the traces
<3> local IP address to use when sending traffic to the server
By default, a custom osmo-pcap specific protocol is used to transport
the captured packets from client to server. However, the `protocol`
VTY configuration command can be used to switch to to using a simple `ipip`
encapsulation. `ipip` can be transparently decoded by protocol analysis
tools like wireshark.
=== Configuring additional servers
In some use cases, you may want to send the captured packets to multiple
remote destinations.
The primary and each of the remote destinations each receive a copy
of each captured packet.
.osmo-pcap-client configuration for an additional remote server
----
client
pcap-store-connection my_server <1>
server ip 192.168.11.10 <2>
server port 54321 <3>
source ip 192.168.11.1 <4>
connect <5>
----
<1> a human-readable identifier for this specific connection (`my_server`)
<2> IP address of the server to which to send the traces
<3> port number of the server to which to send the traces
<4> local IP address to use when sending traffic to the server
<5> request connection to the remote server specified in this section
=== Configuring TLS
By default, the captured packets are sent in plain-text without any additional
layer of encryption or authentication. This means that there is no confidentiality,
nor any integrity protection, unless the original captured packet already featured
such properties.
If desired, `osmo-pcap-client` can be configured to use TLS (transport layer security)
on the protocol between client and server.
TLS is configured separately for each remote server, whether primary or additional.
.osmo-pcap-client configuration with TLS
----
client
server ip 192.168.11.20
server port 54321
source ip 192.168.11.1
enable tls <1>
tls hostname pcapserver.example.test<2>
tls verify-cert <3>
tls capath /etc/osmo-pcap/ca-certificates <4>
tls client-cert /etc/osmo-pcap/client.crt <5>
tls client-key /etc/osmo-pcap/client.key <6>
----
<1> enable TLS for this server
<2> set the hostname we expect the server to have a certificate for
<3> enable certificate verification
<4> path of all CA certificates we consider valid for signing the server cert
<5> file containing the client certificate
<6> file containing the private key for the client certificate

View File

@ -0,0 +1,43 @@
[[overview]]
== OsmoPCAP Overview
=== Package Capturing in distributed telecoms networks
Obtaining raw, binary protocol traces [for later analysis] is an
essential capability in order to investigate any kind of problem
in any computer networking system.
The very distributed, heterogenuous nature of cellular networks
(compared to end-to-end IP networks) results in a lot of relevant
information being present only at some specific interfaces / points
in the network. This in turn means that packet captures have to
be performed at a variety of different network elements in order
to get the full picture of what is happening.
Recording protocol traces at various different points in the network
inevitably raises the question of how to aggregate these.
[[about]]
=== About OsmoPCAP
OsmoPCAP is a software suite consisting of two programs, a client and a
server component.
- osmo-pcap-client obtains protocol traces by using AF_PACKET sockets,
optionally with a capture filter. It then forwards the captures to
a remote server.
- osmo-pcap-server accepts incoming connections from clients. It
receives captured packets from those clients and stores them.
The server and client communicate using a custom, TCP based protocol
for passing captured packets from client to server. Based on your
configuration, it can optionally be secured by TLS transport-level
encryption and authentication.
NOTE:: The osmo-pcap programs runs as normal, single-threaded userspace
programs, without any specific emphasis on efficiency. It doesn't use
any of the advanced zero-copy mechanisms available on many modern OSs.
The goal is to capture telecom signaling (control plane) traffic, whose
bandwidth is (unlike that of the user plane) typically relatively low
compared to the available CPU / IO speeds. Don't expect osmo-pcap to
handle wire-rate multi-gigabit throughput.

View File

@ -0,0 +1,90 @@
== osmo-pcap-server
The osmo-pcap-server program can run anywhere in your network, as long
as it can be reached by the remote osmo-pcap-client instances.
=== Running osmo-pcap-server
==== SYNOPSIS
*osmo-pcap-server* [-D] [-c CFG_FILE] | -h | -V
==== OPTIONS
*-h, --help*::
Print a short help message about the supported options.
*-V, --version*::
Print the compile-time version number of the program.
*-D, --daemonize*::
Fork the process as a daemon into background.
*-c, --config-file 'CONFIGFILE'*::
Specify the file and path name of the configuration file to be
used. If none is specified, use `osmo-pcap-client.cfg` in the current
working directory.
As osmo-pcap-server doesn't capture any packets itself and only receives streams of
captured packets from [remote] osmo-pcap-clients, there is no need to run it as root
or with elevated privileges.
=== Configuring osmo-pcap-server
The osmo-pcap-server configuration consists mainly of the following parts:
* the global server configuration, optionally including TLS related settings
* the per-client (per-connection) configuration
.osmo-pcap-server example global configuration
----
server
base-path /var/lib/osmo-pcap-server <1>
server ip 192.168.11.20 <2>
server port 54321 <3>
max-file-size 100000000 <4>
max-snaplen 100000 <5>
----
<1> directory to which the pcap files are stored
<2> IP address to which to bind/listen
<3> TCP port number to which to bind/listen
<4> maximum size for pcap files; create a new file once max-file-size is reached
<5> maximum pcap snapshot length (per packet, in bytes; default: 9000)
The received packets are stored to a pcap file below the `base-path` using a filename
encoding both the client name and the date/time at time of file creation.
.osmo-pcap-server example global configuration
----
server
client foo 192.168.100.1 <1>
client bar 192.168.200.2 tls <2>
----
<1> Client `foo` connects from 192.168.100.1 and uses no TLS
<2> Client `bar` connects from 192.168.2.00.2 and uses TLS
=== Configuring TLS
By default, the captured packets are received in plain-text without any additional
layer of encryption or authentication. This means that there is no confidentiality,
nor any integrity protection, unless the original captured packet already featured
such properties.
If desired, `osmo-pcap-server` can be configured to use TLS (transport layer security)
on the protocol between client and server.
TLS is configured separately for each remote server, whether primary or additional.
NOTE:: osmo-pcap-server uses the gnutls library for TLS support. See its documentation in terms of supported file formats for CRL, certificates, keys, etc.
.osmo-pcap-server configuration with TLS
----
server
tls allow-auth x509 <1>
tls capath /etc/osmocom/osmo-pcap-ca <2>
tls crlfile /etc/osmocom/osmo-pcap-ca.crl <3>
tls server-cert /etc/osmocom/osmo-pcap-server.crt <4>
tls server-key /etc/osmocom/osmo-pcap-server.key <5>
----
<1> require clients to authenticate using a X.509 client certificate
<2> path of all CA certificates we consider valid for signing the client cert
<3> file containing the certificate revocation list
<4> file containing the server certificate
<5> file containing the private key for the server certificate

View File

@ -0,0 +1,47 @@
<revhistory>
<revision>
<revnumber>1</revnumber>
<date>January 4th, 2021</date>
<authorinitials>HW</authorinitials>
<revremark>
Initial version
</revremark>
</revision>
</revhistory>
<authorgroup>
<author>
<firstname>Harald</firstname>
<surname>Welte</surname>
<email>hwelte@sysmocom.de</email>
<authorinitials>HW</authorinitials>
<affiliation>
<shortaffil>sysmocom</shortaffil>
<orgname>sysmocom - s.f.m.c. GmbH</orgname>
<jobtitle>Managing Director</jobtitle>
</affiliation>
</author>
</authorgroup>
<copyright>
<year>2021</year>
<holder>sysmocom - s.f.m.c. GmbH</holder>
</copyright>
<legalnotice>
<para>
Permission is granted to copy, distribute and/or modify this
document under the terms of the GNU Free Documentation License,
Version 1.3 or any later version published by the Free Software
Foundation; with the Invariant Sections being just 'Foreword',
'Acknowledgements' and 'Preface', with no Front-Cover Texts,
and no Back-Cover Texts. A copy of the license is included in
the section entitled "GNU Free Documentation License".
</para>
<para>
The Asciidoc source code of this manual can be found at
<ulink url="https://gitea.osmocom.org/cellular-infrastructure/osmo-gsm-manuals">
https://gitea.osmocom.org/cellular-infrastructure/osmo-gsm-manuals
</ulink>
</para>
</legalnotice>

View File

@ -0,0 +1,32 @@
:gfdl-enabled:
:program-name: OsmoPCAP
OsmoPCAP User Manual
====================
Harald Welte <hwelte@sysmocom.de>
include::./common/chapters/preface.adoc[]
include::{srcdir}/chapters/overview.adoc[]
include::{srcdir}/chapters/client.adoc[]
include::{srcdir}/chapters/server.adoc[]
include::./common/chapters/counters-overview.adoc[]
include::./common/chapters/vty.adoc[]
include::./common/chapters/logging.adoc[]
include::./common/chapters/port_numbers.adoc[]
include::./common/chapters/bibliography.adoc[]
include::./common/chapters/glossary.adoc[]
include::./common/chapters/gfdl.adoc[]

View File

@ -0,0 +1,37 @@
DOCBOOKS = $(foreach v,$(VARIANTS),vty/osmo-pcap-$(v)-vty-reference.xml)
DOCBOOKS_DEPS = $(DOCBOOKS) $(addsuffix .inc,$(DOCBOOKS))
INC_DIR = $(abspath $(builddir)/vty)
include $(OSMO_GSM_MANUALS_DIR)/build/Makefile.docbook.inc
CLEAN_FILES += $(DOCBOOKS_DEPS)
CLEAN_FILES += $(addsuffix .inc.gen,$(DOCBOOKS))
CLEAN_FILES += $(addsuffix .inc.merged,$(DOCBOOKS))
$(INC_DIR):
mkdir -p $@
vty/osmo-pcap-%-vty-reference.xml: $(top_builddir)/src/osmo-pcap-% $(INC_DIR)
sed -e "s|@@GENERATED@@|$@.inc|" \
-e "s|@@VARIANT@@|$(notdir $<)|" \
-e "s|@@REV_NUMBER@@|$(VERSION)|" \
-e "s|@@REV_DATE@@|$(shell date +"%dth %B %Y")|" \
-e "s|@@CR_YEAR@@|$(shell date +"%Y")|" \
$(srcdir)/vty/osmo-pcap-vty-reference.xml > $@
vty/osmo-pcap-%-vty-reference.xml.inc: $(top_builddir)/src/osmo-pcap-% \
$(OSMO_GSM_MANUALS_DIR)/common/vty_additions.xml \
$(OSMO_GSM_MANUALS_DIR)/common/chapters/vty.xml \
$(OSMO_GSM_MANUALS_DIR)/vty_reference.xsl \
$(srcdir)/vty/*.xml $(INC_DIR)
# a) Invoke osmo-pcap-% to generate the list of commands first
$< --vty-ref-mode default --vty-ref-xml > "$@.gen"
# ... filter garbage potentially printed by libraries to stdout
sed -i '/^<vtydoc/,$$!d' "$@.gen"
# b) Merge the result of a) with global and local additions
$(OSMO_GSM_MANUALS_DIR)/build/vty_reference_combine.sh \
$(realpath $(OSMO_GSM_MANUALS_DIR)/merge_doc.xsl) "$@.gen" \
$(OSMO_GSM_MANUALS_DIR)/common/vty_additions.xml \
$(srcdir)/vty/vty_additions.xml > "$@.merged"
# c) Convert the result of b) into a valid docbook
xsltproc $(OSMO_GSM_MANUALS_DIR)/vty_reference.xsl "$@.merged" > $@

View File

@ -0,0 +1,35 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE book PUBLIC "-//OASIS//DTD DocBook XML 5.0//EN"
"http://docbook.org/xml/5.0/dtd/docbook.dtd" [
<!ENTITY chapter-vty SYSTEM "./common/chapters/vty.xml" >
<!ENTITY sections-vty SYSTEM "@@GENERATED@@" >
]>
<book>
<info>
<revhistory>
<revision>
<revnumber>v1</revnumber>
<date>@@REV_DATE@@</date>
<authorinitials>s.f.m.c.</authorinitials>
<revremark>Automatic build (@@REV_NUMBER@@)</revremark>
</revision>
</revhistory>
<title>OsmoPCAP VTY Reference</title>
<subtitle>@@VARIANT@@</subtitle>
<copyright>
<year>@@CR_YEAR@@</year>
</copyright>
<legalnotice>
<para>This work is copyright by <orgname>sysmocom - s.f.m.c. GmbH</orgname>. All rights reserved.
</para>
</legalnotice>
</info>
<!-- Main chapters-->
&chapter-vty;
</book>

View File

@ -0,0 +1,2 @@
<vtydoc xmlns='urn:osmocom:xml:libosmocore:vty:doc:1.0'>
</vtydoc>

76
doc/tls.txt Normal file
View File

@ -0,0 +1,76 @@
TLS support
===========
Protect forwarded PCAP packet against eave-dropping by using
TLS between client and server.
Anonymous TLS
^^^^^^^^^^^^^
The minimal configuration will use TLS with perfect forward
secrecy but not use X509 certificates. This means a client
will not know if it connects to the intended server but an
attacker listening will not be able to determine the content
of the messages.
Client::
---
enable tls
tls dh generate
tls priority NORMAL:-VERS-SSL3.0:-VERS-TLS1.0:-VERS-TLS1.1:+ANON-ECDH:+ANON-DH
----
Server::
----
enable tls
tls dh generate
tls allow-auth anonymous
----
Authenticate Server
^^^^^^^^^^^^^^^^^^^
This will use x509 certificates and allows a client to verify
it connects to a server with the right credentials. This will
protect messages against eaves-dropping and sending data to the
wrong system.
Client::
----
enable tls
tls verify-cert
tls capath /etc/osmocom/ca.pem
----
Server::
----
enable tls
tls allow-auth x509
tls capath /etc/osmocom/ca.pem
tls crlfile /etc/osmocom/server.crl
tls server-cert /etc/osmocom/server.crt
tls server-key /etc/osmosomc/server.key
client NAME IP store tls
----
Client certificate
^^^^^^^^^^^^^^^^^^
Currently this is not implemented. In the future a client
can be authenticated based on the SN/CN of a certificate.
Debugging
=========
GNUtls debugging can be enabled by setting the TLS debug
region to debug and then setting the _tls loglevel N_. The
setting will be applied on the next connection using TLS.
----
logging level tls debug
tls loglevel 9

41
doc/zmq_data.txt Normal file
View File

@ -0,0 +1,41 @@
ZeroMQ data protocol v1
=======================
The osmo-pcap-server can be configured to publish PCAP data to
zero to many subscribers. The following document describes the
data format used.
Multiple clients might be connected to the osmo-pcap-server and
use different link headers depending on the underlying device
data is being captured from.
The messages published are in two categories. These are client
events and client data. Client events are generated on connect,
disconnect, link type change and client data is sent for each
frame.
Client Events
^^^^^^^^^^^^^
A multi-part message with event.v1.<EVENT_NAME>.<CLIENT_NAME>
as the first part followed by textual data will be generated.
<CLIENT_NAME> is the configured name and <EVENT_NAME> can be
any of:
* connect
* disconnect
* closingtracefile
It might contain more information, such as the filename of the
tracefile that was closed. There is no guarantee for the order
and amount of connect/disconnect messages.
Client Data
^^^^^^^^^^^
A multi-part message with data.v1.<CLIENT_NAME> to allow to
filter for data and a specific client if wanted.
It is followed by the pcap_file_header structure as the second
part and then the data as third part.

View File

@ -92,7 +92,7 @@ fi
if test -n "$v"
then
: # use $v
elif test -d ./../.git \
elif test -d ./.git \
&& v=`git describe --abbrev=4 --match='v*' HEAD 2>/dev/null \
|| git describe --abbrev=4 HEAD 2>/dev/null` \
&& case $v in

View File

@ -1 +1 @@
noinst_HEADERS = common.h
noinst_HEADERS = common.h osmo_pcap_client.h osmo_pcap_server.h wireformat.h osmo_tls.h

View File

@ -1,7 +1,7 @@
/*
* osmo-pcap common
*
* (C) 2011 by Holger Hans Peter Freyther <zecke@selfish.org>
* (C) 2011-2016 by Holger Hans Peter Freyther
* (C) 2011 by On-Waves
* All Rights Reserved
*
@ -28,23 +28,41 @@
#include <osmocom/vty/vty.h>
#include <osmocom/vty/buffer.h>
#include <osmocom/vty/command.h>
#include <osmocom/vty/ports.h>
/* support old versions of libosmocore */
#ifndef OSMO_VTY_PORT_PCAP_CLIENT
#define OSMO_VTY_PORT_PCAP_CLIENT 4227
#endif
#ifndef OSMO_VTY_PORT_PCAP_SERVER
#define OSMO_VTY_PORT_PCAP_SERVER 4228
#endif
enum {
DPCAP,
DCLIENT,
DSERVER,
DVTY,
DTLS,
Debug_LastEntry,
};
enum {
CLIENT_NODE = _LAST_OSMOVTY_NODE + 1,
SERVER_NODE,
CLIENT_SERVER_NODE,
};
extern const struct log_info log_info;
extern const char *osmopcap_copyright;
extern enum node_type osmopcap_go_parent(struct vty *vty);
extern int osmopcap_go_parent(struct vty *vty);
extern int osmopcap_is_config_node(struct vty *vty, int node);
/* defined in libpcap's pcap-int.h, which is not public */
#ifndef MAXIMUM_SNAPLEN
#define MAXIMUM_SNAPLEN 262144
#endif
#define DEFAULT_SNAPLEN 9000
#endif

View File

@ -1,7 +1,7 @@
/*
* osmo-pcap-client code
*
* (C) 2011 by Holger Hans Peter Freyther <zecke@selfish.org>
* (C) 2011-2016 by Holger Hans Peter Freyther <holger@moiji-mobile.com>
* (C) 2011 by On-Waves
* All Rights Reserved
*
@ -20,38 +20,110 @@
*
*/
#include "osmo_tls.h"
#include <inttypes.h>
#include <pcap.h>
#include <osmocom/core/linuxlist.h>
#include <osmocom/core/select.h>
#include <osmocom/core/timer.h>
#include <osmocom/core/write_queue.h>
struct rate_ctr_group;
#define WQUEUE_MAXLEN_DEFAULT 1000
enum {
CLIENT_CTR_CONNECT,
CLIENT_CTR_BYTES,
CLIENT_CTR_PKTS,
CLIENT_CTR_2BIG,
CLIENT_CTR_NOMEM,
CLIENT_CTR_QERR,
CLIENT_CTR_PERR,
CLIENT_CTR_WERR,
CLIENT_CTR_P_RECV,
CLIENT_CTR_P_DROP,
CLIENT_CTR_P_IFDROP,
};
enum osmo_pcap_protocol {
PROTOCOL_OSMOPCAP,
PROTOCOL_IPIP,
};
struct osmo_pcap_client_conn {
struct llist_head entry;
const char *name;
char *srv_ip;
int srv_port;
char *source_ip;
struct osmo_wqueue wqueue;
struct osmo_timer_list timer;
enum osmo_pcap_protocol protocol;
/* TLS handling */
bool tls_on;
bool tls_verify;
char *tls_hostname;
char *tls_capath;
char *tls_priority;
char *tls_client_cert;
char *tls_client_key;
unsigned tls_log_level;
struct osmo_tls_session tls_session;
/* back pointer */
struct osmo_pcap_client *client;
};
struct osmo_pcap_client {
char *device;
pcap_t *handle;
char errbuf[PCAP_ERRBUF_SIZE];
u_int last_ps_recv;
u_int last_ps_drop;
u_int last_ps_ifdrop;
struct osmo_timer_list pcap_stat_timer;
struct bpf_program bpf;
char *filter_string;
int filter_itself;
int gprs_filtering;
int snaplen;
struct osmo_fd fd;
char *srv_ip;
int srv_port;
struct osmo_wqueue wqueue;
struct osmo_timer_list timer;
struct osmo_pcap_client_conn conn;
struct llist_head conns;
/* statistics */
struct rate_ctr_group *ctrg;
};
extern struct osmo_pcap_client *pcap_client;
int vty_client_init(struct osmo_pcap_client *);
struct osmo_pcap_client *osmo_pcap_client_alloc(void *tall_ctx);
int vty_client_init(void);
int osmo_client_capture(struct osmo_pcap_client *client, const char *device);
int osmo_client_filter(struct osmo_pcap_client *client, const char *filter);
void osmo_client_send_data(struct osmo_pcap_client *client,
void osmo_client_send_data(struct osmo_pcap_client_conn *client,
struct pcap_pkthdr *hdr, const uint8_t *data);
void osmo_client_send_link(struct osmo_pcap_client *client);
void osmo_client_connect(struct osmo_pcap_client *);
void osmo_client_send_link(struct osmo_pcap_client_conn *client);
void osmo_client_connect(struct osmo_pcap_client_conn *);
void osmo_client_disconnect(struct osmo_pcap_client_conn *);
void osmo_client_free(struct osmo_pcap_client_conn *);
void osmo_client_reconnect(struct osmo_pcap_client_conn *);
struct osmo_pcap_client_conn *osmo_client_find_or_create_conn(struct osmo_pcap_client *, const char *name);
struct osmo_pcap_client_conn *osmo_client_find_conn(struct osmo_pcap_client *, const char *name);
void osmo_client_conn_init(struct osmo_pcap_client_conn *conn, struct osmo_pcap_client *client);

View File

@ -1,7 +1,7 @@
/*
* osmo-pcap-server code
*
* (C) 2011 by Holger Hans Peter Freyther <zecke@selfish.org>
* (C) 2011-2016 by Holger Hans Peter Freyther <holger@moiji-mobile.com>
* (C) 2011 by On-Waves
* All Rights Reserved
*
@ -23,8 +23,12 @@
#ifndef OSMO_PCAP_SERVER_H
#define OSMO_PCAP_SERVER_H
#include "wireformat.h"
#include "osmo_tls.h"
#include <osmocom/core/select.h>
#include <osmocom/core/linuxlist.h>
#include <osmocom/core/write_queue.h>
#include <sys/socket.h>
#include <netinet/in.h>
@ -32,10 +36,33 @@
#include <pcap.h>
#include <stdbool.h>
#include <time.h>
struct rate_ctr_group;
struct rate_ctr_group_desc;
struct osmo_pcap_server;
#define STATE_INITIAL 0
#define STATE_DATA 1
enum {
PEER_CTR_CONNECT,
PEER_CTR_BYTES,
PEER_CTR_PKTS,
PEER_CTR_PROTATE,
};
enum {
SERVER_CTR_CONNECT,
SERVER_CTR_BYTES,
SERVER_CTR_PKTS,
SERVER_CTR_PROTATE,
SERVER_CTR_NOCLIENT,
};
struct osmo_pcap_conn {
/* list of connections */
struct llist_head entry;
@ -44,17 +71,34 @@ struct osmo_pcap_conn {
/* name */
char *name;
char *remote_host;
int no_store;
struct in_addr remote_addr;
/* Remote connection */
struct osmo_fd rem_fd;
struct osmo_wqueue rem_wq;
int local_fd;
char *curr_filename;
/* pcap stuff */
struct pcap_file_header file_hdr;
/* last time */
struct tm last_write;
/* read buffering */
int state;
int pend;
int reopen;
struct osmo_pcap_data *data;
/* statistics */
struct rate_ctr_group *ctrg;
/* tls */
bool tls_use;
bool direct_read;
size_t tls_limit_read;
struct osmo_tls_session tls_session;
};
struct osmo_pcap_server {
@ -64,16 +108,45 @@ struct osmo_pcap_server {
char *addr;
struct osmo_fd listen_fd;
/* zeromq handling */
int zmq_port;
char *zmq_ip;
void *zmq_ctx;
void *zmq_publ;
/* tls base */
bool tls_on;
bool tls_allow_anon;
bool tls_allow_x509;
unsigned tls_log_level;
char *tls_priority;
char *tls_capath;
char *tls_crlfile;
char *tls_server_cert;
char *tls_server_key;
char *tls_dh_pkcs3;
gnutls_dh_params_t dh_params;
bool dh_params_allocated;
char *base_path;
mode_t permission_mask;
off_t max_size;
int max_snaplen;
/* statistics */
struct rate_ctr_group *ctrg;
};
extern struct osmo_pcap_server *pcap_server;
extern const struct rate_ctr_group_desc pcap_peer_group_desc;
void osmo_pcap_server_reopen(struct osmo_pcap_server *server);
int osmo_pcap_server_listen(struct osmo_pcap_server *server);
struct osmo_pcap_conn *osmo_pcap_server_find(struct osmo_pcap_server *ser,
const char *name);
void osmo_pcap_server_delete(struct osmo_pcap_conn *conn);
void vty_server_init(struct osmo_pcap_server *server);
void vty_server_init(void);
void osmo_pcap_server_close_trace(struct osmo_pcap_conn *conn);
void osmo_pcap_server_close_conn(struct osmo_pcap_conn *conn);
#endif

View File

@ -0,0 +1,80 @@
/*
* osmo-pcap TLS code
*
* (C) 2016 by Holger Hans Peter Freyther <holger@moiji-mobile.com>
* All Rights Reserved
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
#pragma once
#include <gnutls/gnutls.h>
#include <gnutls/abstract.h>
#include <stdbool.h>
#include <stdint.h>
struct osmo_fd;
struct osmo_wqueue;
struct osmo_pcap_client_conn;
struct osmo_pcap_conn;
struct osmo_pcap_server;
struct osmo_tls_session {
bool in_use;
bool need_handshake;
bool need_resend;
gnutls_session_t session;
/* any credentials */
bool anon_alloc;
gnutls_anon_client_credentials_t anon_cred;
bool anon_serv_alloc;
gnutls_anon_server_credentials_t anon_serv_cred;
/* a x509 cert credential */
bool cert_alloc;
gnutls_certificate_credentials_t cert_cred;
/* the private certificate */
bool pcert_alloc;
gnutls_pcert_st pcert;
/* the private key in _RAM_ */
bool privk_alloc;
gnutls_privkey_t privk;
struct osmo_wqueue *wqueue;
int (*read)(struct osmo_tls_session *session);
void (*error)(struct osmo_tls_session *session);
void (*handshake_done)(struct osmo_tls_session *session);
};
void osmo_tls_init(void);
bool osmo_tls_init_client_session(struct osmo_pcap_client_conn *conn);
bool osmo_tls_init_server_session(struct osmo_pcap_conn *conn, struct osmo_pcap_server *server);
void osmo_tls_release(struct osmo_tls_session *);
int osmo_tls_client_bfd_cb(struct osmo_fd *fd, unsigned int what);
size_t osmo_tls_pending(struct osmo_tls_session *session);
void osmo_tls_server_init(struct osmo_pcap_server *server);
void osmo_tls_dh_load(struct osmo_pcap_server *server);
void osmo_tls_dh_generate(struct osmo_pcap_server *server);

View File

@ -26,21 +26,28 @@
#include <inttypes.h>
#include <pcap.h>
/*
* Should send an entire pcap header
*/
#define PKT_LINK_HDR 0
/*
* Should send one packet...
*/
#define PKT_LINK_DATA 1
enum OsmoPcapDataType {
PKT_LINK_HDR, /* Should send an entire pcap header */
PKT_LINK_DATA /* Should send one packet */
};
struct osmo_pcap_data {
uint8_t type;
uint8_t spare[3];
uint32_t len;
uint8_t spare;
uint16_t len;
uint8_t data[0];
} __attribute__((packed));
/**
* struct timeval is not the same across different
* architectures and for the external format it must
* be a 32bit value. We have a 2038 issue here?
*/
struct osmo_pcap_pkthdr {
uint32_t ts_sec;
uint32_t ts_usec;
uint32_t caplen;
uint32_t len;
} __attribute__((packed));
#endif

32
osmoappdesc.py Normal file
View File

@ -0,0 +1,32 @@
#!/usr/bin/env python3
# (C) 2016 by Holger Hans Peter Freyther
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
app_configs = {
"osmo-pcap-client": ["doc/examples/osmo-pcap-client/osmo-pcap-client.cfg",
"doc/examples/osmo-pcap-client/osmo-pcap-client-tls.cfg"],
"osmo-pcap-server": ["doc/examples/osmo-pcap-server/osmo-pcap-server.cfg",
"doc/examples/osmo-pcap-server/osmo-pcap-server-tls.cfg"]
}
apps = [
(4228, "src/osmo-pcap-server", "OsmoPCAPServer", "osmo-pcap-server"),
(4227, "src/osmo-pcap-client", "OsmoPCAPClient", "osmo-pcap-client"),
]
vty_command = ["src/osmo-pcap-server", "-c", "doc/examples/osmo-pcap-server/osmo-pcap-server.cfg"]
vty_app = apps[0]

View File

@ -1,13 +1,16 @@
INCLUDES = $(all_includes) -I$(top_srcdir)/include -I$(top_builddir)/
AM_CFLAGS = -Wall $(LIBOSMOCORE_CFLAGS) $(LIBOSMOVTY_CFLAGS) $(PCAP_CFLAGS)
AM_LDFLAGS = $(LIBOSMOCORE_LIBS) $(LIBOSMOVTY_LIBS)
AM_CPPFLAGS = $(all_includes) -I$(top_srcdir)/include -I$(top_builddir)/
AM_CFLAGS = -Wall $(LIBOSMOCORE_CFLAGS) $(LIBOSMOGSM_CFLAGS) $(LIBOSMOGB_CFLAGS) $(LIBOSMOVTY_CFLAGS) $(PCAP_CFLAGS) $(LIBGNUTLS_CFLAGS)
bin_PROGRAMS = osmo_pcap_client osmo_pcap_server
bin_PROGRAMS = osmo-pcap-client osmo-pcap-server
osmo_pcap_client_SOURCES = osmo_client_main.c osmo_common.c \
osmo_client_core.c osmo_client_vty.c \
osmo_client_network.c
osmo_pcap_client_LDADD = $(PCAP_LIBS)
osmo_client_network.c osmo_tls.c
osmo_pcap_client_LDADD = $(PCAP_LIBS) $(LIBOSMOCORE_LIBS) $(LIBOSMOVTY_LIBS) \
$(LIBOSMOGSM_LIBS) $(LIBGNUTLS_LIBS)
osmo_pcap_server_SOURCES = osmo_server_main.c osmo_common.c \
osmo_server_vty.c osmo_server_network.c
osmo_server_vty.c osmo_server_network.c \
osmo_tls.c
osmo_pcap_server_LDADD = $(LIBOSMOCORE_LIBS) $(LIBOSMOVTY_LIBS) $(LIBZMQ_LIBS) \
$(LIBGNUTLS_LIBS)

View File

@ -1,7 +1,7 @@
/*
* osmo-pcap-client code
*
* (C) 2011 by Holger Hans Peter Freyther <zecke@selfish.org>
* (C) 2011-2016 by Holger Hans Peter Freyther <holger@moiji-mobile.com>
* (C) 2011 by On-Waves
* All Rights Reserved
*
@ -20,28 +20,210 @@
*
*/
#define _DEFAULT_SOURCE
#include <osmo-pcap/osmo_pcap_client.h>
#include <osmo-pcap/common.h>
#include <osmocom/gprs/gprs_bssgp.h>
#include <osmocom/gprs/protocol/gsm_08_16.h>
#include <osmocom/gprs/protocol/gsm_08_18.h>
#include <osmocom/core/rate_ctr.h>
#include <osmocom/core/talloc.h>
#include <netinet/in.h>
#include <netinet/ip.h>
#include <netinet/udp.h>
#include <limits.h>
#ifndef PCAP_NETMASK_UNKNOWN
#define PCAP_NETMASK_UNKNOWN 0xffffffff
#endif
#define IP_LEN sizeof(struct ip)
#define UDP_LEN sizeof(struct udphdr)
#define NS_LEN 1
static int check_gprs(const u_char *data, bpf_u_int32 len)
{
struct tlv_parsed tp;
struct gprs_ns_hdr *hdr = (struct gprs_ns_hdr *) data;
struct bssgp_ud_hdr *bssgp_hdr;
uint8_t llc_sapi;
switch (hdr->pdu_type) {
case NS_PDUT_UNITDATA:
break;
default:
return 1;
}
len -= sizeof(*hdr);
/* NS_PDUT_UNITDATA from here.. */
/* skip NS SDU control bits and BVCI */
if (len < 3)
return 1;
len -= 3;
/* Check if the BSSGP UD hdr fits */
if (len < sizeof(*bssgp_hdr))
return 1;
bssgp_hdr = (struct bssgp_ud_hdr *) &hdr->data[3];
/* BVC flow control is creating too much noise. Drop it */
if (bssgp_hdr->pdu_type == BSSGP_PDUT_FLOW_CONTROL_BVC
|| bssgp_hdr->pdu_type == BSSGP_PDUT_FLOW_CONTROL_BVC_ACK)
return 0;
/* We only need to check UL/DL messages for the sapi */
if (bssgp_hdr->pdu_type != BSSGP_PDUT_DL_UNITDATA
&& bssgp_hdr->pdu_type != BSSGP_PDUT_UL_UNITDATA)
return 1;
len -= sizeof(*bssgp_hdr);
/* now parse the rest of the IEs */
memset(&tp, 0, sizeof(tp));
if (bssgp_tlv_parse(&tp, &bssgp_hdr->data[0], len) < 0)
return 1;
if (!TLVP_PRESENT(&tp, BSSGP_IE_LLC_PDU))
return 1;
if (TLVP_LEN(&tp, BSSGP_IE_LLC_PDU) < 1)
return 1;
llc_sapi = TLVP_VAL(&tp, BSSGP_IE_LLC_PDU)[0] & 0x0f;
/* Skip user data 3, 5, 9, 11 */
if (llc_sapi == 3 || llc_sapi == 5 || llc_sapi == 9 || llc_sapi == 11)
return 0;
return 1;
}
static int can_forward_packet(
struct osmo_pcap_client *client,
struct pcap_pkthdr *hdr,
const u_char *data)
{
int ll_type;
int offset;
struct ip *ip_hdr;
const u_char *ip_data;
const u_char *udp_data;
const u_char *payload_data;
bpf_u_int32 payload_len;
if (!client->gprs_filtering)
return 1;
ll_type = pcap_datalink(client->handle);
switch (ll_type) {
case DLT_EN10MB:
offset = 14;
break;
case DLT_LINUX_SLL:
offset = 16;
break;
default:
LOGP(DCLIENT, LOGL_ERROR, "LL type %d/%s not handled.\n",
ll_type, pcap_datalink_val_to_name(ll_type));
return 1;
}
/* Check if this can be a full UDP frame with NS */
if (offset + IP_LEN + UDP_LEN + NS_LEN > hdr->caplen)
return 1;
ip_data = data + offset;
ip_hdr = (struct ip *) ip_data;
/* Only handle IPv4 */
if (ip_hdr->ip_v != 4)
return 1;
/* Only handle UDP */
if (ip_hdr->ip_p != 17)
return 1;
udp_data = ip_data + IP_LEN;
payload_data = udp_data + UDP_LEN;
payload_len = hdr->caplen - offset - IP_LEN - UDP_LEN;
return check_gprs(payload_data, payload_len);
}
static int pcap_read_cb(struct osmo_fd *fd, unsigned int what)
{
struct osmo_pcap_client *client = fd->data;
struct osmo_pcap_client_conn *conn;
struct pcap_pkthdr hdr;
const u_char *data;
data = pcap_next(client->handle, &hdr);
if (!data)
if (!data) {
rate_ctr_inc(rate_ctr_group_get_ctr(client->ctrg, CLIENT_CTR_PERR));
return -1;
}
osmo_client_send_data(client, &hdr, data);
if (!can_forward_packet(client, &hdr, data))
return 0;
osmo_client_send_data(&client->conn, &hdr, data);
llist_for_each_entry(conn, &client->conns, entry)
osmo_client_send_data(conn, &hdr, data);
return 0;
}
static inline u_int P_CAP_UINT_MAX()
{
u_int val = 0;
return ~val;
}
static void add_psbl_wrapped_ctr(struct osmo_pcap_client *client,
u_int *old_val, u_int new_val, int ctr)
{
/*
* Wrapped..
* So let's at from N to XYZ_MAX
* and then from 0 to new_val
* Only issue is we don't know sizeof(u_int)
*/
if (*old_val > new_val) {
rate_ctr_add(rate_ctr_group_get_ctr(client->ctrg, ctr), P_CAP_UINT_MAX() - *old_val);
rate_ctr_add(rate_ctr_group_get_ctr(client->ctrg, ctr), new_val);
*old_val = new_val;
return;
}
/* Just increment it */
rate_ctr_add(rate_ctr_group_get_ctr(client->ctrg, ctr), new_val - *old_val);
*old_val = new_val;
}
static void pcap_check_stats_cb(void *_client)
{
struct pcap_stat stat;
struct osmo_pcap_client *client = _client;
int rc;
/* reschedule */
osmo_timer_schedule(&client->pcap_stat_timer, 10, 0);
memset(&stat, 0, sizeof(stat));
rc = pcap_stats(client->handle, &stat);
if (rc != 0) {
LOGP(DCLIENT, LOGL_ERROR, "Failed to query pcap stats: %s\n",
pcap_geterr(client->handle));
rate_ctr_inc(rate_ctr_group_get_ctr(client->ctrg, CLIENT_CTR_PERR));
return;
}
add_psbl_wrapped_ctr(client, &client->last_ps_recv, stat.ps_recv, CLIENT_CTR_P_RECV);
add_psbl_wrapped_ctr(client, &client->last_ps_drop, stat.ps_drop, CLIENT_CTR_P_DROP);
add_psbl_wrapped_ctr(client, &client->last_ps_ifdrop, stat.ps_ifdrop, CLIENT_CTR_P_IFDROP);
}
static int osmo_install_filter(struct osmo_pcap_client *client)
{
int rc;
@ -81,29 +263,33 @@ static void free_all(struct osmo_pcap_client *client)
pcap_freecode(&client->bpf);
if (client->fd.fd != -1) {
if (client->fd.fd >= 0) {
osmo_fd_unregister(&client->fd);
client->fd.fd = -1;
}
pcap_close(client->handle);
osmo_timer_del(&client->pcap_stat_timer);
client->handle = NULL;
}
int osmo_client_capture(struct osmo_pcap_client *client, const char *device)
{
struct osmo_pcap_client_conn *conn;
int fd;
talloc_free(client->device);
free_all(client);
client->device = talloc_strdup(client, device);
if (!client) {
if (!client->device) {
LOGP(DCLIENT, LOGL_ERROR, "Failed to copy string.\n");
return 1;
}
client->handle = pcap_open_live(client->device, 2000, 0,
LOGP(DCLIENT, LOGL_INFO, "Opening device %s for capture with snaplen %zu\n",
client->device, (size_t) client->snaplen);
client->handle = pcap_open_live(client->device, client->snaplen, 0,
1000, client->errbuf);
if (!client->handle) {
LOGP(DCLIENT, LOGL_ERROR,
@ -119,10 +305,7 @@ int osmo_client_capture(struct osmo_pcap_client *client, const char *device)
return 3;
}
client->fd.fd = fd;
client->fd.when = BSC_FD_READ;
client->fd.cb = pcap_read_cb;
client->fd.data = client;
osmo_fd_setup(&client->fd, fd, OSMO_FD_READ, pcap_read_cb, client, 0);
if (osmo_fd_register(&client->fd) != 0) {
LOGP(DCLIENT, LOGL_ERROR,
"Failed to register the fd.\n");
@ -131,7 +314,13 @@ int osmo_client_capture(struct osmo_pcap_client *client, const char *device)
return 4;
}
osmo_client_send_link(client);
client->pcap_stat_timer.data = client;
client->pcap_stat_timer.cb = pcap_check_stats_cb;
pcap_check_stats_cb(client);
osmo_client_send_link(&client->conn);
llist_for_each_entry(conn, &client->conns, entry)
osmo_client_send_link(conn);
if (client->filter_string) {
osmo_install_filter(client);
@ -146,3 +335,69 @@ int osmo_client_filter(struct osmo_pcap_client *client, const char *filter)
client->filter_string = talloc_strdup(client, filter);
return osmo_install_filter(client);
}
void osmo_client_conn_init(struct osmo_pcap_client_conn *conn,
struct osmo_pcap_client *client)
{
conn->client = client;
conn->tls_verify = true;
osmo_wqueue_init(&conn->wqueue, WQUEUE_MAXLEN_DEFAULT);
conn->wqueue.bfd.fd = -1;
}
struct osmo_pcap_client *osmo_pcap_client_alloc(void *tall_ctx)
{
struct osmo_pcap_client *client;
client = talloc_zero(tall_ctx, struct osmo_pcap_client);
if (!client)
return NULL;
client->fd.fd = -1;
client->snaplen = DEFAULT_SNAPLEN;
return client;
}
void osmo_client_free(struct osmo_pcap_client_conn *conn)
{
osmo_client_disconnect(conn);
llist_del(&conn->entry);
talloc_free(conn);
}
struct osmo_pcap_client_conn *osmo_client_find_conn(
struct osmo_pcap_client *client,
const char *name)
{
struct osmo_pcap_client_conn *conn;
llist_for_each_entry(conn, &client->conns, entry)
if (strcmp(conn->name, name) == 0)
return conn;
return NULL;
}
struct osmo_pcap_client_conn *osmo_client_find_or_create_conn(
struct osmo_pcap_client *client,
const char *name)
{
struct osmo_pcap_client_conn *conn = osmo_client_find_conn(client, name);;
if (conn)
return conn;
conn = talloc_zero(client, struct osmo_pcap_client_conn);
if (!conn) {
LOGP(DCLIENT, LOGL_ERROR, "Failed to allocate conn for %s\n", name);
return NULL;
}
conn->name = talloc_strdup(conn, name);
if (!conn->name) {
LOGP(DCLIENT, LOGL_ERROR, "Failed to allocate name for %s\n", name);
talloc_free(conn);
return NULL;
}
osmo_client_conn_init(conn, client);
llist_add_tail(&conn->entry, &client->conns);
return conn;
}

View File

@ -1,7 +1,7 @@
/*
* osmo-pcap-client code
*
* (C) 2011 by Holger Hans Peter Freyther <zecke@selfish.org>
* (C) 2011-2016 by Holger Hans Peter Freyther <holger@moiji-mobile.com>
* (C) 2011 by On-Waves
* All Rights Reserved
*
@ -22,15 +22,18 @@
#include <osmo-pcap/common.h>
#include <osmo-pcap/osmo_pcap_client.h>
#include <osmo-pcap/osmo_tls.h>
#include <osmocom/core/application.h>
#include <osmocom/core/process.h>
#include <osmocom/core/rate_ctr.h>
#include <osmocom/core/select.h>
#include <osmocom/core/stats.h>
#include <osmocom/core/talloc.h>
#include <osmocom/vty/logging.h>
#include <osmocom/vty/telnet_interface.h>
#include <osmocom/vty/stats.h>
#include <osmocom/vty/misc.h>
#include <pcap.h>
#include <signal.h>
@ -46,16 +49,36 @@
static const char *config_file = "osmo-pcap-client.cfg";
static int daemonize = 0;
void *tall_bsc_ctx;
void *tall_cli_ctx;
struct osmo_pcap_client *pcap_client;
extern void *tall_msgb_ctx;
extern void *tall_ctr_ctx;
static const struct rate_ctr_desc pcap_client_ctr_desc[] = {
[CLIENT_CTR_CONNECT] = { "server:connect", "Connects to the server" },
[CLIENT_CTR_BYTES] = { "captured:bytes", "Captured bytes " },
[CLIENT_CTR_PKTS] = { "captured:pkts", "Captured packets " },
[CLIENT_CTR_2BIG] = { "bpf:too_big", "Captured data too big " },
[CLIENT_CTR_NOMEM] = { "client:no_mem", "No memory available " },
[CLIENT_CTR_QERR] = { "client:queue_err", "Can not queue data " },
[CLIENT_CTR_PERR] = { "client:pcap_err", "libpcap error " },
[CLIENT_CTR_WERR] = { "client:write_err", "Write error " },
[CLIENT_CTR_P_RECV] = { "pcap:recv", "PCAP received packets " },
[CLIENT_CTR_P_DROP] = { "pcap:drop", "PCAP dropped packets " },
[CLIENT_CTR_P_IFDROP] = { "pcap:ifdrop", "iface dropped packets " },
};
static const struct rate_ctr_group_desc pcap_client_ctr_group_desc = {
.group_name_prefix = "pcap:client",
.group_description = "PCAP Client statistics",
.num_ctr = ARRAY_SIZE(pcap_client_ctr_desc),
.ctr_desc = pcap_client_ctr_desc,
.class_id = OSMO_STATS_CLASS_GLOBAL,
};
static struct vty_app_info vty_info = {
.name = "OsmoPCAPClient",
.version = PACKAGE_VERSION,
.go_parent_cb = osmopcap_go_parent,
.is_config_node = osmopcap_is_config_node,
};
static void print_usage()
@ -68,25 +91,58 @@ static void print_help()
printf(" Some useful help...\n");
printf(" -h --help this text\n");
printf(" -D --daemonize Fork the process into a background daemon\n");
printf(" -V --version Print the version number\n");
printf(" -d option --debug=DRLL:DCC:DMM:DRR:DRSL:DNM enable debugging\n");
printf(" -s --disable-color\n");
printf(" -T --timestamp. Print a timestamp in the debug output.\n");
printf(" -e --log-level number. Set a global loglevel.\n");
printf(" -c --config-file filename The config file to use.\n");
printf("\nVTY reference generation:\n");
printf(" --vty-ref-mode MODE VTY reference generation mode (e.g. 'expert').\n");
printf(" --vty-ref-xml Generate the VTY reference XML output and exit.\n");
}
static void handle_long_options(const char *prog_name, const int long_option)
{
static int vty_ref_mode = VTY_REF_GEN_MODE_DEFAULT;
switch (long_option) {
case 1:
vty_ref_mode = get_string_value(vty_ref_gen_mode_names, optarg);
if (vty_ref_mode < 0) {
fprintf(stderr, "%s: Unknown VTY reference generation "
"mode '%s'\n", prog_name, optarg);
exit(2);
}
break;
case 2:
fprintf(stderr, "Generating the VTY reference in mode '%s' (%s)\n",
get_value_string(vty_ref_gen_mode_names, vty_ref_mode),
get_value_string(vty_ref_gen_mode_desc, vty_ref_mode));
vty_dump_xml_ref_mode(stdout, (enum vty_ref_gen_mode) vty_ref_mode);
exit(0);
default:
fprintf(stderr, "%s: error parsing cmdline options\n", prog_name);
exit(2);
}
}
static void handle_options(int argc, char **argv)
{
while (1) {
int option_index = 0, c;
static int long_option = 0;
static struct option long_options[] = {
{"help", 0, 0, 'h'},
{"daemonize", 0, 0, 'D'},
{"debug", 1, 0, 'd'},
{"version", 0, 0, 'V'},
{"disable-color", 0, 0, 's'},
{"timestamp", 0, 0, 'T'},
{"log-level", 1, 0, 'e'},
{"config-file", 1, 0, 'c'},
{"vty-ref-mode", 1, &long_option, 1},
{"vty-ref-xml", 0, &long_option, 2},
{0, 0, 0, 0}
};
@ -100,12 +156,19 @@ static void handle_options(int argc, char **argv)
print_usage();
print_help();
exit(0);
case 0:
handle_long_options(argv[0], long_option);
break;
case 'D':
daemonize = 1;
break;
case 'd':
log_parse_category_mask(osmo_stderr_target, optarg);
break;
case 'V':
print_version(1);
exit(0);
break;
case 's':
log_set_use_color(osmo_stderr_target, 0);
break;
@ -125,20 +188,29 @@ static void handle_options(int argc, char **argv)
}
}
static void signal_handler(int signal)
static void signal_handler(int signum)
{
fprintf(stdout, "signal %u received\n", signal);
fprintf(stdout, "signal %u received\n", signum);
switch (signal) {
switch (signum) {
case SIGINT:
exit(0);
break;
case SIGABRT:
/* in case of abort, we want to obtain a talloc report
* and then return to the caller, who will abort the process */
/* in case of abort, we want to obtain a talloc report and
* then run default SIGABRT handler, who will generate coredump
* and abort the process. abort() should do this for us after we
* return, but program wouldn't exit if an external SIGABRT is
* received.
*/
talloc_report(tall_vty_ctx, stderr);
talloc_report_full(tall_cli_ctx, stderr);
signal(SIGABRT, SIG_DFL);
raise(SIGABRT);
break;
case SIGUSR1:
talloc_report(tall_vty_ctx, stderr);
talloc_report_full(tall_bsc_ctx, stderr);
talloc_report_full(tall_cli_ctx, stderr);
break;
default:
break;
@ -147,9 +219,8 @@ static void signal_handler(int signal)
static void talloc_init_ctx()
{
tall_bsc_ctx = talloc_named_const(NULL, 0, "nat");
tall_msgb_ctx = talloc_named_const(tall_bsc_ctx, 0, "msgb");
tall_ctr_ctx = talloc_named_const(tall_bsc_ctx, 0, "counter");
tall_cli_ctx = talloc_named_const(NULL, 0, "client");
msgb_talloc_ctx_init(tall_cli_ctx, 0);
}
int main(int argc, char **argv)
@ -157,16 +228,21 @@ int main(int argc, char **argv)
int rc;
talloc_init_ctx();
osmo_init_logging(&log_info);
osmo_init_logging2(tall_cli_ctx, &log_info);
vty_info.copyright = osmopcap_copyright;
vty_info.tall_ctx = tall_cli_ctx;
vty_init(&vty_info);
logging_vty_add_cmds(&log_info);
logging_vty_add_cmds();
osmo_stats_vty_add_cmds();
osmo_talloc_vty_add_cmds();
vty_client_init();
/* parse options */
handle_options(argc, argv);
rate_ctr_init(tall_bsc_ctx);
rate_ctr_init(tall_cli_ctx);
osmo_stats_init(tall_cli_ctx);
/* seed the PRNG */
srand(time(NULL));
@ -177,20 +253,25 @@ int main(int argc, char **argv)
signal(SIGUSR1, &signal_handler);
osmo_init_ignore_signals();
telnet_init(tall_bsc_ctx, NULL, 4240);
osmo_tls_init();
pcap_client = talloc_zero(tall_bsc_ctx, struct osmo_pcap_client);
pcap_client = osmo_pcap_client_alloc(tall_cli_ctx);
if (!pcap_client) {
LOGP(DCLIENT, LOGL_ERROR, "Failed to allocate osmo_pcap_client.\n");
exit(1);
}
pcap_client->fd.fd = -1;
vty_client_init(pcap_client);
/* initialize the queue */
osmo_wqueue_init(&pcap_client->wqueue, 10);
pcap_client->wqueue.bfd.fd = -1;
INIT_LLIST_HEAD(&pcap_client->conns);
osmo_client_conn_init(&pcap_client->conn, pcap_client);
pcap_client->conn.name = "default";
/* initialize the stats interface */
pcap_client->ctrg = rate_ctr_group_alloc(pcap_client, &pcap_client_ctr_group_desc, 0);
if (!pcap_client->ctrg) {
LOGP(DCLIENT, LOGL_ERROR, "Failed to allocate rate ctr\n");
exit(1);
}
if (vty_read_config_file(config_file, NULL) < 0) {
LOGP(DCLIENT, LOGL_ERROR,
@ -198,8 +279,16 @@ int main(int argc, char **argv)
exit(1);
}
rc = telnet_init_default(tall_cli_ctx, NULL, OSMO_VTY_PORT_PCAP_CLIENT);
if (rc < 0) {
LOGP(DCLIENT, LOGL_ERROR, "Failed to bind telnet interface\n");
exit(1);
}
/* attempt to connect to the remote */
osmo_client_connect(pcap_client);
if (pcap_client->conn.srv_ip && pcap_client->conn.srv_port > 0)
osmo_client_connect(&pcap_client->conn);
if (daemonize) {
rc = osmo_daemonize();

View File

@ -1,7 +1,7 @@
/*
* osmo-pcap-client code
*
* (C) 2011 by Holger Hans Peter Freyther <zecke@selfish.org>
* (C) 2011-2016 by Holger Hans Peter Freyther <holger@moiji-mobile.com>
* (C) 2011 by On-Waves
* All Rights Reserved
*
@ -25,41 +25,43 @@
#include <osmo-pcap/wireformat.h>
#include <osmocom/core/msgb.h>
#include <osmocom/core/rate_ctr.h>
#include <osmocom/core/select.h>
#include <osmocom/core/socket.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#include <netdb.h>
#include <sys/ioctl.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <errno.h>
#include <limits.h>
#include <string.h>
#include <unistd.h>
static void _osmo_client_connect(void *_data)
{
osmo_client_connect((struct osmo_pcap_client *) _data);
osmo_client_connect((struct osmo_pcap_client_conn *) _data);
}
static void lost_connection(struct osmo_pcap_client *client)
static void lost_connection(struct osmo_pcap_client_conn *conn)
{
if (client->wqueue.bfd.fd >= 0) {
osmo_fd_unregister(&client->wqueue.bfd);
close(client->wqueue.bfd.fd);
client->wqueue.bfd.fd = -1;
}
osmo_client_disconnect(conn);
client->timer.cb = _osmo_client_connect;
client->timer.data = client;
osmo_timer_schedule(&client->timer, 2, 0);
conn->timer.cb = _osmo_client_connect;
conn->timer.data = conn;
osmo_timer_schedule(&conn->timer, 2, 0);
}
static void write_data(struct osmo_pcap_client *client, struct msgb *msg)
static void write_data(struct osmo_pcap_client_conn *conn, struct msgb *msg)
{
if (osmo_wqueue_enqueue(&client->wqueue, msg) != 0) {
LOGP(DCLIENT, LOGL_ERROR, "Failed to enqueue.\n");
if (osmo_wqueue_enqueue_quiet(&conn->wqueue, msg) != 0) {
LOGP(DCLIENT, LOGL_ERROR, "Failed to enqueue conn=%s (capacity: %u/%u)\n",
conn->name, conn->wqueue.current_length, conn->wqueue.max_length);
rate_ctr_inc(rate_ctr_group_get_ctr(conn->client->ctrg, CLIENT_CTR_QERR));
msgb_free(msg);
return;
}
@ -72,9 +74,10 @@ static int read_cb(struct osmo_fd *fd)
rc = read(fd->fd, buf, sizeof(buf));
if (rc <= 0) {
struct osmo_pcap_client *client = fd->data;
LOGP(DCLIENT, LOGL_ERROR, "Lost connection on read.\n");
lost_connection(client);
struct osmo_pcap_client_conn *conn = fd->data;
LOGP(DCLIENT, LOGL_ERROR, "Lost connection on read conn=%s\n",
conn->name);
lost_connection(conn);
return -1;
}
@ -87,49 +90,157 @@ static int write_cb(struct osmo_fd *fd, struct msgb *msg)
rc = write(fd->fd, msg->data, msg->len);
if (rc < 0) {
struct osmo_pcap_client *client = fd->data;
LOGP(DCLIENT, LOGL_ERROR, "Lost connection on write.\n");
lost_connection(client);
struct osmo_pcap_client_conn *conn = fd->data;
LOGP(DCLIENT, LOGL_ERROR, "Lost connection on write to %s %s:%d.\n",
conn->name, conn->srv_ip, conn->srv_port);
rate_ctr_inc(rate_ctr_group_get_ctr(conn->client->ctrg, CLIENT_CTR_WERR));
lost_connection(conn);
return -1;
}
return 0;
}
void osmo_client_send_data(struct osmo_pcap_client *client,
static void handshake_done_cb(struct osmo_tls_session *session)
{
struct osmo_pcap_client_conn *conn;
conn = container_of(session, struct osmo_pcap_client_conn, tls_session);
osmo_wqueue_clear(&conn->wqueue);
osmo_client_send_link(conn);
}
static void tls_error_cb(struct osmo_tls_session *session)
{
struct osmo_pcap_client_conn *conn;
conn = container_of(session, struct osmo_pcap_client_conn, tls_session);
lost_connection(conn);
}
int conn_cb(struct osmo_fd *fd, unsigned int what)
{
/* finally the socket is connected... continue */
if (what & OSMO_FD_WRITE) {
struct osmo_pcap_client_conn *conn = fd->data;
/*
* The write queue needs to work differently for GNUtls. Before we can
* send data we will need to complete handshake.
*/
if (conn->tls_on) {
if (!osmo_tls_init_client_session(conn)) {
lost_connection(conn);
return -1;
}
conn->tls_session.handshake_done = handshake_done_cb;
conn->tls_session.error = tls_error_cb;
/* fd->data now points somewhere else, stop */
return 0;
} else {
conn->wqueue.bfd.cb = osmo_wqueue_bfd_cb;
conn->wqueue.bfd.data = conn;
osmo_wqueue_clear(&conn->wqueue);
osmo_client_send_link(conn);
}
}
if (what & OSMO_FD_READ)
read_cb(fd);
return 0;
}
static int get_iphdr_offset(int dlt)
{
switch (dlt) {
case DLT_EN10MB:
return 14;
case DLT_LINUX_SLL:
return 16;
default:
return -1;
}
}
void osmo_client_send_data(struct osmo_pcap_client_conn *conn,
struct pcap_pkthdr *in_hdr, const uint8_t *data)
{
struct osmo_pcap_data *om_hdr;
struct pcap_pkthdr *hdr;
struct osmo_pcap_pkthdr *hdr;
struct msgb *msg;
int offset, ip_len;
msg = msgb_alloc(4096, "data-data");
if (in_hdr->len > in_hdr->caplen) {
LOGP(DCLIENT, LOGL_ERROR,
"Recording truncated packet, len %zu > snaplen %zu\n",
(size_t) in_hdr->len, (size_t) in_hdr->caplen);
rate_ctr_inc(rate_ctr_group_get_ctr(conn->client->ctrg, CLIENT_CTR_2BIG));
}
msg = msgb_alloc(in_hdr->caplen + sizeof(*om_hdr) + sizeof(*hdr), "data-data");
if (!msg) {
LOGP(DCLIENT, LOGL_ERROR, "Failed to allocate.\n");
rate_ctr_inc(rate_ctr_group_get_ctr(conn->client->ctrg, CLIENT_CTR_NOMEM));
return;
}
om_hdr = (struct osmo_pcap_data *) msgb_put(msg, sizeof(*om_hdr));
om_hdr->type = PKT_LINK_DATA;
switch (conn->protocol) {
case PROTOCOL_OSMOPCAP:
om_hdr = (struct osmo_pcap_data *) msgb_put(msg, sizeof(*om_hdr));
om_hdr->type = PKT_LINK_DATA;
msg->l2h = msgb_put(msg, sizeof(*hdr));
hdr = (struct pcap_pkthdr *) msg->l2h;
*hdr = *in_hdr;
msg->l2h = msgb_put(msg, sizeof(*hdr));
hdr = (struct osmo_pcap_pkthdr *) msg->l2h;
hdr->ts_sec = in_hdr->ts.tv_sec;
hdr->ts_usec = in_hdr->ts.tv_usec;
hdr->caplen = in_hdr->caplen;
hdr->len = in_hdr->len;
msg->l3h = msgb_put(msg, in_hdr->caplen);
memcpy(msg->l3h, data, in_hdr->caplen);
msg->l3h = msgb_put(msg, in_hdr->caplen);
memcpy(msg->l3h, data, in_hdr->caplen);
om_hdr->len = msgb_l2len(msg);
om_hdr->len = htons(msgb_l2len(msg));
rate_ctr_add(rate_ctr_group_get_ctr(conn->client->ctrg, CLIENT_CTR_BYTES), hdr->caplen);
rate_ctr_inc(rate_ctr_group_get_ctr(conn->client->ctrg, CLIENT_CTR_PKTS));
break;
case PROTOCOL_IPIP:
offset = get_iphdr_offset(pcap_datalink(conn->client->handle));
if (offset < 0) {
msgb_free(msg);
return;
}
ip_len = in_hdr->caplen - offset;
if (ip_len < 0) {
msgb_free(msg);
return;
}
msg->l2h = msgb_put(msg, ip_len);
memcpy(msg->l2h, data+offset, ip_len);
break;
default:
OSMO_ASSERT(0);
}
write_data(client, msg);
write_data(conn, msg);
}
void osmo_client_send_link(struct osmo_pcap_client *client)
void osmo_client_send_link(struct osmo_pcap_client_conn *conn)
{
struct pcap_file_header *hdr;
struct osmo_pcap_data *om_hdr;
struct msgb *msg;
struct msgb *msg = msgb_alloc(4096, "link-data");
/* IPIP encapsulation has no linktype header */
if (conn->protocol == PROTOCOL_IPIP)
return;
if (!conn->client->handle) {
LOGP(DCLIENT, LOGL_ERROR,
"No pcap_handle not sending link info to conn=%s\n", conn->name);
return;
}
msg = msgb_alloc(sizeof(*om_hdr) + sizeof(*hdr), "link-data");
if (!msg) {
LOGP(DCLIENT, LOGL_ERROR, "Failed to allocate data.\n");
return;
@ -138,7 +249,7 @@ void osmo_client_send_link(struct osmo_pcap_client *client)
om_hdr = (struct osmo_pcap_data *) msgb_put(msg, sizeof(*om_hdr));
om_hdr->type = PKT_LINK_HDR;
om_hdr->len = sizeof(*hdr);
om_hdr->len = htons(sizeof(*hdr));
hdr = (struct pcap_file_header *) msgb_put(msg, sizeof(*hdr));
hdr->magic = 0xa1b2c3d4;
@ -146,39 +257,71 @@ void osmo_client_send_link(struct osmo_pcap_client *client)
hdr->version_minor = 4;
hdr->thiszone = 0;
hdr->sigfigs = 0;
hdr->snaplen = UINT_MAX;
hdr->linktype = pcap_datalink(client->handle);
hdr->snaplen = conn->client->snaplen;
hdr->linktype = pcap_datalink(conn->client->handle);
write_data(client, msg);
write_data(conn, msg);
}
void osmo_client_connect(struct osmo_pcap_client *client)
void osmo_client_connect(struct osmo_pcap_client_conn *conn)
{
int fd;
int rc;
uint16_t srv_port;
int sock_type, sock_proto;
unsigned int when;
client->wqueue.read_cb = read_cb;
client->wqueue.write_cb = write_cb;
client->wqueue.bfd.when = BSC_FD_READ;
client->wqueue.bfd.data = client;
osmo_wqueue_clear(&client->wqueue);
osmo_client_disconnect(conn);
fd = osmo_sock_init(AF_INET, SOCK_STREAM, IPPROTO_TCP,
client->srv_ip, client->srv_port, 0);
if (fd < 0) {
LOGP(DCLIENT, LOGL_ERROR,
"Failed to connect to %s:%d\n",
client->srv_ip, client->srv_port);
lost_connection(client);
return;
conn->wqueue.read_cb = read_cb;
conn->wqueue.write_cb = write_cb;
osmo_wqueue_clear(&conn->wqueue);
switch (conn->protocol) {
case PROTOCOL_OSMOPCAP:
srv_port = conn->srv_port;
sock_type = SOCK_STREAM;
sock_proto = IPPROTO_TCP;
when = OSMO_FD_READ | OSMO_FD_WRITE;
break;
case PROTOCOL_IPIP:
srv_port = 0;
sock_type = SOCK_RAW;
sock_proto = IPPROTO_IPIP;
when = OSMO_FD_WRITE;
break;
default:
OSMO_ASSERT(0);
break;
}
client->wqueue.bfd.fd = fd;
if (osmo_fd_register(&client->wqueue.bfd) != 0) {
rc = osmo_sock_init2(AF_INET, sock_type, sock_proto, conn->source_ip, 0, conn->srv_ip, srv_port,
OSMO_SOCK_F_BIND | OSMO_SOCK_F_CONNECT | OSMO_SOCK_F_NONBLOCK);
if (rc < 0) {
LOGP(DCLIENT, LOGL_ERROR,
"Failed to register to BFD.\n");
lost_connection(client);
"Failed to connect conn=%s to %s:%d\n",
conn->name, conn->srv_ip, conn->srv_port);
lost_connection(conn);
return;
}
osmo_fd_setup(&conn->wqueue.bfd, rc, when, conn_cb, conn, 0);
osmo_fd_register(&conn->wqueue.bfd);
osmo_client_send_link(client);
rate_ctr_inc(rate_ctr_group_get_ctr(conn->client->ctrg, CLIENT_CTR_CONNECT));
}
void osmo_client_reconnect(struct osmo_pcap_client_conn *conn)
{
lost_connection(conn);
}
void osmo_client_disconnect(struct osmo_pcap_client_conn *conn)
{
if (conn->wqueue.bfd.fd >= 0) {
osmo_tls_release(&conn->tls_session);
osmo_fd_unregister(&conn->wqueue.bfd);
close(conn->wqueue.bfd.fd);
conn->wqueue.bfd.fd = -1;
}
osmo_timer_del(&conn->timer);
}

View File

@ -1,7 +1,7 @@
/*
* osmo-pcap-client code
*
* (C) 2011 by Holger Hans Peter Freyther <zecke@selfish.org>
* (C) 2011-2016 by Holger Hans Peter Freyther <holger@moiji-mobile.com>
* (C) 2011 by On-Waves
* All Rights Reserved
*
@ -31,9 +31,28 @@
#define PCAP_STRING "PCAP related functions\n"
#define SERVER_STRING "Server string\n"
static const struct value_string osmopcap_protocol_names[] = {
{ PROTOCOL_OSMOPCAP, "osmo-pcap" },
{ PROTOCOL_IPIP, "ipip" },
{ 0, NULL }
};
static struct osmo_pcap_client_conn *get_conn(struct vty *vty)
{
if (vty->node == CLIENT_NODE)
return &pcap_client->conn;
return vty->index;
}
static struct cmd_node client_node = {
CLIENT_NODE,
"%s(client)#",
"%s(client)# ",
1,
};
static struct cmd_node server_node = {
CLIENT_SERVER_NODE,
"%s(server)# ",
1,
};
@ -46,6 +65,63 @@ DEFUN(cfg_client,
return CMD_SUCCESS;
}
static void write_client_conn_data(
struct vty *vty,
struct osmo_pcap_client_conn *conn,
const char *indent)
{
if (conn->tls_on) {
vty_out(vty, "%s enable tls%s", indent, VTY_NEWLINE);
vty_out(vty, "%s tls hostname %s%s", indent, conn->tls_hostname, VTY_NEWLINE);
vty_out(vty, "%s %stls verify-cert%s", indent,
conn->tls_verify ? "" : "no ", VTY_NEWLINE);
if (conn->tls_capath)
vty_out(vty, "%s tls capath %s%s", indent, conn->tls_capath, VTY_NEWLINE);
if (conn->tls_client_cert)
vty_out(vty, "%s tls client-cert %s%s", indent,
conn->tls_client_cert, VTY_NEWLINE);
if (conn->tls_client_key)
vty_out(vty, "%s tls client-key %s%s", indent,
conn->tls_client_key, VTY_NEWLINE);
if (conn->tls_priority)
vty_out(vty, "%s tls priority %s%s", indent,
conn->tls_priority, VTY_NEWLINE);
vty_out(vty, "%s tls log-level %d%s", indent,
conn->tls_log_level, VTY_NEWLINE);
}
if (conn->srv_ip)
vty_out(vty, "%s server ip %s%s", indent,
conn->srv_ip, VTY_NEWLINE);
if (conn->srv_port > 0)
vty_out(vty, "%s server port %d%s", indent,
conn->srv_port, VTY_NEWLINE);
if (conn->source_ip)
vty_out(vty, "%s source ip %s%s", indent,
conn->source_ip, VTY_NEWLINE);
if (conn->protocol != PROTOCOL_OSMOPCAP)
vty_out(vty, "%s protocol %s%s", indent,
get_value_string(osmopcap_protocol_names, conn->protocol), VTY_NEWLINE);
if (conn->wqueue.max_length != WQUEUE_MAXLEN_DEFAULT)
vty_out(vty, "%s wqueue max-length %u%s", indent,
conn->wqueue.max_length, VTY_NEWLINE);
}
static int config_write_server(struct vty *vty)
{
struct osmo_pcap_client_conn *conn;
llist_for_each_entry(conn, &pcap_client->conns, entry) {
vty_out(vty, " pcap-store-connection %s%s", conn->name, VTY_NEWLINE);
write_client_conn_data(vty, conn, " ");
vty_out(vty, " connect%s", VTY_NEWLINE);
}
return CMD_SUCCESS;
}
static int config_write_client(struct vty *vty)
{
vty_out(vty, "client%s", VTY_NEWLINE);
@ -53,21 +129,19 @@ static int config_write_client(struct vty *vty)
if (pcap_client->device)
vty_out(vty, " pcap device %s%s",
pcap_client->device, VTY_NEWLINE);
if (pcap_client->snaplen != DEFAULT_SNAPLEN)
vty_out(vty, " pcap snaplen %d%s",
pcap_client->snaplen, VTY_NEWLINE);
if (pcap_client->filter_string)
vty_out(vty, " pcap filter %s%s",
pcap_client->filter_string, VTY_NEWLINE);
vty_out(vty, " pcap detect-loop %d%s",
pcap_client->filter_itself, VTY_NEWLINE);
if (pcap_client->gprs_filtering)
vty_out(vty, " pcap add-filter gprs%s", VTY_NEWLINE);
if (pcap_client->srv_ip)
vty_out(vty, " server ip %s%s",
pcap_client->srv_ip, VTY_NEWLINE);
if (pcap_client->srv_port > 0)
vty_out(vty, " server port %d%s",
pcap_client->srv_port, VTY_NEWLINE);
write_client_conn_data(vty, &pcap_client->conn, "");
return CMD_SUCCESS;
}
@ -80,6 +154,37 @@ DEFUN(cfg_client_device,
return CMD_SUCCESS;
}
DEFUN(cfg_client_snaplen,
cfg_client_snaplen_cmd,
"pcap snaplen <1-262144>", /* MAXIMUM_SNAPLEN */
PCAP_STRING "snapshot length\n" "Bytes\n")
{
if (pcap_client->handle) {
vty_out(vty, "'pcap snaplen' must be set before 'pcap device' to take effect!%s", VTY_NEWLINE);
return CMD_WARNING;
}
pcap_client->snaplen = atoi(argv[0]);
return CMD_SUCCESS;
}
DEFUN(cfg_client_add_gprs,
cfg_client_add_gprs_cmd,
"pcap add-filter gprs",
PCAP_STRING "Add-filter\n" "Custom filtering for GPRS\n")
{
pcap_client->gprs_filtering = 1;
return CMD_SUCCESS;
}
DEFUN(cfg_client_del_gprs,
cfg_client_del_gprs_cmd,
"no pcap add-filter gprs",
NO_STR PCAP_STRING "Add-filter\n" "Custom filter for GPRS\n")
{
pcap_client->gprs_filtering = 0;
return CMD_SUCCESS;
}
DEFUN(cfg_client_filter,
cfg_client_filter_cmd,
"pcap filter .NAME",
@ -111,13 +216,201 @@ DEFUN(cfg_client_loop,
return CMD_SUCCESS;
}
#define TLS_STR "Transport Layer Security\n"
DEFUN(cfg_enable_tls,
cfg_enable_tls_cmd,
"enable tls",
"Enable\n" "Transport Layer Security\n")
{
struct osmo_pcap_client_conn *conn = get_conn(vty);
if (!conn->tls_on) {
if (conn->wqueue.bfd.fd >= 0)
osmo_client_reconnect(conn);
}
conn->tls_on = true;
return CMD_SUCCESS;
}
DEFUN(cfg_disable_tls,
cfg_disable_tls_cmd,
"disable tls",
"Disable\n" "Transport Layer Security\n")
{
struct osmo_pcap_client_conn *conn = get_conn(vty);
if (conn->tls_on)
osmo_client_reconnect(conn);
conn->tls_on = false;
return CMD_SUCCESS;
}
DEFUN(cfg_tls_hostname,
cfg_tls_hostname_cmd,
"tls hostname NAME",
TLS_STR "hostname for certificate validation\n" "name\n")
{
struct osmo_pcap_client_conn *conn = get_conn(vty);
talloc_free(conn->tls_hostname);
conn->tls_hostname = talloc_strdup(pcap_client, argv[0]);
return CMD_SUCCESS;
}
DEFUN(cfg_no_tls_hostname,
cfg_no_tls_hostname_cmd,
"no tls hostname",
NO_STR TLS_STR "hostname for certificate validation\n")
{
struct osmo_pcap_client_conn *conn = get_conn(vty);
talloc_free(conn->tls_hostname);
conn->tls_hostname = NULL;
return CMD_SUCCESS;
}
DEFUN(cfg_tls_verify,
cfg_tls_verify_cmd,
"tls verify-cert",
TLS_STR "Verify certificates\n")
{
struct osmo_pcap_client_conn *conn = get_conn(vty);
conn->tls_verify = true;
return CMD_SUCCESS;
}
DEFUN(cfg_no_tls_verify,
cfg_no_tls_verify_cmd,
"no tls verify-cert",
NO_STR TLS_STR "Verify certificates\n")
{
struct osmo_pcap_client_conn *conn = get_conn(vty);
conn->tls_verify = false;
return CMD_SUCCESS;
}
DEFUN(cfg_tls_capath,
cfg_tls_capath_cmd,
"tls capath .PATH",
TLS_STR "Trusted root certificates\n" "Filename\n")
{
struct osmo_pcap_client_conn *conn = get_conn(vty);
talloc_free(conn->tls_capath);
conn->tls_capath = talloc_strdup(pcap_client, argv[0]);
return CMD_SUCCESS;
}
DEFUN(cfg_no_tls_capath,
cfg_no_tls_capath_cmd,
"no tls capath",
NO_STR TLS_STR "Trusted root certificates\n")
{
struct osmo_pcap_client_conn *conn = get_conn(vty);
talloc_free(conn->tls_capath);
conn->tls_capath = NULL;
return CMD_SUCCESS;
}
DEFUN(cfg_tls_client_cert,
cfg_tls_client_cert_cmd,
"tls client-cert .PATH",
TLS_STR "Client certificate for authentication\n" "Filename\n")
{
struct osmo_pcap_client_conn *conn = get_conn(vty);
talloc_free(conn->tls_client_cert);
conn->tls_client_cert = talloc_strdup(pcap_client, argv[0]);
return CMD_SUCCESS;
}
DEFUN(cfg_no_tls_client_cert,
cfg_no_tls_client_cert_cmd,
"no tls client-cert",
NO_STR TLS_STR "Client certificate for authentication\n")
{
struct osmo_pcap_client_conn *conn = get_conn(vty);
talloc_free(conn->tls_client_cert);
conn->tls_client_cert = NULL;
return CMD_SUCCESS;
}
DEFUN(cfg_tls_client_key,
cfg_tls_client_key_cmd,
"tls client-key .PATH",
TLS_STR "Client private key\n" "Filename\n")
{
struct osmo_pcap_client_conn *conn = get_conn(vty);
talloc_free(conn->tls_client_key);
conn->tls_client_key = talloc_strdup(pcap_client, argv[0]);
return CMD_SUCCESS;
}
DEFUN(cfg_no_tls_client_key,
cfg_no_tls_client_key_cmd,
"no tls client-key",
NO_STR TLS_STR "Client private key\n")
{
struct osmo_pcap_client_conn *conn = get_conn(vty);
talloc_free(conn->tls_client_key);
conn->tls_client_key = NULL;
return CMD_SUCCESS;
}
DEFUN(cfg_tls_priority,
cfg_tls_priority_cmd,
"tls priority STR",
TLS_STR "Priority string for GNUtls\n" "Priority string\n")
{
struct osmo_pcap_client_conn *conn = get_conn(vty);
talloc_free(conn->tls_priority);
conn->tls_priority = talloc_strdup(pcap_client, argv[0]);
return CMD_SUCCESS;
}
DEFUN(cfg_no_tls_priority,
cfg_no_tls_priority_cmd,
"no tls priority",
NO_STR TLS_STR "Priority string for GNUtls\n")
{
struct osmo_pcap_client_conn *conn = get_conn(vty);
talloc_free(conn->tls_priority);
conn->tls_priority = NULL;
return CMD_SUCCESS;
}
DEFUN(cfg_tls_log_level,
cfg_tls_log_level_cmd,
"tls log-level <0-255>",
TLS_STR "Log-level\n" "GNUtls debug level\n")
{
struct osmo_pcap_client_conn *conn = get_conn(vty);
conn->tls_log_level = atoi(argv[0]);
return CMD_SUCCESS;
}
DEFUN(cfg_server_ip,
cfg_server_ip_cmd,
"server ip A.B.C.D",
SERVER_STRING "IP Address of the server\n" "IP\n")
{
talloc_free(pcap_client->srv_ip);
pcap_client->srv_ip = talloc_strdup(pcap_client, argv[0]);
struct osmo_pcap_client_conn *conn = get_conn(vty);
talloc_free(conn->srv_ip);
conn->srv_ip = talloc_strdup(pcap_client, argv[0]);
return CMD_SUCCESS;
}
@ -126,23 +419,184 @@ DEFUN(cfg_server_port,
"server port <1-65535>",
SERVER_STRING "Port\n" "Number\n")
{
pcap_client->srv_port = atoi(argv[0]);
struct osmo_pcap_client_conn *conn = get_conn(vty);
conn->srv_port = atoi(argv[0]);
return CMD_SUCCESS;
}
DEFUN(cfg_source_ip,
cfg_source_ip_cmd,
"source ip A.B.C.D",
SERVER_STRING "Source IP Address\n" "IP\n")
{
struct osmo_pcap_client_conn *conn = get_conn(vty);
talloc_free(conn->source_ip);
conn->source_ip = talloc_strdup(pcap_client, argv[0]);
return CMD_SUCCESS;
}
int vty_client_init(struct osmo_pcap_client *pcap)
DEFUN(cfg_pcap_store,
cfg_pcap_store_cmd,
"pcap-store-connection .NAME",
"Configure additional PCAP store server\n" "Name of server\n")
{
struct osmo_pcap_client_conn *conn;
conn = osmo_client_find_or_create_conn(pcap_client, argv[0]);
if (!conn) {
vty_out(vty, "%%Failed to find/create conection %s%s",
argv[0], VTY_NEWLINE);
return CMD_WARNING;
}
vty->index = conn;
vty->node = CLIENT_SERVER_NODE;
return CMD_SUCCESS;
}
DEFUN(cfg_no_pcap_store,
cfg_no_pcap_store_cmd,
"no pcap-store-connection .NAME",
NO_STR "Configure additional PCAP store server\n" "Name of server\n")
{
struct osmo_pcap_client_conn *conn;
conn = osmo_client_find_conn(pcap_client, argv[0]);
if (!conn) {
vty_out(vty, "%%Failed to find connection %s%ss",
argv[0], VTY_NEWLINE);
return CMD_WARNING;
}
osmo_client_free(conn);
return CMD_SUCCESS;
}
DEFUN(cfg_client_connect,
cfg_client_connect_cmd,
"connect",
"Connect to the storage\n")
{
struct osmo_pcap_client_conn *conn = get_conn(vty);
osmo_client_connect(conn);
return CMD_SUCCESS;
}
DEFUN(cfg_client_disconnect,
cfg_client_disconnect_cmd,
"disconnect",
"Disconnect to the storage\n")
{
struct osmo_pcap_client_conn *conn = get_conn(vty);
osmo_client_disconnect(conn);
return CMD_SUCCESS;
}
#define PROTOCOL_STR "protocol (osmo-pcap|ipip)"
#define PROTOCOL_HELP "Configure the Protocol used for transfer\n" \
"OsmoPCAP protocol (over TCP)\n" \
"IPIP encapsulation (for real-time streaming to wireshark)\n"
DEFUN(cfg_protocol,
cfg_protocol_cmd,
PROTOCOL_STR,
PROTOCOL_HELP)
{
struct osmo_pcap_client_conn *conn = get_conn(vty);
conn->protocol = get_string_value(osmopcap_protocol_names, argv[0]);
return CMD_SUCCESS;
}
DEFUN(cfg_client_protocol,
cfg_client_protocol_cmd,
PROTOCOL_STR,
PROTOCOL_HELP)
{
struct osmo_pcap_client_conn *conn = get_conn(vty);
conn->protocol = get_string_value(osmopcap_protocol_names, argv[0]);
return CMD_SUCCESS;
}
DEFUN(cfg_wqueue_maxlength,
cfg_wqueue_maxlength_cmd,
"wqueue max-length <1-4294967295>",
"Configure the write-queue used for transfer\n"
"Configure the maximum amount of packets to be stored in the write-queue\n"
"Maximum amount of packets before dropping starts\n")
{
struct osmo_pcap_client_conn *conn = get_conn(vty);
conn->wqueue.max_length = atoi(argv[0]);
return CMD_SUCCESS;
}
int vty_client_init(void)
{
install_element(CONFIG_NODE, &cfg_client_cmd);
install_node(&client_node, config_write_client);
install_default(CLIENT_NODE);
install_node(&server_node, config_write_server);
install_element(CLIENT_NODE, &cfg_client_device_cmd);
install_element(CLIENT_NODE, &cfg_client_snaplen_cmd);
install_element(CLIENT_NODE, &cfg_client_filter_cmd);
install_element(CLIENT_NODE, &cfg_client_loop_cmd);
install_element(CLIENT_NODE, &cfg_server_ip_cmd);
install_element(CLIENT_NODE, &cfg_server_port_cmd);
install_element(CLIENT_NODE, &cfg_source_ip_cmd);
install_element(CLIENT_NODE, &cfg_protocol_cmd);
install_element(CLIENT_NODE, &cfg_wqueue_maxlength_cmd);
install_element(CLIENT_NODE, &cfg_enable_tls_cmd);
install_element(CLIENT_NODE, &cfg_disable_tls_cmd);
install_element(CLIENT_NODE, &cfg_tls_hostname_cmd);
install_element(CLIENT_NODE, &cfg_no_tls_hostname_cmd);
install_element(CLIENT_NODE, &cfg_tls_verify_cmd);
install_element(CLIENT_NODE, &cfg_no_tls_verify_cmd);
install_element(CLIENT_NODE, &cfg_tls_capath_cmd);
install_element(CLIENT_NODE, &cfg_no_tls_capath_cmd);
install_element(CLIENT_NODE, &cfg_tls_client_cert_cmd);
install_element(CLIENT_NODE, &cfg_no_tls_client_cert_cmd);
install_element(CLIENT_NODE, &cfg_tls_client_key_cmd);
install_element(CLIENT_NODE, &cfg_no_tls_client_key_cmd);
install_element(CLIENT_NODE, &cfg_tls_priority_cmd);
install_element(CLIENT_NODE, &cfg_no_tls_priority_cmd);
install_element(CLIENT_NODE, &cfg_tls_log_level_cmd);
install_element(CLIENT_NODE, &cfg_client_add_gprs_cmd);
install_element(CLIENT_NODE, &cfg_client_del_gprs_cmd);
/* per server confiug*/
install_element(CLIENT_NODE, &cfg_pcap_store_cmd);
install_element(CLIENT_NODE, &cfg_no_pcap_store_cmd);
install_element(CLIENT_SERVER_NODE, &cfg_server_ip_cmd);
install_element(CLIENT_SERVER_NODE, &cfg_server_port_cmd);
install_element(CLIENT_SERVER_NODE, &cfg_source_ip_cmd);
install_element(CLIENT_SERVER_NODE, &cfg_enable_tls_cmd);
install_element(CLIENT_SERVER_NODE, &cfg_disable_tls_cmd);
install_element(CLIENT_SERVER_NODE, &cfg_tls_hostname_cmd);
install_element(CLIENT_SERVER_NODE, &cfg_no_tls_hostname_cmd);
install_element(CLIENT_SERVER_NODE, &cfg_tls_verify_cmd);
install_element(CLIENT_SERVER_NODE, &cfg_no_tls_verify_cmd);
install_element(CLIENT_SERVER_NODE, &cfg_tls_capath_cmd);
install_element(CLIENT_SERVER_NODE, &cfg_no_tls_capath_cmd);
install_element(CLIENT_SERVER_NODE, &cfg_tls_client_cert_cmd);
install_element(CLIENT_SERVER_NODE, &cfg_no_tls_client_cert_cmd);
install_element(CLIENT_SERVER_NODE, &cfg_tls_client_key_cmd);
install_element(CLIENT_SERVER_NODE, &cfg_no_tls_client_key_cmd);
install_element(CLIENT_SERVER_NODE, &cfg_tls_priority_cmd);
install_element(CLIENT_SERVER_NODE, &cfg_no_tls_priority_cmd);
install_element(CLIENT_SERVER_NODE, &cfg_tls_log_level_cmd);
install_element(CLIENT_SERVER_NODE, &cfg_client_connect_cmd);
install_element(CLIENT_SERVER_NODE, &cfg_client_disconnect_cmd);
install_element(CLIENT_SERVER_NODE, &cfg_client_protocol_cmd);
return 0;
}

View File

@ -49,6 +49,12 @@ static const struct log_info_cat default_categories[] = {
.color = "\033[1;34m",
.enabled = 1, .loglevel = LOGL_NOTICE,
},
[DTLS] = {
.name = "DTLS",
.description = "TLS code",
.color = "\033[1;34m",
.enabled = 1, .loglevel = LOGL_NOTICE,
},
};
const struct log_info log_info = {
@ -56,14 +62,14 @@ const struct log_info log_info = {
.num_cat = ARRAY_SIZE(default_categories),
};
const char *osmopcap_copyright =
"Copyright (C) 2011 Holger Freyther\r\n"
const char *osmopcap_copyright =
"Copyright (C) 2011-2017 Holger Freyther and contributors\r\n"
"License AGPLv3+: GNU AGPL version 3 or later <http://gnu.org/licenses/agpl-3.0.html>\r\n"
"This is free software: you are free to change and redistribute it.\r\n"
"There is NO WARRANTY, to the extent permitted by law.\r\n";
enum node_type osmopcap_go_parent(struct vty *vty)
int osmopcap_go_parent(struct vty *vty)
{
switch (vty->node) {
case CLIENT_NODE:
@ -71,20 +77,14 @@ enum node_type osmopcap_go_parent(struct vty *vty)
vty->node = CONFIG_NODE;
vty->index = NULL;
break;
case CLIENT_SERVER_NODE:
vty->node = CLIENT_NODE;
vty->index = NULL;
break;
default:
vty->node = CONFIG_NODE;
break;
}
return vty->node;
}
int osmopcap_is_config_node(struct vty *vty, int node)
{
switch (node) {
case CONFIG_NODE:
return 0;
default:
return 1;
}
return vty->node;
}

View File

@ -1,7 +1,7 @@
/*
* osmo-pcap-server code
*
* (C) 2011 by Holger Hans Peter Freyther <zecke@selfish.org>
* (C) 2011-2016 by Holger Hans Peter Freyther <holger@moiji-mobile.com>
* (C) 2011 by On-Waves
* All Rights Reserved
*
@ -22,15 +22,19 @@
#include <osmo-pcap/common.h>
#include <osmo-pcap/osmo_pcap_server.h>
#include <osmo-pcap/osmo_tls.h>
#include <osmocom/core/application.h>
#include <osmocom/core/process.h>
#include <osmocom/core/rate_ctr.h>
#include <osmocom/core/select.h>
#include <osmocom/core/stats.h>
#include <osmocom/core/talloc.h>
#include <osmocom/core/utils.h>
#include <osmocom/vty/logging.h>
#include <osmocom/vty/telnet_interface.h>
#include <osmocom/vty/stats.h>
#include <osmocom/vty/misc.h>
#include <pcap.h>
#include <signal.h>
@ -46,16 +50,45 @@
static const char *config_file = "osmo-pcap-server.cfg";
static int daemonize = 0;
void *tall_bsc_ctx;
void *tall_srv_ctx;
struct osmo_pcap_server *pcap_server;
extern void *tall_msgb_ctx;
extern void *tall_ctr_ctx;
static const struct rate_ctr_desc pcap_peer_ctr_desc[] = {
[PEER_CTR_CONNECT] = { "peer:connect", "Connect of a peer " },
[PEER_CTR_BYTES] = { "peer:bytes", "Received bytes " },
[PEER_CTR_PKTS] = { "peer:pkts", "Received packets " },
[PEER_CTR_PROTATE] = { "peer:file_rotated","Capture file rotated" },
};
static const struct rate_ctr_desc pcap_server_ctr_desc[] = {
[SERVER_CTR_CONNECT] = { "server:connect", "Connect of a peer " },
[SERVER_CTR_BYTES] = { "server:bytes", "Received bytes " },
[SERVER_CTR_PKTS] = { "server:pkts", "Received packets " },
[SERVER_CTR_PROTATE] = { "server:file_rotated", "Capture file rotated" },
[SERVER_CTR_NOCLIENT] = { "server:no_client", "Unknown connected " },
};
const struct rate_ctr_group_desc pcap_peer_group_desc = {
.group_name_prefix = NULL, /* will be dynamically patched */
.group_description = "PCAP peer statistics",
.num_ctr = ARRAY_SIZE(pcap_peer_ctr_desc),
.ctr_desc = pcap_peer_ctr_desc,
.class_id = OSMO_STATS_CLASS_PEER,
};
static const struct rate_ctr_group_desc pcap_server_group_desc = {
.group_name_prefix = "pcap:server",
.group_description = "PCAP Server global statistics",
.num_ctr = ARRAY_SIZE(pcap_server_ctr_desc),
.ctr_desc = pcap_server_ctr_desc,
.class_id = OSMO_STATS_CLASS_GLOBAL,
};
static struct vty_app_info vty_info = {
.name = "OsmoPCAPServer",
.version = PACKAGE_VERSION,
.go_parent_cb = osmopcap_go_parent,
.is_config_node = osmopcap_is_config_node,
};
static void print_usage()
@ -68,25 +101,58 @@ static void print_help()
printf(" Some useful help...\n");
printf(" -h --help this text\n");
printf(" -D --daemonize Fork the process into a background daemon\n");
printf(" -V --version Print the version number\n");
printf(" -d option --debug=DRLL:DCC:DMM:DRR:DRSL:DNM enable debugging\n");
printf(" -s --disable-color\n");
printf(" -T --timestamp. Print a timestamp in the debug output.\n");
printf(" -e --log-level number. Set a global loglevel.\n");
printf(" -c --config-file filename The config file to use.\n");
printf("\nVTY reference generation:\n");
printf(" --vty-ref-mode MODE VTY reference generation mode (e.g. 'expert').\n");
printf(" --vty-ref-xml Generate the VTY reference XML output and exit.\n");
}
static void handle_long_options(const char *prog_name, const int long_option)
{
static int vty_ref_mode = VTY_REF_GEN_MODE_DEFAULT;
switch (long_option) {
case 1:
vty_ref_mode = get_string_value(vty_ref_gen_mode_names, optarg);
if (vty_ref_mode < 0) {
fprintf(stderr, "%s: Unknown VTY reference generation "
"mode '%s'\n", prog_name, optarg);
exit(2);
}
break;
case 2:
fprintf(stderr, "Generating the VTY reference in mode '%s' (%s)\n",
get_value_string(vty_ref_gen_mode_names, vty_ref_mode),
get_value_string(vty_ref_gen_mode_desc, vty_ref_mode));
vty_dump_xml_ref_mode(stdout, (enum vty_ref_gen_mode) vty_ref_mode);
exit(0);
default:
fprintf(stderr, "%s: error parsing cmdline options\n", prog_name);
exit(2);
}
}
static void handle_options(int argc, char **argv)
{
while (1) {
int option_index = 0, c;
static int long_option = 0;
static struct option long_options[] = {
{"help", 0, 0, 'h'},
{"daemonize", 0, 0, 'D'},
{"debug", 1, 0, 'd'},
{"version", 0, 0, 'V'},
{"disable-color", 0, 0, 's'},
{"timestamp", 0, 0, 'T'},
{"log-level", 1, 0, 'e'},
{"config-file", 1, 0, 'c'},
{"vty-ref-mode", 1, &long_option, 1},
{"vty-ref-xml", 0, &long_option, 2},
{0, 0, 0, 0}
};
@ -100,12 +166,18 @@ static void handle_options(int argc, char **argv)
print_usage();
print_help();
exit(0);
case 0:
handle_long_options(argv[0], long_option);
break;
case 'D':
daemonize = 1;
break;
case 'd':
log_parse_category_mask(osmo_stderr_target, optarg);
break;
case 'V':
print_version(1);
exit(0);
case 's':
log_set_use_color(osmo_stderr_target, 0);
break;
@ -125,20 +197,32 @@ static void handle_options(int argc, char **argv)
}
}
static void signal_handler(int signal)
static void signal_handler(int signum)
{
fprintf(stdout, "signal %u received\n", signal);
fprintf(stdout, "signal %u received\n", signum);
switch (signal) {
switch (signum) {
case SIGINT:
exit(0);
break;
case SIGABRT:
/* in case of abort, we want to obtain a talloc report
* and then return to the caller, who will abort the process */
/* in case of abort, we want to obtain a talloc report and
* then run default SIGABRT handler, who will generate coredump
* and abort the process. abort() should do this for us after we
* return, but program wouldn't exit if an external SIGABRT is
* received.
*/
talloc_report(tall_vty_ctx, stderr);
talloc_report_full(tall_srv_ctx, stderr);
signal(SIGABRT, SIG_DFL);
raise(SIGABRT);
break;
case SIGUSR1:
talloc_report(tall_vty_ctx, stderr);
talloc_report_full(tall_bsc_ctx, stderr);
talloc_report_full(tall_srv_ctx, stderr);
break;
case SIGHUP:
osmo_pcap_server_reopen(pcap_server);
break;
default:
break;
@ -147,9 +231,8 @@ static void signal_handler(int signal)
static void talloc_init_ctx()
{
tall_bsc_ctx = talloc_named_const(NULL, 0, "server");
tall_msgb_ctx = talloc_named_const(tall_bsc_ctx, 0, "msgb");
tall_ctr_ctx = talloc_named_const(tall_bsc_ctx, 0, "counter");
tall_srv_ctx = talloc_named_const(NULL, 0, "server");
msgb_talloc_ctx_init(tall_srv_ctx, 0);
}
int main(int argc, char **argv)
@ -157,16 +240,21 @@ int main(int argc, char **argv)
int rc;
talloc_init_ctx();
osmo_init_logging(&log_info);
osmo_init_logging2(tall_srv_ctx, &log_info);
vty_info.copyright = osmopcap_copyright;
vty_info.tall_ctx = tall_srv_ctx;
vty_init(&vty_info);
logging_vty_add_cmds(&log_info);
logging_vty_add_cmds();
osmo_stats_vty_add_cmds();
osmo_talloc_vty_add_cmds();
vty_server_init();
/* parse options */
handle_options(argc, argv);
rate_ctr_init(tall_bsc_ctx);
rate_ctr_init(tall_srv_ctx);
osmo_stats_init(tall_srv_ctx);
/* seed the PRNG */
srand(time(NULL));
@ -175,18 +263,26 @@ int main(int argc, char **argv)
signal(SIGABRT, &signal_handler);
signal(SIGUSR1, &signal_handler);
osmo_init_ignore_signals();
signal(SIGHUP, &signal_handler);
telnet_init(tall_bsc_ctx, NULL, 4241);
osmo_tls_init();
pcap_server = talloc_zero(tall_bsc_ctx, struct osmo_pcap_server);
pcap_server = talloc_zero(tall_srv_ctx, struct osmo_pcap_server);
if (!pcap_server) {
LOGP(DSERVER, LOGL_ERROR, "Failed to allocate osmo_pcap_server.\n");
exit(1);
}
pcap_server->ctrg = rate_ctr_group_alloc(pcap_server, &pcap_server_group_desc, 0);
if (!pcap_server->ctrg) {
LOGP(DSERVER, LOGL_ERROR, "Failed to allocate rate counter.\n");
exit(1);
}
INIT_LLIST_HEAD(&pcap_server->conn);
pcap_server->base_path = talloc_strdup(pcap_server, "./");
pcap_server->permission_mask = 0440;
pcap_server->max_size = 1073741824;
vty_server_init(pcap_server);
pcap_server->max_snaplen = DEFAULT_SNAPLEN;
if (vty_read_config_file(config_file, NULL) < 0) {
LOGP(DSERVER, LOGL_ERROR,
@ -194,6 +290,14 @@ int main(int argc, char **argv)
exit(1);
}
rc = telnet_init_default(tall_srv_ctx, NULL, OSMO_VTY_PORT_PCAP_SERVER);
if (rc < 0) {
LOGP(DCLIENT, LOGL_ERROR, "Failed to bind telnet interface\n");
exit(1);
}
osmo_tls_server_init(pcap_server);
/* attempt to connect to the remote */
if (osmo_pcap_server_listen(pcap_server) != 0) {
LOGP(DSERVER, LOGL_ERROR,

View File

@ -1,7 +1,7 @@
/*
* osmo-pcap-server code
*
* (C) 2011 by Holger Hans Peter Freyther <zecke@selfish.org>
* (C) 2011-2016 by Holger Hans Peter Freyther <holger@moiji-mobile.com>
* (C) 2011 by On-Waves
* All Rights Reserved
*
@ -26,50 +26,154 @@
#include <osmocom/core/socket.h>
#include <osmocom/core/talloc.h>
#include <osmocom/core/rate_ctr.h>
#include <arpa/inet.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <zmq.h>
#include <fcntl.h>
#include <errno.h>
#include <string.h>
#include <unistd.h>
static void close_connection(struct osmo_pcap_conn *conn)
static void pcap_zmq_send(void *publ, const void *data, size_t len, int flags)
{
if (conn->rem_fd.fd != -1) {
close(conn->rem_fd.fd);
conn->rem_fd.fd = -1;
osmo_fd_unregister(&conn->rem_fd);
}
int rc;
zmq_msg_t msg;
if (conn->local_fd != -1) {
rc = zmq_msg_init_size(&msg, len);
if (rc != 0) {
/* sigh.. we said SNDMORE but can't... */
LOGP(DSERVER, LOGL_ERROR, "Failed to init rc=%d errno=%d/%s\n",
rc, errno, strerror(errno));
return;
}
memcpy(zmq_msg_data(&msg), data, len);
rc = zmq_msg_send(&msg, publ, flags);
if (rc == -1) {
/* is the zmq_msg now owned? leak??? */
LOGP(DSERVER, LOGL_ERROR, "Failed to send data rc=%d errno=%d/%s\n",
rc, errno, strerror(errno));
return;
}
}
static void client_event(struct osmo_pcap_conn *conn,
const char *event, const char *data)
{
char *event_name;
if (!conn->server->zmq_publ)
return;
/*
* This multi-part support is insane... so if we lose the first
* or the last part of the multipart message stuff is going out
* of sync. *great* As we can't do anything about it right now
* just close the eyese and send it.
*/
event_name = talloc_asprintf(conn, "event.v1.%s.%s",
event, conn->name);
pcap_zmq_send(conn->server->zmq_publ,
event_name, strlen(event_name),
data ? ZMQ_SNDMORE : 0);
talloc_free(event_name);
if (data)
pcap_zmq_send(conn->server->zmq_publ, data, strlen(data), 0);
}
static void client_data(struct osmo_pcap_conn *conn,
struct osmo_pcap_data *data)
{
char *event_name;
if (!conn->server->zmq_publ)
return;
/*
* This multi-part support is insane... so if we lose the first
* or the last part of the multipart message stuff is going out
* of sync. *great* As we can't do anything about it right now
* just close the eyese and send it.
*/
event_name = talloc_asprintf(conn, "data.v1.%s", conn->name);
pcap_zmq_send(conn->server->zmq_publ, event_name, strlen(event_name), ZMQ_SNDMORE);
talloc_free(event_name);
pcap_zmq_send(conn->server->zmq_publ,
&conn->file_hdr, sizeof(conn->file_hdr),
ZMQ_SNDMORE);
pcap_zmq_send(conn->server->zmq_publ,
&data->data[0], data->len,
0);
}
void osmo_pcap_server_close_trace(struct osmo_pcap_conn *conn)
{
if (conn->local_fd >= 0) {
close(conn->local_fd);
conn->local_fd = -1;
}
if (conn->curr_filename) {
client_event(conn, "closingtracefile", conn->curr_filename);
rate_ctr_inc(rate_ctr_group_get_ctr(conn->ctrg, PEER_CTR_PROTATE));
rate_ctr_inc(rate_ctr_group_get_ctr(conn->server->ctrg, SERVER_CTR_PROTATE));
talloc_free(conn->curr_filename);
conn->curr_filename = NULL;
}
}
static void close_connection(struct osmo_pcap_conn *conn)
{
if (conn->rem_wq.bfd.fd >= 0) {
osmo_fd_unregister(&conn->rem_wq.bfd);
close(conn->rem_wq.bfd.fd);
conn->rem_wq.bfd.fd = -1;
osmo_tls_release(&conn->tls_session);
}
osmo_pcap_server_close_trace(conn);
client_event(conn, "disconnect", NULL);
}
void osmo_pcap_server_close_conn(struct osmo_pcap_conn *conn)
{
return close_connection(conn);
}
static void restart_pcap(struct osmo_pcap_conn *conn)
{
time_t now = time(NULL);
struct tm *tm = localtime(&now);
char *filename;
int rc;
if (conn->local_fd >= 0) {
close(conn->local_fd);
conn->local_fd = -1;
osmo_pcap_server_close_trace(conn);
/* omit any storing/creation of the file */
if (conn->no_store) {
conn->last_write = *tm;
talloc_free(conn->curr_filename);
conn->curr_filename = NULL;
return;
}
filename = talloc_asprintf(conn, "%s/trace-%s-%d%.2d%.2d_%.2d%.2d%.2d.pcap",
conn->curr_filename = talloc_asprintf(conn, "%s/trace-%s-%d%.2d%.2d_%.2d%.2d%.2d.pcap",
conn->server->base_path, conn->name,
tm->tm_year + 1900, tm->tm_mon + 1, tm->tm_mday,
tm->tm_hour, tm->tm_min, tm->tm_sec);
conn->local_fd = creat(filename, S_IRUSR);
if (!conn->curr_filename) {
LOGP(DSERVER, LOGL_ERROR, "Failed to assemble filename for %s.\n", conn->name);
return;
}
conn->local_fd = creat(conn->curr_filename, conn->server->permission_mask);
if (conn->local_fd < 0) {
LOGP(DSERVER, LOGL_ERROR, "Failed to file: '%s'\n", filename);
LOGP(DSERVER, LOGL_ERROR, "Failed to file: '%s'\n", conn->curr_filename);
return;
}
@ -82,42 +186,51 @@ static void restart_pcap(struct osmo_pcap_conn *conn)
}
conn->last_write = *tm;
talloc_free(filename);
}
static void link_data(struct osmo_pcap_conn *conn, struct osmo_pcap_data *data)
static int link_data(struct osmo_pcap_conn *conn, struct osmo_pcap_data *data)
{
struct pcap_file_header *hdr;
if (data->len != sizeof(*hdr)) {
LOGP(DSERVER, LOGL_ERROR, "The pcap_file_header does not fit.\n");
close_connection(conn);
return;
hdr = (struct pcap_file_header *) &data->data[0];
if (hdr->snaplen > conn->server->max_snaplen) {
LOGP(DSERVER, LOGL_ERROR,
"The recvd pcap_file_header contains too big snaplen %zu > %zu\n",
(size_t) hdr->snaplen, (size_t) conn->server->max_snaplen);
return -1;
}
hdr = (struct pcap_file_header *) &data->data[0];
if (conn->local_fd < 0) {
if (!conn->no_store && conn->local_fd < 0) {
conn->file_hdr = *hdr;
restart_pcap(conn);
} else if (memcmp(&conn->file_hdr, hdr, sizeof(*hdr)) != 0) {
conn->file_hdr = *hdr;
restart_pcap(conn);
}
return 1;
}
/*
* Check if we are past the limit or on a day change
*/
static void write_data(struct osmo_pcap_conn *conn, struct osmo_pcap_data *data)
static int write_data(struct osmo_pcap_conn *conn, struct osmo_pcap_data *data)
{
time_t now = time(NULL);
struct tm *tm = localtime(&now);
int rc;
client_data(conn, data);
if (conn->no_store) {
conn->last_write = *tm;
return 1;
}
if (conn->local_fd < -1) {
LOGP(DSERVER, LOGL_ERROR, "No file is open. close connection.\n");
close_connection(conn);
return;
return -1;
}
off_t cur = lseek(conn->local_fd, 0, SEEK_CUR);
@ -135,8 +248,9 @@ static void write_data(struct osmo_pcap_conn *conn, struct osmo_pcap_data *data)
rc = write(conn->local_fd, &data->data[0], data->len);
if (rc != data->len) {
LOGP(DSERVER, LOGL_ERROR, "Failed to write for %s\n", conn->name);
close_connection(conn);
return -1;
}
return 1;
}
@ -150,7 +264,10 @@ void osmo_pcap_server_delete(struct osmo_pcap_conn *conn)
struct osmo_pcap_conn *osmo_pcap_server_find(struct osmo_pcap_server *server,
const char *name)
{
struct rate_ctr_group_desc *desc;
struct osmo_pcap_conn *conn;
size_t buf_size;
llist_for_each_entry(conn, &server->conn, entry) {
if (strcmp(conn->name, name) == 0)
return conn;
@ -159,76 +276,276 @@ struct osmo_pcap_conn *osmo_pcap_server_find(struct osmo_pcap_server *server,
conn = talloc_zero(server, struct osmo_pcap_conn);
if (!conn) {
LOGP(DSERVER, LOGL_ERROR,
"Failed to find the connection.\n");
"Failed to allocate the connection peer=%s.\n", name);
return NULL;
}
buf_size = sizeof(struct osmo_pcap_data);
buf_size += OSMO_MAX(sizeof(struct pcap_file_header),
sizeof(struct osmo_pcap_pkthdr) + server->max_snaplen);
conn->data = talloc_zero_size(conn, buf_size);
/* a bit nasty. we do not work with ids but names */
desc = talloc_zero(conn, struct rate_ctr_group_desc);
if (!desc) {
LOGP(DSERVER, LOGL_ERROR,
"Failed to allocate rate ctr desc peer=%s\n", name);
talloc_free(conn);
return NULL;
}
memcpy(desc, &pcap_peer_group_desc, sizeof(pcap_peer_group_desc));
desc->group_name_prefix = talloc_asprintf(desc, "pcap:peer:%s", name);
if (!desc->group_name_prefix) {
LOGP(DSERVER, LOGL_ERROR,
"Failed to allocate group name prefix peer=%s\n", name);
talloc_free(conn);
return NULL;
}
desc->group_description = talloc_asprintf(desc, "PCAP peer statistics %s", name);
if (!desc->group_description) {
LOGP(DSERVER, LOGL_ERROR,
"Failed to allocate group description peer=%s\n", name);
talloc_free(conn);
return NULL;
}
conn->ctrg = rate_ctr_group_alloc(desc, desc, 0);
if (!conn->ctrg) {
LOGP(DSERVER, LOGL_ERROR,
"Failed to allocate rate ctr peer=%s\n", name);
talloc_free(conn);
return NULL;
}
conn->name = talloc_strdup(conn, name);
conn->rem_fd.fd = -1;
/* we never write */
osmo_wqueue_init(&conn->rem_wq, 0);
conn->rem_wq.bfd.fd = -1;
conn->local_fd = -1;
conn->server = server;
llist_add_tail(&conn->entry, &server->conn);
return conn;
}
static int read_cb(struct osmo_fd *fd, unsigned int what)
static int do_read_tls(struct osmo_pcap_conn *conn, void *buf, size_t want_size)
{
struct osmo_pcap_data *data;
struct osmo_pcap_conn *conn;
char buf[4096];
int rc;
size_t size = want_size;
if (conn->tls_limit_read && size > conn->tls_limit_read)
size = conn->tls_limit_read;
return gnutls_record_recv(conn->tls_session.session, buf, size);
}
conn = fd->data;
data = (struct osmo_pcap_data *) &buf[0];
static int do_read(struct osmo_pcap_conn *conn, void *buf, size_t size)
{
if (conn->direct_read)
return read(conn->rem_wq.bfd.fd, buf, size);
return do_read_tls(conn, buf, size);
}
rc = read(fd->fd, buf, sizeof(*data));
if (rc != sizeof(*data)) {
LOGP(DSERVER, LOGL_ERROR, "Failed to read from %s\n", conn->name);
close_connection(conn);
return -1;
}
if (data->len > 2000) {
LOGP(DSERVER, LOGL_ERROR, "Unplausible result %u\n", data->len);
close_connection(conn);
return -1;
}
rc = read(fd->fd, &data->data[0], data->len);
if (rc != data->len) {
LOGP(DSERVER, LOGL_ERROR, "Two short packet %d\n", rc);
close_connection(conn);
return -1;
}
switch (data->type) {
static bool pcap_data_valid(struct osmo_pcap_conn *conn)
{
unsigned int min_len, max_len;
switch ((enum OsmoPcapDataType) conn->data->type) {
case PKT_LINK_HDR:
link_data(conn, data);
if (conn->data->len != sizeof(struct pcap_file_header)) {
LOGP(DSERVER, LOGL_ERROR,
"Implausible llink_hdr length: %u != %zu\n",
conn->data->len, sizeof(struct osmo_pcap_pkthdr));
return false;
}
break;
case PKT_LINK_DATA:
write_data(conn, data);
min_len = sizeof(struct osmo_pcap_pkthdr);
max_len = conn->server->max_snaplen + sizeof(struct osmo_pcap_pkthdr);
if (conn->data->len < min_len || conn->data->len > max_len) {
LOGP(DSERVER, LOGL_ERROR,
"Implausible data length: %u < %u <= %u\n",
min_len, conn->data->len, max_len);
return false;
}
break;
default:
LOGP(DSERVER, LOGL_ERROR, "Unknown data type %" PRIx8 "\n",
conn->data->type);
return false;
}
return true;
}
static int read_cb_initial(struct osmo_pcap_conn *conn)
{
int rc;
rc = do_read(conn, ((uint8_t*)conn->data) + sizeof(*conn->data) - conn->pend, conn->pend);
if (rc <= 0) {
LOGP(DSERVER, LOGL_ERROR,
"Too short packet. Got %d, wanted %d\n", rc, conn->data->len);
return -1;
}
conn->pend -= rc;
if (conn->pend < 0) {
LOGP(DSERVER, LOGL_ERROR,
"Someone got the pending read wrong: %d\n", conn->pend);
return -1;
} else if (conn->pend == 0) {
conn->data->len = ntohs(conn->data->len);
if (!pcap_data_valid(conn))
return -1;
conn->state = STATE_DATA;
conn->pend = conn->data->len;
}
return 1;
}
static int read_cb_data(struct osmo_pcap_conn *conn)
{
int rc;
rc = do_read(conn, &conn->data->data[conn->data->len - conn->pend], conn->pend);
if (rc <= 0) {
LOGP(DSERVER, LOGL_ERROR,
"Too short packet. Got %d, wanted %d\n", rc, conn->data->len);
return -1;
}
conn->pend -= rc;
if (conn->pend < 0) {
LOGP(DSERVER, LOGL_ERROR,
"Someone got the pending read wrong: %d\n", conn->pend);
return -1;
} else if (conn->pend == 0) {
conn->state = STATE_INITIAL;
conn->pend = sizeof(*conn->data);
/* count the full packet we got */
rate_ctr_inc(rate_ctr_group_get_ctr(conn->ctrg, PEER_CTR_PKTS));
rate_ctr_inc(rate_ctr_group_get_ctr(conn->server->ctrg, SERVER_CTR_PKTS));
/* count the bytes of it */
rate_ctr_add(rate_ctr_group_get_ctr(conn->ctrg, PEER_CTR_BYTES), conn->data->len);
rate_ctr_add(rate_ctr_group_get_ctr(conn->server->ctrg, SERVER_CTR_BYTES), conn->data->len);
switch (conn->data->type) {
case PKT_LINK_HDR:
return link_data(conn, conn->data);
break;
case PKT_LINK_DATA:
return write_data(conn, conn->data);
break;
}
}
return 1;
}
static int dispatch_read(struct osmo_pcap_conn *conn)
{
if (conn->state == STATE_INITIAL) {
if (conn->reopen) {
LOGP(DSERVER, LOGL_INFO, "Reopening log for %s now.\n", conn->name);
restart_pcap(conn);
conn->reopen = 0;
}
return read_cb_initial(conn);
} else if (conn->state == STATE_DATA) {
return read_cb_data(conn);
}
return 0;
}
static int read_cb(struct osmo_fd *fd)
{
struct osmo_pcap_conn *conn;
int rc;
conn = fd->data;
rc = dispatch_read(conn);
if (rc <= 0)
close_connection(conn);
return 0;
}
static void tls_error_cb(struct osmo_tls_session *session)
{
struct osmo_pcap_conn *conn;
conn = container_of(session, struct osmo_pcap_conn, tls_session);
close_connection(conn);
}
static int tls_read_cb(struct osmo_tls_session *session)
{
struct osmo_pcap_conn *conn;
size_t pend;
int rc;
conn = container_of(session, struct osmo_pcap_conn, tls_session);
conn->tls_limit_read = 0;
rc = dispatch_read(conn);
if (rc <= 0)
return rc;
/**
* This is a weakness of a single select approach and the
* buffered reading here. We need to read everything as
* otherwise we do not receive a ready-read. But at the
* same time don't read more than is buffered! So cap what
* can be read right now.
*/
while ((pend = osmo_tls_pending(session)) > 0) {
conn->tls_limit_read = pend;
rc = dispatch_read(conn);
if (rc <= 0)
return rc;
}
return 1;
}
static void new_connection(struct osmo_pcap_server *server,
struct osmo_pcap_conn *client, int new_fd)
{
close_connection(client);
memset(&client->file_hdr, 0, sizeof(client->file_hdr));
client->rem_fd.fd = new_fd;
if (osmo_fd_register(&client->rem_fd) != 0) {
client->rem_wq.bfd.fd = new_fd;
if (osmo_fd_register(&client->rem_wq.bfd) != 0) {
LOGP(DSERVER, LOGL_ERROR, "Failed to register fd.\n");
client->rem_fd.fd = -1;
client->rem_wq.bfd.fd = -1;
close(new_fd);
return;
}
client->rem_fd.data = client;
client->rem_fd.when = BSC_FD_READ;
client->rem_fd.cb = read_cb;
rate_ctr_inc(rate_ctr_group_get_ctr(client->ctrg, PEER_CTR_CONNECT));
client->state = STATE_INITIAL;
client->pend = sizeof(*client->data);
if (client->tls_use && !server->tls_on) {
LOGP(DSERVER, LOGL_NOTICE,
"Require TLS but not enabled on conn=%s\n",
client->name);
close_connection(client);
return;
} else if (client->tls_use) {
if (!osmo_tls_init_server_session(client, server)) {
close_connection(client);
return;
}
client->tls_session.error = tls_error_cb;
client->tls_session.read = tls_read_cb;
client->direct_read = false;
} else {
client->rem_wq.bfd.cb = osmo_wqueue_bfd_cb;
client->rem_wq.bfd.data = client;
client->rem_wq.bfd.when = OSMO_FD_READ;
client->rem_wq.read_cb = read_cb;
client->direct_read = true;
}
}
static int accept_cb(struct osmo_fd *fd, unsigned int when)
@ -246,15 +563,27 @@ static int accept_cb(struct osmo_fd *fd, unsigned int when)
}
server = fd->data;
/* count any accept to see no clients */
rate_ctr_inc(rate_ctr_group_get_ctr(server->ctrg, SERVER_CTR_CONNECT));
llist_for_each_entry(conn, &server->conn, entry) {
if (conn->remote_addr.s_addr == addr.sin_addr.s_addr) {
LOGP(DSERVER, LOGL_NOTICE,
"New connection from %s\n", conn->name);
client_event(conn, "connect", NULL);
new_connection(server, conn, new_fd);
return 0;
}
}
rate_ctr_inc(rate_ctr_group_get_ctr(server->ctrg, SERVER_CTR_NOCLIENT));
/*
* TODO: In the future start with a tls handshake and see if we know
* this client.
*/
LOGP(DSERVER, LOGL_ERROR,
"Failed to find client for %s\n", inet_ntoa(addr.sin_addr));
close(new_fd);
@ -266,14 +595,14 @@ int osmo_pcap_server_listen(struct osmo_pcap_server *server)
int fd;
fd = osmo_sock_init(AF_INET, SOCK_STREAM, IPPROTO_TCP,
server->addr, server->port, 1);
server->addr, server->port, OSMO_SOCK_F_BIND);
if (fd < 0) {
LOGP(DSERVER, LOGL_ERROR, "Failed to create the server socket.\n");
return -1;
}
server->listen_fd.fd = fd;
server->listen_fd.when = BSC_FD_READ;
server->listen_fd.when = OSMO_FD_READ;
server->listen_fd.cb = accept_cb;
server->listen_fd.data = server;
@ -285,3 +614,18 @@ int osmo_pcap_server_listen(struct osmo_pcap_server *server)
return 0;
}
void osmo_pcap_server_reopen(struct osmo_pcap_server *server)
{
struct osmo_pcap_conn *conn;
LOGP(DSERVER, LOGL_INFO, "Reopening all logfiles.\n");
llist_for_each_entry(conn, &server->conn, entry) {
/* Write the complete packet out first */
if (conn->state == STATE_INITIAL) {
restart_pcap(conn);
} else {
LOGP(DSERVER, LOGL_INFO, "Delaying %s until current packet is complete.\n", conn->name);
conn->reopen = 1;
}
}
}

View File

@ -1,7 +1,7 @@
/*
* osmo-pcap-server code
*
* (C) 2011 by Holger Hans Peter Freyther <zecke@selfish.org>
* (C) 2011-2016 by Holger Hans Peter Freyther <zecke@selfish.org>
* (C) 2011 by On-Waves
* All Rights Reserved
*
@ -25,6 +25,12 @@
#include <osmocom/core/talloc.h>
#include <zmq.h>
#include <unistd.h>
#include <errno.h>
#include <string.h>
#define SERVER_STR "Server settings\n"
#define CLIENT_STR "Client\n"
@ -35,6 +41,45 @@ static struct cmd_node server_node = {
1,
};
static void write_tls(struct vty *vty, struct osmo_pcap_server *pcap_server)
{
if (!pcap_server->tls_on)
return;
vty_out(vty, " enable tls%s", VTY_NEWLINE);
vty_out(vty, " tls log-level %d%s",
pcap_server->tls_log_level, VTY_NEWLINE);
if (pcap_server->tls_allow_anon)
vty_out(vty, " tls allow-auth anonymous%s", VTY_NEWLINE);
if (pcap_server->tls_allow_x509)
vty_out(vty, " tls allow-auth x509%s", VTY_NEWLINE);
if (pcap_server->tls_priority)
vty_out(vty, " tls priority %s%s",
pcap_server->tls_priority, VTY_NEWLINE);
if (pcap_server->tls_capath)
vty_out(vty, " tls capath %s%s", pcap_server->tls_capath, VTY_NEWLINE);
if (pcap_server->tls_crlfile)
vty_out(vty, " tls crlfile %s%s", pcap_server->tls_crlfile, VTY_NEWLINE);
if (pcap_server->tls_server_cert)
vty_out(vty, " tls server-cert %s%s",
pcap_server->tls_server_cert, VTY_NEWLINE);
if (pcap_server->tls_server_key)
vty_out(vty, " tls server-key %s%s",
pcap_server->tls_server_key, VTY_NEWLINE);
if (pcap_server->tls_dh_pkcs3)
vty_out(vty, " tls dh pkcs3 %s%s",
pcap_server->tls_dh_pkcs3, VTY_NEWLINE);
else
vty_out(vty, " tls dh generate%s", VTY_NEWLINE);
}
static int config_write_server(struct vty *vty)
{
struct osmo_pcap_conn *conn;
@ -43,14 +88,27 @@ static int config_write_server(struct vty *vty)
if (pcap_server->base_path)
vty_out(vty, " base-path %s%s", pcap_server->base_path, VTY_NEWLINE);
vty_out(vty, " file-permission-mask 0%o%s", pcap_server->permission_mask, VTY_NEWLINE);
if (pcap_server->addr)
vty_out(vty, " server ip %s%s", pcap_server->addr, VTY_NEWLINE);
if (pcap_server->port > 0)
vty_out(vty, "server port %d%s", pcap_server->port, VTY_NEWLINE);
vty_out(vty, " server port %d%s", pcap_server->port, VTY_NEWLINE);
vty_out(vty, " max-file-size %llu%s",
(unsigned long long) pcap_server->max_size, VTY_NEWLINE);
if (pcap_server->max_snaplen != DEFAULT_SNAPLEN)
vty_out(vty, " server max-snaplen %d%s", pcap_server->max_snaplen, VTY_NEWLINE);
if (pcap_server->zmq_port > 0)
vty_out(vty, " zeromq-publisher %s %d%s",
pcap_server->zmq_ip, pcap_server->zmq_port, VTY_NEWLINE);
write_tls(vty, pcap_server);
llist_for_each_entry(conn, &pcap_server->conn, entry) {
vty_out(vty, " client %s %s%s",
conn->name, conn->remote_host, VTY_NEWLINE);
vty_out(vty, " client %s %s%s%s%s",
conn->name, conn->remote_host,
conn->no_store ? " no-store" : " store",
conn->tls_use ? " tls" : "",
VTY_NEWLINE);
}
return CMD_SUCCESS;
@ -75,6 +133,46 @@ DEFUN(cfg_server_base,
return CMD_SUCCESS;
}
DEFUN(cfg_server_file_permission_mask,
cfg_server_file_permission_mask_cmd,
"file-permission-mask MODE",
"Permission mask to use when creating pcap files\n"
"The file permission mask, in octal format (default: 0440)\n")
{
unsigned long long val;
char *endptr;
errno = 0;
val = strtoul(argv[0], &endptr, 8);
switch (errno) {
case 0:
break;
case ERANGE:
case EINVAL:
default:
goto ret_invalid;
}
if (!endptr || *endptr) {
/* No chars were converted */
if (endptr == argv[0])
goto ret_invalid;
/* Or there are surplus chars after the converted number */
goto ret_invalid;
}
/* 'man mode_t': "According to POSIX, it shall be an integer type." */
if (val > INT_MAX)
goto ret_invalid;
pcap_server->permission_mask = val;
return CMD_SUCCESS;
ret_invalid:
vty_out(vty, "%% File permission mask out of range: '%s'%s", argv[0], VTY_NEWLINE);
return CMD_WARNING;
}
DEFUN(cfg_server_ip,
cfg_server_ip_cmd,
"server ip A.B.C.D",
@ -94,25 +192,80 @@ DEFUN(cfg_server_port,
return CMD_SUCCESS;
}
DEFUN(cfg_server_client,
cfg_server_client_cmd,
"client NAME A.B.C.D",
CLIENT_STR "Remote name used in filenames\n" "IP of the remote\n")
DEFUN(cfg_server_max_size,
cfg_server_max_size_cmd,
"max-file-size NR",
"Maximum file size for a trace\n" "Filesize in bytes\n")
{
pcap_server->max_size = strtoull(argv[0], NULL, 10);
return CMD_SUCCESS;
}
DEFUN(cfg_server_max_snaplen,
cfg_server_max_snaplen_cmd,
"max-snaplen <1-262144>", /* MAXIMUM_SNAPLEN */
"Maximum pcap snapshot length\n" "Bytes\n")
{
pcap_server->max_snaplen = atoi(argv[0]);
return CMD_SUCCESS;
}
static int manage_client(struct osmo_pcap_server *pcap_server,
struct vty *vty,
const char *name, const char *remote_host,
bool no_store, bool use_tls)
{
struct osmo_pcap_conn *conn;
conn = osmo_pcap_server_find(pcap_server, argv[0]);
conn = osmo_pcap_server_find(pcap_server, name);
if (!conn) {
vty_out(vty, "Failed to create a pcap server.\n");
return CMD_WARNING;
}
talloc_free(conn->remote_host);
conn->remote_host = talloc_strdup(pcap_server, argv[1]);
inet_aton(argv[1], &conn->remote_addr);
conn->remote_host = talloc_strdup(pcap_server, remote_host);
inet_aton(remote_host, &conn->remote_addr);
/* Checking no-store and maybe closing a pcap file */
if (no_store) {
osmo_pcap_server_close_trace(conn);
conn->no_store = 1;
} else
conn->no_store = 0;
if (use_tls) {
/* force moving to TLS */
if (!conn->tls_use)
osmo_pcap_server_close_conn(conn);
conn->tls_use = true;
} else {
conn->tls_use = false;
}
return CMD_SUCCESS;
}
DEFUN(cfg_server_client,
cfg_server_client_cmd,
"client NAME A.B.C.D [no-store] [tls]",
CLIENT_STR "Remote name used in filenames\n"
"IP of the remote\n" "Do not store traffic\n"
"Use Transport Level Security\n")
{
return manage_client(pcap_server, vty, argv[0], argv[1], argc >= 3, argc >= 4);
}
DEFUN(cfg_server_client_store_tls,
cfg_server_client_store_tls_cmd,
"client NAME A.B.C.D store [tls]",
CLIENT_STR "Remote name used in filenames\n"
"IP of the remote\n" "Do not store traffic\n"
"Use Transport Level Security\n")
{
return manage_client(pcap_server, vty, argv[0], argv[1], false, argc >= 3);
}
DEFUN(cfg_server_no_client,
cfg_server_no_client_cmd,
"no client NAME",
@ -129,16 +282,314 @@ DEFUN(cfg_server_no_client,
return CMD_SUCCESS;
}
void vty_server_init(struct osmo_pcap_server *server)
void destroy_zmq(struct vty *vty)
{
if (pcap_server->zmq_publ) {
int rc = zmq_close(pcap_server->zmq_publ);
pcap_server->zmq_publ = NULL;
if (rc != 0)
vty_out(vty, "%%Failed to close publisher rc=%d errno=%d/%s%s",
rc, errno, strerror(errno), VTY_NEWLINE);
}
if (pcap_server->zmq_ctx) {
int rc = zmq_ctx_destroy(pcap_server->zmq_ctx);
pcap_server->zmq_ctx = NULL;
if (rc != 0)
vty_out(vty, "%%Failed to destroy ctx rc=%d errno=%d/%s%s",
rc, errno, strerror(errno), VTY_NEWLINE);
}
}
DEFUN(cfg_server_zmq_ip_port,
cfg_server_zmq_ip_port_cmd,
"zeromq-publisher (A.B.C.D|*) <1-65535>",
"Enable publishing data to ZeroMQ\n"
"Bind to IPv4 address\n" "Bind to wildcard\n"
"Bind to port\n")
{
int linger, rc;
char *bind_str;
destroy_zmq(vty);
talloc_free(pcap_server->zmq_ip);
pcap_server->zmq_ip = talloc_strdup(pcap_server, argv[0]);
if (!pcap_server->zmq_ip) {
vty_out(vty, "%%Failed to allocate ip string%s", VTY_NEWLINE);
return CMD_WARNING;
}
pcap_server->zmq_port = atoi(argv[1]);
pcap_server->zmq_ctx = zmq_ctx_new();
if (!pcap_server->zmq_ctx) {
vty_out(vty, "%%Failed to create zmq ctx%s", VTY_NEWLINE);
return CMD_WARNING;
}
pcap_server->zmq_publ = zmq_socket(pcap_server->zmq_ctx, ZMQ_PUB);
if (!pcap_server->zmq_publ) {
vty_out(vty, "%%Failed to create zmq publisher%s", VTY_NEWLINE);
destroy_zmq(vty);
return CMD_WARNING;
}
linger = 0;
rc = zmq_setsockopt(pcap_server->zmq_publ, ZMQ_LINGER, &linger, sizeof(linger));
if (rc != 0) {
vty_out(vty, "%%Failed to set linger option rc=%d errno=%d/%s%s",
rc, errno, strerror(errno), VTY_NEWLINE);
destroy_zmq(vty);
return CMD_WARNING;
}
bind_str = talloc_asprintf(pcap_server->zmq_ip, "tcp://%s:%d",
pcap_server->zmq_ip, pcap_server->zmq_port);
rc = zmq_bind(pcap_server->zmq_publ, bind_str);
if (rc != 0) {
vty_out(vty, "%%Failed to bind zmq publ rc=%d errno=%d/%s%s",
rc, errno, strerror(errno), VTY_NEWLINE);
destroy_zmq(vty);
talloc_free(bind_str);
return CMD_WARNING;
}
return CMD_SUCCESS;
}
DEFUN(cfg_no_server_zmq_ip_port,
cfg_no_server_zmq_ip_port_cmd,
"no zeromq-publisher",
NO_STR "Disable zeromq-publishing\n")
{
destroy_zmq(vty);
talloc_free(pcap_server->zmq_ip);
pcap_server->zmq_ip = NULL;
pcap_server->zmq_port = 0;
return CMD_SUCCESS;
}
#define TLS_STR "Transport Layer Security\n"
DEFUN(cfg_enable_tls,
cfg_enable_tls_cmd,
"enable tls",
"Enable\n" "Transport Layer Security\n")
{
pcap_server->tls_on = true;
return CMD_SUCCESS;
}
DEFUN(cfg_disable_tls,
cfg_disable_tls_cmd,
"disable tls",
"Disable\n" "Transport Layer Security\n")
{
pcap_server->tls_on = false;
return CMD_SUCCESS;
}
DEFUN(cfg_tls_log_level,
cfg_tls_log_level_cmd,
"tls log-level <0-255>",
TLS_STR "Log-level\n" "GNUtls debug level\n")
{
pcap_server->tls_log_level = atoi(argv[0]);
return CMD_SUCCESS;
}
DEFUN(cfg_tls_allow_anon,
cfg_tls_allow_anon_cmd,
"tls allow-auth anonymous",
TLS_STR "allow authentication\n" "for anonymous\n")
{
pcap_server->tls_allow_anon = true;
return CMD_SUCCESS;
}
DEFUN(cfg_no_tls_allow_anon,
cfg_no_tls_allow_anon_cmd,
"no tls allow-auth anonymous",
NO_STR TLS_STR "allow authentication\n" "for anonymous\n")
{
pcap_server->tls_allow_anon = false;
return CMD_SUCCESS;
}
DEFUN(cfg_tls_allow_x509,
cfg_tls_allow_x509_cmd,
"tls allow-auth x509",
TLS_STR "allow authentication\n" "for certificates\n")
{
pcap_server->tls_allow_x509 = true;
return CMD_SUCCESS;
}
DEFUN(cfg_no_tls_allow_x509,
cfg_no_tls_allow_x509_cmd,
"no tls allow-auth x509",
NO_STR TLS_STR "allow authentication\n" "for certificates\n")
{
pcap_server->tls_allow_x509 = false;
return CMD_SUCCESS;
}
DEFUN(cfg_tls_priority,
cfg_tls_priority_cmd,
"tls priority STR",
TLS_STR "Priority string for GNUtls\n" "Priority string\n")
{
talloc_free(pcap_server->tls_priority);
pcap_server->tls_priority = talloc_strdup(pcap_server, argv[0]);
return CMD_SUCCESS;
}
DEFUN(cfg_no_tls_priority,
cfg_no_tls_priority_cmd,
"no tls priority",
NO_STR TLS_STR "Priority string for GNUtls\n")
{
talloc_free(pcap_server->tls_priority);
pcap_server->tls_priority = NULL;
return CMD_SUCCESS;
}
DEFUN(cfg_tls_capath,
cfg_tls_capath_cmd,
"tls capath .PATH",
TLS_STR "Trusted root certificates\n" "Filename\n")
{
talloc_free(pcap_server->tls_capath);
pcap_server->tls_capath = talloc_strdup(pcap_server, argv[0]);
return CMD_SUCCESS;
}
DEFUN(cfg_no_tls_capath,
cfg_no_tls_capath_cmd,
"no tls capath",
NO_STR TLS_STR "Trusted root certificates\n")
{
talloc_free(pcap_server->tls_capath);
pcap_server->tls_capath = NULL;
return CMD_SUCCESS;
}
DEFUN(cfg_tls_crlfile,
cfg_tls_crlfile_cmd,
"tls crlfile .PATH",
TLS_STR "CRL file\n" "Filename\n")
{
talloc_free(pcap_server->tls_crlfile);
pcap_server->tls_crlfile = talloc_strdup(pcap_server, argv[0]);
return CMD_SUCCESS;
}
DEFUN(cfg_no_tls_crlfile,
cfg_no_tls_crlfile_cmd,
"no tls crlfile",
NO_STR TLS_STR "CRL file\n")
{
talloc_free(pcap_server->tls_crlfile);
pcap_server->tls_crlfile = NULL;
return CMD_SUCCESS;
}
DEFUN(cfg_tls_server_cert,
cfg_tls_server_cert_cmd,
"tls server-cert .PATH",
TLS_STR "Server certificate\n" "Filename\n")
{
talloc_free(pcap_server->tls_server_cert);
pcap_server->tls_server_cert = talloc_strdup(pcap_server, argv[0]);
return CMD_SUCCESS;
}
DEFUN(cfg_no_tls_server_cert,
cfg_no_tls_server_cert_cmd,
"no tls server-cert",
NO_STR TLS_STR "Server certificate\n")
{
talloc_free(pcap_server->tls_server_cert);
pcap_server->tls_server_cert = NULL;
return CMD_SUCCESS;
}
DEFUN(cfg_tls_server_key,
cfg_tls_server_key_cmd,
"tls server-key .PATH",
TLS_STR "Server private key\n" "Filename\n")
{
talloc_free(pcap_server->tls_server_key);
pcap_server->tls_server_key = talloc_strdup(pcap_server, argv[0]);
return CMD_SUCCESS;
}
DEFUN(cfg_no_tls_server_key,
cfg_no_tls_server_key_cmd,
"no tls server-key",
NO_STR TLS_STR "Server private key\n")
{
talloc_free(pcap_server->tls_server_key);
pcap_server->tls_server_key = NULL;
return CMD_SUCCESS;
}
DEFUN(cfg_tls_dh_pkcs3,
cfg_tls_dh_pkcs3_cmd,
"tls dh pkcs .FILE",
TLS_STR "Diffie-Hellman Key Exchange\n" "PKCS3\n" "Filename\n")
{
talloc_free(pcap_server->tls_dh_pkcs3);
pcap_server->tls_dh_pkcs3 = talloc_strdup(pcap_server, argv[0]);
osmo_tls_dh_load(pcap_server);
return CMD_SUCCESS;
}
DEFUN(cfg_tls_dh_generate,
cfg_tls_dh_generate_cmd,
"tls dh generate",
TLS_STR "Diffie-Hellman Key Exchange\n" "Generate prime\n")
{
talloc_free(pcap_server->tls_dh_pkcs3);
pcap_server->tls_dh_pkcs3 = NULL;
osmo_tls_dh_generate(pcap_server);
return CMD_SUCCESS;
}
void vty_server_init(void)
{
install_element(CONFIG_NODE, &cfg_server_cmd);
install_node(&server_node, config_write_server);
install_default(SERVER_NODE);
install_element(SERVER_NODE, &cfg_server_base_cmd);
install_element(SERVER_NODE, &cfg_server_file_permission_mask_cmd);
install_element(SERVER_NODE, &cfg_server_ip_cmd);
install_element(SERVER_NODE, &cfg_server_port_cmd);
install_element(SERVER_NODE, &cfg_server_max_size_cmd);
install_element(SERVER_NODE, &cfg_server_max_snaplen_cmd);
install_element(SERVER_NODE, &cfg_server_zmq_ip_port_cmd);
install_element(SERVER_NODE, &cfg_no_server_zmq_ip_port_cmd);
/* tls for the server */
install_element(SERVER_NODE, &cfg_enable_tls_cmd);
install_element(SERVER_NODE, &cfg_disable_tls_cmd);
install_element(SERVER_NODE, &cfg_tls_log_level_cmd);
install_element(SERVER_NODE, &cfg_tls_allow_anon_cmd);
install_element(SERVER_NODE, &cfg_no_tls_allow_anon_cmd);
install_element(SERVER_NODE, &cfg_tls_allow_x509_cmd);
install_element(SERVER_NODE, &cfg_no_tls_allow_x509_cmd);
install_element(SERVER_NODE, &cfg_tls_priority_cmd);
install_element(SERVER_NODE, &cfg_no_tls_priority_cmd);
install_element(SERVER_NODE, &cfg_tls_capath_cmd);
install_element(SERVER_NODE, &cfg_no_tls_capath_cmd);
install_element(SERVER_NODE, &cfg_tls_crlfile_cmd);
install_element(SERVER_NODE, &cfg_no_tls_crlfile_cmd);
install_element(SERVER_NODE, &cfg_tls_server_cert_cmd);
install_element(SERVER_NODE, &cfg_no_tls_server_cert_cmd);
install_element(SERVER_NODE, &cfg_tls_server_key_cmd);
install_element(SERVER_NODE, &cfg_no_tls_server_key_cmd);
install_element(SERVER_NODE, &cfg_tls_dh_generate_cmd);
install_element(SERVER_NODE, &cfg_tls_dh_pkcs3_cmd);
install_element(SERVER_NODE, &cfg_server_client_cmd);
install_element(SERVER_NODE, &cfg_server_client_store_tls_cmd);
install_element(SERVER_NODE, &cfg_server_no_client_cmd);
}

553
src/osmo_tls.c Normal file
View File

@ -0,0 +1,553 @@
/*
* osmo-pcap TLS code
*
* (C) 2016 by Holger Hans Peter Freyther <holger@moiji-mobile.com>
* All Rights Reserved
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
#include <osmo-pcap/osmo_tls.h>
#include <osmo-pcap/osmo_pcap_client.h>
#include <osmo-pcap/osmo_pcap_server.h>
#include <osmo-pcap/common.h>
#include <osmocom/core/write_queue.h>
#include <osmocom/core/talloc.h>
#include <string.h>
#define CHECK_RC(rc, str) \
if (rc != 0) { \
LOGP(DTLS, LOGL_ERROR, "%s with rc=%d\n", str, rc); \
exit(1); \
}
static int generate_dh_params(struct osmo_pcap_server *server)
{
int rc;
unsigned int bits = gnutls_sec_param_to_pk_bits(GNUTLS_PK_DH,
GNUTLS_SEC_PARAM_HIGH);
LOGP(DTLS, LOGL_NOTICE, "Going to create DH params for %d bits\n", bits);
/* allocate it */
rc = gnutls_dh_params_init (&server->dh_params);
if (rc != GNUTLS_E_SUCCESS) {
LOGP(DTLS, LOGL_ERROR, "Failed to allocate DH params rc=%d\n", rc);
server->dh_params_allocated = false;
return rc;
}
/* generate and check */
rc = gnutls_dh_params_generate2 (server->dh_params, bits);
if (rc == GNUTLS_E_SUCCESS)
server->dh_params_allocated = true;
else {
LOGP(DTLS, LOGL_ERROR, "Failed to generate DH params rc=%d\n", rc);
server->dh_params_allocated = false;
gnutls_dh_params_deinit(server->dh_params);
}
return rc;
}
void osmo_tls_dh_load(struct osmo_pcap_server *server)
{
gnutls_datum_t data;
int rc;
/* free it before we start */
if (server->dh_params_allocated) {
gnutls_dh_params_deinit(server->dh_params);
server->dh_params_allocated = false;
}
/* check if we have all data */
if (!server->tls_dh_pkcs3) {
LOGP(DTLS, LOGL_ERROR, "Can not generate missing pkcs3=%p\n",
server->tls_dh_pkcs3);
return;
}
/* initialize it again */
rc = gnutls_dh_params_init (&server->dh_params);
if (rc != GNUTLS_E_SUCCESS) {
LOGP(DTLS, LOGL_ERROR, "Failed to allocate DH params rc=%d\n", rc);
server->dh_params_allocated = false;
return;
}
/* load prime and generator */
rc = gnutls_load_file(server->tls_dh_pkcs3, &data);
if (rc != GNUTLS_E_SUCCESS) {
LOGP(DTLS, LOGL_ERROR, "Failed to load DH params from=%s rc=%d\n",
server->tls_dh_pkcs3, rc);
gnutls_dh_params_deinit(server->dh_params);
return;
}
rc = gnutls_dh_params_import_pkcs3(server->dh_params, &data, GNUTLS_X509_FMT_PEM);
gnutls_free(data.data);
if (rc != GNUTLS_E_SUCCESS) {
LOGP(DTLS, LOGL_ERROR, "Failed to import DH params rc=%d\n", rc);
gnutls_dh_params_deinit(server->dh_params);
return;
}
/* done */
server->dh_params_allocated = true;
}
void osmo_tls_dh_generate(struct osmo_pcap_server *server)
{
if (server->dh_params_allocated)
gnutls_dh_params_deinit(server->dh_params);
generate_dh_params(server);
}
static int cert_callback(gnutls_session_t tls_session,
const gnutls_datum_t * req_ca_rdn, int nreqs,
const gnutls_pk_algorithm_t * sign_algos,
int sign_algos_length, gnutls_pcert_st ** pcert,
unsigned int *pcert_length, gnutls_privkey_t * pkey)
{
struct osmo_tls_session *sess = gnutls_session_get_ptr(tls_session);
gnutls_certificate_type_t type;
LOGP(DTLS, LOGL_DEBUG, "cert callback from server\n");
type = gnutls_certificate_type_get(tls_session);
if (type != GNUTLS_CRT_X509)
return -1;
*pcert_length = 1;
*pcert = &sess->pcert;
*pkey = sess->privk;
return 0;
}
static void tls_log_func(int level, const char *str)
{
LOGP(DTLS, LOGL_DEBUG, "GNUtls: |<%d>| %s", level, str);
}
static int verify_cert_cb(gnutls_session_t session)
{
const char *hostname;
unsigned int status;
int ret;
hostname = gnutls_session_get_ptr(session);
ret = gnutls_certificate_verify_peers3(session,
hostname, &status);
if (ret != 0)
return GNUTLS_E_CERTIFICATE_ERROR;
if (status != 0)
return GNUTLS_E_CERTIFICATE_ERROR;
return 0;
}
static void release_keys(struct osmo_tls_session *sess)
{
if (sess->pcert_alloc) {
gnutls_pcert_deinit(&sess->pcert);
sess->pcert_alloc = false;
}
if (sess->privk_alloc) {
gnutls_privkey_deinit(sess->privk);
sess->privk_alloc = false;
}
}
void osmo_tls_init(void)
{
int rc;
rc = gnutls_global_init();
CHECK_RC(rc, "init failed");
gnutls_global_set_log_function(tls_log_func);
}
void osmo_tls_server_init(struct osmo_pcap_server *server)
{
int rc;
if (server->dh_params_allocated)
return;
rc = generate_dh_params(server);
CHECK_RC(rc, "dh params failed");
}
static int need_handshake(struct osmo_tls_session *tls_session)
{
int rc;
rc = gnutls_handshake(tls_session->session);
if (rc == 0) {
/* handshake is done. start writing if we are allowed to */
LOGP(DTLS, LOGL_NOTICE, "TLS handshake done.\n");
osmo_fd_read_enable(&tls_session->wqueue->bfd);
if (!llist_empty(&tls_session->wqueue->msg_queue))
osmo_fd_write_enable(&tls_session->wqueue->bfd);
tls_session->need_handshake = false;
release_keys(tls_session);
if (tls_session->handshake_done)
tls_session->handshake_done(tls_session);
} else if (rc == GNUTLS_E_AGAIN || rc == GNUTLS_E_INTERRUPTED) {
LOGP(DTLS, LOGL_DEBUG, "rc=%d will wait for writable again.\n", rc);
} else if (gnutls_error_is_fatal(rc)) {
/* it failed for good.. */
LOGP(DTLS, LOGL_ERROR, "handshake failed rc=%d str=%s\n",
rc, gnutls_strerror(rc));
tls_session->wqueue->bfd.when = 0;
tls_session->error(tls_session);
}
return 0;
}
static int tls_read(struct osmo_tls_session *sess)
{
char buf[1024];
int rc;
if (sess->read)
return sess->read(sess);
memset(buf, 0, sizeof(buf));
rc = gnutls_record_recv(sess->session, buf, sizeof(buf) - 1);
return rc;
}
static int tls_write(struct osmo_tls_session *sess)
{
int rc;
osmo_fd_write_disable(&sess->wqueue->bfd);
if (llist_empty(&sess->wqueue->msg_queue))
return 0;
if (sess->need_resend) {
rc = gnutls_record_send(sess->session, NULL, 0);
} else {
struct msgb *msg;
msg = (struct msgb *) sess->wqueue->msg_queue.next;
rc = gnutls_record_send(sess->session, msg->data, msg->len);
}
if (rc > 0) {
sess->wqueue->current_length -= 1;
sess->need_resend = false;
struct msgb *msg = msgb_dequeue(&sess->wqueue->msg_queue);
msgb_free(msg);
} else if (rc == GNUTLS_E_INTERRUPTED || rc == GNUTLS_E_AGAIN) {
sess->need_resend = true;
} else if (gnutls_error_is_fatal(rc)) {
return rc;
}
if (sess->need_resend || !llist_empty(&sess->wqueue->msg_queue))
osmo_fd_write_enable(&sess->wqueue->bfd);
return rc;
}
int osmo_tls_client_bfd_cb(struct osmo_fd *fd, unsigned what)
{
struct osmo_tls_session *sess = fd->data;
if (sess->need_handshake)
return need_handshake(sess);
if (what & OSMO_FD_READ) {
int rc = tls_read(sess);
if (rc <= 0) {
sess->error(sess);
return rc;
}
}
if (what & OSMO_FD_WRITE) {
int rc = tls_write(sess);
if (rc < 0) {
sess->error(sess);
return rc;
}
}
return 0;
}
static int load_keys(struct osmo_pcap_client_conn *conn)
{
struct osmo_tls_session *sess = &conn->tls_session;
gnutls_datum_t data;
int rc;
if (!conn->tls_client_cert || !conn->tls_client_key) {
LOGP(DTLS, LOGL_DEBUG, "Skipping x509 client cert %p %p\n",
conn->tls_client_cert, conn->tls_client_key);
return 0;
}
rc = gnutls_load_file(conn->tls_client_cert, &data);
if (rc < 0) {
LOGP(DTLS, LOGL_ERROR, "Failed to load file=%s rc=%d\n",
conn->tls_client_cert, rc);
return -1;
}
rc = gnutls_pcert_import_x509_raw(&sess->pcert, &data, GNUTLS_X509_FMT_PEM, 0);
gnutls_free(data.data);
if (rc < 0) {
LOGP(DTLS, LOGL_ERROR, "Failed to import file=%s rc=%d\n",
conn->tls_client_cert, rc);
return -1;
}
sess->pcert_alloc = true;
/* copied to RAM.. nothing we can do about it */
rc = gnutls_load_file(conn->tls_client_key, &data);
if (rc < 0) {
LOGP(DTLS, LOGL_ERROR, "Failed to load file=%s rc=%d\n",
conn->tls_client_key, rc);
return -1;
}
gnutls_privkey_init(&sess->privk);
rc = gnutls_privkey_import_x509_raw(sess->privk, &data, GNUTLS_X509_FMT_PEM, NULL, 0);
gnutls_free(data.data);
if (rc < 0) {
LOGP(DTLS, LOGL_ERROR, "Failed to load file=%s rc=%d\n",
conn->tls_client_key, rc);
release_keys(sess);
return -1;
}
sess->privk_alloc = true;
return 0;
}
size_t osmo_tls_pending(struct osmo_tls_session *sess)
{
return gnutls_record_check_pending(sess->session);
}
bool osmo_tls_init_server_session(struct osmo_pcap_conn *conn,
struct osmo_pcap_server *server)
{
struct osmo_tls_session *sess = &conn->tls_session;
struct osmo_wqueue *wq = &conn->rem_wq;
int rc;
gnutls_global_set_log_level(server->tls_log_level);
memset(sess, 0, sizeof(*sess));
sess->in_use = sess->anon_alloc = sess->cert_alloc = false;
rc = gnutls_init(&sess->session, GNUTLS_SERVER | GNUTLS_NONBLOCK);
if (rc != GNUTLS_E_SUCCESS) {
LOGP(DTLS, LOGL_ERROR, "gnutls_init failed with rc=%d\n", rc);
return false;
}
gnutls_session_set_ptr(sess->session, sess);
sess->in_use = true;
/* use default or string */
if (server->tls_priority) {
const char *err;
rc = gnutls_priority_set_direct(sess->session, server->tls_priority, &err);
} else {
rc = gnutls_set_default_priority(sess->session);
}
if (rc != GNUTLS_E_SUCCESS) {
LOGP(DTLS, LOGL_ERROR, "def prio failed with rc=%d\n", rc);
osmo_tls_release(sess);
return false;
}
/* allow username/password operation */
rc = gnutls_anon_allocate_server_credentials(&sess->anon_serv_cred);
if (rc != GNUTLS_E_SUCCESS) {
LOGP(DTLS, LOGL_ERROR, "Failed to allocate anon cred rc=%d\n", rc);
osmo_tls_release(sess);
return false;
}
sess->anon_serv_alloc = true;
/* x509 certificate handling */
rc = gnutls_certificate_allocate_credentials(&sess->cert_cred);
if (rc != GNUTLS_E_SUCCESS) {
LOGP(DTLS, LOGL_ERROR, "Failed to allocate x509 cred rc=%d\n", rc);
osmo_tls_release(sess);
return false;
}
sess->cert_alloc = true;
/* set the credentials now */
if (server->dh_params_allocated) {
gnutls_anon_set_server_dh_params(sess->anon_serv_cred, server->dh_params);
gnutls_certificate_set_dh_params(sess->cert_cred, server->dh_params);
}
if (server->tls_allow_anon)
gnutls_credentials_set(sess->session, GNUTLS_CRD_ANON, sess->anon_serv_cred);
if (server->tls_allow_x509)
gnutls_credentials_set(sess->session, GNUTLS_CRD_CERTIFICATE, sess->cert_cred);
if (server->tls_capath) {
rc = gnutls_certificate_set_x509_trust_file(
sess->cert_cred, server->tls_capath, GNUTLS_X509_FMT_PEM);
if (rc != GNUTLS_E_SUCCESS) {
LOGP(DTLS, LOGL_ERROR, "Failed to load capath from path=%s rc=%d\n",
server->tls_capath, rc);
osmo_tls_release(sess);
return false;
}
}
if (server->tls_crlfile) {
rc = gnutls_certificate_set_x509_crl_file(
sess->cert_cred, server->tls_crlfile, GNUTLS_X509_FMT_PEM);
if (rc != GNUTLS_E_SUCCESS) {
LOGP(DTLS, LOGL_ERROR, "Failed to load crlfile from path=%s rc=%d\n",
server->tls_crlfile, rc);
osmo_tls_release(sess);
return false;
}
}
if (server->tls_server_cert && server->tls_server_key) {
rc = gnutls_certificate_set_x509_key_file(
sess->cert_cred, server->tls_server_cert, server->tls_server_key,
GNUTLS_X509_FMT_PEM);
if (rc != GNUTLS_E_SUCCESS) {
LOGP(DTLS, LOGL_ERROR, "Failed to load crt/key from path=%s/%s rc=%d\n",
server->tls_server_cert, server->tls_server_key, rc);
osmo_tls_release(sess);
return false;
}
}
#warning "TODO client certificates"
gnutls_transport_set_int(sess->session, wq->bfd.fd);
gnutls_handshake_set_timeout(sess->session,
GNUTLS_DEFAULT_HANDSHAKE_TIMEOUT);
osmo_fd_setup(&wq->bfd, wq->bfd.fd, OSMO_FD_READ | OSMO_FD_WRITE, osmo_tls_client_bfd_cb, sess, 0);
sess->need_handshake = true;
sess->wqueue = wq;
return true;
}
bool osmo_tls_init_client_session(struct osmo_pcap_client_conn *client)
{
struct osmo_tls_session *sess = &client->tls_session;
struct osmo_wqueue *wq = &client->wqueue;
unsigned int status;
int rc;
gnutls_global_set_log_level(client->tls_log_level);
memset(sess, 0, sizeof(*sess));
sess->in_use = sess->anon_alloc = sess->cert_alloc = false;
rc = gnutls_init(&sess->session, GNUTLS_CLIENT | GNUTLS_NONBLOCK);
if (rc != GNUTLS_E_SUCCESS) {
LOGP(DTLS, LOGL_ERROR, "gnutls_init failed with rc=%d\n", rc);
return false;
}
gnutls_session_set_ptr(sess->session, sess);
sess->in_use = true;
/* use default or string */
if (client->tls_priority) {
const char *err;
rc = gnutls_priority_set_direct(sess->session, client->tls_priority, &err);
} else {
rc = gnutls_set_default_priority(sess->session);
}
if (rc != GNUTLS_E_SUCCESS) {
LOGP(DTLS, LOGL_ERROR, "def prio failed with rc=%d\n", rc);
osmo_tls_release(sess);
return false;
}
/* allow username/password operation */
rc = gnutls_anon_allocate_client_credentials(&sess->anon_cred);
if (rc != GNUTLS_E_SUCCESS) {
LOGP(DTLS, LOGL_ERROR, "Failed to allocate anon cred rc=%d\n", rc);
osmo_tls_release(sess);
return false;
}
sess->anon_alloc = true;
/* x509 certificate handling */
rc = gnutls_certificate_allocate_credentials(&sess->cert_cred);
if (rc != GNUTLS_E_SUCCESS) {
LOGP(DTLS, LOGL_ERROR, "Failed to allocate x509 cred rc=%d\n", rc);
osmo_tls_release(sess);
return false;
}
sess->cert_alloc = true;
/* set the credentials now */
gnutls_credentials_set(sess->session, GNUTLS_CRD_ANON, sess->anon_cred);
gnutls_credentials_set(sess->session, GNUTLS_CRD_CERTIFICATE, sess->cert_cred);
if (client->tls_capath) {
rc = gnutls_certificate_set_x509_trust_file(
sess->cert_cred, client->tls_capath, GNUTLS_X509_FMT_PEM);
if (rc != GNUTLS_E_SUCCESS) {
LOGP(DTLS, LOGL_ERROR, "Failed to load capath from path=%s rc=%d\n",
client->tls_capath, rc);
osmo_tls_release(sess);
return false;
}
}
if (load_keys(client) != 0) {
osmo_tls_release(sess);
return false;
}
gnutls_certificate_set_retrieve_function2(sess->cert_cred, cert_callback);
/* set the hostname if we have one */
if (client->tls_hostname)
gnutls_server_name_set(sess->session, GNUTLS_NAME_DNS,
client->tls_hostname, strlen(client->tls_hostname));
/* do the verification */
if (client->tls_verify) {
gnutls_certificate_set_verify_function(sess->cert_cred, verify_cert_cb);
gnutls_certificate_verify_peers3(sess->session, client->tls_hostname, &status);
} else
LOGP(DTLS, LOGL_NOTICE, "Not going to validate certs as configured\n");
gnutls_transport_set_int(sess->session, wq->bfd.fd);
gnutls_handshake_set_timeout(sess->session,
GNUTLS_DEFAULT_HANDSHAKE_TIMEOUT);
osmo_fd_setup(&wq->bfd, wq->bfd.fd, OSMO_FD_READ | OSMO_FD_WRITE, osmo_tls_client_bfd_cb, sess, 0);
sess->need_handshake = true;
sess->wqueue = wq;
return true;
}
void osmo_tls_release(struct osmo_tls_session *session)
{
if (!session->in_use)
return;
gnutls_deinit(session->session);
release_keys(session);
if (session->anon_alloc)
gnutls_anon_free_client_credentials(session->anon_cred);
if (session->anon_serv_alloc)
gnutls_anon_free_server_credentials(session->anon_serv_cred);
if (session->cert_alloc)
gnutls_certificate_free_credentials(session->cert_cred);
session->in_use = false;
}

50
tests/Makefile.am Normal file
View File

@ -0,0 +1,50 @@
# The `:;' works around a Bash 3.2 bug when the output is not writeable.
$(srcdir)/package.m4: $(top_srcdir)/configure.ac
:;{ \
echo '# Signature of the current package.' && \
echo 'm4_define([AT_PACKAGE_NAME],' && \
echo ' [$(PACKAGE_NAME)])' && \
echo 'm4_define([AT_PACKAGE_TARNAME],' && \
echo ' [$(PACKAGE_TARNAME)])' && \
echo 'm4_define([AT_PACKAGE_VERSION],' && \
echo ' [$(PACKAGE_VERSION)])' && \
echo 'm4_define([AT_PACKAGE_STRING],' && \
echo ' [$(PACKAGE_STRING)])' && \
echo 'm4_define([AT_PACKAGE_BUGREPORT],' && \
echo ' [$(PACKAGE_BUGREPORT)])'; \
echo 'm4_define([AT_PACKAGE_URL],' && \
echo ' [$(PACKAGE_URL)])'; \
} >'$(srcdir)/package.m4'
EXTRA_DIST = testsuite.at $(srcdir)/package.m4 $(TESTSUITE)
DISTCLEANFILES = atconfig
TESTSUITE = $(srcdir)/testsuite
if ENABLE_EXT_TESTS
python-tests: $(top_builddir)/src/osmo-pcap-server \
$(top_builddir)/src/osmo-pcap-client
osmotestvty.py -p $(abs_top_srcdir) -w $(abs_top_builddir) -v
osmotestconfig.py -p $(abs_top_srcdir) -w $(abs_top_builddir) -v
else
python-tests:
echo "Not running python-based tests (determined at configure-time)"
endif
check-local: atconfig $(TESTSUITE)
$(SHELL) '$(TESTSUITE)' $(TESTSUITEFLAGS)
$(MAKE) $(AM_MAKEFLAGS) python-tests
installcheck-local: atconfig $(TESTSUITE)
$(SHELL) '$(TESTSUITE)' AUTOTEST_PATH='$(bindir)' \
$(TESTSUITEFLAGS)
clean-local:
test ! -f '$(TESTSUITE)' || \
$(SHELL) '$(TESTSUITE)' --clean
AUTOM4TE = $(SHELL) $(top_srcdir)/missing --run autom4te
AUTOTEST = $(AUTOM4TE) --language=autotest
$(TESTSUITE): $(srcdir)/testsuite.at $(srcdir)/package.m4
$(AUTOTEST) -I '$(srcdir)' -o $@.tmp $@.at
mv $@.tmp $@

3
tests/testsuite.at Normal file
View File

@ -0,0 +1,3 @@
AT_INIT
AT_BANNER([Regression tests.])