dyndns package

Module contents

Set version.

Submodules

dyndns.cli module

Command line interface for the command dyndns-debug

dyndns.cli.get_argparser() ArgumentParser[source]
dyndns.cli.main() None[source]

dyndns.config module

Load and validate the configuration.

dyndns.config.validate_ip_address_by_version(address: Any, ip_version: Literal[4, 6] | None = None) tuple[str, Literal[4, 6]][source]
dyndns.config.validate_ip_address(address: str) str[source]
dyndns.config.validate_secret(secret: str) str[source]
dyndns.config.validate_port(port: int) int[source]
dyndns.config.validate_name(name: str) str[source]

Validate the given DNS name. A dot is appended to the end of the DNS name if it is not already present.

Parameters:

name – The DNS name to be validated.

Returns:

The validated DNS name as a string.

dyndns.config.validate_tsig_key(tsig_key: str) str[source]

Validates a TSIG key.

Parameters:

tsig_key – The TSIG key to validate.

Returns:

The validated TSIG key.

Raises:

NamesError – If the TSIG key is invalid.

class dyndns.config.ZoneConfig(*, name: str, tsig_key: str)[source]

Bases: BaseModel

model_config: ClassVar[ConfigDict]

Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].

name: Name

The domain name of the zone, for example dyndns.example.com.

tsig_key: TsigKey

The tsig-key. Use the hmac-sha512 algorithm to generate the key: tsig-keygen -a hmac-sha512 dyndns.example.com

class dyndns.config.Config(*, secret: str, nameserver: IPv4Address | IPv6Address, port: int = 53, log_level: int = 20, zones: list[ZoneConfig])[source]

Bases: BaseModel

model_config: ClassVar[ConfigDict]

Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].

secret: Secret

A password-like secret string. The secret string must be at least 8 characters long and only alphanumeric characters are permitted.

nameserver: ipaddress.IPv4Address | ipaddress.IPv6Address

The IP address of your nameserver. Version 4 or version 6 are allowed. Use 127.0.0.1 to communicate with your nameserver on the same machine.

port: Port

The port to which the DNS server listens. If the DNS server listens to port 53 by default, the value does not need to be specified.

log_level: Annotated[int, Field(ge=0, le=50)]

Values from 0 (everything is logged) to 50 (only critical message are logged) are allowed. The default value is 20.

See:

dyndns.log.LogLevel

zones: ZonesList

At least one zone specified as a list.

dyndns.config.load_config(config_file: str | Path | None = None) Config[source]

Load the configuration from the specified file or from the default locations.

Parameters:

config_file – The path to the configuration file. If not provided, the function will search for the configuration file in the default locations.

Returns:

The loaded configuration as a dictionary.

Raises:

ConfigurationError – If the configuration file could not be found.

dyndns.dns module

Query the DSN server using the package “dnspython”.

class dyndns.dns.DnsChangeMessage(fqdn: str, old: str | None, new: str | None, record_type: Literal['A', 'AAAA', 'TXT'])[source]

Bases: object

fqdn: str
old: str | None
new: str | None
record_type: Literal['A', 'AAAA', 'TXT']
property changed: bool
class dyndns.dns.DnsZone(nameserver: str, port: int, zone: Zone)[source]

Bases: object

add_record(name: str, record_type: Literal['A', 'AAAA', 'TXT'], content: str, ttl: int = 300) DnsChangeMessage[source]

Add one record. All existing records with the same name and same record type are deleted before a new record is added.

Parameters:
  • name – A record name (e. g. dyndns) or a fully qualified domain name (e. g. dyndns.example.com).

  • record_type – The type of the resource record. dyndns supports only A, AAAA and TXT record types.

read_resource_record_set(name: str, record_type: Literal['A', 'AAAA', 'TXT']) RRset | None[source]
Parameters:
  • name – A record name (e. g. dyndns) or a fully qualified domain name (e. g. dyndns.example.com).

  • record_type – The type of the resource record. dyndns supports only A, AAAA and TXT record types.

read_record(name: str, record_type: Literal['A', 'AAAA', 'TXT']) str | None[source]

Read one record.

Parameters:
  • name – A record name (e. g. dyndns) or a fully qualified domain name (e. g. dyndns.example.com).

  • record_type – The type of the resource record. dyndns supports only A, AAAA and TXT record types.

read_a_record(name: str) str | None[source]

Read an IPv4 address record.

Parameters:

name – A record name (e. g. dyndns) or a fully qualified domain name (e. g. dyndns.example.com).

Returns:

An IPv4 address.

read_aaaa_record(name: str) str | None[source]

Read an IPv6 address record.

Parameters:

name – A record name (e. g. dyndns) or a fully qualified domain name (e. g. dyndns.example.com).

Returns:

An IPv6 address.

is_a_record(name: str) bool[source]

Return True if the specified name has an A record (IPv4).

Parameters:

name – A record name (e. g. dyndns) or a fully qualified domain name (e. g. dyndns.example.com).

Returns:

True` if the specified name has an A record (IPv4).

is_aaaa_record(name: str) bool[source]

Return True if the specified name has an AAAA record (IPv6).

Parameters:

name – A record name (e. g. dyndns) or a fully qualified domain name (e. g. dyndns.example.com).

Returns:

True` if the specified name has an AAAA record (IPv6).

delete_record(name: str, record_type: Literal['A', 'AAAA', 'TXT'] = 'A') DnsChangeMessage[source]

Delete one record or multiple records of a specific record type.

Parameters:
  • name – A record name (e. g. dyndns) or a fully qualified domain name (e. g. dyndns.example.com).

  • record_type – The type of the resource record. dyndns supports only A, AAAA and TXT record types.

delete_records(name: str) None[source]

Delete all A and the AAAA records.

Parameters:

name – A record name (e. g. dyndns) or a fully qualified domain name (e. g. dyndns.example.com).

check() str[source]

Check the functionality of the DNS server by creating a temporary text record.

dyndns.exceptions module

A collection of exceptions.

exception dyndns.exceptions.DyndnsError[source]

Bases: Exception

Base exception of the package dyndns.

status_code: int

https://www.iana.org/assignments/http-status-codes/http-status-codes.xhtml

log_level: LogLevel
exception dyndns.exceptions.DnsNameError[source]

Bases: DyndnsError

This error gets thrown by invalid DNS names.

log_level: LogLevel
status_code: int

https://www.iana.org/assignments/http-status-codes/http-status-codes.xhtml

exception dyndns.exceptions.IpAddressesError[source]

Bases: DyndnsError

This error gets thrown by invalid IP addresses.

log_level: LogLevel
status_code: int

https://www.iana.org/assignments/http-status-codes/http-status-codes.xhtml

exception dyndns.exceptions.ConfigurationError[source]

Bases: DyndnsError

An error if dyndns has been configured incorrectly. This mainly affects the configuration file in YAML format (/etc/dyndns.yml oder ~/.dyndns.yml).

log_level: LogLevel
status_code: int

https://www.iana.org/assignments/http-status-codes/http-status-codes.xhtml

exception dyndns.exceptions.ParameterError[source]

Bases: DyndnsError

Client side parameter error.

log_level: LogLevel
status_code: int

https://www.iana.org/assignments/http-status-codes/http-status-codes.xhtml

exception dyndns.exceptions.CheckError[source]

Bases: DyndnsError

The check failed.

log_level: LogLevel
status_code: int

https://www.iana.org/assignments/http-status-codes/http-status-codes.xhtml

exception dyndns.exceptions.DNSServerError[source]

Bases: DyndnsError

Communicating with the external DNS server.

log_level: LogLevel
status_code: int

https://www.iana.org/assignments/http-status-codes/http-status-codes.xhtml

dyndns.ipaddresses module

Deal with ipv4 and ipv6 IP addresses.

dyndns.ipaddresses.format_attr(ip_version: Literal[4, 6]) str[source]
class dyndns.ipaddresses.IpAddressContainer(ip_1: str | None = None, ip_2: str | None = None, ipv4: str | None = None, ipv6: str | None = None, request: Request | None = None)[source]

Bases: object

A container class to store and detect IP addresses in both versions (ipv4 and ipv6).

Parameters:
  • ip_1 (str) – An IP address of unkown version.

  • ip_2 (str) – An IP address of unkown version.

  • ipv4 (str) – An IPv4 IP address.

  • ipv6 (str) – An IPv6 IP address.

request: Request
ipv4: str | None

The IPv4 address to update the DNS record with.

ipv6: str | None

The IPv6 address to update the DNS record with.

dyndns.log module

Bundle the logging functionality.

class dyndns.log.Update[source]

Bases: TypedDict

update_time: str
updated: bool
fqdn: str
record_type: str
ip: str
class dyndns.log.LogLevel(value)[source]

Bases: Enum

Define more log levels than the default Pythons levels in order to control more precisely what is logged and what is not.

https://docs.python.org/3/library/logging.html#logging-levels

CRITICAL

The Python default log level value for an critical message.

CONFIGURATION_ERROR

If dyndns has been configured incorrectly. This mainly affects the configuration file in YAML format (/etc/dyndns.yml oder ~/.dyndns.yml).

See:

dyndns.exceptions.ConfigurationError

DNS_SERVER_ERROR
See:

dyndns.exceptions.DNSServerError

IP_ADDRESS_ERROR
See:

dyndns.exceptions.IpAddressesError

DNS_NAME_ERROR
See:

dyndns.exceptions.DnsNameError

PARAMETER_ERROR
See:

dyndns.exceptions.ParameterError

CHECK_ERROR
See:

dyndns.exceptions.CheckError

ERROR

The Python default log level value for an error.

WARNING

The Python default log level value for an warning.

UPDATED
INFO

The Python default log level value for an information message.

UNCHANGED
DEBUG

The Python default log level value for a debug message.

NOTSET

The Python default log level value for an not set log level.

classmethod get_name(value: int) str[source]
log(message: str) str[source]
class dyndns.log.Logger[source]

Bases: object

log(log_level: LogLevel | int, message: object) str[source]
log_change(message: DnsChangeMessage) str[source]
set_level(level: int | LogLevel) None[source]

dyndns.names module

Deal with different kind of names (FQDNs (Fully Qualified Domain Names), record and zone names)

record_name + zone_name = fqdn

class dyndns.names.FullyQualifiedDomainName(zones: ZonesCollection, fqdn: str | None = None, zone_name: str | None = None, record_name: str | None = None)[source]

Bases: object

Stores a FQDN (Fully Qualified Domain Names), a zone name and a record along with the TSIG (Transaction SIGnature) key.

record_name + zone_name = fqdn

Parameters:
  • zones – The ZonesCollection object.

  • fqdn – The Fully Qualified Domain Name (e. g. www.example.com.).

  • zone_name – The zone name (e. g. example.com.).

  • record_name – The name of the resource record (e. g. www.).

Raises:
  • NamesError – If both fqdn and zone_name/record_name are specified.

  • NamesError – If record_name is not provided.

  • NamesError – If zone_name is not provided.

fqdn: str

The Fully Qualified Domain Name (e. g. www.example.com.).

zone_name: str

The zone name (e. g. example.com.).

record_name: str

The name of the resource record (e. g. www.).

tsig_key: str

The TSIG (Transaction SIGnature) key (e. g. tPyvZA==)

dyndns.webapp module

Initialize the Flask app.

class dyndns.webapp.UpdateQueryParams(*, secret: str, fqdn: str | None = None, zone_name: str | None = None, record_name: str | None = None, ip_1: str | None = None, ip_2: str | None = None, ipv4: str | None = None, ipv6: str | None = None, ttl: int = 300)[source]

Bases: BaseModel

model_config: ClassVar[ConfigDict]

Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].

secret: str
fqdn: str | None
zone_name: str | None
record_name: str | None
ip_1: str | None
ip_2: str | None
ipv4: str | None
ipv6: str | None
ttl: int
dyndns.webapp.create_app(env: ConfiguredEnvironment) Flask[source]

dyndns.zones module

class dyndns.zones.Zone(name: str, tsig_key: str)[source]

Bases: object

Stores the zone name together with the corresponding TSIG (Transaction SIGnature) key.

Parameters:
  • zone_name – The zone name (e. g. example.com.).

  • tsig_key – The TSIG (Transaction SIGnature) key (e. g. tPyvZA==).

name: str

The zone name (e. g. example.com.).

tsig_key: str

The TSIG (Transaction SIGnature) key (e. g. tPyvZA==).

get_record_name(name: str) str[source]

Remove the zone from the given DNS name.

Parameters:

name – A record name (e. g. dyndns) or a fully qualified domain name (e. g. dyndns.example.com).

Returns:

The record name (e. g. dyndns.).

get_fqdn(name: str) str[source]

Build a fully qualified domain name.

Parameters:

name – A record name (e. g. dyndns) or a fully qualified domain name (e. g. dyndns.example.com).

Returns:

The fully qualified domain name.

split_fqdn(name: str) tuple[str, str][source]

Split hostname into record_name and zone_name for example: www.example.com -> www. example.com.

Parameters:

name – A record name (e. g. dyndns) or a fully qualified domain name (e. g. dyndns.example.com).

Returns:

A tuple containing the record name and zone name.

class dyndns.zones.ZonesCollection(zones_config: list[ZoneConfig])[source]

Bases: object

zones: dict[str, Zone]
get_zone(name: str) Zone[source]

Get a zone by a DNS name.

Parameters:

name – The DNS name. It can be a fully qualified domain name containing the zone name or the zone name itself.

Returns:

The requested zone.

Raises:

DnsNameError – if the zone could not be found.

split_fqdn(fqdn: str) tuple[str, str] | None[source]

Split a fully qualified domain name into a record name and a zone name, for example: www.example.com -> www. example.com.

Parameters:

fqdn – The fully qualified domain name.

Returns:

A tuple containing two entries: The first is the record name and the second is the zone name.