| 12
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
 100
 101
 102
 103
 104
 105
 106
 107
 108
 109
 110
 111
 112
 113
 114
 115
 116
 117
 118
 119
 120
 121
 122
 123
 124
 125
 126
 127
 128
 129
 130
 131
 132
 133
 134
 135
 136
 137
 138
 139
 140
 141
 142
 143
 144
 145
 146
 147
 148
 149
 150
 151
 152
 153
 154
 155
 156
 157
 158
 159
 160
 161
 162
 163
 164
 165
 166
 167
 168
 169
 170
 171
 172
 173
 174
 175
 176
 177
 178
 179
 180
 181
 182
 183
 184
 185
 186
 187
 188
 189
 190
 191
 192
 193
 194
 195
 196
 197
 198
 199
 200
 201
 202
 203
 204
 205
 206
 207
 208
 209
 210
 211
 212
 213
 214
 215
 216
 217
 218
 219
 220
 221
 222
 223
 224
 225
 226
 227
 228
 229
 230
 231
 232
 233
 234
 235
 236
 237
 238
 239
 240
 241
 242
 243
 244
 245
 246
 247
 248
 249
 250
 251
 252
 253
 254
 255
 256
 257
 258
 259
 260
 261
 262
 263
 264
 265
 266
 267
 268
 269
 270
 271
 272
 273
 274
 275
 276
 277
 278
 279
 280
 281
 282
 283
 284
 285
 286
 287
 288
 289
 290
 291
 292
 293
 294
 295
 296
 297
 298
 299
 300
 301
 302
 303
 304
 305
 306
 307
 308
 309
 310
 311
 312
 313
 314
 315
 316
 317
 318
 319
 320
 321
 322
 323
 324
 325
 326
 327
 328
 329
 330
 331
 332
 333
 334
 335
 336
 337
 338
 339
 340
 341
 342
 343
 344
 345
 346
 347
 348
 349
 350
 351
 352
 353
 354
 355
 356
 357
 358
 359
 360
 361
 362
 363
 364
 365
 366
 367
 368
 369
 370
 371
 372
 373
 374
 375
 376
 377
 378
 379
 380
 381
 382
 383
 384
 385
 386
 387
 388
 389
 390
 391
 392
 393
 394
 395
 396
 397
 398
 399
 400
 401
 402
 403
 404
 405
 406
 407
 408
 409
 410
 411
 412
 413
 414
 415
 416
 417
 418
 419
 420
 421
 422
 423
 424
 425
 426
 427
 428
 429
 430
 431
 432
 433
 434
 435
 436
 437
 438
 439
 440
 441
 442
 443
 444
 445
 446
 447
 448
 449
 450
 451
 452
 453
 454
 455
 456
 457
 458
 459
 460
 461
 462
 463
 464
 465
 466
 467
 468
 469
 470
 471
 472
 473
 474
 475
 476
 477
 478
 479
 480
 481
 482
 483
 484
 485
 486
 487
 488
 489
 490
 491
 492
 493
 494
 495
 496
 497
 498
 499
 500
 501
 502
 503
 504
 505
 506
 507
 508
 509
 510
 511
 512
 513
 514
 515
 516
 517
 518
 519
 520
 521
 522
 523
 524
 525
 526
 527
 528
 529
 530
 531
 532
 533
 534
 535
 536
 537
 538
 539
 540
 541
 542
 543
 544
 545
 546
 547
 548
 549
 550
 551
 552
 553
 554
 555
 556
 557
 558
 559
 560
 561
 562
 563
 564
 565
 566
 567
 568
 569
 570
 571
 572
 573
 574
 575
 576
 577
 578
 579
 580
 581
 582
 583
 584
 585
 586
 587
 588
 589
 590
 591
 592
 593
 594
 595
 596
 597
 598
 599
 600
 601
 602
 603
 604
 605
 606
 607
 608
 609
 610
 611
 612
 613
 614
 615
 616
 617
 618
 619
 620
 621
 622
 623
 624
 625
 626
 627
 628
 629
 630
 631
 632
 633
 634
 635
 636
 637
 638
 639
 640
 641
 642
 643
 644
 645
 646
 647
 648
 649
 650
 651
 652
 653
 654
 655
 656
 657
 658
 659
 660
 661
 662
 663
 664
 665
 666
 667
 668
 669
 670
 671
 672
 673
 674
 675
 676
 677
 678
 679
 680
 681
 682
 683
 684
 685
 686
 687
 688
 689
 690
 691
 692
 693
 694
 695
 696
 697
 698
 699
 700
 701
 702
 703
 704
 705
 706
 707
 708
 709
 710
 711
 712
 713
 714
 715
 716
 717
 718
 719
 720
 721
 722
 723
 724
 725
 726
 727
 728
 729
 730
 731
 732
 733
 734
 735
 736
 737
 738
 739
 740
 741
 742
 743
 744
 745
 746
 747
 748
 749
 750
 751
 752
 753
 754
 755
 756
 757
 
 | /***************************************************************************
 * util.c -- Various utility functions.                                    *
 ***********************IMPORTANT NMAP LICENSE TERMS************************
 *                                                                         *
 * The Nmap Security Scanner is (C) 1996-2022 Nmap Software LLC ("The Nmap *
 * Project"). Nmap is also a registered trademark of the Nmap Project.     *
 *                                                                         *
 * This program is distributed under the terms of the Nmap Public Source   *
 * License (NPSL). The exact license text applying to a particular Nmap    *
 * release or source code control revision is contained in the LICENSE     *
 * file distributed with that version of Nmap or source code control       *
 * revision. More Nmap copyright/legal information is available from       *
 * https://nmap.org/book/man-legal.html, and further information on the    *
 * NPSL license itself can be found at https://nmap.org/npsl/ . This       *
 * header summarizes some key points from the Nmap license, but is no      *
 * substitute for the actual license text.                                 *
 *                                                                         *
 * Nmap is generally free for end users to download and use themselves,    *
 * including commercial use. It is available from https://nmap.org.        *
 *                                                                         *
 * The Nmap license generally prohibits companies from using and           *
 * redistributing Nmap in commercial products, but we sell a special Nmap  *
 * OEM Edition with a more permissive license and special features for     *
 * this purpose. See https://nmap.org/oem/                                 *
 *                                                                         *
 * If you have received a written Nmap license agreement or contract       *
 * stating terms other than these (such as an Nmap OEM license), you may   *
 * choose to use and redistribute Nmap under those terms instead.          *
 *                                                                         *
 * The official Nmap Windows builds include the Npcap software             *
 * (https://npcap.com) for packet capture and transmission. It is under    *
 * separate license terms which forbid redistribution without special      *
 * permission. So the official Nmap Windows builds may not be              *
 * redistributed without special permission (such as an Nmap OEM           *
 * license).                                                               *
 *                                                                         *
 * Source is provided to this software because we believe users have a     *
 * right to know exactly what a program is going to do before they run it. *
 * This also allows you to audit the software for security holes.          *
 *                                                                         *
 * Source code also allows you to port Nmap to new platforms, fix bugs,    *
 * and add new features.  You are highly encouraged to submit your         *
 * changes as a Github PR or by email to the dev@nmap.org mailing list     *
 * for possible incorporation into the main distribution. Unless you       *
 * specify otherwise, it is understood that you are offering us very       *
 * broad rights to use your submissions as described in the Nmap Public    *
 * Source License Contributor Agreement. This is important because we      *
 * fund the project by selling licenses with various terms, and also       *
 * because the inability to relicense code has caused devastating          *
 * problems for other Free Software projects (such as KDE and NASM).       *
 *                                                                         *
 * The free version of Nmap is distributed in the hope that it will be     *
 * useful, but WITHOUT ANY WARRANTY; without even the implied warranty of  *
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. Warranties,        *
 * indemnification and commercial support are all available through the    *
 * Npcap OEM program--see https://nmap.org/oem/                            *
 *                                                                         *
 ***************************************************************************/
/* $Id: util.c 38416 2022-08-29 17:09:47Z dmiller $ */
#include "sys_wrap.h"
#include "util.h"
#include "ncat.h"
#include "nbase.h"
#include "sockaddr_u.h"
#include <stdio.h>
#ifdef WIN32
#include <iphlpapi.h>
#endif
#include <stdlib.h>
#include <stdarg.h>
#include <string.h>
#if HAVE_SYS_STAT_H
#include <sys/stat.h>
#endif
#if HAVE_FCNTL_H
#include <fcntl.h>
#endif
#if HAVE_UNISTD_H
#include <unistd.h>
#endif
#if HAVE_LINUX_VM_SOCKETS_H
#include <linux/vm_sockets.h>
#endif
/* safely add 2 size_t */
size_t sadd(size_t l, size_t r)
{
    size_t t;
    t = l + r;
    if (t < l)
        bye("integer overflow %lu + %lu.", (u_long) l, (u_long) r);
    return t;
}
/* safely multiply 2 size_t */
size_t smul(size_t l, size_t r)
{
    size_t t;
    t = l * r;
    if (l && t / l != r)
        bye("integer overflow %lu * %lu.", (u_long) l, (u_long) r);
    return t;
}
#ifdef WIN32
void windows_init()
{
    WORD werd;
    WSADATA data;
    werd = MAKEWORD(2, 2);
    if ((WSAStartup(werd, &data)) != 0)
        bye("Failed to start WinSock.");
}
#endif
/* Use this to print debug or diagnostic messages to avoid polluting the user
   stream. */
void loguser(const char *fmt, ...)
{
    va_list ap;
    fprintf(stderr, "%s: ", NCAT_NAME);
    va_start(ap, fmt);
    vfprintf(stderr, fmt, ap);
    va_end(ap);
    fflush(stderr);
}
/* Log a user message without the "Ncat: " prefix, to allow building up a line
   with a series of strings. */
void loguser_noprefix(const char *fmt, ...)
{
    va_list ap;
    va_start(ap, fmt);
    vfprintf(stderr, fmt, ap);
    va_end(ap);
    fflush(stderr);
}
void logdebug(const char *fmt, ...)
{
    va_list ap;
    fprintf(stderr, "NCAT DEBUG: ");
    va_start(ap, fmt);
    vfprintf(stderr, fmt, ap);
    va_end(ap);
    fflush(stderr);
}
void logtest(const char *fmt, ...)
{
    va_list ap;
    fprintf(stderr, "NCAT TEST: ");
    va_start(ap, fmt);
    vfprintf(stderr, fmt, ap);
    va_end(ap);
    fflush(stderr);
}
/* Exit status 2 indicates a program error other than a network error. */
void die(char *err)
{
#ifdef WIN32
  int error_number;
  char *strerror_s;
  error_number = GetLastError();
  FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER|FORMAT_MESSAGE_FROM_SYSTEM,
      NULL, error_number, MAKELANGID (LANG_NEUTRAL, SUBLANG_DEFAULT),
      (LPTSTR) &strerror_s,  0, NULL);
  fprintf(stderr, "%s: %s\n", err, strerror_s);
  HeapFree(GetProcessHeap(), 0, strerror_s);
#else
    perror(err);
#endif
    fflush(stderr);
    exit(2);
}
/* adds newline for you */
void bye(const char *fmt, ...)
{
    va_list ap;
    fprintf(stderr, "%s: ", NCAT_NAME);
    va_start(ap, fmt);
    vfprintf(stderr, fmt, ap);
    va_end(ap);
    fprintf(stderr, " QUITTING.\n");
    fflush(stderr);
    exit(2);
}
/* zero out some mem, bzero() is deprecated */
void zmem(void *mem, size_t n)
{
    memset(mem, 0, n);
}
/* Append n bytes starting at s to a malloc-allocated buffer. Reallocates the
   buffer and updates the variables to make room if necessary. */
int strbuf_append(char **buf, size_t *size, size_t *offset, const char *s, size_t n)
{
    ncat_assert(*offset <= *size);
    if (n >= *size - *offset) {
        *size += n + 1;
        *buf = (char *) safe_realloc(*buf, *size);
    }
    memcpy(*buf + *offset, s, n);
    *offset += n;
    (*buf)[*offset] = '\0';
    return n;
}
/* Append a '\0'-terminated string as with strbuf_append. */
int strbuf_append_str(char **buf, size_t *size, size_t *offset, const char *s)
{
    return strbuf_append(buf, size, offset, s, strlen(s));
}
/* Do a sprintf at the given offset into a malloc-allocated buffer. Reallocates
   the buffer and updates the variables to make room if necessary. */
int strbuf_sprintf(char **buf, size_t *size, size_t *offset, const char *fmt, ...)
{
    va_list va;
    int n;
    ncat_assert(*offset <= *size);
    if (*buf == NULL) {
        *size = 1;
        *buf = (char *) safe_malloc(*size);
    }
    for (;;) {
        va_start(va, fmt);
        n = Vsnprintf(*buf + *offset, *size - *offset, fmt, va);
        va_end(va);
        if (n < 0)
            *size = MAX(*size, 1) * 2;
        else if (n >= *size - *offset)
            *size += n + 1;
        else
            break;
        *buf = (char *) safe_realloc(*buf, *size);
    }
    *offset += n;
    return n;
}
/* Return true if the given address is a local one. */
int addr_is_local(const union sockaddr_u *su)
{
    struct addrinfo hints = { 0 }, *addrs, *addr;
    char hostname[128];
    /* Check loopback addresses. */
    if (su->storage.ss_family == AF_INET) {
        if ((ntohl(su->in.sin_addr.s_addr) & 0xFF000000UL) == 0x7F000000UL)
            return 1;
        if (ntohl(su->in.sin_addr.s_addr) == 0x00000000UL)
            return 1;
    }
#ifdef HAVE_IPV6
    else if (su->storage.ss_family == AF_INET6) {
        if (memcmp(&su->in6.sin6_addr, &in6addr_any, sizeof(su->in6.sin6_addr)) == 0
            || memcmp(&su->in6.sin6_addr, &in6addr_loopback, sizeof(su->in6.sin6_addr)) == 0)
            return 1;
    }
#endif
    /* Check addresses assigned to the local host name. */
    if (gethostname(hostname, sizeof(hostname)) == -1)
        return 0;
    hints.ai_family = su->storage.ss_family;
    if (getaddrinfo(hostname, NULL, &hints, &addrs) != 0)
        return 0;
    for (addr = addrs; addr != NULL; addr = addr->ai_next) {
        union sockaddr_u addr_su;
        if (addr->ai_family != su->storage.ss_family)
            continue;
        if (addr->ai_addrlen > sizeof(addr_su)) {
            bye("getaddrinfo returned oversized address (%lu > %lu)",
                (unsigned long) addr->ai_addrlen, (unsigned long) sizeof(addr_su));
        }
        memcpy(&addr_su, addr->ai_addr, addr->ai_addrlen);
        if (su->storage.ss_family == AF_INET) {
            if (su->in.sin_addr.s_addr == addr_su.in.sin_addr.s_addr)
                break;
        } else if (su->storage.ss_family == AF_INET6) {
            if (memcmp(&su->in6.sin6_addr, &addr_su.in6.sin6_addr, sizeof(su->in6.sin6_addr)) == 0)
                break;
        }
    }
    if (addr != NULL) {
        freeaddrinfo(addrs);
        return 1;
    } else {
        return 0;
    }
}
/* Converts an IP address given in a sockaddr_u to an IPv4 or
   IPv6 IP address string.  Since a static buffer is returned, this is
   not thread-safe and can only be used once in calls like printf()
*/
const char *inet_socktop(const union sockaddr_u *su)
{
    static char buf[INET6_ADDRSTRLEN + 1];
    void *addr;
    if (su->storage.ss_family == AF_INET)
        addr = (void *) &su->in.sin_addr;
#if HAVE_IPV6
    else if (su->storage.ss_family == AF_INET6)
        addr = (void *) &su->in6.sin6_addr;
#endif
    else
        bye("Invalid address family passed to inet_socktop().");
    if (inet_ntop(su->storage.ss_family, addr, buf, sizeof(buf)) == NULL) {
        bye("Failed to convert address to presentation format!  Error: %s.",
            strerror(socket_errno()));
    }
    return buf;
}
/* Returns the port number in HOST BYTE ORDER based on the su's family */
unsigned short inet_port(const union sockaddr_u *su)
{
    if (su->storage.ss_family == AF_INET)
        return ntohs(su->in.sin_port);
#if HAVE_IPV6
    else if (su->storage.ss_family == AF_INET6)
        return ntohs(su->in6.sin6_port);
#endif
    bye("Invalid address family passed to inet_port().");
    return 0;
}
/* Return a listening socket after setting various characteristics on it.
   Returns -1 on error. */
int do_listen(int type, int proto, const union sockaddr_u *srcaddr_u)
{
    int sock = 0, option_on = 1;
    size_t sa_len;
    if (type != SOCK_STREAM && type != SOCK_DGRAM)
        return -1;
    /* We need a socket that can be inherited by child processes in
       ncat_exec_win.c, for --exec and --sh-exec. inheritable_socket is from
       nbase. */
    sock = inheritable_socket(srcaddr_u->storage.ss_family, type, proto);
    if (sock < 0)
        return -1;
    Setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &option_on, sizeof(int));
/* IPPROTO_IPV6 is defined in Visual C++ only when _WIN32_WINNT >= 0x501.
   Nbase's nbase_winunix.h defines _WIN32_WINNT to a lower value for
   compatibility with older versions of Windows. This code disables IPv6 sockets
   that also receive IPv4 connections. This is the default on Windows anyway so
   it doesn't make a difference.
   http://support.microsoft.com/kb/950688
   http://msdn.microsoft.com/en-us/library/bb513665
*/
#ifdef IPPROTO_IPV6
#ifdef IPV6_V6ONLY
    if (srcaddr_u->storage.ss_family == AF_INET6) {
        int set = 1;
        /* Tell it to not try and bind to IPV4 */
        if (setsockopt(sock, IPPROTO_IPV6, IPV6_V6ONLY, &set, sizeof(set)) == -1)
            die("Unable to set IPV6 socket to bind only to IPV6");
    }
#endif
#endif
    switch(srcaddr_u->storage.ss_family) {
#ifdef HAVE_SYS_UN_H
      case AF_UNIX:
        sa_len = SUN_LEN(&srcaddr_u->un);
        break;
#endif
#ifdef HAVE_LINUX_VM_SOCKETS_H
      case AF_VSOCK:
        sa_len = sizeof (struct sockaddr_vm);
        break;
#endif
#ifdef HAVE_SOCKADDR_SA_LEN
      default:
        sa_len = srcaddr_u->sockaddr.sa_len;
        break;
#else
      case AF_INET:
        sa_len = sizeof (struct sockaddr_in);
        break;
#ifdef AF_INET6
      case AF_INET6:
        sa_len = sizeof (struct sockaddr_in6);
        break;
#endif
      default:
        sa_len = sizeof(*srcaddr_u);
        break;
#endif
    }
    if (bind(sock, &srcaddr_u->sockaddr, sa_len) < 0) {
#ifdef HAVE_SYS_UN_H
        if (srcaddr_u->storage.ss_family == AF_UNIX)
            bye("bind to %s: %s.", srcaddr_u->un.sun_path,
                socket_strerror(socket_errno()));
        else
#endif
#ifdef HAVE_LINUX_VM_SOCKETS_H
        if (srcaddr_u->storage.ss_family == AF_VSOCK)
            bye("bind to %u:%u: %s.",
                srcaddr_u->vm.svm_cid,
                srcaddr_u->vm.svm_port,
                socket_strerror(socket_errno()));
        else
#endif
            bye("bind to %s:%hu: %s.", inet_socktop(srcaddr_u),
                inet_port(srcaddr_u), socket_strerror(socket_errno()));
    }
    if (type == SOCK_STREAM)
        Listen(sock, BACKLOG);
    if (o.verbose) {
#ifdef HAVE_SYS_UN_H
        if (srcaddr_u->storage.ss_family == AF_UNIX)
            loguser("Listening on %s\n", srcaddr_u->un.sun_path);
        else
#endif
#ifdef HAVE_LINUX_VM_SOCKETS_H
        if (srcaddr_u->storage.ss_family == AF_VSOCK)
            loguser("Listening on %u:%u\n",
                    srcaddr_u->vm.svm_cid,
                    srcaddr_u->vm.svm_port);
        else
#endif
            loguser("Listening on %s:%hu\n", inet_socktop(srcaddr_u), inet_port(srcaddr_u));
    }
    if (o.test)
        logtest("LISTEN\n");
    return sock;
}
/* Only used in proxy connect functions, so doesn't need to support address
 * families that don't support proxying like AF_UNIX and AF_VSOCK */
int do_connect(int type)
{
    int sock = 0;
    if (type != SOCK_STREAM && type != SOCK_DGRAM)
        return -1;
    /* We need a socket that can be inherited by child processes in
       ncat_exec_win.c, for --exec and --sh-exec. inheritable_socket is from
       nbase. */
    sock = inheritable_socket(targetaddrs->addr.storage.ss_family, type, 0);
    if (srcaddr.storage.ss_family != AF_UNSPEC) {
        size_t sa_len;
#ifdef HAVE_SOCKADDR_SA_LEN
        sa_len = srcaddr.sockaddr.sa_len;
#else
        sa_len = sizeof(srcaddr);
#endif
        if (bind(sock, &srcaddr.sockaddr, sa_len) < 0) {
            bye("bind to %s:%hu: %s.", inet_socktop(&srcaddr),
                inet_port(&srcaddr), socket_strerror(socket_errno()));
        }
    }
    if (sock != -1) {
        if (connect(sock, &targetaddrs->addr.sockaddr, (int) targetaddrs->addrlen) != -1)
            return sock;
        else if (socket_errno() == EINPROGRESS || socket_errno() == EAGAIN)
            return sock;
    }
    return -1;
}
unsigned char *buildsrcrte(struct in_addr dstaddr, struct in_addr routes[],
                  int numroutes, int ptr, size_t *len)
{
    int x;
    unsigned char *opts, *p;
    *len = (numroutes + 1) * sizeof(struct in_addr) + 4;
    if (numroutes > 8)
        bye("Bad number of routes passed to buildsrcrte().");
    opts = (unsigned char *) safe_malloc(*len);
    p = opts;
    zmem(opts, *len);
    *p++ = 0x01; /* IPOPT_NOP, for alignment */
    *p++ = 0x83; /* IPOPT_LSRR */
    *p++ = (char) (*len - 1); /* subtract nop */
    *p++ = (char) ptr;
    for (x = 0; x < numroutes; x++) {
        memcpy(p, &routes[x], sizeof(routes[x]));
        p += sizeof(routes[x]);
    }
    memcpy(p, &dstaddr, sizeof(dstaddr));
    return opts;
}
int allow_access(const union sockaddr_u *su)
{
    /* A host not in the allow set is denied, but only if the --allow or
       --allowfile option was given. */
    if (o.allow && !addrset_contains(o.allowset, &su->sockaddr))
        return 0;
    if (addrset_contains(o.denyset, &su->sockaddr))
        return 0;
    return 1;
}
/*
 * Fills the given timeval struct with proper
 * values based on the given time in milliseconds.
 * The pointer to timeval struct must NOT be NULL.
 */
void ms_to_timeval(struct timeval *tv, long ms)
{
    tv->tv_sec = ms / 1000;
    tv->tv_usec = (ms - (tv->tv_sec * 1000)) * 1000;
}
/*
 * ugly code to maintain our list of fds so we can have proper fdmax for
 * select().  really this should be generic list code, not this silly bit of
 * stupidity. -sean
 */
/* add an fdinfo to our list */
int add_fdinfo(fd_list_t *fdl, struct fdinfo *s)
{
    if (fdl->nfds >= fdl->maxfds)
        return -1;
    fdl->fds[fdl->nfds] = *s;
    fdl->nfds++;
    if (s->fd > fdl->fdmax)
        fdl->fdmax = s->fd;
    if (o.debug > 1)
        logdebug("Added fd %d to list, nfds %d, maxfd %d\n", s->fd, fdl->nfds, fdl->fdmax);
    return 0;
}
/* Add a descriptor to the list. Use this when you are only adding to the list
 * for the side effect of increasing fdmax, and don't care about fdinfo
 * members. */
int add_fd(fd_list_t *fdl, int fd)
{
    struct fdinfo info = { 0 };
    info.fd = fd;
    return add_fdinfo(fdl, &info);
}
/* remove a descriptor from our list */
int rm_fd(fd_list_t *fdl, int fd)
{
    int x = 0, last = fdl->nfds;
    /* make sure we have a list */
    if (last == 0)
        bye("Program bug: Trying to remove fd from list with no fds.");
    /* find the fd in the list */
    for (x = 0; x < last; x++)
        if (fdl->fds[x].fd == fd)
            break;
    /* make sure we found it */
    if (x == last)
        bye("Program bug: fd (%d) not on list.", fd);
    /* remove it, does nothing if (last == 1) */
    if (o.debug > 1)
        logdebug("Swapping fd[%d] (%d) with fd[%d] (%d)\n",
                 x, fdl->fds[x].fd, last - 1, fdl->fds[last - 1].fd);
    fdl->fds[x] = fdl->fds[last - 1];
    fdl->nfds--;
    /* was it the max */
    if (fd == fdl->fdmax)
        fdl->fdmax = get_maxfd(fdl);
    if (o.debug > 1)
        logdebug("Removed fd %d from list, nfds %d, maxfd %d\n", fd, fdl->nfds, fdl->fdmax);
    return 0;
}
/* find the max descriptor in our list */
int get_maxfd(fd_list_t *fdl)
{
    int x = 0, max = -1, nfds = fdl->nfds;
    for (x = 0; x < nfds; x++)
        if (fdl->fds[x].fd > max)
            max = fdl->fds[x].fd;
    return max;
}
struct fdinfo *get_fdinfo(const fd_list_t *fdl, int fd)
{
    int x;
    for (x = 0; x < fdl->nfds; x++)
        if (fdl->fds[x].fd == fd)
            return &fdl->fds[x];
    return NULL;
}
void init_fdlist(fd_list_t *fdl, int maxfds)
{
    fdl->fds = (struct fdinfo *) Calloc(maxfds, sizeof(struct fdinfo));
    fdl->nfds = 0;
    fdl->fdmax = -1;
    fdl->maxfds = maxfds;
    if (o.debug > 1)
        logdebug("Initialized fdlist with %d maxfds\n", maxfds);
}
void free_fdlist(fd_list_t *fdl)
{
    free(fdl->fds);
    fdl->nfds = 0;
    fdl->fdmax = -1;
}
/*  If any changes need to be made to EOL sequences to comply with --crlf
 *  then dst will be populated with the modified src, len will be adjusted
 *  accordingly and the return will be non-zero.
 *
 *  state is used to keep track of line endings that span more than one call to
 *  this function. On the first call, state should be a pointer to a int
 *  containing 0. Thereafter, keep passing the same pointer. Separate logical
 *  streams should use separate state pointers.
 *
 *  Returns 0 if changes were not made - len and dst will remain untouched.
 */
int fix_line_endings(char *src, int *len, char **dst, int *state)
{
    int fix_count;
    int i, j;
    int num_bytes = *len;
    int prev_state = *state;
    /* *state is true iff the last byte of the previous block was \r. */
    if (num_bytes > 0)
        *state = (src[num_bytes - 1] == '\r');
    /* get count of \n without matching \r */
    fix_count = 0;
    for (i = 0; i < num_bytes; i++) {
        if (src[i] == '\n' && ((i == 0) ? !prev_state : src[i - 1] != '\r'))
            fix_count++;
    }
    if (fix_count <= 0)
        return 0;
    /* now insert matching \r */
    *dst = (char *) safe_malloc(num_bytes + fix_count);
    j = 0;
    for (i = 0; i < num_bytes; i++) {
        if (src[i] == '\n' && ((i == 0) ? !prev_state : src[i - 1] != '\r')) {
            memcpy(*dst + j, "\r\n", 2);
            j += 2;
        } else {
            memcpy(*dst + j, src + i, 1);
            j++;
        }
    }
    *len += fix_count;
    return 1;
}
/*-
 * next_protos_parse parses a comma separated list of strings into a string
 * in a format suitable for passing to SSL_CTX_set_next_protos_advertised.
 *   outlen: (output) set to the length of the resulting buffer on success.
 *   err: NULL on failure
 *   in: a NULL terminated string like "abc,def,ghi"
 *
 *   returns: a malloc'd buffer or NULL on failure.
 */
unsigned char *next_protos_parse(size_t *outlen, const char *in)
{
    size_t len;
    unsigned char *out;
    size_t i, start = 0;
    len = strlen(in);
    if (len >= 65535)
        return NULL;
    out = (unsigned char *)safe_malloc(strlen(in) + 1);
    for (i = 0; i <= len; ++i) {
        if (i == len || in[i] == ',') {
            if (i - start > 255) {
                free(out);
                return NULL;
            }
            out[start] = i - start;
            start = i + 1;
        } else
            out[i + 1] = in[i];
    }
    *outlen = len + 1;
    return out;
}
 |