c语言 http proxy 源码,一个简单的C语言TCP Proxy实现

前几天项目中需要一个抓取并分析TCP包的工具,在网上倒腾了一阵子整理了一个工具,现在发布在这儿提供参考。

这个工具是使用C语言开发的一个TCP Proxy,实现TCP转发的功能并dump出来数据包的内容。

#include

#include

#include

#include

#include

#include

#define LOG_ERROR(...)

#define LOG_INFO(...)

#define LOG_DEBUG(...)

#define DEBUG 0

#define BUFFER_SIZE 16384

#define LINE_SIZE 32

/* parameter variable */

int listen_port = 0;

int remote_port = 0;

char * remote_host = NULL;

int foreground = 1;

/*global variable */

int listen_socket;

void help(char * program) {

printf("Usage syntax: %s -l listen_port -r remote_host -p remote_port [-f (in foreground)]\n", program);

}

void dumpBufferRaw(const unsigned char buffer[], size_t len) {

int i = 0;

int j = 0;

int k = 0;

char output[LINE_SIZE * 4 + 10] = { ' ' };

// print header

for (k = 0; k < LINE_SIZE; k++) {

printf("%02d ", k);

}

printf("\n");

for (k = 0; k < LINE_SIZE; k++) {

printf("---");

}

printf("\n");

memset(output, ' ', sizeof(output));

for (; i < len; i++) {

sprintf(output + j * 3, "%02X ", buffer[i]);

sprintf(output + LINE_SIZE * 3 + 4 + j , "%c", isprint(buffer[i]) ? buffer[i] : '.');

j++;

if (j >= LINE_SIZE) {

output[j * 3] = ' ';

printf("%s\n", output);

memset(output, ' ', sizeof(output));

j = 0;

}

}

if (j > 0) {

output[j * 3] = ' ';

printf("%s\n", output);

};

// print tailer

for (k = 0; k < LINE_SIZE; k++) {

printf("---");

}

printf("\n");

}

/* create server socket */

int server_listen() {

int optval = 1;

struct sockaddr_in listen_addr;

LOG_DEBUG("Entry of server_listen");

if ((listen_socket = socket(AF_INET, SOCK_STREAM, 0)) < 0) {

LOG_ERROR("Cannot create listen socket, errno=[%d], errstr=[%s]", errno, strerror(errno));

return -1;

}

if (setsockopt(listen_socket, SOL_SOCKET, SO_REUSEADDR, &optval, sizeof(optval)) < 0) {

LOG_ERROR("Cannot set listen socket option, errno=[%d], errstr=[%s]", errno, strerror(errno));

return -1;

}

memset(&listen_addr, 0, sizeof(listen_addr));

listen_addr.sin_family = AF_INET;

listen_addr.sin_port = htons(listen_port);

listen_addr.sin_addr.s_addr = INADDR_ANY;

if (bind(listen_socket, (struct sockaddr *)&listen_addr, sizeof(listen_addr)) != 0) {

LOG_ERROR("Cannot bind listen socket, errno=[%d], errstr=[%s]", errno, strerror(errno));

return -1;

}

if (listen(listen_socket, 5) < 0) {

LOG_ERROR("Cannot listen socket, errno=[%d], errstr=[%s]", errno, strerror(errno));

return -1;

}

LOG_DEBUG("Server listen on port: %d", listen_port);

return 0;

}

/**

* return > 0 : success

* = 0 : socket close

* < 0 : error

*/

ssize_t forward_data(int fromsocket, int tosocket) {

unsigned char buffer[BUFFER_SIZE];

ssize_t n = recv(fromsocket, buffer, sizeof(buffer), 0);

if (n > 0) {

LOG_DEBUG("data socket: %d -> %d, size: %d", fromsocket, tosocket, n);

if (!DEBUG) {

dumpBufferRaw(buffer, n);

}

ssize_t m = send(tosocket, buffer, n, 0); // send data to output socket

if (m < 0) {

LOG_ERROR("Cannot call send, errno=[%d], errstr=[%s]", errno, strerror(errno));

return m;

}

else if (m != n) {

LOG_ERROR("Cannot call send, return %ld, expected %ld", m, n);

return -1;

}

else {

return n;

}

}

else if (n == 0) {

LOG_INFO("socket closed: %d", fromsocket);

return 0;

}

else {

LOG_ERROR("Cannot call recv, errno=[%d], errstr=[%s]", errno, strerror(errno));

return n;

}

}

void message_loop(int client_socket) {

fd_set fdsets;

int remote_socket = connect_remote();

if (remote_socket > 0) {

LOG_INFO("Remote connection, remote socket=%d", remote_socket);

while (1) {

FD_ZERO(&fdsets);

FD_SET(client_socket, &fdsets);

FD_SET(remote_socket, &fdsets);

int ret = select(FD_SETSIZE, &fdsets, NULL, NULL, NULL);

if (ret < 0) {

LOG_ERROR("Cannot call select, errno=[%d], errstr=[%s]", errno, strerror(errno));

break;

}

else if (ret == 0) {

continue;

}

if (FD_ISSET(client_socket, &fdsets)) {

ssize_t n = forward_data(client_socket, remote_socket);

if (n <= 0) {

break;

}

}

if (FD_ISSET(remote_socket, &fdsets)) {

ssize_t n = forward_data(remote_socket, client_socket);

if (n <= 0) {

break;

}

}

}

close(remote_socket);

}

close(client_socket);

}

void server_loop() {

while (1) {

struct sockaddr client_addr;

socklen_t client_size = sizeof(client_addr);

int client_socket = accept(listen_socket, (struct sockaddr *)&client_addr, &client_size);

if (client_socket < 0) {

LOG_ERROR("Cannot accept client connection, errno=[%d], errstr=[%s]", errno, strerror(errno));

continue;

}

LOG_INFO("Connection accept, client socket=%d", client_socket);

pid_t pid = fork();

if (pid > 0) { // parent process

LOG_INFO("close client socket in parent process");

close(client_socket);

}

else if (pid == 0) { // child process

close(listen_socket);

LOG_INFO("close listen socket in child process");

message_loop(client_socket);

exit(0);

}

else if (pid < 0) {

LOG_ERROR("Cannot fork client process, errno=[%d], errstr=[%s]", errno, strerror(errno));

continue;

}

}

}

int connect_remote() {

struct sockaddr_in remote_addr;

struct hostent * remote_server;

int remote_socket;

if ((remote_socket = socket(AF_INET, SOCK_STREAM, 0)) < 0) {

LOG_ERROR("Cannot create remote socket, errno=[%d], errstr=[%s]", errno, strerror(errno));

return -1;

}

if ((remote_server = gethostbyname(remote_host)) == NULL) {

LOG_ERROR("Cannot get host by remote host name %s, errno=[%d], errstr=[%s]", remote_host, errno, strerror(errno));

return -1;

}

memset(&remote_addr, 0, sizeof(remote_addr));

remote_addr.sin_family = AF_INET;

memcpy(&remote_addr.sin_addr.s_addr, remote_server->h_addr, remote_server->h_length);

remote_addr.sin_port = htons(remote_port);

if (connect(remote_socket, (struct sockaddr *) &remote_addr, sizeof(remote_addr)) < 0) {

LOG_ERROR("Cannot connect to remote host %s:%d, errno=[%d], errstr=[%s]", remote_host, remote_port, errno, strerror(errno));

return -1;

}

return remote_socket;

}

int parse_options(int argc, char *argv[]) {

int c = 0;

while ((c = getopt(argc, argv, "l:r:p:f:h")) != -1) {

switch(c) {

case 'l':

listen_port = atoi(optarg);

break;

case 'r':

remote_host = optarg;

break;

case 'p':

remote_port = atoi(optarg);

break;

case 'f':

foreground = 1;

break;

case 'h':

help(argv[0]);

exit(0);

default:

fprintf(stderr, "ERROR: unsupported parameter %c\n", c);

return -1;

}

}

if (listen_port == 0 || remote_host == NULL || remote_port == 0) {

return -1;

}

LOG_INFO("Server configuration, listen on %d, remote host: [%s], remote port: %d", listen_port, remote_host, remote_port);

return 0;

}

/* handle finished child process */

void sigchld_handler(int signal) {

while (waitpid(-1, NULL, WNOHANG) > 0);

}

int main(int argc, char *argv[]) {

if (parse_options(argc, argv) < 0) {

help(argv[0]);

return -1;

}

if (server_listen() < 0) { // start server

LOG_ERROR("Cannot start server listen on port %d", listen_port);

return -1;

}

signal(SIGCHLD, sigchld_handler); // prevent ended children from becoming zombies

if (!foreground) {

pid_t pid = fork();

if (pid > 0) { // parent

exit(0);

}

else if (pid == 0) { // // deamonized child

}

else { // error

LOG_ERROR("Cannot create listen socket, errno=[%d], errstr=[%s]", errno, strerror(errno));

return -1;

}

}

server_loop();

return 0;

}

Linux环境下编译测试通过

$ gcc main.c

$ ./a.out

Usage syntax: ./a.out-l listen_port -r remote_host -p remote_port [-f (in foreground)]

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值