6 var callNetworkInterfaceDump
= rpc
.declare({
7 object
: 'network.interface',
9 expect
: { interface: [] }
12 function applyMask(addr
, mask
, v6
) {
13 var words
= v6
? validation
.parseIPv6(addr
) : validation
.parseIPv4(addr
);
15 if (!words
|| mask
< 0 || mask
> (v6
? 128 : 32))
18 for (var i
= 0; i
< words
.length
; i
++) {
19 var b
= Math
.min(mask
, v6
? 16 : 8);
20 words
[i
] &= ((1 << b
) - 1);
24 return String
.prototype.format
.apply(
25 v6
? '%x:%x:%x:%x:%x:%x:%x:%x' : '%d.%d.%d.%d', words
);
28 return L
.view
.extend({
31 callNetworkInterfaceDump(),
32 L
.resolveDefault(fs
.exec('/sbin/ip', [ '-4', 'neigh', 'show' ]), {}),
33 L
.resolveDefault(fs
.exec('/sbin/ip', [ '-4', 'route', 'show', 'table', 'all' ]), {}),
34 L
.resolveDefault(fs
.exec('/sbin/ip', [ '-6', 'neigh', 'show' ]), {}),
35 L
.resolveDefault(fs
.exec('/sbin/ip', [ '-6', 'route', 'show', 'table', 'all' ]), {})
39 getNetworkByDevice(networks
, dev
, addr
, mask
, v6
) {
40 var addr_arrays
= [ 'ipv4-address', 'ipv6-address', 'ipv6-prefix', 'ipv6-prefix-assignment', 'route' ],
41 matching_iface
= null,
44 for (var i
= 0; i
< networks
.length
; i
++) {
45 if (!L
.isObject(networks
[i
]))
48 if (networks
[i
].l3_device
!= dev
&& networks
[i
].device
!= dev
)
51 for (var j
= 0; j
< addr_arrays
.length
; j
++) {
52 var addr_list
= networks
[i
][addr_arrays
[j
]];
54 if (!Array
.isArray(addr_list
) || addr_list
.length
== 0)
57 for (var k
= 0; k
< addr_list
.length
; k
++) {
58 var cmp_addr
= addr_list
[k
].address
|| addr_list
[k
].target
,
59 cmp_mask
= addr_list
[k
].mask
;
64 var addr1
= applyMask(cmp_addr
, cmp_mask
, v6
),
65 addr2
= applyMask(addr
, cmp_mask
, v6
);
67 if (addr1
!= addr2
|| mask
< cmp_mask
)
70 if (cmp_mask
> matching_prefix
) {
71 matching_iface
= networks
[i
].interface;
72 matching_prefix
= cmp_mask
;
78 return matching_iface
;
81 parseNeigh: function(s
, networks
, v6
) {
82 var lines
= s
.trim().split(/\n/),
85 for (var i
= 0; i
< lines
.length
; i
++) {
86 var m
= lines
[i
].match(/^([0-9a-f:.]+) (.+) (\S+)$/),
87 addr
= m
? m
[1] : null,
88 flags
= m
? m
[2].trim().split(/\s+/) : [],
89 state
= (m
? m
[3] : null) || 'FAILED';
91 if (!addr
|| state
== 'FAILED' || addr
.match(/^fe[89a-f][0-9a-f]:/))
94 for (var j
= 0; j
< flags
.length
; j
+= 2)
95 flags
[flags
[j
]] = flags
[j
+ 1];
100 var net
= this.getNetworkByDevice(networks
, flags
.dev
, addr
, v6
? 128 : 32, v6
);
104 flags
.lladdr
.toUpperCase(),
105 E('span', { 'class': 'ifacebadge' }, [ net
? net
: '(%s)'.format(flags
.dev
) ])
112 parseRoute: function(s
, networks
, v6
) {
113 var lines
= s
.trim().split(/\n/),
116 for (var i
= 0; i
< lines
.length
; i
++) {
117 var m
= lines
[i
].match(/^(?:([a-z_]+|\d+) )?(default|[0-9a-f:.\/]+) (.+)$/),
118 type
= (m
? m
[1] : null) || 'unicast',
119 dest
= m
? (m
[2] == 'default' ? (v6
? '::/0' : '0.0.0.0/0') : m
[2]) : null,
120 flags
= m
? m
[3].trim().split(/\s+/) : [];
122 if (!dest
|| type
!= 'unicast' || dest
== 'fe80::/64' || dest
== 'ff00::/8')
125 for (var j
= 0; j
< flags
.length
; j
+= 2)
126 flags
[flags
[j
]] = flags
[j
+ 1];
128 var addr
= dest
.split('/'),
129 bits
= (addr
[1] != null) ? +addr
[1] : (v6
? 128 : 32),
130 net
= this.getNetworkByDevice(networks
, flags
.dev
, addr
[0], bits
, v6
);
133 E('span', { 'class': 'ifacebadge' }, [ net
? net
: '(%s)'.format(flags
.dev
) ]),
135 (v6
? flags
.from : flags
.via
) || '-',
136 String(flags
.metric
|| 0),
137 flags
.table
|| 'main'
144 render: function(data
) {
145 var networks
= data
[0],
146 ip4neigh
= data
[1].stdout
|| '',
147 ip4route
= data
[2].stdout
|| '',
148 ip6neigh
= data
[3].stdout
|| '',
149 ip6route
= data
[4].stdout
|| '';
151 var neigh4tbl
= E('div', { 'class': 'table' }, [
152 E('div', { 'class': 'tr table-titles' }, [
153 E('div', { 'class': 'th' }, [ _('IPv4-Address') ]),
154 E('div', { 'class': 'th' }, [ _('MAC-Address') ]),
155 E('div', { 'class': 'th' }, [ _('Interface') ])
159 var route4tbl
= E('div', { 'class': 'table' }, [
160 E('div', { 'class': 'tr table-titles' }, [
161 E('div', { 'class': 'th' }, [ _('Network') ]),
162 E('div', { 'class': 'th' }, [ _('Target') ]),
163 E('div', { 'class': 'th' }, [ _('IPv4-Gateway') ]),
164 E('div', { 'class': 'th' }, [ _('Metric') ]),
165 E('div', { 'class': 'th' }, [ _('Table') ])
169 var neigh6tbl
= E('div', { 'class': 'table' }, [
170 E('div', { 'class': 'tr table-titles' }, [
171 E('div', { 'class': 'th' }, [ _('IPv6-Address') ]),
172 E('div', { 'class': 'th' }, [ _('MAC-Address') ]),
173 E('div', { 'class': 'th' }, [ _('Interface') ])
177 var route6tbl
= E('div', { 'class': 'table' }, [
178 E('div', { 'class': 'tr table-titles' }, [
179 E('div', { 'class': 'th' }, [ _('Network') ]),
180 E('div', { 'class': 'th' }, [ _('Target') ]),
181 E('div', { 'class': 'th' }, [ _('Source') ]),
182 E('div', { 'class': 'th' }, [ _('Metric') ]),
183 E('div', { 'class': 'th' }, [ _('Table') ])
187 cbi_update_table(neigh4tbl
, this.parseNeigh(ip4neigh
, networks
, false));
188 cbi_update_table(route4tbl
, this.parseRoute(ip4route
, networks
, false));
189 cbi_update_table(neigh6tbl
, this.parseNeigh(ip6neigh
, networks
, true));
190 cbi_update_table(route6tbl
, this.parseRoute(ip6route
, networks
, true));
193 E('h2', {}, [ _('Routes') ]),
194 E('p', {}, [ _('The following rules are currently active on this system.') ]),
196 E('h3', {}, [ _('ARP') ]),
199 E('h3', {}, _('Active <abbr title="Internet Protocol Version 4">IPv4</abbr>-Routes')),
202 E('h3', {}, [ _('IPv6 Neighbours') ]),
205 E('h3', {}, _('Active <abbr title="Internet Protocol Version 6">IPv6</abbr>-Routes')),
210 handleSaveApply
: null,