/* --------------------------------------------------------------------------- $Id: tsp_local.c,v 1.42 2007/04/25 19:31:33 cnepveu Exp $ --------------------------------------------------------------------------- This source code copyright (c) Hexago Inc. 2002-2007. LICENSE NOTICE: You may use and modify this source code only if you have executed a valid license agreement with Hexago Inc. granting you the right to do so, the said license agreement governing such use and modifications. Copyright or other intellectual property notices are not to be removed from the source code. --------------------------------------------------------------------------- */ /* LINUX */ #include #include #include #include #include #include #include #include #define _USES_SYS_TIME_H_ #define _USES_SYS_SOCKET_H_ #define _USES_NETINET_IN_H_ #define _USES_ARPA_INET_H_ #include "platform.h" /* get data types needed here */ #include "config.h" /* tConf */ #include "xml_tun.h" /* tTunnel */ #include "net.h" /* net_tools_t */ #include "tsp_net.h"/* tspClose */ #include "tsp_client.h"/*tspmain*/ #include "net_ka.h" /* NetKeepaliveV6V4Tunnel */ /* some globals and the logging */ #include "lib.h" #include "log.h" #include "hex_strings.h" #include "errors.h" #include "tsp_tun.h" /* linux's tun */ #include "tsp_setup.h" /* these globals are defined by US used by alot of things in */ char *FileName = "gw6c.conf"; char *ScriptInterpretor = "/bin/sh"; char *ScriptExtension = "sh"; char *ScriptDir = NULL; char *TspHomeDir = "/usr/local/etc/gw6"; char DirSeparator = '/'; int RootUid = 0; #include // Dummy implementation for non-win32 targets // (Library gw6cmessaging is not linked in non-win32 targets). error_t send_status_info( void ) { return GW6CM_UIS__NOERROR; } error_t send_tunnel_info( void ) { return GW6CM_UIS__NOERROR; } error_t send_broker_list( void ) { return GW6CM_UIS__NOERROR; } error_t send_hap6_status_info( void ) { return GW6CM_UIS__NOERROR; } /* Verify for ipv6 support */ static int tspTestIPv6Support() { struct stat buf; if(stat("/proc/net/if_inet6",&buf) == -1) { Display(LOG_LEVEL_1,ELError,"tspTestIPv6Support",HEX_STR_NO_IPV6_SUPPORT_FOUND); Display(LOG_LEVEL_1,ELError,"tspTestIPv6Support",HEX_STR_TRY_MODPROBE_IPV6); return INTERFACE_SETUP_FAILED; } Display(LOG_LEVEL_2,ELInfo,"tspTestIPv6Support",HEX_STR_IPV6_SUPPORT_FOUND); return NO_ERROR; } /* linux specific to setup an env variable */ void tspSetEnv(char *Variable, char *Value, int Flag) { setenv(Variable, Value, Flag); Display(LOG_LEVEL_3, ELNotice, "tspSetEnv", "%s=%s", Variable, Value); } // -------------------------------------------------------------------------- // Called from tsp_setup.c -> tspSetupInterface // Do extra platform-specific stuff before tunnel script is launched. // int tspSetupInterfaceLocal( tConf* pConf, tTunnel* pTun ) { return 0; } /* tspSetupTunnel() will callback here */ char * tspGetLocalAddress(int socket, char *buffer, int size) { struct sockaddr_in6 addr; /* enough place for v4 and v6 */ struct sockaddr_in *addr_v4 = (struct sockaddr_in *)&addr; struct sockaddr_in6 *addr_v6 = (struct sockaddr_in6 *)&addr; int len; len = sizeof addr; if (getsockname(socket, (struct sockaddr *)&addr, &len) < 0) { Display(LOG_LEVEL_3, ELError, "TryServer", HEX_STR_ERR_FIND_SRC_IP); return NULL; } if (addr.sin6_family == AF_INET6) return (char *)inet_ntop(AF_INET6, (const void*) &addr_v6->sin6_addr, buffer, size); else return (char *)inet_ntop(AF_INET, (const void*) &addr_v4->sin_addr, buffer, size); } /* tspSetupTunnel() will callback here */ /* start locally, ie, setup interface and any daemons or anything needed */ int tspStartLocal(SOCKET socket, tConf *c, tTunnel *t, net_tools_t *nt) { int status = NO_ERROR; int keepalive_interval = 0; /* Test for root privileges */ if(geteuid() != 0) { Display(LOG_LEVEL_1, ELError, "tspStartLocal", HEX_STR_FATAL_NOT_ROOT_FOR_TUN); return INTERFACE_SETUP_FAILED; } /* Check Ipv6 support */ Display(LOG_LEVEL_2, ELNotice, "tspStartLocal", HEX_STR_CHECKING_LINUX_IPV6_SUPPORT); if(tspTestIPv6Support() == INTERFACE_SETUP_FAILED) return INTERFACE_SETUP_FAILED; /* start the tunneler service */ if (t->keepalive_interval != NULL) { keepalive_interval = atoi(t->keepalive_interval); Display(LOG_LEVEL_3, ELInfo, "tspStartLocal", HEX_STR_KEEPALIVE_INTERVAL, t->keepalive_interval); } { int tunfd; Display(LOG_LEVEL_3, ELInfo, "tspStartLocal", HEX_STR_GOING_DAEMON); if (daemon(0,0) == -1) { Display(LOG_LEVEL_3, ELError, "tspStartLocal", HEX_STR_CANT_FORK); return INTERFACE_SETUP_FAILED; } if (strcasecmp(t->type, STR_CONFIG_TUNNELMODE_V6UDPV4) == 0 ) { if ((tunfd = TunInit(c->if_tunnel_v6udpv4)) == -1 ) { Display(LOG_LEVEL_3, ELError, "tspStartLocal", HEX_STR_CANT_INIT_TUN_DEV); return(INTERFACE_SETUP_FAILED); } } /* now, run the config script without giving it our tunnel file descriptor. This is important because otherwise the tunnnel will stay open even if we get killed */ { int pid = fork(); if (pid < 0) // fork() error return INTERFACE_SETUP_FAILED; else if (pid == 0) { // child close(tunfd); if (tspSetupInterface(c, t) != 0) exit(INTERFACE_SETUP_FAILED); exit(0); } else { //parent int s = 0; Display(LOG_LEVEL_3, ELInfo, "tspStartLocal", HEX_STR_WAITING_FOR_SETUP_SCRIPT); if (wait(&s) == pid) { // ok our child returned if ( !WIFEXITED(s) ) { Display(LOG_LEVEL_3, ELError, "tspStartLocal", HEX_STR_SCRIPT_FAILED); return INTERFACE_SETUP_FAILED; } if ( WEXITSTATUS(s) != 0 ) { Display(LOG_LEVEL_3, ELError, "tspStartLocal", HEX_STR_SCRIPT_FAILED); return INTERFACE_SETUP_FAILED; } // else everything is fine } else { // error occured we have no other child Display(LOG_LEVEL_1, ELError, "tspStartLocal", HEX_STR_ERR_WAITING_SCRIPT); return INTERFACE_SETUP_FAILED; } } } if (strcasecmp(t->type, STR_CONFIG_TUNNELMODE_V6UDPV4) == 0 ) { status = TunMainLoop(tunfd, socket, c->keepalive, atoi(t->keepalive_interval), t->client_address_ipv6, t->keepalive_address); /* We got out of main loop = keepalive timeout || tunnel error */ close(tunfd); tspClose(socket, nt); return status; } else if (strcasecmp(t->type, STR_CONFIG_TUNNELMODE_V6V4) == 0 ) { if (keepalive_interval == 0) return NO_ERROR; /* if there is no keepalive, we can exit safe at this point */ status = NetKeepaliveV6V4Tunnel(t->client_address_ipv6, t->keepalive_address, keepalive_interval); return status; } } return INTERFACE_SETUP_FAILED;/* should never reach here */ }