0

I have successfully created a client/server TCP encrypted proxy server in C, all from scratch. As part of generating a unique IV for each connection, I am using the current time and the client's source port as seeds. These values are available from the client using:

getsockname(stack[i][1], (struct sockaddr*)&source, &sockaddr_size);

and from the server using:

getpeername(stack[i][0], (struct sockaddr*)&source, &sockaddr_size);

I am using these 2 values as seeds, as I do not want to transmit the seed in a packet to minimize any overhead, however small as it may be.

However, I also want to get the actual (negotiated) TCP port the server is using. When I invoke getpeername() from the client side, I can only get the initial TCP listening port of the server (e.g. 443). I cannot find anywhere in the documentation how I can get the actual (negotiated) TCP server port. This must be available somewhere, otherwise how is the data transmitted between the 2 parties?

I have read all documentation of the functions, and looked up the question online, to no avail.

Can anyone please help with the above?

2
  • Make a minimal reproducible example. We don't know what stack, or source is, for example. Commented May 16 at 6:54
  • stack is simply an array the holds the socket file descriptors for the 2 connections (incoming and outgoing). uint16_t stack[256][2]; source is a struct of type sockaddr_in which is required by the the functions to save the information for each connection. socklen_t sockaddr_size = sizeof(struct sockaddr_in); struct sockaddr_in source; memset(&source, 0, sizeof(source)); source.sin_family = AF_INET; Commented May 16 at 7:02

1 Answer 1

1

However I also want to get the actual (negotiated) TCP port the server is using. When I envoke getpeername from the client side I can only get the initial TCP listening port of the server (e.g. 443).

It is also 443.

ARPANET's original NCP did have a separate "negotiation" (ICP) that would move the connection to a dedicated server-side port. TCP does not. Because each connection has two port numbers (server-side and client-side), there is no need to negotiate a new server-side port because the full <src,dst> can already be used to distinguish between connections.

If you look at the raw TCP/IP packets seen in Wireshark – and compare against e.g. netstat -n on either the server or the client – you will see that all packets are sent between client_port and server:443, and therefore the getsockname/getpeername result (and the netstat output) is accurate.

The only similar cases of "new port per client" are FTP (which actually doesn't do that either; the control connection still remains on port 21, whereas the data ports correspond to brand new TCP connections) and TFTP (which is UDP and generally just weird).

As part of generating a unique IV for each connection, I am using current time and the client's source port as seeds

That's not a very good seed. Some operating systems use incremental source port numbers; if two Windows PCs connected to your server at once, they could easily both have the same timestamp and the same source port.

Use a proper CSPRNG (your cryptography library almost certainly has one) and use OS-provided randomness sources (your cryptography library will likely do so automatically), such as getentropy() or BCryptGenRandom().

At the same time, if you "do not want to transmit" the seed, then this is also not a very good seed. Computer clocks drift (even between NTP syncs) and the timestamp may differ. Networks have latency (packet delivery is non-instant) and the send & receive timestamps may differ. If you try to account for this by reducing timestamp precision, the seed will become even worse quality than it already is.

Also, many clients are behind SNAT gateways which randomize source ports, and the client won't have any way to know if its packets have been rewritten mid-flight to have a different source port, therefore the client's getsockname() and the server's getpeername() will differ. (But this has nothing to do with the 1st part of this answer; this is something that packet-rewriting gateways impose, and not something TCP does explicitly.)

Sign up to request clarification or add additional context in comments.

1 Comment

thanks again for your comment. the test router is currently connected to a single PC which uses incremental ports each time. the time synchronization issue has been (partially) resolved by taking the time since epoch >>5. These values are fed to a XOR RNG from the paper of George Marsaglia. However your comments regarding multiple devices connected have been duly noted and another source of randomness will need to added - hence the real reason this question was posted. The encryption used is chacha20 also writen from scratch.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.