]> git.ipfire.org Git - people/stevee/aiccu.git/blob - unix-console/main.c
binutils gold
[people/stevee/aiccu.git] / unix-console / main.c
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 **********************************************************/
12
13 #include "../common/aiccu.h"
14 #include "../common/tun.h"
15
16 #ifndef _WIN32
17 /* Enable/Disable heartbeating */
18 void sigusr1(int i);
19 void sigusr1(int i)
20 {
21 /* Toggle the flag */
22 g_aiccu->makebeats = !g_aiccu->makebeats;
23
24 /* Reset the signal */
25 signal(i, &sigusr1);
26 }
27
28 void sigterm(int i);
29 void sigterm(int i)
30 {
31 g_aiccu->running = false;
32 signal(i, SIG_IGN);
33 }
34
35 int sigrunning(int sig);
36 int sigrunning(int sig)
37 {
38 int pid;
39 FILE *f;
40
41 if (!g_aiccu) return 0;
42
43 /* Open our PID file */
44 f = fopen(g_aiccu->pidfile, "r");
45 if (!f) return 0;
46
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;
49
50 /* Close the file again */
51 fclose(f);
52
53 /* If we can signal it, it still runs */
54 return (pid > 0 && kill(pid, sig) == 0 ? 1 : 0);
55 }
56
57 #else
58
59 static BOOL sigterm(DWORD sig);
60 static BOOL sigterm(DWORD sig)
61 {
62 D(dolog(LOG_DEBUG, "Terminating due to CTRL event\n"));
63 g_aiccu->running = false;
64 return true;
65 }
66 static BOOL sigterm_testing(DWORD sig);
67 static BOOL sigterm_testing(DWORD sig)
68 {
69 D(dolog(LOG_DEBUG, "Ignoring CTRL event\n"));
70 return true;
71 }
72
73 #endif
74
75 int list_tunnels(void);
76 int list_tunnels(void)
77 {
78 struct TIC_sTunnel *hsTunnel, *t;
79
80 if (!tic_Login(g_aiccu->tic, g_aiccu->username, g_aiccu->password, g_aiccu->server)) return 0;
81
82 hsTunnel = tic_ListTunnels(g_aiccu->tic);
83
84 if (!hsTunnel)
85 {
86 tic_Logout(g_aiccu->tic, "Getting current tunnel listing");
87 return 1;
88 }
89
90 for (t = hsTunnel; t; t = t->next)
91 {
92 printf("%s %s %s %s\n", t->sId, t->sIPv6, t->sIPv4, t->sPOPId);
93 }
94
95 tic_Free_sTunnel(hsTunnel);
96 tic_Logout(g_aiccu->tic, "Getting current tunnel listing");
97 return 1;
98 }
99
100 static unsigned int prevnum = 54321;
101
102 /* Due to broken DNS servers out there, make sure that we get at least the SixXS TIC server */
103 static bool foundsixxs = false;
104
105 void gotrr(unsigned int num, int type, const char *record);
106 void gotrr(unsigned int num, int type, const char *record)
107 {
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");
112
113 /* The current record = the last one seen */
114 prevnum = num;
115
116 /* Print the component */
117 printf("%s|", record);
118
119 /* Found SixXS? */
120 if (strcmp(record, "SixXS") == 0) foundsixxs = true;
121 }
122
123 /* Get Tunnel Brokers from _aiccu.<search path> and from _aiccu.sixxs.net */
124 int list_brokers(void);
125 int list_brokers(void)
126 {
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");
133
134 if (!foundsixxs)
135 {
136 printf("SixXS|tic://tic.sixxs.net|http://www.sixxs.net|be de ee fi gb ie it nl pl pt si se us");
137
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");
140 }
141
142 return 1;
143 }
144
145 /*
146 * AICCU! - Aka... let's get connected ;)
147 * returns a TIC_Tunnel which can then be
148 * used for configuring and keeping it running
149 */
150 struct TIC_Tunnel *get_tunnel(void);
151 struct TIC_Tunnel *get_tunnel(void)
152 {
153
154 struct TIC_sTunnel *hsTunnel, *t;
155 struct TIC_Tunnel *hTunnel;
156
157 /* Login to the TIC Server */
158 if (!tic_Login(g_aiccu->tic, g_aiccu->username, g_aiccu->password, g_aiccu->server)) return NULL;
159
160 /*
161 * Don't try to list the tunnels when
162 * we already have a tunnel_id configured
163 */
164 if (!g_aiccu->tunnel_id)
165 {
166 hsTunnel = tic_ListTunnels(g_aiccu->tic);
167 if (!hsTunnel)
168 {
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;
173 }
174
175 if (hsTunnel->next)
176 {
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)
179 {
180 dolog(LOG_ERR, "%s %s %s %s\n", t->sId, t->sIPv6, t->sIPv4, t->sPOPId);
181 }
182 tic_Free_sTunnel(hsTunnel);
183 tic_Logout(g_aiccu->tic, "User still needed to select a tunnel");
184 return NULL;
185 }
186 g_aiccu->tunnel_id = strdup(hsTunnel->sId);
187
188 /* Free the info */
189 tic_Free_sTunnel(hsTunnel);
190 }
191
192 /* Get Tunnel Information */
193 hTunnel = tic_GetTunnel(g_aiccu->tic, g_aiccu->tunnel_id);
194 if (!hTunnel)
195 {
196 tic_Logout(g_aiccu->tic, "No such tunnel");
197 return NULL;
198 }
199
200 /* Logout, TIC is not needed any more */
201 tic_Logout(g_aiccu->tic, NULL);
202
203 /* Swee.... sufficient information */
204 return hTunnel;
205 }
206
207 enum AICCU_MODES
208 {
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
221 };
222
223 const char *options = "aiccu (start|stop|brokers|tunnels|test|autotest|license|"
224 #ifdef _WIN32
225 "listtaps|"
226 #endif
227 "version) [<configfile>]\n";
228
229 int main(int argc, char *argv[])
230 {
231 enum AICCU_MODES mode = A_NONE;
232
233 struct TIC_Tunnel *hTunnel;
234 #ifdef _WIN32
235 WSADATA wsadata;
236 unsigned int i;
237
238 /* Initialize Winsock so that we can do network functions */
239 WSAStartup(WINSOCK_VERSION, &wsadata);
240 #endif
241
242 /* Initialize Configuration */
243 aiccu_InitConfig();
244
245 /* Make sure we actually have an IPv6 stack */
246 aiccu_install();
247
248 /* Require start/stop/test */
249 if (argc == 2 || argc == 3)
250 {
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;
262 }
263
264 /* Optionally we want a second argument: a config file */
265 if (( argc != 2 &&
266 argc != 3) ||
267 mode == A_NONE)
268 {
269 dolog(LOG_ERR, "%s", options);
270 return -1;
271 }
272
273 if ( mode == A_LICENSE)
274 {
275 printf("%s\n", aiccu_license());
276 return 0;
277 }
278
279 if ( mode == A_VERSION)
280 {
281 printf("AICCU %s by Jeroen Massar\n", AICCU_VERSION);
282 return 0;
283 }
284
285 #ifdef _WIN32
286 if ( mode == A_LISTTAPS)
287 {
288 tun_list_tap_adapters();
289 return 0;
290 }
291 #endif
292
293 if ( mode == A_BROKERS)
294 {
295 int ret = list_brokers();
296 aiccu_FreeConfig();
297 return ret == 0 ? -1 : 0;
298 }
299
300 if (!aiccu_LoadConfig(argc <= 2 ? NULL : argv[2]))
301 {
302 return -1;
303 }
304
305 /* Verify required parameters */
306 if (!g_aiccu->username || !g_aiccu->password)
307 {
308 dolog(LOG_ERR, "Required parameters missing, make sure that username and password are given\n");
309 aiccu_FreeConfig();
310 return -1;
311 }
312
313 if (mode == A_TUNNELS)
314 {
315 int ret = list_tunnels();
316 aiccu_FreeConfig();
317 return ret == 0 ? -1 : 0;
318 }
319
320 #ifndef _WIN32
321 /* start or stop? */
322 if ( mode != A_TEST &&
323 mode != A_AUTOTEST)
324 {
325 /* Already running? */
326 if (sigrunning(mode == A_STOP ? SIGTERM : 0) == 1)
327 {
328 dolog(LOG_ERR, "Already running instance signaled, exiting\n");
329 return 0;
330 }
331 }
332 #endif
333
334 /* Get our tunnel */
335 hTunnel = get_tunnel();
336
337 if (!hTunnel)
338 {
339 dolog(LOG_ERR, "Couldn't retrieve first tunnel for the above reason, aborting\n");
340 aiccu_FreeConfig();
341 return -1;
342 }
343
344 /*
345 * We now have sufficient information.
346 * Thus we can logout from the TIC server
347 */
348 tic_Logout(g_aiccu->tic, NULL);
349 g_aiccu->tic = NULL;
350
351 if (g_aiccu->verbose)
352 {
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);
360 }
361
362 /* One can always try to stop it */
363 if (mode == A_STOP)
364 {
365 aiccu_delete(hTunnel);
366
367 /* Free stuff and exit */
368 tic_Free_Tunnel(hTunnel);
369 aiccu_FreeConfig();
370 return 0;
371 }
372
373 if ( (strcmp(hTunnel->sAdminState, "enabled") != 0) ||
374 (strcmp(hTunnel->sUserState, "enabled") != 0))
375 {
376 dolog(LOG_ERR, "Tunnel is not enabled (UserState: %s, AdminState: %s)\n", hTunnel->sAdminState, hTunnel->sUserState);
377 return -1;
378 }
379
380 /* Do the test thing */
381 if ( mode == A_TEST ||
382 mode == A_AUTOTEST)
383 {
384 #ifdef _WIN32
385 SetConsoleCtrlHandler((PHANDLER_ROUTINE)sigterm_testing, true);
386 #endif
387 /* Setup the tunnel */
388 if (aiccu_setup(hTunnel, true))
389 {
390 aiccu_test(hTunnel, strcasecmp(argv[1], "autotest") == 0 ? true : false);
391
392 /* Tear the tunnel down again */
393 aiccu_delete(hTunnel);
394 }
395 else
396 {
397 dolog(LOG_ERR, "Tunnel Setup Failed\n");
398 }
399
400 /* exit as all is done */
401 tic_Free_Tunnel(hTunnel);
402 aiccu_FreeConfig();
403 return 0;
404 }
405
406 #ifndef _WIN32
407 if ( mode == A_START &&
408 g_aiccu->daemonize != 0)
409 {
410 FILE *f;
411
412 /* Daemonize */
413 int i = fork();
414 if (i < 0)
415 {
416 fprintf(stderr, "Couldn't fork\n");
417 return -1;
418 }
419 /* Exit the mother fork */
420 if (i != 0) return 0;
421
422 /* Child fork */
423 setsid();
424
425 /* Chdir to minimise disruption to FS umounts */
426 (void)chdir("/");
427
428 /* Cleanup stdin/out/err */
429 freopen("/dev/null","r",stdin);
430 freopen("/dev/null","w",stdout);
431 freopen("/dev/null","w",stderr);
432
433 /* */
434 f = fopen(g_aiccu->pidfile, "w");
435 if (!f)
436 {
437 dolog(LOG_ERR, "Could not store PID in file %s\n", g_aiccu->pidfile);
438 return 0;
439 }
440
441 fprintf(f, "%d", getpid());
442 fclose(f);
443
444 dolog(LOG_INFO, "AICCU running as PID %d\n", getpid());
445 }
446
447 #endif /* !_WIN32 */
448
449 /* mode == A_START */
450
451 #ifndef _WIN32
452 /*
453 * Install a signal handler so that
454 * one can disable beating with SIGUSR1
455 */
456 signal(SIGUSR1, &sigusr1);
457
458 /*
459 * Install a signal handler so that
460 * one can stop this program with SIGTERM
461 */
462 signal(SIGTERM, &sigterm);
463 signal(SIGINT, &sigterm);
464 #else
465 SetConsoleCtrlHandler((PHANDLER_ROUTINE)sigterm, true);
466 #endif
467
468 /*
469 * Setup our tunnel
470 * This also spawns required threads for AYIYA
471 */
472 if (aiccu_setup(hTunnel, true))
473 {
474 if (g_aiccu->setupscript)
475 {
476 aiccu_exec("%s", g_aiccu->setupscript);
477 }
478
479 /* We need to stay running when doing Heartbeat or AYIYA */
480 if ( strcasecmp(hTunnel->sType, "6in4-heartbeat") == 0 ||
481 strcasecmp(hTunnel->sType, "ayiya") == 0)
482 {
483 /* We are spawned, now just beat once in a while. */
484 while (g_aiccu->running)
485 {
486 aiccu_beat(hTunnel);
487 #ifndef _WIN32
488 sleep(hTunnel->nHeartbeat_Interval);
489 #else
490 for (i=0; g_aiccu->running && i <= hTunnel->nHeartbeat_Interval; i++) Sleep(1000);
491 #endif
492 }
493
494 /* Clean up the the tunnel, no beat anyway */
495 aiccu_delete(hTunnel);
496 }
497
498 #ifndef _WIN32
499 /* Remove our PID file */
500 if (g_aiccu) unlink(g_aiccu->pidfile);
501 #endif
502 }
503
504 /* Free our resources */
505 aiccu_FreeConfig();
506
507 return 0;
508 }
509