rublon-ssh/PAM/ssh/include/rublon/ip_utils.hpp
rublon-bwi 351964199a
Bwi/v2.3.2 (#19)
* Prevent printing in noninteractive mode

* Allow PAM modules to be configurated directly in pam.d

* Configuration should be redable by everybody

* Add a way to read ip address in when no IP is awailable

* Enable read ip from pam

* Fix veritas BUG
2025-09-11 10:35:22 +02:00

97 lines
2.8 KiB
C++

#pragma once
#include "rublon/utils.hpp"
#include <memory_resource>
#include <rublon/error.hpp>
#include <rublon/memory.hpp>
#include <string>
#include <tl/expected.hpp>
#include <arpa/inet.h>
#include <netinet/in.h>
#include <unistd.h>
#include <utility>
namespace rublon {
using socket_t = int;
constexpr socket_t invalid_socket = -1;
class unique_fd {
socket_t fd_ = invalid_socket;
public:
unique_fd() = default;
explicit unique_fd(socket_t fd) : fd_(fd) {}
~unique_fd() {
close(fd_);
}
unique_fd(const unique_fd &) = delete;
unique_fd & operator=(const unique_fd &) = delete;
unique_fd(unique_fd && other) noexcept : fd_(std::exchange(other.fd_, invalid_socket)) {}
unique_fd & operator=(unique_fd && other) noexcept {
if(this != &other) {
close(fd_);
fd_ = std::exchange(other.fd_, invalid_socket);
}
return *this;
}
socket_t get() const noexcept {
return fd_;
}
socket_t release() noexcept {
return std::exchange(fd_, invalid_socket);
}
void reset(socket_t fd = invalid_socket) noexcept {
if(fd_ != fd) {
close(fd_);
fd_ = fd;
}
}
explicit operator bool() const noexcept {
return fd_ != invalid_socket;
}
};
// this function is a little hack just to fix RSUP-1413
// When loging to rublon from withing the host itself, there is no IP delivered through any 'pam_item'
// but we need to log from what place the request did came.
tl::expected< std::pmr::string, Error > getDefaultRouteIp(std::pmr::memory_resource * mr) {
log(LogLevel::Debug, "Reading default route IP");
unique_fd sock(::socket(AF_INET, SOCK_DGRAM, 0));
if(!sock){
log(LogLevel::Warning, "Cant create socket");
return tl::unexpected{Error{RublonRuntimeException::CantCreateSocket}};
}
sockaddr_in remote{};
remote.sin_family = AF_INET;
remote.sin_port = htons(53);
::inet_pton(AF_INET, "8.8.8.8", &remote.sin_addr);
// we use UDP so no actual connection is estamblished. Only trying to get an interface
if(::connect(sock.get(), ( struct sockaddr * ) &remote, sizeof(remote)) < 0) {
log(LogLevel::Warning, "Cant connect to socket");
return tl::unexpected{Error{RublonRuntimeException::ConnectionFailed}};
}
sockaddr_in local{};
socklen_t len = sizeof(local);
if(::getsockname(sock.get(), ( struct sockaddr * ) &local, &len) < 0) {
log(LogLevel::Warning, "Cant get socket name");
return tl::unexpected{Error{RublonRuntimeException::CantGetSocketName}};
}
char ip[INET_ADDRSTRLEN];
::inet_ntop(AF_INET, &local.sin_addr, ip, sizeof(ip));
return std::pmr::string{ip, mr};
}
} // namespace rublon