nic_router: propagate dns domain name via dhcp

With this commit, the NIC router DHCP client reads out the first DNS domain
name (DHCP option 15) if any from a DHCP reply that generates an IPv4 config
for a domain and stores the name together with the IPv4 config for that domain.
DNS domain names are reported via the new report tag '<dns-domain>' if the
'config' attribute in the config tag '<report>' is set.

Furthermore, the NIC router DHCP server becomes able to obtain a DNS domain
name from another domain that has a DHCP client dynamically (given the config
attribute 'dns_config_from' is set and no static DNS config is given) or
statically from its configuration (new config tag '<dns-domain>') and propagate
this name with DHCP replies (DHCP option 15).

The 'nic_router_dhcp_*' tests are adapted to test the new feautures.

The commit also gets rid of some mirrored files in
'test/nic_router_dhcp/manager'.

Fixes #4246
This commit is contained in:
Martin Stein 2021-08-10 16:57:25 +02:00 committed by Christian Helmuth
parent fa64aae7f8
commit 812fdec27c
23 changed files with 457 additions and 328 deletions

View File

@ -127,6 +127,7 @@ class Net::Dhcp_packet
SUBNET_MASK = 1,
ROUTER = 3,
DNS_SERVER = 6,
DOMAIN_NAME = 15,
BROADCAST_ADDR = 28,
REQ_IP_ADDR = 50,
IP_LEASE_TIME = 51,
@ -227,6 +228,28 @@ class Net::Dhcp_packet
}
};
/**
* Domain name option
*/
class Domain_name : public Option
{
private:
char _name[0];
public:
static constexpr Code CODE = Code::DOMAIN_NAME;
Domain_name (Genode::size_t len) : Option(CODE, len) { }
template <typename FUNC>
void with_string(FUNC && func) const
{
func(_name, Option::len());
}
};
enum class Message_type : Genode::uint8_t {
DISCOVER = 1,
OFFER = 2,
@ -442,6 +465,16 @@ class Net::Dhcp_packet
_base += header_size + data.size();
}
void append_domain_name(char const *data_src,
Genode::size_t data_size)
{
Genode::size_t const header_size { sizeof(Domain_name) };
_size_guard.consume_head(header_size + data_size);
Genode::memcpy((char *)(_base + header_size), data_src, data_size);
Genode::construct_at<Domain_name>((void *)_base, data_size);
_base += header_size + data_size;
}
};

View File

@ -63,6 +63,7 @@ append config {
<dns-server ip="1.2.3.4"/>
<dns-server ip="2.3.4.5"/>
<dns-server ip="3.4.5.6"/>
<dns-domain name="genode.org"/>
</dhcp-server>
@ -96,7 +97,7 @@ append config {
<sleep milliseconds="2000"/>
<inline>
<config>
<config verbose="yes">
<policy label="nic_router_2 -> " domain="downlink"/>
@ -106,6 +107,7 @@ append config {
ip_last="10.2.4.2">
<dns-server ip="6.7.8.9"/>
<dns-domain name="this_is_a_way_to_long_dns_domain_name_that_should_be_rejected_by_the_router_and_cause_the_corresponding_dhcp_option_to_disappear_but_you_never_know_and_so_we_better_test_it"/>
</dhcp-server>
@ -126,6 +128,8 @@ append config {
<dhcp-server ip_first="10.2.4.200"
ip_last="10.2.4.200">
<dns-domain name="genodians.org"/>
</dhcp-server>
</domain>
@ -145,6 +149,8 @@ append config {
<dhcp-server ip_first="10.2.3.2"
ip_last="10.2.3.2">
<dns-domain name="genodians.org"/>
</dhcp-server>
</domain>
@ -281,6 +287,7 @@ append done_string ".* Router: 10.0.3.1.*\n"
append done_string ".* DNS server #1: 1.2.3.4.*\n"
append done_string ".* DNS server #2: 2.3.4.5.*\n"
append done_string ".* DNS server #3: 3.4.5.6.*\n"
append done_string ".* DNS domain name: genode.org.*\n"
append done_string ".*DHCP request completed:.*\n"
append done_string ".* IP lease time: 3600 seconds.*\n"
append done_string ".* Interface: 10.0.3.2/24.*\n"
@ -296,10 +303,12 @@ append done_string ".*DHCP request completed:.*\n"
append done_string ".* IP lease time: 3600 seconds.*\n"
append done_string ".* Interface: 10.0.3.2/24.*\n"
append done_string ".* Router: 10.0.3.1.*\n"
append done_string ".* DNS domain name: genodians.org.*\n"
append done_string ".*DHCP request completed:.*\n"
append done_string ".* IP lease time: 3600 seconds.*\n"
append done_string ".* Interface: 10.0.3.2/24.*\n"
append done_string ".* Router: 10.0.3.1.*\n"
append done_string ".* DNS domain name: genodians.org.*\n"
append done_string ".*DHCP request completed:.*\n"
append done_string ".* IP lease time: 3600 seconds.*\n"
append done_string ".* Interface: 10.0.3.2/24.*\n"
@ -307,5 +316,6 @@ append done_string ".* Router: 10.0.3.1.*\n"
append done_string ".* DNS server #1: 1.2.3.4.*\n"
append done_string ".* DNS server #2: 2.3.4.5.*\n"
append done_string ".* DNS server #3: 3.4.5.6.*\n"
append done_string ".* DNS domain name: genode.org.*\n"
run_genode_until $done_string 30

View File

@ -441,6 +441,7 @@ this:
! ip_last="10.0.1.100"
! ip_lease_time_sec="3600">
!
! <dns-domain name="genodians.org" />
! <dns-server ip="8.8.8.8" />
! <dns-server ip="1.1.1.1" />
! ...
@ -468,6 +469,10 @@ lifetime of an IPv4 address assignment in seconds. The IPv4 address range must
be in the subnet defined by the 'interface' attribute of the <domain> tag and
must not cover the IPv4 address given by this attribute.
The <dns-domain> sub-tag from the first example statically provides a DNS
domain name that shall be propagated by the DHCP server through a DHCP option
15 entry to its clients.
The <dns-server> sub-tags from the first example statically provide a list of
DNS server addresses that shall be propagated by the DHCP server through a DHCP
option 6 entry to its clients. These addresses might be of any IP subnet. The
@ -475,14 +480,15 @@ addresses in the DHCP option 6 entry in the DHCP replies will have the same
order as the <dns-server> tags in the configuration.
The 'dns_config_from' attribute from the second example takes effect only when
the <dhcp-server> tag does not contain any <dns-server> sub-tags. The attribute
states the domain from whose IP config to take the list of propagated DNS
server addresses. Note that the order of DNS server adresses is not altered
thereby. This is useful in scenarios where these addresses must be obtained
dynamically through the DHCP client of another domain. An implication of the
'dns_config_from' attribute is that the link state of all interfaces at the
domain with the DHCP server becomes bound to the validity of the IP config of
the domain that is stated in the attribute.
the <dhcp-server> tag does not contain any <dns-domain> or <dns-server>
sub-tags. The attribute states the domain from whose IP config to take the DNS
domain name and the list of DNS server addresses that shall be propagated. Note
that the order of DNS server adresses is not altered thereby. This is useful in
scenarios where these addresses must be obtained dynamically through the DHCP
client of another domain. An implication of the 'dns_config_from' attribute is
that the link state of all interfaces at the domain with the DHCP server
becomes bound to the validity of the IP config of the domain that is stated in
the attribute.
The lifetime of an IP address assignment that was yet only offered to the
client can be configured for all domains in the <config> tag of the router:
@ -548,6 +554,7 @@ A complete state report of the NIC router is structured the following way
! <domain name="domain_1" rx_bytes="17597" tx_bytes="7788"
! ipv4="100.200.0.10/24" gw="100.200.0.1">
!
! <dns-domain name="genodians.org"/>
! <dns ip="100.200.0.8"/>
! <dns ip="1.1.1.1"/>
! <dns ip="8.8.8.8"/>
@ -687,14 +694,15 @@ simply the 'limit' value minus the 'used' value.
'config'
A boolean value that controls whether the attributes 'ipv4' and 'gw' of the
<domain> tag and the subtag <dns> in the <domain> tag are generated. The
attribute 'ipv4' contains the current IPv4 address of the router in this domain
suffixed by the length of the subnet prefix in bits. The 'gw' attribute
contains the IPv4 address of the gateway in this domain. Each <dns> subtag of a
<domain> tag shows the IPv4 address of a DNS server known to this domain. The
<dns> subtags have the same order that the addresses had in the DHCP option 6
entry of the DHCP reply that the router received and that led to the current
IPv4 configuration of the domain.
<domain> tag and the subtags <dns> and <dns-domain> in the <domain> tag are
generated. The attribute 'ipv4' contains the current IPv4 address of the router
in this domain suffixed by the length of the subnet prefix in bits. The 'gw'
attribute contains the IPv4 address of the gateway in this domain. Each <dns>
subtag of a <domain> tag shows the IPv4 address of a DNS server known to this
domain. The <dns> subtags have the same order that the addresses had in the
DHCP option 6 entry of the DHCP reply that the router received and that led to
the current IPv4 configuration of the domain. The <dns-domain> subtag of the
<domain> tag states the DNS domain name of this domain if any.
'config_triggers'

View File

@ -12,6 +12,12 @@
</xs:restriction>
</xs:simpleType><!-- Domain_name -->
<xs:simpleType name="Dns_domain_name">
<xs:restriction base="xs:string">
<xs:minLength value="1"/>
</xs:restriction>
</xs:simpleType><!-- Dns_domain_name -->
<xs:simpleType name="Icmp_type_3_code_attribute">
<xs:restriction base="xs:string">
<xs:enumeration value="no" />
@ -140,6 +146,12 @@
</xs:complexType>
</xs:element><!-- dns-server -->
<xs:element name="dns-domain">
<xs:complexType>
<xs:attribute name="name" type="Dns_domain_name" />
</xs:complexType>
</xs:element><!-- dns-domain -->
</xs:choice>
<xs:attribute name="ip_first" type="Ipv4_address" />
<xs:attribute name="ip_last" type="Ipv4_address" />

View File

@ -16,6 +16,7 @@
#include <interface.h>
#include <domain.h>
#include <configuration.h>
#include <xml_node.h>
using namespace Net;
using namespace Genode;
@ -42,6 +43,18 @@ Dhcp_server_base::Dhcp_server_base(Xml_node const &node,
_invalid(domain, "invalid DNS server entry");
}
});
node.with_sub_node("dns-domain", [&] (Xml_node const &sub_node) {
xml_node_with_attribute(sub_node, "name", [&] (Xml_attribute const &attr) {
_dns_domain_name.set_to(attr);
if (domain.config().verbose() &&
!_dns_domain_name.valid()) {
log("[", domain, "] rejecting oversized DNS "
"domain name from DHCP server configuration");
}
});
});
}
@ -108,6 +121,9 @@ void Dhcp_server::print(Output &output) const
_dns_servers.for_each([&] (Dns_server const &dns_server) {
Genode::print(output, "DNS server ", dns_server.ip(), ", ");
});
_dns_domain_name.with_string([&] (Dns_domain_name::String const &str) {
Genode::print(output, "DNS domain name ", str, ", ");
});
try { Genode::print(output, "DNS config from ", _dns_config_from(), ", "); }
catch (Pointer<Domain>::Invalid) { }
@ -118,9 +134,11 @@ void Dhcp_server::print(Output &output) const
}
bool Dhcp_server::dns_servers_equal_to_those_of(Dhcp_server const &dhcp_server) const
bool Dhcp_server::config_equal_to_that_of(Dhcp_server const &other) const
{
return _dns_servers.equal_to(dhcp_server._dns_servers);
return _ip_lease_time.value == other._ip_lease_time.value &&
_dns_servers.equal_to(other._dns_servers) &&
_dns_domain_name.equal_to(other._dns_domain_name);
}
@ -177,7 +195,9 @@ void Dhcp_server::free_ip(Domain const &domain,
Pointer<Domain> Dhcp_server::_init_dns_config_from(Genode::Xml_node const node,
Domain_tree &domains)
{
if (!_dns_servers.empty()) {
if (!_dns_servers.empty() ||
_dns_domain_name.valid()) {
return Pointer<Domain>();
}
Domain_name dns_config_from =

View File

@ -18,7 +18,7 @@
#include <bit_allocator_dynamic.h>
#include <list.h>
#include <pointer.h>
#include <dns_server.h>
#include <dns.h>
#include <ipv4_config.h>
/* Genode includes */
@ -47,8 +47,9 @@ class Net::Dhcp_server_base
{
protected:
Genode::Allocator &_alloc;
Net::List<Dns_server> _dns_servers { };
Genode::Allocator &_alloc;
Dns_server_list _dns_servers { };
Dns_domain_name _dns_domain_name { _alloc };
void _invalid(Domain const &domain,
char const *reason);
@ -123,8 +124,15 @@ class Net::Dhcp_server : private Genode::Noncopyable,
}
}
bool
dns_servers_equal_to_those_of(Dhcp_server const &dhcp_server) const;
Dns_domain_name const &dns_domain_name() const
{
if (_dns_config_from.valid()) {
return _resolve_dns_config_from().dns_domain_name();
}
return _dns_domain_name;
}
bool config_equal_to_that_of(Dhcp_server const &dhcp_server) const;
/*********

View File

@ -0,0 +1,128 @@
/*
* \brief Utilities for handling DNS configurations
* \author Martin Stein
* \date 2020-11-17
*/
/*
* Copyright (C) 2020 Genode Labs GmbH
*
* This file is part of the Genode OS framework, which is distributed
* under the terms of the GNU Affero General Public License version 3.
*/
/* local includes */
#include <dns.h>
#include <domain.h>
#include <configuration.h>
/* Genode includes */
#include <util/xml_node.h>
using namespace Net;
using namespace Genode;
/****************
** Dns_server **
****************/
Dns_server::Dns_server(Ipv4_address const &ip)
:
_ip { ip }
{
if (!_ip.valid()) {
throw Invalid { };
}
}
bool Dns_server::equal_to(Dns_server const &server) const
{
return _ip == server._ip;
}
/*********************
** Dns_domain_name **
*********************/
void Dns_domain_name::set_to(Dns_domain_name const &name)
{
if (name.valid()) {
name.with_string([&] (String const &string) {
if (_string.valid()) {
_string() = string;
} else {
_string = *new (_alloc) String { string };
}
});
} else {
set_invalid();
}
}
void Dns_domain_name::set_to(Xml_attribute const &name_attr)
{
name_attr.with_raw_value([&] (char const *base, size_t size) {
if (size < STRING_CAPACITY) {
if (_string.valid()) {
_string() = Cstring { base, size };
} else {
_string = *new (_alloc) String { Cstring { base, size } };
}
} else {
set_invalid();
}
});
}
void Dns_domain_name::set_to(Dhcp_packet::Domain_name const &name_option)
{
name_option.with_string([&] (char const *base, size_t size) {
if (size < STRING_CAPACITY) {
if (_string.valid()) {
_string() = Cstring { base, size };
} else {
_string = *new (_alloc) String { Cstring { base, size } };
}
} else {
set_invalid();
}
});
}
void Dns_domain_name::set_invalid()
{
if (_string.valid()) {
_alloc.free(&_string(), sizeof(String));
_string = { };
}
}
bool Dns_domain_name::equal_to(Dns_domain_name const &other) const
{
if (_string.valid()) {
if (other._string.valid()) {
return _string() == other._string();
}
return false;
}
return !other._string.valid();
}
Dns_domain_name::Dns_domain_name(Genode::Allocator &alloc)
:
_alloc { alloc }
{ }
Dns_domain_name::~Dns_domain_name()
{
set_invalid();
}

View File

@ -0,0 +1,104 @@
/*
* \brief Utilities for handling DNS configurations
* \author Martin Stein
* \date 2020-11-17
*/
/*
* Copyright (C) 2020 Genode Labs GmbH
*
* This file is part of the Genode OS framework, which is distributed
* under the terms of the GNU Affero General Public License version 3.
*/
#ifndef _DNS_H_
#define _DNS_H_
/* local includes */
#include <list.h>
#include <pointer.h>
/* Genode includes */
#include <util/reconstructible.h>
#include <net/ipv4.h>
#include <net/dhcp.h>
namespace Genode {
class Xml_attribute;
}
namespace Net {
class Dns_server;
class Dns_domain_name;
using Dns_server_list = Net::List<Dns_server>;
}
class Net::Dns_server : private Genode::Noncopyable,
public Net::List<Dns_server>::Element
{
private:
Net::Ipv4_address const _ip;
public:
struct Invalid : Genode::Exception { };
Dns_server(Net::Ipv4_address const &ip);
bool equal_to(Dns_server const &server) const;
/***************
** Accessors **
***************/
Net::Ipv4_address const &ip() const { return _ip; }
};
class Net::Dns_domain_name : private Genode::Noncopyable
{
private:
enum { STRING_CAPACITY = 160 };
public:
using String = Genode::String<STRING_CAPACITY>;
private:
Genode::Allocator &_alloc;
Pointer<String> _string { };
public:
Dns_domain_name(Genode::Allocator &alloc);
~Dns_domain_name();
void set_to(Dns_domain_name const &name);
void set_to(Genode::Xml_attribute const &name_attr);
void set_to(Dhcp_packet::Domain_name const &name_option);
void set_invalid();
bool valid() const { return _string.valid(); }
template <typename FUNC>
void with_string(FUNC && func) const
{
if (_string.valid()) {
func(_string());
}
}
bool equal_to(Dns_domain_name const &other) const;
};
#endif /* _DNS_H_ */

View File

@ -1,34 +0,0 @@
/*
* \brief DNS server entry of a DHCP server or IPv4 config
* \author Martin Stein
* \date 2020-11-17
*/
/*
* Copyright (C) 2020 Genode Labs GmbH
*
* This file is part of the Genode OS framework, which is distributed
* under the terms of the GNU Affero General Public License version 3.
*/
/* local includes */
#include <dns_server.h>
using namespace Net;
using namespace Genode;
Net::Dns_server::Dns_server(Ipv4_address const &ip)
:
_ip { ip }
{
if (!_ip.valid()) {
throw Invalid { };
}
}
bool Net::Dns_server::equal_to(Dns_server const &server) const
{
return _ip == server._ip;
}

View File

@ -1,50 +0,0 @@
/*
* \brief DNS server entry of a DHCP server or IPv4 config
* \author Martin Stein
* \date 2020-11-17
*/
/*
* Copyright (C) 2020 Genode Labs GmbH
*
* This file is part of the Genode OS framework, which is distributed
* under the terms of the GNU Affero General Public License version 3.
*/
#ifndef _DNS_SERVER_H_
#define _DNS_SERVER_H_
/* local includes */
#include <list.h>
/* Genode includes */
#include <net/ipv4.h>
namespace Net { class Dns_server; }
class Net::Dns_server : private Genode::Noncopyable,
public Net::List<Dns_server>::Element
{
private:
Net::Ipv4_address const _ip;
public:
struct Invalid : Genode::Exception { };
Dns_server(Net::Ipv4_address const &ip);
bool equal_to(Dns_server const &server) const;
/***************
** Accessors **
***************/
Net::Ipv4_address const &ip() const { return _ip; }
};
#endif /* _DHCP_SERVER_H_ */

View File

@ -113,7 +113,7 @@ void Domain::discard_ip_config()
void Domain::ip_config_from_dhcp_ack(Dhcp_packet &dhcp_ack)
{
_reconstruct_ip_config([&] (Reconstructible<Ipv4_config> &ip_config) {
ip_config.construct(dhcp_ack, _alloc); });
ip_config.construct(dhcp_ack, _alloc, *this); });
}
@ -397,6 +397,13 @@ void Domain::report(Xml_generator &xml)
xml.attribute("ip", String<16>(dns_server.ip()));
});
});
ip_config().dns_domain_name().with_string(
[&] (Dns_domain_name::String const &str)
{
xml.node("dns-domain", [&] () {
xml.attribute("name", str);
});
});
empty = false;
}
if (_config.report().stats()) {

View File

@ -678,6 +678,11 @@ void Interface::_send_dhcp_reply(Dhcp_server const &dhcp_srv,
data.append_address(addr);
});
});
dhcp_srv.dns_domain_name().with_string(
[&] (Dns_domain_name::String const &str)
{
dhcp_opts.append_domain_name(str.string(), str.length());
});
dhcp_opts.append_option<Dhcp_packet::Broadcast_addr>(local_intf.broadcast_address());
dhcp_opts.append_option<Dhcp_packet::Options_end>();
@ -1908,12 +1913,7 @@ void Interface::_update_dhcp_allocations(Domain &old_domain,
try {
Dhcp_server &old_dhcp_srv = old_domain.dhcp_server();
Dhcp_server &new_dhcp_srv = new_domain.dhcp_server();
if (!old_dhcp_srv.dns_servers_equal_to_those_of(new_dhcp_srv)) {
throw Pointer<Dhcp_server>::Invalid();
}
if (old_dhcp_srv.ip_lease_time().value !=
new_dhcp_srv.ip_lease_time().value)
{
if (!old_dhcp_srv.config_equal_to_that_of(new_dhcp_srv)) {
throw Pointer<Dhcp_server>::Invalid();
}
_dhcp_allocations.for_each([&] (Dhcp_allocation &allocation) {

View File

@ -16,6 +16,8 @@
/* local includes */
#include <ipv4_config.h>
#include <domain.h>
#include <configuration.h>
using namespace Genode;
using namespace Net;
@ -45,22 +47,23 @@ Ipv4_config::Ipv4_config(Ipv4_config const &ip_config,
_interface { ip_config._interface },
_gateway { ip_config._gateway }
{
ip_config._dns_servers.for_each([&] (Dns_server const &dns_server) {
ip_config.for_each_dns_server([&] (Dns_server const &dns_server) {
_dns_servers.insert_as_tail(
*new (alloc) Dns_server(dns_server.ip()));
});
_dns_domain_name.set_to(ip_config.dns_domain_name());
}
Ipv4_config::Ipv4_config(Dhcp_packet &dhcp_ack,
Allocator &alloc)
Ipv4_config::Ipv4_config(Dhcp_packet &dhcp_ack,
Allocator &alloc,
Domain const &domain)
:
_alloc { alloc },
_interface { dhcp_ack.yiaddr(),
dhcp_ipv4_option<Dhcp_packet::Subnet_mask>(dhcp_ack) },
_gateway { dhcp_ipv4_option<Dhcp_packet::Router_ipv4>(dhcp_ack) }
{
try {
Dhcp_packet::Dns_server const &dns_server {
dhcp_ack.option<Dhcp_packet::Dns_server>() };
@ -70,6 +73,17 @@ Ipv4_config::Ipv4_config(Dhcp_packet &dhcp_ack,
});
}
catch (Dhcp_packet::Option_not_found) { }
try {
_dns_domain_name.set_to(dhcp_ack.option<Dhcp_packet::Domain_name>());
if (domain.config().verbose() &&
!_dns_domain_name.valid()) {
log("[", domain, "] rejecting oversized DNS "
"domain name from DHCP reply");
}
}
catch (Dhcp_packet::Option_not_found) { }
}

View File

@ -17,12 +17,16 @@
/* local includes */
#include <ipv4_address_prefix.h>
#include <dhcp.h>
#include <dns_server.h>
#include <dns.h>
/* Genode includes */
#include <util/xml_node.h>
namespace Net { class Ipv4_config; }
namespace Net {
class Domain;
class Ipv4_config;
}
class Net::Ipv4_config
{
@ -36,7 +40,8 @@ class Net::Ipv4_config
bool const _point_to_point { _gateway_valid &&
_interface_valid &&
_interface.prefix == 32 };
Net::List<Dns_server> _dns_servers { };
Dns_server_list _dns_servers { };
Dns_domain_name _dns_domain_name { _alloc };
bool const _valid { _point_to_point ||
(_interface_valid &&
(!_gateway_valid ||
@ -45,7 +50,8 @@ class Net::Ipv4_config
public:
Ipv4_config(Net::Dhcp_packet &dhcp_ack,
Genode::Allocator &alloc);
Genode::Allocator &alloc,
Domain const &domain);
Ipv4_config(Genode::Xml_node const &domain_node,
Genode::Allocator &alloc);
@ -59,16 +65,17 @@ class Net::Ipv4_config
bool operator != (Ipv4_config const &other) const
{
return _interface != other._interface ||
_gateway != other._gateway ||
!_dns_servers.equal_to(other._dns_servers);
return _interface != other._interface ||
_gateway != other._gateway ||
!_dns_servers.equal_to(other._dns_servers) ||
!_dns_domain_name.equal_to(other._dns_domain_name);
}
template <typename FUNC>
void for_each_dns_server(FUNC && functor) const
void for_each_dns_server(FUNC && func) const
{
_dns_servers.for_each([&] (Dns_server const &dns_server) {
functor(dns_server);
func(dns_server);
});
}
@ -84,10 +91,11 @@ class Net::Ipv4_config
** Accessors **
***************/
bool valid() const { return _valid; }
Ipv4_address_prefix const &interface() const { return _interface; }
Ipv4_address const &gateway() const { return _gateway; }
bool gateway_valid() const { return _gateway_valid; }
bool valid() const { return _valid; }
Ipv4_address_prefix const &interface() const { return _interface; }
Ipv4_address const &gateway() const { return _gateway; }
bool gateway_valid() const { return _gateway_valid; }
Dns_domain_name const &dns_domain_name() const { return _dns_domain_name; }
};
#endif /* _IPV4_CONFIG_H_ */

View File

@ -73,6 +73,8 @@ class Net::Const_pointer
return *_obj;
}
bool valid() const { return _obj != nullptr; }
};
#endif /* _POINTER_H_ */

View File

@ -22,7 +22,7 @@ SRC_CC += \
link.cc \
transport_rule.cc \
permit_rule.cc \
dns_server.cc \
dns.cc \
dhcp_client.cc \
dhcp_server.cc \
report.cc \
@ -30,7 +30,6 @@ SRC_CC += \
uplink_session_root.cc \
communication_buffer.cc \
INC_DIR += $(PRG_DIR)
CONFIG_XSD = config.xsd

View File

@ -24,6 +24,16 @@ namespace Genode {
Microseconds read_sec_attr(Xml_node const node,
char const *name,
uint64_t const default_sec);
template <typename FUNC>
void xml_node_with_attribute(Xml_node const node,
char const *name,
FUNC && func)
{
if (node.has_attribute(name)) {
func(node.attribute(name));
}
}
}
#endif /* _XML_NODE_H_ */

View File

@ -185,6 +185,15 @@ void Dhcp_client::_handle_dhcp_reply(Dhcp_packet &dhcp)
});
}
catch (Dhcp_packet::Option_not_found) { }
try {
Dhcp_packet::Domain_name const &domain_name {
dhcp.option<Dhcp_packet::Domain_name>() };
domain_name.with_string([&] (char const *base, size_t size) {
log(" DNS domain name: ", Cstring { base, size });
});
}
catch (Dhcp_packet::Option_not_found) { }
Ipv4_config ip_config(
Ipv4_address_prefix(

View File

@ -1,34 +0,0 @@
/*
* \brief DNS server entry of a DHCP server or IPv4 config
* \author Martin Stein
* \date 2020-11-17
*/
/*
* Copyright (C) 2020 Genode Labs GmbH
*
* This file is part of the Genode OS framework, which is distributed
* under the terms of the GNU Affero General Public License version 3.
*/
/* local includes */
#include <dns_server.h>
using namespace Net;
using namespace Genode;
Local::Dns_server::Dns_server(Ipv4_address const &ip)
:
_ip { ip }
{
if (!_ip.valid()) {
throw Invalid { };
}
}
bool Local::Dns_server::equal_to(Dns_server const &server) const
{
return _ip == server._ip;
}

View File

@ -1,50 +0,0 @@
/*
* \brief DNS server entry of a DHCP server or IPv4 config
* \author Martin Stein
* \date 2020-11-17
*/
/*
* Copyright (C) 2020 Genode Labs GmbH
*
* This file is part of the Genode OS framework, which is distributed
* under the terms of the GNU Affero General Public License version 3.
*/
#ifndef _DNS_SERVER_H_
#define _DNS_SERVER_H_
/* local includes */
#include <list.h>
/* Genode includes */
#include <net/ipv4.h>
namespace Local { class Dns_server; }
class Local::Dns_server : private Genode::Noncopyable,
public Local::List<Dns_server>::Element
{
private:
Net::Ipv4_address const _ip;
public:
struct Invalid : Genode::Exception { };
Dns_server(Net::Ipv4_address const &ip);
bool equal_to(Dns_server const &server) const;
/***************
** Accessors **
***************/
Net::Ipv4_address const &ip() const { return _ip; }
};
#endif /* _DHCP_SERVER_H_ */

View File

@ -1,102 +0,0 @@
/*
* \brief Genode list with additional functions needed by NIC router
* \author Martin Stein
* \date 2016-08-19
*/
/*
* Copyright (C) 2016-2017 Genode Labs GmbH
*
* This file is part of the Genode OS framework, which is distributed
* under the terms of the GNU Affero General Public License version 3.
*/
#ifndef _LIST_H_
#define _LIST_H_
/* Genode includes */
#include <util/list.h>
#include <base/allocator.h>
namespace Local { template <typename> class List; }
template <typename LT>
struct Local::List : Genode::List<LT>
{
using Base = Genode::List<LT>;
template <typename FUNC>
void for_each(FUNC && functor)
{
for (LT *elem = Base::first(); elem; )
{
LT *const next = elem->Base::Element::next();
functor(*elem);
elem = next;
}
}
template <typename FUNC>
void for_each(FUNC && functor) const
{
for (LT const *elem = Base::first(); elem; )
{
LT const *const next = elem->Base::Element::next();
functor(*elem);
elem = next;
}
}
void destroy_each(Genode::Deallocator &dealloc)
{
while (LT *elem = Base::first()) {
Base::remove(elem);
destroy(dealloc, elem);
}
}
bool empty() const
{
return Base::first() == nullptr;
}
void insert_as_tail(LT const &le)
{
LT *elem { Base::first() };
if (elem) {
while (elem->Base::Element::next()) {
elem = elem->Base::Element::next();
}
}
Base::insert(&le, elem);
}
bool equal_to(List<LT> const &list) const
{
LT const *curr_elem_1 { Base::first() };
LT const *curr_elem_2 { list.Base::first() };
while (true) {
if (curr_elem_1 == nullptr) {
return curr_elem_2 == nullptr;
}
if (curr_elem_2 == nullptr) {
return false;
}
LT const *const next_elem_1 {
curr_elem_1->List<LT>::Element::next() };
LT const *const next_elem_2 {
curr_elem_2->List<LT>::Element::next() };
if (!curr_elem_1->equal_to(*curr_elem_2)) {
return false;
}
curr_elem_1 = next_elem_1;
curr_elem_2 = next_elem_2;
}
}
};
#endif /* _LIST_H_ */

View File

@ -20,7 +20,10 @@
/* local includes */
#include <ipv4_address_prefix.h>
#include <dns_server.h>
/* NIC router includes */
#include <dns.h>
#include <xml_node.h>
using namespace Net;
using namespace Genode;
@ -39,7 +42,8 @@ class Local::Main
Signal_handler<Main> _router_state_handler { _env.ep(), *this, &Main::_handle_router_state };
Expanding_reporter _router_config_reporter { _env, "config", "router_config" };
bool _router_config_outdated { true };
Local::List<Dns_server> _dns_servers { };
Dns_server_list _dns_servers { };
Dns_domain_name _dns_domain_name { _heap };
void _handle_router_state();
@ -99,7 +103,7 @@ void Local::Main::_handle_router_state()
* Read out all DNS servers from the new uplink state
* and memorize them in a function-local list.
*/
Local::List<Dns_server> dns_servers { };
Dns_server_list dns_servers { };
domain_node.for_each_sub_node(
"dns",
[&] (Xml_node const &dns_node)
@ -110,8 +114,8 @@ void Local::Main::_handle_router_state()
});
/*
* If the new list of DNS servers differs our member list,
* update the member list, and remember to write out a new router
* If the new list of DNS servers differs from the stored list,
* update the stored list, and remember to write out a new router
* configuration.
*/
if (!_dns_servers.equal_to(dns_servers)) {
@ -124,6 +128,19 @@ void Local::Main::_handle_router_state()
_router_config_outdated = true;
}
dns_servers.destroy_each(_heap);
/* read out new DNS domain name */
Dns_domain_name dns_domain_name { _heap };
domain_node.with_sub_node("dns-domain", [&] (Xml_node const &sub_node) {
xml_node_with_attribute(sub_node, "name", [&] (Xml_attribute const &attr) {
dns_domain_name.set_to(attr);
});
});
/* update stored DNS domain name if necessary */
if (!_dns_domain_name.equal_to(dns_domain_name)) {
_dns_domain_name.set_to(dns_domain_name);
_router_config_outdated = true;
}
}
});
@ -164,6 +181,13 @@ void Local::Main::_handle_router_state()
xml.attribute("ip", String<16>(dns_server.ip()));
});
});
_dns_domain_name.with_string(
[&] (Dns_domain_name::String const &str)
{
xml.node("dns-domain", [&] () {
xml.attribute("name", str);
});
});
});
});
});

View File

@ -2,6 +2,9 @@ TARGET = test-nic_router_dhcp-manager
LIBS += base
SRC_CC += main.cc ipv4_address_prefix.cc dns_server.cc
SRC_CC += main.cc ipv4_address_prefix.cc dns.cc xml_node.cc
INC_DIR += $(PRG_DIR)
INC_DIR += $(PRG_DIR) $(REP_DIR)/src/server/nic_router
vpath dns.cc $(REP_DIR)/src/server/nic_router
vpath xml_node.cc $(REP_DIR)/src/server/nic_router