passt/util.h
Stefano Brivio bb70811183 treewide: Packet abstraction with mandatory boundary checks
Implement a packet abstraction providing boundary and size checks
based on packet descriptors: packets stored in a buffer can be queued
into a pool (without storage of its own), and data can be retrieved
referring to an index in the pool, specifying offset and length.

Checks ensure data is not read outside the boundaries of buffer and
descriptors, and that packets added to a pool are within the buffer
range with valid offset and indices.

This implies a wider rework: usage of the "queueing" part of the
abstraction mostly affects tap_handler_{passt,pasta}() functions and
their callees, while the "fetching" part affects all the guest or tap
facing implementations: TCP, UDP, ICMP, ARP, NDP, DHCP and DHCPv6
handlers.

Suggested-by: Stefan Hajnoczi <stefanha@redhat.com>
Signed-off-by: Stefano Brivio <sbrivio@redhat.com>
2022-03-29 15:35:38 +02:00

215 lines
5.1 KiB
C

/* SPDX-License-Identifier: AGPL-3.0-or-later
* Copyright (c) 2021 Red Hat GmbH
* Author: Stefano Brivio <sbrivio@redhat.com>
*/
void err(const char *format, ...);
void warn(const char *format, ...);
void info(const char *format, ...);
void debug(const char *format, ...);
extern int log_trace;
void trace_init(int enable);
#define trace(format, ...) \
do { \
if (log_trace) \
debug(format, ##__VA_ARGS__); \
} while (0)
#ifndef SECCOMP_RET_KILL_PROCESS
#define SECCOMP_RET_KILL_PROCESS SECCOMP_RET_KILL
#endif
#ifndef ETH_MAX_MTU
#define ETH_MAX_MTU USHRT_MAX
#endif
#ifndef ETH_MIN_MTU
#define ETH_MIN_MTU 68
#endif
#ifndef MIN
#define MIN(x, y) (((x) < (y)) ? (x) : (y))
#endif
#ifndef MAX
#define MAX(x, y) (((x) > (y)) ? (x) : (y))
#endif
#define DIV_ROUND_UP(n, d) (((n) + (d) - 1) / (d))
#define ROUND_DOWN(x, y) ((x) & ~((y) - 1))
#define ROUND_UP(x, y) (((x) + (y) - 1) & ~((y) - 1))
#define BIT(n) (1UL << (n))
#define BITMAP_BIT(n) (BIT((n) % (sizeof(long) * 8)))
#define BITMAP_WORD(n) (n / (sizeof(long) * 8))
#define SWAP(a, b) \
do { \
__typeof__(a) __x = (a); (a) = (b); (b) = __x; \
} while (0) \
#define STRINGIFY(x) #x
#define STR(x) STRINGIFY(x)
#ifdef P_tmpdir
#define TMPDIR P_tmpdir
#else
#define TMPDIR "/tmp"
#endif
#define V4 0
#define V6 1
#define IP_VERSIONS 2
enum {
IP_VERSION_DISABLED = 0,
IP_VERSION_ENABLED,
IP_VERSION_PROBE,
};
#define ARRAY_SIZE(a) ((int)(sizeof(a) / sizeof((a)[0])))
#define IN_INTERVAL(a, b, x) ((x) >= (a) && (x) <= (b))
#define FD_PROTO(x, proto) \
(IN_INTERVAL(c->proto.fd_min, c->proto.fd_max, (x)))
#define PORT_EPHEMERAL_MIN ((1 << 15) + (1 << 14)) /* RFC 6335 */
#define PORT_IS_EPHEMERAL(port) ((port) >= PORT_EPHEMERAL_MIN)
#define MAC_ZERO ((uint8_t [ETH_ALEN]){ 0 })
#define MAC_IS_ZERO(addr) (!memcmp((addr), MAC_ZERO, ETH_ALEN))
#define NS_FN_STACK_SIZE (RLIMIT_STACK_VAL * 1024 / 4)
#define NS_CALL(fn, arg) \
do { \
char ns_fn_stack[NS_FN_STACK_SIZE]; \
\
clone((fn), ns_fn_stack + sizeof(ns_fn_stack) / 2, \
CLONE_VM | CLONE_VFORK | CLONE_FILES | SIGCHLD, \
(void *)(arg)); \
} while (0)
#if __BYTE_ORDER == __BIG_ENDIAN
#define L2_BUF_ETH_IP4_INIT \
{ \
.h_dest = { 0 }, \
.h_source = { 0 }, \
.h_proto = ETH_P_IP, \
}
#else
#define L2_BUF_ETH_IP4_INIT \
{ \
.h_dest = { 0 }, \
.h_source = { 0 }, \
.h_proto = __bswap_constant_16(ETH_P_IP), \
}
#endif
#if __BYTE_ORDER == __BIG_ENDIAN
#define L2_BUF_ETH_IP6_INIT \
{ \
.h_dest = { 0 }, \
.h_source = { 0 }, \
.h_proto = ETH_P_IPV6, \
}
#else
#define L2_BUF_ETH_IP6_INIT \
{ \
.h_dest = { 0 }, \
.h_source = { 0 }, \
.h_proto = __bswap_constant_16(ETH_P_IPV6), \
}
#endif
#define L2_BUF_IP4_INIT(proto) \
{ \
.version = 4, \
.ihl = 5, \
.tos = 0, \
.tot_len = 0, \
.id = 0, \
.frag_off = 0, \
.ttl = 255, \
.protocol = (proto), \
.saddr = 0, \
.daddr = 0, \
}
#define L2_BUF_IP6_INIT(proto) \
{ \
.priority = 0, \
.version = 6, \
.flow_lbl = { 0 }, \
.payload_len = 0, \
.nexthdr = (proto), \
.hop_limit = 255, \
.saddr = IN6ADDR_ANY_INIT, \
.daddr = IN6ADDR_ANY_INIT, \
}
#define RCVBUF_BIG (2UL * 1024 * 1024)
#define SNDBUF_BIG (4UL * 1024 * 1024)
#define SNDBUF_SMALL (128UL * 1024)
#include <net/if.h>
#include <limits.h>
#include <stdarg.h>
#include "packet.h"
enum bind_type {
BIND_ANY = 0,
BIND_LOOPBACK,
BIND_LL,
BIND_EXT,
};
struct ctx;
struct ipv6hdr {
#pragma GCC diagnostic ignored "-Wpedantic"
#if __BYTE_ORDER == __BIG_ENDIAN
uint8_t version:4,
priority:4;
#else
uint8_t priority:4,
version:4;
#endif
#pragma GCC diagnostic pop
uint8_t flow_lbl[3];
uint16_t payload_len;
uint8_t nexthdr;
uint8_t hop_limit;
struct in6_addr saddr;
struct in6_addr daddr;
};
struct ipv6_opt_hdr {
uint8_t nexthdr;
uint8_t hdrlen;
/*
* TLV encoded option data follows.
*/
} __attribute__((packed)); /* required for some archs */
__attribute__ ((weak)) int ffsl(long int i) { return __builtin_ffsl(i); }
void __openlog(const char *ident, int option, int facility);
void passt_vsyslog(int pri, const char *format, va_list ap);
void __setlogmask(int mask);
char *ipv6_l4hdr(struct pool *p, int index, size_t offset, uint8_t *proto,
size_t *dlen);
int sock_l4(struct ctx *c, int af, uint8_t proto, uint16_t port,
enum bind_type bind_addr, uint32_t data);
void sock_probe_mem(struct ctx *c);
int timespec_diff_ms(struct timespec *a, struct timespec *b);
void bitmap_set(uint8_t *map, int bit);
void bitmap_clear(uint8_t *map, int bit);
int bitmap_isset(const uint8_t *map, int bit);
char *line_read(char *buf, size_t len, int fd);
void procfs_scan_listen(struct ctx *c, uint8_t proto, int ip_version, int ns,
uint8_t *map, uint8_t *exclude);
void drop_caps(void);
int ns_enter(struct ctx *c);
void write_pidfile(int fd, pid_t pid);
int __daemon(int pidfile_fd, int devnull_fd);
int fls(unsigned long x);