/*  
    VTun - Virtual Tunnel over TCP/IP network.

    Copyright (C) 1998-2008  Maxim Krasnyansky <max_mk@yahoo.com>

    VTun has been derived from VPPP package by Maxim Krasnyansky. 

    This program is free software; you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation; either version 2 of the License, or
    (at your option) any later version.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.
 */

/*
 * $Id: main.c,v 1.9.2.5 2012/07/08 05:32:57 mtbishop Exp $
 */ 

#include "config.h"

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <signal.h>
#include <fcntl.h>
#include <syslog.h>
#include <sys/mman.h>

#ifdef HAVE_NETINET_IN_H
#include <netinet/in.h>
#endif

#include "vtun.h"
#include "lib.h"
#include "compat.h"

/* Global options for the server and client */
struct vtun_opts vtun;
struct vtun_host default_host;

void write_pid(char *, char *);
void reread_config(int sig);
void usage(void);

extern int optind,opterr,optopt;
extern char *optarg;

/* for the NATHack bit.  Is our UDP session connected? */
int is_rmt_fd_connected=1; 

int main(int argc, char *argv[], char *env[])
{
  int svr, daemon, sock, dofork, fd, opt;
     struct vtun_host *host = NULL;
     struct sigaction sa;
     char *hst;

     /* Configure default settings */
     svr = 0; daemon = 1; sock = 0; dofork = 1;

     vtun.cfg_file = VTUN_CONFIG_FILE;
     vtun.persist = -1;
     vtun.timeout = -1;
     vtun.sslauth = -1;
     vtun.transport_af = AF_INET;
	
     /* Dup strings because parser will try to free them */
     vtun.ppp   = strdup("/usr/sbin/pppd");
     vtun.ifcfg = strdup("/sbin/ifconfig");
     vtun.route = strdup("/sbin/route");
     vtun.fwall = strdup("/sbin/ipchains");	
     vtun.iproute = strdup("/sbin/ip");	

     vtun.svr_name = NULL;
     vtun.svr_addr = NULL;
     vtun.bind_addr.port = -1;
     vtun.svr_type = -1;
     vtun.syslog   = LOG_DAEMON;

     /* Initialize default host options */
     memset(&default_host, 0, sizeof(default_host));
     default_host.flags   = VTUN_TTY | VTUN_TCP;
     default_host.multi   = VTUN_MULTI_ALLOW;
     default_host.timeout = VTUN_CONNECT_TIMEOUT;
     default_host.ka_interval = 30;
     default_host.ka_maxfail  = 4;
     default_host.loc_fd = default_host.rmt_fd = -1;
#ifdef HAVE_SSL
     default_host.sslauth = 1;
#else	/* HAVE_SSL */
     default_host.sslauth = 0;
#endif	/* HAVE_SSL */

     /* Start logging to syslog and stderr */
     openlog("vtund", LOG_PID | LOG_NDELAY | LOG_PERROR, LOG_DAEMON);

     while( (opt=getopt(argc,argv,"misf:P:L:t:npq46")) != EOF ){
	switch(opt){
	    case 'm':
	        if (mlockall(MCL_CURRENT | MCL_FUTURE) < 0) {
		    perror("Unable to mlockall()");
		    exit(-1);
	        }
		break;
	    case 'i':
		vtun.svr_type = VTUN_INETD;
	    case 's':
		svr = 1;
		break;
	    case 'L':
		vtun.svr_addr = strdup(optarg);
		break;
	    case 'P':
		vtun.bind_addr.port = atoi(optarg);
		break;
	    case 'f':
		vtun.cfg_file = strdup(optarg);
		break;
	    case 'n':
		daemon = 0;
		break;
	    case 'p':
		vtun.persist = 1;
		break;
	    case 't':
	        vtun.timeout = atoi(optarg);	
	        break;
	    case 'q':
		vtun.quiet = 1;
		break;
	    case '4':
		vtun.transport_af = AF_INET;
	        break;
	    case '6':
		vtun.transport_af = AF_INET6;
	        break;
	    default:
		usage();
	        exit(1);
	}
     }	
     reread_config(0);

     if (vtun.syslog != LOG_DAEMON) {
	/* Restart logging to syslog using specified facility  */
 	closelog();
 	openlog("vtund", LOG_PID|LOG_NDELAY|LOG_PERROR, vtun.syslog);
     }

	clear_nat_hack_flags(svr);

     if(!svr){
	if( argc - optind < 2 ){
	   usage();
           exit(1);
	}
	hst = argv[optind++];

        if( !(host = find_host(hst)) ){	
	   vtun_syslog(LOG_ERR,"Host %s not found in %s", hst, vtun.cfg_file);
	   exit(1);
        }

	vtun.svr_name = strdup(argv[optind]);
     } 
      	
     /* 
      * Now fill uninitialized fields of the options structure
      * with default values. 
      */ 
     if(vtun.bind_addr.port == -1)
	vtun.bind_addr.port = VTUN_PORT;
     if(vtun.persist == -1)
	vtun.persist = 0;
     if(vtun.timeout == -1)
	vtun.timeout = VTUN_TIMEOUT;
    /* 
     * Want to save behaviour from older version: stronger authentication
     * if compiled with --enable-ssl, weaker otherwise
     */
     if(vtun.sslauth == -1)
#ifdef HAVE_SSL
	vtun.sslauth = 1;
#else	/* HAVE_SSL */
	vtun.sslauth = 0;
#endif	/* HAVE_SSL */

     switch( vtun.svr_type ){
	case -1:
	   vtun.svr_type = VTUN_STAND_ALONE;
	   break;
	case VTUN_INETD:
	   sock = dup(0);
	   dofork = 0; 
	   break;
     }

     if( daemon ){
	if( dofork && fork() )
	   exit(0);

        /* Direct stdin,stdout,stderr to '/dev/null' */
        fd = open("/dev/null", O_RDWR);
	close(0); dup(fd);
	close(1); dup(fd);
        close(2); dup(fd);
        close(fd);

	setsid();

	chdir("/");
     }

     if(svr){
        memset(&sa,0,sizeof(sa));     
        sa.sa_handler=reread_config;
        sigaction(SIGHUP,&sa,NULL);

        init_title(argc,argv,env,"vtund[s]: ");

	if( vtun.svr_type == VTUN_STAND_ALONE )	
	   write_pid("server", NULL);
	
	server(sock);
     } else {	
        init_title(argc,argv,env,"vtund[c]: ");
	write_pid(host->host, vtun.svr_name);
        client(host);
     }

     closelog();
	
     return 0;
}

/* 
 * Very simple PID file creation function. Used by server.
 * Overrides existing file. Optionally adds session name and host name to the
 * pidfile name (this naming is very confusing, as the session is referred as
 * host most of the time)
 */
void write_pid(char *session, char *host)
{
     char fn[1024];
     FILE *f;

     if(session != NULL && host != NULL) {
	  snprintf(fn, sizeof(fn), "%s/vtund.%s-%s.pid", VTUN_PID_DIR, session,
			  host);
     } else if(session != NULL) {
	  snprintf(fn, sizeof(fn), "%s/vtund.%s.pid", VTUN_PID_DIR, session);
     } else {
          snprintf(fn, sizeof(fn), "%s/vtund.pid", VTUN_PID_DIR);
     }
     /* Make sure the PID file is not there before opening it for writing. */
     unlink(fn);

     if( !(f = fopen(fn, "w")) ) {
          syslog(LOG_ERR, "Can't write PID file %s: %s", fn, strerror(errno));
          return;
     }

     fprintf(f,"%d",(int)getpid());
     fclose(f);
}

void reread_config(int sig)
{
     if( !read_config(vtun.cfg_file) ){
	vtun_syslog(LOG_ERR,"No hosts defined");
	exit(1);
     }
}

void usage(void)
{
     printf("VTun ver %s\n", VTUN_VER);
     printf("Usage: \n");
     printf("  Server:\n");
     printf("\tvtund <-s> [-f file] [-P port] [-L local address]\n");
     printf("  Client:\n");
     /* I don't think these work. I'm disabling the suggestion - bish 20050601*/
     printf("\tvtund [-f file] " /* [-P port] [-L local address] */
	    "[-p] [-m] [-t timeout] <host profile> <server address>\n");
}
