| package portmapper |
| |
| import ( |
| "fmt" |
| "io" |
| "net" |
| |
| "github.com/ishidawataru/sctp" |
| ) |
| |
| type userlandProxy interface { |
| Start() error |
| Stop() error |
| } |
| |
| // ipVersion refers to IP version - v4 or v6 |
| type ipVersion string |
| |
| const ( |
| // IPv4 is version 4 |
| ipv4 ipVersion = "4" |
| // IPv4 is version 6 |
| ipv6 ipVersion = "6" |
| ) |
| |
| // dummyProxy just listen on some port, it is needed to prevent accidental |
| // port allocations on bound port, because without userland proxy we using |
| // iptables rules and not net.Listen |
| type dummyProxy struct { |
| listener io.Closer |
| addr net.Addr |
| ipVersion ipVersion |
| } |
| |
| func newDummyProxy(proto string, hostIP net.IP, hostPort int) (userlandProxy, error) { |
| // detect version of hostIP to bind only to correct version |
| version := ipv4 |
| if hostIP.To4() == nil { |
| version = ipv6 |
| } |
| switch proto { |
| case "tcp": |
| addr := &net.TCPAddr{IP: hostIP, Port: hostPort} |
| return &dummyProxy{addr: addr, ipVersion: version}, nil |
| case "udp": |
| addr := &net.UDPAddr{IP: hostIP, Port: hostPort} |
| return &dummyProxy{addr: addr, ipVersion: version}, nil |
| case "sctp": |
| addr := &sctp.SCTPAddr{IPAddrs: []net.IPAddr{{IP: hostIP}}, Port: hostPort} |
| return &dummyProxy{addr: addr, ipVersion: version}, nil |
| default: |
| return nil, fmt.Errorf("Unknown addr type: %s", proto) |
| } |
| } |
| |
| func (p *dummyProxy) Start() error { |
| switch addr := p.addr.(type) { |
| case *net.TCPAddr: |
| l, err := net.ListenTCP("tcp"+string(p.ipVersion), addr) |
| if err != nil { |
| return err |
| } |
| p.listener = l |
| case *net.UDPAddr: |
| l, err := net.ListenUDP("udp"+string(p.ipVersion), addr) |
| if err != nil { |
| return err |
| } |
| p.listener = l |
| case *sctp.SCTPAddr: |
| l, err := sctp.ListenSCTP("sctp"+string(p.ipVersion), addr) |
| if err != nil { |
| return err |
| } |
| p.listener = l |
| default: |
| return fmt.Errorf("Unknown addr type: %T", p.addr) |
| } |
| return nil |
| } |
| |
| func (p *dummyProxy) Stop() error { |
| if p.listener != nil { |
| return p.listener.Close() |
| } |
| return nil |
| } |