This is merely a historical archive of years 2008-2021, before the migration to mailman3.
A maintained and still updated list archive can be found at https://lists.osmocom.org/hyperkitty/list/gerrit-log@lists.osmocom.org/.
pespin gerrit-no-reply at lists.osmocom.orgpespin has uploaded this change for review. ( https://gerrit.osmocom.org/c/osmo-ggsn/+/25652 ) Change subject: WIP: gtp-echo-responder ...................................................................... WIP: gtp-echo-responder Change-Id: Ibdd6d8f6920571db0c60cf8b3b25d541b15ad3f1 --- M Makefile.am M configure.ac M contrib/osmo-ggsn.spec.in M debian/control A debian/gtp-echo-responder.install A utils/Makefile.am A utils/gtp_echo_responder.c A utils/gtp_echo_responder_test.py 8 files changed, 449 insertions(+), 1 deletion(-) git pull ssh://gerrit.osmocom.org:29418/osmo-ggsn refs/changes/52/25652/1 diff --git a/Makefile.am b/Makefile.am index f431bd9..7fb2529 100644 --- a/Makefile.am +++ b/Makefile.am @@ -1,5 +1,5 @@ ## Process this file with automake to produce Makefile.in -SUBDIRS = lib gtp ggsn sgsnemu doc contrib tests +SUBDIRS = lib gtp ggsn sgsnemu doc contrib utils tests pkgconfigdir = $(libdir)/pkgconfig pkgconfig_DATA = libgtp.pc diff --git a/configure.ac b/configure.ac index 2cf44fc..cfc9f21 100644 --- a/configure.ac +++ b/configure.ac @@ -257,6 +257,7 @@ lib/Makefile intl/Makefile po/Makefile + utils/Makefile sgsnemu/Makefile doc/manuals/Makefile contrib/Makefile diff --git a/contrib/osmo-ggsn.spec.in b/contrib/osmo-ggsn.spec.in index 6d55af8..bee8fc1 100644 --- a/contrib/osmo-ggsn.spec.in +++ b/contrib/osmo-ggsn.spec.in @@ -61,6 +61,15 @@ This subpackage contains libraries and header files for developing applications that want to make use of libgtp. +%package -n gtp-echo-responder +Summary: Small program answering GTP ECHO Request with GTP ECHO Response +License: MIT +Group: System/Libraries + +%description -n gtp-echo-responder +Small program answering GTP ECHO Request with GTP ECHO Response for both GTPCv1 +and GTPCv2. + %prep %setup -q @@ -122,4 +131,7 @@ %{_libdir}/libgtp.so %{_libdir}/pkgconfig/libgtp.pc +%files -n gtp-echo-responder +%{_bindir}/gtp-echo-responder + %changelog diff --git a/debian/control b/debian/control index bbffd49..6d5cde5 100644 --- a/debian/control +++ b/debian/control @@ -38,6 +38,12 @@ This library is part of OsmoGGSN and implements the GTP protocol between SGSN (Serving GPRS support node) and GGSN. +Package: gtp-echo-responder +Architecture: any +Depends: ${shlibs:Depends}, + ${misc:Depends} +Description: Small program answering GTP ECHO Request with GTP ECHO Response + Package: libgtp-dev Architecture: any Multi-Arch: same @@ -63,6 +69,15 @@ operators as the interface between the Internet and the rest of the mobile network infrastructure. +Package: gtp-echo-responder-dbg +Section: debug +Architecture: any +Priority: extra +Depends: ${shlibs:Depends}, ${misc:Depends}, gtp-echo-responder (= ${binary:Version}) +Multi-Arch: same +Description: Debug symbols for gtp-echo-responder + Small program answering GTP ECHO Request with GTP ECHO Response. + Package: libgtp-dbg Section: debug Architecture: any diff --git a/debian/gtp-echo-responder.install b/debian/gtp-echo-responder.install new file mode 100644 index 0000000..1d6d96f --- /dev/null +++ b/debian/gtp-echo-responder.install @@ -0,0 +1 @@ +/usr/bin/gtp-echo-responder diff --git a/utils/Makefile.am b/utils/Makefile.am new file mode 100644 index 0000000..7ba0ff4 --- /dev/null +++ b/utils/Makefile.am @@ -0,0 +1,3 @@ +bin_PROGRAMS = gtp-echo-responder + +gtp_echo_responder_SOURCES = gtp_echo_responder.c diff --git a/utils/gtp_echo_responder.c b/utils/gtp_echo_responder.c new file mode 100644 index 0000000..66479c7 --- /dev/null +++ b/utils/gtp_echo_responder.c @@ -0,0 +1,338 @@ +/* + * MIT License + * + * Copyright (c) 2021 by sysmocom - s.f.m.c. GmbH <info at sysmocom.de> + * + * SPDX-License-Identifier: MIT Permission is hereby granted, free of charge, to + * any person obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without restriction, + * including without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to permit + * persons to whom the Software is furnished to do so, subject to the following + * conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +/* For more info see: + * 3GPP TS 29.060 (GTPv1 and GTPv0) + * 3GPP TS 29.274 (GTPv2C) + */ + +#include "../config.h" + +#include <stdlib.h> +#include <stdbool.h> +#include <stdio.h> +#include <string.h> +#include <errno.h> +#include <getopt.h> +#include <netinet/in.h> +#include <arpa/inet.h> +#include <sys/select.h> +#include <sys/socket.h> + +#define GTP1C_PORT 2123 +#define GTP_MSGTYPE_ECHO_REQ 1 +#define GTP_MSGTYPE_ECHO_RSP 2 +#define GTP_IE_RECOVERY 14 + +struct gtp1_hdr { +#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__ + uint8_t pn:1, s:1, e:1, spare:1, pt:1, version:3; +#else + uint8_t version:3, pt:1, spare:1, e:1, s:1, pn:1; +#endif + uint8_t type; + uint16_t length; + uint32_t tei; + uint16_t seq; + uint8_t npdu; + uint8_t next; +} __attribute__((packed)); + +struct gtp_echo_resp_state { + struct { + char laddr[INET6_ADDRSTRLEN]; + uint8_t recovery_ctr; + } cfg; + struct sockaddr_storage laddr_gtpc1; + int fd_gtpc1; +}; + +struct gtp_echo_resp_state *g_st; + +static void print_usage(void) +{ + printf("Usage: gtp-echo-responder [-h] [-V] [-l listen_addr]\n"); +} + +static void print_help(void) +{ + printf( " Some useful help...\n" + " -h --help This help text\n" + " -V --version Print the version of gtp-echo-responder\n" + ); +} + +static void print_version(void) +{ + printf("gtp-echo-responder version %s\n", PACKAGE_VERSION); +} + +static void handle_options(int argc, char **argv) +{ + while (1) { + int option_index = 0, c; + static struct option long_options[] = { + { "help", 0, 0, 'h' }, + { "version", 0, 0, 'V' }, + {"listen-addr", 1, 0, 'l'}, + {"recovery-counter", 1, 0, 'R'}, + { 0, 0, 0, 0 } + }; + + c = getopt_long(argc, argv, "hdVl:R:", long_options, &option_index); + if (c == -1) + break; + + switch (c) { + case 'h': + print_usage(); + print_help(); + exit(0); + case 'V': + print_version(); + exit(0); + break; + case 'l': + strncpy(&g_st->cfg.laddr[0], optarg, sizeof(g_st->cfg.laddr)); + g_st->cfg.laddr[sizeof(g_st->cfg.laddr) - 1] = '\0'; + break; + case 'R': + g_st->cfg.recovery_ctr = (uint8_t)atoi(optarg); + } + } +} + +static int init_socket(void) +{ + struct in_addr addr; + struct in6_addr addr6; + struct sockaddr_in *saddr; + struct sockaddr_in6 *saddr6; + int family; + + if (inet_pton(AF_INET6, g_st->cfg.laddr, &addr6) == 1) { + family = AF_INET6; + saddr6 = (struct sockaddr_in6 *)&g_st->laddr_gtpc1; + saddr6->sin6_family = family; + saddr6->sin6_port = htons(GTP1C_PORT); + memcpy(&saddr6->sin6_addr, &addr6, sizeof(addr6)); + + } else if (inet_pton(AF_INET, g_st->cfg.laddr, &addr) == 1) { + family = AF_INET; + saddr = (struct sockaddr_in *)&g_st->laddr_gtpc1; + saddr->sin_family = family; + saddr->sin_port = htons(GTP1C_PORT); + memcpy(&saddr->sin_addr, &addr, sizeof(addr)); + } else { + fprintf(stderr, "Failed parsing address %s\n", g_st->cfg.laddr); + return -1; + } + + if ((g_st->fd_gtpc1 = socket(family, SOCK_DGRAM, 0)) < 0) { + fprintf(stderr, "socket() failed: %s\n", strerror(errno)); + return -2; + } + + if (bind(g_st->fd_gtpc1, (struct sockaddr *)&g_st->laddr_gtpc1, sizeof(g_st->laddr_gtpc1)) < 0) { + fprintf(stderr, "bind() failed: %s\n", strerror(errno)); + return -3; + } + + return 0; +} + +static const char* sockaddr2str(const struct sockaddr* saddr) +{ + static char _rem_addr_str[INET6_ADDRSTRLEN]; + struct sockaddr_in *saddr4; + struct sockaddr_in6 *saddr6; + + switch (saddr->sa_family) { + case AF_INET6: + saddr6 = (struct sockaddr_in6 *)saddr; + if (!inet_ntop(saddr6->sin6_family, &saddr6->sin6_addr, _rem_addr_str, sizeof(_rem_addr_str))) + goto err; + return _rem_addr_str; + case AF_INET: + saddr4 = (struct sockaddr_in *)saddr; + if (!inet_ntop(saddr4->sin_family, &saddr4->sin_addr, _rem_addr_str, sizeof(_rem_addr_str))) + goto err; + return _rem_addr_str; + default: + /* fall through */ + } + +err: + strcpy(_rem_addr_str, "unknwown"); + return _rem_addr_str; +} + +static int write_cb(int fd, const uint8_t *buf, size_t buf_len, const struct sockaddr* rem_saddr) +{ + ssize_t rc; + + rc = sendto(fd, buf, buf_len, 0, rem_saddr, sizeof(struct sockaddr_storage)); + if (rc < 0) { + fprintf(stderr, "sendto() failed: %s\n", strerror(errno)); + return -1; + } + if (rc != buf_len) { + fprintf(stderr, "sendto() short write: %u vs exp %u\n", rc, buf_len); + return -1; + } + return 0; +} + +static int gen_gtpc1_echo_rsp(uint8_t *buf, struct gtp1_hdr *echo_req) +{ + int offset = 0; + struct gtp1_hdr *echo_rsp = (struct gtp1_hdr *)buf; + unsigned exp_hdr_len = (echo_req->s || echo_req->pn || echo_req->e) ? 12 : 8; + + memcpy(echo_rsp, echo_req, exp_hdr_len); + echo_rsp->type = GTP_MSGTYPE_ECHO_RSP; + offset = exp_hdr_len; + buf[offset++] = GTP_IE_RECOVERY; + buf[offset++] = g_st->cfg.recovery_ctr; + + /* Update Length */ + echo_rsp->length = htons(offset - 8); + return offset; +} + +static int rx_gtpc1_echo_req(struct gtp1_hdr *echo_req, unsigned buf_len, const struct sockaddr* rem_saddr) +{ + int rc; + const size_t tx_buf_len = buf_len + 128; /* Leave some extra room */ + uint8_t *tx_buf = alloca(tx_buf_len); + + printf("Rx GTPCv1_ECHO_REQ from %s, Tx GTPCv1_ECHO_RSP\n", sockaddr2str(rem_saddr)); + + memset(tx_buf, 0, tx_buf_len); + rc = gen_gtpc1_echo_rsp(tx_buf, echo_req); + return write_cb(g_st->fd_gtpc1, tx_buf, rc, rem_saddr); +} +static int rx_gtpc1(struct gtp1_hdr *hdr, unsigned buf_len, const struct sockaddr* rem_saddr) +{ + unsigned exp_hdr_len = (hdr->s || hdr->pn || hdr->e) ? 12 : 8; + unsigned pdu_len; + + if (buf_len < exp_hdr_len) { + fprintf(stderr, "GTPCv1 packet size smaller than header! %u < exp %u\n", buf_len, exp_hdr_len); + return -1; + } + + pdu_len = ntohs(hdr->length); + if (buf_len < 8 + pdu_len) { + fprintf(stderr, "GTPCv1 packet size smaller than announced! %u < exp %u\n", buf_len, 8 + pdu_len); + return -1; + } + + if (hdr->pt != 1) { + fprintf(stderr, "GTPCv1 Protocol Type GTP' not supported!\n"); + return -1; + } + + switch (hdr->type) { + case GTP_MSGTYPE_ECHO_REQ: + return rx_gtpc1_echo_req(hdr, buf_len, rem_saddr); + default: + fprintf(stderr, "Silently ignoring unexpected packet of type %u\n", hdr->type); + return 0; + } +} + +static int read_cb(int fd) +{ + ssize_t sz; + uint8_t buf[4096]; + struct sockaddr_storage rem_saddr; + socklen_t rem_saddr_len = sizeof(rem_saddr); + struct gtp1_hdr *hdr1; + + if ((sz = recvfrom(fd, buf, sizeof(buf), 0, (struct sockaddr *)&rem_saddr, &rem_saddr_len)) < 0) { + fprintf(stderr, "recvfrom() failed: %s\n", strerror(errno)); + return -1; + } + if (sz == 0) { + fprintf(stderr, "recvfrom() read zero bytes!\n"); + return -1; + } + + hdr1 = (struct gtp1_hdr *)&buf[0]; + switch (hdr1->version) { + case 1: + return rx_gtpc1(hdr1, sz, (const struct sockaddr *)&rem_saddr); + default: + fprintf(stderr, "Rx GTPv%u: not supported (flags=0x%x)\n", hdr1->version, buf[0]); + return -1; + } +} + +static int loop(void) +{ + int rc; + fd_set rfds; + int nfds; + + while (true) { + FD_ZERO(&rfds); + FD_SET(g_st->fd_gtpc1, &rfds); + nfds = g_st->fd_gtpc1 + 1; + rc = select(nfds, &rfds, NULL, NULL, NULL); + if (rc == 0) + continue; + if (rc < 0) { + fprintf(stderr, "select() failed: %s\n", strerror(errno)); + return -1; + } + + if (FD_ISSET(g_st->fd_gtpc1, &rfds)) { + read_cb(g_st->fd_gtpc1); + } + } +} + +int main(int argc, char **argv) +{ + g_st = calloc(1, sizeof(struct gtp_echo_resp_state)); + + strcpy(g_st->cfg.laddr, "::"); + + handle_options(argc, argv); + + printf("Listening on: %s\n", g_st->cfg.laddr); + + if (init_socket() < 0) + exit(1); + + printf("Socket bound successfuly, listening for requests...\n"); + + if (loop() < 0) + exit(1); + + return 0; +} diff --git a/utils/gtp_echo_responder_test.py b/utils/gtp_echo_responder_test.py new file mode 100755 index 0000000..e90b129 --- /dev/null +++ b/utils/gtp_echo_responder_test.py @@ -0,0 +1,78 @@ +#!/usr/bin/env python3 +# MIT License +# +# Copyright (c) 2021 by sysmocom - s.f.m.c. GmbH <info at sysmocom.de> +# +# SPDX-License-Identifier: MIT Permission is hereby granted, free of charge, to +# any person obtaining a copy of this software and associated documentation +# files (the "Software"), to deal in the Software without restriction, +# including without limitation the rights to use, copy, modify, merge, publish, +# distribute, sublicense, and/or sell copies of the Software, and to permit +# persons to whom the Software is furnished to do so, subject to the following +# conditions: +# +# The above copyright notice and this permission notice (including the next +# paragraph) shall be included in all copies or substantial portions of the +# Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +# SOFTWARE. + + +import socket +import argparse +import struct +from ipaddress import ip_address, IPv4Address + +GTP1C_PORT = 2123 +BUF_SIZE = 4096 + +GTP_HDRv1_FLAG_PN = (1<<0) +GTP_HDRv1_FLAG_S = (1<<1) +GTP_HDRv1_FLAG_E = (1<<2) +GTP_HDRv1_PT_GTP = (1<<4) +GTP_HDRv1_VER_GTP1 = (1<<5) + +def gen_gtpc_v1_hdr(flags, type, length, tei, seq=0, npdu=0, next=0): + spare = 0 + if (flags & (GTP_HDRv1_FLAG_PN|GTP_HDRv1_FLAG_S|GTP_HDRv1_FLAG_E)): + #long format + length += 4 + d = struct.pack('!BBHIHBB',flags, type, length, tei, seq, npdu, next) + else: + #short format + d = struct.pack('!BBHI',flags, type, length, tei) + return d + +def gen_gtpc_v1_echo_req(tei=0, append_flags=0, seq=0, npdu=0, next=0): + return gen_gtpc_v1_hdr(GTP_HDRv1_VER_GTP1 | GTP_HDRv1_PT_GTP | append_flags, 1, 0, tei, seq, npdu, next) + + +def tx_rx(sk, rem_addr, tx_buf, exp_rx = True): + print('Tx ECHO_REQ to %r: %r' % (repr(rem_addr), repr(tx_buf))) + sk.sendto(tx_buf, rem_addr) + if exp_rx: + rx_buf = sk.recvfrom(BUF_SIZE) + msg = "Message from Server {}".format(rx_buf) + print(msg) + +if __name__ == '__main__': + p = argparse.ArgumentParser(description='Tester for gtp-echo-recorder.') + p.add_argument('-l', '--local-address', default='127.0.0.2', help="Local GTP address") + p.add_argument('-r', '--remote-address', default='127.0.0.1', help="Remote GTP address") + args = p.parse_args() + + print('Binding socket on %r...' % repr((args.local_address, GTP1C_PORT))) + family = socket.AF_INET if type(ip_address(args.local_address)) is IPv4Address else socket.AF_INET6 + sk = socket.socket(family=family, type=socket.SOCK_DGRAM) + sk.bind((args.local_address, GTP1C_PORT)); + + rem_addr = (args.remote_address, GTP1C_PORT) + + tx_rx(sk, rem_addr, gen_gtpc_v1_echo_req()) + tx_rx(sk, rem_addr, gen_gtpc_v1_echo_req(1, GTP_HDRv1_FLAG_S, seq=67)) -- To view, visit https://gerrit.osmocom.org/c/osmo-ggsn/+/25652 To unsubscribe, or for help writing mail filters, visit https://gerrit.osmocom.org/settings Gerrit-Project: osmo-ggsn Gerrit-Branch: master Gerrit-Change-Id: Ibdd6d8f6920571db0c60cf8b3b25d541b15ad3f1 Gerrit-Change-Number: 25652 Gerrit-PatchSet: 1 Gerrit-Owner: pespin <pespin at sysmocom.de> Gerrit-MessageType: newchange -------------- next part -------------- An HTML attachment was scrubbed... URL: <http://lists.osmocom.org/pipermail/gerrit-log/attachments/20210930/8b2947d3/attachment.htm>