Compare commits
10 Commits
burble.dn4
...
debian
Author | SHA1 | Date | |
---|---|---|---|
|
9c17195bdd | ||
|
168b57ef0f | ||
|
8ebff291ca | ||
|
6c3c9a4f49 | ||
|
9bdb6c6293 | ||
|
d6126fb7b8 | ||
|
33cdc183d9 | ||
|
09582acd46 | ||
|
e187093f32 | ||
|
ce24a858f6 |
64
ChangeLog
64
ChangeLog
@ -1,65 +1,3 @@
|
||||
2017-01-07 Johnathan Sharratt <johnathan.sharratt@gmail.com>
|
||||
|
||||
* Version 0.2.6
|
||||
|
||||
* Added a new configuration setting named "deadtime" which allows
|
||||
sessions that never made it the VALID to have a different (i.e.
|
||||
shorter) life before they are removed (and potentially retried)
|
||||
(defauilt is the same value as usual TTL for backwards compatibility)
|
||||
|
||||
* Added a new configuration setting named "autowire" in the proxy
|
||||
section (default is off)
|
||||
|
||||
* If the "autowire" setting is on, then upon receiving a NDP
|
||||
Neighbor Advertisment from one of the rule interfaces, a route will
|
||||
be automatically added into the linux IP routing tables thus allowing
|
||||
for a full featured gateway when IPv6 forwarding is turned on.
|
||||
Note: Be careful as "accept_ra" may need to be set to 2 on the
|
||||
interface during testing for the routing tables to retain their
|
||||
default route (unrelated to this patch but took me a while to
|
||||
discover).
|
||||
|
||||
* When a session ends then anything that was "autowired" will be
|
||||
automatically removed thus ensuring the routing tables are in a
|
||||
similar state to before the daemon (or session) made any changes
|
||||
|
||||
* Added a feature where the session will attempt to renew itself
|
||||
(with a new NDP Solicitation) before it self-terminates, this is
|
||||
required otherwise packets could be lost when the session terminates
|
||||
triggering the automatically removal of the route table entry.
|
||||
|
||||
* Ensured that renew operations only take place if the session has
|
||||
been recently touched by an external solicitation - this ensures
|
||||
that sessions that become IDLE are cleaned up quickly
|
||||
|
||||
* Moved the daemonizing step till after the system executed the
|
||||
configure step so that the error exit codes are returned to the daemon
|
||||
caller.
|
||||
|
||||
* No longer continuing to load the daemon if any of the interfaces fail
|
||||
to load which should give a more predictable behaviour and better user experience.
|
||||
|
||||
2016-04-18 Daniel Adolfsson <daniel@priv.nu>
|
||||
|
||||
* Version 0.2.5
|
||||
|
||||
* Defer configuration of interfaces until after daemonized; fixes an
|
||||
issue where ndppd would fail to set ALLMULTI on the interface
|
||||
properly.
|
||||
|
||||
* Fix a cast so ndppd can be compiled on GCC 6.
|
||||
|
||||
* Fix so ndppd changes working directory to / and umask to 0 once
|
||||
daemonized.
|
||||
|
||||
2015-10-13 Daniel Adolfsson <daniel@priv.nu>
|
||||
|
||||
* Version 0.2.4
|
||||
|
||||
* Fix an issue where ndppd daemonizes too early.
|
||||
|
||||
* Fix to make sure the right pid is written to the pidfile.
|
||||
|
||||
2012-09-21 Daniel Adolfsson <daniel@priv.nu>
|
||||
|
||||
* Version 0.2.3
|
||||
@ -72,7 +10,7 @@
|
||||
|
||||
* New "auto" configuration to detect outgoing interface, for forwarding
|
||||
Neighbor Solicitation Messages.
|
||||
|
||||
|
||||
* Improved logging.
|
||||
|
||||
* Bug fixes related to memory management.
|
||||
|
19
Makefile
19
Makefile
@ -9,17 +9,11 @@ CXX ?= g++
|
||||
GZIP ?= /bin/gzip
|
||||
MANDIR ?= ${DESTDIR}${PREFIX}/share/man
|
||||
SBINDIR ?= ${DESTDIR}${PREFIX}/sbin
|
||||
PKG_CONFIG ?= pkg-config
|
||||
|
||||
LIBS =
|
||||
|
||||
OBJS = src/logger.o src/ndppd.o src/iface.o src/proxy.o src/address.o \
|
||||
src/rule.o src/session.o src/conf.o src/route.o
|
||||
|
||||
ifdef WITH_ND_NETLINK
|
||||
LIBS = `${PKG_CONFIG} --libs glib-2.0 libnl-3.0 libnl-route-3.0` -pthread
|
||||
CPPFLAGS = `${PKG_CONFIG} --cflags glib-2.0 libnl-3.0 libnl-route-3.0`
|
||||
OBJ = ${OBJ} src/nd-netlink.o
|
||||
endif
|
||||
src/rule.o src/session.o src/conf.o src/route.o
|
||||
|
||||
all: ndppd ndppd.1.gz ndppd.conf.5.gz
|
||||
|
||||
@ -37,13 +31,10 @@ ndppd.conf.5.gz:
|
||||
${GZIP} < ndppd.conf.5 > ndppd.conf.5.gz
|
||||
|
||||
ndppd: ${OBJS}
|
||||
${CXX} -o ndppd ${LDFLAGS} ${OBJS} ${LIBS}
|
||||
|
||||
nd-proxy: nd-proxy.c
|
||||
${CXX} -o nd-proxy -Wall -Werror ${LDFLAGS} `${PKG_CONFIG} --cflags glib-2.0` nd-proxy.c `${PKG_CONFIG} --libs glib-2.0`
|
||||
${CXX} -o ndppd ${LDFLAGS} ${LIBS} ${OBJS}
|
||||
|
||||
.cc.o:
|
||||
${CXX} -c ${CPPFLAGS} $(CXXFLAGS) -o $@ $<
|
||||
${CXX} -c $(CXXFLAGS) -o $@ $<
|
||||
|
||||
clean:
|
||||
rm -f ndppd ndppd.conf.5.gz ndppd.1.gz ${OBJS} nd-proxy
|
||||
rm -f ndppd ndppd.conf.5.gz ndppd.1.gz ${OBJS}
|
||||
|
23
README
23
README
@ -1,24 +1,24 @@
|
||||
ndppd - NDP Proxy Daemon
|
||||
|
||||
Version 0.2.5
|
||||
Version 0.2.2
|
||||
|
||||
------------------------------------------------------------------------
|
||||
1. Legal
|
||||
------------------------------------------------------------------------
|
||||
|
||||
ndppd - NDP Proxy Daemon
|
||||
Copyright (C) 2011-2016 Daniel Adolfsson <daniel@priv.nu>
|
||||
|
||||
Copyright (C) 2011 Daniel Adolfsson <daniel@priv.nu>
|
||||
|
||||
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 3 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, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
@ -93,7 +93,7 @@
|
||||
If you want to enable debugging, you can type:
|
||||
|
||||
make DEBUG=1 all
|
||||
|
||||
|
||||
Note that this version of the binary is much bigger, and the daemon
|
||||
produces a lot of messages.
|
||||
|
||||
@ -101,8 +101,8 @@
|
||||
5. Usage
|
||||
------------------------------------------------------------------------
|
||||
|
||||
Read through 'ndppd.conf-dist' for guidelines and examples how to
|
||||
configure the daemon.
|
||||
Read through 'ndppd.conf.example' for guidelines how to configure
|
||||
the daemon.
|
||||
|
||||
Usage: ndppd [-d] [-c <config>] [-p <pidfile>]
|
||||
|
||||
@ -115,7 +115,7 @@
|
||||
|
||||
-d Daemonize the process, putting it in the background.
|
||||
Also enables syslogging.
|
||||
|
||||
|
||||
-v Increase logging verbosity. Can be used several times in
|
||||
order to increase even further.
|
||||
|
||||
@ -125,9 +125,10 @@
|
||||
|
||||
Contact : Daniel Adolfsson <daniel@priv.nu>
|
||||
|
||||
Website : https://github.com/DanielAdolfsson/ndppd
|
||||
Website : http://www.priv.nu/projects/ndppd
|
||||
|
||||
Git : git://github.com/DanielAdolfsson/ndppd.git
|
||||
Git : git://github.com/Tuhox/ndppd.git
|
||||
https://github.com/Tuhox/ndppd
|
||||
|
||||
If you want to report a bug, you can either send me a mail directly,
|
||||
or submit an issue on github.com.
|
||||
|
12
README.md
12
README.md
@ -1,12 +0,0 @@
|
||||
# NDPPD
|
||||
|
||||
***ndppd***, or ***NDP Proxy Daemon***, is a daemon that proxies *neighbor discovery* messages. It listens for *neighbor solicitations* on a
|
||||
specified interface and responds with *neighbor advertisements* - as described in **RFC 4861** (section 7.2).
|
||||
|
||||
## Current status
|
||||
|
||||
Version 0.x is in maintenance, and is being replaced by `1.0-devel` which you can find [here](https://github.com/DanielAdolfsson/ndppd/tree/1.0-devel). `1.0` is not yet stable enough to be used in production, and I currently have no estimate when it is. Feel free to try it out if you like.
|
||||
|
||||
Latest stable release is 0.2.5:
|
||||
- [Download](https://github.com/DanielAdolfsson/ndppd/releases/tag/0.2.5)
|
||||
- [README](https://github.com/DanielAdolfsson/ndppd/blob/0.2.5/README)
|
11
debian/changelog
vendored
Normal file
11
debian/changelog
vendored
Normal file
@ -0,0 +1,11 @@
|
||||
ndppd (0.2.3-1) unstable; urgency=low
|
||||
|
||||
* New release (0.2.3).
|
||||
|
||||
-- Daniel Adolfsson <daniel@priv.nu> Fri, 21 Sep 2012 14:42:48 +0200
|
||||
|
||||
ndppd (0.2.2-1) unstable; urgency=low
|
||||
|
||||
* New Package. Closes: #644932.
|
||||
|
||||
-- Daniel Adolfsson <daniel@priv.nu> Fri, 03 Feb 2012 14:48:48 +0100
|
1
debian/compat
vendored
Normal file
1
debian/compat
vendored
Normal file
@ -0,0 +1 @@
|
||||
7
|
20
debian/control
vendored
Normal file
20
debian/control
vendored
Normal file
@ -0,0 +1,20 @@
|
||||
Source: ndppd
|
||||
Section: net
|
||||
Priority: extra
|
||||
Maintainer: Daniel Adolfsson <daniel@priv.nu>
|
||||
Build-Depends: debhelper (>= 7.0.50~)
|
||||
Standards-Version: 3.9.2
|
||||
Homepage: http://www.priv.nu/projects/ndppd
|
||||
Vcs-Git: git://github.com/Tuhox/ndppd.git
|
||||
Vcs-Browser: https://github.com/Tuhox/ndppd/tree/debian
|
||||
|
||||
Package: ndppd
|
||||
Architecture: linux-any
|
||||
Depends: ${shlibs:Depends}, ${misc:Depends}
|
||||
Description: daemon that proxies IPv6 NDP messages
|
||||
ndppd is a daemon that proxies certain IPv6 NDP messages between two or
|
||||
more interfaces. It currently supports proxying Neighbor Solicitation
|
||||
Messages and Neighbor Advertisement messages in order to allow IPv6
|
||||
routing without relying on Linux "proxy_ndp".
|
||||
.
|
||||
The daemon is partially compliant with (experimental) RFC4389.
|
22
debian/copyright
vendored
Normal file
22
debian/copyright
vendored
Normal file
@ -0,0 +1,22 @@
|
||||
Format: http://anonscm.debian.org/viewvc/dep/web/deps/dep5.mdwn?revision=202
|
||||
Upstream-Name: ndppd
|
||||
Source: https://github.com/Tuhox/ndppd
|
||||
|
||||
Files: *
|
||||
Copyright: 2011, Daniel Adolfsson <daniel@priv.nu>
|
||||
License: GPL-3+
|
||||
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 3 of the License, or
|
||||
(at your option) any later version.
|
||||
.
|
||||
This package 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, see <http://www.gnu.org/licenses/>.
|
||||
.
|
||||
On Debian systems, the complete text of the GNU General
|
||||
Public License version 3 can be found in "/usr/share/common-licenses/GPL-3".
|
3
debian/docs
vendored
Normal file
3
debian/docs
vendored
Normal file
@ -0,0 +1,3 @@
|
||||
README
|
||||
ndppd.conf-dist
|
||||
|
123
debian/init.d
vendored
Normal file
123
debian/init.d
vendored
Normal file
@ -0,0 +1,123 @@
|
||||
#!/bin/sh
|
||||
### BEGIN INIT INFO
|
||||
# Provides: ndppd
|
||||
# Required-Start: $network $local_fs $remote_fs
|
||||
# Required-Stop: $remote_fs
|
||||
# Default-Start: 2 3 4 5
|
||||
# Default-Stop: 0 1 6
|
||||
# Short-Description: NDP Proxy Daemon
|
||||
# Description: nppd, or NDP Proxy Daemon, is a daemon that proxies NDP
|
||||
# (Neighbor Discovery Protocol) messages between interfaces.
|
||||
### END INIT INFO
|
||||
|
||||
# Author: Daniel Adolfsson <daniel.adolfsson@tuhox.com>
|
||||
|
||||
PATH=/sbin:/usr/sbin:/bin:/usr/bin
|
||||
DESC=ndppd
|
||||
NAME=ndppd
|
||||
DAEMON=/usr/sbin/ndppd
|
||||
PIDFILE=/var/run/$NAME.pid
|
||||
DAEMON_ARGS="-d -p $PIDFILE"
|
||||
SCRIPTNAME=/etc/init.d/$NAME
|
||||
|
||||
# Exit if the package is not installed
|
||||
[ -x $DAEMON ] || exit 0
|
||||
|
||||
# Read configuration variable file if it is present
|
||||
[ -r /etc/default/$NAME ] && . /etc/default/$NAME
|
||||
|
||||
# Load the VERBOSE setting and other rcS variables
|
||||
. /lib/init/vars.sh
|
||||
|
||||
. /lib/lsb/init-functions
|
||||
|
||||
#
|
||||
# Function that starts the daemon/service
|
||||
#
|
||||
do_start()
|
||||
{
|
||||
# Return
|
||||
# 0 if daemon has been started
|
||||
# 1 if daemon was already running
|
||||
# 2 if daemon could not be started
|
||||
start-stop-daemon --start --quiet --pidfile $PIDFILE --exec $DAEMON --test > /dev/null \
|
||||
|| return 1
|
||||
start-stop-daemon --start --quiet --pidfile $PIDFILE --exec $DAEMON -- \
|
||||
$DAEMON_ARGS || return 2
|
||||
}
|
||||
|
||||
#
|
||||
# Function that stops the daemon/service
|
||||
#
|
||||
do_stop()
|
||||
{
|
||||
# Return
|
||||
# 0 if daemon has been stopped
|
||||
# 1 if daemon was already stopped
|
||||
# 2 if daemon could not be stopped
|
||||
# other if a failure occurred
|
||||
start-stop-daemon --stop --quiet --retry=TERM/30/KILL/5 --pidfile $PIDFILE --name $NAME
|
||||
RETVAL="$?"
|
||||
[ "$RETVAL" = 2 ] && return 2
|
||||
|
||||
# Wait for children to finish too if this is a daemon that forks
|
||||
# and if the daemon is only ever run from this initscript.
|
||||
# If the above conditions are not satisfied then add some other code
|
||||
# that waits for the process to drop all resources that could be
|
||||
# needed by services started subsequently. A last resort is to
|
||||
# sleep for some time.
|
||||
start-stop-daemon --stop --quiet --oknodo --retry=0/30/KILL/5 --exec $DAEMON
|
||||
[ "$?" = 2 ] && return 2
|
||||
# Many daemons don't delete their pidfiles when they exit.
|
||||
rm -f $PIDFILE
|
||||
return "$RETVAL"
|
||||
}
|
||||
|
||||
case "$1" in
|
||||
start)
|
||||
[ "$VERBOSE" != no ] && log_daemon_msg "Starting $DESC " "$NAME"
|
||||
do_start
|
||||
case "$?" in
|
||||
0|1) [ "$VERBOSE" != no ] && log_end_msg 0 ;;
|
||||
2) [ "$VERBOSE" != no ] && log_end_msg 1 ;;
|
||||
esac
|
||||
;;
|
||||
|
||||
stop)
|
||||
[ "$VERBOSE" != no ] && log_daemon_msg "Stopping $DESC" "$NAME"
|
||||
do_stop
|
||||
case "$?" in
|
||||
0|1) [ "$VERBOSE" != no ] && log_end_msg 0 ;;
|
||||
2) [ "$VERBOSE" != no ] && log_end_msg 1 ;;
|
||||
esac
|
||||
;;
|
||||
|
||||
status)
|
||||
status_of_proc "$DAEMON" "$NAME" && exit 0 || exit $?
|
||||
;;
|
||||
|
||||
restart|force-reload)
|
||||
log_daemon_msg "Restarting $DESC" "$NAME"
|
||||
do_stop
|
||||
case "$?" in
|
||||
0|1)
|
||||
do_start
|
||||
case "$?" in
|
||||
0) log_end_msg 0 ;;
|
||||
1) log_end_msg 1 ;; # Old process is still running
|
||||
*) log_end_msg 1 ;; # Failed to start
|
||||
esac
|
||||
;;
|
||||
*)
|
||||
# Failed to stop
|
||||
log_end_msg 1
|
||||
;;
|
||||
esac
|
||||
;;
|
||||
*)
|
||||
echo "Usage: $SCRIPTNAME {start|stop|status|restart|force-reload}" >&2
|
||||
exit 3
|
||||
;;
|
||||
esac
|
||||
|
||||
exit 0
|
6
debian/rules
vendored
Executable file
6
debian/rules
vendored
Executable file
@ -0,0 +1,6 @@
|
||||
#!/usr/bin/make -f
|
||||
|
||||
export PREFIX=/usr
|
||||
|
||||
%:
|
||||
dh $@
|
1
debian/source/format
vendored
Normal file
1
debian/source/format
vendored
Normal file
@ -0,0 +1 @@
|
||||
3.0 (quilt)
|
2
debian/watch
vendored
Normal file
2
debian/watch
vendored
Normal file
@ -0,0 +1,2 @@
|
||||
version=3
|
||||
http://www.tuhox.com/ndppd/files/ndppd_(.+).tar.gz
|
550
nd-proxy.c
550
nd-proxy.c
@ -1,550 +0,0 @@
|
||||
/**
|
||||
* @file nd-proxy.c
|
||||
*
|
||||
* Copyright 2016, Allied Telesis Labs New Zealand, Ltd
|
||||
*
|
||||
* +---------+
|
||||
* If A | | If B
|
||||
* A-----------------| PROXY |-----------------B
|
||||
* | |
|
||||
* +---------+
|
||||
* IPv6: A IPv6: PA IPv6: PB IPv6: B
|
||||
* L2: a L2: pa L2: pb L2: b
|
||||
*
|
||||
* RS/RA proxy
|
||||
* RS
|
||||
* -------------------->
|
||||
* L3src=A, L3dst=AllR L3src=A, L3dst=AllR
|
||||
* L2src=a, L2dst=allr, SLL=a L2src=pb, L2dst=allr, SLL=pb
|
||||
*
|
||||
* RA
|
||||
* <--------------------
|
||||
* L3src=B, L3dst=AllN L3src=B, L3dst=AllN
|
||||
* L2src=pa, L2dst=alln, SLL=pa L2src=b, L2dst=alln, SLL=b
|
||||
*
|
||||
* 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 3 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, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#include <stdlib.h>
|
||||
#include <stdbool.h>
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
#include <unistd.h>
|
||||
#include <syslog.h>
|
||||
#include <glib.h>
|
||||
#include <glib-unix.h>
|
||||
|
||||
#include <netinet/in.h>
|
||||
#include <netinet/ip6.h>
|
||||
#include <netinet/icmp6.h>
|
||||
#include <netinet/ether.h>
|
||||
#include <netpacket/packet.h>
|
||||
|
||||
#include <net/if.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/poll.h>
|
||||
|
||||
#include <linux/filter.h>
|
||||
|
||||
/* Mode */
|
||||
#define PROXY_RS (1 << 0)
|
||||
#define PROXY_RA (1 << 1)
|
||||
#define PROXY_NS (1 << 2)
|
||||
#define PROXY_NA (1 << 3)
|
||||
#define PROXY_RD (1 << 4)
|
||||
|
||||
/* Debug macros */
|
||||
#define DEBUG(fmt, args...) if (debug) printf (fmt, ## args)
|
||||
#define ERROR(fmt, args...) \
|
||||
{ \
|
||||
syslog(LOG_ERR, fmt, ## args); \
|
||||
fprintf(stderr, fmt, ## args); \
|
||||
}
|
||||
|
||||
/* Proxy interface */
|
||||
typedef struct _iface_t {
|
||||
char *name;
|
||||
uint32_t flags;
|
||||
int ifindex;
|
||||
uint8_t hwaddr[ETH_ALEN];
|
||||
int fd;
|
||||
guint src;
|
||||
} iface_t;
|
||||
|
||||
/* Globals */
|
||||
static bool debug = false;
|
||||
static GList *ifaces = NULL;
|
||||
|
||||
/* Find the specified option in the ICMPv6 message */
|
||||
static struct nd_opt_hdr *
|
||||
find_option(struct icmp6_hdr *icmp6_hdr, int len, uint8_t type)
|
||||
{
|
||||
struct nd_opt_hdr *nd_opt;
|
||||
int icmp_hlen;
|
||||
|
||||
/* Each ND type has a different offest to the options */
|
||||
switch (icmp6_hdr->icmp6_type) {
|
||||
case ND_ROUTER_SOLICIT:
|
||||
icmp_hlen = sizeof(struct nd_router_solicit);
|
||||
break;
|
||||
case ND_ROUTER_ADVERT:
|
||||
icmp_hlen = sizeof(struct nd_router_advert);
|
||||
break;
|
||||
case ND_NEIGHBOR_SOLICIT:
|
||||
icmp_hlen = sizeof(struct nd_neighbor_solicit);
|
||||
break;
|
||||
case ND_NEIGHBOR_ADVERT:
|
||||
icmp_hlen = sizeof(struct nd_neighbor_advert);
|
||||
break;
|
||||
case ND_REDIRECT:
|
||||
icmp_hlen = sizeof(struct nd_redirect);
|
||||
break;
|
||||
default:
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Find the option */
|
||||
nd_opt = (struct nd_opt_hdr *)((uint8_t *)icmp6_hdr + icmp_hlen);
|
||||
len -= icmp_hlen;
|
||||
while (len > 0) {
|
||||
int opt_len = nd_opt->nd_opt_len * 8;
|
||||
if (nd_opt->nd_opt_type == type)
|
||||
return nd_opt;
|
||||
nd_opt = (struct nd_opt_hdr *)((uint8_t *)nd_opt +
|
||||
sizeof(struct nd_opt_hdr) + opt_len);
|
||||
len -= (sizeof(struct nd_opt_hdr) + opt_len);
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Update the SLLA option in the packet (and checksum) */
|
||||
static void
|
||||
update_slla_option(struct icmp6_hdr *icmp6_hdr, int len, uint8_t *mac)
|
||||
{
|
||||
struct nd_opt_hdr *nd_opt;
|
||||
|
||||
/* Find the "source link-layer address" option */
|
||||
nd_opt = find_option(icmp6_hdr, len, ND_OPT_SOURCE_LINKADDR);
|
||||
|
||||
/* Update the slla if we found it */
|
||||
if (nd_opt) {
|
||||
/* Option data is the mac address - it is always 16-bit aligned */
|
||||
uint8_t *slla = (uint8_t *)nd_opt + sizeof(struct nd_opt_hdr);
|
||||
|
||||
/* Update ICMPv6 header checksum based on the old and new mac adddress */
|
||||
uint16_t *omac = (uint16_t *)slla;
|
||||
uint16_t *nmac = (uint16_t *)mac;
|
||||
int i;
|
||||
for (i = 0; i < ETH_ALEN / 2; i++) {
|
||||
uint16_t hc_complement = ~ntohs(icmp6_hdr->icmp6_cksum);
|
||||
uint16_t m_complement = ~ntohs(omac[i]);
|
||||
uint16_t m_prime = ntohs(nmac[i]);
|
||||
uint32_t sum = hc_complement + m_complement + m_prime;
|
||||
while (sum >> 16) {
|
||||
sum = (sum & 0xffff) + (sum >> 16);
|
||||
}
|
||||
icmp6_hdr->icmp6_cksum = htons(~((uint16_t)sum));
|
||||
}
|
||||
|
||||
/* Copy the outgoing interface's hw addr into the
|
||||
* "source link-layer address" option in the pkt. */
|
||||
memcpy(slla, mac, ETH_ALEN);
|
||||
}
|
||||
}
|
||||
|
||||
/* Proxying of both RS and RA */
|
||||
static void
|
||||
proxy_rsra(iface_t *iface, uint8_t *msg, int len)
|
||||
{
|
||||
struct ether_header *eth_hdr;
|
||||
struct ip6_hdr *ip6;
|
||||
struct icmp6_hdr *icmp6_hdr;
|
||||
struct sockaddr_ll socket_address;
|
||||
|
||||
/* Parse the packet */
|
||||
eth_hdr = (struct ether_header *)msg;
|
||||
ip6 = (struct ip6_hdr *)(msg + sizeof(struct ether_header));
|
||||
icmp6_hdr = (struct icmp6_hdr *)(msg + sizeof(struct ether_header) +
|
||||
sizeof(struct ip6_hdr));
|
||||
|
||||
DEBUG("Tx(%s): %s\n", iface->name,
|
||||
icmp6_hdr->icmp6_type == ND_ROUTER_SOLICIT ?
|
||||
"ND_ROUTER_SOLICIT" : "ND_ROUTER_ADVERT");
|
||||
|
||||
/* Avoid proxying spoofed packets */
|
||||
if (IN6_IS_ADDR_MULTICAST(&ip6->ip6_src)) {
|
||||
DEBUG("Tx(%s): Ignoring RS/RA from spoofed address\n", iface->name);
|
||||
return;
|
||||
}
|
||||
|
||||
/* RS should be sent to "All Routers Address" FF02::2 */
|
||||
/* RA should be sent to "All Nodes Address" FF02::1 */
|
||||
/* Can only proxy to multicast L2 destinations 33:33:.. */
|
||||
if (!IN6_IS_ADDR_MULTICAST(&ip6->ip6_dst) ||
|
||||
(eth_hdr->ether_dhost[0] != 0x33 && eth_hdr->ether_dhost[1] != 0x33)) {
|
||||
DEBUG("Tx(%s): Ignoring RS/RA to non-multicast address\n", iface->name);
|
||||
return;
|
||||
}
|
||||
|
||||
/* Copy the outgoing interface's hw addr into the
|
||||
* "source link-layer address" option in the pkt */
|
||||
update_slla_option(icmp6_hdr, len - ((uint8_t *)icmp6_hdr - msg), iface->hwaddr);
|
||||
|
||||
/* Copy the outgoing interface's hw addr into the
|
||||
* MAC source address in the pkt. */
|
||||
memcpy((uint8_t *)(eth_hdr->ether_shost), iface->hwaddr, ETH_ALEN);
|
||||
|
||||
/* Send the packet */
|
||||
socket_address.sll_ifindex = iface->ifindex;
|
||||
socket_address.sll_halen = ETH_ALEN;
|
||||
memcpy((uint8_t *)socket_address.sll_addr, iface->hwaddr, ETH_ALEN);
|
||||
if (sendto (iface->fd, msg, len, 0, (struct sockaddr *)&socket_address,
|
||||
sizeof(struct sockaddr_ll)) < 0) {
|
||||
ERROR("Tx(%s): Failed to send packet\n", iface->name);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
static gboolean
|
||||
handle_fd(gint fd, GIOCondition condition, gpointer data)
|
||||
{
|
||||
iface_t *iface = (iface_t *)data;
|
||||
struct msghdr mhdr;
|
||||
struct iovec iov;
|
||||
struct sockaddr_ll t_saddr;
|
||||
uint8_t msg[4096];
|
||||
int size = 4096;
|
||||
int len;
|
||||
|
||||
/* Receive a packet */
|
||||
iov.iov_len = size;
|
||||
iov.iov_base = (caddr_t)msg;
|
||||
memset(&mhdr, 0, sizeof(mhdr));
|
||||
mhdr.msg_name = (caddr_t)&t_saddr;
|
||||
mhdr.msg_namelen = sizeof(struct sockaddr);
|
||||
mhdr.msg_iov = &iov;
|
||||
mhdr.msg_iovlen = 1;
|
||||
if ((len = recvmsg(fd, &mhdr, 0)) < 0) {
|
||||
DEBUG("Rx(%s):Interface has gone away\n", iface->name);
|
||||
return true;
|
||||
}
|
||||
|
||||
/* Check we have at least the icmp header */
|
||||
if ((size_t) len < (ETH_HLEN + sizeof(struct ip6_hdr) + sizeof(struct icmp6_hdr))) {
|
||||
ERROR("Rx(%s): Ignoring short packet (%d bytes)\n", iface->name, len);
|
||||
return true;
|
||||
}
|
||||
|
||||
struct icmp6_hdr *icmp6_hdr = (struct icmp6_hdr *)(msg + ETH_HLEN + sizeof(struct ip6_hdr));
|
||||
uint8_t icmp6_type = icmp6_hdr->icmp6_type;
|
||||
switch (icmp6_type) {
|
||||
case ND_ROUTER_SOLICIT:
|
||||
DEBUG("Rx(%s): ND_ROUTER_SOLICIT\n", iface->name);
|
||||
if (iface->flags & PROXY_RS) {
|
||||
GList *iter;
|
||||
for (iter = ifaces; iter; iter = g_list_next(iter)) {
|
||||
iface_t *oiface = (iface_t *)iter->data;
|
||||
if (oiface != iface)
|
||||
proxy_rsra(oiface, msg, len);
|
||||
}
|
||||
}
|
||||
break;
|
||||
case ND_ROUTER_ADVERT:
|
||||
DEBUG("Rx(%s): ND_ROUTER_ADVERT\n", iface->name);
|
||||
if (iface->flags & PROXY_RA) {
|
||||
GList *iter;
|
||||
for (iter = ifaces; iter; iter = g_list_next(iter)) {
|
||||
iface_t *oiface = (iface_t *)iter->data;
|
||||
if (oiface != iface)
|
||||
proxy_rsra(oiface, msg, len);
|
||||
}
|
||||
}
|
||||
break;
|
||||
case ND_NEIGHBOR_SOLICIT:
|
||||
case ND_NEIGHBOR_ADVERT:
|
||||
case ND_REDIRECT:
|
||||
default:
|
||||
DEBUG("Rx(%s): ignoring ICMPv6 packets of type %d\n", iface->name, icmp6_type);
|
||||
break;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static char *flags_to_string(uint32_t flags)
|
||||
{
|
||||
static char sbuffer[256];
|
||||
sbuffer[0] = '\0';
|
||||
if (flags == 0)
|
||||
sprintf(sbuffer, "no packets");
|
||||
if (flags & PROXY_NS)
|
||||
sprintf(sbuffer + strlen(sbuffer), "%sNS",
|
||||
strlen(sbuffer) ? "," : "");
|
||||
if (flags & PROXY_NA)
|
||||
sprintf(sbuffer + strlen(sbuffer), "%sNA",
|
||||
strlen(sbuffer) ? "," : "");
|
||||
if (flags & PROXY_RS)
|
||||
sprintf(sbuffer + strlen(sbuffer), "%sRS",
|
||||
strlen(sbuffer) ? "," : "");
|
||||
if (flags & PROXY_RA)
|
||||
sprintf(sbuffer + strlen(sbuffer), "%sRA",
|
||||
strlen(sbuffer) ? "," : "");
|
||||
if (flags & PROXY_RD)
|
||||
sprintf(sbuffer + strlen(sbuffer), "%sRD",
|
||||
strlen(sbuffer) ? "," : "");
|
||||
return sbuffer;
|
||||
}
|
||||
|
||||
static struct sock_filter bpf_filter[] = {
|
||||
/* Load the ether_type. */
|
||||
BPF_STMT(BPF_LD | BPF_H | BPF_ABS,
|
||||
offsetof(struct ether_header, ether_type)),
|
||||
/* Bail if it's* not* ETHERTYPE_IPV6. */
|
||||
BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, ETHERTYPE_IPV6, 0, 9),
|
||||
/* Load the next header type. */
|
||||
BPF_STMT(BPF_LD | BPF_B | BPF_ABS,
|
||||
sizeof(struct ether_header) + offsetof(struct ip6_hdr,
|
||||
ip6_nxt)),
|
||||
/* Bail if it's* not* IPPROTO_ICMPV6. */
|
||||
BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, IPPROTO_ICMPV6, 0, 7),
|
||||
/* Load the ICMPv6 type. */
|
||||
BPF_STMT(BPF_LD | BPF_B | BPF_ABS,
|
||||
sizeof(struct ether_header) + sizeof(struct ip6_hdr) +
|
||||
offsetof(struct icmp6_hdr, icmp6_type)),
|
||||
/* Bail if it's* not* ND */
|
||||
BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, ND_ROUTER_SOLICIT, 4, 0),
|
||||
BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, ND_ROUTER_ADVERT, 3, 0),
|
||||
BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, ND_NEIGHBOR_SOLICIT, 2, 0),
|
||||
BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, ND_NEIGHBOR_ADVERT, 1, 0),
|
||||
BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, ND_REDIRECT, 0, 1),
|
||||
/* Keep packet. */
|
||||
BPF_STMT(BPF_RET | BPF_K, (u_int32_t)-1),
|
||||
/* Drop packet. */
|
||||
BPF_STMT(BPF_RET | BPF_K, 0)
|
||||
};
|
||||
|
||||
static void iface_open(gpointer data, gpointer user)
|
||||
{
|
||||
iface_t *iface = (iface_t *)data;
|
||||
struct sockaddr_ll lladdr;
|
||||
struct sock_fprog fprog;
|
||||
struct ifreq ifr;
|
||||
int on = 1;
|
||||
int fd;
|
||||
|
||||
DEBUG("Open(%s): %s\n", iface->name, flags_to_string(iface->flags));
|
||||
|
||||
/* Check the interface exists by getting its ifindex */
|
||||
iface->ifindex = if_nametoindex(iface->name);
|
||||
if (!iface->ifindex) {
|
||||
ERROR("Open(%s): Could not find interface\n", iface->name);
|
||||
exit(-1);
|
||||
}
|
||||
|
||||
/* Create raw socket for tx/rx of IPv6 packets */
|
||||
if ((fd = socket(PF_PACKET, SOCK_RAW, htons(ETH_P_IPV6))) < 0) {
|
||||
ERROR("Open(%s): Unable to create socket\n", iface->name);
|
||||
exit(-1);
|
||||
}
|
||||
|
||||
/* Bind the socket to the specified interface */
|
||||
memset(&lladdr, 0, sizeof(struct sockaddr_ll));
|
||||
lladdr.sll_family = AF_PACKET;
|
||||
lladdr.sll_protocol = htons(ETH_P_IPV6);
|
||||
lladdr.sll_ifindex = iface->ifindex;
|
||||
if (bind(fd, (struct sockaddr *)&lladdr, sizeof(struct sockaddr_ll)) < 0) {
|
||||
close(fd);
|
||||
ERROR("Open(%s): Failed to bind to interface\n", iface->name);
|
||||
exit(-1);
|
||||
}
|
||||
|
||||
/* Set the socket non-blocking */
|
||||
if (ioctl(fd, FIONBIO, (char *)&on) < 0) {
|
||||
close(fd);
|
||||
ERROR("Open(%s): Failed to make interface non-blocking\n", iface->name);
|
||||
exit(-1);
|
||||
}
|
||||
|
||||
/* Setup a filter to only receive ND packets */
|
||||
fprog.len = sizeof(bpf_filter) / sizeof(bpf_filter[0]);
|
||||
fprog.filter = bpf_filter;
|
||||
if (setsockopt(fd, SOL_SOCKET, SO_ATTACH_FILTER, &fprog, sizeof(fprog)) < 0) {
|
||||
close(fd);
|
||||
ERROR("Open(%s): Failed to set filter for ND packets\n", iface->name);
|
||||
exit(-1);
|
||||
}
|
||||
|
||||
/* Enable all multicast for this interface */
|
||||
memset(&ifr, 0, sizeof(struct ifreq));
|
||||
strncpy(ifr.ifr_name, iface->name, IFNAMSIZ - 1);
|
||||
if (ioctl(fd, SIOCGIFFLAGS, &ifr) < 0) {
|
||||
close(fd);
|
||||
ERROR("Open(%s): Failed to get flags for interface\n", iface->name);
|
||||
exit(-1);
|
||||
}
|
||||
ifr.ifr_flags |= IFF_ALLMULTI;
|
||||
if (ioctl(fd, SIOCSIFFLAGS, &ifr) < 0) {
|
||||
close(fd);
|
||||
ERROR("Open(%s): Failed to set flags for interface\n", iface->name);
|
||||
exit(-1);
|
||||
}
|
||||
|
||||
/* Get the hwaddr of the interface */
|
||||
memset(&ifr, 0, sizeof(struct ifreq));
|
||||
strncpy(ifr.ifr_name, iface->name, IFNAMSIZ - 1);
|
||||
if (ioctl(fd, SIOCGIFHWADDR, &ifr) < 0) {
|
||||
ERROR("Open(%s): Failed to get interface hwaddr\n", iface->name);
|
||||
exit(-1);
|
||||
}
|
||||
memcpy(iface->hwaddr, ifr.ifr_hwaddr.sa_data, ETH_ALEN);
|
||||
|
||||
/* Watch for packets */
|
||||
iface->fd = fd;
|
||||
iface->src = g_unix_fd_add(fd, G_IO_IN, handle_fd, iface);
|
||||
}
|
||||
|
||||
static void iface_close(gpointer data)
|
||||
{
|
||||
iface_t *iface = (iface_t *)data;
|
||||
DEBUG("Close(%s)\n", iface->name);
|
||||
g_source_remove(iface->src);
|
||||
close(iface->fd);
|
||||
free(iface->name);
|
||||
free(iface);
|
||||
}
|
||||
|
||||
static iface_t *parse_interface(char *desc)
|
||||
{
|
||||
char *name = NULL;
|
||||
uint32_t flags = PROXY_RS | PROXY_RA;
|
||||
char *pflags = strchr(desc, ':');
|
||||
|
||||
if (pflags) {
|
||||
char *token = strtok(pflags + 1, ",");
|
||||
flags = 0;
|
||||
while (token != NULL) {
|
||||
if (strcmp("NS", token) == 0)
|
||||
flags |= PROXY_NS;
|
||||
else if (strcmp("NA", token) == 0)
|
||||
flags |= PROXY_NA;
|
||||
else if (strcmp("RA", token) == 0)
|
||||
flags |= PROXY_RA;
|
||||
else if (strcmp("RS", token) == 0)
|
||||
flags |= PROXY_RS;
|
||||
else if (strcmp("RD", token) == 0)
|
||||
flags |= PROXY_RD;
|
||||
else
|
||||
return NULL;
|
||||
token = strtok(NULL, ",");
|
||||
}
|
||||
name = strndup(desc, pflags - desc);
|
||||
} else {
|
||||
name = strdup(desc);
|
||||
}
|
||||
iface_t *iface = (iface_t *)g_malloc0(sizeof(iface_t));
|
||||
iface->name = name;
|
||||
iface->flags = flags;
|
||||
iface->fd = -1;
|
||||
iface->src = 0;
|
||||
return iface;
|
||||
}
|
||||
|
||||
static gboolean termination_handler(gpointer arg1)
|
||||
{
|
||||
GMainLoop *loop = (GMainLoop *) arg1;
|
||||
g_main_loop_quit(loop);
|
||||
return false;
|
||||
}
|
||||
|
||||
void help(char *app_name)
|
||||
{
|
||||
printf("Usage: %s [-h] [-b] [-d] -i <interface>[:<type>[,<type>]..]\n"
|
||||
" -h show this help\n"
|
||||
" -b background mode\n"
|
||||
" -d enable verbose debug\n"
|
||||
" -i proxy [NS,NA,RS,RA,RD] messages received on <interface>\n"
|
||||
"\n" "e.g %s -i eth1:RS -i eth2:RA\n", app_name, app_name);
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
int i = 0;
|
||||
bool background = false;
|
||||
GMainLoop *loop = NULL;
|
||||
|
||||
/* Parse options */
|
||||
while ((i = getopt(argc, argv, "hdbi:")) != -1) {
|
||||
switch (i) {
|
||||
case 'd':
|
||||
debug = true;
|
||||
background = false;
|
||||
break;
|
||||
case 'b':
|
||||
background = true;
|
||||
break;
|
||||
case 'i':
|
||||
{
|
||||
iface_t *iface = parse_interface(optarg);
|
||||
if (!iface) {
|
||||
help(argv[0]);
|
||||
ERROR("ERROR: Invalid interface specification (%s)\n", optarg);
|
||||
return 0;
|
||||
}
|
||||
ifaces = g_list_prepend(ifaces, iface);
|
||||
break;
|
||||
}
|
||||
case '?':
|
||||
case 'h':
|
||||
default:
|
||||
help(argv[0]);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
/* Check required */
|
||||
if (g_list_length(ifaces) < 2) {
|
||||
help(argv[0]);
|
||||
ERROR("ERROR: Require at least 2 interfaces.\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Daemonize */
|
||||
if (background && fork() != 0) {
|
||||
/* Parent */
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Main loop instance */
|
||||
loop = g_main_loop_new(NULL, true);
|
||||
|
||||
/* Handle SIGTERM/SIGINT/SIGPIPE gracefully */
|
||||
g_unix_signal_add(SIGINT, termination_handler, loop);
|
||||
g_unix_signal_add(SIGTERM, termination_handler, loop);
|
||||
|
||||
/* Startup */
|
||||
g_list_foreach(ifaces, iface_open, NULL);
|
||||
|
||||
/* Loop while not terminated */
|
||||
g_main_loop_run(loop);
|
||||
|
||||
/* Shutdown */
|
||||
g_list_free_full(ifaces, iface_close);
|
||||
|
||||
/* Free the glib main loop */
|
||||
if (loop)
|
||||
g_main_loop_unref(loop);
|
||||
|
||||
return 0;
|
||||
}
|
@ -1,21 +0,0 @@
|
||||
#!/bin/sh
|
||||
# kFreeBSD do not accept scripts as interpreters, using #!/bin/sh and sourcing.
|
||||
if [ true != "$INIT_D_SCRIPT_SOURCED" ] ; then
|
||||
set "$0" "$@"; INIT_D_SCRIPT_SOURCED=true . /lib/init/init-d-script
|
||||
fi
|
||||
|
||||
### BEGIN INIT INFO
|
||||
# Provides: ndppd
|
||||
# Required-Start: $remote_fs $syslog $network
|
||||
# Required-Stop: $remote_fs $syslog $network
|
||||
# Default-Start: 2 3 4 5
|
||||
# Default-Stop: 0 1 6
|
||||
# Short-Description: ndppd init script
|
||||
# Description: NDP Proxy Daemon init script
|
||||
### END INIT INFO
|
||||
# Author: Torben Nehmer <torben+ndppd@nehmer.net>
|
||||
|
||||
DESC="NDP Proxy Daemon"
|
||||
PIDFILE=/run/ndppd.pid
|
||||
DAEMON=/usr/local/sbin/ndppd
|
||||
DAEMON_ARGS="-d -p $PIDFILE"
|
@ -4,12 +4,6 @@
|
||||
|
||||
route-ttl 30000
|
||||
|
||||
# address-ttl <integer> (NEW)
|
||||
# This tells 'ndppd' how often to reload the IP address file /proc/net/if_inet6
|
||||
# Default value is '30000' (30 seconds).
|
||||
|
||||
address-ttl 30000
|
||||
|
||||
# proxy <interface>
|
||||
# This sets up a listener, that will listen for any Neighbor Solicitation
|
||||
# messages, and respond to them according to a set of rules (see below).
|
||||
@ -28,36 +22,6 @@ proxy eth0 {
|
||||
# invalidating the entry, in milliseconds. Default value is '500'.
|
||||
|
||||
timeout 500
|
||||
|
||||
# autowire <yes|no|true|false>
|
||||
# Controls whether ndppd will automatically create host entries
|
||||
# in the routing tables when it receives Neighbor Advertisements on a
|
||||
# listening interface. The the default value is no.
|
||||
# Note: Autowire will ignore all rules with 'auto' or 'static' given it
|
||||
# is expected that the routes are already defined for these paths
|
||||
|
||||
autowire no
|
||||
|
||||
# keepalive <yes|no|true|false>
|
||||
# Controls whether ndppd will automatically attempt to keep routing
|
||||
# sessions alive by actively sending out NDP Solicitations before the the
|
||||
# session is expired. The the default value is yes.
|
||||
|
||||
keepalive yes
|
||||
|
||||
# retries <integer>
|
||||
# Number of times a NDP Solicitation will be sent out before the daemon
|
||||
# considers a route unreachable. The default value is 3
|
||||
|
||||
retries 3
|
||||
|
||||
# promiscuous <yes|no|true|false>
|
||||
# Controls whether ndppd will put the proxy listening interface into promiscuous
|
||||
# mode and hence will react to inbound and outbound NDP commands. This is
|
||||
# required for machines behind the gateway to talk to each other in more
|
||||
# complex topology scenarios. The the default value is no.
|
||||
|
||||
promiscuous no
|
||||
|
||||
# ttl <integer>
|
||||
# Controls how long a valid or invalid entry remains in the cache, in
|
||||
@ -91,13 +55,6 @@ proxy eth0 {
|
||||
|
||||
auto
|
||||
|
||||
# autovia <yes|no|true|false>
|
||||
# Any addresses updated using NDP advertisments will use a gateway to
|
||||
# route traffic on this particular interface (only works wiith the iface
|
||||
# rule type). Default is no
|
||||
|
||||
autovia no
|
||||
|
||||
# Note that before version 0.2.2 of 'ndppd', if you didn't choose a
|
||||
# method, it defaulted to 'static'. For compatibility reasons we choose
|
||||
# to keep this behavior - for now (it may be removed in a future version).
|
||||
|
14
ndppd.conf.5
14
ndppd.conf.5
@ -48,20 +48,6 @@ Controls how long
|
||||
.B ndppd
|
||||
will cache an entry. This is in milliseconds, and the default value
|
||||
is 30000 (30 seconds).
|
||||
.IP "autowire <yes|no>"
|
||||
Controls whether
|
||||
.B ndppd
|
||||
will automatically create host entries in the routing tables when
|
||||
.B ndppd receives Neighbor Advertisements on a listening interface.
|
||||
The default value is no.
|
||||
.IP "promiscuous <yes|no>"
|
||||
Controls whether
|
||||
.B ndppd
|
||||
will put the proxy listening interface into promiscuous mode and
|
||||
hence will react to inbound and outbound NDP commands. This is
|
||||
required for machines behind the gateway to talk to each other in
|
||||
more complex topology scenarios.
|
||||
The the default value is no.
|
||||
.IP "timeout <value>"
|
||||
Controls how long
|
||||
.B ndppd
|
||||
|
@ -1,11 +0,0 @@
|
||||
[Unit]
|
||||
Description=NDP Proxy Daemon
|
||||
After=network.target
|
||||
|
||||
[Service]
|
||||
ExecStart=/usr/sbin/ndppd -d -p /var/run/ndppd/ndppd.pid
|
||||
Type=forking
|
||||
PIDFile=/var/run/ndppd/ndppd.pid
|
||||
|
||||
[Install]
|
||||
WantedBy=multi-user.target
|
123
src/address.cc
123
src/address.cc
@ -15,8 +15,6 @@
|
||||
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <fstream>
|
||||
#include <list>
|
||||
#include <map>
|
||||
|
||||
#include <cstring>
|
||||
@ -29,16 +27,9 @@
|
||||
|
||||
#include "ndppd.h"
|
||||
#include "address.h"
|
||||
#include "route.h"
|
||||
|
||||
NDPPD_NS_BEGIN
|
||||
|
||||
std::list<ptr<route> > address::_addresses;
|
||||
|
||||
int address::_ttl;
|
||||
|
||||
int address::_c_ttl;
|
||||
|
||||
address::address()
|
||||
{
|
||||
reset();
|
||||
@ -57,19 +48,6 @@ address::address(const address& addr)
|
||||
_mask.s6_addr32[3] = addr._mask.s6_addr32[3];
|
||||
}
|
||||
|
||||
address::address(const ptr<address>& addr)
|
||||
{
|
||||
_addr.s6_addr32[0] = addr->_addr.s6_addr32[0];
|
||||
_addr.s6_addr32[1] = addr->_addr.s6_addr32[1];
|
||||
_addr.s6_addr32[2] = addr->_addr.s6_addr32[2];
|
||||
_addr.s6_addr32[3] = addr->_addr.s6_addr32[3];
|
||||
|
||||
_mask.s6_addr32[0] = addr->_mask.s6_addr32[0];
|
||||
_mask.s6_addr32[1] = addr->_mask.s6_addr32[1];
|
||||
_mask.s6_addr32[2] = addr->_mask.s6_addr32[2];
|
||||
_mask.s6_addr32[3] = addr->_mask.s6_addr32[3];
|
||||
}
|
||||
|
||||
address::address(const std::string& str)
|
||||
{
|
||||
parse_string(str);
|
||||
@ -132,21 +110,6 @@ bool address::operator!=(const address& addr) const
|
||||
((_addr.s6_addr32[3] ^ addr._addr.s6_addr32[3]) & _mask.s6_addr32[3]));
|
||||
}
|
||||
|
||||
bool address::is_empty() const
|
||||
{
|
||||
if (_addr.s6_addr32[0] == 0 &&
|
||||
_addr.s6_addr32[1] == 0 &&
|
||||
_addr.s6_addr32[2] == 0 &&
|
||||
_addr.s6_addr32[3] == 0 &&
|
||||
_mask.s6_addr32[0] == 0xffffffff &&
|
||||
_mask.s6_addr32[1] == 0xffffffff &&
|
||||
_mask.s6_addr32[2] == 0xffffffff &&
|
||||
_mask.s6_addr32[3] == 0xffffffff)
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void address::reset()
|
||||
{
|
||||
_addr.s6_addr32[0] = 0;
|
||||
@ -336,93 +299,7 @@ bool address::is_multicast() const
|
||||
|
||||
bool address::is_unicast() const
|
||||
{
|
||||
if (_addr.s6_addr32[2] == 0 &&
|
||||
_addr.s6_addr32[3] == 0)
|
||||
return false;
|
||||
|
||||
return _addr.s6_addr[0] != 0xff;
|
||||
}
|
||||
|
||||
void address::add(const address& addr, const std::string& ifname)
|
||||
{
|
||||
ptr<route> rt(new route(addr, ifname));
|
||||
// logger::debug() << "address::create() addr=" << addr << ", ifname=" << ifname;
|
||||
_addresses.push_back(rt);
|
||||
}
|
||||
|
||||
std::list<ptr<route> >::iterator address::addresses_begin()
|
||||
{
|
||||
return _addresses.begin();
|
||||
}
|
||||
|
||||
std::list<ptr<route> >::iterator address::addresses_end()
|
||||
{
|
||||
return _addresses.end();
|
||||
}
|
||||
|
||||
void address::load(const std::string& path)
|
||||
{
|
||||
// Hack to make sure the addresses are not freed prematurely.
|
||||
std::list<ptr<route> > tmp_addresses(_addresses);
|
||||
_addresses.clear();
|
||||
|
||||
logger::debug() << "reading IP addresses";
|
||||
|
||||
try {
|
||||
std::ifstream ifs;
|
||||
ifs.exceptions(std::ifstream::badbit | std::ifstream::failbit);
|
||||
ifs.open(path.c_str(), std::ios::in);
|
||||
ifs.exceptions(std::ifstream::badbit);
|
||||
|
||||
while (!ifs.eof()) {
|
||||
char buf[1024];
|
||||
ifs.getline(buf, sizeof(buf));
|
||||
|
||||
if (ifs.gcount() < 53) {
|
||||
if (ifs.gcount() > 0)
|
||||
logger::debug() << "skipping entry (size=" << ifs.gcount() << ")";
|
||||
continue;
|
||||
}
|
||||
|
||||
address addr;
|
||||
|
||||
if (route::hexdec(buf, (unsigned char* )&addr.addr(), 16) != 16) {
|
||||
logger::warning() << "failed to load address (" << buf << ")";
|
||||
continue;
|
||||
}
|
||||
|
||||
addr.prefix(128);
|
||||
|
||||
std::string iface = route::token(buf + 45);
|
||||
|
||||
address::add(addr, iface);
|
||||
|
||||
logger::debug() << "found local addr=" << addr << ", iface=" << iface;
|
||||
}
|
||||
} catch (std::ifstream::failure e) {
|
||||
logger::warning() << "Failed to parse IPv6 address data from '" << path << "'";
|
||||
logger::error() << e.what();
|
||||
}
|
||||
|
||||
logger::debug() << "completed IP addresses load";
|
||||
}
|
||||
|
||||
void address::update(int elapsed_time)
|
||||
{
|
||||
if ((_c_ttl -= elapsed_time) <= 0) {
|
||||
load("/proc/net/if_inet6");
|
||||
_c_ttl = _ttl;
|
||||
}
|
||||
}
|
||||
|
||||
int address::ttl()
|
||||
{
|
||||
return _ttl;
|
||||
}
|
||||
|
||||
void address::ttl(int ttl)
|
||||
{
|
||||
_ttl = ttl;
|
||||
}
|
||||
|
||||
NDPPD_NS_END
|
||||
|
@ -16,7 +16,6 @@
|
||||
#pragma once
|
||||
|
||||
#include <string>
|
||||
#include <list>
|
||||
#include <netinet/ip6.h>
|
||||
|
||||
#include "ndppd.h"
|
||||
@ -25,24 +24,15 @@ NDPPD_NS_BEGIN
|
||||
|
||||
class iface;
|
||||
|
||||
class route;
|
||||
|
||||
class address {
|
||||
public:
|
||||
address();
|
||||
address(const address& addr);
|
||||
address(const ptr<address>& addr);
|
||||
address(const std::string& str);
|
||||
address(const char* str);
|
||||
address(const in6_addr& addr);
|
||||
address(const in6_addr& addr, const in6_addr& mask);
|
||||
address(const in6_addr& addr, int prefix);
|
||||
|
||||
static void update(int elapsed_time);
|
||||
|
||||
static int ttl();
|
||||
|
||||
static void ttl(int ttl);
|
||||
|
||||
struct in6_addr& addr();
|
||||
|
||||
@ -56,8 +46,6 @@ public:
|
||||
bool operator!=(const address& addr) const;
|
||||
|
||||
void reset();
|
||||
|
||||
bool is_empty() const;
|
||||
|
||||
const std::string to_string() const;
|
||||
|
||||
@ -72,22 +60,8 @@ public:
|
||||
bool is_multicast() const;
|
||||
|
||||
operator std::string() const;
|
||||
|
||||
static void add(const address& addr, const std::string& ifname);
|
||||
|
||||
static void load(const std::string& path);
|
||||
|
||||
static std::list<ptr<route> >::iterator addresses_begin();
|
||||
|
||||
static std::list<ptr<route> >::iterator addresses_end();
|
||||
|
||||
private:
|
||||
static int _ttl;
|
||||
|
||||
static int _c_ttl;
|
||||
|
||||
static std::list<ptr<route> > _addresses;
|
||||
|
||||
struct in6_addr _addr, _mask;
|
||||
};
|
||||
|
||||
|
371
src/iface.cc
371
src/iface.cc
@ -34,13 +34,11 @@
|
||||
|
||||
#include <linux/filter.h>
|
||||
|
||||
#include <errno.h>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <map>
|
||||
|
||||
#include "ndppd.h"
|
||||
#include "route.h"
|
||||
|
||||
NDPPD_NS_BEGIN
|
||||
|
||||
@ -66,19 +64,13 @@ iface::~iface()
|
||||
if (_prev_allmulti >= 0) {
|
||||
allmulti(_prev_allmulti);
|
||||
}
|
||||
if (_prev_promiscuous >= 0) {
|
||||
promiscuous(_prev_promiscuous);
|
||||
}
|
||||
close(_pfd);
|
||||
}
|
||||
|
||||
_map_dirty = true;
|
||||
|
||||
_serves.clear();
|
||||
_parents.clear();
|
||||
}
|
||||
|
||||
ptr<iface> iface::open_pfd(const std::string& name, bool promiscuous)
|
||||
ptr<iface> iface::open_pfd(const std::string& name)
|
||||
{
|
||||
int fd = 0;
|
||||
|
||||
@ -155,7 +147,7 @@ ptr<iface> iface::open_pfd(const std::string& name, bool promiscuous)
|
||||
// Bail if it's* not* ND_NEIGHBOR_SOLICIT.
|
||||
BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, ND_NEIGHBOR_SOLICIT, 0, 1),
|
||||
// Keep packet.
|
||||
BPF_STMT(BPF_RET | BPF_K, (u_int32_t)-1),
|
||||
BPF_STMT(BPF_RET | BPF_K, -1),
|
||||
// Drop packet.
|
||||
BPF_STMT(BPF_RET | BPF_K, 0)
|
||||
};
|
||||
@ -176,13 +168,6 @@ ptr<iface> iface::open_pfd(const std::string& name, bool promiscuous)
|
||||
|
||||
// Eh. Allmulti.
|
||||
ifa->_prev_allmulti = ifa->allmulti(1);
|
||||
|
||||
// Eh. Promiscuous
|
||||
if (promiscuous == true) {
|
||||
ifa->_prev_promiscuous = ifa->promiscuous(1);
|
||||
} else {
|
||||
ifa->_prev_promiscuous = -1;
|
||||
}
|
||||
|
||||
_map_dirty = true;
|
||||
|
||||
@ -227,29 +212,23 @@ ptr<iface> iface::open_ifd(const std::string& name)
|
||||
|
||||
if (ioctl(fd, SIOCGIFHWADDR,& ifr) < 0) {
|
||||
close(fd);
|
||||
logger::error()
|
||||
<< "Failed to detect link-layer address for interface '"
|
||||
<< name << "'";
|
||||
logger::error() << "Failed to detect link-layer address for interface '" << name << "'";
|
||||
return ptr<iface>();
|
||||
}
|
||||
|
||||
logger::debug()
|
||||
<< "fd=" << fd << ", hwaddr="
|
||||
<< ether_ntoa((const struct ether_addr* )&ifr.ifr_hwaddr.sa_data);
|
||||
logger::debug() << "fd=" << fd << ", hwaddr=" << ether_ntoa((const struct ether_addr* )&ifr.ifr_hwaddr.sa_data);;
|
||||
|
||||
// Set max hops.
|
||||
|
||||
int hops = 255;
|
||||
|
||||
if (setsockopt(fd, IPPROTO_IPV6, IPV6_MULTICAST_HOPS, &hops,
|
||||
sizeof(hops)) < 0) {
|
||||
if (setsockopt(fd, IPPROTO_IPV6, IPV6_MULTICAST_HOPS,& hops, sizeof(hops)) < 0) {
|
||||
close(fd);
|
||||
logger::error() << "iface::open_ifd() failed IPV6_MULTICAST_HOPS";
|
||||
return ptr<iface>();
|
||||
}
|
||||
|
||||
if (setsockopt(fd, IPPROTO_IPV6, IPV6_UNICAST_HOPS, &hops,
|
||||
sizeof(hops)) < 0) {
|
||||
if (setsockopt(fd, IPPROTO_IPV6, IPV6_UNICAST_HOPS,& hops, sizeof(hops)) < 0) {
|
||||
close(fd);
|
||||
logger::error() << "iface::open_ifd() failed IPV6_UNICAST_HOPS";
|
||||
return ptr<iface>();
|
||||
@ -259,11 +238,9 @@ ptr<iface> iface::open_ifd(const std::string& name)
|
||||
|
||||
int on = 1;
|
||||
|
||||
if (ioctl(fd, FIONBIO, (char*)&on) < 0) {
|
||||
if (ioctl(fd, FIONBIO, (char* )&on) < 0) {
|
||||
close(fd);
|
||||
logger::error()
|
||||
<< "Failed to switch to non-blocking on interface '"
|
||||
<< name << "'";
|
||||
logger::error() << "Failed to switch to non-blocking on interface '" << name << "'";
|
||||
return ptr<iface>();
|
||||
}
|
||||
|
||||
@ -271,7 +248,7 @@ ptr<iface> iface::open_ifd(const std::string& name)
|
||||
|
||||
struct icmp6_filter filter;
|
||||
ICMP6_FILTER_SETBLOCKALL(&filter);
|
||||
ICMP6_FILTER_SETPASS(ND_NEIGHBOR_ADVERT, &filter);
|
||||
ICMP6_FILTER_SETPASS(ND_NEIGHBOR_ADVERT,& filter);
|
||||
|
||||
if (setsockopt(fd, IPPROTO_ICMPV6, ICMP6_FILTER,& filter, sizeof(filter)) < 0) {
|
||||
logger::error() << "Failed to set filter";
|
||||
@ -301,7 +278,7 @@ ptr<iface> iface::open_ifd(const std::string& name)
|
||||
return ifa;
|
||||
}
|
||||
|
||||
ssize_t iface::read(int fd, struct sockaddr* saddr, ssize_t saddr_size, uint8_t* msg, size_t size)
|
||||
ssize_t iface::read(int fd, struct sockaddr* saddr, uint8_t* msg, size_t size)
|
||||
{
|
||||
struct msghdr mhdr;
|
||||
struct iovec iov;
|
||||
@ -315,21 +292,18 @@ ssize_t iface::read(int fd, struct sockaddr* saddr, ssize_t saddr_size, uint8_t*
|
||||
|
||||
memset(&mhdr, 0, sizeof(mhdr));
|
||||
mhdr.msg_name = (caddr_t)saddr;
|
||||
mhdr.msg_namelen = saddr_size;
|
||||
mhdr.msg_namelen = sizeof(struct sockaddr);
|
||||
mhdr.msg_iov =& iov;
|
||||
mhdr.msg_iovlen = 1;
|
||||
|
||||
|
||||
if ((len = recvmsg(fd,& mhdr, 0)) < 0)
|
||||
{
|
||||
logger::error() << "iface::read() failed! error=" << logger::err() << ", ifa=" << name();
|
||||
return -1;
|
||||
}
|
||||
|
||||
logger::debug() << "iface::read() ifa=" << name() << ", len=" << len;
|
||||
|
||||
if (len < sizeof(struct icmp6_hdr))
|
||||
return -1;
|
||||
|
||||
logger::debug() << "iface::read() len=" << len;
|
||||
|
||||
return len;
|
||||
}
|
||||
|
||||
@ -353,16 +327,12 @@ ssize_t iface::write(int fd, const address& daddr, const uint8_t* msg, size_t si
|
||||
mhdr.msg_iov =& iov;
|
||||
mhdr.msg_iovlen = 1;
|
||||
|
||||
logger::debug() << "iface::write() ifa=" << name() << ", daddr=" << daddr.to_string() << ", len="
|
||||
<< size;
|
||||
logger::debug() << "iface::write() daddr=" << daddr.to_string() << ", len=" << size;
|
||||
|
||||
int len;
|
||||
|
||||
if ((len = sendmsg(fd,& mhdr, 0)) < 0)
|
||||
{
|
||||
logger::error() << "iface::write() failed! error=" << logger::err() << ", ifa=" << name() << ", daddr=" << daddr.to_string();
|
||||
return -1;
|
||||
}
|
||||
|
||||
return len;
|
||||
}
|
||||
@ -373,28 +343,20 @@ ssize_t iface::read_solicit(address& saddr, address& daddr, address& taddr)
|
||||
uint8_t msg[256];
|
||||
ssize_t len;
|
||||
|
||||
if ((len = read(_pfd, (struct sockaddr*)&t_saddr, sizeof(struct sockaddr_ll), msg, sizeof(msg))) < 0) {
|
||||
logger::warning() << "iface::read_solicit() failed: " << logger::err();
|
||||
if ((len = read(_pfd, (struct sockaddr* )&t_saddr, msg, sizeof(msg))) < 0)
|
||||
return -1;
|
||||
}
|
||||
|
||||
struct ip6_hdr* ip6h =
|
||||
(struct ip6_hdr* )(msg + ETH_HLEN);
|
||||
|
||||
struct nd_neighbor_solicit* ns =
|
||||
(struct nd_neighbor_solicit*)(msg + ETH_HLEN + sizeof(struct ip6_hdr));
|
||||
(struct nd_neighbor_solicit* )(msg + ETH_HLEN + sizeof( struct ip6_hdr));
|
||||
|
||||
taddr = ns->nd_ns_target;
|
||||
daddr = ip6h->ip6_dst;
|
||||
saddr = ip6h->ip6_src;
|
||||
|
||||
// Ignore packets sent from this machine
|
||||
if (iface::is_local(saddr) == true) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
logger::debug() << "iface::read_solicit() saddr=" << saddr.to_string()
|
||||
<< ", daddr=" << daddr.to_string() << ", taddr=" << taddr.to_string() << ", len=" << len;
|
||||
logger::debug() << "iface::read_solicit() saddr=" << saddr.to_string() << ", daddr=" << daddr.to_string() << ", len=" << len;
|
||||
|
||||
return len;
|
||||
}
|
||||
@ -418,8 +380,7 @@ ssize_t iface::write_solicit(const address& taddr)
|
||||
|
||||
memcpy(&ns->nd_ns_target,& taddr.const_addr(), sizeof(struct in6_addr));
|
||||
|
||||
memcpy(buf + sizeof(struct nd_neighbor_solicit) + sizeof(struct nd_opt_hdr),
|
||||
&hwaddr, 6);
|
||||
memcpy(buf + sizeof(struct nd_neighbor_solicit) + sizeof(struct nd_opt_hdr),& hwaddr, 6);
|
||||
|
||||
// FIXME: Alright, I'm lazy.
|
||||
static address multicast("ff02::1:ff00:0000");
|
||||
@ -432,11 +393,9 @@ ssize_t iface::write_solicit(const address& taddr)
|
||||
daddr.addr().s6_addr[14] = taddr.const_addr().s6_addr[14];
|
||||
daddr.addr().s6_addr[15] = taddr.const_addr().s6_addr[15];
|
||||
|
||||
logger::debug() << "iface::write_solicit() taddr=" << taddr.to_string()
|
||||
<< ", daddr=" << daddr.to_string();
|
||||
logger::debug() << "iface::write_solicit() taddr=" << taddr.to_string() << ", daddr=" << daddr.to_string();
|
||||
|
||||
return write(_ifd, daddr, (uint8_t* )buf, sizeof(struct nd_neighbor_solicit)
|
||||
+ sizeof(struct nd_opt_hdr) + 6);
|
||||
return write(_ifd, daddr, (uint8_t* )buf, sizeof(struct nd_neighbor_solicit) + sizeof(struct nd_opt_hdr) + 6);
|
||||
}
|
||||
|
||||
ssize_t iface::write_advert(const address& daddr, const address& taddr, bool router)
|
||||
@ -455,15 +414,13 @@ ssize_t iface::write_advert(const address& daddr, const address& taddr, bool rou
|
||||
opt->nd_opt_len = 1;
|
||||
|
||||
na->nd_na_type = ND_NEIGHBOR_ADVERT;
|
||||
na->nd_na_flags_reserved = (daddr.is_multicast() ? 0 : ND_NA_FLAG_SOLICITED) | (router ? ND_NA_FLAG_ROUTER : 0);
|
||||
na->nd_na_flags_reserved = ND_NA_FLAG_SOLICITED | (router ? ND_NA_FLAG_ROUTER : 0);
|
||||
|
||||
memcpy(&na->nd_na_target,& taddr.const_addr(), sizeof(struct in6_addr));
|
||||
|
||||
memcpy(buf + sizeof(struct nd_neighbor_advert) + sizeof(struct nd_opt_hdr),
|
||||
&hwaddr, 6);
|
||||
memcpy(buf + sizeof(struct nd_neighbor_advert) + sizeof(struct nd_opt_hdr),& hwaddr, 6);
|
||||
|
||||
logger::debug() << "iface::write_advert() daddr=" << daddr.to_string()
|
||||
<< ", taddr=" << taddr.to_string();
|
||||
logger::debug() << "iface::write_advert() daddr=" << daddr.to_string() << ", taddr=" << taddr.to_string();
|
||||
|
||||
return write(_ifd, daddr, (uint8_t* )buf, sizeof(struct nd_neighbor_advert) +
|
||||
sizeof(struct nd_opt_hdr) + 6);
|
||||
@ -474,22 +431,11 @@ ssize_t iface::read_advert(address& saddr, address& taddr)
|
||||
struct sockaddr_in6 t_saddr;
|
||||
uint8_t msg[256];
|
||||
ssize_t len;
|
||||
|
||||
memset(&t_saddr, 0, sizeof(struct sockaddr_in6));
|
||||
t_saddr.sin6_family = AF_INET6;
|
||||
t_saddr.sin6_port = htons(IPPROTO_ICMPV6); // Needed?
|
||||
|
||||
if ((len = read(_ifd, (struct sockaddr* )&t_saddr, sizeof(struct sockaddr_in6), msg, sizeof(msg))) < 0) {
|
||||
logger::warning() << "iface::read_advert() failed: " << logger::err();
|
||||
if ((len = read(_ifd, (struct sockaddr* )&t_saddr, msg, sizeof(msg))) < 0)
|
||||
return -1;
|
||||
}
|
||||
|
||||
saddr = t_saddr.sin6_addr;
|
||||
|
||||
// Ignore packets sent from this machine
|
||||
if (iface::is_local(saddr) == true) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (((struct icmp6_hdr* )msg)->icmp6_type != ND_NEIGHBOR_ADVERT)
|
||||
return -1;
|
||||
@ -501,79 +447,6 @@ ssize_t iface::read_advert(address& saddr, address& taddr)
|
||||
return len;
|
||||
}
|
||||
|
||||
bool iface::is_local(const address& addr)
|
||||
{
|
||||
// Check if the address is for an interface we own that is attached to
|
||||
// one of the slave interfaces
|
||||
for (std::list<ptr<route> >::iterator ad = address::addresses_begin(); ad != address::addresses_end(); ad++)
|
||||
{
|
||||
if ((*ad)->addr() == addr)
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool iface::handle_local(const address& saddr, const address& taddr)
|
||||
{
|
||||
// Check if the address is for an interface we own that is attached to
|
||||
// one of the slave interfaces
|
||||
for (std::list<ptr<route> >::iterator ad = address::addresses_begin(); ad != address::addresses_end(); ad++)
|
||||
{
|
||||
if ((*ad)->addr() == taddr)
|
||||
{
|
||||
// Loop through all the serves that are using this iface to respond to NDP solicitation requests
|
||||
for (std::list<weak_ptr<proxy> >::iterator pit = serves_begin(); pit != serves_end(); pit++) {
|
||||
ptr<proxy> pr = (*pit);
|
||||
if (!pr) continue;
|
||||
|
||||
for (std::list<ptr<rule> >::iterator it = pr->rules_begin(); it != pr->rules_end(); it++) {
|
||||
ptr<rule> ru = *it;
|
||||
|
||||
if (ru->daughter() && ru->daughter()->name() == (*ad)->ifname())
|
||||
{
|
||||
logger::debug() << "proxy::handle_solicit() found local taddr=" << taddr;
|
||||
write_advert(saddr, taddr, false);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void iface::handle_reverse_advert(const address& saddr, const std::string& ifname)
|
||||
{
|
||||
if (!saddr.is_unicast())
|
||||
return;
|
||||
|
||||
logger::debug()
|
||||
<< "proxy::handle_reverse_advert()";
|
||||
|
||||
// Loop through all the parents that forward new NDP soliciation requests to this interface
|
||||
for (std::list<weak_ptr<proxy> >::iterator pit = parents_begin(); pit != parents_end(); pit++) {
|
||||
ptr<proxy> parent = (*pit);
|
||||
if (!parent || !parent->ifa()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// Setup the reverse path on any proxies that are dealing
|
||||
// with the reverse direction (this helps improve connectivity and
|
||||
// latency in a full duplex setup)
|
||||
for (std::list<ptr<rule> >::iterator it = parent->rules_begin(); it != parent->rules_end(); it++) {
|
||||
ptr<rule> ru = *it;
|
||||
|
||||
if (ru->addr() == saddr &&
|
||||
ru->daughter()->name() == ifname)
|
||||
{
|
||||
logger::debug() << " - generating artifical advertisement: " << ifname;
|
||||
parent->handle_stateless_advert(saddr, saddr, ifname, ru->autovia());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void iface::fixup_pollfds()
|
||||
{
|
||||
_pollfds.resize(_map.size()* 2);
|
||||
@ -596,6 +469,22 @@ void iface::fixup_pollfds()
|
||||
}
|
||||
}
|
||||
|
||||
void iface::remove_session(const ptr<session>& se)
|
||||
{
|
||||
for (std::list<weak_ptr<session> >::iterator it = _sessions.begin();
|
||||
it != _sessions.end(); it++) {
|
||||
if (*it == se) {
|
||||
_sessions.erase(it);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void iface::add_session(const ptr<session>& se)
|
||||
{
|
||||
_sessions.push_back(se);
|
||||
}
|
||||
|
||||
void iface::cleanup()
|
||||
{
|
||||
for (std::map<std::string, weak_ptr<iface> >::iterator it = _map.begin();
|
||||
@ -625,7 +514,6 @@ int iface::poll_all()
|
||||
int len;
|
||||
|
||||
if ((len = ::poll(&_pollfds[0], _pollfds.size(), 50)) < 0) {
|
||||
logger::error() << "Failed to poll interfaces: " << logger::err();
|
||||
return -1;
|
||||
}
|
||||
|
||||
@ -647,107 +535,43 @@ int iface::poll_all()
|
||||
|
||||
bool is_pfd = i++ % 2;
|
||||
|
||||
ptr<iface> ifa = i_it->second;
|
||||
|
||||
if (f_it->revents & POLLERR) {
|
||||
logger::error() << "Error polling interface " << ifa->_name.c_str();
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (!(f_it->revents & POLLIN)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
ptr<iface> ifa = i_it->second;
|
||||
|
||||
address saddr, daddr, taddr;
|
||||
ssize_t size;
|
||||
|
||||
if (is_pfd) {
|
||||
size = ifa->read_solicit(saddr, daddr, taddr);
|
||||
if (size < 0) {
|
||||
if (ifa->read_solicit(saddr, daddr, taddr) < 0) {
|
||||
logger::error() << "Failed to read from interface '%s'", ifa->_name.c_str();
|
||||
continue;
|
||||
}
|
||||
if (size == 0) {
|
||||
logger::debug() << "iface::read_solicit() loopback received and ignored";
|
||||
continue;
|
||||
}
|
||||
|
||||
// Process any local addresses for interfaces that we are proxying
|
||||
if (ifa->handle_local(saddr, taddr) == true) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// We have to handle all the parents who may be interested in
|
||||
// the reverse path towards the one who sent this solicit.
|
||||
// In fact, the parent need to know the source address in order
|
||||
// to respond to NDP Solicitations
|
||||
ifa->handle_reverse_advert(saddr, ifa->name());
|
||||
|
||||
// Loop through all the proxies that are using this iface to respond to NDP solicitation requests
|
||||
bool handled = false;
|
||||
for (std::list<weak_ptr<proxy> >::iterator pit = ifa->serves_begin(); pit != ifa->serves_end(); pit++) {
|
||||
ptr<proxy> pr = (*pit);
|
||||
if (!pr) continue;
|
||||
|
||||
// Process the solicitation request by relating it to other
|
||||
// interfaces or lookup up any statics routes we have configured
|
||||
handled = true;
|
||||
pr->handle_solicit(saddr, taddr, ifa->name());
|
||||
if (!saddr.is_unicast() || !daddr.is_multicast()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// If it was not handled then write an error message
|
||||
if (handled == false) {
|
||||
logger::debug() << " - solicit was ignored";
|
||||
|
||||
if (ifa->_pr) {
|
||||
ifa->_pr->handle_solicit(saddr, daddr, taddr);
|
||||
}
|
||||
|
||||
} else {
|
||||
size = ifa->read_advert(saddr, taddr);
|
||||
if (size < 0) {
|
||||
if (ifa->read_advert(saddr, taddr) < 0) {
|
||||
logger::error() << "Failed to read from interface '%s'", ifa->_name.c_str();
|
||||
continue;
|
||||
}
|
||||
if (size == 0) {
|
||||
logger::debug() << "iface::read_advert() loopback received and ignored";
|
||||
continue;
|
||||
}
|
||||
|
||||
// Process the NDP advert
|
||||
bool handled = false;
|
||||
for (std::list<weak_ptr<proxy> >::iterator pit = ifa->parents_begin(); pit != ifa->parents_end(); pit++) {
|
||||
ptr<proxy> pr = (*pit);
|
||||
if (!pr || !pr->ifa()) {
|
||||
continue;
|
||||
|
||||
for (std::list<weak_ptr<session> >::iterator s_it = ifa->_sessions.begin();
|
||||
s_it != ifa->_sessions.end(); s_it++) {
|
||||
assert(!s_it->is_null());
|
||||
|
||||
const ptr<session> sess = *s_it;
|
||||
|
||||
if ((sess->taddr() == taddr) && (sess->status() == session::WAITING)) {
|
||||
sess->handle_advert();
|
||||
break;
|
||||
}
|
||||
|
||||
// The proxy must have a rule for this interface or it is not meant to receive
|
||||
// any notifications and thus they must be ignored
|
||||
bool autovia = false;
|
||||
bool is_relevant = false;
|
||||
for (std::list<ptr<rule> >::iterator it = pr->rules_begin(); it != pr->rules_end(); it++) {
|
||||
ptr<rule> ru = *it;
|
||||
|
||||
if (ru->addr() == taddr &&
|
||||
ru->daughter() &&
|
||||
ru->daughter()->name() == ifa->name())
|
||||
{
|
||||
is_relevant = true;
|
||||
autovia = ru->autovia();
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (is_relevant == false) {
|
||||
logger::debug() << "iface::read_advert() advert is not for " << ifa->name() << "...skipping";
|
||||
continue;
|
||||
}
|
||||
|
||||
// Process the NDP advertisement
|
||||
handled = true;
|
||||
pr->handle_advert(saddr, taddr, ifa->name(), autovia);
|
||||
}
|
||||
|
||||
// If it was not handled then write an error message
|
||||
if (handled == false) {
|
||||
logger::debug() << " - advert was ignored";
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -759,9 +583,7 @@ int iface::allmulti(int state)
|
||||
{
|
||||
struct ifreq ifr;
|
||||
|
||||
logger::debug()
|
||||
<< "iface::allmulti() state="
|
||||
<< state << ", _name=\"" << _name << "\"";
|
||||
logger::debug() << "iface::allmulti() state=" << state << ", _name=\"" << _name << "\"";
|
||||
|
||||
state = !!state;
|
||||
|
||||
@ -770,11 +592,10 @@ int iface::allmulti(int state)
|
||||
strncpy(ifr.ifr_name, _name.c_str(), IFNAMSIZ);
|
||||
|
||||
if (ioctl(_pfd, SIOCGIFFLAGS, &ifr) < 0) {
|
||||
logger::error() << "Failed to get allmulti: " << logger::err();
|
||||
return -1;
|
||||
}
|
||||
|
||||
int old_state = !!(ifr.ifr_flags &IFF_ALLMULTI);
|
||||
int old_state = !!(ifr.ifr_flags & IFF_ALLMULTI);
|
||||
|
||||
if (state == old_state) {
|
||||
return old_state;
|
||||
@ -787,46 +608,6 @@ int iface::allmulti(int state)
|
||||
}
|
||||
|
||||
if (ioctl(_pfd, SIOCSIFFLAGS, &ifr) < 0) {
|
||||
logger::error() << "Failed to set allmulti: " << logger::err();
|
||||
return -1;
|
||||
}
|
||||
|
||||
return old_state;
|
||||
}
|
||||
|
||||
int iface::promiscuous(int state)
|
||||
{
|
||||
struct ifreq ifr;
|
||||
|
||||
logger::debug()
|
||||
<< "iface::promiscuous() state="
|
||||
<< state << ", _name=\"" << _name << "\"";
|
||||
|
||||
state = !!state;
|
||||
|
||||
memset(&ifr, 0, sizeof(ifr));
|
||||
|
||||
strncpy(ifr.ifr_name, _name.c_str(), IFNAMSIZ);
|
||||
|
||||
if (ioctl(_pfd, SIOCGIFFLAGS, &ifr) < 0) {
|
||||
logger::error() << "Failed to get promiscuous: " << logger::err();
|
||||
return -1;
|
||||
}
|
||||
|
||||
int old_state = !!(ifr.ifr_flags &IFF_PROMISC);
|
||||
|
||||
if (state == old_state) {
|
||||
return old_state;
|
||||
}
|
||||
|
||||
if (state) {
|
||||
ifr.ifr_flags |= IFF_PROMISC;
|
||||
} else {
|
||||
ifr.ifr_flags &= ~IFF_PROMISC;
|
||||
}
|
||||
|
||||
if (ioctl(_pfd, SIOCSIFFLAGS, &ifr) < 0) {
|
||||
logger::error() << "Failed to set promiscuous: " << logger::err();
|
||||
return -1;
|
||||
}
|
||||
|
||||
@ -838,34 +619,14 @@ const std::string& iface::name() const
|
||||
return _name;
|
||||
}
|
||||
|
||||
void iface::add_serves(const ptr<proxy>& pr)
|
||||
void iface::pr(const ptr<proxy>& pr)
|
||||
{
|
||||
_serves.push_back(pr);
|
||||
_pr = pr;
|
||||
}
|
||||
|
||||
std::list<weak_ptr<proxy> >::iterator iface::serves_begin()
|
||||
const ptr<proxy>& iface::pr() const
|
||||
{
|
||||
return _serves.begin();
|
||||
}
|
||||
|
||||
std::list<weak_ptr<proxy> >::iterator iface::serves_end()
|
||||
{
|
||||
return _serves.end();
|
||||
}
|
||||
|
||||
void iface::add_parent(const ptr<proxy>& pr)
|
||||
{
|
||||
_parents.push_back(pr);
|
||||
}
|
||||
|
||||
std::list<weak_ptr<proxy> >::iterator iface::parents_begin()
|
||||
{
|
||||
return _parents.begin();
|
||||
}
|
||||
|
||||
std::list<weak_ptr<proxy> >::iterator iface::parents_end()
|
||||
{
|
||||
return _parents.end();
|
||||
return _pr;
|
||||
}
|
||||
|
||||
NDPPD_NS_END
|
||||
|
53
src/iface.h
53
src/iface.h
@ -38,13 +38,13 @@ public:
|
||||
|
||||
static ptr<iface> open_ifd(const std::string& name);
|
||||
|
||||
static ptr<iface> open_pfd(const std::string& name, bool promiscuous);
|
||||
static ptr<iface> open_pfd(const std::string& name);
|
||||
|
||||
static int poll_all();
|
||||
|
||||
ssize_t read(int fd, struct sockaddr* saddr, ssize_t saddr_size, uint8_t* msg, size_t size);
|
||||
static ssize_t read(int fd, struct sockaddr* saddr, uint8_t* msg, size_t size);
|
||||
|
||||
ssize_t write(int fd, const address& daddr, const uint8_t* msg, size_t size);
|
||||
static ssize_t write(int fd, const address& daddr, const uint8_t* msg, size_t size);
|
||||
|
||||
// Writes a NB_NEIGHBOR_SOLICIT message to the _ifd socket.
|
||||
ssize_t write_solicit(const address& taddr);
|
||||
@ -57,31 +57,21 @@ public:
|
||||
|
||||
// Reads a NB_NEIGHBOR_ADVERT message from the _ifd socket;
|
||||
ssize_t read_advert(address& saddr, address& taddr);
|
||||
|
||||
bool handle_local(const address& saddr, const address& taddr);
|
||||
|
||||
bool is_local(const address& addr);
|
||||
|
||||
void handle_reverse_advert(const address& saddr, const std::string& ifname);
|
||||
|
||||
// Returns the name of the interface.
|
||||
const std::string& name() const;
|
||||
|
||||
std::list<weak_ptr<proxy> >::iterator serves_begin();
|
||||
|
||||
std::list<weak_ptr<proxy> >::iterator serves_end();
|
||||
|
||||
void add_serves(const ptr<proxy>& proxy);
|
||||
|
||||
std::list<weak_ptr<proxy> >::iterator parents_begin();
|
||||
|
||||
std::list<weak_ptr<proxy> >::iterator parents_end();
|
||||
|
||||
void add_parent(const ptr<proxy>& parent);
|
||||
|
||||
static std::map<std::string, weak_ptr<iface> > _map;
|
||||
|
||||
// Adds a session to be monitored for ND_NEIGHBOR_ADVERT messages.
|
||||
void add_session(const ptr<session>& se);
|
||||
|
||||
void remove_session(const ptr<session>& se);
|
||||
|
||||
void pr(const ptr<proxy>& pr);
|
||||
|
||||
const ptr<proxy>& pr() const;
|
||||
|
||||
private:
|
||||
static std::map<std::string, weak_ptr<iface> > _map;
|
||||
|
||||
static bool _map_dirty;
|
||||
|
||||
@ -106,16 +96,15 @@ private:
|
||||
|
||||
// Previous state of ALLMULTI for the interface.
|
||||
int _prev_allmulti;
|
||||
|
||||
// Previous state of PROMISC for the interface
|
||||
int _prev_promiscuous;
|
||||
|
||||
// Name of this interface.
|
||||
std::string _name;
|
||||
|
||||
std::list<weak_ptr<proxy> > _serves;
|
||||
|
||||
std::list<weak_ptr<proxy> > _parents;
|
||||
|
||||
// An array of sessions that are monitoring this interface for
|
||||
// ND_NEIGHBOR_ADVERT messages.
|
||||
std::list<weak_ptr<session> > _sessions;
|
||||
|
||||
weak_ptr<proxy> _pr;
|
||||
|
||||
// The link-layer address of this interface.
|
||||
struct ether_addr hwaddr;
|
||||
@ -123,10 +112,6 @@ private:
|
||||
// Turns on/off ALLMULTI for this interface - returns the previous state
|
||||
// or -1 if there was an error.
|
||||
int allmulti(int state);
|
||||
|
||||
// Turns on/off PROMISC for this interface - returns the previous state
|
||||
// or -1 if there was an error
|
||||
int promiscuous(int state);
|
||||
|
||||
// Constructor.
|
||||
iface();
|
||||
|
@ -18,7 +18,6 @@
|
||||
#include <cctype>
|
||||
#include <cstdlib>
|
||||
#include <cstring>
|
||||
#include <cerrno>
|
||||
#include <iostream>
|
||||
#include <sstream>
|
||||
|
||||
@ -80,28 +79,6 @@ std::string logger::format(const std::string& fmt, ...)
|
||||
return buf;
|
||||
}
|
||||
|
||||
// alpine has a broken definition for strerr_r
|
||||
// see https://stackoverflow.com/questions/41953104/strerror-r-is-incorrectly-declared-on-alpine-linux
|
||||
|
||||
std::string logger::err_str(int result, char *buff, int err)
|
||||
{
|
||||
if (result)
|
||||
sprintf(buff, "unknown error: %d", err);
|
||||
return buff;
|
||||
}
|
||||
|
||||
std::string logger::err_str(char *result, char *buff, int err)
|
||||
{
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
std::string logger::err()
|
||||
{
|
||||
char buf[2048];
|
||||
return logger::err_str(strerror_r(errno, buf, sizeof(buf)), buf, errno);
|
||||
}
|
||||
|
||||
logger logger::error()
|
||||
{
|
||||
return logger(LOG_ERR);
|
||||
|
@ -71,10 +71,7 @@ public:
|
||||
static logger debug();
|
||||
static logger notice();
|
||||
|
||||
static std::string err();
|
||||
|
||||
private:
|
||||
|
||||
int _pri;
|
||||
|
||||
std::stringstream _ss;
|
||||
@ -92,9 +89,7 @@ private:
|
||||
|
||||
static int _max_pri;
|
||||
|
||||
// fixes for strerr_r on alpine
|
||||
static std::string err_str(int result, char *buff, int err);
|
||||
static std::string err_str(char *result, char *buff, int err);
|
||||
|
||||
};
|
||||
|
||||
NDPPD_NS_END
|
||||
|
@ -1,275 +0,0 @@
|
||||
//
|
||||
//@file nd-netlink.cc
|
||||
//
|
||||
// Copyright 2016, Allied Telesis Labs New Zealand, Ltd
|
||||
//
|
||||
// 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 3 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, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
#include <sys/socket.h>
|
||||
#include <errno.h>
|
||||
#include <netlink/route/addr.h>
|
||||
#include <arpa/inet.h>
|
||||
#include "ndppd.h"
|
||||
#include <algorithm>
|
||||
|
||||
NDPPD_NS_BEGIN
|
||||
|
||||
pthread_mutex_t cs_mutex = PTHREAD_MUTEX_INITIALIZER;
|
||||
|
||||
struct in6_addr*
|
||||
address_create_ipv6(struct in6_addr *local)
|
||||
{
|
||||
struct in6_addr *addr = (struct in6_addr *)calloc(1, sizeof(struct in6_addr));
|
||||
memcpy(addr, local, sizeof(struct in6_addr));
|
||||
return addr;
|
||||
}
|
||||
|
||||
void if_add_to_list(int ifindex, const ptr<iface>& ifa)
|
||||
{
|
||||
bool found = false;
|
||||
|
||||
pthread_mutex_lock (&cs_mutex);
|
||||
for (std::vector<interface>::iterator it = interfaces.begin();
|
||||
it != interfaces.end(); it++) {
|
||||
if ((*it).ifindex == ifindex) {
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!found) {
|
||||
logger::debug() << "rule::add_iface() if=" << ifa->name();
|
||||
interface anInterface;
|
||||
anInterface._name = ifa->name();
|
||||
anInterface.ifindex = ifindex;
|
||||
interfaces.push_back(anInterface);
|
||||
}
|
||||
pthread_mutex_unlock (&cs_mutex);
|
||||
}
|
||||
|
||||
void
|
||||
if_addr_add(int ifindex, struct in6_addr *iaddr)
|
||||
{
|
||||
pthread_mutex_lock (&cs_mutex);
|
||||
for (std::vector<interface>::iterator it = interfaces.begin();
|
||||
it != interfaces.end(); it++) {
|
||||
if ((*it).ifindex == ifindex) {
|
||||
address addr = address(*iaddr);
|
||||
logger::debug() << "Adding addr " << addr.to_string();
|
||||
std::list<address>::iterator it_addr;
|
||||
it_addr = std::find((*it).addresses.begin(), (*it).addresses.end(), addr);
|
||||
if (it_addr == (*it).addresses.end()) {
|
||||
(*it).addresses.push_back(addr);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
free(iaddr);
|
||||
pthread_mutex_unlock (&cs_mutex);
|
||||
}
|
||||
|
||||
void
|
||||
if_addr_del(int ifindex, struct in6_addr *iaddr)
|
||||
{
|
||||
pthread_mutex_lock (&cs_mutex);
|
||||
for (std::vector<interface>::iterator it = interfaces.begin();
|
||||
it != interfaces.end(); it++) {
|
||||
if ((*it).ifindex == ifindex) {
|
||||
address addr = address(*iaddr);
|
||||
logger::debug() << "Deleting addr " << addr.to_string();
|
||||
(*it).addresses.remove(addr);
|
||||
break;
|
||||
}
|
||||
}
|
||||
free(iaddr);
|
||||
pthread_mutex_unlock (&cs_mutex);
|
||||
}
|
||||
|
||||
bool
|
||||
if_addr_find(std::string iface, const struct in6_addr *iaddr)
|
||||
{
|
||||
bool found = false;
|
||||
|
||||
pthread_mutex_lock (&cs_mutex);
|
||||
for (std::vector<interface>::iterator it = interfaces.begin();
|
||||
it != interfaces.end(); it++) {
|
||||
if (iface.compare((*it)._name) == 0) {
|
||||
address addr = address(*iaddr);
|
||||
std::list<address>::iterator it_addr;
|
||||
it_addr = std::find((*it).addresses.begin(), (*it).addresses.end(), addr);
|
||||
if (it_addr != (*it).addresses.end()) {
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
pthread_mutex_unlock (&cs_mutex);
|
||||
return found;
|
||||
}
|
||||
|
||||
static void
|
||||
nl_msg_newaddr(struct nlmsghdr *hdr)
|
||||
{
|
||||
struct ifaddrmsg *ifaddr =
|
||||
(struct ifaddrmsg *)(((char *) hdr) + (sizeof(struct nlmsghdr)));
|
||||
// parse the attributes
|
||||
struct nlattr *attrs[IFA_MAX + 1];
|
||||
struct nlattr *s = (struct nlattr *)(((char *) ifaddr) + (sizeof(struct ifaddrmsg)));
|
||||
int len = nlmsg_datalen(hdr) - sizeof(struct ifinfomsg);
|
||||
memset(&attrs, '\0', sizeof(attrs));
|
||||
nla_parse(attrs, IFA_MAX, s, len, NULL);
|
||||
|
||||
struct in6_addr* addr = NULL;
|
||||
|
||||
if (ifaddr->ifa_family == AF_INET6) {
|
||||
addr = address_create_ipv6((struct in6_addr *)nla_data(attrs[IFA_ADDRESS]));
|
||||
if_addr_add(ifaddr->ifa_index, addr);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
nl_msg_deladdr(struct nlmsghdr *hdr)
|
||||
{
|
||||
struct ifaddrmsg *ifaddr =
|
||||
(struct ifaddrmsg *)(((char *) hdr) + (sizeof(struct nlmsghdr)));
|
||||
// parse the attributes
|
||||
struct nlattr *attrs[IFA_MAX + 1];
|
||||
struct nlattr *s = (struct nlattr *)(((char *) ifaddr) + (sizeof(struct ifaddrmsg)));
|
||||
int len = nlmsg_datalen(hdr) - sizeof(struct ifinfomsg);
|
||||
memset(&attrs, '\0', sizeof(attrs));
|
||||
nla_parse(attrs, IFA_MAX, s, len, NULL);
|
||||
|
||||
struct in6_addr* addr = NULL;
|
||||
|
||||
if (ifaddr->ifa_family == AF_INET6) {
|
||||
addr = address_create_ipv6((struct in6_addr *)nla_data(attrs[IFA_ADDRESS]));
|
||||
if_addr_del(ifaddr->ifa_index, addr);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
new_addr(struct nl_object *obj, void *p)
|
||||
{
|
||||
struct rtnl_addr *addr = (struct rtnl_addr *) obj;
|
||||
struct nl_addr *local = rtnl_addr_get_local(addr);
|
||||
int family = rtnl_addr_get_family(addr);
|
||||
int ifindex = rtnl_addr_get_ifindex(addr);
|
||||
struct in6_addr* in_addr = NULL;
|
||||
|
||||
char ipstr[INET6_ADDRSTRLEN];
|
||||
inet_ntop(family, nl_addr_get_binary_addr(local), ipstr, INET6_ADDRSTRLEN);
|
||||
|
||||
switch (family) {
|
||||
case AF_INET:
|
||||
break;
|
||||
case AF_INET6:
|
||||
in_addr = address_create_ipv6((struct in6_addr *)nl_addr_get_binary_addr(local));
|
||||
if_addr_add(ifindex, in_addr);
|
||||
break;
|
||||
default:
|
||||
logger::error() << "Unknown message family: " << family;
|
||||
}
|
||||
}
|
||||
|
||||
static int
|
||||
nl_msg_handler(struct nl_msg *msg, void *arg)
|
||||
{
|
||||
logger::debug() << "nl_msg_handler";
|
||||
struct nlmsghdr *hdr = nlmsg_hdr(msg);
|
||||
|
||||
switch (hdr->nlmsg_type) {
|
||||
case RTM_NEWADDR:
|
||||
nl_msg_newaddr(hdr);
|
||||
break;
|
||||
case RTM_DELADDR:
|
||||
nl_msg_deladdr(hdr);
|
||||
break;
|
||||
default:
|
||||
logger::error() << "Unknown message type: " << hdr->nlmsg_type;
|
||||
}
|
||||
|
||||
return NL_OK;
|
||||
}
|
||||
|
||||
static void *
|
||||
netlink_monitor(void *p)
|
||||
{
|
||||
struct nl_sock *sock = (struct nl_sock *) p;
|
||||
struct nl_cache *addr_cache;
|
||||
|
||||
// get all the current addresses
|
||||
if (rtnl_addr_alloc_cache(sock, &addr_cache) < 0) {
|
||||
perror("rtnl_addr_alloc_cache");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// add existing addresses
|
||||
nl_cache_foreach(addr_cache, new_addr, NULL);
|
||||
// destroy the cache
|
||||
nl_cache_free(addr_cache);
|
||||
|
||||
// switch to notification mode
|
||||
// disable sequence checking
|
||||
nl_socket_disable_seq_check(sock);
|
||||
// set the callback we want
|
||||
nl_socket_modify_cb(sock, NL_CB_VALID, NL_CB_CUSTOM, nl_msg_handler, NULL);
|
||||
|
||||
// subscribe to the IPv6 address change callbacks
|
||||
nl_socket_add_memberships(sock, RTNLGRP_IPV6_IFADDR, 0);
|
||||
|
||||
while (1)
|
||||
{
|
||||
nl_recvmsgs_default(sock);
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static pthread_t monitor_thread;
|
||||
static struct nl_sock *monitor_sock;
|
||||
struct nl_sock *control_sock;
|
||||
|
||||
bool
|
||||
netlink_setup()
|
||||
{
|
||||
// create a netlink socket
|
||||
control_sock = nl_socket_alloc();
|
||||
nl_connect(control_sock, NETLINK_ROUTE);
|
||||
|
||||
// create a thread to run the netlink monitor in
|
||||
// create a netlink socket
|
||||
monitor_sock = nl_socket_alloc();
|
||||
nl_connect(monitor_sock, NETLINK_ROUTE);
|
||||
// increase the recv buffer size to capture all notifications
|
||||
nl_socket_set_buffer_size(monitor_sock, 2048000, 0);
|
||||
|
||||
pthread_create(&monitor_thread, NULL, netlink_monitor, monitor_sock);
|
||||
pthread_setname_np(monitor_thread, "netlink");
|
||||
if (pthread_setschedprio(monitor_thread, -10) < 0)
|
||||
{
|
||||
logger::warning() << "setschedprio: " << strerror(errno);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
netlink_teardown()
|
||||
{
|
||||
void *res = 0;
|
||||
pthread_cancel(monitor_thread);
|
||||
pthread_join(monitor_thread, &res);
|
||||
nl_socket_free(monitor_sock);
|
||||
nl_socket_free(control_sock);
|
||||
return true;
|
||||
}
|
||||
|
||||
NDPPD_NS_END
|
@ -1,28 +0,0 @@
|
||||
//
|
||||
// @file nd-netlink.h
|
||||
//
|
||||
// Copyright 2016, Allied Telesis Labs New Zealand, Ltd
|
||||
//
|
||||
// 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 3 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, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
#pragma once
|
||||
|
||||
NDPPD_NS_BEGIN
|
||||
|
||||
bool netlink_teardown();
|
||||
bool netlink_setup();
|
||||
bool if_addr_find(std::string iface, const struct in6_addr *iaddr);
|
||||
void if_add_to_list(int ifindex, const ptr<iface>& ifa);
|
||||
|
||||
NDPPD_NS_END
|
267
src/ndppd.cc
267
src/ndppd.cc
@ -24,7 +24,6 @@
|
||||
#include <getopt.h>
|
||||
#include <sys/time.h>
|
||||
|
||||
#include <sys/stat.h>
|
||||
#include <sys/types.h>
|
||||
#include <unistd.h>
|
||||
|
||||
@ -33,29 +32,20 @@
|
||||
|
||||
using namespace ndppd;
|
||||
|
||||
static int daemonize()
|
||||
int daemonize()
|
||||
{
|
||||
pid_t pid = fork();
|
||||
if (pid < 0) {
|
||||
logger::error() << "Failed to fork during daemonize: " << logger::err();
|
||||
|
||||
if (pid < 0)
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (pid > 0)
|
||||
exit(0);
|
||||
|
||||
umask(0);
|
||||
|
||||
pid_t sid = setsid();
|
||||
if (sid < 0) {
|
||||
logger::error() << "Failed to setsid during daemonize: " << logger::err();
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (chdir("/") < 0) {
|
||||
logger::error() << "Failed to change path during daemonize: " << logger::err();
|
||||
if (sid < 0)
|
||||
return -1;
|
||||
}
|
||||
|
||||
close(STDIN_FILENO);
|
||||
close(STDOUT_FILENO);
|
||||
@ -64,12 +54,17 @@ static int daemonize()
|
||||
return 0;
|
||||
}
|
||||
|
||||
static ptr<conf> load_config(const std::string& path)
|
||||
bool configure(const std::string& path)
|
||||
{
|
||||
ptr<conf> cf, x_cf;
|
||||
|
||||
if (!(cf = conf::load(path)))
|
||||
return (conf*)NULL;
|
||||
return false;
|
||||
|
||||
if (!(x_cf = cf->find("route-ttl")))
|
||||
route::ttl(30000);
|
||||
else
|
||||
route::ttl(*x_cf);
|
||||
|
||||
std::vector<ptr<conf> >::const_iterator p_it;
|
||||
|
||||
@ -80,94 +75,13 @@ static ptr<conf> load_config(const std::string& path)
|
||||
|
||||
if (pr_cf->empty()) {
|
||||
logger::error() << "'proxy' section is missing interface name";
|
||||
return (conf*)NULL;
|
||||
}
|
||||
|
||||
std::vector<ptr<conf> >::const_iterator r_it;
|
||||
|
||||
std::vector<ptr<conf> > rules(pr_cf->find_all("rule"));
|
||||
|
||||
for (r_it = rules.begin(); r_it != rules.end(); r_it++) {
|
||||
ptr<conf> ru_cf =* r_it;
|
||||
|
||||
if (ru_cf->empty()) {
|
||||
logger::error() << "'rule' is missing an IPv6 address/net";
|
||||
return (conf*)NULL;
|
||||
}
|
||||
|
||||
address addr(*ru_cf);
|
||||
|
||||
if (x_cf = ru_cf->find("iface")) {
|
||||
if (ru_cf->find("static") || ru_cf->find("auto")) {
|
||||
logger::error()
|
||||
<< "Only one of 'iface', 'auto' and 'static' may "
|
||||
<< "be specified.";
|
||||
return (conf*)NULL;
|
||||
}
|
||||
if ((const std::string&)*x_cf == "") {
|
||||
logger::error() << "'iface' expected an interface name";
|
||||
return (conf*)NULL;
|
||||
}
|
||||
} else if (ru_cf->find("static")) {
|
||||
if (ru_cf->find("auto")) {
|
||||
logger::error()
|
||||
<< "Only one of 'iface', 'auto' and 'static' may "
|
||||
<< "be specified.";
|
||||
return (conf*)NULL;
|
||||
}
|
||||
if (addr.prefix() <= 120) {
|
||||
logger::warning()
|
||||
<< "Low prefix length (" << addr.prefix()
|
||||
<< " <= 120) when using 'static' method";
|
||||
}
|
||||
} else if (!ru_cf->find("auto")) {
|
||||
logger::error()
|
||||
<< "You must specify either 'iface', 'auto' or "
|
||||
<< "'static'";
|
||||
return (conf*)NULL;
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return cf;
|
||||
}
|
||||
|
||||
static bool configure(ptr<conf>& cf)
|
||||
{
|
||||
ptr<conf> x_cf;
|
||||
|
||||
if (!(x_cf = cf->find("route-ttl")))
|
||||
route::ttl(30000);
|
||||
else
|
||||
route::ttl(*x_cf);
|
||||
|
||||
if (!(x_cf = cf->find("address-ttl")))
|
||||
address::ttl(30000);
|
||||
else
|
||||
address::ttl(*x_cf);
|
||||
|
||||
std::list<ptr<rule> > myrules;
|
||||
|
||||
std::vector<ptr<conf> >::const_iterator p_it;
|
||||
|
||||
std::vector<ptr<conf> > proxies(cf->find_all("proxy"));
|
||||
|
||||
for (p_it = proxies.begin(); p_it != proxies.end(); p_it++) {
|
||||
ptr<conf> pr_cf = *p_it;
|
||||
|
||||
if (pr_cf->empty()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
bool promiscuous = false;
|
||||
if (!(x_cf = pr_cf->find("promiscuous")))
|
||||
promiscuous = false;
|
||||
else
|
||||
promiscuous = *x_cf;
|
||||
|
||||
ptr<proxy> pr = proxy::open(*pr_cf, promiscuous);
|
||||
if (!pr || pr.is_null() == true) {
|
||||
ptr<proxy> pr = proxy::open(*pr_cf);
|
||||
|
||||
if (!pr) {
|
||||
logger::error() << "Configuration failed for proxy '" << (const std::string& )*pr_cf << "'";
|
||||
return false;
|
||||
}
|
||||
|
||||
@ -175,31 +89,11 @@ static bool configure(ptr<conf>& cf)
|
||||
pr->router(true);
|
||||
else
|
||||
pr->router(*x_cf);
|
||||
|
||||
if (!(x_cf = pr_cf->find("autowire")))
|
||||
pr->autowire(false);
|
||||
else
|
||||
pr->autowire(*x_cf);
|
||||
|
||||
if (!(x_cf = pr_cf->find("keepalive")))
|
||||
pr->keepalive(true);
|
||||
else
|
||||
pr->keepalive(*x_cf);
|
||||
|
||||
if (!(x_cf = pr_cf->find("retries")))
|
||||
pr->retries(3);
|
||||
else
|
||||
pr->retries(*x_cf);
|
||||
|
||||
if (!(x_cf = pr_cf->find("ttl")))
|
||||
pr->ttl(30000);
|
||||
else
|
||||
pr->ttl(*x_cf);
|
||||
|
||||
if (!(x_cf = pr_cf->find("deadtime")))
|
||||
pr->deadtime(pr->ttl());
|
||||
else
|
||||
pr->deadtime(*x_cf);
|
||||
|
||||
if (!(x_cf = pr_cf->find("timeout")))
|
||||
pr->timeout(500);
|
||||
@ -213,78 +107,44 @@ static bool configure(ptr<conf>& cf)
|
||||
for (r_it = rules.begin(); r_it != rules.end(); r_it++) {
|
||||
ptr<conf> ru_cf =* r_it;
|
||||
|
||||
address addr(*ru_cf);
|
||||
|
||||
bool autovia = false;
|
||||
if (!(x_cf = ru_cf->find("autovia")))
|
||||
autovia = false;
|
||||
else
|
||||
autovia = *x_cf;
|
||||
if (ru_cf->empty()) {
|
||||
logger::error() << "'rule' is missing an IPv6 address/net";
|
||||
return false;
|
||||
}
|
||||
|
||||
if (x_cf = ru_cf->find("iface"))
|
||||
{
|
||||
ptr<iface> ifa = iface::open_ifd(*x_cf);
|
||||
if (!ifa || ifa.is_null() == true) {
|
||||
return false;
|
||||
address addr(*ru_cf);
|
||||
|
||||
if (x_cf = ru_cf->find("iface")) {
|
||||
if ((const std::string& )*x_cf == "") {
|
||||
logger::error() << "'iface' expected an interface name";
|
||||
} else {
|
||||
pr->add_rule(addr, iface::open_ifd(*x_cf));
|
||||
}
|
||||
|
||||
ifa->add_parent(pr);
|
||||
|
||||
myrules.push_back(pr->add_rule(addr, ifa, autovia));
|
||||
} else if (ru_cf->find("auto")) {
|
||||
myrules.push_back(pr->add_rule(addr, true));
|
||||
pr->add_rule(addr, true);
|
||||
} else {
|
||||
myrules.push_back(pr->add_rule(addr, false));
|
||||
if (!ru_cf->find("static")) {
|
||||
logger::warning()
|
||||
<< "## I'm going for 'static' since you didn't specify any method. Please fix this" << logger::endl
|
||||
<< "## as it's not going to be supported in future versions of ndppd. (See 'man ndppd.conf')";
|
||||
}
|
||||
|
||||
if (addr.prefix() <= 120) {
|
||||
logger::warning()
|
||||
<< "Low prefix length (" << addr.prefix() << " <= 120) when using 'static' method";
|
||||
}
|
||||
|
||||
pr->add_rule(addr, false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Print out all the topology
|
||||
for (std::map<std::string, weak_ptr<iface> >::iterator i_it = iface::_map.begin(); i_it != iface::_map.end(); i_it++) {
|
||||
ptr<iface> ifa = i_it->second;
|
||||
|
||||
logger::debug() << "iface " << ifa->name() << " {";
|
||||
|
||||
for (std::list<weak_ptr<proxy> >::iterator pit = ifa->serves_begin(); pit != ifa->serves_end(); pit++) {
|
||||
ptr<proxy> pr = (*pit);
|
||||
if (!pr) continue;
|
||||
|
||||
logger::debug() << " " << "proxy " << logger::format("%x", pr.get_pointer()) << " {";
|
||||
|
||||
for (std::list<ptr<rule> >::iterator rit = pr->rules_begin(); rit != pr->rules_end(); rit++) {
|
||||
ptr<rule> ru = *rit;
|
||||
|
||||
logger::debug() << " " << "rule " << logger::format("%x", ru.get_pointer()) << " {";
|
||||
logger::debug() << " " << "taddr " << ru->addr()<< ";";
|
||||
if (ru->is_auto())
|
||||
logger::debug() << " " << "auto;";
|
||||
else if (!ru->daughter())
|
||||
logger::debug() << " " << "static;";
|
||||
else
|
||||
logger::debug() << " " << "iface " << ru->daughter()->name() << ";";
|
||||
logger::debug() << " }";
|
||||
}
|
||||
|
||||
logger::debug() << " }";
|
||||
}
|
||||
|
||||
logger::debug() << " " << "parents {";
|
||||
for (std::list<weak_ptr<proxy> >::iterator pit = ifa->parents_begin(); pit != ifa->parents_end(); pit++) {
|
||||
ptr<proxy> pr = (*pit);
|
||||
|
||||
logger::debug() << " " << "parent " << logger::format("%x", pr.get_pointer()) << ";";
|
||||
}
|
||||
logger::debug() << " }";
|
||||
|
||||
logger::debug() << "}";
|
||||
}
|
||||
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool running = true;
|
||||
bool running = true;
|
||||
|
||||
static void exit_ndppd(int sig)
|
||||
void exit_ndppd(int sig)
|
||||
{
|
||||
logger::error() << "Shutting down...";
|
||||
running = 0;
|
||||
@ -341,26 +201,15 @@ int main(int argc, char* argv[], char* env[])
|
||||
}
|
||||
}
|
||||
|
||||
logger::notice()
|
||||
<< "ndppd (NDP Proxy Daemon) version " NDPPD_VERSION << logger::endl
|
||||
<< "Using configuration file '" << config_path << "'";
|
||||
|
||||
// Load configuration.
|
||||
|
||||
ptr<conf> cf = load_config(config_path);
|
||||
if (cf.is_null())
|
||||
return -1;
|
||||
|
||||
if (daemon) {
|
||||
logger::syslog(true);
|
||||
|
||||
if (daemonize() < 0)
|
||||
if (daemonize() < 0) {
|
||||
logger::error() << "Failed to daemonize process";
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
if (!configure(cf))
|
||||
return -1;
|
||||
|
||||
if (!pidfile.empty()) {
|
||||
std::ofstream pf;
|
||||
pf.open(pidfile.c_str(), std::ios::out | std::ios::trunc);
|
||||
@ -368,16 +217,23 @@ int main(int argc, char* argv[], char* env[])
|
||||
pf.close();
|
||||
}
|
||||
|
||||
logger::notice()
|
||||
<< "ndppd (NDP Proxy Daemon) version " NDPPD_VERSION << logger::endl
|
||||
<< "Using configuration file '" << config_path << "'";
|
||||
|
||||
// Load configuration.
|
||||
|
||||
if (!configure(config_path))
|
||||
return -1;
|
||||
|
||||
//route::load("/proc/net/ipv6_route");
|
||||
|
||||
// Time stuff.
|
||||
|
||||
struct timeval t1, t2;
|
||||
|
||||
gettimeofday(&t1, 0);
|
||||
|
||||
#ifdef WITH_ND_NETLINK
|
||||
netlink_setup();
|
||||
#endif
|
||||
|
||||
while (running) {
|
||||
if (iface::poll_all() < 0) {
|
||||
if (running) {
|
||||
@ -396,19 +252,10 @@ int main(int argc, char* argv[], char* env[])
|
||||
t1.tv_sec = t2.tv_sec;
|
||||
t1.tv_usec = t2.tv_usec;
|
||||
|
||||
if (rule::any_auto())
|
||||
route::update(elapsed_time);
|
||||
|
||||
if (rule::any_iface())
|
||||
address::update(elapsed_time);
|
||||
|
||||
route::update(elapsed_time);
|
||||
session::update_all(elapsed_time);
|
||||
}
|
||||
|
||||
#ifdef WITH_ND_NETLINK
|
||||
netlink_teardown();
|
||||
#endif
|
||||
|
||||
logger::notice() << "Bye";
|
||||
|
||||
return 0;
|
||||
|
@ -21,7 +21,7 @@
|
||||
#define NDPPD_NS_BEGIN namespace ndppd {
|
||||
#define NDPPD_NS_END }
|
||||
|
||||
#define NDPPD_VERSION "0.2.4"
|
||||
#define NDPPD_VERSION "0.2.3"
|
||||
|
||||
#include <assert.h>
|
||||
|
||||
@ -35,4 +35,3 @@
|
||||
#include "proxy.h"
|
||||
#include "session.h"
|
||||
#include "rule.h"
|
||||
#include "nd-netlink.h"
|
||||
|
219
src/proxy.cc
219
src/proxy.cc
@ -26,88 +26,72 @@
|
||||
#include "session.h"
|
||||
|
||||
NDPPD_NS_BEGIN
|
||||
|
||||
static address all_nodes = address("ff02::1");
|
||||
|
||||
|
||||
std::list<ptr<proxy> > proxy::_list;
|
||||
|
||||
proxy::proxy() :
|
||||
_router(true), _ttl(30000), _deadtime(3000), _timeout(500), _autowire(false), _keepalive(true), _promiscuous(false), _retries(3)
|
||||
_router(true), _ttl(30000), _timeout(500)
|
||||
{
|
||||
}
|
||||
|
||||
ptr<proxy> proxy::find_aunt(const std::string& ifname, const address& taddr)
|
||||
{
|
||||
for (std::list<ptr<proxy> >::iterator sit = _list.begin();
|
||||
sit != _list.end(); sit++)
|
||||
{
|
||||
ptr<proxy> pr = (*sit);
|
||||
|
||||
bool has_addr = false;
|
||||
for (std::list<ptr<rule> >::iterator it = pr->_rules.begin(); it != pr->_rules.end(); it++) {
|
||||
ptr<rule> ru = *it;
|
||||
|
||||
if (ru->addr() == taddr) {
|
||||
has_addr = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (has_addr == false) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (pr->ifa() && pr->ifa()->name() == ifname)
|
||||
return pr;
|
||||
}
|
||||
|
||||
return ptr<proxy>();
|
||||
}
|
||||
|
||||
ptr<proxy> proxy::create(const ptr<iface>& ifa, bool promiscuous)
|
||||
ptr<proxy> proxy::create(const ptr<iface>& ifa)
|
||||
{
|
||||
ptr<proxy> pr(new proxy());
|
||||
pr->_ptr = pr;
|
||||
pr->_ifa = ifa;
|
||||
pr->_promiscuous = promiscuous;
|
||||
|
||||
_list.push_back(pr);
|
||||
|
||||
ifa->add_serves(pr);
|
||||
ifa->pr(pr);
|
||||
|
||||
logger::debug() << "proxy::create() if=" << ifa->name();
|
||||
|
||||
return pr;
|
||||
}
|
||||
|
||||
ptr<proxy> proxy::open(const std::string& ifname, bool promiscuous)
|
||||
ptr<proxy> proxy::open(const std::string& ifname)
|
||||
{
|
||||
ptr<iface> ifa = iface::open_pfd(ifname, promiscuous);
|
||||
ptr<iface> ifa = iface::open_pfd(ifname);
|
||||
|
||||
if (!ifa) {
|
||||
return ptr<proxy>();
|
||||
}
|
||||
|
||||
return create(ifa, promiscuous);
|
||||
return create(ifa);
|
||||
}
|
||||
|
||||
ptr<session> proxy::find_or_create_session(const address& taddr)
|
||||
void proxy::handle_solicit(const address& saddr, const address& daddr,
|
||||
const address& taddr)
|
||||
{
|
||||
logger::debug()
|
||||
<< "proxy::handle_solicit() saddr=" << saddr.to_string()
|
||||
<< ", taddr=" << taddr.to_string();
|
||||
|
||||
// Let's check this proxy's list of sessions to see if we can
|
||||
// find one with the same target address.
|
||||
|
||||
for (std::list<ptr<session> >::iterator sit = _sessions.begin();
|
||||
sit != _sessions.end(); sit++) {
|
||||
|
||||
if ((*sit)->taddr() == taddr)
|
||||
return (*sit);
|
||||
|
||||
if ((*sit)->taddr() == taddr) {
|
||||
switch ((*sit)->status()) {
|
||||
case session::WAITING:
|
||||
case session::INVALID:
|
||||
break;
|
||||
|
||||
case session::VALID:
|
||||
(*sit)->send_advert();
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
ptr<session> se;
|
||||
|
||||
|
||||
// Since we couldn't find a session that matched, we'll try to find
|
||||
// a matching rule instead, and then set up a new session.
|
||||
|
||||
|
||||
ptr<session> se;
|
||||
|
||||
for (std::list<ptr<rule> >::iterator it = _rules.begin();
|
||||
it != _rules.end(); it++) {
|
||||
ptr<rule> ru = *it;
|
||||
@ -116,9 +100,9 @@ ptr<session> proxy::find_or_create_session(const address& taddr)
|
||||
|
||||
if (ru->addr() == taddr) {
|
||||
if (!se) {
|
||||
se = session::create(_ptr, taddr, _autowire, _keepalive, _retries);
|
||||
se = session::create(_ptr, saddr, daddr, taddr);
|
||||
}
|
||||
|
||||
|
||||
if (ru->is_auto()) {
|
||||
ptr<route> rt = route::find(taddr);
|
||||
|
||||
@ -127,100 +111,30 @@ ptr<session> proxy::find_or_create_session(const address& taddr)
|
||||
} else {
|
||||
ptr<iface> ifa = rt->ifa();
|
||||
|
||||
if (ifa && (ifa != ru->daughter())) {
|
||||
if (ifa && (ifa != ru->ifa())) {
|
||||
se->add_iface(ifa);
|
||||
}
|
||||
}
|
||||
} else if (!ru->daughter()) {
|
||||
} else if (!ru->ifa()) {
|
||||
// This rule doesn't have an interface, and thus we'll consider
|
||||
// it "static" and immediately send the response.
|
||||
se->handle_advert();
|
||||
return se;
|
||||
|
||||
return;
|
||||
} else {
|
||||
|
||||
ptr<iface> ifa = ru->daughter();
|
||||
se->add_iface(ifa);
|
||||
|
||||
#ifdef WITH_ND_NETLINK
|
||||
if (if_addr_find(ifa->name(), &taddr.const_addr())) {
|
||||
logger::debug() << "Sending NA out " << ifa->name();
|
||||
se->add_iface(_ifa);
|
||||
se->handle_advert();
|
||||
}
|
||||
#endif
|
||||
se->add_iface((*it)->ifa());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if (se) {
|
||||
_sessions.push_back(se);
|
||||
}
|
||||
|
||||
return se;
|
||||
}
|
||||
|
||||
void proxy::handle_advert(const address& saddr, const address& taddr, const std::string& ifname, bool use_via)
|
||||
{
|
||||
// If a session exists then process the advert in the context of the session
|
||||
for (std::list<ptr<session> >::iterator s_it = _sessions.begin();
|
||||
s_it != _sessions.end(); s_it++)
|
||||
{
|
||||
const ptr<session> sess = *s_it;
|
||||
|
||||
if ((sess->taddr() == taddr)) {
|
||||
sess->handle_advert(saddr, ifname, use_via);
|
||||
}
|
||||
se->send_solicit();
|
||||
}
|
||||
}
|
||||
|
||||
void proxy::handle_stateless_advert(const address& saddr, const address& taddr, const std::string& ifname, bool use_via)
|
||||
{
|
||||
logger::debug()
|
||||
<< "proxy::handle_stateless_advert() proxy=" << (ifa() ? ifa()->name() : "null") << ", taddr=" << taddr.to_string() << ", ifname=" << ifname;
|
||||
|
||||
ptr<session> se = find_or_create_session(taddr);
|
||||
if (!se) return;
|
||||
|
||||
if (_autowire == true && se->status() == session::WAITING) {
|
||||
se->handle_auto_wire(saddr, ifname, use_via);
|
||||
}
|
||||
}
|
||||
|
||||
void proxy::handle_solicit(const address& saddr, const address& taddr, const std::string& ifname)
|
||||
{
|
||||
logger::debug()
|
||||
<< "proxy::handle_solicit()";
|
||||
|
||||
// Otherwise find or create a session to scan for this address
|
||||
ptr<session> se = find_or_create_session(taddr);
|
||||
if (!se) return;
|
||||
|
||||
// Touching the session will cause an NDP advert to be transmitted to all
|
||||
// the daughters
|
||||
se->touch();
|
||||
|
||||
// If our session is confirmed then we can respoond with an advert otherwise
|
||||
// subscribe so that if it does become active we can notify everyone
|
||||
if (saddr != taddr) {
|
||||
switch (se->status()) {
|
||||
case session::WAITING:
|
||||
case session::INVALID:
|
||||
se->add_pending(saddr);
|
||||
break;
|
||||
|
||||
case session::VALID:
|
||||
case session::RENEWING:
|
||||
se->send_advert(saddr);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ptr<rule> proxy::add_rule(const address& addr, const ptr<iface>& ifa, bool autovia)
|
||||
ptr<rule> proxy::add_rule(const address& addr, const ptr<iface>& ifa)
|
||||
{
|
||||
ptr<rule> ru(rule::create(_ptr, addr, ifa));
|
||||
ru->autovia(autovia);
|
||||
_rules.push_back(ru);
|
||||
return ru;
|
||||
}
|
||||
@ -232,16 +146,6 @@ ptr<rule> proxy::add_rule(const address& addr, bool aut)
|
||||
return ru;
|
||||
}
|
||||
|
||||
std::list<ptr<rule> >::iterator proxy::rules_begin()
|
||||
{
|
||||
return _rules.begin();
|
||||
}
|
||||
|
||||
std::list<ptr<rule> >::iterator proxy::rules_end()
|
||||
{
|
||||
return _rules.end();
|
||||
}
|
||||
|
||||
void proxy::remove_session(const ptr<session>& se)
|
||||
{
|
||||
_sessions.remove(se);
|
||||
@ -252,11 +156,6 @@ const ptr<iface>& proxy::ifa() const
|
||||
return _ifa;
|
||||
}
|
||||
|
||||
bool proxy::promiscuous() const
|
||||
{
|
||||
return _promiscuous;
|
||||
}
|
||||
|
||||
bool proxy::router() const
|
||||
{
|
||||
return _router;
|
||||
@ -267,36 +166,6 @@ void proxy::router(bool val)
|
||||
_router = val;
|
||||
}
|
||||
|
||||
bool proxy::autowire() const
|
||||
{
|
||||
return _autowire;
|
||||
}
|
||||
|
||||
void proxy::autowire(bool val)
|
||||
{
|
||||
_autowire = val;
|
||||
}
|
||||
|
||||
int proxy::retries() const
|
||||
{
|
||||
return _retries;
|
||||
}
|
||||
|
||||
void proxy::retries(int val)
|
||||
{
|
||||
_retries = val;
|
||||
}
|
||||
|
||||
bool proxy::keepalive() const
|
||||
{
|
||||
return _keepalive;
|
||||
}
|
||||
|
||||
void proxy::keepalive(bool val)
|
||||
{
|
||||
_keepalive = val;
|
||||
}
|
||||
|
||||
int proxy::ttl() const
|
||||
{
|
||||
return _ttl;
|
||||
@ -307,16 +176,6 @@ void proxy::ttl(int val)
|
||||
_ttl = (val >= 0) ? val : 30000;
|
||||
}
|
||||
|
||||
int proxy::deadtime() const
|
||||
{
|
||||
return _deadtime;
|
||||
}
|
||||
|
||||
void proxy::deadtime(int val)
|
||||
{
|
||||
_deadtime = (val >= 0) ? val : 30000;
|
||||
}
|
||||
|
||||
int proxy::timeout() const
|
||||
{
|
||||
return _timeout;
|
||||
|
53
src/proxy.h
53
src/proxy.h
@ -29,50 +29,25 @@ class iface;
|
||||
class rule;
|
||||
|
||||
class proxy {
|
||||
public:
|
||||
static ptr<proxy> create(const ptr<iface>& ifa, bool promiscuous);
|
||||
|
||||
static ptr<proxy> find_aunt(const std::string& ifname, const address& taddr);
|
||||
public:
|
||||
static ptr<proxy> create(const ptr<iface>& ifa);
|
||||
|
||||
static ptr<proxy> open(const std::string& ifn, bool promiscuous);
|
||||
|
||||
ptr<session> find_or_create_session(const address& taddr);
|
||||
|
||||
void handle_advert(const address& saddr, const address& taddr, const std::string& ifname, bool use_via);
|
||||
|
||||
void handle_stateless_advert(const address& saddr, const address& taddr, const std::string& ifname, bool use_via);
|
||||
|
||||
void handle_solicit(const address& saddr, const address& taddr, const std::string& ifname);
|
||||
static ptr<proxy> open(const std::string& ifn);
|
||||
|
||||
void handle_solicit(const address& saddr, const address& daddr,
|
||||
const address& taddr);
|
||||
|
||||
void remove_session(const ptr<session>& se);
|
||||
|
||||
ptr<rule> add_rule(const address& addr, const ptr<iface>& ifa, bool autovia);
|
||||
ptr<rule> add_rule(const address& addr, const ptr<iface>& ifa);
|
||||
|
||||
ptr<rule> add_rule(const address& addr, bool aut = false);
|
||||
|
||||
std::list<ptr<rule> >::iterator rules_begin();
|
||||
|
||||
std::list<ptr<rule> >::iterator rules_end();
|
||||
|
||||
const ptr<iface>& ifa() const;
|
||||
|
||||
bool promiscuous() const;
|
||||
|
||||
bool router() const;
|
||||
|
||||
void router(bool val);
|
||||
|
||||
bool autowire() const;
|
||||
|
||||
void autowire(bool val);
|
||||
|
||||
int retries() const;
|
||||
|
||||
void retries(int val);
|
||||
|
||||
bool keepalive() const;
|
||||
|
||||
void keepalive(bool val);
|
||||
|
||||
int timeout() const;
|
||||
|
||||
@ -81,10 +56,6 @@ public:
|
||||
int ttl() const;
|
||||
|
||||
void ttl(int val);
|
||||
|
||||
int deadtime() const;
|
||||
|
||||
void deadtime(int val);
|
||||
|
||||
private:
|
||||
static std::list<ptr<proxy> > _list;
|
||||
@ -96,18 +67,10 @@ private:
|
||||
std::list<ptr<rule> > _rules;
|
||||
|
||||
std::list<ptr<session> > _sessions;
|
||||
|
||||
bool _promiscuous;
|
||||
|
||||
bool _router;
|
||||
|
||||
bool _autowire;
|
||||
|
||||
int _retries;
|
||||
|
||||
bool _keepalive;
|
||||
|
||||
int _ttl, _deadtime, _timeout;
|
||||
int _ttl, _timeout;
|
||||
|
||||
proxy();
|
||||
};
|
||||
|
@ -70,8 +70,6 @@ protected:
|
||||
|
||||
void acquire(void* ptr)
|
||||
{
|
||||
if (!ptr) return;
|
||||
|
||||
_ref = new ptr_ref();
|
||||
_ref->ptr = (T*)ptr;
|
||||
_ref->wc = !!_weak;
|
||||
|
@ -81,8 +81,6 @@ std::string route::token(const char* str)
|
||||
|
||||
void route::load(const std::string& path)
|
||||
{
|
||||
// Hack to make sure the interfaces are not freed prematurely.
|
||||
std::list<ptr<route> > tmp_routes(_routes);
|
||||
_routes.clear();
|
||||
|
||||
logger::debug() << "reading routes";
|
||||
@ -105,19 +103,19 @@ void route::load(const std::string& path)
|
||||
|
||||
unsigned char pfx;
|
||||
|
||||
if (route::hexdec(buf, (unsigned char* )&addr.addr(), 16) != 16) {
|
||||
if (hexdec(buf, (unsigned char* )&addr.addr(), 16) != 16) {
|
||||
// TODO: Warn here?
|
||||
continue;
|
||||
}
|
||||
|
||||
if (route::hexdec(buf + 33,& pfx, 1) != 1) {
|
||||
if (hexdec(buf + 33,& pfx, 1) != 1) {
|
||||
// TODO: Warn here?
|
||||
continue;
|
||||
}
|
||||
|
||||
addr.prefix((int)pfx);
|
||||
|
||||
route::create(addr, route::token(buf + 141));
|
||||
route::create(addr, token(buf + 141));
|
||||
}
|
||||
} catch (std::ifstream::failure e) {
|
||||
logger::warning() << "Failed to parse IPv6 routing data from '" << path << "'";
|
||||
|
12
src/route.h
12
src/route.h
@ -44,12 +44,6 @@ public:
|
||||
const address& addr() const;
|
||||
|
||||
ptr<iface> ifa();
|
||||
|
||||
route(const address& addr, const std::string& ifname);
|
||||
|
||||
static size_t hexdec(const char* str, unsigned char* buf, size_t size);
|
||||
|
||||
static std::string token(const char* str);
|
||||
|
||||
private:
|
||||
static int _ttl;
|
||||
@ -62,8 +56,14 @@ private:
|
||||
|
||||
ptr<iface> _ifa;
|
||||
|
||||
static size_t hexdec(const char* str, unsigned char* buf, size_t size);
|
||||
|
||||
static std::string token(const char* str);
|
||||
|
||||
static std::list<ptr<route> > _routes;
|
||||
|
||||
route(const address& addr, const std::string& ifname);
|
||||
|
||||
};
|
||||
|
||||
NDPPD_NS_END
|
||||
|
57
src/rule.cc
57
src/rule.cc
@ -16,7 +16,6 @@
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <net/if.h>
|
||||
|
||||
#include "ndppd.h"
|
||||
#include "rule.h"
|
||||
@ -25,14 +24,6 @@
|
||||
|
||||
NDPPD_NS_BEGIN
|
||||
|
||||
std::vector<interface> interfaces;
|
||||
|
||||
bool rule::_any_aut = false;
|
||||
|
||||
bool rule::_any_iface = false;
|
||||
|
||||
bool rule::_any_static = false;
|
||||
|
||||
rule::rule()
|
||||
{
|
||||
}
|
||||
@ -42,22 +33,11 @@ ptr<rule> rule::create(const ptr<proxy>& pr, const address& addr, const ptr<ifac
|
||||
ptr<rule> ru(new rule());
|
||||
ru->_ptr = ru;
|
||||
ru->_pr = pr;
|
||||
ru->_daughter = ifa;
|
||||
ru->_ifa = ifa;
|
||||
ru->_addr = addr;
|
||||
ru->_aut = false;
|
||||
_any_iface = true;
|
||||
unsigned int ifindex;
|
||||
|
||||
ifindex = if_nametoindex(pr->ifa()->name().c_str());
|
||||
#ifdef WITH_ND_NETLINK
|
||||
if_add_to_list(ifindex, pr->ifa());
|
||||
#endif
|
||||
ifindex = if_nametoindex(ifa->name().c_str());
|
||||
#ifdef WITH_ND_NETLINK
|
||||
if_add_to_list(ifindex, ifa);
|
||||
#endif
|
||||
|
||||
logger::debug() << "rule::create() if=" << pr->ifa()->name() << ", slave=" << ifa->name() << ", addr=" << addr;
|
||||
logger::debug() << "rule::create() if=" << pr->ifa()->name() << ", addr=" << addr;
|
||||
|
||||
return ru;
|
||||
}
|
||||
@ -69,10 +49,6 @@ ptr<rule> rule::create(const ptr<proxy>& pr, const address& addr, bool aut)
|
||||
ru->_pr = pr;
|
||||
ru->_addr = addr;
|
||||
ru->_aut = aut;
|
||||
_any_aut = _any_aut || aut;
|
||||
|
||||
if (aut == false)
|
||||
_any_static = true;
|
||||
|
||||
logger::debug()
|
||||
<< "rule::create() if=" << pr->ifa()->name().c_str() << ", addr=" << addr
|
||||
@ -86,9 +62,9 @@ const address& rule::addr() const
|
||||
return _addr;
|
||||
}
|
||||
|
||||
ptr<iface> rule::daughter() const
|
||||
ptr<iface> rule::ifa() const
|
||||
{
|
||||
return _daughter;
|
||||
return _ifa;
|
||||
}
|
||||
|
||||
bool rule::is_auto() const
|
||||
@ -96,31 +72,6 @@ bool rule::is_auto() const
|
||||
return _aut;
|
||||
}
|
||||
|
||||
bool rule::autovia() const
|
||||
{
|
||||
return _autovia;
|
||||
}
|
||||
|
||||
void rule::autovia(bool val)
|
||||
{
|
||||
_autovia = val;
|
||||
}
|
||||
|
||||
bool rule::any_auto()
|
||||
{
|
||||
return _any_aut;
|
||||
}
|
||||
|
||||
bool rule::any_iface()
|
||||
{
|
||||
return _any_iface;
|
||||
}
|
||||
|
||||
bool rule::any_static()
|
||||
{
|
||||
return _any_static;
|
||||
}
|
||||
|
||||
bool rule::check(const address& addr) const
|
||||
{
|
||||
return _addr == addr;
|
||||
|
38
src/rule.h
38
src/rule.h
@ -18,7 +18,6 @@
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <map>
|
||||
#include <list>
|
||||
|
||||
#include <sys/poll.h>
|
||||
|
||||
@ -37,57 +36,24 @@ public:
|
||||
|
||||
const address& addr() const;
|
||||
|
||||
ptr<iface> daughter() const;
|
||||
ptr<iface> ifa() const;
|
||||
|
||||
bool is_auto() const;
|
||||
|
||||
bool check(const address& addr) const;
|
||||
|
||||
static bool any_auto();
|
||||
|
||||
static bool any_static();
|
||||
|
||||
static bool any_iface();
|
||||
|
||||
bool autovia() const;
|
||||
|
||||
void autovia(bool val);
|
||||
|
||||
private:
|
||||
weak_ptr<rule> _ptr;
|
||||
|
||||
weak_ptr<proxy> _pr;
|
||||
|
||||
ptr<iface> _daughter;
|
||||
ptr<iface> _ifa;
|
||||
|
||||
address _addr;
|
||||
|
||||
bool _aut;
|
||||
|
||||
static bool _any_aut;
|
||||
|
||||
static bool _any_static;
|
||||
|
||||
static bool _any_iface;
|
||||
|
||||
bool _autovia;
|
||||
|
||||
rule();
|
||||
};
|
||||
|
||||
class interface {
|
||||
public:
|
||||
// List of IPv6 addresses on this interface
|
||||
std::list<address> addresses;
|
||||
|
||||
// Index of this interface
|
||||
int ifindex;
|
||||
|
||||
// Name of this interface.
|
||||
std::string _name;
|
||||
|
||||
};
|
||||
|
||||
extern std::vector<interface> interfaces;
|
||||
|
||||
NDPPD_NS_END
|
||||
|
275
src/session.cc
275
src/session.cc
@ -14,7 +14,6 @@
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
#include <algorithm>
|
||||
#include <sstream>
|
||||
|
||||
#include "ndppd.h"
|
||||
#include "proxy.h"
|
||||
@ -25,8 +24,6 @@ NDPPD_NS_BEGIN
|
||||
|
||||
std::list<weak_ptr<session> > session::_sessions;
|
||||
|
||||
static address all_nodes = address("ff02::1");
|
||||
|
||||
void session::update_all(int elapsed_time)
|
||||
{
|
||||
for (std::list<weak_ptr<session> >::iterator it = _sessions.begin();
|
||||
@ -43,54 +40,10 @@ void session::update_all(int elapsed_time)
|
||||
}
|
||||
|
||||
switch (se->_status) {
|
||||
|
||||
case session::WAITING:
|
||||
if (se->_fails < se->_retries) {
|
||||
logger::debug() << "session will keep trying [taddr=" << se->_taddr << "]";
|
||||
|
||||
se->_ttl = se->_pr->timeout();
|
||||
se->_fails++;
|
||||
|
||||
// Send another solicit
|
||||
se->send_solicit();
|
||||
} else {
|
||||
|
||||
logger::debug() << "session is now invalid [taddr=" << se->_taddr << "]";
|
||||
|
||||
se->_status = session::INVALID;
|
||||
se->_ttl = se->_pr->deadtime();
|
||||
}
|
||||
break;
|
||||
|
||||
case session::RENEWING:
|
||||
logger::debug() << "session is became invalid [taddr=" << se->_taddr << "]";
|
||||
|
||||
if (se->_fails < se->_retries) {
|
||||
se->_ttl = se->_pr->timeout();
|
||||
se->_fails++;
|
||||
|
||||
// Send another solicit
|
||||
se->send_solicit();
|
||||
} else {
|
||||
se->_pr->remove_session(se);
|
||||
}
|
||||
break;
|
||||
|
||||
case session::VALID:
|
||||
if (se->touched() == true ||
|
||||
se->keepalive() == true)
|
||||
{
|
||||
logger::debug() << "session is renewing [taddr=" << se->_taddr << "]";
|
||||
se->_status = session::RENEWING;
|
||||
se->_ttl = se->_pr->timeout();
|
||||
se->_fails = 0;
|
||||
se->_touched = false;
|
||||
|
||||
// Send another solicit to make sure the route is still valid
|
||||
se->send_solicit();
|
||||
} else {
|
||||
se->_pr->remove_session(se);
|
||||
}
|
||||
logger::debug() << "session is now invalid";
|
||||
se->_status = session::INVALID;
|
||||
se->_ttl = se->_pr->ttl();
|
||||
break;
|
||||
|
||||
default:
|
||||
@ -102,34 +55,30 @@ void session::update_all(int elapsed_time)
|
||||
session::~session()
|
||||
{
|
||||
logger::debug() << "session::~session() this=" << logger::format("%x", this);
|
||||
|
||||
if (_wired == true) {
|
||||
for (std::list<ptr<iface> >::iterator it = _ifaces.begin();
|
||||
|
||||
for (std::list<ptr<iface> >::iterator it = _ifaces.begin();
|
||||
it != _ifaces.end(); it++) {
|
||||
handle_auto_unwire((*it)->name());
|
||||
}
|
||||
(*it)->remove_session(_ptr);
|
||||
}
|
||||
}
|
||||
|
||||
ptr<session> session::create(const ptr<proxy>& pr, const address& taddr, bool auto_wire, bool keepalive, int retries)
|
||||
ptr<session> session::create(const ptr<proxy>& pr, const address& saddr,
|
||||
const address& daddr, const address& taddr)
|
||||
{
|
||||
ptr<session> se(new session());
|
||||
|
||||
se->_ptr = se;
|
||||
se->_pr = pr;
|
||||
se->_taddr = taddr;
|
||||
se->_autowire = auto_wire;
|
||||
se->_keepalive = keepalive;
|
||||
se->_retries = retries;
|
||||
se->_wired = false;
|
||||
se->_ttl = pr->ttl();
|
||||
se->_touched = false;
|
||||
se->_ptr = se;
|
||||
se->_pr = pr;
|
||||
se->_saddr = saddr;
|
||||
se->_taddr = taddr;
|
||||
se->_daddr = daddr;
|
||||
se->_ttl = pr->timeout();
|
||||
|
||||
_sessions.push_back(se);
|
||||
|
||||
logger::debug()
|
||||
<< "session::create() pr=" << logger::format("%x", (proxy* )pr) << ", proxy=" << ((pr->ifa()) ? pr->ifa()->name() : "null")
|
||||
<< ", taddr=" << taddr << " =" << logger::format("%x", (session* )se);
|
||||
<< "session::create() pr=" << logger::format("%x", (proxy* )pr) << ", saddr=" << saddr
|
||||
<< ", daddr=" << daddr << ", taddr=" << taddr << " =" << logger::format("%x", (session* )se);
|
||||
|
||||
return se;
|
||||
}
|
||||
@ -139,19 +88,10 @@ void session::add_iface(const ptr<iface>& ifa)
|
||||
if (std::find(_ifaces.begin(), _ifaces.end(), ifa) != _ifaces.end())
|
||||
return;
|
||||
|
||||
ifa->add_session(_ptr);
|
||||
_ifaces.push_back(ifa);
|
||||
}
|
||||
|
||||
void session::add_pending(const address& addr)
|
||||
{
|
||||
for (std::list<ptr<address> >::iterator ad = _pending.begin(); ad != _pending.end(); ad++) {
|
||||
if (addr == (*ad))
|
||||
return;
|
||||
}
|
||||
|
||||
_pending.push_back(new address(addr));
|
||||
}
|
||||
|
||||
void session::send_solicit()
|
||||
{
|
||||
logger::debug() << "session::send_solicit() (_ifaces.size() = " << _ifaces.size() << ")";
|
||||
@ -163,162 +103,17 @@ void session::send_solicit()
|
||||
}
|
||||
}
|
||||
|
||||
void session::touch()
|
||||
void session::send_advert()
|
||||
{
|
||||
if (_touched == false)
|
||||
{
|
||||
_touched = true;
|
||||
|
||||
if (status() == session::WAITING || status() == session::INVALID) {
|
||||
_ttl = _pr->timeout();
|
||||
|
||||
logger::debug() << "session is now probing [taddr=" << _taddr << "]";
|
||||
|
||||
send_solicit();
|
||||
}
|
||||
}
|
||||
_pr->ifa()->write_advert(_saddr, _taddr, _pr->router());
|
||||
}
|
||||
|
||||
void session::send_advert(const address& daddr)
|
||||
{
|
||||
_pr->ifa()->write_advert(daddr, _taddr, _pr->router());
|
||||
}
|
||||
|
||||
void session::handle_auto_wire(const address& saddr, const std::string& ifname, bool use_via)
|
||||
{
|
||||
if (_wired == true && (_wired_via.is_empty() || _wired_via == saddr))
|
||||
return;
|
||||
|
||||
logger::debug()
|
||||
<< "session::handle_auto_wire() taddr=" << _taddr << ", ifname=" << ifname;
|
||||
|
||||
if (use_via == true &&
|
||||
_taddr != saddr &&
|
||||
saddr.is_unicast() == true &&
|
||||
saddr.is_multicast() == false)
|
||||
{
|
||||
std::stringstream route_cmd;
|
||||
route_cmd << "ip";
|
||||
route_cmd << " " << "-6";
|
||||
route_cmd << " " << "route";
|
||||
route_cmd << " " << "replace";
|
||||
route_cmd << " " << std::string(saddr);
|
||||
route_cmd << " " << "dev";
|
||||
route_cmd << " " << ifname;
|
||||
|
||||
logger::debug()
|
||||
<< "session::system(" << route_cmd.str() << ")";
|
||||
|
||||
system(route_cmd.str().c_str());
|
||||
|
||||
_wired_via = saddr;
|
||||
}
|
||||
else
|
||||
_wired_via.reset();
|
||||
|
||||
{
|
||||
std::stringstream route_cmd;
|
||||
route_cmd << "ip";
|
||||
route_cmd << " " << "-6";
|
||||
route_cmd << " " << "route";
|
||||
route_cmd << " " << "replace";
|
||||
route_cmd << " " << std::string(_taddr);
|
||||
if (_wired_via.is_empty() == false) {
|
||||
route_cmd << " " << "via";
|
||||
route_cmd << " " << std::string(_wired_via);
|
||||
}
|
||||
route_cmd << " " << "dev";
|
||||
route_cmd << " " << ifname;
|
||||
|
||||
logger::debug()
|
||||
<< "session::system(" << route_cmd.str() << ")";
|
||||
|
||||
system(route_cmd.str().c_str());
|
||||
}
|
||||
|
||||
_wired = true;
|
||||
}
|
||||
|
||||
void session::handle_auto_unwire(const std::string& ifname)
|
||||
{
|
||||
logger::debug()
|
||||
<< "session::handle_auto_unwire() taddr=" << _taddr << ", ifname=" << ifname;
|
||||
|
||||
{
|
||||
std::stringstream route_cmd;
|
||||
route_cmd << "ip";
|
||||
route_cmd << " " << "-6";
|
||||
route_cmd << " " << "route";
|
||||
route_cmd << " " << "flush";
|
||||
route_cmd << " " << std::string(_taddr);
|
||||
if (_wired_via.is_empty() == false) {
|
||||
route_cmd << " " << "via";
|
||||
route_cmd << " " << std::string(_wired_via);
|
||||
}
|
||||
route_cmd << " " << "dev";
|
||||
route_cmd << " " << ifname;
|
||||
|
||||
logger::debug()
|
||||
<< "session::system(" << route_cmd.str() << ")";
|
||||
|
||||
system(route_cmd.str().c_str());
|
||||
}
|
||||
|
||||
if (_wired_via.is_empty() == false) {
|
||||
std::stringstream route_cmd;
|
||||
route_cmd << "ip";
|
||||
route_cmd << " " << "-6";
|
||||
route_cmd << " " << "route";
|
||||
route_cmd << " " << "flush";
|
||||
route_cmd << " " << std::string(_wired_via);
|
||||
route_cmd << " " << "dev";
|
||||
route_cmd << " " << ifname;
|
||||
|
||||
logger::debug()
|
||||
<< "session::system(" << route_cmd.str() << ")";
|
||||
|
||||
system(route_cmd.str().c_str());
|
||||
}
|
||||
|
||||
_wired = false;
|
||||
_wired_via.reset();
|
||||
}
|
||||
|
||||
void session::handle_advert(const address& saddr, const std::string& ifname, bool use_via)
|
||||
{
|
||||
if (_autowire == true && _status == WAITING) {
|
||||
handle_auto_wire(saddr, ifname, use_via);
|
||||
}
|
||||
|
||||
handle_advert();
|
||||
}
|
||||
|
||||
|
||||
void session::handle_advert()
|
||||
{
|
||||
logger::debug()
|
||||
<< "session::handle_advert() taddr=" << _taddr << ", ttl=" << _pr->ttl();
|
||||
|
||||
if (_status != VALID) {
|
||||
_status = VALID;
|
||||
|
||||
logger::debug() << "session is active [taddr=" << _taddr << "]";
|
||||
}
|
||||
|
||||
_status = VALID;
|
||||
_ttl = _pr->ttl();
|
||||
_fails = 0;
|
||||
|
||||
if (!_pending.empty()) {
|
||||
for (std::list<ptr<address> >::iterator ad = _pending.begin();
|
||||
ad != _pending.end(); ad++) {
|
||||
ptr<address> addr = (*ad);
|
||||
logger::debug() << " - forward to " << addr;
|
||||
|
||||
send_advert(addr);
|
||||
}
|
||||
|
||||
_pending.clear();
|
||||
}
|
||||
send_advert();
|
||||
}
|
||||
|
||||
const address& session::taddr() const
|
||||
@ -326,34 +121,14 @@ const address& session::taddr() const
|
||||
return _taddr;
|
||||
}
|
||||
|
||||
bool session::autowire() const
|
||||
const address& session::saddr() const
|
||||
{
|
||||
return _autowire;
|
||||
return _saddr;
|
||||
}
|
||||
|
||||
bool session::keepalive() const
|
||||
const address& session::daddr() const
|
||||
{
|
||||
return _keepalive;
|
||||
}
|
||||
|
||||
int session::retries() const
|
||||
{
|
||||
return _retries;
|
||||
}
|
||||
|
||||
int session::fails() const
|
||||
{
|
||||
return _fails;
|
||||
}
|
||||
|
||||
bool session::wired() const
|
||||
{
|
||||
return _wired;
|
||||
}
|
||||
|
||||
bool session::touched() const
|
||||
{
|
||||
return _touched;
|
||||
return _daddr;
|
||||
}
|
||||
|
||||
int session::status() const
|
||||
|
@ -16,7 +16,6 @@
|
||||
#pragma once
|
||||
|
||||
#include <vector>
|
||||
#include <string>
|
||||
|
||||
#include "ndppd.h"
|
||||
|
||||
@ -32,30 +31,14 @@ private:
|
||||
weak_ptr<proxy> _pr;
|
||||
|
||||
address _saddr, _daddr, _taddr;
|
||||
|
||||
bool _autowire;
|
||||
|
||||
bool _keepalive;
|
||||
|
||||
bool _wired;
|
||||
|
||||
address _wired_via;
|
||||
|
||||
bool _touched;
|
||||
|
||||
// An array of interfaces this session is monitoring for
|
||||
// ND_NEIGHBOR_ADVERT on.
|
||||
std::list<ptr<iface> > _ifaces;
|
||||
|
||||
std::list<ptr<address> > _pending;
|
||||
|
||||
// The remaining time in miliseconds the object will stay in the
|
||||
// interface's session array or cache.
|
||||
int _ttl;
|
||||
|
||||
int _fails;
|
||||
|
||||
int _retries;
|
||||
|
||||
int _status;
|
||||
|
||||
@ -64,10 +47,9 @@ private:
|
||||
public:
|
||||
enum
|
||||
{
|
||||
WAITING, // Waiting for an advert response.
|
||||
RENEWING, // Renewing;
|
||||
VALID, // Valid;
|
||||
INVALID // Invalid;
|
||||
WAITING, // Waiting for an advert response.
|
||||
VALID, // Valid;
|
||||
INVALID // Invalid;
|
||||
};
|
||||
|
||||
static void update_all(int elapsed_time);
|
||||
@ -75,45 +57,24 @@ public:
|
||||
// Destructor.
|
||||
~session();
|
||||
|
||||
static ptr<session> create(const ptr<proxy>& pr, const address& taddr, bool autowire, bool keepalive, int retries);
|
||||
static ptr<session> create(const ptr<proxy>& pr, const address& saddr,
|
||||
const address& daddr, const address& taddr);
|
||||
|
||||
void add_iface(const ptr<iface>& ifa);
|
||||
|
||||
void add_pending(const address& addr);
|
||||
|
||||
const address& taddr() const;
|
||||
|
||||
const address& daddr() const;
|
||||
|
||||
const address& saddr() const;
|
||||
|
||||
bool autowire() const;
|
||||
|
||||
int retries() const;
|
||||
|
||||
int fails() const;
|
||||
|
||||
bool keepalive() const;
|
||||
|
||||
bool wired() const;
|
||||
|
||||
bool touched() const;
|
||||
|
||||
int status() const;
|
||||
|
||||
void status(int val);
|
||||
|
||||
|
||||
void handle_advert();
|
||||
|
||||
void handle_advert(const address& saddr, const std::string& ifname, bool use_via);
|
||||
|
||||
void handle_auto_wire(const address& saddr, const std::string& ifname, bool use_via);
|
||||
|
||||
void handle_auto_unwire(const std::string& ifname);
|
||||
|
||||
void touch();
|
||||
|
||||
void send_advert(const address& daddr);
|
||||
void send_advert();
|
||||
|
||||
void send_solicit();
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user