mirror of
https://github.com/Ysurac/openmptcprouter-feeds.git
synced 2025-02-13 11:01:50 +00:00
884 lines
30 KiB
Diff
884 lines
30 KiB
Diff
diff -aurN shadowsocks-libev-nocrypto-nocrypto/configure.ac shadowsocks-libev-nocrypto-ebpf/configure.ac
|
||
--- shadowsocks-libev-nocrypto-nocrypto/configure.ac 2018-06-23 14:57:34.000000000 +0200
|
||
+++ shadowsocks-libev-nocrypto-ebpf/configure.ac 2018-08-14 13:45:18.000000000 +0200
|
||
@@ -245,6 +245,11 @@
|
||
[AC_DEFINE([USE_SYSTEM_SHARED_LIB], [1], [Define if use system shared lib.])],
|
||
[AC_CONFIG_FILES([libbloom/Makefile libcork/Makefile libipset/Makefile])])
|
||
|
||
+AC_CHECK_HEADERS([linux/bpf.h bpf/bpf.h bpf/libbpf.h], [],
|
||
+ [AC_MSG_ERROR([Missing libbpf headers. Install libbpf from kernel library sources])])
|
||
+
|
||
+AC_CHECK_LIB([elf], [elf_getdata], [LIBS="-lelf $LIBS"], [AC_MSG_ERROR([Couldn't find libelf])])
|
||
+
|
||
AC_ARG_ENABLE(connmarktos,
|
||
[AS_HELP_STRING(--enable-connmarktos, Enable saved connmark to IP TOS QoS feature)],
|
||
[
|
||
diff -aurN shadowsocks-libev-nocrypto-nocrypto/src/bpf_helpers.h shadowsocks-libev-nocrypto-ebpf/src/bpf_helpers.h
|
||
--- shadowsocks-libev-nocrypto-nocrypto/src/bpf_helpers.h 1970-01-01 01:00:00.000000000 +0100
|
||
+++ shadowsocks-libev-nocrypto-ebpf/src/bpf_helpers.h 2018-08-14 13:45:18.000000000 +0200
|
||
@@ -0,0 +1,208 @@
|
||
+/* SPDX-License-Identifier: GPL-2.0 */
|
||
+#ifndef __BPF_HELPERS_H
|
||
+#define __BPF_HELPERS_H
|
||
+
|
||
+/* helper macro to place programs, maps, license in
|
||
+ * different sections in elf_bpf file. Section names
|
||
+ * are interpreted by elf_bpf loader
|
||
+ */
|
||
+#define SEC(NAME) __attribute__((section(NAME), used))
|
||
+
|
||
+/* helper functions called from eBPF programs written in C */
|
||
+static void *(*bpf_map_lookup_elem)(void *map, void *key) =
|
||
+ (void *) BPF_FUNC_map_lookup_elem;
|
||
+static int (*bpf_map_update_elem)(void *map, void *key, void *value,
|
||
+ unsigned long long flags) =
|
||
+ (void *) BPF_FUNC_map_update_elem;
|
||
+static int (*bpf_map_delete_elem)(void *map, void *key) =
|
||
+ (void *) BPF_FUNC_map_delete_elem;
|
||
+static int (*bpf_probe_read)(void *dst, int size, void *unsafe_ptr) =
|
||
+ (void *) BPF_FUNC_probe_read;
|
||
+static unsigned long long (*bpf_ktime_get_ns)(void) =
|
||
+ (void *) BPF_FUNC_ktime_get_ns;
|
||
+static int (*bpf_trace_printk)(const char *fmt, int fmt_size, ...) =
|
||
+ (void *) BPF_FUNC_trace_printk;
|
||
+static void (*bpf_tail_call)(void *ctx, void *map, int index) =
|
||
+ (void *) BPF_FUNC_tail_call;
|
||
+static unsigned long long (*bpf_get_smp_processor_id)(void) =
|
||
+ (void *) BPF_FUNC_get_smp_processor_id;
|
||
+static unsigned long long (*bpf_get_current_pid_tgid)(void) =
|
||
+ (void *) BPF_FUNC_get_current_pid_tgid;
|
||
+static unsigned long long (*bpf_get_current_uid_gid)(void) =
|
||
+ (void *) BPF_FUNC_get_current_uid_gid;
|
||
+static int (*bpf_get_current_comm)(void *buf, int buf_size) =
|
||
+ (void *) BPF_FUNC_get_current_comm;
|
||
+static unsigned long long (*bpf_perf_event_read)(void *map,
|
||
+ unsigned long long flags) =
|
||
+ (void *) BPF_FUNC_perf_event_read;
|
||
+static int (*bpf_clone_redirect)(void *ctx, int ifindex, int flags) =
|
||
+ (void *) BPF_FUNC_clone_redirect;
|
||
+static int (*bpf_redirect)(int ifindex, int flags) =
|
||
+ (void *) BPF_FUNC_redirect;
|
||
+static int (*bpf_redirect_map)(void *map, int key, int flags) =
|
||
+ (void *) BPF_FUNC_redirect_map;
|
||
+static int (*bpf_perf_event_output)(void *ctx, void *map,
|
||
+ unsigned long long flags, void *data,
|
||
+ int size) =
|
||
+ (void *) BPF_FUNC_perf_event_output;
|
||
+static int (*bpf_get_stackid)(void *ctx, void *map, int flags) =
|
||
+ (void *) BPF_FUNC_get_stackid;
|
||
+static int (*bpf_probe_write_user)(void *dst, void *src, int size) =
|
||
+ (void *) BPF_FUNC_probe_write_user;
|
||
+static int (*bpf_current_task_under_cgroup)(void *map, int index) =
|
||
+ (void *) BPF_FUNC_current_task_under_cgroup;
|
||
+static int (*bpf_skb_get_tunnel_key)(void *ctx, void *key, int size, int flags) =
|
||
+ (void *) BPF_FUNC_skb_get_tunnel_key;
|
||
+static int (*bpf_skb_set_tunnel_key)(void *ctx, void *key, int size, int flags) =
|
||
+ (void *) BPF_FUNC_skb_set_tunnel_key;
|
||
+static int (*bpf_skb_get_tunnel_opt)(void *ctx, void *md, int size) =
|
||
+ (void *) BPF_FUNC_skb_get_tunnel_opt;
|
||
+static int (*bpf_skb_set_tunnel_opt)(void *ctx, void *md, int size) =
|
||
+ (void *) BPF_FUNC_skb_set_tunnel_opt;
|
||
+static unsigned long long (*bpf_get_prandom_u32)(void) =
|
||
+ (void *) BPF_FUNC_get_prandom_u32;
|
||
+static int (*bpf_xdp_adjust_head)(void *ctx, int offset) =
|
||
+ (void *) BPF_FUNC_xdp_adjust_head;
|
||
+static int (*bpf_setsockopt)(void *ctx, int level, int optname, void *optval,
|
||
+ int optlen) =
|
||
+ (void *) BPF_FUNC_setsockopt;
|
||
+static int (*bpf_sk_redirect_map)(void *ctx, void *map, int key, int flags) =
|
||
+ (void *) BPF_FUNC_sk_redirect_map;
|
||
+static int (*bpf_sock_map_update)(void *map, void *key, void *value,
|
||
+ unsigned long long flags) =
|
||
+ (void *) BPF_FUNC_sock_map_update;
|
||
+
|
||
+
|
||
+/* llvm builtin functions that eBPF C program may use to
|
||
+ * emit BPF_LD_ABS and BPF_LD_IND instructions
|
||
+ */
|
||
+struct sk_buff;
|
||
+unsigned long long load_byte(void *skb,
|
||
+ unsigned long long off) asm("llvm.bpf.load.byte");
|
||
+unsigned long long load_half(void *skb,
|
||
+ unsigned long long off) asm("llvm.bpf.load.half");
|
||
+unsigned long long load_word(void *skb,
|
||
+ unsigned long long off) asm("llvm.bpf.load.word");
|
||
+
|
||
+/* a helper structure used by eBPF C program
|
||
+ * to describe map attributes to elf_bpf loader
|
||
+ */
|
||
+struct bpf_map_def {
|
||
+ unsigned int type;
|
||
+ unsigned int key_size;
|
||
+ unsigned int value_size;
|
||
+ unsigned int max_entries;
|
||
+ unsigned int map_flags;
|
||
+ unsigned int inner_map_idx;
|
||
+ unsigned int numa_node;
|
||
+};
|
||
+
|
||
+static int (*bpf_skb_load_bytes)(void *ctx, int off, void *to, int len) =
|
||
+ (void *) BPF_FUNC_skb_load_bytes;
|
||
+static int (*bpf_skb_store_bytes)(void *ctx, int off, void *from, int len, int flags) =
|
||
+ (void *) BPF_FUNC_skb_store_bytes;
|
||
+static int (*bpf_l3_csum_replace)(void *ctx, int off, int from, int to, int flags) =
|
||
+ (void *) BPF_FUNC_l3_csum_replace;
|
||
+static int (*bpf_l4_csum_replace)(void *ctx, int off, int from, int to, int flags) =
|
||
+ (void *) BPF_FUNC_l4_csum_replace;
|
||
+static int (*bpf_skb_under_cgroup)(void *ctx, void *map, int index) =
|
||
+ (void *) BPF_FUNC_skb_under_cgroup;
|
||
+static int (*bpf_skb_change_head)(void *, int len, int flags) =
|
||
+ (void *) BPF_FUNC_skb_change_head;
|
||
+
|
||
+#if defined(__x86_64__)
|
||
+
|
||
+#define PT_REGS_PARM1(x) ((x)->di)
|
||
+#define PT_REGS_PARM2(x) ((x)->si)
|
||
+#define PT_REGS_PARM3(x) ((x)->dx)
|
||
+#define PT_REGS_PARM4(x) ((x)->cx)
|
||
+#define PT_REGS_PARM5(x) ((x)->r8)
|
||
+#define PT_REGS_RET(x) ((x)->sp)
|
||
+#define PT_REGS_FP(x) ((x)->bp)
|
||
+#define PT_REGS_RC(x) ((x)->ax)
|
||
+#define PT_REGS_SP(x) ((x)->sp)
|
||
+#define PT_REGS_IP(x) ((x)->ip)
|
||
+
|
||
+#elif defined(__s390x__)
|
||
+
|
||
+#define PT_REGS_PARM1(x) ((x)->gprs[2])
|
||
+#define PT_REGS_PARM2(x) ((x)->gprs[3])
|
||
+#define PT_REGS_PARM3(x) ((x)->gprs[4])
|
||
+#define PT_REGS_PARM4(x) ((x)->gprs[5])
|
||
+#define PT_REGS_PARM5(x) ((x)->gprs[6])
|
||
+#define PT_REGS_RET(x) ((x)->gprs[14])
|
||
+#define PT_REGS_FP(x) ((x)->gprs[11]) /* Works only with CONFIG_FRAME_POINTER */
|
||
+#define PT_REGS_RC(x) ((x)->gprs[2])
|
||
+#define PT_REGS_SP(x) ((x)->gprs[15])
|
||
+#define PT_REGS_IP(x) ((x)->psw.addr)
|
||
+
|
||
+#elif defined(__aarch64__)
|
||
+
|
||
+#define PT_REGS_PARM1(x) ((x)->regs[0])
|
||
+#define PT_REGS_PARM2(x) ((x)->regs[1])
|
||
+#define PT_REGS_PARM3(x) ((x)->regs[2])
|
||
+#define PT_REGS_PARM4(x) ((x)->regs[3])
|
||
+#define PT_REGS_PARM5(x) ((x)->regs[4])
|
||
+#define PT_REGS_RET(x) ((x)->regs[30])
|
||
+#define PT_REGS_FP(x) ((x)->regs[29]) /* Works only with CONFIG_FRAME_POINTER */
|
||
+#define PT_REGS_RC(x) ((x)->regs[0])
|
||
+#define PT_REGS_SP(x) ((x)->sp)
|
||
+#define PT_REGS_IP(x) ((x)->pc)
|
||
+
|
||
+#elif defined(__mips__)
|
||
+
|
||
+#define PT_REGS_PARM1(x) ((x)->regs[4])
|
||
+#define PT_REGS_PARM2(x) ((x)->regs[5])
|
||
+#define PT_REGS_PARM3(x) ((x)->regs[6])
|
||
+#define PT_REGS_PARM4(x) ((x)->regs[7])
|
||
+#define PT_REGS_PARM5(x) ((x)->regs[8])
|
||
+#define PT_REGS_RET(x) ((x)->regs[31])
|
||
+#define PT_REGS_FP(x) ((x)->regs[30]) /* Works only with CONFIG_FRAME_POINTER */
|
||
+#define PT_REGS_RC(x) ((x)->regs[1])
|
||
+#define PT_REGS_SP(x) ((x)->regs[29])
|
||
+#define PT_REGS_IP(x) ((x)->cp0_epc)
|
||
+
|
||
+#elif defined(__powerpc__)
|
||
+
|
||
+#define PT_REGS_PARM1(x) ((x)->gpr[3])
|
||
+#define PT_REGS_PARM2(x) ((x)->gpr[4])
|
||
+#define PT_REGS_PARM3(x) ((x)->gpr[5])
|
||
+#define PT_REGS_PARM4(x) ((x)->gpr[6])
|
||
+#define PT_REGS_PARM5(x) ((x)->gpr[7])
|
||
+#define PT_REGS_RC(x) ((x)->gpr[3])
|
||
+#define PT_REGS_SP(x) ((x)->sp)
|
||
+#define PT_REGS_IP(x) ((x)->nip)
|
||
+
|
||
+#elif defined(__sparc__)
|
||
+
|
||
+#define PT_REGS_PARM1(x) ((x)->u_regs[UREG_I0])
|
||
+#define PT_REGS_PARM2(x) ((x)->u_regs[UREG_I1])
|
||
+#define PT_REGS_PARM3(x) ((x)->u_regs[UREG_I2])
|
||
+#define PT_REGS_PARM4(x) ((x)->u_regs[UREG_I3])
|
||
+#define PT_REGS_PARM5(x) ((x)->u_regs[UREG_I4])
|
||
+#define PT_REGS_RET(x) ((x)->u_regs[UREG_I7])
|
||
+#define PT_REGS_RC(x) ((x)->u_regs[UREG_I0])
|
||
+#define PT_REGS_SP(x) ((x)->u_regs[UREG_FP])
|
||
+#if defined(__arch64__)
|
||
+#define PT_REGS_IP(x) ((x)->tpc)
|
||
+#else
|
||
+#define PT_REGS_IP(x) ((x)->pc)
|
||
+#endif
|
||
+
|
||
+#endif
|
||
+
|
||
+#ifdef __powerpc__
|
||
+#define BPF_KPROBE_READ_RET_IP(ip, ctx) ({ (ip) = (ctx)->link; })
|
||
+#define BPF_KRETPROBE_READ_RET_IP BPF_KPROBE_READ_RET_IP
|
||
+#elif defined(__sparc__)
|
||
+#define BPF_KPROBE_READ_RET_IP(ip, ctx) ({ (ip) = PT_REGS_RET(ctx); })
|
||
+#define BPF_KRETPROBE_READ_RET_IP BPF_KPROBE_READ_RET_IP
|
||
+#else
|
||
+#define BPF_KPROBE_READ_RET_IP(ip, ctx) ({ \
|
||
+ bpf_probe_read(&(ip), sizeof(ip), (void *)PT_REGS_RET(ctx)); })
|
||
+#define BPF_KRETPROBE_READ_RET_IP(ip, ctx) ({ \
|
||
+ bpf_probe_read(&(ip), sizeof(ip), \
|
||
+ (void *)(PT_REGS_FP(ctx) + sizeof(ip))); })
|
||
+#endif
|
||
+
|
||
+#endif
|
||
diff -aurN shadowsocks-libev-nocrypto-nocrypto/src/common.h shadowsocks-libev-nocrypto-ebpf/src/common.h
|
||
--- shadowsocks-libev-nocrypto-nocrypto/src/common.h 2018-06-23 14:57:34.000000000 +0200
|
||
+++ shadowsocks-libev-nocrypto-ebpf/src/common.h 2018-08-14 13:45:18.000000000 +0200
|
||
@@ -65,6 +65,7 @@
|
||
GETOPT_VAL_ACL,
|
||
GETOPT_VAL_MTU,
|
||
GETOPT_VAL_MPTCP,
|
||
+ GETOPT_VAL_EBPF,
|
||
GETOPT_VAL_PLUGIN,
|
||
GETOPT_VAL_PLUGIN_OPTS,
|
||
GETOPT_VAL_PASSWORD,
|
||
diff -aurN shadowsocks-libev-nocrypto-nocrypto/src/jconf.c shadowsocks-libev-nocrypto-ebpf/src/jconf.c
|
||
--- shadowsocks-libev-nocrypto-nocrypto/src/jconf.c 2018-06-23 14:57:34.000000000 +0200
|
||
+++ shadowsocks-libev-nocrypto-ebpf/src/jconf.c 2018-08-14 13:45:18.000000000 +0200
|
||
@@ -309,11 +309,16 @@
|
||
check_json_value_type(value, json_integer,
|
||
"invalid config file: option 'mtu' must be an integer");
|
||
conf.mtu = value->u.integer;
|
||
+ } else if (strcmp(name, "ebpf") == 0) {
|
||
+ check_json_value_type(value, json_boolean,
|
||
+ "invalid config file: option 'ebpf' must be a boolean");
|
||
+ conf.ebpf = value->u.boolean;
|
||
} else if (strcmp(name, "mptcp") == 0) {
|
||
check_json_value_type(value, json_boolean,
|
||
"invalid config file: option 'mptcp' must be a boolean");
|
||
conf.mptcp = value->u.boolean;
|
||
- } else if (strcmp(name, "ipv6_first") == 0) {
|
||
+ }
|
||
+ else if (strcmp(name, "ipv6_first") == 0) {
|
||
check_json_value_type(value, json_boolean,
|
||
"invalid config file: option 'ipv6_first' must be a boolean");
|
||
conf.ipv6_first = value->u.boolean;
|
||
diff -aurN shadowsocks-libev-nocrypto-nocrypto/src/jconf.h shadowsocks-libev-nocrypto-ebpf/src/jconf.h
|
||
--- shadowsocks-libev-nocrypto-nocrypto/src/jconf.h 2018-06-23 14:57:34.000000000 +0200
|
||
+++ shadowsocks-libev-nocrypto-ebpf/src/jconf.h 2018-08-14 13:45:18.000000000 +0200
|
||
@@ -84,6 +84,7 @@
|
||
int mode;
|
||
int mtu;
|
||
int mptcp;
|
||
+ int ebpf;
|
||
int ipv6_first;
|
||
int no_delay;
|
||
} jconf_t;
|
||
diff -aurN shadowsocks-libev-nocrypto-nocrypto/src/Makefile.am shadowsocks-libev-nocrypto-ebpf/src/Makefile.am
|
||
--- shadowsocks-libev-nocrypto-nocrypto/src/Makefile.am 2018-06-23 14:57:34.000000000 +0200
|
||
+++ shadowsocks-libev-nocrypto-ebpf/src/Makefile.am 2018-08-14 13:45:18.000000000 +0200
|
||
@@ -105,6 +105,9 @@
|
||
ss_redir_CFLAGS = $(AM_CFLAGS) -DMODULE_REDIR
|
||
ss_redir_LDADD = $(SS_COMMON_LIBS)
|
||
ss_redir_LDADD += -lcares
|
||
+ss_redir_LDADD += -lcap
|
||
+ss_redir_LDADD += -lbpf
|
||
+ss_redir_LDADD += -lelf
|
||
endif
|
||
|
||
lib_LTLIBRARIES = libshadowsocks-libev.la
|
||
diff -aurN shadowsocks-libev-nocrypto-nocrypto/src/redir.c shadowsocks-libev-nocrypto-ebpf/src/redir.c
|
||
--- shadowsocks-libev-nocrypto-nocrypto/src/redir.c 2018-06-23 14:57:34.000000000 +0200
|
||
+++ shadowsocks-libev-nocrypto-ebpf/src/redir.c 2018-08-14 13:45:18.000000000 +0200
|
||
@@ -43,6 +43,10 @@
|
||
|
||
#include <libcork/core.h>
|
||
|
||
+#include <linux/bpf.h>
|
||
+#include <bpf/bpf.h>
|
||
+#include <bpf/libbpf.h>
|
||
+
|
||
#ifdef HAVE_CONFIG_H
|
||
#include "config.h"
|
||
#endif
|
||
@@ -69,6 +73,9 @@
|
||
#define IP6T_SO_ORIGINAL_DST 80
|
||
#endif
|
||
|
||
+#define PARSE_PROG_FILENAME "sockmap_parse.o.ebpf"
|
||
+#define VERDICT_PROG_FILENAME "sockmap_verdict.o.ebpf"
|
||
+
|
||
static void accept_cb(EV_P_ ev_io *w, int revents);
|
||
static void server_recv_cb(EV_P_ ev_io *w, int revents);
|
||
static void server_send_cb(EV_P_ ev_io *w, int revents);
|
||
@@ -86,7 +93,10 @@
|
||
int verbose = 0;
|
||
int reuse_port = 0;
|
||
+int ebpf = 0;
|
||
|
||
static crypto_t *crypto;
|
||
+ebpf_conn_t *connections[65536];
|
||
+obufs_t obufs;
|
||
|
||
static int ipv6first = 0;
|
||
static int mode = TCP_ONLY;
|
||
@@ -128,6 +138,18 @@
|
||
return fcntl(fd, F_SETFL, flags | O_NONBLOCK);
|
||
}
|
||
|
||
+int
|
||
+is_open(int sock)
|
||
+{
|
||
+ int err;
|
||
+ err = recv(sock, NULL, 0, MSG_PEEK|MSG_DONTWAIT);
|
||
+ if(err == 0)
|
||
+ return 1;
|
||
+ if(err == -1 && errno == EAGAIN)
|
||
+ return 1;
|
||
+ return 0;
|
||
+}
|
||
+
|
||
int
|
||
create_and_bind(const char *addr, const char *port)
|
||
{
|
||
@@ -187,6 +209,316 @@
|
||
return listen_sock;
|
||
}
|
||
|
||
+int
|
||
+bpf_prog_load_obj_buf(void *obj_buf, int obj_buf_sz, const char *file, enum bpf_prog_type type,
|
||
+ struct bpf_object **pobj, int *prog_fd)
|
||
+{
|
||
+ struct bpf_program *prog;
|
||
+ struct bpf_object *obj;
|
||
+ int err;
|
||
+
|
||
+ obj = bpf_object__open_buffer(obj_buf, obj_buf_sz, file);
|
||
+ if (libbpf_get_error(obj))
|
||
+ return -ENOENT;
|
||
+
|
||
+ prog = bpf_program__next(NULL, obj);
|
||
+ if (!prog) {
|
||
+ bpf_object__close(obj);
|
||
+ return -ENOENT;
|
||
+ }
|
||
+
|
||
+ bpf_program__set_type(prog, type);
|
||
+ err = bpf_object__load(obj);
|
||
+ if (err) {
|
||
+ bpf_object__close(obj);
|
||
+ return -EINVAL;
|
||
+ }
|
||
+
|
||
+ *pobj = obj;
|
||
+ *prog_fd = bpf_program__fd(prog);
|
||
+ return 0;
|
||
+}
|
||
+
|
||
+int
|
||
+read_obj_file_into_buffer(char *fname, void **obj_buf, int *obj_buf_sz)
|
||
+{
|
||
+ FILE *fileptr = NULL;
|
||
+ char *buf;
|
||
+ long file_size, readed;
|
||
+ int err;
|
||
+
|
||
+ if(obj_buf == NULL || obj_buf_sz == NULL) {
|
||
+ LOGE("Invalid arguments for object file read\n");
|
||
+ goto error;
|
||
+ }
|
||
+
|
||
+ fileptr = fopen(fname, "rb");
|
||
+ if(fileptr == NULL) {
|
||
+ ERROR("fopen");
|
||
+ goto error;
|
||
+ }
|
||
+ err = fseek(fileptr, 0, SEEK_END);
|
||
+ if(err < 0) {
|
||
+ ERROR("fseek");
|
||
+ goto error;
|
||
+ }
|
||
+ file_size = ftell(fileptr);
|
||
+ if(file_size < 0) {
|
||
+ ERROR("ftell");
|
||
+ goto error;
|
||
+ }
|
||
+ rewind(fileptr);
|
||
+
|
||
+ buf = (char *) malloc((file_size) * sizeof(char));
|
||
+ if(buf == NULL) {
|
||
+ ERROR("malloc");
|
||
+ goto error;
|
||
+ }
|
||
+
|
||
+ readed = fread(buf, file_size, 1, fileptr);
|
||
+ if(readed != 1) {
|
||
+ ERROR("fread");
|
||
+ goto cleanup;
|
||
+ }
|
||
+
|
||
+ *obj_buf = (void *) buf;
|
||
+ *obj_buf_sz = file_size;
|
||
+ return 0;
|
||
+
|
||
+cleanup:
|
||
+ free(buf);
|
||
+error:
|
||
+ if(fileptr != NULL)
|
||
+ fclose(fileptr);
|
||
+ return -1;
|
||
+}
|
||
+
|
||
+int
|
||
+init_ebpf_object_buffers(obufs_t *progs)
|
||
+{
|
||
+ char *buf;
|
||
+ int i, err;
|
||
+
|
||
+ if(progs == NULL) {
|
||
+ printf("Invalid argument for object buffer initialization\n");
|
||
+ goto error;
|
||
+ }
|
||
+
|
||
+ err = read_obj_file_into_buffer(PARSE_PROG_FILENAME,
|
||
+ &progs->parse_prog, &progs->parse_prog_size);
|
||
+ if(err < 0) {
|
||
+ goto error;
|
||
+ }
|
||
+
|
||
+ err = read_obj_file_into_buffer(VERDICT_PROG_FILENAME,
|
||
+ &progs->verdict_prog, &progs->verdict_prog_size);
|
||
+ if(err < 0) {
|
||
+ goto error;
|
||
+ }
|
||
+
|
||
+ buf = (char *) progs->verdict_prog;
|
||
+ for(i = 0; i < progs->verdict_prog_size - 3; ++i) {
|
||
+ if(buf[i] == (char)0xfc &&
|
||
+ buf[i+1] == (char)0xfc &&
|
||
+ buf[i+2] == (char)0xfc &&
|
||
+ buf[i+3] == (char)0xfc) {
|
||
+
|
||
+ progs->verdict_port_p = (int *) &buf[i];
|
||
+ }
|
||
+ }
|
||
+
|
||
+ return 0;
|
||
+
|
||
+error:
|
||
+ return -1;
|
||
+}
|
||
+
|
||
+void
|
||
+free_ebpf_object_buffers(obufs_t *progs)
|
||
+{
|
||
+ free(progs->parse_prog);
|
||
+ free(progs->verdict_prog);
|
||
+ progs->verdict_port_p = NULL;
|
||
+ progs->parse_prog_size = -1;
|
||
+ progs->verdict_prog_size = -1;
|
||
+}
|
||
+
|
||
+int
|
||
+init_ebpf_connection(int local_sock, int remote_sock)
|
||
+{
|
||
+ int pfd, vfd, sfd, err = -1;
|
||
+ int local_key, remote_key;
|
||
+ ebpf_conn_t *conn;
|
||
+ socklen_t sock_size;
|
||
+ struct sockaddr_in local_addr;
|
||
+ struct bpf_object *vobj, *pobj;
|
||
+ struct bpf_map *smap;
|
||
+
|
||
+ local_key = 1; remote_key = 0;
|
||
+
|
||
+ conn = (ebpf_conn_t *) malloc(sizeof(ebpf_conn_t));
|
||
+ if(conn == NULL) {
|
||
+ ERROR("malloc");
|
||
+ goto error;
|
||
+ }
|
||
+
|
||
+ sock_size = sizeof(struct sockaddr);
|
||
+ err = getsockname(local_sock, (struct sockaddr *) &local_addr, &sock_size);
|
||
+ if(err < 0) {
|
||
+ ERROR("getsockname");
|
||
+ goto error_cleanup;
|
||
+ }
|
||
+ //set the correct local port in the bytecode before load
|
||
+ if(obufs.verdict_port_p != NULL)
|
||
+ *obufs.verdict_port_p = ntohs(local_addr.sin_port);
|
||
+ else {
|
||
+ LOGE("Invalid memory address to save port\n.");
|
||
+ goto error_cleanup;
|
||
+ }
|
||
+
|
||
+ err = bpf_prog_load_obj_buf(obufs.parse_prog,
|
||
+ obufs.parse_prog_size,
|
||
+ PARSE_PROG_FILENAME, BPF_PROG_TYPE_SK_SKB,
|
||
+ &pobj, &pfd);
|
||
+ if(err < 0) {
|
||
+ LOGE("Failed to load BPF object\n");
|
||
+ goto error_cleanup;
|
||
+ }
|
||
+
|
||
+ err = bpf_prog_load_obj_buf(obufs.verdict_prog,
|
||
+ obufs.verdict_prog_size,
|
||
+ VERDICT_PROG_FILENAME, BPF_PROG_TYPE_SK_SKB,
|
||
+ &vobj, &vfd);
|
||
+ if(err < 0) {
|
||
+ LOGE("Failed to load BPF object\n");
|
||
+ goto error_cleanup;
|
||
+ }
|
||
+
|
||
+ smap = bpf_object__find_map_by_name(vobj, "redirect_map");
|
||
+ if(smap == NULL) {
|
||
+ LOGE("Cannot find sockmap. Malformed BPF object\n");
|
||
+ goto error_cleanup;
|
||
+ }
|
||
+
|
||
+ sfd = bpf_map__fd(smap);
|
||
+ if(sfd < 0) {
|
||
+ LOGE("Unable to get sockmap reference fd\n");
|
||
+ goto error_cleanup;
|
||
+ }
|
||
+
|
||
+ err = bpf_prog_attach(pfd, sfd, BPF_SK_SKB_STREAM_PARSER, 0);
|
||
+ if(err < 0) {
|
||
+ LOGE("Failed to attach stream parser to sockmap\n");
|
||
+ goto error_cleanup;
|
||
+ }
|
||
+
|
||
+ err = bpf_prog_attach(vfd, sfd, BPF_SK_SKB_STREAM_VERDICT, 0);
|
||
+ if(err < 0) {
|
||
+ LOGE("Failed to attach verdict program to sockmap\n");
|
||
+ goto error_cleanup;
|
||
+ }
|
||
+
|
||
+ err = bpf_map_update_elem(sfd, &local_key, &local_sock, BPF_ANY);
|
||
+ if(err < 0) {
|
||
+ LOGE("Failed to put socket into sockmap\n");
|
||
+ goto error_cleanup;
|
||
+ }
|
||
+
|
||
+ err = bpf_map_update_elem(sfd, &remote_key, &remote_sock, BPF_ANY);
|
||
+ if(err < 0) {
|
||
+ LOGE("Failed to put socket into sockmap\n");
|
||
+ goto error_cleanup;
|
||
+ }
|
||
+
|
||
+ conn->sockmap_fd = sfd;
|
||
+ conn->parse_prog_fd = pfd;
|
||
+ conn->verdict_prog_fd = vfd;
|
||
+ conn->local_sock = local_sock;
|
||
+ conn->remote_sock = remote_sock;
|
||
+
|
||
+ connections[ntohs(local_addr.sin_port)] = conn;
|
||
+
|
||
+ free(vobj);
|
||
+ free(pobj);
|
||
+
|
||
+ return 0;
|
||
+
|
||
+error_cleanup:
|
||
+ free(conn);
|
||
+ free(vobj);
|
||
+ free(pobj);
|
||
+error:
|
||
+ return -1;
|
||
+}
|
||
+
|
||
+inline void
|
||
+free_ebpf_connection(ebpf_conn_t *conn)
|
||
+{
|
||
+ close(conn->sockmap_fd);
|
||
+ close(conn->parse_prog_fd);
|
||
+ close(conn->verdict_prog_fd);
|
||
+
|
||
+ if(is_open(conn->local_sock)) {
|
||
+ close(conn->local_sock);
|
||
+ }
|
||
+
|
||
+ if(is_open(conn->remote_sock)) {
|
||
+ close(conn->remote_sock);
|
||
+ }
|
||
+
|
||
+ conn = NULL;
|
||
+}
|
||
+
|
||
+int
|
||
+send_ebpf_handshake(int remote_sock, struct sockaddr_storage *destaddr)
|
||
+{
|
||
+ // send destaddr
|
||
+ buffer_t ss_addr_to_send;
|
||
+ buffer_t *abuf = &ss_addr_to_send;
|
||
+ balloc(abuf, BUF_SIZE);
|
||
+
|
||
+ if (AF_INET6 == destaddr->ss_family) { // IPv6
|
||
+ abuf->data[abuf->len++] = 4; // Type 4 is IPv6 address
|
||
+
|
||
+ size_t in6_addr_len = sizeof(struct in6_addr);
|
||
+ memcpy(abuf->data + abuf->len,
|
||
+ &(((struct sockaddr_in6 *) destaddr)->sin6_addr),
|
||
+ in6_addr_len);
|
||
+ abuf->len += in6_addr_len;
|
||
+ memcpy(abuf->data + abuf->len,
|
||
+ &(((struct sockaddr_in6 *) destaddr)->sin6_port),
|
||
+ 2);
|
||
+ } else { // IPv4
|
||
+ abuf->data[abuf->len++] = 1; // Type 1 is IPv4 address
|
||
+
|
||
+ size_t in_addr_len = sizeof(struct in_addr);
|
||
+ memcpy(abuf->data + abuf->len,
|
||
+ &((struct sockaddr_in *) destaddr)->sin_addr, in_addr_len);
|
||
+ abuf->len += in_addr_len;
|
||
+ memcpy(abuf->data + abuf->len,
|
||
+ &((struct sockaddr_in *) destaddr)->sin_port, 2);
|
||
+ }
|
||
+
|
||
+ abuf->len += 2;
|
||
+
|
||
+ struct sockaddr_storage addr;
|
||
+ memset(&addr, 0, sizeof(struct sockaddr_storage));
|
||
+ socklen_t len = sizeof addr;
|
||
+ int r, tries = 100;
|
||
+ do {
|
||
+ r = getpeername(remote_sock, (struct sockaddr *)&addr, &len);
|
||
+ } while(tries && r != 0);
|
||
+ if(r < 0) {
|
||
+ return -1;
|
||
+ }
|
||
+
|
||
+ r = send(remote_sock, abuf->data, abuf->len, 0);
|
||
+
|
||
+ bfree(abuf);
|
||
+
|
||
+ return r;
|
||
+}
|
||
+
|
||
static void
|
||
server_recv_cb(EV_P_ ev_io *w, int revents)
|
||
{
|
||
@@ -310,6 +642,8 @@
|
||
// all sent out, wait for reading
|
||
server->buf->len = 0;
|
||
server->buf->idx = 0;
|
||
+ if(ebpf && remote->recv_ctx->connected && remote->send_ctx->connected)
|
||
+ init_ebpf_connection(server->fd, remote->fd);
|
||
ev_io_stop(EV_A_ & server_send_ctx->io);
|
||
ev_io_start(EV_A_ & remote->recv_ctx->io);
|
||
}
|
||
@@ -323,17 +657,24 @@
|
||
delayed_connect_watcher);
|
||
remote_t *remote = server->remote;
|
||
|
||
- int r = connect(remote->fd, remote->addr,
|
||
- get_sockaddr_len(remote->addr));
|
||
+ if(!is_open(remote->fd)) {
|
||
+ int r = connect(remote->fd, remote->addr,
|
||
+ get_sockaddr_len(remote->addr));
|
||
|
||
- remote->addr = NULL;
|
||
+ remote->addr = NULL;
|
||
|
||
- if (r == -1 && errno != CONNECT_IN_PROGRESS) {
|
||
- ERROR("connect");
|
||
- close_and_free_remote(EV_A_ remote);
|
||
- close_and_free_server(EV_A_ server);
|
||
- return;
|
||
- } else {
|
||
+ if (r == -1 && errno != CONNECT_IN_PROGRESS) {
|
||
+ ERROR("connect");
|
||
+ close_and_free_remote(EV_A_ remote);
|
||
+ close_and_free_server(EV_A_ server);
|
||
+ return;
|
||
+ }
|
||
+ else {
|
||
+ ev_io_start(EV_A_ & remote->send_ctx->io);
|
||
+ ev_timer_start(EV_A_ & remote->send_ctx->watcher);
|
||
+ }
|
||
+ }
|
||
+ else {
|
||
// listen to remote connected event
|
||
ev_io_start(EV_A_ & remote->send_ctx->io);
|
||
ev_timer_start(EV_A_ & remote->send_ctx->watcher);
|
||
@@ -788,6 +1129,27 @@
|
||
}
|
||
}
|
||
|
||
+ //Initialize eBPF dataplane if enabled
|
||
+ /*if (ebpf) {
|
||
+ int r = connect(remotefd, remote_addr, get_sockaddr_len(remote_addr));
|
||
+ if (r == -1 && errno != CONNECT_IN_PROGRESS) {
|
||
+ ERROR("connect");
|
||
+ return;
|
||
+ }
|
||
+
|
||
+ int err = send_ebpf_handshake(remotefd, &destaddr);
|
||
+ if(err < 0) {
|
||
+ LOGE("eBPF handshake failed");
|
||
+ }
|
||
+
|
||
+ err = init_ebpf_connection(remotefd, serverfd);
|
||
+ if(err < 0) {
|
||
+ LOGE("eBPF connection initialization failed");
|
||
+ }
|
||
+
|
||
+ return;
|
||
+ }*/
|
||
+
|
||
server_t *server = new_server(serverfd);
|
||
remote_t *remote = new_remote(remotefd, listener->timeout);
|
||
server->remote = remote;
|
||
@@ -799,14 +1161,18 @@
|
||
remote->addr = remote_addr;
|
||
ev_timer_start(EV_A_ & server->delayed_connect_watcher);
|
||
} else {
|
||
- int r = connect(remotefd, remote_addr, get_sockaddr_len(remote_addr));
|
||
|
||
- if (r == -1 && errno != CONNECT_IN_PROGRESS) {
|
||
- ERROR("connect");
|
||
- close_and_free_remote(EV_A_ remote);
|
||
- close_and_free_server(EV_A_ server);
|
||
- return;
|
||
+ if(!is_open(remotefd)) {
|
||
+ int r = connect(remotefd, remote_addr, get_sockaddr_len(remote_addr));
|
||
+
|
||
+ if (r == -1 && errno != CONNECT_IN_PROGRESS) {
|
||
+ ERROR("connect");
|
||
+ close_and_free_remote(EV_A_ remote);
|
||
+ close_and_free_server(EV_A_ server);
|
||
+ return;
|
||
+ }
|
||
}
|
||
+
|
||
// listen to remote connected event
|
||
ev_io_start(EV_A_ & remote->send_ctx->io);
|
||
ev_timer_start(EV_A_ & remote->send_ctx->watcher);
|
||
@@ -874,6 +1240,7 @@
|
||
{ "fast-open", no_argument, NULL, GETOPT_VAL_FAST_OPEN },
|
||
{ "mtu", required_argument, NULL, GETOPT_VAL_MTU },
|
||
{ "mptcp", no_argument, NULL, GETOPT_VAL_MPTCP },
|
||
+ { "ebpf", no_argument, NULL, GETOPT_VAL_EBPF },
|
||
{ "plugin", required_argument, NULL, GETOPT_VAL_PLUGIN },
|
||
{ "plugin-opts", required_argument, NULL, GETOPT_VAL_PLUGIN_OPTS },
|
||
{ "reuse-port", no_argument, NULL, GETOPT_VAL_REUSE_PORT },
|
||
@@ -902,6 +1269,10 @@
|
||
mptcp = 1;
|
||
LOGI("enable multipath TCP");
|
||
break;
|
||
+ case GETOPT_VAL_EBPF:
|
||
+ ebpf = 1;
|
||
+ LOGI("enable eBPF dataplane");
|
||
+ break;
|
||
case GETOPT_VAL_NODELAY:
|
||
no_delay = 1;
|
||
LOGI("enable TCP no-delay");
|
||
@@ -1042,6 +1413,9 @@
|
||
if (mptcp == 0) {
|
||
mptcp = conf->mptcp;
|
||
}
|
||
+ if(ebpf == 0) {
|
||
+ ebpf = conf->ebpf;
|
||
+ }
|
||
if (no_delay == 0) {
|
||
no_delay = conf->no_delay;
|
||
}
|
||
@@ -1188,6 +1562,15 @@
|
||
}
|
||
listen_ctx.timeout = atoi(timeout);
|
||
listen_ctx.mptcp = mptcp;
|
||
+ if(ebpf) {
|
||
+ int r = init_ebpf_object_buffers(&obufs);
|
||
+ if(r < 0) {
|
||
+ LOGE("Failed to load eBPF objects");
|
||
+ }
|
||
+ else {
|
||
+ memset(connections, 0, 65536 * sizeof(ebpf_conn_t *));
|
||
+ }
|
||
+ }
|
||
|
||
struct ev_loop *loop = EV_DEFAULT;
|
||
|
||
diff -aurN shadowsocks-libev-nocrypto-nocrypto/src/redir.h shadowsocks-libev-nocrypto-ebpf/src/redir.h
|
||
--- shadowsocks-libev-nocrypto-nocrypto/src/redir.h 2018-06-23 14:57:34.000000000 +0200
|
||
+++ shadowsocks-libev-nocrypto-ebpf/src/redir.h 2018-08-14 13:45:18.000000000 +0200
|
||
@@ -31,6 +31,24 @@
|
||
#include "crypto.h"
|
||
#include "jconf.h"
|
||
|
||
+typedef struct obufs
|
||
+{
|
||
+ void *parse_prog;
|
||
+ void *verdict_prog;
|
||
+ int *verdict_port_p;
|
||
+ int parse_prog_size;
|
||
+ int verdict_prog_size;
|
||
+} obufs_t;
|
||
+
|
||
+typedef struct ebpf_conn
|
||
+{
|
||
+ int sockmap_fd;
|
||
+ int parse_prog_fd;
|
||
+ int verdict_prog_fd;
|
||
+ int local_sock;
|
||
+ int remote_sock;
|
||
+} ebpf_conn_t;
|
||
+
|
||
typedef struct listen_ctx {
|
||
ev_io io;
|
||
int remote_num;
|
||
diff -aurN shadowsocks-libev-nocrypto-nocrypto/src/sockmap_parse.c shadowsocks-libev-nocrypto-ebpf/src/sockmap_parse.c
|
||
--- shadowsocks-libev-nocrypto-nocrypto/src/sockmap_parse.c 1970-01-01 01:00:00.000000000 +0100
|
||
+++ shadowsocks-libev-nocrypto-ebpf/src/sockmap_parse.c 2018-08-14 13:45:18.000000000 +0200
|
||
@@ -0,0 +1,19 @@
|
||
+#include <linux/bpf.h>
|
||
+#include "bpf_helpers.h"
|
||
+
|
||
+int _version SEC("version") = 1;
|
||
+
|
||
+#define bpf_printk(fmt, ...) \
|
||
+({ \
|
||
+ char ____fmt[] = fmt; \
|
||
+ bpf_trace_printk(____fmt, sizeof(____fmt), \
|
||
+ ##__VA_ARGS__); \
|
||
+})
|
||
+
|
||
+SEC("sk_skb_parse_prog")
|
||
+int sk_skb_parse(struct __sk_buff *skb)
|
||
+{
|
||
+ return skb->len;
|
||
+}
|
||
+
|
||
+char _license[] SEC("license") = "GPL";
|
||
diff -aurN shadowsocks-libev-nocrypto-nocrypto/src/sockmap_parse.o.ebpf shadowsocks-libev-nocrypto-ebpf/src/sockmap_parse.o.ebpf
|
||
--- shadowsocks-libev-nocrypto-nocrypto/src/sockmap_parse.o.ebpf 1970-01-01 01:00:00.000000000 +0100
|
||
+++ shadowsocks-libev-nocrypto-ebpf/src/sockmap_parse.o.ebpf 2018-08-14 13:45:18.000000000 +0200
|
||
@@ -0,0 +1 @@
|
||
+ELF |