├── .gitignore ├── CMakeLists.txt ├── LICENSE ├── README ├── build-generic.sh ├── examples └── libdncp_example.c ├── generic ├── ddz.script ├── dhcp.script ├── dhcpv6.script ├── hnetd-backend ├── hnetd-routing ├── multicast.script ├── ohp.script ├── pcp.script ├── tunnel.script └── utils.script ├── hnetd_wireshark.lua ├── openwrt ├── autowifi.script ├── hnet.sh └── luci │ ├── htdocs │ └── luci-static │ │ └── resources │ │ ├── hnet-monitor.js │ │ └── vis.js │ └── luasrc │ ├── controller │ └── hnet.lua │ ├── model │ └── cbi │ │ └── admin_network │ │ └── hnet.lua │ └── view │ └── hnet-status.htm ├── run_coverage.sh ├── run_net_stress.sh ├── src ├── bitops.c ├── bitops.h ├── btrie.c ├── btrie.h ├── dhcp.h ├── dhcpv6.h ├── dncp.c ├── dncp.h ├── dncp_i.h ├── dncp_notify.c ├── dncp_proto.c ├── dncp_proto.h ├── dncp_timeout.c ├── dncp_trust.c ├── dncp_trust.h ├── dncp_util.h ├── dns_util.h ├── dtls.c ├── dtls.h ├── exeq.c ├── exeq.h ├── hncp.c ├── hncp.h ├── hncp_dump.c ├── hncp_dump.h ├── hncp_i.h ├── hncp_io.c ├── hncp_io.h ├── hncp_link.c ├── hncp_link.h ├── hncp_multicast.c ├── hncp_multicast.h ├── hncp_pa.c ├── hncp_pa.h ├── hncp_pa_i.h ├── hncp_proto.h ├── hncp_routing.c ├── hncp_routing.h ├── hncp_sd.c ├── hncp_sd.h ├── hncp_tunnel.c ├── hncp_tunnel.h ├── hncp_wifi.c ├── hncp_wifi.h ├── hnetd.c ├── hnetd.h ├── hnetd_time.c ├── hnetd_time.h ├── iface.c ├── iface.h ├── pa_conf.h ├── pa_core.c ├── pa_core.h ├── pa_filters.c ├── pa_filters.h ├── pa_rules.c ├── pa_rules.h ├── pa_store.c ├── pa_store.h ├── pd.c ├── pd.h ├── platform-generic.c ├── platform-openwrt.c ├── platform.h ├── prefix.c ├── prefix.h ├── prefix_utils.c ├── prefix_utils.h ├── tlv.c ├── tlv.h ├── udp46.c ├── udp46.h └── udp46_i.h └── test ├── cert1.pem ├── cert2.pem ├── eea339da.0 ├── eea339da.1 ├── fake_fork_exec.h ├── fake_iface.h ├── fake_log.h ├── fake_random.h ├── fake_uloop.h ├── key1.pem ├── key2.pem ├── net_sim.h ├── prefixes_library.h ├── smock.h ├── sput.h ├── test_bitops.c ├── test_btrie.c ├── test_dncp_trust.c ├── test_dtls.c ├── test_dummy.c ├── test_exeq.c ├── test_hncp.c ├── test_hncp_bfs.c ├── test_hncp_io.c ├── test_hncp_multicast.c ├── test_hncp_net.c ├── test_hncp_sd.c ├── test_iface.c ├── test_pa_core.c ├── test_pa_filters.c ├── test_pa_rules.c ├── test_pa_store.c └── test_tlv.c /.gitignore: -------------------------------------------------------------------------------- 1 | .project 2 | .cproject 3 | config.log 4 | CMakeCache.txt 5 | CMakeFiles 6 | CMakeScripts 7 | Debug 8 | Release 9 | hnetd.build 10 | hnetd.xcodeproj 11 | CTestTestfile.cmake 12 | CPackConfig.cmake 13 | CPackSourceConfig.cmake 14 | _CPack_Packages 15 | Testing 16 | Makefile 17 | cmake_install.cmake 18 | install_manifest.txt 19 | *.deb 20 | *~ 21 | *.orig 22 | /hnetd 23 | /test_* 24 | .settings 25 | /coverage 26 | /coverage.info 27 | .DS_Store 28 | /cscope.* 29 | libdncp.a 30 | libdncp_example 31 | -------------------------------------------------------------------------------- /README: -------------------------------------------------------------------------------- 1 | hnetd - a home network configuration daemon 2 | 3 | 4 | ** Abstract ** 5 | 6 | hnetd is a networking daemon to automatically manage address assignment, 7 | routing, DNS, SD and border firewalling in home networks running it. 8 | It implements the Home Networking Control protocol as specified in 9 | http://tools.ietf.org/html/draft-ietf-homenet-hncp 10 | 11 | hnetd is designed to run on generic Linux-based routers. 12 | 13 | 14 | ** License ** 15 | 16 | This project was originally licensed under the GNU General Public 17 | License 2. With the agreement of all copyright holders responsible for 18 | contributions in this branch, the license was changed to Apache 2.0 19 | effective April 3rd 2016. 20 | 21 | ** Features ** 22 | 23 | 1. State synchronization between routers 24 | a) link-local multicast transmission 25 | b) unicast fallback for bulk synchronization 26 | c) collision and conflict detection and resolving 27 | 28 | 2. Prefix distribution and allocation 29 | a) IPv6 prefix delegation 30 | b) IPv4 prefix allocation 31 | 32 | 3. Routing setup 33 | a) selection of a shared routing protocol 34 | b) fallback mechanism to setup routes autonomously 35 | 36 | 4. Dynamic border-detection for IPv4 and IPv6 37 | a) on-demand firewall reconfiguration 38 | b) on-demand RA/DHCP/DHCPv6 server configuration 39 | c) integration of fixed external connections (e.g. PPP, 6rd, ...) 40 | 41 | 5. Sharing of DNS and Service Discovery configuration 42 | a) Local DNS configuration 43 | b) mDNS / DNS-SD hybrid proxy configuration 44 | 45 | 46 | ** Compiling ** 47 | 48 | hnetd depends on the following libraries: 49 | * json-c: https://github.com/json-c/json-c 50 | * libubox: https://git.openwrt.org/project/libubox.git 51 | * libubus (OpenWrt only): https://git.openwrt.org/project/ubus.git 52 | 53 | hnetd uses the following auxiliary tools (replacable): 54 | * odhcp6c (DHCPv6 client): https://github.com/sbyx/odhcp6c 55 | * odhcpd (RA/DHCP/DHCPv6 server): https://github.com/sbyx/odhcpd 56 | * ohybridproxy (mDNS proxy, optional): https://github.com/sbyx/ohybridproxy 57 | * minimalist-pcproxy (PCP proxy, optional): https://github.com/fingon/minimalist-pcproxy 58 | * udhcpc (DHCP client): http://busybox.net 59 | 60 | hnetd uses cmake: 61 | * To prepare a Makefile use: "cmake . -DCMAKE_INSTALL_PREFIX=/usr" 62 | * To build / install use: "make" / "make install" afterwards. 63 | * To build DEB or RPM packages use: "make package" afterwards. 64 | 65 | Note: The script "build-generic.sh" can aid in building hnet and its 66 | dependencies and tools on Debian/Ubuntu/Mint and related Linux distributions. 67 | 68 | 69 | ** OpenWrt Firmware Integration ** 70 | 71 | hnetd and ohybridproxy can be built from the openwrt-routing feed. 72 | Use: 73 | ./scripts/feeds update 74 | ./scripts/feeds install hnetd ohybridproxy 75 | 76 | and select both packets in "make menuconfig" under "Network" and the submenu 77 | "IP Addresses and Names". Snapshot packages might be available in the OpenWrt 78 | daily snapshots folder: http://downloads.openwrt.org/snapshots/trunk/ 79 | 80 | To use hnetd on an interface add a config section in /etc/config/network, e.g. 81 | 82 | config interface homenet0 83 | option ifname eth0 84 | option proto hnet 85 | 86 | or select the protocol "Automatic Homenet (HNCP)" in the web interface. 87 | 88 | IMPORTANT: Remove or comment out other config sections running DHCP or DHCPv6 89 | clients on the interfaces your run hnet on. Additional static configuration 90 | section may be kept for debugging purposes. 91 | 92 | WARNING: Do NOT set the proto of either the “lan”, “wan” or “wan6” interface 93 | to hnet directly. Always rename your interfaces to a different name, 94 | e.g. homenet0 or homenet1. 95 | 96 | 97 | ** Generic Firmware Integration ** 98 | 99 | hnetd can be integrated into generic Linux router firmwares with recent 3.10.x 100 | or later kernels. The scripts that need to be adapted for the integration can 101 | be found in the folder "generic". 102 | 103 | Copy the scripts hnet-backend and hnetd-routing to /usr/sbin/ and adapt 104 | them if needed. The symlinks hnet-client, hnet-ifup and hnet-ifdown should be 105 | preserved as well. 106 | 107 | Copy the scripts dhcp.script and dhcpv6.script to /usr/share/hnetd and 108 | adapt them if needed. 109 | 110 | If you are using odhcpd as DHCP/DHCPv6/RA server start it as a daemon. 111 | Afterwards run hnetd with appropriate parameters. 112 | 113 | Once both services are running, you can use the hnet CLI tools: 114 | 115 | hnet-ifup [-c category] [-a] [-d] [-u] [-p prefix] [-l id[/idmask]] 116 | [-i id/idmask [filter-prefix]] [-m ip6_plen] [-k trickle_k] 117 | [-P ping_interval] [-4 global-IPv4-address] [-6 delegated prefix] 118 | [-D dns-server] 119 | adds the network interface (e.g. eth0) to the homenet. 120 | -c is an optional parameter declaring the interface category 121 | (see https://tools.ietf.org/html/draft-ietf-homenet-hncp-04#page-5) 122 | auto: auto-detect if interface is internal or external (default) 123 | external: interface is always external / towards an ISP 124 | static: like external, but does not run a DHCP or DHCPv6 client 125 | internal: interface is always internal / towards interior nodes 126 | leaf: like internal but connects to clients-only (no routers) 127 | guest: like leaf, but clients should only reach the Internet 128 | hybrid: like internal, but connected to trusted, legacy CPE (experimental) 129 | adhoc: like internal, but link is non-transitive (e.g. mesh) (experimental) 130 | static: 131 | -4 is an optional parameter indicating the public IPv4 address of the interface 132 | -6 is an optional parameter indicating an IPv6-prefix delegated to the interface 133 | -D is an optional parameter indicating a public recursive DNS server 134 | internal / leaf / guest / hybrid / adhoc: 135 | -p is an optional parameter indicating one or more static prefixes. 136 | -l is an optional parameter setting the link-id and id-mask. 137 | -i is an optional parameter indicating one or more iface ids. 138 | -m is an optional parameter overriding the default prefix length when 139 | generating an IPv6 assignment. 140 | -d is an optional parameter indicating prefix assignment must be disabled. 141 | -u is an optional parameter indicating that an IPv6 default route should be 142 | announced even when there is only a ULA-prefix present. 143 | -k is an optional parameter indicating the interface's trickle K parameter. 144 | -P is an optional parameter indicating the dead-peer-detection interval value in ms. 145 | 146 | hnet-ifdown removes an interface from hnet again. 147 | 148 | hnet-dump dumps you (most of) the current state of the network as JSON. 149 | -------------------------------------------------------------------------------- /build-generic.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | echo Detecting... 3 | which sudo && which apt-get && sudo apt-get install build-essential git cmake libjson-c-dev 4 | 5 | gitdir="./tmp" 6 | distdir="$(pwd)/dist" 7 | [ -z "$distdir" ] && distdir=./dist 8 | 9 | mkdir -p $gitdir $distdir/usr 10 | 11 | git clone http://git.openwrt.org/project/libubox.git $gitdir/libubox 12 | git clone git://nbd.name/uci.git $gitdir/uci 13 | git clone https://github.com/sbyx/odhcp6c.git $gitdir/odhcp6c 14 | git clone https://github.com/sbyx/odhcpd.git $gitdir/odhcpd 15 | git clone https://github.com/sbyx/hnetd.git $gitdir/hnetd 16 | 17 | ( 18 | cd $gitdir/libubox 19 | cmake -DCMAKE_INSTALL_PREFIX=$distdir/usr -DBUILD_LUA=off . 20 | make install 21 | ) 22 | 23 | ( 24 | cd $gitdir/uci 25 | mv CMakeLists.txt CMakeLists.txt.in 26 | echo "include_directories($distdir/usr/include)" > CMakeLists.txt 27 | echo "link_directories($distdir/usr/lib)" >> CMakeLists.txt 28 | cat CMakeLists.txt.in >> CMakeLists.txt 29 | cmake -DCMAKE_INSTALL_PREFIX=$distdir/usr -DBUILD_LUA=off . 30 | make install VERBOSE=1 31 | ) 32 | 33 | ( 34 | cd $gitdir/odhcp6c 35 | cmake -DCMAKE_INSTALL_PREFIX=$distdir/usr . 36 | make install 37 | ) 38 | 39 | ( 40 | cd $gitdir/odhcpd 41 | mv CMakeLists.txt CMakeLists.txt.in 42 | echo "include_directories($distdir/usr/include)" > CMakeLists.txt 43 | echo "link_directories($distdir/usr/lib)" >> CMakeLists.txt 44 | cat CMakeLists.txt.in >> CMakeLists.txt 45 | cmake -DCMAKE_INSTALL_PREFIX=$distdir/usr . 46 | make install 47 | ) 48 | 49 | ( 50 | cd $gitdir/hnetd 51 | mv CMakeLists.txt CMakeLists.txt.in 52 | echo "include_directories($distdir/usr/include)" > CMakeLists.txt 53 | echo "link_directories($distdir/usr/lib)" >> CMakeLists.txt 54 | cat CMakeLists.txt.in >> CMakeLists.txt 55 | cmake -DCMAKE_INSTALL_PREFIX=$distdir/usr . 56 | make install 57 | ) 58 | -------------------------------------------------------------------------------- /examples/libdncp_example.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2015 Cisco Systems, Inc. 3 | */ 4 | #include "dncp.h" 5 | 6 | /* 7 | * You can compile a static library implementing basic dncp API. 8 | * This library will require the program to be linked with it to 9 | * implement the functions defined in dncp_profile.h 10 | * 11 | * In this example, we just include code from hncp, where these functions 12 | * are implemented. 13 | */ 14 | 15 | int log_level = 7; 16 | 17 | #include 18 | static void example_log(__unused int priority, const char *format, ...) { 19 | va_list myargs; 20 | va_start(myargs, format); 21 | vprintf(format, myargs); 22 | printf("\n"); 23 | va_end(myargs); 24 | } 25 | 26 | void (*hnetd_log)(int priority, const char *format, ...) = example_log; 27 | 28 | /* In this example, we just use hncp's functions */ 29 | #include "udp46.c" 30 | #include "hncp_io.c" 31 | #include "hncp.c" 32 | 33 | int main (int argc, char **argv) 34 | { 35 | hncp hncp; 36 | 37 | uloop_init(); 38 | if(!(hncp = hncp_create())) { 39 | L_ERR("hncp_create error"); 40 | return -1; 41 | } 42 | 43 | argc--; 44 | argv++; 45 | while(argc) { 46 | if(!hncp_io_set_ifname_enabled(hncp, argv[0], 1)) { 47 | L_ERR("Could not enable iface %s", argv[0]); 48 | return -1; 49 | } 50 | argc--; 51 | argv++; 52 | } 53 | 54 | char *data = "The answer"; 55 | dncp_tlv tlv = dncp_add_tlv(hncp->dncp, 42, data, strlen(data), 0); 56 | if(!(tlv)) { 57 | L_ERR("Could not publish TLV"); 58 | } 59 | 60 | uloop_run(); 61 | return 0; 62 | } 63 | -------------------------------------------------------------------------------- /generic/ddz.script: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | #-*-sh-*- 3 | # 4 | # $Id: ddz-script $ 5 | # 6 | # Author: Markus Stenberg 7 | # 8 | # Copyright (c) 2014 cisco Systems, Inc. 9 | # 10 | # Created: Fri Jan 17 11:46:30 2014 mstenber 11 | # Last modified: Tue Sep 15 11:09:27 2015 mstenber 12 | # Edit time: 3 min 13 | # 14 | 15 | # This is minimalist init.d-like start/stop script for 16 | # zonestitcher. 17 | 18 | ZS=zonestitcher 19 | DNSMASQDIR=/tmp/dnsmasq.d 20 | 21 | start() { 22 | mkdir -p $DNSMASQDIR 23 | DOMAIN=$1 24 | shift 25 | echo "server=/${DOMAIN}/127.0.0.2#55" > $DNSMASQDIR/zonestitcher.conf 26 | $ZS -a 127.0.0.2 -p 55 $* & 27 | # TBD: Should we actually restart dnsmasq too? 28 | } 29 | 30 | stop() { 31 | killall -9 $ZS 32 | } 33 | 34 | 35 | CMD=$1 36 | # For debugging purposes 37 | LOGNAME=`basename $0` 38 | echo "$*" | logger -t "$LOGNAME" 39 | stop 40 | start $* 41 | -------------------------------------------------------------------------------- /generic/dhcp.script: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | echo "[dhcp.script] $*" 3 | [ -z "$1" ] && echo "Error: should be run by udhcpc" && exit 1 4 | 5 | BASEDIR=$(dirname $0) 6 | . $BASEDIR/utils.script 7 | 8 | set_classless_routes() { 9 | local max=128 10 | shift 1 11 | 12 | while [ -n "$1" -a -n "$2" -a $max -gt 0 ]; do 13 | ip -4 route add "$1" via "$2" dev "$interface" 14 | max=$(($max-1)) 15 | shift 2 16 | done 17 | } 18 | 19 | setup_interface () { 20 | hnet-call ifup "{\"ifname\": \"$interface\"}" 21 | 22 | ip -4 route flush dev "$interface" 23 | ip -4 address flush dev "$interface" 24 | 25 | ifconfig "$interface" "$ip" netmask "${subnet:-255.255.255.0}" 26 | 27 | [ -n "$METRIC" ] && METRIC="metric $METRIC" 28 | for i in $router; do 29 | [ "$NODEFAULT" != 1 ] && ip -4 route add default via "$i" dev "$interface" $METRIC 30 | for r in $CUSTOMROUTES; do 31 | ip -4 route add "$r" via "$i" dev "$interface" $METRIC 32 | done 33 | done 34 | 35 | # CIDR STATIC ROUTES (rfc3442) 36 | [ -n "$staticroutes" ] && set_classless_routes $staticroutes 37 | [ -n "$msstaticroutes" ] && set_classless_routes $msstaticroutes 38 | 39 | update_resolv "dhcp" "$interface" "$dns" 40 | local dnspart="" 41 | 42 | for entry in $dns; do 43 | if [ -z "$dnspart" ]; then 44 | dnspart="\"$entry\"" 45 | else 46 | dnspart="$dnspart, \"$entry\"" 47 | fi 48 | done 49 | 50 | hnet-call enable_ipv4_uplink "{\"ifname\": \"$interface\", \"dns\": [$dnspart], \"ipv4source\": \"$ip\"}" 51 | } 52 | 53 | deconfig_interface() { 54 | ip -4 route flush dev "$interface" 55 | ip -4 address flush dev "$interface" 56 | hnet-call disable_ipv4_uplink "{\"ifname\": \"$interface\"}" 57 | update_resolv "dhcp" "$interface" "" 58 | } 59 | 60 | case "$1" in 61 | deconfig) 62 | deconfig_interface 63 | ;; 64 | renew|bound) 65 | setup_interface 66 | ;; 67 | esac 68 | 69 | # user rules 70 | [ -f /etc/udhcpc.user ] && . /etc/udhcpc.user 71 | 72 | exit 0 73 | -------------------------------------------------------------------------------- /generic/dhcpv6.script: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | echo "[dhcpv6.script] $*" 3 | [ -z "$2" ] && echo "Error: should be run by odhcpc6c" && exit 1 4 | 5 | BASEDIR=$(dirname $0) 6 | . $BASEDIR/utils.script 7 | 8 | PROTO=72 9 | 10 | setup_interface () { 11 | local device="$1" 12 | 13 | # Merge RA-DNS 14 | for radns in $RA_DNS; do 15 | local duplicate=0 16 | for dns in $RDNSS; do 17 | [ "$radns" = "$dns" ] && duplicate=1 18 | done 19 | [ "$duplicate" = 0 ] && RDNSS="$RDNSS $radns" 20 | done 21 | 22 | local dnspart="" 23 | for dns in $RDNSS; do 24 | if [ -z "$dnspart" ]; then 25 | dnspart="\"$dns\"" 26 | else 27 | dnspart="$dnspart, \"$dns\"" 28 | fi 29 | done 30 | 31 | update_resolv "dhcpv6" "$device" "$dns" 32 | 33 | local prefixpart="" 34 | for entry in $PREFIXES; do 35 | local addr="${entry%%,*}" 36 | entry="${entry#*,}" 37 | local preferred="${entry%%,*}" 38 | entry="${entry#*,}" 39 | local valid="${entry%%,*}" 40 | entry="${entry#*,}" 41 | [ "$entry" = "$valid" ] && entry= 42 | 43 | local class="" 44 | local excluded="" 45 | 46 | while [ -n "$entry" ]; do 47 | local key="${entry%%=*}" 48 | entry="${entry#*=}" 49 | local val="${entry%%,*}" 50 | entry="${entry#*,}" 51 | [ "$entry" = "$val" ] && entry= 52 | 53 | if [ "$key" = "class" ]; then 54 | class=", \"class\": $val" 55 | elif [ "$key" = "excluded" ]; then 56 | excluded=", \"excluded\": \"$val\"" 57 | fi 58 | done 59 | 60 | local prefix="{\"address\": \"$addr\", \"preferred\": $preferred, \"valid\": $valid $class $excluded}" 61 | 62 | if [ -z "$prefixpart" ]; then 63 | prefixpart="$prefix" 64 | else 65 | prefixpart="$prefixpart, $prefix" 66 | fi 67 | 68 | # TODO: delete this somehow when the prefix disappears 69 | #ip -6 route add unreachable "$addr" proto $PROTO 70 | # ^ this is taken care of by hnetd, actually, so we get 71 | # two and this is too low metric -> removed for now -MSt 12/2015 72 | done 73 | 74 | [ -n "$CER" ] && cerid=", \"cerid\": \"$CER\"" 75 | [ -n "$PASSTHRU" ] && passthru=", \"passthru\": \"$PASSTHRU\"" 76 | hnet-call enable_ipv6_uplink "{\"ifname\": \"$device\", \"prefix\": [$prefixpart], \"dns\": [$dnspart]$cerid$passthru}" 77 | 78 | ip -6 route flush dev "$device" proto $PROTO 79 | 80 | # Merge addresses 81 | for entry in $RA_ADDRESSES; do 82 | local duplicate=0 83 | local addr="${entry%%/*}" 84 | for dentry in $ADDRESSES; do 85 | local daddr="${dentry%%/*}" 86 | [ "$addr" = "$daddr" ] && duplicate=1 87 | done 88 | [ "$duplicate" = "0" ] && ADDRESSES="$ADDRESSES $entry" 89 | done 90 | 91 | for entry in $ADDRESSES; do 92 | local addr="${entry%%,*}" 93 | entry="${entry#*,}" 94 | local preferred="${entry%%,*}" 95 | entry="${entry#*,}" 96 | local valid="${entry%%,*}" 97 | 98 | ip -6 address replace "$addr" dev "$device" preferred_lft "$preferred" valid_lft "$valid" 99 | done 100 | 101 | for entry in `ip -6 -o address list scope global dev "$device" | awk '{print $4}'`; do 102 | local duplicate=0 103 | for dentry in $ADDRESSES; do 104 | [ "$entry" = "${dentry%%,*}" ] && duplicate=1 105 | done 106 | [ "$duplicate" = "0" ] && ip -6 address del "$entry" dev "$device" 107 | done 108 | 109 | for entry in $RA_ROUTES; do 110 | local addr="${entry%%,*}" 111 | entry="${entry#*,}" 112 | local gw="${entry%%,*}" 113 | entry="${entry#*,}" 114 | local valid="${entry%%,*}" 115 | entry="${entry#*,}" 116 | local metric="${entry%%,*}" 117 | 118 | if [ -n "$gw" ]; then 119 | ip -6 route add "$addr" via "$gw" metric "$metric" dev "$device" from "::/128" proto $PROTO 120 | else 121 | ip -6 route add "$addr" metric "$metric" dev "$device" proto $PROTO 122 | fi 123 | 124 | for prefix in $PREFIXES; do 125 | local paddr="${prefix%%,*}" 126 | [ -n "$gw" ] && ip -6 route add "$addr" via "$gw" metric "$metric" dev "$device" from "$paddr" proto $PROTO 127 | done 128 | done 129 | } 130 | 131 | teardown_interface() { 132 | local device="$1" 133 | ip -6 route flush dev "$device" proto $PROTO 134 | ip -6 address flush dev "$device" scope global 135 | hnet-call disable_ipv6_uplink "{\"ifname\": \"$device\"}" 136 | update_resolv "dhcpv6" "$device" "" 137 | } 138 | 139 | ( 140 | flock 8 141 | case "$2" in 142 | bound) 143 | teardown_interface "$1" 144 | setup_interface "$1" 145 | ;; 146 | informed|updated|rebound|ra-updated) 147 | setup_interface "$1" 148 | ;; 149 | stopped|unbound) 150 | teardown_interface "$1" 151 | ;; 152 | started) 153 | hnet-call ifup "{\"ifname\": \"$1\"}" 154 | teardown_interface "$1" 155 | ;; 156 | esac 157 | 158 | # user rules 159 | [ -f /etc/odhcp6c.user ] && . /etc/odhcp6c.user 160 | ) 8>/tmp/odhcp6c.lock.$1 161 | rm -f /tmp/odhcp6c.lock.$1 162 | -------------------------------------------------------------------------------- /generic/hnetd-backend: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | BASEDIR=$(dirname $0)/../share/hnetd/ 4 | . $BASEDIR/utils.script 5 | 6 | # iptables 1.4.14 does not have this; 1.4.21 does. it seems crucial for this 7 | # to work correctly though.. sigh. 8 | iptables_wait () { 9 | [ -n "$checked_iptables_wait" ] && echo "$have_iptables_wait" && return 10 | checked_iptables_wait=1 11 | if iptables -h | grep -q " --wait"; then 12 | have_iptables_wait="-w" 13 | fi 14 | iptables_wait 15 | } 16 | 17 | echo "[hnetd-backend] $*" 18 | 19 | case "$1" in 20 | dhcpv4client) 21 | [ "$2" = 1 ] && export NODEFAULT=1 22 | [ -n "$3" ] && export METRIC=$3 23 | [ -n "$4" ] && export CUSTOMROUTES=$4 24 | exec busybox udhcpc -f -t 1000000000 -i "$2" -x "hostname:$(hostname)" -x "0x4d:07484f4d454e4554" -s $BASEDIR/dhcp.script 25 | ;; 26 | 27 | dhcpv6client) 28 | exec odhcp6c -t120 -P0 -F -s $BASEDIR/dhcpv6.script -u HOMENET "$2" 29 | ;; 30 | 31 | setfilter|unsetfilter) 32 | [ "$1" = "setfilter" ] && act="-A" || act="-D" 33 | ip6tables $act INPUT -i "$2" -s fe80::/10 -d fe80::/10 -p udp -m udp --sport 547 --dport 546 -j ACCEPT `iptables_wait` 34 | for cmd in iptables ip6tables; do 35 | case "$cmd" in 36 | iptables) 37 | reject="icmp-port-unreachable" 38 | ;; 39 | ip6tables) 40 | reject="icmp6-port-unreachable" 41 | ;; 42 | esac 43 | $cmd -L MINIUPNPD `iptables_wait` > /dev/null 2>&1 && \ 44 | $cmd $act FORWARD -i "$2" ! -o "$2" -j MINIUPNPD `iptables_wait` 45 | $cmd $act FORWARD -i "$2" -p tcp -m conntrack --ctstate NEW,INVALID -j REJECT --reject-with tcp-reset `iptables_wait` 46 | $cmd $act FORWARD -i "$2" -m conntrack --ctstate NEW,INVALID -j REJECT --reject-with "$reject" `iptables_wait` 47 | $cmd $act INPUT -i "$2" -p tcp -m conntrack --ctstate NEW,INVALID -j REJECT --reject-with tcp-reset `iptables_wait` 48 | $cmd $act INPUT -i "$2" -m conntrack --ctstate NEW,INVALID -j REJECT --reject-with "$reject" `iptables_wait` 49 | 50 | done 51 | iptables -t nat $act POSTROUTING -o "$2" -j MASQUERADE `iptables_wait` 52 | iptables -L MINIUPNPD > /dev/null 2>&1 && \ 53 | iptables -t nat $act PREROUTING -i "$2" -j MINIUPNPD `iptables_wait` && \ 54 | iptables -t mangle $act PREROUTING -i "$2" -j MINIUPNPD `iptables_wait` 55 | ;; 56 | 57 | newaddr|deladdr) 58 | [ "$1" = "newaddr" ] && act="replace" || act="del" 59 | [ -n "$4" -a -n "$5" ] && args="preferred_lft $4 valid_lft $5" || args="" 60 | ip address $act "$3" dev "$2" $args 61 | killall -q -SIGHUP odhcpd 62 | ;; 63 | 64 | newprefixroute|delprefixroute) 65 | [ "$1" = "newprefixroute" ] && act="replace" || act="del" 66 | ip -6 route "$act" unreachable "$2" metric 2147483646 67 | ;; 68 | 69 | newblocked|delblocked) 70 | [ "$1" = "newblocked" ] && act="-A" || act="-D" 71 | case "$3" in 72 | *.*) 73 | cmd="iptables" 74 | reject="icmp-port-unreachable" 75 | ;; 76 | *) 77 | cmd="ip6tables" 78 | reject="icmp6-port-unreachable" 79 | ;; 80 | esac 81 | 82 | $cmd $act FORWARD -i "$2" -d "$3" -p tcp -j REJECT --reject-with tcp-reset `iptables_wait` 83 | $cmd $act FORWARD -i "$2" -d "$3" -j REJECT --reject-with "$reject" `iptables_wait` 84 | 85 | $cmd $act FORWARD -o "$2" -s "$3" -p tcp -j REJECT --reject-with tcp-reset `iptables_wait` 86 | $cmd $act FORWARD -o "$2" -s "$3" -j REJECT --reject-with "$reject" `iptables_wait` 87 | ;; 88 | 89 | startdhcp) 90 | dhcpv4=disabled 91 | dhcpv6=disabled 92 | stateful=0 93 | 94 | [ -n "$3" ] && dhcpv4=server 95 | [ -n "$4" ] && stateful=1 96 | [ -n "$5" ] && dhcpv6=server 97 | 98 | uci batch <<-EOF 99 | set dhcp.$2=dhcp 100 | set dhcp.$2.ifname=$2 101 | set dhcp.$2.ra=server 102 | set dhcp.$2.dhcpv4=$dhcpv4 103 | set dhcp.$2.dhcpv6=$dhcpv6 104 | set dhcp.$2.pd_manager=$6 105 | set dhcp.$2.ra_management=$stateful 106 | set dhcp.$2.filter_class=HOMENET 107 | commit dhcp 108 | EOF 109 | pidof odhcpd && killall -SIGHUP odhcpd || odhcpd & 110 | ;; 111 | 112 | stopdhcp) 113 | uci batch <<-EOF 114 | delete dhcp.$2 115 | commit dhcp 116 | EOF 117 | killall -q -SIGHUP odhcpd 118 | ;; 119 | 120 | setdhcpv6) 121 | [ -z "$DNS" ] && exit 0 122 | 123 | # DNS = external DNS server list. 124 | # We pass it along to guests only. 125 | 126 | IDNS="" 127 | [ -n "$GUEST" ] && IDNS="$DNS" 128 | uci batch <<-EOF 129 | set dhcp.$2=dhcp 130 | set dhcp.$2.dns="$IDNS" 131 | set dhcp.$2.domain="$SEARCH" 132 | set dhcp.$2.dhcpv6_raw="$PASSTHRU" 133 | set dhcp.$2.ra_default="$RA_DEFAULT" 134 | commit dhcp 135 | EOF 136 | killall -q -SIGHUP odhcpd 137 | update_resolv "hnetd" "$2" "$DNS" 138 | ;; 139 | 140 | newnat) 141 | rule="hnet_snat_$1" 142 | iptables -t nat -N "$rule" `iptables_wait` 143 | iptables -t nat -I POSTROUTING -o "$1" -j "$rule" `iptables_wait` 144 | if [ -z "$4" ]; then 145 | iptables -t nat -A "$rule" -d "$2" -j ACCEPT `iptables_wait` 146 | iptables -t nat -A "$rule" -j SNAT --to-source "$3" `iptables_wait` 147 | else 148 | iptables -t nat -A "$rule" -d "$3/$4" -j SNAT --to-source "$3" `iptables_wait` 149 | fi 150 | ;; 151 | 152 | delnat) 153 | rule="hnet_snat_$1" 154 | iptables -t nat -D POSTROUTING -o "$1" -j "$rule" `iptables_wait` 155 | iptables -t nat -F "$rule" `iptables_wait` 156 | iptables -t nat -X "$rule" `iptables_wait` 157 | ;; 158 | 159 | esac 160 | -------------------------------------------------------------------------------- /generic/hnetd-routing: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | PATH=/usr/bin:/usr/sbin:/bin:/sbin 4 | BABEL_EXE=`which babeld` 5 | BABEL_PID=/var/run/babeld-hnetd.pid 6 | BABEL_CONF=/var/run/babeld-hnetd.conf 7 | BABEL_CONF_OWRT=/tmp/babeld.d/hnetd.conf 8 | 9 | # Routing table for BFS (also rule priority) 10 | BFSTABLE=33333 11 | BFSPROTO=73 12 | 13 | act=$1 14 | shift 15 | 16 | create_babel_conf() { 17 | FILE=$1 18 | shift 19 | echo "redistribute" > $FILE 20 | echo "redistribute local deny" >> $FILE 21 | echo "ipv6-subtrees yes" >> $FILE 22 | echo "reflect-kernel-metric true" >> $FILE 23 | for IF in $*; do 24 | echo "interface $IF" >> $FILE 25 | done 26 | } 27 | 28 | handle_babel_openwrt() { 29 | if [ -z "$1" ]; then 30 | /etc/init.d/babeld stop 31 | return 32 | fi 33 | mkdir -p `dirname $BABEL_CONF_OWRT` 34 | create_babel_conf $BABEL_CONF_OWRT $* 35 | /etc/init.d/babeld restart 36 | } 37 | 38 | handle_babel_generic() { 39 | [ -f $BABEL_PID ] && kill -9 `cat $BABEL_PID` 40 | if [ -z "$1" ]; then return ; fi 41 | create_babel_conf $BABEL_CONF $* 42 | rm -f $BABEL_PID 43 | $BABEL_EXE -D -I $BABEL_PID -c $BABEL_CONF 44 | 45 | # Wait for pid file to actually show up 46 | [ -f $BABEL_PID ] || sleep 1 47 | [ -f $BABEL_PID ] || sleep 2 48 | [ -f $BABEL_PID ] || sleep 4 49 | } 50 | 51 | case "$act" in 52 | configure) 53 | if [ -x "$BABEL_EXE" ]; then 54 | if [ -f /etc/openwrt_version ] ; then 55 | handle_babel_openwrt $* 56 | else 57 | handle_babel_generic $* 58 | fi 59 | else 60 | exit 1 61 | fi 62 | ;; 63 | 64 | bfsprepare) 65 | ip -6 rule del table "$BFSTABLE" priority "$BFSTABLE" 66 | ip -4 rule del table "$BFSTABLE" priority "$BFSTABLE" 67 | ip -6 rule add table "$BFSTABLE" priority "$BFSTABLE" 68 | ip -4 rule add table "$BFSTABLE" priority "$BFSTABLE" 69 | ip -6 route flush table "$BFSTABLE" proto $BFSPROTO 70 | ip -4 route flush table "$BFSTABLE" proto $BFSPROTO 71 | ip -6 route flush proto "$BFSPROTO" 72 | ;; 73 | 74 | bfsipv6assigned) 75 | exec ip -6 route add "$1" via "$2" dev "$3" metric "$4" table "$BFSTABLE" proto "$BFSPROTO" 76 | # IPv6 throw routes are broken in historic Linux kernels... 77 | # (this workaround plays havoc with e.g. Babel though) 78 | #exec ip -6 route add "$1" via "$2" dev "$3" metric "$((2140000000+$4))" proto "$BFSPROTO" 79 | ;; 80 | 81 | bfsipv4assigned) 82 | exec ip -4 route add "$1" via "$2" dev "$3" metric "$4" table "$BFSTABLE" proto "$BFSPROTO" onlink 83 | ;; 84 | 85 | bfsipv6prefix) 86 | exec ip -6 route add throw "$1" proto $BFSPROTO metric 2147483645 87 | ;; 88 | 89 | bfsipv6uplink) 90 | ip -6 route add "$5" via "$2" dev "$3" metric "$4" table "$BFSTABLE" proto "$BFSPROTO" from ::/128 91 | exec ip -6 route add "$5" via "$2" dev "$3" metric "$4" table "$BFSTABLE" proto "$BFSPROTO" from "$1" 92 | ;; 93 | 94 | bfsipv4prefix) 95 | exec ip -4 route add throw "$1" proto $BFSPROTO metric 2147483645 96 | ;; 97 | 98 | bfsipv4uplink) 99 | exec ip -4 route add "$5" via "$2" dev "$3" metric "$4" table "$BFSTABLE" proto "$BFSPROTO" onlink 100 | ;; 101 | 102 | esac 103 | -------------------------------------------------------------------------------- /generic/multicast.script: -------------------------------------------------------------------------------- 1 | #! /bin/sh 2 | 3 | # 4 | # Called by hnetd in order to control the multicast daemon 5 | # 6 | # Call syntax: 7 | # 8 | # status 9 | # 10 | # init (start|stop) 11 | # 12 | # rpa (ADDRESS|none) (OLD-ADDRESS|none) 13 | # 14 | # bp ifname (add|remove) ADDRESS PORT 15 | # 16 | # proxy ifname (on|off) [ADDRESS PORT] 17 | # 18 | # pim ifname (on|off) 19 | # 20 | 21 | echo "[multicast.script] $*" 22 | 23 | error () { 24 | echo "This script must be run by hnetd." 25 | exit 1 26 | } 27 | 28 | if [ "$(id -u)" -ne "0" ] || [ "$1" = "" ]; then 29 | error 30 | fi 31 | 32 | status () { 33 | EXE=`which pimbd` 34 | [ -n "$EXE" ] && exit 0 || exit 1 35 | } 36 | 37 | init () { 38 | if [ -f "/etc/init.d/pimbd" ]; then 39 | if [ "$1" = "start" ]; then 40 | /etc/init.d/pimbd restart 41 | else 42 | /etc/init.d/pimbd stop 43 | fi 44 | else 45 | if [ -f "/tmp/pimbd-hnet.pid" ]; then 46 | kill `cat /tmp/pimbd-hnet.pid` 47 | rm /tmp/pimbd-hnet.pid 48 | fi 49 | if [ "$1" = "start" ]; then 50 | pimbd -S -p /tmp/pimbd-hnet.pid & 51 | fi 52 | fi 53 | } 54 | 55 | rpa () { 56 | if [ "$2" != "none" ]; then 57 | pimbc rpa flush "$2" 58 | pimbc rpa set "$2" rpl_jp off 59 | fi 60 | if [ "$1" != "none" ]; then 61 | pimbc rpa add "$1" "ff00::/8" 62 | pimbc rpa add "$1" "224.0.0.0/4" 63 | pimbc rpa set "$1" rpl_jp on 64 | fi 65 | } 66 | 67 | bp () { 68 | case "$1" in 69 | add) pimbc proxy add "$2" "$3" ;; 70 | remove) pimbc proxy del "$2" "$3" ;; 71 | *) error ;; 72 | esac 73 | } 74 | 75 | proxy () { 76 | case "$2" in 77 | on) pimbc link set "$1" proxy "$3" "$4" ;; 78 | off) pimbc link set "$1" proxy off ;; 79 | *) error ;; 80 | esac 81 | } 82 | 83 | pim () { 84 | case "$2" in 85 | on) pimbc link set "$1" pim on ssbidir on mld on igmp on hello 500ms ;; 86 | off) pimbc link set "$1" pim off ssbidir off mld off igmp off ;; 87 | *) error ;; 88 | esac 89 | } 90 | 91 | case "$1" in 92 | status) shift 1; status $@;; 93 | init) shift 1; init $@;; 94 | rpa) shift 1; rpa $@;; 95 | bp) shift 1; bp $@;; 96 | proxy) shift 1; proxy $@;; 97 | pim) shift 1; pim $@;; 98 | *) error;; 99 | esac 100 | 101 | exit 0; -------------------------------------------------------------------------------- /generic/ohp.script: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | #-*-sh-*- 3 | # 4 | # $Id: ohp-script $ 5 | # 6 | # Author: Markus Stenberg 7 | # 8 | # Copyright (c) 2014 cisco Systems, Inc. 9 | # 10 | # Created: Fri Jan 17 11:46:30 2014 mstenber 11 | # Last modified: Mon Feb 3 14:39:15 2014 mstenber 12 | # Edit time: 15 min 13 | # 14 | 15 | # This is a minimalistic init.d-like start/stop script for 16 | # ohybridproxy. However, as ohybridproxy receives its configuration 17 | # via command line, the 'start' command is also equivalent to 18 | # 'restart', and has a bunch of extra arguments.. 19 | 20 | OHP=ohybridproxy 21 | 22 | start() { 23 | $OHP $* & 24 | } 25 | 26 | stop() { 27 | killall -9 $OHP 28 | } 29 | 30 | 31 | CMD=$1 32 | # For debugging purposes 33 | LOGNAME=`basename $0` 34 | echo "$*" | logger -t "$LOGNAME" 35 | case $CMD in 36 | start) 37 | shift 38 | stop 39 | start $* 40 | ;; 41 | stop) 42 | stop 43 | ;; 44 | *) 45 | echo "Only start [config]/stop supported" 46 | exit 1 47 | ;; 48 | esac 49 | -------------------------------------------------------------------------------- /generic/pcp.script: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | #-*-sh-*- 3 | # 4 | # $Id: pcp-script $ 5 | # 6 | # Author: Markus Stenberg 7 | # 8 | # Copyright (c) 2014 cisco Systems, Inc. 9 | # 10 | # Created: Fri Jan 17 11:46:30 2014 mstenber 11 | # Last modified: Fri May 30 13:27:57 2014 mstenber 12 | # Edit time: 16 min 13 | # 14 | 15 | # Copied from ohp-script.. Same idea. Just prod minimalist-pcproxy as 16 | # needed, hoping the miniupnpd is taken care of by the system. 17 | 18 | PCP=minimalist-pcproxy 19 | 20 | start() { 21 | $PCP $* & 22 | } 23 | 24 | stop() { 25 | killall -9 $PCP 26 | } 27 | 28 | 29 | CMD=$1 30 | # For debugging purposes 31 | LOGNAME=`basename $0` 32 | echo "$*" | logger -t "$LOGNAME" 33 | case $CMD in 34 | start) 35 | shift 36 | stop 37 | start $* 38 | ;; 39 | stop) 40 | stop 41 | ;; 42 | *) 43 | echo "Only start [config]/stop supported" 44 | exit 1 45 | ;; 46 | esac 47 | -------------------------------------------------------------------------------- /generic/tunnel.script: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | # Funny NAT workaround for linux kernel 4 | NATCAST4=192.0.2.9 5 | 6 | if [ "$1" = init ]; then 7 | which modprobe && modprobe l2tp_eth 8 | set -e 9 | ip addr replace "$2"/128 dev lo preferred_lft 0 10 | ip addr replace "$NATCAST4"/32 dev lo preferred_lft 0 11 | iptables -t nat -I PREROUTING -d "$3" -j DNAT --to-destination "$NATCAST4" 12 | 13 | else 14 | ifname=hnet-$1 15 | ip link set $ifname down 16 | ip l2tp del session tunnel_id $1 session_id $2 17 | ip l2tp del tunnel tunnel_id $1 18 | 19 | if [ "$4" != 0 ]; then 20 | ip l2tp add tunnel local $3 remote $6 tunnel_id $1 peer_tunnel_id $4 encap udp udp_sport $1 udp_dport $4 21 | ip l2tp add session name $ifname tunnel_id $1 session_id $2 peer_session_id $5 22 | ip link set $ifname up mtu 1280 23 | fi 24 | fi 25 | -------------------------------------------------------------------------------- /generic/utils.script: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | update_resolv() { 4 | local service="$1" 5 | local interface="$2" 6 | local dns="$3" 7 | 8 | ( 9 | flock 9 10 | FILE=`tempfile` 11 | if [ ! -d /run/resolvconf ] 12 | then 13 | grep -v "# ${service}:${interface}" /etc/resolv.conf > $FILE 14 | fi 15 | for c in $dns; do 16 | echo "nameserver $c # ${service}:${interface}" >> $FILE 17 | done 18 | if [ -d /run/resolvconf ] 19 | then 20 | resolvconf -a ${interface}.${service} < $FILE 21 | rm -f $FILE 22 | else 23 | chmod a+r $FILE 24 | mv $FILE /etc/resolv.conf 25 | fi 26 | ) 9>/tmp/resolv.conf.lock 27 | rm -f /tmp/resolv.conf.lock $FILE 28 | } 29 | 30 | 31 | -------------------------------------------------------------------------------- /hnetd_wireshark.lua: -------------------------------------------------------------------------------- 1 | -- -*-lua-*- 2 | -- 3 | -- $Id: hnetd_wireshark.lua $ 4 | -- 5 | -- Author: Markus Stenberg 6 | -- 7 | -- Copyright (c) 2013 cisco Systems, Inc. 8 | -- 9 | -- Created: Tue Dec 3 11:13:05 2013 mstenber 10 | -- Last modified: Sat Jul 14 08:36:53 2018 mstenber 11 | -- Edit time: 123 min 12 | -- 13 | 14 | -- This is Lua module which provides VERY basic dissector for TLVs we 15 | -- transmit. 16 | 17 | -- Usage: wireshark -X lua_script:hnetd_wireshark.lua 18 | 19 | p_hncp = Proto("hncp", "Homenet Control Protocol") 20 | 21 | local f_id = ProtoField.uint16('hncp.id', 'TLV id') 22 | local f_len = ProtoField.uint16('hncp.len', 'TLV len') 23 | local f_data = ProtoField.bytes('hncp.data', 'TLV data') 24 | 25 | local f_nid_hash = ProtoField.bytes('hncp.node_identifier_hash', 26 | 'Node identifier') 27 | local f_data_hash = ProtoField.bytes('hncp.data_hash', 28 | 'Node data hash') 29 | local f_network_hash = ProtoField.bytes('hncp.network_hash', 30 | 'Network state hash') 31 | 32 | local f_lid = ProtoField.uint32('hncp.llid', 'Local link identifier') 33 | local f_rlid = ProtoField.uint32('hncp.rlid', 'Remote link identifier') 34 | local f_upd = ProtoField.uint32('hncp.update_number', 'Update number') 35 | local f_ms = ProtoField.uint32('hncp.ms_since_origination', 36 | 'Time since origination (ms)') 37 | local f_interval_ms = ProtoField.uint32('hncp.keepalive_interval', 38 | 'Keep-alive interval (ms)') 39 | 40 | p_hncp.fields = {f_id, f_len, f_data, 41 | f_nid_hash, f_data_hash, f_network_hash, 42 | f_lid, f_rlid, f_upd, f_ms, f_interval_ms} 43 | 44 | local tlvs = { 45 | -- dncp content 46 | [1]={name='req-net-state'}, 47 | [2]={name='req-node-state', 48 | contents={{4, f_nid_hash}}, 49 | }, 50 | [3]={name='endpoint-id', 51 | contents={{4, f_nid_hash}, 52 | {4, f_lid}}, 53 | }, 54 | [4]={name='net-state', 55 | contents={{8, f_network_hash}}}, 56 | [5]={name='node-state', 57 | contents={{4, f_nid_hash}, 58 | {4, f_upd}, 59 | {4, f_ms}, 60 | {8, f_data_hash}, 61 | }, 62 | recurse=true 63 | }, 64 | -- historic never deployed [6]={name='custom'}, 65 | -- historic never deployed [7]={name='fragment-count'}, 66 | [8]={name='neighbor', contents={{4, f_nid_hash}, 67 | {4, f_rlid}, 68 | {4, f_lid}, 69 | }, 70 | }, 71 | [9]={name='keepalive-interval', contents={{4, f_lid}, 72 | {4, f_interval_ms}}, 73 | }, 74 | [10]={name='trust-verdict'}, 75 | 76 | -- hncp content 77 | [32]={name='version'}, 78 | [33]={name='external-connection', contents={}, recurse=true}, 79 | [34]={name='delegated-prefix'}, 80 | [35]={name='assigned-prefix'}, 81 | [36]={name='router-address'}, 82 | [37]={name='dhcpv4-options'}, 83 | [38]={name='dhcpv6-options'}, 84 | 85 | [39]={name='dns-delegated-zone'}, 86 | [40]={name='dns-domain-name'}, 87 | [41]={name='dns-node-name'}, 88 | [42]={name='managed-psk'}, 89 | [43]={name='prefix-policy'}, 90 | 91 | -- does not seem to exist anymore in the wild: 92 | -- [199]={name='routing-protocol'}, 93 | } 94 | 95 | 96 | function p_hncp.dissector(buffer, pinfo, tree) 97 | pinfo.cols.protocol = 'hncp' 98 | 99 | local rec_decode 100 | local function data_decode(ofs, left, tlv, tree) 101 | for i, v in ipairs(tlv.contents) 102 | do 103 | local elen, ef = unpack(v) 104 | if elen > left 105 | then 106 | tree:append_text(string.format(' (!!! missing data - %d > %d (%s))', 107 | elen, left, v)) 108 | return 109 | end 110 | tree:add(ef, buffer(ofs, elen)) 111 | left = left - elen 112 | ofs = ofs + elen 113 | end 114 | if tlv.recurse 115 | then 116 | rec_decode(ofs, left, tree) 117 | end 118 | end 119 | 120 | rec_decode = function (ofs, left, tree) 121 | if left < 4 122 | then 123 | return 124 | end 125 | local partial 126 | local rid = buffer(ofs, 2) 127 | local rlen = buffer(ofs+2, 2) 128 | local id = rid:uint() 129 | local len = rlen:uint() 130 | local bs = '' 131 | local ps = '' 132 | local tlv = tlvs[id] or {} 133 | if tlv.name 134 | then 135 | bs = ' (' .. tlv.name .. ')' 136 | end 137 | if (len + 4) > left 138 | then 139 | len = left - 4 140 | ps = ' (partial)' 141 | partial = true 142 | end 143 | local tree2 = tree:add(buffer(ofs, len + 4), 144 | string.format('TLV %d%s - %d value bytes%s', 145 | id, bs, len, ps)) 146 | if partial 147 | then 148 | return 149 | end 150 | local fid = tree2:add(f_id, rid) 151 | fid:append_text(bs) 152 | local flen = tree2:add(f_len, rlen) 153 | if len > 0 154 | then 155 | local fdata = tree2:add(f_data, buffer(ofs + 4, len)) 156 | if tlv.contents 157 | then 158 | -- skip the tlv header (that's why +- 4) 159 | data_decode(ofs + 4, len, tlv, fdata) 160 | end 161 | end 162 | -- recursively decode the rest too, hrr :) 163 | 164 | -- (note that we have to round it up to next /4 boundary; stupid 165 | -- alignment..) 166 | len = math.floor((len + 3)/4) * 4 167 | 168 | rec_decode(ofs + len + 4, left - len - 4, tree) 169 | end 170 | rec_decode(0, buffer:len(), tree:add(p_hncp, buffer())) 171 | end 172 | 173 | -- register as udp dissector 174 | udp_table = DissectorTable.get("udp.port") 175 | udp_table:add(8231, p_hncp) 176 | -------------------------------------------------------------------------------- /openwrt/autowifi.script: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | echo "Auto-Wifi Script: $@" >> /tmp/autowifi.log 4 | 5 | wlan="wlan$2" 6 | ssid="$3" 7 | password="$4" 8 | 9 | if [ "$1" = "addssid" ]; then 10 | uci -q batch <<-EOT 11 | set wireless.@wifi-device[$2].disabled=0 12 | set wireless.@wifi-iface[$2].mode='ap' 13 | set wireless.@wifi-iface[$2].ssid=$ssid 14 | set wireless.@wifi-iface[$2].network='hw$2' 15 | set network.hw$2='interface' 16 | set network.hw$2.proto='hnet' 17 | set network.hw$2.slice='$slice' 18 | EOT 19 | if [ -n "$password" -o "$password" = "none" ]; then 20 | uci set wireless.@wifi-iface[$2].encryption='psk2' 21 | uci set wireless.@wifi-iface[$2].key="$password" 22 | else 23 | uci delete wireless.@wifi-iface[$2].encryption 24 | uci delete wireless.@wifi-iface[$2].key 25 | fi 26 | uci commit wireless 27 | uci commit network 28 | reload_config 29 | elif [ "$1" = "delssid" ]; then 30 | uci set wireless.@wifi-device[$2].disabled=1 31 | uci delete network.hw$2 32 | uci commit wireless 33 | uci commit network 34 | reload_config 35 | fi 36 | -------------------------------------------------------------------------------- /openwrt/hnet.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | . /lib/functions.sh 4 | . ../netifd-proto.sh 5 | init_proto "$@" 6 | 7 | 8 | proto_hnet_init_config() { 9 | proto_config_add_string 'dhcpv4_clientid' 10 | proto_config_add_string 'dhcpv6_clientid' 11 | proto_config_add_string 'mode' 12 | proto_config_add_string 'reqaddress' 13 | proto_config_add_string 'reqprefix' 14 | proto_config_add_string 'prefix' 15 | proto_config_add_string 'link_id' 16 | proto_config_add_string 'iface_id' 17 | proto_config_add_string 'ip6assign' 18 | proto_config_add_string 'ip4assign' 19 | proto_config_add_string 'disable_pa' 20 | proto_config_add_string 'ula_default_router' 21 | proto_config_add_string 'dnsname' 22 | proto_config_add_int 'keepalive_interval' 23 | proto_config_add_int 'trickle_k' 24 | proto_config_add_boolean 'ip4uplinklimit' 25 | } 26 | 27 | proto_hnet_setup() { 28 | local interface="$1" 29 | local device="$2" 30 | 31 | local dhcpv4_clientid dhcpv6_clientid reqaddress reqprefix prefix link_id iface_id ip6assign ip4assign disable_pa ula_default_router keepalive_interval trickle_k dnsname mode ip4uplinklimit 32 | json_get_vars dhcpv4_clientid dhcpv6_clientid reqaddress reqprefix prefix link_id iface_id ip6assign ip4assign disable_pa ula_default_router keepalive_interval trickle_k dnsname mode ip4uplinklimit 33 | 34 | logger -t proto-hnet "proto_hnet_setup $device/$interface" 35 | 36 | if [ "$interface" = "lan" -o "$interface" = "wan" -o "$interface" = "wan6" ]; then 37 | logger -t proto-hnet "Interface names 'lan' and 'wan' are restricted for security reasons and do not offer border discovery!" 38 | if [ "$interface" = "lan" ]; then 39 | mode=internal 40 | else 41 | mode=external 42 | fi 43 | fi 44 | 45 | proto_init_update "*" 1 46 | 47 | proto_add_data 48 | json_add_int created 1 49 | [ -n "$mode" ] && json_add_string mode $mode 50 | [ "$disable_pa" = "1" ] && json_add_boolean disable_pa 1 51 | [ "$ula_default_router" = "1" ] && json_add_boolean ula_default_router 1 52 | [ -n "$keepalive_interval" ] && json_add_int keepalive_interval $keepalive_interval 53 | [ -n "$trickle_k" ] && json_add_int trickle_k $trickle_k 54 | [ -n "$ip6assign" ] && json_add_string ip6assign "$ip6assign" 55 | [ -n "$ip4assign" ] && json_add_string ip4assign "$ip4assign" 56 | [ -n "$reqaddress" ] && json_add_string reqaddress "$reqaddress" 57 | [ -n "$reqprefix" ] && json_add_string reqprefix "$reqprefix" 58 | [ -n "$dhcpv6_clientid" ] && json_add_string dhcpv6_clientid "$dhcpv6_clientid" 59 | [ "$ip4uplinklimit" = 1 ] && json_add_boolean ip4uplinklimit 1 60 | 61 | json_add_string dnsname "${dnsname:-$interface}" 62 | json_add_array prefix 63 | for p in $prefix; do 64 | json_add_string "" "$p" 65 | done 66 | json_close_array 67 | json_add_string link_id "$link_id" 68 | json_add_array iface_id 69 | for p in $iface_id; do 70 | json_add_string "" "$p" 71 | done 72 | json_close_array 73 | proto_close_data 74 | 75 | proto_send_update "$interface" 76 | } 77 | 78 | proto_hnet_teardown() { 79 | local interface="$1" 80 | local device="$2" 81 | 82 | # nop? this? hmm 83 | logger -t proto-hnet "proto_hnet_teardown $device/$interface" 84 | } 85 | 86 | add_protocol hnet 87 | 88 | -------------------------------------------------------------------------------- /openwrt/luci/luasrc/controller/hnet.lua: -------------------------------------------------------------------------------- 1 | module("luci.controller.hnet", package.seeall) 2 | 3 | function index() 4 | entry({"admin", "status", "hnet"}, template("hnet-status"), _("Homenet"), 50).dependent=false 5 | entry({"admin", "status", "hnet-dump"}, call("get_hnet_dump")).dependent=false 6 | entry({"admin", "network", "hnet"}, cbi("admin_network/hnet"), _("Homenet"), 50) 7 | end 8 | 9 | function get_hnet_dump() 10 | luci.http.prepare_content("application/json") 11 | luci.http.write(luci.util.exec("ubus call hnet dump 2> /dev/null || echo '{\"error\": \"ubus call failed\"}'")) 12 | end 13 | 14 | -------------------------------------------------------------------------------- /openwrt/luci/luasrc/model/cbi/admin_network/hnet.lua: -------------------------------------------------------------------------------- 1 | --[[ 2 | LuCI - Lua Configuration Interface 3 | 4 | Copyright 2014 Steven Barth 5 | 6 | Licensed under the Apache License, Version 2.0 (the "License"); 7 | you may not use this file except in compliance with the License. 8 | You may obtain a copy of the License at 9 | 10 | http://www.apache.org/licenses/LICENSE-2.0 11 | 12 | $Id$ 13 | ]]-- 14 | 15 | m = Map("hnet", translate("Homenet"), 16 | translate("Overrides for global homenet settings")) 17 | 18 | s = m:section(NamedSection, "pa", "pa", translate("Prefix Assignment")) 19 | s.addremove = false 20 | 21 | s:option(Value, "ulaprefix", translate("ULA-Prefix")) 22 | s:option(Value, "ip4prefix", translate("IPv4-Prefix")) 23 | 24 | s = m:section(NamedSection, "sd", "sd", translate("Service Discovery")) 25 | s:option(Value, "router_name", translate("Router Name")) 26 | s:option(Value, "domain_name", translate("Domain Name")) 27 | 28 | s = m:section(NamedSection, "wifi", "wifi", translate("Auto-Wifi (Unstable feature)")) 29 | s:option(Flag, "enable", translate("Enable automatic ssid configuration")) 30 | s:option(Value, "ssid", translate("SSID")) 31 | pw = s:option(Value, "password", translate("Password")) 32 | pw.password = true 33 | 34 | m.on_after_commit = function() luci.sys.call("/etc/init.d/hnetd reload") end 35 | 36 | return m 37 | -------------------------------------------------------------------------------- /openwrt/luci/luasrc/view/hnet-status.htm: -------------------------------------------------------------------------------- 1 | <%+header%> 2 |

<%:Homenet Status%>

3 | 4 |
<%:Click on a node of the graph to view detailed information.%>
5 | 6 |
7 |
8 |
9 | 10 |
11 |
12 | 13 |
14 |
15 |
16 |
17 | 18 | 19 | 62 | <%+footer%> 63 | 64 | 65 | -------------------------------------------------------------------------------- /run_coverage.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash -ue 2 | #-*-sh-*- 3 | # 4 | # $Id: run_coverage.sh $ 5 | # 6 | # Author: Markus Stenberg 7 | # 8 | # Copyright (c) 2013 cisco Systems, Inc. 9 | # 10 | # Created: Mon Dec 2 11:07:59 2013 mstenber 11 | # Last modified: Mon Dec 2 11:09:09 2013 mstenber 12 | # Edit time: 1 min 13 | # 14 | 15 | # Note: This requires lcov 16 | lcov -z -d . 17 | make check 18 | lcov -c -d . -o coverage.info 19 | genhtml coverage.info --output-directory coverage 20 | 21 | # Open is OS X-ism; I'm not sure what'd be Linux-ism, sensible-browser? 22 | open coverage/index.html 23 | -------------------------------------------------------------------------------- /run_net_stress.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash -ue 2 | #-*-sh-*- 3 | # 4 | # $Id: run_net_stress.sh $ 5 | # 6 | # Author: Markus Stenberg 7 | # 8 | # Copyright (c) 2014 cisco Systems, Inc. 9 | # 10 | # Created: Wed Jul 16 20:26:49 2014 mstenber 11 | # Last modified: Wed Apr 29 16:23:36 2015 mstenber 12 | # Edit time: 12 min 13 | # 14 | 15 | ITERATIONS=1000 16 | JOBS=13 17 | 18 | cmake -DL_LEVEL=1 . 19 | make test_hncp_net 20 | for i in `seq $ITERATIONS` 21 | do 22 | ( ./test_hncp_net -r $i $* 2>&1 | grep -q SUCCESS && echo -n "." || echo $i ) & 23 | if (( $i % $JOBS == 0)) ; then wait ; fi 24 | done 25 | echo 26 | cmake -DL_LEVEL=7 . 27 | make test_hncp_net 28 | 29 | -------------------------------------------------------------------------------- /src/bitops.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Author: Pierre Pfister 3 | * 4 | * Copyright (c) 2014-2015 Cisco Systems, Inc. 5 | */ 6 | 7 | #include "bitops.h" 8 | 9 | #include 10 | #include //cpu_to_xx 11 | 12 | static uint8_t bbytecpy_masks[9] = 13 | {0x00, 0x80, 0xc0, 0xe0, 0xf0, 0xf8, 0xfc, 0xfe, 0xff}; 14 | 15 | void bbytecpy (uint8_t *dst, const uint8_t *src, 16 | uint8_t frombit, uint8_t nbits) 17 | { 18 | uint8_t mask = bbytecpy_masks[nbits] >> frombit; 19 | uint8_t v = *src & mask; 20 | *dst = (*dst & ~mask) | v; 21 | } 22 | 23 | void bmemcpy(void *dst, const void *src, 24 | size_t frombit, size_t nbits) 25 | { 26 | // First bit that should not be copied 27 | size_t tobit = frombit + nbits; 28 | 29 | size_t frombyte = frombit >> 3; 30 | size_t tobyte = tobit >> 3; 31 | size_t nbyte = tobyte - frombyte; 32 | uint8_t frombitrem = frombit & 0x07; 33 | uint8_t tobitrem = tobit & 0x07; 34 | 35 | dst+=frombyte; 36 | src+=frombyte; 37 | 38 | if(!nbyte) { 39 | bbytecpy(dst, src, frombitrem, nbits); 40 | return; 41 | } 42 | 43 | if(frombitrem) { 44 | bbytecpy(dst, src, frombitrem, 8 - frombitrem); 45 | dst += 1; 46 | src += 1; 47 | nbyte -= 1; 48 | } 49 | 50 | memcpy(dst, src, nbyte); 51 | 52 | if(tobitrem) 53 | bbytecpy(dst + nbyte, src + nbyte, 0, tobitrem); 54 | } 55 | 56 | void bmemcpy_shift(void *dst, size_t dst_start, 57 | const void *src, size_t src_start, 58 | size_t nbits) 59 | { 60 | dst += dst_start >> 3; 61 | dst_start &= 0x7; 62 | src += src_start >> 3; 63 | src_start &= 0x7; 64 | 65 | if(dst_start == src_start) { 66 | bmemcpy(dst, src, dst_start, nbits); 67 | } else { 68 | while(nbits) { 69 | uint8_t interm = *((uint8_t *)src); 70 | uint8_t n; 71 | int8_t shift = src_start - dst_start; 72 | if(shift > 0) { 73 | interm <<= shift; 74 | n = 8 - src_start; 75 | if(n > nbits) 76 | n = nbits; 77 | bbytecpy(dst, &interm, dst_start, n); 78 | dst_start += n; 79 | src_start = 0; 80 | src++; 81 | } else { 82 | interm >>= -shift; 83 | n = 8 - dst_start; 84 | if(n > nbits) 85 | n = nbits; 86 | bbytecpy(dst, &interm, dst_start, n); 87 | dst_start = 0; 88 | dst++; 89 | src_start += n; 90 | } 91 | nbits -= n; 92 | } 93 | } 94 | } 95 | 96 | 97 | int bmemcmp(const void *m1, const void *m2, size_t bitlen) 98 | { 99 | size_t bytes = bitlen >> 3; 100 | int r; 101 | if( (r = memcmp(m1, m2, bytes)) ) 102 | return r; 103 | 104 | uint8_t rembit = bitlen & 0x07; 105 | if(!rembit) 106 | return 0; 107 | 108 | uint8_t *p1 = ((uint8_t *) m1) + bytes; 109 | uint8_t *p2 = ((uint8_t *) m2) + bytes; 110 | uint8_t mask = ((uint8_t)0xff) << (8 - rembit); 111 | 112 | return ((int) (*p1 & mask)) - ((int) (*p2 & mask)); 113 | } 114 | 115 | int bmemcmp_s(const uint8_t *m1, const uint8_t *m2, size_t start, size_t nbits) 116 | { 117 | if(!nbits) 118 | return 0; 119 | 120 | size_t mod = start % 8; 121 | size_t first = start / 8; 122 | size_t last = (start + nbits) / 8; 123 | 124 | m1 += first; 125 | m2 += first; 126 | if(first == last) { 127 | uint8_t mask = (0xff >> mod); 128 | mask >>= (8 - nbits - mod); 129 | mask <<= (8 - nbits - mod); 130 | return (m1[0] & mask) - (m2[0] & mask); 131 | } else if(mod) { 132 | uint8_t mask = (0xff >> mod); 133 | int b1 = m1[0] & mask; 134 | int b2 = m2[0] & mask; 135 | int i; 136 | if((i = b1 - b2)) 137 | return i; 138 | m1++; 139 | m2++; 140 | nbits -= (8-mod); 141 | } 142 | return nbits?bmemcmp(m1, m2, nbits):0; 143 | } 144 | 145 | static const uint64_t m1 = 0x5555555555555555; //binary: 0101... 146 | static const uint64_t m2 = 0x3333333333333333; //binary: 00110011.. 147 | static const uint64_t m4 = 0x0f0f0f0f0f0f0f0f; //binary: 4 zeros, 4 ones ... 148 | static const uint64_t hff = 0xffffffffffffffff; //binary: all ones 149 | static const uint64_t h01 = 0x0101010101010101; //the sum of 256 to the power of 0,1,2,3... 150 | static inline int popcount_3(uint64_t x) { 151 | x -= (x >> 1) & m1; //put count of each 2 bits into those 2 bits 152 | x = (x & m2) + ((x >> 2) & m2); //put count of each 4 bits into those 4 bits 153 | x = (x + (x >> 4)) & m4; //put count of each 8 bits into those 8 bits 154 | return (x * h01)>>56; //returns left 8 bits of x + (x<<8) + (x<<16) + (x<<24) + ... 155 | } 156 | 157 | size_t hamming_distance_64(const uint64_t *m1, const uint64_t *m2, size_t nbits) 158 | { 159 | size_t dst = 0; 160 | size_t n = nbits / 64; 161 | size_t rem = nbits % 64; 162 | size_t i; 163 | for(i = 0; i < n; i++) 164 | dst += popcount_3(m1[i] ^ m2[i]); 165 | 166 | if(rem) 167 | dst += popcount_3(be64_to_cpu(m1[n] ^ m2[n]) & (hff << (64 - rem))); 168 | 169 | return dst; 170 | } 171 | 172 | size_t hamming_minimize(const uint8_t *max, const uint8_t *target, 173 | uint8_t *dst, size_t start_len, size_t nbits) 174 | { 175 | //todo: We actually don't need getbit/setbit 176 | //A better approach would be to look for the first bit 177 | //set to 1 in max, and see whether the target 178 | //is greater or lower at that point. If greater 179 | //just flip that bit and copy the rest of the target. 180 | 181 | size_t ret = 0; 182 | size_t end = start_len + nbits; 183 | size_t n = start_len; 184 | while(n != end && !(max[n/8] & (0x80 >> (n%8)))) { 185 | if(target[n/8] & (0x80 >> (n%8))) 186 | ret ++; 187 | n++; 188 | } 189 | bmemcpy(dst, max, start_len, n - start_len); 190 | 191 | nbits = end - n; 192 | if(nbits) { 193 | bmemcpy(dst, target, n, nbits); 194 | if(bmemcmp_s(max, target, n, nbits) < 0) { 195 | dst[n/8] = dst[n/8] & ~(0x80 >> (n%8)); 196 | ret++; 197 | } 198 | } 199 | return ret; 200 | } 201 | 202 | static const char hexdigits[] = "0123456789abcdef"; 203 | static const int8_t hexvals[] = { 204 | -1, -1, -1, -1, -1, -1, -1, -1, -1, -2, -2, -1, -1, -2, -1, -1, 205 | -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 206 | -2, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 207 | 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, -1, -1, -1, -1, -1, -1, 208 | -1, 10, 11, 12, 13, 14, 15, -1, -1, -1, -1, -1, -1, -1, -1, -1, 209 | -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 210 | -1, 10, 11, 12, 13, 14, 15, -1, -1, -1, -1, -1, -1, -1, -1, -1, 211 | -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 212 | }; 213 | 214 | ssize_t unhexlify(uint8_t *dst, size_t len, const char *src) 215 | { 216 | size_t c; 217 | for (c = 0; c < len && src[0] && src[1]; ++c) { 218 | int8_t x = (int8_t)*src++; 219 | int8_t y = (int8_t)*src++; 220 | if (x < 0 || (x = hexvals[x]) < 0 221 | || y < 0 || (y = hexvals[y]) < 0) 222 | return -1; 223 | dst[c] = x << 4 | y; 224 | while (((int8_t)*src) < 0 || 225 | (*src && hexvals[(uint8_t)*src] < 0)) 226 | src++; 227 | } 228 | 229 | return c; 230 | } 231 | 232 | char *hexlify(char *dst, const uint8_t *src, size_t len) 233 | { 234 | char *ret = dst; 235 | for (size_t i = 0; i < len; ++i) { 236 | *dst++ = hexdigits[src[i] >> 4]; 237 | *dst++ = hexdigits[src[i] & 0x0f]; 238 | } 239 | *dst = 0; 240 | return ret; 241 | } 242 | -------------------------------------------------------------------------------- /src/bitops.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Author: Pierre Pfister 3 | * 4 | * Copyright (c) 2014-2015 Cisco Systems, Inc. 5 | * 6 | * Advanced bitwise operations. 7 | * 8 | */ 9 | 10 | #ifndef BITOPS_H_ 11 | #define BITOPS_H_ 12 | 13 | #include 14 | #include 15 | #include 16 | 17 | /** 18 | * Copy bits from one byte to another. 19 | * 20 | * Bits are indexed from greatest to lowest significance. 21 | * 22 | * @param dst Destination byte. 23 | * @param src Source byte (Can be equal to dst byte). 24 | * @parem frombit First copied bit index (From 0 to 7). 25 | * @param nbits Number of copied bits (From 0 to 8). 26 | */ 27 | void bbytecpy (uint8_t *dst, const uint8_t *src, 28 | uint8_t frombit, uint8_t nbits); 29 | 30 | /** 31 | * Compare two prefixes of same bit length. 32 | * 33 | * @param m1 First compared value. 34 | * @param m2 Second compared value. 35 | * @param bitlen Number of bits to be compared. 36 | * 37 | * @return 38 | * 0 if bitlen first bits are equal in m1 and m2. 39 | * A positive value if the first different bit is greater in m1. 40 | * A negative value if the first different bit is greater in m2. 41 | */ 42 | int bmemcmp(const void *m1, const void *m2, size_t bitlen); 43 | 44 | /** 45 | * Compares two bit strings starting from an arbitrary position. 46 | * 47 | * @param m1 First compared value buffer. 48 | * @param m2 Second compared value buffer. 49 | * @param start Starting bit index. Previous bits are ignored. 50 | * @param nbits Number of bits to be compared. 51 | * 52 | * @return 53 | * 0 if bits from 'start' to 'start + nbits' are equal in m1 and m2. 54 | * A positive value if the first different bit is greater in m1. 55 | * A negative value if the first different bit is greater in m2. 56 | */ 57 | int bmemcmp_s(const uint8_t *m1, const uint8_t *m2, size_t start, size_t nbits); 58 | 59 | /** 60 | * Copy bits from one buffer to another. 61 | * 62 | * @param dst Buffer to which bits are copied. 63 | * @param src Buffer from which bits are copied. 64 | * @param frombit First copied bit index. 65 | * @param nbits Number of copied bits. 66 | */ 67 | void bmemcpy(void *dst, const void *src, 68 | size_t frombit, size_t nbits); 69 | 70 | /** 71 | * Copy unaligned bit sequences from one buffer to another. 72 | * 73 | * @param dst Buffer to which bits are copied. 74 | * @param dst_start Bit index of the first replaced bit in dst. 75 | * @param src Buffer from which bits are copied. 76 | * @param nbits Number of copied bits. 77 | */ 78 | void bmemcpy_shift(void *dst, size_t dst_start, 79 | const void *src, size_t src_start, 80 | size_t nbits); 81 | 82 | /** 83 | * Computes the Hamming distance between char arrays. 84 | * 85 | * @param m1 First array 86 | * @param m2 Second array 87 | * @param nbits Number of considered bits for the distance computation. 88 | */ 89 | size_t hamming_distance_64(const uint64_t *m1, const uint64_t *m2, size_t nbits); 90 | 91 | /** 92 | * Provides the value and distance which minimizes the Hamming distance with a given 93 | * target value, while remaining lower than the maximum value. 94 | * Bits which index is under start_len are ignored and not modified. 95 | * 96 | * @param max Array representing the maximum value. 97 | * @param target The array with respect to which the hamming distance is computed. 98 | * @param dst Where the resulting array is written. 99 | * @param start_len First considered bit. 100 | * Previous bits from all arays are just ignored and left unmodified. 101 | * @param nbits The number of considered bits. 102 | * @return The Hamming distance between the returned dst and target. 103 | */ 104 | size_t hamming_minimize(const uint8_t *max, const uint8_t *target, 105 | uint8_t *dst, size_t start_len, size_t nbits); 106 | 107 | ssize_t unhexlify(uint8_t *dst, size_t len, const char *src); 108 | char *hexlify(char *dst, const uint8_t *src, size_t len); 109 | 110 | #endif 111 | -------------------------------------------------------------------------------- /src/dhcp.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2015 Cisco Systems, Inc. 3 | */ 4 | #ifndef DHCP_H_ 5 | #define DHCP_H_ 6 | 7 | enum dhcpv4_opt { 8 | DHCPV4_OPT_NETMASK = 1, 9 | DHCPV4_OPT_ROUTER = 3, 10 | DHCPV4_OPT_DNSSERVER = 6, 11 | DHCPV4_OPT_DOMAIN = 15, 12 | DHCPV4_OPT_MTU = 26, 13 | DHCPV4_OPT_BROADCAST = 28, 14 | DHCPV4_OPT_NTPSERVER = 42, 15 | DHCPV4_OPT_LEASETIME = 51, 16 | DHCPV4_OPT_MESSAGE = 53, 17 | DHCPV4_OPT_SERVERID = 54, 18 | DHCPV4_OPT_RENEW = 58, 19 | DHCPV4_OPT_REBIND = 59, 20 | DHCPV4_OPT_IPADDRESS = 50, 21 | DHCPV4_OPT_HOSTNAME = 10, 22 | DHCPV4_OPT_REQUEST = 17, 23 | DHCPV4_OPT_VENDOR_SPECIFIC_INFORMATION = 125, 24 | DHCPV4_OPT_END = 255, 25 | }; 26 | 27 | 28 | struct dhcpv4_option { 29 | uint8_t type; 30 | uint8_t len; 31 | uint8_t data[]; 32 | }; 33 | 34 | 35 | #define dhcpv4_for_each_option(start, end, opt)\ 36 | for (opt = (struct dhcpv4_option*)(start); \ 37 | &opt[1] <= (struct dhcpv4_option*)(end) && \ 38 | &opt->data[opt->len] <= (end); \ 39 | opt = (struct dhcpv4_option*)&opt->data[opt->len]) 40 | 41 | 42 | #endif /* DHCP_H_ */ 43 | -------------------------------------------------------------------------------- /src/dhcpv6.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2015 Cisco Systems, Inc. 3 | */ 4 | #ifndef DHCPV6_H_ 5 | #define DHCPV6_H_ 6 | 7 | #include 8 | #include 9 | 10 | enum dhcvp6_opt { 11 | DHCPV6_OPT_DNS_SERVERS = 23, 12 | DHCPV6_OPT_DNS_DOMAIN = 24, 13 | #ifdef EXT_PREFIX_CLASS 14 | /* draft-bhandari-dhc-class-based-prefix, not yet standardized */ 15 | DHCPV6_OPT_PREFIX_CLASS = EXT_PREFIX_CLASS, 16 | #endif 17 | }; 18 | 19 | #ifdef EXT_PREFIX_CLASS 20 | struct dhcpv6_prefix_class { 21 | uint16_t type; 22 | uint16_t len; 23 | uint16_t class; 24 | }; 25 | #endif 26 | 27 | #define dhcpv6_for_each_option(start, end, otype, olen, odata)\ 28 | for (uint8_t *_o = (uint8_t*)(start); _o + 4 <= (uint8_t*)(end) &&\ 29 | ((otype) = _o[0] << 8 | _o[1]) && ((odata) = (void*)&_o[4]) &&\ 30 | ((olen) = _o[2] << 8 | _o[3]) + (odata) <= (uint8_t*)(end); \ 31 | _o += 4 + (_o[2] << 8 | _o[3])) 32 | 33 | 34 | #endif 35 | -------------------------------------------------------------------------------- /src/dncp_proto.h: -------------------------------------------------------------------------------- 1 | /* 2 | * $Id: dncp_proto.h $ 3 | * 4 | * Author: Markus Stenberg 5 | * 6 | * Copyright (c) 2013-2015 cisco Systems, Inc. 7 | * 8 | * Created: Wed Nov 27 18:17:46 2013 mstenber 9 | * Last modified: Mon Aug 31 13:04:23 2015 mstenber 10 | * Edit time: 127 min 11 | * 12 | */ 13 | 14 | #pragma once 15 | 16 | #include 17 | #include 18 | 19 | /******************************************************************* TLV T's */ 20 | 21 | enum { 22 | /* Request TLVs (not to be really stored anywhere) */ 23 | DNCP_T_REQ_NET_STATE = 1, /* empty */ 24 | DNCP_T_REQ_NODE_STATE = 2, /* = just normal hash */ 25 | 26 | DNCP_T_NODE_ENDPOINT = 3, 27 | 28 | DNCP_T_NET_STATE = 4, /* = just normal hash, accumulated from node states so sensible to send later */ 29 | DNCP_T_NODE_STATE = 5, 30 | /* was: DNCP_T_CUSTOM = 6, */ 31 | /* was: DNCP_T_FRAGMENT_COUNT = 7 */ 32 | DNCP_T_PEER = 8, 33 | DNCP_T_KEEPALIVE_INTERVAL = 9, 34 | DNCP_T_TRUST_VERDICT = 10 35 | }; 36 | 37 | #define TLV_SIZE sizeof(struct tlv_attr) 38 | 39 | #define DNCP_SHA256_LEN 32 40 | 41 | typedef struct __packed { 42 | unsigned char buf[DNCP_SHA256_LEN]; 43 | } dncp_sha256_s, *dncp_sha256; 44 | 45 | /* DNCP_T_REQ_NET_STATE has no content */ 46 | 47 | /* DNCP_T_REQ_NODE_STATE has only (node identifier) hash */ 48 | 49 | typedef uint32_t ep_id_t; 50 | 51 | /* DNCP_T_NODE_ENDPOINT */ 52 | typedef struct __packed { 53 | /* dncp_node_id_s node_id; variable length, encoded here */ 54 | ep_id_t ep_id; 55 | } dncp_t_ep_id_s, *dncp_t_ep_id; 56 | 57 | /* DNCP_T_NET_STATE has only (network state) hash */ 58 | 59 | /* DNCP_T_NODE_STATE */ 60 | typedef struct __packed { 61 | /* dncp_node_id_s node_id; variable length, encoded here */ 62 | uint32_t update_number; 63 | uint32_t ms_since_origination; 64 | /* + hash + + optional node data after this */ 65 | } dncp_t_node_state_s, *dncp_t_node_state; 66 | 67 | /* DNCP_T_CUSTOM custom data, with H-64 of URI at start to identify type TBD */ 68 | 69 | /* DNCP_T_PEER */ 70 | typedef struct __packed { 71 | /* dncp_node_id_s node_id; variable length, encoded here */ 72 | uint32_t peer_ep_id; 73 | uint32_t ep_id; 74 | } dncp_t_peer_s, *dncp_t_peer; 75 | 76 | /* DNCP_T_KEEPALIVE_INTERVAL */ 77 | typedef struct __packed { 78 | uint32_t ep_id; 79 | uint32_t interval_in_ms; 80 | } dncp_t_keepalive_interval_s, *dncp_t_keepalive_interval; 81 | 82 | typedef enum { 83 | DNCP_VERDICT_NONE = -1, /* internal, should not be stored */ 84 | DNCP_VERDICT_NEUTRAL = 0, 85 | DNCP_VERDICT_CACHED_POSITIVE = 1, 86 | DNCP_VERDICT_CACHED_NEGATIVE = 2, 87 | DNCP_VERDICT_CONFIGURED_POSITIVE = 3, 88 | DNCP_VERDICT_CONFIGURED_NEGATIVE = 4, 89 | NUM_DNCP_VERDICT = 5 90 | } dncp_trust_verdict; 91 | 92 | #define DNCP_T_TRUST_VERDICT_CNAME_LEN 64 93 | 94 | /* DNCP_T_TRUST_VERDICT */ 95 | typedef struct __packed { 96 | uint8_t verdict; 97 | uint8_t reserved[3]; 98 | dncp_sha256_s sha256_hash; 99 | char cname[]; 100 | } dncp_t_trust_verdict_s, *dncp_t_trust_verdict; 101 | -------------------------------------------------------------------------------- /src/dncp_trust.h: -------------------------------------------------------------------------------- 1 | /* 2 | * $Id: dncp_trust.h $ 3 | * 4 | * Author: Markus Stenberg 5 | * 6 | * Copyright (c) 2014-2015 cisco Systems, Inc. 7 | * 8 | * Created: Thu Nov 20 11:46:44 2014 mstenber 9 | * Last modified: Wed Jun 17 11:31:35 2015 mstenber 10 | * Edit time: 34 min 11 | * 12 | */ 13 | 14 | #pragma once 15 | 16 | #include "dncp.h" 17 | #include "dncp_proto.h" 18 | #include "platform.h" 19 | 20 | //#include 21 | #include 22 | 23 | typedef struct dncp_trust_struct dncp_trust_s, *dncp_trust; 24 | 25 | dncp_trust dncp_trust_create(dncp o, const char *filename); 26 | void dncp_trust_destroy(dncp_trust t); 27 | 28 | /* 29 | * Get effective trust verdict for the hash. This operation is 30 | * immediate and does NOT result in state changes in DNCP. 31 | * 32 | * The cname is also retrieved if available and the pointer is 33 | * non-NULL; the size of the pointed buffer must be >= 34 | * DNCP_T_TRUST_VERDICT_CNAME_LEN. 35 | */ 36 | int dncp_trust_get_verdict(dncp_trust t, const dncp_sha256 h, char *cname); 37 | 38 | /* 39 | * Publish the request for a verdict into DNCP. 40 | */ 41 | void dncp_trust_request_verdict(dncp_trust t, 42 | const dncp_sha256 h, 43 | const char *cname); 44 | /* 45 | * Add/Update local configured trust to have this particular entry 46 | * too. 47 | */ 48 | void dncp_trust_set(dncp_trust t, const dncp_sha256 h, 49 | uint8_t verdict, const char *cname); 50 | 51 | /* 52 | * Find next hash available. NULL's next is first hash, so this is a 53 | * looping iterator. 54 | */ 55 | dncp_sha256 dncp_trust_next_hash(dncp_trust t, const dncp_sha256 prev); 56 | 57 | #define dncp_trust_for_each_hash(t, h) \ 58 | for (h = dncp_trust_next_hash(t, NULL) ; h ; h = dncp_trust_next_hash(t, h)) 59 | 60 | /* 61 | * Parse trust verdict (printable form) to value, if any. 62 | * 63 | * This is the interface given to clients; therefore, this set may not 64 | * be complete set of supported verdicts.. 65 | */ 66 | dncp_trust_verdict dncp_trust_verdict_from_string(const char *verdict); 67 | 68 | /* 69 | * Get printable representation of a trust verdict. 70 | */ 71 | const char *dncp_trust_verdict_to_string(dncp_trust_verdict verdict); 72 | 73 | 74 | /* 75 | * Register trust multicall 76 | */ 77 | void dncp_trust_register_multicall(void); 78 | 79 | #ifdef DTLS 80 | 81 | /* 82 | * Callback that can be used with dtls_set_unknown_cert_cb 83 | * (context must be dncp_trust instance) 84 | */ 85 | bool dncp_trust_dtls_unknown_cb(dtls d, dtls_cert cert, void *context); 86 | #endif /* DTLS */ 87 | -------------------------------------------------------------------------------- /src/dncp_util.h: -------------------------------------------------------------------------------- 1 | /* 2 | * $Id: dncp_util.h $ 3 | * 4 | * Author: Markus Stenberg 5 | * 6 | * Copyright (c) 2015 cisco Systems, Inc. 7 | * 8 | * Created: Mon Jun 8 11:36:06 2015 mstenber 9 | * Last modified: Thu Jun 11 09:49:51 2015 mstenber 10 | * Edit time: 5 min 11 | * 12 | */ 13 | 14 | #pragma once 15 | 16 | #include "prefix.h" 17 | #include "dncp_proto.h" 18 | #include "tlv.h" 19 | 20 | /* Assorted utility macros needed by dncp code. Split away from 21 | * dncp_i.h. Note: some that depend on dncp_i content remain within 22 | * that header file (this + dncp.h are essentially 'public' part of 23 | * dncp headers). */ 24 | 25 | #define DNCP_STRUCT_REPR(i) HEX_REPR(&i, sizeof(i)) 26 | 27 | #define SA6_F "[%s]:%d%%%d" 28 | #define SA6_D(sa) \ 29 | sa ? ADDR_REPR(&(sa)->sin6_addr) : "(NULL SA6)", \ 30 | sa ? ntohs((sa)->sin6_port) : 0, \ 31 | sa ? (sa)->sin6_scope_id : 0 32 | 33 | #define ROUND_BITS_TO_BYTES(b) (((b) + 7) / 8) 34 | #define ROUND_BYTES_TO_4BYTES(b) ((((b) + 3) / 4) * 4) 35 | 36 | static inline dncp_t_trust_verdict 37 | dncp_tlv_trust_verdict(const struct tlv_attr *a) 38 | { 39 | if (tlv_id(a) != DNCP_T_TRUST_VERDICT) 40 | return NULL; 41 | if (tlv_len(a) < sizeof(dncp_t_trust_verdict_s) + 1) 42 | return NULL; 43 | if (tlv_len(a) > sizeof(dncp_t_trust_verdict_s) + DNCP_T_TRUST_VERDICT_CNAME_LEN) 44 | return NULL; 45 | const char *data = (const char *)tlv_data(a); 46 | /* Make sure it is also null terminated */ 47 | if (data[tlv_len(a)-1]) 48 | return NULL; 49 | return (dncp_t_trust_verdict)tlv_data(a); 50 | } 51 | 52 | #define dncp_update_number_gt(a,b) \ 53 | ((((uint32_t)(a) - (uint32_t)(b)) & ((uint32_t)1<<31)) != 0) 54 | 55 | #define dncp_update_tlv(o, t, d, dlen, elen, is_add) \ 56 | do { \ 57 | if (is_add) \ 58 | dncp_add_tlv(o, t, d, dlen, elen); \ 59 | else \ 60 | dncp_remove_tlv_matching(o, t, d, dlen); \ 61 | } while(0) 62 | 63 | static inline void sockaddr_in6_set(struct sockaddr_in6 *sin6, 64 | struct in6_addr *a6, 65 | uint16_t port) 66 | { 67 | memset(sin6, 0, sizeof(*sin6)); 68 | #ifdef SIN6_LEN 69 | sin6->sin6_len = sizeof(*sin6); 70 | #endif /* SIN6_LEN */ 71 | sin6->sin6_family = AF_INET6; 72 | if (a6) 73 | sin6->sin6_addr = *a6; 74 | sin6->sin6_port = htons(port); 75 | } 76 | 77 | #define DNCP_NODE_REPR(n) dncp_node_repr(n, alloca(128)) 78 | -------------------------------------------------------------------------------- /src/dtls.h: -------------------------------------------------------------------------------- 1 | /* 2 | * $Id: dtls.h $ 3 | * 4 | * Author: Markus Stenberg 5 | * 6 | * Copyright (c) 2014-2015 cisco Systems, Inc. 7 | * 8 | * Created: Thu Oct 16 10:50:18 2014 mstenber 9 | * Last modified: Tue May 26 07:59:27 2015 mstenber 10 | * Edit time: 36 min 11 | * 12 | */ 13 | 14 | #pragma once 15 | 16 | #include "hnetd.h" 17 | 18 | #include 19 | 20 | /* 21 | * This is 'dtls' module, which hides most of the ugliness of OpenSSL 22 | * (DTLS) API with simple, socket-like API. 23 | * 24 | * It assumes uloop is available to juggle the various file 25 | * descriptors. 26 | * 27 | * The API is more or less same as what dncp_io provides; however, 28 | * underneath, a number of sockets are juggled. 29 | * 30 | * Basic usage: 31 | * 1. create 32 | * 2. .. configure things (psk/cert, callbacks, ..) 33 | * 3. start 34 | * 4. .. do things .. (send, or recvfrom as needed, possibly triggered by cb) 35 | * 5. destroy 36 | */ 37 | 38 | #ifdef DTLS_OPENSSL 39 | typedef struct x509_st *dtls_cert; 40 | #else 41 | #error 42 | #endif /* DTLS_OPENSSL */ 43 | 44 | typedef struct dtls_struct *dtls; 45 | typedef void (*dtls_readable_cb)(dtls d, void *context); 46 | typedef bool (*dtls_unknown_cb)(dtls d, dtls_cert cert, void *context); 47 | 48 | /* Create/destroy instance. */ 49 | dtls dtls_create(uint16_t port); 50 | void dtls_start(); 51 | void dtls_destroy(dtls d); 52 | 53 | typedef struct { 54 | /* 55 | * All limits specified here are 'non-zero => enforce, zero => use default'. 56 | */ 57 | 58 | /* 59 | * Per-packet processing limits (which is easy attack vector, given we do 60 | * relatively expensive operations even on first packet due to 61 | * braindeath that is the DTLS API). 62 | */ 63 | 64 | /* 65 | * Set the acceptable packets per second to process. Anything more 66 | * than this will be silently dropped. 67 | */ 68 | int input_pps; 69 | 70 | /* 71 | * How many seconds a connection can be idle before it is eliminated. 72 | */ 73 | int connection_idle_limit_seconds; 74 | 75 | /* 76 | * Maximum number of connections in non-DATA state 77 | */ 78 | int num_non_data_connections; 79 | 80 | /* 81 | * Maximum number of connections in DATA state 82 | */ 83 | int num_data_connections; 84 | 85 | } dtls_limits_s, *dtls_limits; 86 | 87 | void dtls_set_limits(dtls d, dtls_limits limits); 88 | 89 | 90 | /* Callback to call when dtls has new data. */ 91 | void dtls_set_readable_cb(dtls d, dtls_readable_cb cb, void *cb_context); 92 | 93 | /* Authentication scheme 1 - PSK */ 94 | 95 | /* Set 'global' pre-shared key to use / expect other side to use. */ 96 | bool dtls_set_psk(dtls d, const char *psk, size_t psk_len); 97 | 98 | /* Authentication scheme 2/3 shared requirement - local side setup */ 99 | 100 | /* Set local authentication information */ 101 | bool dtls_set_local_cert(dtls d, const char *certfile, const char *pkfile); 102 | 103 | /* Authentication scheme 2 - PKI approach - provide either single file 104 | * with trusted cert(s), or directory with trusted certs. */ 105 | bool dtls_set_verify_locations(dtls d, const char *path, const char *dir); 106 | 107 | /* Authentication scheme 3 - instead of using PKI, declare verdicts on 108 | * certificates on our own. The return value of 'true' from the 109 | * callback indicates we trust a certificate. */ 110 | void dtls_set_unknown_cert_cb(dtls d, dtls_unknown_cb cb, void *cb_context); 111 | 112 | 113 | 114 | /* Send/receive data. */ 115 | ssize_t dtls_recv(dtls d, 116 | struct sockaddr_in6 **src, 117 | struct sockaddr_in6 **dst, 118 | void *buf, size_t len); 119 | 120 | ssize_t dtls_send(dtls o, 121 | const struct sockaddr_in6 *src, 122 | const struct sockaddr_in6 *dst, 123 | void *buf, size_t len); 124 | 125 | /* Certificate handling utilities */ 126 | bool dtls_cert_to_pem_buf(dtls_cert cert, char *buf, int buf_len); 127 | int dtls_cert_to_der_buf(dtls_cert cert, unsigned char *buf, int buf_len); 128 | void dtls_cert_hash_sha256(dtls_cert cert, unsigned char *buf); 129 | -------------------------------------------------------------------------------- /src/exeq.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Author: Pierre Pfister 3 | * 4 | * Copyright (c) 2014-2015 Cisco Systems, Inc. 5 | * 6 | */ 7 | 8 | #include "exeq.h" 9 | 10 | #include 11 | #include 12 | #include 13 | #include 14 | 15 | #include "hnetd.h" 16 | 17 | /* One eweq task in the queue */ 18 | struct exeq_task { 19 | struct list_head le; 20 | char *args[]; 21 | /* Additional data first contains the array of pointers 22 | * provided to execv: {arg1_p, arg2_p, arg3_p, NULL} 23 | * Then, it contains all the strings that are used in the 24 | * previous array: arg1:arg2:arg3 25 | */ 26 | }; 27 | 28 | static void exeq_start_maybe(struct exeq *e) 29 | { 30 | if(e->process.pending || list_empty(&e->tasks)) 31 | return; 32 | 33 | struct exeq_task *t = list_first_entry(&e->tasks, struct exeq_task, le); 34 | pid_t pid = fork(); 35 | if (pid == 0) { 36 | execv(t->args[0], t->args); 37 | L_ERR("execv error: %s\n", strerror(errno)); 38 | _exit(128); 39 | } 40 | L_DEBUG("exeq_run %s", t->args[0]); 41 | for (int i = 1 ; t->args[i] ; i++) 42 | L_DEBUG(" %s", t->args[i]); 43 | 44 | e->process.pid = pid; 45 | if(uloop_process_add(&e->process)) 46 | L_ERR("Could not add process %d to uloop", pid); 47 | list_del(&t->le); 48 | free(t); 49 | } 50 | 51 | static void _process_handler(struct uloop_process *c, int ret) 52 | { 53 | struct exeq *e = container_of(c, struct exeq, process); 54 | if(ret) 55 | L_WARN("Child process %d exited with status %d", c->pid, ret); 56 | else 57 | L_DEBUG("Child process %d terminated normally.", c->pid, ret); 58 | exeq_start_maybe(e); 59 | } 60 | 61 | /* Add a task to the queue. 62 | * The arguments are copied and can therefore be freed after the call. */ 63 | int exeq_add(struct exeq *e, char **args) 64 | { 65 | size_t datalen = 0; 66 | struct exeq_task *task; 67 | size_t arg_cnt; 68 | char *str; 69 | for(arg_cnt = 0; args[arg_cnt] ; arg_cnt++) 70 | datalen += strlen(args[arg_cnt]) + 1; 71 | 72 | if(!(task = malloc(sizeof(*task) + (arg_cnt + 1) * sizeof(char *) + datalen))) { 73 | L_ERR("exeq_add: malloc failed"); 74 | return -1; 75 | } 76 | 77 | str = (char *)&task->args[arg_cnt + 1]; 78 | for(arg_cnt = 0; args[arg_cnt]; arg_cnt++) { 79 | strcpy(str, args[arg_cnt]); 80 | task->args[arg_cnt] = str; 81 | str += strlen(args[arg_cnt]) + 1; 82 | } 83 | task->args[arg_cnt] = NULL; 84 | 85 | list_add_tail(&task->le, &e->tasks); 86 | exeq_start_maybe(e); 87 | return 0; 88 | } 89 | 90 | void exeq_init(struct exeq *e) 91 | { 92 | memset(&e->process, 0, sizeof(*e)); 93 | e->process.cb = _process_handler; 94 | INIT_LIST_HEAD(&e->tasks); 95 | } 96 | 97 | void exeq_term(struct exeq *e) 98 | { 99 | struct exeq_task *t, *ts; 100 | list_for_each_entry_safe(t, ts, &e->tasks, le) 101 | free(t); 102 | 103 | uloop_process_delete(&e->process); 104 | } 105 | 106 | -------------------------------------------------------------------------------- /src/exeq.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Author: Pierre Pfister 3 | * 4 | * Copyright (c) 2014-2015 Cisco Systems, Inc. 5 | * 6 | * This file provides a process execution fifo. 7 | * It uses execv and will not execute the next task before 8 | * the previous one has finished. 9 | */ 10 | 11 | #ifndef EXEQ_H_ 12 | #define EXEQ_H_ 13 | 14 | #include 15 | #include 16 | 17 | /* A single execution queue structure */ 18 | struct exeq { 19 | struct uloop_process process; 20 | struct list_head tasks; 21 | }; 22 | 23 | /* Initializes a queue structure */ 24 | void exeq_init(struct exeq *); 25 | 26 | /* Add a task to the queue. 27 | * The arguments are copied and can therefore be freed after the call. 28 | * Returns 0 on success. -errorcode on error. */ 29 | int exeq_add(struct exeq *, char **args); 30 | 31 | /* Cancels the execution queue. 32 | * (Does not interrupt the current process if currently running) */ 33 | void exeq_term(struct exeq *e); 34 | 35 | #endif /* EXEQ_H_ */ 36 | -------------------------------------------------------------------------------- /src/hncp.h: -------------------------------------------------------------------------------- 1 | /* 2 | * $Id: hncp.h $ 3 | * 4 | * Author: Markus Stenberg 5 | * 6 | * Copyright (c) 2014-2015 cisco Systems, Inc. 7 | * 8 | * Created: Tue Dec 23 13:30:01 2014 mstenber 9 | * Last modified: Wed Sep 9 10:36:31 2015 mstenber 10 | * Edit time: 20 min 11 | * 12 | */ 13 | 14 | #pragma once 15 | 16 | #include "hnetd.h" 17 | 18 | /* in6_addr */ 19 | #include 20 | 21 | /******************************** DNCP 'profile' values we stick in dncp_ext */ 22 | 23 | /* Intentionally renamed DNCP -> HNCP so that DNCP* ones can be used 24 | * in DNCP code. */ 25 | 26 | /* Minimum interval trickle starts at. The first potential time it may 27 | * send something is actually this divided by two. */ 28 | #define HNCP_TRICKLE_IMIN (HNETD_TIME_PER_SECOND / 5) 29 | 30 | /* Note: This is concrete value, NOT exponent # as noted in RFC. I 31 | * don't know why RFC does that.. We don't want to ever need do 32 | * exponentiation in any case in code. 64 seconds for the time being.. */ 33 | #define HNCP_TRICKLE_IMAX (40 * HNETD_TIME_PER_SECOND) 34 | 35 | /* Redundancy constant. */ 36 | #define HNCP_TRICKLE_K 1 37 | 38 | /* Size of the node identifier */ 39 | #define HNCP_NI_LEN 4 40 | 41 | /* Default keep-alive interval to be used; overridable by user config */ 42 | #define HNCP_KEEPALIVE_INTERVAL 20 * HNETD_TIME_PER_SECOND 43 | 44 | /* How many keep-alive periods can be missed until peer is declared M.I.A. */ 45 | /* (Note: This CANNOT be configured) */ 46 | #define HNCP_KEEPALIVE_MULTIPLIER 21/10 47 | 48 | /* Let's assume we use 64-bit version of MD5 for the time being.. */ 49 | #define HNCP_HASH_LEN 8 50 | 51 | /* How recently the node has to be reachable before prune kills it for real. */ 52 | #define HNCP_PRUNE_GRACE_PERIOD (60 * HNETD_TIME_PER_SECOND) 53 | 54 | /* Don't do node pruning more often than this. This should be less 55 | * than minimum Trickle interval, as currently non-valid state will 56 | * not be used to respond to node data requests about anyone except 57 | * self. */ 58 | #define HNCP_MINIMUM_PRUNE_INTERVAL (HNETD_TIME_PER_SECOND / 50) 59 | 60 | 61 | /****************************************** Other implementation definitions */ 62 | 63 | /* 0 = reserved link id. note it somewhere. */ 64 | 65 | #define HNCP_SD_DEFAULT_DOMAIN "home." 66 | 67 | /* How often we retry multicast joins? Once per second seems sane 68 | * enough. */ 69 | #define HNCP_REJOIN_INTERVAL (1 * HNETD_TIME_PER_SECOND) 70 | 71 | /*********************************************************************** API */ 72 | 73 | typedef struct hncp_struct hncp_s, *hncp; 74 | 75 | /** 76 | * Set IPv6 address for given interface. 77 | */ 78 | void hncp_set_ipv6_address(hncp o, const char *ifname, 79 | const struct in6_addr *a); 80 | 81 | /** 82 | * Set HNCP enabled on an interface. 83 | */ 84 | void hncp_set_enabled(hncp o, const char *ifname, bool enabled); 85 | 86 | /** 87 | * Get the IPv6 address for the given interface (if ifname is set) or any. 88 | */ 89 | struct in6_addr *hncp_get_ipv6_address(hncp o, const char *ifname); 90 | 91 | 92 | #ifdef DTLS 93 | 94 | #include "dtls.h" 95 | 96 | /** 97 | * Set the dtls instance to be used for securing HNCP traffic. 98 | */ 99 | void hncp_set_dtls(hncp o, dtls d); 100 | #endif /* DTLS */ 101 | 102 | /** 103 | * Fork+run an utility script, and return the PID. 104 | */ 105 | pid_t hncp_run(char *argv[]); 106 | 107 | /** 108 | * Create HNCP instance 109 | */ 110 | hncp hncp_create(void); 111 | 112 | 113 | /** 114 | * Destroy HNCP instances 115 | */ 116 | void hncp_destroy(hncp o); 117 | 118 | 119 | /* Intentionally include this only here, so that there are no 120 | * references to DNCP before. */ 121 | #include "dncp.h" 122 | 123 | /** 124 | * Get the DNCP instance pointer. 125 | */ 126 | dncp hncp_get_dncp(hncp o); 127 | -------------------------------------------------------------------------------- /src/hncp_dump.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Author: Pierre Pfister 3 | * 4 | * Copyright (c) 2014-2015 Cisco Systems, Inc. 5 | * 6 | * HNCP database dump tool. 7 | * 8 | */ 9 | 10 | #pragma once 11 | 12 | //#include 13 | #include 14 | 15 | #include "dncp.h" 16 | 17 | /* Returns a blob buffer containing hncp data or NULL in case of error. 18 | * Dump format is the following (Will be updated as new elements are added). 19 | * { 20 | * links : { 21 | * link-name : link-id (u32) 22 | * ... 23 | * } 24 | * nodes : { 25 | * node-id : NODE 26 | * ... 27 | * } 28 | * } 29 | * 30 | * NODE : Represents some router's data TLVs 31 | * { 32 | * version : version-number (u32) 33 | * user-agent : user-agent version (string) 34 | * update : update-number (u32) 35 | * age : age in ms (u64) 36 | * self : whether it is self (bool) 37 | * router-name : Router name (string) 38 | * domain : DNS domain name (string) 39 | * neighbors : [ NEIGHBOR ... ] 40 | * prefixes : [ PREFIX ... ] 41 | * uplinks : [ UPLINK ... ] 42 | * addresses : [ ADDRESS ... ] 43 | * zones : [ ZONE ... ] 44 | * routing : [ ROUTING ... ] 45 | * } 46 | * 47 | * NEIGHBOR : One router's neighbor 48 | * { 49 | * node-id : neighbor's node identifier (string/hex) 50 | * local-link : sender's link id (u32) 51 | * neighbor-link : neighbor's link id (u32) 52 | * } 53 | * 54 | * PREFIX : An assigned prefix 55 | * { 56 | * prefix : The prefix value (string/prefix) 57 | * authoritative : Whether it is authoritative (bool) 58 | * priority : The priority value (u8) 59 | * link : Sender's link id (u32) 60 | * } 61 | * 62 | * UPLINK : An uplink connexion 63 | * { 64 | * dhcpv6 : dhcpv6-data (string/hex) 65 | * dhcpv4 : dhcpv4-data (string/hex) 66 | * delegated : [DELEGATED ... ] 67 | * } 68 | * 69 | * DELEGATED : A delegated prefix 70 | * { 71 | * prefix : The prefix value (string/prefix) 72 | * valid : Valid lifetime when tlv is originated (u32) 73 | * preferred : Pref lifetime when tlv is originated (u32) 74 | * } 75 | * 76 | * ADDRESS : An assigned address 77 | * { 78 | * address : The address value (string/address) 79 | * link-id : Link on which the address is assigned (u32) 80 | * } 81 | * 82 | * ZONE : A domain name zone announced by the node 83 | * { 84 | * address : Server address (string/address) 85 | * search : Search bit (bool) 86 | * browse : Browse bit (bool) 87 | * domain : The domain name 88 | * } 89 | * 90 | * ROUTING : A routing protocol option 91 | * { 92 | * protocol : Protocol id (u8) 93 | * name : Protocol name (string) 94 | * preference : Protocol preference (u8) 95 | * } 96 | * 97 | */ 98 | void hd_init(dncp o); 99 | void hd_register_rpc(void); 100 | -------------------------------------------------------------------------------- /src/hncp_i.h: -------------------------------------------------------------------------------- 1 | /* 2 | * $Id: hncp_i.h $ 3 | * 4 | * Author: Markus Stenberg 5 | * 6 | * Copyright (c) 2014-2015 cisco Systems, Inc. 7 | * 8 | * Created: Tue Dec 23 13:33:03 2014 mstenber 9 | * Last modified: Wed Jun 10 10:15:10 2015 mstenber 10 | * Edit time: 21 min 11 | * 12 | */ 13 | 14 | #pragma once 15 | 16 | #include "hncp.h" 17 | #include "hncp_proto.h" 18 | #include "dncp_util.h" 19 | #include "udp46.h" 20 | 21 | /* TLV handling */ 22 | #include "prefix_utils.h" 23 | 24 | static inline hncp_t_assigned_prefix_header 25 | hncp_tlv_ap(const struct tlv_attr *a) 26 | { 27 | hncp_t_assigned_prefix_header ah; 28 | 29 | if (tlv_id(a) != HNCP_T_ASSIGNED_PREFIX || tlv_len(a) < sizeof(*ah)) 30 | return NULL; 31 | ah = tlv_data(a); 32 | if (tlv_len(a) < (sizeof(*ah) + ROUND_BITS_TO_BYTES(ah->prefix_length_bits)) 33 | || ah->prefix_length_bits > 128) 34 | return NULL; 35 | return ah; 36 | } 37 | 38 | static inline hncp_t_delegated_prefix_header 39 | hncp_tlv_dp(const struct tlv_attr *a) 40 | { 41 | hncp_t_delegated_prefix_header dh; 42 | 43 | if (tlv_id(a) != HNCP_T_DELEGATED_PREFIX || tlv_len(a) < sizeof(*dh)) 44 | return NULL; 45 | dh = tlv_data(a); 46 | if (tlv_len(a) < (sizeof(*dh) + ROUND_BITS_TO_BYTES(dh->prefix_length_bits)) 47 | || dh->prefix_length_bits > 128) 48 | return NULL; 49 | return dh; 50 | } 51 | 52 | static inline hncp_t_node_address 53 | hncp_tlv_ra(const struct tlv_attr *a) 54 | { 55 | if (tlv_id(a) != HNCP_T_NODE_ADDRESS 56 | || tlv_len(a) != sizeof(hncp_t_node_address_s)) 57 | return NULL; 58 | return tlv_data(a); 59 | } 60 | 61 | bool hncp_init(hncp o); 62 | void hncp_uninit(hncp o); 63 | 64 | struct hncp_struct { 65 | /* Our DNCP 'handle' */ 66 | dncp_ext_s ext; 67 | 68 | /* Actual DNCP instance pointer. */ 69 | dncp dncp; 70 | 71 | /* Multicast address */ 72 | struct in6_addr multicast_address; 73 | 74 | /* search domain provided to clients. */ 75 | /* (Shared between pa + sd, that's why it's here) */ 76 | char domain[DNS_MAX_ESCAPED_LEN]; 77 | 78 | /* The port number server is in */ 79 | uint16_t udp_port; 80 | 81 | /* Server's UDP46 */ 82 | udp46 u46_server; 83 | 84 | /* Timeout for doing 'something' in dncp_io. */ 85 | struct uloop_timeout timeout; 86 | 87 | #ifdef DTLS 88 | /* DTLS 'socket' abstraction, which actually hides two UDP sockets 89 | * (client and server) and N OpenSSL contexts tied to each of 90 | * them. */ 91 | dtls d; 92 | 93 | /* Trust consensus model of authz for DTLS is _not_ here; see 94 | * hncp_trust.[ch]. */ 95 | #endif /* DTLS */ 96 | }; 97 | 98 | 99 | struct hncp_bfs_head { 100 | /* List head for implementing BFS */ 101 | struct list_head head; 102 | 103 | /* Next-hop in path (also used to mark visited nodes) */ 104 | const struct in6_addr *next_hop; 105 | const struct in6_addr *next_hop4; 106 | const char *ifname; 107 | unsigned hopcount; 108 | }; 109 | 110 | typedef struct hncp_ep_struct hncp_ep_s, *hncp_ep; 111 | 112 | struct hncp_ep_struct { 113 | /* 'Best' address (if any) */ 114 | bool has_ipv6_address; 115 | struct in6_addr ipv6_address; 116 | 117 | /* Timeout used when joining.. */ 118 | struct uloop_timeout join_timeout; 119 | }; 120 | 121 | typedef struct hncp_node_struct hncp_node_s, *hncp_node; 122 | 123 | struct hncp_node_struct { 124 | /* Version of HNCP */ 125 | uint32_t version; 126 | 127 | /* Iterator to do bfs-traversal */ 128 | struct hncp_bfs_head bfs; 129 | }; 130 | 131 | 132 | #define dncp_get_hncp(o) container_of(o->ext, hncp_s, ext) 133 | -------------------------------------------------------------------------------- /src/hncp_io.h: -------------------------------------------------------------------------------- 1 | /* 2 | * $Id: hncp_io.h $ 3 | * 4 | * Author: Markus Stenberg 5 | * 6 | * Copyright (c) 2015 cisco Systems, Inc. 7 | * 8 | * Created: Tue May 26 07:10:55 2015 mstenber 9 | * Last modified: Wed May 27 10:32:30 2015 mstenber 10 | * Edit time: 0 min 11 | * 12 | */ 13 | 14 | #pragma once 15 | #include 16 | #include 17 | #include "dncp.h" 18 | 19 | bool hncp_io_init(hncp h); 20 | void hncp_io_uninit(hncp h); 21 | 22 | bool hncp_io_set_ifname_enabled(hncp h, const char *ifname, bool enabled); 23 | -------------------------------------------------------------------------------- /src/hncp_link.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2015 Cisco Systems, Inc. 3 | */ 4 | #ifndef SRC_HNCP_LINK_H_ 5 | #define SRC_HNCP_LINK_H_ 6 | 7 | #include "dncp.h" 8 | #include "dncp_proto.h" 9 | #include "hncp.h" 10 | #include "hncp_proto.h" 11 | 12 | struct hncp_link; 13 | 14 | enum hncp_link_elected { 15 | HNCP_LINK_NONE = 0, 16 | HNCP_LINK_LEGACY = 1 << 0, 17 | HNCP_LINK_HOSTNAMES = 1 << 1, 18 | HNCP_LINK_PREFIXDEL = 1 << 2, 19 | HNCP_LINK_MDNSPROXY = 1 << 3, 20 | HNCP_LINK_STATELESS = 1 << 4, 21 | }; 22 | 23 | struct hncp_link_config { 24 | int version; 25 | int cap_mdnsproxy; 26 | int cap_prefixdel; 27 | int cap_hostnames; 28 | int cap_legacy; 29 | char agent[32]; 30 | }; 31 | 32 | typedef struct __packed { 33 | unsigned char buf[HNCP_NI_LEN]; 34 | } hncp_node_id_s, *hncp_node_id; 35 | 36 | typedef struct { 37 | hncp_node_id_s node_id; 38 | uint32_t ep_id; 39 | } *hncp_ep_id, hncp_ep_id_s; 40 | 41 | struct hncp_link_user { 42 | struct list_head head; 43 | void (*cb_link)(struct hncp_link_user*, const char *ifname, 44 | hncp_ep_id peers, size_t peercnt); 45 | void (*cb_elected)(struct hncp_link_user*, const char *ifname, 46 | enum hncp_link_elected elected); 47 | }; 48 | 49 | struct hncp_link* hncp_link_create(dncp dncp, const struct hncp_link_config *conf); 50 | void hncp_link_destroy(struct hncp_link *l); 51 | 52 | void hncp_link_register(struct hncp_link *l, struct hncp_link_user *user); 53 | void hncp_link_unregister(struct hncp_link_user *user); 54 | 55 | #endif /* SRC_HNCP_LINK_H_ */ 56 | -------------------------------------------------------------------------------- /src/hncp_multicast.h: -------------------------------------------------------------------------------- 1 | /* 2 | * $Id: hncp_multicast.h $ 3 | * 4 | * Author: Markus Stenberg 5 | * 6 | * Copyright (c) 2015 cisco Systems, Inc. 7 | * 8 | * Created: Mon Feb 23 20:50:57 2015 mstenber 9 | * Last modified: Thu Jun 11 09:50:54 2015 mstenber 10 | * Edit time: 4 min 11 | * 12 | */ 13 | 14 | #pragma once 15 | 16 | #include "hncp.h" 17 | 18 | typedef struct hncp_multicast_struct hncp_multicast_s, *hncp_multicast; 19 | 20 | typedef struct { 21 | /* For the time being, only real content. */ 22 | const char *multicast_script; 23 | 24 | /* Eventually, could add e.g. support for choosing whether we can 25 | * even support being border proxy, or being RP.. */ 26 | } hncp_multicast_params_s, *hncp_multicast_params; 27 | 28 | hncp_multicast hncp_multicast_create(hncp h, hncp_multicast_params p); 29 | 30 | void hncp_multicast_destroy(hncp_multicast m); 31 | 32 | bool hncp_multicast_busy(hncp_multicast m); 33 | -------------------------------------------------------------------------------- /src/hncp_pa.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Author: Pierre Pfister 3 | * 4 | * Copyright (c) 2014-2015 Cisco Systems, Inc. 5 | * 6 | * This section implements Prefix Assignment related features from HNCP. 7 | * 8 | * - Prefix Assignment 9 | * - Address Assignment 10 | * - ULA and IPv4 prefix handling 11 | * - Prefix Delegation 12 | * 13 | */ 14 | 15 | #ifndef HNCP_PA_H_ 16 | #define HNCP_PA_H_ 17 | 18 | #include "hncp.h" 19 | #include "hncp_link.h" 20 | #include "prefix_utils.h" 21 | 22 | typedef struct hncp_pa_struct hncp_pa_s, *hncp_pa; 23 | 24 | hncp_pa hncp_pa_create(hncp hncp, struct hncp_link *hncp_link); 25 | void hncp_pa_destroy(hncp_pa hpa); 26 | 27 | /* Some way to list current available delegated prefixes. */ 28 | 29 | struct hncp_pa_dp { 30 | struct list_head le; 31 | struct prefix prefix; 32 | bool enabled; //dp should be ignored if not set 33 | bool local; //Whether it was generated locally or obtained through HNCP 34 | }; 35 | 36 | #define hncp_pa_for_each_dp(dp, hncp_pa) \ 37 | list_for_each_entry(dp, __hpa_get_dps(hncp_pa), le) \ 38 | if((dp)->enabled) 39 | 40 | /******************************** 41 | * Internal Interfaces * 42 | ********************************/ 43 | 44 | struct hncp_pa_iface_user { 45 | /* Called whenever a prefix/address is modified. */ 46 | void (*update_address)(struct hncp_pa_iface_user *i, const char *ifname, 47 | const struct in6_addr *addr, uint8_t plen, 48 | hnetd_time_t valid_until, hnetd_time_t preferred_until, 49 | uint8_t *dhcp_data, size_t dhcp_len, 50 | bool del); 51 | 52 | /* A delegated prefix was added or removed */ 53 | void (*update_dp)(struct hncp_pa_iface_user *, 54 | const struct hncp_pa_dp *dp, bool del); 55 | }; 56 | 57 | /** 58 | * Subscription for iface.c so it gets prefix and addresses callbacks. 59 | */ 60 | void hncp_pa_iface_user_register(hncp_pa hp, struct hncp_pa_iface_user *user); 61 | 62 | /******************************** 63 | * Configuration * 64 | ********************************/ 65 | 66 | /* 67 | * Prefix assignment behavior can be modified using these functions. 68 | */ 69 | 70 | /* Starts an update, waiting for new prefixes and addresses. */ 71 | void hncp_pa_conf_iface_update(hncp_pa hp, const char *ifname); 72 | 73 | /* Add a static prefix configuration. */ 74 | int hncp_pa_conf_prefix(hncp_pa hp, const char *ifname, 75 | const struct prefix *p, bool del); 76 | 77 | /* Add a static address configuration by the mean of the last bits of an 78 | * address. */ 79 | int hncp_pa_conf_address(hncp_pa hp, const char *ifname, 80 | const struct in6_addr *addr, uint8_t mask, 81 | const struct prefix *filter, bool del); 82 | 83 | /* Sets a link ID with its mask length. 84 | * mask = 0 will remove the link id. */ 85 | int hncp_pa_conf_set_link_id(hncp_pa hp, const char *ifname, uint32_t id, 86 | uint8_t mask); 87 | 88 | int hncp_pa_conf_set_ip4_plen(hncp_pa hp, const char *ifname, 89 | uint8_t ip4_plen); 90 | 91 | int hncp_pa_conf_set_ip6_plen(hncp_pa hp, const char *ifname, 92 | uint8_t ip6_plen); 93 | 94 | /* Removes all configuration which was not added or refreshed 95 | * since last update. */ 96 | void hncp_pa_conf_iface_flush(hncp_pa hp, const char *ifname); 97 | 98 | 99 | 100 | /* 101 | * ULA and IPv4 prefix generation behavior may be modified with the following API. 102 | */ 103 | 104 | struct hncp_pa_ula_conf 105 | { 106 | /* Enables ULA use 107 | * default = 1 */ 108 | char use_ula; 109 | 110 | /* Disable ULA when an ipv6 prefix is available 111 | * default = 1 */ 112 | char no_ula_if_glb_ipv6; 113 | 114 | /* Generates a random ula, and store it in stable storage. 115 | * default = 1 */ 116 | char use_random_ula; 117 | 118 | /* Sets the prefix length of randomly generated ula prefixes. 119 | * default = 48 */ 120 | char random_ula_plen; 121 | 122 | /* If not random, use that ULA prefix (must be ULA) 123 | * default = undef */ 124 | struct prefix ula_prefix; 125 | 126 | /* Enable IPv4 use 127 | * default = 1 */ 128 | char use_ipv4; 129 | 130 | /* Disable IPv4 when there is global ipv6 available 131 | * default = 0 */ 132 | char no_ipv4_if_glb_ipv6; 133 | 134 | /* Do not generate IPv4 prefix unless we have an uplink 135 | * connectivity. 136 | * default = 1 137 | */ 138 | char no_ipv4_if_no_uplink; 139 | 140 | /* When needed, use that v4 prefix 141 | * default = ::ffff:10.0.0.0/104 */ 142 | struct prefix v4_prefix; 143 | 144 | /* Valid lifetime for local prefixes (ula + ipv4) 145 | * default = 600 * HNETD_TIME_PER_SECOND */ 146 | hnetd_time_t local_valid_lifetime; 147 | 148 | /* Preferred lifetime for local prefixes 149 | * default = 300 * HNETD_TIME_PER_SECOND */ 150 | hnetd_time_t local_preferred_lifetime; 151 | 152 | /* A local prefix lifetime is update when 153 | * prefix.valid - local_update_delay <= now 154 | * This should be more than valid_lifetime - preferred_lifetime. 155 | * default = 330 * HNETD_TIME_PER_SECOND */ 156 | hnetd_time_t local_update_delay; 157 | }; 158 | 159 | void hncp_pa_ula_conf_default(struct hncp_pa_ula_conf *); 160 | int hncp_pa_ula_conf_set(hncp_pa hncp_pa, const struct hncp_pa_ula_conf *); 161 | 162 | 163 | 164 | /* 165 | * Stable storage file may be set and updated 166 | */ 167 | 168 | int hncp_pa_storage_set(hncp_pa hncp_pa, const char *path); 169 | 170 | 171 | /******************************** 172 | * Downstream Prefix Delegation * 173 | ********************************/ 174 | 175 | #define DHCP_DUID_MAX_LENGTH 20 176 | typedef struct hpa_lease_struct *hpa_lease, hpa_lease_s; 177 | typedef void (*hpa_pd_cb)(const struct in6_addr *prefix, uint8_t plen, 178 | hnetd_time_t valid_until, hnetd_time_t preferred_util, 179 | const char *dhcp_data, size_t dhcp_len, 180 | void *priv); 181 | 182 | hpa_lease hpa_pd_add_lease(hncp_pa hp, const char *duid, uint8_t hint_len, 183 | hpa_pd_cb, void *priv); 184 | void hpa_pd_del_lease(hncp_pa hp, hpa_lease l); 185 | 186 | /******************************** 187 | * Private * 188 | ********************************/ 189 | 190 | struct list_head *__hpa_get_dps(hncp_pa hpa); 191 | 192 | #endif /* HNCP_PA_H_ */ 193 | -------------------------------------------------------------------------------- /src/hncp_proto.h: -------------------------------------------------------------------------------- 1 | /* 2 | * $Id: hncp_proto.h $ 3 | * 4 | * Author: Markus Stenberg 5 | * 6 | * Copyright (c) 2014-2015 cisco Systems, Inc. 7 | * 8 | * Created: Tue Dec 23 13:52:55 2014 mstenber 9 | * Last modified: Fri Apr 15 11:16:25 2016 mstenber 10 | * Edit time: 21 min 11 | * 12 | */ 13 | 14 | #pragma once 15 | 16 | /***************************************** Structures encoded on top of DNCP */ 17 | 18 | enum { 19 | /* hncp draft itself */ 20 | HNCP_T_VERSION = 32, 21 | 22 | HNCP_T_EXTERNAL_CONNECTION = 33, 23 | HNCP_T_DELEGATED_PREFIX = 34, /* may contain TLVs */ 24 | HNCP_T_ASSIGNED_PREFIX = 35, /* may contain TLVs */ 25 | HNCP_T_NODE_ADDRESS = 36, /* router address */ 26 | HNCP_T_DHCP_OPTIONS = 37, /* contains just raw DHCP options */ 27 | HNCP_T_DHCPV6_OPTIONS = 38, /* contains just raw DHCPv6 options */ 28 | 29 | HNCP_T_DNS_DELEGATED_ZONE = 39, /* the 'beef' */ 30 | HNCP_T_DOMAIN_NAME = 40, /* non-default domain (very optional) */ 31 | HNCP_T_NODE_NAME = 41, /* node name (moderately optional) */ 32 | HNCP_T_MANAGED_PSK = 42, 33 | HNCP_T_PREFIX_POLICY = 43, 34 | 35 | /* The new values are picked from the 'private use' range (768 - 1023) */ 36 | 37 | /* draft-pfister-homenet-multicast */ 38 | HNCP_T_PIM_RPA_CANDIDATE = 881, 39 | HNCP_T_PIM_BORDER_PROXY = 882, 40 | 41 | /* Experimental feature - hncp_wifi.h */ 42 | HNCP_T_SSID = 793, 43 | }; 44 | 45 | /* HNCP_T_VERSION */ 46 | typedef struct __packed { 47 | uint8_t reserved1; 48 | uint8_t reserved2; 49 | uint8_t caps_mp; 50 | uint8_t caps_hl; 51 | char user_agent[]; 52 | } hncp_t_version_s, *hncp_t_version; 53 | 54 | /* HNCP_T_EXTERNAL_CONNECTION - just container, no own content */ 55 | 56 | /* HNCP_T_DELEGATED_PREFIX */ 57 | typedef struct __packed { 58 | uint32_t ms_valid_at_origination; 59 | uint32_t ms_preferred_at_origination; 60 | uint8_t prefix_length_bits; 61 | /* Prefix data, padded so that ends at 4 byte boundary (0s). */ 62 | uint8_t prefix_data[]; 63 | } hncp_t_delegated_prefix_header_s, *hncp_t_delegated_prefix_header; 64 | 65 | /* HNCP_T_ASSIGNED_PREFIX */ 66 | typedef struct __packed { 67 | ep_id_t ep_id; 68 | uint8_t flags; 69 | uint8_t prefix_length_bits; 70 | /* Prefix data, padded so that ends at 4 byte boundary (0s). */ 71 | uint8_t prefix_data[]; 72 | } hncp_t_assigned_prefix_header_s, *hncp_t_assigned_prefix_header; 73 | 74 | #define HNCP_T_ASSIGNED_PREFIX_FLAG_PRIORITY(flags) ((flags) & 0x0f) 75 | #define HNCP_T_ASSIGNED_PREFIX_FLAG(prio) (prio & 0x0f) 76 | 77 | /* HNCP_T_DHCP_OPTIONS - just container, no own content */ 78 | /* HNCP_T_DHCPV6_OPTIONS - just container, no own content */ 79 | 80 | /* HNCP_T_NODE_ADDRESS */ 81 | typedef struct __packed { 82 | ep_id_t ep_id; 83 | struct in6_addr address; 84 | } hncp_t_node_address_s, *hncp_t_node_address; 85 | 86 | /* HNCP_T_DNS_DELEGATED_ZONE */ 87 | typedef struct __packed { 88 | uint8_t address[16]; 89 | uint8_t flags; 90 | /* Label list in DNS encoding (no compression). */ 91 | uint8_t ll[]; 92 | } hncp_t_dns_delegated_zone_s, *hncp_t_dns_delegated_zone; 93 | 94 | #define HNCP_T_DNS_DELEGATED_ZONE_FLAG_SEARCH 1 95 | #define HNCP_T_DNS_DELEGATED_ZONE_FLAG_BROWSE 2 96 | #define HNCP_T_DNS_DELEGATED_ZONE_FLAG_LEGACY_BROWSE 4 97 | 98 | /* HNCP_T_DOMAIN_NAME has just DNS label sequence */ 99 | 100 | /* HNCP_T_NODE_NAME */ 101 | typedef struct __packed { 102 | struct in6_addr address; 103 | uint8_t name_length; 104 | char name[]; 105 | } hncp_t_node_name_s, *hncp_t_node_name; 106 | 107 | /* HNCP_T_PREFIX_POLICY */ 108 | typedef struct __packed { 109 | uint8_t type; 110 | uint8_t id[]; 111 | } hncp_t_prefix_policy_s, *hncp_t_prefix_policy; 112 | 113 | /* HNCP_T_PIM_RPA_CANDIDATE */ 114 | typedef struct __packed { 115 | struct in6_addr addr; 116 | } hncp_t_pim_rpa_candidate_s, *hncp_t_pim_rpa_candidate; 117 | 118 | /* HNCP_T_PIM_BORDER_PROXY */ 119 | typedef struct __packed { 120 | struct in6_addr addr; 121 | uint16_t port; 122 | } hncp_t_pim_border_proxy_s, *hncp_t_pim_border_proxy; 123 | 124 | /* HNCP_T_SSID */ 125 | #define HNCP_WIFI_SSID_LEN 31 126 | #define HNCP_WIFI_PASSWORD_LEN 31 127 | 128 | typedef struct __packed { 129 | uint8_t ssid[HNCP_WIFI_SSID_LEN + 1]; 130 | uint8_t password[HNCP_WIFI_PASSWORD_LEN + 1]; 131 | } hncp_t_wifi_ssid_s, *hncp_t_wifi_ssid; 132 | 133 | /**************************************************************** Addressing */ 134 | 135 | #define HNCP_PORT 8231 136 | #define HNCP_DTLS_SERVER_PORT 8232 137 | #define HNCP_MCAST_GROUP "ff02::11" 138 | 139 | #define HNCP_UCAST_DISCOVER6 "2001:1::8808" 140 | #define HNCP_UCAST_DISCOVER4 "192.0.0.9" 141 | 142 | /* Presence of HNCP_T_VERSION TLV indicates this version */ 143 | #define HNCP_T_VERSION_INDICATED_VERSION 1 144 | 145 | 146 | /* Pretty arbitrary. I wonder if all links can really guarantee MTU 147 | * size packets going through. However, IPv6 minimum MTU - size of 148 | * IPv6 header - size of UDP header (we consider only the payload 149 | * here) should work. */ 150 | #define HNCP_MAXIMUM_MULTICAST_SIZE (1280-40-8) 151 | 152 | /* Very arbitrary. On some implementations, I have seen some issues 153 | * with 10+kb frames so we use this for now. It MUST be significantly 154 | * more than 4k, due to how code is written at the moment. */ 155 | #define HNCP_MAXIMUM_UNICAST_SIZE 9000 156 | -------------------------------------------------------------------------------- /src/hncp_routing.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Author: Steven Barth 3 | * 4 | * Copyright (c) 2014-2015 cisco Systems, Inc. 5 | */ 6 | 7 | #pragma once 8 | 9 | #include "hncp.h" 10 | 11 | struct hncp_routing_struct; 12 | typedef struct hncp_routing_struct hncp_bfs_s, *hncp_bfs; 13 | 14 | hncp_bfs hncp_routing_create(hncp hncp, const char *script, bool incremental); 15 | void hncp_routing_destroy(hncp_bfs bfs); 16 | -------------------------------------------------------------------------------- /src/hncp_sd.h: -------------------------------------------------------------------------------- 1 | /* 2 | * $Id: hncp_sd.h $ 3 | * 4 | * Author: Markus Stenberg 5 | * 6 | * Copyright (c) 2014-2015 cisco Systems, Inc. 7 | * 8 | * Created: Tue Jan 14 20:09:23 2014 mstenber 9 | * Last modified: Tue Sep 15 11:01:26 2015 mstenber 10 | * Edit time: 10 min 11 | * 12 | */ 13 | 14 | #pragma once 15 | 16 | #include "dncp.h" 17 | #include "hncp_link.h" 18 | #include "hncp.h" 19 | 20 | typedef struct hncp_sd_struct hncp_sd_s, *hncp_sd; 21 | 22 | /* These are the parameters SD code uses. The whole structure's memory 23 | * is owned by the external party, and is assumed to be valid from 24 | * sd_create to sd_destroy. */ 25 | typedef struct hncp_sd_params_struct 26 | { 27 | /* Which script is used to prod at dnsmasq (required for SD) */ 28 | const char *dnsmasq_script; 29 | 30 | /* And where to store the dnsmasq.conf (required for SD) */ 31 | const char *dnsmasq_bonus_file; 32 | 33 | /* Which script is used to prod at ohybridproxy (required for SD) */ 34 | const char *ohp_script; 35 | 36 | /* DDZ changed script - helpful with e.g. zonestitcher; it is called 37 | * with the locally configured domain as the first argument, and then 38 | * each browse zone FQDN as separate arguments. */ 39 | const char *ddz_script; 40 | 41 | /* Which script is used to prod at minimalist-pcproxy (optional) */ 42 | const char *pcp_script; 43 | 44 | /* Router name (if desired, optional) */ 45 | const char *router_name; 46 | 47 | /* Domain name (if desired, optional, copied from others if set there) */ 48 | const char *domain_name; 49 | } hncp_sd_params_s, *hncp_sd_params; 50 | 51 | hncp_sd hncp_sd_create(hncp h, hncp_sd_params p, struct hncp_link *l); 52 | 53 | void hncp_sd_dump_link_fqdn(hncp_sd sd, dncp_ep ep, const char *ifname, 54 | char *buf, size_t buf_len); 55 | 56 | void hncp_sd_destroy(hncp_sd sd); 57 | 58 | bool hncp_sd_busy(hncp_sd sd); 59 | -------------------------------------------------------------------------------- /src/hncp_tunnel.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #define HNCP_TUNNEL_DISCOVERY_INTERVAL 15 4 | #define HNCP_TUNNEL_HOPLIMIT 4 5 | #define HNCP_TUNNEL_MINPORT 16384 6 | #define HNCP_TUNNEL_MAXPENDING 1 7 | 8 | enum { 9 | HNCP_T_TUNNEL_MESSAGE = 50, 10 | HNCP_T_TUNNEL_NEGOTIATE = 51, 11 | HNCP_T_TUNNEL_LINKTYPE = 52, 12 | }; 13 | 14 | enum { 15 | HNCP_TUNNEL_L2TPV3 = 1, 16 | }; 17 | 18 | /* HNCP_T_TUNNEL_NEGOTIATE */ 19 | typedef struct __packed { 20 | uint16_t type; 21 | uint16_t port; 22 | uint32_t session; 23 | } hncp_t_tunnel_l2tpv3_s, *hncp_t_tunnel_l2tpv3; 24 | 25 | struct hncp_tunnel; 26 | struct hncp_tunnel* hncp_tunnel_create(dncp dncp, const char *script); 27 | void hncp_tunnel_destroy(struct hncp_tunnel *t); 28 | -------------------------------------------------------------------------------- /src/hncp_wifi.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Author: Pierre Pfister 3 | * 4 | * Copyright (c) 2014-2015 Cisco Systems, Inc. 5 | * 6 | */ 7 | 8 | #include 9 | 10 | #include "hncp_wifi.h" 11 | #include "hncp_i.h" 12 | #include "hnetd.h" 13 | #include "exeq.h" 14 | 15 | #define HNCP_SSIDS 2 //Number of supported SSID provided to the script 16 | 17 | typedef struct hncp_ssid_struct { 18 | bool valid; 19 | bool to_delete; 20 | char ssid[32]; 21 | char password[32]; 22 | } hncp_ssid_s, *hncp_ssid; 23 | 24 | struct hncp_wifi_struct { 25 | struct uloop_timeout to; 26 | char *script; 27 | dncp dncp; 28 | dncp_subscriber_s subscriber; 29 | hncp_ssid_s ssids[HNCP_SSIDS]; 30 | struct exeq exeq; 31 | }; 32 | 33 | static void wifi_ssid_update(struct uloop_timeout *to) 34 | { 35 | L_DEBUG("wifi_ssid_update timeout"); 36 | hncp_wifi wifi = container_of(to, hncp_wifi_s, to); 37 | size_t i, new_ctr = 0; 38 | hncp_t_wifi_ssid new_tlvs[HNCP_SSIDS] = {}; 39 | 40 | //Mark to delete 41 | for(i=0; issids[i].valid) 43 | wifi->ssids[i].to_delete = 1; 44 | } 45 | 46 | //Find those that are still valid 47 | dncp_node n; 48 | struct tlv_attr *tlv; 49 | dncp_for_each_node(wifi->dncp, n) { 50 | dncp_node_for_each_tlv_with_type(n, tlv, HNCP_T_SSID) { 51 | if(tlv_len(tlv) != sizeof(hncp_t_wifi_ssid_s)) 52 | continue; 53 | 54 | hncp_t_wifi_ssid tlv_ssid = (hncp_t_wifi_ssid) tlv->data; 55 | if(tlv_ssid->password[HNCP_WIFI_PASSWORD_LEN] != 0 || 56 | tlv_ssid->ssid[HNCP_WIFI_SSID_LEN] != 0) 57 | continue; 58 | 59 | //Find this one 60 | bool found = false; 61 | for(i=0; issids[i].to_delete && 63 | !strcmp(wifi->ssids[i].ssid, (char *)tlv_ssid->ssid) && 64 | !strcmp(wifi->ssids[i].password, (char *)tlv_ssid->password)) { 65 | //Found, mark it as valid and go to next tlv 66 | found = true; 67 | wifi->ssids[i].to_delete = 0; 68 | break; 69 | } 70 | } 71 | 72 | //Remember this one is new 73 | if(!found && new_ctr != HNCP_SSIDS) { 74 | new_tlvs[new_ctr] = tlv_ssid; 75 | new_ctr++; 76 | } 77 | } 78 | } 79 | 80 | //Delete those that are not valid anymore 81 | for(i=0; issids[i].to_delete) { 83 | char id[10]; 84 | sprintf(id, "%d", (int)i); 85 | char *argv[] = {wifi->script, "delssid", id, wifi->ssids[i].ssid, wifi->ssids[i].password, NULL}; 86 | L_WARN("Deleting SSID %s (passwd = %s)", wifi->ssids[i].ssid, wifi->ssids[i].password); 87 | if(exeq_add(&wifi->exeq, argv)) 88 | L_ERR("wifi_ssid_update: Unable to execute script to delete SSID."); 89 | wifi->ssids[i].valid = 0; 90 | } 91 | } 92 | 93 | //Try to add those that we can 94 | size_t j = 0; 95 | for(i=0; issids[j].valid; j++); 98 | 99 | if(j == HNCP_SSIDS) { 100 | L_WARN("Not enough SSIDs available to enable SSID %s (passwd = %s)", 101 | (char *)new_tlvs[i]->ssid, (char *)new_tlvs[i]->password); 102 | } else { 103 | strcpy(wifi->ssids[j].password, (char *)new_tlvs[i]->password); 104 | strcpy(wifi->ssids[j].ssid, (char *)new_tlvs[i]->ssid); 105 | 106 | char id[10]; 107 | sprintf(id, "%d", (int) j); 108 | char *argv[] = {wifi->script, "addssid", id, wifi->ssids[j].ssid, wifi->ssids[j].password, NULL}; 109 | L_WARN("Adding SSID %s (passwd = %s)", wifi->ssids[j].ssid, wifi->ssids[j].password); 110 | if(exeq_add(&wifi->exeq, argv)) { 111 | L_ERR("wifi_ssid_update: Unable to execute script to add SSID."); 112 | } else { 113 | wifi->ssids[j].valid = 1; 114 | } 115 | } 116 | } 117 | } 118 | 119 | int hncp_wifi_modssid(hncp_wifi wifi, 120 | const char *ssid, const char *password, bool del) 121 | { 122 | L_INFO("Auto-Wifi mod-ssid %s SSID %s (password %s)", 123 | del?"del":"add", ssid, password); 124 | hncp_t_wifi_ssid_s tlv = { .ssid = {}, .password = {}}; 125 | if(strlen(ssid) > HNCP_WIFI_SSID_LEN || 126 | strlen(password) > HNCP_WIFI_PASSWORD_LEN) { 127 | L_ERR("Auto-Wifi: SSID or password is too long"); 128 | return -1; 129 | } 130 | 131 | strcpy((char *)tlv.ssid, ssid); 132 | strcpy((char *)tlv.password, password); 133 | dncp_tlv dtlv = dncp_find_tlv(wifi->dncp, HNCP_T_SSID, &tlv, sizeof(tlv)); 134 | if(del) { 135 | if(dtlv) { 136 | dncp_remove_tlv(wifi->dncp, dtlv); 137 | return 0; 138 | } 139 | return 1; 140 | } else { 141 | if(!dtlv) 142 | return !!dncp_add_tlv(wifi->dncp, HNCP_T_SSID, &tlv, sizeof(tlv), 0); 143 | return 1; 144 | } 145 | return 0; //for warning 146 | } 147 | 148 | static void wifi_tlv_cb(dncp_subscriber s, 149 | __unused dncp_node n, __unused struct tlv_attr *tlv, __unused bool add) 150 | { 151 | hncp_wifi wifi = container_of(s, hncp_wifi_s, subscriber); 152 | if(!wifi->to.pending && 153 | tlv_id(tlv) == HNCP_T_SSID && 154 | tlv_len(tlv) == sizeof(hncp_t_wifi_ssid_s)) 155 | uloop_timeout_set(&wifi->to, 1000); 156 | } 157 | 158 | hncp_wifi hncp_wifi_init(hncp hncp, char *scriptpath) 159 | { 160 | hncp_wifi wifi; 161 | if(!(wifi = calloc(1, sizeof(*wifi)))) 162 | return NULL; 163 | 164 | L_INFO("Initialize Auto-Wifi component with script %s", scriptpath); 165 | wifi->to.cb = wifi_ssid_update; 166 | wifi->script = scriptpath; 167 | wifi->dncp = hncp->dncp; 168 | wifi->subscriber.tlv_change_cb = wifi_tlv_cb; 169 | exeq_init(&wifi->exeq); 170 | dncp_subscribe(wifi->dncp, &wifi->subscriber); 171 | return wifi; 172 | } 173 | -------------------------------------------------------------------------------- /src/hncp_wifi.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Author: Pierre Pfister 3 | * 4 | * Copyright (c) 2014-2015 Cisco Systems, Inc. 5 | * 6 | * This thing provides some prototyped wifi autoconfiguration. 7 | * 8 | * ** WARNING ** 9 | * SSID passwords are shared through HNCP. 10 | * If HNCP traffic is not encrypted, SSID passwords will be visible. 11 | * 12 | */ 13 | 14 | #ifndef HNCP_WIFI_H_ 15 | #define HNCP_WIFI_H_ 16 | 17 | #include "hnetd.h" 18 | #include "hncp.h" 19 | 20 | typedef struct hncp_wifi_struct hncp_wifi_s, *hncp_wifi; 21 | 22 | /* Initialize auto-wifi sub-module. 23 | * It will listen to HNCP and call the script with the configured SSIDs. */ 24 | hncp_wifi hncp_wifi_init(hncp hncp, char *script); 25 | 26 | /* Add or remove a locally advertised SSID. */ 27 | int hncp_wifi_modssid(hncp_wifi wifi, 28 | const char *ssid, const char *password, bool del); 29 | 30 | #endif /* HNCP_WIFI_H_ */ 31 | -------------------------------------------------------------------------------- /src/hnetd.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Author: Markus Stenberg 3 | * Author: Steven Barth 4 | * Author: Pierre Pfister 5 | * 6 | * Copyright (c) 2014-2015 cisco Systems, Inc. 7 | */ 8 | 9 | #pragma once 10 | 11 | /* Anything up to INFO is compiled in by default; syslog can be used 12 | * to filter them out. DEBUG can be quite spammy and isn't enabled by 13 | * default. */ 14 | #define HNETD_DEFAULT_L_LEVEL 6 15 | 16 | #ifndef L_LEVEL 17 | #define L_LEVEL HNETD_DEFAULT_L_LEVEL 18 | #endif /* !L_LEVEL */ 19 | 20 | #ifndef L_PREFIX 21 | #define L_PREFIX "" 22 | #endif /* !L_PREFIX */ 23 | 24 | #ifdef __APPLE__ 25 | 26 | /* Haha. Got to love advanced IPv6 socket API being disabled by 27 | * default. */ 28 | #define __APPLE_USE_RFC_3542 29 | 30 | #define IPV6_ADD_MEMBERSHIP IPV6_JOIN_GROUP 31 | #define IPV6_DROP_MEMBERSHIP IPV6_LEAVE_GROUP 32 | 33 | /* LIST_HEAD macro in sys/queue.h, argh.. */ 34 | 35 | #include 36 | #ifdef LIST_HEAD 37 | #undef LIST_HEAD 38 | #endif /* LIST_HEAD */ 39 | 40 | #endif /* __APPLE__ */ 41 | 42 | #include 43 | #include 44 | #include 45 | #include 46 | #include 47 | #include 48 | #include 49 | 50 | #define STR_EXPAND(tok) #tok 51 | #define STR(tok) STR_EXPAND(tok) 52 | 53 | #define PRItime PRId64 54 | 55 | #include "hnetd_time.h" 56 | 57 | extern int log_level; 58 | 59 | // Logging macros 60 | 61 | extern void (*hnetd_log)(int priority, const char *format, ...); 62 | 63 | #define L_INTERNAL(level, ...) \ 64 | do { \ 65 | if (hnetd_log && log_level >= level) \ 66 | hnetd_log(level, L_PREFIX __VA_ARGS__); \ 67 | } while(0) 68 | 69 | #if L_LEVEL >= LOG_ERR 70 | #define L_ERR(...) L_INTERNAL(LOG_ERR, __VA_ARGS__) 71 | #else 72 | #define L_ERR(...) do {} while(0) 73 | #endif 74 | 75 | #if L_LEVEL >= LOG_WARNING 76 | #define L_WARN(...) L_INTERNAL(LOG_WARNING, __VA_ARGS__) 77 | #else 78 | #define L_WARN(...) do {} while(0) 79 | #endif 80 | 81 | #if L_LEVEL >= LOG_NOTICE 82 | #define L_NOTICE(...) L_INTERNAL(LOG_NOTICE, __VA_ARGS__) 83 | #else 84 | #define L_NOTICE(...) do {} while(0) 85 | #endif 86 | 87 | #if L_LEVEL >= LOG_INFO 88 | #define L_INFO(...) L_INTERNAL(LOG_INFO, __VA_ARGS__) 89 | #else 90 | #define L_INFO(...) do {} while(0) 91 | #endif 92 | 93 | #if L_LEVEL >= LOG_DEBUG 94 | #define L_DEBUG(...) L_INTERNAL(LOG_DEBUG, __VA_ARGS__) 95 | #else 96 | #define L_DEBUG(...) do {} while(0) 97 | #endif 98 | 99 | 100 | // Some C99 compatibility 101 | #ifndef typeof 102 | #define typeof __typeof 103 | #endif 104 | 105 | #ifndef container_of 106 | #define container_of(ptr, type, member) ( \ 107 | (type *)( (char *)ptr - offsetof(type,member) )) 108 | #endif 109 | 110 | #ifndef __unused 111 | #define __unused __attribute__((unused)) 112 | #endif 113 | -------------------------------------------------------------------------------- /src/hnetd_time.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Author: Markus Stenberg 3 | * Author: Steven Barth 4 | * 5 | * Copyright (c) 2015 cisco Systems, Inc. 6 | */ 7 | 8 | 9 | #define NO_REDEFINE_ULOOP_TIMEOUT 10 | 11 | /* Wrapper functions for time and timeouts. */ 12 | #include "hnetd_time.h" 13 | #include "hnetd.h" 14 | 15 | hnetd_time_t hnetd_time(void) 16 | { 17 | struct timespec ts; 18 | clock_gettime(CLOCK_MONOTONIC, &ts); 19 | return ((hnetd_time_t)ts.tv_sec * HNETD_TIME_PER_SECOND) + 20 | ((hnetd_time_t)ts.tv_nsec / (1000000000 / HNETD_TIME_PER_SECOND)); 21 | } 22 | 23 | int hnetd_time_timeout_add(struct uloop_timeout *timeout) 24 | { 25 | return uloop_timeout_add(timeout); 26 | } 27 | 28 | int hnetd_time_timeout_set(struct uloop_timeout *timeout, int msecs) 29 | { 30 | return uloop_timeout_set(timeout, msecs); 31 | } 32 | 33 | int hnetd_time_timeout_cancel(struct uloop_timeout *timeout) 34 | { 35 | return uloop_timeout_cancel(timeout); 36 | } 37 | 38 | int hnetd_time_timeout_remaining(struct uloop_timeout *timeout) 39 | { 40 | return uloop_timeout_remaining(timeout); 41 | } 42 | -------------------------------------------------------------------------------- /src/hnetd_time.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Author: Markus Stenberg 3 | * Author: Steven Barth 4 | * 5 | * Copyright (c) 2015 cisco Systems, Inc. 6 | */ 7 | 8 | /* 9 | * This module provides the hnetd time/timeout abstractions. 10 | * 11 | * We use this (as opposed to inlined functions) so they can be 12 | * overridden by net_sim in a cleaner way than what the old fake_uloop 13 | * approach did (re-#define, #include foo.c). #include foo.c is still 14 | * valid idea, but if and only if needed (for example) to mock 15 | * something else than time. This way we can use 'production' code, if 16 | * it's only external dependency is {dncp,hncp}_io* and this. 17 | */ 18 | 19 | #pragma once 20 | 21 | #include 22 | 23 | typedef int64_t hnetd_time_t; 24 | #define HNETD_TIME_MAX INT64_MAX 25 | #define HNETD_TIME_PER_SECOND INT64_C(1000) 26 | 27 | /* Get current monotonic clock with millisecond granularity */ 28 | hnetd_time_t hnetd_time(void); 29 | 30 | int hnetd_time_timeout_add(struct uloop_timeout *timeout); 31 | int hnetd_time_timeout_set(struct uloop_timeout *timeout, int msecs); 32 | int hnetd_time_timeout_cancel(struct uloop_timeout *timeout); 33 | int hnetd_time_timeout_remaining(struct uloop_timeout *timeout); 34 | 35 | #ifndef NO_REDEFINE_ULOOP_TIMEOUT 36 | #define uloop_timeout_add(x) hnetd_time_timeout_add(x) 37 | #define uloop_timeout_set(x,y) hnetd_time_timeout_set(x,y) 38 | #define uloop_timeout_cancel(x) hnetd_time_timeout_cancel(x) 39 | #define uloop_timeout_remaining(x) hnetd_time_timeout_remaining(x) 40 | #endif /* !NO_REDEFINE_ULOOP_TIMEOUT */ 41 | -------------------------------------------------------------------------------- /src/pa_filters.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Author: Pierre Pfister 3 | * 4 | * Copyright (c) 2014-2015 Cisco Systems, Inc. 5 | */ 6 | 7 | #include "pa_filters.h" 8 | 9 | int pa_filters_or(struct pa_rule *rule, struct pa_ldp *ldp, struct pa_filter *filter) 10 | { 11 | struct pa_filters *fs = container_of(filter, struct pa_filters, filter); 12 | list_for_each_entry(filter, &fs->filters, le) { 13 | if(filter->accept(rule, ldp, filter)) 14 | return !fs->negate; 15 | } 16 | return !!fs->negate; 17 | } 18 | 19 | int pa_filters_and(struct pa_rule *rule, struct pa_ldp *ldp, struct pa_filter *filter) 20 | { 21 | struct pa_filters *fs = container_of(filter, struct pa_filters, filter); 22 | list_for_each_entry(filter, &fs->filters, le) { 23 | if(!filter->accept(rule, ldp, filter)) 24 | return !!fs->negate; 25 | } 26 | return !fs->negate; 27 | } 28 | 29 | int pa_filter_ldp(__unused struct pa_rule *rule, struct pa_ldp *ldp, struct pa_filter *filter) 30 | { 31 | struct pa_filter_ldp *fb = container_of(filter, struct pa_filter_ldp, filter); 32 | if(fb->link && fb->link != ldp->link) 33 | return 0; 34 | if(fb->dp && fb->dp != ldp->dp) 35 | return 0; 36 | return 1; 37 | } 38 | 39 | #ifdef PA_DP_TYPE 40 | int pa_filter_type_dp(__unused struct pa_rule *rule, struct pa_ldp *ldp, struct pa_filter *filter) 41 | { 42 | struct pa_filter_type *ft = container_of(filter, struct pa_filter_type, filter); 43 | return ldp->dp->type == ft->type; 44 | } 45 | #endif 46 | 47 | #ifdef PA_LINK_TYPE 48 | int pa_filter_type_link(__unused struct pa_rule *rule, struct pa_ldp *ldp, struct pa_filter *filter) 49 | { 50 | struct pa_filter_type *ft = container_of(filter, struct pa_filter_type, filter); 51 | return ldp->link->type == ft->type; 52 | } 53 | #endif 54 | 55 | -------------------------------------------------------------------------------- /src/pa_filters.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Author: Pierre Pfister 3 | * 4 | * Copyright (c) 2014-2015 Cisco Systems, Inc. 5 | * 6 | * Prefix Assignment Rule Filters. 7 | * 8 | * Filters are used by the algorithm in order to allow a single rule to match 9 | * or not match given different contexts. 10 | * 11 | */ 12 | 13 | #ifndef PA_FILTERS_H_ 14 | #define PA_FILTERS_H_ 15 | 16 | #include "pa_core.h" 17 | 18 | struct pa_filter; 19 | typedef int (*pa_filter_f)(struct pa_rule *, struct pa_ldp *, 20 | struct pa_filter *filter); 21 | 22 | /** 23 | * Filter structure used by all filters defined in this file. 24 | */ 25 | struct pa_filter { 26 | pa_filter_f accept; 27 | struct list_head le; 28 | }; 29 | 30 | /* Configure a rule to use the specified filter. */ 31 | #define pa_rule_set_filter(rule, filter) do { \ 32 | (rule)->filter_accept = (int (*)(struct pa_rule *, struct pa_ldp *, void *p)) (filter)->accept; \ 33 | (rule)->filter_private = filter; \ 34 | } while(0) 35 | 36 | /* Remove the filter from a given rule. */ 37 | #define pa_rule_unset_filter(rule) (rule)->filter_accept = NULL 38 | 39 | 40 | 41 | /* 42 | * Multiple filters can be combined together in order 43 | * to form more complex combination. 44 | * AND, OR, NAND and NOR are supported. 45 | */ 46 | struct pa_filters; 47 | struct pa_filters { 48 | struct pa_filter filter; 49 | struct list_head filters; 50 | uint8_t negate; //When set, the result is inverted 51 | }; 52 | 53 | int pa_filters_or(struct pa_rule *rule, struct pa_ldp *ldp, struct pa_filter *filter); 54 | int pa_filters_and(struct pa_rule *rule, struct pa_ldp *ldp, struct pa_filter *filter); 55 | 56 | #define pa_filters_init(fs, accept_f, neg) do{ \ 57 | (fs)->filter.accept = accept_f; \ 58 | (fs)->negate = neg;\ 59 | INIT_LIST_HEAD(&(fs)->filters); \ 60 | } while(0) 61 | 62 | #define pa_filters_or_init(fs, negate) pa_filters_init(fs, pa_filters_or, negate) 63 | #define pa_filters_and_init(fs, negate) pa_filters_init(fs, pa_filters_and, negate) 64 | 65 | #define pa_filters_add(fs, f) list_add(&(f)->le ,&(fs)->filters) 66 | #define pa_filters_del(f) list_del(&(f)->le) 67 | 68 | 69 | /* 70 | * Simple filter used to filter for a given link, dp, or both. 71 | */ 72 | struct pa_filter_ldp { 73 | struct pa_filter filter; 74 | struct pa_link *link; 75 | struct pa_dp *dp; 76 | }; 77 | 78 | int pa_filter_ldp(struct pa_rule *, struct pa_ldp *, struct pa_filter *); 79 | 80 | #define pa_filter_ldp_init(fb, l, d) \ 81 | ((fb)->filter.accept = pa_filter_ldp, (fb)->link = l, (fb)->dp = d) 82 | 83 | /* 84 | * Filter which only matches for a given dp or link type. 85 | */ 86 | struct pa_filter_type { 87 | struct pa_filter filter; 88 | uint8_t type; 89 | }; 90 | 91 | #ifdef PA_DP_TYPE 92 | int pa_filter_type_dp(struct pa_rule *rule, struct pa_ldp *ldp, struct pa_filter *filter); 93 | #define pa_filter_type_dp_init(ft, typ) \ 94 | ((ft)->filter.accept = pa_filter_type_dp, (ft)->type = typ) 95 | 96 | #endif 97 | 98 | #ifdef PA_LINK_TYPE 99 | int pa_filter_type_link(struct pa_rule *rule, struct pa_ldp *ldp, struct pa_filter *filter); 100 | #define pa_filter_type_link_init(ft, typ) \ 101 | ((ft)->filter.accept = pa_filter_type_link, (ft)->type = typ) 102 | #endif 103 | 104 | 105 | #endif /* PA_FILTERS_H_ */ 106 | -------------------------------------------------------------------------------- /src/pd.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Author: Steven Barth 3 | * 4 | * Copyright (c) 2014-2015 cisco Systems, Inc. 5 | */ 6 | 7 | #include "pd.h" 8 | #include "hnetd.h" 9 | #include "prefix_utils.h" 10 | #include "hncp_pa.h" 11 | 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | #include 18 | #include 19 | #include 20 | #include 21 | 22 | //Time given to PA to provide first lease (even temporary) 23 | #define PD_PA_TIMEOUT 5000 24 | 25 | struct pd { 26 | struct uloop_fd fd; 27 | hncp_pa hncp_pa; 28 | struct list_head handles; 29 | }; 30 | 31 | 32 | struct pd_handle { 33 | struct list_head head; 34 | struct ustream_fd fd; 35 | bool established; 36 | bool done; 37 | struct uloop_timeout timeout; 38 | hpa_lease lease; 39 | struct list_head prefixes; 40 | struct pd *pd; 41 | }; 42 | 43 | struct pd_prefix { 44 | struct list_head le; 45 | struct prefix prefix; 46 | hnetd_time_t valid_until, preferred_until; 47 | }; 48 | 49 | // TCP transmission has ended, either because of success or timeout or other error 50 | static void pd_handle_done(struct ustream *s) 51 | { 52 | struct pd_handle *c = container_of(s, struct pd_handle, fd.stream); 53 | if(c->done) //Prevent multiple dones 54 | return; 55 | 56 | c->done = 1; 57 | 58 | if (c->established) 59 | hpa_pd_del_lease(c->pd->hncp_pa, c->lease); 60 | 61 | close(c->fd.fd.fd); 62 | ustream_free(&c->fd.stream); 63 | list_del(&c->head); 64 | free(c); 65 | } 66 | 67 | //PA did not replied in time 68 | static void pd_handle_timeout(struct uloop_timeout *to) 69 | { 70 | struct pd_handle *c = container_of(to, struct pd_handle, timeout); 71 | pd_handle_done(&c->fd.stream); 72 | } 73 | 74 | // Update 75 | static void pd_handle_update(struct pd_handle *c) 76 | { 77 | struct pd_prefix *p; 78 | hnetd_time_t now = hnetd_time(); 79 | 80 | uloop_timeout_cancel(&c->timeout); 81 | bool keep = false; 82 | bool sent = false; 83 | list_for_each_entry(p, &c->prefixes, le) { 84 | hnetd_time_t valid = (p->valid_until > now)? 85 | (p->valid_until - now) /HNETD_TIME_PER_SECOND:0; 86 | hnetd_time_t preferred = (p->preferred_until > now)? 87 | (p->preferred_until - now) / HNETD_TIME_PER_SECOND:0; 88 | 89 | if (valid > UINT32_MAX) 90 | valid = UINT32_MAX; 91 | 92 | if (preferred > UINT32_MAX) 93 | preferred = UINT32_MAX; 94 | 95 | if(!c->fd.fd.error) 96 | ustream_printf(&c->fd.stream, "%s,%"PRId64",%"PRId64"\n", 97 | PREFIX_REPR_C(&p->prefix), preferred, valid); 98 | 99 | sent = true; 100 | 101 | if (valid > 0) 102 | keep = true; 103 | } 104 | 105 | if (sent && !c->fd.fd.error) { 106 | ustream_write(&c->fd.stream, "\n", 1, false); 107 | ustream_write_pending(&c->fd.stream); 108 | } 109 | 110 | if (!keep) 111 | pd_handle_done(&c->fd.stream); 112 | } 113 | 114 | static void pd_cb(const struct in6_addr *prefix, uint8_t plen, 115 | hnetd_time_t valid_until, hnetd_time_t preferred_until, 116 | __unused const char *dhcp_data, __unused size_t dhcp_len, 117 | void *priv) 118 | { 119 | struct pd_handle *c = (struct pd_handle *)priv; 120 | struct pd_prefix *p; 121 | list_for_each_entry(p, &c->prefixes, le) { 122 | if(!memcmp(&p->prefix.prefix, prefix, sizeof(struct in6_addr)) && 123 | p->prefix.plen == plen) 124 | goto found; 125 | } 126 | if(!preferred_until || !(p = malloc(sizeof(*p)))) 127 | return; 128 | p->prefix.prefix = *prefix; 129 | p->prefix.plen = plen; 130 | list_add(&p->le, &c->prefixes); 131 | found: 132 | p->preferred_until = preferred_until; 133 | p->valid_until = valid_until; 134 | pd_handle_update(c); 135 | //todo: Would be better to send a diff instead of a complete dump 136 | if(!preferred_until) { 137 | list_del(&p->le); 138 | free(p); 139 | } 140 | } 141 | 142 | // More data was received from TCP connection 143 | static void pd_handle_data(struct ustream *s, __unused int bytes_new) 144 | { 145 | struct pd_handle *c = container_of(s, struct pd_handle, fd.stream); 146 | int pending; 147 | char *data = ustream_get_read_buf(s, &pending); 148 | char *end = memmem(data, pending, "\n\n", 2); 149 | 150 | uint8_t hint = 62; 151 | 152 | if (!c->established && end) { 153 | end += 2; 154 | end[-1] = 0; 155 | 156 | char *saveptr, *line; 157 | char *seed = strtok_r(data, "\n", &saveptr); 158 | // We don't care about the first line 159 | 160 | if ((line = strtok_r(NULL, "\n", &saveptr)) && 161 | (line = strtok_r(NULL, "/", &saveptr)) && 162 | (line = strtok_r(NULL, ",", &saveptr))) { 163 | hint = atoi(line); 164 | } 165 | 166 | if (hint > 64) 167 | hint = 64; 168 | 169 | if(!(c->lease = hpa_pd_add_lease(c->pd->hncp_pa, seed, hint, pd_cb, c))){ 170 | pd_handle_done(s); 171 | } else { 172 | c->timeout.cb = pd_handle_timeout; 173 | c->timeout.pending = 0; 174 | uloop_timeout_set(&c->timeout, PD_PA_TIMEOUT); 175 | c->established = true; 176 | } 177 | } 178 | } 179 | 180 | 181 | static void pd_accept(struct uloop_fd *fd, __unused unsigned int events) 182 | { 183 | struct pd *pd = container_of(fd, struct pd, fd); 184 | for (;;) { 185 | int sock = accept(fd->fd, NULL, 0); 186 | if (sock < 0) { 187 | if (errno == EWOULDBLOCK) 188 | break; 189 | else 190 | continue; 191 | } 192 | 193 | struct pd_handle *handle = calloc(1, sizeof(*handle)); 194 | INIT_LIST_HEAD(&handle->prefixes); 195 | handle->pd = pd; 196 | 197 | handle->fd.stream.notify_read = pd_handle_data; 198 | handle->fd.stream.notify_state = pd_handle_done; 199 | 200 | ustream_fd_init(&handle->fd, sock); 201 | list_add(&handle->head, &pd->handles); 202 | } 203 | } 204 | 205 | 206 | struct pd* pd_create(hncp_pa hncp_pa, const char *path) 207 | { 208 | L_DEBUG("Initialize HNCP Downstream PD on Unix socket %s", path); 209 | unlink(path); 210 | int sock = usock(USOCK_TCP | USOCK_SERVER | USOCK_UNIX, path, NULL); 211 | if (sock < 0) 212 | return NULL; 213 | 214 | struct pd *pd = calloc(1, sizeof(*pd)); 215 | INIT_LIST_HEAD(&pd->handles); 216 | pd->hncp_pa = hncp_pa; 217 | pd->fd.fd = sock; 218 | pd->fd.cb = pd_accept; 219 | 220 | uloop_fd_add(&pd->fd, ULOOP_READ | ULOOP_EDGE_TRIGGER); 221 | 222 | return pd; 223 | } 224 | 225 | 226 | void pd_destroy(struct pd *pd) 227 | { 228 | while (!list_empty(&pd->handles)) 229 | pd_handle_done(&list_first_entry(&pd->handles, struct pd_handle, head)->fd.stream); 230 | 231 | close(pd->fd.fd); 232 | free(pd); 233 | } 234 | -------------------------------------------------------------------------------- /src/pd.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Author: Steven Barth 3 | * 4 | * Copyright (c) 2014-2015 cisco Systems, Inc. 5 | */ 6 | 7 | #ifndef PD_H_ 8 | #define PD_H_ 9 | 10 | #include "hncp_pa.h" 11 | 12 | struct pd; 13 | struct pd* pd_create(hncp_pa hncp_pa, const char *path); 14 | void pd_destroy(struct pd *pd); 15 | 16 | #endif /* PD_H_ */ 17 | -------------------------------------------------------------------------------- /src/platform.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Author: Steven Barth 3 | * 4 | * Copyright (c) 2014-2015 cisco Systems, Inc. 5 | */ 6 | 7 | #pragma once 8 | #include 9 | #include 10 | #include 11 | 12 | #include "iface.h" 13 | 14 | 15 | // Platform specific initialization 16 | int platform_init(hncp hncp, hncp_pa hncp_pa, const char *pd_socket); 17 | 18 | // Handle internal change 19 | void platform_set_internal(struct iface *c, bool internal); 20 | 21 | // Set / unset an address 22 | void platform_set_address(struct iface *c, struct iface_addr *addr, bool enable); 23 | 24 | // Set owner status 25 | void platform_set_dhcp(struct iface *c, enum hncp_link_elected elected); 26 | 27 | // Restart dhcpv4 client 28 | void platform_restart_dhcpv4(struct iface *c); 29 | 30 | // Set DHCPv6 data 31 | void platform_set_dhcpv6_send(struct iface *c, const void *dhcpv6_data, size_t len, const void *dhcp_data, size_t len4); 32 | 33 | // Create local interface 34 | void platform_iface_new(struct iface *c, const char *handle); 35 | 36 | // Delete local interface 37 | void platform_iface_free(struct iface *c); 38 | 39 | // Set prefix route 40 | void platform_set_prefix_route(const struct prefix *p, bool enable); 41 | 42 | // Filter / unfilter prefix 43 | void platform_filter_prefix(struct iface *c, const struct prefix *p, bool enable); 44 | 45 | // Enable / disable NAT 46 | void platform_set_snat(struct iface *c, const struct prefix *p); 47 | 48 | // Register an RPC function 49 | struct platform_rpc_method; 50 | typedef int(platform_rpc_cb)(struct platform_rpc_method *method, const struct blob_attr *in, struct blob_buf *out); 51 | typedef int(platform_rpc_main)(struct platform_rpc_method *method, int argc, char* const argv[]); 52 | 53 | struct platform_rpc_method { 54 | const char *name; 55 | platform_rpc_cb *cb; 56 | platform_rpc_main *main; 57 | struct blobmsg_policy *policy; 58 | size_t policy_cnt; 59 | }; 60 | int platform_rpc_register(struct platform_rpc_method *method); 61 | 62 | // Call RPC function from your own program 63 | int platform_rpc_cli(const char *name, struct blob_attr *in); 64 | 65 | // Multicall RPC dispatcher 66 | int platform_rpc_multicall(int argc, char *const argv[]); 67 | 68 | // Set platform 69 | void platform_set_iface(const char *name, bool enable); 70 | 71 | #define PLATFORM_RPC_MAX 32 72 | -------------------------------------------------------------------------------- /src/prefix.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Author: Pierre Pfister 3 | * 4 | * Copyright (c) 2014-2015 Cisco Systems, Inc. 5 | * 6 | */ 7 | 8 | #include "prefix.h" 9 | 10 | #include 11 | #include 12 | #include 13 | #include 14 | 15 | const char *addr_ntop(char *dst, size_t bufflen, const struct in6_addr *addr) 16 | { 17 | if (IN6_IS_ADDR_V4MAPPED(addr)) { 18 | return inet_ntop(AF_INET, &addr->s6_addr[12], dst, bufflen); 19 | } else { 20 | return inet_ntop(AF_INET6, addr, dst, bufflen); 21 | } 22 | } 23 | 24 | const char *prefix_ntop(char *dst, size_t bufflen, const struct in6_addr *addr, 25 | uint8_t plen) 26 | { 27 | if (bufflen < 4 || !addr_ntop(dst, bufflen - 4, addr)) 28 | return NULL ; 29 | 30 | char *str = dst + strlen(dst); 31 | if (plen >= 96 && IN6_IS_ADDR_V4MAPPED(addr)) { 32 | sprintf(str, "/%d", plen - 96); 33 | } else { 34 | sprintf(str, "/%d", plen); 35 | } 36 | return dst; 37 | } 38 | 39 | const char *prefix_ntopc(char *dst, size_t bufflen, const struct in6_addr *addr, 40 | uint8_t plen) 41 | { 42 | struct in6_addr p = { .s6_addr = { } }; 43 | size_t bytes = plen >> 3; 44 | memcpy(&p, addr, bytes); 45 | uint8_t rembit = plen & 0x07; 46 | if (rembit) 47 | p.s6_addr[bytes] = (0xff << (8 - rembit)) & addr->s6_addr[bytes]; 48 | 49 | return prefix_ntop(dst, bufflen, &p, plen); 50 | } 51 | 52 | int prefix_pton(const char *src, struct in6_addr *addr, uint8_t *plen) 53 | { 54 | char buf[INET6_ADDRSTRLEN]; 55 | char *slash = strchr(src, '/'), *c; 56 | uint8_t parsed_len = 128; 57 | size_t addrlen; 58 | if (slash) { 59 | addrlen = strlen(slash + 1); 60 | if (!addrlen || addrlen > 3) 61 | return 0; 62 | 63 | /* atoi doesn't return errors, so we check string correctness */ 64 | for (c = slash + 1; *c; c++) { 65 | if (*c < '0' || *c > '9') 66 | return 0; 67 | } 68 | parsed_len = atoi(slash + 1); 69 | addrlen = slash - src; 70 | } else { 71 | addrlen = strlen(src); 72 | } 73 | 74 | if (addrlen >= INET6_ADDRSTRLEN) 75 | return 0; 76 | 77 | memcpy(buf, src, addrlen); 78 | buf[addrlen] = 0; 79 | 80 | if (!slash) 81 | *plen = 128; 82 | 83 | if (inet_pton(AF_INET6, buf, addr) == 1) { 84 | if (slash) { 85 | if (parsed_len > 128) 86 | return 0; 87 | *plen = parsed_len; 88 | } 89 | } else if (inet_pton(AF_INET, buf, &addr->s6_addr[12]) == 1) { 90 | if (slash) { 91 | if (parsed_len > 32) 92 | return 0; 93 | *plen = parsed_len + 96; 94 | } 95 | memset(addr, 0, 10); 96 | addr->s6_addr[10] = 0xff; 97 | addr->s6_addr[11] = 0xff; 98 | } else { 99 | return 0; 100 | } 101 | 102 | return 1; 103 | } 104 | -------------------------------------------------------------------------------- /src/prefix.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Author: Pierre Pfister 3 | * 4 | * Copyright (c) 2014-2015 Cisco Systems, Inc. 5 | * 6 | * IPv4 and IPv6 prefix parsing functions. 7 | * 8 | * IPv4 prefixes are stored as IPv4 in IPv6 mapped address with shifted prefix 9 | * length. 10 | * For instance, 1.2.3.0/24 is stored as ::ffff:1.2.3.0/120. 11 | * 12 | */ 13 | 14 | #ifndef PREFIX_H_ 15 | #define PREFIX_H_ 16 | 17 | #include 18 | 19 | /** 20 | * Maximum required space to print a prefix. 21 | */ 22 | #define PREFIX_MAXBUFFLEN (INET6_ADDRSTRLEN + 4) 23 | 24 | /** 25 | * Format helper for address representation. 26 | * 27 | * IPv4 in IPv6 mapped address are represented as IPv4 addresses. 28 | * 29 | * @param addr The IPv6 address in binary form. 30 | * @return A string representing the IPv6 or IPv4 address. 31 | */ 32 | #define ADDR_REPR(addr) \ 33 | (IN6_IS_ADDR_V4MAPPED(addr))?\ 34 | inet_ntop(AF_INET, &(addr)->s6_addr[12], alloca(INET_ADDRSTRLEN), INET_ADDRSTRLEN):\ 35 | inet_ntop(AF_INET6, addr, alloca(INET6_ADDRSTRLEN), INET6_ADDRSTRLEN) 36 | 37 | /** 38 | * Converts an IPv6 prefix from binary to text form. 39 | * 40 | * Non-significant bits from the prefix are considered. 41 | * IPv4 in IPv6 mapped prefixes are represented in their 42 | * IPv4 form. 43 | * 44 | * @param dst The destination buffer. 45 | * @param bufflen The destination buffer length. 46 | * @param addr The address to be displayed. 47 | * @param plen The prefix length. 48 | * @return dst on success or NULL on otherwise. 49 | */ 50 | const char *prefix_ntop(char *dst, size_t bufflen, const struct in6_addr *addr, 51 | uint8_t plen); 52 | 53 | /** 54 | * Converts an IPv6 prefix from binary to text form. 55 | * 56 | * Similar to prefix_ntop, but only significant bits 57 | * from the prefix are displayed. 58 | * 59 | * @param dst The destination buffer. 60 | * @param bufflen The destination buffer length. 61 | * @param addr The address to be displayed. 62 | * @param plen The prefix length. 63 | * @return dst on success or NULL on otherwise. 64 | */ 65 | const char *prefix_ntopc(char *dst, size_t bufflen, 66 | const struct in6_addr *prefix, uint8_t plen); 67 | 68 | /** 69 | * Converts an IPv4 or IPv6 prefix from text to binary form. 70 | * 71 | * Non-significant bits are converted too. 72 | * 73 | * @param src The string representing an IPv4 or IPv6 prefix. 74 | * @param addr The address destination pointer. 75 | * @param plen The prefix length destination pointer. 76 | * @return 1 upon **success** or 0 otherwise (Because this what inet_pton does). 77 | */ 78 | int prefix_pton(const char *src, struct in6_addr *addr, uint8_t *plen); 79 | 80 | const char *addr_ntop(char *dst, size_t bufflen, const struct in6_addr *addr); 81 | 82 | #endif 83 | -------------------------------------------------------------------------------- /src/prefix_utils.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Author: Pierre Pfister 3 | * 4 | * Copyright (c) 2014-2015 Cisco Systems, Inc. 5 | * 6 | */ 7 | 8 | #include "prefix_utils.h" 9 | 10 | struct prefix ipv4_in_ipv6_prefix = { 11 | .prefix = { .s6_addr = { 12 | 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 13 | 0x00,0x00, 0xff,0xff }}, 14 | .plen = 96 }; 15 | 16 | struct prefix ipv6_ula_prefix = { 17 | .prefix = { .s6_addr = { 0xfd }}, 18 | .plen = 8 }; 19 | 20 | struct prefix ipv6_ll_prefix = { 21 | .prefix = { .s6_addr = { 0xfe,0x80 }}, 22 | .plen = 10 }; 23 | 24 | struct prefix ipv6_global_prefix = { 25 | .prefix = { .s6_addr = { 0x20 }}, 26 | .plen = 3 }; 27 | -------------------------------------------------------------------------------- /src/prefix_utils.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Author: Pierre Pfister 3 | * 4 | * Copyright (c) 2014-2015 Cisco Systems, Inc. 5 | * 6 | * Prefixes manipulation utilities. 7 | * 8 | */ 9 | 10 | #ifndef UTILS_H 11 | #define UTILS_H 12 | 13 | #include 14 | #include 15 | #include 16 | 17 | #include "prefix.h" 18 | #include "bitops.h" 19 | 20 | /* Prefix structure. 21 | * All bits following the plen first are ignored. */ 22 | struct prefix { 23 | struct in6_addr prefix; 24 | uint8_t plen; 25 | }; 26 | 27 | extern struct prefix ipv4_in_ipv6_prefix; 28 | extern struct prefix ipv6_ula_prefix; 29 | extern struct prefix ipv6_ll_prefix; 30 | extern struct prefix ipv6_global_prefix; 31 | 32 | #define prefix_contains(p1, p2) ( ((p2)->plen >= (p1)->plen) && \ 33 | !bmemcmp(&(p1)->prefix, &(p2)->prefix, (p1)->plen) ) 34 | 35 | #define prefix_is_ipv4(prefix) \ 36 | prefix_contains(&ipv4_in_ipv6_prefix, prefix) 37 | 38 | #define prefix_is_ula(prefix) \ 39 | prefix_contains(&ipv6_ula_prefix, prefix) 40 | 41 | #define prefix_is_ipv6_ula(prefix) \ 42 | prefix_contains(&ipv6_ula_prefix, prefix) 43 | 44 | #define prefix_is_ll(prefix) \ 45 | prefix_contains(&ipv6_ll_prefix, prefix) 46 | 47 | #define prefix_is_global(prefix) \ 48 | prefix_contains(&ipv6_global_prefix, prefix) 49 | 50 | static inline int prefix_cmp(const struct prefix *p1, const struct prefix *p2) { 51 | int i; 52 | if((i = (int)p2->plen - (int)p1->plen)) 53 | return i; 54 | 55 | return bmemcmp(&p1->prefix, &p2->prefix, p1->plen); 56 | } 57 | 58 | /*#define prefix_cmp(p1, p2) (((p1)->plen != (p2)->plen)?((p2)->plen - (p1)->plen):\ 59 | bmemcmp(&(p1)->prefix, &(p2)->prefix, (p1)->plen))*/ 60 | 61 | #define prefix_af_length(p) (prefix_is_ipv4(p)?(p)->plen - 96:(p)->plen) 62 | 63 | /** 64 | * Format helper for address representation. 65 | * 66 | * IPv4 in IPv6 mapped address are represented as IPv4 addresses. 67 | * 68 | * @param addr The IPv6 address in binary form. 69 | * @return A string representing the IPv6 or IPv4 address. 70 | */ 71 | #define ADDR_REPR(addr) \ 72 | (IN6_IS_ADDR_V4MAPPED(addr))?\ 73 | inet_ntop(AF_INET, &(addr)->s6_addr[12], alloca(INET_ADDRSTRLEN), INET_ADDRSTRLEN):\ 74 | inet_ntop(AF_INET6, addr, alloca(INET6_ADDRSTRLEN), INET6_ADDRSTRLEN) 75 | 76 | /** 77 | * Format helper to represent a prefix in its canonical form. 78 | * 79 | * @param p The prefix. 80 | * @param len The prefix length. 81 | * @return A canonical string representation of the prefix. 82 | */ 83 | #define PREFIX_REPR_C(p) \ 84 | prefix_ntopc(alloca(PREFIX_MAXBUFFLEN), PREFIX_MAXBUFFLEN, &(p)->prefix, (p)->plen) 85 | 86 | /** 87 | * Format helper to represent a prefix. 88 | * 89 | * @param p The prefix. 90 | * @param len The prefix length. 91 | * @return A string representation of the address and prefix length. 92 | */ 93 | #define PREFIX_REPR(p) \ 94 | prefix_ntop(alloca(PREFIX_MAXBUFFLEN), PREFIX_MAXBUFFLEN, &(p)->prefix, (p)->plen) 95 | 96 | 97 | #endif 98 | -------------------------------------------------------------------------------- /src/tlv.h: -------------------------------------------------------------------------------- 1 | /* 2 | * tlv - library for generating/parsing tagged binary data 3 | * 4 | * Copyright (C) 2010 Felix Fietkau 5 | * 6 | * Permission to use, copy, modify, and/or distribute this software for any 7 | * purpose with or without fee is hereby granted, provided that the above 8 | * copyright notice and this permission notice appear in all copies. 9 | * 10 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 11 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 12 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 13 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 14 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 15 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 16 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 17 | */ 18 | 19 | #ifndef _TLV_H__ 20 | #define _TLV_H__ 21 | 22 | #include 23 | #include 24 | #include 25 | #include 26 | #include 27 | #include 28 | 29 | #include 30 | 31 | #define TLV_COOKIE 0x01234567 32 | #define TLV_ATTR_ID_MASK 0xffff0000 33 | #define TLV_ATTR_ID_SHIFT 16 34 | #define TLV_ATTR_LEN_MASK 0x0000ffff 35 | #define TLV_ATTR_ALIGN 4 36 | 37 | struct tlv_attr { 38 | uint32_t id_len; 39 | char data[]; 40 | } __packed; 41 | 42 | struct tlv_attr_info { 43 | unsigned int type; 44 | unsigned int minlen; 45 | unsigned int maxlen; 46 | bool (*validate)(const struct tlv_attr_info *, struct tlv_attr *); 47 | }; 48 | 49 | struct tlv_buf { 50 | struct tlv_attr *head; 51 | bool (*grow)(struct tlv_buf *buf, int minlen); 52 | int buflen; 53 | void *buf; 54 | }; 55 | 56 | /* 57 | * tlv_data: returns the data pointer for an attribute 58 | */ 59 | static inline void * 60 | tlv_data(const struct tlv_attr *attr) 61 | { 62 | return (void *) attr->data; 63 | } 64 | 65 | /* 66 | * tlv_id: returns the id of an attribute 67 | */ 68 | static inline unsigned int 69 | tlv_id(const struct tlv_attr *attr) 70 | { 71 | int id = (be32_to_cpu(attr->id_len) & TLV_ATTR_ID_MASK) >> TLV_ATTR_ID_SHIFT; 72 | return id; 73 | } 74 | 75 | /* 76 | * tlv_len: returns the length of the attribute's payload 77 | */ 78 | static inline unsigned int 79 | tlv_len(const struct tlv_attr *attr) 80 | { 81 | return (be32_to_cpu(attr->id_len) & TLV_ATTR_LEN_MASK); 82 | } 83 | 84 | /* 85 | * tlv_raw_len: returns the complete length of an attribute (including the header) 86 | */ 87 | static inline unsigned int 88 | tlv_raw_len(const struct tlv_attr *attr) 89 | { 90 | return tlv_len(attr) + sizeof(struct tlv_attr); 91 | } 92 | 93 | /* 94 | * tlv_pad_len: returns the padded length of an attribute (including the header) 95 | */ 96 | static inline unsigned int 97 | tlv_pad_len(const struct tlv_attr *attr) 98 | { 99 | int len = tlv_raw_len(attr); 100 | len = (len + TLV_ATTR_ALIGN - 1) & ~(TLV_ATTR_ALIGN - 1); 101 | return len; 102 | } 103 | 104 | static inline struct tlv_attr * 105 | tlv_next(const struct tlv_attr *attr) 106 | { 107 | return (struct tlv_attr *) ((char *) attr + tlv_pad_len(attr)); 108 | } 109 | 110 | extern void tlv_init(struct tlv_attr *attr, int id, unsigned int len); 111 | extern void tlv_fill_pad(struct tlv_attr *attr); 112 | extern void tlv_set_raw_len(struct tlv_attr *attr, unsigned int len); 113 | extern bool tlv_attr_equal(const struct tlv_attr *a1, const struct tlv_attr *a2); 114 | extern int tlv_attr_cmp(const struct tlv_attr *a1, const struct tlv_attr *a2); 115 | extern int tlv_buf_init(struct tlv_buf *buf, int id); 116 | extern void tlv_buf_free(struct tlv_buf *buf); 117 | extern void tlv_buf_grow(struct tlv_buf *buf, int required); 118 | extern struct tlv_attr *tlv_new(struct tlv_buf *buf, int id, int payload); 119 | extern void *tlv_nest_start(struct tlv_buf *buf, int id, int len); 120 | extern void tlv_nest_end(struct tlv_buf *buf, void *cookie); 121 | extern struct tlv_attr *tlv_put(struct tlv_buf *buf, int id, const void *ptr, int len); 122 | extern struct tlv_attr *tlv_memdup(struct tlv_attr *attr); 123 | extern struct tlv_attr *tlv_put_raw(struct tlv_buf *buf, const void *ptr, int len); 124 | extern bool tlv_sort(void *buf, int len); 125 | 126 | /* Paranoid version: Have faith only in the caller providing correct 127 | * buf + len; pos is used to maintain the current position within buf. */ 128 | #define tlv_for_each_in_buf(pos, buf, len) \ 129 | for ((pos) = (struct tlv_attr *)(buf); \ 130 | (char *)(pos) + sizeof(*(pos)) <= (char *)(buf) + (len) \ 131 | && tlv_raw_len(pos) >= sizeof(*(pos)) \ 132 | && (char *)(pos) + tlv_raw_len(pos) <= (char *)(buf) + (len); \ 133 | (pos) = tlv_next(pos)) 134 | 135 | /* Assume the root 'attr' is trusted. The rest may contain garbage and 136 | * we should still not blow up. */ 137 | #define tlv_for_each_attr(pos, attr) \ 138 | tlv_for_each_in_buf(pos, tlv_data(attr), (attr) ? tlv_len(attr) : 0) 139 | 140 | static inline const char *hex_repr(char *buf, const void *data, int len) 141 | { 142 | char *r = buf; 143 | 144 | if (len <= 0) 145 | { 146 | *r = 0; 147 | return r; 148 | } 149 | while (len--) 150 | { 151 | sprintf(buf, "%02X", (int) *((unsigned char *)data)); 152 | buf += 2; 153 | data = ((char *) data) + 1; 154 | } 155 | return r; 156 | } 157 | 158 | #define HEX_REPR(buf, len) hex_repr((char *)alloca((len) * 2 + 1), (void *)buf, len) 159 | 160 | static inline const char * 161 | tlv_repr(struct tlv_attr *a, char *buf, int buf_len) 162 | { 163 | snprintf(buf, buf_len, "", 164 | tlv_id(a), tlv_len(a), 165 | HEX_REPR((char *)tlv_data(a), tlv_len(a))); 166 | return buf; 167 | } 168 | 169 | #define TLV_REPR_LEN(a) (32 + 2 * tlv_len(a)) 170 | #define TLV_REPR(a) tlv_repr(a, alloca(TLV_REPR_LEN(a)), TLV_REPR_LEN(a)) 171 | 172 | #endif 173 | -------------------------------------------------------------------------------- /src/udp46.h: -------------------------------------------------------------------------------- 1 | /* 2 | * $Id: udp46.h $ 3 | * 4 | * Author: Markus Stenberg 5 | * 6 | * Copyright (c) 2014-2015 cisco Systems, Inc. 7 | * 8 | * Created: Thu May 15 12:16:06 2014 mstenber 9 | * Last modified: Mon Jun 15 12:57:40 2015 mstenber 10 | * Edit time: 27 min 11 | * 12 | */ 13 | 14 | #ifndef UDP46_H 15 | #define UDP46_H 16 | 17 | #include 18 | #include 19 | #include 20 | 21 | /** 22 | * 23 | * As dual-stack IPv6 (listening) UDP sockets are broken on many 24 | * platforms, this module provides an abstraction of a socket that is 25 | * actually _two_ sockets underneath: IPv4-only one, and IPv6-only 26 | * one, with convenience APIs for sending and receiving packets. 27 | * 28 | * All structures coming in and out are sockaddr_in6's. sockaddr_in 29 | * (and in_addr) are hidden. 30 | */ 31 | 32 | typedef struct udp46_struct *udp46, udp46_s; 33 | 34 | /** 35 | * Create/open a new socket. 36 | * 37 | * Effectively combination of socket(), bind(). 38 | * 39 | * Port is the port it is bound to, or 0 if left up to library. (The 40 | * library will get same port # for both IPv4 and IPv6 sockets it 41 | * creates underneath). 42 | */ 43 | udp46 udp46_create(uint16_t port); 44 | 45 | /** 46 | * Get the socket fds. 47 | */ 48 | void udp46_get_fds(udp46 s, int *fd_v4, int *fd_v6); 49 | 50 | typedef void (*udp46_readable_cb)(udp46 s, void *context); 51 | 52 | /** 53 | * Convenience method to set up callback to call when there is 54 | * something available. (It leverages uloop+ufd internally) 55 | */ 56 | void udp46_set_readable_cb(udp46 s, udp46_readable_cb cb, void *cb_context); 57 | 58 | /** 59 | * Receive a packet. 60 | * 61 | * Equivalent of socket type specific recvmsg() + magic to handle 62 | * source and destination addresses. -1 is returned if no packet 63 | * available. src and dst are optional. 64 | */ 65 | ssize_t udp46_recv(udp46 s, 66 | struct sockaddr_in6 *src, 67 | struct sockaddr_in6 *dst, 68 | void *buf, size_t buf_size); 69 | 70 | /** 71 | * Send a packet. 72 | * 73 | * Equivalent of socket type specific sendmsg() + magic to handle 74 | * source and destination addresses. 75 | **/ 76 | int udp46_send_iovec(udp46 s, 77 | const struct sockaddr_in6 *src, 78 | const struct sockaddr_in6 *dst, 79 | struct iovec *iov, int iov_len); 80 | 81 | int udp46_send(udp46 s, 82 | const struct sockaddr_in6 *src, 83 | const struct sockaddr_in6 *dst, 84 | void *buf, size_t buf_size); 85 | 86 | /** 87 | * Destroy/close a socket. 88 | */ 89 | void udp46_destroy(udp46 s); 90 | 91 | #endif /* UDP46_H */ 92 | -------------------------------------------------------------------------------- /src/udp46_i.h: -------------------------------------------------------------------------------- 1 | /* 2 | * $Id: udp46_i.h $ 3 | * 4 | * Author: Markus Stenberg 5 | * 6 | * Copyright (c) 2015 cisco Systems, Inc. 7 | * 8 | * Created: Tue May 26 08:28:45 2015 mstenber 9 | * Last modified: Mon Jun 8 12:19:59 2015 mstenber 10 | * Edit time: 8 min 11 | * 12 | */ 13 | 14 | #pragma once 15 | 16 | #include "hnetd.h" 17 | #include "dncp_util.h" 18 | #include "udp46.h" 19 | 20 | #undef __unused 21 | /* In linux some system includes have fields with __unused. Argh. */ 22 | #include 23 | #include 24 | #include 25 | #include 26 | #include 27 | #include 28 | #define __unused __attribute__((unused)) 29 | 30 | /* This is just cut-n-paste from minimalist-pcproxy shared.h ; most 31 | * likely won't compile on it's own, so just use it in udp46.c :p*/ 32 | 33 | #define IN_ADDR_TO_MAPPED_IN6_ADDR(a, a6) \ 34 | do { \ 35 | memset(a6, 0, sizeof(*(a6))); \ 36 | (a6)->s6_addr[10] = 0xff; \ 37 | (a6)->s6_addr[11] = 0xff; \ 38 | ((uint32_t *)a6)[3] = *((uint32_t *)a); \ 39 | } while (0) 40 | 41 | #define MAPPED_IN6_ADDR_TO_IN_ADDR(a6, a) \ 42 | do { \ 43 | *((uint32_t *)a) = ((uint32_t *)a6)[3]; \ 44 | } while (0) 45 | 46 | #define SOCKADDR_IN6_REPR(sa) SA6_D(sa) 47 | -------------------------------------------------------------------------------- /test/cert1.pem: -------------------------------------------------------------------------------- 1 | -----BEGIN CERTIFICATE----- 2 | MIIC0zCCAbugAwIBAgIJALrLwHnRDtuPMA0GCSqGSIb3DQEBBQUAMAAwHhcNMTQx 3 | MDIyMTA1OTAwWhcNNDgwODA5MTA1OTAwWjAAMIIBIjANBgkqhkiG9w0BAQEFAAOC 4 | AQ8AMIIBCgKCAQEAy1VWuhPQyLA/y3N8UwRJrg/EK6J2euUzPBjOz3YRAJLnhbI/ 5 | wWB9GNEIo56kPyq6qMn6WOMidmh4xJh/1wwdXBJkVZQJWWT4JssIA15ez2TFBbd6 6 | f83GFjHIlgq0bckyp9+73dF6d/O8ef1zTTp76DkMS2kE3iPMOUUf3lUP+aDOgNR3 7 | Zsoun2ncLC/ESfJQn7t6MNm3a+fMpN7szz5VVMfPZK7A+GVgJ0RV+/250dzGUuM/ 8 | lBdfrcm6SWLZxL2j2wPR9WjnoMpC15sryluLebhtSCQhtA1TPZh8z5QSF88al9/P 9 | sfDzIOroOtYvzTqzUAVclmJZNfEpSwbfzHaSRwIDAQABo1AwTjAdBgNVHQ4EFgQU 10 | wHnuh4GpcNf99QGbYOH7sYP7RJswHwYDVR0jBBgwFoAUwHnuh4GpcNf99QGbYOH7 11 | sYP7RJswDAYDVR0TBAUwAwEB/zANBgkqhkiG9w0BAQUFAAOCAQEAfrKKymv8Qljm 12 | 1WV2hMYjPaqDjUz6myVCIs6H3FnMnBE91prq4e8unk/fajiHP4Z5qbMAeaW1y/YQ 13 | LpPnv9oEHip3izYhF1fJkMZ2ubKzYCqJE4SpRnV+RPSlANZr/8RFaYFuIM5Mmlie 14 | ovMGA90ov9A2vha9VkfgZOfnMIE92hIVAhinvHaiHJEB/uRXMV3tiMzSjC0xyb8/ 15 | HHfWknwgdrrmhFCsYZ6ZvbJMnwG3VkYBgyGNLQmwNEEa59dobCgjzYpckWKs3zWi 16 | NLBiH61b2W5kaQIDKTnUMl82BC6r2igsZfGzXj89Eosrrv5mBSgZa+AW/wgXrVVc 17 | 1R6lkKIbuw== 18 | -----END CERTIFICATE----- 19 | -------------------------------------------------------------------------------- /test/cert2.pem: -------------------------------------------------------------------------------- 1 | -----BEGIN CERTIFICATE----- 2 | MIIC0zCCAbugAwIBAgIJALTMHNFp3cB8MA0GCSqGSIb3DQEBBQUAMAAwHhcNMTQx 3 | MDIyMTEwMjIwWhcNNDgwODA5MTEwMjIwWjAAMIIBIjANBgkqhkiG9w0BAQEFAAOC 4 | AQ8AMIIBCgKCAQEAzEsR5uwtaIlNcGXILp49RFKC3u1XpA1/EZ3Jom/1kDToxwVz 5 | fh4Qg6BBwp+4P1vAgErGzdYux4SfjCTC/bUYYW5sCGvN9kSoA9Mb2sf0c8QfEaCb 6 | COZHCcVZl97KmPMNj6jcgs7zGA/0/kaEVOSG5j7zOD02oxESJDEGrQQbVp1+7geC 7 | 5heFY8IfFhDn4Pgb3P5BwH4prXbOlXp/n+z76cK0kXagEUOdvaW8j7m6MOajD4Al 8 | VnK36zGQ6QLj9QubhwrlsTzRDGhrkttuglupdEKYjfn01t3CjnW42au6PwRAb/mY 9 | Ui2uaG+enlw7Q39zq88VmmlI3KsHaghK/vUpgQIDAQABo1AwTjAdBgNVHQ4EFgQU 10 | m66nm/X+R5Tews3T2x2jqS3XU10wHwYDVR0jBBgwFoAUm66nm/X+R5Tews3T2x2j 11 | qS3XU10wDAYDVR0TBAUwAwEB/zANBgkqhkiG9w0BAQUFAAOCAQEAcdLxYsXf0/Ib 12 | oE36pX8vmvkDqKspVp9fp+o1ZF35m37Iqp+LvbL7CK1pWb1WaAftG9T2C3rg1Nq6 13 | Ypkf0bMtziRHFJgqAs7YW57rwN7XNpL747OWBY1RoumxpZy0FA4mgdw2gDEJVikr 14 | jCdZz8Cr/CxVGBcRgS46ccIrFQaMaY2z8AYhfzSrP/ncTdjB8UqxyiNTuPJNgftW 15 | zjj/UOqfkGfz7c+dcmCx9JsVmYFmrVjDdkxR6e/mWGNr2pDonM3RcmoH6fIzkFin 16 | mV6wX866S8CskBmTbhBHiFdL1SxAWhcD2MEl4TOMEo68a/OyS1THl9ZUaqiFQce+ 17 | 0WibdejY6A== 18 | -----END CERTIFICATE----- 19 | -------------------------------------------------------------------------------- /test/eea339da.0: -------------------------------------------------------------------------------- 1 | cert1.pem -------------------------------------------------------------------------------- /test/eea339da.1: -------------------------------------------------------------------------------- 1 | cert2.pem -------------------------------------------------------------------------------- /test/fake_fork_exec.h: -------------------------------------------------------------------------------- 1 | /* 2 | * $Id: fake_fork_exec.h $ 3 | * 4 | * Author: Markus Stenberg 5 | * 6 | * Copyright (c) 2015 cisco Systems, Inc. 7 | * 8 | * Created: Mon Feb 23 21:02:53 2015 mstenber 9 | * Last modified: Wed Apr 29 16:45:08 2015 mstenber 10 | * Edit time: 1 min 11 | * 12 | */ 13 | 14 | #pragma once 15 | 16 | /* Prevent execve/vfork/waitpid/_exit definition */ 17 | #include 18 | #include 19 | #include 20 | 21 | /* Stub out the code that calls things */ 22 | #define execv(cmd, argv) do \ 23 | { \ 24 | if (check_exec || debug_exec) \ 25 | { \ 26 | int i; \ 27 | L_DEBUG("execv: '%s'", cmd); \ 28 | if (check_exec) \ 29 | smock_pull_string_is("execv_cmd", cmd); \ 30 | for (i = 1; argv[i]; i++) \ 31 | { \ 32 | L_DEBUG(" arg#%d: '%s'", i, argv[i]); \ 33 | if (check_exec) \ 34 | smock_pull_string_is("execv_arg", argv[i]); \ 35 | } \ 36 | } \ 37 | else \ 38 | execs++; \ 39 | } while (0) 40 | 41 | bool check_exec, debug_exec; 42 | int execs; 43 | 44 | #define vfork() 0 45 | #define fork() 0 46 | #define waitpid(pid, x, y) 47 | #define _exit(code) 48 | 49 | pid_t hncp_run(char *argv[]) 50 | { 51 | /* Pretend we ran something. */ 52 | execv(argv[0], argv); 53 | return 0; 54 | } 55 | -------------------------------------------------------------------------------- /test/fake_iface.h: -------------------------------------------------------------------------------- 1 | /* 2 | * $Id: fake_iface.h $ 3 | * 4 | * Author: Markus Stenberg 5 | * 6 | * Copyright (c) 2015 cisco Systems, Inc. 7 | * 8 | * Created: Thu Feb 26 13:40:08 2015 mstenber 9 | * Last modified: Tue Jul 21 12:04:42 2015 mstenber 10 | * Edit time: 3 min 11 | * 12 | */ 13 | 14 | #pragma once 15 | 16 | #include "iface.h" 17 | #include "smock.h" 18 | 19 | /********************************************************************* iface */ 20 | 21 | bool mock_iface = false; 22 | 23 | struct iface default_iface = {.elected = -1, 24 | .internal = true}; 25 | 26 | int iface_get_address(struct in6_addr *addr, bool v4, const struct in6_addr *preferred) 27 | { 28 | return -1; 29 | } 30 | 31 | struct iface* iface_get(const char *ifname) 32 | { 33 | if (mock_iface) 34 | return smock_pull("iface_get"); 35 | static struct { 36 | struct iface iface; 37 | char ifname[16]; 38 | } iface; 39 | strcpy(iface.ifname, ifname); 40 | iface.iface = default_iface; 41 | return &iface.iface; 42 | } 43 | 44 | struct iface* iface_next(struct iface *prev) 45 | { 46 | if (mock_iface) 47 | return smock_pull("iface_next"); 48 | return NULL; 49 | } 50 | 51 | void iface_all_set_dhcp_send(const void *dhcpv6_data, size_t dhcpv6_len, 52 | const void *dhcp_data, size_t dhcp_len) 53 | { 54 | } 55 | 56 | int iface_get_preferred_address(struct in6_addr *foo, bool v4, 57 | const char *ifname) 58 | { 59 | inet_pton(AF_INET6, (v4) ? "::ffff:192.168.1.2" : "2001:db8::f00:1", foo); 60 | return 0; 61 | } 62 | 63 | struct list_head *current_iface_users = NULL; 64 | 65 | void iface_register_user(struct iface_user *user) 66 | { 67 | sput_fail_unless(current_iface_users, "no current_iface_users"); 68 | if (current_iface_users) 69 | list_add(&user->head, current_iface_users); 70 | } 71 | 72 | void iface_unregister_user(struct iface_user *user) 73 | { 74 | list_del(&user->head); 75 | } 76 | 77 | #define net_sim_node_iface_cb(n, cb_name, ...) \ 78 | do { \ 79 | struct iface_user *u; \ 80 | list_for_each_entry(u, &n->iface_users, head) \ 81 | if (u->cb_name) \ 82 | u->cb_name(u, __VA_ARGS__); \ 83 | } while(0) 84 | -------------------------------------------------------------------------------- /test/fake_log.h: -------------------------------------------------------------------------------- 1 | /* 2 | * $Id: fake_log.h $ 3 | * 4 | * Author: Markus Stenberg 5 | * 6 | * Copyright (c) 2015 cisco Systems, Inc. 7 | * 8 | * Created: Mon Jun 8 09:54:52 2015 mstenber 9 | * Last modified: Wed Jul 1 11:18:05 2015 mstenber 10 | * Edit time: 18 min 11 | * 12 | */ 13 | 14 | #pragma once 15 | 16 | #include "hnetd.h" 17 | 18 | #include "sput.h" 19 | 20 | #include 21 | #include 22 | 23 | static void fake_log(int priority, const char *format, ...) 24 | { 25 | va_list a; 26 | 27 | printf("[%d]", priority); 28 | va_start(a, format); 29 | vprintf(format, a); 30 | va_end(a); 31 | printf("\n"); 32 | } 33 | 34 | void fake_log_check(int priority __unused, 35 | const char *format, ...) 36 | { 37 | va_list a; 38 | char buf[1024]; 39 | 40 | va_start(a, format); 41 | vsnprintf(buf, sizeof(buf), format, a); 42 | va_end(a); 43 | } 44 | 45 | void fake_log_disable(int priority __unused, 46 | const char *format __unused, ...) 47 | { 48 | } 49 | 50 | 51 | int log_level = 7; 52 | void (*hnetd_log)(int priority, const char *format, ...) = fake_log; 53 | 54 | #define fake_log_init() \ 55 | do { \ 56 | bool quiet = true; \ 57 | if (getenv("FAKE_LOG_CHECK")) \ 58 | hnetd_log = fake_log_check; \ 59 | else if (getenv("FAKE_LOG_DISABLE")) \ 60 | hnetd_log = fake_log_disable; \ 61 | else \ 62 | quiet = false; \ 63 | if (quiet) \ 64 | { \ 65 | FILE *f = fopen("/dev/null", "w"); \ 66 | sput_set_output_stream(f); \ 67 | } \ 68 | } while(0) 69 | -------------------------------------------------------------------------------- /test/fake_random.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2015 Cisco Systems, Inc. 3 | */ 4 | /* 5 | * Author: Pierre Pfister 6 | * 7 | * Fakes random and md5 functions used in various places in hnetd. 8 | * 9 | * It was put in a separate file because both test_pa and test_pa_pd use it. 10 | * 11 | */ 12 | 13 | #ifndef FAKE_RANDOM_H_ 14 | #define FAKE_RANDOM_H_ 15 | 16 | #include "sput.h" 17 | #include "smock.h" 18 | 19 | /* RANDOM */ 20 | 21 | #include 22 | #define FR_RANDOM_QUEUE "fu_random" 23 | #ifdef FR_MASK_RANDOM 24 | bool fr_mask_random = true; 25 | #else 26 | bool fr_mask_random = false; 27 | #endif 28 | 29 | inline static long int fr_random() { 30 | long int res; 31 | if(fr_mask_random) { 32 | int64_t *i = (int64_t *)smock_pull_int(FR_RANDOM_QUEUE); 33 | res = *i; 34 | free(i); 35 | } else { 36 | res = random(); 37 | } 38 | return res; 39 | } 40 | 41 | inline static void fr_random_push(long int i) { 42 | smock_push_int64(FR_RANDOM_QUEUE, i); 43 | } 44 | 45 | #define random fr_random 46 | 47 | 48 | /* MD5 */ 49 | 50 | #include 51 | #define FR_MD5_QUEUE "fu_random" 52 | #ifdef FR_MASK_MD5 53 | bool fr_mask_md5 = true; 54 | #else 55 | bool fr_mask_md5 = false; 56 | #endif 57 | 58 | inline static void fr_md5begin(md5_ctx_t *ctx) 59 | { 60 | if(!fr_mask_md5) 61 | md5_begin(ctx); 62 | } 63 | inline static void fr_md5hash(const void *data, size_t length, md5_ctx_t *ctx) 64 | { 65 | if(!fr_mask_md5) 66 | md5_hash(data, length, ctx); 67 | } 68 | 69 | inline static void fr_md5end(void *resbuf, md5_ctx_t *ctx) 70 | { 71 | void *buff; 72 | if(!fr_mask_md5) { 73 | md5_end(resbuf, ctx); 74 | return; 75 | } 76 | 77 | buff = smock_pull(FR_MD5_QUEUE); 78 | memcpy(resbuf, buff, 16); 79 | free(buff); 80 | } 81 | 82 | inline static void fr_md5_push(const void *buff) 83 | { 84 | void *b = malloc(16); 85 | sput_fail_unless(b, "Can't allocate md5 result"); 86 | if(!b) 87 | return; 88 | 89 | memcpy(b, buff, 16); 90 | smock_push(FR_MD5_QUEUE, b); 91 | } 92 | 93 | #define fr_md5_push_prefix(p) fr_md5_push((void *) &(p)->prefix) 94 | 95 | #define md5_begin fr_md5begin 96 | #define md5_hash fr_md5hash 97 | #define md5_end fr_md5end 98 | 99 | #endif /* FAKE_RANDOM_H_ */ 100 | -------------------------------------------------------------------------------- /test/fake_uloop.h: -------------------------------------------------------------------------------- 1 | /* 2 | * $Id: fake_uloop.h $ 3 | * 4 | * Author: Markus Stenberg 5 | * 6 | * Copyright (c) 2014-2015 cisco Systems, Inc. 7 | * 8 | */ 9 | 10 | /* This is written with two potential applications in mind; 11 | 12 | [1] test applications that want to manage their own time (net_sim) 13 | 14 | and 15 | 16 | [2] test applications that want uloop to pretend that time moves 17 | for them (test_pa, test_iface). 18 | 19 | The code's based on bits and pieces from test_pa and net_sim, 20 | merged to keep it in one place and reusable elsewhere too. The main 21 | idea is that there's only ONE place where time and list of pending 22 | timeouts is kept, and that's here (just like in test_pa). 23 | 24 | As shared functionality, we provide replacement for hnetd_time(), 25 | as well as set_hnetd_time() utility call. 26 | 27 | For case [1] we provide fu_poll() which runs currently pending 28 | timeouts and provide fu_next_time() (returns the time of next event). 29 | 30 | For case [2] we provide uloop_run() which obeys also uloop_end(). 31 | */ 32 | 33 | #ifndef FAKE_ULOOP_H 34 | #define FAKE_ULOOP_H 35 | 36 | #include "hnetd.h" 37 | 38 | #include 39 | 40 | #include "sput.h" 41 | 42 | #define set_hnetd_time fu_set_hnetd_time 43 | #define set_time set_hnetd_time 44 | 45 | #define uloop_init() fu_init() 46 | #define uloop_run() (void)fu_loop(-1) 47 | #define uloop_end() do { _fu_loop_ended = true; } while(0) 48 | 49 | 50 | static hnetd_time_t _fu_time; 51 | LIST_HEAD(timeouts); 52 | 53 | hnetd_time_t hnetd_time() 54 | { 55 | return _fu_time; 56 | } 57 | 58 | static inline void fu_init() 59 | { 60 | /* 12345678901 (> MAXINT, but not much over) */ 61 | _fu_time = 10000000000; 62 | INIT_LIST_HEAD(&timeouts); 63 | } 64 | 65 | static inline void fu_set_hnetd_time(hnetd_time_t v) 66 | { 67 | sput_fail_unless(v >= _fu_time, "time cannot move to past"); 68 | L_DEBUG("fu_set_hnetd_time=%lld", (long long) v); 69 | _fu_time = v; 70 | } 71 | 72 | static void _to_tv(hnetd_time_t t, struct timeval *tv) 73 | { 74 | tv->tv_sec = t / HNETD_TIME_PER_SECOND; 75 | tv->tv_usec = t % HNETD_TIME_PER_SECOND; 76 | } 77 | 78 | static hnetd_time_t _to_time(struct timeval *tv) 79 | { 80 | return (int64_t)tv->tv_sec * HNETD_TIME_PER_SECOND + tv->tv_usec; 81 | } 82 | 83 | int hnetd_time_timeout_remaining(struct uloop_timeout *to) 84 | { 85 | if (!to->pending) 86 | return -1; 87 | return (int)(_to_time(&(to)->time) - _fu_time); 88 | } 89 | 90 | int hnetd_time_timeout_set(struct uloop_timeout *timeout, int ms) 91 | { 92 | sput_fail_if(ms < 0, "Timeout delay is positive"); 93 | hnetd_time_t v = hnetd_time() + ms; 94 | 95 | if(timeout->pending) 96 | list_del(&timeout->list); 97 | else 98 | timeout->pending = true; 99 | 100 | _to_tv(v, &timeout->time); 101 | 102 | struct uloop_timeout *tp; 103 | list_for_each_entry(tp, &timeouts, list) 104 | { 105 | if (_to_time(&tp->time) > v) 106 | { 107 | list_add_tail(&timeout->list, &tp->list); 108 | return 0; 109 | } 110 | } 111 | list_add_tail(&timeout->list, &timeouts); 112 | return 0; 113 | } 114 | 115 | static inline int fu_timeouts() 116 | { 117 | int c = 0; 118 | struct uloop_timeout *tp; 119 | list_for_each_entry(tp, &timeouts, list) 120 | c++; 121 | return c; 122 | } 123 | 124 | int hnetd_time_timeout_cancel(struct uloop_timeout *timeout) 125 | { 126 | #ifdef FU_PARANOID_TIMEOUT_CANCEL 127 | sput_fail_unless(timeout->pending, "Timeout pending in timeout_cancel"); 128 | #endif /* FU_PARANOID_TIMEOUT_CANCEL */ 129 | if (timeout->pending) 130 | { 131 | list_del(&timeout->list); 132 | timeout->pending = 0; 133 | } 134 | return 0; 135 | } 136 | 137 | static inline struct uloop_timeout *fu_next() 138 | { 139 | if (list_empty(&timeouts)) 140 | return NULL; 141 | return list_first_entry(&timeouts, struct uloop_timeout, list); 142 | } 143 | 144 | static inline hnetd_time_t fu_next_time() 145 | { 146 | struct uloop_timeout *to = fu_next(); 147 | return to && _to_time(&to->time); 148 | } 149 | 150 | static inline void fu_run_one(struct uloop_timeout *t) 151 | { 152 | list_del(&t->list); 153 | t->pending = false; 154 | if(t->cb) 155 | t->cb(t); 156 | } 157 | 158 | static bool _fu_loop_ended; 159 | static inline int fu_loop(int rounds) 160 | { 161 | struct uloop_timeout *to; 162 | 163 | _fu_loop_ended = false; 164 | while (!_fu_loop_ended && rounds != 0 && (to = fu_next())) 165 | { 166 | hnetd_time_t when = _to_time(&to->time); 167 | if (when >= hnetd_time()) 168 | set_hnetd_time(when); 169 | fu_run_one(to); 170 | rounds--; 171 | } 172 | return rounds; 173 | } 174 | 175 | static inline int fu_poll(void) 176 | { 177 | int ran = 0; 178 | hnetd_time_t now = hnetd_time(); 179 | struct uloop_timeout *to; 180 | 181 | while ((to = fu_next()) && _to_time(&to->time) <= now) 182 | { 183 | fu_run_one(to); 184 | ran++; 185 | } 186 | return ran; 187 | } 188 | 189 | 190 | #endif /* FAKE_ULOOP_H */ 191 | -------------------------------------------------------------------------------- /test/key1.pem: -------------------------------------------------------------------------------- 1 | -----BEGIN PRIVATE KEY----- 2 | MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQDLVVa6E9DIsD/L 3 | c3xTBEmuD8QronZ65TM8GM7PdhEAkueFsj/BYH0Y0QijnqQ/KrqoyfpY4yJ2aHjE 4 | mH/XDB1cEmRVlAlZZPgmywgDXl7PZMUFt3p/zcYWMciWCrRtyTKn37vd0Xp387x5 5 | /XNNOnvoOQxLaQTeI8w5RR/eVQ/5oM6A1Hdmyi6fadwsL8RJ8lCfu3ow2bdr58yk 6 | 3uzPPlVUx89krsD4ZWAnRFX7/bnR3MZS4z+UF1+tybpJYtnEvaPbA9H1aOegykLX 7 | myvKW4t5uG1IJCG0DVM9mHzPlBIXzxqX38+x8PMg6ug61i/NOrNQBVyWYlk18SlL 8 | Bt/MdpJHAgMBAAECggEACxqm+NR6M2uEoFy3LmVujKXpxaRCqiV4LdEBAk1lUk2z 9 | fRal6q6VRlSsDxtrxtNTjEIzfMUyrZq49auKV7kepVePySijdhFQh/XQgzaVIOhU 10 | 5iIF+5LGPZIMbT06a0BwlsBeJxf4gzJ5WYQg1tfZym3LIRckH+l+jqYavm6Qx8YK 11 | c77jSS1Rwe/tw5EXvbmBVLd1+VCufgogmPGIClK8MPotmpDGGZWIt9/popeGmUSF 12 | TJoo1E+uAfzl6kYsLduiNJv293qekDLmV/lGs7mfc4SiKLk77zYm2aeXD06FWpbe 13 | dX4d8L5n0D6mcKizwRekjB2OtZhvZklHe4NBRPjU2QKBgQDpwtREptj8e5mrJJId 14 | OGwLHk0NC5YpsVK1d0jokDTBP4mpZ0cWHuCeP2xpZAQrHOkuZz54I3T5w4THKol2 15 | hfdd5b1Tv6d+to6elGObkC5LnesqeiFWgZLDYt1axdURckPQXstwdWCqFgCKJ9Uh 16 | NhY1HvtMe61ZyHia5gvZecIhtQKBgQDerXQSahCZ+xCEUyj3w/ha8r9GiUkA6NEg 17 | +O6R4f69qVoAve6qUskLn0TA/y3Cb8ZrIottWiNXRowy6Vb1hL4dUAhdfWKPaQUG 18 | 1nMZIefIZWqTLVSA6zr4A3h9LC5lfmbzN/coUBDsy8tYwk9Z2lnOraJb/CdxiQhF 19 | 83vc5FRRiwKBgQCNLuzBYfwf0g7nvLi7CT7IIE7tGBhjqgOIMjlIrQAPz243cHcQ 20 | tyl2qlux84RI/bcgHZ8vNEsMJrhlCh3oBdV3UrBcip6A+4V75aebZyNu7DwCdaz4 21 | 8F1RwL5sepvLY7XtfbNlgp8VWyCMUK561o3nG4UvlmsGlPuyokp52P4VGQKBgGZK 22 | 1Blpc/roZKwE77rx4XMWNFwY0NqEGR3GfQGzCazi0R+qIKtJoGWgYpsuHj1Fz6aD 23 | lf1D/Rwoolr46iObOSKKE22vHcm3esGrXfBbrPhX7l9x4XHfnZU1MvJ9i0rAiFaO 24 | jRGNxlihPeamTIGAVuUkyoLrEMuNIanQskPE+B8FAoGBANOrh6vxjk+dnb4MxlSP 25 | eVpidxLHg7FI4yJuA9zYRnqouM3Xrjh0CphQsyW0ew1BKk9PmrOS8LS5vCSY+eTg 26 | TB5ZkTv6e7KaylfM3ujVYj6urlrJkcQVtRoskyZxIL4lit6GxuqojmKp4UYPS811 27 | 1WyVNNSULuNgD7CURKaacVM6 28 | -----END PRIVATE KEY----- 29 | -------------------------------------------------------------------------------- /test/key2.pem: -------------------------------------------------------------------------------- 1 | -----BEGIN PRIVATE KEY----- 2 | MIIEvwIBADANBgkqhkiG9w0BAQEFAASCBKkwggSlAgEAAoIBAQDMSxHm7C1oiU1w 3 | Zcgunj1EUoLe7VekDX8Rncmib/WQNOjHBXN+HhCDoEHCn7g/W8CASsbN1i7HhJ+M 4 | JML9tRhhbmwIa832RKgD0xvax/RzxB8RoJsI5kcJxVmX3sqY8w2PqNyCzvMYD/T+ 5 | RoRU5IbmPvM4PTajERIkMQatBBtWnX7uB4LmF4Vjwh8WEOfg+Bvc/kHAfimtds6V 6 | en+f7PvpwrSRdqARQ529pbyPubow5qMPgCVWcrfrMZDpAuP1C5uHCuWxPNEMaGuS 7 | 226CW6l0QpiN+fTW3cKOdbjZq7o/BEBv+ZhSLa5ob56eXDtDf3OrzxWaaUjcqwdq 8 | CEr+9SmBAgMBAAECggEBAIBG1uvX+r88D5r23hafl7rR0IkoILLLIrGuERDlGh09 9 | i7iELLvRJu9vbjtFzQxDkYE88s4GogL3vLLj1mg2ESQEkONMxdvPymv0X/YlPdJ/ 10 | ID8SSKby6UIyYApjg3U8kJRXJHcieTPvuRb8slUX1bi3aEM09Jy5uFlvS1DSVlQw 11 | my36NXE/sTuCJre7yXSROLIZVmC4dKcjYrwtdgqIxkBMVji0rJtr98KnV51re6Cs 12 | qUFgxOvsSb81z9NKS/kKyYXqiijmj0yvI5YuPI0qZ2puj6dePDVUcjfebXTqGaAh 13 | zS/HNUvX4tVRruVON1i+wCMAAqMDvz9Z11CchMSPVi0CgYEA7uE0mkoSR4rtrwdA 14 | 2uD5X727BmyLqxmhNpsvH8tFXVkFtMU/CqM/qjZISykNv7kE/C1inDDp9grAY0b7 15 | kh0AQINXeOaDzLI/FGgC/PPQeT95MYa1YGEjJri3my+JXJeuCEBRb+4ZrIsVPj3N 16 | nmXCgi2xT7BTXfkUU/8tB44GGtsCgYEA2u9L73ZO2GmYm+qkBg4eZE+TGzb9VD8E 17 | Ye0d/ahBtvUapZMNlw8d6qQuFLWz4PYUJFK1fN/gYDXVjCkF+W3Y6YbZ9qo7c4ao 18 | UlmvNme2ahMrK8e1bmvVX85/VOR1czU8JTPKlyr0tIyFPnXc/9k9W5ZD6Pgy2x/Z 19 | 0jonROcQRdMCgYEAo8/QENYmvuTopZRlxzNsD1m+vWMGTGkhAp9cq4LrqF356cMx 20 | vgvBBup+nPwkL4ujfYNqEg4BAvbQg8QTlFlK6PKos4HwdBjv5QCGvAw+tEbwxyPH 21 | kbZLMqyNTGBG5DYn5ASnVAiFlqsyACLFtI+32SmYZDtYkCLU690bdgjQ6u0CgYEA 22 | guOfpVk4yB9Rcp20VD5qoxQD4bhdedl2+Ei3rmfCaexdcvHYpSAPhbGELzN2iB72 23 | acTc5fw+e6aTtgjsnnOyw+KwOs0JYAb4aMtfegpFP2OYYsMx0AM9/NpKu+kd4rPH 24 | 8oHlM70lsS91laMHbhplmXTbwtNoLCL9qbbEtWfjDasCgYAa1bpG93tSbLyv1KW1 25 | Sh5R09UBkdqOwSzIuKrjFVLeMiaXupTLBs6g2tkfaWiumeV4AYkp8DP4JtbcQnXK 26 | 1Z3tYsrKnB6jc6oW5vvpg/ku0BnHs4Ji6PITBwGMXbAmkO9LWRrHlFFCKOVf0qT8 27 | i3ruEAgUIhr0q9NEcRb9LVrXHQ== 28 | -----END PRIVATE KEY----- 29 | -------------------------------------------------------------------------------- /test/prefixes_library.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2015 Cisco Systems, Inc. 3 | */ 4 | /* 5 | * Author: Pierre Pfister 6 | * 7 | * Just a bunch of defined prefixes, interface names and DHCP_DATA that can be used for tests. 8 | * Based on test_pa.c used prefixes. 9 | * 10 | */ 11 | 12 | #ifndef PREFIXES_LIBRARY_H_ 13 | #define PREFIXES_LIBRARY_H_ 14 | 15 | #include "prefix_utils.h" 16 | 17 | 18 | #define PL_ROOT 0x20,0x01, 0x20,0x00, 0x00,0x00 19 | #define PL_V4inV6 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0xff,0xff 20 | #define PL_ROOT4 PL_V4inV6, 0x0a 21 | 22 | #define PL_EUI64 0x00,0x00, 0x00,0x00, 0xff,0xff, 0xff,0xff 23 | #define PL_ADDR0 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00 24 | 25 | #define PL_P1 { .plen = 56 , .prefix = { .s6_addr = {PL_ROOT, 0x01}} } 26 | #define PL_P1_0 { .plen = 60 , .prefix = { .s6_addr = {PL_ROOT, 0x01,0x00}} } 27 | #define PL_P1_01 { .plen = 64 , .prefix = { .s6_addr = {PL_ROOT, 0x01,0x01}} } 28 | #define PL_P1_01A { .plen = 128, .prefix = { .s6_addr = {PL_ROOT, 0x01,0x01, PL_EUI64}} } 29 | #define PL_P1_01A1 { .plen = 128, .prefix = { .s6_addr = {PL_ROOT, 0x01,0x01, PL_ADDR0, 0x01}} } 30 | #define PL_P1_01A2 { .plen = 128, .prefix = { .s6_addr = {PL_ROOT, 0x01,0x01, PL_ADDR0, 0x02}} } 31 | #define PL_P1_02 { .plen = 64 , .prefix = { .s6_addr = {PL_ROOT, 0x01,0x02}} } 32 | #define PL_P1_02A { .plen = 128, .prefix = { .s6_addr = {PL_ROOT, 0x01,0x02, PL_EUI64}} } 33 | #define PL_P1_04 { .plen = 64 , .prefix = { .s6_addr = {PL_ROOT, 0x01,0x04}} } 34 | #define PL_P1_08 { .plen = 64 , .prefix = { .s6_addr = {PL_ROOT, 0x01,0x08}} } 35 | #define PL_P1_10 { .plen = 64 , .prefix = { .s6_addr = {PL_ROOT, 0x01,0x10}} } 36 | #define PL_P1_11 { .plen = 64 , .prefix = { .s6_addr = {PL_ROOT, 0x01,0x11}} } 37 | #define PL_P1_24 { .plen = 64 , .prefix = { .s6_addr = {PL_ROOT, 0x01,0x24}} } 38 | 39 | #define PL_P2 { .plen = 56 , .prefix = { .s6_addr = {PL_ROOT, 0x02}} } 40 | #define PL_P2_01 { .plen = 64 , .prefix = { .s6_addr = {PL_ROOT, 0x02, 0x01}} } 41 | #define PL_P2_02 { .plen = 64 , .prefix = { .s6_addr = {PL_ROOT, 0x02, 0x02}} } 42 | 43 | #define PL_P3 { .plen = 56 , .prefix = { .s6_addr = {PL_ROOT, 0x03}} } 44 | 45 | #define PL_PV4 { .plen = 104, .prefix = { .s6_addr = {PL_ROOT4}} } 46 | #define PL_PV4b { .plen = 112, .prefix = { .s6_addr = {PL_V4inV6, 0xc0, 0xa8}} } 47 | 48 | #define PL_PV4_1 { .plen = 120, .prefix = { .s6_addr = {PL_ROOT4, 0x00, 0x01}} } 49 | #define PL_PV4_1_1 { .plen = 128, .prefix = { .s6_addr = {PL_ROOT4, 0x00, 0x01,0x01}} } 50 | #define PL_PV4_1_ff { .plen = 128, .prefix = { .s6_addr = {PL_ROOT4, 0x00, 0x01,0xff}} } 51 | 52 | #define PL_ULA1 { .plen = 48 , .prefix = { .s6_addr = {0xfd,0x00, 0x00,0x00, 0x00,0x01}} } 53 | #define PL_ULA2 { .plen = 48 , .prefix = { .s6_addr = {0xfd,0x00, 0x00,0x00, 0x00,0x02}} } 54 | 55 | #define PL_IFNAME1 "iface1" 56 | #define PL_IFNAME2 "iface2" 57 | #define PL_IFNAME3 "iface3" 58 | 59 | #define PL_DHCP_DATA "some-dhcp-data" 60 | #define PL_DHCP_LEN 15 61 | 62 | #endif /* PREFIXES_LIBRARY_H_ */ 63 | -------------------------------------------------------------------------------- /test/smock.h: -------------------------------------------------------------------------------- 1 | /* 2 | * $Id: smock.h $ 3 | * 4 | * Author: Markus Stenberg 5 | * 6 | * Copyright (c) 2013-2015 cisco Systems, Inc. 7 | * 8 | * Created: Tue Nov 26 10:14:59 2013 mstenber 9 | * Last modified: Wed Mar 19 17:32:16 2014 mstenber 10 | * Edit time: 72 min 11 | * 12 | */ 13 | 14 | #ifndef SMOCK_H 15 | #define SMOCK_H 16 | 17 | #include 18 | 19 | #define SMOCK_QUEUE_NAME_LENGTH 64 20 | 21 | /* 22 | * Simple mock library. Only dependency is libubox (for linked list) 23 | * and sput (for 'pretty' assertions). 24 | */ 25 | 26 | /* Basic idea: Structure code so that mocked parameters can be 27 | * guessed, or represented in some human-readable code within unit 28 | * tests. Then, actual use consists of: 29 | * 30 | * - In testcase, supplying mock arguments as needed (smock_push(q, 31 | * v)). 32 | * 33 | * - Add hooks to pull input parameters (to be checked on call) and 34 | * output parameters (to be stored in return values) within mock 35 | * functions (smock_pull(q)). 36 | * 37 | * - Finally, ensuring that everything's consumed every now and then 38 | * within the testcase (smock_empty()). 39 | */ 40 | 41 | /* This is where every queue is stored. */ 42 | static struct list_head *_smock_head; 43 | 44 | typedef struct { 45 | /* within _smock_head */ 46 | struct list_head lh; 47 | 48 | /* entries */ 49 | struct list_head eh; 50 | char name[SMOCK_QUEUE_NAME_LENGTH]; 51 | } smock_queue_s, *smock_queue; 52 | 53 | 54 | typedef struct { 55 | struct list_head lh; 56 | void *value; 57 | } smock_entry_s, *smock_entry; 58 | 59 | static inline smock_queue _smock_get_queue(const char *name, bool create) 60 | { 61 | struct list_head *h; 62 | smock_queue q; 63 | 64 | if (!_smock_head) 65 | { 66 | if (!create) 67 | return NULL; 68 | /* Create new head. */ 69 | _smock_head = malloc(sizeof(*_smock_head)); 70 | if (!_smock_head) 71 | return NULL; 72 | INIT_LIST_HEAD(_smock_head); 73 | } 74 | if (strlen(name) >= SMOCK_QUEUE_NAME_LENGTH) 75 | return NULL; 76 | list_for_each(h, _smock_head) 77 | { 78 | q = container_of(h, smock_queue_s, lh); 79 | if (strcmp(name, q->name) == 0) 80 | return q; 81 | } 82 | if (!create) 83 | return NULL; 84 | q = calloc(1, sizeof(*q)); 85 | if (!q) 86 | return NULL; 87 | strcpy(q->name, name); 88 | list_add(&q->lh, _smock_head); 89 | INIT_LIST_HEAD(&q->eh); 90 | return q; 91 | } 92 | 93 | static inline void smock_push(const char *name, void *value) 94 | { 95 | smock_queue q = _smock_get_queue(name, true); 96 | smock_entry e = calloc(1, sizeof(*e)); 97 | 98 | e->value = value; 99 | list_add_tail(&e->lh, &q->eh); 100 | } 101 | 102 | static inline void *smock_pull(const char *name) 103 | { 104 | smock_queue q = _smock_get_queue(name, false); 105 | struct list_head *h; 106 | smock_entry e; 107 | void *r; 108 | 109 | sput_fail_unless(q, name); 110 | if (!q) 111 | { 112 | return NULL; 113 | } 114 | if (list_empty(&q->eh)) 115 | { 116 | sput_fail_unless(!list_empty(&q->eh), "queue not empty "); 117 | return NULL; 118 | } 119 | h = q->eh.next; 120 | list_del(h); 121 | e = container_of(h, smock_entry_s, lh); 122 | r = e->value; 123 | free(e); 124 | if (list_empty(&q->eh)) 125 | { 126 | /* Get rid of q */ 127 | list_del(&q->lh); 128 | free(q); 129 | if (list_empty(_smock_head)) 130 | { 131 | free(_smock_head); 132 | _smock_head = NULL; 133 | } 134 | } 135 | return r; 136 | } 137 | 138 | #define smock_empty() (_smock_head == NULL) 139 | 140 | static inline void smock_is_empty() 141 | { 142 | struct list_head *h; 143 | smock_queue q; 144 | if (!smock_empty()) { 145 | list_for_each(h, _smock_head) 146 | { 147 | q = container_of(h, smock_queue_s, lh); 148 | sput_fail_unless(!q, q->name); 149 | } 150 | } 151 | } 152 | 153 | #define smock_push_int(q,v) smock_push(q, (void *)((intptr_t) (v))) 154 | #define smock_pull_int(q) ((intptr_t)smock_pull(q)) 155 | 156 | #define smock_push_dup(q,v,v_len) \ 157 | do { \ 158 | void *p = malloc(v_len); \ 159 | memcpy(p, v, v_len); \ 160 | smock_push(q, p); \ 161 | } while(0) 162 | 163 | #define smock_push_blob(q,v) smock_push_dup(q,&v,sizeof(v)) 164 | #define smock_push_int64(q,v) smock_push_blob(q,v) 165 | 166 | #define smock_push_bool(q,v) smock_push_int(q, (v) ? 1 : 0) 167 | #define smock_pull_bool(q) (smock_pull_int(q) ? true : false) 168 | 169 | /* Assertion-like utilities. */ 170 | #define smock_pull_int_is(q,v) \ 171 | do { \ 172 | intptr_t _v = smock_pull_int(q); \ 173 | sput_fail_unless(_v == (v), "int match " # q); \ 174 | } while(0) 175 | 176 | #define smock_pull_int64_is(q,v) \ 177 | do { \ 178 | int64_t *_v = smock_pull(q); \ 179 | sput_fail_unless(*_v == (v), "int64ptr match " # q); \ 180 | free(_v); \ 181 | } while(0) 182 | 183 | 184 | #define smock_pull_bool_is(q,v) \ 185 | do { \ 186 | bool _v = smock_pull_bool(q); \ 187 | sput_fail_unless(_v == (v), "bool match " # q); \ 188 | } while(0) 189 | 190 | #define smock_pull_string_is(q, v) \ 191 | do { \ 192 | char *_tmp = smock_pull(q); \ 193 | sput_fail_unless(_tmp && strcmp(_tmp, (v)) == 0, \ 194 | "smock string match " # q); \ 195 | } while(0) 196 | 197 | 198 | #endif /* SMOCK_H */ 199 | -------------------------------------------------------------------------------- /test/test_bitops.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2015 Cisco Systems, Inc. 3 | */ 4 | #include "hnetd.h" 5 | #include "sput.h" 6 | #include 7 | 8 | #include "bitops.h" 9 | #include 10 | 11 | void hamming(void) 12 | { 13 | uint64_t a[] = { 0x1111111111111111, 0x2222222222222222, 0xffffffffffffffff, 0x000000000000ffff, 0x0}; 14 | a[3] = cpu_to_be64(a[3]); 15 | sput_fail_unless(hamming_distance_64(a, a, 64) == 0, ""); 16 | sput_fail_unless(hamming_distance_64(a, a + 1, 64) == 32, ""); 17 | sput_fail_unless(hamming_distance_64(a, a + 2, 64) == 48, ""); 18 | sput_fail_unless(hamming_distance_64(a, a + 3, 64) == 24, ""); 19 | sput_fail_unless(hamming_distance_64(a + 2, a + 3, 64) == 48, ""); 20 | sput_fail_unless(hamming_distance_64(a + 2, a + 4, 64) == 64, ""); 21 | 22 | size_t i; 23 | for(i=0; i<=64; i++) 24 | sput_fail_unless(hamming_distance_64(a + 2, a + 4, i) == i, ""); 25 | 26 | for(i=0; i<48; i++) 27 | sput_fail_unless(hamming_distance_64(a + 3, a + 4, i) == 0, ""); 28 | for(i=48; i<=64; i++) 29 | sput_fail_unless(hamming_distance_64(a + 3, a + 4, i) == i - 48, ""); 30 | 31 | for(i=0; i<48; i++) 32 | sput_fail_unless(hamming_distance_64(a + 2, a + 3, 64+i) == 48, ""); 33 | for(i=48; i<=64; i++) 34 | sput_fail_unless(hamming_distance_64(a + 2, a + 3, 64+i) == i - 48 + 48, ""); 35 | 36 | uint8_t b[] = { 0, 1, 2, 3, 4, 5, 6, 7, 8}; 37 | uint8_t d[10]; 38 | for(i=0; i<8; i++) 39 | sput_fail_unless(hamming_minimize(b+8, b+i, d, 0, 8) == 0 && *d == b[i], ""); 40 | 41 | sput_fail_unless(hamming_minimize(b, b+0, d, 0, 8) == 0 && *d == 0, ""); 42 | sput_fail_unless(hamming_minimize(b, b+1, d, 0, 8) == 1 && *d == 0, ""); 43 | sput_fail_unless(hamming_minimize(b, b+2, d, 0, 8) == 1 && *d == 0, ""); 44 | sput_fail_unless(hamming_minimize(b, b+3, d, 0, 8) == 2 && *d == 0, ""); 45 | sput_fail_unless(hamming_minimize(b, b+4, d, 0, 8) == 1 && *d == 0, ""); 46 | sput_fail_unless(hamming_minimize(b, b+5, d, 0, 8) == 2 && *d == 0, ""); 47 | sput_fail_unless(hamming_minimize(b, b+6, d, 0, 8) == 2 && *d == 0, ""); 48 | sput_fail_unless(hamming_minimize(b, b+7, d, 0, 8) == 3 && *d == 0, ""); 49 | sput_fail_unless(hamming_minimize(b, b+8, d, 0, 8) == 1 && *d == 0, ""); 50 | 51 | int t; 52 | for(t=1; t<32; t++) { 53 | sput_fail_unless(hamming_minimize(b+1, b, d, 0, t) == 0, "Long string"); 54 | sput_fail_unless(hamming_minimize(b+1, b, d, 1, t) == 0, "Long string"); 55 | sput_fail_unless(hamming_minimize(b+1, b, d, 4, t) == 0, "Long string"); 56 | } 57 | 58 | #define _(a1,a2,a3,a4) (d[0] == a1) && (d[1] == a2) && (d[2] == a3) && (d[3] == a4) 59 | sput_fail_unless(hamming_minimize(b, b+1, d, 0, 32) == 2 && _(0, 0, 3, 4), ""); 60 | sput_fail_unless(hamming_minimize(b, b+1, d, 7, 32-7) == 2 && _(0, 0, 3, 4), ""); 61 | sput_fail_unless(hamming_minimize(b, b+1, d, 8, 32-8) == 1 && _(0, 0, 3, 4), ""); 62 | sput_fail_unless(hamming_minimize(b, b+1, d, 14, 32-14) == 1 && _(0, 0, 3, 4), ""); 63 | sput_fail_unless(hamming_minimize(b, b+1, d, 15, 32-15) == 0 && _(0, 0, 3, 4), ""); 64 | sput_fail_unless(hamming_minimize(b, b+1, d, 16, 32-16) == 1 && _(0, 0, 1, 4), ""); 65 | #undef _ 66 | } 67 | 68 | void bmemcmp_s_test() 69 | { 70 | uint8_t a[] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10}; 71 | int i, j, k; 72 | for(i=0; i<=10; i++) { 73 | for(j=0; j<=10;j++) { 74 | int r1 = bmemcmp_s(&a[i], &a[j], 0, 8); 75 | int r2 = bmemcmp_s(&a[i], &a[j], 1, 7); 76 | int r3 = bmemcmp_s(&a[i], &a[j], 2, 6); 77 | if(a[i] == a[j]) { 78 | sput_fail_unless(r1==0,""); 79 | sput_fail_unless(r2==0,""); 80 | sput_fail_unless(r3==0,""); 81 | } else if(a[i] > a[j]) { 82 | sput_fail_unless(r1>0,""); 83 | sput_fail_unless(r2>0,""); 84 | sput_fail_unless(r3>0,""); 85 | } else { 86 | sput_fail_unless(r1<0,""); 87 | sput_fail_unless(r2<0,""); 88 | sput_fail_unless(r3<0,""); 89 | } 90 | } 91 | } 92 | 93 | for(i=0; i<=10; i++) { 94 | for(j=0; j<=10;j++) { 95 | for(k=0; k<=10; k++) { 96 | int r1 = bmemcmp_s(&a[i], &a[j], 0, 8+k*2); 97 | int r2 = bmemcmp_s(&a[i], &a[j], 1, 8+k*2); 98 | int r3 = bmemcmp_s(&a[i], &a[j], 3, 8+k*2); 99 | if(i == j) { 100 | sput_fail_unless(r1==0,""); 101 | sput_fail_unless(r2==0,""); 102 | sput_fail_unless(r3==0,""); 103 | } else if(i > j) { 104 | sput_fail_unless(r1>0,""); 105 | sput_fail_unless(r2>0,""); 106 | sput_fail_unless(r3>0,""); 107 | } else { 108 | sput_fail_unless(r1<0,""); 109 | sput_fail_unless(r2<0,""); 110 | sput_fail_unless(r3<0,""); 111 | } 112 | } 113 | } 114 | } 115 | } 116 | 117 | int main(__unused int argc, __unused char **argv) 118 | { 119 | openlog("test_bitops", LOG_CONS | LOG_PERROR, LOG_DAEMON); 120 | sput_start_testing(); 121 | sput_enter_suite("bitops"); /* optional */ 122 | //sput_run_test(bmemcmp_s_test); 123 | sput_run_test(hamming); 124 | sput_leave_suite(); /* optional */ 125 | sput_finish_testing(); 126 | return sput_get_return_value(); 127 | } 128 | -------------------------------------------------------------------------------- /test/test_dncp_trust.c: -------------------------------------------------------------------------------- 1 | /* 2 | * $Id: test_dncp_trust.c $ 3 | * 4 | * Author: Markus Stenberg 5 | * 6 | * Copyright (c) 2015 cisco Systems, Inc. 7 | * 8 | * Created: Tue Jan 13 15:03:51 2015 mstenber 9 | * Last modified: Mon Jun 15 13:17:54 2015 mstenber 10 | * Edit time: 50 min 11 | * 12 | */ 13 | 14 | #include "net_sim.h" 15 | #include "dncp_trust.h" 16 | 17 | #include 18 | 19 | /************************************************************ NOP callbacks. */ 20 | 21 | int platform_rpc_register(struct platform_rpc_method *m) 22 | {return 0;} 23 | 24 | int platform_rpc_cli(const char *method, struct blob_attr *in) 25 | {return 0;} 26 | 27 | /***************************************** Actual test code (fairly minimal) */ 28 | 29 | #define TESTFILENAME "/tmp/dncp_trust.dat" 30 | 31 | void dncp_trust_base() 32 | { 33 | dncp_sha256_s ha[3]; 34 | int v[3] = { DNCP_VERDICT_NONE, 35 | DNCP_VERDICT_NEUTRAL, 36 | DNCP_VERDICT_CONFIGURED_POSITIVE }; 37 | memset(&ha[0], 42, sizeof(ha[0])); 38 | memset(&ha[1], 7, sizeof(ha[0])); 39 | memset(&ha[2], 3, sizeof(ha[0])); 40 | 41 | net_sim_s s; 42 | net_sim_init(&s); 43 | 44 | /* 3 different cases (before sync) 45 | - nonexistent hash (ha[0]) 46 | - requested hash (ha[1]) 47 | - set hash (ha[2]) */ 48 | dncp d1 = net_sim_find_dncp(&s, "x"); 49 | dncp_trust dt1 = dncp_trust_create(d1, NULL); 50 | 51 | dncp d2 = net_sim_find_dncp(&s, "y"); 52 | dncp_trust dt2 = dncp_trust_create(d2, NULL); 53 | 54 | 55 | dncp_ep l1 = net_sim_dncp_find_ep_by_name(d1, "down"); 56 | dncp_ep l2 = net_sim_dncp_find_ep_by_name(d2, "up"); 57 | net_sim_set_connected(l1, l2, true); 58 | net_sim_set_connected(l2, l1, true); 59 | 60 | dncp_trust_request_verdict(dt1, &ha[1], "bar"); 61 | dncp_trust_set(dt1, &ha[2], DNCP_VERDICT_CONFIGURED_POSITIVE, "foo"); 62 | 63 | SIM_WHILE(&s, 100000, !net_sim_is_converged(&s)); 64 | 65 | /* Verdict must be same for all hashes */ 66 | 67 | int i; 68 | for (i = 0 ; i < 3 ; i++) 69 | { 70 | int v1 = dncp_trust_get_verdict(dt1, &ha[i], NULL); 71 | int v2 = dncp_trust_get_verdict(dt2, &ha[i], NULL); 72 | sput_fail_unless(v1 == v[i], "verdict1 expected"); 73 | sput_fail_unless(v2 == v[i], "verdict2 expected"); 74 | 75 | } 76 | char buf[DNCP_T_TRUST_VERDICT_CNAME_LEN]; 77 | dncp_trust_get_verdict(dt1, &ha[2], buf); 78 | sput_fail_unless(strcmp(buf, "foo")==0, "local cname foo"); 79 | dncp_trust_get_verdict(dt2, &ha[2], buf); 80 | sput_fail_unless(strcmp(buf, "foo")==0, "remote cname foo"); 81 | dncp_trust_get_verdict(dt2, &ha[1], buf); 82 | sput_fail_unless(strcmp(buf, "bar")==0, "cname bar"); 83 | 84 | i = 0; 85 | dncp_sha256 h; 86 | dncp_trust_for_each_hash(dt1, h) 87 | i++; 88 | L_DEBUG("dt1 i=%d", i); 89 | sput_fail_unless(i == 2, "dt1 have data for ha[1]+ha[2]"); 90 | 91 | i = 0; 92 | dncp_trust_for_each_hash(dt2, h) 93 | i++; 94 | L_DEBUG("dt2 i=%d", i); 95 | sput_fail_unless(i == 2, "dt2 have data for ha[1]+ha[2]"); 96 | 97 | dncp_trust_destroy(dt1); 98 | dncp_trust_destroy(dt2); 99 | 100 | net_sim_uninit(&s); 101 | } 102 | 103 | void dncp_trust_io() 104 | { 105 | net_sim_s s; 106 | dncp_sha256_s h; 107 | 108 | memset(&h, 42, sizeof(h)); 109 | net_sim_init(&s); 110 | uloop_init(); 111 | /* Make sure the (implicit) load + save work as advertised */ 112 | unlink(TESTFILENAME); 113 | dncp d = net_sim_find_dncp(&s, "x"); 114 | sput_fail_unless(d, "dncp_create"); 115 | dncp_trust dt = dncp_trust_create(d, TESTFILENAME); 116 | sput_fail_unless(dt, "dncp_trust_create"); 117 | sput_fail_unless(dncp_trust_get_verdict(dt, &h, NULL) == DNCP_VERDICT_NONE, 118 | "verdict none"); 119 | dncp_trust_set(dt, &h, DNCP_VERDICT_CONFIGURED_POSITIVE, "foo"); 120 | dncp_trust_destroy(dt); 121 | 122 | dt = dncp_trust_create(d, TESTFILENAME); 123 | sput_fail_unless(dt, "dncp_trust_create 2"); 124 | char buf[DNCP_T_TRUST_VERDICT_CNAME_LEN]; 125 | sput_fail_unless(dncp_trust_get_verdict(dt, &h, buf) == DNCP_VERDICT_CONFIGURED_POSITIVE, 126 | "verdict none"); 127 | sput_fail_unless(strcmp(buf, "foo")==0, "cname foo"); 128 | dncp_trust_destroy(dt); 129 | 130 | net_sim_uninit(&s); 131 | } 132 | 133 | #define maybe_run_test(fun) sput_maybe_run_test(fun, do {} while(0)) 134 | 135 | int main(int argc, char **argv) 136 | { 137 | setbuf(stdout, NULL); /* so that it's in sync with stderr when redirected */ 138 | openlog("test_dncp_trust", LOG_CONS | LOG_PERROR, LOG_DAEMON); 139 | 140 | sput_start_testing(); 141 | sput_enter_suite("dncp_trust"); /* optional */ 142 | 143 | argc -= 1; 144 | argv += 1; 145 | 146 | maybe_run_test(dncp_trust_base); 147 | maybe_run_test(dncp_trust_io); 148 | 149 | sput_leave_suite(); /* optional */ 150 | sput_finish_testing(); 151 | return sput_get_return_value(); 152 | } 153 | -------------------------------------------------------------------------------- /test/test_dummy.c: -------------------------------------------------------------------------------- 1 | /* 2 | * $Id: test_dummy.c $ 3 | * 4 | * Author: Markus Stenberg 5 | * 6 | * Copyright (c) 2013-2015 cisco Systems, Inc. 7 | * 8 | * Created: Thu Nov 21 12:51:48 2013 mstenber 9 | * Last modified: Mon Jun 8 09:53:07 2015 mstenber 10 | * Edit time: 15 min 11 | * 12 | */ 13 | 14 | 15 | #ifdef L_LEVEL 16 | #undef L_LEVEL 17 | #endif /* L_LEVEL */ 18 | #define L_LEVEL 7 19 | 20 | #include "hnetd.h" 21 | #include "sput.h" 22 | #include "smock.h" 23 | 24 | #include "fake_log.h" 25 | 26 | #include 27 | 28 | int dummy_cb(int i) 29 | { 30 | int v1 = smock_pull_int("in"); 31 | int v2 = smock_pull_int("out"); 32 | printf("i %d->o %d\n", v1, v2); 33 | sput_fail_unless(i == v1, "wrong input argument"); 34 | return v2; 35 | } 36 | 37 | void sample(void) 38 | { 39 | int r; 40 | 41 | L_DEBUG("debug"); 42 | L_INFO("info"); 43 | L_NOTICE("notice"); 44 | L_WARN("warn"); 45 | L_ERR("err"); 46 | 47 | sput_fail_if(0, "0 isn't false!"); 48 | sput_fail_unless(1, "1 isn't true!"); 49 | 50 | /* Play with smock */ 51 | sput_fail_unless(smock_empty(), "smock empty"); 52 | smock_push_int("in", 1); 53 | sput_fail_unless(!smock_empty(), "smock not empty"); 54 | smock_push_int("out", 2); 55 | smock_push_int("in", 3); 56 | smock_push_int("out", 6); 57 | r = dummy_cb(1); 58 | sput_fail_unless(r == 2, "dummy_cb broken"); 59 | r = dummy_cb(3); 60 | sput_fail_unless(r == 6, "dummy_cb broken"); 61 | /* In the end, we should be again gone. */ 62 | sput_fail_unless(smock_empty(), "smock empty"); 63 | } 64 | 65 | int main(__unused int argc, __unused char **argv) 66 | { 67 | openlog("test_dummy", LOG_CONS | LOG_PERROR, LOG_DAEMON); 68 | sput_start_testing(); 69 | sput_enter_suite("dummysuite"); /* optional */ 70 | sput_run_test(sample); 71 | sput_leave_suite(); /* optional */ 72 | sput_finish_testing(); 73 | return sput_get_return_value(); 74 | } 75 | -------------------------------------------------------------------------------- /test/test_exeq.c: -------------------------------------------------------------------------------- 1 | #define NO_REDEFINE_ULOOP_TIMEOUT 2 | 3 | #include "exeq.c" 4 | 5 | #include 6 | #include 7 | #include 8 | 9 | struct uloop_timeout to, end; 10 | struct exeq exeq[2]; 11 | 12 | int log_level = 9; 13 | void (*hnetd_log)(int priority, const char *format, ...) = syslog; 14 | 15 | void _end_to(__unused struct uloop_timeout *t) 16 | { 17 | exit(0); 18 | } 19 | 20 | void _t2(__unused struct uloop_timeout *t) 21 | { 22 | char *argv4[] = { "/bin/echo", "4", NULL }; 23 | exeq_add(&exeq[1], argv4); 24 | char *argv5[] = { "/bin/echo", "5", NULL }; 25 | exeq_add(&exeq[1], argv5); 26 | char *argv6[] = { "/bin/echo", "6", NULL }; 27 | exeq_add(&exeq[0], argv6); 28 | } 29 | 30 | void _t1(__unused struct uloop_timeout *t) 31 | { 32 | exeq_init(&exeq[0]); 33 | exeq_init(&exeq[1]); 34 | char *argv1[] = { "/bin/echo", "1", NULL }; 35 | exeq_add(&exeq[0], argv1); 36 | char *argv2[] = { "/bin/echo", "2", NULL }; 37 | exeq_add(&exeq[0], argv2); 38 | char *argv3[] = { "/bin/echo", "3", NULL }; 39 | exeq_add(&exeq[1], argv3); 40 | to.cb = _t2; 41 | uloop_timeout_set(&to, 200); 42 | } 43 | 44 | int main() 45 | { 46 | openlog("hnetd", LOG_PERROR | LOG_PID, LOG_DAEMON); 47 | uloop_init(); 48 | to.pending = 0; 49 | to.cb = _t1; 50 | uloop_timeout_set(&to, 0); 51 | end.pending = 0; 52 | end.cb = _end_to; 53 | uloop_timeout_set(&end, 1000); 54 | uloop_run(); 55 | return 0; 56 | } 57 | -------------------------------------------------------------------------------- /test/test_hncp_io.c: -------------------------------------------------------------------------------- 1 | /* 2 | * $Id: test_hncp_io.c $ 3 | * 4 | * Author: Markus Stenberg 5 | * 6 | * Copyright (c) 2014-2015 cisco Systems, Inc. 7 | * 8 | * Created: Thu Oct 16 09:56:00 2014 mstenber 9 | * Last modified: Mon Jun 8 09:53:40 2015 mstenber 10 | * Edit time: 64 min 11 | * 12 | */ 13 | 14 | /* This module tests that the hncp_io module's (small) external 15 | * interface seems to work correctly, _and_ that we can use it to send 16 | * packets back and forth. */ 17 | 18 | #include "dncp_i.h" 19 | 20 | #ifdef __APPLE__ 21 | #define LOOPBACK_NAME "lo0" 22 | #else 23 | #define LOOPBACK_NAME "lo" 24 | #endif /* __APPLE__ */ 25 | 26 | 27 | dncp_ep_s static_ep = { .ifname = LOOPBACK_NAME, 28 | .accept_insecure_nonlocal_traffic = true }; 29 | 30 | #define dncp_find_ep_by_name(o, n) &static_ep 31 | #include "hncp_io.c" 32 | #include "sput.h" 33 | #include "smock.h" 34 | 35 | #include "fake_log.h" 36 | 37 | /* Lots of stubs here, rather not put __unused all over the place. */ 38 | #pragma GCC diagnostic ignored "-Wunused-parameter" 39 | 40 | void dncp_ext_ep_ready(dncp_ep ep, bool ready) 41 | { 42 | smock_pull_string_is("dncp_ready", ep->ifname); 43 | smock_pull_bool_is("dncp_ready_value", ready); 44 | } 45 | 46 | void dncp_ext_timeout(dncp o) 47 | { 48 | smock_pull("dncp_run"); 49 | } 50 | 51 | int pending_packets = 0; 52 | 53 | void dncp_ext_readable(dncp o) 54 | { 55 | char buf[1024]; 56 | size_t len = sizeof(buf); 57 | int r; 58 | struct sockaddr_in6 *src, *dst; 59 | dncp_ep ep; 60 | int flags; 61 | 62 | r = o->ext->cb.recv(o->ext, &ep, &src, &dst, &flags, buf, len); 63 | smock_pull_int_is("dncp_poll_io_recvfrom", r); 64 | if (r >= 0) 65 | { 66 | void *b = smock_pull("dncp_poll_io_recvfrom_buf"); 67 | char *ifn = smock_pull("dncp_poll_io_recvfrom_ifname"); 68 | struct sockaddr_in6 *esrc = smock_pull("dncp_poll_io_recvfrom_src"); 69 | struct sockaddr_in6 *edst = smock_pull("dncp_poll_io_recvfrom_dst"); 70 | 71 | sput_fail_unless(memcmp(b, buf, r)==0, "buf mismatch"); 72 | sput_fail_unless(strcmp(ifn, ep->ifname) == 0, "ifname mismatch"); 73 | sput_fail_unless(memcmp(src, esrc, sizeof(*src))==0, "src mismatch"); 74 | sput_fail_unless(memcmp(&dst->sin6_addr, 75 | &edst->sin6_addr, sizeof(dst->sin6_addr))==0, 76 | "dst mismatch"); 77 | if (!--pending_packets) 78 | uloop_end(); 79 | } 80 | } 81 | 82 | static void dncp_io_basic_2() 83 | { 84 | hncp_s h1, h2; 85 | dncp_s d1, d2; 86 | bool r; 87 | struct in6_addr a; 88 | char *msg = "foo"; 89 | char *ifname = LOOPBACK_NAME; 90 | 91 | (void)uloop_init(); 92 | memset(&h1, 0, sizeof(h1)); 93 | memset(&h2, 0, sizeof(h2)); 94 | memset(&d1, 0, sizeof(d1)); 95 | memset(&d2, 0, sizeof(d2)); 96 | h1.udp_port = 62000; 97 | h2.udp_port = 62001; 98 | h1.dncp = &d1; 99 | h2.dncp = &d2; 100 | d1.ext = &h1.ext; 101 | d2.ext = &h2.ext; 102 | r = hncp_io_init(&h1); 103 | sput_fail_unless(r, "dncp_io_init h1"); 104 | r = hncp_io_init(&h2); 105 | sput_fail_unless(r, "dncp_io_init h2"); 106 | 107 | /* Send a packet to ourselves */ 108 | (void)inet_pton(AF_INET6, "::1", &a); 109 | struct sockaddr_in6 src = { 110 | .sin6_family = AF_INET6, 111 | .sin6_port = htons(h1.udp_port), 112 | .sin6_addr = a 113 | #ifdef __APPLE__ 114 | , .sin6_len = sizeof(struct sockaddr_in6) 115 | #endif /* __APPLE__ */ 116 | }; 117 | struct sockaddr_in6 dst = { 118 | .sin6_family = AF_INET6, 119 | .sin6_port = htons(h2.udp_port), 120 | .sin6_addr = a 121 | #ifdef __APPLE__ 122 | , .sin6_len = sizeof(struct sockaddr_in6) 123 | #endif /* __APPLE__ */ 124 | }; 125 | smock_push_int("dncp_poll_io_recvfrom", 3); 126 | smock_push_int("dncp_poll_io_recvfrom_src", &src); 127 | smock_push_int("dncp_poll_io_recvfrom_dst", &dst); 128 | smock_push_int("dncp_poll_io_recvfrom_buf", msg); 129 | smock_push_int("dncp_poll_io_recvfrom_ifname", ifname); 130 | h1.ext.cb.send(&h1.ext, dncp_find_ep_by_name(h1.dncp, "lo"), 131 | NULL, &dst, msg, strlen(msg)); 132 | pending_packets++; 133 | 134 | uloop_run(); 135 | 136 | hncp_io_uninit(&h1); 137 | hncp_io_uninit(&h2); 138 | } 139 | 140 | int main(int argc, char **argv) 141 | { 142 | setbuf(stdout, NULL); /* so that it's in sync with stderr when redirected */ 143 | openlog("test_hncp_io", LOG_CONS | LOG_PERROR, LOG_DAEMON); 144 | sput_start_testing(); 145 | sput_enter_suite("hncp_io"); /* optional */ 146 | argc -= 1; 147 | argv += 1; 148 | 149 | sput_maybe_run_test(dncp_io_basic_2, do {} while(0)); 150 | sput_leave_suite(); /* optional */ 151 | sput_finish_testing(); 152 | return sput_get_return_value(); 153 | } 154 | -------------------------------------------------------------------------------- /test/test_hncp_multicast.c: -------------------------------------------------------------------------------- 1 | /* 2 | * $Id: test_hncp_multicast.c $ 3 | * 4 | * Author: Markus Stenberg 5 | * 6 | * Copyright (c) 2015 cisco Systems, Inc. 7 | * 8 | * Created: Mon Feb 23 21:40:08 2015 mstenber 9 | * Last modified: Thu Jun 11 09:54:57 2015 mstenber 10 | * Edit time: 21 min 11 | * 12 | */ 13 | 14 | #ifdef L_LEVEL 15 | #undef L_LEVEL 16 | #endif /* L_LEVEL */ 17 | #define L_LEVEL 7 18 | 19 | #define DISABLE_HNCP_PA 20 | #define DISABLE_HNCP_SD 21 | #include "net_sim.h" 22 | #include "sput.h" 23 | #include "smock.h" 24 | 25 | #include "hncp_multicast.h" 26 | 27 | void test_hncp_multicast_base(bool aa_enabled) 28 | { 29 | /* Create two nodes. Eventually, one of them has to be RP, and the 30 | * one with (fake) DP must publish it's address. */ 31 | net_sim_s s; 32 | dncp n1, n2; 33 | dncp_ep l1, l2; 34 | 35 | net_sim_init(&s); 36 | s.disable_link_auto_address = !aa_enabled; 37 | n1 = net_sim_find_dncp(&s, "n1"); 38 | l1 = net_sim_dncp_find_ep_by_name(n1, "eth0"); 39 | /* Fake external connection */ 40 | dncp_add_tlv(n1, HNCP_T_EXTERNAL_CONNECTION, 0, 0, 0); 41 | 42 | n2 = net_sim_find_dncp(&s, "n2"); 43 | l2 = net_sim_dncp_find_ep_by_name(n2, "eth0"); 44 | 45 | net_sim_set_connected(l1, l2, true); 46 | net_sim_set_connected(l2, l1, true); 47 | 48 | SIM_WHILE(&s, 100, net_sim_is_busy(&s) || !net_sim_is_converged(&s)); 49 | 50 | /* Make sure there is exactly 1 RPA, and 1 BP */ 51 | int types[] = { HNCP_T_PIM_RPA_CANDIDATE, 52 | HNCP_T_PIM_BORDER_PROXY, 53 | 0 54 | }; 55 | for (int i = 0 ; types[i] ; i++) 56 | { 57 | int c = net_sim_dncp_tlv_type_count(n1, types[i]); 58 | L_DEBUG("tlv #%d: %d", types[i], c); 59 | sput_fail_unless(c == (aa_enabled ? 1 : 0), "1 of tlv"); 60 | } 61 | net_sim_uninit(&s); 62 | } 63 | 64 | void test_hncp_multicast() 65 | { 66 | test_hncp_multicast_base(true); 67 | } 68 | 69 | void test_hncp_multicast_noaddr() 70 | { 71 | test_hncp_multicast_base(false); 72 | } 73 | 74 | int main(__unused int argc, __unused char **argv) 75 | { 76 | setbuf(stdout, NULL); /* so that it's in sync with stderr when redirected */ 77 | openlog(argv[0], LOG_CONS | LOG_PERROR, LOG_DAEMON); 78 | sput_start_testing(); 79 | sput_enter_suite(argv[0]); /* optional */ 80 | sput_run_test(test_hncp_multicast); 81 | sput_run_test(test_hncp_multicast_noaddr); 82 | sput_leave_suite(); /* optional */ 83 | sput_finish_testing(); 84 | return sput_get_return_value(); 85 | 86 | } 87 | -------------------------------------------------------------------------------- /test/test_iface.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2015 Cisco Systems, Inc. 3 | */ 4 | #include "hnetd.h" 5 | #include "sput.h" 6 | #include "smock.h" 7 | 8 | #include 9 | #include 10 | #include 11 | 12 | #include "fake_uloop.h" 13 | #include "prefix_utils.h" 14 | 15 | #include "hncp_sd.h" 16 | #define hncp_get_dncp(o) NULL 17 | 18 | #include "iface.c" 19 | 20 | #include "fake_log.h" 21 | 22 | void hncp_pa_iface_user_register(__unused hncp_pa hp, __unused struct hncp_pa_iface_user *user) {} 23 | struct list_head *__hpa_get_dps(__unused hncp_pa hpa) {return NULL;} 24 | void platform_set_dhcp(__unused struct iface *c, __unused enum hncp_link_elected elected) {} 25 | int platform_init(__unused hncp hncp, __unused hncp_pa pa, __unused const char *pd_socket) { return 0; } 26 | void platform_set_address(__unused struct iface *c, __unused struct iface_addr *addr, __unused bool enable) {} 27 | void platform_iface_free(__unused struct iface *c) {} 28 | void platform_set_internal(__unused struct iface *c, __unused bool internal) {} 29 | void platform_filter_prefix(__unused struct iface *c, __unused const struct prefix *p, __unused bool enable) {} 30 | void platform_iface_new(__unused struct iface *c, __unused const char *handle) { c->platform = (void*)1; } 31 | void platform_set_dhcpv6_send(__unused struct iface *c, __unused const void *dhcpv6_data, __unused size_t len, 32 | __unused const void *dhcp_data, __unused size_t len4) {} 33 | void platform_set_prefix_route(__unused const struct prefix *p, __unused bool enable) {} 34 | void platform_restart_dhcpv4(__unused struct iface *c) {} 35 | void platform_set_snat(__unused struct iface *c, __unused const struct prefix *p) {} 36 | void hncp_sd_dump_link_fqdn(__unused hncp_sd sd, __unused dncp_ep l, __unused const char *ifname, __unused char *buf, __unused size_t buf_len) {} 37 | dncp_ep dncp_find_ep_by_name(__unused dncp h, __unused const char *ifname) { return NULL; } 38 | void hncp_link_register(__unused struct hncp_link *c, __unused struct hncp_link_user *u) {} 39 | 40 | void intiface_mock(__unused struct iface_user *u, __unused const char *ifname, bool enabled) 41 | { 42 | smock_push_bool(ifname, enabled); 43 | uloop_end(); 44 | } 45 | 46 | void extdata_mock(__unused struct iface_user *u, __unused const char *ifname, __unused const void *dhcpv6_data, size_t dhcpv6_len) 47 | { 48 | if (dhcpv6_len) 49 | smock_push_int("extdata", dhcpv6_len); 50 | } 51 | 52 | void prefix_mock(__unused struct iface_user *u, __unused const char *ifname, 53 | __unused const struct prefix *prefix, __unused const struct prefix *excluded, 54 | hnetd_time_t valid_until, __unused hnetd_time_t preferred_until, 55 | __unused const void *dhcpv6_data, __unused size_t dhcpv6_len) 56 | { 57 | if (valid_until > hnetd_time()) { 58 | smock_push("prefix_prefix", (void*)prefix); 59 | smock_push_int64("prefix_valid", valid_until); 60 | smock_push_int64("prefix_preferred", preferred_until); 61 | smock_push("dhcpv6_data", (void*)dhcpv6_data); 62 | smock_push_int("dhcpv6_len", dhcpv6_len); 63 | } else { 64 | smock_push_bool("prefix_remove", true); 65 | } 66 | } 67 | 68 | struct iface_user user_mock = { 69 | .cb_intiface = intiface_mock, 70 | .cb_extdata = extdata_mock, 71 | .cb_prefix = prefix_mock 72 | }; 73 | 74 | 75 | void iface_test_new_unmanaged(void) 76 | { 77 | iface_register_user(&user_mock); 78 | 79 | struct iface *iface = iface_create("test0", NULL, 0); 80 | sput_fail_unless(!!iface, "alloc unmanaged"); 81 | 82 | struct iface *iface2 = iface_get("test0"); 83 | sput_fail_unless(iface == iface2, "get after create"); 84 | 85 | struct iface *iface3 = iface_create("test0", NULL, 0); 86 | sput_fail_unless(iface == iface3, "create after create"); 87 | 88 | iface_remove(iface); 89 | sput_fail_unless(!iface_get("test0"), "delete"); 90 | 91 | smock_is_empty(); 92 | iface_unregister_user(&user_mock); 93 | } 94 | 95 | 96 | void iface_test_new_managed(void) 97 | { 98 | struct in_addr v4source = {INADDR_LOOPBACK}; 99 | iface_register_user(&user_mock); 100 | struct prefix p = {IN6ADDR_LOOPBACK_INIT, 0}; 101 | char test[] = "test"; 102 | 103 | struct iface *iface00 = iface_create("test00", "test00", 0); 104 | iface_update_ipv4_uplink(iface00); 105 | iface_set_ipv4_uplink(iface00, &v4source, 24); 106 | iface_commit_ipv4_uplink(iface00); 107 | /* smock_pull_bool_is("test00", false); */ 108 | /* this was removed in the commit 109 | a5293745c235a057b6a477ffbd817937eaa9bc12 at 5/2015(!); 110 | */ 111 | 112 | struct iface *iface = iface_create("test0", "test0", 0); 113 | iface->carrier = true; 114 | iface_discover_border(iface); 115 | 116 | sput_fail_unless(!!iface, "alloc managed"); 117 | 118 | struct iface *iface2 = iface_get("test0"); 119 | sput_fail_unless(iface == iface2, "get after create"); 120 | 121 | struct iface *iface3 = iface_create("test0", "test0", 0); 122 | sput_fail_unless(iface == iface3, "create after create"); 123 | 124 | /* smock_pull_bool_is("test0", false); */ 125 | /* this was removed in the commit 126 | a5293745c235a057b6a477ffbd817937eaa9bc12 at 5/2015(!); 127 | */ 128 | 129 | uloop_cancelled = false; 130 | uloop_run(); 131 | smock_pull_bool_is("test0", true); 132 | 133 | iface_update_ipv4_uplink(iface); 134 | iface_set_ipv4_uplink(iface, &v4source, 24); 135 | iface_commit_ipv4_uplink(iface); 136 | smock_pull_bool_is("test0", false); 137 | 138 | iface_update_ipv4_uplink(iface); 139 | iface_commit_ipv4_uplink(iface); 140 | uloop_cancelled = false; 141 | uloop_run(); 142 | smock_pull_bool_is("test0", true); 143 | 144 | iface_update_ipv6_uplink(iface); 145 | iface_add_delegated(iface, &p, NULL, HNETD_TIME_MAX, 0, test, sizeof(test)); 146 | iface_commit_ipv6_uplink(iface); 147 | 148 | smock_pull_bool_is("test0", false); 149 | sput_fail_unless(!prefix_cmp(&p, (struct prefix *)smock_pull("prefix_prefix")), "prefix address"); 150 | smock_pull_int64_is("prefix_valid", HNETD_TIME_MAX); 151 | smock_pull_int64_is("prefix_preferred", 0); 152 | sput_fail_unless(!strcmp(smock_pull("dhcpv6_data"), "test"), "dhcpv6_data"); 153 | smock_pull_int_is("dhcpv6_len", sizeof(test)); 154 | 155 | iface_update_ipv4_uplink(iface); 156 | iface_set_ipv4_uplink(iface, &v4source, 24); 157 | iface_commit_ipv4_uplink(iface); 158 | 159 | iface_update_ipv6_uplink(iface); 160 | iface_commit_ipv6_uplink(iface); 161 | smock_pull_bool_is("prefix_remove", true); 162 | 163 | iface_update_ipv4_uplink(iface); 164 | iface_commit_ipv4_uplink(iface); 165 | 166 | uloop_cancelled = false; 167 | uloop_run(); 168 | smock_pull_bool_is("test0", true); 169 | 170 | iface_remove(iface); 171 | sput_fail_unless(!iface_get("test0"), "delete"); 172 | smock_pull_bool_is("test0", false); 173 | smock_is_empty(); 174 | iface_unregister_user(&user_mock); 175 | } 176 | 177 | 178 | int main() 179 | { 180 | sput_start_testing(); 181 | sput_enter_suite("iface"); 182 | sput_run_test(iface_test_new_unmanaged); 183 | sput_run_test(iface_test_new_managed); 184 | sput_leave_suite(); 185 | sput_finish_testing(); 186 | return sput_get_return_value(); 187 | } 188 | -------------------------------------------------------------------------------- /test/test_pa_filters.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2015 Cisco Systems, Inc. 3 | */ 4 | #include "sput.h" 5 | 6 | #include "pa_filters.c" 7 | 8 | struct filter_test { 9 | struct pa_filter filter; 10 | int ret; 11 | }; 12 | 13 | int filter_test(__unused struct pa_rule *rule, __unused struct pa_ldp *ldp, struct pa_filter *filter) 14 | { 15 | struct filter_test *ft = container_of(filter, struct filter_test, filter); 16 | return ft->ret; 17 | } 18 | 19 | #define filter_check(f, rule, ldp, value) \ 20 | sput_fail_unless((f)->accept(rule, ldp, f) == value, "Correct filter value") 21 | 22 | 23 | void pa_filters_type() 24 | { 25 | struct pa_filter_type t; 26 | struct pa_link l; 27 | struct pa_dp d; 28 | struct pa_ldp ldp; 29 | ldp.link = &l; 30 | ldp.dp = &d; 31 | 32 | pa_filter_type_dp_init(&t, 1); 33 | l.type = 1; 34 | d.type = 1; 35 | filter_check(&t.filter, NULL, &ldp, 1); 36 | l.type = 0; 37 | d.type = 1; 38 | filter_check(&t.filter, NULL, &ldp, 1); 39 | l.type = 0; 40 | d.type = 0; 41 | filter_check(&t.filter, NULL, &ldp, 0); 42 | l.type = 1; 43 | d.type = 0; 44 | filter_check(&t.filter, NULL, &ldp, 0); 45 | 46 | pa_filter_type_link_init(&t, 1); 47 | l.type = 1; 48 | d.type = 1; 49 | filter_check(&t.filter, NULL, &ldp, 1); 50 | l.type = 0; 51 | d.type = 1; 52 | filter_check(&t.filter, NULL, &ldp, 0); 53 | l.type = 0; 54 | d.type = 0; 55 | filter_check(&t.filter, NULL, &ldp, 0); 56 | l.type = 1; 57 | d.type = 0; 58 | filter_check(&t.filter, NULL, &ldp, 1); 59 | } 60 | 61 | void pa_filters_ldp() 62 | { 63 | struct pa_filter_ldp f; 64 | struct pa_link l, l2; 65 | struct pa_dp d, d2; 66 | struct pa_ldp ldp, ldp2; 67 | ldp.link = &l; 68 | ldp.dp = &d; 69 | ldp2.link = &l2; 70 | ldp2.dp = &d2; 71 | pa_filter_ldp_init(&f, NULL, NULL); 72 | filter_check(&f.filter, NULL, &ldp, 1); 73 | filter_check(&f.filter, NULL, &ldp2, 1); 74 | f.dp = &d; 75 | filter_check(&f.filter, NULL, &ldp, 1); 76 | filter_check(&f.filter, NULL, &ldp2, 0); 77 | f.link = &l; 78 | filter_check(&f.filter, NULL, &ldp, 1); 79 | filter_check(&f.filter, NULL, &ldp2, 0); 80 | f.dp = NULL; 81 | filter_check(&f.filter, NULL, &ldp, 1); 82 | filter_check(&f.filter, NULL, &ldp2, 0); 83 | } 84 | 85 | void pa_filters_logic() 86 | { 87 | struct filter_test fts[2] = {{.filter = {.accept = filter_test}}, {.filter = {.accept = filter_test}}}; 88 | struct pa_filters fs; 89 | 90 | /* OR */ 91 | pa_filters_or_init(&fs, false); 92 | filter_check(&fs.filter, NULL, NULL, 0); 93 | fs.negate = 1; 94 | filter_check(&fs.filter, NULL, NULL, 1); 95 | 96 | pa_filters_add(&fs, &fts[0].filter); 97 | pa_filters_add(&fs, &fts[1].filter); 98 | 99 | fs.negate = 0; 100 | fts[0].ret = 0; 101 | fts[1].ret = 0; 102 | filter_check(&fs.filter, NULL, NULL, 0); 103 | fts[0].ret = 1; 104 | fts[1].ret = 0; 105 | filter_check(&fs.filter, NULL, NULL, 1); 106 | fts[0].ret = 0; 107 | fts[1].ret = 1; 108 | filter_check(&fs.filter, NULL, NULL, 1); 109 | fts[0].ret = 1; 110 | fts[1].ret = 1; 111 | filter_check(&fs.filter, NULL, NULL, 1); 112 | 113 | fs.negate = 1; 114 | fts[0].ret = 0; 115 | fts[1].ret = 0; 116 | filter_check(&fs.filter, NULL, NULL, 1); 117 | fts[0].ret = 1; 118 | fts[1].ret = 0; 119 | filter_check(&fs.filter, NULL, NULL, 0); 120 | fts[0].ret = 0; 121 | fts[1].ret = 1; 122 | filter_check(&fs.filter, NULL, NULL, 0); 123 | fts[0].ret = 1; 124 | fts[1].ret = 1; 125 | filter_check(&fs.filter, NULL, NULL, 0); 126 | 127 | /* AND */ 128 | pa_filters_and_init(&fs, false); 129 | filter_check(&fs.filter, NULL, NULL, 1); 130 | fs.negate = 1; 131 | filter_check(&fs.filter, NULL, NULL, 0); 132 | 133 | pa_filters_add(&fs, &fts[0].filter); 134 | pa_filters_add(&fs, &fts[1].filter); 135 | 136 | fs.negate = 0; 137 | fts[0].ret = 0; 138 | fts[1].ret = 0; 139 | filter_check(&fs.filter, NULL, NULL, 0); 140 | fts[0].ret = 1; 141 | fts[1].ret = 0; 142 | filter_check(&fs.filter, NULL, NULL, 0); 143 | fts[0].ret = 0; 144 | fts[1].ret = 1; 145 | filter_check(&fs.filter, NULL, NULL, 0); 146 | fts[0].ret = 1; 147 | fts[1].ret = 1; 148 | filter_check(&fs.filter, NULL, NULL, 1); 149 | 150 | fs.negate = 1; 151 | fts[0].ret = 0; 152 | fts[1].ret = 0; 153 | filter_check(&fs.filter, NULL, NULL, 1); 154 | fts[0].ret = 1; 155 | fts[1].ret = 0; 156 | filter_check(&fs.filter, NULL, NULL, 1); 157 | fts[0].ret = 0; 158 | fts[1].ret = 1; 159 | filter_check(&fs.filter, NULL, NULL, 1); 160 | fts[0].ret = 1; 161 | fts[1].ret = 1; 162 | filter_check(&fs.filter, NULL, NULL, 0); 163 | } 164 | 165 | int main() { 166 | sput_start_testing(); 167 | sput_enter_suite("Prefix Assignment Filters tests"); /* optional */ 168 | sput_run_test(pa_filters_logic); 169 | sput_run_test(pa_filters_ldp); 170 | sput_run_test(pa_filters_type); 171 | sput_leave_suite(); /* optional */ 172 | sput_finish_testing(); 173 | return sput_get_return_value(); 174 | } 175 | -------------------------------------------------------------------------------- /test/test_tlv.c: -------------------------------------------------------------------------------- 1 | /* 2 | * $Id: test_tlv.c $ 3 | * 4 | * Author: Markus Stenberg 5 | * 6 | * Copyright (c) 2013-2015 cisco Systems, Inc. 7 | * 8 | * Created: Wed Dec 4 11:53:11 2013 mstenber 9 | * Last modified: Mon Jun 8 09:54:34 2015 mstenber 10 | * Edit time: 46 min 11 | * 12 | */ 13 | 14 | #include "hnetd.h" 15 | #include "tlv.h" 16 | #include "sput.h" 17 | #include "fake_log.h" 18 | 19 | /* Ensure that tlv stuff we add works. Note that some of the failures 20 | * are obvious only on valgrind (e.g. wrong accesses in tlv_iter). */ 21 | 22 | /************************************************************* Test cases */ 23 | 24 | 25 | void tlv_iter(void) 26 | { 27 | struct tlv_buf tb; 28 | struct tlv_attr *a, *a1, *a2, *a3; 29 | int c; 30 | void *tmp; 31 | 32 | /* Initialize test structure. */ 33 | memset(&tb, 0, sizeof(tb)); 34 | tlv_buf_init(&tb, 0); 35 | a1 = tlv_new(&tb, 1, 0); 36 | a2 = tlv_new(&tb, 2, 1); 37 | a3 = tlv_new(&tb, 3, 4); 38 | sput_fail_unless(a1 && a2 && a3, "a1-a3 create"); 39 | 40 | /* Make sure iteration is sane. */ 41 | c = 0; 42 | tlv_for_each_attr(a, tb.head) 43 | c++; 44 | sput_fail_unless(c == 3, "right iter result 1"); 45 | 46 | /* remove 3 bytes -> a3 header complete but not body. */ 47 | tlv_init(tb.head, 0, tlv_raw_len(tb.head) - 3); 48 | c = 0; 49 | tlv_for_each_attr(a, tb.head) 50 | c++; 51 | sput_fail_unless(c == 2, "right iter result 2"); 52 | 53 | /* remove 2 bytes -> a3 header not complete (no body). */ 54 | tlv_init(tb.head, 0, tlv_raw_len(tb.head) - 2); 55 | c = 0; 56 | tmp = malloc(tlv_raw_len(tb.head)); 57 | memcpy(tmp, tb.head, tlv_raw_len(tb.head)); 58 | tlv_for_each_attr(a, tmp) 59 | c++; 60 | sput_fail_unless(c == 2, "right iter result 3"); 61 | free(tmp); 62 | 63 | /* Free structures. */ 64 | tlv_buf_free(&tb); 65 | } 66 | 67 | #define MAX_TLVS 10 68 | 69 | #define TLV_NEXT() \ 70 | do { \ 71 | if (a) \ 72 | ptr += tlv_pad_len(a); \ 73 | sput_fail_unless(first_free < MAX_TLVS, "enough space for tlvs"); \ 74 | a = tlvs[first_free++] = ptr; \ 75 | } while(0) 76 | 77 | void tlv_cmp(void) 78 | { 79 | /* Raw memory blob in which we have our fake TLVs. */ 80 | unsigned char buf[1000]; 81 | void *ptr = buf; 82 | struct tlv_attr *tlvs[MAX_TLVS], *a = NULL; 83 | int i, j, first_free = 0; 84 | 85 | memset(buf, 0, sizeof(buf)); 86 | 87 | /* We _know_ the order. So we insert things here in the order which 88 | * the tlv_attr_cmp should sort them. */ 89 | 90 | /* TLV w/o content - before one with */ 91 | TLV_NEXT(); 92 | tlv_init(a, 24, 4); 93 | 94 | /* TLV with _one_ content > 0s */ 95 | TLV_NEXT(); 96 | tlv_init(a, 24, 5); 97 | *((char *)tlv_data(a)) = 'x'; 98 | 99 | /* TLV with content of 0s */ 100 | TLV_NEXT(); 101 | tlv_init(a, 24, 8); 102 | 103 | /* TLV with content > 0s */ 104 | TLV_NEXT(); 105 | tlv_init(a, 24, 8); 106 | *((char *)tlv_data(a)) = 'x'; 107 | 108 | /* ID with greater ID */ 109 | TLV_NEXT(); 110 | tlv_init(a, 25, 4); 111 | 112 | /* ID with 16 bit ID */ 113 | TLV_NEXT(); 114 | tlv_init(a, 0x4242, 4); 115 | 116 | for (i = 0 ; i < first_free ; i++) 117 | for (j = 0 ; j < first_free ; j++) 118 | { 119 | int r = tlv_attr_cmp(tlvs[i], tlvs[j]); 120 | bool eq = tlv_attr_equal(tlvs[i], tlvs[j]); 121 | 122 | L_NOTICE("comparing %s, %s", 123 | TLV_REPR(tlvs[i]), TLV_REPR(tlvs[j])); 124 | sput_fail_unless(!eq == !(i == j), 125 | "tlv_attr_equal on board"); 126 | if (i == j) 127 | sput_fail_unless(r == 0, "not matching own"); 128 | else if (i < j) 129 | sput_fail_unless(r < 0, "lesser"); 130 | else 131 | sput_fail_unless(r > 0, "greater"); 132 | } 133 | } 134 | 135 | void tlv_nest() 136 | { 137 | struct tlv_buf tb; 138 | void *cookie; 139 | int c, d; 140 | struct tlv_attr *a, *a2; 141 | int cs = 0; 142 | int ds = 0; 143 | 144 | memset(&tb, 0, sizeof(tb)); 145 | /* Produce test data - one 'container' TLV, with fixed 146 | * TLV_ATTR_ALIGN sized header, and then two sub-TLVs. */ 147 | tlv_buf_init(&tb, 0); 148 | cookie = tlv_nest_start(&tb, 33, TLV_ATTR_ALIGN * 2); 149 | memset(tlv_data(tb.head), 42, TLV_ATTR_ALIGN * 2); 150 | tlv_new(&tb, 34, 0); 151 | a = tlv_new(&tb, 35, 1); 152 | *((unsigned char*)tlv_data(a)) = 0x42; 153 | tlv_nest_end(&tb, cookie); 154 | cookie = tlv_nest_start(&tb, 36, TLV_ATTR_ALIGN); 155 | memset(tlv_data(tb.head), 66, TLV_ATTR_ALIGN); 156 | tlv_new(&tb, 37, 0); 157 | tlv_nest_end(&tb, cookie); 158 | 159 | /* Make sure what we produced looks sane. */ 160 | c = 0; 161 | tlv_for_each_attr(a, tb.head) 162 | c++; 163 | L_DEBUG("# of root attrs:%d", c); 164 | sput_fail_unless(c == 2, "should be just 2 root attr"); 165 | 166 | c = 0; 167 | d = 0; 168 | tlv_for_each_attr(a, tb.head) 169 | { 170 | cs += tlv_id(a); 171 | void *base = tlv_data(a); 172 | base += (2 - c) * TLV_ATTR_ALIGN; 173 | void *end = tlv_data(a) + tlv_len(a); 174 | c++; 175 | tlv_for_each_in_buf(a2, base, end-base) 176 | { 177 | ds += tlv_id(a2); 178 | d++; 179 | } 180 | } 181 | sput_fail_unless(cs == 33 + 36, "cs correct"); 182 | sput_fail_unless(ds == 34 + 35 + 37, "ds correct"); 183 | sput_fail_unless(d == 3, "should be 3 nested attrs"); 184 | 185 | L_DEBUG("nested tlv:%s", TLV_REPR(tb.head)); 186 | sput_fail_unless(tlv_len(tb.head) == 187 | 4 * TLV_ATTR_ALIGN + 188 | 5 * sizeof(struct tlv_attr) , "right nested whole size"); 189 | 190 | } 191 | 192 | 193 | void test_tlv_sort() 194 | { 195 | struct tlv_buf tb; 196 | struct tlv_attr *a; 197 | 198 | memset(&tb, 0, sizeof(tb)); 199 | tlv_buf_init(&tb, 0); 200 | tlv_new(&tb, 2, 0); 201 | tlv_new(&tb, 3, 0); 202 | tlv_new(&tb, 1, 0); 203 | tlv_new(&tb, 42, 0); 204 | 205 | /* Sort the TLVs */ 206 | tlv_sort(tlv_data(tb.head), tlv_len(tb.head)); 207 | 208 | /* Make sure they come out in ascending order. */ 209 | int last = -1; 210 | int c = 0; 211 | tlv_for_each_attr(a, tb.head) 212 | { 213 | int nid = tlv_id(a); 214 | L_DEBUG("last:%d id:%d", last, nid); 215 | sput_fail_unless(last < nid, "last < id"); 216 | last = nid; 217 | c++; 218 | } 219 | sput_fail_unless(c == 4, "should be 4 attrs"); 220 | } 221 | 222 | int main(__unused int argc, __unused char **argv) 223 | { 224 | setbuf(stdout, NULL); /* so that it's in sync with stderr when redirected */ 225 | openlog("test_tlv", LOG_CONS | LOG_PERROR, LOG_DAEMON); 226 | sput_start_testing(); 227 | sput_enter_suite("tlv"); /* optional */ 228 | sput_run_test(tlv_iter); 229 | sput_run_test(tlv_cmp); 230 | sput_run_test(tlv_nest); 231 | sput_run_test(test_tlv_sort); 232 | sput_leave_suite(); /* optional */ 233 | sput_finish_testing(); 234 | return sput_get_return_value(); 235 | } 236 | --------------------------------------------------------------------------------