예제 #1
0
파일: net.c 프로젝트: xzcvczx/transmission
static socklen_t setup_sockaddr(tr_address const* addr, tr_port port, struct sockaddr_storage* sockaddr)
{
    TR_ASSERT(tr_address_is_valid(addr));

    if (addr->type == TR_AF_INET)
    {
        struct sockaddr_in sock4;
        memset(&sock4, 0, sizeof(sock4));
        sock4.sin_family = AF_INET;
        sock4.sin_addr.s_addr = addr->addr.addr4.s_addr;
        sock4.sin_port = port;
        memcpy(sockaddr, &sock4, sizeof(sock4));
        return sizeof(struct sockaddr_in);
    }
    else
    {
        struct sockaddr_in6 sock6;
        memset(&sock6, 0, sizeof(sock6));
        sock6.sin6_family = AF_INET6;
        sock6.sin6_port = port;
        sock6.sin6_flowinfo = 0;
        sock6.sin6_addr = addr->addr.addr6;
        memcpy(sockaddr, &sock6, sizeof(sock6));
        return sizeof(struct sockaddr_in6);
    }
}
예제 #2
0
bool
tr_blocklistFileHasAddress (tr_blocklistFile * b, const tr_address * addr)
{
  uint32_t needle;
  const struct tr_ipv4_range * range;

  assert (tr_address_is_valid (addr));

  if (!b->isEnabled || addr->type == TR_AF_INET6)
    return false;

  blocklistEnsureLoaded (b);

  if (!b->rules || !b->ruleCount)
    return false;

  needle = ntohl (addr->addr.addr4.s_addr);

  range = bsearch (&needle,
                   b->rules,
                   b->ruleCount,
                   sizeof (struct tr_ipv4_range),
                   compareAddressToRange);

  return range != NULL;
}
예제 #3
0
bool tr_blocklistFileHasAddress(tr_blocklistFile* b, tr_address const* addr)
{
    TR_ASSERT(tr_address_is_valid(addr));

    uint32_t needle;
    struct tr_ipv4_range const* range;

    if (!b->isEnabled || addr->type == TR_AF_INET6)
    {
        return false;
    }

    blocklistEnsureLoaded(b);

    if (b->rules == NULL || b->ruleCount == 0)
    {
        return false;
    }

    needle = ntohl(addr->addr.addr4.s_addr);

    range = bsearch(&needle, b->rules, b->ruleCount, sizeof(struct tr_ipv4_range), compareAddressToRange);

    return range != NULL;
}
예제 #4
0
const char *
tr_address_to_string_with_buf (const tr_address * addr, char * buf, size_t buflen)
{
    assert (tr_address_is_valid (addr));

    if (addr->type == TR_AF_INET)
        return evutil_inet_ntop (AF_INET, &addr->addr, buf, buflen);
    else
        return evutil_inet_ntop (AF_INET6, &addr->addr, buf, buflen);
}
예제 #5
0
파일: net.c 프로젝트: xzcvczx/transmission
char const* tr_address_to_string_with_buf(tr_address const* addr, char* buf, size_t buflen)
{
    TR_ASSERT(tr_address_is_valid(addr));

    if (addr->type == TR_AF_INET)
    {
        return evutil_inet_ntop(AF_INET, &addr->addr, buf, buflen);
    }
    else
    {
        return evutil_inet_ntop(AF_INET6, &addr->addr, buf, buflen);
    }
}
예제 #6
0
파일: net.c 프로젝트: xzcvczx/transmission
/* isMartianAddr was written by Juliusz Chroboczek,
   and is covered under the same license as third-party/dht/dht.c. */
static bool isMartianAddr(struct tr_address const* a)
{
    TR_ASSERT(tr_address_is_valid(a));

    static unsigned char const zeroes[16] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };

    switch (a->type)
    {
    case TR_AF_INET:
        {
            unsigned char const* address = (unsigned char const*)&a->addr.addr4;
            return address[0] == 0 || address[0] == 127 || (address[0] & 0xE0) == 0xE0;
        }

    case TR_AF_INET6:
        {
            unsigned char const* address = (unsigned char const*)&a->addr.addr6;
            return address[0] == 0xFF || (memcmp(address, zeroes, 15) == 0 && (address[15] == 0 || address[15] == 1));
        }

    default:
        return true;
    }
}
예제 #7
0
파일: net.c 프로젝트: xzcvczx/transmission
bool tr_address_is_valid_for_peers(tr_address const* addr, tr_port port)
{
    return port != 0 && tr_address_is_valid(addr) && !isIPv6LinkLocalAddress(addr) && !isIPv4MappedAddress(addr) &&
           !isMartianAddr(addr);
}
예제 #8
0
파일: net.c 프로젝트: xzcvczx/transmission
static tr_socket_t tr_netBindTCPImpl(tr_address const* addr, tr_port port, bool suppressMsgs, int* errOut)
{
    TR_ASSERT(tr_address_is_valid(addr));

    static int const domains[NUM_TR_AF_INET_TYPES] = { AF_INET, AF_INET6 };
    struct sockaddr_storage sock;
    tr_socket_t fd;
    int addrlen;
    int optval;

    fd = socket(domains[addr->type], SOCK_STREAM, 0);

    if (fd == TR_BAD_SOCKET)
    {
        *errOut = sockerrno;
        return TR_BAD_SOCKET;
    }

    if (evutil_make_socket_nonblocking(fd) == -1)
    {
        *errOut = sockerrno;
        tr_netCloseSocket(fd);
        return TR_BAD_SOCKET;
    }

    optval = 1;
    setsockopt(fd, SOL_SOCKET, SO_KEEPALIVE, (void const*)&optval, sizeof(optval));
    setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (void const*)&optval, sizeof(optval));

#ifdef IPV6_V6ONLY

    if (addr->type == TR_AF_INET6)
    {
        if (setsockopt(fd, IPPROTO_IPV6, IPV6_V6ONLY, (void const*)&optval, sizeof(optval)) == -1)
        {
            if (sockerrno != ENOPROTOOPT) /* if the kernel doesn't support it, ignore it */
            {
                *errOut = sockerrno;
                tr_netCloseSocket(fd);
                return TR_BAD_SOCKET;
            }
        }
    }

#endif

    addrlen = setup_sockaddr(addr, htons(port), &sock);

    if (bind(fd, (struct sockaddr*)&sock, addrlen) == -1)
    {
        int const err = sockerrno;

        if (!suppressMsgs)
        {
            char const* fmt;
            char const* hint;
            char err_buf[512];

            if (err == EADDRINUSE)
            {
                hint = _("Is another copy of Transmission already running?");
            }
            else
            {
                hint = NULL;
            }

            if (hint == NULL)
            {
                fmt = _("Couldn't bind port %d on %s: %s");
            }
            else
            {
                fmt = _("Couldn't bind port %d on %s: %s (%s)");
            }

            tr_logAddError(fmt, port, tr_address_to_string(addr), tr_net_strerror(err_buf, sizeof(err_buf), err), hint);
        }

        tr_netCloseSocket(fd);
        *errOut = err;
        return TR_BAD_SOCKET;
    }

    if (!suppressMsgs)
    {
        tr_logAddDebug("Bound socket %" PRIdMAX " to port %d on %s", (intmax_t)fd, port, tr_address_to_string(addr));
    }

#ifdef TCP_FASTOPEN

#ifndef SOL_TCP
#define SOL_TCP IPPROTO_TCP
#endif

    optval = 5;
    setsockopt(fd, SOL_TCP, TCP_FASTOPEN, (void const*)&optval, sizeof(optval));

#endif

    if (listen(fd, 128) == -1)
    {
        *errOut = sockerrno;
        tr_netCloseSocket(fd);
        return TR_BAD_SOCKET;
    }

    return fd;
}
예제 #9
0
파일: net.c 프로젝트: xzcvczx/transmission
struct tr_peer_socket tr_netOpenPeerSocket(tr_session* session, tr_address const* addr, tr_port port, bool clientIsSeed)
{
    TR_ASSERT(tr_address_is_valid(addr));

    struct tr_peer_socket ret = TR_PEER_SOCKET_INIT;

    static int const domains[NUM_TR_AF_INET_TYPES] = { AF_INET, AF_INET6 };
    tr_socket_t s;
    struct sockaddr_storage sock;
    socklen_t addrlen;
    tr_address const* source_addr;
    socklen_t sourcelen;
    struct sockaddr_storage source_sock;
    char err_buf[512];

    if (!tr_address_is_valid_for_peers(addr, port))
    {
        return ret;
    }

    s = tr_fdSocketCreate(session, domains[addr->type], SOCK_STREAM);

    if (s == TR_BAD_SOCKET)
    {
        return ret;
    }

    /* seeds don't need much of a read buffer... */
    if (clientIsSeed)
    {
        int n = 8192;

        if (setsockopt(s, SOL_SOCKET, SO_RCVBUF, (void const*)&n, sizeof(n)) == -1)
        {
            tr_logAddInfo("Unable to set SO_RCVBUF on socket %" PRIdMAX ": %s", (intmax_t)s,
                tr_net_strerror(err_buf, sizeof(err_buf), sockerrno));
        }
    }

    if (evutil_make_socket_nonblocking(s) == -1)
    {
        tr_netClose(session, s);
        return ret;
    }

    addrlen = setup_sockaddr(addr, port, &sock);

    /* set source address */
    source_addr = tr_sessionGetPublicAddress(session, addr->type, NULL);
    TR_ASSERT(source_addr != NULL);
    sourcelen = setup_sockaddr(source_addr, 0, &source_sock);

    if (bind(s, (struct sockaddr*)&source_sock, sourcelen) == -1)
    {
        tr_logAddError(_("Couldn't set source address %s on %" PRIdMAX ": %s"), tr_address_to_string(source_addr), (intmax_t)s,
            tr_net_strerror(err_buf, sizeof(err_buf), sockerrno));
        tr_netClose(session, s);
        return ret;
    }

    if (connect(s, (struct sockaddr*)&sock, addrlen) == -1 &&
#ifdef _WIN32
        sockerrno != WSAEWOULDBLOCK &&
#endif
        sockerrno != EINPROGRESS)
    {
        int const tmperrno = sockerrno;

        if ((tmperrno != ENETUNREACH && tmperrno != EHOSTUNREACH) || addr->type == TR_AF_INET)
        {
            tr_logAddError(_("Couldn't connect socket %" PRIdMAX " to %s, port %d (errno %d - %s)"), (intmax_t)s,
                tr_address_to_string(addr), (int)ntohs(port), tmperrno, tr_net_strerror(err_buf, sizeof(err_buf), tmperrno));
        }

        tr_netClose(session, s);
    }
    else
    {
        ret = tr_peer_socket_tcp_create(s);
    }

    tr_logAddDeep(__FILE__, __LINE__, NULL, "New OUTGOING connection %" PRIdMAX " (%s)", (intmax_t)s,
        tr_peerIoAddrStr(addr, port));

    return ret;
}