2 * Layer Two Tunnelling Protocol Daemon Control Utility
3 * Copyright (C) 2011 Alexander Dorokhov
5 * This software is distributed under the terms
6 * of the GPL, which you should have received
7 * along with this source.
9 * xl2tpd-control client main file
18 #include <sys/types.h>
24 /* Paul: Alex: can we change this to use stdout, and let applications using
25 * xl2tpd-control capture the output, instead of creating tmp files?
27 /* result filename format including absolute path and formatting %i for pid */
28 #define RESULT_FILENAME_FORMAT "/var/run/xl2tpd/xl2tpd-control-%i.out"
33 int log_level
= ERROR_LEVEL
;
35 void print_error (int level
, const char *fmt
, ...);
37 int read_result(int result_fd
, char* buf
, ssize_t size
);
39 /* Definition of a command */
43 int (*handler
) (FILE*, char* tunnel
, int optc
, char *optv
[]);
46 int command_add (FILE*, char* tunnel
, int optc
, char *optv
[]);
47 int command_connect (FILE*, char* tunnel
, int optc
, char *optv
[]);
48 int command_disconnect (FILE*, char* tunnel
, int optc
, char *optv
[]);
49 int command_remove (FILE*, char* tunnel
, int optc
, char *optv
[]);
51 struct command_t commands
[] = {
52 {"add", &command_add
},
53 {"connect", &command_connect
},
54 {"disconnect", &command_disconnect
},
55 {"remove", &command_remove
},
61 printf ("\nxl2tpd server version %s\n", SERVER_VERSION
);
62 printf ("Usage: xl2tpd-control [-c <PATH>] <command> <tunnel name> [<COMMAND OPTIONS>]\n"
64 " -c\tspecifies xl2tpd control file\n"
65 " -d\tspecify xl2tpd-control to run in debug mode\n"
66 "--help\tshows extended help\n"
67 "Available commands: add, connect, disconnect, remove\n"
77 "\tadd\tadds new or modify existing lac configuration.\n"
78 "\t\tConfiguration must be specified as command options in\n"
79 "\t\t<key>=<value> pairs format.\n"
80 "\t\tSee available options in xl2tpd.conf(5)\n"
81 "\tconnect\ttries to activate the tunnel.\n"
82 "\t\tUsername and secret for the tunnel can be passed as\n"
83 "\t\tcommand options.\n"
84 "\tdisconnect\tdisconnects the tunnel.\n"
85 "\tremove\tremoves lac configuration from xl2tpd.\n"
86 "\t\txl2tpd disconnects the tunnel before removing.\n"
88 "See xl2tpd-control man page for more help\n"
92 int main (int argc
, char *argv
[])
94 char* control_filename
= NULL
;
95 char* tunnel_name
= NULL
;
96 struct command_t
* command
= NULL
;
97 int i
; /* argv iterator */
99 if (!strncmp (argv
[1], "--help", 6))
104 /* parse global options */
105 for (i
= 1; i
< argc
; i
++)
108 if (!strncmp (argv
[i
], "-c", 2))
110 control_filename
= argv
[++i
];
111 } else if (!strncmp (argv
[i
], "-d", 2)) {
112 log_level
= DEBUG_LEVEL
;
119 print_error (ERROR_LEVEL
, "error: command not specified\n");
123 if (!control_filename
)
125 control_filename
= strdup (CONTROL_PIPE
);
127 print_error (DEBUG_LEVEL
, "set control filename to %s\n", control_filename
);
129 /* parse command name */
130 for (command
= commands
; command
->name
; command
++)
132 if (!strcasecmp (argv
[i
], command
->name
))
141 print_error (DEBUG_LEVEL
, "get command %s\n", command
->name
);
143 print_error (ERROR_LEVEL
, "error: no such command %s\n", argv
[i
]);
147 /* get tunnel name */
150 print_error (ERROR_LEVEL
, "error: tunnel name not specified\n");
154 tunnel_name
= argv
[i
++];
155 /* check tunnel name for whitespaces */
156 if (strstr (tunnel_name
, " "))
158 print_error (ERROR_LEVEL
,
159 "error: tunnel name shouldn't include spaces\n");
164 char buf
[CONTROL_PIPE_MESSAGE_SIZE
] = "";
165 FILE* mesf
= fmemopen (buf
, CONTROL_PIPE_MESSAGE_SIZE
, "w");
167 /* create result pipe for reading */
168 char result_filename
[128];
169 snprintf (result_filename
, 128, RESULT_FILENAME_FORMAT
, getpid());
170 unlink (result_filename
);
171 mkfifo (result_filename
, 0600);
172 int result_fd
= open (result_filename
, O_RDONLY
| O_NONBLOCK
, 0600);
175 print_error (ERROR_LEVEL
,
176 "error: unable to open %s for reading.\n", result_filename
);
180 /* turn off O_NONBLOCK */
181 if (fcntl (result_fd
, F_SETFL
, O_RDONLY
) == -1) {
182 print_error (ERROR_LEVEL
,
183 "Can not turn off nonblocking mode for result_fd: %s\n",
188 /* pass result filename to command */
189 fprintf (mesf
, "@%s ", result_filename
);
192 print_error (ERROR_LEVEL
, "internal error: message buffer to short");
196 /* format command with remaining arguments */
197 int command_res
= command
->handler (
198 mesf
, tunnel_name
, argc
- i
, argv
+ i
202 print_error (ERROR_LEVEL
, "error: command parse error\n");
210 print_error (ERROR_LEVEL
,
211 "error: message too long (max = %i ch.)\n",
212 CONTROL_PIPE_MESSAGE_SIZE
- 1);
216 print_error (DEBUG_LEVEL
, "command to be passed:\n%s\n", buf
);
218 /* try to open control file for writing */
219 int control_fd
= open (control_filename
, O_WRONLY
, 0600);
226 print_error (ERROR_LEVEL
,
227 "Unable to open %s for writing."
228 " Is xl2tpd running and you have appropriate permissions?\n",
232 print_error (ERROR_LEVEL
,
233 "Unable to open %s for writing: %s\n",
234 control_filename
, strerror (errorno
));
239 /* pass command to control pipe */
240 write (control_fd
, buf
, ftell (mesf
));
243 /* read result from pipe */
244 char rbuf
[CONTROL_PIPE_MESSAGE_SIZE
] = "";
245 int command_result_code
= read_result (
246 result_fd
, rbuf
, CONTROL_PIPE_MESSAGE_SIZE
253 unlink (result_filename
);
255 return command_result_code
;
258 void print_error (int level
, const char *fmt
, ...)
260 if (level
> log_level
) return;
262 va_start (args
, fmt
);
263 vfprintf (stderr
, fmt
, args
);
267 int read_result(int result_fd
, char* buf
, ssize_t size
)
269 /* read result from result_fd */
270 /*FIXME: there is a chance to hang up reading.
271 Should I create watching thread with timeout?
276 readed
= read (result_fd
, buf
, size
);
279 print_error (ERROR_LEVEL
,
280 "error: can't read command result: %s\n", strerror (errno
));
283 } while (readed
== 0);
286 /* scan result code */
287 int command_result_code
= -3;
288 sscanf (buf
, "%i", &command_result_code
);
290 return command_result_code
;
294 (FILE* mesf
, char* tunnel
, int optc
, char *optv
[])
298 print_error (ERROR_LEVEL
, "error: tunnel configuration expected\n");
301 fprintf (mesf
, "a %s ", tunnel
);
304 for (i
= 0; i
< optc
; i
++)
306 fprintf (mesf
, "%s", optv
[i
]);
309 /* try to find '=' */
310 char* eqv
= strstr (optv
[i
], "=");
313 /* check is it not last symbol */
314 if (eqv
!= (optv
[i
] + strlen(optv
[i
]) - 1))
316 fprintf (mesf
, ";"); /* end up option */
318 wait_key
= 0; /* now we waiting for value */
320 } else { /* two-word key */
321 fprintf (mesf
, " "); /* restore space */
324 fprintf (mesf
, ";"); /* end up option */
325 wait_key
= 1; /* now we again waiting for key */
332 (FILE* mesf
, char* tunnel
, int optc
, char *optv
[])
334 fprintf (mesf
, "c %s", tunnel
);
335 /* try to read authname and password from opts */
338 fprintf (mesf
, " %s", optv
[0]);
340 fprintf (mesf
, " %s %s", optv
[0], optv
[1]);
345 int command_disconnect
346 (FILE* mesf
, char* tunnel
, int optc
, char *optv
[])
348 fprintf (mesf
, "d %s", tunnel
);
353 (FILE* mesf
, char* tunnel
, int optc
, char *optv
[])
355 fprintf (mesf
, "r %s", tunnel
);