From: Michael Brown Date: Mon, 13 Jul 2026 14:39:00 +0000 (+0100) Subject: [http] Allow issuing requests with an explicitly specified HTTP method X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=dcdba1814239cd891090fb3aea009c736987d66a;p=thirdparty%2Fipxe.git [http] Allow issuing requests with an explicitly specified HTTP method The design of IMDSv2 within both AWS and Alibaba Cloud requires the client to obtain a temporary token via an HTTP PUT request. There is no authentication on this request and there is no associated request body: the requirement to use PUT exists solely to reduce the attack surface for SSRF attacks (since vulnerable servers are much more likely to be able to be tricked into issuing a GET request than a PUT request). iPXE can currently issue requests using HTTP GET (if the request body is empty) or HTTP POST (if the request body includes form parameters). There is no support for issuing a PUT request, or for allowing a script to explicitly specify the HTTP method. Add a "--method" option to the "params" command to allow an arbitrary request method name to be specified, and use this as the HTTP request method. Signed-off-by: Michael Brown --- diff --git a/src/core/params.c b/src/core/params.c index b14accafe..bd96501d7 100644 --- a/src/core/params.c +++ b/src/core/params.c @@ -83,12 +83,16 @@ struct parameters * find_parameters ( const char *name ) { * Create request parameter list * * @v name Parameter list name (may be NULL) + * @v method Method name (may be NULL) * @ret params Parameter list, or NULL on failure */ -struct parameters * create_parameters ( const char *name ) { +struct parameters * create_parameters ( const char *name, + const char *method ) { struct parameters *params; size_t name_len; + size_t method_len; char *name_copy; + char *method_copy; /* Destroy any existing parameter list of this name */ params = find_parameters ( name ); @@ -99,23 +103,33 @@ struct parameters * create_parameters ( const char *name ) { /* Allocate parameter list */ name_len = ( name ? ( strlen ( name ) + 1 /* NUL */ ) : 0 ); - params = zalloc ( sizeof ( *params ) + name_len ); + method_len = ( method ? ( strlen ( method ) + 1 /* NUL */ ) : 0 ); + params = zalloc ( sizeof ( *params ) + name_len + method_len ); if ( ! params ) return NULL; ref_init ( ¶ms->refcnt, free_parameters ); - name_copy = ( ( void * ) ( params + 1 ) ); + name_copy = ( ( ( void * ) params ) + sizeof ( *params ) ); + method_copy = ( ( ( void * ) name_copy ) + name_len ); /* Populate parameter list */ if ( name ) { strcpy ( name_copy, name ); params->name = name_copy; } + if ( method ) { + strcpy ( method_copy, method ); + params->method = method_copy; + } INIT_LIST_HEAD ( ¶ms->entries ); /* Add to list of parameter lists */ list_add_tail ( ¶ms->list, ¶meters ); DBGC ( params, "PARAMS \"%s\" created\n", params->name ); + if ( params->method ) { + DBGC ( params, "PARAMS \"%s\" method is \"%s\"\n", + params->name, params->method ); + } return params; } diff --git a/src/hci/commands/param_cmd.c b/src/hci/commands/param_cmd.c index ed57c5eaa..aec3895c5 100644 --- a/src/hci/commands/param_cmd.c +++ b/src/hci/commands/param_cmd.c @@ -41,6 +41,8 @@ FILE_SECBOOT ( PERMITTED ); struct params_options { /** Name */ char *name; + /** Method */ + char *method; /** Delete */ int delete; }; @@ -49,6 +51,8 @@ struct params_options { static struct option_descriptor params_opts[] = { OPTION_DESC ( "name", 'n', required_argument, struct params_options, name, parse_string ), + OPTION_DESC ( "method", 'm', required_argument, + struct params_options, method, parse_string ), OPTION_DESC ( "delete", 'd', no_argument, struct params_options, delete, parse_flag ), }; @@ -74,7 +78,7 @@ static int params_exec ( int argc, char **argv ) { return rc; /* Create parameter list */ - params = create_parameters ( opts.name ); + params = create_parameters ( opts.name, opts.method ); if ( ! params ) return -ENOMEM; diff --git a/src/include/ipxe/http.h b/src/include/ipxe/http.h index e84a75237..e96c2c881 100644 --- a/src/include/ipxe/http.h +++ b/src/include/ipxe/http.h @@ -102,9 +102,16 @@ struct http_method { const char *name; }; -extern struct http_method http_head; -extern struct http_method http_get; -extern struct http_method http_post; +/** HTTP method table */ +#define HTTP_METHODS __table ( struct http_method, "http_methods" ) + +/** Declare an HTTP method */ +#define __http_method __table_entry ( HTTP_METHODS, 01 ) + +extern struct http_method http_head __http_method; +extern struct http_method http_get __http_method; +extern struct http_method http_post __http_method; +extern struct http_method http_put __http_method; /****************************************************************************** * diff --git a/src/include/ipxe/params.h b/src/include/ipxe/params.h index 64008380e..bb7420b1d 100644 --- a/src/include/ipxe/params.h +++ b/src/include/ipxe/params.h @@ -21,6 +21,8 @@ struct parameters { struct list_head list; /** Name */ const char *name; + /** Request method */ + const char *method; /** Parameters */ struct list_head entries; }; @@ -85,7 +87,8 @@ claim_parameters ( struct parameters *params ) { list_for_each_entry ( (param), &(params)->entries, list ) extern struct parameters * find_parameters ( const char *name ); -extern struct parameters * create_parameters ( const char *name ); +extern struct parameters * create_parameters ( const char *name, + const char *method ); extern struct parameter * add_parameter ( struct parameters *params, const char *key, const char *value, unsigned int flags ); diff --git a/src/net/tcp/httpcore.c b/src/net/tcp/httpcore.c index 1180faa98..7dbb0e304 100644 --- a/src/net/tcp/httpcore.c +++ b/src/net/tcp/httpcore.c @@ -136,20 +136,43 @@ static struct http_transfer_encoding http_transfer_identity; */ /** HTTP HEAD method */ -struct http_method http_head = { +struct http_method http_head __http_method = { .name = "HEAD", }; /** HTTP GET method */ -struct http_method http_get = { +struct http_method http_get __http_method = { .name = "GET", }; /** HTTP POST method */ -struct http_method http_post = { +struct http_method http_post __http_method = { .name = "POST", }; +/** HTTP PUT method */ +struct http_method http_put __http_method = { + .name = "PUT", +}; + +/** + * Identify HTTP method + * + * @v name Method name + * @ret method HTTP method, or NULL if not known + */ +static struct http_method * http_method ( const char *name ) { + struct http_method *method; + + /* Identify method */ + for_each_table_entry ( method, HTTP_METHODS ) { + if ( strcasecmp ( name, method->name ) == 0 ) + return method; + } + + return NULL; +} + /****************************************************************************** * * Utility functions @@ -2025,6 +2048,17 @@ int http_open_uri ( struct interface *xfer, struct uri *uri ) { data = NULL; } + /* Use explicitly requested method name if applicable */ + if ( params && params->method ) { + method = http_method ( params->method ); + if ( ! method ) { + DBGC ( uri, "HTTP unsupported method \"%s\"\n", + params->method ); + rc = -ENOTSUP; + goto err_method; + } + } + /* Construct request content */ content.type = type; content.data = data; @@ -2035,6 +2069,7 @@ int http_open_uri ( struct interface *xfer, struct uri *uri ) { goto err_open; err_open: + err_method: free ( data ); err_alloc: return rc; diff --git a/src/tests/uri_test.c b/src/tests/uri_test.c index fa46e22f2..96942c393 100644 --- a/src/tests/uri_test.c +++ b/src/tests/uri_test.c @@ -455,7 +455,7 @@ static void uri_params_okx ( struct uri_params_test *test, const char *file, struct uri *dup; /* Create parameter list */ - params = create_parameters ( test->name ); + params = create_parameters ( test->name, NULL ); okx ( params != NULL, file, line ); if ( params ) { for ( list = test->list ; list->key ; list++ ) {