Browse Source

Change allowed IPs client configuration (#3)

* Turned allowedIPs into per-client entry

AllowedIPs is no longer global set through ENV.  It is
configured during new client configuration.

* Added buttons for quickly setting allowedIPs

* Made WG_DEFAULT_DNS required in ENV

* Added buttons for quickly setting allowedIPs
pull/238/head
Joshua K 5 years ago
committed by joshuakraitberg
parent
commit
5f7bac0ef5
  1. 8
      .idea/.gitignore
  2. 6
      .idea/inspectionProfiles/profiles_settings.xml
  3. 4
      .idea/misc.xml
  4. 8
      .idea/modules.xml
  5. 0
      .idea/sonarlint/issuestore/index.pb
  6. 6
      .idea/vcs.xml
  7. 8
      .idea/wg-easy.iml
  8. 2
      docker-compose.yml
  9. 9
      src/config.js
  10. 7
      src/lib/Server.js
  11. 12
      src/lib/WireGuard.js
  12. 16
      src/www/index.html
  13. 11
      src/www/js/api.js
  14. 20
      src/www/js/app.js

8
.idea/.gitignore

@ -0,0 +1,8 @@
# Default ignored files
/shelf/
/workspace.xml
# Editor-based HTTP Client requests
/httpRequests/
# Datasource local storage ignored files
/dataSources/
/dataSources.local.xml

6
.idea/inspectionProfiles/profiles_settings.xml

@ -0,0 +1,6 @@
<component name="InspectionProjectProfileManager">
<settings>
<option name="USE_PROJECT_PROFILE" value="false" />
<version value="1.0" />
</settings>
</component>

4
.idea/misc.xml

@ -0,0 +1,4 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="ProjectRootManager" version="2" project-jdk-name="Poetry (comp_handbook)" project-jdk-type="Python SDK" />
</project>

8
.idea/modules.xml

@ -0,0 +1,8 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="ProjectModuleManager">
<modules>
<module fileurl="file://$PROJECT_DIR$/.idea/wg-easy.iml" filepath="$PROJECT_DIR$/.idea/wg-easy.iml" />
</modules>
</component>
</project>

0
.idea/sonarlint/issuestore/index.pb

6
.idea/vcs.xml

@ -0,0 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="VcsDirectoryMappings">
<mapping directory="$PROJECT_DIR$" vcs="Git" />
</component>
</project>

8
.idea/wg-easy.iml

@ -0,0 +1,8 @@
<?xml version="1.0" encoding="UTF-8"?>
<module type="PYTHON_MODULE" version="4">
<component name="NewModuleRootManager">
<content url="file://$MODULE_DIR$" />
<orderEntry type="inheritedJdk" />
<orderEntry type="sourceFolder" forTests="false" />
</component>
</module>

2
docker-compose.yml

@ -5,7 +5,7 @@ services:
# ⚠️ Required:
# Change this to your host's public address
- WG_HOST=raspberrypi.local
- WG_DEFAULT_DNS=9.9.9.9
# Optional:
# - PASSWORD=foobar123
# - WG_PORT=51820

9
src/config.js

@ -16,11 +16,6 @@ module.exports.WG_DEFAULT_DNS = typeof process.env.WG_DEFAULT_DNS === 'string'
: '1.1.1.1';
module.exports.WG_ALLOWED_IPS = process.env.WG_ALLOWED_IPS || '0.0.0.0/0, ::/0';
module.exports.WG_POST_UP = process.env.WG_POST_UP || `
iptables -t nat -A POSTROUTING -s ${module.exports.WG_DEFAULT_ADDRESS.replace('x', '0')}/24 -o eth0 -j MASQUERADE;
iptables -A INPUT -p udp -m udp --dport 51820 -j ACCEPT;
iptables -A FORWARD -i wg0 -j ACCEPT;
iptables -A FORWARD -o wg0 -j ACCEPT;
`.split('\n').join(' ');
module.exports.WG_POST_UP = process.env.WG_POST_UP || '';
module.exports.WG_POST_DOWN = process.env.WG_POST_DOWN || '';
module.exports.WG_DEFAULT_DNS = process.env.WG_DEFAULT_DNS;

7
src/lib/Server.js

@ -86,6 +86,9 @@ module.exports = class Server {
debug(`Deleted Session: ${sessionId}`);
}))
.get('/api/wireguard/dns', Util.promisify(async req => {
return WireGuard.getDns();
}))
.get('/api/wireguard/client', Util.promisify(async req => {
return WireGuard.getClients();
}))
@ -105,8 +108,8 @@ module.exports = class Server {
res.send(config);
}))
.post('/api/wireguard/client', Util.promisify(async req => {
const { name } = req.body;
return WireGuard.createClient({ name });
const { name, allowedIPs } = req.body;
return WireGuard.createClient({ name, allowedIPs });
}))
.delete('/api/wireguard/client/:clientId', Util.promisify(async req => {
const { clientId } = req.params;

12
src/lib/WireGuard.js

@ -122,6 +122,10 @@ AllowedIPs = ${client.address}/32`;
debug('Config synced.');
}
async getDns() {
return WG_DEFAULT_DNS ? WG_DEFAULT_DNS : null;
}
async getClients() {
const config = await this.getConfig();
const clients = Object.entries(config.clients).map(([clientId, client]) => ({
@ -198,7 +202,7 @@ ${WG_MTU ? `MTU = ${WG_MTU}` : ''}
[Peer]
PublicKey = ${config.server.publicKey}
PresharedKey = ${client.preSharedKey}
AllowedIPs = ${WG_ALLOWED_IPS}
AllowedIPs = ${client.allowedIPs}
PersistentKeepalive = ${WG_PERSISTENT_KEEPALIVE}
Endpoint = ${WG_HOST}:${WG_PORT}`;
}
@ -211,10 +215,13 @@ Endpoint = ${WG_HOST}:${WG_PORT}`;
});
}
async createClient({ name }) {
async createClient({ name, allowedIPs }) {
if (!name) {
throw new Error('Missing: Name');
}
if (!allowedIPs) {
throw new Error('Missing: allowedIPs');
}
const config = await this.getConfig();
@ -247,6 +254,7 @@ Endpoint = ${WG_HOST}:${WG_PORT}`;
privateKey,
publicKey,
preSharedKey,
allowedIPs: allowedIPs,
createdAt: new Date(),
updatedAt: new Date(),

16
src/www/index.html

@ -54,7 +54,7 @@
<p class="text-2xl font-medium">Clients</p>
</div>
<div class="flex-shrink-0">
<button @click="clientCreate = true; clientCreateName = '';"
<button @click="clientCreate = true; clientCreateName = ''; clientCreateAllowedIPs = clientCreateAllowedIPsDefault;"
class="hover:bg-red-800 hover:border-red-800 hover:text-white text-gray-700 border-2 border-gray-100 py-2 px-4 rounded inline-flex items-center transition">
<svg class="w-4 mr-2" inline xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24"
stroke="currentColor">
@ -236,7 +236,7 @@
</div>
<div v-if="clients && clients.length === 0">
<p class="text-center m-10 text-gray-400 text-sm">There are no clients yet.<br /><br />
<button @click="clientCreate = true; clientCreateName = '';"
<button @click="clientCreate = true; clientCreateName = ''; clientCreateAllowedIPs = clientCreateAllowedIPsDefault;"
class="bg-red-800 text-white hover:bg-red-700 border-2 border-none py-2 px-4 rounded inline-flex items-center transition">
<svg class="w-4 mr-2" inline xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24"
stroke="currentColor">
@ -324,6 +324,16 @@
<p class="text-sm text-gray-500">
<input class="rounded p-2 border-2 border-gray-100 focus:border-gray-200 outline-none w-full"
type="text" v-model.trim="clientCreateName" placeholder="Name" />
<input class="rounded p-2 border-2 border-gray-100 focus:border-gray-200 outline-none w-full"
type="text" v-model.trim="clientCreateAllowedIPs" placeholder="AllowedIPs" />
<button type="button" @click="clientCreateAllowedIPs = clientCreateAllowedIPsDefault"
class="w-full inline-flex justify-center rounded-md border border-transparent shadow-sm px-4 py-2 bg-red-800 text-base font-medium text-white hover:bg-red-700 focus:outline-none sm:ml-3 sm:w-auto sm:text-sm">
Allow all IPs
</button>
<button type="button" @click="clientCreateAllowedIPs; getDns().then(dns => {clientCreateAllowedIPs = dns == null ? clientCreateAllowedIPsExclude : `${clientCreateAllowedIPsExclude}, ${dns}/32`;});"
class="w-full inline-flex justify-center rounded-md border border-transparent shadow-sm px-4 py-2 bg-red-800 text-base font-medium text-white hover:bg-red-700 focus:outline-none sm:ml-3 sm:w-auto sm:text-sm">
Exclude private IPs
</button>
</p>
</div>
</div>
@ -482,4 +492,4 @@
<script src="./js/app.js"></script>
</body>
</html>
</html>

11
src/www/js/api.js

@ -58,6 +58,13 @@ class API {
});
}
async getDns() {
return this.call({
method: 'get',
path: '/wireguard/dns',
});
}
async getClients() {
return this.call({
method: 'get',
@ -72,11 +79,11 @@ class API {
})));
}
async createClient({ name }) {
async createClient({ name, allowedIPs }) {
return this.call({
method: 'post',
path: '/wireguard/client',
body: { name },
body: { name, allowedIPs },
});
}

20
src/www/js/app.js

@ -39,6 +39,19 @@ new Vue({
clientDelete: null,
clientCreate: null,
clientCreateName: '',
clientCreateAllowedIPs: '',
clientCreateAllowedIPsDefault: '0.0.0.0/0, ::0/0',
clientCreateAllowedIPsExclude: (
"::/0, 1.0.0.0/8, 2.0.0.0/8, 3.0.0.0/8, "
+ "4.0.0.0/6, 8.0.0.0/7, 11.0.0.0/8, 12.0.0.0/6, "
+ "16.0.0.0/4, 32.0.0.0/3, 64.0.0.0/2, 128.0.0.0/3, "
+ "160.0.0.0/5, 168.0.0.0/6, 172.0.0.0/12, 172.32.0.0/11, "
+ "172.64.0.0/10, 172.128.0.0/9, 173.0.0.0/8, 174.0.0.0/7, "
+ "176.0.0.0/4, 192.0.0.0/9, 192.128.0.0/11, 192.160.0.0/13, "
+ "192.169.0.0/16, 192.170.0.0/15, 192.172.0.0/14, 192.176.0.0/12, "
+ "192.192.0.0/10, 193.0.0.0/8, 194.0.0.0/7, 196.0.0.0/6, "
+ "200.0.0.0/5, 208.0.0.0/4"
),
clientEditName: null,
clientEditNameId: null,
clientEditAddress: null,
@ -210,11 +223,16 @@ new Vue({
alert(err.message || err.toString());
});
},
getDns() {
return this.api.getDns()
},
createClient() {
const name = this.clientCreateName;
const allowedIPs = this.clientCreateAllowedIPs;
if (!name) return;
if (!allowedIPs) return;
this.api.createClient({ name })
this.api.createClient({ name, allowedIPs })
.catch(err => alert(err.message || err.toString()))
.finally(() => this.refresh().catch(console.error));
},

Loading…
Cancel
Save