mirror of
https://github.com/subhobhai943/SUB-OS.git
synced 2026-10-25 16:52:29 +00:00
feat(net): Full TCP state machine, SYN-ACK packet handler, NetFilter integration, and dynamic netstat
This commit is contained in:
1 parent
c59af27cdb
commit
1ecd677604
4 files changed
+265
-4
No files matched your search
@@ -3,6 +3,13 @@
|
||||
|
||||
#include <net/net.h>
|
||||
|
||||
#define TCP_FLAG_FIN 0x01
|
||||
#define TCP_FLAG_SYN 0x02
|
||||
#define TCP_FLAG_RST 0x04
|
||||
#define TCP_FLAG_PSH 0x08
|
||||
#define TCP_FLAG_ACK 0x10
|
||||
#define TCP_FLAG_URG 0x20
|
||||
|
||||
#define TCP_STATE_CLOSED 0
|
||||
#define TCP_STATE_LISTEN 1
|
||||
#define TCP_STATE_SYN_SENT 2
|
||||
@@ -27,7 +34,24 @@ typedef struct {
|
||||
uint16_t urgent_pointer;
|
||||
} __attribute__((packed)) tcp_header_t;
|
||||
|
||||
typedef struct tcp_conn {
|
||||
uint32_t local_ip;
|
||||
uint32_t remote_ip;
|
||||
uint16_t local_port;
|
||||
uint16_t remote_port;
|
||||
uint8_t state;
|
||||
uint32_t seq_num;
|
||||
uint32_t ack_num;
|
||||
bool in_use;
|
||||
} tcp_conn_t;
|
||||
|
||||
void tcp_init(void);
|
||||
void tcp_receive(const uint8_t* packet, uint16_t length, uint32_t src_ip);
|
||||
void tcp_send_packet(uint32_t dst_ip, uint16_t src_port, uint16_t dst_port,
|
||||
uint32_t seq, uint32_t ack, uint8_t flags,
|
||||
const void* payload, uint16_t payload_len);
|
||||
|
||||
size_t tcp_get_connections_count(void);
|
||||
const tcp_conn_t* tcp_get_connection(size_t index);
|
||||
|
||||
#endif // _NET_TCP_H
|
||||
@@ -1,4 +1,6 @@
|
||||
#include <net/net.h>
|
||||
#include <net/tcp.h>
|
||||
#include <net/filter.h>
|
||||
#include <drivers/e1000.h>
|
||||
#include <lib/string.h>
|
||||
#include <lib/printf.h>
|
||||
@@ -233,8 +235,15 @@ void net_receive(const uint8_t* packet, uint16_t length) {
|
||||
const ip_header_t* ip = (const ip_header_t*)payload;
|
||||
uint8_t ihl = (ip->ihl_version & 0x0F) * 4;
|
||||
if (payload_len >= ihl) {
|
||||
// NetFilter inspection hook
|
||||
if (filter_evaluate(FILTER_HOOK_LOCAL_IN, ip->protocol, ip->src_ip, ip->dst_ip, 0, 0, payload_len) == FILTER_ACTION_DROP) {
|
||||
return; // Dropped by firewall
|
||||
}
|
||||
|
||||
if (ip->protocol == IP_PROTO_ICMP) {
|
||||
net_handle_icmp(ip->src_ip, payload + ihl, payload_len - ihl);
|
||||
} else if (ip->protocol == IP_PROTO_TCP) {
|
||||
tcp_receive(payload + ihl, payload_len - ihl, ip->src_ip);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+213
-1
@@ -1,10 +1,222 @@
|
||||
#include <net/tcp.h>
|
||||
#include <net/net.h>
|
||||
#include <net/ssh.h>
|
||||
#include <net/http.h>
|
||||
#include <mm/kmalloc.h>
|
||||
#include <lib/string.h>
|
||||
#include <lib/printf.h>
|
||||
#include <kernel/printk.h>
|
||||
|
||||
#define MAX_TCP_CONNS 32
|
||||
|
||||
typedef struct {
|
||||
uint32_t src_ip;
|
||||
uint32_t dst_ip;
|
||||
uint8_t zero;
|
||||
uint8_t protocol;
|
||||
uint16_t tcp_len;
|
||||
} __attribute__((packed)) tcp_pseudo_header_t;
|
||||
|
||||
static tcp_conn_t tcp_connections[MAX_TCP_CONNS];
|
||||
|
||||
static uint16_t tcp_checksum(uint32_t src_ip, uint32_t dst_ip, const tcp_header_t* tcp, const void* payload, uint16_t payload_len) {
|
||||
uint16_t tcp_total_len = sizeof(tcp_header_t) + payload_len;
|
||||
|
||||
tcp_pseudo_header_t ph;
|
||||
ph.src_ip = src_ip;
|
||||
ph.dst_ip = dst_ip;
|
||||
ph.zero = 0;
|
||||
ph.protocol = IP_PROTO_TCP;
|
||||
ph.tcp_len = htons(tcp_total_len);
|
||||
|
||||
uint32_t sum = 0;
|
||||
const uint16_t* ptr = (const uint16_t*)&ph;
|
||||
for (size_t i = 0; i < sizeof(ph) / 2; i++) {
|
||||
sum += *ptr++;
|
||||
}
|
||||
|
||||
ptr = (const uint16_t*)tcp;
|
||||
for (size_t i = 0; i < sizeof(tcp_header_t) / 2; i++) {
|
||||
sum += *ptr++;
|
||||
}
|
||||
|
||||
if (payload && payload_len > 0) {
|
||||
ptr = (const uint16_t*)payload;
|
||||
size_t len = payload_len;
|
||||
while (len > 1) {
|
||||
sum += *ptr++;
|
||||
len -= 2;
|
||||
}
|
||||
if (len > 0) {
|
||||
sum += *(const uint8_t*)ptr;
|
||||
}
|
||||
}
|
||||
|
||||
while (sum >> 16) {
|
||||
sum = (sum & 0xFFFF) + (sum >> 16);
|
||||
}
|
||||
return (uint16_t)(~sum);
|
||||
}
|
||||
|
||||
void tcp_init(void) {
|
||||
memset(tcp_connections, 0, sizeof(tcp_connections));
|
||||
printk(KERN_INFO "NET: TCP (Transmission Control Protocol) state machine online\n");
|
||||
}
|
||||
|
||||
void tcp_send_packet(uint32_t dst_ip, uint16_t src_port, uint16_t dst_port,
|
||||
uint32_t seq, uint32_t ack, uint8_t flags,
|
||||
const void* payload, uint16_t payload_len) {
|
||||
net_if_t* netif = net_get_primary_if();
|
||||
uint32_t src_ip = netif ? netif->ip : 0x0A00020F; // 10.0.2.15
|
||||
|
||||
uint16_t total_len = sizeof(tcp_header_t) + payload_len;
|
||||
uint8_t* buf = (uint8_t*)kzalloc(total_len);
|
||||
if (!buf) return;
|
||||
|
||||
tcp_header_t* tcp = (tcp_header_t*)buf;
|
||||
tcp->src_port = htons(src_port);
|
||||
tcp->dst_port = htons(dst_port);
|
||||
tcp->seq_num = htonl(seq);
|
||||
tcp->ack_num = htonl(ack);
|
||||
tcp->data_offset_reserved = (sizeof(tcp_header_t) / 4) << 4;
|
||||
tcp->flags = flags;
|
||||
tcp->window_size = htons(65535);
|
||||
tcp->urgent_pointer = 0;
|
||||
|
||||
if (payload && payload_len > 0) {
|
||||
memcpy(buf + sizeof(tcp_header_t), payload, payload_len);
|
||||
}
|
||||
|
||||
tcp->checksum = 0;
|
||||
tcp->checksum = tcp_checksum(src_ip, dst_ip, tcp, payload, payload_len);
|
||||
|
||||
net_send_ip(dst_ip, IP_PROTO_TCP, buf, total_len);
|
||||
kfree(buf);
|
||||
}
|
||||
|
||||
static tcp_conn_t* find_or_alloc_conn(uint32_t r_ip, uint16_t r_port, uint16_t l_port) {
|
||||
for (size_t i = 0; i < MAX_TCP_CONNS; i++) {
|
||||
if (tcp_connections[i].in_use &&
|
||||
tcp_connections[i].remote_ip == r_ip &&
|
||||
tcp_connections[i].remote_port == r_port &&
|
||||
tcp_connections[i].local_port == l_port) {
|
||||
return &tcp_connections[i];
|
||||
}
|
||||
}
|
||||
for (size_t i = 0; i < MAX_TCP_CONNS; i++) {
|
||||
if (!tcp_connections[i].in_use) {
|
||||
tcp_connections[i].in_use = true;
|
||||
tcp_connections[i].remote_ip = r_ip;
|
||||
tcp_connections[i].remote_port = r_port;
|
||||
tcp_connections[i].local_port = l_port;
|
||||
tcp_connections[i].local_ip = 0x0A00020F;
|
||||
tcp_connections[i].state = TCP_STATE_CLOSED;
|
||||
tcp_connections[i].seq_num = 1000;
|
||||
tcp_connections[i].ack_num = 0;
|
||||
return &tcp_connections[i];
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void tcp_receive(const uint8_t* packet, uint16_t length, uint32_t src_ip) {
|
||||
(void)packet; (void)length; (void)src_ip;
|
||||
if (!packet || length < sizeof(tcp_header_t)) return;
|
||||
|
||||
const tcp_header_t* tcp = (const tcp_header_t*)packet;
|
||||
uint16_t src_port = ntohs(tcp->src_port);
|
||||
uint16_t dst_port = ntohs(tcp->dst_port);
|
||||
uint32_t seq_num = ntohl(tcp->seq_num);
|
||||
uint32_t ack_num = ntohl(tcp->ack_num);
|
||||
uint8_t flags = tcp->flags;
|
||||
(void)ack_num;
|
||||
|
||||
uint8_t header_len = (tcp->data_offset_reserved >> 4) * 4;
|
||||
const uint8_t* payload = packet + header_len;
|
||||
uint16_t payload_len = length > header_len ? length - header_len : 0;
|
||||
|
||||
// Check if target port is SSH (22) or HTTP (80)
|
||||
bool is_ssh_port = (dst_port == sshd_get_port() && sshd_is_running());
|
||||
bool is_http_port = (dst_port == 80 && httpd_is_running());
|
||||
|
||||
if (!is_ssh_port && !is_http_port) {
|
||||
// Port not open: send TCP RST
|
||||
if (!(flags & TCP_FLAG_RST)) {
|
||||
tcp_send_packet(src_ip, dst_port, src_port, 0, seq_num + 1, TCP_FLAG_RST | TCP_FLAG_ACK, NULL, 0);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
tcp_conn_t* conn = find_or_alloc_conn(src_ip, src_port, dst_port);
|
||||
if (!conn) return;
|
||||
|
||||
// Handle TCP SYN (Connection Initiation from Client)
|
||||
if (flags & TCP_FLAG_SYN) {
|
||||
conn->state = TCP_STATE_SYN_RCVD;
|
||||
conn->ack_num = seq_num + 1;
|
||||
conn->seq_num = 10000;
|
||||
|
||||
// Send SYN-ACK
|
||||
tcp_send_packet(src_ip, dst_port, src_port, conn->seq_num, conn->ack_num,
|
||||
TCP_FLAG_SYN | TCP_FLAG_ACK, NULL, 0);
|
||||
conn->seq_num++;
|
||||
return;
|
||||
}
|
||||
|
||||
// Handle TCP FIN (Connection Termination)
|
||||
if (flags & TCP_FLAG_FIN) {
|
||||
conn->ack_num = seq_num + 1;
|
||||
tcp_send_packet(src_ip, dst_port, src_port, conn->seq_num, conn->ack_num,
|
||||
TCP_FLAG_ACK | TCP_FLAG_FIN, NULL, 0);
|
||||
conn->in_use = false;
|
||||
conn->state = TCP_STATE_CLOSED;
|
||||
return;
|
||||
}
|
||||
|
||||
// Handle TCP RST
|
||||
if (flags & TCP_FLAG_RST) {
|
||||
conn->in_use = false;
|
||||
conn->state = TCP_STATE_CLOSED;
|
||||
return;
|
||||
}
|
||||
|
||||
// Handle Data / ACK
|
||||
conn->state = TCP_STATE_ESTABLISHED;
|
||||
|
||||
if (payload_len > 0) {
|
||||
conn->ack_num = seq_num + payload_len;
|
||||
|
||||
if (is_ssh_port) {
|
||||
char resp[1024];
|
||||
int rlen = sshd_process_packet((const char*)payload, payload_len, resp, sizeof(resp));
|
||||
if (rlen > 0) {
|
||||
tcp_send_packet(src_ip, dst_port, src_port, conn->seq_num, conn->ack_num,
|
||||
TCP_FLAG_PSH | TCP_FLAG_ACK, resp, (uint16_t)rlen);
|
||||
conn->seq_num += rlen;
|
||||
} else {
|
||||
tcp_send_packet(src_ip, dst_port, src_port, conn->seq_num, conn->ack_num,
|
||||
TCP_FLAG_ACK, NULL, 0);
|
||||
}
|
||||
} else if (is_http_port) {
|
||||
char resp[2048];
|
||||
int rlen = httpd_handle_request((const char*)payload, resp, sizeof(resp));
|
||||
if (rlen > 0) {
|
||||
tcp_send_packet(src_ip, dst_port, src_port, conn->seq_num, conn->ack_num,
|
||||
TCP_FLAG_PSH | TCP_FLAG_ACK, resp, (uint16_t)rlen);
|
||||
conn->seq_num += rlen;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
size_t tcp_get_connections_count(void) {
|
||||
size_t count = 0;
|
||||
for (size_t i = 0; i < MAX_TCP_CONNS; i++) {
|
||||
if (tcp_connections[i].in_use) count++;
|
||||
}
|
||||
return count;
|
||||
}
|
||||
|
||||
const tcp_conn_t* tcp_get_connection(size_t index) {
|
||||
if (index >= MAX_TCP_CONNS || !tcp_connections[index].in_use) return NULL;
|
||||
return &tcp_connections[index];
|
||||
}
|
||||
@@ -1262,9 +1262,25 @@ static int applet_netstat(int argc, char** argv) {
|
||||
(void)argc; (void)argv;
|
||||
printk(ANSI_BRIGHT_CYAN "Active Internet connections (servers and established)\n" ANSI_RESET);
|
||||
printk(ANSI_YELLOW "Proto Recv-Q Send-Q Local Address Foreign Address State\n" ANSI_RESET);
|
||||
printk("tcp 0 0 0.0.0.0:80 0.0.0.0:* LISTEN\n");
|
||||
printk("udp 0 0 0.0.0.0:53 0.0.0.0:* LISTEN\n");
|
||||
printk("udp 0 0 0.0.0.0:68 0.0.0.0:* ESTABLISHED\n");
|
||||
|
||||
if (sshd_is_running()) {
|
||||
printk("tcp 0 0 0.0.0.0:%-5u 0.0.0.0:* LISTEN (sshd)\n", sshd_get_port());
|
||||
}
|
||||
if (httpd_is_running()) {
|
||||
printk("tcp 0 0 0.0.0.0:80 0.0.0.0:* LISTEN (httpd)\n");
|
||||
}
|
||||
printk("udp 0 0 0.0.0.0:53 0.0.0.0:* LISTEN (dns)\n");
|
||||
printk("udp 0 0 0.0.0.0:68 0.0.0.0:* ESTABLISHED (dhcp)\n");
|
||||
|
||||
for (size_t i = 0; i < 8; i++) {
|
||||
const ssh_session_t* s = sshd_get_session(i);
|
||||
if (s && s->in_use) {
|
||||
char client_ip_str[16];
|
||||
ip_to_str(s->client_ip, client_ip_str);
|
||||
printk("tcp 0 0 10.0.2.15:22 %s:%-5u ESTABLISHED (%s)\n",
|
||||
client_ip_str, s->client_port, s->username);
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
Reference in new issue
Block a user