228 lines
5.7 KiB
C
228 lines
5.7 KiB
C
/** _
|
|
** (_)_ __ __ ___ _ __ _ __
|
|
** | | ' \/ _/ _ \ ' \| ' \
|
|
** |_|_|_|_\__\___/_|_|_|_|_|_|
|
|
**
|
|
** Copyright (C) 2003-2005, Claudio Leite
|
|
** All rights reserved.
|
|
**
|
|
** Please see the file 'COPYING' for licensing information.
|
|
**/
|
|
|
|
#include "imcomm.h"
|
|
|
|
/* PROTO */
|
|
int
|
|
connect_socks5(void *handle, char *host, uint16_t port)
|
|
{
|
|
IMCOMM *h = (IMCOMM *) handle;
|
|
struct sockaddr_in sin;
|
|
struct hostent *he = NULL;
|
|
long addy;
|
|
struct in_addr ina = {0};
|
|
pkt_t *sockspkt;
|
|
uint8_t len;
|
|
unsigned char sockbuf[512];
|
|
|
|
#ifdef DEBUG
|
|
printf("Connecting via SOCKS5 to %s/%u\n", host, port);
|
|
printf("SOCKS5 proxy server: %s/%u\n", h->proxyserver, h->proxyport);
|
|
#endif
|
|
|
|
if ((he = gethostbyname(h->proxyserver)) == NULL) {
|
|
addy = inet_addr(h->proxyserver);
|
|
ina.s_addr = addy;
|
|
}
|
|
if ((h->socket = socket(AF_INET, SOCK_STREAM, 0)) == -1) {
|
|
if (h->callbacks[IMCOMM_ERROR])
|
|
h->callbacks[IMCOMM_ERROR] (handle, IMCOMM_ERROR_PROXY,
|
|
PROXY_ERROR_CONNECT);
|
|
|
|
return IMCOMM_RET_ERROR;
|
|
}
|
|
sin.sin_family = AF_INET;
|
|
sin.sin_port = htons(h->proxyport);
|
|
|
|
if (he == NULL)
|
|
sin.sin_addr = ina;
|
|
else
|
|
sin.sin_addr = *((struct in_addr *) he->h_addr);
|
|
|
|
memset(&(sin.sin_zero), 0, 8);
|
|
|
|
if (connect
|
|
(h->socket, (struct sockaddr *) & sin,
|
|
sizeof(struct sockaddr)) == -1) {
|
|
if (h->callbacks[IMCOMM_ERROR])
|
|
h->callbacks[IMCOMM_ERROR] (handle, IMCOMM_ERROR_PROXY,
|
|
PROXY_ERROR_CONNECT);
|
|
|
|
return IMCOMM_RET_ERROR;
|
|
}
|
|
sockspkt = pkt_init(3);
|
|
pkt_add8(sockspkt, 0x05);
|
|
pkt_add8(sockspkt, 0x01);
|
|
pkt_add8(sockspkt, 0x00);
|
|
|
|
if (send(h->socket, sockspkt->data, sockspkt->len, 0) < 0) {
|
|
pkt_free(sockspkt);
|
|
if (h->callbacks[IMCOMM_ERROR])
|
|
h->callbacks[IMCOMM_ERROR] (handle, IMCOMM_ERROR_DISCONNECTED,
|
|
0);
|
|
|
|
shutdown(h->socket, 0x02);
|
|
h->socket = -1;
|
|
return IMCOMM_RET_ERROR;
|
|
}
|
|
pkt_free(sockspkt);
|
|
|
|
recv(h->socket, sockbuf, 2, 0);
|
|
if (sockbuf[1] != 0x00) {
|
|
if (h->callbacks[IMCOMM_ERROR])
|
|
h->callbacks[IMCOMM_ERROR] (handle, IMCOMM_ERROR_PROXY,
|
|
PROXY_ERROR_AUTH);
|
|
return IMCOMM_RET_ERROR;
|
|
}
|
|
sockspkt = pkt_init(7 + strlen(host));
|
|
pkt_add8(sockspkt, 0x05);
|
|
pkt_add8(sockspkt, 0x01);
|
|
pkt_add8(sockspkt, 0x00);
|
|
pkt_add8(sockspkt, 0x03);
|
|
pkt_add8(sockspkt, (uint8_t) strlen(host));
|
|
pkt_addraw(sockspkt, (unsigned char *) host, strlen(host));
|
|
pkt_add16(sockspkt, port);
|
|
|
|
if (send(h->socket, sockspkt->data, sockspkt->len, 0) < 0) {
|
|
pkt_free(sockspkt);
|
|
if (h->callbacks[IMCOMM_ERROR])
|
|
h->callbacks[IMCOMM_ERROR] (handle, IMCOMM_ERROR_DISCONNECTED,
|
|
0);
|
|
|
|
shutdown(h->socket, 0x02);
|
|
h->socket = -1;
|
|
return IMCOMM_RET_ERROR;
|
|
}
|
|
pkt_free(sockspkt);
|
|
|
|
recv(h->socket, sockbuf, 4, 0);
|
|
if (sockbuf[1] != 0x00) {
|
|
if (h->callbacks[IMCOMM_ERROR])
|
|
h->callbacks[IMCOMM_ERROR] (handle, IMCOMM_ERROR_PROXY,
|
|
PROXY_ERROR_PROXYCONNECT);
|
|
shutdown(h->socket, 0x02);
|
|
h->socket = -1;
|
|
|
|
return IMCOMM_RET_ERROR;
|
|
}
|
|
if (sockbuf[3] == 0x03) {
|
|
recv(h->socket, &len, 1, 0);
|
|
recv(h->socket, sockbuf, len + 2, 0);
|
|
} else if (sockbuf[3] == 0x01) {
|
|
recv(h->socket, sockbuf, 6, 0);
|
|
} else {
|
|
if (h->callbacks[IMCOMM_ERROR])
|
|
h->callbacks[IMCOMM_ERROR] (handle, IMCOMM_ERROR_PROXY,
|
|
PROXY_ERROR_UNKNOWN);
|
|
|
|
shutdown(h->socket, 0x02);
|
|
h->socket = -1;
|
|
return IMCOMM_RET_ERROR;
|
|
}
|
|
|
|
/* now we should be set to read the connection */
|
|
|
|
return IMCOMM_RET_OK;
|
|
}
|
|
|
|
/* PROTO */
|
|
int
|
|
connect_https(void *handle, char *host, uint16_t port)
|
|
{
|
|
IMCOMM *h = (IMCOMM *) handle;
|
|
struct sockaddr_in sin;
|
|
struct hostent *he = NULL;
|
|
long addy;
|
|
struct in_addr ina = {0};
|
|
unsigned char sockbuf[512];
|
|
char *sptr;
|
|
int received, retcode;
|
|
|
|
#ifdef DEBUG
|
|
printf("Connecting via HTTPS to %s/%d.\n", host, port);
|
|
printf("Proxy server: %s/%d\n", h->proxyserver, h->proxyport);
|
|
#endif
|
|
|
|
if ((he = gethostbyname(h->proxyserver)) == NULL) {
|
|
addy = inet_addr(h->proxyserver);
|
|
ina.s_addr = addy;
|
|
}
|
|
if ((h->socket = socket(AF_INET, SOCK_STREAM, 0)) == -1) {
|
|
if (h->callbacks[IMCOMM_ERROR])
|
|
h->callbacks[IMCOMM_ERROR] (handle, IMCOMM_ERROR_PROXY,
|
|
PROXY_ERROR_CONNECT);
|
|
|
|
return IMCOMM_RET_ERROR;
|
|
}
|
|
sin.sin_family = AF_INET;
|
|
sin.sin_port = htons(h->proxyport);
|
|
|
|
if (he == NULL)
|
|
sin.sin_addr = ina;
|
|
else
|
|
sin.sin_addr = *((struct in_addr *) he->h_addr);
|
|
|
|
memset(&(sin.sin_zero), 0, 8);
|
|
|
|
if (connect
|
|
(h->socket, (struct sockaddr *) & sin,
|
|
sizeof(struct sockaddr)) == -1) {
|
|
if (h->callbacks[IMCOMM_ERROR])
|
|
h->callbacks[IMCOMM_ERROR] (handle, IMCOMM_ERROR_PROXY,
|
|
PROXY_ERROR_CONNECT);
|
|
|
|
return IMCOMM_RET_ERROR;
|
|
}
|
|
/*
|
|
* This user agent seems pretty well-accepted. Not sure if this is
|
|
* any sort of problem...
|
|
*/
|
|
|
|
snprintf((char *) sockbuf, sizeof(sockbuf),
|
|
"CONNECT %s:%d HTTP/1.0\r\nUser-agent: Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.0.2) Gecko/20021120 Netscape/7.01\r\n\r\n",
|
|
host, port);
|
|
if (send(h->socket, sockbuf, strlen((char *) sockbuf), 0) < 0) {
|
|
if (h->callbacks[IMCOMM_ERROR])
|
|
h->callbacks[IMCOMM_ERROR] (handle, IMCOMM_ERROR_DISCONNECTED,
|
|
0);
|
|
|
|
shutdown(h->socket, 0x02);
|
|
h->socket = -1;
|
|
return IMCOMM_RET_ERROR;
|
|
}
|
|
received = recv(h->socket, sockbuf, sizeof(sockbuf), 0);
|
|
sockbuf[received] = 0;
|
|
|
|
sptr = strchr((char *) sockbuf, ' ');
|
|
retcode = atoi(sptr + 1);
|
|
|
|
if (retcode != 200) {
|
|
if (h->callbacks[IMCOMM_ERROR])
|
|
h->callbacks[IMCOMM_ERROR] (handle, IMCOMM_ERROR_PROXY,
|
|
PROXY_ERROR_PROXYCONNECT);
|
|
|
|
shutdown(h->socket, 0x02);
|
|
h->socket = -1;
|
|
|
|
return IMCOMM_RET_ERROR;
|
|
} else {
|
|
while (strstr((char *) sockbuf, "\r\n\r\n") == NULL) {
|
|
received = recv(h->socket, sockbuf, sizeof(sockbuf), 0);
|
|
sockbuf[received] = 0;
|
|
}
|
|
}
|
|
|
|
/* now we should be set to read the connection */
|
|
|
|
return IMCOMM_RET_OK;
|
|
}
|