X-Git-Url: http://git.sameswireless.fr/l2tpns.git/blobdiff_plain/0133cf7236592e66398a35e6aedddba71b755393..60d1a5f35a8c00b142d3f33c6f948b983cb53e00:/cli.c?ds=inline

diff --git a/cli.c b/cli.c
index 986361a..9a70875 100644
--- a/cli.c
+++ b/cli.c
@@ -2,10 +2,11 @@
 // vim: sw=8 ts=8
 
 char const *cvs_name = "$Name:  $";
-char const *cvs_id_cli = "$Id: cli.c,v 1.30 2004-11-27 20:41:41 bodea Exp $";
+char const *cvs_id_cli = "$Id: cli.c,v 1.46 2005-01-10 07:17:37 bodea Exp $";
 
 #include <stdio.h>
 #include <stdarg.h>
+#include <unistd.h>
 #include <sys/file.h>
 #include <sys/stat.h>
 #include <syslog.h>
@@ -19,9 +20,10 @@ char const *cvs_id_cli = "$Id: cli.c,v 1.30 2004-11-27 20:41:41 bodea Exp $";
 #include <sys/socket.h>
 #include <sys/types.h>
 #include <signal.h>
-#include <unistd.h>
 #include <dlfcn.h>
+#include <netdb.h>
 #include <libcli.h>
+
 #include "l2tpns.h"
 #include "util.h"
 #include "cluster.h"
@@ -29,7 +31,6 @@ char const *cvs_id_cli = "$Id: cli.c,v 1.30 2004-11-27 20:41:41 bodea Exp $";
 #include "ll.h"
 #ifdef BGP
 #include "bgp.h"
-#include <netdb.h>
 #endif
 
 extern tunnelt *tunnel;
@@ -97,6 +98,7 @@ static int cmd_set(struct cli_def *cli, char *command, char **argv, int argc);
 static int cmd_load_plugin(struct cli_def *cli, char *command, char **argv, int argc);
 static int cmd_remove_plugin(struct cli_def *cli, char *command, char **argv, int argc);
 static int cmd_uptime(struct cli_def *cli, char *command, char **argv, int argc);
+
 static int regular_stuff(struct cli_def *cli);
 static void parsemac(char *string, char mac[6]);
 
@@ -115,6 +117,9 @@ static int cmd_restart_bgp(struct cli_def *cli, char *command, char **argv, int
 static int cmd_ip_access_list(struct cli_def *cli, char *command, char **argv, int argc);
 static int cmd_no_ip_access_list(struct cli_def *cli, char *command, char **argv, int argc);
 static int cmd_ip_access_list_rule(struct cli_def *cli, char *command, char **argv, int argc);
+static int cmd_filter(struct cli_def *cli, char *command, char **argv, int argc);
+static int cmd_no_filter(struct cli_def *cli, char *command, char **argv, int argc);
+static int cmd_show_access_list(struct cli_def *cli, char *command, char **argv, int argc);
 
 /* match if b is a substr of a */
 #define MATCH(a,b) (!strncmp((a), (b), strlen(b)))
@@ -151,6 +156,7 @@ void init_cli(char *hostname)
 	cli_register_command(cli, c, "tunnels", cmd_show_tunnels, PRIVILEGE_UNPRIVILEGED, MODE_EXEC, "Show a list of tunnels or details for a single tunnel");
 	cli_register_command(cli, c, "users", cmd_show_users, PRIVILEGE_UNPRIVILEGED, MODE_EXEC, "Show a list of all connected users or details of selected user");
 	cli_register_command(cli, c, "version", cmd_show_version, PRIVILEGE_UNPRIVILEGED, MODE_EXEC, "Show currently running software version");
+	cli_register_command(cli, c, "access-list", cmd_show_access_list, PRIVILEGE_UNPRIVILEGED, MODE_EXEC, "Show named access-list");
 
 	c2 = cli_register_command(cli, c, "histogram", NULL, PRIVILEGE_UNPRIVILEGED, MODE_EXEC, NULL);
 	cli_register_command(cli, c2, "idle", cmd_show_hist_idle, PRIVILEGE_UNPRIVILEGED, MODE_EXEC, "Show histogram of session idle times");
@@ -169,8 +175,9 @@ void init_cli(char *hostname)
 	cli_register_command(cli, c, "memory", cmd_write_memory, PRIVILEGE_PRIVILEGED, MODE_EXEC, "Save the running config to flash");
 	cli_register_command(cli, c, "terminal", cmd_show_run, PRIVILEGE_UNPRIVILEGED, MODE_EXEC, "Show the running config");
 
-	cli_register_command(cli, NULL, "snoop", cmd_snoop, PRIVILEGE_PRIVILEGED, MODE_EXEC, "Temporarily enable interception for a user");
-	cli_register_command(cli, NULL, "throttle", cmd_throttle, PRIVILEGE_PRIVILEGED, MODE_EXEC, "Temporarily enable throttling for a user");
+	cli_register_command(cli, NULL, "snoop", cmd_snoop, PRIVILEGE_PRIVILEGED, MODE_EXEC, "Enable interception of a session");
+	cli_register_command(cli, NULL, "throttle", cmd_throttle, PRIVILEGE_PRIVILEGED, MODE_EXEC, "Enable throttling of a session");
+	cli_register_command(cli, NULL, "filter", cmd_filter, PRIVILEGE_PRIVILEGED, MODE_EXEC, "Add filtering to a session");
 	cli_register_command(cli, NULL, "debug", cmd_debug, PRIVILEGE_UNPRIVILEGED, MODE_EXEC, "Set the level of logging that is shown on the console");
 
 #ifdef BGP
@@ -179,8 +186,9 @@ void init_cli(char *hostname)
 #endif /* BGP */
 
 	c = cli_register_command(cli, NULL, "no", NULL, PRIVILEGE_UNPRIVILEGED, MODE_EXEC, NULL);
-	cli_register_command(cli, c, "snoop", cmd_no_snoop, PRIVILEGE_PRIVILEGED, MODE_EXEC, "Temporarily disable interception for a user");
-	cli_register_command(cli, c, "throttle", cmd_no_throttle, PRIVILEGE_PRIVILEGED, MODE_EXEC, "Temporarily disable throttling for a user");
+	cli_register_command(cli, c, "snoop", cmd_no_snoop, PRIVILEGE_PRIVILEGED, MODE_EXEC, "Disable interception of a session");
+	cli_register_command(cli, c, "throttle", cmd_no_throttle, PRIVILEGE_PRIVILEGED, MODE_EXEC, "Disable throttling of a session");
+	cli_register_command(cli, c, "filter", cmd_no_filter, PRIVILEGE_PRIVILEGED, MODE_EXEC, "Remove filtering from a session");
 	cli_register_command(cli, c, "debug", cmd_no_debug, PRIVILEGE_UNPRIVILEGED, MODE_EXEC, "Turn off logging of a certain level of debugging");
 
 #ifdef BGP
@@ -227,7 +235,7 @@ void init_cli(char *hostname)
 
 	if (!(f = fopen(CLIUSERS, "r")))
 	{
-		LOG(0, 0, 0, 0, "WARNING! No users specified. Command-line access is open to all\n");
+		LOG(0, 0, 0, "WARNING! No users specified. Command-line access is open to all\n");
 	}
 	else
 	{
@@ -243,12 +251,12 @@ void init_cli(char *hostname)
 			if (!strcmp(buf, "enable"))
 			{
 				cli_allow_enable(cli, p);
-				LOG(3, 0, 0, 0, "Setting enable password\n");
+				LOG(3, 0, 0, "Setting enable password\n");
 			}
 			else
 			{
 				cli_allow_user(cli, buf, p);
-				LOG(3, 0, 0, 0, "Allowing user %s to connect to the CLI\n", buf);
+				LOG(3, 0, 0, "Allowing user %s to connect to the CLI\n", buf);
 			}
 		}
 		fclose(f);
@@ -267,7 +275,7 @@ void init_cli(char *hostname)
 	addr.sin_port = htons(23);
 	if (bind(clifd, (void *) &addr, sizeof(addr)) < 0)
 	{
-		LOG(0, 0, 0, 0, "Error listening on cli port 23: %s\n", strerror(errno));
+		LOG(0, 0, 0, "Error listening on cli port 23: %s\n", strerror(errno));
 		return;
 	}
 	listen(clifd, 10);
@@ -282,18 +290,18 @@ void cli_do(int sockfd)
 	if (fork_and_close()) return;
 	if (getpeername(sockfd, (struct sockaddr *)&addr, &l) == 0)
 	{
-		LOG(3, 0, 0, 0, "Accepted connection to CLI from %s\n", inet_toa(addr.sin_addr.s_addr));
+		LOG(3, 0, 0, "Accepted connection to CLI from %s\n", fmtaddr(addr.sin_addr.s_addr, 0));
 		require_auth = addr.sin_addr.s_addr != inet_addr("127.0.0.1");
 	}
 	else
-		LOG(0, 0, 0, 0, "getpeername() failed on cli socket.  Requiring authentication: %s\n", strerror(errno));
+		LOG(0, 0, 0, "getpeername() failed on cli socket.  Requiring authentication: %s\n", strerror(errno));
 
 	if (require_auth)
 	{
-		LOG(3, 0, 0, 0, "CLI is remote, requiring authentication\n");
+		LOG(3, 0, 0, "CLI is remote, requiring authentication\n");
 		if (!cli->users) /* paranoia */
 		{
-			LOG(0, 0, 0, 0, "No users for remote authentication!  Exiting CLI\n");
+			LOG(0, 0, 0, "No users for remote authentication!  Exiting CLI\n");
 			exit(0);
 		}
 	}
@@ -314,18 +322,18 @@ void cli_do(int sockfd)
 	cli_loop(cli, sockfd);
 
 	close(sockfd);
-	LOG(3, 0, 0, 0, "Closed CLI connection from %s\n", inet_toa(addr.sin_addr.s_addr));
+	LOG(3, 0, 0, "Closed CLI connection from %s\n", fmtaddr(addr.sin_addr.s_addr, 0));
 	exit(0);
 }
 
 static void cli_print_log(struct cli_def *cli, char *string)
 {
-	LOG(3, 0, 0, 0, "%s\n", string);
+	LOG(3, 0, 0, "%s\n", string);
 }
 
 void cli_do_file(FILE *fh)
 {
-	LOG(3, 0, 0, 0, "Reading configuration file\n");
+	LOG(3, 0, 0, "Reading configuration file\n");
 	cli_print_callback(cli, cli_print_log);
 	cli_file(cli, fh, PRIVILEGE_PRIVILEGED, MODE_CONFIG);
 	cli_print_callback(cli, NULL);
@@ -394,23 +402,23 @@ static int cmd_show_session(struct cli_def *cli, char *command, char **argv, int
 			cli_print(cli, "\tCalling Num:\t%s", session[s].calling);
 			cli_print(cli, "\tCalled Num:\t%s", session[s].called);
 			cli_print(cli, "\tTunnel ID:\t%d", session[s].tunnel);
-			cli_print(cli, "\tIP address:\t%s", inet_toa(htonl(session[s].ip)));
+			cli_print(cli, "\tIP address:\t%s", fmtaddr(htonl(session[s].ip), 0));
 			cli_print(cli, "\tUnique SID:\t%lu", session[s].unique_id);
 			cli_print(cli, "\tIdle time:\t%u seconds", abs(time_now - session[s].last_packet));
 			cli_print(cli, "\tNext Recv:\t%u", session[s].nr);
 			cli_print(cli, "\tNext Send:\t%u", session[s].ns);
-			cli_print(cli, "\tBytes In/Out:\t%lu/%lu", (unsigned long)session[s].total_cout, (unsigned long)session[s].total_cin);
-			cli_print(cli, "\tPkts In/Out:\t%lu/%lu", (unsigned long)session[s].pout, (unsigned long)session[s].pin);
+			cli_print(cli, "\tBytes In/Out:\t%u/%u", session[s].total_cout, session[s].total_cin);
+			cli_print(cli, "\tPkts In/Out:\t%u/%u", session[s].pout, session[s].pin);
 			cli_print(cli, "\tMRU:\t\t%d", session[s].mru);
 			cli_print(cli, "\tRadius Session:\t%u", session[s].radius);
-			cli_print(cli, "\tRx Speed:\t%lu", session[s].rx_connect_speed);
-			cli_print(cli, "\tTx Speed:\t%lu", session[s].tx_connect_speed);
+			cli_print(cli, "\tRx Speed:\t%u", session[s].rx_connect_speed);
+			cli_print(cli, "\tTx Speed:\t%u", session[s].tx_connect_speed);
 			if (session[s].filter_in && session[s].filter_in <= MAXFILTER)
-				cli_print(cli, "\tFilter in:\t%u (%s)", session[s].filter_in, filters[session[s].filter_in-1].name);
+				cli_print(cli, "\tFilter in:\t%u (%s)", session[s].filter_in, ip_filters[session[s].filter_in - 1].name);
 			if (session[s].filter_out && session[s].filter_out <= MAXFILTER)
-				cli_print(cli, "\tFilter out:\t%u (%s)", session[s].filter_out, filters[session[s].filter_out-1].name);
+				cli_print(cli, "\tFilter out:\t%u (%s)", session[s].filter_out, ip_filters[session[s].filter_out - 1].name);
 			if (session[s].snoop_ip && session[s].snoop_port)
-				cli_print(cli, "\tIntercepted:\t%s:%d", inet_toa(session[s].snoop_ip), session[s] .snoop_port);
+				cli_print(cli, "\tIntercepted:\t%s:%d", fmtaddr(session[s].snoop_ip, 0), session[s] .snoop_port);
 			else
 				cli_print(cli, "\tIntercepted:\tno");
 
@@ -484,15 +492,12 @@ static int cmd_show_session(struct cli_def *cli, char *command, char **argv, int
 
 	for (i = 1; i < MAXSESSION; i++)
 	{
-		char *userip, *tunnelip;
 		if (!session[i].opened) continue;
-		userip = strdup(inet_toa(htonl(session[i].ip)));
-		tunnelip = strdup(inet_toa(htonl(tunnel[ session[i].tunnel ].ip)));
 		cli_print(cli, "%5d %4d %-32s %-15s %s %s %s %10u %10lu %10lu %4u %-15s %s",
 				i,
 				session[i].tunnel,
 				session[i].user[0] ? session[i].user : "*",
-				userip,
+				fmtaddr(htonl(session[i].ip), 0),
 				(session[i].snoop_ip && session[i].snoop_port) ? "Y" : "N",
 				(session[i].throttle_in || session[i].throttle_out) ? "Y" : "N",
 				(session[i].walled_garden) ? "Y" : "N",
@@ -500,10 +505,8 @@ static int cmd_show_session(struct cli_def *cli, char *command, char **argv, int
 				(unsigned long)session[i].total_cout,
 				(unsigned long)session[i].total_cin,
 				abs(time_now - (session[i].last_packet ? session[i].last_packet : time_now)),
-				tunnelip,
+				fmtaddr(htonl(tunnel[ session[i].tunnel ].ip), 1),
 				session[i].calling[0] ? session[i].calling : "*");
-		if (userip) free(userip);
-		if (tunnelip) free(tunnelip);
 	}
 	return CLI_OK;
 }
@@ -554,7 +557,7 @@ static int cmd_show_tunnels(struct cli_def *cli, char *command, char **argv, int
 				cli_print(cli, "\r\nTunnel %d:", t);
 				cli_print(cli, "\tState:\t\t%s", states[tunnel[t].state]);
 				cli_print(cli, "\tHostname:\t%s", tunnel[t].hostname[0] ? tunnel[t].hostname : "(none)");
-				cli_print(cli, "\tRemote IP:\t%s", inet_toa(htonl(tunnel[t].ip)));
+				cli_print(cli, "\tRemote IP:\t%s", fmtaddr(htonl(tunnel[t].ip), 0));
 				cli_print(cli, "\tRemote Port:\t%d", tunnel[t].port);
 				cli_print(cli, "\tRx Window:\t%u", tunnel[t].window);
 				cli_print(cli, "\tNext Recv:\t%u", tunnel[t].nr);
@@ -589,7 +592,7 @@ static int cmd_show_tunnels(struct cli_def *cli, char *command, char **argv, int
 		cli_print(cli, "%4d %20s %20s %6s %6d",
 				i,
 				*tunnel[i].hostname ? tunnel[i].hostname : "(null)",
-				inet_toa(htonl(tunnel[i].ip)),
+				fmtaddr(htonl(tunnel[i].ip), 0),
 				states[tunnel[i].state],
 				sessions);
 	}
@@ -643,24 +646,24 @@ static int cmd_show_counters(struct cli_def *cli, char *command, char **argv, in
 	if (CLI_HELP_REQUESTED)
 		return CLI_HELP_NO_ARGS;
 
-	cli_print(cli, "%-10s %-8s %-10s %-8s", "Ethernet", "Bytes", "Packets", "Errors");
-	cli_print(cli, "%-10s %8lu %8lu %8lu", "RX",
+	cli_print(cli, "%-10s %10s %8s %8s %8s", "Ethernet", "Bytes", "Packets", "Errors", "Dropped");
+	cli_print(cli, "%-10s %10u %8u %8u %8u", "RX",
 			GET_STAT(tun_rx_bytes),
 			GET_STAT(tun_rx_packets),
-			GET_STAT(tun_rx_errors));
-	cli_print(cli, "%-10s %8lu %8lu %8lu", "TX",
+			GET_STAT(tun_rx_errors),
+			GET_STAT(tun_rx_dropped));
+	cli_print(cli, "%-10s %10u %8u %8u", "TX",
 			GET_STAT(tun_tx_bytes),
 			GET_STAT(tun_tx_packets),
 			GET_STAT(tun_tx_errors));
 	cli_print(cli, "");
 
-	cli_print(cli, "%-10s %-8s %-10s %-8s %-8s", "Tunnel", "Bytes", "Packets", "Errors", "Retries");
-	cli_print(cli, "%-10s %8lu %8lu %8lu %8lu", "RX",
+	cli_print(cli, "%-10s %10s %8s %8s %8s", "Tunnel", "Bytes", "Packets", "Errors", "Retries");
+	cli_print(cli, "%-10s %10u %8u %8u", "RX",
 			GET_STAT(tunnel_rx_bytes),
 			GET_STAT(tunnel_rx_packets),
-			GET_STAT(tunnel_rx_errors),
-			0L);
-	cli_print(cli, "%-10s %8lu %8lu %8lu %8lu", "TX",
+			GET_STAT(tunnel_rx_errors));
+	cli_print(cli, "%-10s %10u %8u %8u %8u", "TX",
 			GET_STAT(tunnel_tx_bytes),
 			GET_STAT(tunnel_tx_packets),
 			GET_STAT(tunnel_tx_errors),
@@ -669,52 +672,56 @@ static int cmd_show_counters(struct cli_def *cli, char *command, char **argv, in
 
 	cli_print(cli, "%-30s%-10s", "Counter", "Value");
 	cli_print(cli, "-----------------------------------------");
-	cli_print(cli, "%-30s%lu", "radius_retries",		GET_STAT(radius_retries));
-	cli_print(cli, "%-30s%lu", "arp_sent",			GET_STAT(arp_sent));
-	cli_print(cli, "%-30s%lu", "packets_snooped",		GET_STAT(packets_snooped));
-	cli_print(cli, "%-30s%lu", "tunnel_created",		GET_STAT(tunnel_created));
-	cli_print(cli, "%-30s%lu", "session_created",		GET_STAT(session_created));
-	cli_print(cli, "%-30s%lu", "tunnel_timeout",		GET_STAT(tunnel_timeout));
-	cli_print(cli, "%-30s%lu", "session_timeout",		GET_STAT(session_timeout));
-	cli_print(cli, "%-30s%lu", "radius_timeout",		GET_STAT(radius_timeout));
-	cli_print(cli, "%-30s%lu", "radius_overflow",		GET_STAT(radius_overflow));
-	cli_print(cli, "%-30s%lu", "tunnel_overflow",		GET_STAT(tunnel_overflow));
-	cli_print(cli, "%-30s%lu", "session_overflow",		GET_STAT(session_overflow));
-	cli_print(cli, "%-30s%lu", "ip_allocated",		GET_STAT(ip_allocated));
-	cli_print(cli, "%-30s%lu", "ip_freed",			GET_STAT(ip_freed));
-	cli_print(cli, "%-30s%lu", "cluster_forwarded",		GET_STAT(c_forwarded));
-	cli_print(cli, "%-30s%lu", "recv_forward",		GET_STAT(recv_forward));
+	cli_print(cli, "%-30s%u", "radius_retries",		GET_STAT(radius_retries));
+	cli_print(cli, "%-30s%u", "arp_sent",			GET_STAT(arp_sent));
+	cli_print(cli, "%-30s%u", "packets_snooped",		GET_STAT(packets_snooped));
+	cli_print(cli, "%-30s%u", "tunnel_created",		GET_STAT(tunnel_created));
+	cli_print(cli, "%-30s%u", "session_created",		GET_STAT(session_created));
+	cli_print(cli, "%-30s%u", "tunnel_timeout",		GET_STAT(tunnel_timeout));
+	cli_print(cli, "%-30s%u", "session_timeout",		GET_STAT(session_timeout));
+	cli_print(cli, "%-30s%u", "radius_timeout",		GET_STAT(radius_timeout));
+	cli_print(cli, "%-30s%u", "radius_overflow",		GET_STAT(radius_overflow));
+	cli_print(cli, "%-30s%u", "tunnel_overflow",		GET_STAT(tunnel_overflow));
+	cli_print(cli, "%-30s%u", "session_overflow",		GET_STAT(session_overflow));
+	cli_print(cli, "%-30s%u", "ip_allocated",		GET_STAT(ip_allocated));
+	cli_print(cli, "%-30s%u", "ip_freed",			GET_STAT(ip_freed));
+	cli_print(cli, "%-30s%u", "cluster_forwarded",		GET_STAT(c_forwarded));
+	cli_print(cli, "%-30s%u", "recv_forward",		GET_STAT(recv_forward));
+	cli_print(cli, "%-30s%u", "select_called",		GET_STAT(select_called));
+	cli_print(cli, "%-30s%u", "multi_read_used",		GET_STAT(multi_read_used));
+	cli_print(cli, "%-30s%u", "multi_read_exceeded",	GET_STAT(multi_read_exceeded));
 
 
 #ifdef STATISTICS
 	cli_print(cli, "\n%-30s%-10s", "Counter", "Value");
 	cli_print(cli, "-----------------------------------------");
-	cli_print(cli, "%-30s%lu", "call_processtun",		GET_STAT(call_processtun));
-	cli_print(cli, "%-30s%lu", "call_processipout",		GET_STAT(call_processipout));
-	cli_print(cli, "%-30s%lu", "call_processudp",		GET_STAT(call_processudp));
-	cli_print(cli, "%-30s%lu", "call_processpap",		GET_STAT(call_processpap));
-	cli_print(cli, "%-30s%lu", "call_processchap",		GET_STAT(call_processchap));
-	cli_print(cli, "%-30s%lu", "call_processlcp",		GET_STAT(call_processlcp));
-	cli_print(cli, "%-30s%lu", "call_processipcp",		GET_STAT(call_processipcp));
-	cli_print(cli, "%-30s%lu", "call_processipin",		GET_STAT(call_processipin));
-	cli_print(cli, "%-30s%lu", "call_processccp",		GET_STAT(call_processccp));
-	cli_print(cli, "%-30s%lu", "call_processrad",		GET_STAT(call_processrad));
-	cli_print(cli, "%-30s%lu", "call_sendarp",		GET_STAT(call_sendarp));
-	cli_print(cli, "%-30s%lu", "call_sendipcp",		GET_STAT(call_sendipcp));
-	cli_print(cli, "%-30s%lu", "call_sendchap",		GET_STAT(call_sendchap));
-	cli_print(cli, "%-30s%lu", "call_sessionbyip",		GET_STAT(call_sessionbyip));
-	cli_print(cli, "%-30s%lu", "call_sessionbyuser",	GET_STAT(call_sessionbyuser));
-	cli_print(cli, "%-30s%lu", "call_tunnelsend",		GET_STAT(call_tunnelsend));
-	cli_print(cli, "%-30s%lu", "call_tunnelkill",		GET_STAT(call_tunnelkill));
-	cli_print(cli, "%-30s%lu", "call_tunnelshutdown",	GET_STAT(call_tunnelshutdown));
-	cli_print(cli, "%-30s%lu", "call_sessionkill",		GET_STAT(call_sessionkill));
-	cli_print(cli, "%-30s%lu", "call_sessionshutdown",	GET_STAT(call_sessionshutdown));
-	cli_print(cli, "%-30s%lu", "call_sessionsetup",		GET_STAT(call_sessionsetup));
-	cli_print(cli, "%-30s%lu", "call_assign_ip_address",	GET_STAT(call_assign_ip_address));
-	cli_print(cli, "%-30s%lu", "call_free_ip_address",	GET_STAT(call_free_ip_address));
-	cli_print(cli, "%-30s%lu", "call_dump_acct_info",	GET_STAT(call_dump_acct_info));
-	cli_print(cli, "%-30s%lu", "call_radiussend",		GET_STAT(call_radiussend));
-	cli_print(cli, "%-30s%lu", "call_radiusretry",		GET_STAT(call_radiusretry));
+	cli_print(cli, "%-30s%u", "call_processtun",		GET_STAT(call_processtun));
+	cli_print(cli, "%-30s%u", "call_processipout",		GET_STAT(call_processipout));
+	cli_print(cli, "%-30s%u", "call_processudp",		GET_STAT(call_processudp));
+	cli_print(cli, "%-30s%u", "call_processpap",		GET_STAT(call_processpap));
+	cli_print(cli, "%-30s%u", "call_processchap",		GET_STAT(call_processchap));
+	cli_print(cli, "%-30s%u", "call_processlcp",		GET_STAT(call_processlcp));
+	cli_print(cli, "%-30s%u", "call_processipcp",		GET_STAT(call_processipcp));
+	cli_print(cli, "%-30s%u", "call_processipin",		GET_STAT(call_processipin));
+	cli_print(cli, "%-30s%u", "call_processccp",		GET_STAT(call_processccp));
+	cli_print(cli, "%-30s%u", "call_processrad",		GET_STAT(call_processrad));
+	cli_print(cli, "%-30s%u", "call_sendarp",		GET_STAT(call_sendarp));
+	cli_print(cli, "%-30s%u", "call_sendipcp",		GET_STAT(call_sendipcp));
+	cli_print(cli, "%-30s%u", "call_sendchap",		GET_STAT(call_sendchap));
+	cli_print(cli, "%-30s%u", "call_sessionbyip",		GET_STAT(call_sessionbyip));
+	cli_print(cli, "%-30s%u", "call_sessionbyuser",		GET_STAT(call_sessionbyuser));
+	cli_print(cli, "%-30s%u", "call_tunnelsend",		GET_STAT(call_tunnelsend));
+	cli_print(cli, "%-30s%u", "call_tunnelkill",		GET_STAT(call_tunnelkill));
+	cli_print(cli, "%-30s%u", "call_tunnelshutdown",	GET_STAT(call_tunnelshutdown));
+	cli_print(cli, "%-30s%u", "call_sessionkill",		GET_STAT(call_sessionkill));
+	cli_print(cli, "%-30s%u", "call_sessionshutdown",	GET_STAT(call_sessionshutdown));
+	cli_print(cli, "%-30s%u", "call_sessionsetup",		GET_STAT(call_sessionsetup));
+	cli_print(cli, "%-30s%u", "call_assign_ip_address",	GET_STAT(call_assign_ip_address));
+	cli_print(cli, "%-30s%u", "call_free_ip_address",	GET_STAT(call_free_ip_address));
+	cli_print(cli, "%-30s%u", "call_dump_acct_info",	GET_STAT(call_dump_acct_info));
+	cli_print(cli, "%-30s%u", "call_radiussend",		GET_STAT(call_radiussend));
+	cli_print(cli, "%-30s%u", "call_radiusretry",		GET_STAT(call_radiusretry));
+	cli_print(cli, "%-30s%u", "call_random_data",		GET_STAT(call_random_data));
 #endif
 	return CLI_OK;
 }
@@ -753,7 +760,7 @@ static int cmd_show_version(struct cli_def *cli, char *command, char **argv, int
 			p = "HEAD";
 
 		e = strpbrk(p, " \t$");
-		cli_print(cli, "Tag: %.*s", e ? e - p + 1 : strlen(p), p);
+		cli_print(cli, "Tag: %.*s", (int) (e ? e - p + 1 : strlen(p)), p);
 	}
 	
 	if (file)
@@ -798,7 +805,9 @@ static int cmd_show_pool(struct cli_def *cli, char *command, char **argv, int ar
 
 	if (!config->cluster_iam_master)
 	{
-		cli_print(cli, "Can't do this on a slave.  Do it on %s", inet_toa(config->cluster_master_address));
+		cli_print(cli, "Can't do this on a slave.  Do it on %s",
+			fmtaddr(config->cluster_master_address, 0));
+
 		return CLI_OK;
 	}
 
@@ -823,7 +832,9 @@ static int cmd_show_pool(struct cli_def *cli, char *command, char **argv, int ar
 		if (ip_address_pool[i].assigned)
 		{
 			cli_print(cli, "%-15s\tY %8d %s",
-				inet_toa(htonl(ip_address_pool[i].address)), ip_address_pool[i].session, session[ip_address_pool[i].session].user);
+				fmtaddr(htonl(ip_address_pool[i].address), 0),
+				ip_address_pool[i].session,
+				session[ip_address_pool[i].session].user);
 
 			used++;
 		}
@@ -831,10 +842,11 @@ static int cmd_show_pool(struct cli_def *cli, char *command, char **argv, int ar
 		{
 			if (ip_address_pool[i].last)
 				cli_print(cli, "%-15s\tN %8s [%s] %ds",
-					inet_toa(htonl(ip_address_pool[i].address)), "",
-					ip_address_pool[i].user, time_now - ip_address_pool[i].last);
+					fmtaddr(htonl(ip_address_pool[i].address), 0), "",
+					ip_address_pool[i].user, (int) time_now - ip_address_pool[i].last);
+
 			else if (show_all)
-				cli_print(cli, "%-15s\tN", inet_toa(htonl(ip_address_pool[i].address)));
+				cli_print(cli, "%-15s\tN", fmtaddr(htonl(ip_address_pool[i].address), 0));
 
 			free++;
 		}
@@ -880,6 +892,7 @@ static char const *show_access_list_rule(int extended, ip_filter_rulet *rule);
 static int cmd_show_run(struct cli_def *cli, char *command, char **argv, int argc)
 {
 	int i;
+	char ipv6addr[INET6_ADDRSTRLEN];
 
 	if (CLI_HELP_REQUESTED)
 		return CLI_HELP_NO_ARGS;
@@ -890,25 +903,27 @@ static int cmd_show_run(struct cli_def *cli, char *command, char **argv, int arg
 	{
 		void *value = ((void *)config) + config_values[i].offset;
 		if (config_values[i].type == STRING)
-			cli_print(cli, "set %s \"%.*s\"", config_values[i].key, config_values[i].size, (char *)value);
-		else if (config_values[i].type == IP)
-			cli_print(cli, "set %s %s", config_values[i].key, inet_toa(*(unsigned *)value));
+			cli_print(cli, "set %s \"%.*s\"", config_values[i].key, config_values[i].size, (char *) value);
+		else if (config_values[i].type == IPv4)
+			cli_print(cli, "set %s %s", config_values[i].key, fmtaddr(*(in_addr_t *) value, 0));
+		else if (config_values[i].type == IPv6)
+			cli_print(cli, "set %s %s", config_values[i].key, inet_ntop(AF_INET6, value, ipv6addr, INET6_ADDRSTRLEN));
 		else if (config_values[i].type == SHORT)
-			cli_print(cli, "set %s %hu", config_values[i].key, *(short *)value);
+			cli_print(cli, "set %s %hu", config_values[i].key, *(short *) value);
 		else if (config_values[i].type == BOOL)
-			cli_print(cli, "set %s %s", config_values[i].key, (*(int *)value) ? "yes" : "no");
+			cli_print(cli, "set %s %s", config_values[i].key, (*(int *) value) ? "yes" : "no");
 		else if (config_values[i].type == INT)
-			cli_print(cli, "set %s %d", config_values[i].key, *(int *)value);
+			cli_print(cli, "set %s %d", config_values[i].key, *(int *) value);
 		else if (config_values[i].type == UNSIGNED_LONG)
-			cli_print(cli, "set %s %lu", config_values[i].key, *(unsigned long *)value);
+			cli_print(cli, "set %s %lu", config_values[i].key, *(unsigned long *) value);
 		else if (config_values[i].type == MAC)
 			cli_print(cli, "set %s %02x%02x.%02x%02x.%02x%02x", config_values[i].key,
-					*(unsigned short *)(value + 0),
-					*(unsigned short *)(value + 1),
-					*(unsigned short *)(value + 2),
-					*(unsigned short *)(value + 3),
-					*(unsigned short *)(value + 4),
-					*(unsigned short *)(value + 5));
+					*(unsigned short *) (value + 0),
+					*(unsigned short *) (value + 1),
+					*(unsigned short *) (value + 2),
+					*(unsigned short *) (value + 3),
+					*(unsigned short *) (value + 4),
+					*(unsigned short *) (value + 5));
 	}
 
 	cli_print(cli, "# Plugins");
@@ -997,7 +1012,7 @@ static int cmd_show_radius(struct cli_def *cli, char *command, char **argv, int
 			NULL);
 	}
 
-	cli_print(cli, "%6s%6s%5s%6s%9s%9s%4s", "ID", "Radius", "Sock", "State", "Session", "Retry", "Try");
+	cli_print(cli, "%6s%7s%5s%6s%9s%9s%4s", "ID", "Radius", "Sock", "State", "Session", "Retry", "Try");
 
 	time(&time_now);
 
@@ -1013,7 +1028,7 @@ static int cmd_show_radius(struct cli_def *cli, char *command, char **argv, int
 
 		if (!show_all && radius[i].state == RADIUSNULL) continue;
 
-		cli_print(cli, "%6d%6d%5d%6s%9d%9u%4d",
+		cli_print(cli, "%6d%7d%5d%6s%9d%9u%4d",
 				i,
 				i >> RADIUS_SHIFT,
 				i & RADIUS_MASK,
@@ -1119,7 +1134,9 @@ static int cmd_drop_user(struct cli_def *cli, char *command, char **argv, int ar
 
 	if (!config->cluster_iam_master)
 	{
-		cli_print(cli, "Can't do this on a slave.  Do it on %s", inet_toa(config->cluster_master_address));
+		cli_print(cli, "Can't do this on a slave.  Do it on %s",
+			fmtaddr(config->cluster_master_address, 0));
+
 		return CLI_OK;
 	}
 
@@ -1158,7 +1175,9 @@ static int cmd_drop_tunnel(struct cli_def *cli, char *command, char **argv, int
 
 	if (!config->cluster_iam_master)
 	{
-		cli_print(cli, "Can't do this on a slave.  Do it on %s", inet_toa(config->cluster_master_address));
+		cli_print(cli, "Can't do this on a slave.  Do it on %s",
+			fmtaddr(config->cluster_master_address, 0));
+
 		return CLI_OK;
 	}
 
@@ -1206,7 +1225,9 @@ static int cmd_drop_session(struct cli_def *cli, char *command, char **argv, int
 
 	if (!config->cluster_iam_master)
 	{
-		cli_print(cli, "Can't do this on a slave.  Do it on %s", inet_toa(config->cluster_master_address));
+		cli_print(cli, "Can't do this on a slave.  Do it on %s",
+			fmtaddr(config->cluster_master_address, 0));
+
 		return CLI_OK;
 	}
 
@@ -1240,8 +1261,8 @@ static int cmd_drop_session(struct cli_def *cli, char *command, char **argv, int
 
 static int cmd_snoop(struct cli_def *cli, char *command, char **argv, int argc)
 {
-	ipt ip;
-	u16 port;
+	in_addr_t ip;
+	uint16_t port;
 	sessionidt s;
 
 	if (CLI_HELP_REQUESTED)
@@ -1271,7 +1292,9 @@ static int cmd_snoop(struct cli_def *cli, char *command, char **argv, int argc)
 
 	if (!config->cluster_iam_master)
 	{
-		cli_print(cli, "Can't do this on a slave.  Do it on %s", inet_toa(config->cluster_master_address));
+		cli_print(cli, "Can't do this on a slave.  Do it on %s",
+			fmtaddr(config->cluster_master_address, 0));
+
 		return CLI_OK;
 	}
 
@@ -1301,7 +1324,7 @@ static int cmd_snoop(struct cli_def *cli, char *command, char **argv, int argc)
 		return CLI_OK;
 	}
 
-	cli_print(cli, "Snooping user %s to %s:%d", argv[0], inet_toa(ip), port);
+	cli_print(cli, "Snooping user %s to %s:%d", argv[0], fmtaddr(ip, 0), port);
 	cli_session_actions[s].snoop_ip = ip;
 	cli_session_actions[s].snoop_port = port;
 	cli_session_actions[s].action |= CLI_SESS_SNOOP;
@@ -1320,7 +1343,9 @@ static int cmd_no_snoop(struct cli_def *cli, char *command, char **argv, int arg
 
 	if (!config->cluster_iam_master)
 	{
-		cli_print(cli, "Can't do this on a slave.  Do it on %s", inet_toa(config->cluster_master_address));
+		cli_print(cli, "Can't do this on a slave.  Do it on %s",
+			fmtaddr(config->cluster_master_address, 0));
+
 		return CLI_OK;
 	}
 
@@ -1392,7 +1417,9 @@ static int cmd_throttle(struct cli_def *cli, char *command, char **argv, int arg
 
 	if (!config->cluster_iam_master)
 	{
-		cli_print(cli, "Can't do this on a slave.  Do it on %s", inet_toa(config->cluster_master_address));
+		cli_print(cli, "Can't do this on a slave.  Do it on %s",
+			fmtaddr(config->cluster_master_address, 0));
+
 		return CLI_OK;
 	}
 
@@ -1426,11 +1453,10 @@ static int cmd_throttle(struct cli_def *cli, char *command, char **argv, int arg
 		int i;
 		for (i = 1; i < argc - 1; i += 2)
 		{
-			int len = strlen(argv[i]);
 			int r = 0;
-			if (!strncasecmp(argv[i], "in", len))
+			if (MATCH("in", argv[i]))
 				r = rate_in = atoi(argv[i+1]);
-			else if (!strncasecmp(argv[i], "out", len))
+			else if (MATCH("out", argv[i]))
 				r = rate_out = atoi(argv[i+1]);
 
 			if (r < 1)
@@ -1483,7 +1509,9 @@ static int cmd_no_throttle(struct cli_def *cli, char *command, char **argv, int
 
 	if (!config->cluster_iam_master)
 	{
-		cli_print(cli, "Can't do this on a slave.  Do it on %s", inet_toa(config->cluster_master_address));
+		cli_print(cli, "Can't do this on a slave.  Do it on %s",
+			fmtaddr(config->cluster_master_address, 0));
+
 		return CLI_OK;
 	}
 
@@ -1560,13 +1588,13 @@ static int cmd_debug(struct cli_def *cli, char *command, char **argv, int argc)
 		if (argv[i][0] == 'c' && len < 2)
 			len = 2; /* distinguish [cr]itical from [ca]lls */
 
-		if (!strncasecmp(argv[i], "critical", len)) { debug_flags.critical = 1; continue; }
-		if (!strncasecmp(argv[i], "error",    len)) { debug_flags.error = 1;    continue; }
-		if (!strncasecmp(argv[i], "warning",  len)) { debug_flags.warning = 1;  continue; }
-		if (!strncasecmp(argv[i], "info",     len)) { debug_flags.info = 1;     continue; }
-		if (!strncasecmp(argv[i], "calls",    len)) { debug_flags.calls = 1;    continue; }
-		if (!strncasecmp(argv[i], "data",     len)) { debug_flags.data = 1;     continue; }
-		if (!strncasecmp(argv[i], "all",      len))
+		if (!strncmp("critical", argv[i], len)) { debug_flags.critical = 1; continue; }
+		if (!strncmp("error",    argv[i], len)) { debug_flags.error = 1;    continue; }
+		if (!strncmp("warning",  argv[i], len)) { debug_flags.warning = 1;  continue; }
+		if (!strncmp("info",     argv[i], len)) { debug_flags.info = 1;     continue; }
+		if (!strncmp("calls",    argv[i], len)) { debug_flags.calls = 1;    continue; }
+		if (!strncmp("data",     argv[i], len)) { debug_flags.data = 1;     continue; }
+		if (!strncmp("all",      argv[i], len))
 		{
 			memset(&debug_flags, 1, sizeof(debug_flags));
 			debug_flags.data = 0;
@@ -1607,13 +1635,13 @@ static int cmd_no_debug(struct cli_def *cli, char *command, char **argv, int arg
 		if (argv[i][0] == 'c' && len < 2)
 			len = 2; /* distinguish [cr]itical from [ca]lls */
 
-		if (!strncasecmp(argv[i], "critical", len)) { debug_flags.critical = 0; continue; }
-		if (!strncasecmp(argv[i], "error",    len)) { debug_flags.error = 0;    continue; }
-		if (!strncasecmp(argv[i], "warning",  len)) { debug_flags.warning = 0;  continue; }
-		if (!strncasecmp(argv[i], "info",     len)) { debug_flags.info = 0;     continue; }
-		if (!strncasecmp(argv[i], "calls",    len)) { debug_flags.calls = 0;    continue; }
-		if (!strncasecmp(argv[i], "data",     len)) { debug_flags.data = 0;     continue; }
-		if (!strncasecmp(argv[i], "all",      len))
+		if (!strncmp("critical", argv[i], len)) { debug_flags.critical = 0; continue; }
+		if (!strncmp("error",    argv[i], len)) { debug_flags.error = 0;    continue; }
+		if (!strncmp("warning",  argv[i], len)) { debug_flags.warning = 0;  continue; }
+		if (!strncmp("info",     argv[i], len)) { debug_flags.info = 0;     continue; }
+		if (!strncmp("calls",    argv[i], len)) { debug_flags.calls = 0;    continue; }
+		if (!strncmp("data",     argv[i], len)) { debug_flags.data = 0;     continue; }
+		if (!strncmp("all",      argv[i], len))
 		{
 			memset(&debug_flags, 0, sizeof(debug_flags));
 			continue;
@@ -1769,7 +1797,7 @@ static int cmd_set(struct cli_def *cli, char *command, char **argv, int argc)
 			{
 				int len = strlen(argv[0])-1;
 				for (i = 0; config_values[i].key; i++)
-					if (!len || !strncmp(argv[0], config_values[i].key, len))
+					if (!len || !strncmp(config_values[i].key, argv[0], len))
 						cli_print(cli, "  %s", config_values[i].key);
 			}
 
@@ -1796,7 +1824,7 @@ static int cmd_set(struct cli_def *cli, char *command, char **argv, int argc)
 
 	for (i = 0; config_values[i].key; i++)
 	{
-		void *value = ((void *)config) + config_values[i].offset;
+		void *value = ((void *) config) + config_values[i].offset;
 		if (strcmp(config_values[i].key, argv[0]) == 0)
 		{
 			// Found a value to set
@@ -1804,28 +1832,31 @@ static int cmd_set(struct cli_def *cli, char *command, char **argv, int argc)
 			switch (config_values[i].type)
 			{
 			case STRING:
-				strncpy((char *)value, argv[1], config_values[i].size - 1);
+				snprintf((char *) value, config_values[i].size, "%s", argv[1]);
 				break;
 			case INT:
-				*(int *)value = atoi(argv[1]);
+				*(int *) value = atoi(argv[1]);
 				break;
 			case UNSIGNED_LONG:
-				*(unsigned long *)value = atol(argv[1]);
+				*(unsigned long *) value = atol(argv[1]);
 				break;
 			case SHORT:
-				*(short *)value = atoi(argv[1]);
+				*(short *) value = atoi(argv[1]);
+				break;
+			case IPv4:
+				*(in_addr_t *) value = inet_addr(argv[1]);
 				break;
-			case IP:
-				*(unsigned *)value = inet_addr(argv[1]);
+			case IPv6:
+				inet_pton(AF_INET6, argv[1], value);
 				break;
 			case MAC:
 				parsemac(argv[1], (char *)value);
 				break;
 			case BOOL:
 				if (strcasecmp(argv[1], "yes") == 0 || strcasecmp(argv[1], "true") == 0 || strcasecmp(argv[1], "1") == 0)
-					*(int *)value = 1;
+					*(int *) value = 1;
 				else
-					*(int *)value = 0;
+					*(int *) value = 0;
 				break;
 			default:
 				cli_print(cli, "Unknown variable type");
@@ -1842,50 +1873,44 @@ static int cmd_set(struct cli_def *cli, char *command, char **argv, int argc)
 
 int regular_stuff(struct cli_def *cli)
 {
-	int i = debug_rb_tail;
-	int reprompt = 0;
+	int out = 0;
+	int i;
 
 #ifdef RINGBUFFER
-	while (i != ringbuffer->tail)
+	for (i = debug_rb_tail; i != ringbuffer->tail; i = (i + 1) % RINGBUFFER_SIZE)
 	{
-		int show_message = 0;
+		char *m = ringbuffer->buffer[i].message;
+		char *p;
+		int show = 0;
 
-		if (*ringbuffer->buffer[i].message)
-		{
-			// Always show messages if we are doing general debug
-			if (ringbuffer->buffer[i].level == 0 && debug_flags.critical) show_message = 1;
-			if (ringbuffer->buffer[i].level == 1 && debug_flags.error)    show_message = 1;
-			if (ringbuffer->buffer[i].level == 2 && debug_flags.warning)  show_message = 1;
-			if (ringbuffer->buffer[i].level == 3 && debug_flags.info)     show_message = 1;
-			if (ringbuffer->buffer[i].level == 4 && debug_flags.calls)    show_message = 1;
-			if (ringbuffer->buffer[i].level == 5 && debug_flags.data)     show_message = 1;
-		}
+		if (!*m) continue;
 
-		if (show_message)
+		switch (ringbuffer->buffer[i].level)
 		{
-			ipt address = htonl(ringbuffer->buffer[i].address);
-			char *ipaddr;
-			struct in_addr addr;
+		case 0: show = debug_flags.critical;	break;
+		case 1: show = debug_flags.error;	break;
+		case 2: show = debug_flags.warning;	break;
+		case 3: show = debug_flags.info;	break;
+		case 4: show = debug_flags.calls;	break;
+		case 5: show = debug_flags.data;	break;
+		}
 
-			memcpy(&addr, &address, sizeof(ringbuffer->buffer[i].address));
-			ipaddr = inet_ntoa(addr);
+		if (!show) continue;
 
-			cli_print(cli, "\r%s-%s-%u-%u %s",
-					debug_levels[(int)ringbuffer->buffer[i].level],
-					ipaddr,
-					ringbuffer->buffer[i].tunnel,
-					ringbuffer->buffer[i].session,
-					ringbuffer->buffer[i].message);
+		if (!(p = strchr(m, '\n')))
+			p = m + strlen(p);
 
-			reprompt = 1;
-		}
+		cli_print(cli, "\r%s-%u-%u %.*s",
+			debug_levels[(int)ringbuffer->buffer[i].level],
+			ringbuffer->buffer[i].tunnel,
+			ringbuffer->buffer[i].session,
+			(int) (p - m), m);
 
-		if (++i == ringbuffer->tail) break;
-		if (i == RINGBUFFER_SIZE) i = 0;
+		out++;
 	}
 
 	debug_rb_tail = ringbuffer->tail;
-	if (reprompt)
+	if (out)
 		cli_reprompt(cli);
 #endif
 	return CLI_OK;
@@ -2029,7 +2054,7 @@ static int cmd_router_bgp_neighbour(struct cli_def *cli, char *command, char **a
 
 		if (!config->neighbour[i].name[0])
 		{
-			snprintf(config->neighbour[i].name, sizeof(config->neighbour[i].name), argv[0]);
+			snprintf(config->neighbour[i].name, sizeof(config->neighbour[i].name), "%s", argv[0]);
 			config->neighbour[i].keepalive = -1;
 			config->neighbour[i].hold = -1;
 		}
@@ -2125,7 +2150,7 @@ static int cmd_show_bgp(struct cli_def *cli, char *command, char **argv, int arg
 			NULL);
 
 	cli_print(cli, "BGPv%d router identifier %s, local AS number %d",
-		BGP_VERSION, inet_toa(my_address), (int) config->as_number);
+		BGP_VERSION, fmtaddr(my_address, 0), (int) config->as_number);
 
 	time(&time_now);
 
@@ -2134,7 +2159,7 @@ static int cmd_show_bgp(struct cli_def *cli, char *command, char **argv, int arg
 		if (!*bgp_peers[i].name)
 			continue;
 
-		addr = inet_toa(bgp_peers[i].addr);
+		addr = fmtaddr(bgp_peers[i].addr, 0);
 		if (argc && strcmp(addr, argv[0]) &&
 		    strncmp(bgp_peers[i].name, argv[0], strlen(argv[0])))
 			continue;
@@ -2148,7 +2173,7 @@ static int cmd_show_bgp(struct cli_def *cli, char *command, char **argv, int arg
 			    "----------- ------- -------- ----- ---- ---------");
 		}
 
-		cli_print(cli, "%-18.18s %5d %15s %-11s %7d %7ds %5s %4s %4d %4d",
+		cli_print(cli, "%-18.18s %5d %15s %-11s %7d %7lds %5s %4s %4d %4d",
 			bgp_peers[i].name,
 			bgp_peers[i].as,
 			addr,
@@ -2186,7 +2211,7 @@ static int cmd_suspend_bgp(struct cli_def *cli, char *command, char **argv, int
 		if (!bgp_peers[i].routing)
 			continue;
 
-		addr = inet_toa(bgp_peers[i].addr);
+		addr = fmtaddr(bgp_peers[i].addr, 0);
 		if (argc && strcmp(addr, argv[0]) && strcmp(bgp_peers[i].name, argv[0]))
 			continue;
 
@@ -2219,7 +2244,7 @@ static int cmd_no_suspend_bgp(struct cli_def *cli, char *command, char **argv, i
 		if (bgp_peers[i].routing)
 			continue;
 
-		addr = inet_toa(bgp_peers[i].addr);
+		addr = fmtaddr(bgp_peers[i].addr, 0);
 		if (argc && strcmp(addr, argv[0]) &&
 		    strncmp(bgp_peers[i].name, argv[0], strlen(argv[0])))
 			continue;
@@ -2250,7 +2275,7 @@ static int cmd_restart_bgp(struct cli_def *cli, char *command, char **argv, int
 		if (!*bgp_peers[i].name)
 			continue;
 
-		addr = inet_toa(bgp_peers[i].addr);
+		addr = fmtaddr(bgp_peers[i].addr, 0);
 		if (argc && strcmp(addr, argv[0]) &&
 		    strncmp(bgp_peers[i].name, argv[0], strlen(argv[0])))
 			continue;
@@ -2380,17 +2405,15 @@ static int cmd_no_ip_access_list(struct cli_def *cli, char *command, char **argv
 	return access_list(cli, argv, argc, 0);
 }
 
-static int show_ip_wild(char *buf, ipt ip, ipt wild)
+static int show_ip_wild(char *buf, in_addr_t ip, in_addr_t wild)
 {
-	int i;
 	if (ip == INADDR_ANY && wild == INADDR_BROADCAST)
 		return sprintf(buf, " any");
 
 	if (wild == INADDR_ANY)
-		return sprintf(buf, " host %s", inet_toa(ip));
+		return sprintf(buf, " host %s", fmtaddr(ip, 0));
 
-	i = sprintf(buf, " %s", inet_toa(ip));
-	return i + sprintf(buf + i, " %s", inet_toa(wild));
+	return sprintf(buf, " %s %s", fmtaddr(ip, 0), fmtaddr(wild, 1));
 }
 
 static int show_ports(char *buf, ip_filter_portt *ports)
@@ -2430,16 +2453,16 @@ static char const *show_access_list_rule(int extended, ip_filter_rulet *rule)
 	if (rule->proto == IPPROTO_TCP || rule->proto == IPPROTO_UDP)
 		p += show_ports(p, &rule->dst_ports);
 
-	if (rule->proto == IPPROTO_TCP && (rule->tcp_sflags || rule->tcp_cflags))
+	if (rule->proto == IPPROTO_TCP && rule->tcp_flag_op)
 	{
-		if (rule->tcp_flag_op == FILTER_FLAG_OP_ANY &&
-		    rule->tcp_sflags == (TCP_FLAG_ACK|TCP_FLAG_FIN) &&
-		    rule->tcp_cflags == TCP_FLAG_SYN)
+		switch (rule->tcp_flag_op)
 		{
+		case FILTER_FLAG_OP_EST:
 			p += sprintf(p, " established");
-		}
-		else
-		{
+			break;
+
+		case FILTER_FLAG_OP_ANY:
+		case FILTER_FLAG_OP_ALL:
 		    	p += sprintf(p, " match-%s", rule->tcp_flag_op == FILTER_FLAG_OP_ALL ? "all" : "any");
 			if (rule->tcp_sflags & TCP_FLAG_FIN) p += sprintf(p, " +fin");
 			if (rule->tcp_cflags & TCP_FLAG_FIN) p += sprintf(p, " -fin");
@@ -2453,9 +2476,13 @@ static char const *show_access_list_rule(int extended, ip_filter_rulet *rule)
 			if (rule->tcp_cflags & TCP_FLAG_ACK) p += sprintf(p, " -ack");
 			if (rule->tcp_sflags & TCP_FLAG_URG) p += sprintf(p, " +urg");
 			if (rule->tcp_cflags & TCP_FLAG_URG) p += sprintf(p, " -urg");
+			break;
 		}
 	}
 
+	if (rule->frag)
+		p += sprintf(p, " fragments");
+
 	return buf;
 }
 
@@ -2509,8 +2536,8 @@ ip_filter_rulet *access_list_rule_ext(struct cli_def *cli, char *command, char *
 
 	for (a = 1, i = 0; i < 2; i++)
 	{
-	    	ipt *ip;
-		ipt *wild;
+	    	in_addr_t *ip;
+		in_addr_t *wild;
 		ip_filter_portt *port;
 
 		if (i == 0)
@@ -2557,7 +2584,7 @@ ip_filter_rulet *access_list_rule_ext(struct cli_def *cli, char *command, char *
 		}
 		else
 		{
-			if (++a >= argc)
+			if (a >= argc - 1)
 			{
 				cli_print(cli, "Specify %s ip address and wildcard", i ? "destination" : "source");
 				return NULL;
@@ -2578,6 +2605,7 @@ ip_filter_rulet *access_list_rule_ext(struct cli_def *cli, char *command, char *
 			}
 
 			*wild = addr.s_addr;
+			a++;
 		}
 
 		if (rule.proto == IPPROTO_IP || a >= argc)
@@ -2633,9 +2661,7 @@ ip_filter_rulet *access_list_rule_ext(struct cli_def *cli, char *command, char *
 	{
 		if (MATCH("established", argv[a]))
 		{
-			rule.tcp_flag_op = FILTER_FLAG_OP_ANY;
-			rule.tcp_sflags = (TCP_FLAG_ACK|TCP_FLAG_FIN);
-			rule.tcp_cflags = TCP_FLAG_SYN;
+			rule.tcp_flag_op = FILTER_FLAG_OP_EST;
 		    	a++;
 		}
 		else if (!strcmp(argv[a], "match-any") || !strcmp(argv[a], "match-an") ||
@@ -2653,7 +2679,7 @@ ip_filter_rulet *access_list_rule_ext(struct cli_def *cli, char *command, char *
 
 			while (a < argc && (argv[a][0] == '+' || argv[a][0] == '-'))
 			{
-			    	u8 *f;
+			    	uint8_t *f;
 
 				f = (argv[a][0] == '+') ? &rule.tcp_sflags : &rule.tcp_cflags;
 
@@ -2674,6 +2700,18 @@ ip_filter_rulet *access_list_rule_ext(struct cli_def *cli, char *command, char *
 		}
 	}
 
+	if (a < argc && MATCH("fragments", argv[a]))
+	{
+		if (rule.src_ports.op || rule.dst_ports.op || rule.tcp_flag_op)
+		{
+			cli_print(cli, "Can't specify \"fragments\" on rules with layer 4 matches");
+			return NULL;
+		}
+
+	    	rule.frag = 1;
+		a++;
+	}
+
 	if (a < argc)
 	{
 		cli_print(cli, "Invalid flag \"%s\"", argv[a]);
@@ -2825,6 +2863,192 @@ static int cmd_ip_access_list_rule(struct cli_def *cli, char *command, char **ar
 	return CLI_OK;
 }
 
+static int cmd_filter(struct cli_def *cli, char *command, char **argv, int argc)
+{
+	sessionidt s;
+	int i;
+
+	/* filter USER {in|out} FILTER ... */
+	if (CLI_HELP_REQUESTED)
+	{
+		switch (argc)
+		{
+		case 1:
+			return cli_arg_help(cli, 0,
+				"USER", "Username of session to filter", NULL);
+
+		case 2:
+		case 4:
+			return cli_arg_help(cli, 0,
+				"in",   "Set incoming filter",
+				"out",  "Set outgoing filter", NULL);
+
+		case 3:
+		case 5:
+			return cli_arg_help(cli, argc == 5 && argv[4][1],
+				"NAME", "Filter name", NULL);
+
+		default:
+			return cli_arg_help(cli, argc > 1, NULL);
+		}
+	}
+
+	if (!config->cluster_iam_master)
+	{
+		cli_print(cli, "Can't do this on a slave.  Do it on %s",
+			fmtaddr(config->cluster_master_address, 0));
+
+		return CLI_OK;
+	}
+
+	if (argc != 3 && argc != 5)
+	{
+		cli_print(cli, "Specify a user and filters");
+		return CLI_OK;
+	}
+
+	if (!(s = sessionbyuser(argv[0])))
+	{
+		cli_print(cli, "User %s is not connected", argv[0]);
+		return CLI_OK;
+	}
+
+	cli_session_actions[s].filter_in = cli_session_actions[s].filter_out = -1;
+	for (i = 1; i < argc; i += 2)
+	{
+		int *f = 0;
+		int v;
+
+		if (MATCH("in", argv[i]))
+		{
+			if (session[s].filter_in)
+			{
+				cli_print(cli, "Input already filtered");
+				return CLI_OK;
+			}
+			f = &cli_session_actions[s].filter_in;
+		}
+		else if (MATCH("out", argv[i]))
+		{
+			if (session[s].filter_out)
+			{
+				cli_print(cli, "Output already filtered");
+				return CLI_OK;
+			}
+			f = &cli_session_actions[s].filter_out;
+		}
+		else
+		{
+			cli_print(cli, "Invalid filter specification");
+			return CLI_OK;
+		}
+
+		v = find_access_list(argv[i+1]);
+		if (v < 0 || !*ip_filters[v].name)
+		{
+			cli_print(cli, "Access-list %s not defined", argv[i+1]);
+			return CLI_OK;
+		}
+
+		*f = v + 1;
+	}
+
+	cli_print(cli, "Filtering user %s", argv[0]);
+	cli_session_actions[s].action |= CLI_SESS_FILTER;
+
+	return CLI_OK;
+}
+
+static int cmd_no_filter(struct cli_def *cli, char *command, char **argv, int argc)
+{
+	int i;
+	sessionidt s;
+
+	if (CLI_HELP_REQUESTED)
+		return cli_arg_help(cli, argc > 1,
+			"USER", "Username of session to remove filters from", NULL);
+
+	if (!config->cluster_iam_master)
+	{
+		cli_print(cli, "Can't do this on a slave.  Do it on %s",
+			fmtaddr(config->cluster_master_address, 0));
+
+		return CLI_OK;
+	}
+
+	if (!argc)
+	{
+		cli_print(cli, "Specify a user to remove filters from");
+		return CLI_OK;
+	}
+
+	for (i = 0; i < argc; i++)
+	{
+		if (!(s = sessionbyuser(argv[i])))
+		{
+			cli_print(cli, "User %s is not connected", argv[i]);
+			continue;
+		}
+
+		if (session[s].filter_in || session[s].filter_out)
+		{
+			cli_print(cli, "Removing filters from user %s", argv[i]);
+			cli_session_actions[s].action |= CLI_SESS_NOFILTER;
+		}
+		else
+		{
+			cli_print(cli, "User %s not filtered", argv[i]);
+		}
+	}
+
+	return CLI_OK;
+}
+
+static int cmd_show_access_list(struct cli_def *cli, char *command, char **argv, int argc)
+{
+	int i;
+
+	if (CLI_HELP_REQUESTED)
+		return cli_arg_help(cli, argc > 1, "NAME", "Filter name", NULL);
+
+	if (argc < 1)
+	{
+		cli_print(cli, "Specify a filter name");
+		return CLI_OK;
+	}
+
+	for (i = 0; i < argc; i++)
+	{
+		int f = find_access_list(argv[i]);
+		ip_filter_rulet *rules;
+
+		if (f < 0 || !*ip_filters[f].name)
+		{
+			cli_print(cli, "Access-list %s not defined", argv[i]);
+			return CLI_OK;
+		}
+
+		if (i)
+			cli_print(cli, "");
+
+		cli_print(cli, "%s IP access list %s",
+			ip_filters[f].extended ? "Extended" : "Standard",
+			ip_filters[f].name);
+
+		for (rules = ip_filters[f].rules; rules->action; rules++)
+		{
+			char const *r = show_access_list_rule(ip_filters[f].extended, rules);
+		    	if (rules->counter)
+				cli_print(cli, "%s (%d match%s)", r,
+					rules->counter, rules->counter > 1 ? "es" : "");
+			else
+				cli_print(cli, "%s", r);
+		}
+	}
+
+	return CLI_OK;
+}
+
 // Convert a string in the form of abcd.ef12.3456 into char[6]
 void parsemac(char *string, char mac[6])
 {