kalasag.org

kalasag.org

Git

This commit has been accessed 3,361 times via Git panel.

commit 6c3dc833bdde64b0c2c097228b9b34d0a99c617a
tree acdc640ff4b70fddf7a8731fc71b089804d57217
author Engels Antonio <engels@majcms.org> 1314301223 +0800
committer Engels Antonio <engels@majcms.org> 1314301223 +0800

    Initial commit, warts and all

diff --git a/Makefile b/Makefile
new file mode 100644
index 0000000..ca83f7c
--- /dev/null
+++ b/Makefile
@@ -0,0 +1,191 @@
+# Makefile for Kalasag
+#
+# STEALTH MODE: Only works on Linux systems right now.
+#
+# The snprintf included with the package is for use with NEXTSTEP only,
+# (Thanks Timothy <tjl@luomat.org>) although it may work elsewhere.
+# We've not tried it under any other OS to date. It shouldn't be needed
+# by any modern OS.
+#
+# Others have used the snprintf from:
+#
+# http://www.ijs.si/software/snprintf/
+#
+# We've not tried this yet but others have had good success. Our only
+# piece of advice for those running an OS without built in snprintf()
+# is to upgrade. :)
+#
+#
+# Generic compiler (usually linked to gcc on most platforms)
+CC = cc
+
+# GNU..
+#CC = gcc
+
+# Normal systems flags
+CFLAGS = -O3 -funroll-loops -fomit-frame-pointer -Wall
+
+# Debug mode for kalasag
+#CFLAGS = -Wall -g -DNODAEMON -DDEBUG
+#CFLAGS = -Wall -g -DNODAEMON
+#CFLAGS = -Wall -g -DDEBUG
+
+# Profiler mode for kalasag
+#CFLAGS = -pg -O -Wall -DNODAEMON
+#LIBS = /usr/lib/libefence.a
+
+INSTALLDIR = /opt
+CHILDDIR=/kalasag
+
+all:
+               @echo "Usage: make <systype>"
+               @echo "<systype> is one of: linux, debian-linux, bsd, solaris, hpux, hpux-gcc,"
+               @echo "freebsd, osx, openbsd, netbsd, bsdi, aix, osf, irix, generic"
+               @echo ""
+               @echo "This code requires snprintf()/vsnprintf() system calls"
+               @echo "to work. If you run a modern OS it should work on"
+               @echo "your system with 'make generic'. If you get it to"
+               @echo "work on an unlisted OS please write us with the"
+               @echo "changes."
+               @echo ""
+               @echo "Install: make install"
+               @echo ""
+               @echo "NOTE: This will install the package in this"
+               @echo "      directory: $(INSTALLDIR)"
+               @echo ""
+               @echo "Edit the makefile if you wish to change these paths."
+               @echo "Any existing files will be overwritten."
+               @echo ""
+
+clean:        
+               /bin/rm ./kalasag
+
+uninstall:    
+               /bin/rm $(INSTALLDIR)$(CHILDDIR)/*
+               /bin/rmdir $(INSTALLDIR)$(CHILDDIR)
+
+install:      
+               @echo "Creating directory $(INSTALLDIR)"
+               @if [ ! -d $(INSTALLDIR) ]; then /bin/mkdir $(INSTALLDIR); fi
+               @echo "Setting directory permissions"
+               @echo "Creating kalasag directory $(INSTALLDIR)$(CHILDDIR)"
+               @if [ ! -d $(INSTALLDIR)$(CHILDDIR) ]; then /bin/mkdir $(INSTALLDIR)$(CHILDDIR); fi
+               @echo "Setting directory permissions"
+               chmod 700 $(INSTALLDIR)$(CHILDDIR)
+               @echo "Copying files"
+               cp ./kalasag.conf $(INSTALLDIR)$(CHILDDIR)
+               cp ./kalasag.ignore $(INSTALLDIR)$(CHILDDIR)
+               cp ./kalasag $(INSTALLDIR)$(CHILDDIR)
+               @echo "Setting permissions"
+               chmod 600 $(INSTALLDIR)$(CHILDDIR)/kalasag.ignore
+               chmod 600 $(INSTALLDIR)$(CHILDDIR)/kalasag.conf
+               chmod 700 $(INSTALLDIR)$(CHILDDIR)/kalasag
+               @echo ""
+               @echo ""
+               @echo "Edit $(INSTALLDIR)$(CHILDDIR)/kalasag.conf and change"
+               @echo "your settings if you haven't already. (route, etc)"
+               @echo ""
+
+linux:        
+               SYSTYPE=linux
+               @echo "Making $(SYSTYPE)"
+               $(CC) $(CFLAGS) -DLINUX -DSUPPORT_STEALTH -o ./kalasag ./kalasag.c ./kalasag_io.c ./kalasag_util.c $(LIBS)
+
+linux-x86_64:         
+               SYSTYPE=linux
+               @echo "Making $(SYSTYPE)"
+               $(CC) $(CFLAGS) -m64 -DLINUX -DSUPPORT_STEALTH -o ./kalasag ./kalasag.c ./kalasag_io.c ./kalasag_util.c $(LIBS)
+
+debian-linux:         
+               SYSTYPE=debian-linux
+               @echo "Making $(SYSTYPE)"
+               $(CC) $(CFLAGS) -DLINUX -DDEBIAN -DSUPPORT_STEALTH -o ./kalasag ./kalasag.c ./kalasag_io.c ./kalasag_util.c $(LIBS)
+
+
+bsd:          
+               SYSTYPE=bsd
+               @echo "Making $(SYSTYPE)"
+               $(CC) $(CFLAGS) -DBSD44 -o ./kalasag ./kalasag.c ./kalasag_io.c ./kalasag_util.c
+
+
+openbsd:              
+               SYSTYPE=openbsd
+               @echo "Making $(SYSTYPE)"
+               $(CC) $(CFLAGS) -DBSD44 -o ./kalasag ./kalasag.c ./kalasag_io.c ./kalasag_util.c
+
+
+freebsd:              
+               SYSTYPE=freebsd
+               @echo "Making $(SYSTYPE)"
+               $(CC) $(CFLAGS) -DBSD44 -o ./kalasag ./kalasag.c ./kalasag_io.c ./kalasag_util.c
+
+osx:          
+               SYSTYPE=osx
+               @echo "Making $(SYSTYPE)"
+               $(CC) $(CFLAGS) -DBSD44 -o ./kalasag ./kalasag.c ./kalasag_io.c ./kalasag_util.c
+
+
+netbsd:               
+               SYSTYPE=netbsd
+               @echo "Making $(SYSTYPE)"
+               $(CC) $(CFLAGS) -DBSD44 -o ./kalasag ./kalasag.c ./kalasag_io.c ./kalasag_util.c
+
+
+bsdi:         
+               SYSTYPE=bsdi
+               @echo "Making $(SYSTYPE)"
+               $(CC) $(CFLAGS) -DBSD44 -o ./kalasag ./kalasag.c ./kalasag_io.c ./kalasag_util.c
+
+
+generic:              
+               SYSTYPE=generic
+               @echo "Making $(SYSTYPE)"
+               $(CC) $(CFLAGS) -o ./kalasag ./kalasag.c ./kalasag_io.c ./kalasag_util.c
+
+
+hpux:         
+               SYSTYPE=hpux
+               @echo "Making $(SYSTYPE)"
+               $(CC) -Ae -DHPUX -o ./kalasag ./kalasag.c ./kalasag_io.c ./kalasag_util.c
+
+
+hpux-gcc:
+               SYSTYPE=hpux-gcc
+               @echo "Making $(SYSTYPE)"
+               $(CC) $(CFLAGS) -DHPUX -o ./kalasag ./kalasag.c ./kalasag_io.c ./kalasag_util.c
+
+
+solaris:              
+               SYSTYPE=solaris
+               @echo "Making $(SYSTYPE)"
+               $(CC) -lnsl -lsocket -lresolv -lc -o ./kalasag ./kalasag.c ./kalasag_io.c ./kalasag_util.c
+
+
+aix:          
+               SYSTYPE=aix
+               @echo "Making $(SYSTYPE)"
+               $(CC) $(CFLAGS) -o ./kalasag ./kalasag.c ./kalasag_io.c ./kalasag_util.c
+
+
+osf:
+               SYSTYPE=osf
+               @echo "Making $(SYSTYPE)"
+               $(CC) $(CFLAGS) -taso -ldb -o ./kalasag ./kalasag.c ./kalasag_io.c ./kalasag_util.c
+
+
+irix:
+               SYSTYPE=irix
+               @echo "Making $(SYSTYPE)"
+               $(CC) $(CFLAGS) -O -n32 -mips3 -o ./kalasag ./kalasag.c ./kalasag_io.c ./kalasag_util.c
+
+
+# NeXTSTEP Users. NeXT used to work, but we changed the log function and
+# it now uses vsnprintf() to format strings. This means that this
+# version does not work under NeXTSTEP until we can find a workable
+# vsnprintf() call to put in the program. Sorry. If you have some good
+# vsnprintf() code to use under NeXT please send it to us and we'll
+# include it on the next update.
+#next:        
+#              SYSTYPE=next
+#              @echo "Making $(SYSTYPE)"
+#              $(CC) $(CFLAGS) -DNEXT -DHAS_NO_SNPRINTF -posix -o ./kalasag ./kalasag.c ./kalasag_io.c ./kalasag_util.c
diff --git a/kalasag.c b/kalasag.c
new file mode 100644
index 0000000..2145b43
--- /dev/null
+++ b/kalasag.c
@@ -0,0 +1,1536 @@
+#include "kalasag.h"
+#include "kalasag_io.h"
+#include "kalasag_util.h"
+
+/* Global variables */
+char gblScanDetectHost[MAXSTATE][IPMAXBUF];
+char gblKillRoute[MAXBUF];
+char gblKillHostsDeny[MAXBUF];
+char gblKillRunCmd[MAXBUF];
+char gblBlockedFile[MAXBUF];
+char gblHistoryFile[MAXBUF];
+char gblIgnoreFile[MAXBUF];
+char gblDetectionType[MAXBUF];
+
+int gblScanDetectCount = 0;
+int gblBlockTCP = 0;
+int gblBlockUDP = 0;
+int gblRunCmdFirst = 0;
+int gblResolveHost = 0;
+int gblConfigTriggerCount = 0;
+
+int main(int argc, char *argv[])
+{
+    if (argc != 2) {
+       Usage();
+       Exit(ERROR);
+    }
+
+    if ((geteuid()) && (getuid()) != 0) {
+       printf("You need to be root to run this.\n");
+       Exit(ERROR);
+    }
+
+
+    /* Cheesy arg parser. Some systems don't support getopt and I don't want to port it. */
+    if ((strcmp(argv[1], "-tcp")) && (strcmp(argv[1], "-udp"))
+       && (strcmp(argv[1], "-stcp")) && (strcmp(argv[1], "-atcp"))
+       && (strcmp(argv[1], "-sudp")) && (strcmp(argv[1], "-audp")) != 0) {
+       Usage();
+       Exit(ERROR);
+    } else {
+       Start();
+       /* This copies the startup type to a global for later use */
+       if ((SafeStrncpy
+            (gblDetectionType, strstr(argv[1], "-") + 1, MAXBUF))
+           == NULL) {
+           Log("adminalert: ERROR: Error setting internal scan detection type.\n");
+           printf("ERROR: Error setting internal scan detection type.\n");
+           printf("ERROR: Kalasag is shutting down!\n");
+           Exit(ERROR);
+       } else if (CheckConfig() == FALSE) {
+           Log("adminalert: ERROR: Configuration files are missing/corrupted. Shutting down.\n");
+           printf("ERROR: Configuration files are missing/corrupted.\n");
+           printf
+               ("ERROR: Check your syslog for a more detailed error message.\n");
+           printf("ERROR: Kalasag is shutting down!\n");
+           Exit(ERROR);
+       } else if (InitConfig() == FALSE) {
+           Log("adminalert: ERROR: Your config file is corrupted/missing mandatory option! Shutting down.\n");
+           printf
+               ("ERROR: Your config file is corrupted/missing mandatory option!\n");
+           printf
+               ("ERROR: Check your syslog for a more detailed error message.\n");
+           printf("ERROR: Kalasag is shutting down!\n");
+           Exit(ERROR);
+       }
+#ifndef NODAEMON
+       else if (DaemonSeed() == ERROR) {
+           Log("adminalert: ERROR: could not go into daemon mode. Shutting down.\n");
+           printf
+               ("ERROR: could not go into daemon mode. Shutting down.\n");
+           Exit(ERROR);
+       }
+#endif
+    }
+
+
+    if (strcmp(argv[1], "-tcp") == 0) {
+       if (KalasagModeTCP() == ERROR) {
+           Log("adminalert: ERROR: could not go into Kalasag mode. Shutting down.\n");
+           Exit(ERROR);
+       }
+    }
+#ifdef SUPPORT_STEALTH
+    else if (strcmp(argv[1], "-stcp") == 0) {
+       if (KalasagStealthModeTCP() == ERROR) {
+           Log("adminalert: ERROR: could not go into Kalasag mode. Shutting down.\n");
+           Exit(ERROR);
+       }
+    } else if (strcmp(argv[1], "-atcp") == 0) {
+       if (KalasagAdvancedStealthModeTCP() == ERROR) {
+           Log("adminalert: ERROR: could not go into Kalasag mode. Shutting down.\n");
+           Exit(ERROR);
+       }
+    } else if (strcmp(argv[1], "-sudp") == 0) {
+       if (KalasagStealthModeUDP() == ERROR) {
+           Log("adminalert: ERROR: could not go into Kalasag mode. Shutting down.\n");
+           Exit(ERROR);
+       }
+    } else if (strcmp(argv[1], "-audp") == 0) {
+       if (KalasagAdvancedStealthModeUDP() == ERROR) {
+           Log("adminalert: ERROR: could not go into Kalasag mode. Shutting down.\n");
+           Exit(ERROR);
+       }
+    }
+#endif
+    else if (strcmp(argv[1], "-udp") == 0) {
+       if (KalasagModeUDP() == ERROR) {
+           Log("adminalert: ERROR: could not go into Kalasag mode. Shutting down.\n");
+           Exit(ERROR);
+       }
+    }
+
+    Exit(TRUE);
+    /* shuts up compiler warning */
+    return (0);
+}
+
+/****************************************************************/
+/* Reads generic config options into global variables           */
+/****************************************************************/
+int InitConfig(void)
+{
+    FILE *input;
+    char configToken[MAXBUF];
+
+    gblBlockTCP = CheckFlag("BLOCK_TCP");
+    gblBlockUDP = CheckFlag("BLOCK_UDP");
+    gblResolveHost = CheckFlag("RESOLVE_HOST");
+
+    memset(gblKillRoute, '\0', MAXBUF);
+    memset(gblKillHostsDeny, '\0', MAXBUF);
+    memset(gblKillRunCmd, '\0', MAXBUF);
+
+    if ((ConfigTokenRetrieve("SCAN_TRIGGER", configToken)) == FALSE) {
+       Log("adminalert: ERROR: Could not read SCAN_TRIGGER option from config file. Disabling SCAN DETECTION TRIGGER");
+       gblConfigTriggerCount = 0;
+    } else {
+#ifdef DEBUG
+       Log("debug: InitConfig: retrieved SCAN_TRIGGER option: %s \n",
+           configToken);
+#endif
+       gblConfigTriggerCount = atoi(configToken);
+    }
+
+    if ((ConfigTokenRetrieve("KILL_ROUTE", gblKillRoute)) == TRUE) {
+#ifdef DEBUG
+       Log("debug: InitConfig: retrieved KILL_ROUTE option: %s \n",
+           gblKillRoute);
+#endif
+    } else {
+#ifdef DEBUG
+       Log("debug: InitConfig: KILL_ROUTE option NOT FOUND.\n");
+#endif
+    }
+
+    if ((ConfigTokenRetrieve("KILL_HOSTS_DENY", gblKillHostsDeny)) == TRUE) {
+#ifdef DEBUG
+       Log("debug: InitConfig: retrieved KILL_HOSTS_DENY option: %s \n",
+           gblKillHostsDeny);
+#endif
+    } else {
+#ifdef DEBUG
+       Log("debug: InitConfig: KILL_HOSTS_DENY option NOT FOUND.\n");
+#endif
+    }
+
+    if ((ConfigTokenRetrieve("KILL_RUN_CMD", gblKillRunCmd)) == TRUE) {
+#ifdef DEBUG
+       Log("debug: InitConfig: retrieved KILL_RUN_CMD option: %s \n",
+           gblKillRunCmd);
+#endif
+       /* Check the order we should run the KILL_RUN_CMD */
+       /* Default is to run the command after blocking */
+       gblRunCmdFirst = CheckFlag("KILL_RUN_CMD_FIRST");
+    } else {
+#ifdef DEBUG
+       Log("debug: InitConfig: KILL_RUN_CMD option NOT FOUND.\n");
+#endif
+    }
+
+    if ((ConfigTokenRetrieve("BLOCKED_FILE", gblBlockedFile)) == TRUE) {
+       if (strlen(gblBlockedFile) < MAXBUF - 5) {
+           strncat(gblBlockedFile, ".", 1);
+           strncat(gblBlockedFile, gblDetectionType, 4);
+       } else {
+           Log("adminalert: ERROR: Blocked filename is too long to append detection type file extension: %s.\n", gblBlockedFile);
+           return (FALSE);
+       }
+#ifdef DEBUG
+       Log("debug: InitConfig: retrieved BLOCKED_FILE option: %s \n",
+           gblBlockedFile);
+       Log("debug: CheckConfig: Removing old block file: %s \n",
+           gblBlockedFile);
+#endif
+
+       if ((input = fopen(gblBlockedFile, "w")) == NULL) {
+           Log("adminalert: ERROR: Cannot delete blocked file on startup: %s.\n", gblBlockedFile);
+           return (FALSE);
+       } else
+           fclose(input);
+    } else {
+       Log("InitConfig: Cannot retrieve BLOCKED_FILE option! Aborting\n");
+       return (FALSE);
+    }
+
+
+    if ((ConfigTokenRetrieve("HISTORY_FILE", gblHistoryFile)) == TRUE) {
+#ifdef DEBUG
+       Log("debug: InitConfig: retrieved HISTORY_FILE option: %s \n",
+           gblHistoryFile);
+#endif
+    } else {
+       Log("InitConfig: Cannot retrieve HISTORY_FILE option! Aborting\n");
+       return (FALSE);
+    }
+
+    if ((ConfigTokenRetrieve("IGNORE_FILE", gblIgnoreFile)) == TRUE) {
+#ifdef DEBUG
+       Log("debug: InitConfig: retrieved IGNORE_FILE option: %s \n",
+           gblIgnoreFile);
+#endif
+    } else {
+       Log("InitConfig: Cannot retrieve IGNORE_FILE option! Aborting\n");
+       return (FALSE);
+    }
+
+    return (TRUE);
+}
+
+
+#ifdef SUPPORT_STEALTH
+
+/* Read in a TCP packet taking into account IP options and other */
+/* errors */
+int PacketReadTCP(int socket, struct iphdr *ipPtr, struct tcphdr *tcpPtr)
+{
+    char packetBuffer[TCPPACKETLEN];
+    struct in_addr addr;
+
+    bzero(ipPtr, sizeof(struct iphdr));
+    bzero(tcpPtr, sizeof(struct tcphdr));
+
+    if (read(socket, packetBuffer, TCPPACKETLEN) == ERROR)
+       return (ERROR);
+
+    memcpy(ipPtr, (struct iphdr *) packetBuffer, sizeof(struct iphdr));
+
+    if ((ipPtr->ihl < 5) || (ipPtr->ihl > 15)) {
+       addr.s_addr = (u_int) ipPtr->saddr;
+       Log("attackalert: Illegal IP header length detected in TCP packet: %d from (possible) host: %s\n", ipPtr->ihl, inet_ntoa(addr));
+       return (FALSE);
+    } else {
+       memcpy(tcpPtr,
+              (struct tcphdr *) (packetBuffer + ((ipPtr->ihl) * 4)),
+              sizeof(struct tcphdr));
+       return (TRUE);
+    }
+
+}
+
+/* Read in a UDP packet taking into account IP options and other */
+/* errors */
+int PacketReadUDP(int socket, struct iphdr *ipPtr, struct udphdr *udpPtr)
+{
+    char packetBuffer[UDPPACKETLEN];
+    struct in_addr addr;
+
+    bzero(ipPtr, sizeof(struct iphdr));
+    bzero(udpPtr, sizeof(struct udphdr));
+
+    if (read(socket, packetBuffer, UDPPACKETLEN) == ERROR)
+       return (ERROR);
+
+    memcpy(ipPtr, (struct iphdr *) packetBuffer, sizeof(struct iphdr));
+
+    if ((ipPtr->ihl < 5) || (ipPtr->ihl > 15)) {
+       addr.s_addr = (u_int) ipPtr->saddr;
+       Log("attackalert: Illegal IP header length detected in UDP packet: %d from (possible) host: %s\n", ipPtr->ihl, inet_ntoa(addr));
+       return (FALSE);
+    } else {
+       memcpy(udpPtr,
+              (struct udphdr *) (packetBuffer + ((ipPtr->ihl) * 4)),
+              sizeof(struct udphdr));
+       return (TRUE);
+    }
+
+}
+
+/****************************************************************/
+/* Stealth scan detection Mode One                              */
+/*                                                              */
+/* This mode will read in a list of ports to monitor and will   */
+/* then open a raw socket to look for packets matching the port. */
+/*                                                              */
+/****************************************************************/
+int KalasagStealthModeTCP(void)
+{
+    struct sockaddr_in client, server;
+    int portCount = 0, portCount2 = 0, ports[MAXSOCKS], ports2[MAXSOCKS];
+    int count = 0, scanDetectTrigger = TRUE, gotBound = FALSE, result =
+       TRUE;
+    int openSockfd = 0, incomingPort = 0;
+    char *temp, target[IPMAXBUF], configToken[MAXBUF];
+    char resolvedHost[DNSMAXBUF], *packetType;
+    struct in_addr addr;
+    struct iphdr ip;
+    struct tcphdr tcp;
+
+    if ((ConfigTokenRetrieve("TCP_PORTS", configToken)) == FALSE) {
+       Log("adminalert: ERROR: Could not read TCP_PORTS option from config file");
+       return (ERROR);
+    }
+
+    /* break out the ports */
+    if ((temp = (char *) strtok(configToken, ",")) != NULL) {
+       ports[0] = atoi(temp);
+       for (count = 1; count < MAXSOCKS; count++) {
+           if ((temp = (char *) strtok(NULL, ",")) != NULL)
+               ports[count] = atoi(temp);
+           else
+               break;
+       }
+       portCount = count;
+    } else {
+       Log("adminalert: ERROR: No TCP ports supplied in config file. Aborting");
+       return (ERROR);
+    }
+
+    /* ok, now check if they have a network daemon on the socket already, if they do */
+    /* then skip that port because it will cause false alarms */
+    for (count = 0; count < portCount; count++) {
+       Log("adminalert: Going into stealth listen mode on TCP port: %d\n",
+           ports[count]);
+       if ((openSockfd = OpenTCPSocket()) == ERROR) {
+           Log("adminalert: ERROR: could not open TCP socket. Aborting.\n");
+           return (ERROR);
+       }
+
+       if (BindSocket(openSockfd, client, server, ports[count]) == ERROR)
+           Log("adminalert: ERROR: Socket %d is in use and will not be monitored. Attempting to continue\n", ports[count]);
+       else {                  /* well we at least bound to one socket so we'll continue */
+
+           gotBound = TRUE;
+           ports2[portCount2++] = ports[count];
+       }
+       close(openSockfd);
+    }
+
+    /* if we didn't bind to anything then abort */
+    if (gotBound == FALSE) {
+       Log("adminalert: ERROR: All supplied TCP sockets are in use and will not be listened to. Shutting down.\n");
+       return (ERROR);
+    }
+
+    /* Open our raw socket for network IO */
+    if ((openSockfd = OpenRAWTCPSocket()) == ERROR) {
+       Log("adminalert: ERROR: could not open RAW TCP socket. Aborting.\n");
+       return (ERROR);
+    }
+
+    Log("adminalert: Kalasag is now active and listening.\n");
+
+    /* main detection loop */
+    for (;;) {
+       if (PacketReadTCP(openSockfd, &ip, &tcp) != TRUE)
+           continue;
+
+
+       incomingPort = ntohs(tcp.dest);
+
+       /* check for an ACK/RST to weed out established connections in case the user */
+       /* is monitoring high ephemeral port numbers */
+       if ((tcp.ack != 1) && (tcp.rst != 1)) {
+           /* this iterates the list of ports looking for a match */
+           for (count = 0; count < portCount; count++) {
+               if (incomingPort == ports2[count]) {
+                   if (SmartVerifyTCP(client, server, incomingPort) ==
+                       TRUE)
+                       break;
+
+                   /* copy the clients address into our buffer for nuking */
+                   addr.s_addr = (u_int) ip.saddr;
+                   SafeStrncpy(target, (char *) inet_ntoa(addr),
+                               IPMAXBUF);
+                   /* check if we should ignore this IP */
+                   result = NeverBlock(target, gblIgnoreFile);
+
+                   if (result == ERROR) {
+                       Log("attackalert: ERROR: cannot open ignore file. Blocking host anyway.\n");
+                       result = FALSE;
+                   }
+
+                   if (result == FALSE) {
+                       /* check if they've visited before */
+                       scanDetectTrigger = CheckStateEngine(target);
+                       if (scanDetectTrigger == TRUE) {
+                           if (gblResolveHost) {       /* Do they want DNS resolution? */
+                               if (CleanAndResolve(resolvedHost, target)
+                                   != TRUE) {
+                                   Log("attackalert: ERROR: Error resolving host. \
+                                             resolving disabled for this host.\n");
+                                   snprintf(resolvedHost, DNSMAXBUF, "%s",
+                                            target);
+                               }
+                           } else {
+                               snprintf(resolvedHost, DNSMAXBUF, "%s",
+                                        target);
+                           }
+
+                           packetType = ReportPacketType(tcp);
+                           Log("attackalert: %s from host: %s/%s to TCP port: %d", packetType, resolvedHost, target, ports2[count]);
+                           /* Report on options present */
+                           if (ip.ihl > 5)
+                               Log("attackalert: Packet from host: %s/%s to TCP port: %d has IP options set (detection avoidance technique).", resolvedHost, target, ports2[count]);
+
+                           /* check if this target is already blocked */
+                           if (IsBlocked(target, gblBlockedFile) == FALSE) {
+                               /* toast the prick */
+                               if (DisposeTCP(target, ports2[count]) !=
+                                   TRUE)
+                                   Log("attackalert: ERROR: Could not block host %s/%s !!", resolvedHost, target);
+                               else
+                                   WriteBlocked(target, resolvedHost,
+                                                ports2[count],
+                                                gblBlockedFile,
+                                                gblHistoryFile, "TCP");
+                           } /* end IsBlocked check */
+                           else
+                               Log("attackalert: Host: %s/%s is already blocked Ignoring", resolvedHost, target);
+                       }       /* end if(scanDetectTrigger) */
+                   }           /* end if(never block) check */
+                   break;      /* get out of for(count) loop above */
+               }               /* end if(incoming port) ==  protected port */
+           }                   /* end for( check for protected port loop ) loop */
+       }                       /* end if(TH_ACK) check */
+    }                          /* end for( ; ; ) loop */
+
+}                              /* end KalasagStealthModeTCP */
+
+
+/****************************************************************/
+/* Advanced Stealth scan detection Mode One                     */
+/*                                                              */
+/* This mode will see what ports are listening below 1024       */
+/* and will then monitor all the rest. This is very sensitive   */
+/* and will react on any packet hitting any monitored port,     */
+/* regardless of TCP flags set                                  */
+/*                                                              */
+/****************************************************************/
+int KalasagAdvancedStealthModeTCP(void)
+{
+    struct sockaddr_in client, server;
+    int result = TRUE, scanDetectTrigger = TRUE, hotPort = TRUE;
+    int openSockfd = 0, incomingPort = 0, smartVerify = FALSE;
+    unsigned int advancedPorts = 1024;
+    unsigned int count = 0, inUsePorts[MAXSOCKS], portCount = 0;
+    char target[IPMAXBUF], configToken[MAXBUF];
+    char resolvedHost[DNSMAXBUF], *temp, *packetType;
+    struct in_addr addr;
+    struct iphdr ip;
+    struct tcphdr tcp;
+
+    if ((ConfigTokenRetrieve("ADVANCED_PORTS_TCP", configToken)) == FALSE) {
+       Log("adminalert: ERROR: Could not read ADVANCED_PORTS_TCP option from config file. Assuming 1024.");
+       advancedPorts = 1024;
+    } else
+       advancedPorts = atoi(configToken);
+
+    Log("adminalert: Advanced mode will monitor first %d ports",
+       advancedPorts);
+
+    /* try to bind to all ports below 1024, any that are taken we exclude later */
+    for (count = 0; count < advancedPorts; count++) {
+       if ((openSockfd = OpenTCPSocket()) == ERROR) {
+           Log("adminalert: ERROR: could not open TCP socket. Aborting.\n");
+           return (ERROR);
+       }
+       if (BindSocket(openSockfd, client, server, count) == ERROR)
+           inUsePorts[portCount++] = count;
+
+       close(openSockfd);
+    }
+
+    if ((ConfigTokenRetrieve("ADVANCED_EXCLUDE_TCP", configToken)) !=
+       FALSE) {
+       /* break out the ports */
+       if ((temp = (char *) strtok(configToken, ",")) != NULL) {
+           inUsePorts[portCount++] = atoi(temp);
+           Log("adminalert: Advanced mode will manually exclude port: %d ", inUsePorts[portCount - 1]);
+           for (count = 0; count < MAXSOCKS; count++) {
+               if ((temp = (char *) strtok(NULL, ",")) != NULL) {
+                   inUsePorts[portCount++] = atoi(temp);
+                   Log("adminalert: Advanced mode will manually exclude port: %d ", inUsePorts[portCount - 1]);
+               } else
+                   break;
+           }
+       }
+    } else
+       Log("adminalert: Advanced mode will manually exclude no ports");
+
+
+    for (count = 0; count < portCount; count++)
+       Log("adminalert: Advanced Stealth scan detection mode activated. Ignored TCP port: %d\n", inUsePorts[count]);
+
+    /* open raw socket for reading */
+    if ((openSockfd = OpenRAWTCPSocket()) == ERROR) {
+       Log("adminalert: ERROR: could not open RAW TCP socket. Aborting.\n");
+       return (ERROR);
+    }
+
+    Log("adminalert: Kalasag is now active and listening.\n");
+
+    /* main detection loop */
+    for (;;) {
+       if (PacketReadTCP(openSockfd, &ip, &tcp) != TRUE)
+           continue;
+
+       incomingPort = ntohs(tcp.dest);
+
+       /* don't monitor packets with ACK set (established) or RST */
+       /* This could be a hole in some cases */
+       if ((tcp.ack != 1) && (tcp.rst != 1)) {
+           /* check if we should ignore this connection to this port */
+           for (count = 0; count < portCount; count++) {
+               if ((incomingPort == inUsePorts[count])
+                   || (incomingPort >= advancedPorts)) {
+                   hotPort = FALSE;
+                   break;
+               } else
+                   hotPort = TRUE;
+           }
+
+           if (hotPort) {
+               smartVerify = SmartVerifyTCP(client, server, incomingPort);
+
+               if (smartVerify != TRUE) {
+                   addr.s_addr = (u_int) ip.saddr;
+                   SafeStrncpy(target, (char *) inet_ntoa(addr),
+                               IPMAXBUF);
+                   /* check if we should ignore this IP */
+                   result = NeverBlock(target, gblIgnoreFile);
+
+                   if (result == ERROR) {
+                       Log("attackalert: ERROR: cannot open ignore file. Blocking host anyway.\n");
+                       result = FALSE;
+                   }
+
+                   if (result == FALSE) {
+                       /* check if they've visited before */
+                       scanDetectTrigger = CheckStateEngine(target);
+
+                       if (scanDetectTrigger == TRUE) {
+                           if (gblResolveHost) {       /* Do they want DNS resolution? */
+                               if (CleanAndResolve(resolvedHost, target)
+                                   != TRUE) {
+                                   Log("attackalert: ERROR: Error resolving host. \
+                                               resolving disabled for this host.\n");
+                                   snprintf(resolvedHost, DNSMAXBUF, "%s",
+                                            target);
+                               }
+                           } else {
+                               snprintf(resolvedHost, DNSMAXBUF, "%s",
+                                        target);
+                           }
+
+                           packetType = ReportPacketType(tcp);
+                           Log("attackalert: %s from host: %s/%s to TCP port: %d", packetType, resolvedHost, target, incomingPort);
+                           /* Report on options present */
+                           if (ip.ihl > 5)
+                               Log("attackalert: Packet from host: %s/%s to TCP port: %d has IP options set (detection avoidance technique).", resolvedHost, target, incomingPort);
+
+                           /* check if this target is already blocked */
+                           if (IsBlocked(target, gblBlockedFile) == FALSE) {
+                               /* toast the prick */
+                               if (DisposeTCP(target, incomingPort) !=
+                                   TRUE)
+                                   Log("attackalert: ERROR: Could not block host %s/%s!!", resolvedHost, target);
+                               else
+                                   WriteBlocked(target, resolvedHost,
+                                                incomingPort,
+                                                gblBlockedFile,
+                                                gblHistoryFile, "TCP");
+                           } /* end IsBlocked check */
+                           else
+                               Log("attackalert: Host: %s/%s is already blocked Ignoring", resolvedHost, target);
+                       }       /* end if(scanDetectTrigger) */
+                   }           /* end if(never block) check */
+               }               /* end if(smartVerify) */
+           }                   /* end if(hotPort) */
+       }                       /* end if(TH_ACK) */
+    }                          /* end for( ; ; ) loop */
+}
+
+/* end KalasagAdvancedStealthModeTCP */
+
+
+
+/****************************************************************/
+/* UDP "stealth" scan detection                                 */
+/*                                                              */
+/* This mode will read in a list of ports to monitor and will   */
+/* then open a raw socket to look for packets matching the port. */
+/*                                                              */
+/****************************************************************/
+int KalasagStealthModeUDP(void)
+{
+    struct sockaddr_in client, server;
+    int portCount = 0, portCount2 = 0, ports[MAXSOCKS], ports2[MAXSOCKS],
+       result = TRUE;
+    int count = 0, scanDetectTrigger = TRUE, gotBound = FALSE;
+    int openSockfd = 0, incomingPort = 0;
+    char *temp, target[IPMAXBUF], configToken[MAXBUF];
+    char resolvedHost[DNSMAXBUF];
+    struct in_addr addr;
+    struct iphdr ip;
+    struct udphdr udp;
+
+
+    if ((ConfigTokenRetrieve("UDP_PORTS", configToken)) == FALSE) {
+       Log("adminalert: ERROR: Could not read UDP_PORTS option from config file");
+       return (ERROR);
+    }
+
+    /* break out the ports */
+    if ((temp = (char *) strtok(configToken, ",")) != NULL) {
+       ports[0] = atoi(temp);
+       for (count = 1; count < MAXSOCKS; count++) {
+           if ((temp = (char *) strtok(NULL, ",")) != NULL)
+               ports[count] = atoi(temp);
+           else
+               break;
+       }
+       portCount = count;
+    } else {
+       Log("adminalert: ERROR: No UDP ports supplied in config file. Aborting");
+       return (ERROR);
+    }
+
+    /* ok, now check if they have a network daemon on the socket already, if they do */
+    /* then skip that port because it will cause false alarms */
+    for (count = 0; count < portCount; count++) {
+       Log("adminalert: Going into stealth listen mode on UDP port: %d\n",
+           ports[count]);
+       if ((openSockfd = OpenUDPSocket()) == ERROR) {
+           Log("adminalert: ERROR: could not open UDP socket. Aborting.\n");
+           return (ERROR);
+       }
+
+       if (BindSocket(openSockfd, client, server, ports[count]) == ERROR)
+           Log("adminalert: ERROR: Socket %d is in use and will not be monitored. Attempting to continue\n", ports[count]);
+       else {
+           gotBound = TRUE;
+           ports2[portCount2++] = ports[count];
+       }
+       close(openSockfd);
+    }
+
+    if (gotBound == FALSE) {
+       Log("adminalert: ERROR: All supplied UDP sockets are in use and will not be listened to. Shutting down.\n");
+       return (ERROR);
+    }
+
+    if ((openSockfd = OpenRAWUDPSocket()) == ERROR) {
+       Log("adminalert: ERROR: could not open RAW UDP socket. Aborting.\n");
+       return (ERROR);
+    }
+
+    Log("adminalert: Kalasag is now active and listening.\n");
+
+    /* main detection loop */
+    for (;;) {
+       if (PacketReadUDP(openSockfd, &ip, &udp) != TRUE)
+           continue;
+
+       incomingPort = ntohs(udp.dest);
+
+       /* this iterates the list of ports looking for a match */
+       for (count = 0; count < portCount; count++) {
+           if (incomingPort == ports2[count]) {
+               if (SmartVerifyUDP(client, server, incomingPort) == TRUE)
+                   break;
+
+               addr.s_addr = (u_int) ip.saddr;
+               SafeStrncpy(target, (char *) inet_ntoa(addr), IPMAXBUF);
+               /* check if we should ignore this IP */
+               result = NeverBlock(target, gblIgnoreFile);
+
+               if (result == ERROR) {
+                   Log("attackalert: ERROR: cannot open ignore file. Blocking host anyway.\n");
+                   result = FALSE;
+               }
+
+               if (result == FALSE) {
+                   /* check if they've visited before */
+                   scanDetectTrigger = CheckStateEngine(target);
+                   if (scanDetectTrigger == TRUE) {
+                       if (gblResolveHost) {   /* Do they want DNS resolution? */
+                           if (CleanAndResolve(resolvedHost, target) !=
+                               TRUE) {
+                               Log("attackalert: ERROR: Error resolving host. \
+                                       resolving disabled for this host.\n");
+                               snprintf(resolvedHost, DNSMAXBUF, "%s",
+                                        target);
+                           }
+                       } else {
+                           snprintf(resolvedHost, DNSMAXBUF, "%s",
+                                    target);
+                       }
+
+                       Log("attackalert: UDP scan from host: %s/%s to UDP port: %d", resolvedHost, target, ports2[count]);
+                       /* Report on options present */
+                       if (ip.ihl > 5)
+                           Log("attackalert: Packet from host: %s/%s to UDP port: %d has IP options set (detection avoidance technique).", resolvedHost, target, incomingPort);
+
+                       /* check if this target is already blocked */
+                       if (IsBlocked(target, gblBlockedFile) == FALSE) {
+                           if (DisposeUDP(target, ports2[count]) != TRUE)
+                               Log("attackalert: ERROR: Could not block host %s/%s!!", resolvedHost, target);
+                           else
+                               WriteBlocked(target, resolvedHost,
+                                            ports2[count], gblBlockedFile,
+                                            gblHistoryFile, "UDP");
+                       } /* end IsBlocked check */
+                       else {
+                           Log("attackalert: Host: %s/%s is already blocked Ignoring", resolvedHost, target);
+                       }
+                   }           /* end if(scanDetectTrigger) */
+               }               /* end if(never block) check */
+               break;          /* get out of for(count) loop above */
+           }                   /* end if(incoming port) ==  protected port */
+       }                       /* end for( check for protected port loop ) loop */
+    }                          /* end for( ; ; ) loop */
+
+}                              /* end KalasagStealthModeUDP */
+
+
+/****************************************************************/
+/* Advanced Stealth scan detection mode for UDP                 */
+/*                                                              */
+/* This mode will see what ports are listening below 1024       */
+/* and will then monitor all the rest. This is very sensitive   */
+/* and will react on any packet hitting any monitored port.     */
+/* This is a very dangerous option and is for advanced users    */
+/*                                                              */
+/****************************************************************/
+int KalasagAdvancedStealthModeUDP(void)
+{
+    struct sockaddr_in client, server;
+    int result = TRUE, scanDetectTrigger = TRUE, hotPort = TRUE;
+    int openSockfd = 0, incomingPort = 0, smartVerify = FALSE;
+    unsigned int advancedPorts = 1024;
+    unsigned int count = 0, inUsePorts[MAXSOCKS], portCount = 0;
+    char target[IPMAXBUF], configToken[MAXBUF];
+    char resolvedHost[DNSMAXBUF], *temp;
+    struct in_addr addr;
+    struct iphdr ip;
+    struct udphdr udp;
+
+
+    if ((ConfigTokenRetrieve("ADVANCED_PORTS_UDP", configToken)) == FALSE) {
+       Log("adminalert: ERROR: Could not read ADVANCED_PORTS_UDP option from config file. Assuming 1024.");
+       advancedPorts = 1024;
+    } else
+       advancedPorts = atoi(configToken);
+
+    Log("adminalert: Advanced mode will monitor first %d ports",
+       advancedPorts);
+
+    /* try to bind to all ports below 1024, any that are taken we exclude later */
+    for (count = 0; count < advancedPorts; count++) {
+       if ((openSockfd = OpenUDPSocket()) == ERROR) {
+           Log("adminalert: ERROR: could not open UDP socket. Aborting.\n");
+           return (ERROR);
+       }
+       if (BindSocket(openSockfd, client, server, count) == ERROR)
+           inUsePorts[portCount++] = count;
+
+       close(openSockfd);
+    }
+
+    if ((ConfigTokenRetrieve("ADVANCED_EXCLUDE_UDP", configToken)) !=
+       FALSE) {
+       /* break out the ports */
+       if ((temp = (char *) strtok(configToken, ",")) != NULL) {
+           inUsePorts[portCount++] = atoi(temp);
+           Log("adminalert: Advanced mode will manually exclude port: %d ", inUsePorts[portCount - 1]);
+           for (count = 0; count < MAXSOCKS; count++) {
+               if ((temp = (char *) strtok(NULL, ",")) != NULL) {
+                   inUsePorts[portCount++] = atoi(temp);
+                   Log("adminalert: Advanced mode will manually exclude port: %d ", inUsePorts[portCount - 1]);
+               } else
+                   break;
+           }
+       }
+    } else
+       Log("adminalert: Advanced mode will manually exclude no ports");
+
+
+    for (count = 0; count < portCount; count++)
+       Log("adminalert: Advanced Stealth scan detection mode activated. Ignored UDP port: %d\n", inUsePorts[count]);
+
+    if ((openSockfd = OpenRAWUDPSocket()) == ERROR) {
+       Log("adminalert: ERROR: could not open RAW UDP socket. Aborting.\n");
+       return (ERROR);
+    }
+
+    Log("adminalert: Kalasag is now active and listening.\n");
+
+    /* main detection loop */
+    for (;;) {
+       if (PacketReadUDP(openSockfd, &ip, &udp) != TRUE)
+           continue;
+
+       incomingPort = ntohs(udp.dest);
+
+       /* check if we should ignore this connection to this port */
+       for (count = 0; count < portCount; count++) {
+           if ((incomingPort == inUsePorts[count])
+               || (incomingPort >= advancedPorts)) {
+               hotPort = FALSE;
+               break;
+           } else
+               hotPort = TRUE;
+       }
+
+       if (hotPort) {
+           smartVerify = SmartVerifyUDP(client, server, incomingPort);
+
+           if (smartVerify != TRUE) {
+               /* copy the clients address into our buffer for nuking */
+               addr.s_addr = (u_int) ip.saddr;
+               SafeStrncpy(target, (char *) inet_ntoa(addr), IPMAXBUF);
+               /* check if we should ignore this IP */
+               result = NeverBlock(target, gblIgnoreFile);
+
+               if (result == ERROR) {
+                   Log("attackalert: ERROR: cannot open ignore file. Blocking host anyway.\n");
+                   result = FALSE;
+               }
+
+               if (result == FALSE) {
+                   /* check if they've visited before */
+                   scanDetectTrigger = CheckStateEngine(target);
+
+                   if (scanDetectTrigger == TRUE) {
+                       if (gblResolveHost) {   /* Do they want DNS resolution? */
+                           if (CleanAndResolve(resolvedHost, target) !=
+                               TRUE) {
+                               Log("attackalert: ERROR: Error resolving host. \
+                                       resolving disabled for this host.\n");
+                               snprintf(resolvedHost, DNSMAXBUF, "%s",
+                                        target);
+                           }
+                       } else {
+                           snprintf(resolvedHost, DNSMAXBUF, "%s",
+                                    target);
+                       }
+
+                       Log("attackalert: UDP scan from host: %s/%s to UDP port: %d", resolvedHost, target, incomingPort);
+                       /* Report on options present */
+                       if (ip.ihl > 5)
+                           Log("attackalert: Packet from host: %s/%s to UDP port: %d has IP options set (detection avoidance technique).", resolvedHost, target, incomingPort);
+
+                       /* check if this target is already blocked */
+                       if (IsBlocked(target, gblBlockedFile) == FALSE) {
+                           if (DisposeUDP(target, incomingPort) != TRUE)
+                               Log("attackalert: ERROR: Could not block host %s/%s!!", resolvedHost, target);
+                           else
+                               WriteBlocked(target, resolvedHost,
+                                            incomingPort, gblBlockedFile,
+                                            gblHistoryFile, "UDP");
+                       } /* end IsBlocked check */
+                       else
+                           Log("attackalert: Host: %s/%s is already blocked Ignoring", resolvedHost, target);
+                   }           /* end if(scanDetectTrigger) */
+               }               /* end if(never block) check */
+           }                   /* end if (smartVerify) */
+       }                       /* end if(hotPort) */
+    }                          /* end for( ; ; ) loop */
+}
+
+/* end KalasagAdvancedStealthModeUDP */
+
+#endif
+
+
+
+
+/****************************************************************/
+/* Classic detection Mode                                       */
+/*                                                              */
+/* This mode will bind to a list of TCP sockets and wait for    */
+/* connections to happen. Although the least prone to false     */
+/* alarms, it also won't detect stealth scans                   */
+/*                                                              */
+/****************************************************************/
+int KalasagModeTCP(void)
+{
+
+    struct sockaddr_in client, server;
+    int length, portCount = 0, ports[MAXSOCKS];
+    int openSockfd[MAXSOCKS], incomingSockfd, result = TRUE;
+    int count = 0, scanDetectTrigger = TRUE, showBanner =
+       FALSE, boundPortCount = 0;
+    int selectResult = 0;
+    char *temp, target[IPMAXBUF], bannerBuffer[MAXBUF],
+       configToken[MAXBUF];
+    char resolvedHost[DNSMAXBUF];
+    fd_set selectFds;
+
+    if ((ConfigTokenRetrieve("TCP_PORTS", configToken)) == FALSE) {
+       Log("adminalert: ERROR: Could not read TCP_PORTS option from config file");
+       return (ERROR);
+    }
+
+    /* break out the ports */
+    if ((temp = (char *) strtok(configToken, ",")) != NULL) {
+       ports[0] = atoi(temp);
+       for (count = 1; count < MAXSOCKS; count++) {
+           if ((temp = (char *) strtok(NULL, ",")) != NULL)
+               ports[count] = atoi(temp);
+           else
+               break;
+       }
+       portCount = count;
+    } else {
+       Log("adminalert: ERROR: No TCP ports supplied in config file. Aborting");
+       return (ERROR);
+    }
+
+    /* read in the banner if one is given */
+    if ((ConfigTokenRetrieve("PORT_BANNER", configToken)) == TRUE) {
+       showBanner = TRUE;
+       SafeStrncpy(bannerBuffer, configToken, MAXBUF);
+    }
+
+
+    /* setup select call */
+    FD_ZERO(&selectFds);
+
+    for (count = 0; count < portCount; count++) {
+       Log("adminalert: Going into listen mode on TCP port: %d\n",
+           ports[count]);
+       if ((openSockfd[boundPortCount] = OpenTCPSocket()) == ERROR) {
+           Log("adminalert: ERROR: could not open TCP socket. Aborting.\n");
+           return (ERROR);
+       }
+
+       if (BindSocket
+           (openSockfd[boundPortCount], client, server,
+            ports[count]) == ERROR) {
+           Log("adminalert: ERROR: could not bind TCP socket: %d. Attempting to continue\n", ports[count]);
+       } else                  /* well we at least bound to one socket so we'll continue */
+           boundPortCount++;
+    }
+
+
+    /* if we didn't bind to anything then abort */
+    if (boundPortCount == 0) {
+       Log("adminalert: ERROR: could not bind ANY TCP sockets. Shutting down.\n");
+       return (ERROR);
+    }
+
+    length = sizeof(client);
+
+    Log("adminalert: Kalasag is now active and listening.\n");
+
+    /* main loop for multiplexing/resetting */
+    for (;;) {
+       /* set up select call */
+       for (count = 0; count < boundPortCount; count++)
+           FD_SET(openSockfd[count], &selectFds);
+       selectResult =
+           select(MAXSOCKS, &selectFds, NULL, NULL,
+                  (struct timeval *) NULL);
+
+       /* something blew up */
+       if (selectResult < 0) {
+           Log("adminalert: ERROR: select call failed. Shutting down.\n");
+           return (ERROR);
+       } else if (selectResult == 0) {
+#ifdef DEBUG
+           Log("Select timeout");
+#endif
+       }
+
+       /* select is reporting a waiting socket. Poll them all to find out which */
+       else if (selectResult > 0) {
+           for (count = 0; count < boundPortCount; count++) {
+               if (FD_ISSET(openSockfd[count], &selectFds)) {
+                   incomingSockfd =
+                       accept(openSockfd[count],
+                              (struct sockaddr *) &client, &length);
+                   if (incomingSockfd < 0) {
+                       Log("attackalert: Possible stealth scan from unknown host to TCP port: %d (accept failed)", ports[count]);
+                       break;
+                   }
+
+                   /* copy the clients address into our buffer for nuking */
+                   SafeStrncpy(target,
+                               (char *) inet_ntoa(client.sin_addr),
+                               IPMAXBUF);
+                   /* check if we should ignore this IP */
+                   result = NeverBlock(target, gblIgnoreFile);
+
+                   if (result == ERROR) {
+                       Log("attackalert: ERROR: cannot open ignore file. Blocking host anyway.\n");
+                       result = FALSE;
+                   }
+
+                   if (result == FALSE) {
+                       /* check if they've visited before */
+                       scanDetectTrigger = CheckStateEngine(target);
+
+                       if (scanDetectTrigger == TRUE) {
+                           /* show the banner if one was selected */
+                           if (showBanner == TRUE)
+                               write(incomingSockfd, bannerBuffer,
+                                     strlen(bannerBuffer));
+                           /* we don't need the bonehead anymore */
+                           close(incomingSockfd);
+                           if (gblResolveHost) {       /* Do they want DNS resolution? */
+                               if (CleanAndResolve(resolvedHost, target)
+                                   != TRUE) {
+                                   Log("attackalert: ERROR: Error resolving host. \
+                                       resolving disabled for this host.\n");
+                                   snprintf(resolvedHost, DNSMAXBUF, "%s",
+                                            target);
+                               }
+                           } else {
+                               snprintf(resolvedHost, DNSMAXBUF, "%s",
+                                        target);
+                           }
+
+                           Log("attackalert: Connect from host: %s/%s to TCP port: %d", resolvedHost, target, ports[count]);
+
+                           /* check if this target is already blocked */
+                           if (IsBlocked(target, gblBlockedFile) == FALSE) {
+                               if (DisposeTCP(target, ports[count]) !=
+                                   TRUE)
+                                   Log("attackalert: ERROR: Could not block host %s !!", target);
+                               else
+                                   WriteBlocked(target, resolvedHost,
+                                                ports[count],
+                                                gblBlockedFile,
+                                                gblHistoryFile, "TCP");
+                           } else
+                               Log("attackalert: Host: %s is already blocked. Ignoring", target);
+                       }
+                   }
+                   close(incomingSockfd);
+                   break;
+               }               /* end if(FD_ISSET) */
+           }                   /* end for() */
+       }                       /* end else (selectResult > 0) */
+    }                          /* end main for(; ; ) loop */
+
+/* not reached */
+    close(incomingSockfd);
+}
+
+
+
+
+
+/****************************************************************/
+/* Classic detection Mode                                       */
+/*                                                              */
+/* This mode will bind to a list of UDP sockets and wait for    */
+/* connections to happen. Stealth scanning really doesn't apply */
+/* here.                                                        */
+/*                                                              */
+/****************************************************************/
+int KalasagModeUDP(void)
+{
+    struct sockaddr_in client, server;
+    int length, ports[MAXSOCKS], openSockfd[MAXSOCKS], result = TRUE;
+    int count = 0, portCount = 0, selectResult = 0, scanDetectTrigger = 0;
+    int boundPortCount = 0, showBanner = FALSE;
+    char *temp, target[IPMAXBUF], bannerBuffer[MAXBUF],
+       configToken[MAXBUF];
+    char buffer[MAXBUF];
+    char resolvedHost[DNSMAXBUF];
+    fd_set selectFds;
+
+    if ((ConfigTokenRetrieve("UDP_PORTS", configToken)) == FALSE) {
+       Log("adminalert: ERROR: Could not read UDP_PORTS option from config file");
+       return (ERROR);
+    }
+
+    /* break out the ports */
+    if ((temp = (char *) strtok(configToken, ",")) != NULL) {
+       ports[0] = atoi(temp);
+       for (count = 1; count < MAXSOCKS; count++) {
+           if ((temp = (char *) strtok(NULL, ",")) != NULL)
+               ports[count] = atoi(temp);
+           else
+               break;
+       }
+       portCount = count;
+    } else {
+       Log("adminalert: ERROR: No UDP ports supplied in config file. Aborting");
+       return (ERROR);
+    }
+
+    /* read in the banner if one is given */
+    if ((ConfigTokenRetrieve("PORT_BANNER", configToken)) == TRUE) {
+       showBanner = TRUE;
+       SafeStrncpy(bannerBuffer, configToken, MAXBUF);
+    }
+
+    /* setup select call */
+    FD_ZERO(&selectFds);
+
+    for (count = 0; count < portCount; count++) {
+       Log("adminalert: Going into listen mode on UDP port: %d\n",
+           ports[count]);
+       if ((openSockfd[boundPortCount] = OpenUDPSocket()) == ERROR) {
+           Log("adminalert: ERROR: could not open UDP socket. Aborting\n");
+           return (ERROR);
+       }
+       if (BindSocket
+           (openSockfd[boundPortCount], client, server,
+            ports[count]) == ERROR) {
+           Log("adminalert: ERROR: could not bind UDP socket: %d. Attempting to continue\n", ports[count]);
+       } else                  /* well we at least bound to one socket so we'll continue */
+           boundPortCount++;
+    }
+
+/* if we didn't bind to anything then abort */
+    if (boundPortCount == 0) {
+       Log("adminalert: ERROR: could not bind ANY UDP sockets. Shutting down.\n");
+       return (ERROR);
+    }
+
+
+    length = sizeof(client);
+    Log("adminalert: Kalasag is now active and listening.\n");
+
+/* main loop for multiplexing/resetting */
+    for (;;) {
+       /* set up select call */
+       for (count = 0; count < boundPortCount; count++)
+           FD_SET(openSockfd[count], &selectFds);
+       /* setup the select multiplexing (blocking mode) */
+       selectResult =
+           select(MAXSOCKS, &selectFds, NULL, NULL,
+                  (struct timeval *) NULL);
+
+       if (selectResult < 0) {
+           Log("adminalert: ERROR: select call failed. Shutting down.\n");
+           return (ERROR);
+       } else if (selectResult == 0) {
+#ifdef DEBUG
+           Log("Select timeout");
+#endif
+       }
+
+       /* select is reporting a waiting socket. Poll them all to find out which */
+       else if (selectResult > 0) {
+           for (count = 0; count < portCount; count++) {
+               if (FD_ISSET(openSockfd[count], &selectFds)) {
+                   /* here just read in one byte from the UDP socket, that's all we need to */
+                   /* know that this person is a jerk */
+                   if (recvfrom(openSockfd[count], buffer, 1, 0,
+                                (struct sockaddr *) &client, &length) < 0)
+                   {
+                       Log("adminalert: ERROR: could not accept incoming socket for UDP port: %d\n", ports[count]);
+                       break;
+                   }
+
+                   /* copy the clients address into our buffer for nuking */
+                   SafeStrncpy(target,
+                               (char *) inet_ntoa(client.sin_addr),
+                               IPMAXBUF);
+#ifdef DEBUG
+                   Log("debug: KalasagModeUDP: accepted UDP connection from: %s\n", target);
+#endif
+                   /* check if we should ignore this IP */
+                   result = NeverBlock(target, gblIgnoreFile);
+                   if (result == ERROR) {
+                       Log("attackalert: ERROR: cannot open ignore file. Blocking host anyway.\n");
+                       result = FALSE;
+                   }
+                   if (result == FALSE) {
+                       /* check if they've visited before */
+                       scanDetectTrigger = CheckStateEngine(target);
+                       if (scanDetectTrigger == TRUE) {
+                           /* show the banner if one was selected */
+                           if (showBanner == TRUE)
+                               sendto(openSockfd[count], bannerBuffer,
+                                      strlen(bannerBuffer), 0,
+                                      (struct sockaddr *) &client,
+                                      length);
+
+                           if (gblResolveHost) {       /* Do they want DNS resolution? */
+                               if (CleanAndResolve(resolvedHost, target)
+                                   != TRUE) {
+                                   Log("attackalert: ERROR: Error resolving host. \
+                                       resolving disabled for this host.\n");
+                                   snprintf(resolvedHost, DNSMAXBUF, "%s",
+                                            target);
+                               }
+                           } else {
+                               snprintf(resolvedHost, DNSMAXBUF, "%s",
+                                        target);
+                           }
+
+                           Log("attackalert: Connect from host: %s/%s to UDP port: %d", resolvedHost, target, ports[count]);
+                           /* check if this target is already blocked */
+                           if (IsBlocked(target, gblBlockedFile) == FALSE) {
+                               if (DisposeUDP(target, ports[count]) !=
+                                   TRUE)
+                                   Log("attackalert: ERROR: Could not block host %s !!", target);
+                               else
+                                   WriteBlocked(target, resolvedHost,
+                                                ports[count],
+                                                gblBlockedFile,
+                                                gblHistoryFile, "UDP");
+                           } else
+                               Log("attackalert: Host: %s is already blocked. Ignoring", target);
+                       }
+                   }
+                   break;
+               }               /* end if(FD_ISSET) */
+           }                   /* end for() */
+       }                       /* end else (selectResult > 0) */
+    }                          /* end main for(; ; ) loop */
+
+}                              /* end UDP Kalasag */
+
+
+
+
+/* kill the TCP connection depending on config option */
+int DisposeTCP(char *target, int port)
+{
+    int status = TRUE;
+
+#ifdef DEBUG
+    Log("debug: DisposeTCP: disposing of host %s on port %d with option: %d", target, port, gblBlockTCP);
+    Log("debug: DisposeTCP: killRunCmd: %s", gblKillRunCmd);
+    Log("debug: DisposeTCP: gblRunCmdFirst: %d", gblRunCmdFirst);
+    Log("debug: DisposeTCP: killHostsDeny: %s", gblKillHostsDeny);
+    Log("debug: DisposeTCP: killRoute: %s  %d", gblKillRoute,
+       strlen(gblKillRoute));
+#endif
+/* Should we ignore TCP from active response? */
+    if (gblBlockTCP == 1) {
+       /* run external command first, hosts.deny second, dead route last */
+       if (gblRunCmdFirst) {
+           if (strlen(gblKillRunCmd) > 0)
+               if (KillRunCmd
+                   (target, port, gblKillRunCmd,
+                    gblDetectionType) != TRUE)
+                   status = FALSE;
+           if (strlen(gblKillHostsDeny) > 0)
+               if (KillHostsDeny
+                   (target, port, gblKillHostsDeny,
+                    gblDetectionType) != TRUE)
+                   status = FALSE;
+           if (strlen(gblKillRoute) > 0)
+               if (KillRoute(target, port, gblKillRoute, gblDetectionType)
+                   != TRUE)
+                   status = FALSE;
+       }
+       /* run hosts.deny first, dead route second, external command last */
+       else {
+           if (strlen(gblKillHostsDeny) > 0)
+               if (KillHostsDeny
+                   (target, port, gblKillHostsDeny,
+                    gblDetectionType) != TRUE)
+                   status = FALSE;
+           if (strlen(gblKillRoute) > 0)
+               if (KillRoute(target, port, gblKillRoute, gblDetectionType)
+                   != TRUE)
+                   status = FALSE;
+           if (strlen(gblKillRunCmd) > 0)
+               if (KillRunCmd
+                   (target, port, gblKillRunCmd,
+                    gblDetectionType) != TRUE)
+                   status = FALSE;
+       }
+    } else if (gblBlockTCP == 2) {
+       /* run external command only */
+       if (strlen(gblKillRunCmd) > 0)
+           if (KillRunCmd(target, port, gblKillRunCmd, gblDetectionType)
+               != TRUE)
+               status = FALSE;
+    } else
+       Log("attackalert: Ignoring TCP response per configuration file setting.");
+
+    return (status);
+}
+
+
+/* kill the UDP connection depending on config option */
+int DisposeUDP(char *target, int port)
+{
+    int status = TRUE;
+
+#ifdef DEBUG
+    Log("debug: DisposeUDP: disposing of host %s on port %d with option: %d", target, port, gblBlockUDP);
+    Log("debug: DisposeUDP: killRunCmd: %d", gblKillRunCmd);
+    Log("debug: DisposeUDP: gblRunCmdFirst: %s", gblRunCmdFirst);
+    Log("debug: DisposeUDP: killHostsDeny: %s", gblKillHostsDeny);
+    Log("debug: DisposeUDP: killRoute: %s  %d", gblKillRoute,
+       strlen(gblKillRoute));
+#endif
+/* Should we ignore TCP from active response? */
+    if (gblBlockUDP == 1) {
+       /* run external command first, hosts.deny second, dead route last */
+       if (gblRunCmdFirst) {
+           if (strlen(gblKillRunCmd) > 0)
+               if (KillRunCmd
+                   (target, port, gblKillRunCmd,
+                    gblDetectionType) != TRUE)
+                   status = FALSE;
+           if (strlen(gblKillHostsDeny) > 0)
+               if (KillHostsDeny
+                   (target, port, gblKillHostsDeny,
+                    gblDetectionType) != TRUE)
+                   status = FALSE;
+           if (strlen(gblKillRoute) > 0)
+               if (KillRoute(target, port, gblKillRoute, gblDetectionType)
+                   != TRUE)
+                   status = FALSE;
+       }
+       /* run hosts.deny first, dead route second, external command last */
+       else {
+           if (strlen(gblKillHostsDeny) > 0)
+               if (KillHostsDeny
+                   (target, port, gblKillHostsDeny,
+                    gblDetectionType) != TRUE)
+                   status = FALSE;
+           if (strlen(gblKillRoute) > 0)
+               if (KillRoute(target, port, gblKillRoute, gblDetectionType)
+                   != TRUE)
+                   status = FALSE;
+           if (strlen(gblKillRunCmd) > 0)
+               if (KillRunCmd
+                   (target, port, gblKillRunCmd,
+                    gblDetectionType) != TRUE)
+                   status = FALSE;
+       }
+    } else if (gblBlockUDP == 2) {
+       /* run external command only */
+       if (strlen(gblKillRunCmd) > 0)
+           if (KillRunCmd(target, port, gblKillRunCmd, gblDetectionType)
+               != TRUE)
+               status = FALSE;
+    } else
+       Log("attackalert: Ignoring UDP response per configuration file setting.");
+
+    return (status);
+}
+
+
+/* duh */
+void Usage(void)
+{
+    printf("Kalasag Port Scan Detector\n");
+    printf("Version: %s\n\n", VERSION);
+#ifdef SUPPORT_STEALTH
+    printf("usage: kalasag [-tcp -udp -stcp -atcp -sudp -audp]\n\n");
+#else
+    printf("Stealth scan detection not supported on this platform\n");
+    printf("usage: kalasag [-tcp -udp]\n\n");
+#endif
+/*
+  printf ("*** PLEASE READ THE DOCS BEFORE USING *** \n\n");
+*/
+}
+
+
+
+/* our cheesy state engine to monitor who has connected here before */
+int CheckStateEngine(char *target)
+{
+    int count = 0, scanDetectTrigger = TRUE;
+    int gotOne = 0;
+
+/* This is the rather basic scan state engine. It maintains     */
+/* an array of past hosts who triggered a connection on a port */
+/* when a new host arrives it is compared against the array */
+/* if it is found in the array it increments a state counter by */
+/* one and checks the remainder of the array. It does this until */
+/* the end is reached or the trigger value has been exceeded */
+/* This would probably be better as a linked list/hash table, */
+/* but for the number of hosts we are tracking this is just as good. */
+/* This will probably change in the future */
+
+    gotOne = 1;                        /* our flag counter if we get a match */
+    scanDetectTrigger = TRUE;  /* set to TRUE until set otherwise */
+
+    if (gblConfigTriggerCount > 0) {
+       for (count = 0; count < MAXSTATE; count++) {
+           /* if the array has the IP address then increment the gotOne counter and */
+           /* check the trigger value. If it is exceeded break out of the loop and */
+           /* set the detecttrigger to TRUE */
+           if (strcmp(gblScanDetectHost[count], target) == 0) {
+               /* compare the number of matches to the configured trigger value */
+               /* if we've exceeded we can stop this noise */
+               if (++gotOne >= gblConfigTriggerCount) {
+                   scanDetectTrigger = TRUE;
+#ifdef DEBUG
+                   Log("debug: CheckStateEngine: host: %s has exceeded trigger value: %d\n", gblScanDetectHost[count], gblConfigTriggerCount);
+#endif
+                   break;
+               }
+           } else
+               scanDetectTrigger = FALSE;
+       }
+
+       /* now add the fresh meat into the state engine */
+       /* if our array is still less than MAXSTATE large add it to the end */
+       if (gblScanDetectCount < MAXSTATE) {
+           SafeStrncpy(gblScanDetectHost[gblScanDetectCount], target,
+                       IPMAXBUF);
+           gblScanDetectCount++;
+       } else {
+           /* otherwise tack it to the beginning and start overwriting older ones */
+           gblScanDetectCount = 0;
+           SafeStrncpy(gblScanDetectHost[gblScanDetectCount], target,
+                       IPMAXBUF);
+           gblScanDetectCount++;
+       }
+
+#ifdef DEBUG
+       for (count = 0; count < MAXSTATE; count++)
+           Log("debug: CheckStateEngine: state engine host: %s -> position: %d Detected: %d\n", gblScanDetectHost[count], count, scanDetectTrigger);
+#endif
+       /* end catch to set state if gblConfigTriggerCount == 0 */
+       if (gotOne >= gblConfigTriggerCount)
+           scanDetectTrigger = TRUE;
+    }
+
+
+    if (gblConfigTriggerCount > MAXSTATE) {
+       Log("securityalert: WARNING: Trigger value %d is larger than state engine capacity of %d.\n", gblConfigTriggerCount);
+       Log("Adjust the value lower or recompile with a larger state engine value.\n", MAXSTATE);
+       Log("securityalert: Blocking host anyway because of invalid trigger value");
+       scanDetectTrigger = TRUE;
+    }
+    return (scanDetectTrigger);
+}
+
+
+#ifdef SUPPORT_STEALTH
+/* This takes a tcp packet and reports what type of scan it is */
+char *ReportPacketType(struct tcphdr tcpPkt)
+{
+    static char packetDesc[MAXBUF];
+    static char *packetDescPtr = packetDesc;
+
+    if ((tcpPkt.syn == 0) && (tcpPkt.fin == 0) && (tcpPkt.ack == 0)
+       && (tcpPkt.psh == 0) && (tcpPkt.rst == 0) && (tcpPkt.urg == 0))
+       snprintf(packetDesc, MAXBUF, " TCP NULL scan");
+    else if ((tcpPkt.fin == 1) && (tcpPkt.urg == 1) && (tcpPkt.psh == 1))
+       snprintf(packetDesc, MAXBUF, "TCP XMAS scan");
+    else if ((tcpPkt.fin == 1) && (tcpPkt.syn != 1) && (tcpPkt.ack != 1)
+            && (tcpPkt.psh != 1) && (tcpPkt.rst != 1)
+            && (tcpPkt.urg != 1))
+       snprintf(packetDesc, MAXBUF, "TCP FIN scan");
+    else if ((tcpPkt.syn == 1) && (tcpPkt.fin != 1) && (tcpPkt.ack != 1)
+            && (tcpPkt.psh != 1) && (tcpPkt.rst != 1)
+            && (tcpPkt.urg != 1))
+       snprintf(packetDesc, MAXBUF, "TCP SYN/Normal scan");
+    else
+       snprintf(packetDesc, MAXBUF,
+                "Unknown Type: TCP Packet Flags: SYN: %d FIN: %d ACK: %d PSH: %d URG: %d RST: %d",
+                tcpPkt.syn, tcpPkt.fin, tcpPkt.ack, tcpPkt.psh,
+                tcpPkt.urg, tcpPkt.rst);
+
+    return (packetDescPtr);
+}
+
+int
+SmartVerifyTCP(struct sockaddr_in client, struct sockaddr_in server,
+              int port)
+{
+
+    int testSockfd;
+
+/* Ok here is where we "Smart-Verify" the socket. If the port was previously */
+/* unbound, but now appears to have someone there, then we will skip responding */
+/* to this inbound packet. This a basic "stateful" inspection of the */
+/* the connection */
+
+    if ((testSockfd = OpenTCPSocket()) == ERROR) {
+       Log("adminalert: ERROR: could not open TCP socket to smart-verify.\n");
+       return (FALSE);
+    } else {
+       if (BindSocket(testSockfd, client, server, port) == ERROR) {
+#ifdef DEBUG
+           Log("debug: SmartVerify: Smart-Verify Port In Use: %d", port);
+#endif
+           close(testSockfd);
+           return (TRUE);
+       }
+    }
+
+    close(testSockfd);
+    return (FALSE);
+}
+
+int
+SmartVerifyUDP(struct sockaddr_in client, struct sockaddr_in server,
+              int port)
+{
+    int testSockfd;
+
+/* Ok here is where we "Smart-Verify" the socket. If the port was previously */
+/* unbound, but now appears to have someone there, then we will skip responding */
+/* to this inbound packet. This essentially is a "stateful" inspection of the */
+/* the connection */
+
+    if ((testSockfd = OpenUDPSocket()) == ERROR) {
+       Log("adminalert: ERROR: could not open UDP socket to smart-verify.\n");
+       return (FALSE);
+    } else {
+       if (BindSocket(testSockfd, client, server, port) == ERROR) {
+#ifdef DEBUG
+           Log("debug: SmartVerify: Smart-Verify Port In Use: %d", port);
+#endif
+           close(testSockfd);
+           return (TRUE);
+       }
+    }
+
+    close(testSockfd);
+    return (FALSE);
+}
+
+#endif                         /* SUPPORT_STEALTH */
diff --git a/kalasag.conf b/kalasag.conf
new file mode 100644
index 0000000..aaa111b
--- /dev/null
+++ b/kalasag.conf
@@ -0,0 +1,293 @@
+# Kalasag Configuration
+#
+# IMPORTANT NOTE: You CAN NOT put spaces between your port arguments.
+#
+# The default ports will catch a large number of common probes
+#
+# All entries must be in quotes.
+
+
+#######################
+# Port Configurations #
+#######################
+#
+#
+# Some example port configs for classic and basic Stealth modes
+#
+# I like to always keep some ports at the "low" end of the spectrum.
+# This will detect a sequential port sweep really quickly and usually
+# these ports are not in use (i.e. tcpmux port 1)
+#
+# ** X-Windows Users **: If you are running X on your box, you need to be sure
+# you are not binding Kalasag to port 6000 (or port 2000 for OpenWindows users).
+# Doing so will prevent the X-client from starting properly.
+#
+# These port bindings are *ignored* for Advanced Stealth Scan Detection Mode.
+#
+
+# Un-comment these if you are really anal:
+#TCP_PORTS="1,7,9,11,15,70,79,80,109,110,111,119,138,139,143,512,513,514,515,540,635,1080,1524,2000,2001,4000,4001,5742,6000,6001,6667,12345,12346,20034,27665,30303,32771,32772,32773,32774,31337,40421,40425,49724,54320"
+#UDP_PORTS="1,7,9,66,67,68,69,111,137,138,161,162,474,513,517,518,635,640,641,666,700,2049,31335,27444,34555,32770,32771,32772,32773,32774,31337,54321"
+#
+# Use these if you just want to be aware:
+TCP_PORTS="1,11,15,79,111,119,143,540,635,1080,1524,2000,5742,6667,12345,12346,20034,27665,31337,32771,32772,32773,32774,40421,49724,54320"
+UDP_PORTS="1,7,9,69,161,162,513,635,640,641,700,37444,34555,31335,32770,32771,32772,32773,32774,31337,54321"
+#
+# Use these for just bare-bones
+#TCP_PORTS="1,11,15,110,111,143,540,635,1080,1524,2000,12345,12346,20034,32771,32772,32773,32774,49724,54320"
+#UDP_PORTS="1,7,9,69,161,162,513,640,700,32770,32771,32772,32773,32774,31337,54321"
+
+###########################################
+# Advanced Stealth Scan Detection Options #
+###########################################
+#
+# This is the number of ports you want Kalasag to monitor in Advanced mode.
+# Any port *below* this number will be monitored. Right now it watches
+# everything below 1024.
+#
+# On many Linux systems you cannot bind above port 61000. This is because
+# these ports are used as part of IP masquerading. I don't recommend you
+# bind over this number of ports. Realistically: I DON'T RECOMMEND YOU MONITOR
+# OVER 1024 PORTS AS YOUR FALSE ALARM RATE WILL ALMOST CERTAINLY RISE. You've been
+# warned! Don't write me if you have have a problem because I'll only tell
+# you to RTFM and don't run above the first 1024 ports.
+#
+#
+ADVANCED_PORTS_TCP="1024"
+ADVANCED_PORTS_UDP="1024"
+#
+# This field tells Kalasag what ports (besides listening daemons) to
+# ignore. This is helpful for services like ident that services such
+# as FTP, SMTP, and wrappers look for but you may not run (and probably
+# *shouldn't* IMHO).
+#
+# By specifying ports here Kalasag will simply not respond to
+# incoming requests, in effect Kalasag treats them as if they are
+# actual bound daemons. The default ports are ones reported as
+# problematic false alarms and should probably be left alone for
+# all but the most isolated systems/networks.
+#
+# Default TCP ident and NetBIOS service
+ADVANCED_EXCLUDE_TCP="113,139"
+# Default UDP route (RIP), NetBIOS, bootp broadcasts.
+ADVANCED_EXCLUDE_UDP="520,138,137,67"
+
+
+######################
+# Configuration Files#
+######################
+#
+# Hosts to ignore
+IGNORE_FILE="/opt/kalasag/kalasag.ignore"
+# Hosts that have been denied (running history)
+HISTORY_FILE="/opt/kalasag/kalasag.history"
+# Hosts that have been denied this session only (temporary until next restart)
+BLOCKED_FILE="/opt/kalasag/kalasag.blocked"
+
+##############################
+# Misc. Configuration Options#
+##############################
+#
+# DNS Name resolution - Setting this to "1" will turn on DNS lookups
+# for attacking hosts. Setting it to "0" (or any other value) will shut
+# it off.
+RESOLVE_HOST = "1"
+
+###################
+# Response Options#
+###################
+# Options to dispose of attacker. Each is an action that will
+# be run if an attack is detected. If you don't want a particular
+# option then comment it out and it will be skipped.
+#
+# The variable $TARGET$ will be substituted with the target attacking
+# host when an attack is detected. The variable $PORT$ will be substituted
+# with the port that was scanned.
+#
+##################
+# Ignore Options #
+##################
+# These options allow you to enable automatic response
+# options for UDP/TCP. This is useful if you just want
+# warnings for connections, but don't want to react for  
+# a particular protocol (i.e. you want to block TCP, but
+# not UDP). To prevent a possible Denial of service attack
+# against UDP and stealth scan detection for TCP, you may
+# want to disable blocking, but leave the warning enabled.
+# I personally would wait for this to become a problem before
+# doing though as most attackers really aren't doing this.
+# The third option allows you to run just the external command
+# in case of a scan to have a pager script or such execute
+# but not drop the route. This may be useful for some admins
+# who want to block TCP, but only want pager/e-mail warnings
+# on UDP, etc.
+#
+#
+# 0 = Do not block UDP/TCP scans.
+# 1 = Block UDP/TCP scans.
+# 2 = Run external command only (KILL_RUN_CMD)
+
+BLOCK_UDP="1"
+BLOCK_TCP="1"
+
+###################
+# Dropping Routes:#
+###################
+# This command is used to drop the route or add the host into
+# a local filter table.
+#
+# The gateway (333.444.555.666) should ideally be a dead host on
+# the *local* subnet. On some hosts you can also point this at
+# localhost (127.0.0.1) and get the same effect. NOTE THAT
+# 333.444.555.66 WILL *NOT* WORK. YOU NEED TO CHANGE IT!!
+#
+# ALL KILL ROUTE OPTIONS ARE COMMENTED OUT INITIALLY. Make sure you
+# uncomment the correct line for your OS. If you OS is not listed
+# here and you have a route drop command that works then please
+# mail it to me so I can include it. ONLY ONE KILL_ROUTE OPTION
+# CAN BE USED AT A TIME SO DON'T UNCOMMENT MULTIPLE LINES.
+#
+# NOTE: The route commands are the least optimal way of blocking
+# and do not provide complete protection against UDP attacks and
+# will still generate alarms for both UDP and stealth scans. I
+# always recommend you use a packet filter because they are made
+# for this purpose.
+#
+
+# Generic
+#KILL_ROUTE="/sbin/route add $TARGET$ 333.444.555.666"
+
+# Generic Linux
+#KILL_ROUTE="/sbin/route add -host $TARGET$ gw 333.444.555.666"
+
+# Newer versions of Linux support the reject flag now. This
+# is cleaner than the above option.
+#KILL_ROUTE="/sbin/route add -host $TARGET$ reject"
+
+# Generic BSD (BSDI, OpenBSD, NetBSD, FreeBSD)
+#KILL_ROUTE="/sbin/route add $TARGET$ 333.444.555.666"
+
+# Generic Sun
+#KILL_ROUTE="/usr/sbin/route add $TARGET$ 333.444.555.666 1"
+
+# NEXTSTEP
+#KILL_ROUTE="/usr/etc/route add $TARGET$ 127.0.0.1 1"
+
+# FreeBSD
+#KILL_ROUTE="route add -net $TARGET$ -netmask 255.255.255.255 127.0.0.1 -blackhole"
+
+# Digital UNIX 4.0D (OSF/1 / Compaq Tru64 UNIX)
+#KILL_ROUTE="/sbin/route add -host -blackhole $TARGET$ 127.0.0.1"
+
+# Generic HP-UX
+#KILL_ROUTE="/usr/sbin/route add net $TARGET$ netmask 255.255.255.0 127.0.0.1"
+
+##
+# Using a packet filter is the PREFERRED. The below lines
+# work well on many OS's. Remember, you can only uncomment *one*
+# KILL_ROUTE option.
+##
+
+# ipfwadm support for Linux
+#KILL_ROUTE="/sbin/ipfwadm -I -i deny -S $TARGET$ -o"
+#
+# ipfwadm support for Linux (no logging of denied packets)
+#KILL_ROUTE="/sbin/ipfwadm -I -i deny -S $TARGET$"
+#
+# ipchain support for Linux
+#KILL_ROUTE="/sbin/ipchains -I input -s $TARGET$ -j DENY -l"
+#
+# ipchain support for Linux (no logging of denied packets)
+#KILL_ROUTE="/sbin/ipchains -I input -s $TARGET$ -j DENY"
+#
+# iptables support for Linux
+KILL_ROUTE="/sbin/iptables -A INPUT -s $TARGET$ -j DROP"
+#
+# For those of you running FreeBSD (and compatible) you can
+# use their built in firewalling as well.
+#
+#KILL_ROUTE="/sbin/ipfw add 1 deny all from $TARGET$:255.255.255.255 to any"
+#
+#
+# For those running ipfilt (OpenBSD, etc.)
+# NOTE THAT YOU NEED TO CHANGE external_interface TO A VALID INTERFACE!!
+#
+#KILL_ROUTE="/bin/echo 'block in log on external_interface from $TARGET$/32 to any' | /sbin/ipf -f -"
+
+
+###############
+# TCP Wrappers#
+###############
+# This text will be dropped into the hosts.deny file for wrappers
+# to use. There are two formats for TCP wrappers:
+#
+# Format One: Old Style - The default when extended host processing
+# options are not enabled.
+#
+KILL_HOSTS_DENY="ALL: $TARGET$"
+
+# Format Two: New Style - The format used when extended option
+# processing is enabled. You can drop in extended processing
+# options, but be sure you escape all '%' symbols with a backslash
+# to prevent problems writing out (i.e. \%c \%h )
+#
+#KILL_HOSTS_DENY="ALL: $TARGET$ : DENY"
+
+###################
+# External Command#
+###################
+# This is a command that is run when a host connects, it can be whatever
+# you want it to be (pager, etc.). This command is executed before the
+# route is dropped or after depending on the KILL_RUN_CMD_FIRST option below
+#
+#
+# I NEVER RECOMMEND YOU PUT IN RETALIATORY ACTIONS AGAINST THE HOST SCANNING
+# YOU!
+#
+# TCP/IP is an *unauthenticated protocol* and people can make scans appear out
+# of thin air. The only time it is reasonably safe (and I *never* think it is
+# reasonable) to run reverse probe scripts is when using the "classic" -tcp mode.
+# This mode requires a full connect and is very hard to spoof.
+#
+# The KILL_RUN_CMD_FIRST value should be set to "1" to force the command
+# to run *before* the blocking occurs and should be set to "0" to make the
+# command run *after* the blocking has occurred.
+#
+#KILL_RUN_CMD_FIRST = "0"
+#
+#
+#KILL_RUN_CMD="/some/path/here/script $TARGET$ $PORT$"
+
+
+#####################
+# Scan trigger value#
+#####################
+# Enter in the number of port connects you will allow before an
+# alarm is given. The default is 0 which will react immediately.
+# A value of 1 or 2 will reduce false alarms. Anything higher is
+# probably not necessary. This value must always be specified, but
+# generally can be left at 0.
+#
+# NOTE: If you are using the advanced detection option you need to
+# be careful that you don't make a hair trigger situation. Because
+# Advanced mode will react for *any* host connecting to a non-used
+# below your specified range, you have the opportunity to really
+# break things. (i.e someone innocently tries to connect to you via
+# SSL [TCP port 443] and you immediately block them). Some of you
+# may even want this though. Just be careful.
+#
+SCAN_TRIGGER="0"
+
+######################
+# Port Banner Section#
+######################
+#
+# Enter text in here you want displayed to a person tripping the Kalasag.
+# I *don't* recommend taunting the person as this will aggravate them.
+# Leave this commented out to disable the feature
+#
+# Stealth scan detection modes don't use this feature
+#
+#PORT_BANNER="** UNAUTHORIZED ACCESS PROHIBITED *** YOUR CONNECTION ATTEMPT HAS BEEN LOGGED. GO AWAY."
+
+# EOF
diff --git a/kalasag.h b/kalasag.h
new file mode 100644
index 0000000..99abca2
--- /dev/null
+++ b/kalasag.h
@@ -0,0 +1,74 @@
+#define VERSION "1.0"
+
+#include <stdio.h>
+#include <syslog.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <signal.h>
+#include <time.h>
+#include <netdb.h>
+#include <string.h>
+#include <ctype.h>
+#include <errno.h>
+#include <stdarg.h>
+#include <assert.h>
+#include <sys/param.h>
+#include <sys/types.h>
+#ifndef _LINUX_C_LIB_VERSION
+#include <sys/socket.h>
+#include <sys/stat.h>
+#include <netinet/in.h>
+#endif
+#include <arpa/inet.h>
+
+#include "kalasag_config.h"
+#include "kalasag_io.h"
+#include "kalasag_util.h"
+
+#ifdef SUPPORT_STEALTH
+#ifdef LINUX
+#include "kalasag_tcpip.h"
+#include <netinet/in_systm.h>
+#endif
+
+#define TCPPACKETLEN 80
+#define UDPPACKETLEN 68
+#endif                         /* SUPPORT_STEALTH */
+
+#ifdef NEXT
+#include <ansi.h>
+#endif
+
+#define ERROR -1
+#define TRUE 1
+#define FALSE 0
+#define MAXBUF 1024
+/* max size of an IP address plus NULL */
+#define IPMAXBUF 16
+/* max sockets we can open */
+#define MAXSOCKS 64
+
+/* Really is about 1025, but we don't need the length for our purposes */
+#define DNSMAXBUF 255
+
+
+/* prototypes */
+int KalasagModeTCP(void);
+int KalasagModeUDP(void);
+int DisposeUDP(char *, int);
+int DisposeTCP(char *, int);
+int CheckStateEngine(char *);
+int InitConfig(void);
+void Usage(void);
+int SmartVerifyTCP(struct sockaddr_in, struct sockaddr_in, int);
+int SmartVerifyUDP(struct sockaddr_in, struct sockaddr_in, int);
+
+#ifdef SUPPORT_STEALTH
+int KalasagStealthModeTCP(void);
+int KalasagAdvancedStealthModeTCP(void);
+int KalasagStealthModeUDP(void);
+int KalasagAdvancedStealthModeUDP(void);
+char *ReportPacketType(struct tcphdr);
+int PacketReadTCP(int, struct iphdr *, struct tcphdr *);
+int PacketReadUDP(int, struct iphdr *, struct udphdr *);
+#endif
diff --git a/kalasag.ignore b/kalasag.ignore
new file mode 100644
index 0000000..fa804ed
--- /dev/null
+++ b/kalasag.ignore
@@ -0,0 +1,2 @@
+127.0.0.1/32
+0.0.0.0
diff --git a/kalasag_config.h b/kalasag_config.h
new file mode 100644
index 0000000..6d5c418
--- /dev/null
+++ b/kalasag_config.h
@@ -0,0 +1,15 @@
+/* These are probably ok. Be sure you change the Makefile if you */
+/* change the path */
+#define CONFIG_FILE "/opt/kalasag/kalasag.conf"
+
+/* The location of Wietse Venema's TCP Wrapper hosts.deny file */
+#define WRAPPER_HOSTS_DENY "/etc/hosts.deny"
+
+/* The default syslog is as daemon.notice. You can also use */
+/* any of the facilities from syslog.h to send messages to (LOCAL0, etc) */
+#define SYSLOG_FACILITY LOG_DAEMON
+#define SYSLOG_LEVEL LOG_NOTICE
+
+
+/* the maximum number of hosts to keep in a "previous connect" state engine*/
+#define MAXSTATE 50
diff --git a/kalasag_io.c b/kalasag_io.c
new file mode 100644
index 0000000..f181bc4
--- /dev/null
+++ b/kalasag_io.c
@@ -0,0 +1,752 @@
+#include "kalasag.h"
+#include "kalasag_io.h"
+#include "kalasag_util.h"
+
+/* Main logging function to surrogate syslog */
+void Log(char *logentry, ...)
+{
+    char logbuffer[MAXBUF];
+
+    va_list argsPtr;
+    va_start(argsPtr, logentry);
+
+    vsnprintf(logbuffer, MAXBUF, logentry, argsPtr);
+
+    va_end(argsPtr);
+
+    openlog("kalasag", LOG_PID, SYSLOG_FACILITY);
+    syslog(SYSLOG_LEVEL, "%s", logbuffer);
+    closelog();
+}
+
+
+void Exit(int status)
+{
+    Log("securityalert: Kalasag is shutting down\n");
+    Log("adminalert: Kalasag is shutting down\n");
+    exit(status);
+}
+
+
+void Start(void)
+{
+    Log("adminalert: Kalasag %s is starting.\n", VERSION);
+#ifdef DEBUG
+    printf("Compiled: " __DATE__ " at " __TIME__ "\n");
+#endif
+}
+
+
+
+/* The daemonizing code copied from Advanced Programming */
+/* in the UNIX Environment by W. Richard Stevens with minor changes */
+int DaemonSeed(void)
+{
+    int childpid;
+
+    signal(SIGALRM, SIG_IGN);
+    signal(SIGHUP, SIG_IGN);
+    signal(SIGPIPE, SIG_IGN);
+    signal(SIGTERM, Exit);
+    signal(SIGABRT, Exit);
+    signal(SIGURG, Exit);
+    signal(SIGKILL, Exit);
+
+    if ((childpid = fork()) < 0)
+       return (ERROR);
+    else if (childpid > 0)
+       exit(0);
+
+    setsid();
+    chdir("/");
+    umask(077);
+
+    /* close stdout, stdin, stderr */
+    close(0);
+    close(1);
+    close(2);
+
+    return (TRUE);
+}
+
+
+/* Compares an IP address against a listed address and its netmask*/
+int CompareIPs(char *target, char *ignoreAddr, int ignoreNetmaskBits)
+{
+    unsigned long int netmaskAddr, ipAddr, targetAddr;
+
+    ipAddr = inet_addr(ignoreAddr);
+    targetAddr = inet_addr(target);
+    netmaskAddr = htonl(0xFFFFFFFF << (32 - ignoreNetmaskBits));
+
+
+#ifdef DEBUG
+    Log("debug: target %s\n", target);
+    Log("debug: ignoreAddr %s\n", ignoreAddr);
+    Log("debug: ignoreNetmaskBits %d\n", ignoreNetmaskBits);
+    Log("debug: ipAddr %lu\n", ipAddr);
+    Log("debug: targetAddr %lu\n", targetAddr);
+    Log("debug: netmask %x\n", netmaskAddr);
+    Log("debug: mix ipAddr %lu\n", (ipAddr & netmaskAddr));
+    Log("debug: mix target %lu\n", (targetAddr & netmaskAddr));
+#endif
+
+    /* Network portion mask & op and return */
+    if ((ipAddr & netmaskAddr) == (targetAddr & netmaskAddr))
+       return (TRUE);
+    else
+       return (FALSE);
+}
+
+
+
+/* check hosts that should never be blocked */
+int NeverBlock(char *target, char *filename)
+{
+    FILE *input;
+    char buffer[MAXBUF], tempBuffer[MAXBUF], netmaskBuffer[MAXBUF];
+    char *slashPos;
+    int count = 0, dest = 0, netmaskBits = 0;
+
+#ifdef DEBUG
+    Log("debug: NeverBlock: Opening ignore file: %s \n", filename);
+#endif
+    if ((input = fopen(filename, "r")) == NULL)
+       return (ERROR);
+
+#ifdef DEBUG
+    Log("debug: NeverBlock: Doing lookup for host: %s \n", target);
+#endif
+
+    while (fgets(buffer, MAXBUF, input) != NULL) {
+       /* Reset destination counter */
+       dest = 0;
+
+       if ((buffer[0] == '#') || (buffer[0] == '\n'))
+           continue;
+
+       for (count = 0; count < strlen(buffer); count++) {
+           /* Parse out digits, colons, and slashes. Everything else rejected */
+           if ((isdigit(buffer[count])) ||
+               (buffer[count] == '.') || (buffer[count] == ':')
+               || (buffer[count] == '/')) {
+               tempBuffer[dest++] = buffer[count];
+           } else {
+               tempBuffer[dest] = '\0';
+               break;
+           }
+       }
+
+       /* Return pointer to slash if it exists and copy data to buffer */
+       slashPos = strchr(tempBuffer, '/');
+       if (slashPos) {
+           SafeStrncpy(netmaskBuffer, slashPos + 1, MAXBUF);
+           /* Terminate tempBuffer string at delimeter for later use */
+           *slashPos = '\0';
+       } else
+           /* Copy in a 32 bit netmask if none given */
+           SafeStrncpy(netmaskBuffer, "32", MAXBUF);
+
+
+       /* Convert netmaskBuffer to bits in netmask */
+       netmaskBits = atoi(netmaskBuffer);
+       if ((netmaskBits < 0) || (netmaskBits > 32)) {
+           Log("adminalert: Invalid netmask in config file: %s  Ignoring entry.\n", buffer);
+           continue;
+       }
+
+       if (CompareIPs(target, tempBuffer, netmaskBits)) {
+#ifdef DEBUG
+           Log("debug: NeverBlock: Host: %s found in ignore file with netmask %s\n", target, netmaskBuffer);
+#endif
+
+           fclose(input);
+           return (TRUE);
+       }
+
+    }                          /* end while() */
+
+#ifdef DEBUG
+    Log("debug: NeverBlock: Host: %s NOT found in ignore file\n", target);
+#endif
+
+    fclose(input);
+    return (FALSE);
+}
+
+
+/* Make sure the config file is available */
+int CheckConfig(void)
+{
+    FILE *input;
+
+    if ((input = fopen(CONFIG_FILE, "r")) == NULL) {
+       Log("adminalert: Cannot open config file: %s. Exiting\n",
+           CONFIG_FILE);
+       return (FALSE);
+    } else
+       fclose(input);
+
+    return (TRUE);
+}
+
+
+/* This writes out blocked hosts to the blocked file. It adds the hostname */
+/* time stamp, and port connection that was acted on */
+int
+WriteBlocked(char *target, char *resolvedHost, int port,
+            char *blockedFilename, char *historyFilename, char *portType)
+{
+    FILE *output;
+    int blockedStatus = TRUE, historyStatus = TRUE;
+
+    struct tm *tmptr;
+
+    time_t current_time;
+    current_time = time(0);
+    tmptr = localtime(&current_time);
+
+
+#ifdef DEBUG
+    Log("debug: WriteBlocked: Opening block file: %s \n", blockedFilename);
+#endif
+
+
+    if ((output = fopen(blockedFilename, "a")) == NULL) {
+       Log("adminalert: ERROR: Cannot open blocked file: %s.\n",
+           blockedFilename);
+       blockedStatus = FALSE;
+    } else {
+       fprintf(output,
+               "%ld - %02d/%02d/%04d %02d:%02d:%02d Host: %s/%s Port: %d %s Blocked\n",
+               current_time, tmptr->tm_mon + 1, tmptr->tm_mday,
+               tmptr->tm_year + 1900, tmptr->tm_hour, tmptr->tm_min,
+               tmptr->tm_sec, resolvedHost, target, port, portType);
+       fclose(output);
+       blockedStatus = TRUE;
+    }
+
+#ifdef DEBUG
+    Log("debug: WriteBlocked: Opening history file: %s \n",
+       historyFilename);
+#endif
+    if ((output = fopen(historyFilename, "a")) == NULL) {
+       Log("adminalert: ERROR: Cannot open history file: %s.\n",
+           historyFilename);
+       historyStatus = FALSE;
+    } else {
+       fprintf(output,
+               "%ld - %02d/%02d/%04d %02d:%02d:%02d Host: %s/%s Port: %d %s Blocked\n",
+               current_time, tmptr->tm_mon + 1, tmptr->tm_mday,
+               tmptr->tm_year + 1900, tmptr->tm_hour, tmptr->tm_min,
+               tmptr->tm_sec, resolvedHost, target, port, portType);
+       fclose(output);
+       historyStatus = TRUE;
+    }
+
+    if (historyStatus || blockedStatus == FALSE)
+       return (FALSE);
+    else
+       return (TRUE);
+}
+
+
+
+
+/* This reads a token from the config file up to the "=" and returns the string */
+/* up to the first space or NULL */
+int ConfigTokenRetrieve(char *token, char *configToken)
+{
+    FILE *config;
+    char buffer[MAXBUF], tokenBuffer[MAXBUF];
+    int count = 0;
+
+    if ((config = fopen(CONFIG_FILE, "r")) == NULL) {
+       Log("adminalert: ERROR: Cannot open config file: %s.\n",
+           CONFIG_FILE);
+       return (ERROR);
+    } else {
+#ifdef DEBUG
+       Log("debug: ConfigTokenRetrieve: checking for token %s", token);
+#endif
+       while ((fgets(buffer, MAXBUF, config)) != NULL) {
+           /* this skips comments */
+           if (buffer[0] != '#') {
+#ifdef DEBUG
+               Log("debug: ConfigTokenRetrieve: data: %s", buffer);
+#endif
+               /* search for the token and make sure the trailing character */
+               /* is a " " or "=" to make sure the entire token was found */
+               if ((strstr(buffer, token) != (char) NULL) &&
+                   ((buffer[strlen(token)] == '=')
+                    || (buffer[strlen(token)] == ' '))) {      /* cut off the '=' and send it back */
+                   if (strstr(buffer, "\"") == (char) NULL) {
+                       Log("adminalert: Quotes missing from %s token. Option skipped\n", token);
+                       fclose(config);
+                       return (FALSE);
+                   }
+
+                   SafeStrncpy(tokenBuffer, strstr(buffer, "\"") + 1,
+                               MAXBUF);
+
+                   /* strip off unprintables/linefeeds (if any) */
+                   count = 0;
+                   while (count < MAXBUF - 1) {
+                       if ((isprint(tokenBuffer[count]))
+                           && tokenBuffer[count] != '"')
+                           configToken[count] = tokenBuffer[count];
+                       else {
+                           configToken[count] = '\0';
+                           break;
+                       }
+                       count++;
+                   }
+
+#ifdef DEBUG
+                   Log("debug: ConfigTokenRetrieved token: %s\n",
+                       configToken);
+#endif
+                   configToken[MAXBUF - 1] = '\0';
+                   fclose(config);
+                   return (TRUE);
+               }
+           }
+       }
+       fclose(config);
+       return (FALSE);
+    }
+
+}
+
+
+
+
+/* This will bind a socket to a port. It works for UDP/TCP */
+int
+BindSocket(int sockfd, struct sockaddr_in client,
+          struct sockaddr_in server, int port)
+{
+#ifdef DEBUG
+    Log("debug: BindSocket: Binding to port: %d\n", port);
+#endif
+
+    bzero((char *) &server, sizeof(server));
+    server.sin_family = AF_INET;
+    server.sin_addr.s_addr = htonl(INADDR_ANY);
+    server.sin_port = htons(port);
+
+    if (bind(sockfd, (struct sockaddr *) &server, sizeof(server)) < 0) {
+#ifdef DEBUG
+       Log("debug: BindSocket: Binding failed\n");
+#endif
+       return (ERROR);
+    } else {
+#ifdef DEBUG
+       Log("debug: BindSocket: Binding successful. Doing listen\n");
+#endif
+       listen(sockfd, 5);
+       return (TRUE);
+    }
+}
+
+
+/* Open a TCP Socket */
+int OpenTCPSocket(void)
+{
+    int sockfd;
+
+#ifdef DEBUG
+    Log("debug: OpenTCPSocket: opening TCP socket\n");
+#endif
+
+    if ((sockfd = socket(AF_INET, SOCK_STREAM, 0)) < 0)
+       return (ERROR);
+    else
+       return (sockfd);
+}
+
+
+/* Open a UDP Socket */
+int OpenUDPSocket(void)
+{
+    int sockfd;
+
+#ifdef DEBUG
+    Log("debug: openUDPSocket opening UDP socket\n");
+#endif
+
+    if ((sockfd = socket(AF_INET, SOCK_DGRAM, 0)) < 0)
+       return (ERROR);
+    else
+       return (sockfd);
+}
+
+#ifdef SUPPORT_STEALTH
+/* Open a RAW TCPSocket */
+int OpenRAWTCPSocket(void)
+{
+    int sockfd;
+
+#ifdef DEBUG
+    Log("debug: OpenRAWTCPSocket: opening RAW TCP socket\n");
+#endif
+
+    if ((sockfd = socket(AF_INET, SOCK_RAW, IPPROTO_TCP)) < 0)
+       return (ERROR);
+    else
+       return (sockfd);
+}
+
+/* Open a RAW UDP Socket */
+int OpenRAWUDPSocket(void)
+{
+    int sockfd;
+
+#ifdef DEBUG
+    Log("debug: OpenRAWUDPSocket: opening RAW UDP socket\n");
+#endif
+
+    if ((sockfd = socket(AF_INET, SOCK_RAW, IPPROTO_UDP)) < 0)
+       return (ERROR);
+    else
+       return (sockfd);
+}
+#endif
+
+/* This will use a system() call to change the route of the target host to */
+/* a dead IP address on your LOCAL SUBNET. */
+int
+KillRoute(char *target, int port, char *killString, char *detectionType)
+{
+    char cleanAddr[MAXBUF], commandStringTemp[MAXBUF];
+    char commandStringTemp2[MAXBUF], commandStringFinal[MAXBUF];
+    char portString[MAXBUF];
+    int killStatus = ERROR, substStatus = ERROR;
+
+    CleanIpAddr(cleanAddr, target);
+    snprintf(portString, MAXBUF, "%d", port);
+
+    substStatus =
+       SubstString(cleanAddr, "$TARGET$", killString, commandStringTemp);
+    if (substStatus == 0) {
+       Log("adminalert: No target variable specified in KILL_ROUTE option. Skipping.\n");
+       return (ERROR);
+    } else if (substStatus == ERROR) {
+       Log("adminalert: Error trying to parse $TARGET$ Token for KILL_ROUTE. Skipping.\n");
+       return (ERROR);
+    }
+
+    if (SubstString
+       (portString, "$PORT$", commandStringTemp,
+        commandStringTemp2) == ERROR) {
+       Log("adminalert: Error trying to parse $PORT$ Token for KILL_ROUTE. Skipping.\n");
+       return (ERROR);
+    }
+
+    if (SubstString
+       (detectionType, "$MODE$", commandStringTemp2,
+        commandStringFinal) == ERROR) {
+       Log("adminalert: Error trying to parse $MODE$ Token for KILL_ROUTE. Skipping.\n");
+       return (ERROR);
+    }
+
+#ifdef DEBUG
+    Log("debug: KillRoute: running route command: %s\n",
+       commandStringFinal);
+#endif
+
+    /* Kill the bastard and report a status */
+    killStatus = system(commandStringFinal);
+
+    if (killStatus == 127) {
+       Log("adminalert: ERROR: There was an error trying to block host (exec fail) %s", target);
+       return (ERROR);
+    } else if (killStatus < 0) {
+       Log("adminalert: ERROR: There was an error trying to block host (system fail) %s", target);
+       return (ERROR);
+    } else {
+       Log("attackalert: Host %s has been blocked via dropped route using command: \"%s\"", target, commandStringFinal);
+       return (TRUE);
+    }
+}
+
+
+
+/* This will run a specified command with TARGET as the option if one is given. */
+int
+KillRunCmd(char *target, int port, char *killString, char *detectionType)
+{
+    char cleanAddr[MAXBUF], commandStringTemp[MAXBUF];
+    char commandStringTemp2[MAXBUF], commandStringFinal[MAXBUF];
+    char portString[MAXBUF];
+    int killStatus = ERROR;
+
+    CleanIpAddr(cleanAddr, target);
+    snprintf(portString, MAXBUF, "%d", port);
+
+    /* Tokens are not required, but we check for an error anyway */
+    if (SubstString(cleanAddr, "$TARGET$", killString, commandStringTemp)
+       == ERROR) {
+       Log("adminalert: Error trying to parse $TARGET$ Token for KILL_RUN_CMD. Skipping.\n");
+       return (ERROR);
+    }
+
+    if (SubstString
+       (portString, "$PORT$", commandStringTemp,
+        commandStringTemp2) == ERROR) {
+       Log("adminalert: Error trying to parse $PORT$ Token for KILL_RUN_CMD. Skipping.\n");
+       return (ERROR);
+    }
+
+    if (SubstString
+       (detectionType, "$MODE$", commandStringTemp2,
+        commandStringFinal) == ERROR) {
+       Log("adminalert: Error trying to parse $MODE$ Token for KILL_RUN_CMD. Skipping.\n");
+       return (ERROR);
+    }
+
+
+    /* Kill the bastard and report a status */
+    killStatus = system(commandStringFinal);
+
+    if (killStatus == 127) {
+       Log("adminalert: ERROR: There was an error trying to run command (exec fail) %s", target);
+       return (ERROR);
+    } else if (killStatus < 0) {
+       Log("adminalert: ERROR: There was an error trying to run command (system fail) %s", target);
+       return (ERROR);
+    } else {
+       /* report success */
+       Log("attackalert: External command run for host: %s using command: \"%s\"", target, commandStringFinal);
+       return (TRUE);
+    }
+}
+
+
+/* this function will drop the host into the TCP wrappers hosts.deny file to deny */
+/* all access. The drop route method is preferred as this stops UDP attacks as well */
+/* as TCP. You may find though that host.deny will be a more permanent home.. */
+int
+KillHostsDeny(char *target, int port, char *killString,
+             char *detectionType)
+{
+
+    FILE *output;
+    char cleanAddr[MAXBUF], commandStringTemp[MAXBUF];
+    char commandStringTemp2[MAXBUF], commandStringFinal[MAXBUF];
+    char portString[MAXBUF];
+    int substStatus = ERROR;
+
+    CleanIpAddr(cleanAddr, target);
+
+    snprintf(portString, MAXBUF, "%d", port);
+
+#ifdef DEBUG
+    Log("debug: KillHostsDeny: parsing string for block: %s\n",
+       killString);
+#endif
+
+    substStatus =
+       SubstString(cleanAddr, "$TARGET$", killString, commandStringTemp);
+    if (substStatus == 0) {
+       Log("adminalert: No target variable specified in KILL_HOSTS_DENY option. Skipping.\n");
+       return (ERROR);
+    } else if (substStatus == ERROR) {
+       Log("adminalert: Error trying to parse $TARGET$ Token for KILL_HOSTS_DENY. Skipping.\n");
+       return (ERROR);
+    }
+
+    if (SubstString
+       (portString, "$PORT$", commandStringTemp,
+        commandStringTemp2) == ERROR) {
+       Log("adminalert: Error trying to parse $PORT$ Token for KILL_HOSTS_DENY. Skipping.\n");
+       return (ERROR);
+    }
+
+    if (SubstString
+       (detectionType, "$MODE$", commandStringTemp2,
+        commandStringFinal) == ERROR) {
+       Log("adminalert: Error trying to parse $MODE$ Token for KILL_HOSTS_DENY. Skipping.\n");
+       return (ERROR);
+    }
+#ifdef DEBUG
+    Log("debug: KillHostsDeny: result string for block: %s\n",
+       commandStringFinal);
+#endif
+
+    if ((output = fopen(WRAPPER_HOSTS_DENY, "a")) == NULL) {
+       Log("adminalert: cannot open hosts.deny file: %s for blocking.",
+           WRAPPER_HOSTS_DENY);
+       Log("securityalert: ERROR: There was an error trying to block host %s", target);
+       return (FALSE);
+    } else {
+       fprintf(output, "%s\n", commandStringFinal);
+       fclose(output);
+       Log("attackalert: Host %s has been blocked via wrappers with string: \"%s\"", target, commandStringFinal);
+       return (TRUE);
+    }
+}
+
+
+/* check if the host is already blocked */
+int IsBlocked(char *target, char *filename)
+{
+    FILE *input;
+    char buffer[MAXBUF], tempBuffer[MAXBUF];
+    char *ipOffset;
+    int count;
+
+
+#ifdef DEBUG
+    Log("debug: IsBlocked: Opening block file: %s \n", filename);
+#endif
+    if ((input = fopen(filename, "r")) == NULL) {
+       Log("adminalert: ERROR: Cannot open blocked file: %s for reading. Will create.\n", filename);
+       return (FALSE);
+    }
+
+    while (fgets(buffer, MAXBUF, input) != NULL) {
+       if ((ipOffset = strstr(buffer, target)) != (char) NULL) {
+           for (count = 0; count < strlen(ipOffset); count++) {
+               if ((isdigit(ipOffset[count])) || (ipOffset[count] == '.')) {
+                   tempBuffer[count] = ipOffset[count];
+               } else {
+                   tempBuffer[count] = '\0';
+                   break;
+               }
+           }
+           if (strcmp(target, tempBuffer) == 0) {
+#ifdef DEBUG
+               Log("debug: isBlocked: Host: %s found in blocked  file\n",
+                   target);
+#endif
+               fclose(input);
+               return (TRUE);
+           }
+       }
+
+    }
+#ifdef DEBUG
+    Log("debug: IsBlocked: Host: %s NOT found in blocked file\n", target);
+#endif
+    fclose(input);
+    return (FALSE);
+}
+
+/*********************************************************************************
+* String substitute function
+*
+* This function takes:
+*
+* 1) A token to use for replacement.
+* 2) A token to find.
+* 3) A string with the tokens in it.
+* 4) A string to write the replaced result.
+*
+* It returns the number of substitutions made during the operation.
+**********************************************************************************/
+int
+SubstString(const char *replace, const char *find, const char *target,
+           char *result)
+{
+    int replaceCount = 0, count = 0, findCount = 0, findLen =
+       0, numberOfSubst = 0;
+    char tempString[MAXBUF], *tempStringPtr;
+
+#ifdef DEBUG
+    Log("debug: SubstString: Processing string: %s %d", target,
+       strlen(target));
+    Log("debug: SubstString: Processing search text: %s %d", replace,
+       strlen(replace));
+    Log("debug: SubstString: Processing replace text: %s %d", find,
+       strlen(find));
+#endif
+
+    /* string not found in target */
+    if (strstr(target, find) == (char) NULL) {
+       strncpy(result, target, MAXBUF);
+#ifdef DEBUG
+       Log("debug: SubstString: Result string: %s", result);
+#endif
+       return (numberOfSubst);
+    }
+    /* String/victim/target too long */
+    else if ((strlen(target)) + (strlen(replace)) + (strlen(find)) >
+            MAXBUF)
+       return (ERROR);
+
+    memset(tempString, '\0', MAXBUF);
+    memset(result, '\0', MAXBUF);
+    findLen = strlen(find);
+    tempStringPtr = tempString;
+
+    for (count = 0; count < MAXBUF; count++) {
+       if (*target == '\0')
+           break;
+       else if ((strncmp(target, find, findLen)) != 0)
+           *tempStringPtr++ = *target++;
+       else {
+           numberOfSubst++;
+           for (replaceCount = 0; replaceCount < strlen(replace);
+                replaceCount++)
+               *tempStringPtr++ = replace[replaceCount];
+           for (findCount = 0; findCount < findLen; findCount++)
+               target++;
+       }
+    }
+
+    strncpy(result, tempString, MAXBUF);
+#ifdef DEBUG
+    Log("debug: SubstString: Result string: %s", result);
+#endif
+    return (numberOfSubst);
+}
+
+
+
+/* This function checks a config variable for a numerical flag and returns it */
+int CheckFlag(char *flagName)
+{
+    char configToken[MAXBUF];
+
+    if ((ConfigTokenRetrieve(flagName, configToken)) == TRUE) {
+#ifdef DEBUG
+       Log("debug: CheckFlag: found %s string.\n", flagName);
+#endif
+       return (atoi(configToken));
+    } else {
+#ifdef DEBUG
+       Log("debug: CheckFlag: %s option not found. Assuming FALSE.\n",
+           flagName);
+#endif
+       return (FALSE);
+    }
+}
+
+
+/* snprintf for NEXTSTEP (others??) */
+/* I don't know where this code came from and I don't */
+/* warrant its effectiveness. CHR */
+
+#ifdef HAS_NO_SNPRINTF
+int snprintf(char *str, size_t n, char const *fmt, ...)
+{
+    va_list ap;
+    FILE f;
+
+    if (n > MAXBUF) {
+       n = MAXBUF;
+    }
+    va_start(ap, fmt);
+    f._file = EOF;
+    f._flag = _IOWRT | _IOSTRG;
+    f._base = f._ptr = str;
+    f._bufsiz = f._cnt = n ? n - 1 : 0;
+    (void) vfprintf(&f, fmt, ap);
+    va_end(ap);
+    if (n) {
+       *f._ptr = '\0';
+    }
+    return (f._ptr - str);
+}
+#endif
diff --git a/kalasag_io.h b/kalasag_io.h
new file mode 100644
index 0000000..bb83ec8
--- /dev/null
+++ b/kalasag_io.h
@@ -0,0 +1,23 @@
+/* prototypes */
+int WriteBlocked(char *, char *, int, char *, char *, char *);
+void Log(char *, ...);
+void Exit(int);
+void Start(void);
+int DaemonSeed(void);
+int NeverBlock(char *, char *);
+int CheckConfig(void);
+int OpenTCPSocket(void);
+int OpenUDPSocket(void);
+#ifdef SUPPORT_STEALTH
+int OpenRAWTCPSocket(void);
+int OpenRAWUDPSocket(void);
+#endif
+int BindSocket(int, struct sockaddr_in, struct sockaddr_in, int);
+int KillRoute(char *, int, char *, char *);
+int KillHostsDeny(char *, int, char *, char *);
+int KillRunCmd(char *, int, char *, char *);
+int ConfigTokenRetrieve(char *, char *);
+int IsBlocked(char *, char *);
+int SubstString(const char *, const char *, const char *, char *);
+int CheckFlag(char *);
+int CompareIPs(char *, char *, int);
diff --git a/kalasag_tcpip.h b/kalasag_tcpip.h
new file mode 100644
index 0000000..b697b1f
--- /dev/null
+++ b/kalasag_tcpip.h
@@ -0,0 +1,159 @@
+/* Versions of Linux are not consistent in how the TCP/UDP/IP headers
+* defined. This file contains the Linux/BSD headers from RedHat 5.0 and
+* should clear up compile problems. CHR
+*/
+
+
+/*
+ * Copyright (c) 1982, 1986, 1993
+ *     The Regents of the University of California.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *     This product includes software developed by the University of
+ *     California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ *     @(#)tcp.h       8.1 (Berkeley) 6/10/93
+ */
+
+#ifndef _NETINET_TCP_H
+#define _NETINET_TCP_H 1
+
+#include <features.h>
+
+__BEGIN_DECLS struct tcphdr {
+    u_int16_t source;
+    u_int16_t dest;
+    u_int32_t seq;
+    u_int32_t ack_seq;
+#if __BYTE_ORDER == __LITTLE_ENDIAN
+    u_int16_t res1:4;
+    u_int16_t doff:4;
+    u_int16_t fin:1;
+    u_int16_t syn:1;
+    u_int16_t rst:1;
+    u_int16_t psh:1;
+    u_int16_t ack:1;
+    u_int16_t urg:1;
+    u_int16_t res2:2;
+#elif __BYTE_ORDER == __BIG_ENDIAN
+    u_int16_t doff:4;
+    u_int16_t res1:4;
+    u_int16_t res2:2;
+    u_int16_t urg:1;
+    u_int16_t ack:1;
+    u_int16_t psh:1;
+    u_int16_t rst:1;
+    u_int16_t syn:1;
+    u_int16_t fin:1;
+#else
+#error "Adjust your <bits/endian.h> defines"
+#endif
+    u_int16_t window;
+    u_int16_t check;
+    u_int16_t urg_ptr;
+};
+
+#endif                         /* tcp.h */
+
+
+
+#ifndef __NETINET_IP_H
+#define __NETINET_IP_H 1
+
+__BEGIN_DECLS struct timestamp {
+    u_int8_t len;
+    u_int8_t ptr;
+#if __BYTE_ORDER == __LITTLE_ENDIAN
+    u_int8_t flags:4;
+    u_int8_t overflow:4;
+#elif __BYTE_ORDER == __BIG_ENDIAN
+    u_int8_t overflow:4;
+    u_int8_t flags:4;
+#else
+#error "Please fix <bytesex.h>"
+#endif
+    u_int32_t data[9];
+};
+
+struct ip_options {
+    u_int32_t faddr;           /* Saved first hop address */
+    u_int8_t optlen;
+    u_int8_t srr;
+    u_int8_t rr;
+    u_int8_t ts;
+    u_int8_t is_setbyuser:1;   /* Set by setsockopt?                   */
+    u_int8_t is_data:1;                /* Options in __data, rather than skb   */
+    u_int8_t is_strictroute:1; /* Strict source route           */
+    u_int8_t srr_is_hit:1;     /* Packet destination addr was our one  */
+    u_int8_t is_changed:1;     /* IP checksum more not valid           */
+    u_int8_t rr_needaddr:1;    /* Need to record addr of outgoing dev  */
+    u_int8_t ts_needtime:1;    /* Need to record timestamp             */
+    u_int8_t ts_needaddr:1;    /* Need to record addr of outgoing dev  */
+    u_int8_t router_alert;
+    u_int8_t __pad1;
+    u_int8_t __pad2;
+    u_int8_t __data[0];
+};
+
+struct iphdr {
+#if __BYTE_ORDER == __LITTLE_ENDIAN
+    u_int8_t ihl:4;
+    u_int8_t version:4;
+#elif __BYTE_ORDER == __BIG_ENDIAN
+    u_int8_t version:4;
+    u_int8_t ihl:4;
+#else
+#error "Please fix <bytesex.h>"
+#endif
+    u_int8_t tos;
+    u_int16_t tot_len;
+    u_int16_t id;
+    u_int16_t frag_off;
+    u_int8_t ttl;
+    u_int8_t protocol;
+    u_int16_t check;
+    u_int32_t saddr;
+    u_int32_t daddr;
+    /*The options start here. */
+};
+
+#endif
+
+#ifndef __NETINET_UDP_H
+#define __NETINET_UDP_H    1
+
+__BEGIN_DECLS
+/* UDP header as specified by RFC 768, August 1980. */
+    struct udphdr {
+    u_int16_t source;
+    u_int16_t dest;
+    u_int16_t len;
+    u_int16_t check;
+};
+
+__END_DECLS
+#endif                         /* netinet/udp.h */
diff --git a/kalasag_util.c b/kalasag_util.c
new file mode 100644
index 0000000..42cb133
--- /dev/null
+++ b/kalasag_util.c
@@ -0,0 +1,114 @@
+#include "kalasag.h"
+#include "kalasag_io.h"
+#include "kalasag_util.h"
+
+/* A replacement for strncpy that covers mistakes a little better */
+char *SafeStrncpy(char *dest, const char *src, size_t size)
+{
+    if (!dest) {
+       dest = NULL;
+       return (NULL);
+    } else if (size < 1) {
+       dest = NULL;
+       return (NULL);
+    }
+
+    /* Null terminate string. Why the hell strncpy doesn't do this */
+    /* for you is mystery to me. God I hate C. */
+    memset(dest, '\0', size);
+    strncpy(dest, src, size - 1);
+
+    return (dest);
+}
+
+
+/************************************************************************/
+/* Generic safety function to process an IP address and remove anything */
+/* that is:                                                             */
+/* 1) Not a number.                                                     */
+/* 2) Not a period.                                                     */
+/* 3) Greater than IPMAXBUF (15)                                        */
+/************************************************************************/
+char *CleanIpAddr(char *cleanAddr, const char *dirtyAddr)
+{
+    int count = 0, maxdot = 0, maxoctet = 0;
+
+#ifdef DEBUG
+    Log("debug: cleanAddr: Cleaning Ip address: %s", dirtyAddr);
+#endif
+
+    memset(cleanAddr, '\0', IPMAXBUF);
+    /* dirtyAddr must be valid */
+    if (dirtyAddr == NULL)
+       return (cleanAddr);
+
+    for (count = 0; count < IPMAXBUF - 1; count++) {
+       if (isdigit(dirtyAddr[count])) {
+           if (++maxoctet > 3) {
+               cleanAddr[count] = '\0';
+               break;
+           }
+           cleanAddr[count] = dirtyAddr[count];
+       } else if (dirtyAddr[count] == '.') {
+           if (++maxdot > 3) {
+               cleanAddr[count] = '\0';
+               break;
+           }
+           maxoctet = 0;
+           cleanAddr[count] = dirtyAddr[count];
+       } else {
+           cleanAddr[count] = '\0';
+           break;
+       }
+    }
+
+#ifdef DEBUG
+    Log("debug: cleanAddr: Cleaned IpAddress: %s Dirty IpAddress: %s",
+       cleanAddr, dirtyAddr);
+#endif
+
+    return (cleanAddr);
+}
+
+
+/************************************************************************/
+/* Generic safety function to process an unresolved address and remove  */
+/* anything that is:                                                    */
+/* 1) Not a number.                                                     */
+/* 2) Not a period.                                                     */
+/* 3) Greater than DNSMAXBUF (255)                                      */
+/* 4) Not a legal DNS character (a-z, A-Z, 0-9, - )                    */
+/*                                                                     */
+/* XXX THIS FUNCTION IS NOT COMPLETE                                   */
+/************************************************************************/
+int CleanAndResolve(char *resolvedHost, const char *unresolvedHost)
+{
+    struct hostent *hostPtr = NULL;
+    struct in_addr addr;
+
+#ifdef DEBUG
+    Log("debug: CleanAndResolv: Resolving address: %s", unresolvedHost);
+#endif
+
+    memset(resolvedHost, '\0', DNSMAXBUF);
+    /* unresolvedHost must be valid */
+    if (unresolvedHost == NULL)
+       return (ERROR);
+
+    /* Not a valid address */
+    if ((inet_aton(unresolvedHost, &addr)) == 0)
+       return (ERROR);
+
+    hostPtr =
+       gethostbyaddr((char *) &addr.s_addr, sizeof(addr.s_addr), AF_INET);
+    if (hostPtr != NULL)
+       snprintf(resolvedHost, DNSMAXBUF, "%s", hostPtr->h_name);
+    else
+       snprintf(resolvedHost, DNSMAXBUF, "%s", unresolvedHost);
+
+#ifdef DEBUG
+    Log("debug: CleanAndResolve: Cleaned Resolved: %s Dirty Unresolved: %s", resolvedHost, unresolvedHost);
+#endif
+
+    return (TRUE);
+}
diff --git a/kalasag_util.h b/kalasag_util.h
new file mode 100644
index 0000000..5f95e2f
--- /dev/null
+++ b/kalasag_util.h
@@ -0,0 +1,6 @@
+/* IP address length plus null */
+#define IPMAXBUF 16
+
+char *SafeStrncpy(char *, const char *, size_t);
+char *CleanIpAddr(char *, const char *);
+int CleanAndResolve(char *, const char *);
 
filedropkalasag.git-1c9f013.tar.bz2 new
20.95 KB
3 downloads
filedropkalasag.git-1c9f013.zip
25.81 KB
1 download
filedropkalasag.git-3ca3612.tar.bz2
20.80 KB
3 downloads
filedropkalasag.git-3ca3612.zip
25.66 KB
1 download
filedropkalasag.git-2ffeaa6.tar.bz2
20.80 KB
3 downloads
filedropkalasag.git-2ffeaa6.zip
25.65 KB
1 download
filedropkalasag.git-2834a11.tar.bz2
20.84 KB
2 downloads
filedropkalasag.git-2834a11.zip
25.72 KB
2 downloads
filedropkalasag.git-afd7b31.tar.bz2
20.84 KB
3 downloads
filedropkalasag.git-afd7b31.zip
25.71 KB
1 download
filedropkalasag.git-97c89e1.tar.bz2
20.82 KB
3 downloads
filedropkalasag.git-97c89e1.zip
25.68 KB
1 download
filedropkalasag.git-1141d13.tar.bz2
20.65 KB
3 downloads
filedropkalasag.git-1141d13.zip
25.37 KB
1 download
filedropkalasag.git-ee3c17b.tar.bz2
20.65 KB
1 download
filedropkalasag.git-ee3c17b.zip
25.34 KB
1 download
filedropkalasag.git-4032c54.tar.bz2
20.63 KB
2 downloads
filedropkalasag.git-4032c54.zip
25.13 KB
1 download
filedropkalasag.git-e51a2a6.tar.bz2
20.65 KB
309 downloads
filedropkalasag.git-e51a2a6.zip
25.13 KB
190 downloads
filedropkalasag.git-599c93a.tar.bz2
20.63 KB
298 downloads
filedropkalasag.git-599c93a.zip
25.11 KB
1,522 downloads
filedropkalasag.git-acdc640.tar.bz2
20.63 KB
288 downloads
filedropkalasag.git-acdc640.zip
25.10 KB
208 downloads