00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025 #include "stdinc.h"
00026 #ifndef _WIN32
00027 #include <netinet/in_systm.h>
00028 #include <netinet/ip.h>
00029 #include <netinet/tcp.h>
00030 #endif
00031 #include "fdlist.h"
00032 #include "s_bsd.h"
00033 #include "client.h"
00034 #include "common.h"
00035 #include "dbuf.h"
00036 #include "event.h"
00037 #include "irc_string.h"
00038 #include "irc_getnameinfo.h"
00039 #include "irc_getaddrinfo.h"
00040 #include "ircd.h"
00041 #include "list.h"
00042 #include "listener.h"
00043 #include "numeric.h"
00044 #include "packet.h"
00045 #include "irc_res.h"
00046 #include "inet_misc.h"
00047 #include "restart.h"
00048 #include "s_auth.h"
00049 #include "s_conf.h"
00050 #include "s_log.h"
00051 #include "s_serv.h"
00052 #include "s_stats.h"
00053 #include "send.h"
00054 #include "memory.h"
00055 #include "s_user.h"
00056 #include "hook.h"
00057
00058 static const char *comm_err_str[] = { "Comm OK", "Error during bind()",
00059 "Error during DNS lookup", "connect timeout", "Error during connect()",
00060 "Comm Error" };
00061
00062 struct Callback *setup_socket_cb = NULL;
00063
00064 static void comm_connect_callback(fde_t *fd, int status);
00065 static PF comm_connect_timeout;
00066 static void comm_connect_dns_callback(void *vptr, struct DNSReply *reply);
00067 static PF comm_connect_tryconnect;
00068
00069 extern void init_netio(void);
00070
00071
00072
00073
00074 void
00075 check_can_use_v6(void)
00076 {
00077 #ifdef IPV6
00078 int v6;
00079
00080 if ((v6 = socket(AF_INET6, SOCK_STREAM, 0)) < 0)
00081 ServerInfo.can_use_v6 = 0;
00082 else
00083 {
00084 ServerInfo.can_use_v6 = 1;
00085 #ifdef _WIN32
00086 closesocket(v6);
00087 #else
00088 close(v6);
00089 #endif
00090 }
00091 #else
00092 ServerInfo.can_use_v6 = 0;
00093 #endif
00094 }
00095
00096
00097
00098
00099
00100
00101
00102 int
00103 get_sockerr(int fd)
00104 {
00105 #ifndef _WIN32
00106 int errtmp = errno;
00107 #else
00108 int errtmp = WSAGetLastError();
00109 #endif
00110 #ifdef SO_ERROR
00111 int err = 0;
00112 socklen_t len = sizeof(err);
00113
00114 if (-1 < fd && !getsockopt(fd, SOL_SOCKET, SO_ERROR, (char*) &err, (socklen_t *)&len))
00115 {
00116 if (err)
00117 errtmp = err;
00118 }
00119 errno = errtmp;
00120 #endif
00121 return errtmp;
00122 }
00123
00124
00125
00126
00127
00128
00129
00130
00131
00132
00133
00134
00135
00136
00137
00138
00139
00140
00141
00142
00143 void
00144 report_error(int level, const char* text, const char* who, int error)
00145 {
00146 who = (who) ? who : "";
00147
00148 sendto_realops_flags(UMODE_DEBUG, level, text, who, strerror(error));
00149 log_oper_action(LOG_IOERR_TYPE, NULL, "%s %s %s\n", who, text, strerror(error));
00150 ilog(L_ERROR, text, who, strerror(error));
00151 }
00152
00153
00154
00155
00156
00157
00158 static void *
00159 setup_socket(va_list args)
00160 {
00161 int fd = va_arg(args, int);
00162 int opt = 1;
00163
00164 setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, (char *) &opt, sizeof(opt));
00165
00166 #ifdef IPTOS_LOWDELAY
00167 opt = IPTOS_LOWDELAY;
00168 setsockopt(fd, IPPROTO_IP, IP_TOS, (char *) &opt, sizeof(opt));
00169 #endif
00170
00171 #ifndef _WIN32
00172 fcntl(fd, F_SETFL, fcntl(fd, F_GETFL, 0) | O_NONBLOCK);
00173 #endif
00174
00175 return NULL;
00176 }
00177
00178
00179
00180
00181
00182
00183 void
00184 init_comm(void)
00185 {
00186 setup_socket_cb = register_callback("setup_socket", setup_socket);
00187 init_netio();
00188 }
00189
00190
00191
00192
00193
00194
00195 void
00196 close_connection(struct Client *client_p)
00197 {
00198 struct ConfItem *conf;
00199 struct AccessItem *aconf;
00200 struct ClassItem *aclass;
00201
00202 assert(NULL != client_p);
00203
00204 if (!IsDead(client_p))
00205 {
00206
00207
00208
00209
00210
00211 ClearSendqBlocked(client_p);
00212 send_queued_write(client_p);
00213 }
00214
00215 if (IsServer(client_p))
00216 {
00217 ServerStats->is_sv++;
00218 ServerStats->is_sbs += client_p->localClient->send.bytes;
00219 ServerStats->is_sbr += client_p->localClient->recv.bytes;
00220 ServerStats->is_sti += CurrentTime - client_p->firsttime;
00221
00222
00223
00224
00225
00226
00227
00228
00229
00230 if ((conf = find_conf_exact(SERVER_TYPE,
00231 client_p->name, client_p->username,
00232 client_p->host)))
00233 {
00234
00235
00236
00237
00238
00239
00240 aconf = (struct AccessItem *)map_to_conf(conf);
00241 aclass = (struct ClassItem *)map_to_conf(aconf->class_ptr);
00242 aconf->hold = time(NULL);
00243 aconf->hold += (aconf->hold - client_p->since > HANGONGOODLINK) ?
00244 HANGONRETRYDELAY : ConFreq(aclass);
00245 if (nextconnect > aconf->hold)
00246 nextconnect = aconf->hold;
00247 }
00248 }
00249 else if (IsClient(client_p))
00250 {
00251 ServerStats->is_cl++;
00252 ServerStats->is_cbs += client_p->localClient->send.bytes;
00253 ServerStats->is_cbr += client_p->localClient->recv.bytes;
00254 ServerStats->is_cti += CurrentTime - client_p->firsttime;
00255 }
00256 else
00257 ServerStats->is_ni++;
00258
00259 #ifdef HAVE_LIBCRYPTO
00260 if (client_p->localClient->fd.ssl)
00261 {
00262 SSL_set_shutdown(client_p->localClient->fd.ssl, SSL_RECEIVED_SHUTDOWN);
00263
00264 if (!SSL_shutdown(client_p->localClient->fd.ssl))
00265 SSL_shutdown(client_p->localClient->fd.ssl);
00266 }
00267 #endif
00268 if (client_p->localClient->fd.flags.open)
00269 fd_close(&client_p->localClient->fd);
00270
00271 if (HasServlink(client_p))
00272 {
00273 if (client_p->localClient->ctrlfd.flags.open)
00274 fd_close(&client_p->localClient->ctrlfd);
00275 }
00276
00277 dbuf_clear(&client_p->localClient->buf_sendq);
00278 dbuf_clear(&client_p->localClient->buf_recvq);
00279
00280 MyFree(client_p->localClient->passwd);
00281 detach_conf(client_p, CONF_TYPE);
00282 client_p->from = NULL;
00283 }
00284
00285 #ifdef HAVE_LIBCRYPTO
00286
00287
00288
00289
00290 static void
00291 ssl_handshake(int fd, struct Client *client_p)
00292 {
00293 int ret = SSL_accept(client_p->localClient->fd.ssl);
00294
00295 if (ret <= 0)
00296 switch (SSL_get_error(client_p->localClient->fd.ssl, ret))
00297 {
00298 case SSL_ERROR_WANT_WRITE:
00299 comm_setselect(&client_p->localClient->fd, COMM_SELECT_WRITE,
00300 (PF *) ssl_handshake, client_p, 0);
00301 return;
00302
00303 case SSL_ERROR_WANT_READ:
00304 comm_setselect(&client_p->localClient->fd, COMM_SELECT_READ,
00305 (PF *) ssl_handshake, client_p, 0);
00306 return;
00307
00308 default:
00309 exit_client(client_p, client_p, "Error during SSL handshake");
00310 return;
00311 }
00312
00313 execute_callback(auth_cb, client_p);
00314 }
00315 #endif
00316
00317
00318
00319
00320
00321
00322
00323
00324 void
00325 add_connection(struct Listener *listener, struct irc_ssaddr *irn, int fd)
00326 {
00327 struct Client *new_client;
00328
00329 assert(NULL != listener);
00330
00331 new_client = make_client(NULL);
00332
00333 fd_open(&new_client->localClient->fd, fd, 1,
00334 (listener->flags & LISTENER_SSL) ?
00335 "Incoming SSL connection" : "Incoming connection");
00336
00337
00338
00339
00340
00341 memcpy(&new_client->localClient->ip, irn, sizeof(struct irc_ssaddr));
00342
00343 irc_getnameinfo((struct sockaddr*)&new_client->localClient->ip,
00344 new_client->localClient->ip.ss_len, new_client->sockhost,
00345 HOSTIPLEN, NULL, 0, NI_NUMERICHOST);
00346 new_client->localClient->aftype = new_client->localClient->ip.ss.ss_family;
00347 #ifdef IPV6
00348 if (new_client->sockhost[0] == ':')
00349 strlcat(new_client->host, "0", HOSTLEN+1);
00350
00351 if (new_client->localClient->aftype == AF_INET6 &&
00352 ConfigFileEntry.dot_in_ip6_addr == 1)
00353 {
00354 strlcat(new_client->host, new_client->sockhost,HOSTLEN+1);
00355 strlcat(new_client->host, ".", HOSTLEN+1);
00356 }
00357 else
00358 #endif
00359 strlcat(new_client->host, new_client->sockhost,HOSTLEN+1);
00360
00361 new_client->connect_id = ++connect_id;
00362 new_client->localClient->listener = listener;
00363 ++listener->ref_count;
00364
00365 #ifdef HAVE_LIBCRYPTO
00366 if (listener->flags & LISTENER_SSL)
00367 {
00368 if ((new_client->localClient->fd.ssl = SSL_new(ServerInfo.ctx)) == NULL)
00369 {
00370 ilog(L_CRIT, "SSL_new() ERROR! -- %s",
00371 ERR_error_string(ERR_get_error(), NULL));
00372
00373 SetDead(new_client);
00374 exit_client(new_client, new_client, "SSL_new failed");
00375 return;
00376 }
00377
00378 SSL_set_fd(new_client->localClient->fd.ssl, fd);
00379 ssl_handshake(0, new_client);
00380 }
00381 else
00382 #endif
00383 execute_callback(auth_cb, new_client);
00384 }
00385
00386
00387
00388
00389
00390
00391
00392 int
00393 ignoreErrno(int ierrno)
00394 {
00395 switch (ierrno)
00396 {
00397 case EINPROGRESS:
00398 case EWOULDBLOCK:
00399 #if EAGAIN != EWOULDBLOCK
00400 case EAGAIN:
00401 #endif
00402 case EALREADY:
00403 case EINTR:
00404 #ifdef ERESTART
00405 case ERESTART:
00406 #endif
00407 return 1;
00408 default:
00409 return 0;
00410 }
00411 }
00412
00413
00414
00415
00416
00417
00418 void
00419 comm_settimeout(fde_t *fd, time_t timeout, PF *callback, void *cbdata)
00420 {
00421 assert(fd->flags.open);
00422
00423 fd->timeout = CurrentTime + (timeout / 1000);
00424 fd->timeout_handler = callback;
00425 fd->timeout_data = cbdata;
00426 }
00427
00428
00429
00430
00431
00432
00433
00434
00435
00436
00437
00438
00439
00440 void
00441 comm_setflush(fde_t *fd, time_t timeout, PF *callback, void *cbdata)
00442 {
00443 assert(fd->flags.open);
00444
00445 fd->flush_timeout = CurrentTime + (timeout / 1000);
00446 fd->flush_handler = callback;
00447 fd->flush_data = cbdata;
00448 }
00449
00450
00451
00452
00453
00454
00455
00456
00457 void
00458 comm_checktimeouts(void *notused)
00459 {
00460 int i;
00461 fde_t *F;
00462 PF *hdl;
00463 void *data;
00464
00465 for (i = 0; i < FD_HASH_SIZE; i++)
00466 for (F = fd_hash[i]; F != NULL; F = fd_next_in_loop)
00467 {
00468 assert(F->flags.open);
00469 fd_next_in_loop = F->hnext;
00470
00471
00472 if (F->flush_handler && F->flush_timeout > 0 &&
00473 F->flush_timeout < CurrentTime)
00474 {
00475 hdl = F->flush_handler;
00476 data = F->flush_data;
00477 comm_setflush(F, 0, NULL, NULL);
00478 hdl(F, data);
00479 }
00480
00481
00482 if (F->timeout_handler && F->timeout > 0 &&
00483 F->timeout < CurrentTime)
00484 {
00485
00486 hdl = F->timeout_handler;
00487 data = F->timeout_data;
00488 comm_settimeout(F, 0, NULL, NULL);
00489 hdl(F, data);
00490 }
00491 }
00492 }
00493
00494
00495
00496
00497
00498
00499
00500
00501
00502
00503
00504
00505
00506
00507 void
00508 comm_connect_tcp(fde_t *fd, const char *host, unsigned short port,
00509 struct sockaddr *clocal, int socklen, CNCB *callback,
00510 void *data, int aftype, int timeout)
00511 {
00512 struct addrinfo hints, *res;
00513 char portname[PORTNAMELEN+1];
00514
00515 assert(callback);
00516 fd->connect.callback = callback;
00517 fd->connect.data = data;
00518
00519 fd->connect.hostaddr.ss.ss_family = aftype;
00520 fd->connect.hostaddr.ss_port = htons(port);
00521
00522
00523
00524
00525
00526
00527
00528
00529 if ((clocal != NULL) && (bind(fd->fd, clocal, socklen) < 0))
00530 {
00531
00532 comm_connect_callback(fd, COMM_ERR_BIND);
00533
00534 return;
00535 }
00536
00537
00538
00539
00540 memset(&hints, 0, sizeof(hints));
00541 hints.ai_family = AF_UNSPEC;
00542 hints.ai_socktype = SOCK_STREAM;
00543 hints.ai_flags = AI_PASSIVE | AI_NUMERICHOST;
00544
00545 snprintf(portname, PORTNAMELEN, "%d", port);
00546
00547 if (irc_getaddrinfo(host, portname, &hints, &res))
00548 {
00549
00550 fd->dns_query = MyMalloc(sizeof(struct DNSQuery));
00551 fd->dns_query->ptr = fd;
00552 fd->dns_query->callback = comm_connect_dns_callback;
00553 gethost_byname(host, fd->dns_query);
00554 }
00555 else
00556 {
00557
00558
00559 assert(res != NULL);
00560 memcpy(&fd->connect.hostaddr, res->ai_addr, res->ai_addrlen);
00561 fd->connect.hostaddr.ss_len = res->ai_addrlen;
00562 fd->connect.hostaddr.ss.ss_family = res->ai_family;
00563 irc_freeaddrinfo(res);
00564 comm_settimeout(fd, timeout*1000, comm_connect_timeout, NULL);
00565 comm_connect_tryconnect(fd, NULL);
00566 }
00567 }
00568
00569
00570
00571
00572 static void
00573 comm_connect_callback(fde_t *fd, int status)
00574 {
00575 CNCB *hdl;
00576
00577
00578 if (fd->connect.callback == NULL)
00579 return;
00580
00581
00582 hdl = fd->connect.callback;
00583 fd->connect.callback = NULL;
00584
00585
00586 comm_settimeout(fd, 0, NULL, NULL);
00587
00588
00589 hdl(fd, status, fd->connect.data);
00590 }
00591
00592
00593
00594
00595
00596
00597 static void
00598 comm_connect_timeout(fde_t *fd, void *notused)
00599 {
00600
00601 comm_connect_callback(fd, COMM_ERR_TIMEOUT);
00602 }
00603
00604
00605
00606
00607
00608
00609
00610 static void
00611 comm_connect_dns_callback(void *vptr, struct DNSReply *reply)
00612 {
00613 fde_t *F = vptr;
00614
00615 if (reply == NULL)
00616 {
00617 MyFree(F->dns_query);
00618 F->dns_query = NULL;
00619 comm_connect_callback(F, COMM_ERR_DNS);
00620 return;
00621 }
00622
00623
00624 comm_settimeout(F, 30*1000, comm_connect_timeout, NULL);
00625
00626
00627
00628
00629
00630
00631
00632 memcpy(&F->connect.hostaddr, &reply->addr, reply->addr.ss_len);
00633
00634 ((struct sockaddr_in *) &F->connect.hostaddr)->sin_port =
00635 F->connect.hostaddr.ss_port;
00636 F->connect.hostaddr.ss_len = reply->addr.ss_len;
00637
00638
00639 MyFree(F->dns_query);
00640 F->dns_query = NULL;
00641 comm_connect_tryconnect(F, NULL);
00642 }
00643
00644
00645
00646
00647
00648
00649
00650
00651
00652 static void
00653 comm_connect_tryconnect(fde_t *fd, void *notused)
00654 {
00655 int retval;
00656
00657
00658 if (fd->connect.callback == NULL)
00659 return;
00660
00661
00662 retval = connect(fd->fd, (struct sockaddr *) &fd->connect.hostaddr,
00663 fd->connect.hostaddr.ss_len);
00664
00665
00666 if (retval < 0)
00667 {
00668 #ifdef _WIN32
00669 errno = WSAGetLastError();
00670 #endif
00671
00672
00673
00674
00675
00676 if (errno == EISCONN)
00677 comm_connect_callback(fd, COMM_OK);
00678 else if (ignoreErrno(errno))
00679
00680 comm_setselect(fd, COMM_SELECT_WRITE, comm_connect_tryconnect,
00681 NULL, 0);
00682 else
00683
00684 comm_connect_callback(fd, COMM_ERR_CONNECT);
00685 return;
00686 }
00687
00688
00689 comm_connect_callback(fd, COMM_OK);
00690 }
00691
00692
00693
00694
00695 const char *
00696 comm_errstr(int error)
00697 {
00698 if (error < 0 || error >= COMM_ERR_MAX)
00699 return "Invalid error number!";
00700 return comm_err_str[error];
00701 }
00702
00703
00704
00705
00706
00707
00708
00709
00710 int
00711 comm_open(fde_t *F, int family, int sock_type, int proto, const char *note)
00712 {
00713 int fd;
00714
00715
00716 if (number_fd >= hard_fdlimit)
00717 {
00718 errno = ENFILE;
00719 return -1;
00720 }
00721
00722
00723
00724
00725
00726
00727 fd = socket(family, sock_type, proto);
00728 if (fd < 0)
00729 {
00730 #ifdef _WIN32
00731 errno = WSAGetLastError();
00732 #endif
00733 return -1;
00734 }
00735
00736 execute_callback(setup_socket_cb, fd);
00737
00738
00739 fd_open(F, fd, 1, note);
00740 return 0;
00741 }
00742
00743
00744
00745
00746
00747
00748
00749
00750 int
00751 comm_accept(struct Listener *lptr, struct irc_ssaddr *pn)
00752 {
00753 int newfd;
00754 socklen_t addrlen = sizeof(struct irc_ssaddr);
00755
00756 if (number_fd >= hard_fdlimit)
00757 {
00758 errno = ENFILE;
00759 return -1;
00760 }
00761
00762
00763
00764
00765
00766
00767 newfd = accept(lptr->fd.fd, (struct sockaddr *)pn, (socklen_t *)&addrlen);
00768 if (newfd < 0)
00769 {
00770 #ifdef _WIN32
00771 errno = WSAGetLastError();
00772 #endif
00773 return -1;
00774 }
00775
00776 #ifdef IPV6
00777 remove_ipv6_mapping(pn);
00778 #else
00779 pn->ss_len = addrlen;
00780 #endif
00781
00782 execute_callback(setup_socket_cb, newfd);
00783
00784
00785 return newfd;
00786 }
00787
00788
00789
00790
00791
00792
00793
00794
00795 #ifdef IPV6
00796 void
00797 remove_ipv6_mapping(struct irc_ssaddr *addr)
00798 {
00799 if (addr->ss.ss_family == AF_INET6)
00800 {
00801 struct sockaddr_in6 *v6;
00802
00803 v6 = (struct sockaddr_in6*)addr;
00804 if (IN6_IS_ADDR_V4MAPPED(&v6->sin6_addr))
00805 {
00806 char v4ip[HOSTIPLEN];
00807 struct sockaddr_in *v4 = (struct sockaddr_in*)addr;
00808 inetntop(AF_INET6, &v6->sin6_addr, v4ip, HOSTIPLEN);
00809 inet_pton(AF_INET, v4ip, &v4->sin_addr);
00810 addr->ss.ss_family = AF_INET;
00811 addr->ss_len = sizeof(struct sockaddr_in);
00812 }
00813 else
00814 addr->ss_len = sizeof(struct sockaddr_in6);
00815 }
00816 else
00817 addr->ss_len = sizeof(struct sockaddr_in);
00818 }
00819 #endif