NOEXPORT int connect_init(CLI *c, int domain) {
    SOCKADDR_UNION bind_addr;

    if(c->bind_addr) {
        /* setup bind_addr based on c->bind_addr */
#if 0
        /* IPv6 addresses converted from IPv4 cause timeouts */
#ifdef USE_IPv6
        if(c->bind_addr->sa.sa_family==AF_INET && domain==AF_INET6) {
            /* convert the binding address from IPv4 to IPv6 */
            memset(&bind_addr, 0, sizeof bind_addr);
            bind_addr.in6.sin6_family=AF_INET6;
            bind_addr.in6.sin6_port=c->bind_addr->in.sin_port;
            /* address format example: ::ffff:192.0.2.128 */
            memset((char *)&bind_addr.in6.sin6_addr+10, 0xff, 2);
            memcpy((char *)&bind_addr.in6.sin6_addr+12,
                &c->bind_addr->in.sin_addr, 4);
        } else /* just make a local copy */
#endif
#endif
            memcpy(&bind_addr, c->bind_addr, (size_t)addr_len(c->bind_addr));
        /* perform the initial sanity checks before creating a socket */
        if(bind_addr.sa.sa_family!=domain) {
            s_log(LOG_DEBUG, "Cannot assign an AF=%d address an AF=%d socket",
                bind_addr.sa.sa_family, domain);
            return 1; /* failure */
        }
    }

    /* create a new socket */
    c->fd=s_socket(domain, SOCK_STREAM, 0, 1, "remote socket");
    if(c->fd==INVALID_SOCKET)
        return 1; /* failure */
    if(!c->bind_addr)
        return 0; /* success */

    /* enable non-local bind if needed (and supported) */
#ifndef USE_WIN32
    if(c->opt->option.transparent_src) {
#if defined(__linux__)
        /* non-local bind on Linux */
        int on=1;
        if(setsockopt(c->fd, SOL_IP, IP_TRANSPARENT, &on, sizeof on)) {
            sockerror("setsockopt IP_TRANSPARENT");
            if(setsockopt(c->fd, SOL_IP, IP_FREEBIND, &on, sizeof on))
                sockerror("setsockopt IP_FREEBIND");
            else
                s_log(LOG_INFO, "IP_FREEBIND socket option set");
        } else
            s_log(LOG_INFO, "IP_TRANSPARENT socket option set");
        /* ignore the error to retain Linux 2.2 compatibility */
        /* the error will be handled by bind(), anyway */
#elif defined(IP_BINDANY) && defined(IPV6_BINDANY)
        /* non-local bind on FreeBSD */
        int on=1;
        if(domain==AF_INET) { /* IPv4 */
            if(setsockopt(c->fd, IPPROTO_IP, IP_BINDANY, &on, sizeof on)) {
                sockerror("setsockopt IP_BINDANY");
                return 1; /* failure */
            }
        } else { /* IPv6 */
            if(setsockopt(c->fd, IPPROTO_IPV6, IPV6_BINDANY, &on, sizeof on)) {
                sockerror("setsockopt IPV6_BINDANY");
                return 1; /* failure */
            }
        }
#else
        /* unsupported platform */
        /* FIXME: move this check to options.c */
        s_log(LOG_ERR, "Transparent proxy in remote mode is not supported"
            " on this platform");
        throw_exception(c, 1);
#endif
    }
#endif /* !defined(USE_WIN32) */

    /* explicit local bind or transparent proxy */
    /* there is no need for a separate IPv6 logic here,
     * as port number is at the same offset in both structures */
    if(ntohs(bind_addr.in.sin_port)>=1024) { /* security check */
        /* this is currently only possible with transparent_src */
        if(!bind(c->fd, &bind_addr.sa, addr_len(&bind_addr))) {
            s_log(LOG_INFO, "bind succeeded on the original port");
            return 0; /* success */
        }
        if(get_last_socket_error()!=S_EADDRINUSE) {
            sockerror("bind (original port)");
            return 1; /* failure */
        }
    }
    bind_addr.in.sin_port=htons(0); /* retry with ephemeral port */
    if(!bind(c->fd, &bind_addr.sa, addr_len(&bind_addr))) {
        s_log(LOG_INFO, "bind succeeded on an ephemeral port");
        return 0; /* success */
    }
    sockerror("bind (ephemeral port)");
    return 1; /* failure */
}