github.com/projectdiscovery/nuclei/v2@v2.9.15/pkg/protocols/common/protocolstate/state.go (about) 1 package protocolstate 2 3 import ( 4 "fmt" 5 "net" 6 "net/url" 7 8 "github.com/pkg/errors" 9 "golang.org/x/net/proxy" 10 11 "github.com/projectdiscovery/fastdialer/fastdialer" 12 "github.com/projectdiscovery/networkpolicy" 13 "github.com/projectdiscovery/nuclei/v2/pkg/types" 14 ) 15 16 // Dialer is a shared fastdialer instance for host DNS resolution 17 var Dialer *fastdialer.Dialer 18 19 // Init creates the Dialer instance based on user configuration 20 func Init(options *types.Options) error { 21 if Dialer != nil { 22 return nil 23 } 24 opts := fastdialer.DefaultOptions 25 InitHeadless(options.RestrictLocalNetworkAccess, options.AllowLocalFileAccess) 26 27 switch { 28 case options.SourceIP != "" && options.Interface != "": 29 isAssociated, err := isIpAssociatedWithInterface(options.SourceIP, options.Interface) 30 if err != nil { 31 return err 32 } 33 if isAssociated { 34 opts.Dialer = &net.Dialer{ 35 LocalAddr: &net.TCPAddr{ 36 IP: net.ParseIP(options.SourceIP), 37 }, 38 } 39 } else { 40 return fmt.Errorf("source ip (%s) is not associated with the interface (%s)", options.SourceIP, options.Interface) 41 } 42 case options.SourceIP != "": 43 isAssociated, err := isIpAssociatedWithInterface(options.SourceIP, "any") 44 if err != nil { 45 return err 46 } 47 if isAssociated { 48 opts.Dialer = &net.Dialer{ 49 LocalAddr: &net.TCPAddr{ 50 IP: net.ParseIP(options.SourceIP), 51 }, 52 } 53 } else { 54 return fmt.Errorf("source ip (%s) is not associated with any network interface", options.SourceIP) 55 } 56 case options.Interface != "": 57 ifadrr, err := interfaceAddress(options.Interface) 58 if err != nil { 59 return err 60 } 61 opts.Dialer = &net.Dialer{ 62 LocalAddr: &net.TCPAddr{ 63 IP: ifadrr, 64 }, 65 } 66 } 67 if types.ProxySocksURL != "" { 68 proxyURL, err := url.Parse(types.ProxySocksURL) 69 if err != nil { 70 return err 71 } 72 var forward *net.Dialer 73 if opts.Dialer != nil { 74 forward = opts.Dialer 75 } else { 76 forward = &net.Dialer{ 77 Timeout: opts.DialerTimeout, 78 KeepAlive: opts.DialerKeepAlive, 79 DualStack: true, 80 } 81 } 82 dialer, err := proxy.FromURL(proxyURL, forward) 83 if err != nil { 84 return err 85 } 86 opts.ProxyDialer = &dialer 87 } 88 89 if options.SystemResolvers { 90 opts.EnableFallback = true 91 } 92 if options.ResolversFile != "" { 93 opts.BaseResolvers = options.InternalResolversList 94 } 95 if options.RestrictLocalNetworkAccess { 96 opts.Deny = append(networkpolicy.DefaultIPv4DenylistRanges, networkpolicy.DefaultIPv6DenylistRanges...) 97 } 98 opts.WithDialerHistory = true 99 opts.SNIName = options.SNI 100 // fastdialer now by default fallbacks to ztls when there are tls related errors 101 dialer, err := fastdialer.NewDialer(opts) 102 if err != nil { 103 return errors.Wrap(err, "could not create dialer") 104 } 105 Dialer = dialer 106 return nil 107 } 108 109 // isIpAssociatedWithInterface checks if the given IP is associated with the given interface. 110 func isIpAssociatedWithInterface(sourceIP, interfaceName string) (bool, error) { 111 addrs, err := interfaceAddresses(interfaceName) 112 if err != nil { 113 return false, err 114 } 115 for _, addr := range addrs { 116 if ipnet, ok := addr.(*net.IPNet); ok { 117 if ipnet.IP.String() == sourceIP { 118 return true, nil 119 } 120 } 121 } 122 return false, nil 123 } 124 125 // interfaceAddress returns the first IPv4 address of the given interface. 126 func interfaceAddress(interfaceName string) (net.IP, error) { 127 addrs, err := interfaceAddresses(interfaceName) 128 if err != nil { 129 return nil, err 130 } 131 var address net.IP 132 for _, addr := range addrs { 133 if ipnet, ok := addr.(*net.IPNet); ok && !ipnet.IP.IsLoopback() { 134 if ipnet.IP.To4() != nil { 135 address = ipnet.IP 136 } 137 } 138 } 139 if address == nil { 140 return nil, fmt.Errorf("no suitable address found for interface: `%s`", interfaceName) 141 } 142 return address, nil 143 } 144 145 // interfaceAddresses returns all interface addresses. 146 func interfaceAddresses(interfaceName string) ([]net.Addr, error) { 147 if interfaceName == "any" { 148 return net.InterfaceAddrs() 149 } 150 ief, err := net.InterfaceByName(interfaceName) 151 if err != nil { 152 return nil, errors.Wrapf(err, "failed to get interface: `%s`", interfaceName) 153 } 154 addrs, err := ief.Addrs() 155 if err != nil { 156 return nil, errors.Wrapf(err, "failed to get interface addresses for: `%s`", interfaceName) 157 } 158 return addrs, nil 159 } 160 161 // Close closes the global shared fastdialer 162 func Close() { 163 if Dialer != nil { 164 Dialer.Close() 165 } 166 }