2 Copyright
2016-
2017 Dan Luedtke
<mail@danrl.com
>
3 Licensed to the public under the Apache License
2.0.
7 local uci = uci.cursor()
12 local function wg_clean(value)
13 if value and value ==
"(none)" then
19 local wg_dump = io.popen(
"wg show all dump")
22 for line in wg_dump:lines() do
23 local line = string.split(line,
"\t")
24 if not (last_device == line[
1]) then
29 listen_port = line[
4],
33 local s = uci:get_list(
"network", line[
1],
"addresses")
36 for key, value in pairs(s) do
38 address = address..
", " ..value
43 enc[line[
1]] =
"[Interface]\nPrivateKey = " ..wg_clean(line[
2])..
"\nAddress = " ..address
49 latest_handshake = line[
6],
50 transfer_rx = line[
7],
51 transfer_tx = line[
8],
52 persistent_keepalive = line[
9]
54 if not (line[
4] == '(none)') then
56 for ipkey, ipvalue in pairs(string.split(line[
5],
",")) do
58 table.insert(peer['allowed_ips'], ipvalue)
62 table.insert(data[line[
1]].peers, peer)
63 enc[line[
1]] = enc[line[
1]]..
"\n\n[Peer]\nEndpoint = " ..wg_clean(line[
4])..
"\nPublicKey = " ..wg_clean(line[
2])..
"\nAllowedIPs = " ..wg_clean(line[
5])
68 if luci.http.formvalue(
"status") ==
"1" then
69 luci.http.prepare_content(
"application/json")
70 luci.http.write_json(data)
77 <script type=
"text/javascript">//<![CDATA[
79 function bytes_to_str(bytes) {
80 bytes = parseFloat(bytes);
81 if (bytes <
1) { return
"0 B"; }
82 var sizes = ['B', 'KiB', 'MiB', 'GiB', 'TiB', 'PiB'];
83 var i = parseInt(Math.floor(Math.log(bytes) / Math.log(
1024)));
84 return Math.round(bytes / Math.pow(
1024, i),
2) + ' ' + sizes[i];
87 function timestamp_to_str(timestamp) {
92 var seconds = (now.getTime() /
1000) - timestamp;
95 ago = parseInt(seconds) + '<%:s ago%
>';
96 } else if (seconds <
3600) {
97 ago = parseInt(seconds /
60) + '<%:m ago%
>';
98 } else if (seconds <
86401) {
99 ago = parseInt(seconds /
3600) + '<%:h ago%
>';
101 ago = '<%:over a day ago%
>';
103 var t = new Date(timestamp *
1000);
104 return t.toUTCString() + ' (' + ago + ')';
107 function toggle_qrcode(iface) {
108 var view = document.getElementById(iface.name);
109 if (view.style.display ===
"none") {
110 view.style.display =
"block";
112 view.style.display =
"none";
116 XHR.poll(-
1, '<%=REQUEST_URI%
>', { status:
1 },
118 for (var key in data) {
119 if (!data.hasOwnProperty(key)) { continue; }
121 var iface = data[key];
123 if (iface.public_key == '(none)') {
124 s += '
<em><%:Interface does not have a public key!%
></em>';
127 '
<strong><%:Public Key%
>:
</strong>%s',
131 if (iface.listen_port
> 0) {
133 '
<br /><strong><%:Listen Port%
>:
</strong>%s',
137 if (iface.fwmark != 'off') {
139 '
<br /><strong><%:Firewall Mark%
>:
</strong>%s',
143 document.getElementById(ifname +
"_info").innerHTML = s;
144 for (var i =
0, ilen = iface.peers.length; i < ilen; i++) {
145 var peer = iface.peers[i];
146 var s = String.format(
147 '
<strong><%:Public Key%
>:
</strong>%s',
150 if (peer.endpoint != '(none)') {
152 '
<br /><strong><%:Endpoint%
>:
</strong>%s',
156 if (peer.allowed_ips.length
> 0) {
157 s += '
<br /><strong><%:Allowed IPs%
>:
</strong>';
158 for (var k =
0, klen = peer.allowed_ips.length; k < klen; k++) {
159 s += '
<br />  • ' + peer.allowed_ips[k];
162 if (peer.persistent_keepalive != 'off') {
164 '
<br /><strong><%:Persistent Keepalive%
>:
</strong>%ss',
165 peer.persistent_keepalive
168 var icon = '
<img src=
"<%=resource%>/icons/tunnel_disabled.png" />';
169 var now = new Date();
170 if (((now.getTime() /
1000) - peer.latest_handshake) <
140) {
171 icon = '
<img src=
"<%=resource%>/icons/tunnel.png" />';
174 '
<br /><strong><%:Latest Handshake%
>:
</strong>%s',
175 timestamp_to_str(peer.latest_handshake)
178 '
<br /><strong><%:Data Received%
>:
</strong>%s' +
179 '
<br /><strong><%:Data Transmitted%
>:
</strong>%s',
180 bytes_to_str(peer.transfer_rx),
181 bytes_to_str(peer.transfer_tx),
183 document.getElementById(ifname +
"_" + peer.public_key +
"_icon").innerHTML = icon;
184 document.getElementById(ifname +
"_" + peer.public_key +
"_info").innerHTML = s;
190 <h2>WireGuard Status
</h2>
192 <div class=
"cbi-section">
195 for ikey, iface in pairs(data) do
197 <h3><%:Interface%
> <%=ikey%
></h3>
198 <div class=
"cbi-value" id=
"button" style=
"padding: 5px">
199 <input class=
"cbi-button cbi-button-apply" type=
"button" name=
"qrcode_<%=ikey%>" value=
"<%:Show/Hide QR-Code%>" onclick=
"toggle_qrcode(this)" />
203 if fs.access(
"/usr/bin/qrencode") then
204 if enc[ikey]:sub(
26,
26) ~=
"\n" then
205 qrcode = luci.sys.exec(
"/usr/bin/qrencode --inline --8bit --type=SVG --output=- '" ..enc[ikey]..
"'")
208 qrcode =
"<em>For QR-Code support please install package 'qrencode'!</em>"
211 <div class=
"cbi-value-title">
212 <span class=
"cbi-value" style=
"display: none" id=
"qrcode_<%=ikey%>"><%=qrcode%
></span>
214 <div class=
"cbi-section-node">
215 <div class=
"table cbi-section-table">
216 <div class=
"tr cbi-section-table-row" style=
"text-align: left;">
217 <div class=
"td" style=
"text-align: left; vertical-align:top"><%:Configuration%
></div>
218 <div class=
"td" style=
"flex: 0 1 90%; text-align: left;">
219 <div class=
"table cbi-section-table" style=
"border: 0px;">
220 <div class=
"tr cbi-section-table-row" style=
"text-align: left; border: 0px;">
221 <div class=
"td" id=
"<%=ikey%>_icon" style=
"width: 22px; text-align: left; border-top: 0px; padding: 3px;"> </div>
222 <div class=
"td" id=
"<%=ikey%>_info" style=
"flex: 0 1 90%; text-align: left; vertical-align:middle; padding: 3px; border-top: 0px;"><em><%:Collecting data...%
></em></div>
228 local cur = uci.cursor()
230 for pkey, peer in pairs(iface.peers) do
232 cur:foreach(
"network",
"wireguard_" .. ikey, function(s)
233 local key, value, tmp_desc, pub_key
234 for key, value in pairs(s) do
235 if key ==
"description" then
238 if value == peer.public_key then
241 if pub_key and tmp_desc then
242 desc = ': ' ..tmp_desc
247 <div class=
"tr cbi-section-table-row" style=
"text-align: left;">
248 <div class=
"td" style=
"text-align: left; vertical-align:top"><%:Peer%
><%=desc%
></div>
249 <div class=
"td" style=
"flex: 0 1 90%; text-align: left;">
250 <div class=
"table cbi-section-table" style=
"border: 0px">
251 <div class=
"tr cbi-section-table-row" style=
"border: 0px;">
252 <div class=
"td" id=
"<%=ikey%>_<%=peer.public_key%>_icon" style=
"width:16px; text-align: left; padding: 3px;border-top: 0px;">
253 <img src=
"<%=resource%>/icons/tunnel_disabled.png" />
256 <div class=
"td" id=
"<%=ikey%>_<%=peer.public_key%>_info" style=
"flex: 0 1 90%; text-align: left; vertical-align:middle; padding: 3px;border-top: 0px;"><em><%:Collecting data...%
></em></div>