add norp v0.1b5

pull/2/head
Jeff Weston 2019-09-11 15:33:15 -04:00
parent 120989e3d6
commit c9ed6bd04f
17 changed files with 5282 additions and 0 deletions

37
norp/TODO.txt Normal file
View File

@ -0,0 +1,37 @@
The basic NORP server state machine is in place and pretty much ready for testing. There are some details that need to be wrapped up:
1) Implement ACK-based flow control using double-buffer markers, explict positive acknowledgement, (DONE) 1a) Add option to NORM to
only ACK after application has read stream data. (DONE)
2) Clean up debugging messages. (SOME)
3) Provide NORM congestion control options (DONE - CCE added)
4) Session configuration options (ouch!) 4a) Src/Dst based proxy methods and parameters
5) Implement auto handoff to TCP direct connnect on port unreachable (what about NORP request timeout, too?) (both DONE)
6) Use protolibd for "safer" socket state
7) norm_rx_stream can hangup shutdown - fix it (DONE)
8) Win32 build and test
8a) Win32 NORM-CCE support that's not WinPcap dependent
9) Send / handle negative SOCKS replies
10) IMPORTANT: Detect remote "norp" failure _or_ make sure that we can _always_ detect when our local TCP socket (originator client, or
correspondent remote) closes. Right now, we stop TCP socket input notification upon NORM flow control block condition (e.g. failed
watermark) ... we probably should have some failed watermark timeout condition, perhaps in conjunction with using an
application-defined command as a "keep-alive" mechanism. For example, have each NORM sender send a "keep-alive" heart beat
periodically, but upon multiple periods of failed watermark ACK _and_ missing "keep-alive", initiate session teardown? Otherwise, this
creates a condition of persistent requests of ACK indefinitely.
11) To provide easier firewall traversal, should we split the "correspondent" norm tx & rx sessions so that it can "talk back" to the
originator source port. Can also use the NORP messaging to signal the norm ports to use.

29
norp/VERSION.TXT Normal file
View File

@ -0,0 +1,29 @@
NORP Version History
Version 0.1b3
=============
- Added "correspondent <remoteNorpAddr>" command to allow 'routing'
of proxied connections through specified remote 'norp' peer
instead of directly to connection destination address.
- Includes fix to NORM source code of receiver rate estimation
measured during 'slow start' phase of congestion control
Version 0.1b2
=============
- Adopted NORM_SYNC_STREAM policy to guarantee synchronization
of stream start at byte offset zero of proxied TCP stream data
- Added norp "persist" command-line option to allow control of how
persistently norp tries to deliver TCP data in disruptive network
environments. A -1 persistence value is infinitely persistent.
The default persistence is 120 seconds (2 minutes).
Version 0.1b1
=============
- Fixed bugs with "forward" command recently added
- Updated "norm" with bug fix in normSession.cpp
Version 0.1
=============
- Started versioning
- This version adds the "forward" command for non-SOCKS proxying

File diff suppressed because one or more lines are too long

BIN
norp/doc/norpUserGuide.pdf Normal file

Binary file not shown.

567
norp/doc/norpUserGuide.xml Normal file
View File

@ -0,0 +1,567 @@
<?xml version="1.0" encoding="UTF-8"?>
<?xml-stylesheet type="text/xsl" href="transform.xsl"?>
<!DOCTYPE article PUBLIC "-//OASIS//DTD DocBook XML V4.1.2//EN"
"http://www.oasis-open.org/docbook/xml/4.1/docbookx.dtd">
<article>
<articleinfo>
<title><inlinemediaobject>
<imageobject>
<imagedata align="center" fileref="resources/ProteanLogo.png"
scale="30"/>
</imageobject>
</inlinemediaobject> <emphasis>norp</emphasis> User's Guide</title>
<titleabbrev><emphasis>norp</emphasis> User's Guide</titleabbrev>
<abstract>
<para>The NRL Nack-Oriented Proxy (<emphasis>norp</emphasis>) project
includes software for an RFC 1928 SOCKS5-compatible proxy server daemon
that is able to use the RFC 5740 Nack-Oriented Reliable Multicast (NORM)
transport protocol for efficient and robust data transfer between
<emphasis>norp</emphasis> proxy instances. The <emphasis>norp</emphasis>
proxy automatically supports conventional SOCKS TCP proxy operation when
a remote <emphasis>norp</emphasis> peer is unavailable. This software
was developed by the <ulink url="http://www.nrl.navy.mil/">Naval
Research Laboratory</ulink> (NRL) PROTocol Engineering Advanced
Networking Research Group.
The NRL reference implementation of NORM used here is available from
<ulink
url="http://www.nrl.navy.mil/itd/ncs/products/norm">http://www.nrl.navy.mil/itd/ncs/products/norm</ulink>.</para>
</abstract>
</articleinfo>
<sect1>
<title>Overview</title>
<para>The <emphasis>norp</emphasis> application ....</para>
</sect1>
<sect1 id="TheoryOfOperation">
<title>Theory of Operation</title>
<para>The <emphasis>norp</emphasis> program acts as a SOCKS proxy server.
It supports the SOCKS5 "CONNECT", "BIND" and "UDP-ASSOCIATE" proxy methods
for conventional SOCKS proxy operation. The current
<emphasis>norp</emphasis> implementation does not require (or support) any
client authentication. Future versions may provide authentication or other
access control mechanisms. The current <emphasis>norp</emphasis>
implementation only provides NORM transport for the SOCKS TCP "CONNECT"
requests. SOCKS "UDP-ASSOCIATE" over NORM will be supported in a future
version.</para>
<para>Unlike a conventional SOCKS server, it is expected that the
<emphasis>norp</emphasis> daemon can be installed and run as a local
"loopback" server that is co-resident on the host running applications
that wish to take advantage of NORM transport benefits. The
<emphasis>norp</emphasis> daemon implements its own signaling protocol
that will automatically determine, upon TCP (or UDP) connection
establishment, if a remote destination is also similarly
"<emphasis>norp</emphasis>-enabled" and establish a NORM transport
connection as the proxy connection. Otherwise a "business-as-usual" TCP
(or UDP) connection is established on the application's behalf and thus
compatibility with "non-<emphasis>norp</emphasis>" hosts is also
supported. <xref linkend="norpConcept"/> illustrates this high level
concept of operation.</para>
<para><figure id="norpConcept">
<title>NORP Concept of Operation</title>
<mediaobject>
<imageobject>
<imagedata fileref="resources/norpConcept.png" format="PNG"
scale="50"/>
</imageobject>
</mediaobject>
</figure></para>
<para><emphasis>TBD - provide some more details on norp signaling for peer
detection and NORM session establishment</emphasis></para>
<para>Note that as an alternative to making proxied connections directly
to connection destination addresses as illustrated above, a remote
<emphasis>norp</emphasis> peer "correspondent" can be specified as part of
the <literal>forward</literal> command or, for SOCKS connections, with the
<literal>correspondent</literal> command (see command descriptions below).
Future versions of <emphasis>norp</emphasis> will include more
sophisticated "routing" options for different destinations and traffic
types.</para>
<sect2>
<title>SOCKS Loopback and Intermediate System</title>
<para>As noted above the principal use case for
<emphasis>norp</emphasis> is to act as a local, "loopback" SOCKS server
that can be used in conjunction with a properly configured SOCKS client.
In this way, all of the configuration parameters are localized and
implicit and no precoordinated configuration with
<emphasis>norp</emphasis> peers (or non-<emphasis>norp</emphasis> hosts)
is required other than using a common UDP port number for NORP
signaling.</para>
<para>However, there may be use cases where it may be desirable to
deploy <emphasis>norp</emphasis> on intermediate systems at the
connection originating site (or domain) and/or the destination site(s)
(or domain(s)). This is easily supported by the
<emphasis>norp</emphasis> design and future norp versions will provide
configuration options for this type of deployment.</para>
</sect2>
<sect2>
<title>NORM Protocol Usage</title>
<para><emphasis>TBD - describe how the NORM streaming capability is used
in a flow-controlled, positively-acknowledged fashion to provide a
reliable TCP proxy function. Also describe the NORM congestion control
options here.</emphasis></para>
</sect2>
</sect1>
<sect1 id="Usage">
<title>Usage</title>
<para>Typically, <emphasis>norp</emphasis> can be run in its default
configuration with no command-line options required. However, a number of
options are available via the command-line. This is a summary of
<emphasis>norp</emphasis> usage:</para>
<para><informalexample>
<programlisting><?dbfo keep-together="always"?>norp [interface &lt;ifaceName&gt;][address &lt;publicAddr&gt;][sport &lt;socksPort&gt;][port &lt;norpPort&gt;]
[norm {on|off}][id &lt;normId&gt;][nport &lt;normPort&gt;][cce | ccl | rate &lt;bits/sec&gt;]
[limit &lt;bits/sec&gt;][persist &lt;seconds&gt;][correspondent &lt;remoteNorpAddr&gt;]
[forward &lt;tcpPort&gt;,&lt;destAddr&gt;/&lt;destPort&gt;[,&lt;remoteNorpAddr&gt;]][version][debug &lt;level&gt;]
[trace][dlog &lt;debugLog&gt;][lport &lt;localNorpPort&gt;][rport &lt;remoteNorpPort&gt;]</programlisting>
<para>The <emphasis>norp</emphasis> program command-line options
include ...</para>
</informalexample></para>
<table>
<title><emphasis><emphasis>norp</emphasis></emphasis> Command-line
Options</title>
<?dbfo keep-together="always"?>
<tgroup cols="2">
<colspec colname="Command" colwidth="1*"/>
<colspec colname="Description" colwidth="2.5*"/>
<tbody>
<row>
<entry align="left"><literal>interface
&lt;interfaceName&gt;</literal></entry>
<entry>The given <literal>&lt;interfaceName&gt;</literal>
specifies the name (or IP address) of the host network interface
<emphasis>norp</emphasis> uses as its "public" proxy address.
Currently a single interface may be designated for an instance of
<emphasis>norp</emphasis>. Future version of
<emphasis>norp</emphasis> may allow for multiple interfaces to be
designated depending upon the source and/or destination address of
SOCKS proxy connections.</entry>
</row>
<row>
<entry><literal>address &lt;publicAddr&gt;</literal></entry>
<entry>This is similar to the "<literal>interface</literal>"
command, but allows a specific address to be set. For example,
hosts with multiple addresses assigned may wish to use a specific
address for proxy functions.</entry>
</row>
<row>
<entry><literal>sport &lt;socksPort&gt;</literal></entry>
<entry>This command is used to specify the port number on which
the <emphasis>norp</emphasis> server listens for SOCKS client
connections. The default port is currently port number
7000.</entry>
</row>
<row>
<entry><literal>port &lt;norpPort&gt;</literal></entry>
<entry>This command is used to specify the UDP port number used
for <emphasis>norp</emphasis> session setup signaling. The default
<emphasis>norp</emphasis> UDP signaling port is 7001. The
configured <emphasis>norp</emphasis> port number (and NORM port
number) MUST be unblocked by any network firewalls between
<emphasis>norp</emphasis> peers. The given port number is used by
<emphasis>norp</emphasis> to listen for remote connection request
and is used as the destination port to signal remote
<emphasis>norp</emphasis> peers.</entry>
</row>
<row>
<entry><literal>norm {on | off}</literal></entry>
<entry>By default, <emphasis>norp</emphasis> attempts to signal
the SOCKS connection endpoint to setup a NORM transport connection
to handle reliable data transfer for the TCP connection being
instantiated. This command with the "<literal>off</literal>"
argument will disable this function and <emphasis>norp</emphasis>
will act as a conventional SOCKS proxy server.</entry>
</row>
<row>
<entry><literal>id &lt;normId&gt;</literal></entry>
<entry>By default, <emphasis>norp</emphasis> will attempt to
self-configure a NORM protocol node identifier using the IP
address of the server host. This command allows a specific NORM
node identifier value to be set. It is generally not necessary to
explicitly set this value for <emphasis>norp</emphasis> unicast
proxy connections.</entry>
</row>
<row>
<entry><constant>nport &lt;normPort&gt;</constant></entry>
<entry>This command can be used to specify a UDP port number that
will be used for NORM protocol transport connections. The default
NORM port number used by <emphasis>norp</emphasis> is 7002. The
configured NORM port number (and <emphasis>norp</emphasis> UDP
signaling <literal>port</literal> number) MUST be unblocked by any
network firewalls between <emphasis>norp</emphasis> peers.</entry>
</row>
<row>
<entry><literal>cce</literal></entry>
<entry>This option enables NORM-CCE congestion control operation
that uses Explicit Congestion Notification (ECN) information for
NORM protocol end-to-end transmission rate adaption. This is an
alternative to the TCP-friendly congestion control mechanism used
for NORM by default. Routers in the path of the
<emphasis>norp</emphasis> peers using the NORM-CCE option MUST be
configured for ECN packet marking in response to
congestion.</entry>
</row>
<row>
<entry><literal>ccl</literal></entry>
<entry>This option enables experimental NORM-CCL ("Loss Tolerant")
congestion control operation that uses some simple heuristics to
try to differentiate packet loss due to congestion versus duo to
channel bit errors. This is another alternative to the
TCP-friendly congestion control mechanism used for NORM by
default. No special intermediate system configuration is required,
and while more loss tolerant than the default TCP-friendly
behavior, is not as effective as the NORM-CCE mode of
operation.</entry>
</row>
<row>
<entry><literal>rate &lt;bits/sec&gt;</literal></entry>
<entry>This option causes <emphasis>norp</emphasis> to use a
preset and fixed transmission rate for each proxied data flow
(e.g. TCP connection). This should only be used when the network
connectivity usage is carefully pre-planned and previsioned for
the expected (i.e. <emphasis>a priori</emphasis> known) flows. At
this time, one common transmission rate is used for all
flows.</entry>
</row>
<row>
<entry><literal>limit &lt;bits/sec&gt;</literal></entry>
<entry>This option sets a limit for the
<emphasis>cumulative</emphasis> transmit rate for
<emphasis>all</emphasis> flows that <emphasis>norp</emphasis> is
proxying. For automated congestion operation, this can also work
to "jump start" the usual "slow start" transport rate control by
setting the lower bound of rate adjustment based on the limit
<literal>&lt;bits/sec&gt; / &lt;numFlows&gt;</literal>. For
example, a single flow will immediately "jump" to close the full
limit rate, while the second of two flows would "jump" to half of
the "limit" rate. Also, by setting a limit based on <emphasis>a
priori</emphasis> connectivity information, this can avoid rate
adjustment "overshoot" and help congestion control operate more
effectively as compared to a "blind" situation. IMPORTANT: This
options should only be applied when the connectivity path is well
known and the impact of the lower bound enforcement here will not
adversely impact other network traffic flows. A future option may
be provided to further reduce or eliminate the lower bound
enforcement that would eliminate this concern in less controlled
network deployments. A limit value of "-1.0" (default) disables
the limit enforcement.</entry>
</row>
<row>
<entry><literal>correspondent
&lt;remoteNorpAddr&gt;</literal></entry>
<entry>This option causes <emphasis>norp</emphasis> to "route"
connections through a <emphasis>norp</emphasis> peer at the
specified <parameter>&lt;remoteNorpAddr&gt;</parameter>. This is
an alternative to the default behavior where
<emphasis>norp</emphasis> attempts to connect directly to the
connection destination addresses.</entry>
</row>
<row>
<entry><literal>persist &lt;seconds&gt;</literal></entry>
<entry>This option controls how persistently norp attempts to
deliver data to the remote endpoint when the remote endpoint fails
to acknowledge reception. A persist value of -1 makes norp
infinitely persistent and the corresponding norp session remains
in place until all data is delivered. If not, an orphaned session
will remain in place if the remote endpoint is permanently
disconnected. The default persist value is 120 seconds (2
minutes).</entry>
</row>
<row>
<entry><literal>forward
&lt;tcpPort&gt;,&lt;dstAddr&gt;/&lt;dstPort&gt;[,&lt;norpAddr&gt;]</literal></entry>
<entry>This command sets up a "preset" TCP proxy (non-SOCKS) port
forwarding session by listening on the specified TCP
<parameter>&lt;tcpPort&gt;</parameter> for connections and then
connecting to the given remote
<parameter>&lt;dstAddr&gt;/&lt;dstPort&gt;</parameter>.
Optionally, a separate remote
<parameter>&lt;norpAddr&gt;</parameter> may be given. Otherwise, a
<emphasis>norp</emphasis> proxy connection is attempted to the
given <parameter>&lt;dstAddr&gt;</parameter> platform on the
<emphasis>norp</emphasis> <parameter>&lt;port&gt;</parameter> (or
<parameter>&lt;rport&gt;</parameter> if specified). Note that
multiple such "preset" proxy sessions may be specified on the
command-line and each "preset" proxy session can handle multiple
connections as needed.</entry>
</row>
<row>
<entry><literal>debug &lt;debugLevel&gt;</literal></entry>
<entrytbl cols="1">
<tbody>
<row>
<entry>This command can be used to control the verbosity of
<emphasis>norp</emphasis> debug logging output. Generally,
the range of the value is 0-12. A higher value results in
more verbose, detailed debug output.</entry>
</row>
</tbody>
</entrytbl>
</row>
<row>
<entry><literal>trace</literal></entry>
<entry>This command enables NORM send and receive packet trace
logging.</entry>
</row>
<row>
<entry><literal>dlog &lt;fileName&gt;</literal></entry>
<entrytbl cols="1">
<tbody>
<row>
<entry>This command can be used to direct
<emphasis>norp</emphasis> debug logging output to a given
file. The default <emphasis>norp</emphasis> debug logging is
to STDERR.</entry>
</row>
</tbody>
</entrytbl>
</row>
<row>
<entry><literal>lport &lt;localNorpPort&gt;</literal></entry>
<entry>This command can enable single host, loopback testing by a
having <emphasis>norp</emphasis> listen on a different port number
than which it uses as the destination port for remote
<emphasis>norp</emphasis> peer signaling. E.g., two
<emphasis>norp</emphasis> instances on a single machine can be set
up with unique <literal>&lt;localNorpPort&gt;</literal> values and
then use the "<literal>rport</literal>" command to specify each
other's destination <emphasis>norp</emphasis> port
numbers.</entry>
</row>
<row>
<entry><literal>rport &lt;remoteNorpPort&gt;</literal></entry>
<entry>This command is intended to be used in conjunction with the
"<literal>lport</literal>" command to allow separate specification
of the destination port number used for remote
<emphasis>norp</emphasis> peer signaling.</entry>
</row>
</tbody>
</tgroup>
</table>
<sect2>
<title>SOCKS Client Configuration</title>
<para><emphasis>TBD - provide overview and examples (for specific SOCKS
clients of note such as Dante, Proxifier, etc) of SOCKS client
configuration</emphasis></para>
</sect2>
<sect2 id="ExampleUsage">
<title>Usage Examples</title>
<para>The SOCKS client(s) must be configured to use the
<emphasis>norp</emphasis> server unless a preset TCP port
<literal>forward</literal> is specified. For example the Dante proxy
distribution (available from <ulink
url="http://www.inet.no/dante/">http://www.inet.no/dante/</ulink>) has a
<emphasis>socksify</emphasis> command that is installed and can be used
to launch existing network applications so their socket communications
are directed through the configured server. With Dante, a SOCKS
configuration file (typically <filename>/etc/socks.conf</filename>) or
the <constant>SOCKS5_SERVER</constant> environment variable can be used
to set the server address and port number.</para>
<para>The <emphasis>norp</emphasis> "server" is a lightweight module and
can be installed on the same end systems requiring the performance
benefits of NORM transport. In this case the SOCKS client server
configuration is the loopback address and <emphasis>norp</emphasis>
SOCKS port number (i.e. <literal>127.0.0.1:7000</literal>). The locally
installed norp SOCKS server will signal remote network destinations
(e.g., upon TCP connection initiation) to determine if the destination
is <emphasis>norp</emphasis>-capable. If possible, it will establish a
NORM-connection to the remote <emphasis>norp</emphasis> correspondent
that connects to the final destination. Otherwise a direct TCP
connection (or UDP relay) will be made to the remote destination.</para>
</sect2>
</sect1>
<sect1 id="Commands">
<title>The "NORP" UDP Signaling Message Format</title>
<para>The <emphasis>norp</emphasis> proxy uses UDP signaling to confirm
presence of a remote <emphasis>norp</emphasis> peer and to set up (and
tear down) NORM transport protocol sessions to support the proxied TCP
(and eventually UDP) transport connections. The norp instance originating
a SOCKS session request is referred to here as the "originator" and the
remote norp peer to which the request is directed is referred to as the
"correspondent". The <emphasis>norp</emphasis> "originator" is the server
associated with the SOCKS client making a request while the
"correspondent" establishes connections with the remote SOCKS
destination.</para>
<para>The following UDP payload format is used for NORP signaling:</para>
<para><programlisting><?dbfo keep-together="always"?>0 1 2 3
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| msgType | reserved | sessionId |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| normNodeId |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| normSrcPort | normDstPort |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| timestamp_sec |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| timestamp_usec |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| content ...
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
</programlisting></para>
<para>The NORP message types include:</para>
<variablelist>
<varlistentry>
<term>SOCKS_REQ</term>
<listitem>
<para>The message content contains a SOCKS5 Request message from the
"originator" to the "correspondent" <emphasis>norp</emphasis>
server.</para>
</listitem>
</varlistentry>
<varlistentry>
<term>ACK_REQ</term>
<listitem>
<para>The message is used to acknowledge receipt of a SOCKS_REQ
message. There is no "content"</para>
</listitem>
</varlistentry>
<varlistentry>
<term>SOCKS_REP</term>
<listitem>
<para>The message content contains a SOCKS5 Reply message from the
"correspondent" <emphasis>norp</emphasis> server.</para>
</listitem>
</varlistentry>
<varlistentry>
<term>ACK_REP</term>
<listitem>
<para>The message is used to acknoledge receipt of a SOCKS_REP
message. There is no "content".</para>
</listitem>
</varlistentry>
<varlistentry>
<term>ORIG_END</term>
<listitem>
<para>This message indicates the "originator"
<emphasis>norp</emphasis> server is terminating the given session.
There is no "content".</para>
</listitem>
</varlistentry>
<varlistentry>
<term>CORR_END</term>
<listitem>
<para>This message indicates the "correspondent"
<emphasis>norp</emphasis> server is terminating the given session.
There is no "content".</para>
</listitem>
</varlistentry>
<varlistentry>
<term>ACK_END</term>
<listitem>
<para>This message is used to acknowledge receipt of either an
ORIG_END or CORR_END message. There is no "content".</para>
</listitem>
</varlistentry>
</variablelist>
<para><emphasis>TBD - describe NORP signaling and the message format given
here.</emphasis></para>
</sect1>
<sect1>
<title>Future Plans</title>
<para>There are a number of additional features and refinements planned
for the <emphasis>norp</emphasis> implementation. Some of these
include:</para>
<orderedlist>
<listitem>
<para>Source / destination configuration and "routing" options</para>
</listitem>
<listitem>
<para>Data compression options</para>
</listitem>
<listitem>
<para>Security features</para>
</listitem>
</orderedlist>
</sect1>
</article>

Binary file not shown.

After

Width:  |  Height:  |  Size: 28 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 58 KiB

644
norp/include/norp.h Normal file
View File

@ -0,0 +1,644 @@
#ifndef _NORP
#define _NORP
#include "protoSocket.h"
#include "protoTimer.h"
#include "protoTree.h"
#include "protoDispatcher.h"
#include "protoPktSOCKS.h"
#include "normApi.h"
class Norp;
// A "NorpSession" associates a SOCKS client session with either a remote
// NORP endpoint (if one was or can be established) or a "direct connect"
// (TCP, UDP) if the remote endpoint is not NORP-enabled
// SOCKS requests/replies relayed via NORM command transmissions
// are prepended with this to uniquely identify the command
// (SOCKS request or reply and associate it with a NorpSession
// TBD - or should the endpoint socket binding addrs/ports be used instead??
//
// ProtoPktNORP is the packet format that NORP uses to relay SOCKS
// requests and replies via the NORM application-defined command
// signaling mechanism. The format of these commands is:
//
// 0 1 2 3
// 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
// | msgType | reserved | sessionId |
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
// | normNodeId |
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
// | normSrcPort | normDstPort |
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
// | timestamp_sec |
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
// | timestamp_usec |
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
// | Content ... |
//
class PortPool
{
public:
PortPool(UINT16 basePort);
UINT16 GrabPort();
void ReleasePort(UINT16 thePort);
private:
UINT16 base_port;
bool port_array[50];
}; // end class PortPool
class NorpMsg : public ProtoPkt
{
public:
NorpMsg(UINT32* bufferPtr = NULL,
unsigned int numBytes = 0,
bool initFromBuffer = true,
bool freeOnDestruct = false);
~NorpMsg();
bool InitFromBuffer(unsigned int msgLength,
UINT32* bufferPtr = NULL,
unsigned int numBytes = 0,
bool freeOnDestruct = false)
{return ProtoPkt::InitFromBuffer(msgLength, bufferPtr, numBytes, freeOnDestruct);}
enum Type
{
MSG_INVALID = 0,
SOCKS_REQ, // "content" is a SOCKS5 request
REQ_ACK, // request acknowledgment (no content)
SOCKS_REP, // "content" is a SOCKS5 request
REP_ACK, // reply acknowledgment (no content)
ORIG_END, // sent by originator to end session
CORR_END, // sent by correspondent to end session
ACK_END // end session acknowledgment (by either)
};
Type GetType() const
{return (Type)((UINT8*)buffer_ptr)[OFFSET_TYPE];}
UINT16 GetSessionId() const
{return (Type)ntohs(((UINT16*)buffer_ptr)[OFFSET_SESSION_ID]);}
// note "GetUINT32()" does ntohl() conversion
NormNodeId GetNodeId() const
{return (NormNodeId)GetUINT32(buffer_ptr + OFFSET_NODE_ID);}
UINT16 GetSourcePort() const
{return (Type)ntohs(((UINT16*)buffer_ptr)[OFFSET_SRC_PORT]);}
UINT16 GetDestinationPort() const
{return (Type)ntohs(((UINT16*)buffer_ptr)[OFFSET_DST_PORT]);}
void GetTimestamp(struct timeval& timestamp) const
{
timestamp.tv_sec = GetUINT32(buffer_ptr + OFFSET_SEC);
timestamp.tv_usec = GetUINT32(buffer_ptr + OFFSET_USEC);
}
void GetTimestamp(ProtoTime& theTime) const
{
struct timeval& timestamp = theTime.AccessTimeVal();
timestamp.tv_sec = GetUINT32(buffer_ptr + OFFSET_SEC);
timestamp.tv_usec = GetUINT32(buffer_ptr + OFFSET_USEC);
}
const UINT32* GetContentPtr() const
{return ((const UINT32*)AccessContentPtr());}
UINT32* AccessContentPtr() const
{return (buffer_ptr + OFFSET_CONTENT);}
unsigned int GetContentLength() const
{return (GetLength() - (OFFSET_CONTENT*4));}
// Packet building methods
void Init()
{
SetType(MSG_INVALID);
SetLength(0);
}
void SetType(Type msgType)
{
((UINT8*)buffer_ptr)[OFFSET_TYPE] = (UINT8)msgType;
pkt_length = (pkt_length < 1) ? 1 : pkt_length;
}
void SetSessionId(UINT16 sessionId)
{
((UINT8*)buffer_ptr)[OFFSET_RESERVED] = 0;
((UINT16*)buffer_ptr)[OFFSET_SESSION_ID] = htons(sessionId);
pkt_length = (pkt_length < 4) ? 4 : pkt_length;
}
void SetNodeId(NormNodeId nodeId)
{
SetUINT32(buffer_ptr + OFFSET_NODE_ID, nodeId);
pkt_length = (pkt_length<8) ? 8 : pkt_length;
}
void SetSourcePort(UINT16 srcPort)
{
((UINT16*)buffer_ptr)[OFFSET_SRC_PORT] = htons(srcPort);
pkt_length = (pkt_length < 10) ? 10 : pkt_length;
}
void SetDestinationPort(UINT16 dstPort)
{
((UINT16*)buffer_ptr)[OFFSET_DST_PORT] = htons(dstPort);
pkt_length = (pkt_length < 12) ? 12 : pkt_length;
}
void SetTimestamp(struct timeval& timestamp)
{
SetUINT32(buffer_ptr+OFFSET_SEC, timestamp.tv_sec);
SetUINT32(buffer_ptr+OFFSET_USEC, timestamp.tv_usec);
pkt_length = (pkt_length < 20) ? 20 : pkt_length;
}
bool SetContent(const char* data, unsigned int numBytes)
{
if ((numBytes + (4*OFFSET_CONTENT)) > GetBufferLength()) return false;
memcpy((char*)(buffer_ptr+OFFSET_CONTENT), data, numBytes);
SetContentLength(numBytes);
return true;
}
void SetContentLength(unsigned int numBytes)
{pkt_length = (4*OFFSET_CONTENT) + numBytes;}
private:
enum
{
OFFSET_TYPE = 0, // UINT8 offset
OFFSET_RESERVED = OFFSET_TYPE + 1, // UINT8 offset
OFFSET_SESSION_ID = (OFFSET_RESERVED+1)/2, // UINT16 offset
OFFSET_NODE_ID = (2*(OFFSET_SESSION_ID+1))/4, // UINT32 offset
OFFSET_SRC_PORT = (4*(OFFSET_NODE_ID+1))/2, // UINT16 offset
OFFSET_DST_PORT = OFFSET_SRC_PORT + 1, // UINT16 offset
OFFSET_SEC = (2*(OFFSET_DST_PORT+1))/4, // UINT32 offset
OFFSET_USEC = OFFSET_SEC + 1, // UINT32 offset
OFFSET_CONTENT = OFFSET_USEC + 1 // UINT32 offset
};
}; // end class NorpMsg
// A NorpPreset is a non-SOCKS proxied session where a
// local TCP port is monitored and connections are proxied
// proxied to a preset remote destination
class NorpPreset : public ProtoTree::Item
{
public:
NorpPreset(Norp& norpController, UINT16 tcpPort, const ProtoAddress& dstAddr, const ProtoAddress& norpAddr);
~NorpPreset();
const ProtoAddress& GetDstAddr() const
{return dst_addr;}
const ProtoAddress& GetNorpAddr() const
{return (norp_addr.IsValid() ? norp_addr : dst_addr);}
bool Listen();
ProtoSocket& AccessServerSocket()
{return server_socket;}
private:
const char* GetKey() const
{return ((const char*)&tcp_port);}
unsigned int GetKeysize() const
{return (sizeof(UINT16) << 3);}
void OnSocketEvent(ProtoSocket& theSocket, ProtoSocket::Event theEvent);
Norp& controller;
UINT16 tcp_port;
ProtoAddress dst_addr;
ProtoAddress norp_addr;
ProtoSocket server_socket;
}; // end class NorpPreset
class NorpPresetList : public ProtoTreeTemplate<NorpPreset>
{
public:
NorpPreset* FindPreset(UINT16 tcpPort) const
{return Find((char*)&tcpPort, sizeof(UINT16) << 3);}
}; // end class NorpPresetList
class NorpSession : public ProtoTree::Item
{
public:
NorpSession(Norp& norpController, UINT16 sessionId, NormNodeId originatorId = NORM_NODE_NONE);
~NorpSession();
enum SocksState
{
SOCKS_VOID, // when session gives self back to "controller" at Close
SOCKS_IDLE, // initial, inactive state (socks_client_socket is closed)
SOCKS_GET_AUTH_REQ, // first active state, accumulating auth request bytes from client
SOCKS_PUT_AUTH_REP, // next, writing auth reply bytes to client
SOCKS_GET_REQUEST, // next, accumulate SOCKS request bytes from client
SOCKS_PUT_REQUEST, // relaying request to remote NORP peer
SOCKS_CONNECTING, // attempt to satisfy request via remote connect, etc (this may need to be refined)
SOCKS_GET_REPLY, // awaiting reply from remote NORP peer
SOCKS_PUT_REPLY, // next, writing SOCK reply bytes to client
SOCKS_CONNECTED, // finally, reading/writing data from/to client
SOCKS_SHUTDOWN // session ended, in process of shutting down
};
void SetProxyAddress(const ProtoAddress& proxyAddr)
{proxy_addr = proxyAddr;}
void SetNormRateBounds(double rateMin, double rateMax);
NormNodeId GetNodeId() const;
UINT16 GetSessionId() const
{return session_id.identifier;}
NormNodeId GetOriginatorId() const
{return session_id.originator;}
bool IsRemoteSession() const
{return (NORM_SESSION_INVALID != norm_session);}
bool IsRemoteOriginator() const // assumes "IsRemoteSession()"
{return (NORM_NODE_NONE == GetOriginatorId());}
bool AcceptClientConnection(ProtoSocket& serverSocket, bool normEnable = true);
bool AcceptPresetClientConnection(NorpPreset& preset, bool normEnable);
SocksState GetSocksState() const
{return socks_state;}
const ProtoAddress& GetClientAddress() const
{return socks_client_socket.GetDestination();}
void Shutdown(); // hard shutdown, including signaling remote via NORP messaging
bool ShutdownComplete() const; // Tests for inband shutdown completion
void Close(); // hard local shutdown and cleanup including session deletion by controller
void OnNormEvent(NormEvent& theEvent);
bool OnClientRequest(const ProtoPktSOCKS::Request request, const ProtoAddress& srcAddr);
bool MakeDirectConnect(); // convert remote session to direct connect
// handles request relayed from remote NORP server
bool OnRemoteRequest(const NorpMsg& theMsg, const ProtoAddress& senderAddr);
bool OnRemoteRequestAcknowledgment(const NorpMsg& theMsg, const ProtoAddress& senderAddr);
bool OnRemoteReply(const NorpMsg& theMsg, const ProtoAddress& senderAddr);
bool OnRemoteReplyAcknowledgment(const NorpMsg& theMsg);
typedef struct Moniker
{
NormNodeId originator;
UINT16 identifier; // TBD - make this UINT32?
} Moniker;
static bool GetNormNodeAddress(NormNodeHandle nodeHandle, ProtoAddress& theAddr);
static const double NORP_RTT_MIN;
static const double NORP_RTT_MAX;
static const double NORP_RTT_DEFAULT;
private:
void ActivateTimer(ProtoTimer& theTimer);
const char* GetKey() const
{return ((const char*)&session_id);}
unsigned int GetKeysize() const
{return (sizeof(Moniker) << 3);}
void OnSocksClientEvent(ProtoSocket& theSocket,
ProtoSocket::Event theEvent);
// Note our "norp_tx_socket" is "connected" so we get error message when "port unreachable"
bool SendMessage(const NorpMsg& msg)
{
unsigned int numBytes = msg.GetLength();
return norp_tx_socket.Send((const char*)msg.GetBuffer(), numBytes);
}
bool OnNorpMsgTimeout(ProtoTimer& theTimer);
bool OnCloseTimeout(ProtoTimer& theTimer);
void OnUdpRelayEvent(ProtoSocket& theSocket,
ProtoSocket::Event theEvent);
// These methods are invoked as needed upon different events and SOCKS state transitions
bool GetClientAuthRequest();
bool PutClientAuthReply();
bool GetClientRequest();
bool ConnectToRemote(const ProtoAddress& srcAddr);
bool BindRemote(UINT16 bindPort);
bool OpenUdpRelay();
bool PutClientReply();
bool GetClientData();
bool PutClientData();
bool PutRemoteRequest(const ProtoPktSOCKS::Request& request, const ProtoAddress& remoteAddr);
bool OriginatorStartNorm(const ProtoAddress& senderAddr,
NormNodeId corrNormId,
UINT16 normSrcPort,
UINT16 normDstPort);
bool PutRemoteReply();
void OnSocksRemoteEvent(ProtoSocket& theSocket,
ProtoSocket::Event theEvent);
// These methods are invoked as needed upon different events and SOCKS state transitions
bool GetRemoteData();
bool PutRemoteData();
enum {SOCKS_BUFFER_SIZE = 16384};
enum {NORP_BUFFER_SIZE = 512};
enum {NORM_BUFFER_SIZE = (8192*1024)};
unsigned int WriteToNormStream(const char* buffer, unsigned int numBytes);
void FlushNormStream(bool eom, NormFlushMode flushMode);
unsigned int ComputeNormStreamBufferSegmentCount(unsigned int bufferBytes, UINT16 segmentSize, UINT16 blockSize);
// Member variables
Norp& controller;
bool is_preset; // special "preset" (non-SOCKS) proxy session
ProtoTimer close_timer;
Moniker session_id;
ProtoAddress proxy_addr; // address to advertise for remote connections
SocksState socks_state;
ProtoSocket socks_client_socket; // TCP connection from this server to SOCKS client
ProtoSocket socks_remote_socket; // TCP connection to remote when "direct connect" is used
ProtoSocket udp_relay_socket; // UDP relay socket (used for UDP_ASSOC requests)
ProtoAddress udp_client_addr; // address of local UDP_ASSOC client
UINT32 client_buffer[SOCKS_BUFFER_SIZE/sizeof(UINT32)]; // usually data received from client
unsigned int client_pending; // total bytes pending reception or transmission
unsigned int client_index; // current index
UINT32 remote_buffer[SOCKS_BUFFER_SIZE/sizeof(UINT32)]; // usually for data received from remote
unsigned int remote_pending; // total bytes pending reception or transmission
unsigned int remote_index; // current index
// NORM-related state
bool norm_enable;
ProtoSocket norp_tx_socket; // used to send NORP signaling messages
ProtoAddress norp_remote_addr;
ProtoTimer norp_msg_timer;
NorpMsg norp_msg; // current message being transmitted
UINT32 norp_msg_buffer[NORP_BUFFER_SIZE/sizeof(UINT32)];
double norp_rtt_estimate; // from REQUEST<->ACK or REPLY<->ACK exchange
NormSessionHandle norm_session;
NormObjectHandle norm_tx_stream;
NormObjectHandle norm_rx_stream;
bool norm_rx_pending;
double persist_interval; // in seconds, to timeout NORM delivery persistence after local TCP disconnect
ProtoTime persist_start_time; // marks start of persistence timeout
double norm_rate_min;
double norm_rate_max;
UINT16 norm_segment_size;
unsigned int norm_stream_buffer_max;
unsigned int norm_stream_buffer_count;
unsigned int norm_stream_bytes_remain;
bool norm_watermark_pending;
}; // end class NorpSession
class NorpSessionList : public ProtoTreeTemplate<NorpSession>
{
public:
NorpSession* FindSession(UINT16 sessionId, NormNodeId originatorId = NORM_NODE_NONE) const
{
NorpSession::Moniker id;
memset(&id, 0, sizeof(NorpSession::Moniker));
id.originator = originatorId;
id.identifier = sessionId;
return Find((char*)&id, sizeof(NorpSession::Moniker) << 3);
} // end NorpSessionList::FindSession()
}; // end class NorpSessionList
// The "Norp" class is an instance of a SOCKS server that manages
// SOCKS/NORM (or direct-connect) sessions
class Norp
{
public:
Norp(ProtoDispatcher& theDispatcher);
~Norp();
enum
{
DEFAULT_SOCKS_PORT = 7000, // SOCKS server TCP listen port used for NORP
DEFAULT_NORP_PORT = 7001, // Where NORP listens for UDP signaling, relayed commands, etc
DEFAULT_NORM_PORT = 7002 // Port used for NORM data transfer
};
static const double DEFAULT_TX_RATE;
static const double DEFAULT_PERSIST_INTERVAL;
void SetSocksPort(UINT16 thePort)
{socks_port = thePort;}
void SetProxyAddress(const ProtoAddress& proxyAddr)
{proxy_addr = proxyAddr;}
const ProtoAddress& GetProxyAddress() const
{return proxy_addr;}
bool StartServer(bool normEnable);
void StopServer();
void SetLocalNorpPort(UINT16 thePort)
{norp_local_port = thePort;}
void SetRemoteNorpPort(UINT16 thePort)
{norp_remote_port = thePort;}
UINT16 GetNorpPort() const
{return norp_remote_port;}
// In future, this will reference a "routing"
// table using the "destAddr"
bool GetRemoteNorpAddress(const ProtoAddress& destAddr,
ProtoAddress& norpAddr) const
{
norpAddr = norp_remote_addr.IsValid() ? norp_remote_addr : destAddr;
return true;
}
// This sets a remote "norp" peer address that is used instead of
// connecting directly to destination endpoints
// TBD - add more routing options than this
void SetRemoteNorpAddress(const ProtoAddress& remoteAddr)
{norp_remote_addr = remoteAddr;}
void SetInitialRtt(double seconds)
{norp_rtt_init = seconds;}
double GetInitialRtt() const
{return norp_rtt_init;}
// NORM protocol parameters
void SetNormNodeId(NormNodeId nodeId)
{norm_node_id = nodeId;}
NormNodeId GetNormNodeId() const
{return norm_node_id;}
NormInstanceHandle GetNormInstance() const
{return norm_instance;}
void SetNormPort(UINT16 thePort)
{norm_port = thePort;}
UINT16 GetNormPort() const
{return norm_port;}
/*
UINT16 GrabPort()
{return port_pool.GrabPort();}
void ReleasePort(UINT16 thePort)
{port_pool.ReleasePort(thePort);}
*/
enum NormCC
{
NORM_CC,
NORM_CCE,
NORM_CCL,
NORM_FIXED
};
void SetNormCC(NormCC ccMode)
{norm_cc_mode = ccMode;}
NormCC GetNormCC() const
{return norm_cc_mode;}
// For fixed-rate operation
void SetNormTxRate(double txRate)
{norm_tx_rate = txRate;}
double GetNormTxRate() const
{return norm_tx_rate;}
// Sets upper bound on _cumulative_ NormSession
// transmit rates
void SetNormTxLimit(double txLimit)
{norm_tx_limit = txLimit;}
double GetNormTxLimit() const
{return norm_tx_limit;}
void SetNormTrace(bool enable)
{norm_trace = enable;}
bool GetNormTrace() const
{return norm_trace;}
void SetNormSegmentSize(UINT16 numBytes)
{norm_segment_size = numBytes;}
UINT16 GetNormSegmentSize() const
{return norm_segment_size;}
void SetNormBlockSize(UINT32 numSegments)
{norm_block_size = numSegments;}
UINT16 GetNormBlockSize() const
{return norm_block_size;}
void SetNormParityCount(UINT16 numSegments)
{norm_parity_count = numSegments;}
UINT16 GetNormParityCount() const
{return norm_parity_count;}
void SetNormParityAuto(UINT16 numSegments)
{norm_parity_auto = numSegments;}
UINT16 GetNormParityAuto() const
{return norm_parity_auto;}
ProtoSocket::Notifier& GetSocketNotifier() const
{return static_cast<ProtoSocket::Notifier&>(dispatcher);}
void ActivateTimer(ProtoTimer& theTimer)
{dispatcher.ActivateTimer(theTimer);}
bool SendMessage(const NorpMsg& msg, const ProtoAddress& dstAddr)
{return norp_rx_socket.SendTo((const char*)msg.GetBuffer(), msg.GetLength(), dstAddr);}
void OnNorpSocketEvent(ProtoSocket& theSocket,
ProtoSocket::Event theEvent);
void OnSessionClose(NorpSession& theSession);
bool AddPreset(UINT16 tcpPort, const ProtoAddress& dstAddr, const ProtoAddress& norpAddr);
bool AcceptPresetClientConnection(NorpPreset& preset);
private:
void AddSession(NorpSession& session);
void RemoveSession(NorpSession& session);
void OnSocksServerEvent(ProtoSocket& theSocket,
ProtoSocket::Event theEvent);
static void NormEventCallback(ProtoDispatcher::Descriptor descriptor,
ProtoDispatcher::Event theEvent,
const void* userData);
void OnNormEvent();
void OnRemoteRequest(const NorpMsg& theMsg, const ProtoAddress& senderAddr);
void OnRemoteReply(const NorpMsg& theMsg, const ProtoAddress& senderAddr);
// Member variables
ProtoDispatcher& dispatcher; // TBD - make Norp multi-threaded w/ a pool of dispatchers
ProtoSocket socks_server_socket; // (SOCKS clients connect to this)
UINT16 socks_port;
ProtoAddress proxy_addr;
UINT16 next_session_id; // used to dole out unique session ids
NorpSessionList session_list; // list of client and remote sessions
unsigned int session_count;
NorpPresetList preset_list; // list of preset proxies w/ listening TCP socket
ProtoSocket norp_rx_socket; // UDP socket for receiving NORP signaling
UINT16 norp_local_port; // For loopback debugging, we allow "local" server port to be different than "remote"
UINT16 norp_remote_port;
ProtoAddress norp_remote_addr; // if unspecified, we proxy directly to connection destination address
double norp_rtt_init; // used as initial roundtrip estimate for NORP signaling
bool norm_enable;
NormInstanceHandle norm_instance;
NormNodeId norm_node_id;
// NORM parameters (including some for debugging
UINT16 norm_port;
NormCC norm_cc_mode;
double norm_tx_rate; // in bits/sec, only applicable for cc_mode == NORM_FIXED
double norm_tx_limit; // in bits/sec (_cumulative_ rate limit option)
char iface_name[64]; // Network interface
UINT16 norm_segment_size; // payload bytes per NORM_DATA message
UINT16 norm_block_size; // number of user data segments per FEC coding block
UINT16 norm_parity_count; // number of _computed_ parity segments per FEC coding block
UINT16 norm_parity_auto; // number of proactive (automatically sent) parity segments per block
bool norm_trace;
//PortPool port_pool;
}; // end class Norp
#endif // _NORP

View File

@ -0,0 +1,3 @@
#ifndef _NORP_VERSION
#define NORP_VERSION "0.1b5"
#endif // NORP_VERSION

View File

@ -0,0 +1,379 @@
#ifndef _PROTO_SOCKS
#define _PROTO_SOCKS
#include "protoPkt.h"
#include "protoAddress.h"
// These classes provide message parsing and building for
// the RFC 1928 SOCKS5 protocol specification.
// NOTES:
// 1) Only the methods needed for SOCKS server operation are defined here so far
// 2) Additional external helper logic is needed to incrementally read data from a
// SOCKS TCP client-server socket for a full SOCKS message. The message parsing
// here assumes the message has been read up to the point of whatever field
// is being requested.
namespace ProtoPktSOCKS
{
// SOCKS5 message definitions per RFC1928
// SOCKS5 auth request: VERSION + NMETHODS + METHOD_LIST ...
// 1 byte + 1 byte + N bytes
// SOCKS5 authentication methods
enum AuthType
{
AUTH_NONE = 0x00,
AUTH_GSSAPI = 0x01,
AUTH_USER = 0x02, // username / password
AUTH_INVALID = 0xff // no acceptable method
};
class AuthRequest : public ProtoPkt
{
public:
AuthRequest(UINT32* bufferPtr = NULL,
unsigned int numBytes = 0,
bool initFromBuffer = true,
bool freeOnDestruct = false);
~AuthRequest();
bool InitFromBuffer(unsigned int reqLength,
UINT32* bufferPtr = NULL,
unsigned int numBytes = 0,
bool freeOnDestruct = false)
{return ProtoPkt::InitFromBuffer(reqLength, bufferPtr, numBytes, freeOnDestruct);}
UINT8 GetVersion() const
{return ((pkt_length > OFFSET_VERSION) ?
(((UINT8*)buffer_ptr)[OFFSET_VERSION]) : 0);}
UINT8 GetMethodCount() const
{return ((pkt_length > OFFSET_NMETHOD) ?
(((UINT8*)buffer_ptr)[OFFSET_NMETHOD]) : 0);}
AuthType GetMethod(UINT8 index) const
{return ((pkt_length > (unsigned int)(OFFSET_METHODS + index)) ?
(AuthType)(((UINT8*)buffer_ptr)[OFFSET_METHODS + index]) : AUTH_INVALID);}
// TBD - implement auth request building (don't need this for a server)
private:
enum
{
OFFSET_VERSION = 0, // 1 byte
OFFSET_NMETHOD = OFFSET_VERSION + 1, // 1 byte
OFFSET_METHODS = OFFSET_NMETHOD + 1 // N bytes
};
}; // end class ProtoPktSOCKS::AuthRequest
// SOCKS5 auth reply: VERSION + METHOD_SELECTED
// bytes: 1 + 1
class AuthReply : public ProtoPkt
{
public:
AuthReply(UINT32* bufferPtr = NULL,
unsigned int numBytes = 0,
bool initFromBuffer = true,
bool freeOnDestruct = false);
~AuthReply();
bool InitFromBuffer(unsigned int replyLength,
UINT32* bufferPtr = NULL,
unsigned int numBytes = 0,
bool freeOnDestruct = false)
{return ProtoPkt::InitFromBuffer(replyLength, bufferPtr, numBytes, freeOnDestruct);}
UINT8 GetVersion() const
{return ((pkt_length > OFFSET_VERSION) ?
(((UINT8*)buffer_ptr)[OFFSET_VERSION]) : 0);}
UINT8 GetMethod() const
{return ((pkt_length > OFFSET_METHOD) ?
(((UINT8*)buffer_ptr)[OFFSET_METHOD]) : AUTH_INVALID);}
void SetVersion(UINT8 version)
{
((UINT8*)buffer_ptr)[OFFSET_VERSION] = version;
pkt_length = 1;
}
void SetMethod(AuthType method)
{
((UINT8*)buffer_ptr)[OFFSET_METHOD] = method;
pkt_length = 2;
}
private:
enum
{
OFFSET_VERSION = 0, // 1 byte
OFFSET_METHOD = OFFSET_VERSION + 1 // 1 byte
};
}; // end class ProtoPktSOCKS::AuthReply
// SOCKS5 request: VERSION + REQ + RESV + ADDR_TYP + DST.ADDR + DST.PORT
// bytes: 1 + 1 + 1 + 1 + N + 2
// SOCKS5 address types (1 byte)
enum AddrType
{
ADDR_INVALID = 0x00, // invalid addr type (for implementation)
IPv4 = 0x01, // 4-bytes, network byte order
NAME = 0x03, // 1-byte of "name" length, followed by "name"
IPv6 = 0x04 // 16-bytes, network byte order
}; // end ProtoPktSOCKS::AddrType
class Request : public ProtoPkt
{
public:
Request(UINT32* bufferPtr = NULL,
unsigned int numBytes = 0,
bool initFromBuffer = true,
bool freeOnDestruct = false);
~Request();
enum Command
{
CMD_INVALID = 0x00,
CONNECT = 0x01,
BIND = 0x02,
UDP_ASSOC = 0x03 // Setup UDP association
}; // end ProtoPktSOCKS::Request::Command
bool InitFromBuffer(unsigned int replyLength,
UINT32* bufferPtr = NULL,
unsigned int numBytes = 0,
bool freeOnDestruct = false)
{return ProtoPkt::InitFromBuffer(replyLength, bufferPtr, numBytes, freeOnDestruct);}
UINT8 GetVersion() const
{return ((pkt_length > OFFSET_VERSION) ?
(((UINT8*)buffer_ptr)[OFFSET_VERSION]) : 0);}
Command GetCommand() const
{return ((pkt_length > OFFSET_COMMAND) ?
(Command)(((UINT8*)buffer_ptr)[OFFSET_COMMAND]) : CMD_INVALID);}
AddrType GetAddressType() const
{return ((pkt_length > OFFSET_ATYPE) ?
(AddrType)(((UINT8*)buffer_ptr)[OFFSET_ATYPE]) : ADDR_INVALID);}
UINT8 GetAddressLength() const;
const char* GetAddressPtr() const
{return (const char*)AccessAddressPtr();}
UINT16 GetPort() const;
bool GetAddress(ProtoAddress& theAddr) const;
// TBD - implement request building (don't need this for a server)
void SetVersion(UINT8 version)
{
((UINT8*)buffer_ptr)[OFFSET_VERSION] = version;
pkt_length = 1;
}
void SetCommand(Command cmd)
{
((UINT8*)buffer_ptr)[OFFSET_COMMAND] = (UINT8)cmd;
pkt_length = 2;
}
void SetAddressType(AddrType addrType)
{
((UINT8*)buffer_ptr)[OFFSET_RESERVED] = 0;
((UINT8*)buffer_ptr)[OFFSET_ATYPE] = (UINT8)addrType;
pkt_length = 4;
}
bool SetAddress(const ProtoAddress& theAddr); // note this sets port, too
bool SetName(const char* theName);
bool SetPort(UINT16 thePort);
private:
enum
{
OFFSET_VERSION = 0, // 1 byte
OFFSET_COMMAND = OFFSET_VERSION + 1, // 1 byte
OFFSET_RESERVED = OFFSET_COMMAND + 1, // 1 byte
OFFSET_ATYPE = OFFSET_RESERVED + 1, // 1 byte
OFFSET_ADDR = OFFSET_ATYPE + 1 // N bytes
};
char* AccessAddressPtr() const
{
char* addrPtr = ((char*)buffer_ptr) + OFFSET_ADDR;
return (NAME == GetAddressType()) ? (addrPtr + 1) : addrPtr;
}
}; // end class ProtoPktSOCKS::Request
// SOCKS5 REPLY: VERSION + REP + RESV + ATYP + BIND.ADDR + BIND.PORT
// bytes: 1 + 1 + 1 + 1 + N + 2
class Reply : public ProtoPkt
{
public:
Reply(UINT32* bufferPtr = NULL,
unsigned int numBytes = 0,
bool initFromBuffer = true,
bool freeOnDestruct = false);
~Reply();
enum Type
{
SUCCESS = 0x00, // succeeded
FAILURE = 0x01, // general failure
DENIED = 0x02, // connection not allowed
NET_X = 0x03, // network unreachable
HOST_X = 0x04, // host unreachable
REFUSED = 0x05, // connection refused
TTL_X = 0x06, // TTL expired
CMD_X = 0x07, // command not supported
ADDR_X = 0x08, // address type not supported
TYPE_INVALID = 0xff // invalid reply type
}; // end ProtoPktSOCKS::Reply::Type
bool InitFromBuffer(unsigned int replyLength,
UINT32* bufferPtr = NULL,
unsigned int numBytes = 0,
bool freeOnDestruct = false)
{return ProtoPkt::InitFromBuffer(replyLength, bufferPtr, numBytes, freeOnDestruct);}
UINT8 GetVersion() const
{return ((pkt_length > OFFSET_VERSION) ?
(((UINT8*)buffer_ptr)[OFFSET_VERSION]) : 0);}
Type GetType() const
{return ((pkt_length > OFFSET_TYPE) ?
(Type)(((UINT8*)buffer_ptr)[OFFSET_TYPE]) : TYPE_INVALID);}
AddrType GetAddressType() const
{return ((pkt_length > OFFSET_ATYPE) ?
(AddrType)(((UINT8*)buffer_ptr)[OFFSET_ATYPE]) : ADDR_INVALID);}
UINT8 GetAddressLength() const;
const char* GetAddressPtr() const
{return (const char*)AccessAddressPtr();}
UINT16 GetPort() const;
bool GetAddress(ProtoAddress& theAddr) const;
// Reply building (call these in order
void SetVersion(UINT8 version)
{
((UINT8*)buffer_ptr)[OFFSET_VERSION] = version;
pkt_length = 1;
}
void SetType(Type replyType)
{
((UINT8*)buffer_ptr)[OFFSET_TYPE] = (UINT8)replyType;
pkt_length = 2;
}
void SetAddress(AddrType addrType, const char* addrPtr, UINT8 addrLen);
void SetPort(UINT16 thePort);
void SetAddress(const ProtoAddress& theAddr); // sets address and port from ProtoAddress
private:
enum
{
OFFSET_VERSION = 0, // 1 byte
OFFSET_TYPE = OFFSET_VERSION + 1, // 1 byte
OFFSET_RESERVED = OFFSET_TYPE + 1, // 1 byte
OFFSET_ATYPE = OFFSET_RESERVED + 1, // 1 byte
OFFSET_ADDR = OFFSET_ATYPE + 1 // N bytes
};
char* AccessAddressPtr() const
{
char* addrPtr = ((char*)buffer_ptr) + OFFSET_ADDR;
return (NAME == GetAddressType()) ? (addrPtr + 1) : addrPtr;
}
}; // end class ProtoPktSOCKS::Reply
// UDP relay header: RESV + FRAG + ATYP + DST.ADDR + DST.PORT + DATA
// bytes: 2 + 1 1 + N + 2 + K
class UdpRequest : public ProtoPkt
{
public:
UdpRequest(UINT32* bufferPtr = NULL,
unsigned int numBytes = 0,
bool initFromBuffer = true,
bool freeOnDestruct = false);
~UdpRequest();
bool InitFromBuffer(unsigned int requestLength,
UINT32* bufferPtr = NULL,
unsigned int numBytes = 0,
bool freeOnDestruct = false)
{return ProtoPkt::InitFromBuffer(requestLength, bufferPtr, numBytes, freeOnDestruct);}
UINT8 GetFrag() const
{return ((pkt_length > OFFSET_FRAG) ?
(((UINT8*)buffer_ptr)[OFFSET_FRAG]) : 0);}
AddrType GetAddressType() const
{return ((pkt_length > OFFSET_ATYPE) ?
(AddrType)(((UINT8*)buffer_ptr)[OFFSET_ATYPE]) : ADDR_INVALID);}
UINT8 GetAddressLength() const;
const char* GetAddressPtr() const
{return (const char*)AccessAddressPtr();}
UINT16 GetPort() const;
bool GetAddress(ProtoAddress& theAddr) const;
const char* GetDataPtr() const
{return (const char*)AccessDataPtr();}
unsigned int GetDataLength() const
{return (GetLength() - (GetDataPtr() - ((const char*)buffer_ptr)));}
// Packet building (call these in order)
void SetFragment(UINT8 fragId)
{
((UINT8*)buffer_ptr)[OFFSET_RESERVED] = 0;
((UINT8*)buffer_ptr)[OFFSET_FRAG] = fragId;
pkt_length = OFFSET_FRAG + 1;
}
void SetAddress(AddrType addrType, const char* addrPtr, UINT8 addrLen);
void SetPort(UINT16 thePort);
void SetAddress(const ProtoAddress& theAddr); // sets address and port from ProtoAddress
void SetData(const char* data, unsigned int numBytes)
{
memcpy(AccessDataPtr(), data, numBytes);
SetDataLength(numBytes);
}
void SetDataLength(unsigned int numBytes)
{pkt_length = (GetDataPtr() - ((char*)buffer_ptr)) + numBytes;}
private:
enum
{
OFFSET_RESERVED = 0, // 2 bytes
OFFSET_FRAG = OFFSET_RESERVED + 2, // 1 byte
OFFSET_ATYPE = OFFSET_FRAG + 1, // 1 byte
OFFSET_ADDR = OFFSET_ATYPE + 1 // N bytes
};
char* AccessAddressPtr() const
{
char* addrPtr = ((char*)buffer_ptr) + OFFSET_ADDR;
return (NAME == GetAddressType()) ? (addrPtr + 1) : addrPtr;
}
char* AccessDataPtr() const
{return (AccessAddressPtr() + GetAddressLength() + 2);}
}; // end class ProtoPktSOCKS::UdpRequest
}; // end namespace ProtoPktSOCKS
#endif // _PROTO_SOCKS

View File

@ -0,0 +1,54 @@
#########################################################################
# "norp" common Makefile portion
#
SHELL=/bin/sh
.SUFFIXES: .cpp $(.SUFFIXES)
# "chant" depends upon the NRL "norm" and "protolib" libraries
NORM = ../norm
PROTOLIB = $(NORM)/protolib
LIBPROTO = $(PROTOLIB)/lib/libprotokit.a
LIBNORM = $(NORM)/lib/libnorm.a
COMMON = ../src/common
NORP_SRC = $(COMMON)/norp.cpp $(COMMON)/norpApp.cpp \
$(COMMON)/protoPktSOCKS.cpp $(SYSTEM_SRC)
NORP_OBJ = $(NORP_SRC:.cpp=.o)
INCLUDES = -I../include -I$(NORM)/include -I$(PROTOLIB)/include
CFLAGS = -g -DPROTO_DEBUG -Wall -O -fPIC $(SYSTEM_CFLAGS) $(PROTO_CFLAGS) $(INCLUDES)
LIBS = $(SYSTEM_LIBS)
TARGETS = norp
# Rule for C++ .cpp extension
.cpp.o:
$(CC) -c $(CFLAGS) -o $*.o $*.cpp
all: norp
$(PROTOLIB)/lib/libprotokit.a:
$(MAKE) -C $(PROTOLIB)/makefiles -f Makefile.$(SYSTEM) libprotokit.a
$(NORM)/lib/libnorm.a:
$(MAKE) -C $(NORM)/makefiles -f Makefile.$(SYSTEM) libnorm.a
norp: $(LIBPROTO) $(LIBNORM) $(NORP_OBJ)
$(CC) $(LDFLAGS) -o $@ $(NORP_OBJ) $(LIBS) $(LIBNORM) $(LIBPROTO)
clean:
rm -f norp $(COMMON)/*.o;
$(MAKE) -C $(NORM)/makefiles -f Makefile.$(SYSTEM) clean;
$(MAKE) -C $(PROTOLIB)/makefiles -f Makefile.$(SYSTEM) clean;
distclean: clean
# DO NOT DELETE THIS LINE -- mkdep uses it.
# DO NOT PUT ANYTHING AFTER THIS LINE, IT WILL GO AWAY.

View File

@ -0,0 +1,27 @@
#
# Linux wxWindows Makefile definitions
#
# 1) Where to find the wxWindows files
WX_FLAGS = `wx-config --cxxflags`
WX_LIBS = `wx-config --libs`
# 2) System specific additional libraries, include paths, etc
# (Where to find X11 libraries, etc)
#
SYSTEM_FLAGS =
SYSTEM_INCLUDES =
SYSTEM_LIBS = -lm -lpthread
SYSTEM_REZ = touch
PROTO_CFLAGS = -DLINUX -DUNIX -DHAVE_IPV6 -DHAVE_GETLOGIN -D_FILE_OFFSET_BITS=64 -DHAVE_LOCKF -DHAVE_OLD_SIGNALHANDLER -DHAVE_DIRFD -DHAVE_ASSERT
SYSTEM = linux
CC = g++
RANLIB = ranlib
AR = ar
SYSTEM_SRC =
include Makefile.common

View File

@ -0,0 +1,48 @@
#
# MacOS-X wxWindows Makefile definitions
#
# 1) wxWidgets flags and libs
WX_CONFIG_PATH = /usr/local/bin/wx-config
WX_CFLAGS = `$(WX_CONFIG_PATH) --cxxflags`
WX_LIBS = `$(WX_CONFIG_PATH) --libs`
# 2) System-specific flags and libs
SYSTEM_CFLAGS = -arch x86_64
SYSTEM_LIBS = -arch x86_64 -lresolv
# 3) System-specific Protolib flags (_must_ correspond to Protolib SYSTEM_HAVES)
# Must choose appropriate for the following:
#
# A) -DHAVE_CUSERID (preferred) or -DHAVE_GETLOGIN for cuserid() or getlogin()
# functions to obtain user's login name (We may change this to getpwd()
# if that is better across different platforms and login environments)
#
# B) -DHAVE_LOCKF (preferred) or -D_LOCKF for lockf() or flock() file locking
# functions to attempt exclusive lock on writing to files
#
# C) Specify -DHAVE_DIRFD if you system provides the "dirfd()" function
# (Most don't have it defined ... but some do)
#
# D) Optionally specify -DHAVE_ASSERT if your system has a built-in ASSERT()
# routine.
#
# E) Some systems (SOLARIS/SUNOS) have a few gotchas which require
# some #ifdefs to avoid compiler warnings ... so you might need
# to specify -DSOLARIS or -DSUNOS depending on your OS.
# (We export these for other Makefiles as needed)
#
PROTO_CFLAGS = -DUNIX -DHAVE_IPV6 -DHAVE_ASSERT -DHAVE_GETLOGIN -DHAVE_FLOCK -DHAVE_DIRFD
# Additional system-specific source code to use
SYSTEM_SRC =
SYSTEM = macosx
CC = c++
RANLIB = ranlib
AR = ar
SYSTEM_BUNDLE = chant.app
include Makefile.common

1
norp/norm Symbolic link
View File

@ -0,0 +1 @@
..

2704
norp/src/common/norp.cpp Normal file

File diff suppressed because it is too large Load Diff

378
norp/src/common/norpApp.cpp Normal file
View File

@ -0,0 +1,378 @@
#include "protoApp.h"
#include "protoNet.h"
#include "norp.h"
#include "norpVersion.h"
#include <stdio.h> // for stderr
#include <stdlib.h> // for atoi()
class NorpApp : public ProtoApp
{
public:
NorpApp();
~NorpApp();
// Required verrides from ProtoApp base
bool OnStartup(int argc, const char*const* argv);
bool ProcessCommands(int argc, const char*const* argv);
void OnShutdown();
private:
enum CmdType {CMD_INVALID, CMD_ARG, CMD_NOARG};
static CmdType GetCmdType(const char* string);
bool OnCommand(const char* cmd, const char* val);
void Usage();
static const char* const CMD_LIST[];
Norp norp;
bool norm_enable;
}; // end class NorpApp
// Our application instance
PROTO_INSTANTIATE_APP(NorpApp)
NorpApp::NorpApp()
: norp(dispatcher), norm_enable(true)
{
}
NorpApp::~NorpApp()
{
norp.StopServer();
}
void NorpApp::Usage()
{
fprintf(stderr, "Usage: norp [interface <ifaceName>][address <publicAddr>][sport <socksPort>][port <norpPort>]\n"
" [norm {on|off}][id <normId>][nport <normPort>][cce | ccl | rate <bits/sec>][persist <seconds>][limit <bits/sec>]\n"
" [correspondent <remoteNorpAddr>][forward <tcpPort>,<destAddr>/<destPort>[,<remoteNorpAddr>]][version]\n"
" [debug <level>][trace][dlog <debugLog>][lport <localNorpPort>][rport <remoteNorpPort>]\n");
}
const char* const NorpApp::CMD_LIST[] =
{
"+interface", // "public facing" interface (its address is used for bindings)
"+address", // explicit "public facing" address to use for bindings
"+sport", // SOCKS server port (7000 by default)
"+port", // NORP UDP signaling port number (7001 by default)
"+norm", // "on" or "off" to enable/disable NORM proxying ("on" by default)
"+id", // set local NormNodeId (auto set from IP address by default)
"+nport", // NORM port (UDP) (7002 by default)
"-cce", // Use NORM-CCE instead of NORM-CC
"-ccl", // Use NORM-CCL instead of NORM-CC
"+rate", // set fixed transmit rate (no congestion control)
"+limit", // set _cumulaltive_ NORP transmit rate limit
"+persist", // <seconds> how long to persist NORM data delivery to receiver after TCP socket closure
"+debug", // set debug level
"-trace", // enables NORM protocol packet send/recv trace in debug output
"+dlog", // specify a file for debug logging
"+lport", // "local" NORP port (for loopback debugging)
"+rport", // "remote" NORP port (for loopback debugging)
"+forward", // <port>,<dstAddr>/<dstPort>[,<remoteNorpAddr>] to set up a preset proxy TCP listener
"+correspondent", // <remoteNorpAddr> to route proxied connections through remote NORP proxy at given addr
"-version", // print version number and exit
NULL
};
NorpApp::CmdType NorpApp::GetCmdType(const char* cmd)
{
if (!cmd) return CMD_INVALID;
unsigned int len = strlen(cmd);
bool matched = false;
CmdType type = CMD_INVALID;
const char* const* nextCmd = CMD_LIST;
while (*nextCmd)
{
if (!strncmp(cmd, *nextCmd+1, len))
{
if (matched)
{
// ambiguous command (command should match only once)
return CMD_INVALID;
}
else
{
matched = true;
if ('+' == *nextCmd[0])
type = CMD_ARG;
else
type = CMD_NOARG;
}
}
nextCmd++;
}
return type;
} // end NorpApp::GetCmdType()
bool NorpApp::OnStartup(int argc, const char*const* argv)
{
if (!ProcessCommands(argc, argv))
{
PLOG(PL_ERROR, "NorpApp::OnStartup() error: bad command line\n");
Usage();
return false;
}
// If a proxy address wasn't set, use "default" local address for host
if (!norp.GetProxyAddress().IsValid())
{
ProtoAddress theAddr;
if (theAddr.ResolveLocalAddress())
norp.SetProxyAddress(theAddr);
else
PLOG(PL_WARN, "NorpApp::OnStartup() warning: proxy address undetermined!\n");
}
PLOG(PL_INFO, "norp: starting proxy with address %s\n", norp.GetProxyAddress().GetHostString());
if (!norp.StartServer(norm_enable))
{
PLOG(PL_ERROR, "NorpApp::OnStartup() error: norp server startup failure!\n");
return false;
}
return true;
} // end NorpApp::OnStartup()
void NorpApp::OnShutdown()
{
norp.StopServer();
CloseDebugLog();
} // end Norp::OnShutdown()
bool NorpApp::ProcessCommands(int argc, const char*const* argv)
{
// Dispatch command-line commands to our OnCommand() method
int i = 1;
while ( i < argc)
{
// Is it a class NorpApp command?
switch (GetCmdType(argv[i]))
{
case CMD_INVALID:
{
PLOG(PL_ERROR, "NorpApp::ProcessCommands() Invalid command:%s\n", argv[i]);
return false;
}
case CMD_NOARG:
if (!OnCommand(argv[i], NULL))
{
PLOG(PL_ERROR, "NorpApp::ProcessCommands() ProcessCommand(%s) error\n", argv[i]);
return false;
}
i++;
break;
case CMD_ARG:
if (!OnCommand(argv[i], argv[i+1]))
{
PLOG(PL_ERROR, "NorpApp::ProcessCommands() ProcessCommand(%s, %s) error\n", argv[i], argv[i+1]);
return false;
}
i += 2;
break;
}
}
return true;
} // end NorpApp::ProcessCommands()
bool NorpApp::OnCommand(const char* cmd, const char* val)
{
// (TBD) move command processing into Mgen class ???
CmdType type = GetCmdType(cmd);
ASSERT(CMD_INVALID != type);
unsigned int len = strlen(cmd);
if ((CMD_ARG == type) && !val)
{
PLOG(PL_ERROR, "NorpApp::ProcessCommand(%s) missing argument\n", cmd);
return false;
}
else if (!strncmp("version", cmd, len))
{
fprintf(stdout, "norp version %s\n", NORP_VERSION);
exit(0);
}
else if (!strncmp("debug", cmd, len))
{
SetDebugLevel(atoi(val));
}
else if (!strncmp("trace", cmd, len))
{
norp.SetNormTrace(true);
}
else if (!strncmp("dlog", cmd, len))
{
OpenDebugLog(val);
}
else if (!strncmp("interface", cmd, len))
{
ProtoAddress ifaceAddr;
if (!ProtoNet::GetInterfaceAddress(val, ProtoAddress::IPv4, ifaceAddr))
{
PLOG(PL_ERROR, "NorpApp::OnCommand(interface) error: unable to get address for interface \"%s\"\n", val);
return false;
}
norp.SetProxyAddress(ifaceAddr);
}
else if (!strncmp("address", cmd, len))
{
ProtoAddress theAddr;
if (!theAddr.ResolveFromString(val))
{
PLOG(PL_ERROR, "NorpApp::OnCommand(interface) error: invalid address \"%s\"\n", val);
return false;
}
norp.SetProxyAddress(theAddr);
}
else if (!strncmp("sport", cmd, len))
{
norp.SetSocksPort(atoi(val));
}
else if (!strncmp("port", cmd, len))
{
UINT16 norpPort = atoi(val);
norp.SetLocalNorpPort(norpPort);
norp.SetRemoteNorpPort(norpPort);
}
else if (!strncmp("norm", cmd, len))
{
if (0 == strcmp("on", val))
norm_enable = true;
else
norm_enable = false;
}
else if (!strncmp("id", cmd, len))
{
norp.SetNormNodeId(atoi(val));
}
else if (!strncmp("nport", cmd, len))
{
norp.SetNormPort(atoi(val));
}
else if (!strncmp("cce", cmd, len))
{
norp.SetNormCC(Norp::NORM_CCE);
}
else if (!strncmp("ccl", cmd, len))
{
norp.SetNormCC(Norp::NORM_CCL);
}
else if (!strncmp("rate", cmd, len))
{
double txRate;
if (1 != sscanf(val, "%lf", &txRate))
{
PLOG(PL_ERROR, "NorpApp::OnCommand(rate) error: invalid rate \"%s\" bps\n", val);
return false;
}
norp.SetNormCC(Norp::NORM_FIXED);
norp.SetNormTxRate(txRate);
}
else if (!strncmp("limit", cmd, len))
{
double txLimit;
if (1 != sscanf(val, "%lf", &txLimit))
{
PLOG(PL_ERROR, "NorpApp::OnCommand(limit) error: invalid limit rate \"%s\" bps\n", val);
return false;
}
norp.SetNormTxLimit(txLimit);
}
else if (!strncmp("lport", cmd, len))
{
norp.SetLocalNorpPort(atoi(val));
}
else if (!strncmp("rport", cmd, len))
{
norp.SetRemoteNorpPort(atoi(val));
}
else if (!strncmp("forward", cmd, len))
{
// <port>,<dstAddr>/<dstPort>[,<remoteNorpAddr>]
char* text = new char[strlen(val) + 1]; // copy so we can slice and dice
if (NULL == text)
{
PLOG(PL_ERROR, "NorpApp::OnCommand(%s) new char[] error: %s\n", cmd, GetErrorString());
return false;
}
strcpy(text, val);
char* dstAddrPtr = strchr(text, ',');
if (NULL == dstAddrPtr)
{
PLOG(PL_ERROR, "NorpApp::OnCommand(%s, %s) error: missing <dstAddr>!\n", cmd, val);
delete[] text;
return false;
}
*dstAddrPtr++ = '\0';
char* dstPortPtr = strchr(dstAddrPtr, '/');
if (NULL == dstPortPtr)
{
PLOG(PL_ERROR, "NorpApp::OnCommand(%s, %s) error: missing <dstPort>!\n", cmd, val);
delete[] text;
return false;
}
UINT16 tcpPort;
int result = sscanf(text, "%hu", &tcpPort);
if ((1 != result) || (0 == tcpPort))
{
PLOG(PL_ERROR, "NorpApp::OnCommand(%s, %s) error: invalid <port> \"%s\"!\n", cmd, val, text);
delete[] text;
return false;
}
*dstPortPtr++ = '\0';
char* norpAddrPtr = strchr(dstPortPtr, ',');
if (NULL != norpAddrPtr) *norpAddrPtr++ = '\0';
ProtoAddress dstAddr;
if (!dstAddr.ResolveFromString(dstAddrPtr))
{
PLOG(PL_ERROR, "NorpApp::OnCommand(%s, %s) error: invalid <dstAddr> \"%s\"!\n", cmd, val, dstAddrPtr);
delete[] text;
return false;
}
UINT16 dstPort;
result = sscanf(dstPortPtr, "%hu", &dstPort);
if ((1 != result) || (0 == dstPort))
{
PLOG(PL_ERROR, "NorpApp::OnCommand(%s, %s) error: invalid <dstPort> \"%s\"!\n", cmd, val, text);
delete[] text;
return false;
}
dstAddr.SetPort(dstPort);
ProtoAddress norpAddr;
if (NULL != norpAddrPtr)
{
if (!norpAddr.ResolveFromString(norpAddrPtr))
{
PLOG(PL_ERROR, "NorpApp::OnCommand(%s, %s) error: invalid <norpAddr> \"%s\"!\n", cmd, val, norpAddrPtr);
delete[] text;
return false;
}
}
if (!norp.AddPreset(tcpPort, dstAddr, norpAddr))
{
PLOG(PL_ERROR, "NorpApp::OnCommand(%s, %s) error: unable to add preset!\n", cmd, val);
delete[] text;
return false;
}
delete[] text;
}
else if (!strncmp("correspondent", cmd, len))
{
// <remoteNorpAddr>
ProtoAddress norpAddr;
if (!norpAddr.ResolveFromString(val))
{
PLOG(PL_ERROR, "NorpApp::OnCommand(%s, %s) error: invalid <remoteNorpAddr>!\n", cmd, val);
return false;
}
norp.SetRemoteNorpAddress(norpAddr);
}
else
{
PLOG(PL_ERROR, "NorpApp::OnCommand(%s) error: unimplemented command!\n", cmd);
return false;
}
return true;
} // end NorpApp::OnCommand()

View File

@ -0,0 +1,388 @@
#include "protoPktSOCKS.h"
#include "protoDebug.h"
ProtoPktSOCKS::AuthRequest::AuthRequest(UINT32* bufferPtr, unsigned int numBytes, bool initFromBuffer, bool freeOnDestruct)
: ProtoPkt(bufferPtr, numBytes, freeOnDestruct)
{
if (initFromBuffer) InitFromBuffer(numBytes);
}
ProtoPktSOCKS::AuthRequest::~AuthRequest()
{
}
ProtoPktSOCKS::AuthReply::AuthReply(UINT32* bufferPtr, unsigned int numBytes, bool initFromBuffer, bool freeOnDestruct)
: ProtoPkt(bufferPtr, numBytes, freeOnDestruct)
{
if (initFromBuffer) InitFromBuffer(numBytes);
}
ProtoPktSOCKS::AuthReply::~AuthReply()
{
}
ProtoPktSOCKS::Request::Request(UINT32* bufferPtr, unsigned int numBytes, bool initFromBuffer, bool freeOnDestruct)
: ProtoPkt(bufferPtr, numBytes, freeOnDestruct)
{
if (initFromBuffer) InitFromBuffer(numBytes);
}
ProtoPktSOCKS::Request::~Request()
{
}
UINT8 ProtoPktSOCKS::Request::GetAddressLength() const
{
switch (GetAddressType())
{
case IPv4:
return 4;
case NAME:
// First byte of "name" is length value
return ((UINT8*)buffer_ptr)[OFFSET_ADDR];
case IPv6:
return 16;
default:
return 0;
}
} // end ProtoPktSOCKS::Request::GetAddressLength()
UINT16 ProtoPktSOCKS::Request::GetPort() const
{
const char* portPtr = GetAddressPtr() + GetAddressLength();
UINT16 temp16;
memcpy(&temp16, portPtr, 2);
return ntohs(temp16);
} // end ProtoPktSOCKS::Request::GetPort()
bool ProtoPktSOCKS::Request::GetAddress(ProtoAddress& theAddr) const
{
switch (GetAddressType())
{
case IPv4:
{
theAddr.SetRawHostAddress(ProtoAddress::IPv4, GetAddressPtr(), 4);
break;
}
case NAME:
{
char name[256];
UINT8 addrLen = GetAddressLength();
strncpy(name, GetAddressPtr(), addrLen);
name[addrLen] = '\0';
if (!theAddr.ResolveFromString(name))
{
PLOG(PL_ERROR, "ProtoPktSOCKS::Request::GetAddress() error: unable to resolve name \"%s\" to addr!\n", name);
return false;
} break;
}
case IPv6:
{
theAddr.SetRawHostAddress(ProtoAddress::IPv6, GetAddressPtr(), 16);
break;
}
default:
{
PLOG(PL_ERROR, "ProtoPktSOCKS::Request::GetAddress() error: invalid address type!\n");
return false;
}
}
theAddr.SetPort(GetPort());
return true;
} // end ProtoPktSOCKS::Request::GetAddress()
bool ProtoPktSOCKS::Request::SetAddress(const ProtoAddress& theAddr)
{
AddrType addrType;
UINT8 addrLength;
switch (theAddr.GetType())
{
case ProtoAddress::IPv4:
addrType = IPv4;
addrLength = 4;
break;
case ProtoAddress::IPv6:
addrType = IPv6;
addrLength = 16;
break;
default:
PLOG(PL_ERROR, "ProtoPktSOCKS::Request::SetAddress() error: invalid address type!\n");
return false;
}
SetAddressType(addrType);
memcpy(AccessAddressPtr(), theAddr.GetRawHostAddress(), addrLength);
pkt_length = OFFSET_ADDR + addrLength;
SetPort(theAddr.GetPort());
return true;
} // end ProtoPktSOCKS::Request::SetAddress()
bool ProtoPktSOCKS::Request::SetPort(UINT16 thePort)
{
char* portPtr = AccessAddressPtr() + GetAddressLength();
UINT16 temp16 = htons(thePort);
memcpy(portPtr, (char*)&temp16, 2);
pkt_length = OFFSET_ADDR + GetAddressLength() + 2;
return true;
} // end ProtoPktSOCKS::Request::SetPort()
bool ProtoPktSOCKS::Request::SetName(const char* theName)
{
SetAddressType(NAME);
unsigned int nameLength = strlen(theName);
// TBD - validate there is sufficient buffer space
memcpy(AccessAddressPtr(), theName, nameLength);
pkt_length += nameLength;
return true;
} // end ProtoPktSOCKS::Request::SetAddress()
ProtoPktSOCKS::Reply::Reply(UINT32* bufferPtr, unsigned int numBytes, bool initFromBuffer, bool freeOnDestruct)
: ProtoPkt(bufferPtr, numBytes, freeOnDestruct)
{
if (initFromBuffer) InitFromBuffer(numBytes);
}
ProtoPktSOCKS::Reply::~Reply()
{
}
UINT8 ProtoPktSOCKS::Reply::GetAddressLength() const
{
switch (GetAddressType())
{
case IPv4:
return 4;
case NAME:
// First byte of "name" is length value
return ((UINT8*)buffer_ptr)[OFFSET_ADDR];
case IPv6:
return 16;
default:
return 0;
}
} // end ProtoPktSOCKS::Reply::GetAddressLength()
UINT16 ProtoPktSOCKS::Reply::GetPort() const
{
const char* portPtr = GetAddressPtr() + GetAddressLength();
UINT16 temp16;
memcpy(&temp16, portPtr, 2);
return ntohs(temp16);
} // end ProtoPktSOCKS::Reply::GetPort()
bool ProtoPktSOCKS::Reply::GetAddress(ProtoAddress& theAddr) const
{
switch (GetAddressType())
{
case IPv4:
{
theAddr.SetRawHostAddress(ProtoAddress::IPv4, GetAddressPtr(), 4);
break;
}
case NAME:
{
char name[256];
UINT8 addrLen = GetAddressLength();
strncpy(name, GetAddressPtr(), addrLen);
name[addrLen] = '\0';
if (!theAddr.ResolveFromString(name))
{
PLOG(PL_ERROR, "ProtoPktSOCKS::Reply::GetAddress() error: unable to resolve name \"%s\" to addr!\n", name);
return false;
} break;
}
case IPv6:
{
theAddr.SetRawHostAddress(ProtoAddress::IPv6, GetAddressPtr(), 16);
break;
}
default:
{
PLOG(PL_ERROR, "ProtoPktSOCKS::Reply::GetAddress() error: invalid address type!\n");
return false;
}
}
theAddr.SetPort(GetPort());
return true;
} // end ProtoPktSOCKS::Reply::GetAddress()
void ProtoPktSOCKS::Reply::SetAddress(AddrType addrType, const char* addrPtr, UINT8 addrLen)
{
switch (addrType)
{
case ProtoPktSOCKS::IPv4:
((UINT8*)buffer_ptr)[OFFSET_ATYPE] = (UINT8)ProtoPktSOCKS::IPv4;
memcpy(((char*)buffer_ptr) + OFFSET_ADDR, addrPtr, 4);
pkt_length = OFFSET_ADDR + 4;
break;
case ProtoPktSOCKS::NAME:
((UINT8*)buffer_ptr)[OFFSET_ATYPE] = (UINT8)ProtoPktSOCKS::NAME;
((UINT8*)buffer_ptr)[OFFSET_ADDR] = (UINT8)addrLen;
memcpy(((char*)buffer_ptr) + OFFSET_ADDR + 1, addrPtr, addrLen);
pkt_length = OFFSET_ADDR + 1 + addrLen;
break;
case ProtoPktSOCKS::IPv6:
((UINT8*)buffer_ptr)[OFFSET_ATYPE] = (UINT8)ProtoPktSOCKS::IPv6;
memcpy(((char*)buffer_ptr) + OFFSET_ADDR, addrPtr, 16);
pkt_length = OFFSET_ADDR + 16;
break;
default:
PLOG(PL_ERROR, "ProtoPktSOCKS::Reply::SetAddress() invalid SOCKS address type\n");
break;
}
} // end ProtoPktSOCKS::Reply::SetAddress()
void ProtoPktSOCKS::Reply::SetPort(UINT16 thePort)
{
UINT16 temp16 = htons(thePort);
char* portPtr = AccessAddressPtr() + GetAddressLength();
memcpy(portPtr, &temp16, 2);
pkt_length = (GetAddressPtr() + GetAddressLength() + 2 - (char*)buffer_ptr);
} // end ProtoPktSOCKS::Reply::SetPort()
void ProtoPktSOCKS::Reply::SetAddress(const ProtoAddress& theAddr)
{
switch (theAddr.GetType())
{
case ProtoAddress::IPv4:
SetAddress(ProtoPktSOCKS::IPv4, theAddr.GetRawHostAddress(), 4);
SetPort(theAddr.GetPort());
break;
case ProtoAddress::IPv6:
SetAddress(ProtoPktSOCKS::IPv6, theAddr.GetRawHostAddress(), 16);
SetPort(theAddr.GetPort());
break;
default:
PLOG(PL_ERROR, "ProtoPktSOCKS::Reply::SetAddress() invalid ProtoAddress type\n");
break;
}
} // end ProtoPktSOCKS::Reply::SetAddress()
ProtoPktSOCKS::UdpRequest::UdpRequest(UINT32* bufferPtr, unsigned int numBytes, bool initFromBuffer, bool freeOnDestruct)
: ProtoPkt(bufferPtr, numBytes, freeOnDestruct)
{
if (initFromBuffer) InitFromBuffer(numBytes);
}
ProtoPktSOCKS::UdpRequest::~UdpRequest()
{
}
UINT8 ProtoPktSOCKS::UdpRequest::GetAddressLength() const
{
switch (GetAddressType())
{
case IPv4:
return 4;
case NAME:
// First byte of "name" is length value
return ((UINT8*)buffer_ptr)[OFFSET_ADDR];
case IPv6:
return 16;
default:
return 0;
}
} // end ProtoPktSOCKS::UdpRequest::GetAddressLength()
UINT16 ProtoPktSOCKS::UdpRequest::GetPort() const
{
const char* portPtr = GetAddressPtr() + GetAddressLength();
UINT16 temp16;
memcpy(&temp16, portPtr, 2);
return ntohs(temp16);
} // end ProtoPktSOCKS::UdpRequest::GetPort()
bool ProtoPktSOCKS::UdpRequest::GetAddress(ProtoAddress& theAddr) const
{
switch (GetAddressType())
{
case IPv4:
{
theAddr.SetRawHostAddress(ProtoAddress::IPv4, GetAddressPtr(), 4);
break;
}
case NAME:
{
char name[256];
UINT8 addrLen = GetAddressLength();
strncpy(name, GetAddressPtr(), addrLen);
name[addrLen] = '\0';
if (!theAddr.ResolveFromString(name))
{
PLOG(PL_ERROR, "ProtoPktSOCKS::UdpRequest::GetAddress() error: unable to resolve name \"%s\" to addr!\n", name);
return false;
}
break;
}
case IPv6:
{
theAddr.SetRawHostAddress(ProtoAddress::IPv6, GetAddressPtr(), 16);
break;
}
default:
{
PLOG(PL_ERROR, "ProtoPktSOCKS::UdpRequest::GetAddress() error: invalid address type!\n");
return false;
}
}
theAddr.SetPort(GetPort());
return true;
} // end ProtoPktSOCKS::UdpRequest::GetAddress()
void ProtoPktSOCKS::UdpRequest::SetAddress(AddrType addrType, const char* addrPtr, UINT8 addrLen)
{
switch (addrType)
{
case ProtoPktSOCKS::IPv4:
((UINT8*)buffer_ptr)[OFFSET_ATYPE] = (UINT8)ProtoPktSOCKS::IPv4;
memcpy(((char*)buffer_ptr) + OFFSET_ADDR, addrPtr, 4);
pkt_length = OFFSET_ADDR + 4;
break;
case ProtoPktSOCKS::NAME:
((UINT8*)buffer_ptr)[OFFSET_ATYPE] = (UINT8)ProtoPktSOCKS::NAME;
((UINT8*)buffer_ptr)[OFFSET_ADDR] = (UINT8)addrLen;
memcpy(((char*)buffer_ptr) + OFFSET_ADDR + 1, addrPtr, addrLen);
pkt_length = OFFSET_ADDR + 1 + addrLen;
break;
case ProtoPktSOCKS::IPv6:
((UINT8*)buffer_ptr)[OFFSET_ATYPE] = (UINT8)ProtoPktSOCKS::IPv6;
memcpy(((char*)buffer_ptr) + OFFSET_ADDR, addrPtr, 16);
pkt_length = OFFSET_ADDR + 16;
break;
default:
PLOG(PL_ERROR, "ProtoPktSOCKS::UdpRequest::SetAddress() invalid SOCKS address type\n");
break;
}
} // end ProtoPktSOCKS::UdpRequest::SetAddress()
void ProtoPktSOCKS::UdpRequest::SetPort(UINT16 thePort)
{
UINT16 temp16 = htons(thePort);
char* portPtr = AccessAddressPtr() + GetAddressLength();
memcpy(portPtr, &temp16, 2);
pkt_length = (GetAddressPtr() + GetAddressLength() + 2 - (char*)buffer_ptr);
} // end ProtoPktSOCKS::UdpRequest::SetPort()
void ProtoPktSOCKS::UdpRequest::SetAddress(const ProtoAddress& theAddr)
{
switch (theAddr.GetType())
{
case ProtoAddress::IPv4:
SetAddress(ProtoPktSOCKS::IPv4, theAddr.GetRawHostAddress(), 4);
SetPort(theAddr.GetPort());
break;
case ProtoAddress::IPv6:
SetAddress(ProtoPktSOCKS::IPv6, theAddr.GetRawHostAddress(), 16);
SetPort(theAddr.GetPort());
break;
default:
PLOG(PL_ERROR, "ProtoPktSOCKS::UdpRequest::SetAddress() invalid ProtoAddress type\n");
break;
}
} // end ProtoPktSOCKS::UdpRequest::SetAddress()