func (i *Trace) SetWriteDeadLine() error {
	tv := syscall.NsecToTimeval(1e6 * DefaultTXTimeout)
	return syscall.SetsockoptTimeval(i.fd, syscall.SOL_SOCKET, syscall.SO_SNDTIMEO, &tv)
}
SetWriteDeadLine sets tx timeout
package icmp
import (
	"bytes"
	"encoding/binary"
	"fmt"
	"math/rand"
	"net"
	"os"
	"os/signal"
	"sort"
	"strings"
	"sync"
	"syscall"
	"time"
	"golang.org/x/net/ipv4"
	"github.com/mehrdadrad/mylg/cli"
	"github.com/mehrdadrad/mylg/ripe"
)
type TCPOption struct {
	kind   uint8
	length uint8
	data   []byte
}
type MHopResp []HopResp
func NewTrace(args string, cfg cli.Config) (*Trace, error) {
	var (
		family    int
		proto     int
		ip, lAddr net.IP
	)
	target, flag := cli.Flag(args)
	forceIPv4 := cli.SetFlag(flag, "4", false).(bool)
	forceIPv6 := cli.SetFlag(flag, "6", false).(bool)
	if _, ok := flag["help"]; ok || len(target) < 3 {
		helpTrace()
		return nil, nil
	}
	ips, err := net.LookupIP(target)
	if err != nil {
		return nil, err
	}
	for _, IP := range ips {
		if IsIPv4(IP) && !forceIPv6 {
			ip = IP
			break
		} else if IsIPv6(IP) && !forceIPv4 {
			ip = IP
			break
		}
	}
	if ip == nil {
		return nil, fmt.Errorf("there is not A or AAAA record")
	}
	if lAddr, err = getLocalAddr(ip.String()); err != nil {
		return nil, err
	}
	if IsIPv4(ip) {
		family = syscall.AF_INET
		proto = syscall.IPPROTO_ICMP
	} else {
		family = syscall.AF_INET6
		proto = syscall.IPPROTO_ICMPV6
	}
	UDP := cli.SetFlag(flag, "u", false).(bool)
	TCP := cli.SetFlag(flag, "t", false).(bool)
	t := &Trace{
		host:     target,
		ips:      ips,
		ip:       ip,
		src:      lAddr,
		seq:      1,
		family:   family,
		proto:    proto,
		icmp:     !UDP && !TCP,
		udp:      UDP && !TCP,
		tcp:      TCP && !UDP,
		pSize:    cli.SetFlag(flag, "p", 52).(int),
		uiTheme:  cli.SetFlag(flag, "T", cfg.Trace.Theme).(string),
		wait:     cli.SetFlag(flag, "w", cfg.Trace.Wait).(string),
		resolve:  cli.SetFlag(flag, "n", true).(bool),
		ripe:     cli.SetFlag(flag, "nr", true).(bool),
		realTime: cli.SetFlag(flag, "r", false).(bool),
		maxTTL:   cli.SetFlag(flag, "m", 30).(int),
		count:    cli.SetFlag(flag, "c", -1).(int),
		report:   cli.SetFlag(flag, "R", false).(bool),
		km:       cli.SetFlag(flag, "km", false).(bool),
	}
	t.setReportDCount(10)
	return t, nil
}
func (h MHopResp) Len() int           { return len(h) }
func (h MHopResp) Swap(i, j int)      { h[i], h[j] = h[j], h[i] }
func (h MHopResp) Less(i, j int) bool { return len(h[i].ip) > len(h[j].ip) }
func (i *Trace) SetTTL(ttl int) {
	i.ttl = ttl
}
func (i *Trace) Send(port int) (int, int, error) {
	rand.Seed(time.Now().UTC().UnixNano())
	var (
		seq    = i.seq
		id     = 38840 + seq
		sotype int
		proto  int
		err    error
	)
	i.seq++
	if i.icmp && i.ip.To4() != nil {
		sotype = syscall.SOCK_RAW
		proto = syscall.IPPROTO_ICMP
	} else if i.icmp && i.ip.To16() != nil {
		sotype = syscall.SOCK_RAW
		proto = syscall.IPPROTO_ICMPV6
	} else {
		sotype = syscall.SOCK_DGRAM
		proto = syscall.IPPROTO_UDP
	}
	fd, err := syscall.Socket(i.family, sotype, proto)
	if err != nil {
		return id, seq, err
	}
	defer syscall.Close(fd)
	if IsIPv4(i.ip) {
		err = i.Sendv4(id, seq, port)
		return id, seq, err
	} else {
		var b [16]byte
		copy(b[:], i.ip.To16())
		addr := syscall.SockaddrInet6{
			Port:   port,
			ZoneId: 0,
			Addr:   b,
		}
		m, err := icmpV6Message(os.Getpid()&0xffff, seq, i.pSize)
		if err != nil {
			return id, seq, err
		}
		setIPv6HopLimit(fd, i.ttl)
		if err := syscall.Sendto(fd, m, 0, &addr); err != nil {
			return id, seq, err
		}
	}
	return id, seq, nil
}
func (i *Trace) Sendv4(id, seq, rport int) error {
	var (
		b     []byte
		proto int
		lport int
	)
	switch {
	case i.icmp:
		proto = 1  
		b, _ = icmpV4Message(os.Getpid()&0xffff, seq, i.pSize)
	case i.udp:
		proto = 17  
		lport = 64000 + rand.Intn(3)*100
		b = udpMessage(lport, rport, i.pSize, true)
	case i.tcp:
		proto = 6  
		b = tcpMessage(0, 33434, 64, true)
		setTCPCheckSum(i.src, i.ip, b)
	}
	c, err := net.ListenPacket(fmt.Sprintf("ip4:%d", proto), "0.0.0.0")
	if err != nil {
		return err
	}
	defer c.Close()
	p, err := ipv4.NewRawConn(c)
	if err != nil {
		return err
	}
	h := &ipv4.Header{
		Version:  ipv4.Version,
		Len:      ipv4.HeaderLen,
		TotalLen: ipv4.HeaderLen + len(b),
		Protocol: proto,
		ID:       id,
		TTL:      i.ttl,
		Dst:      i.ip.To4(),
	}
	if err := p.WriteTo(h, b, nil); err != nil {
		return err
	}
	return nil
}
func (i *Trace) SetReadDeadLine() error {
	timeout, err := time.ParseDuration(i.wait)
	if err != nil {
		return err
	}
	tv := syscall.NsecToTimeval(timeout.Nanoseconds())
	return syscall.SetsockoptTimeval(i.fd, syscall.SOL_SOCKET, syscall.SO_RCVTIMEO, &tv)
}