Filter: Add support for src/dst accessors for Flowspec and SADR

This commit is contained in:
Ondrej Zajicek (work) 2019-12-09 04:23:01 +01:00
parent 21d09632a5
commit ff2ca10cba
7 changed files with 104 additions and 12 deletions

View file

@ -1295,7 +1295,9 @@ in the foot).
prefix. The literals are written as <cf><m/ipaddress//<m/pxlen/ from prefix. The literals are written as <cf><m/ipaddress//<m/pxlen/ from
<m/ipaddress//<m/pxlen/</cf>, where the first part is the destination <m/ipaddress//<m/pxlen/</cf>, where the first part is the destination
prefix and the second art is the source prefix. They support the same prefix and the second art is the source prefix. They support the same
operators as IP prefixes, but just for the destination part. operators as IP prefixes, but just for the destination part. They also
support <cf/.src/ and <cf/.dst/ operators to get respective parts of the
address as separate <cf/NET_IP6/ values.
<cf/NET_VPN4/ and <cf/NET_VPN6/ prefixes hold an IP prefix with VPN <cf/NET_VPN4/ and <cf/NET_VPN6/ prefixes hold an IP prefix with VPN
Route Distinguisher (<rfc id="4364">). They support the same special Route Distinguisher (<rfc id="4364">). They support the same special
@ -1309,7 +1311,9 @@ in the foot).
and <cf/.asn/ which extracts the ASN. and <cf/.asn/ which extracts the ASN.
<cf/NET_FLOW4/ and <cf/NET_FLOW6/ hold an IP prefix together with a <cf/NET_FLOW4/ and <cf/NET_FLOW6/ hold an IP prefix together with a
flowspec rule. Filters currently don't support flowspec parsing. flowspec rule. Filters currently do not support much flowspec parsing,
only <cf/.src/ and <cf/.dst/ operators to get source and destination
parts of the flowspec as separate <cf/NET_IP4/ / <cf/NET_IP6/ values.
<cf/NET_MPLS/ holds a single MPLS label and its handling is currently <cf/NET_MPLS/ holds a single MPLS label and its handling is currently
not implemented. not implemented.

View file

@ -433,7 +433,7 @@ CF_KEYWORDS(FUNCTION, PRINT, PRINTN, UNSET, RETURN,
TRUE, FALSE, RT, RO, UNKNOWN, GENERIC, TRUE, FALSE, RT, RO, UNKNOWN, GENERIC,
FROM, GW, NET, MASK, PROTO, SOURCE, SCOPE, DEST, IFNAME, IFINDEX, FROM, GW, NET, MASK, PROTO, SOURCE, SCOPE, DEST, IFNAME, IFINDEX,
PREFERENCE, PREFERENCE,
ROA_CHECK, ASN, SRC, ROA_CHECK, ASN, SRC, DST,
IS_V4, IS_V6, IS_V4, IS_V6,
LEN, MAXLEN, LEN, MAXLEN,
DEFINED, DEFINED,
@ -940,7 +940,8 @@ term:
| term '.' LEN { $$ = f_new_inst(FI_LENGTH, $1); } | term '.' LEN { $$ = f_new_inst(FI_LENGTH, $1); }
| term '.' MAXLEN { $$ = f_new_inst(FI_ROA_MAXLEN, $1); } | term '.' MAXLEN { $$ = f_new_inst(FI_ROA_MAXLEN, $1); }
| term '.' ASN { $$ = f_new_inst(FI_ROA_ASN, $1); } | term '.' ASN { $$ = f_new_inst(FI_ROA_ASN, $1); }
| term '.' SRC { $$ = f_new_inst(FI_SADR_SRC, $1); } | term '.' SRC { $$ = f_new_inst(FI_NET_SRC, $1); }
| term '.' DST { $$ = f_new_inst(FI_NET_DST, $1); }
| term '.' MASK '(' term ')' { $$ = f_new_inst(FI_IP_MASK, $1, $5); } | term '.' MASK '(' term ')' { $$ = f_new_inst(FI_IP_MASK, $1, $5); }
| term '.' FIRST { $$ = f_new_inst(FI_AS_PATH_FIRST, $1); } | term '.' FIRST { $$ = f_new_inst(FI_AS_PATH_FIRST, $1); }
| term '.' LAST { $$ = f_new_inst(FI_AS_PATH_LAST, $1); } | term '.' LAST { $$ = f_new_inst(FI_AS_PATH_LAST, $1); }

View file

@ -771,18 +771,76 @@
} }
} }
INST(FI_SADR_SRC, 1, 1) { /* Get SADR src prefix */ INST(FI_NET_SRC, 1, 1) { /* Get src prefix */
ARG(1, T_NET); ARG(1, T_NET);
if (!net_is_sadr(v1.val.net))
runtime( "SADR expected" );
net_addr_ip6_sadr *net = (void *) v1.val.net; net_addr_union *net = (void *) v1.val.net;
net_addr *src = falloc(sizeof(net_addr_ip6)); net_addr *src = falloc(sizeof(net_addr_ip6));
net_fill_ip6(src, net->src_prefix, net->src_pxlen); const byte *part;
switch(v1.val.net->type) {
case NET_FLOW4:
part = flow4_get_part(&net->flow4, FLOW_TYPE_SRC_PREFIX);
if (part)
net_fill_ip4(src, flow_read_ip4_part(part), flow_read_pxlen(part));
else
net_fill_ip4(src, IP4_NONE, 0);
break;
case NET_FLOW6:
part = flow6_get_part(&net->flow6, FLOW_TYPE_SRC_PREFIX);
if (part)
net_fill_ip6(src, flow_read_ip6_part(part), flow_read_pxlen(part));
else
net_fill_ip6(src, IP6_NONE, 0);
break;
case NET_IP6_SADR:
net_fill_ip6(src, net->ip6_sadr.src_prefix, net->ip6_sadr.src_pxlen);
break;
default:
runtime( "Flow or SADR expected" );
}
RESULT(T_NET, net, src); RESULT(T_NET, net, src);
} }
INST(FI_NET_DST, 1, 1) { /* Get dst prefix */
ARG(1, T_NET);
net_addr_union *net = (void *) v1.val.net;
net_addr *dst = falloc(sizeof(net_addr_ip6));
const byte *part;
switch(v1.val.net->type) {
case NET_FLOW4:
part = flow4_get_part(&net->flow4, FLOW_TYPE_DST_PREFIX);
if (part)
net_fill_ip4(dst, flow_read_ip4_part(part), flow_read_pxlen(part));
else
net_fill_ip4(dst, IP4_NONE, 0);
break;
case NET_FLOW6:
part = flow6_get_part(&net->flow6, FLOW_TYPE_DST_PREFIX);
if (part)
net_fill_ip6(dst, flow_read_ip6_part(part), flow_read_pxlen(part));
else
net_fill_ip6(dst, IP6_NONE, 0);
break;
case NET_IP6_SADR:
net_fill_ip6(dst, net->ip6_sadr.dst_prefix, net->ip6_sadr.dst_pxlen);
break;
default:
runtime( "Flow or SADR expected" );
}
RESULT(T_NET, net, dst);
}
INST(FI_ROA_MAXLEN, 1, 1) { /* Get ROA max prefix length */ INST(FI_ROA_MAXLEN, 1, 1) { /* Get ROA max prefix length */
ARG(1, T_NET); ARG(1, T_NET);
if (!net_is_roa(v1.val.net)) if (!net_is_roa(v1.val.net))

View file

@ -17,6 +17,7 @@
#include "conf/conf.h" #include "conf/conf.h"
#include "filter/filter.h" #include "filter/filter.h"
#include "filter/data.h" #include "filter/data.h"
#include "lib/flowspec.h"
/* Flags for instructions */ /* Flags for instructions */
enum f_instruction_flags { enum f_instruction_flags {

View file

@ -32,8 +32,9 @@
#include "lib/socket.h" #include "lib/socket.h"
#include "lib/string.h" #include "lib/string.h"
#include "lib/unaligned.h" #include "lib/unaligned.h"
#include "lib/net.h"
#include "lib/ip.h" #include "lib/ip.h"
#include "lib/net.h"
#include "lib/flowspec.h"
#include "nest/route.h" #include "nest/route.h"
#include "nest/protocol.h" #include "nest/protocol.h"
#include "nest/iface.h" #include "nest/iface.h"

View file

@ -243,12 +243,37 @@ flow6_next_part(const byte *pos, const byte *end)
return flow_next_part(pos, end, 1); return flow_next_part(pos, end, 1);
} }
static const byte *
flow_get_part(const byte *data, uint dlen, uint type, int ipv6)
{
const byte *part;
for (part = flow_first_part(data);
part && (part[0] <= type);
part = flow_next_part(part, data+dlen, ipv6))
if (part[0] == type)
return part;
return NULL;
}
const byte *
flow4_get_part(const net_addr_flow4 *f, uint type)
{
return flow_get_part(f->data, f->length - sizeof(net_addr_flow4), type, 0);
}
const byte *
flow6_get_part(const net_addr_flow6 *f, uint type)
{
return flow_get_part(f->data, f->length - sizeof(net_addr_flow6), type, 1);
}
/* /*
* Flowspec accessors * Flowspec accessors
*/ */
static inline ip4_addr static inline ip4_addr
flow_read_ip4(const byte *px, uint pxlen) flow_read_ip4(const byte *px, uint pxlen)
{ {
@ -282,7 +307,6 @@ flow_read_ip6_part(const byte *part)
} }
/* /*
* Flowspec validation * Flowspec validation
*/ */

View file

@ -83,6 +83,8 @@ const byte *flow4_first_part(const net_addr_flow4 *f);
const byte *flow6_first_part(const net_addr_flow6 *f); const byte *flow6_first_part(const net_addr_flow6 *f);
const byte *flow4_next_part(const byte *pos, const byte *end); const byte *flow4_next_part(const byte *pos, const byte *end);
const byte *flow6_next_part(const byte *pos, const byte *end); const byte *flow6_next_part(const byte *pos, const byte *end);
const byte *flow4_get_part(const net_addr_flow4 *f, uint type);
const byte *flow6_get_part(const net_addr_flow6 *f, uint type);
/* /*
@ -91,6 +93,7 @@ const byte *flow6_next_part(const byte *pos, const byte *end);
ip4_addr flow_read_ip4_part(const byte *part); ip4_addr flow_read_ip4_part(const byte *part);
ip6_addr flow_read_ip6_part(const byte *part); ip6_addr flow_read_ip6_part(const byte *part);
static inline int flow_read_pxlen(const byte *part) { return part[1]; }
/* /*