1
0
Fork 0
mirror of https://github.com/Ysurac/openmptcprouter-feeds.git synced 2025-02-15 03:51:51 +00:00
openmptcprouter-feeds/shadowsocks-libev/patches/030-eBPF.patch

885 lines
30 KiB
Diff
Raw Normal View History

2018-12-31 13:52:47 +00:00
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@@a<00>GPL/".text_versionsk_skb_parse_progsk_skb_parse_license.strtab.symtab8<00>H@@P0T@X`
\ Pas de fin de ligne à la fin du fichier
diff -aurN shadowsocks-libev-nocrypto-nocrypto/src/sockmap_verdict.c shadowsocks-libev-nocrypto-ebpf/src/sockmap_verdict.c
--- shadowsocks-libev-nocrypto-nocrypto/src/sockmap_verdict.c 1970-01-01 01:00:00.000000000 +0100
+++ shadowsocks-libev-nocrypto-ebpf/src/sockmap_verdict.c 2018-08-14 13:45:18.000000000 +0200
@@ -0,0 +1,22 @@
+#include <linux/bpf.h>
+#include "bpf_helpers.h"
+
+int _version SEC("version") = 1;
+
+struct bpf_map_def SEC("maps") redirect_map = {
+ .type = BPF_MAP_TYPE_SOCKMAP,
+ .key_size = sizeof(int),
+ .value_size = sizeof(int),
+ .max_entries = 2,
+};
+
+SEC("sk_skb_verdict_prog")
+int sk_skb_verdict(struct __sk_buff *skb)
+{
+ if(skb->local_port == 0xfcfcfcfc)
+ return bpf_sk_redirect_map(skb, &redirect_map, 0, 0);
+
+ return bpf_sk_redirect_map(skb, &redirect_map, 1, 0);
+}
+
+char _license[] SEC("license") = "GPL";
diff -aurN shadowsocks-libev-nocrypto-nocrypto/src/sockmap_verdict.o.ebpf shadowsocks-libev-nocrypto-ebpf/src/sockmap_verdict.o.ebpf
--- shadowsocks-libev-nocrypto-nocrypto/src/sockmap_verdict.o.ebpf 1970-01-01 01:00:00.000000000 +0100
+++ shadowsocks-libev-nocrypto-ebpf/src/sockmap_verdict.o.ebpf 2018-08-14 13:45:18.000000000 +0200
@@ -0,0 +1 @@
+ELF@@ a<12><00><><EFBFBD><EFBFBD>]2<00><00><00><00>4<00>GPLi@bXI( @.textsk_skb_verdictmapsredirect_map_version.relsk_skb_verdict_prog_license.strtab.symtabLBB0_3LBB0_2R<00>p@5@p1 <00> )<00><00>J<00>Z<00><00>
\ Pas de fin de ligne à la fin du fichier