Add INTERNALS file
[l2tpns.git] / cli.c
1 // L2TPNS Command Line Interface
2 // $Id: cli.c,v 1.5 2004-06-23 03:52:24 fred_nerk Exp $
3 // vim: sw=4 ts=8
4
5 #include <stdio.h>
6 #include <sys/file.h>
7 #include <sys/stat.h>
8 #include <syslog.h>
9 #include <malloc.h>
10 #include <sched.h>
11 #include <string.h>
12 #include <stdlib.h>
13 #include <time.h>
14 #include <arpa/inet.h>
15 #include <errno.h>
16 #include <sys/socket.h>
17 #include <sys/types.h>
18 #include <signal.h>
19 #include <unistd.h>
20 #include <libcli.h>
21 #include "l2tpns.h"
22 #include "util.h"
23 #include "cluster.h"
24 #include "tbf.h"
25 #ifdef BGP
26 #include "bgp.h"
27 #endif
28
29 extern tunnelt *tunnel;
30 extern sessiont *session;
31 extern radiust *radius;
32 extern ippoolt *ip_address_pool;
33 extern struct Tstats *_statistics;
34 struct cli_def *cli = NULL;
35 int cli_quit = 0;
36 extern int clifd, udpfd, tapfd, snoopfd, ifrfd, cluster_sockfd;
37 extern int *radfds;
38 extern sessionidt *cli_session_kill;
39 extern tunnelidt *cli_tunnel_kill;
40 extern struct configt *config;
41 extern struct config_descriptt config_values[];
42 extern char hostname[];
43 #ifdef RINGBUFFER
44 extern struct Tringbuffer *ringbuffer;
45 #endif
46
47 char *rcs_id = "$Id: cli.c,v 1.5 2004-06-23 03:52:24 fred_nerk Exp $";
48
49 char *debug_levels[] = {
50 "CRIT",
51 "ERROR",
52 "WARN",
53 "INFO",
54 "CALL",
55 "DATA",
56 };
57
58 struct
59 {
60 char critical;
61 char error;
62 char warning;
63 char info;
64 char calls;
65 char data;
66 } debug_flags;
67
68 int debug_session;
69 int debug_tunnel;
70 int debug_rb_tail;
71 FILE *save_config_fh;
72
73 int cmd_show_session(struct cli_def *cli, char *command, char **argv, int argc);
74 int cmd_show_tunnels(struct cli_def *cli, char *command, char **argv, int argc);
75 int cmd_show_users(struct cli_def *cli, char *command, char **argv, int argc);
76 int cmd_show_radius(struct cli_def *cli, char *command, char **argv, int argc);
77 int cmd_show_counters(struct cli_def *cli, char *command, char **argv, int argc);
78 int cmd_show_version(struct cli_def *cli, char *command, char **argv, int argc);
79 int cmd_show_pool(struct cli_def *cli, char *command, char **argv, int argc);
80 int cmd_show_run(struct cli_def *cli, char *command, char **argv, int argc);
81 int cmd_show_banana(struct cli_def *cli, char *command, char **argv, int argc);
82 int cmd_show_plugins(struct cli_def *cli, char *command, char **argv, int argc);
83 int cmd_show_throttle(struct cli_def *cli, char *command, char **argv, int argc);
84 int cmd_show_cluster(struct cli_def *cli, char *command, char **argv, int argc);
85 int cmd_write_memory(struct cli_def *cli, char *command, char **argv, int argc);
86 int cmd_clear_counters(struct cli_def *cli, char *command, char **argv, int argc);
87 int cmd_drop_user(struct cli_def *cli, char *command, char **argv, int argc);
88 int cmd_drop_tunnel(struct cli_def *cli, char *command, char **argv, int argc);
89 int cmd_drop_session(struct cli_def *cli, char *command, char **argv, int argc);
90 int cmd_snoop(struct cli_def *cli, char *command, char **argv, int argc);
91 int cmd_no_snoop(struct cli_def *cli, char *command, char **argv, int argc);
92 int cmd_throttle(struct cli_def *cli, char *command, char **argv, int argc);
93 int cmd_no_throttle(struct cli_def *cli, char *command, char **argv, int argc);
94 int cmd_debug(struct cli_def *cli, char *command, char **argv, int argc);
95 int cmd_no_debug(struct cli_def *cli, char *command, char **argv, int argc);
96 int cmd_set(struct cli_def *cli, char *command, char **argv, int argc);
97 int cmd_load_plugin(struct cli_def *cli, char *command, char **argv, int argc);
98 int cmd_remove_plugin(struct cli_def *cli, char *command, char **argv, int argc);
99 int cmd_uptime(struct cli_def *cli, char *command, char **argv, int argc);
100 int regular_stuff(struct cli_def *cli);
101
102 void init_cli()
103 {
104 FILE *f;
105 char buf[4096];
106 struct cli_command *c;
107 struct cli_command *c2;
108 int on = 1;
109 struct sockaddr_in addr;
110
111 cli = cli_init();
112
113 c = cli_register_command(cli, NULL, "show", NULL, NULL);
114 cli_register_command(cli, c, "banana", cmd_show_banana, "Show a banana");
115 #ifdef BGP
116 cli_register_command(cli, c, "bgp", cmd_show_bgp, "Show BGP status");
117 #endif /* BGP */
118 cli_register_command(cli, c, "cluster", cmd_show_cluster, "Show cluster information");
119 cli_register_command(cli, c, "ipcache", cmd_show_ipcache, "Show contents of the IP cache");
120 cli_register_command(cli, c, "plugins", cmd_show_plugins, "List all installed plugins");
121 cli_register_command(cli, c, "pool", cmd_show_pool, "Show the IP address allocation pool");
122 cli_register_command(cli, c, "radius", cmd_show_radius, "Show active radius queries");
123 cli_register_command(cli, c, "running-config", cmd_show_run, "Show the currently running configuration");
124 cli_register_command(cli, c, "session", cmd_show_session, "Show a list of sessions or details for a single session");
125 cli_register_command(cli, c, "tbf", cmd_show_tbf, "List all token bucket filters in use");
126 cli_register_command(cli, c, "throttle", cmd_show_throttle, "List all throttled sessions and associated TBFs");
127 cli_register_command(cli, c, "tunnels", cmd_show_tunnels, "Show a list of tunnels or details for a single tunnel");
128 cli_register_command(cli, c, "users", cmd_show_users, "Show a list of all connected users or details of selected user");
129 cli_register_command(cli, c, "version", cmd_show_version, "Show currently running software version");
130
131 c2 = cli_register_command(cli, c, "histogram", NULL, NULL);
132 cli_register_command(cli, c2, "idle", cmd_show_hist_idle, "Show histogram of session idle times");
133 cli_register_command(cli, c2, "open", cmd_show_hist_open, "Show histogram of session durations");
134
135 #ifdef STATISTICS
136 cli_register_command(cli, c, "counters", cmd_show_counters, "Display all the internal counters and running totals");
137
138 c = cli_register_command(cli, NULL, "clear", NULL, NULL);
139 cli_register_command(cli, c, "counters", cmd_clear_counters, "Clear internal counters");
140 #endif
141
142 cli_register_command(cli, NULL, "uptime", cmd_uptime, "Show uptime and bandwidth utilisation");
143
144 c = cli_register_command(cli, NULL, "write", NULL, NULL);
145 cli_register_command(cli, c, "memory", cmd_write_memory, "Save the running config to flash");
146 cli_register_command(cli, c, "terminal", cmd_show_run, "Show the running config");
147
148 cli_register_command(cli, NULL, "snoop", cmd_snoop, "Temporarily enable interception for a user");
149 cli_register_command(cli, NULL, "throttle", cmd_throttle, "Temporarily enable throttling for a user");
150 cli_register_command(cli, NULL, "debug", cmd_debug, "Set the level of logging that is shown on the console");
151
152 c = cli_register_command(cli, NULL, "suspend", NULL, NULL);
153 cli_register_command(cli, c, "bgp", cmd_suspend_bgp, "Withdraw routes from BGP peer");
154
155 c = cli_register_command(cli, NULL, "no", NULL, NULL);
156 cli_register_command(cli, c, "snoop", cmd_no_snoop, "Temporarily disable interception for a user");
157 cli_register_command(cli, c, "throttle", cmd_no_throttle, "Temporarily disable throttling for a user");
158 cli_register_command(cli, c, "debug", cmd_no_debug, "Turn off logging of a certain level of debugging");
159 c2 = cli_register_command(cli, c, "suspend", NULL, NULL);
160 cli_register_command(cli, c2, "bgp", cmd_no_suspend_bgp, "Advertise routes to BGP peer");
161
162 c = cli_register_command(cli, NULL, "drop", NULL, NULL);
163 cli_register_command(cli, c, "user", cmd_drop_user, "Disconnect a user");
164 cli_register_command(cli, c, "tunnel", cmd_drop_tunnel, "Disconnect a tunnel and all sessions on that tunnel");
165 cli_register_command(cli, c, "session", cmd_drop_session, "Disconnect a session");
166
167 c = cli_register_command(cli, NULL, "restart", NULL, NULL);
168 cli_register_command(cli, c, "bgp", cmd_restart_bgp, "Restart BGP");
169
170 c = cli_register_command(cli, NULL, "load", NULL, NULL);
171 cli_register_command(cli, c, "plugin", cmd_load_plugin, "Load a plugin");
172
173 c = cli_register_command(cli, NULL, "remove", NULL, NULL);
174 cli_register_command(cli, c, "plugin", cmd_remove_plugin, "Remove a plugin");
175
176 cli_register_command(cli, NULL, "set", cmd_set, "Set a configuration variable");
177
178 // Enable regular processing
179 cli_regular(cli, regular_stuff);
180
181 if (!(f = fopen(CLIUSERS, "r")))
182 {
183 log(0, 0, 0, 0, "WARNING! No users specified. Command-line access is open to all\n");
184 }
185 else
186 {
187 while (fgets(buf, 4096, f))
188 {
189 char *p;
190 if (*buf == '#') continue;
191 if ((p = strchr(buf, '\r'))) *p = 0;
192 if ((p = strchr(buf, '\n'))) *p = 0;
193 if (!*buf) continue;
194 if (!(p = strchr((char *)buf, ':'))) continue;
195 *p++ = 0;
196 cli_allow_user(cli, buf, p);
197 log(3, 0, 0, 0, "Allowing user %s to connect to the CLI\n", buf);
198 }
199 fclose(f);
200 }
201
202 memset(&addr, 0, sizeof(addr));
203 clifd = socket(PF_INET, SOCK_STREAM, 6);
204 setsockopt(clifd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on));
205 {
206 int flags;
207 // Set cli fd as non-blocking
208 flags = fcntl(clifd, F_GETFL, 0);
209 fcntl(clifd, F_SETFL, flags | O_NONBLOCK);
210 }
211 addr.sin_family = AF_INET;
212 addr.sin_port = htons(23);
213 if (bind(clifd, (void *) &addr, sizeof(addr)) < 0)
214 {
215 log(0, 0, 0, 0, "Error listening on cli port 23: %s\n", strerror(errno));
216 return;
217 }
218 listen(clifd, 10);
219 }
220
221 void cli_do(int sockfd)
222 {
223 int i;
224
225 if (fork()) return;
226 if (config->scheduler_fifo)
227 {
228 int ret;
229 struct sched_param params = {0};
230 params.sched_priority = 0;
231 if ((ret = sched_setscheduler(0, SCHED_OTHER, &params)) == 0)
232 {
233 log(3, 0, 0, 0, "Dropped FIFO scheduler\n");
234 }
235 else
236 {
237 log(0, 0, 0, 0, "Error setting scheduler to OTHER: %s\n", strerror(errno));
238 log(0, 0, 0, 0, "This is probably really really bad.\n");
239 }
240 }
241
242 signal(SIGPIPE, SIG_DFL);
243 signal(SIGCHLD, SIG_DFL);
244 signal(SIGHUP, SIG_DFL);
245 signal(SIGUSR1, SIG_DFL);
246 signal(SIGQUIT, SIG_DFL);
247 signal(SIGKILL, SIG_DFL);
248 signal(SIGALRM, SIG_DFL);
249 signal(SIGTERM, SIG_DFL);
250
251 // Close sockets
252 if (udpfd) close(udpfd); udpfd = 0;
253 if (tapfd) close(tapfd); tapfd = 0;
254 if (snoopfd) close(snoopfd); snoopfd = 0;
255 for (i = 0; i < config->num_radfds; i++)
256 if (radfds[i]) close(radfds[i]);
257 if (ifrfd) close(ifrfd); ifrfd = 0;
258 if (cluster_sockfd) close(cluster_sockfd); cluster_sockfd = 0;
259 if (clifd) close(clifd); clifd = 0;
260 #ifdef BGP
261 for (i = 0; i < BGP_NUM_PEERS; i++)
262 if (bgp_peers[i].sock != -1)
263 close(bgp_peers[i].sock);
264 #endif /* BGP */
265
266 log(3, 0, 0, 0, "Accepted connection to CLI\n");
267
268 debug_session = 0;
269 debug_tunnel = 0;
270 #ifdef RINGBUFFER
271 debug_rb_tail = ringbuffer->tail;
272 #endif
273 memset(&debug_flags, 0, sizeof(debug_flags));
274 debug_flags.critical = 1;
275
276 {
277 char prompt[1005];
278 snprintf(prompt, 1005, "l2tpns> ");
279 cli_loop(cli, sockfd, prompt);
280 }
281
282 close(sockfd);
283 log(3, 0, 0, 0, "Closed CLI connection\n");
284 exit(0);
285 }
286
287 void cli_print_log(struct cli_def *cli, char *string)
288 {
289 log(3, 0, 0, 0, "%s\n", string);
290 }
291
292 void cli_do_file(FILE *fh)
293 {
294 log(3, 0, 0, 0, "Reading configuration file\n");
295 cli_print_callback(cli, cli_print_log);
296 cli_file(cli, fh);
297 cli_print_callback(cli, NULL);
298 }
299
300 int cmd_show_session(struct cli_def *cli, char *command, char **argv, int argc)
301 {
302 int i;
303 time_t time_now;
304
305 time(&time_now);
306 if (argc > 0)
307 {
308 // Show individual session
309 for (i = 0; i < argc; i++)
310 {
311 unsigned int s;
312 s = atoi(argv[i]);
313 if (!s || s > MAXSESSION)
314 {
315 cli_print(cli, "Invalid session id \"%s\"", argv[i]);
316 continue;
317 }
318 cli_print(cli, "\r\nSession %d:", s);
319 cli_print(cli, " User: %s", session[s].user[0] ? session[s].user : "none");
320 cli_print(cli, " Calling Num: %s", session[s].calling);
321 cli_print(cli, " Called Num: %s", session[s].called);
322 cli_print(cli, " Tunnel ID: %d", session[s].tunnel);
323 cli_print(cli, " IP address: %s", inet_toa(htonl(session[s].ip)));
324 cli_print(cli, " HSD sid: %lu", session[s].sid);
325 cli_print(cli, " Idle time: %u seconds", abs(time_now - session[s].last_packet));
326 cli_print(cli, " Next Recv: %u", session[s].nr);
327 cli_print(cli, " Next Send: %u", session[s].ns);
328 cli_print(cli, " Bytes In/Out: %lu/%lu", (unsigned long)session[s].total_cout, (unsigned long)session[s].total_cin);
329 cli_print(cli, " Pkts In/Out: %lu/%lu", (unsigned long)session[s].pout, (unsigned long)session[s].pin);
330 cli_print(cli, " MRU: %d", session[s].mru);
331 cli_print(cli, " Radius Session: %u", session[s].radius);
332 cli_print(cli, " Rx Speed: %lu", session[s].rx_connect_speed);
333 cli_print(cli, " Tx Speed: %lu", session[s].tx_connect_speed);
334 if (session[s].snoop_ip && session[s].snoop_port)
335 cli_print(cli, " Intercepted: %s:%d", inet_toa(session[s].snoop_ip), session[s] .snoop_port);
336 else
337 cli_print(cli, " Intercepted: no");
338 cli_print(cli, " Throttled: %s", session[s].throttle ? "YES" : "no");
339 cli_print(cli, " Walled Garden: %s", session[s].walled_garden ? "YES" : "no");
340 cli_print(cli, " Filter BucketI: %d", session[s].tbf_in);
341 cli_print(cli, " Filter BucketO: %d", session[s].tbf_out);
342 }
343 return CLI_OK;
344 }
345
346 // Show Summary
347 cli_print(cli, " %s %4s %-32s %-15s %s %s %s %10s %10s %10s %4s %-15s %s",
348 "SID",
349 "TID",
350 "Username",
351 "IP",
352 "I",
353 "T",
354 "G",
355 "opened",
356 "downloaded",
357 "uploaded",
358 "idle",
359 "LAC",
360 "CLI");
361 for (i = 1; i < MAXSESSION; i++)
362 {
363 char *userip, *tunnelip;
364 if (!session[i].opened) continue;
365 userip = strdup(inet_toa(htonl(session[i].ip)));
366 tunnelip = strdup(inet_toa(htonl(tunnel[ session[i].tunnel ].ip)));
367 cli_print(cli, "%5d %4d %-32s %-15s %s %s %s %10u %10lu %10lu %4u %-15s %s",
368 i,
369 session[i].tunnel,
370 session[i].user[0] ? session[i].user : "*",
371 userip,
372 (session[i].snoop_ip && session[i].snoop_port) ? "Y" : "N",
373 (session[i].throttle) ? "Y" : "N",
374 (session[i].walled_garden) ? "Y" : "N",
375 abs(time_now - (unsigned long)session[i].opened),
376 (unsigned long)session[i].total_cout,
377 (unsigned long)session[i].total_cin,
378 abs(time_now - (session[i].last_packet ? session[i].last_packet : time_now)),
379 tunnelip,
380 session[i].calling[0] ? session[i].calling : "*");
381 if (userip) free(userip);
382 if (tunnelip) free(tunnelip);
383 }
384 return CLI_OK;
385 }
386
387 int cmd_show_tunnels(struct cli_def *cli, char *command, char **argv, int argc)
388 {
389 int i, x, show_all = 0;
390 time_t time_now;
391 char *states[] = {
392 "Free",
393 "Open",
394 "Closing",
395 "Opening",
396 };
397
398 time(&time_now);
399 if (argc > 0)
400 {
401 if (strcmp(argv[0], "all") == 0)
402 {
403 show_all = 1;
404 }
405 else
406 {
407 // Show individual tunnel
408 for (i = 0; i < argc; i++)
409 {
410 char s[65535] = {0};
411 unsigned int t;
412 t = atoi(argv[i]);
413 if (!t || t > MAXTUNNEL)
414 {
415 cli_print(cli, "Invalid tunnel id \"%s\"", argv[i]);
416 continue;
417 }
418 cli_print(cli, "\r\nTunnel %d:", t);
419 cli_print(cli, " State: %s", states[tunnel[t].state]);
420 cli_print(cli, " Hostname: %s", tunnel[t].hostname[0] ? tunnel[t].hostname : "(none)");
421 cli_print(cli, " Remote IP: %s", inet_toa(htonl(tunnel[t].ip)));
422 cli_print(cli, " Remote Port: %d", tunnel[t].port);
423 cli_print(cli, " Rx Window: %u", tunnel[t].window);
424 cli_print(cli, " Next Recv: %u", tunnel[t].nr);
425 cli_print(cli, " Next Send: %u", tunnel[t].ns);
426 cli_print(cli, " Queue Len: %u", tunnel[t].controlc);
427 cli_print(cli, " Last Packet Age:%u", (unsigned)(time_now - tunnel[t].last));
428
429 for (x = 0; x < MAXSESSION; x++)
430 if (session[x].tunnel == t && session[x].opened && !session[x].die)
431 sprintf(s, "%s%u ", s, x);
432 cli_print(cli, " Sessions: %s", s);
433 }
434 return CLI_OK;
435 }
436 }
437
438 // Show tunnel summary
439 cli_print(cli, "%s %s %s %s %s",
440 "TID",
441 "Hostname",
442 "IP",
443 "State",
444 "Sessions");
445 for (i = 1; i < MAXTUNNEL; i++)
446 {
447 int sessions = 0;
448 if (!show_all && (!tunnel[i].ip || tunnel[i].die || !tunnel[i].hostname[0])) continue;
449
450 for (x = 0; x < MAXSESSION; x++) if (session[x].tunnel == i && session[x].opened && !session[x].die) sessions++;
451 cli_print(cli, "%d %s %s %s %d",
452 i,
453 *tunnel[i].hostname ? tunnel[i].hostname : "(null)",
454 inet_toa(htonl(tunnel[i].ip)),
455 states[tunnel[i].state],
456 sessions);
457 }
458 return CLI_OK;
459 }
460
461 int cmd_show_users(struct cli_def *cli, char *command, char **argv, int argc)
462 {
463 char sid[32][8];
464 char *sargv[32];
465 int sargc = 0;
466 int i;
467 for (i = 0; i < MAXSESSION; i++)
468 {
469 if (!session[i].opened) continue;
470 if (!session[i].user[0]) continue;
471 if (argc > 0)
472 {
473 int j;
474 for (j = 0; j < argc && sargc < 32; j++)
475 {
476 if (strcmp(argv[j], session[i].user) == 0)
477 {
478 snprintf(sid[sargc], sizeof(sid[0]), "%d", i);
479 sargv[sargc] = sid[sargc];
480 sargc++;
481 }
482 }
483
484 continue;
485 }
486
487 cli_print(cli, "%s", session[i].user);
488 }
489
490 if (sargc > 0)
491 return cmd_show_session(cli, "users", sargv, sargc);
492
493 return CLI_OK;
494 }
495
496 int cmd_show_counters(struct cli_def *cli, char *command, char **argv, int argc)
497 {
498 cli_print(cli, "%-10s %-8s %-10s %-8s", "Ethernet", "Bytes", "Packets", "Errors");
499 cli_print(cli, "%-10s %8lu %8lu %8lu", "RX",
500 GET_STAT(tap_rx_bytes),
501 GET_STAT(tap_rx_packets),
502 GET_STAT(tap_rx_errors));
503 cli_print(cli, "%-10s %8lu %8lu %8lu", "TX",
504 GET_STAT(tap_tx_bytes),
505 GET_STAT(tap_tx_packets),
506 GET_STAT(tap_tx_errors));
507 cli_print(cli, "");
508
509 cli_print(cli, "%-10s %-8s %-10s %-8s %-8s", "Tunnel", "Bytes", "Packets", "Errors", "Retries");
510 cli_print(cli, "%-10s %8lu %8lu %8lu %8lu", "RX",
511 GET_STAT(tunnel_rx_bytes),
512 GET_STAT(tunnel_rx_packets),
513 GET_STAT(tunnel_rx_errors),
514 0L);
515 cli_print(cli, "%-10s %8lu %8lu %8lu %8lu", "TX",
516 GET_STAT(tunnel_tx_bytes),
517 GET_STAT(tunnel_tx_packets),
518 GET_STAT(tunnel_tx_errors),
519 GET_STAT(tunnel_retries));
520 cli_print(cli, "");
521
522 cli_print(cli, "%-30s%-10s", "Counter", "Value");
523 cli_print(cli, "-----------------------------------------");
524 cli_print(cli, "%-30s%lu", "radius_retries", GET_STAT(radius_retries));
525 cli_print(cli, "%-30s%lu", "arp_errors", GET_STAT(arp_errors));
526 cli_print(cli, "%-30s%lu", "arp_replies", GET_STAT(arp_replies));
527 cli_print(cli, "%-30s%lu", "arp_discarded", GET_STAT(arp_discarded));
528 cli_print(cli, "%-30s%lu", "arp_sent", GET_STAT(arp_sent));
529 cli_print(cli, "%-30s%lu", "arp_recv", GET_STAT(arp_recv));
530 cli_print(cli, "%-30s%lu", "packets_snooped", GET_STAT(packets_snooped));
531 cli_print(cli, "%-30s%lu", "tunnel_created", GET_STAT(tunnel_created));
532 cli_print(cli, "%-30s%lu", "session_created", GET_STAT(session_created));
533 cli_print(cli, "%-30s%lu", "tunnel_timeout", GET_STAT(tunnel_timeout));
534 cli_print(cli, "%-30s%lu", "session_timeout", GET_STAT(session_timeout));
535 cli_print(cli, "%-30s%lu", "radius_timeout", GET_STAT(radius_timeout));
536 cli_print(cli, "%-30s%lu", "radius_overflow", GET_STAT(radius_overflow));
537 cli_print(cli, "%-30s%lu", "tunnel_overflow", GET_STAT(tunnel_overflow));
538 cli_print(cli, "%-30s%lu", "session_overflow", GET_STAT(session_overflow));
539 cli_print(cli, "%-30s%lu", "ip_allocated", GET_STAT(ip_allocated));
540 cli_print(cli, "%-30s%lu", "ip_freed", GET_STAT(ip_freed));
541 cli_print(cli, "%-30s%lu", "cluster_forwarded", GET_STAT(c_forwarded));
542 cli_print(cli, "%-30s%lu", "recv_forward", GET_STAT(recv_forward));
543
544
545 #ifdef STAT_CALLS
546 cli_print(cli, "\n%-30s%-10s", "Counter", "Value");
547 cli_print(cli, "-----------------------------------------");
548 cli_print(cli, "%-30s%lu", "call_processtap", GET_STAT(call_processtap));
549 cli_print(cli, "%-30s%lu", "call_processarp", GET_STAT(call_processarp));
550 cli_print(cli, "%-30s%lu", "call_processipout", GET_STAT(call_processipout));
551 cli_print(cli, "%-30s%lu", "call_processudp", GET_STAT(call_processudp));
552 cli_print(cli, "%-30s%lu", "call_processpap", GET_STAT(call_processpap));
553 cli_print(cli, "%-30s%lu", "call_processchap", GET_STAT(call_processchap));
554 cli_print(cli, "%-30s%lu", "call_processlcp", GET_STAT(call_processlcp));
555 cli_print(cli, "%-30s%lu", "call_processipcp", GET_STAT(call_processipcp));
556 cli_print(cli, "%-30s%lu", "call_processipin", GET_STAT(call_processipin));
557 cli_print(cli, "%-30s%lu", "call_processccp", GET_STAT(call_processccp));
558 cli_print(cli, "%-30s%lu", "call_processrad", GET_STAT(call_processrad));
559 cli_print(cli, "%-30s%lu", "call_sendarp", GET_STAT(call_sendarp));
560 cli_print(cli, "%-30s%lu", "call_sendipcp", GET_STAT(call_sendipcp));
561 cli_print(cli, "%-30s%lu", "call_sendchap", GET_STAT(call_sendchap));
562 cli_print(cli, "%-30s%lu", "call_sessionbyip", GET_STAT(call_sessionbyip));
563 cli_print(cli, "%-30s%lu", "call_sessionbyuser", GET_STAT(call_sessionbyuser));
564 cli_print(cli, "%-30s%lu", "call_tunnelsend", GET_STAT(call_tunnelsend));
565 cli_print(cli, "%-30s%lu", "call_tunnelkill", GET_STAT(call_tunnelkill));
566 cli_print(cli, "%-30s%lu", "call_tunnelshutdown", GET_STAT(call_tunnelshutdown));
567 cli_print(cli, "%-30s%lu", "call_sessionkill", GET_STAT(call_sessionkill));
568 cli_print(cli, "%-30s%lu", "call_sessionshutdown", GET_STAT(call_sessionshutdown));
569 cli_print(cli, "%-30s%lu", "call_sessionsetup", GET_STAT(call_sessionsetup));
570 cli_print(cli, "%-30s%lu", "call_assign_ip_address",GET_STAT(call_assign_ip_address));
571 cli_print(cli, "%-30s%lu", "call_free_ip_address", GET_STAT(call_free_ip_address));
572 cli_print(cli, "%-30s%lu", "call_dump_acct_info", GET_STAT(call_dump_acct_info));
573 cli_print(cli, "%-30s%lu", "call_radiussend", GET_STAT(call_radiussend));
574 cli_print(cli, "%-30s%lu", "call_radiusretry", GET_STAT(call_radiusretry));
575 #endif
576 return CLI_OK;
577 }
578
579 int cmd_show_version(struct cli_def *cli, char *command, char **argv, int argc)
580 {
581 cli_print(cli, "L2TPNS %s", VERSION);
582 cli_print(cli, "ID: %s", rcs_id);
583 return CLI_OK;
584 }
585
586 int cmd_show_pool(struct cli_def *cli, char *command, char **argv, int argc)
587 {
588 int i;
589 int used = 0, free = 0, show_all = 0;
590 time_t time_now;
591
592 if (argc > 0 && strcmp(argv[0], "all") == 0)
593 show_all = 1;
594
595 time(&time_now);
596 cli_print(cli, "%-15s %4s %8s %s", "IP Address", "Used", "Session", "User");
597 for (i = 0; i < MAXIPPOOL; i++)
598 {
599 if (!ip_address_pool[i].address) continue;
600 if (ip_address_pool[i].assigned)
601 {
602 cli_print(cli, "%-15s Y %8d %s",
603 inet_toa(htonl(ip_address_pool[i].address)), ip_address_pool[i].session, session[ip_address_pool[i].session].user);
604
605 used++;
606 }
607 else
608 {
609 if (ip_address_pool[i].last)
610 cli_print(cli, "%-15s N %8s [%s] %ds",
611 inet_toa(htonl(ip_address_pool[i].address)), "",
612 ip_address_pool[i].user, time_now - ip_address_pool[i].last);
613 else if (show_all)
614 cli_print(cli, "%-15s N", inet_toa(htonl(ip_address_pool[i].address)));
615
616 free++;
617 }
618 }
619
620 if (!show_all)
621 cli_print(cli, "(Not displaying unused addresses)");
622
623 cli_print(cli, "\r\nFree: %d\r\nUsed: %d", free, used);
624 return CLI_OK;
625 }
626
627 void print_save_config(struct cli_def *cli, char *string)
628 {
629 if (save_config_fh)
630 fprintf(save_config_fh, "%s\n", string);
631 }
632
633 int cmd_write_memory(struct cli_def *cli, char *command, char **argv, int argc)
634 {
635 if ((save_config_fh = fopen(config->config_file, "w")))
636 {
637 cli_print(cli, "Writing configuration");
638 cli_print_callback(cli, print_save_config);
639 cmd_show_run(cli, command, argv, argc);
640 cli_print_callback(cli, NULL);
641 fclose(save_config_fh);
642 }
643 else
644 {
645 cli_print(cli, "Error writing configuration: %s", strerror(errno));
646 }
647 return CLI_OK;
648 }
649
650 int cmd_show_run(struct cli_def *cli, char *command, char **argv, int argc)
651 {
652 int i;
653
654 cli_print(cli, "# Current configuration:");
655
656 for (i = 0; config_values[i].key; i++)
657 {
658 void *value = ((void *)config) + config_values[i].offset;
659 if (config_values[i].type == STRING)
660 cli_print(cli, "set %s \"%.*s\"", config_values[i].key, config_values[i].size, (char *)value);
661 else if (config_values[i].type == IP)
662 cli_print(cli, "set %s %s", config_values[i].key, inet_toa(*(unsigned *)value));
663 else if (config_values[i].type == SHORT)
664 cli_print(cli, "set %s %hu", config_values[i].key, *(short *)value);
665 else if (config_values[i].type == BOOL)
666 cli_print(cli, "set %s %s", config_values[i].key, (*(int *)value) ? "yes" : "no");
667 else if (config_values[i].type == INT)
668 cli_print(cli, "set %s %d", config_values[i].key, *(int *)value);
669 else if (config_values[i].type == UNSIGNED_LONG)
670 cli_print(cli, "set %s %lu", config_values[i].key, *(unsigned long *)value);
671 }
672
673 cli_print(cli, "# Plugins");
674 for (i = 0; i < MAXPLUGINS; i++)
675 {
676 if (*config->plugins[i])
677 {
678 cli_print(cli, "load plugin \"%s\"", config->plugins[i]);
679 }
680 }
681
682 cli_print(cli, "# end");
683 return CLI_OK;
684 }
685
686 int cmd_show_radius(struct cli_def *cli, char *command, char **argv, int argc)
687 {
688 char *states[] = {
689 "NULL",
690 "CHAP",
691 "AUTH",
692 "IPCP",
693 "START",
694 "STOP",
695 "WAIT",
696 };
697 int i, free = 0, used = 0, show_all = 0;
698 time_t time_now;
699
700 cli_print(cli, "%6s%5s%6s%9s%9s%4s", "Radius", "Sock", "State", "Session", "Retry", "Try");
701
702 time(&time_now);
703
704 if (argc > 0 && strcmp(argv[0], "all") == 0)
705 show_all = 1;
706
707 for (i = 1; i < MAXRADIUS; i++)
708 {
709 if (radius[i].state == RADIUSNULL)
710 free++;
711 else
712 used++;
713
714 if (!show_all && radius[i].state == RADIUSNULL) continue;
715
716 cli_print(cli, "%6d%5d%6s%9d%9u%4d",
717 i >> RADIUS_SHIFT,
718 i & RADIUS_MASK,
719 states[radius[i].state],
720 radius[i].session,
721 radius[i].retry,
722 radius[i].try);
723 }
724
725 cli_print(cli, "\r\nFree: %d\r\nUsed: %d", free, used);
726
727 return CLI_OK;
728 }
729
730 int cmd_show_plugins(struct cli_def *cli, char *command, char **argv, int argc)
731 {
732 int i;
733 cli_print(cli, "Plugins currently loaded:");
734 for (i = 0; i < MAXPLUGINS; i++)
735 {
736 if (*config->plugins[i])
737 {
738 cli_print(cli, " %s", config->plugins[i]);
739 }
740 }
741 return CLI_OK;
742 }
743
744 int cmd_show_throttle(struct cli_def *cli, char *command, char **argv, int argc)
745 {
746 int i;
747 cli_print(cli, "Token bucket filters:");
748 cli_print(cli, "%-6s %8s %-4s", "ID", "Handle", "Used");
749 for (i = 0; i < MAXSESSION; i++)
750 {
751 if (!session[i].throttle)
752 continue;
753
754 cli_print(cli, "%-6d %8d %8d",
755 i,
756 session[i].tbf_in,
757 session[i].tbf_out);
758 }
759 return CLI_OK;
760 }
761
762 int cmd_show_banana(struct cli_def *cli, char *command, char **argv, int argc)
763 {
764 cli_print(cli, " _\n"
765 "//\\\n"
766 "V \\\n"
767 " \\ \\_\n"
768 " \\,'.`-.\n"
769 " |\\ `. `.\n"
770 " ( \\ `. `-. _,.-:\\\n"
771 " \\ \\ `. `-._ __..--' ,-';/\n"
772 " \\ `. `-. `-..___..---' _.--' ,'/\n"
773 " `. `. `-._ __..--' ,' /\n"
774 " `. `-_ ``--..'' _.-' ,'\n"
775 " `-_ `-.___ __,--' ,'\n"
776 " `-.__ `----\"\"\" __.-'\n"
777 "hh `--..____..--'");
778
779 return CLI_OK;
780 }
781
782 int cmd_clear_counters(struct cli_def *cli, char *command, char **argv, int argc)
783 {
784 cli_print(cli, "Counters cleared");
785 SET_STAT(last_reset, time(NULL));
786 return CLI_OK;
787 }
788
789 int cmd_drop_user(struct cli_def *cli, char *command, char **argv, int argc)
790 {
791 int i;
792 sessionidt s;
793
794 if (!config->cluster_iam_master)
795 {
796 cli_print(cli, "Can't do this on a slave. Do it on %s", inet_toa(config->cluster_master_address));
797 return CLI_OK;
798 }
799 if (!argc)
800 {
801 cli_print(cli, "Specify a user to drop");
802 return CLI_OK;
803 }
804 for (i = 0; i < argc; i++)
805 {
806 if (strchr(argv[i], '?'))
807 {
808 cli_print(cli, "username ...");
809 return CLI_OK;
810 }
811 }
812
813 for (i = 0; i < argc; i++)
814 {
815 if (!(s = sessionbyuser(argv[i])))
816 {
817 cli_print(cli, "User %s is not connected", argv[i]);
818 continue;
819 }
820
821 if (session[s].ip && session[s].opened && !session[s].die)
822 {
823 int x;
824
825 cli_print(cli, "Dropping user %s", session[s].user);
826 for (x = 0; x < MAXSESSION; x++)
827 {
828 if (!cli_session_kill[x])
829 {
830 cli_session_kill[x] = s;
831 break;
832 }
833 }
834 }
835 }
836
837 return CLI_OK;
838 }
839
840 int cmd_drop_tunnel(struct cli_def *cli, char *command, char **argv, int argc)
841 {
842 int i;
843 tunnelidt tid;
844
845 if (!config->cluster_iam_master)
846 {
847 cli_print(cli, "Can't do this on a slave. Do it on %s", inet_toa(config->cluster_master_address));
848 return CLI_OK;
849 }
850 if (!argc)
851 {
852 cli_print(cli, "Specify a tunnel to drop");
853 return CLI_OK;
854 }
855 for (i = 0; i < argc; i++)
856 {
857 if (strchr(argv[i], '?'))
858 {
859 cli_print(cli, "tunnel_id ...");
860 return CLI_OK;
861 }
862 }
863
864 for (i = 0; i < argc; i++)
865 {
866 int x;
867
868 if ((tid = atol(argv[i])) <= 0 || (tid > MAXTUNNEL))
869 {
870 cli_print(cli, "Invalid tunnel ID (%d - %d)", 0, MAXTUNNEL);
871 continue;
872 }
873
874 if (!tunnel[tid].ip)
875 {
876 cli_print(cli, "Tunnel %d is not connected", tid);
877 continue;
878 }
879
880 if (tunnel[tid].die)
881 {
882 cli_print(cli, "Tunnel %d is already being shut down", tid);
883 continue;
884 }
885
886 for (x = 0; x < MAXTUNNEL; x++)
887 {
888 if (!cli_tunnel_kill[x])
889 {
890 cli_tunnel_kill[x] = tid;
891 cli_print(cli, "Tunnel %d shut down (%s)", tid, tunnel[tid].hostname);
892 break;
893 }
894 }
895 }
896
897 return CLI_OK;
898 }
899
900 int cmd_drop_session(struct cli_def *cli, char *command, char **argv, int argc)
901 {
902 int i;
903 sessionidt s;
904
905 if (!config->cluster_iam_master)
906 {
907 cli_print(cli, "Can't do this on a slave. Do it on %s", inet_toa(config->cluster_master_address));
908 return CLI_OK;
909 }
910 if (!argc)
911 {
912 cli_print(cli, "Specify a session id to drop");
913 return CLI_OK;
914 }
915 for (i = 0; i < argc; i++)
916 {
917 if (strchr(argv[i], '?'))
918 {
919 cli_print(cli, "session_id ...");
920 return CLI_OK;
921 }
922 }
923
924 for (i = 0; i < argc; i++)
925 {
926 if ((s = atol(argv[i])) <= 0 || (s > MAXSESSION))
927 {
928 cli_print(cli, "Invalid session ID (%d - %d)", 0, MAXSESSION);
929 continue;
930 }
931
932 if (session[s].opened && !session[s].die)
933 {
934 int x;
935 for (x = 0; x < MAXSESSION; x++)
936 {
937 if (!cli_session_kill[x])
938 {
939 cli_session_kill[x] = s;
940 break;
941 }
942 }
943 cli_print(cli, "Dropping session %d", s);
944 }
945 else
946 {
947 cli_print(cli, "Session %d is not active.", s);
948 }
949 }
950
951 return CLI_OK;
952 }
953
954 int cmd_snoop(struct cli_def *cli, char *command, char **argv, int argc)
955 {
956 int i;
957 ipt ip;
958 u16 port;
959 sessionidt s;
960
961 if (!config->cluster_iam_master)
962 {
963 cli_print(cli, "Can't do this on a slave. Do it on %s", inet_toa(config->cluster_master_address));
964 return CLI_OK;
965 }
966
967 if (argc < 3)
968 {
969 cli_print(cli, "Specify username ip port");
970 return CLI_OK;
971 }
972
973 for (i = 0; i < argc; i++)
974 {
975 if (strchr(argv[i], '?'))
976 {
977 cli_print(cli, "username ip port");
978 return CLI_OK;
979 }
980 }
981
982
983 if (!(s = sessionbyuser(argv[0])))
984 {
985 cli_print(cli, "User %s is not connected", argv[0]);
986 return CLI_OK;
987 }
988
989 ip = inet_addr(argv[1]);
990 if (!ip || ip == INADDR_NONE)
991 {
992 cli_print(cli, "Cannot parse IP \"%s\"", argv[1]);
993 return CLI_OK;
994 }
995
996 port = atoi(argv[2]);
997 if (!port)
998 {
999 cli_print(cli, "Invalid port %s", argv[2]);
1000 return CLI_OK;
1001 }
1002
1003 session[s].snoop_ip = ip;
1004 session[s].snoop_port = port;
1005
1006 cli_print(cli, "Snooping user %s to %s:%d", argv[0], inet_toa(session[s].snoop_ip), session[s].snoop_port);
1007 return CLI_OK;
1008 }
1009
1010 int cmd_no_snoop(struct cli_def *cli, char *command, char **argv, int argc)
1011 {
1012 int i;
1013 sessionidt s;
1014
1015 if (!config->cluster_iam_master)
1016 {
1017 cli_print(cli, "Can't do this on a slave. Do it on %s", inet_toa(config->cluster_master_address));
1018 return CLI_OK;
1019 }
1020
1021 if (!argc)
1022 {
1023 cli_print(cli, "Specify a user");
1024 return CLI_OK;
1025 }
1026 for (i = 0; i < argc; i++)
1027 {
1028 if (strchr(argv[i], '?'))
1029 {
1030 cli_print(cli, "username ...");
1031 return CLI_OK;
1032 }
1033 }
1034
1035 for (i = 0; i < argc; i++)
1036 {
1037 if (!(s = sessionbyuser(argv[i])))
1038 {
1039 cli_print(cli, "User %s is not connected", argv[i]);
1040 continue;
1041 }
1042 session[s].snoop_ip = 0;
1043 session[s].snoop_port = 0;
1044
1045 cli_print(cli, "Not snooping user %s", argv[i]);
1046 }
1047 return CLI_OK;
1048 }
1049
1050 int cmd_throttle(struct cli_def *cli, char *command, char **argv, int argc)
1051 {
1052 int i;
1053 sessionidt s;
1054
1055 if (!config->cluster_iam_master)
1056 {
1057 cli_print(cli, "Can't do this on a slave. Do it on %s", inet_toa(config->cluster_master_address));
1058 return CLI_OK;
1059 }
1060 if (!argc)
1061 {
1062 cli_print(cli, "Specify a user");
1063 return CLI_OK;
1064 }
1065 for (i = 0; i < argc; i++)
1066 {
1067 if (strchr(argv[i], '?'))
1068 {
1069 cli_print(cli, "username ...");
1070 return CLI_OK;
1071 }
1072 }
1073
1074 for (i = 0; i < argc; i++)
1075 {
1076 if (!(s = sessionbyuser(argv[i])))
1077 {
1078 cli_print(cli, "User %s is not connected", argv[i]);
1079 continue;
1080 }
1081 if (!throttle_session(s, config->rl_rate))
1082 cli_print(cli, "Error throttling %s", argv[i]);
1083 else
1084 cli_print(cli, "Throttling user %s", argv[i]);
1085 }
1086 return CLI_OK;
1087 }
1088
1089 int cmd_no_throttle(struct cli_def *cli, char *command, char **argv, int argc)
1090 {
1091 int i;
1092 sessionidt s;
1093
1094 if (!config->cluster_iam_master)
1095 {
1096 cli_print(cli, "Can't do this on a slave. Do it on %s", inet_toa(config->cluster_master_address));
1097 return CLI_OK;
1098 }
1099 if (!argc)
1100 {
1101 cli_print(cli, "Specify a user");
1102 return CLI_OK;
1103 }
1104 for (i = 0; i < argc; i++)
1105 {
1106 if (strchr(argv[i], '?'))
1107 {
1108 cli_print(cli, "username ...");
1109 return CLI_OK;
1110 }
1111 }
1112
1113 for (i = 0; i < argc; i++)
1114 {
1115 if (!(s = sessionbyuser(argv[i])))
1116 {
1117 cli_print(cli, "User %s is not connected", argv[i]);
1118 continue;
1119 }
1120 throttle_session(s, 0);
1121
1122 cli_print(cli, "unthrottling user %s", argv[i]);
1123 }
1124 return CLI_OK;
1125 }
1126
1127 int cmd_debug(struct cli_def *cli, char *command, char **argv, int argc)
1128 {
1129 int i;
1130
1131 if (!argc)
1132 {
1133 cli_print(cli, "Currently debugging: ");
1134 if (debug_flags.critical) cli_print(cli, "critical ");
1135 if (debug_flags.error) cli_print(cli, "error ");
1136 if (debug_flags.warning) cli_print(cli, "warning ");
1137 if (debug_flags.info) cli_print(cli, "info ");
1138 if (debug_flags.calls) cli_print(cli, "calls ");
1139 if (debug_flags.data) cli_print(cli, "data ");
1140 cli_print(cli, "");
1141 return CLI_OK;
1142 }
1143
1144 for (i = 0; i < argc; i++)
1145 {
1146 if (*argv[i] == '?')
1147 {
1148 cli_print(cli, "Possible debugging states are:");
1149 cli_print(cli, " critical");
1150 cli_print(cli, " error");
1151 cli_print(cli, " warning");
1152 cli_print(cli, " info");
1153 cli_print(cli, " calls");
1154 cli_print(cli, " data");
1155 return CLI_OK;
1156 }
1157 }
1158
1159 for (i = 0; i < argc; i++)
1160 {
1161 if (strcasecmp(argv[i], "critical") == 0) debug_flags.critical = 1;
1162 if (strcasecmp(argv[i], "error") == 0) debug_flags.error = 1;
1163 if (strcasecmp(argv[i], "warning") == 0) debug_flags.warning = 1;
1164 if (strcasecmp(argv[i], "info") == 0) debug_flags.info = 1;
1165 if (strcasecmp(argv[i], "calls") == 0) debug_flags.calls = 1;
1166 if (strcasecmp(argv[i], "data") == 0) debug_flags.data = 1;
1167 if (strcasecmp(argv[i], "all") == 0)
1168 {
1169 memset(&debug_flags, 1, sizeof(debug_flags));
1170 debug_flags.data = 0;
1171 }
1172 }
1173
1174 return CLI_OK;
1175 }
1176
1177 int cmd_no_debug(struct cli_def *cli, char *command, char **argv, int argc)
1178 {
1179 int i;
1180
1181 for (i = 0; i < argc; i++)
1182 {
1183 if (strcasecmp(argv[i], "critical") == 0) debug_flags.critical = 0;
1184 if (strcasecmp(argv[i], "error") == 0) debug_flags.error = 0;
1185 if (strcasecmp(argv[i], "warning") == 0) debug_flags.warning = 0;
1186 if (strcasecmp(argv[i], "info") == 0) debug_flags.info = 0;
1187 if (strcasecmp(argv[i], "calls") == 0) debug_flags.calls = 0;
1188 if (strcasecmp(argv[i], "data") == 0) debug_flags.data = 0;
1189 if (strcasecmp(argv[i], "all") == 0) memset(&debug_flags, 0, sizeof(debug_flags));
1190 }
1191
1192 return CLI_OK;
1193 }
1194
1195 int cmd_load_plugin(struct cli_def *cli, char *command, char **argv, int argc)
1196 {
1197 int i, firstfree = 0;
1198 if (argc != 1)
1199 {
1200 cli_print(cli, "Specify a plugin to load");
1201 return CLI_OK;
1202 }
1203
1204 for (i = 0; i < MAXPLUGINS; i++)
1205 {
1206 if (!*config->plugins[i] && !firstfree)
1207 firstfree = i;
1208 if (strcmp(config->plugins[i], argv[0]) == 0)
1209 {
1210 cli_print(cli, "Plugin is already loaded");
1211 return CLI_OK;
1212 }
1213 }
1214
1215 if (firstfree)
1216 {
1217 strncpy(config->plugins[firstfree], argv[0], sizeof(config->plugins[firstfree]) - 1);
1218 config->reload_config = 1;
1219 cli_print(cli, "Loading plugin %s", argv[0]);
1220 }
1221
1222 return CLI_OK;
1223 }
1224
1225 int cmd_remove_plugin(struct cli_def *cli, char *command, char **argv, int argc)
1226 {
1227 int i;
1228
1229 if (argc != 1)
1230 {
1231 cli_print(cli, "Specify a plugin to remove");
1232 return CLI_OK;
1233 }
1234
1235 for (i = 0; i < MAXPLUGINS; i++)
1236 {
1237 if (strcmp(config->plugins[i], argv[0]) == 0)
1238 {
1239 config->reload_config = 1;
1240 memset(config->plugins[i], 0, sizeof(config->plugins[i]));
1241 return CLI_OK;
1242 }
1243 }
1244
1245 cli_print(cli, "Plugin is not loaded");
1246 return CLI_OK;
1247 }
1248
1249 char *duration(time_t seconds)
1250 {
1251 static char *buf = NULL;
1252 if (!buf) buf = calloc(64, 1);
1253
1254 if (seconds > 86400)
1255 sprintf(buf, "%d days", (int)(seconds / 86400.0));
1256 else if (seconds > 60)
1257 sprintf(buf, "%02d:%02lu", (int)(seconds / 3600.0), seconds % 60);
1258 else
1259 sprintf(buf, "%lu sec", seconds);
1260 return buf;
1261 }
1262
1263 int cmd_uptime(struct cli_def *cli, char *command, char **argv, int argc)
1264 {
1265 FILE *fh;
1266 char buf[100], *p = buf, *loads[3];
1267 int i, num_sessions = 0;
1268 time_t time_now;
1269
1270 fh = fopen("/proc/loadavg", "r");
1271 fgets(buf, 100, fh);
1272 fclose(fh);
1273
1274 for (i = 0; i < 3; i++)
1275 loads[i] = strdup(strsep(&p, " "));
1276
1277 time(&time_now);
1278 strftime(buf, 99, "%H:%M:%S", localtime(&time_now));
1279
1280 for (i = 1; i < MAXSESSION; i++)
1281 if (session[i].opened) num_sessions++;
1282
1283 cli_print(cli, "%s up %s, %d users, load average: %s, %s, %s",
1284 buf,
1285 duration(abs(time_now - config->start_time)),
1286 num_sessions,
1287 loads[0], loads[1], loads[2]
1288 );
1289 for (i = 0; i < 3; i++)
1290 if (loads[i]) free(loads[i]);
1291
1292 cli_print(cli, "Bandwidth: %s", config->bandwidth);
1293
1294 return CLI_OK;
1295 }
1296
1297 int cmd_set(struct cli_def *cli, char *command, char **argv, int argc)
1298 {
1299 int i;
1300
1301 if (argc != 2)
1302 {
1303 cli_print(cli, "Usage: set <variable> <value>");
1304 return CLI_OK;
1305 }
1306
1307 for (i = 0; config_values[i].key; i++)
1308 {
1309 void *value = ((void *)config) + config_values[i].offset;
1310 if (strcmp(config_values[i].key, argv[0]) == 0)
1311 {
1312 // Found a value to set
1313 cli_print(cli, "Setting \"%s\" to \"%s\"", argv[0], argv[1]);
1314 switch (config_values[i].type)
1315 {
1316 case STRING:
1317 strncpy((char *)value, argv[1], config_values[i].size - 1);
1318 break;
1319 case INT:
1320 *(int *)value = atoi(argv[1]);
1321 break;
1322 case UNSIGNED_LONG:
1323 *(unsigned long *)value = atol(argv[1]);
1324 break;
1325 case SHORT:
1326 *(short *)value = atoi(argv[1]);
1327 break;
1328 case IP:
1329 *(unsigned *)value = inet_addr(argv[1]);
1330 break;
1331 case BOOL:
1332 if (strcasecmp(argv[1], "yes") == 0 || strcasecmp(argv[1], "true") == 0 || strcasecmp(argv[1], "1") == 0)
1333 *(int *)value = 1;
1334 else
1335 *(int *)value = 0;
1336 break;
1337 default:
1338 cli_print(cli, "Unknown variable type");
1339 break;
1340 }
1341 config->reload_config = 1;
1342 return CLI_OK;
1343 }
1344 }
1345
1346 cli_print(cli, "Unknown variable \"%s\"", argv[0]);
1347 return CLI_OK;
1348 }
1349
1350 int regular_stuff(struct cli_def *cli)
1351 {
1352 int i = debug_rb_tail;
1353 int reprompt = 0;
1354
1355 #ifdef RINGBUFFER
1356 while (i != ringbuffer->tail)
1357 {
1358 int show_message = 0;
1359
1360 if (*ringbuffer->buffer[i].message)
1361 {
1362 // Always show messages if we are doing general debug
1363 if (ringbuffer->buffer[i].level == 0 && debug_flags.critical) show_message = 1;
1364 if (ringbuffer->buffer[i].level == 1 && debug_flags.error) show_message = 1;
1365 if (ringbuffer->buffer[i].level == 2 && debug_flags.warning) show_message = 1;
1366 if (ringbuffer->buffer[i].level == 3 && debug_flags.info) show_message = 1;
1367 if (ringbuffer->buffer[i].level == 4 && debug_flags.calls) show_message = 1;
1368 if (ringbuffer->buffer[i].level == 5 && debug_flags.data) show_message = 1;
1369 }
1370
1371 if (show_message)
1372 {
1373 ipt address = htonl(ringbuffer->buffer[i].address);
1374 char *ipaddr;
1375 struct in_addr addr;
1376
1377 memcpy(&addr, &address, sizeof(ringbuffer->buffer[i].address));
1378 ipaddr = inet_ntoa(addr);
1379
1380 cli_print(cli, "\r%s-%s-%u-%u %s",
1381 debug_levels[(int)ringbuffer->buffer[i].level],
1382 ipaddr,
1383 ringbuffer->buffer[i].tunnel,
1384 ringbuffer->buffer[i].session,
1385 ringbuffer->buffer[i].message);
1386
1387 reprompt = 1;
1388 }
1389
1390 if (++i == ringbuffer->tail) break;
1391 if (i == RINGBUFFER_SIZE) i = 0;
1392 }
1393
1394 debug_rb_tail = ringbuffer->tail;
1395 if (reprompt)
1396 cli_reprompt(cli);
1397 #endif
1398 return CLI_OK;
1399 }