util-lib: move things that parse ifnames to shared/

In subsequent commits, calls to if_nametoindex() will be replaced by a wrapper
that falls back to alternative name resolution over netlink. netlink support
requires libsystemd (for sd-netlink), and we don't want to add any functions
that require netlink in basic/. So stuff that calls if_nametoindex() for user
supplied interface names, and everything that depends on that, needs to be
moved.
This commit is contained in:
Zbigniew Jędrzejewski-Szmek
2020-01-11 12:07:28 +01:00
parent 955bb7fac3
commit 5c3fa98db6
20 changed files with 594 additions and 541 deletions
-36
View File
@@ -439,42 +439,6 @@ int in_addr_from_string_auto(const char *s, int *ret_family, union in_addr_union
return -EINVAL;
}
int in_addr_ifindex_from_string_auto(const char *s, int *family, union in_addr_union *ret_addr, int *ret_ifindex) {
_cleanup_free_ char *buf = NULL;
const char *suffix;
int r, ifindex = 0;
assert(s);
assert(family);
assert(ret_addr);
/* Similar to in_addr_from_string_auto() but also parses an optionally appended IPv6 zone suffix ("scope id")
* if one is found. */
suffix = strchr(s, '%');
if (suffix) {
if (ret_ifindex) {
/* If we shall return the interface index, try to parse it */
ifindex = parse_ifindex_or_ifname(suffix + 1);
if (ifindex < 0)
return ifindex;
}
s = buf = strndup(s, suffix - s);
if (!buf)
return -ENOMEM;
}
r = in_addr_from_string_auto(s, family, ret_addr);
if (r < 0)
return r;
if (ret_ifindex)
*ret_ifindex = ifindex;
return r;
}
unsigned char in4_addr_netmask_to_prefixlen(const struct in_addr *addr) {
assert(addr);
+1 -1
View File
@@ -42,7 +42,7 @@ int in_addr_prefix_to_string(int family, const union in_addr_union *u, unsigned
int in_addr_ifindex_to_string(int family, const union in_addr_union *u, int ifindex, char **ret);
int in_addr_from_string(int family, const char *s, union in_addr_union *ret);
int in_addr_from_string_auto(const char *s, int *ret_family, union in_addr_union *ret);
int in_addr_ifindex_from_string_auto(const char *s, int *family, union in_addr_union *ret, int *ifindex);
unsigned char in4_addr_netmask_to_prefixlen(const struct in_addr *addr);
struct in_addr* in4_addr_prefixlen_to_netmask(struct in_addr *addr, unsigned char prefixlen);
int in4_addr_default_prefixlen(const struct in_addr *addr, unsigned char *prefixlen);
-28
View File
@@ -134,31 +134,3 @@ int socket_address_listen(
return r;
}
int make_socket_fd(int log_level, const char* address, int type, int flags) {
SocketAddress a;
int fd, r;
r = socket_address_parse(&a, address);
if (r < 0)
return log_error_errno(r, "Failed to parse socket address \"%s\": %m", address);
a.type = type;
fd = socket_address_listen(&a, type | flags, SOMAXCONN, SOCKET_ADDRESS_DEFAULT,
NULL, false, false, false, 0755, 0644, NULL);
if (fd < 0 || log_get_max_level() >= log_level) {
_cleanup_free_ char *p = NULL;
r = socket_address_print(&a, &p);
if (r < 0)
return log_error_errno(r, "socket_address_print(): %m");
if (fd < 0)
log_error_errno(fd, "Failed to listen on %s: %m", p);
else
log_full(log_level, "Listening on %s", p);
}
return fd;
}
-247
View File
@@ -52,227 +52,6 @@ static const char* const socket_address_type_table[] = {
DEFINE_STRING_TABLE_LOOKUP(socket_address_type, int);
int socket_address_parse(SocketAddress *a, const char *s) {
_cleanup_free_ char *n = NULL;
char *e;
int r;
assert(a);
assert(s);
*a = (SocketAddress) {
.type = SOCK_STREAM,
};
if (*s == '[') {
uint16_t port;
/* IPv6 in [x:.....:z]:p notation */
e = strchr(s+1, ']');
if (!e)
return -EINVAL;
n = strndup(s+1, e-s-1);
if (!n)
return -ENOMEM;
errno = 0;
if (inet_pton(AF_INET6, n, &a->sockaddr.in6.sin6_addr) <= 0)
return errno_or_else(EINVAL);
e++;
if (*e != ':')
return -EINVAL;
e++;
r = parse_ip_port(e, &port);
if (r < 0)
return r;
a->sockaddr.in6.sin6_family = AF_INET6;
a->sockaddr.in6.sin6_port = htobe16(port);
a->size = sizeof(struct sockaddr_in6);
} else if (*s == '/') {
/* AF_UNIX socket */
size_t l;
l = strlen(s);
if (l >= sizeof(a->sockaddr.un.sun_path)) /* Note that we refuse non-NUL-terminated sockets when
* parsing (the kernel itself is less strict here in what it
* accepts) */
return -EINVAL;
a->sockaddr.un.sun_family = AF_UNIX;
memcpy(a->sockaddr.un.sun_path, s, l);
a->size = offsetof(struct sockaddr_un, sun_path) + l + 1;
} else if (*s == '@') {
/* Abstract AF_UNIX socket */
size_t l;
l = strlen(s+1);
if (l >= sizeof(a->sockaddr.un.sun_path) - 1) /* Note that we refuse non-NUL-terminated sockets here
* when parsing, even though abstract namespace sockets
* explicitly allow embedded NUL bytes and don't consider
* them special. But it's simply annoying to debug such
* sockets. */
return -EINVAL;
a->sockaddr.un.sun_family = AF_UNIX;
memcpy(a->sockaddr.un.sun_path+1, s+1, l);
a->size = offsetof(struct sockaddr_un, sun_path) + 1 + l;
} else if (startswith(s, "vsock:")) {
/* AF_VSOCK socket in vsock:cid:port notation */
const char *cid_start = s + STRLEN("vsock:");
unsigned port;
e = strchr(cid_start, ':');
if (!e)
return -EINVAL;
r = safe_atou(e+1, &port);
if (r < 0)
return r;
n = strndup(cid_start, e - cid_start);
if (!n)
return -ENOMEM;
if (!isempty(n)) {
r = safe_atou(n, &a->sockaddr.vm.svm_cid);
if (r < 0)
return r;
} else
a->sockaddr.vm.svm_cid = VMADDR_CID_ANY;
a->sockaddr.vm.svm_family = AF_VSOCK;
a->sockaddr.vm.svm_port = port;
a->size = sizeof(struct sockaddr_vm);
} else {
uint16_t port;
e = strchr(s, ':');
if (e) {
r = parse_ip_port(e + 1, &port);
if (r < 0)
return r;
n = strndup(s, e-s);
if (!n)
return -ENOMEM;
/* IPv4 in w.x.y.z:p notation? */
r = inet_pton(AF_INET, n, &a->sockaddr.in.sin_addr);
if (r < 0)
return -errno;
if (r > 0) {
/* Gotcha, it's a traditional IPv4 address */
a->sockaddr.in.sin_family = AF_INET;
a->sockaddr.in.sin_port = htobe16(port);
a->size = sizeof(struct sockaddr_in);
} else {
unsigned idx;
if (strlen(n) > IF_NAMESIZE-1)
return -EINVAL;
/* Uh, our last resort, an interface name */
idx = if_nametoindex(n);
if (idx == 0)
return -EINVAL;
a->sockaddr.in6.sin6_family = AF_INET6;
a->sockaddr.in6.sin6_port = htobe16(port);
a->sockaddr.in6.sin6_scope_id = idx;
a->sockaddr.in6.sin6_addr = in6addr_any;
a->size = sizeof(struct sockaddr_in6);
}
} else {
/* Just a port */
r = parse_ip_port(s, &port);
if (r < 0)
return r;
if (socket_ipv6_is_supported()) {
a->sockaddr.in6.sin6_family = AF_INET6;
a->sockaddr.in6.sin6_port = htobe16(port);
a->sockaddr.in6.sin6_addr = in6addr_any;
a->size = sizeof(struct sockaddr_in6);
} else {
a->sockaddr.in.sin_family = AF_INET;
a->sockaddr.in.sin_port = htobe16(port);
a->sockaddr.in.sin_addr.s_addr = INADDR_ANY;
a->size = sizeof(struct sockaddr_in);
}
}
}
return 0;
}
int socket_address_parse_and_warn(SocketAddress *a, const char *s) {
SocketAddress b;
int r;
/* Similar to socket_address_parse() but warns for IPv6 sockets when we don't support them. */
r = socket_address_parse(&b, s);
if (r < 0)
return r;
if (!socket_ipv6_is_supported() && b.sockaddr.sa.sa_family == AF_INET6) {
log_warning("Binding to IPv6 address not available since kernel does not support IPv6.");
return -EAFNOSUPPORT;
}
*a = b;
return 0;
}
int socket_address_parse_netlink(SocketAddress *a, const char *s) {
_cleanup_free_ char *word = NULL;
unsigned group = 0;
int family, r;
assert(a);
assert(s);
zero(*a);
a->type = SOCK_RAW;
r = extract_first_word(&s, &word, NULL, 0);
if (r < 0)
return r;
if (r == 0)
return -EINVAL;
family = netlink_family_from_string(word);
if (family < 0)
return -EINVAL;
if (!isempty(s)) {
r = safe_atou(s, &group);
if (r < 0)
return r;
}
a->sockaddr.nl.nl_family = AF_NETLINK;
a->sockaddr.nl.nl_groups = group;
a->type = SOCK_RAW;
a->size = sizeof(struct sockaddr_nl);
a->protocol = family;
return 0;
}
int socket_address_verify(const SocketAddress *a, bool strict) {
assert(a);
@@ -482,32 +261,6 @@ bool socket_address_equal(const SocketAddress *a, const SocketAddress *b) {
return true;
}
bool socket_address_is(const SocketAddress *a, const char *s, int type) {
struct SocketAddress b;
assert(a);
assert(s);
if (socket_address_parse(&b, s) < 0)
return false;
b.type = type;
return socket_address_equal(a, &b);
}
bool socket_address_is_netlink(const SocketAddress *a, const char *s) {
struct SocketAddress b;
assert(a);
assert(s);
if (socket_address_parse_netlink(&b, s) < 0)
return false;
return socket_address_equal(a, &b);
}
const char* socket_address_get_path(const SocketAddress *a) {
assert(a);
+4 -10
View File
@@ -41,6 +41,8 @@ union sockaddr_union {
uint8_t un_buffer[sizeof(struct sockaddr_un) + 1];
};
#define SUN_PATH_LEN (sizeof(((struct sockaddr_un){}).sun_path))
typedef struct SocketAddress {
union sockaddr_union sockaddr;
@@ -68,12 +70,6 @@ typedef enum SocketAddressBindIPv6Only {
const char* socket_address_type_to_string(int t) _const_;
int socket_address_type_from_string(const char *s) _pure_;
int socket_address_parse(SocketAddress *a, const char *s);
int socket_address_parse_and_warn(SocketAddress *a, const char *s);
int socket_address_parse_netlink(SocketAddress *a, const char *s);
int socket_address_print(const SocketAddress *a, char **p);
int socket_address_verify(const SocketAddress *a, bool strict) _pure_;
int sockaddr_un_unlink(const struct sockaddr_un *sa);
static inline int socket_address_unlink(const SocketAddress *a) {
@@ -94,11 +90,9 @@ int socket_address_listen(
mode_t directory_mode,
mode_t socket_mode,
const char *label);
int make_socket_fd(int log_level, const char* address, int type, int flags);
bool socket_address_is(const SocketAddress *a, const char *s, int type);
bool socket_address_is_netlink(const SocketAddress *a, const char *s);
int socket_address_verify(const SocketAddress *a, bool strict) _pure_;
int socket_address_print(const SocketAddress *a, char **p);
bool socket_address_matches_fd(const SocketAddress *a, int fd);
bool socket_address_equal(const SocketAddress *a, const SocketAddress *b) _pure_;