Chat-O-Matic/libs/libimcomm/proxy.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;
}