static void accept_connection(int pfd, void *data) { static time_t last_oper_notice = 0; struct irc_sockaddr sai; struct irc_inaddr addr; int fd; int pe; struct Listener * listener = data; assert(listener != NULL); if(listener == NULL) return; /* * There may be many reasons for error return, but * in otherwise correctly working environment the * probable cause is running out of file descriptors * (EMFILE, ENFILE or others?). The man pages for * accept don't seem to list these as possible, * although it's obvious that it may happen here. * Thus no specific errors are tested at this * point, just assume that connections cannot * be accepted until some old is closed first. */ fd = comm_accept(listener->fd, &sai); copy_s_addr(IN_ADDR(addr), S_ADDR(sai)); #ifdef IPV6 if((IN6_IS_ADDR_V4MAPPED(&IN_ADDR2(addr))) || (IN6_IS_ADDR_V4COMPAT(&IN_ADDR2(addr)))) { memmove(&addr.sins.sin.s_addr, addr.sins.sin6.s6_addr+12, sizeof(struct in_addr)); sai.sins.sin.sin_family = AF_INET; } #endif if (fd < 0) { /* Re-register a new IO request for the next accept .. */ comm_setselect(listener->fd, FDLIST_SERVICE, COMM_SELECT_READ, accept_connection, listener, 0); return; } /* * check for connection limit */ if ((MAXCONNECTIONS - 10) < fd) { ++ServerStats->is_ref; /* * slow down the whining to opers bit */ if((last_oper_notice + 20) <= CurrentTime) { sendto_realops_flags(UMODE_ALL, L_ALL,"All connections in use. (%s)", get_listener_name(listener)); last_oper_notice = CurrentTime; } send(fd, "ERROR :All connections in use\r\n", 32, 0); fd_close(fd); /* Re-register a new IO request for the next accept .. */ comm_setselect(listener->fd, FDLIST_SERVICE, COMM_SELECT_READ, accept_connection, listener, 0); return; } /* Do an initial check we aren't connecting too fast or with too many * from this IP... */ if ((pe = conf_connect_allowed(&addr, sai.sins.sin.sin_family)) != 0) { ServerStats->is_ref++; /* XXX - this can only be BANNED_CLIENT? */ switch (pe) { case BANNED_CLIENT: send(fd, DLINE_WARNING, sizeof(DLINE_WARNING)-1, 0); break; } fd_close(fd); /* Re-register a new IO request for the next accept .. */ comm_setselect(listener->fd, FDLIST_SERVICE, COMM_SELECT_READ, accept_connection, listener, 0); return; } ServerStats->is_ac++; add_connection(listener, fd); /* Re-register a new IO request for the next accept .. */ comm_setselect(listener->fd, FDLIST_SERVICE, COMM_SELECT_READ, accept_connection, listener, 0); }
static void accept_connection(int pfd, void *data) { static time_t last_oper_notice = 0; struct irc_sockaddr_storage sai; socklen_t addrlen = sizeof(sai); int fd; struct Listener *listener = data; struct ConfItem *aconf; char buf[BUFSIZE]; s_assert(listener != NULL); if(listener == NULL) return; for(;;) /* loop until something breaks us out */ { /* * There may be many reasons for error return, but * in otherwise correctly working environment the * probable cause is running out of file descriptors * (EMFILE, ENFILE or others?). The man pages for * accept don't seem to list these as possible, * although it's obvious that it may happen here. * Thus no specific errors are tested at this * point, just assume that connections cannot * be accepted until some old is closed first. */ fd = comm_accept(listener->fd, (struct sockaddr *) &sai, &addrlen); /* This needs to be done here, otherwise we break dlines */ mangle_mapped_sockaddr((struct sockaddr *) &sai); if(fd < 0) { /* Re-register a new IO request for the next accept .. */ comm_setselect(listener->fd, FDLIST_SERVICE, COMM_SELECT_READ, accept_connection, listener); return; } /* * check for connection limit */ if((maxconnections - 10) < fd) { ++ServerStats->is_ref; /* * slow down the whining to opers bit */ if((last_oper_notice + 20) <= CurrentTime) { sendto_realops_flags(UMODE_ALL, L_ALL, "All connections in use. (%s)", get_listener_name(listener)); last_oper_notice = CurrentTime; } write(fd, "ERROR :All connections in use\r\n", 32); comm_close(fd); /* Re-register a new IO request for the next accept .. */ comm_setselect(listener->fd, FDLIST_SERVICE, COMM_SELECT_READ, accept_connection, listener); return; } /* Do an initial check we aren't connecting too fast or with too many * from this IP... */ if((aconf = conf_connect_allowed((struct sockaddr *) &sai, sai.ss_family)) != NULL) { ServerStats->is_ref++; if(ConfigFileEntry.dline_with_reason) { if(ircsnprintf (buf, sizeof(buf), "ERROR :*** Banned: %s\r\n", aconf->passwd) >= (sizeof(buf) - 1)) { buf[sizeof(buf) - 3] = '\r'; buf[sizeof(buf) - 2] = '\n'; buf[sizeof(buf) - 1] = '\0'; } } else ircsprintf(buf, "ERROR :You have been D-lined.\r\n"); write(fd, buf, strlen(buf)); comm_close(fd); /* Re-register a new IO request for the next accept .. */ comm_setselect(listener->fd, FDLIST_SERVICE, COMM_SELECT_READ, accept_connection, listener); return; } ServerStats->is_ac++; add_connection(listener, fd, (struct sockaddr *) &sai); } /* Re-register a new IO request for the next accept .. */ comm_setselect(listener->fd, FDLIST_SERVICE, COMM_SELECT_READ, accept_connection, listener); }
void accept_connection(struct Listener* listener) { static time_t last_oper_notice = 0; struct SOCKADDR_IN addr; socklen_t addrlen = sizeof(struct SOCKADDR_IN); int fd; assert(0 != listener); listener->last_accept = CurrentTime; /* * There may be many reasons for error return, but * in otherwise correctly working environment the * probable cause is running out of file descriptors * (EMFILE, ENFILE or others?). The man pages for * accept don't seem to list these as possible, * although it's obvious that it may happen here. * Thus no specific errors are tested at this * point, just assume that connections cannot * be accepted until some old is closed first. */ if (-1 == (fd = accept(listener->fd, (struct sockaddr*) &addr, &addrlen))) { if (EAGAIN == errno) return; /* * slow down the whining to opers bit */ if((last_oper_notice + 20) <= CurrentTime) { report_error("Error accepting connection %s:%s", listener->name, errno); last_oper_notice = CurrentTime; } return; } /* * check for connection limit */ if ((MAXCONNECTIONS - 10) < fd) { ++ServerStats->is_ref; /* * slow down the whining to opers bit */ if((last_oper_notice + 20) <= CurrentTime) { sendto_realops("All connections in use. (%s)", get_listener_name(listener)); last_oper_notice = CurrentTime; } send(fd, "ERROR :All connections in use\r\n", 32, 0); CLOSE(fd); return; } /* * check to see if listener is shutting down */ if (!listener->active) { ++ServerStats->is_ref; send(fd, "ERROR :Use another port\r\n", 25, 0); CLOSE(fd); return; } /* * check conf for ip address access */ if (!conf_connect_allowed(addr.SIN_ADDR)) { ServerStats->is_ref++; #ifdef REPORT_DLINE_TO_USER send(fd, "NOTICE DLINE :*** You have been D-lined\r\n", 41, 0); #endif CLOSE(fd); return; } ServerStats->is_ac++; nextping = CurrentTime; add_connection(listener, fd); }