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 ***********************************************************
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"
17 /* Enable/Disable heartbeating */
22 g_aiccu
->makebeats
= !g_aiccu
->makebeats
;
24 /* Reset the signal */
31 g_aiccu
->running
= false;
35 int sigrunning(int sig
);
36 int sigrunning(int sig
)
41 if (!g_aiccu
) return 0;
43 /* Open our PID file */
44 f
= fopen(g_aiccu
->pidfile
, "r");
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 */
53 /* If we can HUP it, it still runs */
54 return (pid
> 0 && kill(pid
, sig
) == 0 ? 1 : 0);
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;
66 static BOOL
sigterm_testing(DWORD sig
);
67 static BOOL
sigterm_testing(DWORD sig
)
69 D(dolog(LOG_DEBUG
, "Ignoring CTRL event\n"));
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
);
86 tic_Logout(g_aiccu
->tic
, "Getting current tunnel listing");
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");
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 */
116 /* Print the component */
117 printf("%s|", record
);
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)
129 getrrs("_aiccu", T_TXT
, gotrr
);
131 getrrs("_aiccu.sixxs.net", T_TXT
, gotrr
);
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");
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
);
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");
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");
186 g_aiccu
->tunnel_id
= strdup(hsTunnel
->sId
);
189 tic_Free_sTunnel(hsTunnel
);
192 /* Get Tunnel Information */
193 hTunnel
= tic_GetTunnel(g_aiccu
->tic
, g_aiccu
->tunnel_id
);
196 tic_Logout(g_aiccu
->tic
, "No such tunnel");
200 /* Logout, TIC is not needed any more */
201 tic_Logout(g_aiccu
->tic
, NULL
);
203 /* Swee.... sufficient information */
223 const char *options
= "aiccu (start|stop|brokers|tunnels|test|autotest|license|"
227 "version) [<configfile>]\n";
229 int main(int argc
, char *argv
[])
231 enum AICCU_MODES mode
= A_NONE
;
233 struct TIC_Tunnel
*hTunnel
;
238 /* Initialize Winsock so that we can do network functions */
239 WSAStartup(WINSOCK_VERSION
, &wsadata
);
242 /* Initialize Configuration */
245 /* Make sure we actually have an IPv6 stack */
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
;
259 else if (strcasecmp(argv
[1], "listtaps") == 0) mode
= A_LISTTAPS
;
261 else if (strcasecmp(argv
[1], "version") == 0) mode
= A_VERSION
;
264 /* Optionally we want a second argument: a config file */
269 dolog(LOG_ERR
, "%s", options
);
273 if ( mode
== A_LICENSE
)
275 printf("%s\n", aiccu_license());
279 if ( mode
== A_VERSION
)
281 printf("AICCU %s by Jeroen Massar\n", AICCU_VERSION
);
286 if ( mode
== A_LISTTAPS
)
288 tun_list_tap_adapters();
293 if ( mode
== A_BROKERS
)
295 int ret
= list_brokers();
297 return ret
== 0 ? -1 : 0;
300 if (!aiccu_LoadConfig(argc
<= 2 ? NULL
: argv
[2]))
307 if ( mode
!= A_TEST
&&
310 /* Already running? */
311 if (sigrunning(mode
== A_STOP
? SIGTERM
: 0) == 1)
313 dolog(LOG_ERR
, "Already running instance HUP'ed, exiting\n");
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");
327 if (mode
== A_TUNNELS
)
329 int ret
= list_tunnels();
331 return ret
== 0 ? -1 : 0;
335 hTunnel
= get_tunnel();
339 dolog(LOG_ERR
, "Couldn't retrieve first tunnel for the above reason, aborting\n");
345 * We now have sufficient information.
346 * Thus we can logout from the TIC server
348 tic_Logout(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 */
365 aiccu_delete(hTunnel
);
367 /* Free stuff and exit */
368 tic_Free_Tunnel(hTunnel
);
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
);
380 /* Do the test thing */
381 if ( mode
== A_TEST
||
385 SetConsoleCtrlHandler((PHANDLER_ROUTINE
)sigterm_testing
, true);
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
);
397 dolog(LOG_ERR
, "Tunnel Setup Failed\n");
400 /* exit as all is done */
401 tic_Free_Tunnel(hTunnel
);
407 if ( mode
== A_START
&&
408 g_aiccu
->daemonize
!= 0)
416 fprintf(stderr
, "Couldn't fork\n");
419 /* Exit the mother fork */
420 if (i
!= 0) return 0;
425 /* Chdir to minimise disruption to FS umounts */
428 /* Cleanup stdin/out/err */
429 freopen("/dev/null","r",stdin
);
430 freopen("/dev/null","w",stdout
);
431 freopen("/dev/null","w",stderr
);
434 f
= fopen(g_aiccu
->pidfile
, "w");
437 dolog(LOG_ERR
, "Could not store PID in file %s\n", g_aiccu
->pidfile
);
441 fprintf(f
, "%d", getpid());
444 dolog(LOG_INFO
, "AICCU running as PID %d\n", getpid());
449 /* mode == A_START */
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
);
465 SetConsoleCtrlHandler((PHANDLER_ROUTINE
)sigterm
, true);
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
)
483 sleep(hTunnel
->nHeartbeat_Interval
);
485 for (i
=0; g_aiccu
->running
&& i
<= hTunnel
->nHeartbeat_Interval
; i
++) Sleep(1000);
489 /* Clean up the the tunnel, no beat anyway */
490 aiccu_delete(hTunnel
);
494 /* Remove our PID file */
495 if (g_aiccu
) unlink(g_aiccu
->pidfile
);
499 /* Free our resources */