-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathMakefile
162 lines (144 loc) · 6.31 KB
/
Makefile
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
# Read configuration from config.json. The config file contains things we may
# not want to check into Git.
#
# Example config.json:
# {
# "server_interface": "eth0",
# "server_hostname": "foo.example",
# "server_port": 51820,
# "clients": ["foo-phone", "bar-laptop"],
# "server_managed_keypairs": ["foo-phone"]
# }
#
# The commands below extract the necessary information from the config. Debug
# this extraction with `make debug-config`.
ifeq ("$(wildcard config.json)","")
$(error You must create config.json before running make)
endif
SERVER_IFACE := $(shell jq -r '.server_interface' config.json)
SERVER_HOSTNAME := $(shell jq -r '.server_hostname' config.json)
SERVER_PORT := $(shell jq -r '.server_port' config.json)
SERVER_MANAGED_KEYPAIRS := $(shell jq -r '.server_managed_keypairs|join(" ")' config.json)
CLIENTS := $(shell jq -r '.clients|join(" ")' config.json)
# Create target names for on-client config files. When generated, these files
# will contain private keys.
CLIENT_CONFIGS := $(patsubst %, gen/%.conf, $(CLIENTS))
# Create target names for on-server config files that describe the clients.
# These files will not contain private keys.
CLIENT_PEER_SECTIONS := $(patsubst %, gen/%.peer.conf, $(CLIENTS))
# Create names for phony targets that bring up/down individual peer interfaces.
ALL_PEERS_START_TARGETS := $(patsubst %, start-%, server $(CLIENTS))
ALL_PEERS_STOP_TARGETS := $(patsubst %, stop-%, server $(CLIENTS))
# Create target names for private and public keys.
SERVER_MANAGED_PRIVATE_KEYS := $(patsubst %, keys-%/private, $(SERVER_MANAGED_KEYPAIRS))
SERVER_MANAGED_PUBLIC_KEYS := $(patsubst %, keys-%/public, $(SERVER_MANAGED_KEYPAIRS))
# Nix carefully constructs the PATH, but sudo will ignore it by default. This
# command prefix preserves the PATH.
SUDO := sudo env PATH=$$PATH LOCALE_ARCHIVE=/usr/lib/locale/locale-archive
$(SERVER_MANAGED_PRIVATE_KEYS):
if [ ! -e $@ ]; then \
mkdir -p $$(dirname $@) && \
umask 077 && wg genkey > $@ ; \
fi
$(SERVER_MANAGED_PUBLIC_KEYS):
if [ ! -e $@ ]; then \
$(MAKE) $$(dirname $@)/private && \
umask 077 && wg pubkey < $$(dirname $@)/private > $@ ; \
fi
# Generate the Wireguard server config. Note that this file incorporates each of
# the client peer configs.
gen/server.conf: gen keys-server/private $(CLIENT_PEER_SECTIONS)
-rm -f $@
echo >> $@ '# This file was autogenerated by $(CURDIR)'
echo >> $@ [Interface]
echo >> $@ Address = 10.8.0.1/24
echo >> $@ PrivateKey = $$(cat keys-server/private)
echo >> $@ SaveConfig = true
echo >> $@ ListenPort = $(SERVER_PORT)
# Configure iptables on the server to masquerade traffic.
# https://wiki.archlinux.org/title/WireGuard#Server_configuration
echo >> $@ 'PostUp = iptables -A FORWARD -i %i -j ACCEPT; iptables -A FORWARD -o %i -j ACCEPT; iptables -t nat -A POSTROUTING -o $(SERVER_IFACE) -j MASQUERADE'
echo >> $@ 'PostDown = iptables -D FORWARD -i %i -j ACCEPT; iptables -D FORWARD -o %i -j ACCEPT; iptables -t nat -D POSTROUTING -o $(SERVER_IFACE) -j MASQUERADE'
echo >> $@
cat >> $@ $(CLIENT_PEER_SECTIONS)
$(CLIENT_PEER_SECTIONS): $(SERVER_MANAGED_PUBLIC_KEYS)
echo >> $@ "# ----- $@ -----"
echo >> $@ [Peer]
CLIENT_NAME=$$(basename $@ .peer.conf) && \
echo >> $@ PublicKey = $$(cat keys-$${CLIENT_NAME}/public) && \
echo >> $@ AllowedIPs = 10.8.0.$$(./unique_octet_for_client.py $${CLIENT_NAME} ${CLIENTS})/32, 10.8.0.0/24
echo >> $@
# This multi-target rule generates each client's config file. This assumes that
# the required private key is present in keys-${CLIENT_NAME}/.
$(CLIENT_CONFIGS): gen keys-server/public $(SERVER_MANAGED_PRIVATE_KEYS)
-rm $@
echo >> $@ [Interface]
CLIENT_NAME=$$(basename $@ .conf) && \
echo >> $@ Address = 10.8.0.$$(./unique_octet_for_client.py $${CLIENT_NAME} ${CLIENTS})/32
# I couldn't get bidirectional connections with Wireguard on iOS until setting
# the MTU to 1420.
echo >> $@ MTU = 1420
echo >> $@ DNS = 8.8.8.8
# Strip "gen/" prefix and ".conf" suffix from the target.
echo >> $@ PrivateKey = $$(cat keys-$$(basename $@ .conf)/private)
echo >> $@
echo >> $@ [Peer]
echo >> $@ PublicKey = $$(cat keys-server/public)
echo >> $@ AllowedIPs = 0.0.0.0/0
echo >> $@ Endpoint = $(SERVER_HOSTNAME):$(SERVER_PORT)
# It's not ideal to blast QR codes containing private keys to stdout, but it
# sure is convenient.
qrencode -t ansiutf8 < $@
gen:
mkdir -p $@
.PHONY: clean
clean:
-rm -rf gen/
# The following recipes are shortcuts on top of `wg-quick` for managing the
# server and clients.
.PHONY: status
status:
${SUDO} wg show
# TODO: Figure out why /etc/server.conf is not exactly the same as
# gen/server.conf. Seems like one of these steps is reformatting it and deleting
# comments. Confusingly, I can't start the systemd service if I delete the `cp`
# command from this recipe.
.PHONY: install-server
install-server: gen/server.conf
# Install the server's wireguard config.
-${SUDO} mkdir /etc/wireguard/
${SUDO} cp $< /etc/wireguard/
# Ensure that wg-quick has started the service so that we can find the
# wg-quick@server.service unit file.
${SUDO} wg-quick up $<
${SUDO} systemctl enable wg-quick@server.service
${SUDO} wg-quick down server
# Ensure we can start the service via systemd.
${SUDO} systemctl start wg-quick@server.service
${SUDO} systemctl status wg-quick@server.service
.PHONY: $(ALL_PEERS_START_TARGETS)
$(ALL_PEERS_START_TARGETS):
peer_config=gen/$$(sed s/start-// <<< $@).conf && \
${MAKE} $$peer_config && \
${SUDO} wg-quick up $$peer_config
if [ "$@" = "start-server" -a \
"$$(/usr/sbin/sysctl net.ipv4.ip_forward)" = "net.ipv4.ip_forward = 0" ]; then \
echo "WARNING: IPv4 forwarding is disabled! Enable it like so:" && \
echo " sudo sysctl net.ipv4.ip_forward=1"; \
fi
.PHONY: $(ALL_PEERS_STOP_TARGETS)
$(ALL_PEERS_STOP_TARGETS):
peer_config=gen/$$(sed s/stop-// <<< $@).conf && \
${MAKE} $$peer_config && \
${SUDO} wg-quick down $$peer_config
# The following recipes are only useful for debugging.
.PHONY: debug-config
debug-config: config.json
@echo "SERVER_IFACE: $(SERVER_IFACE)"
@echo "SERVER_HOSTNAME: $(SERVER_HOSTNAME)"
@echo "SERVER_PORT: $(SERVER_PORT)"
@echo "SERVER_MANAGED_KEYPAIRS: $(SERVER_MANAGED_KEYPAIRS)"
@echo "CLIENTS: $(CLIENTS)"
@echo
@echo "The values above should match the contents of $<:"
@jq . $<