func UPnP() Nat {
	return startautodisc("UPnP", discoverUPnP)
}
UPnP returns a port mapper that uses UPnP. It will attempt to
discover the address of your router using UDP broadcasts.
package nat
import (
	"errors"
	"fmt"
	"net"
	"strings"
	"sync"
	"time"
	"github.com/ThinkiumGroup/go-common/log"
	natpmp "github.com/jackpal/go-nat-pmp"
)
type Nat interface {
	AddMapping(protocol string, extport, intport int, name string, lifetime time.Duration) error
	DeleteMapping(protocol string, extport, intport int) error
	ExternalIP() (net.IP, error)
	String() string
}
func Parse(spec string) (Nat, error) {
	var (
		parts = strings.SplitN(spec, ":", 2)
		mech  = strings.ToLower(parts[0])
		ip    net.IP
	)
	if len(parts) > 1 {
		ip = net.ParseIP(parts[1])
		if ip == nil {
			return nil, errors.New("invalid IP address")
		}
	}
	switch mech {
	case "", "none", "off":
		return nil, nil
	case "any", "auto", "on":
		return Any(), nil
	case "extip", "ip":
		if ip == nil {
			return nil, errors.New("missing IP address")
		}
		return ExtIP(ip), nil
	case "upnp":
		return UPnP(), nil
	case "pmp", "natpmp", "nat-pmp":
		return PMP(ip), nil
	default:
		return nil, fmt.Errorf("unknown mechanism %q", parts[0])
	}
}
const (
	mapTimeout        = 20 * time.Minute
	mapUpdateInterval = 15 * time.Minute
)
func Map(m Nat, c chan struct{}, protocol string, extport, intport int, name string) {
	log.Infof("proto %s, extport %d, intport %d, nat %s", protocol, extport, intport, m)
	refresh := time.NewTimer(mapUpdateInterval)
	defer func() {
		refresh.Stop()
		log.Debug("Deleting port mapping")
		m.DeleteMapping(protocol, extport, intport)
	}()
	if err := m.AddMapping(protocol, extport, intport, name, mapTimeout); err != nil {
		log.Debug("Couldn't add port mapping", "err", err)
	} else {
		log.Info("Mapped network port")
	}
	for {
		select {
		case _, ok := <-c:
			if !ok {
				return
			}
		case <-refresh.C:
			log.Debug("Refreshing port mapping")
			if err := m.AddMapping(protocol, extport, intport, name, mapTimeout); err != nil {
				log.Debug("Couldn't add port mapping", "err", err)
			}
			refresh.Reset(mapUpdateInterval)
		}
	}
}
func ExtIP(ip net.IP) Nat {
	if ip == nil {
		panic("IP must not be nil")
	}
	return extIP(ip)
}
type extIP net.IP
func (n extIP) ExternalIP() (net.IP, error) { return net.IP(n), nil }
func (n extIP) String() string              { return fmt.Sprintf("ExtIP(%v)", net.IP(n)) }
func (extIP) AddMapping(string, int, int, string, time.Duration) error { return nil }
func (extIP) DeleteMapping(string, int, int) error                     { return nil }
func Any() Nat {
	return startautodisc("UPnP or NAT-PMP", func() Nat {
		found := make(chan Nat, 2)
		go func() { found <- discoverUPnP() }()
		go func() { found <- discoverPMP() }()
		for i := 0; i < cap(found); i++ {
			if c := <-found; c != nil {
				return c
			}
		}
		return nil
	})
}