| 1 |
|
/* |
| 2 |
|
* Copyright (c) 2002-2003 Erik Fears |
| 3 |
< |
* Copyright (c) 2014-2017 ircd-hybrid development team |
| 3 |
> |
* Copyright (c) 2014-2020 ircd-hybrid development team |
| 4 |
|
* |
| 5 |
|
* This program is free software; you can redistribute it and/or modify |
| 6 |
|
* it under the terms of the GNU General Public License as published by |
| 30 |
|
#include <netinet/in.h> |
| 31 |
|
#include <arpa/inet.h> |
| 32 |
|
#include <poll.h> |
| 33 |
– |
#include <sys/time.h> |
| 33 |
|
#include <time.h> |
| 35 |
– |
|
| 34 |
|
#include <errno.h> |
| 35 |
|
#include <stdarg.h> |
| 36 |
|
#include <regex.h> |
| 37 |
|
#include <assert.h> |
| 38 |
+ |
#ifdef HAVE_LIBCRYPTO |
| 39 |
+ |
#include <openssl/ssl.h> |
| 40 |
+ |
#include <openssl/x509v3.h> |
| 41 |
+ |
#include <openssl/err.h> |
| 42 |
+ |
#endif |
| 43 |
|
|
| 44 |
|
#include "config.h" |
| 45 |
|
#include "irc.h" |
| 54 |
|
#include "negcache.h" |
| 55 |
|
#include "memory.h" |
| 56 |
|
#include "main.h" |
| 54 |
– |
#include "serno.h" |
| 57 |
|
|
| 58 |
|
|
| 59 |
|
/* |
| 65 |
|
static int IRC_FD = -1; /* File descriptor for IRC client */ |
| 66 |
|
|
| 67 |
|
static struct sockaddr_storage IRC_SVR; /* Sock Address Struct for IRC server */ |
| 68 |
< |
static socklen_t svr_addrlen; |
| 68 |
> |
static socklen_t IRC_SVR_LEN; |
| 69 |
> |
static char IRC_SVR_STR[INET6_ADDRSTRLEN]; |
| 70 |
|
static time_t IRC_LAST; /* Last full line of data from irc server */ |
| 71 |
|
static time_t IRC_LASTRECONNECT; /* Time of last reconnection */ |
| 72 |
|
|
| 73 |
+ |
#ifdef HAVE_LIBCRYPTO |
| 74 |
+ |
static SSL_CTX *ssl_ctx; |
| 75 |
+ |
static SSL *ssl_handle; |
| 76 |
+ |
#endif |
| 77 |
+ |
|
| 78 |
|
|
| 79 |
|
/* get_channel |
| 80 |
|
* |
| 91 |
|
{ |
| 92 |
|
node_t *node; |
| 93 |
|
|
| 94 |
< |
LIST_FOREACH(node, IRCItem->channels->head) |
| 94 |
> |
LIST_FOREACH(node, IRCItem.channels.head) |
| 95 |
|
{ |
| 96 |
|
struct ChannelConf *item = node->data; |
| 97 |
|
|
| 119 |
|
{ |
| 120 |
|
node_t *node; |
| 121 |
|
|
| 122 |
< |
log_printf("IRC -> Connected to %s/%d", IRCItem->server, IRCItem->port); |
| 122 |
> |
log_printf("IRC -> Connected to %s[%s]:%i", IRC_SVR_STR, IRCItem.server, IRCItem.port); |
| 123 |
|
|
| 124 |
|
/* Identify to nickserv if needed */ |
| 125 |
< |
if (!EmptyString(IRCItem->nickserv)) |
| 126 |
< |
irc_send("%s", IRCItem->nickserv); |
| 125 |
> |
if (!EmptyString(IRCItem.nickserv)) |
| 126 |
> |
irc_send("%s", IRCItem.nickserv); |
| 127 |
|
|
| 128 |
|
/* Oper */ |
| 129 |
< |
irc_send("OPER %s", IRCItem->oper); |
| 129 |
> |
if (!EmptyString(IRCItem.oper)) |
| 130 |
> |
irc_send("OPER %s", IRCItem.oper); |
| 131 |
|
|
| 132 |
|
/* Set modes */ |
| 133 |
< |
irc_send("MODE %s %s", IRCItem->nick, IRCItem->mode); |
| 133 |
> |
if (!EmptyString(IRCItem.mode)) |
| 134 |
> |
irc_send("MODE %s %s", IRCItem.nick, IRCItem.mode); |
| 135 |
|
|
| 136 |
|
/* Set Away */ |
| 137 |
< |
if (!EmptyString(IRCItem->away)) |
| 138 |
< |
irc_send("AWAY :%s", IRCItem->away); |
| 137 |
> |
if (!EmptyString(IRCItem.away)) |
| 138 |
> |
irc_send("AWAY :%s", IRCItem.away); |
| 139 |
|
|
| 140 |
|
/* Perform */ |
| 141 |
< |
LIST_FOREACH(node, IRCItem->performs->head) |
| 141 |
> |
LIST_FOREACH(node, IRCItem.performs.head) |
| 142 |
|
irc_send("%s", node->data); |
| 143 |
|
|
| 144 |
|
/* Join all listed channels. */ |
| 145 |
< |
LIST_FOREACH(node, IRCItem->channels->head) |
| 145 |
> |
LIST_FOREACH(node, IRCItem.channels.head) |
| 146 |
|
{ |
| 147 |
|
const struct ChannelConf *channel = node->data; |
| 148 |
|
|
| 190 |
|
static void |
| 191 |
|
m_invite(char *parv[], unsigned int parc, const char *msg, const char *source_p) |
| 192 |
|
{ |
| 183 |
– |
const struct ChannelConf *channel = NULL; |
| 184 |
– |
|
| 193 |
|
if (parc < 4) |
| 194 |
|
return; |
| 195 |
|
|
| 196 |
|
log_printf("IRC -> Invited to %s by %s", parv[3], parv[0]); |
| 197 |
|
|
| 198 |
< |
if ((channel = get_channel(parv[3])) == NULL) |
| 198 |
> |
const struct ChannelConf *channel = get_channel(parv[3]); |
| 199 |
> |
if (channel == NULL) |
| 200 |
|
return; |
| 201 |
|
|
| 202 |
|
irc_send("JOIN %s %s", channel->name, channel->key); |
| 215 |
|
m_ctcp(char *parv[], unsigned int parc, const char *msg, const char *source_p) |
| 216 |
|
{ |
| 217 |
|
if (strncasecmp(parv[3], "\001VERSION\001", 9) == 0) |
| 218 |
< |
irc_send("NOTICE %s :\001VERSION Hybrid Open Proxy Monitor %s(%s)\001", |
| 219 |
< |
source_p, VERSION, SERIALNUM); |
| 218 |
> |
irc_send("NOTICE %s :\001VERSION Hybrid Open Proxy Monitor %s\001", |
| 219 |
> |
source_p, VERSION); |
| 220 |
|
} |
| 221 |
|
|
| 222 |
|
/* m_privmsg |
| 232 |
|
static void |
| 233 |
|
m_privmsg(char *parv[], unsigned int parc, const char *msg, const char *source_p) |
| 234 |
|
{ |
| 226 |
– |
const struct ChannelConf *channel = NULL; |
| 227 |
– |
|
| 235 |
|
if (source_p == NULL) |
| 236 |
|
return; |
| 237 |
|
|
| 250 |
|
return; |
| 251 |
|
|
| 252 |
|
/* Get a target */ |
| 253 |
< |
if ((channel = get_channel(parv[2])) == NULL) |
| 253 |
> |
const struct ChannelConf *channel = get_channel(parv[2]); |
| 254 |
> |
if (channel == NULL) |
| 255 |
|
return; |
| 256 |
|
|
| 257 |
|
int hit = strncasecmp(parv[3], "!all ", 5) == 0; |
| 258 |
|
if (hit == 0) |
| 259 |
|
{ |
| 260 |
< |
size_t nick_len = strlen(IRCItem->nick); |
| 260 |
> |
size_t nick_len = strlen(IRCItem.nick); |
| 261 |
|
|
| 262 |
< |
if (strncasecmp(parv[3], IRCItem->nick, nick_len) == 0) |
| 263 |
< |
hit = *(parv[3] + nick_len) == ' '; |
| 262 |
> |
if (strncasecmp(parv[3], IRCItem.nick, nick_len) == 0) |
| 263 |
> |
hit = *(parv[3] + nick_len) == ' ' || |
| 264 |
> |
*(parv[3] + nick_len) == ',' || |
| 265 |
> |
*(parv[3] + nick_len) == ':'; |
| 266 |
|
} |
| 267 |
|
|
| 268 |
|
if (hit) |
| 269 |
|
/* XXX command_parse will alter parv[3]. */ |
| 270 |
< |
command_parse(parv[3], channel, source_p); |
| 270 |
> |
command_parse(parv[3], channel->name, source_p); |
| 271 |
|
} |
| 272 |
|
|
| 273 |
|
/* m_notice |
| 302 |
|
{ |
| 303 |
|
preg = xcalloc(sizeof(*preg)); |
| 304 |
|
|
| 305 |
< |
if ((errnum = regcomp(preg, IRCItem->connregex, REG_ICASE | REG_EXTENDED))) |
| 305 |
> |
if ((errnum = regcomp(preg, IRCItem.connregex, REG_ICASE | REG_EXTENDED))) |
| 306 |
|
{ |
| 307 |
|
char errmsg[256]; |
| 308 |
|
|
| 346 |
|
log_printf("IRC REGEX -> Parsed %s!%s@%s [%s] from connection notice.", |
| 347 |
|
user[0], user[1], user[2], user[3]); |
| 348 |
|
|
| 349 |
< |
LIST_FOREACH(node, IRCItem->notices->head) |
| 349 |
> |
LIST_FOREACH(node, IRCItem.notices.head) |
| 350 |
|
irc_send("NOTICE %s :%s", user[0], node->data); |
| 351 |
|
|
| 352 |
|
/* Pass this information off to scan.c */ |
| 387 |
|
static void |
| 388 |
|
m_cannot_join(char *parv[], unsigned int parc, const char *msg, const char *source_p) |
| 389 |
|
{ |
| 380 |
– |
const struct ChannelConf *channel = NULL; |
| 381 |
– |
|
| 390 |
|
if (parc < 5) |
| 391 |
|
return; |
| 392 |
|
|
| 393 |
|
/* Is it one of our channels? */ |
| 394 |
< |
if ((channel = get_channel(parv[3])) == NULL) |
| 394 |
> |
const struct ChannelConf *channel = get_channel(parv[3]); |
| 395 |
> |
if (channel == NULL) |
| 396 |
|
return; |
| 397 |
|
|
| 398 |
|
if (EmptyString(channel->invite)) |
| 470 |
|
static void |
| 471 |
|
irc_init(void) |
| 472 |
|
{ |
| 473 |
< |
const void *address = NULL; |
| 473 |
> |
int n; |
| 474 |
> |
const void *address; |
| 475 |
> |
struct addrinfo hints, *res = NULL; |
| 476 |
|
|
| 477 |
|
assert(IRC_FD == -1); |
| 478 |
|
|
| 479 |
|
memset(&IRC_SVR, 0, sizeof(IRC_SVR)); |
| 480 |
|
|
| 481 |
+ |
if (!EmptyString(IRCItem.bind)) |
| 482 |
+ |
{ |
| 483 |
+ |
memset(&hints, 0, sizeof(hints)); |
| 484 |
+ |
|
| 485 |
+ |
hints.ai_family = AF_UNSPEC; |
| 486 |
+ |
hints.ai_socktype = SOCK_STREAM; |
| 487 |
+ |
hints.ai_flags = AI_NUMERICHOST; |
| 488 |
+ |
|
| 489 |
+ |
n = getaddrinfo(IRCItem.bind, NULL, &hints, &res); |
| 490 |
+ |
if (n) |
| 491 |
+ |
{ |
| 492 |
+ |
log_printf("IRC -> getaddrinfo() error: %s", gai_strerror(n)); |
| 493 |
+ |
exit(EXIT_FAILURE); |
| 494 |
+ |
} |
| 495 |
+ |
} |
| 496 |
+ |
|
| 497 |
|
/* Resolve IRC host. */ |
| 498 |
< |
if ((address = firedns_resolveip6(IRCItem->server))) |
| 498 |
> |
if ((res == NULL || res->ai_family == AF_INET6) && (address = firedns_resolveip6(IRCItem.server))) |
| 499 |
|
{ |
| 500 |
|
struct sockaddr_in6 *in = (struct sockaddr_in6 *)&IRC_SVR; |
| 501 |
|
|
| 502 |
< |
svr_addrlen = sizeof(*in); |
| 502 |
> |
IRC_SVR_LEN = sizeof(*in); |
| 503 |
|
IRC_SVR.ss_family = AF_INET6; |
| 504 |
< |
in->sin6_port = htons(IRCItem->port); |
| 504 |
> |
in->sin6_port = htons(IRCItem.port); |
| 505 |
|
memcpy(&in->sin6_addr, address, sizeof(in->sin6_addr)); |
| 506 |
|
} |
| 507 |
< |
else if ((address = firedns_resolveip4(IRCItem->server))) |
| 507 |
> |
else if ((res == NULL || res->ai_family == AF_INET) && (address = firedns_resolveip4(IRCItem.server))) |
| 508 |
|
{ |
| 509 |
|
struct sockaddr_in *in = (struct sockaddr_in *)&IRC_SVR; |
| 510 |
|
|
| 511 |
< |
svr_addrlen = sizeof(*in); |
| 511 |
> |
IRC_SVR_LEN = sizeof(*in); |
| 512 |
|
IRC_SVR.ss_family = AF_INET; |
| 513 |
< |
in->sin_port = htons(IRCItem->port); |
| 513 |
> |
in->sin_port = htons(IRCItem.port); |
| 514 |
|
memcpy(&in->sin_addr, address, sizeof(in->sin_addr)); |
| 515 |
|
} |
| 516 |
|
else |
| 517 |
|
{ |
| 518 |
< |
log_printf("IRC -> firedns_resolveip(\"%s\"): %s", IRCItem->server, |
| 518 |
> |
log_printf("IRC -> Error resolving host '%s': %s", IRCItem.server, |
| 519 |
|
firedns_strerror(firedns_errno)); |
| 520 |
|
exit(EXIT_FAILURE); |
| 521 |
|
} |
| 522 |
|
|
| 523 |
+ |
n = getnameinfo((const struct sockaddr *)&IRC_SVR, IRC_SVR_LEN, IRC_SVR_STR, |
| 524 |
+ |
sizeof(IRC_SVR_STR), NULL, 0, NI_NUMERICHOST); |
| 525 |
+ |
if (n) |
| 526 |
+ |
{ |
| 527 |
+ |
log_printf("IRC -> getnameinfo() error: %s", gai_strerror(n)); |
| 528 |
+ |
exit(EXIT_FAILURE); |
| 529 |
+ |
} |
| 530 |
+ |
|
| 531 |
|
/* Request file desc for IRC client socket */ |
| 532 |
|
IRC_FD = socket(IRC_SVR.ss_family, SOCK_STREAM, 0); |
| 533 |
|
|
| 538 |
|
} |
| 539 |
|
|
| 540 |
|
/* Bind */ |
| 541 |
< |
if (!EmptyString(IRCItem->vhost)) |
| 541 |
> |
if (res) |
| 542 |
|
{ |
| 543 |
< |
struct addrinfo hints, *res; |
| 544 |
< |
int n; |
| 545 |
< |
|
| 546 |
< |
memset(&hints, 0, sizeof(hints)); |
| 543 |
> |
if (bind(IRC_FD, res->ai_addr, res->ai_addrlen)) |
| 544 |
> |
{ |
| 545 |
> |
log_printf("IRC -> error binding to %s: %s", IRCItem.bind, strerror(errno)); |
| 546 |
> |
exit(EXIT_FAILURE); |
| 547 |
> |
} |
| 548 |
|
|
| 549 |
< |
hints.ai_family = AF_UNSPEC; |
| 550 |
< |
hints.ai_socktype = SOCK_STREAM; |
| 515 |
< |
hints.ai_flags = AI_NUMERICHOST; |
| 549 |
> |
freeaddrinfo(res); |
| 550 |
> |
} |
| 551 |
|
|
| 552 |
< |
if ((n = getaddrinfo(IRCItem->vhost, NULL, &hints, &res))) |
| 552 |
> |
if (IRCItem.tls) |
| 553 |
> |
{ |
| 554 |
> |
#ifdef HAVE_LIBCRYPTO |
| 555 |
> |
/* Initialize SSL */ |
| 556 |
> |
static int tls_init = 0; |
| 557 |
> |
if (tls_init == 0) |
| 558 |
|
{ |
| 559 |
< |
log_printf("IRC -> error binding to %s: %s", IRCItem->vhost, gai_strerror(n)); |
| 560 |
< |
exit(EXIT_FAILURE); |
| 559 |
> |
tls_init = 1; |
| 560 |
> |
|
| 561 |
> |
ssl_ctx = SSL_CTX_new(TLS_client_method()); |
| 562 |
> |
if (ssl_ctx == NULL) |
| 563 |
> |
{ |
| 564 |
> |
log_printf("IRC -> unable to create SSL context"); |
| 565 |
> |
exit(EXIT_FAILURE); |
| 566 |
> |
} |
| 567 |
> |
|
| 568 |
> |
if (!EmptyString(IRCItem.rsa_private_key_file) && |
| 569 |
> |
!EmptyString(IRCItem.tls_certificate_file)) |
| 570 |
> |
{ |
| 571 |
> |
if (SSL_CTX_use_certificate_chain_file(ssl_ctx, IRCItem.tls_certificate_file) != 1) |
| 572 |
> |
{ |
| 573 |
> |
log_printf("IRC -> couldn't load client certificate from %s: %s", |
| 574 |
> |
IRCItem.tls_certificate_file, ERR_error_string(ERR_get_error(), NULL)); |
| 575 |
> |
exit(EXIT_FAILURE); |
| 576 |
> |
} |
| 577 |
> |
|
| 578 |
> |
if (SSL_CTX_use_PrivateKey_file(ssl_ctx, IRCItem.rsa_private_key_file, SSL_FILETYPE_PEM) != 1) |
| 579 |
> |
{ |
| 580 |
> |
log_printf("IRC -> couldn't load private key from %s: %s", |
| 581 |
> |
IRCItem.rsa_private_key_file, ERR_error_string(ERR_get_error(), NULL)); |
| 582 |
> |
exit(EXIT_FAILURE); |
| 583 |
> |
} |
| 584 |
> |
|
| 585 |
> |
if (SSL_CTX_check_private_key(ssl_ctx) != 1) |
| 586 |
> |
{ |
| 587 |
> |
log_printf("IRC -> Private key does not match the client certificate: %s", |
| 588 |
> |
ERR_error_string(ERR_get_error(), NULL)); |
| 589 |
> |
exit(EXIT_FAILURE); |
| 590 |
> |
} |
| 591 |
> |
} |
| 592 |
> |
|
| 593 |
> |
SSL_CTX_set_min_proto_version(ssl_ctx, TLS1_2_VERSION); |
| 594 |
> |
SSL_CTX_set_default_verify_paths(ssl_ctx); |
| 595 |
|
} |
| 596 |
< |
else if (bind(IRC_FD, res->ai_addr, res->ai_addrlen)) |
| 596 |
> |
|
| 597 |
> |
ssl_handle = SSL_new(ssl_ctx); |
| 598 |
> |
SSL_set_fd(ssl_handle, IRC_FD); |
| 599 |
> |
|
| 600 |
> |
if (IRCItem.tls_hostname_verification) |
| 601 |
|
{ |
| 602 |
< |
log_printf("IRC -> error binding to %s: %s", IRCItem->vhost, strerror(errno)); |
| 603 |
< |
exit(EXIT_FAILURE); |
| 602 |
> |
SSL_set_hostflags(ssl_handle, X509_CHECK_FLAG_NO_PARTIAL_WILDCARDS); |
| 603 |
> |
|
| 604 |
> |
if (SSL_set1_host(ssl_handle, IRCItem.server) == 0) |
| 605 |
> |
{ |
| 606 |
> |
log_printf("IRC -> unable to set expected DNS hostname"); |
| 607 |
> |
/* OpenSSL is unable to verify the server hostname at this point, so we exit. */ |
| 608 |
> |
exit(EXIT_FAILURE); |
| 609 |
> |
} |
| 610 |
|
} |
| 611 |
|
|
| 612 |
< |
freeaddrinfo(res); |
| 612 |
> |
SSL_set_verify(ssl_handle, SSL_VERIFY_PEER, NULL); |
| 613 |
> |
#else |
| 614 |
> |
log_printf("IRC -> HOPM is not compiled with OpenSSL support"); |
| 615 |
> |
exit(EXIT_FAILURE); |
| 616 |
> |
#endif |
| 617 |
|
} |
| 618 |
|
} |
| 619 |
|
|
| 620 |
< |
/* irc_reconnect |
| 620 |
> |
/* irc_close |
| 621 |
|
* |
| 622 |
|
* Close connection to IRC server. |
| 623 |
|
* |
| 626 |
|
* Return: NONE |
| 627 |
|
*/ |
| 628 |
|
static void |
| 629 |
< |
irc_reconnect(void) |
| 629 |
> |
irc_close(void) |
| 630 |
|
{ |
| 543 |
– |
time_t present; |
| 544 |
– |
|
| 545 |
– |
time(&present); |
| 546 |
– |
|
| 547 |
– |
/* Only try to reconnect every IRCItem->reconnectinterval seconds */ |
| 548 |
– |
if ((present - IRC_LASTRECONNECT) < IRCItem->reconnectinterval) |
| 549 |
– |
{ |
| 550 |
– |
/* Sleep to avoid excessive CPU */ |
| 551 |
– |
sleep(1); |
| 552 |
– |
return; |
| 553 |
– |
} |
| 554 |
– |
|
| 555 |
– |
time(&IRC_LASTRECONNECT); |
| 556 |
– |
|
| 631 |
|
if (IRC_FD > -1) |
| 632 |
|
{ |
| 633 |
+ |
#ifdef HAVE_LIBCRYPTO |
| 634 |
+ |
if (ssl_handle) |
| 635 |
+ |
{ |
| 636 |
+ |
SSL_shutdown(ssl_handle); |
| 637 |
+ |
SSL_free(ssl_handle); |
| 638 |
+ |
ssl_handle = NULL; |
| 639 |
+ |
} |
| 640 |
+ |
#endif |
| 641 |
+ |
|
| 642 |
|
close(IRC_FD); |
| 643 |
|
IRC_FD = -1; /* Set IRC_FD -1 for reconnection on next irc_cycle(). */ |
| 644 |
|
} |
| 645 |
|
|
| 646 |
< |
log_printf("IRC -> Connection to (%s) failed, reconnecting.", IRCItem->server); |
| 646 |
> |
log_printf("IRC -> Connection to (%s) failed, reconnecting.", IRCItem.server); |
| 647 |
|
} |
| 648 |
|
|
| 649 |
|
/* irc_connect |
| 657 |
|
static void |
| 658 |
|
irc_connect(void) |
| 659 |
|
{ |
| 660 |
+ |
time_t present; |
| 661 |
+ |
|
| 662 |
+ |
time(&present); |
| 663 |
+ |
|
| 664 |
+ |
/* Only try to reconnect every IRCItem.reconnectinterval seconds */ |
| 665 |
+ |
if ((present - IRC_LASTRECONNECT) < IRCItem.reconnectinterval) |
| 666 |
+ |
{ |
| 667 |
+ |
/* Sleep to avoid excessive CPU */ |
| 668 |
+ |
sleep(1); |
| 669 |
+ |
return; |
| 670 |
+ |
} |
| 671 |
+ |
|
| 672 |
+ |
time(&IRC_LASTRECONNECT); |
| 673 |
+ |
time(&IRC_LAST); |
| 674 |
+ |
|
| 675 |
+ |
irc_init(); |
| 676 |
+ |
|
| 677 |
+ |
log_printf("IRC -> Attempting to connect to %s[%s]:%i", IRC_SVR_STR, IRCItem.server, IRCItem.port); |
| 678 |
+ |
|
| 679 |
|
/* Connect to IRC server as client. */ |
| 680 |
< |
if (connect(IRC_FD, (struct sockaddr *)&IRC_SVR, svr_addrlen) == -1) |
| 680 |
> |
if (connect(IRC_FD, (struct sockaddr *)&IRC_SVR, IRC_SVR_LEN) == -1) |
| 681 |
|
{ |
| 682 |
|
log_printf("IRC -> connect(): error connecting to %s: %s", |
| 683 |
< |
IRCItem->server, strerror(errno)); |
| 683 |
> |
IRCItem.server, strerror(errno)); |
| 684 |
|
|
| 685 |
< |
if (errno == EISCONN /* Already connected */ || errno == EALREADY /* Previous attempt not complete */) |
| 686 |
< |
return; |
| 585 |
< |
|
| 586 |
< |
/* Try to connect again */ |
| 587 |
< |
irc_reconnect(); |
| 685 |
> |
/* Close socket and try to connect again */ |
| 686 |
> |
irc_close(); |
| 687 |
|
return; |
| 688 |
|
} |
| 689 |
|
|
| 690 |
< |
irc_send("NICK %s", IRCItem->nick); |
| 690 |
> |
#ifdef HAVE_LIBCRYPTO |
| 691 |
> |
if (ssl_handle) |
| 692 |
> |
{ |
| 693 |
> |
int ret = SSL_connect(ssl_handle); |
| 694 |
> |
if (ret != 1) |
| 695 |
> |
{ |
| 696 |
> |
const char *error = ERR_error_string(ERR_get_error(), NULL); |
| 697 |
> |
log_printf("IRC -> connect(): error performing TLS handshake with %s: %s", |
| 698 |
> |
IRCItem.server, error); |
| 699 |
> |
|
| 700 |
> |
/* Close socket and try to connect again */ |
| 701 |
> |
irc_close(); |
| 702 |
> |
return; |
| 703 |
> |
} |
| 704 |
> |
} |
| 705 |
> |
#endif |
| 706 |
> |
|
| 707 |
> |
irc_send("NICK %s", IRCItem.nick); |
| 708 |
|
|
| 709 |
< |
if (!EmptyString(IRCItem->password)) |
| 710 |
< |
irc_send("PASS %s", IRCItem->password); |
| 709 |
> |
if (!EmptyString(IRCItem.password)) |
| 710 |
> |
irc_send("PASS %s", IRCItem.password); |
| 711 |
|
|
| 712 |
|
irc_send("USER %s %s %s :%s", |
| 713 |
< |
IRCItem->username, |
| 714 |
< |
IRCItem->username, |
| 715 |
< |
IRCItem->username, |
| 716 |
< |
IRCItem->realname); |
| 713 |
> |
IRCItem.username, |
| 714 |
> |
IRCItem.username, |
| 715 |
> |
IRCItem.username, |
| 716 |
> |
IRCItem.realname); |
| 717 |
|
time(&IRC_LAST); |
| 718 |
|
} |
| 719 |
|
|
| 738 |
|
* source did not exist |
| 739 |
|
*/ |
| 740 |
|
char *parv[17]; |
| 741 |
+ |
static const unsigned int parv_size = sizeof(parv) / sizeof(parv[0]); |
| 742 |
|
unsigned int parc = 1; |
| 743 |
|
char msg[MSGLENMAX]; /* Temporarily stores IRC msg to pass to handlers */ |
| 744 |
|
|
| 784 |
|
parv[0] = IRC_RAW + 1; |
| 785 |
|
else |
| 786 |
|
{ |
| 787 |
< |
parv[0] = IRCItem->server; |
| 787 |
> |
parv[0] = IRCItem.server; |
| 788 |
|
parv[parc++] = IRC_RAW; |
| 789 |
|
} |
| 790 |
|
|
| 791 |
|
pos = IRC_RAW; |
| 792 |
|
|
| 793 |
< |
while ((pos = strchr(pos, ' ')) && parc <= 17) |
| 793 |
> |
while ((pos = strchr(pos, ' ')) && parc < parv_size) |
| 794 |
|
{ |
| 795 |
|
/* Avoid excessive spaces and end of IRC_RAW */ |
| 796 |
|
if (*(pos + 1) == ' ' || *(pos + 1) == '\0') |
| 844 |
|
ssize_t len; |
| 845 |
|
char c; |
| 846 |
|
|
| 847 |
< |
while ((len = read(IRC_FD, &c, 1)) > 0) |
| 847 |
> |
while (1) |
| 848 |
|
{ |
| 849 |
+ |
#ifdef HAVE_LIBCRYPTO |
| 850 |
+ |
if (ssl_handle) |
| 851 |
+ |
len = SSL_read(ssl_handle, &c, 1); |
| 852 |
+ |
else |
| 853 |
+ |
#endif |
| 854 |
+ |
len = recv(IRC_FD, &c, 1, 0); |
| 855 |
+ |
|
| 856 |
+ |
if (len <= 0) |
| 857 |
+ |
break; |
| 858 |
+ |
|
| 859 |
|
if (c == '\r') |
| 860 |
|
continue; |
| 861 |
|
|
| 869 |
|
|
| 870 |
|
/* Reset counter. */ |
| 871 |
|
IRC_RAW_LEN = 0; |
| 872 |
< |
break; |
| 872 |
> |
return; |
| 873 |
|
} |
| 874 |
|
|
| 875 |
|
if (c != '\0') |
| 881 |
|
if (errno != EINTR) |
| 882 |
|
log_printf("IRC -> Error reading data from server: %s", strerror(errno)); |
| 883 |
|
|
| 884 |
< |
irc_reconnect(); |
| 884 |
> |
irc_close(); |
| 885 |
|
IRC_RAW_LEN = 0; |
| 759 |
– |
return; |
| 886 |
|
} |
| 887 |
|
} |
| 888 |
|
|
| 904 |
|
if (IRC_FD == -1) |
| 905 |
|
{ |
| 906 |
|
/* Initialize negative cache. */ |
| 907 |
< |
if (OptionsItem->negcache) |
| 907 |
> |
if (OptionsItem.negcache) |
| 908 |
|
negcache_init(); |
| 909 |
|
|
| 784 |
– |
/* Resolve remote host. */ |
| 785 |
– |
irc_init(); |
| 786 |
– |
|
| 910 |
|
/* Connect to remote host. */ |
| 911 |
|
irc_connect(); |
| 912 |
|
return; /* In case connect() immediately failed */ |
| 926 |
|
if (pfd.revents & POLLIN) |
| 927 |
|
irc_read(); |
| 928 |
|
else if (pfd.revents & (POLLERR | POLLHUP)) |
| 929 |
< |
irc_reconnect(); |
| 929 |
> |
irc_close(); |
| 930 |
|
|
| 931 |
|
break; |
| 932 |
|
} |
| 947 |
|
{ |
| 948 |
|
va_list arglist; |
| 949 |
|
char buf[MSGLENMAX]; |
| 827 |
– |
size_t len = 0; |
| 950 |
|
|
| 951 |
|
va_start(arglist, data); |
| 952 |
< |
len = vsnprintf(buf, sizeof(buf), data, arglist); |
| 952 |
> |
ssize_t len = vsnprintf(buf, sizeof(buf), data, arglist); |
| 953 |
|
va_end(arglist); |
| 954 |
|
|
| 955 |
|
if (OPT_DEBUG >= 2) |
| 961 |
|
buf[len++] = '\r'; |
| 962 |
|
buf[len++] = '\n'; |
| 963 |
|
|
| 964 |
< |
if (send(IRC_FD, buf, len, 0) == -1) |
| 964 |
> |
ssize_t sent; |
| 965 |
> |
#ifdef HAVE_LIBCRYPTO |
| 966 |
> |
if (ssl_handle) |
| 967 |
> |
sent = SSL_write(ssl_handle, buf, len); |
| 968 |
> |
else |
| 969 |
> |
#endif |
| 970 |
> |
sent = send(IRC_FD, buf, len, 0); |
| 971 |
> |
|
| 972 |
> |
if (sent != len) |
| 973 |
|
{ |
| 974 |
|
/* Return of -1 indicates error sending data; we reconnect. */ |
| 975 |
|
log_printf("IRC -> Error sending data to server: %s", strerror(errno)); |
| 976 |
< |
irc_reconnect(); |
| 976 |
> |
irc_close(); |
| 977 |
|
} |
| 978 |
|
} |
| 979 |
|
|
| 998 |
|
vsnprintf(buf, sizeof(buf), data, arglist); |
| 999 |
|
va_end(arglist); |
| 1000 |
|
|
| 1001 |
< |
LIST_FOREACH(node, IRCItem->channels->head) |
| 1001 |
> |
LIST_FOREACH(node, IRCItem.channels.head) |
| 1002 |
|
{ |
| 1003 |
|
const struct ChannelConf *chan = node->data; |
| 1004 |
|
|
| 1022 |
|
|
| 1023 |
|
delta = present - IRC_LAST; |
| 1024 |
|
|
| 1025 |
< |
/* No data in IRCItem->readtimeout seconds */ |
| 1026 |
< |
if (delta >= IRCItem->readtimeout) |
| 1025 |
> |
/* No data in IRCItem.readtimeout seconds */ |
| 1026 |
> |
if (delta >= IRCItem.readtimeout) |
| 1027 |
|
{ |
| 1028 |
|
log_printf("IRC -> Timeout awaiting data from server."); |
| 1029 |
< |
irc_reconnect(); |
| 1029 |
> |
irc_close(); |
| 1030 |
|
|
| 1031 |
|
/* Make sure we don't do this again for a while */ |
| 1032 |
|
time(&IRC_LAST); |
| 1033 |
|
} |
| 1034 |
< |
else if (delta >= IRCItem->readtimeout / 2) |
| 1034 |
> |
else if (delta >= IRCItem.readtimeout / 2) |
| 1035 |
|
{ |
| 1036 |
|
/* |
| 1037 |
|
* Generate some data so high ping times don't cause uneeded |