@@ -165,12 +165,34 @@ export function NetworkManagerModel() {
165165 const client = cockpit . dbus ( "org.freedesktop.NetworkManager" , { superuser : "try" } ) ;
166166 self . client = client ;
167167
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+
168187 /* resolved once first stage of initialization is done */
169188 self . preinit = new Promise ( ( resolve , reject ) => {
170189 client . call ( "/org/freedesktop/NetworkManager" ,
171190 "org.freedesktop.DBus.Properties" , "Get" ,
172- [ "org.freedesktop.NetworkManager" , "State " ] , { flags : "" } )
191+ [ "org.freedesktop.NetworkManager" , "Version " ] , { flags : "" } )
173192 . 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+
174196 if ( options . flags ) {
175197 if ( options . flags . indexOf ( ">" ) !== - 1 )
176198 utils . set_byteorder ( "be" ) ;
@@ -421,63 +443,52 @@ export function NetworkManagerModel() {
421443 /* NetworkManager specific data conversions and utility functions.
422444 */
423445
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+ } ;
429451 }
430452
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 ) ;
437455
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+ }
445459
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+ } ;
458464 }
459465
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+ } ;
465473 }
466474
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+ }
474485
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+ } ;
481492 }
482493
483494 function settings_from_nm ( settings ) {
@@ -488,15 +499,20 @@ export function NetworkManagerModel() {
488499 return def ;
489500 }
490501
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+
492507 return {
493508 method : get ( first , "method" , "auto" ) ,
494509 ignore_auto_dns : get ( first , "ignore-auto-dns" , false ) ,
495510 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,
498514 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 ) ,
500516 } ;
501517 }
502518
@@ -516,8 +532,8 @@ export function NetworkManagerModel() {
516532 } ;
517533
518534 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 ) ;
521537 }
522538
523539 if ( settings [ "802-3-ethernet" ] ) {
@@ -612,31 +628,61 @@ export function NetworkManagerModel() {
612628 delete result [ first ] [ second ] ;
613629 }
614630
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 ) {
616632 set ( first , "method" , 's' , settings [ first ] . method ) ;
617633 set ( first , "ignore-auto-dns" , 'b' , settings [ first ] . ignore_auto_dns ) ;
618634 set ( first , "ignore-auto-routes" , 'b' , settings [ first ] . ignore_auto_routes ) ;
619635 set ( first , "addr-gen-mode" , 'i' , settings [ first ] . addr_gen_mode ) ;
620636
621- const addresses = settings [ first ] . addresses ;
637+ const addresses = settings [ first ] . address_data ;
622638 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+ }
624665
625- const dns = settings [ first ] . dns ;
626- if ( dns )
627- set ( first , "dns" , ips_sig , dns . map ( ip_from_text ) ) ;
628666 set ( first , "dns-search" , 'as' , settings [ first ] . dns_search ) ;
629667
630- const routes = settings [ first ] . routes ;
668+ const routes = settings [ first ] . route_data ;
631669 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 ) ) ) ;
633671
634672 // Never pass "address-labels" back to NetworkManager. It
635673 // is documented as "internal only", but needs to somehow
636674 // stay in sync with "addresses". By not passing it back
637675 // we don't have to worry about that.
638676 //
639677 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 ;
640686 }
641687
642688 set ( "connection" , "id" , 's' , settings . connection . id ) ;
@@ -649,12 +695,12 @@ export function NetworkManagerModel() {
649695 set ( "connection" , "master" , 's' , settings . connection . group ) ;
650696
651697 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 ) ;
653699 else
654700 delete result . ipv4 ;
655701
656702 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 ) ;
658704 else
659705 delete result . ipv6 ;
660706
@@ -881,7 +927,7 @@ export function NetworkManagerModel() {
881927 ] ,
882928
883929 props : {
884- Addresses : { conv : conv_Array ( ip4_address_from_nm ) , def : [ ] }
930+ AddressData : { conv : conv_Array ( ip_address_from_nm ) , def : [ ] }
885931 }
886932 } ;
887933
@@ -891,7 +937,7 @@ export function NetworkManagerModel() {
891937 ] ,
892938
893939 props : {
894- Addresses : { conv : conv_Array ( ip6_address_from_nm ) , def : [ ] }
940+ AddressData : { conv : conv_Array ( ip_address_from_nm ) , def : [ ] }
895941 }
896942 } ;
897943
@@ -1356,8 +1402,8 @@ export function device_state_text(dev) {
13561402 return _ ( "No carrier" ) ;
13571403 if ( ! is_managed ( dev ) ) {
13581404 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 ) )
13611407 return _ ( "Inactive" ) ;
13621408 }
13631409 return dev . StateText ;
@@ -1387,8 +1433,8 @@ export function render_active_connection(dev, with_link, hide_link_local) {
13871433
13881434 const ip4config = con ? con . Ip4Config : dev . Ip4Config ;
13891435 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 ) ;
13921438 } ) ;
13931439 }
13941440
@@ -1401,9 +1447,9 @@ export function render_active_connection(dev, with_link, hide_link_local) {
14011447
14021448 const ip6config = con ? con . Ip6Config : dev . Ip6Config ;
14031449 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 ) ;
14071453 } ) ;
14081454 }
14091455
0 commit comments