| 346 | } |
| 347 | |
| 348 | static int |
| 349 | rtm_get_jailed(struct rt_addrinfo *info, struct ifnet *ifp, |
| 350 | struct nhop_object *nh, union sockaddr_union *saun, struct ucred *cred) |
| 351 | { |
| 352 | #if defined(INET) || defined(INET6) |
| 353 | struct epoch_tracker et; |
| 354 | #endif |
| 355 | |
| 356 | /* First, see if the returned address is part of the jail. */ |
| 357 | if (prison_if(cred, nh->nh_ifa->ifa_addr) == 0) { |
| 358 | info->rti_info[RTAX_IFA] = nh->nh_ifa->ifa_addr; |
| 359 | return (0); |
| 360 | } |
| 361 | |
| 362 | switch (info->rti_info[RTAX_DST]->sa_family) { |
| 363 | case AF_INET: |
| 364 | { |
| 365 | struct in_addr ia; |
| 366 | struct ifaddr *ifa; |
| 367 | int found; |
| 368 | |
| 369 | found = 0; |
| 370 | /* |
| 371 | * Try to find an address on the given outgoing interface |
| 372 | * that belongs to the jail. |
| 373 | */ |
| 374 | NET_EPOCH_ENTER(et); |
| 375 | CK_STAILQ_FOREACH(ifa, &ifp->if_addrhead, ifa_link) { |
| 376 | struct sockaddr *sa; |
| 377 | sa = ifa->ifa_addr; |
| 378 | if (sa->sa_family != AF_INET) |
| 379 | continue; |
| 380 | ia = ((struct sockaddr_in *)sa)->sin_addr; |
| 381 | if (prison_check_ip4(cred, &ia) == 0) { |
| 382 | found = 1; |
| 383 | break; |
| 384 | } |
| 385 | } |
| 386 | NET_EPOCH_EXIT(et); |
| 387 | if (!found) { |
| 388 | /* |
| 389 | * As a last resort return the 'default' jail address. |
| 390 | */ |
| 391 | ia = ((struct sockaddr_in *)nh->nh_ifa->ifa_addr)-> |
| 392 | sin_addr; |
| 393 | if (prison_get_ip4(cred, &ia) != 0) |
| 394 | return (ESRCH); |
| 395 | } |
| 396 | bzero(&saun->sin, sizeof(struct sockaddr_in)); |
| 397 | saun->sin.sin_len = sizeof(struct sockaddr_in); |
| 398 | saun->sin.sin_family = AF_INET; |
| 399 | saun->sin.sin_addr.s_addr = ia.s_addr; |
| 400 | info->rti_info[RTAX_IFA] = (struct sockaddr *)&saun->sin; |
| 401 | break; |
| 402 | } |
| 403 | #ifdef INET6 |
| 404 | case AF_INET6: |
| 405 | { |
no test coverage detected