wireguard: Add client info view

Signed-off-by: James Valleroy <jvalleroy@mailbox.org>
Reviewed-by: Sunil Mohan Adapa <sunil@medhas.org>
This commit is contained in:
James Valleroy 2019-09-06 10:09:23 -04:00
parent 415e1eb4ba
commit 5d287ce579
No known key found for this signature in database
GPG Key ID: 77C0C75E7B650808
6 changed files with 127 additions and 30 deletions

View File

@ -23,6 +23,8 @@ import argparse
import json import json
import subprocess import subprocess
PUBLIC_KEY_HELP = 'Public key for the client'
SERVER_INTERFACE = 'wg0' SERVER_INTERFACE = 'wg0'
@ -32,14 +34,14 @@ def parse_arguments():
subparsers = parser.add_subparsers(dest='subcommand', help='Sub command') subparsers = parser.add_subparsers(dest='subcommand', help='Sub command')
subparsers.add_parser('setup', help='Setup WireGuard') subparsers.add_parser('setup', help='Setup WireGuard')
subparsers.add_parser('list-clients', help='List all clients') subparsers.add_parser('get-info', help='Get server and clients info')
add_client = subparsers.add_parser('add-client', help='Add a client') add_client = subparsers.add_parser('add-client', help='Add a client')
add_client.add_argument('publickey', help='Public key for the client') add_client.add_argument('publickey', help=PUBLIC_KEY_HELP)
remove_client = subparsers.add_parser('remove-client', remove_client = subparsers.add_parser('remove-client',
help='Remove a client') help='Remove a client')
remove_client.add_argument('publickey', help='Public key for the client') remove_client.add_argument('publickey', help=PUBLIC_KEY_HELP)
subparsers.required = True subparsers.required = True
return parser.parse_args() return parser.parse_args()
@ -52,23 +54,39 @@ def subcommand_setup(_):
check=True) check=True)
def subcommand_list_clients(_): def subcommand_get_info(_):
"""List all clients.""" """Get server and clients info."""
clients = []
output = subprocess.check_output( output = subprocess.check_output(
['wg', 'show', SERVER_INTERFACE, 'latest-handshakes']).decode().strip() ['wg', 'show', SERVER_INTERFACE, 'dump']).decode().strip()
for client_info in output.split('\n'): lines = output.split('\n')
try: server_data = lines.pop(0).split()
public_key, latest_handshake = client_info.split() server = {
except ValueError: 'private_key': server_data[0],
continue 'public_key': server_data[1],
'listen_port': server_data[2],
'fwmark': server_data[3],
}
clients.append({ clients = []
'public_key': public_key, for client_line in lines:
'latest_handshake': latest_handshake, client_data = client_line.split()
}) client_info = {
'public_key': client_data[0],
'preshared_key': client_data[1],
'endpoint': client_data[2],
'allowed_ips': client_data[3],
'latest_handshake': client_data[4],
'transfer_rx': client_data[5],
'transfer_tx': client_data[6],
'persistent_keepalive': client_data[7],
}
clients.append(client_info)
print(json.dumps(clients)) info = {
'server': server,
'clients': clients,
}
print(json.dumps(info))
def subcommand_add_client(arguments): def subcommand_add_client(arguments):

View File

@ -18,6 +18,8 @@
FreedomBox app for wireguard. FreedomBox app for wireguard.
""" """
import json
from django.urls import reverse_lazy from django.urls import reverse_lazy
from django.utils.translation import ugettext_lazy as _ from django.utils.translation import ugettext_lazy as _
@ -98,3 +100,9 @@ def setup(helper, old_version=None):
helper.install(managed_packages) helper.install(managed_packages)
helper.call('post', actions.superuser_run, 'wireguard', ['setup']) helper.call('post', actions.superuser_run, 'wireguard', ['setup'])
helper.call('post', app.enable) helper.call('post', app.enable)
def get_info():
"""Get server and clients info."""
info = actions.superuser_run('wireguard', ['get-info'])
return json.loads(info)

View File

@ -26,23 +26,38 @@
<p>{% trans "Peers allowed to connect to this server" %}</p> <p>{% trans "Peers allowed to connect to this server" %}</p>
<table class="table table-bordered table-condensed table-striped" <table class="table table-bordered table-condensed table-striped"
id="server-clients-list"> id="server-clients-list">
<tr> <tr>
<th>{% trans "Public Key" %}</th> <th>{% trans "Public Key" %}</th>
<th>{% trans "Last Connected Time" %}</th> <th>{% trans "Last Connected Time" %}</th>
<th>{% trans "Delete" %}</th> <th>{% trans "Delete" %}</th>
</tr> </tr>
{% for client in server_clients %} {% if server_clients %}
{% for client in server_clients %}
<tr>
<td>
<a href="{% url 'wireguard:show-client' client.public_key %}">
{{ client.public_key }}
</a>
</td>
<td>{{ client.latest_handshake }}</td>
<td><a class="btn btn-sm btn-default"
href="{% url 'wireguard:delete-client' client.public_key %}">
<span class="fa fa-trash-o" aria-hidden="true">
</span>
</td>
</tr>
{% endfor %}
{% else %}
<tr> <tr>
<td>{{ client.public_key }}</td> <td>
<td>{{ client.latest_handshake }}</td> {% blocktrans trimmed %}
<td><a class="btn btn-sm btn-default" No peers configured to connect to this {{ box_name }} yet.
href="{% url 'wireguard:delete-client' client.public_key %}"> {% endblocktrans %}
<span class="fa fa-trash-o" aria-hidden="true">
</span>
</td> </td>
</tr> </tr>
{% endfor %} {% endif %}
</table> </table>
<a title="{% trans 'Add a new peer' %}" <a title="{% trans 'Add a new peer' %}"

View File

@ -0,0 +1,39 @@
{% extends "base.html" %}
{% comment %}
#
# This file is part of FreedomBox.
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU Affero General Public License as
# published by the Free Software Foundation, either version 3 of the
# License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU Affero General Public License for more details.
#
# You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#
{% endcomment %}
{% load i18n %}
{% block content %}
<h3>{{ title }}</h3>
<h4>{% trans "Connection Information" %}</h4>
<p>{% trans "IP address to use:" %}</p>
<p>{% trans "Server endpoints:" %}</p>
<p>{% trans "Server's public key:" %} {{ server.public_key }}</p>
<p>{% trans "Pre-shared key:" %}</p>
<h4>{% trans "Status" %}</h4>
<p>{% trans "Client Public Key:" %} {{ client.public_key }}</p>
<p>{% trans "Data transmitted:" %} {{ client.transfer_tx }}</p>
<p>{% trans "Data received:" %} {{ client.transfer_rx }}</p>
<p>{% trans "Latest handshake:" %} {{ client.latest_handshake }}</p>
{% endblock %}

View File

@ -26,6 +26,8 @@ urlpatterns = [
url(r'^apps/wireguard/$', views.WireguardView.as_view(), name='index'), url(r'^apps/wireguard/$', views.WireguardView.as_view(), name='index'),
url(r'^apps/wireguard/client/add/$', views.AddClientView.as_view(), url(r'^apps/wireguard/client/add/$', views.AddClientView.as_view(),
name='add-client'), name='add-client'),
url(r'^apps/wireguard/client/(?P<public_key>[^/]+)/show/$',
views.ShowClientView.as_view(), name='show-client'),
url(r'^apps/wireguard/client/(?P<public_key>[^/]+)/delete/$', url(r'^apps/wireguard/client/(?P<public_key>[^/]+)/delete/$',
views.DeleteClientView.as_view(), name='delete-client'), views.DeleteClientView.as_view(), name='delete-client'),
] ]

View File

@ -18,8 +18,6 @@
Views for WireGuard application. Views for WireGuard application.
""" """
import json
from django.contrib import messages from django.contrib import messages
from django.contrib.messages.views import SuccessMessageMixin from django.contrib.messages.views import SuccessMessageMixin
from django.shortcuts import redirect from django.shortcuts import redirect
@ -48,8 +46,8 @@ class WireguardView(AppView):
def get_context_data(self, **kwargs): def get_context_data(self, **kwargs):
"""Return additional context for rendering the template.""" """Return additional context for rendering the template."""
context = super().get_context_data(**kwargs) context = super().get_context_data(**kwargs)
clients_list = actions.superuser_run('wireguard', ['list-clients']) info = wireguard.get_info()
context['server_clients'] = json.loads(clients_list) context['server_clients'] = info['clients']
return context return context
@ -73,6 +71,23 @@ class AddClientView(SuccessMessageMixin, FormView):
return super().form_valid(form) return super().form_valid(form)
class ShowClientView(SuccessMessageMixin, TemplateView):
"""View to show a client's details."""
template_name = 'wireguard_show_client.html'
def get_context_data(self, **kwargs):
"""Return additional context data for rendering the template."""
context = super().get_context_data(**kwargs)
context['title'] = _('Show Client')
public_key = self.kwargs['public_key']
info = wireguard.get_info()
context['server'] = info['server']
for client in info['clients']:
if client['public_key'] == public_key:
context['client'] = client
return context
class DeleteClientView(SuccessMessageMixin, TemplateView): class DeleteClientView(SuccessMessageMixin, TemplateView):
"""View to delete a client.""" """View to delete a client."""
template_name = 'wireguard_delete_client.html' template_name = 'wireguard_delete_client.html'