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