func (n *Net) Interfaces() ([]*Interface, error) {
	if n.v == nil {
		return n.ifs, nil
	}
	return n.v.getInterfaces()
}
Interfaces returns a list of the system's network interfaces.
package vnet
import (
	"encoding/binary"
	"fmt"
	"math/rand"
	"net"
	"strconv"
	"strings"
	"sync"
)
var macAddrCounter uint64 = 0xBEEFED910200
func newMACAddress() net.HardwareAddr {
	b := make([]byte, 8)
	binary.BigEndian.PutUint64(b, macAddrCounter)
	macAddrCounter++
	return b[2:]
}
type vNet struct {
	interfaces []*Interface  
	staticIPs  []net.IP      
	router     *Router       
	udpConns   *udpConnMap   
	mutex      sync.RWMutex
}
func (v *vNet) _getInterfaces() ([]*Interface, error) {
	if len(v.interfaces) == 0 {
		return nil, fmt.Errorf("no interface is available")
	}
	return v.interfaces, nil
}
func (v *vNet) getInterfaces() ([]*Interface, error) {
	v.mutex.RLock()
	defer v.mutex.RUnlock()
	return v._getInterfaces()
}
func (v *vNet) _getInterface(ifName string) (*Interface, error) {
	ifs, err := v._getInterfaces()
	if err != nil {
		return nil, err
	}
	for _, ifc := range ifs {
		if ifc.Name == ifName {
			return ifc, nil
		}
	}
	return nil, fmt.Errorf("interface %s not found", ifName)
}
func (v *vNet) getInterface(ifName string) (*Interface, error) {
	v.mutex.RLock()
	defer v.mutex.RUnlock()
	return v._getInterface(ifName)
}
func (v *vNet) getAllIPAddrs(ipv6 bool) []net.IP {
	ips := []net.IP{}
	for _, ifc := range v.interfaces {
		addrs, err := ifc.Addrs()
		if err != nil {
			continue
		}
		for _, addr := range addrs {
			var ip net.IP
			if ipNet, ok := addr.(*net.IPNet); ok {
				ip = ipNet.IP
			} else if ipAddr, ok := addr.(*net.IPAddr); ok {
				ip = ipAddr.IP
			} else {
				continue
			}
			if !ipv6 {
				if ip.To4() != nil {
					ips = append(ips, ip)
				}
			}
		}
	}
	return ips
}
func (v *vNet) setRouter(r *Router) error {
	v.mutex.Lock()
	defer v.mutex.Unlock()
	v.router = r
	return nil
}
func (v *vNet) onInboundChunk(c Chunk) {
	v.mutex.Lock()
	defer v.mutex.Unlock()
	if c.Network() == "udp" {
		if conn, ok := v.udpConns.find(c.DestinationAddr()); ok {
			conn.onInboundChunk(c)
		}
	}
}
func (v *vNet) _dialUDP(network string, locAddr, remAddr *net.UDPAddr) (UDPPacketConn, error) {
	if network != "udp" && network != "udp4" {
		return nil, fmt.Errorf("unexpected network: %s", network)
	}
	if locAddr == nil {
		locAddr = &net.UDPAddr{
			IP: net.IPv4zero,
		}
	} else if locAddr.IP == nil {
		locAddr.IP = net.IPv4zero
	}
	if !v.hasIPAddr(locAddr.IP) {
		return nil, &net.OpError{
			Op:   "listen",
			Net:  network,
			Addr: locAddr,
			Err:  fmt.Errorf("bind: can't assign requested address"),
		}
	}
	if locAddr.Port == 0 {
		port, err := v.assignPort(locAddr.IP, 5000, 5999)
		if err != nil {
			return nil, &net.OpError{
				Op:   "listen",
				Net:  network,
				Addr: locAddr,
				Err:  err,
			}
		}
		locAddr.Port = port
	} else if _, ok := v.udpConns.find(locAddr); ok {
		return nil, &net.OpError{
			Op:   "listen",
			Net:  network,
			Addr: locAddr,
			Err:  fmt.Errorf("bind: address already in use"),
		}
	}
	conn, err := newUDPConn(locAddr, remAddr, v)
	if err != nil {
		return nil, err
	}
	err = v.udpConns.insert(conn)
	if err != nil {
		return nil, err
	}
	return conn, nil
}
func (v *vNet) listenPacket(network string, address string) (UDPPacketConn, error) {
	v.mutex.Lock()
	defer v.mutex.Unlock()
	locAddr, err := v.resolveUDPAddr(network, address)
	if err != nil {
		return nil, err
	}
	return v._dialUDP(network, locAddr, nil)
}
func (v *vNet) listenUDP(network string, locAddr *net.UDPAddr) (UDPPacketConn, error) {
	v.mutex.Lock()
	defer v.mutex.Unlock()
	return v._dialUDP(network, locAddr, nil)
}
func (v *vNet) dialUDP(network string, locAddr, remAddr *net.UDPAddr) (UDPPacketConn, error) {
	v.mutex.Lock()
	defer v.mutex.Unlock()
	return v._dialUDP(network, locAddr, remAddr)
}
func (v *vNet) dial(network string, address string) (UDPPacketConn, error) {
	v.mutex.Lock()
	defer v.mutex.Unlock()
	remAddr, err := v.resolveUDPAddr(network, address)
	if err != nil {
		return nil, err
	}
	srcIP := v.determineSourceIP(nil, remAddr.IP)
	locAddr := &net.UDPAddr{IP: srcIP, Port: 0}
	return v._dialUDP(network, locAddr, remAddr)
}
func (v *vNet) resolveUDPAddr(network, address string) (*net.UDPAddr, error) {
	if network != "udp" && network != "udp4" {
		return nil, fmt.Errorf("unknown network %s", network)
	}
	host, sPort, err := net.SplitHostPort(address)
	if err != nil {
		return nil, err
	}
	ip := net.ParseIP(host)
	if ip == nil {
		host = strings.ToLower(host)
		if host == "localhost" {
			ip = net.IPv4(127, 0, 0, 1)
		} else {
			if v.router == nil {
				return nil, fmt.Errorf("no router linked")
			}
			ip, err = v.router.resolver.lookUp(host)
			if err != nil {
				return nil, err
			}
		}
	}
	port, err := strconv.Atoi(sPort)
	if err != nil {
		return nil, fmt.Errorf("invalid port number")
	}
	udpAddr := &net.UDPAddr{
		IP:   ip,
		Port: port,
	}
	return udpAddr, nil
}
func (v *vNet) write(c Chunk) error {
	if c.Network() == "udp" {
		if udp, ok := c.(*chunkUDP); ok {
			if c.getDestinationIP().IsLoopback() {
				if conn, ok := v.udpConns.find(udp.DestinationAddr()); ok {
					conn.onInboundChunk(udp)
				}
				return nil
			}
		} else {
			return fmt.Errorf("unexpected type-switch failure")
		}
	}
	if v.router == nil {
		return fmt.Errorf("no router linked")
	}
	v.router.push(c)
	return nil
}
func (v *vNet) onClosed(addr net.Addr) {
	if addr.Network() == "udp" {
		v.udpConns.delete(addr)  
	}
}
func (v *vNet) determineSourceIP(locIP, dstIP net.IP) net.IP {
	if locIP != nil && !locIP.IsUnspecified() {
		return locIP
	}
	var srcIP net.IP
	if dstIP.IsLoopback() {
		srcIP = net.ParseIP("127.0.0.1")
	} else {
		ifc, err2 := v._getInterface("eth0")
		if err2 != nil {
			return nil
		}
		addrs, err2 := ifc.Addrs()
		if err2 != nil {
			return nil
		}
		if len(addrs) == 0 {
			return nil
		}
		var findIPv4 bool
		if locIP != nil {
			findIPv4 = (locIP.To4() != nil)
		} else {
			findIPv4 = (dstIP.To4() != nil)
		}
		for _, addr := range addrs {
			ip := addr.(*net.IPNet).IP
			if findIPv4 {
				if ip.To4() != nil {
					srcIP = ip
					break
				}
			} else {
				if ip.To4() == nil {
					srcIP = ip
					break
				}
			}
		}
	}
	return srcIP
}
func (v *vNet) hasIPAddr(ip net.IP) bool {
	for _, ifc := range v.interfaces {
		if addrs, err := ifc.Addrs(); err == nil {
			for _, addr := range addrs {
				var locIP net.IP
				if ipNet, ok := addr.(*net.IPNet); ok {
					locIP = ipNet.IP
				} else if ipAddr, ok := addr.(*net.IPAddr); ok {
					locIP = ipAddr.IP
				} else {
					continue
				}
				switch ip.String() {
				case "0.0.0.0":
					if locIP.To4() != nil {
						return true
					}
				case "::":
					if locIP.To4() == nil {
						return true
					}
				default:
					if locIP.Equal(ip) {
						return true
					}
				}
			}
		}
	}
	return false
}
func (v *vNet) allocateLocalAddr(ip net.IP, port int) error {
	var ips []net.IP
	if ip.IsUnspecified() {
		ips = v.getAllIPAddrs(ip.To4() == nil)
	} else if v.hasIPAddr(ip) {
		ips = []net.IP{ip}
	}
	if len(ips) == 0 {
		return fmt.Errorf("bind failed for %s", ip.String())
	}
	for _, ip2 := range ips {
		addr := &net.UDPAddr{
			IP:   ip2,
			Port: port,
		}
		if _, ok := v.udpConns.find(addr); ok {
			return &net.OpError{
				Op:   "bind",
				Net:  "udp",
				Addr: addr,
				Err:  fmt.Errorf("bind: address already in use"),
			}
		}
	}
	return nil
}
func (v *vNet) assignPort(ip net.IP, start, end int) (int, error) {
	if end < start {
		return -1, fmt.Errorf("end port is less than the start")
	}
	space := end + 1 - start
	offset := rand.Intn(space)
	for i := 0; i < space; i++ {
		port := ((offset + i) % space) + start
		err := v.allocateLocalAddr(ip, port)
		if err == nil {
			return port, nil
		}
	}
	return -1, fmt.Errorf("port space exhausted")
}
type NetConfig struct {
	StaticIPs []string
	StaticIP string
}
type Net struct {
	v   *vNet
	ifs []*Interface
}
func NewNet(config *NetConfig) *Net {
	if config == nil {
		ifs := []*Interface{}
		if orgIfs, err := net.Interfaces(); err == nil {
			for _, orgIfc := range orgIfs {
				ifc := NewInterface(orgIfc)
				if addrs, err := orgIfc.Addrs(); err == nil {
					for _, addr := range addrs {
						ifc.AddAddr(addr)
					}
				}
				ifs = append(ifs, ifc)
			}
		}
		return &Net{ifs: ifs}
	}
	lo0 := NewInterface(net.Interface{
		Index:        1,
		MTU:          16384,
		Name:         "lo0",
		HardwareAddr: nil,
		Flags:        net.FlagUp | net.FlagLoopback | net.FlagMulticast,
	})
	lo0.AddAddr(&net.IPNet{
		IP:   net.ParseIP("127.0.0.1"),
		Mask: net.CIDRMask(8, 32),
	})
	eth0 := NewInterface(net.Interface{
		Index:        2,
		MTU:          1500,
		Name:         "eth0",
		HardwareAddr: newMACAddress(),
		Flags:        net.FlagUp | net.FlagMulticast,
	})
	var staticIPs []net.IP
	for _, ipStr := range config.StaticIPs {
		if ip := net.ParseIP(ipStr); ip != nil {
			staticIPs = append(staticIPs, ip)
		}
	}
	if len(config.StaticIP) > 0 {
		if ip := net.ParseIP(config.StaticIP); ip != nil {
			staticIPs = append(staticIPs, ip)
		}
	}
	v := &vNet{
		interfaces: []*Interface{lo0, eth0},
		staticIPs:  staticIPs,
		udpConns:   newUDPConnMap(),
	}
	return &Net{
		v: v,
	}
}