source: verona/libeXosip2/src/eXtl_socks.c @ 390:8b9307bf45b3

Last change on this file since 390:8b9307bf45b3 was 390:8b9307bf45b3, checked in by Vadim Lebedev <vadim@…>, 17 months ago

implement socks5 negotiation

File size: 24.1 KB
Line 
1/*
2  eXosip - This is the eXtended osip library.
3  Copyright (C) 2002,2003,2004,2005,2006,2007  Aymeric MOIZARD  - jack@atosc.org
4  Socks support Copyright (C) 2011  MBDSYS  - (vadim@mbdsys.com)
5 
6  eXosip is free software; you can redistribute it and/or modify
7  it under the terms of the GNU General Public License as published by
8  the Free Software Foundation; either version 2 of the License, or
9  (at your option) any later version.
10 
11  eXosip is distributed in the hope that it will be useful,
12  but WITHOUT ANY WARRANTY; without even the implied warranty of
13  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  GNU General Public License for more details.
15 
16  You should have received a copy of the GNU General Public License
17  along with this program; if not, write to the Free Software
18  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
19*/
20
21
22#ifdef ENABLE_MPATROL
23#include <mpatrol.h>
24#endif
25
26#include "eXosip2.h"
27#include "eXtransport.h"
28
29#ifdef HAVE_FCNTL_H
30#include <fcntl.h>
31#endif
32
33#ifdef WIN32
34#include <Mstcpip.h>
35#else
36#define closesocket close
37#endif
38
39#if defined(_WIN32_WCE) || defined(WIN32)
40#define strerror(X) "-1"
41#define ex_errno WSAGetLastError()
42#else
43#define ex_errno errno
44#endif
45
46#ifndef EAGAIN
47#define EAGAIN WSAEWOULDBLOCK
48#endif
49#ifndef EWOULDBLOCK
50#define EWOULDBLOCK WSAEWOULDBLOCK
51#endif
52
53//static int socks_socket;
54static struct sockaddr_storage ai_addr;
55
56static char socks_firewall_ip[64];
57static char socks_firewall_port[10];
58
59#define SOCKST_UDPMASK 8
60enum _socktypes { SOCKST_TCP, SOCKST_HTTP, SOCKST_TCP2UDP=SOCKST_UDPMASK, SOCKST_HTTP2UDP };
61
62struct socks_udp_prefix {
63        uint32_t len;
64};
65
66
67/* persistent connection */
68struct _socks_socket {
69        int socket;
70        int socktype;
71        int nstate;
72        char remote_ip[64];
73        int remote_port;
74        char public_ip[64];
75        int  public_port;
76        char *pbuf;
77        int pbuflen;
78        int udplen;
79        int prefixlen;
80        union {
81                char buf[4];
82                struct socks_udp_prefix data;
83        } prefix;
84};
85
86#define SOCKET_TIMEOUT 0
87
88#ifndef EXOSIP_MAX_SOCKETS
89#define EXOSIP_MAX_SOCKETS 100
90#endif
91
92extern struct eXtl_protocol eXtl_socks_tcp;
93
94static struct _socks_socket socks_socket_tab[EXOSIP_MAX_SOCKETS];
95
96static int socks_tl_init(void)
97{
98        memset(&ai_addr, 0, sizeof(struct sockaddr_storage));
99        memset(&socks_socket_tab, 0, sizeof(struct _socks_socket) * EXOSIP_MAX_SOCKETS);
100        memset(socks_firewall_ip, 0, sizeof(socks_firewall_ip));
101        memset(socks_firewall_port, 0, sizeof(socks_firewall_port));
102        return OSIP_SUCCESS;
103}
104
105static int socks_tl_free(void)
106{
107        int pos;
108        memset(socks_firewall_ip, 0, sizeof(socks_firewall_ip));
109        memset(socks_firewall_port, 0, sizeof(socks_firewall_port));
110        memset(&ai_addr, 0, sizeof(struct sockaddr_storage));
111
112        for (pos = 0; pos < EXOSIP_MAX_SOCKETS; pos++) {
113                struct _socks_socket *sk = &socks_socket_tab[pos];
114                if (sk->socket > 0) {
115                        closesocket(sk->socket);
116                        if (sk->pbuf)
117                                osip_free(sk->pbuf);
118
119                }
120        }
121        memset(&socks_socket_tab, 0, sizeof(struct _socks_socket) * EXOSIP_MAX_SOCKETS);
122        return OSIP_SUCCESS;
123}
124
125// return current time in milliseconds
126static unsigned nowms()
127{
128        struct timeval tv;
129
130        osip_gettimeofday(&tv, 0);
131
132        return tv.tv_sec*1000+tv.tv_usec/1000;
133
134}
135static int
136waitreaddata(int sock, unsigned millisecs)
137{
138        struct timeval tv = { millisecs/1000, (millisecs % 1000) * 1000 };
139        fd_set rdset;
140        int n;
141
142        FD_ZERO(&rdset);
143        FD_SET(sock, &rdset);
144
145        n = select(sock+1, &rdset, 0, 0, &tv);
146        if (n > 0)
147                return 0;
148
149        return 1;
150
151
152}
153
154/* read a response to a http request (terminated by \r\n\r\n) */
155static int
156socks_read_http_response(struct _socks_socket* sk, char* buf,  size_t bsize)
157{
158        unsigned  start = nowms();
159        size_t filled = 0;
160        int s;
161
162        while((nowms() - start) < 2000) {
163                if (!waitreaddata(sk->socket, 2000 - (nowms() - start) )) {
164                        s = recv(sk->socket, buf+filled, bsize - filled, MSG_DONTWAIT);
165                        if ( s > 0) {
166                                filled += s;
167                                buf[filled] = 0;
168                                if (strstr(buf, "\r\n\r\n")) {
169                                        return 0;
170                                }
171                                if (filled >= bsize)
172                                        break;
173                        }
174                }
175
176        }
177        return -1;
178
179
180
181
182
183}
184
185static socks_http_negotiate(struct _socks_socket *sk)
186{
187        char buf[4*1024];
188
189        int ret;
190
191        snprintf(buf, sizeof(buf), "CONNECT %s:%d HTTP/1.1\r\n%s:%s\r\n\r\n",
192                sk->remote_ip, sk->remote_port, (sk->socktype & SOCKST_UDPMASK) ? "UdpHost" : "Host", sk->remote_ip);
193
194        ret = send(sk->socket, buf, strlen(buf), 0);
195        if (ret != strlen(buf))
196                return -1;
197
198        if (!socks_read_http_response(sk, buf, sizeof(buf))) {
199                if (strstr(buf, "HTTP/1.0") || strstr(buf, "HTTP/1.1")) {
200                        const char *space = strstr(buf, " ");
201                        char *nextline;
202                        int status;
203
204                        if (!space)
205                                return 0;
206
207                        status = atoi(space+1);
208                        if (status != 200)
209                                return -1;
210
211                        nextline = strstr(buf, "\r\n");
212                        nextline += 2;
213                        if (!osip_strcasecmp(nextline, "X-PublicAddress:")) {
214                                char *token = strtok(nextline, ":");
215                                if (token) {
216                                        token = strtok(NULL, ":");
217                                        if (token) {
218                                                osip_strncpy(sk->public_ip, token, sizeof(sk->public_ip)-1);
219                                                token = strtok(NULL, ":");
220                                                if (token) {
221                                                        sk->public_port = atoi(token);
222                                                        return 0;
223                                                }
224                                        }
225                                }
226
227                        }
228                        return -1;
229                }
230
231
232        }
233        return -1;
234}
235
236struct socks5_req {
237        char    ver;          /* Version number */
238        char    cmd;          /* Command */
239        char    _nop;         /* Reserved */
240        char    atp ;        /* Address type */
241        uint32_t destip;    /* Dest address */
242        uint16_t dport;    /* Dest port */
243};
244
245static int
246socks5_negotiate(struct _socks_socket *sk)
247{
248        int ret;
249        char msg1[] = { 0x05, 0x01, 0x00 };
250        char auth[2];
251        struct socks5_req req, resp;
252        struct in_addr ina;
253
254        ret = send(sk->socket, msg1, 3, 0);
255        if (ret != 3)
256                return -1;
257
258        ret = recv(sk->socket, auth, 2, 0);
259        if (ret != 2)
260                return -1;
261
262        if (auth[0] != 5) /* check protocol version */
263                return -1;
264        if (auth[1] != 0) /* check auth type */
265                return -1;
266
267        req.ver = 5;
268        req.cmd = (sk->socktype & SOCKST_UDPMASK) ? 4 : 1;
269        req._nop = 0;
270        req.atp = 1;
271        req.destip = inet_addr(sk->remote_ip);
272        req.dport  = htons(sk->remote_port);
273        ret = send(sk->socket, &req, sizeof(req), 0);
274        if (ret != sizeof(req))
275                return -1;
276
277        ret = recv(sk->socket, &resp, 4, 0);
278        if (ret != 4)
279                return -1;
280        if (resp.ver != 5)
281                return -1;
282
283        if (resp.cmd != 0)
284                return -1;
285
286        if (resp.atp != 0)
287                return -1;
288
289        ret = recv(sk->socket, &resp.destip, 6, 0);
290        if (ret != 6)
291                return 0;
292
293        ina.s_addr = resp.destip;
294        osip_strncpy(sk->public_ip, inet_ntoa(ina), sizeof(sk->public_ip)-1);
295        sk->public_port = ntohl(resp.dport);
296
297        return 0;
298}
299
300int socks_negotiate(struct _socks_socket *sk)
301{
302
303
304        if (sk->socktype== SOCKST_HTTP || sk->socktype == SOCKST_HTTP2UDP) {
305                return socks_http_negotiate(sk);
306        }
307        return socks5_negotiate(sk);
308
309
310
311}
312static socks_connect(struct _socks_socket *sk, const char *addr, int port)
313{
314        struct addrinfo *addrinfo = NULL;
315        struct addrinfo *curinfo;
316        int sock;
317        int res;
318
319        res = eXosip_get_addrinfo(&addrinfo,
320                                                          socks_firewall_ip,
321                                                          atoi(socks_firewall_port), eXtl_socks_tcp.proto_num);
322        if (res)
323                return -1;
324
325        for (curinfo = addrinfo; curinfo; curinfo = curinfo->ai_next) {
326                if (curinfo->ai_protocol && curinfo->ai_protocol != IPPROTO_TCP) {
327                        OSIP_TRACE(osip_trace
328                                           (__FILE__, __LINE__, OSIP_INFO2, NULL,
329                                                "Skipping protocol %d\n", curinfo->ai_protocol));
330                        continue;
331                }
332
333                sock = (int) socket(curinfo->ai_family, curinfo->ai_socktype,
334                                curinfo->ai_protocol);
335
336
337                if (sock < 0) {
338                        OSIP_TRACE(osip_trace
339                                        (__FILE__, __LINE__, OSIP_ERROR, NULL,
340                                                        "Cannot create socket %s!\n", strerror(ex_errno)));
341                        continue;
342                }
343
344        }
345
346
347        if ((sock >= 0) && !connect(sock, curinfo->ai_addr, curinfo->ai_addrlen)) {
348                sk->socket = sock;
349                sk->remote_port = port;
350                osip_strncpy(sk->remote_ip, addr, sizeof(sk->remote_ip));
351                if (!socks_negotiate(sk)) {
352                        eXosip_freeaddrinfo(addrinfo);
353                        return 0;
354                }
355        }
356
357        eXosip_freeaddrinfo(addrinfo);
358        closesocket(sock);
359        return -1;
360
361
362}
363
364static struct _socks_socket *
365socks_connect_to(const char *host, int port, int mode)
366{
367        int pos;
368
369        for (pos = 0; pos < EXOSIP_MAX_SOCKETS; pos++) {
370                struct _socks_socket *sk = &socks_socket_tab[pos];
371
372                if (sk->socket == 0) {
373                        sk->socktype = mode;
374                        if (!socks_connect(sk, host, port)) {
375                                if (mode & SOCKST_UDPMASK) {
376                                        sk->pbuf = osip_malloc(SIP_MESSAGE_MAX_LENGTH);
377                                        if (sk->pbuf) {
378                                                closesocket(sk->socket);
379                                                return 0;
380                                        }
381                                }
382                                return sk;
383                        }
384
385
386                }
387        }
388
389}
390
391static int
392socks_get_udp_prefix(struct _socks_socket *sk)
393{
394        int t;
395        int need_more = sizeof(sk->prefix.data) - sk->prefixlen;
396
397        t = recv(sk->socket, sk->prefix.buf+sk->prefixlen, need_more, 0);
398        if (t < 0)
399                return -1;
400        sk->prefixlen += t;
401        if (sk->prefixlen == sizeof(sk->prefix.data)) {
402                sk->udplen = ntohl(sk->prefix.data.len);
403                sk->prefixlen = 0;
404                return 0;
405        }
406        return 1;
407
408}
409
410
411static int socks_tl_open(void)
412{
413
414        return OSIP_SUCCESS;
415}
416
417static int socks_tl_set_fdset(fd_set * osip_fdset, int *fd_max)
418{
419        int pos;
420
421
422        for (pos = 0; pos < EXOSIP_MAX_SOCKETS; pos++) {
423                if (socks_socket_tab[pos].socket > 0) {
424                        eXFD_SET(socks_socket_tab[pos].socket, osip_fdset);
425                        if (socks_socket_tab[pos].socket > *fd_max)
426                                *fd_max = socks_socket_tab[pos].socket;
427                }
428        }
429
430        return OSIP_SUCCESS;
431}
432
433static int
434socks_tl_read_message(fd_set * osip_fdset)
435{
436        int pos = 0;
437        char *buf;
438
439
440
441        buf = NULL;
442
443        for (pos = 0; pos < EXOSIP_MAX_SOCKETS; pos++) {
444                struct _socks_socket *sk = &socks_socket_tab[pos];
445
446                if (sk->socket > 0
447                        && FD_ISSET(sk->socket, osip_fdset)) {
448                        int i;
449
450
451                        if (sk->socktype & SOCKST_UDPMASK) { // We expect 4 bytes of prefix containing packet length
452                                if (!socks_get_udp_prefix(sk)) {
453                                        int need_more = sk->udplen - sk->pbuflen;
454
455                                        i = recv(sk->socket, sk->pbuf, need_more, 0);
456                                        if (i > 0) {
457                                                sk->pbuflen += i;
458                                                if (sk->pbuflen == sk->udplen) {
459                                                        sk->pbuf[sk->udplen] = 0;
460                                                        _eXosip_handle_incoming_message(sk->pbuf,
461                                                                                                                        sk->udplen,
462                                                                                                                        sk->socket,
463                                                                                                                        sk->remote_ip,
464                                                                                                                        sk->remote_port);
465                                                        sk->udplen = 0;
466
467                                                }
468                                        }
469                                }
470                                continue;
471                        }
472
473                        if (buf == NULL)
474                                buf = (char *) osip_malloc(SIP_MESSAGE_MAX_LENGTH * sizeof(char) + 1);
475                        if (buf == NULL)
476                                return OSIP_NOMEM;
477
478                        i = recv(sk->socket, buf, SIP_MESSAGE_MAX_LENGTH, 0);
479
480#define TEST_CODE_FOR_FRAGMENTATION
481#ifdef TEST_CODE_FOR_FRAGMENTATION
482                        if (i > 0) {
483                                char *end_sip;
484                                char *cl_header;
485                                int cl_size;
486                                osip_strncpy(buf + i, "\0", 1);
487                                if (sk->pbuf != NULL) {
488                                        /* concat old data with new data */
489                                        sk->pbuf =
490                                                (char *) osip_realloc(sk->pbuf,
491                                                                                          sk->pbuflen + i + 1);
492                                        if (sk->pbuf == NULL) {
493                                                OSIP_TRACE(osip_trace
494                                                                   (__FILE__, __LINE__, OSIP_ERROR, NULL,
495                                                                        "Reallocation error: (len=%i)",
496                                                                        sk->pbuflen + i + 1));
497                                                sk->pbuflen = 0;
498                                                continue;       /* give up: realloc issue */
499                                        }
500                                        osip_strncpy(sk->pbuf +  sk->pbuflen, buf, i);
501                                        sk->pbuflen += i;
502
503                                }
504
505                                if (sk->pbuf == NULL) {
506                                        sk->pbuf = (char *) osip_malloc(i + 1);
507                                        osip_strncpy(sk->pbuf, buf, i);
508                                        sk->pbuflen = i;
509                                }
510
511                                end_sip = strstr(sk->pbuf, "\r\n\r\n");
512                                /* end_sip might be end of SIP headers */
513                                while (end_sip != NULL) {
514                                        /* a content-legnth MUST exist before the CRLFCRLF */
515                                        cl_header =
516                                                osip_strcasestr(sk->pbuf,
517                                                                                "\ncontent-length ");
518                                        if (cl_header == NULL || cl_header > end_sip)
519                                                cl_header = osip_strcasestr(sk->pbuf, "\ncontent-length:");
520                                        if (cl_header == NULL || cl_header > end_sip)
521                                                cl_header = osip_strcasestr(sk->pbuf,"\r\nl ");
522                                        if (cl_header == NULL || cl_header > end_sip)
523                                                cl_header = osip_strcasestr(sk->pbuf, "\r\nl:");
524
525                                        if (cl_header != NULL && cl_header < end_sip)
526                                                cl_header = strchr(cl_header, ':');
527                                        /* broken data */
528                                        if (cl_header == NULL || cl_header >= end_sip) {
529                                                /* remove data up to crlfcrlf and restart */
530                                                memmove(sk->pbuf, end_sip+4, sk->pbuflen - (end_sip + 4 - sk->pbuf) + 1);
531
532                                                sk->pbuflen -=  (end_sip + 4 - sk->pbuf);
533
534                                                sk->pbuf = (char *) osip_realloc(sk->pbuf,  sk->pbuflen + 1);
535                                                if (sk->pbuf == NULL) {
536                                                        OSIP_TRACE(osip_trace
537                                                                           (__FILE__, __LINE__, OSIP_ERROR, NULL,
538                                                                                "Reallocation error: (len=%i)", sk->pbuflen + 1));
539                                                        sk->pbuflen = 0;
540                                                        break;
541                                                }
542                                                end_sip = strstr(sk->pbuf, "\r\n\r\n");
543                                                continue;       /* and restart from new CRLFCRLF */
544                                        }
545
546                                        /* header content-length was found before CRLFCRLF -> all headers are available */
547                                        cl_header++;    /* after ':' char */
548                                        cl_size = osip_atoi(cl_header);
549
550                                        if (cl_size == 0
551                                                || (cl_size > 0 && end_sip + 4 + cl_size <= sk->pbuf + sk->pbuflen)) {
552                                                /* we have beg_sip & end_sip */
553                                                _eXosip_handle_incoming_message(sk->pbuf,
554                                                                                                                end_sip + 4 + cl_size - sk->pbuf,
555                                                                                                                sk->socket,
556                                                                                                                sk->remote_ip,
557                                                                                                                sk->remote_port);
558
559                                                if (sk->pbuflen - (end_sip + 4 + cl_size -  sk->pbuf) == 0) {
560                                                        end_sip = NULL;
561                                                        OSIP_TRACE(osip_trace
562                                                                           (__FILE__, __LINE__, OSIP_INFO2, NULL,
563                                                                                "All TCP data consumed\n"));
564                                                        sk->pbuflen = 0;
565                                                        osip_free(sk->pbuf);
566                                                        sk->pbuf = NULL;
567                                                        continue;
568                                                }
569
570                                                /* any more content? */
571                                                memmove(sk->pbuf,
572                                                                end_sip + 4 + cl_size,
573                                                                sk->pbuflen - (end_sip + 4 + cl_size -  sk->pbuf) + 1);
574
575                                                sk->pbuflen -=(end_sip +4 + cl_size - sk->pbuf);
576
577                                                sk->pbuf = (char *) osip_realloc(sk->pbuf, sk->pbuflen + 1);
578                                                if (sk->pbuf == NULL) {
579                                                        OSIP_TRACE(osip_trace
580                                                                           (__FILE__, __LINE__, OSIP_ERROR, NULL,
581                                                                                "Reallocation error: (len=%i)",
582                                                                                sk->pbuflen + 1));
583                                                        sk->pbuflen = 0;
584                                                        break;
585                                                }
586                                                end_sip = strstr(sk->pbuf,  "\r\n\r\n");
587                                                continue;       /* and restart from new CRLFCRLF */
588                                        }
589
590                                        /* uncomplete SIP message */
591                                        end_sip = NULL;
592                                        OSIP_TRACE(osip_trace
593                                                           (__FILE__, __LINE__, OSIP_INFO2, NULL,
594                                                                "Uncomplete TCP data (%s)\n", buf));
595                                        continue;
596                                }
597
598                                if (sk->pbuflen == 0) {
599                                        /* all data consumed are reallocation error ? */
600                                        continue;
601                                }
602#else
603                        if (i > 5) {
604                                osip_strncpy(buf + i, "\0", 1);
605                                OSIP_TRACE(osip_trace
606                                                   (__FILE__, __LINE__, OSIP_INFO2, NULL,
607                                                        "Received TCP message: \n%s\n", buf));
608                                _eXosip_handle_incoming_message(buf, i,
609                                                                                                sk->socket,
610                                                                                                sk->remote_ip,
611                                                                                                sk->remote_port);
612#endif
613                        } else if (i < 0) {
614                                int status = ex_errno;
615                                if (status != EAGAIN) {
616                                        OSIP_TRACE(osip_trace
617                                                           (__FILE__, __LINE__, OSIP_ERROR, NULL,
618                                                                "Could not read socket (%s)- close it\n",
619                                                                strerror(status)));
620                                        close(sk->socket);
621                                        if (sk->pbuf)
622                                                osip_free(sk->pbuf);
623                                        memset(sk, 0, sizeof(socks_socket_tab[pos]));
624                                }
625                        } else if (i == 0) {
626                                OSIP_TRACE(osip_trace
627                                                   (__FILE__, __LINE__, OSIP_INFO1, NULL,
628                                                        "End of stream (read 0 byte from %s:%i)\n",
629                                                        sk->remote_ip,
630                                                        sk->remote_port));
631                                close(sk->socket);              struct socks_udp_prefix {
632                                        uint32_t len;
633                                };
634
635                                if (sk->pbuf)
636                                        osip_free(sk->pbuf);
637                                memset(sk, 0, sizeof(socks_socket_tab[pos]));
638                        }
639#ifndef MINISIZE
640                        else {
641                                /* we expect at least one byte, otherwise there's no doubt that it is not a sip message ! */
642                                OSIP_TRACE(osip_trace
643                                                   (__FILE__, __LINE__, OSIP_INFO1, NULL,
644                                                        "Dummy SIP message received (size=%i)\n", i));
645                        }
646#endif
647                }
648        }
649
650        if (buf != NULL)
651                osip_free(buf);
652
653        return OSIP_SUCCESS;
654}
655
656static int _socks_tl_find_socket(char *host, int port)
657{
658        int pos;
659
660        for (pos = 0; pos < EXOSIP_MAX_SOCKETS; pos++) {
661                struct _socks_socket *sk = &socks_socket_tab[pos];
662
663                if (sk->socket != 0) {
664                        if (0 == osip_strcasecmp(sk->remote_ip, host)
665                                && port == sk->remote_port)
666                                return sk->socket;
667                }
668        }
669        return -1;
670}
671
672static int _socks_tl_is_connected(int sock)
673{
674        int res;
675        struct timeval tv;
676        fd_set wrset;
677        int valopt;
678        socklen_t sock_len;
679        tv.tv_sec = SOCKET_TIMEOUT / 1000;
680        tv.tv_usec = (SOCKET_TIMEOUT % 1000) * 1000;
681
682        FD_ZERO(&wrset);
683        FD_SET(sock, &wrset);
684
685        res = select(sock + 1, NULL, &wrset, NULL, &tv);
686        if (res > 0) {
687                sock_len = sizeof(int);
688                if (getsockopt(sock, SOL_SOCKET, SO_ERROR, (void *) (&valopt), &sock_len)
689                        == 0) {
690                        if (valopt) {
691                                OSIP_TRACE(osip_trace
692                                                   (__FILE__, __LINE__, OSIP_INFO2, NULL,
693                                                        "Cannot connect socket node / %s[%d]\n",
694                                                        strerror(ex_errno), ex_errno));
695                                return -1;
696                        } else {
697                                return 0;
698                        }
699                } else {
700                        OSIP_TRACE(osip_trace
701                                           (__FILE__, __LINE__, OSIP_INFO2, NULL,
702                                                "Cannot connect socket node / error in getsockopt %s[%d]\n",
703                                                strerror(ex_errno), ex_errno));
704                        return -1;
705                }
706        } else if (res < 0) {
707                OSIP_TRACE(osip_trace
708                                   (__FILE__, __LINE__, OSIP_INFO2, NULL,
709                                        "Cannot connect socket node / error in select %s[%d]\n",
710                                        strerror(ex_errno), ex_errno));
711                return -1;
712        } else {
713                OSIP_TRACE(osip_trace
714                                   (__FILE__, __LINE__, OSIP_INFO2, NULL,
715                                        "Cannot connect socket node / select timeout (%d ms)\n",
716                                        SOCKET_TIMEOUT));
717                return 1;
718        }
719}
720
721static int _socks_tl_connect_socket2(char *host, int port, int mode)
722{
723        int res;
724        int sock = -1;
725        struct _socks_socket *sk = 0;
726        int i = _socks_tl_find_socket(host, port);
727        if (i >= 0) {
728                return i;
729        }
730
731        OSIP_TRACE(osip_trace
732                           (__FILE__, __LINE__, OSIP_INFO2, NULL,
733                                "New binding with %s\n", host));
734
735
736        sk = socks_connect_to(host, port, mode);
737        if (!sk)
738                return -1;
739
740        sock = sk->socket;
741
742
743        if (sock > 0) {
744                if (mode & SOCKST_UDPMASK) {
745                        sk->pbuf = (char *) osip_malloc(SIP_MESSAGE_MAX_LENGTH);
746                        if (!sk->pbuf) {
747                                closesocket(sk->socket);
748                                memset(sk, 0, sizeof(*sk));
749                                return -1;
750                        }
751
752                }
753
754                return sock;
755        }
756
757        return -1;
758}
759
760
761static int
762socks_tl_send_message2(osip_transaction_t * tr, osip_message_t * sip, char *host,
763                                        int port, int out_socket, int mode)
764{
765        size_t length = 0;
766        char *message;
767        int i;
768
769        if (host == NULL) {
770                host = sip->req_uri->host;
771                if (sip->req_uri->port != NULL)
772                        port = osip_atoi(sip->req_uri->port);
773                else
774                        port = 5060;
775        }
776
777        /* remove preloaded route if there is no tag in the To header
778         */
779        {
780                osip_route_t *route = NULL;
781                osip_generic_param_t *tag = NULL;
782                osip_message_get_route(sip, 0, &route);
783
784                osip_to_get_tag(sip->to, &tag);
785                if (tag == NULL && route != NULL && route->url != NULL) {
786                        osip_list_remove(&sip->routes, 0);
787                }
788                i = osip_message_to_str(sip, &message, &length);
789                if (tag == NULL && route != NULL && route->url != NULL) {
790                        osip_list_add(&sip->routes, route, 0);
791                }
792        }
793
794        if (i != 0 || length <= 0) {
795                return -1;
796        }
797
798        /* Step 1: find existing socket to send message */
799        if (out_socket <= 0) {
800                out_socket = _socks_tl_find_socket(host, port);
801
802                /* Step 2: create new socket with host:port */
803                if (out_socket <= 0) {
804                        out_socket = _socks_tl_connect_socket2(host, port, mode);
805                }
806        } else {
807                OSIP_TRACE(osip_trace(__FILE__, __LINE__, OSIP_INFO1, NULL,
808                                                          "reusing REQUEST connection (to dest=%s:%i)\n",
809                                                          host, port));
810        }
811
812        if (out_socket <= 0) {
813                osip_free(message);
814                return -1;
815        }
816
817        i = _socks_tl_is_connected(out_socket);
818        if (i > 0) {
819                time_t now;
820                now = time(NULL);
821                OSIP_TRACE(osip_trace
822                                   (__FILE__, __LINE__, OSIP_INFO2, NULL,
823                                        "socket node:%s, socket %d [pos=%d], in progress\n",
824                                        host, out_socket, -1));
825                osip_free(message);
826                if (tr != NULL && now - tr->birth_time > 10)
827                        return -1;
828                return 1;
829        } else if (i == 0) {
830                OSIP_TRACE(osip_trace
831                                   (__FILE__, __LINE__, OSIP_INFO2, NULL,
832                                        "socket node:%s , socket %d [pos=%d], connected\n",
833                                        host, out_socket, -1));
834        } else {
835                OSIP_TRACE(osip_trace
836                                   (__FILE__, __LINE__, OSIP_ERROR, NULL,
837                                        "socket node:%s, socket %d [pos=%d], socket error\n",
838                                        host, out_socket, -1));
839                osip_free(message);
840                return -1;
841        }
842
843        OSIP_TRACE(osip_trace(__FILE__, __LINE__, OSIP_INFO1, NULL,
844                                                  "Message sent: (to dest=%s:%i) \n%s\n",
845                                                  host, port, message));
846
847        if (mode & SOCKST_UDPMASK) {
848                struct socks_udp_prefix *pfx;
849
850                pfx = (struct socks_udp_prefix *)osip_malloc(length + sizeof(*pfx));
851                if (!pfx)
852                        return -1;
853                memcpy(pfx+1, message, length);
854                length += sizeof(*pfx);
855                osip_free(message);
856                message = (char *)pfx;
857        }
858
859        while (1) {
860                i = send(out_socket, (const void *) message, length, 0);
861                if (i < 0) {
862                        int status = ex_errno;
863                        if (EAGAIN == status || EWOULDBLOCK == status) {
864                                struct timeval tv;
865                                fd_set wrset;
866                                tv.tv_sec = SOCKET_TIMEOUT / 1000;
867                                tv.tv_usec = (SOCKET_TIMEOUT % 1000) * 1000;
868
869                                FD_ZERO(&wrset);
870                                FD_SET(out_socket, &wrset);
871
872                                i = select(out_socket + 1, NULL, &wrset, NULL, &tv);
873                                if (i > 0) {
874                                        continue;
875                                } else if (i < 0) {
876                                        OSIP_TRACE(osip_trace(__FILE__, __LINE__, OSIP_ERROR, NULL,
877                                                                                  "TCP select error: %s\n",
878                                                                                  strerror(ex_errno)));
879                                        osip_free(message);
880                                        return -1;
881                                } else {
882                                        OSIP_TRACE(osip_trace(__FILE__, __LINE__, OSIP_ERROR, NULL,
883                                                                                  "TCP timeout: %d ms\n", SOCKET_TIMEOUT));
884                                        osip_free(message);
885                                        return -1;
886                                }
887                        } else {
888                                /* SIP_NETWORK_ERROR; */
889                                OSIP_TRACE(osip_trace(__FILE__, __LINE__, OSIP_ERROR, NULL,
890                                                                          "TCP error: %s\n", strerror(status)));
891                                osip_free(message);
892                                return -1;
893                        }
894                }
895                break;
896        }
897
898        osip_free(message);
899        return OSIP_SUCCESS;
900}
901
902static int
903socks_tcp_tl_send_message(osip_transaction_t * tr, osip_message_t * sip, char *host,
904                                        int port, int out_socket)
905{
906        return socks_tl_send_message2(tr, sip, host, port, out_socket, SOCKST_TCP);
907}
908
909static int
910http_tl_send_message(osip_transaction_t * tr, osip_message_t * sip, char *host,
911                                        int port, int out_socket)
912{
913        return socks_tl_send_message2(tr, sip, host, port, out_socket, SOCKST_HTTP);
914}
915
916
917static int
918socks_udp_tl_send_message(osip_transaction_t * tr, osip_message_t * sip, char *host,
919                                        int port, int out_socket)
920{
921        return socks_tl_send_message2(tr, sip, host, port, out_socket, SOCKST_TCP2UDP);
922}
923
924static int
925http_udp_tl_send_message(osip_transaction_t * tr, osip_message_t * sip, char *host,
926                                        int port, int out_socket)
927{
928        return socks_tl_send_message2(tr, sip, host, port, out_socket, SOCKST_HTTP2UDP);
929}
930
931
932
933static int socks_tl_keepalive(void)
934{
935        return 1;
936}
937
938static int socks_tl_set_socket(int socket)
939{
940//      socks_socket = socket;
941
942        return OSIP_SUCCESS;
943}
944
945
946static int socks_tl_masquerade_contact(const char *public_address, int port)
947{
948        if (public_address == NULL || public_address[0] == '\0') {
949                memset(socks_firewall_ip, '\0', sizeof(socks_firewall_ip));
950                memset(socks_firewall_port, '\0', sizeof(socks_firewall_port));
951                if (eXtl_socks_tcp.proto_port > 0)
952                        snprintf(socks_firewall_port, sizeof(socks_firewall_port), "%i",
953                                         eXtl_socks_tcp.proto_port);
954                return OSIP_SUCCESS;
955        }
956        snprintf(socks_firewall_ip, sizeof(socks_firewall_ip), "%s", public_address);
957        if (port > 0) {
958                snprintf(socks_firewall_port, sizeof(socks_firewall_port), "%i", port);
959        }
960        return OSIP_SUCCESS;
961}
962
963static int
964socks_tl_get_masquerade_contact(char *ip, int ip_size, char *port, int port_size)
965{
966    int pos;
967    struct _socks_socket *sk = 0;
968
969        memset(ip, 0, ip_size);
970        memset(port, 0, port_size);
971        for (pos = 0; pos < EXOSIP_MAX_SOCKETS; pos++) {
972                sk = &socks_socket_tab[pos];
973                if (sk->socket > 0)
974                        break;
975        }
976
977        if (!sk)
978                return -1;
979
980        if (socks_firewall_ip[0] != '\0')
981                snprintf(ip, ip_size, "%s", sk->public_ip);
982
983        if (socks_firewall_port[0] != '\0')
984                snprintf(port, port_size, "%d", sk->public_port);
985        return OSIP_SUCCESS;
986}
987
988struct eXtl_protocol eXtl_socks_tcp = {
989        1,
990        7070,
991        "SOCKS+TCP",
992        "0.0.0.0",
993        IPPROTO_TCP,
994        AF_INET,
995        0,
996        0,
997
998        &socks_tl_init,
999        &socks_tl_free,
1000        &socks_tl_open,
1001        &socks_tl_set_fdset,
1002        &socks_tl_read_message,
1003        &socks_tcp_tl_send_message,
1004        &socks_tl_keepalive,
1005        &socks_tl_set_socket,
1006        &socks_tl_masquerade_contact,
1007        &socks_tl_get_masquerade_contact
1008};
1009
1010struct eXtl_protocol eXtl_socks_http = {
1011        1,
1012        7070,
1013        "HTTP+TCP",
1014        "0.0.0.0",
1015        IPPROTO_TCP,
1016        AF_INET,
1017        0,
1018        0,
1019
1020        &socks_tl_init,
1021        &socks_tl_free,
1022        &socks_tl_open,
1023        &socks_tl_set_fdset,
1024        &socks_tl_read_message,
1025        &http_tl_send_message,
1026        &socks_tl_keepalive,
1027        &socks_tl_set_socket,
1028        &socks_tl_masquerade_contact,
1029        &socks_tl_get_masquerade_contact
1030};
1031
1032struct eXtl_protocol eXtl_socks_tcp2udp = {
1033        1,
1034        7070,
1035        "SOCKS+UDP",
1036        "0.0.0.0",
1037        IPPROTO_TCP,
1038        AF_INET,
1039        0,
1040        0,
1041
1042        &socks_tl_init,
1043        &socks_tl_free,
1044        &socks_tl_open,
1045        &socks_tl_set_fdset,
1046        &socks_tl_read_message,
1047        &socks_udp_tl_send_message,
1048        &socks_tl_keepalive,
1049        &socks_tl_set_socket,
1050        &socks_tl_masquerade_contact,
1051        &socks_tl_get_masquerade_contact
1052};
1053
1054struct eXtl_protocol eXtl_socks_http2udp = {
1055        1,
1056        7070,
1057        "HTTP+UDP",
1058        "0.0.0.0",
1059        IPPROTO_TCP,
1060        AF_INET,
1061        0,
1062        0,
1063
1064        &socks_tl_init,
1065        &socks_tl_free,
1066        &socks_tl_open,
1067        &socks_tl_set_fdset,
1068        &socks_tl_read_message,
1069        &http_udp_tl_send_message,
1070        &socks_tl_keepalive,
1071        &socks_tl_set_socket,
1072        &socks_tl_masquerade_contact,
1073        &socks_tl_get_masquerade_contact
1074};
1075
1076
Note: See TracBrowser for help on using the repository browser.