/* connect remote host */ NOEXPORT int connect_remote(CLI *c) { int fd, ind_start, ind_try, ind_cur; setup_connect_addr(c); ind_start=c->connect_addr.cur; /* the race condition here can be safely ignored */ if(c->opt->failover==FAILOVER_RR) c->connect_addr.cur=(ind_start+1)%c->connect_addr.num; /* try to connect each host from the list */ for(ind_try=0; ind_try<c->connect_addr.num; ind_try++) { ind_cur=(ind_start+ind_try)%c->connect_addr.num; c->fd=s_socket(c->connect_addr.addr[ind_cur].sa.sa_family, SOCK_STREAM, 0, 1, "remote socket"); if(c->fd<0) longjmp(c->err, 1); local_bind(c); /* explicit local bind or transparent proxy */ if(s_connect(c, &c->connect_addr.addr[ind_cur], addr_len(&c->connect_addr.addr[ind_cur]))) { closesocket(c->fd); c->fd=-1; continue; /* next IP */ } print_bound_address(c); fd=c->fd; c->fd=-1; return fd; /* success! */ } longjmp(c->err, 1); return -1; /* some C compilers require a return value */ }
/** Send a message through the socket * * If a disconnection occurs, 0 will be returned, as no data was sent. To * differentiate from cases where data couldn't be written just yet, the socket * should be inspected with socket_is_disconnected(). * * \param socket Socket to send message through * \param buf data to send * \param buf_size amount of data to read from buf * \return the amount of data sent, or -1 on error * * \see socket_is_disconnected, sendto(3) */ int socket_sendto(Socket* socket, char* buf, int buf_size) { SocketInt *self = (SocketInt*)socket; int sent; if (self->is_disconnected) { if(!s_connect(self)) { return 0; } } else if((sent = recv(self->sockfd, NULL, 0, MSG_DONTWAIT)) == 0) { /* Test that the server kept the other side of the connection alive */ if (!(sent < 0 && EAGAIN == errno)) { /* EAGAIN is the expected case: connection alive but no data, * everything else is a problem */ logwarn("socket(%s): Server appears to have closed the connection\n", self->name); self->is_disconnected = 1; /* We want higher levels to be aware of this disconnection */ return 0; } } if ((sent = sendto(self->sockfd, buf, buf_size, MSG_NOSIGNAL, &(self->servAddr.sa), sizeof(self->servAddr.sa_stor))) < 0) { if (errno == EPIPE || errno == ECONNRESET) { // The other end closed the connection. self->is_disconnected = 1; o_log(O_LOG_ERROR, "socket(%s): The remote peer closed the connection: %s\n", self->name, strerror(errno)); return 0; } else if (errno == ECONNREFUSED) { self->is_disconnected = 1; o_log(O_LOG_DEBUG, "socket(%s): Connection refused, trying next AI\n", self->name); self->rp = self->rp->ai_next; return 0; } else if (errno == EINTR) { o_log(O_LOG_WARN, "socket(%s): Sending data interrupted: %s\n", self->name, strerror(errno)); return 0; } else { o_log(O_LOG_ERROR, "socket(%s): Sending data failed: %s\n", self->name, strerror(errno)); } return -1; } return sent; }
/** Attempt to reconnect an OComm Socket. * * \param socket OComm socket * \return 0 on failure, the new socket number otherwise * \see s_connect */ int socket_reconnect(Socket* socket) { SocketInt* self = (SocketInt*)socket; if (self == NULL) { o_log(O_LOG_ERROR, "Missing socket definition\n"); return 0; } if (!s_socket(self)) { return 0; } return s_connect(self, NULL, -1); }
int main (int argc, char *argv []) { char *sock = (argc > 1)? argv [1]: ""; if (streq(sock,"")) { zclock_log("cannot start broker for %s", sock); return -1; } char *job = (argc > 2)? argv [2]: ""; if (streq(job,"")) { zclock_log("cannot start broker job %s", job); return -1; } if (s_connect(sock)<0) { zclock_log("cannot connect to %s", sock); return -1; } else { zclock_log("broker connected to %s", sock); } struct sigaction sa; sigemptyset(&sa.sa_mask); sa.sa_flags=0; sa.sa_handler = s_signal_handler; sigaction(SIGHUP, &sa, 0); sigaction(SIGINT, &sa, 0); sigaction(SIGQUIT, &sa, 0); sigaction(SIGABRT, &sa, 0); sigaction(SIGTERM, &sa, 0); if (streq(job,"loop")) { char *arg = (argc > 3)? argv [3]: "1"; int count = atoi(arg); start_loop(count); } if (streq(job,"sleep")) { char *arg = (argc > 3)? argv [3]: "1000"; start_echo(arg); } exit(0); }
Socket* socket_tcp_out_new( char* name, //! Name used for debugging char* addr, //! IP address of the server to connect to. int port //! Port of remote service ) { SocketInt* self; if (addr == NULL) { o_log(O_LOG_ERROR, "socket:%s: Missing address\n", name); return NULL; } if ((self = (SocketInt*)socket_new(name, TRUE)) == NULL) return NULL; if (!s_connect(self, addr, port)) { free(self); return NULL; } // eventloop_on_out_channel((Socket*)self, on_self_connected, NULL); return (Socket*)self; }
const char *tcpremoteinfo(const RFC1035_ADDR *laddr, int lport, const RFC1035_ADDR *raddr, int rport, const char **ostype) { int fd; time_t current_time, max_time; fd_set fds; struct timeval tv; static char buf[512]; char *bufptr; int bufleft, n; char *p; char *q; RFC1035_NETADDR sin; const struct sockaddr *addr; int addrlen; fd=rfc1035_mksocket(SOCK_STREAM, 0, &n); if (fd < 0) return (0); if (rfc1035_mkaddress(n, &sin, laddr, 0, &addr, &addrlen) < 0) { close(fd); return (0); } if (sox_bind(fd, addr, addrlen) < 0) { sox_close(fd); return (0); } time (¤t_time); max_time=current_time+30; if (rfc1035_mkaddress(n, &sin, raddr, htons(113), &addr, &addrlen) < 0) { sox_close(fd); return (0); } if (s_connect(fd, addr, addrlen, max_time - current_time) < 0) { sox_close(fd); return (0); } sprintf(buf, "%d,%d\r\n", ntohs(rport), ntohs(lport)); bufptr=buf; bufleft=strlen(buf); while (bufleft) { time(¤t_time); if (current_time >= max_time) { sox_close(fd); return (0); } FD_ZERO(&fds); FD_SET(fd, &fds); tv.tv_sec=max_time-current_time; tv.tv_usec=0; if (sox_select(fd+1, 0, &fds, 0, &tv) != 1 || !FD_ISSET(fd, &fds)) { sox_close(fd); return (0); } n=sox_write(fd, bufptr, bufleft); if (n <= 0) { sox_close(fd); return (0); } bufptr += n; bufleft -= n; } bufptr=buf; bufleft=sizeof(buf); do { if (bufleft == 0) { sox_close(fd); return (0); } time(¤t_time); if (current_time >= max_time) { sox_close(fd); return (0); } FD_ZERO(&fds); FD_SET(fd, &fds); tv.tv_sec=max_time-current_time; tv.tv_usec=0; if (sox_select(fd+1, &fds, 0, 0, &tv) != 1 || !FD_ISSET(fd, &fds)) { sox_close(fd); return (0); } n=sox_read(fd, bufptr, bufleft); if (n <= 0) { sox_close(fd); return (0); } bufptr += n; bufleft -= n; } while (bufptr[-1] != '\n'); sox_close(fd); bufptr[-1]=0; --bufptr; if (bufptr > buf && bufptr[-1] == '\r') bufptr[-1]=0; if ((p=strchr(buf, ':')) == 0) return (0); q=++p; if ((p=strchr(p, ':')) == 0) return (0); *p++=0; q=strtok(q, " \t"); if (!q || strcmp(q, "USERID")) return (0); if (ostype) *ostype=p; if ((p=strchr(p, ':')) == 0) return (0); *p++=0; while (*p && (*p == ' ' || *p == '\t')) p++; return (p); }
NOEXPORT OCSP_RESPONSE *ocsp_get_response(CLI *c, OCSP_REQUEST *req, char *url) { BIO *bio=NULL; OCSP_REQ_CTX *req_ctx=NULL; OCSP_RESPONSE *resp=NULL; int err; char *host=NULL, *port=NULL, *path=NULL; SOCKADDR_UNION addr; int ssl; /* parse the OCSP URL */ if(!OCSP_parse_url(url, &host, &port, &path, &ssl)) { s_log(LOG_ERR, "OCSP: Failed to parse the OCSP URL"); goto cleanup; } if(ssl) { s_log(LOG_ERR, "OCSP: SSL not supported for OCSP" " - additional stunnel service needs to be defined"); goto cleanup; } memset(&addr, 0, sizeof addr); addr.in.sin_family=AF_INET; if(!hostport2addr(&addr, host, port)) { s_log(LOG_ERR, "OCSP: Failed to resolve the OCSP server address"); goto cleanup; } /* connect specified OCSP server (responder) */ c->fd=s_socket(addr.sa.sa_family, SOCK_STREAM, 0, 1, "OCSP: socket"); if(c->fd<0) goto cleanup; if(s_connect(c, &addr, addr_len(&addr))) goto cleanup; bio=BIO_new_fd(c->fd, BIO_NOCLOSE); if(!bio) goto cleanup; s_log(LOG_DEBUG, "OCSP: response retrieved"); /* OCSP protocol communication loop */ req_ctx=OCSP_sendreq_new(bio, path, req, -1); if(!req_ctx) { sslerror("OCSP: OCSP_sendreq_new"); goto cleanup; } while(OCSP_sendreq_nbio(&resp, req_ctx)==-1) { s_poll_init(c->fds); s_poll_add(c->fds, c->fd, BIO_should_read(bio), BIO_should_write(bio)); err=s_poll_wait(c->fds, c->opt->timeout_busy, 0); if(err==-1) sockerror("OCSP: s_poll_wait"); if(err==0) s_log(LOG_INFO, "OCSP: s_poll_wait: TIMEOUTbusy exceeded"); if(err<=0) goto cleanup; } #if 0 s_log(LOG_DEBUG, "OCSP: context state: 0x%x", *(int *)req_ctx); #endif /* http://www.mail-archive.com/[email protected]/msg61691.html */ if(resp) { s_log(LOG_DEBUG, "OCSP: request completed"); } else { if(ERR_peek_error()) sslerror("OCSP: OCSP_sendreq_nbio"); else /* OpenSSL error: OCSP_sendreq_nbio does not use OCSPerr */ s_log(LOG_ERR, "OCSP: OCSP_sendreq_nbio: OpenSSL internal error"); } cleanup: if(req_ctx) OCSP_REQ_CTX_free(req_ctx); if(bio) BIO_free_all(bio); if(c->fd>=0) { closesocket(c->fd); c->fd=-1; /* avoid double close on cleanup */ } if(host) OPENSSL_free(host); if(port) OPENSSL_free(port); if(path) OPENSSL_free(path); return resp; }
NOEXPORT void auth_user(CLI *c, char *accepted_address) { #ifndef _WIN32_WCE struct servent *s_ent; /* structure for getservbyname */ #endif SOCKADDR_UNION ident; /* IDENT socket name */ char *line, *type, *system, *user; if(!c->opt->username) return; /* -u option not specified */ #ifdef HAVE_STRUCT_SOCKADDR_UN if(c->peer_addr.sa.sa_family==AF_UNIX) { s_log(LOG_INFO, "IDENT not supported on Unix sockets"); return; } #endif c->fd=s_socket(c->peer_addr.sa.sa_family, SOCK_STREAM, 0, 1, "socket (auth_user)"); if(c->fd<0) longjmp(c->err, 1); memcpy(&ident, &c->peer_addr, c->peer_addr_len); #ifndef _WIN32_WCE s_ent=getservbyname("auth", "tcp"); if(s_ent) { ident.in.sin_port=s_ent->s_port; } else #endif { s_log(LOG_WARNING, "Unknown service 'auth': using default 113"); ident.in.sin_port=htons(113); } if(s_connect(c, &ident, addr_len(&ident))) longjmp(c->err, 1); s_log(LOG_DEBUG, "IDENT server connected"); fd_printf(c, c->fd, "%u , %u", ntohs(c->peer_addr.in.sin_port), ntohs(c->opt->local_addr.in.sin_port)); line=fd_getline(c, c->fd); closesocket(c->fd); c->fd=-1; /* avoid double close on cleanup */ type=strchr(line, ':'); if(!type) { s_log(LOG_ERR, "Malformed IDENT response"); str_free(line); longjmp(c->err, 1); } *type++='\0'; system=strchr(type, ':'); if(!system) { s_log(LOG_ERR, "Malformed IDENT response"); str_free(line); longjmp(c->err, 1); } *system++='\0'; if(strcmp(type, " USERID ")) { s_log(LOG_ERR, "Incorrect INETD response type"); str_free(line); longjmp(c->err, 1); } user=strchr(system, ':'); if(!user) { s_log(LOG_ERR, "Malformed IDENT response"); str_free(line); longjmp(c->err, 1); } *user++='\0'; while(*user==' ') /* skip leading spaces */ ++user; if(strcmp(user, c->opt->username)) { safestring(user); s_log(LOG_WARNING, "Connection from %s REFUSED by IDENT (user %s)", accepted_address, user); str_free(line); longjmp(c->err, 1); } s_log(LOG_INFO, "IDENT authentication passed"); str_free(line); }