示例#1
0
gogoc_status tspStartLocal(int socket, tConf *c, tTunnel *t, net_tools_t *nt)
{
  TUNNEL_LOOP_CONFIG tun_loop_cfg;
  gogoc_status status = STATUS_SUCCESS_INIT;
  int ka_interval = 0;
  int tunfd = (-1);
  int pid;


  // Check if we got root privileges.
  if(geteuid() != 0)
  {
    // Error: we don't have root privileges.
    Display( LOG_LEVEL_1, ELError, "tspStartLocal", GOGO_STR_FATAL_NOT_ROOT_FOR_TUN );
    return make_status(CTX_TUNINTERFACESETUP, ERR_INTERFACE_SETUP_FAILED);
  }

  // Check Ipv6 support.
  Display( LOG_LEVEL_2, ELInfo, "tspStartLocal", GOGO_STR_CHECKING_LINUX_IPV6_SUPPORT );
  status = tspTestIPv6Support();
  if( status_number(status) != SUCCESS )
  {
    // Error: It seems the user does not have IPv6 support in kernel.
    return status;
  }

  // Check if we're already daemon. Calling multiple times the daemon() messes up pthreads.
  if( !c->nodaemon && getppid() != 1 )
  {
    // Detach from controlling terminal and run in the background.
    Display( LOG_LEVEL_3, ELInfo, "tspStartLocal", GOGO_STR_GOING_DAEMON );
    if( daemon(1,0) == -1 )
    {
      // Error: Failed to detach.
      Display( LOG_LEVEL_1, ELError, "tspStartLocal", GOGO_STR_CANT_FORK );
      return make_status(CTX_TUNINTERFACESETUP, ERR_INTERFACE_SETUP_FAILED);
    }
  }


  // Check tunnel mode.
  if( strcasecmp(t->type, STR_CONFIG_TUNNELMODE_V4V6) == 0 )
  {
    // V4V6 tunnel mode is not supported on this platform.
    Display( LOG_LEVEL_1, ELError, "tspStartLocal", GOGO_STR_NO_V4V6_ON_PLATFORM );
    return make_status(CTX_TUNINTERFACESETUP, ERR_INTERFACE_SETUP_FAILED);
  }
  else if( strcasecmp(t->type, STR_CONFIG_TUNNELMODE_V6UDPV4) == 0 )
  {
    // When using V6UDPV4 encapsulation, open the TUN device.
    tunfd = TunInit(c->if_tunnel_v6udpv4);
    if( tunfd == -1 )
    {
      // Error: Failed to open TUN device.
      Display( LOG_LEVEL_1, ELError, "tspStartLocal", STR_MISC_FAIL_TUN_INIT );
      return make_status(CTX_TUNINTERFACESETUP, ERR_INTERFACE_SETUP_FAILED);
    }
  }

  while( 1 ) // Dummy loop. 'break' instruction at the end.
  {
    // Run the config script in another thread, without giving it our tunnel
    // descriptor. This is important because otherwise the tunnel will stay
    // open if we get killed.
    //
    pid = fork();

    if( pid < 0 )
    {
      // fork() error
      status = make_status(CTX_TUNINTERFACESETUP, ERR_INTERFACE_SETUP_FAILED);
      break;
    }
    else if (pid == 0)
    {
      // Child processing: run template script.
      if( tunfd != -1 )
      {
        close(tunfd);
      }

      status = tspSetupInterface(c, t);
      exit(status);
    }
    else
    {
      // Parent processing
      int s = 0;


      // Wait for child process to exit.
      Display( LOG_LEVEL_3, ELInfo, "tspStartLocal", GOGO_STR_WAITING_FOR_SETUP_SCRIPT );
      if( wait(&s) != pid )
      {
        // Error occured: we have no other child
        Display( LOG_LEVEL_1, ELError, "tspStartLocal", GOGO_STR_ERR_WAITING_SCRIPT );
        status = make_status(CTX_TUNINTERFACESETUP, ERR_INTERFACE_SETUP_FAILED);
        break;
      }

      // Check if process waited upon has exited.
      if( !WIFEXITED(s) )
      {
        // Error: child has not exited properly. Maybe killed ?
        Display( LOG_LEVEL_1, ELError, "tspStartLocal", STR_GEN_SCRIPT_EXEC_FAILED );
        status = make_status(CTX_TUNINTERFACESETUP, ERR_INTERFACE_SETUP_FAILED);
        break;
      }

      // Check child exit code.
      status = WEXITSTATUS(s);
      if( status_number(status) != SUCCESS )
      {
        break;
      }
    }


    // Retrieve keepalive inteval, if found in tunnel parameters.
    if( t->keepalive_interval != NULL )
    {
      ka_interval = atoi(t->keepalive_interval);
    }

    // Start the tunnel loop, depending on tunnel mode
    //
    if( strcasecmp(t->type, STR_CONFIG_TUNNELMODE_V6UDPV4) == 0 )
    {
      status = TunMainLoop( tunfd, socket, c->keepalive,
                            ka_interval, t->client_address_ipv6,
                            t->keepalive_address);

      /* We got out of V6UDPV4 "TUN" tunnel loop */
      tspClose(socket, nt);
    }
    else if( strcasecmp(t->type, STR_CONFIG_TUNNELMODE_V6V4) == 0 )
    {
      memset( &tun_loop_cfg, 0x00, sizeof(TUNNEL_LOOP_CONFIG) );
      tun_loop_cfg.ka_interval  = ka_interval;
      tun_loop_cfg.ka_src_addr  = t->client_address_ipv6;
      tun_loop_cfg.ka_dst_addr  = t->keepalive_address;
      tun_loop_cfg.sa_family    = AF_INET6;
      tun_loop_cfg.tun_lifetime = 0;

      status = tspPerformTunnelLoop( &tun_loop_cfg );
    }

    break; // END of DUMMY loop.
  }


  // Cleanup: Close tunnel descriptor, if it was opened.
  if( tunfd != -1 )
  {
    // The tunnel file descriptor should be closed before attempting to tear
    // down the tunnel. Destruction of the tunnel interface may fail if
    // descriptor is not closed.
    close( tunfd );
  }

  // Cleanup: Handle tunnel teardown.
  tspTearDownTunnel( c, t );


  return status;
}
示例#2
0
// --------------------------------------------------------------------------
// setup interface and any daemons or anything needed
// tspSetupTunnel() will callback here
//
int tspStartLocal( int socket, tConf *c, tTunnel *t, net_tools_t *nt )
{
  TUNNEL_LOOP_CONFIG tun_loop_cfg;
  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;
  }


  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 = (-1);

    Display( LOG_LEVEL_3, ELInfo, "tspStartLocal", HEX_STR_GOING_DAEMON );
    if (daemon(1, 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 )
    {
      tunfd = TunInit(c->if_tunnel_v6udpv4);
      if( tunfd == -1 )
      {
        Display( LOG_LEVEL_1, ELError, "tspStartLocal", HEX_STR_UNABLE_INIT_TUN_DEV );
        return(INTERFACE_SETUP_FAILED);
      }

      /* We need the real name of the tun device for the template */
      free( c->if_tunnel_v6udpv4 );
      c->if_tunnel_v6udpv4 = (char*) malloc( IFNAMSIZ );
      TunName(tunfd, c->if_tunnel_v6udpv4, IFNAMSIZ );
    }

    if( strcasecmp(t->type, STR_CONFIG_TUNNELMODE_V4V6) == 0 )
    {
      Display( LOG_LEVEL_1, ELError, "tspStartLocal", HEX_STR_NO_V4V6_ON_PLATFORM );
      return(INTERFACE_SETUP_FAILED);
    }

    /* 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 processing: run template script.
        close(tunfd);

        if( tspSetupInterface(c, t) != 0 )
          exit(INTERFACE_SETUP_FAILED);
        exit(0);
      }
      else
      {
        // Parent processing
        int s = 0;

        // Wait for child process to exit.
        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;
          }

          // Check child exit code.
          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,
                            keepalive_interval, t->client_address_ipv6,
                            t->keepalive_address );

      /* We got out of main V6 UDP V4 loop */
      close(tunfd);
      tspClose(socket, nt);
    }
    else if( strcasecmp(t->type, STR_CONFIG_TUNNELMODE_V6V4) == 0 )
    {
      memset( &tun_loop_cfg, 0x00, sizeof(TUNNEL_LOOP_CONFIG) );
      tun_loop_cfg.ka_interval  = keepalive_interval;
      tun_loop_cfg.ka_src_addr  = t->client_address_ipv6;
      tun_loop_cfg.ka_dst_addr  = t->keepalive_address;
      tun_loop_cfg.sa_family    = AF_INET6;
      tun_loop_cfg.tun_lifetime = 0;

      status = tspPerformTunnelLoop( &tun_loop_cfg );
    }
  }

  // Handle tunnel teardown.
  if( tspTearDownTunnel( c, t ) != 0 )
  {
    // Log the error.
    Display( LOG_LEVEL_2, ELError, "tspStartLocal", HEX_STR_SCRIPT_FAILED );
  }


  return status;
}
示例#3
0
gogoc_status tspStartLocal( int socket, tConf *c, tTunnel *t, net_tools_t *nt )
{
  TUNNEL_LOOP_CONFIG tun_loop_cfg;
  gogoc_status status = STATUS_SUCCESS_INIT;
  int ka_interval = 0;
  int tunfd = -1;
  //int pid;


  // Check if we got root privileges.
  if( geteuid() != 0 )
  {
    // Error: we don't have root privileges.
    Display( LOG_LEVEL_1, ELError, "tspStartLocal", GOGO_STR_FATAL_NOT_ROOT_FOR_TUN );
    return make_status(CTX_TUNINTERFACESETUP, ERR_INTERFACE_SETUP_FAILED);
  }

  // Check if we're already daemon. Calling multiple times the daemon() messes up pthreads.
  if( !c->nodaemon && getppid() != 1 )
  {
    // Detach from controlling terminal and run in the background.
    Display( LOG_LEVEL_3, ELInfo, "tspStartLocal", GOGO_STR_GOING_DAEMON );
    if( daemon(1, 0) == -1 )
    {
      // Error: Failed to detach.
      Display( LOG_LEVEL_1, ELError, "tspStartLocal", GOGO_STR_CANT_FORK );
      return make_status(CTX_TUNINTERFACESETUP, ERR_INTERFACE_SETUP_FAILED);
    }
  }

  // Check tunnel mode.
  if( strcasecmp(t->type, STR_CONFIG_TUNNELMODE_V4V6) == 0 )
  {
    // V4V6 encapsulation (DSTM) not supported on darwin.
    Display( LOG_LEVEL_1, ELError, "tspStartLocal", GOGO_STR_NO_V4V6_ON_PLATFORM );
    return make_status(CTX_TUNINTERFACESETUP, ERR_INTERFACE_SETUP_FAILED);
  }
  else if( strcasecmp(t->type, STR_CONFIG_TUNNELMODE_V6UDPV4) == 0 )
  {
    // When using V6UDPV4 encapsulation, open the TUN device.
    tunfd = TunInit(c->if_tunnel_v6udpv4);
    if( tunfd == -1 )
    {
      // Error: Failed to open TUN device.
      Display( LOG_LEVEL_1, ELError, "tspStartLocal", STR_MISC_FAIL_TUN_INIT );
      return make_status(CTX_TUNINTERFACESETUP, ERR_INTERFACE_SETUP_FAILED);
    }

    // Get the real name of the opened tun device for the template script.
    free( c->if_tunnel_v6udpv4 );
    c->if_tunnel_v6udpv4 = (char*) malloc( IFNAMSIZ );
    TunName( tunfd, c->if_tunnel_v6udpv4, IFNAMSIZ );
  }

  t->originalgateway = routepr();
    
  while( 1 ) // Dummy loop. 'break' instruction at the end.
  {
    // Run the config script in another thread, without giving it our tunnel
    // descriptor. This is important because otherwise the tunnel will stay
    // open if we get killed.
    //
//    pid = fork();

//    if( pid < 0 )
//    {
      // fork() error
//      status = make_status(CTX_TUNINTERFACESETUP, ERR_INTERFACE_SETUP_FAILED);
//      break;
//    }
//    else if( pid == 0 )
//    {
      // Child processing: run template script.
//      if( tunfd != -1 )
//      {
//        close(tunfd);
//      }

      status = tspSetupInterface(c, t);
//      exit( status );
//    }
//    else
//    {
      // Parent processing
//      int s = 0;

      // Wait for child process to exit.
//      Display( LOG_LEVEL_3, ELInfo, "tspStartLocal", GOGO_STR_WAITING_FOR_SETUP_SCRIPT );
//      if( wait(&s) != pid )
//      {
//        // Error occured: we have no other child
//        Display( LOG_LEVEL_1, ELError, "tspStartLocal", GOGO_STR_ERR_WAITING_SCRIPT );
//        status = make_status(CTX_TUNINTERFACESETUP, ERR_INTERFACE_SETUP_FAILED);
//        break;
//      }

      // Check if process waited upon has exited.
//      if( !WIFEXITED(s) )
//      {
//        // Error: child has not exited properly. Maybe killed ?
//        Display( LOG_LEVEL_1, ELError, "tspStartLocal", STR_GEN_SCRIPT_EXEC_FAILED );
//        Display( LOG_LEVEL_1, ELError, "tspStartLocal", "status 0x%08X %s (%d).", s, strerror(s), errno);
//        status = make_status(CTX_TUNINTERFACESETUP, ERR_INTERFACE_SETUP_FAILED);
//        break;
//      }

      // Check child exit code.
//      status = WEXITSTATUS(s);
      if( status_number(status) != SUCCESS )
      {
        break;
      }
//    }
      
      gStatusInfo.eStatus = GOGOC_CLISTAT__CONNECTED;
      gStatusInfo.nStatus = GOGOCM_UIS__NOERROR;
      send_status_info();

    // Retrieve keepalive inteval, if found in tunnel parameters.
    if( t->keepalive_interval != NULL )
    {
      ka_interval = atoi(t->keepalive_interval);
    }

    // Start the tunnel loop, depending on tunnel mode
    //
    if( strcasecmp(t->type, STR_CONFIG_TUNNELMODE_V6UDPV4) == 0 )
    {
      status = TunMainLoop( tunfd, socket, c->keepalive,
                            ka_interval, t->client_address_ipv6,
                            t->keepalive_address );

      LOG( LOG_LEVEL_2, ELInfo, "end TunMainLoop. Starting tspClose.");
      // We got out of main V6UDPV4 loop.
      tspClose(socket, nt);
      LOG( LOG_LEVEL_2, ELInfo, "end tspClose.");
    }
    else if( strcasecmp(t->type, STR_CONFIG_TUNNELMODE_V6V4) == 0 )
    {
      memset( &tun_loop_cfg, 0x00, sizeof(TUNNEL_LOOP_CONFIG) );
      tun_loop_cfg.ka_interval  = ka_interval;
      tun_loop_cfg.ka_src_addr  = t->client_address_ipv6;
      tun_loop_cfg.ka_dst_addr  = t->keepalive_address;
      tun_loop_cfg.sa_family    = AF_INET6;
      tun_loop_cfg.tun_lifetime = 0;

      status = tspPerformTunnelLoop( &tun_loop_cfg );
    }

    break; // END of DUMMY loop.
  }


  // Cleanup: Close tunnel descriptor, if it was opened.
  if( tunfd != -1 )
  {
    LOG( LOG_LEVEL_2, ELInfo, "Closing tunnel descriptor");
    // The tunnel file descriptor should be closed before attempting to tear
    // down the tunnel. Destruction of the tunnel interface may fail if
    // descriptor is not closed.
    close( tunfd );
  }

  // Cleanup: Handle tunnel teardown.
  LOG( LOG_LEVEL_2, ELInfo, "Handle tunnel teardown");
  tspTearDownTunnel( c, t );


  return status;
}
示例#4
0
gogoc_status tspStartLocal(int socket, tConf *c, tTunnel *t, net_tools_t *nt)
{
  TUNNEL_LOOP_CONFIG tun_loop_cfg;
  int keepalive_interval = 0;
  gogoc_status status = STATUS_SUCCESS_INIT;


  /* Test for root privileges */
  if(geteuid() != 0)
  {
    Display(LOG_LEVEL_1, ELError, "tspStartLocal", GOGO_STR_FATAL_NOT_ROOT_FOR_TUN);
    return make_status(CTX_TUNINTERFACESETUP, ERR_INTERFACE_SETUP_FAILED);
  }

  /* start the tunneler service */

  if (t->keepalive_interval != NULL)
  {
    keepalive_interval = atoi(t->keepalive_interval);
  }

  {
    Display(LOG_LEVEL_3, ELInfo, "tspStartLocal", GOGO_STR_GOING_DAEMON);

    // Check if we're already daemon. Calling multiple times the daemon() messes up pthreads.
    if( !c->nodaemon && getppid() != 1 )
    {
      if (daemon(1, 0) == -1)
      {
        Display(LOG_LEVEL_1, ELError, "tspStartLocal", GOGO_STR_CANT_FORK);
        return make_status(CTX_TUNINTERFACESETUP, ERR_INTERFACE_SETUP_FAILED);
      }
    }

    if (strcasecmp(t->type, STR_CONFIG_TUNNELMODE_V6UDPV4) == 0 )
    {
      Display(LOG_LEVEL_1, ELError, "tspStartLocal", GOGO_STR_NO_V6UDPV4_ON_PLATFORM);
      return(make_status(CTX_TUNINTERFACESETUP, ERR_INTERFACE_SETUP_FAILED));
    }

    if (strcasecmp(t->type, STR_CONFIG_TUNNELMODE_V4V6) == 0 )
    {
      Display(LOG_LEVEL_1, ELError, "tspStartLocal", GOGO_STR_NO_V4V6_ON_PLATFORM);
      return(make_status(CTX_TUNINTERFACESETUP, ERR_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 make_status(CTX_TUNINTERFACESETUP, ERR_INTERFACE_SETUP_FAILED);
      }
      else if (pid == 0)
      {
        // Child process
        status = tspSetupInterface(c, t);
        exit(status);
      }
      else
      {
        // Parent process
        int s = 0;
        Display(LOG_LEVEL_3, ELInfo, "tspStartLocal", GOGO_STR_WAITING_FOR_SETUP_SCRIPT);
        if (wait(&s) == pid)
        {
          // Our child returned
          if ( !WIFEXITED(s) )
          {
            Display(LOG_LEVEL_1, ELError, "tspStartLocal", STR_GEN_SCRIPT_EXEC_FAILED);
            return make_status(CTX_TUNINTERFACESETUP, ERR_INTERFACE_SETUP_FAILED);
          }

          // Check exit status.
          status = WEXITSTATUS(s);
          if( status_number(status) != SUCCESS )
          {
            return status;
          }
        }
        else
        {
          // Error occured: we have no other child
          Display(LOG_LEVEL_1, ELError, "tspStartLocal", GOGO_STR_ERR_WAITING_SCRIPT);
          return make_status(CTX_TUNINTERFACESETUP, ERR_INTERFACE_SETUP_FAILED);
        }
      }
    }


    if( strcasecmp(t->type, STR_CONFIG_TUNNELMODE_V6V4) == 0 )
    {
      memset( &tun_loop_cfg, 0x00, sizeof(TUNNEL_LOOP_CONFIG) );
      tun_loop_cfg.ka_interval  = keepalive_interval;
      tun_loop_cfg.ka_src_addr  = t->client_address_ipv6;
      tun_loop_cfg.ka_dst_addr  = t->keepalive_address;
      tun_loop_cfg.sa_family    = AF_INET6;
      tun_loop_cfg.tun_lifetime = 0;

      status = tspPerformTunnelLoop( &tun_loop_cfg );
    }

    /* v4v6 not supported yet
    if( strcasecmp(t->type, STR_CONFIG_TUNNELMODE_V4V6) == 0 )
    {
      memset( &tun_loop_cfg, 0x00, sizeof(TUNNEL_LOOP_CONFIG) );
      tun_loop_cfg.ka_interval  = keepalive_interval;
      tun_loop_cfg.ka_src_addr  = t->client_address_ipv4;
      tun_loop_cfg.ka_dst_addr  = t->keepalive_address;
      tun_loop_cfg.sa_family    = AF_INET;
      tun_loop_cfg.tun_lifetime = atoi(t->lifetime);

      status = tspPerformTunnelLoop( &tun_loop_cfg );
    } */
  }


  // Handle tunnel teardown.
  tspTearDownTunnel( c, t );


  return status;
}
示例#5
0
int tspStartLocal(int 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;
  }

  if (t->keepalive_interval != NULL)
  {
    keepalive_interval = atoi(t->keepalive_interval);
    Display(LOG_LEVEL_3, ELInfo, "tspStartLocal", HEX_STR_KEEPALIVE_INTERVAL, t->keepalive_interval);
  }

  Display(LOG_LEVEL_3, ELInfo, "tspStartLocal", HEX_STR_GOING_DAEMON);
  if (daemon(1, 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 )
  {
    Display(LOG_LEVEL_1, ELError, "tspStartLocal", HEX_STR_NO_V6UDPV4_ON_PLATFORM);
    return(INTERFACE_SETUP_FAILED);
  }

  if (strcasecmp(t->type, STR_CONFIG_TUNNELMODE_V4V6) == 0 )
  {
    Display(LOG_LEVEL_1, ELError, "tspStartLocal", HEX_STR_NO_V4V6_ON_PLATFORM);
    return(INTERFACE_SETUP_FAILED);
  }

  /* 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 )
    {
      // Perform child processing: Configure tunneling interface.
      if( tspSetupInterface(c, t) != 0 )
        exit(INTERFACE_SETUP_FAILED);

      exit(0);
    }
    else
    {
      // Parent process.
      int s = 0;
      Display(LOG_LEVEL_3, ELInfo, "tspStartLocal", HEX_STR_WAITING_FOR_SETUP_SCRIPT);

      // Wait for child process to exit.
      if( wait(&s) == pid )
      {
        // The child process has finished.
        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;
      }
    }
  }


  /* v4v6 not supported yet
  if (strcasecmp(t->type, STR_CONFIG_TUNNELMODE_V4V6) == 0 )
  {
    TUNNEL_LOOP_CONFIG tun_loop_cfg;

    memset( &tun_loop_cfg, 0x00, sizeof(TUNNEL_LOOP_CONFIG) );
    tun_loop_cfg.ka_interval  = keepalive_interval;
    tun_loop_cfg.ka_src_addr  = t->client_address_ipv4;
    tun_loop_cfg.ka_dst_addr  = t->keepalive_address;
    tun_loop_cfg.sa_family    = AF_INET;
    tun_loop_cfg.tun_lifetime = 0;

    status = tspPerformTunnelLoop( &tun_loop_cfg );
  }
  */

  if (strcasecmp(t->type, STR_CONFIG_TUNNELMODE_V6V4) == 0 )
  {
    TUNNEL_LOOP_CONFIG tun_loop_cfg;

    memset( &tun_loop_cfg, 0x00, sizeof(TUNNEL_LOOP_CONFIG) );
    tun_loop_cfg.ka_interval  = keepalive_interval;
    tun_loop_cfg.ka_src_addr  = t->client_address_ipv6;
    tun_loop_cfg.ka_dst_addr  = t->keepalive_address;
    tun_loop_cfg.sa_family    = AF_INET6;
    tun_loop_cfg.tun_lifetime = 0;

    status = tspPerformTunnelLoop( &tun_loop_cfg );
  }

  // Handle tunnel teardown.
  if( tspTearDownTunnel( c, t ) != 0 )
  {
    // Log the error.
    Display(LOG_LEVEL_2, ELError, "tspStartLocal", HEX_STR_SCRIPT_FAILED);
  }

  return status;
}