vtun/server.c
2015-10-17 17:21:51 +02:00

210 lines
4.9 KiB
C

/*
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: server.c,v 1.9.2.4 2013/07/07 19:55:14 mtbishop Exp $
*/
#include "config.h"
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include <signal.h>
#include <fcntl.h>
#include <syslog.h>
#include <sys/socket.h>
#ifdef HAVE_NETINET_IN_H
#include <netinet/in.h>
#endif
#ifdef HAVE_NETINET_TCP_H
#include <netinet/tcp.h>
#endif
#ifdef HAVE_ARPA_INET_H
#include <arpa/inet.h>
#endif
#include <sodium.h>
#include "vtun.h"
#include "lib.h"
#include "lock.h"
#include "auth.h"
#include "compat.h"
#include "netlib.h"
static volatile sig_atomic_t server_term;
static void sig_term(int sig)
{
vtun_syslog(LOG_INFO,"Terminated");
server_term = VTUN_SIG_TERM;
}
static void connection(int sock)
{
struct sockaddr_in my_addr, cl_addr;
struct vtun_host *host;
struct sigaction sa;
char *ip;
int opt;
randombytes_stir();
opt = sizeof(struct sockaddr_in);
if( getpeername(sock, (struct sockaddr *) &cl_addr, &opt) ){
vtun_syslog(LOG_ERR, "Can't get peer name");
exit(1);
}
opt = sizeof(struct sockaddr_in);
if( getsockname(sock, (struct sockaddr *) &my_addr, &opt) < 0 ){
vtun_syslog(LOG_ERR, "Can't get local socket address");
exit(1);
}
ip = strdup(inet_ntoa(cl_addr.sin_addr));
io_init();
if( (host=auth_server(sock)) ){
memset(&sa, 0, sizeof sa);
sa.sa_handler=SIG_IGN;
sa.sa_flags=SA_NOCLDWAIT;;
sigaction(SIGHUP,&sa,NULL);
vtun_syslog(LOG_INFO,"Session %s[%s:%d] opened", host->host, ip,
ntohs(cl_addr.sin_port) );
host->rmt_fd = sock;
host->sopt.laddr = strdup(inet_ntoa(my_addr.sin_addr));
host->sopt.lport = vtun.bind_addr.port;
host->sopt.raddr = strdup(ip);
host->sopt.rport = ntohs(cl_addr.sin_port);
/* Start tunnel */
tunnel(host);
vtun_syslog(LOG_INFO,"Session %s closed", host->host);
/* Unlock host. (locked in auth_server) */
unlock_host(host);
} else {
vtun_syslog(LOG_INFO,"Denied connection from %s:%d", ip,
ntohs(cl_addr.sin_port) );
}
close(sock);
exit(0);
}
#ifdef HAVE_WORKING_FORK
static void listener(void)
{
struct sigaction sa;
struct sockaddr_in my_addr, cl_addr;
int s, s1, opt;
memset(&my_addr, 0, sizeof(my_addr));
my_addr.sin_family = AF_INET;
/* Set listen address */
if( generic_addr(&my_addr, &vtun.bind_addr) < 0)
{
vtun_syslog(LOG_ERR, "Can't fill in listen socket");
exit(1);
}
if( (s=socket(AF_INET,SOCK_STREAM,0))== -1 ){
vtun_syslog(LOG_ERR,"Can't create socket");
exit(1);
}
opt=1;
setsockopt(s, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt));
if( bind(s,(struct sockaddr *)&my_addr,sizeof(my_addr)) ){
vtun_syslog(LOG_ERR,"Can't bind to the socket %s", inet_ntoa(my_addr.sin_addr));
exit(1);
}
if( listen(s, 10) ){
vtun_syslog(LOG_ERR,"Can't listen on the socket");
exit(1);
}
memset(&sa,0,sizeof(sa));
sa.sa_flags = SA_NOCLDWAIT;
sa.sa_handler=sig_term;
sigaction(SIGTERM,&sa,NULL);
sigaction(SIGINT,&sa,NULL);
server_term = 0;
set_title("waiting for connections on port %d", vtun.bind_addr.port);
while( (!server_term) || (server_term == VTUN_SIG_HUP) ){
opt=sizeof(cl_addr);
if( (s1=accept(s,(struct sockaddr *)&cl_addr,&opt)) < 0 )
continue;
switch( fork() ){
case 0:
close(s);
connection(s1);
break;
case -1:
vtun_syslog(LOG_ERR, "Couldn't fork()");
default:
close(s1);
break;
}
}
}
#endif
void server(int sock)
{
struct sigaction sa;
memset(&sa, 0, sizeof sa);
sa.sa_handler=SIG_IGN;
sa.sa_flags=SA_NOCLDWAIT;;
sigaction(SIGINT,&sa,NULL);
sigaction(SIGQUIT,&sa,NULL);
sigaction(SIGCHLD,&sa,NULL);
sigaction(SIGPIPE,&sa,NULL);
sigaction(SIGUSR1,&sa,NULL);
vtun_syslog(LOG_INFO,"VTUN server ver %s (%s)", VTUN_VER,
vtun.svr_type == VTUN_INETD ? "inetd" : "stand" );
switch( vtun.svr_type ){
case VTUN_STAND_ALONE:
#ifdef HAVE_WORKING_FORK
listener();
#else
vtun_syslog(LOG_ERR,"Standalone server is not supported: fork() not available");
#endif
break;
case VTUN_INETD:
connection(sock);
break;
}
}