Add "connection reset" TCP handler for incoming SYN frames

This commit is contained in:
Mark
2020-03-23 13:04:49 +02:00
parent 7be54602f5
commit fd235dbb86
5 changed files with 116 additions and 0 deletions
+1
View File
@@ -103,6 +103,7 @@ OBJS+=$(O)/sys/sys_net.o \
$(O)/net/icmp.o \
$(O)/net/udp.o \
$(O)/net/raw.o \
$(O)/net/tcp.o \
$(O)/net/if.o \
$(O)/net/util.o
DIRS+=$(O)/net
+1
View File
@@ -2,6 +2,7 @@
#include "sys/types.h"
#define INET_P_ICMP 1
#define INET_P_TCP 6
#define INET_P_UDP 17
struct inet_frame {
+32
View File
@@ -0,0 +1,32 @@
#pragma once
#include "sys/types.h"
struct tcp_frame {
uint16_t src_port;
uint16_t dst_port;
uint32_t seq;
uint32_t ack_seq;
uint8_t ns:1;
uint8_t zero:3;
uint8_t doff:4;
uint8_t fin:1;
uint8_t syn:1;
uint8_t rst:1;
uint8_t psh:1;
uint8_t ack:1;
uint8_t urg:1;
uint8_t ece:1;
uint8_t cwr:1;
uint16_t window;
uint16_t checksum;
uint16_t urg_ptr;
} __attribute__((packed));
struct eth_frame;
struct inet_frame;
struct packet;
struct vfs_ioctx;
struct ofile;
struct sockaddr;
void tcp_handle_frame(struct packet *p, struct eth_frame *eth, struct inet_frame *ip, void *data, size_t len);
+4
View File
@@ -10,6 +10,7 @@
#include "net/arp.h"
#include "net/eth.h"
#include "net/udp.h"
#include "net/tcp.h"
#include "net/if.h"
uint16_t inet_checksum(const void *data, size_t len) {
@@ -106,6 +107,9 @@ void inet_handle_frame(struct packet *p, struct eth_frame *eth, void *data, size
case INET_P_UDP:
udp_handle_frame(p, eth, ip, data, len);
break;
case INET_P_TCP:
tcp_handle_frame(p, eth, ip, data, len);
break;
default:
kwarn("%s: dropping unknown protocol %02x\n", p->dev->name, ip->proto);
break;
+78
View File
@@ -0,0 +1,78 @@
#include "net/packet.h"
#include "sys/string.h"
#include "sys/debug.h"
#include "net/inet.h"
#include "net/util.h"
#include "net/eth.h"
#include "net/tcp.h"
#include "net/if.h"
static uint16_t tcp_checksum(uint32_t daddr, uint32_t saddr, uint16_t tcp_length, void *tcp_data) {
uint32_t sum = 0;
uint32_t tmp = saddr;
sum += tmp & 0xFFFF;
sum += tmp >> 16;
tmp = daddr;
sum += tmp & 0xFFFF;
sum += tmp >> 16;
sum += 6;
sum += tcp_length;
for (int i = 0; i < tcp_length / 2; ++i) {
sum += ntohs(((uint16_t *) tcp_data)[i]);
}
sum = (sum >> 16) + (sum & 0xFFFF);
return ~(sum & 0xFFFF) & 0xFFFF;
}
// Reset a connection attempt given its SYN packet
static void tcp_syn_reset(struct netdev *dev, uint32_t inaddr, struct tcp_frame *syn_frame) {
if (!(dev->flags & IF_F_HASIP)) {
return;
}
char packet[sizeof(struct eth_frame) + sizeof(struct inet_frame) + sizeof(struct tcp_frame)];
struct tcp_frame *tcp = (struct tcp_frame *) &packet[sizeof(struct eth_frame) + sizeof(struct inet_frame)];
memset(tcp, 0, sizeof(struct tcp_frame));
tcp->src_port = syn_frame->dst_port;
tcp->dst_port = syn_frame->src_port;
tcp->ack_seq = htonl(ntohl(syn_frame->seq) + 1);
tcp->doff = sizeof(struct tcp_frame) / 4;
tcp->rst = 1;
tcp->ack = 1;
tcp->window = syn_frame->window;
uint16_t checksum = tcp_checksum(inaddr, dev->inaddr, sizeof(struct tcp_frame), tcp);
tcp->checksum = htons(checksum);
debug_dump(DEBUG_DEFAULT, tcp, sizeof(struct tcp_frame));
inet_send_wrapped(dev, inaddr, INET_P_TCP, packet, sizeof(packet));
}
void tcp_handle_frame(struct packet *p, struct eth_frame *eth, struct inet_frame *ip, void *data, size_t len) {
if (len < sizeof(struct tcp_frame)) {
kwarn("%s: dropping undersized frame\n", p->dev->name);
return;
}
struct tcp_frame *tcp = data;
size_t frame_size = 4 * tcp->doff;
if (len < frame_size) {
kwarn("%s: dropping undersized frame\n", p->dev->name);
return;
}
data += frame_size;
len -= frame_size;
if (tcp->syn && !tcp->ack) {
// TODO: Check if it's an initial SYN
// Just reset the connection for now
tcp_syn_reset(p->dev, ntohl(ip->src_inaddr), tcp);
} else {
kwarn("%s: unhandled packet: syn=%d, ack=%d, psh=%d, rst=%d\n", tcp->syn, tcp->ack, tcp->psh, tcp->rst);
}
}