mirror of
https://codeberg.org/privacy1st/netcup-dns
synced 2024-12-22 23:36:04 +01:00
init
This commit is contained in:
commit
bc17a5d458
3
.gitignore
vendored
Normal file
3
.gitignore
vendored
Normal file
@ -0,0 +1,3 @@
|
||||
/.idea/
|
||||
/cfg/
|
||||
/venv/
|
24
README.md
Normal file
24
README.md
Normal file
@ -0,0 +1,24 @@
|
||||
# netcup DNS
|
||||
|
||||
Update DNS records with your current external IP address using the netcup DNS API.
|
||||
|
||||
## TODOs
|
||||
|
||||
Alternative external IP detection:
|
||||
|
||||
```python
|
||||
def external_ip_upnp():
|
||||
"""
|
||||
https://stackoverflow.com/a/41385033
|
||||
|
||||
Didn't work for me. Even after double checking fritz.box settings:
|
||||
|
||||
fritz.box > Heimnetz > Netzwerk > Statusinformationen über UPnP übertragen
|
||||
"""
|
||||
import miniupnpc
|
||||
u = miniupnpc.UPnP()
|
||||
u.discoverdelay = 1000
|
||||
u.discover()
|
||||
u.selectigd()
|
||||
print('external ip address: {}'.format(u.externalipaddress()))
|
||||
```
|
88
main.py
Normal file
88
main.py
Normal file
@ -0,0 +1,88 @@
|
||||
import configparser
|
||||
import ipaddress
|
||||
from pathlib import Path
|
||||
|
||||
import requests
|
||||
from nc_dnsapi import Client, DNSRecord
|
||||
|
||||
|
||||
def main():
|
||||
"""
|
||||
https://github.com/nbuchwitz/nc_dnsapi
|
||||
"""
|
||||
destination = external_ipv4()
|
||||
|
||||
files = [file for file in Path('cfg').iterdir() if file.name.endswith('.cfg') and file.is_file()]
|
||||
for file in files:
|
||||
cfg = configparser.ConfigParser()
|
||||
cfg.read(file)
|
||||
customer = cfg['credentials']['customer']
|
||||
api_key = cfg['credentials']['api_key']
|
||||
api_password = cfg['credentials']['api_password']
|
||||
|
||||
domains = [section for section in cfg.sections() if section != 'credentials']
|
||||
|
||||
with Client(customer, api_key, api_password) as api:
|
||||
for domain in domains:
|
||||
hostname = cfg[domain]['hostname']
|
||||
type_ = cfg[domain]['type']
|
||||
update_record_destination(api, domain, hostname, type_, destination)
|
||||
|
||||
|
||||
def update_record_destination(api: Client, domain: str, hostname: str, type_: str, destination: str) -> None:
|
||||
record = get_record(api, domain, hostname, type_)
|
||||
record.destination = destination
|
||||
api.update_dns_record(domain, record)
|
||||
|
||||
|
||||
def get_record(api: Client, domain: str, hostname: str, type_: str) -> DNSRecord:
|
||||
records: list[DNSRecord] = api.dns_records(domain)
|
||||
record: DNSRecord
|
||||
|
||||
matches = [record for record in records if record.hostname == hostname and record.type == type_]
|
||||
if len(matches) != 1:
|
||||
raise Exception(f'Expected one DNSRecord for {hostname}.{domain}, but got {len(matches)}')
|
||||
return matches[0]
|
||||
|
||||
|
||||
def external_ipv4() -> str:
|
||||
"""
|
||||
:return: Public IPv4 address
|
||||
"""
|
||||
|
||||
# IPv4 only.
|
||||
endpoints = ['https://checkipv4.dedyn.io/', 'https://api.ipify.org', 'https://v4.ident.me/']
|
||||
# Not sure if they return IPv4 addresses only,
|
||||
# so we try these endpoints last.
|
||||
endpoints += ['https://ipinfo.io/ip']
|
||||
|
||||
for endpoint in endpoints:
|
||||
backup = None
|
||||
try:
|
||||
# Force the usage of IPv4
|
||||
# https://stackoverflow.com/a/72440253/6334421
|
||||
#
|
||||
# Alternatively, use urllib3: https://stackoverflow.com/a/46972341/6334421
|
||||
backup = requests.packages.urllib3.util.connection.HAS_IPV6
|
||||
requests.packages.urllib3.util.connection.HAS_IPV6 = False
|
||||
|
||||
# Timeout after 5 seconds.
|
||||
ip = requests.get(endpoint, timeout=5).text.strip()
|
||||
# Check if it is actually an IPv4 address.
|
||||
# Some services, such as e.g. v4.ident.me, sometimes return IPv6.
|
||||
ipv4 = ipaddress.ip_address(ip)
|
||||
if not isinstance(ipv4, ipaddress.IPv4Address):
|
||||
continue
|
||||
# Return ip address as string.
|
||||
return ipv4.exploded
|
||||
except Exception as _e:
|
||||
continue
|
||||
finally:
|
||||
# Allow usage of IPv6 again.
|
||||
if backup is not None:
|
||||
requests.packages.urllib3.util.connection.HAS_IPV6 = backup
|
||||
raise Exception('Could not determine public IPv4 address.')
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
1
requirements.txt
Normal file
1
requirements.txt
Normal file
@ -0,0 +1 @@
|
||||
nc-dnsapi
|
Loading…
Reference in New Issue
Block a user