| 457 | #endif /* _SOCKADDR_UNION_DEFINED */ |
| 458 | |
| 459 | static int |
| 460 | rtm_get_jailed(struct rt_addrinfo *info, struct ifnet *ifp, |
| 461 | struct nhop_object *nh, union sockaddr_union *saun, struct ucred *cred) |
| 462 | { |
| 463 | #if defined(INET) || defined(INET6) |
| 464 | struct epoch_tracker et; |
| 465 | #endif |
| 466 | |
| 467 | /* First, see if the returned address is part of the jail. */ |
| 468 | if (prison_if(cred, nh->nh_ifa->ifa_addr) == 0) { |
| 469 | info->rti_info[RTAX_IFA] = nh->nh_ifa->ifa_addr; |
| 470 | return (0); |
| 471 | } |
| 472 | |
| 473 | switch (info->rti_info[RTAX_DST]->sa_family) { |
| 474 | #ifdef INET |
| 475 | case AF_INET: |
| 476 | { |
| 477 | struct in_addr ia; |
| 478 | struct ifaddr *ifa; |
| 479 | int found; |
| 480 | |
| 481 | found = 0; |
| 482 | /* |
| 483 | * Try to find an address on the given outgoing interface |
| 484 | * that belongs to the jail. |
| 485 | */ |
| 486 | NET_EPOCH_ENTER(et); |
| 487 | CK_STAILQ_FOREACH(ifa, &ifp->if_addrhead, ifa_link) { |
| 488 | struct sockaddr *sa; |
| 489 | sa = ifa->ifa_addr; |
| 490 | if (sa->sa_family != AF_INET) |
| 491 | continue; |
| 492 | ia = ((struct sockaddr_in *)sa)->sin_addr; |
| 493 | if (prison_check_ip4(cred, &ia) == 0) { |
| 494 | found = 1; |
| 495 | break; |
| 496 | } |
| 497 | } |
| 498 | NET_EPOCH_EXIT(et); |
| 499 | if (!found) { |
| 500 | /* |
| 501 | * As a last resort return the 'default' jail address. |
| 502 | */ |
| 503 | ia = ((struct sockaddr_in *)nh->nh_ifa->ifa_addr)-> |
| 504 | sin_addr; |
| 505 | if (prison_get_ip4(cred, &ia) != 0) |
| 506 | return (ESRCH); |
| 507 | } |
| 508 | bzero(&saun->sin, sizeof(struct sockaddr_in)); |
| 509 | saun->sin.sin_len = sizeof(struct sockaddr_in); |
| 510 | saun->sin.sin_family = AF_INET; |
| 511 | saun->sin.sin_addr.s_addr = ia.s_addr; |
| 512 | info->rti_info[RTAX_IFA] = (struct sockaddr *)&saun->sin; |
| 513 | break; |
| 514 | } |
| 515 | #endif |
| 516 | #ifdef INET6 |
no test coverage detected