|
|
|
@@ -12,6 +12,7 @@ import (
|
|
|
|
|
"github.com/pion/transport/v3"
|
|
|
|
|
log "github.com/sirupsen/logrus"
|
|
|
|
|
"golang.org/x/net/ipv4"
|
|
|
|
|
"golang.org/x/net/ipv6"
|
|
|
|
|
wgConn "golang.zx2c4.com/wireguard/conn"
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
@@ -24,8 +25,8 @@ type receiverCreator struct {
|
|
|
|
|
iceBind *ICEBind
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func (rc receiverCreator) CreateIPv4ReceiverFn(msgPool *sync.Pool, pc *ipv4.PacketConn, conn *net.UDPConn) wgConn.ReceiveFunc {
|
|
|
|
|
return rc.iceBind.createIPv4ReceiverFn(msgPool, pc, conn)
|
|
|
|
|
func (rc receiverCreator) CreateIPv4ReceiverFn(pc *ipv4.PacketConn, conn *net.UDPConn, rxOffload bool, msgPool *sync.Pool) wgConn.ReceiveFunc {
|
|
|
|
|
return rc.iceBind.createIPv4ReceiverFn(pc, conn, rxOffload, msgPool)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// ICEBind is a bind implementation with two main features:
|
|
|
|
@@ -82,6 +83,10 @@ func (s *ICEBind) Open(uport uint16) ([]wgConn.ReceiveFunc, uint16, error) {
|
|
|
|
|
return nil, 0, err
|
|
|
|
|
}
|
|
|
|
|
fns = append(fns, s.receiveRelayed)
|
|
|
|
|
|
|
|
|
|
s.muUDPMux.Lock()
|
|
|
|
|
s.udpMux = s.createUDPMux()
|
|
|
|
|
s.muUDPMux.Unlock()
|
|
|
|
|
return fns, port, nil
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
@@ -154,28 +159,32 @@ func (b *ICEBind) Send(bufs [][]byte, ep wgConn.Endpoint) error {
|
|
|
|
|
return nil
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func (s *ICEBind) createIPv4ReceiverFn(ipv4MsgsPool *sync.Pool, pc *ipv4.PacketConn, conn *net.UDPConn) wgConn.ReceiveFunc {
|
|
|
|
|
s.muUDPMux.Lock()
|
|
|
|
|
defer s.muUDPMux.Unlock()
|
|
|
|
|
|
|
|
|
|
s.udpMux = NewUniversalUDPMuxDefault(
|
|
|
|
|
UniversalUDPMuxParams{
|
|
|
|
|
UDPConn: conn,
|
|
|
|
|
Net: s.transportNet,
|
|
|
|
|
FilterFn: s.filterFn,
|
|
|
|
|
},
|
|
|
|
|
)
|
|
|
|
|
func (s *ICEBind) createIPv4ReceiverFn(pc *ipv4.PacketConn, conn *net.UDPConn, rxOffload bool, msgsPool *sync.Pool) wgConn.ReceiveFunc {
|
|
|
|
|
return func(bufs [][]byte, sizes []int, eps []wgConn.Endpoint) (n int, err error) {
|
|
|
|
|
msgs := ipv4MsgsPool.Get().(*[]ipv4.Message)
|
|
|
|
|
defer ipv4MsgsPool.Put(msgs)
|
|
|
|
|
msgs := getMessages(msgsPool)
|
|
|
|
|
for i := range bufs {
|
|
|
|
|
(*msgs)[i].Buffers[0] = bufs[i]
|
|
|
|
|
(*msgs)[i].OOB = (*msgs)[i].OOB[:cap((*msgs)[i].OOB)]
|
|
|
|
|
}
|
|
|
|
|
defer putMessages(msgs, msgsPool)
|
|
|
|
|
var numMsgs int
|
|
|
|
|
if runtime.GOOS == "linux" {
|
|
|
|
|
numMsgs, err = pc.ReadBatch(*msgs, 0)
|
|
|
|
|
if err != nil {
|
|
|
|
|
return 0, err
|
|
|
|
|
if runtime.GOOS == "linux" || runtime.GOOS == "android" {
|
|
|
|
|
if rxOffload {
|
|
|
|
|
readAt := len(*msgs) - (wgConn.IdealBatchSize / wgConn.UdpSegmentMaxDatagrams)
|
|
|
|
|
//nolint
|
|
|
|
|
numMsgs, err = pc.ReadBatch((*msgs)[readAt:], 0)
|
|
|
|
|
if err != nil {
|
|
|
|
|
return 0, err
|
|
|
|
|
}
|
|
|
|
|
numMsgs, err = wgConn.SplitCoalescedMessages(*msgs, readAt, wgConn.GetGSOSize)
|
|
|
|
|
if err != nil {
|
|
|
|
|
return 0, err
|
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
numMsgs, err = pc.ReadBatch(*msgs, 0)
|
|
|
|
|
if err != nil {
|
|
|
|
|
return 0, err
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
msg := &(*msgs)[0]
|
|
|
|
@@ -191,11 +200,12 @@ func (s *ICEBind) createIPv4ReceiverFn(ipv4MsgsPool *sync.Pool, pc *ipv4.PacketC
|
|
|
|
|
// todo: handle err
|
|
|
|
|
ok, _ := s.filterOutStunMessages(msg.Buffers, msg.N, msg.Addr)
|
|
|
|
|
if ok {
|
|
|
|
|
sizes[i] = 0
|
|
|
|
|
} else {
|
|
|
|
|
sizes[i] = msg.N
|
|
|
|
|
continue
|
|
|
|
|
}
|
|
|
|
|
sizes[i] = msg.N
|
|
|
|
|
if sizes[i] == 0 {
|
|
|
|
|
continue
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
addrPort := msg.Addr.(*net.UDPAddr).AddrPort()
|
|
|
|
|
ep := &wgConn.StdNetEndpoint{AddrPort: addrPort} // TODO: remove allocation
|
|
|
|
|
wgConn.GetSrcFromControl(msg.OOB[:msg.NN], ep)
|
|
|
|
@@ -241,14 +251,14 @@ func (s *ICEBind) parseSTUNMessage(raw []byte) (*stun.Message, error) {
|
|
|
|
|
|
|
|
|
|
// receiveRelayed is a receive function that is used to receive packets from the relayed connection and forward to the
|
|
|
|
|
// WireGuard. Critical part is do not block if the Closed() has been called.
|
|
|
|
|
func (c *ICEBind) receiveRelayed(buffs [][]byte, sizes []int, eps []wgConn.Endpoint) (int, error) {
|
|
|
|
|
c.closedChanMu.RLock()
|
|
|
|
|
defer c.closedChanMu.RUnlock()
|
|
|
|
|
func (s *ICEBind) receiveRelayed(buffs [][]byte, sizes []int, eps []wgConn.Endpoint) (int, error) {
|
|
|
|
|
s.closedChanMu.RLock()
|
|
|
|
|
defer s.closedChanMu.RUnlock()
|
|
|
|
|
|
|
|
|
|
select {
|
|
|
|
|
case <-c.closedChan:
|
|
|
|
|
case <-s.closedChan:
|
|
|
|
|
return 0, net.ErrClosed
|
|
|
|
|
case msg, ok := <-c.RecvChan:
|
|
|
|
|
case msg, ok := <-s.RecvChan:
|
|
|
|
|
if !ok {
|
|
|
|
|
return 0, net.ErrClosed
|
|
|
|
|
}
|
|
|
|
@@ -259,6 +269,16 @@ func (c *ICEBind) receiveRelayed(buffs [][]byte, sizes []int, eps []wgConn.Endpo
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func (s *ICEBind) createUDPMux() *UniversalUDPMuxDefault {
|
|
|
|
|
return NewUniversalUDPMuxDefault(
|
|
|
|
|
UniversalUDPMuxParams{
|
|
|
|
|
UDPConn: s.StdNetBind.IPv4Conn(),
|
|
|
|
|
Net: s.transportNet,
|
|
|
|
|
FilterFn: s.filterFn,
|
|
|
|
|
},
|
|
|
|
|
)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// fakeAddress returns a fake address that is used to as an identifier for the peer.
|
|
|
|
|
// The fake address is in the format of 127.1.x.x where x.x is the last two octets of the peer address.
|
|
|
|
|
func fakeAddress(peerAddress *net.UDPAddr) (*net.UDPAddr, error) {
|
|
|
|
@@ -273,3 +293,15 @@ func fakeAddress(peerAddress *net.UDPAddr) (*net.UDPAddr, error) {
|
|
|
|
|
}
|
|
|
|
|
return newAddr, nil
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func getMessages(msgsPool *sync.Pool) *[]ipv6.Message {
|
|
|
|
|
return msgsPool.Get().(*[]ipv6.Message)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func putMessages(msgs *[]ipv6.Message, msgsPool *sync.Pool) {
|
|
|
|
|
for i := range *msgs {
|
|
|
|
|
(*msgs)[i].OOB = (*msgs)[i].OOB[:0]
|
|
|
|
|
(*msgs)[i] = ipv6.Message{Buffers: (*msgs)[i].Buffers, OOB: (*msgs)[i].OOB}
|
|
|
|
|
}
|
|
|
|
|
msgsPool.Put(msgs)
|
|
|
|
|
}
|