Ok here is the whole entire thing:
Overview:- Python client (to be compiled and started with War2Combat)
- PHP and MySQL to save NAT stats (nat_stats.php)
- JSON sample of player IP listing (player_ips.php)
Some Notes:- nat_stats.php only saves one stat per IP address, and never updates it (unless the row is deleted, then it would update)
- All MySQL queries are sanitized using PDO to bind params
- The python client checks STUN and if it gets symmetric, it quits. Else it will download IPs from website and then send UDP to each of them from its game port which it gets from registry. After blasting every IP with a small UDP packet, it waits 10 seconds then repeats
@iL its up to you now!
Install Instructions:1. Setup player_ips.php (see source below)
- You will have to populate it with real player IPs, preferably in the format that I gave so that we don't have to change the Python code
- Also, you should have it output all server IPs as well - server.war2.ru, backup that way the server will not send the "port closed" message
2. Create MySQL table for nat_stats.php (see source below)
- I gave you the SQL to run to create the table
3. Add nat_stats.php to war2.ru server (source below)
- You will need to update the username, password, and database name, everything else should be good
4. Update Python script and change the 2 links to war2.info, replace with war2.ru
5.Compile the Python to EXE:
- Download Python 2.7
https://www.python.org/downloads/- Install pip (package manager)
https://pip.pypa.io/en/stable/installing/- Install libraries used:
- C:\Python27\Scripts\pip.exe install requests
- C:\Python27\Scripts\pip.exe install pystun
- C:\Python27\Scripts\pip.exe install json
- C:\Python27\Scripts\pip.exe install time
- C:\Python27\Scripts\pip.exe install _winreg
- C:\Python27\Scripts\pip.exe install socket
- (some of these might have already shipped with Python, I forget)
- C:\Python27\Scripts\pip.exe install pyinstaller
Compile to EXE:
- C:\Python27\python.exe udp_hole_punch.py
- EXE will be saved to dist/udp_hole_punch/udp_hole_punch.exe
6. Add new Python EXE to War2Combat and ship the update
7. Profit
- Hosting fixed
Python UDP hole punch client -- this can be compiled to EXE and started with War2Combat:
import _winreg
import stun
import requests
import socket
import time
import json
def get_war2_port():
# Open the key and return the handle object
hKey = _winreg.OpenKey(_winreg.HKEY_CURRENT_USER, "Software\Battle.net\Configuration")
# Read the value
try:
result = _winreg.QueryValueEx(hKey, "Game Data Port")
# If not found, set to default
except Exception as e:
print e
result = [6112]
# Return port
return result[0]
war2_port = get_war2_port()
nat_type, external_ip, external_port = stun.get_ip_info("0.0.0.0", war2_port)
req = requests.get('
https://war2.info/nat_stats.php?nat_type=' + str(nat_type))
if nat_type != "Sytmmetric NAT":
while True:
time.sleep(10)
req = requests.get('
https://war2.info/player_ips.php')
json_obj = json.loads(req.content)
player_ip_list = json_obj["player_ips"]
print player_ip_list
for player_ip in player_ip_list:
# Target host is IP of player you want to be able to join your game
target_host = player_ip
# create a socket object
client = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
client.bind(('0.0.0.0', war2_port))
# send some data
client.sendto("For the Alliance", (target_host, war2_port))
print "Sent data to " + str(player_ip) + " on port " + str(war2_port)
player_ips.php<?php
// iL, you will have to populate this with actual player IPs for each page load
echo '{"player_ips": ["1.1.1.1", "2.2.2.2", "3.3.3.3"]}';
?>
Create nat_stats table for nat_stats.php, run this SQL:CREATE TABLE nat_stats (
id INT(11) UNSIGNED AUTO_INCREMENT PRIMARY KEY,
ip_address VARCHAR(30) NOT NULL,
nat_type VARCHAR(30) NOT NULL
)
nat_stats.php source:<?php
$ip_address = $_SERVER['REMOTE_ADDR'];
$nat_type = $_GET["nat_type"];
$servername = "localhost";
$username = "user";
$password = "pass!";
$dbname = "db";
try {
$conn = new PDO("mysql:host=$servername;dbname=$dbname", $username, $password);
$conn->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
$stmt = $conn->prepare("SELECT * FROM nat_stats WHERE ip_address = :ip_address");
$stmt->bindParam(':ip_address', $ip_address);
$stmt->execute();
// set the resulting array to associative
$result = $stmt->setFetchMode(PDO::FETCH_ASSOC);
$row = $stmt->fetch();
$previous_nat_type = $row["nat_type"];
}
catch(PDOException $e) {
echo "Error: " . $e->getMessage();
}
$conn = null;
// If we have never seen this IP before, save it in the database
if (isset($previous_nat_type)) {
echo "NAT Type already saved for this IP";
} else {
$conn = new PDO("mysql:host=$servername;dbname=$dbname", $username, $password);
$stmt = $conn->prepare("INSERT INTO nat_stats(ip_address, nat_type)
VALUES(:ip_address, :nat_type)");
$stmt->bindParam(':ip_address', $ip_address);
$stmt->bindParam(':nat_type', $nat_type);
$stmt->execute();
$conn = null;
echo "Saved NAT Type";
}
?>