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 29static 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 37static 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 95static 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 */ 145static 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 */ 221int st_test(); 222 223/* echo test */ 224int dtls_client(const char *hostname, int bypass); 225 226static 227int 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 256int 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 280