socket.c 107 KB
Newer Older
1
2
3
4
5
6
7
/*
 *  OpenVPN -- An application to securely tunnel IP networks
 *             over a single TCP/UDP port, with support for SSL/TLS-based
 *             session authentication and key exchange,
 *             packet encryption, packet authentication, and
 *             packet compression.
 *
Antonio's avatar
Antonio committed
8
 *  Copyright (C) 2002-2022 OpenVPN Inc <sales@openvpn.net>
9
10
11
12
13
14
15
16
17
18
 *
 *  This program is free software; you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License version 2
 *  as published by the Free Software Foundation.
 *
 *  This program 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.  See the
 *  GNU General Public License for more details.
 *
19
20
21
 *  You should have received a copy of the GNU General Public License along
 *  with this program; if not, write to the Free Software Foundation, Inc.,
 *  51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
22
23
 */

24
25
26
27
28
29
#ifdef HAVE_CONFIG_H
#include "config.h"
#elif defined(_MSC_VER)
#include "config-msvc.h"
#endif

30
31
32
33
34
35
36
#include "syshead.h"

#include "socket.h"
#include "fdmisc.h"
#include "misc.h"
#include "gremlin.h"
#include "plugin.h"
37
#include "ps.h"
38
#include "run_command.h"
james's avatar
james committed
39
#include "manage.h"
james's avatar
james committed
40
#include "misc.h"
41
#include "manage.h"
42
#include "openvpn.h"
43
#include "forward.h"
44
45
46

#include "memdbg.h"

james's avatar
james committed
47
48
49
50
/*
 * Convert sockflags/getaddr_flags into getaddr_flags
 */
static unsigned int
51
sf2gaf(const unsigned int getaddr_flags,
james's avatar
james committed
52
53
       const unsigned int sockflags)
{
54
55
56
57
58
59
60
61
    if (sockflags & SF_HOST_RANDOMIZE)
    {
        return getaddr_flags | GETADDR_RANDOMIZE;
    }
    else
    {
        return getaddr_flags;
    }
james's avatar
james committed
62
63
}

64
65
66
/*
 * Functions related to the translation of DNS names to IP addresses.
 */
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
static int
get_addr_generic(sa_family_t af, unsigned int flags, const char *hostname,
                 void *network, unsigned int *netbits,
                 int resolve_retry_seconds, volatile int *signal_received,
                 int msglevel)
{
    char *endp, *sep, *var_host = NULL;
    struct addrinfo *ai = NULL;
    unsigned long bits;
    uint8_t max_bits;
    int ret = -1;

    if (!hostname)
    {
        msg(M_NONFATAL, "Can't resolve null hostname!");
        goto out;
    }

    /* assign family specific default values */
    switch (af)
    {
        case AF_INET:
            bits = 0;
            max_bits = sizeof(in_addr_t) * 8;
            break;
Gert Doering's avatar
Gert Doering committed
92

93
94
95
96
        case AF_INET6:
            bits = 64;
            max_bits = sizeof(struct in6_addr) * 8;
            break;
Gert Doering's avatar
Gert Doering committed
97

98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
        default:
            msg(M_WARN,
                "Unsupported AF family passed to getaddrinfo for %s (%d)",
                hostname, af);
            goto out;
    }

    /* we need to modify the hostname received as input, but we don't want to
     * touch it directly as it might be a constant string.
     *
     * Therefore, we clone the string here and free it at the end of the
     * function */
    var_host = strdup(hostname);
    if (!var_host)
    {
        msg(M_NONFATAL | M_ERRNO,
            "Can't allocate hostname buffer for getaddrinfo");
        goto out;
    }

    /* check if this hostname has a /bits suffix */
Gert Doering's avatar
Gert Doering committed
119
    sep = strchr(var_host, '/');
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
    if (sep)
    {
        bits = strtoul(sep + 1, &endp, 10);
        if ((*endp != '\0') || (bits > max_bits))
        {
            msg(msglevel, "IP prefix '%s': invalid '/bits' spec (%s)", hostname,
                sep + 1);
            goto out;
        }
        *sep = '\0';
    }

    ret = openvpn_getaddrinfo(flags & ~GETADDR_HOST_ORDER, var_host, NULL,
                              resolve_retry_seconds, signal_received, af, &ai);
    if ((ret == 0) && network)
    {
        struct in6_addr *ip6;
        in_addr_t *ip4;

        switch (af)
        {
            case AF_INET:
                ip4 = network;
                *ip4 = ((struct sockaddr_in *)ai->ai_addr)->sin_addr.s_addr;

                if (flags & GETADDR_HOST_ORDER)
                {
                    *ip4 = ntohl(*ip4);
                }
                break;
Gert Doering's avatar
Gert Doering committed
150

151
152
153
154
            case AF_INET6:
                ip6 = network;
                *ip6 = ((struct sockaddr_in6 *)ai->ai_addr)->sin6_addr;
                break;
Gert Doering's avatar
Gert Doering committed
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
            default:
                /* can't get here because 'af' was previously checked */
                msg(M_WARN,
                    "Unsupported AF family for %s (%d)", var_host, af);
                goto out;
        }
    }

    if (netbits)
    {
        *netbits = bits;
    }

    /* restore '/' separator, if any */
    if (sep)
    {
        *sep = '/';
    }
out:
    freeaddrinfo(ai);
    free(var_host);

    return ret;
}
180
181

in_addr_t
182
183
184
185
186
187
getaddr(unsigned int flags,
        const char *hostname,
        int resolve_retry_seconds,
        bool *succeeded,
        volatile int *signal_received)
{
188
    in_addr_t addr;
189
    int status;
190
191
192
193

    status = get_addr_generic(AF_INET, flags, hostname, &addr, NULL,
                              resolve_retry_seconds, signal_received,
                              M_WARN);
194
195
196
197
198
199
    if (status==0)
    {
        if (succeeded)
        {
            *succeeded = true;
        }
200
        return addr;
201
202
203
204
205
206
207
208
209
    }
    else
    {
        if (succeeded)
        {
            *succeeded = false;
        }
        return 0;
    }
210
211
}

212
213
214
215
216
217
218
219
220
221
222
223
224
bool
get_ipv6_addr(const char *hostname, struct in6_addr *network,
              unsigned int *netbits, int msglevel)
{
    if (get_addr_generic(AF_INET6, GETADDR_RESOLVE, hostname, network, netbits,
                         0, NULL, msglevel) < 0)
    {
        return false;
    }

    return true;                /* parsing OK, values set */
}

225
static inline bool
226
streqnull(const char *a, const char *b)
227
{
228
229
230
231
232
233
234
235
236
237
238
239
    if (a == NULL && b == NULL)
    {
        return true;
    }
    else if (a == NULL || b == NULL)
    {
        return false;
    }
    else
    {
        return streq(a, b);
    }
240
241
242
}

/*
243
244
 * get_cached_dns_entry return 0 on success and -1
 * otherwise. (like getaddrinfo)
245
246
 */
static int
247
248
249
250
251
252
get_cached_dns_entry(struct cached_dns_entry *dns_cache,
                     const char *hostname,
                     const char *servname,
                     int ai_family,
                     int resolve_flags,
                     struct addrinfo **ai)
253
{
254
255
    struct cached_dns_entry *ph;
    int flags;
256

257
258
    /* Only use flags that are relevant for the structure */
    flags = resolve_flags & GETADDR_CACHE_MASK;
259

260
    for (ph = dns_cache; ph; ph = ph->next)
261
    {
262
263
264
265
266
267
268
269
        if (streqnull(ph->hostname, hostname)
            && streqnull(ph->servname, servname)
            && ph->ai_family == ai_family
            && ph->flags == flags)
        {
            *ai = ph->ai;
            return 0;
        }
270
    }
271
    return -1;
272
273
274
275
}


static int
276
277
278
279
280
do_preresolve_host(struct context *c,
                   const char *hostname,
                   const char *servname,
                   const int af,
                   const int flags)
281
{
282
283
    struct addrinfo *ai;
    int status;
284

285
286
287
288
289
290
    if (get_cached_dns_entry(c->c1.dns_cache,
                             hostname,
                             servname,
                             af,
                             flags,
                             &ai) == 0)
291
    {
292
293
        /* entry already cached, return success */
        return 0;
294
295
    }

296
297
298
299
    status = openvpn_getaddrinfo(flags, hostname, servname,
                                 c->options.resolve_retry_seconds, NULL,
                                 af, &ai);
    if (status == 0)
300
    {
301
        struct cached_dns_entry *ph;
302

303
304
305
306
307
        ALLOC_OBJ_CLEAR_GC(ph, struct cached_dns_entry, &c->gc);
        ph->ai = ai;
        ph->hostname = hostname;
        ph->servname = servname;
        ph->flags = flags & GETADDR_CACHE_MASK;
308

309
310
311
312
313
314
315
316
        if (!c->c1.dns_cache)
        {
            c->c1.dns_cache = ph;
        }
        else
        {
            struct cached_dns_entry *prev = c->c1.dns_cache;
            while (prev->next)
317
            {
318
                prev = prev->next;
319
            }
320
321
            prev->next = ph;
        }
322

323
        gc_addspecial(ai, &gc_freeaddrinfo_callback, &c->gc);
324
325

    }
326
    return status;
327
328
329
}

void
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
do_preresolve(struct context *c)
{
    int i;
    struct connection_list *l = c->options.connection_list;
    const unsigned int preresolve_flags = GETADDR_RESOLVE
                                          |GETADDR_UPDATE_MANAGEMENT_STATE
                                          |GETADDR_MENTION_RESOLVE_RETRY
                                          |GETADDR_FATAL;


    for (i = 0; i < l->len; ++i)
    {
        int status;
        const char *remote;
        int flags = preresolve_flags;

        struct connection_entry *ce = c->options.connection_list->array[i];

        if (proto_is_dgram(ce->proto))
        {
            flags |= GETADDR_DATAGRAM;
        }

        if (c->options.sockflags & SF_HOST_RANDOMIZE)
        {
            flags |= GETADDR_RANDOMIZE;
        }

        if (c->options.ip_remote_hint)
        {
            remote = c->options.ip_remote_hint;
        }
        else
        {
            remote = ce->remote;
        }

        /* HTTP remote hostname does not need to be resolved */
        if (!ce->http_proxy_options)
        {
370
371
            status = do_preresolve_host(c, remote, ce->remote_port,
                                        ce->af, flags);
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
            if (status != 0)
            {
                goto err;
            }
        }

        /* Preresolve proxy */
        if (ce->http_proxy_options)
        {
            status = do_preresolve_host(c,
                                        ce->http_proxy_options->server,
                                        ce->http_proxy_options->port,
                                        ce->af,
                                        preresolve_flags);

            if (status != 0)
            {
                goto err;
            }
        }

        if (ce->socks_proxy_server)
        {
            status = do_preresolve_host(c,
                                        ce->socks_proxy_server,
                                        ce->socks_proxy_port,
                                        ce->af,
                                        flags);
            if (status != 0)
            {
                goto err;
            }
        }

        if (ce->bind_local)
        {
            flags |= GETADDR_PASSIVE;
            flags &= ~GETADDR_RANDOMIZE;
410
411
            status = do_preresolve_host(c, ce->local, ce->local_port,
                                        ce->af, flags);
412
413
414
415
416
417
            if (status != 0)
            {
                goto err;
            }

        }
418
419
420
421

    }
    return;

422
423
err:
    throw_signal_soft(SIGHUP, "Preresolving failed");
424
}
425

426
/*
427
428
 * Translate IPv4/IPv6 addr or hostname into struct addrinfo
 * If resolve error, try again for resolve_retry_seconds seconds.
429
 */
430
int
431
432
433
434
435
436
437
openvpn_getaddrinfo(unsigned int flags,
                    const char *hostname,
                    const char *servname,
                    int resolve_retry_seconds,
                    volatile int *signal_received,
                    int ai_family,
                    struct addrinfo **res)
438
{
439
440
441
442
443
444
445
    struct addrinfo hints;
    int status;
    int sigrec = 0;
    int msglevel = (flags & GETADDR_FATAL) ? M_FATAL : D_RESOLVE_ERRORS;
    struct gc_arena gc = gc_new();
    const char *print_hostname;
    const char *print_servname;
446

447
    ASSERT(res);
448

449
450
    ASSERT(hostname || servname);
    ASSERT(!(flags & GETADDR_HOST_ORDER));
451

452
453
454
455
456
457
458
459
    if (servname)
    {
        print_servname = servname;
    }
    else
    {
        print_servname = "";
    }
460

461
462
463
464
    if (flags & GETADDR_MSG_VIRT_OUT)
    {
        msglevel |= M_MSG_VIRT_OUT;
    }
465

466
467
468
469
470
    if ((flags & (GETADDR_FATAL_ON_SIGNAL|GETADDR_WARN_ON_SIGNAL))
        && !signal_received)
    {
        signal_received = &sigrec;
    }
471

472
473
474
475
    /* try numeric ipv6 addr first */
    CLEAR(hints);
    hints.ai_family = ai_family;
    hints.ai_flags = AI_NUMERICHOST;
476

477
478
479
480
    if (flags & GETADDR_PASSIVE)
    {
        hints.ai_flags |= AI_PASSIVE;
    }
481

482
483
484
485
486
487
488
489
    if (flags & GETADDR_DATAGRAM)
    {
        hints.ai_socktype = SOCK_DGRAM;
    }
    else
    {
        hints.ai_socktype = SOCK_STREAM;
    }
490

491
    status = getaddrinfo(hostname, servname, &hints, res);
492

493
    if (status != 0) /* parse as numeric address failed? */
494
    {
495
496
497
498
499
500
        const int fail_wait_interval = 5; /* seconds */
        /* Add +4 to cause integer division rounding up (1 + 4) = 5, (0+4)/5=0 */
        int resolve_retries = (flags & GETADDR_TRY_ONCE) ? 1 :
                              ((resolve_retry_seconds + 4)/ fail_wait_interval);
        const char *fmt;
        int level = 0;
501

502
503
504
505
506
507
508
509
510
511
512
513
514
515
        if (hostname && (flags & GETADDR_RANDOMIZE))
        {
            hostname = hostname_randomize(hostname, &gc);
        }

        if (hostname)
        {
            print_hostname = hostname;
        }
        else
        {
            print_hostname = "undefined";
        }

516
517
518
519
        fmt = "RESOLVE: Cannot resolve host address: %s:%s (%s)";
        if ((flags & GETADDR_MENTION_RESOLVE_RETRY)
            && !resolve_retry_seconds)
        {
520
521
522
            fmt = "RESOLVE: Cannot resolve host address: %s:%s (%s) "
                  "(I would have retried this name query if you had "
                  "specified the --resolv-retry option.)";
523
        }
524

525
        if (!(flags & GETADDR_RESOLVE) || status == EAI_FAIL)
526
        {
527
            msg(msglevel, "RESOLVE: Cannot parse IP address: %s:%s (%s)",
528
                print_hostname, print_servname, gai_strerror(status));
529
            goto done;
530
        }
531
532

#ifdef ENABLE_MANAGEMENT
533
        if (flags & GETADDR_UPDATE_MANAGEMENT_STATE)
534
        {
535
536
537
538
539
540
541
542
543
544
            if (management)
            {
                management_set_state(management,
                                     OPENVPN_STATE_RESOLVE,
                                     NULL,
                                     NULL,
                                     NULL,
                                     NULL,
                                     NULL);
            }
545
        }
546
547
#endif

548
549
550
551
        /*
         * Resolve hostname
         */
        while (true)
552
        {
Gert Doering's avatar
Gert Doering committed
553
#ifndef _WIN32
554
            /* force resolv.conf reload */
555
            res_init();
556
#endif
557
558
            /* try hostname lookup */
            hints.ai_flags &= ~AI_NUMERICHOST;
559
560
            dmsg(D_SOCKET_DEBUG,
                 "GETADDRINFO flags=0x%04x ai_family=%d ai_socktype=%d",
561
562
                 flags, hints.ai_family, hints.ai_socktype);
            status = getaddrinfo(hostname, servname, &hints, res);
563

564
            if (signal_received)
565
            {
566
567
                get_signal(signal_received);
                if (*signal_received) /* were we interrupted by a signal? */
568
                {
569
                    if (*signal_received == SIGUSR1) /* ignore SIGUSR1 */
570
                    {
571
572
573
                        msg(level,
                            "RESOLVE: Ignored SIGUSR1 signal received during "
                            "DNS resolution attempt");
574
                        *signal_received = 0;
575
                    }
576
                    else
577
                    {
578
579
580
581
582
583
584
585
586
587
                        /* turn success into failure (interrupted syscall) */
                        if (0 == status)
                        {
                            ASSERT(res);
                            freeaddrinfo(*res);
                            *res = NULL;
                            status = EAI_AGAIN; /* = temporary failure */
                            errno = EINTR;
                        }
                        goto done;
588
                    }
589
590
                }
            }
591

592
593
594
595
596
            /* success? */
            if (0 == status)
            {
                break;
            }
597

598
599
600
601
602
603
604
            /* resolve lookup failed, should we
             * continue or fail? */
            level = msglevel;
            if (resolve_retries > 0)
            {
                level = D_RESOLVE_ERRORS;
            }
605

606
607
608
609
610
            msg(level,
                fmt,
                print_hostname,
                print_servname,
                gai_strerror(status));
611

612
613
614
615
            if (--resolve_retries <= 0)
            {
                goto done;
            }
616

617
            management_sleep(fail_wait_interval);
618
619
        }

620
        ASSERT(res);
621

622
        /* hostname resolve succeeded */
623

624
625
626
627
        /*
         * Do not choose an IP Addresse by random or change the order *
         * of IP addresses, doing so will break RFC 3484 address selection *
         */
628
    }
629
    else
630
    {
631
        /* IP address parse succeeded */
632
633
        if (flags & GETADDR_RANDOMIZE)
        {
634
635
636
            msg(M_WARN,
                "WARNING: ignoring --remote-random-hostname because the "
                "hostname is an IP address");
637
        }
638
639
    }

640
641
done:
    if (signal_received && *signal_received)
642
    {
643
644
645
646
647
648
649
650
651
652
        int level = 0;
        if (flags & GETADDR_FATAL_ON_SIGNAL)
        {
            level = M_FATAL;
        }
        else if (flags & GETADDR_WARN_ON_SIGNAL)
        {
            level = M_WARN;
        }
        msg(level, "RESOLVE: signal received during DNS resolution attempt");
653
654
    }

655
656
    gc_free(&gc);
    return status;
657
658
}

659
660
661
662
663
/*
 * We do our own inet_aton because the glibc function
 * isn't very good about error checking.
 */
int
664
openvpn_inet_aton(const char *dotted_quad, struct in_addr *addr)
665
{
666
    unsigned int a, b, c, d;
667

668
669
    CLEAR(*addr);
    if (sscanf(dotted_quad, "%u.%u.%u.%u", &a, &b, &c, &d) == 4)
670
    {
671
672
673
674
675
676
677
678
679
680
681
682
683
        if (a < 256 && b < 256 && c < 256 && d < 256)
        {
            addr->s_addr = htonl(a<<24 | b<<16 | c<<8 | d);
            return OIA_IP; /* good dotted quad */
        }
    }
    if (string_class(dotted_quad, CC_DIGIT|CC_DOT, 0))
    {
        return OIA_ERROR; /* probably a badly formatted dotted quad */
    }
    else
    {
        return OIA_HOSTNAME; /* probably a hostname */
684
685
686
    }
}

687
bool
688
ip_addr_dotted_quad_safe(const char *dotted_quad)
689
{
690
691
692
693
694
    /* verify non-NULL */
    if (!dotted_quad)
    {
        return false;
    }
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
    /* verify length is within limits */
    if (strlen(dotted_quad) > 15)
    {
        return false;
    }

    /* verify that all chars are either numeric or '.' and that no numeric
     * substring is greater than 3 chars */
    {
        int nnum = 0;
        const char *p = dotted_quad;
        int c;

        while ((c = *p++))
        {
            if (c >= '0' && c <= '9')
            {
                ++nnum;
                if (nnum > 3)
                {
                    return false;
                }
            }
            else if (c == '.')
            {
                nnum = 0;
            }
            else
            {
                return false;
            }
        }
    }
729

730
731
732
733
734
    /* verify that string will convert to IP address */
    {
        struct in_addr a;
        return openvpn_inet_aton(dotted_quad, &a) == OIA_IP;
    }
735
736
}

737
bool
738
ipv6_addr_safe(const char *ipv6_text_addr)
739
{
740
741
742
743
744
    /* verify non-NULL */
    if (!ipv6_text_addr)
    {
        return false;
    }
745

746
747
748
749
750
    /* verify length is within limits */
    if (strlen(ipv6_text_addr) > INET6_ADDRSTRLEN)
    {
        return false;
    }
751

752
753
754
755
756
    /* verify that string will convert to IPv6 address */
    {
        struct in6_addr a6;
        return inet_pton( AF_INET6, ipv6_text_addr, &a6 ) == 1;
    }
757
758
}

759
static bool
760
dns_addr_safe(const char *addr)
761
{
762
    if (addr)
763
    {
764
765
766
767
768
769
        const size_t len = strlen(addr);
        return len > 0 && len <= 255 && string_class(addr, CC_ALNUM|CC_DASH|CC_DOT, 0);
    }
    else
    {
        return false;
770
771
772
    }
}

773
bool
774
ip_or_dns_addr_safe(const char *addr, const bool allow_fqdn)
775
{
776
777
778
779
780
781
782
783
784
785
786
787
    if (ip_addr_dotted_quad_safe(addr))
    {
        return true;
    }
    else if (allow_fqdn)
    {
        return dns_addr_safe(addr);
    }
    else
    {
        return false;
    }
788
789
}

790
bool
791
mac_addr_safe(const char *mac_addr)
792
{
793
794
795
796
797
    /* verify non-NULL */
    if (!mac_addr)
    {
        return false;
    }
798

799
800
801
802
803
    /* verify length is within limits */
    if (strlen(mac_addr) > 17)
    {
        return false;
    }
804

805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
    /* verify that all chars are either alphanumeric or ':' and that no
     * alphanumeric substring is greater than 2 chars */
    {
        int nnum = 0;
        const char *p = mac_addr;
        int c;

        while ((c = *p++))
        {
            if ( (c >= '0' && c <= '9') || (c >= 'a' && c <= 'f') || (c >= 'A' && c <= 'F') )
            {
                ++nnum;
                if (nnum > 2)
                {
                    return false;
                }
            }
            else if (c == ':')
            {
                nnum = 0;
            }
            else
            {
                return false;
            }
        }
    }

    /* error-checking is left to script invoked in lladdr.c */
    return true;
835
836
}

837
static int
838
socket_get_sndbuf(socket_descriptor_t sd)
839
{
840
#if defined(SOL_SOCKET) && defined(SO_SNDBUF)
841
842
    int val;
    socklen_t len;
843

844
845
846
847
848
849
    len = sizeof(val);
    if (getsockopt(sd, SOL_SOCKET, SO_SNDBUF, (void *) &val, &len) == 0
        && len == sizeof(val))
    {
        return val;
    }
850
#endif
851
    return 0;
852
853
854
}

static void
855
socket_set_sndbuf(socket_descriptor_t sd, int size)
856
{
857
#if defined(SOL_SOCKET) && defined(SO_SNDBUF)
858
    if (setsockopt(sd, SOL_SOCKET, SO_SNDBUF, (void *) &size, sizeof(size)) != 0)
859
    {
860
        msg(M_WARN, "NOTE: setsockopt SO_SNDBUF=%d failed", size);
861
862
863
864
865
    }
#endif
}

static int
866
socket_get_rcvbuf(socket_descriptor_t sd)
867
{
868
#if defined(SOL_SOCKET) && defined(SO_RCVBUF)
869
870
    int val;
    socklen_t len;
871

872
873
874
875
876
877
    len = sizeof(val);
    if (getsockopt(sd, SOL_SOCKET, SO_RCVBUF, (void *) &val, &len) == 0
        && len == sizeof(val))
    {
        return val;
    }
878
#endif
879
    return 0;
880
881
882
}

static bool
883
socket_set_rcvbuf(socket_descriptor_t sd, int size)
884
{
885
#if defined(SOL_SOCKET) && defined(SO_RCVBUF)
886
    if (setsockopt(sd, SOL_SOCKET, SO_RCVBUF, (void *) &size, sizeof(size)) != 0)
887
    {
888
889
        msg(M_WARN, "NOTE: setsockopt SO_RCVBUF=%d failed", size);
        return false;
890
    }
891
    return true;
892
893
894
895
#endif
}

static void
896
socket_set_buffers(socket_descriptor_t fd, const struct socket_buffer_size *sbs)
897
{
898
    if (sbs)
899
    {
900
901
902
903
904
905
906
        const int sndbuf_old = socket_get_sndbuf(fd);
        const int rcvbuf_old = socket_get_rcvbuf(fd);

        if (sbs->sndbuf)
        {
            socket_set_sndbuf(fd, sbs->sndbuf);
        }
907

908
909
910
911
        if (sbs->rcvbuf)
        {
            socket_set_rcvbuf(fd, sbs->rcvbuf);
        }
912

913
914
915
916
917
        msg(D_OSBUF, "Socket Buffers: R=[%d->%d] S=[%d->%d]",
            rcvbuf_old,
            socket_get_rcvbuf(fd),
            sndbuf_old,
            socket_get_sndbuf(fd));
918
919
920
    }
}

james's avatar
james committed
921
922
923
924
925
/*
 * Set other socket options
 */

static bool
926
socket_set_tcp_nodelay(socket_descriptor_t sd, int state)
james's avatar
james committed
927
{
928
#if defined(_WIN32) || (defined(IPPROTO_TCP) && defined(TCP_NODELAY))
929
    if (setsockopt(sd, IPPROTO_TCP, TCP_NODELAY, (void *) &state, sizeof(state)) != 0)
james's avatar
james committed
930
    {
931
932
        msg(M_WARN, "NOTE: setsockopt TCP_NODELAY=%d failed", state);
        return false;
james's avatar
james committed
933
    }
934
    else
james's avatar
james committed
935
    {
936
937
        dmsg(D_OSBUF, "Socket flags: TCP_NODELAY=%d succeeded", state);
        return true;
james's avatar
james committed
938
    }
939
#else  /* if defined(_WIN32) || (defined(IPPROTO_TCP) && defined(TCP_NODELAY)) */
940
941
    msg(M_WARN, "NOTE: setsockopt TCP_NODELAY=%d failed (No kernel support)", state);
    return false;
james's avatar
james committed
942
943
944
#endif
}

945
static inline void
946
socket_set_mark(socket_descriptor_t sd, int mark)
947
{
948
#if defined(TARGET_LINUX) && HAVE_DECL_SO_MARK
949
950
951
952
    if (mark && setsockopt(sd, SOL_SOCKET, SO_MARK, (void *) &mark, sizeof(mark)) != 0)
    {
        msg(M_WARN, "NOTE: setsockopt SO_MARK=%d failed", mark);
    }
953
954
955
#endif
}

james's avatar
james committed
956
static bool
957
socket_set_flags(socket_descriptor_t sd, unsigned int sockflags)
james's avatar
james committed
958
{
959
960
961
962
963
964
965
966
    if (sockflags & SF_TCP_NODELAY)
    {
        return socket_set_tcp_nodelay(sd, 1);
    }
    else
    {
        return true;
    }
james's avatar
james committed
967
968
969
}

bool
970
link_socket_update_flags(struct link_socket *ls, unsigned int sockflags)
james's avatar
james committed
971
{
972
973
974
975
976
977
978
979
    if (ls && socket_defined(ls->sd))
    {
        return socket_set_flags(ls->sd, ls->sockflags = sockflags);
    }
    else
    {
        return false;
    }
james's avatar
james committed
980
981
982
}

void
983
link_socket_update_buffer_sizes(struct link_socket *ls, int rcvbuf, int sndbuf)
james's avatar
james committed
984
{
985
    if (ls && socket_defined(ls->sd))
james's avatar
james committed
986
    {
987
988
989
        ls->socket_buffer_sizes.sndbuf = sndbuf;
        ls->socket_buffer_sizes.rcvbuf = rcvbuf;
        socket_set_buffers(ls->sd, &ls->socket_buffer_sizes);
james's avatar
james committed
990
991
992
    }
}

993
/*
994
 * SOCKET INITIALIZATION CODE.
995
996
997
998
 * Create a TCP/UDP socket
 */

socket_descriptor_t
999
create_socket_tcp(struct addrinfo *addrinfo)
1000
{