useful script on bladecenters
[tridge/junkcode.git] / tcpproxy.c
1 #include <stdio.h>
2 #include <stdlib.h>
3 #include <string.h>
4 #include <time.h>
5 #include <errno.h>
6 #include <sys/socket.h>
7 #include <netdb.h>
8 #include <unistd.h>
9 #include <stdlib.h>
10 #include <fcntl.h>
11 #include <sys/types.h>
12 #include <sys/time.h>
13 #include <arpa/inet.h>
14 #include <netinet/in.h>
15 #include <ctype.h>
16 #include <signal.h>
17 #include <sys/ioctl.h>
18
19 #define MAX(a,b) ((a)>(b)?(a):(b))
20
21 /* open a socket to a tcp remote host with the specified port */
22 static int open_socket_out(const char *host, int port)
23 {
24         struct sockaddr_in sock_out;
25         int res;
26         struct hostent *hp;  
27         struct in_addr addr;
28
29         res = socket(PF_INET, SOCK_STREAM, 0);
30         if (res == -1) {
31                 return -1;
32         }
33
34         if (inet_pton(AF_INET, host, &addr) > 0) {
35                 memcpy(&sock_out.sin_addr, &addr, sizeof(addr));
36         } else {
37                 hp = gethostbyname(host);
38                 if (!hp) {
39                         fprintf(stderr,"tseal: unknown host %s\n", host);
40                         return -1;
41                 }
42                 memcpy(&sock_out.sin_addr, hp->h_addr, hp->h_length);
43         }
44
45         sock_out.sin_port = htons(port);
46         sock_out.sin_family = PF_INET;
47
48         if (connect(res,(struct sockaddr *)&sock_out,sizeof(sock_out)) != 0) {
49                 close(res);
50                 fprintf(stderr,"tseal: failed to connect to %s (%s)\n", 
51                         host, strerror(errno));
52                 return -1;
53         }
54
55         return res;
56 }
57
58
59 /*
60   open a socket of the specified type, port and address for incoming data
61 */
62 int open_socket_in(int port)
63 {
64         struct sockaddr_in sock;
65         int res;
66         int one=1;
67
68         memset(&sock,0,sizeof(sock));
69
70 #ifdef HAVE_SOCK_SIN_LEN
71         sock.sin_len = sizeof(sock);
72 #endif
73         sock.sin_port = htons(port);
74         sock.sin_family = AF_INET;
75
76         res = socket(AF_INET, SOCK_STREAM, 0);
77         if (res == -1) { 
78                 fprintf(stderr, "socket failed\n"); return -1; 
79                 return -1;
80         }
81
82         setsockopt(res,SOL_SOCKET,SO_REUSEADDR,(char *)&one,sizeof(one));
83
84         if (bind(res, (struct sockaddr *)&sock, sizeof(sock)) < 0) { 
85                 return(-1); 
86         }
87
88         return res;
89 }
90
91 /* write to a file descriptor, making sure we get all the data out or
92  * die trying */
93 static void write_all(int fd, unsigned char *s, size_t n)
94 {
95         while (n) {
96                 int r;
97                 r = write(fd, s, n);
98                 if (r <= 0) {
99                         exit(1);
100                 }
101                 s += r;
102                 n -= r;
103         }
104 }
105
106 static void recv_send(int sock1, int sock2)
107 {
108         int len;
109         unsigned char *buf;
110         int num_ready;
111
112         if (ioctl(sock1, FIONREAD, &num_ready) != 0 
113             || num_ready == 0) {
114                 exit(0);
115         }
116
117         buf = malloc(num_ready);
118
119         len = read(sock1, buf, num_ready);
120         if (len > 0) {
121                 write_all(sock2, buf, len);
122         }
123
124         free(buf);
125 }
126
127 static void main_loop(int sock1, int sock2)
128 {
129         while (1) {
130                 fd_set fds;
131                 int ret;
132
133                 FD_ZERO(&fds);
134                 FD_SET(sock1, &fds);
135                 FD_SET(sock2, &fds);
136
137                 ret = select(MAX(sock1, sock2)+1, &fds, NULL, NULL, NULL);
138                 if (ret == -1 && errno == EINTR) continue;
139                 if (ret <= 0) break;
140
141                 if (FD_ISSET(sock1, &fds)) {
142                         recv_send(sock1, sock2);
143                 }
144
145                 if (FD_ISSET(sock2, &fds)) {
146                         recv_send(sock2, sock1);
147                 }
148         }       
149 }
150
151 int main(int argc, char *argv[])
152 {
153         int listen_port, dest_port;
154         char *host;
155         int sock_in;
156         int sock_out;
157         int listen_fd;
158         struct sockaddr addr;
159         socklen_t in_addrlen = sizeof(addr);
160
161         if (argc < 4) {
162                 printf("Usage: tcpproxy <inport> <host> <port>\n");
163                 exit(1);
164         }
165
166         listen_port = atoi(argv[1]);
167         host = argv[2];
168         dest_port = atoi(argv[3]);
169
170         listen_fd = open_socket_in(listen_port);
171
172         if (listen_fd == -1) {
173                 fprintf(stderr,"listen on port %d failed - %s\n", 
174                         listen_port, strerror(errno));
175                 exit(1);
176         }
177
178         if (listen(listen_fd, 5) == -1) {
179                 fprintf(stderr,"listen failed\n");
180                 exit(1);
181         }
182
183         signal(SIGCHLD, SIG_IGN);
184
185         while ((sock_in = accept(listen_fd,&addr,&in_addrlen)) != -1) {
186                 if (fork() == 0) {
187                         close(listen_fd);
188                         sock_out = open_socket_out(host, dest_port);
189                         if (sock_out == -1) {
190                                 exit(1);
191                         }
192
193                         main_loop(sock_in, sock_out);
194                         exit(0);
195                 }
196                 close(sock_in);
197         }
198         return 0;
199 }