So I am trying to modify/add some feature to the existing Luci interface. I am using this version of OpenWRT:
And specifically, I am trying to modify the firewall section of Luci. I've added a .js file (domainfilter.js) which I originally copy the forwards.js (in the /feeds/luci/applications/luci-app-firewall/htdocs/luci-static/resource/view/firewall/ folder) and take out alot of things I don't need there. I am VERY NEW to modifying openwrt code and not too familiar with Lua (I assume this is what it is using) programming language.
My first question is that is there ANY detail documentation as for thing such as declaring components such as grid,textbox, check box. I mean I figured out quite a bit from messing around witht he forwards.js. But just wondering if there is a more "complete" documentation which detail all avaliable component and their properties? Also the "events"?
So if you look a the code below. Where can I program the "event" which trigger by user pressing the "save and apply" button? What I would like to do is to be able to modify external "dnsmasq.conf" file under the /etc/config folder of the router. I am trying to create a place where user can build a "black/white list" to do dns filtering. Meaning only allow/block certain url lookup (so that user can or can not go certain web sites).
Any help will be GREATLY appreciated.
Thank you!
'use strict';
'require view';
'require ui';
'require rpc';
'require uci';
'require form';
'require firewall as fwmodel';
'require tools.firewall as fwtool';
'require tools.widgets as widgets';
function rule_proto_txt(s, ctHelpers) {
var family = (uci.get('firewall', s, 'family') || '').toLowerCase().replace(/^(?:any|\*)$/, '');
var dip = uci.get('firewall', s, 'dest_ip') || ''
var proto = L.toArray(uci.get('firewall', s, 'proto')).filter(function(p) {
return (p != '*' && p != 'any' && p != 'all');
}).map(function(p) {
var pr = fwtool.lookupProto(p);
return {
num: pr[0],
name: pr[1],
types: (pr[0] == 1 || pr[0] == 58) ? L.toArray(uci.get('firewall', s, 'icmp_type')) : null
};
});
m = String(uci.get('firewall', s, 'helper') || '').match(/^(!\s*)?(\S+)$/);
var h = m ? {
val: m[0].toUpperCase(),
inv: m[1],
name: (ctHelpers.filter(function(ctH) { return ctH.name.toLowerCase() == m[2].toLowerCase() })[0] || {}).description
} : null;
m = String(uci.get('firewall', s, 'mark')).match(/^(!\s*)?(0x[0-9a-f]{1,8}|[0-9]{1,10})(?:\/(0x[0-9a-f]{1,8}|[0-9]{1,10}))?$/i);
var f = m ? {
val: m[0].toUpperCase().replace(/X/g, 'x'),
inv: m[1],
num: '0x%02X'.format(+m[2]),
mask: m[3] ? '0x%02X'.format(+m[3]) : null
} : null;
return fwtool.fmt(_('Incoming %{ipv6?%{ipv4?<var>IPv4</var> and <var>IPv6</var>:<var>IPv6</var>}:<var>IPv4</var>}%{proto?, protocol %{proto#%{next?, }%{item.types?<var class="cbi-tooltip-container">%{item.name}<span class="cbi-tooltip">ICMP with types %{item.types#%{next?, }<var>%{item}</var>}</span></var>:<var>%{item.name}</var>}}}%{mark?, mark <var%{mark.inv? data-tooltip="Match fwmarks except %{mark.num}%{mark.mask? with mask %{mark.mask}}.":%{mark.mask? data-tooltip="Mask fwmark value with %{mark.mask} before compare."}}>%{mark.val}</var>}%{helper?, helper %{helper.inv?<var data-tooltip="Match any helper except "%{helper.name}"">%{helper.val}</var>:<var data-tooltip="%{helper.name}">%{helper.val}</var>}}'), {
ipv4: ((!family && (dip.indexOf(':') == -1)) || family == 'ipv4'),
ipv6: ((!family && (dip.indexOf(':') != -1)) || family == 'ipv6'),
proto: proto,
helper: h,
mark: f
});
}
function rule_src_txt(s, hosts) {
var z = uci.get('firewall', s, 'src');
return fwtool.fmt(_('From %{src}%{src_ip?, IP %{src_ip#%{next?, }<var%{item.inv? data-tooltip="Match IP addresses except %{item.val}."}>%{item.ival}</var>}}%{src_port?, port %{src_port#%{next?, }<var%{item.inv? data-tooltip="Match ports except %{item.val}."}>%{item.ival}</var>}}%{src_mac?, MAC %{src_mac#%{next?, }<var%{item.inv? data-tooltip="Match MACs except %{item.val}%{item.hint.name? a.k.a. %{item.hint.name}}.":%{item.hint.name? data-tooltip="%{item.hint.name}"}}>%{item.ival}</var>}}'), {
src: E('span', { 'class': 'zonebadge', 'style': fwmodel.getZoneColorStyle(z) }, [(z == '*') ? E('em', _('any zone')) : (z ? E('strong', z) : E('em', _('this device')))]),
src_ip: fwtool.map_invert(uci.get('firewall', s, 'src_ip'), 'toLowerCase'),
src_mac: fwtool.map_invert(uci.get('firewall', s, 'src_mac'), 'toUpperCase').map(function(v) { return Object.assign(v, { hint: hosts[v.val] }) }),
src_port: fwtool.map_invert(uci.get('firewall', s, 'src_port'))
});
}
function rule_dest_txt(s) {
return fwtool.fmt(_('To %{dest}%{dest_ip?, IP %{dest_ip#%{next?, }<var%{item.inv? data-tooltip="Match IP addresses except %{item.val}."}>%{item.ival}</var>}}%{dest_port?, port %{dest_port#%{next?, }<var%{item.inv? data-tooltip="Match ports except %{item.val}."}>%{item.ival}</var>}}'), {
dest: E('span', { 'class': 'zonebadge', 'style': fwmodel.getZoneColorStyle(null) }, [E('em', _('this device'))]),
dest_ip: fwtool.map_invert(uci.get('firewall', s, 'src_dip'), 'toLowerCase'),
dest_port: fwtool.map_invert(uci.get('firewall', s, 'src_dport'))
});
}
function rule_limit_txt(s) {
var m = String(uci.get('firewall', s, 'limit')).match(/^(\d+)\/([smhd])\w*$/i),
l = m ? {
num: +m[1],
unit: ({ s: _('second'), m: _('minute'), h: _('hour'), d: _('day') })[m[2]],
burst: uci.get('firewall', s, 'limit_burst')
} : null;
if (!l)
return '';
return fwtool.fmt(_('Limit matching to <var>%{limit.num}</var> packets per <var>%{limit.unit}</var>%{limit.burst? burst <var>%{limit.burst}</var>}'), { limit: l });
}
function rule_target_txt(s) {
var z = uci.get('firewall', s, 'dest');
return fwtool.fmt(_('<var data-tooltip="DNAT">Forward</var> to %{dest}%{dest_ip? IP <var>%{dest_ip}</var>}%{dest_port? port <var>%{dest_port}</var>}'), {
dest: E('span', { 'class': 'zonebadge', 'style': 'background-color:' + fwmodel.getColorForName((z && z != '*') ? z : null) }, [(z == '*') ? E('em', _('any zone')) : (z ? E('strong', z) : E('em', _('this device')))]),
dest_ip: (uci.get('firewall', s, 'dest_ip') || '').toLowerCase(),
dest_port: uci.get('firewall', s, 'dest_port')
});
}
function validate_opt_family(m, section_id, opt) {
var dopt = m.section.getOption('dest_ip'),
fmopt = m.section.getOption('family');
if (!dopt.isValid(section_id) && opt != 'dest_ip')
return true;
if (!fmopt.isValid(section_id) && opt != 'family')
return true;
var dip = dopt.formvalue(section_id) || '',
fm = fmopt.formvalue(section_id) || '';
if (fm == '' || (fm == 'ipv6' && (dip.indexOf(':') != -1 || dip == '')) || (fm == 'ipv4' && dip.indexOf(':') == -1))
return true;
return _('Address family, Internal IP address must match');
}
return view.extend({
callHostHints: rpc.declare({
object: 'luci-rpc',
method: 'getHostHints',
expect: { '': {} }
}),
callConntrackHelpers: rpc.declare({
object: 'luci',
method: 'getConntrackHelpers',
expect: { result: [] }
}),
callNetworkDevices: rpc.declare({
object: 'luci-rpc',
method: 'getNetworkDevices',
expect: { '': {} }
}),
load: function() {
return Promise.all([
this.callHostHints(),
this.callConntrackHelpers(),
this.callNetworkDevices(),
uci.load('firewall')
]);
},
render: function(data) {
if (fwtool.checkLegacySNAT())
return fwtool.renderMigration();
else
return this.renderForwards(data);
},
renderForwards: function(data) {
var hosts = data[0],
ctHelpers = data[1],
devs = data[2],
m, s, o;
var fw4 = L.hasSystemFeature('firewall4');
m = new form.Map('firewall', _('Firewall - Domain Filtering'),
_('Domain Filtering for traffic going out of WAN'));
s = m.section(form.TypedSection, 'domainfiltering', _('General Settings'));
s.anonymous = true;
s.addremove = false;
o = s.option(form.Flag, 'enable', _('Enable'));
var p = [
s.option(form.ListValue, 'input', _('Input'))
];
for (var i = 0; i < p.length; i++) {
p[i].value('blacklist', _('blacklist'));
p[i].value('whitelist', _('whitelist'));
}
s = m.section(form.GridSection, 'domainfiltering', _('Domain Filtering'));
s.addremove = true;
s.anonymous = true;
s.sortable = true;
s.tab('general', _('General Settings'));
o = s.taboption('general', form.Value, 'name', _('Name'));
o.placeholder = _('Description');
o = s.taboption('general', form.Value, 'domain', _('Domain'));
o.placeholder = _('domain url');
return m.render();
}
});