首页 | 数据结构 | 文件列表 | 数据字段 | 全局定义

udp_proxy_s5.c

浏览该文件的文档。
00001 
00024 // START OF FILE
00025 /*****************************************************************************/
00026 #include "debug.h"              // gaim_debug
00027 
00028 #include "udp_proxy_s5.h"
00029 
00030 extern gint                     // defined in qq_proxy.c
00031  _qq_fill_host(struct sockaddr_in *addr, const gchar * host, guint16 port);
00032 
00033 /*****************************************************************************/
00034 static void _qq_s5_canread_again(gpointer data, gint source, GaimInputCondition cond)
00035 {
00036         unsigned char buf[512];
00037         struct PHB *phb = data;
00038         struct sockaddr_in sin;
00039         int len;
00040 
00041         gaim_input_remove(phb->inpa);
00042         gaim_debug(GAIM_DEBUG_INFO, "socks5 proxy", "Able to read again.\n");
00043 
00044         len = read(source, buf, 10);
00045         if (len < 10) {
00046                 gaim_debug(GAIM_DEBUG_WARNING, "socks5 proxy", "or not...\n");
00047                 close(source);
00048 
00049                 if (phb->account == NULL || gaim_account_get_connection(phb->account) != NULL) {
00050 
00051                         phb->func(phb->data, source, GAIM_INPUT_READ);
00052                 }
00053 
00054                 g_free(phb->host);
00055                 g_free(phb);
00056                 return;
00057         }
00058         if ((buf[0] != 0x05) || (buf[1] != 0x00)) {
00059                 if ((buf[0] == 0x05) && (buf[1] < 0x09))
00060                         gaim_debug(GAIM_DEBUG_ERROR, "socks5 proxy", "socks5 error: %x\n", buf[1]);
00061                 else
00062                         gaim_debug(GAIM_DEBUG_ERROR, "socks5 proxy", "Bad data.\n");
00063                 close(source);
00064 
00065                 if (phb->account == NULL || gaim_account_get_connection(phb->account) != NULL) {
00066 
00067                         phb->func(phb->data, -1, GAIM_INPUT_READ);
00068                 }
00069 
00070                 g_free(phb->host);
00071                 g_free(phb);
00072                 return;
00073         }
00074 
00075         sin.sin_family = AF_INET;
00076         memcpy(&sin.sin_addr.s_addr, buf + 4, 4);
00077         memcpy(&sin.sin_port, buf + 8, 2);
00078 
00079         if (connect(phb->udpsock, (struct sockaddr *) &sin, sizeof(struct sockaddr_in)) < 0) {
00080                 gaim_debug(GAIM_DEBUG_INFO, "s5_canread_again", "connect failed: %s\n", strerror(errno));
00081                 close(phb->udpsock);
00082                 close(source);
00083                 g_free(phb->host);
00084                 g_free(phb);
00085                 return;
00086         }
00087 
00088         int error = ETIMEDOUT;
00089         gaim_debug(GAIM_DEBUG_INFO, "QQ", "Connect didn't block\n");
00090         len = sizeof(error);
00091         if (getsockopt(phb->udpsock, SOL_SOCKET, SO_ERROR, &error, &len) < 0) {
00092                 gaim_debug(GAIM_DEBUG_ERROR, "QQ", "getsockopt failed.\n");
00093                 close(phb->udpsock);
00094                 return;
00095         }
00096         fcntl(phb->udpsock, F_SETFL, 0);
00097 
00098         if (phb->account == NULL || gaim_account_get_connection(phb->account) != NULL) {
00099                 phb->func(phb->data, phb->udpsock, GAIM_INPUT_READ);
00100         }
00101 
00102         g_free(phb->host);
00103         g_free(phb);
00104 }
00105 
00106 /*****************************************************************************/
00107 static void _qq_s5_sendconnect(gpointer data, gint source)
00108 {
00109         unsigned char buf[512];
00110         struct PHB *phb = data;
00111         struct sockaddr_in sin, ctlsin;
00112         int port, ctllen;
00113 
00114         gaim_debug(GAIM_DEBUG_INFO, "s5_sendconnect", "remote host is %s:%d\n", phb->host, phb->port);
00115 
00116         buf[0] = 0x05;
00117         buf[1] = 0x03;          /* udp relay */
00118         buf[2] = 0x00;          /* reserved */
00119         buf[3] = 0x01;          /* address type -- ipv4 */
00120         memset(buf + 4, 0, 0x04);
00121 
00122         ctllen = sizeof(ctlsin);
00123         if (getsockname(source, (struct sockaddr *) &ctlsin, &ctllen) < 0) {
00124                 gaim_debug(GAIM_DEBUG_INFO, "QQ", "getsockname: %s\n", strerror(errno));
00125                 close(source);
00126                 g_free(phb->host);
00127                 g_free(phb);
00128                 return;
00129         }
00130 
00131         phb->udpsock = socket(PF_INET, SOCK_DGRAM, 0);
00132         gaim_debug(GAIM_DEBUG_INFO, "s5_sendconnect", "UDP socket=%d\n", phb->udpsock);
00133         if (phb->udpsock < 0) {
00134                 close(source);
00135                 g_free(phb->host);
00136                 g_free(phb);
00137                 return;
00138         }
00139 
00140         fcntl(phb->udpsock, F_SETFL, O_NONBLOCK);
00141 
00142         port = ntohs(ctlsin.sin_port) + 1;
00143         while (1) {
00144                 _qq_fill_host(&sin, "0.0.0.0", port);
00145                 if (bind(phb->udpsock, (struct sockaddr *) &sin, sizeof(sin)) < 0) {
00146                         port++;
00147                         if (port > 65500) {
00148                                 close(source);
00149                                 g_free(phb->host);
00150                                 g_free(phb);
00151                                 return;
00152                         }
00153                 } else
00154                         break;
00155         }
00156 
00157         memset(buf + 4, 0, 0x04);
00158         memcpy(buf + 8, &(sin.sin_port), 0x02);
00159 
00160         if (write(source, buf, 10) < 10) {
00161                 close(source);
00162                 gaim_debug(GAIM_DEBUG_INFO, "s5_sendconnect", "packet too small\n");
00163 
00164                 if (phb->account == NULL || gaim_account_get_connection(phb->account) != NULL) {
00165                         phb->func(phb->data, -1, GAIM_INPUT_READ);
00166                 }
00167 
00168                 g_free(phb->host);
00169                 g_free(phb);
00170                 return;
00171         }
00172 
00173         phb->inpa = gaim_input_add(source, GAIM_INPUT_READ, _qq_s5_canread_again, phb);
00174 }
00175 
00176 /*****************************************************************************/
00177 static void _qq_s5_readauth(gpointer data, gint source, GaimInputCondition cond)
00178 {
00179         unsigned char buf[512];
00180         struct PHB *phb = data;
00181 
00182         gaim_input_remove(phb->inpa);
00183         gaim_debug(GAIM_DEBUG_INFO, "socks5 proxy", "Got auth response.\n");
00184 
00185         if (read(source, buf, 2) < 2) {
00186                 close(source);
00187 
00188                 if (phb->account == NULL || gaim_account_get_connection(phb->account) != NULL) {
00189 
00190                         phb->func(phb->data, -1, GAIM_INPUT_READ);
00191                 }
00192 
00193                 g_free(phb->host);
00194                 g_free(phb);
00195                 return;
00196         }
00197 
00198         if ((buf[0] != 0x01) || (buf[1] != 0x00)) {
00199                 close(source);
00200 
00201                 if (phb->account == NULL || gaim_account_get_connection(phb->account) != NULL) {
00202 
00203                         phb->func(phb->data, -1, GAIM_INPUT_READ);
00204                 }
00205 
00206                 g_free(phb->host);
00207                 g_free(phb);
00208                 return;
00209         }
00210 
00211         _qq_s5_sendconnect(phb, source);
00212 }
00213 
00214 /*****************************************************************************/
00215 static void _qq_s5_canread(gpointer data, gint source, GaimInputCondition cond)
00216 {
00217         unsigned char buf[512];
00218         struct PHB *phb = data;
00219 
00220         gaim_input_remove(phb->inpa);
00221         gaim_debug(GAIM_DEBUG_INFO, "socks5 proxy", "Able to read.\n");
00222 
00223         int ret = read(source, buf, 2);
00224         if (ret < 2) {
00225                 gaim_debug(GAIM_DEBUG_INFO, "s5_canread", "packet smaller than 2 octet\n");
00226                 close(source);
00227 
00228                 if (phb->account == NULL || gaim_account_get_connection(phb->account) != NULL) {
00229 
00230                         phb->func(phb->data, source, GAIM_INPUT_READ);
00231                 }
00232 
00233                 g_free(phb->host);
00234                 g_free(phb);
00235                 return;
00236         }
00237 
00238         if ((buf[0] != 0x05) || (buf[1] == 0xff)) {
00239                 gaim_debug(GAIM_DEBUG_INFO, "s5_canread", "unsupport\n");
00240                 close(source);
00241 
00242                 if (phb->account == NULL || gaim_account_get_connection(phb->account) != NULL) {
00243 
00244                         phb->func(phb->data, -1, GAIM_INPUT_READ);
00245                 }
00246 
00247                 g_free(phb->host);
00248                 g_free(phb);
00249                 return;
00250         }
00251 
00252         if (buf[1] == 0x02) {
00253                 unsigned int i, j;
00254 
00255                 i = strlen(gaim_proxy_info_get_username(phb->gpi));
00256                 j = strlen(gaim_proxy_info_get_password(phb->gpi));
00257 
00258                 buf[0] = 0x01;  /* version 1 */
00259                 buf[1] = i;
00260                 memcpy(buf + 2, gaim_proxy_info_get_username(phb->gpi), i);
00261                 buf[2 + i] = j;
00262                 memcpy(buf + 2 + i + 1, gaim_proxy_info_get_password(phb->gpi), j);
00263 
00264                 if (write(source, buf, 3 + i + j) < 3 + i + j) {
00265                         close(source);
00266 
00267                         if (phb->account == NULL || gaim_account_get_connection(phb->account) != NULL) {
00268 
00269                                 phb->func(phb->data, -1, GAIM_INPUT_READ);
00270                         }
00271 
00272                         g_free(phb->host);
00273                         g_free(phb);
00274                         return;
00275                 }
00276 
00277                 phb->inpa = gaim_input_add(source, GAIM_INPUT_READ, _qq_s5_readauth, phb);
00278         } else {
00279                 gaim_debug(GAIM_DEBUG_INFO, "s5_canread", "calling s5_sendconnect\n");
00280                 _qq_s5_sendconnect(phb, source);
00281         }
00282 }
00283 
00284 /*****************************************************************************/
00285 void _qq_s5_canwrite(gpointer data, gint source, GaimInputCondition cond)
00286 {
00287         unsigned char buf[512];
00288         int i;
00289         struct PHB *phb = data;
00290         unsigned int len;
00291         int error = ETIMEDOUT;
00292 
00293         gaim_debug(GAIM_DEBUG_INFO, "socks5 proxy", "Connected.\n");
00294 
00295         if (phb->inpa > 0)
00296                 gaim_input_remove(phb->inpa);
00297 
00298         len = sizeof(error);
00299         if (getsockopt(source, SOL_SOCKET, SO_ERROR, &error, &len) < 0) {
00300                 gaim_debug(GAIM_DEBUG_INFO, "getsockopt", "%s\n", strerror(errno));
00301                 close(source);
00302                 if (phb->account == NULL || gaim_account_get_connection(phb->account) != NULL) {
00303 
00304                         phb->func(phb->data, -1, GAIM_INPUT_READ);
00305                 }
00306 
00307                 g_free(phb->host);
00308                 g_free(phb);
00309                 return;
00310         }
00311         fcntl(source, F_SETFL, 0);
00312 
00313         i = 0;
00314         buf[0] = 0x05;          /* SOCKS version 5 */
00315 
00316         if (gaim_proxy_info_get_username(phb->gpi) != NULL) {
00317                 buf[1] = 0x02;  /* two methods */
00318                 buf[2] = 0x00;  /* no authentication */
00319                 buf[3] = 0x02;  /* username/password authentication */
00320                 i = 4;
00321         } else {
00322                 buf[1] = 0x01;
00323                 buf[2] = 0x00;
00324                 i = 3;
00325         }
00326 
00327         if (write(source, buf, i) < i) {
00328                 gaim_debug(GAIM_DEBUG_INFO, "write", "%s\n", strerror(errno));
00329                 gaim_debug(GAIM_DEBUG_ERROR, "socks5 proxy", "Unable to write\n");
00330                 close(source);
00331 
00332                 if (phb->account == NULL || gaim_account_get_connection(phb->account) != NULL) {
00333 
00334                         phb->func(phb->data, -1, GAIM_INPUT_READ);
00335                 }
00336 
00337                 g_free(phb->host);
00338                 g_free(phb);
00339                 return;
00340         }
00341 
00342         phb->inpa = gaim_input_add(source, GAIM_INPUT_READ, _qq_s5_canread, phb);
00343 }
00344 
00345 /*****************************************************************************/
00346 gint qq_proxy_socks5(struct PHB * phb, struct sockaddr * addr, socklen_t addrlen)
00347 {
00348 
00349         gint fd;
00350         gaim_debug(GAIM_DEBUG_INFO, "QQ",
00351                    "Connecting to %s:%d via %s:%d using SOCKS5\n",
00352                    phb->host, phb->port, gaim_proxy_info_get_host(phb->gpi), gaim_proxy_info_get_port(phb->gpi));
00353 
00354         if ((fd = socket(addr->sa_family, SOCK_STREAM, 0)) < 0)
00355                 return -1;
00356 
00357         gaim_debug(GAIM_DEBUG_INFO, "QQ", "proxy_sock5 return fd=%d\n", fd);
00358 
00359         fcntl(fd, F_SETFL, O_NONBLOCK);
00360         if (connect(fd, addr, addrlen) < 0) {
00361                 if ((errno == EINPROGRESS) || (errno == EINTR)) {
00362                         gaim_debug(GAIM_DEBUG_WARNING, "QQ", "Connect in asynchronous mode.\n");
00363                         phb->inpa = gaim_input_add(fd, GAIM_INPUT_WRITE, _qq_s5_canwrite, phb);
00364                 } else {
00365                         close(fd);
00366                         return -1;
00367                 }               // if error
00368         } else {
00369                 gaim_debug(GAIM_DEBUG_MISC, "QQ", "Connect in blocking mode.\n");
00370                 fcntl(fd, F_SETFL, 0);
00371                 _qq_s5_canwrite(phb, fd, GAIM_INPUT_WRITE);
00372         }                       // if connect
00373 
00374         return fd;
00375 }                               // qq_proxy_connect

Generated at Mon May 8 15:41:24 2006 for OpenQ by  doxygen 1.4.4