Skip to content

Commit 4216e61

Browse files
committed
Validate multicast addresses, pre-filter by allowed network stacks
1 parent 062dc6e commit 4216e61

File tree

7 files changed

+53
-34
lines changed

7 files changed

+53
-34
lines changed

src/api_config.cpp

Lines changed: 19 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -149,32 +149,29 @@ void api_config::load_from_file(const std::string &filename) {
149149
else
150150
throw std::runtime_error("This ResolveScope setting is unsupported.");
151151

152-
multicast_addresses_.insert(
153-
multicast_addresses_.end(), machine_group.begin(), machine_group.end());
152+
std::vector<std::string> mcasttmp;
153+
154+
mcasttmp.insert(mcasttmp.end(), machine_group.begin(), machine_group.end());
154155
multicast_ttl_ = 0;
155156

156157
if (scope >= link) {
157-
multicast_addresses_.insert(
158-
multicast_addresses_.end(), link_group.begin(), link_group.end());
159-
multicast_addresses_.push_back("FF02:" + ipv6_multicast_group);
158+
mcasttmp.insert(mcasttmp.end(), link_group.begin(), link_group.end());
159+
mcasttmp.push_back("FF02:" + ipv6_multicast_group);
160160
multicast_ttl_ = 1;
161161
}
162162
if (scope >= site) {
163-
multicast_addresses_.insert(
164-
multicast_addresses_.end(), site_group.begin(), site_group.end());
165-
multicast_addresses_.push_back("FF05:" + ipv6_multicast_group);
163+
mcasttmp.insert(mcasttmp.end(), site_group.begin(), site_group.end());
164+
mcasttmp.push_back("FF05:" + ipv6_multicast_group);
166165
multicast_ttl_ = 24;
167166
}
168167
if (scope >= organization) {
169-
multicast_addresses_.insert(
170-
multicast_addresses_.end(), organization_group.begin(), organization_group.end());
171-
multicast_addresses_.push_back("FF08:" + ipv6_multicast_group);
168+
mcasttmp.insert(mcasttmp.end(), organization_group.begin(), organization_group.end());
169+
mcasttmp.push_back("FF08:" + ipv6_multicast_group);
172170
multicast_ttl_ = 32;
173171
}
174172
if (scope >= global) {
175-
multicast_addresses_.insert(
176-
multicast_addresses_.end(), global_group.begin(), global_group.end());
177-
multicast_addresses_.push_back("FF0E:" + ipv6_multicast_group);
173+
mcasttmp.insert(mcasttmp.end(), global_group.begin(), global_group.end());
174+
mcasttmp.push_back("FF0E:" + ipv6_multicast_group);
178175
multicast_ttl_ = 255;
179176
}
180177

@@ -183,7 +180,14 @@ void api_config::load_from_file(const std::string &filename) {
183180
std::vector<std::string> address_override =
184181
parse_set(pt.get("multicast.AddressesOverride", "{}"));
185182
if (ttl_override >= 0) multicast_ttl_ = ttl_override;
186-
if (!address_override.empty()) multicast_addresses_ = address_override;
183+
if (!address_override.empty()) mcasttmp = address_override;
184+
185+
// Parse, validate and store multicast addresses
186+
for (std::vector<std::string>::iterator it = mcasttmp.begin(); it != mcasttmp.end(); ++it) {
187+
ip::address addr = ip::make_address(*it);
188+
if ((addr.is_v4() && allow_ipv4_) || (addr.is_v6() && allow_ipv6_))
189+
multicast_addresses_.push_back(addr);
190+
}
187191

188192
// The network stack requires the source interfaces for multicast packets to be
189193
// specified as IPv4 address or an IPv6 interface index

src/api_config.h

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,8 @@
77
#include <string>
88
#include <vector>
99

10+
namespace ip = asio::ip;
11+
1012
namespace lsl {
1113
/**
1214
* A configuration object: holds all the configurable settings of liblsl.
@@ -83,7 +85,7 @@ class api_config {
8385
const std::string &resolve_scope() const { return resolve_scope_; }
8486

8587
/**
86-
* @brief List of multicast addresses on which inlets / outlets advertise/discover streams.
88+
* List of multicast addresses on which inlets / outlets advertise/discover streams.
8789
*
8890
* This is merged from several other config file entries
8991
* (LocalAddresses,SiteAddresses,OrganizationAddresses, GlobalAddresses)
@@ -98,7 +100,7 @@ class api_config {
98100
* department) or organization (e.g., the campus), or at larger scope, multicast addresses
99101
* with the according scope need to be included.
100102
*/
101-
const std::vector<std::string> &multicast_addresses() const { return multicast_addresses_; }
103+
const std::vector<ip::address> &multicast_addresses() const { return multicast_addresses_; }
102104

103105
/**
104106
* @brief The address of the local interface on which to listen to multicast traffic.
@@ -226,7 +228,7 @@ class api_config {
226228
bool allow_random_ports_;
227229
uint16_t multicast_port_;
228230
std::string resolve_scope_;
229-
std::vector<std::string> multicast_addresses_;
231+
std::vector<ip::address> multicast_addresses_;
230232
int multicast_ttl_;
231233
std::string listen_address_;
232234
std::vector<std::string> known_peers_;

src/resolver_impl.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ resolver_impl::resolver_impl()
2626
uint16_t mcast_port = cfg_->multicast_port();
2727
for (const auto &mcast_addr : cfg_->multicast_addresses()) {
2828
try {
29-
mcast_endpoints_.emplace_back(asio::ip::make_address(mcast_addr), mcast_port);
29+
mcast_endpoints_.emplace_back(mcast_addr, mcast_port);
3030
} catch (std::exception &) {}
3131
}
3232

src/stream_outlet_impl.cpp

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -79,16 +79,15 @@ void stream_outlet_impl::instantiate_stack(udp udp_protocol) {
7979
// create UDP time server
8080
udp_servers_.push_back(std::make_shared<udp_server>(info_, *io_ctx_service_, udp_protocol));
8181
// create UDP multicast responders
82-
for (const auto &mcastaddr : cfg->multicast_addresses()) {
82+
for (const auto &address : cfg->multicast_addresses()) {
8383
try {
8484
// use only addresses for the protocol that we're supposed to use here
85-
auto address = asio::ip::make_address(mcastaddr);
8685
if (udp_protocol == udp::v4() ? address.is_v4() : address.is_v6())
8786
responders_.push_back(std::make_shared<udp_server>(
88-
info_, *io_ctx_service_, mcastaddr, multicast_port, multicast_ttl, listen_address));
87+
info_, *io_ctx_service_, address, multicast_port, multicast_ttl, listen_address));
8988
} catch (std::exception &e) {
90-
LOG_F(WARNING, "Couldn't create multicast responder for %s (%s)", mcastaddr.c_str(),
91-
e.what());
89+
LOG_F(WARNING, "Couldn't create multicast responder for %s (%s)",
90+
address.to_string().c_str(), e.what());
9291
}
9392
}
9493
}

src/udp_server.cpp

Lines changed: 21 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
#include "udp_server.h"
2+
#include "api_config.h"
23
#include "socket_utils.h"
34
#include "stream_info_impl.h"
45
#include "util/strfuns.hpp"
@@ -34,11 +35,10 @@ udp_server::udp_server(stream_info_impl_p info, asio::io_context &io, udp protoc
3435
(void *)this);
3536
}
3637

37-
udp_server::udp_server(stream_info_impl_p info, asio::io_context &io, const std::string &address,
38+
udp_server::udp_server(stream_info_impl_p info, asio::io_context &io, ip::address addr,
3839
uint16_t port, int ttl, const std::string &listen_address)
3940
: info_(std::move(info)), io_(io), socket_(std::make_shared<udp_socket>(io)),
4041
time_services_enabled_(false) {
41-
ip::address addr = ip::make_address(address);
4242
bool is_broadcast = addr == ip::address_v4::broadcast();
4343

4444
// set up the endpoint where we listen (note: this is not yet the multicast address)
@@ -65,16 +65,28 @@ udp_server::udp_server(stream_info_impl_p info, asio::io_context &io, const std:
6565
// bind to the listen endpoint
6666
socket_->bind(listen_endpoint);
6767

68-
// join the multicast group, if any
68+
// join the multicast groups
6969
if (addr.is_multicast() && !is_broadcast) {
70-
if (addr.is_v4())
71-
socket_->set_option(
72-
ip::multicast::join_group(addr.to_v4(), listen_endpoint.address().to_v4()));
73-
else
74-
socket_->set_option(ip::multicast::join_group(addr));
70+
bool joined_anywhere = false;
71+
asio::error_code err;
72+
for (auto &if_ : api_config::get_instance()->multicast_interfaces) {
73+
DLOG_F(
74+
INFO, "Joining %s to %s", if_.addr.to_string().c_str(), addr.to_string().c_str());
75+
if (addr.is_v4() && if_.addr.is_v4())
76+
socket_->set_option(ip::multicast::join_group(addr.to_v4(), if_.addr.to_v4()), err);
77+
else if (addr.is_v6() && if_.addr.is_v6())
78+
socket_->set_option(
79+
ip::multicast::join_group(addr.to_v6(), if_.addr.to_v6().scope_id()), err);
80+
if (err)
81+
LOG_F(WARNING, "Could not bind multicast responder for %s to interface %s (%s)",
82+
addr.to_string().c_str(), if_.addr.to_string().c_str(), err.message().c_str());
83+
else
84+
joined_anywhere = true;
85+
}
86+
if (!joined_anywhere) throw std::runtime_error("Could not join any multicast group");
7587
}
7688
LOG_F(2, "%s: Started multicast udp server at %s port %d (addr %p)",
77-
this->info_->name().c_str(), address.c_str(), port, (void *)this);
89+
this->info_->name().c_str(), addr.to_string().c_str(), port, (void *)this);
7890
}
7991

8092
// === externally issued asynchronous commands ===

src/udp_server.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,7 @@ class udp_server : public std::enable_shared_from_this<udp_server> {
4646
* This server will listen on a multicast address and responds only to LSL:shortinfo requests.
4747
* This is for multicast/broadcast (and optionally unicast) local service discovery.
4848
*/
49-
udp_server(stream_info_impl_p info, asio::io_context &io, const std::string &address,
49+
udp_server(stream_info_impl_p info, asio::io_context &io, asio::ip::address addr,
5050
uint16_t port, int ttl, const std::string &listen_address);
5151

5252

testing/lslcfgs/default.cfg

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,4 @@
1+
[ports]
2+
IPv6=allow
13
[lab]
24
KnownPeers=127.0.0.1

0 commit comments

Comments
 (0)