openwrt_helloworld/shadowsocksr-libev/src/server/http_simple.c
2022-04-17 03:50:24 +08:00

626 lines
20 KiB
C

#include "http_simple.h"
static char* g_useragent[] = {
"Mozilla/5.0 (Windows NT 6.3; WOW64; rv:40.0) Gecko/20100101 Firefox/40.0",
"Mozilla/5.0 (Windows NT 6.3; WOW64; rv:40.0) Gecko/20100101 Firefox/44.0",
"Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/41.0.2228.0 Safari/537.36",
"Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/535.11 (KHTML, like Gecko) Ubuntu/11.10 Chromium/27.0.1453.93 Chrome/27.0.1453.93 Safari/537.36",
"Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:35.0) Gecko/20100101 Firefox/35.0",
"Mozilla/5.0 (compatible; WOW64; MSIE 10.0; Windows NT 6.2)",
"Mozilla/5.0 (Windows; U; Windows NT 6.1; en-US) AppleWebKit/533.20.25 (KHTML, like Gecko) Version/5.0.4 Safari/533.20.27",
"Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 6.3; Trident/7.0; .NET4.0E; .NET4.0C)",
"Mozilla/5.0 (Windows NT 6.3; Trident/7.0; rv:11.0) like Gecko",
"Mozilla/5.0 (Linux; Android 4.4; Nexus 5 Build/BuildID) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/30.0.0.0 Mobile Safari/537.36",
"Mozilla/5.0 (iPad; CPU OS 5_0 like Mac OS X) AppleWebKit/534.46 (KHTML, like Gecko) Version/5.1 Mobile/9A334 Safari/7534.48.3",
"Mozilla/5.0 (iPhone; CPU iPhone OS 5_0 like Mac OS X) AppleWebKit/534.46 (KHTML, like Gecko) Version/5.1 Mobile/9A334 Safari/7534.48.3",
};
static int g_useragent_index = -1;
typedef struct http_simple_local_data {
int has_sent_header;
int has_recv_header;
char *encode_buffer;
int host_matched;
char *recv_buffer;
int recv_buffer_size;
}http_simple_local_data;
void http_simple_local_data_init(http_simple_local_data* local) {
local->has_sent_header = 0;
local->has_recv_header = 0;
local->encode_buffer = NULL;
local->recv_buffer = malloc(0);
local->recv_buffer_size = 0;
local->host_matched = 0;
if (g_useragent_index == -1) {
g_useragent_index = xorshift128plus() % (sizeof(g_useragent) / sizeof(*g_useragent));
}
}
obfs * http_simple_new_obfs() {
obfs * self = new_obfs();
self->l_data = malloc(sizeof(http_simple_local_data));
http_simple_local_data_init((http_simple_local_data*)self->l_data);
return self;
}
void http_simple_dispose(obfs *self) {
http_simple_local_data *local = (http_simple_local_data*)self->l_data;
if (local->encode_buffer != NULL) {
free(local->encode_buffer);
local->encode_buffer = NULL;
}
free(local);
dispose_obfs(self);
}
char http_simple_hex(char c) {
if (c < 10) return c + '0';
return c - 10 + 'a';
}
int get_data_from_http_header(char *data, char **outdata) {
char *delim = "\r\n";
char *delim_hex = "%";
int outlength = 0;
char *buf = *outdata;
char *p_line;
p_line = strtok(data, delim);
//while(p_line)
{
char *p_hex;
p_hex = strtok(p_line, delim_hex);
while((p_hex = strtok(NULL, delim_hex)))
{
char hex = 0;
if(strlen(p_hex) <= 0)
{
continue;
}
if(strlen(p_hex) > 2)
{
char *c_hex = (char*)malloc(2);
memcpy(c_hex, p_hex, 2);
hex = (char)strtol(c_hex, NULL, 16);
free(c_hex);
}
else
{
hex = (char)strtol(p_hex, NULL, 16);
}
outlength += 1;
buf = (char*)realloc(buf, outlength);
buf[outlength - 1] = hex;
}
//p_line = strtok(p_line, delim);
}
return outlength;
}
void get_host_from_http_header(char *data, char **host) {
char* data_begin = strstr(data, "Host: ");
if(data_begin == NULL)
{
return;
}
data_begin += 6;
char* data_end = strstr(data_begin, "\r\n");
char* data_end_port = strstr(data_begin, ":");
int host_length = 0;
if(data_end_port != NULL)
{
host_length = data_end_port - data_begin;
}
else
{
host_length = data_end - data_begin;
}
if(host_length <= 0)
{
return;
}
memset(*host, 0x00, 1024);
memcpy(*host, data_begin, host_length);
}
void http_simple_encode_head(http_simple_local_data *local, char *data, int datalength) {
if (local->encode_buffer == NULL) {
local->encode_buffer = (char*)malloc(datalength * 3 + 1);
}
int pos = 0;
for (; pos < datalength; ++pos) {
local->encode_buffer[pos * 3] = '%';
local->encode_buffer[pos * 3 + 1] = http_simple_hex(((unsigned char)data[pos] >> 4));
local->encode_buffer[pos * 3 + 2] = http_simple_hex(data[pos] & 0xF);
}
local->encode_buffer[pos * 3] = 0;
}
int http_simple_client_encode(obfs *self, char **pencryptdata, int datalength, size_t* capacity) {
char *encryptdata = *pencryptdata;
http_simple_local_data *local = (http_simple_local_data*)self->l_data;
if (local->has_sent_header) {
return datalength;
}
char hosts[1024];
char * phost[128];
int host_num = 0;
int pos;
char hostport[128];
int head_size = self->server.head_len + (xorshift128plus() & 0x3F);
int outlength;
char * out_buffer = (char*)malloc(datalength + 2048);
char * body_buffer = NULL;
if (head_size > datalength)
head_size = datalength;
http_simple_encode_head(local, encryptdata, head_size);
if (self->server.param && strlen(self->server.param) == 0)
self->server.param = NULL;
strncpy(hosts, self->server.param ? self->server.param : self->server.host, sizeof hosts);
phost[host_num++] = hosts;
for (pos = 0; hosts[pos]; ++pos) {
if (hosts[pos] == ',') {
phost[host_num++] = &hosts[pos + 1];
hosts[pos] = 0;
} else if (hosts[pos] == '#') {
char * body_pointer = &hosts[pos + 1];
char * p;
int trans_char = 0;
p = body_buffer = (char*)malloc(2048);
for ( ; *body_pointer; ++body_pointer) {
if (*body_pointer == '\\') {
trans_char = 1;
continue;
} else if (*body_pointer == '\n') {
*p = '\r';
*++p = '\n';
continue;
}
if (trans_char) {
if (*body_pointer == '\\' ) {
*p = '\\';
} else if (*body_pointer == 'n' ) {
*p = '\r';
*++p = '\n';
} else {
*p = '\\';
*p = *body_pointer;
}
trans_char = 0;
} else {
*p = *body_pointer;
}
++p;
}
*p = 0;
hosts[pos] = 0;
break;
}
}
host_num = xorshift128plus() % host_num;
if (self->server.port == 80)
sprintf(hostport, "%s", phost[host_num]);
else
sprintf(hostport, "%s:%d", phost[host_num], self->server.port);
if (body_buffer) {
sprintf(out_buffer,
"GET /%s HTTP/1.1\r\n"
"Host: %s\r\n"
"%s\r\n\r\n",
local->encode_buffer,
hostport,
body_buffer);
} else {
sprintf(out_buffer,
"GET /%s HTTP/1.1\r\n"
"Host: %s\r\n"
"User-Agent: %s\r\n"
"Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8\r\n"
"Accept-Language: en-US,en;q=0.8\r\n"
"Accept-Encoding: gzip, deflate\r\n"
"DNT: 1\r\n"
"Connection: keep-alive\r\n"
"\r\n",
local->encode_buffer,
hostport,
g_useragent[g_useragent_index]
);
}
//LOGI("http header: %s", out_buffer);
outlength = strlen(out_buffer);
memmove(out_buffer + outlength, encryptdata + head_size, datalength - head_size);
outlength += datalength - head_size;
local->has_sent_header = 1;
if (*capacity < outlength) {
*pencryptdata = (char*)realloc(*pencryptdata, *capacity = outlength * 2);
encryptdata = *pencryptdata;
}
memmove(encryptdata, out_buffer, outlength);
free(out_buffer);
if (body_buffer != NULL)
free(body_buffer);
if (local->encode_buffer != NULL) {
free(local->encode_buffer);
local->encode_buffer = NULL;
}
return outlength;
}
int http_simple_server_encode(obfs *self, char **pencryptdata, int datalength, size_t* capacity) {
char *encryptdata = *pencryptdata;
http_simple_local_data *local = (http_simple_local_data*)self->l_data;
if (local->has_sent_header) {
return datalength;
}
int outlength;
char * out_buffer = (char*)malloc(datalength + 2048);
time_t now;
struct tm *tm_now;
char datetime[200];
time(&now);
tm_now = localtime(&now);
strftime(datetime, 200, "%a, %d %b %Y %H:%M:%S GMT", tm_now);
sprintf(out_buffer,
"HTTP/1.1 200 OK\r\nConnection: keep-alive\r\nContent-Encoding: gzip\r\nContent-Type: text/html\r\nDate: "
"%s"
"\r\nServer: nginx\r\nVary: Accept-Encoding\r\n\r\n",
datetime);
outlength = strlen(out_buffer);
memmove(out_buffer + outlength, encryptdata, datalength);
outlength += datalength;
local->has_sent_header = 1;
if (*capacity < outlength) {
*pencryptdata = (char*)realloc(*pencryptdata, *capacity = outlength * 2);
encryptdata = *pencryptdata;
}
memmove(encryptdata, out_buffer, outlength);
free(out_buffer);
return outlength;
}
int http_simple_client_decode(obfs *self, char **pencryptdata, int datalength, size_t* capacity, int *needsendback) {
char *encryptdata = *pencryptdata;
http_simple_local_data *local = (http_simple_local_data*)self->l_data;
*needsendback = 0;
if (local->has_recv_header) {
return datalength;
}
char* data_begin = strstr(encryptdata, "\r\n\r\n");
if (data_begin) {
int outlength;
data_begin += 4;
local->has_recv_header = 1;
outlength = datalength - (data_begin - encryptdata);
memmove(encryptdata, data_begin, outlength);
return outlength;
} else {
return 0;
}
}
int http_simple_server_decode(obfs *self, char **pencryptdata, int datalength, size_t* capacity, int *needsendback) {
char *encryptdata = *pencryptdata;
http_simple_local_data *local = (http_simple_local_data*)self->l_data;
*needsendback = 0;
if (local->has_recv_header) {
return datalength;
}
if(datalength != 0)
{
local->recv_buffer = (char*)realloc(local->recv_buffer, local->recv_buffer_size + datalength);
memmove(local->recv_buffer + local->recv_buffer_size, encryptdata, datalength);
local->recv_buffer_size += datalength;
int outlength = local->recv_buffer_size;
if (*capacity < outlength) {
*pencryptdata = (char*)realloc(*pencryptdata, *capacity = outlength * 2);
encryptdata = *pencryptdata;
}
memcpy(encryptdata, local->recv_buffer, local->recv_buffer_size);
}
if(local->recv_buffer_size > 10)
{
if(strstr(local->recv_buffer, "GET /") == local->recv_buffer || strstr(local->recv_buffer, "POST /") == local->recv_buffer)
{
if(local->recv_buffer_size > 65536)
{
free(local->recv_buffer);
local->recv_buffer = malloc(0);
local->recv_buffer_size = 0;
local->has_sent_header = 1;
local->has_recv_header = 1;
LOGE("http_simple: over size");
return -1;
}
}
else
{
free(local->recv_buffer);
local->recv_buffer = malloc(0);
local->recv_buffer_size = 0;
local->has_sent_header = 1;
local->has_recv_header = 1;
LOGE("http_simple: not match begin");
return -1;
}
}
else
{
LOGE("http_simple: too short");
local->has_sent_header = 1;
local->has_recv_header = 1;
return -1;
}
char* data_begin = strstr(encryptdata, "\r\n\r\n");
if (data_begin) {
int outlength;
char *ret_buf = (char*)malloc(*capacity);
memset(ret_buf, 0x00, *capacity);
int ret_buf_len = 0;
ret_buf_len = get_data_from_http_header(encryptdata, &ret_buf);
if (self->server.param && strlen(self->server.param) == 0)
{
self->server.param = NULL;
}
else
{
if(local->host_matched == 0)
{
char *host = (char*)malloc(1024);
get_host_from_http_header(local->recv_buffer, &host);
char hosts[1024];
char * phost[128];
int host_num = 0;
int pos = 0;
int is_match = 0;
char * body_buffer = NULL;
strncpy(hosts, self->server.param, sizeof hosts);
phost[host_num++] = hosts;
for (pos = 0; hosts[pos]; ++pos) {
if (hosts[pos] == ',') {
phost[host_num++] = &hosts[pos + 1];
hosts[pos] = 0;
} else if (hosts[pos] == '#') {
char * body_pointer = &hosts[pos + 1];
char * p;
int trans_char = 0;
p = body_buffer = (char*)malloc(2048);
for ( ; *body_pointer; ++body_pointer) {
if (*body_pointer == '\\') {
trans_char = 1;
continue;
} else if (*body_pointer == '\n') {
*p = '\r';
*++p = '\n';
continue;
}
if (trans_char) {
if (*body_pointer == '\\' ) {
*p = '\\';
} else if (*body_pointer == 'n' ) {
*p = '\r';
*++p = '\n';
} else {
*p = '\\';
*p = *body_pointer;
}
trans_char = 0;
} else {
*p = *body_pointer;
}
++p;
}
*p = 0;
hosts[pos] = 0;
break;
}
}
for(pos = 0; pos < host_num; pos++)
{
if(strcmp(phost[pos], host) == 0)
{
is_match = 1;
local->host_matched = 1;
}
}
if(is_match == 0)
{
free(local->recv_buffer);
local->recv_buffer = malloc(0);
local->recv_buffer_size = 0;
local->has_sent_header = 1;
local->has_recv_header = 1;
LOGE("http_simple: not match host, host: %s", host);
return -1;
}
free(host);
}
}
if(ret_buf_len <= 0)
{
return -1;
}
data_begin += 4;
local->has_recv_header = 1;
ret_buf = (char*)realloc(ret_buf, ret_buf_len + datalength - (data_begin - encryptdata));
outlength = ret_buf_len + datalength - (data_begin - encryptdata);
memcpy(ret_buf + ret_buf_len, data_begin, datalength - (data_begin - encryptdata));
if (*capacity < outlength) {
*pencryptdata = (char*)realloc(*pencryptdata, *capacity = outlength * 2);
encryptdata = *pencryptdata;
}
memcpy(encryptdata, ret_buf, outlength);
free(ret_buf);
return outlength;
} else {
return 0;
}
}
void boundary(char result[])
{
char *str = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
int i,lstr;
char ss[3] = {0};
lstr = strlen(str);
srand((unsigned int)time((time_t *)NULL));
for(i = 0; i < 32; ++i)
{
sprintf(ss, "%c", str[(rand()%lstr)]);
strcat(result, ss);
}
}
int http_post_client_encode(obfs *self, char **pencryptdata, int datalength, size_t* capacity) {
char *encryptdata = *pencryptdata;
http_simple_local_data *local = (http_simple_local_data*)self->l_data;
if (local->has_sent_header) {
return datalength;
}
char hosts[1024];
char * phost[128];
int host_num = 0;
int pos;
char hostport[128];
int head_size = self->server.head_len + (xorshift128plus() & 0x3F);
int outlength;
char * out_buffer = (char*)malloc(datalength + 2048);
char * body_buffer = NULL;
if (head_size > datalength)
head_size = datalength;
http_simple_encode_head(local, encryptdata, head_size);
if (self->server.param && strlen(self->server.param) == 0)
self->server.param = NULL;
strncpy(hosts, self->server.param ? self->server.param : self->server.host, sizeof hosts);
phost[host_num++] = hosts;
for (pos = 0; hosts[pos]; ++pos) {
if (hosts[pos] == ',') {
phost[host_num++] = &hosts[pos + 1];
hosts[pos] = 0;
} else if (hosts[pos] == '#') {
char * body_pointer = &hosts[pos + 1];
char * p;
int trans_char = 0;
p = body_buffer = (char*)malloc(2048);
for ( ; *body_pointer; ++body_pointer) {
if (*body_pointer == '\\') {
trans_char = 1;
continue;
} else if (*body_pointer == '\n') {
*p = '\r';
*++p = '\n';
continue;
}
if (trans_char) {
if (*body_pointer == '\\' ) {
*p = '\\';
} else if (*body_pointer == 'n' ) {
*p = '\r';
*++p = '\n';
} else {
*p = '\\';
*p = *body_pointer;
}
trans_char = 0;
} else {
*p = *body_pointer;
}
++p;
}
*p = 0;
hosts[pos] = 0;
break;
}
}
host_num = xorshift128plus() % host_num;
if (self->server.port == 80)
sprintf(hostport, "%s", phost[host_num]);
else
sprintf(hostport, "%s:%d", phost[host_num], self->server.port);
if (body_buffer) {
sprintf(out_buffer,
"POST /%s HTTP/1.1\r\n"
"Host: %s\r\n"
"%s\r\n\r\n",
local->encode_buffer,
hostport,
body_buffer);
} else {
char result[33] = {0};
boundary(result);
sprintf(out_buffer,
"POST /%s HTTP/1.1\r\n"
"Host: %s\r\n"
"User-Agent: %s\r\n"
"Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8\r\n"
"Accept-Language: en-US,en;q=0.8\r\n"
"Accept-Encoding: gzip, deflate\r\n"
"Content-Type: multipart/form-data; boundary=%s\r\n"
"DNT: 1\r\n"
"Connection: keep-alive\r\n"
"\r\n",
local->encode_buffer,
hostport,
g_useragent[g_useragent_index],
result
);
}
//LOGI("http header: %s", out_buffer);
outlength = strlen(out_buffer);
memmove(out_buffer + outlength, encryptdata + head_size, datalength - head_size);
outlength += datalength - head_size;
local->has_sent_header = 1;
if (*capacity < outlength) {
*pencryptdata = (char*)realloc(*pencryptdata, *capacity = outlength * 2);
encryptdata = *pencryptdata;
}
memmove(encryptdata, out_buffer, outlength);
free(out_buffer);
if (body_buffer != NULL)
free(body_buffer);
if (local->encode_buffer != NULL) {
free(local->encode_buffer);
local->encode_buffer = NULL;
}
return outlength;
}