11#include <glibmm/main.h>
12#include <nlohmann/json.hpp>
16#include <condition_variable>
23#include <sys/socket.h>
29namespace fs = std::filesystem;
30using json = nlohmann::json;
37 info.
app_path = j.value(
"process_path", std::string{});
38 info.
app_comm = j.value(
"process_comm", std::string{});
39 info.
app_cwd = j.value(
"process_cwd", std::string{});
40 info.
pid = j.value(
"process_id", std::uint32_t{0});
41 info.
uid = j.value(
"user_id", std::uint32_t{0});
42 if (j.contains(
"process_args") && j[
"process_args"].is_array()) {
43 for (
const auto& a : j[
"process_args"]) info.
app_args.push_back(a.get<std::string>());
45 info.
protocol = j.value(
"protocol", std::string{});
46 info.
src_ip = j.value(
"src_ip", std::string{});
47 info.
src_port = j.value(
"src_port", std::uint32_t{0});
48 info.
dest_host = j.value(
"dst_host", std::string{});
49 info.
dest_ip = j.value(
"dst_ip", std::string{});
50 info.
dest_port = j.value(
"dst_port", std::uint32_t{0});
103 bool start(
const std::string& socketPath) {
104 if (
running_.exchange(
true))
return false;
109 if (p.has_parent_path()) fs::create_directories(p.parent_path());
110 if (fs::exists(p)) fs::remove(p);
111 }
catch (
const std::exception& e) {
112 std::cerr <<
"[UIServer] prep socket: " << e.what() <<
"\n";
115 listen_fd_ = ::socket(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC, 0);
119 addr.sun_family = AF_UNIX;
125 if (::bind(
listen_fd_,
reinterpret_cast<sockaddr*
>(&addr),
sizeof(addr)) < 0) {
126 std::cerr <<
"[UIServer] bind fallita: " << std::strerror(errno) <<
"\n";
138 std::cout <<
"[UIServer] in ascolto su " <<
socket_file_ <<
"\n";
145 if (!
running_.exchange(
false))
return;
149 if (lfd >= 0) { ::shutdown(lfd, SHUT_RDWR); ::close(lfd); }
151 if (cfd >= 0) { ::shutdown(cfd, SHUT_RDWR); ::close(cfd); }
170 int fd = ::accept4(
listen_fd_,
nullptr,
nullptr, SOCK_CLOEXEC);
172 if (errno == EINTR)
continue;
174 std::cerr <<
"[UIServer] accept fallita: " << std::strerror(errno) <<
"\n";
175 std::this_thread::sleep_for(std::chrono::milliseconds(200));
181 if (old >= 0) { ::shutdown(old, SHUT_RDWR); ::close(old); }
193 ssize_t r = ::recv(fd, buf + got, n - got, 0);
194 if (r == 0)
return false;
195 if (r < 0) {
if (errno == EINTR)
continue;
return false; }
196 got +=
static_cast<std::size_t
>(r);
206 bool announced =
false;
209 std::uint8_t lenbuf[4];
213 std::vector<std::uint8_t> payload(
static_cast<std::size_t
>(len));
214 if (!
read_exact(fd, payload.data(), payload.size()))
break;
217 json j = json::parse(payload.begin(), payload.end());
218 const std::string type = j.value(
"type", std::string{});
246 const auto id = j.value(
"id", std::uint64_t{0});
262 const bool got =
reply_cv_.wait_for(lk, std::chrono::seconds(20),
284 ai.
id = j.value(
"id", std::uint64_t{0});
285 const std::string level = j.value(
"level", std::string{
"info"});
286 ai.
type = level ==
"error" ? 0
287 : level ==
"warning" ? 1
289 const std::string what = j.value(
"what", std::string{
"generic"});
290 ai.
what = what ==
"firewall" ? 2
291 : what ==
"connection" ? 3
295 ai.
text = j.value(
"text", std::string{});
296 if (j.contains(
"connection")) {
300 if (j.contains(
"rule")) {
301 ai.
rule_name = j[
"rule"].value(
"name", std::string{});
315 }
catch (
const std::exception& e) {
316 std::cerr <<
"[UIServer] JSON parse error: " << e.what() <<
"\n";
323 client_fd_.compare_exchange_strong(expected, -1);
339 if (fd < 0)
return false;
340 std::vector<std::uint8_t> frame;
343 std::size_t total = 0;
344 while (total < frame.size()) {
345 ssize_t n = ::send(fd, frame.data() + total, frame.size() - total, MSG_NOSIGNAL);
346 if (n < 0) {
if (errno == EINTR)
continue;
return false; }
347 total +=
static_cast<std::size_t
>(n);
358 for (
const auto& j : q) {
381 static const char* kinds[] = {
382 "none",
"enable_interception",
"disable_interception",
383 "enable_firewall",
"disable_firewall",
"reload_fw_rules",
384 "change_config",
"enable_rule",
"disable_rule",
"delete_rule",
385 "change_rule",
"log_level",
"stop",
"task_start",
"task_stop",
386 "desktop_active",
"desktop_idle"
388 const std::string kind = (type >= 0 && type < 17) ? kinds[type] :
"none";
424 impl_->queue_notification(type, data);
static std::string display_app_name(const ConnectionInfo &info)
static ConnectionInfo connection_info_from_json(const json &j)
std::thread accept_thread_
void dispatch_disconnected()
void dispatch_new_connection(const ConnectionInfo &info)
void send_reply(ReplyAction action)
ReplyAction reply_action_
void queue_notification(int type, const std::string &data)
void dispatch_connected()
std::atomic_uint64_t next_id_
std::deque< json > pending_notifs_
void flush_pending_notifs()
std::condition_variable reply_cv_
void dispatch_alert(const AlertInfo &a)
std::atomic_bool running_
void client_session(int fd)
std::thread reader_thread_
bool read_exact(int fd, std::uint8_t *buf, std::size_t n)
std::atomic_int client_fd_
std::uint64_t current_ask_id_
bool start(const std::string &socketPath)
bool send_frame(const std::string &payload)
sigc::signal< void(const ConnectionInfo &)> signal_new_connection
sigc::signal< void()> signal_daemon_disconnected
void sendReply(ReplyAction action)
void queueNotification(int type, const std::string &data={})
sigc::signal< void(const AlertInfo &)> signal_alert
sigc::signal< void()> signal_daemon_connected
std::unique_ptr< Impl > impl_
void start(const std::string &socketPath="unix:///tmp/bsd-daemon.sock")
constexpr std::string_view kHello
constexpr std::string_view kAskRuleReply
constexpr std::string_view kPing
constexpr std::string_view kAskRule
constexpr std::string_view kPong
constexpr std::string_view kNotification
constexpr std::string_view kAlert
std::string resolve_socket_path(std::string uri)
constexpr std::size_t kMaxFrameSize
std::int64_t frame_peek_length(const std::uint8_t *buf, std::size_t len)
void frame_encode(std::string_view payload, std::vector< std::uint8_t > &out)
std::string best_connection_display_name(const std::string &app_comm, const std::string &app_path, const std::vector< std::string > &app_args, const std::string &dst_ip, const std::string &src_ip)
ConnectionInfo connection
std::vector< std::string > app_args