LINUX.ORG.RU

QTcpSocket и прозрачный прокси

 , , ,


0

2

Все доброе утро! Недавно переписал свое приложение с pyqt4 на C++/Qt5. В своем приложении как и раньше использую унаследованный класс от QTcpSocket. Вот пример функции приема:

void TcpSocket :: slotRecvData() {
    QString                     buf;
    QMap<QString, QVariant>     map;
    QJsonDocument               doc;

    log -> set_param("SESSION", "Server");

    while(this -> bytesAvailable())
        try {
            buf = this -> readAll();
            if(!data.isEmpty()) {
                data += buf;
            }
            else {
                parseHeader(buf);
            }

            while(true) {
                if(data.size() < totalSize) {
                    break;
                }
                else if(data.size() > totalSize) {
                    doc = QJsonDocument::fromJson(data.left(totalSize).toLocal8Bit().data());
                    log -> debug() << totalSize << "|" << doc.toJson().data() << '\n';
                    map = doc.toVariant().toMap();
                    emit dataReceived(map);
                    data = data.mid(totalSize);
                    parseHeader(data);
                }
                else {
                    doc = QJsonDocument::fromJson(data.toLocal8Bit().data());
                    log -> debug() << totalSize << "|" << doc.toJson().data() << '\n';
                    map = doc.toVariant().toMap();
                    emit dataReceived(map);
                    data.clear();
                    totalSize = 0;
                    break;
                }
            }
        }
        catch (NetworkHeaderException &s) {
            log -> error() << "Error while recv cmd: " << s.what() << '\n';
            log -> error() << "Ошибка данных сети: " << buf.toStdString() << "\n";
            data.clear();
            totalSize = 0;
            setSocketError(QAbstractSocket::ProxyConnectionRefusedError);
            disconnectFromHost();
            break;
        }
}

void TcpSocket :: parseHeader(QString &buf) {
    int index = buf.indexOf('|');
    if(index == -1) {
        throw NetworkHeaderException();
    }
    bool    res;
    totalSize = buf.left(index).toInt(&res);
    if(!res) {
        throw NetworkHeaderException();
    }
    data = buf.mid(index + 1);
}

На питоне эта функция имеет такой же вид, но только синтаксис другой (Я это функцию просто переписал на плюсы). Проблема в следующем. Когда начали деплоить приложение, выяснилось, что у многих наших клиентов включен прозрачный прокси. Наше приложение работает по портам 80, 8080 и 443. Так вот, приложение подключается нормально, далее следует выдача первой команды, а в ответ прилетает http ответ 404. Но у нас свой протокол (не http - <size>|<payload>). Из-за этого приложение не может нормально работать. Если запускать тоже самое, но написанное на питоне, то приложение работает как надо...Совсем не понимаю в чем дело



Последнее исправление: beastie (всего исправлений: 2)

Наше приложение работает по портам 80, 8080 и 443.

А зачем вешать своё приложение на стандартный порт?

UVV ★★★★★
()
Ответ на: комментарий от UVV

А зачем вешать своё приложение на стандартный порт?

Удваиваю.

Pavval ★★★★★
()

это вам кара за использование портов не по назначению и изобретение велосипедов вместо http@QNetworkAccessManager

dib2 ★★★★★
()
Ответ на: комментарий от unfo

Ну по идее советы должны работать одинаково...

energyclab
() автор топика
Ответ на: комментарий от UVV

Просто изначально выяснилось, что у многих наших клиентов почти все порты закрыты, и разработчики до меня договорились использовать стандартные порты... В итоге то мы добавили свой порт, но просто мне совсем не понятно, из-за чего такое поведение...раньше все работало sudo cast energyclab

energyclab
() автор топика
Ответ на: комментарий от energyclab

sudo cast energyclab

Забавно ты себя кастанул. Я такого фейла ещё не ожидал.

UVV ★★★★★
()
Ответ на: комментарий от energyclab

В итоге то мы добавили свой порт, но просто мне совсем не понятно, из-за чего такое поведение

Из-за того, что ты перехватываешь поток данных, предназначенных не тебе. И.О. КО.

UVV ★★★★★
()
Последнее исправление: UVV (всего исправлений: 1)
Ответ на: комментарий от UVV

Из-за того, что ты перехватываешь поток данных, предназначенных не тебе. И.О. КО.

ну как же так? Мое подключение ловит прокси сервер (более того, он даже не пытается подключиться дальше на наш сервер...). потом он почему то палит, что на 80 порту не http трафик и шлет мне ответ - http страничку... на каком основании? запроса то не было...И как это тогда раньше работало...

energyclab
() автор топика
Ответ на: комментарий от energyclab

перевести на другие порты (что правильно) или настраивайте файерволы на каждом клиенте (можно за отдельные большие деньги), чтобы ваш трафик не попадал в http прокси (который/которая не в курсе вашего еретичного протокола и потому матерится).

MKuznetsov ★★★★★
()
Ответ на: комментарий от energyclab

Просто изначально выяснилось, что у многих наших клиентов почти все порты закрыты и разработчики до меня ...

зафейлились капитально, на базовых знаниях.
рано или поздно вы наткнетесь на закрытые порты/отсутствие шлюза, и выход в инет _только_ через прокси. Используйте http(s) и будет вам счастие.
можете попробовать обернуть свой протокол в http CONNECT, но наткнетесь что половина прокси его либо криво, либо не умеют (не настроено). И дай Бог вам не встретить на пути ISA с NTLMv2 аутентификацией и прочими ужасами.

dib2 ★★★★★
()
Ответ на: комментарий от dib2

Ну а почему же клиент, написанный на питоне, не выявлял проблем? Там ничего онного не было...все тоже самое

    def recvMessage(self):
        while self.bytesAvailable():
            try:
                data = self.readAll()
                if self.buffer['array']:
                    self.buffer['array'].append(data)
                else:
                    self.buffer['len'], self.buffer['array'] = self.parse_header(data)

                while True:
                    if len(self.buffer['array']) < self.buffer['len']:
                        break
                    elif len(self.buffer['array']) > self.buffer['len']:
                        data = loads(self.buffer['array'][:self.buffer['len']].data())
                        self.emit(Qt.SIGNAL('data_ready'), data)
                        data = self.buffer['array'][self.buffer['len']:]
                        self.buffer['len'], self.buffer['array'] = self.parse_header(data)
                    else:
                        data = loads(self.buffer['array'][:self.buffer['len']].data())
                        self.emit(Qt.SIGNAL('data_ready'), data)
                        self.buffer['array'].clear()
                        self.buffer['len'] = 0
                        break
            except TypeError as e:
                self.logErr('TCP read data failed: %s' % e.message)

    def parse_header(self, data):
        index = data.indexOf('|')
        if index == -1:
            raise TypeError('\'|\' not found')
        return (int(data[:index]), data[index + 1:])
sudo cast MKuznetsov

energyclab
() автор топика
Ответ на: комментарий от energyclab

просмотри трафик wireshark или tcpdump - найди разницу

dib2 ★★★★★
()
Ответ на: комментарий от energyclab

чуть выше (про tcpdump) уже ответили..

перевожу, долее детально:

есть подозрение, что питоновская библиотека детектит прокси(или это делает тупо для стандартных портов), подкладывает нужные заголовки, в результате чего (и непрочтения питовской документации) вы немного неправильно портировали софт с питона в C++.

другое подозрение - ваш «протокол» использует 2 соединения.

в любом случае это tcpdump в руки и детская задача «найди отличия».

MKuznetsov ★★★★★
()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.