1 #ifndef AWS_PROXY_H 2 #define AWS_PROXY_H 3 4 /** 5 * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 6 * SPDX-License-Identifier: Apache-2.0. 7 */ 8 9 #include <aws/common/ref_count.h> 10 #include <aws/http/http.h> 11 #include <aws/http/request_response.h> 12 #include <aws/http/status_code.h> 13 14 struct aws_http_client_connection_options; 15 struct aws_http_connection_manager_options; 16 17 struct aws_http_message; 18 struct aws_http_header; 19 20 struct aws_http_proxy_config; 21 struct aws_http_proxy_negotiator; 22 struct aws_http_proxy_strategy; 23 24 struct aws_socket_channel_bootstrap_options; 25 26 /** 27 * @Deprecated - Supported proxy authentication modes. Superceded by proxy strategy. 28 */ 29 enum aws_http_proxy_authentication_type { 30 AWS_HPAT_NONE = 0, 31 AWS_HPAT_BASIC, 32 }; 33 34 enum aws_http_proxy_env_var_type { 35 /** 36 * Default. 37 * Disable reading from environment variable for proxy. 38 */ 39 AWS_HPEV_DISABLE = 0, 40 /** 41 * Enable get proxy URL from environment variable, when the manual proxy options of connection manager is not set. 42 * env HTTPS_PROXY/https_proxy will be checked when the main connection use tls. 43 * env HTTP_PROXY/http_proxy will be checked when the main connection NOT use tls. 44 * The lower case version has precedence. 45 */ 46 AWS_HPEV_ENABLE, 47 }; 48 49 /** 50 * Supported proxy connection types 51 */ 52 enum aws_http_proxy_connection_type { 53 /** 54 * Deprecated, but 0-valued for backwards compatibility 55 * 56 * If tls options are provided (for the main connection) then treat the proxy as a tunneling proxy 57 * If tls options are not provided (for the main connection), then treat the proxy as a forwarding proxy 58 */ 59 AWS_HPCT_HTTP_LEGACY = 0, 60 61 /** 62 * Use the proxy to forward http requests. Attempting to use both this mode and TLS on the tunnel destination 63 * is a configuration error. 64 */ 65 AWS_HPCT_HTTP_FORWARD, 66 67 /** 68 * Use the proxy to establish a connection to a remote endpoint via a CONNECT request through the proxy. 69 * Works for both plaintext and tls connections. 70 */ 71 AWS_HPCT_HTTP_TUNNEL, 72 }; 73 74 /* 75 * Configuration for using proxy from environment variable. 76 * Zero out as default settings. 77 */ 78 struct proxy_env_var_settings { 79 enum aws_http_proxy_env_var_type env_var_type; 80 /* 81 * Optional. 82 * If not set: 83 * If tls options are provided (for the main connection) use tunnel proxy type 84 * If tls options are not provided (for the main connection) use forward proxy type 85 */ 86 enum aws_http_proxy_connection_type connection_type; 87 /* 88 * Optional. 89 * If not set, a default tls option will be created. when https used for Local to proxy connection. 90 * Must be distinct from the the tls_connection_options from aws_http_connection_manager_options 91 */ 92 const struct aws_tls_connection_options *tls_options; 93 }; 94 95 struct aws_http_proxy_strategy; 96 97 /** 98 * Options for http proxy server usage 99 */ 100 struct aws_http_proxy_options { 101 102 /** 103 * Type of proxy connection to make 104 */ 105 enum aws_http_proxy_connection_type connection_type; 106 107 /** 108 * Proxy host to connect to 109 */ 110 struct aws_byte_cursor host; 111 112 /** 113 * Port to make the proxy connection to 114 */ 115 uint16_t port; 116 117 /** 118 * Optional. 119 * TLS configuration for the Local <-> Proxy connection 120 * Must be distinct from the the TLS options in the parent aws_http_connection_options struct 121 */ 122 const struct aws_tls_connection_options *tls_options; 123 124 /** 125 * Optional 126 * Advanced option that allows the user to create a custom strategy that gives low-level control of 127 * certain logical flows within the proxy logic. 128 * 129 * For tunneling proxies it allows custom retry and adaptive negotiation of CONNECT requests. 130 * For forwarding proxies it allows custom request transformations. 131 */ 132 struct aws_http_proxy_strategy *proxy_strategy; 133 134 /** 135 * @Deprecated - What type of proxy authentication to use, if any. 136 * Replaced by instantiating a proxy_strategy 137 */ 138 enum aws_http_proxy_authentication_type auth_type; 139 140 /** 141 * @Deprecated - Optional user name to use for basic authentication 142 * Replaced by instantiating a proxy_strategy via aws_http_proxy_strategy_new_basic_auth() 143 */ 144 struct aws_byte_cursor auth_username; 145 146 /** 147 * @Deprecated - Optional password to use for basic authentication 148 * Replaced by instantiating a proxy_strategy via aws_http_proxy_strategy_new_basic_auth() 149 */ 150 struct aws_byte_cursor auth_password; 151 }; 152 153 /** 154 * Synchronous (for now) callback function to fetch a token used in modifying CONNECT requests 155 */ 156 typedef struct aws_string *(aws_http_proxy_negotiation_get_token_sync_fn)(void *user_data, int *out_error_code); 157 158 /** 159 * Synchronous (for now) callback function to fetch a token used in modifying CONNECT request. Includes a (byte string) 160 * context intended to be used as part of a challenge-response flow. 161 */ 162 typedef struct aws_string *(aws_http_proxy_negotiation_get_challenge_token_sync_fn)( 163 void *user_data, 164 const struct aws_byte_cursor *challenge_context, 165 int *out_error_code); 166 167 /** 168 * Proxy negotiation logic must call this function to indicate an unsuccessful outcome 169 */ 170 typedef void(aws_http_proxy_negotiation_terminate_fn)( 171 struct aws_http_message *message, 172 int error_code, 173 void *internal_proxy_user_data); 174 175 /** 176 * Proxy negotiation logic must call this function to forward the potentially-mutated request back to the proxy 177 * connection logic. 178 */ 179 typedef void(aws_http_proxy_negotiation_http_request_forward_fn)( 180 struct aws_http_message *message, 181 void *internal_proxy_user_data); 182 183 /** 184 * User-supplied transform callback which implements the proxy request flow and ultimately, across all execution 185 * pathways, invokes either the terminate function or the forward function appropriately. 186 * 187 * For tunneling proxy connections, this request flow transform only applies to the CONNECT stage of proxy 188 * connection establishment. 189 * 190 * For forwarding proxy connections, this request flow transform applies to every single http request that goes 191 * out on the connection. 192 * 193 * Forwarding proxy connections cannot yet support a truly async request transform without major surgery on http 194 * stream creation, so for now, we split into an async version (for tunneling proxies) and a separate 195 * synchronous version for forwarding proxies. Also forwarding proxies are a kind of legacy dead-end in some 196 * sense. 197 * 198 */ 199 typedef void(aws_http_proxy_negotiation_http_request_transform_async_fn)( 200 struct aws_http_proxy_negotiator *proxy_negotiator, 201 struct aws_http_message *message, 202 aws_http_proxy_negotiation_terminate_fn *negotiation_termination_callback, 203 aws_http_proxy_negotiation_http_request_forward_fn *negotiation_http_request_forward_callback, 204 void *internal_proxy_user_data); 205 206 typedef int(aws_http_proxy_negotiation_http_request_transform_fn)( 207 struct aws_http_proxy_negotiator *proxy_negotiator, 208 struct aws_http_message *message); 209 210 /** 211 * Tunneling proxy connections only. A callback that lets the negotiator examine the headers in the 212 * response to the most recent CONNECT request as they arrive. 213 */ 214 typedef int(aws_http_proxy_negotiation_connect_on_incoming_headers_fn)( 215 struct aws_http_proxy_negotiator *proxy_negotiator, 216 enum aws_http_header_block header_block, 217 const struct aws_http_header *header_array, 218 size_t num_headers); 219 220 /** 221 * Tunneling proxy connections only. A callback that lets the negotiator examine the status code of the 222 * response to the most recent CONNECT request. 223 */ 224 typedef int(aws_http_proxy_negotiator_connect_status_fn)( 225 struct aws_http_proxy_negotiator *proxy_negotiator, 226 enum aws_http_status_code status_code); 227 228 /** 229 * Tunneling proxy connections only. A callback that lets the negotiator examine the body of the response 230 * to the most recent CONNECT request. 231 */ 232 typedef int(aws_http_proxy_negotiator_connect_on_incoming_body_fn)( 233 struct aws_http_proxy_negotiator *proxy_negotiator, 234 const struct aws_byte_cursor *data); 235 236 /* 237 * Control value that lets the http proxy implementation know if and how to retry a CONNECT request based on 238 * the proxy negotiator's state. 239 */ 240 enum aws_http_proxy_negotiation_retry_directive { 241 /* 242 * Stop trying to connect through the proxy and give up. 243 */ 244 AWS_HPNRD_STOP, 245 246 /* 247 * Establish a new connection to the proxy before making the next CONNECT request 248 */ 249 AWS_HPNRD_NEW_CONNECTION, 250 251 /* 252 * Reuse the existing connection to make the next CONNECT request 253 */ 254 AWS_HPNRD_CURRENT_CONNECTION, 255 }; 256 257 typedef enum aws_http_proxy_negotiation_retry_directive(aws_http_proxy_negotiator_get_retry_directive_fn)( 258 struct aws_http_proxy_negotiator *proxy_negotiator); 259 260 /** 261 * Vtable for forwarding-based proxy negotiators 262 */ 263 struct aws_http_proxy_negotiator_forwarding_vtable { 264 aws_http_proxy_negotiation_http_request_transform_fn *forward_request_transform; 265 }; 266 267 /** 268 * Vtable for tunneling-based proxy negotiators 269 */ 270 struct aws_http_proxy_negotiator_tunnelling_vtable { 271 aws_http_proxy_negotiation_http_request_transform_async_fn *connect_request_transform; 272 273 aws_http_proxy_negotiation_connect_on_incoming_headers_fn *on_incoming_headers_callback; 274 aws_http_proxy_negotiator_connect_status_fn *on_status_callback; 275 aws_http_proxy_negotiator_connect_on_incoming_body_fn *on_incoming_body_callback; 276 277 aws_http_proxy_negotiator_get_retry_directive_fn *get_retry_directive; 278 }; 279 280 /* 281 * Base definition of a proxy negotiator. 282 * 283 * A negotiator works differently based on what kind of proxy connection is being asked for: 284 * 285 * (1) Tunneling - In a tunneling proxy connection, the connect_request_transform is invoked on every CONNECT request. 286 * The connect_request_transform implementation *MUST*, in turn, eventually call one of the terminate or forward 287 * functions it gets supplied with. 288 * 289 * Every CONNECT request, if a response is obtained, will properly invoke the response handling callbacks supplied 290 * in the tunneling vtable. 291 * 292 * (2) Forwarding - In a forwarding proxy connection, the forward_request_transform is invoked on every request sent out 293 * on the connection. 294 */ 295 struct aws_http_proxy_negotiator { 296 struct aws_ref_count ref_count; 297 298 void *impl; 299 300 union { 301 struct aws_http_proxy_negotiator_forwarding_vtable *forwarding_vtable; 302 struct aws_http_proxy_negotiator_tunnelling_vtable *tunnelling_vtable; 303 } strategy_vtable; 304 }; 305 306 /*********************************************************************************************/ 307 308 typedef struct aws_http_proxy_negotiator *(aws_http_proxy_strategy_create_negotiator_fn)( 309 struct aws_http_proxy_strategy *proxy_strategy, 310 struct aws_allocator *allocator); 311 312 struct aws_http_proxy_strategy_vtable { 313 aws_http_proxy_strategy_create_negotiator_fn *create_negotiator; 314 }; 315 316 struct aws_http_proxy_strategy { 317 struct aws_ref_count ref_count; 318 struct aws_http_proxy_strategy_vtable *vtable; 319 void *impl; 320 enum aws_http_proxy_connection_type proxy_connection_type; 321 }; 322 323 /* 324 * Options necessary to create a basic authentication proxy strategy 325 */ 326 struct aws_http_proxy_strategy_basic_auth_options { 327 328 /* type of proxy connection being established, must be forwarding or tunnel */ 329 enum aws_http_proxy_connection_type proxy_connection_type; 330 331 /* user name to use in basic authentication */ 332 struct aws_byte_cursor user_name; 333 334 /* password to use in basic authentication */ 335 struct aws_byte_cursor password; 336 }; 337 338 /* 339 * Options necessary to create a (synchronous) kerberos authentication proxy strategy 340 */ 341 struct aws_http_proxy_strategy_tunneling_kerberos_options { 342 343 aws_http_proxy_negotiation_get_token_sync_fn *get_token; 344 345 void *get_token_user_data; 346 }; 347 348 /* 349 * Options necessary to create a (synchronous) ntlm authentication proxy strategy 350 */ 351 struct aws_http_proxy_strategy_tunneling_ntlm_options { 352 353 aws_http_proxy_negotiation_get_token_sync_fn *get_token; 354 355 aws_http_proxy_negotiation_get_challenge_token_sync_fn *get_challenge_token; 356 357 void *get_challenge_token_user_data; 358 }; 359 360 /* 361 * Options necessary to create an adaptive sequential strategy that tries one or more of kerberos and ntlm (in that 362 * order, if both are active). If an options struct is NULL, then that strategy will not be used. 363 */ 364 struct aws_http_proxy_strategy_tunneling_adaptive_options { 365 /* 366 * If non-null, will insert a kerberos proxy strategy into the adaptive sequence 367 */ 368 struct aws_http_proxy_strategy_tunneling_kerberos_options *kerberos_options; 369 370 /* 371 * If non-null will insert an ntlm proxy strategy into the adaptive sequence 372 */ 373 struct aws_http_proxy_strategy_tunneling_ntlm_options *ntlm_options; 374 }; 375 376 /* 377 * Options necessary to create a sequential proxy strategy. 378 */ 379 struct aws_http_proxy_strategy_tunneling_sequence_options { 380 struct aws_http_proxy_strategy **strategies; 381 382 uint32_t strategy_count; 383 }; 384 385 AWS_EXTERN_C_BEGIN 386 387 /** 388 * Take a reference to an http proxy negotiator 389 * @param proxy_negotiator negotiator to take a reference to 390 * @return the strategy 391 */ 392 AWS_HTTP_API 393 struct aws_http_proxy_negotiator *aws_http_proxy_negotiator_acquire(struct aws_http_proxy_negotiator *proxy_negotiator); 394 395 /** 396 * Release a reference to an http proxy negotiator 397 * @param proxy_negotiator negotiator to release a reference to 398 */ 399 AWS_HTTP_API 400 void aws_http_proxy_negotiator_release(struct aws_http_proxy_negotiator *proxy_negotiator); 401 402 /** 403 * Creates a new proxy negotiator from a proxy strategy 404 * @param allocator memory allocator to use 405 * @param strategy strategy to creation a new negotiator for 406 * @return a new proxy negotiator if successful, otherwise NULL 407 */ 408 AWS_HTTP_API 409 struct aws_http_proxy_negotiator *aws_http_proxy_strategy_create_negotiator( 410 struct aws_http_proxy_strategy *strategy, 411 struct aws_allocator *allocator); 412 413 /** 414 * Take a reference to an http proxy strategy 415 * @param proxy_strategy strategy to take a reference to 416 * @return the strategy 417 */ 418 AWS_HTTP_API 419 struct aws_http_proxy_strategy *aws_http_proxy_strategy_acquire(struct aws_http_proxy_strategy *proxy_strategy); 420 421 /** 422 * Release a reference to an http proxy strategy 423 * @param proxy_strategy strategy to release a reference to 424 */ 425 AWS_HTTP_API 426 void aws_http_proxy_strategy_release(struct aws_http_proxy_strategy *proxy_strategy); 427 428 /** 429 * A constructor for a proxy strategy that performs basic authentication by adding the appropriate 430 * header and header value to requests or CONNECT requests. 431 * 432 * @param allocator memory allocator to use 433 * @param config basic authentication configuration info 434 * @return a new proxy strategy if successfully constructed, otherwise NULL 435 */ 436 AWS_HTTP_API 437 struct aws_http_proxy_strategy *aws_http_proxy_strategy_new_basic_auth( 438 struct aws_allocator *allocator, 439 struct aws_http_proxy_strategy_basic_auth_options *config); 440 441 /** 442 * Constructor for an adaptive tunneling proxy strategy. This strategy attempts a vanilla CONNECT and if that 443 * fails it may make followup CONNECT attempts using kerberos or ntlm tokens, based on configuration and proxy 444 * response properties. 445 * 446 * @param allocator memory allocator to use 447 * @param config configuration options for the strategy 448 * @return a new proxy strategy if successfully constructed, otherwise NULL 449 */ 450 AWS_HTTP_API 451 struct aws_http_proxy_strategy *aws_http_proxy_strategy_new_tunneling_adaptive( 452 struct aws_allocator *allocator, 453 struct aws_http_proxy_strategy_tunneling_adaptive_options *config); 454 455 /* 456 * aws_http_proxy_config is the persistent, memory-managed version of aws_http_proxy_options 457 * 458 * This is a set of APIs for creating, destroying and converting between them 459 */ 460 461 /** 462 * Create a persistent proxy configuration from http connection options 463 * @param allocator memory allocator to use 464 * @param options http connection options to source proxy configuration from 465 * @return 466 */ 467 AWS_HTTP_API 468 struct aws_http_proxy_config *aws_http_proxy_config_new_from_connection_options( 469 struct aws_allocator *allocator, 470 const struct aws_http_client_connection_options *options); 471 472 /** 473 * Create a persistent proxy configuration from http connection manager options 474 * @param allocator memory allocator to use 475 * @param options http connection manager options to source proxy configuration from 476 * @return 477 */ 478 AWS_HTTP_API 479 struct aws_http_proxy_config *aws_http_proxy_config_new_from_manager_options( 480 struct aws_allocator *allocator, 481 const struct aws_http_connection_manager_options *options); 482 483 /** 484 * Create a persistent proxy configuration from non-persistent proxy options. The resulting 485 * proxy configuration assumes a tunneling connection type. 486 * 487 * @param allocator memory allocator to use 488 * @param options http proxy options to source proxy configuration from 489 * @return 490 */ 491 AWS_HTTP_API 492 struct aws_http_proxy_config *aws_http_proxy_config_new_tunneling_from_proxy_options( 493 struct aws_allocator *allocator, 494 const struct aws_http_proxy_options *options); 495 496 /** 497 * Create a persistent proxy configuration from non-persistent proxy options. 498 * Legacy connection type of proxy options will be rejected. 499 * 500 * @param allocator memory allocator to use 501 * @param options http proxy options to source proxy configuration from 502 * @return 503 */ 504 AWS_HTTP_API 505 struct aws_http_proxy_config *aws_http_proxy_config_new_from_proxy_options( 506 struct aws_allocator *allocator, 507 const struct aws_http_proxy_options *options); 508 509 /** 510 * Clones an existing proxy configuration. A refactor could remove this (do a "move" between the old and new user 511 * data in the one spot it's used) but that should wait until we have better test cases for the logic where this 512 * gets invoked (ntlm/kerberos chains). 513 * 514 * @param allocator memory allocator to use 515 * @param proxy_config http proxy configuration to clone 516 * @return 517 */ 518 AWS_HTTP_API 519 struct aws_http_proxy_config *aws_http_proxy_config_new_clone( 520 struct aws_allocator *allocator, 521 const struct aws_http_proxy_config *proxy_config); 522 523 /** 524 * Destroys an http proxy configuration 525 * @param config http proxy configuration to destroy 526 */ 527 AWS_HTTP_API 528 void aws_http_proxy_config_destroy(struct aws_http_proxy_config *config); 529 530 /** 531 * Initializes non-persistent http proxy options from a persistent http proxy configuration 532 * @param options http proxy options to initialize 533 * @param config the http proxy config to use as an initialization source 534 */ 535 AWS_HTTP_API 536 void aws_http_proxy_options_init_from_config( 537 struct aws_http_proxy_options *options, 538 const struct aws_http_proxy_config *config); 539 540 /** 541 * Establish an arbitrary protocol connection through an http proxy via tunneling CONNECT. Alpn is 542 * not required for this connection process to succeed, but we encourage its use if available. 543 * 544 * @param channel_options configuration options for the socket level connection 545 * @param proxy_options configuration options for the proxy connection 546 * 547 * @return AWS_OP_SUCCESS if the asynchronous channel kickoff succeeded, AWS_OP_ERR otherwise 548 */ 549 AWS_HTTP_API int aws_http_proxy_new_socket_channel( 550 struct aws_socket_channel_bootstrap_options *channel_options, 551 struct aws_http_proxy_options *proxy_options); 552 553 AWS_EXTERN_C_END 554 555 #endif /* AWS_PROXY_STRATEGY_H */ 556