2021-04-18 11:57:43 +02:00
|
|
|
package protocolstate
|
|
|
|
|
|
|
|
|
|
import (
|
2022-08-25 17:42:35 +05:30
|
|
|
"fmt"
|
|
|
|
|
"net"
|
2022-09-16 21:36:17 +05:30
|
|
|
"net/url"
|
2022-08-25 17:42:35 +05:30
|
|
|
|
2021-04-18 11:57:43 +02:00
|
|
|
"github.com/pkg/errors"
|
2022-09-16 21:36:17 +05:30
|
|
|
"golang.org/x/net/proxy"
|
2021-11-25 17:09:20 +02:00
|
|
|
|
2021-04-18 11:57:43 +02:00
|
|
|
"github.com/projectdiscovery/fastdialer/fastdialer"
|
2022-11-16 13:49:24 +05:30
|
|
|
"github.com/projectdiscovery/networkpolicy"
|
2021-04-18 11:57:43 +02:00
|
|
|
"github.com/projectdiscovery/nuclei/v2/pkg/types"
|
|
|
|
|
)
|
|
|
|
|
|
2021-06-14 17:14:16 +05:30
|
|
|
// Dialer is a shared fastdialer instance for host DNS resolution
|
2021-04-18 11:57:43 +02:00
|
|
|
var Dialer *fastdialer.Dialer
|
|
|
|
|
|
2021-06-14 17:14:16 +05:30
|
|
|
// Init creates the Dialer instance based on user configuration
|
2021-04-18 11:57:43 +02:00
|
|
|
func Init(options *types.Options) error {
|
2022-06-09 17:18:49 -05:00
|
|
|
if Dialer != nil {
|
|
|
|
|
return nil
|
|
|
|
|
}
|
2021-04-18 11:57:43 +02:00
|
|
|
opts := fastdialer.DefaultOptions
|
2022-08-25 17:42:35 +05:30
|
|
|
|
|
|
|
|
switch {
|
|
|
|
|
case options.SourceIP != "" && options.Interface != "":
|
|
|
|
|
isAssociated, err := isIpAssociatedWithInterface(options.SourceIP, options.Interface)
|
|
|
|
|
if err != nil {
|
|
|
|
|
return err
|
|
|
|
|
}
|
|
|
|
|
if isAssociated {
|
|
|
|
|
opts.Dialer = &net.Dialer{
|
|
|
|
|
LocalAddr: &net.TCPAddr{
|
|
|
|
|
IP: net.ParseIP(options.SourceIP),
|
|
|
|
|
},
|
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
return fmt.Errorf("source ip (%s) is not associated with the interface (%s)", options.SourceIP, options.Interface)
|
|
|
|
|
}
|
|
|
|
|
case options.SourceIP != "":
|
|
|
|
|
isAssociated, err := isIpAssociatedWithInterface(options.SourceIP, "any")
|
|
|
|
|
if err != nil {
|
|
|
|
|
return err
|
|
|
|
|
}
|
|
|
|
|
if isAssociated {
|
|
|
|
|
opts.Dialer = &net.Dialer{
|
|
|
|
|
LocalAddr: &net.TCPAddr{
|
|
|
|
|
IP: net.ParseIP(options.SourceIP),
|
|
|
|
|
},
|
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
return fmt.Errorf("source ip (%s) is not associated with any network interface", options.SourceIP)
|
|
|
|
|
}
|
|
|
|
|
case options.Interface != "":
|
|
|
|
|
ifadrr, err := interfaceAddress(options.Interface)
|
|
|
|
|
if err != nil {
|
|
|
|
|
return err
|
|
|
|
|
}
|
|
|
|
|
opts.Dialer = &net.Dialer{
|
|
|
|
|
LocalAddr: &net.TCPAddr{
|
|
|
|
|
IP: ifadrr,
|
|
|
|
|
},
|
|
|
|
|
}
|
|
|
|
|
}
|
2022-09-16 21:36:17 +05:30
|
|
|
if types.ProxySocksURL != "" {
|
|
|
|
|
proxyURL, err := url.Parse(types.ProxySocksURL)
|
|
|
|
|
if err != nil {
|
|
|
|
|
return err
|
|
|
|
|
}
|
|
|
|
|
var forward *net.Dialer
|
|
|
|
|
if opts.Dialer != nil {
|
|
|
|
|
forward = opts.Dialer
|
|
|
|
|
} else {
|
|
|
|
|
forward = &net.Dialer{
|
|
|
|
|
Timeout: opts.DialerTimeout,
|
|
|
|
|
KeepAlive: opts.DialerKeepAlive,
|
|
|
|
|
DualStack: true,
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
dialer, err := proxy.FromURL(proxyURL, forward)
|
|
|
|
|
if err != nil {
|
|
|
|
|
return err
|
|
|
|
|
}
|
|
|
|
|
opts.ProxyDialer = &dialer
|
|
|
|
|
}
|
2022-08-25 17:42:35 +05:30
|
|
|
|
2021-04-18 11:57:43 +02:00
|
|
|
if options.SystemResolvers {
|
|
|
|
|
opts.EnableFallback = true
|
|
|
|
|
}
|
|
|
|
|
if options.ResolversFile != "" {
|
|
|
|
|
opts.BaseResolvers = options.InternalResolversList
|
|
|
|
|
}
|
2022-11-16 13:49:24 +05:30
|
|
|
if options.Sandbox {
|
|
|
|
|
opts.Deny = append(networkpolicy.DefaultIPv4DenylistRanges, networkpolicy.DefaultIPv6DenylistRanges...)
|
|
|
|
|
}
|
2021-11-22 09:51:13 +05:30
|
|
|
opts.WithDialerHistory = true
|
2022-01-25 20:48:21 +01:00
|
|
|
opts.WithZTLS = options.ZTLS
|
2022-05-12 13:13:56 +02:00
|
|
|
opts.SNIName = options.SNI
|
2021-04-18 11:57:43 +02:00
|
|
|
dialer, err := fastdialer.NewDialer(opts)
|
|
|
|
|
if err != nil {
|
2021-04-19 00:55:33 +05:30
|
|
|
return errors.Wrap(err, "could not create dialer")
|
2021-04-18 11:57:43 +02:00
|
|
|
}
|
|
|
|
|
Dialer = dialer
|
|
|
|
|
return nil
|
|
|
|
|
}
|
|
|
|
|
|
2022-08-25 17:42:35 +05:30
|
|
|
// isIpAssociatedWithInterface checks if the given IP is associated with the given interface.
|
|
|
|
|
func isIpAssociatedWithInterface(souceIP, interfaceName string) (bool, error) {
|
|
|
|
|
addrs, err := interfaceAddresses(interfaceName)
|
|
|
|
|
if err != nil {
|
|
|
|
|
return false, err
|
|
|
|
|
}
|
|
|
|
|
for _, addr := range addrs {
|
|
|
|
|
if ipnet, ok := addr.(*net.IPNet); ok {
|
|
|
|
|
if ipnet.IP.String() == souceIP {
|
|
|
|
|
return true, nil
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return false, nil
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// interfaceAddress returns the first IPv4 address of the given interface.
|
|
|
|
|
func interfaceAddress(interfaceName string) (net.IP, error) {
|
|
|
|
|
addrs, err := interfaceAddresses(interfaceName)
|
|
|
|
|
if err != nil {
|
|
|
|
|
return nil, err
|
|
|
|
|
}
|
|
|
|
|
var address net.IP
|
|
|
|
|
for _, addr := range addrs {
|
|
|
|
|
if ipnet, ok := addr.(*net.IPNet); ok && !ipnet.IP.IsLoopback() {
|
|
|
|
|
if ipnet.IP.To4() != nil {
|
|
|
|
|
address = ipnet.IP
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
if address == nil {
|
|
|
|
|
return nil, fmt.Errorf("no suitable address found for interface: `%s`", interfaceName)
|
|
|
|
|
}
|
|
|
|
|
return address, nil
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// interfaceAddresses returns all interface addresses.
|
|
|
|
|
func interfaceAddresses(interfaceName string) ([]net.Addr, error) {
|
|
|
|
|
if interfaceName == "any" {
|
|
|
|
|
return net.InterfaceAddrs()
|
|
|
|
|
}
|
|
|
|
|
ief, err := net.InterfaceByName(interfaceName)
|
|
|
|
|
if err != nil {
|
|
|
|
|
return nil, errors.Wrapf(err, "failed to get interface: `%s`", interfaceName)
|
|
|
|
|
}
|
|
|
|
|
addrs, err := ief.Addrs()
|
|
|
|
|
if err != nil {
|
|
|
|
|
return nil, errors.Wrapf(err, "failed to get interface addresses for: `%s`", interfaceName)
|
|
|
|
|
}
|
|
|
|
|
return addrs, nil
|
|
|
|
|
}
|
|
|
|
|
|
2021-06-14 17:14:16 +05:30
|
|
|
// Close closes the global shared fastdialer
|
2021-04-18 11:57:43 +02:00
|
|
|
func Close() {
|
|
|
|
|
if Dialer != nil {
|
|
|
|
|
Dialer.Close()
|
|
|
|
|
}
|
|
|
|
|
}
|