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>
|
2012-09-21 Daniel Adolfsson <daniel@priv.nu>
|
||||||
|
|
||||||
* Version 0.2.3
|
* Version 0.2.3
|
||||||
@ -72,7 +10,7 @@
|
|||||||
|
|
||||||
* New "auto" configuration to detect outgoing interface, for forwarding
|
* New "auto" configuration to detect outgoing interface, for forwarding
|
||||||
Neighbor Solicitation Messages.
|
Neighbor Solicitation Messages.
|
||||||
|
|
||||||
* Improved logging.
|
* Improved logging.
|
||||||
|
|
||||||
* Bug fixes related to memory management.
|
* Bug fixes related to memory management.
|
||||||
|
19
Makefile
19
Makefile
@ -9,17 +9,11 @@ CXX ?= g++
|
|||||||
GZIP ?= /bin/gzip
|
GZIP ?= /bin/gzip
|
||||||
MANDIR ?= ${DESTDIR}${PREFIX}/share/man
|
MANDIR ?= ${DESTDIR}${PREFIX}/share/man
|
||||||
SBINDIR ?= ${DESTDIR}${PREFIX}/sbin
|
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 \
|
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
|
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
|
|
||||||
|
|
||||||
all: ndppd ndppd.1.gz ndppd.conf.5.gz
|
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
|
${GZIP} < ndppd.conf.5 > ndppd.conf.5.gz
|
||||||
|
|
||||||
ndppd: ${OBJS}
|
ndppd: ${OBJS}
|
||||||
${CXX} -o ndppd ${LDFLAGS} ${OBJS} ${LIBS}
|
${CXX} -o ndppd ${LDFLAGS} ${LIBS} ${OBJS}
|
||||||
|
|
||||||
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`
|
|
||||||
|
|
||||||
.cc.o:
|
.cc.o:
|
||||||
${CXX} -c ${CPPFLAGS} $(CXXFLAGS) -o $@ $<
|
${CXX} -c $(CXXFLAGS) -o $@ $<
|
||||||
|
|
||||||
clean:
|
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
|
ndppd - NDP Proxy Daemon
|
||||||
|
|
||||||
Version 0.2.5
|
Version 0.2.2
|
||||||
|
|
||||||
------------------------------------------------------------------------
|
------------------------------------------------------------------------
|
||||||
1. Legal
|
1. Legal
|
||||||
------------------------------------------------------------------------
|
------------------------------------------------------------------------
|
||||||
|
|
||||||
ndppd - NDP Proxy Daemon
|
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
|
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
|
it under the terms of the GNU General Public License as published by
|
||||||
the Free Software Foundation, either version 3 of the License, or
|
the Free Software Foundation, either version 3 of the License, or
|
||||||
(at your option) any later version.
|
(at your option) any later version.
|
||||||
|
|
||||||
This program is distributed in the hope that it will be useful,
|
This program is distributed in the hope that it will be useful,
|
||||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
GNU General Public License for more details.
|
GNU General Public License for more details.
|
||||||
|
|
||||||
You should have received a copy of the GNU General Public License
|
You should have received a copy of the GNU General Public License
|
||||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
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:
|
If you want to enable debugging, you can type:
|
||||||
|
|
||||||
make DEBUG=1 all
|
make DEBUG=1 all
|
||||||
|
|
||||||
Note that this version of the binary is much bigger, and the daemon
|
Note that this version of the binary is much bigger, and the daemon
|
||||||
produces a lot of messages.
|
produces a lot of messages.
|
||||||
|
|
||||||
@ -101,8 +101,8 @@
|
|||||||
5. Usage
|
5. Usage
|
||||||
------------------------------------------------------------------------
|
------------------------------------------------------------------------
|
||||||
|
|
||||||
Read through 'ndppd.conf-dist' for guidelines and examples how to
|
Read through 'ndppd.conf.example' for guidelines how to configure
|
||||||
configure the daemon.
|
the daemon.
|
||||||
|
|
||||||
Usage: ndppd [-d] [-c <config>] [-p <pidfile>]
|
Usage: ndppd [-d] [-c <config>] [-p <pidfile>]
|
||||||
|
|
||||||
@ -115,7 +115,7 @@
|
|||||||
|
|
||||||
-d Daemonize the process, putting it in the background.
|
-d Daemonize the process, putting it in the background.
|
||||||
Also enables syslogging.
|
Also enables syslogging.
|
||||||
|
|
||||||
-v Increase logging verbosity. Can be used several times in
|
-v Increase logging verbosity. Can be used several times in
|
||||||
order to increase even further.
|
order to increase even further.
|
||||||
|
|
||||||
@ -125,9 +125,10 @@
|
|||||||
|
|
||||||
Contact : Daniel Adolfsson <daniel@priv.nu>
|
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,
|
If you want to report a bug, you can either send me a mail directly,
|
||||||
or submit an issue on github.com.
|
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
|
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>
|
# proxy <interface>
|
||||||
# This sets up a listener, that will listen for any Neighbor Solicitation
|
# 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).
|
# 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'.
|
# invalidating the entry, in milliseconds. Default value is '500'.
|
||||||
|
|
||||||
timeout 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>
|
# ttl <integer>
|
||||||
# Controls how long a valid or invalid entry remains in the cache, in
|
# Controls how long a valid or invalid entry remains in the cache, in
|
||||||
@ -91,13 +55,6 @@ proxy eth0 {
|
|||||||
|
|
||||||
auto
|
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
|
# 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
|
# method, it defaulted to 'static'. For compatibility reasons we choose
|
||||||
# to keep this behavior - for now (it may be removed in a future version).
|
# 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
|
.B ndppd
|
||||||
will cache an entry. This is in milliseconds, and the default value
|
will cache an entry. This is in milliseconds, and the default value
|
||||||
is 30000 (30 seconds).
|
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>"
|
.IP "timeout <value>"
|
||||||
Controls how long
|
Controls how long
|
||||||
.B ndppd
|
.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/>.
|
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
#include <fstream>
|
|
||||||
#include <list>
|
|
||||||
#include <map>
|
#include <map>
|
||||||
|
|
||||||
#include <cstring>
|
#include <cstring>
|
||||||
@ -29,16 +27,9 @@
|
|||||||
|
|
||||||
#include "ndppd.h"
|
#include "ndppd.h"
|
||||||
#include "address.h"
|
#include "address.h"
|
||||||
#include "route.h"
|
|
||||||
|
|
||||||
NDPPD_NS_BEGIN
|
NDPPD_NS_BEGIN
|
||||||
|
|
||||||
std::list<ptr<route> > address::_addresses;
|
|
||||||
|
|
||||||
int address::_ttl;
|
|
||||||
|
|
||||||
int address::_c_ttl;
|
|
||||||
|
|
||||||
address::address()
|
address::address()
|
||||||
{
|
{
|
||||||
reset();
|
reset();
|
||||||
@ -57,19 +48,6 @@ address::address(const address& addr)
|
|||||||
_mask.s6_addr32[3] = addr._mask.s6_addr32[3];
|
_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)
|
address::address(const std::string& str)
|
||||||
{
|
{
|
||||||
parse_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]));
|
((_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()
|
void address::reset()
|
||||||
{
|
{
|
||||||
_addr.s6_addr32[0] = 0;
|
_addr.s6_addr32[0] = 0;
|
||||||
@ -336,93 +299,7 @@ bool address::is_multicast() const
|
|||||||
|
|
||||||
bool address::is_unicast() 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;
|
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
|
NDPPD_NS_END
|
||||||
|
@ -16,7 +16,6 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <list>
|
|
||||||
#include <netinet/ip6.h>
|
#include <netinet/ip6.h>
|
||||||
|
|
||||||
#include "ndppd.h"
|
#include "ndppd.h"
|
||||||
@ -25,24 +24,15 @@ NDPPD_NS_BEGIN
|
|||||||
|
|
||||||
class iface;
|
class iface;
|
||||||
|
|
||||||
class route;
|
|
||||||
|
|
||||||
class address {
|
class address {
|
||||||
public:
|
public:
|
||||||
address();
|
address();
|
||||||
address(const address& addr);
|
address(const address& addr);
|
||||||
address(const ptr<address>& addr);
|
|
||||||
address(const std::string& str);
|
address(const std::string& str);
|
||||||
address(const char* str);
|
address(const char* str);
|
||||||
address(const in6_addr& addr);
|
address(const in6_addr& addr);
|
||||||
address(const in6_addr& addr, const in6_addr& mask);
|
address(const in6_addr& addr, const in6_addr& mask);
|
||||||
address(const in6_addr& addr, int prefix);
|
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();
|
struct in6_addr& addr();
|
||||||
|
|
||||||
@ -56,8 +46,6 @@ public:
|
|||||||
bool operator!=(const address& addr) const;
|
bool operator!=(const address& addr) const;
|
||||||
|
|
||||||
void reset();
|
void reset();
|
||||||
|
|
||||||
bool is_empty() const;
|
|
||||||
|
|
||||||
const std::string to_string() const;
|
const std::string to_string() const;
|
||||||
|
|
||||||
@ -72,22 +60,8 @@ public:
|
|||||||
bool is_multicast() const;
|
bool is_multicast() const;
|
||||||
|
|
||||||
operator std::string() 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:
|
private:
|
||||||
static int _ttl;
|
|
||||||
|
|
||||||
static int _c_ttl;
|
|
||||||
|
|
||||||
static std::list<ptr<route> > _addresses;
|
|
||||||
|
|
||||||
struct in6_addr _addr, _mask;
|
struct in6_addr _addr, _mask;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
371
src/iface.cc
371
src/iface.cc
@ -34,13 +34,11 @@
|
|||||||
|
|
||||||
#include <linux/filter.h>
|
#include <linux/filter.h>
|
||||||
|
|
||||||
#include <errno.h>
|
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
#include <map>
|
#include <map>
|
||||||
|
|
||||||
#include "ndppd.h"
|
#include "ndppd.h"
|
||||||
#include "route.h"
|
|
||||||
|
|
||||||
NDPPD_NS_BEGIN
|
NDPPD_NS_BEGIN
|
||||||
|
|
||||||
@ -66,19 +64,13 @@ iface::~iface()
|
|||||||
if (_prev_allmulti >= 0) {
|
if (_prev_allmulti >= 0) {
|
||||||
allmulti(_prev_allmulti);
|
allmulti(_prev_allmulti);
|
||||||
}
|
}
|
||||||
if (_prev_promiscuous >= 0) {
|
|
||||||
promiscuous(_prev_promiscuous);
|
|
||||||
}
|
|
||||||
close(_pfd);
|
close(_pfd);
|
||||||
}
|
}
|
||||||
|
|
||||||
_map_dirty = true;
|
_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;
|
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.
|
// Bail if it's* not* ND_NEIGHBOR_SOLICIT.
|
||||||
BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, ND_NEIGHBOR_SOLICIT, 0, 1),
|
BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, ND_NEIGHBOR_SOLICIT, 0, 1),
|
||||||
// Keep packet.
|
// Keep packet.
|
||||||
BPF_STMT(BPF_RET | BPF_K, (u_int32_t)-1),
|
BPF_STMT(BPF_RET | BPF_K, -1),
|
||||||
// Drop packet.
|
// Drop packet.
|
||||||
BPF_STMT(BPF_RET | BPF_K, 0)
|
BPF_STMT(BPF_RET | BPF_K, 0)
|
||||||
};
|
};
|
||||||
@ -176,13 +168,6 @@ ptr<iface> iface::open_pfd(const std::string& name, bool promiscuous)
|
|||||||
|
|
||||||
// Eh. Allmulti.
|
// Eh. Allmulti.
|
||||||
ifa->_prev_allmulti = ifa->allmulti(1);
|
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;
|
_map_dirty = true;
|
||||||
|
|
||||||
@ -227,29 +212,23 @@ ptr<iface> iface::open_ifd(const std::string& name)
|
|||||||
|
|
||||||
if (ioctl(fd, SIOCGIFHWADDR,& ifr) < 0) {
|
if (ioctl(fd, SIOCGIFHWADDR,& ifr) < 0) {
|
||||||
close(fd);
|
close(fd);
|
||||||
logger::error()
|
logger::error() << "Failed to detect link-layer address for interface '" << name << "'";
|
||||||
<< "Failed to detect link-layer address for interface '"
|
|
||||||
<< name << "'";
|
|
||||||
return ptr<iface>();
|
return ptr<iface>();
|
||||||
}
|
}
|
||||||
|
|
||||||
logger::debug()
|
logger::debug() << "fd=" << fd << ", hwaddr=" << ether_ntoa((const struct ether_addr* )&ifr.ifr_hwaddr.sa_data);;
|
||||||
<< "fd=" << fd << ", hwaddr="
|
|
||||||
<< ether_ntoa((const struct ether_addr* )&ifr.ifr_hwaddr.sa_data);
|
|
||||||
|
|
||||||
// Set max hops.
|
// Set max hops.
|
||||||
|
|
||||||
int hops = 255;
|
int hops = 255;
|
||||||
|
|
||||||
if (setsockopt(fd, IPPROTO_IPV6, IPV6_MULTICAST_HOPS, &hops,
|
if (setsockopt(fd, IPPROTO_IPV6, IPV6_MULTICAST_HOPS,& hops, sizeof(hops)) < 0) {
|
||||||
sizeof(hops)) < 0) {
|
|
||||||
close(fd);
|
close(fd);
|
||||||
logger::error() << "iface::open_ifd() failed IPV6_MULTICAST_HOPS";
|
logger::error() << "iface::open_ifd() failed IPV6_MULTICAST_HOPS";
|
||||||
return ptr<iface>();
|
return ptr<iface>();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (setsockopt(fd, IPPROTO_IPV6, IPV6_UNICAST_HOPS, &hops,
|
if (setsockopt(fd, IPPROTO_IPV6, IPV6_UNICAST_HOPS,& hops, sizeof(hops)) < 0) {
|
||||||
sizeof(hops)) < 0) {
|
|
||||||
close(fd);
|
close(fd);
|
||||||
logger::error() << "iface::open_ifd() failed IPV6_UNICAST_HOPS";
|
logger::error() << "iface::open_ifd() failed IPV6_UNICAST_HOPS";
|
||||||
return ptr<iface>();
|
return ptr<iface>();
|
||||||
@ -259,11 +238,9 @@ ptr<iface> iface::open_ifd(const std::string& name)
|
|||||||
|
|
||||||
int on = 1;
|
int on = 1;
|
||||||
|
|
||||||
if (ioctl(fd, FIONBIO, (char*)&on) < 0) {
|
if (ioctl(fd, FIONBIO, (char* )&on) < 0) {
|
||||||
close(fd);
|
close(fd);
|
||||||
logger::error()
|
logger::error() << "Failed to switch to non-blocking on interface '" << name << "'";
|
||||||
<< "Failed to switch to non-blocking on interface '"
|
|
||||||
<< name << "'";
|
|
||||||
return ptr<iface>();
|
return ptr<iface>();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -271,7 +248,7 @@ ptr<iface> iface::open_ifd(const std::string& name)
|
|||||||
|
|
||||||
struct icmp6_filter filter;
|
struct icmp6_filter filter;
|
||||||
ICMP6_FILTER_SETBLOCKALL(&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) {
|
if (setsockopt(fd, IPPROTO_ICMPV6, ICMP6_FILTER,& filter, sizeof(filter)) < 0) {
|
||||||
logger::error() << "Failed to set filter";
|
logger::error() << "Failed to set filter";
|
||||||
@ -301,7 +278,7 @@ ptr<iface> iface::open_ifd(const std::string& name)
|
|||||||
return ifa;
|
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 msghdr mhdr;
|
||||||
struct iovec iov;
|
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));
|
memset(&mhdr, 0, sizeof(mhdr));
|
||||||
mhdr.msg_name = (caddr_t)saddr;
|
mhdr.msg_name = (caddr_t)saddr;
|
||||||
mhdr.msg_namelen = saddr_size;
|
mhdr.msg_namelen = sizeof(struct sockaddr);
|
||||||
mhdr.msg_iov =& iov;
|
mhdr.msg_iov =& iov;
|
||||||
mhdr.msg_iovlen = 1;
|
mhdr.msg_iovlen = 1;
|
||||||
|
|
||||||
if ((len = recvmsg(fd,& mhdr, 0)) < 0)
|
if ((len = recvmsg(fd,& mhdr, 0)) < 0)
|
||||||
{
|
|
||||||
logger::error() << "iface::read() failed! error=" << logger::err() << ", ifa=" << name();
|
|
||||||
return -1;
|
return -1;
|
||||||
}
|
|
||||||
|
|
||||||
logger::debug() << "iface::read() ifa=" << name() << ", len=" << len;
|
|
||||||
|
|
||||||
if (len < sizeof(struct icmp6_hdr))
|
if (len < sizeof(struct icmp6_hdr))
|
||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
|
logger::debug() << "iface::read() len=" << len;
|
||||||
|
|
||||||
return 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_iov =& iov;
|
||||||
mhdr.msg_iovlen = 1;
|
mhdr.msg_iovlen = 1;
|
||||||
|
|
||||||
logger::debug() << "iface::write() ifa=" << name() << ", daddr=" << daddr.to_string() << ", len="
|
logger::debug() << "iface::write() daddr=" << daddr.to_string() << ", len=" << size;
|
||||||
<< size;
|
|
||||||
|
|
||||||
int len;
|
int len;
|
||||||
|
|
||||||
if ((len = sendmsg(fd,& mhdr, 0)) < 0)
|
if ((len = sendmsg(fd,& mhdr, 0)) < 0)
|
||||||
{
|
|
||||||
logger::error() << "iface::write() failed! error=" << logger::err() << ", ifa=" << name() << ", daddr=" << daddr.to_string();
|
|
||||||
return -1;
|
return -1;
|
||||||
}
|
|
||||||
|
|
||||||
return len;
|
return len;
|
||||||
}
|
}
|
||||||
@ -373,28 +343,20 @@ ssize_t iface::read_solicit(address& saddr, address& daddr, address& taddr)
|
|||||||
uint8_t msg[256];
|
uint8_t msg[256];
|
||||||
ssize_t len;
|
ssize_t len;
|
||||||
|
|
||||||
if ((len = read(_pfd, (struct sockaddr*)&t_saddr, sizeof(struct sockaddr_ll), msg, sizeof(msg))) < 0) {
|
if ((len = read(_pfd, (struct sockaddr* )&t_saddr, msg, sizeof(msg))) < 0)
|
||||||
logger::warning() << "iface::read_solicit() failed: " << logger::err();
|
|
||||||
return -1;
|
return -1;
|
||||||
}
|
|
||||||
|
|
||||||
struct ip6_hdr* ip6h =
|
struct ip6_hdr* ip6h =
|
||||||
(struct ip6_hdr* )(msg + ETH_HLEN);
|
(struct ip6_hdr* )(msg + ETH_HLEN);
|
||||||
|
|
||||||
struct nd_neighbor_solicit* ns =
|
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;
|
taddr = ns->nd_ns_target;
|
||||||
daddr = ip6h->ip6_dst;
|
daddr = ip6h->ip6_dst;
|
||||||
saddr = ip6h->ip6_src;
|
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()
|
logger::debug() << "iface::read_solicit() saddr=" << saddr.to_string() << ", daddr=" << daddr.to_string() << ", len=" << len;
|
||||||
<< ", daddr=" << daddr.to_string() << ", taddr=" << taddr.to_string() << ", len=" << len;
|
|
||||||
|
|
||||||
return 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(&ns->nd_ns_target,& taddr.const_addr(), sizeof(struct in6_addr));
|
||||||
|
|
||||||
memcpy(buf + sizeof(struct nd_neighbor_solicit) + sizeof(struct nd_opt_hdr),
|
memcpy(buf + sizeof(struct nd_neighbor_solicit) + sizeof(struct nd_opt_hdr),& hwaddr, 6);
|
||||||
&hwaddr, 6);
|
|
||||||
|
|
||||||
// FIXME: Alright, I'm lazy.
|
// FIXME: Alright, I'm lazy.
|
||||||
static address multicast("ff02::1:ff00:0000");
|
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[14] = taddr.const_addr().s6_addr[14];
|
||||||
daddr.addr().s6_addr[15] = taddr.const_addr().s6_addr[15];
|
daddr.addr().s6_addr[15] = taddr.const_addr().s6_addr[15];
|
||||||
|
|
||||||
logger::debug() << "iface::write_solicit() taddr=" << taddr.to_string()
|
logger::debug() << "iface::write_solicit() taddr=" << taddr.to_string() << ", daddr=" << daddr.to_string();
|
||||||
<< ", daddr=" << daddr.to_string();
|
|
||||||
|
|
||||||
return write(_ifd, daddr, (uint8_t* )buf, sizeof(struct nd_neighbor_solicit)
|
return write(_ifd, daddr, (uint8_t* )buf, sizeof(struct nd_neighbor_solicit) + sizeof(struct nd_opt_hdr) + 6);
|
||||||
+ sizeof(struct nd_opt_hdr) + 6);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
ssize_t iface::write_advert(const address& daddr, const address& taddr, bool router)
|
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;
|
opt->nd_opt_len = 1;
|
||||||
|
|
||||||
na->nd_na_type = ND_NEIGHBOR_ADVERT;
|
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(&na->nd_na_target,& taddr.const_addr(), sizeof(struct in6_addr));
|
||||||
|
|
||||||
memcpy(buf + sizeof(struct nd_neighbor_advert) + sizeof(struct nd_opt_hdr),
|
memcpy(buf + sizeof(struct nd_neighbor_advert) + sizeof(struct nd_opt_hdr),& hwaddr, 6);
|
||||||
&hwaddr, 6);
|
|
||||||
|
|
||||||
logger::debug() << "iface::write_advert() daddr=" << daddr.to_string()
|
logger::debug() << "iface::write_advert() daddr=" << daddr.to_string() << ", taddr=" << taddr.to_string();
|
||||||
<< ", taddr=" << taddr.to_string();
|
|
||||||
|
|
||||||
return write(_ifd, daddr, (uint8_t* )buf, sizeof(struct nd_neighbor_advert) +
|
return write(_ifd, daddr, (uint8_t* )buf, sizeof(struct nd_neighbor_advert) +
|
||||||
sizeof(struct nd_opt_hdr) + 6);
|
sizeof(struct nd_opt_hdr) + 6);
|
||||||
@ -474,22 +431,11 @@ ssize_t iface::read_advert(address& saddr, address& taddr)
|
|||||||
struct sockaddr_in6 t_saddr;
|
struct sockaddr_in6 t_saddr;
|
||||||
uint8_t msg[256];
|
uint8_t msg[256];
|
||||||
ssize_t len;
|
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) {
|
if ((len = read(_ifd, (struct sockaddr* )&t_saddr, msg, sizeof(msg))) < 0)
|
||||||
logger::warning() << "iface::read_advert() failed: " << logger::err();
|
|
||||||
return -1;
|
return -1;
|
||||||
}
|
|
||||||
|
|
||||||
saddr = t_saddr.sin6_addr;
|
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)
|
if (((struct icmp6_hdr* )msg)->icmp6_type != ND_NEIGHBOR_ADVERT)
|
||||||
return -1;
|
return -1;
|
||||||
@ -501,79 +447,6 @@ ssize_t iface::read_advert(address& saddr, address& taddr)
|
|||||||
return len;
|
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()
|
void iface::fixup_pollfds()
|
||||||
{
|
{
|
||||||
_pollfds.resize(_map.size()* 2);
|
_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()
|
void iface::cleanup()
|
||||||
{
|
{
|
||||||
for (std::map<std::string, weak_ptr<iface> >::iterator it = _map.begin();
|
for (std::map<std::string, weak_ptr<iface> >::iterator it = _map.begin();
|
||||||
@ -625,7 +514,6 @@ int iface::poll_all()
|
|||||||
int len;
|
int len;
|
||||||
|
|
||||||
if ((len = ::poll(&_pollfds[0], _pollfds.size(), 50)) < 0) {
|
if ((len = ::poll(&_pollfds[0], _pollfds.size(), 50)) < 0) {
|
||||||
logger::error() << "Failed to poll interfaces: " << logger::err();
|
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -647,107 +535,43 @@ int iface::poll_all()
|
|||||||
|
|
||||||
bool is_pfd = i++ % 2;
|
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)) {
|
if (!(f_it->revents & POLLIN)) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ptr<iface> ifa = i_it->second;
|
||||||
|
|
||||||
address saddr, daddr, taddr;
|
address saddr, daddr, taddr;
|
||||||
ssize_t size;
|
|
||||||
|
|
||||||
if (is_pfd) {
|
if (is_pfd) {
|
||||||
size = ifa->read_solicit(saddr, daddr, taddr);
|
if (ifa->read_solicit(saddr, daddr, taddr) < 0) {
|
||||||
if (size < 0) {
|
|
||||||
logger::error() << "Failed to read from interface '%s'", ifa->_name.c_str();
|
logger::error() << "Failed to read from interface '%s'", ifa->_name.c_str();
|
||||||
continue;
|
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
|
if (!saddr.is_unicast() || !daddr.is_multicast()) {
|
||||||
bool handled = false;
|
continue;
|
||||||
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 it was not handled then write an error message
|
if (ifa->_pr) {
|
||||||
if (handled == false) {
|
ifa->_pr->handle_solicit(saddr, daddr, taddr);
|
||||||
logger::debug() << " - solicit was ignored";
|
|
||||||
}
|
}
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
size = ifa->read_advert(saddr, taddr);
|
if (ifa->read_advert(saddr, taddr) < 0) {
|
||||||
if (size < 0) {
|
|
||||||
logger::error() << "Failed to read from interface '%s'", ifa->_name.c_str();
|
logger::error() << "Failed to read from interface '%s'", ifa->_name.c_str();
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if (size == 0) {
|
|
||||||
logger::debug() << "iface::read_advert() loopback received and ignored";
|
for (std::list<weak_ptr<session> >::iterator s_it = ifa->_sessions.begin();
|
||||||
continue;
|
s_it != ifa->_sessions.end(); s_it++) {
|
||||||
}
|
assert(!s_it->is_null());
|
||||||
|
|
||||||
// Process the NDP advert
|
const ptr<session> sess = *s_it;
|
||||||
bool handled = false;
|
|
||||||
for (std::list<weak_ptr<proxy> >::iterator pit = ifa->parents_begin(); pit != ifa->parents_end(); pit++) {
|
if ((sess->taddr() == taddr) && (sess->status() == session::WAITING)) {
|
||||||
ptr<proxy> pr = (*pit);
|
sess->handle_advert();
|
||||||
if (!pr || !pr->ifa()) {
|
break;
|
||||||
continue;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// 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;
|
struct ifreq ifr;
|
||||||
|
|
||||||
logger::debug()
|
logger::debug() << "iface::allmulti() state=" << state << ", _name=\"" << _name << "\"";
|
||||||
<< "iface::allmulti() state="
|
|
||||||
<< state << ", _name=\"" << _name << "\"";
|
|
||||||
|
|
||||||
state = !!state;
|
state = !!state;
|
||||||
|
|
||||||
@ -770,11 +592,10 @@ int iface::allmulti(int state)
|
|||||||
strncpy(ifr.ifr_name, _name.c_str(), IFNAMSIZ);
|
strncpy(ifr.ifr_name, _name.c_str(), IFNAMSIZ);
|
||||||
|
|
||||||
if (ioctl(_pfd, SIOCGIFFLAGS, &ifr) < 0) {
|
if (ioctl(_pfd, SIOCGIFFLAGS, &ifr) < 0) {
|
||||||
logger::error() << "Failed to get allmulti: " << logger::err();
|
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
int old_state = !!(ifr.ifr_flags &IFF_ALLMULTI);
|
int old_state = !!(ifr.ifr_flags & IFF_ALLMULTI);
|
||||||
|
|
||||||
if (state == old_state) {
|
if (state == old_state) {
|
||||||
return old_state;
|
return old_state;
|
||||||
@ -787,46 +608,6 @@ int iface::allmulti(int state)
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (ioctl(_pfd, SIOCSIFFLAGS, &ifr) < 0) {
|
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;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -838,34 +619,14 @@ const std::string& iface::name() const
|
|||||||
return _name;
|
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();
|
return _pr;
|
||||||
}
|
|
||||||
|
|
||||||
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();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
NDPPD_NS_END
|
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_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();
|
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.
|
// Writes a NB_NEIGHBOR_SOLICIT message to the _ifd socket.
|
||||||
ssize_t write_solicit(const address& taddr);
|
ssize_t write_solicit(const address& taddr);
|
||||||
@ -57,31 +57,21 @@ public:
|
|||||||
|
|
||||||
// Reads a NB_NEIGHBOR_ADVERT message from the _ifd socket;
|
// Reads a NB_NEIGHBOR_ADVERT message from the _ifd socket;
|
||||||
ssize_t read_advert(address& saddr, address& taddr);
|
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.
|
// Returns the name of the interface.
|
||||||
const std::string& name() const;
|
const std::string& name() const;
|
||||||
|
|
||||||
std::list<weak_ptr<proxy> >::iterator serves_begin();
|
// Adds a session to be monitored for ND_NEIGHBOR_ADVERT messages.
|
||||||
|
void add_session(const ptr<session>& se);
|
||||||
std::list<weak_ptr<proxy> >::iterator serves_end();
|
|
||||||
|
void remove_session(const ptr<session>& se);
|
||||||
void add_serves(const ptr<proxy>& proxy);
|
|
||||||
|
void pr(const ptr<proxy>& pr);
|
||||||
std::list<weak_ptr<proxy> >::iterator parents_begin();
|
|
||||||
|
const ptr<proxy>& pr() const;
|
||||||
std::list<weak_ptr<proxy> >::iterator parents_end();
|
|
||||||
|
|
||||||
void add_parent(const ptr<proxy>& parent);
|
|
||||||
|
|
||||||
static std::map<std::string, weak_ptr<iface> > _map;
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
static std::map<std::string, weak_ptr<iface> > _map;
|
||||||
|
|
||||||
static bool _map_dirty;
|
static bool _map_dirty;
|
||||||
|
|
||||||
@ -106,16 +96,15 @@ private:
|
|||||||
|
|
||||||
// Previous state of ALLMULTI for the interface.
|
// Previous state of ALLMULTI for the interface.
|
||||||
int _prev_allmulti;
|
int _prev_allmulti;
|
||||||
|
|
||||||
// Previous state of PROMISC for the interface
|
|
||||||
int _prev_promiscuous;
|
|
||||||
|
|
||||||
// Name of this interface.
|
// Name of this interface.
|
||||||
std::string _name;
|
std::string _name;
|
||||||
|
|
||||||
std::list<weak_ptr<proxy> > _serves;
|
// An array of sessions that are monitoring this interface for
|
||||||
|
// ND_NEIGHBOR_ADVERT messages.
|
||||||
std::list<weak_ptr<proxy> > _parents;
|
std::list<weak_ptr<session> > _sessions;
|
||||||
|
|
||||||
|
weak_ptr<proxy> _pr;
|
||||||
|
|
||||||
// The link-layer address of this interface.
|
// The link-layer address of this interface.
|
||||||
struct ether_addr hwaddr;
|
struct ether_addr hwaddr;
|
||||||
@ -123,10 +112,6 @@ private:
|
|||||||
// Turns on/off ALLMULTI for this interface - returns the previous state
|
// Turns on/off ALLMULTI for this interface - returns the previous state
|
||||||
// or -1 if there was an error.
|
// or -1 if there was an error.
|
||||||
int allmulti(int state);
|
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.
|
// Constructor.
|
||||||
iface();
|
iface();
|
||||||
|
@ -18,7 +18,6 @@
|
|||||||
#include <cctype>
|
#include <cctype>
|
||||||
#include <cstdlib>
|
#include <cstdlib>
|
||||||
#include <cstring>
|
#include <cstring>
|
||||||
#include <cerrno>
|
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
#include <sstream>
|
#include <sstream>
|
||||||
|
|
||||||
@ -80,28 +79,6 @@ std::string logger::format(const std::string& fmt, ...)
|
|||||||
return buf;
|
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()
|
logger logger::error()
|
||||||
{
|
{
|
||||||
return logger(LOG_ERR);
|
return logger(LOG_ERR);
|
||||||
|
@ -71,10 +71,7 @@ public:
|
|||||||
static logger debug();
|
static logger debug();
|
||||||
static logger notice();
|
static logger notice();
|
||||||
|
|
||||||
static std::string err();
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
int _pri;
|
int _pri;
|
||||||
|
|
||||||
std::stringstream _ss;
|
std::stringstream _ss;
|
||||||
@ -92,9 +89,7 @@ private:
|
|||||||
|
|
||||||
static int _max_pri;
|
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
|
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 <getopt.h>
|
||||||
#include <sys/time.h>
|
#include <sys/time.h>
|
||||||
|
|
||||||
#include <sys/stat.h>
|
|
||||||
#include <sys/types.h>
|
#include <sys/types.h>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
|
|
||||||
@ -33,29 +32,20 @@
|
|||||||
|
|
||||||
using namespace ndppd;
|
using namespace ndppd;
|
||||||
|
|
||||||
static int daemonize()
|
int daemonize()
|
||||||
{
|
{
|
||||||
pid_t pid = fork();
|
pid_t pid = fork();
|
||||||
if (pid < 0) {
|
|
||||||
logger::error() << "Failed to fork during daemonize: " << logger::err();
|
if (pid < 0)
|
||||||
return -1;
|
return -1;
|
||||||
}
|
|
||||||
|
|
||||||
if (pid > 0)
|
if (pid > 0)
|
||||||
exit(0);
|
exit(0);
|
||||||
|
|
||||||
umask(0);
|
|
||||||
|
|
||||||
pid_t sid = setsid();
|
pid_t sid = setsid();
|
||||||
if (sid < 0) {
|
|
||||||
logger::error() << "Failed to setsid during daemonize: " << logger::err();
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (chdir("/") < 0) {
|
if (sid < 0)
|
||||||
logger::error() << "Failed to change path during daemonize: " << logger::err();
|
|
||||||
return -1;
|
return -1;
|
||||||
}
|
|
||||||
|
|
||||||
close(STDIN_FILENO);
|
close(STDIN_FILENO);
|
||||||
close(STDOUT_FILENO);
|
close(STDOUT_FILENO);
|
||||||
@ -64,12 +54,17 @@ static int daemonize()
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static ptr<conf> load_config(const std::string& path)
|
bool configure(const std::string& path)
|
||||||
{
|
{
|
||||||
ptr<conf> cf, x_cf;
|
ptr<conf> cf, x_cf;
|
||||||
|
|
||||||
if (!(cf = conf::load(path)))
|
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;
|
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()) {
|
if (pr_cf->empty()) {
|
||||||
logger::error() << "'proxy' section is missing interface name";
|
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;
|
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);
|
ptr<proxy> pr = proxy::open(*pr_cf);
|
||||||
if (!pr || pr.is_null() == true) {
|
|
||||||
|
if (!pr) {
|
||||||
|
logger::error() << "Configuration failed for proxy '" << (const std::string& )*pr_cf << "'";
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -175,31 +89,11 @@ static bool configure(ptr<conf>& cf)
|
|||||||
pr->router(true);
|
pr->router(true);
|
||||||
else
|
else
|
||||||
pr->router(*x_cf);
|
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")))
|
if (!(x_cf = pr_cf->find("ttl")))
|
||||||
pr->ttl(30000);
|
pr->ttl(30000);
|
||||||
else
|
else
|
||||||
pr->ttl(*x_cf);
|
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")))
|
if (!(x_cf = pr_cf->find("timeout")))
|
||||||
pr->timeout(500);
|
pr->timeout(500);
|
||||||
@ -213,78 +107,44 @@ static bool configure(ptr<conf>& cf)
|
|||||||
for (r_it = rules.begin(); r_it != rules.end(); r_it++) {
|
for (r_it = rules.begin(); r_it != rules.end(); r_it++) {
|
||||||
ptr<conf> ru_cf =* r_it;
|
ptr<conf> ru_cf =* r_it;
|
||||||
|
|
||||||
address addr(*ru_cf);
|
if (ru_cf->empty()) {
|
||||||
|
logger::error() << "'rule' is missing an IPv6 address/net";
|
||||||
bool autovia = false;
|
return false;
|
||||||
if (!(x_cf = ru_cf->find("autovia")))
|
}
|
||||||
autovia = false;
|
|
||||||
else
|
|
||||||
autovia = *x_cf;
|
|
||||||
|
|
||||||
if (x_cf = ru_cf->find("iface"))
|
address addr(*ru_cf);
|
||||||
{
|
|
||||||
ptr<iface> ifa = iface::open_ifd(*x_cf);
|
if (x_cf = ru_cf->find("iface")) {
|
||||||
if (!ifa || ifa.is_null() == true) {
|
if ((const std::string& )*x_cf == "") {
|
||||||
return false;
|
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")) {
|
} else if (ru_cf->find("auto")) {
|
||||||
myrules.push_back(pr->add_rule(addr, true));
|
pr->add_rule(addr, true);
|
||||||
} else {
|
} 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;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool running = true;
|
bool running = true;
|
||||||
|
|
||||||
static void exit_ndppd(int sig)
|
void exit_ndppd(int sig)
|
||||||
{
|
{
|
||||||
logger::error() << "Shutting down...";
|
logger::error() << "Shutting down...";
|
||||||
running = 0;
|
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) {
|
if (daemon) {
|
||||||
logger::syslog(true);
|
logger::syslog(true);
|
||||||
|
|
||||||
if (daemonize() < 0)
|
if (daemonize() < 0) {
|
||||||
|
logger::error() << "Failed to daemonize process";
|
||||||
return 1;
|
return 1;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!configure(cf))
|
|
||||||
return -1;
|
|
||||||
|
|
||||||
if (!pidfile.empty()) {
|
if (!pidfile.empty()) {
|
||||||
std::ofstream pf;
|
std::ofstream pf;
|
||||||
pf.open(pidfile.c_str(), std::ios::out | std::ios::trunc);
|
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();
|
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.
|
// Time stuff.
|
||||||
|
|
||||||
struct timeval t1, t2;
|
struct timeval t1, t2;
|
||||||
|
|
||||||
gettimeofday(&t1, 0);
|
gettimeofday(&t1, 0);
|
||||||
|
|
||||||
#ifdef WITH_ND_NETLINK
|
|
||||||
netlink_setup();
|
|
||||||
#endif
|
|
||||||
|
|
||||||
while (running) {
|
while (running) {
|
||||||
if (iface::poll_all() < 0) {
|
if (iface::poll_all() < 0) {
|
||||||
if (running) {
|
if (running) {
|
||||||
@ -396,19 +252,10 @@ int main(int argc, char* argv[], char* env[])
|
|||||||
t1.tv_sec = t2.tv_sec;
|
t1.tv_sec = t2.tv_sec;
|
||||||
t1.tv_usec = t2.tv_usec;
|
t1.tv_usec = t2.tv_usec;
|
||||||
|
|
||||||
if (rule::any_auto())
|
route::update(elapsed_time);
|
||||||
route::update(elapsed_time);
|
|
||||||
|
|
||||||
if (rule::any_iface())
|
|
||||||
address::update(elapsed_time);
|
|
||||||
|
|
||||||
session::update_all(elapsed_time);
|
session::update_all(elapsed_time);
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef WITH_ND_NETLINK
|
|
||||||
netlink_teardown();
|
|
||||||
#endif
|
|
||||||
|
|
||||||
logger::notice() << "Bye";
|
logger::notice() << "Bye";
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -21,7 +21,7 @@
|
|||||||
#define NDPPD_NS_BEGIN namespace ndppd {
|
#define NDPPD_NS_BEGIN namespace ndppd {
|
||||||
#define NDPPD_NS_END }
|
#define NDPPD_NS_END }
|
||||||
|
|
||||||
#define NDPPD_VERSION "0.2.4"
|
#define NDPPD_VERSION "0.2.3"
|
||||||
|
|
||||||
#include <assert.h>
|
#include <assert.h>
|
||||||
|
|
||||||
@ -35,4 +35,3 @@
|
|||||||
#include "proxy.h"
|
#include "proxy.h"
|
||||||
#include "session.h"
|
#include "session.h"
|
||||||
#include "rule.h"
|
#include "rule.h"
|
||||||
#include "nd-netlink.h"
|
|
||||||
|
219
src/proxy.cc
219
src/proxy.cc
@ -26,88 +26,72 @@
|
|||||||
#include "session.h"
|
#include "session.h"
|
||||||
|
|
||||||
NDPPD_NS_BEGIN
|
NDPPD_NS_BEGIN
|
||||||
|
|
||||||
static address all_nodes = address("ff02::1");
|
|
||||||
|
|
||||||
std::list<ptr<proxy> > proxy::_list;
|
std::list<ptr<proxy> > proxy::_list;
|
||||||
|
|
||||||
proxy::proxy() :
|
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)
|
ptr<proxy> proxy::create(const ptr<iface>& ifa)
|
||||||
{
|
|
||||||
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> pr(new proxy());
|
ptr<proxy> pr(new proxy());
|
||||||
pr->_ptr = pr;
|
pr->_ptr = pr;
|
||||||
pr->_ifa = ifa;
|
pr->_ifa = ifa;
|
||||||
pr->_promiscuous = promiscuous;
|
|
||||||
|
|
||||||
_list.push_back(pr);
|
_list.push_back(pr);
|
||||||
|
|
||||||
ifa->add_serves(pr);
|
ifa->pr(pr);
|
||||||
|
|
||||||
logger::debug() << "proxy::create() if=" << ifa->name();
|
logger::debug() << "proxy::create() if=" << ifa->name();
|
||||||
|
|
||||||
return pr;
|
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) {
|
if (!ifa) {
|
||||||
return ptr<proxy>();
|
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
|
// Let's check this proxy's list of sessions to see if we can
|
||||||
// find one with the same target address.
|
// find one with the same target address.
|
||||||
|
|
||||||
for (std::list<ptr<session> >::iterator sit = _sessions.begin();
|
for (std::list<ptr<session> >::iterator sit = _sessions.begin();
|
||||||
sit != _sessions.end(); sit++) {
|
sit != _sessions.end(); sit++) {
|
||||||
|
|
||||||
if ((*sit)->taddr() == taddr)
|
if ((*sit)->taddr() == taddr) {
|
||||||
return (*sit);
|
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
|
// 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.
|
// a matching rule instead, and then set up a new session.
|
||||||
|
|
||||||
|
ptr<session> se;
|
||||||
|
|
||||||
for (std::list<ptr<rule> >::iterator it = _rules.begin();
|
for (std::list<ptr<rule> >::iterator it = _rules.begin();
|
||||||
it != _rules.end(); it++) {
|
it != _rules.end(); it++) {
|
||||||
ptr<rule> ru = *it;
|
ptr<rule> ru = *it;
|
||||||
@ -116,9 +100,9 @@ ptr<session> proxy::find_or_create_session(const address& taddr)
|
|||||||
|
|
||||||
if (ru->addr() == taddr) {
|
if (ru->addr() == taddr) {
|
||||||
if (!se) {
|
if (!se) {
|
||||||
se = session::create(_ptr, taddr, _autowire, _keepalive, _retries);
|
se = session::create(_ptr, saddr, daddr, taddr);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ru->is_auto()) {
|
if (ru->is_auto()) {
|
||||||
ptr<route> rt = route::find(taddr);
|
ptr<route> rt = route::find(taddr);
|
||||||
|
|
||||||
@ -127,100 +111,30 @@ ptr<session> proxy::find_or_create_session(const address& taddr)
|
|||||||
} else {
|
} else {
|
||||||
ptr<iface> ifa = rt->ifa();
|
ptr<iface> ifa = rt->ifa();
|
||||||
|
|
||||||
if (ifa && (ifa != ru->daughter())) {
|
if (ifa && (ifa != ru->ifa())) {
|
||||||
se->add_iface(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
|
// This rule doesn't have an interface, and thus we'll consider
|
||||||
// it "static" and immediately send the response.
|
// it "static" and immediately send the response.
|
||||||
se->handle_advert();
|
se->handle_advert();
|
||||||
return se;
|
return;
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
|
se->add_iface((*it)->ifa());
|
||||||
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
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (se) {
|
if (se) {
|
||||||
_sessions.push_back(se);
|
_sessions.push_back(se);
|
||||||
}
|
se->send_solicit();
|
||||||
|
|
||||||
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);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void proxy::handle_stateless_advert(const address& saddr, const address& taddr, const std::string& ifname, bool use_via)
|
ptr<rule> proxy::add_rule(const address& addr, const ptr<iface>& ifa)
|
||||||
{
|
|
||||||
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> ru(rule::create(_ptr, addr, ifa));
|
ptr<rule> ru(rule::create(_ptr, addr, ifa));
|
||||||
ru->autovia(autovia);
|
|
||||||
_rules.push_back(ru);
|
_rules.push_back(ru);
|
||||||
return ru;
|
return ru;
|
||||||
}
|
}
|
||||||
@ -232,16 +146,6 @@ ptr<rule> proxy::add_rule(const address& addr, bool aut)
|
|||||||
return ru;
|
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)
|
void proxy::remove_session(const ptr<session>& se)
|
||||||
{
|
{
|
||||||
_sessions.remove(se);
|
_sessions.remove(se);
|
||||||
@ -252,11 +156,6 @@ const ptr<iface>& proxy::ifa() const
|
|||||||
return _ifa;
|
return _ifa;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool proxy::promiscuous() const
|
|
||||||
{
|
|
||||||
return _promiscuous;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool proxy::router() const
|
bool proxy::router() const
|
||||||
{
|
{
|
||||||
return _router;
|
return _router;
|
||||||
@ -267,36 +166,6 @@ void proxy::router(bool val)
|
|||||||
_router = 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
|
int proxy::ttl() const
|
||||||
{
|
{
|
||||||
return _ttl;
|
return _ttl;
|
||||||
@ -307,16 +176,6 @@ void proxy::ttl(int val)
|
|||||||
_ttl = (val >= 0) ? val : 30000;
|
_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
|
int proxy::timeout() const
|
||||||
{
|
{
|
||||||
return _timeout;
|
return _timeout;
|
||||||
|
53
src/proxy.h
53
src/proxy.h
@ -29,50 +29,25 @@ class iface;
|
|||||||
class rule;
|
class rule;
|
||||||
|
|
||||||
class proxy {
|
class proxy {
|
||||||
public:
|
public:
|
||||||
static ptr<proxy> create(const ptr<iface>& ifa, bool promiscuous);
|
static ptr<proxy> create(const ptr<iface>& ifa);
|
||||||
|
|
||||||
static ptr<proxy> find_aunt(const std::string& ifname, const address& taddr);
|
|
||||||
|
|
||||||
static ptr<proxy> open(const std::string& ifn, bool promiscuous);
|
static ptr<proxy> open(const std::string& ifn);
|
||||||
|
|
||||||
ptr<session> find_or_create_session(const address& taddr);
|
void handle_solicit(const address& saddr, const address& daddr,
|
||||||
|
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);
|
|
||||||
|
|
||||||
void remove_session(const ptr<session>& se);
|
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);
|
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;
|
const ptr<iface>& ifa() const;
|
||||||
|
|
||||||
bool promiscuous() const;
|
|
||||||
|
|
||||||
bool router() const;
|
bool router() const;
|
||||||
|
|
||||||
void router(bool val);
|
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;
|
int timeout() const;
|
||||||
|
|
||||||
@ -81,10 +56,6 @@ public:
|
|||||||
int ttl() const;
|
int ttl() const;
|
||||||
|
|
||||||
void ttl(int val);
|
void ttl(int val);
|
||||||
|
|
||||||
int deadtime() const;
|
|
||||||
|
|
||||||
void deadtime(int val);
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
static std::list<ptr<proxy> > _list;
|
static std::list<ptr<proxy> > _list;
|
||||||
@ -96,18 +67,10 @@ private:
|
|||||||
std::list<ptr<rule> > _rules;
|
std::list<ptr<rule> > _rules;
|
||||||
|
|
||||||
std::list<ptr<session> > _sessions;
|
std::list<ptr<session> > _sessions;
|
||||||
|
|
||||||
bool _promiscuous;
|
|
||||||
|
|
||||||
bool _router;
|
bool _router;
|
||||||
|
|
||||||
bool _autowire;
|
|
||||||
|
|
||||||
int _retries;
|
|
||||||
|
|
||||||
bool _keepalive;
|
|
||||||
|
|
||||||
int _ttl, _deadtime, _timeout;
|
int _ttl, _timeout;
|
||||||
|
|
||||||
proxy();
|
proxy();
|
||||||
};
|
};
|
||||||
|
@ -70,8 +70,6 @@ protected:
|
|||||||
|
|
||||||
void acquire(void* ptr)
|
void acquire(void* ptr)
|
||||||
{
|
{
|
||||||
if (!ptr) return;
|
|
||||||
|
|
||||||
_ref = new ptr_ref();
|
_ref = new ptr_ref();
|
||||||
_ref->ptr = (T*)ptr;
|
_ref->ptr = (T*)ptr;
|
||||||
_ref->wc = !!_weak;
|
_ref->wc = !!_weak;
|
||||||
|
@ -81,8 +81,6 @@ std::string route::token(const char* str)
|
|||||||
|
|
||||||
void route::load(const std::string& path)
|
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();
|
_routes.clear();
|
||||||
|
|
||||||
logger::debug() << "reading routes";
|
logger::debug() << "reading routes";
|
||||||
@ -105,19 +103,19 @@ void route::load(const std::string& path)
|
|||||||
|
|
||||||
unsigned char pfx;
|
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?
|
// TODO: Warn here?
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (route::hexdec(buf + 33,& pfx, 1) != 1) {
|
if (hexdec(buf + 33,& pfx, 1) != 1) {
|
||||||
// TODO: Warn here?
|
// TODO: Warn here?
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
addr.prefix((int)pfx);
|
addr.prefix((int)pfx);
|
||||||
|
|
||||||
route::create(addr, route::token(buf + 141));
|
route::create(addr, token(buf + 141));
|
||||||
}
|
}
|
||||||
} catch (std::ifstream::failure e) {
|
} catch (std::ifstream::failure e) {
|
||||||
logger::warning() << "Failed to parse IPv6 routing data from '" << path << "'";
|
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;
|
const address& addr() const;
|
||||||
|
|
||||||
ptr<iface> ifa();
|
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:
|
private:
|
||||||
static int _ttl;
|
static int _ttl;
|
||||||
@ -62,8 +56,14 @@ private:
|
|||||||
|
|
||||||
ptr<iface> _ifa;
|
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;
|
static std::list<ptr<route> > _routes;
|
||||||
|
|
||||||
|
route(const address& addr, const std::string& ifname);
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
NDPPD_NS_END
|
NDPPD_NS_END
|
||||||
|
57
src/rule.cc
57
src/rule.cc
@ -16,7 +16,6 @@
|
|||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <net/if.h>
|
|
||||||
|
|
||||||
#include "ndppd.h"
|
#include "ndppd.h"
|
||||||
#include "rule.h"
|
#include "rule.h"
|
||||||
@ -25,14 +24,6 @@
|
|||||||
|
|
||||||
NDPPD_NS_BEGIN
|
NDPPD_NS_BEGIN
|
||||||
|
|
||||||
std::vector<interface> interfaces;
|
|
||||||
|
|
||||||
bool rule::_any_aut = false;
|
|
||||||
|
|
||||||
bool rule::_any_iface = false;
|
|
||||||
|
|
||||||
bool rule::_any_static = false;
|
|
||||||
|
|
||||||
rule::rule()
|
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());
|
ptr<rule> ru(new rule());
|
||||||
ru->_ptr = ru;
|
ru->_ptr = ru;
|
||||||
ru->_pr = pr;
|
ru->_pr = pr;
|
||||||
ru->_daughter = ifa;
|
ru->_ifa = ifa;
|
||||||
ru->_addr = addr;
|
ru->_addr = addr;
|
||||||
ru->_aut = false;
|
ru->_aut = false;
|
||||||
_any_iface = true;
|
|
||||||
unsigned int ifindex;
|
|
||||||
|
|
||||||
ifindex = if_nametoindex(pr->ifa()->name().c_str());
|
logger::debug() << "rule::create() if=" << pr->ifa()->name() << ", addr=" << addr;
|
||||||
#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;
|
|
||||||
|
|
||||||
return ru;
|
return ru;
|
||||||
}
|
}
|
||||||
@ -69,10 +49,6 @@ ptr<rule> rule::create(const ptr<proxy>& pr, const address& addr, bool aut)
|
|||||||
ru->_pr = pr;
|
ru->_pr = pr;
|
||||||
ru->_addr = addr;
|
ru->_addr = addr;
|
||||||
ru->_aut = aut;
|
ru->_aut = aut;
|
||||||
_any_aut = _any_aut || aut;
|
|
||||||
|
|
||||||
if (aut == false)
|
|
||||||
_any_static = true;
|
|
||||||
|
|
||||||
logger::debug()
|
logger::debug()
|
||||||
<< "rule::create() if=" << pr->ifa()->name().c_str() << ", addr=" << addr
|
<< "rule::create() if=" << pr->ifa()->name().c_str() << ", addr=" << addr
|
||||||
@ -86,9 +62,9 @@ const address& rule::addr() const
|
|||||||
return _addr;
|
return _addr;
|
||||||
}
|
}
|
||||||
|
|
||||||
ptr<iface> rule::daughter() const
|
ptr<iface> rule::ifa() const
|
||||||
{
|
{
|
||||||
return _daughter;
|
return _ifa;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool rule::is_auto() const
|
bool rule::is_auto() const
|
||||||
@ -96,31 +72,6 @@ bool rule::is_auto() const
|
|||||||
return _aut;
|
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
|
bool rule::check(const address& addr) const
|
||||||
{
|
{
|
||||||
return _addr == addr;
|
return _addr == addr;
|
||||||
|
38
src/rule.h
38
src/rule.h
@ -18,7 +18,6 @@
|
|||||||
#include <string>
|
#include <string>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
#include <map>
|
#include <map>
|
||||||
#include <list>
|
|
||||||
|
|
||||||
#include <sys/poll.h>
|
#include <sys/poll.h>
|
||||||
|
|
||||||
@ -37,57 +36,24 @@ public:
|
|||||||
|
|
||||||
const address& addr() const;
|
const address& addr() const;
|
||||||
|
|
||||||
ptr<iface> daughter() const;
|
ptr<iface> ifa() const;
|
||||||
|
|
||||||
bool is_auto() const;
|
bool is_auto() const;
|
||||||
|
|
||||||
bool check(const address& addr) 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:
|
private:
|
||||||
weak_ptr<rule> _ptr;
|
weak_ptr<rule> _ptr;
|
||||||
|
|
||||||
weak_ptr<proxy> _pr;
|
weak_ptr<proxy> _pr;
|
||||||
|
|
||||||
ptr<iface> _daughter;
|
ptr<iface> _ifa;
|
||||||
|
|
||||||
address _addr;
|
address _addr;
|
||||||
|
|
||||||
bool _aut;
|
bool _aut;
|
||||||
|
|
||||||
static bool _any_aut;
|
|
||||||
|
|
||||||
static bool _any_static;
|
|
||||||
|
|
||||||
static bool _any_iface;
|
|
||||||
|
|
||||||
bool _autovia;
|
|
||||||
|
|
||||||
rule();
|
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
|
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
|
// You should have received a copy of the GNU General Public License
|
||||||
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
#include <sstream>
|
|
||||||
|
|
||||||
#include "ndppd.h"
|
#include "ndppd.h"
|
||||||
#include "proxy.h"
|
#include "proxy.h"
|
||||||
@ -25,8 +24,6 @@ NDPPD_NS_BEGIN
|
|||||||
|
|
||||||
std::list<weak_ptr<session> > session::_sessions;
|
std::list<weak_ptr<session> > session::_sessions;
|
||||||
|
|
||||||
static address all_nodes = address("ff02::1");
|
|
||||||
|
|
||||||
void session::update_all(int elapsed_time)
|
void session::update_all(int elapsed_time)
|
||||||
{
|
{
|
||||||
for (std::list<weak_ptr<session> >::iterator it = _sessions.begin();
|
for (std::list<weak_ptr<session> >::iterator it = _sessions.begin();
|
||||||
@ -43,54 +40,10 @@ void session::update_all(int elapsed_time)
|
|||||||
}
|
}
|
||||||
|
|
||||||
switch (se->_status) {
|
switch (se->_status) {
|
||||||
|
|
||||||
case session::WAITING:
|
case session::WAITING:
|
||||||
if (se->_fails < se->_retries) {
|
logger::debug() << "session is now invalid";
|
||||||
logger::debug() << "session will keep trying [taddr=" << se->_taddr << "]";
|
se->_status = session::INVALID;
|
||||||
|
se->_ttl = se->_pr->ttl();
|
||||||
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);
|
|
||||||
}
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
@ -102,34 +55,30 @@ void session::update_all(int elapsed_time)
|
|||||||
session::~session()
|
session::~session()
|
||||||
{
|
{
|
||||||
logger::debug() << "session::~session() this=" << logger::format("%x", this);
|
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++) {
|
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());
|
ptr<session> se(new session());
|
||||||
|
|
||||||
se->_ptr = se;
|
se->_ptr = se;
|
||||||
se->_pr = pr;
|
se->_pr = pr;
|
||||||
se->_taddr = taddr;
|
se->_saddr = saddr;
|
||||||
se->_autowire = auto_wire;
|
se->_taddr = taddr;
|
||||||
se->_keepalive = keepalive;
|
se->_daddr = daddr;
|
||||||
se->_retries = retries;
|
se->_ttl = pr->timeout();
|
||||||
se->_wired = false;
|
|
||||||
se->_ttl = pr->ttl();
|
|
||||||
se->_touched = false;
|
|
||||||
|
|
||||||
_sessions.push_back(se);
|
_sessions.push_back(se);
|
||||||
|
|
||||||
logger::debug()
|
logger::debug()
|
||||||
<< "session::create() pr=" << logger::format("%x", (proxy* )pr) << ", proxy=" << ((pr->ifa()) ? pr->ifa()->name() : "null")
|
<< "session::create() pr=" << logger::format("%x", (proxy* )pr) << ", saddr=" << saddr
|
||||||
<< ", taddr=" << taddr << " =" << logger::format("%x", (session* )se);
|
<< ", daddr=" << daddr << ", taddr=" << taddr << " =" << logger::format("%x", (session* )se);
|
||||||
|
|
||||||
return 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())
|
if (std::find(_ifaces.begin(), _ifaces.end(), ifa) != _ifaces.end())
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
ifa->add_session(_ptr);
|
||||||
_ifaces.push_back(ifa);
|
_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()
|
void session::send_solicit()
|
||||||
{
|
{
|
||||||
logger::debug() << "session::send_solicit() (_ifaces.size() = " << _ifaces.size() << ")";
|
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)
|
_pr->ifa()->write_advert(_saddr, _taddr, _pr->router());
|
||||||
{
|
|
||||||
_touched = true;
|
|
||||||
|
|
||||||
if (status() == session::WAITING || status() == session::INVALID) {
|
|
||||||
_ttl = _pr->timeout();
|
|
||||||
|
|
||||||
logger::debug() << "session is now probing [taddr=" << _taddr << "]";
|
|
||||||
|
|
||||||
send_solicit();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
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()
|
void session::handle_advert()
|
||||||
{
|
{
|
||||||
logger::debug()
|
_status = VALID;
|
||||||
<< "session::handle_advert() taddr=" << _taddr << ", ttl=" << _pr->ttl();
|
|
||||||
|
|
||||||
if (_status != VALID) {
|
|
||||||
_status = VALID;
|
|
||||||
|
|
||||||
logger::debug() << "session is active [taddr=" << _taddr << "]";
|
|
||||||
}
|
|
||||||
|
|
||||||
_ttl = _pr->ttl();
|
_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);
|
send_advert();
|
||||||
}
|
|
||||||
|
|
||||||
_pending.clear();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const address& session::taddr() const
|
const address& session::taddr() const
|
||||||
@ -326,34 +121,14 @@ const address& session::taddr() const
|
|||||||
return _taddr;
|
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;
|
return _daddr;
|
||||||
}
|
|
||||||
|
|
||||||
int session::retries() const
|
|
||||||
{
|
|
||||||
return _retries;
|
|
||||||
}
|
|
||||||
|
|
||||||
int session::fails() const
|
|
||||||
{
|
|
||||||
return _fails;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool session::wired() const
|
|
||||||
{
|
|
||||||
return _wired;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool session::touched() const
|
|
||||||
{
|
|
||||||
return _touched;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int session::status() const
|
int session::status() const
|
||||||
|
@ -16,7 +16,6 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <vector>
|
#include <vector>
|
||||||
#include <string>
|
|
||||||
|
|
||||||
#include "ndppd.h"
|
#include "ndppd.h"
|
||||||
|
|
||||||
@ -32,30 +31,14 @@ private:
|
|||||||
weak_ptr<proxy> _pr;
|
weak_ptr<proxy> _pr;
|
||||||
|
|
||||||
address _saddr, _daddr, _taddr;
|
address _saddr, _daddr, _taddr;
|
||||||
|
|
||||||
bool _autowire;
|
|
||||||
|
|
||||||
bool _keepalive;
|
|
||||||
|
|
||||||
bool _wired;
|
|
||||||
|
|
||||||
address _wired_via;
|
|
||||||
|
|
||||||
bool _touched;
|
|
||||||
|
|
||||||
// An array of interfaces this session is monitoring for
|
// An array of interfaces this session is monitoring for
|
||||||
// ND_NEIGHBOR_ADVERT on.
|
// ND_NEIGHBOR_ADVERT on.
|
||||||
std::list<ptr<iface> > _ifaces;
|
std::list<ptr<iface> > _ifaces;
|
||||||
|
|
||||||
std::list<ptr<address> > _pending;
|
|
||||||
|
|
||||||
// The remaining time in miliseconds the object will stay in the
|
// The remaining time in miliseconds the object will stay in the
|
||||||
// interface's session array or cache.
|
// interface's session array or cache.
|
||||||
int _ttl;
|
int _ttl;
|
||||||
|
|
||||||
int _fails;
|
|
||||||
|
|
||||||
int _retries;
|
|
||||||
|
|
||||||
int _status;
|
int _status;
|
||||||
|
|
||||||
@ -64,10 +47,9 @@ private:
|
|||||||
public:
|
public:
|
||||||
enum
|
enum
|
||||||
{
|
{
|
||||||
WAITING, // Waiting for an advert response.
|
WAITING, // Waiting for an advert response.
|
||||||
RENEWING, // Renewing;
|
VALID, // Valid;
|
||||||
VALID, // Valid;
|
INVALID // Invalid;
|
||||||
INVALID // Invalid;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
static void update_all(int elapsed_time);
|
static void update_all(int elapsed_time);
|
||||||
@ -75,45 +57,24 @@ public:
|
|||||||
// Destructor.
|
// Destructor.
|
||||||
~session();
|
~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_iface(const ptr<iface>& ifa);
|
||||||
|
|
||||||
void add_pending(const address& addr);
|
|
||||||
|
|
||||||
const address& taddr() const;
|
const address& taddr() const;
|
||||||
|
|
||||||
const address& daddr() const;
|
const address& daddr() const;
|
||||||
|
|
||||||
const address& saddr() 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;
|
int status() const;
|
||||||
|
|
||||||
void status(int val);
|
void status(int val);
|
||||||
|
|
||||||
void handle_advert();
|
void handle_advert();
|
||||||
|
|
||||||
void handle_advert(const address& saddr, const std::string& ifname, bool use_via);
|
void send_advert();
|
||||||
|
|
||||||
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_solicit();
|
void send_solicit();
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user