Skip to content

Commit

Permalink
Merge pull request #32 from seeyarh/ipv6-support
Browse files Browse the repository at this point in the history
Ipv6 support
  • Loading branch information
ehsandeep committed Feb 15, 2022
2 parents 371b7b9 + b90b9d1 commit 3972c02
Show file tree
Hide file tree
Showing 5 changed files with 94 additions and 35 deletions.
62 changes: 38 additions & 24 deletions fastdialer/dialer.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@ import (
"context"
"crypto/tls"
"encoding/json"
"errors"
"fmt"
"net"
"strings"
Expand Down Expand Up @@ -115,37 +114,52 @@ func (d *Dialer) DialTLSWithConfig(ctx context.Context, network, address string,

func (d *Dialer) dial(ctx context.Context, network, address string, shouldUseTLS bool, tlsconfig *tls.Config) (conn net.Conn, err error) {
var hostname, port, fixedIP string
addressParts := strings.Split(address, ":")
numberOfParts := len(addressParts)
if numberOfParts >= 2 {
// ip|host:port
hostname = addressParts[0]
port = addressParts[1]
// ip|host:port:ip => curl --resolve ip:port:ip
if numberOfParts > 2 {
fixedIP = addressParts[2]

if strings.HasPrefix(address, "[") {
closeBracketIndex := strings.Index(address, "]")
if closeBracketIndex == -1 {
return nil, MalformedIP6Error
}
// check if the ip is within the context
if ctxIP := ctx.Value("ip"); ctxIP != nil {
fixedIP = fmt.Sprint(ctxIP)
hostname = address[:closeBracketIndex+1]
if len(address) < closeBracketIndex+2 {
return nil, NoPortSpecifiedError
}
port = address[closeBracketIndex+2:]
} else {
// no port => error
return nil, errors.New("port was not specified")
addressParts := strings.SplitN(address, ":", 3)
numberOfParts := len(addressParts)

if numberOfParts >= 2 {
// ip|host:port
hostname = addressParts[0]
port = addressParts[1]
// ip|host:port:ip => curl --resolve ip:port:ip
if numberOfParts > 2 {
fixedIP = addressParts[2]
}
// check if the ip is within the context
if ctxIP := ctx.Value("ip"); ctxIP != nil {
fixedIP = fmt.Sprint(ctxIP)
}
} else {
// no port => error
return nil, NoPortSpecifiedError
}
}

// check if data is in cache
data, err := d.GetDNSData(hostname)
if err != nil {
// otherwise attempt to retrieve it
data, err = d.dnsclient.Resolve(hostname)

}
if data == nil {
return nil, errors.New("could not resolve host")
return nil, ResolveHostError
}

if err != nil || len(data.A)+len(data.AAAA) == 0 {
return nil, &NoAddressFoundError{}
return nil, NoAddressFoundError
}

var numInvalidIPS int
Expand Down Expand Up @@ -199,9 +213,9 @@ func (d *Dialer) dial(ctx context.Context, network, address string, shouldUseTLS
}
if conn == nil {
if numInvalidIPS == len(IPS) {
return nil, &NoAddressAllowedError{}
return nil, NoAddressAllowedError
}
return nil, &NoAddressFoundError{}
return nil, NoAddressFoundError
}
if err != nil {
return nil, err
Expand Down Expand Up @@ -238,11 +252,11 @@ func (d *Dialer) GetDialedIP(hostname string) string {
// GetTLSData returns the tls data for a hostname
func (d *Dialer) GetTLSData(hostname string) (*cryptoutil.TLSData, error) {
if !d.options.WithTLSData {
return nil, errors.New("no tls data history available")
return nil, NoTLSHistoryError
}
v, ok := d.dialerTLSData.Get(hostname)
if !ok {
return nil, errors.New("no tls data found for the key")
return nil, NoTLSDataError
}

var tlsData cryptoutil.TLSData
Expand All @@ -259,7 +273,7 @@ func (d *Dialer) GetDNSDataFromCache(hostname string) (*retryabledns.DNSData, er
var data retryabledns.DNSData
dataBytes, ok := d.hm.Get(hostname)
if !ok {
return nil, errors.New("no data found")
return nil, NoDNSDataError
}

err := data.Unmarshal(dataBytes)
Expand All @@ -277,7 +291,7 @@ func (d *Dialer) GetDNSData(hostname string) (*retryabledns.DNSData, error) {
ipv6host := hostname[1:strings.LastIndex(hostname, "]")]
if ip := net.ParseIP(ipv6host); ip != nil {
if ip.To16() != nil {
return &retryabledns.DNSData{AAAA: []string{hostname}}, nil
return &retryabledns.DNSData{AAAA: []string{ip.To16().String()}}, nil
}
}
}
Expand All @@ -303,7 +317,7 @@ func (d *Dialer) GetDNSData(hostname string) (*retryabledns.DNSData, error) {
return nil, err
}
if data == nil {
return nil, errors.New("could not resolve host")
return nil, ResolveHostError
}
b, _ := data.Marshal()
err = d.hm.Set(hostname, b)
Expand Down
39 changes: 39 additions & 0 deletions fastdialer/dialer_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ func TestDialer(t *testing.T) {
options.CacheType = Hybrid
options.CacheMemoryMaxItems = 100
testDialer(t, options)
testDialerIpv6(t, options)
}

func testDialer(t *testing.T, options Options) {
Expand Down Expand Up @@ -50,3 +51,41 @@ func testDialer(t *testing.T, options Options) {
// cleanup
fd.Close()
}

func testDialerIpv6(t *testing.T, options Options) {
// disk based
fd, err := NewDialer(options)
if err != nil {
t.Errorf("couldn't create fastdialer instance: %s", err)
}

// valid resolution + cache
ctx := context.Background()
conn, err := fd.Dial(ctx, "tcp", "ipv6.google.com:80")
if err != nil || conn == nil {
t.Errorf("couldn't connect to target: %s", err)
}
conn.Close()
// retrieve cached data
data, err := fd.GetDNSData("ipv6.google.com")
if err != nil || data == nil {
t.Errorf("couldn't retrieve dns data: %s", err)
}
if len(data.AAAA) == 0 {
t.Error("no AAAA results found")
}

// test address pinning
// this test passes, but will fail if the hard-coded ipv6 address changes
// need to find a better way to test this
/*
conn, err = fd.Dial(ctx, "tcp", "ipv6.google.com:80:[2607:f8b0:4006:807::200e]")
if err != nil || conn == nil {
t.Errorf("couldn't connect to target: %s", err)
}
conn.Close()
*/

// cleanup
fd.Close()
}
23 changes: 13 additions & 10 deletions fastdialer/error.go
Original file line number Diff line number Diff line change
@@ -1,13 +1,16 @@
package fastdialer

type NoAddressFoundError struct{}
import (
"github.com/pkg/errors"
)

func (m *NoAddressFoundError) Error() string {
return "no address found for host"
}

type NoAddressAllowedError struct{}

func (m *NoAddressAllowedError) Error() string {
return "denied address found for host"
}
var (
NoAddressFoundError = errors.New("no address found for host")
NoAddressAllowedError = errors.New("denied address found for host")
NoPortSpecifiedError = errors.New("port was not specified")
MalformedIP6Error = errors.New("malformed IPv6 address")
ResolveHostError = errors.New("could not resolve host")
NoTLSHistoryError = errors.New("no tls data history available")
NoTLSDataError = errors.New("no tls data found for the key")
NoDNSDataError = errors.New("no data found")
)
3 changes: 2 additions & 1 deletion go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,10 @@ require (
github.com/golang/snappy v0.0.4 // indirect
github.com/kr/pretty v0.3.0 // indirect
github.com/miekg/dns v1.1.43 // indirect
github.com/pkg/errors v0.9.1
github.com/projectdiscovery/cryptoutil v0.0.0-20210805184155-b5d2512f9345
github.com/projectdiscovery/hmap v0.0.2-0.20210917080408-0fd7bd286bfa
github.com/projectdiscovery/iputil v0.0.0-20210804143329-3a30fcde43f3 // indirect
github.com/projectdiscovery/iputil v0.0.0-20210804143329-3a30fcde43f3
github.com/projectdiscovery/mapcidr v0.0.8 // indirect
github.com/projectdiscovery/networkpolicy v0.0.1
github.com/projectdiscovery/retryabledns v1.0.13-0.20210916165024-76c5b76fd59a
Expand Down
2 changes: 2 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,8 @@ github.com/onsi/gomega v1.10.1/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1y
github.com/onsi/gomega v1.10.5 h1:7n6FEkpFmfCoo2t+YYqXH0evK+a9ICQz0xcAy9dYcaQ=
github.com/onsi/gomega v1.10.5/go.mod h1:gza4q3jKQJijlu05nKWRCW/GavJumGt8aNRxWg7mt48=
github.com/pkg/diff v0.0.0-20210226163009-20ebb0f2a09e/go.mod h1:pJLUxLENpZxwdsKMEsNbx1VGcRFpLqf3715MtcvvzbA=
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/projectdiscovery/blackrock v0.0.0-20210415162320-b38689ae3a2e h1:7bwaFH1jvtOo5ndhTQgoA349ozhX+1dc4b6tbaPnBOA=
Expand Down

0 comments on commit 3972c02

Please sign in to comment.