/*-------------------------------------------------------------------------*\ * "Disconnects" a DGRAM socket \*-------------------------------------------------------------------------*/ const char *inet_trydisconnect(p_socket ps, int family, p_timeout tm) { switch (family) { case PF_INET: { struct sockaddr_in sin; memset((char *) &sin, 0, sizeof(sin)); sin.sin_family = AF_UNSPEC; sin.sin_addr.s_addr = INADDR_ANY; return socket_strerror(socket_connect(ps, (SA *) &sin, sizeof(sin), tm)); } case PF_INET6: { struct sockaddr_in6 sin6; struct in6_addr addrany = IN6ADDR_ANY_INIT; memset((char *) &sin6, 0, sizeof(sin6)); sin6.sin6_family = AF_UNSPEC; fprintf(stderr, "disconnecting\n"); sin6.sin6_addr = addrany; return socket_strerror(socket_connect(ps, (SA *) &sin6, sizeof(sin6), tm)); } } return NULL; }
/*-------------------------------------------------------------------------*\ * Puts the sockt in listen mode \*-------------------------------------------------------------------------*/ static int meth_listen(lua_State *L) { p_tcp tcp = (p_tcp) auxiliar_checkclass(L, "tcp{master}", 1); int backlog = (int) luaL_optnumber(L, 2, 32); int err = socket_listen(&tcp->sock, backlog); if (err != IO_DONE) { lua_pushnil(L); lua_pushstring(L, socket_strerror(err)); return 2; } /* turn master object into a server object */ auxiliar_setclass(L, "tcp{server}", 1); lua_pushnumber(L, 1); return 1; }
/*-------------------------------------------------------------------------*\ * Waits for and returns a client object attempting connection to the * server object \*-------------------------------------------------------------------------*/ static int meth_acceptfd(lua_State *L) { p_tcp server = (p_tcp) auxiliar_checkclass(L, "tcp{server}", 1); p_timeout tm = timeout_markstart(&server->tm); t_socket sock; int err = socket_accept(&server->sock, &sock, NULL, NULL, tm); /* if successful, push client socket */ if (err == IO_DONE) { lua_pushnumber(L, sock); return 1; } else { lua_pushnil(L); lua_pushstring(L, socket_strerror(err)); return 2; } }
/*-------------------------------------------------------------------------*\ * Tries to connect to remote address (address, port) \*-------------------------------------------------------------------------*/ const char *inet_tryconnect(p_socket ps, int *family, const char *address, const char *serv, p_timeout tm, struct addrinfo *connecthints) { #ifdef LUASOCKET_SECURITY_SANDBOX if (luasocket_ip_allowed(address)) return "connect restricted"; #endif // LUASOCKET_SECURITY_SANDBOX struct addrinfo *iterator = NULL, *resolved = NULL; const char *err = NULL; int current_family = *family; /* try resolving */ err = socket_gaistrerror(getaddrinfo(address, serv, connecthints, &resolved)); if (err != NULL) { if (resolved) freeaddrinfo(resolved); return err; } for (iterator = resolved; iterator; iterator = iterator->ai_next) { timeout_markstart(tm); /* create new socket if necessary. if there was no * bind, we need to create one for every new family * that shows up while iterating. if there was a * bind, all families will be the same and we will * not enter this branch. */ if (current_family != iterator->ai_family || *ps == SOCKET_INVALID) { socket_destroy(ps); err = inet_trycreate(ps, iterator->ai_family, iterator->ai_socktype, iterator->ai_protocol); if (err) continue; current_family = iterator->ai_family; /* set non-blocking before connect */ socket_setnonblocking(ps); } /* try connecting to remote address */ err = socket_strerror(socket_connect(ps, (SA *) iterator->ai_addr, (socklen_t) iterator->ai_addrlen, tm)); /* if success or timeout is zero, break out of loop */ if (err == NULL || timeout_iszero(tm)) { *family = current_family; break; } } freeaddrinfo(resolved); /* here, if err is set, we failed */ return err; }
static ssize_t rd_kafka_transport_socket_recvmsg (rd_kafka_transport_t *rktrans, struct msghdr *msg, char *errstr, size_t errstr_size) { #ifndef _MSC_VER ssize_t r; #ifdef sun /* SunOS doesn't seem to set errno when recvmsg() fails * due to no data and MSG_DONTWAIT is set. */ socket_errno = EAGAIN; #endif r = recvmsg(rktrans->rktrans_s, msg, MSG_DONTWAIT); if (r == -1 && socket_errno == EAGAIN) return 0; else if (r == 0) { /* Receive 0 after POLLIN event means connection closed. */ rd_snprintf(errstr, errstr_size, "Disconnected"); return -1; } else if (r == -1) rd_snprintf(errstr, errstr_size, "%s", rd_strerror(errno)); return r; #else ssize_t sum = 0; int i; for (i = 0; i < msg->msg_iovlen; i++) { ssize_t r; r = recv(rktrans->rktrans_s, msg->msg_iov[i].iov_base, (int) msg->msg_iov[i].iov_len, 0); if (r == SOCKET_ERROR) { if (WSAGetLastError() == WSAEWOULDBLOCK) break; rd_snprintf(errstr, errstr_size, "%s", socket_strerror(WSAGetLastError())); return -1; } sum += r; if ((size_t)r < msg->msg_iov[i].iov_len) break; } return sum; #endif }
/*-------------------------------------------------------------------------*\ * Tries to bind socket to (address, port) \*-------------------------------------------------------------------------*/ const char *inet_trybind(p_socket ps, int *family, const char *address, const char *serv, struct addrinfo *bindhints) { #ifdef LUASOCKET_SECURITY_SANDBOX if (luasocket_ip_allowed(address)) return "bind restricted"; #endif // LUASOCKET_SECURITY_SANDBOX struct addrinfo *iterator = NULL, *resolved = NULL; const char *err = NULL; int current_family = *family; /* translate luasocket special values to C */ if (strcmp(address, "*") == 0) address = NULL; if (!serv) serv = "0"; /* try resolving */ err = socket_gaistrerror(getaddrinfo(address, serv, bindhints, &resolved)); if (err) { if (resolved) freeaddrinfo(resolved); return err; } /* iterate over resolved addresses until one is good */ for (iterator = resolved; iterator; iterator = iterator->ai_next) { if (current_family != iterator->ai_family || *ps == SOCKET_INVALID) { socket_destroy(ps); err = inet_trycreate(ps, iterator->ai_family, iterator->ai_socktype, iterator->ai_protocol); if (err) continue; current_family = iterator->ai_family; } /* try binding to local address */ err = socket_strerror(socket_bind(ps, (SA *) iterator->ai_addr, (socklen_t) iterator->ai_addrlen)); /* keep trying unless bind succeeded */ if (err == NULL) { *family = current_family; /* set to non-blocking after bind */ socket_setnonblocking(ps); break; } } /* cleanup and return error */ freeaddrinfo(resolved); /* here, if err is set, we failed */ return err; }
/** * Map error code into string. */ static const char *ssl_ioerror(void *ctx, int err) { if (err == IO_SSL) { p_ssl ssl = (p_ssl) ctx; switch(ssl->error) { case SSL_ERROR_NONE: return "No error"; case SSL_ERROR_ZERO_RETURN: return "closed"; case SSL_ERROR_WANT_READ: return "wantread"; case SSL_ERROR_WANT_WRITE: return "wantwrite"; case SSL_ERROR_WANT_CONNECT: return "'connect' not completed"; case SSL_ERROR_WANT_ACCEPT: return "'accept' not completed"; case SSL_ERROR_WANT_X509_LOOKUP: return "Waiting for callback"; case SSL_ERROR_SYSCALL: return "System error"; case SSL_ERROR_SSL: return ERR_reason_error_string(ERR_get_error()); default: return "Unknown SSL error"; } } return socket_strerror(err); }
/*-------------------------------------------------------------------------*\ * Binds an object to an address \*-------------------------------------------------------------------------*/ static const char *unix_trybind(p_unix un, const char *path) { struct sockaddr_un local; size_t len = strlen(path); int err; if (len >= sizeof(local.sun_path)) return "path too long"; memset(&local, 0, sizeof(local)); strcpy(local.sun_path, path); local.sun_family = AF_UNIX; #ifdef UNIX_HAS_SUN_LEN local.sun_len = sizeof(local.sun_family) + sizeof(local.sun_len) + len + 1; err = socket_bind(&un->sock, (SA *) &local, local.sun_len); #else err = socket_bind(&un->sock, (SA *) &local, sizeof(local.sun_family) + len); #endif if (err != IO_DONE) socket_destroy(&un->sock); return socket_strerror(err); }
int rd_kafka_transport_poll(rd_kafka_transport_t *rktrans, int tmout) { #ifndef _MSC_VER int r; r = poll(&rktrans->rktrans_pfd, 1, tmout); if (r <= 0) return r; return rktrans->rktrans_pfd.revents; #else int r; r = WSAPoll(&rktrans->rktrans_pfd, 1, tmout); if (r == 0) { /* Workaround for broken WSAPoll() while connecting: * failed connection attempts are not indicated at all by WSAPoll() * so we need to check the socket error when Poll returns 0. * Issue #525 */ r = ECONNRESET; if (unlikely(rktrans->rktrans_rkb->rkb_state == RD_KAFKA_BROKER_STATE_CONNECT && (rd_kafka_transport_get_socket_error(rktrans, &r) == -1 || r != 0))) { char errstr[512]; errno = r; rd_snprintf(errstr, sizeof(errstr), "Connect to %s failed: %s", rd_sockaddr2str(rktrans->rktrans_rkb-> rkb_addr_last, RD_SOCKADDR2STR_F_PORT | RD_SOCKADDR2STR_F_FAMILY), socket_strerror(r)); rd_kafka_transport_connect_done(rktrans, errstr); return -1; } else return 0; } else if (r == SOCKET_ERROR) return -1; return rktrans->rktrans_pfd.revents; #endif }
/*-------------------------------------------------------------------------*\ * Tries to connect to remote address (address, port) \*-------------------------------------------------------------------------*/ const char *inet_tryconnect(p_socket ps, const char *address, unsigned short port, p_timeout tm) { struct sockaddr_in remote; int err; memset(&remote, 0, sizeof(remote)); remote.sin_family = AF_INET; remote.sin_port = htons(port); if (strcmp(address, "*")) { if (!inet_aton(address, &remote.sin_addr)) { struct hostent *hp = NULL; struct in_addr **addr; err = socket_gethostbyname(address, &hp); if (err != IO_DONE) return socket_hoststrerror(err); addr = (struct in_addr **) hp->h_addr_list; memcpy(&remote.sin_addr, *addr, sizeof(struct in_addr)); } } else remote.sin_family = AF_UNSPEC; err = socket_connect(ps, (SA *) &remote, sizeof(remote), tm); return socket_strerror(err); }
/*-------------------------------------------------------------------------*\ * Turns a master unix object into a client object. \*-------------------------------------------------------------------------*/ static const char *unix_tryconnect(p_unix un, const char *path) { struct sockaddr_un remote; int err; size_t len = strlen(path); if (len >= sizeof(remote.sun_path)) return "path too long"; memset(&remote, 0, sizeof(remote)); strcpy(remote.sun_path, path); remote.sun_family = AF_UNIX; timeout_markstart(&un->tm); #ifdef UNIX_HAS_SUN_LEN remote.sun_len = sizeof(remote.sun_family) + sizeof(remote.sun_len) + len + 1; err = socket_connect(&un->sock, (SA *) &remote, remote.sun_len, &un->tm); #else err = socket_connect(&un->sock, (SA *) &remote, sizeof(remote.sun_family) + len, &un->tm); #endif if (err != IO_DONE) socket_destroy(&un->sock); return socket_strerror(err); }
/*-------------------------------------------------------------------------*\ * Tries to bind socket to (address, port) \*-------------------------------------------------------------------------*/ const char *inet_trybind(p_socket ps, const char *address, unsigned short port) { struct sockaddr_in local; int err; memset(&local, 0, sizeof(local)); /* address is either wildcard or a valid ip address */ local.sin_addr.s_addr = htonl(INADDR_ANY); local.sin_port = htons(port); local.sin_family = AF_INET; if (strcmp(address, "*") && !inet_aton(address, &local.sin_addr)) { struct hostent *hp = NULL; struct in_addr **addr; err = socket_gethostbyname(address, &hp); if (err != IO_DONE) return socket_hoststrerror(err); addr = (struct in_addr **) hp->h_addr_list; memcpy(&local.sin_addr, *addr, sizeof(struct in_addr)); } err = socket_bind(ps, (SA *) &local, sizeof(local)); if (err != IO_DONE) socket_destroy(ps); return socket_strerror(err); }
int main(int ac, char **av) { int rc, i; #ifdef WIN32 win_init(); #endif for (i = 0; TestCases[i] != NULL; i++) { const struct test_case *current = TestCases[i]; const char *name = get_test_name(current); printf("%-48s", name); fflush(stdout); rc = test_case_run(current); if (rc) { printf(TEST_FAILED " (%s)\n", socket_strerror(-rc)); break; } printf(TEST_OK "\n"); } return rc; }
/*-------------------------------------------------------------------------*\ * Waits for and returns a client object attempting connection to the * server object \*-------------------------------------------------------------------------*/ static int meth_accept(lua_State *L) { p_unix server = (p_unix) auxiliar_checkclass(L, "unix{server}", 1); p_timeout tm = timeout_markstart(&server->tm); t_socket sock; int err = socket_accept(&server->sock, &sock, NULL, NULL, tm); /* if successful, push client socket */ if (err == IO_DONE) { p_unix clnt = (p_unix) lua_newuserdata(L, sizeof(t_unix)); auxiliar_setclass(L, "unix{client}", -1); /* initialize structure fields */ socket_setnonblocking(&sock); clnt->sock = sock; io_init(&clnt->io, (p_send)socket_send, (p_recv)socket_recv, (p_error) socket_ioerror, &clnt->sock); timeout_init(&clnt->tm, -1, -1); buffer_init(&clnt->buf, &clnt->io, &clnt->tm); return 1; } else { lua_pushnil(L); lua_pushstring(L, socket_strerror(err)); return 2; } }
/*-------------------------------------------------------------------------*\ * Creates a master unix object \*-------------------------------------------------------------------------*/ static int global_create(lua_State *L) { t_socket sock; int err = socket_create(&sock, AF_UNIX, SOCK_STREAM, 0); /* try to allocate a system socket */ if (err == IO_DONE) { /* allocate unix object */ p_unix un = (p_unix) lua_newuserdata(L, sizeof(t_unix)); /* set its type as master object */ auxiliar_setclass(L, "unix{master}", -1); /* initialize remaining structure fields */ socket_setnonblocking(&sock); un->sock = sock; io_init(&un->io, (p_send) socket_send, (p_recv) socket_recv, (p_error) socket_ioerror, &un->sock); timeout_init(&un->tm, -1, -1); buffer_init(&un->buf, &un->io, &un->tm); return 1; } else { lua_pushnil(L); lua_pushstring(L, socket_strerror(err)); return 2; } }
/*-------------------------------------------------------------------------*\ * Tries to connect to remote address (address, port) \*-------------------------------------------------------------------------*/ const char *inet_tryconnect(p_socket ps, const char *address, const char *serv, p_timeout tm, struct addrinfo *connecthints) { struct addrinfo *iterator = NULL, *resolved = NULL; const char *err = NULL; /* try resolving */ err = socket_gaistrerror(getaddrinfo(address, serv, connecthints, &resolved)); if (err != NULL) { if (resolved) freeaddrinfo(resolved); return err; } for (iterator = resolved; iterator; iterator = iterator->ai_next) { timeout_markstart(tm); /* try connecting to remote address */ err = socket_strerror(socket_connect(ps, (SA *) iterator->ai_addr, (socklen_t) iterator->ai_addrlen, tm)); /* if success, break out of loop */ if (err == NULL) break; } freeaddrinfo(resolved); /* here, if err is set, we failed */ return err; }
/* Return a usable socket descriptor after proxy negotiation, or -1 on any error. If any bytes are received through the proxy after negotiation, they are written to stdout. */ static int do_proxy_http(void) { struct socket_buffer sockbuf; char *request; char *status_line, *header; char *remainder; size_t len; int sd, code; int n; sd = do_connect(SOCK_STREAM); if (sd == -1) { loguser("Proxy connection failed: %s.\n", socket_strerror(socket_errno())); return -1; } status_line = NULL; header = NULL; /* First try a request with no authentication. */ request = http_connect_request(&httpconnect, &n); if (send(sd, request, n, 0) < 0) { loguser("Error sending proxy request: %s.\n", socket_strerror(socket_errno())); free(request); return -1; } free(request); socket_buffer_init(&sockbuf, sd); if (http_read_status_line(&sockbuf, &status_line) != 0) { loguser("Error reading proxy response Status-Line.\n"); goto bail; } code = http_parse_status_line_code(status_line); logdebug("Proxy returned status code %d.\n", code); free(status_line); status_line = NULL; if (http_read_header(&sockbuf, &header) != 0) { loguser("Error reading proxy response header.\n"); goto bail; } if (code == 407 && o.proxy_auth != NULL) { struct http_header *h; struct http_challenge challenge; close(sd); sd = -1; if (http_parse_header(&h, header) != 0) { loguser("Error parsing proxy response header.\n"); goto bail; } free(header); header = NULL; if (http_header_get_proxy_challenge(h, &challenge) == NULL) { loguser("Error getting Proxy-Authenticate challenge.\n"); http_header_free(h); goto bail; } http_header_free(h); sd = do_connect(SOCK_STREAM); if (sd == -1) { loguser("Proxy reconnection failed: %s.\n", socket_strerror(socket_errno())); goto bail; } request = http_connect_request_auth(&httpconnect, &n, &challenge); if (request == NULL) { loguser("Error building Proxy-Authorization header.\n"); http_challenge_free(&challenge); goto bail; } logdebug("Reconnection header:\n%s", request); if (send(sd, request, n, 0) < 0) { loguser("Error sending proxy request: %s.\n", socket_strerror(socket_errno())); free(request); http_challenge_free(&challenge); goto bail; } free(request); http_challenge_free(&challenge); socket_buffer_init(&sockbuf, sd); if (http_read_status_line(&sockbuf, &status_line) != 0) { loguser("Error reading proxy response Status-Line.\n"); goto bail; } code = http_parse_status_line_code(status_line); logdebug("Proxy returned status code %d.\n", code); free(status_line); status_line = NULL; if (http_read_header(&sockbuf, &header) != 0) { loguser("Error reading proxy response header.\n"); goto bail; } } free(header); header = NULL; if (code != 200) { loguser("Proxy returned status code %d.\n", code); return -1; } remainder = socket_buffer_remainder(&sockbuf, &len); Write(STDOUT_FILENO, remainder, len); return sd; bail: if (sd != -1) close(sd); if (status_line != NULL) free(status_line); if (header != NULL) free(header); return -1; }
/* handle_connect_results assumes that select or poll have already shown the * descriptor to be active */ void handle_connect_result(struct npool *ms, struct nevent *nse, enum nse_status status) { int optval; socklen_t optlen = sizeof(int); struct niod *iod = nse->iod; #if HAVE_OPENSSL int sslerr; int rc = 0; int sslconnect_inprogress = nse->type == NSE_TYPE_CONNECT_SSL && nse->iod && (nse->sslinfo.ssl_desire == SSL_ERROR_WANT_READ || nse->sslinfo.ssl_desire == SSL_ERROR_WANT_WRITE); #else int sslconnect_inprogress = 0; #endif if (status == NSE_STATUS_TIMEOUT || status == NSE_STATUS_CANCELLED) { nse->status = status; nse->event_done = 1; } else if (sslconnect_inprogress) { /* Do nothing */ } else if (status == NSE_STATUS_SUCCESS) { /* First we want to determine whether the socket really is connected */ if (getsockopt(iod->sd, SOL_SOCKET, SO_ERROR, (char *)&optval, &optlen) != 0) optval = socket_errno(); /* Stupid Solaris */ switch (optval) { case 0: nse->status = NSE_STATUS_SUCCESS; break; /* EACCES can be caused by ICMPv6 dest-unreach-admin, or when a port is blocked by Windows Firewall (WSAEACCES). */ case EACCES: case ECONNREFUSED: case EHOSTUNREACH: case ENETDOWN: case ENETUNREACH: case ENETRESET: case ECONNABORTED: case ETIMEDOUT: case EHOSTDOWN: case ECONNRESET: #ifdef WIN32 case WSAEADDRINUSE: case WSAEADDRNOTAVAIL: #endif #ifndef WIN32 case EPIPE: /* Has been seen after connect on Linux. */ case ENOPROTOOPT: /* Also seen on Linux, perhaps in response to protocol unreachable. */ #endif nse->status = NSE_STATUS_ERROR; nse->errnum = optval; break; default: /* I'd like for someone to report it */ fatal("Strange connect error from %s (%d): %s", inet_ntop_ez(&iod->peer, iod->peerlen), optval, socket_strerror(optval)); } /* Now special code for the SSL case where the TCP connection was successful. */ if (nse->type == NSE_TYPE_CONNECT_SSL && nse->status == NSE_STATUS_SUCCESS) { #if HAVE_OPENSSL assert(ms->sslctx != NULL); /* Reuse iod->ssl if present. If set, this is the second try at connection without the SSL_OP_NO_SSLv2 option set. */ if (iod->ssl == NULL) { iod->ssl = SSL_new(ms->sslctx); if (!iod->ssl) fatal("SSL_new failed: %s", ERR_error_string(ERR_get_error(), NULL)); } #if HAVE_SSL_SET_TLSEXT_HOST_NAME if (iod->hostname != NULL) { if (SSL_set_tlsext_host_name(iod->ssl, iod->hostname) != 1) fatal("SSL_set_tlsext_host_name failed: %s", ERR_error_string(ERR_get_error(), NULL)); } #endif /* Associate our new SSL with the connected socket. It will inherit the * non-blocking nature of the sd */ if (SSL_set_fd(iod->ssl, iod->sd) != 1) fatal("SSL_set_fd failed: %s", ERR_error_string(ERR_get_error(), NULL)); /* Event not done -- need to do SSL connect below */ nse->sslinfo.ssl_desire = SSL_ERROR_WANT_CONNECT; #endif } else { /* This is not an SSL connect (in which case we are always done), or the * TCP connect() underlying the SSL failed (in which case we are also done */ nse->event_done = 1; } } else { fatal("Unknown status (%d)", status); } /* At this point the TCP connection is done, whether successful or not. * Therefore decrease the read/write listen counts that were incremented in * nsock_pool_add_event. In the SSL case, we may increase one of the counts depending * on whether SSL_connect returns an error of SSL_ERROR_WANT_READ or * SSL_ERROR_WANT_WRITE. In that case we will re-enter this function, but we * don't want to execute this block again. */ if (iod->sd != -1 && !sslconnect_inprogress) { int ev = EV_NONE; ev |= socket_count_read_dec(iod); ev |= socket_count_write_dec(iod); ev |= EV_EXCEPT; update_events(iod, ms, EV_NONE, ev); } #if HAVE_OPENSSL if (nse->type == NSE_TYPE_CONNECT_SSL && !nse->event_done) { /* Lets now start/continue/finish the connect! */ if (iod->ssl_session) { rc = SSL_set_session(iod->ssl, iod->ssl_session); if (rc == 0) nsock_log_error("Uh-oh: SSL_set_session() failed - please tell [email protected]"); iod->ssl_session = NULL; /* No need for this any more */ } /* If this is a reinvocation of handle_connect_result, clear out the listen * bits that caused it, based on the previous SSL desire. */ if (sslconnect_inprogress) { int ev; ev = socket_count_dec_ssl_desire(nse); update_events(iod, ms, EV_NONE, ev); } rc = SSL_connect(iod->ssl); if (rc == 1) { /* Woop! Connect is done! */ nse->event_done = 1; /* Check that certificate verification was okay, if requested. */ if (nsi_ssl_post_connect_verify(iod)) { nse->status = NSE_STATUS_SUCCESS; } else { nsock_log_error("certificate verification error for EID %li: %s", nse->id, ERR_error_string(ERR_get_error(), NULL)); nse->status = NSE_STATUS_ERROR; } } else { long options = SSL_get_options(iod->ssl); sslerr = SSL_get_error(iod->ssl, rc); if (rc == -1 && sslerr == SSL_ERROR_WANT_READ) { nse->sslinfo.ssl_desire = sslerr; socket_count_read_inc(iod); update_events(iod, ms, EV_READ, EV_NONE); } else if (rc == -1 && sslerr == SSL_ERROR_WANT_WRITE) { nse->sslinfo.ssl_desire = sslerr; socket_count_write_inc(iod); update_events(iod, ms, EV_WRITE, EV_NONE); } else if (!(options & SSL_OP_NO_SSLv2)) { int saved_ev; /* SSLv3-only and TLSv1-only servers can't be connected to when the * SSL_OP_NO_SSLv2 option is not set, which is the case when the pool * was initialized with nsock_pool_ssl_init_max_speed. Try reconnecting * with SSL_OP_NO_SSLv2. Never downgrade a NO_SSLv2 connection to one * that might use SSLv2. */ nsock_log_info("EID %li reconnecting with SSL_OP_NO_SSLv2", nse->id); saved_ev = iod->watched_events; nsock_engine_iod_unregister(ms, iod); close(iod->sd); nsock_connect_internal(ms, nse, SOCK_STREAM, iod->lastproto, &iod->peer, iod->peerlen, nsock_iod_get_peerport(iod)); nsock_engine_iod_register(ms, iod, saved_ev); SSL_clear(iod->ssl); if(!SSL_clear(iod->ssl)) fatal("SSL_clear failed: %s", ERR_error_string(ERR_get_error(), NULL)); SSL_set_options(iod->ssl, options | SSL_OP_NO_SSLv2); socket_count_read_inc(nse->iod); socket_count_write_inc(nse->iod); update_events(iod, ms, EV_READ|EV_WRITE, EV_NONE); nse->sslinfo.ssl_desire = SSL_ERROR_WANT_CONNECT; } else { nsock_log_info("EID %li %s", nse->id, ERR_error_string(ERR_get_error(), NULL)); nse->event_done = 1; nse->status = NSE_STATUS_ERROR; nse->errnum = EIO; } } } #endif }
/* An event has been completed and the handler is about to be called. This * function writes out tracing data about the event if necessary */ void nsock_trace_handler_callback(struct npool *ms, struct nevent *nse) { struct niod *nsi; char *str; int strlength = 0; char displaystr[256]; char errstr[256]; if (NsockLogLevel > NSOCK_LOG_INFO) return; nsi = nse->iod; if (nse->status == NSE_STATUS_ERROR) Snprintf(errstr, sizeof(errstr), "[%s (%d)] ", socket_strerror(nse->errnum), nse->errnum); else errstr[0] = '\0'; /* Some types have special tracing treatment */ switch (nse->type) { case NSE_TYPE_CONNECT: case NSE_TYPE_CONNECT_SSL: nsock_log_info("Callback: %s %s %sfor EID %li [%s]", nse_type2str(nse->type), nse_status2str(nse->status), errstr, nse->id, get_peeraddr_string(nsi)); break; case NSE_TYPE_READ: if (nse->status != NSE_STATUS_SUCCESS) { nsock_log_info("Callback: %s %s %sfor EID %li [%s]", nse_type2str(nse->type), nse_status2str(nse->status), errstr, nse->id, get_peeraddr_string(nsi)); } else { str = nse_readbuf(nse, &strlength); if (strlength < 80) { memcpy(displaystr, ": ", 2); memcpy(displaystr + 2, str, strlength); displaystr[2 + strlength] = '\0'; replacenonprintable(displaystr + 2, strlength, '.'); } else { displaystr[0] = '\0'; } nsock_log_info("Callback: %s %s for EID %li [%s] %s(%d bytes)%s", nse_type2str(nse->type), nse_status2str(nse->status), nse->id, get_peeraddr_string(nsi), nse_eof(nse) ? "[EOF]" : "", strlength, displaystr); } break; case NSE_TYPE_WRITE: nsock_log_info("Callback: %s %s %sfor EID %li [%s]", nse_type2str(nse->type), nse_status2str(nse->status), errstr, nse->id, get_peeraddr_string(nsi)); break; case NSE_TYPE_TIMER: nsock_log_info("Callback: %s %s %sfor EID %li", nse_type2str(nse->type), nse_status2str(nse->status), errstr, nse->id); break; #if HAVE_PCAP case NSE_TYPE_PCAP_READ: nsock_log_info("Callback: %s %s %sfor EID %li ", nse_type2str(nse->type), nse_status2str(nse->status), errstr, nse->id); break; #endif default: fatal("Invalid nsock event type (%d)", nse->type); } }
/* An event has been completed and the handler is about to be called. This * function writes out tracing data about the event if necessary */ void nsock_trace_handler_callback(mspool *ms, msevent *nse) { msiod *nsi; char *str; int strlength = 0; char displaystr[256]; char errstr[256]; if (ms->tracelevel == 0) return; nsi = nse->iod; if (nse->status == NSE_STATUS_ERROR) Snprintf(errstr, sizeof(errstr), "[%s (%d)] ", socket_strerror(nse->errnum), nse->errnum); else errstr[0] = '\0'; /* Some types have special tracing treatment */ switch(nse->type) { case NSE_TYPE_CONNECT: case NSE_TYPE_CONNECT_SSL: nsock_trace(ms, "Callback: %s %s %sfor EID %li [%s]", nse_type2str(nse->type), nse_status2str(nse->status), errstr, nse->id, get_peeraddr_string(nsi)); break; case NSE_TYPE_READ: if (nse->status != NSE_STATUS_SUCCESS) { if (nsi->peerlen > 0) { nsock_trace(ms, "Callback: %s %s %sfor EID %li [%s]", nse_type2str(nse->type), nse_status2str(nse->status), errstr, nse->id, get_peeraddr_string(nsi)); } else { nsock_trace(ms, "Callback: %s %s %sfor EID %li (peer unspecified)", nse_type2str(nse->type), nse_status2str(nse->status), errstr, nse->id); } } else { str = nse_readbuf(nse, &strlength); if (ms->tracelevel > 1 && strlength < 80) { memcpy(displaystr, ": ", 2); memcpy(displaystr + 2, str, strlength); displaystr[2 + strlength] = '\0'; replacenonprintable(displaystr + 2, strlength, '.'); } else { displaystr[0] = '\0'; } if (nsi->peerlen > 0) { nsock_trace(ms, "Callback: %s %s for EID %li [%s] %s(%d bytes)%s", nse_type2str(nse->type), nse_status2str(nse->status), nse->id, get_peeraddr_string(nsi), nse_eof(nse)? "[EOF]" : "", strlength, displaystr); } else { nsock_trace(ms, "Callback %s %s for EID %li (peer unspecified) %s(%d bytes)%s", nse_type2str(nse->type), nse_status2str(nse->status), nse->id, nse_eof(nse)? "[EOF]" : "", strlength, displaystr); } } break; case NSE_TYPE_WRITE: nsock_trace(ms, "Callback: %s %s %sfor EID %li [%s]", nse_type2str(nse->type), nse_status2str(nse->status), errstr, nse->id, get_peeraddr_string(nsi)); break; case NSE_TYPE_TIMER: nsock_trace(ms, "Callback: %s %s %sfor EID %li", nse_type2str(nse->type), nse_status2str(nse->status), errstr, nse->id); break; #if HAVE_PCAP case NSE_TYPE_PCAP_READ: nsock_trace(ms, "Callback: %s %s %sfor EID %li ", nse_type2str(nse->type), nse_status2str(nse->status), errstr, nse->id); break; #endif default: assert(0); break; } }
/*=========================================================================*\ * Lua methods \*=========================================================================*/ const char *udp_strerror(int err) { /* a 'closed' error on an unconnected means the target address was not * accepted by the transport layer */ if (err == IO_CLOSED) return "refused"; else return socket_strerror(err); }
int socket_api_test_echo_server_stream(socket_stack_t stack, socket_address_family_t af, const char* local_addr, uint16_t port) { struct socket s; struct socket cs; struct socket_addr addr; socket_error_t err; const struct socket_api *api = socket_get_api(stack); server_socket = &s; client_socket = &cs; mbed::Timeout to; mbed::Ticker ticker; // Create the socket TEST_CLEAR(); if (!TEST_NEQ(api, NULL)) { // Test cannot continue without API. TEST_RETURN(); } err = api->init(); if (!TEST_EQ(err, SOCKET_ERROR_NONE)) { TEST_RETURN(); } // Zero the socket implementation s.impl = NULL; // Create a socket err = api->create(&s, af, SOCKET_STREAM, &server_cb); if (!TEST_EQ(err, SOCKET_ERROR_NONE)) { TEST_RETURN(); } err = api->str2addr(&s, &addr, local_addr); if (!TEST_EQ(err, SOCKET_ERROR_NONE)) { TEST_RETURN(); } // start the TCP timer uint32_t interval_ms = api->periodic_interval(&s); TEST_NEQ(interval_ms, 0); uint32_t interval_us = interval_ms * 1000; socket_api_handler_t periodic_task = api->periodic_task(&s); if (TEST_NEQ(periodic_task, NULL)) { ticker.attach_us(periodic_task, interval_us); } err = api->bind(&s, &addr, port); if (!TEST_EQ(err, SOCKET_ERROR_NONE)) { TEST_RETURN(); } void *data = malloc(SOCKET_SENDBUF_MAXSIZE); if(!TEST_NEQ(data, NULL)) { TEST_RETURN(); } // Tell the host test to try and connect TEST_PRINT(">>> EC,%s,%d\r\n", local_addr, port); bool quit = false; // For several iterations while (!quit) { timedout = false; server_event_done = false; incoming = false; to.attach(onTimeout, SOCKET_TEST_SERVER_TIMEOUT); // Listen for incoming connections err = api->start_listen(&s, 0); if (!TEST_EQ(err, SOCKET_ERROR_NONE)) { TEST_EXIT(); } // Reset the state of client_rx_done client_rx_done = false; // Wait for a connect event while (!timedout && !incoming) { __WFI(); } if (TEST_EQ(timedout,0)) { to.detach(); } else { TEST_EXIT(); } if(!TEST_EQ(server_event.event, SOCKET_EVENT_ACCEPT)) { TEST_PRINT("Event: %d\r\n",(int)client_event.event); continue; } // Stop listening server_event_done = false; // err = api->stop_listen(&s); // TEST_EQ(err, SOCKET_ERROR_NONE); // Accept an incoming connection cs.impl = server_event.i.a.newimpl; cs.family = s.family; cs.stack = s.stack; err = api->accept(&cs, client_cb); if(!TEST_EQ(err, SOCKET_ERROR_NONE)) { continue; } to.attach(onTimeout, SOCKET_TEST_SERVER_TIMEOUT); // Client should test for successive connections being rejected // Until Client disconnects while (client_event.event != SOCKET_EVENT_ERROR && client_event.event != SOCKET_EVENT_DISCONNECT) { // Wait for a read event while (!client_event_done && !client_rx_done && !timedout) { __WFI(); } if (!TEST_EQ(client_event_done, false)) { client_event_done = false; continue; } // Reset the state of client_rx_done client_rx_done = false; // Receive some data size_t len = SOCKET_SENDBUF_MAXSIZE; err = api->recv(&cs, data, &len); if (!TEST_NEQ(err, SOCKET_ERROR_WOULD_BLOCK)) { TEST_PRINT("Rx Would Block\r\n"); continue; } if (!TEST_EQ(err, SOCKET_ERROR_NONE)) { TEST_PRINT("err: (%d) %s\r\n", err, socket_strerror(err)); break; } // Check if the server should halt if (strncmp((const char *)data, "quit", 4) == 0) { quit = true; break; } // Send some data err = api->send(&cs, data, len); if (!TEST_EQ(err, SOCKET_ERROR_NONE)) { break; } } to.detach(); TEST_NEQ(timedout, true); // Close client socket err = api->close(&cs); TEST_EQ(err, SOCKET_ERROR_NONE); } err = api->stop_listen(&s); TEST_EQ(err, SOCKET_ERROR_NONE); test_exit: ticker.detach(); TEST_PRINT(">>> KILL,EC\r\n"); free(data); // Destroy server socket TEST_RETURN(); }
int kqueue_loop(mspool *nsp, int msec_timeout) { int results_left = 0; int event_msecs; /* msecs before an event goes off */ int combined_msecs; struct timespec ts, *ts_p; int sock_err = 0; struct kqueue_engine_info *kinfo = (struct kqueue_engine_info *)nsp->engine_data; assert(msec_timeout >= -1); if (nsp->events_pending == 0) return 0; /* No need to wait on 0 events ... */ if (gh_list_count(&nsp->active_iods) > kinfo->evlen) { kinfo->evlen = gh_list_count(&nsp->active_iods) * 2; kinfo->events = (struct kevent *)safe_realloc(kinfo->events, kinfo->evlen * sizeof(struct kevent)); } do { msevent *nse; nsock_log_debug_all(nsp, "wait for events"); nse = next_expirable_event(nsp); if (!nse) event_msecs = -1; /* None of the events specified a timeout */ else event_msecs = MAX(0, TIMEVAL_MSEC_SUBTRACT(nse->timeout, nsock_tod)); #if HAVE_PCAP #ifndef PCAP_CAN_DO_SELECT /* Force a low timeout when capturing packets on systems where * the pcap descriptor is not select()able. */ if (gh_list_count(&nsp->pcap_read_events) > 0) if (event_msecs > PCAP_POLL_INTERVAL) event_msecs = PCAP_POLL_INTERVAL; #endif #endif /* We cast to unsigned because we want -1 to be very high (since it means no * timeout) */ combined_msecs = MIN((unsigned)event_msecs, (unsigned)msec_timeout); /* Set up the timeval pointer we will give to kevent() */ memset(&ts, 0, sizeof(struct timespec)); if (combined_msecs >= 0) { ts.tv_sec = combined_msecs / 1000; ts.tv_nsec = (combined_msecs % 1000) * 1000000L; ts_p = &ts; } else { ts_p = NULL; } #if HAVE_PCAP #ifndef PCAP_CAN_DO_SELECT /* do non-blocking read on pcap devices that doesn't support select() * If there is anything read, just leave this loop. */ if (pcap_read_on_nonselect(nsp)) { /* okay, something was read. */ } else #endif #endif { results_left = kevent(kinfo->kqfd, NULL, 0, kinfo->events, kinfo->evlen, ts_p); if (results_left == -1) sock_err = socket_errno(); } gettimeofday(&nsock_tod, NULL); /* Due to kevent delay */ } while (results_left == -1 && sock_err == EINTR); /* repeat only if signal occurred */ if (results_left == -1 && sock_err != EINTR) { nsock_log_error(nsp, "nsock_loop error %d: %s", sock_err, socket_strerror(sock_err)); nsp->errnum = sock_err; return -1; } iterate_through_event_lists(nsp, results_left); return 1; }
static int ncat_listen_stream(int proto) { int rc, i, fds_ready; fd_set listen_fds; struct timeval tv; struct timeval *tvp = NULL; unsigned int num_sockets; /* clear out structs */ FD_ZERO(&master_readfds); FD_ZERO(&master_writefds); FD_ZERO(&master_broadcastfds); FD_ZERO(&listen_fds); #ifdef HAVE_OPENSSL FD_ZERO(&sslpending_fds); #endif zmem(&client_fdlist, sizeof(client_fdlist)); zmem(&broadcast_fdlist, sizeof(broadcast_fdlist)); #ifdef WIN32 set_pseudo_sigchld_handler(decrease_conn_count); #else /* Reap on SIGCHLD */ Signal(SIGCHLD, sigchld_handler); /* Ignore the SIGPIPE that occurs when a client disconnects suddenly and we send data to it before noticing. */ Signal(SIGPIPE, SIG_IGN); #endif #ifdef HAVE_OPENSSL if (o.ssl) setup_ssl_listen(); #endif /* Not sure if this problem exists on Windows, but fcntl and /dev/null don't */ #ifndef WIN32 /* Check whether stdin is closed. Because we treat this fd specially, we * can't risk it being reopened for an incoming connection, so we'll hold * it open instead. */ if (fcntl(STDIN_FILENO, F_GETFD) == -1 && errno == EBADF) { logdebug("stdin is closed, attempting to reserve STDIN_FILENO\n"); rc = open("/dev/null", O_RDONLY); if (rc >= 0 && rc != STDIN_FILENO) { /* Oh well, we tried */ logdebug("Couldn't reserve STDIN_FILENO\n"); close(rc); } } #endif /* We need a list of fds to keep current fdmax. The second parameter is a number added to the supplied connection limit, that will compensate maxfds for the added by default listen and stdin sockets. */ init_fdlist(&client_fdlist, sadd(o.conn_limit, num_listenaddrs + 1)); for (i = 0; i < NUM_LISTEN_ADDRS; i++) listen_socket[i] = -1; num_sockets = 0; for (i = 0; i < num_listenaddrs; i++) { /* setup the main listening socket */ listen_socket[num_sockets] = do_listen(SOCK_STREAM, proto, &listenaddrs[i]); if (listen_socket[num_sockets] == -1) { if (o.debug > 0) logdebug("do_listen(\"%s\"): %s\n", inet_ntop_ez(&listenaddrs[i].storage, sizeof(listenaddrs[i].storage)), socket_strerror(socket_errno())); continue; } /* Make our listening socket non-blocking because there are timing issues * which could cause us to block on accept() even though select() says it's * readable. See UNPv1 2nd ed, p422 for more. */ unblock_socket(listen_socket[num_sockets]); /* setup select sets and max fd */ FD_SET(listen_socket[num_sockets], &master_readfds); add_fd(&client_fdlist, listen_socket[num_sockets]); FD_SET(listen_socket[num_sockets], &listen_fds); num_sockets++; } if (num_sockets == 0) { if (num_listenaddrs == 1) bye("Unable to open listening socket on %s: %s", inet_ntop_ez(&listenaddrs[0].storage, sizeof(listenaddrs[0].storage)), socket_strerror(socket_errno())); else bye("Unable to open any listening sockets."); } add_fd(&client_fdlist, STDIN_FILENO); init_fdlist(&broadcast_fdlist, o.conn_limit); if (o.idletimeout > 0) tvp = &tv; while (1) { /* We pass these temporary descriptor sets to fselect, since fselect modifies the sets it receives. */ fd_set readfds = master_readfds, writefds = master_writefds; struct fdinfo *fdi = NULL; if (o.debug > 1) logdebug("selecting, fdmax %d\n", client_fdlist.fdmax); if (o.debug > 1 && o.broker) logdebug("Broker connection count is %d\n", get_conn_count()); if (o.idletimeout > 0) ms_to_timeval(tvp, o.idletimeout); fds_ready = fselect(client_fdlist.fdmax + 1, &readfds, &writefds, NULL, tvp); if (o.debug > 1) logdebug("select returned %d fds ready\n", fds_ready); if (fds_ready == 0) bye("Idle timeout expired (%d ms).", o.idletimeout); /* * FIXME: optimize this loop to look only at the fds in the fd list, * doing it this way means that if you have one descriptor that is very * large, say 500, and none close to it, that you'll loop many times for * nothing. */ for (i = 0; i <= client_fdlist.fdmax && fds_ready > 0; i++) { /* Loop through descriptors until there's something to read */ if (!FD_ISSET(i, &readfds) && !FD_ISSET(i, &writefds)) continue; if (o.debug > 1) logdebug("fd %d is ready\n", i); #ifdef HAVE_OPENSSL /* Is this an ssl socket pending a handshake? If so handle it. */ if (o.ssl && FD_ISSET(i, &sslpending_fds)) { FD_CLR(i, &master_readfds); FD_CLR(i, &master_writefds); fdi = get_fdinfo(&client_fdlist, i); ncat_assert(fdi != NULL); switch (ssl_handshake(fdi)) { case NCAT_SSL_HANDSHAKE_COMPLETED: /* Clear from sslpending_fds once ssl is established */ FD_CLR(i, &sslpending_fds); post_handle_connection(*fdi); break; case NCAT_SSL_HANDSHAKE_PENDING_WRITE: FD_SET(i, &master_writefds); break; case NCAT_SSL_HANDSHAKE_PENDING_READ: FD_SET(i, &master_readfds); break; case NCAT_SSL_HANDSHAKE_FAILED: default: SSL_free(fdi->ssl); Close(fdi->fd); FD_CLR(i, &sslpending_fds); FD_CLR(i, &master_readfds); rm_fd(&client_fdlist, i); /* Are we in single listening mode(without -k)? If so then we should quit also. */ if (!o.keepopen && !o.broker) return 1; --conn_inc; break; } } else #endif if (FD_ISSET(i, &listen_fds)) { /* we have a new connection request */ handle_connection(i); } else if (i == STDIN_FILENO) { if (o.broker) { read_and_broadcast(i); } else { /* Read from stdin and write to all clients. */ rc = read_stdin(); if (rc == 0) { if (o.proto != IPPROTO_TCP || (o.proto == IPPROTO_TCP && o.sendonly)) { /* There will be nothing more to send. If we're not receiving anything, we can quit here. */ return 0; } if (!o.noshutdown) shutdown_sockets(SHUT_WR); } if (rc < 0) return 1; } } else if (!o.sendonly) { if (o.broker) { read_and_broadcast(i); } else { /* Read from a client and write to stdout. */ rc = read_socket(i); if (rc <= 0 && !o.keepopen) return rc == 0 ? 0 : 1; } } fds_ready--; } } return 0; }
/* This is sufficiently different from the TCP code (wrt SSL, etc) that it * resides in its own simpler function */ static int ncat_listen_dgram(int proto) { struct { int fd; union sockaddr_u addr; } sockfd[NUM_LISTEN_ADDRS]; int i, fdn = -1; int fdmax, nbytes, n, fds_ready; char buf[DEFAULT_UDP_BUF_LEN] = { 0 }; char *tempbuf = NULL; fd_set read_fds; union sockaddr_u remotess; socklen_t sslen = sizeof(remotess.storage); struct timeval tv; struct timeval *tvp = NULL; unsigned int num_sockets; for (i = 0; i < NUM_LISTEN_ADDRS; i++) { sockfd[i].fd = -1; sockfd[i].addr.storage.ss_family = AF_UNSPEC; } FD_ZERO(&read_fds); /* Initialize remotess struct so recvfrom() doesn't hit the fan.. */ zmem(&remotess.storage, sizeof(remotess.storage)); remotess.storage.ss_family = o.af; #ifdef WIN32 set_pseudo_sigchld_handler(decrease_conn_count); #else /* Reap on SIGCHLD */ Signal(SIGCHLD, sigchld_handler); /* Ignore the SIGPIPE that occurs when a client disconnects suddenly and we send data to it before noticing. */ Signal(SIGPIPE, SIG_IGN); #endif /* Not sure if this problem exists on Windows, but fcntl and /dev/null don't */ #ifndef WIN32 /* Check whether stdin is closed. Because we treat this fd specially, we * can't risk it being reopened for an incoming connection, so we'll hold * it open instead. */ if (fcntl(STDIN_FILENO, F_GETFD) == -1 && errno == EBADF) { logdebug("stdin is closed, attempting to reserve STDIN_FILENO\n"); i = open("/dev/null", O_RDONLY); if (i >= 0 && i != STDIN_FILENO) { /* Oh well, we tried */ logdebug("Couldn't reserve STDIN_FILENO\n"); close(i); } } #endif /* set for selecting udp listening sockets */ fd_set listen_fds; fd_list_t listen_fdlist; FD_ZERO(&listen_fds); init_fdlist(&listen_fdlist, num_listenaddrs); num_sockets = 0; for (i = 0; i < num_listenaddrs; i++) { /* create the UDP listen sockets */ sockfd[num_sockets].fd = do_listen(SOCK_DGRAM, proto, &listenaddrs[i]); if (sockfd[num_sockets].fd == -1) { if (o.debug > 0) logdebug("do_listen(\"%s\"): %s\n", inet_ntop_ez(&listenaddrs[i].storage, sizeof(listenaddrs[i].storage)), socket_strerror(socket_errno())); continue; } FD_SET(sockfd[num_sockets].fd, &listen_fds); add_fd(&listen_fdlist, sockfd[num_sockets].fd); sockfd[num_sockets].addr = listenaddrs[i]; num_sockets++; } if (num_sockets == 0) { if (num_listenaddrs == 1) bye("Unable to open listening socket on %s: %s", inet_ntop_ez(&listenaddrs[0].storage, sizeof(listenaddrs[0].storage)), socket_strerror(socket_errno())); else bye("Unable to open any listening sockets."); } if (o.idletimeout > 0) tvp = &tv; while (1) { int i, j, conn_count, socket_n; if (fdn != -1) { /*remove socket descriptor which is burnt */ FD_CLR(sockfd[fdn].fd, &listen_fds); rm_fd(&listen_fdlist, sockfd[fdn].fd); /* Rebuild the udp socket which got burnt */ sockfd[fdn].fd = do_listen(SOCK_DGRAM, proto, &sockfd[fdn].addr); if (sockfd[fdn].fd == -1) bye("do_listen: %s", socket_strerror(socket_errno())); FD_SET(sockfd[fdn].fd, &listen_fds); add_fd(&listen_fdlist, sockfd[fdn].fd); } fdn = -1; socket_n = -1; fd_set fds; FD_ZERO(&fds); while (1) { /* * We just select to get a list of sockets which we can talk to */ if (o.debug > 1) logdebug("selecting, fdmax %d\n", listen_fdlist.fdmax); fds = listen_fds; if (o.idletimeout > 0) ms_to_timeval(tvp, o.idletimeout); fds_ready = fselect(listen_fdlist.fdmax + 1, &fds, NULL, NULL, tvp); if (o.debug > 1) logdebug("select returned %d fds ready\n", fds_ready); if (fds_ready == 0) bye("Idle timeout expired (%d ms).", o.idletimeout); /* * Figure out which listening socket got a connection. This loop should * really call a function for each ready socket instead of breaking on * the first one. */ for (i = 0; i <= listen_fdlist.fdmax && fds_ready > 0; i++) { /* Loop through descriptors until there is something ready */ if (!FD_ISSET(i, &fds)) continue; /* Check each listening socket */ for (j = 0; j < num_sockets; j++) { if (i == sockfd[j].fd) { if (o.debug > 1) logdebug("Valid descriptor %d \n", i); fdn = j; socket_n = i; break; } } /* if we found a valid socket break */ if (fdn != -1) { fds_ready--; break; } } /* Make sure someone connected */ if (fdn == -1) continue; /* * We just peek so we can get the client connection details without * removing anything from the queue. Sigh. */ nbytes = recvfrom(socket_n, buf, sizeof(buf), MSG_PEEK, &remotess.sockaddr, &sslen); if (nbytes < 0) { loguser("%s.\n", socket_strerror(socket_errno())); close(socket_n); return 1; } /* Check conditions that might cause us to deny the connection. */ conn_count = get_conn_count(); if (conn_count >= o.conn_limit) { if (o.verbose) loguser("New connection denied: connection limit reached (%d)\n", conn_count); } else if (!allow_access(&remotess)) { if (o.verbose) loguser("New connection denied: not allowed\n"); } else { /* Good to go. */ break; } /* Dump the current datagram */ nbytes = recv(socket_n, buf, sizeof(buf), 0); if (nbytes < 0) { loguser("%s.\n", socket_strerror(socket_errno())); close(socket_n); return 1; } ncat_log_recv(buf, nbytes); } if (o.debug > 1) logdebug("Valid Connection from %d\n", socket_n); conn_inc++; /* * We're using connected udp. This has the down side of only * being able to handle one udp client at a time */ Connect(socket_n, &remotess.sockaddr, sslen); /* clean slate for buf */ zmem(buf, sizeof(buf)); /* are we executing a command? then do it */ if (o.cmdexec) { struct fdinfo info = { 0 }; info.fd = socket_n; if (o.keepopen) netrun(&info, o.cmdexec); else netexec(&info, o.cmdexec); continue; } FD_SET(socket_n, &read_fds); FD_SET(STDIN_FILENO, &read_fds); fdmax = socket_n; /* stdin -> socket and socket -> stdout */ while (1) { fd_set fds; fds = read_fds; if (o.debug > 1) logdebug("udp select'ing\n"); if (o.idletimeout > 0) ms_to_timeval(tvp, o.idletimeout); fds_ready = fselect(fdmax + 1, &fds, NULL, NULL, tvp); if (fds_ready == 0) bye("Idle timeout expired (%d ms).", o.idletimeout); if (FD_ISSET(STDIN_FILENO, &fds)) { nbytes = Read(STDIN_FILENO, buf, sizeof(buf)); if (nbytes <= 0) { if (nbytes < 0 && o.verbose) { logdebug("Error reading from stdin: %s\n", strerror(errno)); } else if (nbytes == 0 && o.debug) { logdebug("EOF on stdin\n"); } FD_CLR(STDIN_FILENO, &read_fds); if (nbytes < 0) return 1; continue; } if (o.crlf) fix_line_endings((char *) buf, &nbytes, &tempbuf, &crlf_state); if (!o.recvonly) { if (tempbuf != NULL) n = send(socket_n, tempbuf, nbytes, 0); else n = send(socket_n, buf, nbytes, 0); if (n < nbytes) { loguser("%s.\n", socket_strerror(socket_errno())); close(socket_n); return 1; } ncat_log_send(buf, nbytes); } if (tempbuf != NULL) { free(tempbuf); tempbuf = NULL; } } if (FD_ISSET(socket_n, &fds)) { nbytes = recv(socket_n, buf, sizeof(buf), 0); if (nbytes < 0) { loguser("%s.\n", socket_strerror(socket_errno())); close(socket_n); return 1; } ncat_log_recv(buf, nbytes); if (!o.sendonly) Write(STDOUT_FILENO, buf, nbytes); } zmem(buf, sizeof(buf)); } } return 0; }
/*-------------------------------------------------------------------------*\ * Tries to create a new inet socket \*-------------------------------------------------------------------------*/ const char *inet_trycreate(p_socket ps, int type) { return socket_strerror(socket_create(ps, AF_INET, type, 0)); }
/* Return a listening socket after setting various characteristics on it. Returns -1 on error. */ int do_listen(int type, int proto, const union sockaddr_u *srcaddr_u) { int sock = 0, option_on = 1; size_t sa_len; if (type != SOCK_STREAM && type != SOCK_DGRAM) return -1; /* We need a socket that can be inherited by child processes in ncat_exec_win.c, for --exec and --sh-exec. inheritable_socket is from nbase. */ sock = inheritable_socket(srcaddr_u->storage.ss_family, type, proto); if (sock < 0) return -1; Setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &option_on, sizeof(int)); /* IPPROTO_IPV6 is defined in Visual C++ only when _WIN32_WINNT >= 0x501. Nbase's nbase_winunix.h defines _WIN32_WINNT to a lower value for compatibility with older versions of Windows. This code disables IPv6 sockets that also receive IPv4 connections. This is the default on Windows anyway so it doesn't make a difference. http://support.microsoft.com/kb/950688 http://msdn.microsoft.com/en-us/library/bb513665 */ #ifdef IPPROTO_IPV6 #ifdef IPV6_V6ONLY if (srcaddr_u->storage.ss_family == AF_INET6) { int set = 1; /* Tell it to not try and bind to IPV4 */ if (setsockopt(sock, IPPROTO_IPV6, IPV6_V6ONLY, &set, sizeof(set)) == -1) die("Unable to set IPV6 socket to bind only to IPV6"); } #endif #endif #ifdef HAVE_SYS_UN_H if (srcaddr_u->storage.ss_family == AF_UNIX) sa_len = SUN_LEN(&srcaddr_u->un); else #endif #ifdef HAVE_SOCKADDR_SA_LEN sa_len = srcaddr_u->sockaddr.sa_len; #else sa_len = sizeof(*srcaddr_u); #endif if (bind(sock, &srcaddr_u->sockaddr, sa_len) < 0) { #ifdef HAVE_SYS_UN_H if (srcaddr_u->storage.ss_family == AF_UNIX) bye("bind to %s: %s.", srcaddr_u->un.sun_path, socket_strerror(socket_errno())); else #endif bye("bind to %s:%hu: %s.", inet_socktop(srcaddr_u), inet_port(srcaddr_u), socket_strerror(socket_errno())); } if (type == SOCK_STREAM) Listen(sock, BACKLOG); if (o.verbose) { #ifdef HAVE_SYS_UN_H if (srcaddr_u->storage.ss_family == AF_UNIX) loguser("Listening on %s\n", srcaddr_u->un.sun_path); else #endif loguser("Listening on %s:%hu\n", inet_socktop(srcaddr_u), inet_port(srcaddr_u)); } if (o.test) logtest("LISTEN\n"); return sock; }
/*-------------------------------------------------------------------------*\ * Tries to create a new inet socket \*-------------------------------------------------------------------------*/ const char *inet_trycreate(p_socket ps, int family, int type) { return socket_strerror(socket_create(ps, family, type, 0)); }
const char *socket_ioerror(p_socket ps, int err) { (void) ps; return socket_strerror(err); }
int ncat_connect(void) { nsock_pool mypool; int rc; /* Unless explicitely asked not to do so, ncat uses the * fallback nsock engine to maximize compatibility between * operating systems and the different use cases. */ if (!o.nsock_engine) nsock_set_default_engine("select"); /* Create an nsock pool */ if ((mypool = nsp_new(NULL)) == NULL) bye("Failed to create nsock_pool."); if (o.debug >= 6) nsock_set_loglevel(mypool, NSOCK_LOG_DBG_ALL); else if (o.debug >= 3) nsock_set_loglevel(mypool, NSOCK_LOG_DBG); else if (o.debug >= 1) nsock_set_loglevel(mypool, NSOCK_LOG_INFO); else nsock_set_loglevel(mypool, NSOCK_LOG_ERROR); /* Allow connections to broadcast addresses. */ nsp_setbroadcast(mypool, 1); #ifdef HAVE_OPENSSL set_ssl_ctx_options((SSL_CTX *) nsp_ssl_init(mypool)); #endif if (httpconnect.storage.ss_family == AF_UNSPEC && socksconnect.storage.ss_family == AF_UNSPEC) { /* A non-proxy connection. Create an iod for a new socket. */ cs.sock_nsi = nsi_new(mypool, NULL); if (cs.sock_nsi == NULL) bye("Failed to create nsock_iod."); if (nsi_set_hostname(cs.sock_nsi, o.target) == -1) bye("Failed to set hostname on iod."); #if HAVE_SYS_UN_H /* For DGRAM UNIX socket we have to use source socket */ if (o.af == AF_UNIX && o.udp) { if (srcaddr.storage.ss_family != AF_UNIX) { char *tmp_name = NULL; /* If no source socket was specified, we have to create temporary one. */ if ((tmp_name = tempnam(NULL, "ncat.")) == NULL) bye("Failed to create name for temporary DGRAM source Unix domain socket (tempnam)."); srcaddr.un.sun_family = AF_UNIX; strncpy(srcaddr.un.sun_path, tmp_name, sizeof(srcaddr.un.sun_path)); free (tmp_name); } nsi_set_localaddr(cs.sock_nsi, &srcaddr.storage, SUN_LEN((struct sockaddr_un *)&srcaddr.storage)); if (o.verbose) loguser("[%s] used as source DGRAM Unix domain socket.\n", srcaddr.un.sun_path); } else #endif if (srcaddr.storage.ss_family != AF_UNSPEC) nsi_set_localaddr(cs.sock_nsi, &srcaddr.storage, sizeof(srcaddr.storage)); if (o.numsrcrtes) { unsigned char *ipopts = NULL; size_t ipoptslen = 0; if (o.af != AF_INET) bye("Sorry, -g can only currently be used with IPv4."); ipopts = buildsrcrte(targetss.in.sin_addr, o.srcrtes, o.numsrcrtes, o.srcrteptr, &ipoptslen); nsi_set_ipoptions(cs.sock_nsi, ipopts, ipoptslen); free(ipopts); /* Nsock has its own copy */ } #if HAVE_SYS_UN_H if (o.af == AF_UNIX) { if (o.udp) { nsock_connect_unixsock_datagram(mypool, cs.sock_nsi, connect_handler, NULL, &targetss.sockaddr, SUN_LEN((struct sockaddr_un *)&targetss.sockaddr)); } else { nsock_connect_unixsock_stream(mypool, cs.sock_nsi, connect_handler, o.conntimeout, NULL, &targetss.sockaddr, SUN_LEN((struct sockaddr_un *)&targetss.sockaddr)); } } else #endif if (o.udp) { nsock_connect_udp(mypool, cs.sock_nsi, connect_handler, NULL, &targetss.sockaddr, targetsslen, inet_port(&targetss)); } #ifdef HAVE_OPENSSL else if (o.sctp && o.ssl) { nsock_connect_ssl(mypool, cs.sock_nsi, connect_handler, o.conntimeout, NULL, &targetss.sockaddr, targetsslen, IPPROTO_SCTP, inet_port(&targetss), NULL); } #endif else if (o.sctp) { nsock_connect_sctp(mypool, cs.sock_nsi, connect_handler, o.conntimeout, NULL, &targetss.sockaddr, targetsslen, inet_port(&targetss)); } #ifdef HAVE_OPENSSL else if (o.ssl) { nsock_connect_ssl(mypool, cs.sock_nsi, connect_handler, o.conntimeout, NULL, &targetss.sockaddr, targetsslen, IPPROTO_TCP, inet_port(&targetss), NULL); } #endif else { nsock_connect_tcp(mypool, cs.sock_nsi, connect_handler, o.conntimeout, NULL, &targetss.sockaddr, targetsslen, inet_port(&targetss)); } } else { /* A proxy connection. */ static int connect_socket; int len; char *line; size_t n; if (httpconnect.storage.ss_family != AF_UNSPEC) { connect_socket = do_proxy_http(); if (connect_socket == -1) return 1; } else if (socksconnect.storage.ss_family != AF_UNSPEC) { struct socket_buffer stateful_buf; struct socks4_data socks4msg; char socksbuf[8]; connect_socket = do_connect(SOCK_STREAM); if (connect_socket == -1) { loguser("Proxy connection failed: %s.\n", socket_strerror(socket_errno())); return 1; } socket_buffer_init(&stateful_buf, connect_socket); if (o.verbose) { loguser("Connected to proxy %s:%hu\n", inet_socktop(&targetss), inet_port(&targetss)); } /* Fill the socks4_data struct */ zmem(&socks4msg, sizeof(socks4msg)); socks4msg.version = SOCKS4_VERSION; socks4msg.type = SOCKS_CONNECT; socks4msg.port = socksconnect.in.sin_port; socks4msg.address = socksconnect.in.sin_addr.s_addr; if (o.proxy_auth) Strncpy(socks4msg.username, (char *) o.proxy_auth, sizeof(socks4msg.username)); len = 8 + strlen(socks4msg.username) + 1; if (send(connect_socket, (char *) &socks4msg, len, 0) < 0) { loguser("Error sending proxy request: %s.\n", socket_strerror(socket_errno())); return 1; } /* The size of the socks4 response is 8 bytes. So read exactly 8 bytes from the buffer */ if (socket_buffer_readcount(&stateful_buf, socksbuf, 8) < 0) { loguser("Error: short reponse from proxy.\n"); return 1; } if (socksbuf[1] != 90) { loguser("Proxy connection failed.\n"); return 1; } /* Clear out whatever is left in the socket buffer which may be already sent by proxy server along with http response headers. */ line = socket_buffer_remainder(&stateful_buf, &n); /* Write the leftover data to stdout. */ Write(STDOUT_FILENO, line, n); } /* Once the proxy negotiation is done, Nsock takes control of the socket. */ cs.sock_nsi = nsi_new2(mypool, connect_socket, NULL); /* Create IOD for nsp->stdin */ if ((cs.stdin_nsi = nsi_new2(mypool, 0, NULL)) == NULL) bye("Failed to create stdin nsiod."); post_connect(mypool, cs.sock_nsi); } /* connect */ rc = nsock_loop(mypool, -1); if (o.verbose) { struct timeval end_time; double time; gettimeofday(&end_time, NULL); time = TIMEVAL_MSEC_SUBTRACT(end_time, start_time) / 1000.0; loguser("%lu bytes sent, %lu bytes received in %.2f seconds.\n", nsi_get_write_count(cs.sock_nsi), nsi_get_read_count(cs.sock_nsi), time); } #if HAVE_SYS_UN_H if (o.af == AF_UNIX && o.udp) { if (o.verbose) loguser("Deleting source DGRAM Unix domain socket. [%s]\n", srcaddr.un.sun_path); unlink(srcaddr.un.sun_path); } #endif nsp_delete(mypool); return rc == NSOCK_LOOP_ERROR ? 1 : 0; }