- Revise CCP, send ConfigReq once only.
authorBrendan O'Dea <bod@optus.net>
Sat, 27 Nov 2004 05:19:53 +0000 (05:19 +0000)
committerBrendan O'Dea <bod@optus.net>
Sat, 27 Nov 2004 05:19:53 +0000 (05:19 +0000)
- Check control serial before clearing window, prevents looping tunnel
  setup in some instances.
- Add configuration syntax for adding named access lists (work in progress).

Changes
Docs/manual.html
Docs/startup-config.5
cli.c
l2tpns.c
l2tpns.h
l2tpns.spec
ppp.c
radius.c

diff --git a/Changes b/Changes
index 59dde80..1d2bdcd 100644 (file)
--- a/Changes
+++ b/Changes
@@ -1,8 +1,11 @@
-* Thu Nov 25 2004 Brendan O'Dea <bod@optusnet.com.au> 2.0.9
+* Sat Nov 27 2004 Brendan O'Dea <bod@optusnet.com.au> 2.0.9
 - Revise CCP, send ConfigReq once only.
 - Don't copy the old buffer into Config{Nak,Rej} LCP responses (oops);
   add length checks when appending.
 - Have makeppp print a backtrace on overflow.
+- Check control serial before clearing window, prevents looping tunnel
+  setup in some instances.
+- Add configuration syntax for adding named access lists (work in progress).
 
 * Sat Nov 20 2004 Brendan O'Dea <bod@optusnet.com.au> 2.0.8
 - Ignore gateway address in Framed-Route (from Jonathan McDowell).
index 08d9408..13748a9 100644 (file)
@@ -52,7 +52,8 @@ H3 {
     <LI><A HREF="#Interception">Interception</A></LI>
     <LI><A HREF="#Authentication">Authentication</A></LI>
     <LI><A HREF="#Plugins">Plugins</A></LI>
-    <LI><A HREF="#Walled Garden">Walled Garden</A></LI>
+    <LI><A HREF="#WalledGarden">Walled Garden</A></LI>
+    <LI><A HREF="#Filtering">Filtering</A></LI>
     <LI><A HREF="#Clustering">Clustering</A></LI>
     <LI><A HREF="#Routing">Routing</A></LI>
     <LI><A HREF="#Performance">Performance</A></LI>
@@ -200,29 +201,34 @@ software upgrade.
 
 <LI><B>primary_radius</B> (ip address)
 <LI><B>secondary_radius</B> (ip address)<BR>
-Sets the radius servers used for both authentication and accounting. 
-If the primary server does not respond, then the secondary radius
-server will be tried.
+Sets the RADIUS servers used for both authentication and accounting. 
+If the primary server does not respond, then the secondary RADIUS
+server will be tried.<br>
+<strong>Note:</strong> in addition to the source IP address and
+identifier, the RADIUS server <strong>must</strong> include the source
+port when detecting duplicates to supress (in order to cope with a
+large number of sessions comming on-line simultaneously l2tpns uses a
+set of udp sockets, each with a seperate identifier).
 </LI>
 
 <LI><B>primary_radius_port</B> (short)
 <LI><B>secondary_radius_port</B> (short)<BR>
-Sets the authentication ports for the primary and secondary radius
+Sets the authentication ports for the primary and secondary RADIUS
 servers.  The accounting port is one more than the authentication
-port.  If no radius ports are given, the authentication port defaults
+port.  If no RADIUS ports are given, the authentication port defaults
 to 1645, and the accounting port to 1646.
 </LI>
 
 <LI><B>radius_accounting</B> (boolean)<BR>
-If set to true, then radius accounting packets will be sent.  This
+If set to true, then RADIUS accounting packets will be sent.  This
 means that a Start record will be sent when the session is
 successfully authenticated, and a Stop record will be sent when the
 session is closed.
 </LI>
 
 <LI><B>radius_secret</B> (string)<BR>
-This secret will be used in all radius queries.  If this is not set then
-radius queries will fail.
+This secret will be used in all RADIUS queries.  If this is not set then
+RADIUS queries will fail.
 </LI>
 
 <LI><B>bind_address</B> (ip address)<BR>
@@ -338,6 +344,40 @@ Where <I>peer</I> specifies the BGP neighbour as either a hostname or
 IP address, <I>as</I> is the remote AS number and <I>keepalive</I>,
 <I>hold</I> are the timer values in seconds.
 
+<P>Named access-lists are configured using one of the commands:
+<DL>
+  <DD><B>ip access-list standard</B> <I>name</I>
+  <DD><B>ip access-list extended</B> <I>name</I>
+</DL>
+
+<P>Subsequent lines prefixed with <B>permit</B> or <B>deny</B>
+define the body of the access-list.  Standard access-list syntax:
+<DL>
+  <DD>{<B>permit</B>|<B>deny</B>}
+    {<I>host</I>|<I>source source-wildcard</I>|<B>any</B>}
+    [{<I>host</I>|<I>destination destination-wildcard</I>|<B>any</B>}]
+</DL>
+
+Extended access-lists:
+
+<DL>
+  <DD>{<B>permit</B>|<B>deny</B>} <B>ip</B>
+    {<I>host</I>|<I>source source-wildcard</I>|<B>any</B>}
+    {<I>host</I>|<I>destination destination-wildcard</I>|<B>any</B>}
+  <DD>{<B>permit</B>|<B>deny</B>} <B>udp</B>
+    {<I>host</I>|<I>source source-wildcard</I>|<B>any</B>}
+       [{<B>eq</B>|<B>neq</B>|<B>gt</B>|<B>lt</B>} <I>port</I>|<B>range</B> <I>from</I> <I>to</I>]
+    {<I>host</I>|<I>destination destination-wildcard</I>|<B>any</B>}
+       [{<B>eq</B>|<B>neq</B>|<B>gt</B>|<B>lt</B>} <I>port</I>|<B>range</B> <I>from</I> <I>to</I>]
+  <DD>{<B>permit</B>|<B>deny</B>} <B>tcp</B>
+    {<I>host</I>|<I>source source-wildcard</I>|<B>any</B>}
+       [{<B>eq</B>|<B>neq</B>|<B>gt</B>|<B>lt</B>} <I>port</I>|<B>range</B> <I>from</I> <I>to</I>]
+    {<I>host</I>|<I>destination destination-wildcard</I>|<B>any</B>}
+       [{<B>eq</B>|<B>neq</B>|<B>gt</B>|<B>lt</B>} <I>port</I>|<B>range</B> <I>from</I> <I>to</I>]
+       [{<B>established</B>|{<B>match-any</B>|<B>match-all</B>}
+           {<B>+</B>|<B>-</B>}{<B>fin</B>|<B>syn</B>|<B>rst</B>|<B>psh</B>|<B>ack</B>|<B>urg</B>} ...]
+</DL>
+
 <H3 ID="users">users</H3>
 
 Usernames and passwords for the command-line interface are stored in
@@ -500,19 +540,19 @@ IP Address      Used  Session User
 </LI>
 
 <LI><B>show radius</B><BR>
-Show a summary of the in-use radius sessions.  This list should not be very
-long, as radius sessions should be cleaned up as soon as they are used.  The
+Show a summary of the in-use RADIUS sessions.  This list should not be very
+long, as RADIUS sessions should be cleaned up as soon as they are used.  The
 columns listed are:
 <TABLE>
-       <TR><TD><B>Radius</B></TD><TD>The ID of the radius request.  This is
-       sent in the packet to the radius server for identification.</TD></TR>
+       <TR><TD><B>Radius</B></TD><TD>The ID of the RADIUS request.  This is
+       sent in the packet to the RADIUS server for identification.</TD></TR>
        <TR><TD><B>State</B></TD><TD>The state of the request - WAIT, CHAP,
        AUTH, IPCP, START, STOP, NULL.</TD></TR>
-       <TR><TD><B>Session</B></TD><TD>The session ID that this radius
+       <TR><TD><B>Session</B></TD><TD>The session ID that this RADIUS
        request is associated with</TD></TR>
        <TR><TD><B>Retry</B></TD><TD>If a response does not appear to the
        request, it will retry at this time.  This is a unix timestamp.</TD></TR>
-       <TR><TD><B>Try</B></TD><TD>Retry count.  The radius request is
+       <TR><TD><B>Try</B></TD><TD>Retry count.  The RADIUS request is
        discarded after 3 retries.</TD></TR>
 </TABLE>
 <P>
@@ -553,7 +593,7 @@ current session for that username will be forwarded to the given
 host/port.  Specify <EM>no snoop username</EM> to disable interception
 for the session.<P>
 
-If you want interception to be permanent, you will have to modify the radius
+If you want interception to be permanent, you will have to modify the RADIUS
 response for the user.  See <A HREF="#Interception">Interception</A>.
 <P>
 </LI>
@@ -564,7 +604,7 @@ session.  Specify <EM>no throttle username</EM> to disable throttling
 for the current session.<P>
 
 If you want throttling to be permanent, you will have to modify the
-radius response for the user.  See <A HREF="#THrottling">Throttling</A>.
+RADIUS response for the user.  See <A HREF="#Throttling">Throttling</A>.
 <P>
 </LI>
 
@@ -660,7 +700,7 @@ desire.  You must first enable the global setting <EM>throttle_speed</EM>
 before this will be activated.<P>
 
 If you wish a session to be throttled permanently, you should set the
-Vendor-Specific radius value <B>Cisco-Avpair="throttle=yes"</B>, which
+Vendor-Specific RADIUS value <B>Cisco-Avpair="throttle=yes"</B>, which
 will be handled by the <EM>autothrottle</EM> module.<P>
 
 Otherwise, you can enable and disable throttling an active session using
@@ -684,7 +724,7 @@ and <EM>no snoop username</EM> CLI commands.  These will enable interception
 immediately.<P>
 
 If you wish the user to be intercepted whenever they reconnect, you will
-need to modify the radius response to include the Vendor-Specific value
+need to modify the RADIUS response to include the Vendor-Specific value
 <B>Cisco-Avpair="intercept=yes"</B>.  For this feature to be enabled,
 you need to have the <EM>autosnoop</EM> module loaded.<P>
 
@@ -694,11 +734,11 @@ Whenever a session connects, it is not fully set up until authentication is
 completed.  The remote end must send a PPP CHAP or PPP PAP authentication
 request to l2tpns.<P>
 
-This request is sent to the radius server, which will hopefully respond with
+This request is sent to the RADIUS server, which will hopefully respond with
 Auth-Accept or Auth-Reject.<P>
 
 If Auth-Accept is received, the session is set up and an IP address is
-assigned.  The radius server can include a Framed-IP-Address field in the
+assigned.  The RADIUS server can include a Framed-IP-Address field in the
 reply, and that address will be assigned to the client.  It can also include
 specific DNS servers, and a Framed-Route if that is required.<P>
 
@@ -708,7 +748,7 @@ walled garden module is loaded, in which case the user still receives the
 PPP AUTHACK, but their session is flagged as being a garden'd user, and they
 should not receive any service.<P>
 
-The radius reply can also contain a Vendor-Specific attribute called
+The RADIUS reply can also contain a Vendor-Specific attribute called
 Cisco-Avpair.  This field is a freeform text field that most Cisco
 devices understand to contain configuration instructions for the session.  In
 the case of l2tpns it is expected to be of the form
@@ -758,7 +798,7 @@ supplied structure:
 <TABLE CELLSPACING=1 CELLPADDING=3>
        <TR BGCOLOR=LIGHTGREEN><TH><B>Event</B></TH><TH><B>Description</B></TH><TH><B>Parameters</B></TH></TR>
        <TR VALIGN=TOP BGCOLOR=WHITE><TD><B>pre_auth</B></TD>
-               <TD>This is called after a radius response has been
+               <TD>This is called after a RADIUS response has been
                received, but before it has been processed by the
                code.  This will allow you to modify the response in
                some way.
@@ -775,7 +815,7 @@ supplied structure:
                </TD>
        </TR>
        <TR VALIGN=TOP BGCOLOR=WHITE><TD><B>post_auth</B></TD>
-               <TD>This is called after a radius response has been
+               <TD>This is called after a RADIUS response has been
                received, and the basic checks have been performed.  This
                is what the garden module uses to force authentication
                to be accepted.
@@ -855,7 +895,7 @@ supplied structure:
                </TD>
        </TR>
        <TR VALIGN=TOP BGCOLOR=WHITE><TD><B>radius_response</B></TD>
-               <TD>This is called whenever a radius response includes a
+               <TD>This is called whenever a RADIUS response includes a
                Cisco-Avpair value.  The value is split up into
                <EM>key=value</EM> pairs, and each is processed through all
                modules.
@@ -901,7 +941,7 @@ Walled Garden is implemented so that you can provide perhaps limited service
 to sessions that incorrectly authenticate.<P>
 
 Whenever a session provides incorrect authentication, and the
-radius server responds with Auth-Reject, the walled garden module
+RADIUS server responds with Auth-Reject, the walled garden module
 (if loaded) will force authentication to succeed, but set the flag
 <EM>garden</EM> in the session structure, and adds an iptables rule to
 the <B>garden_users</B> chain to force all packets for the session's IP
@@ -926,6 +966,14 @@ command:
 iptables -t nat -L garden -nvx
 </PRE>
 
+<H2 ID="Filtering">Filtering</H2>
+
+Sessions may be filtered by specifying <B>Filter-Id</B> attributes in
+the RADIUS reply.  <I>filter</I>.<B>in</B> specifies that the named
+access-list <I>filter</I> should be applied to traffic from the
+customer, <I>filter</I>.<B>out</B> specifies a list for traffic to the
+customer.
+
 <H2 ID="Clustering">Clustering</H2>
 
 An l2tpns cluster consists of of one* or more servers configured with
index fbc33ba..c1112ff 100644 (file)
@@ -2,7 +2,7 @@
 .de Id
 .ds Dt \\$4 \\$5
 ..
-.Id $Id: startup-config.5,v 1.1 2004-11-17 15:08:19 bodea Exp $
+.Id $Id: startup-config.5,v 1.2 2004-11-27 05:19:54 bodea Exp $
 .TH STARTUP-CONFIG 5 "\*(Dt" L2TPNS "File Formats and Conventions"
 .SH NAME
 startup\-config \- configuration file for l2tpns
@@ -199,5 +199,111 @@ is the remote AS number and
 .IR keepalive ,
 .I hold
 are the timer values in seconds.
+.SS NAMED ACCESS LISTS
+Named access lists may be defined with either of
+.IP
+.BI "ip access\-list standard " name
+.br
+.BI "ip access\-list extended " name
+.PP
+Subsequent lines starting with
+.B permit
+or
+.B deny
+define the body of the access\-list.
+.PP
+.B Standard Access Lists
+.RS 4n
+Standard access lists are defined with:
+.IP
+.RB { permit | deny }
+.IR source " [" dest ]
+.PP
+Where
+.I source
+and
+.I dest
+specify IP matches using one of:
+.IP
+.I address
+.I wildard
+.br
+.B host
+.I address
+.br
+.B any
+.PP
+.I address
+and
+.I wildard
+are in dotted-quad notation, bits in the
+.I wildard
+indicate which address bits in
+.I address
+are relevant to the match (0 = exact match; 1 = don't care).
+.PP
+The shorthand
+.RB ' host
+.IR address '
+is equivalent to
+.RI ' address
+.BR 0.0.0.0 ';
+.RB ' any '
+to
+.RB ' 0.0.0.0
+.BR 255.255.255.255 '.
+.RE
+.PP
+.B Extended Access Lists
+.RS 4n
+Extended access lists are defined with:
+.IP
+.RB { permit | deny }
+.I proto
+.IR source " [" ports "] " dest " [" ports "] [" flags ]
+.PP
+Where
+.I proto
+is one of
+.BR ip ,
+.B tcp
+or
+.BR udp ,
+and
+.I source
+and
+.I dest
+are as described above for standard lists.
+.PP
+For
+.B tcp
+and
+.B udp
+matches, source and destination may be optionally followed by a
+.I ports
+specification:
+.IP
+.RB { eq | neq | gt | lt }
+.I port
+.br
+.B
+range
+.I from to
+.PP
+.B tcp
+matches may also specify
+.I flags
+to match against tcp header flags:
+.IP
+.RB { match\-any | match\-all }
+.RB { + | - }{ fin | syn | rst | psh | ack | urg }
+\&...
+.br
+.B established
+.PP
+.RB ' established '
+is shorthand for
+.RB ' "match-any +ack +rst -syn" '.
+.RE
 .SH SEE ALSO
 .BR l2tpns (8)
diff --git a/cli.c b/cli.c
index 50712b1..967f4ae 100644 (file)
--- 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.28 2004-11-16 07:54:32 bodea Exp $";
+char const *cvs_id_cli = "$Id: cli.c,v 1.29 2004-11-27 05:19:53 bodea Exp $";
 
 #include <stdio.h>
 #include <stdarg.h>
@@ -38,14 +38,15 @@ extern radiust *radius;
 extern ippoolt *ip_address_pool;
 extern struct Tstats *_statistics;
 static struct cli_def *cli = NULL;
-extern struct configt *config;
-extern struct config_descriptt config_values[];
+extern configt *config;
+extern config_descriptt config_values[];
 #ifdef RINGBUFFER
 extern struct Tringbuffer *ringbuffer;
 #endif
 extern struct cli_session_actions *cli_session_actions;
 extern struct cli_tunnel_actions *cli_tunnel_actions;
 extern tbft *filter_list;
+extern ip_filtert *ip_filters;
 
 static char *debug_levels[] = {
        "CRIT",
@@ -110,6 +111,14 @@ static int cmd_no_suspend_bgp(struct cli_def *cli, char *command, char **argv, i
 static int cmd_restart_bgp(struct cli_def *cli, char *command, char **argv, int argc);
 #endif /* BGP */
 
+#define MODE_CONFIG_NACL 9
+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);
+
+/* match if b is a substr of a */
+#define MATCH(a,b) (!strncmp((a), (b), strlen(b)))
+
 void init_cli(char *hostname)
 {
        FILE *f;
@@ -203,6 +212,16 @@ void init_cli(char *hostname)
 
        cli_register_command(cli, NULL, "set", cmd_set, PRIVILEGE_PRIVILEGED, MODE_CONFIG, "Set a configuration variable");
 
+       c = cli_register_command(cli, NULL, "ip", NULL, PRIVILEGE_PRIVILEGED, MODE_CONFIG, NULL);
+       cli_register_command(cli, c, "access-list", cmd_ip_access_list, PRIVILEGE_PRIVILEGED, MODE_CONFIG, "Add named access-list");
+
+       cli_register_command(cli, NULL, "permit", cmd_ip_access_list_rule, PRIVILEGE_PRIVILEGED, MODE_CONFIG_NACL, "Permit rule");
+       cli_register_command(cli, NULL, "deny", cmd_ip_access_list_rule, PRIVILEGE_PRIVILEGED, MODE_CONFIG_NACL, "Deny rule");
+
+       c = cli_register_command(cli, NULL, "no", NULL, PRIVILEGE_UNPRIVILEGED, MODE_CONFIG, NULL);
+       c2 = cli_register_command(cli, c, "ip", NULL, PRIVILEGE_PRIVILEGED, MODE_CONFIG, NULL);
+       cli_register_command(cli, c2, "access-list", cmd_no_ip_access_list, PRIVILEGE_PRIVILEGED, MODE_CONFIG, "Remove named access-list");
+
        // Enable regular processing
        cli_regular(cli, regular_stuff);
 
@@ -267,7 +286,7 @@ void cli_do(int sockfd)
                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, 0, "getpeername() failed on cli socket.  Requiring authentication: %s\n", strerror(errno));
 
        if (require_auth)
        {
@@ -852,6 +871,8 @@ static int cmd_write_memory(struct cli_def *cli, char *command, char **argv, int
        return CLI_OK;
 }
 
+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;
@@ -898,17 +919,17 @@ static int cmd_show_run(struct cli_def *cli, char *command, char **argv, int arg
 #ifdef BGP
        if (config->as_number)
        {
-               int k;
+               int k;
                int h;
 
-               cli_print(cli, "# BGP");
+               cli_print(cli, "# BGP");
                cli_print(cli, "router bgp %u", config->as_number);
                for (i = 0; i < BGP_NUM_PEERS; i++)
                {
                        if (!config->neighbour[i].name[0])
                                continue;
 
-                       cli_print(cli, " neighbour %s remote-as %u", config->neighbour[i].name, config->neighbour[i].as);
+                       cli_print(cli, " neighbour %s remote-as %u", config->neighbour[i].name, config->neighbour[i].as);
 
                        k = config->neighbour[i].keepalive;
                        h = config->neighbour[i].hold;
@@ -929,6 +950,22 @@ static int cmd_show_run(struct cli_def *cli, char *command, char **argv, int arg
        }
 #endif
 
+       cli_print(cli, "# Filters");
+       for (i = 0; i < MAXFILTER; i++)
+       {
+               ip_filter_rulet *rules;
+               if (!*ip_filters[i].name)
+                       continue;
+
+               cli_print(cli, "ip access-list %s %s",
+                       ip_filters[i].extended ? "extended" : "standard",
+                       ip_filters[i].name);
+
+               rules = ip_filters[i].rules;
+               while (rules->action)
+                       cli_print(cli, "%s", show_access_list_rule(ip_filters[i].extended, rules++));
+       }
+
        cli_print(cli, "# end");
        return CLI_OK;
 }
@@ -1877,7 +1914,7 @@ static int cmd_router_bgp(struct cli_def *cli, char *command, char **argv, int a
        return CLI_OK;
 }
 
-static int find_bgp_neighbour(char *name)
+static int find_bgp_neighbour(char const *name)
 {
        int i;
        int new = -1;
@@ -1893,7 +1930,7 @@ static int find_bgp_neighbour(char *name)
 
        for (i = 0; i < BGP_NUM_PEERS; i++)
        {
-               if (!config->neighbour[i].name[0])
+               if (!config->neighbour[i].name[0])
                {
                        if (new == -1) new = i;
                        continue;
@@ -1940,12 +1977,12 @@ static int cmd_router_bgp_neighbour(struct cli_def *cli, char *command, char **a
                                NULL);
 
                default:
-                       if (!strncmp("remote-as", argv[1], strlen(argv[1])))
-                               return cli_arg_help(cli, argv[2][1], "<1-65535>", "Autonomous system number", NULL);
+                       if (MATCH("remote-as", argv[1]))
+                               return cli_arg_help(cli, argv[2][1], "<1-65535>", "Autonomous system number", NULL);
 
-                       if (!strncmp("timers", argv[1], strlen(argv[1])))
+                       if (MATCH("timers", argv[1]))
                        {
-                               if (argc == 3)
+                               if (argc == 3)
                                        return cli_arg_help(cli, 0, "<1-65535>", "Keepalive time", NULL);
 
                                if (argc == 4)
@@ -1977,9 +2014,9 @@ static int cmd_router_bgp_neighbour(struct cli_def *cli, char *command, char **a
                return CLI_OK;
        }
 
-       if (!strncmp("remote-as", argv[1], strlen(argv[1])))
+       if (MATCH("remote-as", argv[1]))
        {
-               int as = atoi(argv[2]);
+               int as = atoi(argv[2]);
                if (as < 0 || as > 65535)
                {
                        cli_print(cli, "Invalid autonomous system number");
@@ -1997,7 +2034,7 @@ static int cmd_router_bgp_neighbour(struct cli_def *cli, char *command, char **a
                return CLI_OK;
        }
 
-       if (argc != 4 || strncmp("timers", argv[1], strlen(argv[1])))
+       if (argc != 4 || !MATCH("timers", argv[1]))
        {
                cli_print(cli, "Invalid arguments");
                return CLI_OK;
@@ -2222,6 +2259,568 @@ static int cmd_restart_bgp(struct cli_def *cli, char *command, char **argv, int
 }
 #endif /* BGP*/
 
+static int filt;
+static int find_access_list(char const *name)
+{
+       int i;
+
+       for (i = 0; i < MAXFILTER; i++)
+               if (!(*ip_filters[i].name && strcmp(ip_filters[i].name, name)))
+                       return i;
+
+       return -1;
+}
+
+static int access_list(struct cli_def *cli, char **argv, int argc, int add)
+{
+       int extended;
+
+       if (CLI_HELP_REQUESTED)
+       {
+               switch (argc)
+               {
+               case 1:
+                       return cli_arg_help(cli, 0,
+                               "standard", "Standard syntax",
+                               "extended", "Extended syntax",
+                               NULL);
+
+               case 2:
+                       return cli_arg_help(cli, argv[1][1],
+                               "NAME", "Access-list name",
+                               NULL);
+
+               default:
+                       if (argc == 3 && !argv[2][1])
+                               return cli_arg_help(cli, 1, NULL);
+
+                       return CLI_OK;
+               }
+       }
+
+       if (argc != 2)
+       {
+               cli_print(cli, "Specify access-list type and name");
+               return CLI_OK;
+       }
+
+       if (MATCH("standard", argv[0]))
+               extended = 0;
+       else if (MATCH("extended", argv[0]))
+               extended = 1;
+       else
+       {
+               cli_print(cli, "Invalid access-list type");
+               return CLI_OK;
+       }
+
+       if (strlen(argv[1]) > sizeof(ip_filters[0].name) - 1 ||
+           strspn(argv[1], "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789_") != strlen(argv[1]))
+       {
+               cli_print(cli, "Invalid access-list name");
+               return CLI_OK;
+       }
+
+       filt = find_access_list(argv[1]);
+       if (add)
+       {
+               if (filt < 0)
+               {
+                       cli_print(cli, "Too many access-lists");
+                       return CLI_OK;
+               }
+
+               // racy
+               if (!*ip_filters[filt].name)
+               {
+                       memset(&ip_filters[filt], 0, sizeof(ip_filters[filt]));
+                       strcpy(ip_filters[filt].name, argv[1]);
+                       ip_filters[filt].extended = extended;
+               }
+               else if (ip_filters[filt].extended != extended)
+               {
+                       cli_print(cli, "Access-list is %s",
+                               ip_filters[filt].extended ? "extended" : "standard");
+
+                       return CLI_OK;
+               }
+
+               cli_set_configmode(cli, MODE_CONFIG_NACL, extended ? "ext-nacl" : "std-nacl");
+               return CLI_OK;
+       }
+
+       if (filt < 0 || !*ip_filters[filt].name)
+       {
+               cli_print(cli, "Access-list not defined");
+               return CLI_OK;
+       }
+
+       // racy
+       if (ip_filters[filt].used)
+       {
+               cli_print(cli, "Access-list in use");
+               return CLI_OK;
+       }
+
+       memset(&ip_filters[filt], 0, sizeof(ip_filters[filt]));
+       return CLI_OK;
+}
+
+static int cmd_ip_access_list(struct cli_def *cli, char *command, char **argv, int argc)
+{
+       return access_list(cli, argv, argc, 1);
+}
+
+static int cmd_no_ip_access_list(struct cli_def *cli, char *command, char **argv, int argc)
+{
+       return access_list(cli, argv, argc, 0);
+}
+
+static int show_ip_wild(char *buf, ipt ip, ipt 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));
+
+       i = sprintf(buf, " %s", inet_toa(ip));
+       return i + sprintf(buf + i, " %s", inet_toa(wild));
+}
+
+static int show_ports(char *buf, ip_filter_portt *ports)
+{
+       switch (ports->op)
+       {
+       case FILTER_PORT_OP_EQ:    return sprintf(buf, " eq %u", ports->port);
+       case FILTER_PORT_OP_NEQ:   return sprintf(buf, " neq %u", ports->port);
+       case FILTER_PORT_OP_GT:    return sprintf(buf, " gt %u", ports->port);
+       case FILTER_PORT_OP_LT:    return sprintf(buf, " lt %u", ports->port);
+       case FILTER_PORT_OP_RANGE: return sprintf(buf, " range %u %u", ports->port, ports->port2);
+       }
+
+       return 0;
+}
+
+static char const *show_access_list_rule(int extended, ip_filter_rulet *rule)
+{
+       static char buf[256];
+       char *p = buf;
+
+       p += sprintf(p, " %s", rule->action == FILTER_ACTION_PERMIT ? "permit" : "deny");
+       if (extended)
+       {
+               struct protoent *proto = getprotobynumber(rule->proto);
+               p += sprintf(p, " %s", proto ? proto->p_name : "ERR");
+       }
+
+       p += show_ip_wild(p, rule->src_ip, rule->src_wild);
+       if (!extended)
+               return buf;
+
+       if (rule->proto == IPPROTO_TCP || rule->proto == IPPROTO_UDP)
+               p += show_ports(p, &rule->src_ports);
+
+       p += show_ip_wild(p, rule->dst_ip, rule->dst_wild);
+       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->tcp_flag_op == FILTER_FLAG_OP_ANY &&
+                   rule->tcp_sflags == (TCP_FLAG_ACK|TCP_FLAG_FIN) &&
+                   rule->tcp_cflags == TCP_FLAG_SYN)
+               {
+                       p += sprintf(p, " established");
+               }
+               else
+               {
+                       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");
+                       if (rule->tcp_sflags & TCP_FLAG_SYN) p += sprintf(p, " +syn");
+                       if (rule->tcp_cflags & TCP_FLAG_SYN) p += sprintf(p, " -syn");
+                       if (rule->tcp_sflags & TCP_FLAG_RST) p += sprintf(p, " +rst");
+                       if (rule->tcp_cflags & TCP_FLAG_RST) p += sprintf(p, " -rst");
+                       if (rule->tcp_sflags & TCP_FLAG_PSH) p += sprintf(p, " +psh");
+                       if (rule->tcp_cflags & TCP_FLAG_PSH) p += sprintf(p, " -psh");
+                       if (rule->tcp_sflags & TCP_FLAG_ACK) p += sprintf(p, " +ack");
+                       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");
+               }
+       }
+
+       return buf;
+}
+
+ip_filter_rulet *access_list_rule_ext(struct cli_def *cli, char *command, char **argv, int argc)
+{
+       static ip_filter_rulet rule;
+       struct in_addr addr;
+       int i;
+       int a;
+
+       if (CLI_HELP_REQUESTED)
+       {
+               if (argc == 1)
+               {
+                       cli_arg_help(cli, 0,
+                               "ip",  "Match IP packets",
+                               "tcp", "Match TCP packets",
+                               "udp", "Match UDP packets",
+                               NULL);
+
+                       return NULL;
+               }
+
+               // *sigh*, too darned complex
+               cli_arg_help(cli, 0, "RULE", "SOURCE [PORTS] DEST [PORTS] FLAGS", NULL);
+               return NULL;
+       }
+
+       if (argc < 3)
+       {
+               cli_print(cli, "Specify rule details");
+               return NULL;
+       }
+
+       memset(&rule, 0, sizeof(rule));
+       rule.action = (command[0] == 'p')
+               ? FILTER_ACTION_PERMIT
+               : FILTER_ACTION_DENY;
+
+       if (MATCH("ip", argv[0]))
+               rule.proto = IPPROTO_IP;
+       else if (MATCH("udp", argv[0]))
+               rule.proto = IPPROTO_UDP;
+       else if (MATCH("tcp", argv[0]))
+               rule.proto = IPPROTO_TCP;
+       else
+       {
+               cli_print(cli, "Invalid protocol \"%s\"", argv[0]);
+               return NULL;
+       }
+
+       for (a = 1, i = 0; i < 2; i++)
+       {
+               ipt *ip;
+               ipt *wild;
+               ip_filter_portt *port;
+
+               if (i == 0)
+               {
+                       ip = &rule.src_ip;
+                       wild = &rule.src_wild;
+                       port = &rule.src_ports;
+               }
+               else
+               {
+                       ip = &rule.dst_ip;
+                       wild = &rule.dst_wild;
+                       port = &rule.dst_ports;
+                       if (a >= argc)
+                       {
+                               cli_print(cli, "Specify destination");
+                               return NULL;
+                       }
+               }
+
+               if (MATCH("any", argv[a]))
+               {
+                       *ip = INADDR_ANY;
+                       *wild = INADDR_BROADCAST;
+                       a++;
+               }
+               else if (MATCH("host", argv[a]))
+               {
+                       if (++a >= argc)
+                       {
+                               cli_print(cli, "Specify host ip address");
+                               return NULL;
+                       }
+
+                       if (!inet_aton(argv[a], &addr))
+                       {
+                               cli_print(cli, "Cannot parse IP \"%s\"", argv[a]);
+                               return NULL;
+                       }
+
+                       *ip = addr.s_addr;
+                       *wild = INADDR_ANY;
+                       a++;
+               }
+               else
+               {
+                       if (++a >= argc)
+                       {
+                               cli_print(cli, "Specify %s ip address and wildcard", i ? "destination" : "source");
+                               return NULL;
+                       }
+
+                       if (!inet_aton(argv[a], &addr))
+                       {
+                               cli_print(cli, "Cannot parse IP \"%s\"", argv[a]);
+                               return NULL;
+                       }
+
+                       *ip = addr.s_addr;
+
+                       if (!inet_aton(argv[++a], &addr))
+                       {
+                               cli_print(cli, "Cannot parse IP \"%s\"", argv[a]);
+                               return NULL;
+                       }
+
+                       *wild = addr.s_addr;
+               }
+
+               if (rule.proto == IPPROTO_IP || a >= argc)
+                       continue;
+
+               port->op = 0;
+               if (MATCH("eq", argv[a]))
+                       port->op = FILTER_PORT_OP_EQ;
+               else if (MATCH("neq", argv[a]))
+                       port->op = FILTER_PORT_OP_NEQ;
+               else if (MATCH("gt", argv[a]))
+                       port->op = FILTER_PORT_OP_GT;
+               else if (MATCH("lt", argv[a]))
+                       port->op = FILTER_PORT_OP_LT;
+               else if (MATCH("range", argv[a]))
+                       port->op = FILTER_PORT_OP_RANGE;
+
+               if (!port->op)
+                       continue;
+
+               if (++a >= argc)
+               {
+                       cli_print(cli, "Specify port");
+                       return NULL;
+               }
+
+               if (!(port->port = atoi(argv[a])))
+               {
+                       cli_print(cli, "Invalid port \"%s\"", argv[a]);
+                       return NULL;
+               }
+                       
+               a++;
+               if (port->op != FILTER_PORT_OP_RANGE)
+                       continue;
+
+               if (a >= argc)
+               {
+                       cli_print(cli, "Specify port");
+                       return NULL;
+               }
+
+               if (!(port->port2 = atoi(argv[a])) || port->port2 < port->port)
+               {
+                       cli_print(cli, "Invalid port \"%s\"", argv[a]);
+                       return NULL;
+               }
+                       
+               a++;
+       }
+
+       if (rule.proto == IPPROTO_TCP && a < argc)
+       {
+               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;
+                       a++;
+               }
+               else if (!strcmp(argv[a], "match-any") || !strcmp(argv[a], "match-an") ||
+                        !strcmp(argv[a], "match-all") || !strcmp(argv[a], "match-al"))
+               {
+                       rule.tcp_flag_op = argv[a][7] == 'n'
+                               ? FILTER_FLAG_OP_ANY
+                               : FILTER_FLAG_OP_ALL;
+
+                       if (++a >= argc)
+                       {
+                               cli_print(cli, "Specify tcp flags");
+                               return NULL;
+                       }
+
+                       while (a < argc && (argv[a][0] == '+' || argv[a][0] == '-'))
+                       {
+                               u8 *f;
+
+                               f = (argv[a][0] == '+') ? &rule.tcp_sflags : &rule.tcp_cflags;
+
+                               if (MATCH("fin", &argv[a][1]))      *f |= TCP_FLAG_FIN;
+                               else if (MATCH("syn", &argv[a][1])) *f |= TCP_FLAG_SYN;
+                               else if (MATCH("rst", &argv[a][1])) *f |= TCP_FLAG_RST;
+                               else if (MATCH("psh", &argv[a][1])) *f |= TCP_FLAG_PSH;
+                               else if (MATCH("ack", &argv[a][1])) *f |= TCP_FLAG_ACK;
+                               else if (MATCH("urg", &argv[a][1])) *f |= TCP_FLAG_URG;
+                               else
+                               {
+                                       cli_print(cli, "Invalid tcp flag \"%s\"", argv[a]);
+                                       return NULL;
+                               }
+
+                               a++;
+                       }
+               }
+       }
+
+       if (a < argc)
+       {
+               cli_print(cli, "Invalid flag \"%s\"", argv[a]);
+               return NULL;
+       }
+
+       return &rule;
+}
+
+ip_filter_rulet *access_list_rule_std(struct cli_def *cli, char *command, char **argv, int argc)
+{
+       static ip_filter_rulet rule;
+       struct in_addr addr;
+
+       if (CLI_HELP_REQUESTED)
+       {
+               if (argc == 1)
+               {
+                       cli_arg_help(cli, argv[0][1],
+                               "A.B.C.D", "Source address",
+                               "any",     "Any source address",
+                               "host",    "Source host",
+                               NULL);
+
+                       return NULL;
+               }
+
+               if (MATCH("any", argv[0]))
+               {
+                       if (argc == 2 && !argv[1][1])
+                               cli_arg_help(cli, 1, NULL);
+               }
+               else if (MATCH("host", argv[0]))
+               {
+                       if (argc == 2)
+                       {
+                               cli_arg_help(cli, argv[1][1],
+                                       "A.B.C.D", "Host address",
+                                       NULL);
+                       }
+                       else if (argc == 3 && !argv[2][1])
+                               cli_arg_help(cli, 1, NULL);
+               }
+               else
+               {
+                       if (argc == 2)
+                       {
+                               cli_arg_help(cli, 1,
+                                       "A.B.C.D", "Wildcard bits",
+                                       NULL);
+                       }
+                       else if (argc == 3 && !argv[2][1])
+                               cli_arg_help(cli, 1, NULL);
+               }
+
+               return NULL;
+       }
+
+       if (argc < 1)
+       {
+               cli_print(cli, "Specify rule details");
+               return NULL;
+       }
+
+       memset(&rule, 0, sizeof(rule));
+       rule.action = (command[0] == 'p')
+               ? FILTER_ACTION_PERMIT
+               : FILTER_ACTION_DENY;
+
+       rule.proto = IPPROTO_IP;
+       if (MATCH("any", argv[0]))
+       {
+               rule.src_ip = INADDR_ANY;
+               rule.src_wild = INADDR_BROADCAST;
+       }
+       else if (MATCH("host", argv[0]))
+       {
+               if (argc != 2)
+               {
+                       cli_print(cli, "Specify host ip address");
+                       return NULL;
+               }
+
+               if (!inet_aton(argv[1], &addr))
+               {
+                       cli_print(cli, "Cannot parse IP \"%s\"", argv[1]);
+                       return NULL;
+               }
+
+               rule.src_ip = addr.s_addr;
+               rule.src_wild = INADDR_ANY;
+       }
+       else
+       {
+               if (argc > 2)
+               {
+                       cli_print(cli, "Specify source ip address and wildcard");
+                       return NULL;
+               }
+
+               if (!inet_aton(argv[0], &addr))
+               {
+                       cli_print(cli, "Cannot parse IP \"%s\"", argv[0]);
+                       return NULL;
+               }
+
+               rule.src_ip = addr.s_addr;
+
+               if (argc > 1)
+               {
+                       if (!inet_aton(argv[1], &addr))
+                       {
+                               cli_print(cli, "Cannot parse IP \"%s\"", argv[1]);
+                               return NULL;
+                       }
+
+                       rule.src_wild = addr.s_addr;
+               }
+               else
+                       rule.src_wild = INADDR_ANY;
+       }
+
+       return &rule;
+}
+
+static int cmd_ip_access_list_rule(struct cli_def *cli, char *command, char **argv, int argc)
+{
+       int i;
+       ip_filter_rulet *rule = ip_filters[filt].extended
+               ? access_list_rule_ext(cli, command, argv, argc)
+               : access_list_rule_std(cli, command, argv, argc);
+
+       if (!rule)
+               return CLI_OK;
+
+       for (i = 0; i < MAXFILTER_RULES - 1; i++) // -1: list always terminated by empty rule
+       {
+               if (!ip_filters[filt].rules[i].action)
+               {
+                       memcpy(&ip_filters[filt].rules[i], rule, sizeof(*rule));
+                       return CLI_OK;
+               }
+
+               if (!memcmp(&ip_filters[filt].rules[i], rule, sizeof(*rule)))
+                       return CLI_OK;
+       }
+
+       cli_print(cli, "Too many rules");
+       return CLI_OK;
+}
+
 // Convert a string in the form of abcd.ef12.3456 into char[6]
 void parsemac(char *string, char mac[6])
 {
index 9f5801f..b53f687 100644 (file)
--- 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.56 2004-11-25 02:49:18 bodea Exp $";
+char const *cvs_id_l2tpns = "$Id: l2tpns.c,v 1.57 2004-11-27 05:19:53 bodea Exp $";
 
 #include <arpa/inet.h>
 #include <assert.h>
@@ -54,7 +54,7 @@ char const *cvs_id_l2tpns = "$Id: l2tpns.c,v 1.56 2004-11-25 02:49:18 bodea Exp
 #endif /* BGP */
 
 // Globals
-struct configt *config = NULL; // all configuration
+configt *config = NULL;                // all configuration
 int tunfd = -1;                        // tun interface file handle. (network device)
 int udpfd = -1;                        // UDP file handle
 int controlfd = -1;            // Control signal handle
@@ -88,9 +88,9 @@ linked_list *loaded_plugins;
 linked_list *plugins[MAX_PLUGIN_TYPES];
 
 #define membersize(STRUCT, MEMBER) sizeof(((STRUCT *)0)->MEMBER)
-#define CONFIG(NAME, MEMBER, TYPE) { NAME, offsetof(struct configt, MEMBER), membersize(struct configt, MEMBER), TYPE }
+#define CONFIG(NAME, MEMBER, TYPE) { NAME, offsetof(configt, MEMBER), membersize(configt, MEMBER), TYPE }
 
-struct config_descriptt config_values[] = {
+config_descriptt config_values[] = {
        CONFIG("debug", debug, INT),
        CONFIG("log_file", log_filename, STRING),
        CONFIG("pid_file", pid_file, STRING),
@@ -146,6 +146,7 @@ sessiont *session = NULL;           // Array of session structures.
 sessioncountt *sess_count = NULL;      // Array of partial per-session traffic counters.
 radiust *radius = NULL;                        // Array of radius structures.
 ippoolt *ip_address_pool = NULL;       // Array of dynamic IP addresses.
+ip_filtert *ip_filters = NULL; // Array of named filters.
 static controlt *controlfree = 0;
 struct Tstats *_statistics = NULL;
 #ifdef RINGBUFFER
@@ -942,8 +943,10 @@ static void controladd(controlt * c, tunnelidt t, sessionidt s)
                tunnel[t].controle->next = c;
        else
                tunnel[t].controls = c;
+
        tunnel[t].controle = c;
        tunnel[t].controlc++;
+
        // send now if space in window
        if (tunnel[t].controlc <= tunnel[t].window)
        {
@@ -1306,10 +1309,9 @@ void processudp(u8 * buf, int len, struct sockaddr_in *addr)
                        STAT(tunnel_rx_errors);
                        return;
                }
-               LOG(3, ntohl(addr->sin_addr.s_addr), s, t, "Control message (%d bytes): (unacked %d) l-ns %d l-nr %d r-ns %d r-nr %d\n",
-                               l, tunnel[t].controlc, tunnel[t].ns, tunnel[t].nr, ns, nr);
-               // if no tunnel specified, assign one
-               if (!t)
+
+               // check for duplicate tunnel open message
+               if (!t && ns == 0)
                {
                        int i;
 
@@ -1323,10 +1325,15 @@ void processudp(u8 * buf, int len, struct sockaddr_in *addr)
                                        tunnel[i].port != ntohs(addr->sin_port) )
                                        continue;
                                t = i;
+                               LOG(3, ntohl(addr->sin_addr.s_addr), s, t, "Duplicate SCCRQ?\n");
                                break;
                        }
                }
 
+               LOG(3, ntohl(addr->sin_addr.s_addr), s, t, "Control message (%d bytes): (unacked %d) l-ns %d l-nr %d r-ns %d r-nr %d\n",
+                               l, tunnel[t].controlc, tunnel[t].ns, tunnel[t].nr, ns, nr);
+
+               // if no tunnel specified, assign one
                if (!t)
                {
                        if (!(t = new_tunnel()))
@@ -1339,8 +1346,28 @@ void processudp(u8 * buf, int len, struct sockaddr_in *addr)
                        tunnel[t].ip = ntohl(*(ipt *) & addr->sin_addr);
                        tunnel[t].port = ntohs(addr->sin_port);
                        tunnel[t].window = 4; // default window
-                       LOG(1, ntohl(addr->sin_addr.s_addr), 0, t, "   New tunnel from %u.%u.%u.%u/%u ID %d\n", tunnel[t].ip >> 24, tunnel[t].ip >> 16 & 255, tunnel[t].ip >> 8 & 255, tunnel[t].ip & 255, tunnel[t].port, t);
                        STAT(tunnel_created);
+                       LOG(1, ntohl(addr->sin_addr.s_addr), 0, t, "   New tunnel from %u.%u.%u.%u/%u ID %d\n",
+                               tunnel[t].ip >> 24, tunnel[t].ip >> 16 & 255,
+                               tunnel[t].ip >> 8 & 255, tunnel[t].ip & 255, tunnel[t].port, t);
+               }
+
+                       // If the 'ns' just received is not the 'nr' we're
+                       // expecting, just send an ack and drop it.
+                       //
+                       // if 'ns' is less, then we got a retransmitted packet.
+                       // if 'ns' is greater than missed a packet. Either way
+                       // we should ignore it.
+               if (ns != tunnel[t].nr)
+               {
+                       // is this the sequence we were expecting?
+                       STAT(tunnel_rx_errors);
+                       LOG(1, ntohl(addr->sin_addr.s_addr), 0, t, "   Out of sequence tunnel %d, (%d is not the expected %d)\n",
+                               t, ns, tunnel[t].nr);
+
+                       if (l)  // Is this not a ZLB?
+                               controlnull(t);
+                       return;
                }
 
                // This is used to time out old tunnels
@@ -1350,7 +1377,7 @@ void processudp(u8 * buf, int len, struct sockaddr_in *addr)
                {
                        int skip = tunnel[t].window; // track how many in-window packets are still in queue
                                // some to clear maybe?
-                       while (tunnel[t].controlc && (((tunnel[t].ns - tunnel[t].controlc) - nr) & 0x8000))
+                       while (tunnel[t].controlc > 0 && (((tunnel[t].ns - tunnel[t].controlc) - nr) & 0x8000))
                        {
                                controlt *c = tunnel[t].controls;
                                tunnel[t].controls = c->next;
@@ -1361,22 +1388,6 @@ void processudp(u8 * buf, int len, struct sockaddr_in *addr)
                                tunnel[t].try = 0; // we have progress
                        }
 
-                               // If the 'ns' just received is not the 'nr' we're
-                               // expecting, just send an ack and drop it.
-                               //
-                               // if 'ns' is less, then we got a retransmitted packet.
-                               // if 'ns' is greater than missed a packet. Either way
-                               // we should ignore it.
-                       if (ns != tunnel[t].nr)
-                       {
-                               // is this the sequence we were expecting?
-                               LOG(1, ntohl(addr->sin_addr.s_addr), 0, t, "   Out of sequence tunnel %d, (%d is not the expected %d)\n", t, ns, tunnel[t].nr);
-                               STAT(tunnel_rx_errors);
-
-                               if (l)  // Is this not a ZLB?
-                                       controlnull(t);
-                               return;
-                       }
                        // receiver advance (do here so quoted correctly in any sends below)
                        if (l) tunnel[t].nr = (ns + 1);
                        if (skip < 0) skip = 0;
@@ -2480,12 +2491,12 @@ static void initdata(int optdebug, char *optconfig)
                LOG(0, 0, 0, 0, "Error doing malloc for _statistics: %s\n", strerror(errno));
                exit(1);
        }
-       if (!(config = shared_malloc(sizeof(struct configt))))
+       if (!(config = shared_malloc(sizeof(configt))))
        {
                LOG(0, 0, 0, 0, "Error doing malloc for configuration: %s\n", strerror(errno));
                exit(1);
        }
-       memset(config, 0, sizeof(struct configt));
+       memset(config, 0, sizeof(configt));
        time(&config->start_time);
        strncpy(config->config_file, optconfig, strlen(optconfig));
        config->debug = optdebug;
@@ -2521,6 +2532,13 @@ static void initdata(int optdebug, char *optconfig)
                exit(1);
        }
 
+if (!(ip_filters = shared_malloc(sizeof(ip_filtert) * MAXFILTER)))
+{
+       LOG(0, 0, 0, 0, "Error doing malloc for ip_filters: %s\n", strerror(errno));
+       exit(1);
+}
+memset(ip_filters, 0, sizeof(ip_filtert) * MAXFILTER);
+
 #ifdef RINGBUFFER
        if (!(ringbuffer = shared_malloc(sizeof(struct Tringbuffer))))
        {
@@ -2572,11 +2590,11 @@ static void initdata(int optdebug, char *optconfig)
        _statistics->start_time = _statistics->last_reset = time(NULL);
 
 #ifdef BGP
-       if (!(bgp_peers = shared_malloc(sizeof(struct bgp_peer) * BGP_NUM_PEERS)))
-       {
-               LOG(0, 0, 0, 0, "Error doing malloc for bgp: %s\n", strerror(errno));
-               exit(1);
-       }
+       if (!(bgp_peers = shared_malloc(sizeof(struct bgp_peer) * BGP_NUM_PEERS)))
+       {
+               LOG(0, 0, 0, 0, "Error doing malloc for bgp: %s\n", strerror(errno));
+               exit(1);
+       }
 #endif /* BGP */
 }
 
index c73727b..0825d38 100644 (file)
--- a/l2tpns.h
+++ b/l2tpns.h
@@ -1,5 +1,5 @@
 // L2TPNS Global Stuff
-// $Id: l2tpns.h,v 1.37 2004-11-25 12:41:35 bodea Exp $
+// $Id: l2tpns.h,v 1.38 2004-11-27 05:19:53 bodea Exp $
 
 #ifndef __L2TPNS_H__
 #define __L2TPNS_H__
@@ -142,7 +142,7 @@ struct cli_tunnel_actions {
 #define DUMP_MAGIC "L2TPNS#" VERSION "#"
 
 // structures
-typedef struct routes           // route
+typedef struct                 // route
 {
        ipt ip;
        ipt mask;
@@ -157,7 +157,7 @@ typedef struct controls         // control message
 }
 controlt;
 
-typedef struct sessions
+typedef struct
 {
        sessionidt next;                // next session in linked list
        sessionidt far;                 // far end session ID
@@ -199,7 +199,9 @@ typedef struct sessions
        ipt snoop_ip;                   // Interception destination IP
        u16 snoop_port;                 // Interception destination port
        u16 sid;                        // near end session id.
-       char reserved[20];              // Space to expand structure without changing HB_VERSION
+       u8 filter_in;                   // input filter index (to ip_filters[N-1]; 0 if none)
+       u8 filter_out;                  // output filter index
+       char reserved[18];              // Space to expand structure without changing HB_VERSION
 }
 sessiont;
 
@@ -207,7 +209,8 @@ sessiont;
 #define SF_LCP_ACKED   2       // LCP negotiated
 #define SF_CCP_ACKED   4       // CCP negotiated
 
-typedef struct {
+typedef struct
+{
        u32     cin;
        u32     cout;
 } sessioncountt;
@@ -216,7 +219,7 @@ typedef struct {
 #define        SESSIONACFC     2       // ACFC negotiated flags
 
 // 168 bytes per tunnel
-typedef struct tunnels
+typedef struct
 {
        tunnelidt far;          // far end tunnel ID
        ipt ip;                 // Ip for far end
@@ -239,7 +242,7 @@ typedef struct tunnels
 tunnelt;
 
 // 180 bytes per radius session
-typedef struct radiuss         // outstanding RADIUS requests
+typedef struct                 // outstanding RADIUS requests
 {
        sessionidt session;     // which session this applies to
        hasht auth;             // request authenticator
@@ -393,7 +396,7 @@ struct Tstats
 #define SET_STAT(x, y)
 #endif
 
-struct configt
+typedef struct
 {
        int             debug;                          // debugging level
        time_t          start_time;                     // time when l2tpns was started
@@ -470,16 +473,65 @@ struct configt
                int     hold;
        }               neighbour[BGP_NUM_PEERS];
 #endif
-};
+} configt;
 
 enum config_typet { INT, STRING, UNSIGNED_LONG, SHORT, BOOL, IP, MAC };
-struct config_descriptt
+typedef struct
 {
        char *key;
        int offset;
        int size;
        enum config_typet type;
-};
+} config_descriptt;
+
+typedef struct
+{
+       u8 op;          // operation
+#define FILTER_PORT_OP_NONE    0 // all ports match
+#define FILTER_PORT_OP_EQ      1
+#define FILTER_PORT_OP_NEQ     2
+#define FILTER_PORT_OP_GT      3
+#define FILTER_PORT_OP_LT      4
+#define FILTER_PORT_OP_RANGE   5
+       portt port;
+       portt port2;    // for range
+} ip_filter_portt;
+
+typedef struct
+{
+       int action;             // permit/deny
+#define FILTER_ACTION_DENY     1
+#define FILTER_ACTION_PERMIT   2
+       int proto;              // protocol: IPPROTO_* (netinet/in.h)
+       ipt src_ip;             // source ip
+       ipt src_wild;
+       ip_filter_portt src_ports;
+       ipt dst_ip;             // dest ip
+       ipt dst_wild;
+       ip_filter_portt dst_ports;
+       u8 tcp_flag_op;         // match type: any, all
+#define FILTER_FLAG_OP_ANY     0
+#define FILTER_FLAG_OP_ALL     1
+       u8 tcp_sflags;          // flags set
+       u8 tcp_cflags;          // flags clear
+} ip_filter_rulet;
+
+#define TCP_FLAG_FIN   0x01
+#define TCP_FLAG_SYN   0x02
+#define TCP_FLAG_RST   0x04
+#define TCP_FLAG_PSH   0x08
+#define TCP_FLAG_ACK   0x10
+#define TCP_FLAG_URG   0x20
+
+#define MAXFILTER              32
+#define MAXFILTER_RULES                32
+typedef struct
+{
+       char name[32];          // ACL name
+       int extended;           // type: 0 = standard, 1 = extended
+       ip_filter_rulet rules[MAXFILTER_RULES];
+       int used;               // session ref count
+} ip_filtert;
 
 // arp.c
 void sendarp(int ifr_idx, const unsigned char* mac, ipt ip);
@@ -570,7 +622,7 @@ if (count++ < max) { \
 }
 
 
-extern struct configt *config;
+extern configt *config;
 extern time_t basetime;                // Time when this process started.
 extern time_t time_now;                // Seconds since EPOCH.
 extern u32 last_id;
index be9b52a..1a39885 100644 (file)
@@ -43,5 +43,5 @@ rm -rf %{buildroot}
 %attr(644,root,root) /usr/share/man/man[58]/*
 
 %changelog
-* Thu Nov 25 2004 Brendan O'Dea <bod@optusnet.com.au> 2.0.9-1
+* Sat Nov 27 2004 Brendan O'Dea <bod@optusnet.com.au> 2.0.9-1
 - 2.0.9 release, see /usr/share/doc/l2tpns-2.0.9/Changes
diff --git a/ppp.c b/ppp.c
index a784c29..d44ed25 100644 (file)
--- a/ppp.c
+++ b/ppp.c
@@ -1,6 +1,6 @@
 // L2TPNS PPP Stuff
 
-char const *cvs_id_ppp = "$Id: ppp.c,v 1.30 2004-11-25 12:46:48 bodea Exp $";
+char const *cvs_id_ppp = "$Id: ppp.c,v 1.31 2004-11-27 05:19:53 bodea Exp $";
 
 #include <stdio.h>
 #include <string.h>
@@ -21,7 +21,7 @@ extern int tunfd;
 extern char hostname[];
 extern u32 eth_tx;
 extern time_t time_now;
-extern struct configt *config;
+extern configt *config;
 
 static void initccp(tunnelidt t, sessionidt s);
 
index 29eea22..634db50 100644 (file)
--- a/radius.c
+++ b/radius.c
@@ -1,6 +1,6 @@
 // L2TPNS Radius Stuff
 
-char const *cvs_id_radius = "$Id: radius.c,v 1.13 2004-11-25 02:45:27 bodea Exp $";
+char const *cvs_id_radius = "$Id: radius.c,v 1.14 2004-11-27 05:19:53 bodea Exp $";
 
 #include <time.h>
 #include <stdio.h>
@@ -22,7 +22,7 @@ extern radiust *radius;
 extern sessiont *session;
 extern tunnelt *tunnel;
 extern u32 sessionid;
-extern struct configt *config;
+extern configt *config;
 extern int *radfds;
 
 static const char *radius_state(int state)