If the redirect target isn't link local address, and redirect destination and redirect target address are the same,
the route install for redirect will fail.
In this cause, the type of gateway address is AF_LINK, the size of that address structure is 56 bytes, but the max size of store address of nhop
is only 28 bytes, which cause size check failure.
Details
- Reviewers
melifaro
Diff Detail
- Repository
- rG FreeBSD src repository
- Lint
Lint Skipped - Unit
Tests Skipped
Event Timeline
Thank you for submitting the patch. I’m not sure I fully understand the problem and the solution.
Could you please provide some examples?
Thank you for your replying, first of all, I want to say sorry for replying to you so late because I was a bit busy recently. I give a test example here.
ex:
a router send a redirect icmp6:
Frame 8: 110 bytes on wire (880 bits), 110 bytes captured (880 bits) on interface unknown, id 0
Ethernet II, Src: Sytek_10:10:60 (00:00:10:10:10:60), Dst: Dell_10:ba:3a (6c:3c:8c:10:ba:3a)
Internet Protocol Version 6, Src: fe80::200:10ff:fe10:1060, Dst: 2001:2:0:1000:49f1:31ca:b020:fc0a
Internet Control Message Protocol v6
Type: Redirect (137) Code: 0 Checksum: 0xcf90 [correct] [Checksum Status: Good] Reserved: 00000000 Target Address: 2001:2:0:1001:200:10ff:fe10:1180 Destination Address: 2001:2:0:1001:200:10ff:fe10:1180 ICMPv6 Option (Target link-layer address : 00:00:10:10:10:80) ICMPv6 Option (Source link-layer address : 22:22:22:22:22:22)
after the host receive it, we expect a new redirect route table will be added:
2001:2:0:1001:200:10ff:fe10:1180 #link1
but the route is not added, the adding is prevented by function nhop_set_gw length check
the redirect icmp6 process:
icmp6_redirect_input -> rib_add_redirect -> nhop_set_gw
the param gw and is_gw of nhop_set_gw are transmitted by icmp6_redirect_inpu, the value is set in icmp6.c line 2285, code show below:
is_router = is_onlink = 0; if (IN6_IS_ADDR_LINKLOCAL(&redtgt6)) is_router = 1; /* router case */ if (bcmp(&redtgt6, &reddst6, sizeof(redtgt6)) == 0) is_onlink = 1; /* on-link destination case */
Target Address is 2001:2:0:1001:200:10ff:fe10:1180, is not linklocal, so is_route=0, and is_online = 1.
in icmp6.c line 3448:
if (is_router) { bzero(&sgw, sizeof(sgw)); sgw.sin6_family = AF_INET6; sgw.sin6_len = sizeof(struct sockaddr_in6); bcopy(&redtgt6, &sgw.sin6_addr, sizeof(struct in6_addr)); gw = (struct sockaddr *)&sgw; rt_flags |= RTF_GATEWAY; } else gw = ifp->if_addr->ifa_addr; //run here for (fibnum = 0; fibnum < rt_numfibs; fibnum++) rib_add_redirect(fibnum, (struct sockaddr *)&sdst, gw, (struct sockaddr *)&ssrc, ifp, rt_flags, V_icmp6_redirtimeout);
the gw is ifa_addr, which is AF_LINK. so gw->sa_len is sizeof(struct sockaddr_dl_short), but in the nhop_set_gw, the length check compare with gw_buf length of struct nhop:
if (gw->sa_len > sizeof(nh->gw_buf)) { ... }
nh->gw_buf is defined with max size 28 bytes, but gw->sa_len is the size of struct sockaddr_dl_short which is 12 bytes. so the check return error.