Compare commits

...

10 Commits

Author SHA1 Message Date
Linus Lüssing 62ca2ad4a8 brmldproxy: add package
Adds the package brmldproxy from https://github.com/T-X/brmldproxy

Signed-off-by: Linus Lüssing <linus.luessing@c0d3.blue>
2024-03-26 21:01:51 +01:00
Florian Maurer 3d08b0fee8 wgpeerselector: fix undefined variable peer
Signed-off-by: Florian Maurer <f.maurer@outlook.de>
2024-01-22 23:22:23 +01:00
Matthias Schiffer 53ea3b8977 libplatforminfo: update bcm27xx target name
The RPi targets were renamed in OpenWrt 21.02 (Gluon 2022.1). As
libplatforminfo was not adjusted, image names were using autodetected
model names including a revision number again, requiring additional
manifest aliases.
2023-12-19 18:40:02 +01:00
Matthias Schiffer 28a35ea2c9 libplatforminfo: drop obsolete ar71xx-mikrotik target
The obsolete ar71xx-mikrotik.c was symlinked to template/nosysupgrade.c.
As all new mikrotik targets have sysupgrade support, we can just remove
the symlink and use the default handling of libplatforminfo.

nosysupgrade.c becomes unused, but it left in the repository for future
experimental targets without sysupgrade support.
2023-12-19 18:40:02 +01:00
Matthias Schiffer dc99bbb906
Merge pull request #268 from Kistelini/armsr
libplatforminfo: handle armsr target
2023-10-19 17:53:29 +02:00
Christian Buschau 2cf0156fd7
libplatforminfo: handle armsr target 2023-10-19 10:20:28 +02:00
Matthias Schiffer ce2e6ac193 simple-tc: fix kmod dependencies
simple-tc hasn't been working since OpenWrt 22.03, as act_police was moved
to a separate package.

While we're at it, we can also clean up the other dependencies:

- Remove the obsolete conditional dependencies, these were for
  GLUON_SPECIALIZE_KERNEL
- cls_basic was moved to kmod-sched-core, so we don't need kmod-sched
  anymore
2023-10-13 19:45:28 +02:00
Matthias Schiffer 72efd369ed uradvd: remove redundant package
uradvd lives in openwrt/packages now.
2023-10-02 23:46:03 +02:00
Matthias Schiffer c113a73912
Merge pull request #265 from freifunk-gluon/remove-tunneldigger
tunneldigger: remove redundant package
2023-09-27 21:38:51 +02:00
Matthias Schiffer 8329130a7c
tunneldigger: remove redundant package
A tunneldigger package has been upstreamed to openwrt/packages. Drop our
redundant copy.
2023-09-26 19:09:47 +02:00
17 changed files with 277 additions and 989 deletions

View File

@ -1 +0,0 @@
template/nosysupgrade.c

View File

@ -0,0 +1 @@
template/subtarget.c

View File

@ -0,0 +1,59 @@
/*
Copyright (c) 2015, Matthias Schiffer <mschiffer@universe-factory.net>
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
1. Redistributions of source code must retain the above copyright notice,
this list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include <libplatforminfo.h>
#include "../common.h"
#define _STRINGIFY(s) #s
#define STRINGIFY(s) _STRINGIFY(s)
static char * model = NULL;
__attribute__((constructor)) static void init(void) {
model = read_line("/tmp/sysinfo/model");
}
__attribute__((destructor)) static void deinit(void) {
free(model);
model = NULL;
}
const char * platforminfo_get_board_name(void) {
return NULL;
}
const char * platforminfo_get_model(void) {
return model;
}
const char * platforminfo_get_image_name(void) {
return STRINGIFY(TARGET) "-" STRINGIFY(SUBTARGET);
}

View File

@ -1,59 +0,0 @@
/*
Copyright (c) 2015, Matthias Schiffer <mschiffer@universe-factory.net>
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
1. Redistributions of source code must retain the above copyright notice,
this list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include <libplatforminfo.h>
#include "../common.h"
#define _STRINGIFY(s) #s
#define STRINGIFY(s) _STRINGIFY(s)
static char * model = NULL;
__attribute__((constructor)) static void init(void) {
model = read_line("/tmp/sysinfo/model");
}
__attribute__((destructor)) static void deinit(void) {
free(model);
model = NULL;
}
const char * platforminfo_get_board_name(void) {
return NULL;
}
const char * platforminfo_get_model(void) {
return model;
}
const char * platforminfo_get_image_name(void) {
return STRINGIFY(TARGET) "-" STRINGIFY(SUBTARGET);
}

View File

@ -0,0 +1 @@
template/subtarget.c

44
net/brmldproxy/Makefile Normal file
View File

@ -0,0 +1,44 @@
# SPDX-License-Identifier: MIT
# Copyright (C) 2023 Linus Lüssing <linus.luessing@c0d3.blue>
include $(TOPDIR)/rules.mk
PKG_NAME:=brmldproxy
PKG_RELEASE:=1
PKG_SOURCE_PROTO:=git
PKG_SOURCE_DATE:=2023-12-31
PKG_SOURCE_URL=https://github.com/T-X/brmldproxy.git
PKG_SOURCE_VERSION:=4d7fdb1a5c6e726b4c1930ad411d5571e09fa2f0
PKG_MIRROR_HASH:=1541eeaf6ae2fb4390448f02c5486da708cfa4d6200be77f884b47a2c86a7d06
PKG_MAINTAINER:=Linus Lüssing <linus.luessing@c0d3.blue>
PKG_LICENSE:=GPL-2.0-or-later
PKG_LICENSE_FILES:=LICENSE
include $(INCLUDE_DIR)/package.mk
define Package/brmldproxy
SECTION:=net
CATEGORY:=Network
TITLE:=Bridge MLD Proxy
DEPENDS:=+tc
endef
define Package/brmldproxy/description
A userspace controlled MLD proxy implementation for a Linux bridge.
The bridge itself will appear as a single multicast listening host
to any MLD querier on a configured proxy port, acting in deputy
for any other multicast listener behind adjacent bridge ports.
This potentially reduces MLD report overhead.
brmldproxy further allows to filter out specific multicast groups
and bridge ports from its combined MLD report.
endef
define Package/brmldproxy/install
$(INSTALL_DIR) $(1)/usr/sbin
$(INSTALL_BIN) $(PKG_BUILD_DIR)/brmldproxy $(1)/usr/sbin/
$(CP) ./files/* $(1)/
endef
$(eval $(call BuildPackage,brmldproxy))

View File

@ -0,0 +1,20 @@
#config brmldproxy 'lan'
# option disabled '1'
# # The bridge to apply brmldproxy to. Either the
# # bridge interface name or the UCI network interface
# # section name.
# option bridge 'lan'
# # Currently only "ipv6" is supported, optional.
# option family 'ipv6'
# # bridge port to proxy to
# list proxiedport 'wan0'
# # bridge port to proxy from
# list includedport 'lan0'
# # bridge port to exclude from proxying
# list excludedport 'lan1'
# # multicast IP address (range) to exclude from proxying
# list excludefilter 'ff00::/ff0e::'
# list excludefilter 'ff0e::/64'
# # multicast IP address (range) to include in proxying
# # (includes ff0e::123 even though ff0e::/64 was excluded above)
# list includefilter 'ff0e::123'

View File

@ -0,0 +1,37 @@
# SPDX-License-Identifier: MIT
# Copyright (C) 2023 Linus Lüssing <linus.luessing@c0d3.blue>
. /lib/functions.sh
[ -z "$INTERFACE" ] && exit 0
[ "$ACTION" != "ifup" ] && [ "$ACTION" != "ifdown" ] && exit 0
/etc/init.d/brmldproxy enabled || exit 0
brmldproxy_handle() {
local cfg="$1"
local disabled
local bridge
config_get_bool disabled "$cfg" disabled 0
[ "$disabled" -gt 0 ] && return 0
config_get bridge "$cfg" bridge
[ -z "$bridge" ] && return 0
[ "$bridge" != "$INTERFACE" ] && return 0
if [ "$ACTION" = "ifup" ]; then
/etc/init.d/brmldproxy start "$cfg" || return 0
else
/etc/init.d/brmldproxy stop "brmldproxy.$cfg" || return 0
fi
# success, stop
return 1
}
config_load brmldproxy
config_foreach brmldproxy_handle brmldproxy

View File

@ -0,0 +1,111 @@
#!/bin/sh /etc/rc.common
# SPDX-License-Identifier: MIT
# Copyright (C) 2023 Linus Lüssing <linus.luessing@c0d3.blue>
USE_PROCD=1
START=19
STOP=90
brmldproxy_start() {
local cfg="$1"
local namespace="$2"
local disabled
local ifname
local family
local bridge
local includedports
local excludedports
local proxiedports
local includefilters
local excludefilters
config_get_bool disabled "$cfg" disabled 0
[ "$disabled" -gt 0 ] && return 0
config_get bridge "$cfg" "bridge"
config_get family "$cfg" "family"
config_get includedports "$cfg" "includedport"
config_get excludedports "$cfg" "excludedport"
config_get proxiedports "$cfg" "proxiedport"
config_get includefilters "$cfg" "includefilter"
config_get excludefilters "$cfg" "excludefilter"
[ -z "$bridge" ] && {
echo "Error: no bridge specified for $cfg" >&2
return 0
}
. /lib/functions/network.sh
if network_get_device ifname "$bridge" && [ -n "$ifname" ]; then
bridge="$ifname"
fi
[ -n "$excludedports" ] && excludedports=$(echo "$excludedports" | sed 's/[^ ]* */-e &/g')
[ -n "$includedports" ] && includedports=$(echo "$includedports" | sed 's/[^ ]* */-i &/g')
[ -n "$proxiedports" ] && proxiedports=$(echo "$proxiedports" | sed 's/[^ ]* */-p &/g')
[ -n "$includefilters" ] && includefilters=$(echo "$includefilters" | sed 's/[^ ]* */-I &/g')
[ -n "$excludefilters" ] && excludefilters=$(echo "$excludefilters" | sed 's/[^ ]* */-E &/g')
[ -z "$namespace" ] && namespace="brmldproxy"
procd_open_instance "$namespace.$cfg"
procd_set_param command /usr/sbin/brmldproxy
[ "${family}" = "ipv4" ] && procd_append_param command -4
[ "${family}" = "ipv6" ] && procd_append_param command -6
procd_append_param command -b "$bridge"
[ -n "$excludedports" ] && procd_append_param command $excludedports
[ -n "$includedports" ] && procd_append_param command $includedports
[ -n "$proxiedports" ] && procd_append_param command $proxiedports
[ -n "$includefilters" ] && procd_append_param command $includefilters
[ -n "$excludefilters" ] && procd_append_param command $excludefilters
procd_set_param respawn ${respawn_threshold:-3600} ${respawn_timeout:-5} ${respawn_retry:-5}
procd_set_param stderr 1
procd_close_instance
}
start_service() {
local cfg="$1"
local namespace="$2"
local instance_found=0
. /lib/functions/network.sh
# no procd boot startup, via hotplug or manual only
[ $PPID -eq 1 ] && return 0
config_cb() {
local type="$1"
local name="$2"
if [ "$type" = "brmldproxy" ]; then
if [ -n "$cfg" -a "$cfg" = "$name" ]; then
instance_found=1
fi
fi
}
config_load brmldproxy
if [ -n "$cfg" ]; then
[ "$instance_found" -gt 0 ] || return
brmldproxy_start "$cfg" "$namespace"
else
config_foreach brmldproxy_start brmldproxy "$namespace"
fi
}
stop_service() {
local cfg="$1"
local namespace="$2"
[ -z "$namespace" ] && namespace="brmldproxy"
}
service_triggers() {
procd_add_reload_trigger brmldproxy
}

View File

@ -1,9 +1,7 @@
include $(TOPDIR)/rules.mk
PKG_NAME:=simple-tc
PKG_VERSION:=2
PKG_CONFIG_DEPENDS := CONFIG_KERNEL_NET_SCH_TBF CONFIG_KERNEL_NET_SCH_INGRESS CONFIG_KERNEL_NET_CLS_BASIC KERNEL_NET_ACT_POLICE
PKG_VERSION:=3
include $(INCLUDE_DIR)/package.mk
@ -11,7 +9,7 @@ define Package/simple-tc
SECTION:=net
CATEGORY:=Network
TITLE:=Simple bandwidth limiting
DEPENDS:=+!KERNEL_NET_SCH_TBF:kmod-sched-core +!KERNEL_NET_SCH_INGRESS:kmod-sched-core +!KERNEL_NET_CLS_BASIC:kmod-sched +!KERNEL_NET_ACT_POLICE:kmod-sched +libnl-tiny
DEPENDS:=+kmod-sched-core +kmod-sched-act-police +libnl-tiny
endef
TARGET_CFLAGS += -I$(STAGING_DIR)/usr/include/libnl-tiny

View File

@ -1,44 +0,0 @@
include $(TOPDIR)/rules.mk
PKG_NAME:=tunneldigger
PKG_RELEASE:=1
PKG_SOURCE_PROTO:=git
PKG_SOURCE_URL:=https://github.com/wlanslovenija/tunneldigger.git
PKG_SOURCE_DATE:=2020-05-17
PKG_SOURCE_VERSION:=8995046a2ba8f111391e01e6bb38a352c0cedaa1
include $(INCLUDE_DIR)/package.mk
include $(INCLUDE_DIR)/cmake.mk
define Package/tunneldigger
SECTION:=net
CATEGORY:=Network
DEPENDS:=+libnl-tiny +kmod-l2tp +kmod-l2tp-eth +librt +libpthread
TITLE:=L2TPv3 tunnel broker client
endef
TARGET_CFLAGS += \
-I$(STAGING_DIR)/usr/include/libnl-tiny \
-I$(STAGING_DIR)/usr/include \
-DLIBNL_TINY
define Build/Prepare
$(call Build/Prepare/Default)
$(CP) $(PKG_BUILD_DIR)/client/* $(PKG_BUILD_DIR)
endef
define Package/tunneldigger/install
$(INSTALL_DIR) $(1)/usr/bin
$(INSTALL_BIN) $(PKG_BUILD_DIR)/tunneldigger $(1)/usr/bin/tunneldigger
$(INSTALL_DIR) $(1)/etc/init.d
$(INSTALL_BIN) ./files/tunneldigger.init $(1)/etc/init.d/tunneldigger
$(INSTALL_DIR) $(1)/etc/config
$(INSTALL_DATA) ./files/config.default $(1)/etc/config/tunneldigger
endef
define Package/tunneldigger/conffiles
/etc/config/tunneldigger
endef
$(eval $(call BuildPackage,tunneldigger))

View File

@ -1,10 +0,0 @@
config broker
list address 'x.y.z.w:8942'
list address 'x.y.z.w:53'
list address 'x.y.z.w:123'
option uuid 'abcd'
option group 'root'
option interface 'l2tp0'
option limit_bw_down '1024'
option broker_selection 'usage'
option enabled '0'

View File

@ -1,97 +0,0 @@
#!/bin/sh /etc/rc.common
. $IPKG_INSTROOT/lib/functions/network.sh
START=90
PIDPATH=/var/run
tunnel_id=1
missing() {
echo "Not starting tunneldigger - missing $1" >&2
}
config_cb() {
local cfg="$CONFIG_SECTION"
config_get configname "$cfg" TYPE
case "$configname" in
broker)
config_get_bool enabled "$cfg" enabled 1
config_get addresses "$cfg" address
config_get uuid "$cfg" uuid
config_get interface "$cfg" interface
config_get group "$cfg" group
config_get limit_bw_down "$cfg" limit_bw_down
config_get hook_script "$cfg" hook_script
config_get bind_interface "$cfg" bind_interface
config_get broker_selection "$cfg" broker_selection
[ $enabled -eq 0 ] && return
local broker_opts=""
for address in $addresses; do
append broker_opts "-b ${address}"
done
[ ! -z "${limit_bw_down}" ] && append broker_opts "-L ${limit_bw_down}"
[ ! -z "${hook_script}" ] && append broker_opts "-s ${hook_script}"
[ ! -z "${bind_interface}" ] && {
# Resolve logical interface name.
unset _bind_interface
network_get_device _bind_interface "${bind_interface}" || _bind_interface="${bind_interface}"
append broker_opts "-I ${_bind_interface}"
}
[ ! -z "${broker_selection}" ] && {
# Set broker selection.
case "${broker_selection}" in
usage)
append broker_opts "-a"
;;
first)
append broker_opts "-g"
;;
random)
append broker_opts "-r"
;;
esac
}
if [ -z "$uuid" ]; then
missing uuid
return
elif [ -z "$interface" ]; then
missing interface
return
fi
echo "Starting tunneldigger on ${interface}"
/sbin/start-stop-daemon -S -q -b -m -c root:${group} -p ${PIDPATH}/tunneldigger.${interface}.pid -x /usr/bin/tunneldigger -- -u ${uuid} -i ${interface} -t ${tunnel_id} ${broker_opts}
let tunnel_id++
;;
esac
}
start() {
config_load tunneldigger
}
stop() {
for PIDFILE in `find ${PIDPATH}/ -name "tunneldigger\.*\.pid"`; do
PID="$(cat ${PIDFILE})"
IFACE="$(echo ${PIDFILE} | awk -F\/tunneldigger '{print $2}' | cut -d'.' -f2)"
echo "Stopping tunneldigger for interface ${IFACE}"
start-stop-daemon -K -q -p $PIDFILE
while test -d "/proc/${PID}"; do
echo " waiting for tunneldigger to stop"
sleep 1
done
echo " tunneldigger stopped"
done
}
restart() {
stop
start
}

View File

@ -1,20 +0,0 @@
include $(TOPDIR)/rules.mk
PKG_NAME:=uradvd
PKG_VERSION:=1
include $(INCLUDE_DIR)/package.mk
define Package/uradvd
SECTION:=net
CATEGORY:=Network
TITLE:=A tiny radvd
DEPENDS:=@IPV6 +librt
endef
define Package/uradvd/install
$(INSTALL_DIR) $(1)/usr/sbin
$(INSTALL_BIN) $(PKG_BUILD_DIR)/uradvd $(1)/usr/sbin/
endef
$(eval $(call BuildPackage,uradvd))

View File

@ -1,4 +0,0 @@
all: uradvd
uradvd: uradvd.c
$(CC) $(CPPFLAGS) $(CFLAGS) $(LDFLAGS) -Wall -o $@ $^ $(LDLIBS) -lrt

View File

@ -1,748 +0,0 @@
/*
Copyright (c) 2014, Matthias Schiffer <mschiffer@universe-factory.net>
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
1. Redistributions of source code must retain the above copyright notice,
this list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#define _GNU_SOURCE
#include <errno.h>
#include <ifaddrs.h>
#include <fcntl.h>
#include <getopt.h>
#include <limits.h>
#include <poll.h>
#include <stdbool.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include <unistd.h>
#include <arpa/inet.h>
#include <linux/netlink.h>
#include <linux/rtnetlink.h>
#include <net/if.h>
#include <netinet/in.h>
#include <netinet/icmp6.h>
#include <sys/types.h>
#include <sys/ioctl.h>
#include <sys/socket.h>
#include <sys/uio.h>
#include <sys/stat.h>
#define MAX_PREFIXES 8
#define MAX_RDNSS 3
/* These are in seconds */
#define AdvValidLifetime 86400u
#define AdvPreferredLifetime 14400u
#define AdvDefaultLifetime 0u
#define AdvCurHopLimit 64u
#define AdvRDNSSLifetime 1200u
#define MinRtrAdvInterval 200u
#define MaxRtrAdvInterval 600u
/* And these in milliseconds */
#define MAX_RA_DELAY_TIME 500u
#define MIN_DELAY_BETWEEN_RAS 3000u
struct icmpv6_opt {
uint8_t type;
uint8_t length;
uint8_t data[6];
};
struct iface {
bool ok;
unsigned int ifindex;
struct in6_addr ifaddr;
uint8_t mac[6];
};
struct __attribute__((__packed__)) nd_opt_rdnss {
uint8_t nd_opt_rdnss_type;
uint8_t nd_opt_rdnss_len;
uint16_t nd_opt_rdnss_reserved;
uint32_t nd_opt_rdnss_lifetime;
};
static struct global {
struct iface iface;
struct timespec time;
struct timespec next_advert;
struct timespec next_advert_earliest;
int icmp_sock;
int rtnl_sock;
const char *ifname;
uint16_t adv_default_lifetime;
size_t n_prefixes;
struct in6_addr prefixes[MAX_PREFIXES];
bool prefixes_onlink[MAX_PREFIXES];
size_t n_rdnss;
struct in6_addr rdnss[MAX_RDNSS];
} G = {
.rtnl_sock = -1,
.icmp_sock = -1,
.adv_default_lifetime = AdvDefaultLifetime,
};
static inline void print_error(const char *prefix, const char *message, int err) {
if (err)
fprintf(stderr, "uradvd: %s: %s: %s\n", prefix, message, strerror(err));
else
fprintf(stderr, "uradvd: %s: %s\n", prefix, message);
}
static inline void exit_error(const char *message, int err) {
print_error("error", message, err);
exit(1);
}
static inline void exit_errno(const char *message) {
exit_error(message, errno);
}
static inline void warn_error(const char *message, int err) {
print_error("error", message, err);
}
static inline void warn_errno(const char *message) {
warn_error(message, errno);
}
static inline void update_time(void) {
clock_gettime(CLOCK_MONOTONIC, &G.time);
}
/* Compares two timespecs and returns true if tp1 is after tp2 */
static inline bool timespec_after(const struct timespec *tp1, const struct timespec *tp2) {
return (tp1->tv_sec > tp2->tv_sec ||
(tp1->tv_sec == tp2->tv_sec && tp1->tv_nsec > tp2->tv_nsec));
}
/* Returns (tp1 - tp2) in milliseconds */
static inline int timespec_diff(const struct timespec *tp1, const struct timespec *tp2) {
return ((tp1->tv_sec - tp2->tv_sec))*1000 + (tp1->tv_nsec - tp2->tv_nsec)/1e6;
}
static inline void timespec_add(struct timespec *tp, unsigned int ms) {
tp->tv_sec += ms/1000;
tp->tv_nsec += (ms%1000) * 1e6;
if (tp->tv_nsec >= 1e9) {
tp->tv_nsec -= 1e9;
tp->tv_sec++;
}
}
static inline int setsockopt_int(int socket, int level, int option, int value) {
return setsockopt(socket, level, option, &value, sizeof(value));
}
static void init_random(void) {
unsigned int seed;
int fd = open("/dev/urandom", O_RDONLY);
if (fd < 0)
exit_errno("can't open /dev/urandom");
if (read(fd, &seed, sizeof(seed)) != sizeof(seed))
exit_errno("can't read from /dev/urandom");
close(fd);
srandom(seed);
}
static inline int rand_range(int min, int max) {
unsigned int r = (unsigned int)random();
return (r%(max-min) + min);
}
static void init_icmp(void) {
G.icmp_sock = socket(AF_INET6, SOCK_RAW|SOCK_NONBLOCK, IPPROTO_ICMPV6);
if (G.icmp_sock < 0)
exit_errno("can't open ICMP socket");
setsockopt_int(G.icmp_sock, IPPROTO_RAW, IPV6_CHECKSUM, 2);
setsockopt_int(G.icmp_sock, IPPROTO_IPV6, IPV6_MULTICAST_HOPS, 255);
setsockopt_int(G.icmp_sock, IPPROTO_IPV6, IPV6_MULTICAST_LOOP, 1);
setsockopt_int(G.icmp_sock, IPPROTO_IPV6, IPV6_RECVHOPLIMIT, 1);
struct icmp6_filter filter;
ICMP6_FILTER_SETBLOCKALL(&filter);
ICMP6_FILTER_SETPASS(ND_ROUTER_SOLICIT, &filter);
setsockopt(G.icmp_sock, IPPROTO_ICMPV6, ICMP6_FILTER, &filter, sizeof(filter));
}
static void init_rtnl(void) {
G.rtnl_sock = socket(AF_NETLINK, SOCK_DGRAM|SOCK_NONBLOCK, NETLINK_ROUTE);
if (G.rtnl_sock < 0)
exit_errno("can't open RTNL socket");
struct sockaddr_nl snl = {
.nl_family = AF_NETLINK,
.nl_groups = RTMGRP_LINK | RTMGRP_IPV6_IFADDR,
};
if (bind(G.rtnl_sock, (struct sockaddr *)&snl, sizeof(snl)) < 0)
exit_errno("can't bind RTNL socket");
}
static void schedule_advert(bool nodelay) {
struct timespec t = G.time;
if (nodelay)
timespec_add(&t, rand_range(0, MAX_RA_DELAY_TIME));
else
timespec_add(&t, rand_range(MinRtrAdvInterval*1000, MaxRtrAdvInterval*1000));
if (timespec_after(&G.next_advert_earliest, &t))
t = G.next_advert_earliest;
if (!nodelay || timespec_after(&G.next_advert, &t))
G.next_advert = t;
}
static int join_multicast(void) {
struct ipv6_mreq mreq = {
.ipv6mr_multiaddr = {
.s6_addr = {
/* all-routers address */
0xff, 0x02, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x02,
}
},
.ipv6mr_interface = G.iface.ifindex,
};
if (setsockopt(G.icmp_sock, IPPROTO_IPV6, IPV6_ADD_MEMBERSHIP, &mreq, sizeof(mreq)) == 0) {
return 2;
}
else if (errno != EADDRINUSE) {
warn_errno("can't join multicast group");
return 0;
}
return 1;
}
static void update_interface(void) {
struct iface old;
memcpy(&old, &G.iface, sizeof(struct iface));
memset(&G.iface, 0, sizeof(struct iface));
/* Update ifindex */
G.iface.ifindex = if_nametoindex(G.ifname);
if (!G.iface.ifindex)
return;
/* Update MAC address */
struct ifreq ifr = {};
strncpy(ifr.ifr_name, G.ifname, sizeof(ifr.ifr_name)-1);
if (ioctl(G.icmp_sock, SIOCGIFHWADDR, &ifr) < 0)
return;
memcpy(G.iface.mac, ifr.ifr_hwaddr.sa_data, sizeof(G.iface.mac));
struct ifaddrs *addrs, *addr;
if (getifaddrs(&addrs) < 0) {
warn_errno("getifaddrs");
return;
}
memset(&G.iface.ifaddr, 0, sizeof(G.iface.ifaddr));
for (addr = addrs; addr; addr = addr->ifa_next) {
if (!addr->ifa_addr || addr->ifa_addr->sa_family != AF_INET6)
continue;
const struct sockaddr_in6 *in6 = (const struct sockaddr_in6 *)addr->ifa_addr;
if (!IN6_IS_ADDR_LINKLOCAL(&in6->sin6_addr))
continue;
if (strncmp(addr->ifa_name, G.ifname, IFNAMSIZ-1) != 0)
continue;
G.iface.ifaddr = in6->sin6_addr;
}
freeifaddrs(addrs);
if (IN6_IS_ADDR_UNSPECIFIED(&G.iface.ifaddr))
return;
int joined = join_multicast();
if (!joined)
return;
setsockopt(G.icmp_sock, SOL_SOCKET, SO_BINDTODEVICE, G.ifname, strnlen(G.ifname, IFNAMSIZ-1));
G.iface.ok = true;
if (memcmp(&old, &G.iface, sizeof(struct iface)) != 0 || joined == 2)
schedule_advert(true);
}
static bool handle_rtnl_link(uint16_t type, const struct ifinfomsg *msg) {
switch (type) {
case RTM_NEWLINK:
if (!G.iface.ok)
return true;
break;
case RTM_SETLINK:
if ((unsigned)msg->ifi_index == G.iface.ifindex)
return true;
if (!G.iface.ok)
return true;
break;
case RTM_DELLINK:
if (G.iface.ok && (unsigned)msg->ifi_index == G.iface.ifindex)
return true;
}
return false;
}
static bool handle_rtnl_addr(uint16_t type, const struct ifaddrmsg *msg) {
switch (type) {
case RTM_NEWADDR:
if (!G.iface.ok && (unsigned)msg->ifa_index == G.iface.ifindex)
return true;
break;
case RTM_DELADDR:
if (G.iface.ok && (unsigned)msg->ifa_index == G.iface.ifindex)
return true;
}
return false;
}
static bool handle_rtnl_msg(uint16_t type, const void *data) {
switch (type) {
case RTM_NEWLINK:
case RTM_DELLINK:
case RTM_SETLINK:
return handle_rtnl_link(type, data);
case RTM_NEWADDR:
case RTM_DELADDR:
return handle_rtnl_addr(type, data);
default:
return false;
}
}
static void handle_rtnl(void) {
char buffer[4096];
ssize_t len = recv(G.rtnl_sock, buffer, sizeof(buffer), 0);
if (len < 0) {
warn_errno("recv");
return;
}
const struct nlmsghdr *nh;
for (nh = (struct nlmsghdr *)buffer; NLMSG_OK(nh, len); nh = NLMSG_NEXT(nh, len)) {
switch (nh->nlmsg_type) {
case NLMSG_DONE:
return;
case NLMSG_ERROR:
exit_error("netlink error", 0);
default:
if (handle_rtnl_msg(nh->nlmsg_type, NLMSG_DATA(nh))) {
update_interface();
return;
}
}
}
}
static void add_pktinfo(struct msghdr *msg) {
struct cmsghdr *cmsg = (struct cmsghdr*)((char*)msg->msg_control + msg->msg_controllen);
cmsg->cmsg_level = IPPROTO_IPV6;
cmsg->cmsg_type = IPV6_PKTINFO;
cmsg->cmsg_len = CMSG_LEN(sizeof(struct in6_pktinfo));
msg->msg_controllen += cmsg->cmsg_len;
struct in6_pktinfo pktinfo = {
.ipi6_addr = G.iface.ifaddr,
.ipi6_ifindex = G.iface.ifindex,
};
memcpy(CMSG_DATA(cmsg), &pktinfo, sizeof(pktinfo));
}
static void handle_solicit(void) {
struct sockaddr_in6 addr;
uint8_t buffer[1500] __attribute__((aligned(8)));
struct iovec vec = { .iov_base = buffer, .iov_len = sizeof(buffer) };
uint8_t cbuf[1024] __attribute__((aligned(8)));
struct msghdr msg = {
.msg_name = &addr,
.msg_namelen = sizeof(addr),
.msg_iov = &vec,
.msg_iovlen = 1,
.msg_control = cbuf,
.msg_controllen = sizeof(cbuf),
};
ssize_t len = recvmsg(G.icmp_sock, &msg, 0);
if (len < (ssize_t)sizeof(struct nd_router_solicit)) {
if (len < 0)
warn_errno("recvmsg");
return;
}
struct cmsghdr *cmsg;
for (cmsg = CMSG_FIRSTHDR(&msg); cmsg != NULL; cmsg = CMSG_NXTHDR(&msg, cmsg)) {
if (cmsg->cmsg_level != IPPROTO_IPV6)
continue;
if (cmsg->cmsg_type != IPV6_HOPLIMIT)
continue;
if (*(int*)CMSG_DATA(cmsg) != 255)
return;
break;
}
const struct nd_router_solicit *s = (struct nd_router_solicit *)buffer;
if (s->nd_rs_hdr.icmp6_type != ND_ROUTER_SOLICIT || s->nd_rs_hdr.icmp6_code != 0)
return;
const struct icmpv6_opt *opt = (struct icmpv6_opt *)(buffer + sizeof(struct nd_router_solicit)), *end = (struct icmpv6_opt *)(buffer+len);
for (; opt < end; opt += opt->length) {
if (opt+1 < end)
return;
if (!opt->length)
return;
if (opt+opt->length < end)
return;
if (opt->type == ND_OPT_SOURCE_LINKADDR && IN6_IS_ADDR_UNSPECIFIED(&addr.sin6_addr))
return;
}
if (opt != end)
return;
schedule_advert(true);
}
static void send_advert(void) {
if (!G.iface.ok)
return;
struct nd_router_advert advert = {
.nd_ra_hdr = {
.icmp6_type = ND_ROUTER_ADVERT,
.icmp6_dataun.icmp6_un_data8 = {AdvCurHopLimit, 0 /* Flags */, (G.adv_default_lifetime>>8) & 0xff, G.adv_default_lifetime & 0xff },
},
};
struct icmpv6_opt lladdr = {ND_OPT_SOURCE_LINKADDR, 1, {}};
memcpy(lladdr.data, G.iface.mac, sizeof(G.iface.mac));
struct nd_opt_prefix_info prefixes[G.n_prefixes];
size_t i;
for (i = 0; i < G.n_prefixes; i++) {
uint8_t flags = ND_OPT_PI_FLAG_AUTO;
if (G.prefixes_onlink[i])
flags |= ND_OPT_PI_FLAG_ONLINK;
prefixes[i] = (struct nd_opt_prefix_info){
.nd_opt_pi_type = ND_OPT_PREFIX_INFORMATION,
.nd_opt_pi_len = 4,
.nd_opt_pi_prefix_len = 64,
.nd_opt_pi_flags_reserved = flags,
.nd_opt_pi_valid_time = htonl(AdvValidLifetime),
.nd_opt_pi_preferred_time = htonl(AdvPreferredLifetime),
.nd_opt_pi_prefix = G.prefixes[i],
};
}
struct nd_opt_rdnss rdnss = {};
uint8_t rdnss_ips[G.n_rdnss][16];
if (G.n_rdnss > 0) {
rdnss.nd_opt_rdnss_type = 25;
rdnss.nd_opt_rdnss_len = 1 + 2 * G.n_rdnss;
rdnss.nd_opt_rdnss_lifetime = htonl(AdvRDNSSLifetime);
for (i = 0; i < G.n_rdnss; i++)
memcpy(rdnss_ips[i], G.rdnss[i].s6_addr, 16);
}
struct iovec vec[5] = {
{ .iov_base = &advert, .iov_len = sizeof(advert) },
{ .iov_base = &lladdr, .iov_len = sizeof(lladdr) },
{ .iov_base = prefixes, .iov_len = sizeof(prefixes) },
{ .iov_base = &rdnss, .iov_len = sizeof(rdnss) },
{ .iov_base = rdnss_ips, .iov_len = sizeof(rdnss_ips) }
};
struct sockaddr_in6 addr = {
.sin6_family = AF_INET6,
.sin6_addr = {
.s6_addr = {
/* all-nodes address */
0xff, 0x02, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x01,
}
},
.sin6_scope_id = G.iface.ifindex,
};
uint8_t cbuf[1024] __attribute__((aligned(8))) = {};
struct msghdr msg = {
.msg_name = &addr,
.msg_namelen = sizeof(addr),
.msg_iov = vec,
.msg_iovlen = G.n_rdnss > 0 ? 5 : 3,
.msg_control = cbuf,
.msg_controllen = 0,
.msg_flags = 0,
};
add_pktinfo(&msg);
if (sendmsg(G.icmp_sock, &msg, 0) < 0) {
G.iface.ok = false;
return;
}
G.next_advert_earliest = G.time;
timespec_add(&G.next_advert_earliest, MIN_DELAY_BETWEEN_RAS);
schedule_advert(false);
}
static void usage(void) {
fprintf(stderr, "Usage: uradvd [-h] -i <interface> -a/-p <prefix> [ -a/-p <prefix> ... ] [ --default-lifetime <seconds> ] [ --rdnss <ip> ... ]\n");
}
static void add_rdnss(const char *ip) {
if (G.n_rdnss == MAX_RDNSS) {
fprintf(stderr, "uradvd: error: maximum number of RDNSS IPs is %i.\n", MAX_RDNSS);
exit(1);
}
if (inet_pton(AF_INET6, ip, &G.rdnss[G.n_rdnss]) != 1) {
fprintf(stderr, "uradvd: error: invalid RDNSS IP address %s.\n", ip);
exit(1);
}
G.n_rdnss++;
}
static void add_prefix(const char *prefix, bool adv_onlink) {
if (G.n_prefixes == MAX_PREFIXES) {
fprintf(stderr, "uradvd: error: maximum number of prefixes is %i.\n", MAX_PREFIXES);
exit(1);
}
const size_t len = strlen(prefix)+1;
char prefix2[len];
memcpy(prefix2, prefix, len);
char *slash = strchr(prefix2, '/');
if (slash) {
*slash = 0;
if (strcmp(slash+1, "64") != 0)
goto error;
}
if (inet_pton(AF_INET6, prefix2, &G.prefixes[G.n_prefixes]) != 1)
goto error;
static const uint8_t zero[8] = {};
if (memcmp(G.prefixes[G.n_prefixes].s6_addr + 8, zero, 8) != 0)
goto error;
G.prefixes_onlink[G.n_prefixes] = adv_onlink;
G.n_prefixes++;
return;
error:
fprintf(stderr, "uradvd: error: invalid prefix %s (only prefixes of length 64 are supported).\n", prefix);
exit(1);
}
static void parse_cmdline(int argc, char *argv[]) {
int c;
char *endptr;
unsigned long val;
static struct option long_options[] =
{
{"default-lifetime", required_argument, 0, 0},
{"rdnss", required_argument, 0, 1},
{0, 0, 0, 0}
};
int option_index = 0;
while ((c = getopt_long(argc, argv, "i:a:p:h", long_options, &option_index)) != -1) {
switch(c) {
case 0: // --default-lifetime
val = strtoul(optarg, &endptr, 0);
if (!*optarg || *endptr || val > UINT16_MAX)
exit_error("invalid default lifetime\n", 0);
G.adv_default_lifetime = val;
break;
case 1: // --rdnss
add_rdnss(optarg);
break;
case 'i':
if (G.ifname)
exit_error("multiple interfaces are not supported.\n", 0);
G.ifname = optarg;
break;
case 'a':
add_prefix(optarg, false);
break;
case 'p':
add_prefix(optarg, true);
break;
case 'h':
usage();
exit(0);
default:
usage();
exit(1);
}
}
}
int main(int argc, char *argv[]) {
parse_cmdline(argc, argv);
if (!G.ifname || !G.n_prefixes)
exit_error("interface and prefix arguments are required.\n", 0);
init_random();
init_icmp();
init_rtnl();
update_time();
G.next_advert = G.next_advert_earliest = G.time;
update_interface();
while (true) {
struct pollfd fds[2] = {
{ .fd = G.icmp_sock, .events = POLLIN },
{ .fd = G.rtnl_sock, .events = POLLIN },
};
int timeout = -1;
if (G.iface.ok) {
timeout = timespec_diff(&G.next_advert, &G.time);
if (timeout < 0)
timeout = 0;
}
int ret = poll(fds, 2, timeout);
if (ret < 0)
exit_errno("poll");
update_time();
if (fds[0].revents & POLLIN)
handle_solicit();
if (fds[1].revents & POLLIN)
handle_rtnl();
if (timespec_after(&G.time, &G.next_advert))
send_advert();
}
}

View File

@ -380,7 +380,7 @@ function WGPeerSelector:main()
if self:try_connect_to_peer(peer, timeout) then
connected_peer = peer
log(syslog.LOG_INFO, 'Connection established with '..peer.name..'.')
log(syslog.LOG_INFO, 'Connection established with '..connected_peer.name..'.')
end
elseif state == 'established' then
@ -388,8 +388,8 @@ function WGPeerSelector:main()
if not connected_peer:has_recent_handshake() then
connected_peer:uninstall_from_kernel()
log(syslog.LOG_INFO, 'Connection to '..connected_peer.name..' lost.')
connected_peer = nil
log(syslog.LOG_INFO, 'Connection to '..peer.name..' lost.')
else
-- check connections every 5 seconds
sleep(5)