int main(int argc, char *argv[]) { enum AICCU_MODES mode = A_NONE; struct TIC_Tunnel *hTunnel; #ifdef _WIN32 WSADATA wsadata; unsigned int i; /* Initialize Winsock so that we can do network functions */ WSAStartup(WINSOCK_VERSION, &wsadata); #endif /* Initialize Configuration */ aiccu_InitConfig(); /* Make sure we actually have an IPv6 stack */ aiccu_install(); /* Require start/stop/test */ if (argc == 2 || argc == 3) { if (strcasecmp(argv[1], "start") == 0) mode = A_START; else if (strcasecmp(argv[1], "stop") == 0) mode = A_STOP; else if (strcasecmp(argv[1], "brokers") == 0) mode = A_BROKERS; else if (strcasecmp(argv[1], "tunnels") == 0) mode = A_TUNNELS; else if (strcasecmp(argv[1], "test") == 0) mode = A_TEST; else if (strcasecmp(argv[1], "autotest")== 0) mode = A_AUTOTEST; else if (strcasecmp(argv[1], "license") == 0) mode = A_LICENSE; #ifdef _WIN32 else if (strcasecmp(argv[1], "listtaps") == 0) mode = A_LISTTAPS; #endif else if (strcasecmp(argv[1], "version") == 0) mode = A_VERSION; } /* Optionally we want a second argument: a config file */ if (( argc != 2 && argc != 3) || mode == A_NONE) { dolog(LOG_ERR, "%s", options); return -1; } if ( mode == A_LICENSE) { printf("%s\n", aiccu_license()); return 0; } if ( mode == A_VERSION) { printf("AICCU %s by Jeroen Massar\n", AICCU_VERSION); return 0; } #ifdef _WIN32 if ( mode == A_LISTTAPS) { tun_list_tap_adapters(); return 0; } #endif if ( mode == A_BROKERS) { int ret = list_brokers(); aiccu_FreeConfig(); return ret == 0 ? -1 : 0; } if (!aiccu_LoadConfig(argc <= 2 ? NULL : argv[2])) { return -1; } #ifndef _WIN32 /* start or stop? */ if ( mode != A_TEST && mode != A_AUTOTEST) { /* Already running? */ if (sigrunning(mode == A_STOP ? SIGTERM : 0) == 1) { dolog(LOG_ERR, "Already running instance HUP'ed, exiting\n"); return 0; } } #endif /* Verify required parameters */ if (!g_aiccu || !g_aiccu->username || !g_aiccu->password) { dolog(LOG_ERR, "Required parameters missing, make sure that username and password are given\n"); aiccu_FreeConfig(); return -1; } if (mode == A_TUNNELS) { int ret = list_tunnels(); aiccu_FreeConfig(); return ret == 0 ? -1 : 0; } /* Get our tunnel */ hTunnel = get_tunnel(); if (!hTunnel) { dolog(LOG_ERR, "Couldn't retrieve first tunnel for the above reason, aborting\n"); aiccu_FreeConfig(); return -1; } /* * We now have sufficient information. * Thus we can logout from the TIC server */ tic_Logout(g_aiccu->tic, NULL); g_aiccu->tic = NULL; if (g_aiccu->verbose) { printf("Tunnel Information for %s:\n",hTunnel->sId); printf("POP Id : %s\n", hTunnel->sPOP_Id); printf("IPv6 Local : %s/%u\n", hTunnel->sIPv6_Local,hTunnel->nIPv6_PrefixLength); printf("IPv6 Remote : %s/%u\n", hTunnel->sIPv6_POP,hTunnel->nIPv6_PrefixLength); printf("Tunnel Type : %s\n", hTunnel->sType); printf("Adminstate : %s\n", hTunnel->sAdminState); printf("Userstate : %s\n", hTunnel->sUserState); } /* One can always try to stop it */ if (mode == A_STOP) { aiccu_delete(hTunnel); /* Free stuff and exit */ tic_Free_Tunnel(hTunnel); aiccu_FreeConfig(); return 0; } if ( (strcmp(hTunnel->sAdminState, "enabled") != 0) || (strcmp(hTunnel->sUserState, "enabled") != 0)) { dolog(LOG_ERR, "Tunnel is not enabled (UserState: %s, AdminState: %s)\n", hTunnel->sAdminState, hTunnel->sUserState); return -1; } /* Do the test thing */ if ( mode == A_TEST || mode == A_AUTOTEST) { #ifdef _WIN32 SetConsoleCtrlHandler((PHANDLER_ROUTINE)sigterm_testing, true); #endif /* Setup the tunnel */ if (aiccu_setup(hTunnel, true)) { aiccu_test(hTunnel, strcasecmp(argv[1], "autotest") == 0 ? true : false); /* Tear the tunnel down again */ aiccu_delete(hTunnel); } else { dolog(LOG_ERR, "Tunnel Setup Failed\n"); } /* exit as all is done */ tic_Free_Tunnel(hTunnel); aiccu_FreeConfig(); return 0; } #ifndef _WIN32 if ( mode == A_START && g_aiccu->daemonize != 0) { FILE *f; /* Daemonize */ int i = fork(); if (i < 0) { fprintf(stderr, "Couldn't fork\n"); return -1; } /* Exit the mother fork */ if (i != 0) return 0; /* Child fork */ setsid(); /* Chdir to minimise disruption to FS umounts */ (void)chdir("/"); /* Cleanup stdin/out/err */ freopen("/dev/null","r",stdin); freopen("/dev/null","w",stdout); freopen("/dev/null","w",stderr); /* */ f = fopen(g_aiccu->pidfile, "w"); if (!f) { dolog(LOG_ERR, "Could not store PID in file %s\n", g_aiccu->pidfile); return 0; } fprintf(f, "%d", getpid()); fclose(f); dolog(LOG_INFO, "AICCU running as PID %d\n", getpid()); } #endif /* !_WIN32 */ /* mode == A_START */ #ifndef _WIN32 /* * Install a signal handler so that * one can disable beating with SIGUSR1 */ signal(SIGUSR1, &sigusr1); /* * Install a signal handler so that * one can stop this program with SIGTERM */ signal(SIGTERM, &sigterm); signal(SIGINT, &sigterm); #else SetConsoleCtrlHandler((PHANDLER_ROUTINE)sigterm, true); #endif /* * Setup our tunnel * This also spawns required threads for AYIYA */ if (aiccu_setup(hTunnel, true)) { /* We need to stay running when doing Heartbeat or AYIYA */ if ( strcasecmp(hTunnel->sType, "6in4-heartbeat") == 0 || strcasecmp(hTunnel->sType, "ayiya") == 0) { /* We are spawned, now just beat once in a while. */ while (g_aiccu->running) { aiccu_beat(hTunnel); #ifndef _WIN32 sleep(hTunnel->nHeartbeat_Interval); #else for (i=0; g_aiccu->running && i <= hTunnel->nHeartbeat_Interval; i++) Sleep(1000); #endif } /* Clean up the the tunnel, no beat anyway */ aiccu_delete(hTunnel); } #ifndef _WIN32 /* Remove our PID file */ if (g_aiccu) unlink(g_aiccu->pidfile); #endif } /* Free our resources */ aiccu_FreeConfig(); return 0; }
struct TIC_Tunnel *tic_GetTunnel(struct TIC_conf *tic, const char *sId) { char buf[1024]; struct TIC_Tunnel *tun; /* Get a Tunnel */ sock_printf(tic->sock, "tunnel show %s\n", sId); /* Fetch the answer */ if (sock_getline(tic->sock, tic_buf, sizeof(tic_buf), &tic_filled, buf, sizeof(buf)) == -1) { return NULL; } /* 201 (start of information) ? */ if (buf[0] != '2' || buf[1] != '0' || buf[2] != '1') { dolog(LOG_ERR, "Couldn't show tunnel %s: %s.\n", sId, buf); return NULL; } /* Allocate a new struct */ tun = (struct TIC_Tunnel *)malloc(sizeof(*tun)); if (!tun) { dolog(LOG_ERR, "Memory problem while getting tunnel %s\n", sId); return NULL; } memset(tun, 0, sizeof(*tun)); /* Gather the information */ while (sock_getline(tic->sock, tic_buf, sizeof(tic_buf), &tic_filled, buf, sizeof(buf)) != -1) { /* 202 (end of list) ? */ if (buf[0] == '2' && buf[1] == '0' && buf[2] == '2') break; parseline(buf, ": ", tunnel_rules, tun); } /* All went okay? */ if (buf[0] == '2' && buf[1] == '0' && buf[2] == '2') { struct in6_addr ipv6_ll, ipv6_local; char ll[100]; /* Log that the fetch was succesful */ #ifndef AICCU_PATCH dolog(LOG_INFO, "Succesfully retrieved tunnel information for %s\n", sId); #endif /* * Some TUN/TAP devices don't have any * link local addresses and we want multicast and MLD to work * thus we invent one based on the following: * * ipv6_us = 2001:0db8:1234:5678: : : :0001 * ipv6_ll = fe80: : : :0db8:1234:5678:0001 * * Thus we ignore the first 16bits, take the following 48 bits * and then add the last 16bits. * * As we are not 100% sure that this LL is unique we clear that bit. */ inet_pton(AF_INET6, tun->sIPv6_Local, &ipv6_local); /* Link Local (fe80::/64) */ ipv6_ll.s6_addr[ 0] = 0xfe; ipv6_ll.s6_addr[ 1] = 0x80; ipv6_ll.s6_addr[ 2] = 0x00; ipv6_ll.s6_addr[ 3] = 0x00; ipv6_ll.s6_addr[ 4] = 0x00; ipv6_ll.s6_addr[ 5] = 0x00; ipv6_ll.s6_addr[ 6] = 0x00; ipv6_ll.s6_addr[ 7] = 0x00; ipv6_ll.s6_addr[ 8] = ipv6_local.s6_addr[ 2] & 0xfc; /* Clear the LL Unique Bit */ ipv6_ll.s6_addr[ 9] = ipv6_local.s6_addr[ 3]; ipv6_ll.s6_addr[10] = ipv6_local.s6_addr[ 4]; ipv6_ll.s6_addr[11] = ipv6_local.s6_addr[ 5]; ipv6_ll.s6_addr[12] = ipv6_local.s6_addr[ 6]; ipv6_ll.s6_addr[13] = ipv6_local.s6_addr[ 7]; ipv6_ll.s6_addr[14] = ipv6_local.s6_addr[14]; ipv6_ll.s6_addr[15] = ipv6_local.s6_addr[15]; inet_ntop(AF_INET6, &ipv6_ll, ll, sizeof(ll)); if (tun->sIPv6_LinkLocal) free(tun->sIPv6_LinkLocal); tun->sIPv6_LinkLocal = strdup(ll); if ( strcmp(tun->sType, "ayiya") == 0 || strcmp(tun->sType, "l2tp") == 0) { tun->uses_tundev = 1; #ifdef NO_IFHEAD dolog(LOG_ERR, "This build doesn't support the Tun/TAP device and thus can't instantiate tunnels of type %s, please fix your OS and recompile\n", tun->sType); tic_Free_Tunnel(tun); return NULL; #endif } else tun->uses_tundev = 0; /* Need to override the local IPv4 address? */ #ifndef AICCU_PATCH if (g_aiccu->local_ipv4_override) { dolog(LOG_INFO, "Overriding Local IPv4 address from %s to %s\n", tun->sIPv4_Local, g_aiccu->local_ipv4_override); free(tun->sIPv4_Local); tun->sIPv4_Local = strdup(g_aiccu->local_ipv4_override); } #endif return tun; } /* Free the structure, it is broken anyway */ tic_Free_Tunnel(tun); dolog(LOG_ERR, "Tunnel Get for %s went wrong: %s\n", sId, buf); return NULL; }