Group :: System/Servers
RPM: miredo
Main Changelog Spec Patches Sources Download Gear Bugs and FR Repocop
Patch: miredo-1.2.6-alt1.patch
Download
Download
TODO | 1 -
doc/miredo.conf.5 | 47 +++++++-
libteredo/Makefile.am | 4 +-
libteredo/discovery.c | 290 ++++++++++++++++++++++++++++++++++++++++++++++++
libteredo/discovery.h | 97 ++++++++++++++++
libteredo/iothread.c | 94 ++++++++++++++++
libteredo/iothread.h | 57 ++++++++++
libteredo/libteredo.sym | 1 +
libteredo/packets.c | 41 ++++---
libteredo/packets.h | 16 +++
libteredo/peerlist.h | 5 +-
libteredo/relay.c | 253 +++++++++++++++++++++++++++++++++++-------
libteredo/tunnel.h | 45 +++++++-
src/relayd.c | 98 +++++++++++++++-
14 files changed, 981 insertions(+), 68 deletions(-)
diff --git a/TODO b/TODO
index fddc96e..8e93119 100644
--- a/TODO
+++ b/TODO
@@ -15,7 +15,6 @@ Important features & fixes:
----------------------------
(*) do something in case of DoS against the peers list
( ) fixed TODOs and FIXMEs in source code
-(*) local Teredo discovery
Not so important features:
---------------------------
diff --git a/doc/miredo.conf.5 b/doc/miredo.conf.5
index e864253..ed5ccdf 100644
--- a/doc/miredo.conf.5
+++ b/doc/miredo.conf.5
@@ -1,5 +1,5 @@
.\" ***********************************************************************
-.\" * Copyright © 2004-2006 Rémi Denis-Courmont. *
+.\" * Copyright © 2004-2009 Rémi Denis-Courmont and contributors. *
.\" * This program is free software; you can redistribute and/or modify *
.\" * it under the terms of the GNU General Public License as published *
.\" * by the Free Software Foundation; version 2 of the license. *
@@ -116,6 +116,51 @@ Miredo assumes that the secondary Teredo server address equals the
primary server address plus one. If that is not the case, this
directive must be used.
+.TP
+.BI "LocalDiscovery " "mode"
+Determines whether the local client discovery procedure is performed.
+Local discovery works by sending multicast packets
+on the local network interfaces at regular intervals,
+announcing a client's Teredo address.
+
+.RI "If " "mode" " is " "\fBenabled" " (the default),"
+all the multicast-capable network interfaces with a local IPv4 address
+will be considered for the exchange of local discovery packets.
+.RI "If " "mode" " is " "\fBforced" ,
+interfaces with a global address will be considered as well.
+.RB "A value of " "disabled" " will turn off local discovery completely."
+
+.TP
+.BI "DiscoveryInterfaces " "regex"
+Restricts the network interfaces considered for local discovery
+to those whose names match the given regular expression.
+.IR "regex" " is a POSIX extended regular expression;"
+it is not anchored so be careful to include
+.BR "^" " and " "$" " if this is what you mean."
+
+.RI "For instance, on Linux, a " "regex" " of " "\fB^eth[0-9]"
+will restrict local discovery to operate
+on the regular ethernet interfaces only.
+You may specify a list of interfaces using the branch operator,
+.RB "as in " "^(eth0|eth1|ppp0)$" .
+See regex(7) for more information about regular expressions.
+
+.TP
+.BI "DiscoveryNetmask " "netmask"
+Specifies which Teredo addresses are accepted from local peers.
+An IPv6 Teredo address embeds a client's external IPv4 address.
+When receiving announcements from the local networks,
+Miredo compares this external address with its own.
+.RI "The " "netmask" " parameter, written in dotted-quad IPv4 notation,"
+specifies which bits of the address should match.
+
+.RB "A value of " "255.255.255.255" " (the default)"
+will restrict the accepted local peers to those with the
+exact same external IPv4 address as ours,
+and silently ignore announcements from other clients.
+.RB "On the other hand, if " "\fInetmask" " is " "0.0.0.0" ,
+any local client will be accepted, regardless of its external address.
+
.SH RELAY OPTIONS
.RI "The following directives are only available in " "relay" " mode."
.RI "They are not available in " "(auto)client" " mode."
diff --git a/libteredo/Makefile.am b/libteredo/Makefile.am
index 45679e0..6c3bc1a 100644
--- a/libteredo/Makefile.am
+++ b/libteredo/Makefile.am
@@ -42,9 +42,9 @@ libteredo_common_la_LDFLAGS = -no-undefined
# libteredo.la
libteredo_la_SOURCES = init.c relay.c security.c security.h md5.c md5.h \
packets.c packets.h peerlist.c peerlist.h \
- clock.c clock.h stub.c
+ clock.c clock.h iothread.c iothread.h stub.c
if TEREDO_CLIENT
-libteredo_la_SOURCES += maintain.c maintain.h
+libteredo_la_SOURCES += maintain.c maintain.h discovery.c discovery.h
endif
libteredo_la_DEPENDENCIES = libteredo.sym $(LIBADD)
libteredo_la_LIBADD = @LIBJUDY@ @LIBRT@ $(LTLIBINTL) $(LIBADD)
diff --git a/libteredo/discovery.c b/libteredo/discovery.c
new file mode 100644
index 0000000..a736c52
--- /dev/null
+++ b/libteredo/discovery.c
@@ -0,0 +1,290 @@
+/*
+ * discovery.c - Teredo local client discovery procedure
+ *
+ * See "Teredo: Tunneling IPv6 over UDP through NATs"
+ * for more information
+ */
+
+/***********************************************************************
+ * Copyright © 2009 Jérémie Koenig. *
+ * This program is free software; you can redistribute and/or modify *
+ * it under the terms of the GNU General Public License as published *
+ * by the Free Software Foundation; version 2 of the license, 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, you can get it from: *
+ * http://www.gnu.org/copyleft/gpl.html *
+ ***********************************************************************/
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include <stdbool.h>
+#include <inttypes.h>
+#include <stdlib.h> // malloc()
+#include <string.h> // mem???()
+
+#include <netinet/in.h> // struct in6_addr
+#include <netinet/ip6.h> // struct ip6_hdr (for packets.h)
+#include <arpa/inet.h> // inet_ntop()
+#include <pthread.h>
+#include <ifaddrs.h> // getifaddrs()
+#include <net/if.h> // IFF_MULTICAST
+
+#include "teredo.h"
+#include "teredo-udp.h"
+#include "packets.h"
+#include "v4global.h"
+#include "security.h"
+#include "clock.h"
+#include "debug.h"
+#include "iothread.h"
+#include "tunnel.h"
+#include "discovery.h"
+
+
+struct teredo_discovery
+{
+ int refcnt;
+ struct teredo_discovery_interface
+ {
+ uint32_t addr;
+ uint32_t mask;
+ } *ifaces;
+ struct in6_addr src;
+ teredo_iothread *recv;
+ teredo_iothread *send;
+};
+
+
+static const struct in6_addr in6addr_allnodes =
+{ { { 0xff, 0x02, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x1 } } };
+
+
+bool is_ipv4_discovered (teredo_discovery *d, uint32_t ip)
+{
+ int i;
+
+ for (i = 0; d->ifaces[i].addr; i++)
+ if (((ip ^ d->ifaces[i].addr) & d->ifaces[i].mask) == 0)
+ return true;
+
+ return false;
+}
+
+
+void SendDiscoveryBubble (teredo_discovery *d, int fd)
+{
+ struct ip_mreqn mreq;
+ int i, r;
+
+ for (i = 0; d->ifaces[i].addr; i++)
+ {
+ memset (&mreq, 0, sizeof mreq);
+ mreq.imr_multiaddr.s_addr = htonl (TEREDO_DISCOVERY_IPV4);
+ mreq.imr_address.s_addr = d->ifaces[i].addr;
+ r = setsockopt(fd, IPPROTO_IP, IP_MULTICAST_IF,
+ &mreq, sizeof mreq);
+ if (r < 0)
+ {
+ debug ("Could not set multicast interface");
+ continue;
+ }
+
+ teredo_send_bubble_anyway (fd, htonl (TEREDO_DISCOVERY_IPV4),
+ htons (IPPORT_TEREDO),
+ &d->src, &in6addr_allnodes);
+ }
+
+ debug ("discovery bubble sent");
+}
+
+
+bool IsDiscoveryBubble (const teredo_packet *restrict packet)
+{
+ return IsBubble(packet->ip6)
+ && packet->dest_ipv4 == htonl (TEREDO_DISCOVERY_IPV4)
+ && memcmp(&packet->ip6->ip6_dst, &in6addr_allnodes, 16) == 0;
+}
+
+
+// 5.2.8 Optional Local Client Discovery Procedure
+static LIBTEREDO_NORETURN void *teredo_sendmcast_thread (void *opaque, int fd)
+{
+ teredo_discovery *d = (teredo_discovery *)opaque;
+
+ for (;;)
+ {
+ SendDiscoveryBubble (d, fd);
+
+ int interval = 200 + teredo_get_flbits (teredo_clock ()) % 100;
+ struct timespec delay = { .tv_sec = interval };
+ while (clock_nanosleep (CLOCK_REALTIME, 0, &delay, &delay));
+ }
+}
+
+
+/* Join the Teredo local discovery multicast group on a given interface */
+static void teredo_discovery_joinmcast(int sk, uint32_t ifaddr)
+{
+ struct ip_mreqn mreq;
+ int r;
+ char addr[20];
+
+ memset (&mreq, 0, sizeof mreq);
+ mreq.imr_address.s_addr = ifaddr;
+ mreq.imr_multiaddr.s_addr = htonl (TEREDO_DISCOVERY_IPV4);
+ r = setsockopt (sk, IPPROTO_IP, IP_ADD_MEMBERSHIP, &mreq, sizeof mreq);
+
+ debug (r < 0 ? "Could not join the Teredo local discovery "
+ "multicast group on interface %.20s"
+ : "Listening for Teredo local discovery bubbles "
+ "on interface %.20s",
+ inet_ntop(AF_INET, &ifaddr, addr, sizeof addr));
+}
+
+
+teredo_discovery *
+teredo_discovery_start (const teredo_discovery_params *params,
+ int fd, const struct in6_addr *src,
+ teredo_iothread_proc proc, void *opaque)
+{
+ struct ifaddrs *ifaddrs, *ifa;
+ int r, ifno;
+
+ teredo_discovery *d = malloc (sizeof (teredo_discovery));
+ if (d == NULL)
+ {
+ return NULL;
+ }
+
+ d->refcnt = 1;
+
+ /* Get a list of the suitable interfaces */
+
+ r = getifaddrs(&ifaddrs);
+ if (r < 0)
+ {
+ debug ("Could not enumerate interfaces for local discovery");
+ free (d);
+ return NULL;
+ }
+
+ d->ifaces = NULL;
+ ifno = 0;
+
+ for (ifa = ifaddrs; ifa; ifa = ifa->ifa_next)
+ {
+ struct teredo_discovery_interface *list = d->ifaces;
+ struct sockaddr_in *sa = (struct sockaddr_in *) ifa->ifa_addr;
+ struct sockaddr_in *ma = (struct sockaddr_in *) ifa->ifa_netmask;
+
+ if (!ifa->ifa_addr || ifa->ifa_addr->sa_family != AF_INET)
+ continue;
+ if (!(ifa->ifa_flags & IFF_MULTICAST))
+ continue;
+
+ if (!params->forced
+ && is_ipv4_global_unicast (sa->sin_addr.s_addr))
+ continue;
+ if (params->ifname_re
+ && regexec(params->ifname_re, ifa->ifa_name, 0, NULL, 0) != 0)
+ continue;
+
+ list = realloc (list, (ifno + 2) * sizeof (*d->ifaces));
+ if(list == NULL)
+ {
+ debug ("Out of memory.");
+ break; // memory error
+ }
+
+ d->ifaces = list;
+ d->ifaces[ifno].addr = sa->sin_addr.s_addr;
+ d->ifaces[ifno].mask = ma->sin_addr.s_addr;
+ ifno++;
+ }
+
+ freeifaddrs(ifaddrs);
+
+ if (d->ifaces == NULL)
+ {
+ debug ("No suitable interfaces found for local discovery");
+ free (d);
+ return NULL;
+ }
+ d->ifaces[ifno].addr = 0;
+
+ /* Setup the multicast-receiving socket */
+
+ int sk = teredo_socket (0, htons (IPPORT_TEREDO));
+ if (sk < 0)
+ {
+ debug ("Could not create the local discovery socket");
+ free (d->ifaces);
+ free (d);
+ return NULL;
+ }
+
+ for (ifno = 0; d->ifaces[ifno].addr; ifno++)
+ teredo_discovery_joinmcast (sk, d->ifaces[ifno].addr);
+
+ d->recv = teredo_iothread_start (proc, opaque, sk);
+
+ /* Start the discovery procedure thread */
+
+ memcpy (&d->src, src, sizeof d->src);
+ setsockopt (fd, IPPROTO_IP, IP_MULTICAST_LOOP, &(int){0}, sizeof (int));
+
+ d->send = teredo_iothread_start (teredo_sendmcast_thread, d, fd);
+
+ return d;
+}
+
+
+struct teredo_discovery *teredo_discovery_grab (teredo_discovery *d)
+{
+ assert (d->refcnt);
+
+ d->refcnt++;
+ return d;
+}
+
+
+void teredo_discovery_release (teredo_discovery *d)
+{
+ assert (d->refcnt);
+
+ if (--d->refcnt)
+ return;
+
+ assert (d->send == NULL); // ie. teredo_discovery_stop() has been called
+ assert (d->recv == NULL);
+
+ free (d->ifaces);
+ free (d);
+}
+
+
+void teredo_discovery_stop (teredo_discovery *d)
+{
+ if (d->send)
+ {
+ teredo_iothread_stop (d->send, false);
+ d->send = NULL;
+ }
+ if (d->recv)
+ {
+ teredo_iothread_stop (d->recv, true);
+ d->recv = NULL;
+ }
+
+ teredo_discovery_release(d);
+}
+
diff --git a/libteredo/discovery.h b/libteredo/discovery.h
new file mode 100644
index 0000000..e957097
--- /dev/null
+++ b/libteredo/discovery.h
@@ -0,0 +1,97 @@
+/*
+ * @file discovery.h
+ * @brief Local client discovery procedure
+ */
+
+/***********************************************************************
+ * Copyright © 2009 Jérémie Koenig. *
+ * This program is free software; you can redistribute and/or modify *
+ * it under the terms of the GNU General Public License as published *
+ * by the Free Software Foundation; version 2 of the license, 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, you can get it from: *
+ * http://www.gnu.org/copyleft/gpl.html *
+ ***********************************************************************/
+
+#ifndef LIBTEREDO_TEREDO_DISCOVERY_H
+# define LIBTEREDO_TEREDO_DISCOVERY_H
+
+/**
+ * Teredo local client discovery procedure internal state.
+ */
+typedef struct teredo_discovery teredo_discovery;
+
+# ifdef __cplusplus
+extern "C" {
+# endif
+
+/**
+ * Tests whether a given IPv4 address belongs to one of the local networks
+ * a given discovery object operates on.
+ *
+ * @param ip IPv4 address to test.
+ */
+bool is_ipv4_discovered (teredo_discovery *d, uint32_t ip);
+
+/**
+ * Sends a discovery bubble.
+ *
+ * @param fd socket to send the bubble from.
+ */
+void SendDiscoveryBubble (teredo_discovery *d, int fd);
+
+/**
+ * Returns true if the given @p packet looks like a discovery bubble.
+ */
+bool IsDiscoveryBubble (const teredo_packet *restrict packet);
+
+/**
+ * Creates and starts threads for the Teredo local client discovery procedure.
+ * A list of interfaces suitable for the exchange of multicast local discovery
+ * bubbles will be assembled for later use by SendDiscoveryBubble().
+ *
+ * @param params local discovery configuration parameters.
+ * @param fd socket used for sending the discovery bubbles.
+ * @param src source Teredo IPv6 address for the discovery bubbles.
+ * @param proc IO procedure to use for receiving multicast traffic
+ * @param opaque pointer passed to @p proc
+ */
+teredo_discovery *
+teredo_discovery_start (const teredo_discovery_params *params,
+ int fd, const struct in6_addr *src,
+ teredo_iothread_proc proc, void *opaque);
+
+/**
+ * Protects a @c teredo_discovery object from destruction until
+ * teredo_discovery_release() is called.
+ *
+ * @param d the discovery object to grab
+ * @return @c d
+ */
+struct teredo_discovery *teredo_discovery_grab (teredo_discovery *d);
+
+/**
+ * Release a previously grabbed @c teredo_discovery object.
+ * A reference counter is used: this function must be called exactly as many
+ * times as teredo_discovery_grab() has been used.
+ */
+void teredo_discovery_release (teredo_discovery *d);
+
+/**
+ * Stops and destroys discovery threads created by teredo_discovery_start().
+ *
+ * @param d non-NULL pointer from teredo_discovery_start().
+ */
+void teredo_discovery_stop (teredo_discovery *d);
+
+# ifdef __cplusplus
+}
+# endif
+#endif /* ifndef LIBTEREDO_TEREDO_DISCOVERY_H */
diff --git a/libteredo/iothread.c b/libteredo/iothread.c
new file mode 100644
index 0000000..5ceb302
--- /dev/null
+++ b/libteredo/iothread.c
@@ -0,0 +1,94 @@
+/*
+ * iothread.c - IO thread management for Teredo tunnels
+ */
+
+/***********************************************************************
+ * Copyright © 2009 Jérémie Koenig *
+ * This program is free software; you can redistribute and/or modify *
+ * it under the terms of the GNU General Public License as published *
+ * by the Free Software Foundation; version 2 of the license, 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, you can get it from: *
+ * http://www.gnu.org/copyleft/gpl.html *
+ ***********************************************************************/
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include <stdbool.h>
+#include <stdlib.h> // malloc()
+#include <assert.h>
+#include <inttypes.h>
+#include <pthread.h>
+
+#include "iothread.h"
+#include "teredo-udp.h" // teredo_close()
+#include "debug.h"
+
+
+struct teredo_iothread
+{
+ pthread_t thread;
+ teredo_iothread_proc proc;
+ void *opaque;
+ int fd;
+};
+
+
+static void *teredo_iothread_run (void *data)
+{
+ teredo_iothread *io = (teredo_iothread *)data;
+ return io->proc (io->opaque, io->fd);
+}
+
+
+teredo_iothread *teredo_iothread_start (teredo_iothread_proc proc,
+ void *opaque, int fd)
+{
+ teredo_iothread *io = malloc (sizeof *io);
+ if (io == NULL)
+ return NULL;
+
+ io->proc = proc;
+ io->opaque = opaque;
+ io->fd = fd;
+
+ if (pthread_create (&io->thread, NULL, teredo_iothread_run, io))
+ {
+ debug ("Could not create IO thread for fd %d.", fd);
+ free (io);
+ return NULL;
+ }
+
+#ifndef NDEBUG
+ debug ("IO thread started (%p, %p, %p, %d)", io, proc, opaque, fd);
+#endif
+
+ return io;
+}
+
+
+void teredo_iothread_stop (teredo_iothread *io, bool close)
+{
+ pthread_cancel (io->thread);
+ pthread_join (io->thread, NULL);
+
+ if (close)
+ teredo_close (io->fd);
+
+#ifndef NDEBUG
+ debug ("IO thread stopped (%p)", io);
+#endif
+
+ free (io);
+}
+
+
diff --git a/libteredo/iothread.h b/libteredo/iothread.h
new file mode 100644
index 0000000..404b28c
--- /dev/null
+++ b/libteredo/iothread.h
@@ -0,0 +1,57 @@
+/**
+ * @file iothread.h
+ * @brief IO thread management
+ */
+
+/***********************************************************************
+ * Copyright © 2009 Jérémie Koenig. *
+ * This program is free software; you can redistribute and/or modify *
+ * it under the terms of the GNU General Public License as published *
+ * by the Free Software Foundation; version 2 of the license, 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, you can get it from: *
+ * http://www.gnu.org/copyleft/gpl.html *
+ ***********************************************************************/
+
+#ifndef LIBTEREDO_IOTHREAD_H
+# define LIBTEREDO_IOTHREAD_H
+
+# ifdef __cplusplus
+extern "C" {
+# endif
+
+typedef struct teredo_iothread teredo_iothread;
+typedef void *(*teredo_iothread_proc) (void *opaque, int fd);
+
+/**
+ * Start a new IO thread.
+ *
+ * @param proc callback function to be run as the new thread.
+ * @param opaque opaque pointer passed to @p proc.
+ * @param fd file descriptor for this thread.
+ *
+ * @return the new IO thread on success, NULL on error.
+ */
+teredo_iothread *teredo_iothread_start (teredo_iothread_proc proc,
+ void *opaque, int fd);
+
+/**
+ * Stop an IO thread and destroy the teredo_iothread object.
+ *
+ * @param io the IO thread to stop.
+ * @param close whether to close the file descriptor associted with it.
+ */
+void teredo_iothread_stop (teredo_iothread *io, bool close);
+
+# ifdef __cplusplus
+}
+# endif /* ifdef __cplusplus */
+#endif /* ifndef LIBTEREDO_IOTHREAD_H */
+
diff --git a/libteredo/libteredo.sym b/libteredo/libteredo.sym
index 82832e3..053adc5 100644
--- a/libteredo/libteredo.sym
+++ b/libteredo/libteredo.sym
@@ -4,6 +4,7 @@ teredo_create
teredo_destroy
teredo_get_privdata
teredo_set_client_mode
+teredo_set_discovery_params
teredo_set_relay_mode
teredo_set_cone_flag
teredo_set_icmpv6_callback
diff --git a/libteredo/packets.c b/libteredo/packets.c
index c323f92..52442c8 100644
--- a/libteredo/packets.c
+++ b/libteredo/packets.c
@@ -51,27 +51,34 @@
int
-teredo_send_bubble (int fd, uint32_t ip, uint16_t port,
- const struct in6_addr *src, const struct in6_addr *dst)
+teredo_send_bubble_anyway (int fd, uint32_t ip, uint16_t port,
+ const struct in6_addr *src,
+ const struct in6_addr *dst)
{
- if (is_ipv4_global_unicast (ip))
+ static const uint8_t head[] =
+ "\x60\x00\x00\x00" /* flow */
+ "\x00\x00" /* plen = 0 */
+ "\x3b" /* nxt = IPPROTO_NONE */
+ "\x00" /* hlim = 0 */;
+ struct iovec iov[3] =
{
- static const uint8_t head[] =
- "\x60\x00\x00\x00" /* flow */
- "\x00\x00" /* plen = 0 */
- "\x3b" /* nxt = IPPROTO_NONE */
- "\x00" /* hlim = 0 */;
- struct iovec iov[3] =
- {
- { (void *)head, 8 },
- { (void *)src, 16 },
- { (void *)dst, 16 }
- };
+ { (void *)head, 8 },
+ { (void *)src, 16 },
+ { (void *)dst, 16 }
+ };
- return teredo_sendv (fd, iov, 3, ip, port) == 40 ? 0 : -1;
- }
+ return teredo_sendv (fd, iov, 3, ip, port) == 40 ? 0 : -1;
+}
- return 0;
+
+int
+teredo_send_bubble (int fd, uint32_t ip, uint16_t port,
+ const struct in6_addr *src, const struct in6_addr *dst)
+{
+ if (is_ipv4_global_unicast (ip))
+ return teredo_send_bubble_anyway(fd, ip, port, src, dst);
+ else
+ return 0; /* FIXME: really ? */
}
diff --git a/libteredo/packets.h b/libteredo/packets.h
index 1e90f73..63794ba 100644
--- a/libteredo/packets.h
+++ b/libteredo/packets.h
@@ -76,6 +76,22 @@ int teredo_send_bubble (int fd, uint32_t ip, uint16_t port,
const struct in6_addr *src,
const struct in6_addr *dst);
+/**
+ * Sends a Teredo bubble.
+ *
+ * This version does not check that @p ip is a global unicast address.
+ *
+ * @param ip destination IPv4
+ * @param port destination UDP port
+ * @param src pointer to source IPv6 address
+ * @param dst pointer to destination IPv6 address
+ *
+ * @return 0 on success, -1 on error.
+ */
+int teredo_send_bubble_anyway (int fd, uint32_t ip, uint16_t port,
+ const struct in6_addr *src,
+ const struct in6_addr *dst);
+
static inline int teredo_reply_bubble (int fd, uint32_t ip, uint16_t port,
const struct ip6_hdr *req)
{
diff --git a/libteredo/peerlist.h b/libteredo/peerlist.h
index 33ce29b..8fbdf00 100644
--- a/libteredo/peerlist.h
+++ b/libteredo/peerlist.h
@@ -34,12 +34,13 @@ typedef struct teredo_peer
size_t queue_left;
teredo_clock_t last_rx;
teredo_clock_t last_tx;
+ teredo_clock_t last_ping;
uint32_t mapped_addr;
uint16_t mapped_port;
unsigned trusted:1;
+ unsigned local:1;
unsigned bubbles:3;
unsigned pings:3;
- unsigned last_ping:9;
} teredo_peer;
@@ -82,7 +83,7 @@ static inline void TouchTransmit (teredo_peer *peer, teredo_clock_t now)
static inline
bool IsValid (const teredo_peer *peer, teredo_clock_t now)
{
- return (now - peer->last_rx) <= 30;
+ return (now - peer->last_rx) <= (peer->local ? 600 : 30);
}
diff --git a/libteredo/relay.c b/libteredo/relay.c
index 410c423..62ee5c8 100644
--- a/libteredo/relay.c
+++ b/libteredo/relay.c
@@ -6,7 +6,7 @@
*/
/***********************************************************************
- * Copyright © 2004-2007 Rémi Denis-Courmont. *
+ * Copyright © 2004-2009 Rémi Denis-Courmont and contributors. *
* This program is free software; you can redistribute and/or modify *
* it under the terms of the GNU General Public License as published *
* by the Free Software Foundation; version 2 of the license, or (at *
@@ -51,8 +51,10 @@
#include "maintain.h"
#include "clock.h"
#include "peerlist.h"
+#include "iothread.h"
#ifdef MIREDO_TEREDO_CLIENT
# include "security.h"
+# include "discovery.h"
#endif
#include "debug.h"
#ifndef NDEBUG
@@ -65,9 +67,11 @@ struct teredo_tunnel
void *opaque;
#ifdef MIREDO_TEREDO_CLIENT
struct teredo_maintenance *maintenance;
+ struct teredo_discovery *discovery;
teredo_state_up_cb up_cb;
teredo_state_down_cb down_cb;
+ const teredo_discovery_params *disc_params;
#endif
teredo_recv_cb recv_cb;
teredo_icmpv6_cb icmpv6_cb;
@@ -84,11 +88,7 @@ struct teredo_tunnel
} ratelimit;
// Asynchronous packet reception
- struct
- {
- pthread_t thread;
- bool running;
- } recv;
+ teredo_iothread *recv;
int fd;
};
@@ -174,6 +174,8 @@ TeredoRelay::EmitICMPv6Error (const void *packet, size_t length,
#ifdef MIREDO_TEREDO_CLIENT
+static LIBTEREDO_NORETURN void *teredo_recv_thread (void *opaque, int fd);
+
static void
teredo_state_change (const teredo_state *state, void *self)
{
@@ -185,6 +187,12 @@ teredo_state_change (const teredo_state *state, void *self)
if (tunnel->state.up)
{
+ if (tunnel->discovery)
+ {
+ teredo_discovery_stop (tunnel->discovery);
+ tunnel->discovery = NULL;
+ }
+
/*
* NOTE: we get an hold on both state and peer list locks here.
* As such, in any case, attempting to acquire the state lock while
@@ -200,9 +208,20 @@ teredo_state_change (const teredo_state *state, void *self)
debug ("Internal IPv4 address: %s",
inet_ntop (AF_INET, &tunnel->state.ipv4, b, sizeof (b)));
#endif
+
+ if (tunnel->disc_params)
+ {
+ teredo_discovery *d;
+ d = teredo_discovery_start (tunnel->disc_params,
+ tunnel->fd,
+ &tunnel->state.addr.ip6,
+ teredo_recv_thread, tunnel);
+ tunnel->discovery = d;
+ }
}
else
if (previously_up)
+ /* FIXME: stop discovery? */
tunnel->down_cb (tunnel->opaque);
/*
@@ -228,7 +247,7 @@ static int CountPing (teredo_peer *peer, teredo_clock_t now)
res = -1;
// test must be separated by at least 2 seconds
else
- if (((now - peer->last_ping) & 0x1ff) <= 2)
+ if (now - peer->last_ping <= 2)
res = 1;
else
res = 0; // can test again!
@@ -430,12 +449,13 @@ int teredo_transmit (teredo_tunnel *restrict tunnel,
}
else
{
- p->trusted = p->bubbles = p->pings = 0;
+ p->trusted = p->local = p->bubbles = p->pings = 0;
}
- debug ("Connecting %s: %strusted, %svalid, %u pings, %u bubbles",
+ debug ("Connecting %s: %s%strusted, %svalid, %u pings, %u bubbles",
created ? "<unknown>" : inet_ntop(AF_INET, &p->mapped_addr,
b, sizeof (b)),
+ !p->local ? "" : "LOCAL, ",
p->trusted ? "" : "NOT ",
IsValid (p, now) ? "" : "NOT ",
p->pings, p->bubbles);
@@ -474,12 +494,46 @@ int teredo_transmit (teredo_tunnel *restrict tunnel,
inet_ntop (AF_INET6, &dst->ip6, b, sizeof (b)), res);
return 0;
}
+
+ /* Client case 3: untrusted local peer */
+ if (p->local && IsValid (p, now))
+ {
+ teredo_enqueue_out (p, packet, length);
+
+ int res = CountBubble (p, now);
+ uint32_t addr = p->mapped_addr;
+ uint16_t port = p->mapped_port;
+
+ teredo_list_release (list);
+
+ if (res == 0)
+ {
+ teredo_send_bubble_anyway (tunnel->fd, addr, port,
+ &s.addr.ip6, &dst->ip6);
+
+ pthread_rwlock_rdlock (&tunnel->state_lock);
+ teredo_discovery *d = NULL;
+ if (tunnel->discovery)
+ d = teredo_discovery_grab (tunnel->discovery);
+ pthread_rwlock_unlock (&tunnel->state_lock);
+
+ if (d != NULL)
+ SendDiscoveryBubble (d, tunnel->fd);
+
+ teredo_discovery_release (d);
+ }
+
+ if (res == -1)
+ // TODO: blacklist as a local peer ?
+ teredo_send_unreach (tunnel, ICMP6_DST_UNREACH_ADDR,
+ packet, length);
+
+ return 0;
+ }
#endif
// Untrusted Teredo client
- /* Client case 3: TODO: implement local discovery */
-
if (created)
/* Unknown Teredo clients */
SetMapping (p, IN6_TEREDO_IPV4 (dst), IN6_TEREDO_PORT (dst));
@@ -524,6 +578,34 @@ int teredo_transmit (teredo_tunnel *restrict tunnel,
}
+#ifdef MIREDO_TEREDO_CLIENT
+/**
+ * Checks whether a given packet qualifies as a local one.
+ * Must be called with the state lock held for reading.
+ */
+static bool
+teredo_islocal (teredo_tunnel *restrict tunnel,
+ const struct teredo_packet *restrict packet)
+{
+ if (!tunnel->disc_params || !tunnel->discovery)
+ return false; // local discovery disabled
+
+ union teredo_addr our = tunnel->state.addr;
+ if (IN6_TEREDO_PREFIX (&packet->ip6->ip6_src) != our.teredo.prefix)
+ return false; // not a teredo address
+
+ uint32_t client_ip = IN6_TEREDO_IPV4 (&packet->ip6->ip6_src);
+ if ((client_ip ^ ~our.teredo.client_ip) & tunnel->disc_params->netmask)
+ return false; // non-matching mapped IPv4
+
+ if (!is_ipv4_discovered (tunnel->discovery, packet->source_ipv4))
+ return false; // non-matching source IPv4
+
+ return true;
+}
+#endif
+
+
static
void teredo_predecap (teredo_tunnel *restrict tunnel,
teredo_peer *restrict peer, teredo_clock_t now)
@@ -576,9 +658,11 @@ teredo_run_inner (teredo_tunnel *restrict tunnel,
return; // malformatted IPv6 packet
}
- teredo_state s;
pthread_rwlock_rdlock (&tunnel->state_lock);
- s = tunnel->state;
+ teredo_state s = tunnel->state;
+#ifdef MIREDO_TEREDO_CLIENT
+ bool islocal = teredo_islocal (tunnel, packet);
+#endif
/*
* We can afford to use a slightly outdated state, but we cannot afford to
* use an inconsistent state, hence this lock. Also, we cannot call
@@ -670,6 +754,62 @@ teredo_run_inner (teredo_tunnel *restrict tunnel,
return;
}
+ /* Actual packet reception, either as a relay or a client */
+
+ teredo_clock_t now = teredo_clock ();
+
+ // Checks source IPv6 address / looks up peer in the list:
+ struct teredo_peerlist *list = tunnel->list;
+ teredo_peer *p = teredo_list_lookup (list, &ip6->ip6_src, NULL);
+
+#ifdef MIREDO_TEREDO_CLIENT
+ /*
+ * Client case 4 (local discovery bubble)
+ *
+ * NOTE: In addition to their announcement role, local discovery
+ * bubbles are used in a way similar to indirect bubbles: when
+ * transmitting to an untrusted local peer, a client sends both a
+ * direct unicast bubble and a local discovery bubble, then waits for
+ * the unicast reply we send below. (client tx case 3 and rx case 5)
+ *
+ * So we must check discovery bubbles right now, before case 1 gets a
+ * chance to discard them, otherwise a trusted local peer will never
+ * get a chance to trust us as well.
+ */
+ if (islocal && IsDiscoveryBubble (packet))
+ {
+ if (p == NULL)
+ {
+ p = teredo_list_lookup (list, &ip6->ip6_src, &(bool){ false });
+ if (p == NULL) {
+ debug ("Out of memory.");
+ return; // memory error
+ }
+ p->trusted = 0;
+ p->local = 0;
+ }
+
+ /* reset the number of bubbles when a peer becomes local */
+ if (!p->local)
+ p->bubbles = 0;
+
+ SetMappingFromPacket (p, packet);
+ p->local = 1;
+ TouchReceive (p, now);
+ teredo_list_release (list);
+
+ if (CountBubble (p, now) != 0)
+ return;
+
+ debug ("Replying to discovery bubble");
+ teredo_send_bubble_anyway (tunnel->fd,
+ packet->source_ipv4,
+ packet->source_port,
+ &s.addr.ip6, &ip6->ip6_src);
+ return;
+ }
+#endif
+
/*
* NOTE:
* Clients are supposed to check that the destination is their Teredo IPv6
@@ -680,8 +820,9 @@ teredo_run_inner (teredo_tunnel *restrict tunnel,
* is served by them (i.e. egress filtering from Teredo to native IPv6).
* The IPv6 stack firewall should be used to that end.
*
- * Multicast destinations are not supposed to occur, not even for hole
- * punching. We drop them as a precautionary measure.
+ * With the exception of local client discovery bubbles, multicast
+ * destinations are not supposed to occur, not even for hole punching.
+ * We drop them as a precautionary measure.
*
* We purposedly don't drop packets on the basis of link-local destination
* as it breaks hole punching: we send Teredo bubbles with a link-local
@@ -691,20 +832,14 @@ teredo_run_inner (teredo_tunnel *restrict tunnel,
*
*/
if (ip6->ip6_dst.s6_addr[0] == 0xff)
- {
+ {
+ if (p != NULL)
+ teredo_list_release (list);
debug ("Multicast destination %s not supported.",
inet_ntop (AF_INET6, &ip6->ip6_dst.s6_addr, b, sizeof b));
return;
}
- /* Actual packet reception, either as a relay or a client */
-
- teredo_clock_t now = teredo_clock ();
-
- // Checks source IPv6 address / looks up peer in the list:
- struct teredo_peerlist *list = tunnel->list;
- teredo_peer *p = teredo_list_lookup (list, &ip6->ip6_src, NULL);
-
if (p != NULL)
{
@@ -744,12 +879,27 @@ teredo_run_inner (teredo_tunnel *restrict tunnel,
// Client case 3 (unknown or untrusted matching Teredo client):
if (IN6_MATCHES_TEREDO_CLIENT (&ip6->ip6_src, packet->source_ipv4,
packet->source_port)
+#ifdef MIREDO_TEREDO_CLIENT
+ // Client case 5 (untrusted local peer)
+ || (p != NULL && p->local
+ && (packet->source_ipv4 == p->mapped_addr)
+ && (packet->source_port == p->mapped_port))
+ // Extension: packet from unknown local peer (faster discovery)
+ || (p == NULL && islocal)
+#endif
// Extension: allow mismatch (i.e. clients behind symmetric NATs)
|| (IsBubble (ip6) && (CheckBubble (packet) == 0)))
{
#ifdef MIREDO_TEREDO_CLIENT
if (IsClient (tunnel) && (p == NULL))
+ {
p = teredo_list_lookup (list, &ip6->ip6_src, &(bool){ false });
+ if (p == NULL) {
+ debug ("Out of memory.");
+ return; // memory error
+ }
+ p->local = islocal;
+ }
#endif
/*
* Relays are explicitly allowed to drop packets from
@@ -774,8 +924,6 @@ teredo_run_inner (teredo_tunnel *restrict tunnel,
tunnel->recv_cb (tunnel->opaque, ip6, length);
return;
}
-
- // TODO: local Teredo
}
#ifdef MIREDO_TEREDO_CLIENT
else
@@ -783,8 +931,6 @@ teredo_run_inner (teredo_tunnel *restrict tunnel,
assert (IN6_TEREDO_PREFIX (&ip6->ip6_src) != s.addr.teredo.prefix);
assert (IsClient (tunnel));
- // TODO: implement client cases 4 & 5 for local Teredo
-
/*
* Default: Client case 6:
* (unknown non-Teredo node or Tereco client with incorrect mapping):
@@ -815,7 +961,8 @@ teredo_run_inner (teredo_tunnel *restrict tunnel,
{
p->mapped_port = 0;
p->mapped_addr = 0;
- p->trusted = p->bubbles = p->pings = 0;
+ p->trusted = p->local = 0;
+ p->bubbles = p->pings = 0;
}
}
@@ -933,13 +1080,13 @@ void teredo_destroy (teredo_tunnel *t)
* we need not lock anyting in teredo_destroy(). */
if (t->maintenance != NULL)
teredo_maintenance_stop (t->maintenance);
+
+ if (t->discovery != NULL)
+ teredo_discovery_stop (t->discovery);
#endif
- if (t->recv.running)
- {
- pthread_cancel (t->recv.thread);
- pthread_join (t->recv.thread, NULL);
- }
+ if (t->recv != NULL)
+ teredo_iothread_stop (t->recv, false);
teredo_list_destroy (t->list);
pthread_rwlock_destroy (&t->state_lock);
@@ -949,7 +1096,7 @@ void teredo_destroy (teredo_tunnel *t)
}
-static LIBTEREDO_NORETURN void *teredo_recv_thread (void *t)
+static LIBTEREDO_NORETURN void *teredo_recv_thread (void *t, int fd)
{
teredo_tunnel *tunnel = (teredo_tunnel *)t;
@@ -957,7 +1104,7 @@ static LIBTEREDO_NORETURN void *teredo_recv_thread (void *t)
{
struct teredo_packet packet;
- if (teredo_wait_recv (tunnel->fd, &packet) == 0)
+ if (teredo_wait_recv (fd, &packet) == 0)
{
pthread_setcancelstate (PTHREAD_CANCEL_DISABLE, NULL);
teredo_run_inner (tunnel, &packet);
@@ -972,13 +1119,13 @@ int teredo_run_async (teredo_tunnel *t)
assert (t != NULL);
/* already running */
- if (t->recv.running)
+ if (t->recv)
return -1;
- if (pthread_create (&t->recv.thread, NULL, teredo_recv_thread, t))
+ t->recv = teredo_iothread_start (teredo_recv_thread, t, t->fd);
+ if (t->recv == NULL)
return -1;
- t->recv.running = true;
return 0;
}
@@ -1072,6 +1219,17 @@ int teredo_set_client_mode (teredo_tunnel *restrict t,
return -1;
}
+ /* expand the list's expiration time to handle local peers */
+ teredo_peerlist *newlist = teredo_list_create (MAX_PEERS, 600);
+ if (newlist == NULL)
+ {
+ debug ("Could not create new list for client mode.");
+ pthread_rwlock_unlock (&t->state_lock);
+ return -1;
+ }
+ teredo_list_destroy (t->list);
+ t->list = newlist;
+
struct teredo_maintenance *m;
m = teredo_maintenance_start (t->fd, teredo_state_change, t, s, s2,
0, 0, 0, 0);
@@ -1089,6 +1247,23 @@ int teredo_set_client_mode (teredo_tunnel *restrict t,
}
+int teredo_set_discovery_params (teredo_tunnel *restrict t,
+ const teredo_discovery_params *p)
+{
+#ifdef MIREDO_TEREDO_CLIENT
+ pthread_rwlock_wrlock (&t->state_lock);
+ assert (t != NULL && IsClient(t));
+ t->disc_params = p;
+ pthread_rwlock_unlock (&t->state_lock);
+ return 0;
+#else
+ (void)t;
+ (void)p;
+ return -1;
+#endif
+}
+
+
void *teredo_set_privdata (teredo_tunnel *t, void *opaque)
{
assert (t != NULL);
diff --git a/libteredo/tunnel.h b/libteredo/tunnel.h
index 3de29f8..4f79088 100644
--- a/libteredo/tunnel.h
+++ b/libteredo/tunnel.h
@@ -12,7 +12,7 @@
*/
/***********************************************************************
- * Copyright © 2004-2006 Rémi Denis-Courmont. *
+ * Copyright © 2004-2009 Rémi Denis-Courmont and contributors. *
* This program is free software; you can redistribute and/or modify *
* it under the terms of the GNU General Public License as published *
* by the Free Software Foundation; version 2 of the license, or (at *
@@ -213,6 +213,49 @@ int teredo_set_client_mode (teredo_tunnel *restrict t, const char *s1,
const char *s2);
/**
+ * Parameters for the local client discovery procedure.
+ */
+typedef struct teredo_discovery_params
+{
+ /**
+ * Specifies whether the network interfaces with a global address
+ * should be considered for local discovery.
+ */
+ bool forced;
+
+ /**
+ * Regular expression for network interface filtering.
+ * If this is a non-@c NULL pointer to a @c regex_t object (initialized
+ * with regcomp()), only the network interfaces whose names match this
+ * regex will be considered for local discovery.
+ */
+ regex_t *ifname_re;
+
+ /**
+ * Netmask (in network byte order) for comparing the mapped external
+ * IPv4 address of the local clients with our own.
+ */
+ uint32_t netmask;
+
+} teredo_discovery_params;
+
+/**
+ * Enables the Teredo local client discovery procedure.
+ * teredo_set_client_mode() must have been called for the given tunnel prior to
+ * invoking this function.
+ *
+ * @param t Tereo tunnel instance
+ * @param p local discovery parameters
+ *
+ * Thread-safety: This function is thread-safe.
+ *
+ * @return 0 on success, -1 in case of error.
+ * In case of error, the teredo_tunnel instance is not modifed.
+ */
+int teredo_set_discovery_params (teredo_tunnel *restrict t,
+ const teredo_discovery_params *p);
+
+/**
* Sets the private data pointer of a Teredo tunnel instance.
* This value is passed to callbacks.
*
diff --git a/src/relayd.c b/src/relayd.c
index e9b51c3..ce6ad62 100644
--- a/src/relayd.c
+++ b/src/relayd.c
@@ -3,7 +3,7 @@
*/
/***********************************************************************
- * Copyright © 2004-2007 Rémi Denis-Courmont. *
+ * Copyright © 2004-2009 Rémi Denis-Courmont and contributors. *
* This program is free software; you can redistribute and/or modify *
* it under the terms of the GNU General Public License as published *
* by the Free Software Foundation; version 2 of the license, or (at *
@@ -199,6 +199,69 @@ ParseRelayType (miredo_conf *conf, const char *name, int *type)
}
+static bool
+ParseLocalDiscovery (miredo_conf *conf, const char *name,
+ teredo_discovery_params **disc_params)
+{
+ unsigned line;
+ char *val = miredo_conf_get (conf, name, &line);
+
+ if (val == NULL)
+ return true;
+
+ if (strcasecmp (val, "enabled") == 0)
+ (*disc_params)->forced = false;
+ else
+ if (strcasecmp (val, "forced") == 0)
+ (*disc_params)->forced = false;
+ else
+ if (strcasecmp (val, "disabled") == 0)
+ *disc_params = NULL;
+ else
+ {
+ syslog (LOG_ERR, _("Invalid discovery mode \"%s\" at line %u"),
+ val, line);
+ free (val);
+ return false;
+ }
+ free (val);
+ return true;
+}
+
+
+static bool
+ParseDiscoveryInterfaces (miredo_conf *conf, const char *name, regex_t **preg)
+{
+ unsigned line;
+ char *val = miredo_conf_get (conf, name, &line);
+
+ if (val == NULL)
+ {
+ *preg = NULL;
+ return true;
+ }
+
+ int r = regcomp (*preg, val, REG_EXTENDED);
+ if (r != 0)
+ {
+ char err[100];
+ regerror (r, *preg, err, sizeof err);
+
+ /* TRANSLATORS: the second %s is an error message for the
+ * failed regex compilation */
+ syslog (LOG_ERR, _("Invalid regex \"%s\" at line %u: %s"),
+ val, line, err);
+
+ free (val);
+ regfree (*preg);
+ return false;
+ }
+
+ free(val);
+ return true;
+}
+
+
#ifdef MIREDO_TEREDO_CLIENT
static tun6 *
create_dynamic_tunnel (const char *ifname, int *pfd)
@@ -311,15 +374,23 @@ miredo_down_callback (void *data)
static int
-setup_client (teredo_tunnel *client, const char *server, const char *server2)
+setup_client (teredo_tunnel *client, const char *server, const char *server2,
+ teredo_discovery_params *disc_params)
{
+ int r;
+
teredo_set_state_cb (client, miredo_up_callback, miredo_down_callback);
- return teredo_set_client_mode (client, server, server2);
+ r = teredo_set_client_mode (client, server, server2);
+
+ if (disc_params && r == 0)
+ r = teredo_set_discovery_params (client, disc_params);
+
+ return r;
}
#else
# define create_dynamic_tunnel( a, b ) NULL
# define destroy_dynamic_tunnel( a, b ) (void)0
-# define setup_client( a, b, c ) (-1)
+# define setup_client( a, b, c, d ) (-1)
#endif
@@ -454,6 +525,14 @@ relay_run (miredo_conf *conf, const char *server_name)
#ifdef MIREDO_TEREDO_CLIENT
const char *server_name2 = NULL;
char namebuf[NI_MAXHOST], namebuf2[NI_MAXHOST];
+
+ regex_t preg;
+ teredo_discovery_params ldp =
+ {
+ .forced = false,
+ .netmask = 0xffffffff,
+ .ifname_re = &preg,
+ }, *disc_params = &ldp;
#endif
uint16_t mtu = 1280;
bool cone = false;
@@ -482,6 +561,14 @@ relay_run (miredo_conf *conf, const char *server_name)
server_name2 = namebuf2;
}
}
+
+ if (!ParseLocalDiscovery (conf, "LocalDiscovery", &disc_params)
+ || !ParseDiscoveryInterfaces (conf, "DiscoveryInterfaces", &ldp.ifname_re)
+ || !miredo_conf_parse_IPv4 (conf, "DiscoveryNetmask", &ldp.netmask))
+ {
+ syslog (LOG_ALERT, _("Fatal configuration error"));
+ return -2;
+ }
#else
syslog (LOG_ALERT, _("Unsupported Teredo client mode"));
syslog (LOG_ALERT, _("Fatal configuration error"));
@@ -570,7 +657,8 @@ relay_run (miredo_conf *conf, const char *server_name)
teredo_set_icmpv6_callback (relay, miredo_icmp6_callback);
retval = (mode & TEREDO_CLIENT)
- ? setup_client (relay, server_name, server_name2)
+ ? setup_client (relay, server_name, server_name2,
+ disc_params)
: setup_relay (relay, prefix.teredo.prefix, cone);
/*