mirror of
https://gitea.osmocom.org/cellular-infrastructure/osmo-ggsn.git
synced 2025-10-23 08:22:07 +00:00
ggsn: Use osmo_netdev_addaddr() libosmocore API
This allows dropping a lot of duplicated code. While at it, drop references to non-linux systems, which are not maintained anymore. Param "dstaddr" was not used anywhere in the old APIs, so it can also be dropped. Param "tun->routes" was also used in BSD code, so it can also be dropped. Change-Id: I1fccfd658542481cd61536fbd3c7a3a32a1c253b
This commit is contained in:
13
ggsn/ggsn.c
13
ggsn/ggsn.c
@@ -264,7 +264,7 @@ int apn_start(struct apn_ctx *apn)
|
||||
if (apn->v4.cfg.ifconfig_prefix.addr.len) {
|
||||
LOGPAPN(LOGL_INFO, apn, "Setting tun IP address %s\n",
|
||||
in46p_ntoa(&apn->v4.cfg.ifconfig_prefix));
|
||||
if (tun_addaddr(apn->tun.tun, &apn->v4.cfg.ifconfig_prefix.addr, NULL,
|
||||
if (tun_addaddr(apn->tun.tun, &apn->v4.cfg.ifconfig_prefix.addr,
|
||||
apn->v4.cfg.ifconfig_prefix.prefixlen)) {
|
||||
LOGPAPN(LOGL_ERROR, apn, "Failed to set tun IPv4 address %s: %s\n",
|
||||
in46p_ntoa(&apn->v4.cfg.ifconfig_prefix), strerror(errno));
|
||||
@@ -276,7 +276,7 @@ int apn_start(struct apn_ctx *apn)
|
||||
if (apn->v6.cfg.ifconfig_prefix.addr.len) {
|
||||
LOGPAPN(LOGL_INFO, apn, "Setting tun IPv6 address %s\n",
|
||||
in46p_ntoa(&apn->v6.cfg.ifconfig_prefix));
|
||||
if (tun_addaddr(apn->tun.tun, &apn->v6.cfg.ifconfig_prefix.addr, NULL,
|
||||
if (tun_addaddr(apn->tun.tun, &apn->v6.cfg.ifconfig_prefix.addr,
|
||||
apn->v6.cfg.ifconfig_prefix.prefixlen)) {
|
||||
LOGPAPN(LOGL_ERROR, apn, "Failed to set tun IPv6 address %s: %s. "
|
||||
"Ensure you have ipv6 support and not used the disable_ipv6 sysctl?\n",
|
||||
@@ -289,7 +289,7 @@ int apn_start(struct apn_ctx *apn)
|
||||
if (apn->v6.cfg.ll_prefix.addr.len) {
|
||||
LOGPAPN(LOGL_INFO, apn, "Setting tun IPv6 link-local address %s\n",
|
||||
in46p_ntoa(&apn->v6.cfg.ll_prefix));
|
||||
if (tun_addaddr(apn->tun.tun, &apn->v6.cfg.ll_prefix.addr, NULL,
|
||||
if (tun_addaddr(apn->tun.tun, &apn->v6.cfg.ll_prefix.addr,
|
||||
apn->v6.cfg.ll_prefix.prefixlen)) {
|
||||
LOGPAPN(LOGL_ERROR, apn, "Failed to set tun IPv6 link-local address %s: %s. "
|
||||
"Ensure you have ipv6 support and not used the disable_ipv6 sysctl?\n",
|
||||
@@ -300,6 +300,13 @@ int apn_start(struct apn_ctx *apn)
|
||||
apn->v6_lladdr = apn->v6.cfg.ll_prefix.addr.v6;
|
||||
}
|
||||
|
||||
rc = osmo_netdev_ifupdown(apn->tun.tun->netdev, true);
|
||||
if (rc < 0) {
|
||||
LOGPAPN(LOGL_ERROR, apn, "Failed to set tun interface UP: %s\n", strerror(errno));
|
||||
apn_stop(apn);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (apn->tun.cfg.ipup_script) {
|
||||
LOGPAPN(LOGL_INFO, apn, "Running ip-up script %s\n",
|
||||
apn->tun.cfg.ipup_script);
|
||||
|
508
lib/netdev.c
508
lib/netdev.c
@@ -37,522 +37,14 @@
|
||||
#include <net/route.h>
|
||||
#include <net/if.h>
|
||||
|
||||
#if defined(__linux__)
|
||||
#include <linux/netlink.h>
|
||||
#include <linux/rtnetlink.h>
|
||||
|
||||
#elif defined (__FreeBSD__)
|
||||
#include <net/if_var.h>
|
||||
#include <netinet/in_var.h>
|
||||
|
||||
#elif defined (__APPLE__)
|
||||
#include <net/if.h>
|
||||
|
||||
#else
|
||||
#error "Unknown platform!"
|
||||
#endif
|
||||
|
||||
#include "netdev.h"
|
||||
#include "syserr.h"
|
||||
|
||||
#if defined(__linux__)
|
||||
|
||||
#include <linux/ipv6.h>
|
||||
|
||||
static int netdev_nlattr(struct nlmsghdr *n, int nsize, int type, void *d, int dlen)
|
||||
{
|
||||
int len = RTA_LENGTH(dlen);
|
||||
int alen = NLMSG_ALIGN(n->nlmsg_len);
|
||||
struct rtattr *rta = (struct rtattr *)(((void *)n) + alen);
|
||||
if (alen + len > nsize)
|
||||
return -1;
|
||||
rta->rta_len = len;
|
||||
rta->rta_type = type;
|
||||
memcpy(RTA_DATA(rta), d, dlen);
|
||||
n->nlmsg_len = alen + len;
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
static int netdev_sifflags(const char *devname, int flags)
|
||||
{
|
||||
struct ifreq ifr;
|
||||
int fd;
|
||||
|
||||
memset(&ifr, '\0', sizeof(ifr));
|
||||
ifr.ifr_flags = flags;
|
||||
strncpy(ifr.ifr_name, devname, IFNAMSIZ);
|
||||
ifr.ifr_name[IFNAMSIZ - 1] = 0; /* Make sure to terminate */
|
||||
if ((fd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
|
||||
SYS_ERR(DTUN, LOGL_ERROR, errno, "socket() failed");
|
||||
return -1;
|
||||
}
|
||||
if (ioctl(fd, SIOCSIFFLAGS, &ifr)) {
|
||||
SYS_ERR(DTUN, LOGL_ERROR, errno,
|
||||
"ioctl(SIOCSIFFLAGS) failed");
|
||||
close(fd);
|
||||
return -1;
|
||||
}
|
||||
close(fd);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int netdev_setaddr4(const char *devname, struct in_addr *addr,
|
||||
struct in_addr *dstaddr, struct in_addr *netmask)
|
||||
{
|
||||
struct ifreq ifr;
|
||||
int fd;
|
||||
|
||||
memset(&ifr, '\0', sizeof(ifr));
|
||||
ifr.ifr_addr.sa_family = AF_INET;
|
||||
ifr.ifr_dstaddr.sa_family = AF_INET;
|
||||
|
||||
#if defined(__linux__)
|
||||
ifr.ifr_netmask.sa_family = AF_INET;
|
||||
#elif defined(__FreeBSD__) || defined (__APPLE__)
|
||||
((struct sockaddr_in *)&ifr.ifr_addr)->sin_len =
|
||||
sizeof(struct sockaddr_in);
|
||||
((struct sockaddr_in *)&ifr.ifr_dstaddr)->sin_len =
|
||||
sizeof(struct sockaddr_in);
|
||||
#endif
|
||||
|
||||
strncpy(ifr.ifr_name, devname, IFNAMSIZ);
|
||||
ifr.ifr_name[IFNAMSIZ - 1] = 0; /* Make sure to terminate */
|
||||
|
||||
/* Create a channel to the NET kernel. */
|
||||
if ((fd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
|
||||
SYS_ERR(DTUN, LOGL_ERROR, errno, "socket() failed");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (addr) { /* Set the interface address */
|
||||
memcpy(&((struct sockaddr_in *)&ifr.ifr_addr)->sin_addr, addr,
|
||||
sizeof(*addr));
|
||||
if (ioctl(fd, SIOCSIFADDR, (void *)&ifr) < 0) {
|
||||
if (errno != EEXIST) {
|
||||
SYS_ERR(DTUN, LOGL_ERROR, errno,
|
||||
"ioctl(SIOCSIFADDR) failed");
|
||||
} else {
|
||||
SYS_ERR(DTUN, LOGL_NOTICE, errno,
|
||||
"ioctl(SIOCSIFADDR): Address already exists");
|
||||
}
|
||||
close(fd);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
if (dstaddr) { /* Set the destination address */
|
||||
memcpy(&((struct sockaddr_in *)&ifr.ifr_dstaddr)->sin_addr,
|
||||
dstaddr, sizeof(*dstaddr));
|
||||
if (ioctl(fd, SIOCSIFDSTADDR, (caddr_t) & ifr) < 0) {
|
||||
SYS_ERR(DTUN, LOGL_ERROR, errno,
|
||||
"ioctl(SIOCSIFDSTADDR) failed");
|
||||
close(fd);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
if (netmask) { /* Set the netmask */
|
||||
#if defined(__linux__)
|
||||
memcpy(&((struct sockaddr_in *)&ifr.ifr_netmask)->sin_addr,
|
||||
netmask, sizeof(*netmask));
|
||||
#elif defined(__FreeBSD__) || defined (__APPLE__)
|
||||
((struct sockaddr_in *)&ifr.ifr_addr)->sin_addr.s_addr =
|
||||
netmask->s_addr;
|
||||
#endif
|
||||
|
||||
if (ioctl(fd, SIOCSIFNETMASK, (void *)&ifr) < 0) {
|
||||
SYS_ERR(DTUN, LOGL_ERROR, errno,
|
||||
"ioctl(SIOCSIFNETMASK) failed");
|
||||
close(fd);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
close(fd);
|
||||
|
||||
netdev_sifflags(devname, IFF_UP | IFF_RUNNING);
|
||||
|
||||
/* On linux the route to the interface is set automatically
|
||||
on FreeBSD we have to do this manually */
|
||||
#if defined(__FreeBSD__) || defined (__APPLE__)
|
||||
netdev_addroute4(dstaddr, addr, &this->netmask);
|
||||
#endif
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int netdev_setaddr6(const char *devname, struct in6_addr *addr, struct in6_addr *dstaddr,
|
||||
size_t prefixlen)
|
||||
{
|
||||
struct in6_ifreq ifr;
|
||||
int fd;
|
||||
|
||||
memset(&ifr, 0, sizeof(ifr));
|
||||
|
||||
#if defined(__linux__)
|
||||
ifr.ifr6_prefixlen = prefixlen;
|
||||
ifr.ifr6_ifindex = if_nametoindex(devname);
|
||||
if (ifr.ifr6_ifindex == 0) {
|
||||
SYS_ERR(DTUN, LOGL_ERROR, 0, "Error getting ifindex for %s\n", devname);
|
||||
return -1;
|
||||
}
|
||||
#elif defined(__FreeBSD__) || defined (__APPLE__)
|
||||
strncpy(ifr.ifr_name, devname, IFNAMSIZ);
|
||||
#endif
|
||||
|
||||
/* Create a channel to the NET kernel */
|
||||
if ((fd = socket(AF_INET6, SOCK_DGRAM, 0)) < 0) {
|
||||
SYS_ERR(DTUN, LOGL_ERROR, 0, "socket() failed");
|
||||
return -1;
|
||||
}
|
||||
|
||||
#if defined(__linux__)
|
||||
if (addr) {
|
||||
memcpy(&ifr.ifr6_addr, addr, sizeof(*addr));
|
||||
if (ioctl(fd, SIOCSIFADDR, (void *) &ifr) < 0) {
|
||||
if (errno != EEXIST) {
|
||||
SYS_ERR(DTUN, LOGL_ERROR, 0, "ioctl(SIOCSIFADDR) failed");
|
||||
} else {
|
||||
SYS_ERR(DTUN, LOGL_NOTICE, 0, "ioctl(SIOCSIFADDR): Address already exists");
|
||||
}
|
||||
close(fd);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
#if 0
|
||||
/* FIXME: looks like this is not possible/necessary for IPv6? */
|
||||
if (dstaddr) {
|
||||
memcpy(&ifr.ifr6_addr, dstaddr, sizeof(*dstaddr));
|
||||
if (ioctl(fd, SIOCSIFDSTADDR, (caddr_t *) &ifr) < 0) {
|
||||
SYS_ERR(DTUN, LOGL_ERROR, "ioctl(SIOCSIFDSTADDR) failed");
|
||||
close(fd);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
#elif defined(__FreeBSD__) || defined (__APPLE__)
|
||||
if (addr)
|
||||
memcpy(&ifr.ifr_ifru.ifru_addr, addr, sizeof(ifr.ifr_ifru.ifru_addr));
|
||||
if (dstaddr)
|
||||
memcpy(&ifr.ifr_ifru.ifru_dstaddr, dstaddr, sizeof(ifr.ifr_ifru.ifru_dstaddr));
|
||||
|
||||
if (ioctl(fd, SIOCSIFADDR_IN6, (struct ifreq *)&ifr) < 0) {
|
||||
SYS_ERR(DTUN, LOGL_ERROR, 0, "ioctl(SIOCSIFADDR_IN6) failed");
|
||||
close(fd);
|
||||
return -1;
|
||||
}
|
||||
#endif
|
||||
|
||||
close(fd);
|
||||
|
||||
netdev_sifflags(devname, IFF_UP | IFF_RUNNING);
|
||||
|
||||
/* On linux the route to the interface is set automatically
|
||||
on FreeBSD we have to do this manually */
|
||||
#if 0 /* FIXME */
|
||||
//#if defined(__FreeBSD__) || defined (__APPLE__)
|
||||
netdev_addroute6(dstaddr, addr, prefixlen);
|
||||
#endif
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int netdev_addaddr4(const char *devname, struct in_addr *addr,
|
||||
struct in_addr *dstaddr, struct in_addr *netmask)
|
||||
{
|
||||
int fd;
|
||||
#if defined(__linux__)
|
||||
struct {
|
||||
struct nlmsghdr n;
|
||||
struct ifaddrmsg i;
|
||||
char buf[TUN_NLBUFSIZE];
|
||||
} req;
|
||||
|
||||
struct sockaddr_nl local;
|
||||
socklen_t addr_len;
|
||||
int status;
|
||||
|
||||
struct sockaddr_nl nladdr;
|
||||
struct iovec iov;
|
||||
struct msghdr msg;
|
||||
|
||||
memset(&req, 0, sizeof(req));
|
||||
req.n.nlmsg_len = NLMSG_LENGTH(sizeof(struct ifaddrmsg));
|
||||
req.n.nlmsg_flags = NLM_F_REQUEST | NLM_F_CREATE;
|
||||
req.n.nlmsg_type = RTM_NEWADDR;
|
||||
req.i.ifa_family = AF_INET;
|
||||
req.i.ifa_prefixlen = 32; /* 32 FOR IPv4 */
|
||||
req.i.ifa_flags = 0;
|
||||
req.i.ifa_scope = RT_SCOPE_HOST; /* TODO or 0 */
|
||||
req.i.ifa_index = if_nametoindex(devname);
|
||||
if (!req.i.ifa_index) {
|
||||
SYS_ERR(DTUN, LOGL_ERROR, errno, "Unable to get ifindex for %s", devname);
|
||||
return -1;
|
||||
}
|
||||
|
||||
netdev_nlattr(&req.n, sizeof(req), IFA_ADDRESS, addr, sizeof(*addr));
|
||||
if (dstaddr)
|
||||
netdev_nlattr(&req.n, sizeof(req), IFA_LOCAL, dstaddr, sizeof(*dstaddr));
|
||||
|
||||
if ((fd = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE)) < 0) {
|
||||
SYS_ERR(DTUN, LOGL_ERROR, errno, "socket() failed");
|
||||
return -1;
|
||||
}
|
||||
|
||||
memset(&local, 0, sizeof(local));
|
||||
local.nl_family = AF_NETLINK;
|
||||
local.nl_groups = 0;
|
||||
|
||||
if (bind(fd, (struct sockaddr *)&local, sizeof(local)) < 0) {
|
||||
SYS_ERR(DTUN, LOGL_ERROR, errno, "bind() failed");
|
||||
close(fd);
|
||||
return -1;
|
||||
}
|
||||
|
||||
addr_len = sizeof(local);
|
||||
if (getsockname(fd, (struct sockaddr *)&local, &addr_len) < 0) {
|
||||
SYS_ERR(DTUN, LOGL_ERROR, errno,
|
||||
"getsockname() failed");
|
||||
close(fd);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (addr_len != sizeof(local)) {
|
||||
SYS_ERR(DTUN, LOGL_ERROR, 0,
|
||||
"Wrong address length %d", addr_len);
|
||||
close(fd);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (local.nl_family != AF_NETLINK) {
|
||||
SYS_ERR(DTUN, LOGL_ERROR, 0,
|
||||
"Wrong address family %d", local.nl_family);
|
||||
close(fd);
|
||||
return -1;
|
||||
}
|
||||
|
||||
iov.iov_base = (void *)&req.n;
|
||||
iov.iov_len = req.n.nlmsg_len;
|
||||
|
||||
msg.msg_name = (void *)&nladdr;
|
||||
msg.msg_namelen = sizeof(nladdr);
|
||||
msg.msg_iov = &iov;
|
||||
msg.msg_iovlen = 1;
|
||||
msg.msg_control = NULL;
|
||||
msg.msg_controllen = 0;
|
||||
msg.msg_flags = 0;
|
||||
|
||||
memset(&nladdr, 0, sizeof(nladdr));
|
||||
nladdr.nl_family = AF_NETLINK;
|
||||
nladdr.nl_pid = 0;
|
||||
nladdr.nl_groups = 0;
|
||||
|
||||
req.n.nlmsg_seq = 0;
|
||||
req.n.nlmsg_flags |= NLM_F_ACK;
|
||||
|
||||
status = sendmsg(fd, &msg, 0);
|
||||
if (status != req.n.nlmsg_len) {
|
||||
SYS_ERR(DTUN, LOGL_ERROR, errno, "sendmsg() failed, returned %d", status);
|
||||
close(fd);
|
||||
return -1;
|
||||
}
|
||||
|
||||
status = netdev_sifflags(devname, IFF_UP | IFF_RUNNING);
|
||||
if (status == -1) {
|
||||
close(fd);
|
||||
return -1;
|
||||
}
|
||||
#elif defined (__FreeBSD__) || defined (__APPLE__)
|
||||
struct ifaliasreq areq;
|
||||
|
||||
memset(&areq, 0, sizeof(areq));
|
||||
|
||||
/* Set up interface name */
|
||||
strncpy(areq.ifra_name, devname, IFNAMSIZ);
|
||||
areq.ifra_name[IFNAMSIZ - 1] = 0; /* Make sure to terminate */
|
||||
|
||||
((struct sockaddr_in *)&areq.ifra_addr)->sin_family = AF_INET;
|
||||
((struct sockaddr_in *)&areq.ifra_addr)->sin_len =
|
||||
sizeof(areq.ifra_addr);
|
||||
((struct sockaddr_in *)&areq.ifra_addr)->sin_addr.s_addr = addr->s_addr;
|
||||
|
||||
((struct sockaddr_in *)&areq.ifra_mask)->sin_family = AF_INET;
|
||||
((struct sockaddr_in *)&areq.ifra_mask)->sin_len =
|
||||
sizeof(areq.ifra_mask);
|
||||
((struct sockaddr_in *)&areq.ifra_mask)->sin_addr.s_addr =
|
||||
netmask->s_addr;
|
||||
|
||||
/* For some reason FreeBSD uses ifra_broadcast for specifying dstaddr */
|
||||
((struct sockaddr_in *)&areq.ifra_broadaddr)->sin_family = AF_INET;
|
||||
((struct sockaddr_in *)&areq.ifra_broadaddr)->sin_len =
|
||||
sizeof(areq.ifra_broadaddr);
|
||||
((struct sockaddr_in *)&areq.ifra_broadaddr)->sin_addr.s_addr =
|
||||
dstaddr->s_addr;
|
||||
|
||||
/* Create a channel to the NET kernel. */
|
||||
if ((fd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
|
||||
SYS_ERR(DTUN, LOGL_ERROR, errno, "socket() failed");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (ioctl(fd, SIOCAIFADDR, (void *)&areq) < 0) {
|
||||
SYS_ERR(DTUN, LOGL_ERROR, errno,
|
||||
"ioctl(SIOCAIFADDR) failed");
|
||||
close(fd);
|
||||
return -1;
|
||||
}
|
||||
#endif
|
||||
close(fd);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int netdev_addaddr6(const char *devname, struct in6_addr *addr,
|
||||
struct in6_addr *dstaddr, int prefixlen)
|
||||
{
|
||||
int fd;
|
||||
#if defined(__linux__)
|
||||
struct {
|
||||
struct nlmsghdr n;
|
||||
struct ifaddrmsg i;
|
||||
char buf[TUN_NLBUFSIZE];
|
||||
} req;
|
||||
|
||||
struct sockaddr_nl local;
|
||||
socklen_t addr_len;
|
||||
int status;
|
||||
|
||||
struct sockaddr_nl nladdr;
|
||||
struct iovec iov;
|
||||
struct msghdr msg;
|
||||
|
||||
memset(&req, 0, sizeof(req));
|
||||
req.n.nlmsg_len = NLMSG_LENGTH(sizeof(struct ifaddrmsg));
|
||||
req.n.nlmsg_flags = NLM_F_REQUEST | NLM_F_CREATE;
|
||||
req.n.nlmsg_type = RTM_NEWADDR;
|
||||
req.i.ifa_family = AF_INET6;
|
||||
req.i.ifa_prefixlen = prefixlen; /* 64 FOR IPv6 */
|
||||
req.i.ifa_flags = 0;
|
||||
req.i.ifa_scope = RT_SCOPE_HOST; /* TODO or 0 */
|
||||
req.i.ifa_index = if_nametoindex(devname);
|
||||
if (!req.i.ifa_index) {
|
||||
SYS_ERR(DTUN, LOGL_ERROR, errno, "Unable to get ifindex for %s", devname);
|
||||
return -1;
|
||||
}
|
||||
|
||||
netdev_nlattr(&req.n, sizeof(req), IFA_ADDRESS, addr, sizeof(*addr));
|
||||
if (dstaddr)
|
||||
netdev_nlattr(&req.n, sizeof(req), IFA_LOCAL, dstaddr, sizeof(*dstaddr));
|
||||
|
||||
if ((fd = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE)) < 0) {
|
||||
SYS_ERR(DTUN, LOGL_ERROR, errno, "socket() failed");
|
||||
return -1;
|
||||
}
|
||||
|
||||
memset(&local, 0, sizeof(local));
|
||||
local.nl_family = AF_NETLINK;
|
||||
local.nl_groups = 0;
|
||||
|
||||
if (bind(fd, (struct sockaddr *)&local, sizeof(local)) < 0) {
|
||||
SYS_ERR(DTUN, LOGL_ERROR, errno, "bind() failed");
|
||||
close(fd);
|
||||
return -1;
|
||||
}
|
||||
|
||||
addr_len = sizeof(local);
|
||||
if (getsockname(fd, (struct sockaddr *)&local, &addr_len) < 0) {
|
||||
SYS_ERR(DTUN, LOGL_ERROR, errno,
|
||||
"getsockname() failed");
|
||||
close(fd);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (addr_len != sizeof(local)) {
|
||||
SYS_ERR(DTUN, LOGL_ERROR, 0,
|
||||
"Wrong address length %d", addr_len);
|
||||
close(fd);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (local.nl_family != AF_NETLINK) {
|
||||
SYS_ERR(DTUN, LOGL_ERROR, 0,
|
||||
"Wrong address family %d", local.nl_family);
|
||||
close(fd);
|
||||
return -1;
|
||||
}
|
||||
|
||||
iov.iov_base = (void *)&req.n;
|
||||
iov.iov_len = req.n.nlmsg_len;
|
||||
|
||||
msg.msg_name = (void *)&nladdr;
|
||||
msg.msg_namelen = sizeof(nladdr);
|
||||
msg.msg_iov = &iov;
|
||||
msg.msg_iovlen = 1;
|
||||
msg.msg_control = NULL;
|
||||
msg.msg_controllen = 0;
|
||||
msg.msg_flags = 0;
|
||||
|
||||
memset(&nladdr, 0, sizeof(nladdr));
|
||||
nladdr.nl_family = AF_NETLINK;
|
||||
nladdr.nl_pid = 0;
|
||||
nladdr.nl_groups = 0;
|
||||
|
||||
req.n.nlmsg_seq = 0;
|
||||
req.n.nlmsg_flags |= NLM_F_ACK;
|
||||
|
||||
status = sendmsg(fd, &msg, 0);
|
||||
if (status != req.n.nlmsg_len) {
|
||||
SYS_ERR(DTUN, LOGL_ERROR, errno, "sendmsg() failed, returned %d", status);
|
||||
close(fd);
|
||||
return -1;
|
||||
}
|
||||
|
||||
status = netdev_sifflags(devname, IFF_UP | IFF_RUNNING);
|
||||
if (status == -1) {
|
||||
close(fd);
|
||||
return -1;
|
||||
}
|
||||
#elif defined (__FreeBSD__) || defined (__APPLE__)
|
||||
struct ifaliasreq areq;
|
||||
|
||||
memset(&areq, 0, sizeof(areq));
|
||||
|
||||
/* Set up interface name */
|
||||
strncpy(areq.ifra_name, devname, IFNAMSIZ);
|
||||
areq.ifra_name[IFNAMSIZ - 1] = 0; /* Make sure to terminate */
|
||||
|
||||
((struct sockaddr_in6 *)&areq.ifra_addr)->sin6_family = AF_INET6;
|
||||
((struct sockaddr_in6 *)&areq.ifra_addr)->sin6_len = sizeof(areq.ifra_addr);
|
||||
((struct sockaddr_in6 *)&areq.ifra_addr)->sin6_addr.s6_addr = addr->s6_addr;
|
||||
|
||||
((struct sockaddr_in6 *)&areq.ifra_mask)->sin6_family = AF_INET6;
|
||||
((struct sockaddr_in6 *)&areq.ifra_mask)->sin6_len = sizeof(areq.ifra_mask);
|
||||
((struct sockaddr_in6 *)&areq.ifra_mask)->sin6_addr.s6_addr = netmask->s6_addr;
|
||||
|
||||
/* For some reason FreeBSD uses ifra_broadcast for specifying dstaddr */
|
||||
((struct sockaddr_in6 *)&areq.ifra_broadaddr)->sin6_family = AF_INET6;
|
||||
((struct sockaddr_in6 *)&areq.ifra_broadaddr)->sin6_len = sizeof(areq.ifra_broadaddr);
|
||||
((struct sockaddr_in6 *)&areq.ifra_broadaddr)->sin6_addr.s6_addr = dstaddr->s6_addr;
|
||||
|
||||
/* Create a channel to the NET kernel. */
|
||||
if ((fd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
|
||||
SYS_ERR(DTUN, LOGL_ERROR, errno, "socket() failed");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (ioctl(fd, SIOCAIFADDR, (void *)&areq) < 0) {
|
||||
SYS_ERR(DTUN, LOGL_ERROR, errno,
|
||||
"ioctl(SIOCAIFADDR) failed");
|
||||
close(fd);
|
||||
return -1;
|
||||
}
|
||||
#endif
|
||||
close(fd);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int netdev_route4(struct in_addr *dst, struct in_addr *gateway, struct in_addr *mask, int delete)
|
||||
{
|
||||
int fd;
|
||||
|
12
lib/netdev.h
12
lib/netdev.h
@@ -53,18 +53,6 @@ struct iphdr
|
||||
};
|
||||
#endif /* !HAVE_IPHDR */
|
||||
|
||||
extern int netdev_setaddr4(const char *devname, struct in_addr *addr,
|
||||
struct in_addr *dstaddr, struct in_addr *netmask);
|
||||
|
||||
extern int netdev_setaddr6(const char *devname, struct in6_addr *addr, struct in6_addr *dstaddr,
|
||||
size_t prefixlen);
|
||||
|
||||
extern int netdev_addaddr4(const char *devname, struct in_addr *addr,
|
||||
struct in_addr *dstaddr, struct in_addr *netmask);
|
||||
|
||||
extern int netdev_addaddr6(const char *devname, struct in6_addr *addr,
|
||||
struct in6_addr *dstaddr, int prefixlen);
|
||||
|
||||
extern int netdev_addroute4(struct in_addr *dst, struct in_addr *gateway, struct in_addr *mask);
|
||||
extern int netdev_delroute4(struct in_addr *dst, struct in_addr *gateway, struct in_addr *mask);
|
||||
extern int netdev_addroute6(struct in6_addr *dst, struct in6_addr *gateway, int prefixlen, const char *gw_iface);
|
||||
|
113
lib/tun.c
113
lib/tun.c
@@ -49,99 +49,38 @@
|
||||
#include "syserr.h"
|
||||
#include "gtp-kernel.h"
|
||||
|
||||
static int tun_setaddr4(struct tun_t *this, struct in_addr *addr,
|
||||
struct in_addr *dstaddr, struct in_addr *netmask)
|
||||
int tun_addaddr(struct tun_t *this, struct in46_addr *addr, size_t prefixlen)
|
||||
{
|
||||
struct osmo_sockaddr osa = {0};
|
||||
int rc;
|
||||
rc = netdev_setaddr4(this->devname, addr, dstaddr, netmask);
|
||||
if (rc < 0)
|
||||
return rc;
|
||||
OSMO_ASSERT(this->netdev);
|
||||
OSMO_ASSERT(addr);
|
||||
|
||||
if (addr) {
|
||||
this->addr.len = sizeof(struct in_addr);
|
||||
this->addr.v4.s_addr = addr->s_addr;
|
||||
}
|
||||
if (dstaddr) {
|
||||
this->dstaddr.len = sizeof(struct in_addr);
|
||||
this->dstaddr.v4.s_addr = dstaddr->s_addr;
|
||||
}
|
||||
if (netmask)
|
||||
this->netmask.s_addr = netmask->s_addr;
|
||||
this->addrs++;
|
||||
#if defined(__FreeBSD__) || defined (__APPLE__)
|
||||
this->routes = 1;
|
||||
#endif
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
static int tun_setaddr6(struct tun_t *this, struct in6_addr *addr, struct in6_addr *dstaddr,
|
||||
size_t prefixlen)
|
||||
{
|
||||
int rc;
|
||||
rc = netdev_setaddr6(this->devname, addr, dstaddr, prefixlen);
|
||||
if (rc < 0)
|
||||
return rc;
|
||||
if (dstaddr) {
|
||||
this->dstaddr.len = sizeof(*dstaddr);
|
||||
memcpy(&this->dstaddr.v6, dstaddr, sizeof(*dstaddr));
|
||||
}
|
||||
this->addrs++;
|
||||
#if defined(__FreeBSD__) || defined (__APPLE__)
|
||||
this->routes = 1;
|
||||
#endif
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
static int tun_addaddr4(struct tun_t *this, struct in_addr *addr,
|
||||
struct in_addr *dstaddr, struct in_addr *netmask)
|
||||
{
|
||||
int rc;
|
||||
|
||||
/* TODO: Is this needed on FreeBSD? */
|
||||
if (!this->addrs) /* Use ioctl for first addr to make ping work */
|
||||
return tun_setaddr4(this, addr, dstaddr, netmask); /* TODO dstaddr */
|
||||
|
||||
rc = netdev_addaddr4(this->devname, addr, dstaddr, netmask);
|
||||
if (rc < 0)
|
||||
return rc;
|
||||
|
||||
this->addrs++;
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
static int tun_addaddr6(struct tun_t *this,
|
||||
struct in6_addr *addr,
|
||||
struct in6_addr *dstaddr, int prefixlen)
|
||||
{
|
||||
int rc;
|
||||
|
||||
if (!this->addrs) /* Use ioctl for first addr to make ping work */
|
||||
return tun_setaddr6(this, addr, dstaddr, prefixlen);
|
||||
|
||||
rc = netdev_addaddr6(this->devname, addr, dstaddr, prefixlen);
|
||||
if (rc < 0)
|
||||
return rc;
|
||||
|
||||
this->addrs++;
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
int tun_addaddr(struct tun_t *this, struct in46_addr *addr, struct in46_addr *dstaddr, size_t prefixlen)
|
||||
{
|
||||
struct in_addr netmask;
|
||||
switch (addr->len) {
|
||||
case 4:
|
||||
netmask.s_addr = htonl(0xffffffff << (32 - prefixlen));
|
||||
return tun_addaddr4(this, &addr->v4, dstaddr ? &dstaddr->v4 : NULL, &netmask);
|
||||
osa.u.sin.sin_family = AF_INET;
|
||||
memcpy(&osa.u.sin.sin_addr, &addr->v4, sizeof(struct in_addr));
|
||||
/* Store first IPv4 IP address to be used in ipup script: */
|
||||
if (this->addrs == 0) {
|
||||
this->addr.len = sizeof(struct in_addr);
|
||||
this->addr.v4.s_addr = addr->v4.s_addr;
|
||||
this->netmask.s_addr = htonl(0xffffffff << (32 - prefixlen));
|
||||
}
|
||||
break;
|
||||
case 16:
|
||||
return tun_addaddr6(this, &addr->v6, dstaddr ? &dstaddr->v6 : NULL, prefixlen);
|
||||
osa.u.sin.sin_family = AF_INET6;
|
||||
memcpy(&osa.u.sin6.sin6_addr, &addr->v6, sizeof(struct in6_addr));
|
||||
break;
|
||||
default:
|
||||
return -1;
|
||||
}
|
||||
|
||||
rc = osmo_netdev_add_addr(this->netdev, &osa, prefixlen);
|
||||
if (rc < 0)
|
||||
return rc;
|
||||
|
||||
this->addrs++;
|
||||
return rc;
|
||||
}
|
||||
|
||||
static int tun_tundev_data_ind_cb(struct osmo_tundev *tundev, struct msgb *msg)
|
||||
@@ -168,7 +107,6 @@ int tun_new(struct tun_t **tun, const char *dev_name, bool use_kernel, int fd0,
|
||||
|
||||
t->cb_ind = NULL;
|
||||
t->addrs = 0;
|
||||
t->routes = 0;
|
||||
t->fd = -1;
|
||||
|
||||
if (!use_kernel) {
|
||||
@@ -235,11 +173,6 @@ err_kernel_create:
|
||||
|
||||
int tun_free(struct tun_t *tun)
|
||||
{
|
||||
|
||||
if (tun->routes) {
|
||||
netdev_delroute4(&tun->dstaddr.v4, &tun->addr.v4, &tun->netmask);
|
||||
}
|
||||
|
||||
if (tun->tundev) {
|
||||
if (osmo_tundev_close(tun->tundev) < 0) {
|
||||
SYS_ERR(DTUN, LOGL_ERROR, errno, "close() failed");
|
||||
|
@@ -37,10 +37,8 @@ struct tun_t {
|
||||
struct osmo_netdev *netdev;
|
||||
int fd; /* File descriptor to tun interface */
|
||||
struct in46_addr addr;
|
||||
struct in46_addr dstaddr;
|
||||
struct in_addr netmask;
|
||||
int addrs; /* Number of allocated IP addresses */
|
||||
int routes; /* One if we allocated an automatic route */
|
||||
char devname[IFNAMSIZ]; /* Name of the tun device */
|
||||
int (*cb_ind) (struct tun_t * tun, void *pack, unsigned len);
|
||||
/* to be used by libgtp callers/users (to attach their own private state) */
|
||||
@@ -52,8 +50,7 @@ extern int tun_free(struct tun_t *tun);
|
||||
extern int tun_decaps(struct tun_t *this);
|
||||
extern int tun_encaps(struct tun_t *tun, void *pack, unsigned len);
|
||||
|
||||
extern int tun_addaddr(struct tun_t *this, struct in46_addr *addr,
|
||||
struct in46_addr *dstaddr, size_t prefixlen);
|
||||
extern int tun_addaddr(struct tun_t *this, struct in46_addr *addr, size_t prefixlen);
|
||||
|
||||
extern int tun_set_cb_ind(struct tun_t *this,
|
||||
int (*cb_ind) (struct tun_t * tun, void *pack,
|
||||
|
@@ -1649,7 +1649,7 @@ static int create_pdp_conf(struct pdp_t *pdp, void *cbp, int cause)
|
||||
if (addr[i].len == 16)
|
||||
prefixlen = 64;
|
||||
/* printf("Setting up interface and routing\n"); */
|
||||
tun_addaddr(tun, &addr[i], NULL, prefixlen);
|
||||
tun_addaddr(tun, &addr[i], prefixlen);
|
||||
if (options.defaultroute) {
|
||||
if (in46a_is_v4(&addr[i])) {
|
||||
struct in_addr rm;
|
||||
@@ -1786,7 +1786,7 @@ static void handle_router_adv(struct pdp_t *pdp, struct ip6_hdr *ip6h, struct ic
|
||||
}
|
||||
}
|
||||
#endif
|
||||
rc = tun_addaddr(tun, &addr, NULL, opt_prefix->prefix_len);
|
||||
rc = tun_addaddr(tun, &addr, opt_prefix->prefix_len);
|
||||
if (rc < 0) {
|
||||
SYS_ERR(DSGSN, LOGL_ERROR, 0, "Failed to add addr %s to tun %s",
|
||||
in46a_ntoa(&addr), tun->devname);
|
||||
@@ -1936,7 +1936,7 @@ int main(int argc, char **argv)
|
||||
}
|
||||
|
||||
if ((options.createif) && (options.netaddr.len)) {
|
||||
tun_addaddr(tun, &options.netaddr, NULL, options.prefixlen);
|
||||
tun_addaddr(tun, &options.netaddr, options.prefixlen);
|
||||
if (options.defaultroute) {
|
||||
if (in46a_is_v4(&options.netaddr)) {
|
||||
struct in_addr rm;
|
||||
|
Reference in New Issue
Block a user