net: hacked up udp stuff, dns resolver
This commit is contained in:
parent
f187a5c85f
commit
4d8ee9840a
@ -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;
|
||||
}
|
||||
|
30
apps/fetch.c
30
apps/fetch.c
@ -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");
|
||||
|
@ -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;
|
||||
|
@ -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);
|
||||
|
@ -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 {
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user