1414from sshuttle .ssnet import SockWrapper , Handler , Proxy , Mux , MuxWrapper
1515from sshuttle .helpers import log , debug1 , debug2 , debug3 , Fatal , islocal , \
1616 resolvconf_nameservers
17- from sshuttle .methods import get_method
17+ from sshuttle .methods import get_method , Features
1818
1919_extra_fd = os .open ('/dev/null' , os .O_RDONLY )
2020
@@ -505,19 +505,44 @@ def main(listenip_v6, listenip_v4,
505505
506506 fw = FirewallClient (method_name )
507507
508- features = fw .method .get_supported_features ()
508+ # Get family specific subnet lists
509+ if dns :
510+ nslist += resolvconf_nameservers ()
511+
512+ subnets = subnets_include + subnets_exclude # we don't care here
513+ subnets_v6 = [i for i in subnets if i [0 ] == socket .AF_INET6 ]
514+ nslist_v6 = [i for i in nslist if i [0 ] == socket .AF_INET6 ]
515+ subnets_v4 = [i for i in subnets if i [0 ] == socket .AF_INET ]
516+ nslist_v4 = [i for i in nslist if i [0 ] == socket .AF_INET ]
517+
518+ # Check features available
519+ avail = fw .method .get_supported_features ()
520+ required = Features ()
521+
509522 if listenip_v6 == "auto" :
510- if features .ipv6 :
523+ if avail .ipv6 :
511524 listenip_v6 = ('::1' , 0 )
512525 else :
513526 listenip_v6 = None
514527
528+ required .ipv6 = len (subnets_v6 ) > 0 or len (nslist_v6 ) > 0
529+ required .udp = avail .udp
530+ required .dns = len (nslist ) > 0
531+
532+ fw .method .assert_features (required )
533+
534+ if required .ipv6 and listenip_v6 is None :
535+ raise Fatal ("IPv6 required but not listening." )
536+
537+ # display features enabled
538+ debug1 ("IPv6 enabled: %r\n " % required .ipv6 )
539+ debug1 ("UDP enabled: %r\n " % required .udp )
540+ debug1 ("DNS enabled: %r\n " % required .dns )
541+
542+ # bind to required ports
515543 if listenip_v4 == "auto" :
516544 listenip_v4 = ('127.0.0.1' , 0 )
517545
518- udp = features .udp
519- debug1 ("UDP enabled: %r\n " % udp )
520-
521546 if listenip_v6 and listenip_v6 [1 ] and listenip_v4 and listenip_v4 [1 ]:
522547 # if both ports given, no need to search for a spare port
523548 ports = [0 , ]
@@ -536,7 +561,7 @@ def main(listenip_v6, listenip_v4,
536561 tcp_listener = MultiListener ()
537562 tcp_listener .setsockopt (socket .SOL_SOCKET , socket .SO_REUSEADDR , 1 )
538563
539- if udp :
564+ if required . udp :
540565 udp_listener = MultiListener (socket .SOCK_DGRAM )
541566 udp_listener .setsockopt (socket .SOL_SOCKET , socket .SO_REUSEADDR , 1 )
542567 else :
@@ -584,10 +609,7 @@ def main(listenip_v6, listenip_v4,
584609 udp_listener .print_listening ("UDP redirector" )
585610
586611 bound = False
587- if dns or nslist :
588- if dns :
589- nslist += resolvconf_nameservers ()
590- dns = True
612+ if required .dns :
591613 # search for spare port for DNS
592614 debug2 ('Binding DNS:' )
593615 ports = range (12300 , 9000 , - 1 )
@@ -628,17 +650,41 @@ def main(listenip_v6, listenip_v4,
628650 dnsport_v4 = 0
629651 dns_listener = None
630652
631- fw .method .check_settings (udp , dns )
653+ # Last minute sanity checks.
654+ # These should never fail.
655+ # If these do fail, something is broken above.
656+ if len (subnets_v6 ) > 0 :
657+ assert required .ipv6
658+ if redirectport_v6 == 0 :
659+ raise Fatal ("IPv6 subnets defined but not listening" )
660+
661+ if len (nslist_v6 ) > 0 :
662+ assert required .dns
663+ assert required .ipv6
664+ if dnsport_v6 == 0 :
665+ raise Fatal ("IPv6 ns servers defined but not listening" )
666+
667+ if len (subnets_v4 ) > 0 :
668+ if redirectport_v4 == 0 :
669+ raise Fatal ("IPv4 subnets defined but not listening" )
670+
671+ if len (nslist_v4 ) > 0 :
672+ if dnsport_v4 == 0 :
673+ raise Fatal ("IPv4 ns servers defined but not listening" )
674+
675+ # setup method specific stuff on listeners
632676 fw .method .setup_tcp_listener (tcp_listener )
633677 if udp_listener :
634678 fw .method .setup_udp_listener (udp_listener )
635679 if dns_listener :
636680 fw .method .setup_udp_listener (dns_listener )
637681
682+ # start the firewall
638683 fw .setup (subnets_include , subnets_exclude , nslist ,
639684 redirectport_v6 , redirectport_v4 , dnsport_v6 , dnsport_v4 ,
640- udp )
685+ required . udp )
641686
687+ # start the client process
642688 try :
643689 return _main (tcp_listener , udp_listener , fw , ssh_cmd , remotename ,
644690 python , latency_control , dns_listener ,
0 commit comments