diff --git a/repos/os/include/net/dhcp.h b/repos/os/include/net/dhcp.h index 0d5f83c98d..c23aaca91e 100644 --- a/repos/os/include/net/dhcp.h +++ b/repos/os/include/net/dhcp.h @@ -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 + 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 + 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( + (void *)_base, data.size()); + + _base += header_size + data.size(); + } }; diff --git a/repos/os/src/server/nic_router/README b/repos/os/src/server/nic_router/README index b2e3e87355..1570fc0121 100644 --- a/repos/os/src/server/nic_router/README +++ b/repos/os/src/server/nic_router/README @@ -469,10 +469,10 @@ be in the subnet defined by the 'interface' attribute of the tag and must not cover the IPv4 address given by this attribute. The 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 - 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 tags in the configuration. The 'dns_server_from' attribute from the second example takes effect only when the tag does not contain any 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 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 tag of the router: ! @@ -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 subtag of a tag shows the IPv4 address of a DNS server known to this domain. The - 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 entries in the corresponding router -configuration). + 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' diff --git a/repos/os/src/server/nic_router/interface.cc b/repos/os/src/server/nic_router/interface.cc index 218a720240..f8925bdd39 100644 --- a/repos/os/src/server/nic_router/interface.cc +++ b/repos/os/src/server/nic_router/interface.cc @@ -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; /*************** @@ -671,8 +672,11 @@ void Interface::_send_dhcp_reply(Dhcp_server const &dhcp_srv, dhcp_opts.append_option(dhcp_srv.ip_lease_time().value / 1000 / 1000); dhcp_opts.append_option(local_intf.subnet_mask()); dhcp_opts.append_option(local_intf.address); - dhcp_srv.for_each_dns_server_ip([&] (Ipv4_address const &dns_server_ip) { - dhcp_opts.append_option(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(local_intf.broadcast_address()); dhcp_opts.append_option(); diff --git a/repos/os/src/server/nic_router/ipv4_config.cc b/repos/os/src/server/nic_router/ipv4_config.cc index bd844de3ad..8bf7d6eeab 100644 --- a/repos/os/src/server/nic_router/ipv4_config.cc +++ b/repos/os/src/server/nic_router/ipv4_config.cc @@ -60,18 +60,16 @@ Ipv4_config::Ipv4_config(Dhcp_packet &dhcp_ack, dhcp_ipv4_option(dhcp_ack) }, gateway { dhcp_ipv4_option(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(&opt)->value())); - } - catch (Dns_server::Invalid) { } - }); + + try { + Dhcp_packet::Dns_server const &dns_server { + dhcp_ack.option() }; + + 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) { } } diff --git a/repos/os/src/test/nic_router_dhcp/client/dhcp_client.cc b/repos/os/src/test/nic_router_dhcp/client/dhcp_client.cc index f1a3271f04..629a210af4 100644 --- a/repos/os/src/test/nic_router_dhcp/client/dhcp_client.cc +++ b/repos/os/src/test/nic_router_dhcp/client/dhcp_client.cc @@ -170,24 +170,28 @@ void Dhcp_client::_handle_dhcp_reply(Dhcp_packet &dhcp) log(" Interface: ", Ipv4_address_prefix(dhcp.yiaddr(), dhcp.option().value())); log(" Router: ", dhcp.option().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(&opt)->value(); - } - if (opt.code() != Dhcp_packet::Option::Code::DNS_SERVER) { - return; - } - log(" DNS server #", idx++, ": ", reinterpret_cast(&opt)->value()); - }); + try { + Dhcp_packet::Dns_server const &dns_server { + dhcp.option() }; + + dns_server.for_each_address([&] (Ipv4_address const &addr) { + + if (!dns_server_addr.valid()) { + dns_server_addr = addr; + } + log(" DNS server #", idx++, ": ", addr); + }); + } + catch (Dhcp_packet::Option_not_found) { } + Ipv4_config ip_config( Ipv4_address_prefix( dhcp.yiaddr(), dhcp.option().value()), dhcp.option().value(), - dns_server); + dns_server_addr); _handler.ip_config(ip_config); break;