Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Sign in / Register
Toggle navigation
C
Coredns
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Locked Files
Issues
0
Issues
0
List
Boards
Labels
Service Desk
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Security & Compliance
Security & Compliance
Dependency List
License Compliance
Packages
Packages
List
Container Registry
Analytics
Analytics
CI / CD
Code Review
Insights
Issues
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
Railgun
Coredns
Commits
61afc6db
Commit
61afc6db
authored
Feb 09, 2017
by
Richard Hillmann
Committed by
Miek Gieben
Feb 09, 2017
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Add middleware reverse (#452)
parent
a7c9fd5d
Changes
9
Show whitespace changes
Inline
Side-by-side
Showing
9 changed files
with
804 additions
and
0 deletions
+804
-0
core/coredns.go
core/coredns.go
+1
-0
core/dnsserver/zdirectives.go
core/dnsserver/zdirectives.go
+1
-0
middleware.cfg
middleware.cfg
+1
-0
middleware/reverse/README.md
middleware/reverse/README.md
+97
-0
middleware/reverse/network.go
middleware/reverse/network.go
+123
-0
middleware/reverse/network_test.go
middleware/reverse/network_test.go
+135
-0
middleware/reverse/reverse.go
middleware/reverse/reverse.go
+114
-0
middleware/reverse/setup.go
middleware/reverse/setup.go
+146
-0
middleware/reverse/setup_test.go
middleware/reverse/setup_test.go
+186
-0
No files found.
core/coredns.go
View file @
61afc6db
...
...
@@ -25,6 +25,7 @@ import (
_
"github.com/miekg/coredns/middleware/metrics"
_
"github.com/miekg/coredns/middleware/pprof"
_
"github.com/miekg/coredns/middleware/proxy"
_
"github.com/miekg/coredns/middleware/reverse"
_
"github.com/miekg/coredns/middleware/rewrite"
_
"github.com/miekg/coredns/middleware/root"
_
"github.com/miekg/coredns/middleware/secondary"
...
...
core/dnsserver/zdirectives.go
View file @
61afc6db
...
...
@@ -29,6 +29,7 @@ var directives = []string{
"secondary"
,
"etcd"
,
"kubernetes"
,
"reverse"
,
"proxy"
,
"httpprox"
,
"whoami"
,
...
...
middleware.cfg
View file @
61afc6db
...
...
@@ -37,6 +37,7 @@
160:secondary:
170:etcd:
180:kubernetes:
185:reverse:
190:proxy:
200:httpprox:
210:whoami:
...
...
middleware/reverse/README.md
0 → 100644
View file @
61afc6db
# reverse
The
*reverse*
middleware allows CoreDNS to respond dynamic to an PTR request and the related A/AAAA request.
## Syntax
~~~
reverse NETWORK.. {
hostname TEMPLATE
[ttl TTL]
[fallthrough]
~~~
*
**NETWORK**
one or more CIDR formatted networks to respond on.
*
`hostname`
inject the ip and zone to an template for the hostname. Defaults to "ip-{ip}.{zone[0]}". See below for template.
*
`ttl`
defaults to 60
*
`fallthrough`
If zone matches and no record can be generated, pass request to the next middleware.
### Template Syntax
The template for the hostname is used for generating the PTR for an reverse lookup and matching the forward lookup back to an ip.
#### `{ip}`
This symbol is
**required**
to work.
V4 network replaces the "." with an "-". 10.1.1.1 results in "10-1-1-1"
V6 network removes the ":" and fills the zeros. "ffff::ffff" results in "ffff000000000000000000000000ffff"
#### `{zone[i]}`
This symbol is
**optional**
to use and can be replaced by a fix zone string.
The zone will be matched by the configured listener on the server block key.
`i`
needs to be replaced to the index of the configured listener zones, starting with 0.
`arpa.:53 domain.com.:8053`
will resolve
`zone{0}`
to
`arpa.`
and
`zone{1}`
to
`domain.com.`
## Examples
~~~
# Serve on port 53
# match arpa. and compute.internal. to resolv reverse and forward lookup
.arpa.:53 compute.internal.:53 {
# proxy unmatched requests
proxy . 8.8.8.8
# answer requests for IPs in this networks
# PTR 1.0.32.10.in-addr.arpa. 3600 ip-10-0-32-1.compute.internal.
# A ip-10-0-32-1.compute.internal. 3600 10.0.32.1
# v6 is also possible
# PTR 1.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.1.0.d.f.ip6.arpa. 3600 ip-fd010000000000000000000000000001.compute.internal.
# AAAA ip-fd010000000000000000000000000001.compute.internal. 3600 fd01::1
reverse 10.32.0.0/16 fd01::/16 {
# template of the ip injection to hostname, zone resolved to compute.internal.
hostname ip-{ip}.{zone[1]}
# set time-to-live of the RR
ttl 3600
# forward unanswered or unmatched requests to proxy
# without this flag, requesting A/AAAA records on compute.internal. will end here
fallthrough
}
# cache with ttl timeout
cache
}
~~~
~~~
# Serve on port 53
# listen only on the specific network
32.10.in-addr.arpa.arpa.:53 arpa.company.org.:53 {
reverse 10.32.0.0/16 {
# template of the ip injection to hostname, zone resolved to arpa.company.org.
hostname "ip-{ip}.v4.{zone[1]}"
# set time-to-live of the RR
ttl 3600
# fallthrough is not required, v4.arpa.company.org. will be only answered here
}
# cidr closer to the ip wins, so we can overwrite the "default"
reverse 10.32.2.0/24 {
# its also possible to set fix domain suffix
hostname ip-{ip}.fix.arpa.company.org.
# set time-to-live of the RR
ttl 3600
}
# cache with ttl timeout
cache
}
~~~
middleware/reverse/network.go
0 → 100644
View file @
61afc6db
package
reverse
import
(
"net"
"regexp"
"bytes"
"strings"
)
type
network
struct
{
IPnet
*
net
.
IPNet
Zone
string
// forward lookup zone
Template
string
TTL
uint32
RegexMatchIP
*
regexp
.
Regexp
Fallthrough
bool
}
const
hexDigit
=
"0123456789abcdef"
const
templateNameIP
=
"{ip}"
const
regexMatchV4
=
"((?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)
\\
-){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?))"
const
regexMatchV6
=
"([0-9a-fA-F]{32})"
// For forward lookup
// converts the hostname back to an ip, based on the template
// returns nil if there is no ip found
func
(
network
*
network
)
hostnameToIP
(
rname
string
)
net
.
IP
{
var
matchedIP
net
.
IP
// use precompiled regex by setup
match
:=
network
.
RegexMatchIP
.
FindStringSubmatch
(
rname
)
// regex did not matched
if
(
len
(
match
)
!=
2
)
{
return
nil
}
if
network
.
IPnet
.
IP
.
To4
()
!=
nil
{
matchedIP
=
net
.
ParseIP
(
strings
.
Replace
(
match
[
1
],
"-"
,
"."
,
4
))
}
else
{
var
buf
bytes
.
Buffer
// convert back to an valid ipv6 string with colons
for
i
:=
0
;
i
<
8
*
4
;
i
+=
4
{
buf
.
WriteString
(
match
[
1
][
i
:
i
+
4
])
if
(
i
<
28
)
{
buf
.
WriteString
(
":"
)
}
}
matchedIP
=
net
.
ParseIP
(
buf
.
String
())
}
// No valid ip or it does not belong to this network
if
matchedIP
==
nil
||
!
network
.
IPnet
.
Contains
(
matchedIP
)
{
return
nil
}
return
matchedIP
}
// For reverse lookup
// Converts an Ip to an dns compatible hostname and injects it into the template.domain
func
(
network
*
network
)
ipToHostname
(
ip
net
.
IP
)
string
{
var
name
string
ipv4
:=
ip
.
To4
()
if
ipv4
!=
nil
{
// replace . to -
name
=
uitoa
(
ipv4
[
0
])
+
"-"
+
uitoa
(
ipv4
[
1
])
+
"-"
+
uitoa
(
ipv4
[
2
])
+
"-"
+
uitoa
(
ipv4
[
3
])
}
else
{
// assume v6
// ensure zeros are present in string
buf
:=
make
([]
byte
,
0
,
len
(
ip
)
*
4
)
for
i
:=
0
;
i
<
len
(
ip
);
i
++
{
v
:=
ip
[
i
]
buf
=
append
(
buf
,
hexDigit
[
v
>>
4
])
buf
=
append
(
buf
,
hexDigit
[
v
&
0xF
])
}
name
=
string
(
buf
)
}
// inject the converted ip into the fqdn template
return
strings
.
Replace
(
network
.
Template
,
templateNameIP
,
name
,
1
)
}
// just the same from net.ip package, but with uint8
func
uitoa
(
val
uint8
)
string
{
if
val
==
0
{
// avoid string allocation
return
"0"
}
var
buf
[
20
]
byte
// big enough for 64bit value base 10
i
:=
len
(
buf
)
-
1
for
val
>=
10
{
q
:=
val
/
10
buf
[
i
]
=
byte
(
'0'
+
val
-
q
*
10
)
i
--
val
=
q
}
// val < 10
buf
[
i
]
=
byte
(
'0'
+
val
)
return
string
(
buf
[
i
:
])
}
type
networks
[]
network
// implements the sort interface
func
(
slice
networks
)
Len
()
int
{
return
len
(
slice
)
}
// implements the sort interface
// cidr closer to the ip wins (by netmask)
func
(
slice
networks
)
Less
(
i
,
j
int
)
bool
{
isize
,
_
:=
slice
[
i
]
.
IPnet
.
Mask
.
Size
()
jsize
,
_
:=
slice
[
j
]
.
IPnet
.
Mask
.
Size
()
return
isize
>
jsize
}
// implements the sort interface
func
(
slice
networks
)
Swap
(
i
,
j
int
)
{
slice
[
i
],
slice
[
j
]
=
slice
[
j
],
slice
[
i
]
}
\ No newline at end of file
middleware/reverse/network_test.go
0 → 100644
View file @
61afc6db
package
reverse
import
(
"testing"
"net"
"reflect"
"regexp"
)
// Test converting from hostname to IP and back again to hostname
func
TestNetworkConversion
(
t
*
testing
.
T
)
{
_
,
net4
,
_
:=
net
.
ParseCIDR
(
"10.1.1.0/24"
)
_
,
net6
,
_
:=
net
.
ParseCIDR
(
"fd01::/64"
)
regexIP4
,
_
:=
regexp
.
Compile
(
"^dns-"
+
regexMatchV4
+
"
\\
.domain
\\
.internal
\\
.$"
)
regexIP6
,
_
:=
regexp
.
Compile
(
"^dns-"
+
regexMatchV6
+
"
\\
.domain
\\
.internal
\\
.$"
)
tests
:=
[]
struct
{
network
network
resultHost
string
resultIP
net
.
IP
}{
{
network
{
IPnet
:
net4
,
Template
:
"dns-{ip}.domain.internal."
,
RegexMatchIP
:
regexIP4
,
},
"dns-10-1-1-23.domain.internal."
,
net
.
ParseIP
(
"10.1.1.23"
),
},
{
network
{
IPnet
:
net6
,
Template
:
"dns-{ip}.domain.internal."
,
RegexMatchIP
:
regexIP6
,
},
"dns-fd01000000000000000000000000a32f.domain.internal."
,
net
.
ParseIP
(
"fd01::a32f"
),
},
}
for
i
,
test
:=
range
tests
{
resultIP
:=
test
.
network
.
hostnameToIP
(
test
.
resultHost
)
if
!
reflect
.
DeepEqual
(
test
.
resultIP
,
resultIP
)
{
t
.
Fatalf
(
"Test %d expected %v, got %v"
,
i
,
test
.
resultIP
,
resultIP
)
}
resultHost
:=
test
.
network
.
ipToHostname
(
test
.
resultIP
)
if
!
reflect
.
DeepEqual
(
test
.
resultHost
,
resultHost
)
{
t
.
Fatalf
(
"Test %d expected %v, got %v"
,
i
,
test
.
resultHost
,
resultHost
)
}
}
}
func
TestNetworkHostnameToIP
(
t
*
testing
.
T
)
{
_
,
net4
,
_
:=
net
.
ParseCIDR
(
"10.1.1.0/24"
)
_
,
net6
,
_
:=
net
.
ParseCIDR
(
"fd01::/64"
)
regexIP4
,
_
:=
regexp
.
Compile
(
"^dns-"
+
regexMatchV4
+
"
\\
.domain
\\
.internal
\\
.$"
)
regexIP6
,
_
:=
regexp
.
Compile
(
"^dns-"
+
regexMatchV6
+
"
\\
.domain
\\
.internal
\\
.$"
)
// Test regex does NOT match
// All this test should return nil
testsNil
:=
[]
struct
{
network
network
hostname
string
}{
{
network
{
IPnet
:
net4
,
RegexMatchIP
:
regexIP4
,
},
// domain does not match
"dns-10-1-1-23.domain.internals."
,
},
{
network
{
IPnet
:
net4
,
RegexMatchIP
:
regexIP4
,
},
// IP does match / contain in subnet
"dns-200-1-1-23.domain.internals."
,
},
{
network
{
IPnet
:
net4
,
RegexMatchIP
:
regexIP4
,
},
// template does not match
"dns-10-1-1-23-x.domain.internal."
,
},
{
network
{
IPnet
:
net4
,
RegexMatchIP
:
regexIP4
,
},
// template does not match
"IP-dns-10-1-1-23.domain.internal."
,
},
{
network
{
IPnet
:
net6
,
RegexMatchIP
:
regexIP6
,
},
// template does not match
"dnx-fd01000000000000000000000000a32f.domain.internal."
,
},
{
network
{
IPnet
:
net6
,
RegexMatchIP
:
regexIP6
,
},
// no valid v6 (missing one 0, only 31 chars)
"dns-fd0100000000000000000000000a32f.domain.internal."
,
},
{
network
{
IPnet
:
net6
,
RegexMatchIP
:
regexIP6
,
},
// IP does match / contain in subnet
"dns-ed01000000000000000000000000a32f.domain.internal."
,
},
}
for
i
,
test
:=
range
testsNil
{
resultIP
:=
test
.
network
.
hostnameToIP
(
test
.
hostname
)
if
resultIP
!=
nil
{
t
.
Fatalf
(
"Test %d expected nil, got %v"
,
i
,
resultIP
)
}
}
}
middleware/reverse/reverse.go
0 → 100644
View file @
61afc6db
package
reverse
import
(
"net"
"github.com/miekg/coredns/request"
"github.com/miekg/coredns/middleware"
"github.com/miekg/coredns/middleware/pkg/dnsutil"
"github.com/miekg/dns"
"golang.org/x/net/context"
)
// Reverse provides dynamic reverse dns and the related forward rr
type
Reverse
struct
{
Next
middleware
.
Handler
Networks
networks
}
// ServeDNS implements the middleware.Handler interface.
func
(
reverse
Reverse
)
ServeDNS
(
ctx
context
.
Context
,
w
dns
.
ResponseWriter
,
r
*
dns
.
Msg
)
(
int
,
error
)
{
var
rr
dns
.
RR
nextHandler
:=
true
state
:=
request
.
Request
{
W
:
w
,
Req
:
r
}
m
:=
new
(
dns
.
Msg
)
m
.
SetReply
(
r
)
m
.
Authoritative
,
m
.
RecursionAvailable
,
m
.
Compress
=
true
,
true
,
true
switch
state
.
QType
(){
case
dns
.
TypePTR
:
address
:=
dnsutil
.
ExtractAddressFromReverse
(
state
.
Name
())
if
address
==
""
{
// Not an reverse lookup, but can still be an pointer for an domain
break
}
ip
:=
net
.
ParseIP
(
address
)
// loop through the configured networks
for
_
,
n
:=
range
reverse
.
Networks
{
if
(
n
.
IPnet
.
Contains
(
ip
))
{
nextHandler
=
n
.
Fallthrough
rr
=
&
dns
.
PTR
{
Hdr
:
dns
.
RR_Header
{
Name
:
state
.
QName
(),
Rrtype
:
dns
.
TypePTR
,
Class
:
dns
.
ClassINET
,
Ttl
:
n
.
TTL
},
Ptr
:
n
.
ipToHostname
(
ip
),
}
break
}
}
case
dns
.
TypeA
:
for
_
,
n
:=
range
reverse
.
Networks
{
if
dns
.
IsSubDomain
(
n
.
Zone
,
state
.
Name
())
{
nextHandler
=
n
.
Fallthrough
// skip if requesting an v4 address and network is not v4
if
n
.
IPnet
.
IP
.
To4
()
==
nil
{
continue
}
result
:=
n
.
hostnameToIP
(
state
.
Name
())
if
result
!=
nil
{
rr
=
&
dns
.
A
{
Hdr
:
dns
.
RR_Header
{
Name
:
state
.
QName
(),
Rrtype
:
dns
.
TypeA
,
Class
:
dns
.
ClassINET
,
Ttl
:
n
.
TTL
},
A
:
result
,
}
break
}
}
}
case
dns
.
TypeAAAA
:
for
_
,
n
:=
range
reverse
.
Networks
{
if
dns
.
IsSubDomain
(
n
.
Zone
,
state
.
Name
())
{
nextHandler
=
n
.
Fallthrough
// Do not use To16 which tries to make v4 in v6
if
n
.
IPnet
.
IP
.
To4
()
!=
nil
{
continue
}
result
:=
n
.
hostnameToIP
(
state
.
Name
())
if
result
!=
nil
{
rr
=
&
dns
.
AAAA
{
Hdr
:
dns
.
RR_Header
{
Name
:
state
.
QName
(),
Rrtype
:
dns
.
TypeAAAA
,
Class
:
dns
.
ClassINET
,
Ttl
:
n
.
TTL
},
AAAA
:
result
,
}
break
}
}
}
}
if
rr
==
nil
{
if
reverse
.
Next
==
nil
||
!
nextHandler
{
// could not resolv
w
.
WriteMsg
(
m
)
return
dns
.
RcodeNameError
,
nil
}
return
reverse
.
Next
.
ServeDNS
(
ctx
,
w
,
r
)
}
m
.
Answer
=
append
(
m
.
Answer
,
rr
)
state
.
SizeAndDo
(
m
)
w
.
WriteMsg
(
m
)
return
dns
.
RcodeSuccess
,
nil
}
// Name implements the Handler interface.
func
(
reverse
Reverse
)
Name
()
string
{
return
"reverse"
}
middleware/reverse/setup.go
0 → 100644
View file @
61afc6db
package
reverse
import
(
"net"
"sort"
"strings"
"strconv"
"regexp"
"github.com/miekg/coredns/core/dnsserver"
"github.com/miekg/coredns/middleware"
"github.com/mholt/caddy"
)
func
init
()
{
caddy
.
RegisterPlugin
(
"reverse"
,
caddy
.
Plugin
{
ServerType
:
"dns"
,
Action
:
setupReverse
,
})
}
func
setupReverse
(
c
*
caddy
.
Controller
)
error
{
networks
,
err
:=
reverseParse
(
c
)
if
err
!=
nil
{
return
middleware
.
Error
(
"reverse"
,
err
)
}
dnsserver
.
GetConfig
(
c
)
.
AddMiddleware
(
func
(
next
middleware
.
Handler
)
middleware
.
Handler
{
return
Reverse
{
Next
:
next
,
Networks
:
networks
}
})
return
nil
}
func
reverseParse
(
c
*
caddy
.
Controller
)
(
networks
,
error
)
{
var
err
error
// normalize zones, validation is almost done by dnsserver
zones
:=
make
([]
string
,
len
(
c
.
ServerBlockKeys
))
for
i
,
str
:=
range
c
.
ServerBlockKeys
{
host
,
_
,
_
:=
net
.
SplitHostPort
(
str
)
zones
[
i
]
=
strings
.
ToLower
(
host
)
}
networks
:=
networks
{}
for
c
.
Next
()
{
if
c
.
Val
()
==
"reverse"
{
var
cidrs
[]
*
net
.
IPNet
// parse all networks
for
_
,
cidr
:=
range
c
.
RemainingArgs
()
{
if
cidr
==
"{"
{
break
}
_
,
ipnet
,
err
:=
net
.
ParseCIDR
(
cidr
)
if
err
!=
nil
{
return
nil
,
c
.
Errf
(
"%v needs to be an CIDR formatted Network
\n
"
,
cidr
)
}
cidrs
=
append
(
cidrs
,
ipnet
)
}
if
len
(
cidrs
)
==
0
{
return
nil
,
c
.
ArgErr
()
}
// set defaults
var
(
template
=
"ip-"
+
templateNameIP
+
".{zone[0]}"
ttl
=
60
fall
=
false
)
for
c
.
NextBlock
()
{
switch
c
.
Val
()
{
case
"hostname"
:
if
!
c
.
NextArg
()
{
return
nil
,
c
.
ArgErr
()
}
template
=
c
.
Val
()
case
"ttl"
:
if
!
c
.
NextArg
()
{
return
nil
,
c
.
ArgErr
()
}
ttl
,
err
=
strconv
.
Atoi
(
c
.
Val
())
if
err
!=
nil
{
return
nil
,
err
}
case
"fallthrough"
:
fall
=
true
default
:
return
nil
,
c
.
ArgErr
()
}
}
// prepare template
// replace {zone[index]} by the listen zone/domain of this config block
for
i
,
zone
:=
range
zones
{
template
=
strings
.
Replace
(
template
,
"{zone["
+
string
(
i
+
48
)
+
"]}"
,
zone
,
1
)
}
if
!
strings
.
HasSuffix
(
template
,
"."
)
{
template
+=
"."
}
// extract zone from template
templateZone
:=
strings
.
SplitAfterN
(
template
,
"."
,
2
)
if
len
(
templateZone
)
!=
2
||
templateZone
[
1
]
==
""
{
return
nil
,
c
.
Errf
(
"Cannot find domain in template '%v'"
,
template
)
}
// Create for each configured network in this stanza
for
_
,
ipnet
:=
range
cidrs
{
// precompile regex for hostname to ip matching
regexIP
:=
regexMatchV4
if
ipnet
.
IP
.
To4
()
==
nil
{
regexIP
=
regexMatchV6
}
regex
,
err
:=
regexp
.
Compile
(
"^"
+
strings
.
Replace
(
// inject ip regex into template
regexp
.
QuoteMeta
(
template
),
// escape dots
regexp
.
QuoteMeta
(
templateNameIP
),
regexIP
,
1
,
)
+
"$"
)
if
err
!=
nil
{
// invalid regex
return
nil
,
err
}
networks
=
append
(
networks
,
network
{
IPnet
:
ipnet
,
Zone
:
templateZone
[
1
],
Template
:
template
,
RegexMatchIP
:
regex
,
TTL
:
uint32
(
ttl
),
Fallthrough
:
fall
,
})
}
}
}
// sort by cidr
sort
.
Sort
(
networks
)
return
networks
,
nil
}
middleware/reverse/setup_test.go
0 → 100644
View file @
61afc6db
package
reverse
import
(
"testing"
"net"
"reflect"
"regexp"
"github.com/mholt/caddy"
)
func
TestSetupParse
(
t
*
testing
.
T
)
{
_
,
net4
,
_
:=
net
.
ParseCIDR
(
"10.1.1.0/24"
)
_
,
net6
,
_
:=
net
.
ParseCIDR
(
"fd01::/64"
)
regexIP6
,
_
:=
regexp
.
Compile
(
"^ip-"
+
regexMatchV6
+
"
\\
.domain
\\
.com
\\
.$"
)
regexIpv4dynamic
,
_
:=
regexp
.
Compile
(
"^dynamic-"
+
regexMatchV4
+
"-intern
\\
.dynamic
\\
.domain
\\
.com
\\
.$"
)
regexIpv6dynamic
,
_
:=
regexp
.
Compile
(
"^dynamic-"
+
regexMatchV6
+
"-intern
\\
.dynamic
\\
.domain
\\
.com
\\
.$"
)
regexIpv4vpndynamic
,
_
:=
regexp
.
Compile
(
"^dynamic-"
+
regexMatchV4
+
"-vpn
\\
.dynamic
\\
.domain
\\
.com
\\
.$"
)
serverBlockKeys
:=
[]
string
{
"domain.com.:8053"
,
"dynamic.domain.com.:8053"
}
tests
:=
[]
struct
{
inputFileRules
string
shouldErr
bool
networks
networks
}{
{
// with defaults
`reverse fd01::/64`
,
false
,
networks
{
network
{
IPnet
:
net6
,
Template
:
"ip-{ip}.domain.com."
,
Zone
:
"domain.com."
,
TTL
:
60
,
RegexMatchIP
:
regexIP6
,
Fallthrough
:
false
,
}},
},
{
`reverse`
,
true
,
networks
{},
},
{
//no cidr
`reverse 10.1.1.1`
,
true
,
networks
{},
},
{
//no cidr
`reverse 10.1.1.0/16 fd00::`
,
true
,
networks
{},
},
{
// invalid key
`reverse 10.1.1.0/24 {
notavailable
}`
,
true
,
networks
{},
},
{
// no domain suffix
`reverse 10.1.1.0/24 {
hostname ip-{ip}.
}`
,
true
,
networks
{},
},
{
// hostname requires an second arg
`reverse 10.1.1.0/24 {
hostname
}`
,
true
,
networks
{},
},
{
// template breaks regex compile
`reverse 10.1.1.0/24 {
hostname ip-{[-x
}`
,
true
,
networks
{},
},
{
// ttl requires an (u)int
`reverse 10.1.1.0/24 {
ttl string
}`
,
true
,
networks
{},
},
{
`reverse fd01::/64 {
hostname dynamic-{ip}-intern.{zone[1]}
ttl 50
}
reverse 10.1.1.0/24 {
hostname dynamic-{ip}-vpn.{zone[1]}
fallthrough
}`
,
false
,
networks
{
network
{
IPnet
:
net6
,
Template
:
"dynamic-{ip}-intern.dynamic.domain.com."
,
Zone
:
"dynamic.domain.com."
,
TTL
:
50
,
RegexMatchIP
:
regexIpv6dynamic
,
Fallthrough
:
false
,
},
network
{
IPnet
:
net4
,
Template
:
"dynamic-{ip}-vpn.dynamic.domain.com."
,
Zone
:
"dynamic.domain.com."
,
TTL
:
60
,
RegexMatchIP
:
regexIpv4vpndynamic
,
Fallthrough
:
true
,
}},
},
{
// multiple networks in one stanza
`reverse fd01::/64 10.1.1.0/24 {
hostname dynamic-{ip}-intern.{zone[1]}
ttl 50
fallthrough
}`
,
false
,
networks
{
network
{
IPnet
:
net6
,
Template
:
"dynamic-{ip}-intern.dynamic.domain.com."
,
Zone
:
"dynamic.domain.com."
,
TTL
:
50
,
RegexMatchIP
:
regexIpv6dynamic
,
Fallthrough
:
true
,
},
network
{
IPnet
:
net4
,
Template
:
"dynamic-{ip}-intern.dynamic.domain.com."
,
Zone
:
"dynamic.domain.com."
,
TTL
:
50
,
RegexMatchIP
:
regexIpv4dynamic
,
Fallthrough
:
true
,
}},
},
{
// fix domain in template
`reverse fd01::/64 {
hostname dynamic-{ip}-intern.dynamic.domain.com
ttl 300
fallthrough
}`
,
false
,
networks
{
network
{
IPnet
:
net6
,
Template
:
"dynamic-{ip}-intern.dynamic.domain.com."
,
Zone
:
"dynamic.domain.com."
,
TTL
:
300
,
RegexMatchIP
:
regexIpv6dynamic
,
Fallthrough
:
true
,
}},
},
}
for
i
,
test
:=
range
tests
{
c
:=
caddy
.
NewTestController
(
"dns"
,
test
.
inputFileRules
)
c
.
ServerBlockKeys
=
serverBlockKeys
networks
,
err
:=
reverseParse
(
c
)
if
err
==
nil
&&
test
.
shouldErr
{
t
.
Fatalf
(
"Test %d expected errors, but got no error"
,
i
)
}
else
if
err
!=
nil
&&
!
test
.
shouldErr
{
t
.
Fatalf
(
"Test %d expected no errors, but got '%v'"
,
i
,
err
)
}
else
{
for
j
,
n
:=
range
networks
{
reflect
.
DeepEqual
(
test
.
networks
[
j
],
n
)
if
!
reflect
.
DeepEqual
(
test
.
networks
[
j
],
n
)
{
t
.
Fatalf
(
"Test %d/%d expected %v, got %v"
,
i
,
j
,
test
.
networks
[
j
],
n
)
}
}
}
}
}
\ No newline at end of file
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment