1 /* test.c */
2 /* Id: test.c,v 1.1 2001/09/17 19:06:59 bodo Exp  */
3 
4 #define L_PORT 9999
5 #define C_PORT 443
6 
7 #include <arpa/inet.h>
8 #include <assert.h>
9 #include <errno.h>
10 #include <fcntl.h>
11 #include <netinet/in.h>
12 #include <netinet/tcp.h>
13 #include <stdlib.h>
14 #include <stdio.h>
15 #include <string.h>
16 #include <sys/select.h>
17 #include <sys/socket.h>
18 #include <unistd.h>
19 
20 #include "test.h"
21 #include "easy-tls.h"
22 
23 void
24 test_process_init(int fd, int client_p, void *apparg)
25 {
26     fprintf(stderr, "test_process_init(fd = %d, client_p = %d, apparg = %p)\n", fd, client_p, apparg);
27 }
28 
29 void
30 test_errflush(int child_p, char *errbuf, size_t num, void *apparg)
31 {
32     fputs(errbuf, stderr);
33 }
34 
35 
36 int
37 main(int argc, char *argv[])
38 {
39     int s, fd, r;
40     FILE *conn_in;
41     FILE *conn_out;
42     char buf[256];
43     SSL_CTX *ctx;
44     int client_p = 0;
45     int port;
46     int tls = 0;
47     char infobuf[TLS_INFO_SIZE + 1];
48 
49     if (argc > 1 && argv[1][0] == '-') {
50 	fputs("Usage: test [port]                   -- server\n"
51 	      "       test num.num.num.num [port]   -- client\n",
52 	      stderr);
53 	exit(1);
54     }
55 
56     if (argc > 1) {
57 	if (strchr(argv[1], '.')) {
58 	    client_p = 1;
59 	}
60     }
61 
62     fputs(client_p ? "Client\n" : "Server\n", stderr);
63 
64     {
65 	struct tls_create_ctx_args a = tls_create_ctx_defaultargs();
66 	a.client_p = client_p;
67 	a.certificate_file = "cert.pem";
68 	a.key_file = "cert.pem";
69 	a.ca_file = "cacerts.pem";
70 
71 	ctx = tls_create_ctx(a, NULL);
72 	if (ctx == NULL)
73 	    exit(1);
74     }
75 
76     s = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
77     if (s == -1) {
78 	perror("socket");
79 	exit(1);
80     }
81 
82     if (client_p) {
83 	struct sockaddr_in addr;
84 	size_t addr_len = sizeof addr;
85 
86 	addr.sin_family = AF_INET;
87 	assert(argc > 1);
88 	if (argc > 2)
89 	    sscanf(argv[2], "%d", &port);
90 	else
91 	    port = C_PORT;
92 	addr.sin_port = htons(port);
93 	addr.sin_addr.s_addr = inet_addr(argv[1]);
94 
95 	r = connect(s, &addr, addr_len);
96 	if (r != 0) {
97 	    perror("connect");
98 	    exit(1);
99 	}
100 	fd = s;
101 	fprintf(stderr, "Connect (fd = %d).\n", fd);
102     } else {
103 	/* server */
104 	{
105 	    int i = 1;
106 
107 	    r = setsockopt(s, SOL_SOCKET, SO_REUSEADDR, (void *) &i, sizeof i);
108 	    if (r == -1) {
109 		perror("setsockopt");
110 		exit(1);
111 	    }
112 	}
113 
114 	{
115 	    struct sockaddr_in addr;
116 	    size_t addr_len = sizeof addr;
117 
118 	    if (argc > 1)
119 		sscanf(argv[1], "%d", &port);
120 	    else
121 		port = L_PORT;
122 	    addr.sin_family = AF_INET;
123 	    addr.sin_port = htons(port);
124 	    addr.sin_addr.s_addr = INADDR_ANY;
125 
126 	    r = bind(s, &addr, addr_len);
127 	    if (r != 0) {
128 		perror("bind");
129 		exit(1);
130 	    }
131 	}
132 
133 	r = listen(s, 1);
134 	if (r == -1) {
135 	    perror("listen");
136 	    exit(1);
137 	}
138 
139 	fprintf(stderr, "Listening at port %i.\n", port);
140 
141 	fd = accept(s, NULL, 0);
142 	if (fd == -1) {
143 	    perror("accept");
144 	    exit(1);
145 	}
146 
147 	fprintf(stderr, "Accept (fd = %d).\n", fd);
148     }
149 
150     conn_in = fdopen(fd, "r");
151     if (conn_in == NULL) {
152 	perror("fdopen");
153 	exit(1);
154     }
155     conn_out = fdopen(fd, "w");
156     if (conn_out == NULL) {
157 	perror("fdopen");
158 	exit(1);
159     }
160 
161     setvbuf(conn_in, NULL, _IOLBF, 256);
162     setvbuf(conn_out, NULL, _IOLBF, 256);
163 
164     while (fgets(buf, sizeof buf, stdin) != NULL) {
165 	if (buf[0] == 'W') {
166 	    fprintf(conn_out, "%.*s\r\n", (int)(strlen(buf + 1) - 1), buf + 1);
167 	    fprintf(stderr, ">>> %.*s\n", (int)(strlen(buf + 1) - 1), buf + 1);
168 	} else if (buf[0] == 'C') {
169 	    fprintf(stderr, "Closing.\n");
170 	    fclose(conn_in);
171 	    fclose(conn_out);
172 	    exit(0);
173 	} else if (buf[0] == 'R') {
174 	    int lines = 0;
175 
176 	    sscanf(buf + 1, "%d", &lines);
177 	    do {
178 		if (fgets(buf, sizeof buf, conn_in) == NULL) {
179 		    if (ferror(conn_in)) {
180 			fprintf(stderr, "ERROR\n");
181 			exit(1);
182 		    }
183 		    fprintf(stderr, "CLOSED\n");
184 		    return 0;
185 		}
186 		fprintf(stderr, "<<< %s", buf);
187 	    } while (--lines > 0);
188 	} else if (buf[0] == 'T') {
189 	    int infofd;
190 
191 	    tls++;
192 	    {
193 		struct tls_start_proxy_args a = tls_start_proxy_defaultargs();
194 		a.fd = fd;
195 		a.client_p = client_p;
196 		a.ctx = ctx;
197 		a.infofd = &infofd;
198 		r = tls_start_proxy(a, NULL);
199 	    }
200 	    assert(r != 1);
201 	    if (r != 0) {
202 		fprintf(stderr, "tls_start_proxy failed: %d\n", r);
203 		switch (r) {
204 		case -1:
205 		    fputs("socketpair", stderr); break;
206 		case 2:
207 		    fputs("FD_SETSIZE exceeded", stderr); break;
208 		case -3:
209 		    fputs("pipe", stderr); break;
210 		case -4:
211 		    fputs("fork", stderr); break;
212 		case -5:
213 		    fputs("dup2", stderr); break;
214 		default:
215 		    fputs("?", stderr);
216 		}
217 		if (r < 0)
218 		    perror("");
219 		else
220 		    fputc('\n', stderr);
221 		exit(1);
222 	    }
223 
224 	    r = read(infofd, infobuf, sizeof infobuf - 1);
225 	    if (r > 0) {
226 		const char *info = infobuf;
227 		const char *eol;
228 
229 		infobuf[r] = '\0';
230 		while ((eol = strchr(info, '\n')) != NULL) {
231 		    fprintf(stderr, "+++ `%.*s'\n", eol - info, info);
232 		    info = eol+1;
233 		}
234 		close (infofd);
235 	    }
236 	} else {
237 	    fprintf(stderr, "W...  write line to network\n"
238 		    "R[n]  read line (n lines) from network\n"
239 		    "C     close\n"
240 		    "T     start %sTLS proxy\n", tls ? "another " : "");
241 	}
242     }
243     return 0;
244 }
245