GridProxy

From libopenmetaverse - libomv - Developer Wiki

Jump to: navigation, search

Contents

Introduction

GridProxy is a library that works in conjunction with libopenmetaverse to allow applications to wedge themselves between the official Second Life client and servers. GridProxy applications can inspect and modify any packet as it passes between the client and the servers; remove packets from the stream; and inject new packets into the stream. GridProxy automatically takes care of tracking circuits and modifying sequence numbers and acknowledgements to account for changes to the packet stream.

The continued existence of this software of course rests on the good will of Linden Lab toward the Second Life reverse engineering effort. Please use common sense when designing applications and report any security holes you may find to security@lindenlab.com.

To use an GridProxy application, you must first start the proxy, then start Second Life with the switch `-loginuri http://localhost:8080/'. In Windows, add this switch (without the quotes) to your Second Life shortcut. In MacOS X, this can be accomplished by sending the following commands to the Terminal (assuming Second Life is installed in /Applications):

       cd "/Applications/Second Life.app"
       "Contents/MacOS/Second Life" -loginuri http://localhost:8080/

Note that for security reasons, by default, GridProxy applications must be running on the same computer as Second Life. If you need to run a proxy on a different machine or port, start the proxy with the --proxy-help switch and see the options available.

GridProxy can only handle one client using a proxy at a time.

Getting Started

For information on getting started with libopenmetaverse and how to get the source, see the Getting Started article

To build GridProxy, you must check out the entire libopenmetaverse trunk with subversion:

 svn co svn://openmetaverse.org/omf/libopenmetaverse/trunk libopenmetaverse

The libopenmetaverse project must be built first; see the libopenmetaverse README for instructions. Building GridProxy should be straightforward with Microsoft Visual Studio. If you're using Mono, you can build the solution with the included build script:

 perl build

The GridProxy library and its example applications will be built in bin/Debug. In order to run the example applications, you must first add the libopenmetaverse build directory to your MONO_PATH environment variable. For example, if your libopenmetaverse directory is ~/libopenmetaverse and your shell is bash, you can type:

 export MONO_PATH=$MONO_PATH:~/libopenmetaverse/bin/

INCLUDED APPLICATIONS

Included with GridProxy are a few example application, which are covered in this section.

Plugin loader (Proxy.exe)

This loads plugins such as Analyst. Pass it the plugins you want to load on the command line (--load=Analyst.dll, where Analyst.dll should be replaced with the plugin in question) or use the command "/load <plugin>" in in-world chat.

Being loosely based on the old Analyst code, it also accepts a --log-login command line switch, which causes the XML-RPC login request and response to dumped to the console.

ChatConsole

ChatConsole is a trivial GridProxy application intended as an example of how GridProxy applications can be written. When connected to Second Life through ChatConsole, all in-world chat will be echoed to the console, and anything typed in the console will be echoed to the game as in-world chat.

INCLUDED PLUGINS

Analyst

(Analyst can be launched using the command "Proxy.exe --load=Analyst.dll")

Analyst makes GridProxy's packet inspection and modification functionality interactive. When connected to Second Life through Analyst, you use the following commands by saying them using in-world chat:

/log <packet name>
   Packets of type <packet name> will be dumped to the console.  For
   example, say `/log ChatFromSimulator' to get a packet dump of all
   incoming chat.
/-log <packet name>
   Packets of type <packet name> will no longer be dumped to the
   console.
/log *
   All packets will be dumped to the console.
/-log *
   No packets will be dumped to the console.
/grep [regex]
   Only log packets that have a field for which regex matches
   <packet name>.<block name>.<field name> = <value>.  To stop
   filtering, type /grep without an argument.  Matches are case
   insensitive.  In the case of a variable field, Analyst will try to
   convert it into a string; if that doesn't match, it will try
   converting it into a hexidecimal numeral preceeded by 0x.
   (currently not available - victim of the switch to pregen - but it may be possible to re-add it in some form if anyone wants it.)
/set <packet name> <block name> <field name> <value>
   All forthcoming packets of type <packet name> will have the field
   identified by <block name> and <field name> set to <value>.  For
   example, if you say `/set ChatFromViewer ChatData Type 0',
   everything you say thereafter will be whispered.  Values for
   variable fields will be interpreted as strings unless they begin
   with a 0x, in which case they will be treated as hexidecimal
   numerals representing the contents of the field.
/-set <packet name> <block name> <field name>
   Packets of type <packet name> will no longer have the field
   identified by <block name> and <field name> modified.
/-set *
   No fields will be modified.
/inject <packet file> [value]
   Inject the packet described by <packet file>.packet in the working
   directory.  The [value] is optional and may be required by some
   packet files.  `/in' is an alias for `/inject'.  The syntax of a
   packet file is described in section 2.1.  GridProxy comes with two
   example packet files: god.packet allows you to enable hacked god
   mode by typing `/inject god', and whisper.packet allows you to
   whisper by typing `/inject whisper <message>'.

These commands will not be forwarded to the server, so other people won't hear you say them.

Analyst accepts a --log-all command line switch, which causes the proxy to start out logging all packets as if you had typed `/log *'. This can be useful if you want to capture a complete dump of your session, including login.

Packet files

A packet file describes a packet that can be injected with the /inject command. Please refer to god.packet and whisper.packet (in the bin/Debug/ directory) as examples.

The first line of a packet file must contain the word `in' or `out', specifying whether the packet is incoming or outgoing, respectively, followed by the name of the packet.

The remainder of the file specifies the packet's blocks and fields. A block is described by placing its name in square brackets (e.g. `[GrantData]'). Following the the line specifying the block's name, the block's fields and values are specified, separated by equal signs (e.g. `GodLevel = 255'), one per line.

The value of a field can be a literal value (e.g. `255'), or one of the following special values:

$Value

 the [value] specified by the user

$UUID

 a random UUID

$AgentID

 the user's AgentID

$SessionID

 the user's SessionID


PUBLIC INTERFACE

This section describes the interface that GridProxy applications will use to interact with the packet stream. Please see ChatConsole.cs for a simple example of how this interface can be used.

GridProxy extends the functionality of libopenmetaverse, so we assume here that the reader is already familiar with libopenmetaverse's Packet and PacketBuilder classes.

ProxyConfig class

An instance of ProxyConfig represents the configuration of a Proxy object, and must be provided when constructing a Proxy. ProxyConfig has two constructors:

       ProxyConfig(string userAgent, string author)
       ProxyConfig(string userAgent, string author, string[] args)

Both constructors require a user agent name and the author's email address. These are sent to Second Life's login server to identify the client, and to allow Linden Lab to get in touch with authors whose applications may inadvertantly be causing problems. The second constructor is preferred and takes an array of command-line arguments that allow the user to override certain network settings. For a list of command line arguments, start your appliation with the --proxy-help switch.

Proxy class

The Proxy class represents an instance of an GridProxy and provides the methods necessary to modify the packet stream. Proxy's sole constructor takes an instance of ProxyConfig.

Login delegates

You may specify that GridProxy should call a delegate method in your application when the user requests login or the server responds.

       delegate void XmlRpcRequestDelegate(XmlRpcRequest request)
       delegate void XmlRpcResponseDelegate(XmlRpcResponse response)
       void SetLoginRequestDelegate(XmlRpcRequestDelegate loginRequestDelegate)
       void SetLoginResponseDelegate(XmlRpcResponseDelegate loginResponseDelegate)

A login response delegate, in particular, is useful for retrieving the agent_id and session_id, which are required when injecting certain types of packets. See ChatConsole.cs for an example of how these can be retrieved.

Note that all delegates must terminate (not go into an infinite loop), and must be thread-safe.

Packet delegates

Packet delegates allow you to inspect and modify packets as they pass between the client and the server:

       delegate Packet PacketDelegate(Packet packet, IPEndPoint endPoint)
       void AddDelegate(string packetName, Direction direction, PacketDelegate packetDelegate)
       void RemoveDelegate(string packetName, Direction direction)

AddDelegate adds a callback delegate for packets named packetName going direction. Directions are either Direction.Incoming, meaning packets heading from the server to the client, or Direction.Outgoing, meaning packets heading from the client to the server. Only one delegate can apply to a packet at a time; if you add a new delegate with the same packetName and direction, the old one will be removed.

RemoveDelegate simply removes the delegate for the specified type of packet.

PacketDelegate methods are passed a copy of the packet (in the form of a libopenmetaverse Packet object) and the IPEndPoint of the server that sent (or will receive) the packet. PacketDelegate methods may do one of three things:

1. Return the same packet, in which case it will be passed on. 2. Return a new packet (built with libopenmetaverse), in which case the

  new packet will substitute for the original.  GridProxy will
  automatically copy the sequence number and appended ACKs from the
  old packet to the new one.

3. Return null, in which case the packet will not be passed on.

GridProxy automatically takes care of ensuring that sequence numbers and acknowledgements are adjusted to account for changes made by the application. When replacing a reliable packet with an unreliable packet or removing a reliable packet, a fake acknowledgement is injected. When replacing an unreliable packet with a reliable packet, GridProxy ensures delivery and intercepts its acknowledgement. Note that if a reliable packet is passed on but then lost on the network, Second Life will resend it and the delegate will be called again. You can tell if a packet is being resent by checking if (packet.Data[0] & Helpers.MSG_RESENT) is nonzero, although be advised that it's possible that the original packet never made it to the proxy and the packet will be marked RESENT the first time the proxy ever sees it. Note that all delegates must terminate (not go into an infinite loop), and must be thread-safe.

Packet injection

New packets may be injected into the stream at any point, either during a delegate callback or by another thread in your application. Packets are injected with the InjectPacket method:

       void InjectPacket(Packet packet, Direction direction)

This will inject a packet heading to either the client or to the active server, when direction is Direction.Incoming or Direction.Outgoing, respectively. The packet's sequence number will be set automatically, and if the packet is reliable, GridProxy will ensure its delivery and intercept its acknowledgement.

Injecting a packet immediately upon (or prior to) connection is not recommended, since the client and the server won't have initialized their session yet.

Starting and stopping the proxy

Once you've constructed a Proxy and added your delegates, you must start it with the Start method:

       void Start()

Once started, the proxy will begin listening for connections. The Start method spawns new threads for the proxy and returns immediately.

When your application is ready to shut down, you must call the Stop method:

       void Stop()

Note that this may not actually force the proxy to stop accepting connections; it merely guarantees that all foreground threads are stopped, allowing the application to exit cleanly.

(adapted from the GridProxy README file)

Credits

Originally written by axial. Modifications by Qode, makomk, and mcortez.