gtp-link: allow to specify listener address

gtp-link add <device> <family> [--sgsn] [<address>]

Allow to specify listener address, if not specified use ANY_ADDRESS.

Change-Id: I7a9b64393fd68d58c2c158c0e85c0470be007f63
This commit is contained in:
Pablo Neira Ayuso 2024-02-15 21:08:26 +01:00 committed by Oliver Smith
parent 72ddb01219
commit d489488a70
1 changed files with 54 additions and 14 deletions

View File

@ -39,6 +39,7 @@
#include <linux/if_link.h>
#include <libgtpnl/gtpnl.h>
#include <errno.h>
struct gtp_server_sock {
int family;
@ -55,20 +56,26 @@ struct gtp_server_sock {
struct sockaddr_in6 in6;
} fd2;
} sockaddr;
union {
struct in_addr v4;
struct in6_addr v6;
} addr;
};
static void setup_sockaddr_in(struct sockaddr_in *sockaddr, uint16_t port)
static void setup_sockaddr_in(struct sockaddr_in *sockaddr, struct in_addr *in,
uint16_t port)
{
sockaddr->sin_family = AF_INET;
sockaddr->sin_port = htons(port);
sockaddr->sin_addr.s_addr = INADDR_ANY;
sockaddr->sin_addr = *in;
}
static void setup_sockaddr_in6(struct sockaddr_in6 *sockaddr, uint16_t port)
static void setup_sockaddr_in6(struct sockaddr_in6 *sockaddr, struct in6_addr *in6,
uint16_t port)
{
sockaddr->sin6_family = AF_INET6;
sockaddr->sin6_port = htons(port);
sockaddr->sin6_addr = in6addr_any;
sockaddr->sin6_addr = *in6;
}
static int setup_socket(struct gtp_server_sock *gtp_sock, int family)
@ -80,8 +87,6 @@ static int setup_socket(struct gtp_server_sock *gtp_sock, int family)
if (fd1 < 0 || fd2 < 0)
return -1;
memset(gtp_sock, 0, sizeof(*gtp_sock));
gtp_sock->family = family;
gtp_sock->fd1 = fd1;
gtp_sock->fd2 = fd2;
@ -89,13 +94,17 @@ static int setup_socket(struct gtp_server_sock *gtp_sock, int family)
switch (family) {
case AF_INET:
gtp_sock->len = sizeof(struct sockaddr_in);
setup_sockaddr_in(&gtp_sock->sockaddr.fd1.in, 3386);
setup_sockaddr_in(&gtp_sock->sockaddr.fd2.in, 2152);
setup_sockaddr_in(&gtp_sock->sockaddr.fd1.in,
&gtp_sock->addr.v4, 3386);
setup_sockaddr_in(&gtp_sock->sockaddr.fd2.in,
&gtp_sock->addr.v4, 2152);
break;
case AF_INET6:
gtp_sock->len = sizeof(struct sockaddr_in6);
setup_sockaddr_in6(&gtp_sock->sockaddr.fd1.in6, 3386);
setup_sockaddr_in6(&gtp_sock->sockaddr.fd2.in6, 2152);
setup_sockaddr_in6(&gtp_sock->sockaddr.fd1.in6,
&gtp_sock->addr.v6, 3386);
setup_sockaddr_in6(&gtp_sock->sockaddr.fd2.in6,
&gtp_sock->addr.v6, 2152);
if (setsockopt(fd1, IPPROTO_IPV6, IPV6_V6ONLY, &one, sizeof(one)) < 0)
perror("setsockopt IPV6_V6ONLY: ");
if (setsockopt(fd2, IPPROTO_IPV6, IPV6_V6ONLY, &one, sizeof(one)) < 0)
@ -111,9 +120,12 @@ int main(int argc, char *argv[])
char buf[MNL_SOCKET_BUFFER_SIZE];
struct gtp_server_sock gtp_sock;
int ret, sgsn_mode = 0, family;
const char *addr = NULL;
memset(&gtp_sock, 0, sizeof(gtp_sock));
if (argc < 3) {
printf("Usage: %s add <device> <family> [--sgsn]\n", argv[0]);
printf("Usage: %s add <device> <family> [--sgsn] [<address>]\n", argv[0]);
printf(" %s del <device>\n", argv[0]);
exit(EXIT_FAILURE);
}
@ -126,12 +138,23 @@ int main(int argc, char *argv[])
return 0;
} else if (!strcmp(argv[1], "add")) {
if (argc < 4) {
printf("Usage: %s add <device> <family> [--sgsn]\n", argv[0]);
printf("Usage: %s add <device> <family> [--sgsn] [<address>]\n", argv[0]);
exit(EXIT_FAILURE);
}
if (argc == 5 && !strcmp(argv[4], "--sgsn"))
sgsn_mode = 1;
if (argc == 5) {
if (!strcmp(argv[4], "--sgsn"))
sgsn_mode = 1;
else
addr = argv[4];
}
if (argc == 6) {
if (!strcmp(argv[4], "--sgsn"))
sgsn_mode = 1;
addr = argv[5];
}
}
if (!strcmp(argv[3], "ip"))
@ -144,6 +167,23 @@ int main(int argc, char *argv[])
exit(EXIT_FAILURE);
}
if (addr) {
if (!inet_pton(family, addr, &gtp_sock.addr)) {
fprintf(stderr, "invalid listener address: %s\n",
strerror(errno));
exit(EXIT_FAILURE);
}
} else {
switch (family) {
case AF_INET:
gtp_sock.addr.v4.s_addr = INADDR_ANY;
break;
case AF_INET6:
gtp_sock.addr.v6 = in6addr_any;
break;
}
}
if (setup_socket(&gtp_sock, family) < 0) {
perror("socket");
exit(EXIT_FAILURE);