Forum

NAT Fix -- Solves the "connection accepted" issue

Post tutorials on how to do certain tasks within game or engine code here.

Moderator: InsideQC Admins

NAT Fix -- Solves the "connection accepted" issue

Postby Baker » Fri Dec 11, 2009 8:32 am

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.
User avatar
Baker
 
Posts: 3666
Joined: Tue Mar 14, 2006 5:15 am

Postby Team Xlink » Fri Dec 11, 2009 11:08 pm

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.
Team Xlink
 
Posts: 368
Joined: Thu Jun 25, 2009 4:45 am
Location: Michigan

Postby Baker » Sat Dec 12, 2009 12:02 am

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].
User avatar
Baker
 
Posts: 3666
Joined: Tue Mar 14, 2006 5:15 am

Postby mh » Sat Dec 12, 2009 2:19 am

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
User avatar
mh
 
Posts: 2292
Joined: Sat Jan 12, 2008 1:38 am

Postby Team Xlink » Sat Dec 12, 2009 2:20 am

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.
Team Xlink
 
Posts: 368
Joined: Thu Jun 25, 2009 4:45 am
Location: Michigan

Reasoning

Postby Spike » Sat Dec 12, 2009 10:51 am

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.
Spike
 
Posts: 2883
Joined: Fri Nov 05, 2004 3:12 am
Location: UK

Postby frag.machine » Sat Dec 12, 2009 2:55 pm

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)
User avatar
frag.machine
 
Posts: 2078
Joined: Sat Nov 25, 2006 1:49 pm

Postby r00k » Sat Dec 12, 2009 3:58 pm

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... ?
r00k
 
Posts: 1110
Joined: Sat Nov 13, 2004 10:39 pm

Postby Baker » Sat Dec 12, 2009 4:22 pm

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).
User avatar
Baker
 
Posts: 3666
Joined: Tue Mar 14, 2006 5:15 am

Postby r00k » Sun Dec 13, 2009 9:13 am

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?
r00k
 
Posts: 1110
Joined: Sat Nov 13, 2004 10:39 pm

Postby Team Xlink » Sun Dec 13, 2009 5:00 pm

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.
Team Xlink
 
Posts: 368
Joined: Thu Jun 25, 2009 4:45 am
Location: Michigan

Postby r00k » Mon Dec 14, 2009 6:12 pm

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!
r00k
 
Posts: 1110
Joined: Sat Nov 13, 2004 10:39 pm

Postby Baker » Sat Aug 21, 2010 8:32 pm

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 ..
User avatar
Baker
 
Posts: 3666
Joined: Tue Mar 14, 2006 5:15 am

Postby mh » Sat Aug 21, 2010 8:49 pm

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
User avatar
mh
 
Posts: 2292
Joined: Sat Jan 12, 2008 1:38 am

Postby r00k » Mon Aug 23, 2010 6:59 am

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;
         }
      }
   }
r00k
 
Posts: 1110
Joined: Sat Nov 13, 2004 10:39 pm

Next

Return to Programming Tutorials

Who is online

Users browsing this forum: No registered users and 1 guest