{% if (sites[domain.Site.ID()].Name == siteName) and ('dhcp4' in domain.Features) and domain.IPv4Address and domain.DefaultRange.Defined() and domain.DefaultRange.Get().IPv4Start and domain.DefaultRange.Get().IPv4End %}
# {{ domain.Name }}
subnet {{ domain.IPv4Address }} netmask {{ domain.IPv4PrefixLength.Mask() }} {
+ {% if domain.IPv4DNSServer.AsIP() %}
+ option domain-name-servers {{ domain.IPv4DNSServer.AsIP().String() }};
+ {% elif routeraddresses.IPv4[domain.IPv4Address] is defined %}
+ option domain-name-servers {{ routeraddresses.IPv4[domain.IPv4Address].Address }};
+ {% endif %}
+
{% if routeraddresses.IPv4[domain.IPv4Address] is defined %}
option routers {{ routeraddresses.IPv4[domain.IPv4Address].Address }};
- option domain-name-servers {{ routeraddresses.IPv4[domain.IPv4Address].Address }};
{% endif %}
option domain-name "{{ domain.DNSSearch[0] }}";
{% if sites[domain.Site.ID()].Name == siteName and 'dhcp6' in domain.Features and domain.IPv6Address is defined and domain.DefaultRange.Defined() and domain.DefaultRange.Get().IPv6Start and domain.DefaultRange.Get().IPv6End %}
# {{ domain.Name }}
subnet6 {{ domain.IPv6Address }}/{{ domain.IPv6PrefixLength }} {
- {% if routeraddresses.IPv6[domain.IPv6Address] -%}
+ {% if domain.IPv6DNSServer.AsIP() -%}
+ option dhcp6.name-servers {{ domain.IPv6DNSServer.AsIP().String() }};
+ {% elif routeraddresses.IPv6[domain.IPv6Address] -%}
option dhcp6.name-servers {{ routeraddresses.IPv6[domain.IPv6Address].Address }};
{%- endif %}
- # option dhcp6.domain-name {{ domain.DNSSearch[0] }};
- # option dhcp6.domain-search {{ domain.DNSSearch[0] }};
+ # option dhcp6.domain-name "{{ domain.DNSSearch[0] }}";
+ # option dhcp6.domain-search "{{ domain.DNSSearch[0] }}";
option dhcp6.domain-search "{{ domain.DNSSearch | join("\", \"") }}";
{% for id, range in domain.Ranges -%}
"net"
"slices"
"strings"
+ "sync"
"time"
"github.com/miekg/dns"
type Timestamp uint64
type IPString string
+type IPv4OrInterfaceString string
+type IPv6OrInterfaceString string
type HexEncoded string
type IPv4PrefixLength uint8
type IPv6PrefixLength uint8
type ErrUnhandledRecordType string
+var netIfaces []net.Interface
+var netIfacesOnce sync.Once
+
func (e ErrUnhandledRecordType) Error() string {
return string(e)
}
TTL uint `json:"ttl"`
}
+func getNetInterfaces() []net.Interface {
+ netIfacesOnce.Do(func() {
+ var err error
+ netIfaces, err = net.Interfaces()
+ if err != nil {
+ logger.Fatalf("failed to get network interfaces: %v")
+ }
+ })
+
+ return netIfaces
+}
+
func (r *DNSRecord) ToRR() (dns.RR, error) {
var msg dns.RR
Site *Sparse[Site] `json:"site"`
VlanID uint `json:"vlan_id"`
- IPv4Address IPString `json:"inet4_address"`
- IPv4PrefixLength IPv4PrefixLength `json:"inet4_prefixlen"`
- IPv4RouterAddress IPString `json:"inet4_routeraddr"`
+ IPv4Address IPString `json:"inet4_address"`
+ IPv4PrefixLength IPv4PrefixLength `json:"inet4_prefixlen"`
+ IPv4RouterAddress IPString `json:"inet4_routeraddr"`
+ IPv4DNSServer IPv4OrInterfaceString `json:"dns_server_v4"`
- IPv6Address IPString `json:"inet6_address"`
- IPv6PrefixLength IPv6PrefixLength `json:"inet6_prefixlen"`
- IPv6RouterAddress IPString `json:"inet6_routeraddr"`
+ IPv6Address IPString `json:"inet6_address"`
+ IPv6PrefixLength IPv6PrefixLength `json:"inet6_prefixlen"`
+ IPv6RouterAddress IPString `json:"inet6_routeraddr"`
+ IPv6DNSServer IPv6OrInterfaceString `json:"dns_server_v6"`
PXEServerIPv4 IPString `json:"pxe4_server"`
PXEServerIPv6 IPString `json:"pxe6_server"`
return net.ParseIP(string(ip))
}
+func (s IPv4OrInterfaceString) AsIP() net.IP {
+ if string(s) == "" {
+ return nil
+ }
+
+ if ip := net.ParseIP(string(s)); ip.To4() != nil {
+ return ip
+ }
+
+ netifaces := getNetInterfaces()
+ for _, iface := range netifaces {
+ if iface.Name != string(s) {
+ continue
+ }
+
+ if addrs, err := iface.Addrs(); err == nil {
+ for _, addr := range addrs {
+ if addr.Network() != "ip+net" {
+ continue
+ }
+
+ ipaddr, _, err := net.ParseCIDR(addr.String())
+ if err != nil {
+ continue
+ }
+
+ if ipv4 := ipaddr.To4(); ipv4 != nil {
+ return ipv4
+ }
+ }
+ }
+ }
+
+ return nil
+}
+
+func (s IPv6OrInterfaceString) AsIP() net.IP {
+ if ip := net.ParseIP(string(s)); ip.To4() == nil && ip.To16() != nil {
+ return ip
+ }
+
+ netifaces := getNetInterfaces()
+ for _, iface := range netifaces {
+ if iface.Name != string(s) {
+ continue
+ }
+
+ if addrs, err := iface.Addrs(); err == nil {
+ for _, addr := range addrs {
+ if addr.Network() != "ip+net" {
+ continue
+ }
+
+ ipaddr, _, err := net.ParseCIDR(addr.String())
+ if err != nil {
+ continue
+ }
+
+ if bytes.Equal(ipaddr[0:2], []byte{0xfe, 0x80}) {
+ continue
+ }
+
+ if ipaddr.To4() != nil {
+ continue
+ }
+
+ return ipaddr
+ }
+ }
+ }
+
+ return nil
+}
+
func (ip IPString) AsInt32() int32 {
netip := ip.AsIP().To4()
if netip == nil {