Libc: implement getifaddrs

Implement getifaddrs and freeifaddrs within the libc using socket
control files at the VFS. Add an "address" and "netmask" file to the
lwIP plugin.

Only a single IPv4 address is initially supported, and the broadcast
address returned will never be valid.

Ref #3439
This commit is contained in:
Ehmry - 2019-07-05 16:32:19 +02:00
parent 5e8bc9ef51
commit d7f24d8bca
6 changed files with 189 additions and 6 deletions

View File

@ -256,6 +256,8 @@ class Lwip::Nic_netif
virtual ~Nic_netif() { }
Lwip::netif& lwip_netif() { return _netif; }
/**
* Status callback to override in subclass
*/

View File

@ -263,6 +263,8 @@ gethostbyaddr_r T
gethostbyname W
gethostid T
gethostname T
getifaddrs T
freeifaddrs T
getline T
getloadavg T
getlogin T

View File

@ -106,8 +106,6 @@ DUMMY(uid_t , 0, geteuid, (void))
DUMMY(gid_t , 0, getgid, (void))
DUMMY(int , -1, getgroups, (int, gid_t *))
DUMMY(struct hostent *, 0, gethostbyname, (const char *))
DUMMY(int, -1, getifaddrs, (struct ifaddrs **))
DUMMY(void, , freeifaddrs, (struct ifaddrs *ifp))
DUMMY(char *, 0, _getlogin, (void))
DUMMY(int , -1, getnameinfo, (const sockaddr *, socklen_t, char *, size_t, char *, size_t, int))
DUMMY_SILENT(pid_t , -1, getpid, (void))

View File

@ -1,5 +1,3 @@
#include <base/debug.h>
/*
* \brief Libc pseudo plugin for socket fs
* \author Christian Helmuth
@ -34,6 +32,7 @@
#include <netinet/tcp.h>
#include <stdio.h>
#include <sys/ioctl.h>
#include <ifaddrs.h>
/* libc-internal includes */
#include "socket_fs_plugin.h"
@ -973,6 +972,59 @@ extern "C" int socket_fs_socket(int domain, int type, int protocol)
}
static int read_ifaddr_file(sockaddr_in &sockaddr, Absolute_path const &path)
{
Host_string address;
Port_string service;
*service.base() = '0';
{
FILE *fp = ::fopen(path.base(), "r");
if (!fp) return -1;
::fscanf(fp, "%s\n", address.base());
::fclose(fp);
}
try { sockaddr = sockaddr_in_struct(address, service); }
catch (...) { return -1; }
return 0;
}
extern "C" int getifaddrs(struct ifaddrs **ifap)
{
static Genode::Lock lock;
Genode::Lock::Guard guard(lock);
// TODO: dual-stack / multi-homing
static sockaddr_in address;
static sockaddr_in netmask { 0 };
static sockaddr_in broadcast { 0 };
static ifaddrs ifaddr {
.ifa_addr = (sockaddr*)&address,
.ifa_netmask = (sockaddr*)&netmask,
.ifa_broadaddr = (sockaddr*)&broadcast,
};
*ifap = &ifaddr;
Absolute_path const root(Libc::config_socket());
if (read_ifaddr_file(address, Absolute_path("address", root.base())))
return -1;
read_ifaddr_file(netmask, Absolute_path("netmask", root.base()));
return 0;
}
extern "C" void freeifaddrs(struct ifaddrs *) { }
/****************************
** File-plugin operations **
****************************/

View File

@ -84,6 +84,8 @@ extern "C" {
};
struct Lwip_handle;
struct Lwip_nameserver_handle;
struct Lwip_address_handle;
struct Lwip_netmask_handle;
struct Lwip_file_handle;
struct Lwip_dir_handle;
@ -113,7 +115,8 @@ extern "C" {
enum {
PORT_STRLEN_MAX = 6, /* :65536 */
ENDPOINT_STRLEN_MAX = IPADDR_STRLEN_MAX+PORT_STRLEN_MAX
ENDPOINT_STRLEN_MAX = IPADDR_STRLEN_MAX+PORT_STRLEN_MAX,
ADDRESS_FILE_SIZE = IPADDR_STRLEN_MAX+2,
};
struct Directory;
@ -195,6 +198,66 @@ struct Lwip::Lwip_nameserver_handle final : Lwip_handle, private Nameserver_regi
};
struct Lwip::Lwip_address_handle final : Lwip_handle
{
Lwip::netif const &netif;
Lwip_address_handle(Vfs::File_system &fs, Allocator &alloc,
Lwip::netif &netif)
: Lwip_handle(fs, alloc, Vfs::Directory_service::OPEN_MODE_RDONLY)
, netif(netif)
{ }
Read_result read(char *dst, file_size count,
file_size &out_count) override
{
using namespace Genode;
char address[IPADDR_STRLEN_MAX] { '\0' };
ipaddr_ntoa_r(&netif.ip_addr, address, IPADDR_STRLEN_MAX);
Genode::String<ADDRESS_FILE_SIZE>
line((char const *)address, "\n");
size_t n = min(line.length(), count);
memcpy(dst, line.string(), n);
out_count = n;
return Read_result::READ_OK;
}
};
struct Lwip::Lwip_netmask_handle final : Lwip_handle
{
Lwip::netif const &netif;
Lwip_netmask_handle(Vfs::File_system &fs, Allocator &alloc,
Lwip::netif &netif)
: Lwip_handle(fs, alloc, Vfs::Directory_service::OPEN_MODE_RDONLY)
, netif(netif)
{ }
Read_result read(char *dst, file_size count,
file_size &out_count) override
{
using namespace Genode;
char netmask[IPADDR_STRLEN_MAX] { '\0' };
ipaddr_ntoa_r(&netif.netmask, netmask, IPADDR_STRLEN_MAX);
Genode::String<ADDRESS_FILE_SIZE>
line((char const *)netmask, "\n");
size_t n = min(line.length(), count);
memcpy(dst, line.string(), n);
out_count = n;
return Read_result::READ_OK;
}
};
struct Lwip::Lwip_file_handle final : Lwip_handle, private Lwip_handle_list::Element
{
friend class Lwip_handle_list;
@ -1674,6 +1737,12 @@ class Lwip::File_system final : public Vfs::File_system, public Lwip::Directory
proc(path+3, _netif.udp_dir);
}
static bool match_address(char const *name) {
return (!strcmp(name, "address")); }
static bool match_netmask(char const *name) {
return (!strcmp(name, "netmask")); }
static bool match_nameserver(char const *name) {
return (!strcmp(name, "nameserver")); }
@ -1707,7 +1776,9 @@ class Lwip::File_system final : public Vfs::File_system, public Lwip::Directory
char const *leaf_path(char const *path) override
{
if (*path == '/') ++path;
if (match_nameserver(path))
if (match_address(path)
|| match_netmask(path)
|| match_nameserver(path))
return path;
char const *r = nullptr;
@ -1723,6 +1794,12 @@ class Lwip::File_system final : public Vfs::File_system, public Lwip::Directory
st = Stat();
st.device = (Genode::addr_t)this;
if (match_address(path) || match_netmask(path)) {
st.size = ADDRESS_FILE_SIZE;
st.mode = STAT_MODE_FILE;
return STAT_OK;
}
if (match_nameserver(path)) {
st.size = IPADDR_STRLEN_MAX;
st.mode = STAT_MODE_FILE;
@ -1761,6 +1838,18 @@ class Lwip::File_system final : public Vfs::File_system, public Lwip::Directory
*/
if (mode & OPEN_MODE_CREATE) return OPEN_ERR_NO_PERM;
if (match_address(path)) {
*out_handle = new (alloc)
Lwip_address_handle(*this, alloc, _netif.lwip_netif());
return OPEN_OK;
}
if (match_netmask(path)) {
*out_handle = new (alloc)
Lwip_netmask_handle(*this, alloc, _netif.lwip_netif());
return OPEN_OK;
}
if (match_nameserver(path)) {
*out_handle = new (alloc)
Lwip_nameserver_handle(*this, alloc, _netif.nameserver_handles);

View File

@ -15,9 +15,49 @@
#include <string.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#include <ifaddrs.h>
int main(int argc, char **argv)
{
{
struct ifaddrs *addrs = NULL;
if (getifaddrs(&addrs)) {
printf("Check getifaddrs failed\n");
return ~0;
}
char ip_addr[NI_MAXHOST],
netmask[NI_MAXHOST],
broadcast[NI_MAXHOST],
sbuf[NI_MAXSERV];
if (getnameinfo(addrs->ifa_addr, addrs->ifa_addr->sa_len,
ip_addr, sizeof(ip_addr), sbuf, sizeof(sbuf),
NI_NUMERICHOST | NI_NUMERICSERV))
{
printf("could not get address from getifaddrs\n");
return ~0;
}
if (getnameinfo(addrs->ifa_netmask, addrs->ifa_netmask->sa_len,
netmask, sizeof(netmask), sbuf, sizeof(sbuf),
NI_NUMERICHOST | NI_NUMERICSERV))
{
printf("could not get netmask from getifaddrs\n");
}
if (getnameinfo(addrs->ifa_broadaddr, addrs->ifa_broadaddr->sa_len,
broadcast, sizeof(broadcast), sbuf, sizeof(sbuf),
NI_NUMERICHOST | NI_NUMERICSERV))
{
printf("could not get broadcast from getifaddrs\n");
}
freeifaddrs(addrs);
printf("getifaddrs ip_addr=%s, netmask=%s broadcast=%s\n", ip_addr, netmask, broadcast);
}
struct addrinfo hints;
char ipstr[INET6_ADDRSTRLEN];