@@ -3951,23 +3951,59 @@ static CURLcode parseurlandfillconn(struct SessionHandle *data,
3951
3951
if (result != CURLE_OK )
3952
3952
return result ;
3953
3953
3954
- if (conn -> host .name [0 ] == '[' ) {
3954
+ if (conn -> host .name [0 ] == '[' && ! data -> state . this_is_a_follow ) {
3955
3955
/* This looks like an IPv6 address literal. See if there is an address
3956
- scope. */
3957
- char * percent = strstr (conn -> host .name , "%25" );
3956
+ scope if there is no location header */
3957
+ char * percent = strchr (conn -> host .name , '%' );
3958
3958
if (percent ) {
3959
+ unsigned int identifier_offset = 3 ;
3959
3960
char * endp ;
3960
- unsigned long scope = strtoul (percent + 3 , & endp , 10 );
3961
+ unsigned long scope ;
3962
+ if (strncmp ("%25" , percent , 3 ) != 0 ) {
3963
+ infof (data ,
3964
+ "Please URL encode %% as %%25, see RFC 6874.\n" );
3965
+ identifier_offset = 1 ;
3966
+ }
3967
+ scope = strtoul (percent + identifier_offset , & endp , 10 );
3961
3968
if (* endp == ']' ) {
3962
3969
/* The address scope was well formed. Knock it out of the
3963
3970
hostname. */
3964
3971
memmove (percent , endp , strlen (endp )+ 1 );
3965
- if (!data -> state .this_is_a_follow )
3966
- /* Don't honour a scope given in a Location: header */
3967
- conn -> scope = (unsigned int )scope ;
3972
+ conn -> scope = (unsigned int )scope ;
3973
+ }
3974
+ else {
3975
+ /* Zone identifier is not numeric */
3976
+ #ifdef HAVE_NET_IF_H
3977
+ char ifname [IFNAMSIZ + 2 ];
3978
+ char * square_bracket ;
3979
+ unsigned int scopeidx = 0 ;
3980
+ strncpy (ifname , percent + identifier_offset , IFNAMSIZ + 2 );
3981
+ /* Ensure nullbyte termination */
3982
+ ifname [IFNAMSIZ + 1 ] = '\0' ;
3983
+ square_bracket = strchr (ifname , ']' );
3984
+ if (square_bracket ) {
3985
+ /* Remove ']' */
3986
+ * square_bracket = '\0' ;
3987
+ scopeidx = if_nametoindex (ifname );
3988
+ if (scopeidx == 0 ) {
3989
+ infof (data , "Invalid network interface: %s; %s\n" , ifname ,
3990
+ strerror (errno ));
3991
+ }
3992
+ }
3993
+ if (scopeidx > 0 ) {
3994
+ /* Remove zone identifier from hostname */
3995
+ memmove (percent ,
3996
+ percent + identifier_offset + strlen (ifname ),
3997
+ identifier_offset + strlen (ifname ));
3998
+ conn -> scope = scopeidx ;
3999
+ }
4000
+ else {
4001
+ #endif /* HAVE_NET_IF_H */
4002
+ infof (data , "Invalid IPv6 address format\n" );
4003
+ #ifdef HAVE_NET_IF_H
4004
+ }
4005
+ #endif /* HAVE_NET_IF_H */
3968
4006
}
3969
- else
3970
- infof (data , "Invalid IPv6 address format\n" );
3971
4007
}
3972
4008
}
3973
4009
@@ -4350,12 +4386,21 @@ static CURLcode parse_proxy(struct SessionHandle *data,
4350
4386
/* start scanning for port number at this point */
4351
4387
portptr = proxyptr ;
4352
4388
4353
- /* detect and extract RFC2732 -style IPv6-addresses */
4389
+ /* detect and extract RFC6874 -style IPv6-addresses */
4354
4390
if (* proxyptr == '[' ) {
4355
4391
char * ptr = ++ proxyptr ; /* advance beyond the initial bracket */
4356
- while (* ptr && (ISXDIGIT (* ptr ) || (* ptr == ':' ) || (* ptr == '%' ) ||
4357
- (* ptr == '.' )))
4392
+ while (* ptr && (ISXDIGIT (* ptr ) || (* ptr == ':' ) || (* ptr == '.' )))
4393
+ ptr ++ ;
4394
+ if (* ptr == '%' ) {
4395
+ /* There might be a zone identifier */
4396
+ if (strncmp ("%25" , ptr , 3 ))
4397
+ infof (data , "Please URL encode %% as %%25, see RFC 6874.\n" );
4358
4398
ptr ++ ;
4399
+ /* Allow unresered characters as defined in RFC 3986 */
4400
+ while (* ptr && (ISALPHA (* ptr ) || ISXDIGIT (* ptr ) || (* ptr == '-' ) ||
4401
+ (* ptr == '.' ) || (* ptr == '_' ) || (* ptr == '~' )))
4402
+ ptr ++ ;
4403
+ }
4359
4404
if (* ptr == ']' )
4360
4405
/* yeps, it ended nicely with a bracket as well */
4361
4406
* ptr ++ = 0 ;
0 commit comments