NAT Fix -- Solves the "connection accepted" issue

Post tutorials on how to do certain tasks within game or engine code here.
Baker
Posts: 3666
Joined: Tue Mar 14, 2006 5:15 am

NAT Fix -- Solves the "connection accepted" issue

Post by Baker »

In cl_main.c (<--- not platform specific! Fix on any platform easy.) :
/*
=====================
CL_EstablishConnection

Host should be either "local" or a net address to be passed on
=====================
*/
void CL_EstablishConnection (char *host)
{
if (cls.state == ca_dedicated)
return;

if (cls.demoplayback)
return;

CL_Disconnect ();

cls.netcon = NET_Connect (host);
if (!cls.netcon)
Host_Error ("CL_Connect: connect failed\n");
Con_DPrintf ("CL_EstablishConnection: connected to %s\n", host);

cls.demonum = -1; // not in the demo loop now
cls.state = ca_connected;
cls.signon = 0; // need all the signon messages before playing

MSG_WriteByte (&cls.message, clc_nop); // ProQuake NAT Fix

}
The notes and many changes to the network code in ProQuake make this difficult to isolate. I remembered seeing this singular change in the Q2K4 engine's source recently examinating Quake2 model support.

In both ProQuake and JoeQuake there about 3-4 changes marked NAT fix. Not sure why.

I was able to verify that this change alone solves the issue. Adding it in resolves the "connection accepted situation" and commenting it out generates "connection accepted". Despite all the places marked NAT fix in the ProQuake and JoeQuake source code, this single change above appears to be the only part necessary.

And the mystery of what exactly is required to do the NAT fix has boggled people such as Entar, aguirRe, myself and aggravated a lot of PSP developers and Wii people and so forth because winquake/glquake ports invariably inherit this problem.
Team Xlink
Posts: 368
Joined: Thu Jun 25, 2009 4:45 am
Location: Michigan

Post by Team Xlink »

This has caused me so much frustration and has torn me to shreds trying to figure this out.

Baker, your are a life saver, I don't know how I can thank you enough for this.

I have went through ProQuakes, and JoeQuakes Source countless times and have tried so many different things, I can't thank you enough for what you have just done for me.


Thank you.
Baker
Posts: 3666
Joined: Tue Mar 14, 2006 5:15 am

Post by Baker »

Team Xlink wrote:This has caused me so much frustration and has torn me to shreds trying to figure this out.

Baker, your are a life saver, I don't know how I can thank you enough for this.

I have went through ProQuakes, and JoeQuakes Source countless times and have tried so many different things, I can't thank you enough for what you have just done for me.


Thank you.
It frustrated me to death in the past as well.

No need to thank me --- you solved my frustration with never being able to figure out how the hell to compile for the PSP [which led to me finally understanding how to use cygwin and then compiling FlashQuake].
mh
Posts: 2292
Joined: Sat Jan 12, 2008 1:38 am

Post by mh »

One question about this - it's a protocol change isn't it? So one can't just add it to any engine in other words cos a client that has it would need a server that also has it?
We had the power, we had the space, we had a sense of time and place
We knew the words, we knew the score, we knew what we were fighting for
Team Xlink
Posts: 368
Joined: Thu Jun 25, 2009 4:45 am
Location: Michigan

Post by Team Xlink »

mh wrote:One question about this - it's a protocol change isn't it? So one can't just add it to any engine in other words cos a client that has it would need a server that also has it?
I think it is only for the client because the Nat fix fixes the problem on the client side where the client doesn't complete the handshake.

So, Client Side I believe.
Spike
Posts: 2914
Joined: Fri Nov 05, 2004 3:12 am
Location: UK
Contact:

Reasoning

Post by Spike »

Reasoning:

A NAT will route packets from the client to the server and back.
If you have multiple clients/computers on the inside of the NAT and a new packet arrives, the NAT is only able to route the packet to the client computer if it knows which client computer it is meant to be sent to.
With the NQ protocols, the server listens on one port, and opens a new port for each client. It also initiates the connection on that new port.
This means that the client can begin connecting to the server, but once it has got a connection, the server starts sending packets to the router, and the router receives packets which it does not know how to route.
The solution is to send a dummy packet from the client's port to the server's new port for that client, thus opening a route on the client's NAT which basically tells the router how to route packets properly.

Complications:
Broken routers:
There are some routers which are so mind numbingly stupid that they close the connection again after 2 mins, and which will only be reopened by a client->server packet. NQ clients only send packets on receipt of a packet from a server, and in this case, no NAT fix will save you. Such routers are of course absurdly broken. A work around is to just send dummy nop packets (or even corrupt ones) every 2 mins, or each time you lose your connection, lol.
Server NATS:
Additionally, this is a client-side NAT fix only. For servers behind a NAT or router, the server will listen on a known port for new clients, and then auto-allocate a new port for each client. You can forward the known port, but the port-per-client ports are generated almost at random, depending on the operating system. Its generally a bad plan to route 4096+ to that server... The solution to this is to change port allocation to a known range, or to rewrite the network code to always use a single port for every client. This is probably why there are multiple chunks of proquake code marked as NAT fixes, perhaps.

Alternatives:
As mentioned above, the server can be modified to use a single serverside port. This provides a NAT fix for all clients' NATS as well as the server. But its a lot of code. FTE does this, as does DP, but it doesn't fix the client if they connect elsewhere, of course.

You don't have to send a meaningful packet. You could send a 'corrupt' packet to the server, so long as you send at least one udp payload byte from the correct client port to the correct server port. The server does not need to parse it, it needs merely to be routed by the client's NAT.
Generally UDP over wireless is quite lossy, so you may wish to send a couple of packets (with a time gap) if the client is on a wifi connection before the router, but over ethernet more than 1 is overkill, its not really possible to tell however.
frag.machine
Posts: 2126
Joined: Sat Nov 25, 2006 1:49 pm

Post by frag.machine »

mh wrote:One question about this - it's a protocol change isn't it? So one can't just add it to any engine in other words cos a client that has it would need a server that also has it?
Not really. AFAIK this just adds an already existing (and harmless, since there's no server behavior for client nop's) message to the protocol handshake so the connection is kept alive. In theory, the client could send periodically a nop message to the server without breaking compatibility.
I know FrikaC made a cgi-bin version of the quakec interpreter once and wrote part of his website in QuakeC :) (LordHavoc)
r00k
Posts: 1111
Joined: Sat Nov 13, 2004 10:39 pm

Post by r00k »

Looking closely it seems that the nat fix tells outbound packets to new connecting clients to wait until in datagram_getmessage

Code: Select all

		// joe: NAT fix from ProQuake
		if (sock->net_wait)
		{
			sock->addr = readaddr;
			strcpy (sock->address, sfunc.AddrToString(&readaddr));
			sock->net_wait = false;
		}

where it updates the port... ?
Baker
Posts: 3666
Joined: Tue Mar 14, 2006 5:15 am

Post by Baker »

There does happen to be a server-side NAT fix written by Yugo2Heck:

http://quakeone.com/q1files/downloads/l ... -ssp.patch
http://quakeone.com/forums/quake-talk/q ... #post11770

Back in the "older" days (2004-2006), I recommend someone with trouble connecting to try to connect to quake.ihoc.net to see if they could connect and if so, I knew they weren't using an NAT fixed client.

And you'd see a lot of "I can only connect to IHOC! I can't connect to any other server, please help OMG!".

However the best server answer would be to do whatever DarkPlaces and FTE do to use a single port. It would make server setup much easier for server hosts unfamiliar with NQ, which typically run into firewall issues because only post 26000 is open.
r00k wrote:Looking closely it seems that the nat fix tells outbound packets to new connecting clients to wait until in datagram_getmessage

Code: Select all

		// joe: NAT fix from ProQuake
		if (sock->net_wait)
		{
			sock->addr = readaddr;
			strcpy (sock->address, sfunc.AddrToString(&readaddr));
			sock->net_wait = false;
		}

where it updates the port... ?
@Rook: I don't claim to understand the networking code in code all that well, but I do know I didn't need to use the above code you quoted code to do a client-side fix for GLQuake. Just the one yellow line of code in post #1. I tested the NAT-fixed GLQuake against both ProQuake servers and against non-ProQuake servers (Clan Rum) and the single line of code allowed me to connect to both of them without "connection accepted" (and commenting out the single line would cause the "connection accepted" problem to come back).
r00k
Posts: 1111
Joined: Sat Nov 13, 2004 10:39 pm

Post by r00k »

Hmm, that clc_nop just sends an emtpy packet.
Curious though if yugo's patch will still allow two machines on same network to connect to the same server?
Team Xlink
Posts: 368
Joined: Thu Jun 25, 2009 4:45 am
Location: Michigan

Post by Team Xlink »

r00k wrote:Hmm, that clc_nop just sends an emtpy packet.
Curious though if yugo's patch will still allow two machines on same network to connect to the same server?
Correct me if I am wrong but isn't this already possible?

I swear I have done this.


EDIT: My mistakem it turns out I did this when I was hosting a public server so I had multiple clients connect to it. Sorry, about that.
r00k
Posts: 1111
Joined: Sat Nov 13, 2004 10:39 pm

Post by r00k »

I meant would this patch DISALLOW multiple connections from the SAME IP address? :|

The client re-init's the socket after connection accepted, then the server scans the connected client's ip address, then reconnects the proper port. If two players have same IP but diff ports there may be a conflict. Hmm, or maybe two people sharing the same pov :O lol!
Baker
Posts: 3666
Joined: Tue Mar 14, 2006 5:15 am

Post by Baker »

Meanwhile, I might add to this thread that this NAT fix is good but not complete. It isn't enough in some situations, but regardless is a good improvement over not having it.

A European NetQuake player found a sitation where this NAT fix was insufficient in DirectQ and still got connection accepted.

MH rummaged through ProQuake's code some more and added a 2nd chunk and maybe 3rd chunk of an NAT fix.
The night is young. How else can I annoy the world before sunsrise? 8) Inquisitive minds want to know ! And if they don't -- well like that ever has stopped me before ..
mh
Posts: 2292
Joined: Sat Jan 12, 2008 1:38 am

Post by mh »

I basically copied in all of ProQuake's net_dgrm.c :D

Not too certain exactly what the required code is, but it seems to be that this chunk is key:

Code: Select all

	// joe, from ProQuake: make NAT work by opening a new socket
	if (sock->mod == MOD_PROQUAKE && sock->mod_version >= 34)
	{
		clientsock = dfunc.OpenSocket(0);
		if (clientsock == -1)
			goto ErrorReturn;
		dfunc.CloseSocket(newsock);
		newsock = clientsock;
		sock->socket = newsock;
	}
We had the power, we had the space, we had a sense of time and place
We knew the words, we knew the score, we knew what we were fighting for
r00k
Posts: 1111
Joined: Sat Nov 13, 2004 10:39 pm

Post by r00k »

mh wrote:I basically copied in all of ProQuake's net_dgrm.c :D

Not too certain exactly what the required code is, but it seems to be that this chunk is key:

Code: Select all

	// joe, from ProQuake: make NAT work by opening a new socket
	if (sock->mod == MOD_PROQUAKE && sock->mod_version >= 34)
	{
		clientsock = dfunc.OpenSocket(0);
		if (clientsock == -1)
			goto ErrorReturn;
		dfunc.CloseSocket(newsock);
		newsock = clientsock;
		sock->socket = newsock;
	}
wait a sec now MOD_PROQUAKE fakes a pq client (to a pq server) and the mod_version is any pq client >= 3.40, all that mumbo jumbo with sock->mod can be nixed. It's just JPG's way of doing a cls.protocol at the socket level. Primarily used for precise angle read/writes, but later used for cheatfree stuff. What proquake servers do is first connect on one socket, then opens another socket after initial signon.

i removed all that net_wait stuff an djust use yugo's code in _Datagram_CheckNewConnections

Code: Select all

	if ((control & (~NETFLAG_LENGTH_MASK)) != NETFLAG_CTL)
	{
		/* Yugo2Heck: ProQuake 3.4 (and up) clients close their request socket
		** and make a new socket for the session.  This means we
		** connected back to the wrong socket when accepting the
		** connection.  So we look for a "bogus" request packet 
		** from that client on a different port, and re-connect 
		** back to that port instead.
		*/
		for (s = net_activeSockets; s; s = s->next)
		{
			if (s->driver != net_driverlevel)
				continue;

			ret = dfunc.AddrCompare(&clientaddr, &s->addr);
			if (ret == 1)
			{	//same client, different port: reconnect back
				dfunc.Connect(s->socket, &clientaddr);								
				return NULL;
			}
		}
	}
Post Reply