net: hacked up udp stuff, dns resolver

This commit is contained in:
K. Lange 2021-06-14 14:18:23 +09:00
parent f187a5c85f
commit 4d8ee9840a
9 changed files with 334 additions and 16 deletions

View File

@ -386,6 +386,9 @@ static int configure_interface(const char * if_name) {
char addr[16];
ip_ntoa(ntohl(ip_data), addr);
printf("%s: %s: nameserver %s\n", _argv_0, if_name, addr);
FILE * resolve = fopen("/etc/resolv.conf","w");
fprintf(resolve, "nameserver %s\n", addr);
fclose(resolve);
}
opt += len;
}

View File

@ -11,9 +11,10 @@
#include <stdlib.h>
#include <getopt.h>
#include <time.h>
#include <sys/time.h>
#include <termios.h>
#include <unistd.h>
#include <sys/time.h>
#include <sys/socket.h>
#include <toaru/hashmap.h>
@ -289,9 +290,6 @@ int main(int argc, char * argv[]) {
struct http_req my_req;
parse_url(argv[optind], &my_req);
char file[600];
sprintf(file, "/dev/net/%s", my_req.domain);
if (fetch_options.calculate_output) {
char * tmp = strdup(my_req.path);
char * x = strrchr(tmp,'/');
@ -306,7 +304,29 @@ int main(int argc, char * argv[]) {
fetch_options.out = fopen(fetch_options.output_file, "w+");
}
FILE * f = fopen(file,"r+");
int sock = socket(AF_INET, SOCK_STREAM, 0);
if (sock < 0) {
perror("socket");
return 1;
}
struct hostent * remote = gethostbyname(my_req.domain);
if (!remote) {
perror("gethostbyname");
return 1;
}
struct sockaddr_in addr;
addr.sin_family = AF_INET;
memcpy(&addr.sin_addr.s_addr, remote->h_addr, remote->h_length);
if (connect(sock, &addr, sizeof(struct sockaddr_in)) < 0) {
perror("connect");
return 1;
}
FILE * f = fdopen(sock,"w+");
if (!f) {
fprintf(stderr, "Nope.\n");

View File

@ -32,7 +32,7 @@ int main(int argc, char * argv[]) {
}
char addr[16] = {0};
ip_ntoa(*(uint32_t *)host->h_addr_list[0], addr);
ip_ntoa(ntohl(*(uint32_t *)host->h_addr_list[0]), addr);
fprintf(stderr, "%s: %s\n", host->h_name, addr);
return 0;

View File

@ -19,6 +19,8 @@ typedef struct SockData {
list_t * rx_wait;
list_t * rx_queue;
uint16_t priv[4];
long (*sock_recv)(struct SockData * sock, struct msghdr * msg, int flags);
long (*sock_send)(struct SockData * sock, const struct msghdr *msg, int flags);
void (*sock_close)(struct SockData * sock);

View File

@ -32,6 +32,10 @@ struct hostent {
char **h_addr_list; /* list of addresses */
};
#ifndef _KERNEL_
#define h_addr h_addr_list[0]
#endif
typedef size_t socklen_t;
struct sockaddr {

View File

@ -11,6 +11,7 @@
#include <kernel/string.h>
#include <kernel/printf.h>
#include <kernel/syscall.h>
#include <kernel/hashmap.h>
#include <kernel/vfs.h>
#include <kernel/net/netif.h>
@ -40,6 +41,14 @@ struct icmp_header {
uint8_t data[];
} __attribute__((packed)) __attribute__((aligned(2)));
struct udp_packet {
uint16_t source_port;
uint16_t destination_port;
uint16_t length;
uint16_t checksum;
uint8_t payload[];
} __attribute__ ((packed)) __attribute__((aligned(2)));
#define IPV4_PROT_UDP 17
#define IPV4_PROT_TCP 6
@ -112,6 +121,10 @@ static void icmp_handle(struct ipv4_packet * packet, const char * src, const cha
}
}
extern void net_sock_add(sock_t * sock, void * frame);
static hashmap_t * udp_sockets = NULL;
void net_ipv4_handle(struct ipv4_packet * packet, fs_node_t * nic) {
char dest[16];
@ -124,21 +137,146 @@ void net_ipv4_handle(struct ipv4_packet * packet, fs_node_t * nic) {
case 1:
icmp_handle(packet, src, dest, nic);
break;
case IPV4_PROT_UDP:
case IPV4_PROT_UDP: {
uint16_t dest_port = ntohs(((uint16_t*)&packet->payload)[1]);
printf("net: ipv4: %s: %s -> %s udp %d to %d\n", nic->name, src, dest, ntohs(((uint16_t*)&packet->payload)[0]), ntohs(((uint16_t*)&packet->payload)[1]));
if (udp_sockets && hashmap_has(udp_sockets, (void*)(uintptr_t)dest_port)) {
printf("net: udp: received and have a waiting endpoint!\n");
void * tmp = malloc(ntohs(packet->length));
memcpy(tmp, packet, ntohs(packet->length));
sock_t * sock = hashmap_get(udp_sockets, (void*)(uintptr_t)dest_port);
net_sock_add(sock, tmp);
}
break;
}
case IPV4_PROT_TCP:
printf("net: ipv4: %s: %s -> %s tcp %d to %d\n", nic->name, src, dest, ntohs(((uint16_t*)&packet->payload)[0]), ntohs(((uint16_t*)&packet->payload)[1]));
break;
}
}
extern fs_node_t * net_if_any(void);
static spin_lock_t udp_port_lock = {0};
static int next_port = 12345;
static int udp_get_port(sock_t * sock) {
spin_lock(udp_port_lock);
int out = next_port++;
if (!udp_sockets) {
udp_sockets = hashmap_create_int(10);
}
hashmap_set(udp_sockets, (void*)(uintptr_t)out, sock);
sock->priv[0] = out;
spin_unlock(udp_port_lock);
return out;
}
static long sock_udp_send(sock_t * sock, const struct msghdr *msg, int flags) {
printf("udp: send called\n");
if (msg->msg_iovlen > 1) {
printf("net: todo: can't send multiple iovs\n");
return -ENOTSUP;
}
if (msg->msg_iovlen == 0) return 0;
if (msg->msg_namelen != sizeof(struct sockaddr_in)) {
printf("udp: invalid destination address size %ld\n", msg->msg_namelen);
return -EINVAL;
}
if (sock->priv[0] == 0) {
udp_get_port(sock);
printf("udp: assigning port %d to socket\n", sock->priv[0]);
}
struct sockaddr_in * name = msg->msg_name;
char dest[16];
ip_ntoa(ntohl(name->sin_addr.s_addr), dest);
printf("udp: want to send to %s\n", dest);
/* Routing: We need a device to send this on... */
fs_node_t * nic = net_if_any();
size_t total_length = sizeof(struct ipv4_packet) + msg->msg_iov[0].iov_len + sizeof(struct udp_packet);
struct ipv4_packet * response = malloc(total_length);
response->length = htons(total_length);
response->destination = name->sin_addr.s_addr;
response->source = ((struct EthernetDevice*)nic->device)->ipv4_addr;
response->ttl = 64;
response->protocol = IPV4_PROT_UDP;
response->ident = 0;
response->flags_fragment = htons(0x4000);
response->version_ihl = 0x45;
response->dscp_ecn = 0;
response->checksum = 0;
response->checksum = htons(calculate_ipv4_checksum(response));
/* Stick UDP header into payload */
struct udp_packet * udp_packet = &response->payload;
udp_packet->source_port = htons(sock->priv[0]);
udp_packet->destination_port = name->sin_port;
udp_packet->length = htons(sizeof(struct udp_packet) + msg->msg_iov[0].iov_len);
udp_packet->checksum = 0;
memcpy(response->payload + sizeof(struct udp_packet), msg->msg_iov[0].iov_base, msg->msg_iov[0].iov_len);
net_eth_send((struct EthernetDevice*)nic->device, ntohs(response->length), response, ETHERNET_TYPE_IPV4, ETHERNET_BROADCAST_MAC);
free(response);
return 0;
}
static long sock_udp_recv(sock_t * sock, struct msghdr * msg, int flags) {
printf("udp: recv called\n");
if (!sock->priv[0]) {
printf("udp: recv() but socket has no port\n");
return -EINVAL;
}
if (msg->msg_iovlen > 1) {
printf("net: todo: can't recv multiple iovs\n");
return -ENOTSUP;
}
if (msg->msg_iovlen == 0) return 0;
struct ipv4_packet * data = net_sock_get(sock);
printf("udp: got response, size is %u - sizeof(ipv4) - sizeof(udp) = %lu\n",
ntohs(data->length), ntohs(data->length) - sizeof(struct ipv4_packet) - sizeof(struct udp_packet));
memcpy(msg->msg_iov[0].iov_base, data->payload + 8, ntohs(data->length) - sizeof(struct ipv4_packet) - sizeof(struct udp_packet));
printf("udp: data copied to iov 0, return length?\n");
long resp = ntohs(data->length) - sizeof(struct ipv4_packet) - sizeof(struct udp_packet);
free(data);
return resp;
}
static void sock_udp_close(sock_t * sock) {
if (sock->priv[0] && udp_sockets) {
printf("udp: removing port %d from bound map\n", sock->priv[0]);
spin_lock(udp_port_lock);
hashmap_remove(udp_sockets, (void*)(uintptr_t)sock->priv[0]);
spin_unlock(udp_port_lock);
}
}
static int udp_socket(void) {
printf("udp socket...\n");
sock_t * sock = net_sock_create();
sock->sock_recv = sock_udp_recv;
sock->sock_send = sock_udp_send;
sock->sock_close = sock_udp_close;
return process_append_fd((process_t *)this_core->current_process, (fs_node_t *)sock);
}
long net_ipv4_socket(int type, int protocol) {
/* Ignore protocol, make socket for 'type' only... */
switch (type) {
case SOCK_DGRAM:
printf("udp socket...\n");
return -EINVAL;
return udp_socket();
case SOCK_STREAM:
printf("tcp socket...\n");
return -EINVAL;

View File

@ -21,6 +21,7 @@
static hashmap_t * interfaces = NULL;
extern list_t * net_raw_sockets_list;
static fs_node_t * _if_first = NULL;
void net_install(void) {
/* Set up virtual devices */
@ -37,9 +38,15 @@ int net_add_interface(const char * name, fs_node_t * deviceNode) {
snprintf(tmp,100,"/dev/net/%s", name);
vfs_mount(tmp, deviceNode);
if (!_if_first) _if_first = deviceNode;
return 0;
}
fs_node_t * net_if_lookup(const char * name) {
return hashmap_get(interfaces, name);
}
fs_node_t * net_if_any(void) {
return _if_first;
}

View File

@ -196,22 +196,27 @@ long net_setsockopt(int sockfd, int level, int optname, const void *optval, sock
}
long net_getsockopt(int sockfd, int level, int optname, void *optval, socklen_t *optlen) {
if (!FD_CHECK(sockfd)) return -EBADF;
return -EINVAL;
}
long net_bind(int sockfd, const struct sockaddr *addr, socklen_t addrlen) {
if (!FD_CHECK(sockfd)) return -EBADF;
return -EINVAL;
}
long net_accept(int sockfd, struct sockaddr * addr, socklen_t * addrlen) {
if (!FD_CHECK(sockfd)) return -EBADF;
return -EINVAL;
}
long net_listen(int sockd, int backlog) {
long net_listen(int sockfd, int backlog) {
if (!FD_CHECK(sockfd)) return -EBADF;
return -EINVAL;
}
long net_connect(int sockfd, const struct sockaddr *addr, socklen_t addrlen) {
if (!FD_CHECK(sockfd)) return -EBADF;
return -EINVAL;
}

View File

@ -162,11 +162,150 @@ int getpeername(int sockfd, struct sockaddr *addr, socklen_t *addrlen) {
return -1;
}
struct hostent * gethostbyname(const char * name) {
/* This formerly called into the kernel network device to perform
* DNS lookups, but we're going to resolve directly with a UDP DNS
* client with timeouts and everything, right here in the libc... */
UNIMPLEMENTED;
return NULL;
static uint32_t ip_aton(const char * in) {
char ip[16];
char * c = ip;
uint32_t out[4];
char * i;
memcpy(ip, in, strlen(in) < 15 ? strlen(in) + 1 : 15);
ip[15] = '\0';
i = (char *)strchr(c, '.');
*i = '\0';
out[0] = atoi(c);
c += strlen(c) + 1;
i = (char *)strchr(c, '.');
*i = '\0';
out[1] = atoi(c);
c += strlen(c) + 1;
i = (char *)strchr(c, '.');
*i = '\0';
out[2] = atoi(c);
c += strlen(c) + 1;
out[3] = atoi(c);
return htonl((out[0] << 24) | (out[1] << 16) | (out[2] << 8) | (out[3]));
}
static struct hostent _hostent = {0};
static uint32_t _hostent_addr = 0;
static char * _host_entry_list[1] = {0};
struct dns_packet {
uint16_t qid;
uint16_t flags;
uint16_t questions;
uint16_t answers;
uint16_t authorities;
uint16_t additional;
uint8_t data[];
} __attribute__((packed)) __attribute__((aligned(2)));
struct hostent * gethostbyname(const char * name) {
/* Try to open /etc/resolv.conf */
FILE * resolv = fopen("/etc/resolv.conf","r");
if (!resolv) {
fprintf(stderr, "gethostbyname: no resolver\n");
return NULL;
}
/* Try to get a udp socket */
int sock = socket(AF_INET, SOCK_DGRAM, 0);
if (sock < 0) {
fprintf(stderr, "gethostbyname: could not get a socket\n");
return NULL;
}
/* Try to send something to the name server */
char tmp[256];
fread(tmp, 256, 1, resolv);
if (strncmp(tmp,"nameserver ",strlen("nameserver "))) {
fprintf(stderr, "gethostbyname: resolv doesn't look right?\n");
}
/* Try to convert so we can connect... */
uint32_t ns_addr = ip_aton(tmp + strlen("nameserver "));
fprintf(stderr, "gethostbyname: asking %#x\n", ns_addr);
/* Form a DNS request */
char dat[256];
struct dns_packet * req = (struct dns_packet*)&dat;
uint16_t qid = rand() & 0xFFFF;
req->qid = htons(qid);
req->flags = htons(0x0100);
req->questions = htons(1);
req->answers = htons(0);
req->authorities = htons(0);
req->additional = htons(0);
fprintf(stderr, "gethostbyname: Frobbing bits...\n");
/* Turn requested name into DNS request */
ssize_t i = 0;
const char * c = name;
while (*c) {
const char * n = strchr(c,'.');
if (!n) n = c + strlen(c);
ssize_t len = n - c;
fprintf(stderr, "gethostbyname: segment of len %zd\n", len);
req->data[i++] = len;
for (; c < n; ++c, ++i) {
req->data[i] = *c;
}
if (!*c) break;
c++;
}
req->data[i++] = 0x00;
req->data[i++] = 0x00;
req->data[i++] = 0x01; /* A */
req->data[i++] = 0x00;
req->data[i++] = 0x01; /* IN */
struct sockaddr_in dest;
dest.sin_family = AF_INET;
dest.sin_port = htons(53);
memcpy(&dest.sin_addr.s_addr, &ns_addr, sizeof(ns_addr));
if (sendto(sock, &dat, sizeof(struct dns_packet) + i, 0, &dest, sizeof(struct sockaddr_in)) < 0) {
fprintf(stderr, "gethostbyname: failed to send\n");
return NULL;
}
char buf[1550];
/* TODO timeout... */
ssize_t len = recv(sock, buf, 1550, 0);
if (len < 0) {
fprintf(stderr, "gethostbyname: failed to recv\n");
return NULL;
}
/* Now examine the response */
fprintf(stderr, "gethostbyname: response from server\n");
struct dns_packet * response = (struct dns_packet *)&buf;
if (ntohs(response->answers) == 0) {
fprintf(stderr, "gethostbyname: no answer\n");
return NULL;
}
fprintf(stderr, "gethostbyname: got %d answers\n", ntohs(response->answers));
/* XXX Just kinda blindly assume the answer is at the end */
fprintf(stderr, "packet is of len %d, so answer must be %x\n", (int)len, *(uint32_t*)(buf+len-4));
/* Get a return value */
_hostent.h_name = name;
_hostent.h_aliases = NULL;
_hostent.h_addrtype = AF_INET;
_hostent.h_length = sizeof(uint32_t);
_hostent.h_addr_list = &_host_entry_list;
_host_entry_list[0] = &_hostent_addr;
_hostent_addr = *(uint32_t*)(buf+len-4);
return &_hostent;
}