📄 ssl_engine_io.c
字号:
ctx->bb = apr_brigade_create(ctx->pool, c->bucket_alloc); /* ... and a temporary brigade. */ tempb = apr_brigade_create(r->pool, c->bucket_alloc); ap_log_cerror(APLOG_MARK, APLOG_DEBUG, 0, c, "filling buffer"); do { apr_status_t rv; apr_bucket *e, *next; /* The request body is read from the protocol-level input * filters; the buffering filter will reinject it from that * level, allowing content/resource filters to run later, if * necessary. */ rv = ap_get_brigade(r->proto_input_filters, tempb, AP_MODE_READBYTES, APR_BLOCK_READ, 8192); if (rv) { ap_log_rerror(APLOG_MARK, APLOG_ERR, rv, r, "could not read request body for SSL buffer"); return HTTP_INTERNAL_SERVER_ERROR; } /* Iterate through the returned brigade: setaside each bucket * into the context's pool and move it into the brigade. */ for (e = APR_BRIGADE_FIRST(tempb); e != APR_BRIGADE_SENTINEL(tempb) && !eos; e = next) { const char *data; apr_size_t len; next = APR_BUCKET_NEXT(e); if (APR_BUCKET_IS_EOS(e)) { eos = 1; } else if (!APR_BUCKET_IS_METADATA(e)) { rv = apr_bucket_read(e, &data, &len, APR_BLOCK_READ); if (rv != APR_SUCCESS) { ap_log_rerror(APLOG_MARK, APLOG_ERR, rv, r, "could not read bucket for SSL buffer"); return HTTP_INTERNAL_SERVER_ERROR; } total += len; } rv = apr_bucket_setaside(e, ctx->pool); if (rv != APR_SUCCESS) { ap_log_rerror(APLOG_MARK, APLOG_ERR, rv, r, "could not setaside bucket for SSL buffer"); return HTTP_INTERNAL_SERVER_ERROR; } APR_BUCKET_REMOVE(e); APR_BRIGADE_INSERT_TAIL(ctx->bb, e); } ap_log_cerror(APLOG_MARK, APLOG_DEBUG, 0, c, "total of %" APR_OFF_T_FMT " bytes in buffer, eos=%d", total, eos); /* Fail if this exceeds the maximum buffer size. */ if (total > SSL_MAX_IO_BUFFER) { ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, "request body exceeds maximum size for SSL buffer"); return HTTP_REQUEST_ENTITY_TOO_LARGE; } } while (!eos); apr_brigade_destroy(tempb); /* After consuming all protocol-level input, remove all protocol-level * filters. It should strictly only be necessary to remove filters * at exactly ftype == AP_FTYPE_PROTOCOL, since this filter will * precede all > AP_FTYPE_PROTOCOL anyway. */ while (r->proto_input_filters->frec->ftype < AP_FTYPE_CONNECTION) { ap_remove_input_filter(r->proto_input_filters); } /* Insert the filter which will supply the buffered content. */ ap_add_input_filter(ssl_io_buffer, ctx, r, c); return 0;}/* This input filter supplies the buffered request body to the caller * from the brigade stored in f->ctx. Note that the placement of this * filter in the filter stack is important; it must be the first * r->proto_input_filter; lower-typed filters will not be preserved * across internal redirects (see PR 43738). */static apr_status_t ssl_io_filter_buffer(ap_filter_t *f, apr_bucket_brigade *bb, ap_input_mode_t mode, apr_read_type_e block, apr_off_t bytes){ struct modssl_buffer_ctx *ctx = f->ctx; apr_status_t rv; ap_log_cerror(APLOG_MARK, APLOG_DEBUG, 0, f->c, "read from buffered SSL brigade, mode %d, " "%" APR_OFF_T_FMT " bytes", mode, bytes); if (mode != AP_MODE_READBYTES && mode != AP_MODE_GETLINE) { return APR_ENOTIMPL; } if (APR_BRIGADE_EMPTY(ctx->bb)) { /* Suprisingly (and perhaps, wrongly), the request body can be * pulled from the input filter stack more than once; a * handler may read it, and ap_discard_request_body() will * attempt to do so again after *every* request. So input * filters must be prepared to give up an EOS if invoked after * initially reading the request. The HTTP_IN filter does this * with its ->eos_sent flag. */ APR_BRIGADE_INSERT_TAIL(bb, apr_bucket_eos_create(f->c->bucket_alloc)); return APR_SUCCESS; } if (mode == AP_MODE_READBYTES) { apr_bucket *e; /* Partition the buffered brigade. */ rv = apr_brigade_partition(ctx->bb, bytes, &e); if (rv && rv != APR_INCOMPLETE) { ap_log_cerror(APLOG_MARK, APLOG_ERR, rv, f->c, "could not partition buffered SSL brigade"); ap_remove_input_filter(f); return rv; } /* If the buffered brigade contains less then the requested * length, just pass it all back. */ if (rv == APR_INCOMPLETE) { APR_BRIGADE_CONCAT(bb, ctx->bb); } else { apr_bucket *d = APR_BRIGADE_FIRST(ctx->bb); e = APR_BUCKET_PREV(e); /* Unsplice the partitioned segment and move it into the * passed-in brigade; no convenient way to do this with * the APR_BRIGADE_* macros. */ APR_RING_UNSPLICE(d, e, link); APR_RING_SPLICE_HEAD(&bb->list, d, e, apr_bucket, link); APR_BRIGADE_CHECK_CONSISTENCY(bb); APR_BRIGADE_CHECK_CONSISTENCY(ctx->bb); } } else { /* Split a line into the passed-in brigade. */ rv = apr_brigade_split_line(bb, ctx->bb, mode, bytes); if (rv) { ap_log_cerror(APLOG_MARK, APLOG_ERR, rv, f->c, "could not split line from buffered SSL brigade"); ap_remove_input_filter(f); return rv; } } if (APR_BRIGADE_EMPTY(ctx->bb)) { apr_bucket *e = APR_BRIGADE_LAST(bb); /* Ensure that the brigade is terminated by an EOS if the * buffered request body has been entirely consumed. */ if (e == APR_BRIGADE_SENTINEL(bb) || !APR_BUCKET_IS_EOS(e)) { e = apr_bucket_eos_create(f->c->bucket_alloc); APR_BRIGADE_INSERT_TAIL(bb, e); } ap_log_cerror(APLOG_MARK, APLOG_DEBUG, 0, f->c, "buffered SSL brigade exhausted"); /* Note that the filter must *not* be removed here; it may be * invoked again, see comment above. */ } return APR_SUCCESS;}static void ssl_io_input_add_filter(ssl_filter_ctx_t *filter_ctx, conn_rec *c, SSL *ssl){ bio_filter_in_ctx_t *inctx; inctx = apr_palloc(c->pool, sizeof(*inctx)); filter_ctx->pInputFilter = ap_add_input_filter(ssl_io_filter, inctx, NULL, c); filter_ctx->pbioRead = BIO_new(&bio_filter_in_method); filter_ctx->pbioRead->ptr = (void *)inctx; inctx->ssl = ssl; inctx->bio_out = filter_ctx->pbioWrite; inctx->f = filter_ctx->pInputFilter; inctx->rc = APR_SUCCESS; inctx->mode = AP_MODE_READBYTES; inctx->cbuf.length = 0; inctx->bb = apr_brigade_create(c->pool, c->bucket_alloc); inctx->block = APR_BLOCK_READ; inctx->pool = c->pool; inctx->filter_ctx = filter_ctx;}void ssl_io_filter_init(conn_rec *c, SSL *ssl){ ssl_filter_ctx_t *filter_ctx; filter_ctx = apr_palloc(c->pool, sizeof(ssl_filter_ctx_t)); filter_ctx->nobuffer = 0; filter_ctx->pOutputFilter = ap_add_output_filter(ssl_io_filter, filter_ctx, NULL, c); filter_ctx->pbioWrite = BIO_new(&bio_filter_out_method); filter_ctx->pbioWrite->ptr = (void *)bio_filter_out_ctx_new(filter_ctx, c); /* We insert a clogging input filter. Let the core know. */ c->clogging_input_filters = 1; ssl_io_input_add_filter(filter_ctx, c, ssl); SSL_set_bio(ssl, filter_ctx->pbioRead, filter_ctx->pbioWrite); filter_ctx->pssl = ssl; apr_pool_cleanup_register(c->pool, (void*)filter_ctx, ssl_io_filter_cleanup, apr_pool_cleanup_null); if (c->base_server->loglevel >= APLOG_DEBUG) { BIO_set_callback(SSL_get_rbio(ssl), ssl_io_data_cb); BIO_set_callback_arg(SSL_get_rbio(ssl), (void *)ssl); } return;}void ssl_io_filter_register(apr_pool_t *p){ /* This filter MUST be after the HTTP_HEADER filter, but it also must be * a resource-level filter so it has the request_rec. */ ap_register_output_filter ("UPGRADE_FILTER", ssl_io_filter_Upgrade, NULL, AP_FTYPE_PROTOCOL + 5); ap_register_input_filter (ssl_io_filter, ssl_io_filter_input, NULL, AP_FTYPE_CONNECTION + 5); ap_register_output_filter (ssl_io_filter, ssl_io_filter_output, NULL, AP_FTYPE_CONNECTION + 5); ap_register_input_filter (ssl_io_buffer, ssl_io_filter_buffer, NULL, AP_FTYPE_PROTOCOL); return;}/* _________________________________________________________________**** I/O Data Debugging** _________________________________________________________________*/#define DUMP_WIDTH 16static void ssl_io_data_dump(server_rec *srvr, MODSSL_BIO_CB_ARG_TYPE *s, long len){ char buf[256]; char tmp[64]; int i, j, rows, trunc; unsigned char ch; trunc = 0; for(; (len > 0) && ((s[len-1] == ' ') || (s[len-1] == '\0')); len--) trunc++; rows = (len / DUMP_WIDTH); if ((rows * DUMP_WIDTH) < len) rows++; ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, srvr, "+-------------------------------------------------------------------------+"); for(i = 0 ; i< rows; i++) {#if APR_CHARSET_EBCDIC char ebcdic_text[DUMP_WIDTH]; /* Determine how many bytes we are going to process in this row. */ j = DUMP_WIDTH; if ((i * DUMP_WIDTH + j) > len) j = len % DUMP_WIDTH; if (j == 0) j = DUMP_WIDTH; memcpy(ebcdic_text, (char *)(s) + i * DUMP_WIDTH, j); ap_xlate_proto_from_ascii(ebcdic_text, j);#endif apr_snprintf(tmp, sizeof(tmp), "| %04x: ", i * DUMP_WIDTH); apr_cpystrn(buf, tmp, sizeof(buf)); for (j = 0; j < DUMP_WIDTH; j++) { if (((i * DUMP_WIDTH) + j) >= len) apr_cpystrn(buf+strlen(buf), " ", sizeof(buf)-strlen(buf)); else { ch = ((unsigned char)*((char *)(s) + i * DUMP_WIDTH + j)) & 0xff; apr_snprintf(tmp, sizeof(tmp), "%02x%c", ch , j==7 ? '-' : ' '); apr_cpystrn(buf+strlen(buf), tmp, sizeof(buf)-strlen(buf)); } } apr_cpystrn(buf+strlen(buf), " ", sizeof(buf)-strlen(buf)); for (j = 0; j < DUMP_WIDTH; j++) { if (((i * DUMP_WIDTH) + j) >= len) apr_cpystrn(buf+strlen(buf), " ", sizeof(buf)-strlen(buf)); else { ch = ((unsigned char)*((char *)(s) + i * DUMP_WIDTH + j)) & 0xff;#if APR_CHARSET_EBCDIC apr_snprintf(tmp, sizeof(tmp), "%c", ((ch >= 0x20 /*' '*/) && (ch <= 0x7e /*'~'*/)) ? ebcdic_text[j] : '.');#else apr_snprintf(tmp, sizeof(tmp), "%c", ((ch >= ' ') && (ch <= '~')) ? ch : '.');#endif apr_cpystrn(buf+strlen(buf), tmp, sizeof(buf)-strlen(buf)); } } apr_cpystrn(buf+strlen(buf), " |", sizeof(buf)-strlen(buf)); ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, srvr, "%s", buf); } if (trunc > 0) ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, srvr, "| %04ld - <SPACES/NULS>", len + trunc); ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, srvr, "+-------------------------------------------------------------------------+"); return;}long ssl_io_data_cb(BIO *bio, int cmd, MODSSL_BIO_CB_ARG_TYPE *argp, int argi, long argl, long rc){ SSL *ssl; conn_rec *c; server_rec *s; if ((ssl = (SSL *)BIO_get_callback_arg(bio)) == NULL) return rc; if ((c = (conn_rec *)SSL_get_app_data(ssl)) == NULL) return rc; s = c->base_server; if ( cmd == (BIO_CB_WRITE|BIO_CB_RETURN) || cmd == (BIO_CB_READ |BIO_CB_RETURN) ) { if (rc >= 0) { ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, s, "%s: %s %ld/%d bytes %s BIO#%pp [mem: %pp] %s", SSL_LIBRARY_NAME, (cmd == (BIO_CB_WRITE|BIO_CB_RETURN) ? "write" : "read"), rc, argi, (cmd == (BIO_CB_WRITE|BIO_CB_RETURN) ? "to" : "from"), bio, argp, (argp != NULL ? "(BIO dump follows)" : "(Oops, no memory buffer?)")); if (argp != NULL) ssl_io_data_dump(s, argp, rc); } else { ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, s, "%s: I/O error, %d bytes expected to %s on BIO#%pp [mem: %pp]", SSL_LIBRARY_NAME, argi, (cmd == (BIO_CB_WRITE|BIO_CB_RETURN) ? "write" : "read"), bio, argp); } } return rc;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -