quickjs-tart

quickjs-based runtime for wallet-core logic
Log | Files | Refs | README | LICENSE

noproxy.c (7531B)


      1 /***************************************************************************
      2  *                                  _   _ ____  _
      3  *  Project                     ___| | | |  _ \| |
      4  *                             / __| | | | |_) | |
      5  *                            | (__| |_| |  _ <| |___
      6  *                             \___|\___/|_| \_\_____|
      7  *
      8  * Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
      9  *
     10  * This software is licensed as described in the file COPYING, which
     11  * you should have received as part of this distribution. The terms
     12  * are also available at https://curl.se/docs/copyright.html.
     13  *
     14  * You may opt to use, copy, modify, merge, publish, distribute and/or sell
     15  * copies of the Software, and permit persons to whom the Software is
     16  * furnished to do so, under the terms of the COPYING file.
     17  *
     18  * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
     19  * KIND, either express or implied.
     20  *
     21  * SPDX-License-Identifier: curl
     22  *
     23  ***************************************************************************/
     24 
     25 #include "curl_setup.h"
     26 
     27 #ifndef CURL_DISABLE_PROXY
     28 
     29 #include <curl/curl.h>  /* for curl_strnequal() */
     30 #include "curlx/inet_pton.h"
     31 #include "noproxy.h"
     32 #include "curlx/strparse.h"
     33 
     34 #ifdef HAVE_NETINET_IN_H
     35 #include <netinet/in.h>
     36 #endif
     37 
     38 #ifdef HAVE_ARPA_INET_H
     39 #include <arpa/inet.h>
     40 #endif
     41 
     42 /*
     43  * Curl_cidr4_match() returns TRUE if the given IPv4 address is within the
     44  * specified CIDR address range.
     45  */
     46 UNITTEST bool Curl_cidr4_match(const char *ipv4,    /* 1.2.3.4 address */
     47                                const char *network, /* 1.2.3.4 address */
     48                                unsigned int bits)
     49 {
     50   unsigned int address = 0;
     51   unsigned int check = 0;
     52 
     53   if(bits > 32)
     54     /* strange input */
     55     return FALSE;
     56 
     57   if(1 != curlx_inet_pton(AF_INET, ipv4, &address))
     58     return FALSE;
     59   if(1 != curlx_inet_pton(AF_INET, network, &check))
     60     return FALSE;
     61 
     62   if(bits && (bits != 32)) {
     63     unsigned int mask = 0xffffffff << (32 - bits);
     64     unsigned int haddr = htonl(address);
     65     unsigned int hcheck = htonl(check);
     66 #if 0
     67     fprintf(stderr, "Host %s (%x) network %s (%x) bits %u mask %x => %x\n",
     68             ipv4, haddr, network, hcheck, bits, mask,
     69             (haddr ^ hcheck) & mask);
     70 #endif
     71     if((haddr ^ hcheck) & mask)
     72       return FALSE;
     73     return TRUE;
     74   }
     75   return address == check;
     76 }
     77 
     78 UNITTEST bool Curl_cidr6_match(const char *ipv6,
     79                                const char *network,
     80                                unsigned int bits)
     81 {
     82 #ifdef USE_IPV6
     83   unsigned int bytes;
     84   unsigned int rest;
     85   unsigned char address[16];
     86   unsigned char check[16];
     87 
     88   if(!bits)
     89     bits = 128;
     90 
     91   bytes = bits / 8;
     92   rest = bits & 0x07;
     93   if((bytes > 16) || ((bytes == 16) && rest))
     94     return FALSE;
     95   if(1 != curlx_inet_pton(AF_INET6, ipv6, address))
     96     return FALSE;
     97   if(1 != curlx_inet_pton(AF_INET6, network, check))
     98     return FALSE;
     99   if(bytes && memcmp(address, check, bytes))
    100     return FALSE;
    101   if(rest && !((address[bytes] ^ check[bytes]) & (0xff << (8 - rest))))
    102     return FALSE;
    103 
    104   return TRUE;
    105 #else
    106   (void)ipv6;
    107   (void)network;
    108   (void)bits;
    109   return FALSE;
    110 #endif
    111 }
    112 
    113 enum nametype {
    114   TYPE_HOST,
    115   TYPE_IPV4,
    116   TYPE_IPV6
    117 };
    118 
    119 /****************************************************************
    120 * Checks if the host is in the noproxy list. returns TRUE if it matches and
    121 * therefore the proxy should NOT be used.
    122 ****************************************************************/
    123 bool Curl_check_noproxy(const char *name, const char *no_proxy)
    124 {
    125   char hostip[128];
    126 
    127   /*
    128    * If we do not have a hostname at all, like for example with a FILE
    129    * transfer, we have nothing to interrogate the noproxy list with.
    130    */
    131   if(!name || name[0] == '\0')
    132     return FALSE;
    133 
    134   /* no_proxy=domain1.dom,host.domain2.dom
    135    *   (a comma-separated list of hosts which should
    136    *   not be proxied, or an asterisk to override
    137    *   all proxy variables)
    138    */
    139   if(no_proxy && no_proxy[0]) {
    140     const char *p = no_proxy;
    141     size_t namelen;
    142     enum nametype type = TYPE_HOST;
    143     if(!strcmp("*", no_proxy))
    144       return TRUE;
    145 
    146     /* NO_PROXY was specified and it was not just an asterisk */
    147 
    148     if(name[0] == '[') {
    149       char *endptr;
    150       /* IPv6 numerical address */
    151       endptr = strchr(name, ']');
    152       if(!endptr)
    153         return FALSE;
    154       name++;
    155       namelen = endptr - name;
    156       if(namelen >= sizeof(hostip))
    157         return FALSE;
    158       memcpy(hostip, name, namelen);
    159       hostip[namelen] = 0;
    160       name = hostip;
    161       type = TYPE_IPV6;
    162     }
    163     else {
    164       unsigned int address;
    165       namelen = strlen(name);
    166       if(1 == curlx_inet_pton(AF_INET, name, &address))
    167         type = TYPE_IPV4;
    168       else {
    169         /* ignore trailing dots in the hostname */
    170         if(name[namelen - 1] == '.')
    171           namelen--;
    172       }
    173     }
    174 
    175     while(*p) {
    176       const char *token;
    177       size_t tokenlen = 0;
    178       bool match = FALSE;
    179 
    180       /* pass blanks */
    181       curlx_str_passblanks(&p);
    182 
    183       token = p;
    184       /* pass over the pattern */
    185       while(*p && !ISBLANK(*p) && (*p != ',')) {
    186         p++;
    187         tokenlen++;
    188       }
    189 
    190       if(tokenlen) {
    191         switch(type) {
    192         case TYPE_HOST:
    193           /* ignore trailing dots in the token to check */
    194           if(token[tokenlen - 1] == '.')
    195             tokenlen--;
    196 
    197           if(tokenlen && (*token == '.')) {
    198             /* ignore leading token dot as well */
    199             token++;
    200             tokenlen--;
    201           }
    202           /* A: example.com matches 'example.com'
    203              B: www.example.com matches 'example.com'
    204              C: nonexample.com DOES NOT match 'example.com'
    205           */
    206           if(tokenlen == namelen)
    207             /* case A, exact match */
    208             match = curl_strnequal(token, name, namelen);
    209           else if(tokenlen < namelen) {
    210             /* case B, tailmatch domain */
    211             match = (name[namelen - tokenlen - 1] == '.') &&
    212               curl_strnequal(token, name + (namelen - tokenlen),
    213                              tokenlen);
    214           }
    215           /* case C passes through, not a match */
    216           break;
    217         case TYPE_IPV4:
    218         case TYPE_IPV6: {
    219           const char *check = token;
    220           char *slash;
    221           unsigned int bits = 0;
    222           char checkip[128];
    223           if(tokenlen >= sizeof(checkip))
    224             /* this cannot match */
    225             break;
    226           /* copy the check name to a temp buffer */
    227           memcpy(checkip, check, tokenlen);
    228           checkip[tokenlen] = 0;
    229           check = checkip;
    230 
    231           slash = strchr(check, '/');
    232           /* if the slash is part of this token, use it */
    233           if(slash) {
    234             /* if the bits variable gets a crazy value here, that is fine as
    235                the value will then be rejected in the cidr function */
    236             bits = (unsigned int)atoi(slash + 1);
    237             *slash = 0; /* null-terminate there */
    238           }
    239           if(type == TYPE_IPV6)
    240             match = Curl_cidr6_match(name, check, bits);
    241           else
    242             match = Curl_cidr4_match(name, check, bits);
    243           break;
    244         }
    245         }
    246         if(match)
    247           return TRUE;
    248       } /* if(tokenlen) */
    249       /* pass blanks after pattern */
    250       curlx_str_passblanks(&p);
    251       /* if not a comma, this ends the loop */
    252       if(*p != ',')
    253         break;
    254       /* pass any number of commas */
    255       while(*p == ',')
    256         p++;
    257     } /* while(*p) */
    258   } /* NO_PROXY was specified and it was not just an asterisk */
    259 
    260   return FALSE;
    261 }
    262 
    263 #endif /* CURL_DISABLE_PROXY */