1 /***********************************************************************
5 * Simple (VERY simple) command-processor for the L2TP daemon.
7 * Copyright (C) 2002 Roaring Penguin Software Inc.
9 * This software may be distributed under the terms of the GNU General
10 * Public License, Version 2, or (at your option) any later version.
14 ***********************************************************************/
16 static char const RCSID
[] =
17 "$Id: cmd.c,v 1.1.48.1 2005/08/08 12:05:25 honor Exp $";
21 #include "event_tcp.h"
24 #include <sys/socket.h>
34 #define HANDLER_NAME "cmd"
36 static int process_option(EventSelector
*, char const *, char const *);
37 static void cmd_acceptor(EventSelector
*es
, int fd
);
38 static void cmd_handler(EventSelector
*es
,
39 int fd
, char *buf
, int len
, int flag
, void *data
);
42 static void cmd_exit(EventSelector
*es
, int fd
);
43 static void cmd_start_session(EventSelector
*es
, int fd
, char *buf
);
44 static void cmd_stop_session(EventSelector
*es
, int fd
, char *buf
);
45 static void cmd_dump_sessions(EventSelector
*es
, int fd
, char *buf
);
46 static void cmd_reply(EventSelector
*es
, int fd
, char const *msg
);
48 static option_handler my_option_handler
= {
49 NULL
, HANDLER_NAME
, process_option
52 /* Socket name for commands */
53 static char const *sockname
= NULL
;
55 static l2tp_opt_descriptor my_opts
[] = {
56 { "socket-path", OPT_TYPE_STRING
, &sockname
},
57 { NULL
, OPT_TYPE_BOOL
, NULL
}
61 /**********************************************************************
62 * %FUNCTION: describe_session
64 * ses -- an L2TP session
65 * str -- a dynamic string to which description is appended
69 * Dumps session description into str
70 ***********************************************************************/
72 describe_session(l2tp_session
*ses
,
77 sprintf(buf
, "Session %s MyID %d AssignedID %d",
78 (ses
->we_are_lac
? "LAC" : "LNS"),
79 (int) ses
->my_id
, (int) ses
->assigned_id
);
80 dynstring_append(str
, buf
);
81 sprintf(buf
, " State %s\n",
82 l2tp_session_state_name(ses
));
83 dynstring_append(str
, buf
);
86 /**********************************************************************
87 * %FUNCTION: describe_tunnel
89 * tunnel -- an L2TP tunnel
90 * str -- a dynamic string to which description is appended
94 * Dumps tunnel description into str
95 ***********************************************************************/
97 describe_tunnel(l2tp_tunnel
*tunnel
,
104 sprintf(buf
, "Tunnel MyID %d AssignedID %d",
105 (int) tunnel
->my_id
, (int) tunnel
->assigned_id
);
106 dynstring_append(str
, buf
);
107 sprintf(buf
, " NumSessions %d", (int) hash_num_entries(&tunnel
->sessions_by_my_id
));
108 dynstring_append(str
, buf
);
109 sprintf(buf
, " PeerIP %s State %s\n", inet_ntoa(tunnel
->peer_addr
.sin_addr
),
110 l2tp_tunnel_state_name(tunnel
));
112 dynstring_append(str
, buf
);
114 /* Describe each session */
115 for (ses
= l2tp_tunnel_first_session(tunnel
, &cursor
);
117 ses
= l2tp_tunnel_next_session(tunnel
, &cursor
)) {
118 describe_session(ses
, str
);
122 /**********************************************************************
123 * %FUNCTION: handler_init
125 * es -- event selector
129 * Initializes the command processor's option handler. We do not
130 * actually start a command processor until last option has been parsed.
131 ***********************************************************************/
133 handler_init(EventSelector
*es
)
135 l2tp_option_register_section(&my_option_handler
);
138 /**********************************************************************
139 * %FUNCTION: process_option
141 * es -- event selector
142 * name, value -- name and value of option
144 * 0 on success; -1 on failure.
146 * Processes options. When last option has been processed, begins
148 ***********************************************************************/
150 process_option(EventSelector
*es
,
154 struct sockaddr_un addr
;
158 if (!strcmp(name
, "*begin*")) return 0;
159 if (strcmp(name
, "*end*")) {
160 return l2tp_option_set(es
, name
, value
, my_opts
);
163 /* We have hit the end of our options. Open command socket */
165 sockname
= "/var/run/l2tpctrl";
168 (void) remove(sockname
);
169 fd
= socket(AF_LOCAL
, SOCK_STREAM
, 0);
171 l2tp_set_errmsg("cmd: process_option: socket: %s", strerror(errno
));
175 memset(&addr
, 0, sizeof(addr
));
176 addr
.sun_family
= AF_LOCAL
;
177 strncpy(addr
.sun_path
, sockname
, sizeof(addr
.sun_path
) - 1);
180 if (bind(fd
, (struct sockaddr
*) &addr
, SUN_LEN(&addr
)) < 0) {
181 l2tp_set_errmsg("cmd: process_option: bind: %s", strerror(errno
));
185 (void) chmod(sockname
, 0600);
186 if (listen(fd
, 5) < 0) {
187 l2tp_set_errmsg("cmd: process_option: listen: %s", strerror(errno
));
193 signal(SIGPIPE
, SIG_IGN
);
195 /* Add an accept handler */
196 if (!EventTcp_CreateAcceptor(es
, fd
, cmd_acceptor
)) {
197 l2tp_set_errmsg("cmd: process_option: EventTcp_CreateAcceptor: %s", strerror(errno
));
204 /**********************************************************************
205 * %FUNCTION: cmd_acceptor
207 * es -- event selector
208 * fd -- file descriptor of accepted connection
212 * Accepts a control connection and sets up read event.
213 ***********************************************************************/
215 cmd_acceptor(EventSelector
*es
, int fd
)
217 EventTcp_ReadBuf(es
, fd
, 512, '\n', cmd_handler
, 5, NULL
);
220 /**********************************************************************
221 * %FUNCTION: cmd_handler
223 * es -- event selector
224 * fd -- file descriptor
225 * buf -- buffer which was read
226 * len -- length of data
232 * Processes a command from the user
233 ***********************************************************************/
235 cmd_handler(EventSelector
*es
,
244 if (flag
== EVENT_TCP_FLAG_IOERROR
|| flag
== EVENT_TCP_FLAG_TIMEOUT
) {
254 /* Chop off newline */
255 if (len
&& (buf
[len
-1] == '\n')) {
260 buf
= (char *) l2tp_chomp_word(buf
, word
);
262 if (!strcmp(word
, "exit")) {
264 } else if (!strcmp(word
, "start-session")) {
265 cmd_start_session(es
, fd
, buf
);
266 } else if (!strcmp(word
, "stop-session")) {
267 cmd_stop_session(es
, fd
, buf
);
268 } else if (!strcmp(word
, "dump-sessions")) {
269 cmd_dump_sessions(es
, fd
, buf
);
271 cmd_reply(es
, fd
, "ERR Unknown command");
275 /**********************************************************************
276 * %FUNCTION: cmd_reply
278 * es -- event selector
279 * fd -- file descriptor
284 * Schedules reply to be shot back to user
285 ***********************************************************************/
287 cmd_reply(EventSelector
*es
,
291 EventTcp_WriteBuf(es
, fd
, (char *) msg
, strlen(msg
), NULL
, 10, NULL
);
294 /**********************************************************************
295 * %FUNCTION: cmd_exit
297 * es -- Event selector
298 * fd -- command file descriptor
302 * Tears down tunnels and quits
303 ***********************************************************************/
305 cmd_exit(EventSelector
*es
,
308 cmd_reply(es
, fd
, "OK Shutting down");
309 l2tp_tunnel_stop_all("Stopped by system administrator");
314 /**********************************************************************
315 * %FUNCTION: cmd_start_session
317 * es -- event selector
318 * fd -- command file descriptor
319 * buf -- rest of command from user
323 * Starts an L2TP session, if possible
324 ***********************************************************************/
326 cmd_start_session(EventSelector
*es
,
332 struct sockaddr_in haddr
;
336 buf
= (char *) l2tp_chomp_word(buf
, peer
);
337 he
= gethostbyname(peer
);
339 cmd_reply(es
, fd
, "ERR Unknown peer - gethostbyname failed");
342 memcpy(&haddr
.sin_addr
, he
->h_addr
, sizeof(haddr
.sin_addr
));
343 p
= l2tp_peer_find(&haddr
, NULL
);
345 cmd_reply(es
, fd
, "ERR Unknown peer");
348 sess
= l2tp_session_call_lns(p
, "foobar", es
, NULL
);
350 cmd_reply(es
, fd
, l2tp_get_errmsg());
355 sprintf(peer
, "OK %d %d",
356 (int) sess
->tunnel
->my_id
,
358 cmd_reply(es
, fd
, peer
);
361 /**********************************************************************
362 * %FUNCTION: cmd_stop_session
364 * es -- event selector
365 * fd -- command file descriptor
366 * buf -- rest of command from user
370 * Stops an L2TP session, identified by (Tunnel, Session) pair.
371 ***********************************************************************/
373 cmd_stop_session(EventSelector
*es
,
382 buf
= (char *) l2tp_chomp_word(buf
, junk
);
383 if (sscanf(junk
, "%u", &x
) != 1) {
384 cmd_reply(es
, fd
, "ERR Syntax error: stop-session tid sid");
387 tunnel
= l2tp_tunnel_find_by_my_id((uint16_t) x
);
389 cmd_reply(es
, fd
, "ERR No such tunnel");
394 buf
= (char *) l2tp_chomp_word(buf
, junk
);
395 if (sscanf(junk
, "%u", &x
) != 1) {
396 cmd_reply(es
, fd
, "ERR Syntax error: stop-session tid sid");
399 sess
= l2tp_tunnel_find_session(tunnel
, (uint16_t) x
);
402 cmd_reply(es
, fd
, "ERR No such session");
406 /* Stop the session */
407 l2tp_session_send_CDN(sess
, RESULT_GENERAL_REQUEST
, ERROR_OK
,
408 "Call terminated by operator");
409 cmd_reply(es
, fd
, "OK Session stopped");
412 /**********************************************************************
413 * %FUNCTION: cmd_dump_sessions
415 * es -- event selector
416 * fd -- command file descriptor
417 * buf -- rest of command from user
421 * Dumps info about all currently-active tunnels and sessions
422 ***********************************************************************/
424 cmd_dump_sessions(EventSelector
*es
,
434 dynstring_init(&str
);
436 dynstring_append(&str
, "OK\n");
438 /* Print info about each tunnel */
439 sprintf(tmp
, "NumL2TPTunnels %d\n", l2tp_num_tunnels());
440 dynstring_append(&str
, tmp
);
442 for (tunnel
= l2tp_first_tunnel(&cursor
);
444 tunnel
= l2tp_next_tunnel(&cursor
)) {
445 describe_tunnel(tunnel
, &str
);
448 /* If something went wrong, say so... */
449 ans
= dynstring_data(&str
);
451 cmd_reply(es
, fd
, "ERR Out of memory");
455 cmd_reply(es
, fd
, ans
);
456 dynstring_free(&str
);