@@ -586,70 +586,143 @@ def main(listenip_v6, listenip_v4,
586
586
587
587
fw = FirewallClient (method_name , sudo_pythonpath )
588
588
589
- # Get family specific subnet lists
589
+ # If --dns is used, store the IP addresses that the client
590
+ # normally uses for DNS lookups in nslist. The firewall needs to
591
+ # redirect packets outgoing to this server to the remote host
592
+ # instead.
590
593
if dns :
591
594
nslist += resolvconf_nameservers ()
592
595
if to_nameserver is not None :
593
596
to_nameserver = "%s@%s" % tuple (to_nameserver [1 :])
594
597
else :
595
598
# option doesn't make sense if we aren't proxying dns
599
+ if to_nameserver and len (to_nameserver ) > 0 :
600
+ print ("WARNING: --to-ns option is ignored because --dns was not "
601
+ "used." )
596
602
to_nameserver = None
597
603
598
- subnets = subnets_include + subnets_exclude # we don't care here
599
- subnets_v6 = [i for i in subnets if i [0 ] == socket .AF_INET6 ]
600
- nslist_v6 = [i for i in nslist if i [0 ] == socket .AF_INET6 ]
601
- subnets_v4 = [i for i in subnets if i [0 ] == socket .AF_INET ]
604
+ # Get family specific subnet lists. Also, the user may not specify
605
+ # any subnets if they use --auto-nets. In this case, our subnets
606
+ # list will be empty and the forwarded subnets will be determined
607
+ # later by the server.
608
+ subnets_v4 = [i for i in subnets_include if i [0 ] == socket .AF_INET ]
609
+ subnets_v6 = [i for i in subnets_include if i [0 ] == socket .AF_INET6 ]
602
610
nslist_v4 = [i for i in nslist if i [0 ] == socket .AF_INET ]
611
+ nslist_v6 = [i for i in nslist if i [0 ] == socket .AF_INET6 ]
603
612
604
- # Check features available
613
+ # Get available features from the firewall method
605
614
avail = fw .method .get_supported_features ()
615
+
616
+ # A feature is "required" if the user supplies us parameters which
617
+ # implies that the feature is needed.
606
618
required = Features ()
607
619
620
+ # Select the default addresses to bind to / listen to.
621
+
622
+ # Assume IPv4 is always available and should always be enabled. If
623
+ # a method doesn't provide IPv4 support or if we wish to run
624
+ # ipv6-only, changes to this code are required.
625
+ assert avail .ipv4
626
+ required .ipv4 = True
627
+
628
+ # listenip_v4 contains user specified value or it is set to "auto".
629
+ if listenip_v4 == "auto" :
630
+ listenip_v4 = ('127.0.0.1' , 0 )
631
+
632
+ # listenip_v6 is...
633
+ # None when IPv6 is disabled.
634
+ # "auto" when listen address is unspecified.
635
+ # The user specified address if provided by user
636
+ if listenip_v6 is None :
637
+ debug1 ("IPv6 disabled by --disable-ipv6\n " )
608
638
if listenip_v6 == "auto" :
609
639
if avail .ipv6 :
640
+ debug1 ("IPv6 enabled: Using default IPv6 listen address ::1\n " )
610
641
listenip_v6 = ('::1' , 0 )
611
642
else :
643
+ debug1 ("IPv6 disabled since it isn't supported by method "
644
+ "%s.\n " % fw .method .name )
612
645
listenip_v6 = None
613
646
647
+ # Make final decision about enabling IPv6:
648
+ required .ipv6 = False
649
+ if listenip_v6 :
650
+ required .ipv6 = True
651
+
652
+ # If we get here, it is possible that listenip_v6 was user
653
+ # specified but not supported by the current method.
654
+ if required .ipv6 and not avail .ipv6 :
655
+ raise Fatal ("An IPv6 listen address was supplied, but IPv6 is "
656
+ "disabled at your request or is unsupported by the %s "
657
+ "method." % fw .method .name )
658
+
614
659
if user is not None :
615
660
if getpwnam is None :
616
661
raise Fatal ("Routing by user not available on this system." )
617
662
try :
618
663
user = getpwnam (user ).pw_uid
619
664
except KeyError :
620
665
raise Fatal ("User %s does not exist." % user )
666
+ required .user = False if user is None else True
621
667
622
- if fw .method .name != 'nat' :
623
- required .ipv6 = len (subnets_v6 ) > 0 or listenip_v6 is not None
624
- required .ipv4 = len (subnets_v4 ) > 0 or listenip_v4 is not None
625
- else :
626
- required .ipv6 = None
627
- required .ipv4 = None
668
+ if not required .ipv6 and len (subnets_v6 ) > 0 :
669
+ print ("WARNING: IPv6 subnets were ignored because IPv6 is disabled "
670
+ "in sshuttle." )
671
+ subnets_v6 = []
672
+ subnets_include = subnets_v4
628
673
629
- required .udp = avail .udp
674
+ required .udp = avail .udp # automatically enable UDP if it is available
630
675
required .dns = len (nslist ) > 0
631
- required .user = False if user is None else True
632
676
633
- # if IPv6 not supported, ignore IPv6 DNS servers
677
+ # Remove DNS servers using IPv6.
678
+ if required .dns :
679
+ if not required .ipv6 and len (nslist_v6 ) > 0 :
680
+ print ("WARNING: Your system is configured to use an IPv6 DNS "
681
+ "server but sshuttle is not using IPv6. Therefore DNS "
682
+ "traffic your system sends to the IPv6 DNS server won't "
683
+ "be redirected via sshuttle to the remote machine." )
684
+ nslist_v6 = []
685
+ nslist = nslist_v4
686
+
687
+ if len (nslist ) == 0 :
688
+ raise Fatal ("Can't redirect DNS traffic since IPv6 is not "
689
+ "enabled in sshuttle and all of the system DNS "
690
+ "servers are IPv6." )
691
+
692
+ # If we aren't using IPv6, we can safely ignore excluded IPv6 subnets.
634
693
if not required .ipv6 :
635
- nslist_v6 = []
636
- nslist = nslist_v4
637
-
694
+ orig_len = len (subnets_exclude )
695
+ subnets_exclude = [i for i in subnets_exclude
696
+ if i [0 ] == socket .AF_INET ]
697
+ if len (subnets_exclude ) < orig_len :
698
+ print ("WARNING: Ignoring one or more excluded IPv6 subnets "
699
+ "because IPv6 is not enabled." )
700
+
701
+ # This will print error messages if we required a feature that
702
+ # isn't available by the current method.
638
703
fw .method .assert_features (required )
639
704
640
- if required .ipv6 and listenip_v6 is None :
641
- raise Fatal ("IPv6 required but not listening." )
642
-
643
705
# display features enabled
644
- debug1 ("IPv6 enabled: %r\n " % required .ipv6 )
645
- debug1 ("UDP enabled: %r\n " % required .udp )
646
- debug1 ("DNS enabled: %r\n " % required .dns )
647
- debug1 ("User enabled: %r\n " % required .user )
706
+ def feature_status (label , enabled , available ):
707
+ msg = label + ": "
708
+ if enabled :
709
+ msg += "on"
710
+ else :
711
+ msg += "off "
712
+ if available :
713
+ msg += "(available)"
714
+ else :
715
+ msg += "(not available with %s method)" % fw .method .name
716
+ debug1 (msg + "\n " )
648
717
649
- # bind to required ports
650
- if listenip_v4 == "auto" :
651
- listenip_v4 = ('127.0.0.1' , 0 )
718
+ debug1 ("Method: %s\n " % fw .method .name )
719
+ feature_status ("IPv4" , required .ipv4 , avail .ipv4 )
720
+ feature_status ("IPv6" , required .ipv6 , avail .ipv6 )
721
+ feature_status ("UDP " , required .udp , avail .udp )
722
+ feature_status ("DNS " , required .dns , avail .dns )
723
+ feature_status ("User" , required .user , avail .user )
652
724
725
+ # Exclude traffic destined to our listen addresses.
653
726
if required .ipv4 and \
654
727
not any (listenip_v4 [0 ] == sex [1 ] for sex in subnets_v4 ):
655
728
subnets_exclude .append ((socket .AF_INET , listenip_v4 [0 ], 32 , 0 , 0 ))
@@ -658,6 +731,25 @@ def main(listenip_v6, listenip_v4,
658
731
not any (listenip_v6 [0 ] == sex [1 ] for sex in subnets_v6 ):
659
732
subnets_exclude .append ((socket .AF_INET6 , listenip_v6 [0 ], 128 , 0 , 0 ))
660
733
734
+ # We don't print the IP+port of where we are listening here
735
+ # because we do that below when we have identified the ports to
736
+ # listen on.
737
+ debug1 ("Subnets to forward through remote host (type, IP, cidr mask "
738
+ "width, startPort, endPort):\n " )
739
+ for i in subnets_include :
740
+ print (" " + str (i ))
741
+ if auto_nets :
742
+ debug1 ("NOTE: Additional subnets to forward may be added below by "
743
+ "--auto-nets.\n " )
744
+ debug1 ("Subnets to exclude from forwarding:\n " )
745
+ for i in subnets_exclude :
746
+ print (" " + str (i ))
747
+ if required .dns :
748
+ debug1 ("DNS requests normally directed at these servers will be "
749
+ "redirected to remote:\n " )
750
+ for i in nslist :
751
+ print (" " + str (i ))
752
+
661
753
if listenip_v6 and listenip_v6 [1 ] and listenip_v4 and listenip_v4 [1 ]:
662
754
# if both ports given, no need to search for a spare port
663
755
ports = [0 , ]
0 commit comments