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