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