RPZ A records were parsed as address redirects, but the query pipeline treated the address as a CNAME target and returned the wrong result. Answer IP-literal redirects directly with the matching A or AAAA record, and return NODATA for other query types. Add the requested EdgeRouter domain overrides as a local RPZ source so each bare owner covers its apex and all subdomains. Mount that source into the pods and document the address-record form. When the Zones page has no existing zone, start the Add Record form in New zone mode and tell the operator to enter its apex.
This commit is contained in:
1 parent
47ef5c1133
commit
87b6946ab7
7 files changed
+67
-6
No files matched your search
@@ -495,7 +495,7 @@ plain-list entry becomes `**.name`.
|
||||
| `hosts` | `IP name [name…]`, `0 name`, `localhost` lines, `#`/`;` comments | `0.0.0.0 ads.example.com` | `localhost`/`broadcasthost`/`ip6-*` lines are skipped; a line whose first field is not an address falls back to the plain parser, with a notice in the parse stats |
|
||||
| `adblock` | `\|\|host^` and `\|http://host/…` (blocked), `@@\|\|host^` (allowed), bare hostnames | `\|\|ads.example.com^$third-party` | element-hiding rules (`##`, `#@#`, `#?#`) and regex rules are skipped and reported in `stats.notices`; a URL path rule blocks the whole host |
|
||||
| `plain` | one name per line, `0.0.0.0 name`, `!allow name` / `!name` / `@@…` allow markers, adblock tails on pasted lines | `ads.example.com` | a single-label name without a dot is rejected |
|
||||
| `rpz` | an RFC 1035 policy zone | `ads.example.com CNAME .` | parsed by `internal/zonefile`; the zone's own default TTL wins for records with no TTL column; a bare owner name covers the domain and everything under it (`**.name`, RPZ semantics), an owner written `*.name` covers only its subdomains |
|
||||
| `rpz` | an RFC 1035 policy zone | `ads.example.com CNAME .` | parsed by `internal/zonefile`; the zone's own default TTL wins for records with no TTL column; a bare owner name covers the domain and everything under it (`**.name`, RPZ semantics), an owner written `*.name` covers only its subdomains; `example.com A 192.0.2.10` redirects matching A queries to that address |
|
||||
| `auto` | sniffs the first 200 meaningful lines | — | default; a `$TTL`/`$ORIGIN`/`$INCLUDE` line or a `name TTL IN A …` shape means `rpz`, an address-first line means `hosts`, `\|\|`/`##`/`@@` means `adblock`, otherwise `plain` |
|
||||
|
||||
**Categories.** `blocklist.lists[].categories` are copied onto every rule from
|
||||
|
||||
@@ -84,6 +84,11 @@ data:
|
||||
managed_zones: /var/lib/fancy-dns/managed-zones
|
||||
local_zones: [/etc/fancy-dns/zones/*.zone]
|
||||
lists:
|
||||
- name: edge-router-x-address-overrides
|
||||
format: rpz
|
||||
path: /etc/fancy-dns/rpz/address-overrides.rpz
|
||||
enabled: true
|
||||
refresh: 0s
|
||||
- name: haas
|
||||
format: plain
|
||||
url: https://raw.githubusercontent.com/StevenBlack/hosts/master/hosts
|
||||
|
||||
@@ -0,0 +1,16 @@
|
||||
apiVersion: v1
|
||||
kind: ConfigMap
|
||||
metadata:
|
||||
name: fancy-dns-rpz
|
||||
namespace: dns
|
||||
labels:
|
||||
app.kubernetes.io/name: fancy-dns
|
||||
app.kubernetes.io/component: address-overrides
|
||||
data:
|
||||
address-overrides.rpz: |
|
||||
$TTL 60
|
||||
tornberg.me A 10.10.3.10
|
||||
knatofs.se A 10.10.3.10
|
||||
k6n.net A 10.10.3.10
|
||||
slask.local A 10.10.3.10
|
||||
iamu.dev A 10.10.3.10
|
||||
@@ -139,6 +139,9 @@ spec:
|
||||
- name: zones
|
||||
mountPath: /etc/fancy-dns/zones
|
||||
readOnly: true
|
||||
- name: rpz
|
||||
mountPath: /etc/fancy-dns/rpz
|
||||
readOnly: true
|
||||
- name: tls
|
||||
mountPath: /etc/fancy-dns/tls
|
||||
readOnly: true
|
||||
@@ -157,6 +160,10 @@ spec:
|
||||
configMap:
|
||||
name: fancy-dns-zones
|
||||
optional: false
|
||||
- name: rpz
|
||||
configMap:
|
||||
name: fancy-dns-rpz
|
||||
optional: false
|
||||
- name: tls
|
||||
secret:
|
||||
secretName: fancy-dns-tls
|
||||
|
||||
@@ -12,6 +12,7 @@ resources:
|
||||
- 00-config.yaml
|
||||
- 05-serviceaccount.yaml
|
||||
- 06-zones.yaml
|
||||
- 07-rpz.yaml
|
||||
- 10-deployment.yaml
|
||||
- 20-service.yaml
|
||||
- 30-ingress.yaml
|
||||
|
||||
@@ -1033,9 +1033,9 @@ func sinkhole(q *dns.Msg, cfg config.Block) *dns.Msg {
|
||||
return m
|
||||
}
|
||||
|
||||
// redirect answers with a CNAME to a configured name, plus an A/AAAA for the
|
||||
// target when we know it (a CNAME to a name that does not resolve would be a
|
||||
// worse answer than no CNAME at all).
|
||||
// redirect answers with the configured address when target is an IP literal.
|
||||
// Otherwise it answers with a CNAME to a configured name, plus an A/AAAA for
|
||||
// the target when available.
|
||||
func redirect(q *dns.Msg, target string, ttl uint32) *dns.Msg {
|
||||
m := new(dns.Msg)
|
||||
m.SetReply(q)
|
||||
@@ -1046,6 +1046,27 @@ func redirect(q *dns.Msg, target string, ttl uint32) *dns.Msg {
|
||||
if len(q.Question) == 0 {
|
||||
return m
|
||||
}
|
||||
if addr, err := netip.ParseAddr(target); err == nil {
|
||||
addr = addr.Unmap()
|
||||
var rrType uint16
|
||||
switch {
|
||||
case addr.Is4() && q.Question[0].Qtype == dns.TypeA:
|
||||
rrType = dns.TypeA
|
||||
case addr.Is6() && q.Question[0].Qtype == dns.TypeAAAA:
|
||||
rrType = dns.TypeAAAA
|
||||
default:
|
||||
m.Ns = []dns.RR{syntheticSOA(q, ttl)}
|
||||
return m
|
||||
}
|
||||
rr, err := dns.NewRR(q.Question[0].Name + " 0 IN " + dns.TypeToString[rrType] + " " + addr.String())
|
||||
if err == nil {
|
||||
rr.Header().Ttl = ttl
|
||||
m.Answer = []dns.RR{rr}
|
||||
} else {
|
||||
m.Ns = []dns.RR{syntheticSOA(q, ttl)}
|
||||
}
|
||||
return m
|
||||
}
|
||||
cname, err := dns.NewRR(q.Question[0].Name + " 0 IN CNAME " + dns.Fqdn(target))
|
||||
if err != nil {
|
||||
return m
|
||||
|
||||
+13
-2
@@ -187,7 +187,14 @@ export default function Zones() {
|
||||
|
||||
const openNew = (): void => {
|
||||
setEditing(null)
|
||||
setForm({ zone: origin, name: '', type: data?.types[0] ?? 'A', ttl: '', value: '' })
|
||||
setNewZone('')
|
||||
setForm({
|
||||
zone: origin || NEW_ZONE,
|
||||
name: '',
|
||||
type: data?.types[0] ?? 'A',
|
||||
ttl: '',
|
||||
value: '',
|
||||
})
|
||||
setFormError(null)
|
||||
setRecordOpen(true)
|
||||
}
|
||||
@@ -210,7 +217,11 @@ export default function Zones() {
|
||||
setFormError(null)
|
||||
const zoneName = form.zone === NEW_ZONE ? newZone.trim() : form.zone
|
||||
if (zoneName === '') {
|
||||
setFormError('name the zone this record belongs to')
|
||||
setFormError(
|
||||
form.zone === NEW_ZONE
|
||||
? 'enter the new zone apex'
|
||||
: 'choose the zone this record belongs to',
|
||||
)
|
||||
return
|
||||
}
|
||||
if (form.name.trim() === '') {
|
||||
|
||||
Reference in new issue
Block a user