Skip to content

Commit 5f94f90

Browse files
authored
Merge pull request #69 from AnnikaH/master
Conntrack: Adding stateful_tcp member (true/false)
2 parents 0af7dac + 4f5cb34 commit 5f94f90

5 files changed

Lines changed: 229 additions & 95 deletions

File tree

cpp_template.mustache

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,11 @@
3232
{{#has_load_balancers}}
3333
#include <microLB>
3434
{{/has_load_balancers}}
35+
{{#conntracks}}
36+
{{#stateful}}
37+
#include <net/tcp/tcp_conntrack.hpp>
38+
{{/stateful}}
39+
{{/conntracks}}
3540
#include <syslogd>
3641
{{#has_timers}}
3742
#include <timers>
@@ -305,6 +310,9 @@ void register_plugin_nacl() {
305310

306311
nacl_ct_obj = std::make_shared<Conntrack>();
307312
{{#conntracks}}
313+
{{#stateful}}
314+
nacl_ct_obj->tcp_in = tcp::tcp4_conntrack;
315+
{{/stateful}}
308316
{{#limit}}nacl_ct_obj->maximum_entries = {{.}};{{/limit}}
309317
{{#reserve}}nacl_ct_obj->reserve({{.}});{{/reserve}}
310318
{{#timeouts}}

examples/conntrack_stateful.nacl

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
Conntrack my_conntrack {
2+
stateful_tcp: true,
3+
limit: 20000,
4+
reserve: 10000,
5+
timeout: {
6+
established: {
7+
tcp: 100,
8+
udp: 200,
9+
icmp: 300
10+
},
11+
unconfirmed: {
12+
tcp: 400,
13+
udp: 500,
14+
icmp: 600
15+
},
16+
confirmed: {
17+
tcp: 700,
18+
udp: 800,
19+
icmp: 900
20+
}
21+
}
22+
}
23+
24+
Iface eth0 {
25+
index: 0,
26+
address: 10.0.0.45,
27+
netmask: 255.255.255.0,
28+
gateway: 10.0.0.1,
29+
prerouting: my_filter
30+
}
31+
32+
Filter::IP my_filter {
33+
accept
34+
}

goldenfiles/conntrack_stateful.cpp

Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,80 @@
1+
// This file is a part of the IncludeOS unikernel - www.includeos.org
2+
//
3+
// Copyright 2017-2018 IncludeOS AS, Oslo, Norway
4+
//
5+
// Licensed under the Apache License, Version 2.0 (the "License");
6+
// you may not use this file except in compliance with the License.
7+
// You may obtain a copy of the License at
8+
//
9+
// http://www.apache.org/licenses/LICENSE-2.0
10+
//
11+
// Unless required by applicable law or agreed to in writing, software
12+
// distributed under the License is distributed on an "AS IS" BASIS,
13+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14+
// See the License for the specific language governing permissions and
15+
// limitations under the License.
16+
//
17+
// Autogenerated by NaCl
18+
19+
#include <iostream>
20+
#include <net/interfaces>
21+
#include <net/ip4/cidr.hpp>
22+
#include <net/tcp/tcp_conntrack.hpp>
23+
#include <syslogd>
24+
25+
using namespace net;
26+
27+
namespace nacl {
28+
class Filter {
29+
public:
30+
virtual Filter_verdict<IP4> operator()(IP4::IP_packet_ptr pckt, Inet& stack, Conntrack::Entry_ptr ct_entry) = 0;
31+
virtual ~Filter() {}
32+
};
33+
}
34+
35+
std::shared_ptr<Conntrack> nacl_ct_obj;
36+
37+
namespace custom_made_classes_from_nacl {
38+
39+
class My_Filter : public nacl::Filter {
40+
public:
41+
Filter_verdict<IP4> operator()(IP4::IP_packet_ptr pckt, Inet& stack, Conntrack::Entry_ptr ct_entry) {
42+
if (not ct_entry) {
43+
return {nullptr, Filter_verdict_type::DROP};
44+
}
45+
return {std::move(pckt), Filter_verdict_type::ACCEPT};
46+
47+
}
48+
};
49+
50+
} //< namespace custom_made_classes_from_nacl
51+
52+
void register_plugin_nacl() {
53+
INFO("NaCl", "Registering NaCl plugin");
54+
55+
auto& eth0 = Interfaces::get(0);
56+
eth0.network_config(IP4::addr{10,0,0,45}, IP4::addr{255,255,255,0}, IP4::addr{10,0,0,1});
57+
58+
custom_made_classes_from_nacl::My_Filter my_filter;
59+
60+
eth0.ip_obj().prerouting_chain().chain.push_back(my_filter);
61+
62+
// Ct
63+
64+
nacl_ct_obj = std::make_shared<Conntrack>();
65+
nacl_ct_obj->tcp_in = tcp::tcp4_conntrack;
66+
nacl_ct_obj->maximum_entries = 20000;
67+
nacl_ct_obj->reserve(10000);
68+
nacl_ct_obj->timeout.established.tcp = Conntrack::Timeout_duration{ 100 };
69+
nacl_ct_obj->timeout.established.udp = Conntrack::Timeout_duration{ 200 };
70+
nacl_ct_obj->timeout.established.icmp = Conntrack::Timeout_duration{ 300 };
71+
nacl_ct_obj->timeout.confirmed.tcp = Conntrack::Timeout_duration{ 700 };
72+
nacl_ct_obj->timeout.confirmed.udp = Conntrack::Timeout_duration{ 800 };
73+
nacl_ct_obj->timeout.confirmed.icmp = Conntrack::Timeout_duration{ 900 };
74+
nacl_ct_obj->timeout.unconfirmed.tcp = Conntrack::Timeout_duration{ 400 };
75+
nacl_ct_obj->timeout.unconfirmed.udp = Conntrack::Timeout_duration{ 500 };
76+
nacl_ct_obj->timeout.unconfirmed.icmp = Conntrack::Timeout_duration{ 600 };
77+
78+
INFO("NaCl", "Enabling Conntrack on eth0");
79+
eth0.enable_conntrack(nacl_ct_obj);
80+
}

test/cpp_diff.sh

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ declare -a examples=(
88
"assignments"
99
"cidr"
1010
"config_options"
11+
"conntrack_stateful"
1112
"conntrack"
1213
"conntrack_with_timeout"
1314
"conntrack_with_timeout_assignments"

type_processors/conntrack.py

Lines changed: 106 additions & 95 deletions
Original file line numberDiff line numberDiff line change
@@ -18,134 +18,145 @@
1818
# To avoid: <...>/NaCl/type_processors/conntrack.py:1: RuntimeWarning: Parent module '<...>/NaCl/type_processors' not found while handling absolute import
1919

2020
from NaCl import exit_NaCl, NaCl_exception, Typed
21-
from shared import TEMPLATE_KEY_NAME, TCP, UDP, ICMP
21+
from shared import TEMPLATE_KEY_NAME, TCP, UDP, ICMP, TRUE
2222

2323
# -------------------- CONSTANTS Conntrack --------------------
2424

25-
TYPE_CONNTRACK = "conntrack"
25+
TYPE_CONNTRACK = "conntrack"
2626

2727
# ---- Conntrack keys ----
2828

29-
CONNTRACK_KEY_LIMIT = "limit"
30-
CONNTRACK_KEY_RESERVE = "reserve"
31-
CONNTRACK_KEY_TIMEOUT = "timeout"
29+
CONNTRACK_KEY_LIMIT = "limit"
30+
CONNTRACK_KEY_RESERVE = "reserve"
31+
CONNTRACK_KEY_STATEFUL_TCP = "stateful_tcp"
32+
CONNTRACK_KEY_TIMEOUT = "timeout"
3233

3334
PREDEFINED_CONNTRACK_KEYS = [
34-
CONNTRACK_KEY_LIMIT,
35-
CONNTRACK_KEY_RESERVE,
36-
CONNTRACK_KEY_TIMEOUT
35+
CONNTRACK_KEY_LIMIT,
36+
CONNTRACK_KEY_RESERVE,
37+
CONNTRACK_KEY_STATEFUL_TCP,
38+
CONNTRACK_KEY_TIMEOUT
3739
]
3840

3941
CONNTRACK_TIMEOUT_KEY_ESTABLISHED = "established"
4042
CONNTRACK_TIMEOUT_KEY_UNCONFIRMED = "unconfirmed"
4143
CONNTRACK_TIMEOUT_KEY_CONFIRMED = "confirmed"
4244

4345
PREDEFINED_CONNTRACK_TIMEOUT_KEYS = [
44-
CONNTRACK_TIMEOUT_KEY_ESTABLISHED,
45-
CONNTRACK_TIMEOUT_KEY_UNCONFIRMED,
46-
CONNTRACK_TIMEOUT_KEY_CONFIRMED
46+
CONNTRACK_TIMEOUT_KEY_ESTABLISHED,
47+
CONNTRACK_TIMEOUT_KEY_UNCONFIRMED,
48+
CONNTRACK_TIMEOUT_KEY_CONFIRMED
4749
]
4850

4951
PREDEFINED_CONNTRACK_TIMEOUT_INNER_KEYS = [
50-
TCP,
51-
UDP,
52-
ICMP
52+
TCP,
53+
UDP,
54+
ICMP
5355
]
5456

5557
# -------------------- TEMPLATE KEYS (pystache) --------------------
5658

5759
TEMPLATE_KEY_CONNTRACKS = "conntracks"
5860

59-
TEMPLATE_KEY_CONNTRACK_TIMEOUTS = "timeouts"
60-
TEMPLATE_KEY_CONNTRACK_TYPE = "type"
61+
TEMPLATE_KEY_CONNTRACK_LIMIT = CONNTRACK_KEY_LIMIT
62+
TEMPLATE_KEY_CONNTRACK_RESERVE = CONNTRACK_KEY_RESERVE
63+
TEMPLATE_KEY_CONNTRACK_STATEFUL = "stateful"
64+
TEMPLATE_KEY_CONNTRACK_TIMEOUTS = "timeouts"
65+
TEMPLATE_KEY_CONNTRACK_TYPE = "type"
6166

6267
# -------------------- class Conntrack --------------------
6368

6469
class Conntrack(Typed):
65-
def __init__(self, nacl_state, idx, name, ctx, base_type, type_t):
66-
super(Conntrack, self).__init__(nacl_state, idx, name, ctx, base_type, type_t)
67-
68-
def add_conntrack(self):
69-
timeout = self.members.get(CONNTRACK_KEY_TIMEOUT)
70-
timeouts = []
71-
72-
if timeout is not None:
73-
class_name = self.get_class_name()
74-
75-
if not isinstance(timeout, dict):
76-
exit_NaCl(self.ctx, "Invalid " + CONNTRACK_KEY_TIMEOUT + " value of " + class_name + " (needs to be an object)")
77-
78-
for conntrack_type in timeout:
79-
t = timeout.get(conntrack_type)
80-
81-
if not isinstance(t, dict):
82-
exit_NaCl(self.ctx, "Invalid " + conntrack_type + " value of " + class_name + " (needs to be an object)")
83-
84-
tcp_timeout = t.get(TCP)
85-
udp_timeout = t.get(UDP)
86-
icmp_timeout = t.get(ICMP)
87-
88-
timeouts.append({
89-
TEMPLATE_KEY_CONNTRACK_TYPE: conntrack_type,
90-
TCP: tcp_timeout,
91-
UDP: udp_timeout,
92-
ICMP: icmp_timeout
93-
})
94-
95-
self.nacl_state.append_to_pystache_data_list(TEMPLATE_KEY_CONNTRACKS, {
96-
TEMPLATE_KEY_NAME: self.name,
97-
CONNTRACK_KEY_LIMIT: self.members.get(CONNTRACK_KEY_LIMIT),
98-
CONNTRACK_KEY_RESERVE: self.members.get(CONNTRACK_KEY_RESERVE),
99-
TEMPLATE_KEY_CONNTRACK_TIMEOUTS: timeouts
100-
})
101-
102-
# Overriding
103-
def validate_dictionary_key(self, key, parent_key, level, value_ctx):
104-
class_name = self.get_class_name()
105-
106-
if level == 1:
107-
if key not in PREDEFINED_CONNTRACK_KEYS:
108-
exit_NaCl(value_ctx, "Invalid " + class_name + " member " + key)
109-
return
110-
111-
if parent_key == "":
112-
exit_NaCl(value_ctx, "Internal error: Parent key of " + key + " has not been given")
113-
114-
if level == 2:
115-
if parent_key == CONNTRACK_KEY_TIMEOUT and key not in PREDEFINED_CONNTRACK_TIMEOUT_KEYS:
116-
exit_NaCl(value_ctx, "Invalid " + class_name + " member " + key + " in " + self.name + "." + parent_key)
117-
elif level == 3:
118-
if parent_key not in PREDEFINED_CONNTRACK_TIMEOUT_KEYS:
119-
exit_NaCl(value_ctx, "Internal error: Invalid parent key " + parent_key + " of " + key)
120-
if key not in PREDEFINED_CONNTRACK_TIMEOUT_INNER_KEYS:
121-
exit_NaCl(value_ctx, "Invalid " + class_name + " member " + key)
122-
else:
123-
exit_NaCl(value_ctx, "Invalid " + class_name + " member " + key)
124-
125-
# Overriding
126-
def resolve_dictionary_value(self, dictionary, key, value):
127-
# Add found value
128-
dictionary[key] = self.nacl_state.transpile_value(value)
129-
130-
# Main processing method
131-
def process(self):
132-
if self.res is None:
133-
# Then process
134-
135-
self.process_ctx()
136-
self.process_assignments()
137-
self.add_conntrack()
138-
139-
self.res = self.members
140-
141-
return self.res
70+
def __init__(self, nacl_state, idx, name, ctx, base_type, type_t):
71+
super(Conntrack, self).__init__(nacl_state, idx, name, ctx, base_type, type_t)
72+
73+
def add_conntrack(self):
74+
timeout = self.members.get(CONNTRACK_KEY_TIMEOUT)
75+
timeouts = []
76+
77+
if timeout is not None:
78+
class_name = self.get_class_name()
79+
80+
if not isinstance(timeout, dict):
81+
exit_NaCl(self.ctx, "Invalid " + CONNTRACK_KEY_TIMEOUT + " value of " + class_name + " (needs to be an object)")
82+
83+
for conntrack_type in timeout:
84+
t = timeout.get(conntrack_type)
85+
86+
if not isinstance(t, dict):
87+
exit_NaCl(self.ctx, "Invalid " + conntrack_type + " value of " + class_name + " (needs to be an object)")
88+
89+
tcp_timeout = t.get(TCP)
90+
udp_timeout = t.get(UDP)
91+
icmp_timeout = t.get(ICMP)
92+
93+
timeouts.append({
94+
TEMPLATE_KEY_CONNTRACK_TYPE: conntrack_type,
95+
TCP: tcp_timeout,
96+
UDP: udp_timeout,
97+
ICMP: icmp_timeout
98+
})
99+
100+
stateful = False
101+
stateful_tcp = self.members.get(CONNTRACK_KEY_STATEFUL_TCP)
102+
if stateful_tcp is not None and stateful_tcp == TRUE:
103+
stateful = True
104+
105+
self.nacl_state.append_to_pystache_data_list(TEMPLATE_KEY_CONNTRACKS, {
106+
TEMPLATE_KEY_NAME: self.name,
107+
TEMPLATE_KEY_CONNTRACK_LIMIT: self.members.get(CONNTRACK_KEY_LIMIT),
108+
TEMPLATE_KEY_CONNTRACK_RESERVE: self.members.get(CONNTRACK_KEY_RESERVE),
109+
TEMPLATE_KEY_CONNTRACK_STATEFUL: stateful,
110+
TEMPLATE_KEY_CONNTRACK_TIMEOUTS: timeouts
111+
})
112+
113+
# Overriding
114+
def validate_dictionary_key(self, key, parent_key, level, value_ctx):
115+
class_name = self.get_class_name()
116+
117+
if level == 1:
118+
if key not in PREDEFINED_CONNTRACK_KEYS:
119+
exit_NaCl(value_ctx, "Invalid " + class_name + " member " + key)
120+
return
121+
122+
if parent_key == "":
123+
exit_NaCl(value_ctx, "Internal error: Parent key of " + key + " has not been given")
124+
125+
if level == 2:
126+
if parent_key == CONNTRACK_KEY_TIMEOUT and key not in PREDEFINED_CONNTRACK_TIMEOUT_KEYS:
127+
exit_NaCl(value_ctx, "Invalid " + class_name + " member " + key + " in " + self.name + "." + parent_key)
128+
elif level == 3:
129+
if parent_key not in PREDEFINED_CONNTRACK_TIMEOUT_KEYS:
130+
exit_NaCl(value_ctx, "Internal error: Invalid parent key " + parent_key + " of " + key)
131+
if key not in PREDEFINED_CONNTRACK_TIMEOUT_INNER_KEYS:
132+
exit_NaCl(value_ctx, "Invalid " + class_name + " member " + key)
133+
else:
134+
exit_NaCl(value_ctx, "Invalid " + class_name + " member " + key)
135+
136+
# Overriding
137+
def resolve_dictionary_value(self, dictionary, key, value):
138+
# Add found value
139+
dictionary[key] = self.nacl_state.transpile_value(value)
140+
141+
# Main processing method
142+
def process(self):
143+
if self.res is None:
144+
# Then process
145+
146+
self.process_ctx()
147+
self.process_assignments()
148+
self.add_conntrack()
149+
150+
self.res = self.members
151+
152+
return self.res
142153

143154
# < class Conntrack
144155

145156
def create_connstrack_pystache_lists(nacl_state):
146-
nacl_state.create_pystache_data_lists([
157+
nacl_state.create_pystache_data_lists([
147158
TEMPLATE_KEY_CONNTRACKS
148-
])
159+
])
149160

150161
def init(nacl_state):
151162
# print "Init conntrack: Conntrack"

0 commit comments

Comments
 (0)