txthinking/brook · error

Invalid dial with IP

Error message

Invalid dial with IP

What it means

NewDialWithIP builds a DialWithIP plugin from an IPv4 and an IPv6 address string. Before error [70] is thrown, the function validates the ip4 argument: it must either be empty or parse as a valid IP via net.ParseIP AND convert to a 4-byte IPv4 address via To4(). This error means the supplied ip4 string was non-empty but was not a valid IPv4 address (it was unparseable, or it was an IPv6/different form), so the constructor aborts rather than storing a bogus address.

Source

Thrown at plugins/dialwithip/dialwithip.go:32

package dialwithip

import (
	"errors"
	"net"

	"github.com/txthinking/brook"
	"github.com/txthinking/socks5"
)

type DialWithIP struct {
	IP4 net.IP
	IP6 net.IP
}

func NewDialWithIP(ip4, ip6 string) (*DialWithIP, error) {
	if ip4 != "" && (net.ParseIP(ip4) == nil || net.ParseIP(ip4).To4() == nil) {
		return nil, errors.New("Invalid dial with IP")
	}
	if ip6 != "" && (net.ParseIP(ip6) == nil || net.ParseIP(ip6).To4() != nil) {
		return nil, errors.New("Invalid dial with IP")
	}
	d := &DialWithIP{}
	if ip4 != "" {
		d.IP4 = net.ParseIP(ip4).To4()
	}
	if ip6 != "" {
		d.IP6 = net.ParseIP(ip6).To16()
	}
	return d, nil
}

func (p *DialWithIP) TouchBrook() {
	brook.DialTCP = func(network string, laddr, raddr string) (net.Conn, error) {
		var la, ra *net.TCPAddr
		if laddr != "" {

View on GitHub (pinned to 5cd13ef3b1)

Solutions

  1. Check the ip4 argument and correct it to a valid IPv4 address (e.g. "10.0.0.1"); if you only have IPv6, pass "" as ip4 and supply the address as ip6 instead.
  2. Pre-validate with net.ParseIP(ip4).To4() != nil before calling NewDialWithIP to fail fast with a clearer message.
  3. If the value is a hostname, resolve it first with net.LookupHost and pick the A record for ip4.
  4. Trim whitespace and strip any port suffix from the string before passing it in.

Example fix

// before
_, err := brookplugin.NewDialWithIP("example.com", "2001:db8::1")
// after
ip4, _ := net.LookupHost("example.com")
d, err := brookplugin.NewDialWithIP(ip4[0], "2001:db8::1") // ip4[0] e.g. "93.184.216.34"
Defensive patterns

Strategy: validation

Validate before calling

func isValidIPv4(s string) bool {
    ip := net.ParseIP(strings.TrimSpace(s))
    return s == "" || (ip != nil && ip.To4() != nil)
}
// call: if !isValidIPv4(ip4) { return fmt.Errorf("bad ipv4: %q", ip4) }

Type guard

func isIPv4(s string) bool {
    ip := net.ParseIP(s)
    return ip != nil && ip.To4() != nil
}

Try / catch

d, err := brookplugin.NewDialWithIP(ip4, ip6)
if err != nil {
    if err.Error() == "Invalid dial with IP" {
        log.Fatalf("invalid IPv4 literal %q: must parse via net.ParseIP and To4()", ip4)
    }
    return err
}

Prevention

When it happens

Trigger: Calling NewDialWithIP with a non-empty ip4 string that fails net.ParseIP (e.g. "999.1.1.1", "192.168.1", "example.com") or that parses but is not IPv4 (e.g. "::1", "2001:db8::1", an IPv4-in-IPv6 form where To4() returns nil).

Common situations: Passing a hostname instead of an IP in config; swapping the arguments and passing an IPv6 address as ip4; typos or extra whitespace/port suffixes like "10.0.0.1:53" in the IPv4 field; environment-specific config files where an IPv6 address was pasted into the IPv4 slot.

Understand the failure class

Background: "Must be a positive integer", "Invalid value", "Unsupported": the invalid-argument-value error family, when a library rejects the value you pass — this error's family across 35 libraries.

Related errors


AI-assisted analysis of txthinking/brook@5cd13ef3b1 (2026-09-06). Data as JSON: /api/errors/183e92c9a9538cf7. Report an issue: GitHub.