add norp v0.1b5
parent
120989e3d6
commit
c9ed6bd04f
|
|
@ -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.
|
||||
|
||||
|
|
@ -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
Binary file not shown.
|
|
@ -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 <ifaceName>][address <publicAddr>][sport <socksPort>][port <norpPort>]
|
||||
[norm {on|off}][id <normId>][nport <normPort>][cce | ccl | rate <bits/sec>]
|
||||
[limit <bits/sec>][persist <seconds>][correspondent <remoteNorpAddr>]
|
||||
[forward <tcpPort>,<destAddr>/<destPort>[,<remoteNorpAddr>]][version][debug <level>]
|
||||
[trace][dlog <debugLog>][lport <localNorpPort>][rport <remoteNorpPort>]</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
|
||||
<interfaceName></literal></entry>
|
||||
|
||||
<entry>The given <literal><interfaceName></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 <publicAddr></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 <socksPort></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 <norpPort></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 <normId></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 <normPort></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 <bits/sec></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 <bits/sec></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><bits/sec> / <numFlows></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
|
||||
<remoteNorpAddr></literal></entry>
|
||||
|
||||
<entry>This option causes <emphasis>norp</emphasis> to "route"
|
||||
connections through a <emphasis>norp</emphasis> peer at the
|
||||
specified <parameter><remoteNorpAddr></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 <seconds></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
|
||||
<tcpPort>,<dstAddr>/<dstPort>[,<norpAddr>]</literal></entry>
|
||||
|
||||
<entry>This command sets up a "preset" TCP proxy (non-SOCKS) port
|
||||
forwarding session by listening on the specified TCP
|
||||
<parameter><tcpPort></parameter> for connections and then
|
||||
connecting to the given remote
|
||||
<parameter><dstAddr>/<dstPort></parameter>.
|
||||
Optionally, a separate remote
|
||||
<parameter><norpAddr></parameter> may be given. Otherwise, a
|
||||
<emphasis>norp</emphasis> proxy connection is attempted to the
|
||||
given <parameter><dstAddr></parameter> platform on the
|
||||
<emphasis>norp</emphasis> <parameter><port></parameter> (or
|
||||
<parameter><rport></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 <debugLevel></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 <fileName></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 <localNorpPort></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><localNorpPort></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 <remoteNorpPort></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 |
|
|
@ -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
|
||||
|
|
@ -0,0 +1,3 @@
|
|||
#ifndef _NORP_VERSION
|
||||
#define NORP_VERSION "0.1b5"
|
||||
#endif // NORP_VERSION
|
||||
|
|
@ -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
|
||||
|
|
@ -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.
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
File diff suppressed because it is too large
Load Diff
|
|
@ -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()
|
||||
|
||||
|
||||
|
||||
|
|
@ -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()
|
||||
|
||||
Loading…
Reference in New Issue