src/shared/: split AF_UNIX/AF_VSOCK address parsing into src/basic/
We'll use it from libsystemd0 later, but AF_INET/6 requires some netlink calls and thus the additional library dependency
This commit is contained in:
@@ -1472,3 +1472,71 @@ int connect_unix_path(int fd, int dir_fd, const char *path) {
|
||||
|
||||
return RET_NERRNO(connect(fd, &sa.sa, salen));
|
||||
}
|
||||
|
||||
int socket_address_parse_unix(SocketAddress *ret_address, const char *s) {
|
||||
struct sockaddr_un un;
|
||||
int r;
|
||||
|
||||
assert(ret_address);
|
||||
assert(s);
|
||||
|
||||
if (!IN_SET(*s, '/', '@'))
|
||||
return -EPROTO;
|
||||
|
||||
r = sockaddr_un_set_path(&un, s);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
*ret_address = (SocketAddress) {
|
||||
.sockaddr.un = un,
|
||||
.size = r,
|
||||
};
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int socket_address_parse_vsock(SocketAddress *ret_address, const char *s) {
|
||||
/* AF_VSOCK socket in vsock:cid:port notation */
|
||||
_cleanup_free_ char *n = NULL;
|
||||
char *e, *cid_start;
|
||||
unsigned port, cid;
|
||||
int r;
|
||||
|
||||
assert(ret_address);
|
||||
assert(s);
|
||||
|
||||
cid_start = startswith(s, "vsock:");
|
||||
if (!cid_start)
|
||||
return -EPROTO;
|
||||
|
||||
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))
|
||||
cid = VMADDR_CID_ANY;
|
||||
else {
|
||||
r = safe_atou(n, &cid);
|
||||
if (r < 0)
|
||||
return r;
|
||||
}
|
||||
|
||||
*ret_address = (SocketAddress) {
|
||||
.sockaddr.vm = {
|
||||
.svm_cid = cid,
|
||||
.svm_family = AF_VSOCK,
|
||||
.svm_port = port,
|
||||
},
|
||||
.size = sizeof(struct sockaddr_vm),
|
||||
};
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -336,3 +336,9 @@ int socket_get_mtu(int fd, int af, size_t *ret);
|
||||
#define UCRED_INVALID { .pid = 0, .uid = UID_INVALID, .gid = GID_INVALID }
|
||||
|
||||
int connect_unix_path(int fd, int dir_fd, const char *path);
|
||||
|
||||
/* Parses AF_UNIX and AF_VSOCK addresses. AF_INET[6] require some netlink calls, so it cannot be in
|
||||
* src/basic/ and is done from 'socket_local_address from src/shared/. Return -EPROTO in case of
|
||||
* protocol mismatch. */
|
||||
int socket_address_parse_unix(SocketAddress *ret_address, const char *s);
|
||||
int socket_address_parse_vsock(SocketAddress *ret_address, const char *s);
|
||||
|
||||
+57
-103
@@ -17,120 +17,74 @@
|
||||
#include "string-util.h"
|
||||
|
||||
int socket_address_parse(SocketAddress *a, const char *s) {
|
||||
_cleanup_free_ char *n = NULL;
|
||||
char *e;
|
||||
uint16_t port;
|
||||
int r;
|
||||
|
||||
assert(a);
|
||||
assert(s);
|
||||
|
||||
if (IN_SET(*s, '/', '@')) {
|
||||
/* AF_UNIX socket */
|
||||
struct sockaddr_un un;
|
||||
r = socket_address_parse_unix(a, s);
|
||||
if (r == -EPROTO)
|
||||
r = socket_address_parse_vsock(a, s);
|
||||
if (r != -EPROTO)
|
||||
return r;
|
||||
|
||||
r = sockaddr_un_set_path(&un, s);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
*a = (SocketAddress) {
|
||||
.sockaddr.un = un,
|
||||
.size = r,
|
||||
};
|
||||
|
||||
} else if (startswith(s, "vsock:")) {
|
||||
/* AF_VSOCK socket in vsock:cid:port notation */
|
||||
const char *cid_start = s + STRLEN("vsock:");
|
||||
unsigned port, cid;
|
||||
|
||||
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))
|
||||
cid = VMADDR_CID_ANY;
|
||||
else {
|
||||
r = safe_atou(n, &cid);
|
||||
if (r < 0)
|
||||
return r;
|
||||
}
|
||||
|
||||
*a = (SocketAddress) {
|
||||
.sockaddr.vm = {
|
||||
.svm_cid = cid,
|
||||
.svm_family = AF_VSOCK,
|
||||
.svm_port = port,
|
||||
},
|
||||
.size = sizeof(struct sockaddr_vm),
|
||||
};
|
||||
r = parse_ip_port(s, &port);
|
||||
if (r == -ERANGE)
|
||||
return r; /* Valid port syntax, but the numerical value is wrong for a port. */
|
||||
if (r >= 0) {
|
||||
/* Just a port */
|
||||
if (socket_ipv6_is_supported())
|
||||
*a = (SocketAddress) {
|
||||
.sockaddr.in6 = {
|
||||
.sin6_family = AF_INET6,
|
||||
.sin6_port = htobe16(port),
|
||||
.sin6_addr = in6addr_any,
|
||||
},
|
||||
.size = sizeof(struct sockaddr_in6),
|
||||
};
|
||||
else
|
||||
*a = (SocketAddress) {
|
||||
.sockaddr.in = {
|
||||
.sin_family = AF_INET,
|
||||
.sin_port = htobe16(port),
|
||||
.sin_addr.s_addr = INADDR_ANY,
|
||||
},
|
||||
.size = sizeof(struct sockaddr_in),
|
||||
};
|
||||
|
||||
} else {
|
||||
uint16_t port;
|
||||
union in_addr_union address;
|
||||
int family, ifindex;
|
||||
|
||||
r = parse_ip_port(s, &port);
|
||||
if (r == -ERANGE)
|
||||
return r; /* Valid port syntax, but the numerical value is wrong for a port. */
|
||||
if (r >= 0) {
|
||||
/* Just a port */
|
||||
if (socket_ipv6_is_supported())
|
||||
*a = (SocketAddress) {
|
||||
.sockaddr.in6 = {
|
||||
.sin6_family = AF_INET6,
|
||||
.sin6_port = htobe16(port),
|
||||
.sin6_addr = in6addr_any,
|
||||
},
|
||||
.size = sizeof(struct sockaddr_in6),
|
||||
};
|
||||
else
|
||||
*a = (SocketAddress) {
|
||||
.sockaddr.in = {
|
||||
.sin_family = AF_INET,
|
||||
.sin_port = htobe16(port),
|
||||
.sin_addr.s_addr = INADDR_ANY,
|
||||
},
|
||||
.size = sizeof(struct sockaddr_in),
|
||||
};
|
||||
r = in_addr_port_ifindex_name_from_string_auto(s, &family, &address, &port, &ifindex, NULL);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
} else {
|
||||
union in_addr_union address;
|
||||
int family, ifindex;
|
||||
if (port == 0) /* No port, no go. */
|
||||
return -EINVAL;
|
||||
|
||||
r = in_addr_port_ifindex_name_from_string_auto(s, &family, &address, &port, &ifindex, NULL);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
if (port == 0) /* No port, no go. */
|
||||
return -EINVAL;
|
||||
|
||||
if (family == AF_INET)
|
||||
*a = (SocketAddress) {
|
||||
.sockaddr.in = {
|
||||
.sin_family = AF_INET,
|
||||
.sin_addr = address.in,
|
||||
.sin_port = htobe16(port),
|
||||
},
|
||||
.size = sizeof(struct sockaddr_in),
|
||||
};
|
||||
else if (family == AF_INET6)
|
||||
*a = (SocketAddress) {
|
||||
.sockaddr.in6 = {
|
||||
.sin6_family = AF_INET6,
|
||||
.sin6_addr = address.in6,
|
||||
.sin6_port = htobe16(port),
|
||||
.sin6_scope_id = ifindex,
|
||||
},
|
||||
.size = sizeof(struct sockaddr_in6),
|
||||
};
|
||||
else
|
||||
assert_not_reached();
|
||||
}
|
||||
if (family == AF_INET)
|
||||
*a = (SocketAddress) {
|
||||
.sockaddr.in = {
|
||||
.sin_family = AF_INET,
|
||||
.sin_addr = address.in,
|
||||
.sin_port = htobe16(port),
|
||||
},
|
||||
.size = sizeof(struct sockaddr_in),
|
||||
};
|
||||
else if (family == AF_INET6)
|
||||
*a = (SocketAddress) {
|
||||
.sockaddr.in6 = {
|
||||
.sin6_family = AF_INET6,
|
||||
.sin6_addr = address.in6,
|
||||
.sin6_port = htobe16(port),
|
||||
.sin6_scope_id = ifindex,
|
||||
},
|
||||
.size = sizeof(struct sockaddr_in6),
|
||||
};
|
||||
else
|
||||
assert_not_reached();
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
Reference in New Issue
Block a user