aboutsummaryrefslogtreecommitdiffstats
path: root/doc-src/features/reverseproxy.html
blob: 5ef4efc5270e51bd6d75e48bdc4372d18257fce9 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
In reverse proxy mode, mitmproxy accepts standard HTTP requests and forwards
them to the specified upstream server. This is in contrast to
<a href="@!urlTo("upstreamproxy.html")!@">upstream proxy mode</a>, in which
mitmproxy forwards HTTP proxy requests to an upstream proxy server.

<table class="table">
    <tbody>
        <tr>
            <th width="20%">command-line</th> <td>-R <i>schema</i>://hostname[:port]</td>
        </tr>
    </tbody>
</table>

Here, **schema** is one of http, https, http2https or https2http. The latter
two extended schema specifications control the use of HTTP and HTTPS on
mitmproxy and the upstream server. You can indicate that mitmproxy should use
HTTP, and the upstream server uses HTTPS like this:

	http2https://hostname:port

And you can indicate that mitmproxy should use HTTPS while the upstream
service uses HTTP like this:

	https2http://hostname:port


### Host Header

In reverse proxy mode, mitmproxy does not rewrite the host header. While often useful, this
may lead to issues with public web servers. For example, consider the following scenario:

    $ python mitmdump -d -R http://example.com/ &
    $ curl http://localhost:8080/

    >> GET https://example.com/
        Host: localhost:8080
        User-Agent: curl/7.35.0
        [...]

    << 404 Not Found 345B

Since the Host header doesn't match <samp>example.com</samp>, an error is returned.<br>
There are two ways to solve this:
<ol>
    <li>Modify the hosts file of your OS so that example.com resolves to 127.0.0.1.</li>
    <li>
        Instruct mitmproxy to rewrite the host header by passing <kbd>&#8209;&#8209;setheader&nbsp;:~q:Host:example.com</kbd>.
        However, keep in mind that absolute URLs within the returned document or HTTP redirects will cause the client application
        to bypass the proxy.
    </li>
</ol>
acktick */ .highlight .sc { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Char */ .highlight .dl { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Delimiter */ .highlight .sd { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Doc */ .highlight .s2 { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Double */ .highlight .se { color: #0044dd; background-color: #fff0f0 } /* Literal.String.Escape */ .highlight .sh { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Heredoc */ .highlight .si { color: #3333bb; background-color: #fff0f0 } /* Literal.String.Interpol */ .highlight .sx { color: #22bb22; background-color: #f0fff0 } /* Literal.String.Other */ .highlight .sr { color: #008800; background-color: #fff0ff } /* Literal.String.Regex */ .highlight .s1 { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Single */ .highlight .ss { color: #aa6600; background-color: #fff0f0 } /* Literal.String.Symbol */ .highlight .bp { color: #003388 } /* Name.Builtin.Pseudo */ .highlight .fm { color: #0066bb; font-weight: bold } /* Name.Function.Magic */ .highlight .vc { color: #336699 } /* Name.Variable.Class */ .highlight .vg { color: #dd7700 } /* Name.Variable.Global */ .highlight .vi { color: #3333bb } /* Name.Variable.Instance */ .highlight .vm { color: #336699 } /* Name.Variable.Magic */ .highlight .il { color: #0000DD; font-weight: bold } /* Literal.Number.Integer.Long */
/******************************************************************************
 * acm_ops.c
 *
 * Copyright (C) 2005 IBM Corporation
 *
 * Author:
 * Reiner Sailer <sailer@watson.ibm.com>
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License as
 * published by the Free Software Foundation, version 2 of the
 * License.
 *
 * Process acm command requests from guest OS.
 *
 */

#include <xen/config.h>
#include <xen/types.h>
#include <xen/lib.h>
#include <xen/mm.h>
#include <public/acm.h>
#include <public/acm_ops.h>
#include <xen/sched.h>
#include <xen/event.h>
#include <xen/trace.h>
#include <xen/console.h>
#include <asm/shadow.h>
#include <public/sched_ctl.h>
#include <acm/acm_hooks.h>

#ifndef ACM_SECURITY

long do_acm_op(struct acm_op * u_acm_op)
{
    return -ENOSYS;
}

#else

enum acm_operation {
    POLICY,                     /* access to policy interface (early drop) */
    GETPOLICY,                  /* dump policy cache */
    SETPOLICY,                  /* set policy cache (controls security) */
    DUMPSTATS,                  /* dump policy statistics */
    GETSSID,                    /* retrieve ssidref for domain id (decide inside authorized domains) */
    GETDECISION                 /* retrieve ACM decision from authorized domains */
};

int acm_authorize_acm_ops(struct domain *d, enum acm_operation pops)
{
    /* currently, policy management functions are restricted to privileged domains */
    if (!IS_PRIV(d))
        return -EPERM;

    return 0;
}

long do_acm_op(struct acm_op * u_acm_op)
{
    long ret = 0;
    struct acm_op curop, *op = &curop;

    if (acm_authorize_acm_ops(current->domain, POLICY))
        return -EPERM;

    if (copy_from_user(op, u_acm_op, sizeof(*op)))
        return -EFAULT;

    if (op->interface_version != ACM_INTERFACE_VERSION)
        return -EACCES;

    switch (op->cmd)
    {
    case ACM_SETPOLICY:
    {
        ret = acm_authorize_acm_ops(current->domain, SETPOLICY);
        if (!ret)
            ret = acm_set_policy(op->u.setpolicy.pushcache,
                                 op->u.setpolicy.pushcache_size, 1);
    }
    break;

    case ACM_GETPOLICY:
    {
        ret = acm_authorize_acm_ops(current->domain, GETPOLICY);
        if (!ret)
            ret = acm_get_policy(op->u.getpolicy.pullcache,
                                 op->u.getpolicy.pullcache_size);
        if (!ret)
            copy_to_user(u_acm_op, op, sizeof(*op));
    }
    break;

    case ACM_DUMPSTATS:
    {
        ret = acm_authorize_acm_ops(current->domain, DUMPSTATS);
        if (!ret)
            ret = acm_dump_statistics(op->u.dumpstats.pullcache,
                                      op->u.dumpstats.pullcache_size);
        if (!ret)
            copy_to_user(u_acm_op, op, sizeof(*op));
    }
    break;

    case ACM_GETSSID:
    {
        ssidref_t ssidref;

        ret = acm_authorize_acm_ops(current->domain, GETSSID);
        if (ret)
            break;

        if (op->u.getssid.get_ssid_by == SSIDREF)
            ssidref = op->u.getssid.id.ssidref;
        else if (op->u.getssid.get_ssid_by == DOMAINID)
        {
            struct domain *subj = find_domain_by_id(op->u.getssid.id.domainid);
            if (!subj)
            {
                ret = -ESRCH; /* domain not found */
                break;
            }
            if (subj->ssid == NULL)
            {
                put_domain(subj);
                ret = -ESRCH;
                break;
            }
            ssidref = ((struct acm_ssid_domain *)(subj->ssid))->ssidref;
            put_domain(subj);
        }
        else
        {
            ret = -ESRCH;
            break;
        }
        ret = acm_get_ssid(ssidref,
                           op->u.getssid.ssidbuf,
                           op->u.getssid.ssidbuf_size);
        if (!ret)
            copy_to_user(u_acm_op, op, sizeof(*op));
    }
    break;

    case ACM_GETDECISION:
    {
        ssidref_t ssidref1, ssidref2;

        ret = acm_authorize_acm_ops(current->domain, GETDECISION);
        if (ret)
            break;

        if (op->u.getdecision.get_decision_by1 == SSIDREF)
            ssidref1 = op->u.getdecision.id1.ssidref;
        else if (op->u.getdecision.get_decision_by1 == DOMAINID)
        {
            struct domain *subj = find_domain_by_id(op->u.getdecision.id1.domainid);
            if (!subj)
            {
                ret = -ESRCH; /* domain not found */
                break;
            }
            if (subj->ssid == NULL)
            {
                put_domain(subj);
                ret = -ESRCH;
                break;
            }
            ssidref1 = ((struct acm_ssid_domain *)(subj->ssid))->ssidref;
            put_domain(subj);
        }
        else
        {
            ret = -ESRCH;
            break;
        }
        if (op->u.getdecision.get_decision_by2 == SSIDREF)
            ssidref2 = op->u.getdecision.id2.ssidref;
        else if (op->u.getdecision.get_decision_by2 == DOMAINID)
        {
            struct domain *subj = find_domain_by_id(op->u.getdecision.id2.domainid);
            if (!subj)
            {
                ret = -ESRCH; /* domain not found */
                break;;
            }
            if (subj->ssid == NULL)
            {
                put_domain(subj);
                ret = -ESRCH;
                break;
            }
            ssidref2 = ((struct acm_ssid_domain *)(subj->ssid))->ssidref;
            put_domain(subj);
        }
        else
        {
            ret = -ESRCH;
            break;
        }
        ret = acm_get_decision(ssidref1, ssidref2, op->u.getdecision.hook);

        if (ret == ACM_ACCESS_PERMITTED)
        {
            op->u.getdecision.acm_decision = ACM_ACCESS_PERMITTED;
            ret = 0;
        }
        else if  (ret == ACM_ACCESS_DENIED)
        {
            op->u.getdecision.acm_decision = ACM_ACCESS_DENIED;
            ret = 0;
        }
        else
            ret = -ESRCH;

        if (!ret)
            copy_to_user(u_acm_op, op, sizeof(*op));
    }
    break;

    default:
        ret = -ESRCH;
    }

    return ret;
}

#endif

/*
 * Local variables:
 * mode: C
 * c-set-style: "BSD"
 * c-basic-offset: 4
 * tab-width: 4
 * indent-tabs-mode: nil
 * End:
 */