From ab32e2a4809544be9dd3d6e038804d1f7ac88e1d Mon Sep 17 00:00:00 2001 From: clowwindy Date: Thu, 24 May 2012 17:51:51 +0800 Subject: [PATCH] add server(not implemented yet) --- Makefile.am | 3 +- Makefile.in | 14 +- server.c | 451 ++++++++++++++++++++++++++++++++++++++++++++++++++++ server.h | 52 ++++++ socks5.h | 37 +++++ 5 files changed, 553 insertions(+), 4 deletions(-) create mode 100644 server.c create mode 100644 server.h create mode 100755 socks5.h diff --git a/Makefile.am b/Makefile.am index 91ddeb8a..5bbaa3c8 100644 --- a/Makefile.am +++ b/Makefile.am @@ -1,3 +1,4 @@ -bin_PROGRAMS = local +bin_PROGRAMS = local server local_SOURCES = encrypt.c encrypt.h local.c local.h +server_SOURCES = encrypt.c encrypt.h server.c server.h socks5.h diff --git a/Makefile.in b/Makefile.in index a20dcf4d..836a0cd2 100644 --- a/Makefile.in +++ b/Makefile.in @@ -32,7 +32,7 @@ POST_INSTALL = : NORMAL_UNINSTALL = : PRE_UNINSTALL = : POST_UNINSTALL = : -bin_PROGRAMS = local$(EXEEXT) +bin_PROGRAMS = local$(EXEEXT) server$(EXEEXT) subdir = . DIST_COMMON = $(am__configure_deps) $(srcdir)/Makefile.am \ $(srcdir)/Makefile.in $(srcdir)/config.h.in \ @@ -52,6 +52,9 @@ PROGRAMS = $(bin_PROGRAMS) am_local_OBJECTS = encrypt.$(OBJEXT) local.$(OBJEXT) local_OBJECTS = $(am_local_OBJECTS) local_LDADD = $(LDADD) +am_server_OBJECTS = encrypt.$(OBJEXT) server.$(OBJEXT) +server_OBJECTS = $(am_server_OBJECTS) +server_LDADD = $(LDADD) DEFAULT_INCLUDES = -I.@am__isrc@ depcomp = $(SHELL) $(top_srcdir)/depcomp am__depfiles_maybe = depfiles @@ -60,8 +63,8 @@ COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \ $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) CCLD = $(CC) LINK = $(CCLD) $(AM_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) $(LDFLAGS) -o $@ -SOURCES = $(local_SOURCES) -DIST_SOURCES = $(local_SOURCES) +SOURCES = $(local_SOURCES) $(server_SOURCES) +DIST_SOURCES = $(local_SOURCES) $(server_SOURCES) ETAGS = etags CTAGS = ctags DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) @@ -166,6 +169,7 @@ top_build_prefix = @top_build_prefix@ top_builddir = @top_builddir@ top_srcdir = @top_srcdir@ local_SOURCES = encrypt.c encrypt.h local.c local.h +server_SOURCES = encrypt.c encrypt.h server.c server.h socks5.h all: config.h $(MAKE) $(AM_MAKEFLAGS) all-am @@ -260,6 +264,9 @@ clean-binPROGRAMS: local$(EXEEXT): $(local_OBJECTS) $(local_DEPENDENCIES) $(EXTRA_local_DEPENDENCIES) @rm -f local$(EXEEXT) $(LINK) $(local_OBJECTS) $(local_LDADD) $(LIBS) +server$(EXEEXT): $(server_OBJECTS) $(server_DEPENDENCIES) $(EXTRA_server_DEPENDENCIES) + @rm -f server$(EXEEXT) + $(LINK) $(server_OBJECTS) $(server_LDADD) $(LIBS) mostlyclean-compile: -rm -f *.$(OBJEXT) @@ -269,6 +276,7 @@ distclean-compile: @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/encrypt.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/local.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/server.Po@am__quote@ .c.o: @am__fastdepCC_TRUE@ $(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< diff --git a/server.c b/server.c new file mode 100644 index 00000000..9ad03cce --- /dev/null +++ b/server.c @@ -0,0 +1,451 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "server.h" +#include "encrypt.h" + +#define SERVER "127.0.0.1" +#define REMOTE_PORT "8499" +#define PORT "1080" +#define KEY "foobar!" + +#define REPLY "HTTP/1.1 200 OK\n\nhello" + +#define min(a,b) \ + ({ typeof (a) _a = (a); \ + typeof (b) _b = (b); \ + _a < _b ? _a : _b; }) + +// every watcher type has its own typedef'd struct +// with the name ev_TYPE +ev_io stdin_watcher; + + +struct client_ctx { + ev_io io; + int fd; +}; + +int setnonblocking(int fd) { + int flags; + if (-1 ==(flags = fcntl(fd, F_GETFL, 0))) + flags = 0; + return fcntl(fd, F_SETFL, flags | O_NONBLOCK); +} + +int create_and_bind(char *port) { + struct addrinfo hints; + struct addrinfo *result, *rp; + int s, listen_sock; + + memset(&hints, 0, sizeof(struct addrinfo)); + hints.ai_family = AF_UNSPEC; /* Return IPv4 and IPv6 choices */ + hints.ai_socktype = SOCK_STREAM; /* We want a TCP socket */ + hints.ai_flags = AI_PASSIVE; /* All interfaces */ + + s = getaddrinfo("0.0.0.0", port, &hints, &result); + if (s != 0) { + fprintf(stderr, "getaddrinfo: %s\n", gai_strerror(s)); + return -1; + } + + for (rp = result; rp != NULL; rp = rp->ai_next) { + listen_sock = socket(rp->ai_family, rp->ai_socktype, rp->ai_protocol); + int opt = 1; + setsockopt(listen_sock, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt)); + if (listen_sock == -1) + continue; + + s = bind(listen_sock, rp->ai_addr, rp->ai_addrlen); + if (s == 0) { + /* We managed to bind successfully! */ + break; + } else { + perror("bind"); + } + + close(listen_sock); + } + + if (rp == NULL) { + fprintf(stderr, "Could not bind\n"); + return -1; + } + + freeaddrinfo(result); + + return listen_sock; +} + +static void server_recv_cb (EV_P_ ev_io *w, int revents) { + struct server_ctx *server_recv_ctx = (struct server_ctx *)w; + struct server *server = server_recv_ctx->server; + struct remote *remote = server->remote; + if (remote == NULL) { + close_and_free_server(EV_A_ server); + return; + } + while (1) { + ssize_t r = recv(server->fd, remote->buf, BUF_SIZE, 0); + if (r == 0) { + // connection closed + remote->buf_len = 0; + close_and_free_server(EV_A_ server); + if (remote != NULL) { + ev_io_start(EV_A_ &remote->send_ctx->io); + } + return; + } else if(r < 0) { + perror("recv"); + if (errno == EAGAIN) { + // no data + // continue to wait for recv + break; + } else { + close_and_free_server(EV_A_ server); + close_and_free_remote(EV_A_ remote); + return; + } + } + encrypt(remote->buf, r); + int w = send(remote->fd, remote->buf, r, MSG_NOSIGNAL); + if(w == -1) { + perror("send"); + if (errno == EAGAIN) { + // no data, wait for send + ev_io_stop(EV_A_ &server_recv_ctx->io); + ev_io_start(EV_A_ &remote->send_ctx->io); + break; + } else { + close_and_free_server(EV_A_ server); + close_and_free_remote(EV_A_ remote); + return; + } + } else if(w < r) { + char *pt; + for (pt = remote->buf; pt < pt + min(w, BUF_SIZE); pt++) { + *pt = *(pt + w); + } + remote->buf_len = r - w; + ev_io_stop(EV_A_ &server_recv_ctx->io); + ev_io_start(EV_A_ &remote->send_ctx->io); + break; + } + } +} +static void server_send_cb (EV_P_ ev_io *w, int revents) { + struct server_ctx *server_send_ctx = (struct server_ctx *)w; + struct server *server = server_send_ctx->server; + struct remote *remote = server->remote; + if (server->buf_len == 0) { + // close and free + close_and_free_server(EV_A_ server); + close_and_free_remote(EV_A_ remote); + return; + } else { + // has data to send + ssize_t r = send(server->fd, server->buf, + server->buf_len, 0); + if (r < 0) { + perror("send"); + if (errno != EAGAIN) { + close_and_free_server(EV_A_ server); + close_and_free_remote(EV_A_ remote); + return; + } + return; + } + if (r < server->buf_len) { + // printf("r=%d\n", r); + // printf("server->buf_len=%d\n", server->buf_len); + // partly sent, move memory, wait for the next time to send + char *pt; + for (pt = server->buf; pt < pt + min(r, BUF_SIZE); pt++) { + *pt = *(pt + r); + } + server->buf_len -= r; + return; + } else { + // all sent out, wait for reading + ev_io_stop(EV_A_ &server_send_ctx->io); + if (remote != NULL) { + ev_io_start(EV_A_ &remote->recv_ctx->io); + } else { + close_and_free_server(EV_A_ server); + close_and_free_remote(EV_A_ remote); + return; + } + } + } + +} +static void remote_recv_cb (EV_P_ ev_io *w, int revents) { + struct remote_ctx *remote_recv_ctx = (struct remote_ctx *)w; + struct remote *remote = remote_recv_ctx->remote; + struct server *server = remote->server; + if (server == NULL) { + close_and_free_remote(EV_A_ remote); + return; + } + while (1) { + ssize_t r = recv(remote->fd, server->buf, BUF_SIZE, 0); + // printf("after recv: r=%d\n", r); + if (r == 0) { + // connection closed + server->buf_len = 0; + close_and_free_remote(EV_A_ remote); + if (server != NULL) { + ev_io_start(EV_A_ &server->send_ctx->io); + } + return; + } else if(r < 0) { + perror("recv"); + if (errno == EAGAIN) { + // no data + // continue to wait for recv + break; + } else { + close_and_free_server(EV_A_ server); + close_and_free_remote(EV_A_ remote); + return; + } + } + decrypt(server->buf, r); + int w = send(server->fd, server->buf, r, MSG_NOSIGNAL); + // printf("after send: w=%d\n", w); + if(w == -1) { + perror("send"); + if (errno == EAGAIN) { + // no data, wait for send + ev_io_stop(EV_A_ &remote_recv_ctx->io); + ev_io_start(EV_A_ &server->send_ctx->io); + break; + } else { + close_and_free_server(EV_A_ server); + close_and_free_remote(EV_A_ remote); + return; + } + } else if(w < r) { + char *pt; + for (pt = server->buf; pt < pt + min(w, BUF_SIZE); pt++) { + *pt = *(pt + w); + } + server->buf_len = r - w; + ev_io_stop(EV_A_ &remote_recv_ctx->io); + ev_io_start(EV_A_ &server->send_ctx->io); + break; + } + } +} +static void remote_send_cb (EV_P_ ev_io *w, int revents) { + struct remote_ctx *remote_send_ctx = (struct remote_ctx *)w; + struct remote *remote = remote_send_ctx->remote; + struct server *server = remote->server; + if (!remote_send_ctx->connected) { + socklen_t len; + struct sockaddr_storage addr; + char ipstr[INET6_ADDRSTRLEN]; + int port; + len = sizeof addr; + int r = getpeername(remote->fd, (struct sockaddr*)&addr, &len); + if (r == 0) { + remote_send_ctx->connected = 1; + ev_io_stop(EV_A_ &remote_send_ctx->io); + ev_io_start(EV_A_ &server->recv_ctx->io); + ev_io_start(EV_A_ &remote->recv_ctx->io); + } else { + perror("getpeername"); + // not connected + close_and_free_remote(EV_A_ remote); + close_and_free_server(EV_A_ server); + return; + } + } else { + if (remote->buf_len == 0) { + // close and free + close_and_free_remote(EV_A_ remote); + close_and_free_server(EV_A_ server); + return; + } else { + // has data to send + ssize_t r = send(remote->fd, remote->buf, + remote->buf_len, 0); + if (r < 0) { + perror("send"); + if (errno != EAGAIN) { + // close and free + close_and_free_remote(EV_A_ remote); + close_and_free_server(EV_A_ server); + return; + } + return; + } + if (r < remote->buf_len) { + // partly sent, move memory, wait for the next time to send + char *pt; + for (pt = remote->buf; pt < pt + min(r, BUF_SIZE); pt++) { + *pt = *(pt + r); + } + remote->buf_len -= r; + return; + } else { + // all sent out, wait for reading + ev_io_stop(EV_A_ &remote_send_ctx->io); + if (server != NULL) { + ev_io_start(EV_A_ &server->recv_ctx->io); + } else { + close_and_free_remote(EV_A_ remote); + close_and_free_server(EV_A_ server); + return; + } + } + } + + } +} + +struct remote* new_remote(int fd) { + struct remote *remote; + remote = malloc(sizeof(struct remote)); + remote->fd = fd; + remote->recv_ctx = malloc(sizeof(struct remote_ctx)); + remote->send_ctx = malloc(sizeof(struct remote_ctx)); + ev_io_init(&remote->recv_ctx->io, remote_recv_cb, fd, EV_READ); + ev_io_init(&remote->send_ctx->io, remote_send_cb, fd, EV_WRITE); + remote->recv_ctx->remote = remote; + remote->recv_ctx->connected = 0; + remote->send_ctx->remote = remote; + remote->send_ctx->connected = 0; + fprintf(stderr, "new remote\n"); + return remote; +} +void free_remote(struct remote *remote) { + if (remote != NULL) { + if (remote->server != NULL) { + remote->server->remote = NULL; + } + free(remote->recv_ctx); + free(remote->send_ctx); + free(remote); + fprintf(stderr, "free remote\n"); + } +} +void close_and_free_remote(EV_P_ struct remote *remote) { + if (remote != NULL) { + ev_io_stop(EV_A_ &remote->send_ctx->io); + ev_io_stop(EV_A_ &remote->recv_ctx->io); + close(remote->fd); + free_remote(remote); + } +} +struct server* new_server(int fd) { + struct server *server; + server = malloc(sizeof(struct server)); + server->fd = fd; + server->recv_ctx = malloc(sizeof(struct server_ctx)); + server->send_ctx = malloc(sizeof(struct server_ctx)); + ev_io_init(&server->recv_ctx->io, server_recv_cb, fd, EV_READ); + ev_io_init(&server->send_ctx->io, server_send_cb, fd, EV_WRITE); + server->recv_ctx->server = server; + server->recv_ctx->connected = 0; + server->send_ctx->server = server; + server->send_ctx->connected = 0; + fprintf(stderr, "new server\n"); + return server; +} +void free_server(struct server *server) { + if (server != NULL) { + if (server->remote != NULL) { + server->remote->server = NULL; + } + free(server->recv_ctx); + free(server->send_ctx); + free(server); + fprintf(stderr, "free server\n"); + } +} +void close_and_free_server(EV_P_ struct server *server) { + if (server != NULL) { + ev_io_stop(EV_A_ &server->send_ctx->io); + ev_io_stop(EV_A_ &server->recv_ctx->io); + close(server->fd); + free_server(server); + } +} +static void accept_cb (EV_P_ ev_io *w, int revents) +{ + struct listen_ctx *listener = (struct listen_ctx *)w; + int serverfd; + while (1) { + serverfd = accept(listener->fd, NULL, NULL); + if (serverfd == -1) { + perror("accept"); + break; + } + struct server *server = new_server(serverfd); + struct addrinfo hints, *res; + int sockfd; + memset(&hints, 0, sizeof hints); + hints.ai_family = AF_UNSPEC; + hints.ai_socktype = SOCK_STREAM; + getaddrinfo(SERVER, REMOTE_PORT, &hints, &res); + sockfd = socket(res->ai_family, res->ai_socktype, res->ai_protocol); + if (sockfd < 0) { + perror("socket"); + close(sockfd); + free_server(server); + continue; + } + setnonblocking(sockfd); + struct remote *remote = new_remote(sockfd); + server->remote = remote; + remote->server = server; + connect(sockfd, res->ai_addr, res->ai_addrlen); + // listen to remote connected event + ev_io_start(EV_A_ &remote->send_ctx->io); + break; + } +} + +int main (void) +{ + fprintf(stderr, "calculating ciphers\n"); + get_table(KEY); + + int listenfd; + listenfd = create_and_bind(PORT); + if (listenfd < 0) { + return 1; + } + if (listen(listenfd, SOMAXCONN) == -1) { + perror("listen() error."); + return 1; + } + fprintf(stderr, "server listening at port %s\n", PORT); + setnonblocking(listenfd); + struct listen_ctx listen_ctx; + listen_ctx.fd = listenfd; + struct ev_loop *loop = EV_DEFAULT; + ev_io_init (&listen_ctx.io, accept_cb, listenfd, EV_READ); + ev_io_start (loop, &listen_ctx.io); + ev_run (loop, 0); + return 0; +} + diff --git a/server.h b/server.h new file mode 100644 index 00000000..bae4a19a --- /dev/null +++ b/server.h @@ -0,0 +1,52 @@ +#pragma once + +#include + +#define BUF_SIZE 1500 + +struct listen_ctx { + ev_io io; + int fd; + struct sockaddr sock; +}; + +struct server { + int fd; + char buf[BUF_SIZE]; // server send from, remote recv into + int buf_len; + struct server_ctx *recv_ctx; + struct server_ctx *send_ctx; + struct remote *remote; +}; +struct server_ctx { + ev_io io; + int connected; + struct server *server; +}; +struct remote { + int fd; + char buf[BUF_SIZE]; // remote send from, server recv into + int buf_len; + struct remote_ctx *recv_ctx; + struct remote_ctx *send_ctx; + struct server *server; +}; +struct remote_ctx { + ev_io io; + int connected; + struct remote *remote; +}; + + +static void accept_cb (EV_P_ ev_io *w, int revents); +static void server_recv_cb (EV_P_ ev_io *w, int revents); +static void server_send_cb (EV_P_ ev_io *w, int revents); +static void remote_recv_cb (EV_P_ ev_io *w, int revents); +static void remote_send_cb (EV_P_ ev_io *w, int revents); +struct remote* new_remote(int fd); +void free_remote(struct remote *remote); +void close_and_free_remote(EV_P_ struct remote *remote); +struct server* new_server(int fd); +void free_server(struct server *server); +void close_and_free_server(EV_P_ struct server *server); + diff --git a/socks5.h b/socks5.h new file mode 100755 index 00000000..998c404e --- /dev/null +++ b/socks5.h @@ -0,0 +1,37 @@ +#pragma once + +#define VERSION 0x05 +#define CONNECT 0x01 +#define IPV4 0x01 +#define DOMAIN 0x03 +#define IPV6 0x04 + +struct method_select_request +{ + char ver; + char nmethods; + char methods[255]; +}; + +struct method_select_response +{ + char version; + char method; +}; + +struct socks5_request +{ + char ver; + char cmd; + char rsv; + char atyp; +}; + +struct socks5_response +{ + char ver; + char rep; + char rsv; + char atyp; +}; +