| 6577 | } |
| 6578 | |
| 6579 | bool |
| 6580 | HttpTransact::will_this_request_self_loop(State *s) |
| 6581 | { |
| 6582 | // The self-loop detection for this ATS node will allow up to max_proxy_cycles |
| 6583 | // (each time it sees it returns to itself it is one cycle) before declaring a self-looping condition detected. |
| 6584 | // If max_proxy_cycles is > 0 then next-hop is disabled since -- |
| 6585 | // * if first cycle then it is alright okay |
| 6586 | // * if not first cycle then will be detected by via string checking the next time that |
| 6587 | // it enters the node |
| 6588 | int max_proxy_cycles = s->txn_conf->max_proxy_cycles; |
| 6589 | |
| 6590 | //////////////////////////////////////// |
| 6591 | // check if we are about to self loop // |
| 6592 | //////////////////////////////////////// |
| 6593 | if (s->dns_info.active) { |
| 6594 | TxnDbg(dbg_ctl_http_transact, "max_proxy_cycles = %d", max_proxy_cycles); |
| 6595 | if (max_proxy_cycles == 0) { |
| 6596 | in_port_t dst_port = s->hdr_info.client_request.url_get()->port_get(); // going to this port. |
| 6597 | in_port_t local_port = s->client_info.dst_addr.host_order_port(); // already connected proxy port. |
| 6598 | // It's a loop if connecting to the same port as it already connected to the proxy and |
| 6599 | // it's a proxy address or the same address it already connected to. |
| 6600 | TxnDbg(dbg_ctl_http_transact, "dst_port = %d local_port = %d", dst_port, local_port); |
| 6601 | if (dst_port == local_port && ((s->dns_info.active->data.ip == &Machine::instance()->ip.sa) || |
| 6602 | (s->dns_info.active->data.ip == s->client_info.dst_addr))) { |
| 6603 | switch (s->dns_info.looking_up) { |
| 6604 | case ResolveInfo::ORIGIN_SERVER: |
| 6605 | TxnDbg(dbg_ctl_http_transact, "host ip and port same as local ip and port - bailing"); |
| 6606 | break; |
| 6607 | case ResolveInfo::PARENT_PROXY: |
| 6608 | TxnDbg(dbg_ctl_http_transact, "parent proxy ip and port same as local ip and port - bailing"); |
| 6609 | break; |
| 6610 | default: |
| 6611 | TxnDbg(dbg_ctl_http_transact, "unknown's ip and port same as local ip and port - bailing"); |
| 6612 | break; |
| 6613 | } |
| 6614 | SET_VIA_STRING(VIA_ERROR_TYPE, VIA_ERROR_LOOP_DETECTED); |
| 6615 | Metrics::Counter::increment(http_rsb.proxy_loop_detected); |
| 6616 | build_error_response(s, HTTP_STATUS_BAD_REQUEST, "Cycle Detected", "request#cycle_detected"); |
| 6617 | return true; |
| 6618 | } |
| 6619 | } |
| 6620 | |
| 6621 | // Now check for a loop using the Via string. |
| 6622 | int count = 0; |
| 6623 | MIMEField *via_field = s->hdr_info.client_request.field_find(MIME_FIELD_VIA, MIME_LEN_VIA); |
| 6624 | std::string_view uuid{Machine::instance()->uuid.getString()}; |
| 6625 | |
| 6626 | while (via_field) { |
| 6627 | // No need to waste cycles comma separating the via values since we want to do a match anywhere in the |
| 6628 | // in the string. We can just loop over the dup hdr fields |
| 6629 | auto via_string{via_field->value_get()}; |
| 6630 | |
| 6631 | if ((count <= max_proxy_cycles) && via_string.data()) { |
| 6632 | std::string_view current{via_field->value_get()}; |
| 6633 | std::string_view::size_type offset; |
| 6634 | TxnDbg(dbg_ctl_http_transact, "Incoming via: \"%.*s\" --has-- (%s[%s] (%s))", static_cast<int>(via_string.length()), |
| 6635 | via_string.data(), s->http_config_param->proxy_hostname, uuid.data(), |
| 6636 | s->http_config_param->proxy_request_via_string); |
nothing calls this directly
no test coverage detected