//------------------------------------------------------------------------------
// Author: Pavel Karneliuk
// Description: Structs for sessions.
// Copyright (c) 2013 EPAM Systems
//------------------------------------------------------------------------------
/*
This file is part of Nfstrace.
Nfstrace is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, version 2 of the License.
Nfstrace is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Nfstrace. If not, see .
*/
//------------------------------------------------------------------------------
#include
#include // for inet_ntop(), ntohs()
#include
#include // for AF_INET/AF_INET6
#include "api/plugin_api.h" // for NST_PUBLIC
#include "utils/out.h"
#include "utils/sessions.h"
//------------------------------------------------------------------------------
namespace NST
{
namespace utils
{
std::ostream& operator<<(std::ostream& out, const ApplicationSession& session);
ApplicationSession::ApplicationSession(const NetworkSession& s, Direction from_client)
: utils::Session(s)
{
if(s.direction != from_client)
{
//TODO: implement correct swap_src_dst()
std::swap(port[0], port[1]);
switch(ip_type)
{
case Session::IPType::v4:
std::swap(ip.v4.addr[0], ip.v4.addr[1]);
break;
case Session::IPType::v6:
std::swap(ip.v6.addr[0], ip.v6.addr[1]);
break;
}
}
// TODO: print network addresses in human readable form and
// potential host name lookup may be expensive, to try to use
// std::future(async | deferred, ...) and std::promise, to perform
// this operation asynchronously
std::stringstream stream(std::ios_base::out);
stream << *this;
session_str = stream.str();
}
namespace
{
std::ostream& operator<<(std::ostream& out, const Session::Type type)
{
switch(type)
{
case Session::Type::TCP:
return out << " [TCP]";
case Session::Type::UDP:
return out << " [UDP]";
}
return out;
}
void print_ipv4_port(std::ostream& out, in_addr_t ipv4, in_port_t port)
{
static_assert(sizeof(ipv4) == sizeof(struct in_addr), "they must be equal");
char buf[INET_ADDRSTRLEN];
const char* str{inet_ntop(AF_INET, &ipv4, buf, sizeof(buf))};
out << (str ? str : "Invalid IPv4 address")
<< ':' << ntohs(port);
}
void print_ipv6_port(std::ostream& out, const uint8_t (&ipv6)[16], in_port_t port)
{
static_assert(sizeof(ipv6) == sizeof(struct in6_addr), "they must be equal");
char buf[INET6_ADDRSTRLEN];
const char* str{inet_ntop(AF_INET6, ipv6, buf, sizeof(buf))};
out << (str ? str : "Invalid IPv6 address")
<< ':' << ntohs(port);
}
// TODO: getnameinfo call may be expensive
template
void print_sockaddr(std::ostream& out, SockAddr& addr)
{
char hostname[1025];
char service[65];
const int err{getnameinfo((sockaddr*)&addr, sizeof(addr),
hostname, sizeof(hostname),
service, sizeof(service),
NI_NAMEREQD)};
if(err == 0)
{
out << '(' << hostname << ':' << service << ')';
}
}
void print_ipv4_port_as_hostname_service(std::ostream& out,
in_addr_t ipv4,
in_port_t port)
{
sockaddr_in addr;
addr.sin_family = AF_INET;
addr.sin_port = port;
addr.sin_addr.s_addr = ipv4;
print_sockaddr(out, addr);
}
void print_ipv6_port_as_hostname_service(std::ostream& out,
const uint8_t (&ipv6)[16],
in_port_t port)
{
sockaddr_in6 addr;
addr.sin6_family = AF_INET6;
addr.sin6_port = port;
addr.sin6_flowinfo = 0;
addr.sin6_addr = (in6_addr&)ipv6;
addr.sin6_scope_id = 0;
print_sockaddr(out, addr);
}
} // unnamed namespace
std::ostream& operator<<(std::ostream& out, const Session& session)
{
print_session(out, session);
return out;
}
extern "C" NST_PUBLIC void print_session(std::ostream& out, const Session& session)
{
switch(session.ip_type)
{
case Session::IPType::v4:
{
print_ipv4_port(out, session.ip.v4.addr[Session::Source],
session.port[Session::Source]);
out << " --> ";
print_ipv4_port(out, session.ip.v4.addr[Session::Destination],
session.port[Session::Destination]);
}
break;
case Session::IPType::v6:
{
print_ipv6_port(out, session.ip.v6.addr[Session::Source],
session.port[Session::Source]);
out << " --> ";
print_ipv6_port(out, session.ip.v6.addr[Session::Destination],
session.port[Session::Destination]);
}
break;
}
out << session.type;
}
std::ostream& operator<<(std::ostream& out, const ApplicationSession& session)
{
const bool namelookup{Out::Global::get_level() == Out::Level::All};
switch(session.ip_type)
{
case Session::IPType::v4:
{
{
auto& port = session.port[Session::Source];
auto& addr = session.ip.v4.addr[Session::Source];
print_ipv4_port(out, addr, port);
if(namelookup)
{
print_ipv4_port_as_hostname_service(out, addr, port);
}
}
out << " --> ";
{
auto& port = session.port[Session::Destination];
auto& addr = session.ip.v4.addr[Session::Destination];
print_ipv4_port(out, addr, port);
if(namelookup)
{
print_ipv4_port_as_hostname_service(out, addr, port);
}
}
}
break;
case Session::IPType::v6:
{
{
auto& port = session.port[Session::Source];
auto& addr = session.ip.v6.addr[Session::Source];
print_ipv6_port(out, addr, port);
if(namelookup)
{
print_ipv6_port_as_hostname_service(out, addr, port);
}
}
out << " --> ";
{
auto& port = session.port[Session::Destination];
auto& addr = session.ip.v6.addr[Session::Destination];
print_ipv6_port(out, addr, port);
if(namelookup)
{
print_ipv6_port_as_hostname_service(out, addr, port);
}
}
}
break;
}
out << session.type;
return out;
}
} // namespace utils
} // namespace NST
//------------------------------------------------------------------------------