Skip to content

Commit

Permalink
cli: add padding settings
Browse files Browse the repository at this point in the history
  • Loading branch information
hack3ric committed Sep 30, 2024
1 parent e05d3af commit 058185b
Show file tree
Hide file tree
Showing 7 changed files with 102 additions and 76 deletions.
9 changes: 5 additions & 4 deletions bpf/egress.c
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,8 @@ static inline int mangle_data(struct __sk_buff* skb, __u16 offset, __be32* csum_
padding_len = min(padding_len, MAX_PADDING_LEN);
if (padding_len < 2) padding_len = 1;
if (padding_len < 3) padding_len = 2;
__builtin_memset(buf, ';', min(MAX_PADDING_LEN, sizeof(buf)));
for (int i = 0; i < padding_len / 4 + !!(padding_len % 4); i++)
((__u32*)buf)[i] = bpf_get_prandom_u32();
*csum_diff = bpf_csum_diff(NULL, 0, (__be32*)buf, padding_len, *csum_diff);
try_shot(bpf_skb_store_bytes(skb, offset + TCP_UDP_HEADER_DIFF, buf, padding_len, 0));
}
Expand Down Expand Up @@ -116,7 +117,7 @@ int egress_handler(struct __sk_buff* skb) {
if (likely(conn->state == CONN_ESTABLISHED)) {
seq = conn->seq;
ack_seq = conn->ack_seq;
conn->seq += payload_len + conn->padding_len;
conn->seq += payload_len + conn->settings.padding;
} else {
if (conn->state == CONN_IDLE) {
__u32 cooldown = conn_cooldown(conn);
Expand Down Expand Up @@ -159,7 +160,7 @@ int egress_handler(struct __sk_buff* skb) {
conn_cwnd = conn->cwnd;
bpf_spin_unlock(&conn->lock);

size_t reserve_len = TCP_UDP_HEADER_DIFF + conn->padding_len;
size_t reserve_len = TCP_UDP_HEADER_DIFF + conn->settings.padding;
if (ipv4) {
__be16 old_len = ipv4->tot_len;
__be16 new_len = htons(ntohs(old_len) + reserve_len);
Expand All @@ -175,7 +176,7 @@ int egress_handler(struct __sk_buff* skb) {
}

__be32 csum_diff = 0;
try_tc(mangle_data(skb, ip_end + sizeof(*udp), &csum_diff, conn->padding_len));
try_tc(mangle_data(skb, ip_end + sizeof(*udp), &csum_diff, conn->settings.padding));
decl_shot(struct tcphdr, tcp, ip_end, skb);
update_tcp_header(tcp, payload_len, seq, ack_seq, conn_cwnd);

Expand Down
4 changes: 2 additions & 2 deletions bpf/ingress.c
Original file line number Diff line number Diff line change
Expand Up @@ -303,7 +303,7 @@ int ingress_handler(struct xdp_md* xdp) {
}
if (will_drop) return XDP_DROP;

size_t reserve_len = TCP_UDP_HEADER_DIFF + conn->padding_len;
size_t reserve_len = TCP_UDP_HEADER_DIFF + conn->settings.padding;
if (ipv4) {
__be16 old_len = ipv4->tot_len;
__be16 new_len = htons(ntohs(old_len) - reserve_len);
Expand All @@ -325,7 +325,7 @@ int ingress_handler(struct xdp_md* xdp) {

__be32 csum_diff = 0;
try_xdp(restore_data(xdp, ip_end + sizeof(*tcp), ip_end + ip_payload_len, &csum_diff,
conn->padding_len));
conn->settings.padding));
decl_drop(struct udphdr, udp, ip_end, xdp);
csum += u32_fold(ntohl(csum_diff));

Expand Down
25 changes: 15 additions & 10 deletions common/defs.h
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,8 @@
#define max(x, y) ((x) < (y) ? (y) : (x))
#define cmp(x, y) ((x) > (y) - (x) < (y))

#define sizeof_array(arr) (sizeof(arr) / sizeof(arr[0]))

#define swap(x, y) \
({ \
typeof(x) t = x; \
Expand Down Expand Up @@ -202,22 +204,23 @@ struct filter {
struct filter_settings {
union {
struct {
union { struct {
union { struct filter_handshake {
union {
struct { __s16 interval, retry; };
struct { __s16 i, r; };
__s16 array[2];
};
} handshake, h; };
union { struct {
union { struct filter_keepalive {
union {
struct { __s16 time, interval, retry, stale; };
struct { __s16 t, i, r, s; };
__s16 array[4];
};
} keepalive, k; };
__s16 padding;
};
__s16 array[6];
__s16 array[7];
};
};
// clang-format on
Expand All @@ -232,15 +235,16 @@ struct filter_info {
static const struct filter_settings DEFAULT_SETTINGS = {
.handshake.array = {2, 3},
.keepalive.array = {180, 10, 3, 600},
.padding = 0,
};

static const struct filter_settings FALLBACK_SETTINGS = {
.array = {-1, -1, -1, -1, -1, -1},
.array = {-1, -1, -1, -1, -1, -1, -1},
};

static inline void filter_settings_apply(struct filter_settings* local,
const struct filter_settings* global) {
for (int i = 0; i < 6; i++)
for (int i = 0; i < sizeof_array(local->array); i++)
if (local->array[i] < 0) local->array[i] = global->array[i];
}

Expand All @@ -260,12 +264,14 @@ struct connection {
CONN_SYN_SENT,
CONN_SYN_RECV,
CONN_ESTABLISHED,
} state : 2;
} state : 3;
bool keepalive_sent : 1;
__u8 padding_len : 5;
__u8 cooldown_mul;
__u16 peer_mss;
__u8 cooldown_mul : 4;
__u32 : 24;
};
struct {
struct filter_settings settings;
__u16 peer_mss;
};

__u64 retry_tstamp, reset_tstamp, stale_tstamp;
Expand All @@ -276,7 +282,6 @@ static __always_inline struct connection conn_init(struct filter_settings* setti
struct connection conn = {.cwnd = INIT_CWND};
__builtin_memcpy(&conn.settings, settings, sizeof(*settings));
conn.retry_tstamp = conn.reset_tstamp = conn.stale_tstamp = tstamp;
conn.padding_len = 0; // TODO: expose padding
return conn;
}

Expand Down
72 changes: 41 additions & 31 deletions src/config.c
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
#include <netdb.h>
#include <netinet/in.h>
#include <stdbool.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
Expand Down Expand Up @@ -75,15 +76,27 @@ static int parse_host_port(char* str, char** host, __u16* port) {
return 0;
}

static int parse_int(const char* str, int* dest) {
static int parse_int(const char* str, int* dest, int min, int max) {
if (min > max) return -EINVAL;
char* endptr;
long parsed = strtol(str, &endptr, 10);
if (*str == '\0' || *endptr != '\0') ret(-EINVAL, _("invalid integer: '%s'"), str);
if (parsed > INT_MAX || parsed < INT_MIN) ret(-E2BIG, _("integer out of range: '%ld'"), parsed);
if (parsed < min || parsed > max) ret(-E2BIG, _("integer out of range: '%ld'"), parsed);
*dest = parsed;
return 0;
}

static inline int parse_int_any(const char* str, int* dest) {
return parse_int(str, dest, INT_MIN, INT_MAX);
}

static inline int parse_int_non_neg(const char* str, int min, int max) {
if (min < 0) return -EINVAL;
int parsed;
try(parse_int(str, &parsed, min, max));
return parsed;
}

static int parse_int_seq(char* str, int* nums, size_t len) {
size_t str_len = strlen(str);
char* head = str;
Expand All @@ -93,14 +106,7 @@ static int parse_int_seq(char* str, int* nums, size_t len) {
char orig_char = str[i];
if (nums_idx >= len) ret(-EINVAL, _("sequence length out of range: '%s'"), str);
str[i] = '\0';
if (*head == '\0') {
nums[nums_idx++] = -1;
} else {
int num;
try(parse_int(head, &num));
if (num < 0 || num > 65535) ret(-EINVAL, _("integer out of range: '%d'"), num);
nums[nums_idx++] = num;
}
nums[nums_idx++] = *head == '\0' ? -1 : try(parse_int_non_neg(head, 0, INT16_MAX));
head = str + i + 1;
str[i] = orig_char;
}
Expand All @@ -120,24 +126,26 @@ __attribute__((unused)) static int parse_bool(const char* str, bool* result) {
return 0;
}

int parse_handshake(char* str, struct filter_settings* settings) {
if (!str || !settings) return -EINVAL;
int parse_handshake(char* str, struct filter_handshake* h) {
if (!str || !h) return -EINVAL;
int nums[2];
try(parse_int_seq(str, nums, 2));
for (int i = 0; i < 2; i++)
if (nums[i] >= 0) settings->handshake.array[i] = nums[i];
if (nums[i] >= 0) h->array[i] = nums[i];
return 0;
}

int parse_keepalive(char* str, struct filter_settings* settings) {
if (!str || !settings) return -EINVAL;
int parse_keepalive(char* str, struct filter_keepalive* k) {
if (!str || !k) return -EINVAL;
int nums[4];
try(parse_int_seq(str, nums, 4));
for (int i = 0; i < 4; i++)
if (nums[i] >= 0) settings->keepalive.array[i] = nums[i];
if (nums[i] >= 0) k->array[i] = nums[i];
return 0;
}

int parse_padding(const char* str) { return parse_int_non_neg(str, 0, MAX_PADDING_LEN); }

int parse_filter(char* filter_str, struct filter* filters, struct filter_info* info, int size) {
int ret;

Expand Down Expand Up @@ -194,9 +202,11 @@ int parse_filter(char* filter_str, struct filter* filters, struct filter_info* i
if (next_delim) *next_delim = '\0';
try(parse_kv(delim, &k, &v));
if (strcmp("handshake", k) == 0)
try(parse_handshake(v, &info[0].settings));
try(parse_handshake(v, &info[0].settings.handshake));
else if (strcmp("keepalive", k) == 0)
try(parse_keepalive(v, &info[0].settings));
try(parse_keepalive(v, &info[0].settings.keepalive));
else if (strcmp("padding", k) == 0)
info[0].settings.padding = parse_padding(v);
else
ret(-EINVAL, _("unsupported option type: '%s'"), k);
if (!next_delim) break;
Expand Down Expand Up @@ -240,14 +250,15 @@ int parse_config_file(FILE* file, struct run_args* args) {
log_verbosity = parsed;

} else if (strcmp(k, "handshake") == 0) {
try(parse_handshake(v, &args->gsettings));
try(parse_handshake(v, &args->gsettings.handshake));
} else if (strcmp(k, "keepalive") == 0) {
try(parse_keepalive(v, &args->gsettings));
try(parse_keepalive(v, &args->gsettings.keepalive));
} else if (strcmp(k, "filter") == 0) {
unsigned int fc = args->filter_count;
ret = parse_filter(v, &args->filters[fc], &args->info[fc], MAX_FILTER_COUNT - fc);
ret = parse_filter(v, &args->filters[fc], &args->info[fc], sizeof_array(args->filters) - fc);
if (ret == -E2BIG)
ret(-E2BIG, _("currently only maximum of %d filters is supported"), MAX_FILTER_COUNT);
ret(-E2BIG, _("currently only maximum of %d filters is supported"),
sizeof_array(args->filters));
else if (ret < 0)
return ret;
else
Expand Down Expand Up @@ -276,25 +287,24 @@ int parse_lock_file(FILE* file, struct lock_content* c) {
try(parse_kv(line, &k, &v));

if (strcmp(k, "version") == 0) {
if (strcmp(v, argp_program_version) != 0) {
if (strcmp(v, argp_program_version) != 0)
ret(-EINVAL, _("current Mimic version is %s, but lock file's is '%s'"),
argp_program_version, v);
}
version_checked = true;
} else if (strcmp(k, "pid") == 0)
try(parse_int(v, &c->pid));
try(parse_int_any(v, &c->pid));
else if (strcmp(k, "egress_id") == 0)
try(parse_int(v, &c->egress_id));
try(parse_int_any(v, &c->egress_id));
else if (strcmp(k, "ingress_id") == 0)
try(parse_int(v, &c->ingress_id));
try(parse_int_any(v, &c->ingress_id));
else if (strcmp(k, "whitelist_id") == 0)
try(parse_int(v, &c->whitelist_id));
try(parse_int_any(v, &c->whitelist_id));
else if (strcmp(k, "conns_id") == 0)
try(parse_int(v, &c->conns_id));
try(parse_int_any(v, &c->conns_id));
else if (strcmp(k, "handshake") == 0)
try(parse_handshake(v, &c->settings));
try(parse_handshake(v, &c->settings.handshake));
else if (strcmp(k, "keepalive") == 0)
try(parse_keepalive(v, &c->settings));
try(parse_keepalive(v, &c->settings.keepalive));
else
ret(-EINVAL, _("unknown key '%s'"), k);
}
Expand Down
13 changes: 5 additions & 8 deletions src/main.h
Original file line number Diff line number Diff line change
Expand Up @@ -12,10 +12,6 @@
#include "common/defs.h"
#include "common/try.h"

#ifndef MAX_FILTER_COUNT
#define MAX_FILTER_COUNT 32
#endif

struct args {
enum {
CMD_NULL,
Expand All @@ -25,8 +21,8 @@ struct args {
union {
struct run_args {
const char *ifname, *file;
struct filter filters[MAX_FILTER_COUNT];
struct filter_info info[MAX_FILTER_COUNT];
struct filter filters[32];
struct filter_info info[32];
struct filter_settings gsettings;
unsigned int filter_count;
} run;
Expand All @@ -53,8 +49,9 @@ struct lock_content {
struct filter_settings settings;
};

int parse_handshake(char* str, struct filter_settings* settings);
int parse_keepalive(char* str, struct filter_settings* settings);
int parse_handshake(char* str, struct filter_handshake* h);
int parse_keepalive(char* str, struct filter_keepalive* k);
int parse_padding(const char* str);
int parse_filter(char* filter_str, struct filter* filters, struct filter_info* info, int size);
int parse_config_file(FILE* file, struct run_args* args);
int parse_lock_file(FILE* file, struct lock_content* c);
Expand Down
19 changes: 12 additions & 7 deletions src/run.c
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ static const struct argp_option options[] = {
N_("Specify what packets to process. This may be specified for multiple times."), 1},
{"handshake", 'h', N_("i:r"), 0, N_("Controls retry behaviour of initiating connection"), 2},
{"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"), 2},
{"file", 'F', N_("PATH"), 0, N_("Load configuration from file"), 3},
{},
};
Expand All @@ -56,29 +57,33 @@ static inline error_t args_parse_opt(int key, char* arg, struct argp_state* stat
if (log_verbosity > 0) log_verbosity--;
break;
case 'f':
ret = parse_filter(arg, &args->filters[fc], &args->info[fc], MAX_FILTER_COUNT - fc);
ret =
parse_filter(arg, &args->filters[fc], &args->info[fc], sizeof_array(args->filters) - fc);
if (ret == -E2BIG)
ret(-E2BIG, _("currently only maximum of %d filters is supported"), MAX_FILTER_COUNT);
ret(-E2BIG, _("currently only maximum of %d filters is supported"),
sizeof_array(args->filters));
else if (ret < 0)
return ret;
else
args->filter_count += ret;
break;
case 'h':
try(parse_handshake(arg, &args->gsettings));
try(parse_handshake(arg, &args->gsettings.handshake));
break;
case 'k':
try(parse_keepalive(arg, &args->gsettings));
try(parse_keepalive(arg, &args->gsettings.keepalive));
break;
case 'p':
args->gsettings.padding = parse_padding(arg);
break;
case 'F':
args->file = arg;
break;
case ARGP_KEY_ARG:
if (!args->ifname) {
if (!args->ifname)
args->ifname = arg;
} else {
else
return ARGP_ERR_UNKNOWN;
}
break;
case ARGP_KEY_NO_ARGS:
argp_usage(state);
Expand Down
Loading

0 comments on commit 058185b

Please sign in to comment.