Skip to content

Commit

Permalink
Merge pull request #69 from AnnikaH/master
Browse files Browse the repository at this point in the history
Conntrack: Adding stateful_tcp member (true/false)
  • Loading branch information
AnnikaH authored Oct 24, 2018
2 parents 0af7dac + 4f5cb34 commit 5f94f90
Show file tree
Hide file tree
Showing 5 changed files with 229 additions and 95 deletions.
8 changes: 8 additions & 0 deletions cpp_template.mustache
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,11 @@
{{#has_load_balancers}}
#include <microLB>
{{/has_load_balancers}}
{{#conntracks}}
{{#stateful}}
#include <net/tcp/tcp_conntrack.hpp>
{{/stateful}}
{{/conntracks}}
#include <syslogd>
{{#has_timers}}
#include <timers>
Expand Down Expand Up @@ -305,6 +310,9 @@ void register_plugin_nacl() {

nacl_ct_obj = std::make_shared<Conntrack>();
{{#conntracks}}
{{#stateful}}
nacl_ct_obj->tcp_in = tcp::tcp4_conntrack;
{{/stateful}}
{{#limit}}nacl_ct_obj->maximum_entries = {{.}};{{/limit}}
{{#reserve}}nacl_ct_obj->reserve({{.}});{{/reserve}}
{{#timeouts}}
Expand Down
34 changes: 34 additions & 0 deletions examples/conntrack_stateful.nacl
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
Conntrack my_conntrack {
stateful_tcp: true,
limit: 20000,
reserve: 10000,
timeout: {
established: {
tcp: 100,
udp: 200,
icmp: 300
},
unconfirmed: {
tcp: 400,
udp: 500,
icmp: 600
},
confirmed: {
tcp: 700,
udp: 800,
icmp: 900
}
}
}

Iface eth0 {
index: 0,
address: 10.0.0.45,
netmask: 255.255.255.0,
gateway: 10.0.0.1,
prerouting: my_filter
}

Filter::IP my_filter {
accept
}
80 changes: 80 additions & 0 deletions goldenfiles/conntrack_stateful.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
// This file is a part of the IncludeOS unikernel - www.includeos.org
//
// Copyright 2017-2018 IncludeOS AS, Oslo, Norway
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
// Autogenerated by NaCl

#include <iostream>
#include <net/interfaces>
#include <net/ip4/cidr.hpp>
#include <net/tcp/tcp_conntrack.hpp>
#include <syslogd>

using namespace net;

namespace nacl {
class Filter {
public:
virtual Filter_verdict<IP4> operator()(IP4::IP_packet_ptr pckt, Inet& stack, Conntrack::Entry_ptr ct_entry) = 0;
virtual ~Filter() {}
};
}

std::shared_ptr<Conntrack> nacl_ct_obj;

namespace custom_made_classes_from_nacl {

class My_Filter : public nacl::Filter {
public:
Filter_verdict<IP4> operator()(IP4::IP_packet_ptr pckt, Inet& stack, Conntrack::Entry_ptr ct_entry) {
if (not ct_entry) {
return {nullptr, Filter_verdict_type::DROP};
}
return {std::move(pckt), Filter_verdict_type::ACCEPT};

}
};

} //< namespace custom_made_classes_from_nacl

void register_plugin_nacl() {
INFO("NaCl", "Registering NaCl plugin");

auto& eth0 = Interfaces::get(0);
eth0.network_config(IP4::addr{10,0,0,45}, IP4::addr{255,255,255,0}, IP4::addr{10,0,0,1});

custom_made_classes_from_nacl::My_Filter my_filter;

eth0.ip_obj().prerouting_chain().chain.push_back(my_filter);

// Ct

nacl_ct_obj = std::make_shared<Conntrack>();
nacl_ct_obj->tcp_in = tcp::tcp4_conntrack;
nacl_ct_obj->maximum_entries = 20000;
nacl_ct_obj->reserve(10000);
nacl_ct_obj->timeout.established.tcp = Conntrack::Timeout_duration{ 100 };
nacl_ct_obj->timeout.established.udp = Conntrack::Timeout_duration{ 200 };
nacl_ct_obj->timeout.established.icmp = Conntrack::Timeout_duration{ 300 };
nacl_ct_obj->timeout.confirmed.tcp = Conntrack::Timeout_duration{ 700 };
nacl_ct_obj->timeout.confirmed.udp = Conntrack::Timeout_duration{ 800 };
nacl_ct_obj->timeout.confirmed.icmp = Conntrack::Timeout_duration{ 900 };
nacl_ct_obj->timeout.unconfirmed.tcp = Conntrack::Timeout_duration{ 400 };
nacl_ct_obj->timeout.unconfirmed.udp = Conntrack::Timeout_duration{ 500 };
nacl_ct_obj->timeout.unconfirmed.icmp = Conntrack::Timeout_duration{ 600 };

INFO("NaCl", "Enabling Conntrack on eth0");
eth0.enable_conntrack(nacl_ct_obj);
}
1 change: 1 addition & 0 deletions test/cpp_diff.sh
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ declare -a examples=(
"assignments"
"cidr"
"config_options"
"conntrack_stateful"
"conntrack"
"conntrack_with_timeout"
"conntrack_with_timeout_assignments"
Expand Down
201 changes: 106 additions & 95 deletions type_processors/conntrack.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,134 +18,145 @@
# To avoid: <...>/NaCl/type_processors/conntrack.py:1: RuntimeWarning: Parent module '<...>/NaCl/type_processors' not found while handling absolute import

from NaCl import exit_NaCl, NaCl_exception, Typed
from shared import TEMPLATE_KEY_NAME, TCP, UDP, ICMP
from shared import TEMPLATE_KEY_NAME, TCP, UDP, ICMP, TRUE

# -------------------- CONSTANTS Conntrack --------------------

TYPE_CONNTRACK = "conntrack"
TYPE_CONNTRACK = "conntrack"

# ---- Conntrack keys ----

CONNTRACK_KEY_LIMIT = "limit"
CONNTRACK_KEY_RESERVE = "reserve"
CONNTRACK_KEY_TIMEOUT = "timeout"
CONNTRACK_KEY_LIMIT = "limit"
CONNTRACK_KEY_RESERVE = "reserve"
CONNTRACK_KEY_STATEFUL_TCP = "stateful_tcp"
CONNTRACK_KEY_TIMEOUT = "timeout"

PREDEFINED_CONNTRACK_KEYS = [
CONNTRACK_KEY_LIMIT,
CONNTRACK_KEY_RESERVE,
CONNTRACK_KEY_TIMEOUT
CONNTRACK_KEY_LIMIT,
CONNTRACK_KEY_RESERVE,
CONNTRACK_KEY_STATEFUL_TCP,
CONNTRACK_KEY_TIMEOUT
]

CONNTRACK_TIMEOUT_KEY_ESTABLISHED = "established"
CONNTRACK_TIMEOUT_KEY_UNCONFIRMED = "unconfirmed"
CONNTRACK_TIMEOUT_KEY_CONFIRMED = "confirmed"

PREDEFINED_CONNTRACK_TIMEOUT_KEYS = [
CONNTRACK_TIMEOUT_KEY_ESTABLISHED,
CONNTRACK_TIMEOUT_KEY_UNCONFIRMED,
CONNTRACK_TIMEOUT_KEY_CONFIRMED
CONNTRACK_TIMEOUT_KEY_ESTABLISHED,
CONNTRACK_TIMEOUT_KEY_UNCONFIRMED,
CONNTRACK_TIMEOUT_KEY_CONFIRMED
]

PREDEFINED_CONNTRACK_TIMEOUT_INNER_KEYS = [
TCP,
UDP,
ICMP
TCP,
UDP,
ICMP
]

# -------------------- TEMPLATE KEYS (pystache) --------------------

TEMPLATE_KEY_CONNTRACKS = "conntracks"

TEMPLATE_KEY_CONNTRACK_TIMEOUTS = "timeouts"
TEMPLATE_KEY_CONNTRACK_TYPE = "type"
TEMPLATE_KEY_CONNTRACK_LIMIT = CONNTRACK_KEY_LIMIT
TEMPLATE_KEY_CONNTRACK_RESERVE = CONNTRACK_KEY_RESERVE
TEMPLATE_KEY_CONNTRACK_STATEFUL = "stateful"
TEMPLATE_KEY_CONNTRACK_TIMEOUTS = "timeouts"
TEMPLATE_KEY_CONNTRACK_TYPE = "type"

# -------------------- class Conntrack --------------------

class Conntrack(Typed):
def __init__(self, nacl_state, idx, name, ctx, base_type, type_t):
super(Conntrack, self).__init__(nacl_state, idx, name, ctx, base_type, type_t)

def add_conntrack(self):
timeout = self.members.get(CONNTRACK_KEY_TIMEOUT)
timeouts = []

if timeout is not None:
class_name = self.get_class_name()

if not isinstance(timeout, dict):
exit_NaCl(self.ctx, "Invalid " + CONNTRACK_KEY_TIMEOUT + " value of " + class_name + " (needs to be an object)")

for conntrack_type in timeout:
t = timeout.get(conntrack_type)

if not isinstance(t, dict):
exit_NaCl(self.ctx, "Invalid " + conntrack_type + " value of " + class_name + " (needs to be an object)")

tcp_timeout = t.get(TCP)
udp_timeout = t.get(UDP)
icmp_timeout = t.get(ICMP)

timeouts.append({
TEMPLATE_KEY_CONNTRACK_TYPE: conntrack_type,
TCP: tcp_timeout,
UDP: udp_timeout,
ICMP: icmp_timeout
})

self.nacl_state.append_to_pystache_data_list(TEMPLATE_KEY_CONNTRACKS, {
TEMPLATE_KEY_NAME: self.name,
CONNTRACK_KEY_LIMIT: self.members.get(CONNTRACK_KEY_LIMIT),
CONNTRACK_KEY_RESERVE: self.members.get(CONNTRACK_KEY_RESERVE),
TEMPLATE_KEY_CONNTRACK_TIMEOUTS: timeouts
})

# Overriding
def validate_dictionary_key(self, key, parent_key, level, value_ctx):
class_name = self.get_class_name()

if level == 1:
if key not in PREDEFINED_CONNTRACK_KEYS:
exit_NaCl(value_ctx, "Invalid " + class_name + " member " + key)
return

if parent_key == "":
exit_NaCl(value_ctx, "Internal error: Parent key of " + key + " has not been given")

if level == 2:
if parent_key == CONNTRACK_KEY_TIMEOUT and key not in PREDEFINED_CONNTRACK_TIMEOUT_KEYS:
exit_NaCl(value_ctx, "Invalid " + class_name + " member " + key + " in " + self.name + "." + parent_key)
elif level == 3:
if parent_key not in PREDEFINED_CONNTRACK_TIMEOUT_KEYS:
exit_NaCl(value_ctx, "Internal error: Invalid parent key " + parent_key + " of " + key)
if key not in PREDEFINED_CONNTRACK_TIMEOUT_INNER_KEYS:
exit_NaCl(value_ctx, "Invalid " + class_name + " member " + key)
else:
exit_NaCl(value_ctx, "Invalid " + class_name + " member " + key)

# Overriding
def resolve_dictionary_value(self, dictionary, key, value):
# Add found value
dictionary[key] = self.nacl_state.transpile_value(value)

# Main processing method
def process(self):
if self.res is None:
# Then process

self.process_ctx()
self.process_assignments()
self.add_conntrack()

self.res = self.members

return self.res
def __init__(self, nacl_state, idx, name, ctx, base_type, type_t):
super(Conntrack, self).__init__(nacl_state, idx, name, ctx, base_type, type_t)

def add_conntrack(self):
timeout = self.members.get(CONNTRACK_KEY_TIMEOUT)
timeouts = []

if timeout is not None:
class_name = self.get_class_name()

if not isinstance(timeout, dict):
exit_NaCl(self.ctx, "Invalid " + CONNTRACK_KEY_TIMEOUT + " value of " + class_name + " (needs to be an object)")

for conntrack_type in timeout:
t = timeout.get(conntrack_type)

if not isinstance(t, dict):
exit_NaCl(self.ctx, "Invalid " + conntrack_type + " value of " + class_name + " (needs to be an object)")

tcp_timeout = t.get(TCP)
udp_timeout = t.get(UDP)
icmp_timeout = t.get(ICMP)

timeouts.append({
TEMPLATE_KEY_CONNTRACK_TYPE: conntrack_type,
TCP: tcp_timeout,
UDP: udp_timeout,
ICMP: icmp_timeout
})

stateful = False
stateful_tcp = self.members.get(CONNTRACK_KEY_STATEFUL_TCP)
if stateful_tcp is not None and stateful_tcp == TRUE:
stateful = True

self.nacl_state.append_to_pystache_data_list(TEMPLATE_KEY_CONNTRACKS, {
TEMPLATE_KEY_NAME: self.name,
TEMPLATE_KEY_CONNTRACK_LIMIT: self.members.get(CONNTRACK_KEY_LIMIT),
TEMPLATE_KEY_CONNTRACK_RESERVE: self.members.get(CONNTRACK_KEY_RESERVE),
TEMPLATE_KEY_CONNTRACK_STATEFUL: stateful,
TEMPLATE_KEY_CONNTRACK_TIMEOUTS: timeouts
})

# Overriding
def validate_dictionary_key(self, key, parent_key, level, value_ctx):
class_name = self.get_class_name()

if level == 1:
if key not in PREDEFINED_CONNTRACK_KEYS:
exit_NaCl(value_ctx, "Invalid " + class_name + " member " + key)
return

if parent_key == "":
exit_NaCl(value_ctx, "Internal error: Parent key of " + key + " has not been given")

if level == 2:
if parent_key == CONNTRACK_KEY_TIMEOUT and key not in PREDEFINED_CONNTRACK_TIMEOUT_KEYS:
exit_NaCl(value_ctx, "Invalid " + class_name + " member " + key + " in " + self.name + "." + parent_key)
elif level == 3:
if parent_key not in PREDEFINED_CONNTRACK_TIMEOUT_KEYS:
exit_NaCl(value_ctx, "Internal error: Invalid parent key " + parent_key + " of " + key)
if key not in PREDEFINED_CONNTRACK_TIMEOUT_INNER_KEYS:
exit_NaCl(value_ctx, "Invalid " + class_name + " member " + key)
else:
exit_NaCl(value_ctx, "Invalid " + class_name + " member " + key)

# Overriding
def resolve_dictionary_value(self, dictionary, key, value):
# Add found value
dictionary[key] = self.nacl_state.transpile_value(value)

# Main processing method
def process(self):
if self.res is None:
# Then process

self.process_ctx()
self.process_assignments()
self.add_conntrack()

self.res = self.members

return self.res

# < class Conntrack

def create_connstrack_pystache_lists(nacl_state):
nacl_state.create_pystache_data_lists([
nacl_state.create_pystache_data_lists([
TEMPLATE_KEY_CONNTRACKS
])
])

def init(nacl_state):
# print "Init conntrack: Conntrack"
Expand Down

0 comments on commit 5f94f90

Please sign in to comment.