dns_server.py 7.5 KB

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