summaryrefslogtreecommitdiffstatshomepage
path: root/src
diff options
context:
space:
mode:
authorJason A. Donenfeld <Jason@zx2c4.com>2017-01-24 17:43:35 +0100
committerJason A. Donenfeld <Jason@zx2c4.com>2017-02-13 21:55:18 +0100
commit5a6d43eb15b537e525d724c9fb3400031ae14c70 (patch)
tree2824757f1016582eb74fc83bf06989b142cb627b /src
parentmain: add `wg` type alias (diff)
downloadwireguard-monolithic-historical-5a6d43eb15b537e525d724c9fb3400031ae14c70.tar.xz
wireguard-monolithic-historical-5a6d43eb15b537e525d724c9fb3400031ae14c70.zip
socket: enable setting of fwmark
Diffstat (limited to 'src')
-rw-r--r--src/config.c6
-rw-r--r--src/device.h1
-rw-r--r--src/socket.c3
-rw-r--r--src/tools/completion/wg.bash-completion6
-rw-r--r--src/tools/config.c28
-rw-r--r--src/tools/set.c2
-rw-r--r--src/tools/show.c8
-rw-r--r--src/tools/showconf.c4
-rwxr-xr-xsrc/tools/wg-quick.bash35
-rw-r--r--src/tools/wg.86
-rw-r--r--src/uapi.h6
11 files changed, 80 insertions, 25 deletions
diff --git a/src/config.c b/src/config.c
index 172287a..30c876e 100644
--- a/src/config.c
+++ b/src/config.c
@@ -125,6 +125,11 @@ int config_set_device(struct wireguard_device *wg, void __user *user_device)
goto out;
}
+ if (in_device.fwmark || (!in_device.fwmark && (in_device.flags & WGDEVICE_REMOVE_FWMARK))) {
+ wg->fwmark = in_device.fwmark;
+ peer_for_each_unlocked(wg, clear_peer_endpoint_src, NULL);
+ }
+
if (in_device.port) {
ret = set_device_port(wg, in_device.port);
if (ret)
@@ -287,6 +292,7 @@ int config_get_device(struct wireguard_device *wg, void __user *udevice)
}
out_device.port = wg->incoming_port;
+ out_device.fwmark = wg->fwmark;
strncpy(out_device.interface, dev->name, IFNAMSIZ - 1);
out_device.interface[IFNAMSIZ - 1] = 0;
diff --git a/src/device.h b/src/device.h
index 3cbbbaa..855ec27 100644
--- a/src/device.h
+++ b/src/device.h
@@ -19,6 +19,7 @@
struct wireguard_device {
struct sock __rcu *sock4, *sock6;
u16 incoming_port;
+ u32 fwmark;
struct net *creating_net;
struct workqueue_struct *workqueue;
struct workqueue_struct *parallelqueue;
diff --git a/src/socket.c b/src/socket.c
index e26504d..f799d91 100644
--- a/src/socket.c
+++ b/src/socket.c
@@ -20,6 +20,7 @@ static inline int send4(struct wireguard_device *wg, struct sk_buff *skb, struct
.daddr = endpoint->addr4.sin_addr.s_addr,
.fl4_dport = endpoint->addr4.sin_port,
.fl4_sport = htons(wg->incoming_port),
+ .flowi4_mark = wg->fwmark,
.flowi4_proto = IPPROTO_UDP
};
struct rtable *rt = NULL;
@@ -62,7 +63,6 @@ static inline int send4(struct wireguard_device *wg, struct sk_buff *skb, struct
if (cache)
dst_cache_set_ip4(cache, &rt->dst, fl.saddr);
}
-
udp_tunnel_xmit_skb(rt, sock, skb,
fl.saddr, fl.daddr,
ds, ip4_dst_hoplimit(&rt->dst), 0,
@@ -85,6 +85,7 @@ static inline int send6(struct wireguard_device *wg, struct sk_buff *skb, struct
.daddr = endpoint->addr6.sin6_addr,
.fl6_dport = endpoint->addr6.sin6_port,
.fl6_sport = htons(wg->incoming_port),
+ .flowi6_mark = wg->fwmark,
.flowi6_oif = endpoint->addr6.sin6_scope_id,
.flowi6_proto = IPPROTO_UDP
/* TODO: addr->sin6_flowinfo */
diff --git a/src/tools/completion/wg.bash-completion b/src/tools/completion/wg.bash-completion
index 76a832a..8822d01 100644
--- a/src/tools/completion/wg.bash-completion
+++ b/src/tools/completion/wg.bash-completion
@@ -19,7 +19,7 @@ _wg_completion() {
fi
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
fi
@@ -31,9 +31,10 @@ _wg_completion() {
[[ ${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
[[ ${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]} == preshared-key ]] && has_preshared_key=1
[[ ${COMP_WORDS[i]} == peer ]] && { has_peer=$i; break; }
@@ -41,6 +42,7 @@ _wg_completion() {
if [[ $has_peer -eq 0 ]]; then
if ((COMP_CWORD % 2 != 0)); then
[[ $has_listen_port -eq 1 ]] || words+=( listen-port )
+ [[ $has_fwmark -eq 1 ]] || words+=( fwmark )
[[ $has_private_key -eq 1 ]] || words+=( private-key )
[[ $has_preshared_key -eq 1 ]] || words+=( preshared-key )
words+=( peer )
diff --git a/src/tools/config.c b/src/tools/config.c
index da19cc3..b3384da 100644
--- a/src/tools/config.c
+++ b/src/tools/config.c
@@ -91,6 +91,25 @@ static inline uint16_t parse_port(const char *value)
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)
{
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 (key_match("ListenPort"))
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")) {
ret = parse_key(ctx->buf.dev->private_key, value);
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))
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) {
if (!key_is_valid(peer->public_key)) {
@@ -448,6 +471,11 @@ bool config_read_cmd(struct wgdevice **device, char *argv[], int argc)
goto error;
argv += 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) {
char *line;
int ret = read_line(&line, argv[1]);
diff --git a/src/tools/set.c b/src/tools/set.c
index 48b0050..5e4291f 100644
--- a/src/tools/set.c
+++ b/src/tools/set.c
@@ -13,7 +13,7 @@ int set_main(int argc, char *argv[])
int ret = 1;
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;
}
diff --git a/src/tools/show.c b/src/tools/show.c
index 124e323..c20d858 100644
--- a/src/tools/show.c
+++ b/src/tools/show.c
@@ -203,7 +203,7 @@ static char *bytes(uint64_t b)
static const char *COMMAND_NAME = NULL;
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)
@@ -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));
if (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) {
sort_peers(device);
terminal_printf("\n");
@@ -271,6 +273,10 @@ static bool ugly_print(struct wgdevice *device, const char *param, bool with_int
if (with_interface)
printf("%s\t", device->interface);
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")) {
if (with_interface)
printf("%s\t", device->interface);
diff --git a/src/tools/showconf.c b/src/tools/showconf.c
index d2f36e0..585b08d 100644
--- a/src/tools/showconf.c
+++ b/src/tools/showconf.c
@@ -44,7 +44,9 @@ int showconf_main(int argc, char *argv[])
printf("[Interface]\n");
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)) {
b64_ntop(device->private_key, WG_KEY_LEN, b64, b64_len(WG_KEY_LEN));
printf("PrivateKey = %s\n", b64);
diff --git a/src/tools/wg-quick.bash b/src/tools/wg-quick.bash
index 1eb71b2..5db3485 100755
--- a/src/tools/wg-quick.bash
+++ b/src/tools/wg-quick.bash
@@ -78,10 +78,15 @@ add_if() {
}
del_if() {
- if [[ $(ip route show table all) =~ .*\ dev\ $INTERFACE\ table\ ([0-9]+)\ .* ]]; then
- while [[ -n $(ip rule show table ${BASH_REMATCH[1]}) ]]; do
- cmd ip rule delete table "${BASH_REMATCH[1]}"
- [[ $(ip rule show table main) == *"from all lookup main suppress_prefixlength 0"* ]] && cmd ip rule delete table main suppress_prefixlength 0
+ DEFAULT_TABLE=$(("$(wg show "$INTERFACE" fwmark)"))
+ if [[ $DEFAULT_TABLE -ne 0 ]]; then
+ while [[ -n $(ip -4 rule show table $DEFAULT_TABLE) ]]; do
+ 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
fi
cmd ip link delete dev "$INTERFACE"
@@ -104,22 +109,22 @@ add_route() {
}
DEFAULT_TABLE=
-PREVIOUS_ENDPOINT=
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
- first=1
DEFAULT_TABLE=51820
while [[ -n $(ip route show table $DEFAULT_TABLE) ]]; do ((DEFAULT_TABLE++)); done
fi
- cmd ip route add "$1" dev "$INTERFACE" table $DEFAULT_TABLE
- [[ $PREVIOUS_ENDPOINT == "$endpoint" ]] && return 0
- PREVIOUS_ENDPOINT="$endpoint"
- cmd ip rule add not to "$endpoint" table $DEFAULT_TABLE
- [[ $first -eq 1 ]] || return 0
- cmd ip rule add table main suppress_prefixlength 0
+ local proto=-4
+ [[ $1 == *:* ]] && proto=-6
+ cmd wg set "$INTERFACE" fwmark $DEFAULT_TABLE
+ cmd ip $proto route add "$1" dev "$INTERFACE" table $DEFAULT_TABLE
+ cmd ip $proto rule add not fwmark $DEFAULT_TABLE table $DEFAULT_TABLE
+ 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() {
diff --git a/src/tools/wg.8 b/src/tools/wg.8
index be05acf..9aa76cf 100644
--- a/src/tools/wg.8
+++ b/src/tools/wg.8
@@ -36,7 +36,7 @@ Sub-commands that take an INTERFACE must be passed a WireGuard interface.
.SH COMMANDS
.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.
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,
@@ -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
by \fICONFIGURATION FILE FORMAT\fP below.
.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
\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
@@ -125,6 +125,8 @@ for post-quantum resistance.
.IP \(bu
ListenPort \(em a 16-bit port for listening. Optional; if not specified, chosen
randomly.
+.IP \(bu
+FwMark \(em a 32-bit fwmark for outgoing packets. Optional.
.P
The \fIPeer\fP sections may contain the following fields:
.IP \(bu
diff --git a/src/uapi.h b/src/uapi.h
index eb8d9d3..9cf9b2c 100644
--- a/src/uapi.h
+++ b/src/uapi.h
@@ -121,7 +121,8 @@ struct wgpeer {
enum {
WGDEVICE_REPLACE_PEERS = (1 << 0),
WGDEVICE_REMOVE_PRIVATE_KEY = (1 << 1),
- WGDEVICE_REMOVE_PRESHARED_KEY = (1 << 2)
+ WGDEVICE_REMOVE_PRESHARED_KEY = (1 << 2),
+ WGDEVICE_REMOVE_FWMARK = (1 << 3)
};
struct wgdevice {
char interface[IFNAMSIZ]; /* Get */
@@ -130,11 +131,12 @@ struct wgdevice {
__u8 public_key[WG_KEY_LEN]; /* Get */
__u8 private_key[WG_KEY_LEN]; /* Get/Set */
__u8 preshared_key[WG_KEY_LEN]; /* Get/Set */
+ __u32 fwmark; /* Get/Set */
__u16 port; /* Get/Set */
union {
__u16 num_peers; /* Get/Set */
- __u64 peers_size; /* Get */
+ __u32 peers_size; /* Get */
};
};