Add IPv6 support

This commit is contained in:
Mr.Robot
2025-10-23 18:53:41 +08:00
committed by GitHub
parent 2b0dea70f5
commit 7f96a2d5b7
5 changed files with 29 additions and 13 deletions

View File

@@ -305,6 +305,10 @@ To enable support for multiple users perform the steps below:
</details>
### Step 7 [OPTIONAL]: Enable IPv6
To enable support for IPv6 set the environment variable ``ZOFFLINE_SERVER_HOST`` or use the script ``run_ipv6.bat``.
### Extra features
<details><summary>Ghosts</summary>

View File

@@ -1,5 +1,6 @@
import dns.resolver
import socketserver
import os
class DNSQuery:
def __init__(self, data):
@@ -55,8 +56,8 @@ class DNSServer:
def addname(self, name, ip):
DNSServer.namemap[name] = ip
def start(self):
HOST, PORT = "0.0.0.0", self.port
socketserver.ThreadingUDPServer.allow_reuse_address = True
HOST = os.environ.get('ZOFFLINE_SERVER_HOST', '')
PORT = self.port
server = socketserver.ThreadingUDPServer((HOST, PORT), DNSUDPHandler)
server.serve_forever()

3
scripts/run_ipv6.bat Normal file
View File

@@ -0,0 +1,3 @@
@ECHO OFF
SET ZOFFLINE_SERVER_HOST=::
python ..\standalone.py

View File

@@ -271,12 +271,12 @@ class TCPHandler(socketserver.BaseRequestHandler):
details1 = msg.udp_config.relay_addresses.add()
details1.lb_realm = udp_node_msgs_pb2.ZofflineConstants.RealmID
details1.lb_course = 6 # watopia crowd
details1.ip = '127.0.0.1' if self.request.getpeername()[0] == '127.0.0.1' else zo.server_ip
details1.ip = self.request.getpeername()[0] if self.request.getpeername()[0] in ['127.0.0.1', '::1'] else zo.server_ip
details1.port = 3022
details2 = msg.udp_config.relay_addresses.add()
details2.lb_realm = 0 #generic load balancing realm
details2.lb_course = 0 #generic load balancing course
details2.ip = '127.0.0.1' if self.request.getpeername()[0] == '127.0.0.1' else zo.server_ip
details2.ip = self.request.getpeername()[0] if self.request.getpeername()[0] in ['127.0.0.1', '::1'] else zo.server_ip
details2.port = 3022
msg.udp_config.uc_f2 = 10
msg.udp_config.uc_f3 = 30
@@ -788,23 +788,30 @@ if os.path.isfile(ENABLE_BOTS_FILE):
bot = threading.Thread(target=play_bots)
bot.start()
SERVER_HOST = os.environ.get('ZOFFLINE_SERVER_HOST', '')
if ':' in SERVER_HOST:
import socket
socketserver.ThreadingTCPServer.address_family = socket.AF_INET6
socketserver.ThreadingUDPServer.address_family = socket.AF_INET6
socketserver.ThreadingTCPServer.allow_reuse_address = True
cdn_host = os.environ.get('ZOFFLINE_CDN_HOST', '')
socketserver.ThreadingUDPServer.allow_reuse_address = True
cdn_host = os.environ.get('ZOFFLINE_CDN_HOST', SERVER_HOST)
cdn_port = int(os.environ.get('ZOFFLINE_CDN_PORT', 80))
httpd = socketserver.ThreadingTCPServer((cdn_host, cdn_port), CDNHandler)
zoffline_thread = threading.Thread(target=httpd.serve_forever)
zoffline_thread.daemon = True
zoffline_thread.start()
tcp_host = os.environ.get('ZOFFLINE_TCP_HOST', '')
tcp_host = os.environ.get('ZOFFLINE_TCP_HOST', SERVER_HOST)
tcp_port = int(os.environ.get('ZOFFLINE_TCP_PORT', 3025))
tcpserver = socketserver.ThreadingTCPServer((tcp_host, tcp_port), TCPHandler)
tcpserver_thread = threading.Thread(target=tcpserver.serve_forever)
tcpserver_thread.daemon = True
tcpserver_thread.start()
socketserver.ThreadingUDPServer.allow_reuse_address = True
udp_host = os.environ.get('ZOFFLINE_UDP_HOST', '')
udp_host = os.environ.get('ZOFFLINE_UDP_HOST', SERVER_HOST)
udp_port = int(os.environ.get('ZOFFLINE_UDP_PORT', 3024))
udpserver = socketserver.ThreadingUDPServer((udp_host, udp_port), UDPHandler)
udpserver_thread = threading.Thread(target=udpserver.serve_forever)

View File

@@ -1410,7 +1410,7 @@ def api_users_login():
response.info.apis.trainingpeaks_url = "https://api.trainingpeaks.com"
response.info.time = int(time.time())
udp_node = response.info.nodes.nodes.add()
udp_node.ip = '127.0.0.1' if request.remote_addr == '127.0.0.1' else server_ip # TCP telemetry server
udp_node.ip = request.remote_addr if request.remote_addr in ['127.0.0.1', '::1'] else server_ip # TCP telemetry server
udp_node.port = 3023
response.relay_session_id = player_id
response.expiration = 70
@@ -3073,7 +3073,7 @@ def api_profiles_goals_id(player_id, goal_id):
def api_tcp_config():
infos = per_session_info_pb2.TcpConfig()
info = infos.nodes.add()
info.ip = '127.0.0.1' if request.remote_addr == '127.0.0.1' else server_ip
info.ip = request.remote_addr if request.remote_addr in ['127.0.0.1', '::1'] else server_ip
info.port = 3023
return infos.SerializeToString(), 200
@@ -4437,10 +4437,11 @@ def run_standalone(passed_online, passed_global_relay, passed_global_pace_partne
remove_inactive_thread = threading.Thread(target=remove_inactive)
remove_inactive_thread.start()
logger.info("Server version %s is running." % ZWIFT_VER_CUR)
host = os.environ.get('ZOFFLINE_API_HOST', '0.0.0.0')
SERVER_HOST = os.environ.get('ZOFFLINE_SERVER_HOST', '0.0.0.0')
host = os.environ.get('ZOFFLINE_API_HOST', SERVER_HOST)
port = int(os.environ.get('ZOFFLINE_API_PORT', 443))
use_cert = os.environ.get('ZOFFLINE_API_USE_CERT', 'true').lower() == 'true'
if host != '0.0.0.0' or port != 443 or not use_cert:
if host != SERVER_HOST or port != 443 or not use_cert:
logger.info("Listening on %s:%d using certificate: %s", host, port, use_cert)
cert_kwargs = {'certfile': '%s/cert-zwift-com.pem' % SSL_DIR, 'keyfile': '%s/key-zwift-com.pem' % SSL_DIR}
if not use_cert:
@@ -4448,7 +4449,7 @@ def run_standalone(passed_online, passed_global_relay, passed_global_pace_partne
server = WSGIServer((host, port), app, log=logger, **cert_kwargs)
server.serve_forever()
# app.run(ssl_context=('%s/cert-zwift-com.pem' % SSL_DIR, '%s/key-zwift-com.pem' % SSL_DIR), port=443, threaded=True, host='0.0.0.0') # debug=True, use_reload=False)
# app.run(ssl_context=('%s/cert-zwift-com.pem' % SSL_DIR, '%s/key-zwift-com.pem' % SSL_DIR), port=443, threaded=True, host=SERVER_HOST) # debug=True, use_reload=False)
if __name__ == "__main__":