Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Prohibit DELETE method in default configuration #2058 #2078

Open
wants to merge 14 commits into
base: master
Choose a base branch
from

Conversation

biathlon3
Copy link
Contributor

My first attempt, I am not sure that it is the best solution, but it seems to work.

fw/http_limits.c Outdated
}
__FRANG_FSM_MOVE(Frang_Req_Hdr_UriLen);
}
T_FSM_STATE(Frang_Req_Hdr_Method) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Invalid tabulation.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sorry, I have changed my editor's behavior.

fw/http_limits.c Outdated

if (!f_cfg->http_methods_mask) {
/* If we have a default value, we set all bits to 1 except DELETE */
f_cfg->http_methods_mask = ~(1 << TFW_HTTP_METH_DELETE);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think we should also prohibit PUT method here

@EvgeniiMekhanik
Copy link
Contributor

You should also fix tests, where DELETE method is used by adding appropriate DELETE method to frang config

Copy link
Contributor

@krizhanovsky krizhanovsky left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Definitely need more work and it seems the issue isn't so straightforward as I thought, so we need a good discussion on this.

Also please make pull requests from our repo, not your own - this way we can just switch between branches during review instead of cloning repos of each developers.

Finally, please don't forget to update wiki about allowed methods by default. Probably it also makes sense to describe in the wiki how DELETE behaves with the cache.

fw/http_limits.c Outdated Show resolved Hide resolved
fw/http_limits.c Outdated Show resolved Hide resolved
fw/http_limits.c Show resolved Hide resolved
fw/http_limits.c Show resolved Hide resolved
Copy link
Contributor

@krizhanovsky krizhanovsky left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM with just a small coding style cleanup

fw/vhost.c Outdated
Comment on lines 135 to 138

#define TFW_FRANG_HTTP_METHODS_MASK_DEFAULT ((1 << TFW_HTTP_METH_GET) | \
(1 << TFW_HTTP_METH_HEAD) | \
(1 << TFW_HTTP_METH_POST))

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
#define TFW_FRANG_HTTP_METHODS_MASK_DEFAULT ((1 << TFW_HTTP_METH_GET) | \
(1 << TFW_HTTP_METH_HEAD) | \
(1 << TFW_HTTP_METH_POST))
#define TFW_FRANG_HTTP_METHODS_MASK_DEFAULT ((1 << TFW_HTTP_METH_GET) | \
(1 << TFW_HTTP_METH_HEAD) | \
(1 << TFW_HTTP_METH_POST))

We almost never use 2 empty lines in C/C++ code and we use alignments (tabs plus spaces)

Copy link
Contributor

@const-t const-t left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would like to suggest another solution. In TfwCfgSpec we can specify default values for each directive.
Example:

{
		.name = "http_methods",
		.deflt = "get post head",
		.handler = tfw_cfgop_frang_http_methods,
		.allow_reconfig = true,
	},

Field deflt it's just value, same as in config, that will be parsed and assigned to directive. Please, change TfwCfgSpec for each context.
Also, I believe, we don't need to remove already made changes, we will treat empty value, as defualt. Or we can remove these changes, and treat empty value of this directive as error - this looks more clear for me. Up to you.

@@ -3220,7 +3237,7 @@ static TfwCfgSpec tfw_vhost_internal_specs[] = {
.handler = tfw_cfg_handle_children,
.cleanup = tfw_cfgop_frang_cleanup,
.dest = tfw_vhost_frang_specs,
.allow_none = true,
.allow_none = false,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why do we set allow_none to false for frang_limits?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If we leave allow_none as true, the default configuration won't be read in spec_finish_handling(TfwCfgSpec specs[]).
It was the reason why I wrote my previous version.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This seems wrong. Are you sure? There are plenty of places in the code with both .allow_none = true and .deflt set to some value.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, guys, I was wrong.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I tested it more careful and found that with .allow_none = true, in this position, it stops using default configuration when vhost is configured in tempesta_fw.cfg.
Looks like I hastened to agree with you. And we need to use .allow_none = false or change behavior of spec_finish_handling(TfwCfgSpec specs[]) or change somthing else.

fw/vhost.c Outdated
return -EINVAL;
}

T_ERR_NL("frang: http_methods should contain at least one "
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks like dead code and we never reach this place. If we have ce->dflt_value == false it means value was specified in config and now we know that this value is empty. Therefore, we will always return in if (!ce->dflt_value). Is there a case when ce->dflt_value == true but ce->val_n == false?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This situation is possible when we have " http_methods ;" in config

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In my understanding when we have " http_methods ;" then we have ce->dflt_value == false and ce->val_n == false in other cases we will have ce->val_n > 0. For example: http_methods ""; or http_methods " "; will have ce->val_n > 0 and will disallowed in TFW_CFG_ENTRY_FOR_EACH_VAL. I can't find another value for http_methods where ce->val_n == 0 except " http_methods ;". Do you know such value for http_methods?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, when we have
.name = "http_methods",
.deflt = "",
in the code

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Now we doesn't, and I believe we must not maintain this. If you warring about this, it would be better to write a comment in appropriate place.

@const-t
Copy link
Contributor

const-t commented Apr 4, 2024

Please remove todo from http_limits.c, when you will rebase.
TODO: Remove when PR #2078 merged

@@ -1142,14 +1140,13 @@ frang_http_req_process(FrangAcc *ra, TfwConn *conn, TfwFsmData *data,

/* Ensure that HTTP request method is one of those defined by a user. */
T_FSM_STATE(Frang_Req_Hdr_Method) {
if (f_cfg->http_methods_mask) {
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I removed checking f_cfg->http_methods_mask because this checking breaks new logic.

biathlon3 and others added 2 commits May 7, 2024 08:36
@krizhanovsky
Copy link
Contributor

Please implement a workaround for #2119 with a TODO comment

biathlon3 and others added 2 commits May 21, 2024 14:53
Fixed reading default value of http_strict_host_checking.
Chenged frang inheritance for locatians in default vhost.
@biathlon3
Copy link
Contributor Author

Please implement a workaround for #2119 with a TODO comment

I manage to do it in normal way.

@const-t
Copy link
Contributor

const-t commented May 31, 2024

A want to ask you to check following(and others similar conditions) part in tfw_http_req_process():

if (res.type == TFW_HTTP_RES_REDIR) {
tfw_http_req_redir(req, res.redir.resp_code, &res.redir);
return T_OK;
}

In this case we don't freed split skb as well. To check it just use redirects.

http_chain redirects {
    # Absolute path
    uri == "/company.html" -> 301 = https://tempesta-tech.com/company;

    # Use variables
    uri == "/blog/" -> 308 = https://$host/$request_uri/;

    # Relative path
    uri == "*/services.html" -> 303 = /services;

    # Temporal redirection for the default index page only to a temporal landing page.
    uri == "/" -> 307 = /c++-services;
}

fw/tls.c Outdated
@@ -1128,6 +1128,11 @@ tfw_tls_start(void)
return 0;
}

bool tfw_tls_get_allow_any_sni_reconfig(void)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
bool tfw_tls_get_allow_any_sni_reconfig(void)
bool
tfw_tls_get_allow_any_sni_reconfig(void)

Copy link
Contributor

@const-t const-t left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In general looks good, but could you add a little bit description to the last commit.

Chenged frang inheritance for locatians in default vhost

Why it's changed, how it's changed. Also looks like you fixed live-reconfig logic for frang, describe it also in the commit message.

fw/http.c Outdated
"parsed request has been filtered out",
HTTP2_ECODE_PROTO);
if (skb) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Seems we can remove this unnecessary condition if (skb) then just assign skb and return r instead of T_DROP.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We should not change return code here, because it is used to determine how Tempesta close connection.
We should also fix this memory leak in all other places in this function.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code reworked. I tried to make it universal, but if you think it is not the best way, I will rework it for special cases only.

Copy link
Contributor

@EvgeniiMekhanik EvgeniiMekhanik left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Change fixing memory leak

# http_uri_len 0;
# http_body_len 1073741824;
# http_hdr_len 0;
# http_header_cnt 0;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

50 is default value for this setting. Please also check all other settings. concurrent_tcp_connections - 1000 is default settings

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed

fw/vhost.c Outdated
@@ -2141,7 +2197,7 @@ tfw_cfgop_frang_strict_host_checking(TfwCfgSpec *cs, TfwCfgEntry *ce)
int r;
FrangVhostCfg *cfg = tfw_cfgop_frang_get_cfg();

if (ce->dflt_value && cfg->http_strict_host_checking)
if (ce->dflt_value && !cfg->http_strict_host_checking)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We need to discuss this place. If I understand it correctly we have the same problem for http_body_len also and may be some other settings.

frang_limits {
    http_body_len 0;
}
frang_limits {
}

The second one frang_limits has default http_body_len == 1073741824, should we override previosly set http_body_len or not?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I returned the old behavior, only explicit parameters should be overridden.

fw/vhost.c Outdated
@@ -1903,6 +1911,11 @@ __tfw_cfgop_frang_http_methods(TfwCfgSpec *cs, TfwCfgEntry *ce,
methods_mask |= (1UL << method_id);
}

if (!ce->val_n && !ce->dflt_value) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You don't need to check !ce->dflt_value here, because if it is dflt_value vam_n is always 3 (get post head). This check is better to do before TFW_CFG_ENTRY_FOR_EACH_VAL loop

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

TFW_CFG_CHECK_VAL_N(>, 0, cs, ce);
TFW_CFG_CHECK_NO_ATTRS(cs, ce);

is right way. Tempesta interpret get=hhhsdsd as attribute and silently ignore such invalid configuration

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Reworked.

fw/vhost.c Outdated
.allow_reconfig = true,
},
{
.name = "http_body_len",
.deflt = "1073741824", /* 1 Gb. */
.handler = tfw_cfgop_frang_body_len,
.handler = tfw_cfgop_frang_glob_set_long,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It is incorrect to use tfw_cfgop_frang_glob_set_long here. If we have global frang limits like below:
frang_limits {
http_body_len 0;
}
frang_limits {
}

We should not override http_body_len 0; in the second config as i understand the idea in all other places.
I thinkn that using tfw_cfgop_frang_glob_set_int for tfw_frang_glob_reconfig.http_hdr_cnt is also incorrect. Same as for concurrent_tcp_connections

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I returned the old behavior, only explicit parameters should be overridden.

fw/vhost.c Outdated
.allow_reconfig = true,
},
{
.name = "http_strict_host_checking",
.deflt = "true",
.handler = tfw_cfgop_frang_strict_host_checking,
.handler = tfw_cfgop_frang_glob_set_bool,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We can't use tfw_cfgop_frang_glob_set_bool here because default value is true.
frang_limits {
http_strict_host_checking false;
}
frang_limits {
}

We have http_strict_host_checking true, but should have false

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please add tests for all this changes! We need to cover all this cases because I found a lot of mistakes here. you should check several frang_limits on one level and how it is work.

if (tfw_frang_cfg_inherit(loc->frang_cfg, vhost->loc_dflt->frang_cfg))
return NULL;
if (strncasecmp(vhost->name.data, TFW_VH_DFT_NAME, vhost->name.len)) {
if (tfw_frang_cfg_inherit(loc->frang_cfg,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please look at this function tfw_frang_cfg_inherit we have BUG in it.
if (!curr->http_ct_vals)
we only set r = -ENOMEM and do not return. Then we memcpy(curr->http_ct_vals, from->http_ct_vals, sz);

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Add else to avoid using curr->http_ct_vals after error.

* Do not perform any SNI<=>authority validation if
* tls_match_any_server_name is set.
*/
if (tfw_tls_allow_any_sni)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why do you delete this check? Previously when tls_match_any_server_name is true, we return T_OK. Why this behavior is changed?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

When tfw_tls_allow_any_sni is true, it means connection with empty sni or sni not listed in our vhost is "routed" to default vhost. In other words tfw_tls_allow_any_sni is the way to enable default vhost and it's not related to other vhosts. But when we have this check here and we want to check SNI vs authority for some vhosts and don't check for other we can't do this, because tfw_tls_allow_any_sni will override it.

Now I would prefer to introduce new knob only for domain fronting, that must be disabled by default. It will depends on tfw_tls_allow_any_sni also, but in the future we will remove default vhost and tfw_tls_allow_any_sni and will check SNI only when vhost is found by http tables.

fw/vhost.c Outdated
static int
tfw_cfgop_frang_glob_rsp_code_block(TfwCfgSpec *cs, TfwCfgEntry *ce)
{
FrangVhostCfg *cfg = &tfw_frang_vhost_reconfig;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why we can't use tfw_cfgop_frang_rsp_code_block. The only difference that here we directly set FrangVhostCfg *cfg = &tfw_frang_vhost_reconfig; instead of FrangVhostCfg *cfg = tfw_cfgop_frang_get_cfg(); ?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It was attempt to solve strange location inheritance for default vhost. I returned it back now because my code had changed overriding.

fw/vhost.c Outdated
kfree(cfg->http_resp_code_block);
cfg->http_resp_code_block = NULL;
}
return __tfw_cfgop_frang_rsp_code_block(cs, ce, cfg);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you also check __tfw_cfgop_frang_rsp_code_block. I see that we return -EINVAL after memory allocation without
freeing previously allocated cb = kzalloc(sizeof(FrangHttpRespCodeBlock), GFP_KERNEL); Is there memory leak or we will free it later?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It assigns to conf->http_resp_code_block and will be freed by __tfw_frang_clean() in case of error.

biathlon3 and others added 2 commits June 10, 2024 13:10
    Only GET, HEAD and POST are allowed by default.
    Global frang initialization happens before
    reading config file.
    Global frang was copied before initialization
    to prevent using old config during live-reconfiguration.
    Fixed memory leak when skb was split
    in tfw_http_req_process().
    Fixed bug in tfw_frang_cfg_inherit().
    tls_match_any_server_name is now permited only globaly.
    Now tls_match_any_server_name and http_strict_host_checking
    are used independandly.
    Changed inheritance for locations of default vhost.
    Added print frang configuration.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

5 participants