cdirt/ascii/
cdirt/data/BULL/
cdirt/data/ZONES/PENDING/
cdirt/pending/
cdirt/src/utils/
cdirt/utils/
/**************************************************
 * DNS Server 1.0  (C) 1997, Giancarlo Castrataro *
 **************************************************/

#include "dns-serv.h"
#include "../../include/MACHINE.H"
#include <errno.h>
#include <sys/time.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <stdlib.h>
#include <ctype.h>
#include <signal.h>
#ifdef _OLD_LINUX_
  extern char *sys_errlist[];
#else
  #include <errno.h>
#endif

static FILE *logfp;

int daemonize(void);

char host_ip[100];

int main() {
  int main_sock, i, fd, numavail;
  fd_set input_set, output_set;
  struct hostent *h;
  int fdused;
  FILE   *fp;
  
  for (i = 0 ; i < MAX_CONNECT ; i++) 
    init_conn(i);

  if (daemonize() == -1) {  
    printf("Could not daemonize the Server.\n");
    return;
  }

  if ((main_sock = makesock()) == -1)
    return;           

  width = main_sock + 1;
	
  while (1) {
    FD_ZERO(&input_set);
    FD_ZERO(&output_set);
    FD_SET(main_sock, &input_set);

    for (i = 0 ; i < width ; i++) {
      if (fdesc(i) != -1) {
	FD_SET(fdesc(i), &input_set);
        if (output(i))
	  FD_SET(fdesc(i), &output_set);
      }
    }
    
    numavail = select(width, &input_set, &output_set, NULL, NULL);
    
    for (fd = 0 ; numavail > 0 ; fd++) {
      fdused = 0;

      if (FD_ISSET(fd, &input_set)) {
        if (fd == main_sock)
          new_conn(main_sock);
        else
          read_packet(fd);
        numavail--;
      }
      if (FD_ISSET(fd, &output_set)) {
        write_packet(fd);
        numavail--;
      }
    }
  }
}

void init_conn(int i) {
  output(i) = False;
  fdesc(i) = -1;
  *readbuff(i) = *writebuff(i) = 0;
  readpos(i) = readbuff(i);
  writepos(i) = writebuff(i);
}

int makesock(void) {
  int sock;
  char opt = 1;
  struct sockaddr_in sin;
  struct hostent *h;

  if ((sock = socket(AF_INET, SOCK_STREAM, 0)) == -1) {
    printf("Unable to create socket.\n");
    return(-1);
  }

  setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt));
 
  if (!(h = gethostbyname(_HOSTNAME_))) {
    fprintf(stderr, "Unable to bind to your hostname. Run configure.\n");
    return -2;
  }

  sin.sin_family = AF_INET;
  sin.sin_port = htons (SERVER_PORT);
  bcopy (h->h_addr_list[0], &(sin.sin_addr), h->h_length);

  if (bind(sock, (struct sockaddr *) &sin, sizeof (sin)) == -1) {
    printf("Dns server already running [not an error].\n");
    return(-1);
  }
  listen(sock, 5);
  return(sock);
}

void write_packet(int fd) {
  int num_wrote;

  conn = find_index(fd);
  num_wrote = write(fd, writepos(conn), strlen(writepos(conn)) + 1);
  writepos(conn) += num_wrote;

  if (*(writepos(conn) - 1) == 0) {
    *writebuff(conn) = 0;
    writepos(conn) = writebuff(conn);
    output(conn) = False;
  }
}

int escapechars(int conn) {
  char buff[READLEN * 2];
  char *p, *b;

  for (p = connects[conn].readbuff, b = buff ; *p ; p++, b++) {
    if (*p != '%')
      *b = *p;
    else {
      *b++ = '%';
      *b = '%';
    }
  }
  *b = 0;

  if (strlen(buff) > READLEN)
    return(-1);
  else {
    strcpy(connects[conn].readbuff, buff);
    return(0);
  }
}

int ht_pos(char *s) {
  char *ptr;
  int sum = 0;  

  for (ptr = s ; *ptr ; ptr++)
    sum += *ptr;

  return(sum % HT_SIZE);
}

void ht_add(char *ip_addr, char *hostname) {
  ht_elem *elem;
  ht_elem *nelem;
  int i;

  i = ht_pos(ip_addr);

  nelem = malloc(sizeof(ht_elem));
  nelem->next = NULL;
  nelem->ip_addr = COPY(ip_addr);
  nelem->hostname = COPY(hostname);

  if (!htable[i])
    htable[i] = nelem;
  else {
    elem = htable[i];
    while ((elem = elem->next));
    elem = nelem;
  }
}

char *match(char *token, ht_elem *start) {
  ht_elem *elem;

  elem = start;

  while (elem) {
    if (!strcmp(elem->ip_addr, token))
      return(elem->hostname);
    else
      elem = elem->next;
  }

  return(NULL);  
}

char *ht_lookup(char *token) {
  int i;

  i = ht_pos(token);
  return(match(token, htable[i]));
}

void read_packet(int fd) {
  int num_read, plrnum;
  unsigned long int inetnum;
  struct hostent *h;
  char ip_addr[16] = "\0";
  char *rslt;

  conn = find_index(fd);
  num_read = read(fd, readpos(conn), (100 - (readpos(conn) - readbuff(conn))));
  readpos(conn) += num_read;

  if (num_read < 1) {
    end_conn(fd);
    return;
  }

  if (*(readpos(conn) - 1) == 0) {

    readpos(conn) = readbuff(conn);

    if (escapechars(conn) == -1)
      return;

    plrnum = -1;
    sscanf(readbuff(conn), "%d%s", &plrnum, ip_addr);

    if (!*ip_addr || plrnum == -1)
      return;
    else {
      if (!(rslt = ht_lookup(ip_addr))) {
        inetnum = inet_addr(ip_addr);
        h = gethostbyaddr((char *) &inetnum, sizeof(inetnum), AF_INET);
        if (h) {
          rslt = (char *) h->h_name;
          ht_add(ip_addr, rslt);
        }
        else
          rslt = ip_addr;
      } 
      sprintf(writebuff(conn), "%-3d%-96s", plrnum, rslt);
      output(conn) = True;
    }
  }
}

int find_index(int fd) {
  int i;

  for (i = 0 ; i < MAX_CONNECT ; i++)
    if (fdesc(i) == fd)
      return(i);
  return(-1);
}

int find_new_index(int fd) { 
  int i;

  for (i = 0 ; i < MAX_CONNECT ; i++)
    if (fdesc(i) == -1) {
      fdesc(i) = fd;
      return(i);
    }

  return(-1);
}

void new_conn(int mainfd) {
  int i, fd, sin_len;
  struct sockaddr_in sin;
  struct hostent *h;

  bzero ((char *) &sin, sizeof (struct sockaddr_in));
  sin_len = sizeof (struct sockaddr_in);

  if ((fd = accept (mainfd, (struct sockaddr *) &sin, &sin_len)) < 0) {
    perror("accept()");
    return;
  }
  if (fcntl (fd, F_SETFL, FNDELAY) == -1) { 
    perror("fcntl()");
    return;
  }
  if ((i = find_new_index(fd)) == -1)
    return;

  h = gethostbyaddr((char *)&sin.sin_addr, sizeof(sin.sin_addr), AF_INET);
 
  if (!h)
    end_conn(fd);
  else if (strcmp(h->h_name, _HOSTNAME_) && strcmp(h->h_name, _IPNAME_))
    end_conn(fd);
   else if (fd >= width)
    width = fd + 1;
}

void end_conn(int fd) {
  char buff[200];
  int mud;

  if (fd >= width)
    width = fd;

  close(fd);

  mud = find_index(fd);
  init_conn(mud);
}

/**************************************************************************
 ** Signal Handler routines.
 **************************************************************************/

void remove_connections(void)
{   int i;

    for (i = 0; i < width; i++)
    {   if (fdesc(i) != -1)
           close(fdesc(i));
    }
}

void ee_handler(int sig)
{
    remove_connections();
    exit(0);
}

void abort_handler(int sig)
{   char message[255];
    int  i;

    remove_connections();
    exit(0);
}

void set_sighandlers(void)
{   signal(SIGALRM,SIG_IGN);
    signal(SIGSEGV,ee_handler);
    signal(SIGBUS,ee_handler);
    signal(SIGABRT,abort_handler);
    signal(SIGQUIT,abort_handler);
    signal(SIGINT,abort_handler);
}

int daemonize(void)
{   int pid;

    set_sighandlers();

    switch((pid = fork())) {
    case 0 : break;
    case -1: perror("Deamonize()"); return -1;
    default:
	fflush(stdout);
	fflush(stderr);
        exit(0);		/* Die silently */
    }
    return 0;
}