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 +#include +#include +#include + #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 +#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•GPL/".text_versionsk_skb_parse_progsk_skb_parse_license.strtab.symtab8¸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 +#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ˆüüüü]2···…4•GPLi@bXI( @.textsk_skb_verdictmapsredirect_map_version.relsk_skb_verdict_prog_license.strtab.symtabLBB0_3LBB0_2R p@5@p1 € )°´JÐZب \ Pas de fin de ligne à la fin du fichier