diff --git a/src/include/ipxe/proxy.h b/src/include/ipxe/proxy.h new file mode 100644 index 0000000..56985e9 --- /dev/null +++ b/src/include/ipxe/proxy.h @@ -0,0 +1,17 @@ +#ifndef _IPXE_PROXY_H +#define _IPXE_PROXY_H + +/** @file + * + * HTTP Proxy + * + */ + +FILE_LICENCE ( GPL2_OR_LATER ); + +int is_proxy_set ( ); +struct uri *get_proxy ( ); +const char *proxied_uri_host ( struct uri *uri ); +unsigned int proxied_uri_port ( struct uri *uri, unsigned int default_port ); + +#endif /* _IPXE_IP_H */ diff --git a/src/include/ipxe/settings.h b/src/include/ipxe/settings.h index 0f1ec5b..3ab994a 100644 --- a/src/include/ipxe/settings.h +++ b/src/include/ipxe/settings.h @@ -307,6 +307,7 @@ extern struct setting uuid_setting __setting ( SETTING_HOST ); extern struct setting next_server_setting __setting ( SETTING_BOOT ); extern struct setting mac_setting __setting ( SETTING_NETDEV ); extern struct setting busid_setting __setting ( SETTING_NETDEV ); +extern struct setting http_proxy_setting __setting ( SETTING_MISC ); /** * Initialise a settings block diff --git a/src/net/proxy.c b/src/net/proxy.c new file mode 100644 index 0000000..3e631d4 --- /dev/null +++ b/src/net/proxy.c @@ -0,0 +1,70 @@ +#include +#include +#include +#include + +/** @file + * + * HTTP Proxy + * + */ + +FILE_LICENCE ( GPL2_OR_LATER ); + +struct uri *proxy_uri = NULL; + +/** HTTP proxy address setting */ +struct setting http_proxy_setting __setting ( SETTING_MISC ) = { + .name = "http-proxy", + .description = "Address and port of the HTTP (not HTTPS) proxy to use, as a http scheme URI", + .type = &setting_type_string, +}; + +int is_proxy_set ( ) { + /* Later, this may be expanded to encompass other settings */ + if ( ! proxy_uri ) { + proxy_uri = get_proxy(); + } + return ! ! proxy_uri; +} + +struct uri *get_proxy ( ) { + char *http_proxy_unexpanded, *http_proxy; + + if ( setting_exists ( NULL, &http_proxy_setting ) && ! proxy_uri ) { + /* Later, this may select from multiple settings*/ + fetch_string_setting_copy ( NULL, &http_proxy_setting, &http_proxy_unexpanded ); + http_proxy = expand_settings ( http_proxy_unexpanded ); + proxy_uri = parse_uri ( http_proxy ); + free ( http_proxy_unexpanded ); + free ( http_proxy ); + /* Only the http scheme is currently supported */ + if ( strcmp ( proxy_uri->scheme, "http" ) != 0 ) { + uri_put ( proxy_uri ); + DBG ( "http-proxy must begin with \"http://\"" ); + return NULL; + } + } + + return proxy_uri; +} + +const char *proxied_uri_host ( struct uri *uri ) { + /* Later, this could select from multiple proxies, + based on hostname patterns matched against the uri */ + if ( is_proxy_set ( ) ) { + return proxy_uri->host; + } else { + return uri->host; + } +} + +unsigned int proxied_uri_port ( struct uri *uri, unsigned int default_port ) { + /* Later, this could select from multiple proxies, + based on hostname patterns matched against the uri */ + if ( is_proxy_set ( ) ) { + return uri_port ( proxy_uri, default_port); + } else { + return uri_port ( uri, default_port); + } +} diff --git a/src/net/tcp/httpcore.c b/src/net/tcp/httpcore.c index 617f49b..3d8fa56 100644 --- a/src/net/tcp/httpcore.c +++ b/src/net/tcp/httpcore.c @@ -46,6 +46,7 @@ FILE_LICENCE ( GPL2_OR_LATER ); #include #include #include +#include /** Block size used for HTTP block device request */ #define HTTP_BLKSIZE 512 @@ -614,8 +615,7 @@ static void http_step ( struct http_request *http ) { uint8_t user_pw[ user_pw_len + 1 /* NUL */ ]; char user_pw_base64[ user_pw_base64_len + 1 /* NUL */ ]; int rc; - int request_len = unparse_uri ( NULL, 0, http->uri, - URI_PATH_BIT | URI_QUERY_BIT ); + int request_len = unparse_uri ( NULL, 0, http->uri, URI_ALL ); char request[ request_len + 1 /* NUL */ ]; char range[48]; /* Enough for two 64-bit integers in decimal */ int partial; @@ -629,8 +629,12 @@ static void http_step ( struct http_request *http ) { return; /* Construct path?query request */ - unparse_uri ( request, sizeof ( request ), http->uri, - URI_PATH_BIT | URI_QUERY_BIT ); + if ( is_proxy_set ( ) ) { + unparse_uri ( request, sizeof ( request ), http->uri, URI_ALL ); + } else { + unparse_uri ( request, sizeof ( request ), http->uri, + URI_PATH_BIT | URI_QUERY_BIT ); + } /* Construct authorisation, if applicable */ if ( user ) { @@ -863,15 +867,15 @@ int http_open_filter ( struct interface *xfer, struct uri *uri, /* Open socket */ memset ( &server, 0, sizeof ( server ) ); - server.st_port = htons ( uri_port ( http->uri, default_port ) ); + server.st_port = htons ( proxied_uri_port ( uri, default_port ) ); socket = &http->socket; if ( filter ) { - if ( ( rc = filter ( socket, uri->host, &socket ) ) != 0 ) + if ( ( rc = filter ( socket, proxied_uri_host ( uri ), &socket ) ) != 0 ) goto err; } if ( ( rc = xfer_open_named_socket ( socket, SOCK_STREAM, ( struct sockaddr * ) &server, - uri->host, NULL ) ) != 0 ) + proxied_uri_host ( uri ), NULL ) ) != 0 ) goto err; /* Attach to parent interface, mortalise self, and return */