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