2 Copyright 2016-2017 Dan Luedtke <mail@danrl.com>
3 Licensed to the public under the Apache License 2.0.
8 return (s:gsub("^%s*(.-)%s*$", "%1"))
12 return (string.len(strip(s)) > 0)
15 function peer_add(peers, public_key)
17 public_key = public_key,
21 latest_handshake = -1,
22 persistent_keepalive = "",
27 function peer_set_transfer(peers, public_key, rx, tx)
28 for key, peer in pairs(peers) do
29 if peer.public_key == public_key then
30 peers[key].transfer_rx = rx
31 peers[key].transfer_tx = tx
37 function peer_set_latest_handshake(peers, public_key, latest_handshake)
38 for key, peer in pairs(peers) do
39 if peer.public_key == public_key then
40 peers[key].latest_handshake = latest_handshake
46 function peer_set_endpoint(peers, public_key, endpoint)
47 for key, peer in pairs(peers) do
48 if peer.public_key == public_key then
49 peers[key].endpoint = endpoint
55 function peer_set_persistent_keepalive(peers, public_key, persistent_keepalive)
56 for key, peer in pairs(peers) do
57 if peer.public_key == public_key then
58 peers[key].persistent_keepalive = persistent_keepalive
64 function peer_set_allowed_ips(peers, public_key, allowed_ips)
65 for key, peer in pairs(peers) do
66 if peer.public_key == public_key then
67 for ipkey, ipvalue in pairs(string.split(allowed_ips, " ")) do
68 if is_valid(ipvalue) then
69 table.insert(peers[key].allowed_ips, strip(ipvalue))
79 local wg_ifaces = luci.sys.exec("wg show interfaces")
80 for key, name in pairs(string.split(wg_ifaces, "\n")) do
81 if not is_valid(name) then break end
83 local public_key = luci.sys.exec("wg show \"" .. name .. "\" public-key")
84 local listening_port = luci.sys.exec("wg show \"" .. name .. "\" listen-port")
87 local wg_peers = luci.sys.exec("wg show \"" .. name .. "\" peers")
88 for key, public_key in pairs(string.split(wg_peers, "\n")) do
89 if not is_valid(public_key) then break end
90 peer_add(peers, public_key)
93 local wg_endpoints = luci.sys.exec("wg show \"" .. name .. "\" endpoints")
94 for key, endpoint in pairs(string.split(wg_endpoints, "\n")) do
95 if not is_valid(endpoint) then break end
96 local ln = string.split(strip(endpoint), "\t")
97 peer_set_endpoint(peers, ln[1], strip(ln[2]))
100 local wg_allowed_ips = luci.sys.exec("wg show \"" .. name .. "\" allowed-ips")
101 for key, allowed_ips in pairs(string.split(wg_allowed_ips, "\n")) do
102 if not is_valid(allowed_ips) then break end
103 local ln = string.split(strip(allowed_ips), "\t", 2)
104 peer_set_allowed_ips(peers, ln[1], strip(ln[2]))
107 local wg_persistent_keepalives = luci.sys.exec("wg show \"" .. name .. "\" persistent-keepalive")
108 for key, persistent_keepalive in pairs(string.split(wg_persistent_keepalives, "\n")) do
109 if not is_valid(persistent_keepalive) then break end
110 local ln = string.split(strip(persistent_keepalive), "\t")
111 peer_set_persistent_keepalive(peers, strip(ln[1]), strip(ln[2]))
114 local wg_latest_handshakes = luci.sys.exec("wg show \"" .. name .. "\" latest-handshakes")
115 for key, latest_handshake in pairs(string.split(wg_latest_handshakes, "\n")) do
116 if not is_valid(latest_handshake) then break end
117 local ln = string.split(strip(latest_handshake), "\t")
118 peer_set_latest_handshake(peers, strip(ln[1]), tonumber(ln[2]))
121 local wg_transfers = luci.sys.exec("wg show \"" .. name .. "\" transfer")
122 for key, transfer in pairs(string.split(wg_transfers, "\n")) do
123 if not is_valid(transfer) then break end
124 local ln = string.split(strip(transfer), "\t")
125 peer_set_transfer(peers, ln[1], strip(ln[2]), strip(ln[3]))
130 public_key = strip(public_key),
131 listening_port = tonumber(strip(listening_port)),
136 if luci.http.formvalue("status") == "1" then
137 luci.http.prepare_content("application/json")
138 luci.http.write_json(data)
145 <script type="text/javascript" src="<%=resource%>/cbi.js"></script>
146 <script type="text/javascript">//<![CDATA[
148 function bytes_to_str(bytes) {
149 var sizes = ['B', 'KiB', 'MiB', 'GiB', 'TiB', 'PiB'];
150 var i = parseInt(Math.floor(Math.log(bytes) / Math.log(1024)));
151 return Math.round(bytes / Math.pow(1024, i), 2) + ' ' + sizes[i];
154 function timestamp_to_str(timestamp) {
155 var now = new Date();
156 var seconds = (now.getTime() / 1000) - timestamp;
158 return parseInt(seconds) + '<%:s ago%>';
160 else if (seconds < 3600){
161 return parseInt(seconds / 60) + '<%:m ago%>';
163 else if (seconds < 86400){
164 return parseInt(seconds / 3600) + '<%:h ago%>';
166 return '<%:over a day ago%>';
170 XHR.poll(5, '<%=REQUEST_URI%>', { status: 1 },
172 for (var i = 0, ilen = data.length; i < ilen; i++) {
174 var ifid = iface['public_key'] + "_";
175 var s = String.format(
176 '<strong><%:Public Key%>: </strong>%s' +
177 '<br /><strong><%:Listening Port%>: </strong>%<%:s%>',
179 iface['listening_port']
181 document.getElementById(ifid + "info").innerHTML = s;
182 for (var j = 0, jlen = iface['peers'].length; j < jlen; j++) {
183 var peer = iface['peers'][j];
184 var pid = ifid + peer['public_key'] + "_";
186 '<strong><%:Public Key%>: </strong>%s',
189 if (peer['endpoint'] != '(none)') {
191 '<br /><strong><%:Endpoint%>: </strong>%s',
195 if (peer['allowed_ips'].length > 0) {
196 s += '<br /><strong><%:Allowed IPs%>:</strong>';
197 for (var k = 0, klen = peer['allowed_ips'].length; k < klen; k++) {
198 s += '<br /> • ' + peer['allowed_ips'][k];
201 if (peer['persistent_keepalive'] != 'off') {
203 '<br /><strong><%:Persistent Keepalive%>: </strong>%ss',
204 peer['persistent_keepalive']
207 var icon = '<img src="<%=resource%>/icons/tunnel_disabled.png" />';
208 if (((now.getTime() / 1000) - peer['latest_handshake']) < 140) {
209 icon = '<img src="<%=resource%>/icons/tunnel.png" />';
211 '<br /><strong><%:Latest Handshake%>: </strong>%s',
212 timestamp_to_str(peer['latest_handshake'])
216 '<br /><strong><%:Data Received%>: </strong>%s' +
217 '<br /><strong><%:Data Transmitted%>: </strong>%s',
218 bytes_to_str(peer['transfer_rx']),
219 bytes_to_str(peer['transfer_tx'])
221 document.getElementById(pid + "icon").innerHTML = icon;
222 document.getElementById(pid + "info").innerHTML = s;
228 <h2>WireGuard Status</h2>
231 <fieldset class="cbi-section">
233 for key, iface in pairs(data) do
234 local ifid = iface.public_key .. "_"
236 <legend><%:Interface%> <%=iface.name%></legend>
237 <table width="100%" cellspacing="10">
239 <td width="33%" style="vertical-align:top"><%:Configuration%></td>
243 <td id="<%=ifid%>icon" style="width:16px; text-align:center; padding:3px">
246 <td id="<%=ifid%>info" style="vertical-align:middle; padding: 3px">
247 <em><%:Collecting data...%></em>
253 for key, peer in pairs(iface.peers) do
254 local pid = ifid .. peer.public_key .. "_"
257 <td width="33%" style="vertical-align:top"><%:Peer%></td>
261 <td id="<%=pid%>icon" style="width:16px; text-align:center; padding:3px">
262 <img src="<%=resource%>/icons/tunnel_disabled.png" /><br />
265 <td id="<%=pid%>info" style="vertical-align:middle; padding: 3px">
266 <em><%:Collecting data...%></em>