#include "s_misc.h"
#include "s_user.h"
#include "send.h"
+#include "ssl.h"
#include "struct.h"
#include "sys.h"
#include "uping.h"
#include <sys/utsname.h>
#include <unistd.h>
-#ifdef USE_POLL
-#include <sys/poll.h>
-#endif /* USE_POLL */
-
/** Array of my own clients, indexed by file descriptor. */
struct Client* LocalClientArray[MAXCONNECTIONS];
/** Maximum file descriptor in current use. */
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
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;
}
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",
{
const struct irc_sockaddr *local;
IOResult result;
+ int family = 0;
+
assert(0 != aconf);
assert(0 != 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;
/*
* 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) {
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,
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;
}
{
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);
* @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;
* 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,
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;
*/
os_disable_options(fd);
- if (listener->server)
+ if (listener_server(listener))
{
new_client = make_client(0, STAT_UNKNOWN_SERVER);
}
++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
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:
return 0;
}
}
-
+
/*
* For server connections, we process as many as we can without
* worrying about the time of day or anything :)
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;
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()