TT#38351 support specifying interfaces by name

closes #566

Change-Id: Ia9a5c6d9d702e27404a7e27503970ee9a8dac7b9
changes/68/22068/1
Richard Fuchs 8 years ago
parent cbe7e5ab1d
commit d66a2e5191

@ -685,12 +685,28 @@ Interfaces configuration
The command-line options `-i` or `--interface=`, or equivalently the `interface=` config file option,
specify local network interfaces for RTP. At least one must be given, but multiple can be specified.
The format of the value is `[NAME/]IP[!IP]` with `IP` being either an IPv4 address or an IPv6 address.
The format of the value is `[NAME/]IP[!IP]` with `IP` being either an IPv4 address, an IPv6 address,
or the name of a system network interface (such as `eth0`).
The possibility of configuring a network interface by name rather than by address should not be confused
with the logical interface name used internally by *rtpengine* (as described below). The `NAME` token
in the syntax above refers to the internal logical interface name, while the name of a system network
interface is used in place of the first `IP` token in the syntax above. For example, to configure a
logical network interface called `int` using all the addresses from the existing system network
interface `eth0`, you would use the syntax `int/eth0`. (Unless omitted, the second `IP` token used
for the advertised address must be an actual network address and cannot be an interface name.)
To configure multiple interfaces using the command-line options, simply present multiple `-i` or
`--interface=` options. When using the config file, only use a single `interface=` line, but specify
multiple values separated by semicolons (e.g. `interface = internal/12.23.34.45;external/23.34.45.54`).
If an interface option is given using a system interface name in place of a network address, and if
multiple network address are found configured on that network interface, then *rtpengine* behaves as
if multiple `--interface` options had been specified. For example, if interface `eth0` exists with
both addresses `192.168.1.120` and `2001:db8:85a3::7334` configured on it, and if the option
`--interface=ext/eth0` is given, then *rtpengine* would behave as if both options
`--interface=ext/192.168.1.120` and `--interface=ext/2001:db8:85a3::7334` had been specified.
The second IP address after the exclamation point is optional and can be used if the address to advertise
in outgoing SDP bodies should be different from the actual local address. This can be useful in certain
cases, such as your SIP proxy being behind NAT. For example, `--interface=10.65.76.2!192.0.2.4` means

@ -13,6 +13,8 @@
#include <stdlib.h>
#include <time.h>
#include <openssl/ssl.h>
#include <ifaddrs.h>
#include <net/if.h>
#include "poller.h"
#include "control_tcp.h"
@ -141,10 +143,11 @@ static void resources(void) {
static struct intf_config *if_addr_parse(char *s) {
static int if_addr_parse(GQueue *q, char *s, struct ifaddrs *ifas) {
str name;
char *c;
sockaddr_t addr, adv;
sockaddr_t *addr, adv;
GQueue addrs = G_QUEUE_INIT;
struct intf_config *ifa;
/* name */
@ -163,33 +166,82 @@ static struct intf_config *if_addr_parse(char *s) {
*c++ = 0;
/* address */
if (sockaddr_parse_any(&addr, s))
return NULL;
if (is_addr_unspecified(&addr))
return NULL;
addr = g_slice_alloc(sizeof(*addr));
if (!sockaddr_parse_any(addr, s)) {
if (is_addr_unspecified(addr))
return -1;
g_queue_push_tail(&addrs, addr);
}
else {
// could be an interface name?
ilog(LOG_DEBUG, "Could not parse '%s' as network address, checking to see if "
"it's an interface", s);
for (struct ifaddrs *ifa = ifas; ifa; ifa = ifa->ifa_next) {
if (strcmp(ifa->ifa_name, s))
continue;
if (!(ifa->ifa_flags & IFF_UP))
continue;
if (!ifa->ifa_addr)
continue;
if (ifa->ifa_addr->sa_family == AF_INET) {
struct sockaddr_in *sin = (void *) ifa->ifa_addr;
addr->family = __get_socket_family_enum(SF_IP4);
addr->u.ipv4 = sin->sin_addr;
}
else if (ifa->ifa_addr->sa_family == AF_INET6) {
struct sockaddr_in6 *sin = (void *) ifa->ifa_addr;
if (sin->sin6_scope_id)
continue; // link-local
addr->family = __get_socket_family_enum(SF_IP6);
addr->u.ipv6 = sin->sin6_addr;
}
else
continue;
// got one
ilog(LOG_DEBUG, "Determined address %s for interface '%s'",
sockaddr_print_buf(addr), s);
g_queue_push_tail(&addrs, addr);
addr = g_slice_alloc(sizeof(*addr));
}
// free last unused entry
g_slice_free1(sizeof(*addr), addr);
}
adv = addr;
if (!addrs.length) // nothing found
return -1;
ZERO(adv);
if (c) {
if (sockaddr_parse_any(&adv, c))
return NULL;
return -1;
if (is_addr_unspecified(&adv))
return NULL;
return -1;
}
ifa = g_slice_alloc0(sizeof(*ifa));
ifa->name = name;
ifa->local_address.addr = addr;
ifa->local_address.type = socktype_udp;
ifa->advertised_address.addr = adv;
ifa->advertised_address.type = ifa->local_address.type;
ifa->port_min = rtpe_config.port_min;
ifa->port_max = rtpe_config.port_max;
while ((addr = g_queue_pop_head(&addrs))) {
ifa = g_slice_alloc0(sizeof(*ifa));
ifa->name = name;
ifa->local_address.addr = *addr;
ifa->local_address.type = socktype_udp;
ifa->advertised_address.addr = adv;
if (is_addr_unspecified(&ifa->advertised_address.addr))
ifa->advertised_address.addr = *addr;
ifa->advertised_address.type = ifa->local_address.type;
ifa->port_min = rtpe_config.port_min;
ifa->port_max = rtpe_config.port_max;
// handle "base:suffix" separation for round-robin selection
ifa->name_rr_spec = ifa->name;
str_token(&ifa->name_base, &ifa->name_rr_spec, ':'); // sets name_rr_spec to null string if no ':' found
// handle "base:suffix" separation for round-robin selection
ifa->name_rr_spec = ifa->name;
str_token(&ifa->name_base, &ifa->name_rr_spec, ':'); // sets name_rr_spec to null string if no ':' found
g_queue_push_tail(q, ifa);
g_slice_free1(sizeof(*addr), addr);
}
return ifa;
return 0;
}
@ -233,7 +285,6 @@ static void options(int *argc, char ***argv) {
unsigned long uint_keyspace_db;
str str_keyspace_db;
char **iter;
struct intf_config *ifa;
char *listenps = NULL;
char *listenudps = NULL;
char *listenngs = NULL;
@ -325,12 +376,19 @@ static void options(int *argc, char ***argv) {
if (!listenps && !listenudps && !listenngs)
die("Missing option --listen-tcp, --listen-udp or --listen-ng");
struct ifaddrs *ifas;
if (getifaddrs(&ifas)) {
ifas = NULL;
ilog(LOG_WARN, "Failed to retrieve list of network interfaces: %s", strerror(errno));
}
for (iter = if_a; *iter; iter++) {
ifa = if_addr_parse(*iter);
if (!ifa)
int ret = if_addr_parse(&rtpe_config.interfaces, *iter, ifas);
if (ret)
die("Invalid interface specification: %s", *iter);
g_queue_push_tail(&rtpe_config.interfaces, ifa);
}
if (ifas)
freeifaddrs(ifas);
if (!rtpe_config.interfaces.length)
die("Cannot start without any configured interfaces");

Loading…
Cancel
Save