C/C++ Program to Build Secure VPN Proxy Server Using Socket Programming

Here, I’m going to share information about “C/C++ Program to Build Secure VPN Proxy Server Using Socket Programming”. Let’s try to execute the task using this article. Let’s go.

C/C++ Program to Build Secure VPN Proxy Server Using Socket Programming

C/C++ Program to Build Secure VPN Proxy Server Using Socket Programming

Source Code

/*
 * tunproxy.c --- small demo program for tunneling over UDP with tun/tap
 *
 * Copyright (C) 2003  Philippe Biondi <phil@secdev.org>
 *
 * This program is free software; you can redistribute it and/or modify it
 * under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation.
 *
 * This program is distributed in the hope that it will be useful, but
 * WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 */

#include <openssl/evp.h>
#include <openssl/hmac.h>

#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <unistd.h>
#include <signal.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/timerfd.h>
#include <netinet/in.h>
#include <string.h>
#include <net/if.h>
#include <linux/if_tun.h>
#include <getopt.h>
#include <sys/ioctl.h>

#include <memory.h>
#include <errno.h>
#include <arpa/inet.h>
#include <netdb.h>

#include <openssl/rsa.h>       /* SSLeay stuff */
#include <openssl/crypto.h>
#include <openssl/x509.h>
#include <openssl/pem.h>
#include <openssl/ssl.h>
#include <openssl/err.h>

//#define exit(a)

#define PERROR(x)          do { perror(x); exit(1); } while (0)
#define ERROR(x, args ...) do { fprintf(stderr,"ERROR:" x, ## args); exit(1); } while (0)
#define CHK_NULL(x)        if ((x)==NULL) exit (1)
#define CHK_ERR(err,s)     if ((err)==-1) { perror(s); exit(1); }
#define CHK_SSL(err)       if ((err)==-1) { ERR_print_errors_fp(stderr); exit(2); }

//#define SLEEP(a)           if (DEBUG) {sleep(a);}
#define SLEEP(a)             {sleep(a);}

#define ABORT()            {killpg(getpgid(getpid()),SIGTERM);}

#define CLIENT 0
#define SERVER 1

#define MAX_KEY_LENGTH   (32)
#define IV_LENGTH        (16)
#define BUFFER_LENGTH    (4096)
#define HASH_LENGTH      (32)
#define MAX_BLOCK_LENGTH (BUFFER_LENGTH + EVP_MAX_BLOCK_LENGTH + HASH_LENGTH)

#define POKE_INTERVAL_IN_SECS   3

/* from cli.cpp */
#define CCERTF "client.crt"
#define CKEYF  "client.key"
#define CCACERT "ca.crt"

/* from serv.cpp */
/* define HOME to be dir for key and cert files... */
#define HOME "./"
/* Make these what you want for cert & key files */
#define SCERTF  HOME "server.crt"
#define SKEYF   HOME "server.key"
#define SCACERT HOME "ca.crt"


char KEY[MAX_KEY_LENGTH+1] = "Wazaaaaaaaaaaahhhh !";
unsigned char IV[IV_LENGTH] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
char pokemsg[BUFFER_LENGTH]; /* Used for client/server "poke" communication */
char msg[BUFFER_LENGTH]; /* Used for client/server SSL comm while tunnels are off and messages from parent/child */
char buf[MAX_BLOCK_LENGTH]; /* Used exclusively within child processes for tunnel/UDP transfers */
unsigned char out[MAX_BLOCK_LENGTH];
unsigned char md_value[HASH_LENGTH];
char szCommonName[512];
int md_len = 0;
int DEBUG = 0;
char *progname;

void do_encrypt(char *in, int inl, char *out, int *outl)
{
    EVP_CIPHER_CTX ctx;
    int tmpl = 0;

    if (DEBUG) write(1,"0", 1);
    EVP_CIPHER_CTX_init(&ctx);
    if (DEBUG) write(1,"1", 1);
    if(0 == EVP_EncryptInit_ex(&ctx, EVP_aes_128_cbc(), NULL, KEY, IV)) PERROR("EVP_EncryptInit_ex");
    if (DEBUG) write(1,"2", 1);
    if(0 == EVP_EncryptUpdate(&ctx, out, outl, in, inl))                PERROR("EVP_EncryptUpdate");
    if (DEBUG) write(1,"3", 1);
    if(0 == EVP_EncryptFinal_ex(&ctx, out+*outl, &tmpl))                PERROR("EVP_EncryptFinal_ex");
    *outl += tmpl;
    if (DEBUG) write(1,"4", 1);
    EVP_CIPHER_CTX_cleanup(&ctx);
    if (DEBUG) write(1,"5", 1);
}

void do_decrypt(char *in, int inl, char *out, int *outl)
{
    EVP_CIPHER_CTX ctx;
    int tmpl = 0;

    if (DEBUG) write(1,"6", 1);
    EVP_CIPHER_CTX_init(&ctx);
    if (DEBUG) write(1,"7", 1);
    if(0 == EVP_DecryptInit_ex(&ctx, EVP_aes_128_cbc(), NULL, KEY, IV)) PERROR("EVP_DecryptInit_ex");
    if (DEBUG) write(1,"8", 1);
    if(0 == EVP_DecryptUpdate(&ctx, out, outl, in, inl))                PERROR("EVP_DecryptUpdate");
    if (DEBUG) write(1,"9", 1);
    if(0 == EVP_DecryptFinal_ex(&ctx, out+*outl, &tmpl))                PERROR("EVP_DecryptFinal_ex");
    *outl += tmpl;
    if (DEBUG) write(1,"a", 1);
    EVP_CIPHER_CTX_cleanup(&ctx);
    if (DEBUG) write(1,"b", 1);
}

int isEqual(char *h1, char *h2, int len){
    int i = 0, j = 0;
    unsigned char a, b;

    for(i = 0; i < len; i++){
        a = (unsigned char)h1[i];
        b = (unsigned char)h2[i];
#if 1
        for(j = 0; j < 8; j++){
            if((a & 0x01) != (b & 0x01)){
                return 0;
            }

            a = a >> 1;
            b = b >> 1;
        }// for
#else
        if (a != b) {
            return 0;
        }// if
#endif
    }// for

    return 1;
}

void printHash(unsigned char *hash,int len)
{
    int i=0;

    while ( i<len) {
        printf("%02x",(unsigned int)hash[i]);
        i++;
    }
}

void dumpBuf(unsigned char *buf, int len)
{
    int i = 0;

    for (i=0; i<len; i++) {
        printf("%02X",buf[i]);
    }
}

void createHash(unsigned char *in, int inl, unsigned char *md_value, int *md_len)
{
    HMAC_CTX ctx;
    const EVP_MD *md;

    // Create new digest
    OpenSSL_add_all_digests();
    md = EVP_get_digestbyname("sha256");
    HMAC_CTX_init(&ctx);
    HMAC_Init_ex(&ctx, KEY, sizeof(KEY), md, NULL);
    HMAC_Update(&ctx, in, inl);
    HMAC_Final(&ctx, md_value, md_len);
    if (DEBUG) {printf("in: "); dumpBuf(in,inl); printf(" inl: %d  md_value: ",inl);}
    if (DEBUG) printHash(md_value,*md_len);
    if (DEBUG) printf(" md_len: %dn",*md_len);
}

void usage()
{
    fprintf(stderr, "Usage: %s [-s port|-c targetip:port] [-e]n", progname);
    exit(0);
}

int getch()
{
    int r;
    unsigned char c;
    if ((r = read(0, &c, sizeof(c))) < 0) {
        return r;
    } else {
        return c;
    }
}

void randomizeString(char *pszStr,int len)
{
   int i;
   for (i=0; i<len; i++) {
      pszStr[i] = rand() % 93 + 33;
   }//for
}

void randomizeArray(unsigned char *pArray,int len)
{
   int i;
   for (i=0; i<len; i++) {
      pArray[i] = rand() % 255;
   }//for
}

void displayClientMenu(void)
{
   /* Display menu of choices */
   printf("n");
   printf("k - Enter KEYn");
   printf("i - Enter IVn");
   printf("r - Randomize KEY/IV pairn");
   printf("c - Clear Sessionn");
   printf("s - STOPn");
   printf("> - ");
   fflush(stdout);
}

int main(int argc, char *argv[])
{
   struct sockaddr_in sin, from, sout;
   struct ifreq ifr;
   int fd_tunnel, fd_udp, fd_tcp, fromlen, soutlen, port, PORT, l;
   char c, *p, *ip;
   fd_set fdset;    
   int outl = sizeof(out);
   int cliserv = -1; /* must be specified on cmd line */
   int flags   = IFF_TUN; /* default */
   char if_name[IFNAMSIZ] = "";
   int i;
   int fds[2];
   pid_t pid;
   
   /* initialize random seed */
   srand(time(NULL));
   
   progname = argv[0];

   while ((c = getopt(argc, argv, "s:c:ehd")) != -1) {
      switch (c) {
         case 'h':
            usage();
         case 'd':
            DEBUG++;
            break;
         case 's':
            cliserv = SERVER;
            PORT = atoi(optarg);
            break;
         case 'c':
            cliserv = CLIENT;
            p = memchr(optarg,':',16);
            if (!p) ERROR("invalid argument : [%s]n",optarg);
            *p = 0;
            ip = optarg;
            port = atoi(p+1);
            PORT = 0;
            break;
         case 'e':
            flags = IFF_TAP;
            break;
         default:
            usage();
      }//switch
   }//while
   if (cliserv < 0) usage();

   /* Establish the Tunnel connection */
   if ((fd_tunnel = open("/dev/net/tun",O_RDWR)) < 0) PERROR("open");

   memset(&ifr, 0, sizeof(ifr));
   ifr.ifr_flags = flags;
   strncpy(ifr.ifr_name, "toto%d", IFNAMSIZ);
   if (ioctl(fd_tunnel, TUNSETIFF, (void *)&ifr) < 0) PERROR("ioctl");

   printf("Allocated interface %s. Configure and use itn", ifr.ifr_name);

   /* Establish the UDP Network connection */
   fd_udp = socket(PF_INET, SOCK_DGRAM, 0);
   sin.sin_family = AF_INET;
   sin.sin_addr.s_addr = htonl(INADDR_ANY);
   sin.sin_port = htons(PORT);
   if (bind(fd_udp,(struct sockaddr *)&sin, sizeof(sin)) < 0) PERROR("UDP-bind");

   /* Establish the TCP Network connection */
   fd_tcp = socket(PF_INET, SOCK_STREAM, 0);
   sin.sin_family = AF_INET;
   sin.sin_addr.s_addr = htonl(INADDR_ANY);
   sin.sin_port = htons(PORT);
   if (bind(fd_tcp,(struct sockaddr *)&sin, sizeof(sin)) < 0) PERROR("TCP-bind");

   if (cliserv == CLIENT) {
      /* CLIENT */
      int err = -1;
      int sd = -1;
      struct sockaddr_in sa;
      int salen = sizeof(sa);
      SSL_CTX* ctx = NULL;
      SSL*     ssl = NULL;
      X509*    server_cert;
      char*    str = NULL;
      SSL_METHOD *meth = SSLv23_client_method(); //SSLv2_client_method();
      char     input;
      int      cnValid  = 0;
      int      keyValid = 0;
      int      ivValid  = 0;
      int      poke_count = 0;
      
      /* Create a pipe with two ends of pipe placed in fds[2], read_end=0, write_end=1 */
      pipe(fds);
      /* Fork a child process */
      pid = fork();
      if (pid > (pid_t) 0) { /* TCP/SSL get Keys */
         /* Client-Parent process */

         /* close our copy of the read end of pipe */
         close(fds[0]);

         /* Display startup message */
         printf("MiniVPN Client...n");

         /* Output menu of choices */
         displayClientMenu();
         fflush(stdout);
         
         while(1) {
            /* Wait for TCP or user to make choice */
            FD_ZERO(&fdset);
            FD_SET(STDIN_FILENO,&fdset);
            FD_SET(fd_tcp,&fdset);
            if (select(STDIN_FILENO+fd_tcp+1,&fdset,NULL,NULL,NULL) < 0) PERROR("Client-Parent select");
            if (FD_ISSET(fd_tcp, &fdset)) {
               if (ssl) {
                  /* Process POKE from Server */
                  if (DEBUG) printf("Client Waiting on Server... ");
                  err = SSL_read(ssl,pokemsg,sizeof(pokemsg)-1);
                  if (!strncmp(pokemsg,"POKE",4)) {
                     if (DEBUG) printf("Received '%s', ",pokemsg);
                     if (DEBUG) printf("Sending POKE_ACK, #pokes=%dn",poke_count++);
                     err = SSL_write(ssl,"POKE_ACK",strlen("POKE_ACK"));
                     if (-1 == err) {ERR_print_errors_fp(stderr); continue;}
                  }//if
                  else if (-1 == err) {
                     PERROR("Client-Parent select");
                  }//else if
               }//if ssl
            }//if fd_tcp
            if (FD_ISSET(STDIN_FILENO, &fdset)) {
               /* Notify the child process to STOP send/receive packets */
               strcpy(msg,"STOP");
               write(fds[1],msg,strlen(msg)+1);
               SLEEP(1);
               
               /* Close down current SSL session */
               printf("Clearing SSL session... ");
               /* send SSL/TLS close_notify */
               if (NULL != ssl) SSL_shutdown(ssl);
               /* Clean up. */
               if (sd >= 0)     {close (sd);        sd =    -1;}
               if (NULL != ssl) {SSL_free(ssl);     ssl = NULL;}
               if (NULL != ctx) {SSL_CTX_free(ctx); ctx = NULL;}
               poke_count = 0;
               printf("Donen");
               SLEEP(1);

               /* Get User Choice */
               input = getch();
               
               /* Process User Choice */
               if ('k' == tolower(input)) {
                  printf("nKEY option...");
                  printf("nEnter CommonName(CN)n");
                  printf(">");
                  fflush(stdout);
                  memset(szCommonName,0,sizeof(szCommonName));
                  scanf("%s",szCommonName);
                  printf("nEnter KEYn");
                  printf("[--------------------------------]n");
                  printf(">");
                  fflush(stdout);
                  memset(msg,0,sizeof(msg));
                  scanf("%s",msg);
                  memset(KEY,0,sizeof(KEY));
                  strncpy(KEY,msg,MAX_KEY_LENGTH);
               }//if
               else if ('i' == tolower(input)) {
                  printf("nIV option...");
                  printf("nEnter CommonName(CN)n");
                  printf(">");
                  fflush(stdout);
                  memset(szCommonName,0,sizeof(szCommonName));
                  scanf("%s",szCommonName);
                  printf("nEnter IV (%d numbers)n",IV_LENGTH);
                  printf("[----------------]n");
                  printf(">");
                  fflush(stdout);
                  for (i=0; i<IV_LENGTH; i++) IV[i]=getch();
                  getch();
               }//else if
               else if ('r' == tolower(input)) {
                  printf("nRandomize KEY/IV option...");
                  printf("nEnter CommonName(CN)n");
                  printf(">");
                  fflush(stdout);
                  memset(szCommonName,0,sizeof(szCommonName));
                  scanf("%s",szCommonName);
                  printf("Random KEY and IV are being generated... ");
                  /* Randomly generate ... KEY, IV */
                  memset(KEY,0,sizeof(KEY));
                  randomizeString(KEY,sizeof(KEY)-1);
                  randomizeArray(IV,sizeof(IV));
                  printf("Donen");
               }//else if
               else if ('c' == tolower(input)) {
                  /* Close down current SSL session */
                  printf("Clearing SSL session... ");
                  /* send SSL/TLS close_notify */
                  if (NULL != ssl) SSL_shutdown(ssl);
                  /* Clean up. */
                  if (sd >= 0)     {close (sd);        sd =    -1;}
                  if (NULL != ssl) {SSL_free(ssl);     ssl = NULL;}
                  if (NULL != ctx) {SSL_CTX_free(ctx); ctx = NULL;}
                  poke_count = 0;
                  printf("Donen");
                  SLEEP(1);
                  continue;               
               }//else if
               else if ('s' == tolower(input)) {
                  printf("nClosing Tunnel... ");
                  close(fd_tunnel);
                  printf("Cleanup Donen");
                  printf("GoodByen");
                  printf("Killing process treen");
                  SLEEP(1);
                  killpg(getpgid(getpid()),SIGTERM); /* Kill the complete process tree including child. */
                  SLEEP(2);
                  printf("Press Control-C to terminaten");
                  while(1);
               }//else if
               else {
                  /* Output menu of choices */
                  displayClientMenu();
            
                  continue;
               }//else
                 
               /* Echo back to the user the CN + KEY + IV being used */
               if (DEBUG)  printf("CN  is: [%s]n",szCommonName);
               if (DEBUG)  printf("KEY is: [%s]n",KEY);
               if (DEBUG) {printf("IV  is: ["); dumpBuf(IV,IV_LENGTH); printf("]nn");}
               
               if (DEBUG)  printf("Session: ctx=%p, ssl=%p, sd=%dn",ctx,ssl,sd);

               /* PKI: Authenticate the Server */
               if (!ctx || !ssl || (sd < 0)) {
                  if (DEBUG) printf("PKI: Authenticating the Server...n");
                  SSLeay_add_ssl_algorithms();
                  SSL_load_error_strings();
                  ctx = SSL_CTX_new(meth);
                  if (NULL == ctx) {if (DEBUG) printf("ctx errorn");err=-1;continue;};

                  SSL_CTX_set_verify(ctx,SSL_VERIFY_PEER,NULL);
                  SSL_CTX_load_verify_locations(ctx,CCACERT,NULL);

                  if (SSL_CTX_use_certificate_file(ctx,CCERTF,SSL_FILETYPE_PEM)<=0){
                     ERR_print_errors_fp(stderr);err=-2;continue;}
                  if (SSL_CTX_use_PrivateKey_file(ctx,CKEYF,SSL_FILETYPE_PEM)  <=0){
                     ERR_print_errors_fp(stderr);err=-3;continue;}
                  if (!SSL_CTX_check_private_key(ctx)){
                     printf("Private key doesn't match cert. public keyn");err=-4;continue;}

                  /* Create a socket and connect to server using normal socket calls. */
                  sd = socket (AF_INET, SOCK_STREAM, 0);
                  if (-1 == sd) {perror("socket");err=-5;continue;}

                  memset(&sa,0,sizeof(sa));
                  sa.sin_family = AF_INET;
                  inet_aton(ip, &sa.sin_addr); /* Server IP */
                  sa.sin_port   = htons(port); /* Server Port */

                  err = connect(sd,(struct sockaddr*)&sa,sizeof(sa));
                  if (-1 == err) {perror("connect");err=-6;continue;}

                  /* Now we have TCP connection. Start SSL negotiation. */
                  ssl = SSL_new(ctx);     if (NULL == ssl) {printf("TCP connect failuren");err=-7;continue;}
                  SSL_set_fd(ssl,sd);
                  err = SSL_connect(ssl); if (-1 == err) {ERR_print_errors_fp(stderr);err=-8;continue;};

                  /* Following two steps are optional and not required for data exchange to be successful. */

                  /* Get the cipher - opt */
                  if (DEBUG) printf("SSL connection using %sn",SSL_get_cipher(ssl));

                  /* Get server's certificate (note: beware of dynamic allocation) - opt */
                  server_cert = SSL_get_peer_certificate(ssl);
                  if (NULL == server_cert){err=-9;continue;}
                  if (DEBUG) printf("Server certificate:n");

                  str = X509_NAME_oneline(X509_get_subject_name(server_cert),0,0);
                  if (NULL == str){err=-10;continue;}
                  //if (subjectstr) strcpy(subjectstr,str);
                  if (DEBUG) printf("t subject: %sn",str);
                  OPENSSL_free(str);

                  str = X509_NAME_oneline(X509_get_issuer_name(server_cert),0,0);
                  if (NULL == str){err=-11;continue;}
                  //if (issuerstr) strcpy(issuerstr,str);
                  if (DEBUG) printf("t issuer: %sn",str);
                  OPENSSL_free(str);

                  /* We can do all sorts of certificate verification stuff here before
                     deallocating the certificate. */
                  X509_free(server_cert);
               }//if

               /* DATA EXCHANGE AREA */
               if (ssl) {
                  /* Write CommonName (CN) to Server */
                  if (DEBUG) printf("Writing CN [%s] to Servern",szCommonName);
                  strcpy(msg,"CN:");
                  strcat(msg,szCommonName);
                  err = SSL_write(ssl,msg,strlen(msg));  if (-1 == err) {ERR_print_errors_fp(stderr); continue;}
                  /* Read CN reply from Server */
                  err = SSL_read(ssl,msg,sizeof(msg)-1); if (-1 == err) {ERR_print_errors_fp(stderr); continue;}
                  msg[err] = '';
                  if (DEBUG) printf("Server replied with %d chars:'%s'n",err,msg);
                  if (strncmp(msg,"CN_ACK",6)) {cnValid=0;printf("Client_CN_ACK_Errorn");}
                  else cnValid=1;
                  
                  /* Write KEY to Server */
                  if (DEBUG) printf("Writing KEY [%s] to Servern",KEY);
                  strcpy(msg,"KEY:");
                  strcat(msg,KEY);
                  err = SSL_write(ssl,msg,strlen(msg));  if (-1 == err) {ERR_print_errors_fp(stderr); continue;}
                  /* Read KEY reply from Server */
                  err = SSL_read(ssl,msg,sizeof(msg)-1); if (-1 == err) {ERR_print_errors_fp(stderr); continue;}
                  msg[err] = '';
                  if (DEBUG) printf("Server replied with %d chars:'%s'n",err,msg);
                  if (strncmp(msg,"KEY_ACK",7)) {keyValid=0;printf("Client_KEY_ACK_Errorn");}
                  else keyValid=1;
                  
                  /* Write IV to Server */
                  if (DEBUG) {printf("Writing IV ["); dumpBuf(IV,IV_LENGTH); printf("] to Servern");}
                  strcpy(msg,"IV:");
                  memcpy(&msg[3],&IV,sizeof(IV));
                  err = SSL_write(ssl,msg,3+sizeof(IV)); if (-1 == err) {ERR_print_errors_fp(stderr); continue;}
                  /* Read IV reply from Server */
                  err = SSL_read(ssl,msg,sizeof(msg)-1); if (-1 == err) {ERR_print_errors_fp(stderr); continue;}
                  msg[err] = '';
                  if (DEBUG) printf("Server replied with %d chars:'%s'n",err,msg);
                  if (strncmp(msg,"IV_ACK",6)) {ivValid=0;printf("Client_IV_ACK_Errorn");}
                  else ivValid=1;

                  /* Configure Client-Child to enable tunnel */
                  if (cnValid && keyValid && ivValid) {
                     /* Write KEY to the child process */
                     if (DEBUG) printf("Issuing KEY to Client-Childn");
                     strcpy(msg,"KEY:");
                     strcat(msg,KEY);
                     write(fds[1],msg,strlen(msg)+1);
                     SLEEP(1);
                                    
                     /* Write IV to the child process */
                     if (DEBUG) printf("Issuing IV to Client-Childn");
                     strcpy(msg,"IV:");
                     memcpy(&msg[3],&IV,sizeof(IV));
                     write(fds[1],msg,3+sizeof(IV));
                     SLEEP(1);
                  
                     /* Initialize FROM to point to Server's ip:port */
                     memset(&from,0,sizeof(from));
                     fromlen = sizeof(from);
                     from.sin_family = AF_INET;
                     from.sin_port = htons(port);
                     inet_aton(ip,&from.sin_addr);

                     /* Write FROM to the child process */
                     if (DEBUG) printf("Informing Client-Child the server's UDP addr+portn");
                     strcpy(msg,"FROM:");
                     memcpy(&msg[5],&from,sizeof(from));
                     write(fds[1],msg,5+sizeof(from));
                     SLEEP(1);

                     /* Notify the child process to be ready to send/receive packets */
                     if (DEBUG) printf("Issuing START to Client-Childn");
                     strcpy(msg,"START");
                     write(fds[1],msg,strlen(msg)+1);
                     SLEEP(1);
                  }//if
               }//if ssl
            }//else if STDIN_FILENO
         }//while
       }//if Client-PARENT
       else {                 /* UDP use keys */
          /* Client-Child process */
         int okToStart = 0;
         struct sockaddr_in from;

          /* close our copy of the write end of pipe */
          close(fds[1]);

         /* Set unblock pipe read */
         
         /* Tunnel connection */
         
         /* Keep reading from fds[0], fd_udp, fd_tunnel */
         
         /* If notification is not received, do not send/receive */
         
         /* while(true){if (read(fds[0]) == "start") break;} */
         
         /* while(true){select from fd_udp and fd_tunnel, encryption/decryption, hash, sending/receiving packets} */

          while (1) {
              FD_ZERO(&fdset);
              FD_SET(fds[0],   &fdset); /* Pipe from Parent */
              FD_SET(fd_tunnel,&fdset); /* Tunnel */
              FD_SET(fd_udp,   &fdset); /* Net-UDP */
              if (select(fds[0]+fd_tunnel+fd_udp+1,&fdset,NULL,NULL,NULL) < 0) PERROR("Client-Child select");
              if (FD_ISSET(fds[0], &fdset)) {
                  memset(buf,0,sizeof(buf));
                  l = read(fds[0], buf, sizeof(buf));
                  if (l < 0) PERROR("read");
                  if (!strncmp(buf,"KEY:",4)) {
                  if (DEBUG) printf("KEY: [%s] received from Client-Parentn",&buf[4]);
                  strncpy(KEY,&buf[4],sizeof(KEY));
               }//if
               else if (!strncmp(buf,"IV:",3)) {
                  if (DEBUG) {printf("IV: [");dumpBuf(&buf[3],sizeof(IV));printf("] received from Client-Parentn",&buf[3]);}
                  memcpy(IV,&buf[3],sizeof(IV));
               }//else if
               else if (!strncmp(buf,"FROM:",5)) {
                  if (DEBUG) printf("FROM: received from Client-Parentn");
                  memcpy(&from,&buf[5],sizeof(from));
               }//else if
               else if (!strncmp(buf,"START",5)) {
                  if (DEBUG) printf("START received from Client-Parentn");
                  okToStart = 1;
                  /*if (DEBUG)*/ printf("Client Tunnel running...n");
               }//else if
               else if (!strncmp(buf,"STOP",4)) {
                  if (DEBUG) printf("STOP received from Client-Parentn");
                  okToStart = 0;
                  /*if (DEBUG)*/ printf("Client Tunnel stoppedn");
               }//else if
               else okToStart = 0;
            }//if
              else if (FD_ISSET(fd_tunnel, &fdset)) {
                 if (okToStart) {
                    /* wait for data from tunnel, then encrypt+hash, then send to "remote/from" network socket */
                     if (DEBUG) write(1,">", 1);
                     l = read(fd_tunnel, buf, sizeof(buf));
                     if (l < 0) PERROR("read");
                     else {
                        if (DEBUG) {printf("nTx=%d[",l); dumpBuf(buf,l); printf("]n");}
                        outl = sizeof(out);
                        do_encrypt(buf,l,out,&outl);
                        if (outl > MAX_BLOCK_LENGTH) PERROR("Encrypt Too Big");
                        if (DEBUG) {printf("nEncrypt=%d[",outl); dumpBuf(out,outl); printf("]n");}
                        createHash(buf, l, md_value, &md_len);
                        if ((outl + md_len) > MAX_BLOCK_LENGTH) PERROR("Encrypt+Hash Too Big");
                        if (DEBUG) {printf("Hash=%d[",md_len); dumpBuf(md_value,md_len); printf("]n");}
                        for (i=0; i<md_len; i++) {out[outl+i] = md_value[i];}
                        outl += md_len;
                        if (sendto(fd_udp, out, outl, 0, (struct sockaddr *)&from, sizeof(from)) < 0)PERROR("sendto");
                     }//else
                  }//if okToStart
                  else if (!okToStart) { /* read from Tunnel and DISCARD */
                     l = read(fd_tunnel, buf, sizeof(buf));
                     if (l < 0) PERROR("read");
                  }//else if !okToStart
               }//else if
               else if (FD_ISSET(fd_udp, &fdset)) {
                  if (okToStart) {
                     /* wait for data from "remote/from" node, audit connection, decrypt+rehash+audit,
                       then forward to tunnel */
                     if (DEBUG) write(1,"<", 1);
                     /* do *not* use "from" so that we can audit which node the revieved packet comes from */
                     soutlen = sizeof(sout);
                     l = recvfrom(fd_udp, buf, sizeof(buf), 0, (struct sockaddr *)&sout, &soutlen);
                     if (l < 0) {
                         printf("fd_udp=%d,buf=%p,bufsize=%d,flags=%d,sockaddr=%p,soutlen=%pn",
                                 fd_udp,buf,sizeof(buf),0,&sout,&soutlen);
                         PERROR("recvfrom");
                     }//if
                     else {
                        /* audit to make sure data came from node "established" at connection time */
                        if ((sout.sin_addr.s_addr != from.sin_addr.s_addr) || (sout.sin_port != from.sin_port)) {
#if 0
                             printf("Got packet from  %s:%i instead of %s:%in", 
                                        (char *)inet_ntoa(sout.sin_addr/*.s_addr*/), ntohs(sout.sin_port),
                                        (char *)inet_ntoa(from.sin_addr/*.s_addr*/), ntohs(from.sin_port));
#endif
                         }//if
                         else {
                            /* data from correct node, subtract off HASH, decrypt+rehash, audit hash,
                               then forward to tunnel */
                             l -= HASH_LENGTH;
                             outl = sizeof(out);
                             if (DEBUG) {printf("nRx=%d[",l); dumpBuf(buf,l); printf("]n");}
                             if (DEBUG) {printf("Hash=%d[",HASH_LENGTH); dumpBuf(&buf[l],HASH_LENGTH); printf("]n");}
                             do_decrypt(buf,l,out,&outl);
                             if (DEBUG) {printf("nDecrypt=%d[",outl); dumpBuf(out,outl); printf("]n");}
                             createHash(out, outl, md_value, &md_len);
                             if (!isEqual(&buf[l], md_value, md_len)) PERROR("HASH");
                             if (write(fd_tunnel, out, outl) < 0) PERROR("write");
                         }//else
                     }//else
                  }//if okToStart
                  else if (!okToStart) { /* receive from node and DISCARD */
                     soutlen = sizeof(sout);
                     l = recvfrom(fd_udp, buf, sizeof(buf), 0, (struct sockaddr *)&sout, &soutlen);
                     if (l < 0) {
                         printf("fd_udp=%d,buf=%p,bufsize=%d,flags=%d,sockaddr=%p,soutlen=%pn",
                                 fd_udp,buf,sizeof(buf),0,&sout,&soutlen);
                         PERROR("recvfrom");
                     }//if
                  }//else if !okToStart                 
              }//else if
          }//while
       }// else Client-CHILD
    }// if CLIENT
    else {
      /* SERVER */
      int err = -1;
      int listen_sd = fd_tcp;
      int sd = -1;
      //struct sockaddr_in sa_serv;
      struct sockaddr_in sa_cli;
      size_t client_len;
      SSL_CTX* ctx = NULL;
      SSL*     ssl = NULL;
      X509*    client_cert = NULL;
      char*    str = NULL;
      char     subjectstr[512];
      char     issuerstr[512];
      SSL_METHOD *meth = SSLv23_server_method();
      int cnValid  = 0;
      int keyValid = 0;
      int ivValid  = 0;
      struct itimerspec time_period = {{POKE_INTERVAL_IN_SECS,0},{POKE_INTERVAL_IN_SECS,0}}; /* periodic timer */
      struct timeval sel_timeout;
      int timer_fd;
      int result;
      int poke_count = 0;
      
      /* create time to fire every 1 second */
      timer_fd = timerfd_create(CLOCK_MONOTONIC,0);
      if (timer_fd < 0) {printf("Timer fd failedn");killpg(getpgid(getpid()),SIGTERM);}

      result = timerfd_settime(timer_fd,0,&time_period,NULL);
      if (result < 0) {printf("timer fd set time failedn");killpg(getpgid(getpid()),SIGTERM);}

      /* Create a pipe with two ends of pipe placed in fds[2], read_end=0, write_end=1 */
      pipe(fds);
      /* Fork a child process */
      pid = fork();
      if (pid > (pid_t) 0) { /* TCP get Keys */
         /* Server-Parent process */

         /* close our copy of the read end of pipe */
         close(fds[0]);

         /* Display startup message */
         printf("MiniVPN Server...n");         
         fflush(stdout);
         
         while(1) {
            FD_ZERO(&fdset);
            FD_SET(fd_tcp,&fdset);
            FD_SET(timer_fd,&fdset);
            if (select(fd_tcp+timer_fd+1,&fdset,NULL,NULL,NULL) < 0) PERROR("Server-Parent select");
            if (FD_ISSET(timer_fd, &fdset)) {
               int s;
               uint64_t exp;
               s = read(timer_fd, &exp, sizeof(uint64_t));
               
               /* Reset time-interval in case altered */
               time_period.it_interval.tv_sec  = POKE_INTERVAL_IN_SECS;
               time_period.it_interval.tv_nsec = 0;
               time_period.it_value.tv_sec     = POKE_INTERVAL_IN_SECS;
               time_period.it_value.tv_nsec    = 0;
               
               /* Is SSL connection currently active with Client? */
               if (ssl) {
                  /* POKE_Client via SSL*/
                  if (DEBUG) printf("Server POKE Client, Waiting... ");
                  err = SSL_write(ssl,"POKE",strlen("POKE"));
                  memset(pokemsg,0,sizeof(pokemsg));
                  err = SSL_read(ssl,pokemsg,sizeof(msg)-1);
                  if ((-1 == err) || (strncmp(pokemsg,"POKE_ACK",8)))
                  {
                     /* Client did not respond -OR- invalid reponse */
                     if (err >= 0) {
                        pokemsg[err] = '';
                        if (DEBUG) printf("Received '%s'n",pokemsg);
                     }//if
                     else {
                        if (DEBUG) printf("Timeoutn");
                     }//else
                     
                     if (DEBUG) printf("Closing SSL connection with Clientn");
                     
                     /* Close SSL connection with Client. */
                     if (sd >= 0)     {close(sd);         sd =    -1;}
                     if (NULL != ssl) {SSL_free(ssl);     ssl = NULL;}
                     if (NULL != ctx) {SSL_CTX_free(ctx); ctx = NULL;}
                     
                     poke_count = 0;
                     
                     /* Notify the child process to STOP send/receive packets */
                     strcpy(pokemsg,"STOP");
                     write(fds[1],pokemsg,strlen(pokemsg)+1);
                  }//if disconnect Client
                  else {
                     pokemsg[err] = '';
                     if (DEBUG) printf("Received '%s', #pokes=%dn",pokemsg,poke_count++);
                  }//else
               }//if ssl
            }//if timer_fd
            if (FD_ISSET(fd_tcp, &fdset)) {
               /* Notify the child process to STOP send/receive packets */
               strcpy(msg,"STOP");
               write(fds[1],msg,strlen(msg)+1);
               SLEEP(1);

               if (DEBUG) printf("Session: ctx=%p, ssl=%p, sd=%dn",ctx,ssl,sd);

               /* PKI: Authenticate the Client */
               if (!ctx || !ssl || (sd < 0)) {
                  if (DEBUG) printf("PKI: Authenticating the Client...n");
                
                  /* SSL preliminaries. We keep the certificate and key with the context. */
                  SSLeay_add_ssl_algorithms();
                  SSL_load_error_strings();
                  ctx = SSL_CTX_new (meth);
                  if (!ctx) {ERR_print_errors_fp(stderr);err=-1;continue;}

                  SSL_CTX_set_verify(ctx,SSL_VERIFY_PEER,NULL); /* whether verify the certificate */
                  SSL_CTX_load_verify_locations(ctx,SCACERT,NULL);
        
                  if (SSL_CTX_use_certificate_file(ctx,SCERTF,SSL_FILETYPE_PEM)<=0){
                     ERR_print_errors_fp(stderr);err=-2;continue;}
                  if (SSL_CTX_use_PrivateKey_file(ctx,SKEYF,SSL_FILETYPE_PEM)  <=0){
                     ERR_print_errors_fp(stderr);err=-3;continue;}
                  if (!SSL_CTX_check_private_key(ctx)){
                     fprintf(stderr,"Private key does not match the certificate public keyn");err=-4;continue;}

                  /* Prepare TCP socket for receiving connections */
                  //listen_sd = socket(AF_INET,SOCK_STREAM,0);
                  if (-1 == listen_sd) {perror("socket");err=-5;continue;}
        
                  //memset(&sa_serv,0,sizeof(sa_serv));
                  //sa_serv.sin_family      = AF_INET;
                  //sa_serv.sin_addr.s_addr = INADDR_ANY;
                  //sa_serv.sin_port        = htons(PORT); /* Server Port number */
        
                  //err = bind(listen_sd,(struct sockaddr*)&sa_serv,sizeof(sa_serv));
                  //if (-1 == err) {perror("bind");err=-6;continue;}
                  
                  /* Receive a TCP connection. */
                  err = listen(listen_sd,5);
                  if (-1 == err) {perror("listen");err=-7;continue;}

                  client_len = sizeof(sa_cli);
                  sd = accept(listen_sd,(struct sockaddr*)&sa_cli,&client_len);
                  if (-1 == sd) {perror("accept");err=-8;continue;}
                  //close(listen_sd);

                  //if (DEBUG) printf("Connection from %lx, port %dn",sa_cli.sin_addr.s_addr,sa_cli.sin_port);
                  if (DEBUG) printf("Connection from ip:port %s:%i establishedn",
                                     inet_ntoa(sa_cli.sin_addr/*.s_addr*/),ntohs(sa_cli.sin_port));

                  /* TCP connection is ready. Do server side SSL. */
                  ssl = SSL_new(ctx);     if (NULL == ssl) {printf("TCP connect failuren");err=-9;continue;}
                  SSL_set_fd(ssl,sd);
                  err = SSL_accept(ssl);  if (-1 == err) {ERR_print_errors_fp(stderr);err=-10;continue;}
                  
                  /* Get the cipher - opt */
                  if (DEBUG) printf("SSL connection using %sn",SSL_get_cipher(ssl));
        
                  /* Get client's certificate (note: beware of dynamic allocation) - opt */
                  client_cert = SSL_get_peer_certificate(ssl);
                  if (NULL == client_cert) {printf("Client does not have certificate.n");err=-11;continue;}
                  if (DEBUG) printf("Client certificate:n");
          
                  str = X509_NAME_oneline(X509_get_subject_name(client_cert),0,0);
                  if (NULL == str) {err=-12;continue;}
                  strncpy(subjectstr,str,sizeof(subjectstr)-1);
                  if (DEBUG) printf("t subject: %sn",str);
                  OPENSSL_free(str);
                  
                  str = X509_NAME_oneline(X509_get_issuer_name(client_cert),0,0);
                  if (NULL == str) {err=-13;continue;}
                  strncpy(issuerstr,str,sizeof(issuerstr)-1);
                  if (DEBUG) printf("t issuer: %sn",str);
                  OPENSSL_free(str);

                  /* We can do all sorts of certificate verification stuff here before
                     deallocating the certificate. */
                  X509_free (client_cert);
               }//if

               /* DATA EXCHANGE - Receive messages and send replies */
               if (ssl) {
                  /* Read CN from Client */
                  err = SSL_read(ssl,msg,sizeof(msg)-1);
                  if (-1 == err) {ERR_print_errors_fp(stderr);err=-14;continue;}
                  msg[err] = '';
                  if (DEBUG) printf("Received from Client %d chars:'%s'n",err,msg);
                  /* Audit CN from Client */
                  cnValid = 0;
                  if (!strncmp(msg,"CN:",3)) {
                     char *pch_start = strstr(subjectstr,"/CN=");
                     if (NULL != pch_start) {
                        char *pch_end = strstr(&pch_start[1],"/");
                        if (NULL != pch_end) {
                           int cn_len = (int)pch_end - (int)&pch_start[4];
                           if (!strncmp(&pch_start[4],&msg[3],cn_len)) {
                              cnValid=1;
                           }//if
                        }//if
                     }//if
                  }//if
                  /* Write CN reply to Client */
                  if (1 == cnValid) {
                     err = SSL_write(ssl,"CN_ACK",strlen("CN_ACK"));
                     if (-1 == err) {ERR_print_errors_fp(stderr);err=-15;continue;}
                  }//if
                  else {
                     err = SSL_write(ssl,"CN_NACK",strlen("CN_NACK"));
                     if (-1 == err) {ERR_print_errors_fp(stderr);err=-16;continue;}
                  }//else

                  /* Read KEY from Client */
                  err = SSL_read(ssl,msg,sizeof(msg)-1); 
                  if (-1 == err) {ERR_print_errors_fp(stderr);err=-17;continue;}
                  msg[err] = '';
                  if (DEBUG) printf("Received from Client %d chars:'%s'n",err,msg);
                  /* Write KEY reply to Client */
                  if (!strncmp(msg,"KEY:",4)) {
                     strncpy(KEY,&msg[4],MAX_KEY_LENGTH);
                     keyValid=1;
                     err = SSL_write(ssl,"KEY_ACK",strlen("KEY_ACK"));
                     if (-1 == err) {ERR_print_errors_fp(stderr);err=-18;continue;}
                  }//if
                  else {
                     keyValid=0;
                     err = SSL_write(ssl,"KEY_NACK",strlen("KEY_NACK"));
                     if (-1 == err) {ERR_print_errors_fp(stderr);err=-19;continue;}
                  }//else
                  
                  /* Read IV from Client */
                  err = SSL_read(ssl,msg,sizeof(msg)-1);
                  if (-1 == err) {ERR_print_errors_fp(stderr);err=-20;continue;}
                  msg[err] = '';
                  if (DEBUG) {printf("Received from Client %d chars:'%c%c%c",err,msg[0],msg[1],msg[2]);
                              dumpBuf(&msg[3],err-3);printf("'n");}
                  /* Write IV reply to Client */
                  if (!strncmp(msg,"IV:",3)) {
                     memcpy(IV,&msg[3],IV_LENGTH);
                     ivValid=1;
                     err = SSL_write(ssl,"IV_ACK",strlen("IV_ACK"));
                     if (-1 == err) {ERR_print_errors_fp(stderr);err=-21;continue;}
                  }//if
                  else {
                     ivValid=0;
                     err = SSL_write(ssl,"IV_NACK",strlen("IV_NACK"));
                     if (-1 == err) {ERR_print_errors_fp(stderr);err=-22;continue;}
                  }//else

#if 0
                     /* Clean up. */
                     if (sd >= 0)     {close(sd);         sd = -1;}
                     if (NULL != ssl) {SSL_free(ssl);     ssl = NULL;}
                     if (NULL != ctx) {SSL_CTX_free(ctx); ctx = NULL;}
#endif

                  if (cnValid && keyValid && ivValid) {
                     /* Write KEY to the child process */
                     strcpy(msg,"KEY:");
                     strcat(msg,KEY);
                     write(fds[1],msg,strlen(msg)+1);
                     SLEEP(1);
                  
                     /* Write IV to the child process */
                     strcpy(msg,"IV:");
                     memcpy(&msg[3],&IV,sizeof(IV));
                     write(fds[1],msg,3+sizeof(IV));
                     SLEEP(1);
                     
                     /* Initialize FROM to point to Client's ip:port */
                     memset(&from,0,sizeof(from));
                     fromlen = sizeof(from);
                     from = sa_cli;

                     /* Write FROM to the child process */
                     strcpy(msg,"FROM:");
                     memcpy(&msg[5],&from,sizeof(from));
                     write(fds[1],msg,5+sizeof(from));
                     SLEEP(1);

                     /* Notify the child process to be ready to send/receive packets */
                     strcpy(msg,"START");
                     write(fds[1],msg,strlen(msg)+1);
                     SLEEP(1);
                  }//if VALID
               }// ssl
            }//else if TCP
         }// while
      }// if Server-PARENT
      else {                 /* UDP use keys */
         /* Server-Child process */
         int okToStart = 0;
         struct sockaddr_in from;

         /* close our copy of the write end of pipe */
         close(fds[1]);

         /* Set unblock pipe read */

         /* Tunnel connection */

         /* Keep reading from fds[0], fd_udp, fd_tunnel */

         /* If notification is not received, do not send/receive */

         while (1) {
            FD_ZERO(&fdset);
            FD_SET(fds[0],   &fdset); /* Pipe from Parent */
            FD_SET(fd_tunnel,&fdset); /* Tunnel */
            FD_SET(fd_udp,   &fdset); /* Net-UDP */
            if (select(fds[0]+fd_tunnel+fd_udp+1,&fdset,NULL,NULL,NULL) < 0) PERROR("Server-Child select");
            if (FD_ISSET(fds[0], &fdset)) {
               memset(buf,0,sizeof(buf));
               l = read(fds[0], buf, sizeof(buf));
               if (l < 0) PERROR("read");
               if (!strncmp(buf,"KEY:",4)) {
                  if (DEBUG) printf("KEY: [%s] received from Server-Parentn",&buf[4]);
                  strncpy(KEY,&buf[4],sizeof(KEY));
               }//if
               else if (!strncmp(buf,"IV:",3)) {
                  if (DEBUG) {
                     printf("IV: [");
                     dumpBuf(&buf[3],sizeof(IV));
                     printf("] received from Server-Parentn",&buf[3]);
                  }//if
                  memcpy(IV,&buf[3],sizeof(IV));
               }//else if
               else if (!strncmp(buf,"FROM:",5)) {
                  if (DEBUG) printf("FROM: received from Server-Parentn");
                  memcpy(&from,&buf[5],sizeof(from));
               }//else if
               else if (!strncmp(buf,"START",5)) {
                  if (DEBUG) printf("START received from Server-Parentn");
                  okToStart = 1;
                  /*if (DEBUG)*/ printf("Server Tunnel running...n");
               }//else if
               else if (!strncmp(buf,"STOP",4)) {
                  if (DEBUG) printf("STOP received from Server-Parentn");
                  okToStart = 0;
                  /*if (DEBUG)*/ printf("Server Tunnel stoppedn");
               }//else if
               else okToStart = 0;
            }//if
            else if (FD_ISSET(fd_tunnel, &fdset)) {
               if (okToStart) {
                  /* wait for data from tunnel, then encrypt+hash, then send to "remote/from" network socket */
                  if (DEBUG) write(1,">", 1);
                  l = read(fd_tunnel, buf, sizeof(buf));
                  if (l < 0) PERROR("read");
                  else {
                     if (DEBUG) {printf("nTx=%d[",l); dumpBuf(buf,l); printf("]n");}
                     outl = sizeof(out);
                     do_encrypt(buf,l,out,&outl);
                     if (outl > MAX_BLOCK_LENGTH) PERROR("Encrypt Too Big");
                     if (DEBUG) {printf("nEncrypt=%d[",outl); dumpBuf(out,outl); printf("]n");}
                     createHash(buf, l, md_value, &md_len);
                     if ((outl + md_len) > MAX_BLOCK_LENGTH) PERROR("Encrypt+Hash Too Big");
                     if (DEBUG) {printf("Hash=%d[",md_len); dumpBuf(md_value,md_len); printf("]n");}
                     for (i=0; i<md_len; i++) {out[outl+i] = md_value[i];}
                     outl += md_len;
                     if (sendto(fd_udp, out, outl, 0, (struct sockaddr *)&from, sizeof(from)) < 0)PERROR("sendto");
                  }//else
               }//if okToStart
               else if (!okToStart) { /* "read" from Tunnel and DISCARD */
                  l = read(fd_tunnel, buf, sizeof(buf));
                  if (l < 0) PERROR("read");
               }//else if !okToStart
            }//else if
            else if (FD_ISSET(fd_udp, &fdset)) {
               if (okToStart) {
                  /* wait for data from "remote/from" node, audit connection, decrypt+rehash+audit,
                     then forward to tunnel */
                  if (DEBUG) write(1,"<", 1);
                  /* do *not* use "from" so that we can audit which node the recieved packet comes from */
                  soutlen = sizeof(sout);
                  l = recvfrom(fd_udp, buf, sizeof(buf), 0, (struct sockaddr *)&sout, &soutlen);
                  if (l < 0) {
                      printf("fd_udp=%d,buf=%p,bufsize=%d,flags=%d,sockaddr=%p,soutlen=%pn",
                              fd_udp,buf,sizeof(buf),0,&sout,&soutlen);
                      PERROR("recvfrom");
                  }//if
                  else {
                     /* audit to make sure data came from node "established" at connection time */
                     if ((sout.sin_addr.s_addr != from.sin_addr.s_addr) || (sout.sin_port != from.sin_port)) {
#if 0
                        printf("Got packet from  %s:%i instead of %s:%in", 
                                 (char *)inet_ntoa(sout.sin_addr/*.s_addr*/), ntohs(sout.sin_port),
                                 (char *)inet_ntoa(from.sin_addr/*.s_addr*/), ntohs(from.sin_port));
                        printf("Updating FROM with this new ip:portn");
#endif
                        from = sout;
                     }//if
                     else
                     {
                        /* data from correct node, subtract off HASH, decrypt+rehash, audit hash,
                           then forward to tunnel */
                        l -= HASH_LENGTH;
                        outl = sizeof(out);
                        if (DEBUG) {printf("nRx=%d[",l); dumpBuf(buf,l); printf("]n");}
                        if (DEBUG) {printf("Hash=%d[",HASH_LENGTH); dumpBuf(&buf[l],HASH_LENGTH); printf("]n");}
                        do_decrypt(buf,l,out,&outl);
                        if (DEBUG) {printf("nDecrypt=%d[",outl); dumpBuf(out,outl); printf("]n");}
                        createHash(out, outl, md_value, &md_len);
                        if (!isEqual(&buf[l], md_value, md_len)) PERROR("HASH");
                        if (write(fd_tunnel, out, outl) < 0) PERROR("write");
                     }//else
                  }//else
               }//if okToStart
               else if (!okToStart) { /* "receive" from node and DISCARD */
                  soutlen = sizeof(sout);
                  l = recvfrom(fd_udp, buf, sizeof(buf), 0, (struct sockaddr *)&sout, &soutlen);
                  if (l < 0) {
                      printf("fd_udp=%d,buf=%p,bufsize=%d,flags=%d,sockaddr=%p,soutlen=%pn",
                              fd_udp,buf,sizeof(buf),0,&sout,&soutlen);
                      PERROR("recvfrom");
                  }//if
               }//else if !okToStart
              }//else if
          }//while
      }// else Server-CHILD
   }// else SERVER

}//main

Conclusion

I hope this article helps you to learn the topic of “C/C++ Program to Build Secure VPN Proxy Server Using Socket Programming”. If you face any issues please let me know via the comment section. Share this article with other C/C++ developers via social networks.

Share on:

Hi, I'm Ranjith a full-time Blogger, YouTuber, Affiliate Marketer, & founder of Coding Diksha. Here, I post about programming to help developers.

Leave a Comment