mirror of
https://github.com/daeuniverse/dae.git
synced 2025-07-14 09:48:47 +07:00
feat: add config_parser
This commit is contained in:
99
component/control/kern/bpf_endian.h
Normal file
99
component/control/kern/bpf_endian.h
Normal file
@ -0,0 +1,99 @@
|
||||
/* SPDX-License-Identifier: (LGPL-2.1 OR BSD-2-Clause) */
|
||||
#ifndef __BPF_ENDIAN__
|
||||
#define __BPF_ENDIAN__
|
||||
|
||||
/*
|
||||
* Isolate byte #n and put it into byte #m, for __u##b type.
|
||||
* E.g., moving byte #6 (nnnnnnnn) into byte #1 (mmmmmmmm) for __u64:
|
||||
* 1) xxxxxxxx nnnnnnnn xxxxxxxx xxxxxxxx xxxxxxxx xxxxxxxx mmmmmmmm xxxxxxxx
|
||||
* 2) nnnnnnnn xxxxxxxx xxxxxxxx xxxxxxxx xxxxxxxx mmmmmmmm xxxxxxxx 00000000
|
||||
* 3) 00000000 00000000 00000000 00000000 00000000 00000000 00000000 nnnnnnnn
|
||||
* 4) 00000000 00000000 00000000 00000000 00000000 00000000 nnnnnnnn 00000000
|
||||
*/
|
||||
#define ___bpf_mvb(x, b, n, m) ((__u##b)(x) << (b-(n+1)*8) >> (b-8) << (m*8))
|
||||
|
||||
#define ___bpf_swab16(x) ((__u16)( \
|
||||
___bpf_mvb(x, 16, 0, 1) | \
|
||||
___bpf_mvb(x, 16, 1, 0)))
|
||||
|
||||
#define ___bpf_swab32(x) ((__u32)( \
|
||||
___bpf_mvb(x, 32, 0, 3) | \
|
||||
___bpf_mvb(x, 32, 1, 2) | \
|
||||
___bpf_mvb(x, 32, 2, 1) | \
|
||||
___bpf_mvb(x, 32, 3, 0)))
|
||||
|
||||
#define ___bpf_swab64(x) ((__u64)( \
|
||||
___bpf_mvb(x, 64, 0, 7) | \
|
||||
___bpf_mvb(x, 64, 1, 6) | \
|
||||
___bpf_mvb(x, 64, 2, 5) | \
|
||||
___bpf_mvb(x, 64, 3, 4) | \
|
||||
___bpf_mvb(x, 64, 4, 3) | \
|
||||
___bpf_mvb(x, 64, 5, 2) | \
|
||||
___bpf_mvb(x, 64, 6, 1) | \
|
||||
___bpf_mvb(x, 64, 7, 0)))
|
||||
|
||||
/* LLVM's BPF target selects the endianness of the CPU
|
||||
* it compiles on, or the user specifies (bpfel/bpfeb),
|
||||
* respectively. The used __BYTE_ORDER__ is defined by
|
||||
* the compiler, we cannot rely on __BYTE_ORDER from
|
||||
* libc headers, since it doesn't reflect the actual
|
||||
* requested byte order.
|
||||
*
|
||||
* Note, LLVM's BPF target has different __builtin_bswapX()
|
||||
* semantics. It does map to BPF_ALU | BPF_END | BPF_TO_BE
|
||||
* in bpfel and bpfeb case, which means below, that we map
|
||||
* to cpu_to_be16(). We could use it unconditionally in BPF
|
||||
* case, but better not rely on it, so that this header here
|
||||
* can be used from application and BPF program side, which
|
||||
* use different targets.
|
||||
*/
|
||||
#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
|
||||
# define __bpf_ntohs(x) __builtin_bswap16(x)
|
||||
# define __bpf_htons(x) __builtin_bswap16(x)
|
||||
# define __bpf_constant_ntohs(x) ___bpf_swab16(x)
|
||||
# define __bpf_constant_htons(x) ___bpf_swab16(x)
|
||||
# define __bpf_ntohl(x) __builtin_bswap32(x)
|
||||
# define __bpf_htonl(x) __builtin_bswap32(x)
|
||||
# define __bpf_constant_ntohl(x) ___bpf_swab32(x)
|
||||
# define __bpf_constant_htonl(x) ___bpf_swab32(x)
|
||||
# define __bpf_be64_to_cpu(x) __builtin_bswap64(x)
|
||||
# define __bpf_cpu_to_be64(x) __builtin_bswap64(x)
|
||||
# define __bpf_constant_be64_to_cpu(x) ___bpf_swab64(x)
|
||||
# define __bpf_constant_cpu_to_be64(x) ___bpf_swab64(x)
|
||||
#elif __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__
|
||||
# define __bpf_ntohs(x) (x)
|
||||
# define __bpf_htons(x) (x)
|
||||
# define __bpf_constant_ntohs(x) (x)
|
||||
# define __bpf_constant_htons(x) (x)
|
||||
# define __bpf_ntohl(x) (x)
|
||||
# define __bpf_htonl(x) (x)
|
||||
# define __bpf_constant_ntohl(x) (x)
|
||||
# define __bpf_constant_htonl(x) (x)
|
||||
# define __bpf_be64_to_cpu(x) (x)
|
||||
# define __bpf_cpu_to_be64(x) (x)
|
||||
# define __bpf_constant_be64_to_cpu(x) (x)
|
||||
# define __bpf_constant_cpu_to_be64(x) (x)
|
||||
#else
|
||||
# error "Fix your compiler's __BYTE_ORDER__?!"
|
||||
#endif
|
||||
|
||||
#define bpf_htons(x) \
|
||||
(__builtin_constant_p(x) ? \
|
||||
__bpf_constant_htons(x) : __bpf_htons(x))
|
||||
#define bpf_ntohs(x) \
|
||||
(__builtin_constant_p(x) ? \
|
||||
__bpf_constant_ntohs(x) : __bpf_ntohs(x))
|
||||
#define bpf_htonl(x) \
|
||||
(__builtin_constant_p(x) ? \
|
||||
__bpf_constant_htonl(x) : __bpf_htonl(x))
|
||||
#define bpf_ntohl(x) \
|
||||
(__builtin_constant_p(x) ? \
|
||||
__bpf_constant_ntohl(x) : __bpf_ntohl(x))
|
||||
#define bpf_cpu_to_be64(x) \
|
||||
(__builtin_constant_p(x) ? \
|
||||
__bpf_constant_cpu_to_be64(x) : __bpf_cpu_to_be64(x))
|
||||
#define bpf_be64_to_cpu(x) \
|
||||
(__builtin_constant_p(x) ? \
|
||||
__bpf_constant_be64_to_cpu(x) : __bpf_be64_to_cpu(x))
|
||||
|
||||
#endif /* __BPF_ENDIAN__ */
|
4139
component/control/kern/bpf_helper_defs.h
Normal file
4139
component/control/kern/bpf_helper_defs.h
Normal file
File diff suppressed because it is too large
Load Diff
263
component/control/kern/bpf_helpers.h
Normal file
263
component/control/kern/bpf_helpers.h
Normal file
@ -0,0 +1,263 @@
|
||||
// Copied from https://github.com/cilium/ebpf/blob/e0ada270a5/examples/headers/bpf_helpers.h
|
||||
/* SPDX-License-Identifier: (LGPL-2.1 OR BSD-2-Clause) */
|
||||
#ifndef __BPF_HELPERS__
|
||||
#define __BPF_HELPERS__
|
||||
|
||||
/*
|
||||
* Note that bpf programs need to include either
|
||||
* vmlinux.h (auto-generated from BTF) or linux/types.h
|
||||
* in advance since bpf_helper_defs.h uses such types
|
||||
* as __u64.
|
||||
*/
|
||||
#include "bpf_helper_defs.h"
|
||||
|
||||
#define __uint(name, val) int (*name)[val]
|
||||
#define __type(name, val) typeof(val) *name
|
||||
#define __array(name, val) typeof(val) *name[]
|
||||
|
||||
/*
|
||||
* Helper macro to place programs, maps, license in
|
||||
* different sections in elf_bpf file. Section names
|
||||
* are interpreted by libbpf depending on the context (BPF programs, BPF maps,
|
||||
* extern variables, etc).
|
||||
* To allow use of SEC() with externs (e.g., for extern .maps declarations),
|
||||
* make sure __attribute__((unused)) doesn't trigger compilation warning.
|
||||
*/
|
||||
#define SEC(name) \
|
||||
_Pragma("GCC diagnostic push") \
|
||||
_Pragma("GCC diagnostic ignored \"-Wignored-attributes\"") \
|
||||
__attribute__((section(name), used)) \
|
||||
_Pragma("GCC diagnostic pop") \
|
||||
|
||||
/* Avoid 'linux/stddef.h' definition of '__always_inline'. */
|
||||
#undef __always_inline
|
||||
#define __always_inline inline __attribute__((always_inline))
|
||||
|
||||
#ifndef __noinline
|
||||
#define __noinline __attribute__((noinline))
|
||||
#endif
|
||||
#ifndef __weak
|
||||
#define __weak __attribute__((weak))
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Use __hidden attribute to mark a non-static BPF subprogram effectively
|
||||
* static for BPF verifier's verification algorithm purposes, allowing more
|
||||
* extensive and permissive BPF verification process, taking into account
|
||||
* subprogram's caller context.
|
||||
*/
|
||||
#define __hidden __attribute__((visibility("hidden")))
|
||||
|
||||
/* When utilizing vmlinux.h with BPF CO-RE, user BPF programs can't include
|
||||
* any system-level headers (such as stddef.h, linux/version.h, etc), and
|
||||
* commonly-used macros like NULL and KERNEL_VERSION aren't available through
|
||||
* vmlinux.h. This just adds unnecessary hurdles and forces users to re-define
|
||||
* them on their own. So as a convenience, provide such definitions here.
|
||||
*/
|
||||
#ifndef NULL
|
||||
#define NULL ((void *)0)
|
||||
#endif
|
||||
|
||||
#ifndef KERNEL_VERSION
|
||||
#define KERNEL_VERSION(a, b, c) (((a) << 16) + ((b) << 8) + ((c) > 255 ? 255 : (c)))
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Helper macros to manipulate data structures
|
||||
*/
|
||||
#ifndef offsetof
|
||||
#define offsetof(TYPE, MEMBER) ((unsigned long)&((TYPE *)0)->MEMBER)
|
||||
#endif
|
||||
#ifndef container_of
|
||||
#define container_of(ptr, type, member) \
|
||||
({ \
|
||||
void *__mptr = (void *)(ptr); \
|
||||
((type *)(__mptr - offsetof(type, member))); \
|
||||
})
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Helper macro to throw a compilation error if __bpf_unreachable() gets
|
||||
* built into the resulting code. This works given BPF back end does not
|
||||
* implement __builtin_trap(). This is useful to assert that certain paths
|
||||
* of the program code are never used and hence eliminated by the compiler.
|
||||
*
|
||||
* For example, consider a switch statement that covers known cases used by
|
||||
* the program. __bpf_unreachable() can then reside in the default case. If
|
||||
* the program gets extended such that a case is not covered in the switch
|
||||
* statement, then it will throw a build error due to the default case not
|
||||
* being compiled out.
|
||||
*/
|
||||
#ifndef __bpf_unreachable
|
||||
# define __bpf_unreachable() __builtin_trap()
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Helper function to perform a tail call with a constant/immediate map slot.
|
||||
*/
|
||||
#if __clang_major__ >= 8 && defined(__bpf__)
|
||||
static __always_inline void
|
||||
bpf_tail_call_static(void *ctx, const void *map, const __u32 slot)
|
||||
{
|
||||
if (!__builtin_constant_p(slot))
|
||||
__bpf_unreachable();
|
||||
|
||||
/*
|
||||
* Provide a hard guarantee that LLVM won't optimize setting r2 (map
|
||||
* pointer) and r3 (constant map index) from _different paths_ ending
|
||||
* up at the _same_ call insn as otherwise we won't be able to use the
|
||||
* jmpq/nopl retpoline-free patching by the x86-64 JIT in the kernel
|
||||
* given they mismatch. See also d2e4c1e6c294 ("bpf: Constant map key
|
||||
* tracking for prog array pokes") for details on verifier tracking.
|
||||
*
|
||||
* Note on clobber list: we need to stay in-line with BPF calling
|
||||
* convention, so even if we don't end up using r0, r4, r5, we need
|
||||
* to mark them as clobber so that LLVM doesn't end up using them
|
||||
* before / after the call.
|
||||
*/
|
||||
asm volatile("r1 = %[ctx]\n\t"
|
||||
"r2 = %[map]\n\t"
|
||||
"r3 = %[slot]\n\t"
|
||||
"call 12"
|
||||
:: [ctx]"r"(ctx), [map]"r"(map), [slot]"i"(slot)
|
||||
: "r0", "r1", "r2", "r3", "r4", "r5");
|
||||
}
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Helper structure used by eBPF C program
|
||||
* to describe BPF map attributes to libbpf loader
|
||||
*/
|
||||
struct bpf_map_def {
|
||||
unsigned int type;
|
||||
unsigned int key_size;
|
||||
unsigned int value_size;
|
||||
unsigned int max_entries;
|
||||
unsigned int map_flags;
|
||||
};
|
||||
|
||||
enum libbpf_pin_type {
|
||||
LIBBPF_PIN_NONE,
|
||||
/* PIN_BY_NAME: pin maps by name (in /sys/fs/bpf by default) */
|
||||
LIBBPF_PIN_BY_NAME,
|
||||
};
|
||||
|
||||
enum libbpf_tristate {
|
||||
TRI_NO = 0,
|
||||
TRI_YES = 1,
|
||||
TRI_MODULE = 2,
|
||||
};
|
||||
|
||||
#define __kconfig __attribute__((section(".kconfig")))
|
||||
#define __ksym __attribute__((section(".ksyms")))
|
||||
|
||||
#ifndef ___bpf_concat
|
||||
#define ___bpf_concat(a, b) a ## b
|
||||
#endif
|
||||
#ifndef ___bpf_apply
|
||||
#define ___bpf_apply(fn, n) ___bpf_concat(fn, n)
|
||||
#endif
|
||||
#ifndef ___bpf_nth
|
||||
#define ___bpf_nth(_, _1, _2, _3, _4, _5, _6, _7, _8, _9, _a, _b, _c, N, ...) N
|
||||
#endif
|
||||
#ifndef ___bpf_narg
|
||||
#define ___bpf_narg(...) \
|
||||
___bpf_nth(_, ##__VA_ARGS__, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0)
|
||||
#endif
|
||||
|
||||
#define ___bpf_fill0(arr, p, x) do {} while (0)
|
||||
#define ___bpf_fill1(arr, p, x) arr[p] = x
|
||||
#define ___bpf_fill2(arr, p, x, args...) arr[p] = x; ___bpf_fill1(arr, p + 1, args)
|
||||
#define ___bpf_fill3(arr, p, x, args...) arr[p] = x; ___bpf_fill2(arr, p + 1, args)
|
||||
#define ___bpf_fill4(arr, p, x, args...) arr[p] = x; ___bpf_fill3(arr, p + 1, args)
|
||||
#define ___bpf_fill5(arr, p, x, args...) arr[p] = x; ___bpf_fill4(arr, p + 1, args)
|
||||
#define ___bpf_fill6(arr, p, x, args...) arr[p] = x; ___bpf_fill5(arr, p + 1, args)
|
||||
#define ___bpf_fill7(arr, p, x, args...) arr[p] = x; ___bpf_fill6(arr, p + 1, args)
|
||||
#define ___bpf_fill8(arr, p, x, args...) arr[p] = x; ___bpf_fill7(arr, p + 1, args)
|
||||
#define ___bpf_fill9(arr, p, x, args...) arr[p] = x; ___bpf_fill8(arr, p + 1, args)
|
||||
#define ___bpf_fill10(arr, p, x, args...) arr[p] = x; ___bpf_fill9(arr, p + 1, args)
|
||||
#define ___bpf_fill11(arr, p, x, args...) arr[p] = x; ___bpf_fill10(arr, p + 1, args)
|
||||
#define ___bpf_fill12(arr, p, x, args...) arr[p] = x; ___bpf_fill11(arr, p + 1, args)
|
||||
#define ___bpf_fill(arr, args...) \
|
||||
___bpf_apply(___bpf_fill, ___bpf_narg(args))(arr, 0, args)
|
||||
|
||||
/*
|
||||
* BPF_SEQ_PRINTF to wrap bpf_seq_printf to-be-printed values
|
||||
* in a structure.
|
||||
*/
|
||||
#define BPF_SEQ_PRINTF(seq, fmt, args...) \
|
||||
({ \
|
||||
static const char ___fmt[] = fmt; \
|
||||
unsigned long long ___param[___bpf_narg(args)]; \
|
||||
\
|
||||
_Pragma("GCC diagnostic push") \
|
||||
_Pragma("GCC diagnostic ignored \"-Wint-conversion\"") \
|
||||
___bpf_fill(___param, args); \
|
||||
_Pragma("GCC diagnostic pop") \
|
||||
\
|
||||
bpf_seq_printf(seq, ___fmt, sizeof(___fmt), \
|
||||
___param, sizeof(___param)); \
|
||||
})
|
||||
|
||||
/*
|
||||
* BPF_SNPRINTF wraps the bpf_snprintf helper with variadic arguments instead of
|
||||
* an array of u64.
|
||||
*/
|
||||
#define BPF_SNPRINTF(out, out_size, fmt, args...) \
|
||||
({ \
|
||||
static const char ___fmt[] = fmt; \
|
||||
unsigned long long ___param[___bpf_narg(args)]; \
|
||||
\
|
||||
_Pragma("GCC diagnostic push") \
|
||||
_Pragma("GCC diagnostic ignored \"-Wint-conversion\"") \
|
||||
___bpf_fill(___param, args); \
|
||||
_Pragma("GCC diagnostic pop") \
|
||||
\
|
||||
bpf_snprintf(out, out_size, ___fmt, \
|
||||
___param, sizeof(___param)); \
|
||||
})
|
||||
|
||||
#ifdef BPF_NO_GLOBAL_DATA
|
||||
#define BPF_PRINTK_FMT_MOD
|
||||
#else
|
||||
#define BPF_PRINTK_FMT_MOD static const
|
||||
#endif
|
||||
|
||||
#define __bpf_printk(fmt, ...) \
|
||||
({ \
|
||||
BPF_PRINTK_FMT_MOD char ____fmt[] = fmt; \
|
||||
bpf_trace_printk(____fmt, sizeof(____fmt), \
|
||||
##__VA_ARGS__); \
|
||||
})
|
||||
|
||||
/*
|
||||
* __bpf_vprintk wraps the bpf_trace_vprintk helper with variadic arguments
|
||||
* instead of an array of u64.
|
||||
*/
|
||||
#define __bpf_vprintk(fmt, args...) \
|
||||
({ \
|
||||
static const char ___fmt[] = fmt; \
|
||||
unsigned long long ___param[___bpf_narg(args)]; \
|
||||
\
|
||||
_Pragma("GCC diagnostic push") \
|
||||
_Pragma("GCC diagnostic ignored \"-Wint-conversion\"") \
|
||||
___bpf_fill(___param, args); \
|
||||
_Pragma("GCC diagnostic pop") \
|
||||
\
|
||||
bpf_trace_vprintk(___fmt, sizeof(___fmt), \
|
||||
___param, sizeof(___param)); \
|
||||
})
|
||||
|
||||
/* Use __bpf_printk when bpf_printk call has 3 or fewer fmt args
|
||||
* Otherwise use __bpf_vprintk
|
||||
*/
|
||||
#define ___bpf_pick_printk(...) \
|
||||
___bpf_nth(_, ##__VA_ARGS__, __bpf_vprintk, __bpf_vprintk, __bpf_vprintk, \
|
||||
__bpf_vprintk, __bpf_vprintk, __bpf_vprintk, __bpf_vprintk, \
|
||||
__bpf_vprintk, __bpf_vprintk, __bpf_printk /*3*/, __bpf_printk /*2*/,\
|
||||
__bpf_printk /*1*/, __bpf_printk /*0*/)
|
||||
|
||||
/* Helper macro to print out debug messages */
|
||||
#define bpf_printk(fmt, args...) ___bpf_pick_printk(args)(fmt, ##args)
|
||||
|
||||
#endif
|
@ -1,30 +1,23 @@
|
||||
// +build ignore
|
||||
/*
|
||||
* SPDX-License-Identifier: AGPL-3.0-only
|
||||
* Copyright (c) since 2022, mzz2017 (mzz@tuta.io). All rights reserved.
|
||||
*/
|
||||
|
||||
#include <asm-generic/errno-base.h>
|
||||
#include <iproute2/bpf_elf.h>
|
||||
#include <linux/bpf.h>
|
||||
#include <linux/if_ether.h>
|
||||
#include <linux/in.h>
|
||||
#include <linux/in6.h>
|
||||
#include <linux/ip.h>
|
||||
#include <linux/ipv6.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/pkt_cls.h>
|
||||
#include <linux/tcp.h>
|
||||
#include <linux/types.h>
|
||||
#include <linux/udp.h>
|
||||
#include <net/if.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
#include <bpf/bpf_endian.h>
|
||||
#include <bpf/bpf_helpers.h>
|
||||
#include <sys/cdefs.h>
|
||||
#include <sys/types.h>
|
||||
#include "bpf_endian.h"
|
||||
#include "bpf_helpers.h"
|
||||
|
||||
// #include "addr.h"
|
||||
|
||||
// #define likely(x) x
|
||||
// #define unlikely(x) x
|
||||
@ -41,12 +34,15 @@
|
||||
|
||||
#define MAX_PARAM_LEN 16
|
||||
#define MAX_INTERFACE_NUM 128
|
||||
#define MAX_ROUTING_LEN 96
|
||||
#define MAX_ROUTING_LEN (32 * 3)
|
||||
#define MAX_LPM_SIZE 20480
|
||||
//#define MAX_LPM_SIZE 20480
|
||||
#define MAX_LPM_NUM (MAX_ROUTING_LEN + 8)
|
||||
#define MAX_DEST_MAPPING_NUM (65536 * 2)
|
||||
#define IPV6_MAX_EXTENSIONS 4
|
||||
|
||||
#define OUTBOUND_DIRECT 0
|
||||
#define OUTBOUND_BLOCK 1
|
||||
#define OUTBOUND_CONTROL_PLANE_DIRECT 0xFE
|
||||
#define OUTBOUND_LOGICAL_AND 0xFF
|
||||
|
||||
@ -62,10 +58,6 @@ static const __u32 zero_key = 0;
|
||||
static const __u32 tproxy_port_key = 1;
|
||||
static const __u32 disable_l4_tx_checksum_key = 2;
|
||||
static const __u32 disable_l4_rx_checksum_key = 3;
|
||||
static const __u32 epoch_key __attribute__((unused, deprecated)) = 4;
|
||||
static const __u32 routings_len_key __attribute__((unused, deprecated)) = 5;
|
||||
|
||||
static __be32 unspecific_ipv6[4] __attribute__((__unused__)) = {0, 0, 0, 0};
|
||||
|
||||
struct ip_port {
|
||||
__be32 ip[4];
|
||||
@ -96,7 +88,7 @@ struct {
|
||||
// enough for identifier. And UDP client
|
||||
// side does not care it (full-cone).
|
||||
__type(value, struct ip_port_outbound); // Original target.
|
||||
__uint(max_entries, 0xFF << 2);
|
||||
__uint(max_entries, MAX_DEST_MAPPING_NUM);
|
||||
/// NOTICE: It MUST be pinned.
|
||||
__uint(pinning, LIBBPF_PIN_BY_NAME);
|
||||
} dst_map SEC(".maps");
|
||||
@ -132,7 +124,7 @@ struct {
|
||||
__uint(max_entries, MAX_INTERFACE_NUM);
|
||||
/// NOTICE: No persistence.
|
||||
// __uint(pinning, LIBBPF_PIN_BY_NAME);
|
||||
} ifindex_ip_map SEC(".maps");
|
||||
} ifindex_tproxy_ip_map SEC(".maps");
|
||||
|
||||
// Array of LPM tries:
|
||||
struct lpm_key {
|
||||
@ -145,12 +137,12 @@ struct map_lpm_type {
|
||||
__uint(max_entries, MAX_LPM_SIZE);
|
||||
__uint(key_size, sizeof(struct lpm_key));
|
||||
__uint(value_size, sizeof(__u32));
|
||||
} unused_lpm_type SEC(".maps");
|
||||
} unused_lpm_type SEC(".maps"), host_ip_lpm SEC(".maps");
|
||||
struct {
|
||||
__uint(type, BPF_MAP_TYPE_ARRAY_OF_MAPS);
|
||||
__uint(key_size, sizeof(__u32));
|
||||
__uint(max_entries, MAX_LPM_NUM);
|
||||
__uint(pinning, LIBBPF_PIN_BY_NAME);
|
||||
// __uint(pinning, LIBBPF_PIN_BY_NAME);
|
||||
__array(values, struct map_lpm_type);
|
||||
} lpm_array_map SEC(".maps");
|
||||
|
||||
@ -199,16 +191,11 @@ struct {
|
||||
__type(key, __u32);
|
||||
__type(value, struct routing);
|
||||
__uint(max_entries, MAX_ROUTING_LEN);
|
||||
__uint(pinning, LIBBPF_PIN_BY_NAME);
|
||||
// __uint(pinning, LIBBPF_PIN_BY_NAME);
|
||||
} routing_map SEC(".maps");
|
||||
|
||||
struct domain_routing {
|
||||
__u32 bitmap[MAX_ROUTING_LEN / 32];
|
||||
/// DEPRECATED: Epoch is the epoch at the write time. Every time the control
|
||||
/// plane restarts, epoch += 1. It was deprecated because long connection will
|
||||
/// keep their states by persistent dst_map (we only need to know if it is a
|
||||
/// old connection).
|
||||
__u32 epoch;
|
||||
};
|
||||
struct {
|
||||
__uint(type, BPF_MAP_TYPE_LRU_HASH);
|
||||
@ -220,7 +207,7 @@ struct {
|
||||
|
||||
// Functions:
|
||||
|
||||
static __always_inline bool equal_ipv6(__be32 x[4], __be32 y[4]) {
|
||||
static __always_inline bool equal_ipv6_format(__be32 x[4], __be32 y[4]) {
|
||||
#if __clang_major__ >= 10
|
||||
return ((__be64 *)x)[0] == ((__be64 *)y)[0] &&
|
||||
((__be64 *)x)[1] == ((__be64 *)y)[1];
|
||||
@ -248,7 +235,7 @@ static __always_inline long rewrite_ip(struct __sk_buff *skb, bool is_ipv6,
|
||||
__u8 proto, __u8 ihl, __be32 old_ip[4],
|
||||
__be32 new_ip[4], bool is_dest) {
|
||||
// Nothing to do.
|
||||
if (equal_ipv6(old_ip, new_ip)) {
|
||||
if (equal_ipv6_format(old_ip, new_ip)) {
|
||||
return 0;
|
||||
}
|
||||
// bpf_printk("%pI6->%pI6", old_ip, new_ip);
|
||||
@ -486,28 +473,26 @@ parse_transport(struct __sk_buff *skb, struct ethhdr **ethh, struct iphdr **iph,
|
||||
}
|
||||
|
||||
static __always_inline long ip_is_host(bool is_ipv6, __u32 ifindex,
|
||||
__be32 ip[4],
|
||||
__be32 (*first_interface_ip)[4]) {
|
||||
struct if_ip *if_ip = bpf_map_lookup_elem(&ifindex_ip_map, &ifindex);
|
||||
if (unlikely(!if_ip)) {
|
||||
return -1;
|
||||
__be32 ip[4], __be32 tproxy_ip[4]) {
|
||||
if (tproxy_ip) {
|
||||
struct if_ip *if_ip = bpf_map_lookup_elem(&ifindex_tproxy_ip_map, &ifindex);
|
||||
if (unlikely(!if_ip)) {
|
||||
return -1;
|
||||
}
|
||||
if (!is_ipv6 && (*if_ip).hasIp4) {
|
||||
__builtin_memcpy(tproxy_ip, (*if_ip).ip4, IPV6_BYTE_LENGTH);
|
||||
} else if (is_ipv6 && (*if_ip).hasIp6) {
|
||||
__builtin_memcpy(tproxy_ip, (*if_ip).ip6, IPV6_BYTE_LENGTH);
|
||||
} else {
|
||||
// Should TC_ACT_OK outer.
|
||||
return -EFAULT;
|
||||
}
|
||||
}
|
||||
__u32 host_ip[4];
|
||||
if (!is_ipv6 && (*if_ip).hasIp4) {
|
||||
__builtin_memcpy(host_ip, (*if_ip).ip4, IPV6_BYTE_LENGTH);
|
||||
} else if (is_ipv6 && (*if_ip).hasIp6) {
|
||||
__builtin_memcpy(host_ip, (*if_ip).ip6, IPV6_BYTE_LENGTH);
|
||||
} else {
|
||||
// Should TC_ACT_OK outer.
|
||||
return -EFAULT;
|
||||
}
|
||||
if (first_interface_ip) {
|
||||
__builtin_memcpy(*first_interface_ip, host_ip, IPV6_BYTE_LENGTH);
|
||||
}
|
||||
if (equal_ipv6(ip, host_ip)) {
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
|
||||
struct lpm_key lpm_key;
|
||||
lpm_key.trie_key.prefixlen = IPV6_BYTE_LENGTH * 8;
|
||||
__builtin_memcpy(lpm_key.data, ip, IPV6_BYTE_LENGTH);
|
||||
return bpf_map_lookup_elem(&host_ip_lpm, &lpm_key) ? 1 : 0;
|
||||
}
|
||||
|
||||
static __always_inline long adjust_udp_len(struct __sk_buff *skb, __u16 oldlen,
|
||||
@ -597,9 +582,9 @@ static __always_inline long encap_after_udp_hdr(struct __sk_buff *skb,
|
||||
__be16 iphdr_tot_len,
|
||||
void *newhdr, __u32 newhdrlen) {
|
||||
if (unlikely(newhdrlen % 4 != 0)) {
|
||||
bpf_trace_printk("encap_after_udp_hdr: unexpected newhdrlen value %u :must "
|
||||
"be a multiple of 4",
|
||||
newhdrlen);
|
||||
bpf_printk("encap_after_udp_hdr: unexpected newhdrlen value %u :must "
|
||||
"be a multiple of 4",
|
||||
newhdrlen);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
@ -664,10 +649,9 @@ static __always_inline int decap_after_udp_hdr(struct __sk_buff *skb,
|
||||
__be16 iphdr_tot_len, void *to,
|
||||
__u32 decap_hdrlen) {
|
||||
if (unlikely(decap_hdrlen % 4 != 0)) {
|
||||
bpf_trace_printk(
|
||||
"encap_after_udp_hdr: unexpected decap_hdrlen value %u :must "
|
||||
"be a multiple of 4",
|
||||
decap_hdrlen);
|
||||
bpf_printk("encap_after_udp_hdr: unexpected decap_hdrlen value %u :must "
|
||||
"be a multiple of 4",
|
||||
decap_hdrlen);
|
||||
return -EINVAL;
|
||||
}
|
||||
long ret = 0;
|
||||
@ -742,15 +726,7 @@ static long routing(__u8 flag[2], void *l4_hdr, __be32 saddr[4],
|
||||
__be32 daddr[4], __be32 mac[4]) {
|
||||
#define _l4proto flag[0]
|
||||
#define _ipversion flag[1]
|
||||
// // Get len of routings and epoch from param_map.
|
||||
// __u32 *routings_len = bpf_map_lookup_elem(¶m_map, &routings_len_key);
|
||||
// if (!routings_len) {
|
||||
// return -EINVAL;
|
||||
// }
|
||||
// __u32 *epoch = bpf_map_lookup_elem(¶m_map, &epoch_key);
|
||||
// if (!epoch) {
|
||||
// return -EINVAL;
|
||||
// }
|
||||
|
||||
// Define variables for further use.
|
||||
__u16 h_dport;
|
||||
__u16 h_sport;
|
||||
@ -786,13 +762,6 @@ static long routing(__u8 flag[2], void *l4_hdr, __be32 saddr[4],
|
||||
bool bad_rule = false;
|
||||
struct domain_routing *domain_routing;
|
||||
|
||||
/// DEPRECATED: Epoch was deprecated and domain_routing_map was unpinned, thus
|
||||
/// this branch will never hit.
|
||||
// if (domain_routing && domain_routing->epoch != *epoch) {
|
||||
// // Dirty (epoch dismatch) traffic should be routed by the control plane.
|
||||
// return OUTBOUND_CONTROL_PLANE_DIRECT;
|
||||
// }
|
||||
|
||||
#pragma unroll
|
||||
for (__u32 key = 0; key < MAX_ROUTING_LEN; key++) {
|
||||
__u32 k = key; // Clone to pass code checker.
|
||||
@ -895,6 +864,7 @@ int tproxy_ingress(struct __sk_buff *skb) {
|
||||
struct udphdr *udph;
|
||||
__sum16 bak_cksm;
|
||||
__u8 ihl;
|
||||
bool tcp_state_syn;
|
||||
long ret = parse_transport(skb, ðh, &iph, &ipv6h, &tcph, &udph, &ihl);
|
||||
if (ret) {
|
||||
bpf_printk("parse_transport: %ld", ret);
|
||||
@ -906,13 +876,7 @@ int tproxy_ingress(struct __sk_buff *skb) {
|
||||
|
||||
// Backup for further use.
|
||||
__u8 l4_proto;
|
||||
if (tcph) {
|
||||
l4_proto = IPPROTO_TCP;
|
||||
} else if (udph) {
|
||||
l4_proto = IPPROTO_UDP;
|
||||
} else {
|
||||
return TC_ACT_OK;
|
||||
}
|
||||
__be16 ip_tot_len = 0;
|
||||
|
||||
// Parse saddr and daddr as ipv6 format.
|
||||
__be32 saddr[4];
|
||||
@ -927,6 +891,8 @@ int tproxy_ingress(struct __sk_buff *skb) {
|
||||
daddr[1] = 0;
|
||||
daddr[2] = bpf_htonl(0x0000ffff);
|
||||
daddr[3] = iph->daddr;
|
||||
|
||||
ip_tot_len = iph->tot_len;
|
||||
} else if (ipv6h) {
|
||||
__builtin_memcpy(daddr, &ipv6h->daddr, IPV6_BYTE_LENGTH);
|
||||
__builtin_memcpy(saddr, &ipv6h->saddr, IPV6_BYTE_LENGTH);
|
||||
@ -935,8 +901,8 @@ int tproxy_ingress(struct __sk_buff *skb) {
|
||||
}
|
||||
|
||||
// If this packet is sent to this host, accept it.
|
||||
__u32 first_interface_ip[4];
|
||||
long to_host = ip_is_host(ipv6h, skb->ifindex, daddr, &first_interface_ip);
|
||||
__u32 tproxy_ip[4];
|
||||
long to_host = ip_is_host(ipv6h, skb->ifindex, daddr, tproxy_ip);
|
||||
if (to_host < 0) { // error
|
||||
// bpf_printk("to_host: %ld", to_host);
|
||||
return TC_ACT_OK;
|
||||
@ -946,7 +912,6 @@ int tproxy_ingress(struct __sk_buff *skb) {
|
||||
// To host:53. Process it.
|
||||
} else {
|
||||
// To host. Accept.
|
||||
/// FIXME: all host ip.
|
||||
return TC_ACT_OK;
|
||||
}
|
||||
}
|
||||
@ -958,8 +923,9 @@ int tproxy_ingress(struct __sk_buff *skb) {
|
||||
|
||||
if (tcph) {
|
||||
// Backup for further use.
|
||||
l4_proto = IPPROTO_TCP;
|
||||
bak_cksm = tcph->check;
|
||||
bool tcp_state_syn = tcph->syn && !tcph->ack;
|
||||
tcp_state_syn = tcph->syn && !tcph->ack;
|
||||
struct ip_port_proto key_src;
|
||||
__builtin_memset(&key_src, 0, sizeof(key_src));
|
||||
__builtin_memcpy(key_src.ip, saddr, IPV6_BYTE_LENGTH);
|
||||
@ -1003,6 +969,8 @@ int tproxy_ingress(struct __sk_buff *skb) {
|
||||
bpf_printk("tcp: outbound: %u, %pI6", outbound, daddr);
|
||||
if (outbound == OUTBOUND_DIRECT) {
|
||||
return TC_ACT_OK;
|
||||
} else if (unlikely(outbound == OUTBOUND_BLOCK)) {
|
||||
return TC_ACT_SHOT;
|
||||
} else {
|
||||
// Rewrite to control plane.
|
||||
|
||||
@ -1017,8 +985,8 @@ int tproxy_ingress(struct __sk_buff *skb) {
|
||||
|
||||
__u32 *dst_ip = daddr;
|
||||
__u16 dst_port = tcph->dest;
|
||||
if ((ret = rewrite_ip(skb, ipv6h, IPPROTO_TCP, ihl, dst_ip,
|
||||
first_interface_ip, true))) {
|
||||
if ((ret = rewrite_ip(skb, ipv6h, IPPROTO_TCP, ihl, dst_ip, tproxy_ip,
|
||||
true))) {
|
||||
bpf_printk("Shot IP: %ld", ret);
|
||||
return TC_ACT_SHOT;
|
||||
}
|
||||
@ -1031,6 +999,7 @@ int tproxy_ingress(struct __sk_buff *skb) {
|
||||
} else if (udph) {
|
||||
// Backup for further use.
|
||||
bak_cksm = udph->check;
|
||||
l4_proto = IPPROTO_UDP;
|
||||
struct ip_port_outbound new_hdr;
|
||||
__builtin_memset(&new_hdr, 0, sizeof(new_hdr));
|
||||
__builtin_memcpy(new_hdr.ip, daddr, IPV6_BYTE_LENGTH);
|
||||
@ -1059,18 +1028,19 @@ int tproxy_ingress(struct __sk_buff *skb) {
|
||||
|
||||
if (new_hdr.outbound == OUTBOUND_DIRECT) {
|
||||
return TC_ACT_OK;
|
||||
} else if (unlikely(new_hdr.outbound == OUTBOUND_BLOCK)) {
|
||||
return TC_ACT_SHOT;
|
||||
} else {
|
||||
// Rewrite to control plane.
|
||||
|
||||
// Encap a header to transmit fullcone tuple.
|
||||
__be16 ip_tot_len = iph ? iph->tot_len : 0;
|
||||
encap_after_udp_hdr(skb, ipv6h, ihl, ip_tot_len, &new_hdr,
|
||||
sizeof(new_hdr));
|
||||
|
||||
// Rewrite udp dst ip.
|
||||
// bpf_printk("rewrite dst ip from %pI4", &ori_dst.ip);
|
||||
if ((ret = rewrite_ip(skb, ipv6h, IPPROTO_UDP, ihl, new_hdr.ip,
|
||||
first_interface_ip, true))) {
|
||||
if ((ret = rewrite_ip(skb, ipv6h, IPPROTO_UDP, ihl, new_hdr.ip, tproxy_ip,
|
||||
true))) {
|
||||
bpf_printk("Shot IP: %ld", ret);
|
||||
return TC_ACT_SHOT;
|
||||
}
|
||||
@ -1129,6 +1099,7 @@ int tproxy_egress(struct __sk_buff *skb) {
|
||||
struct tcphdr *tcph;
|
||||
struct udphdr *udph;
|
||||
__sum16 bak_cksm;
|
||||
__u8 l4_proto;
|
||||
__u8 ihl;
|
||||
long ret = parse_transport(skb, ðh, &iph, &ipv6h, &tcph, &udph, &ihl);
|
||||
if (ret) {
|
||||
@ -1138,6 +1109,7 @@ int tproxy_egress(struct __sk_buff *skb) {
|
||||
// Parse saddr and daddr as ipv6 format.
|
||||
__be32 saddr[4];
|
||||
__be32 daddr[4];
|
||||
__be16 ip_tot_len = 0;
|
||||
if (iph) {
|
||||
saddr[0] = 0;
|
||||
saddr[1] = 0;
|
||||
@ -1148,6 +1120,8 @@ int tproxy_egress(struct __sk_buff *skb) {
|
||||
daddr[1] = 0;
|
||||
daddr[2] = bpf_htonl(0x0000ffff);
|
||||
daddr[3] = iph->daddr;
|
||||
|
||||
ip_tot_len = iph->tot_len;
|
||||
} else if (ipv6h) {
|
||||
__builtin_memcpy(daddr, ipv6h->daddr.in6_u.u6_addr32, IPV6_BYTE_LENGTH);
|
||||
__builtin_memcpy(saddr, ipv6h->saddr.in6_u.u6_addr32, IPV6_BYTE_LENGTH);
|
||||
@ -1160,23 +1134,17 @@ int tproxy_egress(struct __sk_buff *skb) {
|
||||
if (!tproxy_port) {
|
||||
return TC_ACT_OK;
|
||||
}
|
||||
long from_host = ip_is_host(ipv6h, skb->ifindex, saddr, NULL);
|
||||
if (!(from_host == 1)) {
|
||||
// Not from localhost.
|
||||
__be32 tproxy_ip[4];
|
||||
ret = ip_is_host(ipv6h, skb->ifindex, saddr, tproxy_ip);
|
||||
if (!(ret == 1)) {
|
||||
return TC_ACT_OK;
|
||||
}
|
||||
if (!equal_ipv6_format(saddr, tproxy_ip)) {
|
||||
return TC_ACT_OK;
|
||||
}
|
||||
|
||||
// Backup for further use.
|
||||
__u8 l4_proto;
|
||||
if (tcph) {
|
||||
l4_proto = IPPROTO_TCP;
|
||||
} else if (udph) {
|
||||
l4_proto = IPPROTO_UDP;
|
||||
} else {
|
||||
return TC_ACT_OK;
|
||||
}
|
||||
|
||||
if (tcph) {
|
||||
if (tcph->source != *tproxy_port) {
|
||||
return TC_ACT_OK;
|
||||
}
|
||||
@ -1216,6 +1184,7 @@ int tproxy_egress(struct __sk_buff *skb) {
|
||||
return TC_ACT_SHOT;
|
||||
}
|
||||
} else if (udph) {
|
||||
l4_proto = IPPROTO_UDP;
|
||||
if (udph->source != *tproxy_port) {
|
||||
return TC_ACT_OK;
|
||||
}
|
||||
@ -1233,7 +1202,6 @@ int tproxy_egress(struct __sk_buff *skb) {
|
||||
// Get source ip/port from our packet header.
|
||||
|
||||
// Decap header to get fullcone tuple.
|
||||
__be16 ip_tot_len = iph ? iph->tot_len : 0;
|
||||
decap_after_udp_hdr(skb, ipv6h, ihl, ip_tot_len, &ori_src, sizeof(ori_src));
|
||||
|
||||
// Rewrite udp src ip
|
||||
@ -1274,7 +1242,7 @@ int tproxy_egress(struct __sk_buff *skb) {
|
||||
if (*disable_l4_checksum == DISABLE_L4_CHECKSUM_POLICY_SET_ZERO) {
|
||||
bak_cksm = 0;
|
||||
}
|
||||
bpf_skb_store_bytes(skb, l4_cksm_off, &bak_cksm, 2, 0);
|
||||
bpf_skb_store_bytes(skb, l4_cksm_off, &bak_cksm, sizeof(bak_cksm), 0);
|
||||
}
|
||||
}
|
||||
return TC_ACT_OK;
|
||||
|
Reference in New Issue
Block a user