mirror of
https://github.com/valitydev/osquery-1.git
synced 2024-11-07 18:08:53 +00:00
Adding new table to display iptables filters, chains and rules
Patching headers to avoid void pointers Adding test for parsing ipt_ip entries
This commit is contained in:
parent
3294929226
commit
4f21090fb8
@ -57,6 +57,7 @@ else()
|
||||
ADD_OSQUERY_LINK(FALSE "cryptsetup")
|
||||
ADD_OSQUERY_LINK(FALSE "udev")
|
||||
ADD_OSQUERY_LINK(FALSE "uuid")
|
||||
ADD_OSQUERY_LINK(FALSE "ip4tc")
|
||||
endif()
|
||||
|
||||
file(GLOB OSQUERY_CROSS_TABLES "[!ue]*/*.cpp")
|
||||
|
159
osquery/tables/networking/linux/iptables.cpp
Normal file
159
osquery/tables/networking/linux/iptables.cpp
Normal file
@ -0,0 +1,159 @@
|
||||
/*
|
||||
* Copyright (c) 2014, Facebook, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This source code is licensed under the BSD-style license found in the
|
||||
* LICENSE file in the root directory of this source tree. An additional grant
|
||||
* of patent rights can be found in the PATENTS file in the same directory.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <sstream>
|
||||
|
||||
#include <arpa/inet.h>
|
||||
#include <libiptc/libiptc.h>
|
||||
|
||||
#include <boost/algorithm/string/split.hpp>
|
||||
#include <boost/algorithm/string/trim.hpp>
|
||||
|
||||
#include <osquery/tables.h>
|
||||
#include <osquery/filesystem.h>
|
||||
#include <osquery/logger.h>
|
||||
|
||||
namespace osquery {
|
||||
namespace tables {
|
||||
|
||||
const std::string kLinuxIpTablesNames = "/proc/net/ip_tables_names";
|
||||
const char MAP[] = {'0','1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F'};
|
||||
const int HIGH_BITS = 4;
|
||||
const int LOW_BITS = 15;
|
||||
|
||||
void parseIpEntry(ipt_ip *ip, Row &r) {
|
||||
r["protocol"] = INTEGER(ip->proto);
|
||||
if (strlen(ip->iniface)) {
|
||||
r["iniface"] = TEXT(ip->iniface);
|
||||
} else {
|
||||
r["iniface"] = "all";
|
||||
}
|
||||
if (strlen(ip->outiface)) {
|
||||
r["outiface"] = TEXT(ip->outiface);
|
||||
} else {
|
||||
r["outiface"] = "all";
|
||||
}
|
||||
char src_ip_string[INET6_ADDRSTRLEN] = {0};
|
||||
if (inet_ntop(AF_INET, (struct in_addr *)&ip->src, src_ip_string, INET6_ADDRSTRLEN) != NULL) {
|
||||
r["src_ip"] = TEXT(src_ip_string);
|
||||
}
|
||||
char dst_ip_string[INET6_ADDRSTRLEN] = {0};
|
||||
if (inet_ntop(AF_INET, (struct in_addr *)&ip->dst, dst_ip_string, INET6_ADDRSTRLEN) != NULL) {
|
||||
r["dst_ip"] = TEXT(dst_ip_string);
|
||||
}
|
||||
char src_ip_mask[INET6_ADDRSTRLEN] = {0};
|
||||
if (inet_ntop(AF_INET, (struct in_addr *)&ip->smsk, src_ip_mask, INET6_ADDRSTRLEN) != NULL) {
|
||||
r["src_mask"] = TEXT(src_ip_mask);
|
||||
}
|
||||
char dst_ip_mask[INET6_ADDRSTRLEN] = {0};
|
||||
if (inet_ntop(AF_INET, (struct in_addr *)&ip->dmsk, dst_ip_mask, INET6_ADDRSTRLEN) != NULL) {
|
||||
r["dst_mask"] = TEXT(dst_ip_mask);
|
||||
}
|
||||
|
||||
char aux_char[2];
|
||||
std::string iniface_mask = "";
|
||||
for (int i = 0; ip->iniface_mask[i] != 0x00 && i<IFNAMSIZ; i++) {
|
||||
aux_char[0] = MAP[(int) ip->iniface_mask[i] >> HIGH_BITS];
|
||||
aux_char[1] = MAP[(int) ip->iniface_mask[i] & LOW_BITS];
|
||||
iniface_mask += aux_char[0];
|
||||
iniface_mask += aux_char[1];
|
||||
}
|
||||
|
||||
r["iniface_mask"] = TEXT(iniface_mask);
|
||||
std::string outiface_mask = "";
|
||||
for (int i = 0; ip->outiface_mask[i] != 0x00 && i<IFNAMSIZ; i++) {
|
||||
aux_char[0] = MAP[(int) ip->outiface_mask[i] >> HIGH_BITS];
|
||||
aux_char[1] = MAP[(int) ip->outiface_mask[i] & LOW_BITS];
|
||||
outiface_mask += aux_char[0];
|
||||
outiface_mask += aux_char[1];
|
||||
}
|
||||
r["outiface_mask"] = TEXT(outiface_mask);
|
||||
}
|
||||
|
||||
QueryData getIptablesRules(const std::string& content) {
|
||||
QueryData results;
|
||||
|
||||
for (auto& line : split(content, "\n")) {
|
||||
if (line.size() == 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// Inline trim each line.
|
||||
boost::trim(line);
|
||||
|
||||
Row r;
|
||||
|
||||
r["filter_name"] = TEXT(line);
|
||||
|
||||
// Initialize the access to iptc
|
||||
auto handle = (struct iptc_handle*) iptc_init(line.c_str());
|
||||
|
||||
if (handle) {
|
||||
// Iterate through chains
|
||||
for (auto chain = iptc_first_chain((struct iptc_handle*)handle); chain; chain = iptc_next_chain((struct iptc_handle*)handle)) {
|
||||
r["chain"] = TEXT(chain);
|
||||
|
||||
struct ipt_counters counters;
|
||||
const char* policy;
|
||||
|
||||
if ((policy = iptc_get_policy(chain, &counters, (struct iptc_handle*)handle))) {
|
||||
r["policy"] = TEXT(policy);
|
||||
r["packets"] = INTEGER(counters.pcnt);
|
||||
r["bytes"] = INTEGER(counters.bcnt);
|
||||
}
|
||||
|
||||
struct ipt_entry *prev_rule;
|
||||
|
||||
// Iterating through all the rules per chain
|
||||
for (auto chain_rule = iptc_first_rule(chain, (struct iptc_handle*)handle); chain_rule; chain_rule = iptc_next_rule(prev_rule, (struct iptc_handle*)handle)) {
|
||||
prev_rule = (struct ipt_entry*)chain_rule;
|
||||
|
||||
auto target = iptc_get_target(chain_rule, (struct iptc_handle*)handle);
|
||||
if (target) {
|
||||
r["target"] = TEXT(target);
|
||||
}
|
||||
|
||||
if (chain_rule->target_offset) {
|
||||
r["match"] = "yes";
|
||||
} else {
|
||||
r["match"] = "no";
|
||||
}
|
||||
|
||||
struct ipt_ip *ip = (struct ipt_ip*)&chain_rule->ip;
|
||||
parseIpEntry(ip, r);
|
||||
|
||||
results.push_back(r);
|
||||
} // Rule iteration
|
||||
results.push_back(r);
|
||||
} // Chain iteration
|
||||
|
||||
iptc_free((struct iptc_handle*) handle);
|
||||
|
||||
}
|
||||
} // Filter table iteration
|
||||
|
||||
return results;
|
||||
}
|
||||
|
||||
QueryData genIptables(QueryContext& context) {
|
||||
std::string content;
|
||||
QueryData results;
|
||||
|
||||
auto s = osquery::readFile(kLinuxIpTablesNames, content);
|
||||
|
||||
if (s.ok()) {
|
||||
return getIptablesRules(content);
|
||||
} else {
|
||||
LOG(ERROR) << "Error reading " << kLinuxIpTablesNames << " : " << s.toString();
|
||||
return {};
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
66
osquery/tables/networking/linux/tests/iptables_tests.cpp
Normal file
66
osquery/tables/networking/linux/tests/iptables_tests.cpp
Normal file
@ -0,0 +1,66 @@
|
||||
/*
|
||||
* Copyright (c) 2014, Facebook, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This source code is licensed under the BSD-style license found in the
|
||||
* LICENSE file in the root directory of this source tree. An additional grant
|
||||
* of patent rights can be found in the PATENTS file in the same directory.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <gtest/gtest.h>
|
||||
|
||||
#include <osquery/logger.h>
|
||||
#include <osquery/database.h>
|
||||
|
||||
#include <libiptc/libiptc.h>
|
||||
#include <arpa/inet.h>
|
||||
|
||||
#include "osquery/core/test_util.h"
|
||||
|
||||
namespace osquery {
|
||||
namespace tables {
|
||||
|
||||
void parseIpEntry(ipt_ip *ip, Row &row);
|
||||
|
||||
ipt_ip* getIpEntryContent() {
|
||||
static ipt_ip ip_entry;
|
||||
|
||||
ip_entry.proto = 6;
|
||||
memset(ip_entry.iniface, 0, IFNAMSIZ);
|
||||
strcpy(ip_entry.outiface, "eth0");
|
||||
inet_aton("123.123.123.123", &ip_entry.src);
|
||||
inet_aton("45.45.45.45", &ip_entry.dst);
|
||||
inet_aton("250.251.252.253", &ip_entry.smsk);
|
||||
inet_aton("253.252.251.250", &ip_entry.dmsk);
|
||||
memset(ip_entry.iniface_mask, 0xfe, IFNAMSIZ );
|
||||
memset(ip_entry.outiface_mask, 0xfa, IFNAMSIZ );
|
||||
|
||||
return &ip_entry;
|
||||
}
|
||||
|
||||
Row getIpEntryExpectedResults() {
|
||||
Row row;
|
||||
|
||||
row["protocol"] = "6";
|
||||
row["iniface"] = "all";
|
||||
row["outiface"] = "eth0";
|
||||
row["src_ip"] = "123.123.123.123";
|
||||
row["dst_ip"] = "45.45.45.45";
|
||||
row["src_mask"] = "250.251.252.253";
|
||||
row["dst_mask"] = "253.252.251.250";
|
||||
row["iniface_mask"] = "FEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFE";
|
||||
row["outiface_mask"] = "FAFAFAFAFAFAFAFAFAFAFAFAFAFAFAFA";
|
||||
|
||||
return row;
|
||||
}
|
||||
|
||||
class IptablesTests : public testing::Test {};
|
||||
|
||||
TEST_F(IptablesTests, test_iptables_ip_entry) {
|
||||
Row row;
|
||||
parseIpEntry(getIpEntryContent(), row);
|
||||
EXPECT_EQ(row, getIpEntryExpectedResults());
|
||||
}
|
||||
}
|
||||
}
|
21
osquery/tables/specs/linux/iptables.table
Normal file
21
osquery/tables/specs/linux/iptables.table
Normal file
@ -0,0 +1,21 @@
|
||||
table_name("iptables")
|
||||
description("Linux IP packet filtering and NAT tool.")
|
||||
schema([
|
||||
Column("filter_name", TEXT, "Packet matching filter table name."),
|
||||
Column("chain", TEXT, "Size of module content."),
|
||||
Column("policy", TEXT, "Policy that applies for this rule."),
|
||||
Column("target", TEXT, "Target that applies for this rule."),
|
||||
Column("protocol", INTEGER, "Protocol number identification."),
|
||||
Column("src_ip", TEXT, "Source IP address."),
|
||||
Column("src_mask", TEXT, "Source IP address mask."),
|
||||
Column("iniface", TEXT, "Input interface for the rule."),
|
||||
Column("iniface_mask", TEXT, "Input interface mask for the rule."),
|
||||
Column("dst_ip", TEXT, "Destination IP address."),
|
||||
Column("dst_mask", TEXT, "Destination IP address mask."),
|
||||
Column("outiface", TEXT, "Output interface for the rule."),
|
||||
Column("outiface_mask", TEXT, "Output interface mask for the rule."),
|
||||
Column("match", TEXT, "Matching rule that applies."),
|
||||
Column("packets", INTEGER, "Number of matching packets for this rule."),
|
||||
Column("bytes", INTEGER, "Number of matching bytes for this rule."),
|
||||
])
|
||||
implementation("iptables@genIptables")
|
@ -62,6 +62,9 @@ function main_centos() {
|
||||
package rpm-devel
|
||||
package rpm-build
|
||||
package libblkid-devel
|
||||
package iptables
|
||||
package iptables-devel
|
||||
patch_iptables_headers
|
||||
|
||||
install_cmake
|
||||
|
||||
|
@ -151,6 +151,38 @@ function install_boost() {
|
||||
fi
|
||||
}
|
||||
|
||||
function patch_iptables_headers() {
|
||||
IPV4FILE="/usr/include/linux/netfilter_ipv4/ip_tables.h"
|
||||
IPV6FILE="/usr/include/linux/netfilter_ipv6/ip6_tables.h"
|
||||
CODE_TO_PATCH="return (void \*)e + e->target_offset;"
|
||||
if [[ -f "$IPV4FILE" ]]; then
|
||||
if [[ -n `grep "$CODE_TO_PATCH" "$IPV4FILE"` ]]; then
|
||||
log "IPv4 code to patch found, backing up first"
|
||||
sudo cp "$IPV4FILE" "$IPV4FILE.osquery"
|
||||
PATCH="return (struct ipt_entry_target *)((char *)e + e->target_offset);"
|
||||
cat "$IPV4FILE" | sudo bash -c "sed \"s/$CODE_TO_PATCH/$PATCH/g\" > \"$IPV4FILE\""
|
||||
log "IPv4 headers patched succesfully"
|
||||
else
|
||||
log "IPv4 code to patch not found, skipping."
|
||||
fi
|
||||
else
|
||||
log "IPv4 iptables headers not found, skipping."
|
||||
fi
|
||||
if [[ -f "$IPV6FILE" ]]; then
|
||||
if [[ -n `grep "$CODE_TO_PATCH" "$IPV6FILE"` ]]; then
|
||||
log "IPv6 code to patch found, backing up first"
|
||||
sudo cp "$IPV6FILE" "$IPV6FILE.osquery"
|
||||
PATCH="return (struct ip6t_entry_target *)((char *)e + e->target_offset);"
|
||||
cat "$IPV6FILE" | sudo bash -c "sed \"s/$CODE_TO_PATCH/$PATCH/g\" > \"$IPV6FILE\""
|
||||
log "IPv6 headers patched succesfully"
|
||||
else
|
||||
log "IPv6 code to patch not found, skipping."
|
||||
fi
|
||||
else
|
||||
log "IPv6 iptables headers not found, skipping."
|
||||
fi
|
||||
}
|
||||
|
||||
function install_gflags() {
|
||||
if [[ ! -f /usr/local/lib/libgflags.a ]]; then
|
||||
if [[ ! -f v2.1.1.tar.gz ]]; then
|
||||
|
@ -41,6 +41,9 @@ function main_rhel() {
|
||||
package xz
|
||||
package xz-devel
|
||||
package subscription-manager
|
||||
package iptables
|
||||
package iptables-devel
|
||||
patch_iptables_headers
|
||||
|
||||
if [[ -z `rpm -qa epel-release` ]]; then
|
||||
if [[ $DISTRO = "rhel6" ]]; then
|
||||
|
@ -32,6 +32,9 @@ function main_ubuntu() {
|
||||
package libbz2-dev
|
||||
package devscripts
|
||||
package debhelper
|
||||
package iptables
|
||||
package iptables-dev
|
||||
patch_iptables_headers
|
||||
|
||||
if [[ $DISTRO = "precise" ]]; then
|
||||
package clang-3.4
|
||||
|
Loading…
Reference in New Issue
Block a user