|
|
@@ -2235,8 +2235,8 @@ function renderFilterRules() {
|
|
|
<td class="py-2.5 px-3 text-center text-slate-500 font-bold">${r.order || idx + 1}</td>
|
|
|
<td class="py-2.5 px-3 text-center">${renderRuleFlag(r.disabled, !!r.comment)}</td>
|
|
|
<td class="py-2.5 px-3 font-bold text-white">${r.chain}</td>
|
|
|
- <td class="py-2.5 px-3 text-slate-300">${r.src_address || r.src_address_list ? (r.src_address || `list:${r.src_address_list}`) : '<span class="text-slate-600">0.0.0.0/0</span>'}</td>
|
|
|
- <td class="py-2.5 px-3 text-slate-300">${r.dst_address || r.dst_address_list ? (r.dst_address || `list:${r.dst_address_list}`) : '<span class="text-slate-600">0.0.0.0/0</span>'}</td>
|
|
|
+ <td class="py-2.5 px-3 text-slate-300">${formatTarget(r.src_address, r.src_address_list, r.src_geoip)}</td>
|
|
|
+ <td class="py-2.5 px-3 text-slate-300">${formatTarget(r.dst_address, r.dst_address_list, r.dst_geoip)}</td>
|
|
|
<td class="py-2.5 px-3 text-cyan-400 uppercase">${r.protocol || 'all'}</td>
|
|
|
<td class="py-2.5 px-3 text-amber-400">${ports || '-'}</td>
|
|
|
<td class="py-2.5 px-3 text-emerald-400">${ifaces || '-'}</td>
|
|
|
@@ -2258,6 +2258,23 @@ function renderFilterRules() {
|
|
|
});
|
|
|
}
|
|
|
|
|
|
+function formatTarget(addr, list, geo) {
|
|
|
+ const parts = [];
|
|
|
+ if (addr) parts.push(`<span>${addr}</span>`);
|
|
|
+ if (list) {
|
|
|
+ const inv = list.startsWith('!') ? '!' : '';
|
|
|
+ const clean = list.replace(/^!/, '');
|
|
|
+ parts.push(`<span class="px-1.5 py-0.5 rounded text-[10px] bg-amber-950/80 border border-amber-800/40 text-amber-300 font-mono" title="Address List: ${list}">${inv}list:${clean}</span>`);
|
|
|
+ }
|
|
|
+ if (geo) {
|
|
|
+ const inv = geo.startsWith('!') ? '!' : '';
|
|
|
+ const clean = geo.replace(/^!/, '').replace(/^geo:/, '');
|
|
|
+ parts.push(`<span class="px-1.5 py-0.5 rounded text-[10px] bg-emerald-950/80 border border-emerald-800/40 text-emerald-300 font-mono" title="Geo-Location: ${geo}">🌍 ${inv}${clean}</span>`);
|
|
|
+ }
|
|
|
+ if (parts.length === 0) return '<span class="text-slate-600">0.0.0.0/0</span>';
|
|
|
+ return parts.join(' ');
|
|
|
+}
|
|
|
+
|
|
|
function populateInterfaceSelect(selectId, currentVal = '') {
|
|
|
const sel = document.getElementById(selectId);
|
|
|
if (!sel) return;
|
|
|
@@ -2276,41 +2293,17 @@ function populateAddressListSelect(selectId, currentVal = '') {
|
|
|
if (!sel) return;
|
|
|
sel.innerHTML = '<option value="">(None)</option>';
|
|
|
|
|
|
- const cleanVal = currentVal.startsWith('!') ? currentVal.substring(1) : currentVal;
|
|
|
-
|
|
|
- // 1. Custom Address Lists
|
|
|
+ const cleanVal = (currentVal || '').replace(/^!/, '');
|
|
|
const customNames = Array.from(new Set((state.addressLists || []).map(a => a.name))).sort();
|
|
|
- if (customNames.length > 0) {
|
|
|
- const optgroup = document.createElement('optgroup');
|
|
|
- optgroup.label = 'Custom Address Lists';
|
|
|
- customNames.forEach(name => {
|
|
|
- const count = (state.addressLists || []).filter(a => a.name === name).length;
|
|
|
- const opt = document.createElement('option');
|
|
|
- opt.value = name;
|
|
|
- opt.innerText = `${name} (${count} entries)`;
|
|
|
- if (name === cleanVal) opt.selected = true;
|
|
|
- optgroup.appendChild(opt);
|
|
|
- });
|
|
|
- sel.appendChild(optgroup);
|
|
|
- }
|
|
|
-
|
|
|
- // 2. Enabled Geo-Location Countries
|
|
|
- const geoCountries = (state.geoCountries || []).filter(c => c.enabled);
|
|
|
- if (geoCountries.length > 0) {
|
|
|
- const optgroup = document.createElement('optgroup');
|
|
|
- optgroup.label = '🌍 Geo-Location Countries';
|
|
|
- geoCountries.forEach(c => {
|
|
|
- const val = `geo:${c.code}`;
|
|
|
- const opt = document.createElement('option');
|
|
|
- opt.value = val;
|
|
|
- opt.innerText = `${c.name} (${c.code}) - ${c.subnet_count.toLocaleString()} subnets`;
|
|
|
- if (val === cleanVal || `geo_${c.code}` === cleanVal) opt.selected = true;
|
|
|
- optgroup.appendChild(opt);
|
|
|
- });
|
|
|
- sel.appendChild(optgroup);
|
|
|
- }
|
|
|
+ customNames.forEach(name => {
|
|
|
+ const count = (state.addressLists || []).filter(a => a.name === name).length;
|
|
|
+ const opt = document.createElement('option');
|
|
|
+ opt.value = name;
|
|
|
+ opt.innerText = `${name} (${count} entries)`;
|
|
|
+ if (name === cleanVal) opt.selected = true;
|
|
|
+ sel.appendChild(opt);
|
|
|
+ });
|
|
|
|
|
|
- // Fallback: If cleanVal is set but not in list, add it as custom option
|
|
|
if (cleanVal && !sel.querySelector(`option[value="${cleanVal}"]`)) {
|
|
|
const opt = document.createElement('option');
|
|
|
opt.value = cleanVal;
|
|
|
@@ -2320,6 +2313,45 @@ function populateAddressListSelect(selectId, currentVal = '') {
|
|
|
}
|
|
|
}
|
|
|
|
|
|
+function populateGeoIPSelect(selectId, currentVal = '') {
|
|
|
+ const sel = document.getElementById(selectId);
|
|
|
+ if (!sel) return;
|
|
|
+ sel.innerHTML = '<option value="">(None)</option>';
|
|
|
+
|
|
|
+ const cleanVal = (currentVal || '').replace(/^!/, '').replace(/^geo:/, '').toUpperCase();
|
|
|
+
|
|
|
+ // Presets optgroup
|
|
|
+ const grpPresets = document.createElement('optgroup');
|
|
|
+ grpPresets.label = '⚡ Regional Presets';
|
|
|
+ const presets = [
|
|
|
+ { code: 'EU', label: '🇪🇺 European Union (EU - 27 countries)' },
|
|
|
+ { code: 'BALKANS', label: '🏛️ Balkans (GR, CY, BG, RO, AL, etc.)' },
|
|
|
+ { code: 'BLOCKLIST', label: '🛡️ High-Risk Blocklist (CN, RU, IR, KP, BY)' }
|
|
|
+ ];
|
|
|
+ presets.forEach(p => {
|
|
|
+ const opt = document.createElement('option');
|
|
|
+ opt.value = p.code;
|
|
|
+ opt.innerText = p.label;
|
|
|
+ if (p.code === cleanVal) opt.selected = true;
|
|
|
+ grpPresets.appendChild(opt);
|
|
|
+ });
|
|
|
+ sel.appendChild(grpPresets);
|
|
|
+
|
|
|
+ // All Countries optgroup
|
|
|
+ const grpCountries = document.createElement('optgroup');
|
|
|
+ grpCountries.label = '🌍 All Countries';
|
|
|
+ const countries = (state.geoCountries || []).slice().sort((a, b) => a.name.localeCompare(b.name));
|
|
|
+ countries.forEach(c => {
|
|
|
+ const opt = document.createElement('option');
|
|
|
+ opt.value = c.code;
|
|
|
+ const subnetsInfo = c.subnet_count ? ` [${c.subnet_count.toLocaleString()} subnets]` : '';
|
|
|
+ opt.innerText = `${c.name} (${c.code})${subnetsInfo}`;
|
|
|
+ if (c.code === cleanVal) opt.selected = true;
|
|
|
+ grpCountries.appendChild(opt);
|
|
|
+ });
|
|
|
+ sel.appendChild(grpCountries);
|
|
|
+}
|
|
|
+
|
|
|
function openAddFilterModal() {
|
|
|
document.getElementById('filter-modal-title').innerText = 'Add Firewall Filter Rule';
|
|
|
document.getElementById('filter-modal-id').value = '';
|
|
|
@@ -2341,8 +2373,15 @@ function openAddFilterModal() {
|
|
|
|
|
|
populateInterfaceSelect('filter-modal-iniface');
|
|
|
populateInterfaceSelect('filter-modal-outiface');
|
|
|
+ if (document.getElementById('filter-modal-srclist-inv')) document.getElementById('filter-modal-srclist-inv').checked = false;
|
|
|
+ if (document.getElementById('filter-modal-dstlist-inv')) document.getElementById('filter-modal-dstlist-inv').checked = false;
|
|
|
populateAddressListSelect('filter-modal-srclist');
|
|
|
populateAddressListSelect('filter-modal-dstlist');
|
|
|
+
|
|
|
+ if (document.getElementById('filter-modal-srcgeoip-inv')) document.getElementById('filter-modal-srcgeoip-inv').checked = false;
|
|
|
+ if (document.getElementById('filter-modal-dstgeoip-inv')) document.getElementById('filter-modal-dstgeoip-inv').checked = false;
|
|
|
+ populateGeoIPSelect('filter-modal-srcgeoip');
|
|
|
+ populateGeoIPSelect('filter-modal-dstgeoip');
|
|
|
toggleFilterActionFields();
|
|
|
|
|
|
document.getElementById('filter-modal').classList.remove('hidden');
|
|
|
@@ -2373,8 +2412,20 @@ function openEditFilterModal(id) {
|
|
|
|
|
|
populateInterfaceSelect('filter-modal-iniface', r.in_interface);
|
|
|
populateInterfaceSelect('filter-modal-outiface', r.out_interface);
|
|
|
- populateAddressListSelect('filter-modal-srclist', r.src_address_list);
|
|
|
- populateAddressListSelect('filter-modal-dstlist', r.dst_address_list);
|
|
|
+
|
|
|
+ const srcInv = (r.src_address_list || '').startsWith('!');
|
|
|
+ const dstInv = (r.dst_address_list || '').startsWith('!');
|
|
|
+ if (document.getElementById('filter-modal-srclist-inv')) document.getElementById('filter-modal-srclist-inv').checked = srcInv;
|
|
|
+ if (document.getElementById('filter-modal-dstlist-inv')) document.getElementById('filter-modal-dstlist-inv').checked = dstInv;
|
|
|
+ populateAddressListSelect('filter-modal-srclist', r.src_address_list || '');
|
|
|
+ populateAddressListSelect('filter-modal-dstlist', r.dst_address_list || '');
|
|
|
+
|
|
|
+ const srcGeoInv = (r.src_geoip || '').startsWith('!');
|
|
|
+ const dstGeoInv = (r.dst_geoip || '').startsWith('!');
|
|
|
+ if (document.getElementById('filter-modal-srcgeoip-inv')) document.getElementById('filter-modal-srcgeoip-inv').checked = srcGeoInv;
|
|
|
+ if (document.getElementById('filter-modal-dstgeoip-inv')) document.getElementById('filter-modal-dstgeoip-inv').checked = dstGeoInv;
|
|
|
+ populateGeoIPSelect('filter-modal-srcgeoip', r.src_geoip || '');
|
|
|
+ populateGeoIPSelect('filter-modal-dstgeoip', r.dst_geoip || '');
|
|
|
toggleFilterActionFields();
|
|
|
|
|
|
document.getElementById('filter-modal').classList.remove('hidden');
|
|
|
@@ -2406,8 +2457,25 @@ async function submitSaveFilterRule(e) {
|
|
|
const inIface = document.getElementById('filter-modal-iniface').value;
|
|
|
const outIface = document.getElementById('filter-modal-outiface').value;
|
|
|
const connmark = document.getElementById('filter-modal-connmark').value.trim();
|
|
|
- const srclist = document.getElementById('filter-modal-srclist').value;
|
|
|
- const dstlist = document.getElementById('filter-modal-dstlist').value;
|
|
|
+
|
|
|
+ let srclist = document.getElementById('filter-modal-srclist')?.value || '';
|
|
|
+ if (srclist && document.getElementById('filter-modal-srclist-inv')?.checked) {
|
|
|
+ srclist = '!' + srclist.replace(/^!/, '');
|
|
|
+ }
|
|
|
+ let dstlist = document.getElementById('filter-modal-dstlist')?.value || '';
|
|
|
+ if (dstlist && document.getElementById('filter-modal-dstlist-inv')?.checked) {
|
|
|
+ dstlist = '!' + dstlist.replace(/^!/, '');
|
|
|
+ }
|
|
|
+
|
|
|
+ let srcgeoip = document.getElementById('filter-modal-srcgeoip')?.value || '';
|
|
|
+ if (srcgeoip && document.getElementById('filter-modal-srcgeoip-inv')?.checked) {
|
|
|
+ srcgeoip = '!' + srcgeoip.replace(/^!/, '');
|
|
|
+ }
|
|
|
+ let dstgeoip = document.getElementById('filter-modal-dstgeoip')?.value || '';
|
|
|
+ if (dstgeoip && document.getElementById('filter-modal-dstgeoip-inv')?.checked) {
|
|
|
+ dstgeoip = '!' + dstgeoip.replace(/^!/, '');
|
|
|
+ }
|
|
|
+
|
|
|
const comment = document.getElementById('filter-modal-comment').value.trim();
|
|
|
const disabled = document.getElementById('filter-modal-disabled').checked;
|
|
|
const rejectWith = document.getElementById('filter-modal-rejectwith')?.value || '';
|
|
|
@@ -2438,6 +2506,8 @@ async function submitSaveFilterRule(e) {
|
|
|
connection_mark: connmark,
|
|
|
src_address_list: srclist,
|
|
|
dst_address_list: dstlist,
|
|
|
+ src_geoip: srcgeoip,
|
|
|
+ dst_geoip: dstgeoip,
|
|
|
comment,
|
|
|
disabled
|
|
|
})
|
|
|
@@ -2521,8 +2591,8 @@ function renderNATRules() {
|
|
|
<td class="py-2.5 px-3 text-center text-slate-500 font-bold">${r.order || idx + 1}</td>
|
|
|
<td class="py-2.5 px-3 text-center">${renderRuleFlag(r.disabled, !!r.comment)}</td>
|
|
|
<td class="py-2.5 px-3 font-bold text-amber-400">${r.chain}</td>
|
|
|
- <td class="py-2.5 px-3 text-slate-300">${r.src_address || '<span class="text-slate-600">0.0.0.0/0</span>'}</td>
|
|
|
- <td class="py-2.5 px-3 text-slate-300">${r.dst_address || '<span class="text-slate-600">0.0.0.0/0</span>'}</td>
|
|
|
+ <td class="py-2.5 px-3 text-slate-300">${formatTarget(r.src_address, r.src_address_list, r.src_geoip)}</td>
|
|
|
+ <td class="py-2.5 px-3 text-slate-300">${formatTarget(r.dst_address, r.dst_address_list, r.dst_geoip)}</td>
|
|
|
<td class="py-2.5 px-3 text-cyan-400 uppercase">${r.protocol || 'all'}${r.dst_port ? ':' + r.dst_port : ''}</td>
|
|
|
<td class="py-2.5 px-3 text-emerald-400">${ifaces || '-'}</td>
|
|
|
<td class="py-2.5 px-3">${renderActionBadge(r.action)}</td>
|
|
|
@@ -2566,6 +2636,13 @@ function openAddNATModal() {
|
|
|
if (srcInvEl) srcInvEl.checked = false;
|
|
|
const dstInvEl = document.getElementById('nat-modal-dstlist-inv');
|
|
|
if (dstInvEl) dstInvEl.checked = false;
|
|
|
+
|
|
|
+ populateGeoIPSelect('nat-modal-srcgeoip');
|
|
|
+ populateGeoIPSelect('nat-modal-dstgeoip');
|
|
|
+ const srcGeoInvEl = document.getElementById('nat-modal-srcgeoip-inv');
|
|
|
+ if (srcGeoInvEl) srcGeoInvEl.checked = false;
|
|
|
+ const dstGeoInvEl = document.getElementById('nat-modal-dstgeoip-inv');
|
|
|
+ if (dstGeoInvEl) dstGeoInvEl.checked = false;
|
|
|
toggleNATActionFields();
|
|
|
|
|
|
document.getElementById('nat-modal').classList.remove('hidden');
|
|
|
@@ -2599,6 +2676,15 @@ function openEditNATModal(id) {
|
|
|
if (dstInvEl) dstInvEl.checked = dstInv;
|
|
|
populateAddressListSelect('nat-modal-srclist', r.src_address_list || '');
|
|
|
populateAddressListSelect('nat-modal-dstlist', r.dst_address_list || '');
|
|
|
+
|
|
|
+ const srcGeoInv = (r.src_geoip || '').startsWith('!');
|
|
|
+ const dstGeoInv = (r.dst_geoip || '').startsWith('!');
|
|
|
+ const srcGeoInvEl = document.getElementById('nat-modal-srcgeoip-inv');
|
|
|
+ if (srcGeoInvEl) srcGeoInvEl.checked = srcGeoInv;
|
|
|
+ const dstGeoInvEl = document.getElementById('nat-modal-dstgeoip-inv');
|
|
|
+ if (dstGeoInvEl) dstGeoInvEl.checked = dstGeoInv;
|
|
|
+ populateGeoIPSelect('nat-modal-srcgeoip', r.src_geoip || '');
|
|
|
+ populateGeoIPSelect('nat-modal-dstgeoip', r.dst_geoip || '');
|
|
|
toggleNATActionFields();
|
|
|
|
|
|
document.getElementById('nat-modal').classList.remove('hidden');
|
|
|
@@ -2641,6 +2727,7 @@ async function submitSaveNATRule(e) {
|
|
|
const dport = document.getElementById('nat-modal-dport').value.trim();
|
|
|
const inIface = document.getElementById('nat-modal-iniface').value;
|
|
|
const outIface = document.getElementById('nat-modal-outiface').value;
|
|
|
+
|
|
|
let srclist = document.getElementById('nat-modal-srclist')?.value || '';
|
|
|
if (srclist && document.getElementById('nat-modal-srclist-inv')?.checked) {
|
|
|
srclist = '!' + srclist.replace(/^!/, '');
|
|
|
@@ -2649,6 +2736,16 @@ async function submitSaveNATRule(e) {
|
|
|
if (dstlist && document.getElementById('nat-modal-dstlist-inv')?.checked) {
|
|
|
dstlist = '!' + dstlist.replace(/^!/, '');
|
|
|
}
|
|
|
+
|
|
|
+ let srcgeoip = document.getElementById('nat-modal-srcgeoip')?.value || '';
|
|
|
+ if (srcgeoip && document.getElementById('nat-modal-srcgeoip-inv')?.checked) {
|
|
|
+ srcgeoip = '!' + srcgeoip.replace(/^!/, '');
|
|
|
+ }
|
|
|
+ let dstgeoip = document.getElementById('nat-modal-dstgeoip')?.value || '';
|
|
|
+ if (dstgeoip && document.getElementById('nat-modal-dstgeoip-inv')?.checked) {
|
|
|
+ dstgeoip = '!' + dstgeoip.replace(/^!/, '');
|
|
|
+ }
|
|
|
+
|
|
|
const comment = document.getElementById('nat-modal-comment').value.trim();
|
|
|
const disabled = document.getElementById('nat-modal-disabled').checked;
|
|
|
|
|
|
@@ -2670,6 +2767,8 @@ async function submitSaveNATRule(e) {
|
|
|
out_interface: outIface,
|
|
|
src_address_list: srclist,
|
|
|
dst_address_list: dstlist,
|
|
|
+ src_geoip: srcgeoip,
|
|
|
+ dst_geoip: dstgeoip,
|
|
|
comment,
|
|
|
disabled
|
|
|
})
|
|
|
@@ -2749,8 +2848,8 @@ function renderMangleRules() {
|
|
|
<td class="py-2.5 px-3 text-center text-slate-500 font-bold">${r.order || idx + 1}</td>
|
|
|
<td class="py-2.5 px-3 text-center">${renderRuleFlag(r.disabled, !!r.comment)}</td>
|
|
|
<td class="py-2.5 px-3 font-bold text-purple-400">${r.chain}</td>
|
|
|
- <td class="py-2.5 px-3 text-slate-300">${r.src_address || '<span class="text-slate-600">0.0.0.0/0</span>'}</td>
|
|
|
- <td class="py-2.5 px-3 text-slate-300">${r.dst_address || '<span class="text-slate-600">0.0.0.0/0</span>'}</td>
|
|
|
+ <td class="py-2.5 px-3 text-slate-300">${formatTarget(r.src_address, r.src_address_list, r.src_geoip)}</td>
|
|
|
+ <td class="py-2.5 px-3 text-slate-300">${formatTarget(r.dst_address, r.dst_address_list, r.dst_geoip)}</td>
|
|
|
<td class="py-2.5 px-3">${renderActionBadge(r.action)}</td>
|
|
|
<td class="py-2.5 px-3 font-mono font-bold text-cyan-300">${markVal || '-'}</td>
|
|
|
<td class="py-2.5 px-3 text-center">${r.passthrough ? '<span class="text-emerald-400">yes</span>' : '<span class="text-slate-500">no</span>'}</td>
|
|
|
@@ -2792,6 +2891,13 @@ function openAddMangleModal() {
|
|
|
const dstInvEl = document.getElementById('mangle-modal-dstlist-inv');
|
|
|
if (dstInvEl) dstInvEl.checked = false;
|
|
|
|
|
|
+ populateGeoIPSelect('mangle-modal-srcgeoip');
|
|
|
+ populateGeoIPSelect('mangle-modal-dstgeoip');
|
|
|
+ const srcGeoInvEl = document.getElementById('mangle-modal-srcgeoip-inv');
|
|
|
+ if (srcGeoInvEl) srcGeoInvEl.checked = false;
|
|
|
+ const dstGeoInvEl = document.getElementById('mangle-modal-dstgeoip-inv');
|
|
|
+ if (dstGeoInvEl) dstGeoInvEl.checked = false;
|
|
|
+
|
|
|
document.getElementById('mangle-modal').classList.remove('hidden');
|
|
|
}
|
|
|
|
|
|
@@ -2822,6 +2928,15 @@ function openEditMangleModal(id) {
|
|
|
populateAddressListSelect('mangle-modal-srclist', r.src_address_list || '');
|
|
|
populateAddressListSelect('mangle-modal-dstlist', r.dst_address_list || '');
|
|
|
|
|
|
+ const srcGeoInv = (r.src_geoip || '').startsWith('!');
|
|
|
+ const dstGeoInv = (r.dst_geoip || '').startsWith('!');
|
|
|
+ const srcGeoInvEl = document.getElementById('mangle-modal-srcgeoip-inv');
|
|
|
+ if (srcGeoInvEl) srcGeoInvEl.checked = srcGeoInv;
|
|
|
+ const dstGeoInvEl = document.getElementById('mangle-modal-dstgeoip-inv');
|
|
|
+ if (dstGeoInvEl) dstGeoInvEl.checked = dstGeoInv;
|
|
|
+ populateGeoIPSelect('mangle-modal-srcgeoip', r.src_geoip || '');
|
|
|
+ populateGeoIPSelect('mangle-modal-dstgeoip', r.dst_geoip || '');
|
|
|
+
|
|
|
document.getElementById('mangle-modal').classList.remove('hidden');
|
|
|
}
|
|
|
|
|
|
@@ -2843,6 +2958,7 @@ async function submitSaveMangleRule(e) {
|
|
|
const src = document.getElementById('mangle-modal-src').value.trim();
|
|
|
const dst = document.getElementById('mangle-modal-dst').value.trim();
|
|
|
const inIface = document.getElementById('mangle-modal-iniface').value;
|
|
|
+
|
|
|
let srclist = document.getElementById('mangle-modal-srclist')?.value || '';
|
|
|
if (srclist && document.getElementById('mangle-modal-srclist-inv')?.checked) {
|
|
|
srclist = '!' + srclist.replace(/^!/, '');
|
|
|
@@ -2851,6 +2967,16 @@ async function submitSaveMangleRule(e) {
|
|
|
if (dstlist && document.getElementById('mangle-modal-dstlist-inv')?.checked) {
|
|
|
dstlist = '!' + dstlist.replace(/^!/, '');
|
|
|
}
|
|
|
+
|
|
|
+ let srcgeoip = document.getElementById('mangle-modal-srcgeoip')?.value || '';
|
|
|
+ if (srcgeoip && document.getElementById('mangle-modal-srcgeoip-inv')?.checked) {
|
|
|
+ srcgeoip = '!' + srcgeoip.replace(/^!/, '');
|
|
|
+ }
|
|
|
+ let dstgeoip = document.getElementById('mangle-modal-dstgeoip')?.value || '';
|
|
|
+ if (dstgeoip && document.getElementById('mangle-modal-dstgeoip-inv')?.checked) {
|
|
|
+ dstgeoip = '!' + dstgeoip.replace(/^!/, '');
|
|
|
+ }
|
|
|
+
|
|
|
const connmark = document.getElementById('mangle-modal-connmark').value.trim();
|
|
|
const comment = document.getElementById('mangle-modal-comment').value.trim();
|
|
|
const disabled = document.getElementById('mangle-modal-disabled').checked;
|
|
|
@@ -2865,6 +2991,8 @@ async function submitSaveMangleRule(e) {
|
|
|
in_interface: inIface,
|
|
|
src_address_list: srclist,
|
|
|
dst_address_list: dstlist,
|
|
|
+ src_geoip: srcgeoip,
|
|
|
+ dst_geoip: dstgeoip,
|
|
|
connection_mark: connmark,
|
|
|
comment,
|
|
|
disabled
|