/ src / main.cpp
main.cpp
  1  // SPDX-FileCopyrightText: Copyright (C) 2024-2026 Marek Küthe <m.k@mk16.de>
  2  //
  3  // SPDX-License-Identifier: GPL-3.0-or-later
  4  
  5  #include <fstream>
  6  #include <memory>
  7  #include <span>
  8  #include <sstream>
  9  #include <system_error>
 10  #include <stdexcept>
 11  #include <cstdlib>
 12  #include <boost/asio.hpp>
 13  #include <boost/log/trivial.hpp>
 14  #include <boost/version.hpp>
 15  #include "capability_managment.hpp"
 16  #include "capsicum.hpp"
 17  #include "configuration.hpp"
 18  #include "crazytrace.hpp"
 19  #include "landlock.hpp"
 20  #include "nodecontainer.hpp"
 21  #include "posix_wrapper.hpp"
 22  #include "seccomp.hpp"
 23  #include <tuntap++.hh>
 24  
 25  int main(int argc, char * argv[]) // NOLINT(bugprone-exception-escape)
 26  {
 27      try
 28      {
 29  #ifdef HAVE_LIBCAPNG
 30          CapabilityManagment::check_for_capabilites();
 31          CapabilityManagment::lock();
 32          CapabilityManagment::drop_capabilies();
 33  #endif
 34  #ifdef HAVE_LANDLOCK
 35          const LandlockRuleset landlock_ruleset_init(
 36              LANDLOCK_ACCESS_FS_READ_DIR | LANDLOCK_ACCESS_FS_REMOVE_DIR |
 37                  LANDLOCK_ACCESS_FS_REMOVE_FILE | LANDLOCK_ACCESS_FS_MAKE_CHAR |
 38                  LANDLOCK_ACCESS_FS_MAKE_DIR | LANDLOCK_ACCESS_FS_MAKE_REG |
 39                  LANDLOCK_ACCESS_FS_MAKE_SOCK | LANDLOCK_ACCESS_FS_MAKE_FIFO |
 40                  LANDLOCK_ACCESS_FS_MAKE_BLOCK | LANDLOCK_ACCESS_FS_MAKE_SYM |
 41                  LANDLOCK_ACCESS_FS_REFER,
 42              LANDLOCK_ACCESS_NET_BIND_TCP | LANDLOCK_ACCESS_NET_CONNECT_TCP,
 43              LANDLOCK_SCOPE_ABSTRACT_UNIX_SOCKET);
 44      #ifdef HAVE_LANDLOCK_RESTRICT_SELF_LOG_NEW_EXEC_ON
 45          landlock_ruleset_init.restrict_self(
 46              LANDLOCK_RESTRICT_SELF_LOG_NEW_EXEC_ON);
 47      #else
 48          landlock_ruleset_init.restrict_self();
 49      #endif
 50  #endif
 51  
 52  #ifdef HAVE_SECCOMP
 53          SeccompFilterContext seccomp_context(SCMP_ACT_ALLOW);
 54          // see also
 55          // https://lists.boost.org/archives/list/boost-users@lists.boost.org/thread/YJ5RTK25HLPFEZ3XVBBFQDJOSPIIOBNA/
 56          // and https://sourceforge.net/p/asio/mailman/message/59260797/
 57          // due to complexity use seccomp blacklist
 58          seccomp_context.kill_chown();
 59          seccomp_context.kill_clock();
 60          seccomp_context.kill_cpu_emulation();
 61          seccomp_context.kill_debug();
 62          seccomp_context.kill_others();
 63          seccomp_context.kill_ipc();
 64          seccomp_context.kill_keyring();
 65          seccomp_context.kill_memlock();
 66          seccomp_context.kill_module();
 67          seccomp_context.kill_obsolete();
 68          seccomp_context.kill_privileged();
 69          seccomp_context.kill_rawio();
 70          seccomp_context.kill_reboot();
 71          seccomp_context.kill_resources();
 72      #ifndef HAVE_SETUGID
 73          seccomp_context.kill_setuid();
 74      #endif
 75          seccomp_context.kill_swap();
 76          seccomp_context.kill_sync();
 77          seccomp_context.kill_system_service();
 78          seccomp_context.load();
 79  #endif
 80  
 81          const auto args = std::span(argv, static_cast<std::size_t>(argc));
 82          if (args.size() != 2)
 83              throw std::runtime_error("A configuration file must be specified.");
 84  
 85          const std::string filename(args.at(1));
 86          const crazytrace::Configuration config(filename);
 87          config.get_log_level().apply();
 88  
 89          BOOST_LOG_TRIVIAL(info)
 90              << "libtuntap version (compile time): " << TUNTAP_VERSION_MAJOR
 91              << "." << TUNTAP_VERSION_MINOR;
 92          const int version = ::tuntap_version();
 93          const int major = (version >> 8) & 0xFF;
 94          const int minor = version & 0xFF;
 95          BOOST_LOG_TRIVIAL(info)
 96              << "libtuntap version (runtime): " << major << "." << minor;
 97  
 98  #if defined(TINS_VERSION_MAJOR) && defined(TINS_VERSION_MINOR) && \
 99      defined(TINS_VERSION_PATCH)
100          BOOST_LOG_TRIVIAL(info)
101              << "libtins version (compile time): " << TINS_VERSION_MAJOR << "."
102              << TINS_VERSION_MINOR << "." << TINS_VERSION_PATCH;
103  #endif
104  
105          BOOST_LOG_TRIVIAL(info)
106              << "Boost version (compile time): " << (BOOST_VERSION / 100'000)
107              << "." << (BOOST_VERSION / 100 % 1000) << "."
108              << (BOOST_VERSION % 100);
109  
110  #ifdef HAVE_LIBCAPNG
111          BOOST_LOG_TRIVIAL(info) << "libcapng: true";
112  #else
113          BOOST_LOG_TRIVIAL(info) << "libcapng: false";
114  #endif
115  
116  #ifdef HAVE_SECCOMP
117          BOOST_LOG_TRIVIAL(info) << "seccomp: true";
118          const auto * seccomp_ver = seccomp_version();
119          BOOST_LOG_TRIVIAL(info)
120              << "seccomp version (runtime): " << seccomp_ver->major << "."
121              << seccomp_ver->minor << "." << seccomp_ver->micro;
122  #else
123          BOOST_LOG_TRIVIAL(info) << "seccomp: false";
124  #endif
125  
126  #ifdef HAVE_LANDLOCK
127          BOOST_LOG_TRIVIAL(info) << "Landlock: true";
128          BOOST_LOG_TRIVIAL(info)
129              << "Landlock ABI version: " << LandlockRuleset::get_abi_version();
130  #else
131          BOOST_LOG_TRIVIAL(info) << "Landlock: false";
132  #endif
133  
134  #ifdef HAVE_CAPSICUM
135          BOOST_LOG_TRIVIAL(info) << "capsicum: true";
136  #else
137          BOOST_LOG_TRIVIAL(info) << "capsicum: false";
138  #endif
139  
140  #ifdef HAVE_SETUGID
141          BOOST_LOG_TRIVIAL(info) << "setugid: true";
142  #else
143          BOOST_LOG_TRIVIAL(info) << "setugid: false";
144  #endif
145  
146          const std::shared_ptr<crazytrace::NodeContainer> nodecontainer =
147              config.get_node_container();
148  
149          std::ostringstream nodes_verbose;
150          nodecontainer->print(nodes_verbose);
151          BOOST_LOG_TRIVIAL(info) << nodes_verbose.str();
152  
153          constexpr std::size_t mtu = 1500;
154          BOOST_LOG_TRIVIAL(debug) << "Create TUN device.";
155          tuntap::tuntap dev(TUNTAP_MODE_ETHERNET);
156          dev.name(config.get_device_name());
157          BOOST_LOG_TRIVIAL(debug) << "Set MTU to " << mtu << ".";
158          dev.mtu(mtu);
159          BOOST_LOG_TRIVIAL(debug) << "Set the TUN device up.";
160          dev.up();
161  
162          const int tap_dev_fd = PosixWrapper::dup(dev.native_handle());
163  
164          boost::asio::io_context io;
165  #ifdef BOOST_PROCESS_V1
166          config.get_postup_commands().execute_commands();
167  #else
168          config.get_postup_commands().execute_commands(io.get_executor());
169  #endif
170  
171  #ifdef HAVE_SETUGID
172          if (config.has_setugid())
173          {
174              const std::string& username = config.get_user();
175              const auto uid = PosixWrapper::username_to_uid(username);
176              PosixWrapper::set_uid(uid);
177              BOOST_LOG_TRIVIAL(info)
178                  << "setuid: " << username << " (" << uid << ")";
179  
180              const std::string& groupname = config.get_group();
181              const auto gid = PosixWrapper::groupname_to_gid(groupname);
182              PosixWrapper::set_gid(gid);
183              BOOST_LOG_TRIVIAL(info)
184                  << "setgid: " << groupname << " (" << gid << ")";
185          }
186  #endif
187  #ifdef HAVE_LIBCAPNG
188          CapabilityManagment::drop_all_capabilies();
189  #endif
190  #ifdef HAVE_LANDLOCK
191          const LandlockRuleset landlock_ruleset_loop(
192              LANDLOCK_ACCESS_FS_EXECUTE | LANDLOCK_ACCESS_FS_WRITE_FILE |
193                  LANDLOCK_ACCESS_FS_READ_FILE | LANDLOCK_ACCESS_FS_TRUNCATE |
194                  LANDLOCK_ACCESS_FS_READ_DIR | LANDLOCK_ACCESS_FS_REMOVE_DIR |
195                  LANDLOCK_ACCESS_FS_REMOVE_FILE | LANDLOCK_ACCESS_FS_MAKE_CHAR |
196                  LANDLOCK_ACCESS_FS_MAKE_DIR | LANDLOCK_ACCESS_FS_MAKE_REG |
197                  LANDLOCK_ACCESS_FS_MAKE_SOCK | LANDLOCK_ACCESS_FS_MAKE_FIFO |
198                  LANDLOCK_ACCESS_FS_MAKE_BLOCK | LANDLOCK_ACCESS_FS_MAKE_SYM |
199                  LANDLOCK_ACCESS_FS_REFER | LANDLOCK_ACCESS_FS_IOCTL_DEV,
200              LANDLOCK_ACCESS_NET_BIND_TCP | LANDLOCK_ACCESS_NET_CONNECT_TCP,
201              LANDLOCK_SCOPE_ABSTRACT_UNIX_SOCKET | LANDLOCK_SCOPE_SIGNAL);
202          // see also
203          // https://lore.kernel.org/landlock/20251119212707.71275873@ciel/T/
204      #ifdef HAVE_LANDLOCK_RESTRICT_SELF_LOG_NEW_EXEC_ON
205          landlock_ruleset_init.restrict_self(
206              LANDLOCK_RESTRICT_SELF_LOG_NEW_EXEC_ON);
207      #else
208          landlock_ruleset_init.restrict_self();
209      #endif
210  #endif
211  #ifdef HAVE_SECCOMP
212          seccomp_context.kill_signal();
213          seccomp_context.load();
214          seccomp_context.release();
215  #endif
216  #ifdef HAVE_CAPSICUM
217          Capsicum::enter();
218          Capsicum::limit_stdio();
219          Capsicum::limit_rights(dev.native_handle(),
220                                 CAP_EVENT,
221                                 CAP_FCNTL,
222                                 CAP_IOCTL,
223                                 CAP_READ,
224                                 CAP_WRITE);
225          Capsicum::limit_fcntls(dev.native_handle(),
226                                 CAP_FCNTL_GETFL | CAP_FCNTL_SETFL);
227          Capsicum::limit_ioctls(dev.native_handle(),
228                                 {FIONBIO, FIONREAD, SIOCATMARK});
229  
230          if (Capsicum::in_capability_mode())
231          {
232              BOOST_LOG_TRIVIAL(info) << "capsicum capabiliy mode: true";
233          }
234          else
235          {
236              BOOST_LOG_TRIVIAL(info) << "capsicum capabiliy mode: false";
237          }
238  #endif
239  
240          const crazytrace::Crazytrace ct(
241              io.get_executor(), tap_dev_fd, nodecontainer);
242  
243          io.run();
244      }
245      catch (const std::exception& e)
246      {
247          BOOST_LOG_TRIVIAL(fatal) << "Error: " << e.what() << std::endl
248                                   << "Exit program.";
249          std::exit(EXIT_FAILURE); // NOLINT(concurrency-mt-unsafe)
250      }
251      catch (...)
252      {
253          BOOST_LOG_TRIVIAL(fatal) << "Unknown error caught." << std::endl
254                                   << "Exit program.";
255          std::exit(EXIT_FAILURE); // NOLINT(concurrency-mt-unsafe)
256      }
257      return EXIT_SUCCESS;
258  }