Changes to server to allow better control over binding to interfaces (#582)

* refactor: remove unused imports

* server: new options to choose certain IP versions

On some setups, IPv6 or IPv4 might be disabled in the OS.
In my case IPv6 is disabled and this causes errors when starting the server.

* server: add options to choose the address to bind to

Sometimes a user might want to bind to localhost only for testing
or have multiple interfaces per IP version and only one must be used.
This commit is contained in:
powerjungle 2023-07-03 20:24:34 +02:00 committed by GitHub
parent 884d79bed3
commit 8ba286567d
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
14 changed files with 78 additions and 14 deletions

View File

@ -6,19 +6,26 @@ from twisted.internet.error import CannotListenError
from syncplay.server import SyncFactory, ConfigurationGetter from syncplay.server import SyncFactory, ConfigurationGetter
class ServerStatus: pass
class ServerStatus:
listening6 = False
listening4 = False
def isListening6(f): def isListening6(f):
ServerStatus.listening6 = True ServerStatus.listening6 = True
def isListening4(f): def isListening4(f):
ServerStatus.listening4 = True ServerStatus.listening4 = True
def failed6(f): def failed6(f):
ServerStatus.listening6 = False ServerStatus.listening6 = False
print(f.value) print(f.value)
print("IPv6 listening failed.") print("IPv6 listening failed.")
def failed4(f): def failed4(f):
ServerStatus.listening4 = False ServerStatus.listening4 = False
if f.type is CannotListenError and ServerStatus.listening6: if f.type is CannotListenError and ServerStatus.listening6:
@ -27,9 +34,11 @@ def failed4(f):
print(f.value) print(f.value)
print("IPv4 listening failed.") print("IPv4 listening failed.")
def main(): def main():
argsGetter = ConfigurationGetter() argsGetter = ConfigurationGetter()
args = argsGetter.getConfiguration() args = argsGetter.getConfiguration()
factory = SyncFactory( factory = SyncFactory(
args.port, args.port,
args.password, args.password,
@ -45,15 +54,25 @@ def main():
args.stats_db_file, args.stats_db_file,
args.tls args.tls
) )
endpoint6 = TCP6ServerEndpoint(reactor, int(args.port))
endpoint6.listen(factory).addCallbacks(isListening6, failed6) if args.ipv6_only is True:
endpoint4 = TCP4ServerEndpoint(reactor, int(args.port)) endpoint6 = TCP6ServerEndpoint(reactor, int(args.port), interface=args.interface_ipv6)
endpoint4.listen(factory).addCallbacks(isListening4, failed4) endpoint6.listen(factory).addCallbacks(isListening6, failed6)
elif args.ipv4_only is True:
endpoint4 = TCP4ServerEndpoint(reactor, int(args.port), interface=args.interface_ipv4)
endpoint4.listen(factory).addCallbacks(isListening4, failed4)
else:
endpoint6 = TCP6ServerEndpoint(reactor, int(args.port), interface=args.interface_ipv6)
endpoint6.listen(factory).addCallbacks(isListening6, failed6)
endpoint4 = TCP4ServerEndpoint(reactor, int(args.port), interface=args.interface_ipv4)
endpoint4.listen(factory).addCallbacks(isListening4, failed4)
if ServerStatus.listening6 or ServerStatus.listening4: if ServerStatus.listening6 or ServerStatus.listening4:
reactor.run() reactor.run()
else: else:
print("Unable to listen using either IPv4 and IPv6 protocols. Quitting the server now.") print("Unable to listen using either IPv4 and IPv6 protocols. Quitting the server now.")
sys.exit() sys.exit()
if __name__ == "__main__": if __name__ == "__main__":
main() main()

View File

@ -499,6 +499,10 @@ de = {
"server-startTLS-argument": "Erlaube TLS-Verbindungen mit den Zertifikatdateien im Angegebenen Pfad", "server-startTLS-argument": "Erlaube TLS-Verbindungen mit den Zertifikatdateien im Angegebenen Pfad",
"server-messed-up-motd-unescaped-placeholders": "Die Nachricht des Tages hat unmaskierte Platzhalter. Alle $-Zeichen sollten verdoppelt werden ($$).", "server-messed-up-motd-unescaped-placeholders": "Die Nachricht des Tages hat unmaskierte Platzhalter. Alle $-Zeichen sollten verdoppelt werden ($$).",
"server-messed-up-motd-too-long": "Die Nachricht des Tages ist zu lang - Maximal {} Zeichen, aktuell {}.", "server-messed-up-motd-too-long": "Die Nachricht des Tages ist zu lang - Maximal {} Zeichen, aktuell {}.",
"server-listen-only-on-ipv4": "Listen only on IPv4 when starting the server.",
"server-listen-only-on-ipv6": "Listen only on IPv6 when starting the server.",
"server-interface-ipv4": "The IP address to bind to for IPv4. Leaving it empty defaults to using all.",
"server-interface-ipv6": "The IP address to bind to for IPv6. Leaving it empty defaults to using all.",
# Server errors # Server errors
"unknown-command-server-error": "Unbekannter Befehl {}", # message "unknown-command-server-error": "Unbekannter Befehl {}", # message

View File

@ -500,6 +500,10 @@ en = {
"server-startTLS-argument": "Enable TLS connections using the certificate files in the path provided", "server-startTLS-argument": "Enable TLS connections using the certificate files in the path provided",
"server-messed-up-motd-unescaped-placeholders": "Message of the Day has unescaped placeholders. All $ signs should be doubled ($$).", "server-messed-up-motd-unescaped-placeholders": "Message of the Day has unescaped placeholders. All $ signs should be doubled ($$).",
"server-messed-up-motd-too-long": "Message of the Day is too long - maximum of {} chars, {} given.", "server-messed-up-motd-too-long": "Message of the Day is too long - maximum of {} chars, {} given.",
"server-listen-only-on-ipv4": "Listen only on IPv4 when starting the server.",
"server-listen-only-on-ipv6": "Listen only on IPv6 when starting the server.",
"server-interface-ipv4": "The IP address to bind to for IPv4. Leaving it empty defaults to using all.",
"server-interface-ipv6": "The IP address to bind to for IPv6. Leaving it empty defaults to using all.",
# Server errors # Server errors
"unknown-command-server-error": "Unknown command {}", # message "unknown-command-server-error": "Unknown command {}", # message

View File

@ -503,6 +503,10 @@ eo = {
"server-startTLS-argument": "Ŝalti TLS-konektojn per la atestilaj dosieroj en la donita vojo", "server-startTLS-argument": "Ŝalti TLS-konektojn per la atestilaj dosieroj en la donita vojo",
"server-messed-up-motd-unescaped-placeholders": "Mesaĝo de tago havas neŝirmitajn anstataŭiĝojn. Ĉiuj dolarsignoj devus aperi duoble ($$).", "server-messed-up-motd-unescaped-placeholders": "Mesaĝo de tago havas neŝirmitajn anstataŭiĝojn. Ĉiuj dolarsignoj devus aperi duoble ($$).",
"server-messed-up-motd-too-long": "Mesaĝo de tago estas tro longa maksimuma kvanto estas {} signoj, sed {} estas donitaj.", "server-messed-up-motd-too-long": "Mesaĝo de tago estas tro longa maksimuma kvanto estas {} signoj, sed {} estas donitaj.",
"server-listen-only-on-ipv4": "Listen only on IPv4 when starting the server.",
"server-listen-only-on-ipv6": "Listen only on IPv6 when starting the server.",
"server-interface-ipv4": "The IP address to bind to for IPv4. Leaving it empty defaults to using all.",
"server-interface-ipv6": "The IP address to bind to for IPv6. Leaving it empty defaults to using all.",
# Server errors # Server errors
"unknown-command-server-error": "Nekonata ordono {}", # message "unknown-command-server-error": "Nekonata ordono {}", # message

View File

@ -499,6 +499,10 @@ es = {
"server-startTLS-argument": "Habilitar conexiones TLS usando los archivos de certificado en la ruta provista", "server-startTLS-argument": "Habilitar conexiones TLS usando los archivos de certificado en la ruta provista",
"server-messed-up-motd-unescaped-placeholders": "El mensaje del dia contiene marcadores de posición sin escapar. Todos los signos $ deberían ser dobles ($$).", "server-messed-up-motd-unescaped-placeholders": "El mensaje del dia contiene marcadores de posición sin escapar. Todos los signos $ deberían ser dobles ($$).",
"server-messed-up-motd-too-long": "El mensaje del día es muy largo - máximo de {} caracteres, se recibieron {}.", "server-messed-up-motd-too-long": "El mensaje del día es muy largo - máximo de {} caracteres, se recibieron {}.",
"server-listen-only-on-ipv4": "Listen only on IPv4 when starting the server.",
"server-listen-only-on-ipv6": "Listen only on IPv6 when starting the server.",
"server-interface-ipv4": "The IP address to bind to for IPv4. Leaving it empty defaults to using all.",
"server-interface-ipv6": "The IP address to bind to for IPv6. Leaving it empty defaults to using all.",
# Server errors # Server errors
"unknown-command-server-error": "Comando desconocido {}", # message "unknown-command-server-error": "Comando desconocido {}", # message

View File

@ -500,6 +500,10 @@ fr = {
"server-startTLS-argument": "Activer les connexions TLS à l'aide des fichiers de certificat dans le chemin fourni", "server-startTLS-argument": "Activer les connexions TLS à l'aide des fichiers de certificat dans le chemin fourni",
"server-messed-up-motd-unescaped-placeholders": "Le message du jour a des espaces réservés non échappés. Tous les signes $ doivent être doublés ($$).", "server-messed-up-motd-unescaped-placeholders": "Le message du jour a des espaces réservés non échappés. Tous les signes $ doivent être doublés ($$).",
"server-messed-up-motd-too-long": "Le message du jour est trop long: {}caractères maximum, {} donnés.", "server-messed-up-motd-too-long": "Le message du jour est trop long: {}caractères maximum, {} donnés.",
"server-listen-only-on-ipv4": "Listen only on IPv4 when starting the server.",
"server-listen-only-on-ipv6": "Listen only on IPv6 when starting the server.",
"server-interface-ipv4": "The IP address to bind to for IPv4. Leaving it empty defaults to using all.",
"server-interface-ipv6": "The IP address to bind to for IPv6. Leaving it empty defaults to using all.",
# Server errors # Server errors
"unknown-command-server-error": "Commande inconnue {}", # message "unknown-command-server-error": "Commande inconnue {}", # message

View File

@ -499,6 +499,10 @@ it = {
"server-startTLS-argument": "Abilita il protocollo TLS usando i certificati contenuti nel percorso indicato", "server-startTLS-argument": "Abilita il protocollo TLS usando i certificati contenuti nel percorso indicato",
"server-messed-up-motd-unescaped-placeholders": "Il messaggio del giorno ha dei caratteri non 'escaped'. Tutti i simboli $ devono essere doppi ($$).", "server-messed-up-motd-unescaped-placeholders": "Il messaggio del giorno ha dei caratteri non 'escaped'. Tutti i simboli $ devono essere doppi ($$).",
"server-messed-up-motd-too-long": "Il messaggio del giorno è troppo lungo - numero massimo di caratteri è {}, {} trovati.", "server-messed-up-motd-too-long": "Il messaggio del giorno è troppo lungo - numero massimo di caratteri è {}, {} trovati.",
"server-listen-only-on-ipv4": "Listen only on IPv4 when starting the server.",
"server-listen-only-on-ipv6": "Listen only on IPv6 when starting the server.",
"server-interface-ipv4": "The IP address to bind to for IPv4. Leaving it empty defaults to using all.",
"server-interface-ipv6": "The IP address to bind to for IPv6. Leaving it empty defaults to using all.",
# Server errors # Server errors
"unknown-command-server-error": "Comando non riconosciuto {}", # message "unknown-command-server-error": "Comando non riconosciuto {}", # message

View File

@ -500,6 +500,10 @@ pt_BR = {
"server-startTLS-argument": "Habilita conexões TLS usando os arquivos de certificado no caminho fornecido", "server-startTLS-argument": "Habilita conexões TLS usando os arquivos de certificado no caminho fornecido",
"server-messed-up-motd-unescaped-placeholders": "A Mensagem do Dia possui placeholders não escapados. Todos os sinais de $ devem ser dobrados (como em $$).", "server-messed-up-motd-unescaped-placeholders": "A Mensagem do Dia possui placeholders não escapados. Todos os sinais de $ devem ser dobrados (como em $$).",
"server-messed-up-motd-too-long": "A Mensagem do Dia é muito longa - máximo de {} caracteres, {} foram dados.", "server-messed-up-motd-too-long": "A Mensagem do Dia é muito longa - máximo de {} caracteres, {} foram dados.",
"server-listen-only-on-ipv4": "Listen only on IPv4 when starting the server.",
"server-listen-only-on-ipv6": "Listen only on IPv6 when starting the server.",
"server-interface-ipv4": "The IP address to bind to for IPv4. Leaving it empty defaults to using all.",
"server-interface-ipv6": "The IP address to bind to for IPv6. Leaving it empty defaults to using all.",
# Server errors # Server errors
"unknown-command-server-error": "Comando desconhecido: {}", # message "unknown-command-server-error": "Comando desconhecido: {}", # message

View File

@ -499,6 +499,10 @@ pt_PT = {
"server-startTLS-argument": "Habilita conexões TLS usando os arquivos de certificado no caminho fornecido", "server-startTLS-argument": "Habilita conexões TLS usando os arquivos de certificado no caminho fornecido",
"server-messed-up-motd-unescaped-placeholders": "A Mensagem do Dia possui placeholders não escapados. Todos os sinais de $ devem ser dobrados (como em $$).", "server-messed-up-motd-unescaped-placeholders": "A Mensagem do Dia possui placeholders não escapados. Todos os sinais de $ devem ser dobrados (como em $$).",
"server-messed-up-motd-too-long": "A Mensagem do Dia é muito longa - máximo de {} caracteres, {} foram dados.", "server-messed-up-motd-too-long": "A Mensagem do Dia é muito longa - máximo de {} caracteres, {} foram dados.",
"server-listen-only-on-ipv4": "Listen only on IPv4 when starting the server.",
"server-listen-only-on-ipv6": "Listen only on IPv6 when starting the server.",
"server-interface-ipv4": "The IP address to bind to for IPv4. Leaving it empty defaults to using all.",
"server-interface-ipv6": "The IP address to bind to for IPv6. Leaving it empty defaults to using all.",
# Server errors # Server errors
"unknown-command-server-error": "Comando desconhecido: {}", # message "unknown-command-server-error": "Comando desconhecido: {}", # message

View File

@ -496,6 +496,10 @@ ru = {
"server-startTLS-argument": "Включить TLS-соединения используя файлы сертификатов в указанном пути", "server-startTLS-argument": "Включить TLS-соединения используя файлы сертификатов в указанном пути",
"server-messed-up-motd-unescaped-placeholders": "MOTD-сообщение содержит неэкранированные спецсимволы. Все знаки $ должны быть продублированы ($$).", "server-messed-up-motd-unescaped-placeholders": "MOTD-сообщение содержит неэкранированные спецсимволы. Все знаки $ должны быть продублированы ($$).",
"server-messed-up-motd-too-long": "MOTD-сообщение слишком длинное: максимальная длина - {} символ(ов), текущая длина - {} символ(ов).", "server-messed-up-motd-too-long": "MOTD-сообщение слишком длинное: максимальная длина - {} символ(ов), текущая длина - {} символ(ов).",
"server-listen-only-on-ipv4": "Listen only on IPv4 when starting the server.",
"server-listen-only-on-ipv6": "Listen only on IPv6 when starting the server.",
"server-interface-ipv4": "The IP address to bind to for IPv4. Leaving it empty defaults to using all.",
"server-interface-ipv6": "The IP address to bind to for IPv6. Leaving it empty defaults to using all.",
# Server errors # Server errors
"unknown-command-server-error": "Неизвестная команда: {}", # message "unknown-command-server-error": "Неизвестная команда: {}", # message

View File

@ -500,6 +500,10 @@ tr = {
"server-startTLS-argument": "Dosya yolundaki sertifika dosyalarını kullanarak TLS bağlantılarını etkinleştirin", "server-startTLS-argument": "Dosya yolundaki sertifika dosyalarını kullanarak TLS bağlantılarını etkinleştirin",
"server-messed-up-motd-unescaped-placeholders": "Günün Mesajında çıkış karaktersiz yer tutucular var. Tüm $ işaretleri iki katına çıkarılmalıdır ($$).", "server-messed-up-motd-unescaped-placeholders": "Günün Mesajında çıkış karaktersiz yer tutucular var. Tüm $ işaretleri iki katına çıkarılmalıdır ($$).",
"server-messed-up-motd-too-long": "Günün Mesajı çok uzun - maksimum {} karakter olmalı, {} verildi.", "server-messed-up-motd-too-long": "Günün Mesajı çok uzun - maksimum {} karakter olmalı, {} verildi.",
"server-listen-only-on-ipv4": "Listen only on IPv4 when starting the server.",
"server-listen-only-on-ipv6": "Listen only on IPv6 when starting the server.",
"server-interface-ipv4": "The IP address to bind to for IPv4. Leaving it empty defaults to using all.",
"server-interface-ipv6": "The IP address to bind to for IPv6. Leaving it empty defaults to using all.",
# Server errors # Server errors
"unknown-command-server-error": "Bilinmeyen komut {}", # message "unknown-command-server-error": "Bilinmeyen komut {}", # message

View File

@ -500,6 +500,10 @@ zh_CN = {
"server-startTLS-argument": "使用提供的路径中的证书文件启用TLS连接", "server-startTLS-argument": "使用提供的路径中的证书文件启用TLS连接",
"server-messed-up-motd-unescaped-placeholders": "每日信息中有未转义的占位符。所有 $ 字符应当重复两遍 ($$).", "server-messed-up-motd-unescaped-placeholders": "每日信息中有未转义的占位符。所有 $ 字符应当重复两遍 ($$).",
"server-messed-up-motd-too-long": "每日信息过长 - 最大{}个chars, 给出的长度{}", "server-messed-up-motd-too-long": "每日信息过长 - 最大{}个chars, 给出的长度{}",
"server-listen-only-on-ipv4": "Listen only on IPv4 when starting the server.",
"server-listen-only-on-ipv6": "Listen only on IPv6 when starting the server.",
"server-interface-ipv4": "The IP address to bind to for IPv4. Leaving it empty defaults to using all.",
"server-interface-ipv6": "The IP address to bind to for IPv6. Leaving it empty defaults to using all.",
# Server errors # Server errors
"unknown-command-server-error": "未知命令 {}", # message "unknown-command-server-error": "未知命令 {}", # message

View File

@ -2,9 +2,7 @@ import argparse
import codecs import codecs
import hashlib import hashlib
import os import os
import random
import time import time
import json
from string import Template from string import Template
from twisted.enterprise import adbapi from twisted.enterprise import adbapi
@ -292,18 +290,18 @@ class StatsRecorder(object):
def __init__(self, dbHandle, roomManager): def __init__(self, dbHandle, roomManager):
self._dbHandle = dbHandle self._dbHandle = dbHandle
self._roomManagerHandle = roomManager self._roomManagerHandle = roomManager
def startRecorder(self, delay): def startRecorder(self, delay):
try: try:
self._dbHandle.connect() self._dbHandle.connect()
reactor.callLater(delay, self._scheduleClientSnapshot) reactor.callLater(delay, self._scheduleClientSnapshot)
except: except:
print("--- Error in initializing the stats database. Server Stats not enabled. ---") print("--- Error in initializing the stats database. Server Stats not enabled. ---")
def _scheduleClientSnapshot(self): def _scheduleClientSnapshot(self):
self._clientSnapshotTimer = task.LoopingCall(self._runClientSnapshot) self._clientSnapshotTimer = task.LoopingCall(self._runClientSnapshot)
self._clientSnapshotTimer.start(constants.SERVER_STATS_SNAPSHOT_INTERVAL) self._clientSnapshotTimer.start(constants.SERVER_STATS_SNAPSHOT_INTERVAL)
def _runClientSnapshot(self): def _runClientSnapshot(self):
try: try:
snapshotTime = int(time.time()) snapshotTime = int(time.time())
@ -499,7 +497,7 @@ class RoomManager(object):
while username.lower() in allnames: while username.lower() in allnames:
username += '_' username += '_'
return username return username
def exportRooms(self): def exportRooms(self):
return self._rooms return self._rooms
@ -891,3 +889,7 @@ class ConfigurationGetter(object):
self._argparser.add_argument('--max-username-length', metavar='maxUsernameLength', type=int, nargs='?', help=getMessage("server-maxusernamelength-argument").format(constants.MAX_USERNAME_LENGTH)) self._argparser.add_argument('--max-username-length', metavar='maxUsernameLength', type=int, nargs='?', help=getMessage("server-maxusernamelength-argument").format(constants.MAX_USERNAME_LENGTH))
self._argparser.add_argument('--stats-db-file', metavar='file', type=str, nargs='?', help=getMessage("server-stats-db-file-argument")) self._argparser.add_argument('--stats-db-file', metavar='file', type=str, nargs='?', help=getMessage("server-stats-db-file-argument"))
self._argparser.add_argument('--tls', metavar='path', type=str, nargs='?', help=getMessage("server-startTLS-argument")) self._argparser.add_argument('--tls', metavar='path', type=str, nargs='?', help=getMessage("server-startTLS-argument"))
self._argparser.add_argument('--ipv4-only', action='store_true', help=getMessage("server-listen-only-on-ipv4"))
self._argparser.add_argument('--ipv6-only', action='store_true', help=getMessage("server-listen-only-on-ipv6"))
self._argparser.add_argument('--interface-ipv4', metavar='interfaceIPv4', type=str, nargs='?', help=getMessage("server-interface-ipv4"), default='')
self._argparser.add_argument('--interface-ipv6', metavar='interfaceIPv6', type=str, nargs='?', help=getMessage("server-interface-ipv6"), default='')

View File

@ -12,7 +12,6 @@ import subprocess
import sys import sys
import time import time
import traceback import traceback
import unicodedata
import urllib.error import urllib.error
import urllib.parse import urllib.parse
import urllib.request import urllib.request