<commit_before>// This file is a part of the IncludeOS unikernel - www.includeos.org
//
// Copyright 2015 Oslo and Akershus University College of Applied Sciences
// and <NAME>
//
// 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.

//#define IP_DEBUG 1
#ifdef IP_DEBUG
#define PRINT(fmt, ...) printf(fmt, ##__VA_ARGS__)
#else
#define PRINT(fmt, ...) /* fmt */
#endif

#include <net/ip4/ip4.hpp>
#include <net/ip4/packet_ip4.hpp>
#include <net/packet.hpp>
#include <statman>
#include <net/ip4/icmp4.hpp>

namespace net {

  const IP4::addr IP4::ADDR_ANY(0);
  const IP4::addr IP4::ADDR_BCAST(0xff,0xff,0xff,0xff);

  IP4::IP4(Stack& inet) noexcept :
  packets_rx_       {Statman::get().create(Stat::UINT64, inet.ifname() + ".ip4.packets_rx").get_uint64()},
  packets_tx_       {Statman::get().create(Stat::UINT64, inet.ifname() + ".ip4.packets_tx").get_uint64()},
  packets_dropped_  {Statman::get().create(Stat::UINT32, inet.ifname() + ".ip4.packets_dropped").get_uint32()},
  stack_            {inet}
  {}


  IP4::IP_packet_ptr IP4::drop(IP_packet_ptr ptr, Direction direction, Drop_reason reason) {
    packets_dropped_++;

    if(drop_handler_)
      drop_handler_(std::move(ptr), direction, reason);

    return nullptr;
  }


  IP4::IP_packet_ptr IP4::drop_invalid_in(IP4::IP_packet_ptr packet)
  {
    IP4::Direction up = IP4::Direction::Upstream;

    // RFC-1122 3.2.1.1, Silently discard Version != 4
    if (UNLIKELY(not packet->is_ipv4()))
      return drop(std::move(packet), up, Drop_reason::Wrong_version);

    // RFC-1122 3.2.1.2, Verify IP checksum, silently discard bad dgram
    if (UNLIKELY(packet->compute_checksum() != 0))
      return drop(std::move(packet), up, Drop_reason::Wrong_checksum);

    // RFC-1122 3.2.1.3, Silently discard datagram with bad src addr
    // Here dropping if the source ip address is a multicast address or is this interface's broadcast address
    if (UNLIKELY(packet->ip_src().is_multicast() or packet->ip_src() == IP4::ADDR_BCAST or
      packet->ip_src() == stack_.broadcast_addr())) {
      return drop(std::move(packet), up, Drop_reason::Bad_source);
    }

    return packet;
  }


  IP4::IP_packet_ptr IP4::drop_invalid_out(IP4::IP_packet_ptr packet)
  {
    // RFC-1122 3.2.1.7, MUST NOT send packet with TTL of 0
    if (packet->ip_ttl() == 0)
      return drop(std::move(packet), Direction::Downstream, Drop_reason::TTL0);

    // RFC-1122 3.2.1.7, MUST NOT send packet addressed to 127.*
    if (packet->ip_dst().part(0) == 127)
      drop(std::move(packet), Direction::Downstream, Drop_reason::Bad_destination);

    return packet;
  }

  /*
   * RFC 1122, p. 30
   * An incoming datagram is destined
     for the host if the datagram's destination address field is:
     (1)  (one of) the host's IP address(es); or
     (2)  an IP broadcast address valid for the connected
          network; or
     (3)  the address for a multicast group of which the host is
          a member on the incoming physical interface.
  */
  bool IP4::is_for_me(ip4::Addr dst) const
  {
    return stack_.is_valid_source(dst)
      or (dst | stack_.netmask()) == ADDR_BCAST
      or local_ip() == ADDR_ANY;
  }

  void IP4::receive(Packet_ptr pckt, const bool link_bcast)
  {
    // Cast to IP4 Packet
    auto packet = static_unique_ptr_cast<net::PacketIP4>(std::move(pckt));

    PRINT("<IP4 Receive> Source IP: %s Dest.IP: %s Type: 0x%x LinkBcast: %d ",
           packet->ip_src().str().c_str(),
           packet->ip_dst().str().c_str(),
           (int) packet->ip_protocol(),
           link_bcast);
    switch (packet->ip_protocol()) {
    case Protocol::ICMPv4:
       PRINT("Type: ICMP\n"); break;
    case Protocol::UDP:
       PRINT("Type: UDP\n"); break;
    case Protocol::TCP:
       PRINT("Type: TCP\n"); break;
    default:
       PRINT("Type: UNKNOWN %hhu. Dropping. \n", packet->ip_protocol());
    }

    // Stat increment packets received
    packets_rx_++;

    packet = drop_invalid_in(std::move(packet));
    if (UNLIKELY(packet == nullptr)) return;

    /* PREROUTING */
    // Track incoming packet if conntrack is active
    Conntrack::Entry_ptr ct = (stack_.conntrack())
      ? stack_.conntrack()->in(*packet) : nullptr;
    auto res = prerouting_chain_(*packet, stack_, ct);
    if (UNLIKELY(res == Filter_verdict::DROP)) return;


    // Drop / forward if my ip address doesn't match dest. or broadcast
    if(not is_for_me(packet->ip_dst())) {
      if (forward_packet_) {
        forward_packet_(stack_, std::move(packet));
        PRINT("Packet forwarded \n");<commit_msg>ip4: loopback check now uses is_valid_source<commit_after>// This file is a part of the IncludeOS unikernel - www.includeos.org
//
// Copyright 2015 Oslo and Akershus University College of Applied Sciences
// and <NAME>
//
// 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.

//#define IP_DEBUG 1
#ifdef IP_DEBUG
#define PRINT(fmt, ...) printf(fmt, ##__VA_ARGS__)
#else
#define PRINT(fmt, ...) /* fmt */
#endif

#include <net/ip4/ip4.hpp>
#include <net/ip4/packet_ip4.hpp>
#include <net/packet.hpp>
#include <statman>
#include <net/ip4/icmp4.hpp>

namespace net {

  const IP4::addr IP4::ADDR_ANY(0);
  const IP4::addr IP4::ADDR_BCAST(0xff,0xff,0xff,0xff);

  IP4::IP4(Stack& inet) noexcept :
  packets_rx_       {Statman::get().create(Stat::UINT64, inet.ifname() + ".ip4.packets_rx").get_uint64()},
  packets_tx_       {Statman::get().create(Stat::UINT64, inet.ifname() + ".ip4.packets_tx").get_uint64()},
  packets_dropped_  {Statman::get().create(Stat::UINT32, inet.ifname() + ".ip4.packets_dropped").get_uint32()},
  stack_            {inet}
  {}


  IP4::IP_packet_ptr IP4::drop(IP_packet_ptr ptr, Direction direction, Drop_reason reason) {
    packets_dropped_++;

    if(drop_handler_)
      drop_handler_(std::move(ptr), direction, reason);

    return nullptr;
  }


  IP4::IP_packet_ptr IP4::drop_invalid_in(IP4::IP_packet_ptr packet)
  {
    IP4::Direction up = IP4::Direction::Upstream;

    // RFC-1122 3.2.1.1, Silently discard Version != 4
    if (UNLIKELY(not packet->is_ipv4()))
      return drop(std::move(packet), up, Drop_reason::Wrong_version);

    // RFC-1122 3.2.1.2, Verify IP checksum, silently discard bad dgram
    if (UNLIKELY(packet->compute_checksum() != 0))
      return drop(std::move(packet), up, Drop_reason::Wrong_checksum);

    // RFC-1122 3.2.1.3, Silently discard datagram with bad src addr
    // Here dropping if the source ip address is a multicast address or is this interface's broadcast address
    if (UNLIKELY(packet->ip_src().is_multicast() or packet->ip_src() == IP4::ADDR_BCAST or
      packet->ip_src() == stack_.broadcast_addr())) {
      return drop(std::move(packet), up, Drop_reason::Bad_source);
    }

    return packet;
  }


  IP4::IP_packet_ptr IP4::drop_invalid_out(IP4::IP_packet_ptr packet)
  {
    // RFC-1122 3.2.1.7, MUST NOT send packet with TTL of 0
    if (packet->ip_ttl() == 0)
      return drop(std::move(packet), Direction::Downstream, Drop_reason::TTL0);

    // RFC-1122 3.2.1.7, MUST NOT send packet addressed to 127.*
    if (packet->ip_dst().part(0) == 127)
      drop(std::move(packet), Direction::Downstream, Drop_reason::Bad_destination);

    return packet;
  }

  /*
   * RFC 1122, p. 30
   * An incoming datagram is destined
     for the host if the datagram's destination address field is:
     (1)  (one of) the host's IP address(es); or
     (2)  an IP broadcast address valid for the connected
          network; or
     (3)  the address for a multicast group of which the host is
          a member on the incoming physical interface.
  */
  bool IP4::is_for_me(ip4::Addr dst) const
  {
    return stack_.is_valid_source(dst)
      or (dst | stack_.netmask()) == ADDR_BCAST
      or local_ip() == ADDR_ANY;
  }

  void IP4::receive(Packet_ptr pckt, const bool link_bcast)
  {
    // Cast to IP4 Packet
    auto packet = static_unique_ptr_cast<net::PacketIP4>(std::move(pckt));

    PRINT("<IP4 Receive> Source IP: %s Dest.IP: %s Type: 0x%x LinkBcast: %d ",
           packet->ip_src().str().c_str(),
           packet->ip_dst().str().c_str(),
           (int) packet->ip_protocol(),
           link_bcast);
    switch (packet->ip_protocol()) {
    case Protocol::ICMPv4:
       PRINT("Type: ICMP\n"); break;
    case Protocol::UDP:
       PRINT("Type: UDP\n"); break;
    case Protocol::TCP:
       PRINT("Type: TCP\n"); break;
    default:
       PRINT("Type: UNKNOWN %hhu. Dropping. \n", packet->ip_protocol());
    }

    // Stat increment packets received
    packets_rx_++;

    packet = drop_invalid_in(std::move(packet));
    if (UNLIKELY(packet == nullptr)) return;

    /* PREROUTING */
    // Track incoming packet if conntrack is active
    Conntrack::Entry_ptr ct = (stack_.conntrack())
      ? stack_.conntrack()->in(*packet) : nullptr;
    auto res = prerouting_chain_(*packet, stack_, ct);
    if (UNLIKELY(res == Filter_verdict::DROP)) return;


    // Drop / forward if my ip address doesn't match dest. or broadcast
    if(not stack_.is_valid_source(packet->ip_dst())) {
      if (forward_packet_) {
        forward_packet_(stack_, std::move(packet));
        PRINT("Packet forwarded \n");
{'fraction_non_alphanumeric': 0.13922804253643167, 'fraction_numerical': 0.024123670736510436, 'mean_word_length': 3.3912667531344574, 'pattern_counts': {'":': 0, '<': 19, '<?xml version=': 0, '>': 47, 'https://': 0, 'lorem ipsum': 0, 'www.': 4, 'xml': 0}, 'pii_count': 10, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '1262355', 'n_tokens_mistral': 3561, 'n_tokens_neox': 3354, 'n_words': 908}