Skip to content

Commit 0033520

Browse files
authored
Merge pull request #101 from nautobot/release-1.2.0
Release 1.2.0
2 parents 3c2a3a0 + 0b5d147 commit 0033520

File tree

17 files changed

+1398
-653
lines changed

17 files changed

+1398
-653
lines changed

docs/admin/install.md

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -65,4 +65,14 @@ sudo systemctl restart nautobot nautobot-worker nautobot-scheduler
6565

6666
## App Configuration
6767

68-
There are no specific options to add to `nautobot_config.py` at this time.
68+
This option is configured via the Admin GUI.
69+
70+
`DNS_VALIDATION_LEVEL` (default: "Wire format")
71+
72+
This setting controls the DNS validation level applied to zones and records:
73+
74+
- **Disabled** - No DNS validation is performed
75+
- **Wire format** - Enforces DNS label and name length rules as specified in [RFC 1035 §3.1](https://datatracker.ietf.org/doc/html/rfc1035#section-3.1):
76+
- Each label (the parts of the name separated by dots) must be no more than 63 bytes in wire format
77+
- Empty labels (e.g., consecutive dots or leading/trailing dots) are not allowed
78+
- The total length of the fully qualified DNS name (including all dots, in wire format) must not exceed 255 bytes
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
2+
# v1.2 Release Notes
3+
4+
This document describes all new features and changes in the release. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/) and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
5+
6+
## Release Overview
7+
8+
This release makes DNS models globally searchable in Nautobot and added DNS name length validation per RFC 1035.
9+
10+
## [v1.2.0 (2025-07-25)](https://github.com/nautobot/nautobot-app-dns-models/releases/tag/v1.2.0)
11+
12+
### Added
13+
14+
- [#93](https://github.com/nautobot/nautobot-app-dns-models/issues/93) - Added searchable models to the app config to make DNS models globally searchable.
15+
16+
### Changed
17+
18+
- [#87](https://github.com/nautobot/nautobot-app-dns-models/issues/87) - Changed TTL of DNS Records to be optional and inherited from the zone if no value is provided.
19+
20+
### Fixed
21+
22+
- [#45](https://github.com/nautobot/nautobot-app-dns-models/issues/45) - Fixed issue where ARecord model would accept IPv6 addresses.
23+
- [#45](https://github.com/nautobot/nautobot-app-dns-models/issues/45) - Fixed issue where AAAARecords model would accept IPv4 addresses.
24+
- [#76](https://github.com/nautobot/nautobot-app-dns-models/issues/76) - Added DNS name length validation per RFC 1035 §3.1 for zone and record names.
25+
- [#98](https://github.com/nautobot/nautobot-app-dns-models/issues/98) - Fixed conflicting migrations.
26+
- [#102](https://github.com/nautobot/nautobot-app-dns-models/issues/102) - Fixed unittest for PTRRecordModelViewTest.

docs/models/aaaarecordmodel.md

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1 +1,10 @@
11
# AAAA Record Model
2+
3+
The AAAA Record model is used to represent IPv6 address records in DNS. It maps a hostname to an IPv6 address.
4+
5+
- `name` (string): FQDN of the record, without TLD.
6+
- `zone` (DNSZoneModel): The DNS zone this record belongs to.
7+
- `ttl` (integer): Time to live for the record.
8+
- `description` (string): Description of the record.
9+
- `comment` (string): Comment for the record.
10+
- `address` (IPAddress): IPv6 address for the record (AAAA records must use IPv6).

docs/models/arecordmodel.md

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1 +1,11 @@
11
# A Record Model
2+
# A Record Model
3+
4+
The A Record model is used to represent IPv4 address records in DNS. It maps a hostname to an IPv4 address.
5+
6+
- `name` (string): FQDN of the record, without TLD.
7+
- `zone` (DNSZoneModel): The DNS zone this record belongs to.
8+
- `ttl` (integer): Time to live for the record.
9+
- `description` (string): Description of the record.
10+
- `comment` (string): Comment for the record.
11+
- `address` (IPAddress): IPv4 address for the record (A records must use IPv4).

docs/models/dnsrecordmodel.md

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1 +1,11 @@
11
# DNS Record Model
2+
3+
+++ 1.2.0 "DNS name length rules"
4+
5+
When DNS validation is enabled (via the `DNS_VALIDATION_LEVEL` configuration), `DNSRecordModel` enforces the following DNS label and name length rules, as specified by [RFC 1035 §3.1](https://datatracker.ietf.org/doc/html/rfc1035#section-3.1):
6+
7+
- Each label (the parts of the name separated by dots) must be no more than 63 bytes in wire format
8+
- Empty labels (e.g., consecutive dots or leading/trailing dots) are not allowed
9+
- The total length of the fully qualified DNS name (including the zone and all dots, in wire format) must not exceed 255 bytes
10+
11+
See the [installation guide](../admin/install.md#app-configuration) for configuration options.

docs/models/dnszonemodel.md

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,3 +13,12 @@ The DNS zone model is used to represent a distinct DNS zone. It contains the zon
1313
- `soa_expire`: (integer): Time in seconds for secondary name servers to stop answering requests if the master does not respond. This value must be bigger than the sum of refresh and retry.
1414
- `soa_serial`: (integer): Serial number of the zone. This value must be incremented each time the zone is changed, and secondary DNS servers must be able to retrieve this value to check if the zone has been updated.
1515
- `soa_minimum`: (integer): Minimum TTL for records in this zone.
16+
17+
+++ 1.2.0 "DNS label length rules"
18+
19+
When DNS validation is enabled (via the `DNS_VALIDATION_LEVEL` configuration), `DNSZoneModel` enforces the following DNS label length rules, as specified by [RFC 1035 §3.1](https://datatracker.ietf.org/doc/html/rfc1035#section-3.1):
20+
21+
- Each label (the parts of the name separated by dots) must be no more than 63 bytes in wire format
22+
- Empty labels (e.g., consecutive dots or leading/trailing dots) are not allowed
23+
24+
See the [installation guide](../admin/install.md#app-configuration) for configuration options.

docs/user/faq.md

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,3 +3,29 @@
33
## Does this App turn Nautobot into a DDI Solution?
44

55
No, but you now have DNS as well as IPAM data in one place, so you can write your own automation, like Nautobot Jobs, to deploy/verify configuration on your servers!
6+
7+
## DNS Naming Rules and Internationalization
8+
9+
### Why does my internationalized domain name (or label) fail validation even though it looks short enough?
10+
For internationalized names (those containing non-ASCII characters), the DNS protocol uses a special encoding called IDNA (Internationalized Domain Names in Applications). Some characters use more than one byte in this encoding, so a label or name may reach the 63-byte (per label) or 255-byte (full name) limit before it reaches 63 or 255 characters.
11+
12+
!!! tip
13+
If you see a length error, try using fewer characters or only ASCII letters and digits. The app checks the encoded (wire format) length, not just the visible character count.
14+
15+
---
16+
17+
### What DNS standards does this app follow for name validation?
18+
This app enforces DNS naming rules as specified in:
19+
20+
- **[RFC 1035 §2.3.4](https://datatracker.ietf.org/doc/html/rfc1035#section-2.3.4):**
21+
Maximum label (63 bytes) and full name (255 bytes) length limits for DNS.
22+
23+
This ensures that all DNS names are valid, interoperable, and compatible with the global DNS system.
24+
25+
!!! note
26+
DNS validation can be configured or disabled via the `DNS_VALIDATION_LEVEL` setting. See the [installation guide](../admin/install.md#app-configuration) for details.
27+
28+
---
29+
30+
### What does "wire format" mean in the context of DNS names?
31+
"Wire format" refers to the way DNS names are encoded for transmission over the network. Each label is encoded using the IDNA 2003 standard, and the total length (in bytes) of all labels and dots must not exceed 255 bytes. This is stricter than simply counting characters, especially for internationalized names.

mkdocs.yml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -83,6 +83,7 @@ markdown_extensions:
8383
class: "mermaid"
8484
format: !!python/name:pymdownx.superfences.fence_code_format
8585
- "pymdownx.blocks.caption"
86+
- "pymdownx.details"
8687
- "footnotes"
8788
plugins:
8889
- "search"
@@ -128,6 +129,7 @@ nav:
128129
- Compatibility Matrix: "admin/compatibility_matrix.md"
129130
- Release Notes:
130131
- "admin/release_notes/index.md"
132+
- v1.2: "admin/release_notes/version_1.2.md"
131133
- v1.1: "admin/release_notes/version_1.1.md"
132134
- v1.0: "admin/release_notes/version_1.0.md"
133135
- v0.2: "admin/release_notes/version_0.2.md"

nautobot_dns_models/__init__.py

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,16 @@
1919
],
2020
},
2121
],
22+
"dns_validation_level": [
23+
"django.forms.fields.ChoiceField",
24+
{
25+
"widget": "django.forms.Select",
26+
"choices": [
27+
("none", "Disabled"),
28+
("wire-format", "Wire format"),
29+
],
30+
},
31+
],
2232
}
2333

2434
# pylint:disable=no-member
@@ -52,7 +62,24 @@ class NautobotDnsModelsConfig(NautobotAppConfig):
5262
help_text="Show PTR Records panel in IP Address detailed view.",
5363
field_type="show_dns_panel",
5464
),
65+
"DNS_VALIDATION_LEVEL": ConstanceConfigItem(
66+
default="wire-format",
67+
help_text="DNS validation level for zones and records.",
68+
field_type="dns_validation_level",
69+
),
5570
}
5671

72+
searchable_models = [
73+
"DNSZoneModel",
74+
"ARecordModel",
75+
"AAAARecordModel",
76+
"PTRRecordModel",
77+
"CNAMERecordModel",
78+
"NSRecordModel",
79+
"MXRecordModel",
80+
"SRVRecordModel",
81+
"TXTRecordModel",
82+
]
83+
5784

5885
config = NautobotDnsModelsConfig # pylint:disable=invalid-name
Lines changed: 157 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,157 @@
1+
# Generated by Django 4.2.21 on 2025-06-27 14:24
2+
3+
import django.core.validators
4+
import django.db.models.deletion
5+
from django.db import migrations, models
6+
7+
8+
class Migration(migrations.Migration):
9+
dependencies = [
10+
("ipam", "0051_added_optional_vrf_relationship_to_vdc"),
11+
("nautobot_dns_models", "0002_srvrecordmodel"),
12+
]
13+
14+
operations = [
15+
migrations.RemoveField(
16+
model_name="aaaarecordmodel",
17+
name="ttl",
18+
),
19+
migrations.RemoveField(
20+
model_name="arecordmodel",
21+
name="ttl",
22+
),
23+
migrations.RemoveField(
24+
model_name="cnamerecordmodel",
25+
name="ttl",
26+
),
27+
migrations.RemoveField(
28+
model_name="mxrecordmodel",
29+
name="ttl",
30+
),
31+
migrations.RemoveField(
32+
model_name="nsrecordmodel",
33+
name="ttl",
34+
),
35+
migrations.RemoveField(
36+
model_name="ptrrecordmodel",
37+
name="ttl",
38+
),
39+
migrations.RemoveField(
40+
model_name="srvrecordmodel",
41+
name="ttl",
42+
),
43+
migrations.RemoveField(
44+
model_name="txtrecordmodel",
45+
name="ttl",
46+
),
47+
migrations.AddField(
48+
model_name="aaaarecordmodel",
49+
name="_ttl",
50+
field=models.IntegerField(
51+
blank=True,
52+
null=True,
53+
validators=[
54+
django.core.validators.MinValueValidator(300),
55+
django.core.validators.MaxValueValidator(2147483647),
56+
],
57+
),
58+
),
59+
migrations.AddField(
60+
model_name="arecordmodel",
61+
name="_ttl",
62+
field=models.IntegerField(
63+
blank=True,
64+
null=True,
65+
validators=[
66+
django.core.validators.MinValueValidator(300),
67+
django.core.validators.MaxValueValidator(2147483647),
68+
],
69+
),
70+
),
71+
migrations.AddField(
72+
model_name="cnamerecordmodel",
73+
name="_ttl",
74+
field=models.IntegerField(
75+
blank=True,
76+
null=True,
77+
validators=[
78+
django.core.validators.MinValueValidator(300),
79+
django.core.validators.MaxValueValidator(2147483647),
80+
],
81+
),
82+
),
83+
migrations.AddField(
84+
model_name="mxrecordmodel",
85+
name="_ttl",
86+
field=models.IntegerField(
87+
blank=True,
88+
null=True,
89+
validators=[
90+
django.core.validators.MinValueValidator(300),
91+
django.core.validators.MaxValueValidator(2147483647),
92+
],
93+
),
94+
),
95+
migrations.AddField(
96+
model_name="nsrecordmodel",
97+
name="_ttl",
98+
field=models.IntegerField(
99+
blank=True,
100+
null=True,
101+
validators=[
102+
django.core.validators.MinValueValidator(300),
103+
django.core.validators.MaxValueValidator(2147483647),
104+
],
105+
),
106+
),
107+
migrations.AddField(
108+
model_name="ptrrecordmodel",
109+
name="_ttl",
110+
field=models.IntegerField(
111+
blank=True,
112+
null=True,
113+
validators=[
114+
django.core.validators.MinValueValidator(300),
115+
django.core.validators.MaxValueValidator(2147483647),
116+
],
117+
),
118+
),
119+
migrations.AddField(
120+
model_name="srvrecordmodel",
121+
name="_ttl",
122+
field=models.IntegerField(
123+
blank=True,
124+
null=True,
125+
validators=[
126+
django.core.validators.MinValueValidator(300),
127+
django.core.validators.MaxValueValidator(2147483647),
128+
],
129+
),
130+
),
131+
migrations.AddField(
132+
model_name="txtrecordmodel",
133+
name="_ttl",
134+
field=models.IntegerField(
135+
blank=True,
136+
null=True,
137+
validators=[
138+
django.core.validators.MinValueValidator(300),
139+
django.core.validators.MaxValueValidator(2147483647),
140+
],
141+
),
142+
),
143+
migrations.AlterField(
144+
model_name="aaaarecordmodel",
145+
name="address",
146+
field=models.ForeignKey(
147+
limit_choices_to={"ip_version": 6}, on_delete=django.db.models.deletion.CASCADE, to="ipam.ipaddress"
148+
),
149+
),
150+
migrations.AlterField(
151+
model_name="arecordmodel",
152+
name="address",
153+
field=models.ForeignKey(
154+
limit_choices_to={"ip_version": 4}, on_delete=django.db.models.deletion.CASCADE, to="ipam.ipaddress"
155+
),
156+
),
157+
]

0 commit comments

Comments
 (0)