diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/rdisc/Makefile.am | 1 | ||||
-rw-r--r-- | src/rdisc/nm-fake-rdisc.c | 133 | ||||
-rw-r--r-- | src/rdisc/nm-fake-rdisc.h | 49 | ||||
-rw-r--r-- | src/rdisc/nm-rdisc.c | 179 | ||||
-rw-r--r-- | src/rdisc/nm-rdisc.h | 130 | ||||
-rw-r--r-- | src/rdisc/tests/.gitignore | 1 | ||||
-rw-r--r-- | src/rdisc/tests/Makefile.am | 22 | ||||
-rw-r--r-- | src/rdisc/tests/rdisc.c | 26 |
8 files changed, 541 insertions, 0 deletions
diff --git a/src/rdisc/Makefile.am b/src/rdisc/Makefile.am new file mode 100644 index 0000000000..3c6155b9c6 --- /dev/null +++ b/src/rdisc/Makefile.am @@ -0,0 +1 @@ +SUBDIRS = tests diff --git a/src/rdisc/nm-fake-rdisc.c b/src/rdisc/nm-fake-rdisc.c new file mode 100644 index 0000000000..f39c5a208c --- /dev/null +++ b/src/rdisc/nm-fake-rdisc.c @@ -0,0 +1,133 @@ +/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */ +/* nm-fake-rdisc.c - Fake implementation of router discovery + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Copyright (C) 2013 Red Hat, Inc. + */ + +#include <string.h> +#include <arpa/inet.h> + +#include "nm-fake-rdisc.h" + +#include "nm-logging.h" + +#define debug(...) nm_log_dbg (LOGD_IP6, __VA_ARGS__) +#define warning(...) nm_log_warn (LOGD_IP6, __VA_ARGS__) +#define error(...) nm_log_err (LOGD_IP6, __VA_ARGS__) + +#define NM_FAKE_RDISC_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), NM_TYPE_FAKE_RDISC, NMFakeRDiscPrivate)) + +G_DEFINE_TYPE (NMFakeRDisc, nm_fake_rdisc, NM_TYPE_RDISC) + +/******************************************************************/ + +NMRDisc * +nm_fake_rdisc_new (int ifindex, const char *ifname) +{ + NMRDisc *rdisc = g_object_new (NM_TYPE_FAKE_RDISC, NULL); + + g_assert (rdisc); + + rdisc->ifindex = ifindex; + rdisc->ifname = g_strdup (ifname); + + return rdisc; +} + +static void +delayed_start (NMRDisc *rdisc) +{ + int changed = + NM_RDISC_CONFIG_GATEWAYS | NM_RDISC_CONFIG_ADDRESSES | NM_RDISC_CONFIG_ROUTES | + NM_RDISC_CONFIG_DNS_SERVERS | NM_RDISC_CONFIG_DNS_DOMAINS; + debug ("%d", rdisc->dhcp_level); + + g_signal_emit_by_name ( + rdisc, NM_RDISC_CONFIG_CHANGED, changed); +} + +static void +start (NMRDisc *rdisc) +{ + g_idle_add ((GSourceFunc) (delayed_start), rdisc); +} + +/******************************************************************/ + +static void +nm_fake_rdisc_init (NMFakeRDisc *fake_rdisc) +{ + NMRDisc *rdisc = NM_RDISC (fake_rdisc); + NMRDiscGateway gateway; + NMRDiscAddress address; + NMRDiscRoute route; + NMRDiscDNSServer dns_server; + NMRDiscDNSDomain dns_domain; + + rdisc->dhcp_level = NM_RDISC_DHCP_LEVEL_NONE; + + memset (&gateway, 0, sizeof (gateway)); + inet_pton (AF_INET6, "fe80::1", &gateway.address); + g_array_append_val (rdisc->gateways, gateway); + inet_pton (AF_INET6, "fe80::2", &gateway.address); + g_array_append_val (rdisc->gateways, gateway); + inet_pton (AF_INET6, "fe80::3", &gateway.address); + g_array_append_val (rdisc->gateways, gateway); + + memset (&address, 0, sizeof (address)); + inet_pton (AF_INET6, "2001:db8:a:a::1", &address.address); + g_array_append_val (rdisc->addresses, address); + inet_pton (AF_INET6, "2001:db8:a:a::2", &address.address); + g_array_append_val (rdisc->addresses, address); + inet_pton (AF_INET6, "2001:db8:f:f::1", &address.address); + g_array_append_val (rdisc->addresses, address); + + memset (&route, 0, sizeof (route)); + route.plen = 64; + inet_pton (AF_INET6, "2001:db8:a:a::", &route.network); + g_array_append_val (rdisc->routes, route); + inet_pton (AF_INET6, "2001:db8:b:b::", &route.network); + g_array_append_val (rdisc->routes, route); + + memset (&dns_server, 0, sizeof (dns_server)); + inet_pton (AF_INET6, "2001:db8:c:c::1", &dns_server.address); + g_array_append_val (rdisc->dns_servers, dns_server); + inet_pton (AF_INET6, "2001:db8:c:c::2", &dns_server.address); + g_array_append_val (rdisc->dns_servers, dns_server); + inet_pton (AF_INET6, "2001:db8:c:c::3", &dns_server.address); + g_array_append_val (rdisc->dns_servers, dns_server); + inet_pton (AF_INET6, "2001:db8:c:c::4", &dns_server.address); + g_array_append_val (rdisc->dns_servers, dns_server); + inet_pton (AF_INET6, "2001:db8:c:c::5", &dns_server.address); + g_array_append_val (rdisc->dns_servers, dns_server); + + memset (&dns_domain, 0, sizeof (dns_domain)); + dns_domain.domain = g_strdup ("example.net"); + g_array_append_val (rdisc->dns_domains, dns_domain); + dns_domain.domain = g_strdup ("example.com"); + g_array_append_val (rdisc->dns_domains, dns_domain); + dns_domain.domain = g_strdup ("example.org"); + g_array_append_val (rdisc->dns_domains, dns_domain); +} + +static void +nm_fake_rdisc_class_init (NMFakeRDiscClass *klass) +{ + NMRDiscClass *rdisc_class = NM_RDISC_CLASS (klass); + + rdisc_class->start = start; +} diff --git a/src/rdisc/nm-fake-rdisc.h b/src/rdisc/nm-fake-rdisc.h new file mode 100644 index 0000000000..248283b22b --- /dev/null +++ b/src/rdisc/nm-fake-rdisc.h @@ -0,0 +1,49 @@ +/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */ +/* nm-fake-rdisc.h - Fake implementation of router discovery + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Copyright (C) 2013 Red Hat, Inc. + */ + +#ifndef NM_FAKE_RDISC_H +#define NM_FAKE_RDISC_H + +#include "nm-rdisc.h" + +#define NM_TYPE_FAKE_RDISC (nm_fake_rdisc_get_type ()) +#define NM_FAKE_RDISC(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), NM_TYPE_FAKE_RDISC, NMFakeRDisc)) +#define NM_FAKE_RDISC_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), NM_TYPE_FAKE_RDISC, NMFakeRDiscClass)) +#define NM_IS_FAKE_RDISC(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), NM_TYPE_FAKE_RDISC)) +#define NM_IS_FAKE_RDISC_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), NM_TYPE_FAKE_RDISC)) +#define NM_FAKE_RDISC_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), NM_TYPE_FAKE_RDISC, NMFakeRDiscClass)) + +/******************************************************************/ + +typedef struct { + NMRDisc parent; +} NMFakeRDisc; + +typedef struct { + NMRDiscClass parent; +} NMFakeRDiscClass; + +/******************************************************************/ + +GType nm_fake_rdisc_get_type (void); + +NMRDisc *nm_fake_rdisc_new (int ifindex, const char *ifname); + +#endif /* NM_FAKE_RDISC_H */ diff --git a/src/rdisc/nm-rdisc.c b/src/rdisc/nm-rdisc.c new file mode 100644 index 0000000000..7e90e637ed --- /dev/null +++ b/src/rdisc/nm-rdisc.c @@ -0,0 +1,179 @@ +/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */ +/* nm-rdisc.c - Perform IPv6 router discovery + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Copyright (C) 2013 Red Hat, Inc. + */ + +#include <stdlib.h> +#include <arpa/inet.h> + +#include "nm-rdisc.h" + +#include "nm-logging.h" + +#define debug(...) nm_log_dbg (LOGD_IP6, __VA_ARGS__) + +G_DEFINE_TYPE (NMRDisc, nm_rdisc, G_TYPE_OBJECT) + +enum { + CONFIG_CHANGED, + LAST_SIGNAL +}; + +static guint signals[LAST_SIGNAL] = { 0 }; + +/******************************************************************/ + +void +nm_rdisc_set_lladdr (NMRDisc *rdisc, const char *addr, size_t addrlen) +{ + rdisc->lladdr = g_bytes_new (addr, addrlen); +} + +void +nm_rdisc_start (NMRDisc *rdisc) +{ + NMRDiscClass *klass = NM_RDISC_GET_CLASS (rdisc); + + g_assert (klass->start); + + debug ("(%s): starting router discovery: %d", rdisc->ifname, rdisc->ifindex); + + if (klass->start) + klass->start (rdisc); +} + +#define CONFIG_MAP_MAX_STR 7 + +static void +config_map_to_string (NMRDiscConfigMap map, char *p) +{ + if (map & NM_RDISC_CONFIG_DHCP_LEVEL) + *p++ = 'd'; + if (map & NM_RDISC_CONFIG_GATEWAYS) + *p++ = 'G'; + if (map & NM_RDISC_CONFIG_ADDRESSES) + *p++ = 'A'; + if (map & NM_RDISC_CONFIG_ROUTES) + *p++ = 'R'; + if (map & NM_RDISC_CONFIG_DNS_SERVERS) + *p++ = 'S'; + if (map & NM_RDISC_CONFIG_DNS_DOMAINS) + *p++ = 'D'; + *p = '\0'; +} + +static const char * +dhcp_level_to_string (NMRDiscDHCPLevel dhcp_level) +{ + switch (dhcp_level) { + case NM_RDISC_DHCP_LEVEL_NONE: + return "none"; + case NM_RDISC_DHCP_LEVEL_OTHERCONF: + return "otherconf"; + case NM_RDISC_DHCP_LEVEL_MANAGED: + return "managed"; + default: + return "INVALID"; + } +} + +#define expiry(item) (item->timestamp + item->lifetime) + +static void +config_changed (NMRDisc *rdisc, NMRDiscConfigMap changed) +{ + int i; + char changedstr[CONFIG_MAP_MAX_STR]; + char addrstr[INET6_ADDRSTRLEN]; + + config_map_to_string (changed, changedstr); + debug ("(%s): router discovery configuration changed [%s]:", rdisc->ifname, changedstr); + debug (" dhcp-level %s", dhcp_level_to_string (rdisc->dhcp_level)); + for (i = 0; i < rdisc->gateways->len; i++) { + NMRDiscGateway *gateway = &g_array_index (rdisc->gateways, NMRDiscGateway, i); + + inet_ntop (AF_INET6, &gateway->address, addrstr, sizeof (addrstr)); + debug (" gateway %s pref %d exp %u", addrstr, gateway->preference, expiry (gateway)); + } + for (i = 0; i < rdisc->addresses->len; i++) { + NMRDiscGateway *address = &g_array_index (rdisc->addresses, NMRDiscGateway, i); + + inet_ntop (AF_INET6, &address->address, addrstr, sizeof (addrstr)); + debug (" address %s exp %u", addrstr, expiry (address)); + } + for (i = 0; i < rdisc->routes->len; i++) { + NMRDiscRoute *route = &g_array_index (rdisc->routes, NMRDiscRoute, i); + + inet_ntop (AF_INET6, &route->network, addrstr, sizeof (addrstr)); + debug (" route %s pref %d exp %u", addrstr, route->preference, expiry (route)); + } + for (i = 0; i < rdisc->dns_servers->len; i++) { + NMRDiscDNSServer *dns_server = &g_array_index (rdisc->dns_servers, NMRDiscDNSServer, i); + + inet_ntop (AF_INET6, &dns_server->address, addrstr, sizeof (addrstr)); + debug (" dns_server %s exp %u", addrstr, expiry (dns_server)); + } + for (i = 0; i < rdisc->dns_domains->len; i++) { + NMRDiscDNSDomain *dns_domain = &g_array_index (rdisc->dns_domains, NMRDiscDNSDomain, i); + + debug (" dns_domain %s exp %u", dns_domain->domain, expiry (dns_domain)); + } +} + +/******************************************************************/ + +static void +nm_rdisc_init (NMRDisc *rdisc) +{ + rdisc->gateways = g_array_new (FALSE, FALSE, sizeof (NMRDiscGateway)); + rdisc->addresses = g_array_new (FALSE, FALSE, sizeof (NMRDiscAddress)); + rdisc->routes = g_array_new (FALSE, FALSE, sizeof (NMRDiscRoute)); + rdisc->dns_servers = g_array_new (FALSE, FALSE, sizeof (NMRDiscDNSServer)); + rdisc->dns_domains = g_array_new (FALSE, FALSE, sizeof (NMRDiscDNSDomain)); +} + +static void +nm_rdisc_finalize (GObject *object) +{ + NMRDisc *rdisc = NM_RDISC (object); + + g_free (rdisc->ifname); + g_array_unref (rdisc->gateways); + g_array_unref (rdisc->addresses); + g_array_unref (rdisc->routes); + g_array_unref (rdisc->dns_servers); + g_array_unref (rdisc->dns_domains); +} + +static void +nm_rdisc_class_init (NMRDiscClass *klass) +{ + GObjectClass *object_class = G_OBJECT_CLASS (klass); + + object_class->finalize = nm_rdisc_finalize; + + klass->config_changed = config_changed; + + signals[CONFIG_CHANGED] = g_signal_new ( + NM_RDISC_CONFIG_CHANGED, + G_OBJECT_CLASS_TYPE (klass), + G_SIGNAL_RUN_FIRST, + G_STRUCT_OFFSET (NMRDiscClass, config_changed), + NULL, NULL, NULL, + G_TYPE_NONE, 1, G_TYPE_INT); +} diff --git a/src/rdisc/nm-rdisc.h b/src/rdisc/nm-rdisc.h new file mode 100644 index 0000000000..abdd81cdab --- /dev/null +++ b/src/rdisc/nm-rdisc.h @@ -0,0 +1,130 @@ +/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */ +/* nm-rdisc.h - Perform IPv6 router discovery + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Copyright (C) 2013 Red Hat, Inc. + */ + +#ifndef NM_RDISC_H +#define NM_RDISC_H + +#include <glib-object.h> + +#include <stdlib.h> +#include <netinet/in.h> + +#define NM_TYPE_RDISC (nm_rdisc_get_type ()) +#define NM_RDISC(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), NM_TYPE_RDISC, NMRDisc)) +#define NM_RDISC_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), NM_TYPE_RDISC, NMRDiscClass)) +#define NM_IS_RDISC(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), NM_TYPE_RDISC)) +#define NM_IS_RDISC_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), NM_TYPE_RDISC)) +#define NM_RDISC_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), NM_TYPE_RDISC, NMRDiscClass)) + +#define NM_RDISC_CONFIG_CHANGED "config-changed" + +typedef enum { + NM_RDISC_DHCP_LEVEL_UNKNOWN, + NM_RDISC_DHCP_LEVEL_NONE, + NM_RDISC_DHCP_LEVEL_OTHERCONF, + NM_RDISC_DHCP_LEVEL_MANAGED +} NMRDiscDHCPLevel; + +typedef enum { + NM_RDISC_PREFERENCE_INVALID, + NM_RDISC_PREFERENCE_LOW, + NM_RDISC_PREFERENCE_MEDIUM, + NM_RDISC_PREFERENCE_HIGH +} NMRDiscPreference; + +typedef struct { + struct in6_addr address; + guint32 timestamp; + guint32 lifetime; + NMRDiscPreference preference; +} NMRDiscGateway; + +typedef struct { + struct in6_addr address; + guint32 timestamp; + guint32 lifetime; + guint32 preferred_lft; +} NMRDiscAddress; + +typedef struct { + struct in6_addr network; + int plen; + struct in6_addr gateway; + guint32 timestamp; + guint32 lifetime; + NMRDiscPreference preference; +} NMRDiscRoute; + +typedef struct { + struct in6_addr address; + guint32 timestamp; + guint32 lifetime; +} NMRDiscDNSServer; + +typedef struct { + char *domain; + guint32 timestamp; + guint32 lifetime; +} NMRDiscDNSDomain; + +typedef enum { + NM_RDISC_CONFIG_DHCP_LEVEL = 1 << 0, + NM_RDISC_CONFIG_GATEWAYS = 1 << 1, + NM_RDISC_CONFIG_ADDRESSES = 1 << 2, + NM_RDISC_CONFIG_ROUTES = 1 << 3, + NM_RDISC_CONFIG_DNS_SERVERS = 1 << 4, + NM_RDISC_CONFIG_DNS_DOMAINS = 1 << 5 +} NMRDiscConfigMap; + +/** + * NMRDisc: + * @ifindex: Interface index + * + * Interface-specific structure that handles incoming router advertisements, + * caches advertised items and removes them when they are obsolete. + */ +typedef struct { + GObject parent; + + int ifindex; + char *ifname; + GBytes *lladdr; + + NMRDiscDHCPLevel dhcp_level; + GArray *gateways; + GArray *addresses; + GArray *routes; + GArray *dns_servers; + GArray *dns_domains; +} NMRDisc; + +typedef struct { + GObjectClass parent; + + void (*start) (NMRDisc *rdisc); + void (*config_changed) (NMRDisc *rdisc, NMRDiscConfigMap changed); +} NMRDiscClass; + +GType nm_rdisc_get_type (void); + +void nm_rdisc_set_lladdr (NMRDisc *rdisc, const char *addr, size_t addrlen); +void nm_rdisc_start (NMRDisc *rdisc); + +#endif /* NM_RDISC_H */ diff --git a/src/rdisc/tests/.gitignore b/src/rdisc/tests/.gitignore new file mode 100644 index 0000000000..a773713bb0 --- /dev/null +++ b/src/rdisc/tests/.gitignore @@ -0,0 +1 @@ +/rdisc diff --git a/src/rdisc/tests/Makefile.am b/src/rdisc/tests/Makefile.am new file mode 100644 index 0000000000..8e3843b7ec --- /dev/null +++ b/src/rdisc/tests/Makefile.am @@ -0,0 +1,22 @@ +AM_CPPFLAGS = \ + -I${top_srcdir} \ + -I${top_srcdir}/src \ + -I${top_srcdir}/src/logging \ + -I${top_srcdir}/libnm-util \ + -I${srcdir}/.. \ + $(GLIB_CFLAGS) \ + $(LIBNL_CFLAGS) + +AM_CFLAGS = $(CODE_COVERAGE_CFLAGS) +AM_LDFLAGS = $(GLIB_LIBS) $(CODE_COVERAGE_LDFLAGS) + +@GNOME_CODE_COVERAGE_RULES@ + +noinst_PROGRAMS = \ + rdisc + +rdisc_SOURCES = \ + rdisc.c \ + ../nm-rdisc.c \ + ../nm-fake-rdisc.c \ + ../../logging/nm-logging.c diff --git a/src/rdisc/tests/rdisc.c b/src/rdisc/tests/rdisc.c new file mode 100644 index 0000000000..4d8a95b025 --- /dev/null +++ b/src/rdisc/tests/rdisc.c @@ -0,0 +1,26 @@ +#include <syslog.h> + +#include "nm-rdisc.h" +#include "nm-fake-rdisc.h" +#include "nm-logging.h" + +int +main (int argc, char **argv) +{ + GMainLoop *loop; + NMRDisc *rdisc; + + g_type_init (); + loop = g_main_loop_new (NULL, FALSE); + nm_logging_setup ("debug", NULL, NULL); + openlog (G_LOG_DOMAIN, LOG_CONS | LOG_PERROR, LOG_DAEMON); + + rdisc = nm_fake_rdisc_new (1); + + nm_rdisc_start (rdisc); + g_main_loop_run (loop); + + g_clear_object (&rdisc); + + return EXIT_SUCCESS; +} |