powered by simpleCommunicator - 2.0.61     © 2026 Programmizd 02
Целевая тема:
Создать новую тему:
Автор:
Закрыть
Цитировать
Форумы / C++ [игнор отключен] [закрыт для гостей] / C++/Linux перехватчик CONNECT, отладка
6 сообщений из 6, страница 1 из 1
C++/Linux перехватчик CONNECT, отладка
    #34576496
ErV
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Есть программа (самодельная), которая должна (по идее) запускаться вместе с системой (под правами рута) и работать до её выключения без вмешательства.
Программа работает как "тупая" http-прокся, которая понимает один запрос - "CONNECT", отлавливает его, изменяет адрес сервера назначения и пересылает запрос на другую проксю,
после чего открывает и поддерживает туннель.
Проблема в том, что несколько раз в неделю она вываливается с Segmentation Fault, из-за чего её приходится перезапускать вручную.

Вопрос: как можно найти глюк? Программа многопоточная, иначе можно было бы запустить её при помощи gdb.
Какие ещё есть варианты? Как отловить адрес ошибки в самой программе?
Буду признателен за линки/"указатели направления"/RTFM с указанием FM и т.д.

Исходники ниже.
Написана через месяц после перехода на систему, изначально портирована с Win/MSVC2005, из-за этого
в кода местами бардак.:
main.cpp:
Код: plaintext
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
27.
28.
29.
30.
31.
32.
33.
34.
35.
36.
37.
38.
39.
40.
41.
42.
43.
44.
45.
46.
47.
48.
49.
50.
51.
52.
53.
54.
55.
56.
57.
58.
59.
60.
61.
62.
63.
64.
65.
66.
67.
68.
69.
70.
71.
72.
73.
74.
75.
76.
77.
78.
79.
80.
81.
82.
83.
84.
85.
86.
87.
88.
89.
90.
91.
92.
93.
94.
95.
96.
97.
98.
99.
100.
101.
102.
103.
104.
105.
106.
107.
108.
109.
110.
111.
112.
113.
114.
115.
116.
117.
118.
119.
120.
121.
122.
123.
124.
125.
126.
127.
128.
129.
130.
131.
132.
133.
134.
135.
136.
137.
138.
139.
140.
141.
142.
143.
144.
145.
146.
147.
148.
149.
150.
151.
152.
153.
154.
155.
156.
157.
158.
159.
160.
161.
162.
163.
164.
165.
166.
167.
168.
169.
170.
171.
172.
173.
174.
175.
176.
177.
178.
179.
180.
181.
182.
183.
184.
185.
186.
187.
188.
189.
190.
191.
192.
193.
194.
195.
196.
197.
198.
199.
200.
201.
202.
203.
204.
205.
206.
207.
208.
209.
210.
211.
212.
213.
214.
215.
216.
217.
218.
219.
220.
221.
222.
223.
224.
225.
226.
227.
228.
229.
230.
231.
232.
233.
234.
235.
236.
237.
238.
239.
240.
241.
242.
243.
244.
245.
246.
247.
248.
249.
250.
251.
252.
253.
254.
255.
256.
257.
258.
259.
260.
261.
262.
263.
264.
265.
266.
267.
268.
269.
270.
271.
272.
273.
274.
275.
276.
277.
278.
279.
280.
281.
282.
283.
284.
285.
286.
287.
288.
289.
290.
291.
292.
293.
294.
295.
296.
297.
298.
299.
300.
301.
302.
303.
304.
305.
306.
307.
308.
309.
310.
311.
312.
313.
314.
315.
316.
317.
318.
319.
320.
321.
322.
323.
324.
325.
326.
327.
328.
329.
330.
331.
332.
333.
334.
335.
336.
337.
338.
339.
340.
341.
342.
343.
344.
345.
346.
347.
#include <stdio.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <unistd.h>
#include <ctype.h>
#include <netdb.h>
//#include <winsock2.h>
#include <netinet/in.h>
#include <memory.h>
#include <arpa/inet.h>
#include "buffer.h"
#include <errno.h>
#include <pthread.h>
#include <signal.h>

typedef unsigned long DWORD;
//#pragma comment(lib, "Ws2_32.lib")

SOCKET input = INVALID_SOCKET;
int portIndex =  8100 ;
bool running = true;

const char* proxyAddr = "80.82.32.27";//"cache.vsi.ru";
const int proxyPort =  3128 ;
/*const char* proxyAddr = "128.0.0.1";
const int proxyPort = 8080;*/


inline bool strCmp(const char* str1, const char* str2){
        if (!str1||!str2) return false;
        while ((*str1)&&(*str2)){
                if ((*(str1++))!=(*(str2++)))
                        return false;
        }
        if (*str1 != *str2) return false;
        return true;
}

void sigHandler (int sigNum){
        //fprintf(stderr, "shutting
        running = false;
}

SOCKET bindPort(int port){
    SOCKET result;
    struct sockaddr_in addr;

    if((result = socket(AF_INET, SOCK_STREAM, 0)) == INVALID_SOCKET){
        fprintf(stderr, "Create socket failed.\n");
        return INVALID_SOCKET;
    }

    memset(&addr, 0, sizeof(addr));
    addr.sin_family = AF_INET;
    addr.sin_port = htons(port);
    addr.sin_addr.s_addr = INADDR_ANY;

    if(bind(result, (struct sockaddr*)&addr, sizeof(addr)) == SOCKET_ERROR){
        fprintf(stderr, "bind() failed.\nreason: %s\n\n", strerror(errno));
        return INVALID_SOCKET;
    }

    if(listen(result, 1) == SOCKET_ERROR){
        fprintf(stderr, "listen() failed.\nreason: %s\n\n", strerror(errno));
        return INVALID_SOCKET;
    }

    return result;
}

struct TunnelData{
        SOCKET src;
        SOCKET dest;
        TunnelData(void){
                src = dest = INVALID_SOCKET;
        }
        TunnelData(const SOCKET _src, const SOCKET _dest)
                :src(_src), dest(_dest){
        }
};

//DWORD WINAPI TunnelThread(void* p){
void* tunnelThread(void* p){
        TunnelData* tunnelData = (TunnelData*)p;
        SOCKET src = tunnelData->src;
        SOCKET dest = tunnelData->dest;
        char tmp[4096];
        while(true){
                //int size = recv(src, tmp, sizeof(tmp), 0);
                int size = read(src, tmp, sizeof(tmp));
                if (size == 0){
                        write(dest, 0, 0);
                        //send(dest, 0, 0, 0);
                        break;//connection closed;
                }
                
                if (size < 0)
                        break;
                /*if (size == SOCKET_ERROR){
                        if (WSAGetLastError() == WSAECONNRESET)
                                continue;
                        break;
                }*/

                int offset = 0;
                while(offset < size){
                        //int sent = send(dest, &tmp[offset], size - offset, 0);
                        int sent = write(dest, &tmp[offset], size - offset);
                        
                        if ((sent == SOCKET_ERROR)||(sent == 0))
                                break;

                        offset += sent;
                }

                if (offset < size)
                        break;
        }

        shutdown(src, SHUT_RD);//SD_RECEIVE);
        shutdown(dest, SHUT_WR);//SD_SEND);
//      delete tunnelData;
        return 0;
}

struct ConnectionData{
        SOCKET socket;
        sockaddr_in srcAddr;
        sockaddr_in destAddr;
        ConnectionData(const SOCKET _socket, const sockaddr_in& _srcAddr, const sockaddr_in& _destAddr){
                socket = _socket;
                srcAddr = _srcAddr;
                destAddr = _destAddr;
        }
};

void printAddress(const sockaddr_in& addr){
        union{
                DWORD dw;
                unsigned char c[4];
        } from;
        from.dw = ntohl(addr.sin_addr.s_addr);
        fprintf(stderr, "access from %d.%d.%d.%d\n", from.c[3], from.c[2], from.c[1], from.c[0]);
}

struct Filter{
        const char* oldStr;
        const char* newStr;
};

const Filter filters[] = {
        {"CONNECT vir1a.toonel.net:8081 HTTP/1.1\r\n\r\n", "CONNECT vir1a.toonel.net:443 HTTP/1.1\r\n\r\n"},
        {"CONNECT dub1.toonel.net:8081 HTTP/1.1\r\n\r\n", "CONNECT vir1a.toonel.net:443 HTTP/1.1\r\n\r\n"},
        {"CONNECT vir1b.toonel.net:8081 HTTP/1.1\r\n\r\n", "CONNECT vir1a.toonel.net:443 HTTP/1.1\r\n\r\n"},
        {"CONNECT vir1a.toonel.net:8081 HTTP/1.1\n\n", "CONNECT vir1a.toonel.net:443 HTTP/1.1\r\n\r\n"},
        {"CONNECT dub1.toonel.net:8081 HTTP/1.1\n\n", "CONNECT vir1a.toonel.net:443 HTTP/1.1\r\n\r\n"},
        {"CONNECT vir1b.toonel.net:8081 HTTP/1.1\n\n", "CONNECT vir1a.toonel.net:443 HTTP/1.1\r\n\r\n"},
        {0, 0}
};

void processConnection(const SOCKET srcSock, const sockaddr_in& srcAddr, const sockaddr_in& destAddr){
        printAddress(srcAddr);

        fprintf(stderr, "creating proxy socket\n");
        SOCKET destSock = socket(AF_INET, SOCK_STREAM, 0);
        if (destSock == INVALID_SOCKET){
                fprintf(stderr, "can't create proxy socket!\n");
                shutdown(srcSock, SHUT_RD);//SD_BOTH);
                //closesocket(srcSock);
                close(srcSock);
                return;
        }

        fprintf(stderr, "connecting dest socket\n");
        if (connect(destSock, (const sockaddr*)&destAddr, sizeof(destAddr)) != 0){
                fprintf(stderr, "can't connect dest proxy!\n");
                shutdown(srcSock, SHUT_RDWR);//SD_BOTH);
                //closesocket(srcSock);
                //closesocket(destSock);
                return;
        }

        fprintf(stderr, "reading http data\n");
        Buffer buf;
        buf.appendHttp(srcSock);
        buf.append('\0');
        
        for (const Filter* filter = filters; filter->oldStr; filter++){
                if (strCmp(filter->oldStr, buf.getData())==0){
                        buf.clear();
                        buf.append(filter->newStr);
                        buf.append('\0');
                        fprintf(stderr, "filter found\n");
                        break;
                }
        }
        fprintf(stderr, "client said:\n%s\nretrasmitting to proxy\n", buf.getData());

        //send(destSock, buf.getData(), buf.getSize()-1, 0);
        write(destSock, buf.getData(), buf.getSize()-1);

        buf.clear();
        buf.appendHttp(destSock);
        buf.append('\0');

        fprintf(stderr, "proxy answered:\n%s\nretrasmitting to client\n", buf.getData());

        write(srcSock, buf.getData(), buf.getSize()-1);
        //send(srcSock, buf.getData(), buf.getSize()-1, 0);

        fprintf(stderr, "starting tunnels\n");

        /*HANDLE threads[2];
        threads[0] = CreateThread(0, 0, TunnelThread, new TunnelData(srcSock, destSock), 0, 0);
        threads[1] = CreateThread(0, 0, TunnelThread, new TunnelData(destSock, srcSock), 0, 0);
        WaitForMultipleObjects(2, threads, TRUE, INFINITE);

        CloseHandle(threads[0]);
        CloseHandle(threads[1]);*/

        pthread_t threads[2];
        TunnelData tunnelData[2];
        tunnelData[0].src = srcSock;
        tunnelData[0].dest = destSock;
        tunnelData[1].src = destSock;
        tunnelData[1].dest = srcSock;
        
        pthread_create(&threads[0], 0, tunnelThread, &tunnelData[0]);
        pthread_create(&threads[1], 0, tunnelThread, &tunnelData[1]);
        pthread_join(threads[0], 0);
        pthread_join(threads[1], 0);

        //closesocket(destSock);
        close(destSock);
        //closesocket(srcSock);
        close(srcSock);
}

void* /*DWORD WINAPI*/ threadProc(void* p){
        ConnectionData* connectionData = (ConnectionData*)p;
        processConnection(connectionData->socket, connectionData->srcAddr, connectionData->destAddr);
        delete connectionData;
        //return 0;
}

void mainLoop(const sockaddr_in& proxyAddr){
        fprintf(stderr, "main loop started\n");
        while (running){
                sockaddr_in srcAddr;
                //int len = sizeof(srcAddr);
                socklen_t len = sizeof(srcAddr);
                SOCKET incoming = accept(input, (sockaddr*)&srcAddr, &len);
                if (incoming == INVALID_SOCKET){
                        //int wsaError = WSAGetLastError();
                        //if (wsaError == WSAEINTR)
                        int errorNum = errno;
                        if (errorNum == EINTR)
                                continue;
                        fprintf(stderr, "Cannot accept request, error index: %d\n", errorNum);//wsaError);
                        break;
                }

                fprintf(stderr, "new connection.\n");
                
                ConnectionData* connectionData = new ConnectionData(incoming, srcAddr, proxyAddr);
                //DWORD threadId;
                //HANDLE thread = CreateThread(0, 0, threadProc, (void*)connectionData, 0, &threadId);
                //CloseHandle(thread);
                pthread_t thread;
                pthread_create(&thread, 0, threadProc, (void*)connectionData);//TODO very dangerous
                //threadProc(connectionData);
        }
        fprintf(stderr, "main loop completed\n");
}

/*BOOL WINAPI ctrlHandler(DWORD ctrlType){
        fprintf("shutting down the app\n");
        running = false;
        
        closesocket(input);
        input = INVALID_SOCKET;
        
        return TRUE;
}*/

bool isAddr(const char* p){
        for (;*p; p++){
                char c = *p;
                if (isdigit(c) == 0)
                        if (c != '.')
                                return false;
        }
        return true;
}

bool getProxyAddr(sockaddr_in& saddr, const char* addr, const int port){
        hostent* host;
        if (isAddr(addr)){
                unsigned long inetAddr = inet_addr(addr);
                host = gethostbyaddr((char*)&inetAddr, 4, AF_INET);
        }
        else
                host = gethostbyname(addr);
        if (!host) return false;
        saddr.sin_family = AF_INET;
        saddr.sin_port = htons(port);
        memcpy(&saddr.sin_addr.s_addr, host->h_addr, host->h_length);
        /*saddr.sin_addr.S_un.S_un_b.s_b1 = host->h_addr[0];
        saddr.sin_addr.S_un.S_un_b.s_b2 = host->h_addr[1];
        saddr.sin_addr.S_un.S_un_b.s_b3 = host->h_addr[2];
        saddr.sin_addr.S_un.S_un_b.s_b4 = host->h_addr[3];*/
        return true;
}

int main(void){
        fprintf(stderr, "this is a simple windows redirector\n");
        //WSADATA wsaData;
        //WSAStartup(MAKEWORD(2, 2), &wsaData);
        
        sockaddr_in proxySAddr;
        if (!getProxyAddr(proxySAddr, proxyAddr, proxyPort)){
                fprintf(stderr, "getProxyAddr(\"%s\") failed.\n", proxyAddr);
                //WSACleanup();
                return 0;
        }

        input = bindPort(portIndex);
        //SetConsoleCtrlHandler(ctrlHandler, true);
        struct sigaction sa;
        memset(&sa, 0, sizeof(sa));
        sa.sa_handler = sigHandler;
        sigaction(SIGINT, &sa, 0);
        sigaction(SIGTERM, &sa, 0);

        if (input != INVALID_SOCKET){
                mainLoop(proxySAddr);
                if (input != INVALID_SOCKET)
                        close/*socket*/(input);
                fprintf(stderr, "closing down app...\n");
        }
        else
                fprintf(stderr, "an error has occured\n");

        //WSACleanup();
        return  0 ;
}


buffer.h
Код: plaintext
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
27.
28.
29.
30.
31.
32.
//#pragma once
#ifndef _BUFFER_H_
#define _BUFFER_H_

typedef unsigned long dword;

typedef int SOCKET;
#define SOCKET_ERROR - 1 
#define INVALID_SOCKET - 1 

class Buffer{
protected:
        char* data;
        dword size;
        dword capacity;
        dword  increment;

public:
        inline dword getSize(void){return size;}
        inline const char* getData(void) const {return data;}

        void clear(void);
        void grow(void);
        void append(const char* src, dword size);
        void append(const char* src);
        void append(const char c);
        bool appendHttp(SOCKET src);//true if succesful
        Buffer(dword capacity = 0x1000, dword increment =  0 );
        ~Buffer(void);
};

#endif //_BUFFER_H_

buffer.cpp
Код: plaintext
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
27.
28.
29.
30.
31.
32.
33.
34.
35.
36.
37.
38.
39.
40.
41.
42.
43.
44.
45.
46.
47.
48.
49.
50.
51.
52.
53.
54.
55.
56.
57.
58.
59.
60.
61.
62.
63.
64.
65.
66.
67.
68.
69.
70.
71.
72.
73.
74.
75.
76.
77.
78.
79.
//#include <winsock2.h>
//#include <stdio.h>
#include <sys/socket.h>
#include <sys/types.h>
#include "buffer.h"
#include <memory.h>
#include <errno.h>
//#include <string.h>

void Buffer::grow(void){
        dword newCapacity = increment ? capacity + increment: capacity *  2 ;
        char* newData = new char[newCapacity];
        memcpy(newData, data, size);
        delete[] data;
        data = newData;
}

Buffer::Buffer(dword _capacity, dword _increment)
:size( 0 ), capacity(_capacity), increment(_increment), data( 0 ){
        data = new char[capacity];
}

void Buffer::clear(void){
        size =  0 ;
}

Buffer::~Buffer(void){
        delete[] data;
}

void Buffer::append(const char* src, dword srcsize){
        while (size + srcsize > capacity)
                grow();//TODO НОЮЯМН.
        memcpy(&data[size], src, srcsize);
        size += srcsize;
}

void Buffer::append(const char* src){
        dword size = (dword)strlen(src);
        append(src, size);
}

void Buffer::append(const char c){
        append(&c,  1 );
}

bool Buffer::appendHttp(SOCKET src){
        int startSize = size;
        for (int dataSize =  0 ; true;){
                char tmp[ 4096 ];
                if ((size-startSize) >=  4 )
                        if (memcmp(&data[size- 4 ], "\r\n\r\n",  4 )== 0 )
                                break;

                if ((size-startSize) >=  2 )
                        //if (*((dword*)&data[size-4]) == 0x0a0d0a0d)
                        if (memcmp(&data[size- 2 ], "\n\n",  2 )== 0 )
                                break;

                //dataSize = read(src, tmp, sizeof(tmp));
                dataSize = recv(src, tmp, sizeof(tmp),  0 );
                if (dataSize ==  0 )
                        break;

                if (dataSize == SOCKET_ERROR)
                    return false;
                    /*if (WSAGetLastError() == WSAECONNRESET)
                        if (errno == ECONNRESET
                                continue;
                        else{
                                //TODO: size = startSize?
                                return false;
                        }*/
                
                
                append(tmp, dataSize);
        }
        return true;
}

Makefile:
Код: plaintext
1.
2.
3.
4.
5.
6.
7.
CXXFLAGS=-O2

redirector: main.o buffer.o
        g++ -o redirector -g main.o buffer.o -lpthread

clean: 
        rm -f main.o buffer.o redirector

Буду рад выслушать любые замечания по коду.
Posted via ActualForum NNTP Server 1.4
...
Рейтинг: 0 / 0
C++/Linux перехватчик CONNECT, отладка
    #34578805
White Owl
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
ErVБуду рад выслушать любые замечания по коду.На первый взгляд видна смесь С и С++. А это никогда не приводит к хорошим результатам.
...
Рейтинг: 0 / 0
C++/Linux перехватчик CONNECT, отладка
    #34579073
ErV
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
White Owl wrote:

> На первый взгляд видна смесь С и С++.
Ну, так ведь libpthread - сишная, потому и смесь получается...

Что, получается - переписывать на C/malloc/realloc или на C++/QThread?
Posted via ActualForum NNTP Server 1.4
...
Рейтинг: 0 / 0
C++/Linux перехватчик CONNECT, отладка
    #34579098
Фотография blinded
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Ну можно и самому обернуть. Можно взять JTC или АСЕ
...
Рейтинг: 0 / 0
C++/Linux перехватчик CONNECT, отладка
    #34579355
White Owl
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
ErVЧто, получается - переписывать на C/malloc/realloc или на C++/QThread?я бы начал с этого... разбираться в плавающих глюках возникающих в смесях меня никогда не привлекало. И лично я бы взял первый вариант... Но это я :)
...
Рейтинг: 0 / 0
C++/Linux перехватчик CONNECT, отладка
    #34579441
ErV
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
White Owl wrote:

> я бы начал с этого... разбираться в плавающих глюках возникающих в смесях
> меня никогда не привлекало. И лично я бы взял первый вариант... Но это я
> :)
Ладно, буду пробовать... (все равно эту прогу давно почистить надо было...)
Posted via ActualForum NNTP Server 1.4
...
Рейтинг: 0 / 0
6 сообщений из 6, страница 1 из 1
Форумы / C++ [игнор отключен] [закрыт для гостей] / C++/Linux перехватчик CONNECT, отладка
Найденые пользователи ...
Разблокировать пользователей ...
Читали форум (0):
Пользователи онлайн (0):
x
x
Закрыть


Просмотр
0 / 0
Close
Debug Console [Select Text]