Exemple #1
0
 def __init__(self, **kwargs):
     port = kwargs.pop("port")
     dport = kwargs.pop("dport")
     dserver = kwargs.pop("dserver")
     self.program = kwargs.pop("program", NFS4_PROGRAM)
     self.version = kwargs.pop("version", 4)
     self.cb_version = kwargs.pop("cb_version", 1)
     self.tag = "proxy tag"
     self.fchannel = self.Channel(34000, 34000, 1200, 8, 8)
     self.bchannel = self.Channel(4096, 4096, 0, 2, 1)
     rpc.Server.__init__(self,
                         prog=self.program,
                         versions=[self.version],
                         port=port)
     # we support only one server connection
     self.client = self.ProxyClient(self.program, self.version,
                                    self.cb_version, dserver, dport, None)
     self.client.proxy = self
     # load error description file
     errfile = kwargs.pop("errorfile", None)
     self.errorhandler = ErrorParser(errfile)
Exemple #2
0
 def __init__(self, **kwargs):
     port = kwargs.pop("port")
     dport = kwargs.pop("dport")
     dserver = kwargs.pop("dserver")
     self.program = kwargs.pop("program", NFS4_PROGRAM)
     self.version = kwargs.pop("version", 4)
     self.cb_version = kwargs.pop("cb_version", 1)
     self.tag = "proxy tag"
     self.fchannel = self.Channel(34000, 34000, 1200, 8, 8)
     self.bchannel = self.Channel(4096, 4096, 0, 2, 1)
     rpc.Server.__init__(self, prog=self.program, versions=[self.version],
                         port=port)
     # we support only one server connection
     self.client = self.ProxyClient(self.program, self.version,
                                    self.cb_version,
                                    dserver, dport,
                                    None)
     self.client.proxy = self
     # load error description file
     errfile = kwargs.pop("errorfile", None)
     self.errorhandler = ErrorParser(errfile)
Exemple #3
0
class NFS4Proxy(rpc.Server):
    """Implement an NFS(v4.x) proxy."""
    class Channel(object):
        def __init__(self, maxreqsz, maxrespsz, maxrespszc, maxops, maxreqs):
            self.maxrequestsize = maxreqsz
            self.maxresponsesize = maxrespsz
            self.maxresponsesize_cached = maxrespszc
            self.maxoperations = maxops
            self.maxrequests = maxreqs

    class ProxyClient(rpc.Client):
        def __init__(self, prog, version, cb_version, server, port, pipe):
            rpc.Client.__init__(self, prog, version)
            self.proxy = None
            self.prog = prog
            self.version = version
            self.dserver = server
            self.dport = port
            self.cb_prog = None
            self.cb_versions = [cb_version]
            # currently support only root (? fix ? )
            rpcsec = rpc.security.instance(rpc.AUTH_SYS)
            self.default_cred = rpcsec.init_cred(uid=0, gid=0, name="root")
            if pipe:  #reuse connection
                self.pipe = pipe
            else:
                self.pipe = self.connect_to_server()

        def _check_program(self, prog):
            if self.cb_prog is not None:
                return (prog == self.cb_prog)

        def _version_range(self, prog):
            return (min(self.cb_versions), max(self.cb_versions))

        def _find_method(self, msg):
            method = getattr(self.proxy, 'handle_cb_%i' % msg.proc, None)
            if method is not None:
                return method
            return None

        def connect_to_server(self, delay=5, retries=3):
            while True:
                try:
                    server_address = (self.dserver, self.dport)
                    print(server_address)
                    pipe = self.connect(server_address)
                except:
                    traceback.print_exc(file=sys.stdout)
                    log.critical("Cannot connect to destination server %r:%r" %
                                 (self.dserver, self.dport))
                    log.critical("Retrying in %s secs..." % delay)
                    time.sleep(delay)
                    delay = delay + delay
                    retries -= 1
                    if retries < 0:
                        raise Exception
                    continue
                else:
                    return pipe

        def make_call(self, proc, data, timeout=15.0):
            xid = self.pipe.send_call(self.prog, self.version, proc, data,
                                      self.default_cred)
            header, data = self.pipe.listen(xid, timeout)
            return data

    def __init__(self, **kwargs):
        port = kwargs.pop("port")
        dport = kwargs.pop("dport")
        dserver = kwargs.pop("dserver")
        self.program = kwargs.pop("program", NFS4_PROGRAM)
        self.version = kwargs.pop("version", 4)
        self.cb_version = kwargs.pop("cb_version", 1)
        self.tag = "proxy tag"
        self.fchannel = self.Channel(34000, 34000, 1200, 8, 8)
        self.bchannel = self.Channel(4096, 4096, 0, 2, 1)
        rpc.Server.__init__(self,
                            prog=self.program,
                            versions=[self.version],
                            port=port)
        # we support only one server connection
        self.client = self.ProxyClient(self.program, self.version,
                                       self.cb_version, dserver, dport, None)
        self.client.proxy = self
        # load error description file
        errfile = kwargs.pop("errorfile", None)
        self.errorhandler = ErrorParser(errfile)

    def start(self):
        """Cause the server to start listening on the previously bound port"""
        try:
            rpc.Server.start(self)
        except KeyboardInterrupt:
            import sys
            sys.exit()

    def start_cb_proxy(self, program, version, client_pipe):
        # FIXME: we support only one client at a time (at least with backchannel)
        self.client.cb_prog = program
        self.cb_client = self.ProxyClient(program, version, None, None, None,
                                          client_pipe)
        self.cb_client.proxy = self

    def forward_call(self,
                     calldata,
                     callback=False,
                     procedure=1,
                     timeout=15.0,
                     retries=3):
        def get_client(callback):
            if callback:
                return self.cb_client
            return self.client

        while True:
            try:
                client = get_client(callback)
                data = client.make_call(procedure, calldata)
                return data
            except rpc.RPCTimeout:
                log.critical('-' * 60)
                log.critical("RPC call forwarding failed")
                traceback.print_exc(file=sys.stdout)
                retries = retries - 1
                if retries > 0:
                    log.critical("Retrying...")
                    continue
                raise rpc.RPCTimeout

    def handle_cb_0(self, data, cred):
        return self.handle_0(data, cred, callback=True)

    def handle_cb_1(self, data, cred):
        return self.handle_1(data, cred, callback=True)

    def handle_0(self, data, cred, callback=False):
        """NULL procedure"""
        log.debug("*" * 20)
        if callback:
            log.debug("** CALLBACK **")
        log.debug("Handling NULL")
        try:
            self.forward_call(calldata="", callback=callback, procedure=0)
            return rpc.SUCCESS, ''
        except rpc.RPCTimeout:
            log.critical("Error: cannot connect to destination server")
            return rpc.GARBAGE_ARGS, None

    def handle_1(self, data, cred, callback=False):
        """COMPOUND procedure"""
        log.debug("*" * 40)
        if callback:
            log.debug("** CALLBACK **")
        log.debug("Handling COMPOUND")
        # stage 1: data in XDR as received from the client
        unpacker = nfs4lib.FancyNFS4Unpacker(data)
        if callback:
            args = unpacker.unpack_CB_COMPOUNDargs()
        else:
            args = unpacker.unpack_COMPOUND4args()
        log.debug("Client sent:")
        log.debug(repr(args))
        unpacker.done()
        # stage 2: pre-processing - data in COMPOUND4args
        # XXX: check operation, alter stuff, delay etc. etc.
        args.req_size = len(data)  # BUG, need to use cred.payload_size
        if callback:
            env = CBCompoundState(args, cred)
        else:
            env = CompoundState(args, cred)
        for arg in args.argarray:
            env.index += 1
            opname = nfs_opnum4.get(arg.argop, 'op_illegal')
            log.info("*** %s (%d) ***" % (opname, arg.argop))
            # look for functions implemented by the proxy
            # that override communication
            funct = getattr(self, opname.lower(), None)
            if funct is not None and callable(funct):
                try:
                    result = funct(arg, cred, direction=0)
                except Exception:
                    log.error("Function override %s failed" % opname.lower())
            # handle error condition if specified
            error = None
            if self.errorhandler is not None:
                error = self.errorhandler.get_error(opname.lower()[3:], arg,
                                                    env)
            if error is not None:
                result = encode_status_by_name(opname.lower()[3:],
                                               int(error),
                                               msg="Proxy Rewrite Error")
                env.results.append(result)
                p = nfs4lib.FancyNFS4Packer()
                if callback:
                    res = CB_COMPOUND4res(env.results.reply.status,
                                          env.results.reply.tag,
                                          env.results.reply.results)
                    p.pack_CB_COMPOUND4res(res)
                else:
                    res = COMPOUND4res(env.results.reply.status,
                                       env.results.reply.tag,
                                       env.results.reply.results)
                    p.pack_COMPOUND4res(res)
                log.info(repr(res))
                reply = p.get_buffer()
                return rpc.SUCCESS, reply
        #stage 3: repack the data and forward to server
        packer = nfs4lib.FancyNFS4Packer()
        if callback:
            packer.pack_CB_COMPOUND4args(args)
        else:
            packer.pack_COMPOUND4args(args)
        log.debug("Proxy sent:")
        log.debug(repr(args))
        calldata = packer.get_buffer()
        try:
            ret_data = self.forward_call(calldata, callback)
        except rpc.RPCTimeout:
            log.critical("Error: cannot connect to destination server")
            return rpc.GARBAGE_ARGS, None
        # stage 4: data in XDR as returned by the server
        unpacker = nfs4lib.FancyNFS4Unpacker(ret_data)
        if callback:
            res = unpacker.unpack_CB_COMPOUND4res()
        else:
            res = unpacker.unpack_COMPOUND4res()
        log.debug("Server returned:")
        log.debug(repr(res))
        unpacker.done()
        # stage 5: post-processing - data in COMPOUND4res
        # XXX: check operation etc.
        for arg in res.resarray:
            opname = nfs_opnum4.get(arg.resop, 'op_illegal')
            log.info("*** %s (%d) ***" % (opname, arg.resop))
            # look for functions implemented by the proxy
            # that override communication
            funct = getattr(self, opname.lower(), None)
            if funct is not None and callable(funct):
                try:
                    result = funct(arg, cred, direction=1)
                except Exception:
                    log.error("Function override %s failed" % opname.lower())
        # state 6: repack and return XDR data to client
        packer = nfs4lib.FancyNFS4Packer()
        if callback:
            packer.pack_CB_COMPOUND4res(res)
        else:
            packer.pack_COMPOUND4res(res)
        log.debug("Proxy returned:")
        log.debug(repr(res))
        reply = packer.get_buffer()
        return rpc.SUCCESS, reply

# FUNCTION OVERRIDING START
# just define a function called "op_<name>(self, arg, callback)"

    def op_create_session(self, arg, cred, direction=0):
        def _adjust_channel_values(attrs, chan):
            if chan.maxrequestsize < attrs.ca_maxrequestsize:
                attrs.ca_maxrequestsize = chan.maxrequestsize
            if chan.maxresponsesize < attrs.ca_maxresponsesize:
                attrs.ca_maxresponsesize = chan.maxresponsesize
            if chan.maxresponsesize_cached < attrs.ca_maxresponsesize_cached:
                attrs.ca_maxresposnesize_cached = chan.maxresponsesize_cached
            if chan.maxoperations < attrs.ca_maxoperations:
                attrs.ca_maxoperations = chan.maxoperations
            if chan.maxrequests < attrs.ca_maxrequests:
                attrs.ca_maxrequests = chan.maxrequests

        if direction is 0:  # client to proxy
            # XXX: this might be buggy with more than one clients (?)
            self.start_cb_proxy(arg.opcreate_session.csa_cb_program,
                                version=1,
                                client_pipe=cred.connection)
            _adjust_channel_values(arg.opcreate_session.csa_fore_chan_attrs,
                                   self.fchannel)
            _adjust_channel_values(arg.opcreate_session.csa_back_chan_attrs,
                                   self.bchannel)
        elif direction is 1:  # proxy to client
            pass
Exemple #4
0
class NFS4Proxy(rpc.Server):
    """Implement an NFS(v4.x) proxy."""
    class Channel(object):
        def __init__(self, maxreqsz, maxrespsz, maxrespszc, maxops, maxreqs):
            self.maxrequestsize = maxreqsz
            self.maxresponsesize = maxrespsz
            self.maxresponsesize_cached = maxrespszc
            self.maxoperations = maxops
            self.maxrequests = maxreqs

    class ProxyClient(rpc.Client):
        def __init__(self, prog, version, cb_version, server, port, pipe):
            rpc.Client.__init__(self, prog, version)
            self.proxy = None
            self.prog = prog
            self.version = version
            self.dserver = server
            self.dport = port
            self.cb_prog = None
            self.cb_versions = [cb_version]
            # currently support only root (? fix ? )
            rpcsec = rpc.security.instance(rpc.AUTH_SYS)
            self.default_cred = rpcsec.init_cred(uid=0,gid=0,name="root")
            if pipe: #reuse connection
                self.pipe = pipe
            else:
                self.pipe = self.connect_to_server()

        def _check_program(self, prog):
            if self.cb_prog is not None:
                return (prog == self.cb_prog)

        def _version_range(self, prog):
            return (min(self.cb_versions), max(self.cb_versions))

        def _find_method(self, msg):
            method = getattr(self.proxy, 'handle_cb_%i' % msg.proc, None)
            if method is not None:
                return method
            return None

        def connect_to_server(self, delay=5, retries=3):
            while True:
                try:
                    server_address = (self.dserver, self.dport)
                    print server_address
                    pipe = self.connect(server_address)
                except:
                    traceback.print_exc(file=sys.stdout)
                    log.critical("Cannot connect to destination server %r:%r"
                                 % (self.dserver, self.dport))
                    log.critical("Retrying in %s secs..." % delay)
                    time.sleep(delay)
                    delay = delay + delay
                    retries -= 1
                    if retries < 0:
                        raise Exception
                    continue
                else:
                    return pipe

        def make_call(self, proc, data, timeout=15.0):
                xid = self.pipe.send_call(self.prog, self.version,
                                          proc, data, self.default_cred)
                header, data = self.pipe.listen(xid, timeout)
                return data

    def __init__(self, **kwargs):
        port = kwargs.pop("port")
        dport = kwargs.pop("dport")
        dserver = kwargs.pop("dserver")
        self.program = kwargs.pop("program", NFS4_PROGRAM)
        self.version = kwargs.pop("version", 4)
        self.cb_version = kwargs.pop("cb_version", 1)
        self.tag = "proxy tag"
        self.fchannel = self.Channel(34000, 34000, 1200, 8, 8)
        self.bchannel = self.Channel(4096, 4096, 0, 2, 1)
        rpc.Server.__init__(self, prog=self.program, versions=[self.version],
                            port=port)
        # we support only one server connection
        self.client = self.ProxyClient(self.program, self.version,
                                       self.cb_version,
                                       dserver, dport,
                                       None)
        self.client.proxy = self
        # load error description file
        errfile = kwargs.pop("errorfile", None)
        self.errorhandler = ErrorParser(errfile)

    def start(self):
        """Cause the server to start listening on the previously bound port"""
        try:
            rpc.Server.start(self)
        except KeyboardInterrupt:
            import sys
            sys.exit()

    def start_cb_proxy(self, program, version, client_pipe):
        # FIXME: we support only one client at a time (at least with backchannel)
        self.client.cb_prog = program
        self.cb_client = self.ProxyClient(program, version, None, None,
                                          None, client_pipe)
        self.cb_client.proxy = self

    def forward_call(self, calldata, callback=False, procedure=1,
                     timeout=15.0, retries=3):
        def get_client(callback):
            if callback:
                return self.cb_client
            return self.client
        while True:
            try:
                client = get_client(callback)
                data = client.make_call(procedure, calldata)
                return data
            except rpc.RPCTimeout:
                log.critical('-'*60)
                log.critical("RPC call forwarding failed")
                traceback.print_exc(file=sys.stdout)
                retries = retries - 1
                if retries > 0:
                    log.critical("Retrying...")
                    continue
                raise rpc.RPCTimeout

    def handle_cb_0(self, data, cred):
        return self.handle_0(data, cred, callback=True)

    def handle_cb_1(self, data, cred):
        return self.handle_1(data, cred, callback=True)

    def handle_0(self, data, cred, callback=False):
        """NULL procedure"""
        log.debug("*" * 20)
        if callback:
            log.debug("** CALLBACK **")
        log.debug("Handling NULL")
        try:
            self.forward_call(calldata="", callback=callback, procedure=0)
            return rpc.SUCCESS, ''
        except rpc.RPCTimeout:
            log.critical("Error: cannot connect to destination server")
            return rpc.GARBAGE_ARGS, None

    def handle_1(self, data, cred, callback=False):
        """COMPOUND procedure"""
        log.debug("*" * 40)
        if callback:
            log.debug("** CALLBACK **")
        log.debug("Handling COMPOUND")
        # stage 1: data in XDR as received from the client
        unpacker = nfs4lib.FancyNFS4Unpacker(data)
        if callback:
            args = unpacker.unpack_CB_COMPOUNDargs()
        else:
            args = unpacker.unpack_COMPOUND4args()
        log.debug("Client sent:")
        log.debug(repr(args))
        unpacker.done()
        # stage 2: pre-processing - data in COMPOUND4args
        # XXX: check operation, alter stuff, delay etc. etc.
        args.req_size = len(data) # BUG, need to use cred.payload_size
        if callback:
            env = CBCompoundState(args, cred)
        else:
            env = CompoundState(args, cred)
        for arg in args.argarray:
            env.index += 1
            opname = nfs_opnum4.get(arg.argop, 'op_illegal')
            log.info("*** %s (%d) ***" % (opname, arg.argop))
            # look for functions implemented by the proxy
            # that override communication
            funct = getattr(self, opname.lower(), None)
            if funct is not None and callable(funct):
                try:
                    result = funct(arg, cred, direction=0)
                except Exception:
                    log.error("Function override %s failed" % opname.lower())
            # handle error condition if specified
            error = None
            if self.errorhandler is not None:
                error = self.errorhandler.get_error(opname.lower()[3:],
                                                    arg, env)
            if error is not None:
                result = encode_status_by_name(opname.lower()[3:],
                                            int(error),
                                            msg="Proxy Rewrite Error")
                env.results.append(result)
                p = nfs4lib.FancyNFS4Packer()
                if callback:
                    res = CB_COMPOUND4res(env.results.reply.status,
                                          env.results.reply.tag,
                                          env.results.reply.results)
                    p.pack_CB_COMPOUND4res(res)
                else:
                    res = COMPOUND4res(env.results.reply.status,
                                       env.results.reply.tag,
                                       env.results.reply.results)
                    p.pack_COMPOUND4res(res)
                log.info(repr(res))
                reply = p.get_buffer()
                return rpc.SUCCESS, reply
        #stage 3: repack the data and forward to server
        packer = nfs4lib.FancyNFS4Packer()
        if callback:
            packer.pack_CB_COMPOUND4args(args)
        else:
            packer.pack_COMPOUND4args(args)
        log.debug("Proxy sent:")
        log.debug(repr(args))
        calldata = packer.get_buffer()
        try:    
            ret_data = self.forward_call(calldata, callback)
        except rpc.RPCTimeout:
            log.critical("Error: cannot connect to destination server")
            return rpc.GARBAGE_ARGS, None
        # stage 4: data in XDR as returned by the server
        unpacker = nfs4lib.FancyNFS4Unpacker(ret_data)
        if callback:
            res = unpacker.unpack_CB_COMPOUND4res()
        else:
            res = unpacker.unpack_COMPOUND4res()
        log.debug("Server returned:")
        log.debug(repr(res))
        unpacker.done()
        # stage 5: post-processing - data in COMPOUND4res
        # XXX: check operation etc.
        for arg in res.resarray:
            opname = nfs_opnum4.get(arg.resop, 'op_illegal')
            log.info("*** %s (%d) ***" % (opname, arg.resop))
            # look for functions implemented by the proxy
            # that override communication
            funct = getattr(self, opname.lower(), None)
            if funct is not None and callable(funct):
                try:
                    result = funct(arg, cred, direction=1)
                except Exception:
                    log.error("Function override %s failed" % opname.lower())
        # state 6: repack and return XDR data to client
        packer = nfs4lib.FancyNFS4Packer()
        if callback:
            packer.pack_CB_COMPOUND4res(res)
        else:
            packer.pack_COMPOUND4res(res)
        log.debug("Proxy returned:")
        log.debug(repr(res))
        reply = packer.get_buffer()
        return rpc.SUCCESS, reply

# FUNCTION OVERRIDING START
# just define a function called "op_<name>(self, arg, callback)"

    def op_create_session(self, arg, cred, direction=0):
            def _adjust_channel_values(attrs, chan):
                if chan.maxrequestsize < attrs.ca_maxrequestsize:
                    attrs.ca_maxrequestsize = chan.maxrequestsize
                if chan.maxresponsesize < attrs.ca_maxresponsesize:
                    attrs.ca_maxresponsesize = chan.maxresponsesize
                if chan.maxresponsesize_cached < attrs.ca_maxresponsesize_cached:
                    attrs.ca_maxresposnesize_cached = chan.maxresponsesize_cached
                if chan.maxoperations < attrs.ca_maxoperations:
                    attrs.ca_maxoperations = chan.maxoperations
                if chan.maxrequests < attrs.ca_maxrequests:
                    attrs.ca_maxrequests = chan.maxrequests
            if direction is 0: # client to proxy
                # XXX: this might be buggy with more than one clients (?)
                self.start_cb_proxy(arg.opcreate_session.csa_cb_program,
                                    version=1, client_pipe=cred.connection)
                _adjust_channel_values(arg.opcreate_session.csa_fore_chan_attrs,
                                       self.fchannel)
                _adjust_channel_values(arg.opcreate_session.csa_back_chan_attrs,
                                       self.bchannel)
            elif direction is 1: # proxy to client
                pass