-
Notifications
You must be signed in to change notification settings - Fork 103
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
Fix farious frang errors #1200
Fix farious frang errors #1200
Conversation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I made a very quick high-level review, a more accurate reviews are required.
ca946b0
to
8993afa
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It seems not all #1028 requirements are satisfied and some logic should be reworked.
e10a035
to
ce8d74d
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Basically this version is good, but there are several architectural questions and notes, so I'd like to discuss the notes and review the next changes afterwards.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
No changes since last review, please fix them ASAP.
7288cda
to
2cbd599
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Small improvements are still required. The most crucial change is to call Frang on moving from HTTP headers to HTTP body.
if (hdr_tmt) { | ||
req->tm_header = jiffies; | ||
if (!f_cfg->http_trailer_split) | ||
return TFW_PASS; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please add framg_msg()
here to notify about the reason for a request blocking
: req->vhost->frang_gconf; | ||
tfw_cli_conn_close_all_sync((TfwClient *)req->conn->peer); | ||
if (fg_cfg->ip_block) | ||
tfw_filter_block_ip(&FRANG_ACC2CLI(ra)->addr); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This comment is till not addressed. If we block IP, but leave a client connection, then we can send data to a client, but we won't receive neither ACK not probbing response from it - the connection will spend our resources untill OS closes it.
I believe we should call tfw_filter_block_ip()
only with connection closing, i.e. there should be a new API function or tfw_filter_block_ip()
just can call connection closing. Next, we can not do normal close here, because on blocked IP, we can not receive FIN-ACK and the connection hangs. We need to use RST closing or just free the connection resources silently.
The proper closing is the subject for #861 and sycnhronous doesn't solve the issue.
: req->vhost->frang_gconf; | ||
tfw_cli_conn_close_all_sync((TfwClient *)req->conn->peer); | ||
if (fg_cfg->ip_block) | ||
tfw_filter_block_ip(&FRANG_ACC2CLI(ra)->addr); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think it makes sense just to remove or comment (out?) the synchronous closing with TODO referering #860.
if (r == TFW_PASS && resp_cblk) | ||
r = frang_bad_resp_limit(ra, resp_cblk); | ||
__FRANG_FSM_MOVE(Frang_Req_Hdr_Start); | ||
r = frang_http_req_incomplete_body_check(ra, data, fg_cfg, f_cfg); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
OK, make sense. Please write explicitly in the Wiki that we process trailers accordingly the body limits.
|
||
bool http_ct_required; | ||
bool http_host_required; | ||
bool http_trailer_split; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please comment the field above
.deflt = "false", | ||
.handler = tfw_cfgop_frang_trailer_split, | ||
.allow_reconfig = true, | ||
}, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Wiki and #673 must be updated for the new configuration option.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Patchset is large so I'll submit my comments so far. From the part I looked into, I found no major issues. Mostly spelling typos, and also some side notes. (Feel free to mark them as resolved at your discretion.)
I'll continue to read the patchset further.
etc/tempesta_fw.conf
Outdated
@@ -921,10 +921,14 @@ | |||
|
|||
# TAG: frang_limits | |||
# | |||
# The section containing static limits for the classifier. | |||
# The section containing static limits for the classifier. Can apper at top |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
# The section containing static limits for the classifier. Can apper at top | |
# The section containing static limits for the classifier. Can appear at the top |
etc/tempesta_fw.conf
Outdated
# The section containing static limits for the classifier. | ||
# The section containing static limits for the classifier. Can apper at top | ||
# level, inside 'vhost' directive, inside 'location' directive. Once the | ||
# directive is listed in the configuration it redefine default vaues for |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
# directive is listed in the configuration it redefine default vaues for | |
# directive is listed in the configuration it redefines default values for the |
tempesta_fw/http.c
Outdated
* - get vhost from the HTTP session information (by Sticky cookie); | ||
* - get Vhost according to TLS SNI header parsing. | ||
* But vhost returned from all that functions can be very different | ||
* depending on HTTP chain configuration due to it flexibility and |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
* depending on HTTP chain configuration due to it flexibility and | |
* depending on HTTP chain configuration due to its flexibility and |
tempesta_fw/http.c
Outdated
* But vhost returned from all that functions can be very different | ||
* depending on HTTP chain configuration due to it flexibility and | ||
* client (attacker) behaviour. | ||
* The most secure and a slow way: compare all of them and reject if |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
* The most secure and a slow way: compare all of them and reject if | |
* The most secure and slow way: compare all of them and reject if |
tempesta_fw/http.c
Outdated
* depending on HTTP chain configuration due to it flexibility and | ||
* client (attacker) behaviour. | ||
* The most secure and a slow way: compare all of them and reject if | ||
* at least some doesn't match. Can be too strict, service quality can |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
* at least some doesn't match. Can be too strict, service quality can | |
* at least some do not match. Can be too strict, service quality can |
tempesta_fw/sock_clnt.c
Outdated
@@ -298,6 +310,21 @@ tfw_cli_conn_close_all(void *data) | |||
return tfw_peer_for_each_conn(cli, conn, list, __cli_conn_close_cb); | |||
} | |||
|
|||
/** | |||
* Close all connections with given client, called on security events. Unlike | |||
* asynchronous function above, this one must guarantee that all the close |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'd propose to change "asynchronous function above" to "tfw_cli_conn_close_all". It's too easy to add another function between these two, and so to accidentally make the comment wrong.
tempesta_fw/sock_clnt.c
Outdated
* Close all connections with given client, called on security events. Unlike | ||
* asynchronous function above, this one must guarantee that all the close | ||
* requests will be done. Attackers can spam Tempesta with lot of requests and | ||
* connections, trying to cause work queue overrun and delay of security events |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
* connections, trying to cause work queue overrun and delay of security events | |
* connections, trying to cause a work queue overrun and delay security events |
} | ||
|
||
if (!READ_ONCE(tfw_tls.fallback_to_dflt_sni) || !vhost->vhost_dflt) { | ||
tfw_vhost_put(vhost); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Function name says it "gets", but here it puts the refcounter on vhost
. Wouldn't be better to leave putting vhosts to the calling side?
tempesta_fw/tls.c
Outdated
/** | ||
* Find matching vhost according to server name in SNI extension. The function | ||
* is also called if there is no SNI extension and fallback to some default | ||
* configuration is required. In the last case @data is NULL and @len is 0. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
* configuration is required. In the last case @data is NULL and @len is 0. | |
* configuration is required. In the latter case @data is NULL and @len is 0. |
tempesta_fw/tls.c
Outdated
return -TTLS_ERR_BAD_HS_CLIENT_HELLO; | ||
|
||
if (data && len) | ||
vhost = tfw_vhost_lookup(&srv_name); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
vhost = tfw_vhost_lookup(&srv_name); | |
vhost = tfw_vhost_lookup(&srv_name); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Found no issues with the PR, looks good.
There are some more spelling comments below. And also a comment about locking required for configuration processing. If that turns out to be a real issue and not something I mistakenly saw as a bug, its fix is beyond the scope of this PR anyway.
tempesta_fw/tls.c
Outdated
@@ -625,6 +630,74 @@ static TfwConnHooks tls_conn_hooks = { | |||
.conn_send = tfw_tls_conn_send, | |||
}; | |||
|
|||
static bool | |||
tfw_tls_get_if_configured(TlsCtx *ctx, TfwVhost *vhost) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The function only uses ctx
to set ctx->peer_conf
. This parameter can be easily removed along with making function to return cfg
on success or NULL
on failure. That way it will be obvious that function won't touch TlsCtx
at all, and only needs TfwVhost
to make a decision.
tempesta_fw/tls.c
Outdated
ttls_pk_context key; | ||
unsigned long crt_pg_addr; | ||
unsigned int crt_pg_order; | ||
bool allow_unknown_sni; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
"Allow unknown server name indication" sounds a bit off. Perhaps, "allow_unknown_server_name"?
Also, what does this flag mean? As far as I can understand from the code, it's something like: "If client did not provide SNI extension, or if the name in that extension did not correspond to any known vhosts, use the default one". Is that correct?
tempesta_fw/tls.c
Outdated
unsigned long crt_pg_addr; | ||
unsigned int crt_pg_order; | ||
bool allow_unknown_sni; | ||
bool fallback_to_dflt_sni; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
"sni" here also contains "indication" part, which doesn't make sense in a flag name.
Also, what does this flag mean? As far as I can tell, it's: "If selected vhost does not contain required TLS configuration, use configuration from the default vhost". Is that correct?
tempesta_fw/tls_conf.c
Outdated
static int | ||
tfw_tls_peer_tls_init(TfwVhost *vhost) | ||
{ | ||
TlsConfEntry *conf = (TlsConfEntry *)vhost->tls_cfg.priv; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Explicit cast is not necessary here.
tempesta_fw/tls_conf.c
Outdated
static inline TlsCertConf * | ||
tfw_tls_get_cert_conf(TfwVhost *vhost, unsigned int directive) | ||
{ | ||
TlsConfEntry *conf = (TlsConfEntry *)vhost->tls_cfg.priv; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Type casting is not required here.
tempesta_fw/vhost.c
Outdated
return 0; | ||
|
||
/* | ||
* Implicit default vhost is still useful even if it never used to |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
* Implicit default vhost is still useful even if it never used to | |
* Implicit default vhost is still useful even if it's never used to |
if (tfw_frang_cfg_inherit(vh_dflt->loc_dflt->frang_cfg, | ||
&tfw_frang_vhost_reconfig)) | ||
return -ENOMEM; | ||
sg_def = tfw_sg_lookup_reconfig(TFW_VH_DFT_NAME, SLEN("default")); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
sg_def = tfw_sg_lookup_reconfig(TFW_VH_DFT_NAME, SLEN("default")); | |
sg_def = tfw_sg_lookup_reconfig(TFW_VH_DFT_NAME, SLEN(TFW_VH_DFT_NAME)); |
rcu_read_lock(); | ||
vh_list = rcu_dereference(tfw_vhosts); | ||
rcu_read_unlock(); | ||
rcu_assign_pointer(tfw_vhosts, tfw_vhosts_reconfig); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I believe here is an issue with multiple threads calling this function. For example, if administrator starts Tempesta multiple times in parallel. Then we can get here in two or more threads, get non-NULL vh_list
, and then try to release its contents multiple times.
The obvious solution is to wrap rcu_dereference and rcu_assign_pointer with a lock. But since this line uses tfw_vhosts_reconfig
which contents is updated in many places, we need a larger scope lock that protect whole configuration sequence.
tempesta_fw/vhost.c
Outdated
static TfwCfgSpec tfw_vhost_location_specs[] = { | ||
/* | ||
* Not all Frang specs can be applied to nested locations and can be applied | ||
* only as high-level options. It's possible to provide it's own sets for global |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
* only as high-level options. It's possible to provide it's own sets for global | |
* only as high-level options. It's possible to provide their own sets for global |
tls/ttls.h
Outdated
* ttls_set_hs_ca_chain() as well as the client | ||
* authentication mode with \c ttls_set_hs_authmode(), | ||
* certificate is found, the callback must fill the | ||
* peer tls configuration part in TLS context, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
* peer tls configuration part in TLS context, | |
* peer tls configuration part in the TLS context, |
Corrected tests, because in this PR blocking by |
@@ -252,7 +252,7 @@ typedef struct { | |||
do { \ | |||
char abuf[TFW_ADDR_STR_BUF_SIZE] = {0}; \ | |||
tfw_addr_fmt(addr, TFW_NO_PORT, abuf); \ | |||
TFW_DBG("frang: " fmt_msg, abuf, ##__VA_ARGS__); \ | |||
T_DBG("frang: " fmt_msg, abuf, ##__VA_ARGS__); \ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Strange space at the end of the line.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It's a tabulation. As there is \
at the end of the line, some spacing is required anyway.
tls/ttls.h
Outdated
typedef struct { | ||
/** allowed ciphersuites per version */ | ||
const int *ciphersuite_list[4]; | ||
/** allowed curves */ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Strange tabs at the end of comments and also below
…ined Default vhost stores default policies for the connection or requests. Remove differences between implicit and explicit 'default' vhosts and make it possible to assign such vhost to a connection or request.
It was discussed, that all client connections with unknown or not set sni must always use default vhost. Thus there is no need in 'tls_fallback_default' directive at all: it would be always enabled.
# Conflicts: # tempesta_fw/vhost.c
6b4f1be
to
e0e1fb7
Compare
fix #1028
Fixed:
TfwHttpReq->frang_st
duplicates existing Gfsm state in frang FSM and it was removed. Frang states are hookable now, so advanced analytics can be attached to it.UPD
Major updates in handling frang directives.
Frang directives now are really per-vhost and per-location. Each vhost and location may include
frang_limits
section now. Previous behaviour: frang limits may be defined only globally and only inside locations (and not inside vhosts!), but limits was listed in locations without grouping into sectionfrang_limits
Nested locations and vhosts inherit Frang configuration from parents.
frang_limits
section now can appear many times on the same level to force new defaults before new bunch of vhosts|locations. Previous behaviour: no inheritance, every location must define it's own frang settings, so less copy-paste now.Frang limits was split into two groups: global and per-vhost. Since messages are received by parts, it's not possible to deduce which per-vhost limits should be applied before the whole message is received. So some limits has no sense in beeing per-vhost, they're global now.