1 /* 2 * rtpw.c 3 * 4 * rtp word sender/receiver 5 * 6 * David A. McGrew 7 * Cisco Systems, Inc. 8 * 9 * This app is a simple RTP application intended only for testing 10 * libsrtp. It reads one word at a time from /usr/dict/words (or 11 * whatever file is specified as DICT_FILE), and sends one word out 12 * each USEC_RATE microseconds. Secure RTP protections can be 13 * applied. See the usage() function for more details. 14 * 15 */ 16 17 /* 18 * 19 * Copyright (c) 2001-2006, Cisco Systems, Inc. 20 * All rights reserved. 21 * 22 * Redistribution and use in source and binary forms, with or without 23 * modification, are permitted provided that the following conditions 24 * are met: 25 * 26 * Redistributions of source code must retain the above copyright 27 * notice, this list of conditions and the following disclaimer. 28 * 29 * Redistributions in binary form must reproduce the above 30 * copyright notice, this list of conditions and the following 31 * disclaimer in the documentation and/or other materials provided 32 * with the distribution. 33 * 34 * Neither the name of the Cisco Systems, Inc. nor the names of its 35 * contributors may be used to endorse or promote products derived 36 * from this software without specific prior written permission. 37 * 38 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 39 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 40 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 41 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE 42 * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, 43 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 44 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 45 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 46 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 47 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 48 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED 49 * OF THE POSSIBILITY OF SUCH DAMAGE. 50 * 51 */ 52 53 54 #include "datatypes.h" 55 #include "getopt_s.h" /* for local getopt() */ 56 57 #include <stdio.h> /* for printf, fprintf */ 58 #include <stdlib.h> /* for atoi() */ 59 #include <errno.h> 60 #include <unistd.h> /* for close() */ 61 62 #include <string.h> /* for strncpy() */ 63 #include <time.h> /* for usleep() */ 64 #ifdef HAVE_SYS_SOCKET_H 65 # include <sys/socket.h> 66 #endif 67 #ifdef HAVE_NETINET_IN_H 68 # include <netinet/in.h> 69 #elif defined HAVE_WINSOCK2_H 70 # include <winsock2.h> 71 # include <ws2tcpip.h> 72 # define RTPW_USE_WINSOCK2 1 73 #endif 74 #ifdef HAVE_ARPA_INET_H 75 # include <arpa/inet.h> 76 #endif 77 78 #include "srtp.h" 79 #include "rtp.h" 80 81 #ifdef RTPW_USE_WINSOCK2 82 # define DICT_FILE "words.txt" 83 #else 84 # define DICT_FILE "/usr/share/dict/words" 85 #endif 86 #define USEC_RATE (5e5) 87 #define MAX_WORD_LEN 128 88 #define ADDR_IS_MULTICAST(a) IN_MULTICAST(htonl(a)) 89 #define MAX_KEY_LEN 64 90 #define MASTER_KEY_LEN 30 91 92 93 #ifndef HAVE_USLEEP 94 # ifdef HAVE_WINDOWS_H 95 # define usleep(us) Sleep((us)/1000) 96 # else 97 # define usleep(us) sleep((us)/1000000) 98 # endif 99 #endif 100 101 102 /* 103 * the function usage() prints an error message describing how this 104 * program should be called, then calls exit() 105 */ 106 107 void 108 usage(char *prog_name); 109 110 /* 111 * leave_group(...) de-registers from a multicast group 112 */ 113 114 void 115 leave_group(int sock, struct ip_mreq mreq, char *name); 116 117 118 /* 119 * program_type distinguishes the [s]rtp sender and receiver cases 120 */ 121 122 typedef enum { sender, receiver, unknown } program_type; 123 124 int 125 main (int argc, char *argv[]) { 126 char *dictfile = DICT_FILE; 127 FILE *dict; 128 char word[MAX_WORD_LEN]; 129 int sock, ret; 130 struct in_addr rcvr_addr; 131 struct sockaddr_in name; 132 struct ip_mreq mreq; 133 #if BEW 134 struct sockaddr_in local; 135 #endif 136 program_type prog_type = unknown; 137 sec_serv_t sec_servs = sec_serv_none; 138 unsigned char ttl = 5; 139 int c; 140 char *input_key = NULL; 141 char *address = NULL; 142 char key[MAX_KEY_LEN]; 143 unsigned short port = 0; 144 rtp_sender_t snd; 145 srtp_policy_t policy; 146 err_status_t status; 147 int len; 148 int do_list_mods = 0; 149 uint32_t ssrc = 0xdeadbeef; /* ssrc value hardcoded for now */ 150 #ifdef RTPW_USE_WINSOCK2 151 WORD wVersionRequested = MAKEWORD(2, 0); 152 WSADATA wsaData; 153 154 ret = WSAStartup(wVersionRequested, &wsaData); 155 if (ret != 0) { 156 fprintf(stderr, "error: WSAStartup() failed: %d\n", ret); 157 exit(1); 158 } 159 #endif 160 161 /* initialize srtp library */ 162 status = srtp_init(); 163 if (status) { 164 printf("error: srtp initialization failed with error code %d\n", status); 165 exit(1); 166 } 167 168 /* check args */ 169 while (1) { 170 c = getopt_s(argc, argv, "k:rsaeld:"); 171 if (c == -1) { 172 break; 173 } 174 switch (c) { 175 case 'k': 176 input_key = optarg_s; 177 break; 178 case 'e': 179 sec_servs |= sec_serv_conf; 180 break; 181 case 'a': 182 sec_servs |= sec_serv_auth; 183 break; 184 case 'r': 185 prog_type = receiver; 186 break; 187 case 's': 188 prog_type = sender; 189 break; 190 case 'd': 191 status = crypto_kernel_set_debug_module(optarg_s, 1); 192 if (status) { 193 printf("error: set debug module (%s) failed\n", optarg_s); 194 exit(1); 195 } 196 break; 197 case 'l': 198 do_list_mods = 1; 199 break; 200 default: 201 usage(argv[0]); 202 } 203 } 204 205 if (prog_type == unknown) { 206 if (do_list_mods) { 207 status = crypto_kernel_list_debug_modules(); 208 if (status) { 209 printf("error: list of debug modules failed\n"); 210 exit(1); 211 } 212 return 0; 213 } else { 214 printf("error: neither sender [-s] nor receiver [-r] specified\n"); 215 usage(argv[0]); 216 } 217 } 218 219 if ((sec_servs && !input_key) || (!sec_servs && input_key)) { 220 /* 221 * a key must be provided if and only if security services have 222 * been requested 223 */ 224 usage(argv[0]); 225 } 226 227 if (argc != optind_s + 2) { 228 /* wrong number of arguments */ 229 usage(argv[0]); 230 } 231 232 /* get address from arg */ 233 address = argv[optind_s++]; 234 235 /* get port from arg */ 236 port = atoi(argv[optind_s++]); 237 238 /* set address */ 239 #ifdef HAVE_INET_ATON 240 if (0 == inet_aton(address, &rcvr_addr)) { 241 fprintf(stderr, "%s: cannot parse IP v4 address %s\n", argv[0], address); 242 exit(1); 243 } 244 if (rcvr_addr.s_addr == INADDR_NONE) { 245 fprintf(stderr, "%s: address error", argv[0]); 246 exit(1); 247 } 248 #else 249 rcvr_addr.s_addr = inet_addr(address); 250 if (0xffffffff == rcvr_addr.s_addr) { 251 fprintf(stderr, "%s: cannot parse IP v4 address %s\n", argv[0], address); 252 exit(1); 253 } 254 #endif 255 256 /* open socket */ 257 sock = socket(PF_INET, SOCK_DGRAM, IPPROTO_UDP); 258 if (sock < 0) { 259 int err; 260 #ifdef RTPW_USE_WINSOCK2 261 err = WSAGetLastError(); 262 #else 263 err = errno; 264 #endif 265 fprintf(stderr, "%s: couldn't open socket: %d\n", argv[0], err); 266 exit(1); 267 } 268 269 name.sin_addr = rcvr_addr; 270 name.sin_family = PF_INET; 271 name.sin_port = htons(port); 272 273 if (ADDR_IS_MULTICAST(rcvr_addr.s_addr)) { 274 if (prog_type == sender) { 275 ret = setsockopt(sock, IPPROTO_IP, IP_MULTICAST_TTL, &ttl, 276 sizeof(ttl)); 277 if (ret < 0) { 278 fprintf(stderr, "%s: Failed to set TTL for multicast group", argv[0]); 279 perror(""); 280 exit(1); 281 } 282 } 283 284 mreq.imr_multiaddr.s_addr = rcvr_addr.s_addr; 285 mreq.imr_interface.s_addr = htonl(INADDR_ANY); 286 ret = setsockopt(sock, IPPROTO_IP, IP_ADD_MEMBERSHIP, (void*)&mreq, 287 sizeof(mreq)); 288 if (ret < 0) { 289 fprintf(stderr, "%s: Failed to join multicast group", argv[0]); 290 perror(""); 291 exit(1); 292 } 293 } 294 295 /* report security services selected on the command line */ 296 printf("security services: "); 297 if (sec_servs & sec_serv_conf) 298 printf("confidentiality "); 299 if (sec_servs & sec_serv_auth) 300 printf("message authentication"); 301 if (sec_servs == sec_serv_none) 302 printf("none"); 303 printf("\n"); 304 305 /* set up the srtp policy and master key */ 306 if (sec_servs) { 307 /* 308 * create policy structure, using the default mechanisms but 309 * with only the security services requested on the command line, 310 * using the right SSRC value 311 */ 312 switch (sec_servs) { 313 case sec_serv_conf_and_auth: 314 crypto_policy_set_rtp_default(&policy.rtp); 315 crypto_policy_set_rtcp_default(&policy.rtcp); 316 break; 317 case sec_serv_conf: 318 crypto_policy_set_aes_cm_128_null_auth(&policy.rtp); 319 crypto_policy_set_rtcp_default(&policy.rtcp); 320 break; 321 case sec_serv_auth: 322 crypto_policy_set_null_cipher_hmac_sha1_80(&policy.rtp); 323 crypto_policy_set_rtcp_default(&policy.rtcp); 324 break; 325 default: 326 printf("error: unknown security service requested\n"); 327 return -1; 328 } 329 policy.ssrc.type = ssrc_specific; 330 policy.ssrc.value = ssrc; 331 policy.key = (uint8_t *) key; 332 policy.next = NULL; 333 policy.window_size = 128; 334 policy.allow_repeat_tx = 0; 335 policy.rtp.sec_serv = sec_servs; 336 policy.rtcp.sec_serv = sec_serv_none; /* we don't do RTCP anyway */ 337 338 /* 339 * read key from hexadecimal on command line into an octet string 340 */ 341 len = hex_string_to_octet_string(key, input_key, MASTER_KEY_LEN*2); 342 343 /* check that hex string is the right length */ 344 if (len < MASTER_KEY_LEN*2) { 345 fprintf(stderr, 346 "error: too few digits in key/salt " 347 "(should be %d hexadecimal digits, found %d)\n", 348 MASTER_KEY_LEN*2, len); 349 exit(1); 350 } 351 if (strlen(input_key) > MASTER_KEY_LEN*2) { 352 fprintf(stderr, 353 "error: too many digits in key/salt " 354 "(should be %d hexadecimal digits, found %u)\n", 355 MASTER_KEY_LEN*2, (unsigned)strlen(input_key)); 356 exit(1); 357 } 358 359 printf("set master key/salt to %s/", octet_string_hex_string(key, 16)); 360 printf("%s\n", octet_string_hex_string(key+16, 14)); 361 362 } else { 363 /* 364 * we're not providing security services, so set the policy to the 365 * null policy 366 * 367 * Note that this policy does not conform to the SRTP 368 * specification, since RTCP authentication is required. However, 369 * the effect of this policy is to turn off SRTP, so that this 370 * application is now a vanilla-flavored RTP application. 371 */ 372 policy.key = (uint8_t *)key; 373 policy.ssrc.type = ssrc_specific; 374 policy.ssrc.value = ssrc; 375 policy.rtp.cipher_type = NULL_CIPHER; 376 policy.rtp.cipher_key_len = 0; 377 policy.rtp.auth_type = NULL_AUTH; 378 policy.rtp.auth_key_len = 0; 379 policy.rtp.auth_tag_len = 0; 380 policy.rtp.sec_serv = sec_serv_none; 381 policy.rtcp.cipher_type = NULL_CIPHER; 382 policy.rtcp.cipher_key_len = 0; 383 policy.rtcp.auth_type = NULL_AUTH; 384 policy.rtcp.auth_key_len = 0; 385 policy.rtcp.auth_tag_len = 0; 386 policy.rtcp.sec_serv = sec_serv_none; 387 policy.window_size = 0; 388 policy.allow_repeat_tx = 0; 389 policy.next = NULL; 390 } 391 392 if (prog_type == sender) { 393 394 #if BEW 395 /* bind to local socket (to match crypto policy, if need be) */ 396 memset(&local, 0, sizeof(struct sockaddr_in)); 397 local.sin_addr.s_addr = htonl(INADDR_ANY); 398 local.sin_port = htons(port); 399 ret = bind(sock, (struct sockaddr *) &local, sizeof(struct sockaddr_in)); 400 if (ret < 0) { 401 fprintf(stderr, "%s: bind failed\n", argv[0]); 402 perror(""); 403 exit(1); 404 } 405 #endif /* BEW */ 406 407 /* initialize sender's rtp and srtp contexts */ 408 snd = rtp_sender_alloc(); 409 if (snd == NULL) { 410 fprintf(stderr, "error: malloc() failed\n"); 411 exit(1); 412 } 413 rtp_sender_init(snd, sock, name, ssrc); 414 status = rtp_sender_init_srtp(snd, &policy); 415 if (status) { 416 fprintf(stderr, 417 "error: srtp_create() failed with code %d\n", 418 status); 419 exit(1); 420 } 421 422 /* open dictionary */ 423 dict = fopen (dictfile, "r"); 424 if (dict == NULL) { 425 fprintf(stderr, "%s: couldn't open file %s\n", argv[0], dictfile); 426 if (ADDR_IS_MULTICAST(rcvr_addr.s_addr)) { 427 leave_group(sock, mreq, argv[0]); 428 } 429 exit(1); 430 } 431 432 /* read words from dictionary, then send them off */ 433 while (fgets(word, MAX_WORD_LEN, dict) != NULL) { 434 len = strlen(word) + 1; /* plus one for null */ 435 436 if (len > MAX_WORD_LEN) 437 printf("error: word %s too large to send\n", word); 438 else { 439 rtp_sendto(snd, word, len); 440 printf("sending word: %s", word); 441 } 442 usleep(USEC_RATE); 443 } 444 445 } else { /* prog_type == receiver */ 446 rtp_receiver_t rcvr; 447 448 if (bind(sock, (struct sockaddr *)&name, sizeof(name)) < 0) { 449 close(sock); 450 fprintf(stderr, "%s: socket bind error\n", argv[0]); 451 perror(NULL); 452 if (ADDR_IS_MULTICAST(rcvr_addr.s_addr)) { 453 leave_group(sock, mreq, argv[0]); 454 } 455 exit(1); 456 } 457 458 rcvr = rtp_receiver_alloc(); 459 if (rcvr == NULL) { 460 fprintf(stderr, "error: malloc() failed\n"); 461 exit(1); 462 } 463 rtp_receiver_init(rcvr, sock, name, ssrc); 464 status = rtp_receiver_init_srtp(rcvr, &policy); 465 if (status) { 466 fprintf(stderr, 467 "error: srtp_create() failed with code %d\n", 468 status); 469 exit(1); 470 } 471 472 /* get next word and loop */ 473 while (1) { 474 len = MAX_WORD_LEN; 475 if (rtp_recvfrom(rcvr, word, &len) > -1) 476 printf("\tword: %s", word); 477 } 478 479 } 480 481 if (ADDR_IS_MULTICAST(rcvr_addr.s_addr)) { 482 leave_group(sock, mreq, argv[0]); 483 } 484 485 #ifdef RTPW_USE_WINSOCK2 486 WSACleanup(); 487 #endif 488 489 return 0; 490 } 491 492 493 void 494 usage(char *string) { 495 496 printf("usage: %s [-d <debug>]* [-k <key> [-a][-e]] " 497 "[-s | -r] dest_ip dest_port\n" 498 "or %s -l\n" 499 "where -a use message authentication\n" 500 " -e use encryption\n" 501 " -k <key> sets the srtp master key\n" 502 " -s act as rtp sender\n" 503 " -r act as rtp receiver\n" 504 " -l list debug modules\n" 505 " -d <debug> turn on debugging for module <debug>\n", 506 string, string); 507 exit(1); 508 509 } 510 511 512 void 513 leave_group(int sock, struct ip_mreq mreq, char *name) { 514 int ret; 515 516 ret = setsockopt(sock, IPPROTO_IP, IP_DROP_MEMBERSHIP, (void*)&mreq, 517 sizeof(mreq)); 518 if (ret < 0) { 519 fprintf(stderr, "%s: Failed to leave multicast group", name); 520 perror(""); 521 } 522 } 523 524