1
1
mirror of https://github.com/systemd/systemd-stable.git synced 2025-01-08 21:17:47 +03:00

Merge pull request #21050 from yuwata/network-bpf-cleanups

libsystemd-network: cleanup BPF code
This commit is contained in:
Yu Watanabe 2021-10-22 01:46:15 +09:00 committed by GitHub
commit a3e33adfb5
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 64 additions and 75 deletions

View File

@ -14,7 +14,7 @@
#include "unaligned.h"
#include "util.h"
int arp_update_filter(int fd, const struct in_addr *a, const struct ether_addr *eth_mac) {
int arp_update_filter(int fd, const struct in_addr *a, const struct ether_addr *mac) {
struct sock_filter filter[] = {
BPF_STMT(BPF_LD + BPF_W + BPF_LEN, 0), /* A <- packet length */
BPF_JUMP(BPF_JMP + BPF_JGE + BPF_K, sizeof(struct ether_arp), 1, 0), /* packet >= arp packet ? */
@ -36,30 +36,22 @@ int arp_update_filter(int fd, const struct in_addr *a, const struct ether_addr *
BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, ARPOP_REPLY, 1, 0), /* protocol == reply ? */
BPF_STMT(BPF_RET + BPF_K, 0), /* ignore */
/* Sender Hardware Address must be different from our own */
BPF_STMT(BPF_LD + BPF_IMM, unaligned_read_be32(&eth_mac->ether_addr_octet[0])),/* A <- 4 bytes of client's MAC */
BPF_STMT(BPF_MISC + BPF_TAX, 0), /* X <- A */
BPF_STMT(BPF_LDX + BPF_IMM, unaligned_read_be32(&mac->ether_addr_octet[0])), /* X <- 4 bytes of client's MAC */
BPF_STMT(BPF_LD + BPF_W + BPF_ABS, offsetof(struct ether_arp, arp_sha)), /* A <- 4 bytes of SHA */
BPF_STMT(BPF_ALU + BPF_XOR + BPF_X, 0), /* A xor X */
BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, 0, 0, 6), /* A == 0 ? */
BPF_STMT(BPF_LD + BPF_IMM, unaligned_read_be16(&eth_mac->ether_addr_octet[4])),/* A <- remainder of client's MAC */
BPF_STMT(BPF_MISC + BPF_TAX, 0), /* X <- A */
BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_X, 0, 0, 4), /* A == X ? */
BPF_STMT(BPF_LDX + BPF_IMM, unaligned_read_be16(&mac->ether_addr_octet[4])), /* X <- remainder of client's MAC */
BPF_STMT(BPF_LD + BPF_H + BPF_ABS, offsetof(struct ether_arp, arp_sha) + 4), /* A <- remainder of SHA */
BPF_STMT(BPF_ALU + BPF_XOR + BPF_X, 0), /* A xor X */
BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, 0, 0, 1), /* A == 0 ? */
BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_X, 0, 0, 1), /* A == X ? */
BPF_STMT(BPF_RET + BPF_K, 0), /* ignore */
/* Sender Protocol Address or Target Protocol Address must be equal to the one we care about */
BPF_STMT(BPF_LD + BPF_IMM, htobe32(a->s_addr)), /* A <- clients IP */
BPF_STMT(BPF_MISC + BPF_TAX, 0), /* X <- A */
BPF_STMT(BPF_LDX + BPF_IMM, htobe32(a->s_addr)), /* X <- clients IP */
BPF_STMT(BPF_LD + BPF_W + BPF_ABS, offsetof(struct ether_arp, arp_spa)), /* A <- SPA */
BPF_STMT(BPF_ALU + BPF_XOR + BPF_X, 0), /* X xor A */
BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, 0, 0, 1), /* A == 0 ? */
BPF_STMT(BPF_RET + BPF_K, 65535), /* return all */
BPF_STMT(BPF_LD + BPF_IMM, htobe32(a->s_addr)), /* A <- clients IP */
BPF_STMT(BPF_MISC + BPF_TAX, 0), /* X <- A */
BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_X, 0, 0, 1), /* A == X ? */
BPF_STMT(BPF_RET + BPF_K, UINT32_MAX), /* accept */
BPF_STMT(BPF_LDX + BPF_IMM, htobe32(a->s_addr)), /* A <- clients IP */
BPF_STMT(BPF_LD + BPF_W + BPF_ABS, offsetof(struct ether_arp, arp_tpa)), /* A <- TPA */
BPF_STMT(BPF_ALU + BPF_XOR + BPF_X, 0), /* X xor A */
BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, 0, 0, 1), /* A == 0 ? */
BPF_STMT(BPF_RET + BPF_K, 65535), /* return all */
BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_X, 0, 0, 1), /* A == 0 ? */
BPF_STMT(BPF_RET + BPF_K, UINT32_MAX), /* accept */
BPF_STMT(BPF_RET + BPF_K, 0), /* ignore */
};
struct sock_fprog fprog = {
@ -75,7 +67,7 @@ int arp_update_filter(int fd, const struct in_addr *a, const struct ether_addr *
return 0;
}
int arp_network_bind_raw_socket(int ifindex, const struct in_addr *a, const struct ether_addr *eth_mac) {
int arp_network_bind_raw_socket(int ifindex, const struct in_addr *a, const struct ether_addr *mac) {
union sockaddr_union link = {
.ll.sll_family = AF_PACKET,
.ll.sll_protocol = htobe16(ETH_P_ARP),
@ -87,12 +79,13 @@ int arp_network_bind_raw_socket(int ifindex, const struct in_addr *a, const stru
int r;
assert(ifindex > 0);
assert(mac);
s = socket(AF_PACKET, SOCK_DGRAM | SOCK_CLOEXEC | SOCK_NONBLOCK, 0);
if (s < 0)
return -errno;
r = arp_update_filter(s, a, eth_mac);
r = arp_update_filter(s, a, mac);
if (r < 0)
return r;

View File

@ -11,8 +11,8 @@
#include "socket-util.h"
#include "sparse-endian.h"
int arp_update_filter(int fd, const struct in_addr *a, const struct ether_addr *eth_mac);
int arp_network_bind_raw_socket(int ifindex, const struct in_addr *a, const struct ether_addr *eth_mac);
int arp_update_filter(int fd, const struct in_addr *a, const struct ether_addr *mac);
int arp_network_bind_raw_socket(int ifindex, const struct in_addr *a, const struct ether_addr *mac);
int arp_send_packet(
int fd,

View File

@ -58,24 +58,20 @@ static int _bind_raw_socket(int ifindex, union sockaddr_union *link,
/* We only support MAC address length to be either 0 or 6 (ETH_ALEN). Optionally
* compare chaddr for ETH_ALEN bytes. */
BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, ETH_ALEN, 0, 12), /* A (the MAC address length) == ETH_ALEN ? */
BPF_STMT(BPF_LD + BPF_IMM, unaligned_read_be32(&eth_mac->ether_addr_octet[0])), /* A <- 4 bytes of client's MAC */
BPF_STMT(BPF_MISC + BPF_TAX, 0), /* X <- A */
BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, ETH_ALEN, 0, 8), /* A (the MAC address length) == ETH_ALEN ? */
BPF_STMT(BPF_LDX + BPF_IMM, unaligned_read_be32(&eth_mac->ether_addr_octet[0])), /* X <- 4 bytes of client's MAC */
BPF_STMT(BPF_LD + BPF_W + BPF_ABS, offsetof(DHCPPacket, dhcp.chaddr)), /* A <- 4 bytes of MAC from dhcp.chaddr */
BPF_STMT(BPF_ALU + BPF_XOR + BPF_X, 0), /* A xor X */
BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, 0, 1, 0), /* A == 0 ? */
BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_X, 0, 1, 0), /* A == X ? */
BPF_STMT(BPF_RET + BPF_K, 0), /* ignore */
BPF_STMT(BPF_LD + BPF_IMM, unaligned_read_be16(&eth_mac->ether_addr_octet[4])), /* A <- remainder of client's MAC */
BPF_STMT(BPF_MISC + BPF_TAX, 0), /* X <- A */
BPF_STMT(BPF_LDX + BPF_IMM, unaligned_read_be16(&eth_mac->ether_addr_octet[4])), /* X <- remainder of client's MAC */
BPF_STMT(BPF_LD + BPF_H + BPF_ABS, offsetof(DHCPPacket, dhcp.chaddr) + 4), /* A <- remainder of MAC from dhcp.chaddr */
BPF_STMT(BPF_ALU + BPF_XOR + BPF_X, 0), /* A xor X */
BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, 0, 1, 0), /* A == 0 ? */
BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_X, 0, 1, 0), /* A == X ? */
BPF_STMT(BPF_RET + BPF_K, 0), /* ignore */
BPF_STMT(BPF_LD + BPF_W + BPF_ABS, offsetof(DHCPPacket, dhcp.magic)), /* A <- DHCP magic cookie */
BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, DHCP_MAGIC_COOKIE, 1, 0), /* cookie == DHCP magic cookie ? */
BPF_STMT(BPF_RET + BPF_K, 0), /* ignore */
BPF_STMT(BPF_RET + BPF_K, 65535), /* return all */
BPF_STMT(BPF_RET + BPF_K, UINT32_MAX), /* accept */
};
struct sock_fprog fprog = {
.len = ELEMENTSOF(filter),
@ -115,10 +111,17 @@ static int _bind_raw_socket(int ifindex, union sockaddr_union *link,
return TAKE_FD(s);
}
int dhcp_network_bind_raw_socket(int ifindex, union sockaddr_union *link, uint32_t xid,
const uint8_t *mac_addr, size_t mac_addr_len,
const uint8_t *bcast_addr, size_t bcast_addr_len,
uint16_t arp_type, uint16_t port) {
int dhcp_network_bind_raw_socket(
int ifindex,
union sockaddr_union *link,
uint32_t xid,
const uint8_t *mac_addr,
size_t mac_addr_len,
const uint8_t *bcast_addr,
size_t bcast_addr_len,
uint16_t arp_type,
uint16_t port) {
static const uint8_t eth_bcast[] = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF };
/* Default broadcast address for IPoIB */
static const uint8_t ib_bcast[] = {
@ -172,7 +175,6 @@ int dhcp_network_bind_udp_socket(int ifindex, be32_t address, uint16_t port, int
r = setsockopt_int(s, IPPROTO_IP, IP_TOS, ip_service_type);
else
r = setsockopt_int(s, IPPROTO_IP, IP_TOS, IPTOS_CLASS_CS6);
if (r < 0)
return r;
@ -204,43 +206,49 @@ int dhcp_network_bind_udp_socket(int ifindex, be32_t address, uint16_t port, int
return r;
}
r = bind(s, &src.sa, sizeof(src.in));
if (r < 0)
if (bind(s, &src.sa, sizeof(src.in)) < 0)
return -errno;
return TAKE_FD(s);
}
int dhcp_network_send_raw_socket(int s, const union sockaddr_union *link,
const void *packet, size_t len) {
int r;
int dhcp_network_send_raw_socket(
int s,
const union sockaddr_union *link,
const void *packet,
size_t len) {
/* Do not add assert(s >= 0) here, as this is called in fuzz-dhcp-server, and in that case this
* function should fail with negative errno. */
assert(link);
assert(packet);
assert(len);
assert(len > 0);
r = sendto(s, packet, len, 0, &link->sa, SOCKADDR_LL_LEN(link->ll));
if (r < 0)
if (sendto(s, packet, len, 0, &link->sa, SOCKADDR_LL_LEN(link->ll)) < 0)
return -errno;
return 0;
}
int dhcp_network_send_udp_socket(int s, be32_t address, uint16_t port,
const void *packet, size_t len) {
int dhcp_network_send_udp_socket(
int s,
be32_t address,
uint16_t port,
const void *packet,
size_t len) {
union sockaddr_union dest = {
.in.sin_family = AF_INET,
.in.sin_port = htobe16(port),
.in.sin_addr.s_addr = address,
};
int r;
assert(s >= 0);
assert(packet);
assert(len);
assert(len > 0);
r = sendto(s, packet, len, 0, &dest.sa, sizeof(dest.in));
if (r < 0)
if (sendto(s, packet, len, 0, &dest.sa, sizeof(dest.in)) < 0)
return -errno;
return 0;

View File

@ -34,16 +34,17 @@ static int icmp6_bind_router_message(const struct icmp6_filter *filter,
_cleanup_close_ int s = -1;
int r;
assert(filter);
assert(mreq);
s = socket(AF_INET6, SOCK_RAW | SOCK_CLOEXEC | SOCK_NONBLOCK, IPPROTO_ICMPV6);
if (s < 0)
return -errno;
r = setsockopt(s, IPPROTO_ICMPV6, ICMP6_FILTER, filter, sizeof(*filter));
if (r < 0)
if (setsockopt(s, IPPROTO_ICMPV6, ICMP6_FILTER, filter, sizeof(*filter)) < 0)
return -errno;
r = setsockopt(s, IPPROTO_IPV6, IPV6_ADD_MEMBERSHIP, mreq, sizeof(*mreq));
if (r < 0)
if (setsockopt(s, IPPROTO_IPV6, IPV6_ADD_MEMBERSHIP, mreq, sizeof(*mreq)) < 0)
return -errno;
/* RFC 3315, section 6.7, bullet point 2 may indicate that an
@ -131,15 +132,13 @@ int icmp6_send_router_solicitation(int s, const struct ether_addr *ether_addr) {
.msg_iov = &iov,
.msg_iovlen = 1,
};
int r;
assert(s >= 0);
assert(ether_addr);
rs.rs_opt_mac = *ether_addr;
r = sendmsg(s, &msg, 0);
if (r < 0)
if (sendmsg(s, &msg, 0) < 0)
return -errno;
return 0;

View File

@ -9,7 +9,6 @@
#include "socket-util.h"
int lldp_network_bind_raw_socket(int ifindex) {
static const struct sock_filter filter[] = {
BPF_STMT(BPF_LD + BPF_W + BPF_ABS, offsetof(struct ethhdr, h_dest)), /* A <- 4 bytes of destination MAC */
BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, 0x0180c200, 1, 0), /* A != 01:80:c2:00 */
@ -24,26 +23,21 @@ int lldp_network_bind_raw_socket(int ifindex) {
BPF_STMT(BPF_RET + BPF_K, 0), /* drop packet */
BPF_STMT(BPF_RET + BPF_K, UINT32_MAX), /* accept packet */
};
static const struct sock_fprog fprog = {
.len = ELEMENTSOF(filter),
.filter = (struct sock_filter*) filter,
};
struct packet_mreq mreq = {
.mr_ifindex = ifindex,
.mr_type = PACKET_MR_MULTICAST,
.mr_alen = ETH_ALEN,
.mr_address = { 0x01, 0x80, 0xC2, 0x00, 0x00, 0x00 }
};
union sockaddr_union saddrll = {
.ll.sll_family = AF_PACKET,
.ll.sll_ifindex = ifindex,
};
_cleanup_close_ int fd = -1;
int r;
assert(ifindex > 0);
@ -52,29 +46,24 @@ int lldp_network_bind_raw_socket(int ifindex) {
if (fd < 0)
return -errno;
r = setsockopt(fd, SOL_SOCKET, SO_ATTACH_FILTER, &fprog, sizeof(fprog));
if (r < 0)
if (setsockopt(fd, SOL_SOCKET, SO_ATTACH_FILTER, &fprog, sizeof(fprog)) < 0)
return -errno;
/* customer bridge */
r = setsockopt(fd, SOL_PACKET, PACKET_ADD_MEMBERSHIP, &mreq, sizeof(mreq));
if (r < 0)
if (setsockopt(fd, SOL_PACKET, PACKET_ADD_MEMBERSHIP, &mreq, sizeof(mreq)) < 0)
return -errno;
/* non TPMR bridge */
mreq.mr_address[ETH_ALEN - 1] = 0x03;
r = setsockopt(fd, SOL_PACKET, PACKET_ADD_MEMBERSHIP, &mreq, sizeof(mreq));
if (r < 0)
if (setsockopt(fd, SOL_PACKET, PACKET_ADD_MEMBERSHIP, &mreq, sizeof(mreq)) < 0)
return -errno;
/* nearest bridge */
mreq.mr_address[ETH_ALEN - 1] = 0x0E;
r = setsockopt(fd, SOL_PACKET, PACKET_ADD_MEMBERSHIP, &mreq, sizeof(mreq));
if (r < 0)
if (setsockopt(fd, SOL_PACKET, PACKET_ADD_MEMBERSHIP, &mreq, sizeof(mreq)) < 0)
return -errno;
r = bind(fd, &saddrll.sa, sizeof(saddrll.ll));
if (r < 0)
if (bind(fd, &saddrll.sa, sizeof(saddrll.ll)) < 0)
return -errno;
return TAKE_FD(fd);