#include <unistd.h>
#include <stdlib.h>
#include <limits.h>
#include <string.h>
#include <ctype.h>
#include <stdio.h>
#include <stdarg.h>
#include <fcntl.h>
#include <signal.h>
#include <setjmp.h>
#include <errno.h>
#include <netdb.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/time.h>
#include <sys/ioctl.h>
#include <sys/stat.h>
#include <net/if.h>
#include <netinet/in.h>
#include <netinet/tcp.h>
#include <arpa/inet.h>
#include "zlib.h"
#include "sdb.h"


/* #define NO_TCP 1 */          /* disable TCP at all */
/* #define TRACE_PACKET_TIME 1 */ /* include (relative) timestaps into log */
#define TCP_NODELAY_OPTION 1    /* activate this option for TCP connections */
/* #define SO_SNDBUF_SIZE 2048 */ /* set send buffer for TCP sockets */

#define NO_ETHERNET_II_HOPS 1	/* discards packets from Ethernet with a hop
                                   count > 0 if only Ethernet II and bpf is
				   used */
#define USE_BPF_BUFFERING 1	/* bpf is read by an own daemon */

#define DEFAULT_UDP_PORT 7777	/* default port numbers for UDP data */
#define DEFAULT_CTRL_PORT 7778	/* control data */
#define DEFAULT_TCP_PORT 7777	/* TCP connect requests */
#define DEFAULT_MAXAGE 1000     /* identic Ethernet packets within
                                   this time (milisecs) are discarded */

#define MAX_CBUF_ANZ 4		/* No. of max. accumulated IPX packets */
#define MAX_CBUF_ACCUMULATION 1400	/* should be a bit samller as MTU of
					   UDP / TCP line */
#define MAX_SEND_DELAY 10               /* in millisecounds, see docs */
#define DUMMY_COUNT 8                   /* counter, see docs */
#define TCP_TIMEWAIT 30			/* Timeout for TCP connections */
#define TCP_PING_INTERVALL 30		/* Intervall of "ping" */
#define ROUNDTRIP_LAMBDA 0.75		/* whight of old values for ping */
#define SERVERWAIT_INTERVALL 15		/* Intervall of id reports to server */
#define CHECK_PEER_INTERVALL 600        /* If no packets arrives from a peer
					   in this time, it will be removed */

#define DEFAULT_CONFFILE "./ipxtund.conf"
#define DEFAULT_LOGFILE "./ipxtund.log"

/* #define BROKEN_INTERFACE 1 *//* in case of many "ipx_length x differ from
                                   packet_len y" errors */
#define IGNORE_UDP_CONNECT_REFUSED 1	/* where is the bug? */
/* #define DELAY_LINE 50 */ 		/* for simulating an delay in msec */
/* #define SLOW_LINE 6 */	/* for simulating a SLOW_LINE kbytes/sec line */

/* #define LOCAL_UDP_TESTLOOP 1	*//* for Testing only, dont activate unless you
				     know what it does */

#define MAXLINE 255		/* maximum line length in config file */
#define MAX_ROUTERS 16		/* maximum number of routers */
#define MAX_ETHERS 4		/* maximum number of Ethernet interfaces */
#define BUFSIZE 8192		/* size of internal data buffer, have to be
				   a bit larger than MAX_CBUF_ACCUMULATION
				   and maximum Ethernet size 1514 */

#ifndef NO_TCP
# define MAX_HDR_CACHE 250      /* set to 0 to disable header compression */
#else
# define MAX_HDR_CACHE 0
#endif
#define MAX_CACHE 252		/* dont change */
#define MAX_PROT 4		/* maximum number of Ethernet protocolls,
				   dont change */
#define MAX_ERRORS 100
#define S_STRLEN 80		/* dont change */
#define STRLEN 255		/* dont change */

#define IPX_BROADCAST_NODE "\377\377\377\377\377\377"	/* dont change */
#define IPX_NOVELL_SERVER_NODE "\000\000\000\000\000\001" /* dont change */
#define UDP_TCP_MAGIC "ABCD"	/* dont change */
#define DUMMY_MAGIC "DUMM"	/* dont change */
#define TCP_PING_MAGIC "PING"	/* dont change */
#define UDP_TCP_HDR_LEN 10	/* dont change */

#ifndef TRUE
typedef int boolean;
#define TRUE 1
#define FALSE 0
#endif

#define E_STDERR 1
#define E_LOG 2
#define E_ALL (E_STDERR | E_LOG)

#define ASCIITIMESTRLEN 26

#define ETHER_II 1
#define ETHER_802_2 2
#define ETHER_802_3 4
#define ETHER_SNAP 8
#define ETHER_TRANS 16
#define ETHER_AUTO 32
#define ETHER_NONE 64

#define DEFAULT_ETHER_FRAMETYPE ETHER_AUTO
#define DEFAULT_BUILD_ETHER_FRAMETYPE ETHER_802_2
#define DEFAULT_UDP_FRAMETYPE ETHER_NONE

enum Comtype {com_ether, com_tcp, com_udp, com_udp_tcp};

struct Stat {
  u_long bytes_r;	/* read bytes */
  u_long max_bytes_r;	/* max. size of a read packet */
  u_int packets_r;	/* no. of read packets */
  u_int errors_r;	/* read errors */
  u_long bytes_s;	/* written bytes */
  u_long max_bytes_s;	/* max. size of a written packet */
  u_int packets_s;	/* no. of written packets */
  u_int errors_s;	/* write errors */
};

struct Ether {
  int fd[MAX_PROT];	/* ethernet file descriptors for reading */
  int w_fd;		/* ethernet file descriptor for writing */
  u_short fd_anz;	/* no. of reading file descriptors */
  char name[MAXLINE];	/* name of ethernet interface */
  u_char mac[6];	/* ethernet MAC */
  struct sockaddr w_saddr;	/* write address for ethernet (socket only) */
  u_int r_frametypes;	/* set of read-recognized ethernet frametypes */
  u_int s_frametype;	/* ethernet frametype for writing */
  boolean s_autoframetype;	/* TRUE if automatic (a) is configures */
  size_t bufsize;	/* actual buffersize for read/write */
  struct Sdb *packet_db;  /* last received ethernet packets */
  struct Stat stat;	/* statistics */
};

struct Tcpcon {
  int tcp_listen_fd;	/* socket for "listen()" */
  u_short tcp_listen_port;	/* port for "listen()" */
  time_t req_timer;	/* time to block TCP connection requests */
  time_t ack_timer;	/* time to block TCP connection request acknowledges */
};

struct Local {
  char hostid[MAXLINE];	/* host id if hostname / IP number unknown */
  char server_name[MAXLINE]; /* server which resolves host ids to IP addr. */
  int udp_fd;		/* socket for UDP data transfer (read/write) */
  u_short udp_port;	/* port for UDP data transfer */
  int ctrl_fd;		/* socket for UDP control messages */
  u_short ctrl_port;	/* port for UDP control messages */
  struct Tcpcon tcp;	/* for TCP connection requests */
  u_int r_frametypes;	/* set of read-recognized ethernet frametypes */
  struct Stat stat;	/* statistics */
};

struct C_buf {
  u_short anz;		/* no. of packets in buf */
  char *p;		/* pointer of actual packet */
  char buf[BUFSIZE];
};

struct Ping {
  boolean pending;	/* TRUE, if a ping is alredy sent but not replied */
  u_short pending_id;	/* id of a pending ping */
  u_long last_ping_time; /* time at which last ping was sent */
  u_long roundtrip_time; /* mean time between a ping and its reply */
};

struct Cache_entry {
  u_short size;
  char *data;
};

struct Cache {
  struct Cache_entry slot[MAX_CACHE];
  u_short next_idx;
  u_short max_anz;
  u_short anz;
};

struct Router {
  int udp_fd;		/* file descriptor for IPX packets sent by UDP */
  u_short udp_port;	/* port number for IPX packets sent by UDP */
  int ctrl_fd;		/* ditto for control messages */
  u_short ctrl_port;
  int tcp_fd;		/* ditto for TCP connect requests */
  u_short tcp_port;
  struct Ping ping;	/* info about pings to this router */
  enum Comtype com;	/* type of communication (UDP or TCP) */
  u_long last_send_time;
  u_short dummycnt;
  boolean flush;        /* true, if send buffer must be flushed */
  char name[MAXLINE];	/* name or IP address of router */
  u_int s_frametype;	/* Ethernet-IPX frametype for sending to router */
  struct sockaddr_in sin; /* in_addr of router (UDP) */
  struct C_buf c_buf;	/* accumulator buffer for sending */
  struct Cache s_hdr_cache;
  struct Cache r_hdr_cache;
  struct Stat stat;
};

struct Config {
  struct Ether ether[MAX_ETHERS];
  int ether_anz;			/* no. of Ethernet interfaces */
  struct Router router[MAX_ROUTERS];
  int router_anz;			/* no. of routers */
  struct Local local;
};

struct Peer {
  int fw_idx;		/* index into router array */
  enum Comtype com;	/* communication of peer (ethernet or udp/tcp) */
  time_t last_time;     /* time of last packet arrived */
};

struct Data_packet {
  enum Comtype from_com;	/* communication type of data source */
  int from_fd;			/* file descriptor of data surce (for Ethernet
  				   or TCP valid) */
  struct sockaddr_in from_sin;	/* in_addr of data source (for UDP valid) */
  int from_sin_len;		/* legth of above in_addr */
  u_int from_frametype;		/* Ethernet-IPX frametype of data source */
  char *data;			/* pointer to begin of data packet */
  size_t len;			/* length of data packet */
  char buf[BUFSIZE];
};

#define COMPRESSED 1
#define UNCOMPRESSED 2
#define HDR_COMPRESSED 4
#define IPX_PACKET 8

extern FILE *log_fp;
extern int debuglevel, compresslevel;
extern boolean verbose;
extern time_t start_time;
extern sigjmp_buf sigenv, sigalrmenv;

int init(struct Config *config, struct Sdb **peer_db, const char *conffile);
int init_sender_db(struct Sdb **sender_db, const char *senderfile);
boolean get_ipx_to_ether_offset(const u_char *frame, u_int *type,
                                size_t *ipxoff);
int build_ether_packet(char *ether_packet, size_t *ether_len, size_t *ipx_off,
                       u_int ethertype, const char *ipx_packet,
                       const size_t ipx_len);
boolean is_realframetype(const u_int frametype);
int check_ether_age(const struct Data_packet *packet,
		    const struct Ether *ether, const u_int maxage);
boolean filter_sender(struct Sdb *sender_db, struct Data_packet *packet);
void save_ether_addr(char *packet, const size_t ipx_off);
int open_ether(struct Ether *ether);
int close_ether(struct Ether *ether);
int read_ipx_from_ether(struct Data_packet *packet, struct Ether *ether,
                        const u_short ether_idx, boolean *more_data);
int write_ipx_to_ether(const struct Data_packet *packet,
                       struct Ether *ether);
int read_ipx_from_udp_tcp(struct Data_packet *packet, struct Local *local,
                          struct Router *router, boolean *more_data);
int write_ipx_to_udp_tcp(struct Data_packet *packet, struct Router *router);
int flush_to_udp_tcp(struct Router *router);
int register_peer(struct Sdb *peer_db, const struct Data_packet *packet,
                  struct Ether ether_array[], const int ether_anz,
                  struct Router router_array[], const int router_anz);
int forward_ipx_packet(struct Data_packet *packet,
		       struct Ether *ether_array, const int ether_anz,
                       struct Router *router_array, const int router_anz,
		       struct Sdb *peer_db);
int check_peer_timeout(struct Sdb *peer_db);
int send_tcp_connect_request(struct Local *local, struct Router *router);
int process_tcp_request(struct Local *local,
                        struct Router *router_array, const int router_anz);
int send_tcp_cmd(const char cmd, const struct Router *router);
int process_tcp_accept(struct Local *local, struct Router *router);
int process_tcp_connect(struct Router *router);
int send_tcp_ping(struct Router *router);
int echo_tcp_ping(char *buf, struct Router *router);
int process_tcp_ping_reply(char *buf, struct Router *router);
int check_tcp_connection(struct Router *router);
int close_tcp_connection(struct Router *router);
boolean test_and_increment_ipx_ctl(char *ipx_packet);
void get_ipx_dest_node(char *node, const char *ipx_packet);
void get_ipx_dest_net(char *net, const char *ipx_packet);
void get_ipx_source_node(char *node, const char *ipx_packet);
void get_ipx_source_net(char *net, const char *ipx_packet);
u_char get_ipx_type(const char *ipx_packet);
size_t get_ipx_length(const char *ipx_packet);
void hs_to_str(char *str, const u_short n);
u_short str_to_hs(const char *str);
void errormsg(const int destmask, const char *upname, const char *fmt, ...);
void log(const char *fmt, ...);
void log_configuration(const struct Config *config);
void log_frametypes(const u_int frametypes);
void log_statistics(const time_t ti, const struct Ether ether_array[],
                    const int ether_anz, const struct Router router_array[],
		    const int router_anz, const struct Local *local);
void log_ether_header(const u_char *ether_packet);
void log_ipx_header(const u_char *ipx_packet);
void log_ipx_packet(const struct Data_packet *packet);
int fprint_as_hex(FILE *fp, const char *bytes, const size_t len);
int fprint_as_hex_nl(FILE *fp, const char *bytes, const size_t len);
void printifverbose(const char *fmt, ...);
void clear_stat(struct Stat *stat);
int read_config_file(struct Config *config, const char *path);
int router_connect(struct Local *local, struct Router *router_array,
                   int router_anz);
int router_connect_server(struct Local *local, struct Router *router_array,
                          int router_anz);
int router_connect_client(struct Local *local, struct Router *router_array,
                          int router_anz);
int header_compress(struct Data_packet *packet, struct Router *router);
int header_decompress(struct Data_packet *packet, struct Router *router);
int header_put_cache(struct Data_packet *packet, struct Router *router);
struct Cache_entry *get_d_cache(const u_short idx, struct Cache *cache);
int get_i_cache(const struct Cache_entry *entry, struct Cache *cache);
int put_cache(struct Cache *cache, struct Cache_entry *entry,
              const boolean copy);
void clear_cache(struct Cache *cache);
int compr(char *dest, u_long *d_len, char *source, u_long s_len);
int uncompr(char *dest, u_long *d_len, char *source, u_long s_len);
ssize_t readn(int fd, void *vptr, size_t n);
ssize_t writen(int fd, const void *vptr, size_t n);
ssize_t recvn(int s, void *buf, size_t len, int flags);
ssize_t sendn(int s, const void *buf, size_t len, int flags);
int get_inet_addr(struct in_addr *sin_addr, const char *hostname);
u_long msec_from_start(void);

