|
@@ -6,66 +6,66 @@
|
|
|
# Website: https://linuxgsm.com
|
|
# Website: https://linuxgsm.com
|
|
|
# Description: Allows querying of various game servers.
|
|
# Description: Allows querying of various game servers.
|
|
|
|
|
|
|
|
-import optparse
|
|
|
|
|
|
|
+import argparse
|
|
|
import socket
|
|
import socket
|
|
|
import sys
|
|
import sys
|
|
|
|
|
|
|
|
|
|
+engine_types=('protocol-valve','protocol-quake3', 'protocol-quake3','protocol-gamespy1','protocol-unreal2','ut3 minecraft','minecraftbe','jc2mp','mumbleping','soldat','teeworlds')
|
|
|
|
|
+
|
|
|
class gsquery:
|
|
class gsquery:
|
|
|
- def __init__(self, options, arguments):
|
|
|
|
|
- self.option = options
|
|
|
|
|
|
|
+ server_response_timeout = 5
|
|
|
|
|
+ default_buffer_length = 1024
|
|
|
|
|
+ sourcequery=('protocol-valve','avalanche3.0','barotrauma','madness','quakelive','realvirtuality','refractor','source','goldsrc','spark','starbound','unity3d','unreal4','wurm')
|
|
|
|
|
+ idtech2query=('protocol-quake3','idtech2','quake','iw2.0')
|
|
|
|
|
+ idtech3query=('protocol-quake3','iw3.0','ioquake3','qfusion')
|
|
|
|
|
+ minecraftquery=('minecraft','lwjgl2')
|
|
|
|
|
+ minecraftbequery=('minecraftbe',)
|
|
|
|
|
+ jc2mpquery=('jc2mp',)
|
|
|
|
|
+ mumblequery=('mumbleping',)
|
|
|
|
|
+ soldatquery=('soldat',)
|
|
|
|
|
+ twquery=('teeworlds',)
|
|
|
|
|
+ unrealquery=('protocol-gamespy1','unreal')
|
|
|
|
|
+ unreal2query=('protocol-unreal2','unreal2')
|
|
|
|
|
+ unreal3query=('ut3','unreal3')
|
|
|
|
|
+
|
|
|
|
|
+ def __init__(self, arguments):
|
|
|
self.argument = arguments
|
|
self.argument = arguments
|
|
|
#
|
|
#
|
|
|
- self.server_response_timeout = 5
|
|
|
|
|
- self.default_buffer_length = 1024
|
|
|
|
|
- #
|
|
|
|
|
- sourcequery=['protocol-valve','avalanche3.0','barotrauma','madness','quakelive','realvirtuality','refractor','source','goldsrc','spark','starbound','unity3d','unreal4','wurm']
|
|
|
|
|
- idtech2query=['protocol-quake3','idtech2','quake','iw2.0']
|
|
|
|
|
- idtech3query=['protocol-quake3','iw3.0','ioquake3','qfusion']
|
|
|
|
|
- minecraftquery=['minecraft','lwjgl2']
|
|
|
|
|
- minecraftbequery=['minecraftbe']
|
|
|
|
|
- jc2mpquery=['jc2mp']
|
|
|
|
|
- mumblequery=['mumbleping']
|
|
|
|
|
- soldatquery=['soldat']
|
|
|
|
|
- twquery=['teeworlds']
|
|
|
|
|
- unrealquery=['protocol-gamespy1','unreal']
|
|
|
|
|
- unreal2query=['protocol-unreal2','unreal2']
|
|
|
|
|
- unreal3query=['ut3','unreal3']
|
|
|
|
|
- if self.option.engine in sourcequery:
|
|
|
|
|
|
|
+ if self.argument.engine in self.sourcequery:
|
|
|
self.query_prompt_string = b'\xFF\xFF\xFF\xFFTSource Engine Query\0'
|
|
self.query_prompt_string = b'\xFF\xFF\xFF\xFFTSource Engine Query\0'
|
|
|
- elif self.option.engine in idtech2query:
|
|
|
|
|
|
|
+ elif self.argument.engine in self.idtech2query:
|
|
|
self.query_prompt_string = b'\xff\xff\xff\xffstatus\x00'
|
|
self.query_prompt_string = b'\xff\xff\xff\xffstatus\x00'
|
|
|
- elif self.option.engine in idtech3query:
|
|
|
|
|
|
|
+ elif self.argument.engine in self.idtech3query:
|
|
|
self.query_prompt_string = b'\xff\xff\xff\xffgetstatus'
|
|
self.query_prompt_string = b'\xff\xff\xff\xffgetstatus'
|
|
|
- elif self.option.engine in jc2mpquery:
|
|
|
|
|
|
|
+ elif self.argument.engine in self.jc2mpquery:
|
|
|
self.query_prompt_string = b'\xFE\xFD\x09\x10\x20\x30\x40'
|
|
self.query_prompt_string = b'\xFE\xFD\x09\x10\x20\x30\x40'
|
|
|
- elif self.option.engine in minecraftquery:
|
|
|
|
|
|
|
+ elif self.argument.engine in self.minecraftquery:
|
|
|
self.query_prompt_string = b'\xFE\xFD\x09\x3d\x54\x1f\x93'
|
|
self.query_prompt_string = b'\xFE\xFD\x09\x3d\x54\x1f\x93'
|
|
|
- elif self.option.engine in minecraftbequery:
|
|
|
|
|
|
|
+ elif self.argument.engine in self.minecraftbequery:
|
|
|
self.query_prompt_string = b'\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\xff\xff\x00\xfe\xfe\xfe\xfe\xfd\xfd\xfd\xfd\x12\x34\x56\x78\x00\x00\x00\x00\x00\x00\x00\x00'
|
|
self.query_prompt_string = b'\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\xff\xff\x00\xfe\xfe\xfe\xfe\xfd\xfd\xfd\xfd\x12\x34\x56\x78\x00\x00\x00\x00\x00\x00\x00\x00'
|
|
|
- elif self.option.engine in mumblequery:
|
|
|
|
|
|
|
+ elif self.argument.engine in self.mumblequery:
|
|
|
self.query_prompt_string = b'\x00\x00\x00\x00\x01\x02\x03\x04\x05\x06\x07\x08'
|
|
self.query_prompt_string = b'\x00\x00\x00\x00\x01\x02\x03\x04\x05\x06\x07\x08'
|
|
|
- elif self.option.engine in soldatquery:
|
|
|
|
|
|
|
+ elif self.argument.engine in self.soldatquery:
|
|
|
self.query_prompt_string = b'\x69\x00'
|
|
self.query_prompt_string = b'\x69\x00'
|
|
|
- elif self.option.engine in twquery:
|
|
|
|
|
- self.query_prompt_string = b"\x04\x00\x00\xff\xff\xff\xff\x05" + bytearray(511)
|
|
|
|
|
- elif self.option.engine in unrealquery:
|
|
|
|
|
|
|
+ elif self.argument.engine in self.twquery:
|
|
|
|
|
+ self.query_prompt_string = b'\x04\x00\x00\xff\xff\xff\xff\x05' + bytearray(511)
|
|
|
|
|
+ elif self.argument.engine in self.unrealquery:
|
|
|
self.query_prompt_string = b'\x5C\x69\x6E\x66\x6F\x5C'
|
|
self.query_prompt_string = b'\x5C\x69\x6E\x66\x6F\x5C'
|
|
|
- elif self.option.engine in unreal2query:
|
|
|
|
|
|
|
+ elif self.argument.engine in self.unreal2query:
|
|
|
self.query_prompt_string = b'\x79\x00\x00\x00\x00'
|
|
self.query_prompt_string = b'\x79\x00\x00\x00\x00'
|
|
|
- elif self.option.engine in unreal3query:
|
|
|
|
|
|
|
+ elif self.argument.engine in self.unreal3query:
|
|
|
self.query_prompt_string = b'\xFE\xFD\x09\x00\x00\x00\x00'
|
|
self.query_prompt_string = b'\xFE\xFD\x09\x00\x00\x00\x00'
|
|
|
|
|
|
|
|
self.connected = False
|
|
self.connected = False
|
|
|
self.response = None
|
|
self.response = None
|
|
|
- self.sanity_checks()
|
|
|
|
|
|
|
|
|
|
@staticmethod
|
|
@staticmethod
|
|
|
- def fatal_error(self, error_message, error_code=1):
|
|
|
|
|
|
|
+ def fatal_error(error_message, error_code=1):
|
|
|
sys.stderr.write('ERROR: ' + str(error_message) + '\n')
|
|
sys.stderr.write('ERROR: ' + str(error_message) + '\n')
|
|
|
sys.exit(error_code)
|
|
sys.exit(error_code)
|
|
|
|
|
|
|
|
@staticmethod
|
|
@staticmethod
|
|
|
- def exit_success(self, success_message=''):
|
|
|
|
|
|
|
+ def exit_success(success_message=''):
|
|
|
sys.stdout.write('OK: ' + str(success_message) + '\n')
|
|
sys.stdout.write('OK: ' + str(success_message) + '\n')
|
|
|
sys.exit(0)
|
|
sys.exit(0)
|
|
|
|
|
|
|
@@ -74,10 +74,10 @@ class gsquery:
|
|
|
connection = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
|
|
connection = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
|
|
|
connection.settimeout(self.server_response_timeout)
|
|
connection.settimeout(self.server_response_timeout)
|
|
|
try:
|
|
try:
|
|
|
- self.connected = connection.connect((self.option.address, int(self.option.port)))
|
|
|
|
|
|
|
+ self.connected = connection.connect((self.argument.address, int(self.argument.port)))
|
|
|
except socket.timeout:
|
|
except socket.timeout:
|
|
|
self.fatal_error('Request timed out', 1)
|
|
self.fatal_error('Request timed out', 1)
|
|
|
- except:
|
|
|
|
|
|
|
+ except Exception:
|
|
|
self.fatal_error('Unable to connect', 1)
|
|
self.fatal_error('Unable to connect', 1)
|
|
|
# Send.
|
|
# Send.
|
|
|
connection.send(self.query_prompt_string)
|
|
connection.send(self.query_prompt_string)
|
|
@@ -95,52 +95,57 @@ class gsquery:
|
|
|
else:
|
|
else:
|
|
|
self.exit_success(str(self.response))
|
|
self.exit_success(str(self.response))
|
|
|
|
|
|
|
|
- def sanity_checks(self):
|
|
|
|
|
- if not self.option.address:
|
|
|
|
|
- self.fatal_error('No IPv4 address supplied.', 4)
|
|
|
|
|
- if not self.option.port:
|
|
|
|
|
- self.fatal_error('No port supplied.', 4)
|
|
|
|
|
-
|
|
|
|
|
-if __name__ == '__main__':
|
|
|
|
|
- parser = optparse.OptionParser(
|
|
|
|
|
- usage='usage: python3 %prog [options]',
|
|
|
|
|
- version='%prog 0.0.1'
|
|
|
|
|
|
|
+def parse_args():
|
|
|
|
|
+ parser = argparse.ArgumentParser(
|
|
|
|
|
+ description='Allows querying of various game servers.',
|
|
|
|
|
+ usage='usage: python3 %(prog)s [options]',
|
|
|
|
|
+ add_help=False
|
|
|
)
|
|
)
|
|
|
- parser.add_option(
|
|
|
|
|
|
|
+ parser.add_argument(
|
|
|
'-a', '--address',
|
|
'-a', '--address',
|
|
|
- action='store',
|
|
|
|
|
- dest='address',
|
|
|
|
|
- default=False,
|
|
|
|
|
|
|
+ type=str,
|
|
|
|
|
+ required=True,
|
|
|
help='The IPv4 address of the server.'
|
|
help='The IPv4 address of the server.'
|
|
|
)
|
|
)
|
|
|
- parser.add_option(
|
|
|
|
|
|
|
+ parser.add_argument(
|
|
|
'-p', '--port',
|
|
'-p', '--port',
|
|
|
- action='store',
|
|
|
|
|
- dest='port',
|
|
|
|
|
- default=False,
|
|
|
|
|
|
|
+ type=int,
|
|
|
|
|
+ required=True,
|
|
|
help='The IPv4 port of the server.'
|
|
help='The IPv4 port of the server.'
|
|
|
)
|
|
)
|
|
|
- parser.add_option(
|
|
|
|
|
|
|
+ parser.add_argument(
|
|
|
'-e', '--engine',
|
|
'-e', '--engine',
|
|
|
- action='store',
|
|
|
|
|
- dest='engine',
|
|
|
|
|
- default=False,
|
|
|
|
|
- help='Engine type: protocol-valve protocol-quake3 protocol-quake3 protocol-gamespy1 protocol-unreal2 ut3 minecraft minecraftbe jc2mp mumbleping soldat teeworlds'
|
|
|
|
|
|
|
+ metavar='ENGINE',
|
|
|
|
|
+ choices=engine_types,
|
|
|
|
|
+ help='Engine type: ' + ' '.join(engine_types)
|
|
|
)
|
|
)
|
|
|
- parser.add_option(
|
|
|
|
|
|
|
+ parser.add_argument(
|
|
|
'-v', '--verbose',
|
|
'-v', '--verbose',
|
|
|
action='store_true',
|
|
action='store_true',
|
|
|
- dest='verbose',
|
|
|
|
|
- default=False,
|
|
|
|
|
help='Display verbose output.'
|
|
help='Display verbose output.'
|
|
|
)
|
|
)
|
|
|
- parser.add_option(
|
|
|
|
|
|
|
+ parser.add_argument(
|
|
|
'-d', '--debug',
|
|
'-d', '--debug',
|
|
|
action='store_true',
|
|
action='store_true',
|
|
|
- dest='debug',
|
|
|
|
|
- default=False,
|
|
|
|
|
help='Display debugging output.'
|
|
help='Display debugging output.'
|
|
|
)
|
|
)
|
|
|
- options, arguments = parser.parse_args()
|
|
|
|
|
- server = gsquery(options, arguments)
|
|
|
|
|
|
|
+ parser.add_argument(
|
|
|
|
|
+ '-V', '--version',
|
|
|
|
|
+ action='version',
|
|
|
|
|
+ version='%(prog)s 0.0.1',
|
|
|
|
|
+ help='Display version and exit.'
|
|
|
|
|
+ )
|
|
|
|
|
+ parser.add_argument(
|
|
|
|
|
+ '-h', '--help',
|
|
|
|
|
+ action='help',
|
|
|
|
|
+ help='Display help and exit.'
|
|
|
|
|
+ )
|
|
|
|
|
+ return parser.parse_args()
|
|
|
|
|
+
|
|
|
|
|
+def main():
|
|
|
|
|
+ arguments = parse_args()
|
|
|
|
|
+ server = gsquery(arguments)
|
|
|
server.responding()
|
|
server.responding()
|
|
|
|
|
+
|
|
|
|
|
+if __name__ == '__main__':
|
|
|
|
|
+ main()
|