Compare commits

...

10 Commits

Author SHA1 Message Date
T-X ea3f9b8c9a
Merge ef6317e324 into 3d08b0fee8 2024-01-27 14:41:27 +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
13 changed files with 65 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

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)