Skip to content

Commit

Permalink
Complete ipv6 support (#1204)
Browse files Browse the repository at this point in the history
* Add new ipv6 types

Add a new ipv6addr struct which contains the 16 bytes of the ip address
as 4 uint32_ts. It also has methods for comparisons and subnet checks.

Also add new PPM types PT_IPV6ADDR/PT_IPV6NET as well as a general
PT_IPADDR/PT_IPNET type. The general types will be used for things like
filterchecks where they operate interchangeably on ipv4/ipv6 addresses.

* Add ipv6 address support to sinsp interfaces

Fully support ipv6 addresses in sinsp_network_interfaces. When storing
an ipv6 interface, use the new explicit type ipv6addr instead of 16-byte
arrays. Also only save the network portion in a single ipv6 address.

Add methods import_ipv6_interface, is_ipv6addr_in_local_machine,
infer_ipv6_address, which are used by update_fd to update sinsp_fdinfo
structs based on interface information.

* Handle ipv6 addrs in comparisons/string conversion

Handle PT_IPV6ADDR as a type in string conversions to/from rawvals, both
directly and into the lua stack. Generally it's just inet_pton/inet_ntop
on the bytes in the ipv6addr struct.

Also handle comparisons on PT_IPV6ADDR/PT_IPV6NET, using the equality
and netmast comparison operators on the struct.

To handle conversion/comparisons for PT_IPADDR/PT_IPNET, use the size of
the rawval to determine if it's an ipv4 or ipv6 address and call
comparison/converson method again with PT_IPV6ADDR/PT_IPV4ADDR as
appropriate. For strings, infer the type based on whether the string has
'.' or ':' characters.

This required a change to the methods to take the param
type/format instead of a filtercheck_field_info, as there are other uses
that don't have a filtercheck_field_info.

* Handle ipv6 addresses in csysdig

In get_thread_table_int, support SCAP_FD_IPV6 types, grabbing the right
part of the sockinfo struct and doing the right conversion for the
address family.

Add a default column width for ipv6 addresses.

* Support ipv6 addrs in fd.{*ip*,*net*} filterchecks

Change all fd.ip/fd.net filterchecks to work on PT_IPADDR types
instead. When extracting, add tests for SCAP_FD_IPV6_* types and extract
the right part of the sockinfo struct.

Comparisons/conversion is already handled by the rawval_to_string
changes that handle PT_IPADDR/PT_IPNET types.

* Handle event parsing for ipv6 addresses

Instead of simply handling ipv4 mapped ipv6 addresses, handle any ipv6
address, filling in the right part of the sockinfo struct from the event
parameter.

Also handle source/dest swapping when determining the client/server
endpoints of a connection.

Conversions that used to work simply on an ipv6 address as byte array
now work on the m_b field of the ipv6addr struct.

* Change typechar for server sockets to 4/6

The documentation of fd.typechar doesn't distinguish between server
sockets and non-server sockets, so simplify things by simply using
'4'/'6' to reflect the ipv4/ipv6 type.

* Update chisels to support ipv6

In cases where a chisel's filter was specific to ipv4, also allow ipv6.

* Don't return local strings from proto filterchecks

These were returning pointers to local string values on the
stack. Replace with m_tstr, a general purpose string in the object,
instead.
  • Loading branch information
mstemm authored Sep 5, 2018
1 parent b39d7e1 commit f079a9c
Show file tree
Hide file tree
Showing 27 changed files with 1,014 additions and 332 deletions.
6 changes: 5 additions & 1 deletion driver/ppm_events_public.h
Original file line number Diff line number Diff line change
Expand Up @@ -1276,7 +1276,11 @@ enum ppm_param_type {
PT_CHARBUFARRAY = 35, /* Pointer to an array of strings, exported by the user events decoder. 64bit. For internal use only. */
PT_CHARBUF_PAIR_ARRAY = 36, /* Pointer to an array of string pairs, exported by the user events decoder. 64bit. For internal use only. */
PT_IPV4NET = 37, /* An IPv4 network. */
PT_MAX = 38 /* array size */
PT_IPV6ADDR = 38, /* A 16 byte raw IPv6 address. */
PT_IPV6NET = 39, /* An IPv6 network. */
PT_IPADDR = 40, /* Either an IPv4 or IPv6 address. The length indicates which one it is. */
PT_IPNET = 41, /* Either an IPv4 or IPv6 network. The length indicates which one it is. */
PT_MAX = 42 /* array size */
};

enum ppm_print_format {
Expand Down
1 change: 1 addition & 0 deletions userspace/libsinsp/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,7 @@ add_library(sinsp STATIC
prefix_search.cpp
protodecoder.cpp
threadinfo.cpp
tuples.cpp
sinsp.cpp
stats.cpp
table.cpp
Expand Down
185 changes: 119 additions & 66 deletions userspace/libsinsp/chisel_api.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -62,12 +62,11 @@ void lua_stackdump(lua_State *L);
///////////////////////////////////////////////////////////////////////////////
#ifdef HAS_LUA_CHISELS

uint32_t lua_cbacks::rawval_to_lua_stack(lua_State *ls, uint8_t* rawval, const filtercheck_field_info* finfo, uint32_t len)
uint32_t lua_cbacks::rawval_to_lua_stack(lua_State *ls, uint8_t* rawval, ppm_param_type ptype, uint32_t len)
{
ASSERT(rawval != NULL);
ASSERT(finfo != NULL);

switch(finfo->m_type)
switch(ptype)
{
case PT_INT8:
lua_pushnumber(ls, *(int8_t*)rawval);
Expand Down Expand Up @@ -158,9 +157,46 @@ uint32_t lua_cbacks::rawval_to_lua_stack(lua_State *ls, uint8_t* rawval, const f
lua_pushstring(ls, ch->m_lua_fld_storage);
return 1;
}
case PT_IPV6ADDR:
{
char address[100];
ipv6addr *ip = (ipv6addr *) rawval;

lua_getglobal(ls, "sichisel");
sinsp_chisel* ch = (sinsp_chisel*)lua_touserdata(ls, -1);
lua_pop(ls, 1);

if(NULL == inet_ntop(AF_INET6, ip->m_b, address, 100))
{
strcpy(address, "<NA>");
}

strncpy(ch->m_lua_fld_storage,
address,
sizeof(ch->m_lua_fld_storage));

lua_pushstring(ls, ch->m_lua_fld_storage);
return 1;
}
case PT_IPADDR:
{
if(len == sizeof(struct in_addr))
{
return rawval_to_lua_stack(ls, rawval, PT_IPV4ADDR, len);
}
else if(len == sizeof(struct in6_addr))
{
return rawval_to_lua_stack(ls, rawval, PT_IPV6ADDR, len);
}
else
{
throw sinsp_exception("rawval_to_lua_stack called with IP address of incorrect size " + to_string(len));
}
}
break;
default:
ASSERT(false);
string err = "wrong event type " + to_string((long long) finfo->m_type);
string err = "wrong event type " + to_string((long long) ptype);
fprintf(stderr, "%s\n", err.c_str());
throw sinsp_exception("chisel error");
}
Expand Down Expand Up @@ -323,7 +359,7 @@ int lua_cbacks::field(lua_State *ls)

if(rawval != NULL)
{
return rawval_to_lua_stack(ls, rawval, chk->get_field_info(), vlen);
return rawval_to_lua_stack(ls, rawval, chk->get_field_info()->m_type, vlen);
}
else
{
Expand Down Expand Up @@ -671,7 +707,6 @@ int lua_cbacks::get_thread_table_int(lua_State *ls, bool include_fds, bool bareb
sinsp_filter* filter = NULL;
sinsp_evt tevt;
scap_evt tscapevt;
char ipbuf[128];

//
// Get the chisel state
Expand Down Expand Up @@ -916,81 +951,99 @@ int lua_cbacks::get_thread_table_int(lua_State *ls, bool include_fds, bool bareb
}

scap_fd_type evt_type = fdit->second.m_type;
if(evt_type == SCAP_FD_IPV4_SOCK || evt_type == SCAP_FD_IPV4_SERVSOCK)
if(evt_type == SCAP_FD_IPV4_SOCK || evt_type == SCAP_FD_IPV4_SERVSOCK ||
evt_type == SCAP_FD_IPV6_SOCK || evt_type == SCAP_FD_IPV6_SERVSOCK)
{
uint8_t* pip4;
bool include_client;
char sipbuf[128], cipbuf[128];
uint8_t *sip, *cip;
uint16_t sport, cport;
bool is_server;
int af;

if(evt_type == SCAP_FD_IPV4_SOCK)
{
// cip
pip4 = (uint8_t*)&(fdit->second.m_sockinfo.m_ipv4info.m_fields.m_sip);
snprintf(ipbuf,
sizeof(ipbuf),
"%" PRIu8 ".%" PRIu8 ".%" PRIu8 ".%" PRIu8,
pip4[0],
pip4[1],
pip4[2],
pip4[3]);
include_client = true;
af = AF_INET;
cip = (uint8_t*)&(fdit->second.m_sockinfo.m_ipv4info.m_fields.m_sip);
sip = (uint8_t*)&(fdit->second.m_sockinfo.m_ipv4info.m_fields.m_dip);
cport = fdit->second.m_sockinfo.m_ipv4info.m_fields.m_sport;
sport = fdit->second.m_sockinfo.m_ipv4info.m_fields.m_dport;
is_server = fdit->second.is_role_server();
}
else if (evt_type == SCAP_FD_IPV4_SERVSOCK)
{
include_client = false;
af = AF_INET;
cip = NULL;
sip = (uint8_t*)&(fdit->second.m_sockinfo.m_ipv4serverinfo.m_ip);
sport = fdit->second.m_sockinfo.m_ipv4serverinfo.m_port;
is_server = true;
}
else if (evt_type == SCAP_FD_IPV6_SOCK)
{
include_client = true;
af = AF_INET6;
cip = (uint8_t*)&(fdit->second.m_sockinfo.m_ipv6info.m_fields.m_sip);
sip = (uint8_t*)&(fdit->second.m_sockinfo.m_ipv6info.m_fields.m_dip);
cport = fdit->second.m_sockinfo.m_ipv6info.m_fields.m_sport;
sport = fdit->second.m_sockinfo.m_ipv6info.m_fields.m_dport;
is_server = fdit->second.is_role_server();
}
else
{
include_client = false;
af = AF_INET6;
cip = NULL;
sip = (uint8_t*)&(fdit->second.m_sockinfo.m_ipv6serverinfo.m_ip);
sport = fdit->second.m_sockinfo.m_ipv6serverinfo.m_port;
is_server = true;
}

lua_pushliteral(ls, "cip");
lua_pushstring(ls, ipbuf);
lua_settable(ls, -3);
// Now convert the raw sip/cip to strings
if(NULL == inet_ntop(af, sip, sipbuf, sizeof(sipbuf)))
{
strcpy(sipbuf, "<NA>");
}

// sip
pip4 = (uint8_t*)&(fdit->second.m_sockinfo.m_ipv4info.m_fields.m_dip);
snprintf(ipbuf,
sizeof(ipbuf),
"%" PRIu8 ".%" PRIu8 ".%" PRIu8 ".%" PRIu8,
pip4[0],
pip4[1],
pip4[2],
pip4[3]);
if(cip)
{
if(NULL == inet_ntop(af, cip, cipbuf, sizeof(cipbuf)))
{
strcpy(cipbuf, "<NA>");
}
}

lua_pushliteral(ls, "sip");
lua_pushstring(ls, ipbuf);
if(include_client)
{
// cip
lua_pushliteral(ls, "cip");
lua_pushstring(ls, cipbuf);
lua_settable(ls, -3);
}

// sip
lua_pushliteral(ls, "sip");
lua_pushstring(ls, sipbuf);
lua_settable(ls, -3);

if(include_client)
{
// cport
lua_pushliteral(ls, "cport");
lua_pushnumber(ls, fdit->second.m_sockinfo.m_ipv4info.m_fields.m_sport);
lua_settable(ls, -3);

// sport
lua_pushliteral(ls, "sport");
lua_pushnumber(ls, fdit->second.m_sockinfo.m_ipv4info.m_fields.m_dport);
lua_settable(ls, -3);

// is_server
lua_pushliteral(ls, "is_server");
lua_pushboolean(ls, fdit->second.is_role_server());
lua_pushnumber(ls, cport);
lua_settable(ls, -3);
}
else
{
// sip
pip4 = (uint8_t*)&(fdit->second.m_sockinfo.m_ipv4serverinfo.m_ip);
snprintf(ipbuf,
sizeof(ipbuf),
"%" PRIu8 ".%" PRIu8 ".%" PRIu8 ".%" PRIu8,
pip4[0],
pip4[1],
pip4[2],
pip4[3]);

lua_pushliteral(ls, "sip");
lua_pushstring(ls, ipbuf);
lua_settable(ls, -3);

// sport
lua_pushliteral(ls, "sport");
lua_pushnumber(ls, fdit->second.m_sockinfo.m_ipv4serverinfo.m_port);
lua_settable(ls, -3);
// sport
lua_pushliteral(ls, "sport");
lua_pushnumber(ls, sport);
lua_settable(ls, -3);

// is_server
lua_pushliteral(ls, "is_server");
lua_pushboolean(ls, 1);
lua_settable(ls, -3);
}
// is_server
lua_pushliteral(ls, "is_server");
lua_pushboolean(ls, is_server);
lua_settable(ls, -3);

// l4proto
const char* l4ps;
Expand Down
2 changes: 1 addition & 1 deletion userspace/libsinsp/chisel_api.h
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ along with sysdig. If not, see <http://www.gnu.org/licenses/>.
class lua_cbacks
{
public:
static uint32_t rawval_to_lua_stack(lua_State *ls, uint8_t* rawval, const filtercheck_field_info* finfo, uint32_t len);
static uint32_t rawval_to_lua_stack(lua_State *ls, uint8_t* rawval, ppm_param_type ptype, uint32_t len);

static int get_num(lua_State *ls);
static int get_ts(lua_State *ls);
Expand Down
1 change: 1 addition & 0 deletions userspace/libsinsp/cursestable.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,7 @@ curses_table::curses_table(sinsp_cursesui* parent, sinsp* inspector, sinsp_table
m_colsizes[PT_SOCKFAMILY] = 8;
m_colsizes[PT_BOOL] = 8;
m_colsizes[PT_IPV4ADDR] = 8;
m_colsizes[PT_IPV6ADDR] = 16;
m_colsizes[PT_DYN] = 8;
m_colsizes[PT_FLAGS8] = 32;
m_colsizes[PT_FLAGS16] = 32;
Expand Down
22 changes: 22 additions & 0 deletions userspace/libsinsp/event.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1700,6 +1700,28 @@ const char* sinsp_evt::get_param_as_str(uint32_t id, OUT const char** resolved_s
"INVALID IPv4");
}
}
else if(payload[0] == PPM_AF_INET6)
{
if(payload_len == 1 + 16 + 2)
{
ipv6serverinfo addr;
memcpy((uint8_t *) addr.m_ip.m_b, (uint8_t *) payload+1, sizeof(addr.m_ip.m_b));
addr.m_port = *(uint16_t*)(payload+17);
addr.m_l4proto = (m_fdinfo != NULL) ? m_fdinfo->get_l4proto() : SCAP_L4_UNKNOWN;
string straddr = ipv6serveraddr_to_string(&addr, m_inspector->m_hostname_and_port_resolution_enabled);
snprintf(&m_paramstr_storage[0],
m_paramstr_storage.size(),
"%s",
straddr.c_str());
}
else
{
ASSERT(false);
snprintf(&m_paramstr_storage[0],
m_paramstr_storage.size(),
"INVALID IPv6");
}
}
else
{
snprintf(&m_paramstr_storage[0],
Expand Down
4 changes: 2 additions & 2 deletions userspace/libsinsp/fdinfo.h
Original file line number Diff line number Diff line change
Expand Up @@ -31,8 +31,8 @@ class sinsp_protodecoder;
#define CHAR_FD_IPV4_SOCK '4'
#define CHAR_FD_IPV6_SOCK '6'
#define CHAR_FD_DIRECTORY 'd'
#define CHAR_FD_IPV4_SERVSOCK '2'
#define CHAR_FD_IPV6_SERVSOCK '3'
#define CHAR_FD_IPV4_SERVSOCK '4'
#define CHAR_FD_IPV6_SERVSOCK '6'
#define CHAR_FD_FIFO 'p'
#define CHAR_FD_UNIX_SOCK 'u'
#define CHAR_FD_EVENT 'e'
Expand Down
Loading

0 comments on commit f079a9c

Please sign in to comment.