]> git.saurik.com Git - apple/security.git/blob - tlsnke/tlsnketest/main.c
Security-55471.tar.gz
[apple/security.git] / tlsnke / tlsnketest / main.c
1 //
2 // main.c
3 // tlsnketest
4 //
5 // Created by Fabrice Gautier on 12/7/11.
6 // Copyright (c) 2011 Apple, Inc. All rights reserved.
7 //
8
9 #include <stdlib.h>
10 #include <stdio.h>
11 #include <string.h>
12
13 #include <unistd.h>
14 #include <sys/socket.h>
15 #include <netinet/in.h>
16 #include <arpa/inet.h>
17 #include <net/kext_net.h>
18 #include <pthread.h>
19 #include <netdb.h>
20 #include <fcntl.h>
21
22 #include <stdbool.h>
23
24 #include <AssertMacros.h>
25 #include "tlssocket.h"
26 #include "tlsnke.h"
27
28
29 static void print_data(const char *s, size_t l, const unsigned char *p)
30 {
31 printf("%s, %zu:",s, l);
32 for(int i=0; i<l; i++)
33 printf(" %02x", p[i]);
34 printf("\n");
35 }
36
37 static void *server_thread_func(void *arg)
38 {
39 int sock;
40 struct sockaddr_in server_addr;
41 int err;
42
43 if ((sock = socket(AF_INET, SOCK_DGRAM, 0)) == -1) {
44 perror("server socket");
45 exit(1);
46 }
47
48 // Dont use TLSSocket_Attach for the server:
49 // TLSSocket_Attach can only open one TLS socket at a time.
50 {
51 struct so_nke so_tlsnke;
52
53 memset(&so_tlsnke, 0, sizeof(so_tlsnke));
54 so_tlsnke.nke_handle = TLS_HANDLE_IP4;
55 err=setsockopt(sock, SOL_SOCKET, SO_NKE, &so_tlsnke, sizeof(so_tlsnke));
56 if(err<0) {
57 perror("attach (server)");
58 exit(err);
59 }
60 }
61
62 server_addr.sin_family = AF_INET;
63 server_addr.sin_port = htons(23232);
64 server_addr.sin_addr.s_addr = INADDR_ANY;
65 bzero(&(server_addr.sin_zero),8);
66
67 if (bind(sock, (struct sockaddr *)&server_addr, sizeof(struct sockaddr))
68 == -1) {
69 perror("Unable to bind");
70 exit(1);
71 }
72
73 printf("\nBound - Server Waiting for client on port 23232\n");
74 fflush(stdout);
75
76 while (1)
77 {
78 int rc;
79 SSLRecord rec;
80 rc=TLSSocket_Funcs.read((intptr_t)sock, &rec);
81 if(!rc) {
82 print_data("recvd", rec.contents.length, rec.contents.data);
83 rec.contents.data[rec.contents.length-1]=0;
84 printf("recvd: %ld, %s\n", rec.contents.length, rec.contents.data);
85 free(rec.contents.data);
86 } else {
87 printf("read failed: %d\n", rc);
88 }
89 }
90
91 close(sock);
92 return NULL;
93 }
94
95 static int create_client_socket(const char *hostname)
96 {
97 int sock;
98 int err;
99
100
101 printf("Create client socket\n");
102 sock = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
103 if(sock<0) {
104 perror("client socket");
105 return sock;
106 }
107
108
109 #if 1
110 err=TLSSocket_Attach(sock);
111 if(err<0) {
112 perror("TLSSocket_Attach (server)");
113 exit(err);
114 }
115 #endif
116
117
118 struct hostent *host;
119 struct sockaddr_in server_addr;
120
121 //host = gethostbyname("kruk.apple.com");
122 //host = gethostbyname("localhost");
123 host= gethostbyname(hostname);
124 if(!host) {
125 herror("host");
126 return -1;
127 }
128 server_addr.sin_family = AF_INET;
129 server_addr.sin_port = htons(23232);
130 server_addr.sin_addr = *((struct in_addr *)host->h_addr);
131 bzero(&(server_addr.sin_zero),8);
132
133 err = connect(sock, (struct sockaddr *)&server_addr,
134 sizeof(struct sockaddr));
135 if(err)
136 {
137 perror("connect");
138 return err;
139 }
140
141 return sock;
142 }
143
144 /* simple test */
145 static int kext_test(const char *hostname, int bypass)
146 {
147 int sock, i;
148 char send_data[1024];
149 int tlsfd;
150 pthread_t server_thread;
151
152 if(strcmp(hostname, "localhost")==0) {
153 pthread_create(&server_thread, NULL, server_thread_func, NULL);
154 // Just wait for the server to be setup
155 sleep(1);
156 }
157
158
159 sock = create_client_socket(hostname);
160
161 if(bypass) {
162 /* Have to open this after we attached the filter to the client socket */
163 tlsfd=open("/dev/tlsnke", O_RDWR);
164 if(tlsfd<0) {
165 perror("open tlsnke");
166 exit(1);
167 }
168 }
169
170
171 for(i=0; i<20;i++) {
172 int n;
173 ssize_t err;
174 n=sprintf(send_data, "Message #%d\n", i);
175 if(n<0) {
176 perror("sprintf");
177 exit(1);
178 }
179
180 printf("Client(1) sending %d bytes (\"%s\")\n", n, send_data);
181
182 if(bypass) {
183 err = write(tlsfd, send_data, n);
184 if(err<0) {
185 perror("write to tlsnke");
186 exit(1);
187 }
188 } else {
189 SSLRecord rec;
190
191 rec.contentType = SSL_RecordTypeAppData;
192 rec.protocolVersion = DTLS_Version_1_0;
193 rec.contents.data = (uint8_t *)send_data;
194 rec.contents.length = n;
195
196 err = TLSSocket_Funcs.write((intptr_t)sock, rec);
197 if(err<0) {
198 perror("write to socket");
199 exit(1);
200 }
201
202 /* serviceWriteQueue every 2 writes, this will trigger rdar://11348395 */
203 if(i&1) {
204 int err;
205 err = TLSSocket_Funcs.serviceWriteQueue((intptr_t)sock);
206 if(err<0) {
207 perror("service write queue");
208 exit(1);
209 }
210 }
211 }
212
213 sleep(1);
214 }
215
216 return 0;
217 }
218
219
220 /* handshake test */
221 int st_test();
222
223 /* echo test */
224 int dtls_client(const char *hostname, int bypass);
225
226 static
227 int usage(const char *argv0)
228 {
229 printf("Usage: %s <test> <hostname> <bypass>\n", argv0);
230 printf(" <test>: type of test: 's'imple, 'h'andshake or 'e'cho] (see below)\n");
231 printf(" <hostname>: hostname of server\n");
232 printf(" <bypass>: use /dev/tlsnke bypass test\n");
233
234 printf("\n 'S'imple test:\n"
235 "\tVery basic test with no handshake. DTLS packets are sent through the socket filter, non encrypted.\n"
236 "\tIf hostname is 'localhost', a local simple server will be created that will also use the tls filter,\n"
237 "\tsuch that the input path is tested.\n"
238 "\tOtherwise, a server on the other side is not required only the output path is tested. If there is no server replying\n"
239 "\tonly the ouput path will be tested. If a server is replying, input packet will be processed but are never read to userspace\n"
240 "\tif bypass=1, also send the same packet through the /dev/tlsnke interface, as if they were coming from utun\n");
241
242 printf("\n 'H'andshake:\n");
243 printf("\tTest SSL Handshake with various ciphers, between a local client going through the tlsnke\n"
244 "\tfilter, and a local server using only the userland SecureTransport.\n"
245 "\thostname and bypass are ignored.\n");
246
247 printf("\n 'E'cho:\n");
248 printf("\tTest to connect to an udp echo server indicated by hostname, on port 23232.\n"
249 "\tSet bypass=1 to use the /dev/tlsnke bsd device to send/recv the app data (emulate utun behaviour)\n");
250
251 printf("\n\tbypass=1 require the tlsnke kext to be compiled with TLS_TEST=1 (not the default in the build)\n");
252
253 return -1;
254 }
255
256 int main (int argc, const char * argv[])
257 {
258
259 printf("argv0=%s argc=%d\n", argv[0], argc);
260 if(argc<2)
261 return usage(argv[0]);
262
263 switch (argv[1][0]) {
264 case 's':
265 case 'S':
266 if(argc<3) return usage(argv[0]);
267 return kext_test(argv[2], atoi(argv[3])?1:0);
268 case 'h':
269 case 'H':
270 return st_test();
271 case 'e':
272 case 'E':
273 if(argc<3) return usage(argv[0]);
274 return dtls_client(argv[2], atoi(argv[3])?1:0);
275 default:
276 return usage(argv[0]);
277 }
278 }
279