7 var callNetworkInterfaceDump
= rpc
.declare({
8 object
: 'network.interface',
10 expect
: { interface: [] }
13 function applyMask(addr
, mask
, v6
) {
14 var words
= v6
? validation
.parseIPv6(addr
) : validation
.parseIPv4(addr
);
16 if (!words
|| mask
< 0 || mask
> (v6
? 128 : 32))
19 for (var i
= 0; i
< words
.length
; i
++) {
20 var b
= Math
.min(mask
, v6
? 16 : 8);
21 words
[i
] &= ((1 << b
) - 1);
25 return String
.prototype.format
.apply(
26 v6
? '%x:%x:%x:%x:%x:%x:%x:%x' : '%d.%d.%d.%d', words
);
32 callNetworkInterfaceDump(),
33 L
.resolveDefault(fs
.exec('/sbin/ip', [ '-4', 'neigh', 'show' ]), {}),
34 L
.resolveDefault(fs
.exec('/sbin/ip', [ '-4', 'route', 'show', 'table', 'all' ]), {}),
35 L
.resolveDefault(fs
.exec('/sbin/ip', [ '-6', 'neigh', 'show' ]), {}),
36 L
.resolveDefault(fs
.exec('/sbin/ip', [ '-6', 'route', 'show', 'table', 'all' ]), {})
40 getNetworkByDevice(networks
, dev
, addr
, mask
, v6
) {
41 var addr_arrays
= [ 'ipv4-address', 'ipv6-address', 'ipv6-prefix', 'ipv6-prefix-assignment', 'route' ],
42 matching_iface
= null,
45 for (var i
= 0; i
< networks
.length
; i
++) {
46 if (!L
.isObject(networks
[i
]))
49 if (networks
[i
].l3_device
!= dev
&& networks
[i
].device
!= dev
)
52 for (var j
= 0; j
< addr_arrays
.length
; j
++) {
53 var addr_list
= networks
[i
][addr_arrays
[j
]];
55 if (!Array
.isArray(addr_list
) || addr_list
.length
== 0)
58 for (var k
= 0; k
< addr_list
.length
; k
++) {
59 var cmp_addr
= addr_list
[k
].address
|| addr_list
[k
].target
,
60 cmp_mask
= addr_list
[k
].mask
;
65 var addr1
= applyMask(cmp_addr
, cmp_mask
, v6
),
66 addr2
= applyMask(addr
, cmp_mask
, v6
);
68 if (addr1
!= addr2
|| mask
< cmp_mask
)
71 if (cmp_mask
> matching_prefix
) {
72 matching_iface
= networks
[i
].interface;
73 matching_prefix
= cmp_mask
;
79 return matching_iface
;
82 parseNeigh: function(s
, networks
, v6
) {
83 var lines
= s
.trim().split(/\n/),
86 for (var i
= 0; i
< lines
.length
; i
++) {
87 var m
= lines
[i
].match(/^([0-9a-f:.]+) (.+) (\S+)$/),
88 addr
= m
? m
[1] : null,
89 flags
= m
? m
[2].trim().split(/\s+/) : [],
90 state
= (m
? m
[3] : null) || 'FAILED';
92 if (!addr
|| state
== 'FAILED' || addr
.match(/^fe[89a-f][0-9a-f]:/))
95 for (var j
= 0; j
< flags
.length
; j
+= 2)
96 flags
[flags
[j
]] = flags
[j
+ 1];
101 var net
= this.getNetworkByDevice(networks
, flags
.dev
, addr
, v6
? 128 : 32, v6
);
105 flags
.lladdr
.toUpperCase(),
106 E('span', { 'class': 'ifacebadge' }, [ net
? net
: '(%s)'.format(flags
.dev
) ])
113 parseRoute: function(s
, networks
, v6
) {
114 var lines
= s
.trim().split(/\n/),
117 for (var i
= 0; i
< lines
.length
; i
++) {
118 var m
= lines
[i
].match(/^(?:([a-z_]+|\d+) )?(default|[0-9a-f:.\/]+) (.+)$/),
119 type
= (m
? m
[1] : null) || 'unicast',
120 dest
= m
? (m
[2] == 'default' ? (v6
? '::/0' : '0.0.0.0/0') : m
[2]) : null,
121 flags
= m
? m
[3].trim().split(/\s+/) : [];
123 if (!dest
|| type
!= 'unicast' || dest
== 'fe80::/64' || dest
== 'ff00::/8')
126 for (var j
= 0; j
< flags
.length
; j
+= 2)
127 flags
[flags
[j
]] = flags
[j
+ 1];
129 var addr
= dest
.split('/'),
130 bits
= (addr
[1] != null) ? +addr
[1] : (v6
? 128 : 32),
131 net
= this.getNetworkByDevice(networks
, flags
.dev
, addr
[0], bits
, v6
);
134 E('span', { 'class': 'ifacebadge' }, [ net
? net
: '(%s)'.format(flags
.dev
) ]),
136 (v6
? flags
.from : flags
.via
) || '-',
137 String(flags
.metric
|| 0),
138 flags
.table
|| 'main'
145 render: function(data
) {
146 var networks
= data
[0],
147 ip4neigh
= data
[1].stdout
|| '',
148 ip4route
= data
[2].stdout
|| '',
149 ip6neigh
= data
[3].stdout
|| '',
150 ip6route
= data
[4].stdout
|| '';
152 var neigh4tbl
= E('div', { 'class': 'table' }, [
153 E('div', { 'class': 'tr table-titles' }, [
154 E('div', { 'class': 'th' }, [ _('IPv4-Address') ]),
155 E('div', { 'class': 'th' }, [ _('MAC-Address') ]),
156 E('div', { 'class': 'th' }, [ _('Interface') ])
160 var route4tbl
= E('div', { 'class': 'table' }, [
161 E('div', { 'class': 'tr table-titles' }, [
162 E('div', { 'class': 'th' }, [ _('Network') ]),
163 E('div', { 'class': 'th' }, [ _('Target') ]),
164 E('div', { 'class': 'th' }, [ _('IPv4-Gateway') ]),
165 E('div', { 'class': 'th' }, [ _('Metric') ]),
166 E('div', { 'class': 'th' }, [ _('Table') ])
170 var neigh6tbl
= E('div', { 'class': 'table' }, [
171 E('div', { 'class': 'tr table-titles' }, [
172 E('div', { 'class': 'th' }, [ _('IPv6-Address') ]),
173 E('div', { 'class': 'th' }, [ _('MAC-Address') ]),
174 E('div', { 'class': 'th' }, [ _('Interface') ])
178 var route6tbl
= E('div', { 'class': 'table' }, [
179 E('div', { 'class': 'tr table-titles' }, [
180 E('div', { 'class': 'th' }, [ _('Network') ]),
181 E('div', { 'class': 'th' }, [ _('Target') ]),
182 E('div', { 'class': 'th' }, [ _('Source') ]),
183 E('div', { 'class': 'th' }, [ _('Metric') ]),
184 E('div', { 'class': 'th' }, [ _('Table') ])
188 cbi_update_table(neigh4tbl
, this.parseNeigh(ip4neigh
, networks
, false));
189 cbi_update_table(route4tbl
, this.parseRoute(ip4route
, networks
, false));
190 cbi_update_table(neigh6tbl
, this.parseNeigh(ip6neigh
, networks
, true));
191 cbi_update_table(route6tbl
, this.parseRoute(ip6route
, networks
, true));
194 E('h2', {}, [ _('Routes') ]),
195 E('p', {}, [ _('The following rules are currently active on this system.') ]),
197 E('h3', {}, [ _('ARP') ]),
200 E('h3', {}, _('Active <abbr title="Internet Protocol Version 4">IPv4</abbr>-Routes')),
203 E('h3', {}, [ _('IPv6 Neighbours') ]),
206 E('h3', {}, _('Active <abbr title="Internet Protocol Version 6">IPv6</abbr>-Routes')),
211 handleSaveApply
: null,