- if (local_ip != 0 || local_port != 0) {
- memset(&locaddr, 0, sizeof(locaddr));
- locaddr.sin_family = AF_INET;
- locaddr.sin_port = htons(local_port);
- locaddr.sin_addr.s_addr = (local_ip == 0) ?
- INADDR_ANY : htonl(local_ip);
-
+ if (interface >= 0 || local_port != 0) {
+ struct sockaddr_storage locaddr = {};
+ struct sockaddr_in *sin = (void *)&locaddr;
+ struct sockaddr_in6 *sin6 = (void *)&locaddr;
+
+ switch (family) {
+ case AF_INET:
+ sin->sin_family = AF_INET;
+ sin->sin_addr.s_addr = INADDR_ANY;
+ if (interface >= 0 && remaddr) {
+ struct sockaddr_in *rem = (void *)remaddr;
+ __u32 ip;
+
+ rc = choose_ipv4_src(&ip,
+ interface,
+ ntohl(rem->sin_addr.s_addr),
+ ns);
+ if (rc)
+ goto failed;
+ sin->sin_addr.s_addr = htonl(ip);
+ }
+ sin->sin_port = htons(local_port);
+ break;
+ case AF_INET6:
+ sin6->sin6_family = AF_INET6;
+ sin6->sin6_addr = in6addr_any;
+ if (interface >= 0 && remaddr) {
+ struct sockaddr_in6 *rem = (void *)remaddr;
+
+ ipv6_dev_get_saddr(ns,
+ dev_get_by_index(ns,
+ interface),
+ &rem->sin6_addr, 0,
+ &sin6->sin6_addr);
+ }
+ sin6->sin6_port = htons(local_port);
+ break;
+ }