Skip to content

Instantly share code, notes, and snippets.

@xream
Created December 30, 2011 05:12
Show Gist options
  • Save xream/1538016 to your computer and use it in GitHub Desktop.
Save xream/1538016 to your computer and use it in GitHub Desktop.
Multiple SSH Tunnels
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#include <signal.h>
#include <fcntl.h>
#include <netdb.h>
#define PORT 7070
#define ADDRESS "127.0.0.1"
#define RPORT 7071
#define THREAD 4
#define RADDR "127.0.0.1"
#define MAXDATA 1024
#define MAXCLIENT 255
#define LOG 0
#define ERRLOG 1
#define SELLOG 0
int INDEX = -1;
#define MSG_NOSIGNAL 0
void xsocket(int *_listen_fd){
int on = 1;
errno = 0;
if((*_listen_fd=socket(AF_INET, SOCK_STREAM, 0)) >= 0){
if(LOG) {perror("#10000.socket\t");}
}
else{
if(ERRLOG) {perror("#10001.socket\t");}
//exit(1);
}
errno = 0;
if(setsockopt(*_listen_fd, SOL_SOCKET, SO_REUSEADDR, (int *) &on, sizeof(on)) >= 0){
if(LOG) {perror("#10020.setopt\t");}
}
else{
if(ERRLOG) {perror("#10021.setopt\t");}
}
return;
}
void xbzero(struct sockaddr_in *_saddr){
bzero(((char *) _saddr), sizeof(*_saddr));
return;
}
void xbind(int *_listen_fd, struct sockaddr_in *_saddr, int *len){
_saddr->sin_family = PF_INET;
_saddr->sin_addr.s_addr = inet_addr(ADDRESS);
_saddr->sin_port = htons(PORT);
errno = 0;
if(bind(*_listen_fd, (struct sockaddr *)_saddr, *len) >= 0){
if(LOG) {perror("#10100.bind\t");}
}
else{
if(ERRLOG) {perror("#10101.bind\t");}
//exit(1);
}
return;
}
void xlisten(int *_listen_fd){
errno = 0;
if(listen(*_listen_fd, MAXCLIENT) >= 0){
if(LOG) {perror("#10200.listen\t");}
}
else{
if(ERRLOG) {perror("#10201.listen\t");}
exit(1);
}
printf("start listening port %d\n", PORT);
return;
}
int xaccept(int *_listen_fd, struct sockaddr_in *_caddr, int *_len){
int conn_fd;
if((conn_fd = accept(*_listen_fd, (struct sockaddr *) _caddr, (socklen_t *__restrict) _len)) >= 0){
if(LOG) {perror("#10300.accept\t");}
}
else{
if(ERRLOG) {perror("#10301.accept\t");}
}
return conn_fd;
}
void xgetaddrinfo(char *_name, int _port, struct addrinfo **_addr){
char port[10];
sprintf(port, "%d", _port);
errno = 0;
if(getaddrinfo(_name, port, NULL, _addr) >= 0){
if(LOG) {perror("#11000.getaddr\t");}
}
else{
if(ERRLOG) {perror("#11001.getaddr\t");}
exit(1);
}
return;
}
int xconnect(int *_conn_fd, struct addrinfo *_addr){
int ret = 0;
errno = 0;
if(connect(*_conn_fd, _addr->ai_addr, _addr->ai_addrlen) >= 0){
if(LOG) {perror("#11100.connect\t");}
}
else{
if(ERRLOG) {perror("#11101.connect\t");}
ret = -1;
}
return ret;
}
int max(int x, int y){
if(x >= y){
return x;
}
else{
return y;
}
}
void dclose(int *fd, int *rfd, int i){
close(fd[i]);
close(rfd[i]);
fd[i] = -1;
rfd[i] = -1;
return;
}
int main(int argc, char **argv){
struct sockaddr_in saddr;
struct sockaddr_in caddr;
int listen_fd;
int len = sizeof(struct sockaddr_in);
int rsize;
char buf[MAXDATA];
int i;
int ret;
int fd[MAXCLIENT];
int rfd[MAXCLIENT];
int nfds = 0;
struct addrinfo *addr[THREAD];
fd_set rd;
FD_ZERO(&rd);
for(i = 0;i < MAXCLIENT;i++){
fd[i] = -1;
rfd[i] = -1;
}
for(i = 0;i < THREAD;i++){
xgetaddrinfo(RADDR, RPORT+i, &addr[i]);
}
signal(SIGPIPE, SIG_IGN);
xsocket(&listen_fd);
xbzero(&saddr);
xbzero(&caddr);
xbind(&listen_fd, &saddr, &len);
xlisten(&listen_fd);
while(1){
if(SELLOG){printf("loop start\n");}
FD_ZERO(&rd);
FD_SET(listen_fd, &rd);
for(i = 0; i < MAXCLIENT; i++){
if(fd[i] >= 0){
FD_SET(fd[i], &rd);
}
if(rfd[i] >= 0){
FD_SET(rfd[i], &rd);
}
}
nfds = max(nfds, listen_fd);
ret = select(nfds+1, &rd, NULL, NULL, NULL);
if(SELLOG){printf("select return\n");}
if(ret < 0){
if (errno == EINTR){ //EINTR = 4
continue;
}
else{
if(ERRLOG){printf("begin select failure\n");}
}
}
if(FD_ISSET(listen_fd ,&rd)){
if(SELLOG){printf("start accept\n");}
for(i = 0; i < MAXCLIENT; i++){
if(fd[i] < 0){
fd[i] = xaccept(&listen_fd, &caddr, &len);
if(fd[i] < 0){
if(ERRLOG){printf("accept a new connection failure\n");}
}
else{
if(++INDEX >= THREAD){
INDEX = 0;
}
if(SELLOG){printf("%d\n",RPORT+INDEX);}
xsocket(&(rfd[i]));
if(xconnect(&(rfd[i]), addr[INDEX]) < 0){
if(ERRLOG){printf("connect remote server error\n");}
dclose(fd, rfd, i);
}
else{
if(SELLOG){printf("connect remote server finish\n");}
}
}
if (fd[i] > nfds){
nfds = fd[i];
}
if (rfd[i] > nfds){
nfds = rfd[i];
}
break;
}
}
continue;
}
for(i = 0; i < MAXCLIENT; i++){
if(fd[i] < 0){
continue;
}
if(FD_ISSET(fd[i], &rd)){
bzero(&buf, sizeof(buf));
errno = 0;
if(SELLOG){printf("recv data form local\n");}
rsize = recv(fd[i], buf, MAXDATA, MSG_NOSIGNAL);
if(rsize < 0){
if(SELLOG){perror("#50001.recv error");}
dclose(fd, rfd, i);
continue;
}
else if(rsize ==0){
if(SELLOG){printf("local connection closed\n");}
dclose(fd, rfd, i);
continue;
}
else{
if(SELLOG){printf("send data to remote server\n");}
if(send(rfd[i], buf, rsize, MSG_NOSIGNAL) < 0){
if(SELLOG){printf("send data to remote server error\n");}
dclose(fd, rfd, i);
continue;
}
}
}
if(FD_ISSET(rfd[i], &rd)){
bzero(&buf, sizeof(buf));
errno = 0;
if(SELLOG){printf("recv data form remote server\n");}
rsize = recv(rfd[i], buf, MAXDATA, MSG_NOSIGNAL);
if(rsize < 0){
if(SELLOG){perror("#50001.recv error");}
dclose(fd, rfd, i);
continue;
}
else if(rsize ==0){
if(SELLOG){printf("remote connection closed\n");}
dclose(fd, rfd, i);
continue;
}
else{
if(SELLOG){printf("send data to local\n");}
if(send(fd[i], buf, rsize, MSG_NOSIGNAL) < 0){
if(SELLOG){printf("send data to local error\n");}
dclose(fd, rfd, i);
continue;
}
}
}
}
}
return 0;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment