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