Merge pull request #3 from meemo/master
Cleanup, display IP addresses with leading zeros, switch Windows build system to Nuitka
This commit is contained in:
6 files changed
+113
-103
No files matched your search
@@ -0,0 +1,2 @@
|
||||
# Auto detect text files and perform LF normalization
|
||||
* text=auto
|
||||
@@ -0,0 +1,8 @@
|
||||
.idea/
|
||||
__pycache__/
|
||||
sudomemoDNS.build/
|
||||
sudomemoDNS.dist/
|
||||
sudomemoDNS.onefile-build/
|
||||
|
||||
sudomemoDNS.exe
|
||||
|
||||
@@ -15,19 +15,21 @@ Run the .exe provided in this release. You may have to click past a warning from
|
||||
|
||||
## Running on anything else:
|
||||
|
||||
Required packages (installable with pip): `requests`, `dnslib`
|
||||
Required packages are installable with the following command:
|
||||
|
||||
Required Python version: 3+, tested with 3.6
|
||||
sudo python3 -m pip install -r requirements.txt
|
||||
|
||||
sudo <name of your python binary> sudomemoDNS.py
|
||||
Required Python version: 3.6+, tested with 3.9.9
|
||||
|
||||
sudo python3 sudomemoDNS.py
|
||||
|
||||
Note: `python3` is assumed to be the name of your python binary, if it is not then it will need to be substituted with the name and/or path of your binary.
|
||||
|
||||
## What you'll see when it starts up
|
||||
|
||||
The following will display when you start it up:
|
||||
|
||||
+===============================+
|
||||
| Sudomemo DNS Server |
|
||||
| Version 1.2 |
|
||||
| Version 1.2.1 |
|
||||
+===============================+
|
||||
|
||||
== Welcome to sudomemoDNS! ==
|
||||
@@ -40,24 +42,26 @@ The following will display when you start it up:
|
||||
Then, put these settings in for DNS on your console:
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
Primary DNS: XXX.XXX.XXX.XXX (NOTE: This value will be unique when you run the program)
|
||||
Secondary DNS: 8.8.8.8
|
||||
Secondary DNS: 008.008.008.008
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
== Getting Help ==
|
||||
Need help? Visit our Discord server or check out https://support.sudomemo.net
|
||||
|
||||
When entering your DNS settings, if the Primary DNS is displayed like this (this is an example):
|
||||
|
||||
192.168.1.7
|
||||
|
||||
then you can enter it as follows:
|
||||
|
||||
192.168.001.007
|
||||
|
||||
## Building on Windows
|
||||
|
||||
Install dnslib, requests, and pyinstaller via pip, then modify the paths in the spec file to where sudomemoDNS and the sudomemoDNS icon is stored.
|
||||
- Install Python 3.6+ (preferably 3.9). Make sure to install the x86 version for 32 bit targets.
|
||||
|
||||
Then, run the following as an administrator:
|
||||
- Install all requirements via the following command as an administrator
|
||||
|
||||
pyinstaller.exe sudomemoDNS_v1.2.spec
|
||||
```
|
||||
python -m pip install -r requirements.txt nuitka zstandard
|
||||
```
|
||||
|
||||
- Run the following (answer yes to any prompts):
|
||||
|
||||
```shell
|
||||
python -m nuitka --standalone --onefile --windows-icon-from-ico=sudomemoDNS_icon.ico -o sudomemoDNS.exe sudomemoDNS.py
|
||||
```
|
||||
|
||||
- Run `sudomemoDNS.exe`
|
||||
@@ -0,0 +1,2 @@
|
||||
requests
|
||||
dnslib
|
||||
+79
-53
@@ -1,33 +1,44 @@
|
||||
# sudomemoDNS
|
||||
|
||||
from datetime import datetime
|
||||
from json import loads
|
||||
from socket import socket, AF_INET, SOCK_DGRAM, gethostbyname
|
||||
from sys import platform
|
||||
from time import sleep
|
||||
|
||||
from dnslib import DNSLabel, QTYPE, RD, RR
|
||||
from dnslib import A, AAAA, CNAME, MX, NS, SOA, TXT
|
||||
from dnslib import DNSLabel, QTYPE, RD, RR
|
||||
from dnslib.server import DNSServer
|
||||
from requests import get
|
||||
from requests.exceptions import RequestException
|
||||
from requests.exceptions import Timeout
|
||||
|
||||
import socket
|
||||
import requests
|
||||
import json
|
||||
import sys
|
||||
|
||||
def get_platform():
|
||||
platforms = {
|
||||
'linux1' : 'Linux',
|
||||
'linux2' : 'Linux',
|
||||
'darwin' : 'macOS',
|
||||
'win32' : 'Windows'
|
||||
'linux1': 'Linux',
|
||||
'linux2': 'Linux',
|
||||
'darwin': 'macOS',
|
||||
'win32': 'Windows'
|
||||
}
|
||||
if sys.platform not in platforms:
|
||||
return sys.platform
|
||||
if platform not in platforms:
|
||||
return platform
|
||||
|
||||
return platforms[sys.platform]
|
||||
return platforms[platform]
|
||||
|
||||
|
||||
SUDOMEMODNS_VERSION = "1.2.1"
|
||||
|
||||
|
||||
# Adds preceding zeros to IP addresses
|
||||
# e.g `1.1.1.1` becomes `001.001.001.001`
|
||||
def format_ip(address):
|
||||
octets = str(address).split(".")
|
||||
return f"{int(octets[0]):03d}.{int(octets[1]):03d}.{int(octets[2]):03d}.{int(octets[3]):03d}"
|
||||
|
||||
SUDOMEMODNS_VERSION = "1.2"
|
||||
|
||||
def get_ip():
|
||||
s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
|
||||
s = socket(AF_INET, SOCK_DGRAM)
|
||||
try:
|
||||
# doesn't even have to be reachable
|
||||
s.connect(('10.255.255.255', 1))
|
||||
@@ -38,25 +49,27 @@ def get_ip():
|
||||
s.close()
|
||||
return IP
|
||||
|
||||
|
||||
EPOCH = datetime(1970, 1, 1)
|
||||
SERIAL = int((datetime.utcnow() - EPOCH).total_seconds())
|
||||
MY_IP = get_ip()
|
||||
|
||||
print("+===============================+")
|
||||
print("| Sudomemo DNS Server |")
|
||||
print("| Version " + SUDOMEMODNS_VERSION + " |")
|
||||
print(f"| Version {SUDOMEMODNS_VERSION} |")
|
||||
print("+===============================+\n")
|
||||
|
||||
print("== Welcome to sudomemoDNS! ==")
|
||||
print("This server will allow you to connect to Sudomemo when your Internet Service Provider does not work with custom DNS.\n")
|
||||
print("== Welcome to sudomemoDNS! ==")
|
||||
print(
|
||||
"This server will allow you to connect to Sudomemo when your Internet Service Provider does not work with custom DNS.\n")
|
||||
|
||||
print("== How To Use ==")
|
||||
print("First, make sure that your console is connected to the same network as this computer.\n")
|
||||
|
||||
print("Then, put these settings in for DNS on your console:")
|
||||
print("~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~")
|
||||
print("Primary DNS: ",MY_IP)
|
||||
print("Secondary DNS: 8.8.8.8")
|
||||
print(f"Primary DNS: {format_ip(MY_IP)}")
|
||||
print("Secondary DNS: 008.008.008.008")
|
||||
print("~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n")
|
||||
|
||||
print("== Getting Help ==")
|
||||
@@ -74,24 +87,32 @@ TYPE_LOOKUP = {
|
||||
TXT: QTYPE.TXT,
|
||||
}
|
||||
|
||||
|
||||
# Can't seem to turn off DNSLogger with a None type so let's just null it out with a dummy function
|
||||
|
||||
class SudomemoDNSLogger(object):
|
||||
def log_recv(self, handler, data):
|
||||
pass
|
||||
|
||||
def log_send(self, handler, data):
|
||||
pass
|
||||
|
||||
def log_request(self, handler, request):
|
||||
print("[INFO] Received DNS request from console at " + handler.client_address[0])
|
||||
|
||||
def log_reply(self, handler, reply):
|
||||
print("[INFO] Sent response to console at " + handler.client_address[0])
|
||||
|
||||
def log_error(self, handler, e):
|
||||
print("[ERROR] Invalid DNS request from " + handler.client_address[0])
|
||||
|
||||
def log_truncated(self, handler, reply):
|
||||
pass
|
||||
|
||||
def log_data(self, dnsobj):
|
||||
pass
|
||||
|
||||
|
||||
class Record:
|
||||
def __init__(self, rdata_type, *args, rtype=None, rname=None, ttl=None, **kwargs):
|
||||
if isinstance(rdata_type, RD):
|
||||
@@ -103,12 +124,12 @@ class Record:
|
||||
if rdata_type == SOA and len(args) == 2:
|
||||
# add sensible times to SOA
|
||||
args += ((
|
||||
SERIAL, # serial number
|
||||
60 * 60 * 1, # refresh
|
||||
60 * 60 * 3, # retry
|
||||
60 * 60 * 24, # expire
|
||||
60 * 60 * 1, # minimum
|
||||
),)
|
||||
SERIAL, # serial number
|
||||
60 * 60 * 1, # refresh
|
||||
60 * 60 * 3, # retry
|
||||
60 * 60 * 24, # expire
|
||||
60 * 60 * 1, # minimum
|
||||
),)
|
||||
rdata = rdata_type(*args)
|
||||
|
||||
if rtype:
|
||||
@@ -144,26 +165,28 @@ class Record:
|
||||
ZONES = {}
|
||||
|
||||
try:
|
||||
get_zones = requests.get("https://www.sudomemo.net/api/dns_zones.json", headers={'User-Agent': 'SudomemoDNS/' + SUDOMEMODNS_VERSION + ' (' + get_platform() + ')'})
|
||||
except requests.exceptions.Timeout:
|
||||
print("[ERROR] Unable to load DNS data: Connection to Sudomemo timed out. Are you connected to the Internet?")
|
||||
except requests.exceptions.RequestException as e:
|
||||
print("[ERROR] Unable load DNS data.")
|
||||
print("[ERROR] Exception: ",e)
|
||||
sys.exit(1)
|
||||
get_zones = get("https://www.sudomemo.net/api/dns_zones.json",
|
||||
headers={'User-Agent': 'SudomemoDNS/' + SUDOMEMODNS_VERSION + ' (' + get_platform() + ')'})
|
||||
except Timeout:
|
||||
print("[ERROR] Unable to load DNS data: Connection to Sudomemo timed out. Are you connected to the Internet?")
|
||||
except RequestException as e:
|
||||
print("[ERROR] Unable load DNS data.")
|
||||
print("[ERROR] Exception: ", e)
|
||||
exit(1)
|
||||
try:
|
||||
zones = json.loads(get_zones.text)
|
||||
zones = loads(get_zones.text)
|
||||
except ValueError as e:
|
||||
print("[ERROR] Unable load DNS data: Invalid response from server. Check that you can visit sudomemo.net")
|
||||
print("[ERROR] Unable load DNS data: Invalid response from server. Check that you can visit sudomemo.net")
|
||||
|
||||
for zone in zones:
|
||||
if zone["type"] == "a":
|
||||
ZONES[zone["name"]] = [ Record(A, zone["value"]) ]
|
||||
elif zone["type"] == "p":
|
||||
ZONES[zone["name"]] = [ Record(A, socket.gethostbyname(zone["value"])) ]
|
||||
if zone["type"] == "a":
|
||||
ZONES[zone["name"]] = [Record(A, zone["value"])]
|
||||
elif zone["type"] == "p":
|
||||
ZONES[zone["name"]] = [Record(A, gethostbyname(zone["value"]))]
|
||||
|
||||
print("[INFO] DNS information loaded successfully.")
|
||||
|
||||
|
||||
class Resolver:
|
||||
def __init__(self):
|
||||
self.zones = {DNSLabel(k): v for k, v in ZONES.items()}
|
||||
@@ -171,6 +194,7 @@ class Resolver:
|
||||
def resolve(self, request, handler):
|
||||
reply = request.reply()
|
||||
zone = self.zones.get(request.q.qname)
|
||||
|
||||
if zone is not None:
|
||||
for zone_records in zone:
|
||||
rr = zone_records.try_rr(request.q)
|
||||
@@ -196,26 +220,28 @@ dnsLogger = SudomemoDNSLogger()
|
||||
print("[INFO] Detected operating system:", get_platform())
|
||||
|
||||
if get_platform() == 'linux':
|
||||
print("[INFO] Please note that you will have to run this as root or with permissions to bind to UDP port 53.")
|
||||
print("[INFO] If you aren't seeing any requests, check that this is the case first with lsof -i:53 (requires lsof)")
|
||||
print("[INFO] To run as root, prefix the command with 'sudo'")
|
||||
print("[INFO] Please note that you will have to run this as root or with permissions to bind to UDP port 53.")
|
||||
print("[INFO] If you aren't seeing any requests, check that this is the case first with lsof -i:53 (requires lsof)")
|
||||
print("[INFO] To run as root, prefix the command with 'sudo'")
|
||||
elif get_platform() == 'macOS':
|
||||
print("[INFO] Please note that you will have to run this as root or with permissions to bind to UDP port 53.")
|
||||
print("[INFO] If you aren't seeing any requests, check that this is the case first with lsof -i:53 (requires lsof)")
|
||||
print("[INFO] To run as root, prefix the command with 'sudo'")
|
||||
print("[INFO] Please note that you will have to run this as root or with permissions to bind to UDP port 53.")
|
||||
print("[INFO] If you aren't seeing any requests, check that this is the case first with lsof -i:53 (requires lsof)")
|
||||
print("[INFO] To run as root, prefix the command with 'sudo'")
|
||||
elif get_platform() == 'Windows':
|
||||
print("[INFO] Please note that you may have to allow this application through the firewall. If so, a popup will appear in a moment.")
|
||||
print("[INFO] If you are not seeing any requests, make sure you have allowed this application through the firewall. If you have already done so, disregard this message.")
|
||||
print(
|
||||
"[INFO] Please note that you may have to allow this application through the firewall. If so, a popup will appear in a moment.")
|
||||
print(
|
||||
"[INFO] If you are not seeing any requests, make sure you have allowed this application through the firewall. If you have already done so, disregard this message.")
|
||||
|
||||
try:
|
||||
servers = [
|
||||
DNSServer(resolver=resolver, port=53, address=MY_IP, tcp=True, logger=dnsLogger),
|
||||
DNSServer(resolver=resolver, port=53, address=MY_IP, tcp=False, logger=dnsLogger),
|
||||
]
|
||||
except PermissionError:
|
||||
print("[ERROR] Permission error: Check that you are running this as an administrator or root")
|
||||
sys.exit(1)
|
||||
servers = [
|
||||
DNSServer(resolver=resolver, port=53, address=MY_IP, tcp=True, logger=dnsLogger),
|
||||
DNSServer(resolver=resolver, port=53, address=MY_IP, tcp=False, logger=dnsLogger)
|
||||
]
|
||||
|
||||
except PermissionError:
|
||||
print("[ERROR] Permission error: Check that you are running this as an administrator or root")
|
||||
exit(1)
|
||||
|
||||
print("[INFO] sudomemoDNS is ready. Now waiting for DNS requests from your console...")
|
||||
|
||||
|
||||
@@ -1,32 +0,0 @@
|
||||
# -*- mode: python -*-
|
||||
|
||||
block_cipher = None
|
||||
|
||||
|
||||
a = Analysis(['sudomemoDNS.py'],
|
||||
pathex=['C:\\PATH\\TO\\SUDOMEMODNS'],
|
||||
binaries=[],
|
||||
datas=[],
|
||||
hiddenimports=[],
|
||||
hookspath=[],
|
||||
runtime_hooks=[],
|
||||
excludes=[],
|
||||
win_no_prefer_redirects=False,
|
||||
win_private_assemblies=False,
|
||||
cipher=block_cipher,
|
||||
noarchive=False)
|
||||
pyz = PYZ(a.pure, a.zipped_data,
|
||||
cipher=block_cipher)
|
||||
exe = EXE(pyz,
|
||||
a.scripts,
|
||||
a.binaries,
|
||||
a.zipfiles,
|
||||
a.datas,
|
||||
[],
|
||||
name='sudomemoDNS_v1.2',
|
||||
debug=False,
|
||||
bootloader_ignore_signals=False,
|
||||
strip=False,
|
||||
upx=True,
|
||||
runtime_tmpdir=None,
|
||||
console=True , icon='C:\\PATH\\TO\\SUDOMEMODNS\\ICON.ico')
|
||||
Reference in new issue
Block a user
