From 0fed925502becfcbbe1a251ed75a4e877e734430 Mon Sep 17 00:00:00 2001 From: sunshouxun Date: Thu, 27 Oct 2022 00:55:21 +0800 Subject: [PATCH 1/2] tcp_comp: added new sockopt for tcp compressed transport. hulk inclusion category: feature bugzilla: https://gitee.com/openeuler/kernel/issues/I4PNEK CVE: NA ------------------------------------------------- added new sockopt for tcp compressed transport. This sockopt is used to turn off the compression or decompression function of part of the tcp connection after the compression transmission function is turned on. Signed-off-by: sunshouxun --- include/linux/tcp.h | 4 +++- include/uapi/linux/tcp.h | 3 ++- net/core/filter.c | 14 ++++++++++++++ net/ipv4/tcp_comp.c | 24 +++++++++++++++++++++--- 4 files changed, 40 insertions(+), 5 deletions(-) diff --git a/include/linux/tcp.h b/include/linux/tcp.h index 5293d504b09b..7cdc6de6cadc 100644 --- a/include/linux/tcp.h +++ b/include/linux/tcp.h @@ -229,7 +229,9 @@ struct tcp_sock { u8 compressed_ack; u8 dup_ack_counter:2, tlp_retrans:1, /* TLP is a retransmission */ - unused:5; + no_comp_tx:1, /* tcp comp tx status */ + no_comp_rx:1, /* tcp comp rx status */ + unused:3; u32 chrono_start; /* Start time in jiffies of a TCP chrono */ u32 chrono_stat[3]; /* Time in jiffies for chrono_stat stats */ u8 chrono_type:2, /* current chronograph type */ diff --git a/include/uapi/linux/tcp.h b/include/uapi/linux/tcp.h index 62db78b9c1a0..c87ae6a09f4f 100644 --- a/include/uapi/linux/tcp.h +++ b/include/uapi/linux/tcp.h @@ -128,7 +128,8 @@ enum { #define TCP_CM_INQ TCP_INQ #define TCP_TX_DELAY 37 /* delay outgoing packets by XX usec */ - +#define TCP_NO_COMP_TX 38 /* controls whether tcp compression tx is enabled */ +#define TCP_NO_COMP_RX 39 /* controls whether tcp compression rx is enabled */ #define TCP_REPAIR_ON 1 #define TCP_REPAIR_OFF 0 diff --git a/net/core/filter.c b/net/core/filter.c index 51514e41025e..653dba4893e5 100644 --- a/net/core/filter.c +++ b/net/core/filter.c @@ -4903,6 +4903,20 @@ static int _bpf_setsockopt(struct sock *sk, int level, int optname, tp->notsent_lowat = val; sk->sk_write_space(sk); break; +#if IS_ENABLED(CONFIG_TCP_COMP) + case TCP_NO_COMP_TX: + if (val > 1 || val < 0) + ret = -EINVAL; + else + tp->no_comp_tx = val; + break; + case TCP_NO_COMP_RX: + if (val > 1 || val < 0) + ret = -EINVAL; + else + tp->no_comp_rx = val; + break; +#endif default: ret = -EINVAL; } diff --git a/net/ipv4/tcp_comp.c b/net/ipv4/tcp_comp.c index ffddbd6d3a6b..f93a27047dba 100644 --- a/net/ipv4/tcp_comp.c +++ b/net/ipv4/tcp_comp.c @@ -24,6 +24,8 @@ unsigned long *sysctl_tcp_compression_ports = tcp_compression_ports; int sysctl_tcp_compression_local __read_mostly; static struct proto tcp_prot_override; +static struct proto tcp_prot_override_send; +static struct proto tcp_prot_override_recv; struct tcp_comp_context_tx { ZSTD_CStream *cstream; @@ -824,13 +826,22 @@ void tcp_init_compression(struct sock *sk) ctx->sk_write_space = sk->sk_write_space; ctx->sk_proto = sk->sk_prot; - WRITE_ONCE(sk->sk_prot, &tcp_prot_override); - sk->sk_write_space = tcp_comp_write_space; + + if (!tp->no_comp_tx && !tp->no_comp_rx) + WRITE_ONCE(sk->sk_prot, &tcp_prot_override); + else if (!tp->no_comp_tx) + WRITE_ONCE(sk->sk_prot, &tcp_prot_override_send); + else if (!tp->no_comp_rx) + WRITE_ONCE(sk->sk_prot, &tcp_prot_override_recv); + + if (!tp->no_comp_tx) + sk->sk_write_space = tcp_comp_write_space; rcu_assign_pointer(icsk->icsk_ulp_data, ctx); sock_set_flag(sk, SOCK_COMP); - comp_setup_strp(sk, ctx); + if (!tp->no_comp_rx) + comp_setup_strp(sk, ctx); } static void tcp_comp_context_tx_free(struct tcp_comp_context *ctx) @@ -896,5 +907,12 @@ int tcp_comp_init(void) tcp_prot_override.recvmsg = tcp_comp_recvmsg; tcp_prot_override.stream_memory_read = comp_stream_read; + tcp_prot_override_send = tcp_prot; + tcp_prot_override_send.sendmsg = tcp_comp_sendmsg; + + tcp_prot_override_recv = tcp_prot; + tcp_prot_override_recv.recvmsg = tcp_comp_recvmsg; + tcp_prot_override_recv.stream_memory_read = comp_stream_read; + return 0; } -- Gitee From 39ac1bdd078c7f5144e60f3f7c718f0ffe60f0c2 Mon Sep 17 00:00:00 2001 From: sunshouxun Date: Thu, 27 Oct 2022 01:07:52 +0800 Subject: [PATCH 2/2] tcp_comp: Use bpf program to realize port-based open or close network program compression transmission function. hulk inclusion category: feature bugzilla: https://gitee.com/openeuler/kernel/issues/I4PNEK CVE: NA ------------------------------------------------- Use the bpf program to control the TCP_NO_COMP_TX and TCP_NO_COMP_RX sockopt options during the tcp three-way handshake. Turn on or off the compressed transmission function of the network program based on the port. Signed-off-by: sunshouxun --- samples/bpf/Makefile | 1 + samples/bpf/tcp_comp_option.h | 152 ++++++++ samples/bpf/tcp_comp_option_kern.c | 534 +++++++++++++++++++++++++++++ 3 files changed, 687 insertions(+) create mode 100644 samples/bpf/tcp_comp_option.h create mode 100644 samples/bpf/tcp_comp_option_kern.c diff --git a/samples/bpf/Makefile b/samples/bpf/Makefile index aeebf5d12f32..1e325dc1fd81 100644 --- a/samples/bpf/Makefile +++ b/samples/bpf/Makefile @@ -153,6 +153,7 @@ always-y += tcp_bufs_kern.o always-y += tcp_cong_kern.o always-y += tcp_iw_kern.o always-y += tcp_clamp_kern.o +always-y += tcp_comp_option_kern.o always-y += tcp_basertt_kern.o always-y += tcp_tos_reflect_kern.o always-y += tcp_dumpstats_kern.o diff --git a/samples/bpf/tcp_comp_option.h b/samples/bpf/tcp_comp_option.h new file mode 100644 index 000000000000..f7ebd1b22afa --- /dev/null +++ b/samples/bpf/tcp_comp_option.h @@ -0,0 +1,152 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* Copyright (c) 2022 sunshouxun */ + +#ifndef _BPF_TCP_COMP_H +#define _BPF_TCP_COMP_H + +struct bpf_comp_option { + __u8 flags; + __u8 no_comp_tx; + __u8 no_comp_rx; +} __attribute__((packed)); + +enum { + OPTION_RESEND, + OPTION_NO_COMP_TX, + OPTION_NO_COMP_RX, + __NR_OPTION_FLAGS, +}; + +#define OPTION_F_RESEND (1 << OPTION_RESEND) +#define OPTION_F_NO_COMP_TX (1 << OPTION_NO_COMP_TX) +#define OPTION_F_NO_COMP_RX (1 << OPTION_NO_COMP_RX) +#define OPTION_MASK ((1 << __NR_OPTION_FLAGS) - 1) + +#define TEST_OPTION_FLAGS(flags, option) (1 & ((flags) >> (option))) +#define SET_OPTION_FLAGS(flags, option) ((flags) |= (1 << (option))) + +/* Store in bpf_sk_storage */ +struct hdr_stg { + bool active; + bool resend_syn; /* active side only */ + bool syncookie; /* passive side only */ + bool fastopen; /* passive side only */ +}; + +struct linum_err { + unsigned int linum; + int err; +}; + +#define TCPHDR_FIN 0x01 +#define TCPHDR_SYN 0x02 +#define TCPHDR_RST 0x04 +#define TCPHDR_PSH 0x08 +#define TCPHDR_ACK 0x10 +#define TCPHDR_URG 0x20 +#define TCPHDR_ECE 0x40 +#define TCPHDR_CWR 0x80 +#define TCPHDR_SYNACK (TCPHDR_SYN | TCPHDR_ACK) + +#define TCPOPT_EOL 0 +#define TCPOPT_NOP 1 +#define TCPOPT_WINDOW 3 +#define TCPOPT_EXP 254 + +#define TCP_BPF_EXPOPT_BASE_LEN 4 +#define MAX_TCP_HDR_LEN 60 +#define MAX_TCP_OPTION_SPACE 40 + +#ifdef BPF_PROG_TCP_COMP + +#define CG_OK 1 +#define CG_ERR 0 + +#ifndef SOL_TCP +#define SOL_TCP 6 +#endif + +struct tcp_exprm_opt { + __u8 kind; + __u8 len; + __u16 magic; + union { + __u8 data[4]; + __u32 data32; + }; +} __attribute__((packed)); + +struct tcp_opt { + __u8 kind; + __u8 len; + union { + __u8 data[4]; + __u32 data32; + }; +} __attribute__((packed)); + +struct { + __uint(type, BPF_MAP_TYPE_HASH); + __uint(max_entries, 2); + __type(key, int); + __type(value, struct linum_err); +} lport_linum_map SEC(".maps"); + +static inline unsigned int tcp_hdrlen(const struct tcphdr *th) +{ + return th->doff << 2; +} + +static inline __u8 skops_tcp_flags(const struct bpf_sock_ops *skops) +{ + return skops->skb_tcp_flags; +} + +static inline void clear_hdr_cb_flags(struct bpf_sock_ops *skops) +{ + bpf_sock_ops_cb_flags_set(skops, + skops->bpf_sock_ops_cb_flags & + ~(BPF_SOCK_OPS_PARSE_UNKNOWN_HDR_OPT_CB_FLAG | + BPF_SOCK_OPS_WRITE_HDR_OPT_CB_FLAG)); +} + +static inline void set_hdr_cb_flags(struct bpf_sock_ops *skops, __u32 extra) +{ + bpf_sock_ops_cb_flags_set(skops, + skops->bpf_sock_ops_cb_flags | + BPF_SOCK_OPS_PARSE_UNKNOWN_HDR_OPT_CB_FLAG | + BPF_SOCK_OPS_WRITE_HDR_OPT_CB_FLAG | + extra); +} +static inline void +clear_parse_all_hdr_cb_flags(struct bpf_sock_ops *skops) +{ + bpf_sock_ops_cb_flags_set(skops, + skops->bpf_sock_ops_cb_flags & + ~BPF_SOCK_OPS_PARSE_ALL_HDR_OPT_CB_FLAG); +} + +static inline void +set_parse_all_hdr_cb_flags(struct bpf_sock_ops *skops) +{ + bpf_sock_ops_cb_flags_set(skops, + skops->bpf_sock_ops_cb_flags | + BPF_SOCK_OPS_PARSE_ALL_HDR_OPT_CB_FLAG); +} + +#define RET_CG_ERR(__err) ({ \ + struct linum_err __linum_err; \ + int __lport; \ + \ + __linum_err.linum = __LINE__; \ + __linum_err.err = __err; \ + __lport = skops->local_port; \ + bpf_map_update_elem(&lport_linum_map, &__lport, &__linum_err, BPF_NOEXIST); \ + clear_hdr_cb_flags(skops); \ + clear_parse_all_hdr_cb_flags(skops); \ + return CG_ERR; \ +}) + +#endif /* BPF_PROG_TCP_COMP */ + +#endif /* _BPF_TCP_COMP_H */ \ No newline at end of file diff --git a/samples/bpf/tcp_comp_option_kern.c b/samples/bpf/tcp_comp_option_kern.c new file mode 100644 index 000000000000..c30adcd42a8f --- /dev/null +++ b/samples/bpf/tcp_comp_option_kern.c @@ -0,0 +1,534 @@ +// SPDX-License-Identifier: GPL-2.0 +/* Copyright (c) 2022 sunshouxun */ + +#include +#include +#include +#include +#include +#define BPF_PROG_TCP_COMP +#include "tcp_comp_option.h" + +#ifndef sizeof_field +#define sizeof_field(TYPE, MEMBER) sizeof((((TYPE *)0)->MEMBER)) +#endif + +__u8 option_kind = TCPOPT_EXP; +__u16 option_magic = 0xeB9F; + +int port = 1234; + +static struct bpf_comp_option passive_synack_out = { + .flags = 6, + .no_comp_tx = 1, + .no_comp_rx = 1, +}; + +static struct bpf_comp_option active_syn_out = { + .flags = 6, + .no_comp_tx = 1, + .no_comp_rx = 1, +}; + +struct { + __uint(type, BPF_MAP_TYPE_SK_STORAGE); + __uint(map_flags, BPF_F_NO_PREALLOC); + __type(key, int); + __type(value, struct hdr_stg); +} hdr_stg_map SEC(".maps"); + +static bool skops_want_cookie(const struct bpf_sock_ops *skops) +{ + return skops->args[0] == BPF_WRITE_HDR_TCP_SYNACK_COOKIE; +} + +static __u8 option_total_len(__u8 flags) +{ + __u8 i, len = 1; /* +1 for flags */ + + if (!flags) + return 0; + + /* RESEND bit does not use a byte */ + for (i = OPTION_RESEND + 1; i < __NR_OPTION_FLAGS; i++) + len += !!TEST_OPTION_FLAGS(flags, i); + + if (option_kind == TCPOPT_EXP) + return len + TCP_BPF_EXPOPT_BASE_LEN; + else + return len + 2; /* +1 kind, +1 kind-len */ +} + +static void write_comp_option(const struct bpf_comp_option *comp_opt, + __u8 *data) +{ + __u8 offset = 0; + + data[offset++] = comp_opt->flags; + if (TEST_OPTION_FLAGS(comp_opt->flags, OPTION_NO_COMP_TX)){ + data[offset++] = comp_opt->no_comp_tx; + } + + if (TEST_OPTION_FLAGS(comp_opt->flags, OPTION_NO_COMP_RX)){ + data[offset++] = comp_opt->no_comp_rx; + } +} + +static int store_option(struct bpf_sock_ops *skops, + const struct bpf_comp_option *comp_opt) +{ + union { + struct tcp_exprm_opt exprm; + struct tcp_opt regular; + } write_opt; + int err; + + if (option_kind == TCPOPT_EXP) { + write_opt.exprm.kind = TCPOPT_EXP; + write_opt.exprm.len = option_total_len(comp_opt->flags); + write_opt.exprm.magic = __bpf_htons(option_magic); + write_opt.exprm.data32 = 0; + write_comp_option(comp_opt, write_opt.exprm.data); + err = bpf_store_hdr_opt(skops, &write_opt.exprm, + sizeof(write_opt.exprm), 0); + } else { + write_opt.regular.kind = option_kind; + write_opt.regular.len = option_total_len(comp_opt->flags); + write_opt.regular.data32 = 0; + write_comp_option(comp_opt, write_opt.regular.data); + err = bpf_store_hdr_opt(skops, &write_opt.regular, + sizeof(write_opt.regular), 0); + } + + if (err) + RET_CG_ERR(err); + + return CG_OK; +} + +static int parse_comp_option(struct bpf_comp_option *opt, const __u8 *start) +{ + opt->flags = *start++; + + + if (TEST_OPTION_FLAGS(opt->flags, OPTION_NO_COMP_TX)) + opt->no_comp_tx = *start++; + + if (TEST_OPTION_FLAGS(opt->flags, OPTION_NO_COMP_RX)) + opt->no_comp_rx = *start++; + + return 0; +} + +static int load_option(struct bpf_sock_ops *skops, + struct bpf_comp_option *comp_opt, bool from_syn) +{ + union { + struct tcp_exprm_opt exprm; + struct tcp_opt regular; + } search_opt; + int ret, load_flags = from_syn ? BPF_LOAD_HDR_OPT_TCP_SYN : 0; + + if (option_kind == TCPOPT_EXP) { + search_opt.exprm.kind = TCPOPT_EXP; + search_opt.exprm.len = 4; + search_opt.exprm.magic = __bpf_htons(option_magic); + search_opt.exprm.data32 = 0; + ret = bpf_load_hdr_opt(skops, &search_opt.exprm, + sizeof(search_opt.exprm), load_flags); + if (ret < 0) + return ret; + return parse_comp_option(comp_opt, search_opt.exprm.data); + } else { + search_opt.regular.kind = option_kind; + search_opt.regular.len = 0; + search_opt.regular.data32 = 0; + ret = bpf_load_hdr_opt(skops, &search_opt.regular, + sizeof(search_opt.regular), load_flags); + if (ret < 0) + return ret; + return parse_comp_option(comp_opt, search_opt.regular.data); + } +} + +static int synack_opt_len(struct bpf_sock_ops *skops) +{ + struct bpf_comp_option comp_opt = {}; + __u8 optlen; + int err; + + if (!passive_synack_out.flags) + return CG_OK; + + err = load_option(skops, &comp_opt, true); + + /* bpf_comp_option is not found */ + if (err) + RET_CG_ERR(err); + + optlen = option_total_len(passive_synack_out.flags); + if (optlen) { + err = bpf_reserve_hdr_opt(skops, optlen, 0); + if (err) + RET_CG_ERR(err); + } + + return CG_OK; +} + +static int write_synack_opt(struct bpf_sock_ops *skops) +{ + struct bpf_comp_option opt; + + if (!passive_synack_out.flags) + /* We should not even be called since no header + * space has been reserved. + */ + RET_CG_ERR(0); + + opt = passive_synack_out; + if (skops_want_cookie(skops)) + SET_OPTION_FLAGS(opt.flags, OPTION_RESEND); + + return store_option(skops, &opt); +} + +static int syn_opt_len(struct bpf_sock_ops *skops) +{ + __u8 optlen; + int err; + + if (!active_syn_out.flags) + return CG_OK; + + optlen = option_total_len(active_syn_out.flags); + if (optlen) { + err = bpf_reserve_hdr_opt(skops, optlen, 0); + if (err) + RET_CG_ERR(err); + } + + return CG_OK; +} + +static int write_syn_opt(struct bpf_sock_ops *skops) +{ + if (!active_syn_out.flags) + RET_CG_ERR(0); + + return store_option(skops, &active_syn_out); +} + +static int resend_in_ack(struct bpf_sock_ops *skops) +{ + struct hdr_stg *hdr_stg; + + if (!skops->sk) + return -1; + + hdr_stg = bpf_sk_storage_get(&hdr_stg_map, skops->sk, NULL, 0); + if (!hdr_stg) + return -1; + + return !!hdr_stg->resend_syn; +} + +static int nodata_opt_len(struct bpf_sock_ops *skops) +{ + int resend; + + resend = resend_in_ack(skops); + if (resend < 0) + RET_CG_ERR(0); + + if (resend) + return syn_opt_len(skops); + + return CG_OK; +} + +static int write_nodata_opt(struct bpf_sock_ops *skops) +{ + int resend; + + resend = resend_in_ack(skops); + if (resend < 0) + RET_CG_ERR(0); + + if (resend) + return write_syn_opt(skops); + + return CG_OK; +} + +static int data_opt_len(struct bpf_sock_ops *skops) +{ + /* Same as the nodata version. Mostly to show + * an example usage on skops->skb_len. + */ + return nodata_opt_len(skops); +} + +static int write_data_opt(struct bpf_sock_ops *skops) +{ + return write_nodata_opt(skops); +} + +static int handle_hdr_opt_len(struct bpf_sock_ops *skops) +{ + __u8 tcp_flags = skops_tcp_flags(skops); + + if ((tcp_flags & TCPHDR_SYNACK) == TCPHDR_SYNACK) + return synack_opt_len(skops); + + if (tcp_flags & TCPHDR_SYN) + return syn_opt_len(skops); + + if (skops->skb_len) + return data_opt_len(skops); + + return nodata_opt_len(skops); +} + +static int handle_write_hdr_opt(struct bpf_sock_ops *skops) +{ + __u8 tcp_flags = skops_tcp_flags(skops); + struct tcphdr *th; + + if ((tcp_flags & TCPHDR_SYNACK) == TCPHDR_SYNACK) + return write_synack_opt(skops); + + if (tcp_flags & TCPHDR_SYN) + return write_syn_opt(skops); + + th = skops->skb_data; + if (th + 1 > skops->skb_data_end) + RET_CG_ERR(0); + + if (skops->skb_len > tcp_hdrlen(th)) + return write_data_opt(skops); + + return write_nodata_opt(skops); +} + +static int set_no_comp_tx(struct bpf_sock_ops *skops, __u32 no_comp_tx) +{ + return bpf_setsockopt(skops, SOL_TCP, TCP_NO_COMP_TX, + &no_comp_tx, sizeof(no_comp_tx)); +} + + +static int set_no_comp_rx(struct bpf_sock_ops *skops, __u32 no_comp_rx) +{ + return bpf_setsockopt(skops, SOL_TCP, TCP_NO_COMP_RX, + &no_comp_rx, sizeof(no_comp_rx)); +} + +// client side +static int handle_active_estab(struct bpf_sock_ops *skops) +{ + struct hdr_stg init_stg = { + .active = true, + }; + + struct bpf_comp_option active_estab_in = {}; + int err; + + err = load_option(skops, &active_estab_in, false); + if (err) + RET_CG_ERR(err); + + init_stg.resend_syn = TEST_OPTION_FLAGS(active_estab_in.flags, + OPTION_RESEND); + if (!skops->sk || !bpf_sk_storage_get(&hdr_stg_map, skops->sk, + &init_stg, + BPF_SK_STORAGE_GET_F_CREATE)) + RET_CG_ERR(0); + + if (init_stg.resend_syn) + /* Don't clear the write_hdr cb now because + * the ACK may get lost and retransmit may + * be needed. + * + * PARSE_ALL_HDR cb flag is set to learn if this + * resend_syn option has received by the peer. + * + * The header option will be resent until a valid + * packet is received at handle_parse_hdr() + * and all hdr cb flags will be cleared in + * handle_parse_hdr(). + */ + set_parse_all_hdr_cb_flags(skops); + else + /* No options will be written from now */ + clear_hdr_cb_flags(skops); + + // use map data + if (active_syn_out.no_comp_tx == 1 && active_estab_in.no_comp_rx == 1) { + err = set_no_comp_tx(skops, active_syn_out.no_comp_tx); + if (err) + RET_CG_ERR(err); + } + + if (active_syn_out.no_comp_rx == 1 && active_estab_in.no_comp_tx == 1) { + err = set_no_comp_rx(skops, active_syn_out.no_comp_rx); + if (err) + RET_CG_ERR(err); + } + + return CG_OK; +} + +// server side +static int handle_passive_estab(struct bpf_sock_ops *skops) +{ + struct hdr_stg init_stg = {}; + struct bpf_comp_option passive_estab_in = {}; + struct tcphdr *th; + + int err; + + err = load_option(skops, &passive_estab_in, true); + + if (err == -2) { + /* -2 is No such file or directory + * saved_syn is not found. It was in syncookie mode. + * We have asked the active side to resend the options + * in ACK, so try to find the bpf_comp_option from ACK now. + */ + err = load_option(skops, &passive_estab_in, false); + init_stg.syncookie = true; + } + + /* ENOMSG: The bpf_comp_option is not found which is fine. + * Bail out now for all other errors. + */ + if (err) + RET_CG_ERR(err); + + th = skops->skb_data; + if (th + 1 > skops->skb_data_end) + RET_CG_ERR(0); + + if (th->syn) { + /* Fastopen */ + + /* Cannot clear cb_flags to stop write_hdr cb. + * synack is not sent yet for fast open. + * Even it was, the synack may need to be retransmitted. + * + * PARSE_ALL_HDR cb flag is set to learn + * if synack has reached the peer. + * All cb_flags will be cleared in handle_parse_hdr(). + */ + set_parse_all_hdr_cb_flags(skops); + init_stg.fastopen = true; + } else { + /* No options will be written from now */ + clear_hdr_cb_flags(skops); + } + + if (!skops->sk || + !bpf_sk_storage_get(&hdr_stg_map, skops->sk, &init_stg, + BPF_SK_STORAGE_GET_F_CREATE)) + RET_CG_ERR(0); + + + if (passive_synack_out.no_comp_tx == 1 && passive_estab_in.no_comp_rx == 1) { + err = set_no_comp_tx(skops, passive_synack_out.no_comp_tx); + if (err) + RET_CG_ERR(err); + } + + if (passive_synack_out.no_comp_rx == 1 && passive_estab_in.no_comp_tx == 1) { + err = set_no_comp_rx(skops, passive_synack_out.no_comp_rx); + if (err) + RET_CG_ERR(err); + } + + return CG_OK; +} + +static int handle_parse_hdr(struct bpf_sock_ops *skops) +{ + struct hdr_stg *hdr_stg; + struct tcphdr *th; + + if (!skops->sk) + RET_CG_ERR(0); + + th = skops->skb_data; + if (th + 1 > skops->skb_data_end) + RET_CG_ERR(0); + + hdr_stg = bpf_sk_storage_get(&hdr_stg_map, skops->sk, NULL, 0); + if (!hdr_stg) + RET_CG_ERR(0); + + if (hdr_stg->resend_syn || hdr_stg->fastopen) { + /* The PARSE_ALL_HDR cb flag was turned on + * to ensure that the previously written + * options have reached the peer. + * Those previously written option includes: + * - Active side: resend_syn in ACK during syncookie + * or + * - Passive side: SYNACK during fastopen + * + * A valid packet has been received here after + * the 3WHS, so the PARSE_ALL_HDR cb flag + * can be cleared now. + */ + clear_parse_all_hdr_cb_flags(skops); + + /* Active side resent the syn option in ACK + * because the server was in syncookie mode. + * A valid packet has been received, so + * the SYNACK has reached the peer. + * Clear header cb flags if there is no more + * option to send. + * + * or + * + * Passive side was in fastopen. + * A valid packet has been received, so + * clear header cb flags if there is no + * more option to send. + */ + clear_hdr_cb_flags(skops); + } + + return CG_OK; +} + +SEC("sockops") +int bpf_tcp_comp_option(struct bpf_sock_ops *skops) +{ + int true_val = 1; + if(port != bpf_ntohl(skops->remote_port) && port != skops->local_port) { + return 0; + } + switch (skops->op) { + case BPF_SOCK_OPS_TCP_LISTEN_CB: + bpf_setsockopt(skops, SOL_TCP, TCP_SAVE_SYN, + &true_val, sizeof(true_val)); + set_hdr_cb_flags(skops, BPF_SOCK_OPS_STATE_CB_FLAG); + break; + case BPF_SOCK_OPS_TCP_CONNECT_CB: + set_hdr_cb_flags(skops, 0); + break; + case BPF_SOCK_OPS_PARSE_HDR_OPT_CB: + return handle_parse_hdr(skops); + case BPF_SOCK_OPS_HDR_OPT_LEN_CB: + return handle_hdr_opt_len(skops); + case BPF_SOCK_OPS_WRITE_HDR_OPT_CB: + return handle_write_hdr_opt(skops); + case BPF_SOCK_OPS_PASSIVE_ESTABLISHED_CB: + return handle_passive_estab(skops); + case BPF_SOCK_OPS_ACTIVE_ESTABLISHED_CB: + return handle_active_estab(skops); + } + + return CG_OK; +} + +char _license[] SEC("license") = "GPL"; \ No newline at end of file -- Gitee