* Do proper source address selection on an unbound socket in case * of connect. Take jails into account as well. */
| 1236 | * of connect. Take jails into account as well. |
| 1237 | */ |
| 1238 | int |
| 1239 | in_pcbladdr(struct inpcb *inp, struct in_addr *faddr, struct in_addr *laddr, |
| 1240 | struct ucred *cred) |
| 1241 | { |
| 1242 | struct ifaddr *ifa; |
| 1243 | struct sockaddr *sa; |
| 1244 | struct sockaddr_in *sin, dst; |
| 1245 | struct nhop_object *nh; |
| 1246 | int error; |
| 1247 | |
| 1248 | NET_EPOCH_ASSERT(); |
| 1249 | KASSERT(laddr != NULL, ("%s: laddr NULL", __func__)); |
| 1250 | /* |
| 1251 | * Bypass source address selection and use the primary jail IP |
| 1252 | * if requested. |
| 1253 | */ |
| 1254 | if (cred != NULL && !prison_saddrsel_ip4(cred, laddr)) |
| 1255 | return (0); |
| 1256 | |
| 1257 | error = 0; |
| 1258 | |
| 1259 | nh = NULL; |
| 1260 | bzero(&dst, sizeof(dst)); |
| 1261 | sin = &dst; |
| 1262 | sin->sin_family = AF_INET; |
| 1263 | sin->sin_len = sizeof(struct sockaddr_in); |
| 1264 | sin->sin_addr.s_addr = faddr->s_addr; |
| 1265 | |
| 1266 | /* |
| 1267 | * If route is known our src addr is taken from the i/f, |
| 1268 | * else punt. |
| 1269 | * |
| 1270 | * Find out route to destination. |
| 1271 | */ |
| 1272 | if ((inp->inp_socket->so_options & SO_DONTROUTE) == 0) |
| 1273 | nh = fib4_lookup(inp->inp_inc.inc_fibnum, *faddr, |
| 1274 | 0, NHR_NONE, 0); |
| 1275 | |
| 1276 | /* |
| 1277 | * If we found a route, use the address corresponding to |
| 1278 | * the outgoing interface. |
| 1279 | * |
| 1280 | * Otherwise assume faddr is reachable on a directly connected |
| 1281 | * network and try to find a corresponding interface to take |
| 1282 | * the source address from. |
| 1283 | */ |
| 1284 | if (nh == NULL || nh->nh_ifp == NULL) { |
| 1285 | struct in_ifaddr *ia; |
| 1286 | struct ifnet *ifp; |
| 1287 | |
| 1288 | ia = ifatoia(ifa_ifwithdstaddr((struct sockaddr *)sin, |
| 1289 | inp->inp_socket->so_fibnum)); |
| 1290 | if (ia == NULL) { |
| 1291 | ia = ifatoia(ifa_ifwithnet((struct sockaddr *)sin, 0, |
| 1292 | inp->inp_socket->so_fibnum)); |
| 1293 | } |
| 1294 | if (ia == NULL) { |
| 1295 | error = ENETUNREACH; |
no test coverage detected