+
+/*
+ * Translate addr in host addr when it is a virtual address
+ */
+void sotranslate_out(struct socket *so, struct sockaddr_storage *addr)
+{
+ Slirp *slirp = so->slirp;
+ struct sockaddr_in *sin = (struct sockaddr_in *)addr;
+ struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)addr;
+
+ switch (addr->ss_family) {
+ case AF_INET:
+ if ((so->so_faddr.s_addr & slirp->vnetwork_mask.s_addr) ==
+ slirp->vnetwork_addr.s_addr) {
+ /* It's an alias */
+ if (so->so_faddr.s_addr == slirp->vnameserver_addr.s_addr) {
+ if (get_dns_addr(&sin->sin_addr) < 0) {
+ sin->sin_addr = loopback_addr;
+ }
+ } else {
+ sin->sin_addr = loopback_addr;
+ }
+ }
+
+ DEBUG_MISC((dfd, " addr.sin_port=%d, "
+ "addr.sin_addr.s_addr=%.16s\n",
+ ntohs(sin->sin_port), inet_ntoa(sin->sin_addr)));
+ break;
+
+ case AF_INET6:
+ if (in6_equal_net(&so->so_faddr6, &slirp->vprefix_addr6,
+ slirp->vprefix_len)) {
+ if (in6_equal(&so->so_faddr6, &slirp->vnameserver_addr6)) {
+ /*if (get_dns_addr(&addr) < 0) {*/ /* TODO */
+ sin6->sin6_addr = in6addr_loopback;
+ /*}*/
+ } else {
+ sin6->sin6_addr = in6addr_loopback;
+ }
+ }
+ break;
+
+ default:
+ break;
+ }
+}
+
+void sotranslate_in(struct socket *so, struct sockaddr_storage *addr)
+{
+ Slirp *slirp = so->slirp;
+ struct sockaddr_in *sin = (struct sockaddr_in *)addr;
+ struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)addr;
+
+ switch (addr->ss_family) {
+ case AF_INET:
+ if ((so->so_faddr.s_addr & slirp->vnetwork_mask.s_addr) ==
+ slirp->vnetwork_addr.s_addr) {
+ uint32_t inv_mask = ~slirp->vnetwork_mask.s_addr;
+
+ if ((so->so_faddr.s_addr & inv_mask) == inv_mask) {
+ sin->sin_addr = slirp->vhost_addr;
+ } else if (sin->sin_addr.s_addr == loopback_addr.s_addr ||
+ so->so_faddr.s_addr != slirp->vhost_addr.s_addr) {
+ sin->sin_addr = so->so_faddr;
+ }
+ }
+ break;
+
+ case AF_INET6:
+ if (in6_equal_net(&so->so_faddr6, &slirp->vprefix_addr6,
+ slirp->vprefix_len)) {
+ if (in6_equal(&sin6->sin6_addr, &in6addr_loopback)
+ || !in6_equal(&so->so_faddr6, &slirp->vhost_addr6)) {
+ sin6->sin6_addr = so->so_faddr6;
+ }
+ }
+ break;
+
+ default:
+ break;
+ }
+}
+
+/*
+ * Translate connections from localhost to the real hostname
+ */
+void sotranslate_accept(struct socket *so)
+{
+ Slirp *slirp = so->slirp;
+
+ switch (so->so_ffamily) {
+ case AF_INET:
+ if (so->so_faddr.s_addr == INADDR_ANY ||
+ (so->so_faddr.s_addr & loopback_mask) ==
+ (loopback_addr.s_addr & loopback_mask)) {
+ so->so_faddr = slirp->vhost_addr;
+ }
+ break;
+
+ case AF_INET6:
+ if (in6_equal(&so->so_faddr6, &in6addr_any) ||
+ in6_equal(&so->so_faddr6, &in6addr_loopback)) {
+ so->so_faddr6 = slirp->vhost_addr6;
+ }
+ break;
+
+ default:
+ break;
+ }
+}