diff options
| author | SkyperTHC | 2026-03-03 06:28:55 +0000 |
|---|---|---|
| committer | SkyperTHC | 2026-03-03 06:28:55 +0000 |
| commit | 5d3573ef7a109ee70416fe94db098fe6a769a798 (patch) | |
| tree | dc2d5b294c9db8ab2db7433511f94e1c4bb8b698 /other/ssharp/ssh-keyscan.c | |
| parent | c6c59dc73cc4586357f93ab38ecf459e98675cc5 (diff) | |
packetstorm sync
Diffstat (limited to 'other/ssharp/ssh-keyscan.c')
| -rw-r--r-- | other/ssharp/ssh-keyscan.c | 646 |
1 files changed, 646 insertions, 0 deletions
diff --git a/other/ssharp/ssh-keyscan.c b/other/ssharp/ssh-keyscan.c new file mode 100644 index 0000000..3f6c231 --- /dev/null +++ b/other/ssharp/ssh-keyscan.c | |||
| @@ -0,0 +1,646 @@ | |||
| 1 | /* | ||
| 2 | * Copyright 1995, 1996 by David Mazieres <dm@lcs.mit.edu>. | ||
| 3 | * | ||
| 4 | * Modification and redistribution in source and binary forms is | ||
| 5 | * permitted provided that due credit is given to the author and the | ||
| 6 | * OpenBSD project (for instance by leaving this copyright notice | ||
| 7 | * intact). | ||
| 8 | */ | ||
| 9 | |||
| 10 | #include "includes.h" | ||
| 11 | RCSID("$OpenBSD: ssh-keyscan.c,v 1.22 2001/03/06 06:11:18 deraadt Exp $"); | ||
| 12 | |||
| 13 | #if defined(HAVE_SYS_QUEUE_H) && !defined(HAVE_BOGUS_SYS_QUEUE_H) | ||
| 14 | #include <sys/queue.h> | ||
| 15 | #else | ||
| 16 | #include "openbsd-compat/fake-queue.h" | ||
| 17 | #endif | ||
| 18 | #include <errno.h> | ||
| 19 | |||
| 20 | #include <openssl/bn.h> | ||
| 21 | |||
| 22 | #include "xmalloc.h" | ||
| 23 | #include "ssh.h" | ||
| 24 | #include "ssh1.h" | ||
| 25 | #include "key.h" | ||
| 26 | #include "buffer.h" | ||
| 27 | #include "bufaux.h" | ||
| 28 | #include "log.h" | ||
| 29 | #include "atomicio.h" | ||
| 30 | |||
| 31 | static int argno = 1; /* Number of argument currently being parsed */ | ||
| 32 | |||
| 33 | int family = AF_UNSPEC; /* IPv4, IPv6 or both */ | ||
| 34 | |||
| 35 | #define MAXMAXFD 256 | ||
| 36 | |||
| 37 | /* The number of seconds after which to give up on a TCP connection */ | ||
| 38 | int timeout = 5; | ||
| 39 | |||
| 40 | int maxfd; | ||
| 41 | #define MAXCON (maxfd - 10) | ||
| 42 | |||
| 43 | #ifdef HAVE___PROGNAME | ||
| 44 | extern char *__progname; | ||
| 45 | #else | ||
| 46 | char *__progname; | ||
| 47 | #endif | ||
| 48 | fd_set *read_wait; | ||
| 49 | size_t read_wait_size; | ||
| 50 | int ncon; | ||
| 51 | |||
| 52 | /* | ||
| 53 | * Keep a connection structure for each file descriptor. The state | ||
| 54 | * associated with file descriptor n is held in fdcon[n]. | ||
| 55 | */ | ||
| 56 | typedef struct Connection { | ||
| 57 | u_char c_status; /* State of connection on this file desc. */ | ||
| 58 | #define CS_UNUSED 0 /* File descriptor unused */ | ||
| 59 | #define CS_CON 1 /* Waiting to connect/read greeting */ | ||
| 60 | #define CS_SIZE 2 /* Waiting to read initial packet size */ | ||
| 61 | #define CS_KEYS 3 /* Waiting to read public key packet */ | ||
| 62 | int c_fd; /* Quick lookup: c->c_fd == c - fdcon */ | ||
| 63 | int c_plen; /* Packet length field for ssh packet */ | ||
| 64 | int c_len; /* Total bytes which must be read. */ | ||
| 65 | int c_off; /* Length of data read so far. */ | ||
| 66 | char *c_namebase; /* Address to free for c_name and c_namelist */ | ||
| 67 | char *c_name; /* Hostname of connection for errors */ | ||
| 68 | char *c_namelist; /* Pointer to other possible addresses */ | ||
| 69 | char *c_output_name; /* Hostname of connection for output */ | ||
| 70 | char *c_data; /* Data read from this fd */ | ||
| 71 | struct timeval c_tv; /* Time at which connection gets aborted */ | ||
| 72 | TAILQ_ENTRY(Connection) c_link; /* List of connections in timeout order. */ | ||
| 73 | } con; | ||
| 74 | |||
| 75 | TAILQ_HEAD(conlist, Connection) tq; /* Timeout Queue */ | ||
| 76 | con *fdcon; | ||
| 77 | |||
| 78 | /* | ||
| 79 | * This is just a wrapper around fgets() to make it usable. | ||
| 80 | */ | ||
| 81 | |||
| 82 | /* Stress-test. Increase this later. */ | ||
| 83 | #define LINEBUF_SIZE 16 | ||
| 84 | |||
| 85 | typedef struct { | ||
| 86 | char *buf; | ||
| 87 | u_int size; | ||
| 88 | int lineno; | ||
| 89 | const char *filename; | ||
| 90 | FILE *stream; | ||
| 91 | void (*errfun) (const char *,...); | ||
| 92 | } Linebuf; | ||
| 93 | |||
| 94 | Linebuf * | ||
| 95 | Linebuf_alloc(const char *filename, void (*errfun) (const char *,...)) | ||
| 96 | { | ||
| 97 | Linebuf *lb; | ||
| 98 | |||
| 99 | if (!(lb = malloc(sizeof(*lb)))) { | ||
| 100 | if (errfun) | ||
| 101 | (*errfun) ("linebuf (%s): malloc failed\n", lb->filename); | ||
| 102 | return (NULL); | ||
| 103 | } | ||
| 104 | if (filename) { | ||
| 105 | lb->filename = filename; | ||
| 106 | if (!(lb->stream = fopen(filename, "r"))) { | ||
| 107 | xfree(lb); | ||
| 108 | if (errfun) | ||
| 109 | (*errfun) ("%s: %s\n", filename, strerror(errno)); | ||
| 110 | return (NULL); | ||
| 111 | } | ||
| 112 | } else { | ||
| 113 | lb->filename = "(stdin)"; | ||
| 114 | lb->stream = stdin; | ||
| 115 | } | ||
| 116 | |||
| 117 | if (!(lb->buf = malloc(lb->size = LINEBUF_SIZE))) { | ||
| 118 | if (errfun) | ||
| 119 | (*errfun) ("linebuf (%s): malloc failed\n", lb->filename); | ||
| 120 | xfree(lb); | ||
| 121 | return (NULL); | ||
| 122 | } | ||
| 123 | lb->errfun = errfun; | ||
| 124 | lb->lineno = 0; | ||
| 125 | return (lb); | ||
| 126 | } | ||
| 127 | |||
| 128 | void | ||
| 129 | Linebuf_free(Linebuf * lb) | ||
| 130 | { | ||
| 131 | fclose(lb->stream); | ||
| 132 | xfree(lb->buf); | ||
| 133 | xfree(lb); | ||
| 134 | } | ||
| 135 | |||
| 136 | void | ||
| 137 | Linebuf_restart(Linebuf * lb) | ||
| 138 | { | ||
| 139 | clearerr(lb->stream); | ||
| 140 | rewind(lb->stream); | ||
| 141 | lb->lineno = 0; | ||
| 142 | } | ||
| 143 | |||
| 144 | int | ||
| 145 | Linebuf_lineno(Linebuf * lb) | ||
| 146 | { | ||
| 147 | return (lb->lineno); | ||
| 148 | } | ||
| 149 | |||
| 150 | char * | ||
| 151 | Linebuf_getline(Linebuf * lb) | ||
| 152 | { | ||
| 153 | int n = 0; | ||
| 154 | |||
| 155 | lb->lineno++; | ||
| 156 | for (;;) { | ||
| 157 | /* Read a line */ | ||
| 158 | if (!fgets(&lb->buf[n], lb->size - n, lb->stream)) { | ||
| 159 | if (ferror(lb->stream) && lb->errfun) | ||
| 160 | (*lb->errfun) ("%s: %s\n", lb->filename, | ||
| 161 | strerror(errno)); | ||
| 162 | return (NULL); | ||
| 163 | } | ||
| 164 | n = strlen(lb->buf); | ||
| 165 | |||
| 166 | /* Return it or an error if it fits */ | ||
| 167 | if (n > 0 && lb->buf[n - 1] == '\n') { | ||
| 168 | lb->buf[n - 1] = '\0'; | ||
| 169 | return (lb->buf); | ||
| 170 | } | ||
| 171 | if (n != lb->size - 1) { | ||
| 172 | if (lb->errfun) | ||
| 173 | (*lb->errfun) ("%s: skipping incomplete last line\n", | ||
| 174 | lb->filename); | ||
| 175 | return (NULL); | ||
| 176 | } | ||
| 177 | /* Double the buffer if we need more space */ | ||
| 178 | if (!(lb->buf = realloc(lb->buf, (lb->size *= 2)))) { | ||
| 179 | if (lb->errfun) | ||
| 180 | (*lb->errfun) ("linebuf (%s): realloc failed\n", | ||
| 181 | lb->filename); | ||
| 182 | return (NULL); | ||
| 183 | } | ||
| 184 | } | ||
| 185 | } | ||
| 186 | |||
| 187 | int | ||
| 188 | fdlim_get(int hard) | ||
| 189 | { | ||
| 190 | #if defined(HAVE_GETRLIMIT) && defined(RLIMIT_NOFILE) | ||
| 191 | struct rlimit rlfd; | ||
| 192 | |||
| 193 | if (getrlimit(RLIMIT_NOFILE, &rlfd) < 0) | ||
| 194 | return (-1); | ||
| 195 | if ((hard ? rlfd.rlim_max : rlfd.rlim_cur) == RLIM_INFINITY) | ||
| 196 | return 10000; | ||
| 197 | else | ||
| 198 | return hard ? rlfd.rlim_max : rlfd.rlim_cur; | ||
| 199 | #elif defined (HAVE_SYSCONF) | ||
| 200 | return sysconf (_SC_OPEN_MAX); | ||
| 201 | #else | ||
| 202 | return 10000; | ||
| 203 | #endif | ||
| 204 | } | ||
| 205 | |||
| 206 | int | ||
| 207 | fdlim_set(int lim) | ||
| 208 | { | ||
| 209 | #if defined(HAVE_SETRLIMIT) && defined(RLIMIT_NOFILE) | ||
| 210 | struct rlimit rlfd; | ||
| 211 | #endif | ||
| 212 | if (lim <= 0) | ||
| 213 | return (-1); | ||
| 214 | #if defined(HAVE_SETRLIMIT) && defined(RLIMIT_NOFILE) | ||
| 215 | if (getrlimit(RLIMIT_NOFILE, &rlfd) < 0) | ||
| 216 | return (-1); | ||
| 217 | rlfd.rlim_cur = lim; | ||
| 218 | if (setrlimit(RLIMIT_NOFILE, &rlfd) < 0) | ||
| 219 | return (-1); | ||
| 220 | #elif defined (HAVE_SETDTABLESIZE) | ||
| 221 | setdtablesize(lim); | ||
| 222 | #endif | ||
| 223 | return (0); | ||
| 224 | } | ||
| 225 | |||
| 226 | /* | ||
| 227 | * This is an strsep function that returns a null field for adjacent | ||
| 228 | * separators. This is the same as the 4.4BSD strsep, but different from the | ||
| 229 | * one in the GNU libc. | ||
| 230 | */ | ||
| 231 | char * | ||
| 232 | xstrsep(char **str, const char *delim) | ||
| 233 | { | ||
| 234 | char *s, *e; | ||
| 235 | |||
| 236 | if (!**str) | ||
| 237 | return (NULL); | ||
| 238 | |||
| 239 | s = *str; | ||
| 240 | e = s + strcspn(s, delim); | ||
| 241 | |||
| 242 | if (*e != '\0') | ||
| 243 | *e++ = '\0'; | ||
| 244 | *str = e; | ||
| 245 | |||
| 246 | return (s); | ||
| 247 | } | ||
| 248 | |||
| 249 | /* | ||
| 250 | * Get the next non-null token (like GNU strsep). Strsep() will return a | ||
| 251 | * null token for two adjacent separators, so we may have to loop. | ||
| 252 | */ | ||
| 253 | char * | ||
| 254 | strnnsep(char **stringp, char *delim) | ||
| 255 | { | ||
| 256 | char *tok; | ||
| 257 | |||
| 258 | do { | ||
| 259 | tok = xstrsep(stringp, delim); | ||
| 260 | } while (tok && *tok == '\0'); | ||
| 261 | return (tok); | ||
| 262 | } | ||
| 263 | |||
| 264 | void | ||
| 265 | keyprint(char *host, char *output_name, char *kd, int len) | ||
| 266 | { | ||
| 267 | static Key *rsa; | ||
| 268 | static Buffer msg; | ||
| 269 | |||
| 270 | if (rsa == NULL) { | ||
| 271 | buffer_init(&msg); | ||
| 272 | rsa = key_new(KEY_RSA1); | ||
| 273 | } | ||
| 274 | buffer_append(&msg, kd, len); | ||
| 275 | buffer_consume(&msg, 8 - (len & 7)); /* padding */ | ||
| 276 | if (buffer_get_char(&msg) != (int) SSH_SMSG_PUBLIC_KEY) { | ||
| 277 | error("%s: invalid packet type", host); | ||
| 278 | buffer_clear(&msg); | ||
| 279 | return; | ||
| 280 | } | ||
| 281 | buffer_consume(&msg, 8); /* cookie */ | ||
| 282 | |||
| 283 | /* server key */ | ||
| 284 | (void) buffer_get_int(&msg); | ||
| 285 | buffer_get_bignum(&msg, rsa->rsa->e); | ||
| 286 | buffer_get_bignum(&msg, rsa->rsa->n); | ||
| 287 | |||
| 288 | /* host key */ | ||
| 289 | (void) buffer_get_int(&msg); | ||
| 290 | buffer_get_bignum(&msg, rsa->rsa->e); | ||
| 291 | buffer_get_bignum(&msg, rsa->rsa->n); | ||
| 292 | buffer_clear(&msg); | ||
| 293 | |||
| 294 | fprintf(stdout, "%s ", output_name ? output_name : host); | ||
| 295 | key_write(rsa, stdout); | ||
| 296 | fputs("\n", stdout); | ||
| 297 | } | ||
| 298 | |||
| 299 | int | ||
| 300 | tcpconnect(char *host) | ||
| 301 | { | ||
| 302 | struct addrinfo hints, *ai, *aitop; | ||
| 303 | char strport[NI_MAXSERV]; | ||
| 304 | int gaierr, s = -1; | ||
| 305 | |||
| 306 | snprintf(strport, sizeof strport, "%d", SSH_DEFAULT_PORT); | ||
| 307 | memset(&hints, 0, sizeof(hints)); | ||
| 308 | hints.ai_family = family; | ||
| 309 | hints.ai_socktype = SOCK_STREAM; | ||
| 310 | if ((gaierr = getaddrinfo(host, strport, &hints, &aitop)) != 0) | ||
| 311 | fatal("getaddrinfo %s: %s", host, gai_strerror(gaierr)); | ||
| 312 | for (ai = aitop; ai; ai = ai->ai_next) { | ||
| 313 | s = socket(ai->ai_family, SOCK_STREAM, 0); | ||
| 314 | if (s < 0) { | ||
| 315 | error("socket: %s", strerror(errno)); | ||
| 316 | continue; | ||
| 317 | } | ||
| 318 | if (fcntl(s, F_SETFL, O_NONBLOCK) < 0) | ||
| 319 | fatal("F_SETFL: %s", strerror(errno)); | ||
| 320 | if (connect(s, ai->ai_addr, ai->ai_addrlen) < 0 && | ||
| 321 | errno != EINPROGRESS) | ||
| 322 | error("connect (`%s'): %s", host, strerror(errno)); | ||
| 323 | else | ||
| 324 | break; | ||
| 325 | close(s); | ||
| 326 | s = -1; | ||
| 327 | } | ||
| 328 | freeaddrinfo(aitop); | ||
| 329 | return s; | ||
| 330 | } | ||
| 331 | |||
| 332 | int | ||
| 333 | conalloc(char *iname, char *oname) | ||
| 334 | { | ||
| 335 | int s; | ||
| 336 | char *namebase, *name, *namelist; | ||
| 337 | |||
| 338 | namebase = namelist = xstrdup(iname); | ||
| 339 | |||
| 340 | do { | ||
| 341 | name = xstrsep(&namelist, ","); | ||
| 342 | if (!name) { | ||
| 343 | xfree(namebase); | ||
| 344 | return (-1); | ||
| 345 | } | ||
| 346 | } while ((s = tcpconnect(name)) < 0); | ||
| 347 | |||
| 348 | if (s >= maxfd) | ||
| 349 | fatal("conalloc: fdno %d too high", s); | ||
| 350 | if (fdcon[s].c_status) | ||
| 351 | fatal("conalloc: attempt to reuse fdno %d", s); | ||
| 352 | |||
| 353 | fdcon[s].c_fd = s; | ||
| 354 | fdcon[s].c_status = CS_CON; | ||
| 355 | fdcon[s].c_namebase = namebase; | ||
| 356 | fdcon[s].c_name = name; | ||
| 357 | fdcon[s].c_namelist = namelist; | ||
| 358 | fdcon[s].c_output_name = xstrdup(oname); | ||
| 359 | fdcon[s].c_data = (char *) &fdcon[s].c_plen; | ||
| 360 | fdcon[s].c_len = 4; | ||
| 361 | fdcon[s].c_off = 0; | ||
| 362 | gettimeofday(&fdcon[s].c_tv, NULL); | ||
| 363 | fdcon[s].c_tv.tv_sec += timeout; | ||
| 364 | TAILQ_INSERT_TAIL(&tq, &fdcon[s], c_link); | ||
| 365 | FD_SET(s, read_wait); | ||
| 366 | ncon++; | ||
| 367 | return (s); | ||
| 368 | } | ||
| 369 | |||
| 370 | void | ||
| 371 | confree(int s) | ||
| 372 | { | ||
| 373 | if (s >= maxfd || fdcon[s].c_status == CS_UNUSED) | ||
| 374 | fatal("confree: attempt to free bad fdno %d", s); | ||
| 375 | close(s); | ||
| 376 | xfree(fdcon[s].c_namebase); | ||
| 377 | xfree(fdcon[s].c_output_name); | ||
| 378 | if (fdcon[s].c_status == CS_KEYS) | ||
| 379 | xfree(fdcon[s].c_data); | ||
| 380 | fdcon[s].c_status = CS_UNUSED; | ||
| 381 | TAILQ_REMOVE(&tq, &fdcon[s], c_link); | ||
| 382 | FD_CLR(s, read_wait); | ||
| 383 | ncon--; | ||
| 384 | } | ||
| 385 | |||
| 386 | void | ||
| 387 | contouch(int s) | ||
| 388 | { | ||
| 389 | TAILQ_REMOVE(&tq, &fdcon[s], c_link); | ||
| 390 | gettimeofday(&fdcon[s].c_tv, NULL); | ||
| 391 | fdcon[s].c_tv.tv_sec += timeout; | ||
| 392 | TAILQ_INSERT_TAIL(&tq, &fdcon[s], c_link); | ||
| 393 | } | ||
| 394 | |||
| 395 | int | ||
| 396 | conrecycle(int s) | ||
| 397 | { | ||
| 398 | int ret; | ||
| 399 | con *c = &fdcon[s]; | ||
| 400 | char *iname, *oname; | ||
| 401 | |||
| 402 | iname = xstrdup(c->c_namelist); | ||
| 403 | oname = xstrdup(c->c_output_name); | ||
| 404 | confree(s); | ||
| 405 | ret = conalloc(iname, oname); | ||
| 406 | xfree(iname); | ||
| 407 | xfree(oname); | ||
| 408 | return (ret); | ||
| 409 | } | ||
| 410 | |||
| 411 | void | ||
| 412 | congreet(int s) | ||
| 413 | { | ||
| 414 | char buf[80], *cp; | ||
| 415 | size_t bufsiz; | ||
| 416 | int n = 0; | ||
| 417 | con *c = &fdcon[s]; | ||
| 418 | |||
| 419 | bufsiz = sizeof(buf); | ||
| 420 | cp = buf; | ||
| 421 | while (bufsiz-- && (n = read(s, cp, 1)) == 1 && *cp != '\n' && *cp != '\r') | ||
| 422 | cp++; | ||
| 423 | if (n < 0) { | ||
| 424 | if (errno != ECONNREFUSED) | ||
| 425 | error("read (%s): %s", c->c_name, strerror(errno)); | ||
| 426 | conrecycle(s); | ||
| 427 | return; | ||
| 428 | } | ||
| 429 | if (*cp != '\n' && *cp != '\r') { | ||
| 430 | error("%s: bad greeting", c->c_name); | ||
| 431 | confree(s); | ||
| 432 | return; | ||
| 433 | } | ||
| 434 | *cp = '\0'; | ||
| 435 | fprintf(stderr, "# %s %s\n", c->c_name, buf); | ||
| 436 | n = snprintf(buf, sizeof buf, "SSH-1.5-OpenSSH-keyscan\r\n"); | ||
| 437 | if (atomicio(write, s, buf, n) != n) { | ||
| 438 | error("write (%s): %s", c->c_name, strerror(errno)); | ||
| 439 | confree(s); | ||
| 440 | return; | ||
| 441 | } | ||
| 442 | c->c_status = CS_SIZE; | ||
| 443 | contouch(s); | ||
| 444 | } | ||
| 445 | |||
| 446 | void | ||
| 447 | conread(int s) | ||
| 448 | { | ||
| 449 | int n; | ||
| 450 | con *c = &fdcon[s]; | ||
| 451 | |||
| 452 | if (c->c_status == CS_CON) { | ||
| 453 | congreet(s); | ||
| 454 | return; | ||
| 455 | } | ||
| 456 | n = read(s, c->c_data + c->c_off, c->c_len - c->c_off); | ||
| 457 | if (n < 0) { | ||
| 458 | error("read (%s): %s", c->c_name, strerror(errno)); | ||
| 459 | confree(s); | ||
| 460 | return; | ||
| 461 | } | ||
| 462 | c->c_off += n; | ||
| 463 | |||
| 464 | if (c->c_off == c->c_len) | ||
| 465 | switch (c->c_status) { | ||
| 466 | case CS_SIZE: | ||
| 467 | c->c_plen = htonl(c->c_plen); | ||
| 468 | c->c_len = c->c_plen + 8 - (c->c_plen & 7); | ||
| 469 | c->c_off = 0; | ||
| 470 | c->c_data = xmalloc(c->c_len); | ||
| 471 | c->c_status = CS_KEYS; | ||
| 472 | break; | ||
| 473 | case CS_KEYS: | ||
| 474 | keyprint(c->c_name, c->c_output_name, c->c_data, c->c_plen); | ||
| 475 | confree(s); | ||
| 476 | return; | ||
| 477 | break; | ||
| 478 | default: | ||
| 479 | fatal("conread: invalid status %d", c->c_status); | ||
| 480 | break; | ||
| 481 | } | ||
| 482 | |||
| 483 | contouch(s); | ||
| 484 | } | ||
| 485 | |||
| 486 | void | ||
| 487 | conloop(void) | ||
| 488 | { | ||
| 489 | fd_set *r, *e; | ||
| 490 | struct timeval seltime, now; | ||
| 491 | int i; | ||
| 492 | con *c; | ||
| 493 | |||
| 494 | gettimeofday(&now, NULL); | ||
| 495 | c = tq.tqh_first; | ||
| 496 | |||
| 497 | if (c && (c->c_tv.tv_sec > now.tv_sec || | ||
| 498 | (c->c_tv.tv_sec == now.tv_sec && c->c_tv.tv_usec > now.tv_usec))) { | ||
| 499 | seltime = c->c_tv; | ||
| 500 | seltime.tv_sec -= now.tv_sec; | ||
| 501 | seltime.tv_usec -= now.tv_usec; | ||
| 502 | if (seltime.tv_usec < 0) { | ||
| 503 | seltime.tv_usec += 1000000; | ||
| 504 | seltime.tv_sec--; | ||
| 505 | } | ||
| 506 | } else | ||
| 507 | seltime.tv_sec = seltime.tv_usec = 0; | ||
| 508 | |||
| 509 | r = xmalloc(read_wait_size); | ||
| 510 | memcpy(r, read_wait, read_wait_size); | ||
| 511 | e = xmalloc(read_wait_size); | ||
| 512 | memcpy(e, read_wait, read_wait_size); | ||
| 513 | |||
| 514 | while (select(maxfd, r, NULL, e, &seltime) == -1 && | ||
| 515 | (errno == EAGAIN || errno == EINTR)) | ||
| 516 | ; | ||
| 517 | |||
| 518 | for (i = 0; i < maxfd; i++) { | ||
| 519 | if (FD_ISSET(i, e)) { | ||
| 520 | error("%s: exception!", fdcon[i].c_name); | ||
| 521 | confree(i); | ||
| 522 | } else if (FD_ISSET(i, r)) | ||
| 523 | conread(i); | ||
| 524 | } | ||
| 525 | xfree(r); | ||
| 526 | xfree(e); | ||
| 527 | |||
| 528 | c = tq.tqh_first; | ||
| 529 | while (c && (c->c_tv.tv_sec < now.tv_sec || | ||
| 530 | (c->c_tv.tv_sec == now.tv_sec && c->c_tv.tv_usec < now.tv_usec))) { | ||
| 531 | int s = c->c_fd; | ||
| 532 | |||
| 533 | c = c->c_link.tqe_next; | ||
| 534 | conrecycle(s); | ||
| 535 | } | ||
| 536 | } | ||
| 537 | |||
| 538 | char * | ||
| 539 | nexthost(int argc, char **argv) | ||
| 540 | { | ||
| 541 | static Linebuf *lb; | ||
| 542 | |||
| 543 | for (;;) { | ||
| 544 | if (!lb) { | ||
| 545 | if (argno >= argc) | ||
| 546 | return (NULL); | ||
| 547 | if (argv[argno][0] != '-') | ||
| 548 | return (argv[argno++]); | ||
| 549 | if (!strcmp(argv[argno], "--")) { | ||
| 550 | if (++argno >= argc) | ||
| 551 | return (NULL); | ||
| 552 | return (argv[argno++]); | ||
| 553 | } else if (!strncmp(argv[argno], "-f", 2)) { | ||
| 554 | char *fname; | ||
| 555 | |||
| 556 | if (argv[argno][2]) | ||
| 557 | fname = &argv[argno++][2]; | ||
| 558 | else if (++argno >= argc) { | ||
| 559 | error("missing filename for `-f'"); | ||
| 560 | return (NULL); | ||
| 561 | } else | ||
| 562 | fname = argv[argno++]; | ||
| 563 | if (!strcmp(fname, "-")) | ||
| 564 | fname = NULL; | ||
| 565 | lb = Linebuf_alloc(fname, error); | ||
| 566 | } else | ||
| 567 | error("ignoring invalid/misplaced option `%s'", | ||
| 568 | argv[argno++]); | ||
| 569 | } else { | ||
| 570 | char *line; | ||
| 571 | |||
| 572 | line = Linebuf_getline(lb); | ||
| 573 | if (line) | ||
| 574 | return (line); | ||
| 575 | Linebuf_free(lb); | ||
| 576 | lb = NULL; | ||
| 577 | } | ||
| 578 | } | ||
| 579 | } | ||
| 580 | |||
| 581 | void | ||
| 582 | usage(void) | ||
| 583 | { | ||
| 584 | fatal("usage: %s [-t timeout] { [--] host | -f file } ...", __progname); | ||
| 585 | return; | ||
| 586 | } | ||
| 587 | |||
| 588 | int | ||
| 589 | main(int argc, char **argv) | ||
| 590 | { | ||
| 591 | char *host = NULL; | ||
| 592 | |||
| 593 | __progname = get_progname(argv[0]); | ||
| 594 | TAILQ_INIT(&tq); | ||
| 595 | |||
| 596 | if (argc <= argno) | ||
| 597 | usage(); | ||
| 598 | |||
| 599 | if (argv[1][0] == '-' && argv[1][1] == 't') { | ||
| 600 | argno++; | ||
| 601 | if (argv[1][2]) | ||
| 602 | timeout = atoi(&argv[1][2]); | ||
| 603 | else { | ||
| 604 | if (argno >= argc) | ||
| 605 | usage(); | ||
| 606 | timeout = atoi(argv[argno++]); | ||
| 607 | } | ||
| 608 | if (timeout <= 0) | ||
| 609 | usage(); | ||
| 610 | } | ||
| 611 | if (argc <= argno) | ||
| 612 | usage(); | ||
| 613 | |||
| 614 | maxfd = fdlim_get(1); | ||
| 615 | if (maxfd < 0) | ||
| 616 | fatal("%s: fdlim_get: bad value", __progname); | ||
| 617 | if (maxfd > MAXMAXFD) | ||
| 618 | maxfd = MAXMAXFD; | ||
| 619 | if (MAXCON <= 0) | ||
| 620 | fatal("%s: not enough file descriptors", __progname); | ||
| 621 | if (maxfd > fdlim_get(0)) | ||
| 622 | fdlim_set(maxfd); | ||
| 623 | fdcon = xmalloc(maxfd * sizeof(con)); | ||
| 624 | memset(fdcon, 0, maxfd * sizeof(con)); | ||
| 625 | |||
| 626 | read_wait_size = howmany(maxfd, NFDBITS) * sizeof(fd_mask); | ||
| 627 | read_wait = xmalloc(read_wait_size); | ||
| 628 | memset(read_wait, 0, read_wait_size); | ||
| 629 | |||
| 630 | do { | ||
| 631 | while (ncon < MAXCON) { | ||
| 632 | char *name; | ||
| 633 | |||
| 634 | host = nexthost(argc, argv); | ||
| 635 | if (host == NULL) | ||
| 636 | break; | ||
| 637 | name = strnnsep(&host, " \t\n"); | ||
| 638 | conalloc(name, *host ? host : name); | ||
| 639 | } | ||
| 640 | conloop(); | ||
| 641 | } while (host); | ||
| 642 | while (ncon > 0) | ||
| 643 | conloop(); | ||
| 644 | |||
| 645 | return (0); | ||
| 646 | } | ||
