Mercurial > pidgin
diff src/proxy.c @ 1087:56c7ceb986a8
[gaim-migrate @ 1097]
thank god, someone finally redid the proxy stuff. i think most of it works even. isn't that neat? thanks adam.
committer: Tailor Script <tailor@pidgin.im>
| author | Eric Warmenhoven <eric@warmenhoven.org> |
|---|---|
| date | Sun, 12 Nov 2000 23:54:07 +0000 |
| parents | d50d3abb9eb7 |
| children | 46c09828e929 |
line wrap: on
line diff
--- a/src/proxy.c Sun Nov 12 14:14:12 2000 +0000 +++ b/src/proxy.c Sun Nov 12 23:54:07 2000 +0000 @@ -38,16 +38,8 @@ #include "gaim.h" #include "proxy.h" - -/* static int proxy_inited=0; */ -int proxy_type = 0; -char proxy_host[256]; -int proxy_port = 3128; -char *proxy_realhost = NULL; - /* this code is borrowed from cvs 1.10 */ -static int -proxy_recv_line (int sock, char **resultp) +static int proxy_recv_line (int sock, char **resultp) { int c; char *result; @@ -93,183 +85,222 @@ return input_index; } - -struct hostent *proxy_gethostbyname(char *host) +static int proxy_connect_none(char *host, unsigned short port) { - - if (proxy_type == PROXY_NONE) - return (gethostbyname(host)); + struct sockaddr_in sin; + struct hostent *hp; + int fd = -1; + + debug_printf("connecting to %s:%d with no proxy\n", host, port); + + if (!(hp = gethostbyname(host))) + return -1; + + memset(&sin, 0, sizeof(struct sockaddr_in)); + memcpy(&sin.sin_addr.s_addr, hp->h_addr, hp->h_length); + sin.sin_family = hp->h_addrtype; + sin.sin_port = htons(port); + + if ((fd = socket(hp->h_addrtype, SOCK_STREAM, 0)) < 0) + return -1; + + if (connect(fd, (struct sockaddr *)&sin, sizeof(sin)) < 0) { + close(fd); + return -1; + } + + return fd; +} + +#define HTTP_GOODSTRING "HTTP/1.0 200 Connection established" +#define HTTP_GOODSTRING2 "HTTP/1.1 200 Connection established" + +static int proxy_connect_http(char *host, unsigned short port, + char *proxyhost, unsigned short proxyport) +{ + struct hostent *hp; + struct sockaddr_in sin; + int fd = -1; + char cmd[384]; + char *inputline; - if (proxy_realhost != NULL) - g_free(proxy_realhost); + debug_printf("connecting to %s:%d via %s:%d using HTTP\n", host, port, proxyhost, proxyport); + + if (!(hp = gethostbyname(proxyhost))) + return -1; + + memset(&sin, 0, sizeof(struct sockaddr_in)); + memcpy(&sin.sin_addr.s_addr, hp->h_addr, hp->h_length); + sin.sin_family = hp->h_addrtype; + sin.sin_port = htons(proxyport); + + if ((fd = socket(hp->h_addrtype, SOCK_STREAM, 0)) < 0) + return -1; + + if (connect(fd, (struct sockaddr *)&sin, sizeof(sin)) < 0) { + close(fd); + return -1; + } + + snprintf(cmd, sizeof(cmd), "CONNECT %s:%d HTTP/1.1\n\r\n\r", host, port); - /* we keep the real host name for the Connect command */ - proxy_realhost = (char *) strdup(host); - - return (gethostbyname(proxy_host)); - + if (send(fd, cmd, strlen(cmd),0) < 0) + return -1; + if (proxy_recv_line(fd, &inputline) < 0) + return -1; + + if ((memcmp(HTTP_GOODSTRING, inputline, strlen(HTTP_GOODSTRING) == 0) || + (memcmp(HTTP_GOODSTRING2, inputline, strlen(HTTP_GOODSTRING2) == 0)))) { + while (strlen(inputline) > 1) { + free(inputline); + if (proxy_recv_line(fd, &inputline) < 0) + return -1; + } + free(inputline); + return fd; + } + + free(inputline); + + close(fd); + + return -1; } - -int proxy_connect(int sockfd, struct sockaddr *serv_addr, int - addrlen ) +static int proxy_connect_socks4(char *host, unsigned short port, + char *proxyhost, unsigned short proxyport) { - struct sockaddr_in name; - int ret; + struct sockaddr_in sin; + unsigned char packet[12]; + struct hostent *hp; + int fd = -1; - switch (proxy_type) { - case PROXY_NONE: - /* normal use */ - return (connect(sockfd,serv_addr,addrlen)); - break; - case PROXY_HTTP: /* Http proxy */ - /* do the tunneling */ - /* step one : connect to proxy */ - { - struct hostent *hostinfo; - unsigned short shortport = proxy_port; + debug_printf("connecting to %s:%d via %s:%d using SOCKS4\n", host, port, proxyhost, proxyport); - memset (&name, 0, sizeof (name)); - name.sin_family = AF_INET; - name.sin_port = htons (shortport); - hostinfo = gethostbyname (proxy_host); - if (hostinfo == NULL) { - fprintf (stderr, "Unknown host %s.\n", proxy_host); - return (-1); - } - name.sin_addr = *(struct in_addr *) hostinfo->h_addr; - } - sprintf(debug_buff,"Trying to connect ...\n"); - debug_print(debug_buff); - if ((ret = connect(sockfd,(struct sockaddr *)&name,sizeof(name)))<0) - return(ret); - - /* step two : do proxy tunneling init */ - { - char cmd[80]; - char *inputline; - unsigned short realport=ntohs(((struct sockaddr_in *)serv_addr)->sin_port); - sprintf(cmd,"CONNECT %s:%d HTTP/1.1\n\r\n\r",proxy_realhost,realport); - sprintf(debug_buff,"<%s>\n",cmd); - debug_print(debug_buff); - if (send(sockfd,cmd,strlen(cmd),0)<0) - return(-1); - if (proxy_recv_line(sockfd,&inputline) < 0) { - return(-1); - } - sprintf(debug_buff,"<%s>\n",inputline); - debug_print(debug_buff); - if (memcmp("HTTP/1.0 200 Connection established",inputline,35)) - if (memcmp("HTTP/1.1 200 Connection established",inputline,35)) { - free(inputline); - return(-1); - } + if (!(hp = gethostbyname(proxyhost))) + return -1; - while (strlen(inputline)>1) { - free(inputline); - if (proxy_recv_line(sockfd,&inputline) < 0) { - return(-1); - } - sprintf(debug_buff,"<%s>\n",inputline); - debug_print(debug_buff); - } - free(inputline); - } - - return 0; - break; - case PROXY_SOCKS4: - /* code shamelessly stolen from everybuddy */ - { - struct sockaddr_in sa; - unsigned char packet[12]; - struct hostent *hp; - - debug_print("connecting with socks4.\n"); - - if (!(hp = gethostbyname(proxy_host))) - return -1; + memset(&sin, 0, sizeof(struct sockaddr_in)); + memcpy(&sin.sin_addr.s_addr, hp->h_addr, hp->h_length); + sin.sin_family = hp->h_addrtype; + sin.sin_port = htons(proxyport); - bzero(&sa, sizeof(sa)); - sa.sin_family = AF_INET; - sa.sin_port = htons(proxy_port); - bcopy(hp->h_addr, (char *) &sa.sin_addr, hp->h_length); + if ((fd = socket(hp->h_addrtype, SOCK_STREAM, 0)) < 0) + return -1; - if (connect(sockfd, (struct sockaddr *) &sa, sizeof (sa)) != -1) { - unsigned short realport = htons(((struct sockaddr_in *)serv_addr)->sin_port); - - if (!(hp = gethostbyname(proxy_realhost))) - return -1; - packet[0] = 4; - packet[1] = 1; - packet[2] = (((unsigned short) realport) >> 8); - packet[3] = (((unsigned short) realport) & 0xff); - packet[4] = (unsigned char) (hp->h_addr_list[0])[0]; - packet[5] = (unsigned char) (hp->h_addr_list[0])[1]; - packet[6] = (unsigned char) (hp->h_addr_list[0])[2]; - packet[7] = (unsigned char) (hp->h_addr_list[0])[3]; - packet[8] = 0; - if (write(sockfd, packet, 9) == 9) { - bzero(packet, sizeof(packet)); - if (read(sockfd, packet, 9) >= 4 && packet[1] == 90) - return 0; - } - close(sockfd); - } + if (connect(fd, (struct sockaddr *)&sin, sizeof(sin)) < 0) { + close(fd); return -1; } - break; - case PROXY_SOCKS5: - { - struct sockaddr_in sin; - struct hostent *hostinfo; - char buff[11]; - sethostent(0); - hostinfo = gethostbyname(proxy_host); - if (!hostinfo) return -1; - - sin.sin_addr.s_addr = atol(hostinfo->h_addr); - sin.sin_family = AF_INET; - sin.sin_port = htons(proxy_port); - - if (connect(sockfd, (struct sockaddr *)&sin, sizeof(sin)) < 0) - return -1; - - buff[0] = 5; - buff[1] = 1; - buff[2] = 0; - - write(sockfd, buff, 3); - read(sockfd, buff, 2); - - if (buff[1]) return -1; + /* XXX does socks4 not support host name lookups by the proxy? */ + if (!(hp = gethostbyname(host))) + return -1; - hostinfo = gethostbyname(proxy_realhost); - if (!hostinfo) return -1; - - buff[0] = 5; - buff[1] = 1; - buff[2] = 0; - buff[3] = 1; - buff[4] = (unsigned char) (hostinfo->h_addr_list[0])[0]; - buff[5] = (unsigned char) (hostinfo->h_addr_list[0])[1]; - buff[6] = (unsigned char) (hostinfo->h_addr_list[0])[2]; - buff[7] = (unsigned char) (hostinfo->h_addr_list[0])[3]; - memcpy(buff+8, &((struct sockaddr_in *)serv_addr)->sin_port, 2); + packet[0] = 4; + packet[1] = 1; + packet[2] = (((unsigned short) htons(port)) >> 8); + packet[3] = (((unsigned short) htons(port)) & 0xff); + packet[4] = (unsigned char) (hp->h_addr_list[0])[0]; + packet[5] = (unsigned char) (hp->h_addr_list[0])[1]; + packet[6] = (unsigned char) (hp->h_addr_list[0])[2]; + packet[7] = (unsigned char) (hp->h_addr_list[0])[3]; + packet[8] = 0; + if (write(fd, packet, 9) == 9) { + memset(packet, 0, sizeof(packet)); + if (read(fd, packet, 9) >= 4 && packet[1] == 90) + return fd; + } + close(fd); - write(sockfd, buff, 10); - read(sockfd, buff, 10); - - if (buff[1]) return -1; - - return 0; - } - break; - default: - fprintf(stderr,"Unknown proxy type : %d.\n",proxy_type); - break; - } - return(-1); + return -1; } +static int proxy_connect_socks5(char *host, unsigned short port, + char *proxyhost, unsigned short proxyport) +{ + int i, fd = -1; + unsigned char buf[512]; + struct sockaddr_in sin; + struct hostent *hp; + + debug_printf("connecting to %s:%d via %s:%d using SOCKS5\n", host, port, proxyhost, proxyport); + + if (!(hp = gethostbyname(proxyhost))) + return -1; + + memset(&sin, 0, sizeof(struct sockaddr_in)); + memcpy(&sin.sin_addr.s_addr, hp->h_addr, hp->h_length); + sin.sin_family = hp->h_addrtype; + sin.sin_port = htons(proxyport); + + if ((fd = socket(hp->h_addrtype, SOCK_STREAM, 0)) < 0) + return -1; + + if (connect(fd, (struct sockaddr *)&sin, sizeof(sin)) < 0) { + close(fd); + return -1; + } + + i = 0; + buf[0] = 0x05; /* SOCKS version 5 */ + buf[1] = 0x01; + buf[2] = 0x00; + i = 3; + + if (write(fd, buf, i) < i) { + close(fd); + return -1; + } + + if (read(fd, buf, 2) < 2) { + close(fd); + return -1; + } + + if ((buf[0] != 0x05) || (buf[1] == 0xff)) { + close(fd); + return -1; + } + + buf[0] = 0x05; + buf[1] = 0x01; /* CONNECT */ + buf[2] = 0x00; /* reserved */ + buf[3] = 0x03; /* address type -- host name */ + buf[4] = strlen(host); + memcpy(buf+5, host, strlen(host)); + buf[5+strlen(host)] = htons(port) >> 8; + buf[5+strlen(host)+1] = htons(port) & 0xff; + + if (write(fd, buf, (5+strlen(host)+2)) < (5+strlen(host)+2)) { + close(fd); + return -1; + } + if (read(fd, buf, 10) < 10) { + close(fd); + return -1; + } + if ((buf[0] != 0x05) || (buf[1] != 0x00)) { + close(fd); + return -1; + } + + return fd; +} + +int proxy_connect(char *host, int port, char *proxyhost, int proxyport, int proxytype) +{ + if (!host || !port || (port == -1)) + return -1; + else if ((proxytype == PROXY_NONE) || + !proxyhost || !proxyhost[0] || + !proxyport || (proxyport == -1)) + return proxy_connect_none(host, port); + else if (proxytype == PROXY_HTTP) + return proxy_connect_http(host, port, proxyhost, proxyport); + else if (proxytype == PROXY_SOCKS4) + return proxy_connect_socks4(host, port, proxyhost, proxyport); + else if (proxytype == PROXY_SOCKS5) + return proxy_connect_socks5(host, port, proxyhost, proxyport); + return -1; +}
