/* Distributed Checksum Clearinghouse * * server daemon definitions * * Copyright (c) 2005 by Rhyolite Software, LLC * * This agreement is not applicable to any entity which sells anti-spam * solutions to others or provides an anti-spam solution as part of a * security solution sold to other entities, or to a private network * which employs the DCC or uses data provided by operation of the DCC * but does not provide corresponding data to other users. * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * Parties not eligible to receive a license under this agreement can * obtain a commercial license to use DCC and permission to use * U.S. Patent 6,330,590 by contacting Commtouch at http://www.commtouch.com/ * or by email to nospam@commtouch.com. * * A commercial license would be for Distributed Checksum and Reputation * Clearinghouse software. That software includes additional features. This * free license for Distributed ChecksumClearinghouse Software does not in any * way grant permision to use Distributed Checksum and Reputation Clearinghouse * software * * THE SOFTWARE IS PROVIDED "AS IS" AND RHYOLITE SOFTWARE, LLC DISCLAIMS ALL * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL RHYOLITE SOFTWARE, LLC * BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES * OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, * WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, * ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS * SOFTWARE. * * Rhyolite Software DCC 1.3.42-1.147 $Revision$ */ #ifndef DCCD_DEFS_H #define DCCD_DEFS_H #include "srvr_defs.h" #include "dcc_xhdr.h" extern DCC_EMSG dcc_emsg; extern u_char grey; extern u_char background; extern int stopint; extern DCC_SRVR_ID my_srvr_id; extern const char *brand; /* our brand name */ extern u_char use_ipv6; extern u_int16_t def_port; typedef struct srvr_soc { struct srvr_soc *fwd; DCC_SOCKU su; union { struct dcc_in6_addr in6; struct in_addr in4; } arg_addr; int udp; int listen; u_int16_t arg_port; u_char arg_family; u_char flags; # define SRVR_SOC_ADDR 0x01 /* explicit IP address */ # define SRVR_SOC_IF 0x02 /* port on all interfaces */ # define SRVR_SOC_LISTEN 0x04 /* need a listen socket for port */ # define SRVR_SOC_MARK 0X08 # define SRVR_SOC_NEW 0X10 } SRVR_SOC; extern SRVR_SOC *srvr_socs; extern int srvr_rcvbuf; extern DB_RCD host_id_rcd; /* our host's globally unique ID */ extern time_t host_id_next, host_id_last; #define DCC_SRVR_ID_SEC (24*60*60) /* defend server-IDs this often */ #define DCC_SRVR_ID_SEC0 (5*60) /* defend after daemon is running */ extern time_t boot_ok_time; /* suppress flooding errors at first */ /* normal keepalive interval */ #define KEEPALIVE_IN (60*15) #define KEEPALIVE_OUT (KEEPALIVE_IN+FLODS_CK_SECS) /* things should be quicker while we are shutting down flooding */ #define KEEPALIVE_IN_STOP 15 #define KEEPALIVE_OUT_STOP (KEEPALIVE_IN_STOP+FLODS_CK_SECS) /* be really quick if stopping the daemon */ #define SHUTDOWN_DELAY 2 extern int summarize_delay_secs; /* delay summaries by this */ #define MAX_SUMMARIZE_DELAY_SECS (DCC_NEW_SPAM_SECS/2) extern int queue_max; extern u_char anon_off; /* turn off anonymous access */ extern u_char query_only; /* 1=treat reports as queries */ extern time_t anon_delay_us; /* anonymous client delay */ extern u_int anon_delay_inflate; extern struct timeval wake_time; /* when we awoke from select() */ extern u_char grey_weak_body; /* 1=ignore bodies for greylisting */ extern u_char grey_weak_ip; /* 1=one good triple whitelists addr */ extern int grey_embargo; extern int grey_window; extern int grey_white; /* rate limiting * One of these structures is maintained for every recent client, * where "recent" is at least one day */ typedef struct rl { struct rl *fwd, *bak, **hash; struct rl *older, *newer; DCC_CLNT_ID clnt_id; struct in6_addr clnt_addr; time_t last_used; time_t requests_avg_date; /* end of "today" for averaging */ # define RL_AVG_DAY (24*60*60 - 30*60) int requests_cur_avg; /* yesterday's total */ int nops_cur_avg; int requests_next_avg; /* growing total for tomorrow */ int nops_next_avg; # define RL_REQUESTS_AVG(rl) max((rl)->requests_cur_avg, \ (rl)->requests+(rl)->requests_next_avg) # define RL_NOPS_AVG(rl) max((rl)->nops_cur_avg, \ (rl)->nops+(rl)->nops_next_avg) int requests; int nops; int request_credits; /* operations */ int bug_credits; /* complaints about this client */ short ref_cnt; /* in use by entry in queue */ u_char vers; /* recent protocol version */ u_char flags; # define RL_CK_BLACKLIST 0x01 /* 0=need the check blacklist */ # define RL_BLACKLIST 0x02 /* 1=blacklisted client */ # define RL_TRACE 0x04 # define RL_MARKED 0x08 } RL; typedef struct { float penalty_secs; int sec, lo, hi; } RL_RATE; extern RL_RATE rl_sub_rate; /* X/sec/paying customer */ extern RL_RATE rl_anon_rate; /* X/sec/freeloader */ extern RL_RATE rl_all_anon_rate; /* X/sec for all freeloaders */ extern RL_RATE rl_bugs_rate; /* X complaints/sec */ #define RL_MIN_MAX 10000 /* freely create this many blocks */ #define RL_MAX_MAX (RL_MIN_MAX*8) /* absolute limit */ #define RL_AVG_SECS 10 /* average for this many seconds */ #define RL_LIFE_SECS (RL_AVG_SECS*2) /* lifetime of rate limit block */ #define RL_OVF_CREDITS 0x7fffffff /* fit {bug,request}_credits */ #define RL_SCALE 10 #define RL_MAX_CREDITS (RL_OVF_CREDITS/RL_AVG_SECS/RL_SCALE/2) extern time_t clients_cleared; /* report cache used to detect duplicate reports * One of these structures is maintained for every current operation */ typedef struct ridc { struct ridc *fwd, *bak, **hash; struct ridc *older, *newer; time_t last_used; DCC_HDR hdr; u_int16_t clnt_port; int len; u_char op; union { DCC_ANSWER_BODY_CKS b; DCC_ADMN_RESP_ANON_DELAY anon_delay; char msg[DCC_ERROR_MSG_LEN]; } result; } RIDC; /* entry in main job queue */ typedef struct dccd_queue { struct dccd_queue *later, *earlier; RL *rl; RIDC *ridc; SRVR_SOC *sp; DCC_CLNT_ID clnt_id; /* validated client-ID */ DCC_SOCKU clnt_su; /* send answer here */ u_int pkt_len; time_t delay_us; /* how long to delay the answer */ struct timeval answer; /* when it should be answered */ u_char flags; # define Q_FLG_RPT_OK 0x01 /* override dccd -Q */ DCC_PASSWD passwd; /* sign answers with this */ union { DCC_HDR hdr; DCC_REPORT r; DCC_DELETE d; DCC_GREY_SPAM gs; DCC_ADMN_REQ ad; } pkt; } QUEUE; typedef struct iflod_info IFLOD_INFO; typedef struct { DCC_SRVR_ID from_lo; DCC_SRVR_ID from_hi; u_char result; } OFLOD_SRVR_ID_MAP; typedef enum { ID_MAP_NO, ID_MAP_REJ, ID_MAP_SELF } ID_MAP_RESULT; typedef struct { int val; int limit; } FLOD_LIMCNT; #define FLOD_CNTERR(lc) (++(lc)->val - ((lc)->limit + 10)) #define FLOD_LIM_CLEAR_SECS (60*60) typedef struct { u_int flags; # define FLOD_OPT_OFF 0x0001 # define FLOD_OPT_DEL_OK 0x0002 # define FLOD_OPT_DEL_SET 0x0004 # define FLOD_OPT_NO_LOG_DEL 0x0008 # define FLOD_OPT_TRAPS 0x0010 # define FLOD_OPT_PASSIVE 0x0020 # define FLOD_OPT_SOCKS 0x0040 # define FLOD_OPT_IPv4 0x0080 # define FLOD_OPT_IPv6 0x0100 # define FLOD_OPT_NO_REP 0x0200 OFLOD_SRVR_ID_MAP srvr_map[10]; u_char num_maps; u_char path_len; } OFLOD_OPTS; typedef struct { FLOD_MMAP *mp; int s; /* outgoing socket */ int lno; char rem_portname[sizeof(flod_mmaps->mmaps[0].rem_portname)]; char rem_hostname[sizeof(flod_mmaps->mmaps[0].rem_hostname)]; char loc_hostname[MAXHOSTNAMELEN]; DCC_SRVR_ID rem_id, in_passwd_id, out_passwd_id; u_int16_t rem_port, loc_port; DCC_SOCKU rem_su; /* target of the flood */ time_t out_try_again; /* don't connect() before then */ int out_try_secs; /* backoff */ time_t in_try_again; /* no SOCKS connect() before then */ int in_try_secs; /* backoff */ time_t limit_reset; /* when to reset complaint limits */ time_t keep_out_time; /* last sent to peer */ time_t keep_in_time; /* last heard from peer */ struct { time_t saved; /* last wrote counts to file */ int out_reports; /* total reports sent */ int total; /* total reports received */ int accepted; /* acceptable received reports */ FLOD_LIMCNT stale; /* bad timestamp */ FLOD_LIMCNT dup; /* already received */ FLOD_LIMCNT ok2; /* whitelisted */ FLOD_LIMCNT not_deleted; /* delete commands ignored */ FLOD_LIMCNT bad_id; /* unrecognized server-IDs */ FLOD_LIMCNT complaint; /* output complaint from peer */ FLOD_LIMCNT iflod_bad; /* generic bad report */ } cnts; DB_PTR xmit_pos; /* last transmitted position */ DB_PTR recv_pos; /* heard this from target */ DB_PTR cur_pos; /* completed to here */ DB_PTR rewind_pos; /* will have rewound by here */ u_int ibuf_len; union { DCC_FLOD_POS pos; FLOD_END end; FLOD_NOTE note; u_char b[sizeof(DCC_FLOD_POS)*2+DCC_FLOD_MAX_RESP+1]; } ibuf; u_int obuf_reports, obuf_len, obuf_off; union { DCC_FLOD_VERSION_HDR vers; DCC_FLOD f[3]; # define FLOD_BUF_SIZE 2048 char c[FLOD_BUF_SIZE]; } obuf; OFLOD_OPTS i_opts; OFLOD_OPTS o_opts; time_t ids_mtime; IFLOD_INFO *ifp; u_int flags; # define OFLOD_FG_CONNECTED 0x0001 /* connect() complete */ # define OFLOD_FG_NEW 0x0002 /* new connection */ # define OFLOD_FG_SHUTDOWN 0x0004 /* brakes applied */ # define OFLOD_FG_SHUTDOWN_REQ 0x0008 # define OFLOD_FG_PASSWD_NEXT 0x0010 /* have a 2nd password */ # define OFLOD_FG_TOO_BUSY 0x0020 /* stopped filling buffer */ # define OFLOD_FG_EAGAIN 0x0040 /* recent bogus EAGAIN */ u_char iversion, oversion; } OFLOD_INFO; typedef struct { int total; int active; OFLOD_INFO infos[DCCD_MAX_FLOODS]; } OFLODS; extern OFLODS oflods; extern DB_PTR oflods_max_pos; extern enum FLODS_ST { FLODS_ST_OFF, FLODS_ST_RESTART, FLODS_ST_ON } flods_st; extern DB_FLOD_THOLDS flod_tholds; struct iflod_info { int s; /* incoming socket */ DCC_SOCKU su; /* sender of the flood */ char hostname[sizeof(flod_mmaps->mmaps[0].rem_hostname)]; DCC_FLOD_POS pos, pos_sent; OFLOD_INFO *ofp; time_t quit_connect; /* when to stop waiting for password */ # define IFLOD_CONNECT_SECS KEEPALIVE_IN u_int ibuf_len, ibuf_off; u_char flags; # define IFLOD_FG_CONNECTED 0x01 # define IFLOD_FG_VERS_CK 0x02 # define IFLOD_FG_END_REQ 0x04 # define IFLOD_FG_FAST_LINGER 0x08 # define IFLOD_FG_PEER_REP_OFF 0x10 /* peer rejects reputations */ union { DCC_FLOD_VERSION_HDR vers; DCC_FLOD f[3]; char c[FLOD_BUF_SIZE]; } ibuf; }; typedef struct { int active; IFLOD_INFO infos[DCCD_MAX_FLOODS]; } IFLODS; extern IFLODS iflods; extern int flods_off; /* # of reasons flooding is off */ extern int flod_db_sick; /* # of flooding DB sicknesses */ extern u_int complained_many_iflods; extern u_char too_busy; /* too busy to flood */ extern time_t next_flods_ck; #define FLODS_CK_SECS 5 #define GREY_FLODS_CK_SECS 5 #define MISC_CK_SECS (FLODS_CK_SECS-1) #define FLOD_RETRY_SECS (60*5) /* try to connect once in 5 minutes */ #define FLOD_SLOW_RETRY_SECS (60*60*4) /* 4 hours after bad authentication */ extern time_t got_hosts; #define FLOD_NAMES_RESOLVE_SECS (60*15) /* resolve hostnames once/15 minutes */ extern pid_t resolve_hosts_pid; extern const char *need_del_dbclean; extern time_t del_dbclean_next; #define DEL_DBCLEAN_SECS (60*30) /* limit dbclean if not urgent */ extern time_t dbclean_limit; #define DBCLEAN_LIMIT_SECS 15 /* not too often for any reason */ extern time_t dbclean_limit_secs; extern DCCD_STATS dccd_stats; /* Avoid the costs of generating and passing the args to syslog() by * checking bits in the caller. * If the server ran only on modern Unix, we could use gcc's macro varargs. */ #define TMSG(t,p) do { \ if (DCC_TRACE_##t##_BIT & dccd_tracemask) \ dcc_trace_msg(p);} while (0) #define TMSG1(t,p,arg) do { \ if (DCC_TRACE_##t##_BIT & dccd_tracemask) \ dcc_trace_msg(p,arg);} while (0) #define TMSG2(t,p,arg1,arg2) do { \ if (DCC_TRACE_##t##_BIT & dccd_tracemask) \ dcc_trace_msg(p,arg1,arg2);} while (0) #define TMSG3(t,p,arg1,arg2,arg3) do { \ if (DCC_TRACE_##t##_BIT & dccd_tracemask) \ dcc_trace_msg(p,arg1,arg2,arg3);} while (0) #define TMSG4(t,p,arg1,arg2,arg3,arg4) do { \ if (DCC_TRACE_##t##_BIT & dccd_tracemask) \ dcc_trace_msg(p,arg1,arg2,arg3,arg4);} while (0) #define TMSG5(t,p,arg1,arg2,arg3,arg4,arg5) do { \ if (DCC_TRACE_##t##_BIT & dccd_tracemask) \ dcc_trace_msg(p,arg1,arg2,arg3,arg4,arg5);} while (0) #define TMSG6(t,p,arg1,arg2,arg3,arg4,arg5,arg6) do { \ if (DCC_TRACE_##t##_BIT & dccd_tracemask) \ dcc_trace_msg(p,arg1,arg2,arg3,arg4,arg5,arg6);} while (0) #define Q_CIP(q) dcc_su2str_err(&(q)->clnt_su) static inline void db_ptr2flod_pos(DCC_FLOD_POS bp, DB_PTR pos) { bp[7] = pos; bp[6] = pos>>8; bp[5] = pos>>16; bp[4] = pos>>24; bp[3] = pos>>32; bp[2] = pos>>40; bp[1] = pos>>48; bp[0] = pos>>56; } static inline DB_PTR flod_pos2db_ptr(const DCC_FLOD_POS pos) { return ((DB_PTR)pos[7] + (((DB_PTR)pos[6])<<8) + (((DB_PTR)pos[5])<<16) + (((DB_PTR)pos[4])<<24) + (((DB_PTR)pos[3])<<32) + (((DB_PTR)pos[2])<<40) + (((DB_PTR)pos[1])<<48) + (((DB_PTR)pos[0])<<56)); } /* dccd.c */ extern void free_q(QUEUE *); extern void close_srvr_socs(void); extern void set_dbclean_timer(void); extern void bad_stop(const char *, ...) PATTRIB(1,2); /* iflod.c */ const char *flod_stats_str(int *, int, enum FLOD_ERR_OP); extern void rpt_err(LAST_ERROR *, u_char, enum FLOD_ERR_OP, int, const char *, ...) PATTRIB(5,6); extern u_char set_flod_socket(int, const char *, const DCC_SOCKU *, u_char); extern u_char flod_names_resolve_ck(void); extern u_char flod_names_resolve_start(void); extern ID_MAP_RESULT id_map(DCC_SRVR_ID, const OFLOD_OPTS *); extern void iflod_stop(IFLOD_INFO *, const char *); extern void iflods_stop(const char *, u_char); extern void iflod_start(SRVR_SOC *); extern void iflods_start(void); extern void iflod_socks_start(OFLOD_INFO *); extern u_char dccd_db_open(u_char); extern void iflod_close(IFLOD_INFO *, u_char, enum FLOD_ERR_OP, int, const char *, ...) PATTRIB(5,6); extern void iflod_read(IFLOD_INFO *); extern u_char iflod_send_pos(IFLOD_INFO *, u_char); extern int flods_list(char *, int, u_char); extern int flod_stats(char *, int, u_int32_t, u_char); extern void new_peer(OFLOD_INFO *); /* oflod.c */ extern void oflod_open(OFLOD_INFO *); extern void oflods_unmap(void); extern u_char oflods_load(void); extern void save_flod_cnts(OFLOD_INFO *); extern void oflod_close(OFLOD_INFO *, u_char, enum FLOD_ERR_OP, int); extern void oflod_read(OFLOD_INFO *); extern void oflod_write(OFLOD_INFO *); extern void oflods_stop(u_char); extern const char *version_str(const OFLOD_INFO *); extern u_char oflod_connect_fin(OFLOD_INFO *); extern void PATTRIB(3,4) db_broken(int, const char *, const char *, ...); extern void flods_restart(const char *); extern void flods_ck(u_char); extern void flods_init(void); /* rl.c */ extern void clients_get_id(DCC_ADMN_RESP_VAL *, int *, const QUEUE *, u_int, int, u_char, const struct in6_addr *, const struct in6_addr *); extern int clients_get(DCC_ADMN_RESP_VAL *, int *, const QUEUE *, u_int, int, u_char, const struct in6_addr *, const struct in6_addr *); #ifdef DCC_PKT_VERSION6 extern void clients_get_idv6(DCC_ADMN_RESP_VAL *, int *, u_int, int, u_char); #endif #define CLIENTS_AGE (24*60*60) extern void clients_clear(u_char); extern u_char ck_sign(ID_TBL **, DCC_PASSWD, DCC_CLNT_ID, const void *, u_int); extern u_char ck_id(QUEUE *, DCC_CLNT_ID); extern u_char ck_clnt_srvr_id(QUEUE *); extern u_char ck_clnt_id(QUEUE *); extern void check_blacklist_file(void); /* trace.c */ extern u_long dccd_tracemask; extern void vanon_msg(const char *, va_list); extern void anon_msg(const char *, ...) PATTRIB(1,2); extern void clnt_msg(const QUEUE *, const char *, ...) PATTRIB(2,3); /* work.c */ extern u_char ridc_get(QUEUE *); extern void update_q_delay(QUEUE *); extern void cycle_q_delay(void); extern void stats_clear(void); extern u_char summarize_dly(void); extern u_char add_dly_rcd(DB_RCD *, u_char); extern void do_work(QUEUE *); extern void do_grey(QUEUE *); extern void do_grey_spam(QUEUE *); extern void do_nop(QUEUE *); extern void do_admn(QUEUE *); extern void do_delete(QUEUE *); extern void discard_error(const QUEUE *, const char *, ...) PATTRIB(2,3); extern void send_ok(QUEUE *); #endif /* DCCD_DEFS_H */