httpsrr.c (6648B)
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 #ifdef USE_HTTPSRR 28 29 #include "urldata.h" 30 #include "curl_addrinfo.h" 31 #include "httpsrr.h" 32 #include "connect.h" 33 #include "sendf.h" 34 #include "strdup.h" 35 36 /* The last 3 #include files should be in this order */ 37 #include "curl_printf.h" 38 #include "curl_memory.h" 39 #include "memdebug.h" 40 41 #define MAX_ALPN_LENGTH 255 42 43 static CURLcode httpsrr_decode_alpn(const char *cp, size_t len, 44 unsigned char *alpns) 45 { 46 /* 47 * The wire-format value for "alpn" consists of at least one alpn-id 48 * prefixed by its length as a single octet, and these length-value pairs 49 * are concatenated to form the SvcParamValue. These pairs MUST exactly fill 50 * the SvcParamValue; otherwise, the SvcParamValue is malformed. 51 */ 52 int idnum = 0; 53 54 while(len > 0) { 55 size_t tlen = (size_t) *cp++; 56 enum alpnid id; 57 len--; 58 if(tlen > len) 59 return CURLE_BAD_CONTENT_ENCODING; 60 61 /* we only store ALPN ids we know about */ 62 id = Curl_alpn2alpnid(cp, tlen); 63 if(id != ALPN_none) { 64 if(idnum == MAX_HTTPSRR_ALPNS) 65 break; 66 if(idnum && memchr(alpns, id, idnum)) 67 /* this ALPN id is already stored */ 68 ; 69 else 70 alpns[idnum++] = (unsigned char)id; 71 } 72 cp += tlen; 73 len -= tlen; 74 } 75 if(idnum < MAX_HTTPSRR_ALPNS) 76 alpns[idnum] = ALPN_none; /* terminate the list */ 77 return CURLE_OK; 78 } 79 80 CURLcode Curl_httpsrr_set(struct Curl_easy *data, 81 struct Curl_https_rrinfo *hi, 82 uint16_t rrkey, const uint8_t *val, size_t vlen) 83 { 84 CURLcode result = CURLE_OK; 85 switch(rrkey) { 86 case HTTPS_RR_CODE_MANDATORY: 87 CURL_TRC_DNS(data, "HTTPS RR MANDATORY left to implement"); 88 break; 89 case HTTPS_RR_CODE_ALPN: /* str_list */ 90 result = httpsrr_decode_alpn((const char *)val, vlen, hi->alpns); 91 CURL_TRC_DNS(data, "HTTPS RR ALPN: %u %u %u %u", 92 hi->alpns[0], hi->alpns[1], hi->alpns[2], hi->alpns[3]); 93 break; 94 case HTTPS_RR_CODE_NO_DEF_ALPN: 95 if(vlen) /* no data */ 96 return CURLE_BAD_FUNCTION_ARGUMENT; 97 hi->no_def_alpn = TRUE; 98 CURL_TRC_DNS(data, "HTTPS RR no-def-alpn"); 99 break; 100 case HTTPS_RR_CODE_IPV4: /* addr4 list */ 101 if(!vlen || (vlen & 3)) /* the size must be 4-byte aligned */ 102 return CURLE_BAD_FUNCTION_ARGUMENT; 103 hi->ipv4hints = Curl_memdup(val, vlen); 104 if(!hi->ipv4hints) 105 return CURLE_OUT_OF_MEMORY; 106 hi->ipv4hints_len = vlen; 107 CURL_TRC_DNS(data, "HTTPS RR IPv4"); 108 break; 109 case HTTPS_RR_CODE_ECH: 110 if(!vlen) 111 return CURLE_BAD_FUNCTION_ARGUMENT; 112 hi->echconfiglist = Curl_memdup(val, vlen); 113 if(!hi->echconfiglist) 114 return CURLE_OUT_OF_MEMORY; 115 hi->echconfiglist_len = vlen; 116 CURL_TRC_DNS(data, "HTTPS RR ECH"); 117 break; 118 case HTTPS_RR_CODE_IPV6: /* addr6 list */ 119 if(!vlen || (vlen & 15)) /* the size must be 16-byte aligned */ 120 return CURLE_BAD_FUNCTION_ARGUMENT; 121 hi->ipv6hints = Curl_memdup(val, vlen); 122 if(!hi->ipv6hints) 123 return CURLE_OUT_OF_MEMORY; 124 hi->ipv6hints_len = vlen; 125 CURL_TRC_DNS(data, "HTTPS RR IPv6"); 126 break; 127 case HTTPS_RR_CODE_PORT: 128 if(vlen != 2) 129 return CURLE_BAD_FUNCTION_ARGUMENT; 130 hi->port = (unsigned short)((val[0] << 8) | val[1]); 131 CURL_TRC_DNS(data, "HTTPS RR port %u", hi->port); 132 break; 133 default: 134 CURL_TRC_DNS(data, "HTTPS RR unknown code"); 135 break; 136 } 137 return result; 138 } 139 140 struct Curl_https_rrinfo * 141 Curl_httpsrr_dup_move(struct Curl_https_rrinfo *rrinfo) 142 { 143 struct Curl_https_rrinfo *dup = Curl_memdup(rrinfo, sizeof(*rrinfo)); 144 if(dup) 145 memset(rrinfo, 0, sizeof(*rrinfo)); 146 return dup; 147 } 148 149 void Curl_httpsrr_cleanup(struct Curl_https_rrinfo *rrinfo) 150 { 151 Curl_safefree(rrinfo->target); 152 Curl_safefree(rrinfo->echconfiglist); 153 Curl_safefree(rrinfo->ipv4hints); 154 Curl_safefree(rrinfo->ipv6hints); 155 } 156 157 158 #ifdef USE_ARES 159 160 static CURLcode httpsrr_opt(struct Curl_easy *data, 161 const ares_dns_rr_t *rr, 162 ares_dns_rr_key_t key, size_t idx, 163 struct Curl_https_rrinfo *hinfo) 164 { 165 const unsigned char *val = NULL; 166 unsigned short code; 167 size_t len = 0; 168 169 code = ares_dns_rr_get_opt(rr, key, idx, &val, &len); 170 return Curl_httpsrr_set(data, hinfo, code, val, len); 171 } 172 173 CURLcode Curl_httpsrr_from_ares(struct Curl_easy *data, 174 const ares_dns_record_t *dnsrec, 175 struct Curl_https_rrinfo *hinfo) 176 { 177 CURLcode result = CURLE_OK; 178 size_t i; 179 180 for(i = 0; i < ares_dns_record_rr_cnt(dnsrec, ARES_SECTION_ANSWER); i++) { 181 const char *target; 182 size_t opt; 183 const ares_dns_rr_t *rr = 184 ares_dns_record_rr_get_const(dnsrec, ARES_SECTION_ANSWER, i); 185 if(ares_dns_rr_get_type(rr) != ARES_REC_TYPE_HTTPS) 186 continue; 187 /* When SvcPriority is 0, the SVCB record is in AliasMode. Otherwise, it 188 is in ServiceMode */ 189 target = ares_dns_rr_get_str(rr, ARES_RR_HTTPS_TARGET); 190 if(target && target[0]) { 191 hinfo->target = strdup(target); 192 if(!hinfo->target) { 193 result = CURLE_OUT_OF_MEMORY; 194 goto out; 195 } 196 CURL_TRC_DNS(data, "HTTPS RR target: %s", hinfo->target); 197 } 198 CURL_TRC_DNS(data, "HTTPS RR priority: %u", 199 ares_dns_rr_get_u16(rr, ARES_RR_HTTPS_PRIORITY)); 200 for(opt = 0; opt < ares_dns_rr_get_opt_cnt(rr, ARES_RR_HTTPS_PARAMS); 201 opt++) { 202 result = httpsrr_opt(data, rr, ARES_RR_HTTPS_PARAMS, opt, hinfo); 203 if(result) 204 break; 205 } 206 } 207 out: 208 return result; 209 } 210 211 #endif /* USE_ARES */ 212 213 #endif /* USE_HTTPSRR */