/* * start_auth_query - Flag the client to show that an attempt to * contact the ident server on the client's host. The connect and * subsequently the socket are all put into 'non-blocking' mode. * Should the connect or any later phase of the identifing process fail, * it is aborted and the user is given a username of "unknown". */ static int start_auth_query(struct AuthRequest* auth) { struct sockaddr_in remote_addr; struct sockaddr_in local_addr; int fd; IOResult result; assert(0 != auth); assert(0 != auth->client); if ((fd = socket(AF_INET, SOCK_STREAM, 0)) == -1) { ++ServerStats->is_abad; return 0; } if ((MAXCONNECTIONS - 10) < fd) { close(fd); return 0; } if (!os_set_nonblocking(fd)) { close(fd); return 0; } if (IsUserPort(auth->client)) sendheader(auth->client, REPORT_DO_ID); /* * get the local address of the client and bind to that to * make the auth request. This used to be done only for * ifdef VIRTTUAL_HOST, but needs to be done for all clients * since the ident request must originate from that same address-- * and machines with multiple IP addresses are common now */ memset(&local_addr, 0, sizeof(struct sockaddr_in)); os_get_sockname(cli_fd(auth->client), &local_addr); local_addr.sin_port = htons(0); if (bind(fd, (struct sockaddr*) &local_addr, sizeof(struct sockaddr_in))) { close(fd); return 0; } remote_addr.sin_addr.s_addr = (cli_ip(auth->client)).s_addr; remote_addr.sin_port = htons(113); remote_addr.sin_family = AF_INET; if ((result = os_connect_nonb(fd, &remote_addr)) == IO_FAILURE || !socket_add(&auth->socket, auth_sock_callback, (void*) auth, result == IO_SUCCESS ? SS_CONNECTED : SS_CONNECTING, SOCK_EVENT_READABLE, fd)) { ServerStats->is_abad++; /* * No error report from this... */ close(fd); if (IsUserPort(auth->client)) sendheader(auth->client, REPORT_FAIL_ID); return 0; } auth->flags |= AM_SOCKET; auth->fd = fd; SetAuthConnect(auth); if (result == IO_SUCCESS) send_auth_query(auth); /* this does a SetAuthPending(auth) for us */ return 1; }
/** Set up address and port and make a connection. * @param aconf Provides the connection information. * @param cptr Client structure for the peer. * @return Non-zero on success; zero on failure. */ static int connect_inet(struct ConfItem* aconf, struct Client* cptr) { const struct irc_sockaddr *local; IOResult result; int family = 0; assert(0 != aconf); assert(0 != cptr); /* * Might as well get sockhost from here, the connection is attempted * with it so if it fails its useless. */ if (irc_in_addr_valid(&aconf->origin.addr)) local = &aconf->origin; else if (irc_in_addr_is_ipv4(&aconf->address.addr)) { local = &VirtualHost_v4; family = AF_INET; } else local = &VirtualHost_v6; cli_fd(cptr) = os_socket(local, SOCK_STREAM, cli_name(cptr), family); if (cli_fd(cptr) < 0) return 0; /* * save connection info in client */ memcpy(&cli_ip(cptr), &aconf->address.addr, sizeof(cli_ip(cptr))); ircd_ntoa_r(cli_sock_ip(cptr), &cli_ip(cptr)); /* * we want a big buffer for server connections */ if (!os_set_sockbufs(cli_fd(cptr), feature_int(FEAT_SOCKSENDBUF), feature_int(FEAT_SOCKRECVBUF))) { cli_error(cptr) = errno; report_error(SETBUFS_ERROR_MSG, cli_name(cptr), errno); close(cli_fd(cptr)); cli_fd(cptr) = -1; return 0; } /* * Set the TOS bits - this is nonfatal if it doesn't stick. */ if (!os_set_tos(cli_fd(cptr), feature_int(FEAT_TOS_SERVER))) { report_error(TOS_ERROR_MSG, cli_name(cptr), errno); } if ((result = os_connect_nonb(cli_fd(cptr), &aconf->address)) == IO_FAILURE) { cli_error(cptr) = errno; report_error(CONNECT_ERROR_MSG, cli_name(cptr), errno); close(cli_fd(cptr)); cli_fd(cptr) = -1; return 0; } if (!socket_add(&(cli_socket(cptr)), client_sock_callback, (void*) cli_connect(cptr), (result == IO_SUCCESS) ? SS_CONNECTED : SS_CONNECTING, SOCK_EVENT_READABLE, cli_fd(cptr))) { cli_error(cptr) = ENFILE; report_error(REGISTER_ERROR_MSG, cli_name(cptr), ENFILE); close(cli_fd(cptr)); cli_fd(cptr) = -1; return 0; } cli_freeflag(cptr) |= FREEFLAG_SOCKET; return 1; }