/*
   p0f - packet capture and overall host / flow bookkeeping
   --------------------------------------------------------

   Copyright (C) 2012 by Michal Zalewski <lcamtuf@coredump.cx>

   Distributed under the terms and conditions of GNU LGPL.

 */

#ifndef _HAVE_PROCESS_H
#define _HAVE_PROCESS_H

#include <pcap.h>

#include "types.h"
#include "fp_tcp.h"
#include "fp_http.h"

/* Parsed information handed over by the pcap callback: */

struct packet_data {

  u8  ip_ver;                           /* IP_VER4, IP_VER6                   */
  u8  tcp_type;                         /* TCP_SYN, ACK, FIN, RST             */

  u8  src[16];                          /* Source address (left-aligned)      */
  u8  dst[16];                          /* Destination address (left-aligned  */

  u16 sport;                            /* Source port                        */
  u16 dport;                            /* Destination port                   */

  u8  ttl;                              /* Observed TTL                       */
  u8  tos;                              /* IP ToS value                       */

  u16 mss;                              /* Maximum segment size               */
  u16 win;                              /* Window size                        */
  u8  wscale;                           /* Window scaling                     */
  u16 tot_hdr;                          /* Total headers (for MTU calc)       */

  u8  opt_layout[MAX_TCP_OPT];          /* Ordering of TCP options            */
  u8  opt_cnt;                          /* Count of TCP options               */
  u8  opt_eol_pad;                      /* Amount of padding past EOL         */

  u32 ts1;                              /* Own timestamp                      */

  u32 quirks;                           /* QUIRK_*                            */

  u8  ip_opt_len;                       /* Length of IP options               */

  u8* payload;                          /* TCP payload                        */
  u16 pay_len;                          /* Length of TCP payload              */

  u32 seq;                              /* seq value seen                     */

};

/* IP-level quirks: */

#define QUIRK_ECN            0x00000001 /* ECN supported                      */
#define QUIRK_DF             0x00000002 /* DF used (probably PMTUD)           */
#define QUIRK_NZ_ID          0x00000004 /* Non-zero IDs when DF set           */
#define QUIRK_ZERO_ID        0x00000008 /* Zero IDs when DF not set           */
#define QUIRK_NZ_MBZ         0x00000010 /* IP "must be zero" field isn't      */
#define QUIRK_FLOW           0x00000020 /* IPv6 flows used                    */

/* Core TCP quirks: */

#define QUIRK_ZERO_SEQ       0x00001000 /* SEQ is zero                        */
#define QUIRK_NZ_ACK         0x00002000 /* ACK non-zero when ACK flag not set */
#define QUIRK_ZERO_ACK       0x00004000 /* ACK is zero when ACK flag set      */
#define QUIRK_NZ_URG         0x00008000 /* URG non-zero when URG flag not set */
#define QUIRK_URG            0x00010000 /* URG flag set                       */
#define QUIRK_PUSH           0x00020000 /* PUSH flag on a control packet      */

/* TCP option quirks: */

#define QUIRK_OPT_ZERO_TS1   0x01000000 /* Own timestamp set to zero          */
#define QUIRK_OPT_NZ_TS2     0x02000000 /* Peer timestamp non-zero on SYN     */
#define QUIRK_OPT_EOL_NZ     0x04000000 /* Non-zero padding past EOL          */
#define QUIRK_OPT_EXWS       0x08000000 /* Excessive window scaling           */
#define QUIRK_OPT_BAD        0x10000000 /* Problem parsing TCP options        */

/* Host record with persistent fingerprinting data: */

struct host_data {

  struct host_data *prev, *next;        /* Linked lists                       */
  struct host_data *older, *newer;
  u32 use_cnt;                          /* Number of packet_flows attached    */

  u32 first_seen;                       /* Record created (unix time)         */
  u32 last_seen;                        /* Host last seen (unix time)         */
  u32 total_conn;                       /* Total number of connections ever   */

  u8 ip_ver;                            /* Address type                       */
  u8 addr[16];                          /* Host address data                  */

  struct tcp_sig* last_syn;             /* Sig of the most recent SYN         */
  struct tcp_sig* last_synack;          /* Sig of the most recent SYN+ACK     */

  s32 last_class_id;                    /* OS class ID (-1 = not found)       */
  s32 last_name_id;                     /* OS name ID (-1 = not found)        */
  u8* last_flavor;                      /* Last OS flavor                     */

  u8  last_quality;                     /* Generic or fuzzy match?            */

  u8* link_type;                        /* MTU-derived link type              */

  u8  cli_scores[NAT_SCORES];           /* Scoreboard for client NAT          */
  u8  srv_scores[NAT_SCORES];           /* Scoreboard for server NAT          */
  u16 nat_reasons;                      /* NAT complaints                     */

  u32 last_nat;                         /* Last NAT detection time            */
  u32 last_chg;                         /* Last OS change detection time      */

  u16 last_port;                        /* Source port on last SYN            */

  u8  distance;                         /* Last measured distance             */

  s32 last_up_min;                      /* Last computed uptime (-1 = none)   */
  u32 up_mod_days;                      /* Uptime modulo (days)               */

  /* HTTP business: */

  struct http_sig* http_req_os;         /* Last request, if class != -1       */
  struct http_sig* http_resp;           /* Last response                      */

  s32 http_name_id;                     /* Client name ID (-1 = not found)    */
  u8* http_flavor;                      /* Client flavor                      */

  u8* language;                         /* Detected language                  */

  u8  bad_sw;                           /* Used dishonest U-A or Server?      */

  u16 http_resp_port;                   /* Port on which response seen        */

};

/* Reasons for NAT detection: */

#define NAT_APP_SIG          0x0001     /* App signature <-> OS mismatch      */
#define NAT_OS_SIG           0x0002     /* OS detection mismatch              */
#define NAT_UNK_DIFF         0x0004     /* Current sig unknown, but different */
#define NAT_TO_UNK           0x0008     /* Sig changed from known to unknown  */
#define NAT_TS               0x0010     /* Timestamp goes back                */
#define NAT_PORT             0x0020     /* Source port goes back              */
#define NAT_TTL              0x0040     /* TTL changes unexpectedly           */
#define NAT_FUZZY            0x0080     /* Signature fuzziness changes        */
#define NAT_MSS              0x0100     /* MSS changes                        */

#define NAT_APP_LB           0x0200     /* Server signature changes           */
#define NAT_APP_VIA          0x0400     /* Via / X-Forwarded-For seen         */
#define NAT_APP_DATE         0x0800     /* Date changes in a weird way        */
#define NAT_APP_UA           0x1000     /* User-Agent OS inconsistency        */

/* TCP flow record, maintained until all fingerprinting modules are happy: */

struct packet_flow {

  struct packet_flow *prev, *next;      /* Linked lists                       */
  struct packet_flow *older, *newer;
  u32 bucket;                           /* Bucket this flow belongs to        */

  struct host_data* client;             /* Requesting client                  */
  struct host_data* server;             /* Target server                      */

  u16 cli_port;                         /* Client port                        */
  u16 srv_port;                         /* Server port                        */

  u8  acked;                            /* SYN+ACK received?                  */
  u8  sendsyn;                          /* Created by p0f-sendsyn?            */

  s16 srv_tps;                          /* Computed TS divisor (-1 = bad)     */ 
  s16 cli_tps;

  u8* request;                          /* Client-originating data            */
  u32 req_len;                          /* Captured data length               */
  u32 next_cli_seq;                     /* Next seq on cli -> srv packet      */

  u8* response;                         /* Server-originating data            */
  u32 resp_len;                         /* Captured data length               */
  u32 next_srv_seq;                     /* Next seq on srv -> cli packet      */
  u16 syn_mss;                          /* MSS on SYN packet                  */

  u32 created;                          /* Flow creation date (unix time)     */

  /* Application-level fingerprinting: */

  s8  in_http;                          /* 0 = tbd, 1 = yes, -1 = no          */

  u8  http_req_done;                    /* Done collecting req headers?       */
  u32 http_pos;                         /* Current parsing offset             */
  u8  http_gotresp1;                    /* Got initial line of a response?    */

  struct http_sig http_tmp;             /* Temporary signature                */

};

extern u64 packet_cnt;

void parse_packet(void* junk, const struct pcap_pkthdr* hdr, const u8* data);

u8* addr_to_str(u8* data, u8 ip_ver);

u64 get_unix_time_ms(void);
u32 get_unix_time(void);

void add_nat_score(u8 to_srv, struct packet_flow* f, u16 reason, u8 score);
void verify_tool_class(u8 to_srv, struct packet_flow* f, u32* sys, u32 sys_cnt);

struct host_data* lookup_host(u8* addr, u8 ip_ver);

void destroy_all_hosts(void);

#endif /* !_HAVE_PROCESS_H */