mirror of
https://github.com/morgan9e/systemd
synced 2026-04-15 08:56:15 +09:00
The RA's Retransmission Timer field was being ignored. This resolves the IPv6
Core Conformance test, v6LC.2.1.5 [1].
Retransmission Timer is a 32-bit unsigned integer. The time, in milliseconds,
between retransmitted Neighbor Solicitation messages. Used by the Address
Resolution and Neighbor Unreachability Detection (NUD) algorithm.
Support setting a default value for the neighbour retransmission timer value with:
[Network]
IPv6RetransmissionTimeSec=<int>
By default, upon receiving a Router Advertisement with the Retransmission Timer
field set to a non-zero value, it will update the kernel's retransmit timer value.
To disable this behaviour, configure the UseIPv6RetransmissionTime= under the
[IPv6AcceptRA] section.
[IPv6AcceptRA]
UseIPv6RetransmissionTime=<bool>
RFC4861: Neighbor Discovery in IPv6
* Section 4.2 RA Message Format.
* Section 6.3.4 Processing Received Router Advertisements
A Router Advertisement field (e.g., Cur Hop Limit, Reachable Time,
and Retrans Timer) may contain a value denoting that it is
unspecified. In such cases, the parameter should be ignored and the
host should continue using whatever value it is already using. In
particular, a host MUST NOT interpret the unspecified value as
meaning change back to the default value that was in use before the
first Router Advertisement was received.
The RetransTimer variable SHOULD be copied from the Retrans Timer
field, if the received value is non-zero.
References
[1] IPv6 Core Conformance Spec (PDF)
158 lines
4.2 KiB
C
158 lines
4.2 KiB
C
/* SPDX-License-Identifier: LGPL-2.1-or-later */
|
|
|
|
#include <errno.h>
|
|
#include <fcntl.h>
|
|
#include <stdio.h>
|
|
#include <unistd.h>
|
|
|
|
#include "af-list.h"
|
|
#include "fd-util.h"
|
|
#include "fileio.h"
|
|
#include "log.h"
|
|
#include "macro.h"
|
|
#include "path-util.h"
|
|
#include "socket-util.h"
|
|
#include "string-util.h"
|
|
#include "sysctl-util.h"
|
|
|
|
char *sysctl_normalize(char *s) {
|
|
char *n;
|
|
|
|
n = strpbrk(s, "/.");
|
|
|
|
/* If the first separator is a slash, the path is
|
|
* assumed to be normalized and slashes remain slashes
|
|
* and dots remains dots. */
|
|
|
|
if (n && *n == '.')
|
|
/* Dots become slashes and slashes become dots. Fun. */
|
|
do {
|
|
if (*n == '.')
|
|
*n = '/';
|
|
else
|
|
*n = '.';
|
|
|
|
n = strpbrk(n + 1, "/.");
|
|
} while (n);
|
|
|
|
path_simplify(s);
|
|
|
|
/* Kill the leading slash, but keep the first character of the string in the same place. */
|
|
if (s[0] == '/' && s[1] != 0)
|
|
memmove(s, s+1, strlen(s));
|
|
|
|
return s;
|
|
}
|
|
|
|
int sysctl_write(const char *property, const char *value) {
|
|
char *p;
|
|
|
|
assert(property);
|
|
assert(value);
|
|
|
|
p = strjoina("/proc/sys/", property);
|
|
|
|
path_simplify(p);
|
|
if (!path_is_normalized(p))
|
|
return -EINVAL;
|
|
|
|
log_debug("Setting '%s' to '%s'", p, value);
|
|
|
|
return write_string_file(p, value, WRITE_STRING_FILE_VERIFY_ON_FAILURE | WRITE_STRING_FILE_DISABLE_BUFFER | WRITE_STRING_FILE_SUPPRESS_REDUNDANT_VIRTUAL);
|
|
}
|
|
|
|
int sysctl_writef(const char *property, const char *format, ...) {
|
|
_cleanup_free_ char *v = NULL;
|
|
va_list ap;
|
|
int r;
|
|
|
|
va_start(ap, format);
|
|
r = vasprintf(&v, format, ap);
|
|
va_end(ap);
|
|
|
|
if (r < 0)
|
|
return -ENOMEM;
|
|
|
|
return sysctl_write(property, v);
|
|
}
|
|
|
|
int sysctl_write_ip_property(int af, const char *ifname, const char *property, const char *value) {
|
|
const char *p;
|
|
|
|
assert(property);
|
|
assert(value);
|
|
|
|
if (!IN_SET(af, AF_INET, AF_INET6))
|
|
return -EAFNOSUPPORT;
|
|
|
|
if (ifname) {
|
|
if (!ifname_valid_full(ifname, IFNAME_VALID_SPECIAL))
|
|
return -EINVAL;
|
|
|
|
p = strjoina("net/", af_to_ipv4_ipv6(af), "/conf/", ifname, "/", property);
|
|
} else
|
|
p = strjoina("net/", af_to_ipv4_ipv6(af), "/", property);
|
|
|
|
return sysctl_write(p, value);
|
|
}
|
|
|
|
int sysctl_write_ip_neighbor_property(int af, const char *ifname, const char *property, const char *value) {
|
|
const char *p;
|
|
|
|
assert(property);
|
|
assert(value);
|
|
assert(ifname);
|
|
|
|
if (!IN_SET(af, AF_INET, AF_INET6))
|
|
return -EAFNOSUPPORT;
|
|
|
|
if (ifname) {
|
|
if (!ifname_valid_full(ifname, IFNAME_VALID_SPECIAL))
|
|
return -EINVAL;
|
|
p = strjoina("net/", af_to_ipv4_ipv6(af), "/neigh/", ifname, "/", property);
|
|
} else
|
|
p = strjoina("net/", af_to_ipv4_ipv6(af), "/neigh/default/", property);
|
|
|
|
return sysctl_write(p, value);
|
|
}
|
|
|
|
int sysctl_read(const char *property, char **ret) {
|
|
char *p;
|
|
int r;
|
|
|
|
assert(property);
|
|
|
|
p = strjoina("/proc/sys/", property);
|
|
|
|
path_simplify(p);
|
|
if (!path_is_normalized(p)) /* Filter out attempts to write to /proc/sys/../../…, just in case */
|
|
return -EINVAL;
|
|
|
|
r = read_full_virtual_file(p, ret, NULL);
|
|
if (r < 0)
|
|
return r;
|
|
if (ret)
|
|
delete_trailing_chars(*ret, NEWLINE);
|
|
|
|
return r;
|
|
}
|
|
|
|
int sysctl_read_ip_property(int af, const char *ifname, const char *property, char **ret) {
|
|
const char *p;
|
|
|
|
assert(property);
|
|
|
|
if (!IN_SET(af, AF_INET, AF_INET6))
|
|
return -EAFNOSUPPORT;
|
|
|
|
if (ifname) {
|
|
if (!ifname_valid_full(ifname, IFNAME_VALID_SPECIAL))
|
|
return -EINVAL;
|
|
|
|
p = strjoina("net/", af_to_ipv4_ipv6(af), "/conf/", ifname, "/", property);
|
|
} else
|
|
p = strjoina("net/", af_to_ipv4_ipv6(af), "/", property);
|
|
|
|
return sysctl_read(p, ret);
|
|
}
|