blob: b1bd7fc2d1448da01e45d025b391187acb1ec2ad [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)
293 LOGTUN(tun, LOGL_ERROR, "Cannot add IPv4 default route\n");
294 else
295 LOGTUN(tun, LOGL_INFO, "Added IPv4 default route\n");
296
297 rc = netdev_add_defaultroute(tun->nl, tun->ifindex, AF_INET6);
298 if (rc < 0)
299 LOGTUN(tun, LOGL_ERROR, "Cannot add IPv6 default route\n");
300 else
301 LOGTUN(tun, LOGL_INFO, "Added IPv6 default route\n");
302 }
303
304 if (pthread_create(&tun->thread, NULL, tun_device_thread, tun)) {
305 LOGTUN(tun, LOGL_ERROR, "Cannot create TUN thread: %s\n", strerror(errno));
306 goto err_free_nl;
307 }
308
309 LOGTUN(tun, LOGL_INFO, "Created (in netns '%s')\n", tun->netns_name);
310 llist_add_tail(&tun->list, &d->tun_devices);
311
312 return tun;
313
314err_free_nl:
315 nl_socket_free(tun->nl);
316err_close:
317 close(tun->fd);
318err_restore_ns:
319 if (tun->netns_name)
320 OSMO_ASSERT(restore_ns(&oldmask) == 0);
321err_close_ns:
322 if (tun->netns_name)
323 close(tun->netns_fd);
324err_free:
325 talloc_free(tun);
326 return NULL;
327}
328
329struct tun_device *
330_tun_device_find(struct gtp_daemon *d, const char *devname)
331{
332 struct tun_device *tun;
333
334 llist_for_each_entry(tun, &d->tun_devices, list) {
335 if (!strcmp(tun->devname, devname))
336 return tun;
337 }
338 return NULL;
339}
340
Harald Welte24557a72020-04-17 22:08:29 +0200341/* find the first tun device within given named netns */
342struct tun_device *
343tun_device_find_netns(struct gtp_daemon *d, const char *netns_name)
344{
345 struct tun_device *tun;
346
347 pthread_rwlock_rdlock(&d->rwlock);
348 llist_for_each_entry(tun, &d->tun_devices, list) {
349 if (!strcmp(tun->netns_name, netns_name)) {
350 pthread_rwlock_unlock(&d->rwlock);
351 return tun;
352 }
353 }
354 pthread_rwlock_unlock(&d->rwlock);
355 return NULL;
356}
357
Harald Weltef7365592020-04-15 21:48:45 +0200358struct tun_device *
359tun_device_find_or_create(struct gtp_daemon *d, const char *devname, const char *netns_name)
360{
361 struct tun_device *tun;
362
363 /* talloc is not thread safe, all alloc/free must come from main thread */
364 ASSERT_MAIN_THREAD(d);
365
366 pthread_rwlock_wrlock(&d->rwlock);
367 tun = _tun_device_find(d, devname);
368 if (tun)
369 tun->use_count++;
370 else
371 tun = _tun_device_create(d, devname, netns_name);
372 pthread_rwlock_unlock(&d->rwlock);
373
374 return tun;
375}
376
377/* UNLOCKED hard/forced destroy; caller must make sure references are cleaned up */
378static void _tun_device_destroy(struct tun_device *tun)
379{
380 /* talloc is not thread safe, all alloc/free must come from main thread */
381 ASSERT_MAIN_THREAD(tun->d);
382
383 pthread_cancel(tun->thread);
384 llist_del(&tun->list);
385 if (tun->netns_name)
386 close(tun->netns_fd);
387 close(tun->fd);
388 nl_socket_free(tun->nl);
389 LOGTUN(tun, LOGL_INFO, "Destroying\n");
390 talloc_free(tun);
391}
392
393/* UNLOCKED remove all objects referencing this tun and then destroy */
394void _tun_device_deref_destroy(struct tun_device *tun)
395{
396 struct gtp_daemon *d = tun->d;
397 char *devname = talloc_strdup(d, tun->devname);
398 struct gtp_tunnel *t, *t2;
399 struct tun_device *tun2;
400
401 /* talloc is not thread safe, all alloc/free must come from main thread */
402 ASSERT_MAIN_THREAD(tun->d);
403
404 llist_for_each_entry_safe(t, t2, &g_daemon->gtp_tunnels, list) {
405 if (t->tun_dev == tun)
406 _gtp_tunnel_destroy(t);
407 }
408 /* _tun_device_destroy may already have been called via
409 * _gtp_tunnel_destroy -> _tun_device_release, so we have to
410 * check if the tun can still be found in the list */
411 tun2 = _tun_device_find(d, devname);
412 if (tun2 && tun2 == tun)
413 _tun_device_destroy(tun2);
414
415 talloc_free(devname);
416}
417
418/* UNLOCKED release a reference; destroy if refcount drops to 0 */
419bool _tun_device_release(struct tun_device *tun)
420{
421 bool released = false;
422
423 /* talloc is not thread safe, all alloc/free must come from main thread */
424 ASSERT_MAIN_THREAD(tun->d);
425
426 tun->use_count--;
427 if (tun->use_count == 0) {
428 _tun_device_destroy(tun);
429 released = true;
430 } else
431 LOGTUN(tun, LOGL_DEBUG, "Release; new use_count=%lu\n", tun->use_count);
432
433 return released;
434}
435
436/* release a reference; destroy if refcount drops to 0 */
437bool tun_device_release(struct tun_device *tun)
438{
439 struct gtp_daemon *d = tun->d;
440 bool released;
441
442 /* talloc is not thread safe, all alloc/free must come from main thread */
443 ASSERT_MAIN_THREAD(tun->d);
444
445 pthread_rwlock_wrlock(&d->rwlock);
446 released = _tun_device_release(tun);
447 pthread_rwlock_unlock(&d->rwlock);
448
449 return released;
450}