6 Commits

Author SHA1 Message Date
RTechSn
0c726cacbf Fix Generate Configuration (#36)
* Fix "generate client configuration"

* Add qrencode dependency

* Added client IP and DNS settings in client config generator

* Added Download Config button

* fix
2025-06-26 01:34:20 +07:00
EugeneTM
d91b8929de fix var names in config import (#35)
Исправлены названия переменных для корректного импорта текстовой конфигурации
2025-03-27 21:21:14 +07:00
Slava-Shchipunov
33e363e9d9 feat: disable sync owrt releases 2025-03-13 09:24:17 +07:00
Slava-Shchipunov
3d865a8d4d feat: disable build to snapshots 2025-03-13 09:22:29 +07:00
Slava-Shchipunov
e285146833 docs: fix script link 2024-10-27 20:30:00 +07:00
Slava-Shchipunov
1dd92441aa Feat/add install script (#31)
* feat: add awg install script

* fix: replace curl with wget

* fix: add opkg update run

* feat: add firewall settings

* fix: fix allowed_ips set

* fix: add timeout

* fix: fix peer create

* docs: update readme
2024-10-26 04:36:27 +07:00
5 changed files with 116 additions and 46 deletions

View File

@@ -7,8 +7,8 @@ on:
push:
tags:
- "SNAPSHOT"
schedule:
- cron: '0 */4 * * *'
# schedule:
# - cron: '0 */4 * * *'
workflow_dispatch:
jobs:

View File

@@ -1,8 +1,8 @@
name: Sync OpenWRT Releases
on:
schedule:
- cron: '0 0 */3 * *' # Проверка новых релизов раз в три дня
# schedule:
# - cron: '0 0 */3 * *' # Проверка новых релизов раз в три дня
workflow_dispatch: # Возможность вручную запустить Action
jobs:
@@ -63,4 +63,4 @@ jobs:
if: needs.sync-releases.outputs.release_exists == 'false'
uses: Slava-Shchipunov/awg-openwrt/.github/workflows/build-module.yml@master
with:
tag_name: ${{ needs.sync-releases.outputs.release_tag }}
tag_name: ${{ needs.sync-releases.outputs.release_tag }}

View File

@@ -4,7 +4,7 @@
Если же вам нужно только установить пакеты, я добавил скрипт amneziawg-install - он автоматически скачает пакеты из этого репозитория под ваше устройство (только для стабильной версии OpenWRT), а также предложит сразу настроить интерфейс с протоколом AmneziaWG. Если пользователь согласится, нужно будет ввести параметры конфига, которые запросит скрипт. При этом скрипт создаст интерфейс, настроит для него правила фаерволла, а также **включит перенаправление всего траффика через тунель AmneziaWG** (установит в настройках Peer галочку Route Allowed IPs).
Для запуска скрипта подключитесь к роутеру по SSH, введите команду и следуйте инструкциям на экране:
```
sh <(wget -O - https://raw.githubusercontent.com/Slava-Shchipunov/awg-openwrt/refs/heads/feat/add-install-script/amneziawg-install.sh)
sh <(wget -O - https://raw.githubusercontent.com/Slava-Shchipunov/awg-openwrt/refs/heads/master/amneziawg-install.sh)
```
# Сборка пакетов для всех устройств, поддерживающих OpenWRT
@@ -51,7 +51,7 @@ For automatic configuration, I recommend using the [script](https://github.com/i
If you only need to install packages, I added the amneziawg-install script - it will automatically download packages from this repository for your device (only for the stable version of OpenWRT), and also offer to immediately configure the interface with the AmneziaWG protocol. If the user agrees, you will need to enter the config parameters that the script will request. The script will create an interface, configure firewall rules for it, and also **enable redirection of all traffic through the AmneziaWG tunnel** (check the Route Allowed IPs box in the Peer settings).
To run the script, connect to the router via SSH, enter the command and follow the instructions on the screen:
```
sh <(wget -O - https://raw.githubusercontent.com/Slava-Shchipunov/awg-openwrt/refs/heads/feat/add-install-script/amneziawg-install.sh)
sh <(wget -O - https://raw.githubusercontent.com/Slava-Shchipunov/awg-openwrt/refs/heads/master/amneziawg-install.sh)
```
# Building packages for all devices that support OpenWRT

View File

@@ -7,7 +7,7 @@
include $(TOPDIR)/rules.mk
LUCI_TITLE:=Support for AmneziaWG VPN
LUCI_DEPENDS:=+amneziawg-tools +ucode
LUCI_DEPENDS:=+amneziawg-tools +ucode +qrencode
LUCI_PKGARCH:=all
PKG_PROVIDES:=luci-app-amneziawg

View File

@@ -64,15 +64,29 @@ function generateDescription(name, texts) {
]);
}
function invokeQREncode(data, code) {
function invokeQREncode(data, div) {
var code = div.children[0];
var btn = div.children[1];
dom.content(btn, [
E('a', {
'class': 'btn cbi-button-action',
'style': 'text-align: center',
'href': 'data:text/plain;charset=utf-8,' + encodeURIComponent(data),
'download': 'amneziawg.conf'
}, ['Download Configuration']),
]);
return fs.exec_direct('/usr/bin/qrencode', [
'--inline', '--8bit', '--type=SVG',
'--output=-', '--', data
]).then(function(svg) {
code.style.opacity = '';
div.style.opacity = '';
dom.content(code, Object.assign(E(svg), { style: 'width:100%;height:auto' }));
}).catch(function(error) {
code.style.opacity = '';
div.style.opacity = '';
if (L.isObject(error) && error.name == 'NotFoundError') {
dom.content(code, [
@@ -402,15 +416,15 @@ return network.registerProtocol('amneziawg', {
s.getOption('public_key').getUIElement(s.section).setValue(keypair.pub);
s.getOption('listen_port').getUIElement(s.section).setValue(config.interface_listenport || '');
s.getOption('addresses').getUIElement(s.section).setValue(config.interface_address);
s.getOption('awg_jc').getUIElement(s.section).setValue(config.awg_jc);
s.getOption('awg_jmin').getUIElement(s.section).setValue(config.awg_jmin);
s.getOption('awg_jmax').getUIElement(s.section).setValue(config.awg_jmax);
s.getOption('awg_s1').getUIElement(s.section).setValue(config.awg_s1);
s.getOption('awg_s2').getUIElement(s.section).setValue(config.awg_s2);
s.getOption('awg_h1').getUIElement(s.section).setValue(config.awg_h1);
s.getOption('awg_h2').getUIElement(s.section).setValue(config.awg_h2);
s.getOption('awg_h3').getUIElement(s.section).setValue(config.awg_h3);
s.getOption('awg_h4').getUIElement(s.section).setValue(config.awg_h4);
s.getOption('awg_jc').getUIElement(s.section).setValue(config.interface_jc);
s.getOption('awg_jmin').getUIElement(s.section).setValue(config.interface_jmin);
s.getOption('awg_jmax').getUIElement(s.section).setValue(config.interface_jmax);
s.getOption('awg_s1').getUIElement(s.section).setValue(config.interface_s1);
s.getOption('awg_s2').getUIElement(s.section).setValue(config.interface_s2);
s.getOption('awg_h1').getUIElement(s.section).setValue(config.interface_h1);
s.getOption('awg_h2').getUIElement(s.section).setValue(config.interface_h2);
s.getOption('awg_h3').getUIElement(s.section).setValue(config.interface_h3);
s.getOption('awg_h4').getUIElement(s.section).setValue(config.interface_h4);
if (config.interface_dns)
s.getOption('dns').getUIElement(s.section).setValue(config.interface_dns);
@@ -743,39 +757,65 @@ return network.registerProtocol('amneziawg', {
o.modalonly = true;
o.createPeerConfig = function(section_id, endpoint, ips) {
o.createPeerConfig = function (section_id, endpoint, ips, eips, dns) {
var pub = s.formvalue(s.section, 'public_key'),
port = s.formvalue(s.section, 'listen_port') || '51820',
jc = s.formvalue
prv = this.section.formvalue(section_id, 'private_key'),
psk = this.section.formvalue(section_id, 'preshared_key'),
eport = this.section.formvalue(section_id, 'endpoint_port'),
keep = this.section.formvalue(section_id, 'persistent_keepalive');
// If endpoint is IPv6 we must escape it with []
port = s.formvalue(s.section, 'listen_port') || '51820',
prv = this.section.formvalue(section_id, 'private_key'),
psk = this.section.formvalue(section_id, 'preshared_key'),
eport = this.section.formvalue(section_id, 'endpoint_port'),
keep = this.section.formvalue(section_id, 'persistent_keepalive'),
jc = s.formvalue(s.section, 'awg_jc'),
jmin = s.formvalue(s.section, 'awg_jmin'),
jmax = s.formvalue(s.section, 'awg_jmax'),
s1 = s.formvalue(s.section, 'awg_s1'),
s2 = s.formvalue(s.section, 'awg_s2'),
h1 = s.formvalue(s.section, 'awg_h1'),
h2 = s.formvalue(s.section, 'awg_h2'),
h3 = s.formvalue(s.section, 'awg_h3'),
h4 = s.formvalue(s.section, 'awg_h4');
if (endpoint.indexOf(':') > 0) {
endpoint = '['+endpoint+']';
endpoint = '[' + endpoint + ']';
}
return [
var configLines = [
'[Interface]',
'PrivateKey = ' + prv,
eport ? 'ListenPort = ' + eport : '# ListenPort not defined',
eips && eips.length ? 'Address = ' + eips.join(', ') : '# Address not defined',
dns && dns.length ? 'DNS = ' + dns.join(', ') : '# DNS not defined',
''
];
if (jc) configLines.push('jc = ' + jc);
if (jmin) configLines.push('jmin = ' + jmin);
if (jmax) configLines.push('jmax = ' + jmax);
if (s1) configLines.push('s1 = ' + s1);
if (s2) configLines.push('s2 = ' + s2);
if (h1) configLines.push('h1 = ' + h1);
if (h2) configLines.push('h2 = ' + h2);
if (h3) configLines.push('h3 = ' + h3);
if (h4) configLines.push('h4 = ' + h4);
configLines.push(
'',
'[Peer]',
'PublicKey = ' + pub,
psk ? 'PresharedKey = ' + psk : '# PresharedKey not used',
ips && ips.length ? 'AllowedIPs = ' + ips.join(', ') : '# AllowedIPs not defined',
endpoint ? 'Endpoint = ' + endpoint + ':' + port : '# Endpoint not defined',
keep ? 'PersistentKeepAlive = ' + keep : '# PersistentKeepAlive not defined'
].join('\n');
};
keep ? 'PersistentKeepAlive = ' + keep : '# PersistentKeepAlive not defined',
''
);
return configLines.join('\n');
};
o.handleGenerateQR = function(section_id, ev) {
var mapNode = ss.getActiveModalMap(),
headNode = mapNode.parentNode.querySelector('h4'),
configGenerator = this.createPeerConfig.bind(this, section_id),
parent = this.map;
headNode = mapNode.parentNode.querySelector('h4'),
configGenerator = this.createPeerConfig.bind(this, section_id),
parent = this.map,
eips = this.section.formvalue(section_id, 'allowed_ips');
return Promise.all([
network.getWANNetworks(),
@@ -804,21 +844,33 @@ return network.registerProtocol('amneziawg', {
var ips = [ '0.0.0.0/0', '::/0' ];
var dns = [];
var qrm, qrs, qro;
qrm = new form.JSONMap({ config: { endpoint: hostnames[0], allowed_ips: ips } }, null, _('The generated configuration can be imported into a AmneziaWG client application to set up a connection towards this device.'));
qrm = new form.JSONMap({
config: {
endpoint: hostnames[0],
allowed_ips: ips,
addresses: eips,
dns_servers: dns
}
}, null, _('The generated configuration can be imported into a AmneziaWG client application to set up a connection towards this device.'));
qrm.parent = parent;
qrs = qrm.section(form.NamedSection, 'config');
function handleConfigChange(ev, section_id, value) {
var code = this.map.findElement('.qr-code'),
conf = this.map.findElement('.client-config'),
endpoint = this.section.getUIElement(section_id, 'endpoint'),
ips = this.section.getUIElement(section_id, 'allowed_ips');
conf = this.map.findElement('.client-config'),
endpoint = this.section.getUIElement(section_id, 'endpoint'),
ips = this.section.getUIElement(section_id, 'allowed_ips');
eips = this.section.getUIElement(section_id, 'addresses');
dns = this.section.getUIElement(section_id, 'dns_servers');
if (this.isValid(section_id)) {
conf.firstChild.data = configGenerator(endpoint.getValue(), ips.getValue());
conf.firstChild.data = configGenerator(endpoint.getValue(), ips.getValue(), eips.getValue(), dns.getValue());
code.style.opacity = '.5';
invokeQREncode(conf.firstChild.data, code);
@@ -836,18 +888,36 @@ return network.registerProtocol('amneziawg', {
ips.forEach(function(ip) { qro.value(ip) });
qro.onchange = handleConfigChange;
qro = qrs.option(form.DynamicList, 'dns_servers', _('DNS Servers'), _('DNS servers for the remote clients using this tunnel to your openwrt device. Some wireguard clients require this to be set.'));
qro.datatype = 'ipaddr';
qro.default = dns;
qro.onchange = handleConfigChange;
qro = qrs.option(form.DynamicList, 'addresses', _('Addresses'), _('IP addresses for the peer to use inside the tunnel. Some clients require this setting.'));
qro.datatype = 'ipaddr';
qro.default = eips;
eips.forEach(function(eip) { qro.value(eip) });
qro.onchange = handleConfigChange;
qro = qrs.option(form.DummyValue, 'output');
qro.renderWidget = function() {
var peer_config = configGenerator(hostnames[0], ips);
var peer_config = configGenerator(hostnames[0], ips, eips, dns);
var node = E('div', {
'style': 'display:flex;flex-wrap:wrap;align-items:center;gap:.5em;width:100%'
}, [
E('div', {
'class': 'qr-code',
'style': 'width:320px;flex:0 1 320px;text-align:center'
'style': 'display:flex; flex-direction: column; text-align: center',
}, [
E('em', { 'class': 'spinning' }, [ _('Generating QR code…') ])
E('div', {
'style': 'width:320px;flex:0 1 320px;text-align:center'
}, [
E('em', { 'class': 'spinning' }, [ _('Generating QR code…') ])
]),
E('div', {
}, ['Download Configuration']),
]),
E('pre', {
'class': 'client-config',