func IsIPv4(ip net.IP) bool {
	return len(ip.To4()) == net.IPv4len
}
IsIPv4 returns true if ip version is v4
package icmp
import (
	"errors"
	"fmt"
	"golang.org/x/net/icmp"
	"golang.org/x/net/ipv4"
	"golang.org/x/net/ipv6"
	"math/rand"
	"net"
	"os"
	"os/signal"
	"regexp"
	"strings"
	"sync"
	"syscall"
	"time"
	"github.com/mehrdadrad/mylg/cli"
)
type packet struct {
	bytes []byte
	addr  net.Addr
	err   error
}
type Response struct {
	RTT      float64
	Size     int
	Sequence int
	Addr     string
	Timeout  bool
	Error    error
}
func NewPing(args string, cfg cli.Config) (*Ping, error) {
	var (
		err error
	)
	target, flag := cli.Flag(args)
	if _, ok := flag["help"]; ok || len(target) < 3 {
		help(cfg)
		return nil, nil
	}
	p := Ping{
		id:        rand.Intn(0xffff),
		seq:       -1,
		pSize:     64,
		target:    target,
		isV4Avail: false,
		isV6Avail: false,
		isCIDR:    isCIDR(target),
		count:     cli.SetFlag(flag, "c", cfg.Ping.Count).(int),
		forceV4:   cli.SetFlag(flag, "4", false).(bool),
		forceV6:   cli.SetFlag(flag, "6", false).(bool),
		network:   "ip",
		source:    "",
		MaxRTT:    time.Second,
	}
	if !p.isCIDR {
		ips, err := net.LookupIP(target)
		if err != nil {
			return nil, err
		}
		p.addrs = ips
		if err := p.SetIP(ips); err != nil {
			return nil, err
		}
	}
	timeoutStr := cli.SetFlag(flag, "t", cfg.Ping.Timeout).(string)
	timeoutStr = NormalizeDuration(timeoutStr)
	if p.timeout, err = time.ParseDuration(timeoutStr); err != nil {
		return nil, fmt.Errorf("timeout options is not valid")
	}
	intervalStr := cli.SetFlag(flag, "i", cfg.Ping.Interval).(string)
	intervalStr = NormalizeDuration(intervalStr)
	if p.interval, err = time.ParseDuration(intervalStr); err != nil {
		return nil, fmt.Errorf("interval options is not valid")
	}
	return &p, nil
}
func (p *Ping) Run() chan Response {
	var r = make(chan Response, 1)
	go func() {
		for n := 0; n < p.count; n++ {
			p.Ping(r)
			if n != p.count-1 {
				time.Sleep(p.interval)
			}
		}
		close(r)
	}()
	return r
}
func (p *Ping) MRun() chan Response {
	var (
		r           = make(chan Response, 1000)
		sigCh       = make(chan os.Signal, 1)
		_, ipNet, _ = net.ParseCIDR(p.target)
		ifs, _      = net.Interfaces()
		skipIPs     = map[string]struct{}{}
	)
	for _, i := range ifs {
		addrs, _ := i.Addrs()
		for _, addr := range addrs {
			IP, net, _ := net.ParseCIDR(addr.String())
			if IsIPv4(IP) {
				skipIPs[broadcast(IP, net)] = struct{}{}
			}
			skipIPs[strings.Split(net.String(), "/")[0]] = struct{}{}
		}
	}
	if len(ipNet.IP) == 4 {
		go func() {
			signal.Notify(sigCh, os.Interrupt)
			defer signal.Stop(sigCh)
		LOOP:
			for ip := range walkIPv4(p.target) {
				if _, ok := skipIPs[ip]; ok {
					continue
				}
				pp := p
				pp.isV4Avail = true
				pp.addr = &net.IPAddr{IP: net.ParseIP(ip)}
				pp.Ping(r)
				select {
				case <-sigCh:
					break LOOP
				default:
					continue
				}
			}
			close(r)
		}()
	} else {
		println("IPv6 doesn't support")
		close(r)
	}
	return r
}
func broadcast(ipo net.IP, ipnet *net.IPNet) string {
	ip := ipo.To4()
	broadcast := make(net.IP, net.IPv4len)
	copy(broadcast, ip)
	for i, v := range ip {
		broadcast[i] = v | ^ipnet.Mask[i]
	}
	return broadcast.String()
}