blog.farhan.codes

Farhan's Personal and Professional Blog


Old Chat Framework in C

During my high school years, I used to be part of an “underground” IRC server. We would talk about security-related topics and the latest exploits, usually about some Unix variant. Even though no one would really care about our late-night computer conversations, I thought it best that we chat over an encrypted medium, and considering that I knew nothing about how SSL could serve to transparently encrypt IRC daemons and clients, I decided to write my own encrypted chat server. Below is the C code using the Unix API for the very simple framework. I planned on adding encryption for which I was learning the GMP library - I was not familiar with OpenSSL. I was a kid, sue me 🙄. I wrote the code below my junior year of HS.

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <netdb.h>
#include <netinet/in.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <sys/time.h>
#include <sys/socket.h>
#include <sys/uio.h>
#include <arpa/inet.h>

struct clientinfo {
   int fd;
   struct sockaddr_in info;
};

int rmfd(struct clientinfo *connects, int location, int numcon) {
   int count;
   struct clientinfo *temp;

   for(count=location;count<=numcon;count++)
      connects[count] = connects[count+1];

   temp = malloc(sizeof(struct clientinfo)*(numcon-1+(numcon-1==0)));

   for(count=0;count<numcon-1;count++) {
      temp[count] = connects[count];
   }

   connects = malloc(sizeof(struct clientinfo)*(numcon-1+(numcon-1==0)));
   for(count=0;count<numcon-1;count++) {
      connects[count] = temp[count];
   }

   return numcon-1;
}

int addfd(struct clientinfo *connects, int numcon) {
   struct clientinfo *temp;
   int count;
   temp = malloc(sizeof(struct clientinfo) * (numcon+(numcon==0)));
   for(count=0;count<numcon;count++) {
      temp[count].fd = connects[count].fd;
      temp[count].info = connects[count].info;
   }
   connects = malloc(sizeof(struct clientinfo)*(numcon+1));
   for(count=0;count<numcon;count++) {
      connects[count].fd = temp[count].fd;

      connects[count].info = temp[count].info;
   }
   return numcon+1;
}

int main(int argc, char **argv) {
   int check;
   int sin_size;
   int numcon;
   int maxfd;
   int readtest;
   int writecount;
   char rwbuf[1024];
   struct timeval timer;
   struct clientinfo *connects;
   fd_set sockrd;

   if (argc != 2) {
      fprintf(stderr, "usage: %s port\n", argv[0]);
      exit(-1);
   }

   sin_size = sizeof(struct sockaddr);
   numcon = 0;
   connects = malloc(sizeof(struct clientinfo));
   FD_ZERO(&sockrd);
   connects[0].info.sin_family = AF_INET;
   connects[0].info.sin_port = htons(atoi(argv[1]));
   connects[0].info.sin_addr.s_addr = INADDR_ANY;

   connects[0].fd = socket(AF_INET, SOCK_STREAM, 0);
   check = bind(connects[0].fd, (struct sockaddr *)&connects[0].info, sizeof(struct sockaddr));
   if(check == -1) {
      perror("bind");
      exit(check);
   }
   check = listen(connects[0].fd, 1024);
   if (check == -1) {
      perror("listen");
      exit(check);
   }
   maxfd = connects[0].fd;
   for(;;) {
      FD_ZERO(&sockrd);
      FD_SET(connects[0].fd, &sockrd);
      for(check=1;check<=numcon;check++)
         FD_SET(connects[check].fd, &sockrd);
      timer.tv_sec = 60;
      timer.tv_usec = 0;

      select(maxfd+1, &sockrd, NULL, NULL, &timer);
      if (FD_ISSET(connects[0].fd, &sockrd)) {
         sin_size = sizeof(struct sockaddr_in);
         numcon = addfd(connects, numcon);
         connects[numcon].fd = accept(connects[0].fd, (struct sockaddr *)&connects[numcon].info, &sin_size);
         if (connects[numcon].fd > maxfd)
            maxfd = connects[numcon].fd;
      }
      else {
         for(readtest=1;readtest<=numcon;readtest++) {
            if(FD_ISSET(connects[readtest].fd, &sockrd)) {
               memset(rwbuf, 0, 1024);
               check = read(connects[readtest].fd, rwbuf, 1024);
               if (check == 0) {
                  close(connects[readtest].fd);
                  numcon = rmfd(connects, readtest, numcon);
               }
               else {
                  for(writecount=1;writecount<=numcon;writecount++) {
                     if (writecount != readtest)
                        write(connects[writecount].fd, rwbuf, 1024);
                  }
               }
            }
         }
      }
   }
}