From: bodea Date: Sun, 28 Nov 2004 20:09:52 +0000 (+0000) Subject: add filtering X-Git-Tag: release_2_0_9~17 X-Git-Url: http://git.sameswireless.fr/l2tpns.git/commitdiff_plain/386fbf71abfd11ef4572ede20bdb011c67b03673?ds=inline add filtering --- diff --git a/Changes b/Changes index 1d2bdcd..2285f0f 100644 --- a/Changes +++ b/Changes @@ -1,11 +1,12 @@ -* Sat Nov 27 2004 Brendan O'Dea 2.0.9 +* Mon Nov 29 2004 Brendan O'Dea 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). +- Implement named access-lists which may be applied to a session + either via Filter-Id RADIUS responses, or using the CLI. * Sat Nov 20 2004 Brendan O'Dea 2.0.8 - Ignore gateway address in Framed-Route (from Jonathan McDowell). diff --git a/cli.c b/cli.c index 714d9a4..d38d0d2 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.32 2004/11/28 02:53:11 bodea Exp $"; +char const *cvs_id_cli = "$Id: cli.c,v 1.33 2004/11/28 20:09:53 bodea Exp $"; #include #include @@ -2433,10 +2433,10 @@ 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_sflags == (TCP_FLAG_ACK|TCP_FLAG_RST) && rule->tcp_cflags == TCP_FLAG_SYN) { p += sprintf(p, " established"); @@ -2638,7 +2638,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_sflags = (TCP_FLAG_ACK|TCP_FLAG_RST); rule.tcp_cflags = TCP_FLAG_SYN; a++; } diff --git a/l2tpns.c b/l2tpns.c index 16e5a29..a1f30a2 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.58 2004/11/28 02:53:11 bodea Exp $"; +char const *cvs_id_l2tpns = "$Id: l2tpns.c,v 1.59 2004/11/28 20:10:04 bodea Exp $"; #include #include @@ -764,6 +764,10 @@ static void processipout(u8 * buf, int len) t = session[s].tunnel; sp = &session[s]; + // run access-list if any + if (session[s].filter_out && !ip_filter(buf, len, session[s].filter_out - 1)) + return; + if (sp->tbf_out) { // Are we throttling this session? @@ -4380,3 +4384,107 @@ static int unhide_avp(u8 *avp, tunnelidt t, sessionidt s, u16 length) return hidden_length + 6; } +static int ip_filter_port(ip_filter_portt *p, portt port) +{ + switch (p->op) + { + case FILTER_PORT_OP_EQ: return port == p->port; + case FILTER_PORT_OP_NEQ: return port != p->port; + case FILTER_PORT_OP_GT: return port > p->port; + case FILTER_PORT_OP_LT: return port < p->port; + case FILTER_PORT_OP_RANGE: return port >= p->port && port <= p->port2; + } + + return 0; +} + +static int ip_filter_flag(u8 op, u8 sflags, u8 cflags, u8 flags) +{ + switch (op) + { + /* + * NOTE: "match-any +A +B -C -D" is interpreted as "match if + * either A or B is set *and* C or D is clear". While "or" is + * possibly more correct, the way "established" is currently + * implemented depends on this behaviour. + */ + case FILTER_FLAG_OP_ANY: + return (flags & sflags) && !(flags & cflags); + + case FILTER_FLAG_OP_ALL: + return (flags & sflags) == sflags && (~flags & cflags) == cflags; + } + + return 0; +} + +int ip_filter(u8 *buf, int len, u8 filter) +{ + u8 proto; + ipt src_ip; + ipt dst_ip; + portt src_port = 0; + portt dst_port = 0; + u8 flags = 0; + ip_filter_rulet *rule; + + if (len < 20) // up to end of destination address + return 0; + + if (*buf >> 4) // IPv4 + return 0; + + proto = buf[9]; + src_ip = *(u32 *) (buf + 12); + dst_ip = *(u32 *) (buf + 16); + + if (proto == IPPROTO_TCP || proto == IPPROTO_UDP) + { + int l = buf[0] & 0xf; + if (len < l + 4) // ports + return 0; + + src_port = ntohs(*(u16 *) (buf + l)); + dst_port = ntohs(*(u16 *) (buf + l + 2)); + if (proto == IPPROTO_TCP) + { + if (len < l + 15) // flags + return 0; + + flags = buf[l + 14] & 0x3f; + } + } + + for (rule = ip_filters[filter].rules; rule->action; rule++) + { + if (proto && proto != rule->proto) + continue; + + if (rule->src_wild != INADDR_BROADCAST && + (src_ip & ~rule->src_wild) != (rule->src_ip & ~rule->src_wild)) + continue; + + if (rule->dst_wild != INADDR_BROADCAST && + (dst_ip & ~rule->dst_wild) != (rule->dst_ip & ~rule->dst_wild)) + continue; + + if (proto == IPPROTO_TCP || proto == IPPROTO_UDP) + { + if (rule->src_ports.op && !ip_filter_port(&rule->src_ports, src_port)) + continue; + + if (rule->dst_ports.op && !ip_filter_port(&rule->dst_ports, dst_port)) + continue; + + if (proto == IPPROTO_TCP && rule->tcp_flag_op && + !ip_filter_flag(rule->tcp_flag_op, rule->tcp_sflags, rule->tcp_cflags, flags)) + continue; + } + + // matched + return rule->action == FILTER_ACTION_PERMIT; + } + + // default deny + return 0; +} diff --git a/l2tpns.h b/l2tpns.h index 910504d..1b950e5 100644 --- a/l2tpns.h +++ b/l2tpns.h @@ -1,5 +1,5 @@ // L2TPNS Global Stuff -// $Id: l2tpns.h,v 1.39 2004/11/28 02:53:11 bodea Exp $ +// $Id: l2tpns.h,v 1.40 2004/11/28 20:10:04 bodea Exp $ #ifndef __L2TPNS_H__ #define __L2TPNS_H__ @@ -497,8 +497,8 @@ typedef struct #define FILTER_PORT_OP_GT 3 #define FILTER_PORT_OP_LT 4 #define FILTER_PORT_OP_RANGE 5 - portt port; - portt port2; // for range + portt port; // port (host byte order) + portt port2; // range } ip_filter_portt; typedef struct @@ -506,16 +506,16 @@ 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 + u8 proto; // protocol: IPPROTO_* (netinet/in.h) + ipt src_ip; // source ip (network byte order) 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 +#define FILTER_FLAG_OP_ANY 1 +#define FILTER_FLAG_OP_ALL 2 u8 tcp_sflags; // flags set u8 tcp_cflags; // flags clear } ip_filter_rulet; @@ -573,6 +573,7 @@ void tunnelsend(u8 * buf, u16 l, tunnelidt t); void sendipcp(tunnelidt t, sessionidt s); void processudp(u8 * buf, int len, struct sockaddr_in *addr); void snoop_send_packet(char *packet, u16 size, ipt destination, u16 port); +int ip_filter(u8 *buf, int len, u8 filter); int cmd_show_ipcache(struct cli_def *cli, char *command, char **argv, int argc); int cmd_show_hist_idle(struct cli_def *cli, char *command, char **argv, int argc); int cmd_show_hist_open(struct cli_def *cli, char *command, char **argv, int argc); diff --git a/l2tpns.spec b/l2tpns.spec index 1a39885..fa22ce0 100644 --- a/l2tpns.spec +++ b/l2tpns.spec @@ -43,5 +43,5 @@ rm -rf %{buildroot} %attr(644,root,root) /usr/share/man/man[58]/* %changelog -* Sat Nov 27 2004 Brendan O'Dea 2.0.9-1 +* Mon Nov 29 2004 Brendan O'Dea 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 9cd9948..323c4bd 100644 --- a/ppp.c +++ b/ppp.c @@ -1,6 +1,6 @@ // L2TPNS PPP Stuff -char const *cvs_id_ppp = "$Id: ppp.c,v 1.31 2004/11/27 05:19:53 bodea Exp $"; +char const *cvs_id_ppp = "$Id: ppp.c,v 1.32 2004/11/28 20:10:04 bodea Exp $"; #include #include @@ -719,6 +719,10 @@ void processipin(tunnelidt t, sessionidt s, u8 *p, u16 l) return; } + // run access-list if any + if (session[s].filter_in && !ip_filter(p, l, session[s].filter_in - 1)) + return; + // Add on the tun header p -= 4; *(u32 *)p = htonl(0x00000800);