Imported Upstream version 20070115
[aiccu.git] / unix-console / main.c
blob8a4d9a9b7ab60a16d4c92383e69256ef9863517b
1 /**********************************************************
2 SixXS - Automatic IPv6 Connectivity Configuration Utility
3 ***********************************************************
4 Copyright 2003-2005 SixXS - http://www.sixxs.net
5 ***********************************************************
6 unix-client/aiccu.c - AICCU - The client for UNIX
7 ***********************************************************
8 $Author: jeroen $
9 $Id: main.c,v 1.20 2007-01-15 11:57:34 jeroen Exp $
10 $Date: 2007-01-15 11:57:34 $
11 **********************************************************/
13 #include "../common/aiccu.h"
14 #include "../common/tun.h"
16 #ifndef _WIN32
17 /* Enable/Disable heartbeating */
18 void sigusr1(int i);
19 void sigusr1(int i)
21 /* Toggle the flag */
22 g_aiccu->makebeats = !g_aiccu->makebeats;
24 /* Reset the signal */
25 signal(i, &sigusr1);
28 void sigterm(int i);
29 void sigterm(int i)
31 g_aiccu->running = false;
32 signal(i, SIG_IGN);
35 int sigrunning(int sig);
36 int sigrunning(int sig)
38 int pid;
39 FILE *f;
41 if (!g_aiccu) return 0;
43 /* Open our PID file */
44 f = fopen(g_aiccu->pidfile, "r");
45 if (!f) return 0;
47 /* Get the PID from the file or make it invalid when the format is wrong */
48 if (fscanf(f, "%d", &pid) != 1) pid = -1;
50 /* Close the file again */
51 fclose(f);
53 /* If we can HUP it, it still runs */
54 return (pid > 0 && kill(pid, sig) == 0 ? 1 : 0);
57 #else
59 static BOOL sigterm(DWORD sig);
60 static BOOL sigterm(DWORD sig)
62 D(dolog(LOG_DEBUG, "Terminating due to CTRL event\n"));
63 g_aiccu->running = false;
64 return true;
66 static BOOL sigterm_testing(DWORD sig);
67 static BOOL sigterm_testing(DWORD sig)
69 D(dolog(LOG_DEBUG, "Ignoring CTRL event\n"));
70 return true;
73 #endif
75 int list_tunnels(void);
76 int list_tunnels(void)
78 struct TIC_sTunnel *hsTunnel, *t;
80 if (!tic_Login(g_aiccu->tic, g_aiccu->username, g_aiccu->password, g_aiccu->server)) return 0;
82 hsTunnel = tic_ListTunnels(g_aiccu->tic);
84 if (!hsTunnel)
86 tic_Logout(g_aiccu->tic, "Getting current tunnel listing");
87 return 1;
90 for (t = hsTunnel; t; t = t->next)
92 printf("%s %s %s %s\n", t->sId, t->sIPv6, t->sIPv4, t->sPOPId);
95 tic_Free_sTunnel(hsTunnel);
96 tic_Logout(g_aiccu->tic, "Getting current tunnel listing");
97 return 1;
100 static unsigned int prevnum = 54321;
102 /* Due to broken DNS servers out there, make sure that we get at least the SixXS TIC server */
103 static bool foundsixxs = false;
105 void gotrr(unsigned int num, int type, const char *record);
106 void gotrr(unsigned int num, int type, const char *record)
108 /* Skip non-TXT records + Comments */
109 if (type != T_TXT || record[0] == '#') return;
110 /* If the record number changed and it is not the first one, add a return */
111 if (num != prevnum && prevnum != 54321) printf("\n");
113 /* The current record = the last one seen */
114 prevnum = num;
116 /* Print the component */
117 printf("%s|", record);
119 /* Found SixXS? */
120 if (strcmp(record, "SixXS") == 0) foundsixxs = true;
123 /* Get Tunnel Brokers from _aiccu.<search path> and from _aiccu.sixxs.net */
124 int list_brokers(void);
125 int list_brokers(void)
127 foundsixxs = false;
128 prevnum = 54321;
129 getrrs("_aiccu", T_TXT, gotrr);
130 prevnum = 54321;
131 getrrs("_aiccu.sixxs.net", T_TXT, gotrr);
132 printf("\n");
134 if (!foundsixxs)
136 printf("SixXS|tic://tic.sixxs.net|http://www.sixxs.net|be de ee fi gb ie it nl pl pt si se us");
138 /* Warn the user of the missing global tb's */
139 fprintf(stderr, "Warning: Couldn't find global Tunnel Brokers List, please check your DNS settings and read the FAQ.\n");
142 return 1;
146 * AICCU! - Aka... let's get connected ;)
147 * returns a TIC_Tunnel which can then be
148 * used for configuring and keeping it running
150 struct TIC_Tunnel *get_tunnel(void);
151 struct TIC_Tunnel *get_tunnel(void)
154 struct TIC_sTunnel *hsTunnel, *t;
155 struct TIC_Tunnel *hTunnel;
157 /* Login to the TIC Server */
158 if (!tic_Login(g_aiccu->tic, g_aiccu->username, g_aiccu->password, g_aiccu->server)) return NULL;
161 * Don't try to list the tunnels when
162 * we already have a tunnel_id configured
164 if (!g_aiccu->tunnel_id)
166 hsTunnel = tic_ListTunnels(g_aiccu->tic);
167 if (!hsTunnel)
169 dolog(LOG_ERR, "No tunnel available, request one first\n");
170 tic_Free_sTunnel(hsTunnel);
171 tic_Logout(g_aiccu->tic, "I didn't have any tunnels to select");
172 return NULL;
175 if (hsTunnel->next)
177 dolog(LOG_ERR, "Multiple tunnels available, please pick one from the following list and configure the aiccu.conf using it\n");
178 for (t = hsTunnel; t; t = t->next)
180 dolog(LOG_ERR, "%s %s %s %s\n", t->sId, t->sIPv6, t->sIPv4, t->sPOPId);
182 tic_Free_sTunnel(hsTunnel);
183 tic_Logout(g_aiccu->tic, "User still needed to select a tunnel");
184 return NULL;
186 g_aiccu->tunnel_id = strdup(hsTunnel->sId);
188 /* Free the info */
189 tic_Free_sTunnel(hsTunnel);
192 /* Get Tunnel Information */
193 hTunnel = tic_GetTunnel(g_aiccu->tic, g_aiccu->tunnel_id);
194 if (!hTunnel)
196 tic_Logout(g_aiccu->tic, "No such tunnel");
197 return NULL;
200 /* Logout, TIC is not needed any more */
201 tic_Logout(g_aiccu->tic, NULL);
203 /* Swee.... sufficient information */
204 return hTunnel;
207 enum AICCU_MODES
209 A_NONE = 0,
210 A_START,
211 A_STOP,
212 A_BROKERS,
213 A_TUNNELS,
214 A_TEST,
215 A_AUTOTEST,
216 A_LICENSE,
217 #ifdef _WIN32
218 A_LISTTAPS,
219 #endif
220 A_VERSION
223 const char *options = "aiccu (start|stop|brokers|tunnels|test|autotest|license|"
224 #ifdef _WIN32
225 "listtaps|"
226 #endif
227 "version) [<configfile>]\n";
229 int main(int argc, char *argv[])
231 enum AICCU_MODES mode = A_NONE;
233 struct TIC_Tunnel *hTunnel;
234 #ifdef _WIN32
235 WSADATA wsadata;
236 unsigned int i;
238 /* Initialize Winsock so that we can do network functions */
239 WSAStartup(WINSOCK_VERSION, &wsadata);
240 #endif
242 /* Initialize Configuration */
243 aiccu_InitConfig();
245 /* Make sure we actually have an IPv6 stack */
246 aiccu_install();
248 /* Require start/stop/test */
249 if (argc == 2 || argc == 3)
251 if (strcasecmp(argv[1], "start") == 0) mode = A_START;
252 else if (strcasecmp(argv[1], "stop") == 0) mode = A_STOP;
253 else if (strcasecmp(argv[1], "brokers") == 0) mode = A_BROKERS;
254 else if (strcasecmp(argv[1], "tunnels") == 0) mode = A_TUNNELS;
255 else if (strcasecmp(argv[1], "test") == 0) mode = A_TEST;
256 else if (strcasecmp(argv[1], "autotest")== 0) mode = A_AUTOTEST;
257 else if (strcasecmp(argv[1], "license") == 0) mode = A_LICENSE;
258 #ifdef _WIN32
259 else if (strcasecmp(argv[1], "listtaps") == 0) mode = A_LISTTAPS;
260 #endif
261 else if (strcasecmp(argv[1], "version") == 0) mode = A_VERSION;
264 /* Optionally we want a second argument: a config file */
265 if (( argc != 2 &&
266 argc != 3) ||
267 mode == A_NONE)
269 dolog(LOG_ERR, "%s", options);
270 return -1;
273 if ( mode == A_LICENSE)
275 printf("%s\n", aiccu_license());
276 return 0;
279 if ( mode == A_VERSION)
281 printf("AICCU %s by Jeroen Massar\n", AICCU_VERSION);
282 return 0;
285 #ifdef _WIN32
286 if ( mode == A_LISTTAPS)
288 tun_list_tap_adapters();
289 return 0;
291 #endif
293 if ( mode == A_BROKERS)
295 int ret = list_brokers();
296 aiccu_FreeConfig();
297 return ret == 0 ? -1 : 0;
300 if (!aiccu_LoadConfig(argc <= 2 ? NULL : argv[2]))
302 return -1;
305 #ifndef _WIN32
306 /* start or stop? */
307 if ( mode != A_TEST &&
308 mode != A_AUTOTEST)
310 /* Already running? */
311 if (sigrunning(mode == A_STOP ? SIGTERM : 0) == 1)
313 dolog(LOG_ERR, "Already running instance HUP'ed, exiting\n");
314 return 0;
317 #endif
319 /* Verify required parameters */
320 if (!g_aiccu->username || !g_aiccu->password)
322 dolog(LOG_ERR, "Required parameters missing, make sure that username and password are given\n");
323 aiccu_FreeConfig();
324 return -1;
327 if (mode == A_TUNNELS)
329 int ret = list_tunnels();
330 aiccu_FreeConfig();
331 return ret == 0 ? -1 : 0;
334 /* Get our tunnel */
335 hTunnel = get_tunnel();
337 if (!hTunnel)
339 dolog(LOG_ERR, "Couldn't retrieve first tunnel for the above reason, aborting\n");
340 aiccu_FreeConfig();
341 return -1;
345 * We now have sufficient information.
346 * Thus we can logout from the TIC server
348 tic_Logout(g_aiccu->tic, NULL);
349 g_aiccu->tic = NULL;
351 if (g_aiccu->verbose)
353 printf("Tunnel Information for %s:\n",hTunnel->sId);
354 printf("POP Id : %s\n", hTunnel->sPOP_Id);
355 printf("IPv6 Local : %s/%u\n", hTunnel->sIPv6_Local,hTunnel->nIPv6_PrefixLength);
356 printf("IPv6 Remote : %s/%u\n", hTunnel->sIPv6_POP,hTunnel->nIPv6_PrefixLength);
357 printf("Tunnel Type : %s\n", hTunnel->sType);
358 printf("Adminstate : %s\n", hTunnel->sAdminState);
359 printf("Userstate : %s\n", hTunnel->sUserState);
362 /* One can always try to stop it */
363 if (mode == A_STOP)
365 aiccu_delete(hTunnel);
367 /* Free stuff and exit */
368 tic_Free_Tunnel(hTunnel);
369 aiccu_FreeConfig();
370 return 0;
373 if ( (strcmp(hTunnel->sAdminState, "enabled") != 0) ||
374 (strcmp(hTunnel->sUserState, "enabled") != 0))
376 dolog(LOG_ERR, "Tunnel is not enabled (UserState: %s, AdminState: %s)\n", hTunnel->sAdminState, hTunnel->sUserState);
377 return -1;
380 /* Do the test thing */
381 if ( mode == A_TEST ||
382 mode == A_AUTOTEST)
384 #ifdef _WIN32
385 SetConsoleCtrlHandler((PHANDLER_ROUTINE)sigterm_testing, true);
386 #endif
387 /* Setup the tunnel */
388 if (aiccu_setup(hTunnel, true))
390 aiccu_test(hTunnel, strcasecmp(argv[1], "autotest") == 0 ? true : false);
392 /* Tear the tunnel down again */
393 aiccu_delete(hTunnel);
395 else
397 dolog(LOG_ERR, "Tunnel Setup Failed\n");
400 /* exit as all is done */
401 tic_Free_Tunnel(hTunnel);
402 aiccu_FreeConfig();
403 return 0;
406 #ifndef _WIN32
407 if ( mode == A_START &&
408 g_aiccu->daemonize != 0)
410 FILE *f;
412 /* Daemonize */
413 int i = fork();
414 if (i < 0)
416 fprintf(stderr, "Couldn't fork\n");
417 return -1;
419 /* Exit the mother fork */
420 if (i != 0) return 0;
422 /* Child fork */
423 setsid();
425 /* Chdir to minimise disruption to FS umounts */
426 (void)chdir("/");
428 /* Cleanup stdin/out/err */
429 freopen("/dev/null","r",stdin);
430 freopen("/dev/null","w",stdout);
431 freopen("/dev/null","w",stderr);
433 /* */
434 f = fopen(g_aiccu->pidfile, "w");
435 if (!f)
437 dolog(LOG_ERR, "Could not store PID in file %s\n", g_aiccu->pidfile);
438 return 0;
441 fprintf(f, "%d", getpid());
442 fclose(f);
444 dolog(LOG_INFO, "AICCU running as PID %d\n", getpid());
447 #endif /* !_WIN32 */
449 /* mode == A_START */
451 #ifndef _WIN32
453 * Install a signal handler so that
454 * one can disable beating with SIGUSR1
456 signal(SIGUSR1, &sigusr1);
459 * Install a signal handler so that
460 * one can stop this program with SIGTERM
462 signal(SIGTERM, &sigterm);
463 signal(SIGINT, &sigterm);
464 #else
465 SetConsoleCtrlHandler((PHANDLER_ROUTINE)sigterm, true);
466 #endif
469 * Setup our tunnel
470 * This also spawns required threads for AYIYA
472 if (aiccu_setup(hTunnel, true))
474 /* We need to stay running when doing Heartbeat or AYIYA */
475 if ( strcasecmp(hTunnel->sType, "6in4-heartbeat") == 0 ||
476 strcasecmp(hTunnel->sType, "ayiya") == 0)
478 /* We are spawned, now just beat once in a while. */
479 while (g_aiccu->running)
481 aiccu_beat(hTunnel);
482 #ifndef _WIN32
483 sleep(hTunnel->nHeartbeat_Interval);
484 #else
485 for (i=0; g_aiccu->running && i <= hTunnel->nHeartbeat_Interval; i++) Sleep(1000);
486 #endif
489 /* Clean up the the tunnel, no beat anyway */
490 aiccu_delete(hTunnel);
493 #ifndef _WIN32
494 /* Remove our PID file */
495 if (g_aiccu) unlink(g_aiccu->pidfile);
496 #endif
499 /* Free our resources */
500 aiccu_FreeConfig();
502 return 0;