diff options
author | Anton Kling <anton@kling.gg> | 2024-06-20 23:13:51 +0200 |
---|---|---|
committer | Anton Kling <anton@kling.gg> | 2024-06-20 23:13:51 +0200 |
commit | 9725791024d159ba0c5b6e8eef13a0e9077523a9 (patch) | |
tree | 91555c2f74e3d0794964f9f9cbb948b62550e46b /userland | |
parent | d7f2c29a6b238d678c6f76237b35b14eda258e7d (diff) |
Add getaddrinfo and change other libc stuff
Diffstat (limited to 'userland')
-rw-r--r-- | userland/libc/Makefile | 4 | ||||
-rw-r--r-- | userland/libc/include/netdb.h | 7 | ||||
-rw-r--r-- | userland/libc/include/unistd.h | 2 | ||||
-rw-r--r-- | userland/libc/netdb/getaddrinfo.c | 239 | ||||
-rw-r--r-- | userland/libc/unistd/lseek.c | 4 | ||||
-rw-r--r-- | userland/libc/unistd/write.c | 3 |
6 files changed, 253 insertions, 6 deletions
diff --git a/userland/libc/Makefile b/userland/libc/Makefile index 2d301cb..2be101e 100644 --- a/userland/libc/Makefile +++ b/userland/libc/Makefile @@ -1,8 +1,8 @@ CC="i686-sb-gcc" AR="i686-sb-ar" AS="i686-sb-as" -CFLAGS = -ggdb -ffreestanding -O0 -Wall -Wextra -pedantic -Werror -Wimplicit-fallthrough -I./include/ -static -I../../include/ -Wno-int-conversion -Wno-unused-parameter -OBJ=crt0.o libc.o malloc/malloc.o pty.o sys/mman/mmap.o sys/mman/munmap.o memset.o assert.o stdio/snprintf.o stdio/vfprintf.o string/memcpy.o string/memcmp.o string/strcmp.o ubsan.o string/strcpy.o isspace.o stdio/puts.o stdio/putchar.o dirent/opendir.o dirent/readdir.o dirent/closedir.o unistd/getopt.o dirent/scandir.o dirent/alphasort.o stdio/printf.o stdio/vdprintf.o stdio/vprintf.o stdio/dprintf.o stdio/vprintf.o string/strlen.o string/strnlen.o stdio/stdin.o stdio/getchar.o stdio/fgetc.o arpa/inet/htons.o arpa/inet/htonl.o stdio/fread.o stdio/fwrite.o stdio/fopen.o stdio/fclose.o stdio/fseek.o ctype/isascii.o stdio/fprintf.o stdlib/atoi.o stdlib/strtol.o ctype/toupper.o ctype/tolower.o string/strcat.o string/strchr.o string/sscanf.o sys/stat/stat.o stdlib/getenv.o string/strrchr.o stdio/ftell.o stdio/tmpfile.o stdio/fgets.o stdio/feof.o stdio/fscanf.o stdio/ungetc.o string/strncmp.o stdio/fputc.o string/strncpy.o stdio/remove.o stdio/ferror.o stdio/fputs.o stdlib/rand.o stdlib/srand.o unistd/getpid.o stdlib/strtoul.o stdio/fflush.o stdlib/abort.o string/strcspn.o time/localtime.o time/time.o time/clock_gettime.o time/gmtime.o time/strftime.o string/strpbrk.o ctype/isdigit.o ctype/isalpha.o ctype/isxdigit.o ctype/ispunct.o stdio/setvbuf.o stdio/fileno.o stdio/putc.o stdio/sprintf.o stdlib/abs.o string/strspn.o stdlib/qsort.o string/memmove.o setjmp/longjmp.o setjmp/setjmp.o libgen/basename.o string/strdup.o string/strndup.o string/strlcpy.o stdlib/atexit.o stdio/open_memstream.o libgen/dirname.o unistd/unlink.o string/strstr.o string/strcasecmp.o string/strncasecmp.o stdlib/mkstemp.o string/strtok.o unistd/execvp.o unistd/_exit.o ctype/isalnum.o time/ctime_r.o stdlib/strtold.o sys/time/gettimeofday.o stdio/fgetpos.o stdio/fsetpos.o ctype/isprint.o stdlib/system.o stdio/tmpnam.o unistd/msleep.o stdlib/atof.o stdlib/strtod.o stdio/rename.o sys/stat/mkdir.o unistd/uptime.o unistd/ftruncate.o sys/socket/recvfrom.o sys/socket/sendto.o signal/kill.o signal/sigaction.o unistd/chdir.o unistd/getcwd.o stdio/getdelim.o stdio/getline.o unistd/isatty.o sys/socket/listen.o stdlib/realpath.o systemcall.o sys/random/randomfill.o fcntl/open.o unistd/write.o unistd/pwrite.o fcntl/open_process.o tb/sb.o tb/sv.o string/memchr.o stdlib/atol.o stdlib/atoll.o stdlib/strtoll.o sys/stat/fstat.o unistd/lseek.o ctype/isupper.o ctype/islower.o ctype/isblank.o ctype/isgraph.o ctype/iscntrl.o math/ldexp.o sys/socket/connect.o sys/socket/setsockopt.o +CFLAGS = -ggdb -ffreestanding -nostdlib -O0 -Wall -Wextra -pedantic -Werror -Wimplicit-fallthrough -I./include/ -static -I../../include/ -Wno-int-conversion -Wno-unused-parameter +OBJ=crt0.o libc.o malloc/malloc.o pty.o sys/mman/mmap.o sys/mman/munmap.o memset.o assert.o stdio/snprintf.o stdio/vfprintf.o string/memcpy.o string/memcmp.o string/strcmp.o ubsan.o string/strcpy.o isspace.o stdio/puts.o stdio/putchar.o dirent/opendir.o dirent/readdir.o dirent/closedir.o unistd/getopt.o dirent/scandir.o dirent/alphasort.o stdio/printf.o stdio/vdprintf.o stdio/vprintf.o stdio/dprintf.o stdio/vprintf.o string/strlen.o string/strnlen.o stdio/stdin.o stdio/getchar.o stdio/fgetc.o arpa/inet/htons.o arpa/inet/htonl.o stdio/fread.o stdio/fwrite.o stdio/fopen.o stdio/fclose.o stdio/fseek.o ctype/isascii.o stdio/fprintf.o stdlib/atoi.o stdlib/strtol.o ctype/toupper.o ctype/tolower.o string/strcat.o string/strchr.o string/sscanf.o sys/stat/stat.o stdlib/getenv.o string/strrchr.o stdio/ftell.o stdio/tmpfile.o stdio/fgets.o stdio/feof.o stdio/fscanf.o stdio/ungetc.o string/strncmp.o stdio/fputc.o string/strncpy.o stdio/remove.o stdio/ferror.o stdio/fputs.o stdlib/rand.o stdlib/srand.o unistd/getpid.o stdlib/strtoul.o stdio/fflush.o stdlib/abort.o string/strcspn.o time/localtime.o time/time.o time/clock_gettime.o time/gmtime.o time/strftime.o string/strpbrk.o ctype/isdigit.o ctype/isalpha.o ctype/isxdigit.o ctype/ispunct.o stdio/setvbuf.o stdio/fileno.o stdio/putc.o stdio/sprintf.o stdlib/abs.o string/strspn.o stdlib/qsort.o string/memmove.o setjmp/longjmp.o setjmp/setjmp.o libgen/basename.o string/strdup.o string/strndup.o string/strlcpy.o stdlib/atexit.o stdio/open_memstream.o libgen/dirname.o unistd/unlink.o string/strstr.o string/strcasecmp.o string/strncasecmp.o stdlib/mkstemp.o string/strtok.o unistd/execvp.o unistd/_exit.o ctype/isalnum.o time/ctime_r.o stdlib/strtold.o sys/time/gettimeofday.o stdio/fgetpos.o stdio/fsetpos.o ctype/isprint.o stdlib/system.o stdio/tmpnam.o unistd/msleep.o stdlib/atof.o stdlib/strtod.o stdio/rename.o sys/stat/mkdir.o unistd/uptime.o unistd/ftruncate.o sys/socket/recvfrom.o sys/socket/sendto.o signal/kill.o signal/sigaction.o unistd/chdir.o unistd/getcwd.o stdio/getdelim.o stdio/getline.o unistd/isatty.o sys/socket/listen.o stdlib/realpath.o systemcall.o sys/random/randomfill.o fcntl/open.o unistd/write.o unistd/pwrite.o fcntl/open_process.o tb/sb.o tb/sv.o string/memchr.o stdlib/atol.o stdlib/atoll.o stdlib/strtoll.o sys/stat/fstat.o unistd/lseek.o ctype/isupper.o ctype/islower.o ctype/isblank.o ctype/isgraph.o ctype/iscntrl.o math/ldexp.o sys/socket/connect.o sys/socket/setsockopt.o arpa/inet/ntohl.o arpa/inet/ntohs.o netdb/getaddrinfo.o all: libc.a %.o: %.c diff --git a/userland/libc/include/netdb.h b/userland/libc/include/netdb.h index e69de29..4b4dc99 100644 --- a/userland/libc/include/netdb.h +++ b/userland/libc/include/netdb.h @@ -0,0 +1,7 @@ +#include <arpa/inet.h> +#include <sys/socket.h> + +int getaddrinfo(const char *restrict node, const char *restrict service, + const struct addrinfo *restrict hints, + struct addrinfo **restrict res); +void freeaddrinfo(struct addrinfo *res); diff --git a/userland/libc/include/unistd.h b/userland/libc/include/unistd.h index f3e0f28..b44ca3e 100644 --- a/userland/libc/include/unistd.h +++ b/userland/libc/include/unistd.h @@ -30,5 +30,5 @@ int pread(int fd, void *buf, size_t count, size_t offset); int fork(void); int write(int fd, const char *buf, size_t count); int pwrite(int fd, const char *buf, size_t count, size_t offset); -off_t lseek(int fildes, off_t offset, int whence); +int lseek(int fildes, int offset, int whence); #endif diff --git a/userland/libc/netdb/getaddrinfo.c b/userland/libc/netdb/getaddrinfo.c new file mode 100644 index 0000000..d550b39 --- /dev/null +++ b/userland/libc/netdb/getaddrinfo.c @@ -0,0 +1,239 @@ +#include <assert.h> +#include <stdint.h> +#include <stdlib.h> +#include <tb/sv.h> +#include <arpa/inet.h> +#include <assert.h> +#include <ctype.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <sys/socket.h> +#include <unistd.h> + +#define PORT 53 + +u16 add_domain_label(u8 *buffer, struct sv label) { + assert(label.length < 64); + u16 size = 0; + u8 ll = label.length; + memcpy(buffer + size, &ll, sizeof(u8)); + size += sizeof(u8); + memcpy(buffer + size, label.s, label.length); + size += label.length; + return size; +} + +u16 send_domain_request(int sockfd, const char *domain, u16 *id) { + *id = 0; + u8 message[512]; + memset(message, 0, sizeof(message)); + + u16 size = 0; + size += 6 * sizeof(u16); // header + + u16 flags = htons(0x0100); + u16 qdcount = htons(1); + memcpy(message, id, sizeof(u16)); + memcpy(message + sizeof(u16), &flags, sizeof(u16)); + memcpy(message + sizeof(u16) * 2, &qdcount, sizeof(u16)); + + struct sv labels = C_TO_SV(domain); + for (; !sv_isempty(labels);) { + struct sv label = sv_split_delim(labels, &labels, '.'); + size += add_domain_label(message + size, label); + } + + size += add_domain_label(message + size, C_TO_SV("")); + + u16 query_type = htons(1); // A type + memcpy(message + size, &query_type, sizeof(u16)); + size += sizeof(u16); + + u16 q_class = htons(1); // IN + memcpy(message + size, &q_class, sizeof(u16)); + size += sizeof(u16); + + printf("sending: %d\n", size); + + write(sockfd, (char *)message, size); + return size; +} + +int connect_dns(void) { + int sockfd; + struct sockaddr_in servaddr; + + memset(&servaddr, 0, sizeof(servaddr)); + servaddr.sin_addr.a[0] = 8; + servaddr.sin_addr.a[1] = 8; + servaddr.sin_addr.a[2] = 8; + servaddr.sin_addr.a[3] = 8; + servaddr.sin_port = htons(PORT); + servaddr.sin_family = AF_INET; + + sockfd = socket(AF_INET, SOCK_DGRAM, 0); + + if (connect(sockfd, (struct sockaddr *)&servaddr, sizeof(servaddr)) < 0) { + return -1; + } + return sockfd; +} + +/* + hints.ai_family = AF_UNSPEC; + hints.ai_socktype = type; + hints.ai_flags = AI_PASSIVE; + hints.ai_protocol = 0; + hints.ai_canonname = NULL; + hints.ai_addr = NULL; + hints.ai_next = NULL; +*/ + +#define EAI_AGAIN 1 +#define EAI_FAIL 2 +#define EAI_NONAME 3 +#define EAI_MEMORY 4 + +u16 service_to_port(const char *service) { + int is_number = 0; + for (int i = 0; service[i]; i++) { + if (isdigit(service[i])) { + is_number = 1; + } + } + if (is_number) { + return htons(atoi(service)); + } + +#define SERVICE(_name, _port) \ + if (0 == strcmp(_name, service)) { \ + return htons(_port); \ + } + SERVICE("http", 80) + SERVICE("https", 443) +#undef SERVICE + return 0; +} + +int getaddrinfo(const char *restrict node, const char *restrict service, + const struct addrinfo *restrict hints, + struct addrinfo **restrict res) { + int sockfd = connect_dns(); + if (-1 == sockfd) { + return EAI_AGAIN; + } + + // TODO: Use the hints to make decisions about what data to request. + (void)hints; + + u16 id; + u16 size = send_domain_request(sockfd, node, &id); + + u8 buffer[512]; + memset(buffer, 0, sizeof(buffer)); + int rc = read(sockfd, buffer, sizeof(buffer)); + if (rc < size) { + close(sockfd); + return EAI_FAIL; + } + + if (0 != memcmp(buffer, &id, sizeof(u16))) { + close(sockfd); + return EAI_FAIL; + } + + u16 flags; + memcpy(&flags, buffer + sizeof(u16), sizeof(u16)); + flags = ntohs(flags); + + if (!(flags & (1 << 15))) { // QR + close(sockfd); + return EAI_FAIL; + } + if (0 != (flags & 0x1F)) { // Error field + close(sockfd); + return EAI_AGAIN; + } + + u16 qcount = ntohs(*(u16 *)(buffer + sizeof(u16) * 2)); + if (1 != qcount) { + close(sockfd); + return EAI_FAIL; + } + + u16 ancount = ntohs(*(u16 *)(buffer + sizeof(u16) * 3)); + if (1 != ancount) { + close(sockfd); + return EAI_NONAME; // TODO: Check if this is correct + } + + u8 *answer = buffer + size; + u16 answer_length = rc - size; + if (0 == answer_length) { + close(sockfd); + return EAI_FAIL; + } + + /* + // get labels + { + u16 offset = ntohs(*(u16 *)answer); + assert(3 == offset >> 14); + offset &= ~(3 << 14); + + printf("offset: %d\n", offset); + printf("name: "); + u8 length = buffer[offset]; + for (int i = 0; i < length; i++) { + printf("%c", buffer[offset + 1 + i]); + } + printf("\n"); + } + */ + + // type + u16 type = ntohs(*(u16 *)(answer + sizeof(u16))); + u16 class = ntohs(*(u16 *)(answer + sizeof(u16) * 2)); + if (1 != type) { + close(sockfd); + return EAI_FAIL; + } + if (1 != class) { + close(sockfd); + return EAI_FAIL; + } + + u16 rdlength = ntohs(*(u16 *)(answer + sizeof(u16) * 3 + sizeof(u32))); + + if (4 != rdlength) { + close(sockfd); + return EAI_FAIL; + } + u32 ip = *(u32 *)(answer + sizeof(u16) * 4 + sizeof(u32)); + + if (res) { + *res = calloc(1, sizeof(struct addrinfo)); + if (!(*res)) { + close(sockfd); + return EAI_MEMORY; + } + struct sockaddr_in *sa = calloc(1, sizeof(struct sockaddr_in)); + if (!sa) { + free(*res); + close(sockfd); + return EAI_MEMORY; + } + (*res)->ai_addr = (struct sockaddr *)sa; + sa->sin_addr.s_addr = ip; + sa->sin_port = service_to_port(service); + sa->sin_family = AF_INET; + } + close(sockfd); + return 0; +} + +void freeaddrinfo(struct addrinfo *res) { + free(res->ai_addr); + free(res); +} diff --git a/userland/libc/unistd/lseek.c b/userland/libc/unistd/lseek.c index 2dcd661..b9ebfae 100644 --- a/userland/libc/unistd/lseek.c +++ b/userland/libc/unistd/lseek.c @@ -1,7 +1,7 @@ #include <errno.h> -#include <unistd.h> #include <syscall.h> +#include <unistd.h> -off_t lseek(int fildes, off_t offset, int whence) { +int lseek(int fildes, int offset, int whence) { RC_ERRNO(syscall(SYS_LSEEK, (u32)fildes, offset, whence, 0, 0)); } diff --git a/userland/libc/unistd/write.c b/userland/libc/unistd/write.c index 661fb01..0dd1824 100644 --- a/userland/libc/unistd/write.c +++ b/userland/libc/unistd/write.c @@ -1,6 +1,7 @@ #include <syscall.h> #include <unistd.h> +#include <errno.h> int write(int fd, const char *buf, size_t count) { - return syscall(SYS_WRITE, fd, buf, count, 0, 0); + RC_ERRNO(syscall(SYS_WRITE, fd, buf, count, 0, 0)); } |