Beispiel #1
0
        public static void Main(string[] args)
        {
            string cmdLine = Environment.GetCommandLineArgs()[0];

            if (args.Length < 3)
            {
                Console.WriteLine("Usage: " + cmdLine + " <proxy port> <gameserver ip> <gameserver port>");
                Environment.Exit(1);
            }
            IPAddress targetIP;
            int       targetPort;
            int       localPort;

            if (!int.TryParse(args[0], out localPort) || localPort < 1 || localPort > 65535)
            {
                Console.WriteLine("Invalid proxy port!");
                Environment.Exit(2);
            }
            if (!IPAddress.TryParse(args[1], out targetIP))
            {
                Console.WriteLine("Invalid gameserver IP address!");
                Environment.Exit(3);
            }
            if (!int.TryParse(args[2], out targetPort) || targetPort < 1 || targetPort > 65535)
            {
                Console.WriteLine("Invalid gameserver port!");
                Environment.Exit(4);
            }

            EndPoint requestingEP = Init(localPort, targetIP, targetPort);

            if (requestingEP == null)
            {
                Console.WriteLine("Cannot bind proxy port!");
                Environment.Exit(4);
            }

            Console.WriteLine(
                "iptables -t nat -I PREROUTING -p udp -d {0} --dport {1} -m u32 --u32  '0>>22&0x3C@8=0xFFFFFFFF && 0>>22&0x3C@12=0x54536F75 && 0>>22&0x3C@16=0x72636520 && 0>>22&0x3C@20=0x456E6769 && 0>>22&0x3C@24=0x6E652051 && 0>>22&0x3C@28=0x75657279' -j REDIRECT --to-port {2}",
                args[1], args[2], args[0]
                );

            // Give our time trackers an initial time
            lastInfoTime    = DateTime.Now - TimeSpan.FromSeconds(30);
            lastPlayersTime = DateTime.Now - TimeSpan.FromSeconds(30);
            lastRulesTime   = DateTime.Now - TimeSpan.FromSeconds(30);
            lastPrint       = DateTime.Now;

            //// Main query receiving loop
            while (true)
            {
                byte[] reqPacket = new byte[maxPacket];
                try
                {
                    publicSock.ReceiveFrom(reqPacket, ref requestingEP);
                }
                catch (Exception)
                {
                    continue;
                }

                ThreadWorkerInfo info = new ThreadWorkerInfo();
                info.reqPacket    = reqPacket;
                info.requestingEP = requestingEP;
                ThreadPool.QueueUserWorkItem(HandleQuery, info);

                if (DateTime.Now.AddSeconds(-10) >= lastPrint)
                {
                    int workerThreads = 0, completionPortThreads = 0;
                    ThreadPool.GetAvailableThreads(out workerThreads, out completionPortThreads);

                    Console.WriteLine(
                        "{0}/{1} info queries and {2}/{3} other queries in last {4} seconds, availability {5}/{6}",
                        recvInfoQueries, infoQueries, recvOtherQueries, otherQueries,
                        (DateTime.Now - lastPrint).Seconds,
                        workerThreads, completionPortThreads
                        );

                    Interlocked.Exchange(ref infoQueries, 0);
                    Interlocked.Exchange(ref otherQueries, 0);
                    Interlocked.Exchange(ref recvInfoQueries, 0);
                    Interlocked.Exchange(ref recvOtherQueries, 0);
                    lastPrint = DateTime.Now;
                }
            }
        }
Beispiel #2
0
        public static void HandleQuery(Object data)
        {
            ThreadWorkerInfo info         = (ThreadWorkerInfo)data;
            EndPoint         requestingEP = info.requestingEP;

            byte[] reqPacket = info.reqPacket;

            switch (reqPacket[4])
            {
            case 0x54:                     // Info Queries
            {
                Interlocked.Increment(ref infoQueries);

                if (lastInfoTime + TimeSpan.FromSeconds(5) <= DateTime.Now)
                {
                    if (updateInfoCacheLock.WaitOne(100))
                    {
                        // Update our cached values
                        if (!UpdateCache(reqPacket[4]))
                        {
                            return;
                        }

                        lastInfoTime = DateTime.Now;
                        updateInfoCacheLock.ReleaseMutex();
                    }
                }

                // If we get this far, we send our cached values.
                try
                {
                    infoCacheLock.AcquireReaderLock(100);

                    try
                    {
                        publicSock.SendTo(infoCache, requestingEP);
                        Interlocked.Increment(ref recvInfoQueries);
                    }
                    catch
                    {
                        return;
                    }
                    finally
                    {
                        infoCacheLock.ReleaseReaderLock();
                    }
                }
                catch (ApplicationException)
                { }

                break;
            }

            case 0x55:                     // Player list
            {
                Interlocked.Increment(ref otherQueries);

                if (!ChallengeIsValid(reqPacket))
                {
                    // We check that the client is using the correct challenge code
                    try
                    {
                        publicSock.SendTo(BuildRequest(0x41), requestingEP);
                    }
                    catch
                    {
                        return;
                    }

                    // We'll send the client the correct challenge code to use.
                    break;
                }

                if (lastPlayersTime + TimeSpan.FromSeconds(3) <= DateTime.Now)
                {
                    if (updatePlayerCacheLock.WaitOne(100))
                    {
                        if (!UpdateCache(reqPacket[4]))
                        {
                            return;
                        }

                        lastPlayersTime = DateTime.Now;
                        updatePlayerCacheLock.ReleaseMutex();
                    }
                }

                try
                {
                    playerCacheLock.AcquireReaderLock(100);

                    bool success = true;
                    for (int i = 0; i < playerCache.Length; i++)
                    {
                        try
                        {
                            publicSock.SendTo(playerCache[i], requestingEP);
                        }
                        catch
                        {
                            success = false;
                            break;
                        }
                    }

                    if (success)
                    {
                        Interlocked.Increment(ref recvOtherQueries);
                    }

                    playerCacheLock.ReleaseReaderLock();
                }
                catch (ApplicationException)
                { }

                break;
            }

            case 0x56:                     //Rules list
            {
                Interlocked.Increment(ref otherQueries);

                if (!ChallengeIsValid(reqPacket))
                {
                    try
                    {
                        publicSock.SendTo(BuildRequest(0x41), requestingEP);
                    }
                    catch
                    {
                        return;
                    }
                    break;
                }

                if (lastRulesTime + TimeSpan.FromSeconds(10) <= DateTime.Now)
                {
                    if (updateRulesCacheLock.WaitOne(100))
                    {
                        if (!UpdateCache(reqPacket[4]))
                        {
                            return;
                        }

                        lastRulesTime = DateTime.Now;
                        updateRulesCacheLock.ReleaseMutex();
                    }
                }

                try
                {
                    rulesCacheLock.AcquireReaderLock(100);

                    bool success = true;
                    for (int i = 0; i < rulesCache.Length; i++)
                    {
                        try
                        {
                            publicSock.SendTo(rulesCache[i], requestingEP);
                        }
                        catch
                        {
                            success = false;
                            break;
                        }
                    }

                    if (success)
                    {
                        Interlocked.Increment(ref recvOtherQueries);
                    }

                    rulesCacheLock.ReleaseReaderLock();
                }
                catch (ApplicationException)
                { }

                break;
            }

            case 0x57:                     // Challenge request
            {
                Interlocked.Increment(ref otherQueries);

                try
                {
                    // Send challenge response.
                    publicSock.SendTo(BuildRequest(0x41), requestingEP);
                    Interlocked.Increment(ref recvOtherQueries);
                }
                catch
                {
                    return;
                }
                break;
            }
            }

            return;
        }