mirror of
https://gitlab.nic.cz/labs/bird.git
synced 2024-12-22 09:41:54 +00:00
Flowspec: Fix IPv6 prefix when offset is not multiple of 8
Current implementation handles flowspec prefix length and offset only in bytes, but RFC 8956 (Dissemination of Flow Specification Rules for IPv6) Section 3.1 [1] and example in Section 3.8.2 [2] states the pattern should begin right after offset *bits*. For example, pattern "::1:1234:5678:9800:0/60-104" is currently serialized as "02 68 3c 01 12 34 56 78 98", but it should shift its pattern 4 more bits to the left: "02 68 3c 11 23 45 67 89 80". This patch implements shifting left/right for IPv6 type and use it to correct the behaviour. Test data are replaced with the correct ones. Minor changes and test vectors done by committer. [1]: https://www.rfc-editor.org/rfc/rfc8956.html#section-3.1 [2]: https://www.rfc-editor.org/rfc/rfc8956.html#section-3.8.2
This commit is contained in:
parent
6f9ccfae9e
commit
072821e55e
@ -293,13 +293,9 @@ flow_read_ip4_part(const byte *part)
|
|||||||
static inline ip6_addr
|
static inline ip6_addr
|
||||||
flow_read_ip6(const byte *px, uint pxlen, uint pxoffset)
|
flow_read_ip6(const byte *px, uint pxlen, uint pxoffset)
|
||||||
{
|
{
|
||||||
uint floor_offset = BYTES(pxoffset - (pxoffset % 8));
|
|
||||||
uint ceil_len = BYTES(pxlen);
|
|
||||||
ip6_addr ip = IP6_NONE;
|
ip6_addr ip = IP6_NONE;
|
||||||
|
memcpy(&ip, px, BYTES(pxlen - pxoffset));
|
||||||
memcpy(((byte *) &ip) + floor_offset, px, ceil_len - floor_offset);
|
return ip6_shift_right(ip6_ntoh(ip), pxoffset);
|
||||||
|
|
||||||
return ip6_ntoh(ip);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
ip6_addr
|
ip6_addr
|
||||||
@ -476,7 +472,7 @@ flow_validate(const byte *nlri, uint len, int ipv6)
|
|||||||
uint pxoffset = *pos++;
|
uint pxoffset = *pos++;
|
||||||
if (pxoffset > IP6_MAX_PREFIX_LENGTH || pxoffset > pxlen)
|
if (pxoffset > IP6_MAX_PREFIX_LENGTH || pxoffset > pxlen)
|
||||||
return FLOW_ST_EXCEED_MAX_PREFIX_OFFSET;
|
return FLOW_ST_EXCEED_MAX_PREFIX_OFFSET;
|
||||||
bytes -= pxoffset / 8;
|
bytes = BYTES(pxlen - pxoffset);
|
||||||
}
|
}
|
||||||
pos += bytes;
|
pos += bytes;
|
||||||
|
|
||||||
@ -749,12 +745,12 @@ flow_builder6_add_pfx(struct flow_builder *fb, const net_addr_ip6 *n6, u32 pxoff
|
|||||||
if (!builder_add_prepare(fb))
|
if (!builder_add_prepare(fb))
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
ip6_addr ip6 = ip6_hton(n6->prefix);
|
ip6_addr ip6 = ip6_hton(ip6_shift_left(n6->prefix, pxoffset));
|
||||||
|
|
||||||
BUFFER_PUSH(fb->data) = fb->this_type;
|
BUFFER_PUSH(fb->data) = fb->this_type;
|
||||||
BUFFER_PUSH(fb->data) = n6->pxlen;
|
BUFFER_PUSH(fb->data) = n6->pxlen;
|
||||||
BUFFER_PUSH(fb->data) = pxoffset;
|
BUFFER_PUSH(fb->data) = pxoffset;
|
||||||
push_pfx_to_buffer(fb, BYTES(n6->pxlen) - (pxoffset / 8), ((byte *) &ip6) + (pxoffset / 8));
|
push_pfx_to_buffer(fb, BYTES(n6->pxlen - pxoffset), ((byte *) &ip6));
|
||||||
|
|
||||||
builder_add_finish(fb);
|
builder_add_finish(fb);
|
||||||
return 1;
|
return 1;
|
||||||
|
@ -542,7 +542,7 @@ t_builder6(void)
|
|||||||
|
|
||||||
const net_addr_flow6 *expect = NET_ADDR_FLOW6_NLRI(
|
const net_addr_flow6 *expect = NET_ADDR_FLOW6_NLRI(
|
||||||
0,
|
0,
|
||||||
FLOW_TYPE_DST_PREFIX, 103, 61, 0x01, 0x12, 0x34, 0x56, 0x78, 0x98,
|
FLOW_TYPE_DST_PREFIX, 103, 61, 0x22, 0x46, 0x8a, 0xcf, 0x13, 0x00,
|
||||||
FLOW_TYPE_SRC_PREFIX, 8, 0, 0xc0,
|
FLOW_TYPE_SRC_PREFIX, 8, 0, 0xc0,
|
||||||
FLOW_TYPE_NEXT_HEADER, 0x80, 0x06,
|
FLOW_TYPE_NEXT_HEADER, 0x80, 0x06,
|
||||||
FLOW_TYPE_PORT, 0x03, 0x89, 0x45, 0x8b, 0x91, 0x1f, 0x90,
|
FLOW_TYPE_PORT, 0x03, 0x89, 0x45, 0x8b, 0x91, 0x1f, 0x90,
|
||||||
@ -678,7 +678,7 @@ t_formatting6(void)
|
|||||||
expect[0] = "flow6 { dst ::1:1234:5678:9800:0/103 offset 61; src c000::/8; next header 6; port 20..40,273; label < 500000; }";
|
expect[0] = "flow6 { dst ::1:1234:5678:9800:0/103 offset 61; src c000::/8; next header 6; port 20..40,273; label < 500000; }";
|
||||||
input[0] = NET_ADDR_FLOW6_NLRI(
|
input[0] = NET_ADDR_FLOW6_NLRI(
|
||||||
0,
|
0,
|
||||||
FLOW_TYPE_DST_PREFIX, 103, 61, 0x01, 0x12, 0x34, 0x56, 0x78, 0x98,
|
FLOW_TYPE_DST_PREFIX, 103, 61, 0x22, 0x46, 0x8a, 0xcf, 0x13, 0x00,
|
||||||
FLOW_TYPE_SRC_PREFIX, 8, 0, 0xc0,
|
FLOW_TYPE_SRC_PREFIX, 8, 0, 0xc0,
|
||||||
FLOW_TYPE_NEXT_HEADER, 0x81, 0x06,
|
FLOW_TYPE_NEXT_HEADER, 0x81, 0x06,
|
||||||
FLOW_TYPE_PORT, 0x03, 20, 0x45, 40, 0x91, 0x01, 0x11,
|
FLOW_TYPE_PORT, 0x03, 20, 0x45, 40, 0x91, 0x01, 0x11,
|
||||||
|
48
lib/ip.c
48
lib/ip.c
@ -156,6 +156,54 @@ ip6_classify(ip6_addr *a)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* IPv6 bit shifting
|
||||||
|
*/
|
||||||
|
|
||||||
|
ip6_addr
|
||||||
|
ip6_shift_left(ip6_addr a, uint bits)
|
||||||
|
{
|
||||||
|
if (bits == 0)
|
||||||
|
return a;
|
||||||
|
|
||||||
|
if (bits > 127)
|
||||||
|
return IP6_NONE;
|
||||||
|
|
||||||
|
int words = bits / 32;
|
||||||
|
int rem = bits % 32;
|
||||||
|
|
||||||
|
for (int i = 0; i < 3 - words; i++)
|
||||||
|
a.addr[i] = (a.addr[i + words] << rem) |
|
||||||
|
(rem ? (a.addr[i + words + 1] >> (32 - rem)) : 0);
|
||||||
|
|
||||||
|
a.addr[3 - words] = a.addr[3] << rem;
|
||||||
|
memset(&a.addr[4 - words], 0, words * 4);
|
||||||
|
|
||||||
|
return a;
|
||||||
|
}
|
||||||
|
|
||||||
|
ip6_addr
|
||||||
|
ip6_shift_right(ip6_addr a, uint bits)
|
||||||
|
{
|
||||||
|
if (bits == 0)
|
||||||
|
return a;
|
||||||
|
|
||||||
|
if (bits > 127)
|
||||||
|
return IP6_NONE;
|
||||||
|
|
||||||
|
int words = bits / 32;
|
||||||
|
int rem = bits % 32;
|
||||||
|
|
||||||
|
for (int i = 3; i > words; i--)
|
||||||
|
a.addr[i] = (a.addr[i - words] >> rem) |
|
||||||
|
(rem ? (a.addr[i - words - 1] << (32 - rem)) : 0);
|
||||||
|
|
||||||
|
a.addr[words] = a.addr[0] >> rem;
|
||||||
|
memset(&a.addr[0], 0, words * 4);
|
||||||
|
|
||||||
|
return a;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Conversion of IPv6 address to presentation format and vice versa.
|
* Conversion of IPv6 address to presentation format and vice versa.
|
||||||
|
3
lib/ip.h
3
lib/ip.h
@ -354,6 +354,9 @@ static inline ip4_addr ip4_setbits(ip4_addr a, uint pos, uint val)
|
|||||||
static inline ip6_addr ip6_setbits(ip6_addr a, uint pos, uint val)
|
static inline ip6_addr ip6_setbits(ip6_addr a, uint pos, uint val)
|
||||||
{ a.addr[pos / 32] |= val << (31 - pos % 32); return a; }
|
{ a.addr[pos / 32] |= val << (31 - pos % 32); return a; }
|
||||||
|
|
||||||
|
ip6_addr ip6_shift_left(ip6_addr a, uint bits);
|
||||||
|
ip6_addr ip6_shift_right(ip6_addr a, uint bits);
|
||||||
|
|
||||||
|
|
||||||
static inline ip4_addr ip4_opposite_m1(ip4_addr a)
|
static inline ip4_addr ip4_opposite_m1(ip4_addr a)
|
||||||
{ return _MI4(_I(a) ^ 1); }
|
{ return _MI4(_I(a) ^ 1); }
|
||||||
|
@ -231,6 +231,66 @@ t_ip6_prefix_equal(void)
|
|||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
t_ip6_shift_left(void)
|
||||||
|
{
|
||||||
|
ip6_addr a = ip6_build(0x8D0D8BDC, 0x1F04DB92, 0xE5117673, 0x70E54449);
|
||||||
|
|
||||||
|
struct { int n; ip6_addr val; } test_vectors[] = {
|
||||||
|
0, ip6_build(0x8D0D8BDC, 0x1F04DB92, 0xE5117673, 0x70E54449),
|
||||||
|
9, ip6_build(0x1B17B83E, 0x09B725CA, 0x22ECE6E1, 0xCA889200),
|
||||||
|
18, ip6_build(0x2F707C13, 0x6E4B9445, 0xD9CDC395, 0x11240000),
|
||||||
|
27, ip6_build(0xE0F826DC, 0x97288BB3, 0x9B872A22, 0x48000000),
|
||||||
|
36, ip6_build(0xF04DB92E, 0x51176737, 0x0E544490, 0x00000000),
|
||||||
|
45, ip6_build(0x9B725CA2, 0x2ECE6E1C, 0xA8892000, 0x00000000),
|
||||||
|
54, ip6_build(0xE4B9445D, 0x9CDC3951, 0x12400000, 0x00000000),
|
||||||
|
63, ip6_build(0x7288BB39, 0xB872A224, 0x80000000, 0x00000000),
|
||||||
|
72, ip6_build(0x11767370, 0xE5444900, 0x00000000, 0x00000000),
|
||||||
|
81, ip6_build(0xECE6E1CA, 0x88920000, 0x00000000, 0x00000000),
|
||||||
|
90, ip6_build(0xCDC39511, 0x24000000, 0x00000000, 0x00000000),
|
||||||
|
99, ip6_build(0x872A2248, 0x00000000, 0x00000000, 0x00000000),
|
||||||
|
108, ip6_build(0x54449000, 0x00000000, 0x00000000, 0x00000000),
|
||||||
|
117, ip6_build(0x89200000, 0x00000000, 0x00000000, 0x00000000),
|
||||||
|
126, ip6_build(0x40000000, 0x00000000, 0x00000000, 0x00000000),
|
||||||
|
128, ip6_build(0x00000000, 0x00000000, 0x00000000, 0x00000000),
|
||||||
|
};
|
||||||
|
|
||||||
|
for (uint i = 0; i < ARRAY_SIZE(test_vectors); i++)
|
||||||
|
bt_assert(ip6_equal(ip6_shift_left(a, test_vectors[i].n), test_vectors[i].val));
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
t_ip6_shift_right(void)
|
||||||
|
{
|
||||||
|
ip6_addr a = ip6_build(0x8D0D8BDC, 0x1F04DB92, 0xE5117673, 0x70E54449);
|
||||||
|
|
||||||
|
struct { int n; ip6_addr val; } test_vectors[] = {
|
||||||
|
0, ip6_build(0x8D0D8BDC, 0x1F04DB92, 0xE5117673, 0x70E54449),
|
||||||
|
9, ip6_build(0x004686C5, 0xEE0F826D, 0xC97288BB, 0x39B872A2),
|
||||||
|
18, ip6_build(0x00002343, 0x62F707C1, 0x36E4B944, 0x5D9CDC39),
|
||||||
|
27, ip6_build(0x00000011, 0xA1B17B83, 0xE09B725C, 0xA22ECE6E),
|
||||||
|
36, ip6_build(0x00000000, 0x08D0D8BD, 0xC1F04DB9, 0x2E511767),
|
||||||
|
45, ip6_build(0x00000000, 0x0004686C, 0x5EE0F826, 0xDC97288B),
|
||||||
|
54, ip6_build(0x00000000, 0x00000234, 0x362F707C, 0x136E4B94),
|
||||||
|
63, ip6_build(0x00000000, 0x00000001, 0x1A1B17B8, 0x3E09B725),
|
||||||
|
72, ip6_build(0x00000000, 0x00000000, 0x008D0D8B, 0xDC1F04DB),
|
||||||
|
81, ip6_build(0x00000000, 0x00000000, 0x00004686, 0xC5EE0F82),
|
||||||
|
90, ip6_build(0x00000000, 0x00000000, 0x00000023, 0x4362F707),
|
||||||
|
99, ip6_build(0x00000000, 0x00000000, 0x00000000, 0x11A1B17B),
|
||||||
|
108, ip6_build(0x00000000, 0x00000000, 0x00000000, 0x0008D0D8),
|
||||||
|
117, ip6_build(0x00000000, 0x00000000, 0x00000000, 0x00000468),
|
||||||
|
126, ip6_build(0x00000000, 0x00000000, 0x00000000, 0x00000002),
|
||||||
|
128, ip6_build(0x00000000, 0x00000000, 0x00000000, 0x00000000),
|
||||||
|
};
|
||||||
|
|
||||||
|
for (uint i = 0; i < ARRAY_SIZE(test_vectors); i++)
|
||||||
|
bt_assert(ip6_equal(ip6_shift_right(a, test_vectors[i].n), test_vectors[i].val));
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
int
|
int
|
||||||
main(int argc, char *argv[])
|
main(int argc, char *argv[])
|
||||||
{
|
{
|
||||||
@ -242,6 +302,8 @@ main(int argc, char *argv[])
|
|||||||
bt_test_suite(t_ip6_ntop, "Converting ip6_addr struct to IPv6 string");
|
bt_test_suite(t_ip6_ntop, "Converting ip6_addr struct to IPv6 string");
|
||||||
bt_test_suite(t_ip4_prefix_equal, "Testing ip4_prefix_equal()");
|
bt_test_suite(t_ip4_prefix_equal, "Testing ip4_prefix_equal()");
|
||||||
bt_test_suite(t_ip6_prefix_equal, "Testing ip6_prefix_equal()");
|
bt_test_suite(t_ip6_prefix_equal, "Testing ip6_prefix_equal()");
|
||||||
|
bt_test_suite(t_ip6_shift_left, "Testing ip6_shift_left()");
|
||||||
|
bt_test_suite(t_ip6_shift_right, "Testing ip6_shift_right()");
|
||||||
|
|
||||||
return bt_exit_value();
|
return bt_exit_value();
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user