X-Git-Url: http://git.pk910.de/?a=blobdiff_plain;f=ircd%2Fs_bsd.c;h=5fd6d9193eb1ed0e1d55fd2727754abfcb05ee4a;hb=7fbfc390d32f9acc3192d011b813f66f35370faa;hp=63a0228517e68d5f3c18a87fe4f2c9062b8d9312;hpb=cc48e03d9c68fcdd305ca35065468be8bbc9b5c1;p=ircu2.10.12-pk.git diff --git a/ircd/s_bsd.c b/ircd/s_bsd.c index 63a0228..5fd6d91 100644 --- a/ircd/s_bsd.c +++ b/ircd/s_bsd.c @@ -53,6 +53,7 @@ #include "s_misc.h" #include "s_user.h" #include "send.h" +#include "ssl.h" #include "struct.h" #include "sys.h" #include "uping.h" @@ -71,10 +72,6 @@ #include #include -#ifdef USE_POLL -#include -#endif /* USE_POLL */ - /** Array of my own clients, indexed by file descriptor. */ struct Client* LocalClientArray[MAXCONNECTIONS]; /** Maximum file descriptor in current use. */ @@ -108,24 +105,6 @@ const char* const TOS_ERROR_MSG = "error setting TOS for %s: %s"; static void client_sock_callback(struct Event* ev); static void client_timer_callback(struct Event* ev); -#if !defined(USE_POLL) -#if FD_SETSIZE < (MAXCONNECTIONS + 4) -/* - * Sanity check - * - * All operating systems work when MAXCONNECTIONS <= 252. - * Most operating systems work when MAXCONNECTIONS <= 1020 and FD_SETSIZE is - * updated correctly in the system headers (on BSD systems our sys.h has - * defined FD_SETSIZE to MAXCONNECTIONS+4 before including the system's headers - * but sys/types.h might have abruptly redefined it so the check is still - * done), you might already need to recompile your kernel. - * For larger FD_SETSIZE your mileage may vary (kernel patches may be needed). - * The check is _NOT_ done if we will not use FD_SETS at all (USE_POLL) - */ -#error "FD_SETSIZE is too small or MAXCONNECTIONS too large." -#endif -#endif - /* * Cannot use perror() within daemon. stderr is closed in @@ -154,13 +133,7 @@ void report_error(const char* text, const char* who, int err) if (EmptyString(who)) who = "unknown"; - if (last_notice + 20 < CurrentTime) { - /* - * pace error messages so opers don't get flooded by transients - */ - sendto_opmask_butone(0, SNO_OLDSNO, text, who, errmsg); - last_notice = CurrentTime; - } + sendto_opmask_butone_ratelimited(0, SNO_OLDSNO, &last_notice, text, who, errmsg); log_write(LS_SOCKET, L_ERROR, 0, text, who, errmsg); errno = errtmp; } @@ -172,14 +145,13 @@ void report_error(const char* text, const char* who, int err) * @param vptr The struct ConfItem representing the Connect block. * @param hp A pointer to the DNS lookup results (NULL on failure). */ -static void connect_dns_callback(void* vptr, struct DNSReply* hp) +static void connect_dns_callback(void* vptr, const struct irc_in_addr *addr, const char *h_name) { struct ConfItem* aconf = (struct ConfItem*) vptr; assert(aconf); aconf->dns_pending = 0; - if (hp) { - memcpy(&aconf->address, &hp->addr, sizeof(aconf->address)); - MyFree(hp); + if (addr) { + memcpy(&aconf->address, addr, sizeof(aconf->address)); connect_server(aconf, 0); } else @@ -211,7 +183,7 @@ int init_connection_limits(void) if (0 == limit) return 1; if (limit < 0) { - fprintf(stderr, "error setting max fd's to %d\n", limit); + fprintf(stderr, "error setting max fds to %d: %s\n", limit, strerror(errno)); } else if (limit > 0) { fprintf(stderr, "ircd fd table too big\nHard Limit: %d IRC max: %d\n", @@ -230,6 +202,8 @@ 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); /* @@ -238,11 +212,12 @@ static int connect_inet(struct ConfItem* aconf, struct Client* cptr) */ if (irc_in_addr_valid(&aconf->origin.addr)) local = &aconf->origin; - else if (irc_in_addr_is_ipv4(&aconf->address.addr)) + else if (irc_in_addr_is_ipv4(&aconf->address.addr)) { local = &VirtualHost_v4; - else + family = AF_INET; + } else local = &VirtualHost_v6; - cli_fd(cptr) = os_socket(local, SOCK_STREAM, cli_name(cptr)); + cli_fd(cptr) = os_socket(local, SOCK_STREAM, cli_name(cptr), family); if (cli_fd(cptr) < 0) return 0; @@ -264,7 +239,7 @@ static int connect_inet(struct ConfItem* aconf, struct Client* cptr) /* * Set the TOS bits - this is nonfatal if it doesn't stick. */ - if (!os_set_tos(cli_fd(cptr), FEAT_TOS_SERVER)) { + 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) { @@ -274,6 +249,7 @@ static int connect_inet(struct ConfItem* aconf, struct Client* 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, @@ -284,6 +260,21 @@ static int connect_inet(struct ConfItem* aconf, struct Client* cptr) cli_fd(cptr) = -1; return 0; } + + if(aconf->usessl) { + struct SSLConnection *ssl = ssl_create_connect(cli_fd(cptr), cptr, SSLData_Client); + cli_connect(cptr)->con_ssl = ssl; + if(ssl_handshake(ssl)) { + unsigned int events = 0; + if(ssl_wantread(ssl)) + events |= SOCK_EVENT_READABLE; + if(ssl_wantwrite(ssl)) + events |= SOCK_EVENT_WRITABLE; + socket_events(&(cli_socket(cptr)), SOCK_ACTION_SET | events); + result = IO_BLOCKED; + } + } + cli_freeflag(cptr) |= FREEFLAG_SOCKET; return 1; } @@ -300,9 +291,16 @@ unsigned int deliver_it(struct Client *cptr, struct MsgQ *buf) { unsigned int bytes_written = 0; unsigned int bytes_count = 0; + IOResult result; assert(0 != cptr); - switch (os_sendv_nonb(cli_fd(cptr), buf, &bytes_count, &bytes_written)) { + if(cli_connect(cptr)->con_ssl) { + result = ssl_send_encrypt(cli_connect(cptr)->con_ssl, buf, &bytes_count, &bytes_written); + } else { + result = os_sendv_nonb(cli_fd(cptr), buf, &bytes_count, &bytes_written); + } + + switch (result) { case IO_SUCCESS: ClrFlag(cptr, FLAG_BLOCKED); @@ -323,27 +321,12 @@ unsigned int deliver_it(struct Client *cptr, struct MsgQ *buf) return bytes_written; } -/** Free the client's DNS reply, if any. - * @param cptr Client to operate on. - */ -void release_dns_reply(struct Client* cptr) -{ - assert(0 != cptr); - assert(MyConnect(cptr)); - - if (cli_dns_reply(cptr)) { - MyFree(cli_dns_reply(cptr)->h_name); - MyFree(cli_dns_reply(cptr)); - cli_dns_reply(cptr) = 0; - } -} - /** Complete non-blocking connect()-sequence. Check access and * terminate connection, if trouble detected. * @param cptr Client to which we have connected, with all ConfItem structs attached. * @return Zero on failure (caller should exit_client()), non-zero on success. */ -static int completed_connection(struct Client* cptr) +int completed_connection(struct Client* cptr) { struct ConfItem *aconf; time_t newts; @@ -393,7 +376,7 @@ static int completed_connection(struct Client* cptr) * Make us timeout after twice the timeout for DNS look ups */ cli_lasttime(cptr) = CurrentTime; - SetFlag(cptr, FLAG_PINGSENT); + ClearPingSent(cptr); sendrawto_one(cptr, MSG_SERVER " %s 1 %Tu %Tu J%s %s%s +%s6 :%s", cli_name(&me), cli_serv(&me)->timestamp, newts, @@ -444,6 +427,11 @@ void close_connection(struct Client *cptr) else ServerStats->is_ni++; + if(cli_connect(cptr)->con_ssl) { + ssl_free_connection(cli_connect(cptr)->con_ssl); + cli_connect(cptr)->con_ssl = NULL; + } + if (-1 < cli_fd(cptr)) { flush_connections(cptr); LocalClientArray[cli_fd(cptr)] = 0; @@ -534,27 +522,32 @@ void add_connection(struct Listener* listener, int fd) { */ os_disable_options(fd); - /* - * Add this local client to the IPcheck registry. - * - * If they're throttled, murder them, but tell them why first. - */ - if (!IPcheck_local_connect(&addr.addr, &next_target) && !listener->server) + if (listener_server(listener)) { - ++ServerStats->is_ref; - write(fd, throttle_message, strlen(throttle_message)); - close(fd); - return; + new_client = make_client(0, STAT_UNKNOWN_SERVER); + } + else + { + /* + * Add this local client to the IPcheck registry. + * + * If they're throttled, murder them, but tell them why first. + */ + if (!IPcheck_local_connect(&addr.addr, &next_target)) + { + ++ServerStats->is_ref; + write(fd, throttle_message, strlen(throttle_message)); + close(fd); + return; + } + new_client = make_client(0, STAT_UNKNOWN_USER); + SetIPChecked(new_client); } - - new_client = make_client(0, ((listener->server) ? - STAT_UNKNOWN_SERVER : STAT_UNKNOWN_USER)); /* * Copy ascii address to 'sockhost' just in case. Then we have something * valid to put into error messages... */ - SetIPChecked(new_client); ircd_ntoa_r(cli_sock_ip(new_client), &addr.addr); strcpy(cli_sockhost(new_client), cli_sock_ip(new_client)); memcpy(&cli_ip(new_client), &addr.addr, sizeof(cli_ip(new_client))); @@ -576,8 +569,20 @@ void add_connection(struct Listener* listener, int fd) { ++listener->ref_count; Count_newunknown(UserStats); - /* if we've made it this far we can put the client on the auth query pile */ - start_auth(new_client); + + if(listener_ssl(listener)) { + struct Connection* con = cli_connect(new_client); + con->con_ssl = ssl_start_handshake_listener(listener->ssl_listener, fd, new_client, SSLData_Client); + unsigned int events = 0; + if(ssl_wantread(con->con_ssl)) + events |= SOCK_EVENT_READABLE; + if(ssl_wantwrite(con->con_ssl)) + events |= SOCK_EVENT_WRITABLE; + socket_events(&(cli_socket(new_client)), SOCK_ACTION_SET | events); + } else { + /* if we've made it this far we can put the client on the auth query pile */ + start_auth(new_client); + } } /** Determines whether to tell the events engine we're interested in @@ -613,16 +618,24 @@ static int read_packet(struct Client *cptr, int socket_ready) if (socket_ready && !(IsUser(cptr) && DBufLength(&(cli_recvQ(cptr))) > feature_int(FEAT_CLIENT_FLOOD))) { - switch (os_recv_nonb(cli_fd(cptr), readbuf, sizeof(readbuf), &length)) { + + /* Handle SSL Sockets + */ + int recvret; + if(cli_connect(cptr)->con_ssl) { + recvret = ssl_recv_decrypt(cli_connect(cptr)->con_ssl, readbuf, sizeof(readbuf), &length); + } else { + recvret = os_recv_nonb(cli_fd(cptr), readbuf, sizeof(readbuf), &length); + } + switch (recvret) { case IO_SUCCESS: if (length) { - if (!IsServer(cptr)) - cli_lasttime(cptr) = CurrentTime; + cli_lasttime(cptr) = CurrentTime; + ClearPingSent(cptr); + ClrFlag(cptr, FLAG_NONL); if (cli_lasttime(cptr) > cli_since(cptr)) cli_since(cptr) = cli_lasttime(cptr); - ClrFlag(cptr, FLAG_PINGSENT); - ClrFlag(cptr, FLAG_NONL); } break; case IO_BLOCKED: @@ -633,7 +646,7 @@ static int read_packet(struct Client *cptr, int socket_ready) return 0; } } - + /* * For server connections, we process as many as we can without * worrying about the time of day or anything :) @@ -672,7 +685,13 @@ static int read_packet(struct Client *cptr, int socket_ready) if (DBufLength(&(cli_recvQ(cptr))) < 510) SetFlag(cptr, FLAG_NONL); else + { + /* More than 512 bytes in the line - drop the input and yell + * at the client. + */ DBufClear(&(cli_recvQ(cptr))); + send_reply(cptr, ERR_INPUTTOOLONG); + } } else if (client_dopacket(cptr, dolen) == CPTR_KILLED) return CPTR_KILLED; @@ -759,14 +778,9 @@ int connect_server(struct ConfItem* aconf, struct Client* by) if (!irc_in_addr_valid(&aconf->address.addr) && !ircd_aton(&aconf->address.addr, aconf->host)) { char buf[HOSTLEN + 1]; - struct DNSQuery query; - query.vptr = aconf; - query.callback = connect_dns_callback; host_from_uh(buf, aconf->host, HOSTLEN); - buf[HOSTLEN] = '\0'; - - gethost_byname(buf, &query); + gethost_byname(buf, connect_dns_callback, aconf); aconf->dns_pending = 1; return 0; } @@ -786,10 +800,10 @@ int connect_server(struct ConfItem* aconf, struct Client* by) if (!find_conf_byhost(cli_confs(cptr), aconf->host, CONF_SERVER)) { sendto_opmask_butone(0, SNO_OLDSNO, "Host %s is not enabled for " - "connecting: no C-line", aconf->name); + "connecting: no Connect block", aconf->name); if (by && IsUser(by) && !MyUser(by)) { sendcmdto_one(&me, CMD_NOTICE, by, "%C :Connect to host %s failed: no " - "C-line", by, aconf->name); + "Connect block", by, aconf->name); } det_confs_butmask(cptr, 0); free_client(cptr); @@ -891,13 +905,21 @@ static void client_sock_callback(struct Event* ev) break; case ET_CONNECT: /* socket connection completed */ - if (!completed_connection(cptr) || IsDead(cptr)) + if(cli_connect(cptr)->con_ssl) { + ssl_start_handshake_connect(cli_connect(cptr)->con_ssl); + } + else if (!completed_connection(cptr) || IsDead(cptr)) fallback = cli_info(cptr); break; case ET_ERROR: /* an error occurred */ fallback = cli_info(cptr); cli_error(cptr) = ev_data(ev); + /* If the OS told us we have a bad file descriptor, we should + * record that for future reference. + */ + if (cli_error(cptr) == EBADF) + cli_fd(cptr) = -1; if (s_state(&(con_socket(con))) == SS_CONNECTING) { completed_connection(cptr); /* for some reason, the os_get_sockerr() in completed_connect()