mirror of
https://github.com/genodelabs/genode.git
synced 2025-01-31 08:25:38 +00:00
nic_router: list dns servers in one dhcp option 6
The NIC router DHCP server used to add an extra option 6 field to DHCP replies for each DNS server address. This conflicts with RFC #2132 section 3.8 which states that the addresses should be listed within one option 6 field without delimiter. The discrepancy is fixed by this commit. Ref #4242
This commit is contained in:
parent
80c1459e79
commit
9e6f7988c2
@ -201,6 +201,32 @@ class Net::Dhcp_packet
|
||||
Parameter_request_list(Genode::size_t len) : Option(CODE, len) { }
|
||||
};
|
||||
|
||||
/**
|
||||
* Domain name server option
|
||||
*/
|
||||
class Dns_server : public Option
|
||||
{
|
||||
private:
|
||||
|
||||
Ipv4_address _dns_servers[0];
|
||||
|
||||
public:
|
||||
|
||||
static constexpr Code CODE = Code::DNS_SERVER;
|
||||
|
||||
Dns_server(Genode::size_t len) : Option(CODE, len) { }
|
||||
|
||||
template <typename FUNC>
|
||||
void for_each_address(FUNC && func) const
|
||||
{
|
||||
for (unsigned idx = 0;
|
||||
idx < len() / sizeof(_dns_servers[0]); idx++) {
|
||||
|
||||
func(_dns_servers[idx]);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
enum class Message_type : Genode::uint8_t {
|
||||
DISCOVER = 1,
|
||||
OFFER = 2,
|
||||
@ -341,6 +367,36 @@ class Net::Dhcp_packet
|
||||
Genode::size_t size() const { return _size; }
|
||||
};
|
||||
|
||||
class Dns_server_data
|
||||
{
|
||||
private:
|
||||
|
||||
Ipv4_address *const _addr_array;
|
||||
Genode::size_t _addr_idx { 0 };
|
||||
SIZE_GUARD &_pkt_size_guard;
|
||||
|
||||
public:
|
||||
|
||||
Dns_server_data(Ipv4_address *addr_array,
|
||||
SIZE_GUARD &pkt_size_guard)
|
||||
:
|
||||
_addr_array { addr_array },
|
||||
_pkt_size_guard { pkt_size_guard }
|
||||
{ }
|
||||
|
||||
void append_address(Ipv4_address const &addr)
|
||||
{
|
||||
_pkt_size_guard.consume_head(sizeof(_addr_array[0]));
|
||||
_addr_array[_addr_idx] = addr;
|
||||
_addr_idx++;
|
||||
}
|
||||
|
||||
Genode::size_t size() const
|
||||
{
|
||||
return _addr_idx * sizeof(Ipv4_address);
|
||||
}
|
||||
};
|
||||
|
||||
Options_aggregator(Dhcp_packet &packet,
|
||||
SIZE_GUARD &size_guard)
|
||||
:
|
||||
@ -371,6 +427,21 @@ class Net::Dhcp_packet
|
||||
|
||||
_base += sizeof(Parameter_request_list) + data.size();
|
||||
}
|
||||
|
||||
template <typename INIT_DATA>
|
||||
void append_dns_server(INIT_DATA && init_data)
|
||||
{
|
||||
Genode::size_t const header_size { sizeof(Dns_server) };
|
||||
_size_guard.consume_head(header_size);
|
||||
Dns_server_data data {
|
||||
(Ipv4_address *)(_base + header_size), _size_guard };
|
||||
|
||||
init_data(data);
|
||||
Genode::construct_at<Dns_server>(
|
||||
(void *)_base, data.size());
|
||||
|
||||
_base += header_size + data.size();
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
|
@ -469,10 +469,10 @@ 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-server> sub-tags from the first example statically provide a list of
|
||||
DNS server addresses that shall be propagated by the DHCP server through DHCP
|
||||
option 6 entries to its clients. These addresses might be of any IP subnet. The
|
||||
DHCP option 6 entries in the DHCP replies will have the same order as the
|
||||
<dns-server> tags in the configuration.
|
||||
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
|
||||
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_server_from' attribute from the second example takes effect only when
|
||||
the <dhcp-server> tag does not contain any <dns-server> sub-tags. The attribute
|
||||
@ -484,8 +484,8 @@ dynamically through the DHCP client of another domain. An implication of 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 assignment that was yet only offered to the client can be
|
||||
configured for all domains in the <config> tag of the router:
|
||||
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:
|
||||
|
||||
! <config dhcp_offer_timeout_sec="6">
|
||||
|
||||
@ -692,10 +692,9 @@ 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 when the router
|
||||
received them (i.e., the order of DHCP option 6 entries in the corresponding
|
||||
DHCP replies or the order of <dns> entries in the corresponding router
|
||||
configuration).
|
||||
<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.
|
||||
|
||||
'config_triggers'
|
||||
|
||||
|
@ -37,6 +37,7 @@ using Genode::Constructible;
|
||||
using Genode::Reconstructible;
|
||||
using Genode::Signal_context_capability;
|
||||
using Genode::Signal_transmitter;
|
||||
using Dhcp_options = Dhcp_packet::Options_aggregator<Size_guard>;
|
||||
|
||||
|
||||
/***************
|
||||
@ -671,8 +672,11 @@ void Interface::_send_dhcp_reply(Dhcp_server const &dhcp_srv,
|
||||
dhcp_opts.append_option<Dhcp_packet::Ip_lease_time>(dhcp_srv.ip_lease_time().value / 1000 / 1000);
|
||||
dhcp_opts.append_option<Dhcp_packet::Subnet_mask>(local_intf.subnet_mask());
|
||||
dhcp_opts.append_option<Dhcp_packet::Router_ipv4>(local_intf.address);
|
||||
dhcp_srv.for_each_dns_server_ip([&] (Ipv4_address const &dns_server_ip) {
|
||||
dhcp_opts.append_option<Dhcp_packet::Dns_server_ipv4>(dns_server_ip);
|
||||
|
||||
dhcp_opts.append_dns_server([&] (Dhcp_options::Dns_server_data &data) {
|
||||
dhcp_srv.for_each_dns_server_ip([&] (Ipv4_address const &addr) {
|
||||
data.append_address(addr);
|
||||
});
|
||||
});
|
||||
dhcp_opts.append_option<Dhcp_packet::Broadcast_addr>(local_intf.broadcast_address());
|
||||
dhcp_opts.append_option<Dhcp_packet::Options_end>();
|
||||
|
@ -60,19 +60,17 @@ Ipv4_config::Ipv4_config(Dhcp_packet &dhcp_ack,
|
||||
dhcp_ipv4_option<Dhcp_packet::Subnet_mask>(dhcp_ack) },
|
||||
gateway { dhcp_ipv4_option<Dhcp_packet::Router_ipv4>(dhcp_ack) }
|
||||
{
|
||||
dhcp_ack.for_each_option([&] (Dhcp_packet::Option const &opt)
|
||||
{
|
||||
if (opt.code() != Dhcp_packet::Option::Code::DNS_SERVER) {
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
dns_servers.insert_as_tail(*new (alloc)
|
||||
Dns_server(
|
||||
reinterpret_cast<Dhcp_packet::Dns_server_ipv4 const *>(&opt)->value()));
|
||||
}
|
||||
catch (Dns_server::Invalid) { }
|
||||
Dhcp_packet::Dns_server const &dns_server {
|
||||
dhcp_ack.option<Dhcp_packet::Dns_server>() };
|
||||
|
||||
dns_server.for_each_address([&] (Ipv4_address const &addr) {
|
||||
dns_servers.insert_as_tail(*new (alloc) Dns_server(addr));
|
||||
});
|
||||
}
|
||||
catch (Dhcp_packet::Option_not_found) { }
|
||||
}
|
||||
|
||||
|
||||
Ipv4_config::~Ipv4_config()
|
||||
|
@ -170,24 +170,28 @@ void Dhcp_client::_handle_dhcp_reply(Dhcp_packet &dhcp)
|
||||
log(" Interface: ", Ipv4_address_prefix(dhcp.yiaddr(), dhcp.option<Dhcp_packet::Subnet_mask>().value()));
|
||||
log(" Router: ", dhcp.option<Dhcp_packet::Router_ipv4>().value());
|
||||
|
||||
Ipv4_address dns_server { };
|
||||
Ipv4_address dns_server_addr { };
|
||||
unsigned idx { 1 };
|
||||
dhcp.for_each_option([&] (Dhcp_packet::Option const &opt)
|
||||
{
|
||||
if (!dns_server.valid()) {
|
||||
dns_server = reinterpret_cast<Dhcp_packet::Dns_server_ipv4 const *>(&opt)->value();
|
||||
try {
|
||||
Dhcp_packet::Dns_server const &dns_server {
|
||||
dhcp.option<Dhcp_packet::Dns_server>() };
|
||||
|
||||
dns_server.for_each_address([&] (Ipv4_address const &addr) {
|
||||
|
||||
if (!dns_server_addr.valid()) {
|
||||
dns_server_addr = addr;
|
||||
}
|
||||
if (opt.code() != Dhcp_packet::Option::Code::DNS_SERVER) {
|
||||
return;
|
||||
}
|
||||
log(" DNS server #", idx++, ": ", reinterpret_cast<Dhcp_packet::Dns_server_ipv4 const *>(&opt)->value());
|
||||
log(" DNS server #", idx++, ": ", addr);
|
||||
});
|
||||
}
|
||||
catch (Dhcp_packet::Option_not_found) { }
|
||||
|
||||
Ipv4_config ip_config(
|
||||
Ipv4_address_prefix(
|
||||
dhcp.yiaddr(),
|
||||
dhcp.option<Dhcp_packet::Subnet_mask>().value()),
|
||||
dhcp.option<Dhcp_packet::Router_ipv4>().value(),
|
||||
dns_server);
|
||||
dns_server_addr);
|
||||
|
||||
_handler.ip_config(ip_config);
|
||||
break;
|
||||
|
Loading…
x
Reference in New Issue
Block a user