mirror of
https://github.com/Grasscutters/mitmproxy.git
synced 2024-11-26 10:16:27 +00:00
Introduced the capability to spoof the source address
of outgoing sessions + an accompanying shim loader.
This commit is contained in:
parent
b476966a45
commit
a6e0c7e8f0
@ -255,6 +255,7 @@ def get_common_options(args):
|
||||
listen_port = args.port,
|
||||
mode = mode,
|
||||
no_upstream_cert = args.no_upstream_cert,
|
||||
spoof_source_address = args.spoof_source_address,
|
||||
rawtcp = args.rawtcp,
|
||||
upstream_server = upstream_server,
|
||||
upstream_auth = args.upstream_auth,
|
||||
@ -474,7 +475,11 @@ def proxy_options(parser):
|
||||
"Disabled by default. "
|
||||
"Default value will change in a future version."
|
||||
)
|
||||
|
||||
group.add_argument(
|
||||
"--spoof-source-address",
|
||||
action="store_true", dest="spoof_source_address",
|
||||
help="Use client's IP for the server-side connection"
|
||||
)
|
||||
|
||||
def proxy_ssl_options(parser):
|
||||
# TODO: Agree to consistently either use "upstream" or "server".
|
||||
|
71
mitmproxy/contrib/mitmproxy_shim.c
Normal file
71
mitmproxy/contrib/mitmproxy_shim.c
Normal file
@ -0,0 +1,71 @@
|
||||
#define _GNU_SOURCE
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <sys/prctl.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/capability.h>
|
||||
#include <unistd.h>
|
||||
#include <errno.h>
|
||||
|
||||
int set_caps(cap_t cap_struct, cap_value_t *caps, int len) {
|
||||
if (cap_set_flag(cap_struct, CAP_PERMITTED, len, caps, CAP_SET) ||
|
||||
cap_set_flag(cap_struct, CAP_EFFECTIVE, len, caps, CAP_SET) ||
|
||||
cap_set_flag(cap_struct, CAP_INHERITABLE, len, caps, CAP_SET)) {
|
||||
if (len < 2) {
|
||||
fprintf(stderr, "Cannot manipulate capability data structure as user: %s.\n", strerror(errno));
|
||||
} else {
|
||||
fprintf(stderr, "Cannot manipulate capability data structure as root: %s.\n", strerror(errno));
|
||||
}
|
||||
|
||||
return 7;
|
||||
}
|
||||
|
||||
if (len < 2) {
|
||||
if (prctl(PR_CAP_AMBIENT, PR_CAP_AMBIENT_RAISE, CAP_NET_RAW, 0, 0)) {
|
||||
fprintf(stderr, "Failed to add CAP_NET_RAW to the ambient set: %s.\n", strerror(errno));
|
||||
return 88;
|
||||
}
|
||||
}
|
||||
|
||||
if (cap_set_proc(cap_struct)) {
|
||||
if (len < 2) {
|
||||
fprintf(stderr, "Cannot set capabilities as user: %s.\n", strerror(errno));
|
||||
} else {
|
||||
fprintf(stderr, "Cannot set capabilities as root: %s.\n", strerror(errno));
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (len > 1) {
|
||||
if (prctl(PR_SET_KEEPCAPS, 1L)) {
|
||||
fprintf(stderr, "Cannot keep capabilities after dropping privileges: %s.\n", strerror(errno));
|
||||
return 4;
|
||||
}
|
||||
if (cap_clear(cap_struct)) {
|
||||
fprintf(stderr, "Cannot clear capability data structure: %s.\n", strerror(errno));
|
||||
return 6;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int main(int argc, char **argv, char **envp) {
|
||||
cap_t cap_struct = cap_init();
|
||||
cap_value_t root_caps[2] = { CAP_NET_RAW, CAP_SETUID };
|
||||
cap_value_t user_caps[1] = { CAP_NET_RAW };
|
||||
uid_t user = getuid();
|
||||
|
||||
if (setresuid(0, 0, 0)) {
|
||||
fprintf(stderr, "Cannot switch to root: %s.\n", strerror(errno));
|
||||
return 1;
|
||||
}
|
||||
|
||||
set_caps(cap_struct, root_caps, 2);
|
||||
if (setresuid(user, user, user)) {
|
||||
fprintf(stderr, "Cannot drop root privileges: %s.\n", strerror(errno));
|
||||
return 5;
|
||||
}
|
||||
set_caps(cap_struct, user_caps, 1);
|
||||
|
||||
if (execve(argv[1], argv + 1, envp))
|
||||
perror("Cannot exec");
|
||||
}
|
@ -123,8 +123,8 @@ class ServerConnection(tcp.TCPClient, stateobject.StateObject):
|
||||
timestamp_end: Connection end timestamp
|
||||
"""
|
||||
|
||||
def __init__(self, address, source_address=None):
|
||||
tcp.TCPClient.__init__(self, address, source_address)
|
||||
def __init__(self, address, source_address=None, spoof_source_address=None):
|
||||
tcp.TCPClient.__init__(self, address, source_address, spoof_source_address)
|
||||
|
||||
self.via = None
|
||||
self.timestamp_start = None
|
||||
|
@ -69,6 +69,7 @@ class Options(optmanager.OptManager):
|
||||
mode = "regular", # type: str
|
||||
no_upstream_cert = False, # type: bool
|
||||
rawtcp = False, # type: bool
|
||||
spoof_source_address = False, # type: bool
|
||||
upstream_server = "", # type: str
|
||||
upstream_auth = "", # type: str
|
||||
ssl_version_client="secure", # type: str
|
||||
@ -126,6 +127,7 @@ class Options(optmanager.OptManager):
|
||||
self.mode = mode
|
||||
self.no_upstream_cert = no_upstream_cert
|
||||
self.rawtcp = rawtcp
|
||||
self.spoof_source_address = spoof_source_address
|
||||
self.upstream_server = upstream_server
|
||||
self.upstream_auth = upstream_auth
|
||||
self.ssl_version_client = ssl_version_client
|
||||
|
@ -114,7 +114,13 @@ class ServerConnectionMixin(object):
|
||||
|
||||
def __init__(self, server_address=None):
|
||||
super(ServerConnectionMixin, self).__init__()
|
||||
self.server_conn = models.ServerConnection(server_address, (self.config.options.listen_host, 0))
|
||||
|
||||
self.server_conn = None
|
||||
if self.config.options.spoof_source_address:
|
||||
self.server_conn = models.ServerConnection(server_address, (self.ctx.client_conn.address.host, 0), True)
|
||||
else:
|
||||
self.server_conn = models.ServerConnection(server_address, (self.config.options.listen_host, 0))
|
||||
|
||||
self.__check_self_connect()
|
||||
|
||||
def __check_self_connect(self):
|
||||
@ -151,11 +157,15 @@ class ServerConnectionMixin(object):
|
||||
"""
|
||||
self.log("serverdisconnect", "debug", [repr(self.server_conn.address)])
|
||||
address = self.server_conn.address
|
||||
source_address = self.server_conn.source_address
|
||||
self.server_conn.finish()
|
||||
self.server_conn.close()
|
||||
self.channel.tell("serverdisconnect", self.server_conn)
|
||||
self.server_conn = models.ServerConnection(address, (source_address.host, 0))
|
||||
|
||||
if self.config.options.spoof_source_address:
|
||||
self.server_conn = models.ServerConnection(address, (self.ctx.client_conn.address.host, 0), True)
|
||||
else:
|
||||
self.server_conn = models.ServerConnection(address, (self.server_conn.source_address.host, 0))
|
||||
|
||||
|
||||
def connect(self):
|
||||
"""
|
||||
|
@ -605,7 +605,7 @@ class ConnectionCloser(object):
|
||||
|
||||
class TCPClient(_Connection):
|
||||
|
||||
def __init__(self, address, source_address=None):
|
||||
def __init__(self, address, source_address=None, spoof_source_address=None):
|
||||
super(TCPClient, self).__init__(None)
|
||||
self.address = address
|
||||
self.source_address = source_address
|
||||
@ -613,6 +613,7 @@ class TCPClient(_Connection):
|
||||
self.server_certs = []
|
||||
self.ssl_verification_error = None # type: Optional[exceptions.InvalidCertificateException]
|
||||
self.sni = None
|
||||
self.spoof_source_address = spoof_source_address
|
||||
|
||||
@property
|
||||
def address(self):
|
||||
@ -729,6 +730,11 @@ class TCPClient(_Connection):
|
||||
def connect(self):
|
||||
try:
|
||||
connection = socket.socket(self.address.family, socket.SOCK_STREAM)
|
||||
if self.spoof_source_address:
|
||||
if os.geteuid() != 0:
|
||||
raise RuntimeError("Insufficient privileges to set socket option")
|
||||
else:
|
||||
connection.setsockopt(socket.SOL_IP, 19, 1)
|
||||
if self.source_address:
|
||||
connection.bind(self.source_address())
|
||||
connection.connect(self.address())
|
||||
|
Loading…
Reference in New Issue
Block a user