Page Menu
Home
VyOS Platform
Search
Configure Global Search
Log In
Files
F38742108
dns_forwarding.py
No One
Temporary
Actions
Download File
Edit File
Delete File
View Transforms
Subscribe
Flag For Later
Award Token
Size
6 KB
Referenced Files
None
Subscribers
None
dns_forwarding.py
View Options
#!/usr/bin/env python3
#
# Copyright (C) 2018-2022 VyOS maintainers and contributors
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License version 2 or later as
# published by the Free Software Foundation.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
import
os
from
netifaces
import
interfaces
from
sys
import
exit
from
vyos.config
import
Config
from
vyos.configdict
import
dict_merge
from
vyos.hostsd_client
import
Client
as
hostsd_client
from
vyos.template
import
render
from
vyos.template
import
is_ipv6
from
vyos.util
import
call
from
vyos.util
import
chown
from
vyos.util
import
dict_search
from
vyos.xml
import
defaults
from
vyos
import
ConfigError
from
vyos
import
airbag
airbag
.
enable
()
pdns_rec_user
=
pdns_rec_group
=
'pdns'
pdns_rec_run_dir
=
'/run/powerdns'
pdns_rec_lua_conf_file
=
f
'{pdns_rec_run_dir}/recursor.conf.lua'
pdns_rec_hostsd_lua_conf_file
=
f
'{pdns_rec_run_dir}/recursor.vyos-hostsd.conf.lua'
pdns_rec_hostsd_zones_file
=
f
'{pdns_rec_run_dir}/recursor.forward-zones.conf'
pdns_rec_config_file
=
f
'{pdns_rec_run_dir}/recursor.conf'
hostsd_tag
=
'static'
def
get_config
(
config
=
None
):
if
config
:
conf
=
config
else
:
conf
=
Config
()
base
=
[
'service'
,
'dns'
,
'forwarding'
]
if
not
conf
.
exists
(
base
):
return
None
dns
=
conf
.
get_config_dict
(
base
,
key_mangling
=
(
'-'
,
'_'
),
get_first_key
=
True
)
# We have gathered the dict representation of the CLI, but there are default
# options which we need to update into the dictionary retrived.
default_values
=
defaults
(
base
)
dns
=
dict_merge
(
default_values
,
dns
)
# some additions to the default dictionary
if
'system'
in
dns
:
base_nameservers
=
[
'system'
,
'name-server'
]
if
conf
.
exists
(
base_nameservers
):
dns
.
update
({
'system_name_server'
:
conf
.
return_values
(
base_nameservers
)})
return
dns
def
verify
(
dns
):
# bail out early - looks like removal from running config
if
not
dns
:
return
None
if
'listen_address'
not
in
dns
:
raise
ConfigError
(
'DNS forwarding requires a listen-address'
)
if
'allow_from'
not
in
dns
:
raise
ConfigError
(
'DNS forwarding requires an allow-from network'
)
# we can not use dict_search() when testing for domain servers
# as a domain will contains dot's which is out dictionary delimiter.
if
'domain'
in
dns
:
for
domain
in
dns
[
'domain'
]:
if
'server'
not
in
dns
[
'domain'
][
domain
]:
raise
ConfigError
(
f
'No server configured for domain {domain}!'
)
if
'dns64_prefix'
in
dns
:
dns_prefix
=
dns
[
'dns64_prefix'
]
.
split
(
'/'
)[
1
]
# RFC 6147 requires prefix /96
if
int
(
dns_prefix
)
!=
96
:
raise
ConfigError
(
'DNS 6to4 prefix must be of length /96'
)
if
'system'
in
dns
:
if
not
'system_name_server'
in
dns
:
print
(
'Warning: No "system name-server" configured'
)
return
None
def
generate
(
dns
):
# bail out early - looks like removal from running config
if
not
dns
:
return
None
render
(
pdns_rec_config_file
,
'dns-forwarding/recursor.conf.tmpl'
,
dns
,
user
=
pdns_rec_user
,
group
=
pdns_rec_group
)
render
(
pdns_rec_lua_conf_file
,
'dns-forwarding/recursor.conf.lua.tmpl'
,
dns
,
user
=
pdns_rec_user
,
group
=
pdns_rec_group
)
# if vyos-hostsd didn't create its files yet, create them (empty)
for
file
in
[
pdns_rec_hostsd_lua_conf_file
,
pdns_rec_hostsd_zones_file
]:
with
open
(
file
,
'a'
):
pass
chown
(
file
,
user
=
pdns_rec_user
,
group
=
pdns_rec_group
)
return
None
def
apply
(
dns
):
if
not
dns
:
# DNS forwarding is removed in the commit
call
(
'systemctl stop pdns-recursor.service'
)
if
os
.
path
.
isfile
(
pdns_rec_config_file
):
os
.
unlink
(
pdns_rec_config_file
)
else
:
### first apply vyos-hostsd config
hc
=
hostsd_client
()
# add static nameservers to hostsd so they can be joined with other
# sources
hc
.
delete_name_servers
([
hostsd_tag
])
if
'name_server'
in
dns
:
hc
.
add_name_servers
({
hostsd_tag
:
dns
[
'name_server'
]})
# delete all nameserver tags
hc
.
delete_name_server_tags_recursor
(
hc
.
get_name_server_tags_recursor
())
## add nameserver tags - the order determines the nameserver order!
# our own tag (static)
hc
.
add_name_server_tags_recursor
([
hostsd_tag
])
if
'system'
in
dns
:
hc
.
add_name_server_tags_recursor
([
'system'
])
else
:
hc
.
delete_name_server_tags_recursor
([
'system'
])
# add dhcp nameserver tags for configured interfaces
if
'system_name_server'
in
dns
:
for
interface
in
dns
[
'system_name_server'
]:
# system_name_server key contains both IP addresses and interface
# names (DHCP) to use DNS servers. We need to check if the
# value is an interface name - only if this is the case, add the
# interface based DNS forwarder.
if
interface
in
interfaces
():
hc
.
add_name_server_tags_recursor
([
'dhcp-'
+
interface
,
'dhcpv6-'
+
interface
])
# hostsd will generate the forward-zones file
# the list and keys() are required as get returns a dict, not list
hc
.
delete_forward_zones
(
list
(
hc
.
get_forward_zones
()
.
keys
()))
if
'domain'
in
dns
:
hc
.
add_forward_zones
(
dns
[
'domain'
])
# call hostsd to generate forward-zones and its lua-config-file
hc
.
apply
()
### finally (re)start pdns-recursor
call
(
'systemctl restart pdns-recursor.service'
)
if
__name__
==
'__main__'
:
try
:
c
=
get_config
()
verify
(
c
)
generate
(
c
)
apply
(
c
)
except
ConfigError
as
e
:
print
(
e
)
exit
(
1
)
File Metadata
Details
Attached
Mime Type
text/x-script.python
Expires
Mon, Dec 15, 9:09 PM (1 d, 2 h)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
3098044
Default Alt Text
dns_forwarding.py (6 KB)
Attached To
Mode
rVYOSONEX vyos-1x
Attached
Detach File
Event Timeline
Log In to Comment