From 0a29a72f55590ec82f57497072c2abfcc35fd3f6 Mon Sep 17 00:00:00 2001 From: bodea Date: Sun, 28 Nov 2004 02:53:11 +0000 Subject: [PATCH 1/1] update filter refcounts add cli commands for filtering/unfiltering --- cli.c | 190 +++++++++++++++++++++++++++++++++++++++++++++++-------- l2tpns.c | 85 ++++++++++++++++++++++++- l2tpns.h | 6 +- radius.c | 6 +- 4 files changed, 258 insertions(+), 29 deletions(-) diff --git a/cli.c b/cli.c index 2c0fd1e..714d9a4 100644 --- a/cli.c +++ b/cli.c @@ -2,7 +2,7 @@ // vim: sw=8 ts=8 char const *cvs_name = "$Name: $"; -char const *cvs_id_cli = "$Id: cli.c,v 1.31 2004/11/27 21:10:50 bodea Exp $"; +char const *cvs_id_cli = "$Id: cli.c,v 1.32 2004/11/28 02:53:11 bodea Exp $"; #include #include @@ -115,6 +115,8 @@ 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); /* match if b is a substr of a */ #define MATCH(a,b) (!strncmp((a), (b), strlen(b))) @@ -169,8 +171,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 +182,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 @@ -406,9 +410,9 @@ static int cmd_show_session(struct cli_def *cli, char *command, char **argv, int cli_print(cli, "\tRx Speed:\t%lu", session[s].rx_connect_speed); cli_print(cli, "\tTx Speed:\t%lu", 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, ip_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, ip_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); else @@ -1426,11 +1430,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) @@ -1560,13 +1563,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 +1610,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 +1772,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); } @@ -2826,6 +2829,143 @@ 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", inet_toa(config->cluster_master_address)); + 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", inet_toa(config->cluster_master_address)); + 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; +} + // Convert a string in the form of abcd.ef12.3456 into char[6] void parsemac(char *string, char mac[6]) { diff --git a/l2tpns.c b/l2tpns.c index 54b4667..16e5a29 100644 --- a/l2tpns.c +++ b/l2tpns.c @@ -4,7 +4,7 @@ // Copyright (c) 2002 FireBrick (Andrews & Arnold Ltd / Watchfront Ltd) - GPL licenced // vim: sw=8 ts=8 -char const *cvs_id_l2tpns = "$Id: l2tpns.c,v 1.57 2004/11/27 05:19:53 bodea Exp $"; +char const *cvs_id_l2tpns = "$Id: l2tpns.c,v 1.58 2004/11/28 02:53:11 bodea Exp $"; #include #include @@ -1002,6 +1002,44 @@ void throttle_session(sessionidt s, int rate_in, int rate_out) } } +// add/remove filters from session (-1 = no change) +void filter_session(sessionidt s, int filter_in, int filter_out) +{ + if (!session[s].tunnel) + return; // No-one home. + + if (!*session[s].user) + return; // User not logged in + + // paranoia + if (filter_in > MAXFILTER) filter_in = -1; + if (filter_out > MAXFILTER) filter_out = -1; + if (session[s].filter_in > MAXFILTER) session[s].filter_in = 0; + if (session[s].filter_out > MAXFILTER) session[s].filter_out = 0; + + if (filter_in >= 0) + { + if (session[s].filter_in) + ip_filters[session[s].filter_in - 1].used--; + + if (filter_in > 0) + ip_filters[filter_in - 1].used++; + + session[s].filter_in = filter_in; + } + + if (filter_out >= 0) + { + if (session[s].filter_out) + ip_filters[session[s].filter_out - 1].used--; + + if (filter_out > 0) + ip_filters[filter_out - 1].used++; + + session[s].filter_out = filter_out; + } +} + // start tidy shutdown of session void sessionshutdown(sessionidt s, char *reason) { @@ -1081,6 +1119,10 @@ void sessionshutdown(sessionidt s, char *reason) if (!session[s].die) session[s].die = now() + 150; // Clean up in 15 seconds + // update filter refcounts + if (session[s].filter_in) ip_filters[session[s].filter_in - 1].used--; + if (session[s].filter_out) ip_filters[session[s].filter_out - 1].used--; + cluster_send_session(s); } @@ -2131,6 +2173,22 @@ static int regular_cleanups(void) send++; } + if (a & CLI_SESS_NOFILTER) + { + LOG(2, 0, s, session[s].tunnel, "Un-filtering session by CLI\n"); + filter_session(s, 0, 0); + send++; + } + else if (a & CLI_SESS_FILTER) + { + LOG(2, 0, s, session[s].tunnel, "Filtering session by CLI (in=%d, out=%d)\n", + cli_session_actions[s].filter_in, + cli_session_actions[s].filter_out); + + filter_session(s, cli_session_actions[s].filter_in, cli_session_actions[s].filter_out); + send++; + } + if (send) cluster_send_session(s); @@ -3729,6 +3787,31 @@ int load_session(sessionidt s, sessiont *new) } } + // check filters + if (new->filter_in && (new->filter_in > MAXFILTER || !ip_filters[new->filter_in - 1].name[0])) + { + LOG(2, session[s].ip, s, session[s].tunnel, "Dropping invalid input filter %d\n", (int) new->filter_in); + new->filter_in = 0; + } + + if (new->filter_out && (new->filter_out > MAXFILTER || !ip_filters[new->filter_out - 1].name[0])) + { + LOG(2, session[s].ip, s, session[s].tunnel, "Dropping invalid output filter %d\n", (int) new->filter_out); + new->filter_out = 0; + } + + if (new->filter_in != session[s].filter_in) + { + if (session[s].filter_in) ip_filters[session[s].filter_in - 1].used--; + if (new->filter_in) ip_filters[new->filter_in - 1].used++; + } + + if (new->filter_out != session[s].filter_out) + { + if (session[s].filter_out) ip_filters[session[s].filter_out - 1].used--; + if (new->filter_out) ip_filters[new->filter_out - 1].used++; + } + if (new->tunnel && s > config->cluster_highest_sessionid) // Maintain this in the slave. It's used // for walking the sessions to forward byte counts to the master. config->cluster_highest_sessionid = s; diff --git a/l2tpns.h b/l2tpns.h index eb575a3..910504d 100644 --- a/l2tpns.h +++ b/l2tpns.h @@ -1,5 +1,5 @@ // L2TPNS Global Stuff -// $Id: l2tpns.h,v 1.38 2004/11/27 05:19:53 bodea Exp $ +// $Id: l2tpns.h,v 1.39 2004/11/28 02:53:11 bodea Exp $ #ifndef __L2TPNS_H__ #define __L2TPNS_H__ @@ -124,6 +124,8 @@ struct cli_session_actions { u16 snoop_port; int throttle_in; int throttle_out; + int filter_in; + int filter_out; }; #define CLI_SESS_KILL 0x01 @@ -131,6 +133,8 @@ struct cli_session_actions { #define CLI_SESS_NOSNOOP 0x04 #define CLI_SESS_THROTTLE 0x08 #define CLI_SESS_NOTHROTTLE 0x10 +#define CLI_SESS_FILTER 0x20 +#define CLI_SESS_NOFILTER 0x40 struct cli_tunnel_actions { char action; diff --git a/radius.c b/radius.c index fb295fb..fd3417c 100644 --- a/radius.c +++ b/radius.c @@ -1,6 +1,6 @@ // L2TPNS Radius Stuff -char const *cvs_id_radius = "$Id: radius.c,v 1.16 2004/11/27 21:10:51 bodea Exp $"; +char const *cvs_id_radius = "$Id: radius.c,v 1.17 2004/11/28 02:53:11 bodea Exp $"; #include #include @@ -573,7 +573,9 @@ void processrad(u8 *buf, int len, char socket_index) !strncmp(ip_filters[i].name, filter, l)) *f = i + 1; - if (!*f) + if (*f) + ip_filters[*f - 1].used++; + else LOG(3, 0, s, session[s].tunnel, " Unknown filter\n"); } -- 2.20.1