Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Issues with custom dialer #46

Open
kotori2 opened this issue Jan 6, 2024 · 2 comments
Open

Issues with custom dialer #46

kotori2 opened this issue Jan 6, 2024 · 2 comments

Comments

@kotori2
Copy link
Contributor

kotori2 commented Jan 6, 2024

I want to customize the dialer so that it can dial outgoing connection using IPv6 address.
However, this library will prefer DNS resolution by default. In a dual-stack environment and the client use socks5h (which means the hostname will not be resolved by the client), the resolved IP address might be IPv4, thus making the dialing failed.

Although I found a workaround that can pretend the name resolution success with empty result:

func (d YourResolver) Resolve(ctx context.Context, name string) (context.Context, net.IP, error) {
	return ctx, []byte{}, nil
}

And it can trick the address formatter to use the FQDN instead:

// String returns a string suitable to dial; prefer returning IP-based
// address, fallback to FQDN
func (sf *AddrSpec) String() string {
if len(sf.IP) != 0 {
return net.JoinHostPort(sf.IP.String(), strconv.Itoa(sf.Port))
}
return net.JoinHostPort(sf.FQDN, strconv.Itoa(sf.Port))
}

It depends on the fallback of the error case, so it's not ideal to implement like this.
Considering we need to have backwards compatibility, we also can't change the resolve logic here:

go-socks5/handle.go

Lines 50 to 65 in 6191a34

// handleRequest is used for request processing after authentication
func (sf *Server) handleRequest(write io.Writer, req *Request) error {
var err error
ctx := context.Background()
// Resolve the address if we have a FQDN
dest := req.RawDestAddr
if dest.FQDN != "" {
ctx, dest.IP, err = sf.resolver.Resolve(ctx, dest.FQDN)
if err != nil {
if err := SendReply(write, statute.RepHostUnreachable, nil); err != nil {
return fmt.Errorf("failed to send reply, %v", err)
}
return fmt.Errorf("failed to resolve destination[%v], %v", dest.FQDN, err)
}
}

So I'm creating an issue looking for ideas to solve this issue.

@cxz66666
Copy link
Contributor

Maybe your question is to force your custom resolver to return an ipv6 address?

You can try net.ResolveIPAddr("ip6", name) or other go resolver, maybe like following:

func (d DNSResolver) Resolve(ctx context.Context, name string) (context.Context, net.IP, error) {
	addr, err := net.ResolveIPAddr("ip6", name)
	if err != nil {
		addr, err = net.ResolveIPAddr("ip4", name)
		if err != nil {
			return ctx, nil, err
		}
		return ctx, addr.IP, nil
	}
	return ctx, addr.IP, nil
}

@kotori2
Copy link
Contributor Author

kotori2 commented Feb 25, 2024

Maybe your question is to force your custom resolver to return an ipv6 address?

You can try net.ResolveIPAddr("ip6", name) or other go resolver, maybe like following:

func (d DNSResolver) Resolve(ctx context.Context, name string) (context.Context, net.IP, error) {
	addr, err := net.ResolveIPAddr("ip6", name)
	if err != nil {
		addr, err = net.ResolveIPAddr("ip4", name)
		if err != nil {
			return ctx, nil, err
		}
		return ctx, addr.IP, nil
	}
	return ctx, addr.IP, nil
}

So what I'm trying to do is that, I want to use user a for IPv4 outbound and b for IPv6 outbound.
Although I can use ctx for storing user information, it will be way easier if we have the option to skip the domain resolution.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants