diff --git a/bpf/egress.c b/bpf/egress.c index 419a992..0a94353 100644 --- a/bpf/egress.c +++ b/bpf/egress.c @@ -192,7 +192,8 @@ int egress_handler(struct __sk_buff* skb) { __be32 csum_diff = 0; try_tc(mangle_data(skb, ip_end + sizeof(*udp), &csum_diff, padding)); decl_shot(struct tcphdr, tcp, ip_end, skb); - update_tcp_header(tcp, payload_len, seq, ack_seq, conn_cwnd); + update_tcp_header(tcp, payload_len, seq, ack_seq, + settings->max_window ? 0xffff << CWND_SCALE : conn_cwnd); __u32 csum_off = ip_end + offsetof(struct tcphdr, check); redecl_shot(struct tcphdr, tcp, ip_end, skb); diff --git a/bpf/ingress.c b/bpf/ingress.c index a766f30..9e962a1 100644 --- a/bpf/ingress.c +++ b/bpf/ingress.c @@ -294,8 +294,10 @@ int ingress_handler(struct xdp_md* xdp) { bpf_spin_unlock(&conn->lock); if (flags & TCP_FLAG_SYN && flags & TCP_FLAG_ACK) log_conn(LOG_CONN_ACCEPT, &conn_key); - if (will_send_ctrl_packet) - send_ctrl_packet(&conn_key, flags, seq, ack_seq, flags & TCP_FLAG_RST ? 0 : cwnd); + if (will_send_ctrl_packet) { + __u32 out_cwnd = flags & TCP_FLAG_RST ? 0 : settings->max_window ? 0xffff << CWND_SCALE : cwnd; + send_ctrl_packet(&conn_key, flags, seq, ack_seq, out_cwnd); + } if (unlikely(flags & TCP_FLAG_RST)) { log_destroy(&conn_key, DESTROY_INVALID, cooldown); use_pktbuf(RB_ITEM_FREE_PKTBUF, pktbuf); diff --git a/common/defs.h b/common/defs.h index 0e9086a..409fc51 100644 --- a/common/defs.h +++ b/common/defs.h @@ -221,8 +221,9 @@ struct filter_settings { }; } keepalive, k; }; __s16 padding; + __s16 max_window; }; - __s16 array[7]; + __s16 array[8]; }; }; // clang-format on @@ -238,10 +239,11 @@ static const struct filter_settings DEFAULT_SETTINGS = { .handshake.array = {2, 3}, .keepalive.array = {180, 10, 3, 600}, .padding = 0, + .max_window = true, }; static const struct filter_settings FALLBACK_SETTINGS = { - .array = {-1, -1, -1, -1, -1, -1, -1}, + .array = {-1, -1, -1, -1, -1, -1, -1, -1}, }; static inline void filter_settings_apply(struct filter_settings* local, diff --git a/docs/mimic.1.md b/docs/mimic.1.md index 2755982..8b64ce2 100644 --- a/docs/mimic.1.md +++ b/docs/mimic.1.md @@ -36,6 +36,9 @@ `-p, --padding` : Padding size appended to each packet. Pass 'random' to use random padding. +`-W, --max-window` +: Always use maximum window size in TCP packets. + `-F, --file=PATH` : Load configuration from file @@ -108,7 +111,7 @@ See **/usr/share/doc/mimic/eth0.conf.example** for detailed examples. `log.verbosity` : Controls how much information should be printed. Log level equal to or higher (in number) than log verbosity will be discarded. Both number and string matching log levels are accepted. Number must be greater than or equal to 0. Defaults to info (2). Available levels are: 0 - error (cannot be discarded), 1 - warn, 2 - info, 3 - debug, 4 - trace. -`handshake`, `keepalive`, `padding` +`handshake`, `keepalive`, `padding`, `max_window` : See [**OPTIONS**](#options). `filter` diff --git a/src/config.c b/src/config.c index 26b028c..925368f 100644 --- a/src/config.c +++ b/src/config.c @@ -116,11 +116,11 @@ static int parse_int_seq(char* str, int* nums, size_t len) { return nums_idx; } -__attribute__((unused)) static int parse_bool(const char* str, bool* result) { +static int parse_bool(const char* str, __s16* result) { if (strcmp("true", str) == 0 || strcmp("1", str) == 0) - *result = true; + *result = 1; else if (strcmp("false", str) == 0 || strcmp("0", str) == 0) - *result = false; + *result = 0; else ret(-EINVAL, _("invalid boolean value: '%s'"), str); return 0; @@ -159,6 +159,8 @@ static int parse_setting(const char* k, char* v, struct filter_settings* setting try(parse_keepalive(v, &settings->keepalive)); else if (strcmp("padding", k) == 0) try(parse_padding(v, &settings->padding)); + else if (strcmp("max_window", k) == 0) + try(parse_bool(v, &settings->max_window)); else return 0; return 1; diff --git a/src/run.c b/src/run.c index e052bae..01150d2 100644 --- a/src/run.c +++ b/src/run.c @@ -42,6 +42,7 @@ static const struct argp_option options[] = { {"keepalive", 'k', N_("t:i:r:s"), 0, N_("Controls keepalive mechanism"), 2}, {"padding", 'p', N_("bytes"), 0, N_("Padding size appended to each packet. Pass 'random' to use random padding."), 2}, + {"max-window", 'W', NULL, 0, N_("Always use maximum window size in TCP packets"), 2}, {"file", 'F', N_("PATH"), 0, N_("Load configuration from file"), 3}, {}, }; @@ -77,6 +78,9 @@ static inline error_t args_parse_opt(int key, char* arg, struct argp_state* stat case 'p': try(parse_padding(arg, &args->gsettings.padding)); break; + case 'W': + args->gsettings.max_window = true; + break; case 'F': args->file = arg; break; @@ -356,13 +360,14 @@ static int do_routine(int conns_fd, const char* ifname) { time_diff_sec(tstamp, conn.stale_tstamp) >= conn.settings.keepalive.stale) { reset = remove = true; } else if (conn.settings.keepalive.time > 0 && retry_secs >= conn.settings.keepalive.time) { + __u32 cwnd = conn.settings.max_window ? 0xffff << CWND_SCALE : conn.cwnd; if (conn.settings.keepalive.interval <= 0) { reset = true; } else if (conn.retry_tstamp >= conn.reset_tstamp) { log_conn(LOG_DEBUG, &key, _("sending keepalive")); conn.reset_tstamp = tstamp; conn.keepalive_sent = true; - send_ctrl_packet(&key, TCP_FLAG_ACK, conn.seq - 1, conn.ack_seq, conn.cwnd, ifname); + send_ctrl_packet(&key, TCP_FLAG_ACK, conn.seq - 1, conn.ack_seq, cwnd, ifname); bpf_map_update_elem(conns_fd, &key, &conn, BPF_EXIST | BPF_F_LOCK); } else { int reset_secs = time_diff_sec(tstamp, conn.reset_tstamp); @@ -370,7 +375,7 @@ static int do_routine(int conns_fd, const char* ifname) { reset = true; } else if (reset_secs % conn.settings.keepalive.interval == 0) { log_conn(LOG_DEBUG, &key, _("sending keepalive")); - send_ctrl_packet(&key, TCP_FLAG_ACK, conn.seq - 1, conn.ack_seq, conn.cwnd, ifname); + send_ctrl_packet(&key, TCP_FLAG_ACK, conn.seq - 1, conn.ack_seq, cwnd, ifname); } } } diff --git a/src/show.c b/src/show.c index 4a68b17..1e6efc5 100644 --- a/src/show.c +++ b/src/show.c @@ -62,6 +62,7 @@ int show_overview(int whitelist_fd, struct filter_settings* gs, int log_verbosit fprintf(out, _(", padding random")); else if (gs->padding) fprintf(out, _(", padding %d"), gs->padding); + if (gs->max_window) fprintf(out, _(", max window")); fprintf(out, "\n"); char buf[FILTER_FMT_MAX_LEN]; @@ -97,6 +98,9 @@ int show_overview(int whitelist_fd, struct filter_settings* gs, int log_verbosit else fprintf(out, ",padding=%d", info.settings.padding); } + if (a->max_window != b->max_window) { + fprintf(out, _(",max_window=%s"), info.settings.max_window ? "true" : "false"); + } if (strlen(info.host) != 0) fprintf(out, _(" %s(resolved from %s)"), RESET GRAY, info.host); fprintf(out, RESET "\n"); }