From dfec754bf1e95cd3e23a114f63842ad061cf79df Mon Sep 17 00:00:00 2001 From: Jeff Weston Date: Wed, 11 Sep 2019 15:36:43 -0400 Subject: [PATCH] update norp to latest --- norp/VERSION.TXT | 13 +++ norp/doc/norpUserGuide.html | 10 +- norp/doc/norpUserGuide.pdf | Bin 126544 -> 127586 bytes norp/include/norp.h | 4 +- norp/include/norpVersion.h | 2 +- norp/makefiles/Makefile.linux | 4 +- norp/makefiles/win32/norp.sln | 78 ++++++++++++++ norp/makefiles/win32/norp.vcxproj | 114 +++++++++++++++++++++ norp/src/common/norp.cpp | 164 ++++++++++++++++++++++++------ 9 files changed, 348 insertions(+), 41 deletions(-) create mode 100644 norp/makefiles/win32/norp.sln create mode 100644 norp/makefiles/win32/norp.vcxproj diff --git a/norp/VERSION.TXT b/norp/VERSION.TXT index ba836ac..a5f615d 100644 --- a/norp/VERSION.TXT +++ b/norp/VERSION.TXT @@ -1,5 +1,18 @@ NORP Version History +Version 0.1b8 +============= + - Improved NAT traversal by using single NORM tx/rx socket + +Version 0.1b6 +============= + - Added Visual Studio project files for Windows builds + (Thanks to Sam Rhody of John Hopkins APL) + - Fixed code that poorly assumed that zero bytes read from + a ProtoSocket(TCP) meant the connection had ended. Fixed + related Window ProtoSocket(TCP) issue to make sure socket + close events are reported properly. + Version 0.1b3 ============= - Added "correspondent " command to allow 'routing' diff --git a/norp/doc/norpUserGuide.html b/norp/doc/norpUserGuide.html index 5388c85..2b4132a 100644 --- a/norp/doc/norpUserGuide.html +++ b/norp/doc/norpUserGuide.html @@ -1,10 +1,10 @@ - norp User's Guide

norp User's Guide

Abstract

The NRL Nack-Oriented Proxy (norp) 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 norp proxy instances. The norp proxy automatically supports conventional SOCKS TCP proxy operation when a remote norp peer is unavailable. This software was developed by the Naval Research Laboratory (NRL) PROTocol Engineering Advanced Networking Research Group. The NRL reference implementation of NORM used here is available from http://www.nrl.navy.mil/itd/ncs/products/norm.


1. Overview

The norp application ....

2. Theory of Operation

The norp 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 norp implementation does not require (or support) any client authentication. Future versions may provide authentication or other access control mechanisms. The current norp implementation only provides NORM transport for the SOCKS TCP "CONNECT" requests. SOCKS "UDP-ASSOCIATE" over NORM will be supported in a future version.

Unlike a conventional SOCKS server, it is expected that the norp 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 norp daemon implements its own signaling protocol that will automatically determine, upon TCP (or UDP) connection establishment, if a remote destination is also similarly "norp-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-norp" hosts is also supported. Figure 1, “NORP Concept of Operation” illustrates this high level concept of operation.

Figure 1. NORP Concept of Operation

NORP Concept of Operation


TBD - provide some more details on norp signaling for peer detection and NORM session establishment

Note that as an alternative to making proxied connections directly to connection destination addresses as illustrated above, a remote norp peer "correspondent" can be specified as part of the forward command or, for SOCKS connections, with the correspondent command (see command descriptions below). Future versions of norp will include more sophisticated "routing" options for different destinations and traffic types.

2.1. SOCKS Loopback and Intermediate System

As noted above the principal use case for norp 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 norp peers (or non-norp hosts) is required other than using a common UDP port number for NORP signaling.

However, there may be use cases where it may be desirable to deploy norp 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 norp design and future norp versions will provide configuration options for this type of deployment.

2.2. NORM Protocol Usage

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.

3. Usage

Typically, norp 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 norp usage:

norp [interface <ifaceName>][address <publicAddr>][sport <socksPort>][port <norpPort>]
+   norp User's Guide

norp User's Guide

Abstract

The NRL Nack-Oriented Proxy (norp) 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 norp proxy instances. The norp proxy automatically supports conventional SOCKS TCP proxy operation when a remote norp peer is unavailable. This software was developed by the Naval Research Laboratory (NRL) PROTocol Engineering Advanced Networking Research Group. The NRL reference implementation of NORM used here is available from http://www.nrl.navy.mil/itd/ncs/products/norm.


1. Overview

The norp application ....

2. Theory of Operation

The norp 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 norp implementation does not require (or support) any client authentication. Future versions may provide authentication or other access control mechanisms. The current norp implementation only provides NORM transport for the SOCKS TCP "CONNECT" requests. SOCKS "UDP-ASSOCIATE" over NORM will be supported in a future version.

Unlike a conventional SOCKS server, it is expected that the norp 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 norp daemon implements its own signaling protocol that will automatically determine, upon TCP (or UDP) connection establishment, if a remote destination is also similarly "norp-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-norp" hosts is also supported. Figure 1, “NORP Concept of Operation” illustrates this high level concept of operation.

Figure 1. NORP Concept of Operation

NORP Concept of Operation


TBD - provide some more details on norp signaling for peer detection and NORM session establishment

Note that as an alternative to making proxied connections directly to connection destination addresses as illustrated above, a remote norp peer "correspondent" can be specified as part of the forward command or, for SOCKS connections, with the correspondent command (see command descriptions below). Future versions of norp will include more sophisticated "routing" options for different destinations and traffic types.

2.1. SOCKS Loopback and Intermediate System

As noted above the principal use case for norp 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 norp peers (or non-norp hosts) is required other than using a common UDP port number for NORP signaling.

However, there may be use cases where it may be desirable to deploy norp 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 norp design and future norp versions will provide configuration options for this type of deployment.

2.2. NORM Protocol Usage

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.

3. Usage

Typically, norp 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 norp usage:

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>]

The norp program command-line options include ...

Table 1. norp Command-line Options

interface <interfaceName>The given <interfaceName> specifies the name (or IP address) of the host network interface norp uses as its "public" proxy address. Currently a single interface may be designated for an instance of norp. Future version of norp may allow for multiple interfaces to be designated depending upon the source and/or destination address of SOCKS proxy connections.
address <publicAddr>This is similar to the "interface" 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.
sport <socksPort>This command is used to specify the port number on which the norp server listens for SOCKS client connections. The default port is currently port number 7000.
port <norpPort>This command is used to specify the UDP port number used for norp session setup signaling. The default norp UDP signaling port is 7001. The configured norp port number (and NORM port number) MUST be unblocked by any network firewalls between norp peers. The given port number is used by norp to listen for remote connection request and is used as the destination port to signal remote norp peers.
norm {on | off}By default, norp 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 "off" argument will disable this function and norp will act as a conventional SOCKS proxy server.
id <normId>By default, norp 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 norp unicast proxy connections.
nport <normPort>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 norp is 7002. The configured NORM port number (and norp UDP signaling port number) MUST be unblocked by any network firewalls between norp peers.
cceThis 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 norp peers using the NORM-CCE option MUST be configured for ECN packet marking in response to congestion.
cclThis 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.
rate <bits/sec>This option causes norp 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. a priori known) flows. At this time, one common transmission rate is used for all flows.
limit <bits/sec>This option sets a limit for the cumulative transmit rate for all flows that norp 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 <bits/sec> / <numFlows>. 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 a priori 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.
correspondent <remoteNorpAddr>This option causes norp to "route" connections through a norp peer at the specified <remoteNorpAddr>. This is an alternative to the default behavior where norp attempts to connect directly to the connection destination addresses.
persist <seconds>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).
forward <tcpPort>,<dstAddr>/<dstPort>[,<norpAddr>]This command sets up a "preset" TCP proxy (non-SOCKS) port forwarding session by listening on the specified TCP <tcpPort> for connections and then connecting to the given remote <dstAddr>/<dstPort>. Optionally, a separate remote <norpAddr> may be given. Otherwise, a norp proxy connection is attempted to the given <dstAddr> platform on the norp <port> (or <rport> 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.
debug <debugLevel>
This command can be used to control the verbosity of norp debug logging output. Generally, the range of the value is 0-12. A higher value results in more verbose, detailed debug output.
traceThis command enables NORM send and receive packet trace logging.
dlog <fileName>
This command can be used to direct norp debug logging output to a given file. The default norp debug logging is to STDERR.
lport <localNorpPort>This command can enable single host, loopback testing by a having norp listen on a different port number than which it uses as the destination port for remote norp peer signaling. E.g., two norp instances on a single machine can be set up with unique <localNorpPort> values and then use the "rport" command to specify each other's destination norp port numbers.
rport <remoteNorpPort>This command is intended to be used in conjunction with the "lport" command to allow separate specification of the destination port number used for remote norp peer signaling.

3.1. SOCKS Client Configuration

TBD - provide overview and examples (for specific SOCKS clients of note such as Dante, Proxifier, etc) of SOCKS client configuration

3.2. Usage Examples

The SOCKS client(s) must be configured to use the norp server unless a preset TCP port forward is specified. For example the Dante proxy distribution (available from http://www.inet.no/dante/) has a socksify 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 /etc/socks.conf) or the SOCKS5_SERVER environment variable can be used to set the server address and port number.

The norp "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 norp SOCKS port number (i.e. 127.0.0.1:7000). The locally installed norp SOCKS server will signal remote network destinations (e.g., upon TCP connection initiation) to determine if the destination is norp-capable. If possible, it will establish a NORM-connection to the remote norp correspondent that connects to the final destination. Otherwise a direct TCP connection (or UDP relay) will be made to the remote destination.

4. The "NORP" UDP Signaling Message Format

The norp proxy uses UDP signaling to confirm presence of a remote norp 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 norp "originator" is the server associated with the SOCKS client making a request while the "correspondent" establishes connections with the remote SOCKS destination.

The following UDP payload format is used for NORP signaling:

0                   1                   2                   3 
+     [limit <bits/sec>][persist <seconds>][segment <segmentSize>]
+     [correspondent <remoteNorpAddr>][forward <tcpPort>,<destAddr>/<destPort>[,<remoteNorpAddr>]]
+     [version][debug <level>][trace][dlog <debugLog>][lport <localNorpPort>][rport <remoteNorpPort>]

The norp program command-line options include ...

Table 1. norp Command-line Options

interface <interfaceName>The given <interfaceName> specifies the name (or IP address) of the host network interface norp uses as its "public" proxy address. Currently a single interface may be designated for an instance of norp. Future version of norp may allow for multiple interfaces to be designated depending upon the source and/or destination address of SOCKS proxy connections.
address <publicAddr>This is similar to the "interface" 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.
sport <socksPort>This command is used to specify the port number on which the norp server listens for SOCKS client connections. The default port is currently port number 7000.
port <norpPort>This command is used to specify the UDP port number used for norp session setup signaling. The default norp UDP signaling port is 7001. The configured norp port number (and NORM port number) MUST be unblocked by any network firewalls between norp peers. The given port number is used by norp to listen for remote connection request and is used as the destination port to signal remote norp peers.
norm {on | off}By default, norp 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 "off" argument will disable this function and norp will act as a conventional SOCKS proxy server.
id <normId>By default, norp 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 norp unicast proxy connections.
nport <normPort>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 norp is 7002. The configured NORM port number (and norp UDP signaling port number) MUST be unblocked by any network firewalls between norp peers.
cceThis 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 norp peers using the NORM-CCE option MUST be configured for ECN packet marking in response to congestion.
cclThis 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.
rate <bits/sec>This option causes norp 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. a priori known) flows. At this time, one common transmission rate is used for all flows.
limit <bits/sec>This option sets a limit for the cumulative transmit rate for all flows that norp 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 <bits/sec> / <numFlows>. 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 a priori 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.
segment <segmentSize>This option sets the NORM protocol maximum packet payload size where is <segmentSize> is in units of bytes. . For norp that uses the NORM_OBJECT_STREAM, the maximum NORM UDP payload size is 40 bytes of NORM header plus the configured segment size. The resultant total maximum IPv4 UDP packet size (including IP and UDP headers) is then 28 + 40 + <segmentSize> bytes. For IPv6, the resultant maximum packet size is 48 + 40 + <segmentSize> bytes. The default NORM segment size, if this option is not invoked, is 1400 bytes, resulting in NORM UDP packets with 1440 byte payloads. Thus, for IPv4 that has 28 bytes of IP + UDP header, this results in a maximum norp packet size of 1468 bytes while, for IPv6, the maximum norp packet size would be 1488 bytes.
correspondent <remoteNorpAddr>This option causes norp to "route" connections through a norp peer at the specified <remoteNorpAddr>. This is an alternative to the default behavior where norp attempts to connect directly to the connection destination addresses.
persist <seconds>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).
forward <tcpPort>,<dstAddr>/<dstPort>[,<norpAddr>]This command sets up a "preset" TCP proxy (non-SOCKS) port forwarding session by listening on the specified TCP <tcpPort> for connections and then connecting to the given remote <dstAddr>/<dstPort>. Optionally, a separate remote <norpAddr> may be given. Otherwise, a norp proxy connection is attempted to the given <dstAddr> platform on the norp <port> (or <rport> 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.
debug <debugLevel>
This command can be used to control the verbosity of norp debug logging output. Generally, the range of the value is 0-12. A higher value results in more verbose, detailed debug output.
traceThis command enables NORM send and receive packet trace logging.
dlog <fileName>
This command can be used to direct norp debug logging output to a given file. The default norp debug logging is to STDERR.
lport <localNorpPort>This command can enable single host, loopback testing by a having norp listen on a different port number than which it uses as the destination port for remote norp peer signaling. E.g., two norp instances on a single machine can be set up with unique <localNorpPort> values and then use the "rport" command to specify each other's destination norp port numbers.
rport <remoteNorpPort>This command is intended to be used in conjunction with the "lport" command to allow separate specification of the destination port number used for remote norp peer signaling.

3.1. SOCKS Client Configuration

TBD - provide overview and examples (for specific SOCKS clients of note such as Dante, Proxifier, etc) of SOCKS client configuration

3.2. Usage Examples

The SOCKS client(s) must be configured to use the norp server unless a preset TCP port forward is specified. For example the Dante proxy distribution (available from http://www.inet.no/dante/) has a socksify 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 /etc/socks.conf) or the SOCKS5_SERVER environment variable can be used to set the server address and port number.

The norp "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 norp SOCKS port number (i.e. 127.0.0.1:7000). The locally installed norp SOCKS server will signal remote network destinations (e.g., upon TCP connection initiation) to determine if the destination is norp-capable. If possible, it will establish a NORM-connection to the remote norp correspondent that connects to the final destination. Otherwise a direct TCP connection (or UDP relay) will be made to the remote destination.

4. The "NORP" UDP Signaling Message Format

The norp proxy uses UDP signaling to confirm presence of a remote norp 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 norp "originator" is the server associated with the SOCKS client making a request while the "correspondent" establishes connections with the remote SOCKS destination.

The following UDP payload format is used for NORP signaling:

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           |
@@ -20,4 +20,4 @@
 |                           content ...
 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
 
-

The NORP message types include:

SOCKS_REQ

The message content contains a SOCKS5 Request message from the "originator" to the "correspondent" norp server.

ACK_REQ

The message is used to acknowledge receipt of a SOCKS_REQ message. There is no "content"

SOCKS_REP

The message content contains a SOCKS5 Reply message from the "correspondent" norp server.

ACK_REP

The message is used to acknoledge receipt of a SOCKS_REP message. There is no "content".

ORIG_END

This message indicates the "originator" norp server is terminating the given session. There is no "content".

CORR_END

This message indicates the "correspondent" norp server is terminating the given session. There is no "content".

ACK_END

This message is used to acknowledge receipt of either an ORIG_END or CORR_END message. There is no "content".

TBD - describe NORP signaling and the message format given here.

5. Future Plans

There are a number of additional features and refinements planned for the norp implementation. Some of these include:

  1. Source / destination configuration and "routing" options

  2. Data compression options

  3. Security features

\ No newline at end of file +

The NORP message types include:

SOCKS_REQ

The message content contains a SOCKS5 Request message from the "originator" to the "correspondent" norp server.

ACK_REQ

The message is used to acknowledge receipt of a SOCKS_REQ message. There is no "content"

SOCKS_REP

The message content contains a SOCKS5 Reply message from the "correspondent" norp server.

ACK_REP

The message is used to acknowledge receipt of a SOCKS_REP message. There is no "content".

ORIG_END

This message indicates the "originator" norp server is terminating the given session. There is no "content".

CORR_END

This message indicates the "correspondent" norp server is terminating the given session. There is no "content".

ACK_END

This message is used to acknowledge receipt of either an ORIG_END or CORR_END message. There is no "content".

TBD - describe NORP signaling and the message format given here.

5. Future Plans

There are a number of additional features and refinements planned for the norp implementation. Some of these include:

  1. Source / destination configuration and "routing" options

  2. Data compression options

  3. Security features

\ No newline at end of file diff --git a/norp/doc/norpUserGuide.pdf b/norp/doc/norpUserGuide.pdf index 05e2b7d9c24f259741d291a3754c4c2cf56521aa..92194976ec15fe2d5a271dca3883f73e35cef77b 100644 GIT binary patch delta 20260 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 diff --git a/norp/include/norp.h b/norp/include/norp.h index 3872131..8aa9627 100644 --- a/norp/include/norp.h +++ b/norp/include/norp.h @@ -410,6 +410,7 @@ class NorpSession : public ProtoTree::Item NormObjectHandle norm_tx_stream; NormObjectHandle norm_rx_stream; bool norm_rx_pending; + bool norm_sender_heard; 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; @@ -577,8 +578,7 @@ class Norp 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);} + bool SendMessage(const NorpMsg& msg, const ProtoAddress& dstAddr); void OnNorpSocketEvent(ProtoSocket& theSocket, ProtoSocket::Event theEvent); diff --git a/norp/include/norpVersion.h b/norp/include/norpVersion.h index cd8aefc..1478446 100644 --- a/norp/include/norpVersion.h +++ b/norp/include/norpVersion.h @@ -1,3 +1,3 @@ #ifndef _NORP_VERSION -#define NORP_VERSION "0.1b6" +#define NORP_VERSION "0.1b8" #endif // NORP_VERSION diff --git a/norp/makefiles/Makefile.linux b/norp/makefiles/Makefile.linux index bc2ec0b..8bb6e5a 100644 --- a/norp/makefiles/Makefile.linux +++ b/norp/makefiles/Makefile.linux @@ -15,7 +15,9 @@ 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 +PROTO_CFLAGS = -DLINUX -DECN_SUPPORT -DHAVE_IPV6 -DHAVE_GETLOGIN -D_FILE_OFFSET_BITS=64 -DHAVE_LOCKF \ + -DHAVE_OLD_SIGNALHANDLER -DHAVE_DIRFD -DHAVE_ASSERT -DNO_SCM_RIGHTS -DHAVE_SCHED -DUNIX \ + -DUSE_SELECT -DUSE_TIMERFD -DUSE_EVENTFD -DHAVE_PSELECT SYSTEM = linux CC = g++ diff --git a/norp/makefiles/win32/norp.sln b/norp/makefiles/win32/norp.sln new file mode 100644 index 0000000..d18d3c7 --- /dev/null +++ b/norp/makefiles/win32/norp.sln @@ -0,0 +1,78 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio Express 2013 for Windows Desktop +VisualStudioVersion = 12.0.30723.0 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "norp", "norp.vcxproj", "{C0E6D0C8-02F8-4727-AD71-E90751C0754F}" + ProjectSection(ProjectDependencies) = postProject + {D7B0023C-8798-4918-8DA0-05C9054D70B9} = {D7B0023C-8798-4918-8DA0-05C9054D70B9} + {DE94F096-A09B-44B6-8EFE-C7BF1F65C4C9} = {DE94F096-A09B-44B6-8EFE-C7BF1F65C4C9} + EndProjectSection +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{718EBD7D-202A-4A44-8F6D-203B5EAF0765}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "NormLib", "..\..\norm\makefiles\win32\NormLib.vcxproj", "{D7B0023C-8798-4918-8DA0-05C9054D70B9}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Protokit", "..\..\norm\protolib\makefiles\win32\Protokit.vcxproj", "{DE94F096-A09B-44B6-8EFE-C7BF1F65C4C9}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Mixed Platforms = Debug|Mixed Platforms + Debug|Win32 = Debug|Win32 + Debug|x64 = Debug|x64 + Debug|x86 = Debug|x86 + Release|Mixed Platforms = Release|Mixed Platforms + Release|Win32 = Release|Win32 + Release|x64 = Release|x64 + Release|x86 = Release|x86 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {C0E6D0C8-02F8-4727-AD71-E90751C0754F}.Debug|Mixed Platforms.ActiveCfg = Debug|Win32 + {C0E6D0C8-02F8-4727-AD71-E90751C0754F}.Debug|Mixed Platforms.Build.0 = Debug|Win32 + {C0E6D0C8-02F8-4727-AD71-E90751C0754F}.Debug|Win32.ActiveCfg = Debug|Win32 + {C0E6D0C8-02F8-4727-AD71-E90751C0754F}.Debug|Win32.Build.0 = Debug|Win32 + {C0E6D0C8-02F8-4727-AD71-E90751C0754F}.Debug|x64.ActiveCfg = Debug|Win32 + {C0E6D0C8-02F8-4727-AD71-E90751C0754F}.Debug|x86.ActiveCfg = Debug|Win32 + {C0E6D0C8-02F8-4727-AD71-E90751C0754F}.Debug|x86.Build.0 = Debug|Win32 + {C0E6D0C8-02F8-4727-AD71-E90751C0754F}.Release|Mixed Platforms.ActiveCfg = Release|Win32 + {C0E6D0C8-02F8-4727-AD71-E90751C0754F}.Release|Mixed Platforms.Build.0 = Release|Win32 + {C0E6D0C8-02F8-4727-AD71-E90751C0754F}.Release|Win32.ActiveCfg = Release|Win32 + {C0E6D0C8-02F8-4727-AD71-E90751C0754F}.Release|Win32.Build.0 = Release|Win32 + {C0E6D0C8-02F8-4727-AD71-E90751C0754F}.Release|x64.ActiveCfg = Release|Win32 + {C0E6D0C8-02F8-4727-AD71-E90751C0754F}.Release|x86.ActiveCfg = Release|Win32 + {C0E6D0C8-02F8-4727-AD71-E90751C0754F}.Release|x86.Build.0 = Release|Win32 + {D7B0023C-8798-4918-8DA0-05C9054D70B9}.Debug|Mixed Platforms.ActiveCfg = Debug|Win32 + {D7B0023C-8798-4918-8DA0-05C9054D70B9}.Debug|Mixed Platforms.Build.0 = Debug|Win32 + {D7B0023C-8798-4918-8DA0-05C9054D70B9}.Debug|Win32.ActiveCfg = Debug|Win32 + {D7B0023C-8798-4918-8DA0-05C9054D70B9}.Debug|Win32.Build.0 = Debug|Win32 + {D7B0023C-8798-4918-8DA0-05C9054D70B9}.Debug|x64.ActiveCfg = Debug|Win32 + {D7B0023C-8798-4918-8DA0-05C9054D70B9}.Debug|x86.ActiveCfg = Debug|Win32 + {D7B0023C-8798-4918-8DA0-05C9054D70B9}.Debug|x86.Build.0 = Debug|Win32 + {D7B0023C-8798-4918-8DA0-05C9054D70B9}.Release|Mixed Platforms.ActiveCfg = Release|Win32 + {D7B0023C-8798-4918-8DA0-05C9054D70B9}.Release|Mixed Platforms.Build.0 = Release|Win32 + {D7B0023C-8798-4918-8DA0-05C9054D70B9}.Release|Win32.ActiveCfg = Release|Win32 + {D7B0023C-8798-4918-8DA0-05C9054D70B9}.Release|Win32.Build.0 = Release|Win32 + {D7B0023C-8798-4918-8DA0-05C9054D70B9}.Release|x64.ActiveCfg = Release|Win32 + {D7B0023C-8798-4918-8DA0-05C9054D70B9}.Release|x86.ActiveCfg = Release|Win32 + {D7B0023C-8798-4918-8DA0-05C9054D70B9}.Release|x86.Build.0 = Release|Win32 + {DE94F096-A09B-44B6-8EFE-C7BF1F65C4C9}.Debug|Mixed Platforms.ActiveCfg = Debug|Win32 + {DE94F096-A09B-44B6-8EFE-C7BF1F65C4C9}.Debug|Mixed Platforms.Build.0 = Debug|Win32 + {DE94F096-A09B-44B6-8EFE-C7BF1F65C4C9}.Debug|Win32.ActiveCfg = Debug|Win32 + {DE94F096-A09B-44B6-8EFE-C7BF1F65C4C9}.Debug|Win32.Build.0 = Debug|Win32 + {DE94F096-A09B-44B6-8EFE-C7BF1F65C4C9}.Debug|x64.ActiveCfg = Debug|x64 + {DE94F096-A09B-44B6-8EFE-C7BF1F65C4C9}.Debug|x64.Build.0 = Debug|x64 + {DE94F096-A09B-44B6-8EFE-C7BF1F65C4C9}.Debug|x86.ActiveCfg = Debug|Win32 + {DE94F096-A09B-44B6-8EFE-C7BF1F65C4C9}.Debug|x86.Build.0 = Debug|Win32 + {DE94F096-A09B-44B6-8EFE-C7BF1F65C4C9}.Release|Mixed Platforms.ActiveCfg = Release|Win32 + {DE94F096-A09B-44B6-8EFE-C7BF1F65C4C9}.Release|Mixed Platforms.Build.0 = Release|Win32 + {DE94F096-A09B-44B6-8EFE-C7BF1F65C4C9}.Release|Win32.ActiveCfg = Release|Win32 + {DE94F096-A09B-44B6-8EFE-C7BF1F65C4C9}.Release|Win32.Build.0 = Release|Win32 + {DE94F096-A09B-44B6-8EFE-C7BF1F65C4C9}.Release|x64.ActiveCfg = Release|x64 + {DE94F096-A09B-44B6-8EFE-C7BF1F65C4C9}.Release|x64.Build.0 = Release|x64 + {DE94F096-A09B-44B6-8EFE-C7BF1F65C4C9}.Release|x86.ActiveCfg = Release|Win32 + {DE94F096-A09B-44B6-8EFE-C7BF1F65C4C9}.Release|x86.Build.0 = Release|Win32 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection +EndGlobal diff --git a/norp/makefiles/win32/norp.vcxproj b/norp/makefiles/win32/norp.vcxproj new file mode 100644 index 0000000..02bbaec --- /dev/null +++ b/norp/makefiles/win32/norp.vcxproj @@ -0,0 +1,114 @@ + + + + + Debug + Win32 + + + Release + Win32 + + + + + + + C:\Users\rhodysn1\NORP Code\norm\protolib\include;C:\Users\rhodysn1\NORP Code\norm\include;%(AdditionalIncludeDirectories) + + + + + + + + + + + {d7b0023c-8798-4918-8da0-05c9054d70b9} + + + {de94f096-a09b-44b6-8efe-c7bf1f65c4c9} + + + + {C0E6D0C8-02F8-4727-AD71-E90751C0754F} + Win32Proj + + + + Application + true + v120 + MultiByte + + + Application + false + v120 + + + + + + + + + + + + + + + false + + + false + + + + _DEBUG;PROTO_DEBUG;HAVE_IPV6;HAVE_ASSERT;WIN32;_CRT_SECURE_NO_WARNINGS;_CONSOLE;%(PreprocessorDefinitions) + MultiThreadedDebugDLL + Level3 + ProgramDatabase + Disabled + ..\..\include;..\..\norm\include;..\..\norm\protolib\include;%(AdditionalIncludeDirectories) + + + MachineX86 + true + Console + ..\..\include\;%(AdditionalLibraryDirectories) + iphlpapi.lib;ws2_32.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies) + false + MSVCRT;%(IgnoreSpecificDefaultLibraries) + + + + + + + PROTO_DEBUG;HAVE_IPV6;HAVE_ASSERT;WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + MultiThreadedDLL + Level3 + ProgramDatabase + ..\..\include;..\..\norm\include;..\..\norm\protolib\include;%(AdditionalIncludeDirectories) + + + MachineX86 + true + Console + true + true + ..\..\include\;%(AdditionalLibraryDirectories) + iphlpapi.lib;ws2_32.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies) + + + + true + + + + + + \ No newline at end of file diff --git a/norp/src/common/norp.cpp b/norp/src/common/norp.cpp index 16ee4ba..2579232 100644 --- a/norp/src/common/norp.cpp +++ b/norp/src/common/norp.cpp @@ -11,6 +11,9 @@ // configured to use a specific set of port // numbers for NORM traffic. +// Uncomment this to enable new NORM port handling to improve NAT compatibility +#define NEW_PORT + PortPool::PortPool(UINT16 basePort) : base_port(basePort) { @@ -61,7 +64,7 @@ NorpSession::NorpSession(Norp& theController, UINT16 sessionId, NormNodeId origi client_pending(0), client_index(0), remote_pending(0), remote_index(0), norm_enable(true), norp_tx_socket(ProtoSocket::UDP), norp_rtt_estimate(NORP_RTT_DEFAULT), norm_session(NORM_SESSION_INVALID), norm_tx_stream(NORM_OBJECT_INVALID), - norm_rx_stream(NORM_OBJECT_INVALID), norm_rx_pending(false), + norm_rx_stream(NORM_OBJECT_INVALID), norm_rx_pending(false), norm_sender_heard(false), persist_interval(Norp::DEFAULT_PERSIST_INTERVAL), persist_start_time(0, 0), norm_rate_min(-1.0), norm_rate_max(-1.0), norm_segment_size(0), norm_stream_buffer_max(0), norm_stream_buffer_count(0), @@ -357,7 +360,7 @@ void NorpSession::OnSocksClientEvent(ProtoSocket& theSocket, // do a recv() - probably means client disconnected (prematurely) if (theSocket.Recv((char*)client_buffer, numBytes)) { - if (SOCKS_SHUTDOWN != socks_state) + if ((SOCKS_SHUTDOWN != socks_state) && (0 != numBytes)) PLOG(PL_WARN, "NorpSession::OnSocksClientEvent() warning: unexpectedly received %u bytes from SOCKS client!\n", numBytes); } else @@ -686,7 +689,16 @@ bool NorpSession::PutRemoteRequest(const ProtoPktSOCKS::Request& request, const // request command, etc. if (NORM_SESSION_INVALID == norm_session) { + // This creates the client-side NORM session for a connection. + // (TBD) Create single-socket NORM session using an ephemeral port and connect() to the remote + // NORP server NORM port. (Use NormChangeDestination() after NormStartReceiver() to + // configure this newly-create NormSession as needed) +#ifdef NEW_PORT + // We use port zero to get session that will bound to an ephemeral port (single port for tx and rx) upon NormStartReceiver + norm_session = NormCreateSession(controller.GetNormInstance(), remoteAddr.GetHostString(), 0, controller.GetNormNodeId()); +#else norm_session = NormCreateSession(controller.GetNormInstance(), remoteAddr.GetHostString(), controller.GetNormPort(), controller.GetNormNodeId()); +#endif if (NORM_SESSION_INVALID == norm_session) { PLOG(PL_ERROR, "NorpSession::PutRemoteRequest() NormCreateSession() failure!\n"); @@ -744,6 +756,10 @@ bool NorpSession::PutRemoteRequest(const ProtoPktSOCKS::Request& request, const PLOG(PL_ERROR, "NorpSession::PutRemoteRequest() error: NormStartSender() failure!\n"); return false; } +#ifdef NEW_PORT + // Now call NormChangeDestination() to set proper destination port and "connect" to it + NormChangeDestination(norm_session, remoteAddr.GetHostString(), controller.GetNormPort(), true); +#endif // NEW_PORT //NormSetTxSocketBuffer(norm_session, 4096); NormSetFlowControl(norm_session, 0.0); // disable timer-based flow control since we are ACK-limiting writes to stream norm_segment_size = controller.GetNormSegmentSize(); @@ -797,6 +813,7 @@ bool NorpSession::PutRemoteRequest(const ProtoPktSOCKS::Request& request, const bool NorpSession::MakeDirectConnect() { + TRACE("MAKING DIRECT CONNECTION ..."); // This assumes our "norp_msg" previously sent in attempt to connect // to a remote "norp" peer is cached (per PutRemoveRequest() if (NORM_SESSION_INVALID != norm_session) @@ -974,6 +991,9 @@ bool NorpSession::OnRemoteRequest(const NorpMsg& theMsg, const ProtoAddress& sen // 1) Create a NormSession with request sender as session (destination) address UINT16 normSessionPort = controller.GetNormPort(); norm_session = NormCreateSession(controller.GetNormInstance(), senderAddr.GetHostString(), normSessionPort, controller.GetNormNodeId()); +#ifdef NEW_PORT + NormSetTxPort(norm_session, normSessionPort); // single port +#endif // NEW_PORT if (NORM_SESSION_INVALID == norm_session) { PLOG(PL_ERROR, "NorpSession::OnRemoteRequest() NormCreateSession() failure!\n"); @@ -1016,7 +1036,11 @@ bool NorpSession::OnRemoteRequest(const NorpMsg& theMsg, const ProtoAddress& sen NormSetTxRateBounds(norm_session, norm_rate_min, norm_rate_max); // The "NormSetRxPortReuse()" call here "connects" us to the remote NORM sender source addr/port // (this creates a proper binding since we reuse the same port number for multiple NORM sessions) +#ifdef NEW_PORT + NormSetRxPortReuse(norm_session, true); // defer connecting to remote sender until to REMOTE_SENDER_NEW to get correct port +#else NormSetRxPortReuse(norm_session, true, NULL, senderAddr.GetHostString(), theMsg.GetSourcePort()); +#endif // if/else NEW_PORT if (!NormStartReceiver(norm_session, NORM_BUFFER_SIZE)) { PLOG(PL_ERROR, "NorpSession::OnRemoteRequest() error: NormStartReceiver() failure!\n"); @@ -1176,7 +1200,7 @@ bool NorpSession::OnRemoteReplyAcknowledgment(const NorpMsg& theMsg) } else { - ASSERT(norp_rtt_estimate > 0.0); + ASSERT(norp_rtt_estimate > 0.0); // Only use duplicative ACKs to update RTT estimate via EWMA double rttNew = ProtoTime::Delta(recvTime, sentTime); norp_rtt_estimate = 0.5*(norp_rtt_estimate + rttNew); // TBD - is this a reasonable "smoothing" factor @@ -1204,8 +1228,8 @@ bool NorpSession::ConnectToRemote(const ProtoAddress& destAddr) return false; } ASSERT(!socks_remote_socket.IsConnected()); // TBD - handle immediate connection case??? - PLOG(PL_DETAIL, "NorpSession::ConnectToRemote() connection to %s/%hu initiated ...\n", - destAddr.GetHostString(), destAddr.GetPort()); + PLOG(PL_DETAIL, "NorpSession::ConnectToRemote() connection to %s/%hu initiated (connected:%d)...\n", + destAddr.GetHostString(), destAddr.GetPort(), socks_remote_socket.IsConnected()); if (socks_client_socket.IsOpen()) socks_client_socket.StopInputNotification(); // don't accept more from client until connected socks_state = SOCKS_CONNECTING; @@ -1266,9 +1290,9 @@ bool NorpSession::OpenUdpRelay() // We use the bind (local source) addr of our client socket as the SOCKS reply BIND.ADDR // and the port number of our udp relay socket as the SOCKS reply BIND.PORT ProtoAddress bindAddr = socks_client_socket.GetSourceAddr(); - PLOG(PL_INFO, "udp relay bind addr = %s/%hu\n", bindAddr.GetHostString(), bindAddr.GetPort()); bindAddr.SetPort(udp_relay_socket.GetPort()); reply.SetAddress(bindAddr); + PLOG(PL_INFO, "udp relay bind addr = %s/%hu\n", bindAddr.GetHostString(), bindAddr.GetPort()); remote_pending = reply.GetLength(); remote_index = 0; socks_state = SOCKS_PUT_REPLY; @@ -1350,13 +1374,15 @@ bool NorpSession::GetClientData() ASSERT(0 == client_pending); if (socks_client_socket.Recv((char*)client_buffer, numBytes)) { - socks_client_socket.StopInputNotification(); - client_pending = numBytes; - client_index = 0; - PLOG(PL_DETAIL, "NorpSession::GetClientData() originator read %lu bytes from SOCKS client ...\n", numBytes); - if (0 != numBytes) - return PutRemoteData(); - // else socket will disconnect itself + client_pending = numBytes; + client_index = 0; + if (0 != numBytes) + { + PLOG(PL_DETAIL, "NorpSession::GetClientData() originator read %lu bytes from SOCKS client ...\n", numBytes); + socks_client_socket.StopInputNotification(); + return PutRemoteData(); + } + // else socket will close itself when appropriate } else { @@ -1552,7 +1578,15 @@ void NorpSession::OnSocksRemoteEvent(ProtoSocket& theSocket, case ProtoSocket::SEND: PLOG(PL_DETAIL, "SEND) ...\n"); // write pending data from client_buffer to remote - if (!PutRemoteData()) + if (SOCKS_PUT_REPLY == socks_state) + { + if (!PutRemoteReply()) + { + PLOG(PL_ERROR, "NorpSession::OnSocksRemoteEvent() error: PutRemoteReply() failure!\n"); + Shutdown(); + } + } + else if (!PutRemoteData()) { PLOG(PL_ERROR, "NorpSession::OnSocksRemoteEvent() error: PutRemoteData() failure!\n"); Shutdown(); @@ -1649,11 +1683,14 @@ bool NorpSession::GetRemoteData() ASSERT(0 == remote_pending); if (socks_remote_socket.Recv((char*)remote_buffer, numBytes)) { - remote_pending = numBytes; - remote_index = 0; - socks_remote_socket.StopInputNotification(); - if (0 != numBytes) - return PutClientData(); + remote_pending = numBytes; + remote_index = 0; + if (0 != numBytes) + { + PLOG(PL_DETAIL, "NorpSession::GetClientData() originator read %lu bytes from remote ...\n", numBytes); + socks_remote_socket.StopInputNotification(); + return PutClientData(); + } // else socket will disconnect itself and session will close } else @@ -1732,7 +1769,7 @@ bool NorpSession::PutRemoteData() } else { - ASSERT(SOCKS_SHUTDOWN == socks_state); + ASSERT(SOCKS_SHUTDOWN == socks_state); if (socks_remote_socket.IsConnected()) { socks_remote_socket.Shutdown(); @@ -1774,7 +1811,7 @@ void NorpSession::OnUdpRelayEvent(ProtoSocket& theSocket, { PLOG(PL_ERROR, "NorpSession::OnUdpRelayEvent() received fragmented packet from client!" " (fragmentation not yet supported.)\n"); - numBytes = (8192 - 22); + numBytes = (8192 - 22); // reset "numBytes" continue; // get next packet } ProtoAddress dstAddr; @@ -1784,12 +1821,22 @@ void NorpSession::OnUdpRelayEvent(ProtoSocket& theSocket, numBytes = 8192; continue; // get next packet } + // TBD - for NORM relaying we need to establish a new child NorpSession to hand + // the packet stream off to for each unique UDP destination. Since UDP is + // connectionless, we will need to have some rules of motion regarding + // timeout, etc of the child session? We will have to buffer incoming UDP + // packets while the child NorpSession is being setup. We could use the new + // NormSocket APIs to signal setup with a SOCKS handshake relayed in-band + // at the NORM connection startup .... + + // Relay the packet (TBD - add buffering, etc?) - if (!udp_relay_socket.SendTo(udpReq.GetDataPtr(), udpReq.GetDataLength(), dstAddr)) + unsigned int bytesSent = udpReq.GetDataLength(); + if (!udp_relay_socket.SendTo(udpReq.GetDataPtr(), bytesSent, dstAddr) || (0 == bytesSent)) { PLOG(PL_ERROR, "NorpSession::OnUdpRelayEvent() error: unable to send packet to %s/%hu!\n", dstAddr.GetHostString(), dstAddr.GetPort()); - numBytes = (8192 - 22); + numBytes = (8192 - 22); // reset "numBytes" continue; // get next packet } } @@ -1810,7 +1857,8 @@ void NorpSession::OnUdpRelayEvent(ProtoSocket& theSocket, udpReq.SetAddress(srcAddr); udpReq.SetDataLength(numBytes); // Send to client - if (!udp_relay_socket.SendTo(reqPtr, udpReq.GetLength(), udp_client_addr)) + unsigned int bytesSent = udpReq.GetLength(); + if (!udp_relay_socket.SendTo(reqPtr, bytesSent, udp_client_addr) || (0 == bytesSent)) { PLOG(PL_ERROR, "NorpSession::OnUdpRelayEvent() error: unable to relay inbound packet to %s/%hu!\n", udp_client_addr.GetHostString(), udp_client_addr.GetPort()); @@ -1916,8 +1964,8 @@ void NorpSession::FlushNormStream(bool eom, NormFlushMode flushMode) if (!norm_watermark_pending && (norm_stream_buffer_count >= (norm_stream_buffer_max >> 1))) { //TRACE("NorpSession::FlushNormStream() initiating watermark ACK request (buffer count:%lu max:%lu usage:%u)...\n", - // norm_stream_buffer_count, norm_stream_buffer_max); - NormSetWatermark(norm_session, norm_tx_stream, NormStreamGetBufferUsage(norm_tx_stream)); + // norm_stream_buffer_count, norm_stream_buffer_max, NormStreamGetBufferUsage(norm_tx_stream)); + NormSetWatermark(norm_session, norm_tx_stream, true); norm_watermark_pending = true; } } @@ -1948,18 +1996,18 @@ bool NorpSession::OnNorpMsgTimeout(ProtoTimer& theTimer) switch (socks_state) { case SOCKS_PUT_REQUEST: - if (!MakeDirectConnect()) + if (!MakeDirectConnect()) { PLOG(PL_ERROR, "NorpSession::OnNorpMsgTimeout() error: also unable to make direct TCP connection\n"); Shutdown(); } - return false; // MakeDirectConnect() kills timer + return false; // MakeDirectConnect() kills timer break; case SOCKS_PUT_REPLY: - Shutdown(); + Shutdown(); break; case SOCKS_SHUTDOWN: - Close(); + Close(); return false; default: ASSERT(0); // shouldn't be messaging in any other states @@ -2092,8 +2140,36 @@ void NorpSession::OnNormEvent(NormEvent& theEvent) PLOG(PL_DETAIL, "NORM_LOCAL_SENDER_CLOSED)\n"); break; case NORM_REMOTE_SENDER_NEW: + { PLOG(PL_DETAIL, "NORM_REMOTE_SENDER_NEW)\n"); + char addrBuffer[16]; + unsigned int addrLen = 16; + UINT16 sndrPort; + NormNodeGetAddress(theEvent.sender, addrBuffer, &addrLen, &sndrPort); + ProtoAddress sndrAddr; + switch (addrLen) + { + case 4: + sndrAddr.SetRawHostAddress(ProtoAddress::IPv4, addrBuffer, 4); + break; + case 16: + sndrAddr.SetRawHostAddress(ProtoAddress::IPv6, addrBuffer, 16); + break; + default: + TRACE("invalid remote sender address ?!\n"); + break; + } +#ifdef NEW_PORT + TRACE("new remote sender address %s/%hu (orig:%d) ...\n", sndrAddr.GetHostString(), sndrPort, IsRemoteOriginator()); + if (!IsRemoteOriginator() && !norm_sender_heard) + { + NormChangeDestination(theEvent.session, sndrAddr.GetHostString(), sndrPort, true); + norm_sender_heard = true; + //NormSetRxPortReuse(theEvent.session, true, NULL, sndrAddr.GetHostString(), sndrPort); + } +#endif // NEW_PORT break; + } case NORM_REMOTE_SENDER_ACTIVE: PLOG(PL_DETAIL, "NORM_REMOTE_SENDER_ACTIVE)\n"); break; @@ -2195,6 +2271,11 @@ void NorpSession::OnNormEvent(NormEvent& theEvent) norm_rx_pending = false; if (ShutdownComplete()) Close(); break; + case NORM_SEND_ERROR: + PLOG(PL_ERROR, "NorpSession::OnNormEvent(NORM_SEND_ERROR) error ...\n");//: remote session unexpectedly closed!\n"); + Close(); + break; + case NORM_RX_OBJECT_ABORTED: PLOG(PL_DETAIL, "NORM_RX_OBJECT_ABORTED)\n"); break; @@ -2303,6 +2384,25 @@ Norp::~Norp() StopServer(); } +bool Norp::SendMessage(const NorpMsg& msg, const ProtoAddress& dstAddr) +{ + unsigned int numBytes = msg.GetLength(); + if (norp_rx_socket.SendTo((const char*)msg.GetBuffer(), numBytes, dstAddr)) + { + if (0 == numBytes) + { + PLOG(PL_WARN, "Norp::SendMessage() norp_rx_socket.SendTo() error: %s\n", GetErrorString()); + return false; + } + } + else + { + PLOG(PL_ERROR, "Norp::SendMessage() norp_rx_socket.SendTo() error: %s\n", GetErrorString()); + return false; + } + return true; +} // end Norp::SendMessage() + bool Norp::StartServer(bool normEnable) { if (!socks_server_socket.Listen(socks_port)) @@ -2461,7 +2561,7 @@ void Norp::RemoveSession(NorpSession& session) { session_list.Remove(session); session_count--; - if (norm_tx_limit >= 0.0) + if ((session_count > 0) && (norm_tx_limit >= 0.0)) { double lowerLimit = 0.9 * (norm_tx_limit / (double)session_count); NorpSessionList::Iterator iterator(session_list); @@ -2683,7 +2783,7 @@ void Norp::OnNormEvent() { PLOG(PL_DETAIL, "Norp::OnNormEvent("); // See if this event is for a "child" NorpSession - if (NORM_SESSION_INVALID != theEvent.session) + if (NORM_SESSION_INVALID != theEvent.session) { NorpSession* norpSession = (NorpSession*)NormGetUserData(theEvent.session); if (NULL != norpSession)