#include <errno.h>
#include <limits.h>
#include <linux/if.h>
+#include <linux/if_arp.h>
#include <net/if.h>
#include <netdb.h>
#include <netinet/ip.h>
return memcpy_safe(buf, CMSG_DATA(cmsg), buf_len);
}
+size_t sockaddr_ll_len(const struct sockaddr_ll *sa) {
+ /* Certain hardware address types (e.g Infiniband) do not fit into sll_addr
+ * (8 bytes) and run over the structure. This function returns the correct size that
+ * must be passed to kernel. */
+
+ assert(sa->sll_family == AF_PACKET);
+
+ size_t mac_len = sizeof(sa->sll_addr);
+
+ if (be16toh(sa->sll_hatype) == ARPHRD_ETHER)
+ mac_len = MAX(mac_len, (size_t) ETH_ALEN);
+ if (be16toh(sa->sll_hatype) == ARPHRD_INFINIBAND)
+ mac_len = MAX(mac_len, (size_t) INFINIBAND_ALEN);
+
+ return offsetof(struct sockaddr_ll, sll_addr) + mac_len;
+}
+
+size_t sockaddr_un_len(const struct sockaddr_un *sa) {
+ /* Covers only file system and abstract AF_UNIX socket addresses, but not unnamed socket addresses. */
+
+ assert(sa->sun_family == AF_UNIX);
+
+ return offsetof(struct sockaddr_un, sun_path) +
+ (sa->sun_path[0] == 0 ?
+ 1 + strnlen(sa->sun_path+1, sizeof(sa->sun_path)-1) :
+ strnlen(sa->sun_path, sizeof(sa->sun_path))+1);
+}
+
+size_t sockaddr_len(const union sockaddr_union *sa) {
+ switch (sa->sa.sa_family) {
+ case AF_INET:
+ return sizeof(struct sockaddr_in);
+ case AF_INET6:
+ return sizeof(struct sockaddr_in6);
+ case AF_UNIX:
+ return sockaddr_un_len(&sa->un);
+ case AF_PACKET:
+ return sockaddr_ll_len(&sa->ll);
+ case AF_NETLINK:
+ return sizeof(struct sockaddr_nl);
+ case AF_VSOCK:
+ return sizeof(struct sockaddr_vm);
+ default:
+ assert_not_reached();
+ }
+}
+
int socket_ioctl_fd(void) {
int fd;
(size) == CMSG_ALIGN(size) ? 1 : -1]; \
}
-/*
- * Certain hardware address types (e.g Infiniband) do not fit into sll_addr
- * (8 bytes) and run over the structure. This macro returns the correct size that
- * must be passed to kernel.
- */
-#define SOCKADDR_LL_LEN(sa) \
- ({ \
- const struct sockaddr_ll *_sa = &(sa); \
- size_t _mac_len = sizeof(_sa->sll_addr); \
- assert(_sa->sll_family == AF_PACKET); \
- if (be16toh(_sa->sll_hatype) == ARPHRD_ETHER) \
- _mac_len = MAX(_mac_len, (size_t) ETH_ALEN); \
- if (be16toh(_sa->sll_hatype) == ARPHRD_INFINIBAND) \
- _mac_len = MAX(_mac_len, (size_t) INFINIBAND_ALEN); \
- offsetof(struct sockaddr_ll, sll_addr) + _mac_len; \
- })
+size_t sockaddr_ll_len(const struct sockaddr_ll *sa);
-/* Covers only file system and abstract AF_UNIX socket addresses, but not unnamed socket addresses. */
-#define SOCKADDR_UN_LEN(sa) \
- ({ \
- const struct sockaddr_un *_sa = &(sa); \
- assert(_sa->sun_family == AF_UNIX); \
- offsetof(struct sockaddr_un, sun_path) + \
- (_sa->sun_path[0] == 0 ? \
- 1 + strnlen(_sa->sun_path+1, sizeof(_sa->sun_path)-1) : \
- strnlen(_sa->sun_path, sizeof(_sa->sun_path))+1); \
- })
+size_t sockaddr_un_len(const struct sockaddr_un *sa);
-#define SOCKADDR_LEN(saddr) \
- ({ \
- const union sockaddr_union *__sa = &(saddr); \
- size_t _len; \
- switch (__sa->sa.sa_family) { \
- case AF_INET: \
- _len = sizeof(struct sockaddr_in); \
- break; \
- case AF_INET6: \
- _len = sizeof(struct sockaddr_in6); \
- break; \
- case AF_UNIX: \
- _len = SOCKADDR_UN_LEN(__sa->un); \
- break; \
- case AF_PACKET: \
- _len = SOCKADDR_LL_LEN(__sa->ll); \
- break; \
- case AF_NETLINK: \
- _len = sizeof(struct sockaddr_nl); \
- break; \
- case AF_VSOCK: \
- _len = sizeof(struct sockaddr_vm); \
- break; \
- default: \
- assert_not_reached(); \
- } \
- _len; \
- })
+size_t sockaddr_len(const union sockaddr_union *sa);
int socket_ioctl_fd(void);
/* We may overflow link->ll. link->ll_buffer ensures we have enough space. */
memcpy(link->ll.sll_addr, bcast_addr->bytes, bcast_addr->length);
- r = bind(s, &link->sa, SOCKADDR_LL_LEN(link->ll));
+ r = bind(s, &link->sa, sockaddr_ll_len(&link->ll));
if (r < 0)
return -errno;
assert(packet);
assert(len > 0);
- if (sendto(s, packet, len, 0, &link->sa, SOCKADDR_LL_LEN(link->ll)) < 0)
+ if (sendto(s, packet, len, 0, &link->sa, sockaddr_ll_len(&link->ll)) < 0)
return -errno;
return 0;
/* Note that we use the old /var/run prefix here, to increase compatibility with really old containers */
.sun_path = "/var/run/dbus/system_bus_socket",
};
- b->sockaddr_size = SOCKADDR_UN_LEN(b->sockaddr.un);
+ b->sockaddr_size = sockaddr_un_len(&b->sockaddr.un);
b->is_local = false;
return 0;
};
struct msghdr mh = {
.msg_name = (struct sockaddr*) &sa.sa,
- .msg_namelen = SOCKADDR_UN_LEN(sa.un),
+ .msg_namelen = sockaddr_un_len(&sa.un),
};
ssize_t k;
bool have_syslog_identifier = false;
/* Make an address -> name query */
sa.in.sin_addr.s_addr = inet_addr(argc >= 3 ? argv[2] : "193.99.144.71");
- r = sd_resolve_getnameinfo(resolve, &q2, &sa.sa, SOCKADDR_LEN(sa), 0, SD_RESOLVE_GET_BOTH, getnameinfo_handler, NULL);
+ r = sd_resolve_getnameinfo(resolve, &q2, &sa.sa, sockaddr_len(&sa), 0, SD_RESOLVE_GET_BOTH, getnameinfo_handler, NULL);
if (r < 0)
log_error_errno(r, "sd_resolve_getnameinfo(): %m");
(void) sockaddr_un_unlink(&sockaddr.un);
WITH_UMASK(0000)
- if (bind(m->listen_fd, &sockaddr.sa, SOCKADDR_UN_LEN(sockaddr.un)) < 0)
+ if (bind(m->listen_fd, &sockaddr.sa, sockaddr_un_len(&sockaddr.un)) < 0)
return log_error_errno(errno, "Failed to bind socket: %m");
if (listen(m->listen_fd, SOMAXCONN) < 0)
(void) sockaddr_un_unlink(&sa.un);
WITH_UMASK(0577) { /* only set "w" bit, which is all that's necessary for connecting from the container */
- r = bind(fd, &sa.sa, SOCKADDR_UN_LEN(sa.un));
+ r = bind(fd, &sa.sa, sockaddr_un_len(&sa.un));
if (r < 0)
return log_error_errno(errno, "bind(" NSPAWN_NOTIFY_SOCKET_PATH ") failed: %m");
}
(void) sockaddr_un_unlink(&sockaddr.un);
WITH_UMASK(0000)
- if (bind(m->listen_fd, &sockaddr.sa, SOCKADDR_UN_LEN(sockaddr.un)) < 0)
+ if (bind(m->listen_fd, &sockaddr.sa, sockaddr_un_len(&sockaddr.un)) < 0)
return log_error_errno(errno, "Failed to bind socket: %m");
r = mkdir_p("/run/systemd/userdb", 0755);
return r;
}
- r = RET_NERRNO(connect(fd, &sa.sa, SOCKADDR_LEN(sa)));
+ r = RET_NERRNO(connect(fd, &sa.sa, sockaddr_len(&sa)));
if (!IN_SET(r,
0,
-ENETUNREACH,
if (tfo_address) {
s->tfo_address = *tfo_address;
- s->tfo_salen = SOCKADDR_LEN(*tfo_address);
+ s->tfo_salen = sockaddr_len(tfo_address);
}
*ret = TAKE_PTR(s);
log_debug_errno(r, "Failed to enable fragment size reception, ignoring: %m");
}
- r = RET_NERRNO(bind(fd, &sa.sa, SOCKADDR_LEN(sa)));
+ r = RET_NERRNO(bind(fd, &sa.sa, sockaddr_len(&sa)));
if (r < 0)
goto fail;
assert_se((bindfd = socket(AF_INET, SOCK_STREAM | SOCK_CLOEXEC, 0)) >= 0);
assert_se(setsockopt(bindfd, SOL_SOCKET, SO_REUSEADDR, &(int){1}, sizeof(int)) >= 0);
- assert_se(bind(bindfd, &server_address.sa, SOCKADDR_LEN(server_address)) >= 0);
+ assert_se(bind(bindfd, &server_address.sa, sockaddr_len(&server_address)) >= 0);
assert_se(listen(bindfd, 1) >= 0);
assert_se((acceptfd = accept(bindfd, NULL, NULL)) >= 0);
server_handle(acceptfd);
assert_se((clientfd = socket(AF_INET, SOCK_STREAM | SOCK_CLOEXEC, 0)) >= 0);
for (int i = 0; i < 100; i++) {
- r = connect(clientfd, &server_address.sa, SOCKADDR_LEN(server_address));
+ r = connect(clientfd, &server_address.sa, sockaddr_len(&server_address));
if (r >= 0)
break;
usleep_safe(EVENT_TIMEOUT_USEC / 100);
* make use of the binding and return it. Hence, let's not unnecessarily fail early here: we
* can still easily detect if the auto-binding worked or not, by comparing the bound IP
* address with zero — which we do below. */
- if (connect(fd, &sa.sa, SOCKADDR_LEN(sa)) < 0)
+ if (connect(fd, &sa.sa, sockaddr_len(&sa)) < 0)
log_debug_errno(errno, "Failed to connect SOCK_DGRAM socket to gateway, ignoring: %m");
/* Let's now read the socket address of the socket. A routing decision should have been
* made. Let's verify that and use the data. */
- salen = SOCKADDR_LEN(sa);
+ salen = sockaddr_len(&sa);
if (getsockname(fd, &sa.sa, &salen) < 0)
return -errno;
assert(sa.sa.sa_family == i->family);
- assert(salen == SOCKADDR_LEN(sa));
+ assert(salen == sockaddr_len(&sa));
switch (i->family) {
if (fd < 0)
return -errno;
- if (connect(fd, &sa.sa, SOCKADDR_UN_LEN(sa.un)) < 0)
+ if (connect(fd, &sa.sa, sockaddr_un_len(&sa.un)) < 0)
return -errno;
return TAKE_FD(fd);
if (fd < 0)
return log_error_errno(errno, "Failed to allocate AF_VSOCK socket: %m");
- if (connect(fd, &sa.sa, SOCKADDR_LEN(sa)) < 0)
+ if (connect(fd, &sa.sa, sockaddr_len(&sa)) < 0)
return log_error_errno(errno, "Failed to connect to vsock:%u:%u: %m", sa.vm.svm_cid, sa.vm.svm_port);
/* OpenSSH wants us to send a single byte along with the file descriptor, hence do so */
assert_se(sockaddr_un_set_path(&sa.un, j) >= 0);
- assert_se(bind(listener, &sa.sa, SOCKADDR_UN_LEN(sa.un)) >= 0);
+ assert_se(bind(listener, &sa.sa, sockaddr_un_len(&sa.un)) >= 0);
assert_se(listen(listener, 1) >= 0);
/* Make sure the socket doesn't fit into a struct sockaddr_un, but we can still access it */
socket_fd = socket(AF_UNIX, SOCK_STREAM|SOCK_CLOEXEC, 0);
assert_se(socket_fd >= 0);
assert_se(sockaddr_un_set_path(&sa.un, k) >= 0);
- assert_se(bind(socket_fd, &sa.sa, SOCKADDR_UN_LEN(sa.un)) >= 0);
+ assert_se(bind(socket_fd, &sa.sa, sockaddr_un_len(&sa.un)) >= 0);
assert_se(listen(socket_fd, 1) >= 0);
/* Ideally we'd just allocate this on the stack, but AddressSanitizer doesn't like it if threads
.sun_path = "\0foobar",
};
- assert_se(SOCKADDR_UN_LEN(fs) == offsetof(struct sockaddr_un, sun_path) + strlen(fs.sun_path) + 1);
- assert_se(SOCKADDR_UN_LEN(abstract) == offsetof(struct sockaddr_un, sun_path) + 1 + strlen(abstract.sun_path + 1));
+ assert_se(sockaddr_un_len(&fs) == offsetof(struct sockaddr_un, sun_path) + strlen(fs.sun_path) + 1);
+ assert_se(sockaddr_un_len(&abstract) == offsetof(struct sockaddr_un, sun_path) + 1 + strlen(abstract.sun_path + 1));
}
TEST(in_addr_is_multicast) {
fd1 = socket(AF_UNIX, SOCK_STREAM|SOCK_CLOEXEC, 0);
assert_se(fd1 >= 0);
- assert_se(bind(fd1, &sa.sa, SOCKADDR_LEN(sa)) >= 0);
+ assert_se(bind(fd1, &sa.sa, sockaddr_len(&sa)) >= 0);
assert_se(listen(fd1, 1) >= 0);
sh = unlink_and_free(sh); /* remove temporary symlink */
fd2 = socket(AF_UNIX, SOCK_STREAM|SOCK_CLOEXEC, 0);
assert_se(fd2 >= 0);
- assert_se(connect(fd2, &sa.sa, SOCKADDR_LEN(sa)) < 0);
+ assert_se(connect(fd2, &sa.sa, sockaddr_len(&sa)) < 0);
assert_se(errno == ENOENT); /* we removed the symlink, must fail */
free(j);
assert_se(fd3 > 0);
assert_se(sockaddr_un_set_path(&sa.un, FORMAT_PROC_FD_PATH(fd3)) >= 0); /* connect via O_PATH instead, circumventing 108ch limit */
- assert_se(connect(fd2, &sa.sa, SOCKADDR_LEN(sa)) >= 0);
+ assert_se(connect(fd2, &sa.sa, sockaddr_len(&sa)) >= 0);
}
TEST(getpeerpidref) {
.sun_path = "/run/udev/control",
};
- uctrl->addrlen = SOCKADDR_UN_LEN(uctrl->saddr.un);
+ uctrl->addrlen = sockaddr_un_len(&uctrl->saddr.un);
*ret = TAKE_PTR(uctrl);
return 0;
(void) sockaddr_un_unlink(&sockaddr.un);
WITH_UMASK(0000)
- if (bind(m->listen_fd, &sockaddr.sa, SOCKADDR_UN_LEN(sockaddr.un)) < 0)
+ if (bind(m->listen_fd, &sockaddr.sa, sockaddr_un_len(&sockaddr.un)) < 0)
return log_error_errno(errno, "Failed to bind socket: %m");
FOREACH_STRING(alias,