Hi,
On Mon, 29 Jun 2020 10:12:23 +0200
Martin Pieuchot <[email protected]> wrote:
> On 28/06/20(Sun) 20:41, YASUOKA Masahiko wrote:
>> Hi,
>>
>> When "::/0" is used as "default",
>>
>> # route add ::/0 fe80::1%em0
>> add net ::/0: gateway fe80::1%em0: Invalid argument
>>
>> route command trims the sockaddr to { .len = 2, .family = AF_INET6 }
>> for "::/0", but rtable_satoplen() refuses it. I think it should be
>> accepted.
>
> rtable_satoplen() is used in many places, not just in the socket parsing
> code used by route(8). I don't know what side effects can be introduced
> by this change.
>
> Why is IPv6 different from IPv4 when it comes to the default route?
Diferent functions are used. route(8) uses inet_makenetandmask() to
create a sockaddr for IPv4 prefix length and uses prefixlen() for IPv6
prefix length. "/0" results:
IPv4
{ .len = 1, .family = 0, ... }
IPv6
{ .len = 2, .family = AF_INET6, ... }
Next, route(8) uses mask_addr() to trim the tailing zeros.
1129 void
1130 mask_addr(union sockunion *addr, union sockunion *mask, int which)
1131 {
1132 int olen = mask->sa.sa_len;
1133 char *cp1 = olen + (char *)mask, *cp2;
1134
1135 for (mask->sa.sa_len = 0; cp1 > (char *)mask; )
1136 if (*--cp1 != '\0') {
1137 mask->sa.sa_len = 1 + cp1 - (char *)mask;
1138 break;
1139 }
See #1135 carefully. As the results, the sockaddrs become:
IPv4
{ .len = 0, .family = 0, ... }
IPv6
{ .len = 2, .family = AF_INET6, ... }
Yes, we can fix IPv6 case to have .len = 0 as well.
But I thought kernel should accept both cases, since the
representation for IPv6 didn't seem so bad for me.
> Shouldn't we change route(8) to have a `sa_len' of 0?
>
> That would make the following true:
>
> mlen = mask->sa_len;
>
> /* Default route */
> if (mlen == 0)
> return (0)
>
>> Allow sockaddr for prefix length be trimmed before the key(address)
>> field. Actually "route" command trims at the address family field for
>> "::/0"
>>
>> Index: sys/net/rtable.c
>> ===================================================================
>> RCS file: /cvs/src/sys/net/rtable.c,v
>> retrieving revision 1.69
>> diff -u -p -r1.69 rtable.c
>> --- sys/net/rtable.c 21 Jun 2019 17:11:42 -0000 1.69
>> +++ sys/net/rtable.c 28 Jun 2020 11:30:54 -0000
>> @@ -887,8 +887,8 @@ rtable_satoplen(sa_family_t af, struct s
>>
>> ap = (uint8_t *)((uint8_t *)mask) + dp->dom_rtoffset;
>> ep = (uint8_t *)((uint8_t *)mask) + mlen;
>> - if (ap > ep)
>> - return (-1);
>> + if (ap >= ep)
>> + return (0);
>
> That means the kernel now silently ignore sockaddr short `sa_len'. Are
> they supposed to be supported or are they symptoms of bugs?
I have missed rtable_satoplen() is used by other functions.
>
>> /* Trim trailing zeroes. */
>> while (ap < ep && ep[-1] == 0)
>