2015-04-08 02:20:04 -04:00
|
|
|
package portmapper
|
|
|
|
|
|
|
|
import (
|
|
|
|
"fmt"
|
2015-05-21 15:20:48 -04:00
|
|
|
"io"
|
2015-04-08 02:20:04 -04:00
|
|
|
"net"
|
2017-06-13 01:29:56 -04:00
|
|
|
|
|
|
|
"github.com/ishidawataru/sctp"
|
2015-04-08 02:20:04 -04:00
|
|
|
)
|
|
|
|
|
|
|
|
type userlandProxy interface {
|
|
|
|
Start() error
|
|
|
|
Stop() error
|
|
|
|
}
|
|
|
|
|
2020-12-13 18:56:30 -05:00
|
|
|
// 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"
|
|
|
|
)
|
|
|
|
|
2015-05-21 15:20:48 -04:00
|
|
|
// 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 {
|
2020-12-13 18:56:30 -05:00
|
|
|
listener io.Closer
|
|
|
|
addr net.Addr
|
|
|
|
ipVersion ipVersion
|
2015-05-21 15:20:48 -04:00
|
|
|
}
|
|
|
|
|
2017-06-13 01:29:56 -04:00
|
|
|
func newDummyProxy(proto string, hostIP net.IP, hostPort int) (userlandProxy, error) {
|
2020-12-13 18:56:30 -05:00
|
|
|
// detect version of hostIP to bind only to correct version
|
|
|
|
version := ipv4
|
|
|
|
if hostIP.To4() == nil {
|
|
|
|
version = ipv6
|
|
|
|
}
|
2015-05-21 15:20:48 -04:00
|
|
|
switch proto {
|
|
|
|
case "tcp":
|
|
|
|
addr := &net.TCPAddr{IP: hostIP, Port: hostPort}
|
2020-12-13 18:56:30 -05:00
|
|
|
return &dummyProxy{addr: addr, ipVersion: version}, nil
|
2015-05-21 15:20:48 -04:00
|
|
|
case "udp":
|
|
|
|
addr := &net.UDPAddr{IP: hostIP, Port: hostPort}
|
2020-12-13 18:56:30 -05:00
|
|
|
return &dummyProxy{addr: addr, ipVersion: version}, nil
|
2017-06-13 01:29:56 -04:00
|
|
|
case "sctp":
|
2019-05-02 07:23:31 -04:00
|
|
|
addr := &sctp.SCTPAddr{IPAddrs: []net.IPAddr{{IP: hostIP}}, Port: hostPort}
|
2020-12-13 18:56:30 -05:00
|
|
|
return &dummyProxy{addr: addr, ipVersion: version}, nil
|
2017-06-13 01:29:56 -04:00
|
|
|
default:
|
|
|
|
return nil, fmt.Errorf("Unknown addr type: %s", proto)
|
2015-05-21 15:20:48 -04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func (p *dummyProxy) Start() error {
|
|
|
|
switch addr := p.addr.(type) {
|
|
|
|
case *net.TCPAddr:
|
2020-12-13 18:56:30 -05:00
|
|
|
l, err := net.ListenTCP("tcp"+string(p.ipVersion), addr)
|
2015-05-21 15:20:48 -04:00
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
p.listener = l
|
|
|
|
case *net.UDPAddr:
|
2020-12-13 18:56:30 -05:00
|
|
|
l, err := net.ListenUDP("udp"+string(p.ipVersion), addr)
|
2015-05-21 15:20:48 -04:00
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
p.listener = l
|
2017-06-13 01:29:56 -04:00
|
|
|
case *sctp.SCTPAddr:
|
2020-12-13 18:56:30 -05:00
|
|
|
l, err := sctp.ListenSCTP("sctp"+string(p.ipVersion), addr)
|
2017-06-13 01:29:56 -04:00
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
p.listener = l
|
2015-05-21 15:20:48 -04:00
|
|
|
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
|
|
|
|
}
|