query_gsquery.py 5.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146
  1. #! /usr/bin/env python3
  2. # -*- coding: utf-8 -*-
  3. # LinuxGSM query_gsquery.py function
  4. # Author: Daniel Gibbs
  5. # Contributors: http://linuxgsm.com/contrib
  6. # Website: https://linuxgsm.com
  7. # Description: Allows querying of various game servers.
  8. import optparse
  9. import socket
  10. import sys
  11. class gsquery:
  12. def __init__(self, options, arguments):
  13. self.option = options
  14. self.argument = arguments
  15. #
  16. self.server_response_timeout = 5
  17. self.default_buffer_length = 1024
  18. #
  19. sourcequery=['protocol-valve','avalanche3.0','barotrauma','madness','quakelive','realvirtuality','refractor','source','goldsrc','spark','starbound','unity3d','unreal4','wurm']
  20. idtech2query=['protocol-quake3','idtech2','quake','iw2.0']
  21. idtech3query=['protocol-quake3','iw3.0','ioquake3','qfusion']
  22. minecraftquery=['minecraft','lwjgl2']
  23. minecraftbequery=['minecraftbe']
  24. jc2mpquery=['jc2mp']
  25. mumblequery=['mumbleping']
  26. soldatquery=['soldat']
  27. twquery=['teeworlds']
  28. unrealquery=['protocol-gamespy1','unreal']
  29. unreal2query=['protocol-unreal2','unreal2']
  30. unreal3query=['ut3','unreal3']
  31. if self.option.engine in sourcequery:
  32. self.query_prompt_string = b'\xFF\xFF\xFF\xFFTSource Engine Query\0'
  33. elif self.option.engine in idtech2query:
  34. self.query_prompt_string = b'\xff\xff\xff\xffstatus\x00'
  35. elif self.option.engine in idtech3query:
  36. self.query_prompt_string = b'\xff\xff\xff\xffgetstatus'
  37. elif self.option.engine in jc2mpquery:
  38. self.query_prompt_string = b'\xFE\xFD\x09\x10\x20\x30\x40'
  39. elif self.option.engine in minecraftquery:
  40. self.query_prompt_string = b'\xFE\xFD\x09\x3d\x54\x1f\x93'
  41. elif self.option.engine in minecraftbequery:
  42. 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'
  43. elif self.option.engine in mumblequery:
  44. self.query_prompt_string = b'\x00\x00\x00\x00\x01\x02\x03\x04\x05\x06\x07\x08'
  45. elif self.option.engine in soldatquery:
  46. self.query_prompt_string = b'\x69\x00'
  47. elif self.option.engine in twquery:
  48. self.query_prompt_string = b"\x04\x00\x00\xff\xff\xff\xff\x05" + bytearray(511)
  49. elif self.option.engine in unrealquery:
  50. self.query_prompt_string = b'\x5C\x69\x6E\x66\x6F\x5C'
  51. elif self.option.engine in unreal2query:
  52. self.query_prompt_string = b'\x79\x00\x00\x00\x00'
  53. elif self.option.engine in unreal3query:
  54. self.query_prompt_string = b'\xFE\xFD\x09\x00\x00\x00\x00'
  55. self.connected = False
  56. self.response = None
  57. self.sanity_checks()
  58. @staticmethod
  59. def fatal_error(self, error_message, error_code=1):
  60. sys.stderr.write('ERROR: ' + str(error_message) + '\n')
  61. sys.exit(error_code)
  62. @staticmethod
  63. def exit_success(self, success_message=''):
  64. sys.stdout.write('OK: ' + str(success_message) + '\n')
  65. sys.exit(0)
  66. def responding(self):
  67. # Connect.
  68. connection = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
  69. connection.settimeout(self.server_response_timeout)
  70. try:
  71. self.connected = connection.connect((self.option.address, int(self.option.port)))
  72. except socket.timeout:
  73. self.fatal_error('Request timed out', 1)
  74. except:
  75. self.fatal_error('Unable to connect', 1)
  76. # Send.
  77. connection.send(self.query_prompt_string)
  78. # Receive.
  79. try:
  80. self.response = connection.recv(self.default_buffer_length)
  81. except socket.error:
  82. self.fatal_error('Unable to receive', 2)
  83. connection.close()
  84. # Response.
  85. if self.response is None:
  86. self.fatal_error('No response', 3)
  87. if len(self.response) < 5:
  88. sys.exit('Short response.', 3)
  89. else:
  90. self.exit_success(str(self.response))
  91. def sanity_checks(self):
  92. if not self.option.address:
  93. self.fatal_error('No IPv4 address supplied.', 4)
  94. if not self.option.port:
  95. self.fatal_error('No port supplied.', 4)
  96. if __name__ == '__main__':
  97. parser = optparse.OptionParser(
  98. usage='usage: python3 %prog [options]',
  99. version='%prog 0.0.1'
  100. )
  101. parser.add_option(
  102. '-a', '--address',
  103. action='store',
  104. dest='address',
  105. default=False,
  106. help='The IPv4 address of the server.'
  107. )
  108. parser.add_option(
  109. '-p', '--port',
  110. action='store',
  111. dest='port',
  112. default=False,
  113. help='The IPv4 port of the server.'
  114. )
  115. parser.add_option(
  116. '-e', '--engine',
  117. action='store',
  118. dest='engine',
  119. default=False,
  120. help='Engine type: protocol-valve protocol-quake3 protocol-quake3 protocol-gamespy1 protocol-unreal2 ut3 minecraft minecraftbe jc2mp mumbleping soldat teeworlds'
  121. )
  122. parser.add_option(
  123. '-v', '--verbose',
  124. action='store_true',
  125. dest='verbose',
  126. default=False,
  127. help='Display verbose output.'
  128. )
  129. parser.add_option(
  130. '-d', '--debug',
  131. action='store_true',
  132. dest='debug',
  133. default=False,
  134. help='Display debugging output.'
  135. )
  136. options, arguments = parser.parse_args()
  137. server = gsquery(options, arguments)
  138. server.responding()