/*
 * Copyright (c) 2002, 2003, 2004 Niels Provos <provos@citi.umich.edu>
 * All rights reserved.
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 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 General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 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 General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 */
#ifndef _HONEYD_H_
#define _HONEYD_H_

#define PIDFILE			"/var/run/honeyd.pid"

#define TCP_DEFAULT_SIZE	512
#define TCP_MAX_SIZE		4096
#define TCP_MAX_SEND		512

#define HONEYD_MTU		1500
#define HONEYD_MAX_INTERFACES	8

#define HONEYD_MAX_CONNECTS	32000

#define HONEYD_CLOSE_WAIT	60
#define HONEYD_SYN_WAIT		60
#define HONEYD_IDLE_TIMEOUT	300
#define HONEYD_DFL_TTL		64
#define HONEYD_UDP_WAIT		60
#define HONEYD_MAX_SOFTERRS	3	   /* Softerrors to state free*/

#define HONEYD_POLL_INTERVAL	{0, 10000}

#define HONEYD_ADDR_MASK        0xFFFFFF00 /* for ICMP address mask replies */

struct config {
	char *config;	 /* Name of configuration file */
	char *pers;
	char *xprobe;
	char *assoc;
	char *osfp;
};

struct count;
struct stats_network {
	struct count *input_bytes;
	struct count *output_bytes;
};

struct spoof {
	struct addr new_src;	/* where the reply should appear to come from */
	struct addr new_dst;	/* where the reply should go */
};

extern struct spoof no_spoof;

struct delay {
	struct event timeout;

	struct addr src;
	struct addr dst;

	struct template *tmpl;
	struct ip_hdr *ip;
	u_int iplen;

	struct spoof spoof;
	int flags;
};

#define DELAY_NEEDFREE	0x0001
#define DELAY_EXTERNAL	0x0002
#define DELAY_FREEPKT	0x0004
#define DELAY_TUNNEL	0x0008
#define DELAY_UNREACH	0x0010
#define DELAY_ETHERNET	0x0020	/* packet needs to be sent via ethernet */

enum status {PORT_OPEN = 0, PORT_PROXY, PORT_BLOCK, PORT_RESET,
	     PORT_SUBSYSTEM, PORT_PYTHON, PORT_RESERVED
};

enum forward {FW_DROP = 0, FW_INTERNAL, FW_EXTERNAL};

#define PORT_ISOPEN(x) ((x)->status == PORT_OPEN || \
			(x)->status == PORT_PROXY || \
			(x)->status == PORT_SUBSYSTEM || \
			(x)->status == PORT_PYTHON)			

struct interface;
struct subsystem;
struct action {
	char *action;
	void *action_extend;
	struct addrinfo *aitop;
	enum status status;
	int flags;
};

#define PORT_TARPIT	0x01

struct port_encapsulate;

struct port {
	SPLAY_ENTRY(port) node;
	TAILQ_ENTRY(port) next;

	TAILQ_HEAD(pendingq, port_encapsulate) pending;

	int proto;
	u_short number;

	struct action action;

	/* Subsystem related information */
	struct subsystem *sub;
	struct template *subtmpl;
	int sub_fd;
	int sub_islisten;
	struct port **sub_conport;
};

SPLAY_HEAD(porttree, port);

/* Contains information common to both UDP and TCP connections */

struct tuple {
	SPLAY_ENTRY(tuple) node;
	TAILQ_ENTRY(tuple) next;

	ip_addr_t ip_src;
	ip_addr_t ip_dst;
	uint16_t sport;
	uint16_t dport;

	int type;	/* Eiter SOCK_STREAM or SOCK_DGRAM */

	/* Statistics */
	uint32_t received;
	uint32_t sent;

	struct event timeout;

	int local;	/* locally initiated */

	/* Potentially pending connection to subsystem */
	struct port_encapsulate *pending;
};

SPLAY_HEAD(tree, tuple);
TAILQ_HEAD(conlru, tuple);

struct command {
	pid_t pid;
	int pfd;
	int perrfd;

	struct event pread;
	struct event pwrite;
	struct event peread;

	uint8_t fdconnected:1,
	        fdwantclose:1,
		fdgotfin:1,	/* if data still buffered delay shutdown */
	        unused:5;

	void *state;		/* Currently used only for Python */
};

/*
 * For subsystems, we need to be able to schedule a callback that hands
 * the subsytem a file descriptor to the new connection.  However, Honeyd
 * may not block on this as this might lead to dead lock with the
 * subsystem.  Intead, we encapsulate all the necessary information and
 * hope that the underlying data does not go away.  XXX: that's a bug.
 */

struct port_encapsulate {
	TAILQ_ENTRY(port_encapsulate) next;

	struct tuple *hdr;
	struct command *cmd;
	struct port *port;
	void *con;

	struct event ev;
};

/* State about TCP connections */

struct tcp_con {
	/* Has to be the first member of the structure */
	struct tuple conhdr;
#define con_ipsrc conhdr.ip_src
#define con_ipdst conhdr.ip_dst
#define con_sport conhdr.sport
#define con_dport conhdr.dport

	uint8_t dupacks;
	uint32_t snd_una;

	uint32_t rcv_next;
	uint32_t last_acked;

	struct template *tmpl;
	uint8_t rcv_flags;

	struct command cmd;
#define cmd_pfd	cmd.pfd
#define cmd_perrfd cmd.perrfd

	u_char *payload;
	u_int psize;
	u_int plen;		/* date in buffer */
	u_int poff;		/* current send offset */

	u_char *readbuf;
	u_int rsize;
	u_int rlen;

	uint8_t state;
	uint8_t sentfin:1,
		finacked:1,
		sawwscale:1,
		sawtimestamp:1,
		unused:4;

	u_short	mss;
	u_short window;
	uint32_t echotimestamp;

	u_short retrans_time;

	struct event retrans_timeout;

	struct port *port;		/* used if bound to sub system */

	uint16_t flags;			/* Currently used for tarpitting */
};

#define TCP_TARPIT	0x01

#define MAX_UDP_BUFFERS	10

struct conbuffer {
	TAILQ_ENTRY(conbuffer) next;

	u_char *buf;
	size_t len;
};

struct udp_con {
	/* Has to be the first member of the structure */
	struct tuple conhdr;

	struct template *tmpl;

	struct command cmd;

	TAILQ_HEAD(bufferq, conbuffer) incoming;
	int nincoming;

	int softerrors;		/* ICMP unreachables for this state */

	struct port *port;
};

struct callback {
	void (*cb_read)(int, short, void *);
	void (*cb_write)(int, short, void *);
	void (*cb_eread)(int, short, void *);
	void (*cb_connect)(int, short, void *);
};

/* YM
 * Timestamp message data
 */
struct icmp_msg_timestamp { /* dnet.h define this but the size is wrong */
				/* So define ours */
	struct icmp_hdr hdr;			/* ICMP header */
	uint16_t        icmp_id;                /* identifier */
        uint16_t        icmp_seq;               /* sequence number */
        uint32_t        icmp_ts_orig;           /* originate timestamp */
        uint32_t        icmp_ts_rx;             /* receive timestamp */
        uint32_t        icmp_ts_tx;             /* transmit timestamp */
};

/* YM
 * Address mask message data, RFC 950
 */
struct icmp_mesg_mask { /* Our definition */
	struct icmp_hdr hdr;			/* ICMP header */
        uint16_t        icmp_id;                /* identifier */
        uint16_t        icmp_seq;               /* sequence number */
        uint32_t        icmp_mask;              /* address mask */
};

/* YM
 * Information Reply message data, RFC 792
 */
struct icmp_msg_inforeply { /* Our definition */
	struct icmp_hdr hdr;			/* ICMP header */
	struct icmp_msg_idseq idseq;		/* ID_SEQ */
};

#define TCP_BYTESINFLIGHT(x)	(x)->poff
#define TCP_MAX_INFLIGHT	4096

/* Iterate over all active connections */
int tuple_iterate(struct conlru *, int (*f)(struct tuple *, void *), void *);
struct tuple *tuple_find(struct tree *, struct tuple *);

void honeyd_ip_send(u_char *, u_int, struct spoof spoof);
void honeyd_dispatch(struct template *, struct ip_hdr *, u_short);
char *honeyd_contoa(const struct tuple *);

void honeyd_input(const struct interface *, struct ip_hdr *, u_short);

/* Command prototypes for services */
void cmd_droppriv(uid_t, gid_t);

void cmd_ready_fd(struct command *, struct callback *, void *);
void cmd_trigger_read(struct command *, int);
void cmd_trigger_write(struct command *, int);
void cmd_free(struct command *);
int cmd_fork(struct tuple *, struct command *, struct template *,
    char *, char **, void *);
int cmd_python(struct tuple *, struct command *, void *);
int cmd_subsystem(struct template *, struct subsystem *, char *, char **);

struct addrinfo;
struct addrinfo *cmd_proxy_getinfo(char *, int, short);
int cmd_proxy_connect(struct tuple *, struct command *, struct addrinfo *,
    void *);

int cmd_subsystem_schedule_connect(struct tuple *hdr, struct command *cmd,
    struct port *, void *arg);
int cmd_subsystem_connect(struct tuple *hdr, struct command *cmd,
    struct port *, void *arg);
int cmd_subsystem_localconnect(struct tuple *hdr, struct command *cmd,
    struct port *, void *arg);

/* Network connection elements */
struct tcp_con *tcp_new(struct ip_hdr *, struct tcp_hdr *, int);
struct udp_con *udp_new(struct ip_hdr *, struct udp_hdr *, int);
int tcp_setupconnect(struct tcp_con *);
void tcp_connectfail(struct tcp_con *con);

void generic_timeout(struct event *, int);

/* Network protocol related prototypes */
int conhdr_compare(struct tuple *, struct tuple *);

void tcp_free(struct tcp_con *);
int tcp_send(struct tcp_con *, uint8_t, u_char *, u_int);
void tcp_senddata(struct tcp_con *, uint8_t);
void tcp_sendfin(struct tcp_con *);

void udp_free(struct udp_con *);
int udp_send(struct udp_con *con, u_char *payload, u_int len);

void config_init(void);
void config_read(char *);

struct port *port_insert(struct template *, int, int, struct action *);
struct port *port_random(struct template *, int, struct action *, int, int);
struct port *port_find(struct template *, int, int);
void port_free(struct template *, struct port *);
void port_encapsulation_free(struct port_encapsulate *);

void icmp_echo_reply(struct template *, struct ip_hdr *, uint8_t,
    uint8_t, uint16_t, uint8_t,	u_char *, u_int, struct spoof spoof);
void change_quote_header(struct ip_hdr *, uint16_t, 
    uint16_t, uint16_t, uint16_t, uint16_t);
void icmp_unreachable_reply(struct ip_hdr *rip, uint8_t ttl, uint8_t tos,
	uint16_t df, uint16_t riplen, struct spoof spoof);
void icmp_mask_reply(struct template *, struct ip_hdr *, 
	struct icmp_msg_idseq *, uint8_t, uint32_t, struct spoof spoof);
void icmp_info_reply(struct template *, struct ip_hdr *, 
		struct icmp_msg_idseq *, uint8_t, struct spoof spoof);
void icmp_timestamp_reply(struct template *, struct ip_hdr *,
    struct icmp_msg_timestamp *, uint8_t, struct spoof spoof);

void honeyd_use_uid(uid_t);
void honeyd_use_gid(gid_t);

#endif
