blob: 325a45f795ac7ff1c195965849b984ed6d805714 [file] [log] [blame]
Harald Welte51b00a62014-04-03 09:37:38 -04001/* Command line utility to create GTP link */
2
3/* (C) 2014 by sysmocom - s.f.m.c. GmbH
Pablo Neira Ayuso448bce42016-05-08 21:43:40 +02004 * (C) 2016 by Pablo Neira Ayuso <pablo@netfilter.org>
5 *
Harald Welte51b00a62014-04-03 09:37:38 -04006 * Author: Pablo Neira Ayuso <pablo@gnumonks.org>
7 *
8 * All Rights Reserved
9 *
10 * This program is free software; you can redistribute it and/or modify
11 * it under the terms of the GNU General Public License as published by
12 * the Free Software Foundation; either version 2 of the License, or
13 * (at your option) any later version.
14 *
15 * This program is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 * GNU Affero General Public License for more details.
19 *
20 * You should have received a copy of the GNU General Public License
21 * along with this program. If not, see <http://www.gnu.org/licenses/>.
22 *
23 */
24
Pablo Neira Ayuso14506662014-02-20 18:43:15 +010025#include <stdio.h>
26#include <stdlib.h>
27#include <unistd.h>
28#include <string.h>
29#include <time.h>
Pablo Neira Ayuso50826a52016-05-10 18:00:51 +020030#include <netinet/in.h>
31#include <arpa/inet.h>
Pablo Neira Ayuso14506662014-02-20 18:43:15 +010032
33#include <libmnl/libmnl.h>
34#include <linux/if.h>
35#include <linux/if_link.h>
36#include <linux/rtnetlink.h>
37
Pablo Neira Ayusob9f6ffe2016-05-08 18:27:55 +020038#include <linux/gtp.h>
39#include <linux/if_link.h>
Pablo Neira Ayuso14506662014-02-20 18:43:15 +010040
Pablo Neira Ayuso448bce42016-05-08 21:43:40 +020041#include <libgtpnl/gtpnl.h>
42
Pablo Neira Ayuso38b5e232023-11-03 17:58:43 +010043struct gtp_server_sock {
44 int family;
45 int fd1;
46 int fd2;
47 socklen_t len;
48 struct {
49 union {
50 struct sockaddr_in in;
51 struct sockaddr_in6 in6;
52 } fd1;
53 union {
54 struct sockaddr_in in;
55 struct sockaddr_in6 in6;
56 } fd2;
57 } sockaddr;
58};
59
60static void setup_sockaddr_in(struct sockaddr_in *sockaddr, uint16_t port)
61{
62 sockaddr->sin_family = AF_INET;
63 sockaddr->sin_port = htons(port);
64 sockaddr->sin_addr.s_addr = INADDR_ANY;
65}
66
67static void setup_sockaddr_in6(struct sockaddr_in6 *sockaddr, uint16_t port)
68{
69 sockaddr->sin6_family = AF_INET6;
70 sockaddr->sin6_port = htons(port);
71 sockaddr->sin6_addr = in6addr_any;
72}
73
74static int setup_socket(struct gtp_server_sock *gtp_sock, int family)
75{
76 int fd1 = socket(family, SOCK_DGRAM, 0);
77 int fd2 = socket(family, SOCK_DGRAM, 0);
Pablo Neira Ayusoed42b8a2024-01-31 19:03:13 +010078 int one = 1;
Pablo Neira Ayuso38b5e232023-11-03 17:58:43 +010079
80 if (fd1 < 0 || fd2 < 0)
81 return -1;
82
83 memset(gtp_sock, 0, sizeof(*gtp_sock));
84
85 gtp_sock->family = family;
86 gtp_sock->fd1 = fd1;
87 gtp_sock->fd2 = fd2;
88
89 switch (family) {
90 case AF_INET:
91 gtp_sock->len = sizeof(struct sockaddr_in);
92 setup_sockaddr_in(&gtp_sock->sockaddr.fd1.in, 3386);
93 setup_sockaddr_in(&gtp_sock->sockaddr.fd2.in, 2152);
94 break;
95 case AF_INET6:
96 gtp_sock->len = sizeof(struct sockaddr_in6);
97 setup_sockaddr_in6(&gtp_sock->sockaddr.fd1.in6, 3386);
98 setup_sockaddr_in6(&gtp_sock->sockaddr.fd2.in6, 2152);
Pablo Neira Ayuso0e7a6352024-01-31 18:17:51 +010099 if (setsockopt(fd1, IPPROTO_IPV6, IPV6_V6ONLY, &one, sizeof(one)) < 0)
100 perror("setsockopt IPV6_V6ONLY: ");
101 if (setsockopt(fd2, IPPROTO_IPV6, IPV6_V6ONLY, &one, sizeof(one)) < 0)
102 perror("setsockopt IPV6_V6ONLY: ");
Pablo Neira Ayuso38b5e232023-11-03 17:58:43 +0100103 break;
104 }
105
106 return 0;
107}
108
Pablo Neira Ayuso14506662014-02-20 18:43:15 +0100109int main(int argc, char *argv[])
110{
Pablo Neira Ayuso14506662014-02-20 18:43:15 +0100111 char buf[MNL_SOCKET_BUFFER_SIZE];
Pablo Neira Ayuso38b5e232023-11-03 17:58:43 +0100112 struct gtp_server_sock gtp_sock;
113 int ret, sgsn_mode = 0, family;
Pablo Neira Ayuso14506662014-02-20 18:43:15 +0100114
Harald Welte3bf55c32017-03-15 18:03:42 +0100115 if (argc < 3) {
Pablo Neira Ayuso38b5e232023-11-03 17:58:43 +0100116 printf("Usage: %s add <device> <family> [--sgsn]\n", argv[0]);
Oliver Smith6954da72022-09-07 15:48:16 +0200117 printf(" %s del <device>\n", argv[0]);
Pablo Neira Ayuso14506662014-02-20 18:43:15 +0100118 exit(EXIT_FAILURE);
119 }
120
Pablo Neira Ayuso448bce42016-05-08 21:43:40 +0200121 if (!strcmp(argv[1], "del")) {
122 printf("destroying gtp interface...\n");
123 if (gtp_dev_destroy(argv[2]) < 0)
124 perror("gtp_dev_destroy");
125
126 return 0;
Pablo Neira Ayuso38b5e232023-11-03 17:58:43 +0100127 } else if (!strcmp(argv[1], "add")) {
128 if (argc < 4) {
129 printf("Usage: %s add <device> <family> [--sgsn]\n", argv[0]);
130 exit(EXIT_FAILURE);
131 }
132
133 if (argc == 5 && !strcmp(argv[4], "--sgsn"))
134 sgsn_mode = 1;
Pablo Neira Ayuso448bce42016-05-08 21:43:40 +0200135 }
136
Pablo Neira Ayuso38b5e232023-11-03 17:58:43 +0100137 if (!strcmp(argv[3], "ip"))
138 family = AF_INET;
139 else if (!strcmp(argv[3], "ip6"))
140 family = AF_INET6;
141 else {
142 fprintf(stderr, "unsupport family `%s', expecting `ip' or `ip6'\n",
143 argv[3]);
144 exit(EXIT_FAILURE);
145 }
Harald Welte3bf55c32017-03-15 18:03:42 +0100146
Pablo Neira Ayuso38b5e232023-11-03 17:58:43 +0100147 if (setup_socket(&gtp_sock, family) < 0) {
148 perror("socket");
149 exit(EXIT_FAILURE);
150 }
Pablo Neira Ayuso50826a52016-05-10 18:00:51 +0200151
Pablo Neira Ayuso38b5e232023-11-03 17:58:43 +0100152 if (bind(gtp_sock.fd1, (struct sockaddr *) &gtp_sock.sockaddr.fd1, gtp_sock.len) < 0) {
Pablo Neira Ayuso50826a52016-05-10 18:00:51 +0200153 perror("bind");
154 exit(EXIT_FAILURE);
155 }
Pablo Neira Ayuso38b5e232023-11-03 17:58:43 +0100156 if (bind(gtp_sock.fd2, (struct sockaddr *) &gtp_sock.sockaddr.fd2, gtp_sock.len) < 0) {
Pablo Neira Ayuso50826a52016-05-10 18:00:51 +0200157 perror("bind");
158 exit(EXIT_FAILURE);
159 }
Pablo Neira Ayuso7aa20872014-02-24 11:38:52 +0100160
Harald Welte3bf55c32017-03-15 18:03:42 +0100161 if (sgsn_mode)
Pablo Neira Ayuso38b5e232023-11-03 17:58:43 +0100162 ret = gtp_dev_create_sgsn(-1, argv[2], gtp_sock.fd1, gtp_sock.fd2);
Harald Welte3bf55c32017-03-15 18:03:42 +0100163 else
Pablo Neira Ayuso38b5e232023-11-03 17:58:43 +0100164 ret = gtp_dev_create(-1, argv[2], gtp_sock.fd1, gtp_sock.fd2);
Harald Weltea7a4df32017-03-15 20:53:08 +0100165 if (ret < 0) {
166 perror("cannot create GTP device\n");
Pablo Neira Ayuso14506662014-02-20 18:43:15 +0100167 exit(EXIT_FAILURE);
168 }
169
Pablo Neira Ayuso448bce42016-05-08 21:43:40 +0200170 fprintf(stderr, "WARNING: attaching dummy socket descriptors. Keep "
171 "this process running for testing purposes.\n");
Pablo Neira Ayuso50826a52016-05-10 18:00:51 +0200172
173 while (1) {
Pablo Neira Ayuso38b5e232023-11-03 17:58:43 +0100174 union {
175 struct sockaddr_in addr;
176 struct sockaddr_in6 addr6;
177 } sock;
Pablo Neira Ayuso50826a52016-05-10 18:00:51 +0200178
Pablo Neira Ayuso38b5e232023-11-03 17:58:43 +0100179 ret = recvfrom(gtp_sock.fd1, buf, sizeof(buf), 0,
180 (struct sockaddr *)&sock, &gtp_sock.len);
Pablo Neira Ayuso50826a52016-05-10 18:00:51 +0200181 printf("received %d bytes via UDP socket\n", ret);
182 }
Pablo Neira Ayuso448bce42016-05-08 21:43:40 +0200183
Pablo Neira Ayuso14506662014-02-20 18:43:15 +0100184 return 0;
185}