<commit_before>/*
  Copyright (C) 2016 Eneo Tecnologia S.L.
  Author: <NAME> <<EMAIL>>
  Based on Luca Deri nprobe 6.22 collector

  This program is free software; you can redistribute it and/or modify
  it under the terms of the GNU Affero General Public License as
  published by the Free Software Foundation, either version 3 of the
  License, or (at your option) any later version.

  This program is distributed in the hope that it will be useful,
  but WITHOUT ANY WARRANTY; without even the implied warranty of
  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  GNU Affero General Public License for more details.

  You should have received a copy of the GNU General Public License
  along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */

 // @TODO check all real_field_offset and real_field_len

#include "export.h"
#include "util.h"
#include "rb_mac.h"
#include "rb_sensor.h"

#ifdef HAVE_UDNS
#include "rb_dns_cache.h"
#endif

#include <librd/rdfile.h>

#define NETFLOW_DIRECTION_INGRESS 0
#define NETFLOW_DIRECTION_EGRESS  1

typedef enum{
  DIRECTION_UNSET,
  DIRECTION_INGRESS,
  DIRECTION_EGRESS,
  DIRECTION_INTERNAL,
} direction_t;

struct flowCache *new_flowCache(){
  return calloc(1,sizeof(struct flowCache));
}

void associateSensor(struct flowCache *flowCache, struct sensor *sensor){
  flowCache->sensor = sensor;
}

void free_flowCache(struct flowCache *cache){
  free(cache);
}

static int ip_direction(int known_src,int known_dst) {
  if(!known_src && known_dst) {
    return DIRECTION_EGRESS;
  } else if(known_src && !known_dst) {
    return DIRECTION_INGRESS;
  } else if(known_src && known_dst) {
    return DIRECTION_INTERNAL;
  }
  // No "external"
  return DIRECTION_UNSET;
}

static int mac_direction(int known_src,int known_dst) {
  if(known_src && !known_dst) {
    return DIRECTION_EGRESS;
  } else if(!known_src && known_dst) {
    return DIRECTION_INGRESS;
  }

  // else no idea
  return DIRECTION_UNSET;
}

/*
  Try to guess direction based on source and destination address
  return: 1 if guessed/already setted. 0 if couldn't set
*/
int guessDirection(struct flowCache *cache){
  // Don't trust in flow direction unless there is no choice
  // if(cache->macs.direction != DIRECTION_UNSET){
  //  return 1; /* no need to guess */
  //}

  if(sensor_has_mac_db(cache->sensor)) {
    const uint64_t src_mac_as_num = net2number((const char *)cache->macs.src_mac,6);
    const uint64_t dst_mac_as_num = is_span_sensor(cache->sensor) ?
      net2number((const char *)cache->macs.dst_mac,6) :
      net2number((const char *)cache->macs.post_dst_mac,6);

    const int src_mac_is_router = sensor_has_router_mac(cache->sensor,src_mac_as_num);
    const int dst_mac_is_router = sensor_has_router_mac(cache->sensor,dst_mac_as_num);

    if(0!=src_mac_as_num && valid_mac(src_mac_as_num)
       && 0!=dst_mac_as_num && valid_mac(dst_mac_as_num)) {

      const int mac_guessed_direction = mac_direction(src_mac_is_router,dst_mac_is_router);
      if(mac_guessed_direction != DIRECTION_UNSET) {
        cache->macs.direction = mac_guessed_direction;
        return 1;
      }
    }
  }

  if(0 == cache->address.src || 0 == cache->address.dst){
    /* Can't guess direction */
    return -1;
  }

  const int src_ip_in_home_net = NULL!=network_ip(cache->sensor,cache->address.src);
  const int dst_ip_in_home_net = NULL!=network_ip(cache->sensor,cache->address.dst);

  const int ip_guessed_direction = ip_direction(src_ip_in_home_net,dst_ip_in_home_net);
  if(ip_guessed_direction != DIRECTION_UNSET) {
    cache->macs.direction = ip_guessed_direction;
    return 1;
  }

  return 1;
}

#if 0
/* Just for templating */
/*<commit_msg>:bug: Fix invalid memory check<commit_after>/*
  Copyright (C) 2016 Eneo Tecnologia S.L.
  Author: <NAME> <<EMAIL>>
  Based on <NAME> nprobe 6.22 collector

  This program is free software; you can redistribute it and/or modify
  it under the terms of the GNU Affero General Public License as
  published by the Free Software Foundation, either version 3 of the
  License, or (at your option) any later version.

  This program is distributed in the hope that it will be useful,
  but WITHOUT ANY WARRANTY; without even the implied warranty of
  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  GNU Affero General Public License for more details.

  You should have received a copy of the GNU General Public License
  along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */

 // @TODO check all real_field_offset and real_field_len

#include "export.h"
#include "util.h"
#include "rb_mac.h"
#include "rb_sensor.h"

#ifdef HAVE_UDNS
#include "rb_dns_cache.h"
#endif

#include <librd/rdfile.h>

#define NETFLOW_DIRECTION_INGRESS 0
#define NETFLOW_DIRECTION_EGRESS  1

typedef enum{
  DIRECTION_UNSET,
  DIRECTION_INGRESS,
  DIRECTION_EGRESS,
  DIRECTION_INTERNAL,
} direction_t;

struct flowCache *new_flowCache(){
  return calloc(1,sizeof(struct flowCache));
}

void associateSensor(struct flowCache *flowCache, struct sensor *sensor){
  flowCache->sensor = sensor;
}

void free_flowCache(struct flowCache *cache){
  free(cache);
}

static int ip_direction(int known_src,int known_dst) {
  if(!known_src && known_dst) {
    return DIRECTION_EGRESS;
  } else if(known_src && !known_dst) {
    return DIRECTION_INGRESS;
  } else if(known_src && known_dst) {
    return DIRECTION_INTERNAL;
  }
  // No "external"
  return DIRECTION_UNSET;
}

static int mac_direction(int known_src,int known_dst) {
  if(known_src && !known_dst) {
    return DIRECTION_EGRESS;
  } else if(!known_src && known_dst) {
    return DIRECTION_INGRESS;
  }

  // else no idea
  return DIRECTION_UNSET;
}

/*
  Try to guess direction based on source and destination address
  return: 1 if guessed/already setted. 0 if couldn't set
*/
int guessDirection(struct flowCache *cache){
  static const char zeros[sizeof(cache->address.src)] = {0};
  // Don't trust in flow direction unless there is no choice
  // if(cache->macs.direction != DIRECTION_UNSET){
  //  return 1; /* no need to guess */
  //}

  if(sensor_has_mac_db(cache->sensor)) {
    const uint64_t src_mac_as_num = net2number((const char *)cache->macs.src_mac,6);
    const uint64_t dst_mac_as_num = is_span_sensor(cache->sensor) ?
      net2number((const char *)cache->macs.dst_mac,6) :
      net2number((const char *)cache->macs.post_dst_mac,6);

    const int src_mac_is_router = sensor_has_router_mac(cache->sensor,src_mac_as_num);
    const int dst_mac_is_router = sensor_has_router_mac(cache->sensor,dst_mac_as_num);

    if(0!=src_mac_as_num && valid_mac(src_mac_as_num)
       && 0!=dst_mac_as_num && valid_mac(dst_mac_as_num)) {

      const int mac_guessed_direction = mac_direction(src_mac_is_router,dst_mac_is_router);
      if(mac_guessed_direction != DIRECTION_UNSET) {
        cache->macs.direction = mac_guessed_direction;
        return 1;
      }
    }
  }

  if (0 == memcmp(cache->address.src, zeros, sizeof(cache->address.src)) ||
      0 == memcmp(cache->address.dst, zeros, sizeof(cache->address.dst))) {
    /* Can't guess direction */
    return -1;
  }

  const int src_ip_in_home_net = NULL!=network_ip(cache->sensor,cache->address.src);
  const int dst_ip_in_home_net = NULL!=network_ip(cache->sensor,cache->address.dst);

  const int ip_guessed_direction = ip_direction(src_ip_in_home_net,dst_ip_in_home_net);
  if(ip_guessed_direction != DIRECTION_UNSET) {
    cache->macs.direction = ip_guessed_direction;
    return 1;
  }

  return 1;
}

#if 0
/* Just for templating */
/*
{'fraction_non_alphanumeric': 0.10215409012818819, 'fraction_numerical': 0.008854235496233646, 'mean_word_length': 4.190672153635116, 'pattern_counts': {'":': 0, '<': 14, '<?xml version=': 0, '>': 51, 'https://': 0, 'lorem ipsum': 0, 'www.': 2, 'xml': 0}, 'pii_count': 0, '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': '429157', 'n_tokens_mistral': 2664, 'n_tokens_neox': 2595, 'n_words': 669}