aboutsummaryrefslogtreecommitdiff
path: root/source
diff options
context:
space:
mode:
authorJeremy Lainé <jeremy.laine@m4x.org>2010-02-25 12:21:53 +0000
committerJeremy Lainé <jeremy.laine@m4x.org>2010-02-25 12:21:53 +0000
commitb9123796e79b1f9c08b5b113900826008f5d6dc8 (patch)
tree5a18ffd99ee0af574f83f3e88aaf421abf5aa68c /source
parent9334406b1ac2716ba799c5bb71d25efefaca29bc (diff)
downloadqxmpp-b9123796e79b1f9c08b5b113900826008f5d6dc8.tar.gz
add code for handling SOCKS5 bytestreams
Diffstat (limited to 'source')
-rw-r--r--source/QXmppByteStreamIq.cpp163
-rw-r--r--source/QXmppByteStreamIq.h84
-rw-r--r--source/QXmppSocks.cpp302
-rw-r--r--source/QXmppSocks.h83
-rw-r--r--source/source.pro4
5 files changed, 636 insertions, 0 deletions
diff --git a/source/QXmppByteStreamIq.cpp b/source/QXmppByteStreamIq.cpp
new file mode 100644
index 00000000..3f9f3ecb
--- /dev/null
+++ b/source/QXmppByteStreamIq.cpp
@@ -0,0 +1,163 @@
+/*
+ * Copyright (C) 2010 Bolloré telecom
+ *
+ * Author:
+ * Jeremy Lainé
+ *
+ * Source:
+ * http://code.google.com/p/qxmpp
+ *
+ * This file is a part of QXmpp library.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ */
+
+#include <QDomElement>
+
+#include "QXmppByteStreamIq.h"
+#include "QXmppConstants.h"
+#include "QXmppUtils.h"
+
+QHostAddress QXmppByteStreamIq::StreamHost::host() const
+{
+ return m_host;
+}
+
+void QXmppByteStreamIq::StreamHost::setHost(const QHostAddress &host)
+{
+ m_host = host;
+}
+
+QString QXmppByteStreamIq::StreamHost::jid() const
+{
+ return m_jid;
+}
+
+void QXmppByteStreamIq::StreamHost::setJid(const QString &jid)
+{
+ m_jid = jid;
+}
+
+quint16 QXmppByteStreamIq::StreamHost::port() const
+{
+ return m_port;
+}
+
+void QXmppByteStreamIq::StreamHost::setPort(quint16 port)
+{
+ m_port = port;
+}
+
+QXmppByteStreamIq::Mode QXmppByteStreamIq::mode() const
+{
+ return m_mode;
+}
+
+void QXmppByteStreamIq::setMode(QXmppByteStreamIq::Mode mode)
+{
+ m_mode = mode;
+}
+
+QString QXmppByteStreamIq::sid() const
+{
+ return m_sid;
+}
+
+void QXmppByteStreamIq::setSid(const QString &sid)
+{
+ m_sid = sid;
+}
+
+QList<QXmppByteStreamIq::StreamHost> QXmppByteStreamIq::streamHosts() const
+{
+ return m_streamHosts;
+}
+
+void QXmppByteStreamIq::setStreamHosts(const QList<QXmppByteStreamIq::StreamHost> &streamHosts)
+{
+ m_streamHosts = streamHosts;
+}
+
+QString QXmppByteStreamIq::streamHostUsed() const
+{
+ return m_streamHostUsed;
+}
+
+void QXmppByteStreamIq::setStreamHostUsed(const QString &jid)
+{
+ m_streamHostUsed = jid;
+}
+
+bool QXmppByteStreamIq::isByteStreamIq(QDomElement &element)
+{
+ return element.firstChildElement("query").namespaceURI() == ns_bytestreams;
+}
+
+void QXmppByteStreamIq::parse(QDomElement &element)
+{
+ setId(element.attribute("id"));
+ setFrom(element.attribute("from"));
+ setTo(element.attribute("to"));
+ setTypeFromStr(element.attribute("type"));
+
+ QDomElement queryElement = element.firstChildElement("query");
+ m_sid = queryElement.attribute("sid");
+ const QString modeStr = queryElement.attribute("mode");
+ if (modeStr == "tcp")
+ m_mode = Tcp;
+ else if (modeStr == "udp")
+ m_mode = Udp;
+ else
+ m_mode = None;
+
+ QDomElement hostElement = queryElement.firstChildElement("streamhost");
+ while (!hostElement.isNull())
+ {
+ StreamHost streamHost;
+ streamHost.setHost(QHostAddress(hostElement.attribute("host")));
+ streamHost.setJid(hostElement.attribute("jid"));
+ streamHost.setPort(hostElement.attribute("port").toInt());
+ m_streamHosts.append(streamHost);
+
+ hostElement = hostElement.nextSiblingElement("streamhost");
+ }
+ m_streamHostUsed = queryElement.firstChildElement("streamhost-used").attribute("jid");
+}
+
+void QXmppByteStreamIq::toXmlElementFromChild(QXmlStreamWriter *writer) const
+{
+ writer->writeStartElement("query");
+ helperToXmlAddAttribute(writer, "xmlns", ns_bytestreams);
+ helperToXmlAddAttribute(writer, "sid", m_sid);
+ QString modeStr;
+ if (m_mode == Tcp)
+ modeStr = "tcp";
+ else if (m_mode == Udp)
+ modeStr = "udp";
+ helperToXmlAddAttribute(writer, "mode", modeStr);
+ foreach (const StreamHost& streamHost, m_streamHosts)
+ {
+ writer->writeStartElement("streamhost");
+ helperToXmlAddAttribute(writer, "host", streamHost.host().toString());
+ helperToXmlAddAttribute(writer, "jid", streamHost.jid());
+ helperToXmlAddAttribute(writer, "port", QString::number(streamHost.port()));
+ writer->writeEndElement();
+ }
+ if (!m_streamHostUsed.isEmpty())
+ {
+ writer->writeStartElement("streamhost-used");
+ helperToXmlAddAttribute(writer, "jid", m_streamHostUsed);
+ writer->writeEndElement();
+ }
+
+ writer->writeEndElement();
+}
diff --git a/source/QXmppByteStreamIq.h b/source/QXmppByteStreamIq.h
new file mode 100644
index 00000000..294e2710
--- /dev/null
+++ b/source/QXmppByteStreamIq.h
@@ -0,0 +1,84 @@
+/*
+ * Copyright (C) 2010 Bolloré telecom
+ *
+ * Author:
+ * Jeremy Lainé
+ *
+ * Source:
+ * http://code.google.com/p/qxmpp
+ *
+ * This file is a part of QXmpp library.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ */
+
+#ifndef QXMPPBYTESTREAMIQ_H
+#define QXMPPBYTESTREAMIQ_H
+
+#include "QXmppIq.h"
+
+#include <QHostAddress>
+
+class QDomElement;
+class QXmlStreamWriter;
+
+class QXmppByteStreamIq : public QXmppIq
+{
+public:
+ enum Mode {
+ None = 0,
+ Tcp,
+ Udp,
+ };
+
+ class StreamHost
+ {
+ public:
+ QString jid() const;
+ void setJid(const QString &jid);
+
+ QHostAddress host() const;
+ void setHost(const QHostAddress &host);
+
+ quint16 port() const;
+ void setPort(quint16 port);
+
+ private:
+ QHostAddress m_host;
+ QString m_jid;
+ quint16 m_port;
+ };
+
+ QXmppByteStreamIq::Mode mode() const;
+ void setMode(QXmppByteStreamIq::Mode mode);
+
+ QString sid() const;
+ void setSid(const QString &sid);
+
+ QList<QXmppByteStreamIq::StreamHost> streamHosts() const;
+ void setStreamHosts(const QList<QXmppByteStreamIq::StreamHost> &streamHosts);
+
+ QString streamHostUsed() const;
+ void setStreamHostUsed(const QString &jid);
+
+ void parse(QDomElement &element);
+ void toXmlElementFromChild(QXmlStreamWriter *writer) const;
+ static bool isByteStreamIq(QDomElement &element);
+
+private:
+ Mode m_mode;
+ QString m_sid;
+ QList<StreamHost> m_streamHosts;
+ QString m_streamHostUsed;
+};
+
+#endif
diff --git a/source/QXmppSocks.cpp b/source/QXmppSocks.cpp
new file mode 100644
index 00000000..575a1102
--- /dev/null
+++ b/source/QXmppSocks.cpp
@@ -0,0 +1,302 @@
+/*
+ * Copyright (C) 2010 Bolloré telecom
+ *
+ * Author:
+ * Jeremy Lainé
+ *
+ * Source:
+ * http://code.google.com/p/qxmpp
+ *
+ * This file is a part of QXmpp library.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ */
+
+#include <QTcpServer>
+#include <QTcpSocket>
+
+#include "QXmppSocks.h"
+
+const static char SocksVersion = 5;
+
+enum AuthenticationMethod {
+ NoAuthentication = 0,
+ GSSAPI = 1,
+ UsernamePassword = 2,
+};
+
+enum Command {
+ ConnectCommand = 1,
+ BindCommand = 2,
+ AssociateCommand = 3,
+};
+
+enum AddressType {
+ IPv4Address = 1,
+ DomainName = 3,
+ IPv6Address = 4,
+};
+
+enum ReplyType {
+ Succeeded = 0,
+ SocksFailure = 1,
+ ConnectionNotAllowed = 2,
+ NetworkUnreachable = 3,
+ HostUnreachable = 4,
+ ConnectionRefused = 5,
+ TtlExpired = 6,
+ CommandNotSupported = 7,
+ AddressTypeNotSupported = 8,
+};
+
+QByteArray encodeHostAndPort(quint8 type, const QByteArray &host, quint16 port)
+{
+ QByteArray buffer;
+ buffer.resize(2);
+ // set host name
+ buffer[0] = type;
+ buffer[1] = host.size();
+ buffer.append(host);
+ // set port
+ int pos = buffer.size();
+ buffer.resize(pos + 2);
+ quint16 p = htons(port);
+ memcpy(buffer.data() + pos, &p, 2);
+ return buffer;
+}
+
+bool parseHostAndPort(const QByteArray buffer, quint8 &type, QByteArray &host, quint16 &port)
+{
+ if (buffer.size() < 4)
+ return false;
+
+ // parse host type
+ int pos = 0;
+ type = buffer.at(pos);
+ pos++;
+
+ // parse host name
+ quint8 hostLength = buffer.at(pos);
+ pos++;
+ if (buffer.size() < hostLength + 4)
+ {
+ qWarning("Invalid host length");
+ return false;
+ }
+ host = buffer.mid(pos, hostLength);
+ pos += hostLength;
+
+ // parse host port
+ quint16 p;
+ memcpy(&p, buffer.data() + pos, 2);
+ port = ntohs(p);
+ return true;
+}
+
+QXmppSocksClient::QXmppSocksClient(const QHostAddress &proxyAddress, quint16 proxyPort, QObject *parent)
+ : QObject(parent), m_proxyAddress(proxyAddress), m_proxyPort(proxyPort)
+{
+ m_socket = new QTcpSocket(this);
+}
+
+void QXmppSocksClient::connectToHost(const QString &hostName, quint16 hostPort)
+{
+ m_hostName = hostName;
+ m_hostPort = hostPort;
+ m_socket->connectToHost(m_proxyAddress, m_proxyPort);
+}
+
+QString QXmppSocksClient::errorString() const
+{
+ return m_socket->errorString();
+}
+
+QByteArray QXmppSocksClient::readAll()
+{
+ return m_socket->readAll();
+}
+
+bool QXmppSocksClient::waitForConnected(int msecs)
+{
+ if (!m_socket->waitForConnected(msecs))
+ return false;
+
+ // send connect to server
+ QByteArray buffer;
+ buffer.resize(3);
+ buffer[0] = SocksVersion;
+ buffer[1] = 0x01; // number of methods
+ buffer[2] = NoAuthentication;
+ m_socket->write(buffer);
+
+ // wait for connect to server response
+ if (!m_socket->waitForReadyRead(msecs))
+ return false;
+ buffer = m_socket->readAll();
+ if (buffer.size() != 2 || buffer.at(0) != SocksVersion || buffer.at(1) != NoAuthentication)
+ {
+ qWarning("QXmppSocksClient received an invalid response during handshake");
+ return false;
+ }
+
+ // send CONNECT command
+ buffer.resize(3);
+ buffer[0] = SocksVersion;
+ buffer[1] = ConnectCommand;
+ buffer[2] = 0x00; // reserved
+ buffer.append(encodeHostAndPort(
+ DomainName,
+ m_hostName.toAscii(),
+ m_hostPort));
+ m_socket->write(buffer);
+
+ // wait for CONNECT response
+ if (!m_socket->waitForReadyRead(msecs))
+ return false;
+ buffer = m_socket->readAll();
+ if (buffer.size() < 6 ||
+ buffer.at(0) != SocksVersion ||
+ buffer.at(1) != Succeeded ||
+ buffer.at(2) != 0)
+ {
+ qWarning("QXmppSocksClient received an invalid response to CONNECT command");
+ return false;
+ }
+
+ // parse host
+ quint8 hostType;
+ QByteArray hostName;
+ quint16 hostPort;
+ if (!parseHostAndPort(buffer.mid(3), hostType, hostName, hostPort))
+ {
+ qWarning("QXmppSocksClient could not parse type/host/port");
+ return false;
+ }
+ // FIXME : what do we do with the resulting name / port?
+
+ connect(m_socket, SIGNAL(disconnected()), this, SIGNAL(disconnected()));
+ connect(m_socket, SIGNAL(readyRead()), this, SIGNAL(readyRead()));
+ return true;
+}
+
+QXmppSocksServer::QXmppSocksServer(QObject *parent)
+ : QObject(parent),
+ m_hostPort(0),
+ m_socket(0)
+{
+ m_server = new QTcpServer(this);
+ connect(m_server, SIGNAL(newConnection()), this, SLOT(slotNewConnection()));
+}
+
+bool QXmppSocksServer::listen(const QHostAddress &address, quint16 port)
+{
+ return m_server->listen(address, port);
+}
+
+QHostAddress QXmppSocksServer::serverAddress() const
+{
+ return m_server->serverAddress();
+}
+
+quint16 QXmppSocksServer::serverPort() const
+{
+ return m_server->serverPort();
+}
+
+void QXmppSocksServer::slotNewConnection()
+{
+ m_socket = m_server->nextPendingConnection();
+ if (!m_socket)
+ return;
+
+ // wait for connect to server
+ if (!m_socket->waitForReadyRead())
+ return;
+ QByteArray buffer = m_socket->readAll();
+ if (buffer.size() < 3 ||
+ buffer.at(0) != SocksVersion ||
+ buffer.at(1) != 0x01 ||
+ buffer.at(2) != NoAuthentication)
+ {
+ qWarning("QXmppSocksServer received invalid handshake");
+ m_socket->close();
+ return;
+ }
+
+ // send connect to server response
+ buffer.resize(2);
+ buffer[0] = SocksVersion;
+ buffer[1] = NoAuthentication;
+ m_socket->write(buffer);
+
+ // wait for connect command
+ if (!m_socket->waitForReadyRead())
+ return;
+ buffer = m_socket->readAll();
+ if (buffer.size() < 4 ||
+ buffer.at(0) != SocksVersion ||
+ buffer.at(1) != ConnectCommand ||
+ buffer.at(2) != 0x00)
+ {
+ qWarning("QXmppSocksServer received an invalid command");
+ m_socket->close();
+ return;
+ }
+
+ // parse host
+ quint8 hostType;
+ QByteArray hostName;
+ quint16 hostPort;
+ if (!parseHostAndPort(buffer.mid(3), hostType, hostName, hostPort))
+ {
+ qWarning("QXmppSocksServer could not parse type/host/port");
+ m_socket->close();
+ return;
+ }
+ if (hostName != m_hostName || hostPort != m_hostPort)
+ {
+ qWarning("QXmppSocksServer got wrong host or port");
+ m_socket->close();
+ return;
+ }
+
+ //send connect response
+ buffer.resize(3);
+ buffer[0] = SocksVersion;
+ buffer[1] = Succeeded;
+ buffer[2] = 0x00;
+ buffer.append(encodeHostAndPort(
+ DomainName,
+ m_server->serverAddress().toString().toAscii(),
+ m_server->serverPort()));
+ m_socket->write(buffer);
+
+ // connect signals
+ connect(m_socket, SIGNAL(disconnected()), this, SIGNAL(disconnected()));
+ connect(m_socket, SIGNAL(bytesWritten(qint64)), this, SIGNAL(bytesWritten(qint64)));
+}
+
+void QXmppSocksServer::setHostName(const QString &hostName)
+{
+ m_hostName = hostName;
+}
+
+void QXmppSocksServer::setHostPort(quint16 hostPort)
+{
+ m_hostPort = hostPort;
+}
+
+void QXmppSocksServer::write(const QByteArray &data)
+{
+ if (m_socket)
+ m_socket->write(data);
+}
diff --git a/source/QXmppSocks.h b/source/QXmppSocks.h
new file mode 100644
index 00000000..f9a7e71c
--- /dev/null
+++ b/source/QXmppSocks.h
@@ -0,0 +1,83 @@
+/*
+ * Copyright (C) 2010 Bolloré telecom
+ *
+ * Author:
+ * Jeremy Lainé
+ *
+ * Source:
+ * http://code.google.com/p/qxmpp
+ *
+ * This file is a part of QXmpp library.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ */
+
+#ifndef QXMPPSOCKS_H
+#define QXMPPSOCKS_H
+
+#include <QHostAddress>
+#include <QObject>
+
+class QTcpServer;
+class QTcpSocket;
+
+class QXmppSocksClient : public QObject
+{
+ Q_OBJECT
+
+public:
+ QXmppSocksClient(const QHostAddress &proxyAddress, quint16 proxyPort, QObject *parent=0);
+ void connectToHost(const QString &hostName, quint16 hostPort);
+ QString errorString() const;
+ QByteArray readAll();
+ bool waitForConnected(int msecs = 30000);
+
+signals:
+ void disconnected();
+ void readyRead();
+
+private:
+ QHostAddress m_proxyAddress;
+ quint16 m_proxyPort;
+ QString m_hostName;
+ quint16 m_hostPort;
+ QTcpSocket *m_socket;
+};
+
+class QXmppSocksServer : public QObject
+{
+ Q_OBJECT
+
+public:
+ QXmppSocksServer(QObject *parent=0);
+ bool listen(const QHostAddress &address, quint16 port = 0);
+ QHostAddress serverAddress() const;
+ quint16 serverPort() const;
+ void setHostName(const QString &hostName);
+ void setHostPort(quint16 hostPort);
+ void write(const QByteArray &data);
+
+signals:
+ void bytesWritten(qint64);
+ void disconnected();
+
+private slots:
+ void slotNewConnection();
+
+private:
+ QString m_hostName;
+ quint16 m_hostPort;
+ QTcpServer *m_server;
+ QTcpSocket *m_socket;
+};
+
+#endif
diff --git a/source/source.pro b/source/source.pro
index 7d1368a8..52037813 100644
--- a/source/source.pro
+++ b/source/source.pro
@@ -17,6 +17,7 @@ HEADERS += QXmppUtils.h \
QXmppArchiveIq.h \
QXmppArchiveManager.h \
QXmppBind.h \
+ QXmppByteStreamIq.h \
QXmppClient.h \
QXmppConfiguration.h \
QXmppConstants.h \
@@ -30,6 +31,7 @@ HEADERS += QXmppUtils.h \
QXmppRoster.h \
QXmppRosterIq.h \
QXmppSession.h \
+ QXmppSocks.h \
QXmppStanza.h \
QXmppStream.h \
QXmppStreamInitiationIq.h \
@@ -51,6 +53,7 @@ SOURCES += QXmppUtils.cpp \
QXmppArchiveIq.cpp \
QXmppArchiveManager.cpp \
QXmppBind.cpp \
+ QXmppByteStreamIq.cpp \
QXmppClient.cpp \
QXmppConfiguration.cpp \
QXmppConstants.cpp \
@@ -64,6 +67,7 @@ SOURCES += QXmppUtils.cpp \
QXmppRoster.cpp \
QXmppRosterIq.cpp \
QXmppSession.cpp \
+ QXmppSocks.cpp \
QXmppStanza.cpp \
QXmppStream.cpp \
QXmppStreamInitiationIq.cpp \