From 339a0354ce20f86630964ade3adb50474d0aa925 Mon Sep 17 00:00:00 2001 From: Christian Prochaska Date: Thu, 2 May 2013 16:01:46 +0200 Subject: [PATCH] libc_lwip_nic_dhcp: provide '/etc/resolv.conf' With this patch, the 'libc_lwip_nic_dhcp' plugin provides the DNS server address acquired by lwIP via DHCP in the file '/etc/resolv.conf'. This feature can be disabled from the config file: The static network interface configuration attributes are now also a part of the '' config node: Fixes #731. --- libports/lib/mk/libc_lwip_nic_dhcp.mk | 2 +- libports/run/test-nicbridge_static2.run | 2 +- libports/src/lib/libc_lwip_nic_dhcp/init.cc | 69 +++--- libports/src/lib/libc_lwip_nic_dhcp/plugin.cc | 234 ++++++++++++++++++ 4 files changed, 277 insertions(+), 30 deletions(-) create mode 100644 libports/src/lib/libc_lwip_nic_dhcp/plugin.cc diff --git a/libports/lib/mk/libc_lwip_nic_dhcp.mk b/libports/lib/mk/libc_lwip_nic_dhcp.mk index 926db97fa..5b8c6e3a4 100644 --- a/libports/lib/mk/libc_lwip_nic_dhcp.mk +++ b/libports/lib/mk/libc_lwip_nic_dhcp.mk @@ -1,4 +1,4 @@ -SRC_CC = init.cc +SRC_CC = init.cc plugin.cc vpath %.cc $(REP_DIR)/src/lib/libc_lwip_nic_dhcp diff --git a/libports/run/test-nicbridge_static2.run b/libports/run/test-nicbridge_static2.run index 775081c51..77587042a 100644 --- a/libports/run/test-nicbridge_static2.run +++ b/libports/run/test-nicbridge_static2.run @@ -109,7 +109,7 @@ mimetype.assign = ( - + diff --git a/libports/src/lib/libc_lwip_nic_dhcp/init.cc b/libports/src/lib/libc_lwip_nic_dhcp/init.cc index 9f52a183c..23745c044 100644 --- a/libports/src/lib/libc_lwip_nic_dhcp/init.cc +++ b/libports/src/lib/libc_lwip_nic_dhcp/init.cc @@ -27,12 +27,15 @@ extern "C" { extern void create_lwip_plugin(); +extern void create_etc_resolv_conf_plugin(); void __attribute__((constructor)) init_nic_dhcp(void) { PDBG("init_nic_dhcp()\n"); + bool provide_etc_resolv_conf = true; + char ip_addr_str[16] = {0}; char netmask_str[16] = {0}; char gateway_str[16] = {0}; @@ -40,50 +43,57 @@ void __attribute__((constructor)) init_nic_dhcp(void) genode_int32_t ip_addr = 0; genode_int32_t netmask = 0; genode_int32_t gateway = 0; - + try { - Genode::Xml_node interface_node = Genode::config()->xml_node().sub_node("interface"); + Genode::Xml_node libc_node = Genode::config()->xml_node().sub_node("libc"); try { - interface_node.attribute("ip_addr").value(ip_addr_str, sizeof(ip_addr_str)); - } - catch(Genode::Xml_node::Nonexistent_attribute) - { - PERR("Missing \"ip_addr\" attribute. Ignore interface config."); - throw; - } + if (libc_node.attribute("resolv").has_value("no")) + provide_etc_resolv_conf = false; + } catch(...) { } try { - interface_node.attribute("netmask").value(netmask_str, sizeof(netmask_str)); - } - catch(Genode::Xml_node::Nonexistent_attribute) - { - PERR("Missing \"netmask\" attribute. Ignore interface config."); - throw; - } + libc_node.attribute("ip_addr").value(ip_addr_str, sizeof(ip_addr_str)); + } catch(...) { } try { - interface_node.attribute("gateway").value(gateway_str, sizeof(gateway_str)); - } - catch(Genode::Xml_node::Nonexistent_attribute) - { - PERR("Missing \"gateway\" attribute. Ignore interface config."); - throw; - } - - PDBG("interface: ip_addr=%s netmask=%s gateway=%s ", + libc_node.attribute("netmask").value(netmask_str, sizeof(netmask_str)); + } catch(...) { } + + try { + libc_node.attribute("gateway").value(gateway_str, sizeof(gateway_str)); + } catch(...) { } + + /* either none or all 3 interface attributes must exist */ + if ((strlen(ip_addr_str) != 0) || + (strlen(netmask_str) != 0) || + (strlen(gateway_str) != 0)) { + if (strlen(ip_addr_str) == 0) { + PERR("Missing \"ip_addr\" attribute. Ignoring network interface config."); + throw Genode::Xml_node::Nonexistent_attribute(); + } else if (strlen(netmask_str) == 0) { + PERR("Missing \"netmask\" attribute. Ignoring network interface config."); + throw Genode::Xml_node::Nonexistent_attribute(); + } else if (strlen(gateway_str) == 0) { + PERR("Missing \"gateway\" attribute. Ignoring network interface config."); + throw Genode::Xml_node::Nonexistent_attribute(); + } + } else + throw -1; + + PDBG("static network interface: ip_addr=%s netmask=%s gateway=%s ", ip_addr_str, netmask_str, gateway_str ); - genode_int32_t ip, nm, gw; + genode_uint32_t ip, nm, gw; ip = inet_addr(ip_addr_str); nm = inet_addr(netmask_str); gw = inet_addr(gateway_str); if (ip == INADDR_NONE || nm == INADDR_NONE || gw == INADDR_NONE) { - PERR("Invalid interface config."); - throw; + PERR("Invalid network interface config."); + throw -1; } else { ip_addr = ip; netmask = nm; @@ -102,4 +112,7 @@ void __attribute__((constructor)) init_nic_dhcp(void) } catch (Genode::Parent::Service_denied) { /* ignore for now */ } + + if (provide_etc_resolv_conf) + create_etc_resolv_conf_plugin(); } diff --git a/libports/src/lib/libc_lwip_nic_dhcp/plugin.cc b/libports/src/lib/libc_lwip_nic_dhcp/plugin.cc new file mode 100644 index 000000000..e14400254 --- /dev/null +++ b/libports/src/lib/libc_lwip_nic_dhcp/plugin.cc @@ -0,0 +1,234 @@ +/* + * \brief Libc plugin providing lwIP's DNS server address in the + * '/etc/resolv.conf' file + * \author Christian Prochaska + * \date 2013-05-02 + */ + +/* + * Copyright (C) 2013 Genode Labs GmbH + * + * This file is part of the Genode OS framework, which is distributed + * under the terms of the GNU General Public License version 2. + */ + +/* lwip includes */ +#include +#include +#include + +/* fix redefinition warnings */ +#undef LITTLE_ENDIAN +#undef BIG_ENDIAN +#undef BYTE_ORDER + +/* libc plugin interface */ +#include +#include + +/* libc includes */ +#include +#include +#include +#include + +/* Genode includes */ +#include +#include + + +namespace { + + class Plugin_context : public Libc::Plugin_context + { + private: + + int _status_flags; + off_t _seek_offset; + + public: + + Plugin_context() : _status_flags(0), _seek_offset(0) { } + + /** + * Set/get file status status flags + */ + void status_flags(int flags) { _status_flags = flags; } + int status_flags() { return _status_flags; } + + /** + * Set seek offset + */ + void seek_offset(size_t seek_offset) { _seek_offset = seek_offset; } + + /** + * Return seek offset + */ + off_t seek_offset() const { return _seek_offset; } + + /** + * Advance current seek position by 'incr' number of bytes + */ + void advance_seek_offset(size_t incr) + { + _seek_offset += incr; + } + + void infinite_seek_offset() + { + _seek_offset = ~0; + } + + }; + + + static inline Plugin_context *context(Libc::File_descriptor *fd) + { + return static_cast(fd->context); + } + + + class Plugin : public Libc::Plugin + { + private: + + /** + * File name this plugin feels responsible for + */ + static char const *_file_name() { return "/etc/resolv.conf"; } + + const char *_file_content() + { + static char result[32]; + ip_addr_t nameserver_ip = dns_getserver(0); + snprintf(result, sizeof(result), "nameserver %s\n", + ipaddr_ntoa(&nameserver_ip)); + return result; + } + + ::off_t _file_size(Libc::File_descriptor *fd) + { + struct stat stat_buf; + if (fstat(fd, &stat_buf) == -1) + return -1; + return stat_buf.st_size; + } + + public: + + /** + * Constructor + */ + Plugin() { } + + bool supports_stat(const char *path) + { + return (Genode::strcmp(path, "/etc") == 0) || + (Genode::strcmp(path, _file_name()) == 0); + } + + bool supports_open(const char *path, int flags) + { + return (Genode::strcmp(path, _file_name()) == 0); + } + + Libc::File_descriptor *open(const char *pathname, int flags) + { + Plugin_context *context = new (Genode::env()->heap()) Plugin_context; + context->status_flags(flags); + return Libc::file_descriptor_allocator()->alloc(this, context); + } + + int close(Libc::File_descriptor *fd) + { + Genode::destroy(Genode::env()->heap(), context(fd)); + Libc::file_descriptor_allocator()->free(fd); + return 0; + } + + int stat(const char *path, struct stat *buf) + { + if (buf) { + Genode::memset(buf, 0, sizeof(struct stat)); + if (Genode::strcmp(path, "/etc") == 0) + buf->st_mode = S_IFDIR; + else if (Genode::strcmp(path, _file_name()) == 0) { + buf->st_mode = S_IFREG; + buf->st_size = strlen(_file_content()) + 1; + } else { + errno = ENOENT; + return -1; + } + } + return 0; + } + + int fstat(Libc::File_descriptor *fd, struct stat *buf) + { + if (buf) { + Genode::memset(buf, 0, sizeof(struct stat)); + buf->st_mode = S_IFREG; + buf->st_size = strlen(_file_content()) + 1; + } + return 0; + } + + ::off_t lseek(Libc::File_descriptor *fd, ::off_t offset, int whence) + { + switch (whence) { + + case SEEK_SET: + context(fd)->seek_offset(offset); + return offset; + + case SEEK_CUR: + context(fd)->advance_seek_offset(offset); + return context(fd)->seek_offset(); + + case SEEK_END: + if (offset != 0) { + errno = EINVAL; + return -1; + } + context(fd)->infinite_seek_offset(); + return _file_size(fd); + + default: + errno = EINVAL; + return -1; + } + } + + ssize_t read(Libc::File_descriptor *fd, void *buf, ::size_t count) + { + ::off_t seek_offset = context(fd)->seek_offset(); + + if (seek_offset >= _file_size(fd)) + return 0; + + const char *content = _file_content(); + count = Genode::min((::off_t)count, _file_size(fd) - seek_offset); + + memcpy(buf, &content[seek_offset], count); + + context(fd)->advance_seek_offset(count); + + return count; + } + + int fcntl(Libc::File_descriptor *fd, int cmd, long arg) + { + switch (cmd) { + case F_GETFL: return context(fd)->status_flags(); + default: PERR("fcntl(): command %d not supported", cmd); return -1; + } + } + }; + +} /* unnamed namespace */ + + +void create_etc_resolv_conf_plugin() +{ + static Plugin plugin; +}