mirror of
https://gitea.osmocom.org/cellular-infrastructure/osmo-ggsn.git
synced 2025-11-03 13:43:25 +00:00
Compare commits
5 Commits
1.10.0
...
pespin/lin
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
9b17053825 | ||
|
|
dd64f649f8 | ||
|
|
4d407a18ca | ||
|
|
cb809ca721 | ||
|
|
b00c7caf35 |
25
ggsn/ggsn.c
25
ggsn/ggsn.c
@@ -194,6 +194,7 @@ int apn_start(struct apn_ctx *apn)
|
||||
struct in46_prefix ipv6_tun_linklocal_ip;
|
||||
struct in46_prefix *blacklist;
|
||||
int blacklist_size;
|
||||
int rc;
|
||||
|
||||
if (apn->started)
|
||||
return 0;
|
||||
@@ -240,16 +241,32 @@ 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,
|
||||
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",
|
||||
in46p_ntoa(&apn->v6.cfg.ll_prefix), strerror(errno));
|
||||
apn_stop(apn, false);
|
||||
return -1;
|
||||
}
|
||||
apn->v6_lladdr = apn->v6.cfg.ll_prefix.addr.v6;
|
||||
}
|
||||
|
||||
if (apn->tun.cfg.ipup_script) {
|
||||
LOGPAPN(LOGL_INFO, apn, "Running ip-up script %s\n",
|
||||
apn->tun.cfg.ipup_script);
|
||||
tun_runscript(apn->tun.tun, apn->tun.cfg.ipup_script);
|
||||
}
|
||||
|
||||
if (apn->cfg.apn_type_mask & (APN_TYPE_IPv6|APN_TYPE_IPv4v6)) {
|
||||
if (tun_ip_local_get(apn->tun.tun, &ipv6_tun_linklocal_ip, 1, IP_TYPE_IPv6_LINK) < 1) {
|
||||
LOGPAPN(LOGL_ERROR, apn, "Cannot obtain IPv6 link-local address of "
|
||||
"interface: %s\n", strerror(errno));
|
||||
if (apn->cfg.apn_type_mask & (APN_TYPE_IPv6|APN_TYPE_IPv4v6) &&
|
||||
apn->v6.cfg.ll_prefix.addr.len == 0) {
|
||||
rc = tun_ip_local_get(apn->tun.tun, &ipv6_tun_linklocal_ip, 1, IP_TYPE_IPv6_LINK);
|
||||
if (rc < 1) {
|
||||
LOGPAPN(LOGL_ERROR, apn, "Cannot obtain IPv6 link-local address of interface: %s\n",
|
||||
rc ? strerror(errno) : "tun interface has no link-local IP assigned");
|
||||
apn_stop(apn, false);
|
||||
return -1;
|
||||
}
|
||||
|
||||
@@ -22,6 +22,7 @@ struct ggsn_ctx;
|
||||
struct apn_ctx_ip {
|
||||
struct {
|
||||
struct in46_prefix ifconfig_prefix;
|
||||
struct in46_prefix ll_prefix;
|
||||
struct in46_prefix static_prefix;
|
||||
struct in46_prefix dynamic_prefix;
|
||||
/* v4 DNS server names */
|
||||
|
||||
@@ -513,6 +513,24 @@ DEFUN(cfg_apn_no_ipv6_ifconfig, cfg_apn_no_ipv6_ifconfig_cmd,
|
||||
return CMD_SUCCESS;
|
||||
}
|
||||
|
||||
DEFUN(cfg_apn_ipv6_linklocal, cfg_apn_ipv6_linklocal_cmd,
|
||||
"ipv6 link-local X:X::X:X/M",
|
||||
IP6_STR IFCONFIG_STR "IPv6 Link-local Adress/Prefix-Length\n")
|
||||
{
|
||||
struct apn_ctx *apn = (struct apn_ctx *) vty->index;
|
||||
str2prefix(&apn->v6.cfg.ll_prefix, argv[0]);
|
||||
return CMD_SUCCESS;
|
||||
}
|
||||
|
||||
DEFUN(cfg_apn_no_ipv6_linklocal, cfg_apn_no_ipv6_linklocal_cmd,
|
||||
"no ipv6 link-local",
|
||||
NO_STR IP6_STR IFCONFIG_STR)
|
||||
{
|
||||
struct apn_ctx *apn = (struct apn_ctx *) vty->index;
|
||||
memset(&apn->v6.cfg.ll_prefix, 0, sizeof(apn->v6.cfg.ll_prefix));
|
||||
return CMD_SUCCESS;
|
||||
}
|
||||
|
||||
#define DNS_STRINGS "Configure DNS Server\n" "primary/secondary DNS\n" "IP address of DNS Sever\n"
|
||||
|
||||
DEFUN(cfg_apn_ip_dns, cfg_apn_ip_dns_cmd,
|
||||
@@ -893,6 +911,8 @@ int ggsn_vty_init(void)
|
||||
install_element(APN_NODE, &cfg_apn_no_ip_ifconfig_cmd);
|
||||
install_element(APN_NODE, &cfg_apn_ipv6_ifconfig_cmd);
|
||||
install_element(APN_NODE, &cfg_apn_no_ipv6_ifconfig_cmd);
|
||||
install_element(APN_NODE, &cfg_apn_ipv6_linklocal_cmd);
|
||||
install_element(APN_NODE, &cfg_apn_no_ipv6_linklocal_cmd);
|
||||
install_element(APN_NODE, &cfg_apn_gpdu_seq_cmd);
|
||||
install_element(APN_NODE, &cfg_apn_no_gpdu_seq_cmd);
|
||||
|
||||
|
||||
186
lib/tun.c
186
lib/tun.c
@@ -295,7 +295,7 @@ int tun_setaddr(struct tun_t *this, struct in46_addr *addr, struct in46_addr *ds
|
||||
}
|
||||
}
|
||||
|
||||
int tun_addaddr(struct tun_t *this,
|
||||
static int tun_addaddr4(struct tun_t *this,
|
||||
struct in_addr *addr,
|
||||
struct in_addr *dstaddr, struct in_addr *netmask)
|
||||
{
|
||||
@@ -333,8 +333,9 @@ int tun_addaddr(struct tun_t *this,
|
||||
return -1;
|
||||
}
|
||||
|
||||
tun_nlattr(&req.n, sizeof(req), IFA_ADDRESS, addr, sizeof(addr));
|
||||
tun_nlattr(&req.n, sizeof(req), IFA_LOCAL, dstaddr, sizeof(dstaddr));
|
||||
tun_nlattr(&req.n, sizeof(req), IFA_ADDRESS, addr, sizeof(*addr));
|
||||
if (dstaddr)
|
||||
tun_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");
|
||||
@@ -464,6 +465,185 @@ int tun_addaddr(struct tun_t *this,
|
||||
|
||||
}
|
||||
|
||||
static int tun_addaddr6(struct tun_t *this,
|
||||
struct in6_addr *addr,
|
||||
struct in6_addr *dstaddr, int prefixlen)
|
||||
{
|
||||
|
||||
#if defined(__linux__)
|
||||
struct {
|
||||
struct nlmsghdr n;
|
||||
struct ifaddrmsg i;
|
||||
char buf[TUN_NLBUFSIZE];
|
||||
} req;
|
||||
|
||||
struct sockaddr_nl local;
|
||||
socklen_t addr_len;
|
||||
int fd;
|
||||
int status;
|
||||
|
||||
struct sockaddr_nl nladdr;
|
||||
struct iovec iov;
|
||||
struct msghdr msg;
|
||||
|
||||
if (!this->addrs) /* Use ioctl for first addr to make ping work */
|
||||
return tun_setaddr6(this, addr, dstaddr, prefixlen);
|
||||
|
||||
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 = 64; /* 64 FOR IPv6 */
|
||||
req.i.ifa_flags = 0;
|
||||
req.i.ifa_scope = RT_SCOPE_HOST; /* TODO or 0 */
|
||||
req.i.ifa_index = if_nametoindex(this->devname);
|
||||
if (!req.i.ifa_index) {
|
||||
SYS_ERR(DTUN, LOGL_ERROR, errno, "Unable to get ifindex for %s", this->devname);
|
||||
return -1;
|
||||
}
|
||||
|
||||
tun_nlattr(&req.n, sizeof(req), IFA_ADDRESS, addr, sizeof(*addr));
|
||||
if (dstaddr)
|
||||
tun_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 = tun_sifflags(this, IFF_UP | IFF_RUNNING);
|
||||
if (status == -1) {
|
||||
close(fd);
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
close(fd);
|
||||
this->addrs++;
|
||||
return 0;
|
||||
|
||||
#elif defined (__FreeBSD__) || defined (__APPLE__)
|
||||
|
||||
int fd;
|
||||
struct ifaliasreq areq;
|
||||
|
||||
/* TODO: Is this needed on FreeBSD? */
|
||||
if (!this->addrs) /* Use ioctl for first addr to make ping work */
|
||||
return tun_setaddr6(this, addr, dstaddr, netmask); /* TODO dstaddr */
|
||||
|
||||
memset(&areq, 0, sizeof(areq));
|
||||
|
||||
/* Set up interface name */
|
||||
strncpy(areq.ifra_name, this->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;
|
||||
}
|
||||
|
||||
close(fd);
|
||||
this->addrs++;
|
||||
return 0;
|
||||
|
||||
#endif
|
||||
|
||||
}
|
||||
|
||||
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);
|
||||
case 16:
|
||||
return tun_addaddr6(this, &addr->v6, dstaddr ? &dstaddr->v6 : NULL, prefixlen);
|
||||
default:
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
static int tun_route(struct tun_t *this,
|
||||
struct in_addr *dst,
|
||||
struct in_addr *gateway, struct in_addr *mask, int delete)
|
||||
|
||||
@@ -80,8 +80,8 @@ 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 in_addr *addr,
|
||||
struct in_addr *dstaddr, struct in_addr *netmask);
|
||||
extern int tun_addaddr(struct tun_t *this, struct in46_addr *addr,
|
||||
struct in46_addr *dstaddr, size_t prefixlen);
|
||||
|
||||
extern int tun_setaddr(struct tun_t *this, struct in46_addr *our_adr,
|
||||
struct in46_addr *his_adr, size_t prefixlen);
|
||||
|
||||
@@ -1,13 +1,13 @@
|
||||
/*
|
||||
/*
|
||||
* OsmoGGSN - Gateway GPRS Support Node
|
||||
* Copyright (C) 2002, 2003, 2004 Mondru AB.
|
||||
* Copyright (C) 2017 Harald Welte <laforge@gnumonks.org>
|
||||
*
|
||||
*
|
||||
* The contents of this file may be used under the terms of the GNU
|
||||
* General Public License Version 2, provided that the above copyright
|
||||
* notice and this permission notice is included in all copies or
|
||||
* substantial portions of the software.
|
||||
*
|
||||
*
|
||||
*/
|
||||
|
||||
/*
|
||||
@@ -85,7 +85,7 @@ struct {
|
||||
int debug; /* Print debug messages */
|
||||
int createif; /* Create local network interface */
|
||||
char *tun_dev_name;
|
||||
struct in_addr netaddr, destaddr, net; /* Network interface */
|
||||
struct in46_addr netaddr, destaddr, net; /* Network interface */
|
||||
size_t prefixlen;
|
||||
char *ipup, *ipdown; /* Filename of scripts */
|
||||
int defaultroute; /* Set up default route */
|
||||
@@ -372,10 +372,10 @@ static int process_options(int argc, char **argv)
|
||||
|
||||
/* foreground */
|
||||
/* If fg flag not given run as a daemon */
|
||||
/* Do not allow sgsnemu to run as deamon
|
||||
/* Do not allow sgsnemu to run as deamon
|
||||
if (!args_info.fg_flag)
|
||||
{
|
||||
closelog();
|
||||
closelog();
|
||||
freopen("/dev/null", "w", stdout);
|
||||
freopen("/dev/null", "w", stderr);
|
||||
freopen("/dev/null", "r", stdin);
|
||||
@@ -873,23 +873,21 @@ static int process_options(int argc, char **argv)
|
||||
/* net */
|
||||
/* Store net as in_addr net and mask */
|
||||
if (args_info.net_arg) {
|
||||
struct in46_addr in46;
|
||||
if (ippool_aton
|
||||
(&in46, &options.prefixlen, args_info.net_arg, 0)) {
|
||||
(&options.net, &options.prefixlen, args_info.net_arg, 0)) {
|
||||
SYS_ERR(DSGSN, LOGL_ERROR, 0,
|
||||
"Invalid network address: %s!",
|
||||
args_info.net_arg);
|
||||
exit(1);
|
||||
}
|
||||
options.net.s_addr = in46.v4.s_addr;
|
||||
options.netaddr.s_addr = options.net.s_addr;
|
||||
options.destaddr.s_addr = options.net.s_addr;
|
||||
options.netaddr = options.net;
|
||||
options.destaddr = options.net;
|
||||
|
||||
} else {
|
||||
options.net.s_addr = 0;
|
||||
memset(&options.net, 0, sizeof(options.net));
|
||||
options.prefixlen = 0;
|
||||
options.netaddr.s_addr = 0;
|
||||
options.destaddr.s_addr = 0;
|
||||
memset(&options.netaddr, 0, sizeof(options.netaddr));
|
||||
memset(&options.destaddr, 0, sizeof(options.destaddr));
|
||||
}
|
||||
|
||||
/* ipup */
|
||||
@@ -1427,7 +1425,7 @@ static int create_pdp_conf(struct pdp_t *pdp, void *cbp, int cause)
|
||||
break;
|
||||
}
|
||||
|
||||
if ((options.createif) && (!options.net.s_addr)) {
|
||||
if ((options.createif) && (!options.net.len)) {
|
||||
size_t prefixlen = 32;
|
||||
if (addr.len == 16)
|
||||
prefixlen = 64;
|
||||
@@ -1580,15 +1578,13 @@ int main(int argc, char **argv)
|
||||
maxfd = tun->fd;
|
||||
}
|
||||
|
||||
if ((options.createif) && (options.net.s_addr)) {
|
||||
struct in_addr mask;
|
||||
mask.s_addr = options.prefixlen ? (0xFFFFFFFF >> (32 - options.prefixlen)) : 0;
|
||||
if ((options.createif) && (options.net.len)) {
|
||||
/* printf("Setting up interface and routing\n"); */
|
||||
tun_addaddr(tun, &options.netaddr, &options.destaddr, &mask);
|
||||
tun_addaddr(tun, &options.netaddr, &options.destaddr, options.prefixlen);
|
||||
if (options.defaultroute) {
|
||||
struct in_addr rm;
|
||||
rm.s_addr = 0;
|
||||
tun_addroute(tun, &rm, &options.destaddr, &rm);
|
||||
tun_addroute(tun, &rm, &options.destaddr.v4, &rm);
|
||||
}
|
||||
if (options.ipup)
|
||||
tun_runscript(tun, options.ipup);
|
||||
@@ -1700,7 +1696,7 @@ int main(int argc, char **argv)
|
||||
pdp->hisaddr0 = options.remote;
|
||||
pdp->hisaddr1 = options.remote;
|
||||
|
||||
pdp->cch_pdp = options.cch; /* 2048 = Normal, 1024 = Prepaid,
|
||||
pdp->cch_pdp = options.cch; /* 2048 = Normal, 1024 = Prepaid,
|
||||
512 = Flat rate, 256 = Hot billing */
|
||||
|
||||
pdp->tx_gpdu_seq = options.tx_gpdu_seq;
|
||||
|
||||
Reference in New Issue
Block a user