2
0

tunnels.js 7.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276
  1. 'use strict';
  2. 'require view';
  3. 'require form';
  4. 'require ui';
  5. 'require uci';
  6. 'require network';
  7. 'require validation';
  8. 'require tools.widgets as widgets';
  9. function calculateNetwork(addr, mask) {
  10. const parsedAddr = validation.parseIPv4(String(addr));
  11. if (parsedAddr == null) return null;
  12. const parsedMask = !isNaN(mask)
  13. ? validation.parseIPv4(network.prefixToMask(+mask))
  14. : validation.parseIPv4(String(mask));
  15. if (parsedMask == null) return null;
  16. const networkAddr = parsedAddr.map((byte, i) => byte & (parsedMask[i] >>> 0 & 255));
  17. return `${networkAddr.join('.')}/${network.maskToPrefix(parsedMask.join('.'))}`;
  18. }
  19. return view.extend({
  20. load: function() {
  21. return Promise.all([
  22. network.getDevices(),
  23. uci.load('libreswan'),
  24. ]);
  25. },
  26. render: function(data) {
  27. var netDevs = data[0];
  28. var m, s, o;
  29. var proposals;
  30. proposals = uci.sections('libreswan', 'crypto_proposal');
  31. if (proposals == '') {
  32. ui.addNotification(null, E('p', _('Proposals must be configured for Tunnels')));
  33. return;
  34. }
  35. m = new form.Map('libreswan', 'IPSec Tunnels');
  36. s = m.section(form.GridSection, 'tunnel');
  37. s.anonymous = false;
  38. s.addremove = true;
  39. s.nodedescription = false;
  40. s.addbtntitle = _('Add Tunnel');
  41. s.renderSectionAdd = function(extra_class) {
  42. var el = form.GridSection.prototype.renderSectionAdd.apply(this, arguments),
  43. nameEl = el.querySelector('.cbi-section-create-name');
  44. ui.addValidator(nameEl, 'uciname', true, function(v) {
  45. let sections = [
  46. ...uci.sections('libreswan', 'crypto_proposal'),
  47. ...uci.sections('libreswan', 'tunnel'),
  48. ];
  49. if (sections.find(function(s) {
  50. return s['.name'] == v;
  51. })) {
  52. return _('This may not share the same name as other proposals or configured tunnels.');
  53. }
  54. if (v.length > 15) return _('Name length shall not exceed 15 characters');
  55. return true;
  56. }, 'blur', 'keyup');
  57. return el;
  58. };
  59. o = s.tab('general', _('General'));
  60. o = s.tab('authentication', _('Authentication'));
  61. o = s.tab('interface', _('Interface'));
  62. o = s.tab('advanced', _('Advanced'));
  63. o = s.taboption('general', form.ListValue, 'auto', _('Mode'));
  64. o.default = 'start';
  65. o.value('add', _('Listen'));
  66. o.value('start', _('Initiate'));
  67. o = s.taboption('general', widgets.NetworkSelect, 'left_interface', _('Left Interface'));
  68. o.datatype = 'string';
  69. o.multiple = false;
  70. o.optional = true;
  71. o = s.taboption('general', form.Value, 'left', _('Left IP/Device'));
  72. o.datatype = 'or(string, ipaddr)';
  73. netDevs.forEach(netDev => {
  74. netDev.getIPAddrs().forEach(addr => {
  75. o.value(addr.split('/')[0]);
  76. });
  77. });
  78. netDevs.forEach(netDev => {
  79. o.value(`%${netDev.device}`);
  80. });
  81. o.value('%defaultroute');
  82. o.optional = false;
  83. o.depends({ 'left_interface' : '' });
  84. o = s.taboption('general', form.Value, 'leftid', _('Left ID'));
  85. o.datatype = 'string';
  86. o.value('%any');
  87. o.modalonly = true;
  88. o = s.taboption('general', form.Value, 'right', _('Remote IP'));
  89. o.datatype = 'or(string, ipaddr)';
  90. o.value('0.0.0.0');
  91. o.value('%any');
  92. o.optional = false;
  93. o = s.taboption('general', form.Value, 'rightid', _('Right ID'));
  94. o.datatype = 'string';
  95. o.value('%any');
  96. o.modalonly = true;
  97. o = s.taboption('general', form.Value, 'leftsourceip', _('Local Source IP'));
  98. o.datatype = 'ipaddr';
  99. netDevs.forEach(netDev => {
  100. netDev.getIPAddrs().forEach(addr => {
  101. o.value(addr.split('/')[0]);
  102. });
  103. });
  104. o.optional = false;
  105. o.modalonly = true;
  106. o = s.taboption('general', form.Value, 'rightsourceip', _('Remote Source IP'));
  107. o.datatype = 'ipaddr';
  108. o.optional = false;
  109. o.modalonly = true;
  110. o = s.taboption('general', form.DynamicList, 'leftsubnets', _('Local Subnets'));
  111. o.datatype = 'ipaddr';
  112. for (var i = 0; i < netDevs.length; i++) {
  113. var addrs = netDevs[i].getIPAddrs();
  114. for (var j = 0; j < addrs.length; j++) {
  115. var subnet = calculateNetwork(addrs[j].split('/')[0], addrs[j].split('/')[1]);
  116. if (subnet) {
  117. o.value(subnet);
  118. }
  119. }
  120. }
  121. o.value('0.0.0.0/0');
  122. o = s.taboption('general', form.DynamicList, 'rightsubnets', _('Remote Subnets'));
  123. o.datatype = 'ipaddr';
  124. o.value('0.0.0.0/0');
  125. o = s.taboption('authentication', form.ListValue, 'authby', _('Auth Method'));
  126. o.default = 'secret'
  127. o.value('secret', _('Shared Secret'));
  128. o.value('never', 'Never');
  129. o.value('null', 'Null');
  130. o.modalonly = true;
  131. o.optional = false;
  132. o = s.taboption('authentication', form.Value, 'psk', _('Preshared Key'));
  133. o.datatype = 'and(string, minlength(8))'
  134. o.depends({ 'authby' : 'secret' });
  135. o.password = true;
  136. o.modalonly = true;
  137. o.optional = false;
  138. o = s.taboption('advanced', form.ListValue, 'ikev2', _('IKE V2'));
  139. o.default = 'yes';
  140. o.value('yes', _('IKE Version 2'));
  141. o.value('no', _('IKE Version 1'));
  142. o.modalonly = true;
  143. o = s.taboption('advanced', form.MultiValue, 'ike', _('Phase1 Proposals'));
  144. for (var i = 0; i < proposals.length; i++) {
  145. o.value(proposals[i]['.name']);
  146. }
  147. o.modalonly = true;
  148. function timevalidate(section_id, value) {
  149. if (!/^[0-9]{1,3}[smhd]$/.test(value)) {
  150. return _('Acceptable values are an integer followed by m, h, d');
  151. }
  152. return true;
  153. }
  154. o = s.taboption('advanced', form.Value, 'ikelifetime', _('IKE Life Time'), _('Acceptable values are an integer followed by m, h, d'));
  155. o.default = '8h';
  156. o.value('1h', '1h');
  157. o.value('2h', '2h');
  158. o.value('4h', '4h');
  159. o.value('8h', '8h');
  160. o.value('12h', '12h');
  161. o.value('16h', '16h');
  162. o.value('24h', '24h');
  163. o.modalonly = false;
  164. o.modalonly = true;
  165. o.validate = timevalidate;
  166. o = s.taboption('advanced', form.Flag, 'rekey', _('Rekey'));
  167. o.default = false;
  168. o.modalonly = false;
  169. o.modalonly = true;
  170. o = s.taboption('advanced', form.Value, 'rekeymargin', _('Rekey Margin Time'), _('Acceptable values are an integer followed by m, h, d'));
  171. o.default = '9m';
  172. o.value('5m', '5m');
  173. o.value('9m', '9m');
  174. o.value('15m', '15m');
  175. o.value('20m', '20m');
  176. o.value('30m', '30m');
  177. o.value('60m', '60m');
  178. o.modalonly = false;
  179. o.modalonly = true;
  180. o.validate = timevalidate;
  181. o = s.taboption('advanced', form.ListValue, 'dpdaction', _('DPD Action'));
  182. o.default = 'restart';
  183. o.value('none', _('None'));
  184. o.value('clear', _('Clear'));
  185. o.value('hold', _('Hold'));
  186. o.value('restart', _('Restart'));
  187. o.modalonly = true;
  188. o = s.taboption('advanced', form.Value, 'dpddelay', _('DPD Delay'));
  189. o.datatype = 'uinteger';
  190. o.default = 30;
  191. o.modalonly = true;
  192. o = s.taboption('advanced', form.Value, 'dpdtimeout', _('DPD Timeout'));
  193. o.datatype = 'uinteger';
  194. o.default = 150;
  195. o.modalonly = true;
  196. o = s.taboption('advanced', form.ListValue, 'phase2', _('Phase2 Protocol'));
  197. o.default = 'esp';
  198. o.value('esp', 'ESP');
  199. o.modalonly = true;
  200. o.optional = false;
  201. o = s.taboption('advanced', form.MultiValue, 'phase2alg', _('Phase2 Proposals'));
  202. for (var i = 0; i < proposals.length; i++) {
  203. o.value(proposals[i]['.name']);
  204. }
  205. o.modalonly = true;
  206. o = s.taboption('advanced', form.Value, 'nflog', _('Enable nflog on nfgroup'));
  207. o.default = 0;
  208. o.datatype = 'uinteger';
  209. o.rmempty = true;
  210. o.optional = true;
  211. o.modalonly = true;
  212. var interfaces = uci.sections('network', 'interface');
  213. o = s.taboption('advanced', form.ListValue, 'interface', _('Tunnel Interface'),
  214. _('Lists XFRM interfaces in format "ipsecN", N denotes ifid of xfrm interface') + '<br>' +
  215. _('Lists VTI interfaces configured with ikey and okey'));
  216. o.datatype = 'string';
  217. o.rmempty = true;
  218. o.modalonly = true;
  219. o.value('');
  220. interfaces.forEach(iface => {
  221. const { proto, ikey, okey, ifid, ['.name']: name } = iface;
  222. if (proto === "vti" && ikey && okey) {
  223. o.value(name, `VTI - ${name}`);
  224. }
  225. if (proto === "xfrm" && ifid && name.match(`ipsec${ifid}`)) {
  226. o.value(name, `XFRM - ${name}`);
  227. }
  228. });
  229. o = s.taboption('advanced', form.Flag, 'update_peeraddr', _('Update Peer Address'),
  230. _('Auto Update Peer Address of VTI interface'));
  231. o.rmempty = true;
  232. o.modalonly = true;
  233. return m.render();
  234. }
  235. });