1
1
mirror of https://github.com/systemd/systemd-stable.git synced 2024-12-23 17:34:00 +03:00

network: automatically pick an address on link when L2TP.Local= is not specified

This makes L2TP.Local= support an empty string, 'auto', 'static', and
'dynamic'. When one of the values are specified, a local address is
automatically picked from the local interface of the tunnel.
This commit is contained in:
Yu Watanabe 2019-03-12 11:35:23 +09:00
parent 3a56e697c8
commit d053d08a37
3 changed files with 108 additions and 7 deletions

View File

@ -772,7 +772,12 @@
<varlistentry>
<term><varname>Local=</varname></term>
<listitem>
<para>Specifies the IP address of the local interface. This address must be the address of a local interface. This option is compulsory.</para>
<para>Specifies the IP address of the local interface. Takes an IP address, or the special values
<literal>auto</literal>, <literal>static</literal>, or <literal>dynamic</literal>. When an address
is set, then the local interface must have the address. If <literal>auto</literal>, then one of the
addresses on the local interface is used. Similarly, if <literal>static</literal> or
<literal>dynamic</literal> is set, then one of the static or dynamic addresses on the local
interface is used. Defaults to <literal>auto</literal>.</para>
</listitem>
</varlistentry>
<varlistentry>

View File

@ -11,6 +11,7 @@
#include "l2tp-tunnel.h"
#include "missing.h"
#include "netlink-util.h"
#include "networkd-address.h"
#include "networkd-manager.h"
#include "parse-util.h"
#include "socket-util.h"
@ -33,6 +34,14 @@ static const char* const l2tp_encap_type_table[_NETDEV_L2TP_ENCAPTYPE_MAX] = {
DEFINE_PRIVATE_STRING_TABLE_LOOKUP_FROM_STRING(l2tp_encap_type, L2tpEncapType);
DEFINE_CONFIG_PARSE_ENUM(config_parse_l2tp_encap_type, l2tp_encap_type, L2tpEncapType, "Failed to parse L2TP Encapsulation Type");
static const char* const l2tp_local_address_type_table[_NETDEV_L2TP_LOCAL_ADDRESS_MAX] = {
[NETDEV_L2TP_LOCAL_ADDRESS_AUTO] = "auto",
[NETDEV_L2TP_LOCAL_ADDRESS_STATIC] = "static",
[NETDEV_L2TP_LOCAL_ADDRESS_DYNAMIC] = "dynamic",
};
DEFINE_PRIVATE_STRING_TABLE_LOOKUP_FROM_STRING(l2tp_local_address_type, L2tpLocalAddressType);
static void l2tp_session_free(L2tpSession *s) {
if (!s)
return;
@ -91,13 +100,14 @@ static int l2tp_session_new_static(L2tpTunnel *t, const char *filename, unsigned
return 0;
}
static int netdev_l2tp_fill_message_tunnel(NetDev *netdev, sd_netlink_message **ret) {
static int netdev_l2tp_fill_message_tunnel(NetDev *netdev, union in_addr_union *local_address, sd_netlink_message **ret) {
_cleanup_(sd_netlink_message_unrefp) sd_netlink_message *m = NULL;
uint16_t encap_type;
L2tpTunnel *t;
int r;
assert(netdev);
assert(local_address);
t = L2TP(netdev);
@ -134,7 +144,7 @@ static int netdev_l2tp_fill_message_tunnel(NetDev *netdev, sd_netlink_message **
return log_netdev_error_errno(netdev, r, "Could not append L2TP_ATTR_ENCAP_TYPE attribute: %m");
if (t->family == AF_INET) {
r = sd_netlink_message_append_in_addr(m, L2TP_ATTR_IP_SADDR, &t->local.in);
r = sd_netlink_message_append_in_addr(m, L2TP_ATTR_IP_SADDR, &local_address->in);
if (r < 0)
return log_netdev_error_errno(netdev, r, "Could not append L2TP_ATTR_IP_SADDR attribute: %m");
@ -142,7 +152,7 @@ static int netdev_l2tp_fill_message_tunnel(NetDev *netdev, sd_netlink_message **
if (r < 0)
return log_netdev_error_errno(netdev, r, "Could not append L2TP_ATTR_IP_DADDR attribute: %m");
} else {
r = sd_netlink_message_append_in6_addr(m, L2TP_ATTR_IP6_SADDR, &t->local.in6);
r = sd_netlink_message_append_in6_addr(m, L2TP_ATTR_IP6_SADDR, &local_address->in6);
if (r < 0)
return log_netdev_error_errno(netdev, r, "Could not append L2TP_ATTR_IP6_SADDR attribute: %m");
@ -247,8 +257,54 @@ static int netdev_l2tp_fill_message_session(NetDev *netdev, L2tpSession *session
return 0;
}
static int l2tp_acquire_local_address_one(L2tpTunnel *t, Address *a, union in_addr_union *ret) {
if (a->family != t->family)
return -EINVAL;
if (in_addr_is_null(a->family, &a->in_addr_peer) <= 0)
return -EINVAL;
if (t->local_address_type == NETDEV_L2TP_LOCAL_ADDRESS_STATIC &&
!FLAGS_SET(a->flags, IFA_F_PERMANENT))
return -EINVAL;
if (t->local_address_type == NETDEV_L2TP_LOCAL_ADDRESS_DYNAMIC &&
FLAGS_SET(a->flags, IFA_F_PERMANENT))
return -EINVAL;
*ret = a->in_addr;
return 0;
}
static int l2tp_acquire_local_address(L2tpTunnel *t, Link *link, union in_addr_union *ret) {
Address *a;
Iterator i;
assert(t);
assert(link);
assert(ret);
assert(IN_SET(t->family, AF_INET, AF_INET6));
if (!in_addr_is_null(t->family, &t->local)) {
/* local address is explicitly specified. */
*ret = t->local;
return 0;
}
SET_FOREACH(a, link->addresses, i)
if (l2tp_acquire_local_address_one(t, a, ret) >= 0)
return 1;
SET_FOREACH(a, link->addresses_foreign, i)
if (l2tp_acquire_local_address_one(t, a, ret) >= 0)
return 1;
return -ENODATA;
}
static int netdev_l2tp_tunnel_create(NetDev *netdev, Link *link) {
_cleanup_(sd_netlink_message_unrefp) sd_netlink_message *m = NULL;
union in_addr_union local_address;
L2tpTunnel *t;
L2tpSession *session;
uint32_t serial;
@ -261,7 +317,18 @@ static int netdev_l2tp_tunnel_create(NetDev *netdev, Link *link) {
assert(t);
r = netdev_l2tp_fill_message_tunnel(netdev, &m);
r = l2tp_acquire_local_address(t, link, &local_address);
if (r < 0)
return log_netdev_error_errno(netdev, r, "Could not find local address.");
if (r > 0 && DEBUG_LOGGING) {
_cleanup_free_ char *str = NULL;
(void) in_addr_to_string(t->family, &local_address, &str);
log_netdev_debug(netdev, "Local address %s acquired.", strna(str));
}
r = netdev_l2tp_fill_message_tunnel(netdev, &local_address, &m);
if (r < 0)
return r;
@ -309,6 +376,26 @@ int config_parse_l2tp_tunnel_address(
assert(rvalue);
assert(data);
if (streq(lvalue, "Local")) {
L2tpLocalAddressType addr_type;
if (isempty(rvalue))
addr_type = NETDEV_L2TP_LOCAL_ADDRESS_AUTO;
else
addr_type = l2tp_local_address_type_from_string(rvalue);
if (addr_type >= 0) {
if (in_addr_is_null(t->family, &t->remote) != 0)
/* If Remote= is not specified yet, then also clear family. */
t->family = AF_UNSPEC;
t->local = IN_ADDR_NULL;
t->local_address_type = addr_type;
return 0;
}
}
if (t->family == AF_UNSPEC)
r = in_addr_from_string_auto(rvalue, &t->family, addr);
else
@ -546,9 +633,9 @@ static int netdev_l2tp_tunnel_verify(NetDev *netdev, const char *filename) {
"%s: L2TP tunnel with invalid address family configured. Ignoring",
filename);
if (in_addr_is_null(t->family, &t->local) || in_addr_is_null(t->family, &t->remote))
if (in_addr_is_null(t->family, &t->remote))
return log_netdev_error_errno(netdev, SYNTHETIC_ERRNO(EINVAL),
"%s: L2TP tunnel without a local or remote address configured. Ignoring",
"%s: L2TP tunnel without a remote address configured. Ignoring",
filename);
if (t->tunnel_id == 0 || t->peer_tunnel_id == 0)

View File

@ -21,6 +21,14 @@ typedef enum L2tpEncapType {
_NETDEV_L2TP_ENCAPTYPE_INVALID = -1,
} L2tpEncapType;
typedef enum L2tpLocalAddressType {
NETDEV_L2TP_LOCAL_ADDRESS_AUTO,
NETDEV_L2TP_LOCAL_ADDRESS_STATIC,
NETDEV_L2TP_LOCAL_ADDRESS_DYNAMIC,
_NETDEV_L2TP_LOCAL_ADDRESS_MAX,
_NETDEV_L2TP_LOCAL_ADDRESS_INVALID = -1,
} L2tpLocalAddressType;
typedef struct L2tpTunnel L2tpTunnel;
typedef struct L2tpSession {
@ -49,6 +57,7 @@ struct L2tpTunnel {
bool udp6_csum_rx;
bool udp6_csum_tx;
L2tpLocalAddressType local_address_type;
union in_addr_union local;
union in_addr_union remote;