/* Copyright (C) 2002, J.P. Grossman 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. */ // iplog.c #include "quakedef.h" iplog_t *iplogs, *iplog_head; int iplog_size, iplog_next, iplog_full; #define DEFAULT_IPLOGSIZE 0x10000 /* ==================== IPLog_Init ==================== */ void IPLog_Init (void) { int p; FILE *f; iplog_t temp; // Allocate space for the IP logs iplog_size = 0; if (!(p = COM_CheckParm("-iplog"))) return; if (p < com_argc - 1) iplog_size = Q_atoi(com_argv[p+1]) * 1024 / sizeof(iplog_t); if (!iplog_size) iplog_size = DEFAULT_IPLOGSIZE; iplogs = (iplog_t *)Hunk_AllocName (iplog_size * sizeof(iplog_t), "iplog"); iplog_next = 0; iplog_head = NULL; iplog_full = 0; // Attempt to load log data from iplog.dat Sys_GetLock (); if ((f = fopen("iplog.dat", "r"))) { while (fread(&temp, 20, 1, f)) IPLog_Add (temp.addr, temp.name); fclose (f); } Sys_ReleaseLock (); Cmd_AddCommand ("identify", IPLog_Identify_f); Cmd_AddCommand ("ipdump", IPLog_Dump); Cmd_AddCommand ("ipmerge", IPLog_Import); } /* ==================== IPLog_Import ==================== */ void IPLog_Import (void) { FILE *f; iplog_t temp; if (Cmd_Argc() < 2) { Con_Printf ("Usage: ipmerge \n"); return; } if ((f = fopen(va("%s", Cmd_Argv(1)), "r"))) { while (fread(&temp, 20, 1, f)) IPLog_Add (temp.addr, temp.name); fclose (f); Con_Printf ("Merged %s\n", Cmd_Argv(1)); } else { Con_Printf ("Could not open %s\n", Cmd_Argv(1)); } } /* ==================== IPLog_WriteLog ==================== */ void IPLog_WriteLog (void) { int i; FILE *f; iplog_t temp; if (!iplog_size) return; Sys_GetLock (); // first merge if ((f = fopen("iplog.dat", "r"))) { while (fread(&temp, 20, 1, f)) IPLog_Add (temp.addr, temp.name); fclose (f); } // then write if ((f = fopen("iplog.dat", "w"))) { if (iplog_full) { for (i = iplog_next + 1 ; i < iplog_size ; i++) fwrite (&iplogs[i], 20, 1, f); } for (i = 0 ; i < iplog_next ; i++) fwrite (&iplogs[i], 20, 1, f); fclose (f); } else { Con_Printf ("Could not write iplog.dat\n"); } Sys_ReleaseLock (); } #define MAX_REPITITION 64 /* ==================== IPLog_Add ==================== */ void IPLog_Add (int addr, char *name) { int i, cmatch; // limit 128 entries per IP char *ch, name2[16]; iplog_t *iplog_new, *parent, **ppnew, *match[MAX_REPITITION]; if (!iplog_size) return; // delete trailing spaces strncpy (name2, name, 15); ch = &name2[15]; *ch = 0; while (ch >= name2 && (*ch == 0 || *ch == ' ')) *ch-- = 0; if (ch < name2) return; iplog_new = &iplogs[iplog_next]; cmatch = 0; parent = NULL; ppnew = &iplog_head; while (*ppnew) { if ((*ppnew)->addr == addr) { if (!strcmp(name2, (*ppnew)->name)) return; match[cmatch] = *ppnew; if (++cmatch == MAX_REPITITION) { // shift up the names and replace the last one for (i = 0 ; i < MAX_REPITITION - 1 ; i++) strcpy (match[i]->name, match[i+1]->name); strcpy (match[i]->name, name2); return; } } parent = *ppnew; ppnew = &(*ppnew)->children[addr > (*ppnew)->addr]; } *ppnew = iplog_new; strcpy (iplog_new->name, name2); iplog_new->addr = addr; iplog_new->parent = parent; iplog_new->children[0] = NULL; iplog_new->children[1] = NULL; if (++iplog_next == iplog_size) { iplog_next = 0; iplog_full = 1; } if (iplog_full) IPLog_Delete (&iplogs[iplog_next]); } /* ==================== IPLog_Delete ==================== */ void IPLog_Delete (iplog_t *node) { iplog_t *newlog; if ((newlog = IPLog_Merge(node->children[0], node->children[1]))) newlog->parent = node->parent; if (node->parent) node->parent->children[node->addr > node->parent->addr] = newlog; else iplog_head = newlog; } /* ==================== IPLog_Merge ==================== */ iplog_t *IPLog_Merge (iplog_t *left, iplog_t *right) { if (!left) return right; if (!right) return left; if (rand() & 1) { left->children[1] = IPLog_Merge (left->children[1], right); left->children[1]->parent = left; return left; } right->children[0] = IPLog_Merge (left, right->children[0]); right->children[0]->parent = right; return right; } /* ==================== IPLog_Identify ==================== */ void IPLog_Identify (int addr) { int count = 0; iplog_t *node; node = iplog_head; while (node) { if (node->addr == addr) { Con_Printf ("%s\n", node->name); count++; } node = node->children[addr > node->addr]; } Con_Printf ("%d %s found\n", count, (count == 1) ? "entry" : "entries"); } // used to translate to non-fun characters for identify char unfun[129] = "................[]olzeasbt89...." "........[]......olzeasbt89..[.]." "aabcdefghijklmnopqrstuvwxyz[.].." ".abcdefghijklmnopqrstuvwxyz[.].."; // try to find s1 inside of s2 int unfun_match (char *s1, char *s2) { int i; for ( ; *s2 ; s2++) { for (i=0 ; s1[i] ; i++) { if (unfun[s1[i] & 127] != unfun[s2[i] & 127]) break; } if (!s1[i]) return true; } return false; } /* ================== IPLog_Identify_f Print all known names for the specified player's ip address ================== */ void IPLog_Identify_f (void) { int i, a, b, c; char name[16]; if (Cmd_Argc() < 2) { Con_Printf ("usage: identify \n"); return; } if (sscanf(Cmd_Argv(1), "%d.%d.%d", &a, &b, &c) == 3) { Con_Printf ("known aliases for %d.%d.%d:\n", a, b, c); IPLog_Identify ((a << 16) | (b << 8) | c); return; } i = Q_atoi(Cmd_Argv(1)) - 1; if (i == -1) { if (sv.active) { for (i=0 ; i= svs.maxclients || !svs.clients[i].active) { Con_Printf ("No such player\n"); return; } if (sscanf(svs.clients[i].netconnection->address, "%d.%d.%d", &a, &b, &c) != 3) { Con_Printf ("Could not determine IP information for %s\n", svs.clients[i].name); return; } Q_strncpyz (name, svs.clients[i].name, sizeof(name)); Con_Printf ("known aliases for %s:\n", name); IPLog_Identify ((a << 16) | (b << 8) | c); } else { if (i < 0 || i >= cl.maxclients || !cl.scores[i].name[0]) { Con_Printf ("No such player\n"); return; } if (!cl.scores[i].addr) { Con_Printf ("No IP information for %.15s\nUse 'status'\n", cl.scores[i].name); return; } Q_strncpyz (name, cl.scores[i].name, sizeof(name)); Con_Printf ("known aliases for %s:\n", name); IPLog_Identify (cl.scores[i].addr); } } /* ==================== IPLog_DumpTree ==================== */ void IPLog_DumpTree (iplog_t *root, FILE *f) { char address[16], name[16]; if (!root) return; IPLog_DumpTree (root->children[0], f); sprintf (address, "%d.%d.%d.xxx", root->addr >> 16, (root->addr >> 8) & 0xff, root->addr & 0xff); strcpy (name, root->name); fprintf (f, "%-16s %s\n", address, name); IPLog_DumpTree (root->children[1], f); } /* ==================== IPLog_Dump ==================== */ void IPLog_Dump (void) { FILE *f; if (!(f = fopen(va("%s/iplog.txt", com_gamedir), "w"))) { Con_Printf ("Couldn't write iplog.txt\n"); return; } IPLog_DumpTree (iplog_head, f); fclose (f); Con_Printf ("Wrote iplog.txt\n"); }