Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Rfc9293 WIP #202

Open
wants to merge 40 commits into
base: master
Choose a base branch
from
Open
Changes from 10 commits
Commits
Show all changes
40 commits
Select commit Hold shift + click to select a range
1113751
tcp: Remove redundant :ack-p t
ebrasca Feb 19, 2024
3b0fe68
tcp: Update the protocol specification link to rfc9293
ebrasca Feb 25, 2024
ef54dfb
tcp: Do nothing to finish segments when in state :closed or :listen
ebrasca Feb 25, 2024
c140f05
tcp: Fix errata
ebrasca Feb 25, 2024
d2c3874
tcp: Refactor acceptable-segment-p
ebrasca Feb 25, 2024
8c0a1c1
tcp: Add tcp4-send-ack
ebrasca Mar 20, 2024
e8b7f35
tcp: Add challenge-ack
ebrasca Mar 20, 2024
0e6ca64
tcp: Check the sequence numbers before accepting RST in :syn-sent
ebrasca Mar 20, 2024
bce312d
tcp: Send RST when package is from old connection in :syn-sent state
ebrasca Mar 20, 2024
fb4e215
tcp: Refactor tcp4-connection-receive :syn-sent state
ebrasca Mar 20, 2024
e91e108
tcp: ACK non RST incoming unacceptable segments
ebrasca Mar 20, 2024
5a6d095
tcp: Check incomming RST segments
ebrasca Mar 20, 2024
53363c9
tcp: Don't abort connection when resiving segment in :syn-received state
ebrasca Mar 20, 2024
cc921f7
tcp: Remove connection from listener when getting SYN in state :syn-r…
ebrasca Mar 20, 2024
d602981
tcp: Challenge any SYN segment when not in :syn-sent state
ebrasca Mar 20, 2024
352172c
tcp: Add :time-wait state
ebrasca Mar 20, 2024
663c799
tcp: Add =<
ebrasca Mar 22, 2024
9688f25
tcp: Deal with wrap around sequence numbers correctly
ebrasca Mar 22, 2024
08e01fb
tcp: Small refactor
ebrasca Mar 22, 2024
f6fa477
tcp: Send RST to segments of old connections in :syn-received state
ebrasca Mar 22, 2024
3278434
tcp: Handle FIN in :syn-received state
ebrasca Mar 22, 2024
180b7b4
tcp: Chenck ACK sequence number in :last-ack state before ending it
ebrasca Mar 22, 2024
3334d79
tcp: Hangle FIN in :last-ack state
ebrasca Mar 22, 2024
0c28348
tcp: Ignore SYN or RST packets without ACK
ebrasca Mar 22, 2024
c9a2b0d
tcp: Allow sending data in half open connection
ebrasca Mar 22, 2024
d4bf137
tcp: Add rfc5961 mitigation
ebrasca Mar 22, 2024
98af636
tcp: Send ACK to segments that acknowledges something not yet sent
ebrasca Mar 22, 2024
bfb920a
tcp: Hangle FIN in :closing state
ebrasca Mar 22, 2024
dd95347
tcp: Hangle FIN in :close-wait state
ebrasca Mar 23, 2024
0d07fa7
tcp: Allow to resive data and control in the same segment
ebrasca Mar 23, 2024
5a15692
tcp: Refactor tcp4-connection-receive :fin-wait-1 state
ebrasca Mar 23, 2024
7cf7956
tcp: Update window size
ebrasca Mar 27, 2024
b365915
arp: Use correct function to get the time
ebrasca Jul 1, 2024
4f2bd69
tcp: Report connection-closing in tcp-send when connetion is closing
ebrasca Jul 1, 2024
c229bc9
tcp: Implemented abort close
ebrasca Jul 1, 2024
24ea270
tcp: Refactor tcp-send
ebrasca Jul 9, 2024
94ebcb6
tcp: Add missing :closed case
ebrasca Jul 9, 2024
dc3eced
tcp: Implemented time-wait timeout
ebrasca Jul 10, 2024
1690e24
tcp: Add :closed case to tcp4-connection-receive
ebrasca Jul 12, 2024
fe6ae64
tcp: Add close for :syn-sent and :syn-received cases
ebrasca Jul 12, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
121 changes: 64 additions & 57 deletions net/tcp.lisp
Original file line number Diff line number Diff line change
@@ -1,14 +1,8 @@
;;; TCP
;;;
;;; Transmission Control Protocol - Protocol Specification
;;; https://tools.ietf.org/html/rfc793
;;; https://datatracker.ietf.org/doc/html/rfc9293
fitzsim marked this conversation as resolved.
Show resolved Hide resolved
;;;
;;; EFSM/SDL modeling of the original TCP standard (RFC793) and the
;;; Congestion Control Mechanism of TCP Reno
;;; http://www.medianet.kent.edu/techreports/TR2005-07-22-tcp-EFSM.pdf
;;;
;;; Computing TCP's Retransmission Timer
;;; https://tools.ietf.org/html/rfc6298

(in-package :mezzano.network.tcp)

Expand Down Expand Up @@ -383,8 +377,9 @@ Set to a value near 2^32 to test SND sequence number wrapping.")
(setf (tcp-connection-last-ack-time connection)
(get-internal-run-time))
(when (not *netmangler-force-local-retransmit*)
(tcp4-send-packet connection iss (+u32 irs 1) nil :ack-p t :syn-p t))))
(tcp4-send-packet connection iss (+u32 irs 1) nil :syn-p t))))
((logtest flags +tcp4-flag-rst+)) ; Do nothing for resets addressed to nobody.
((logtest flags +tcp4-flag-fin+)) ; Do nothing for finish since the SEG.SEQ cannot be validated
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do you have a way to test this?

(t
(let* ((seq (if (logtest flags +tcp4-flag-ack+)
(tcp-packet-acknowledgment-number packet start end)
Expand Down Expand Up @@ -471,11 +466,7 @@ Set to a value near 2^32 to test SND sequence number wrapping.")
(when (<= seq (tcp-connection-rcv.nxt connection))
;; Don't check *netmangler-force-local-retransmit* here,
;; or no acks will ever get through.
(tcp4-send-packet connection
(tcp-connection-snd.nxt connection)
(tcp-connection-rcv.nxt connection)
nil
:ack-p t)))
(tcp4-send-ack connection)))

(defun tcp-packet-sequence-number (packet start end)
(declare (ignore end))
Expand All @@ -496,20 +487,29 @@ Set to a value near 2^32 to test SND sequence number wrapping.")
(defun tcp-packet-data-length (packet start end)
(- end (+ start (tcp-packet-header-length packet start end))))

(defun acceptable-segment-p (connection packet start end)
(defun acceptable-segment-p (connection seg.seq seg.len)
(let ((rcv.wnd (tcp-connection-rcv.wnd connection))
(rcv.nxt (tcp-connection-rcv.nxt connection))
(seg.seq (tcp-packet-sequence-number packet start end))
(seg.len (tcp-packet-data-length packet start end)))
(rcv.nxt (tcp-connection-rcv.nxt connection)))
(if (eql rcv.wnd 0)
(and (eql seg.len 0)
(eql seg.seq rcv.nxt))
;; Arithmetic here is not wrapping, so as to avoid wrap-around problems.
(and (and (<= rcv.nxt seg.seq) (< seg.seq (+ rcv.nxt rcv.wnd)))
(and (<= rcv.nxt seg.seq)
fitzsim marked this conversation as resolved.
Show resolved Hide resolved
(< seg.seq (+ rcv.nxt rcv.wnd))
(or (eql seg.len 0)
(let ((seq-end (+ seg.seq seg.len -1)))
(and (<= rcv.nxt seq-end) (< seq-end (+ rcv.nxt rcv.wnd)))))))))

(defun acceptable-ack-p (connection seg.ack)
"If SND.UNA < SEG.ACK <= SND.NXT, then the ACK is acceptable."
(if (< (tcp-connection-snd.una connection)
(tcp-connection-snd.nxt connection))
(and (< (tcp-connection-snd.una connection) seg.ack)
(<= seg.ack (tcp-connection-snd.nxt connection)))
;; Sequence numbers wrapped.
(or (< (tcp-connection-snd.una connection) seg.ack)
(<= seg.ack (tcp-connection-snd.nxt connection)))))

(defun update-timeout-timer (connection)
(when (not (eql (tcp-connection-state connection) :syn-sent))
(disarm-timeout-timer connection)
Expand Down Expand Up @@ -556,12 +556,13 @@ Set to a value near 2^32 to test SND sequence number wrapping.")
(flags (tcp-packet-flags packet start end))
(header-length (tcp-packet-header-length packet start end))
(data-length (tcp-packet-data-length packet start end)))
(when (and (not (eql (tcp-connection-state connection) :established))
(logtest flags +tcp4-flag-rst+))
(when (and (logtest flags +tcp4-flag-rst+)
(not (or (eql (tcp-connection-state connection) :syn-sent)
(eql (tcp-connection-state connection) :established))))
;; FIXME: This code isn't correct, it needs to check the sequence numbers
;; before accepting this packet and resetting the connection. This is
;; currently only done correctly in the :ESTABLISHED state, but should
;; be done for the other states too.
;; currently only done correctly in the states: :SYN-SENT, :ESTABLISHED
;; But should be done for the other states too.
;; Remote has sent RST, aborting connection
(setf (tcp-connection-pending-error connection)
(make-condition 'connection-reset
Expand All @@ -573,38 +574,42 @@ Set to a value near 2^32 to test SND sequence number wrapping.")
;; :CLOSED should never be seen here
(ecase (tcp-connection-state connection)
(:syn-sent
;; Active open
(cond ((and (logtest flags +tcp4-flag-ack+)
(cond ((logtest flags +tcp4-flag-rst+)
(when (acceptable-ack-p connection ack)
(setf (tcp-connection-pending-error connection)
(make-condition 'connection-reset
:host (tcp-connection-remote-ip connection)
:port (tcp-connection-remote-port connection)))
(detach-tcp-connection connection)))
((and (logtest flags +tcp4-flag-ack+)
(not (acceptable-ack-p connection ack)))
;; Segment comes from an old connection
(unless *netmangler-force-local-retransmit*
(tcp4-send-packet connection ack seq nil :ack-p nil :rst-p t)))
((and (logtest flags +tcp4-flag-ack+)
(logtest flags +tcp4-flag-syn+)
(eql ack (tcp-connection-snd.nxt connection)))
;; Remote has sent SYN+ACK and waiting for ACK
;; Active open
(initial-rtt-measurement connection)
(setf (tcp-connection-state connection) :established)
(setf (tcp-connection-rcv.nxt connection) (+u32 seq 1))
(setf (tcp-connection-snd.una connection) ack)
(when (not *netmangler-force-local-retransmit*)
(tcp4-send-packet connection ack (tcp-connection-rcv.nxt connection) nil))
(setf (tcp-connection-state connection) :established
fitzsim marked this conversation as resolved.
Show resolved Hide resolved
(tcp-connection-rcv.nxt connection) (+u32 seq 1)
(tcp-connection-snd.una connection) ack)
(unless *netmangler-force-local-retransmit*
(tcp4-send-ack connection))
;; Cancel retransmit
(disarm-retransmit-timer connection)
(disarm-timeout-timer connection))
((logtest flags +tcp4-flag-syn+)
;; Simultaneous open
(setf (tcp-connection-state connection) :syn-received
(tcp-connection-rcv.nxt connection) (+u32 seq 1))
(when (not *netmangler-force-local-retransmit*)
;; TODO: Update window
fitzsim marked this conversation as resolved.
Show resolved Hide resolved
(unless *netmangler-force-local-retransmit*
(tcp4-send-packet connection ack (tcp-connection-rcv.nxt connection) nil
:ack-p t :syn-p t))
:syn-p t))
;; Cancel retransmit
(disarm-retransmit-timer connection)
(disarm-timeout-timer connection))
(t
;; Aborting connection
(tcp4-send-packet connection ack seq nil :rst-p t)
(setf (tcp-connection-pending-error connection)
(make-condition 'connection-aborted
:host (tcp-connection-remote-ip connection)
:port (tcp-connection-remote-port connection)))
(detach-tcp-connection connection))))
(disarm-timeout-timer connection))))
(:syn-received
;; Pasive open
(cond ((and (eql flags +tcp4-flag-ack+)
Expand Down Expand Up @@ -632,13 +637,9 @@ Set to a value near 2^32 to test SND sequence number wrapping.")
(remhash connection (tcp-listener-pending-connections listener))
(decf (tcp-listener-n-pending-connections listener))))))
(:established
(cond ((not (acceptable-segment-p connection packet start end))
(cond ((not (acceptable-segment-p connection seq data-length))
(when (not (logtest flags +tcp4-flag-rst+))
(tcp4-send-packet connection
(tcp-connection-snd.nxt connection)
(tcp-connection-rcv.nxt connection)
nil
:ack-p t)))
(tcp4-send-ack connection)))
((logtest flags +tcp4-flag-rst+)
(setf (tcp-connection-pending-error connection)
(make-condition 'connection-reset
Expand All @@ -652,7 +653,7 @@ Set to a value near 2^32 to test SND sequence number wrapping.")
:port (tcp-connection-remote-port connection)))
(detach-tcp-connection connection)
(tcp4-send-packet connection
(tcp-connection-snd.next connection)
(tcp-connection-snd.nxt connection)
fitzsim marked this conversation as resolved.
Show resolved Hide resolved
0 ; ???
nil
:ack-p nil
Expand Down Expand Up @@ -700,7 +701,7 @@ Set to a value near 2^32 to test SND sequence number wrapping.")
(setf (mezzano.supervisor:event-state
(tcp-connection-receive-event connection))
t)
(tcp4-send-packet connection ack (+u32 seq 1) nil :ack-p t))
(tcp4-send-packet connection ack (+u32 seq 1) nil))
fitzsim marked this conversation as resolved.
Show resolved Hide resolved
(tcp4-receive-data connection data-length end header-length packet seq start)))
((eql (tcp-connection-snd.una connection) ack)
;; TODO: slow start/duplicate ack detection/fast retransmit/etc.
Expand All @@ -722,10 +723,7 @@ Set to a value near 2^32 to test SND sequence number wrapping.")
(cond ((logtest flags +tcp4-flag-fin+)
(setf (tcp-connection-rcv.nxt connection)
(+u32 (tcp-connection-rcv.nxt connection) 1))
(tcp4-send-packet connection
(tcp-connection-snd.nxt connection)
(tcp-connection-rcv.nxt connection)
nil)
(tcp4-send-ack connection)
(if (logtest flags +tcp4-flag-ack+)
;; Remote saw our FIN and closed as well.
(detach-tcp-connection connection)
Expand All @@ -743,10 +741,7 @@ Set to a value near 2^32 to test SND sequence number wrapping.")
;; Remote has sent FIN and waiting for ACK
(setf (tcp-connection-rcv.nxt connection)
(+u32 (tcp-connection-rcv.nxt connection) 1))
(tcp4-send-packet connection
(tcp-connection-snd.nxt connection)
(tcp-connection-rcv.nxt connection)
nil)
(tcp4-send-ack connection)
(detach-tcp-connection connection))
(tcp4-receive-data connection data-length end header-length packet seq start)))
(:closing
Expand Down Expand Up @@ -787,6 +782,18 @@ Set to a value near 2^32 to test SND sequence number wrapping.")
(when errors-escape
(error c))))))

(defun tcp4-send-ack (connection)
fitzsim marked this conversation as resolved.
Show resolved Hide resolved
(tcp4-send-packet connection
(tcp-connection-snd.nxt connection)
(tcp-connection-rcv.nxt connection)
nil))

(defun challenge-ack (connection)
fitzsim marked this conversation as resolved.
Show resolved Hide resolved
(tcp4-send-packet connection
(tcp-connection-snd.nxt connection)
(tcp-connection-rcv.nxt connection)
nil))

(defun compute-ip-pseudo-header-partial-checksum (src-ip dst-ip protocol length)
(+ (logand src-ip #xFFFF)
(logand (ash src-ip -16) #xFFFF)
Expand Down