14
14
use core:: net:: SocketAddr ;
15
15
use std:: fmt;
16
16
use std:: net:: IpAddr ;
17
+ use std:: net:: Ipv4Addr ;
18
+ use std:: net:: Ipv6Addr ;
17
19
#[ cfg( target_os = "linux" ) ]
18
20
use std:: os:: linux:: net:: SocketAddrExt ;
19
21
use std:: str:: FromStr ;
@@ -236,6 +238,26 @@ impl<M: RemoteMessage> Rx<M> for MpscRx<M> {
236
238
}
237
239
}
238
240
241
+ /// The hostname to use for TLS connections.
242
+ #[ derive(
243
+ Clone ,
244
+ Debug ,
245
+ PartialEq ,
246
+ Eq ,
247
+ Hash ,
248
+ Serialize ,
249
+ Deserialize ,
250
+ strum:: EnumIter ,
251
+ strum:: Display ,
252
+ strum:: EnumString
253
+ ) ]
254
+ pub enum TcpMode {
255
+ /// Use localhost/loopback for the connection.
256
+ Localhost ,
257
+ /// Use host domain name for the connection.
258
+ Hostname ,
259
+ }
260
+
239
261
/// The hostname to use for TLS connections.
240
262
#[ derive(
241
263
Clone ,
@@ -315,7 +337,7 @@ impl fmt::Display for MetaTlsAddr {
315
337
#[ derive( Clone , Debug , PartialEq , Eq , Hash , Serialize , Deserialize , Named ) ]
316
338
pub enum ChannelTransport {
317
339
/// Transport over a TCP connection.
318
- Tcp ,
340
+ Tcp ( TcpMode ) ,
319
341
320
342
/// Transport over a TCP connection with TLS support within Meta
321
343
MetaTls ( TlsMode ) ,
@@ -333,7 +355,7 @@ pub enum ChannelTransport {
333
355
impl fmt:: Display for ChannelTransport {
334
356
fn fmt ( & self , f : & mut fmt:: Formatter < ' _ > ) -> fmt:: Result {
335
357
match self {
336
- Self :: Tcp => write ! ( f, "tcp" ) ,
358
+ Self :: Tcp ( mode ) => write ! ( f, "tcp({:?})" , mode ) ,
337
359
Self :: MetaTls ( mode) => write ! ( f, "metatls({:?})" , mode) ,
338
360
Self :: Local => write ! ( f, "local" ) ,
339
361
Self :: Sim ( transport) => write ! ( f, "sim({})" , transport) ,
@@ -358,7 +380,13 @@ impl FromStr for ChannelTransport {
358
380
}
359
381
360
382
match s {
361
- "tcp" => Ok ( ChannelTransport :: Tcp ) ,
383
+ // Default to TcpMode::Hostname, if the mode isn't set
384
+ "tcp" => Ok ( ChannelTransport :: Tcp ( TcpMode :: Hostname ) ) ,
385
+ s if s. starts_with ( "tcp(" ) => {
386
+ let inner = & s[ "tcp(" . len ( ) ..s. len ( ) - 1 ] ;
387
+ let mode = inner. parse ( ) ?;
388
+ Ok ( ChannelTransport :: Tcp ( mode) )
389
+ }
362
390
"local" => Ok ( ChannelTransport :: Local ) ,
363
391
"unix" => Ok ( ChannelTransport :: Unix ) ,
364
392
s if s. starts_with ( "metatls(" ) && s. ends_with ( ")" ) => {
@@ -373,9 +401,10 @@ impl FromStr for ChannelTransport {
373
401
374
402
impl ChannelTransport {
375
403
/// All known channel transports.
376
- pub fn all ( ) -> [ ChannelTransport ; 3 ] {
404
+ pub fn all ( ) -> [ ChannelTransport ; 4 ] {
377
405
[
378
- ChannelTransport :: Tcp ,
406
+ ChannelTransport :: Tcp ( TcpMode :: Localhost ) ,
407
+ ChannelTransport :: Tcp ( TcpMode :: Hostname ) ,
379
408
ChannelTransport :: Local ,
380
409
ChannelTransport :: Unix ,
381
410
// TODO add MetaTls (T208303369)
@@ -392,7 +421,7 @@ impl ChannelTransport {
392
421
/// Returns true if this transport type represents a remote channel.
393
422
pub fn is_remote ( & self ) -> bool {
394
423
match self {
395
- ChannelTransport :: Tcp => true ,
424
+ ChannelTransport :: Tcp ( _ ) => true ,
396
425
ChannelTransport :: MetaTls ( _) => true ,
397
426
ChannelTransport :: Local => false ,
398
427
ChannelTransport :: Sim ( _) => false ,
@@ -502,18 +531,27 @@ impl ChannelAddr {
502
531
/// servers to "any" address.
503
532
pub fn any ( transport : ChannelTransport ) -> Self {
504
533
match transport {
505
- ChannelTransport :: Tcp => {
506
- let ip = hostname:: get ( )
507
- . ok ( )
508
- . and_then ( |hostname| {
509
- // TODO: Avoid using DNS directly once we figure out a good extensibility story here
510
- hostname. to_str ( ) . and_then ( |hostname_str| {
511
- dns_lookup:: lookup_host ( hostname_str)
512
- . ok ( )
513
- . and_then ( |addresses| addresses. first ( ) . cloned ( ) )
534
+ ChannelTransport :: Tcp ( mode) => {
535
+ let ip = match mode {
536
+ TcpMode :: Localhost => {
537
+ // Try IPv6 first, fall back to IPv4 if the system doesn't support IPv6
538
+ match std:: net:: TcpListener :: bind ( ( Ipv6Addr :: LOCALHOST , 0 ) ) {
539
+ Ok ( _) => IpAddr :: V6 ( Ipv6Addr :: LOCALHOST ) ,
540
+ Err ( _) => IpAddr :: V4 ( Ipv4Addr :: UNSPECIFIED ) ,
541
+ }
542
+ }
543
+ TcpMode :: Hostname => hostname:: get ( )
544
+ . ok ( )
545
+ . and_then ( |hostname| {
546
+ // TODO: Avoid using DNS directly once we figure out a good extensibility story here
547
+ hostname. to_str ( ) . and_then ( |hostname_str| {
548
+ dns_lookup:: lookup_host ( hostname_str)
549
+ . ok ( )
550
+ . and_then ( |addresses| addresses. first ( ) . cloned ( ) )
551
+ } )
514
552
} )
515
- } )
516
- . unwrap_or_else ( || IpAddr :: from_str ( "::1" ) . unwrap ( ) ) ;
553
+ . expect ( "Failed to resolve hostname to IP address" ) ,
554
+ } ;
517
555
Self :: Tcp ( SocketAddr :: new ( ip, 0 ) )
518
556
}
519
557
ChannelTransport :: MetaTls ( mode) => {
@@ -542,7 +580,13 @@ impl ChannelAddr {
542
580
/// The transport used by this address.
543
581
pub fn transport ( & self ) -> ChannelTransport {
544
582
match self {
545
- Self :: Tcp ( _) => ChannelTransport :: Tcp ,
583
+ Self :: Tcp ( addr) => {
584
+ if addr. ip ( ) . is_loopback ( ) {
585
+ ChannelTransport :: Tcp ( TcpMode :: Localhost )
586
+ } else {
587
+ ChannelTransport :: Tcp ( TcpMode :: Hostname )
588
+ }
589
+ }
546
590
Self :: MetaTls ( addr) => match addr {
547
591
MetaTlsAddr :: Host { hostname, .. } => match hostname. parse :: < IpAddr > ( ) {
548
592
Ok ( IpAddr :: V6 ( _) ) => ChannelTransport :: MetaTls ( TlsMode :: IpV6 ) ,
0 commit comments