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
: ns-3
internet-stack
: ns-3-dev
: All All
: P1 blocker
Assigned To:
:
:
:
:
  Show dependency treegraph
 
Reported: 2009-06-29 00:19 EDT by
Modified: 2009-10-07 23:11 EDT (History)


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 From 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 From 2009-06-29 00:22:10 EDT -------
Created an attachment (id=504) [details]
testcase
------- Comment #2 From 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 From 2009-09-28 15:58:40 EDT -------
Created an attachment (id=605) [details]
testcase 2 (with packet sink)
------- Comment #4 From 2009-09-30 12:27:30 EDT -------
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?
------- Comment #5 From 2009-10-07 00:31:36 EDT -------
(In reply to comment #4)
> Created an attachment (id=609) [details] [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 From 2009-10-07 11:23:55 EDT -------
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.

So I guess if this is the case, then I propose the attached patch.  
------- Comment #7 From 2009-10-07 12:29:23 EDT -------
(In reply to comment #6)
> Created an attachment (id=622) [details] [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 From 2009-10-07 23:11:33 EDT -------
changeset 3a8177ed2dda