diff --git a/src/rtp/net_udp.c b/src/rtp/net_udp.c index 59f8a1847..695036b1c 100644 --- a/src/rtp/net_udp.c +++ b/src/rtp/net_udp.c @@ -905,11 +905,10 @@ error: return NULL; } -static const struct in6_addr in6_blackhole = IN6ADDR_BLACKHOLE_INIT; - bool udp_is_blackhole(socket_udp *s) { return s->sock.ss_family == AF_INET6 && - memcmp(&((struct sockaddr_in6 *) &s->sock)->sin6_addr, &in6_blackhole, IN6_BLACKHOLE_PREFIX_LEN) == 0; + is_addr_blackhole( + &((struct sockaddr_in6 *) &s->sock)->sin6_addr); } void udp_set_receiver(socket_udp *s, struct sockaddr *sa, socklen_t len) { diff --git a/src/rtp/rtp.c b/src/rtp/rtp.c index 8cade3917..46451251b 100644 --- a/src/rtp/rtp.c +++ b/src/rtp/rtp.c @@ -1074,7 +1074,8 @@ struct rtp *rtp_init_if(const char *addr, const char *iface, session->opt = (options *) malloc(sizeof(options)); session->userdata = userdata; session->mt_recv = multithreaded; - session->send_rtcp_to_origin = tx_port == 0 && is_host_loopback(addr); + session->send_rtcp_to_origin = + (tx_port == 0 && is_host_loopback(addr)) || is_host_blackhole(addr); if (rx_port == 0) { const unsigned random_off = (ug_rand() % (IPPORT_MAX - IPPORT_DYNAMIC + 1)) & ~1U; diff --git a/src/utils/net.c b/src/utils/net.c index f0283686d..884b498c5 100644 --- a/src/utils/net.c +++ b/src/utils/net.c @@ -3,7 +3,7 @@ * @author Martin Pulec */ /* - * Copyright (c) 2016-2023 CESNET z.s.p.o. + * Copyright (c) 2016-2024 CESNET * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -41,6 +41,9 @@ #include "config_win32.h" #endif +#include +#include + #ifdef WIN32 #include #else @@ -156,6 +159,26 @@ static struct addrinfo *resolve_host(const char *hostname, const char *err_prefi return ai; } +/// returns true for RFC 6666 IPv6 black hole address +bool +is_addr_blackhole(const struct in6_addr *addr) +{ + static const struct in6_addr in6_blackhole = IN6ADDR_BLACKHOLE_INIT; + return memcmp(addr, &in6_blackhole, IN6_BLACKHOLE_PREFIX_LEN) == 0; +} + +/// returns true for RFC 6666 IPv6 black hole address string +bool +is_host_blackhole(const char *hostname) +{ + if (strchr(hostname, ':') == NULL) { // not an IPv6 literal + return false; + } + struct in6_addr ipv6_addr; + inet_pton(AF_INET6, hostname, &ipv6_addr); + return is_addr_blackhole(&ipv6_addr); +} + bool is_host_loopback(const char *hostname) { struct addrinfo *ai = resolve_host(hostname, "is_host_loopback: "); diff --git a/src/utils/net.h b/src/utils/net.h index fe2645fe1..21cbd4e52 100644 --- a/src/utils/net.h +++ b/src/utils/net.h @@ -3,7 +3,7 @@ * @author Martin Pulec */ /* - * Copyright (c) 2016-2021 CESNET z.s.p.o. + * Copyright (c) 2016-2024 CESNET * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -50,19 +50,22 @@ #define IN6_MAX_ASCII_LEN 39 // 32 nibbles + 7 colons #define IN6ADDR_BLACKHOLE_INIT { { { 1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1 } } } // RFC 6666 -#define IN6_BLACKHOLE_PREFIX_LEN 8 +#define IN6_BLACKHOLE_PREFIX_LEN 8 // in bytes (64 bit prefix) #define IN6_BLACKHOLE_STR "100::1" #ifdef __cplusplus extern "C" { #endif +struct in6_addr; struct sockaddr; struct sockaddr_storage; +bool is_addr_blackhole(const struct in6_addr *addr); bool is_addr_linklocal(struct sockaddr *sa); bool is_addr_loopback(struct sockaddr *sa); bool is_addr_private(struct sockaddr *sa); bool is_addr_multicast(const char *addr); +bool is_host_blackhole(const char *hostname); bool is_host_loopback(const char *hostname); bool is_host_private(const char *hostname); uint16_t socket_get_recv_port(int fd);