mirror of
https://github.com/netbirdio/netbird.git
synced 2025-08-13 17:07:30 +02:00
Refactor UDP mux to handle STUN only messages
This commit is contained in:
@ -13,7 +13,7 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
type BindMux interface {
|
type BindMux interface {
|
||||||
HandlePacket(p []byte, n int, addr net.Addr) error
|
HandleSTUNMessage(msg *stun.Message, addr net.Addr) error
|
||||||
Type() string
|
Type() string
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -96,6 +96,17 @@ func listenNet(network string, port int) (*net.UDPConn, int, error) {
|
|||||||
return conn, uaddr.Port, nil
|
return conn, uaddr.Port, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func parseStunMessage(raw []byte) (*stun.Message, error) {
|
||||||
|
msg := &stun.Message{
|
||||||
|
Raw: append([]byte{}, raw...),
|
||||||
|
}
|
||||||
|
if err := msg.Decode(); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return msg, nil
|
||||||
|
}
|
||||||
|
|
||||||
func (b *ICEBind) makeReceiveIPv4(c net.PacketConn) conn.ReceiveFunc {
|
func (b *ICEBind) makeReceiveIPv4(c net.PacketConn) conn.ReceiveFunc {
|
||||||
return func(buff []byte) (int, conn.Endpoint, error) {
|
return func(buff []byte) (int, conn.Endpoint, error) {
|
||||||
n, endpoint, err := c.ReadFrom(buff)
|
n, endpoint, err := c.ReadFrom(buff)
|
||||||
@ -114,37 +125,20 @@ func (b *ICEBind) makeReceiveIPv4(c net.PacketConn) conn.ReceiveFunc {
|
|||||||
Zone: e.Addr().Zone(),
|
Zone: e.Addr().Zone(),
|
||||||
}), nil
|
}), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
msg, err := parseStunMessage(buff[:n])
|
||||||
|
if err != nil {
|
||||||
|
return 0, nil, err
|
||||||
|
}
|
||||||
|
|
||||||
b.mu.Lock()
|
b.mu.Lock()
|
||||||
|
|
||||||
/* msg := &stun.Message{
|
|
||||||
Raw: append([]byte{}, buff[:n]...),
|
|
||||||
}
|
|
||||||
if err := msg.Decode(); err != nil {
|
|
||||||
return 0, nil, err
|
|
||||||
}
|
|
||||||
strAttrs := []string{}
|
|
||||||
for _, attribute := range msg.Attributes {
|
|
||||||
strAttrs = append(strAttrs, attribute.String())
|
|
||||||
}
|
|
||||||
|
|
||||||
xorMapped := "EMPTY"
|
|
||||||
_, err = msg.Get(stun.AttrXORMappedAddress)
|
|
||||||
if err == nil {
|
|
||||||
var addr stun.XORMappedAddress
|
|
||||||
if err := addr.GetFrom(msg); err == nil {
|
|
||||||
xorMapped = addr.String()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
log.Printf("endpoint %s XORMAPPED %s mux type %s msg type %s, attributes %s", endpoint.String(), xorMapped, bindMux.Type(), msg.Type.String(), strings.Join(strAttrs[:], ";"))
|
|
||||||
*/
|
|
||||||
if _, ok := b.endpointMap[e.String()]; !ok {
|
if _, ok := b.endpointMap[e.String()]; !ok {
|
||||||
b.endpointMap[e.String()] = c
|
b.endpointMap[e.String()] = c
|
||||||
log.Infof("added endpoint %s", e.String())
|
log.Infof("added endpoint %s", e.String())
|
||||||
}
|
}
|
||||||
b.mu.Unlock()
|
b.mu.Unlock()
|
||||||
|
|
||||||
err = b.udpMux.HandlePacket(buff, n, endpoint)
|
err = b.udpMux.HandleSTUNMessage(msg, endpoint)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return 0, nil, err
|
return 0, nil, err
|
||||||
}
|
}
|
||||||
|
@ -72,7 +72,7 @@ func (m *UDPMuxDefault) Type() string {
|
|||||||
return "HOST"
|
return "HOST"
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m *UDPMuxDefault) HandlePacket(p []byte, n int, addr net.Addr) error {
|
func (m *UDPMuxDefault) HandleSTUNMessage(msg *stun.Message, addr net.Addr) error {
|
||||||
|
|
||||||
udpAddr, ok := addr.(*net.UDPAddr)
|
udpAddr, ok := addr.(*net.UDPAddr)
|
||||||
if !ok {
|
if !ok {
|
||||||
@ -89,45 +89,32 @@ func (m *UDPMuxDefault) HandlePacket(p []byte, n int, addr net.Addr) error {
|
|||||||
}
|
}
|
||||||
m.addressMapMu.Unlock()
|
m.addressMapMu.Unlock()
|
||||||
|
|
||||||
// If we haven't seen this address before but is a STUN packet lookup by ufrag
|
// This block is needed to discover Peer Reflexive Candidates for which we don't know the Endpoint upfront.
|
||||||
if stun.IsMessage(p[:20]) {
|
// However, we can take a username attribute from the STUN message which contains ufrag.
|
||||||
// This block is needed to discover Peer Reflexive Candidates for which we don't know the Endpoint upfront.
|
// We can use ufrag to identify the destination conn to route packet to.
|
||||||
// However, we can take a username attribute from the STUN message which contains ufrag.
|
|
||||||
// We can use ufrag to identify the destination conn to route packet to.
|
|
||||||
msg := &stun.Message{
|
|
||||||
Raw: append([]byte{}, p[:n]...),
|
|
||||||
}
|
|
||||||
|
|
||||||
if err := msg.Decode(); err != nil {
|
attr, stunAttrErr := msg.Get(stun.AttrUsername)
|
||||||
log.Warnf("Failed to handle decode ICE from %s: %v\n", addr.String(), err)
|
if stunAttrErr == nil {
|
||||||
return err
|
ufrag := strings.Split(string(attr), ":")[0]
|
||||||
}
|
|
||||||
|
|
||||||
attr, stunAttrErr := msg.Get(stun.AttrUsername)
|
m.mu.Lock()
|
||||||
if stunAttrErr == nil {
|
if destinationConn, ok := m.conns[ufrag]; ok {
|
||||||
ufrag := strings.Split(string(attr), ":")[0]
|
exists := false
|
||||||
|
for _, conn := range destinationConnList {
|
||||||
m.mu.Lock()
|
if conn.params.Key == destinationConn.params.Key {
|
||||||
if destinationConn, ok := m.conns[ufrag]; ok {
|
exists = true
|
||||||
exists := false
|
break
|
||||||
for _, conn := range destinationConnList {
|
|
||||||
if conn.params.Key == destinationConn.params.Key {
|
|
||||||
exists = true
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if !exists {
|
|
||||||
destinationConnList = append(destinationConnList, destinationConn)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
m.mu.Unlock()
|
if !exists {
|
||||||
} else {
|
destinationConnList = append(destinationConnList, destinationConn)
|
||||||
//log.Warnf("No Username attribute in STUN message from %s\n", addr.String())
|
}
|
||||||
}
|
}
|
||||||
|
m.mu.Unlock()
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, conn := range destinationConnList {
|
for _, conn := range destinationConnList {
|
||||||
if err := conn.writePacket(p[:n], udpAddr); err != nil {
|
if err := conn.writePacket(msg.Raw, udpAddr); err != nil {
|
||||||
log.Errorf("could not write packet: %v", err)
|
log.Errorf("could not write packet: %v", err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -79,34 +79,23 @@ func (m *UniversalUDPMuxDefault) Type() string {
|
|||||||
return "SRFLX"
|
return "SRFLX"
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m *UniversalUDPMuxDefault) HandlePacket(p []byte, n int, addr net.Addr) error {
|
func (m *UniversalUDPMuxDefault) HandleSTUNMessage(msg *stun.Message, addr net.Addr) error {
|
||||||
if stun.IsMessage(p[:20]) {
|
|
||||||
msg := &stun.Message{
|
|
||||||
Raw: append([]byte{}, p[:n]...),
|
|
||||||
}
|
|
||||||
|
|
||||||
if err := msg.Decode(); err != nil {
|
udpAddr, ok := addr.(*net.UDPAddr)
|
||||||
log.Warnf("Failed to handle decode ICE from %s: %v\n", addr.String(), err)
|
if !ok {
|
||||||
// todo proper error
|
// message about this err will be logged in the UDPMux
|
||||||
return nil
|
return nil
|
||||||
}
|
|
||||||
|
|
||||||
udpAddr, ok := addr.(*net.UDPAddr)
|
|
||||||
if !ok {
|
|
||||||
// message about this err will be logged in the UDPMux
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
if m.isXORMappedResponse(msg, udpAddr.String()) {
|
|
||||||
err := m.handleXORMappedResponse(udpAddr, msg)
|
|
||||||
if err != nil {
|
|
||||||
log.Debugf("%w: %v", errors.New("failed to get XOR-MAPPED-ADDRESS response"), err)
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
return m.UDPMuxDefault.HandlePacket(p, n, addr)
|
|
||||||
|
if m.isXORMappedResponse(msg, udpAddr.String()) {
|
||||||
|
err := m.handleXORMappedResponse(udpAddr, msg)
|
||||||
|
if err != nil {
|
||||||
|
log.Debugf("%w: %v", errors.New("failed to get XOR-MAPPED-ADDRESS response"), err)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
return m.UDPMuxDefault.HandleSTUNMessage(msg, addr)
|
||||||
}
|
}
|
||||||
|
|
||||||
// isXORMappedResponse indicates whether the message is a XORMappedAddress and is coming from the known STUN server.
|
// isXORMappedResponse indicates whether the message is a XORMappedAddress and is coming from the known STUN server.
|
||||||
|
Reference in New Issue
Block a user