seperate net folder

This commit is contained in:
boreddevnl
2026-03-16 15:00:24 +01:00
parent 6b18d44fab
commit 65f362feab
7 changed files with 7 additions and 40 deletions

278
src/userland/net/net.c Normal file
View File

@@ -0,0 +1,278 @@
#include <stdlib.h>
#include <syscall.h>
static void print_ip(const net_ipv4_address_t* ip) {
if (!ip) return;
printf("%d.%d.%d.%d", ip->bytes[0], ip->bytes[1], ip->bytes[2], ip->bytes[3]);
}
static int parse_ip(const char* str, net_ipv4_address_t* ip) {
int val = 0;
int part = 0;
const char* p = str;
while (*p) {
if (*p >= '0' && *p <= '9') {
val = val * 10 + (*p - '0');
if (val > 255) return -1;
} else if (*p == '.') {
if (part > 3) return -1;
ip->bytes[part++] = (uint8_t)val;
val = 0;
} else {
return -1;
}
p++;
}
if (part != 3) return -1;
ip->bytes[3] = (uint8_t)val;
return 0;
}
static int resolve_host(const char* host, net_ipv4_address_t* ip) {
if (parse_ip(host, ip) == 0) return 0;
// Try DNS
return sys_dns_lookup(host, ip);
}
static void cmd_dhcp(void) {
printf("Acquiring DHCP lease...\n");
if (sys_network_dhcp_acquire() == 0) {
net_ipv4_address_t ip;
sys_network_get_ip(&ip);
printf("DHCP Success. IP: ");
print_ip(&ip);
printf("\n");
} else {
printf("DHCP Failed.\n");
}
}
static void cmd_dnsset(const char* ip_str) {
net_ipv4_address_t ip;
if (parse_ip(ip_str, &ip) != 0) {
printf("Invalid IP: %s\n", ip_str);
return;
}
if (sys_set_dns_server(&ip) == 0) {
printf("DNS server set to %s\n", ip_str);
} else {
printf("Failed to set DNS server.\n");
}
}
static void cmd_dig(const char* name) {
net_ipv4_address_t ip;
printf("Resolving %s...\n", name);
if (sys_dns_lookup(name, &ip) == 0) {
printf("%s resolves to ", name);
print_ip(&ip);
printf("\n");
} else {
printf("Failed to resolve %s\n", name);
}
}
static void cmd_nc(const char* host, const char* port_str, const char* msg) {
net_ipv4_address_t ip;
if (resolve_host(host, &ip) != 0) {
printf("Failed to resolve %s\n", host);
return;
}
uint16_t port = (uint16_t)atoi(port_str);
printf("Connecting to "); print_ip(&ip); printf(":%d...\n", port);
if (sys_tcp_connect(&ip, port) != 0) {
printf("Connection failed.\n");
return;
}
printf("Connected.\n");
if (msg == NULL) msg = "Hello world! (From BoredOS)\n";
sys_tcp_send(msg, strlen(msg));
char buf[1024];
int len = sys_tcp_recv(buf, 1023);
if (len > 0) {
buf[len] = 0;
printf("Received: %s\n", buf);
}
sys_tcp_close();
}
static void cmd_curl(const char* url) {
const char* host_start = url;
int is_https = 0;
if (url[0] == 'h' && url[1] == 't' && url[2] == 't' && url[3] == 'p') {
if (url[4] == 's' && url[5] == ':') {
is_https = 1;
host_start = url + 8;
} else if (url[4] == ':') {
host_start = url + 7;
}
}
if (is_https) {
printf("Error: HTTPS is not yet supported in BoredOS. Please use http://\n");
return;
}
char hostname[256];
int i = 0;
while (host_start[i] && host_start[i] != '/' && i < 255) {
hostname[i] = host_start[i];
i++;
}
hostname[i] = 0;
net_ipv4_address_t ip;
if (sys_dns_lookup(hostname, &ip) != 0) {
printf("Failed to resolve %s\n", hostname);
return;
}
printf("Connecting to %s (", hostname); print_ip(&ip); printf("):80...\n");
if (sys_tcp_connect(&ip, 80) != 0) {
printf("Failed to connect to %s:80\n", hostname);
return;
}
const char* path = host_start + i;
if (*path == 0) path = "/";
char request[1024];
int req_len = 0;
const char *r1 = "GET ";
const char *r2 = " HTTP/1.1\r\nHost: ";
const char *r3 = "\r\nUser-Agent: BoredOS/1.0\r\nAccept: */*\r\nConnection: close\r\n\r\n";
const char *p;
p = r1; while(*p) request[req_len++] = *p++;
p = path; while(*p) request[req_len++] = *p++;
p = r2; while(*p) request[req_len++] = *p++;
p = hostname; while(*p) request[req_len++] = *p++;
p = r3; while(*p) request[req_len++] = *p++;
request[req_len] = 0;
sys_tcp_send(request, req_len);
char buf[4096];
int total = 0;
while (1) {
int len = sys_tcp_recv(buf, 4095);
if (len < 0) {
printf("\n[Error: Connection error]\n");
break;
}
if (len == 0) break; // End of stream or timeout
buf[len] = 0;
printf("%s", buf);
total += len;
if (total > 1000000) {
printf("\n[Error: Data limit exceeded]\n");
break;
}
}
sys_tcp_close();
}
static void cmd_ping(const char* host) {
net_ipv4_address_t ip;
if (resolve_host(host, &ip) != 0) {
printf("Failed to resolve %s\n", host);
return;
}
printf("Pinging %s (", host); print_ip(&ip); printf(")...\n");
int successful = 0;
for (int i = 0; i < 4; i++) {
int rtt = sys_icmp_ping(&ip);
if (rtt >= 0) {
printf("64 bytes from "); print_ip(&ip);
printf(": icmp_seq=%d time=%dms\n", i + 1, rtt);
successful++;
} else {
printf("Request timeout for icmp_seq %d\n", i + 1);
}
for(volatile int d=0; d<1000000; d++);
}
printf("\n--- %s ping statistics ---\n", host);
printf("4 packets transmitted, %d received, %d%% packet loss\n", successful, (4-successful)*25);
}
static void cmd_netinfo(void) {
if (!sys_network_is_initialized()) {
printf("Network not initialized.\n");
return;
}
net_mac_address_t mac;
net_ipv4_address_t ip, gw, dns;
char nic_name[64];
if (sys_network_get_nic_name(nic_name) == 0) {
printf("NIC: %s\n", nic_name);
} else {
printf("NIC: Unknown\n");
}
sys_network_get_mac(&mac);
printf("MAC: %X:%X:%X:%X:%X:%X\n", mac.bytes[0], mac.bytes[1], mac.bytes[2], mac.bytes[3], mac.bytes[4], mac.bytes[5]);
if (sys_network_has_ip()) {
sys_network_get_ip(&ip);
sys_network_get_gateway(&gw);
sys_network_get_dns(&dns);
printf("IP: "); print_ip(&ip); printf("\n");
printf("GW: "); print_ip(&gw); printf("\n");
printf("DNS: "); print_ip(&dns); printf("\n");
} else {
printf("IP: Not assigned (DHCP in progress or failed)\n");
}
printf("Stats: Link RX=%d, TX=%d, UDP RX=%d\n", sys_network_get_stat(0), sys_network_get_stat(2), sys_network_get_stat(1));
}
int main(int argc, char** argv) {
if (argc < 2) {
printf("Usage: net <command> [args]\n");
printf("Commands: dhcp, dnsset <ip>, dig <host>, nc <host> <port>, curl <url>, ping <host>, init, info, unlock\n");
return 1;
}
if (strcmp(argv[1], "init") == 0) {
if (sys_network_init() == 0) printf("Network OK\n");
else printf("Network Fail\n");
return 0;
}
if (!sys_network_is_initialized()) {
printf("Initializing network...\n");
sys_network_init();
}
if (strcmp(argv[1], "dhcp") == 0) cmd_dhcp();
else if (strcmp(argv[1], "dnsset") == 0) {
if (argc < 3) cmd_dnsset("1.1.1.1");
else cmd_dnsset(argv[2]);
} else if (strcmp(argv[1], "dig") == 0) {
if (argc < 3) printf("Usage: net dig <host>\n");
else cmd_dig(argv[2]);
} else if (strcmp(argv[1], "nc") == 0) {
if (argc < 4) printf("Usage: net nc <host> <port> [message]\n");
else {
const char* msg = (argc >= 5) ? argv[4] : NULL;
cmd_nc(argv[2], argv[3], msg);
}
} else if (strcmp(argv[1], "curl") == 0) {
if (argc < 3) printf("Usage: net curl <url>\n");
else cmd_curl(argv[2]);
} else if (strcmp(argv[1], "ping") == 0) {
if (argc < 3) printf("Usage: net ping <host>\n");
else cmd_ping(argv[2]);
} else if (strcmp(argv[1], "info") == 0) cmd_netinfo();
else if (strcmp(argv[1], "unlock") == 0) {
sys_network_force_unlock();
printf("Network processing lock cleared.\n");
} else printf("Unknown command: %s\n", argv[1]);
return 0;
}

70
src/userland/net/ping.c Normal file
View File

@@ -0,0 +1,70 @@
#include <stdlib.h>
#include <syscall.h>
static int parse_ip(const char* str, net_ipv4_address_t* ip) {
int val = 0;
int part = 0;
const char* p = str;
while (*p) {
if (*p >= '0' && *p <= '9') {
val = val * 10 + (*p - '0');
if (val > 255) return -1;
} else if (*p == '.') {
if (part > 3) return -1;
ip->bytes[part++] = (uint8_t)val;
val = 0;
} else {
return -1;
}
p++;
}
if (part != 3) return -1;
ip->bytes[3] = (uint8_t)val;
return 0;
}
static int resolve_host(const char* host, net_ipv4_address_t* ip) {
if (parse_ip(host, ip) == 0) return 0;
return sys_dns_lookup(host, ip);
}
int main(int argc, char **argv) {
if (argc < 2) {
printf("Usage: ping <host>\n");
return 1;
}
if (!sys_network_is_initialized()) {
printf("Initializing network...\n");
sys_network_init();
}
const char *host = argv[1];
net_ipv4_address_t ip;
if (resolve_host(host, &ip) != 0) {
printf("Failed to resolve %s\n", host);
return 1;
}
printf("Pinging %s (%d.%d.%d.%d)...\n", host, ip.bytes[0], ip.bytes[1], ip.bytes[2], ip.bytes[3]);
int successful = 0;
for (int i = 0; i < 4; i++) {
int rtt = sys_icmp_ping(&ip);
if (rtt >= 0) {
printf("64 bytes from %d.%d.%d.%d: icmp_seq=%d time=%dms\n",
ip.bytes[0], ip.bytes[1], ip.bytes[2], ip.bytes[3], i + 1, rtt);
successful++;
} else {
printf("Request timeout for icmp_seq %d\n", i + 1);
}
// Small delay between pings
for(volatile int d=0; d<1000000; d++);
}
printf("\n--- %s ping statistics ---\n", host);
printf("4 packets transmitted, %d received, %d%% packet loss\n", successful, (4-successful)*25);
return successful > 0 ? 0 : 1;
}

405
src/userland/net/telnet.c Normal file
View File

@@ -0,0 +1,405 @@
// Copyright (c) 2023-2026 Chris (boreddevnl)
// This software is released under the GNU General Public License v3.0. See LICENSE file for details.
// This header needs to maintain in any file it is present in, as per the GPL license terms.
#include <stdlib.h>
#include <syscall.h>
#include "libc/libui.h"
static int term_cols = 116;
static int term_rows = 41;
#define IAC 255
#define DONT 254
#define DO 253
#define WONT 252
#define WILL 251
#define SB 250 // sub-negotiation begin
#define SE 240 // sub-negotiation end
#define GA 249
#define EL 248
#define EC 247
#define AYT 246
#define AO 245
#define IP 244
#define BRK 243
#define DM 242
#define NOP 241
// Telnet options
#define OPT_ECHO 1
#define OPT_SUPPRESS_GA 3
#define OPT_STATUS 5
#define OPT_TIMING_MARK 6
#define OPT_NAWS 31 // Negotiate About Window Size
#define OPT_NEW_ENVIRON 39
#define OPT_TERMINAL_TYPE 24
// ─── IAC send helpers ────────────────────────────────────────────────────────
static void telnet_send(const uint8_t *data, int len) {
sys_tcp_send(data, len);
}
static void telnet_send_3(uint8_t a, uint8_t b, uint8_t c) {
uint8_t buf[3] = { a, b, c };
telnet_send(buf, 3);
}
// Send NAWS subnegotiation with current terminal dimensions
static void telnet_send_naws(void) {
uint8_t buf[9];
buf[0] = IAC;
buf[1] = SB;
buf[2] = OPT_NAWS;
buf[3] = (uint8_t)((term_cols >> 8) & 0xFF);
buf[4] = (uint8_t)(term_cols & 0xFF);
buf[5] = (uint8_t)((term_rows >> 8) & 0xFF);
buf[6] = (uint8_t)(term_rows & 0xFF);
buf[7] = IAC;
buf[8] = SE;
telnet_send(buf, 9);
}
static void telnet_handle_option(uint8_t cmd, uint8_t opt) {
switch (cmd) {
case DO:
if (opt == OPT_NAWS) {
telnet_send_3(IAC, WILL, OPT_NAWS);
telnet_send_naws();
} else if (opt == OPT_TERMINAL_TYPE) {
telnet_send_3(IAC, WILL, OPT_TERMINAL_TYPE);
} else {
telnet_send_3(IAC, WONT, opt);
}
break;
case DONT:
telnet_send_3(IAC, WONT, opt);
break;
case WILL:
if (opt == OPT_SUPPRESS_GA) {
// Good — accept suppressed GA (most BBS systems do this)
telnet_send_3(IAC, DO, OPT_SUPPRESS_GA);
} else if (opt == OPT_ECHO) {
// Server will echo chars (remote echo) — accept it
telnet_send_3(IAC, DO, OPT_ECHO);
} else {
// Refuse other server offers
telnet_send_3(IAC, DONT, opt);
}
break;
case WONT:
telnet_send_3(IAC, DONT, opt);
break;
default:
break;
}
}
static void telnet_handle_sb_terminal_type(const uint8_t *sb_data, int sb_len) {
if (sb_len < 1 || sb_data[0] != 1) return; // 1 = SEND
uint8_t reply[12];
int i = 0;
reply[i++] = IAC;
reply[i++] = SB;
reply[i++] = OPT_TERMINAL_TYPE;
reply[i++] = 0; // IS
reply[i++] = 'A'; reply[i++] = 'N'; reply[i++] = 'S'; reply[i++] = 'I';
reply[i++] = IAC;
reply[i++] = SE;
telnet_send(reply, i);
}
typedef enum {
TS_DATA = 0,
TS_IAC,
TS_CMD,
TS_OPT,
TS_SB,
TS_SB_IAC
} TelnetParseState;
static TelnetParseState ts_state = TS_DATA;
static uint8_t ts_cmd = 0;
static uint8_t ts_sb_opt = 0;
static uint8_t ts_sb_buf[256];
static int ts_sb_pos = 0;
// Output buffer — accumulate non-IAC bytes to write in bulk
static char out_buf[4096];
static int out_pos = 0;
static void flush_out(void) {
if (out_pos > 0) {
sys_write(1, out_buf, out_pos);
out_pos = 0;
}
}
static void out_char(char c) {
if (out_pos >= (int)(sizeof(out_buf) - 1)) {
flush_out();
}
out_buf[out_pos++] = c;
}
// Process a chunk of raw TCP data from server. Returns false if connection lost.
static int telnet_process(const uint8_t *data, int len) {
for (int i = 0; i < len; i++) {
uint8_t b = data[i];
switch (ts_state) {
case TS_DATA:
if (b == IAC) {
ts_state = TS_IAC;
} else {
// Pass directly to display
out_char((char)b);
}
break;
case TS_IAC:
switch (b) {
case IAC:
// Escaped IAC — literal 0xFF
out_char((char)0xFF);
ts_state = TS_DATA;
break;
case DO: case DONT: case WILL: case WONT:
ts_cmd = b;
ts_state = TS_OPT;
break;
case SB:
ts_sb_pos = 0;
ts_state = TS_CMD;
break;
case GA: case NOP: case DM: case BRK: case IP:
case AO: case AYT: case EC: case EL:
ts_state = TS_DATA;
break;
default:
ts_state = TS_DATA;
break;
}
break;
case TS_CMD:
ts_sb_opt = b;
ts_sb_pos = 0;
ts_state = TS_SB;
break;
case TS_OPT:
flush_out();
telnet_handle_option(ts_cmd, b);
ts_state = TS_DATA;
break;
case TS_SB:
if (b == IAC) {
ts_state = TS_SB_IAC;
} else {
if (ts_sb_pos < (int)sizeof(ts_sb_buf) - 1) {
ts_sb_buf[ts_sb_pos++] = b;
}
}
break;
case TS_SB_IAC:
if (b == SE) {
flush_out();
if (ts_sb_opt == OPT_TERMINAL_TYPE) {
telnet_handle_sb_terminal_type(ts_sb_buf, ts_sb_pos);
}
ts_state = TS_DATA;
} else if (b == IAC) {
if (ts_sb_pos < (int)sizeof(ts_sb_buf) - 1) {
ts_sb_buf[ts_sb_pos++] = IAC;
}
ts_state = TS_SB;
} else {
ts_state = TS_DATA;
}
break;
}
}
flush_out();
return 1;
}
static int map_key(char c, uint8_t *key_out) {
if (c == 29) {
// Ctrl+]
return -1;
}
if (c == 17) {
// UP arrow
key_out[0] = 0x1b; key_out[1] = '['; key_out[2] = 'A';
return 3;
}
if (c == 18) {
// DOWN arrow
key_out[0] = 0x1b; key_out[1] = '['; key_out[2] = 'B';
return 3;
}
if (c == 20) {
// RIGHT arrow
key_out[0] = 0x1b; key_out[1] = '['; key_out[2] = 'C';
return 3;
}
if (c == 19) {
// LEFT arrow
key_out[0] = 0x1b; key_out[1] = '['; key_out[2] = 'D';
return 3;
}
if (c == '\n') {
// Enter
key_out[0] = '\r'; key_out[1] = '\n';
return 2;
}
if (c == '\b') {
// Backspace
key_out[0] = '\x7f';
return 1;
}
// Normal printable character
key_out[0] = (uint8_t)c;
return 1;
}
static int my_atoi(const char *s) {
int v = 0;
while (*s >= '0' && *s <= '9') { v = v*10 + (*s - '0'); s++; }
return v;
}
static int parse_ip(const char *s, net_ipv4_address_t *ip) {
int part = 0, val = 0;
while (*s) {
if (*s >= '0' && *s <= '9') {
val = val*10 + (*s - '0');
if (val > 255) return -1;
} else if (*s == '.') {
if (part > 3) return -1;
ip->bytes[part++] = (uint8_t)val;
val = 0;
} else {
return -1;
}
s++;
}
if (part != 3) return -1;
ip->bytes[3] = (uint8_t)val;
return 0;
}
int main(int argc, char **argv) {
if (argc < 2) {
printf("Usage: telnet <host> [port]\n");
printf(" Connect to a Telnet BBS or server.\n");
printf(" Default port: 23\n");
printf(" Press Ctrl+] to disconnect.\n");
return 1;
}
const char *host = argv[1];
int port = (argc >= 3) ? my_atoi(argv[2]) : 23;
if (port <= 0 || port > 65535) port = 23;
if (!sys_network_is_initialized()) {
printf("Initializing network...\n");
sys_network_init();
}
if (!sys_network_has_ip()) {
printf("Acquiring DHCP...\n");
if (sys_network_dhcp_acquire() != 0) {
printf("DHCP failed.\n");
return 1;
}
}
net_ipv4_address_t ip;
if (parse_ip(host, &ip) != 0) {
printf("Resolving %s...\n", host);
if (sys_dns_lookup(host, &ip) != 0) {
printf("Failed to resolve: %s\n", host);
return 1;
}
}
printf("Connecting to %s:%d...\n", host, port);
if (sys_tcp_connect(&ip, (uint16_t)port) != 0) {
printf("Connection failed.\n");
return 1;
}
printf("Connected. Press Ctrl+] to disconnect.\n\n");
sys_system(41, 1, 0, 0, 0); // SYSTEM_CMD_SET_RAW_MODE = 1
uint8_t recv_buf[4096];
int total = 0;
int idle_count = 0;
int connected = 1;
while (connected) {
gui_event_t ev;
while (ui_get_event(0, &ev)) { // win=0 for console proc
if (ev.type == GUI_EVENT_KEY) {
uint8_t key_data[16];
int key_len = map_key((char)ev.arg1, key_data);
if (key_len < 0) {
connected = 0;
break;
}
telnet_send(key_data, key_len);
}
}
if (!connected) break;
int len = sys_tcp_recv_nb(recv_buf, sizeof(recv_buf) - 1);
if (len < 0) {
printf("\r\n[Connection error]\r\n");
connected = 0;
break;
}
if (len == 0) {
idle_count++;
// Don't timeout too fast if we are just waiting for user input
if (idle_count > 10000000) {
printf("\r\n[Connection timed out]\r\n");
connected = 0;
break;
}
sys_yield();
continue;
}
idle_count = 0;
total += len;
if (total > 10000000) {
printf("\r\n[Data limit reached]\r\n");
connected = 0;
break;
}
if (!telnet_process(recv_buf, len)) {
connected = 0;
}
}
// Disable raw mode before exiting
sys_system(41, 0, 0, 0, 0);
sys_tcp_close();
printf("\r\n[Telnet session ended]\r\n");
return 0;
}