mirror of https://gerrit.osmocom.org/osmo-pcap
Compare commits
201 Commits
Author | SHA1 | Date |
---|---|---|
Vadim Yanitskiy | 9f47bedf37 | |
Andreas Eversberg | 13b41bc206 | |
Pau Espin | 88b5dc63a9 | |
Vadim Yanitskiy | 7f4debf1b9 | |
Oliver Smith | 2ec703f7c8 | |
Oliver Smith | b8d16e4e44 | |
Max | 17da7b38b9 | |
Pau Espin | 3092167e4e | |
Daniel Willmann | fa47880575 | |
Daniel Willmann | 4e934bb546 | |
Daniel Willmann | 50cc638ac7 | |
arehbein | 9d7556a73e | |
Pau Espin | 97c5c0c15c | |
Vadim Yanitskiy | af54579bd4 | |
Max | 36061e0d37 | |
Pau Espin | bddebaecb2 | |
Pau Espin | 5364393417 | |
Harald Welte | 57be1059bd | |
Pau Espin | a55253f438 | |
Pau Espin | 50dcc15a2e | |
Pau Espin | 6bbda89308 | |
Pau Espin | d72581492f | |
Pau Espin | b9be6767ab | |
Oliver Smith | 235eba3e9b | |
Harald Welte | 2c2eadcadf | |
Vadim Yanitskiy | b9392bfde0 | |
Pau Espin | 02d9d05143 | |
Pau Espin | 30bc1885e4 | |
Oliver Smith | eedd83c113 | |
Oliver Smith | 22f3d95ac9 | |
Pau Espin | ef92a539e8 | |
Harald Welte | 6e564a97b9 | |
Harald Welte | 8b73a2a530 | |
Harald Welte | dd1389c3d3 | |
Harald Welte | 9148d49841 | |
Harald Welte | 831494ed34 | |
Vadim Yanitskiy | 69ce121c6c | |
Harald Welte | a663ed23b1 | |
Harald Welte | 8a119642ac | |
Harald Welte | b0b2a2d542 | |
Vadim Yanitskiy | ff3f4b3bef | |
Vadim Yanitskiy | d59783e601 | |
Joachim Steiger | 52f06fd54b | |
Harald Welte | 611fd19fa3 | |
Pau Espin Pedrol | 06303a6dc5 | |
Oliver Smith | 288c39be10 | |
Harald Welte | 72cc2a508d | |
Pau Espin | 716a4db54c | |
Harald Welte | 5899cb4fbf | |
Harald Welte | a9600141b8 | |
Harald Welte | 20c6ba5a9e | |
Oliver Smith | f93e3dc1f8 | |
Oliver Smith | fd387ecec3 | |
Oliver Smith | 9d5fadcc79 | |
Pau Espin | d8368cebf8 | |
Oliver Smith | 7aa63021b6 | |
Oliver Smith | 47ea18eb8e | |
Oliver Smith | fdd62daa66 | |
Oliver Smith | 380305ee09 | |
Pau Espin | 5e10f1db12 | |
Pau Espin | ce0660cfe1 | |
Pau Espin | 210ed934bb | |
Pau Espin | 901543a788 | |
Pau Espin | 300cb49540 | |
Oliver Smith | d567571180 | |
Oliver Smith | e524725f9b | |
Pau Espin | d68773c4dc | |
Harald Welte | 407f7f9307 | |
Harald Welte | 066fc59ed0 | |
Oliver Smith | 5edc9b2382 | |
Oliver Smith | 14512ddae8 | |
Pau Espin | 3ad56f0408 | |
Pau Espin | a3a6ceb5f7 | |
Pau Espin | 45283d84e3 | |
Pau Espin | b29f84ff6c | |
Pau Espin | b96c957a22 | |
Pau Espin | 80d2b7b8dd | |
Pau Espin | a82aaef507 | |
Pau Espin | 868a501213 | |
Pau Espin | b799344ecd | |
Pau Espin | f946fa21ee | |
Pau Espin | 168949e119 | |
Pau Espin | db7be44632 | |
Pau Espin | f10c57801a | |
Pau Espin | 78262bda57 | |
Pau Espin | e241eada55 | |
Pau Espin | f59fabf9dc | |
Pau Espin | d475673b69 | |
Pau Espin | dc27ca85aa | |
Pau Espin | 5f3c30c40c | |
Pau Espin | 2828690633 | |
Pau Espin | 6e9bf9aa15 | |
Pau Espin | 3dfdbc21dc | |
Harald Welte | e89231d8b0 | |
Harald Welte | f335e37ed5 | |
Max | 53044df9d5 | |
Max | 93ac357b48 | |
Harald Welte | 5f071cd2c6 | |
Harald Welte | f266924bac | |
Harald Welte | 2fe9cb937d | |
Harald Welte | 2aea8704f3 | |
Harald Welte | 604e071159 | |
Holger Hans Peter Freyther | 4776b2972e | |
Holger Hans Peter Freyther | 17f5b00506 | |
Holger Hans Peter Freyther | 40c1e85499 | |
Holger Hans Peter Freyther | fdebd88059 | |
Holger Hans Peter Freyther | 36a183fd78 | |
Holger Hans Peter Freyther | 9294c40f14 | |
Holger Hans Peter Freyther | 0a94e57b72 | |
Holger Hans Peter Freyther | d7ab53dc16 | |
Holger Hans Peter Freyther | 1448f50db4 | |
Holger Hans Peter Freyther | 956c3facf1 | |
Holger Hans Peter Freyther | e3d7c3e154 | |
Holger Hans Peter Freyther | bdda28b1f5 | |
Holger Hans Peter Freyther | 13f397c68c | |
Holger Hans Peter Freyther | 0381276993 | |
Holger Hans Peter Freyther | 22acd211f1 | |
Holger Hans Peter Freyther | 07b94157ec | |
Holger Hans Peter Freyther | cf29fd7069 | |
Holger Hans Peter Freyther | ff3314e45c | |
Holger Hans Peter Freyther | 9ea4da4bbb | |
Holger Hans Peter Freyther | 064d224288 | |
Holger Hans Peter Freyther | 1bec9d5d09 | |
Holger Hans Peter Freyther | 098850d0a8 | |
Holger Hans Peter Freyther | 6413e7669e | |
Holger Hans Peter Freyther | c266796caa | |
Holger Hans Peter Freyther | c1c194393b | |
Holger Hans Peter Freyther | 3d439d0d08 | |
Holger Hans Peter Freyther | 0b4b824887 | |
Holger Hans Peter Freyther | fa5572e2af | |
Holger Hans Peter Freyther | 99526a6ad0 | |
Holger Hans Peter Freyther | c3455dcb79 | |
Holger Hans Peter Freyther | f416463a3c | |
Holger Hans Peter Freyther | 918be51338 | |
Holger Hans Peter Freyther | 86282d65db | |
Holger Hans Peter Freyther | 6e938eda1c | |
Holger Hans Peter Freyther | f8ff41e0f9 | |
Holger Hans Peter Freyther | df92652c95 | |
Holger Hans Peter Freyther | bdcbe0a679 | |
Holger Hans Peter Freyther | 2c503dd852 | |
Holger Hans Peter Freyther | e024869a72 | |
Holger Hans Peter Freyther | ad29ce6f06 | |
Holger Hans Peter Freyther | 2899428be2 | |
Holger Hans Peter Freyther | 9646754e1f | |
Holger Hans Peter Freyther | 26ba7b247e | |
Holger Hans Peter Freyther | c2715e917f | |
Holger Hans Peter Freyther | ea4ad4680a | |
Holger Hans Peter Freyther | ddc698fa92 | |
Holger Hans Peter Freyther | 072b183cd8 | |
Holger Hans Peter Freyther | 7ab0c0b86c | |
Holger Hans Peter Freyther | 157797317d | |
Holger Hans Peter Freyther | 5dff9f9ef5 | |
Holger Hans Peter Freyther | 3fedbf8361 | |
Holger Hans Peter Freyther | e6bad63dc6 | |
Holger Hans Peter Freyther | fd15a866db | |
Holger Hans Peter Freyther | d2650854b6 | |
Holger Hans Peter Freyther | c016b5d382 | |
Holger Hans Peter Freyther | 66b80cc8f5 | |
Holger Hans Peter Freyther | fbdcf593f8 | |
Holger Hans Peter Freyther | 42421c4f7e | |
Holger Hans Peter Freyther | ff1a5dc751 | |
Holger Hans Peter Freyther | 26327bd0ce | |
Holger Hans Peter Freyther | a316c9394a | |
Holger Hans Peter Freyther | 74f89c6119 | |
Holger Hans Peter Freyther | f42bbbc278 | |
Holger Hans Peter Freyther | ae5ec91a40 | |
Holger Hans Peter Freyther | b7a834b4cb | |
Sylvain Munaut | 07d96eb654 | |
Holger Hans Peter Freyther | 4edd6e6f1e | |
Holger Hans Peter Freyther | b08783de7b | |
Holger Hans Peter Freyther | b7568c6897 | |
Holger Hans Peter Freyther | d7999f0557 | |
Holger Hans Peter Freyther | 6d06bb1500 | |
Holger Hans Peter Freyther | fc3a427fb1 | |
Holger Hans Peter Freyther | 557215fd56 | |
Holger Hans Peter Freyther | e8b9177706 | |
Holger Hans Peter Freyther | 56d12cb505 | |
Daniel Willmann | f8e6e1888a | |
Holger Hans Peter Freyther | 0741879e11 | |
Daniel Willmann | 53e1f38514 | |
Daniel Willmann | 0e94548484 | |
Holger Hans Peter Freyther | b4fc89bfcf | |
Holger Hans Peter Freyther | cae1b7c960 | |
Daniel Willmann | 5d62ed0904 | |
Daniel Willmann | b000368ad6 | |
Daniel Willmann | c7401c6c23 | |
Daniel Willmann | de77386d84 | |
Holger Hans Peter Freyther | f60990e3f4 | |
Holger Hans Peter Freyther | dea9e8bbfe | |
Holger Hans Peter Freyther | de6262a97e | |
Holger Hans Peter Freyther | 91eaae33ea | |
Holger Hans Peter Freyther | 39d904f149 | |
Holger Hans Peter Freyther | 9df7dc5f69 | |
Holger Hans Peter Freyther | 59bfb5854d | |
Holger Hans Peter Freyther | b1f5d5ebed | |
Holger Hans Peter Freyther | afcc2ae172 | |
Holger Hans Peter Freyther | 54ff0b1b86 | |
Holger Hans Peter Freyther | dc3d1dcd59 | |
Holger Hans Peter Freyther | e6acfea051 | |
Holger Hans Peter Freyther | 0391b0a9c3 | |
Holger Hans Peter Freyther | 821f4fad68 |
|
@ -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
|
||||
|
|
|
@ -0,0 +1,3 @@
|
|||
[gerrit]
|
||||
host=gerrit.osmocom.org
|
||||
project=osmo-pcap
|
17
Makefile.am
17
Makefile.am
|
@ -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:
|
||||
|
|
|
@ -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.
|
|
@ -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).
|
|
@ -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.
|
147
configure.ac
147
configure.ac
|
@ -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)
|
||||
|
|
|
@ -0,0 +1,2 @@
|
|||
SUBDIRS = systemd
|
||||
dist_pkgdata_DATA = osmo_pcap_clean_old
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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)
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -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
|
|
@ -0,0 +1 @@
|
|||
10
|
|
@ -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
|
|
@ -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/>.
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -0,0 +1 @@
|
|||
3.0 (native)
|
|
@ -0,0 +1,4 @@
|
|||
SUBDIRS = \
|
||||
examples \
|
||||
manuals \
|
||||
$(NULL)
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
||||
|
|
@ -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.
|
|
@ -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
|
|
@ -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>
|
|
@ -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[]
|
|
@ -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" > $@
|
|
@ -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>
|
|
@ -0,0 +1,2 @@
|
|||
<vtydoc xmlns='urn:osmocom:xml:libosmocore:vty:doc:1.0'>
|
||||
</vtydoc>
|
|
@ -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
|
|
@ -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.
|
|
@ -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
|
||||
|
|
|
@ -1 +1 @@
|
|||
noinst_HEADERS = common.h
|
||||
noinst_HEADERS = common.h osmo_pcap_client.h osmo_pcap_server.h wireformat.h osmo_tls.h
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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);
|
|
@ -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
|
||||
|
|
|
@ -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]
|
||||
|
||||
|
|
@ -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)
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
|
@ -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 $@
|
||||
|
|
@ -0,0 +1,3 @@
|
|||
AT_INIT
|
||||
AT_BANNER([Regression tests.])
|
||||
|
Loading…
Reference in New Issue