Bug 615 - TCP does not respond with RST to non-listening port
TCP does not respond with RST to non-listening port
Status: RESOLVED FIXED
Product: ns-3
Classification: Unclassified
Component: internet
ns-3-dev
All All
: P1 blocker
Assigned To: George Riley
:
Depends on:
Blocks:
  Show dependency treegraph
 
Reported: 2009-06-29 00:19 EDT by Tom Henderson
Modified: 2009-10-07 23:11 EDT (History)
2 users (show)

See Also:


Attachments
testcase (2.50 KB, text/x-c++src)
2009-06-29 00:22 EDT, Tom Henderson
Details
testcase 2 (with packet sink) (2.79 KB, text/x-c++src)
2009-09-28 15:58 EDT, Josh Pelkey
Details
Possible patch for bug 615 (1.54 KB, patch)
2009-09-30 12:27 EDT, Josh Pelkey
Details | Diff
Patch with RX_ENDPOINT_CLOSED (2.41 KB, patch)
2009-10-07 11:23 EDT, Josh Pelkey
Details | Diff

Note You need to log in before you can comment on or make changes to this bug.
Description Tom Henderson 2009-06-29 00:19:33 EDT
ns-3's TCP should send RST to a SYN sent to a non-listening port.  For instance, this test case using ns-3 TCP produces:

tcpdump -r tcp-nonlistening-server-0-0.pcap -nn -tt
reading from file tcp-nonlistening-server-0-0.pcap, link-type PPP (PPP)
1.000000 IP 10.1.1.1.49153 > 10.1.1.2.500: S 0:0(0) win 65535
1.020080 IP 10.1.1.2 > 10.1.1.1: ICMP 10.1.1.2 tcp port 500 unreachable, length 36
4.000000 IP 10.1.1.1.49153 > 10.1.1.2.500: S 0:0(0) win 65535
4.020080 IP 10.1.1.2 > 10.1.1.1: ICMP 10.1.1.2 tcp port 500 unreachable, length 36

while, if NSC is used, produces:
 tcpdump -r tcp-nonlistening-server-0-0.pcap -nn -tt
reading from file tcp-nonlistening-server-0-0.pcap, link-type PPP (PPP)
1.000000 IP 10.1.1.1.35283 > 10.1.1.2.500: S 26342578:26342578(0) win 5840 <mss 1460,sackOK,timestamp 1000 0,nop,wscale 5>
1.020083 IP 10.1.1.2.500 > 10.1.1.1.35283: R 0:0(0) ack 26342579 win 0
Comment 1 Tom Henderson 2009-06-29 00:22:10 EDT
Created attachment 504 [details]
testcase
Comment 2 Josh Pelkey 2009-09-28 15:58:03 EDT
It looks like TcpL4Protocol::Receive is doing this.  Line 505 in src/internet-stack/tcp-l4-protocol.cc:  if (endPoints.empty ())...

The packet won't get forwarded up, so TcpSocketImpl can't look and see if it's a SYN and send out a RST.  I'm not sure if this is the correct behavior, or if it should be handled in TcpL4Protocol.  I just thought I'd point out where I think the logic is diverging when a packet comes in with a port that isn't listening.

Also, the example testcase posted doesn't have a TCP sink or anything like I'm used to seeing.  I'm not sure if this will affect the behavior in the end when a fix is posted.  I've added an attachment with a packet sink on node 1.  The port it uses is different than the one that the client tries to connect to.
Comment 3 Josh Pelkey 2009-09-28 15:58:40 EDT
Created attachment 605 [details]
testcase 2 (with packet sink)
Comment 4 Josh Pelkey 2009-09-30 12:27:30 EDT
Created attachment 609 [details]
Possible patch for bug 615

(In reply to comment #0)
> ns-3's TCP should send RST to a SYN sent to a non-listening port.  For
> instance, this test case using ns-3 TCP produces:
> 
> tcpdump -r tcp-nonlistening-server-0-0.pcap -nn -tt
> reading from file tcp-nonlistening-server-0-0.pcap, link-type PPP (PPP)
> 1.000000 IP 10.1.1.1.49153 > 10.1.1.2.500: S 0:0(0) win 65535
> 1.020080 IP 10.1.1.2 > 10.1.1.1: ICMP 10.1.1.2 tcp port 500 unreachable, length
> 36
> 4.000000 IP 10.1.1.1.49153 > 10.1.1.2.500: S 0:0(0) win 65535
> 4.020080 IP 10.1.1.2 > 10.1.1.1: ICMP 10.1.1.2 tcp port 500 unreachable, length
> 36
> 
> while, if NSC is used, produces:
>  tcpdump -r tcp-nonlistening-server-0-0.pcap -nn -tt
> reading from file tcp-nonlistening-server-0-0.pcap, link-type PPP (PPP)
> 1.000000 IP 10.1.1.1.35283 > 10.1.1.2.500: S 26342578:26342578(0) win 5840 <mss
> 1460,sackOK,timestamp 1000 0,nop,wscale 5>
> 1.020083 IP 10.1.1.2.500 > 10.1.1.1.35283: R 0:0(0) ack 26342579 win 0
> 

Ok, I got this from the RFC:

    If the state is CLOSED (i.e., TCB does not exist) then

      all data in the incoming segment is discarded.  An incoming
      segment containing a RST is discarded.  An incoming segment not
      containing a RST causes a RST to be sent in response.  The
      acknowledgment and sequence field values are selected to make the
      reset sequence acceptable to the TCP that sent the offending
      segment.

      If the ACK bit is off, sequence number zero is used,

        <SEQ=0><ACK=SEG.SEQ+SEG.LEN><CTL=RST,ACK>

      If the ACK bit is on,

        <SEQ=SEG.ACK><CTL=RST>

      Return.

Attached is a patch that allows this.  The output of tcpdump is shown below:

1.010033 IP 10.1.1.1.49153 > 10.1.1.2.500: S 0:0(0) win 65535
1.010033 IP 10.1.1.2.500 > 10.1.1.1.49153: R 0:0(0) ack 1 win 65535

One thing I wasn't sure about with the patch, is the return statement for this case.  Is it ok to have RX_OK here?
Comment 5 Tom Henderson 2009-10-07 00:31:36 EDT
(In reply to comment #4)
> Created an attachment (id=609) [details]
> Possible patch for bug 615
> 
> (In reply to comment #0)
> > ns-3's TCP should send RST to a SYN sent to a non-listening port.  For
> > instance, this test case using ns-3 TCP produces:
> > 
> > tcpdump -r tcp-nonlistening-server-0-0.pcap -nn -tt
> > reading from file tcp-nonlistening-server-0-0.pcap, link-type PPP (PPP)
> > 1.000000 IP 10.1.1.1.49153 > 10.1.1.2.500: S 0:0(0) win 65535
> > 1.020080 IP 10.1.1.2 > 10.1.1.1: ICMP 10.1.1.2 tcp port 500 unreachable, length
> > 36
> > 4.000000 IP 10.1.1.1.49153 > 10.1.1.2.500: S 0:0(0) win 65535
> > 4.020080 IP 10.1.1.2 > 10.1.1.1: ICMP 10.1.1.2 tcp port 500 unreachable, length
> > 36
> > 
> > while, if NSC is used, produces:
> >  tcpdump -r tcp-nonlistening-server-0-0.pcap -nn -tt
> > reading from file tcp-nonlistening-server-0-0.pcap, link-type PPP (PPP)
> > 1.000000 IP 10.1.1.1.35283 > 10.1.1.2.500: S 26342578:26342578(0) win 5840 <mss
> > 1460,sackOK,timestamp 1000 0,nop,wscale 5>
> > 1.020083 IP 10.1.1.2.500 > 10.1.1.1.35283: R 0:0(0) ack 26342579 win 0
> > 
> 
> Ok, I got this from the RFC:
> 
>     If the state is CLOSED (i.e., TCB does not exist) then
> 
>       all data in the incoming segment is discarded.  An incoming
>       segment containing a RST is discarded.  An incoming segment not
>       containing a RST causes a RST to be sent in response.  The
>       acknowledgment and sequence field values are selected to make the
>       reset sequence acceptable to the TCP that sent the offending
>       segment.
> 
>       If the ACK bit is off, sequence number zero is used,
> 
>         <SEQ=0><ACK=SEG.SEQ+SEG.LEN><CTL=RST,ACK>
> 
>       If the ACK bit is on,
> 
>         <SEQ=SEG.ACK><CTL=RST>
> 
>       Return.
> 
> Attached is a patch that allows this.  The output of tcpdump is shown below:
> 
> 1.010033 IP 10.1.1.1.49153 > 10.1.1.2.500: S 0:0(0) win 65535
> 1.010033 IP 10.1.1.2.500 > 10.1.1.1.49153: R 0:0(0) ack 1 win 65535
> 
> One thing I wasn't sure about with the patch, is the return statement for this
> case.  Is it ok to have RX_OK here?

I would return UNREACH here also since the segment did not reach a real transport endpoint.

Otherwise, looks good to me.

> 

Comment 6 Josh Pelkey 2009-10-07 11:23:55 EDT
Created attachment 622 [details]
Patch with RX_ENDPOINT_CLOSED

(In reply to comment #5)
> I would return UNREACH here also since the segment did not reach a real
> transport endpoint.
> 
> Otherwise, looks good to me.
> 
> 

I thought that seemed more appropriate, but this will force an ICMP message based on the logic in Ipv4L3Protocol::LocalDeliver.  How about adding another constant like RX_ENDPOINT_CLOSED?

Related to this, I am unsure of whether or not an ICMP should ever be sent in response to a TCP packet.  For anything other than a RST packet, from the RFC, a RST should be sent back (what we are trying to fix in this bug).  For the other case, where a RST is sent to a closed port, the RFC just says that it's discarded (nothing about ICMP).  The reason I bring this up is because RX_ENDPOINT_UNREACH should not be returned in TcpL4Protocol if ICMP should not be sent.

So I guess if this is the case, then I propose the attached patch.
Comment 7 Tom Henderson 2009-10-07 12:29:23 EDT
(In reply to comment #6)
> Created an attachment (id=622) [details]
> Patch with RX_ENDPOINT_CLOSED
> 
> (In reply to comment #5)
> > I would return UNREACH here also since the segment did not reach a real
> > transport endpoint.
> > 
> > Otherwise, looks good to me.
> > 
> > 
> 
> I thought that seemed more appropriate, but this will force an ICMP message
> based on the logic in Ipv4L3Protocol::LocalDeliver.  How about adding another
> constant like RX_ENDPOINT_CLOSED?
> 
> Related to this, I am unsure of whether or not an ICMP should ever be sent in
> response to a TCP packet.  For anything other than a RST packet, from the RFC,
> a RST should be sent back (what we are trying to fix in this bug).  For the
> other case, where a RST is sent to a closed port, the RFC just says that it's
> discarded (nothing about ICMP).  The reason I bring this up is because
> RX_ENDPOINT_UNREACH should not be returned in TcpL4Protocol if ICMP should not
> be sent.

Yes, ICMP Port Unreachable is not sent for unwanted TCP segments.  I don't know the historical reason for this exception.  So, I agree that we do not want ICMP generated in this case, and am fine with your suggested change.

Comment 8 Josh Pelkey 2009-10-07 23:11:33 EDT
changeset 3a8177ed2dda