MITM tool for NFS traffic on linux
Subsystems (2)
PATCH 1/3 Fix default arg order error on swig > 1.x
In reply to Benjamin CoddingtonThe gssapi.py module ends up with
def initSecContext(name, context=None, INPUT=0, cred=0, mech, flags=2, time=0, chan=0):
which creates the error "SyntaxError: non-default argument follows default argument" on import. Revert to earlier swig behavior of using compact default args.
--- gssapi/gssapi.i | 2 ++ 1 files changed, 2 insertions(+), 0 deletions(-)
gssapi/gssapi.i +2 -0
@@ -487,6 +487,7 @@ OM_uint32 reordered_init_sec_context %apply gss_buffer_t OUTPUT {gss_buffer_t token}; %apply OM_uint32 *OUTPUT {OM_uint32 *flags, OM_uint32 *time}; %feature("autodoc", "initSecContext(gss_name_t name, gss_ctx_id_t *context=None, string token=None, gss_cred_id_t cred=None, gss_OID mech=krb5oid, int flags=0, int time=0, gss_channel_bindings_t chan=None) -> context, mech, token, flags, time"); +%feature("compactdefaultargs"); OM_uint32 reordered_init_sec_context (OM_uint32 *minor, /* minor_status */ gss_name_t name, /* target_name IN*/
@@ -507,6 +508,7 @@ OM_uint32 reordered_init_sec_context %clear gss_OID *mech; %clear gss_buffer_t token; %clear OM_uint32 *flags, OM_uint32 *time; +%feature("compactdefaultargs", 0); /********/
Signature · 1 line
1.7.1
PATCH 2/3 Add a tool for modification of NFS network traffic: itm
In reply to Benjamin CoddingtonProvide a framework to allow the inspection and modification of NFS network traffic between an existing server and client, provided one of them is able to use netfilter's libnfqueue. This essentially linux-only tool is similar to nfs-proxy in that it can be used to inject protocol errors and other behaviors, however it is more convenient to use on linux as it can quickly be inserted or removed from existing server-client pairs.
--- itm/README | 26 +++++ itm/handlers.py | 9 ++ itm/handlers/default.py | 19 ++++ itm/handlers/example.py | 14 +++ itm/itm.py | 230 ++++++++++++++++++++++++++++++++++++++++++++++ itm/run_itm.sh | 41 ++++++++ itm/use_local.py | 14 +++ 7 files changed, 353 insertions(+), 0 deletions(-) create mode 100644 itm/README create mode 100644 itm/__init__.py create mode 100644 itm/handlers.py create mode 100644 itm/handlers/__init__.py create mode 100644 itm/handlers/default.py create mode 100644 itm/handlers/example.py create mode 100755 itm/itm.py create mode 100755 itm/run_itm.sh create mode 100644 itm/use_local.py
itm/README new file +26 -0
@@ -0,0 +1,26 @@ +PyNFS ITM - In-the-Middle + +This tool uses bits of the main pynfs encoding/decoding functionality to +allow the inspection and modification of NFS network traffic between clients +and servers. More than a few bugs have been difficult to reproduce from +above the filesystem, and some bugs require access to specialized servers +that behave in strange ways. This tool may allow a shorter path to problem +reproduction when the on-wire behavior is known be reproduced by enabling +the quick injection and then removal of behaviors written into handlers. + +This tool relies on libnetfilter_queue to forward packets from a Linux +client or server's netfilter to userspace to accept or modify the payload. + +Requirements: + nfqueue-bindings + https://www.wzdftpd.net/redmine/projects/nfqueue-bindings/wiki + python-dpkt + +Usage: +First, edit itm/run_itm.sh to configure either the client or server's +hostname. If running on a client, set the server's name; if on a server, +set the client's hostname. + +./itm/run_itm.sh [name of handler] + +Handlers can be found/created in itm/handlers/
itm/__init__.py new file +0 -0
itm/handlers.py new file +9 -0
@@ -0,0 +1,9 @@ +class BaseHandler(object): + def __init__(self): + pass + + def will_handle(self, cb_info): + return 0; + + def handle(self, cb_info): + return 0;
itm/handlers/__init__.py new file +0 -0
itm/handlers/default.py new file +19 -0
@@ -0,0 +1,19 @@ +import itm +from itm.handlers import BaseHandler + +class Handler(BaseHandler): + ''' this default handler only prints out information about + rpc message ''' + def __init__(self): + print "init default itm.handler" + + def will_handle(self, cb_info): + # turn me on! + return 0 + + def handle(self, cb_info): + cb_info.dump_IP() + #cb_info.dump_RPC() + #cb_info.dump_NFS() + #cb_info.dump_data() + return 0
itm/handlers/example.py new file +14 -0
@@ -0,0 +1,14 @@ +from itm.handlers import BaseHandler + +class Handler(BaseHandler): + def will_handle(self, cb_info): + # implement stateful setup or conditions here + # return 1 if you want to handle this record + return 0 + + def handle(self, cb_info): + # modify the payload here + # return 1 to submit the modified payload + return 0 + +
itm/itm.py new file +230 -0
230 lines not on this page · raw message
itm/run_itm.sh new file +41 -0
41 lines not on this page · raw message
itm/use_local.py new file +14 -0
@@ -0,0 +1,14 @@ +import sys +import os +from os.path import join, split +cwd = os.path.dirname(os.path.realpath(__file__)) +if True or cwd not in sys.path: + head, tail = split(cwd) + dirs = [ join(head, "gssapi"), + join(head, "xdr"), + join(head, "ply"), + join(head, "rpc"), + join(head, "nfs4.1"), + cwd, + ] + sys.path[1:1] = dirs
Signature · 1 line
1.7.1
cover MITM tool for NFS traffic on linux
What follows is a small tool I think may be convenient to test and reproduce certain types of bugs that are difficult to create from above the filesystem, but are clearly problematic and have well-defined network triggers. Anna's recent BAD_STATEID on WRITES with delegation is a good example of that. This tool uses netfilters NFQUEUE target to allow a linux host to modify the NFS network traffic between existing clients and servers. In that sense, it is very similar to nfs-proxy, however I find it to be much more convenient to use, as it can be quickly inserted and removed from an existing network conection.
Benjamin Coddington (3):
Fix default arg order error on swig > 1.x
Add a tool for modification of NFS network traffic: itm
itm: add a handler that truncates READDIR response page data
gssapi/gssapi.i | 2 + itm/README | 26 ++++ itm/handlers.py | 9 ++ itm/handlers/default.py | 19 +++ itm/handlers/example.py | 14 ++ itm/handlers/readdir_reply_nopages.py | 86 ++++++++++++ itm/itm.py | 230 +++++++++++++++++++++++++++++++++ itm/run_itm.sh | 41 ++++++ itm/use_local.py | 14 ++ 9 files changed, 441 insertions(+), 0 deletions(-) create mode 100644 itm/README create mode 100644 itm/__init__.py create mode 100644 itm/handlers.py create mode 100644 itm/handlers/__init__.py create mode 100644 itm/handlers/default.py create mode 100644 itm/handlers/example.py create mode 100644 itm/handlers/readdir_reply_nopages.py create mode 100755 itm/itm.py create mode 100755 itm/run_itm.sh create mode 100644 itm/use_local.py
PATCH 3/3 itm: add a handler that truncates READDIR response page data
--- itm/handlers/readdir_reply_nopages.py | 86 +++++++++++++++++++++++++++++++++ 1 files changed, 86 insertions(+), 0 deletions(-) create mode 100644 itm/handlers/readdir_reply_nopages.py
itm/handlers/readdir_reply_nopages.py new file +86 -0
@@ -0,0 +1,86 @@ +from rpc_const import * +from xdrdef.nfs4_const import * +from xdrdef.nfs4_type import * +from xdrdef.nfs3_const import * +from xdrdef.nfs3_type import * +from xdrdef.nfs3_pack import NFS3Packer, NFS3Unpacker +from nfs4commoncode import encode_status_by_name +from itm.handlers import BaseHandler + +import itm +import nfs4lib + +""" + This handler modifies the response body for a v4 READDIR call + or v3 READDIRPLUS call such that there are no pages of data in + the response. + + https://bugzilla.redhat.com/show_bug.cgi?id=1182830 + http://marc.info/?l=linux-nfs&m=142964061807798&w=2 + ce85cfb NFS: Don't attempt to decode missing directory entries +""" + +class Handler(BaseHandler): + + def will_handle(self, cb_info): + + # setup for v4: + if hasattr(cb_info, "v4_res"): + res = cb_info.v4_res; + my_ops = filter(lambda x: x.resop == OP_READDIR, res.resarray) + if not my_ops: + return 0; + + # save the resop for handle() + self.my_resop = my_ops[0] + return 1; + + # setup for v3: + msg = cb_info.rpc_msg + if msg.body.mtype == REPLY and \ + msg.body.cbody.vers == 3 and \ + msg.body.cbody.proc == NFSPROC3_READDIRPLUS: + + unpacker = NFS3Unpacker(cb_info.rpc_msg_data) + self.my_resop = unpacker.unpack_READDIRPLUS3res() + + return 1; + + return 0; + + def handle(self, cb_info): + print "readdir is returning no pages" + + msg = cb_info.rpc_msg + + if msg.body.cbody.vers == 4: + # remove whatever results were being returned so that we have a + # predictable length: + self.my_resop.opreaddir.resok4.reply = dirlist4([], eof=0) + + p = nfs4lib.FancyNFS4Packer() + p.pack_COMPOUND4res(cb_info.v4_res) + buf = p.get_buffer() + + # chop off the page data: + cb_info.rpc_msg_data = buf[:-8] + #itm.dump_data(cb_info.rpc_msg_data) + cb_info.encode_RPC() + return 1 + + elif msg.body.cbody.vers == 3: + # remove whatever results were being returned so that we have a + # predictable length: + self.my_resop.resok.reply = dirlistplus3([], eof=0) + + p = NFS3Packer() + p.pack_READDIRPLUS3res(self.my_resop) + buf = p.get_buffer() + + # chop off the page data: + cb_info.rpc_msg_data = buf[:-8] + #itm.dump_data(cb_info.rpc_msg_data) + cb_info.encode_RPC() + return 1 + + return 0
Signature · 1 line
1.7.1
Quoted 4 lines · Benjamin Coddington
What follows is a small tool I think may be convenient to test and reproduce certain types of bugs that are difficult to create from above the filesystem, but are clearly problematic and have well-defined network triggers. Anna's recent
BAD_STATEIDon WRITES with delegation is a good
*Olga
Apologies.
Ben
Quoted 37 lines
example of that. This tool uses netfilters NFQUEUE target to allow a linux host to modify the NFS network traffic between existing clients and servers. In that sense, it is very similar to nfs-proxy, however I find it to be much more convenient to use, as it can be quickly inserted and removed from an existing network conection.
Benjamin Coddington (3):
Fix default arg order error on swig > 1.x
Add a tool for modification of NFS network traffic: itm
itm: add a handler that truncates READDIR response page datagssapi/gssapi.i | 2 + itm/README | 26 ++++ itm/handlers.py | 9 ++ itm/handlers/default.py | 19 +++ itm/handlers/example.py | 14 ++ itm/handlers/readdir_reply_nopages.py | 86 ++++++++++++ itm/itm.py | 230 +++++++++++++++++++++++++++++++++ itm/run_itm.sh | 41 ++++++ itm/use_local.py | 14 ++ 9 files changed, 441 insertions(+), 0 deletions(-) create mode 100644 itm/README create mode 100644 itm/__init__.py create mode 100644 itm/handlers.py create mode 100644 itm/handlers/__init__.py create mode 100644 itm/handlers/default.py create mode 100644 itm/handlers/example.py create mode 100644 itm/handlers/readdir_reply_nopages.py create mode 100755 itm/itm.py create mode 100755 itm/run_itm.sh create mode 100644 itm/use_local.py--
To unsubscribe from this list: send the line "unsubscribe linux-nfs" in the body of a message to [email protected]
More majordomo info at http://vger.kernel.org/majordomo-info.html
Quoted 7 lines · Benjamin Coddington
Quoted 4 lines · Benjamin Coddington
What follows is a small tool I think may be convenient to test and reproduce certain types of bugs that are difficult to create from above the filesystem, but are clearly problematic and have well-defined network triggers. Anna's recent
BAD_STATEIDon WRITES with delegation is a good
Quoted 11 lines
*Olga
Apologies.
Ben
Quoted 5 lines
example of that. This tool uses netfilters NFQUEUE target to allow a linux host to modify the NFS network traffic between existing clients and servers. In that sense, it is very similar to nfs-proxy, however I find it to be much more convenient to use, as it can be quickly inserted and removed from an existing network conection.
By the way, I only recently noticed there's a branch of Fred's old pynfs repo with the proxy-nfs code. I've just merged that branch into my tree. (Let me know if anyone uses that.)
Do you want me to take these patches to? Do you think you're going to continue using this?
--b.
Quoted 20 lines · J. Bruce Fields
Quoted 7 lines · Benjamin Coddington
Quoted 4 lines · Benjamin Coddington
What follows is a small tool I think may be convenient to test and reproduce certain types of bugs that are difficult to create from above the filesystem, but are clearly problematic and have well-defined network triggers. Anna's recent
BAD_STATEIDon WRITES with delegation is a goodQuoted 11 lines
*Olga
Apologies.
Ben
Quoted 5 lines
example of that. This tool uses netfilters NFQUEUE target to allow a linux host to modify the NFS network traffic between existing clients and servers. In that sense, it is very similar to nfs-proxy, however I find it to be much more convenient to use, as it can be quickly inserted and removed from an existing network conection.
Quoted 6 lines
By the way, I only recently noticed there's a branch of Fred's old pynfs repo with the proxy-nfs code. I've just merged that branch into my tree. (Let me know if anyone uses that.)
Do you want me to take these patches to? Do you think you're going to continue using this?
I'm actually not sure yet if this is more or less useful than the
nfs-proxy.. In using it the past week, I found it to be convenient for
quickly inserting and removing behaviors, and then modifiying those behaviors and quickly inserting/removing them again. I think doing that with the nfs-proxy would be more disruptive to the client, potentially.
It does suffer from a scrambling of TCP sequencing if payload sizes are modified - the nfs-proxy doesn't have this problem. That causes the transport to want to reconnect.. so when using it you have to keep TCP in mind.
I think I'll continue to use what I have and do a bit of refinement and post back again in a bit.
Ben
Quoted 35 lines · Benjamin Coddington
Quoted 20 lines · J. Bruce Fields
Quoted 7 lines · Benjamin Coddington
Quoted 4 lines · Benjamin Coddington
What follows is a small tool I think may be convenient to test and reproduce certain types of bugs that are difficult to create from above the filesystem, but are clearly problematic and have well-defined network triggers. Anna's recent
BAD_STATEIDon WRITES with delegation is a goodQuoted 11 lines
*Olga
Apologies.
Ben
Quoted 5 lines
example of that. This tool uses netfilters NFQUEUE target to allow a linux host to modify the NFS network traffic between existing clients and servers. In that sense, it is very similar to nfs-proxy, however I find it to be much more convenient to use, as it can be quickly inserted and removed from an existing network conection.
Quoted 6 lines
By the way, I only recently noticed there's a branch of Fred's old pynfs repo with the proxy-nfs code. I've just merged that branch into my tree. (Let me know if anyone uses that.)
Do you want me to take these patches to? Do you think you're going to continue using this?
I'm actually not sure yet if this is more or less useful than the
nfs-proxy.. In using it the past week, I found it to be convenient for
quickly inserting and removing behaviors, and then modifiying those behaviors and quickly inserting/removing them again. I think doing that with the nfs-proxy would be more disruptive to the client, potentially.
Quoted 4 lines
It does suffer from a scrambling of TCP sequencing if payload sizes are modified - the nfs-proxy doesn't have this problem. That causes the transport to want to reconnect.. so when using it you have to keep TCP in mind.
Sounds a little scary.
Quoted 2 lines
I think I'll continue to use what I have and do a bit of refinement and post back again in a bit.
OK.
--b.
Re: [PATCH pynfs 1/3] Fix default arg order error on swig > 1.x
In reply to Benjamin CoddingtonQuoted 8 lines · Benjamin Coddington
The
gssapi.pymodule ends up with
definitSecContext(name, context=None, INPUT=0, cred=0, mech, flags=2, time=0, chan=0):which creates the error "SyntaxError: non-default argument follows default argument" on import. Revert to earlier swig behavior of using compact default args.
Signed-off-by Benjamin Coddington <[email protected]>
Anyway this one is useful.
thanks,
Kinglong Mee
Quoted 25 lines
--- gssapi/gssapi.i | 2 ++ 1 files changed, 2 insertions(+), 0 deletions(-)gssapi/gssapi.i +2
-0@@ -487,6 +487,7 @@ OM_uint32 reordered_init_sec_context %apply gss_buffer_t OUTPUT {gss_buffer_t token}; %apply OM_uint32 *OUTPUT {OM_uint32 *flags, OM_uint32 *time}; %feature("autodoc", "initSecContext(gss_name_t name, gss_ctx_id_t *context=None, string token=None, gss_cred_id_t cred=None, gss_OID mech=krb5oid, int flags=0, int time=0, gss_channel_bindings_t chan=None) -> context, mech, token, flags, time"); +%feature("compactdefaultargs"); OM_uint32 reordered_init_sec_context (OM_uint32 *minor, /* minor_status */ gss_name_t name, /* target_name IN*/@@ -507,6 +508,7 @@ OM_uint32 reordered_init_sec_context %clear gss_OID *mech; %clear gss_buffer_t token; %clear OM_uint32 *flags, OM_uint32 *time; +%feature("compactdefaultargs", 0); /********/