blob: 7d1948f7f1b0a186b0c50f443b13cdbd9f54267b [file] [log] [blame]
Harald Weltef7365592020-04-15 21:48:45 +02001/* SPDX-License-Identifier: GPL-2.0 */
2#include <unistd.h>
3#include <stdint.h>
4#include <stdbool.h>
5#include <stdlib.h>
6#include <string.h>
7#include <stdio.h>
8#include <errno.h>
9#include <sys/types.h>
10#include <sys/socket.h>
11#include <sys/stat.h>
12#include <fcntl.h>
13#include <signal.h>
14#include <netdb.h>
15
16#include <netinet/ip.h>
17#include <netinet/ip6.h>
18
19#include <pthread.h>
20
21#include <linux/if.h>
22#include <linux/if_tun.h>
23#include <sys/ioctl.h>
24
Harald Weltef2be0992020-04-20 11:12:42 +000025#include <linux/netlink.h>
Harald Weltef7365592020-04-15 21:48:45 +020026#include <netlink/socket.h>
27#include <netlink/route/link.h>
28
29#include <osmocom/core/linuxlist.h>
30#include <osmocom/core/talloc.h>
31#include <osmocom/core/logging.h>
32#include <osmocom/core/utils.h>
33
34#include "gtp.h"
35#include "internal.h"
36#include "netns.h"
37
38/***********************************************************************
39 * TUN Device
40 ***********************************************************************/
41
42#define LOGTUN(tun, lvl, fmt, args ...) \
43 LOGP(DTUN, lvl, "%s: " fmt, (tun)->devname, ## args)
44
45/* extracted information from a packet */
46struct pkt_info {
47 struct sockaddr_storage saddr;
48 struct sockaddr_storage daddr;
49 uint8_t proto;
50};
51
52static int parse_pkt(struct pkt_info *out, const uint8_t *in, unsigned int in_len)
53{
54 const struct iphdr *ip4 = (struct iphdr *) in;
55 const uint16_t *l4h = NULL;
56
57 memset(out, 0, sizeof(*out));
58
59 if (ip4->version == 4) {
60 struct sockaddr_in *saddr4 = (struct sockaddr_in *) &out->saddr;
61 struct sockaddr_in *daddr4 = (struct sockaddr_in *) &out->daddr;
62
63 if (in_len < sizeof(*ip4) || in_len < 4*ip4->ihl)
64 return -1;
65
66 saddr4->sin_family = AF_INET;
67 saddr4->sin_addr.s_addr = ip4->saddr;
68
69 daddr4->sin_family = AF_INET;
70 daddr4->sin_addr.s_addr = ip4->daddr;
71
72 out->proto = ip4->protocol;
73 l4h = (const uint16_t *) (in + sizeof(*ip4));
74
75 switch (out->proto) {
76 case IPPROTO_TCP:
77 case IPPROTO_UDP:
78 case IPPROTO_DCCP:
79 case IPPROTO_SCTP:
80 case IPPROTO_UDPLITE:
81 saddr4->sin_port = ntohs(l4h[0]);
82 daddr4->sin_port = ntohs(l4h[1]);
83 break;
84 default:
85 break;
86 }
87 } else if (ip4->version == 6) {
88 const struct ip6_hdr *ip6 = (struct ip6_hdr *) in;
89 struct sockaddr_in6 *saddr6 = (struct sockaddr_in6 *) &out->saddr;
90 struct sockaddr_in6 *daddr6 = (struct sockaddr_in6 *) &out->daddr;
91
92 if (in_len < sizeof(*ip6))
93 return -1;
94
95 saddr6->sin6_family = AF_INET6;
96 saddr6->sin6_addr = ip6->ip6_src;
97
98 daddr6->sin6_family = AF_INET6;
99 daddr6->sin6_addr = ip6->ip6_dst;
100
101 /* FIXME: ext hdr */
102 out->proto = ip6->ip6_nxt;
103 l4h = (const uint16_t *) (in + sizeof(*ip6));
104
105 switch (out->proto) {
106 case IPPROTO_TCP:
107 case IPPROTO_UDP:
108 case IPPROTO_DCCP:
109 case IPPROTO_SCTP:
110 case IPPROTO_UDPLITE:
111 saddr6->sin6_port = ntohs(l4h[0]);
112 daddr6->sin6_port = ntohs(l4h[1]);
113 break;
114 default:
115 break;
116 }
117 } else
118 return -1;
119
120 return 0;
121}
122
123/* one thread for reading from each TUN device (TUN -> GTP encapsulation) */
124static void *tun_device_thread(void *arg)
125{
126 struct tun_device *tun = (struct tun_device *)arg;
127 struct gtp_daemon *d = tun->d;
128
129 uint8_t base_buffer[MAX_UDP_PACKET+sizeof(struct gtp1_header)];
130 struct gtp1_header *gtph = (struct gtp1_header *)base_buffer;
131 uint8_t *buffer = base_buffer + sizeof(struct gtp1_header);
132
133 struct sockaddr_storage daddr;
134
135 /* initialize the fixed part of the GTP header */
136 gtph->flags = 0x30;
137 gtph->type = GTP_TPDU;
138
139 while (1) {
140 struct gtp_tunnel *t;
141 struct pkt_info pinfo;
142 int rc, nread, outfd;
143
144 /* 1) read from tun */
145 rc = read(tun->fd, buffer, MAX_UDP_PACKET);
146 if (rc < 0) {
147 LOGTUN(tun, LOGL_FATAL, "Error readingfrom tun device: %s\n", strerror(errno));
148 exit(1);
149 }
150 nread = rc;
151 gtph->length = htons(nread);
152
153 rc = parse_pkt(&pinfo, buffer, nread);
154 if (rc < 0) {
155 LOGTUN(tun, LOGL_NOTICE, "Error parsing IP packet: %s\n",
156 osmo_hexdump(buffer, nread));
157 continue;
158 }
159
160 if (pinfo.saddr.ss_family == AF_INET6 && pinfo.proto == IPPROTO_ICMPV6) {
161 /* 2) TODO: magic voodoo for IPv6 neighbor discovery */
162 }
163
164 /* 3) look-up tunnel based on source IP address (+ filter) */
165 pthread_rwlock_rdlock(&d->rwlock);
166 t = _gtp_tunnel_find_eua(tun, (struct sockaddr *) &pinfo.saddr, pinfo.proto);
167 if (!t) {
168 char host[128];
169 char port[8];
170 pthread_rwlock_unlock(&d->rwlock);
171 getnameinfo((const struct sockaddr *)&pinfo.saddr,
172 sizeof(pinfo.saddr), host, sizeof(host), port, sizeof(port),
173 NI_NUMERICHOST | NI_NUMERICSERV);
174 LOGTUN(tun, LOGL_NOTICE, "No tunnel found for source address %s:%s\n", host, port);
175 continue;
176 }
177 outfd = t->gtp_ep->fd;
178 memcpy(&daddr, &t->remote_udp, sizeof(daddr));
179 gtph->tid = htonl(t->tx_teid);
180 pthread_rwlock_unlock(&d->rwlock);
181
182 /* 4) write to GTP/UDP socket */
183 rc = sendto(outfd, base_buffer, nread+sizeof(*gtph), 0,
184 (struct sockaddr *)&daddr, sizeof(daddr));
185 if (rc < 0) {
186 LOGTUN(tun, LOGL_FATAL, "Error Writing to UDP socket: %s\n", strerror(errno));
187 exit(1);
188 }
189 }
190}
191
192static int tun_open(int flags, const char *name)
193{
194 struct ifreq ifr;
195 int fd, rc;
196
197 fd = open("/dev/net/tun", O_RDWR);
198 if (fd < 0) {
199 LOGP(DTUN, LOGL_ERROR, "Cannot open /dev/net/tun: %s\n", strerror(errno));
200 return fd;
201 }
202
203 memset(&ifr, 0, sizeof(ifr));
204 ifr.ifr_flags = IFF_TUN | IFF_NO_PI | flags;
205 if (name) {
206 /* if a TUN interface name was specified, put it in the structure; otherwise,
207 the kernel will try to allocate the "next" device of the specified type */
Harald Weltef23abd72020-04-20 12:09:32 +0200208 osmo_strlcpy(ifr.ifr_name, name, IFNAMSIZ);
Harald Weltef7365592020-04-15 21:48:45 +0200209 }
210
211 /* try to create the device */
212 rc = ioctl(fd, TUNSETIFF, (void *) &ifr);
213 if (rc < 0) {
214 close(fd);
215 return rc;
216 }
217
218 /* FIXME: read name back from device? */
219 /* FIXME: SIOCSIFTXQLEN / SIOCSIFFLAGS */
220
221 return fd;
222}
223
224static struct tun_device *
225_tun_device_create(struct gtp_daemon *d, const char *devname, const char *netns_name)
226{
227 struct rtnl_link *link;
228 struct tun_device *tun;
229 sigset_t oldmask;
230 int rc;
231
232 tun = talloc_zero(d, struct tun_device);
233 if (!tun)
234 return NULL;
235
236 tun->d = d;
237 tun->use_count = 1;
238 tun->devname = talloc_strdup(tun, devname);
239
240 if (netns_name) {
241 tun->netns_name = talloc_strdup(tun, netns_name);
242 tun->netns_fd = get_nsfd(tun->netns_name);
243 if (tun->netns_fd < 0) {
244 LOGTUN(tun, LOGL_ERROR, "Cannot obtain netns file descriptor: %s\n",
245 strerror(errno));
246 goto err_free;
247 }
248 }
249
250 /* temporarily switch to specified namespace to create tun device */
251 if (tun->netns_name) {
252 rc = switch_ns(tun->netns_fd, &oldmask);
253 if (rc < 0) {
254 LOGTUN(tun, LOGL_ERROR, "Cannot switch to netns '%s': %s\n",
255 tun->netns_name, strerror(errno));
256 goto err_close_ns;
257 }
258 }
259
260 tun->fd = tun_open(0, tun->devname);
261 if (tun->fd < 0) {
262 LOGTUN(tun, LOGL_ERROR, "Cannot open TUN device: %s\n", strerror(errno));
263 goto err_restore_ns;
264 }
265
266 tun->nl = nl_socket_alloc();
267 if (!tun->nl || nl_connect(tun->nl, NETLINK_ROUTE) < 0) {
268 LOGTUN(tun, LOGL_ERROR, "Cannot create netlink socket in namespace '%s'\n",
269 tun->netns_name);
270 goto err_close;
271 }
272
273 rc = rtnl_link_get_kernel(tun->nl, 0, tun->devname, &link);
274 if (rc < 0) {
275 LOGTUN(tun, LOGL_ERROR, "Cannot get ifindex for netif after create?!?\n");
276 goto err_free_nl;
277 }
278 tun->ifindex = rtnl_link_get_ifindex(link);
279 rtnl_link_put(link);
280
281 /* switch back to default namespace before creating new thread */
282 if (tun->netns_name)
283 OSMO_ASSERT(restore_ns(&oldmask) == 0);
284
285 /* bring the network device up */
286 rc = netdev_set_link(tun->nl, tun->ifindex, true);
287 if (rc < 0)
288 LOGTUN(tun, LOGL_ERROR, "Cannot set interface to 'up'\n");
289
290 if (tun->netns_name) {
291 rc = netdev_add_defaultroute(tun->nl, tun->ifindex, AF_INET);
292 if (rc < 0)
Vadim Yanitskiy115a1762022-01-31 02:36:00 +0600293 LOGTUN(tun, LOGL_ERROR, "Cannot add IPv4 default route "
294 "(rc=%d): %s\n", rc, nl_geterror(rc));
Harald Weltef7365592020-04-15 21:48:45 +0200295 else
296 LOGTUN(tun, LOGL_INFO, "Added IPv4 default route\n");
297
298 rc = netdev_add_defaultroute(tun->nl, tun->ifindex, AF_INET6);
299 if (rc < 0)
Vadim Yanitskiy115a1762022-01-31 02:36:00 +0600300 LOGTUN(tun, LOGL_ERROR, "Cannot add IPv6 default route "
301 "(rc=%d): %s\n", rc, nl_geterror(rc));
Harald Weltef7365592020-04-15 21:48:45 +0200302 else
303 LOGTUN(tun, LOGL_INFO, "Added IPv6 default route\n");
304 }
305
306 if (pthread_create(&tun->thread, NULL, tun_device_thread, tun)) {
307 LOGTUN(tun, LOGL_ERROR, "Cannot create TUN thread: %s\n", strerror(errno));
308 goto err_free_nl;
309 }
310
311 LOGTUN(tun, LOGL_INFO, "Created (in netns '%s')\n", tun->netns_name);
312 llist_add_tail(&tun->list, &d->tun_devices);
313
314 return tun;
315
316err_free_nl:
317 nl_socket_free(tun->nl);
318err_close:
319 close(tun->fd);
320err_restore_ns:
321 if (tun->netns_name)
322 OSMO_ASSERT(restore_ns(&oldmask) == 0);
323err_close_ns:
324 if (tun->netns_name)
325 close(tun->netns_fd);
326err_free:
327 talloc_free(tun);
328 return NULL;
329}
330
331struct tun_device *
332_tun_device_find(struct gtp_daemon *d, const char *devname)
333{
334 struct tun_device *tun;
335
336 llist_for_each_entry(tun, &d->tun_devices, list) {
337 if (!strcmp(tun->devname, devname))
338 return tun;
339 }
340 return NULL;
341}
342
Harald Welte24557a72020-04-17 22:08:29 +0200343/* find the first tun device within given named netns */
344struct tun_device *
345tun_device_find_netns(struct gtp_daemon *d, const char *netns_name)
346{
347 struct tun_device *tun;
348
349 pthread_rwlock_rdlock(&d->rwlock);
350 llist_for_each_entry(tun, &d->tun_devices, list) {
351 if (!strcmp(tun->netns_name, netns_name)) {
352 pthread_rwlock_unlock(&d->rwlock);
353 return tun;
354 }
355 }
356 pthread_rwlock_unlock(&d->rwlock);
357 return NULL;
358}
359
Harald Weltef7365592020-04-15 21:48:45 +0200360struct tun_device *
361tun_device_find_or_create(struct gtp_daemon *d, const char *devname, const char *netns_name)
362{
363 struct tun_device *tun;
364
365 /* talloc is not thread safe, all alloc/free must come from main thread */
366 ASSERT_MAIN_THREAD(d);
367
368 pthread_rwlock_wrlock(&d->rwlock);
369 tun = _tun_device_find(d, devname);
370 if (tun)
371 tun->use_count++;
372 else
373 tun = _tun_device_create(d, devname, netns_name);
374 pthread_rwlock_unlock(&d->rwlock);
375
376 return tun;
377}
378
379/* UNLOCKED hard/forced destroy; caller must make sure references are cleaned up */
380static void _tun_device_destroy(struct tun_device *tun)
381{
382 /* talloc is not thread safe, all alloc/free must come from main thread */
383 ASSERT_MAIN_THREAD(tun->d);
384
385 pthread_cancel(tun->thread);
386 llist_del(&tun->list);
387 if (tun->netns_name)
388 close(tun->netns_fd);
389 close(tun->fd);
390 nl_socket_free(tun->nl);
391 LOGTUN(tun, LOGL_INFO, "Destroying\n");
392 talloc_free(tun);
393}
394
395/* UNLOCKED remove all objects referencing this tun and then destroy */
396void _tun_device_deref_destroy(struct tun_device *tun)
397{
398 struct gtp_daemon *d = tun->d;
399 char *devname = talloc_strdup(d, tun->devname);
400 struct gtp_tunnel *t, *t2;
401 struct tun_device *tun2;
402
403 /* talloc is not thread safe, all alloc/free must come from main thread */
404 ASSERT_MAIN_THREAD(tun->d);
405
406 llist_for_each_entry_safe(t, t2, &g_daemon->gtp_tunnels, list) {
407 if (t->tun_dev == tun)
408 _gtp_tunnel_destroy(t);
409 }
410 /* _tun_device_destroy may already have been called via
411 * _gtp_tunnel_destroy -> _tun_device_release, so we have to
412 * check if the tun can still be found in the list */
413 tun2 = _tun_device_find(d, devname);
414 if (tun2 && tun2 == tun)
415 _tun_device_destroy(tun2);
416
417 talloc_free(devname);
418}
419
420/* UNLOCKED release a reference; destroy if refcount drops to 0 */
421bool _tun_device_release(struct tun_device *tun)
422{
423 bool released = false;
424
425 /* talloc is not thread safe, all alloc/free must come from main thread */
426 ASSERT_MAIN_THREAD(tun->d);
427
428 tun->use_count--;
429 if (tun->use_count == 0) {
430 _tun_device_destroy(tun);
431 released = true;
432 } else
433 LOGTUN(tun, LOGL_DEBUG, "Release; new use_count=%lu\n", tun->use_count);
434
435 return released;
436}
437
438/* release a reference; destroy if refcount drops to 0 */
439bool tun_device_release(struct tun_device *tun)
440{
441 struct gtp_daemon *d = tun->d;
442 bool released;
443
444 /* talloc is not thread safe, all alloc/free must come from main thread */
445 ASSERT_MAIN_THREAD(tun->d);
446
447 pthread_rwlock_wrlock(&d->rwlock);
448 released = _tun_device_release(tun);
449 pthread_rwlock_unlock(&d->rwlock);
450
451 return released;
452}