luci.wireguard 2.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120
  1. // Copyright 2022 Jo-Philipp Wich <jo@mein.io>
  2. // Licensed to the public under the Apache License 2.0.
  3. 'use strict';
  4. import { cursor } from 'uci';
  5. import { popen } from 'fs';
  6. function shellquote(s) {
  7. return `'${replace(s ?? '', "'", "'\\''")}'`;
  8. }
  9. function command(cmd) {
  10. return trim(popen(cmd)?.read?.('all'));
  11. }
  12. function checkPeerHost(configHost, configPort, wgHost) {
  13. const ips = popen(`resolveip ${configHost} 2>/dev/null`);
  14. if (ips) {
  15. for (let line = ips.read('line'); length(line); line = ips.read('line')) {
  16. const ip = rtrim(line, '\n');
  17. if (ip + ":" + configPort == wgHost) {
  18. return true;
  19. }
  20. }
  21. }
  22. return false;
  23. }
  24. const methods = {
  25. generatePsk: {
  26. call: function() {
  27. return { psk: command('wg genpsk 2>/dev/null') };
  28. }
  29. },
  30. generateKeyPair: {
  31. call: function() {
  32. const priv = command('wg genkey 2>/dev/null');
  33. const pub = command(`echo ${shellquote(priv)} | wg pubkey 2>/dev/null`);
  34. return { keys: { priv, pub } };
  35. }
  36. },
  37. getPublicAndPrivateKeyFromPrivate: {
  38. args: { privkey: "privkey" },
  39. call: function(req) {
  40. const priv = req.args?.privkey;
  41. const pub = command(`echo ${shellquote(priv)} | wg pubkey 2>/dev/null`);
  42. return { keys: { priv, pub } };
  43. }
  44. },
  45. getWgInstances: {
  46. call: function() {
  47. const data = {};
  48. let last_device;
  49. let qr_pubkey = {};
  50. const uci = cursor();
  51. const wg_dump = popen("wg show all dump 2>/dev/null");
  52. if (wg_dump) {
  53. uci.load("network");
  54. for (let line = wg_dump.read('line'); length(line); line = wg_dump.read('line')) {
  55. const record = split(rtrim(line, '\n'), '\t');
  56. if (last_device != record[0]) {
  57. last_device = record[0];
  58. data[last_device] = {
  59. name: last_device,
  60. public_key: record[2],
  61. listen_port: record[3],
  62. fwmark: record[4],
  63. peers: []
  64. };
  65. if (!length(record[2]) || record[2] == '(none)')
  66. qr_pubkey[last_device] = '';
  67. else
  68. qr_pubkey[last_device] = `PublicKey = ${record[2]}`;
  69. }
  70. else {
  71. let peer_name;
  72. uci.foreach('network', `wireguard_${last_device}`, (s) => {
  73. if (!s.disabled && s.public_key == record[1] && (!s.endpoint_host || checkPeerHost(s.endpoint_host, s.endpoint_port, record[3])))
  74. peer_name = s.description;
  75. });
  76. const peer = {
  77. name: peer_name,
  78. public_key: record[1],
  79. endpoint: record[3],
  80. allowed_ips: [],
  81. latest_handshake: record[5],
  82. transfer_rx: record[6],
  83. transfer_tx: record[7],
  84. persistent_keepalive: record[8]
  85. };
  86. if (record[3] != '(none)' && length(record[4]))
  87. push(peer.allowed_ips, ...split(record[4], ','));
  88. push(data[last_device].peers, peer);
  89. }
  90. }
  91. }
  92. return data;
  93. }
  94. }
  95. };
  96. return { 'luci.wireguard': methods };