123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978 |
- #include <kopano/platform.h>
- #include <memory>
- #include <new>
- #include <kopano/ECChannel.h>
- #include <kopano/stringutil.h>
- #include <csignal>
- #include <netdb.h>
- #include <poll.h>
- #include <sys/types.h>
- #include <sys/socket.h>
- #include <sys/stat.h>
- #include <sys/un.h>
- #include <netinet/in.h>
- #include <netinet/tcp.h>
- #include <arpa/inet.h>
- #ifdef LINUX
- #include <linux/rtnetlink.h>
- #endif
- #include <cerrno>
- #include <mapicode.h>
- #ifndef hrSuccess
- #define hrSuccess 0
- #endif
- namespace KC {
- SSL_CTX* ECChannel::lpCTX = NULL;
- HRESULT ECChannel::HrSetCtx(ECConfig *lpConfig)
- {
- if (lpConfig == NULL) {
- ec_log_err("ECChannel::HrSetCtx(): invalid parameters");
- return MAPI_E_CALL_FAILED;
- }
- HRESULT hr = hrSuccess;
- const char *szFile = NULL;
- const char *szPath = NULL;
- std::unique_ptr<char> ssl_protocols(strdup(lpConfig->GetSetting("ssl_protocols")));
- const char *ssl_ciphers = lpConfig->GetSetting("ssl_ciphers");
- char *ssl_name = NULL;
- int ssl_op = 0, ssl_include = 0, ssl_exclude = 0;
- #if !defined(OPENSSL_NO_ECDH) && defined(NID_X9_62_prime256v1)
- EC_KEY *ecdh;
- #endif
- if (lpCTX) {
- SSL_CTX_free(lpCTX);
- lpCTX = NULL;
- }
- SSL_library_init();
- SSL_load_error_strings();
-
- lpCTX = SSL_CTX_new(SSLv23_server_method());
- SSL_CTX_set_options(lpCTX, SSL_OP_ALL);
- ssl_name = strtok(ssl_protocols.get(), " ");
- while(ssl_name != NULL) {
- int ssl_proto = 0;
- bool ssl_neg = false;
- if (*ssl_name == '!') {
- ++ssl_name;
- ssl_neg = true;
- }
- if (strcasecmp(ssl_name, SSL_TXT_SSLV3) == 0)
- ssl_proto = 0x02;
- #ifdef SSL_TXT_SSLV2
- else if (strcasecmp(ssl_name, SSL_TXT_SSLV2) == 0)
- ssl_proto = 0x01;
- #endif
- else if (strcasecmp(ssl_name, SSL_TXT_TLSV1) == 0)
- ssl_proto = 0x04;
- #ifdef SSL_TXT_TLSV1_1
- else if (strcasecmp(ssl_name, SSL_TXT_TLSV1_1) == 0)
- ssl_proto = 0x08;
- #endif
- #ifdef SSL_TXT_TLSV1_2
- else if (strcasecmp(ssl_name, SSL_TXT_TLSV1_2) == 0)
- ssl_proto = 0x10;
- #endif
- else {
- ec_log_err("Unknown protocol \"%s\" in ssl_protocols setting", ssl_name);
- hr = MAPI_E_CALL_FAILED;
- goto exit;
- }
- if (ssl_neg)
- ssl_exclude |= ssl_proto;
- else
- ssl_include |= ssl_proto;
- ssl_name = strtok(NULL, " ");
- }
- if (ssl_include != 0) {
-
- ssl_exclude |= 0x1f & ~ssl_include;
- }
- if ((ssl_exclude & 0x01) != 0)
- ssl_op |= SSL_OP_NO_SSLv2;
- if ((ssl_exclude & 0x02) != 0)
- ssl_op |= SSL_OP_NO_SSLv3;
- if ((ssl_exclude & 0x04) != 0)
- ssl_op |= SSL_OP_NO_TLSv1;
- #ifdef SSL_OP_NO_TLSv1_1
- if ((ssl_exclude & 0x08) != 0)
- ssl_op |= SSL_OP_NO_TLSv1_1;
- #endif
- #ifdef SSL_OP_NO_TLSv1_2
- if ((ssl_exclude & 0x10) != 0)
- ssl_op |= SSL_OP_NO_TLSv1_2;
- #endif
- if (ssl_protocols) {
- SSL_CTX_set_options(lpCTX, ssl_op);
- }
- #if !defined(OPENSSL_NO_ECDH) && defined(NID_X9_62_prime256v1)
- ecdh = EC_KEY_new_by_curve_name(NID_X9_62_prime256v1);
- if (ecdh != NULL) {
-
- SSL_CTX_set_options(lpCTX, SSL_OP_SINGLE_ECDH_USE);
- SSL_CTX_set_tmp_ecdh(lpCTX, ecdh);
- EC_KEY_free(ecdh);
- }
- #endif
- if (ssl_ciphers && SSL_CTX_set_cipher_list(lpCTX, ssl_ciphers) != 1) {
- ec_log_err("Can not set SSL cipher list to \"%s\": %s", ssl_ciphers, ERR_error_string(ERR_get_error(), 0));
- hr = MAPI_E_CALL_FAILED;
- goto exit;
- }
- if (parseBool(lpConfig->GetSetting("ssl_prefer_server_ciphers"))) {
- SSL_CTX_set_options(lpCTX, SSL_OP_CIPHER_SERVER_PREFERENCE);
- }
- SSL_CTX_set_default_verify_paths(lpCTX);
- if (SSL_CTX_use_certificate_chain_file(lpCTX, lpConfig->GetSetting("ssl_certificate_file")) != 1) {
- ec_log_err("SSL CTX certificate file error: %s", ERR_error_string(ERR_get_error(), 0));
- hr = MAPI_E_CALL_FAILED;
- goto exit;
- }
- if (SSL_CTX_use_PrivateKey_file(lpCTX, lpConfig->GetSetting("ssl_private_key_file"), SSL_FILETYPE_PEM) != 1) {
- ec_log_err("SSL CTX private key file error: %s", ERR_error_string(ERR_get_error(), 0));
- hr = MAPI_E_CALL_FAILED;
- goto exit;
- }
- if (SSL_CTX_check_private_key(lpCTX) != 1) {
- ec_log_err("SSL CTX check private key error: %s", ERR_error_string(ERR_get_error(), 0));
- hr = MAPI_E_CALL_FAILED;
- goto exit;
- }
- if (strcmp(lpConfig->GetSetting("ssl_verify_client"), "yes") == 0)
- SSL_CTX_set_verify(lpCTX, SSL_VERIFY_PEER | SSL_VERIFY_FAIL_IF_NO_PEER_CERT, 0);
- else
- SSL_CTX_set_verify(lpCTX, SSL_VERIFY_NONE, 0);
- if (lpConfig->GetSetting("ssl_verify_file")[0])
- szFile = lpConfig->GetSetting("ssl_verify_file");
- if (lpConfig->GetSetting("ssl_verify_path")[0])
- szPath = lpConfig->GetSetting("ssl_verify_path");
- if (szFile || szPath) {
- if (SSL_CTX_load_verify_locations(lpCTX, szFile, szPath) != 1)
- ec_log_err("SSL CTX error loading verify locations: %s", ERR_error_string(ERR_get_error(), 0));
- }
- exit:
- if (hr != hrSuccess)
- HrFreeCtx();
- return hr;
- }
- HRESULT ECChannel::HrFreeCtx() {
- if (lpCTX) {
- SSL_CTX_free(lpCTX);
- lpCTX = NULL;
- }
- return hrSuccess;
- }
- ECChannel::ECChannel(int fd) {
- int flag = 1;
-
- this->fd = fd;
- if (setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, reinterpret_cast<const char *>(&flag), sizeof(flag)) < 0)
- ;
- *peer_atxt = '\0';
- memset(&peer_sockaddr, 0, sizeof(peer_sockaddr));
- }
- ECChannel::~ECChannel() {
- if (lpSSL) {
- SSL_shutdown(lpSSL);
- SSL_free(lpSSL);
- }
- close(fd);
- }
- HRESULT ECChannel::HrEnableTLS(void)
- {
- int rc = -1;
- HRESULT hr = hrSuccess;
- if (lpSSL || lpCTX == NULL) {
- hr = MAPI_E_CALL_FAILED;
- ec_log_err("ECChannel::HrEnableTLS(): invalid parameters");
- goto exit;
- }
- lpSSL = SSL_new(lpCTX);
- if (!lpSSL) {
- ec_log_err("ECChannel::HrEnableTLS(): SSL_new failed");
- hr = MAPI_E_CALL_FAILED;
- goto exit;
- }
- SSL_clear(lpSSL);
- if (SSL_set_fd(lpSSL, fd) != 1) {
- ec_log_err("ECChannel::HrEnableTLS(): SSL_set_fd failed");
- hr = MAPI_E_CALL_FAILED;
- goto exit;
- }
- SSL_set_accept_state(lpSSL);
- if ((rc = SSL_accept(lpSSL)) != 1) {
- ec_log_err("ECChannel::HrEnableTLS(): SSL_accept failed: %d", SSL_get_error(lpSSL, rc));
- hr = MAPI_E_CALL_FAILED;
- goto exit;
- }
- exit:
- if (hr != hrSuccess && lpSSL) {
- SSL_shutdown(lpSSL);
- SSL_free(lpSSL);
- lpSSL = NULL;
- }
- return hr;
- }
- HRESULT ECChannel::HrGets(char *szBuffer, ULONG ulBufSize, ULONG *lpulRead) {
- char *lpRet = NULL;
- int len = ulBufSize;
- if (!szBuffer || !lpulRead)
- return MAPI_E_INVALID_PARAMETER;
- if (lpSSL)
- lpRet = SSL_gets(szBuffer, &len);
- else
- lpRet = fd_gets(szBuffer, &len);
- if (lpRet) {
- *lpulRead = len;
- return hrSuccess;
- }
- return MAPI_E_CALL_FAILED;
- }
- HRESULT ECChannel::HrReadLine(std::string * strBuffer, ULONG ulMaxBuffer) {
- HRESULT hr = hrSuccess;
- ULONG ulRead = 0;
- if(!strBuffer)
- return MAPI_E_INVALID_PARAMETER;
- char buffer[65536];
-
- strBuffer->clear();
- do {
- hr = HrGets(buffer, 65536, &ulRead);
- if (hr != hrSuccess)
- break;
- strBuffer->append(buffer, ulRead);
- if (strBuffer->size() > ulMaxBuffer) {
- hr = MAPI_E_TOO_BIG;
- break;
- }
- } while (ulRead == 65535);
- return hr;
- }
- HRESULT ECChannel::HrWriteString(const char *szBuffer)
- {
- HRESULT hr = hrSuccess;
- if(!szBuffer)
- return MAPI_E_INVALID_PARAMETER;
- if (lpSSL) {
- if (SSL_write(lpSSL, szBuffer, (int)strlen(szBuffer)) < 1)
- hr = MAPI_E_NETWORK_ERROR;
- }
- else if (send(fd, szBuffer, (int)strlen(szBuffer), 0) < 1) {
- hr = MAPI_E_NETWORK_ERROR;
- }
- return hr;
- }
- HRESULT ECChannel::HrWriteString(const std::string & strBuffer) {
- HRESULT hr = hrSuccess;
- if (lpSSL) {
- if (SSL_write(lpSSL, strBuffer.c_str(), (int)strBuffer.size()) < 1)
- hr = MAPI_E_NETWORK_ERROR;
- } else if (send(fd, strBuffer.c_str(), (int)strBuffer.size(), 0) < 1) {
- hr = MAPI_E_NETWORK_ERROR;
- }
- return hr;
- }
- HRESULT ECChannel::HrWriteLine(const char *szBuffer, int len) {
- std::string strLine;
- if (len == 0)
- strLine.assign(szBuffer);
- else
- strLine.assign(szBuffer, len);
- strLine += "\r\n";
-
- return HrWriteString(strLine);
- }
- HRESULT ECChannel::HrWriteLine(const std::string & strBuffer) {
- return HrWriteString(strBuffer + "\r\n");
- }
- HRESULT ECChannel::HrReadAndDiscardBytes(ULONG ulByteCount) {
- ULONG ulTotRead = 0;
- char szBuffer[4096];
- while (ulTotRead < ulByteCount) {
- ULONG ulBytesLeft = ulByteCount - ulTotRead;
- ULONG ulRead = ulBytesLeft > sizeof szBuffer ? sizeof szBuffer : ulBytesLeft;
- if (lpSSL)
- ulRead = SSL_read(lpSSL, szBuffer, ulRead);
- else
- ulRead = recv(fd, szBuffer, ulRead, 0);
- if (ulRead == (ULONG)-1) {
- if (errno == EINTR)
- continue;
- return MAPI_E_NETWORK_ERROR;
- }
- if (ulRead == 0 || ulRead > ulByteCount)
- return MAPI_E_NETWORK_ERROR;
- ulTotRead += ulRead;
- }
- return (ulTotRead == ulByteCount) ? hrSuccess : MAPI_E_CALL_FAILED;
- }
- HRESULT ECChannel::HrReadBytes(char *szBuffer, ULONG ulByteCount) {
- ULONG ulRead = 0;
- ULONG ulTotRead = 0;
- if(!szBuffer)
- return MAPI_E_INVALID_PARAMETER;
- while(ulTotRead < ulByteCount) {
- if (lpSSL)
- ulRead = SSL_read(lpSSL, szBuffer + ulTotRead, ulByteCount - ulTotRead);
- else
- ulRead = recv(fd, szBuffer + ulTotRead, ulByteCount - ulTotRead, 0);
- if (ulRead == (ULONG)-1) {
- if (errno == EINTR)
- continue;
- return MAPI_E_NETWORK_ERROR;
- }
- if (ulRead == 0 || ulRead > ulByteCount)
- return MAPI_E_NETWORK_ERROR;
- ulTotRead += ulRead;
- }
- szBuffer[ulTotRead] = '\0';
- return (ulTotRead == ulByteCount) ? hrSuccess : MAPI_E_CALL_FAILED;
- }
- HRESULT ECChannel::HrReadBytes(std::string * strBuffer, ULONG ulByteCount) {
- HRESULT hr = hrSuccess;
- std::unique_ptr<char[]> buffer;
- if (strBuffer == nullptr)
- return MAPI_E_INVALID_PARAMETER;
- buffer.reset(new(std::nothrow) char[ulByteCount+1]);
- if (buffer == nullptr)
- return MAPI_E_NOT_ENOUGH_MEMORY;
- hr = HrReadBytes(buffer.get(), ulByteCount);
- if (hr != hrSuccess)
- return hr;
- strBuffer->assign(buffer.get(), ulByteCount);
- return hrSuccess;
- }
- HRESULT ECChannel::HrSelect(int seconds) {
- struct pollfd pollfd = {fd, POLLIN | POLLRDHUP, 0};
- if(lpSSL && SSL_pending(lpSSL))
- return hrSuccess;
- int res = poll(&pollfd, 1, seconds * 1000);
- if (res == -1) {
- if (errno == EINTR)
-
- return MAPI_E_CANCEL;
- return MAPI_E_NETWORK_ERROR;
- }
- if (res == 0)
- return MAPI_E_TIMEOUT;
- return hrSuccess;
- }
- char * ECChannel::fd_gets(char *buf, int *lpulLen) {
- char *newline = NULL, *bp = buf;
- int len = *lpulLen;
- if (--len < 1)
- return NULL;
- do {
-
- int n = recv(fd, bp, len, MSG_PEEK);
- if (n == 0)
- return NULL;
- if (n == -1) {
- if (errno == EINTR)
- continue;
- return NULL;
- }
- if ((newline = (char *)memchr((void *)bp, '\n', n)) != NULL)
- n = newline - bp + 1;
- retry:
- int recv_n = recv(fd, bp, n, 0);
- if (recv_n == 0)
- return NULL;
- if (recv_n == -1) {
- if (errno == EINTR)
- goto retry;
- return NULL;
- }
- bp += recv_n;
- len -= recv_n;
- }
- while(!newline && len > 0);
-
- if(newline){
- --bp;
- --newline;
- if(newline >= buf && *newline == '\r')
- --bp;
- }
- *bp = '\0';
- *lpulLen = (int)(bp - buf);
- return buf;
- }
- char * ECChannel::SSL_gets(char *buf, int *lpulLen) {
- char *newline, *bp = buf;
- int len = *lpulLen;
- int n = 0;
- if (--len < 1)
- return NULL;
- do {
-
- if ((n = SSL_peek(lpSSL, bp, len)) <= 0)
- return NULL;
- if ((newline = (char *)memchr((void *)bp, '\n', n)) != NULL)
- n = newline - bp + 1;
- if ((n = SSL_read(lpSSL, bp, n)) < 0)
- return NULL;
- bp += n;
- len -= n;
- } while (!newline && len > 0);
-
-
- if(newline){
- --bp;
- --newline;
- if(newline >= buf && *newline == '\r')
- --bp;
- }
- *bp = '\0';
- *lpulLen = (int)(bp - buf);
- return buf;
- }
- void ECChannel::SetIPAddress(const struct sockaddr *sa, size_t slen)
- {
- char host[256], serv[16];
- if (getnameinfo(sa, slen, host, sizeof(host), serv, sizeof(serv),
- NI_NUMERICHOST | NI_NUMERICSERV) != 0)
- snprintf(peer_atxt, sizeof(peer_atxt), "<indeterminate>");
- else if (sa->sa_family == AF_INET6)
- snprintf(peer_atxt, sizeof(peer_atxt), "[%s]:%s", host, serv);
- else if (sa->sa_family == AF_UNIX)
- snprintf(peer_atxt, sizeof(peer_atxt), "unix:%s:%s", host, serv);
- else
- snprintf(peer_atxt, sizeof(peer_atxt), "%s:%s", host, serv);
- memcpy(&peer_sockaddr, sa, slen);
- peer_salen = slen;
- }
- #ifdef LINUX
- static int peer_is_local2(int rsk, const struct nlmsghdr *nlh)
- {
- if (send(rsk, nlh, nlh->nlmsg_len, 0) < 0)
- return -errno;
- char rspbuf[512];
- ssize_t ret = recv(rsk, rspbuf, sizeof(rspbuf), 0);
- if (ret < 0)
- return -errno;
- if (static_cast<size_t>(ret) < sizeof(struct nlmsghdr))
- return -ENODATA;
- nlh = reinterpret_cast<const struct nlmsghdr *>(rspbuf);
- if (!NLMSG_OK(nlh, nlh->nlmsg_len))
- return -EIO;
- auto rtm = reinterpret_cast<const struct rtmsg *>(NLMSG_DATA(nlh));
- return rtm->rtm_type == RTN_LOCAL;
- }
- #endif
- int zcp_peeraddr_is_local(const struct sockaddr *peer_sockaddr,
- socklen_t peer_socklen)
- {
- if (peer_sockaddr->sa_family == AF_UNIX) {
- return true;
- } else if (peer_sockaddr->sa_family == AF_INET6) {
- if (peer_socklen < sizeof(struct sockaddr_in6))
- return -EIO;
- } else if (peer_sockaddr->sa_family == AF_INET) {
- if (peer_socklen < sizeof(struct sockaddr_in))
- return -EIO;
- } else {
- return -EPROTONOSUPPORT;
- }
- #ifdef LINUX
- int rsk = socket(AF_NETLINK, SOCK_DGRAM, NETLINK_ROUTE);
- if (rsk < 0) {
- fprintf(stderr, "socket AF_NETLINK: %s\n", strerror(errno));
- return -errno;
- }
- struct {
- struct nlmsghdr nh;
- struct rtmsg rth;
- char attrbuf[512];
- } req;
- memset(&req, 0, sizeof(req));
- req.nh.nlmsg_len = NLMSG_LENGTH(sizeof(req.rth));
- req.nh.nlmsg_flags = NLM_F_REQUEST;
- req.nh.nlmsg_type = RTM_GETROUTE;
- req.rth.rtm_family = peer_sockaddr->sa_family;
- req.rth.rtm_protocol = RTPROT_UNSPEC;
- req.rth.rtm_type = RTN_UNSPEC;
- req.rth.rtm_scope = RT_SCOPE_UNIVERSE;
- req.rth.rtm_table = RT_TABLE_UNSPEC;
- auto rta = reinterpret_cast<struct rtattr *>(reinterpret_cast<char *>(&req) + NLMSG_ALIGN(req.nh.nlmsg_len));
- rta->rta_type = RTA_DST;
- int ret = -ENODATA;
- if (peer_sockaddr->sa_family == AF_INET6) {
- const struct in6_addr &ad = reinterpret_cast<const struct sockaddr_in6 *>(peer_sockaddr)->sin6_addr;
- static const uint8_t mappedv4[] =
- {0,0,0,0, 0,0,0,0, 0,0,0xff,0xff};
- req.rth.rtm_dst_len = sizeof(ad);
- if (memcmp(&ad, mappedv4, 12) == 0) {
-
- req.rth.rtm_family = AF_INET;
- rta->rta_len = RTA_LENGTH(sizeof(struct in_addr));
- req.nh.nlmsg_len = NLMSG_ALIGN(req.nh.nlmsg_len) + rta->rta_len;
- memcpy(RTA_DATA(rta), &ad.s6_addr[12], 4);
- } else {
- rta->rta_len = RTA_LENGTH(sizeof(ad));
- req.nh.nlmsg_len = NLMSG_ALIGN(req.nh.nlmsg_len) + rta->rta_len;
- memcpy(RTA_DATA(rta), &ad, sizeof(ad));
- }
- } else if (peer_sockaddr->sa_family == AF_INET) {
- const struct in_addr &ad = reinterpret_cast<const struct sockaddr_in *>(peer_sockaddr)->sin_addr;
- req.rth.rtm_dst_len = sizeof(ad);
- rta->rta_len = RTA_LENGTH(sizeof(ad));
- req.nh.nlmsg_len = NLMSG_ALIGN(req.nh.nlmsg_len) + rta->rta_len;
- memcpy(RTA_DATA(rta), &ad, sizeof(ad));
- }
- ret = peer_is_local2(rsk, &req.nh);
- close(rsk);
- return ret;
- #endif
- return -EPROTONOSUPPORT;
- }
- int zcp_peerfd_is_local(int fd)
- {
- struct sockaddr_storage peer_sockaddr;
- socklen_t peer_socklen = sizeof(sockaddr);
- auto sa = reinterpret_cast<struct sockaddr *>(&peer_sockaddr);
- int ret = getsockname(fd, sa, &peer_socklen);
- if (ret < 0)
- return -errno;
- return zcp_peeraddr_is_local(sa, peer_socklen);
- }
- int ECChannel::peer_is_local(void) const
- {
- return zcp_peeraddr_is_local(reinterpret_cast<const struct sockaddr *>(&peer_sockaddr), peer_salen);
- }
- static struct addrinfo *reorder_addrinfo_ipv6(struct addrinfo *node)
- {
- struct addrinfo v6head, othead;
- v6head.ai_next = NULL;
- othead.ai_next = node;
- struct addrinfo *v6tail = &v6head, *prev = &othead;
- while (node != NULL) {
- if (node->ai_family != AF_INET6) {
- prev = node;
- node = node->ai_next;
- continue;
- }
-
- prev->ai_next = node->ai_next;
- node->ai_next = NULL;
-
- v6tail->ai_next = node;
- v6tail = node;
-
- node = prev->ai_next;
- }
-
- v6tail->ai_next = othead.ai_next;
- return v6head.ai_next;
- }
- HRESULT HrListen(const char *szPath, int *lpulListenSocket)
- {
- HRESULT hr = hrSuccess;
- int fd = -1;
- struct sockaddr_un sun_addr;
- mode_t prevmask = 0;
- if (szPath == NULL || strlen(szPath) >= sizeof(sun_addr.sun_path) ||
- lpulListenSocket == NULL) {
- hr = MAPI_E_INVALID_PARAMETER;
- goto exit;
- }
- memset(&sun_addr, 0, sizeof(sun_addr));
- sun_addr.sun_family = AF_UNIX;
- kc_strlcpy(sun_addr.sun_path, szPath, sizeof(sun_addr.sun_path));
- if ((fd = socket(PF_UNIX, SOCK_STREAM, 0)) == -1) {
- ec_log_crit("Unable to create AF_UNIX socket");
- hr = MAPI_E_NETWORK_ERROR;
- goto exit;
- }
- unlink(szPath);
-
- prevmask = umask(0111);
- if (bind(fd, (struct sockaddr *)&sun_addr, sizeof(sun_addr)) == -1) {
- ec_log_crit("Unable to bind to socket %s (%s). This is usually caused by another process (most likely another kopano-server) already using this port. This program will terminate now.", szPath, strerror(errno));
- kill(0, SIGTERM);
- exit(1);
- }
-
- if (listen(fd, SOMAXCONN) == -1) {
- ec_log_crit("Unable to start listening on socket \"%s\".", szPath);
- hr = MAPI_E_NETWORK_ERROR;
- goto exit;
- }
- *lpulListenSocket = fd;
- exit:
- if (prevmask)
- umask(prevmask);
- if (hr != hrSuccess && fd != -1)
- close(fd);
- return hr;
- }
- int zcp_bindtodevice(int fd, const char *i)
- {
- if (i == NULL || strcmp(i, "any") == 0 || strcmp(i, "all") == 0 ||
- strcmp(i, "") == 0)
- return 0;
- #ifdef LINUX
- if (setsockopt(fd, SOL_SOCKET, SO_BINDTODEVICE, i, strlen(i)) >= 0)
- return 0;
- ec_log_err("Unable to bind to interface %s: %s", i, strerror(errno));
- return -errno;
- #else
- ec_log_err("Bind-to-interface not supported.");
- return -ENOSYS;
- #endif
- }
- HRESULT HrListen(const char *szBind, uint16_t ulPort, int *lpulListenSocket)
- {
- HRESULT hr = hrSuccess;
- int fd = -1, opt = 1, ret;
- struct addrinfo *sock_res = NULL, sock_hints;
- const struct addrinfo *sock_addr, *sock_last = NULL;
- char port_string[sizeof("65535")];
- if (lpulListenSocket == NULL || ulPort == 0 || szBind == NULL) {
- hr = MAPI_E_INVALID_PARAMETER;
- goto exit;
- }
- snprintf(port_string, sizeof(port_string), "%u", ulPort);
- memset(&sock_hints, 0, sizeof(sock_hints));
-
- sock_hints.ai_flags = AI_NUMERICHOST | AI_NUMERICSERV | AI_PASSIVE;
- sock_hints.ai_socktype = SOCK_STREAM;
- ret = getaddrinfo(*szBind == '\0' ? NULL : szBind,
- port_string, &sock_hints, &sock_res);
- if (ret != 0) {
- hr = MAPI_E_INVALID_PARAMETER;
- ec_log_err("getaddrinfo(%s,%u): %s", szBind, ulPort, gai_strerror(ret));
- goto exit;
- }
- sock_res = reorder_addrinfo_ipv6(sock_res);
- errno = 0;
- for (sock_addr = sock_res; sock_addr != NULL;
- sock_addr = sock_addr->ai_next)
- {
- sock_last = sock_addr;
- fd = socket(sock_addr->ai_family, sock_addr->ai_socktype,
- sock_addr->ai_protocol);
- if (fd < 0)
- continue;
- if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR,
- reinterpret_cast<const char *>(&opt), sizeof(opt)) < 0)
- ec_log_warn("Unable to set reuseaddr socket option: %s",
- strerror(errno));
- ret = bind(fd, sock_addr->ai_addr, sock_addr->ai_addrlen);
- if (ret < 0 && errno == EADDRINUSE) {
-
- int saved_errno = errno;
- close(fd);
- fd = -1;
- errno = saved_errno;
- break;
- }
- if (ret < 0) {
- int saved_errno = errno;
- close(fd);
- fd = -1;
- errno = saved_errno;
- continue;
- }
- if (listen(fd, SOMAXCONN) < 0) {
- ec_log_err("Unable to start listening on port %d: %s",
- ulPort, strerror(errno));
- hr = MAPI_E_NETWORK_ERROR;
- goto exit;
- }
-
- break;
- }
- if (fd < 0 && sock_last != NULL) {
- ec_log_crit("Unable to create socket(%u,%u,%u) port %s: %s",
- sock_last->ai_family, sock_last->ai_socktype,
- sock_last->ai_protocol, port_string, strerror(errno));
- hr = MAPI_E_NETWORK_ERROR;
- goto exit;
- } else if (fd < 0) {
- ec_log_err("no sockets proposed");
- hr = MAPI_E_NETWORK_ERROR;
- goto exit;
- }
- *lpulListenSocket = fd;
- exit:
- if (sock_res != NULL)
- freeaddrinfo(sock_res);
- if (hr != hrSuccess && fd >= 0)
- close(fd);
- return hr;
- }
- HRESULT HrAccept(int ulListenFD, ECChannel **lppChannel)
- {
- int socket = 0;
- struct sockaddr_storage client;
- std::unique_ptr<ECChannel> lpChannel;
- socklen_t len = sizeof(client);
- if (ulListenFD < 0 || lppChannel == NULL) {
- ec_log_err("HrAccept: invalid parameters");
- return MAPI_E_INVALID_PARAMETER;
- }
- #ifdef TCP_FASTOPEN
- static const int qlen = SOMAXCONN;
- if (setsockopt(ulListenFD, SOL_TCP, TCP_FASTOPEN, &qlen, sizeof(qlen)) < 0)
- ;
- #endif
- memset(&client, 0, sizeof(client));
- socket = accept(ulListenFD, (struct sockaddr *)&client, &len);
- if (socket == -1) {
- ec_log_err("Unable to accept(): %s", strerror(errno));
- return MAPI_E_NETWORK_ERROR;
- }
- lpChannel.reset(new ECChannel(socket));
- lpChannel->SetIPAddress(reinterpret_cast<const struct sockaddr *>(&client), len);
- ec_log_info("Accepted connection from %s", lpChannel->peer_addr());
- *lppChannel = lpChannel.release();
- return hrSuccess;
- }
- }
|