1 //=============================================================================
2 //
3 // File : KviIrcSocket.cpp
4 // Creation date : Tue Jul 30 19:25:18 2002 GMT by Szymon Stefanek
5 //
6 // This file is part of the KVIrc IRC client distribution
7 // Copyright (C) 2002-2010 Szymon Stefanek (pragma at kvirc dot net)
8 //
9 // This program is FREE software. You can redistribute it and/or
10 // modify it under the terms of the GNU General Public License
11 // as published by the Free Software Foundation; either version 2
12 // of the License, or (at your option) any later version.
13 //
14 // This program is distributed in the HOPE that it will be USEFUL,
15 // but WITHOUT ANY WARRANTY; without even the implied warranty of
16 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
17 // See the GNU General Public License for more details.
18 //
19 // You should have received a copy of the GNU General Public License
20 // along with this program. If not, write to the Free Software Foundation,
21 // Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
22 //
23 //=============================================================================
24
25 #include "KviIrcSocket.h"
26 #include "KviIrcServer.h"
27 #include "KviProxy.h"
28 #include "KviProxyDataBase.h"
29 #include "KviNetUtils.h"
30 #include "kvi_settings.h"
31 #include "KviLocale.h"
32 #include "KviMemory.h"
33 #include "kvi_debug.h"
34 #include "KviCString.h"
35 #include "KviOptions.h"
36 #include "KviConsoleWindow.h"
37 #include "kvi_out.h"
38 #include "KviIrcLink.h"
39 #include "KviIrcConnection.h"
40 #include "KviDataBuffer.h"
41
42 #ifdef COMPILE_SSL_SUPPORT
43 #include "KviSSLMaster.h"
44 #endif
45
46 #include <QTimer>
47 #include <QSocketNotifier>
48 #include <memory>
49
50 #if !defined(COMPILE_ON_WINDOWS) && !defined(COMPILE_ON_MINGW)
51 #include <unistd.h> //for gettimeofday()
52 #endif
53 //#include <fcntl.h>
54 //#include <errno.h>
55
56 // FIXME: #warning "Lag-o-meter"
57
58 unsigned int g_uNextIrcLinkId = 1;
59
KviIrcSocket(KviIrcLink * pLink)60 KviIrcSocket::KviIrcSocket(KviIrcLink * pLink)
61 : QObject(), m_pLink(pLink)
62 {
63 m_uId = g_uNextIrcLinkId;
64 g_uNextIrcLinkId++;
65
66 m_pConsole = m_pLink->console();
67
68 m_tAntiFloodLastMessageTime.tv_sec = 0;
69 m_tAntiFloodLastMessageTime.tv_usec = 0;
70
71 if(KVI_OPTION_UINT(KviOption_uintSocketQueueFlushTimeout) < 100)
72 KVI_OPTION_UINT(KviOption_uintSocketQueueFlushTimeout) = 100; // this is our minimum, we don't want to lag the app
73
74 m_pFlushTimer = std::make_unique<QTimer>(); // queue flush timer
75 connect(m_pFlushTimer.get(), SIGNAL(timeout()), this, SLOT(flushSendQueue()));
76 }
77
~KviIrcSocket()78 KviIrcSocket::~KviIrcSocket()
79 {
80 reset();
81 }
82
reset()83 void KviIrcSocket::reset()
84 {
85 #ifdef COMPILE_SSL_SUPPORT
86 if(m_pSSL)
87 {
88 KviSSLMaster::freeSSL(m_pSSL);
89 m_pSSL = nullptr;
90 }
91 #endif
92 if(m_pIrcServer)
93 {
94 delete m_pIrcServer;
95 m_pIrcServer = nullptr;
96 }
97
98 if(m_pProxy)
99 {
100 delete m_pProxy;
101 m_pProxy = nullptr;
102 }
103
104 if(m_pRsn)
105 {
106 delete m_pRsn;
107 m_pRsn = nullptr;
108 }
109
110 if(m_pWsn)
111 {
112 delete m_pWsn;
113 m_pWsn = nullptr;
114 }
115
116 if(kvi_socket_isValid(m_sock))
117 {
118 kvi_socket_destroy(m_sock);
119 m_sock = KVI_INVALID_SOCKET;
120 }
121
122 if(m_pTimeoutTimer)
123 {
124 m_pTimeoutTimer->stop();
125 delete m_pTimeoutTimer;
126 m_pTimeoutTimer = nullptr;
127 }
128
129 m_bInProcessData = false;
130
131 m_uReadBytes = 0;
132 m_uSentBytes = 0;
133 m_uSentPackets = 0;
134 m_tAntiFloodLastMessageTime.tv_sec = 0;
135 m_tAntiFloodLastMessageTime.tv_usec = 0;
136
137 m_bInProcessData = false;
138
139 if(m_pFlushTimer->isActive())
140 m_pFlushTimer->stop();
141
142 queue_removeAllMessages();
143
144 setState(Idle);
145 }
146
clearOutputQueue(bool bPrivateMessagesOnly)147 void KviIrcSocket::clearOutputQueue(bool bPrivateMessagesOnly)
148 {
149 if(bPrivateMessagesOnly)
150 queue_removePrivateMessages();
151 else
152 queue_removeAllMessages();
153 }
154
outputQueueSize()155 unsigned int KviIrcSocket::outputQueueSize()
156 {
157 KviIrcSocketMsgEntry * pMsg = m_pSendQueueTail;
158 if(!pMsg)
159 return 0;
160
161 unsigned int uCount = 0;
162
163 do
164 {
165 uCount++;
166 pMsg = pMsg->next_ptr;
167 } while(pMsg);
168
169 return uCount;
170 }
171
outputSSLMessage(const QString & szMsg)172 void KviIrcSocket::outputSSLMessage(const QString & szMsg)
173 {
174 m_pConsole->output(KVI_OUT_SSL, __tr2qs("[SSL]: %Q"), &szMsg);
175 }
176
outputSSLError(const QString & szMsg)177 void KviIrcSocket::outputSSLError(const QString & szMsg)
178 {
179 m_pConsole->output(KVI_OUT_SSL, __tr2qs("[SSL ERROR]: %Q"), &szMsg);
180 }
181
outputProxyMessage(const QString & szMsg)182 void KviIrcSocket::outputProxyMessage(const QString & szMsg)
183 {
184 for(const auto & it : szMsg.split('\n', QString::SkipEmptyParts))
185 {
186 QString szTemporary = it.trimmed();
187 m_pConsole->output(KVI_OUT_SOCKETMESSAGE, __tr2qs("[PROXY]: %Q"), &szTemporary);
188 }
189 }
190
outputProxyError(const QString & szMsg)191 void KviIrcSocket::outputProxyError(const QString & szMsg)
192 {
193 for(const auto & it : szMsg.split('\n', QString::SkipEmptyParts))
194 {
195 QString szTemporary = it.trimmed();
196 m_pConsole->output(KVI_OUT_SOCKETERROR, __tr2qs("[PROXY ERROR]: %Q"), &szTemporary);
197 }
198 }
199
outputSocketMessage(const QString & szMsg)200 void KviIrcSocket::outputSocketMessage(const QString & szMsg)
201 {
202 m_pConsole->output(KVI_OUT_SOCKETMESSAGE, __tr2qs("[SOCKET]: %Q"), &szMsg);
203 }
204
outputSocketError(const QString & szMsg)205 void KviIrcSocket::outputSocketError(const QString & szMsg)
206 {
207 m_pConsole->output(KVI_OUT_SOCKETERROR, __tr2qs("[SOCKET ERROR]: %Q"), &szMsg);
208 }
209
outputSocketWarning(const QString & szMsg)210 void KviIrcSocket::outputSocketWarning(const QString & szMsg)
211 {
212 m_pConsole->output(KVI_OUT_SOCKETWARNING, __tr2qs("[SOCKET WARNING]: %Q"), &szMsg);
213 }
214
setState(SocketState state)215 void KviIrcSocket::setState(SocketState state)
216 {
217 if(state != m_state)
218 {
219 m_state = state;
220 m_pLink->socketStateChange();
221 }
222 }
223
raiseError(KviError::Code eError)224 void KviIrcSocket::raiseError(KviError::Code eError)
225 {
226 m_eLastError = eError;
227 //m_pConsole->socketError(iError);
228 if((m_eLastError == KviError::RemoteEndClosedConnection) && (m_state == ProxyHttpError))
229 outputSocketMessage(KviError::getDescription(eError));
230 else
231 outputSocketError(KviError::getDescription(eError));
232 }
233
startConnection(KviIrcServer * pServer,KviProxy * pProxy,const char * pcBindAddress)234 KviError::Code KviIrcSocket::startConnection(KviIrcServer * pServer, KviProxy * pProxy, const char * pcBindAddress)
235 {
236 // Attempts to establish an IRC connection
237 // to the server specified by *srv.
238 // Uses the proxy *prx if not 0
239 if(m_state != Idle)
240 return KviError::AnotherConnectionInProgress;
241
242 // Coherent state, thnx.
243 reset();
244
245 #ifndef COMPILE_SSL_SUPPORT
246 if(pServer->useSSL())
247 {
248 return KviError::NoSSLSupport;
249 }
250 #endif //COMPILE_SSL_SUPPORT
251
252 // Copy the server
253 m_pIrcServer = new KviIrcServer(*pServer);
254
255 bool bTargetIPv6 = false;
256 bool bNeedServerIp = !pProxy;
257 if(pProxy)
258 bNeedServerIp = ((pProxy->protocol() != KviProxy::Http) && (pProxy->protocol() != KviProxy::Socks5));
259
260 // We're going to check the addresses now
261
262 // check the proxy stuff...
263 if(pProxy)
264 {
265 // Yeah...here comes the proxy
266 m_pProxy = new KviProxy(*pProxy);
267 // check the proxy IP address
268 if(m_pProxy->isIPv6())
269 {
270 // IPv6 proxy :) (STILL QUITE UNTESTED ?)
271 #ifdef COMPILE_IPV6_SUPPORT
272 bTargetIPv6 = true;
273 if(!KviNetUtils::isValidStringIPv6(m_pProxy->ip()))
274 return KviError::InvalidProxyAddress;
275 // SOCKSv4 does not support IPv6 addresses
276 if(m_pProxy->protocol() == KviProxy::Socks4)
277 return KviError::SocksV4LacksIPv6Support;
278 #else
279 return KviError::NoIPv6Support;
280 #endif
281 }
282 else
283 {
284 // IPv4 proxy
285 if(!KviNetUtils::isValidStringIp(m_pProxy->ip()))
286 return KviError::InvalidProxyAddress;
287 }
288 }
289
290 if(bNeedServerIp)
291 {
292 // check the IRC host IP
293 #ifdef COMPILE_IPV6_SUPPORT
294 if(m_pIrcServer->isIPv6())
295 {
296 // We have an IPv6 server host (Interesting if proxy is IPv4)
297 if(!KviNetUtils::isValidStringIPv6(m_pIrcServer->ip()))
298 return KviError::InvalidIpAddress;
299 if(!m_pProxy)
300 bTargetIPv6 = true; // otherwise the proxy rules
301 }
302 else
303 {
304 #endif
305 // We have an IPv4 server host
306 if(!KviNetUtils::isValidStringIp(m_pIrcServer->ip()))
307 return KviError::InvalidIpAddress;
308 #ifdef COMPILE_IPV6_SUPPORT
309 }
310 #endif
311 }
312
313 KviSockaddr sa(pProxy ? m_pProxy->ip().toUtf8().data() : m_pIrcServer->ip().toUtf8().data(), pProxy ? m_pProxy->port() : m_pIrcServer->port(), bTargetIPv6);
314
315 if(!sa.socketAddress())
316 return KviError::InvalidIpAddress;
317
318 // create the socket
319 #ifdef COMPILE_IPV6_SUPPORT
320 m_sock = kvi_socket_create(bTargetIPv6 ? KVI_SOCKET_PF_INET6 : KVI_SOCKET_PF_INET, KVI_SOCKET_TYPE_STREAM, KVI_SOCKET_PROTO_TCP);
321 #else
322 m_sock = kvi_socket_create(KVI_SOCKET_PF_INET, KVI_SOCKET_TYPE_STREAM, KVI_SOCKET_PROTO_TCP);
323 #endif
324
325 if(m_sock < 0)
326 return KviError::SocketCreationFailed;
327
328 if(pcBindAddress)
329 {
330 // we have to bind the socket to a local address
331 KviSockaddr localSa(pcBindAddress, 0, bTargetIPv6);
332 bool bBindOk = localSa.socketAddress();
333
334 if(bBindOk)
335 {
336 bBindOk = kvi_socket_bind(m_sock, localSa.socketAddress(), ((int)(localSa.addressLength())));
337 }
338
339 QString szTmp;
340 if(bBindOk)
341 {
342 if(_OUTPUT_VERBOSE)
343 szTmp = QString(__tr2qs("Binding to local address %1")).arg(pcBindAddress);
344 outputSocketMessage(szTmp);
345 }
346 else
347 {
348 if(_OUTPUT_VERBOSE)
349 szTmp = QString(__tr2qs("Binding to local address %1 failed: the kernel will choose the correct interface")).arg(pcBindAddress);
350 outputSocketWarning(szTmp);
351 }
352 }
353
354 // make it non blocking
355 if(!kvi_socket_setNonBlocking(m_sock))
356 {
357 reset();
358 return KviError::AsyncSocketFailed;
359 }
360
361 if(!kvi_socket_connect(m_sock, sa.socketAddress(), ((int)(sa.addressLength()))))
362 {
363 // Oops!
364 int iErr = kvi_socket_error();
365
366 if(!kvi_socket_recoverableConnectError(iErr))
367 {
368 // Oops!
369 int iSockError = iErr;
370 if(iSockError == 0)
371 {
372 // Zero error ?...let's look closer
373 int iSize = sizeof(int);
374 if(!kvi_socket_getsockopt(m_sock, SOL_SOCKET, SO_ERROR, (void *)&iSockError, &iSize))
375 iSockError = 0;
376 }
377 // die :(
378 reset();
379 // And declare problems :)
380 if(iSockError)
381 return KviError::translateSystemError(iSockError);
382 else
383 return KviError::UnknownError; //Error 0 ?
384 }
385 }
386
387 // and setup the WRITE notifier...
388 m_pWsn = new QSocketNotifier((int)m_sock, QSocketNotifier::Write);
389 QObject::connect(m_pWsn, SIGNAL(activated(int)), this, SLOT(writeNotifierFired(int)));
390 m_pWsn->setEnabled(true);
391
392 // set the timer
393 if(KVI_OPTION_UINT(KviOption_uintIrcSocketTimeout) < 5)
394 KVI_OPTION_UINT(KviOption_uintIrcSocketTimeout) = 5;
395
396 m_pTimeoutTimer = new QTimer();
397 QObject::connect(m_pTimeoutTimer, SIGNAL(timeout()), this, SLOT(connectionTimedOut()));
398 m_pTimeoutTimer->setSingleShot(true);
399 m_pTimeoutTimer->setInterval(KVI_OPTION_UINT(KviOption_uintIrcSocketTimeout) * 1000);
400 m_pTimeoutTimer->start();
401
402 // and wait for connect
403 setState(Connecting);
404
405 return KviError::Success;
406 }
407
connectionTimedOut()408 void KviIrcSocket::connectionTimedOut()
409 {
410 // the m_pTimeoutTimer fired :(
411 raiseError(KviError::ConnectionTimedOut);
412 reset();
413 }
414
writeNotifierFired(int)415 void KviIrcSocket::writeNotifierFired(int)
416 {
417 // kill the timeout timer
418 if(m_pTimeoutTimer)
419 {
420 delete m_pTimeoutTimer;
421 m_pTimeoutTimer = nullptr;
422 }
423
424 // Check for errors...
425 int iSockError;
426 int iSize = sizeof(int);
427 if(!kvi_socket_getsockopt(m_sock, SOL_SOCKET, SO_ERROR, (void *)&iSockError, &iSize))
428 iSockError = -1;
429
430 //sockError = 0;
431 if(iSockError != 0)
432 {
433 //failed
434 KviError::Code eError;
435 if(iSockError > 0)
436 eError = KviError::translateSystemError(iSockError);
437 else
438 eError = KviError::UnknownError; //Error 0 ?
439
440 raiseError(eError);
441 reset();
442 return;
443 }
444
445 // kill the write notifier
446 delete m_pWsn;
447 m_pWsn = nullptr;
448
449 //Successfully connected...
450 connectionEstablished();
451 }
452
connectionEstablished()453 void KviIrcSocket::connectionEstablished()
454 {
455 if(m_sock == KVI_INVALID_SOCKET)
456 return; // ops...disconnected in setState() ????
457
458 if(m_pProxy)
459 connectedToProxy();
460 else
461 connectedToIrcServer();
462 }
463
connectedToProxy()464 void KviIrcSocket::connectedToProxy()
465 {
466 if(!m_pProxy)
467 qDebug("WARNING: connectedToProxy() without a m_pProxy!");
468
469 // FIXME: Do we want to support SSL proxies ?
470 // it would be just a matter of SSL handshaking
471 // with the proxy
472
473 setState(ProxyLogin);
474
475 if(m_pRsn)
476 {
477 delete m_pRsn;
478 m_pRsn = nullptr;
479 }
480
481 m_pRsn = new QSocketNotifier((int)m_sock, QSocketNotifier::Read);
482
483 QObject::connect(m_pRsn, SIGNAL(activated(int)), this, SLOT(readProxyData(int)));
484
485 switch(m_pProxy->protocol())
486 {
487 case KviProxy::Http:
488 proxyLoginHttp();
489 break;
490 case KviProxy::Socks5:
491 proxyLoginV5();
492 break;
493 default:
494 proxyLoginV4();
495 break;
496 }
497 }
498
readHttpProxyErrorData(int)499 void KviIrcSocket::readHttpProxyErrorData(int)
500 {
501 char cBuffer[256];
502 int iReadLength;
503
504 iReadLength = kvi_socket_recv(m_sock, cBuffer, 255);
505 if(iReadLength <= 0)
506 {
507 handleInvalidSocketRead(iReadLength);
508 return;
509 }
510
511 outputProxyMessage(m_pConsole->decodeText(cBuffer));
512 }
513
connectedToIrcServer()514 void KviIrcSocket::connectedToIrcServer()
515 {
516 #ifdef COMPILE_SSL_SUPPORT
517 if(m_pIrcServer->useSSL())
518 {
519 enterSSLMode();
520 return;
521 }
522 #endif //COMPILE_SSL_SUPPORT
523 linkUp();
524 }
525
526 #ifdef COMPILE_SSL_SUPPORT
enterSSLMode()527 void KviIrcSocket::enterSSLMode()
528 {
529 Q_ASSERT(!m_pSSL); // Don't call this function twice in a session
530
531 m_pSSL = KviSSLMaster::allocSSL(m_pConsole, m_sock, KviSSL::Client);
532 if(!m_pSSL)
533 {
534 raiseSSLError();
535 raiseError(KviError::SSLError);
536 reset();
537 return;
538 }
539 setState(SSLHandshake);
540 doSSLHandshake(0);
541 }
542 #endif //COMPILE_SSL_SUPPORT
543
readProxyData(int)544 void KviIrcSocket::readProxyData(int)
545 {
546 char cBuffer[256];
547 int iReadLength;
548 /*
549 // THIS IS WORKING CODE THAT SUPPORTS SSL PROXIES!
550 #ifdef COMPILE_SSL_SUPPORT
551 if(m_pSSL)
552 {
553 readLength = m_pSSL->read(buffer,256);
554 if(readLength <= 0)
555 {
556 // ssl error....?
557 switch(m_pSSL->getProtocolError(readLength))
558 {
559 case KviSSL::ZeroReturn:
560 readLength = 0;
561 break;
562 case KviSSL::WantRead:
563 case KviSSL::WantWrite:
564 // hmmm...
565 return;
566 break;
567 case KviSSL::SyscallError:
568 {
569 int iE = m_pSSL->getLastError(true);
570 if(iE != 0)
571 {
572 raiseSSLError();
573 raiseError(KviError::SSLError);
574 reset();
575 return;
576 }
577 }
578 break;
579 case KviSSL::SSLError:
580 raiseSSLError();
581 raiseError(KviError::SSLError);
582 reset();
583 return;
584 break;
585 default:
586 raiseError(KviError::SSLError);
587 reset();
588 return;
589 break;
590
591 }
592 handleInvalidSocketRead(readLength);
593 return;
594 }
595 } else {
596 #endif
597 */
598 iReadLength = kvi_socket_recv(m_sock, cBuffer, 255);
599 if(iReadLength <= 0)
600 {
601 handleInvalidSocketRead(iReadLength);
602 return;
603 }
604 /*
605 #ifdef COMPILE_SSL_SUPPORT
606 }
607 #endif
608 */
609 // we need at least two bytes...
610 if(iReadLength < 2)
611 {
612 // a single byte of reply means:
613 // - connection through a 1 bps modem
614 // - a totally blocked network
615 // - remote host is not a SOCKS/HTTP server
616 // Anyway....it is always a meaningless reply
617 // better to try again later :)
618 raiseError(KviError::UnrecognizedProxyReply);
619 reset();
620 return;
621 }
622
623 // handle the reply
624 switch(m_state)
625 {
626 case ProxyFinalV4:
627 //V4 final reply
628 proxyHandleV4FinalReply((unsigned char)cBuffer[1]);
629 break;
630 case ProxySelectAuthMethodV5:
631 //V5 method selection reply
632 proxyHandleV5MethodReply((unsigned char)cBuffer[1]);
633 break;
634 case ProxyUserPassV5:
635 //V5 user and pass reply
636 proxyHandleV5AuthReply((unsigned char)cBuffer[1]);
637 break;
638 case ProxyFinalV5:
639 //V5 final reply
640 proxyHandleV5FinalReply((unsigned char)cBuffer[1]);
641 break;
642 case ProxyFinalHttp:
643 //Http final reply
644 cBuffer[iReadLength] = '\0';
645 proxyHandleHttpFinalReply(cBuffer, iReadLength);
646 break;
647 default:
648 // what ?
649 raiseError(KviError::UnrecognizedProxyReply);
650 reset();
651 break;
652 }
653 }
654
proxyLoginHttp()655 void KviIrcSocket::proxyLoginHttp()
656 {
657 // Well..this is just plain and easy: connect to the proxy machine
658 // and say "CONNECT <irc.server>:<port> HTTP/<version>\n\n"
659 // if it requires auth then say Proxy-Authorization: Basic user:passwd
660 // Then expect a server reply header (2 newlines)
661 // HTTP 200 = Success
662 // HTTP Anything else = Failure
663
664 if(_OUTPUT_VERBOSE)
665 outputProxyMessage(__tr2qs("Using HTTP protocol."));
666
667 setState(ProxyFinalHttp);
668 KviCString szTmp(KviCString::Format, "CONNECT %s:%u HTTP/1.0\r\n", m_pIrcServer->hostName().toUtf8().data(), (unsigned int)(m_pIrcServer->port()));
669
670 szTmp.append(KviCString::Format, "User-Agent: KVIrc-ProxyClient/4.0\r\n");
671
672 if(m_pProxy->hasUser())
673 {
674 KviCString szAuth(KviCString::Format, "%s:%s", m_pProxy->user().toUtf8().data(), m_pProxy->pass().toUtf8().data());
675 KviCString szEncoded;
676 szEncoded.bufferToBase64(szAuth.ptr(), szAuth.len());
677 szTmp.append(KviCString::Format, "Proxy-Authorization: Basic %s\r\n\r\n", szEncoded.ptr());
678 }
679 else
680 {
681 szTmp.append("\r\n");
682 }
683
684 sendRawData(szTmp.ptr(), szTmp.len());
685 }
686
proxyLoginV4()687 void KviIrcSocket::proxyLoginV4()
688 {
689 // SOCKSv4 protocol
690 //
691 // 1) CONNECT
692 //
693 // The client connects to the SOCKS server and sends a CONNECT request when
694 // it wants to establish a connection to an application server. The client
695 // includes in the request packet the IP address and the port number of the
696 // destination host, and userid, in the following format.
697 //
698 // +----+----+----+----+----+----+----+----+----+----+....+----+
699 // | VN | CD | DSTPORT | DSTIP | USERID |NULL|
700 // +----+----+----+----+----+----+----+----+----+----+....+----+
701 // # of bytes: 1 1 2 4 variable 1
702 //
703 // VN is the SOCKS protocol version number and should be 4. CD is the
704 // SOCKS command code and should be 1 for CONNECT request. NULL is a byte
705 // of all zero bits.
706 //
707 // The SOCKS server checks to see whether such a request should be granted
708 // based on any combination of source IP address, destination IP address,
709 // destination port number, the userid, and information it may obtain by
710 // consulting IDENT, cf. RFC 1413. If the request is granted, the SOCKS
711 // server makes a connection to the specified port of the destination host.
712 // A reply packet is sent to the client when this connection is established,
713 // or when the request is rejected or the operation fails.
714 //
715 if(_OUTPUT_VERBOSE)
716 outputProxyMessage(__tr2qs("Using SOCKSv4 protocol."));
717
718 m_pProxy->normalizeUserAndPass();
719 // the protocol does not specify the "userid" format...
720 // so build a userid from the pass and/or username...
721
722 KviCString szUserAndPass = m_pProxy->user();
723 if(m_pProxy->hasPass())
724 {
725 if(szUserAndPass.hasData())
726 szUserAndPass.append(' ');
727 szUserAndPass.append(m_pProxy->pass());
728 }
729
730 int iLen = szUserAndPass.len() + 9;
731
732 // build the request packet
733 char * pcBufToSend = new char[iLen];
734 pcBufToSend[0] = (unsigned char)4; //Version 4
735 pcBufToSend[1] = (unsigned char)1; //Connect
736
737 quint16 port = (quint16)htons(m_pIrcServer->port());
738 KviMemory::move((void *)(pcBufToSend + 2), (void *)&port, 2);
739
740 struct in_addr ircInAddr;
741
742 if(!KviNetUtils::stringIpToBinaryIp(m_pIrcServer->ip(), &ircInAddr))
743 qDebug("SOCKET INTERNAL ERROR IN IPV4 (SOCKS4) ADDR CONVERSION");
744
745 quint32 host = (quint32)ircInAddr.s_addr;
746 KviMemory::move((void *)(pcBufToSend + 4), (void *)&host, 4);
747 KviMemory::move((void *)(pcBufToSend + 8), (void *)(szUserAndPass.ptr()), szUserAndPass.len());
748
749 pcBufToSend[iLen - 1] = '\0';
750
751 // send it into hyperspace...
752 setState(ProxyFinalV4);
753 sendRawData(pcBufToSend, iLen);
754 delete[] pcBufToSend;
755 // and wait for reply...
756 }
757
proxyLoginV5()758 void KviIrcSocket::proxyLoginV5()
759 {
760 // SOCKSv5 protocol.
761 //
762 // When a TCP-based client wishes to establish a connection to an object
763 // that is reachable only via a firewall (such determination is left up
764 // to the implementation), it must open a TCP connection to the
765 // appropriate SOCKS port on the SOCKS server system. The SOCKS service
766 // is conventionally located on TCP port 1080. If the connection
767 // request succeeds, the client enters a negotiation for the
768 // authentication method to be used, authenticates with the chosen
769 // method, then sends a relay request. The SOCKS server evaluates the
770 // request, and either establishes the appropriate connection or denies
771 // it.
772 //
773 // The client connects to the server, and sends a version
774 // identifier/method selection message:
775 //
776 // +----+----------+----------+
777 // |VER | NMETHODS | METHODS |
778 // +----+----------+----------+
779 // | 1 | 1 | 1 to 255 |
780 // +----+----------+----------+
781 //
782 // The VER field is set to X'05' for this version of the protocol. The
783 // NMETHODS field contains the number of method identifier octets that
784 // appear in the METHODS field.
785 // The values currently defined for METHOD are:
786 //
787 // o X'00' NO AUTHENTICATION REQUIRED
788 // o X'01' GSSAPI
789 // o X'02' USERNAME/PASSWORD
790 // o X'03' CHAP
791 // o X'04' to X'7F' IANA ASSIGNED
792 // o X'80' to X'FE' RESERVED FOR PRIVATE METHODS
793 // o X'FF' NO ACCEPTABLE METHODS
794 //
795
796 if(_OUTPUT_VERBOSE)
797 outputProxyMessage(__tr2qs("Using SOCKSv5 protocol."));
798
799 m_pProxy->normalizeUserAndPass();
800 // the protocol does not specify the "userid" format...
801 // so build a userid from the pass and/or username...
802
803 char cBufToSend[4];
804 cBufToSend[0] = (unsigned char)5; //use version 5
805 int iSendLen = 3;
806
807 if(!(m_pProxy->hasUser() || m_pProxy->hasPass()))
808 {
809 // no auth needed.
810 cBufToSend[1] = (unsigned char)1; //select one method
811 cBufToSend[2] = (unsigned char)0; //select method 0 : no auth
812 if(_OUTPUT_VERBOSE)
813 outputProxyMessage(__tr2qs("We can accept auth method 0 (no auth)"));
814 }
815 else
816 {
817 // we can provide a password and username if needed...
818 cBufToSend[1] = (unsigned char)2; //select from two methods
819 cBufToSend[2] = (unsigned char)0; //method 0 or
820 cBufToSend[3] = (unsigned char)2; //method 2 username/pass auth
821 iSendLen = 4;
822 if(_OUTPUT_VERBOSE)
823 outputProxyMessage(__tr2qs("We can accept auth method 0 (no auth) or 2 (user/pass)"));
824 }
825
826 // notify the user before sending...since we may get disconnected
827 setState(ProxySelectAuthMethodV5);
828 sendRawData(cBufToSend, iSendLen);
829 // and wait for response
830 }
831
proxyAuthUserPassV5()832 void KviIrcSocket::proxyAuthUserPassV5()
833 {
834 // Once the SOCKS V5 server has started, and the client has selected the
835 // Username/Password Authentication protocol, the Username/Password
836 // subnegotiation begins. This begins with the client producing a
837 // Username/Password request:
838 //
839 // +----+------+----------+------+----------+
840 // |VER | ULEN | UNAME | PLEN | PASSWD |
841 // +----+------+----------+------+----------+
842 // | 1 | 1 | 1 to 255 | 1 | 1 to 255 |
843 // +----+------+----------+------+----------+
844 //
845 // The VER field contains the current version of the subnegotiation,
846 // which is X'01'. The ULEN field contains the length of the UNAME field
847 // that follows. The UNAME field contains the username as known to the
848 // source operating system. The PLEN field contains the length of the
849 // PASSWD field that follows. The PASSWD field contains the password
850 // association with the given UNAME.
851 //
852 unsigned int uPass = (unsigned int)m_pProxy->passLen();
853 unsigned int uUser = (unsigned int)m_pProxy->userLen();
854
855 if(uPass > 255)
856 uPass = 255;
857
858 if(uUser > 255)
859 uUser = 255;
860
861 int iLen = uPass + uUser + 3;
862 char * pcBufToSend = new char[iLen];
863
864 //version x'01'
865 pcBufToSend[0] = (unsigned char)1;
866
867 //length of the username
868 pcBufToSend[1] = (unsigned char)uUser;
869
870 //username
871 KviMemory::move((void *)(pcBufToSend + 2), (void *)m_pProxy->user().toUtf8().data(), uUser);
872
873 //length of the password
874 pcBufToSend[2 + uUser] = (unsigned char)uPass;
875 KviMemory::move((void *)(pcBufToSend + 3 + uUser), (void *)m_pProxy->pass().toUtf8().data(), uPass);
876
877 // spit out the buffer and wait
878 setState(ProxyUserPassV5);
879 sendRawData(pcBufToSend, iLen);
880 delete[] pcBufToSend;
881 // and wait for response...
882 }
883
proxySendTargetDataV5()884 void KviIrcSocket::proxySendTargetDataV5()
885 {
886 // Once the method-dependent subnegotiation has completed, the client
887 // sends the request details. If the negotiated method includes
888 // encapsulation for purposes of integrity checking and/or
889 // confidentiality, these requests MUST be encapsulated in the method-
890 // dependent encapsulation.
891 //
892 // The SOCKS request is formed as follows:
893 //
894 // +----+-----+------+------+----------+----------+
895 // |VER | CMD | FLAG | ATYP | DST.ADDR | DST.PORT |
896 // +----+-----+------+------+----------+----------+
897 // | 1 | 1 | 1 | 1 | Variable | 2 |
898 // +----+-----+------+------+----------+----------+
899 //
900 // Where:
901 //
902 // o VER protocol version: X'05'
903 // o CMD
904 // o CONNECT X'01'
905 // o BIND X'02'
906 // o UDP ASSOCIATE X'03'
907 // o X'04' to X'7F' IANA ASSIGNED
908 // o X'80' to X'FF' RESERVED FOR PRIVATE METHODS
909 // o FLAG command dependent flag (defaults to X'00')
910 // o ATYP address type of following address
911 // o IP V4 address: X'01'
912 // o DOMAINNAME: X'03'
913 // o IP V6 address: X'04'
914 // o DST.ADDR desired destination address
915 // o DST.PORT desired destination port in network octet
916 // order
917 //
918 // The SOCKS server will typically evaluate the request based on
919 // source and destination addresses, and return one or more reply
920 // messages, as appropriate for the request type.
921 //
922 // In an address field (DST.ADDR, BND.ADDR), the ATYP field specifies
923 // the type of address contained within the field:
924 //
925 // o X'01'
926 //
927 // The address is a version-4 IP address, with a length of 4 octets.
928 //
929 // o X'03'
930 //
931 // The address field contains a fully-qualified domain name. The first
932 // octet of the address field contains the number of octets of name that
933 // follow, there is no terminating NUL octet.
934 //
935 // o X'04'
936 //
937 // The address is a version-6 IP address, with a length of 16 octets.
938 bool bRemoteDns = !(
939 (
940 KviNetUtils::isValidStringIp(m_pIrcServer->ip())
941 #ifdef COMPILE_IPV6_SUPPORT
942 || KviNetUtils::isValidStringIPv6(m_pIrcServer->ip())
943 #endif
944 )
945
946 && m_pIrcServer->cacheIp());
947 int iBufLen = bRemoteDns ? 4 + 1 + m_pIrcServer->hostName().toUtf8().length() + 2
948 : (m_pIrcServer->isIPv6() ? 22 : 10);
949 char * pcBufToSend = (char *)KviMemory::allocate(sizeof(char) * iBufLen);
950 pcBufToSend[0] = (unsigned char)5; //Proto 5
951 pcBufToSend[1] = (unsigned char)1; //CONNECT
952 pcBufToSend[2] = (unsigned char)0; //RSV
953
954 if(bRemoteDns)
955 {
956 bRemoteDns = true;
957 pcBufToSend[3] = 3;
958 pcBufToSend[4] = m_pIrcServer->hostName().toUtf8().length();
959 }
960 else
961 {
962 pcBufToSend[3] = (unsigned char)m_pIrcServer->isIPv6() ? 4 : 1; // IPv6 : IPv4
963 }
964
965 if(bRemoteDns)
966 {
967 KviMemory::move((void *)(pcBufToSend + 5),
968 (void *)(m_pIrcServer->hostName().toUtf8().data()),
969 m_pIrcServer->hostName().toUtf8().length());
970 quint16 port = (quint16)htons(m_pIrcServer->port());
971 KviMemory::move((void *)(pcBufToSend + 4 + 1 + m_pIrcServer->hostName().toUtf8().length()), (void *)&port, 2);
972 }
973 else if(m_pIrcServer->isIPv6())
974 {
975 #ifdef COMPILE_IPV6_SUPPORT
976 struct in6_addr ircInAddr;
977
978 if(!KviNetUtils::stringIpToBinaryIp_V6(m_pIrcServer->ip(), &ircInAddr))
979 qDebug("SOCKET INTERNAL ERROR IN IPV6 ADDR CONVERSION");
980 KviMemory::move((void *)(pcBufToSend + 4), (void *)(&ircInAddr), 4);
981 quint16 port = (quint16)htons(m_pIrcServer->port());
982 KviMemory::move((void *)(pcBufToSend + 20), (void *)&port, 2);
983 #endif
984 }
985 else
986 {
987 struct in_addr ircInAddr;
988
989 if(!KviNetUtils::stringIpToBinaryIp(m_pIrcServer->ip(), &ircInAddr))
990 qDebug("SOCKET INTERNAL ERROR IN IPV4 ADDR CONVERSION");
991 quint32 host = (quint32)ircInAddr.s_addr;
992 KviMemory::move((void *)(pcBufToSend + 4), (void *)&host, 4);
993 quint16 port = (quint16)htons(m_pIrcServer->port());
994 KviMemory::move((void *)(pcBufToSend + 8), (void *)&port, 2);
995 }
996
997 // send it into hyperspace...
998 setState(ProxyFinalV5);
999 sendRawData(pcBufToSend, iBufLen);
1000 KviMemory::free(pcBufToSend);
1001 // and wait for reply...
1002 }
1003
proxyHandleV5AuthReply(unsigned char cReply)1004 void KviIrcSocket::proxyHandleV5AuthReply(unsigned char cReply)
1005 {
1006 // The server verifies the supplied UNAME and PASSWD, and sends the
1007 // following response:
1008 //
1009 // +----+--------+
1010 // |VER | STATUS |
1011 // +----+--------+
1012 // | 1 | 1 |
1013 // +----+--------+
1014 //
1015 // A STATUS field of X'00' indicates success. If the server returns a
1016 // `failure' (STATUS value other than X'00') status, it MUST close the
1017 // connection.
1018 //
1019 if(cReply == 0)
1020 {
1021 if(_OUTPUT_VERBOSE)
1022 outputProxyMessage(__tr2qs("Proxy response: auth OK: access granted"));
1023 proxySendTargetDataV5();
1024 return;
1025 }
1026 raiseError(KviError::ProxyAuthFailed);
1027 reset();
1028 }
1029
proxyHandleV5MethodReply(unsigned char cReply)1030 void KviIrcSocket::proxyHandleV5MethodReply(unsigned char cReply)
1031 {
1032 // The server selects from one of the methods given in METHODS, and
1033 // sends a METHOD selection message:
1034 //
1035 // +----+--------+
1036 // |VER | METHOD |
1037 // +----+--------+
1038 // | 1 | 1 |
1039 // +----+--------+
1040 //
1041 // If the selected METHOD is X'FF', none of the methods listed by the
1042 // client are acceptable, and the client MUST close the connection.
1043 //
1044 // The values currently defined for METHOD are:
1045 //
1046 // o X'00' NO AUTHENTICATION REQUIRED
1047 // o X'01' GSSAPI
1048 // o X'02' USERNAME/PASSWORD
1049 // o X'03' CHAP
1050 // o X'04' to X'7F' IANA ASSIGNED
1051 // o X'80' to X'FE' RESERVED FOR PRIVATE METHODS
1052 // o X'FF' NO ACCEPTABLE METHODS
1053 //
1054 if(cReply == 0)
1055 {
1056 if(_OUTPUT_VERBOSE)
1057 outputProxyMessage(__tr2qs("Proxy response: auth method OK: using method 0 (no auth)"));
1058 proxySendTargetDataV5();
1059 return;
1060 }
1061
1062 if(cReply == 2)
1063 {
1064 if(_OUTPUT_VERBOSE)
1065 outputProxyMessage(__tr2qs("Proxy response: auth method OK: using method 2 (user/pass)"));
1066 proxyAuthUserPassV5();
1067 return;
1068 }
1069
1070 //Request rejected
1071 if(cReply == 0xFF)
1072 {
1073 raiseError(KviError::ProxyNoAcceptableAuthMethod);
1074 reset();
1075 }
1076 else
1077 {
1078 // unrecognized...
1079 raiseError(KviError::UnrecognizedProxyReply);
1080 reset();
1081 }
1082 }
1083
proxyHandleV5FinalReply(unsigned char cReply)1084 void KviIrcSocket::proxyHandleV5FinalReply(unsigned char cReply)
1085 {
1086 //
1087 // The SOCKS request information is sent by the client as soon as it has
1088 // established a connection to the SOCKS server, and completed the
1089 // authentication negotiations. The server evaluates the request, and
1090 // returns a reply formed as follows:
1091 //
1092 // +----+-----+------+------+----------+----------+
1093 // |VER | REP | FLAG | ATYP | BND.ADDR | BND.PORT |
1094 // +----+-----+------+------+----------+----------+
1095 // | 1 | 1 | 1 | 1 | Variable | 2 |
1096 // +----+-----+------+------+----------+----------+
1097 //
1098 // Where:
1099 // o VER protocol version: X'05'
1100 // o REP Reply field:
1101 // o X'00' succeeded
1102 // o X'01' general SOCKS server failure
1103 // o X'02' connection not allowed by ruleset
1104 // o X'03' Network unreachable
1105 // o X'04' Host unreachable
1106 // o X'05' Connection refused
1107 // o X'06' TTL expired
1108 // o X'07' Command not supported
1109 // o X'08' Address type not supported
1110 // o X'09' Invalid address
1111 // o X'0A' to X'FF' unassigned
1112 // o FLAG command dependent flag
1113 // o ATYP address type of following address
1114 // o IP V4 address: X'01'
1115 // o DOMAINNAME: X'03'
1116 // o IP V6 address: X'04'
1117 // o BND.ADDR server bound address
1118 // o BND.PORT server bound port in network octet order
1119 //
1120 if(cReply == 0)
1121 {
1122 // Request granted
1123 if(_OUTPUT_VERBOSE)
1124 outputProxyMessage(__tr2qs("Proxy response: target data OK: request granted"));
1125 connectedToIrcServer();
1126 }
1127 else
1128 {
1129 //Request rejected
1130 KviError::Code eError;
1131 switch(cReply)
1132 {
1133 case 1:
1134 eError = KviError::ProxyReply01GeneralSOCKSFailure;
1135 break;
1136 case 2:
1137 eError = KviError::ProxyReply02ConnectionNotAllowed;
1138 break;
1139 case 3:
1140 eError = KviError::ProxyReply03NetworkUnreachable;
1141 break;
1142 case 4:
1143 eError = KviError::ProxyReply04HostUnreachable;
1144 break;
1145 case 5:
1146 eError = KviError::ProxyReply05ConnectionRefused;
1147 break;
1148 case 6:
1149 eError = KviError::ProxyReply06TTLExpired;
1150 break;
1151 case 7:
1152 eError = KviError::ProxyReply07CommandNotSupported;
1153 break;
1154 case 8:
1155 eError = KviError::ProxyReply08AddressTypeNotSupported;
1156 break;
1157 case 9:
1158 eError = KviError::ProxyReply09InvalidAddress;
1159 break;
1160 default:
1161 eError = KviError::UnrecognizedProxyReply;
1162 break;
1163 }
1164 raiseError(eError);
1165 reset();
1166 }
1167 }
1168
proxyHandleV4FinalReply(unsigned char cReply)1169 void KviIrcSocket::proxyHandleV4FinalReply(unsigned char cReply)
1170 {
1171 // If the request is granted, the SOCKS
1172 // server makes a connection to the specified port of the destination host.
1173 // A reply packet is sent to the client when this connection is established,
1174 // or when the request is rejected or the operation fails.
1175 //
1176 //
1177 // +----+----+----+----+----+----+----+----+
1178 // | VN | CD | DSTPORT | DSTIP |
1179 // +----+----+----+----+----+----+----+----+
1180 // # of bytes: 1 1 2 4
1181 //
1182 // VN is the version of the reply code and should be 0. CD is the result
1183 // code with one of the following values:
1184 //
1185 // 90: request granted
1186 // 91: request rejected or failed
1187 // 92: request rejected because SOCKS server cannot connect to
1188 // identd on the client
1189 // 93: request rejected because the client program and identd
1190 // report different user-ids
1191 //
1192 // The remaining fields are ignored.
1193 //
1194 // The SOCKS server closes its connection immediately after notifying
1195 // the client of a failed or rejected request. For a successful request,
1196 // the SOCKS server gets ready to relay traffic on both directions. This
1197 // enables the client to do I/O on its connection as if it were directly
1198 // connected to the application server.
1199 if(cReply == 90)
1200 {
1201 // Request granted
1202 if(_OUTPUT_VERBOSE)
1203 outputProxyMessage(__tr2qs("Proxy response: target data OK: request granted"));
1204 connectedToIrcServer();
1205 }
1206 else
1207 {
1208 //Request rejected
1209 KviError::Code eError;
1210 switch(cReply)
1211 {
1212 case 91:
1213 eError = KviError::ProxyReply91RequestFailed;
1214 break;
1215 case 92:
1216 eError = KviError::ProxyReply92IdentFailed;
1217 break;
1218 case 93:
1219 eError = KviError::ProxyReply93IdentNotMatching;
1220 break;
1221 default:
1222 eError = KviError::UnrecognizedProxyReply;
1223 break;
1224 }
1225 raiseError(eError);
1226 reset();
1227 }
1228 // Just looked out of the window...
1229 // Hmmmm...strange light outside...
1230 // Looked at the clock...6:34 !
1231 // I think I'll go sleep.... :)
1232 }
1233
proxyHandleHttpFinalReply(const char * pcBuffer,int)1234 void KviIrcSocket::proxyHandleHttpFinalReply(const char * pcBuffer, int)
1235 {
1236 // Escape character is '^]'.
1237 // CONNECT warszawa.irc.pl:6667 HTTP/1.0
1238 //
1239 // HTTP/1.0 200 Connection established
1240
1241 KviCString szTmp = pcBuffer;
1242 // FIXME: #warning "We could even show the proxy output here...!"
1243 szTmp.cutFromFirst('\n');
1244 szTmp.trim();
1245
1246 if(kvi_strEqualCIN(szTmp.ptr(), "HTTP", 4))
1247 {
1248 int iIdx = szTmp.findFirstIdx(" 200 ");
1249 if(iIdx != -1)
1250 {
1251 if(iIdx == szTmp.findFirstIdx(' '))
1252 {
1253 QString szMsg = __tr2qs("Proxy response: ");
1254 szMsg += szTmp.ptr();
1255 if(_OUTPUT_VERBOSE)
1256 outputProxyMessage(szMsg);
1257 connectedToIrcServer();
1258 return;
1259 }
1260 }
1261 }
1262
1263 outputProxyError(__tr2qs("Proxy said something about: \n"));
1264 outputProxyMessage(m_pConsole->decodeText(pcBuffer));
1265
1266 //Read HTTP error page and show it
1267
1268 if(m_pWsn)
1269 {
1270 delete m_pWsn;
1271 m_pWsn = nullptr;
1272 }
1273
1274 if(m_pRsn)
1275 {
1276 delete m_pRsn;
1277 m_pRsn = nullptr;
1278 }
1279
1280 m_pRsn = new QSocketNotifier((int)m_sock, QSocketNotifier::Read);
1281 QObject::connect(m_pRsn, SIGNAL(activated(int)), this, SLOT(readHttpProxyErrorData(int)));
1282 m_pRsn->setEnabled(true);
1283
1284 setState(ProxyHttpError);
1285
1286 }
1287
1288 //
1289 // SSL HANDSHAKE
1290 //
1291
1292 #ifdef COMPILE_SSL_SUPPORT
printSSLPeerCertificate()1293 void KviIrcSocket::printSSLPeerCertificate()
1294 {
1295 KviSSLCertificate * c = m_pSSL->getPeerCertificate();
1296 if(c)
1297 {
1298 //m_pConsole->socketEvent(SSLCertificate,(void *)c);
1299 if(_OUTPUT_VERBOSE)
1300 KviSSLMaster::printSSLCertificate(m_pConsole, __tr("Server X509 certificate"), c);
1301 delete c;
1302 }
1303 else
1304 {
1305 if(_OUTPUT_VERBOSE)
1306 outputSSLMessage(__tr2qs("The server didn't provide a certificate"));
1307 }
1308 }
1309
printSSLCipherInfo()1310 void KviIrcSocket::printSSLCipherInfo()
1311 {
1312 KviSSLCipherInfo * ci = m_pSSL->getCurrentCipherInfo();
1313 if(ci)
1314 {
1315 KviSSLMaster::printSSLCipherInfo(m_pConsole, __tr("Current transmission cipher"), ci);
1316 delete ci;
1317 }
1318 else
1319 {
1320 if(_OUTPUT_VERBOSE)
1321 outputSSLMessage(__tr2qs("Unable to determine the current cipher"));
1322 }
1323 }
1324
raiseSSLError()1325 void KviIrcSocket::raiseSSLError()
1326 {
1327 KviCString szBuffer;
1328 while(m_pSSL->getLastErrorString(szBuffer))
1329 {
1330 outputSSLError(szBuffer.ptr());
1331 }
1332 }
1333 #endif // COMPILE_SSL_SUPPORT
1334
doSSLHandshake(int)1335 void KviIrcSocket::doSSLHandshake(int)
1336 {
1337 #ifdef COMPILE_SSL_SUPPORT
1338 KVI_ASSERT(m_pSSL);
1339
1340 if(m_pRsn)
1341 {
1342 delete m_pRsn;
1343 m_pRsn = nullptr;
1344 }
1345
1346 if(m_pWsn)
1347 {
1348 delete m_pWsn;
1349 m_pWsn = nullptr;
1350 }
1351
1352 if(!m_pSSL)
1353 {
1354 qDebug("Oops! Have I lost the SSL class?");
1355 reset();
1356 return; // ops ?
1357 }
1358
1359 switch(m_pSSL->connect())
1360 {
1361 case KviSSL::Success:
1362 // done!
1363 printSSLCipherInfo();
1364 printSSLPeerCertificate();
1365 linkUp();
1366 break;
1367 case KviSSL::WantRead:
1368 m_pRsn = new QSocketNotifier((int)m_sock, QSocketNotifier::Read);
1369 QObject::connect(m_pRsn, SIGNAL(activated(int)), this, SLOT(doSSLHandshake(int)));
1370 m_pRsn->setEnabled(true);
1371 break;
1372 case KviSSL::WantWrite:
1373 m_pWsn = new QSocketNotifier((int)m_sock, QSocketNotifier::Write);
1374 QObject::connect(m_pWsn, SIGNAL(activated(int)), this, SLOT(doSSLHandshake(int)));
1375 m_pWsn->setEnabled(true);
1376 break;
1377 case KviSSL::RemoteEndClosedConnection:
1378 raiseError(KviError::RemoteEndClosedConnection);
1379 reset();
1380 break;
1381 case KviSSL::SSLError:
1382 raiseSSLError();
1383 raiseError(KviError::SSLError);
1384 reset();
1385 break;
1386 case KviSSL::SyscallError:
1387 {
1388 // syscall problem
1389 int iErr = kvi_socket_error();
1390 if(!kvi_socket_recoverableError(iErr))
1391 {
1392 // Declare problems :)
1393 raiseError((iErr ? KviError::translateSystemError(iErr) : KviError::UnknownError));
1394 }
1395 else
1396 {
1397 // can recover ? (EAGAIN, EINTR ?)
1398 m_pWsn = new QSocketNotifier((int)m_sock, QSocketNotifier::Write);
1399 QObject::connect(m_pWsn, SIGNAL(activated(int)), this, SLOT(doSSLHandshake(int)));
1400 m_pWsn->setEnabled(true);
1401 return;
1402 }
1403 reset();
1404 }
1405 break;
1406 default:
1407 raiseError(KviError::SSLError);
1408 reset();
1409 break;
1410 }
1411
1412 #else //COMPILE_SSL_SUPPORT
1413 qDebug("Oops! SSL handshake without SSL support. Aborting!");
1414 exit(-1);
1415 #endif //COMPILE_SSL_SUPPORT
1416 }
1417
1418 //
1419 // LINK UP
1420 //
1421
linkUp()1422 void KviIrcSocket::linkUp()
1423 {
1424 setState(Connected);
1425
1426 // the last check
1427 if(m_sock == KVI_INVALID_SOCKET)
1428 return; // ops...disconnected in setState() ????
1429
1430 // OK.. it seems that we're really up and running now!
1431 if(m_pWsn)
1432 {
1433 delete m_pWsn;
1434 m_pWsn = nullptr;
1435 }
1436
1437 if(m_pRsn)
1438 {
1439 delete m_pRsn;
1440 m_pRsn = nullptr;
1441 }
1442
1443 m_pRsn = new QSocketNotifier((int)m_sock, QSocketNotifier::Read);
1444 QObject::connect(m_pRsn, SIGNAL(activated(int)), this, SLOT(readData(int)));
1445 m_pRsn->setEnabled(true);
1446 }
1447
readData(int)1448 void KviIrcSocket::readData(int)
1449 {
1450 //read data
1451 char cBuffer[1025];
1452 int iReadLength;
1453 #ifdef COMPILE_SSL_SUPPORT
1454 if(m_pSSL)
1455 {
1456 iReadLength = m_pSSL->read(cBuffer, 1024);
1457 if(iReadLength <= 0)
1458 {
1459 // ssl error....?
1460 switch(m_pSSL->getProtocolError(iReadLength))
1461 {
1462 case KviSSL::ZeroReturn:
1463 iReadLength = 0;
1464 break;
1465 case KviSSL::WantRead:
1466 case KviSSL::WantWrite:
1467 // hmmm...
1468 return;
1469 break;
1470 case KviSSL::SyscallError:
1471 {
1472 int iE = m_pSSL->getLastError(true);
1473 if(iE != 0)
1474 {
1475 raiseSSLError();
1476 raiseError(KviError::SSLError);
1477 reset();
1478 return;
1479 }
1480 }
1481 break;
1482 case KviSSL::SSLError:
1483 raiseSSLError();
1484 raiseError(KviError::SSLError);
1485 reset();
1486 return;
1487 break;
1488 default:
1489 raiseError(KviError::SSLError);
1490 reset();
1491 return;
1492 break;
1493 }
1494 handleInvalidSocketRead(iReadLength);
1495 return;
1496 }
1497 }
1498 else
1499 {
1500 #endif
1501 iReadLength = kvi_socket_recv(m_sock, cBuffer, 1024);
1502 if(iReadLength <= 0)
1503 {
1504 handleInvalidSocketRead(iReadLength);
1505 return;
1506 }
1507 #ifdef COMPILE_SSL_SUPPORT
1508 }
1509 #endif
1510
1511 //terminate our buffer
1512 (*(cBuffer + iReadLength)) = '\0';
1513
1514 m_uReadBytes += iReadLength;
1515
1516 // Shut up the socket notifier
1517 // in case that we enter in a local loop somewhere
1518 // while processing data...
1519 m_pRsn->setEnabled(false);
1520 // shut also the flushing of the message queue
1521 // in this way we prevent disconnect detection
1522 // during the processing of a message effectively
1523 // making it always an asynchronous event.
1524 m_bInProcessData = true;
1525
1526 m_pLink->processData(cBuffer, iReadLength);
1527 // after this line there should be nothing that relies
1528 // on the "connected" state of this socket.
1529 // It may happen that it has been reset() in the middle of the processData() call
1530 // and (unverified) it might have been even deleted.
1531
1532 // re-enable the socket notifier... (if it's still there)
1533 if(m_pRsn)
1534 m_pRsn->setEnabled(true);
1535 // and the message queue flushing
1536 m_bInProcessData = false;
1537 // and flush the queue too!
1538 if(m_pSendQueueHead)
1539 flushSendQueue();
1540 }
1541
abort()1542 void KviIrcSocket::abort()
1543 {
1544 // flush the send queue if possible (and if not yet disconnected in fact)
1545 if(m_state == Connected)
1546 flushSendQueue();
1547 if(m_state != Idle)
1548 raiseError(KviError::OperationAborted);
1549 // and reset
1550 reset();
1551 }
1552
handleInvalidSocketRead(int iReadLength)1553 void KviIrcSocket::handleInvalidSocketRead(int iReadLength)
1554 {
1555 KVI_ASSERT(iReadLength <= 0);
1556 if(iReadLength == 0)
1557 {
1558 raiseError(KviError::RemoteEndClosedConnection);
1559 reset();
1560 }
1561 else
1562 {
1563 //check for transmission errors
1564 int iErr = kvi_socket_error();
1565 #if defined(COMPILE_ON_WINDOWS) || defined(COMPILE_ON_MINGW)
1566 if((iErr != EAGAIN) && (iErr != EINTR) && (iErr != WSAEWOULDBLOCK))
1567 #else
1568 if((iErr != EAGAIN) && (iErr != EINTR))
1569 #endif
1570 {
1571 if(iErr > 0)
1572 raiseError((KviError::translateSystemError(iErr)));
1573 else
1574 raiseError(KviError::RemoteEndClosedConnection);
1575 reset();
1576 } //else transient error...wait again...
1577 }
1578 }
1579
queue_insertMessage(KviIrcSocketMsgEntry * pMsg)1580 void KviIrcSocket::queue_insertMessage(KviIrcSocketMsgEntry * pMsg)
1581 {
1582 KVI_ASSERT(pMsg);
1583
1584 pMsg->next_ptr = nullptr;
1585
1586 if(m_pSendQueueHead)
1587 {
1588 m_pSendQueueTail->next_ptr = pMsg;
1589 m_pSendQueueTail = pMsg;
1590 }
1591 else
1592 {
1593 m_pSendQueueHead = pMsg;
1594 m_pSendQueueTail = pMsg;
1595 }
1596 }
1597
free_msgEntry(KviIrcSocketMsgEntry * e)1598 void KviIrcSocket::free_msgEntry(KviIrcSocketMsgEntry * e)
1599 {
1600 if(e->pData)
1601 delete e->pData;
1602
1603 e->pData = nullptr;
1604 KviMemory::free(e);
1605 }
1606
queue_removeMessage()1607 bool KviIrcSocket::queue_removeMessage()
1608 {
1609 KVI_ASSERT(m_pSendQueueTail);
1610 KVI_ASSERT(m_pSendQueueHead);
1611
1612 if(m_pSendQueueHead->pData)
1613 delete m_pSendQueueHead->pData;
1614
1615 KviIrcSocketMsgEntry * pEntry = m_pSendQueueHead;
1616 m_pSendQueueHead = pEntry->next_ptr;
1617 KviMemory::free((void *)pEntry);
1618
1619 if(m_pSendQueueHead == nullptr)
1620 {
1621 m_pSendQueueTail = nullptr;
1622 return false;
1623 }
1624 else
1625 return true;
1626 }
1627
queue_removeAllMessages()1628 void KviIrcSocket::queue_removeAllMessages()
1629 {
1630 if(m_pSendQueueHead)
1631 while(queue_removeMessage())
1632 {
1633 }
1634 }
1635
queue_removePrivateMessages()1636 void KviIrcSocket::queue_removePrivateMessages()
1637 {
1638 KviIrcSocketMsgEntry * pPrevEntry = nullptr;
1639 KviIrcSocketMsgEntry * pEntry = m_pSendQueueHead;
1640 while(pEntry)
1641 {
1642 if(pEntry->pData->size() > 7)
1643 {
1644 if(kvi_strEqualCIN((char *)(pEntry->pData->data()), "PRIVMSG", 7))
1645 {
1646 // remove it
1647 if(pPrevEntry)
1648 {
1649 pPrevEntry->next_ptr = pEntry->next_ptr;
1650 if(!pPrevEntry->next_ptr)
1651 m_pSendQueueTail = nullptr;
1652 free_msgEntry(pEntry);
1653 pEntry = pPrevEntry->next_ptr;
1654 }
1655 else
1656 {
1657 m_pSendQueueHead = pEntry->next_ptr;
1658 if(!m_pSendQueueHead)
1659 m_pSendQueueTail = nullptr;
1660 free_msgEntry(pEntry);
1661 pEntry = m_pSendQueueHead;
1662 }
1663 continue;
1664 }
1665 }
1666 pPrevEntry = pEntry;
1667 pEntry = pEntry->next_ptr;
1668 }
1669 }
1670
flushSendQueue()1671 void KviIrcSocket::flushSendQueue()
1672 {
1673 // If we're called from the flush timer, stop it
1674 if(m_pFlushTimer->isActive())
1675 m_pFlushTimer->stop();
1676
1677 // OK...have something to send...
1678 KVI_ASSERT(m_state != Idle);
1679
1680 struct timeval curTime;
1681
1682 while(m_pSendQueueHead)
1683 {
1684 if(KVI_OPTION_BOOL(KviOption_boolLimitOutgoingTraffic))
1685 {
1686 kvi_gettimeofday(&curTime);
1687
1688 int iTimeDiff = curTime.tv_usec - m_tAntiFloodLastMessageTime.tv_usec;
1689 iTimeDiff += (curTime.tv_sec - m_tAntiFloodLastMessageTime.tv_sec) * 1000000;
1690
1691 if(((unsigned int)iTimeDiff) < KVI_OPTION_UINT(KviOption_uintOutgoingTrafficLimitUSeconds))
1692 {
1693 // need to wait for a while....
1694 m_pFlushTimer->start(((KVI_OPTION_UINT(KviOption_uintOutgoingTrafficLimitUSeconds) - iTimeDiff) / 1000) + 1);
1695 return;
1696 } // else can send
1697 }
1698 // Write one data buffer...
1699 int iResult;
1700 #ifdef COMPILE_SSL_SUPPORT
1701 if(m_pSSL)
1702 {
1703 iResult = m_pSSL->write((char *)(m_pSendQueueHead->pData->data()), m_pSendQueueHead->pData->size());
1704 }
1705 else
1706 {
1707 #endif
1708 iResult = kvi_socket_send(m_sock, (char *)(m_pSendQueueHead->pData->data()), m_pSendQueueHead->pData->size());
1709 #ifdef COMPILE_SSL_SUPPORT
1710 }
1711 #endif
1712 if(iResult == (int)m_pSendQueueHead->pData->size())
1713 {
1714 // Successful send...remove this data buffer
1715 m_uSentPackets++;
1716 m_uSentBytes += iResult;
1717 //if(m_pConsole->hasMonitors())outgoingMessageNotifyMonitors((char *)(m_pSendQueueHead->pData->data()),result);
1718 queue_removeMessage();
1719 if(KVI_OPTION_BOOL(KviOption_boolLimitOutgoingTraffic))
1720 {
1721 m_tAntiFloodLastMessageTime.tv_sec = curTime.tv_sec;
1722 m_tAntiFloodLastMessageTime.tv_usec = curTime.tv_usec;
1723 }
1724 // And try next buffer...
1725 continue;
1726 }
1727 else
1728 {
1729 // Something wrong ?
1730 #ifdef COMPILE_SSL_SUPPORT
1731 if(iResult <= 0)
1732 {
1733 if(m_pSSL)
1734 {
1735 // ops...might be an SSL error
1736 switch(m_pSSL->getProtocolError(iResult))
1737 {
1738 case KviSSL::WantWrite:
1739 case KviSSL::WantRead:
1740 // Async continue...
1741 m_pFlushTimer->start(KVI_OPTION_UINT(KviOption_uintSocketQueueFlushTimeout));
1742 return;
1743 break;
1744 case KviSSL::SyscallError:
1745 if(iResult == 0)
1746 {
1747 raiseSSLError();
1748 raiseError(KviError::RemoteEndClosedConnection);
1749 reset();
1750 return;
1751 }
1752 else
1753 {
1754 int iSSLErr = m_pSSL->getLastError(true);
1755 if(iSSLErr != 0)
1756 {
1757 raiseSSLError();
1758 raiseError(KviError::SSLError);
1759 reset();
1760 return;
1761 }
1762 else
1763 {
1764 goto handle_system_error;
1765 }
1766 }
1767 break;
1768 case KviSSL::SSLError:
1769 raiseSSLError();
1770 raiseError(KviError::SSLError);
1771 reset();
1772 return;
1773 break;
1774 default:
1775 raiseError(KviError::SSLError);
1776 reset();
1777 return;
1778 break;
1779 }
1780 }
1781 }
1782 else
1783 {
1784 #else // COMPILE_SSL_SUPPORT
1785 if(iResult >= 0)
1786 {
1787 if(iResult > 0)
1788 {
1789 #endif // COMPILE_SSL_SUPPORT
1790
1791 // Partial send...need to finish it later
1792 m_pSendQueueHead->pData->remove(iResult);
1793
1794 m_uSentBytes += iResult;
1795 if(_OUTPUT_VERBOSE)
1796 outputSocketWarning(__tr2qs("Partial socket write: packet broken into smaller pieces."));
1797 #ifndef COMPILE_SSL_SUPPORT
1798 }
1799 #endif // COMPILE_SSL_SUPPORT
1800 // Async continue...
1801 m_pFlushTimer->start(KVI_OPTION_UINT(KviOption_uintSocketQueueFlushTimeout));
1802 return;
1803 }
1804
1805 handle_system_error:
1806 // Oops...error ?
1807 int iErr = kvi_socket_error();
1808 #if defined(COMPILE_ON_WINDOWS) || defined(COMPILE_ON_MINGW)
1809 if((iErr == EAGAIN) || (iErr == EINTR) || (iErr == WSAEWOULDBLOCK))
1810 #else
1811 if((iErr == EAGAIN) || (iErr == EINTR))
1812 #endif
1813 {
1814 // Transient error...partial send as before...
1815 if(_OUTPUT_VERBOSE)
1816 outputSocketWarning(__tr2qs("Partial socket write: packet broken into smaller pieces."));
1817 // Async continue...
1818 m_pFlushTimer->start(KVI_OPTION_UINT(KviOption_uintSocketQueueFlushTimeout));
1819 return;
1820 }
1821 else
1822 {
1823 // Disconnected... :(
1824 raiseError((KviError::translateSystemError(iErr)));
1825 reset();
1826 return;
1827 }
1828 }
1829 }
1830 //flushed completely ...
1831 }
1832
1833 bool KviIrcSocket::getLocalHostIp(QString & szIp, bool bIPv6)
1834 {
1835 if(m_state != Connected)
1836 return false;
1837
1838 if(bIPv6)
1839 {
1840 #ifdef COMPILE_IPV6_SUPPORT
1841 struct sockaddr_in6 name;
1842 int iLen = sizeof(name);
1843 if(!kvi_socket_getsockname(m_sock, (struct sockaddr *)&name, &iLen))
1844 return false;
1845 //I assume that getsockname returns data in Network byte order...
1846 //The man page misses to specify that...
1847 if(!KviNetUtils::binaryIpToStringIp_V6(name.sin6_addr, szIp))
1848 return false;
1849
1850 return true;
1851 #else
1852 return false; // no support
1853 #endif
1854 }
1855
1856 struct sockaddr_in name;
1857 int iLen = sizeof(name);
1858 if(!kvi_socket_getsockname(m_sock, (struct sockaddr *)&name, &iLen))
1859 return false;
1860 //I assume that getsockname returns data in Network byte order...
1861 //The man page misses to specify that...
1862 if(!KviNetUtils::binaryIpToStringIp(name.sin_addr, szIp))
1863 return false;
1864
1865 return true;
1866 }
1867
1868 /*
1869 bool KviIrcSocket::sendFmtData(const char *fmt,...)
1870 {
1871 if(m_state != Connected)return false;
1872 //new buffer
1873 KviIrcSocketMsgEntry *ptr = (KviIrcSocketMsgEntry *)KviMemory::allocate(sizeof(KviIrcSocketMsgEntry));
1874 ptr->pData = new KviDataBuffer(512);
1875 kvi_va_list(list);
1876 kvi_va_start(list,fmt);
1877 bool bTruncated;
1878 //sprintf the buffer up to 512 chars (adds a CRLF too)
1879 int iLen = kvi_irc_vsnprintf((char *)(ptr->pData->data()),fmt,list,&bTruncated);
1880 kvi_va_end(list);
1881 //adjust the buffer size
1882 if(iLen < 512)ptr->pData->resize(iLen);
1883 if(bTruncated)
1884 {
1885 if(_OUTPUT_VERBOSE)
1886 outputSocketWarning(__tr2qs("Socket message truncated to 512 bytes."));
1887 }
1888
1889 queue_insertMessage(ptr);
1890 if(!m_bInProcessData)flushSendQueue();
1891 return (m_state != Idle);
1892 }
1893 */
1894 /*
1895 bool KviIrcSocket::sendData(const char *buffer,int buflen)
1896 {
1897 if(m_state != Connected)return false;
1898 //new buffer
1899 KviIrcSocketMsgEntry *ptr = (KviIrcSocketMsgEntry *)KviMemory::allocate(sizeof(KviIrcSocketMsgEntry));
1900 if(buflen < 0)buflen = strlen(buffer);
1901 if(buflen > 510)
1902 {
1903 buflen = 510;
1904 if(_OUTPUT_VERBOSE)
1905 outputSocketWarning(__tr2qs("Socket message truncated to 512 bytes."));
1906 }
1907 ptr->pData = new KviDataBuffer(buflen + 2);
1908 KviMemory::move(ptr->pData->data(),buffer,buflen);
1909 *(ptr->pData->data()+buflen)='\r';
1910 *(ptr->pData->data()+buflen+1)='\n';
1911
1912 queue_insertMessage(ptr);
1913 if(!m_bInProcessData)flushSendQueue();
1914 return (m_state != Idle);
1915 }
1916 */
1917
1918 bool KviIrcSocket::sendRawData(const char * pcBuffer, int iBuflen)
1919 {
1920 if((m_state == Idle) || (m_state == Connecting))
1921 return false;
1922
1923 //new buffer
1924 KviIrcSocketMsgEntry * pEntry = (KviIrcSocketMsgEntry *)KviMemory::allocate(sizeof(KviIrcSocketMsgEntry));
1925 pEntry->pData = new KviDataBuffer(iBuflen);
1926
1927 KviMemory::move(pEntry->pData->data(), pcBuffer, iBuflen);
1928 queue_insertMessage(pEntry);
1929
1930 if(!m_bInProcessData)
1931 flushSendQueue();
1932
1933 return (m_state != Idle);
1934 }
1935
1936 bool KviIrcSocket::sendPacket(KviDataBuffer * pData)
1937 {
1938 if(m_state != Connected)
1939 {
1940 delete pData;
1941 pData = nullptr;
1942 return false;
1943 }
1944
1945 KviIrcSocketMsgEntry * pEntry = (KviIrcSocketMsgEntry *)KviMemory::allocate(sizeof(KviIrcSocketMsgEntry));
1946 pEntry->pData = pData;
1947 queue_insertMessage(pEntry);
1948
1949 if(!m_bInProcessData)
1950 flushSendQueue();
1951
1952 return (m_state != Idle);
1953 }
1954