1 /* $OpenBSD: misc.c,v 1.72 2009/10/28 16:38:18 reyk Exp $ */ 2 /* 3 * Copyright (c) 2000 Markus Friedl. All rights reserved. 4 * Copyright (c) 2005,2006 Damien Miller. All rights reserved. 5 * 6 * Redistribution and use in source and binary forms, with or without 7 * modification, are permitted provided that the following conditions 8 * are met: 9 * 1. Redistributions of source code must retain the above copyright 10 * notice, this list of conditions and the following disclaimer. 11 * 2. Redistributions in binary form must reproduce the above copyright 12 * notice, this list of conditions and the following disclaimer in the 13 * documentation and/or other materials provided with the distribution. 14 * 15 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 16 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 17 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 18 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 19 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 20 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 21 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 22 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 23 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 24 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 25 */ 26 27 #include <sys/types.h> 28 #include <sys/ioctl.h> 29 #include <sys/socket.h> 30 #include <sys/param.h> 31 32 #include <net/if.h> 33 #include <netinet/in.h> 34 #include <netinet/tcp.h> 35 36 #include <errno.h> 37 #include <fcntl.h> 38 #include <netdb.h> 39 #include <paths.h> 40 #include <pwd.h> 41 #include <stdarg.h> 42 #include <stdio.h> 43 #include <stdlib.h> 44 #include <string.h> 45 #include <unistd.h> 46 47 #include "xmalloc.h" 48 #include "misc.h" 49 #include "log.h" 50 #include "ssh.h" 51 52 /* remove newline at end of string */ 53 char * 54 chop(char *s) 55 { 56 char *t = s; 57 while (*t) { 58 if (*t == '\n' || *t == '\r') { 59 *t = '\0'; 60 return s; 61 } 62 t++; 63 } 64 return s; 65 66 } 67 68 /* set/unset filedescriptor to non-blocking */ 69 int 70 set_nonblock(int fd) 71 { 72 int val; 73 74 val = fcntl(fd, F_GETFL, 0); 75 if (val < 0) { 76 error("fcntl(%d, F_GETFL, 0): %s", fd, strerror(errno)); 77 return (-1); 78 } 79 if (val & O_NONBLOCK) { 80 debug3("fd %d is O_NONBLOCK", fd); 81 return (0); 82 } 83 debug2("fd %d setting O_NONBLOCK", fd); 84 val |= O_NONBLOCK; 85 if (fcntl(fd, F_SETFL, val) == -1) { 86 debug("fcntl(%d, F_SETFL, O_NONBLOCK): %s", fd, 87 strerror(errno)); 88 return (-1); 89 } 90 return (0); 91 } 92 93 int 94 unset_nonblock(int fd) 95 { 96 int val; 97 98 val = fcntl(fd, F_GETFL, 0); 99 if (val < 0) { 100 error("fcntl(%d, F_GETFL, 0): %s", fd, strerror(errno)); 101 return (-1); 102 } 103 if (!(val & O_NONBLOCK)) { 104 debug3("fd %d is not O_NONBLOCK", fd); 105 return (0); 106 } 107 debug("fd %d clearing O_NONBLOCK", fd); 108 val &= ~O_NONBLOCK; 109 if (fcntl(fd, F_SETFL, val) == -1) { 110 debug("fcntl(%d, F_SETFL, ~O_NONBLOCK): %s", 111 fd, strerror(errno)); 112 return (-1); 113 } 114 return (0); 115 } 116 117 const char * 118 ssh_gai_strerror(int gaierr) 119 { 120 if (gaierr == EAI_SYSTEM) 121 return strerror(errno); 122 return gai_strerror(gaierr); 123 } 124 125 /* disable nagle on socket */ 126 void 127 set_nodelay(int fd) 128 { 129 int opt; 130 socklen_t optlen; 131 132 optlen = sizeof opt; 133 if (getsockopt(fd, IPPROTO_TCP, TCP_NODELAY, &opt, &optlen) == -1) { 134 debug("getsockopt TCP_NODELAY: %.100s", strerror(errno)); 135 return; 136 } 137 if (opt == 1) { 138 debug2("fd %d is TCP_NODELAY", fd); 139 return; 140 } 141 opt = 1; 142 debug2("fd %d setting TCP_NODELAY", fd); 143 if (setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, &opt, sizeof opt) == -1) 144 error("setsockopt TCP_NODELAY: %.100s", strerror(errno)); 145 } 146 147 /* open a socket in the specified routing domain */ 148 int 149 socket_rdomain(int domain, int type, int protocol, int rdomain) 150 { 151 int sock, ipproto = IPPROTO_IP; 152 153 if ((sock = socket(domain, type, protocol)) == -1) 154 return (-1); 155 156 if (rdomain == -1) 157 return (sock); 158 159 switch (domain) { 160 case AF_INET6: 161 ipproto = IPPROTO_IPV6; 162 /* FALLTHROUGH */ 163 case AF_INET: 164 debug2("socket %d af %d setting rdomain %d", 165 sock, domain, rdomain); 166 if (setsockopt(sock, ipproto, SO_RDOMAIN, &rdomain, 167 sizeof(rdomain)) == -1) { 168 debug("setsockopt SO_RDOMAIN: %.100s", 169 strerror(errno)); 170 close(sock); 171 return (-1); 172 } 173 break; 174 default: 175 debug("socket %d af %d does not support rdomain %d", 176 sock, domain, rdomain); 177 close(sock); 178 return (-1); 179 } 180 181 return (sock); 182 } 183 184 /* Characters considered whitespace in strsep calls. */ 185 #define WHITESPACE " \t\r\n" 186 #define QUOTE "\"" 187 188 /* return next token in configuration line */ 189 char * 190 strdelim(char **s) 191 { 192 char *old; 193 int wspace = 0; 194 195 if (*s == NULL) 196 return NULL; 197 198 old = *s; 199 200 *s = strpbrk(*s, WHITESPACE QUOTE "="); 201 if (*s == NULL) 202 return (old); 203 204 if (*s[0] == '\"') { 205 memmove(*s, *s + 1, strlen(*s)); /* move nul too */ 206 /* Find matching quote */ 207 if ((*s = strpbrk(*s, QUOTE)) == NULL) { 208 return (NULL); /* no matching quote */ 209 } else { 210 *s[0] = '\0'; 211 return (old); 212 } 213 } 214 215 /* Allow only one '=' to be skipped */ 216 if (*s[0] == '=') 217 wspace = 1; 218 *s[0] = '\0'; 219 220 /* Skip any extra whitespace after first token */ 221 *s += strspn(*s + 1, WHITESPACE) + 1; 222 if (*s[0] == '=' && !wspace) 223 *s += strspn(*s + 1, WHITESPACE) + 1; 224 225 return (old); 226 } 227 228 struct passwd * 229 pwcopy(struct passwd *pw) 230 { 231 struct passwd *copy = xcalloc(1, sizeof(*copy)); 232 233 copy->pw_name = xstrdup(pw->pw_name); 234 copy->pw_passwd = xstrdup(pw->pw_passwd); 235 copy->pw_gecos = xstrdup(pw->pw_gecos); 236 copy->pw_uid = pw->pw_uid; 237 copy->pw_gid = pw->pw_gid; 238 copy->pw_expire = pw->pw_expire; 239 copy->pw_change = pw->pw_change; 240 copy->pw_class = xstrdup(pw->pw_class); 241 copy->pw_dir = xstrdup(pw->pw_dir); 242 copy->pw_shell = xstrdup(pw->pw_shell); 243 return copy; 244 } 245 246 /* 247 * Convert ASCII string to TCP/IP port number. 248 * Port must be >=0 and <=65535. 249 * Return -1 if invalid. 250 */ 251 int 252 a2port(const char *s) 253 { 254 long long port; 255 const char *errstr; 256 257 port = strtonum(s, 0, 65535, &errstr); 258 if (errstr != NULL) 259 return -1; 260 return (int)port; 261 } 262 263 int 264 a2tun(const char *s, int *remote) 265 { 266 const char *errstr = NULL; 267 char *sp, *ep; 268 int tun; 269 270 if (remote != NULL) { 271 *remote = SSH_TUNID_ANY; 272 sp = xstrdup(s); 273 if ((ep = strchr(sp, ':')) == NULL) { 274 xfree(sp); 275 return (a2tun(s, NULL)); 276 } 277 ep[0] = '\0'; ep++; 278 *remote = a2tun(ep, NULL); 279 tun = a2tun(sp, NULL); 280 xfree(sp); 281 return (*remote == SSH_TUNID_ERR ? *remote : tun); 282 } 283 284 if (strcasecmp(s, "any") == 0) 285 return (SSH_TUNID_ANY); 286 287 tun = strtonum(s, 0, SSH_TUNID_MAX, &errstr); 288 if (errstr != NULL) 289 return (SSH_TUNID_ERR); 290 291 return (tun); 292 } 293 294 #define SECONDS 1 295 #define MINUTES (SECONDS * 60) 296 #define HOURS (MINUTES * 60) 297 #define DAYS (HOURS * 24) 298 #define WEEKS (DAYS * 7) 299 300 /* 301 * Convert a time string into seconds; format is 302 * a sequence of: 303 * time[qualifier] 304 * 305 * Valid time qualifiers are: 306 * <none> seconds 307 * s|S seconds 308 * m|M minutes 309 * h|H hours 310 * d|D days 311 * w|W weeks 312 * 313 * Examples: 314 * 90m 90 minutes 315 * 1h30m 90 minutes 316 * 2d 2 days 317 * 1w 1 week 318 * 319 * Return -1 if time string is invalid. 320 */ 321 long 322 convtime(const char *s) 323 { 324 long total, secs; 325 const char *p; 326 char *endp; 327 328 errno = 0; 329 total = 0; 330 p = s; 331 332 if (p == NULL || *p == '\0') 333 return -1; 334 335 while (*p) { 336 secs = strtol(p, &endp, 10); 337 if (p == endp || 338 (errno == ERANGE && (secs == LONG_MIN || secs == LONG_MAX)) || 339 secs < 0) 340 return -1; 341 342 switch (*endp++) { 343 case '\0': 344 endp--; 345 break; 346 case 's': 347 case 'S': 348 break; 349 case 'm': 350 case 'M': 351 secs *= MINUTES; 352 break; 353 case 'h': 354 case 'H': 355 secs *= HOURS; 356 break; 357 case 'd': 358 case 'D': 359 secs *= DAYS; 360 break; 361 case 'w': 362 case 'W': 363 secs *= WEEKS; 364 break; 365 default: 366 return -1; 367 } 368 total += secs; 369 if (total < 0) 370 return -1; 371 p = endp; 372 } 373 374 return total; 375 } 376 377 /* 378 * Returns a standardized host+port identifier string. 379 * Caller must free returned string. 380 */ 381 char * 382 put_host_port(const char *host, u_short port) 383 { 384 char *hoststr; 385 386 if (port == 0 || port == SSH_DEFAULT_PORT) 387 return(xstrdup(host)); 388 if (asprintf(&hoststr, "[%s]:%d", host, (int)port) < 0) 389 fatal("put_host_port: asprintf: %s", strerror(errno)); 390 debug3("put_host_port: %s", hoststr); 391 return hoststr; 392 } 393 394 /* 395 * Search for next delimiter between hostnames/addresses and ports. 396 * Argument may be modified (for termination). 397 * Returns *cp if parsing succeeds. 398 * *cp is set to the start of the next delimiter, if one was found. 399 * If this is the last field, *cp is set to NULL. 400 */ 401 char * 402 hpdelim(char **cp) 403 { 404 char *s, *old; 405 406 if (cp == NULL || *cp == NULL) 407 return NULL; 408 409 old = s = *cp; 410 if (*s == '[') { 411 if ((s = strchr(s, ']')) == NULL) 412 return NULL; 413 else 414 s++; 415 } else if ((s = strpbrk(s, ":/")) == NULL) 416 s = *cp + strlen(*cp); /* skip to end (see first case below) */ 417 418 switch (*s) { 419 case '\0': 420 *cp = NULL; /* no more fields*/ 421 break; 422 423 case ':': 424 case '/': 425 *s = '\0'; /* terminate */ 426 *cp = s + 1; 427 break; 428 429 default: 430 return NULL; 431 } 432 433 return old; 434 } 435 436 char * 437 cleanhostname(char *host) 438 { 439 if (*host == '[' && host[strlen(host) - 1] == ']') { 440 host[strlen(host) - 1] = '\0'; 441 return (host + 1); 442 } else 443 return host; 444 } 445 446 char * 447 colon(char *cp) 448 { 449 int flag = 0; 450 451 if (*cp == ':') /* Leading colon is part of file name. */ 452 return (0); 453 if (*cp == '[') 454 flag = 1; 455 456 for (; *cp; ++cp) { 457 if (*cp == '@' && *(cp+1) == '[') 458 flag = 1; 459 if (*cp == ']' && *(cp+1) == ':' && flag) 460 return (cp+1); 461 if (*cp == ':' && !flag) 462 return (cp); 463 if (*cp == '/') 464 return (0); 465 } 466 return (0); 467 } 468 469 /* function to assist building execv() arguments */ 470 void 471 addargs(arglist *args, char *fmt, ...) 472 { 473 va_list ap; 474 char *cp; 475 u_int nalloc; 476 int r; 477 478 va_start(ap, fmt); 479 r = vasprintf(&cp, fmt, ap); 480 va_end(ap); 481 if (r == -1) 482 fatal("addargs: argument too long"); 483 484 nalloc = args->nalloc; 485 if (args->list == NULL) { 486 nalloc = 32; 487 args->num = 0; 488 } else if (args->num+2 >= nalloc) 489 nalloc *= 2; 490 491 args->list = xrealloc(args->list, nalloc, sizeof(char *)); 492 args->nalloc = nalloc; 493 args->list[args->num++] = cp; 494 args->list[args->num] = NULL; 495 } 496 497 void 498 replacearg(arglist *args, u_int which, char *fmt, ...) 499 { 500 va_list ap; 501 char *cp; 502 int r; 503 504 va_start(ap, fmt); 505 r = vasprintf(&cp, fmt, ap); 506 va_end(ap); 507 if (r == -1) 508 fatal("replacearg: argument too long"); 509 510 if (which >= args->num) 511 fatal("replacearg: tried to replace invalid arg %d >= %d", 512 which, args->num); 513 xfree(args->list[which]); 514 args->list[which] = cp; 515 } 516 517 void 518 freeargs(arglist *args) 519 { 520 u_int i; 521 522 if (args->list != NULL) { 523 for (i = 0; i < args->num; i++) 524 xfree(args->list[i]); 525 xfree(args->list); 526 args->nalloc = args->num = 0; 527 args->list = NULL; 528 } 529 } 530 531 /* 532 * Expands tildes in the file name. Returns data allocated by xmalloc. 533 * Warning: this calls getpw*. 534 */ 535 char * 536 tilde_expand_filename(const char *filename, uid_t uid) 537 { 538 const char *path; 539 char user[128], ret[MAXPATHLEN]; 540 struct passwd *pw; 541 u_int len, slash; 542 543 if (*filename != '~') 544 return (xstrdup(filename)); 545 filename++; 546 547 path = strchr(filename, '/'); 548 if (path != NULL && path > filename) { /* ~user/path */ 549 slash = path - filename; 550 if (slash > sizeof(user) - 1) 551 fatal("tilde_expand_filename: ~username too long"); 552 memcpy(user, filename, slash); 553 user[slash] = '\0'; 554 if ((pw = getpwnam(user)) == NULL) 555 fatal("tilde_expand_filename: No such user %s", user); 556 } else if ((pw = getpwuid(uid)) == NULL) /* ~/path */ 557 fatal("tilde_expand_filename: No such uid %ld", (long)uid); 558 559 if (strlcpy(ret, pw->pw_dir, sizeof(ret)) >= sizeof(ret)) 560 fatal("tilde_expand_filename: Path too long"); 561 562 /* Make sure directory has a trailing '/' */ 563 len = strlen(pw->pw_dir); 564 if ((len == 0 || pw->pw_dir[len - 1] != '/') && 565 strlcat(ret, "/", sizeof(ret)) >= sizeof(ret)) 566 fatal("tilde_expand_filename: Path too long"); 567 568 /* Skip leading '/' from specified path */ 569 if (path != NULL) 570 filename = path + 1; 571 if (strlcat(ret, filename, sizeof(ret)) >= sizeof(ret)) 572 fatal("tilde_expand_filename: Path too long"); 573 574 return (xstrdup(ret)); 575 } 576 577 /* 578 * Expand a string with a set of %[char] escapes. A number of escapes may be 579 * specified as (char *escape_chars, char *replacement) pairs. The list must 580 * be terminated by a NULL escape_char. Returns replaced string in memory 581 * allocated by xmalloc. 582 */ 583 char * 584 percent_expand(const char *string, ...) 585 { 586 #define EXPAND_MAX_KEYS 16 587 struct { 588 const char *key; 589 const char *repl; 590 } keys[EXPAND_MAX_KEYS]; 591 u_int num_keys, i, j; 592 char buf[4096]; 593 va_list ap; 594 595 /* Gather keys */ 596 va_start(ap, string); 597 for (num_keys = 0; num_keys < EXPAND_MAX_KEYS; num_keys++) { 598 keys[num_keys].key = va_arg(ap, char *); 599 if (keys[num_keys].key == NULL) 600 break; 601 keys[num_keys].repl = va_arg(ap, char *); 602 if (keys[num_keys].repl == NULL) 603 fatal("percent_expand: NULL replacement"); 604 } 605 va_end(ap); 606 607 if (num_keys >= EXPAND_MAX_KEYS) 608 fatal("percent_expand: too many keys"); 609 610 /* Expand string */ 611 *buf = '\0'; 612 for (i = 0; *string != '\0'; string++) { 613 if (*string != '%') { 614 append: 615 buf[i++] = *string; 616 if (i >= sizeof(buf)) 617 fatal("percent_expand: string too long"); 618 buf[i] = '\0'; 619 continue; 620 } 621 string++; 622 if (*string == '%') 623 goto append; 624 for (j = 0; j < num_keys; j++) { 625 if (strchr(keys[j].key, *string) != NULL) { 626 i = strlcat(buf, keys[j].repl, sizeof(buf)); 627 if (i >= sizeof(buf)) 628 fatal("percent_expand: string too long"); 629 break; 630 } 631 } 632 if (j >= num_keys) 633 fatal("percent_expand: unknown key %%%c", *string); 634 } 635 return (xstrdup(buf)); 636 #undef EXPAND_MAX_KEYS 637 } 638 639 /* 640 * Read an entire line from a public key file into a static buffer, discarding 641 * lines that exceed the buffer size. Returns 0 on success, -1 on failure. 642 */ 643 int 644 read_keyfile_line(FILE *f, const char *filename, char *buf, size_t bufsz, 645 u_long *lineno) 646 { 647 while (fgets(buf, bufsz, f) != NULL) { 648 if (buf[0] == '\0') 649 continue; 650 (*lineno)++; 651 if (buf[strlen(buf) - 1] == '\n' || feof(f)) { 652 return 0; 653 } else { 654 debug("%s: %s line %lu exceeds size limit", __func__, 655 filename, *lineno); 656 /* discard remainder of line */ 657 while (fgetc(f) != '\n' && !feof(f)) 658 ; /* nothing */ 659 } 660 } 661 return -1; 662 } 663 664 int 665 tun_open(int tun, int mode) 666 { 667 struct ifreq ifr; 668 char name[100]; 669 int fd = -1, sock; 670 671 /* Open the tunnel device */ 672 if (tun <= SSH_TUNID_MAX) { 673 snprintf(name, sizeof(name), "/dev/tun%d", tun); 674 fd = open(name, O_RDWR); 675 } else if (tun == SSH_TUNID_ANY) { 676 for (tun = 100; tun >= 0; tun--) { 677 snprintf(name, sizeof(name), "/dev/tun%d", tun); 678 if ((fd = open(name, O_RDWR)) >= 0) 679 break; 680 } 681 } else { 682 debug("%s: invalid tunnel %u", __func__, tun); 683 return (-1); 684 } 685 686 if (fd < 0) { 687 debug("%s: %s open failed: %s", __func__, name, strerror(errno)); 688 return (-1); 689 } 690 691 debug("%s: %s mode %d fd %d", __func__, name, mode, fd); 692 693 /* Set the tunnel device operation mode */ 694 snprintf(ifr.ifr_name, sizeof(ifr.ifr_name), "tun%d", tun); 695 if ((sock = socket(PF_UNIX, SOCK_STREAM, 0)) == -1) 696 goto failed; 697 698 if (ioctl(sock, SIOCGIFFLAGS, &ifr) == -1) 699 goto failed; 700 701 /* Set interface mode */ 702 ifr.ifr_flags &= ~IFF_UP; 703 if (mode == SSH_TUNMODE_ETHERNET) 704 ifr.ifr_flags |= IFF_LINK0; 705 else 706 ifr.ifr_flags &= ~IFF_LINK0; 707 if (ioctl(sock, SIOCSIFFLAGS, &ifr) == -1) 708 goto failed; 709 710 /* Bring interface up */ 711 ifr.ifr_flags |= IFF_UP; 712 if (ioctl(sock, SIOCSIFFLAGS, &ifr) == -1) 713 goto failed; 714 715 close(sock); 716 return (fd); 717 718 failed: 719 if (fd >= 0) 720 close(fd); 721 if (sock >= 0) 722 close(sock); 723 debug("%s: failed to set %s mode %d: %s", __func__, name, 724 mode, strerror(errno)); 725 return (-1); 726 } 727 728 void 729 sanitise_stdfd(void) 730 { 731 int nullfd, dupfd; 732 733 if ((nullfd = dupfd = open(_PATH_DEVNULL, O_RDWR)) == -1) { 734 fprintf(stderr, "Couldn't open /dev/null: %s\n", 735 strerror(errno)); 736 exit(1); 737 } 738 while (++dupfd <= 2) { 739 /* Only clobber closed fds */ 740 if (fcntl(dupfd, F_GETFL, 0) >= 0) 741 continue; 742 if (dup2(nullfd, dupfd) == -1) { 743 fprintf(stderr, "dup2: %s\n", strerror(errno)); 744 exit(1); 745 } 746 } 747 if (nullfd > 2) 748 close(nullfd); 749 } 750 751 char * 752 tohex(const void *vp, size_t l) 753 { 754 const u_char *p = (const u_char *)vp; 755 char b[3], *r; 756 size_t i, hl; 757 758 if (l > 65536) 759 return xstrdup("tohex: length > 65536"); 760 761 hl = l * 2 + 1; 762 r = xcalloc(1, hl); 763 for (i = 0; i < l; i++) { 764 snprintf(b, sizeof(b), "%02x", p[i]); 765 strlcat(r, b, hl); 766 } 767 return (r); 768 } 769 770 u_int64_t 771 get_u64(const void *vp) 772 { 773 const u_char *p = (const u_char *)vp; 774 u_int64_t v; 775 776 v = (u_int64_t)p[0] << 56; 777 v |= (u_int64_t)p[1] << 48; 778 v |= (u_int64_t)p[2] << 40; 779 v |= (u_int64_t)p[3] << 32; 780 v |= (u_int64_t)p[4] << 24; 781 v |= (u_int64_t)p[5] << 16; 782 v |= (u_int64_t)p[6] << 8; 783 v |= (u_int64_t)p[7]; 784 785 return (v); 786 } 787 788 u_int32_t 789 get_u32(const void *vp) 790 { 791 const u_char *p = (const u_char *)vp; 792 u_int32_t v; 793 794 v = (u_int32_t)p[0] << 24; 795 v |= (u_int32_t)p[1] << 16; 796 v |= (u_int32_t)p[2] << 8; 797 v |= (u_int32_t)p[3]; 798 799 return (v); 800 } 801 802 u_int16_t 803 get_u16(const void *vp) 804 { 805 const u_char *p = (const u_char *)vp; 806 u_int16_t v; 807 808 v = (u_int16_t)p[0] << 8; 809 v |= (u_int16_t)p[1]; 810 811 return (v); 812 } 813 814 void 815 put_u64(void *vp, u_int64_t v) 816 { 817 u_char *p = (u_char *)vp; 818 819 p[0] = (u_char)(v >> 56) & 0xff; 820 p[1] = (u_char)(v >> 48) & 0xff; 821 p[2] = (u_char)(v >> 40) & 0xff; 822 p[3] = (u_char)(v >> 32) & 0xff; 823 p[4] = (u_char)(v >> 24) & 0xff; 824 p[5] = (u_char)(v >> 16) & 0xff; 825 p[6] = (u_char)(v >> 8) & 0xff; 826 p[7] = (u_char)v & 0xff; 827 } 828 829 void 830 put_u32(void *vp, u_int32_t v) 831 { 832 u_char *p = (u_char *)vp; 833 834 p[0] = (u_char)(v >> 24) & 0xff; 835 p[1] = (u_char)(v >> 16) & 0xff; 836 p[2] = (u_char)(v >> 8) & 0xff; 837 p[3] = (u_char)v & 0xff; 838 } 839 840 841 void 842 put_u16(void *vp, u_int16_t v) 843 { 844 u_char *p = (u_char *)vp; 845 846 p[0] = (u_char)(v >> 8) & 0xff; 847 p[1] = (u_char)v & 0xff; 848 } 849 850 void 851 ms_subtract_diff(struct timeval *start, int *ms) 852 { 853 struct timeval diff, finish; 854 855 gettimeofday(&finish, NULL); 856 timersub(&finish, start, &diff); 857 *ms -= (diff.tv_sec * 1000) + (diff.tv_usec / 1000); 858 } 859 860 void 861 ms_to_timeval(struct timeval *tv, int ms) 862 { 863 if (ms < 0) 864 ms = 0; 865 tv->tv_sec = ms / 1000; 866 tv->tv_usec = (ms % 1000) * 1000; 867 } 868 869