socket: enable setting of fwmark
Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com>
This commit is contained in:
parent
ef29165cde
commit
c8472e2dab
|
@ -19,7 +19,7 @@ _wg_completion() {
|
||||||
fi
|
fi
|
||||||
|
|
||||||
if [[ $COMP_CWORD -eq 3 && ${COMP_WORDS[1]} == show && ${COMP_WORDS[2]} != interfaces ]]; then
|
if [[ $COMP_CWORD -eq 3 && ${COMP_WORDS[1]} == show && ${COMP_WORDS[2]} != interfaces ]]; then
|
||||||
COMPREPLY+=( $(compgen -W "public-key private-key preshared-key listen-port peers endpoints allowed-ips latest-handshakes persistent-keepalive transfer" -- "${COMP_WORDS[3]}") )
|
COMPREPLY+=( $(compgen -W "public-key private-key preshared-key listen-port peers endpoints allowed-ips fwmark latest-handshakes persistent-keepalive transfer" -- "${COMP_WORDS[3]}") )
|
||||||
return
|
return
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
@ -31,9 +31,10 @@ _wg_completion() {
|
||||||
|
|
||||||
[[ ${COMP_WORDS[1]} == set ]] || return
|
[[ ${COMP_WORDS[1]} == set ]] || return
|
||||||
|
|
||||||
local has_listen_port=0 has_private_key=0 has_preshared_key=0 has_peer=0 has_remove=0 has_endpoint=0 has_persistent_keepalive=0 has_allowed_ips=0 words=() i j
|
local has_listen_port=0 has_fwmark=0 has_private_key=0 has_preshared_key=0 has_peer=0 has_remove=0 has_endpoint=0 has_persistent_keepalive=0 has_allowed_ips=0 words=() i j
|
||||||
for ((i=3;i<COMP_CWORD;i+=2)); do
|
for ((i=3;i<COMP_CWORD;i+=2)); do
|
||||||
[[ ${COMP_WORDS[i]} == listen-port ]] && has_listen_port=1
|
[[ ${COMP_WORDS[i]} == listen-port ]] && has_listen_port=1
|
||||||
|
[[ ${COMP_WORDS[i]} == fwmark ]] && has_fwmark=1
|
||||||
[[ ${COMP_WORDS[i]} == private-key ]] && has_private_key=1
|
[[ ${COMP_WORDS[i]} == private-key ]] && has_private_key=1
|
||||||
[[ ${COMP_WORDS[i]} == preshared-key ]] && has_preshared_key=1
|
[[ ${COMP_WORDS[i]} == preshared-key ]] && has_preshared_key=1
|
||||||
[[ ${COMP_WORDS[i]} == peer ]] && { has_peer=$i; break; }
|
[[ ${COMP_WORDS[i]} == peer ]] && { has_peer=$i; break; }
|
||||||
|
@ -41,6 +42,7 @@ _wg_completion() {
|
||||||
if [[ $has_peer -eq 0 ]]; then
|
if [[ $has_peer -eq 0 ]]; then
|
||||||
if ((COMP_CWORD % 2 != 0)); then
|
if ((COMP_CWORD % 2 != 0)); then
|
||||||
[[ $has_listen_port -eq 1 ]] || words+=( listen-port )
|
[[ $has_listen_port -eq 1 ]] || words+=( listen-port )
|
||||||
|
[[ $has_fwmark -eq 1 ]] || words+=( fwmark )
|
||||||
[[ $has_private_key -eq 1 ]] || words+=( private-key )
|
[[ $has_private_key -eq 1 ]] || words+=( private-key )
|
||||||
[[ $has_preshared_key -eq 1 ]] || words+=( preshared-key )
|
[[ $has_preshared_key -eq 1 ]] || words+=( preshared-key )
|
||||||
words+=( peer )
|
words+=( peer )
|
||||||
|
|
28
src/config.c
28
src/config.c
|
@ -91,6 +91,25 @@ static inline uint16_t parse_port(const char *value)
|
||||||
return port;
|
return port;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static inline bool parse_fwmark(uint32_t *fwmark, unsigned int *flags, const char *value)
|
||||||
|
{
|
||||||
|
unsigned long ret;
|
||||||
|
char *end;
|
||||||
|
int base = 10;
|
||||||
|
|
||||||
|
if (value[0] == '0' && value[1] == 'x') {
|
||||||
|
value += 2;
|
||||||
|
base = 16;
|
||||||
|
}
|
||||||
|
ret = strtoul(value, &end, base);
|
||||||
|
if (!*value || *end || ret > UINT32_MAX)
|
||||||
|
return false;
|
||||||
|
*fwmark = ret;
|
||||||
|
if (!ret)
|
||||||
|
*flags |= WGDEVICE_REMOVE_FWMARK;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
static inline bool parse_key(uint8_t key[static WG_KEY_LEN], const char *value)
|
static inline bool parse_key(uint8_t key[static WG_KEY_LEN], const char *value)
|
||||||
{
|
{
|
||||||
uint8_t tmp[WG_KEY_LEN + 1];
|
uint8_t tmp[WG_KEY_LEN + 1];
|
||||||
|
@ -281,6 +300,8 @@ static bool process_line(struct config_ctx *ctx, const char *line)
|
||||||
if (ctx->is_device_section) {
|
if (ctx->is_device_section) {
|
||||||
if (key_match("ListenPort"))
|
if (key_match("ListenPort"))
|
||||||
ret = !!(ctx->buf.dev->port = parse_port(value));
|
ret = !!(ctx->buf.dev->port = parse_port(value));
|
||||||
|
else if (key_match("FwMark"))
|
||||||
|
ret = parse_fwmark(&ctx->buf.dev->fwmark, &ctx->buf.dev->flags, value);
|
||||||
else if (key_match("PrivateKey")) {
|
else if (key_match("PrivateKey")) {
|
||||||
ret = parse_key(ctx->buf.dev->private_key, value);
|
ret = parse_key(ctx->buf.dev->private_key, value);
|
||||||
if (!ret)
|
if (!ret)
|
||||||
|
@ -372,6 +393,8 @@ bool config_read_finish(struct config_ctx *ctx)
|
||||||
}
|
}
|
||||||
if (ctx->buf.dev->flags & WGDEVICE_REPLACE_PEERS && !key_is_valid(ctx->buf.dev->preshared_key))
|
if (ctx->buf.dev->flags & WGDEVICE_REPLACE_PEERS && !key_is_valid(ctx->buf.dev->preshared_key))
|
||||||
ctx->buf.dev->flags |= WGDEVICE_REMOVE_PRESHARED_KEY;
|
ctx->buf.dev->flags |= WGDEVICE_REMOVE_PRESHARED_KEY;
|
||||||
|
if (ctx->buf.dev->flags & WGDEVICE_REPLACE_PEERS && !ctx->buf.dev->fwmark)
|
||||||
|
ctx->buf.dev->flags |= WGDEVICE_REMOVE_FWMARK;
|
||||||
|
|
||||||
for_each_wgpeer(ctx->buf.dev, peer, i) {
|
for_each_wgpeer(ctx->buf.dev, peer, i) {
|
||||||
if (!key_is_valid(peer->public_key)) {
|
if (!key_is_valid(peer->public_key)) {
|
||||||
|
@ -448,6 +471,11 @@ bool config_read_cmd(struct wgdevice **device, char *argv[], int argc)
|
||||||
goto error;
|
goto error;
|
||||||
argv += 2;
|
argv += 2;
|
||||||
argc -= 2;
|
argc -= 2;
|
||||||
|
} else if (!strcmp(argv[0], "fwmark") && argc >= 2 && !buf.dev->num_peers) {
|
||||||
|
if (!parse_fwmark(&buf.dev->fwmark, &buf.dev->flags, argv[1]))
|
||||||
|
goto error;
|
||||||
|
argv += 2;
|
||||||
|
argc -= 2;
|
||||||
} else if (!strcmp(argv[0], "private-key") && argc >= 2 && !buf.dev->num_peers) {
|
} else if (!strcmp(argv[0], "private-key") && argc >= 2 && !buf.dev->num_peers) {
|
||||||
char *line;
|
char *line;
|
||||||
int ret = read_line(&line, argv[1]);
|
int ret = read_line(&line, argv[1]);
|
||||||
|
|
|
@ -13,7 +13,7 @@ int set_main(int argc, char *argv[])
|
||||||
int ret = 1;
|
int ret = 1;
|
||||||
|
|
||||||
if (argc < 3) {
|
if (argc < 3) {
|
||||||
fprintf(stderr, "Usage: %s %s <interface> [listen-port <port>] [private-key <file path>] [peer <base64 public key> [remove] [endpoint <ip>:<port>] [persistent-keepalive <interval seconds>] [allowed-ips <ip1>/<cidr1>[,<ip2>/<cidr2>]...] ]...\n", PROG_NAME, argv[0]);
|
fprintf(stderr, "Usage: %s %s <interface> [listen-port <port>] [fwmark <mark>] [private-key <file path>] [peer <base64 public key> [remove] [endpoint <ip>:<port>] [persistent-keepalive <interval seconds>] [allowed-ips <ip1>/<cidr1>[,<ip2>/<cidr2>]...] ]...\n", PROG_NAME, argv[0]);
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -203,7 +203,7 @@ static char *bytes(uint64_t b)
|
||||||
static const char *COMMAND_NAME = NULL;
|
static const char *COMMAND_NAME = NULL;
|
||||||
static void show_usage(void)
|
static void show_usage(void)
|
||||||
{
|
{
|
||||||
fprintf(stderr, "Usage: %s %s { <interface> | all | interfaces } [public-key | private-key | preshared-key | listen-port | peers | endpoints | allowed-ips | latest-handshakes | transfer | persistent-keepalive]\n", PROG_NAME, COMMAND_NAME);
|
fprintf(stderr, "Usage: %s %s { <interface> | all | interfaces } [public-key | private-key | preshared-key | listen-port | fwmark | peers | endpoints | allowed-ips | latest-handshakes | transfer | persistent-keepalive]\n", PROG_NAME, COMMAND_NAME);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void pretty_print(struct wgdevice *device)
|
static void pretty_print(struct wgdevice *device)
|
||||||
|
@ -222,6 +222,8 @@ static void pretty_print(struct wgdevice *device)
|
||||||
terminal_printf(" " TERMINAL_BOLD "pre-shared key" TERMINAL_RESET ": %s\n", masked_key(device->preshared_key));
|
terminal_printf(" " TERMINAL_BOLD "pre-shared key" TERMINAL_RESET ": %s\n", masked_key(device->preshared_key));
|
||||||
if (device->port)
|
if (device->port)
|
||||||
terminal_printf(" " TERMINAL_BOLD "listening port" TERMINAL_RESET ": %u\n", device->port);
|
terminal_printf(" " TERMINAL_BOLD "listening port" TERMINAL_RESET ": %u\n", device->port);
|
||||||
|
if (device->fwmark)
|
||||||
|
terminal_printf(" " TERMINAL_BOLD "fwmark" TERMINAL_RESET ": 0x%x\n", device->fwmark);
|
||||||
if (device->num_peers) {
|
if (device->num_peers) {
|
||||||
sort_peers(device);
|
sort_peers(device);
|
||||||
terminal_printf("\n");
|
terminal_printf("\n");
|
||||||
|
@ -271,6 +273,10 @@ static bool ugly_print(struct wgdevice *device, const char *param, bool with_int
|
||||||
if (with_interface)
|
if (with_interface)
|
||||||
printf("%s\t", device->interface);
|
printf("%s\t", device->interface);
|
||||||
printf("%u\n", device->port);
|
printf("%u\n", device->port);
|
||||||
|
} else if (!strcmp(param, "fwmark")) {
|
||||||
|
if (with_interface)
|
||||||
|
printf("%s\t", device->interface);
|
||||||
|
printf("0x%x\n", device->fwmark);
|
||||||
} else if (!strcmp(param, "endpoints")) {
|
} else if (!strcmp(param, "endpoints")) {
|
||||||
if (with_interface)
|
if (with_interface)
|
||||||
printf("%s\t", device->interface);
|
printf("%s\t", device->interface);
|
||||||
|
|
|
@ -44,7 +44,9 @@ int showconf_main(int argc, char *argv[])
|
||||||
|
|
||||||
printf("[Interface]\n");
|
printf("[Interface]\n");
|
||||||
if (device->port)
|
if (device->port)
|
||||||
printf("ListenPort = %d\n", device->port);
|
printf("ListenPort = %u\n", device->port);
|
||||||
|
if (device->fwmark)
|
||||||
|
printf("FwMark = 0x%x\n", device->fwmark);
|
||||||
if (memcmp(device->private_key, zero, WG_KEY_LEN)) {
|
if (memcmp(device->private_key, zero, WG_KEY_LEN)) {
|
||||||
b64_ntop(device->private_key, WG_KEY_LEN, b64, b64_len(WG_KEY_LEN));
|
b64_ntop(device->private_key, WG_KEY_LEN, b64, b64_len(WG_KEY_LEN));
|
||||||
printf("PrivateKey = %s\n", b64);
|
printf("PrivateKey = %s\n", b64);
|
||||||
|
|
|
@ -78,10 +78,15 @@ add_if() {
|
||||||
}
|
}
|
||||||
|
|
||||||
del_if() {
|
del_if() {
|
||||||
if [[ $(ip route show table all) =~ .*\ dev\ $INTERFACE\ table\ ([0-9]+)\ .* ]]; then
|
DEFAULT_TABLE=$(("$(wg show "$INTERFACE" fwmark)"))
|
||||||
while [[ -n $(ip rule show table ${BASH_REMATCH[1]}) ]]; do
|
if [[ $DEFAULT_TABLE -ne 0 ]]; then
|
||||||
cmd ip rule delete table "${BASH_REMATCH[1]}"
|
while [[ -n $(ip -4 rule show table $DEFAULT_TABLE) ]]; do
|
||||||
[[ $(ip rule show table main) == *"from all lookup main suppress_prefixlength 0"* ]] && cmd ip rule delete table main suppress_prefixlength 0
|
cmd ip -4 rule delete table $DEFAULT_TABLE
|
||||||
|
[[ $(ip -4 rule show table main) == *"from all lookup main suppress_prefixlength 0"* ]] && cmd ip -4 rule delete table main suppress_prefixlength 0
|
||||||
|
done
|
||||||
|
while [[ -n $(ip -6 rule show table $DEFAULT_TABLE) ]]; do
|
||||||
|
cmd ip -6 rule delete table $DEFAULT_TABLE
|
||||||
|
[[ $(ip -6 rule show table main) == *"from all lookup main suppress_prefixlength 0"* ]] && cmd ip -6 rule delete table main suppress_prefixlength 0
|
||||||
done
|
done
|
||||||
fi
|
fi
|
||||||
cmd ip link delete dev "$INTERFACE"
|
cmd ip link delete dev "$INTERFACE"
|
||||||
|
@ -104,22 +109,22 @@ add_route() {
|
||||||
}
|
}
|
||||||
|
|
||||||
DEFAULT_TABLE=
|
DEFAULT_TABLE=
|
||||||
PREVIOUS_ENDPOINT=
|
|
||||||
add_default() {
|
add_default() {
|
||||||
[[ $(join <(wg show "$INTERFACE" allowed-ips) <(wg show "$INTERFACE" endpoints)) =~ ([A-Za-z0-9/+=]{44})\ ([0-9a-f/.:]+ )*${1//./\\.}\ ([0-9a-f/.:]+ )*\[?([0-9.:a-f]+)\]?:[0-9]+ ]] && local endpoint="${BASH_REMATCH[4]}"
|
|
||||||
[[ -n $endpoint ]] || return 0
|
|
||||||
local first=0
|
|
||||||
if [[ -z $DEFAULT_TABLE ]]; then
|
if [[ -z $DEFAULT_TABLE ]]; then
|
||||||
first=1
|
|
||||||
DEFAULT_TABLE=51820
|
DEFAULT_TABLE=51820
|
||||||
while [[ -n $(ip route show table $DEFAULT_TABLE) ]]; do ((DEFAULT_TABLE++)); done
|
while [[ -n $(ip route show table $DEFAULT_TABLE) ]]; do ((DEFAULT_TABLE++)); done
|
||||||
fi
|
fi
|
||||||
cmd ip route add "$1" dev "$INTERFACE" table $DEFAULT_TABLE
|
local proto=-4
|
||||||
[[ $PREVIOUS_ENDPOINT == "$endpoint" ]] && return 0
|
[[ $1 == *:* ]] && proto=-6
|
||||||
PREVIOUS_ENDPOINT="$endpoint"
|
cmd wg set "$INTERFACE" fwmark $DEFAULT_TABLE
|
||||||
cmd ip rule add not to "$endpoint" table $DEFAULT_TABLE
|
cmd ip $proto route add "$1" dev "$INTERFACE" table $DEFAULT_TABLE
|
||||||
[[ $first -eq 1 ]] || return 0
|
cmd ip $proto rule add not fwmark $DEFAULT_TABLE table $DEFAULT_TABLE
|
||||||
cmd ip rule add table main suppress_prefixlength 0
|
cmd ip $proto rule add table main suppress_prefixlength 0
|
||||||
|
local key equals value
|
||||||
|
while read -r key equals value; do
|
||||||
|
[[ $value -eq 1 ]] && sysctl -q "$key=2"
|
||||||
|
done < <(sysctl -a -r 'net\.ipv4.conf\..+\.rp_filter')
|
||||||
|
return 0
|
||||||
}
|
}
|
||||||
|
|
||||||
set_config() {
|
set_config() {
|
||||||
|
|
6
src/wg.8
6
src/wg.8
|
@ -36,7 +36,7 @@ Sub-commands that take an INTERFACE must be passed a WireGuard interface.
|
||||||
.SH COMMANDS
|
.SH COMMANDS
|
||||||
|
|
||||||
.TP
|
.TP
|
||||||
\fBshow\fP { \fI<interface>\fP | \fIall\fP | \fIinterfaces\fP } [\fIpublic-key\fP | \fIprivate-key\fP | \fIpreshared-key\fP | \fIlisten-port\fP | \fIpeers\fP | \fIendpoints\fP | \fIallowed-ips\fP | \fIlatest-handshakes\fP | \fIpersistent-keepalive\fP | \fItransfer\fP]
|
\fBshow\fP { \fI<interface>\fP | \fIall\fP | \fIinterfaces\fP } [\fIpublic-key\fP | \fIprivate-key\fP | \fIpreshared-key\fP | \fIlisten-port\fP | \fIfwmark\fP | \fIpeers\fP | \fIendpoints\fP | \fIallowed-ips\fP | \fIlatest-handshakes\fP | \fIpersistent-keepalive\fP | \fItransfer\fP]
|
||||||
Shows current WireGuard configuration of specified \fI<interface>\fP.
|
Shows current WireGuard configuration of specified \fI<interface>\fP.
|
||||||
If no \fI<interface>\fP is specified, \fI<interface>\fP defaults to \fIall\fP.
|
If no \fI<interface>\fP is specified, \fI<interface>\fP defaults to \fIall\fP.
|
||||||
If \fIinterfaces\fP is specified, prints a list of all WireGuard interfaces,
|
If \fIinterfaces\fP is specified, prints a list of all WireGuard interfaces,
|
||||||
|
@ -49,7 +49,7 @@ newlines and tabs, meant to be used in scripts.
|
||||||
Shows the current configuration of \fI<interface>\fP in the format described
|
Shows the current configuration of \fI<interface>\fP in the format described
|
||||||
by \fICONFIGURATION FILE FORMAT\fP below.
|
by \fICONFIGURATION FILE FORMAT\fP below.
|
||||||
.TP
|
.TP
|
||||||
\fBset\fP \fI<interface>\fP [\fIlisten-port\fP \fI<port>\fP] [\fIprivate-key\fP \fI<file-path>\fP] [\fIpreshared-key\fP \fI<file-path>\fP] [\fIpeer\fP \fI<base64-public-key>\fP [\fIremove\fP] [\fIendpoint\fP \fI<ip>:<port>\fP] [\fIpersistent-keepalive\fP \fI<interval seconds>\fP] [\fIallowed-ips\fP \fI<ip1>/<cidr1>\fP[,\fI<ip2>/<cidr2>\fP]...] ]...
|
\fBset\fP \fI<interface>\fP [\fIlisten-port\fP \fI<port>\fP] [\fIfwmark\fP \fI<fwmark>\fP] [\fIprivate-key\fP \fI<file-path>\fP] [\fIpreshared-key\fP \fI<file-path>\fP] [\fIpeer\fP \fI<base64-public-key>\fP [\fIremove\fP] [\fIendpoint\fP \fI<ip>:<port>\fP] [\fIpersistent-keepalive\fP \fI<interval seconds>\fP] [\fIallowed-ips\fP \fI<ip1>/<cidr1>\fP[,\fI<ip2>/<cidr2>\fP]...] ]...
|
||||||
Sets configuration values for the specified \fI<interface>\fP. Multiple
|
Sets configuration values for the specified \fI<interface>\fP. Multiple
|
||||||
\fIpeer\fPs may be specified, and if the \fIremove\fP argument is given
|
\fIpeer\fPs may be specified, and if the \fIremove\fP argument is given
|
||||||
for a peer, that peer is removed, not configured. If \fIlisten-port\fP
|
for a peer, that peer is removed, not configured. If \fIlisten-port\fP
|
||||||
|
@ -125,6 +125,8 @@ for post-quantum resistance.
|
||||||
.IP \(bu
|
.IP \(bu
|
||||||
ListenPort \(em a 16-bit port for listening. Optional; if not specified, chosen
|
ListenPort \(em a 16-bit port for listening. Optional; if not specified, chosen
|
||||||
randomly.
|
randomly.
|
||||||
|
.IP \(bu
|
||||||
|
FwMark \(em a 32-bit fwmark for outgoing packets. Optional.
|
||||||
.P
|
.P
|
||||||
The \fIPeer\fP sections may contain the following fields:
|
The \fIPeer\fP sections may contain the following fields:
|
||||||
.IP \(bu
|
.IP \(bu
|
||||||
|
|
Loading…
Reference in a new issue