int main (void) { int listenfd; ev_io io; struct ev_loop *loop = EV_DEFAULT; signal(SIGPIPE, SIG_IGN); signal(SIGABRT, SIG_IGN); listenfd = create_and_bind("127.0.0.1", "10001"); setnonblocking(listenfd); if (listenfd < 0) { printf("listen sock error\n"); } if (listen(listenfd, 128) == -1){ printf("listen error\n"); } ev_io_init(&io, accept_cb, listenfd, EV_READ); ev_io_start(loop, &io); ev_run(loop, 0); return 0; }
int main(int argc, char argv[]) { const char *ip = "127.0.0.1"; const char *port = "2016"; int sfd = create_and_bind(ip, port); if (sfd == -1) { return -1; } struct event_base *base = event_init(); if (base == NULL) { return -1; } struct event ev; event_set(&ev, sfd, EV_READ|EV_PERSIST, accept_cb, NULL); event_add(&ev, NULL); event_base_dispatch(base); return 0; }
int create_send_socket(void){ datafd = create_and_bind(LOCAL_IP, LOCAL_DATA_PORT); if(datafd < 0) { return datafd; } //lenfd = create_and_bind(LOCAL_IP, LOCAL_LEN_PORT); //if(lenfd < 0) // return lenfd; return 1; }
int main (int argc, char *argv[]) { int sfd, s; int efd; struct epoll_event event; struct epoll_event events[MAXEVENTS]; if (argc < 2){ fprintf (stderr, "Usage: %s [port]\n", basename(argv[0])); exit (EXIT_FAILURE); } // const char *ip = argv[1]; // int port = atoi(argv[2]); sfd = create_and_bind (argv[1]); if (sfd == -1) abort (); //listen for connection coming s = listen (sfd, SOMAXCONN); if (s == -1) { perror ("listen"); abort (); } //create a epoll object efd = epoll_create1 (0); if (efd == -1) { perror ("epoll_create"); abort (); } //add the listen socket to the event poll addfd(efd, sfd, 1); while(1) { int ret = epoll_wait(efd, events, MAXEVENTS, -1); if(ret < 0){ printf("epoll wait failture..\n"); break; } //et(events, ret, efd, sfd); lt(events, ret, efd, sfd); } close (sfd); return EXIT_SUCCESS; }
void main(int argc, char *argv[]) { // Create Socket int infd = create_and_bind("1234"); // Bind Socket int outfd = bind_socket(infd) // Listen on Socket int r = listen(outfd) // Accept Socket }
int main(int argc, char *argv[]) { if(argc <= 1) { printf("Usage: %s port\n", basename(argv[0])); return -1; } int ret = 0; int sfd = create_and_bind(argv[1]); if(sfd < 0) {printf("create_and_bind failed.\n"); return -2;} listen(sfd, 5); struct sockaddr_in client_address; socklen_t client_addrlength = sizeof( client_address ); int connfd = accept( sfd, ( struct sockaddr* )&client_address, &client_addrlength ); if ( connfd < 0 ) { printf( "errno is: %d\n", errno ); close( sfd); return -3; } char buff[1024]; struct pollfd pfd[FDNUM]; pfd[0].fd = connfd; pfd[0].events = POLLIN | POLLPRI; while(1) { memset( buff, '\0', sizeof( buff ) ); int n = poll(pfd, 1, -1); printf("poll get %d fd ready.\n"); if(pfd[0].revents & POLLIN) { int nr = read(connfd, buff, sizeof(buff)); if(nr > 0) { printf("get %d bytes data: %s\n", nr, buff); } else if(nr == 0) { // client close the connection printf("client close the connection.\n"); break; } else { // error occures perror("read"); ret = -4; break; } } if(pfd[0].revents & POLLPRI) { int nr = recv(connfd, buff, sizeof(buff) - 1, MSG_OOB); if(nr < 0) { perror("recv"); ret = -5; break; } printf("recv %d bytes OOB data: %s\n", nr, buff); } } close(sfd); return ret; }
int main(void) { char in[3000], sent[500], code[50], file[200], mime[100], moved[200], length[100], auth[200], auth_dir[500], start[100], end[100]; char *result=NULL, *hostname, *hostnamef, *lines, *ext=NULL, *extf, *auth_dirf=NULL, *authf=NULL, *rangetmp; int buffer_chunks; long filesize, range=0; get_conf(); create_and_bind(); //Important stuff happens here. while(1) { sin_size = sizeof(struct sockaddr_in); if ((new_fd = accept(sockfd, (struct sockaddr *)&their_addr, &sin_size)) == -1) { perror("accept"); continue; } if (!fork()) { close(sockfd); if (read(new_fd, in, 3000) == -1) { perror("recive"); } else { lines = strtok(in, "\n\r"); do { hostname = strtok(NULL, "\n\r"); if (hostname[0] == 'R' && hostname[1] == 'a' && hostname[2] == 'n' && hostname[3] == 'g' && hostname[4] == 'e') { rangetmp = hostname; strcpy(code, "206 Partial Content"); } } while (hostname[0] != 'H' || hostname[1] != 'o' || hostname[2] != 's' || hostname[3] != 't'); hostnamef = strtok(hostname, " "); hostnamef = strtok(NULL, " "); result = strtok(lines, " "); result = strtok(NULL, " "); if (strcmp(code, "206 Partial Content") == 0 ) { rangetmp = strtok(strpbrk(rangetmp, "="), "=-"); range = atoi(rangetmp); } strcpy(file, result); if (opendir(file)){ if (file[strlen(file)-1] == '/'){ strcat(file, "/index.html"); openfile=fopen (file, "r"); if (openfile){ strcpy(code, "200 OK"); } else { //Here should be some kind of directory listing strcpy(file, "/404.html"); openfile = fopen (file, "r"); strcpy(code, "404 Not Found"); } } else { strcpy(code, "301 Moved Permanently"); strcpy(moved, "Location: http://"); strcat(moved, hostnamef); strcat(moved, result); strcat(moved, "/"); } } else { openfile=fopen (file, "rb"); if (openfile){ if (strlen(code) < 1) { strcpy (code, "200 OK"); } } else { strcpy(file, "/404.html"); openfile = fopen (file, "r"); strcpy(code, "404 Not Found"); } } } if (strcmp(code, "301 Moved Permanently") != 0){ fseek (openfile , 0 , SEEK_END); filesize = ftell (openfile); rewind (openfile); if (range > 0) { sprintf(end, "%d", filesize); filesize = filesize - range; sprintf(start, "%d", range); fseek (openfile , range , SEEK_SET); } buffer_chunks = filesize/1048576; if(filesize%1048576 > 0){ buffer_chunks++; } sprintf(length, "%d", filesize); buffer_counter = 0; buffer = (char*) malloc (sizeof(char)*1048576); } if (strcmp(code, "404 Not Found") != 0 && strcmp(code, "301 Moved Permanently") !=0){ ext = strtok(file, "."); while(ext != NULL){ ext = strtok(NULL, "."); if (ext != NULL){ extf = ext; } } } else { extf="html"; } /* Maybe I should read mime types from a file. At least for now, add here what you need.*/ if (strcmp(extf, "html") == 0){ strcpy (mime, "text/html"); } else if(strcmp(extf, "jpg") == 0){ strcpy (mime, "image/jpeg"); } else if(strcmp(extf, "gif") == 0){ strcpy (mime, "image/gif"); } else if(strcmp(extf, "css") == 0){ strcpy (mime, "text/css"); } else { strcpy(mime, "application/octet-stream"); } strcpy(sent, "HTTP/1.1 "); strcat(sent, code); strcat(sent, "\nServer: qshttpd 0.3.0\n"); if(strcmp(code, "301 Moved Permanently") == 0){ strcat(sent, moved); strcat(sent, "\n"); } strcat(sent, "Content-Length: "); if(strcmp(code, "301 Moved Permanently") != 0){ strcat(sent, length); } else { strcat(sent, "0"); } if(strcmp(code, "206 Partial Content") == 0) { strcat(sent, "\nContent-Range: bytes "); strcat(sent, start); strcat(sent, "-"); strcat(sent, end); strcat(sent, "/"); strcat(sent, end); } strcat(sent, "\nConnection: close\nContent-Type: "); strcat(sent, mime); strcat(sent, "; charset="); strcat(sent, charset); strcat(sent, "\n\n"); write(new_fd, sent, strlen(sent)); while (buffer_counter < buffer_chunks) { read_chunk(); write(new_fd, buffer, 1048576); } close(new_fd); exit(0); } close(new_fd); } return 0; }
int main(int argc, char **argv) { int i, c; int pid_flags = 0; char *user = NULL; char *local_port = NULL; char *local_addr = NULL; char *password = NULL; char *timeout = NULL; char *method = NULL; char *pid_path = NULL; char *conf_path = NULL; char *iface = NULL; int remote_num = 0; ss_addr_t remote_addr[MAX_REMOTE_NUM]; char *remote_port = NULL; ss_addr_t tunnel_addr = { .host = NULL, .port = NULL }; char *tunnel_addr_str = NULL; opterr = 0; USE_TTY(); #ifdef ANDROID while ((c = getopt(argc, argv, "f:s:p:l:k:t:m:i:c:b:L:a:uUvV")) != -1) { #else while ((c = getopt(argc, argv, "f:s:p:l:k:t:m:i:c:b:L:a:uUv")) != -1) { #endif switch (c) { case 's': if (remote_num < MAX_REMOTE_NUM) { remote_addr[remote_num].host = optarg; remote_addr[remote_num++].port = NULL; } break; case 'p': remote_port = optarg; break; case 'l': local_port = optarg; break; case 'k': password = optarg; break; case 'f': pid_flags = 1; pid_path = optarg; break; case 't': timeout = optarg; break; case 'm': method = optarg; break; case 'c': conf_path = optarg; break; case 'i': iface = optarg; break; case 'b': local_addr = optarg; break; case 'u': mode = TCP_AND_UDP; break; case 'U': mode = UDP_ONLY; break; case 'L': tunnel_addr_str = optarg; break; case 'a': user = optarg; break; case 'v': verbose = 1; break; #ifdef ANDROID case 'V': vpn = 1; break; #endif } } if (opterr) { usage(); exit(EXIT_FAILURE); } if (argc == 1) { if (conf_path == NULL) { conf_path = DEFAULT_CONF_PATH; } } if (conf_path != NULL) { jconf_t *conf = read_jconf(conf_path); if (remote_num == 0) { remote_num = conf->remote_num; for (i = 0; i < remote_num; i++) { remote_addr[i] = conf->remote_addr[i]; } } if (remote_port == NULL) { remote_port = conf->remote_port; } if (local_addr == NULL) { local_addr = conf->local_addr; } if (local_port == NULL) { local_port = conf->local_port; } if (password == NULL) { password = conf->password; } if (method == NULL) { method = conf->method; } if (timeout == NULL) { timeout = conf->timeout; } } if (remote_num == 0 || remote_port == NULL || tunnel_addr_str == NULL || local_port == NULL || password == NULL) { usage(); exit(EXIT_FAILURE); } if (timeout == NULL) { timeout = "60"; } if (local_addr == NULL) { local_addr = "127.0.0.1"; } if (pid_flags) { USE_SYSLOG(argv[0]); daemonize(pid_path); } // parse tunnel addr parse_addr(tunnel_addr_str, &tunnel_addr); if (tunnel_addr.port == NULL) { FATAL("tunnel port is not defined"); } #ifdef __MINGW32__ winsock_init(); #else // ignore SIGPIPE signal(SIGPIPE, SIG_IGN); signal(SIGABRT, SIG_IGN); #endif // Setup keys LOGI("initialize ciphers... %s", method); int m = enc_init(password, method); // Setup proxy context struct listen_ctx listen_ctx; listen_ctx.tunnel_addr = tunnel_addr; listen_ctx.remote_num = remote_num; listen_ctx.remote_addr = malloc(sizeof(struct sockaddr *) * remote_num); for (i = 0; i < remote_num; i++) { char *host = remote_addr[i].host; char *port = remote_addr[i].port == NULL ? remote_port : remote_addr[i].port; struct sockaddr_storage *storage = malloc(sizeof(struct sockaddr_storage)); memset(storage, 0, sizeof(struct sockaddr_storage)); if (get_sockaddr(host, port, storage, 1) == -1) { FATAL("failed to resolve the provided hostname"); } listen_ctx.remote_addr[i] = (struct sockaddr *)storage; } listen_ctx.timeout = atoi(timeout); listen_ctx.iface = iface; listen_ctx.method = m; struct ev_loop *loop = EV_DEFAULT; if (mode != UDP_ONLY) { // Setup socket int listenfd; listenfd = create_and_bind(local_addr, local_port); if (listenfd < 0) { FATAL("bind() error:"); } if (listen(listenfd, SOMAXCONN) == -1) { FATAL("listen() error:"); } setnonblocking(listenfd); listen_ctx.fd = listenfd; ev_io_init(&listen_ctx.io, accept_cb, listenfd, EV_READ); ev_io_start(loop, &listen_ctx.io); } // Setup UDP if (mode != TCP_ONLY) { LOGI("UDP relay enabled"); init_udprelay(local_addr, local_port, listen_ctx.remote_addr[0], get_sockaddr_len(listen_ctx.remote_addr[0]), tunnel_addr, m, listen_ctx.timeout, iface); } if (mode == UDP_ONLY) { LOGI("TCP relay disabled"); } LOGI("listening at %s:%s", local_addr, local_port); // setuid if (user != NULL) { run_as(user); } ev_run(loop, 0); #ifdef __MINGW32__ winsock_cleanup(); #endif return 0; }
int main(int argc, char *argv[]) { int sfd, s; int efd; int so_rcvbuf = 0; int verbose = 0; struct epoll_event event; struct epoll_event *events; struct edata { int fd; int content_length; int content_offset; char *header_buf; int header_off; int header_max; }; if (argc < 2 || argc > 3) { fprintf(stderr, "Usage: %s [port] [rcvbuf]\n", argv[0]); exit(EXIT_FAILURE); } sfd = create_and_bind(argv[1]); if (sfd == -1) abort(); if (argc == 3) so_rcvbuf = atoi(argv[2]); s = make_socket_non_blocking(sfd); if (s == -1) abort(); s = listen(sfd, SOMAXCONN); if (s == -1) { perror("listen"); abort(); } efd = epoll_create1(0); if (efd == -1) { perror("epoll_create"); abort(); } struct edata *ed = malloc(sizeof(*ed)); ed->fd = sfd; ed->header_buf = 0; event.data.ptr = ed; event.events = EPOLLIN | EPOLLET; s = epoll_ctl(efd, EPOLL_CTL_ADD, sfd, &event); if (s == -1) { perror("epoll_ctl"); abort(); } /* Buffer where events are returned */ events = calloc(MAXEVENTS, sizeof event); /* The event loop */ while (1) { int n, i; n = epoll_wait(efd, events, MAXEVENTS, -1); for (i = 0; i < n; i++) { struct edata *ed = events[i].data.ptr; int fd = ed->fd; if ((events[i].events & EPOLLERR) || (events[i].events & EPOLLHUP) || (!(events[i].events & EPOLLIN))) { fprintf(stderr, "epoll error\n"); s = epoll_ctl(efd, EPOLL_CTL_DEL, fd, 0); if (s == -1) { perror("epoll_ctl"); abort(); } close(fd); free(ed); continue; } else if (sfd == fd) { while (1) { struct sockaddr in_addr; socklen_t in_len; int infd; char hbuf[NI_MAXHOST], sbuf[NI_MAXSERV]; in_len = sizeof in_addr; infd = accept(sfd, &in_addr, &in_len); if (infd == -1) { if ((errno == EAGAIN) || (errno == EWOULDBLOCK)) { break; } else { perror("accept"); break; } } s = getnameinfo(&in_addr, in_len, hbuf, sizeof hbuf, sbuf, sizeof sbuf, NI_NUMERICHOST | NI_NUMERICSERV); if (s == 0) { if (verbose) printf("Accepted connection on descriptor %d " "(host=%s, port=%s)\n", infd, hbuf, sbuf); } if (so_rcvbuf) if (setsockopt(infd, SOL_SOCKET, SO_RCVBUF, &so_rcvbuf, sizeof(so_rcvbuf))) { perror("setsocopt"); abort(); } s = make_socket_non_blocking(infd); if (s == -1) abort(); ed = malloc(sizeof(*ed)); ed->fd = infd; ed->content_length = -1; ed->header_max = 999; ed->header_buf = malloc(ed->header_max + 1); ed->header_off = 0; event.data.ptr = ed; event.events = EPOLLIN | EPOLLET; s = epoll_ctl(efd, EPOLL_CTL_ADD, infd, &event); if (s == -1) { perror("epoll_ctl"); abort(); } } continue; } else { int done = 0; while (1) { ssize_t count; char buf[32768]; if (ed->content_length == -1) { count = read(fd, ed->header_buf + ed->header_off, ed->header_max - ed->header_off); } else { count = read(fd, buf, sizeof buf); } if (count == -1) { if (errno != EAGAIN) { perror("read"); done = 1; } break; } else if (count == 0) { done = 1; break; } else { if (ed->content_length == -1) { const char *cp2; ed->header_off += count; ed->header_buf[ed->header_off] = '\0'; cp2 = strstr(ed->header_buf, "\r\n\r\n"); if (cp2) cp2 += 4; else if (!cp2) { cp2 = strstr(ed->header_buf, "\n\n"); if (cp2) cp2 += 2; } if (cp2) /* complete header? */ { const char *cp1 = strstr(ed->header_buf, "\nContent-Length:"); if (!cp1) cp1 = strstr(ed->header_buf, "\nContent-length:"); if (cp1 && cp1 < cp2) ed->content_length = atoi(cp1 + 16); else ed->content_length = 0; ed->content_offset = ed->header_off - (cp2 - ed->header_buf); if (ed->content_offset == 0) { if (strstr(ed->header_buf, "\nExpect: 100-continue")) { char buf[64]; strcpy(buf, "HTTP/1.1 100 Continue\r\n\r\n"); write(fd, buf, strlen(buf)); } } if (verbose) printf("complete header length=%d\n", ed->content_length); } else { if (ed->header_off == ed->header_max) { printf("Too big header\n"); done = 1; } } } else { ed->content_offset += count; } if (ed->content_length != -1 && ed->content_offset == ed->content_length) { if (verbose) printf("Got all content %d\n", ed->content_length); done = 1; } } } if (done) { if (verbose) printf("Closing descriptor %d\n", fd); char buf[1000]; strcpy(buf, "HTTP/1.0 200 OK\r\n" "Content-Length: 0\r\n" "Connection: Close\r\n" "\r\n"); write(fd, buf, strlen(buf)); s = epoll_ctl(efd, EPOLL_CTL_DEL, fd, 0); if (s == -1) { perror("epoll_ctl"); abort(); } close(fd); free(ed->header_buf); free(ed); } } } } free(events); close(sfd); return EXIT_SUCCESS; }
int main(int argc, char **argv) { int lfd, s, efd; struct epoll_event event; struct epoll_event *events; char path[MAX_LINE]; int port; configuration(&port, path); char port_str[6]; bzero(port_str, 6); snprintf(port_str, 5, "%d", port); lfd=create_and_bind(port_str); if(lfd==-1) abort(); s=listen(lfd, SOMAXCONN); if(s==-1) { perror("listen"); abort(); } efd=epoll_create1(0); if(efd==-1) { perror("epoll_create"); abort(); } addfd(efd, lfd, false); events=(struct epoll_event*)calloc(MAXEVENTS, sizeof(event)); while(1) { int n, i; n=epoll_wait(efd, events, MAXEVENTS, -1); for(i=0; i<n; i++) { if ((events[i].events&EPOLLERR)|| (events[i].events&EPOLLHUP)|| (!(events[i].events&EPOLLIN))) { /* A error has occured on this fd, or the socket is not * ready for reading (why were we notified then?) */ fprintf(stderr, "epoll error\n"); close(events[i].data.fd); continue; } else if(lfd==events[i].data.fd) { /* We have a notification on the listening socket, * which means one or more incoming connections. */ while(1) { struct sockaddr in_addr; socklen_t in_len; int infd; char hbuf[NI_MAXHOST], sbuf[NI_MAXSERV]; in_len=sizeof(in_addr); infd=accept(lfd, &in_addr, &in_len); if(infd==-1) { if((errno==EAGAIN)||(errno==EWOULDBLOCK)) { /* We have processed all incoming connections. */ break; } else { perror("accept"); break; } } s=getnameinfo(&in_addr, in_len, hbuf, sizeof(hbuf), sbuf, sizeof(sbuf), NI_NUMERICHOST|NI_NUMERICSERV); if(s==0) { print("Accepted connnection on descriptor %d: (host=%s, port=%s)\n", infd, hbuf, sbuf); } /* Make the incoming socket non-blocking and * add it to the list of fds to monitor. */ addfd(efd, infd, true); } continue; } else { /* We have data on the fd waiting to be read. Read and display it. * We must read whatever data is available completely, as we are running * in edge-triggered mode and won't get a notification again for the same data. */ pthread_t thread; args param; param.cfd=events[i].data.fd; param.efd=efd; // pthread_create(&thread, NULL, worker, (void*)¶m); worker((void*)¶m); } } } free(events); close(lfd); return EXIT_SUCCESS; }
int start_ss_local_server(profile_t profile) { srand(time(NULL)); char *remote_host = profile.remote_host; char *local_addr = profile.local_addr; char *method = profile.method; char *password = profile.password; char *log = profile.log; int remote_port = profile.remote_port; int local_port = profile.local_port; int timeout = profile.timeout; mode = profile.mode; fast_open = profile.fast_open; verbose = profile.verbose; char local_port_str[16]; char remote_port_str[16]; sprintf(local_port_str, "%d", local_port); sprintf(remote_port_str, "%d", remote_port); USE_LOGFILE(log); if (profile.acl != NULL) { acl = !init_acl(profile.acl); } if (local_addr == NULL) { local_addr = "127.0.0.1"; } #ifdef __MINGW32__ winsock_init(); #else // ignore SIGPIPE signal(SIGPIPE, SIG_IGN); signal(SIGABRT, SIG_IGN); #endif struct ev_signal sigint_watcher; struct ev_signal sigterm_watcher; ev_signal_init(&sigint_watcher, signal_cb, SIGINT); ev_signal_init(&sigterm_watcher, signal_cb, SIGTERM); ev_signal_start(EV_DEFAULT, &sigint_watcher); ev_signal_start(EV_DEFAULT, &sigterm_watcher); // Setup keys LOGI("initialize ciphers... %s", method); int m = enc_init(password, method); struct sockaddr_storage *storage = malloc(sizeof(struct sockaddr_storage)); memset(storage, 0, sizeof(struct sockaddr_storage)); if (get_sockaddr(remote_host, remote_port_str, storage, 1) == -1) { return -1; } // Setup proxy context struct ev_loop *loop = EV_DEFAULT; struct listen_ctx listen_ctx; listen_ctx.remote_num = 1; listen_ctx.remote_addr = malloc(sizeof(struct sockaddr *)); listen_ctx.remote_addr[0] = (struct sockaddr *)storage; listen_ctx.timeout = timeout; listen_ctx.method = m; listen_ctx.iface = NULL; // Setup socket int listenfd; listenfd = create_and_bind(local_addr, local_port_str); if (listenfd < 0) { ERROR("bind()"); return -1; } if (listen(listenfd, SOMAXCONN) == -1) { ERROR("listen()"); return -1; } setnonblocking(listenfd); listen_ctx.fd = listenfd; ev_io_init(&listen_ctx.io, accept_cb, listenfd, EV_READ); ev_io_start(loop, &listen_ctx.io); // Setup UDP if (mode != TCP_ONLY) { LOGI("udprelay enabled"); struct sockaddr *addr = (struct sockaddr *)storage; init_udprelay(local_addr, local_port_str, addr, get_sockaddr_len(addr), m, timeout, NULL); } LOGI("listening at %s:%s", local_addr, local_port_str); // Init connections cork_dllist_init(&connections); // Enter the loop ev_run(loop, 0); if (verbose) { LOGI("closed gracefully"); } // Clean up if (mode != TCP_ONLY) { free_udprelay(); } ev_io_stop(loop, &listen_ctx.io); free_connections(loop); close(listen_ctx.fd); free(listen_ctx.remote_addr); #ifdef __MINGW32__ winsock_cleanup(); #endif ev_signal_stop(EV_DEFAULT, &sigint_watcher); ev_signal_stop(EV_DEFAULT, &sigterm_watcher); // cannot reach here return 0; }
int start_ss_local_server(profile_t profile) { srand(time(NULL)); char *remote_host = profile.remote_host; char *local_addr = profile.local_addr; char *method = profile.method; char *password = profile.password; char *log = profile.log; int remote_port = profile.remote_port; int local_port = profile.local_port; int timeout = profile.timeout; udprelay = profile.udp_relay; fast_open = profile.fast_open; verbose = profile.verbose; char local_port_str[16]; char remote_port_str[16]; sprintf(local_port_str, "%d", local_port); sprintf(remote_port_str, "%d", remote_port); USE_LOGFILE(log); if (profile.acl != NULL) { acl = !init_acl(profile.acl); } if (local_addr == NULL) { local_addr = "0.0.0.0"; } #ifdef __MINGW32__ winsock_init(); #else // ignore SIGPIPE signal(SIGPIPE, SIG_IGN); signal(SIGABRT, SIG_IGN); #endif struct ev_signal sigint_watcher; struct ev_signal sigterm_watcher; ev_signal_init(&sigint_watcher, signal_cb, SIGINT); ev_signal_init(&sigterm_watcher, signal_cb, SIGTERM); ev_signal_start(EV_DEFAULT, &sigint_watcher); ev_signal_start(EV_DEFAULT, &sigterm_watcher); // Setup keys LOGD("initialize ciphers... %s", method); int m = enc_init(password, method); // Setup socket int listenfd; listenfd = create_and_bind(local_addr, local_port_str); if (listenfd < 0) { FATAL("bind()"); } if (listen(listenfd, SOMAXCONN) == -1) { FATAL("listen()"); } setnonblocking(listenfd); LOGD("server listening at port %s.", local_port_str); // Setup proxy context struct listen_ctx listen_ctx; listen_ctx.remote_num = 1; listen_ctx.remote_addr = malloc(sizeof(ss_addr_t)); listen_ctx.remote_addr[0].host = remote_host; listen_ctx.remote_addr[0].port = remote_port_str; listen_ctx.timeout = timeout; listen_ctx.fd = listenfd; listen_ctx.method = m; listen_ctx.iface = NULL; struct ev_loop *loop = EV_DEFAULT; if (!loop) { FATAL("ev_loop error."); } ev_io_init(&listen_ctx.io, accept_cb, listenfd, EV_READ); ev_io_start(loop, &listen_ctx.io); // Setup UDP if (udprelay) { LOGD("udprelay enabled."); init_udprelay(local_addr, local_port_str, remote_host, remote_port_str, m, listen_ctx.timeout, NULL); } // Init connections cork_dllist_init(&connections); // Enter the loop ev_run(loop, 0); if (verbose) { LOGD("closed nicely."); } // Clean up free_connections(loop); if (udprelay) { free_udprelay(); } ev_io_stop(loop, &listen_ctx.io); free(listen_ctx.remote_addr); close(listen_ctx.fd); #ifdef __MINGW32__ winsock_cleanup(); #endif ev_signal_stop(EV_DEFAULT, &sigint_watcher); ev_signal_stop(EV_DEFAULT, &sigterm_watcher); // cannot reach here return 0; }
int main(int argc, char *argv[]) { int sfd, res, epoll, cnt, i, sd; struct epoll_event event, events[MAX_EVENTS]; if (argc != 2) { perror("usage : port \n"); exit(1); } sfd = create_and_bind(argv[1]); if (sfd == -1) { perror("error : cannot create socket!\n"); exit(1); } res = make_socket_non_binding(sfd); if (res == -1) { perror("error : connot set flags!\n"); exit(1); } res = listen(sfd, SOMAXCONN); if (res == -1) { perror("error : cannot listen!\n"); exit(1); } epoll = epoll_create(1); if (epoll == -1) { perror("error : cannot create epoll!\n"); exit(1); } event.events = EPOLLIN | EPOLLOUT | EPOLLET; event.data.fd = sfd; res = epoll_ctl(epoll, EPOLL_CTL_ADD, sfd, &event); if (res == -1) { perror("error : can not add event to epoll!\n"); exit(1); } while (1) { cnt = epoll_wait(epoll, events, MAX_EVENTS, -1); for (i = 0; i < cnt; i++) { if ((events[i].events & EPOLLERR) || (events[i].events & EPOLLHUP) || !(events[i].events & EPOLLIN)) { perror("error : socket fd error!\n"); close(events[i].data.fd); continue; } else if (events[i].data.fd == sfd) { while (1) { struct sockaddr client_addr; int addrlen = sizeof(struct sockaddr); sd = accept(sfd, &client_addr, &addrlen); if (sd == -1) { if (errno == EAGAIN || errno == EWOULDBLOCK) { break; } else { perror("error : cannot accept new socket!\n"); continue; } } res = make_socket_non_binding(sd); if (res == -1) { perror("error : cannot set flags!\n"); exit(1); } event.data.fd = sd; event.events = EPOLLET | EPOLLIN; res = epoll_ctl(epoll, EPOLL_CTL_ADD, sd, &event); if (res == -1) { perror("error : cannot add to epoll!\n"); exit(1); } } } else { int cnt; char buf[BUF_SIZE]; while (1) { cnt = read(events[i].data.fd, buf, BUF_SIZE); if (cnt == -1) { if (errno == EAGAIN) { break; } perror("error : read error!\n"); exit(1); } else if (cnt == 0) { close(events[i].data.fd); break; } printf("receive client data : %s\n", buf); } } } } close(sfd); return 0; }
int main (int argc, char *argv[]) { int sfd, s; int efd; struct epoll_event event; struct epoll_event *events; if (argc != 2) { fprintf (stderr, "Usage: %s [port]\n", argv[0]); exit (EXIT_FAILURE); } sfd = create_and_bind (argv[1]); if (sfd == -1) abort (); s = make_socket_non_blocking (sfd); if (s == -1) abort (); s = listen (sfd, SOMAXCONN); if (s == -1) { perror ("listen"); abort (); } efd = epoll_create1 (0); if (efd == -1) { perror ("epoll_create"); abort (); } event.data.fd = sfd; event.events = EPOLLIN | EPOLLET; // READ AND ET s = epoll_ctl (efd, EPOLL_CTL_ADD, sfd, &event); if (s == -1) { perror ("epoll_ctl"); abort (); } /* Buffer where events are returned */ /* function allocates memory for an array of nmemb elements of size bytes each and returns a pointer to the allocated memory. */ /* max event is 64 */ events = calloc (MAXEVENTS, sizeof event); /* The event loop */ while (1) { printf("wait here\n"); int n, i; // RETURN THE ERADY NUMBS // ET AND LT only for the epoll_wait n = epoll_wait (efd, events, MAXEVENTS, -1); for (i = 0; i < n; i++) { if ((events[i].events & EPOLLERR) || (events[i].events & EPOLLHUP) || (!(events[i].events & EPOLLIN))) { /* An error has occured on this fd, or the socket is not ready for reading (why were we notified then?) */ fprintf (stderr, "epoll error\n"); close (events[i].data.fd); continue; } else if (sfd == events[i].data.fd) { /* We have a notification on the listening socket, which means one or more incoming connections. */ while (1) { struct sockaddr in_addr; socklen_t in_len; int infd; char hbuf[NI_MAXHOST], sbuf[NI_MAXSERV]; in_len = sizeof in_addr; // if there is connection wait to process it will return the // infd infd = accept (sfd, &in_addr, &in_len); if (infd == -1) { if ((errno == EAGAIN) || (errno == EWOULDBLOCK)) { /* We have processed all incoming connections. */ break; } else { perror ("accept"); break; } } //it converts a socket address to a corresponding host and service //return numeric host and service s = getnameinfo (&in_addr, in_len, hbuf, sizeof hbuf, sbuf, sizeof sbuf, NI_NUMERICHOST | NI_NUMERICSERV); if (s == 0) { printf ("Accepted connection on descriptor %d " "(host=%s, port=%s)\n", infd, hbuf, sbuf); } /* Make the incoming socket non-blocking and add it to the list of fds to monitor. */ s = make_socket_non_blocking (infd); if (s == -1) abort (); event.data.fd = infd; event.events = EPOLLIN | EPOLLET; s = epoll_ctl (efd, EPOLL_CTL_ADD, infd, &event); if (s == -1) { perror ("epoll_ctl"); abort (); } } continue; } else { /* We have data on the fd waiting to be read. Read and display it. We must read whatever data is available completely, as we are running in edge-triggered mode and won't get a notification again for the same data. */ int done = 0; while (1) { ssize_t count; char buf[512]; count = read (events[i].data.fd, buf, sizeof buf); if (count == -1) { /* If errno == EAGAIN, that means we have read all data. So go back to the main loop. */ if (errno != EAGAIN) { perror ("read"); done = 1; } break; } else if (count == 0) { /* End of file. The remote has closed the connection. */ done = 1; break; } /* Write the buffer to standard output */ s = write (1, buf, count); if (s == -1) { perror ("write"); abort (); } } if (done) { printf ("Closed connection on descriptor %d\n", events[i].data.fd); /* Closing the descriptor will make epoll remove it from the set of descriptors which are monitored. */ close (events[i].data.fd); } } } } free (events); close (sfd); return EXIT_SUCCESS; }
int main(int argc, char *argv[]) { int sfd, s; int efd; struct epoll_event event; struct epoll_event *events; if(argc != 2) { fprintf(stderr, "Usage: %s [port]\n", argv[0]); exit(EXIT_FAILURE); } sfd = create_and_bind(argv[1]); if(sfd == -1) abort(); s = make_socket_non_blocking(sfd); if(s == -1) abort(); s = listen(sfd, SOMAXCONN); if(s == -1) { perror("listen"); abort(); } efd = epoll_create1(0); if(efd == -1) { perror("epoll_create1"); abort(); } event.data.fd = sfd; event.events = EPOLLIN | EPOLLET; s = epoll_ctl(efd, EPOLL_CTL_ADD, sfd, &event); if(s == -1) { perror("epoll_ctl"); abort(); } events = calloc(MAXEVENTS, sizeof(event)); /* The event loop */ while(1) { int n, i; n = epoll_wait(efd, events, MAXEVENTS, -1); for(i = 0; i < n; i++) { if((events[i].events & EPOLLERR) || (events[i].events & EPOLLHUP) || (!(events[i].events & EPOLLIN))) { /*An error occurred, notified but no ready*/ fprintf(stderr, "epoll error\n"); close(events[i].data.fd); continue; } else if(sfd == events[i].data.fd) { /*listener port is notified, which means incoming connection*/ while(1) { struct sockaddr in_addr; socklen_t in_len; int infd; char hbuf[NI_MAXHOST], sbuf[NI_MAXSERV]; in_len = sizeof(in_addr); infd = accept(sfd, &in_addr, &in_len); if(infd == -1) { if((errno == EAGAIN) || (errno == EWOULDBLOCK)) { /*we have processed all incoming connections*/ break; } else { perror("accept"); break; } } s = getnameinfo(&in_addr, in_len, hbuf, sizeof(hbuf), sbuf, sizeof(sbuf), NI_NUMERICHOST | NI_NUMERICSERV); if(s == 0) { printf("Accepted connection on descriptor %d (host=%s, port=%s)\n", infd, hbuf, sbuf); } /*make the socket non-blocking and add it to monitor list*/ s = make_socket_non_blocking(infd); if(s == -1) abort(); event.data.fd = infd; event.events = EPOLLIN | EPOLLET; s = epoll_ctl(efd, EPOLL_CTL_ADD, infd, &event); if(s == -1) { perror("epoll_ctl"); abort(); } } continue; } else { /*read is ready*/ int done = 0; while(1) { ssize_t count; char buf[512]; count = read(events[i].data.fd, buf, sizeof(buf)); if(count == -1) { if(errno != EAGAIN) { perror("read"); done = 1; } break; } else if(count == 0) { /*End of file*/ done = 1; break; } /*Write the buffer to stdout*/ s = write(1, buf, count); if(s == -1) { perror("write"); abort(); } } if(done) { printf("closed connection on descriptor %d\n", events[i].data.fd); /*close connection*/ close(events[i].data.fd); } } } } free(events); close(sfd); return EXIT_SUCCESS; }
int main (int argc, char **argv) { int i, c; int pid_flags = 0; char *user = NULL; char *password = NULL; char *timeout = NULL; char *method = NULL; char *pid_path = NULL; char *conf_path = NULL; char *iface = NULL; int server_num = 0; const char *server_host[MAX_REMOTE_NUM]; const char *server_port = NULL; int dns_thread_num = DNS_THREAD_NUM; int option_index = 0; static struct option long_options[] = { {"fast-open", no_argument, 0, 0 }, {"port-start", required_argument, 0, 0 }, {"port-end", required_argument, 0, 0 }, {0, 0, 0, 0 } }; opterr = 0; while ((c = getopt_long(argc, argv, "f:s:p:l:k:t:m:c:i:d:a:uv", long_options, &option_index)) != -1) { printf("option_index %d\n", option_index); switch (c) { case 0: if (option_index == 0) { #ifdef TCP_FASTOPEN fast_open = 1; LOGD("using tcp fast open"); #else LOGE("tcp fast open is not supported by this environment"); #endif } else if (option_index == 1) { start_port = atoi(optarg); } else if (option_index == 2) { end_port = atoi(optarg); } break; case 's': server_host[server_num++] = optarg; break; case 'p': server_port = optarg; break; case 'k': password = optarg; break; case 'f': pid_flags = 1; pid_path = optarg; break; case 't': timeout = optarg; break; case 'm': method = optarg; break; case 'c': conf_path = optarg; break; case 'i': iface = optarg; break; case 'd': dns_thread_num = atoi(optarg); if (!dns_thread_num) FATAL("Invalid DNS thread number"); break; case 'a': user = optarg; break; case 'u': udprelay = 1; break; case 'v': verbose = 1; break; } } printf("start %d end %d\n", start_port, end_port); if (opterr) { usage(); exit(EXIT_FAILURE); } if (conf_path != NULL) { jconf_t *conf = read_jconf(conf_path); if (server_num == 0) { server_num = conf->remote_num; for (i = 0; i < server_num; i++) { server_host[i] = conf->remote_addr[i].host; } } if (server_port == NULL) server_port = conf->remote_port; if (password == NULL) password = conf->password; if (method == NULL) method = conf->method; if (timeout == NULL) timeout = conf->timeout; #ifdef TCP_FASTOPEN if (fast_open == 0) fast_open = conf->fast_open; #endif #ifdef HAVE_SETRLIMIT if (nofile == 0) nofile = conf->nofile; /* * no need to check the return value here since we will show * the user an error message if setrlimit(2) fails */ if (nofile) { if (verbose) { LOGD("setting NOFILE to %d", nofile); } set_nofile(nofile); } #endif } if ((start_port > 0 && end_port <= 0) || (start_port <= 0 && end_port > 0)) { printf("Both start_prot and end_port needs to be specified\n"); usage(); exit(EXIT_FAILURE); } if (server_port != NULL && start_port > 0) { printf("server port can't be set if you want to use a port range\n"); usage(); exit(EXIT_FAILURE); } if (server_num == 0 || (server_port == NULL && start_port <= 0) || password == NULL) { usage(); exit(EXIT_FAILURE); } if (timeout == NULL) timeout = "60"; if (pid_flags) { USE_SYSLOG(argv[0]); daemonize(pid_path); } // ignore SIGPIPE signal(SIGPIPE, SIG_IGN); signal(SIGCHLD, SIG_IGN); signal(SIGABRT, SIG_IGN); // setup asyncns asyncns_t *asyncns; if (!(asyncns = asyncns_new(dns_thread_num))) { FATAL("asyncns failed"); } // setup keys LOGD("initialize ciphers... %s", method); int m = enc_init(password, method); // inilitialize ev loop struct ev_loop *loop = EV_DEFAULT; // inilitialize listen context struct listen_ctx listen_ctx_list[server_num + 1]; // bind to each interface while (server_num > 0) { int index = --server_num; const char* host = server_host[index]; int success = 1; int listenfd; if (start_port > 0) { server_port = itoa(start_port); } do { // Bind to port listenfd = create_and_bind(host, server_port); success = 1; if (listenfd < 0) { success = 0; } if (listen(listenfd, SOMAXCONN) == -1) { success = 0; } if (!success) { if (start_port < end_port) { start_port++; server_port = itoa(start_port); } else { FATAL("Out of listen ports!"); exit(1); } } } while (!success); setnonblocking(listenfd); LOGD("server listening at port %s.", server_port); struct listen_ctx *listen_ctx = &listen_ctx_list[index + 1]; // Setup proxy context listen_ctx->timeout = atoi(timeout); listen_ctx->asyncns = asyncns; listen_ctx->fd = listenfd; listen_ctx->method = m; listen_ctx->iface = iface; ev_io_init (&listen_ctx->io, accept_cb, listenfd, EV_READ); ev_io_start (loop, &listen_ctx->io); } // initialize the DNS struct listen_ctx *listen_ctx = &listen_ctx_list[0]; int asyncnsfd = asyncns_fd(asyncns); listen_ctx->timeout = atoi(timeout); listen_ctx->asyncns = asyncns; listen_ctx->fd = asyncnsfd; listen_ctx->method = m; listen_ctx->iface = iface; ev_io_init (&listen_ctx->io, server_resolve_cb, asyncnsfd, EV_READ); ev_io_start (loop, &listen_ctx->io); // Setup UDP if (udprelay) { LOGD("udprelay enabled."); udprelay_init(server_host[0], server_port, dns_thread_num, m, listen_ctx->timeout, iface); } // setuid if (user != NULL) run_as(user); // start ev loop ev_run (loop, 0); return 0; }
void* sock_boot (void *v_options) { int sfd, s; int efd; struct epoll_event event; struct epoll_event *events; s_options* options = (s_options *) v_options; sfd = create_and_bind (options->port); if (sfd == -1) abort (); s = make_socket_non_blocking (sfd); if (s == -1) abort (); s = listen (sfd, SOMAXCONN); if (s == -1) { perror ("listen"); abort (); } efd = epoll_create (1); if (efd == -1) { perror ("epoll_create"); abort (); } event.data.fd = sfd; event.events = EPOLLIN | EPOLLET; s = epoll_ctl (efd, EPOLL_CTL_ADD, sfd, &event); if (s == -1) { perror ("epoll_ctl"); abort (); } /* Buffer where events are returned */ events = calloc (MAXEVENTS, sizeof event); /* The event loop */ while (1) { int n, i; n = epoll_wait (efd, events, MAXEVENTS, -1); for (i = 0; i < n; i++) { if ((events[i].events & EPOLLERR) || (events[i].events & EPOLLHUP) || (!(events[i].events & EPOLLIN))) { /* An error has occured on this fd, or the socket is not ready for reading (why were we notified then?) */ fprintf (stderr, "epoll error\n"); close (events[i].data.fd); continue; } else if (sfd == events[i].data.fd) { /* We have a notification on the listening socket, which means one or more incoming connections. */ while (1) { struct sockaddr in_addr; socklen_t in_len; int infd; char hbuf[NI_MAXHOST], sbuf[NI_MAXSERV]; in_len = sizeof in_addr; infd = accept (sfd, &in_addr, &in_len); if (infd == -1) { if ((errno == EAGAIN) || (errno == EWOULDBLOCK)) { /* We have processed all incoming connections. */ break; } else { perror ("accept"); break; } } s = getnameinfo (&in_addr, in_len, hbuf, sizeof hbuf, sbuf, sizeof sbuf, NI_NUMERICHOST | NI_NUMERICSERV); if (s == 0) { printf("Accepted connection on descriptor %d " "(host=%s, port=%s)\n", infd, hbuf, sbuf); } /* Make the incoming socket non-blocking and add it to the list of fds to monitor. */ s = make_socket_non_blocking (infd); if (s == -1) abort (); event.data.fd = infd; event.events = EPOLLIN | EPOLLET; s = epoll_ctl (efd, EPOLL_CTL_ADD, infd, &event); if (s == -1) { perror ("epoll_ctl"); abort (); } } continue; } else { /* We have data on the fd waiting to be read. Read and display it. We must read whatever data is available completely, as we are running in edge-triggered mode and won't get a notification again for the same data. */ int done = 0; while (1) { ssize_t count; char buf[512]; count = read (events[i].data.fd, buf, sizeof buf); if (count == -1) { /* If errno == EAGAIN, that means we have read all data. So go back to the main loop. */ if (errno != EAGAIN) { perror ("read"); done = 1; } break; } else if (count == 0) { /* End of file. The remote has closed the connection. */ done = 1; break; } char c_payload_size[9]; memcpy(c_payload_size,&buf[0],8); c_payload_size[8] = '\0'; char *e; unsigned long int payload_size = strtoul(c_payload_size,&e,16); clients_data[i].payload_size = payload_size; memcpy(clients_data[i].buffer,&buf[8],payload_size); t_split *directives = ksplit(clients_data[i].buffer,"\x0d\x0a"); int j; for (j=0; j < directives->count; ++j) { memcpy(&received_data_queue[received_data_queue_tail++],directives->splited_ary[j],payload_size); if (received_data_queue_tail > MAX_RECEIVE_QUEUE) received_data_queue_tail = 0; //strcpy(clients_data[i].buffer,&buf[8]); #ifdef DEBUG //printf("payload_size:[%d] | ",payload_size); //printf("clients_data[%d].payload_size:[%lu] | ",i,payload_size); printf("clients_data[%d].buffer:[%s]\n",i,directives->splited_ary[j]); #endif } } if (done) { printf ("Closed connection on descriptor %d\n", events[i].data.fd); /* Closing the descriptor will make epoll remove it from the set of descriptors which are monitored. */ close (events[i].data.fd); } } } } free (events); close (sfd); return EXIT_SUCCESS; }
int main(int argc, char **argv) { int i, c; int pid_flags = 0; char *user = NULL; char *local_port = NULL; char *local_addr = NULL; char *password = NULL; char *timeout = NULL; char *method = NULL; char *pid_path = NULL; char *conf_path = NULL; int remote_num = 0; ss_addr_t remote_addr[MAX_REMOTE_NUM]; char *remote_port = NULL; opterr = 0; while ((c = getopt(argc, argv, "f:s:p:l:k:t:m:c:b:a:")) != -1) { switch (c) { case 's': if (remote_num < MAX_REMOTE_NUM) { remote_addr[remote_num].host = optarg; remote_addr[remote_num++].port = NULL; } break; case 'p': remote_port = optarg; break; case 'l': local_port = optarg; break; case 'k': password = optarg; break; case 'f': pid_flags = 1; pid_path = optarg; break; case 't': timeout = optarg; break; case 'm': method = optarg; break; case 'c': conf_path = optarg; break; case 'b': local_addr = optarg; break; case 'a': user = optarg; break; } } if (opterr) { usage(); exit(EXIT_FAILURE); } if(argc == 1) { if(conf_path == NULL) { conf_path = DEFAULT_CONF_PATH; } } if (conf_path != NULL) { jconf_t *conf = read_jconf(conf_path); if (remote_num == 0) { remote_num = conf->remote_num; for (i = 0; i < remote_num; i++) { remote_addr[i] = conf->remote_addr[i]; } } if (remote_port == NULL) { remote_port = conf->remote_port; } if (local_addr == NULL) { local_addr = conf->local_addr; } if (local_port == NULL) { local_port = conf->local_port; } if (password == NULL) { password = conf->password; } if (method == NULL) { method = conf->method; } if (timeout == NULL) { timeout = conf->timeout; } } if (remote_num == 0 || remote_port == NULL || local_port == NULL || password == NULL) { usage(); exit(EXIT_FAILURE); } if (timeout == NULL) { timeout = "10"; } if (local_addr == NULL) { local_addr = "127.0.0.1"; } if (pid_flags) { USE_SYSLOG(argv[0]); daemonize(pid_path); } // ignore SIGPIPE signal(SIGPIPE, SIG_IGN); signal(SIGABRT, SIG_IGN); // Setup keys LOGI("initialize ciphers... %s", method); int m = enc_init(password, method); // Setup socket int listenfd; listenfd = create_and_bind(local_addr, local_port); if (listenfd < 0) { FATAL("bind() error"); } if (listen(listenfd, SOMAXCONN) == -1) { FATAL("listen() error"); } setnonblocking(listenfd); LOGI("listening at %s:%s", local_addr, local_port); // Setup proxy context struct listen_ctx listen_ctx; listen_ctx.remote_num = remote_num; listen_ctx.remote_addr = malloc(sizeof(struct sockaddr *) * remote_num); for (int i = 0; i < remote_num; i++) { char *host = remote_addr[i].host; char *port = remote_addr[i].port == NULL ? remote_port : remote_addr[i].port; struct sockaddr_storage *storage = malloc(sizeof(struct sockaddr_storage)); memset(storage, 0, sizeof(struct sockaddr_storage)); if (get_sockaddr(host, port, storage, 1) == -1) { FATAL("failed to resolve the provided hostname"); } listen_ctx.remote_addr[i] = (struct sockaddr *)storage; } listen_ctx.timeout = atoi(timeout); listen_ctx.fd = listenfd; listen_ctx.method = m; struct ev_loop *loop = EV_DEFAULT; ev_io_init(&listen_ctx.io, accept_cb, listenfd, EV_READ); ev_io_start(loop, &listen_ctx.io); // setuid if (user != NULL) { run_as(user); } ev_run(loop, 0); return 0; }
int main (int argc, char **argv) { int i, c; int pid_flags = 0; char *user = NULL; char *local_port = NULL; char *local_addr = NULL; char *password = NULL; char *timeout = NULL; char *method = NULL; char *pid_path = NULL; char *conf_path = NULL; char *iface = NULL; int remote_num = 0; ss_addr_t remote_addr[MAX_REMOTE_NUM]; char *remote_port = NULL; opterr = 0; while ((c = getopt (argc, argv, "f:s:p:l:k:t:m:i:c:b:a:uv")) != -1) { switch (c) { case 's': remote_addr[remote_num].host = optarg; remote_addr[remote_num++].port = NULL; break; case 'p': remote_port = optarg; break; case 'l': local_port = optarg; break; case 'k': password = optarg; break; case 'f': pid_flags = 1; pid_path = optarg; break; case 't': timeout = optarg; break; case 'm': method = optarg; break; case 'c': conf_path = optarg; break; case 'i': iface = optarg; break; case 'b': local_addr = optarg; break; case 'a': user = optarg; break; case 'u': udprelay = 1; break; case 'v': verbose = 1; break; } } if (opterr) { usage(); exit(EXIT_FAILURE); } if (conf_path != NULL) { jconf_t *conf = read_jconf(conf_path); if (remote_num == 0) { remote_num = conf->remote_num; for (i = 0; i < remote_num; i++) { remote_addr[i] = conf->remote_addr[i]; } } if (remote_port == NULL) remote_port = conf->remote_port; if (local_addr == NULL) local_addr = conf->local_addr; if (local_port == NULL) local_port = conf->local_port; if (password == NULL) password = conf->password; if (method == NULL) method = conf->method; if (timeout == NULL) timeout = conf->timeout; } if (remote_num == 0 || remote_port == NULL || local_port == NULL || password == NULL) { usage(); exit(EXIT_FAILURE); } if (timeout == NULL) timeout = "10"; if (local_addr == NULL) local_addr = "0.0.0.0"; if (pid_flags) { USE_SYSLOG(argv[0]); demonize(pid_path); } #ifdef __MINGW32__ winsock_init(); #else // ignore SIGPIPE signal(SIGPIPE, SIG_IGN); signal(SIGABRT, SIG_IGN); #endif // Setup keys LOGD("initialize ciphers... %s", method); int m = enc_init(password, method); // Setup socket int listenfd; listenfd = create_and_bind(local_addr, local_port); if (listenfd < 0) { FATAL("bind() error.."); } if (listen(listenfd, SOMAXCONN) == -1) { FATAL("listen() error."); } setnonblocking(listenfd); LOGD("server listening at port %s.", local_port); // Setup proxy context struct listen_ctx listen_ctx; listen_ctx.remote_num = remote_num; listen_ctx.remote_addr = malloc(sizeof(ss_addr_t) * remote_num); while (remote_num > 0) { int index = --remote_num; if (remote_addr[index].port == NULL) remote_addr[index].port = remote_port; listen_ctx.remote_addr[index] = remote_addr[index]; } listen_ctx.timeout = atoi(timeout); listen_ctx.fd = listenfd; listen_ctx.iface = iface; listen_ctx.method = m; struct ev_loop *loop = ev_default_loop(0); if (!loop) { FATAL("ev_loop error."); } ev_io_init (&listen_ctx.io, accept_cb, listenfd, EV_READ); ev_io_start (loop, &listen_ctx.io); // Setup UDP if (udprelay) { LOGD("udprelay enabled."); udprelay_init(local_addr, local_port, remote_addr[0].host, remote_addr[0].port, m, listen_ctx.timeout, iface); } // setuid if (user != NULL) run_as(user); ev_run (loop, 0); #ifdef __MINGW32__ winsock_cleanup(); #endif return 0; }
int EpollServer::create_and_bind(const char *port) { return create_and_bind(NULL, port); }
int main(int argc, char **argv) { int i, c; int pid_flags = 0; char *user = NULL; char *password = NULL; char *timeout = NULL; char *method = NULL; char *pid_path = NULL; char *conf_path = NULL; char *iface = NULL; int server_num = 0; const char *server_host[MAX_REMOTE_NUM]; char * nameservers[MAX_DNS_NUM + 1]; int nameserver_num = 0; int option_index = 0; static struct option long_options[] = { { "fast-open", no_argument, 0, 0 }, { "acl", required_argument, 0, 0 }, { "manager-address", required_argument, 0, 0 }, { 0, 0, 0, 0 } }; opterr = 0; USE_TTY(); while ((c = getopt_long(argc, argv, "f:s:p:l:k:t:m:c:i:d:a:uUv", long_options, &option_index)) != -1) { switch (c) { case 0: if (option_index == 0) { fast_open = 1; } else if (option_index == 1) { LOGI("initialize acl..."); acl = !init_acl(optarg); } else if (option_index == 2) { manager_address = optarg; } break; case 's': if (server_num < MAX_REMOTE_NUM) { server_host[server_num++] = optarg; } break; case 'p': server_port = optarg; break; case 'k': password = optarg; break; case 'f': pid_flags = 1; pid_path = optarg; break; case 't': timeout = optarg; break; case 'm': method = optarg; break; case 'c': conf_path = optarg; break; case 'i': iface = optarg; break; case 'd': if (nameserver_num < MAX_DNS_NUM) { nameservers[nameserver_num++] = optarg; } break; case 'a': user = optarg; break; case 'u': mode = TCP_AND_UDP; break; case 'U': mode = UDP_ONLY; break; case 'v': verbose = 1; break; } } if (opterr) { usage(); exit(EXIT_FAILURE); } if (argc == 1) { if (conf_path == NULL) { conf_path = DEFAULT_CONF_PATH; } } if (conf_path != NULL) { jconf_t *conf = read_jconf(conf_path); if (server_num == 0) { server_num = conf->remote_num; for (i = 0; i < server_num; i++) { server_host[i] = conf->remote_addr[i].host; } } if (server_port == NULL) { server_port = conf->remote_port; } if (password == NULL) { password = conf->password; } if (method == NULL) { method = conf->method; } if (timeout == NULL) { timeout = conf->timeout; } #ifdef TCP_FASTOPEN if (fast_open == 0) { fast_open = conf->fast_open; } #endif #ifdef HAVE_SETRLIMIT if (nofile == 0) { nofile = conf->nofile; } /* * no need to check the return value here since we will show * the user an error message if setrlimit(2) fails */ if (nofile) { if (verbose) { LOGI("setting NOFILE to %d", nofile); } set_nofile(nofile); } #endif if (conf->nameserver != NULL) { nameservers[nameserver_num++] = conf->nameserver; } } if (server_num == 0) { server_host[server_num++] = NULL; } if (server_num == 0 || server_port == NULL || password == NULL) { usage(); exit(EXIT_FAILURE); } if (method == NULL) { method = "table"; } if (timeout == NULL) { timeout = "60"; } if (pid_flags) { USE_SYSLOG(argv[0]); daemonize(pid_path); } if (fast_open == 1) { #ifdef TCP_FASTOPEN LOGI("using tcp fast open"); #else LOGE("tcp fast open is not supported by this environment"); #endif } #ifdef __MINGW32__ winsock_init(); #else // ignore SIGPIPE signal(SIGPIPE, SIG_IGN); signal(SIGCHLD, SIG_IGN); signal(SIGABRT, SIG_IGN); #endif struct ev_signal sigint_watcher; struct ev_signal sigterm_watcher; ev_signal_init(&sigint_watcher, signal_cb, SIGINT); ev_signal_init(&sigterm_watcher, signal_cb, SIGTERM); ev_signal_start(EV_DEFAULT, &sigint_watcher); ev_signal_start(EV_DEFAULT, &sigterm_watcher); // setup keys LOGI("initialize ciphers... %s", method); int m = enc_init(password, method); // inilitialize ev loop struct ev_loop *loop = EV_DEFAULT; // setup udns if (nameserver_num == 0) { #ifdef __MINGW32__ nameservers[nameserver_num++] = "8.8.8.8"; resolv_init(loop, nameservers, nameserver_num); #else resolv_init(loop, NULL, 0); #endif } else { resolv_init(loop, nameservers, nameserver_num); } for (int i = 0; i < nameserver_num; i++) { LOGI("using nameserver: %s", nameservers[i]); } // inilitialize listen context struct listen_ctx listen_ctx_list[server_num]; // bind to each interface while (server_num > 0) { int index = --server_num; const char * host = server_host[index]; if (mode != UDP_ONLY) { // Bind to port int listenfd; listenfd = create_and_bind(host, server_port); if (listenfd < 0) { FATAL("bind() error"); } if (listen(listenfd, SSMAXCONN) == -1) { FATAL("listen() error"); } setnonblocking(listenfd); struct listen_ctx *listen_ctx = &listen_ctx_list[index]; // Setup proxy context listen_ctx->timeout = atoi(timeout); listen_ctx->fd = listenfd; listen_ctx->method = m; listen_ctx->iface = iface; listen_ctx->loop = loop; ev_io_init(&listen_ctx->io, accept_cb, listenfd, EV_READ); ev_io_start(loop, &listen_ctx->io); } // Setup UDP if (mode != TCP_ONLY) { init_udprelay(server_host[index], server_port, m, atoi(timeout), iface); } LOGI("listening at %s:%s", host ? host : "*", server_port); } if (manager_address != NULL) { ev_timer_init(&stat_update_watcher, stat_update_cb, UPDATE_INTERVAL, UPDATE_INTERVAL); ev_timer_start(EV_DEFAULT, &stat_update_watcher); } if (mode != TCP_ONLY) { LOGI("UDP relay enabled"); } if (mode == UDP_ONLY) { LOGI("TCP relay disabled"); } // setuid if (user != NULL) { run_as(user); } // Init connections cork_dllist_init(&connections); // start ev loop ev_run(loop, 0); if (verbose) { LOGI("closed gracefully"); } if (manager_address != NULL) { ev_timer_stop(EV_DEFAULT, &stat_update_watcher); } // Clean up for (int i = 0; i <= server_num; i++) { struct listen_ctx *listen_ctx = &listen_ctx_list[i]; if (mode != UDP_ONLY) { ev_io_stop(loop, &listen_ctx->io); close(listen_ctx->fd); } } if (mode != UDP_ONLY) { free_connections(loop); } if (mode != TCP_ONLY) { free_udprelay(); } resolv_shutdown(loop); #ifdef __MINGW32__ winsock_cleanup(); #endif ev_signal_stop(EV_DEFAULT, &sigint_watcher); ev_signal_stop(EV_DEFAULT, &sigterm_watcher); return 0; }
int main (int argc, char *argv[]) { struct epoll_event event, *events; int sfd, s; int efd; /* Set up listening socket, 'listen_sock' (socket(), bind(), listen()) */ sfd = create_and_bind ("8888"); if (sfd == -1) abort (); s = make_socket_non_blocking (sfd); if (s == -1) { err_sys("socket error"); exit(1); } s = listen (sfd, SOMAXCONN); if (s == -1) { err_sys("listen"); exit(-1); } efd = epoll_create1 (0); if (efd == -1) { err_sys("epoll_create"); exit(-1); } event.data.fd = sfd; //event.events = EPOLLIN | EPOLLET; event.events = EPOLLIN; s = epoll_ctl (efd, EPOLL_CTL_ADD, sfd, &event); if (s == -1) { err_sys("epoll_ctl"); exit(-1); } /* Buffer where events are returned */ events = calloc (MAXEVENTS, sizeof event); /* The event loop */ while (1) { int n, i; n = epoll_wait (efd, events, MAXEVENTS, -1); for (i = 0; i < n; i++) { if ((events[i].events & EPOLLERR) || (events[i].events & EPOLLHUP) || (!(events[i].events & EPOLLIN))) { /* An error has occured on this fd, or the socket is not ready for reading (why were we notified then?) */ fprintf (stderr, "epoll error\n"); close (events[i].data.fd); continue; } else if (sfd == events[i].data.fd) { /* We have a notification on the listening socket, which means one or more incoming connections. */ while (1) { struct sockaddr in_addr; socklen_t in_len; int infd; char hbuf[NI_MAXHOST], sbuf[NI_MAXSERV]; in_len = sizeof in_addr; infd = accept (sfd, &in_addr, &in_len); if (infd == -1) { if ((errno == EAGAIN) || (errno == EWOULDBLOCK)) { /* We have processed all incoming connections. */ break; } else { perror ("accept"); break; } } s = getnameinfo (&in_addr, in_len, hbuf, sizeof hbuf, sbuf, sizeof sbuf, NI_NUMERICHOST | NI_NUMERICSERV); if (s == 0) { printf("Accepted connection on descriptor %d " "(host=%s, port=%s)\n", infd, hbuf, sbuf); } /* Make the incoming socket non-blocking and add it to the list of fds to monitor. */ s = make_socket_non_blocking (infd); if (s == -1) abort (); event.data.fd = infd; //event.events = EPOLLIN | EPOLLET; event.events = EPOLLIN; s = epoll_ctl (efd, EPOLL_CTL_ADD, infd, &event); if (s == -1) { err_sys("epoll_ctl"); } } continue; } else { /* We have data on the fd waiting to be read. Read and display it. We must read whatever data is available completely, as we are running in edge-triggered mode and won't get a notification again for the same data. */ int done = 0; while (1) { ssize_t count; char buf[2]; count = read (events[i].data.fd, buf, sizeof buf); if (count == -1) { /* If errno == EAGAIN, that means we have read all data. So go back to the main loop. */ if (errno != EAGAIN) { perror ("read"); done = 1; } break; } else if (count == 0) { /* End of file. The remote has closed the connection. */ done = 1; break; } /* Write the buffer to standard output */ s = write (1, buf, count); if (s == -1) { err_sys("write"); } } if (done) { printf ("Closed connection on descriptor %d\n", events[i].data.fd); /* Closing the descriptor will make epoll remove it from the set of descriptors which are monitored. */ close (events[i].data.fd); } } } } return 0; }
int main(int argc, char **argv) { int i, c; int pid_flags = 0; char *user = NULL; char *local_port = NULL; char *local_addr = NULL; char *password = NULL; char *timeout = NULL; char *method = NULL; char *pid_path = NULL; char *conf_path = NULL; char *iface = NULL; srand(time(NULL)); int remote_num = 0; ss_addr_t remote_addr[MAX_REMOTE_NUM]; char *remote_port = NULL; int option_index = 0; static struct option long_options[] = { { "fast-open", no_argument, 0, 0 }, { "acl", required_argument, 0, 0 }, { 0, 0, 0, 0 } }; opterr = 0; USE_TTY(); #ifdef ANDROID while ((c = getopt_long(argc, argv, "f:s:p:l:k:t:m:i:c:b:a:uvVA", long_options, &option_index)) != -1) { #else while ((c = getopt_long(argc, argv, "f:s:p:l:k:t:m:i:c:b:a:uvA", long_options, &option_index)) != -1) { #endif switch (c) { case 0: if (option_index == 0) { fast_open = 1; } else if (option_index == 1) { LOGI("initialize acl..."); acl = !init_acl(optarg); } break; case 's': if (remote_num < MAX_REMOTE_NUM) { remote_addr[remote_num].host = optarg; remote_addr[remote_num++].port = NULL; } break; case 'p': remote_port = optarg; break; case 'l': local_port = optarg; break; case 'k': password = optarg; break; case 'f': pid_flags = 1; pid_path = optarg; break; case 't': timeout = optarg; break; case 'm': method = optarg; break; case 'c': conf_path = optarg; break; case 'i': iface = optarg; break; case 'b': local_addr = optarg; break; case 'a': user = optarg; break; case 'u': mode = TCP_AND_UDP; break; case 'v': verbose = 1; break; case 'A': auth = 1; break; #ifdef ANDROID case 'V': vpn = 1; break; #endif } } if (opterr) { usage(); exit(EXIT_FAILURE); } if (argc == 1) { if (conf_path == NULL) { conf_path = DEFAULT_CONF_PATH; } } if (conf_path != NULL) { jconf_t *conf = read_jconf(conf_path); if (remote_num == 0) { remote_num = conf->remote_num; for (i = 0; i < remote_num; i++) { remote_addr[i] = conf->remote_addr[i]; } } if (remote_port == NULL) { remote_port = conf->remote_port; } if (local_addr == NULL) { local_addr = conf->local_addr; } if (local_port == NULL) { local_port = conf->local_port; } if (password == NULL) { password = conf->password; } if (method == NULL) { method = conf->method; } if (timeout == NULL) { timeout = conf->timeout; } if (fast_open == 0) { fast_open = conf->fast_open; } #ifdef HAVE_SETRLIMIT if (nofile == 0) { nofile = conf->nofile; } /* * no need to check the return value here since we will show * the user an error message if setrlimit(2) fails */ if (nofile) { if (verbose) { LOGI("setting NOFILE to %d", nofile); } set_nofile(nofile); } #endif } if (remote_num == 0 || remote_port == NULL || local_port == NULL || password == NULL) { usage(); exit(EXIT_FAILURE); } if (timeout == NULL) { timeout = "60"; } if (local_addr == NULL) { local_addr = "127.0.0.1"; } if (pid_flags) { USE_SYSLOG(argv[0]); daemonize(pid_path); } if (fast_open == 1) { #ifdef TCP_FASTOPEN LOGI("using tcp fast open"); #else LOGE("tcp fast open is not supported by this environment"); #endif } if (auth) { LOGI("onetime authentication enabled"); } #ifdef __MINGW32__ winsock_init(); #else // ignore SIGPIPE signal(SIGPIPE, SIG_IGN); signal(SIGABRT, SIG_IGN); #endif struct ev_signal sigint_watcher; struct ev_signal sigterm_watcher; ev_signal_init(&sigint_watcher, signal_cb, SIGINT); ev_signal_init(&sigterm_watcher, signal_cb, SIGTERM); ev_signal_start(EV_DEFAULT, &sigint_watcher); ev_signal_start(EV_DEFAULT, &sigterm_watcher); // Setup keys LOGI("initialize ciphers... %s", method); int m = enc_init(password, method); // Setup proxy context struct listen_ctx listen_ctx; listen_ctx.remote_num = remote_num; listen_ctx.remote_addr = malloc(sizeof(struct sockaddr *) * remote_num); for (i = 0; i < remote_num; i++) { char *host = remote_addr[i].host; char *port = remote_addr[i].port == NULL ? remote_port : remote_addr[i].port; struct sockaddr_storage *storage = malloc(sizeof(struct sockaddr_storage)); memset(storage, 0, sizeof(struct sockaddr_storage)); if (get_sockaddr(host, port, storage, 1) == -1) { FATAL("failed to resolve the provided hostname"); } listen_ctx.remote_addr[i] = (struct sockaddr *)storage; } listen_ctx.timeout = atoi(timeout); listen_ctx.iface = iface; listen_ctx.method = m; struct ev_loop *loop = EV_DEFAULT; // Setup socket int listenfd; listenfd = create_and_bind(local_addr, local_port); if (listenfd < 0) { FATAL("bind() error"); } if (listen(listenfd, SOMAXCONN) == -1) { FATAL("listen() error"); } setnonblocking(listenfd); listen_ctx.fd = listenfd; ev_io_init(&listen_ctx.io, accept_cb, listenfd, EV_READ); ev_io_start(loop, &listen_ctx.io); // Setup UDP if (mode != TCP_ONLY) { LOGI("udprelay enabled"); init_udprelay(local_addr, local_port, listen_ctx.remote_addr[0], get_sockaddr_len(listen_ctx.remote_addr[0]), m, listen_ctx.timeout, iface); } LOGI("listening at %s:%s", local_addr, local_port); // setuid if (user != NULL) { run_as(user); } // Init connections cork_dllist_init(&connections); // Enter the loop ev_run(loop, 0); if (verbose) { LOGI("closed gracefully"); } // Clean up ev_io_stop(loop, &listen_ctx.io); free_connections(loop); if (mode != TCP_ONLY) { free_udprelay(); } for (i = 0; i < remote_num; i++) { free(listen_ctx.remote_addr[i]); } free(listen_ctx.remote_addr); #ifdef __MINGW32__ winsock_cleanup(); #endif ev_signal_stop(EV_DEFAULT, &sigint_watcher); ev_signal_stop(EV_DEFAULT, &sigterm_watcher); return 0; } #else int start_ss_local_server(profile_t profile) { srand(time(NULL)); char *remote_host = profile.remote_host; char *local_addr = profile.local_addr; char *method = profile.method; char *password = profile.password; char *log = profile.log; int remote_port = profile.remote_port; int local_port = profile.local_port; int timeout = profile.timeout; mode = profile.mode; fast_open = profile.fast_open; verbose = profile.verbose; char local_port_str[16]; char remote_port_str[16]; sprintf(local_port_str, "%d", local_port); sprintf(remote_port_str, "%d", remote_port); USE_LOGFILE(log); if (profile.acl != NULL) { acl = !init_acl(profile.acl); } if (local_addr == NULL) { local_addr = "127.0.0.1"; } #ifdef __MINGW32__ winsock_init(); #else // ignore SIGPIPE signal(SIGPIPE, SIG_IGN); signal(SIGABRT, SIG_IGN); #endif struct ev_signal sigint_watcher; struct ev_signal sigterm_watcher; ev_signal_init(&sigint_watcher, signal_cb, SIGINT); ev_signal_init(&sigterm_watcher, signal_cb, SIGTERM); ev_signal_start(EV_DEFAULT, &sigint_watcher); ev_signal_start(EV_DEFAULT, &sigterm_watcher); // Setup keys LOGI("initialize ciphers... %s", method); int m = enc_init(password, method); struct sockaddr_storage *storage = malloc(sizeof(struct sockaddr_storage)); memset(storage, 0, sizeof(struct sockaddr_storage)); if (get_sockaddr(remote_host, remote_port_str, storage, 1) == -1) { return -1; } // Setup proxy context struct ev_loop *loop = EV_DEFAULT; struct listen_ctx listen_ctx; listen_ctx.remote_num = 1; listen_ctx.remote_addr = malloc(sizeof(struct sockaddr *)); listen_ctx.remote_addr[0] = (struct sockaddr *)storage; listen_ctx.timeout = timeout; listen_ctx.method = m; listen_ctx.iface = NULL; // Setup socket int listenfd; listenfd = create_and_bind(local_addr, local_port_str); if (listenfd < 0) { ERROR("bind()"); return -1; } if (listen(listenfd, SOMAXCONN) == -1) { ERROR("listen()"); return -1; } setnonblocking(listenfd); listen_ctx.fd = listenfd; ev_io_init(&listen_ctx.io, accept_cb, listenfd, EV_READ); ev_io_start(loop, &listen_ctx.io); // Setup UDP if (mode != TCP_ONLY) { LOGI("udprelay enabled"); struct sockaddr *addr = (struct sockaddr *)storage; init_udprelay(local_addr, local_port_str, addr, get_sockaddr_len(addr), m, timeout, NULL); } LOGI("listening at %s:%s", local_addr, local_port_str); // Init connections cork_dllist_init(&connections); // Enter the loop ev_run(loop, 0); if (verbose) { LOGI("closed gracefully"); } // Clean up if (mode != TCP_ONLY) { free_udprelay(); } ev_io_stop(loop, &listen_ctx.io); free_connections(loop); close(listen_ctx.fd); free(listen_ctx.remote_addr); #ifdef __MINGW32__ winsock_cleanup(); #endif ev_signal_stop(EV_DEFAULT, &sigint_watcher); ev_signal_stop(EV_DEFAULT, &sigterm_watcher); // cannot reach here return 0; }
int main(int argc, char* argv[]) { int listen_fd, ret; int epoll_fd; struct epoll_event event; struct epoll_event *events; listen_fd = create_and_bind(PORT); if (listen_fd == -1) { return -1; } ret = set_non_block(listen_fd); if (ret == -1) { return -1; } ret = listen(listen_fd, SOMAXCONN); if (ret == -1) { perror("listen"); return -1; } epoll_fd = epoll_create1(0); if (epoll_fd == -1) { perror("epoll_create"); return -1; } event.data.fd = listen_fd; event.events = EPOLLIN | EPOLLET; ret = epoll_ctl(epoll_fd, EPOLL_CTL_ADD, listen_fd, &event); if (ret == -1) { perror("epoll_ctl"); return -1; } events = calloc(MAX_EVENTS, sizeof event); for (;;) { int n, i; n = epoll_wait(epoll_fd, events, MAX_EVENTS, -1); for (i = 0; i < n; i++) { if (events[i].events & EPOLLERR || events[i].events & EPOLLHUP || !events[i].events & EPOLLIN) { fprintf(stderr, "epoll error\n"); close(events[i].data.fd); continue; } else if (listen_fd == events[i].data.fd) { for (;;) { struct sockaddr in_addr; socklen_t in_len; int in_fd; char hbuf[NI_MAXHOST], sbuf[NI_MAXSERV]; in_len = sizeof in_addr; in_fd = accept(listen_fd, &in_addr, &in_len); if (in_fd == -1) { if (errno == EAGAIN || errno == EWOULDBLOCK) { break; } else { perror("accpet"); break; } } ret = getnameinfo(&in_addr, in_len, hbuf, sizeof hbuf, sbuf, sizeof sbuf, NI_NUMERICHOST | NI_NUMERICSERV); if (ret == 0) { printf("accept connection on fd %d, [%s:%s]\n", in_fd, hbuf, sbuf); } ret = set_non_block(in_fd); if (ret == -1) { return -1; } event.data.fd = in_fd; event.events = EPOLLIN | EPOLLET; ret = epoll_ctl(epoll_fd, EPOLL_CTL_ADD, in_fd, &event); if (ret == -1) { perror("epoll_ctl"); return -1; } } continue; } else if (events[i].events & EPOLLIN) { // get request int done = 0; for (;;) { ssize_t count; char buf[512]; count = read(events[i].data.fd, buf, sizeof buf); if (count == -1) { if (errno != EAGAIN) { perror("read"); done = 1; break; } event.events = EPOLLOUT | EPOLLET; event.data.fd = events[i].data.fd; ret = epoll_ctl(epoll_fd, EPOLL_CTL_MOD, events[i].data.fd, &event); if (ret == -1) { perror("epoll_ctl:mod"); done = 1; } break; } else if (count == 0) { done = 1; break; } // 写入标准输出 ret = write(1, buf, count); if (ret == -1) { perror("write"); done = 1; break; } } if (done == 1) { close(events[i].data.fd); } } else if (events[i].events & EPOLLOUT) { // response int fd; int done = 0; size_t size = 512; ssize_t count; fd = open("./epoll-server.c", O_RDONLY | O_NONBLOCK); if (fd == -1) { perror("open"); close(events[i].data.fd); return -1; } char *head = "HTTP/1.1 200 OK\r\nContent-Type: text/html\r\n\r\n"; count = write(events[i].data.fd, head, sizeof head); if (count == -1 && errno != EAGAIN) { perror("write"); close(events[i].data.fd); return -1; } for (;;) { count = sendfile(events[i].data.fd, fd, 0, size); if (count == -1) { if (errno != EAGAIN) { perror("sendfile"); done = 1; } break; } else if (count == 0) { done = 1; break; } } if (done == 1) { close(events[i].data.fd); } } } } free(events); return 0; }
int main(int argc, char **argv) { int i, c; int pid_flags = 0; char *user = NULL; char *local_port = NULL; char *local_addr = NULL; char *password = NULL; char *timeout = NULL; char *method = NULL; char *pid_path = NULL; char *conf_path = NULL; char *iface = NULL; srand(time(NULL)); int remote_num = 0; ss_addr_t remote_addr[MAX_REMOTE_NUM]; char *remote_port = NULL; int option_index = 0; static struct option long_options[] = { { "fast-open", no_argument, 0, 0 }, { "acl", required_argument, 0, 0 }, { 0, 0, 0, 0 } }; opterr = 0; while ((c = getopt_long(argc, argv, "f:s:p:l:k:t:m:i:c:b:a:uv", long_options, &option_index)) != -1) { switch (c) { case 0: if (option_index == 0) { fast_open = 1; } else if (option_index == 1) { LOGD("initialize acl..."); acl = !init_acl(optarg); } break; case 's': remote_addr[remote_num].host = optarg; remote_addr[remote_num++].port = NULL; break; case 'p': remote_port = optarg; break; case 'l': local_port = optarg; break; case 'k': password = optarg; break; case 'f': pid_flags = 1; pid_path = optarg; break; case 't': timeout = optarg; break; case 'm': method = optarg; break; case 'c': conf_path = optarg; break; case 'i': iface = optarg; break; case 'b': local_addr = optarg; break; case 'a': user = optarg; break; case 'u': udprelay = 1; break; case 'v': verbose = 1; break; } } if (opterr) { usage(); exit(EXIT_FAILURE); } if (conf_path != NULL) { jconf_t *conf = read_jconf(conf_path); if (remote_num == 0) { remote_num = conf->remote_num; for (i = 0; i < remote_num; i++) { remote_addr[i] = conf->remote_addr[i]; } } if (remote_port == NULL) { remote_port = conf->remote_port; } if (local_addr == NULL) { local_addr = conf->local_addr; } if (local_port == NULL) { local_port = conf->local_port; } if (password == NULL) { password = conf->password; } if (method == NULL) { method = conf->method; } if (timeout == NULL) { timeout = conf->timeout; } if (fast_open == 0) { fast_open = conf->fast_open; } #ifdef HAVE_SETRLIMIT if (nofile == 0) { nofile = conf->nofile; } /* * no need to check the return value here since we will show * the user an error message if setrlimit(2) fails */ if (nofile) { if (verbose) { LOGD("setting NOFILE to %d", nofile); } set_nofile(nofile); } #endif } if (remote_num == 0 || remote_port == NULL || local_port == NULL || password == NULL) { usage(); exit(EXIT_FAILURE); } if (timeout == NULL) { timeout = "10"; } if (local_addr == NULL) { local_addr = "0.0.0.0"; } if (pid_flags) { USE_SYSLOG(argv[0]); daemonize(pid_path); } if (fast_open == 1) { #ifdef TCP_FASTOPEN LOGD("using tcp fast open"); #else LOGE("tcp fast open is not supported by this environment"); #endif } #ifdef __MINGW32__ winsock_init(); #else // ignore SIGPIPE signal(SIGPIPE, SIG_IGN); signal(SIGABRT, SIG_IGN); #endif struct ev_signal sigint_watcher; struct ev_signal sigterm_watcher; ev_signal_init(&sigint_watcher, signal_cb, SIGINT); ev_signal_init(&sigterm_watcher, signal_cb, SIGTERM); ev_signal_start(EV_DEFAULT, &sigint_watcher); ev_signal_start(EV_DEFAULT, &sigterm_watcher); // Setup keys LOGD("initialize ciphers... %s", method); int m = enc_init(password, method); // Setup socket int listenfd; listenfd = create_and_bind(local_addr, local_port); if (listenfd < 0) { FATAL("bind() error.."); } if (listen(listenfd, SOMAXCONN) == -1) { FATAL("listen() error."); } setnonblocking(listenfd); LOGD("server listening at port %s.", local_port); // Setup proxy context struct listen_ctx listen_ctx; listen_ctx.remote_num = remote_num; listen_ctx.remote_addr = malloc(sizeof(ss_addr_t) * remote_num); while (remote_num > 0) { int index = --remote_num; if (remote_addr[index].port == NULL) { remote_addr[index].port = remote_port; } listen_ctx.remote_addr[index] = remote_addr[index]; } listen_ctx.timeout = atoi(timeout); listen_ctx.fd = listenfd; listen_ctx.iface = iface; listen_ctx.method = m; struct ev_loop *loop = EV_DEFAULT; if (!loop) { FATAL("ev_loop error."); } ev_io_init(&listen_ctx.io, accept_cb, listenfd, EV_READ); ev_io_start(loop, &listen_ctx.io); // Setup UDP if (udprelay) { LOGD("udprelay enabled."); init_udprelay(local_addr, local_port, remote_addr[0].host, remote_addr[0].port, m, listen_ctx.timeout, iface); } // setuid if (user != NULL) { run_as(user); } // Init connections cork_dllist_init(&connections); // Enter the loop ev_run(loop, 0); if (verbose) { LOGD("closed nicely."); } // Clean up free_connections(loop); free_udprelay(); ev_io_stop(loop, &listen_ctx.io); free(listen_ctx.remote_addr); #ifdef __MINGW32__ winsock_cleanup(); #endif ev_signal_stop(EV_DEFAULT, &sigint_watcher); ev_signal_stop(EV_DEFAULT, &sigterm_watcher); return 0; }
int main (int argc, char *argv[]) { /* initialization code */ cvect_t *dyn_vect = ccache_init(); assert(dyn_vect); int sfd, s; int efd; struct epoll_event event; struct epoll_event *events; char buf[BUFFER_SIZE]; char localbuf[BUFFER_SIZE]; if (argc != 2) { fprintf (stderr, "Usage: %s [port]\n", argv[0]); exit (EXIT_FAILURE); } sfd = create_and_bind (argv[1]); if (sfd == -1) abort (); s = make_socket_non_blocking (sfd); if (s == -1) abort (); s = listen (sfd, SOMAXCONN); if (s == -1) { perror ("listen"); abort (); } efd = epoll_create1 (0); if (efd == -1) { perror ("epoll_create"); abort (); } event.data.fd = sfd; event.events = EPOLLIN | EPOLLET; s = epoll_ctl (efd, EPOLL_CTL_ADD, sfd, &event); if (s == -1) { perror ("epoll_ctl"); abort (); } /* Buffer where events are returned */ events = calloc (MAXEVENTS, sizeof event); /* The event loop */ while (1) { int n, i; n = epoll_wait (efd, events, MAXEVENTS, -1); for (i = 0; i < n; i++) { if ((events[i].events & EPOLLERR) || (events[i].events & EPOLLHUP) || (!(events[i].events & EPOLLIN))) { /* An error has occured on this fd, or the socket is not ready for reading (why were we notified then?) */ fprintf (stderr, "epoll error\n"); close (events[i].data.fd); continue; } else if (sfd == events[i].data.fd) { /* We have a notification on the listening socket, which means one or more incoming connections. */ while (1) { struct sockaddr in_addr; socklen_t in_len; int infd; char hbuf[NI_MAXHOST], sbuf[NI_MAXSERV]; in_len = sizeof in_addr; infd = accept (sfd, &in_addr, &in_len); if (infd == -1) { if ((errno == EAGAIN) || (errno == EWOULDBLOCK)) { /* We have processed all incoming connections. */ break; } else { perror ("accept"); break; } } s = getnameinfo (&in_addr, in_len, hbuf, sizeof hbuf, sbuf, sizeof sbuf, NI_NUMERICHOST | NI_NUMERICSERV); if (s == 0) { printf("Accepted connection on descriptor %d " "(host=%s, port=%s)\n", infd, hbuf, sbuf); } /* Make the incoming socket non-blocking and add it to the list of fds to monitor. */ s = make_socket_non_blocking (infd); if (s == -1) abort (); event.data.fd = infd; event.events = EPOLLIN | EPOLLET; s = epoll_ctl (efd, EPOLL_CTL_ADD, infd, &event); if (s == -1) { perror ("epoll_ctl"); abort (); } } continue; } else { /* We have data on the fd waiting to be read. Read and process it. We must read whatever data is available completely, as we are running in edge-triggered mode and won't get a notification again for the same data. */ int done = 0; while (1) { ssize_t count; bzero(buf,BUFFER_SIZE); //zero out the buffer every time count = read (events[i].data.fd, buf, sizeof buf); if (count == -1) { /* If errno == EAGAIN, that means we have read all data. So go back to the main loop. */ if (errno != EAGAIN) { perror ("read"); done = 1; } break; } else if (count == 0) { /* End of file. The remote has closed the connection. */ done = 1; break; } /* Process the buffered request and write the results to the output */ buf[strlen(buf)-1] = '\0'; //remove trailing newline /* Make sure this request is complete - can do special handling based on creq_type then */ strcpy(localbuf, buf); ccmd_t type = get_creq_type(localbuf); strcpy(localbuf, buf); if(type == CSET) { creq_t *creq = (creq_t *) malloc(sizeof(creq_t)); creq = ccache_req_parse(buf); //now process that actual buffer /* Write Header and Footer to socket */ printf("before header: %s, strlen: %i\n", buf, strlen(creq->resp.header)); if((s = write (events[i].data.fd, creq->resp.header, strlen(creq->resp.header))) == -1) goto write_error; if(creq->resp.errcode == RERROR || creq->resp.errcode == 0){ if((s = write (events[i].data.fd, creq->resp.footer, strlen(creq->resp.footer))) == -1) goto write_error; } } /* CGET */ else if(type == CGET){ /* split multiple requests into single requests and process them */ char * pch; int counter = 0; pch = strtok(localbuf, " "); while(pch != NULL){ if(counter != 0){ /* formulate this new request and then skip the parsing step */ creq_t *creq = (creq_t *) malloc(sizeof(creq_t)); strcpy(creq->key, pch); creq->type = CGET; creq = ccache_get(creq); /* Write Header and Footer to socket */ //printf("before header: %s, strlen: %i\n", buf, strlen(creq->resp.header)); if((s = write (events[i].data.fd, creq->resp.header, strlen(creq->resp.header))) == -1) goto write_error; if(creq->resp.errcode == RERROR || creq->resp.errcode == 0){ if((s = write (events[i].data.fd, creq->resp.footer, strlen(creq->resp.footer))) == -1) goto write_error; } } pch = strtok(NULL, " "); counter++; } /* now that we're done transmitting all the CGET reqs - transmit END */ if((s = write (events[i].data.fd, "END\r\n", strlen("END\r\n"))) == -1) goto write_error; } else if(type == CDELETE || type == INVALID){ creq_t *creq = (creq_t *) malloc(sizeof(creq_t)); creq = ccache_req_parse(buf); //now process that actual buffer /* Write Header and Footer to socket */ printf("before header: %s, strlen: %i\n", buf, strlen(creq->resp.header)); if((s = write (events[i].data.fd, creq->resp.header, strlen(creq->resp.header))) == -1) goto write_error; if(creq->resp.errcode == RERROR || creq->resp.errcode == 0){ if((s = write (events[i].data.fd, creq->resp.footer, strlen(creq->resp.footer))) == -1) goto write_error; } /* cleanup from delete */ free(creq); } else{ printf("error! exiting\n"); exit(1); } } if (done) { printf ("Closed connection on descriptor %d\n", events[i].data.fd); /* Closing the descriptor will make epoll remove it from the set of descriptors which are monitored. */ close (events[i].data.fd); } } } } free (events); close (sfd); return EXIT_SUCCESS; write_error: if (s == -1) { perror ("write"); abort (); } return -1; }
int main(int argc, char **argv) { int i, c; int pid_flags = 0; char *user = NULL; char *local_port = NULL; char *local_addr = NULL; char *password = NULL; char *timeout = NULL; char *method = NULL; char *pid_path = NULL; char *conf_path = NULL; int remote_num = 0; ss_addr_t remote_addr[MAX_REMOTE_NUM]; char *remote_port = NULL; opterr = 0; while ((c = getopt(argc, argv, "f:s:p:l:k:t:m:c:b:a:n:uUvA")) != -1) switch (c) { case 's': if (remote_num < MAX_REMOTE_NUM) { remote_addr[remote_num].host = optarg; remote_addr[remote_num++].port = NULL; } break; case 'p': remote_port = optarg; break; case 'l': local_port = optarg; break; case 'k': password = optarg; break; case 'f': pid_flags = 1; pid_path = optarg; break; case 't': timeout = optarg; break; case 'm': method = optarg; break; case 'c': conf_path = optarg; break; case 'b': local_addr = optarg; break; case 'a': user = optarg; break; #ifdef HAVE_SETRLIMIT case 'n': nofile = atoi(optarg); break; #endif case 'u': mode = TCP_AND_UDP; break; case 'U': mode = UDP_ONLY; break; case 'v': verbose = 1; break; case 'A': auth = 1; break; } if (opterr) { usage(); exit(EXIT_FAILURE); } if (argc == 1) { if (conf_path == NULL) { conf_path = DEFAULT_CONF_PATH; } } if (conf_path != NULL) { jconf_t *conf = read_jconf(conf_path); if (remote_num == 0) { remote_num = conf->remote_num; for (i = 0; i < remote_num; i++) remote_addr[i] = conf->remote_addr[i]; } if (remote_port == NULL) { remote_port = conf->remote_port; } if (local_addr == NULL) { local_addr = conf->local_addr; } if (local_port == NULL) { local_port = conf->local_port; } if (password == NULL) { password = conf->password; } if (method == NULL) { method = conf->method; } if (timeout == NULL) { timeout = conf->timeout; } if (auth == 0) { auth = conf->auth; } #ifdef HAVE_SETRLIMIT if (nofile == 0) { nofile = conf->nofile; } /* * no need to check the return value here since we will show * the user an error message if setrlimit(2) fails */ if (nofile > 1024) { if (verbose) { LOGI("setting NOFILE to %d", nofile); } set_nofile(nofile); } #endif } if (remote_num == 0 || remote_port == NULL || local_port == NULL || password == NULL) { usage(); exit(EXIT_FAILURE); } if (timeout == NULL) { timeout = "60"; } if (local_addr == NULL) { local_addr = "127.0.0.1"; } if (pid_flags) { USE_SYSLOG(argv[0]); daemonize(pid_path); } if (auth) { LOGI("onetime authentication enabled"); } // ignore SIGPIPE signal(SIGPIPE, SIG_IGN); signal(SIGABRT, SIG_IGN); // Setup keys LOGI("initialize ciphers... %s", method); int m = enc_init(password, method); // Setup proxy context listen_ctx_t listen_ctx; listen_ctx.remote_num = remote_num; listen_ctx.remote_addr = malloc(sizeof(struct sockaddr *) * remote_num); for (int i = 0; i < remote_num; i++) { char *host = remote_addr[i].host; char *port = remote_addr[i].port == NULL ? remote_port : remote_addr[i].port; struct sockaddr_storage *storage = malloc(sizeof(struct sockaddr_storage)); memset(storage, 0, sizeof(struct sockaddr_storage)); if (get_sockaddr(host, port, storage, 1) == -1) { FATAL("failed to resolve the provided hostname"); } listen_ctx.remote_addr[i] = (struct sockaddr *)storage; } listen_ctx.timeout = atoi(timeout); listen_ctx.method = m; struct ev_loop *loop = EV_DEFAULT; if (mode != UDP_ONLY) { // Setup socket int listenfd; listenfd = create_and_bind(local_addr, local_port); if (listenfd < 0) { FATAL("bind() error"); } if (listen(listenfd, SOMAXCONN) == -1) { FATAL("listen() error"); } setnonblocking(listenfd); listen_ctx.fd = listenfd; ev_io_init(&listen_ctx.io, accept_cb, listenfd, EV_READ); ev_io_start(loop, &listen_ctx.io); } // Setup UDP if (mode != TCP_ONLY) { LOGI("UDP relay enabled"); init_udprelay(local_addr, local_port, listen_ctx.remote_addr[0], get_sockaddr_len(listen_ctx.remote_addr[0]), m, auth, listen_ctx.timeout, NULL); } if (mode == UDP_ONLY) { LOGI("TCP relay disabled"); } LOGI("listening at %s:%s", local_addr, local_port); // setuid if (user != NULL) { run_as(user); } ev_run(loop, 0); return 0; }
int main(int argc, char **argv) { srand(time(NULL)); int i, c; int pid_flags = 0; int mptcp = 0; int mtu = 0; char *user = NULL; char *local_port = NULL; char *local_addr = NULL; char *password = NULL; char *key = NULL; char *timeout = NULL; char *method = NULL; char *pid_path = NULL; char *conf_path = NULL; char *plugin = NULL; char *plugin_opts = NULL; char *plugin_host = NULL; char *plugin_port = NULL; char tmp_port[8]; int remote_num = 0; ss_addr_t remote_addr[MAX_REMOTE_NUM]; char *remote_port = NULL; int dscp_num = 0; ss_dscp_t * dscp = NULL; static struct option long_options[] = { { "fast-open", no_argument, NULL, GETOPT_VAL_FAST_OPEN }, { "mtu", required_argument, NULL, GETOPT_VAL_MTU }, { "mptcp", no_argument, NULL, GETOPT_VAL_MPTCP }, { "plugin", required_argument, NULL, GETOPT_VAL_PLUGIN }, { "plugin-opts", required_argument, NULL, GETOPT_VAL_PLUGIN_OPTS }, { "reuse-port", no_argument, NULL, GETOPT_VAL_REUSE_PORT }, { "no-delay", no_argument, NULL, GETOPT_VAL_NODELAY }, { "password", required_argument, NULL, GETOPT_VAL_PASSWORD }, { "key", required_argument, NULL, GETOPT_VAL_KEY }, { "help", no_argument, NULL, GETOPT_VAL_HELP }, { NULL, 0, NULL, 0 } }; opterr = 0; USE_TTY(); while ((c = getopt_long(argc, argv, "f:s:p:l:k:t:m:c:b:a:n:huUv6A", long_options, NULL)) != -1) { switch (c) { case GETOPT_VAL_FAST_OPEN: fast_open = 1; break; case GETOPT_VAL_MTU: mtu = atoi(optarg); LOGI("set MTU to %d", mtu); break; case GETOPT_VAL_MPTCP: mptcp = 1; LOGI("enable multipath TCP"); break; case GETOPT_VAL_NODELAY: no_delay = 1; LOGI("enable TCP no-delay"); break; case GETOPT_VAL_PLUGIN: plugin = optarg; break; case GETOPT_VAL_PLUGIN_OPTS: plugin_opts = optarg; break; case GETOPT_VAL_KEY: key = optarg; break; case GETOPT_VAL_REUSE_PORT: reuse_port = 1; break; case 's': if (remote_num < MAX_REMOTE_NUM) { remote_addr[remote_num].host = optarg; remote_addr[remote_num++].port = NULL; } break; case 'p': remote_port = optarg; break; case 'l': local_port = optarg; break; case GETOPT_VAL_PASSWORD: case 'k': password = optarg; break; case 'f': pid_flags = 1; pid_path = optarg; break; case 't': timeout = optarg; break; case 'm': method = optarg; break; case 'c': conf_path = optarg; break; case 'b': local_addr = optarg; break; case 'a': user = optarg; break; #ifdef HAVE_SETRLIMIT case 'n': nofile = atoi(optarg); break; #endif case 'u': mode = TCP_AND_UDP; break; case 'U': mode = UDP_ONLY; break; case 'v': verbose = 1; break; case GETOPT_VAL_HELP: case 'h': usage(); exit(EXIT_SUCCESS); case '6': ipv6first = 1; break; case 'A': FATAL("One time auth has been deprecated. Try AEAD ciphers instead."); break; case '?': // The option character is not recognized. LOGE("Unrecognized option: %s", optarg); opterr = 1; break; } } if (opterr) { usage(); exit(EXIT_FAILURE); } if (argc == 1) { if (conf_path == NULL) { conf_path = DEFAULT_CONF_PATH; } } if (conf_path != NULL) { jconf_t *conf = read_jconf(conf_path); if (remote_num == 0) { remote_num = conf->remote_num; for (i = 0; i < remote_num; i++) remote_addr[i] = conf->remote_addr[i]; } if (remote_port == NULL) { remote_port = conf->remote_port; } if (local_addr == NULL) { local_addr = conf->local_addr; } if (local_port == NULL) { local_port = conf->local_port; } if (password == NULL) { password = conf->password; } if (key == NULL) { key = conf->key; } if (method == NULL) { method = conf->method; } if (timeout == NULL) { timeout = conf->timeout; } if (user == NULL) { user = conf->user; } if (plugin == NULL) { plugin = conf->plugin; } if (plugin_opts == NULL) { plugin_opts = conf->plugin_opts; } if (mode == TCP_ONLY) { mode = conf->mode; } if (mtu == 0) { mtu = conf->mtu; } if (mptcp == 0) { mptcp = conf->mptcp; } if (reuse_port == 0) { reuse_port = conf->reuse_port; } if (disable_sni == 0) { disable_sni = conf->disable_sni; } if (fast_open == 0) { fast_open = conf->fast_open; } #ifdef HAVE_SETRLIMIT if (nofile == 0) { nofile = conf->nofile; } #endif if (ipv6first == 0) { ipv6first = conf->ipv6_first; } dscp_num = conf->dscp_num; dscp = conf->dscp; } if (remote_num == 0 || remote_port == NULL || local_port == NULL || (password == NULL && key == NULL)) { usage(); exit(EXIT_FAILURE); } if (plugin != NULL) { uint16_t port = get_local_port(); if (port == 0) { FATAL("failed to find a free port"); } snprintf(tmp_port, 8, "%d", port); plugin_host = "127.0.0.1"; plugin_port = tmp_port; LOGI("plugin \"%s\" enabled", plugin); } if (method == NULL) { method = "rc4-md5"; } if (timeout == NULL) { timeout = "600"; } #ifdef HAVE_SETRLIMIT /* * no need to check the return value here since we will show * the user an error message if setrlimit(2) fails */ if (nofile > 1024) { if (verbose) { LOGI("setting NOFILE to %d", nofile); } set_nofile(nofile); } #endif if (local_addr == NULL) { local_addr = "127.0.0.1"; } if (fast_open == 1) { #ifdef TCP_FASTOPEN LOGI("using tcp fast open"); #else LOGE("tcp fast open is not supported by this environment"); fast_open = 0; #endif } USE_SYSLOG(argv[0], pid_flags); if (pid_flags) { daemonize(pid_path); } if (ipv6first) { LOGI("resolving hostname to IPv6 address first"); } if (plugin != NULL) { int len = 0; size_t buf_size = 256 * remote_num; char *remote_str = ss_malloc(buf_size); snprintf(remote_str, buf_size, "%s", remote_addr[0].host); for (int i = 1; i < remote_num; i++) { snprintf(remote_str + len, buf_size - len, "|%s", remote_addr[i].host); len = strlen(remote_str); } int err = start_plugin(plugin, plugin_opts, remote_str, remote_port, plugin_host, plugin_port, MODE_CLIENT); if (err) { FATAL("failed to start the plugin"); } } // ignore SIGPIPE signal(SIGPIPE, SIG_IGN); signal(SIGABRT, SIG_IGN); ev_signal_init(&sigint_watcher, signal_cb, SIGINT); ev_signal_init(&sigterm_watcher, signal_cb, SIGTERM); ev_signal_init(&sigchld_watcher, signal_cb, SIGCHLD); ev_signal_start(EV_DEFAULT, &sigint_watcher); ev_signal_start(EV_DEFAULT, &sigterm_watcher); ev_signal_start(EV_DEFAULT, &sigchld_watcher); // Setup keys LOGI("initializing ciphers... %s", method); crypto = crypto_init(password, key, method); if (crypto == NULL) FATAL("failed to initialize ciphers"); // Setup proxy context struct listen_ctx listen_ctx; memset(&listen_ctx, 0, sizeof(struct listen_ctx)); listen_ctx.remote_num = remote_num; listen_ctx.remote_addr = ss_malloc(sizeof(struct sockaddr *) * remote_num); memset(listen_ctx.remote_addr, 0, sizeof(struct sockaddr *) * remote_num); for (i = 0; i < remote_num; i++) { char *host = remote_addr[i].host; char *port = remote_addr[i].port == NULL ? remote_port : remote_addr[i].port; if (plugin != NULL) { host = plugin_host; port = plugin_port; } struct sockaddr_storage *storage = ss_malloc(sizeof(struct sockaddr_storage)); memset(storage, 0, sizeof(struct sockaddr_storage)); if (get_sockaddr(host, port, storage, 1, ipv6first) == -1) { FATAL("failed to resolve the provided hostname"); } listen_ctx.remote_addr[i] = (struct sockaddr *)storage; if (plugin != NULL) break; } listen_ctx.timeout = atoi(timeout); listen_ctx.mptcp = mptcp; struct ev_loop *loop = EV_DEFAULT; listen_ctx_t* listen_ctx_current = &listen_ctx; do { if (mode != UDP_ONLY) { // Setup socket int listenfd; listenfd = create_and_bind(local_addr, local_port); if (listenfd == -1) { FATAL("bind() error"); } if (listen(listenfd, SOMAXCONN) == -1) { FATAL("listen() error"); } setnonblocking(listenfd); listen_ctx_current->fd = listenfd; ev_io_init(&listen_ctx_current->io, accept_cb, listenfd, EV_READ); ev_io_start(loop, &listen_ctx_current->io); } // Setup UDP if (mode != TCP_ONLY) { LOGI("UDP relay enabled"); char *host = remote_addr[0].host; char *port = remote_addr[0].port == NULL ? remote_port : remote_addr[0].port; struct sockaddr_storage *storage = ss_malloc(sizeof(struct sockaddr_storage)); memset(storage, 0, sizeof(struct sockaddr_storage)); if (get_sockaddr(host, port, storage, 1, ipv6first) == -1) { FATAL("failed to resolve the provided hostname"); } struct sockaddr *addr = (struct sockaddr *)storage; init_udprelay(local_addr, local_port, addr, get_sockaddr_len(addr), mtu, crypto, listen_ctx_current->timeout, NULL); } if (mode == UDP_ONLY) { LOGI("TCP relay disabled"); } if(listen_ctx_current->tos) { LOGI("listening at %s:%s (TOS 0x%x)", local_addr, local_port, listen_ctx_current->tos); } else { LOGI("listening at %s:%s", local_addr, local_port); } // Handle additionals TOS/DSCP listening ports if (dscp_num > 0) { listen_ctx_current = (listen_ctx_t*) ss_malloc(sizeof(listen_ctx_t)); listen_ctx_current = memcpy(listen_ctx_current, &listen_ctx, sizeof(listen_ctx_t)); local_port = dscp[dscp_num-1].port; listen_ctx_current->tos = dscp[dscp_num-1].dscp << 2; } } while (dscp_num-- > 0); // setuid if (user != NULL && !run_as(user)) { FATAL("failed to switch user"); } if (geteuid() == 0) { LOGI("running from root user"); } ev_run(loop, 0); if (plugin != NULL) { stop_plugin(); } return 0; }
int main(int argc, char **argv) { srand(time(NULL)); int i, c; int pid_flags = 0; int mptcp = 0; int mtu = 0; char *user = NULL; char *local_port = NULL; char *local_addr = NULL; char *password = NULL; char *timeout = NULL; char *method = NULL; char *pid_path = NULL; char *conf_path = NULL; int remote_num = 0; ss_addr_t remote_addr[MAX_REMOTE_NUM]; char *remote_port = NULL; int option_index = 0; static struct option long_options[] = { { "mtu", required_argument, 0, 0 }, { "mptcp", no_argument, 0, 0 }, { "help", no_argument, 0, 0 }, { 0, 0, 0, 0 } }; opterr = 0; USE_TTY(); while ((c = getopt_long(argc, argv, "f:s:p:l:k:t:m:c:b:a:n:huUvA6", long_options, &option_index)) != -1) { switch (c) { case 0: if (option_index == 0) { mtu = atoi(optarg); LOGI("set MTU to %d", mtu); } else if (option_index == 1) { mptcp = 1; LOGI("enable multipath TCP"); } else if (option_index == 2) { usage(); exit(EXIT_SUCCESS); } break; case 's': if (remote_num < MAX_REMOTE_NUM) { remote_addr[remote_num].host = optarg; remote_addr[remote_num++].port = NULL; } break; case 'p': remote_port = optarg; break; case 'l': local_port = optarg; break; case 'k': password = optarg; break; case 'f': pid_flags = 1; pid_path = optarg; break; case 't': timeout = optarg; break; case 'm': method = optarg; break; case 'c': conf_path = optarg; break; case 'b': local_addr = optarg; break; case 'a': user = optarg; break; #ifdef HAVE_SETRLIMIT case 'n': nofile = atoi(optarg); break; #endif case 'u': mode = TCP_AND_UDP; break; case 'U': mode = UDP_ONLY; break; case 'v': verbose = 1; break; case 'h': usage(); exit(EXIT_SUCCESS); case 'A': auth = 1; break; case '6': ipv6first = 1; break; case '?': // The option character is not recognized. LOGE("Unrecognized option: %s", optarg); opterr = 1; break; } } if (opterr) { usage(); exit(EXIT_FAILURE); } if (argc == 1) { if (conf_path == NULL) { conf_path = DEFAULT_CONF_PATH; } } if (conf_path != NULL) { jconf_t *conf = read_jconf(conf_path); if (remote_num == 0) { remote_num = conf->remote_num; for (i = 0; i < remote_num; i++) remote_addr[i] = conf->remote_addr[i]; } if (remote_port == NULL) { remote_port = conf->remote_port; } if (local_addr == NULL) { local_addr = conf->local_addr; } if (local_port == NULL) { local_port = conf->local_port; } if (password == NULL) { password = conf->password; } if (method == NULL) { method = conf->method; } if (timeout == NULL) { timeout = conf->timeout; } if (user == NULL) { user = conf->user; } if (auth == 0) { auth = conf->auth; } if (mtu == 0) { mtu = conf->mtu; } if (mptcp == 0) { mptcp = conf->mptcp; } #ifdef HAVE_SETRLIMIT if (nofile == 0) { nofile = conf->nofile; } #endif } if (remote_num == 0 || remote_port == NULL || local_port == NULL || password == NULL) { usage(); exit(EXIT_FAILURE); } if (method == NULL) { method = "rc4-md5"; } if (timeout == NULL) { timeout = "600"; } #ifdef HAVE_SETRLIMIT /* * no need to check the return value here since we will show * the user an error message if setrlimit(2) fails */ if (nofile > 1024) { if (verbose) { LOGI("setting NOFILE to %d", nofile); } set_nofile(nofile); } #endif if (local_addr == NULL) { local_addr = "127.0.0.1"; } if (pid_flags) { USE_SYSLOG(argv[0]); daemonize(pid_path); } if (ipv6first) { LOGI("resolving hostname to IPv6 address first"); } if (auth) { LOGI("onetime authentication enabled"); } // ignore SIGPIPE signal(SIGPIPE, SIG_IGN); signal(SIGABRT, SIG_IGN); signal(SIGINT, signal_cb); signal(SIGTERM, signal_cb); // Setup keys LOGI("initializing ciphers... %s", method); int m = enc_init(password, method); // Setup proxy context listen_ctx_t listen_ctx; listen_ctx.remote_num = remote_num; listen_ctx.remote_addr = ss_malloc(sizeof(struct sockaddr *) * remote_num); for (int i = 0; i < remote_num; i++) { char *host = remote_addr[i].host; char *port = remote_addr[i].port == NULL ? remote_port : remote_addr[i].port; struct sockaddr_storage *storage = ss_malloc(sizeof(struct sockaddr_storage)); memset(storage, 0, sizeof(struct sockaddr_storage)); if (get_sockaddr(host, port, storage, 1, ipv6first) == -1) { FATAL("failed to resolve the provided hostname"); } listen_ctx.remote_addr[i] = (struct sockaddr *)storage; } listen_ctx.timeout = atoi(timeout); listen_ctx.method = m; listen_ctx.mptcp = mptcp; struct ev_loop *loop = EV_DEFAULT; if (mode != UDP_ONLY) { // Setup socket int listenfd; listenfd = create_and_bind(local_addr, local_port); if (listenfd == -1) { FATAL("bind() error"); } if (listen(listenfd, SOMAXCONN) == -1) { FATAL("listen() error"); } setnonblocking(listenfd); listen_ctx.fd = listenfd; ev_io_init(&listen_ctx.io, accept_cb, listenfd, EV_READ); ev_io_start(loop, &listen_ctx.io); } // Setup UDP if (mode != TCP_ONLY) { LOGI("UDP relay enabled"); init_udprelay(local_addr, local_port, listen_ctx.remote_addr[0], get_sockaddr_len(listen_ctx.remote_addr[0]), mtu, m, auth, listen_ctx.timeout, NULL); } if (mode == UDP_ONLY) { LOGI("TCP relay disabled"); } LOGI("listening at %s:%s", local_addr, local_port); // setuid if (user != NULL && ! run_as(user)) { FATAL("failed to switch user"); } if (geteuid() == 0){ LOGI("running from root user"); } ev_run(loop, 0); return 0; }
int main(int argc, char *argv[]) { if (argc != 2) { print_err("Arguments failure"); } pid_t main_pid = fork(); switch(main_pid) { case 0: break; case -1: print_err("Can't fork main"); default: exit(0); } if(setsid()<0) { print_err("Can't start new session"); } pid_t nsession_pid = fork(); switch(nsession_pid) { case 0: break; case -1: print_err("Can't fork from deamon"); default: return 0; } pid_t daemon_pid = getpid(); int tmp_fd = open("/tmp/netsh.pid", O_WRONLY | O_CREAT); char* buf = new char[64]; int digits = sprintf(buf, "%d\n", daemon_pid); ssize_t written_count = write(tmp_fd, buf, digits); if (written_count == -1) { close(tmp_fd); print_err("Failed to write pid to file"); } close(tmp_fd); //Done pre part const int epoll_size = 32; struct epoll_event event; struct epoll_event *events; //prepare socket int socket_fd = create_and_bind(argv[1]); make_socket_non_blocking(socket_fd); if (listen(socket_fd, SOMAXCONN) == -1) { print_err("Can't setup listener"); } //Setup epoll int epoll_fd = epoll_create1(0); if (epoll_fd == -1) { print_err("Can't create epoll"); } event.data.fd = socket_fd; event.events = EPOLLIN | EPOLLET; int ectl_status = epoll_ctl(epoll_fd, EPOLL_CTL_ADD, socket_fd, &event); if (ectl_status == -1) { print_err("Can't register fd in epoll"); } events = calloc(epoll_size, sizeof(event)); while (1) { int n, i; n = epoll_wait (epoll_fd, events, epoll_size, -1); for (i = 0; i < n; i++) { if ((events[i].events & EPOLLERR) || (events[i].events & EPOLLHUP) || (!(events[i].events & EPOLLIN))) { close (events[i].data.fd); continue; } else if (socket_fd == events[i].data.fd) { while (1) { struct sockaddr in_addr; socklen_t in_len; int infd; char hbuf[NI_MAXHOST], sbuf[NI_MAXSERV]; in_len = sizeof in_addr; infd = accept (socket_fd, &in_addr, &in_len); if (infd == -1) { if ((errno == EAGAIN) || (errno == EWOULDBLOCK)) { break; } else { perror ("Can't accept"); break; } } int unblock_status = make_socket_non_blocking (infd); if (unblock_status == -1) print_err("Can't unblock socket"); event.data.fd = infd; event.events = EPOLLIN | EPOLLET; int epc_status = epoll_ctl (epoll_fd, EPOLL_CTL_ADD, infd, &event); if (epc_status == -1) { print_err("Can't add flags"); } } continue; } else if (events[i].events == EPOLLIN) { int done = 0; read_and_exec(events[i].data.fd); if (1) { close (events[i].data.fd); } } else if (events[i].events == EPOLLOUT) { } } } return 0; }