int rdr_repeater_step(struct rdr_repeater_ctx_t *ctx, fd_set *readfds, fd_set *writefds) { struct endpoint_t *ep; assert(ctx); assert(readfds); assert(writefds); for (ep = ctx->head; ep != NULL; ep = ep->next) { switch (ep->status) { case S_CONNECTING: assert(ep->s >= 0); if (!FD_ISSET(ep->s, writefds)) break; /* Socket ready for writing */ if (finish_socket_opening(ctx, ep) < 0) { try_reopen_socket(ctx, ep); } break; case S_WRITING: assert(ep->s >= 0); if (FD_ISSET(ep->s, readfds)) { ssize_t rcvd; unsigned char buf[1]; tcflush(ep->s, TCIFLUSH); rcvd = read(ep->s, &buf, 1); if (rcvd == 0) { if (ctx->verbose) fprintf(stderr, "%s Connection %s closed \n", TAG, get_endpoint_name(ep)); try_reopen_socket(ctx, ep); break; }else if (rcvd < 0) { if (errno != EAGAIN && (errno != EINTR)) { if (ctx->verbose) fprintf(stderr, "%s %s read() error: %s\n", TAG, get_endpoint_name(ep), strerror(errno)); try_reopen_socket(ctx, ep); break; } } } if (FD_ISSET(ep->s, writefds)) buffered_write(ctx, ep, NULL, 0); break; case S_WAITING: try_reopen_socket(ctx, ep); break; case S_NOT_INITIALIZED: default: /* UNREACHABLE */ assert(0); break; } } return 1; }
static int finish_socket_opening(struct rdr_repeater_ctx_t *ctx, struct endpoint_t *ep) { socklen_t peer_name_len; struct sockaddr_storage peer_name; assert(ctx); assert(ep); assert(ep->status == S_CONNECTING); /* Socket ready for writing */ peer_name_len=sizeof(peer_name); if (getpeername(ep->s, (struct sockaddr *)&peer_name, &peer_name_len) < 0) { int error; socklen_t error_len; error_len = sizeof(error); error = 0; if (errno == ENOTCONN) { if (getsockopt(ep->s, SOL_SOCKET, SO_ERROR, &error, &error_len) < 0) error = errno; }else error = errno; if (ctx->verbose > 1) fprintf(stderr, "%s connect(%s) error: %s\n", TAG, get_endpoint_name(ep), strerror(error)); return -1; }else { if (ctx->verbose) fprintf(stderr, "%s connection with %s established successfully\n", TAG, get_endpoint_name(ep)); ep->status = S_WRITING; } return 1; }
void web_server::run(void) { pthread_attr_t attr; pthread_check(pthread_attr_init(&attr), "pthread_attr_init"); pthread_check(pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED), "pthread_attr_setdetachstate"); for(;;) { int client_fd = accept(fd, NULL, NULL); if (client_fd == -1) { dolog(LOG_INFO, "web_server: accept failed: %s", strerror(errno)); continue; } std::string host = get_endpoint_name(client_fd); dolog(LOG_INFO, "web_server: connected with %s", host.c_str()); http_client_t *p_client = new http_client_t; p_client -> p_server = this; p_client -> fd = client_fd; pthread_t thread; pthread_check(pthread_create(&thread, &attr, thread_wrapper_http_server, reinterpret_cast<void *>(p_client)), "pthread_create"); } }
int rdr_repeater_init_connection(struct rdr_repeater_ctx_t *ctx, unsigned socket_buf_size, int verbose) { struct endpoint_t *ep; assert(ctx); ctx->s_bufsize = socket_buf_size; ctx->verbose = verbose; if (ctx->verbose && (ctx->head != NULL)) { fprintf(stderr, "Repeat all incoming TCP packets to hosts: "); for (ep = ctx->head; ep != NULL; ep = ep->next) { fprintf(stderr, "%s%s", get_endpoint_name(ep), ep->next == NULL ? "\n" : ", "); } } for (ep = ctx->head; ep != NULL; ep = ep->next) { purge_buffer(ep); try_reopen_socket(ctx, ep); assert(ep->status != S_NOT_INITIALIZED); } return 1; }
static int buffered_write(struct rdr_repeater_ctx_t *ctx, struct endpoint_t *ep, void *data, size_t data_size) { ssize_t written; assert(ctx); assert(ep); /* TODO useless memory move */ if (data != NULL) { /* Append data */ if (sizeof(ep->buf) < data_size) { if (ctx->verbose >= 10) fprintf(stderr, "%s %s Buffer overflow. %u bytes packet skipped\n", TAG, get_endpoint_name(ep), (unsigned)data_size); return 0; } if (sizeof(ep->buf) - ep->iptr < data_size) { if (sizeof(ep->buf) - ep->iptr + ep->optr >= data_size) { memmove(ep->buf, &ep->buf[ep->optr], ep->iptr - ep->optr); ep->iptr -= ep->optr; ep->optr = 0; }else { if (ctx->verbose >= 10) fprintf(stderr, "%s %s Buffer overflow. %u bytes skipped\n", TAG, get_endpoint_name(ep), ep->iptr+1); purge_buffer(ep); } } assert(ep->iptr + data_size <= sizeof(ep->buf)); memcpy(&ep->buf[ep->iptr], data, data_size); ep->iptr += data_size; } if (ep->status != S_WRITING) return 0; if (ep->iptr == ep->optr) { if (data == NULL) { int error; socklen_t error_len; /* No data. Check socket status */ error = 0; error_len = sizeof(error); if (getsockopt(ep->s, SOL_SOCKET, SO_ERROR, &error, &error_len) < 0) error = errno; if (error != 0) { if (ctx->verbose) fprintf(stderr, "%s %s socket error: %s\n", TAG, get_endpoint_name(ep), strerror(error)); try_reopen_socket(ctx, ep); return -1; } } return 0; } assert(ep->optr < ep->iptr); written = write(ep->s, &ep->buf[ep->optr], ep->iptr - ep->optr); if (written < 0) { if (errno == EAGAIN || (errno == EINTR)) return 0; /* Error */ if (ctx->verbose) fprintf(stderr, "%s write() error: %s\n", TAG, strerror(errno)); try_reopen_socket(ctx, ep); }else { ep->optr += written; if (ep->optr == ep->iptr) ep->iptr = ep->optr = 0; } return written; }
static int open_socket(struct rdr_repeater_ctx_t *ctx, struct endpoint_t *ep) { int old_status; int flags; assert(ctx); assert(ep); assert(ep->status == S_NOT_INITIALIZED); assert(ep->s < 0); assert(ep->addrinfo != NULL); assert(ep->cur_addr != NULL); if (ctx->verbose > 1) fprintf(stderr, "%s Trying %s...\n", TAG, get_endpoint_name(ep)); ep->s = socket(ep->cur_addr->ai_family, ep->cur_addr->ai_socktype, ep->cur_addr->ai_protocol); if (ep->s < 0) { if (ctx->verbose > 1) fprintf(stderr, "%s Socket() error: %s\n", TAG, strerror(errno)); return -1; } #ifdef SO_SNDBUF if (ctx->s_bufsize > 0) { unsigned sndbuf; sndbuf = ctx->s_bufsize; if (setsockopt(ep->s, SOL_SOCKET, SO_SNDBUF, &sndbuf, sizeof(sndbuf)) < 0) { perror("setsockopt(SO_SNDBUF) error"); close(ep->s); ep->s = -1; return -1; } } #endif flags = fcntl(ep->s, F_GETFL, 0); fcntl(ep->s, F_SETFL, flags | O_NONBLOCK); old_status = ep->status; ep->status = S_CONNECTING; if (connect(ep->s, ep->cur_addr->ai_addr, ep->cur_addr->ai_addrlen) < 0) { if (errno != EINPROGRESS) { if (ctx->verbose > 1) fprintf(stderr, "%s connect(%s) error: %s\n", TAG, get_endpoint_name(ep), strerror(errno)); close(ep->s); ep->s = -1; ep->status = old_status; return -1; } }else { if (finish_socket_opening(ctx, ep) < 0) { close(ep->s); ep->s = -1; ep->status = old_status; return -1; } } return ep->s; }
int auth_eb_user(int fd, int to, users *user_map, std::string & username_out, std::string & password, long long unsigned int *challenge, bool is_proxy_auth, bool *is_server_in, std::string & type, random_source *rs, encrypt_stream *es, hasher *mac, std::string handshake_hash, unsigned int max_get_put_size, statistics_global *sg) { std::string host = get_endpoint_name(fd); const char *ts = is_proxy_auth ? "Proxy-auth" : "Connection"; /* Inform the client about the hash-functions and ciphers that are used */ std::string mac_data = mac -> get_name(); std::string cipher_data = es -> get_name(); if (send_length_data(fd, handshake_hash.c_str(), handshake_hash.size(), to) == -1) { dolog(LOG_INFO, "%s failure sending handshake hash (fd: %d, host: %s)", ts, fd, host.c_str()); return -1; } if (send_length_data(fd, mac_data.c_str(), mac_data.size(), to) == -1) { dolog(LOG_INFO, "%s failure sending data MAC (fd: %d, host: %s)", ts, fd, host.c_str()); return -1; } if (send_length_data(fd, cipher_data.c_str(), cipher_data.size(), to) == -1) { dolog(LOG_INFO, "%s failure sending data cipher (fd: %d, host: %s)", ts, fd, host.c_str()); return -1; } ///// /* send random with which will be concatenated to the password and then hashed */ long long unsigned int rnd = 9; rs -> get(reinterpret_cast<unsigned char *>(&rnd), sizeof rnd); char rnd_str[128]; unsigned int rnd_str_size = snprintf(rnd_str, sizeof rnd_str, "%llu", rnd); *challenge = rnd; if (rnd_str_size == 0) error_exit("INTERNAL ERROR: random string is 0 characters!"); if (send_length_data(fd, rnd_str, rnd_str_size, to) == -1) { dolog(LOG_INFO, "%s failure sending random (fd: %d, host: %s)", ts, fd, host.c_str()); return -1; } ///// /* receive username */ char *username = NULL; unsigned int username_length = 0; if (recv_length_data(fd, &username, &username_length, to) == -1) { dolog(LOG_INFO, "%s receiving username (fd: %d, host: %s)", ts, fd, host.c_str()); return -1; } dolog(LOG_INFO, "User '%s'[len: %d] requesting access (fd: %d, host: %s)", username, username_length, fd, host.c_str()); if (username == NULL || username[0] == 0x00 || username_length == 0) { dolog(LOG_WARNING, "Empty username"); sg -> put_history_log(HL_LOGIN_OTHER, host, "", "", get_ts(), 0, "empty username"); free(username); return -1; } username_out.assign(username); bool user_known = user_map -> get_password(username_out, password); if (!user_known) { dolog(LOG_WARNING, "User '%s' not known, (fd: %d, host: %s)", username, fd, host.c_str()); sg -> put_history_log(HL_LOGIN_USER_FAIL, host, "", username_out, get_ts(), 0, "username not known"); user_known = false; } free(username); ///// /* receive hashed password */ hasher *hh = hasher::select_hasher(handshake_hash); int hash_len = hh -> get_hash_size(); char hash_cmp_str[256], *hash_cmp = reinterpret_cast<char *>(malloc(hash_len)), *hash_in = reinterpret_cast<char *>(malloc(hash_len)); int hash_cmp_str_len = snprintf(hash_cmp_str, sizeof hash_cmp_str, "%s %s", rnd_str, password.c_str()); if (!hash_cmp || !hash_in) error_exit("out of memory"); hh -> do_hash((unsigned char *)hash_cmp_str, hash_cmp_str_len, reinterpret_cast<unsigned char *>(hash_cmp)); if (READ_TO(fd, hash_in, hash_len, to) != hash_len) { dolog(LOG_INFO, "%s receiving hash failed (fd: %d, host: %s)", ts, fd, host.c_str()); free(hash_cmp); free(hash_in); delete hh; return -1; } if (!user_known || memcmp(hash_cmp, hash_in, hash_len) != 0) { dolog(LOG_INFO, "%s authentication failed! (fd: %d, host: %s)", ts, fd, host.c_str()); free(hash_cmp); free(hash_in); delete hh; sg -> put_history_log(HL_LOGIN_PW_FAIL, host, "", username_out, get_ts(), 0, "hash mismatch"); return -1; } free(hash_cmp); free(hash_in); delete hh; ///// /* receive a byte which indicates if the other end is a client or a server */ char is_server = 0; if (READ_TO(fd, &is_server, 1, to) != 1) { dolog(LOG_INFO, "%s failed retrieving server/client (fd: %d, host: %s)", ts, fd, host.c_str()); return -1; } *is_server_in = is_server ? true : false; ///// /* receive a string which describes the other send */ char *type_in = NULL; unsigned int type_in_size = 0; if (recv_length_data(fd, &type_in, &type_in_size, to) == -1) { dolog(LOG_INFO, "%s failed retrieving type (fd: %d, host: %s)", ts, fd, host.c_str()); return -1; } type = std::string(type_in); free(type_in); ///// /* how many bits can be put/get in one go */ unsigned char max_get_put_size_bytes[4]; uint_to_uchar(max_get_put_size, max_get_put_size_bytes); if (WRITE_TO(fd, max_get_put_size_bytes, 4, to) == -1) { dolog(LOG_INFO, "Connection closed (fd: %d, host: %s)", fd, host.c_str()); return -1; } dolog(LOG_INFO, "%s authentication ok (fd: %d, host: %s)", ts, fd, host.c_str()); double now_ts = get_ts(); user_map -> set_last_login(username_out, now_ts); sg -> put_history_log(HL_LOGIN_OK, host, type, username_out, now_ts, 0, ""); return 0; }