Verified Commit ed4cc911 authored by Martin Petráček's avatar Martin Petráček

Merge branch 'blue-turris-fix'

parents 35ba4d01 948873b0
Pipeline #4173 passed with stage
in 1 minute and 20 seconds
......@@ -6,6 +6,10 @@ VALGRIND := valgrind --leak-check=full --show-leak-kinds=all --track-fds=yes --t
MAX_LOG_LEVEL := TRACE
ifdef HAVE_RECVMMSG
CXXFLAGS_ALL += -DHAVE_RECVMMSG=1
endif
include $(S)/build/Makefile.top
LUA_NAME := $(shell for lua in lua5.1 lua-5.1 lua51 lua ; do if pkg-config $$lua ; then echo $$lua ; break ; fi ; done)
......
......@@ -53,7 +53,7 @@ void extract(lua_State *state, int index, std::string &value) {
const char *str = lua_tolstring(state, index, &len);
value = std::string(str, len);
} else
throw Mismatch("String expected on index " + std::to_string(index));
throw Mismatch("String expected on index " + to_string(index));
}
void extract(lua_State *state, int index, Value &value) {
value.store(index, state);
......
......@@ -124,13 +124,13 @@ template<class T> typename std::enable_if<std::is_integral<T>::value>::type extr
if (lua_isnumber(state, index))
value = lua_tointeger(state, index);
else
throw Mismatch("Integer expected on index " + std::to_string(index));
throw Mismatch("Integer expected on index " + to_string(index));
}
template<class T> typename std::enable_if<std::is_floating_point<T>::value>::type extract(lua_State *state, int index, T &value) {
if (lua_isnumber(state, index))
value = lua_tonumber(state, index);
else
throw Mismatch("Number expected on index " + std::to_string(index));
throw Mismatch("Number expected on index " + to_string(index));
}
void extract(lua_State *state, int index, bool &value);
void extract(lua_State *state, int index, std::string &value);
......@@ -178,7 +178,7 @@ template<class Container> typename std::enable_if<IsSequence<Container>::value>:
// Get rid of that nil on top of stack and the table below
lua_pop(state, 2);
} else
throw Mismatch("Table expected on index " + std::to_string(index) + " to fill in seqeunce container");
throw Mismatch("Table expected on index " + to_string(index) + " to fill in seqeunce container");
}
// A helper function to unify code between extract for maps and sets
template<class Store> void extractTable(lua_State *state, int index, const Store &store) {
......@@ -201,7 +201,7 @@ template<class Store> void extractTable(lua_State *state, int index, const Store
// Get rid of the copied table
lua_pop(state, 1);
} else
throw Mismatch("Table expected on index " + std::to_string(index) + " to fill mapping container");
throw Mismatch("Table expected on index " + to_string(index) + " to fill mapping container");
}
template<class Container> typename std::enable_if<IsMap<Container>::value>::type extract(lua_State *state, int index, Container &container) {
// Instead of clearing the old container first, we create a new one and swap if it went well. That way we don't have to do it in the middle of the helper function
......
......@@ -34,8 +34,10 @@ NFQ::NFQ(Dissector &dissector, Family family, Direction direction, size_t qsize,
dissector(dissector),
flags(flags),
direction(direction),
recvIovs(batchSize),
recvHeaders(batchSize)
#ifdef HAVE_RECVMMSG
recvHeaders(batchSize),
#endif
recvIovs(batchSize)
{
TRC;
CHECK(handle = nfq_open());
......@@ -53,6 +55,7 @@ NFQ::NFQ(Dissector &dissector, Family family, Direction direction, size_t qsize,
for (size_t i = 0; i < batchSize; i ++) {
recvIovs[i].iov_len = pktSize;
recvIovs[i].iov_base = buffer + i * pktSize;
#ifdef HAVE_RECVMMSG
recvHeaders[i].msg_hdr.msg_name = nullptr;
recvHeaders[i].msg_hdr.msg_namelen = 0;
recvHeaders[i].msg_hdr.msg_iov = &recvIovs[i];
......@@ -61,6 +64,7 @@ NFQ::NFQ(Dissector &dissector, Family family, Direction direction, size_t qsize,
recvHeaders[i].msg_hdr.msg_controllen = 0;
// We have to reset this after each call, unfortunately :-(, as it is set
recvHeaders[i].msg_hdr.msg_flags = 0;
#endif
}
}
......@@ -96,6 +100,10 @@ bool NFQ::process() {
* They reference buffers reused on the next call.
*/
ExitGuard guard([this]{ this->packets.clear(); });
std::vector<std::unique_ptr<char[]>> bigPktBuff; // Buffer to copy big packets into and fill with zeroes
timestamp = timeMsec();
timestamp_monotonic = timeMsec(CLOCK_MONOTONIC);
#ifdef HAVE_RECVMMSG
int result = recvmmsg(fdInternal, &recvHeaders[0], recvHeaders.size(), MSG_DONTWAIT | MSG_TRUNC, NULL);
switch (result) {
case -1:
......@@ -112,9 +120,6 @@ bool NFQ::process() {
break;
}
LOG(TRACE, "Received ", result, " packets");
timestamp = timeMsec();
timestamp_monotonic = timeMsec(CLOCK_MONOTONIC);
std::vector<std::unique_ptr<char[]>> bigPktBuff; // Buffer to copy big packets into and fill with zeroes
// Process the received messages and convert them to packets
for (int i = 0; i < result; i ++) {
char *data = static_cast<char *>(recvIovs[i].iov_base);
......@@ -141,6 +146,37 @@ bool NFQ::process() {
if (result != 0)
LOG_DUMP(ERROR, "Failed to handle a packet: ", result, "/", Blob(data, recvHeaders[i].msg_len).toString());
}
#else
for (size_t i = 0; i < batchSize; i ++) {
struct msghdr hdr;
hdr.msg_name = nullptr;
hdr.msg_namelen = 0;
hdr.msg_iov = &recvIovs[i];
hdr.msg_iovlen = 1;
hdr.msg_control = nullptr;
hdr.msg_controllen = 0;
hdr.msg_flags = 0;
int result = recvmsg(fdInternal, &hdr, MSG_DONTWAIT | MSG_TRUNC);
if (result == -1) {
CHECK(errno == EAGAIN || errno == EWOULDBLOCK || errno == EINTR || errno == ENOBUFS);
// OK, no more packets for now, try again later
break;
}
char *data = static_cast<char *>(recvIovs[i].iov_base);
size_t size = result;
if (hdr.msg_flags & MSG_TRUNC) {
LOG(INFO, "Truncated packet, original ", result, " bytes");
// Copy the packet somewhere and fill the rest with zeroes
bigPktBuff.emplace_back(new char[size]);
data = bigPktBuff.back().get();
memcpy(data, recvIovs[i].iov_base, pktSize);
memset(data + pktSize, 0, size - pktSize);
}
result = nfq_handle_packet(handle, data, size);
if (result != 0)
LOG_DUMP(ERROR, "Failed to handle a packet: ", result, "/", Blob(data, size).toString());
}
#endif
// Process the packets and assign flows
const Flows &flows(dissector.process(packets));
// TODO: Process the flows further ‒ through lua, DNS, send them to the socket…
......
......@@ -65,10 +65,12 @@ private:
// The following is prepared to receive data by recvmmsg and reused.
// Buffer to receive packets into
uint8_t buffer[pktSize * batchSize];
// The vectors for receiving scatter-gather by recvmmsg
std::vector<struct iovec> recvIovs;
#ifdef HAVE_RECVMMSG
// The headers for recvmmsg
std::vector<struct mmsghdr> recvHeaders;
#endif
// The vectors for receiving scatter-gather by recvmmsg
std::vector<struct iovec> recvIovs;
int packet(struct nfq_data *data);
public:
/*
......
......@@ -179,7 +179,9 @@ Packet::Packet(struct nfq_data *data, const unordered_map<string, string> &flags
struct nfqnl_msg_packet_hdr *header = nfq_get_msg_packet_hdr(data);
if (!header)
throw Unparsable("Can't parse the packet id");
store<PKT_id>(ntohl(header->packet_id));
// passing just header->packet_id to ntohl causes compile error: "cannot bind packed field 'header->nfqnl_msg_packet_hdr::packet_id' to 'unsigned int&'"
unsigned long packet_id_n = header->packet_id;
store<PKT_id>(ntohl(packet_id_n));
uint8_t *data_ptr;
int len = nfq_get_payload(data, &data_ptr);
this->data = data_ptr;
......
......@@ -33,7 +33,6 @@ using std::vector;
using std::string;
using std::sort;
using std::min;
using std::to_string;
using std::ofstream;
/*
......
......@@ -100,7 +100,21 @@ public:
}
};
#define CHECK(condition) do { if (!(condition)) throw CheckError(std::string(#condition " failed at " __FILE__ ":") + std::to_string(__LINE__) + ":" + __PRETTY_FUNCTION__ + "(error: " + std::to_string(errno) + "/" + strerror(errno) + ")"); } while (0)
/*
* Implement our own to_string.
*
* One of the systems we compile for doesn't seem to provide to_string, despite
* that being part of standard library. This is a very simple function, so the
* easiest thing is to simply implement our own copy.
*/
template<class T> std::string to_string(const T& value) {
std::stringstream output;
output << value;
return output.str();
}
#define CHECK(condition) do { if (!(condition)) throw CheckError(std::string(#condition " failed at " __FILE__ ":") + to_string(__LINE__) + ":" + __PRETTY_FUNCTION__ + "(error: " + to_string(errno) + "/" + strerror(errno) + ")"); } while (0)
/*
* Thanks to Hanička Dusíková for providing the spark that
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment