dns_server.py 6.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197
  1. #! /usr/bin/env python
  2. # -*- coding: utf-8 -*-
  3. # SPDX-FileCopyrightText: Copyright (C) 2015-2021 MH3SP Server Project
  4. # SPDX-License-Identifier: AGPL-3.0-or-later
  5. """Monster Hunter DNS server."""
  6. import socket
  7. from other.utils import get_default_ip
  8. try:
  9. # Python 3
  10. import socketserver as SocketServer
  11. except ImportError:
  12. # Python 2
  13. import SocketServer
  14. STR2HAX = ("97.74.103.14", "173.201.71.14")
  15. class MHTriDNSServer(SocketServer.UDPServer):
  16. """Generic DNS server class for MHTri.
  17. Empty record will point to the server IP.
  18. """
  19. record = {
  20. "cfh.wapp.wii.com": STR2HAX,
  21. # Nintendo WFC
  22. "gpcm.gs.nintendowifi.net": "",
  23. "gpsp.gs.nintendowifi.net": "",
  24. "naswii.nintendowifi.net": "",
  25. "nas.nintendowifi.net": "",
  26. "gamestats.gs.nintendowifi.net": "",
  27. "gamestats2.gs.nintendowifi.net": "",
  28. "wiinat.available.gs.nintendowifi.net": "",
  29. "wiinat.natneg1.gs.nintendowifi.net": "",
  30. "wiinat.natneg2.gs.nintendowifi.net": "",
  31. "wiinat.natneg3.gs.nintendowifi.net": "",
  32. # Monster Hunter 3 (JAP)
  33. "monhunter3wii.gamestats.gs.nintendowifi.net": "",
  34. "monhunter3wii.gamestats2.gs.nintendowifi.net": "",
  35. "monhunter3wii.available.gs.nintendowifi.net": "",
  36. "monhunter3wii.natneg1.gs.nintendowifi.net": "",
  37. "monhunter3wii.natneg2.gs.nintendowifi.net": "",
  38. "monhunter3wii.natneg3.gs.nintendowifi.net": "",
  39. "monhunter3wii.master.gs.nintendowifi.net": "",
  40. "monhunter3wii.ms16.gs.nintendowifi.net": "",
  41. # Monster Hunter 3 (EU/US)
  42. "mh3uswii.available.gs.nintendowifi.net": "",
  43. "mh3uswii.natneg1.gs.nintendowifi.net": "",
  44. "mh3uswii.natneg2.gs.nintendowifi.net": "",
  45. "mh3uswii.natneg3.gs.nintendowifi.net": "",
  46. "mh3uswii.master.gs.nintendowifi.net": "",
  47. "mh3uswii.gamestats.gs.nintendowifi.net": "",
  48. "mh3uswii.gamestats2.gs.nintendowifi.net": "",
  49. "mh3uswii.ms1.gs.nintendowifi.net": "",
  50. # Wiimmfi
  51. "gpcm.gs.wiimmfi.de": "",
  52. "gpsp.gs.wiimmfi.de": "",
  53. "naswii.wiimmfi.de": "",
  54. "nas.wiimmfi.de": "",
  55. "gamestats.gs.wiimmfi.de": "",
  56. "gamestats2.gs.wiimmfi.de": "",
  57. "wiinat.available.gs.wiimmfi.de": "",
  58. "wiinat.natneg1.gs.wiimmfi.de": "",
  59. "wiinat.natneg2.gs.wiimmfi.de": "",
  60. "wiinat.natneg3.gs.wiimmfi.de": "",
  61. # Monster Hunter 3 (JAP)
  62. "monhunter3wii.gamestats.gs.wiimmfi.de": "",
  63. "monhunter3wii.gamestats2.gs.wiimmfi.de": "",
  64. "monhunter3wii.available.gs.wiimmfi.de": "",
  65. "monhunter3wii.natneg1.gs.wiimmfi.de": "",
  66. "monhunter3wii.natneg2.gs.wiimmfi.de": "",
  67. "monhunter3wii.natneg3.gs.wiimmfi.de": "",
  68. "monhunter3wii.master.gs.wiimmfi.de": "",
  69. "monhunter3wii.ms16.gs.wiimmfi.de": "",
  70. # Monster Hunter 3 (EU/US)
  71. "mh3uswii.available.gs.wiimmfi.de": "",
  72. "mh3uswii.natneg1.gs.wiimmfi.de": "",
  73. "mh3uswii.natneg2.gs.wiimmfi.de": "",
  74. "mh3uswii.natneg3.gs.wiimmfi.de": "",
  75. "mh3uswii.master.gs.wiimmfi.de": "",
  76. "mh3uswii.gamestats.gs.wiimmfi.de": "",
  77. "mh3uswii.gamestats2.gs.wiimmfi.de": "",
  78. "mh3uswii.ms1.gs.wiimmfi.de": "",
  79. # Capcom server
  80. "mh.capcom.co.jp": "",
  81. "mmh-t1-opn01.mmh-service.capcom.co.jp": "",
  82. "mmh-t1-opn02.mmh-service.capcom.co.jp": "",
  83. "mmh-t1-opn03.mmh-service.capcom.co.jp": "",
  84. "mmh-t1-opn04.mmh-service.capcom.co.jp": "",
  85. }
  86. def __init__(self, server_address, RequestHandlerClass,
  87. bind_and_activate=True, record={}):
  88. SocketServer.UDPServer.__init__(self,
  89. server_address,
  90. RequestHandlerClass,
  91. bind_and_activate)
  92. if len(record) > 0:
  93. self.record = record
  94. def __len__(self):
  95. return len(self.record)
  96. def __getitem__(self, key):
  97. return self.record[key]
  98. def __setitem__(self, key, item):
  99. self.record[key] = item
  100. def __delitem__(self, key):
  101. del self.record[key]
  102. def dns_pack(data, ip):
  103. """Pack DNS answer"""
  104. header = b"\x81\x80\x00\x01\x00\x01\x00\x00\x00\x00"
  105. response = b"\xc0\x0c\x00\x01\x00\x01\x00\x00\x08\x47\x00\x04"
  106. answer = data[0:2] + header + data[12:]
  107. answer += response + socket.inet_aton(ip)
  108. return answer
  109. class MHTriDNSRequestHandler(SocketServer.BaseRequestHandler):
  110. """Basic DNS request handler"""
  111. def forward(self, forwarders):
  112. if not self.server.str2hax:
  113. return None
  114. data, sock = self.request
  115. for dns_server in forwarders:
  116. s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
  117. s.sendto(data, (dns_server, 53))
  118. response, addrinfo = s.recvfrom(256)
  119. s.close()
  120. if not response:
  121. continue
  122. sock.sendto(response, self.client_address)
  123. print(">>> Forwarded via {}".format(dns_server))
  124. return True
  125. print("--- Failed to forward request!")
  126. def handle(self):
  127. data = bytearray(self.request[0])
  128. sock = self.request[1]
  129. name = data.strip()[13:].split(b'\0')[0]
  130. s = "".join("." if c < 32 else chr(c) for c in name)
  131. print("<<< {}".format(s))
  132. if s in self.server.record:
  133. record = self.server.record[s]
  134. if not record:
  135. s = get_default_ip()
  136. elif isinstance(record, tuple):
  137. if self.forward(record):
  138. return # Request forwarded successfully
  139. try:
  140. ip = socket.gethostbyname(s)
  141. print(">>> {}".format(ip))
  142. sock.sendto(dns_pack(data, ip), self.client_address)
  143. except socket.gaierror:
  144. pass
  145. if __name__ == "__main__":
  146. from argparse import ArgumentParser
  147. parser = ArgumentParser()
  148. parser.add_argument("-H", "--hostname", action="store", type=str,
  149. default=get_default_ip(), dest="host",
  150. help="set server hostname")
  151. parser.add_argument("-P", "--port", action="store", type=int,
  152. default=53, dest="port",
  153. help="set server port")
  154. parser.add_argument("--str2hax", action="store_true",
  155. help="Enable str2hax forwarder")
  156. args = parser.parse_args()
  157. server = MHTriDNSServer((args.host, args.port), MHTriDNSRequestHandler)
  158. server.str2hax = args.str2hax
  159. if args.str2hax:
  160. print("!!!")
  161. print("!!! USE STR2HAX AT YOUR OWN RISK! THIS METHOD IS DISCOURAGED!")
  162. print("!!! - IP(s): {}".format(", ".join(STR2HAX)))
  163. print("!!!")
  164. try:
  165. print("Server: {} | Port: {}".format(*server.server_address))
  166. server.serve_forever()
  167. except KeyboardInterrupt:
  168. print("[Server] Closing...")
  169. server.server_close()