blob: 0b14bc54166ed4ee02227de96273816b1fedbcd0 [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>
Pablo Neira Ayusod4894882024-02-15 21:08:26 +010042#include <errno.h>
Pablo Neira Ayuso448bce42016-05-08 21:43:40 +020043
Pablo Neira Ayuso38b5e232023-11-03 17:58:43 +010044struct gtp_server_sock {
45 int family;
46 int fd1;
47 int fd2;
48 socklen_t len;
49 struct {
50 union {
51 struct sockaddr_in in;
52 struct sockaddr_in6 in6;
53 } fd1;
54 union {
55 struct sockaddr_in in;
56 struct sockaddr_in6 in6;
57 } fd2;
58 } sockaddr;
Pablo Neira Ayusod4894882024-02-15 21:08:26 +010059 union {
60 struct in_addr v4;
61 struct in6_addr v6;
62 } addr;
Pablo Neira Ayuso38b5e232023-11-03 17:58:43 +010063};
64
Pablo Neira Ayusod4894882024-02-15 21:08:26 +010065static void setup_sockaddr_in(struct sockaddr_in *sockaddr, struct in_addr *in,
66 uint16_t port)
Pablo Neira Ayuso38b5e232023-11-03 17:58:43 +010067{
68 sockaddr->sin_family = AF_INET;
69 sockaddr->sin_port = htons(port);
Pablo Neira Ayusod4894882024-02-15 21:08:26 +010070 sockaddr->sin_addr = *in;
Pablo Neira Ayuso38b5e232023-11-03 17:58:43 +010071}
72
Pablo Neira Ayusod4894882024-02-15 21:08:26 +010073static void setup_sockaddr_in6(struct sockaddr_in6 *sockaddr, struct in6_addr *in6,
74 uint16_t port)
Pablo Neira Ayuso38b5e232023-11-03 17:58:43 +010075{
76 sockaddr->sin6_family = AF_INET6;
77 sockaddr->sin6_port = htons(port);
Pablo Neira Ayusod4894882024-02-15 21:08:26 +010078 sockaddr->sin6_addr = *in6;
Pablo Neira Ayuso38b5e232023-11-03 17:58:43 +010079}
80
81static int setup_socket(struct gtp_server_sock *gtp_sock, int family)
82{
Pablo Neira Ayuso9911f6b2024-01-31 18:17:51 +010083 int one = 1;
Pablo Neira Ayuso38b5e232023-11-03 17:58:43 +010084
Oliver Smith79281522024-02-19 12:15:40 +010085 gtp_sock->fd1 = socket(family, SOCK_DGRAM, 0);
86 gtp_sock->fd2 = socket(family, SOCK_DGRAM, 0);
87
88 if (gtp_sock->fd1 < 0 || gtp_sock->fd2 < 0)
Pablo Neira Ayuso38b5e232023-11-03 17:58:43 +010089 return -1;
90
Pablo Neira Ayuso38b5e232023-11-03 17:58:43 +010091 gtp_sock->family = family;
Pablo Neira Ayuso38b5e232023-11-03 17:58:43 +010092
93 switch (family) {
94 case AF_INET:
95 gtp_sock->len = sizeof(struct sockaddr_in);
Pablo Neira Ayusod4894882024-02-15 21:08:26 +010096 setup_sockaddr_in(&gtp_sock->sockaddr.fd1.in,
97 &gtp_sock->addr.v4, 3386);
98 setup_sockaddr_in(&gtp_sock->sockaddr.fd2.in,
99 &gtp_sock->addr.v4, 2152);
Pablo Neira Ayuso38b5e232023-11-03 17:58:43 +0100100 break;
101 case AF_INET6:
102 gtp_sock->len = sizeof(struct sockaddr_in6);
Pablo Neira Ayusod4894882024-02-15 21:08:26 +0100103 setup_sockaddr_in6(&gtp_sock->sockaddr.fd1.in6,
104 &gtp_sock->addr.v6, 3386);
105 setup_sockaddr_in6(&gtp_sock->sockaddr.fd2.in6,
106 &gtp_sock->addr.v6, 2152);
Oliver Smith79281522024-02-19 12:15:40 +0100107 if (setsockopt(gtp_sock->fd1, IPPROTO_IPV6, IPV6_V6ONLY, &one, sizeof(one)) < 0)
Pablo Neira Ayuso9911f6b2024-01-31 18:17:51 +0100108 perror("setsockopt IPV6_V6ONLY: ");
Oliver Smith79281522024-02-19 12:15:40 +0100109 if (setsockopt(gtp_sock->fd2, IPPROTO_IPV6, IPV6_V6ONLY, &one, sizeof(one)) < 0)
Pablo Neira Ayuso9911f6b2024-01-31 18:17:51 +0100110 perror("setsockopt IPV6_V6ONLY: ");
Pablo Neira Ayuso38b5e232023-11-03 17:58:43 +0100111 break;
112 }
113
114 return 0;
115}
116
Oliver Smith79281522024-02-19 12:15:40 +0100117static void close_socket(struct gtp_server_sock *gtp_sock)
118{
119 if (gtp_sock->fd1 != -1) {
120 close(gtp_sock->fd1);
121 gtp_sock->fd1 = -1;
122 }
123
124 if (gtp_sock->fd2 != -1) {
125 close(gtp_sock->fd2);
126 gtp_sock->fd2 = -1;
127 }
128}
129
Pablo Neira Ayuso14506662014-02-20 18:43:15 +0100130int main(int argc, char *argv[])
131{
Pablo Neira Ayuso14506662014-02-20 18:43:15 +0100132 char buf[MNL_SOCKET_BUFFER_SIZE];
Pablo Neira Ayuso38b5e232023-11-03 17:58:43 +0100133 struct gtp_server_sock gtp_sock;
134 int ret, sgsn_mode = 0, family;
Pablo Neira Ayusod4894882024-02-15 21:08:26 +0100135 const char *addr = NULL;
136
137 memset(&gtp_sock, 0, sizeof(gtp_sock));
Pablo Neira Ayuso14506662014-02-20 18:43:15 +0100138
Harald Welte3bf55c32017-03-15 18:03:42 +0100139 if (argc < 3) {
Pablo Neira Ayusod4894882024-02-15 21:08:26 +0100140 printf("Usage: %s add <device> <family> [--sgsn] [<address>]\n", argv[0]);
Oliver Smith6954da72022-09-07 15:48:16 +0200141 printf(" %s del <device>\n", argv[0]);
Pablo Neira Ayuso14506662014-02-20 18:43:15 +0100142 exit(EXIT_FAILURE);
143 }
144
Pablo Neira Ayuso448bce42016-05-08 21:43:40 +0200145 if (!strcmp(argv[1], "del")) {
146 printf("destroying gtp interface...\n");
147 if (gtp_dev_destroy(argv[2]) < 0)
148 perror("gtp_dev_destroy");
149
150 return 0;
Pablo Neira Ayuso38b5e232023-11-03 17:58:43 +0100151 } else if (!strcmp(argv[1], "add")) {
152 if (argc < 4) {
Pablo Neira Ayusod4894882024-02-15 21:08:26 +0100153 printf("Usage: %s add <device> <family> [--sgsn] [<address>]\n", argv[0]);
Pablo Neira Ayuso38b5e232023-11-03 17:58:43 +0100154 exit(EXIT_FAILURE);
155 }
156
Pablo Neira Ayusod4894882024-02-15 21:08:26 +0100157 if (argc == 5) {
158 if (!strcmp(argv[4], "--sgsn"))
159 sgsn_mode = 1;
160 else
161 addr = argv[4];
162 }
163
164 if (argc == 6) {
165 if (!strcmp(argv[4], "--sgsn"))
166 sgsn_mode = 1;
167
168 addr = argv[5];
169 }
Pablo Neira Ayuso448bce42016-05-08 21:43:40 +0200170 }
171
Pablo Neira Ayuso38b5e232023-11-03 17:58:43 +0100172 if (!strcmp(argv[3], "ip"))
173 family = AF_INET;
174 else if (!strcmp(argv[3], "ip6"))
175 family = AF_INET6;
176 else {
177 fprintf(stderr, "unsupport family `%s', expecting `ip' or `ip6'\n",
178 argv[3]);
179 exit(EXIT_FAILURE);
180 }
Harald Welte3bf55c32017-03-15 18:03:42 +0100181
Pablo Neira Ayusod4894882024-02-15 21:08:26 +0100182 if (addr) {
183 if (!inet_pton(family, addr, &gtp_sock.addr)) {
184 fprintf(stderr, "invalid listener address: %s\n",
185 strerror(errno));
186 exit(EXIT_FAILURE);
187 }
188 } else {
189 switch (family) {
190 case AF_INET:
191 gtp_sock.addr.v4.s_addr = INADDR_ANY;
192 break;
193 case AF_INET6:
194 gtp_sock.addr.v6 = in6addr_any;
195 break;
196 }
197 }
198
Pablo Neira Ayuso38b5e232023-11-03 17:58:43 +0100199 if (setup_socket(&gtp_sock, family) < 0) {
200 perror("socket");
Oliver Smith79281522024-02-19 12:15:40 +0100201 close_socket(&gtp_sock);
Pablo Neira Ayuso38b5e232023-11-03 17:58:43 +0100202 exit(EXIT_FAILURE);
203 }
Pablo Neira Ayuso50826a52016-05-10 18:00:51 +0200204
Pablo Neira Ayuso38b5e232023-11-03 17:58:43 +0100205 if (bind(gtp_sock.fd1, (struct sockaddr *) &gtp_sock.sockaddr.fd1, gtp_sock.len) < 0) {
Pablo Neira Ayuso50826a52016-05-10 18:00:51 +0200206 perror("bind");
Oliver Smith79281522024-02-19 12:15:40 +0100207 close_socket(&gtp_sock);
Pablo Neira Ayuso50826a52016-05-10 18:00:51 +0200208 exit(EXIT_FAILURE);
209 }
Pablo Neira Ayuso38b5e232023-11-03 17:58:43 +0100210 if (bind(gtp_sock.fd2, (struct sockaddr *) &gtp_sock.sockaddr.fd2, gtp_sock.len) < 0) {
Pablo Neira Ayuso50826a52016-05-10 18:00:51 +0200211 perror("bind");
Oliver Smith79281522024-02-19 12:15:40 +0100212 close_socket(&gtp_sock);
Pablo Neira Ayuso50826a52016-05-10 18:00:51 +0200213 exit(EXIT_FAILURE);
214 }
Pablo Neira Ayuso7aa20872014-02-24 11:38:52 +0100215
Harald Welte3bf55c32017-03-15 18:03:42 +0100216 if (sgsn_mode)
Pablo Neira Ayuso38b5e232023-11-03 17:58:43 +0100217 ret = gtp_dev_create_sgsn(-1, argv[2], gtp_sock.fd1, gtp_sock.fd2);
Harald Welte3bf55c32017-03-15 18:03:42 +0100218 else
Pablo Neira Ayuso38b5e232023-11-03 17:58:43 +0100219 ret = gtp_dev_create(-1, argv[2], gtp_sock.fd1, gtp_sock.fd2);
Harald Weltea7a4df32017-03-15 20:53:08 +0100220 if (ret < 0) {
221 perror("cannot create GTP device\n");
Oliver Smith79281522024-02-19 12:15:40 +0100222 close_socket(&gtp_sock);
Pablo Neira Ayuso14506662014-02-20 18:43:15 +0100223 exit(EXIT_FAILURE);
224 }
225
Pablo Neira Ayuso448bce42016-05-08 21:43:40 +0200226 fprintf(stderr, "WARNING: attaching dummy socket descriptors. Keep "
227 "this process running for testing purposes.\n");
Pablo Neira Ayuso50826a52016-05-10 18:00:51 +0200228
229 while (1) {
Pablo Neira Ayuso38b5e232023-11-03 17:58:43 +0100230 union {
231 struct sockaddr_in addr;
232 struct sockaddr_in6 addr6;
233 } sock;
Pablo Neira Ayuso50826a52016-05-10 18:00:51 +0200234
Pablo Neira Ayuso38b5e232023-11-03 17:58:43 +0100235 ret = recvfrom(gtp_sock.fd1, buf, sizeof(buf), 0,
236 (struct sockaddr *)&sock, &gtp_sock.len);
Pablo Neira Ayuso50826a52016-05-10 18:00:51 +0200237 printf("received %d bytes via UDP socket\n", ret);
238 }
Pablo Neira Ayuso448bce42016-05-08 21:43:40 +0200239
Pablo Neira Ayuso14506662014-02-20 18:43:15 +0100240 return 0;
241}