mehrdadrad / mylg

Network Diagnostic Tool
http://mylg.io
MIT License
2.7k stars 232 forks source link

hping with ipv6 #54

Closed jungle-boogie closed 7 years ago

jungle-boogie commented 7 years ago

Hi,

From looking at the hping options, it doesn't seem there's an option to connect via ipv6:

    usage:
          hping url [options]

    options:
          -c   count        Send 'count' requests (default: 5)
          -t   timeout      Set a time limit for requests in ms/s (default: 2s)
          -i   interval     Set a wait time between sending each request in ms/s (default: 1s)
          -m   method       HTTP methods: GET/POST/HEAD (default: head)
          -d   data         Sending the given data (text/json) (default: "mylg")
          -u   user agent   Set user agent
          -q                Quiet reqular output
          -k                Enable keep alive
          -dc               Disable compression
          -nc               Don_t check the server certificate
          -trace            Provides the events within client requests
          -json             Export statistics as json format

    Proxy:
        hping parses environment variables HTTP(S)_PROXY to determine which/if any
        proxies should be used.
gummiboll commented 7 years ago

I've been tinkering with this since I believe the ability to force hping to use IPv4/IPv6 would be a great addition to it.

The problem is that golangs http client can't (at least from my investigation) be forced to use IPv4/IPv6 easily. From my understanding there are two ways to solve this:

I'm leaning towards the second setup but it feels a bit.. icky. What are your thoughts on this, @mehrdadrad? Do you know of a better way to solve this or have I misunderstood something about golangs http client and its easy to specify the IP-version?

jungle-boogie commented 7 years ago

I checked on the #go-nuts IRC channel. Perhaps this is clear to you two:

So net.Dial gives you a net.Conn, you put the net.Conn in the http.Transport, you put the http.Transport in the http.Client

mehrdadrad commented 7 years ago

@gummiboll I didn't try it yet but may it works once we resolved to specific IP address

    http.DefaultTransport.(*http.Transport).DialContext = func(ctx context.Context, network, addr string) (net.Conn, error) {
               addr = net.JoinHostPort(ipAddress, port)
               return dialer.DialContext(ctx, network, addr)
    }
mehrdadrad commented 7 years ago

another suggestion from Golang slack channel

t := &http.Transport{
        DialContext: func(ctx context.Context, network, addr string) (net.Conn, error) {
            if conn, err := net.Dial("tcp6", addr); err == nil {
                return conn, nil
            }

            return net.Dial("tcp", addr)
        },
    }

    c := &http.Client{
        Transport: t,
    }
gummiboll commented 7 years ago

That seems quite clean. Will fiddle a little with it and make a PR. :)

gummiboll commented 7 years ago

PR submitted.

However, note the issue mentioned in it about happy eyeballs. I.e; since mylg first resolves the ip-address of the hostname and then again when it does the actual requests it can cause a issue where you think its pinging the IPv4-address but instead it pings the IPv6-address or the other way around. From testing this it seems like ResolveIPAddr prefers IPv4 over IPv6 but I haven't read through the sorce for ResolveIPAddr so I can be wrong.

As I see it, there is a couple of ways to handle this:

mehrdadrad commented 7 years ago

@gummiboll How about this:

+ 316         DialContext: func(ctx context.Context, network, addr string) (net.Conn, error) {
+ 317             if r := strings.Index(p.rAddr.String(), ":"); r != -1 {
+ 318                 return net.Dial("tcp6", addr)
+ 319             }
+ 320             return net.Dial("tcp4", addr)
+ 321         },
gummiboll commented 7 years ago

I was thinking something like:

DialContext: func(ctx context.Context, network, addr string) (net.Conn, error) {
        if p.rAddr.To4() != nil {
                return net.Dial("tcp4", addr)
        } else {
                return net.Dial("tcp6", addr)
        }
}

but will investigate however ResolveIPAddr prefers ipv4 or not first.

mehrdadrad commented 7 years ago

type net.Addr doesn't have To4 as net.IP does. anyway, same solution. Thanks for investigating

gummiboll commented 7 years ago

Ah, yeah - that's correct. So either change rAddr to net.IP or do a strings.Index. I kinda like the .To4()-solution better, looks cleaner but doesn't really matter. Both works. :)

If I read this correctly it seems like ResolveIPAddr does prefer ipv4 and from testing it seems to always return the ipv4-address but that kinda feels.. weird.

mehrdadrad commented 7 years ago

@gummiboll check the myLG->ping how it works, if IPv6 available on the client and name server then it tries to use IPv6 but if IPv6 not available on the client or name server then it tries to use IPv4. it think this login is make sense. what do you think?

jungle-boogie commented 7 years ago

@gummiboll, @mehrdadrad, I think something is missing:

 -4                Force IPv4
 -6                Force IPv6

hping -6 scanme.nmap.com and even hping -4 scanme.nmap.com return the help for hping.

mehrdadrad commented 7 years ago

@jungle-boogie usage: hping url [options] try hping scanme.nmap.com -6

gummiboll commented 7 years ago

@mehrdadrad: Will fiddle and try to come up with a good solution and make a pr when done.

jungle-boogie commented 7 years ago

thanks for implementing this!