Skip to content

Commit 2956f73

Browse files
committed
ip4: packet filtering (RFC-1122) and experimental vip/loopback
1 parent dd44698 commit 2956f73

4 files changed

Lines changed: 154 additions & 19 deletions

File tree

api/net/ip4/addr.hpp

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -316,6 +316,23 @@ struct Addr {
316316
std::string to_string() const
317317
{ return str(); }
318318

319+
/**
320+
* RFC-1122 / IANA IP4 address space defines 127.* as loopback
321+
**/
322+
bool is_loopback() const noexcept
323+
{ return part(3) == 127; }
324+
325+
/**
326+
* Determine if an address is a-priori illegal as source address in *all* cases.
327+
*
328+
* @note: The class E range 240/4 for "future use" is not illegal here
329+
* @note: RFC-1122 prohibits 0.0.0.0 as source, but with exceptions
330+
*/
331+
bool is_illegal_src() const noexcept {
332+
return (part(3) >= 224 and part(3) < 240) // Multicast
333+
or (part(0) == 255); // Limited and directed broadcast
334+
}
335+
319336
/* Data member */
320337
uint32_t whole;
321338
} __attribute__((packed)); //< struct Addr

api/net/ip4/ip4.hpp

Lines changed: 44 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -30,12 +30,23 @@ namespace net {
3030
/** IP4 layer */
3131
class IP4 {
3232
public:
33+
34+
enum class Drop_reason
35+
{ None, Bad_source, Bad_destination, Wrong_version, Wrong_checksum,
36+
Unknown_proto, TTL0 };
37+
38+
enum class Direction
39+
{ Upstream, Downstream };
40+
41+
3342
using Stack = Inet<IP4>;
3443
using addr = ip4::Addr;
3544
using header = ip4::Header;
3645
using IP_packet = PacketIP4;
3746
using IP_packet_ptr = std::unique_ptr<IP_packet>;
3847
using downstream_arp = delegate<void(Packet_ptr, IP4::addr)>;
48+
using Packet_filter = delegate<IP_packet_ptr(IP_packet_ptr)>;
49+
using drop_handler = delegate<void(IP_packet_ptr, Direction, Drop_reason)>;
3950

4051
/** Initialize. Sets a dummy linklayer out. */
4152
explicit IP4(Stack&) noexcept;
@@ -69,14 +80,25 @@ namespace net {
6980
void set_tcp_handler(upstream s)
7081
{ tcp_handler_ = s; }
7182

83+
/** Set packet dropped handler */
84+
void set_drop_handler(drop_handler s)
85+
{ drop_handler_ = s; }
86+
7287
/** Set handler for packets not addressed to this interface (upstream) */
7388
void set_packet_forwarding(Stack::Forward_delg fwd)
7489
{ forward_packet_ = fwd; }
7590

7691
/** Set linklayer out (downstream) */
7792
void set_linklayer_out(downstream_arp s)
78-
{ linklayer_out_ = s; };
93+
{ linklayer_out_ = s; }
7994

95+
/** Assign function to determine which upstream packets gets filtered */
96+
void set_upstream_filter(Packet_filter f)
97+
{ upstream_filter_ = f; }
98+
99+
/** Assign function to determine which downstream packets gets filtered */
100+
void set_downstream_filter(Packet_filter f)
101+
{ downstream_filter_ = f; }
80102

81103
//
82104
// Delegate getters
@@ -120,6 +142,7 @@ namespace net {
120142
return stack_.ip_addr();
121143
}
122144

145+
123146
/**
124147
* Stats getters
125148
**/
@@ -132,6 +155,15 @@ namespace net {
132155
uint64_t get_packets_dropped()
133156
{ return packets_dropped_; }
134157

158+
/** Default upstream packet filter */
159+
IP_packet_ptr filter_upstream(IP_packet_ptr packet);
160+
161+
/** Default downstream packet filter */
162+
IP_packet_ptr filter_downstream(IP_packet_ptr packet);
163+
164+
165+
166+
135167
private:
136168
/** Stats */
137169
uint64_t& packets_rx_;
@@ -151,9 +183,19 @@ namespace net {
151183
/** Packet forwarding */
152184
Stack::Forward_delg forward_packet_;
153185

154-
}; //< class IP4
186+
/** Packet filters */
187+
Packet_filter upstream_filter_;
188+
Packet_filter downstream_filter_;
155189

156190

191+
/** All dropped packets go here */
192+
drop_handler drop_handler_;
193+
194+
/** Drop a packet, calling drop handler if set */
195+
IP_packet_ptr drop(IP_packet_ptr ptr, Direction direction, Drop_reason reason);
196+
197+
}; //< class IP4
198+
157199
} //< namespace net
158200

159201
#endif

api/net/ip4/packet_ip4.hpp

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,10 @@ namespace net {
3939

4040
/** Get IP protocol version field. Must be 4 (RFC 1122) */
4141
uint8_t ip_version() const noexcept
42-
{ return ip_header().version_ihl & 0x0f; }
42+
{ return (ip_header().version_ihl >> 4) & 0xf; }
43+
44+
bool is_ipv4() const noexcept
45+
{ return (ip_header().version_ihl & 0xf0) == 0x40; }
4346

4447
/** Get IP header length field as-is. */
4548
uint8_t ip_ihl() const noexcept
@@ -71,7 +74,7 @@ namespace net {
7174

7275
/** Get Fragment offset field */
7376
uint16_t ip_frag_offs() const noexcept
74-
{ return ntohs(ip_header().frag_off_flags) | 0xe; }
77+
{ return ntohs(ip_header().frag_off_flags) & 0xe; }
7578

7679
/** Get Time-To-Live field */
7780
uint8_t ip_ttl() const noexcept
@@ -104,6 +107,9 @@ namespace net {
104107
uint16_t ip_capacity() const noexcept
105108
{ return capacity() - ip_header_length(); }
106109

110+
/** Compute IP header checksum on header as-is */
111+
uint16_t compute_checksum() noexcept
112+
{ return net::checksum(&ip_header(), ip_header_length()); };
107113

108114

109115
//
@@ -208,6 +214,8 @@ namespace net {
208214
hdr.frag_off_flags = 0;
209215
hdr.ttl = DEFAULT_TTL;
210216
hdr.protocol = static_cast<uint8_t>(proto);
217+
hdr.check = 0;
218+
hdr.tot_len = 0x1400; // Big-endian 20
211219
increment_data_end(sizeof(IP4::header));
212220
}
213221

@@ -219,7 +227,6 @@ namespace net {
219227
return {ip_data_ptr(), ip_data_length()};
220228
}
221229

222-
223230
protected:
224231

225232
/** Get pointer to IP data */

src/net/ip4/ip4.cpp

Lines changed: 83 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -15,8 +15,8 @@
1515
// See the License for the specific language governing permissions and
1616
// limitations under the License.
1717

18-
// #define DEBUG // Allow debugging
19-
// #define DEBUG2 // Allow debug lvl 2
18+
#define DEBUG // Allow debugging
19+
#define DEBUG2 // Allow debug lvl 2
2020

2121
#include <net/ip4/ip4.hpp>
2222
#include <net/ip4/packet_ip4.hpp>
@@ -32,33 +32,90 @@ namespace net {
3232
packets_rx_ {Statman::get().create(Stat::UINT64, inet.ifname() + ".ip4.packets_rx").get_uint64()},
3333
packets_tx_ {Statman::get().create(Stat::UINT64, inet.ifname() + ".ip4.packets_tx").get_uint64()},
3434
packets_dropped_ {Statman::get().create(Stat::UINT32, inet.ifname() + ".ip4.packets_dropped").get_uint32()},
35-
stack_ {inet}
35+
stack_ {inet},
36+
upstream_filter_ {this, &IP4::filter_upstream},
37+
downstream_filter_{this, &IP4::filter_downstream}
3638
{ }
3739

40+
41+
IP4::IP_packet_ptr IP4::drop(IP_packet_ptr ptr, Direction direction, Drop_reason reason) {
42+
packets_dropped_++;
43+
44+
if(drop_handler_)
45+
drop_handler_(std::move(ptr), direction, reason);
46+
47+
return nullptr;
48+
}
49+
50+
51+
IP4::IP_packet_ptr IP4::filter_upstream(IP4::IP_packet_ptr packet)
52+
{
53+
54+
IP4::Direction up = IP4::Direction::Upstream;
55+
56+
// RFC-1122 3.2.1.1, Silently discard Version != 4
57+
if (UNLIKELY(not packet->is_ipv4()))
58+
return drop(std::move(packet), up, Drop_reason::Wrong_version);
59+
60+
// RFC-1122 3.2.1.2, Verify IP checksum, silently discard bad dgram
61+
if (UNLIKELY(packet->compute_checksum() != 0))
62+
return drop(std::move(packet), up, Drop_reason::Wrong_checksum);
63+
64+
// RFC-1122 3.2.1.3, Silently discard datagram with bad src addr
65+
if (UNLIKELY(packet->ip_src().is_illegal_src()))
66+
return drop(std::move(packet), up, Drop_reason::Bad_source);
67+
68+
69+
return packet;
70+
71+
};
72+
73+
74+
IP4::IP_packet_ptr IP4::filter_downstream(IP4::IP_packet_ptr packet)
75+
{
76+
77+
// RFC-1122 3.2.1.7, MUST NOT send packet with TTL of 0
78+
if (packet->ip_ttl() == 0)
79+
return drop(std::move(packet), Direction::Downstream, Drop_reason::TTL0);
80+
81+
// RFC-1122 3.2.1.7, MUST NOT send packet addressed to 127.*
82+
if (packet->ip_dst().part(0) == 127)
83+
drop(std::move(packet), Direction::Downstream, Drop_reason::Bad_destination);
84+
85+
return packet;
86+
}
87+
88+
3889
void IP4::receive(Packet_ptr pckt)
3990
{
4091
// Cast to IP4 Packet
4192
auto packet = static_unique_ptr_cast<net::PacketIP4>(std::move(pckt));
4293

43-
// Stat increment packets received
44-
packets_rx_++;
45-
46-
debug2("\t Source IP: %s Dest.IP: %s Type: 0x%x\n",
94+
debug("<IP4> received packet \n");
95+
debug2("\t* Source IP: %s Dest.IP: %s Type: 0x%x\n",
4796
packet->ip_src().str().c_str(),
4897
packet->ip_dst().str().c_str(),
4998
packet->ip_protocol());
5099

51-
// Drop if my ip address doesn't match destination ip address or broadcast
100+
101+
// Stat increment packets received
102+
packets_rx_++;
103+
104+
packet = upstream_filter_(std::move(packet));
105+
if (UNLIKELY(packet == nullptr)) return;
106+
107+
// Drop / forward if my ip address doesn't match dest. or broadcast
52108
if (UNLIKELY(packet->ip_dst() != local_ip()
53-
and (packet->ip_dst() | stack_.netmask()) != ADDR_BCAST
54-
and local_ip() != ADDR_ANY)) {
109+
and (packet->ip_dst() | stack_.netmask()) != ADDR_BCAST
110+
and local_ip() != ADDR_ANY
111+
and not stack_.is_loopback(packet->ip_dst()))) {
55112

56113
if (forward_packet_) {
57114
forward_packet_(stack_, std::move(packet));
58115
debug("Packet forwarded \n");
59116
} else {
60117
debug("Packet dropped \n");
61-
packets_dropped_++;
118+
drop(std::move(packet), Direction::Upstream, Drop_reason::Bad_destination);
62119
}
63120

64121
return;
@@ -79,6 +136,7 @@ namespace net {
79136
break;
80137
default:
81138
debug("\t Type: UNKNOWN %hhu\n", packet->ip_protocol());
139+
drop(std::move(packet), Direction::Upstream, Drop_reason::Unknown_proto);
82140
break;
83141
}
84142
}
@@ -97,8 +155,15 @@ namespace net {
97155
{
98156
auto ip4_pckt = static_unique_ptr_cast<PacketIP4>(std::move(pckt));
99157

158+
// Send loopback packets right back
159+
if (UNLIKELY(stack_.is_loopback(ip4_pckt->ip_dst()))) {
160+
debug("<IP4> Destination address is loopback \n");
161+
IP4::receive(std::move(ip4_pckt));
162+
return;
163+
}
164+
100165
addr next_hop;
101-
// Keep IP when broadcasting to all
166+
102167
if (ip4_pckt->ip_dst() != IP4::ADDR_BCAST)
103168
{
104169
// Create local and target subnets
@@ -114,11 +179,15 @@ namespace net {
114179
stack_.ip_addr().str().c_str(),
115180
stack_.gateway().str().c_str(),
116181
next_hop.str().c_str());
117-
}
118-
else {
182+
183+
} else {
119184
next_hop = IP4::ADDR_BCAST;
120185
}
121186

187+
// Filter illegal egress packets
188+
ip4_pckt = upstream_filter_(std::move(ip4_pckt));
189+
if (ip4_pckt == nullptr) return;
190+
122191
// Stat increment packets transmitted
123192
packets_tx_++;
124193

0 commit comments

Comments
 (0)