8 var callNetworkInterfaceDump
= rpc
.declare({
9 object
: 'network.interface',
11 expect
: { interface: [] }
14 function applyMask(addr
, mask
, v6
) {
15 var words
= v6
? validation
.parseIPv6(addr
) : validation
.parseIPv4(addr
);
17 if (!words
|| mask
< 0 || mask
> (v6
? 128 : 32))
20 for (var i
= 0; i
< words
.length
; i
++) {
21 var b
= Math
.min(mask
, v6
? 16 : 8);
22 words
[i
] &= ((1 << b
) - 1);
26 return String
.prototype.format
.apply(
27 v6
? '%x:%x:%x:%x:%x:%x:%x:%x' : '%d.%d.%d.%d', words
);
33 callNetworkInterfaceDump(),
34 L
.resolveDefault(fs
.exec('/sbin/ip', [ '-4', 'neigh', 'show' ]), {}),
35 L
.resolveDefault(fs
.exec('/sbin/ip', [ '-4', 'route', 'show', 'table', 'all' ]), {}),
36 L
.resolveDefault(fs
.exec('/sbin/ip', [ '-4', 'rule', 'show' ]), {}),
37 L
.resolveDefault(fs
.exec('/sbin/ip', [ '-6', 'neigh', 'show' ]), {}),
38 L
.resolveDefault(fs
.exec('/sbin/ip', [ '-6', 'route', 'show', 'table', 'all' ]), {}),
39 L
.resolveDefault(fs
.exec('/sbin/ip', [ '-6', 'rule', 'show' ]), {})
43 getNetworkByDevice(networks
, dev
, addr
, mask
, v6
) {
44 var addr_arrays
= [ 'ipv4-address', 'ipv6-address', 'ipv6-prefix', 'ipv6-prefix-assignment', 'route' ],
45 matching_iface
= null,
48 for (var i
= 0; i
< networks
.length
; i
++) {
49 if (!L
.isObject(networks
[i
]))
52 if (networks
[i
].l3_device
!= dev
&& networks
[i
].device
!= dev
)
55 for (var j
= 0; j
< addr_arrays
.length
; j
++) {
56 var addr_list
= networks
[i
][addr_arrays
[j
]];
58 if (!Array
.isArray(addr_list
) || addr_list
.length
== 0)
61 for (var k
= 0; k
< addr_list
.length
; k
++) {
62 var cmp_addr
= addr_list
[k
].address
|| addr_list
[k
].target
,
63 cmp_mask
= addr_list
[k
].mask
;
68 var addr1
= applyMask(cmp_addr
, cmp_mask
, v6
),
69 addr2
= applyMask(addr
, cmp_mask
, v6
);
71 if (addr1
!= addr2
|| mask
< cmp_mask
)
74 if (cmp_mask
> matching_prefix
) {
75 matching_iface
= networks
[i
].interface;
76 matching_prefix
= cmp_mask
;
82 return matching_iface
;
85 parseNeigh: function(s
, networks
, v6
) {
86 var lines
= s
.trim().split(/\n/),
89 for (var i
= 0; i
< lines
.length
; i
++) {
90 var m
= lines
[i
].match(/^([0-9a-f:.]+) (.+) (\S+)$/),
91 addr
= m
? m
[1] : null,
92 flags
= m
? m
[2].trim().split(/\s+/) : [],
93 state
= (m
? m
[3] : null) || 'FAILED';
95 if (!addr
|| state
== 'FAILED' || addr
.match(/^fe[89a-f][0-9a-f]:/))
98 for (var j
= 0; j
< flags
.length
; j
+= 2)
99 flags
[flags
[j
]] = flags
[j
+ 1];
104 var net
= this.getNetworkByDevice(networks
, flags
.dev
, addr
, v6
? 128 : 32, v6
);
108 flags
.lladdr
.toUpperCase(),
109 E('span', { 'class': 'ifacebadge' }, [ net
? net
: '(%s)'.format(flags
.dev
) ])
116 parseRoute: function(s
, networks
, v6
) {
117 var lines
= s
.trim().split(/\n/),
120 for (var i
= 0; i
< lines
.length
; i
++) {
121 var m
= lines
[i
].match(/^(?:([a-z_]+|\d+) )?(default|[0-9a-f:.\/]+) (.+)$/),
122 type
= (m
? m
[1] : null) || 'unicast',
123 dest
= m
? (m
[2] == 'default' ? (v6
? '::/0' : '0.0.0.0/0') : m
[2]) : null,
124 flags
= m
? m
[3].trim().split(/\s+/) : [];
126 if (!dest
|| type
!= 'unicast' || dest
== 'fe80::/64' || dest
== 'ff00::/8')
129 for (var j
= 0; j
< flags
.length
; j
+= 2)
130 flags
[flags
[j
]] = flags
[j
+ 1];
132 var addr
= dest
.split('/'),
133 bits
= (addr
[1] != null) ? +addr
[1] : (v6
? 128 : 32),
134 net
= this.getNetworkByDevice(networks
, flags
.dev
, addr
[0], bits
, v6
);
137 E('span', { 'class': 'ifacebadge' }, [ net
? net
: '(%s)'.format(flags
.dev
) ]),
139 (v6
? flags
.from : flags
.via
) || '-',
140 String(flags
.metric
|| 0),
141 flags
.table
|| 'main',
149 parseRule: function(s
) {
150 var lines
= s
.trim().split(/\n/),
153 for (var i
= 0; i
< lines
.length
; i
++) {
154 var m
= lines
[i
].match(/^(\d+):\s+(.+)$/),
155 prio
= m
? m
[1] : null,
156 rule
= m
? m
[2] : null;
167 render: function(data
) {
168 var networks
= data
[0],
169 ip4neigh
= data
[1].stdout
|| '',
170 ip4route
= data
[2].stdout
|| '',
171 ip4rule
= data
[3].stdout
|| '',
172 ip6neigh
= data
[4].stdout
|| '',
173 ip6route
= data
[5].stdout
|| '',
174 ip6rule
= data
[6].stdout
|| '';
176 var neigh4tbl
= E('table', { 'class': 'table' }, [
177 E('tr', { 'class': 'tr table-titles' }, [
178 E('th', { 'class': 'th' }, [ _('IP address') ]),
179 E('th', { 'class': 'th' }, [ _('MAC address') ]),
180 E('th', { 'class': 'th' }, [ _('Interface') ])
184 var route4tbl
= E('table', { 'class': 'table' }, [
185 E('tr', { 'class': 'tr table-titles' }, [
186 E('th', { 'class': 'th' }, [ _('Network') ]),
187 E('th', { 'class': 'th' }, [ _('Target') ]),
188 E('th', { 'class': 'th' }, [ _('Gateway') ]),
189 E('th', { 'class': 'th' }, [ _('Metric') ]),
190 E('th', { 'class': 'th' }, [ _('Table') ]),
191 E('th', { 'class': 'th' }, [ _('Protocol') ])
195 var rule4tbl
= E('table', { 'class': 'table' }, [
196 E('tr', { 'class': 'tr table-titles' }, [
197 E('th', { 'class': 'th' }, [ _('Priority') ]),
198 E('th', { 'class': 'th' }, [ _('Rule') ])
202 var neigh6tbl
= E('table', { 'class': 'table' }, [
203 E('tr', { 'class': 'tr table-titles' }, [
204 E('th', { 'class': 'th' }, [ _('IP address') ]),
205 E('th', { 'class': 'th' }, [ _('MAC address') ]),
206 E('th', { 'class': 'th' }, [ _('Interface') ])
210 var route6tbl
= E('table', { 'class': 'table' }, [
211 E('tr', { 'class': 'tr table-titles' }, [
212 E('th', { 'class': 'th' }, [ _('Network') ]),
213 E('th', { 'class': 'th' }, [ _('Target') ]),
214 E('th', { 'class': 'th' }, [ _('Source') ]),
215 E('th', { 'class': 'th' }, [ _('Metric') ]),
216 E('th', { 'class': 'th' }, [ _('Table') ]),
217 E('th', { 'class': 'th' }, [ _('Protocol') ])
221 var rule6tbl
= E('table', { 'class': 'table' }, [
222 E('tr', { 'class': 'tr table-titles' }, [
223 E('th', { 'class': 'th' }, [ _('Priority') ]),
224 E('th', { 'class': 'th' }, [ _('Rule') ])
228 cbi_update_table(neigh4tbl
, this.parseNeigh(ip4neigh
, networks
, false));
229 cbi_update_table(route4tbl
, this.parseRoute(ip4route
, networks
, false));
230 cbi_update_table(rule4tbl
, this.parseRule(ip4rule
, networks
, false));
231 cbi_update_table(neigh6tbl
, this.parseNeigh(ip6neigh
, networks
, true));
232 cbi_update_table(route6tbl
, this.parseRoute(ip6route
, networks
, true));
233 cbi_update_table(rule6tbl
, this.parseRule(ip6rule
, networks
, false));
236 E('h2', {}, [ _('Routing') ]),
237 E('p', {}, [ _('The following rules are currently active on this system.') ]),
239 E('div', { 'data-tab': 'ipv4routing', 'data-tab-title': _('IPv4 Routing') }, [
240 E('h3', {}, [ _('IPv4 Neighbours') ]),
243 E('h3', {}, [ _('Active IPv4 Routes') ]),
246 E('h3', {}, [ _('Active IPv4 Rules') ]),
249 E('div', { 'data-tab': 'ipv6routing', 'data-tab-title': _('IPv6 Routing') }, [
250 E('h3', {}, [ _('IPv6 Neighbours') ]),
253 E('h3', {}, [ _('Active IPv6 Routes') ]),
256 E('h3', {}, [ _('Active IPv6 Rules') ]),
262 ui
.tabs
.initTabGroup(view
.lastElementChild
.childNodes
);
267 handleSaveApply
: null,