Annotation of src/crypto/external/bsd/openssh/dist/misc.c, Revision 1.1.1.6
1.1.1.6 ! christos 1: /* $OpenBSD: misc.c,v 1.91 2013/07/12 00:43:50 djm Exp $ */
1.1 christos 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>
1.1.1.3 christos 34: #include <netinet/in_systm.h>
35: #include <netinet/ip.h>
1.1 christos 36: #include <netinet/tcp.h>
37:
38: #include <errno.h>
39: #include <fcntl.h>
40: #include <netdb.h>
41: #include <paths.h>
42: #include <pwd.h>
43: #include <stdarg.h>
44: #include <stdio.h>
45: #include <stdlib.h>
46: #include <string.h>
47: #include <unistd.h>
48:
49: #include "xmalloc.h"
50: #include "misc.h"
51: #include "log.h"
52: #include "ssh.h"
53:
54: /* remove newline at end of string */
55: char *
56: chop(char *s)
57: {
58: char *t = s;
59: while (*t) {
60: if (*t == '\n' || *t == '\r') {
61: *t = '\0';
62: return s;
63: }
64: t++;
65: }
66: return s;
67:
68: }
69:
70: /* set/unset filedescriptor to non-blocking */
71: int
72: set_nonblock(int fd)
73: {
74: int val;
75:
76: val = fcntl(fd, F_GETFL, 0);
77: if (val < 0) {
78: error("fcntl(%d, F_GETFL, 0): %s", fd, strerror(errno));
79: return (-1);
80: }
81: if (val & O_NONBLOCK) {
82: debug3("fd %d is O_NONBLOCK", fd);
83: return (0);
84: }
85: debug2("fd %d setting O_NONBLOCK", fd);
86: val |= O_NONBLOCK;
87: if (fcntl(fd, F_SETFL, val) == -1) {
88: debug("fcntl(%d, F_SETFL, O_NONBLOCK): %s", fd,
89: strerror(errno));
90: return (-1);
91: }
92: return (0);
93: }
94:
95: int
96: unset_nonblock(int fd)
97: {
98: int val;
99:
100: val = fcntl(fd, F_GETFL, 0);
101: if (val < 0) {
102: error("fcntl(%d, F_GETFL, 0): %s", fd, strerror(errno));
103: return (-1);
104: }
105: if (!(val & O_NONBLOCK)) {
106: debug3("fd %d is not O_NONBLOCK", fd);
107: return (0);
108: }
109: debug("fd %d clearing O_NONBLOCK", fd);
110: val &= ~O_NONBLOCK;
111: if (fcntl(fd, F_SETFL, val) == -1) {
112: debug("fcntl(%d, F_SETFL, ~O_NONBLOCK): %s",
113: fd, strerror(errno));
114: return (-1);
115: }
116: return (0);
117: }
118:
119: const char *
120: ssh_gai_strerror(int gaierr)
121: {
1.1.1.6 ! christos 122: if (gaierr == EAI_SYSTEM && errno != 0)
1.1 christos 123: return strerror(errno);
124: return gai_strerror(gaierr);
125: }
126:
127: /* disable nagle on socket */
128: void
129: set_nodelay(int fd)
130: {
131: int opt;
132: socklen_t optlen;
133:
134: optlen = sizeof opt;
135: if (getsockopt(fd, IPPROTO_TCP, TCP_NODELAY, &opt, &optlen) == -1) {
136: debug("getsockopt TCP_NODELAY: %.100s", strerror(errno));
137: return;
138: }
139: if (opt == 1) {
140: debug2("fd %d is TCP_NODELAY", fd);
141: return;
142: }
143: opt = 1;
144: debug2("fd %d setting TCP_NODELAY", fd);
145: if (setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, &opt, sizeof opt) == -1)
146: error("setsockopt TCP_NODELAY: %.100s", strerror(errno));
147: }
148:
149: /* Characters considered whitespace in strsep calls. */
150: #define WHITESPACE " \t\r\n"
151: #define QUOTE "\""
152:
153: /* return next token in configuration line */
154: char *
155: strdelim(char **s)
156: {
157: char *old;
158: int wspace = 0;
159:
160: if (*s == NULL)
161: return NULL;
162:
163: old = *s;
164:
165: *s = strpbrk(*s, WHITESPACE QUOTE "=");
166: if (*s == NULL)
167: return (old);
168:
169: if (*s[0] == '\"') {
170: memmove(*s, *s + 1, strlen(*s)); /* move nul too */
171: /* Find matching quote */
172: if ((*s = strpbrk(*s, QUOTE)) == NULL) {
173: return (NULL); /* no matching quote */
174: } else {
175: *s[0] = '\0';
1.1.1.2 adam 176: *s += strspn(*s + 1, WHITESPACE) + 1;
1.1 christos 177: return (old);
178: }
179: }
180:
181: /* Allow only one '=' to be skipped */
182: if (*s[0] == '=')
183: wspace = 1;
184: *s[0] = '\0';
185:
186: /* Skip any extra whitespace after first token */
187: *s += strspn(*s + 1, WHITESPACE) + 1;
188: if (*s[0] == '=' && !wspace)
189: *s += strspn(*s + 1, WHITESPACE) + 1;
190:
191: return (old);
192: }
193:
194: struct passwd *
195: pwcopy(struct passwd *pw)
196: {
197: struct passwd *copy = xcalloc(1, sizeof(*copy));
198:
199: copy->pw_name = xstrdup(pw->pw_name);
200: copy->pw_passwd = xstrdup(pw->pw_passwd);
201: copy->pw_gecos = xstrdup(pw->pw_gecos);
202: copy->pw_uid = pw->pw_uid;
203: copy->pw_gid = pw->pw_gid;
204: copy->pw_expire = pw->pw_expire;
205: copy->pw_change = pw->pw_change;
206: copy->pw_class = xstrdup(pw->pw_class);
207: copy->pw_dir = xstrdup(pw->pw_dir);
208: copy->pw_shell = xstrdup(pw->pw_shell);
209: return copy;
210: }
211:
212: /*
213: * Convert ASCII string to TCP/IP port number.
214: * Port must be >=0 and <=65535.
215: * Return -1 if invalid.
216: */
217: int
218: a2port(const char *s)
219: {
220: long long port;
221: const char *errstr;
222:
223: port = strtonum(s, 0, 65535, &errstr);
224: if (errstr != NULL)
225: return -1;
226: return (int)port;
227: }
228:
229: int
230: a2tun(const char *s, int *remote)
231: {
232: const char *errstr = NULL;
233: char *sp, *ep;
234: int tun;
235:
236: if (remote != NULL) {
237: *remote = SSH_TUNID_ANY;
238: sp = xstrdup(s);
239: if ((ep = strchr(sp, ':')) == NULL) {
1.1.1.6 ! christos 240: free(sp);
1.1 christos 241: return (a2tun(s, NULL));
242: }
243: ep[0] = '\0'; ep++;
244: *remote = a2tun(ep, NULL);
245: tun = a2tun(sp, NULL);
1.1.1.6 ! christos 246: free(sp);
1.1 christos 247: return (*remote == SSH_TUNID_ERR ? *remote : tun);
248: }
249:
250: if (strcasecmp(s, "any") == 0)
251: return (SSH_TUNID_ANY);
252:
253: tun = strtonum(s, 0, SSH_TUNID_MAX, &errstr);
254: if (errstr != NULL)
255: return (SSH_TUNID_ERR);
256:
257: return (tun);
258: }
259:
260: #define SECONDS 1
261: #define MINUTES (SECONDS * 60)
262: #define HOURS (MINUTES * 60)
263: #define DAYS (HOURS * 24)
264: #define WEEKS (DAYS * 7)
265:
266: /*
267: * Convert a time string into seconds; format is
268: * a sequence of:
269: * time[qualifier]
270: *
271: * Valid time qualifiers are:
272: * <none> seconds
273: * s|S seconds
274: * m|M minutes
275: * h|H hours
276: * d|D days
277: * w|W weeks
278: *
279: * Examples:
280: * 90m 90 minutes
281: * 1h30m 90 minutes
282: * 2d 2 days
283: * 1w 1 week
284: *
285: * Return -1 if time string is invalid.
286: */
287: long
288: convtime(const char *s)
289: {
290: long total, secs;
291: const char *p;
292: char *endp;
293:
294: errno = 0;
295: total = 0;
296: p = s;
297:
298: if (p == NULL || *p == '\0')
299: return -1;
300:
301: while (*p) {
302: secs = strtol(p, &endp, 10);
303: if (p == endp ||
304: (errno == ERANGE && (secs == LONG_MIN || secs == LONG_MAX)) ||
305: secs < 0)
306: return -1;
307:
308: switch (*endp++) {
309: case '\0':
310: endp--;
311: break;
312: case 's':
313: case 'S':
314: break;
315: case 'm':
316: case 'M':
317: secs *= MINUTES;
318: break;
319: case 'h':
320: case 'H':
321: secs *= HOURS;
322: break;
323: case 'd':
324: case 'D':
325: secs *= DAYS;
326: break;
327: case 'w':
328: case 'W':
329: secs *= WEEKS;
330: break;
331: default:
332: return -1;
333: }
334: total += secs;
335: if (total < 0)
336: return -1;
337: p = endp;
338: }
339:
340: return total;
341: }
342:
343: /*
344: * Returns a standardized host+port identifier string.
345: * Caller must free returned string.
346: */
347: char *
348: put_host_port(const char *host, u_short port)
349: {
350: char *hoststr;
351:
352: if (port == 0 || port == SSH_DEFAULT_PORT)
353: return(xstrdup(host));
354: if (asprintf(&hoststr, "[%s]:%d", host, (int)port) < 0)
355: fatal("put_host_port: asprintf: %s", strerror(errno));
356: debug3("put_host_port: %s", hoststr);
357: return hoststr;
358: }
359:
360: /*
361: * Search for next delimiter between hostnames/addresses and ports.
362: * Argument may be modified (for termination).
363: * Returns *cp if parsing succeeds.
364: * *cp is set to the start of the next delimiter, if one was found.
365: * If this is the last field, *cp is set to NULL.
366: */
367: char *
368: hpdelim(char **cp)
369: {
370: char *s, *old;
371:
372: if (cp == NULL || *cp == NULL)
373: return NULL;
374:
375: old = s = *cp;
376: if (*s == '[') {
377: if ((s = strchr(s, ']')) == NULL)
378: return NULL;
379: else
380: s++;
381: } else if ((s = strpbrk(s, ":/")) == NULL)
382: s = *cp + strlen(*cp); /* skip to end (see first case below) */
383:
384: switch (*s) {
385: case '\0':
386: *cp = NULL; /* no more fields*/
387: break;
388:
389: case ':':
390: case '/':
391: *s = '\0'; /* terminate */
392: *cp = s + 1;
393: break;
394:
395: default:
396: return NULL;
397: }
398:
399: return old;
400: }
401:
402: char *
403: cleanhostname(char *host)
404: {
405: if (*host == '[' && host[strlen(host) - 1] == ']') {
406: host[strlen(host) - 1] = '\0';
407: return (host + 1);
408: } else
409: return host;
410: }
411:
412: char *
413: colon(char *cp)
414: {
415: int flag = 0;
416:
417: if (*cp == ':') /* Leading colon is part of file name. */
1.1.1.2 adam 418: return NULL;
1.1 christos 419: if (*cp == '[')
420: flag = 1;
421:
422: for (; *cp; ++cp) {
423: if (*cp == '@' && *(cp+1) == '[')
424: flag = 1;
425: if (*cp == ']' && *(cp+1) == ':' && flag)
426: return (cp+1);
427: if (*cp == ':' && !flag)
428: return (cp);
429: if (*cp == '/')
1.1.1.2 adam 430: return NULL;
1.1 christos 431: }
1.1.1.2 adam 432: return NULL;
1.1 christos 433: }
434:
435: /* function to assist building execv() arguments */
436: void
437: addargs(arglist *args, char *fmt, ...)
438: {
439: va_list ap;
440: char *cp;
441: u_int nalloc;
442: int r;
443:
444: va_start(ap, fmt);
445: r = vasprintf(&cp, fmt, ap);
446: va_end(ap);
447: if (r == -1)
448: fatal("addargs: argument too long");
449:
450: nalloc = args->nalloc;
451: if (args->list == NULL) {
452: nalloc = 32;
453: args->num = 0;
454: } else if (args->num+2 >= nalloc)
455: nalloc *= 2;
456:
457: args->list = xrealloc(args->list, nalloc, sizeof(char *));
458: args->nalloc = nalloc;
459: args->list[args->num++] = cp;
460: args->list[args->num] = NULL;
461: }
462:
463: void
464: replacearg(arglist *args, u_int which, char *fmt, ...)
465: {
466: va_list ap;
467: char *cp;
468: int r;
469:
470: va_start(ap, fmt);
471: r = vasprintf(&cp, fmt, ap);
472: va_end(ap);
473: if (r == -1)
474: fatal("replacearg: argument too long");
475:
476: if (which >= args->num)
477: fatal("replacearg: tried to replace invalid arg %d >= %d",
478: which, args->num);
1.1.1.6 ! christos 479: free(args->list[which]);
1.1 christos 480: args->list[which] = cp;
481: }
482:
483: void
484: freeargs(arglist *args)
485: {
486: u_int i;
487:
488: if (args->list != NULL) {
489: for (i = 0; i < args->num; i++)
1.1.1.6 ! christos 490: free(args->list[i]);
! 491: free(args->list);
1.1 christos 492: args->nalloc = args->num = 0;
493: args->list = NULL;
494: }
495: }
496:
497: /*
498: * Expands tildes in the file name. Returns data allocated by xmalloc.
499: * Warning: this calls getpw*.
500: */
501: char *
502: tilde_expand_filename(const char *filename, uid_t uid)
503: {
1.1.1.6 ! christos 504: const char *path, *sep;
! 505: char user[128], *ret;
1.1 christos 506: struct passwd *pw;
507: u_int len, slash;
508:
509: if (*filename != '~')
510: return (xstrdup(filename));
511: filename++;
512:
513: path = strchr(filename, '/');
514: if (path != NULL && path > filename) { /* ~user/path */
515: slash = path - filename;
516: if (slash > sizeof(user) - 1)
517: fatal("tilde_expand_filename: ~username too long");
518: memcpy(user, filename, slash);
519: user[slash] = '\0';
520: if ((pw = getpwnam(user)) == NULL)
521: fatal("tilde_expand_filename: No such user %s", user);
522: } else if ((pw = getpwuid(uid)) == NULL) /* ~/path */
523: fatal("tilde_expand_filename: No such uid %ld", (long)uid);
524:
525: /* Make sure directory has a trailing '/' */
526: len = strlen(pw->pw_dir);
1.1.1.6 ! christos 527: if (len == 0 || pw->pw_dir[len - 1] != '/')
! 528: sep = "/";
! 529: else
! 530: sep = "";
1.1 christos 531:
532: /* Skip leading '/' from specified path */
533: if (path != NULL)
534: filename = path + 1;
1.1.1.6 ! christos 535:
! 536: if (xasprintf(&ret, "%s%s%s", pw->pw_dir, sep, filename) >= MAXPATHLEN)
1.1 christos 537: fatal("tilde_expand_filename: Path too long");
538:
1.1.1.6 ! christos 539: return (ret);
1.1 christos 540: }
541:
542: /*
543: * Expand a string with a set of %[char] escapes. A number of escapes may be
544: * specified as (char *escape_chars, char *replacement) pairs. The list must
545: * be terminated by a NULL escape_char. Returns replaced string in memory
546: * allocated by xmalloc.
547: */
548: char *
549: percent_expand(const char *string, ...)
550: {
551: #define EXPAND_MAX_KEYS 16
1.1.1.2 adam 552: u_int num_keys, i, j;
1.1 christos 553: struct {
554: const char *key;
555: const char *repl;
556: } keys[EXPAND_MAX_KEYS];
557: char buf[4096];
558: va_list ap;
559:
560: /* Gather keys */
561: va_start(ap, string);
562: for (num_keys = 0; num_keys < EXPAND_MAX_KEYS; num_keys++) {
563: keys[num_keys].key = va_arg(ap, char *);
564: if (keys[num_keys].key == NULL)
565: break;
566: keys[num_keys].repl = va_arg(ap, char *);
567: if (keys[num_keys].repl == NULL)
1.1.1.2 adam 568: fatal("%s: NULL replacement", __func__);
1.1 christos 569: }
1.1.1.2 adam 570: if (num_keys == EXPAND_MAX_KEYS && va_arg(ap, char *) != NULL)
571: fatal("%s: too many keys", __func__);
1.1 christos 572: va_end(ap);
573:
574: /* Expand string */
575: *buf = '\0';
576: for (i = 0; *string != '\0'; string++) {
577: if (*string != '%') {
578: append:
579: buf[i++] = *string;
580: if (i >= sizeof(buf))
1.1.1.2 adam 581: fatal("%s: string too long", __func__);
1.1 christos 582: buf[i] = '\0';
583: continue;
584: }
585: string++;
1.1.1.2 adam 586: /* %% case */
1.1 christos 587: if (*string == '%')
588: goto append;
589: for (j = 0; j < num_keys; j++) {
590: if (strchr(keys[j].key, *string) != NULL) {
591: i = strlcat(buf, keys[j].repl, sizeof(buf));
592: if (i >= sizeof(buf))
1.1.1.2 adam 593: fatal("%s: string too long", __func__);
1.1 christos 594: break;
595: }
596: }
597: if (j >= num_keys)
1.1.1.2 adam 598: fatal("%s: unknown key %%%c", __func__, *string);
1.1 christos 599: }
600: return (xstrdup(buf));
601: #undef EXPAND_MAX_KEYS
602: }
603:
604: /*
605: * Read an entire line from a public key file into a static buffer, discarding
606: * lines that exceed the buffer size. Returns 0 on success, -1 on failure.
607: */
608: int
609: read_keyfile_line(FILE *f, const char *filename, char *buf, size_t bufsz,
610: u_long *lineno)
611: {
612: while (fgets(buf, bufsz, f) != NULL) {
613: if (buf[0] == '\0')
614: continue;
615: (*lineno)++;
616: if (buf[strlen(buf) - 1] == '\n' || feof(f)) {
617: return 0;
618: } else {
619: debug("%s: %s line %lu exceeds size limit", __func__,
620: filename, *lineno);
621: /* discard remainder of line */
622: while (fgetc(f) != '\n' && !feof(f))
623: ; /* nothing */
624: }
625: }
626: return -1;
627: }
628:
629: int
630: tun_open(int tun, int mode)
631: {
632: struct ifreq ifr;
633: char name[100];
634: int fd = -1, sock;
635:
636: /* Open the tunnel device */
637: if (tun <= SSH_TUNID_MAX) {
638: snprintf(name, sizeof(name), "/dev/tun%d", tun);
639: fd = open(name, O_RDWR);
640: } else if (tun == SSH_TUNID_ANY) {
641: for (tun = 100; tun >= 0; tun--) {
642: snprintf(name, sizeof(name), "/dev/tun%d", tun);
643: if ((fd = open(name, O_RDWR)) >= 0)
644: break;
645: }
646: } else {
647: debug("%s: invalid tunnel %u", __func__, tun);
648: return (-1);
649: }
650:
651: if (fd < 0) {
652: debug("%s: %s open failed: %s", __func__, name, strerror(errno));
653: return (-1);
654: }
655:
656: debug("%s: %s mode %d fd %d", __func__, name, mode, fd);
657:
658: /* Set the tunnel device operation mode */
659: snprintf(ifr.ifr_name, sizeof(ifr.ifr_name), "tun%d", tun);
660: if ((sock = socket(PF_UNIX, SOCK_STREAM, 0)) == -1)
661: goto failed;
662:
663: if (ioctl(sock, SIOCGIFFLAGS, &ifr) == -1)
664: goto failed;
665:
666: /* Set interface mode */
667: ifr.ifr_flags &= ~IFF_UP;
668: if (mode == SSH_TUNMODE_ETHERNET)
669: ifr.ifr_flags |= IFF_LINK0;
670: else
671: ifr.ifr_flags &= ~IFF_LINK0;
672: if (ioctl(sock, SIOCSIFFLAGS, &ifr) == -1)
673: goto failed;
674:
675: /* Bring interface up */
676: ifr.ifr_flags |= IFF_UP;
677: if (ioctl(sock, SIOCSIFFLAGS, &ifr) == -1)
678: goto failed;
679:
680: close(sock);
681: return (fd);
682:
683: failed:
684: if (fd >= 0)
685: close(fd);
686: if (sock >= 0)
687: close(sock);
688: debug("%s: failed to set %s mode %d: %s", __func__, name,
689: mode, strerror(errno));
690: return (-1);
691: }
692:
693: void
694: sanitise_stdfd(void)
695: {
696: int nullfd, dupfd;
697:
698: if ((nullfd = dupfd = open(_PATH_DEVNULL, O_RDWR)) == -1) {
699: fprintf(stderr, "Couldn't open /dev/null: %s\n",
700: strerror(errno));
701: exit(1);
702: }
703: while (++dupfd <= 2) {
704: /* Only clobber closed fds */
705: if (fcntl(dupfd, F_GETFL, 0) >= 0)
706: continue;
707: if (dup2(nullfd, dupfd) == -1) {
708: fprintf(stderr, "dup2: %s\n", strerror(errno));
709: exit(1);
710: }
711: }
712: if (nullfd > 2)
713: close(nullfd);
714: }
715:
716: char *
717: tohex(const void *vp, size_t l)
718: {
719: const u_char *p = (const u_char *)vp;
720: char b[3], *r;
721: size_t i, hl;
722:
723: if (l > 65536)
724: return xstrdup("tohex: length > 65536");
725:
726: hl = l * 2 + 1;
727: r = xcalloc(1, hl);
728: for (i = 0; i < l; i++) {
729: snprintf(b, sizeof(b), "%02x", p[i]);
730: strlcat(r, b, hl);
731: }
732: return (r);
733: }
734:
735: u_int64_t
736: get_u64(const void *vp)
737: {
738: const u_char *p = (const u_char *)vp;
739: u_int64_t v;
740:
741: v = (u_int64_t)p[0] << 56;
742: v |= (u_int64_t)p[1] << 48;
743: v |= (u_int64_t)p[2] << 40;
744: v |= (u_int64_t)p[3] << 32;
745: v |= (u_int64_t)p[4] << 24;
746: v |= (u_int64_t)p[5] << 16;
747: v |= (u_int64_t)p[6] << 8;
748: v |= (u_int64_t)p[7];
749:
750: return (v);
751: }
752:
753: u_int32_t
754: get_u32(const void *vp)
755: {
756: const u_char *p = (const u_char *)vp;
757: u_int32_t v;
758:
759: v = (u_int32_t)p[0] << 24;
760: v |= (u_int32_t)p[1] << 16;
761: v |= (u_int32_t)p[2] << 8;
762: v |= (u_int32_t)p[3];
763:
764: return (v);
765: }
766:
767: u_int16_t
768: get_u16(const void *vp)
769: {
770: const u_char *p = (const u_char *)vp;
771: u_int16_t v;
772:
773: v = (u_int16_t)p[0] << 8;
774: v |= (u_int16_t)p[1];
775:
776: return (v);
777: }
778:
779: void
780: put_u64(void *vp, u_int64_t v)
781: {
782: u_char *p = (u_char *)vp;
783:
784: p[0] = (u_char)(v >> 56) & 0xff;
785: p[1] = (u_char)(v >> 48) & 0xff;
786: p[2] = (u_char)(v >> 40) & 0xff;
787: p[3] = (u_char)(v >> 32) & 0xff;
788: p[4] = (u_char)(v >> 24) & 0xff;
789: p[5] = (u_char)(v >> 16) & 0xff;
790: p[6] = (u_char)(v >> 8) & 0xff;
791: p[7] = (u_char)v & 0xff;
792: }
793:
794: void
795: put_u32(void *vp, u_int32_t v)
796: {
797: u_char *p = (u_char *)vp;
798:
799: p[0] = (u_char)(v >> 24) & 0xff;
800: p[1] = (u_char)(v >> 16) & 0xff;
801: p[2] = (u_char)(v >> 8) & 0xff;
802: p[3] = (u_char)v & 0xff;
803: }
804:
805:
806: void
807: put_u16(void *vp, u_int16_t v)
808: {
809: u_char *p = (u_char *)vp;
810:
811: p[0] = (u_char)(v >> 8) & 0xff;
812: p[1] = (u_char)v & 0xff;
813: }
814:
815: void
816: ms_subtract_diff(struct timeval *start, int *ms)
817: {
818: struct timeval diff, finish;
819:
820: gettimeofday(&finish, NULL);
821: timersub(&finish, start, &diff);
822: *ms -= (diff.tv_sec * 1000) + (diff.tv_usec / 1000);
823: }
824:
825: void
826: ms_to_timeval(struct timeval *tv, int ms)
827: {
828: if (ms < 0)
829: ms = 0;
830: tv->tv_sec = ms / 1000;
831: tv->tv_usec = (ms % 1000) * 1000;
832: }
833:
1.1.1.6 ! christos 834: time_t
! 835: monotime(void)
! 836: {
! 837: struct timespec ts;
! 838:
! 839: if (clock_gettime(CLOCK_MONOTONIC, &ts) != 0)
! 840: fatal("clock_gettime: %s", strerror(errno));
! 841:
! 842: return (ts.tv_sec);
! 843: }
! 844:
1.1.1.3 christos 845: void
846: bandwidth_limit_init(struct bwlimit *bw, u_int64_t kbps, size_t buflen)
847: {
848: bw->buflen = buflen;
849: bw->rate = kbps;
850: bw->thresh = bw->rate;
851: bw->lamt = 0;
852: timerclear(&bw->bwstart);
853: timerclear(&bw->bwend);
854: }
855:
856: /* Callback from read/write loop to insert bandwidth-limiting delays */
857: void
858: bandwidth_limit(struct bwlimit *bw, size_t read_len)
859: {
860: u_int64_t waitlen;
861: struct timespec ts, rm;
862:
863: if (!timerisset(&bw->bwstart)) {
864: gettimeofday(&bw->bwstart, NULL);
865: return;
866: }
867:
868: bw->lamt += read_len;
869: if (bw->lamt < bw->thresh)
870: return;
871:
872: gettimeofday(&bw->bwend, NULL);
873: timersub(&bw->bwend, &bw->bwstart, &bw->bwend);
874: if (!timerisset(&bw->bwend))
875: return;
876:
877: bw->lamt *= 8;
878: waitlen = (double)1000000L * bw->lamt / bw->rate;
879:
880: bw->bwstart.tv_sec = waitlen / 1000000L;
881: bw->bwstart.tv_usec = waitlen % 1000000L;
882:
883: if (timercmp(&bw->bwstart, &bw->bwend, >)) {
884: timersub(&bw->bwstart, &bw->bwend, &bw->bwend);
885:
886: /* Adjust the wait time */
887: if (bw->bwend.tv_sec) {
888: bw->thresh /= 2;
889: if (bw->thresh < bw->buflen / 4)
890: bw->thresh = bw->buflen / 4;
891: } else if (bw->bwend.tv_usec < 10000) {
892: bw->thresh *= 2;
893: if (bw->thresh > bw->buflen * 8)
894: bw->thresh = bw->buflen * 8;
895: }
896:
897: TIMEVAL_TO_TIMESPEC(&bw->bwend, &ts);
898: while (nanosleep(&ts, &rm) == -1) {
899: if (errno != EINTR)
900: break;
901: ts = rm;
902: }
903: }
904:
905: bw->lamt = 0;
906: gettimeofday(&bw->bwstart, NULL);
907: }
908:
909: /* Make a template filename for mk[sd]temp() */
910: void
911: mktemp_proto(char *s, size_t len)
912: {
913: const char *tmpdir;
914: int r;
915:
916: if ((tmpdir = getenv("TMPDIR")) != NULL) {
917: r = snprintf(s, len, "%s/ssh-XXXXXXXXXXXX", tmpdir);
918: if (r > 0 && (size_t)r < len)
919: return;
920: }
921: r = snprintf(s, len, "/tmp/ssh-XXXXXXXXXXXX");
922: if (r < 0 || (size_t)r >= len)
923: fatal("%s: template string too short", __func__);
924: }
925:
926: static const struct {
927: const char *name;
928: int value;
929: } ipqos[] = {
930: { "af11", IPTOS_DSCP_AF11 },
931: { "af12", IPTOS_DSCP_AF12 },
932: { "af13", IPTOS_DSCP_AF13 },
1.1.1.5 christos 933: { "af21", IPTOS_DSCP_AF21 },
1.1.1.3 christos 934: { "af22", IPTOS_DSCP_AF22 },
935: { "af23", IPTOS_DSCP_AF23 },
936: { "af31", IPTOS_DSCP_AF31 },
937: { "af32", IPTOS_DSCP_AF32 },
938: { "af33", IPTOS_DSCP_AF33 },
939: { "af41", IPTOS_DSCP_AF41 },
940: { "af42", IPTOS_DSCP_AF42 },
941: { "af43", IPTOS_DSCP_AF43 },
942: { "cs0", IPTOS_DSCP_CS0 },
943: { "cs1", IPTOS_DSCP_CS1 },
944: { "cs2", IPTOS_DSCP_CS2 },
945: { "cs3", IPTOS_DSCP_CS3 },
946: { "cs4", IPTOS_DSCP_CS4 },
947: { "cs5", IPTOS_DSCP_CS5 },
948: { "cs6", IPTOS_DSCP_CS6 },
949: { "cs7", IPTOS_DSCP_CS7 },
950: { "ef", IPTOS_DSCP_EF },
951: { "lowdelay", IPTOS_LOWDELAY },
952: { "throughput", IPTOS_THROUGHPUT },
953: { "reliability", IPTOS_RELIABILITY },
954: { NULL, -1 }
955: };
956:
1.1.1.2 adam 957: int
1.1.1.3 christos 958: parse_ipqos(const char *cp)
1.1.1.2 adam 959: {
1.1.1.3 christos 960: u_int i;
961: char *ep;
962: long val;
1.1.1.2 adam 963:
1.1.1.3 christos 964: if (cp == NULL)
965: return -1;
966: for (i = 0; ipqos[i].name != NULL; i++) {
967: if (strcasecmp(cp, ipqos[i].name) == 0)
968: return ipqos[i].value;
969: }
970: /* Try parsing as an integer */
971: val = strtol(cp, &ep, 0);
972: if (*cp == '\0' || *ep != '\0' || val < 0 || val > 255)
973: return -1;
974: return val;
1.1.1.2 adam 975: }
1.1.1.3 christos 976:
1.1.1.4 christos 977: const char *
978: iptos2str(int iptos)
979: {
980: int i;
981: static char iptos_str[sizeof "0xff"];
982:
983: for (i = 0; ipqos[i].name != NULL; i++) {
984: if (ipqos[i].value == iptos)
985: return ipqos[i].name;
986: }
987: snprintf(iptos_str, sizeof iptos_str, "0x%02x", iptos);
988: return iptos_str;
989: }
CVSweb <webmaster@jp.NetBSD.org>