Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Allow modifying keepalive packets drop probability #35

Open
wants to merge 1 commit into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 12 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -53,13 +53,24 @@ allow_unsupported_modules 1

### Usage

This extension takes two parameters.
This extension takes three parameters.

`--key` for a shared secret between client and server. If a key is a long
string, it will be cut at 32 characters; if a key is short, then it will be
repeated until reaches 32 characters. This 32 characters long string is the key
used by chacha8 hash.

`--keepalive-drop-chance=n` (optional) to specify chance to drop a wireguard
keepalive packet. Chance is represented as a number from 0 to 255. Corresponding
probability to drop a packet can be calculated via the following formula:
`p = n / 256`.

In other words:
- `n=0` means never drop keepalive packets.
- `n=255` means drop keepalive packet almost every time.

By default, it is set to 205 (`p ≈ 0.8`).

`--obfs` or `--unobfs` to indicate the operation mode.

**Before** bring up wg, on client, insert two iptables rules:
Expand Down
42 changes: 34 additions & 8 deletions src/libxt_WGOBFS.c
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
*/
#include <stdio.h>
#include <string.h>
#include <inttypes.h>
#include <errno.h>
#include <getopt.h>
#include <xtables.h>
Expand All @@ -17,6 +18,7 @@ enum {

enum {
OPT_KEY = 0,
OPT_KEEPALIVE_DROP_CHANCE,
OPT_OBFS,
OPT_UNOBFS
};
Expand All @@ -28,6 +30,7 @@ enum {

static const struct option wg_obfs_opts[] = {
{ .name = "key", .has_arg = true, .val = OPT_KEY },
{ .name = "keepalive-drop-chance", .has_arg = optional_argument, .val = OPT_KEEPALIVE_DROP_CHANCE },
{ .name = "obfs", .has_arg = false, .val = OPT_OBFS },
{ .name = "unobfs", .has_arg = false, .val = OPT_UNOBFS },
{},
Expand All @@ -37,6 +40,7 @@ static void wg_obfs_help(void)
{
printf("WGOBFS target options:\n"
" --key <string>\n"
" --keepalive-drop-chance=<0-255>\n"
" --obfs or --unobfs\n");
}

Expand Down Expand Up @@ -77,6 +81,15 @@ static int wg_obfs_parse(int c, char **argv, int z1, unsigned int *flags,
expand_string(s, len, chacha_key, XT_CHACHA_KEY_SIZE);
memcpy(info->chacha_key, chacha_key, XT_CHACHA_KEY_SIZE);
return true;
case OPT_KEEPALIVE_DROP_CHANCE:
if (s == NULL)
xtables_error(PARAMETER_PROBLEM,
"WGOBFS: Drop chance should be specified");
if (sscanf(s, "%" SCNu8, &info->keepalive_drop_chance) != 1)
xtables_error(PARAMETER_PROBLEM,
"WGOBFS: Drop chance is not a valid number");
info->is_kdc_default = false;
return true;
case OPT_OBFS:
info->mode = XT_MODE_OBFS;
*flags |= FLAGS_OBFS;
Expand All @@ -100,25 +113,36 @@ static void wg_obfs_check(unsigned int flags)
"WGOBFS: --obfs or --unobfs is required.");
}

/* set default parameters for --keepalive-drop-chance */
static void wg_obfs_init(struct xt_entry_target *tgt)
{
struct xt_wg_obfs_info *info = (void *)tgt->data;

info->is_kdc_default = true;
info->keepalive_drop_chance = XT_WGOBFS_DEFAULT_KDC;
}

/* invoke by `iptables -L` to show previously inserted rules */
static void wg_obfs_print(const void *z1, const struct xt_entry_target *tgt,
int z2)
{
const struct xt_wg_obfs_info *info = (const void *)tgt->data;

printf(" --key %s", info->key);

if (!info->is_kdc_default)
printf(" --keepalive-drop-chance=%" PRIu8, info->keepalive_drop_chance);

if (info->mode == XT_MODE_OBFS)
printf(" --key %s --obfs", info->key);
printf(" --obfs ");
else if (info->mode == XT_MODE_UNOBFS)
printf(" --key %s --unobfs", info->key);
printf(" --unobfs ");
}

/* for iptables-save to dump rules */
/* for iptables-save to dump rules; identical to print */
static void wg_obfs_save(const void *u, const struct xt_entry_target *tgt)
{
const struct xt_wg_obfs_info *info = (const void *)tgt->data;
if (info->mode == XT_MODE_OBFS)
printf(" --key %s --obfs", info->key);
else if (info->mode == XT_MODE_UNOBFS)
printf(" --key %s --unobfs", info->key);
wg_obfs_print(u, tgt, 0);
}

static struct xtables_target wg_obfs_reg[] = {
Expand All @@ -130,6 +154,7 @@ static struct xtables_target wg_obfs_reg[] = {
.size = XT_ALIGN(sizeof(struct xt_wg_obfs_info)),
.userspacesize = XT_ALIGN(sizeof(struct xt_wg_obfs_info)),
.help = wg_obfs_help,
.init = wg_obfs_init,
.parse = wg_obfs_parse,
.final_check = wg_obfs_check,
.print = wg_obfs_print,
Expand All @@ -144,6 +169,7 @@ static struct xtables_target wg_obfs_reg[] = {
.size = XT_ALIGN(sizeof(struct xt_wg_obfs_info)),
.userspacesize = XT_ALIGN(sizeof(struct xt_wg_obfs_info)),
.help = wg_obfs_help,
.init = wg_obfs_init,
.parse = wg_obfs_parse,
.final_check = wg_obfs_check,
.print = wg_obfs_print,
Expand Down
4 changes: 4 additions & 0 deletions src/xt_WGOBFS.h
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,12 @@
#define XT_MODE_OBFS 0
#define XT_MODE_UNOBFS 1

#define XT_WGOBFS_DEFAULT_KDC 205

struct xt_wg_obfs_info {
unsigned char mode;
unsigned char keepalive_drop_chance;
unsigned char is_kdc_default;
char key[XT_WGOBFS_MAX_KEY_SIZE + 1];
unsigned char chacha_key[XT_CHACHA_KEY_SIZE]; /* 256 bits chacha key */
};
Expand Down
7 changes: 4 additions & 3 deletions src/xt_WGOBFS_main.c
Original file line number Diff line number Diff line change
Expand Up @@ -105,7 +105,8 @@ static void obfs_mac2(u8 *buf, const int data_len, struct obfs_buf *ob,
}

static int random_drop_wg_keepalive(u8 *buf, const int len,
struct obfs_buf *ob, const u8 *key)
struct obfs_buf *ob, const u8 *key,
const u8 drop_chance)
{
u8 type = *buf;
u8 *counter = ob->chacha_in;
Expand All @@ -117,7 +118,7 @@ static int random_drop_wg_keepalive(u8 *buf, const int len,
(*counter)++;
chacha_hash(ob->chacha_in, key, ob->chacha_out, ONE_WORD);

if (ob->chacha_out[0] > 50)
if (ob->chacha_out[0] < drop_chance)
return 1;
else
return 0;
Expand Down Expand Up @@ -214,7 +215,7 @@ static unsigned int xt_obfs_udp_payload(struct sk_buff *skb, u8 *rnd_len_out,
ob.chacha_in[0] += 42;

if (random_drop_wg_keepalive(buf_udp, wg_data_len, &ob,
info->chacha_key))
info->chacha_key, info->keepalive_drop_chance))
return NF_DROP;

/* Insert a long pseudo-random string if the WG packet is small, or a
Expand Down