* Commented out an unused packet from SLProxy * mapgenerator now takes four arguments, the new third argument is the new unusedpackets.txt file that specifies backend packets that are not used in libsecondlife * Updated build and solution files to reflect the new changes git-svn-id: http://libopenmetaverse.googlecode.com/svn/trunk@767 52acb1d6-8a22-11de-b505-999d5b087335
376 lines
14 KiB
Plaintext
376 lines
14 KiB
Plaintext
NOTE: THIS DEVELOPER BRANCH IS THE NEW PREGEN SLPROXY. THIS DOCUMENT
|
|
MAY NOT BE UP TO DATE WITH THE NEW VERSION.
|
|
|
|
Public Source - Release Canidate 1
|
|
|
|
MODIFICATIONS BY "ALPHA ZAIUS" / ANDREW ORTMAN. QODE IN EFNET: #LIBSL
|
|
AND #LIBSL-DEV
|
|
|
|
SPECIAL THANKS TO "mcortez" IN EFNET (#libsl-dev) FOR A HELPFUL PATCH
|
|
TO ANALYST AND SLPROXY-PREGEN TO KICKSTART ITS TESTING.
|
|
|
|
---------------------------------------------------------------------
|
|
SLProxy is a library that works in conjunction with libsecondlife to
|
|
allow applications to wedge themselves between the official Second
|
|
Life client and servers. SLProxy 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.
|
|
SLProxy 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 SLProxy 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, SLProxy 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.
|
|
|
|
SLProxy can only handle one client using a proxy at a time.
|
|
|
|
BUILDING
|
|
========
|
|
|
|
To build SLProxy, you must check out the entire libsecondlife trunk
|
|
with subversion:
|
|
|
|
svn co svn://svn.gna.org/svn/libsecondlife/trunk libsecondlife
|
|
|
|
The libsecondlife-cs project must be built first; see
|
|
libsecondlife-cs/README for instructions. Building SLProxy 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 SLProxy library and its example applications will be built in
|
|
bin/Debug. In order to run the example applications, you must first
|
|
add the libsecondlife-cs build directory to your MONO_PATH environment
|
|
variable. For example, if your libsecondlife-cs directory is
|
|
~/libsecondlife/libsecondlife-cs and your shell is bash, you can type:
|
|
|
|
export MONO_PATH=$MONO_PATH:~/libsecondlife/libsecondlife-cs/bin/Debug/
|
|
|
|
INCLUDED APPLICATIONS
|
|
=====================
|
|
|
|
Included with SLProxy are a few example application, which are covered
|
|
in this section.
|
|
|
|
1. Analyst
|
|
----------
|
|
|
|
Analyst makes SLProxy'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.
|
|
|
|
/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. SLProxy 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.
|
|
|
|
Analyst also accepts a --log-login command line switch, which causes
|
|
the XML-RPC login request and response to dumped to the console.
|
|
|
|
2.1 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
|
|
|
|
2. ChatConsole
|
|
--------------
|
|
|
|
ChatConsole is a trivial SLProxy application intended as an example of
|
|
how SLProxy 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.
|
|
|
|
PUBLIC INTERFACE
|
|
================
|
|
|
|
This section describes the interface that SLProxy applications will
|
|
use to interact with the packet stream. Please see ChatConsole.cs for
|
|
a simple example of how this interface can be used.
|
|
|
|
SLProxy extends the functionality of libsecondlife, so we assume here
|
|
that the reader is already familiar with libsecondlife's Packet and
|
|
PacketBuilder classes.
|
|
|
|
1. 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.
|
|
|
|
2. Proxy class
|
|
--------------
|
|
|
|
The Proxy class represents an instance of an SLProxy and provides the
|
|
methods necessary to modify the packet stream. Proxy's sole
|
|
constructor takes an instance of ProxyConfig.
|
|
|
|
2.1 Login delegates
|
|
- - - - - - - - - -
|
|
|
|
You may specify that SLProxy 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.
|
|
|
|
2.2 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 libsecondlife 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 libsecondlife), in which case the
|
|
new packet will substitute for the original. SLProxy 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.
|
|
|
|
SLProxy 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,
|
|
SLProxy 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.
|
|
|
|
2.3 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, SLProxy 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.
|
|
|
|
2.4 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.
|
|
|
|
3. PacketUtility class
|
|
----------------------
|
|
|
|
The PacketUtility class provides a handful of static methods which may
|
|
be useful when inspecting and modifying packets.
|
|
|
|
3.1 Hashtable Unbuild(Packet packet)
|
|
- - - - - - - - - - - - - - - - - -
|
|
|
|
The Unbuild method takes a Packet object and returns a table of
|
|
blocks, structured in a format suitable for passing to PacketUtility's
|
|
GetField and SetField methods or PacketBuilder's BuildPacket method.
|
|
|
|
For example, this should make an approximate copy of a packet:
|
|
|
|
Hashtable packetBlocks = PacketUtility.Unbuild(packet);
|
|
Packet packetCopy = PacketBuilder.BuildPacket(packet.Layout.Name, protocolManager, packetBlocks, packet.Data[0]);
|
|
|
|
3.2 object GetField(Hashtable blocks, string block, string field)
|
|
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
|
|
|
The GetField method takes a table of blocks (produced by
|
|
PacketUtility.Unbuild) and extracts the value of a particular field.
|
|
If the field is part of a variable block, an arbitrary instance of the
|
|
field will be returned. If the field does not exist, null will be
|
|
returned.
|
|
|
|
3.3 void SetField(Hashtable blocks, string block, string field, object value)
|
|
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
|
|
|
The SetField method takes a table of blocks (produced by
|
|
PacketUtility.Unbuild) and sets the value of a particular field. If
|
|
the field is part of a variable block, all instances of the field will
|
|
be set. If the field does not exist, SetField will have no effect.
|
|
|
|
This can be used by a packet delegate method in conjunction with
|
|
PacketUtility.Unbuild and PacketBuilder.BuildPacket to substitute a
|
|
new packet that is a copy of the original packet with certain fields
|
|
modified.
|