@@ -165,12 +165,34 @@ export function NetworkManagerModel() {
165
165
const client = cockpit . dbus ( "org.freedesktop.NetworkManager" , { superuser : "try" } ) ;
166
166
self . client = client ;
167
167
168
+ // set to false by default as newer API is backwards compatible
169
+ // and supports both "dns" and "dns-data" properties
170
+ // dns-data property was added in version 1.42.0
171
+ self . supports_dns_data = false ;
172
+
173
+ function check_version_dns_data_support ( version ) {
174
+ if ( version . length < 2 ) {
175
+ return false ;
176
+ }
177
+
178
+ if ( version [ 0 ] > 1 ) {
179
+ return true ;
180
+ } else if ( version [ 0 ] === 1 && version [ 1 ] >= 42 ) {
181
+ return true ;
182
+ }
183
+
184
+ return false ;
185
+ }
186
+
168
187
/* resolved once first stage of initialization is done */
169
188
self . preinit = new Promise ( ( resolve , reject ) => {
170
189
client . call ( "/org/freedesktop/NetworkManager" ,
171
190
"org.freedesktop.DBus.Properties" , "Get" ,
172
- [ "org.freedesktop.NetworkManager" , "State " ] , { flags : "" } )
191
+ [ "org.freedesktop.NetworkManager" , "Version " ] , { flags : "" } )
173
192
. then ( ( reply , options ) => {
193
+ const nm_version = reply [ 0 ] . v . split ( "." ) . map ( n => Number . parseInt ( n ) ) ;
194
+ self . supports_dns_data = check_version_dns_data_support ( nm_version ) ;
195
+
174
196
if ( options . flags ) {
175
197
if ( options . flags . indexOf ( ">" ) !== - 1 )
176
198
utils . set_byteorder ( "be" ) ;
@@ -421,63 +443,52 @@ export function NetworkManagerModel() {
421
443
/* NetworkManager specific data conversions and utility functions.
422
444
*/
423
445
424
- function ip4_address_from_nm ( addr ) {
425
- return [ utils . ip4_to_text ( addr [ 0 ] ) ,
426
- utils . ip_prefix_to_text ( addr [ 1 ] ) ,
427
- utils . ip4_to_text ( addr [ 2 ] , true )
428
- ] ;
446
+ function ip_address_from_nm ( addr ) {
447
+ return {
448
+ address : addr . address . v ,
449
+ prefix : utils . ip_prefix_to_text ( addr . prefix . v )
450
+ } ;
429
451
}
430
452
431
- function ip4_address_to_nm ( addr ) {
432
- return [ utils . ip4_from_text ( addr [ 0 ] ) ,
433
- utils . ip4_prefix_from_text ( addr [ 1 ] ) ,
434
- utils . ip4_from_text ( addr [ 2 ] , true )
435
- ] ;
436
- }
453
+ function ip_address_to_nm ( addr , ipv ) {
454
+ const prefix = ipv === "ipv4" ? utils . ip4_prefix_from_text ( addr . prefix ) : utils . ip_prefix_from_text ( addr . prefix ) ;
437
455
438
- function ip4_route_from_nm ( addr ) {
439
- return [ utils . ip4_to_text ( addr [ 0 ] ) ,
440
- utils . ip_prefix_to_text ( addr [ 1 ] ) ,
441
- utils . ip4_to_text ( addr [ 2 ] , true ) ,
442
- utils . ip_metric_to_text ( addr [ 3 ] )
443
- ] ;
444
- }
456
+ if ( ! utils . validate_ip ( addr . address ) ) {
457
+ throw cockpit . format ( _ ( "Invalid IP address: $0" ) , addr . address ) ;
458
+ }
445
459
446
- function ip4_route_to_nm ( addr ) {
447
- return [ utils . ip4_from_text ( addr [ 0 ] ) ,
448
- utils . ip4_prefix_from_text ( addr [ 1 ] ) ,
449
- utils . ip4_from_text ( addr [ 2 ] , true ) ,
450
- utils . ip_metric_from_text ( addr [ 3 ] )
451
- ] ;
452
- }
453
- function ip6_address_from_nm ( addr ) {
454
- return [ utils . ip6_to_text ( addr [ 0 ] ) ,
455
- utils . ip_prefix_to_text ( addr [ 1 ] ) ,
456
- utils . ip6_to_text ( addr [ 2 ] , true )
457
- ] ;
460
+ return {
461
+ address : { t : "s" , v : addr . address } ,
462
+ prefix : { t : "u" , v : prefix } ,
463
+ } ;
458
464
}
459
465
460
- function ip6_address_to_nm ( addr ) {
461
- return [ utils . ip6_from_text ( addr [ 0 ] ) ,
462
- parseInt ( addr [ 1 ] , 10 ) || 64 ,
463
- utils . ip6_from_text ( addr [ 2 ] , true )
464
- ] ;
466
+ function route_from_nm ( route ) {
467
+ return {
468
+ dest : route . dest . v ,
469
+ prefix : utils . ip_prefix_to_text ( route . prefix . v ) ,
470
+ next_hop : route [ "next-hop" ] . v ,
471
+ metric : utils . ip_metric_to_text ( route . metric . v ) ,
472
+ } ;
465
473
}
466
474
467
- function ip6_route_from_nm ( addr ) {
468
- return [ utils . ip6_to_text ( addr [ 0 ] ) ,
469
- utils . ip_prefix_to_text ( addr [ 1 ] ) ,
470
- utils . ip6_to_text ( addr [ 2 ] , true ) ,
471
- utils . ip_metric_to_text ( addr [ 3 ] ) ,
472
- ] ;
473
- }
475
+ function route_to_nm ( route , ipv ) {
476
+ const prefix = ipv === "ipv4" ? utils . ip4_prefix_from_text ( route . prefix ) : utils . ip_prefix_from_text ( route . prefix ) ;
477
+
478
+ if ( ! utils . validate_ip ( route . dest ) ) {
479
+ throw cockpit . format ( _ ( "Invalid destination address: $0" ) , route . dest ) ;
480
+ }
481
+
482
+ if ( ! utils . validate_ip ( route . next_hop ) ) {
483
+ throw cockpit . format ( _ ( "Invalid gateway address: $0" ) , route . next_hop ) ;
484
+ }
474
485
475
- function ip6_route_to_nm ( addr ) {
476
- return [ utils . ip6_from_text ( addr [ 0 ] ) ,
477
- utils . ip_prefix_from_text ( addr [ 1 ] ) ,
478
- utils . ip6_from_text ( addr [ 2 ] , true ) ,
479
- utils . ip_metric_from_text ( addr [ 3 ] )
480
- ] ;
486
+ return {
487
+ dest : { t : "s" , v : route . dest } ,
488
+ prefix : { t : "u" , v : prefix } ,
489
+ "next-hop" : { t : "s" , v : route . next_hop } ,
490
+ metric : { t : "u" , v : utils . ip_metric_from_text ( route . metric ) } ,
491
+ } ;
481
492
}
482
493
483
494
function settings_from_nm ( settings ) {
@@ -488,15 +499,20 @@ export function NetworkManagerModel() {
488
499
return def ;
489
500
}
490
501
491
- function get_ip ( first , addr_from_nm , route_from_nm , ip_to_text ) {
502
+ function get_ip ( first , ip_to_text ) {
503
+ const dns_data = self . supports_dns_data
504
+ ? get ( first , "dns-data" , [ ] )
505
+ : get ( first , "dns" , [ ] ) . map ( ip_to_text ) ;
506
+
492
507
return {
493
508
method : get ( first , "method" , "auto" ) ,
494
509
ignore_auto_dns : get ( first , "ignore-auto-dns" , false ) ,
495
510
ignore_auto_routes : get ( first , "ignore-auto-routes" , false ) ,
496
- addresses : get ( first , "addresses" , [ ] ) . map ( addr_from_nm ) ,
497
- dns : get ( first , "dns" , [ ] ) . map ( ip_to_text ) ,
511
+ address_data : get ( first , "address-data" , [ ] ) . map ( ip_address_from_nm ) ,
512
+ gateway : get ( first , "gateway" , "" ) ,
513
+ dns_data,
498
514
dns_search : get ( first , "dns-search" , [ ] ) ,
499
- routes : get ( first , "routes " , [ ] ) . map ( route_from_nm )
515
+ route_data : get ( first , "route-data " , [ ] ) . map ( route_from_nm ) ,
500
516
} ;
501
517
}
502
518
@@ -516,8 +532,8 @@ export function NetworkManagerModel() {
516
532
} ;
517
533
518
534
if ( ! settings . connection . master ) {
519
- result . ipv4 = get_ip ( "ipv4" , ip4_address_from_nm , ip4_route_from_nm , utils . ip4_to_text ) ;
520
- result . ipv6 = get_ip ( "ipv6" , ip6_address_from_nm , ip6_route_from_nm , utils . ip6_to_text ) ;
535
+ result . ipv4 = get_ip ( "ipv4" , utils . ip4_to_text ) ;
536
+ result . ipv6 = get_ip ( "ipv6" , utils . ip6_to_text ) ;
521
537
}
522
538
523
539
if ( settings [ "802-3-ethernet" ] ) {
@@ -612,31 +628,61 @@ export function NetworkManagerModel() {
612
628
delete result [ first ] [ second ] ;
613
629
}
614
630
615
- function set_ip ( first , addrs_sig , addr_to_nm , routes_sig , route_to_nm , ips_sig , ip_from_text ) {
631
+ function set_ip ( first , dns_ip_sig , ip_from_text ) {
616
632
set ( first , "method" , 's' , settings [ first ] . method ) ;
617
633
set ( first , "ignore-auto-dns" , 'b' , settings [ first ] . ignore_auto_dns ) ;
618
634
set ( first , "ignore-auto-routes" , 'b' , settings [ first ] . ignore_auto_routes ) ;
619
635
set ( first , "addr-gen-mode" , 'i' , settings [ first ] . addr_gen_mode ) ;
620
636
621
- const addresses = settings [ first ] . addresses ;
637
+ const addresses = settings [ first ] . address_data ;
622
638
if ( addresses )
623
- set ( first , "addresses" , addrs_sig , addresses . map ( addr_to_nm ) ) ;
639
+ set ( first , "address-data" , "aa{sv}" , addresses . map ( addr => ip_address_to_nm ( addr , first ) ) ) ;
640
+
641
+ const gateway = settings [ first ] . gateway ;
642
+ if ( gateway && addresses . length > 0 ) {
643
+ if ( ! utils . validate_ip ( gateway ) ) {
644
+ throw cockpit . format ( _ ( "Invalid gateway address: $0" ) , gateway ) ;
645
+ }
646
+ set ( first , "gateway" , "s" , gateway ) ;
647
+ } else {
648
+ // gateway cannot be set if there are no addresses
649
+ delete result [ first ] . gateway ;
650
+ }
651
+
652
+ const dns = settings [ first ] . dns_data ;
653
+ if ( dns ) {
654
+ const invalid = dns . find ( addr => ! utils . validate_ip ( addr ) ) ;
655
+ if ( invalid ) {
656
+ throw cockpit . format ( _ ( "Invalid DNS address: $0" ) , invalid ) ;
657
+ }
658
+
659
+ if ( self . supports_dns_data ) {
660
+ set ( first , "dns-data" , "as" , dns ) ;
661
+ } else {
662
+ set ( first , "dns" , dns_ip_sig , dns . map ( addr => ip_from_text ( addr ) ) ) ;
663
+ }
664
+ }
624
665
625
- const dns = settings [ first ] . dns ;
626
- if ( dns )
627
- set ( first , "dns" , ips_sig , dns . map ( ip_from_text ) ) ;
628
666
set ( first , "dns-search" , 'as' , settings [ first ] . dns_search ) ;
629
667
630
- const routes = settings [ first ] . routes ;
668
+ const routes = settings [ first ] . route_data ;
631
669
if ( routes )
632
- set ( first , "routes " , routes_sig , routes . map ( route_to_nm ) ) ;
670
+ set ( first , "route-data " , "aa{sv}" , routes . map ( route => route_to_nm ( route , first ) ) ) ;
633
671
634
672
// Never pass "address-labels" back to NetworkManager. It
635
673
// is documented as "internal only", but needs to somehow
636
674
// stay in sync with "addresses". By not passing it back
637
675
// we don't have to worry about that.
638
676
//
639
677
delete result [ first ] [ "address-labels" ] ;
678
+
679
+ // Never pass "addresses", instead use "address-data" + "gateway"
680
+ delete result [ first ] . addresses ;
681
+ // Never pass "routes", instead use "route-data"
682
+ delete result [ first ] . routes ;
683
+ // Never pass "dns" if "dns-data" is supported
684
+ if ( self . supports_dns_data )
685
+ delete result [ first ] . dns ;
640
686
}
641
687
642
688
set ( "connection" , "id" , 's' , settings . connection . id ) ;
@@ -649,12 +695,12 @@ export function NetworkManagerModel() {
649
695
set ( "connection" , "master" , 's' , settings . connection . group ) ;
650
696
651
697
if ( settings . ipv4 )
652
- set_ip ( "ipv4" , 'aau' , ip4_address_to_nm , 'aau' , ip4_route_to_nm , ' au', utils . ip4_from_text ) ;
698
+ set_ip ( "ipv4" , 'au' , utils . ip4_from_text ) ;
653
699
else
654
700
delete result . ipv4 ;
655
701
656
702
if ( settings . ipv6 )
657
- set_ip ( "ipv6" , 'a(ayuay)' , ip6_address_to_nm , 'a(ayuayu)' , ip6_route_to_nm , ' aay', utils . ip6_from_text ) ;
703
+ set_ip ( "ipv6" , 'aay' , utils . ip6_from_text ) ;
658
704
else
659
705
delete result . ipv6 ;
660
706
@@ -881,7 +927,7 @@ export function NetworkManagerModel() {
881
927
] ,
882
928
883
929
props : {
884
- Addresses : { conv : conv_Array ( ip4_address_from_nm ) , def : [ ] }
930
+ AddressData : { conv : conv_Array ( ip_address_from_nm ) , def : [ ] }
885
931
}
886
932
} ;
887
933
@@ -891,7 +937,7 @@ export function NetworkManagerModel() {
891
937
] ,
892
938
893
939
props : {
894
- Addresses : { conv : conv_Array ( ip6_address_from_nm ) , def : [ ] }
940
+ AddressData : { conv : conv_Array ( ip_address_from_nm ) , def : [ ] }
895
941
}
896
942
} ;
897
943
@@ -1356,8 +1402,8 @@ export function device_state_text(dev) {
1356
1402
return _ ( "No carrier" ) ;
1357
1403
if ( ! is_managed ( dev ) ) {
1358
1404
if ( ! dev . ActiveConnection &&
1359
- ( ! dev . Ip4Config || dev . Ip4Config . Addresses . length === 0 ) &&
1360
- ( ! dev . Ip6Config || dev . Ip6Config . Addresses . length === 0 ) )
1405
+ ( ! dev . Ip4Config || dev . Ip4Config . AddressData . length === 0 ) &&
1406
+ ( ! dev . Ip6Config || dev . Ip6Config . AddressData . length === 0 ) )
1361
1407
return _ ( "Inactive" ) ;
1362
1408
}
1363
1409
return dev . StateText ;
@@ -1387,8 +1433,8 @@ export function render_active_connection(dev, with_link, hide_link_local) {
1387
1433
1388
1434
const ip4config = con ? con . Ip4Config : dev . Ip4Config ;
1389
1435
if ( ip4config ) {
1390
- ip4config . Addresses . forEach ( function ( a ) {
1391
- parts . push ( a [ 0 ] + "/" + a [ 1 ] ) ;
1436
+ ip4config . AddressData . forEach ( function ( a ) {
1437
+ parts . push ( a . address + "/" + a . prefix ) ;
1392
1438
} ) ;
1393
1439
}
1394
1440
@@ -1401,9 +1447,9 @@ export function render_active_connection(dev, with_link, hide_link_local) {
1401
1447
1402
1448
const ip6config = con ? con . Ip6Config : dev . Ip6Config ;
1403
1449
if ( ip6config ) {
1404
- ip6config . Addresses . forEach ( function ( a ) {
1405
- if ( ! ( hide_link_local && is_ipv6_link_local ( a [ 0 ] ) ) )
1406
- parts . push ( a [ 0 ] + "/" + a [ 1 ] ) ;
1450
+ ip6config . AddressData . forEach ( function ( a ) {
1451
+ if ( ! ( hide_link_local && is_ipv6_link_local ( a . address ) ) )
1452
+ parts . push ( a . address + "/" + a . prefix ) ;
1407
1453
} ) ;
1408
1454
}
1409
1455
0 commit comments