commit 84f16b3929fbbc6bb6fe9e77e80a0bdb4f3662c6
parent 41ddf46aeafc3cf75902ea6666508d91bb30e5af
Author: erai <erai@omiltem.net>
Date: Sun, 5 May 2024 23:14:47 -0400
rst tcp connections
Diffstat:
M | kernel.c | | | 167 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-- |
1 file changed, 164 insertions(+), 3 deletions(-)
diff --git a/kernel.c b/kernel.c
@@ -763,6 +763,26 @@ struct arp_entry {
}
struct tcp_state {
+ // Network tuple
+ peer_ip: int;
+ peer_port: int;
+ sock_ip: int;
+ sock_port: int;
+
+ send_una: int;
+ send_nxt: int;
+ send_wnd: int;
+ send_wl1: int;
+ send_wl2: int;
+ send_iss: int;
+
+ rcv_nxt: int;
+ rcv_wnd: int;
+ rcv_up: int;
+ rcv_irs: int;
+
+ send_buf: *byte;
+ recv_buf: *byte;
}
struct global {
@@ -1289,6 +1309,8 @@ struct rxinfo {
tcp_ack: int;
tcp_flags: int;
tcp_win: int;
+ tcp_opt: *byte;
+ tcp_opt_len: int;
tcp_seg: *byte;
tcp_seg_len: int;
@@ -1404,6 +1426,15 @@ struct txinfo {
udp_src: int;
udp_dest: int;
+
+ tcp_src: int;
+ tcp_dest: int;
+ tcp_seq: int;
+ tcp_ack: int;
+ tcp_flags: int;
+ tcp_win: int;
+ tcp_opt: *byte;
+ tcp_opt_len: int;
}
alloc_tx(): *txinfo {
@@ -1976,7 +2007,134 @@ rx_udp(pkt: *rxinfo) {
handle_udp(pkt);
}
+send_tcp(pkt: *txinfo) {
+ var len: int;
+ var sum: int;
+
+ len = 20 + ((pkt.tcp_opt_len + 3) & -4);
+
+ pkt.buf = &pkt.buf[-len];
+ pkt.len = pkt.len + len;
+
+ bzero(pkt.buf, len);
+
+ pkt.buf[0] = (pkt.tcp_src >> 8):byte;
+ pkt.buf[1] = pkt.tcp_src:byte;
+ pkt.buf[2] = (pkt.tcp_dest >> 8):byte;
+ pkt.buf[3] = pkt.tcp_dest:byte;
+
+ pkt.buf[4] = (pkt.tcp_seq >> 24):byte;
+ pkt.buf[5] = (pkt.tcp_seq >> 16):byte;
+ pkt.buf[6] = (pkt.tcp_seq >> 8):byte;
+ pkt.buf[7] = pkt.tcp_seq:byte;
+
+ pkt.buf[8] = (pkt.tcp_ack >> 24):byte;
+ pkt.buf[9] = (pkt.tcp_ack >> 16):byte;
+ pkt.buf[10] = (pkt.tcp_ack >> 8):byte;
+ pkt.buf[11] = pkt.tcp_ack:byte;
+
+ pkt.buf[12] = (len << 2):byte;
+ pkt.buf[13] = pkt.tcp_flags:byte;
+ pkt.buf[14] = (pkt.tcp_win >> 8):byte;
+ pkt.buf[15] = pkt.tcp_win:byte;
+
+ memcpy(&pkt.buf[20], pkt.tcp_opt, pkt.tcp_opt_len);
+
+ sum = (pkt.ip_src & 0xffff)
+ + ((pkt.ip_src >> 16) & 0xffff)
+ + (pkt.ip_dest & 0xffff)
+ + ((pkt.ip_dest >> 16) & 0xffff)
+ + IP_TCP
+ + pkt.len;
+
+ sum = ~onesum(pkt.buf, pkt.len, sum);
+ pkt.buf[16] = (sum >> 8):byte;
+ pkt.buf[17] = sum:byte;
+
+ pkt.ip_proto = IP_TCP;
+
+ xxd(pkt.buf, pkt.len);
+
+ send_ip(pkt);
+}
+
+send_rst(pkt: *rxinfo) {
+ var tx: *txinfo;
+ tx = alloc_tx();
+
+ tx.ip_src = pkt.ip_dest;
+ tx.ip_dest = pkt.ip_src;
+ tx.tcp_src = pkt.tcp_dest;
+ tx.tcp_dest = pkt.tcp_src;
+ tx.tcp_win = 0;
+ tx.tcp_opt = 0:*byte;
+ tx.tcp_opt_len = 0;
+ tx.len = 0;
+
+ if pkt.tcp_flags & TCP_ACK {
+ tx.tcp_seq = pkt.tcp_ack;
+ tx.tcp_ack = 0;
+ tx.tcp_flags = TCP_RST;
+ } else {
+ tx.tcp_seq = 0;
+ tx.tcp_ack = pkt.tcp_seq + pkt.tcp_seg_len;
+ tx.tcp_flags = TCP_RST | TCP_ACK;
+ if pkt.tcp_flags & TCP_SYN {
+ tx.tcp_ack = tx.tcp_ack + 1;
+ }
+ }
+
+ send_tcp(tx);
+
+ free_tx(tx);
+}
+
handle_tcp(pkt: *rxinfo) {
+ var global: *global;
+ var tcb: *tcp_state;
+ var i: int;
+ global = g();
+
+ // Find the tcb
+ i = 0;
+ loop {
+ if i == global.tcp_count {
+ tcb = 0:*tcp_state;
+ break;
+ }
+
+ tcb = global.tcp[i];
+ if tcb
+ && tcb.peer_ip == pkt.ip_src
+ && tcb.peer_port == pkt.tcp_src
+ && tcb.sock_ip == pkt.ip_dest
+ && tcb.sock_port == pkt.tcp_dest {
+ break;
+ }
+
+ i = i + 1;
+ }
+
+ // Send a reset
+ if !tcb {
+ if pkt.tcp_flags & TCP_RST {
+ return;
+ }
+
+ send_rst(pkt);
+ return;
+ }
+
+ // Got a reset
+ if pkt.tcp_flags & TCP_RST {
+ // close the connection
+ return;
+ }
+
+ // TODO: slow-start add-inc-mul-dec retrans-timer fast-retrans listen maxss
+ // TODO: ssh random
+
+ // Handle data
kputip(pkt.ip_src);
kputc(':');
kputd(pkt.tcp_src);
@@ -1985,6 +2143,7 @@ handle_tcp(pkt: *rxinfo) {
kputc(':');
kputd(pkt.tcp_dest);
kputc('\n');
+ xxd(pkt.tcp_opt, pkt.tcp_opt_len);
xxd(pkt.tcp_seg, pkt.tcp_seg_len);
}
@@ -2021,16 +2180,18 @@ rx_tcp(pkt: *rxinfo) {
+ (pkt.tcp[9]:int << 16)
+ (pkt.tcp[10]:int << 8)
+ pkt.tcp[11]:int;
- pkt.tcp_flags = (pkt.tcp[12]:int << 8)
- + pkt.tcp[13]:int;
+ pkt.tcp_flags = pkt.tcp[13]:int;
pkt.tcp_win = (pkt.tcp[14]:int << 8)
+ pkt.tcp[15]:int;
- off = (pkt.tcp_flags >> 12) << 2;
+ off = (pkt.tcp[12]:int >> 4) << 2;
if off < 20 || off > pkt.tcp_len {
return;
}
+ pkt.tcp_opt = &pkt.tcp[20];
+ pkt.tcp_opt_len = off - 20;
+
pkt.tcp_seg = &pkt.tcp[off];
pkt.tcp_seg_len = pkt.tcp_len - off;