Skip to content

Commit

Permalink
Merge branch 'dev'
Browse files Browse the repository at this point in the history
  • Loading branch information
gershnik committed Jan 12, 2025
2 parents bd7530d + 2126cdb commit 452e6c8
Show file tree
Hide file tree
Showing 24 changed files with 192 additions and 44 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,7 @@ jobs:
mac:
runs-on: macos-14
env:
DEVELOPER_DIR: /Applications/Xcode_15.4.app
DEVELOPER_DIR: /Applications/Xcode_16.2.app

steps:
- name: Checkout
Expand Down
35 changes: 27 additions & 8 deletions .github/workflows/check.yml
Original file line number Diff line number Diff line change
Expand Up @@ -21,26 +21,43 @@ on:

jobs:
linux:
runs-on: ubuntu-latest
runs-on: ${{ matrix.os }}
strategy:
fail-fast: false
matrix:
include:
#gcc
- compiler: gcc
version: 11
os: ubuntu-latest
- compiler: gcc
version: 12
os: ubuntu-latest
- compiler: gcc
version: 13
os: ubuntu-latest
- compiler: gcc
version: 14
os: ubuntu-latest
#clang
- compiler: clang
version: 13
# See https://github.com/actions/runner-images/issues/8659
# - compiler: clang
# version: 13
# - compiler: clang
# version: 14
os: ubuntu-22.04
- compiler: clang
version: 14
os: ubuntu-22.04
- compiler: clang
version: 15
os: ubuntu-22.04
- compiler: clang
version: 16
os: ubuntu-22.04
- compiler: clang
version: 17
os: ubuntu-latest
- compiler: clang
version: 18
os: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v4
Expand All @@ -54,8 +71,10 @@ jobs:
wget https://apt.llvm.org/llvm.sh
chmod u+x llvm.sh
sudo ./llvm.sh ${{ matrix.version }}
sudo apt-get install -y clang-tools-${{ matrix.version }} libc++-${{ matrix.version }}-dev libc++abi-${{ matrix.version }}-dev
echo "CC=clang-${{ matrix.version }}" >> $GITHUB_ENV
echo "CXX=clang++-${{ matrix.version }}" >> $GITHUB_ENV
echo "CXXFLAGS=-stdlib=libc++" >> $GITHUB_ENV
fi
if [[ '${{ matrix.compiler }}' == 'gcc' ]]; then
Expand Down Expand Up @@ -110,9 +129,9 @@ jobs:
- os: macos-13
xcode: '15.2'
- os: macos-14
xcode: '14.3.1'
xcode: '15.4'
- os: macos-14
xcode: '15.3'
xcode: '16.2'
env:
DEVELOPER_DIR: /Applications/Xcode_${{ matrix.xcode }}.app
steps:
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/publish.yml
Original file line number Diff line number Diff line change
Expand Up @@ -75,7 +75,7 @@ jobs:
runs-on: macos-14
needs: prepare
env:
DEVELOPER_DIR: /Applications/Xcode_15.4.app
DEVELOPER_DIR: /Applications/Xcode_16.2.app

steps:
- name: Checkout
Expand Down
9 changes: 9 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,15 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),

## Unreleased

### Added
* `--source-port` command line argument and `source-port` config file option to set the source port for multicast messages
for better firewall interoperability.
* Configuration files for `firewalld`. These are now also delivered and used in RPM binary packages.

### Changed
- Updated 3rd party dependencies
- Firewall configuration files now live under `config/firewalls`

## [1.15] - 2024-10-03

### Changed
Expand Down
23 changes: 18 additions & 5 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -324,7 +324,7 @@ sudo dnf install wsddn
#sudo yum install wsddn
```

On first install firewall ports `5357/tcp` and `3702/udp` will be opened.
On first install firewall will be configured to open `wsddn` service.

Enable and start the daemon:

Expand Down Expand Up @@ -661,7 +661,7 @@ Command line flags and configuration file entries are documented in `man wsddn`

### Firewall Setup

<small>Note: The following instructions are copied verbatim from [wsdd][wsdd] one since the requirements are identical</small>
<small>Note: The following instructions are copied almost verbatim from [wsdd][wsdd] since the requirements are identical</small>

Traffic for the following ports, directions and addresses must be allowed.

Expand All @@ -673,12 +673,17 @@ Traffic for the following ports, directions and addresses must be allowed.

You should further restrict the traffic to the (link-)local subnet, e.g. by using the `fe80::/10` address space for IPv6. Please note that IGMP traffic must be enabled in order to get IPv4 multicast traffic working.

For UFW and firewalld, application/service profiles can be found under `config/firewalls`. If using binary installation packages these are provided
as part of the installation. Note that UFW profiles only allow to grant the traffic on specific UDP and TCP ports, but a restriction on the IP range (like link local for IPv6) or the multicast traffic is not possible.

### Security

There are two main security concerns with a daemon that delivers data about local machine over the network
There are four main security concerns with a daemon that accepts network requests and delivers data about local machine over the network

1. A bug inside daemon code may allow remote attacker to penetrate the machine running it.
1. A bug inside the daemon code may allow a remote attacker to penetrate the machine running it.
2. The information legitimately provided by the daemon will disclose something to an attacker that would otherwise remain unknown, enabling him to mount further attacks.
3. A bug or even the _normal functionality_ of the daemon might allow a remote attacker to use it to mount further attacks against other systems. For example it might be possible to "convince" the daemon to become a part of a distributed denial of service (DDoS) attack.
4. A bug or a normal operation of the daemon might allow a remote attacker to make it or even the entire machine hosting it unresponsive resulting in a denial of service.

Currently the implementation ignores the second concern. The things **wsdd-native** discloses are the existence of the local host, its name, presence of Samba on it and domain/workgroup membership. All of these are generally disclosed by Samba itself via SMB broadcasts so, assuming the firewall is configured as described above, there is no net gain for an attacker. WS-Discovery protocol contains provisions for encrypting its HTTP traffic and potentially authenticating clients accessing your host via their client certificates. This limits exposure somewhat but at a significant configuration and maintenance cost. If there is interest in any of it it is possible to easily add this functionality in a future version.

Expand All @@ -688,7 +693,15 @@ The first concern is by far the most significant one. All software contains bugs

These measures are automatic and cannot be bypassed. Taken together they should limit the fallout of any vulnerability though, of course, nothing ever can be claimed to be 100% secure.

Note that when running on `systemd` systems it is recommended to use its `DynamicUser` facility instead of running as root and relying on the measures above. The Debian/Ubuntu/Arch installer does so.
Note that when running on `systemd` systems it is recommended to use its `DynamicUser` facility instead of running as root and relying on the measures above. The Debian/Ubuntu/Fedora/Arch binary packages do so.

The third concern is also a significant one. Even in absence of any bugs a completely correct implementation of WS-Discovery protocol is known to be vulnerable to these kinds of attacks. See for example
[here](https://blogs.akamai.com/sitr/2019/09/new-ddos-vector-observed-in-the-wild-wsd-attacks-hitting-35gbps.html) and
[here](https://www.zdnet.com/article/protocol-used-by-630000-devices-can-be-abused-for-devastating-ddos-attacks/).
Bugs (always a possibility) can make things even worse. As far as I know there is no effective mitigation to this threat that **wsdd-native** can implement in code. The only way to prevent these kinds of attacks is to __never__ expose **wsdd-native** ports to open internet via [firewall configuration](#firewall-setup). Given that the whole purpose of this daemon is to enable interoperability with Windows via SMB protocol there is probably never a good
reason to let it accept and send traffic outside of a local network.

The fourth concern, while also present, is less severe than the above. **wsdd-native** is single threaded and so, even if overwhelmed by traffic, will not stress more than 1 CPU core. Its memory consumption is bounded so, in absence of bugs, it will not stress system memory either. It can itself be rendered unresponsive, of course, by too much traffic but, considering that it probably isn't a vital service for anyone, this isn't something that would excite any attacker. Possible bugs change this picture, however. If the network process is hijacked, even if mitigations for the 1st concern prevent further system penetration, the attacker can still make the network process consume too much CPU and memory. You can try to mitigate against this possibility by limiting daemon CPU and memory usage via [cgroups](https://www.redhat.com/en/blog/cgroups-part-four) or other mechanisms. However, a much simpler solution to these issues is the same as the above - never expose the daemon to the open internet.

### Custom metadata

Expand Down
23 changes: 14 additions & 9 deletions cmake/dependencies.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ list(APPEND DEPENDECIES_JSON "\"argum\": \"pkg:github/${ARGUM_REPO}@${ARGUM_VER}
#################################################

set(SYS_STRING_REPO gershnik/sys_string)
set(SYS_STRING_VER v2.14)
set(SYS_STRING_VER v2.16)
FetchContent_Declare(sys_string
GIT_REPOSITORY https://github.com/${SYS_STRING_REPO}.git
GIT_TAG ${SYS_STRING_VER}
Expand Down Expand Up @@ -77,7 +77,7 @@ if (NOT LibXml2_FOUND)
set(LIBXML2_WITH_MODULES OFF)
set(LIBXML2_WITH_PROGRAMS OFF)

set(LIBXML_VER v2.13.4)
set(LIBXML_VER v2.13.5)
FetchContent_Declare(libxml2
GIT_REPOSITORY https://gitlab.gnome.org/GNOME/libxml2.git
GIT_TAG ${LIBXML_VER}
Expand All @@ -91,7 +91,7 @@ endif()
#################################################

set(UUID_REPO gershnik/libuuid-cmake)
set(UUID_VER v2.40.2)
set(UUID_VER v2.40.3)
FetchContent_Declare(libuuid
GIT_REPOSITORY https://github.com/${UUID_REPO}.git
GIT_TAG ${UUID_VER}
Expand All @@ -105,7 +105,7 @@ list(APPEND DEPENDECIES_JSON "\"libuuid\": \"pkg:github/${UUID_REPO}@${UUID_VER}
set(FMT_INSTALL OFF)

set(FMT_REPO fmtlib/fmt)
set(FMT_VER 11.0.2)
set(FMT_VER 11.1.1)
FetchContent_Declare(fmt
GIT_REPOSITORY https://github.com/${FMT_REPO}
GIT_TAG ${FMT_VER}
Expand All @@ -122,11 +122,16 @@ set(SPDLOG_NO_TLS ON CACHE BOOL "prevent spdlog from using thread local storage"
set(SPDLOG_FMT_EXTERNAL ON CACHE BOOL "Use external fmt library instead of bundled")

set(SPDLOG_REPO gabime/spdlog)
set(SPDLOG_VER v1.14.1)
set(SPDLOG_VER v1.15.0)
FetchContent_Declare(spdlog
GIT_REPOSITORY https://github.com/${SPDLOG_REPO}
GIT_TAG ${SPDLOG_VER}
GIT_SHALLOW TRUE
# GIT_REPOSITORY https://github.com/${SPDLOG_REPO}
# GIT_TAG ${SPDLOG_VER}
# GIT_SHALLOW TRUE

URL https://github.com/${SPDLOG_REPO}/tarball/${SPDLOG_VER}

PATCH_COMMAND patch -p0 -s -f -i ${CMAKE_CURRENT_LIST_DIR}/patches/spdlog.diff
LOG_PATCH ON
)
list(APPEND DECLARED_DEPENDENCIES spdlog)
list(APPEND DEPENDECIES_JSON "\"spdlog\": \"pkg:github/${SPDLOG_REPO}@${SPDLOG_VER}\"")
Expand All @@ -150,7 +155,7 @@ list(APPEND DEPENDECIES_JSON "\"tomlplusplus\": \"pkg:github/${TOMPLUSPLUS_REPO}
#################################################

set(OUTCOME_REPO ned14/outcome)
set(OUTCOME_VER v2.2.10)
set(OUTCOME_VER v2.2.11)
# FetchContent_Declare(outcome
# GIT_REPOSITORY https://github.com/${OUTCOME_REPO}
# GIT_TAG ${OUTCOME_VER}
Expand Down
8 changes: 8 additions & 0 deletions cmake/patches/spdlog.diff
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
--- include/spdlog/fmt/fmt.h
+++ include/spdlog/fmt/fmt.h
@@ -27,4 +27,5 @@
#else // SPDLOG_FMT_EXTERNAL is defined - use external fmtlib
#include <fmt/core.h>
#include <fmt/format.h>
+ #include <fmt/xchar.h>
#endif
6 changes: 6 additions & 0 deletions config/firewalls/etc/firewalld/services/wsddn-http.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<service>
<short>WS-Discovery Host Daemon (HTTP Interface)</short>
<description>Allows your machine to be discovered by Windows 10 and above systems and displayed by their Explorer &quot;Network&quot; views.</description>
<port port="5357" protocol="tcp"/>
</service>
8 changes: 8 additions & 0 deletions config/firewalls/etc/firewalld/services/wsddn.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
<?xml version="1.0" encoding="utf-8"?>
<service>
<short>WS-Discovery Host Daemon</short>
<description>Allows your machine to be discovered by Windows 10 and above systems and displayed by their Explorer &quot;Network&quot; views.</description>
<port port="3702" protocol="udp"/>
<destination ipv4="239.255.255.250" ipv6="FF02::C"/>
<include service="wsddn-http"/>
</service>
4 changes: 4 additions & 0 deletions config/firewalls/etc/ufw/applications.d/wsddn
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
[wsddn]
title=WS-Discovery Host Daemon
description=Allows your machine to be discovered by Windows 10 and above systems and displayed by their Explorer "Network" views.
ports=3702/udp|5357/tcp
4 changes: 0 additions & 4 deletions config/systemd/etc/ufw/applications.d/wsddn

This file was deleted.

10 changes: 10 additions & 0 deletions doc/wsddn.8
Original file line number Diff line number Diff line change
Expand Up @@ -178,6 +178,13 @@ Set the hop limit for multicast packets.
The default is 1 which should prevent packets from leaving the local
network segment.
The equivalent config file option is \f[CR]hoplimit\f[R]
.TP
\f[CR]\-\-source\-port\f[R] \f[I]number\f[R]
Set the source port for outgoing multicast messages, so that replies
will use this as the destination port.
This is useful for firewalls that do not detect incoming unicast replies
to a multicast as part of the flow, so the port needs to be fixed in
order to be allowed manually.
.SS Machine information options
.TP
\f[CR]\-\-uuid\f[R] \f[I]uuid\f[R]
Expand Down Expand Up @@ -288,6 +295,9 @@ Same as \f[CR]\-\-chroot\f[R] command line option
\f[CR]hoplimit\f[R] = \f[I]number\f[R]
Same as \f[CR]\-\-hoplimit\f[R] command line option
.TP
\f[CR]source\-port\f[R] = \f[I]number\f[R]
Same as \f[CR]\-\-source\-port\f[R] command line option
.TP
\f[CR]hostname\f[R] = \[lq]\f[I]name\f[R]\[rq]
Same as \f[CR]\-\-hostname\f[R] command line option
.TP
Expand Down
18 changes: 17 additions & 1 deletion doc/wsddn.8.html

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

6 changes: 6 additions & 0 deletions doc/wsddn.8.md
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,9 @@ exploits into wsddn. If not specified the behavior is as follows
`--hoplimit` _number_
: Set the hop limit for multicast packets. The default is 1 which should prevent packets from leaving the local network segment. The equivalent config file option is `hoplimit`

`--source-port` _number_
: Set the source port for outgoing multicast messages, so that replies will use this as the destination port. This is useful for firewalls that do not detect incoming unicast replies to a multicast as part of the flow, so the port needs to be fixed in order to be allowed manually.

## Machine information options

`--uuid` _uuid_
Expand Down Expand Up @@ -154,6 +157,9 @@ Any options specified on command line take precedence over options in the config
`hoplimit` = _number_
: Same as `--hoplimit` command line option

`source-port` = _number_
: Same as `--source-port` command line option

`hostname` = "_name_"
: Same as `--hostname` command line option

Expand Down
7 changes: 4 additions & 3 deletions installers/deb/build.py
Original file line number Diff line number Diff line change
Expand Up @@ -34,9 +34,10 @@

installCode(builddir, stagedir / 'usr')

shutil.copytree(srcdir / 'config/systemd/usr', stagedir / 'usr', dirs_exist_ok=True)
shutil.copytree(srcdir / 'config/systemd/etc', stagedir / 'etc', dirs_exist_ok=True)
shutil.copytree(srcdir / 'config/sysv/etc', stagedir / 'etc', dirs_exist_ok=True)
shutil.copytree(srcdir / 'config/systemd/usr', stagedir / 'usr', dirs_exist_ok=True)
shutil.copytree(srcdir / 'config/firewalls/etc/ufw', stagedir / 'etc/ufw', dirs_exist_ok=True)
shutil.copytree(srcdir / 'config/firewalls/etc/firewalld', stagedir / 'usr/lib/firewalld', dirs_exist_ok=True)
shutil.copytree(srcdir / 'config/sysv/etc', stagedir / 'etc', dirs_exist_ok=True)

docdir = stagedir / 'usr/share/doc/wsddn'
docdir.mkdir(parents=True)
Expand Down
Loading

0 comments on commit 452e6c8

Please sign in to comment.