简体   繁体   中英

UDP Source port different on client getsocketname() and server recv()

Hi my question is simple:

I try to establish an UDP connection via a TCP connection (Because multiple clients are connected via multiple channels to the server and I want to identifiy same clients via the main TCP connection)

I did this by creating a TCP and UDP Socket on the client and transmit the local UDP port assigned randomly by the OS via TCP to the server. (On Windows I get the port after sendto() via getsocketname()). On the server I use this port to send UDP packets to this exact client. Unfortunately the port i really have to send to is different to the local port i sent to the server.

For example:

My Client gets a local UDP port 56423 assigned. Sends it to my Server via the established TCP connection. Server tries to send UDP Packets to that port -> Failed. When i use the standard way of retreiving the port on the server via recv() on the UDP socket it reports a source port of 30299. (I have to send UDP packets in advance for that info, but I want to avoid implementing a UDP connection handshake)

How can this be?

To my understanding UDP just has a destination port and a source port. So it should work by sending the client local port to the server. Can there possibly be proxy services inbetween that use alternate ports?

Edit: Some code:

On the client: (s32 = int, c8 = char)

if(m_WinSock == INVALID_SOCKET)
    return;

struct sockaddr_storage addr;
s32 len = sizeof(sockaddr);

getsockname(m_WinSock, (SOCKADDR*)&addr, &len);
c8 ipstr[INET6_ADDRSTRLEN + 1];
s32 port;
if(addr.ss_family == AF_INET)
{
    struct sockaddr_in *s = (struct sockaddr_in *)&addr;
    m_uLocalPort = ntohs(s->sin_port);
    inet_ntop(AF_INET, &s->sin_addr, ipstr, sizeof ipstr);
}
else
{ // AF_INET6
    struct sockaddr_in6 *s = (struct sockaddr_in6 *)&addr;
    m_uLocalPort = ntohs(s->sin6_port);
    inet_ntop(AF_INET6, &s->sin6_addr, ipstr, sizeof ipstr);
}

m_uLocalPort is transmitted via TCP after that.

On the server:

    SOCKADDR_IN address;
    ZeroMemory(&address, sizeof(address));
    address.sin_addr = addrin;
    address.sin_port = htons((u16)remoteport);
    address.sin_family = AF_INET;

remoteport is the port sent by the client.

Using this code on the server after sending a packet from the client:

struct sockaddr_storage addr;
s32 len = sizeof(sockaddr);
s32 bytes = recvfrom(m_WinSock, m_RecvBuffer, NET_MAX_UDP_SIZE, 0, (SOCKADDR*)&addr, &len);
m_RecvAddress = *(struct sockaddr_in *)&addr;

s32 port = ntohs(m_RecvAddress.sin_port);
printf("recv from port %i\n", port);

I receive a totally different port.

This is not a reliable approach for the problem. For example, NAT can get in the way and remap your port or even the local ip seen from your client. You may also need to do udp hole punching.

The proper way is not assume any co-relation on tcp and udp - they are different pipes.

EDIT: For example:

  1. Client connect() to server's public tcp interface.
  2. Authentication
  3. Server sends an an authentication code (cookie) to the client.
  4. Client sendto() server's public udp interface, with the cookie.
  5. Server gets sockaddr from recvfrom() .
  6. Server co-relation such sockaddr to the revalent tcp connection, using the cookie. Optionally check/restrict the ip to prevent bull force by other.
  7. That is, now you have a pair of connection - an accepted tcp socket along with sockaddr for udp communication.

PS. You may also want to do some encryption on the handshake, but that's out of the question's scope.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM